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