aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ipvlan/ipvlan_main.c
diff options
context:
space:
mode:
authorMahesh Bandewar <maheshb@google.com>2016-09-16 15:59:19 -0400
committerDavid S. Miller <davem@davemloft.net>2016-09-19 01:25:22 -0400
commit4fbae7d83c98c30efcf0a2a2ac55fbb75ef5a1a5 (patch)
tree3ea819d38ad4fbbae8d4db166f58451c2a78ee20 /drivers/net/ipvlan/ipvlan_main.c
parente8bffe0cf964f0330595bb376b74921cccdaac88 (diff)
ipvlan: Introduce l3s mode
In a typical IPvlan L3 setup where master is in default-ns and each slave is into different (slave) ns. In this setup egress packet processing for traffic originating from slave-ns will hit all NF_HOOKs in slave-ns as well as default-ns. However same is not true for ingress processing. All these NF_HOOKs are hit only in the slave-ns skipping them in the default-ns. IPvlan in L3 mode is restrictive and if admins want to deploy iptables rules in default-ns, this asymmetric data path makes it impossible to do so. This patch makes use of the l3_rcv() (added as part of l3mdev enhancements) to perform input route lookup on RX packets without changing the skb->dev and then uses nf_hook at NF_INET_LOCAL_IN to change the skb->dev just before handing over skb to L4. Signed-off-by: Mahesh Bandewar <maheshb@google.com> CC: David Ahern <dsa@cumulusnetworks.com> Reviewed-by: David Ahern <dsa@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ipvlan/ipvlan_main.c')
-rw-r--r--drivers/net/ipvlan/ipvlan_main.c87
1 files changed, 80 insertions, 7 deletions
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
index 18b4e8c7f68a..f442eb366863 100644
--- a/drivers/net/ipvlan/ipvlan_main.c
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -9,24 +9,87 @@
9 9
10#include "ipvlan.h" 10#include "ipvlan.h"
11 11
12static u32 ipvl_nf_hook_refcnt = 0;
13
14static struct nf_hook_ops ipvl_nfops[] __read_mostly = {
15 {
16 .hook = ipvlan_nf_input,
17 .pf = NFPROTO_IPV4,
18 .hooknum = NF_INET_LOCAL_IN,
19 .priority = INT_MAX,
20 },
21 {
22 .hook = ipvlan_nf_input,
23 .pf = NFPROTO_IPV6,
24 .hooknum = NF_INET_LOCAL_IN,
25 .priority = INT_MAX,
26 },
27};
28
29static struct l3mdev_ops ipvl_l3mdev_ops __read_mostly = {
30 .l3mdev_l3_rcv = ipvlan_l3_rcv,
31};
32
12static void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev) 33static void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev)
13{ 34{
14 ipvlan->dev->mtu = dev->mtu - ipvlan->mtu_adj; 35 ipvlan->dev->mtu = dev->mtu - ipvlan->mtu_adj;
15} 36}
16 37
17static void ipvlan_set_port_mode(struct ipvl_port *port, u16 nval) 38static int ipvlan_register_nf_hook(void)
39{
40 int err = 0;
41
42 if (!ipvl_nf_hook_refcnt) {
43 err = _nf_register_hooks(ipvl_nfops, ARRAY_SIZE(ipvl_nfops));
44 if (!err)
45 ipvl_nf_hook_refcnt = 1;
46 } else {
47 ipvl_nf_hook_refcnt++;
48 }
49
50 return err;
51}
52
53static void ipvlan_unregister_nf_hook(void)
54{
55 WARN_ON(!ipvl_nf_hook_refcnt);
56
57 ipvl_nf_hook_refcnt--;
58 if (!ipvl_nf_hook_refcnt)
59 _nf_unregister_hooks(ipvl_nfops, ARRAY_SIZE(ipvl_nfops));
60}
61
62static int ipvlan_set_port_mode(struct ipvl_port *port, u16 nval)
18{ 63{
19 struct ipvl_dev *ipvlan; 64 struct ipvl_dev *ipvlan;
65 struct net_device *mdev = port->dev;
66 int err = 0;
20 67
68 ASSERT_RTNL();
21 if (port->mode != nval) { 69 if (port->mode != nval) {
70 if (nval == IPVLAN_MODE_L3S) {
71 /* New mode is L3S */
72 err = ipvlan_register_nf_hook();
73 if (!err) {
74 mdev->l3mdev_ops = &ipvl_l3mdev_ops;
75 mdev->priv_flags |= IFF_L3MDEV_MASTER;
76 } else
77 return err;
78 } else if (port->mode == IPVLAN_MODE_L3S) {
79 /* Old mode was L3S */
80 mdev->priv_flags &= ~IFF_L3MDEV_MASTER;
81 ipvlan_unregister_nf_hook();
82 mdev->l3mdev_ops = NULL;
83 }
22 list_for_each_entry(ipvlan, &port->ipvlans, pnode) { 84 list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
23 if (nval == IPVLAN_MODE_L3) 85 if (nval == IPVLAN_MODE_L3 || nval == IPVLAN_MODE_L3S)
24 ipvlan->dev->flags |= IFF_NOARP; 86 ipvlan->dev->flags |= IFF_NOARP;
25 else 87 else
26 ipvlan->dev->flags &= ~IFF_NOARP; 88 ipvlan->dev->flags &= ~IFF_NOARP;
27 } 89 }
28 port->mode = nval; 90 port->mode = nval;
29 } 91 }
92 return err;
30} 93}
31 94
32static int ipvlan_port_create(struct net_device *dev) 95static int ipvlan_port_create(struct net_device *dev)
@@ -74,6 +137,11 @@ static void ipvlan_port_destroy(struct net_device *dev)
74 struct ipvl_port *port = ipvlan_port_get_rtnl(dev); 137 struct ipvl_port *port = ipvlan_port_get_rtnl(dev);
75 138
76 dev->priv_flags &= ~IFF_IPVLAN_MASTER; 139 dev->priv_flags &= ~IFF_IPVLAN_MASTER;
140 if (port->mode == IPVLAN_MODE_L3S) {
141 dev->priv_flags &= ~IFF_L3MDEV_MASTER;
142 ipvlan_unregister_nf_hook();
143 dev->l3mdev_ops = NULL;
144 }
77 netdev_rx_handler_unregister(dev); 145 netdev_rx_handler_unregister(dev);
78 cancel_work_sync(&port->wq); 146 cancel_work_sync(&port->wq);
79 __skb_queue_purge(&port->backlog); 147 __skb_queue_purge(&port->backlog);
@@ -132,7 +200,8 @@ static int ipvlan_open(struct net_device *dev)
132 struct net_device *phy_dev = ipvlan->phy_dev; 200 struct net_device *phy_dev = ipvlan->phy_dev;
133 struct ipvl_addr *addr; 201 struct ipvl_addr *addr;
134 202
135 if (ipvlan->port->mode == IPVLAN_MODE_L3) 203 if (ipvlan->port->mode == IPVLAN_MODE_L3 ||
204 ipvlan->port->mode == IPVLAN_MODE_L3S)
136 dev->flags |= IFF_NOARP; 205 dev->flags |= IFF_NOARP;
137 else 206 else
138 dev->flags &= ~IFF_NOARP; 207 dev->flags &= ~IFF_NOARP;
@@ -372,13 +441,14 @@ static int ipvlan_nl_changelink(struct net_device *dev,
372{ 441{
373 struct ipvl_dev *ipvlan = netdev_priv(dev); 442 struct ipvl_dev *ipvlan = netdev_priv(dev);
374 struct ipvl_port *port = ipvlan_port_get_rtnl(ipvlan->phy_dev); 443 struct ipvl_port *port = ipvlan_port_get_rtnl(ipvlan->phy_dev);
444 int err = 0;
375 445
376 if (data && data[IFLA_IPVLAN_MODE]) { 446 if (data && data[IFLA_IPVLAN_MODE]) {
377 u16 nmode = nla_get_u16(data[IFLA_IPVLAN_MODE]); 447 u16 nmode = nla_get_u16(data[IFLA_IPVLAN_MODE]);
378 448
379 ipvlan_set_port_mode(port, nmode); 449 err = ipvlan_set_port_mode(port, nmode);
380 } 450 }
381 return 0; 451 return err;
382} 452}
383 453
384static size_t ipvlan_nl_getsize(const struct net_device *dev) 454static size_t ipvlan_nl_getsize(const struct net_device *dev)
@@ -473,10 +543,13 @@ static int ipvlan_link_new(struct net *src_net, struct net_device *dev,
473 unregister_netdevice(dev); 543 unregister_netdevice(dev);
474 return err; 544 return err;
475 } 545 }
546 err = ipvlan_set_port_mode(port, mode);
547 if (err) {
548 unregister_netdevice(dev);
549 return err;
550 }
476 551
477 list_add_tail_rcu(&ipvlan->pnode, &port->ipvlans); 552 list_add_tail_rcu(&ipvlan->pnode, &port->ipvlans);
478 ipvlan_set_port_mode(port, mode);
479
480 netif_stacked_transfer_operstate(phy_dev, dev); 553 netif_stacked_transfer_operstate(phy_dev, dev);
481 return 0; 554 return 0;
482} 555}