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