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