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