ipvlan_l3s.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /* Copyright (c) 2014 Mahesh Bandewar <maheshb@google.com>
  3. */
  4. #include <net/ip.h>
  5. #include "ipvlan.h"
  6. static unsigned int ipvlan_netid __read_mostly;
  7. struct ipvlan_netns {
  8. unsigned int ipvl_nf_hook_refcnt;
  9. };
  10. static struct ipvl_addr *ipvlan_skb_to_addr(struct sk_buff *skb,
  11. struct net_device *dev)
  12. {
  13. struct ipvl_addr *addr = NULL;
  14. struct ipvl_port *port;
  15. int addr_type;
  16. void *lyr3h;
  17. if (!dev || !netif_is_ipvlan_port(dev))
  18. goto out;
  19. port = ipvlan_port_get_rcu(dev);
  20. if (!port || port->mode != IPVLAN_MODE_L3S)
  21. goto out;
  22. lyr3h = ipvlan_get_L3_hdr(port, skb, &addr_type);
  23. if (!lyr3h)
  24. goto out;
  25. addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
  26. out:
  27. return addr;
  28. }
  29. static struct sk_buff *ipvlan_l3_rcv(struct net_device *dev,
  30. struct sk_buff *skb, u16 proto)
  31. {
  32. struct ipvl_addr *addr;
  33. struct net_device *sdev;
  34. addr = ipvlan_skb_to_addr(skb, dev);
  35. if (!addr)
  36. goto out;
  37. sdev = addr->master->dev;
  38. switch (proto) {
  39. case AF_INET:
  40. {
  41. const struct iphdr *ip4h = ip_hdr(skb);
  42. int err;
  43. err = ip_route_input_noref(skb, ip4h->daddr, ip4h->saddr,
  44. ip4h_dscp(ip4h), sdev);
  45. if (unlikely(err))
  46. goto out;
  47. break;
  48. }
  49. #if IS_ENABLED(CONFIG_IPV6)
  50. case AF_INET6:
  51. {
  52. struct dst_entry *dst;
  53. struct ipv6hdr *ip6h = ipv6_hdr(skb);
  54. int flags = RT6_LOOKUP_F_HAS_SADDR;
  55. struct flowi6 fl6 = {
  56. .flowi6_iif = sdev->ifindex,
  57. .daddr = ip6h->daddr,
  58. .saddr = ip6h->saddr,
  59. .flowlabel = ip6_flowinfo(ip6h),
  60. .flowi6_mark = skb->mark,
  61. .flowi6_proto = ip6h->nexthdr,
  62. };
  63. skb_dst_drop(skb);
  64. dst = ip6_route_input_lookup(dev_net(sdev), sdev, &fl6,
  65. skb, flags);
  66. skb_dst_set(skb, dst);
  67. break;
  68. }
  69. #endif
  70. default:
  71. break;
  72. }
  73. out:
  74. return skb;
  75. }
  76. static const struct l3mdev_ops ipvl_l3mdev_ops = {
  77. .l3mdev_l3_rcv = ipvlan_l3_rcv,
  78. };
  79. static unsigned int ipvlan_nf_input(void *priv, struct sk_buff *skb,
  80. const struct nf_hook_state *state)
  81. {
  82. struct ipvl_addr *addr;
  83. unsigned int len;
  84. addr = ipvlan_skb_to_addr(skb, skb->dev);
  85. if (!addr)
  86. goto out;
  87. skb->dev = addr->master->dev;
  88. skb->skb_iif = skb->dev->ifindex;
  89. #if IS_ENABLED(CONFIG_IPV6)
  90. if (addr->atype == IPVL_IPV6)
  91. IP6CB(skb)->iif = skb->dev->ifindex;
  92. #endif
  93. len = skb->len + ETH_HLEN;
  94. ipvlan_count_rx(addr->master, len, true, false);
  95. out:
  96. return NF_ACCEPT;
  97. }
  98. static const struct nf_hook_ops ipvl_nfops[] = {
  99. {
  100. .hook = ipvlan_nf_input,
  101. .pf = NFPROTO_IPV4,
  102. .hooknum = NF_INET_LOCAL_IN,
  103. .priority = INT_MAX,
  104. },
  105. #if IS_ENABLED(CONFIG_IPV6)
  106. {
  107. .hook = ipvlan_nf_input,
  108. .pf = NFPROTO_IPV6,
  109. .hooknum = NF_INET_LOCAL_IN,
  110. .priority = INT_MAX,
  111. },
  112. #endif
  113. };
  114. static int ipvlan_register_nf_hook(struct net *net)
  115. {
  116. struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
  117. int err = 0;
  118. if (!vnet->ipvl_nf_hook_refcnt) {
  119. err = nf_register_net_hooks(net, ipvl_nfops,
  120. ARRAY_SIZE(ipvl_nfops));
  121. if (!err)
  122. vnet->ipvl_nf_hook_refcnt = 1;
  123. } else {
  124. vnet->ipvl_nf_hook_refcnt++;
  125. }
  126. return err;
  127. }
  128. static void ipvlan_unregister_nf_hook(struct net *net)
  129. {
  130. struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
  131. if (WARN_ON(!vnet->ipvl_nf_hook_refcnt))
  132. return;
  133. vnet->ipvl_nf_hook_refcnt--;
  134. if (!vnet->ipvl_nf_hook_refcnt)
  135. nf_unregister_net_hooks(net, ipvl_nfops,
  136. ARRAY_SIZE(ipvl_nfops));
  137. }
  138. void ipvlan_migrate_l3s_hook(struct net *oldnet, struct net *newnet)
  139. {
  140. struct ipvlan_netns *old_vnet;
  141. ASSERT_RTNL();
  142. old_vnet = net_generic(oldnet, ipvlan_netid);
  143. if (!old_vnet->ipvl_nf_hook_refcnt)
  144. return;
  145. ipvlan_register_nf_hook(newnet);
  146. ipvlan_unregister_nf_hook(oldnet);
  147. }
  148. static void ipvlan_ns_exit(struct net *net)
  149. {
  150. struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
  151. if (WARN_ON_ONCE(vnet->ipvl_nf_hook_refcnt)) {
  152. vnet->ipvl_nf_hook_refcnt = 0;
  153. nf_unregister_net_hooks(net, ipvl_nfops,
  154. ARRAY_SIZE(ipvl_nfops));
  155. }
  156. }
  157. static struct pernet_operations ipvlan_net_ops = {
  158. .id = &ipvlan_netid,
  159. .size = sizeof(struct ipvlan_netns),
  160. .exit = ipvlan_ns_exit,
  161. };
  162. int ipvlan_l3s_init(void)
  163. {
  164. return register_pernet_subsys(&ipvlan_net_ops);
  165. }
  166. void ipvlan_l3s_cleanup(void)
  167. {
  168. unregister_pernet_subsys(&ipvlan_net_ops);
  169. }
  170. int ipvlan_l3s_register(struct ipvl_port *port)
  171. {
  172. struct net_device *dev = port->dev;
  173. int ret;
  174. ASSERT_RTNL();
  175. ret = ipvlan_register_nf_hook(read_pnet(&port->pnet));
  176. if (!ret) {
  177. dev->l3mdev_ops = &ipvl_l3mdev_ops;
  178. dev->priv_flags |= IFF_L3MDEV_RX_HANDLER;
  179. }
  180. return ret;
  181. }
  182. void ipvlan_l3s_unregister(struct ipvl_port *port)
  183. {
  184. struct net_device *dev = port->dev;
  185. ASSERT_RTNL();
  186. dev->priv_flags &= ~IFF_L3MDEV_RX_HANDLER;
  187. ipvlan_unregister_nf_hook(read_pnet(&port->pnet));
  188. }