root/drivers/net/ipvlan/ipvlan_l3s.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ipvlan_skb_to_addr
  2. ipvlan_l3_rcv
  3. ipvlan_nf_input
  4. ipvlan_register_nf_hook
  5. ipvlan_unregister_nf_hook
  6. ipvlan_migrate_l3s_hook
  7. ipvlan_ns_exit
  8. ipvlan_l3s_init
  9. ipvlan_l3s_cleanup
  10. ipvlan_l3s_register
  11. ipvlan_l3s_unregister

   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 
   7 static unsigned int ipvlan_netid __read_mostly;
   8 
   9 struct ipvlan_netns {
  10         unsigned int ipvl_nf_hook_refcnt;
  11 };
  12 
  13 static 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);
  33 out:
  34         return addr;
  35 }
  36 
  37 static 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         }
  85 out:
  86         return skb;
  87 }
  88 
  89 static const struct l3mdev_ops ipvl_l3mdev_ops = {
  90         .l3mdev_l3_rcv = ipvlan_l3_rcv,
  91 };
  92 
  93 static 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);
 106 out:
 107         return NF_ACCEPT;
 108 }
 109 
 110 static 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 
 127 static 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 
 144 static 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 
 157 void 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 
 171 static 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 
 182 static struct pernet_operations ipvlan_net_ops = {
 183         .id   = &ipvlan_netid,
 184         .size = sizeof(struct ipvlan_netns),
 185         .exit = ipvlan_ns_exit,
 186 };
 187 
 188 int ipvlan_l3s_init(void)
 189 {
 190         return register_pernet_subsys(&ipvlan_net_ops);
 191 }
 192 
 193 void ipvlan_l3s_cleanup(void)
 194 {
 195         unregister_pernet_subsys(&ipvlan_net_ops);
 196 }
 197 
 198 int 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 
 214 void 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 }

/* [<][>][^][v][top][bottom][index][help] */