aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ipvlan/ipvlan_main.c
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2017-04-20 12:08:15 -0400
committerDavid S. Miller <davem@davemloft.net>2017-04-25 10:43:22 -0400
commit3133822f5ac13b04c2ca46f27cfe74606bbd4a6d (patch)
tree3834ea2bcc3a0520f80187cdcd094cff62fefab4 /drivers/net/ipvlan/ipvlan_main.c
parent86a5df1495cce7ed7357af0a3e1f439867ed1c64 (diff)
ipvlan: use pernet operations and restrict l3s hooks to master netns
commit 4fbae7d83c98c30efc ("ipvlan: Introduce l3s mode") added registration of netfilter hooks via nf_register_hooks(). This API provides the illusion of 'global' netfilter hooks by placing the hooks in all current and future network namespaces. In case of ipvlan the hook appears to be only needed in the namespace that contains the ipvlan master device (i.e., usually init_net), so placing them in all namespaces is not needed. This switches ipvlan driver to pernet operations, and then only registers hooks in namespaces where a ipvlan master device is set to l3s mode. Extra care has to be taken when the master device is moved to another namespace, as we might have to 'move' the netfilter hooks too. This is done by storing the namespace the ipvlan port was created in. On REGISTER event, do (un)register operations in the old/new namespaces. This will also allow removal of the nf_register_hooks() in a future patch. Cc: Mahesh Bandewar <maheshb@google.com> Signed-off-by: Florian Westphal <fw@strlen.de> 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.c83
1 files changed, 68 insertions, 15 deletions
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
index aa8575ccbce3..618ed88fad0f 100644
--- a/drivers/net/ipvlan/ipvlan_main.c
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -9,7 +9,11 @@
9 9
10#include "ipvlan.h" 10#include "ipvlan.h"
11 11
12static u32 ipvl_nf_hook_refcnt = 0; 12static unsigned int ipvlan_netid __read_mostly;
13
14struct ipvlan_netns {
15 unsigned int ipvl_nf_hook_refcnt;
16};
13 17
14static struct nf_hook_ops ipvl_nfops[] __read_mostly = { 18static struct nf_hook_ops ipvl_nfops[] __read_mostly = {
15 { 19 {
@@ -35,28 +39,34 @@ static void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev)
35 ipvlan->dev->mtu = dev->mtu; 39 ipvlan->dev->mtu = dev->mtu;
36} 40}
37 41
38static int ipvlan_register_nf_hook(void) 42static int ipvlan_register_nf_hook(struct net *net)
39{ 43{
44 struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
40 int err = 0; 45 int err = 0;
41 46
42 if (!ipvl_nf_hook_refcnt) { 47 if (!vnet->ipvl_nf_hook_refcnt) {
43 err = _nf_register_hooks(ipvl_nfops, ARRAY_SIZE(ipvl_nfops)); 48 err = nf_register_net_hooks(net, ipvl_nfops,
49 ARRAY_SIZE(ipvl_nfops));
44 if (!err) 50 if (!err)
45 ipvl_nf_hook_refcnt = 1; 51 vnet->ipvl_nf_hook_refcnt = 1;
46 } else { 52 } else {
47 ipvl_nf_hook_refcnt++; 53 vnet->ipvl_nf_hook_refcnt++;
48 } 54 }
49 55
50 return err; 56 return err;
51} 57}
52 58
53static void ipvlan_unregister_nf_hook(void) 59static void ipvlan_unregister_nf_hook(struct net *net)
54{ 60{
55 WARN_ON(!ipvl_nf_hook_refcnt); 61 struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
62
63 if (WARN_ON(!vnet->ipvl_nf_hook_refcnt))
64 return;
56 65
57 ipvl_nf_hook_refcnt--; 66 vnet->ipvl_nf_hook_refcnt--;
58 if (!ipvl_nf_hook_refcnt) 67 if (!vnet->ipvl_nf_hook_refcnt)
59 _nf_unregister_hooks(ipvl_nfops, ARRAY_SIZE(ipvl_nfops)); 68 nf_unregister_net_hooks(net, ipvl_nfops,
69 ARRAY_SIZE(ipvl_nfops));
60} 70}
61 71
62static int ipvlan_set_port_mode(struct ipvl_port *port, u16 nval) 72static int ipvlan_set_port_mode(struct ipvl_port *port, u16 nval)
@@ -69,7 +79,7 @@ static int ipvlan_set_port_mode(struct ipvl_port *port, u16 nval)
69 if (port->mode != nval) { 79 if (port->mode != nval) {
70 if (nval == IPVLAN_MODE_L3S) { 80 if (nval == IPVLAN_MODE_L3S) {
71 /* New mode is L3S */ 81 /* New mode is L3S */
72 err = ipvlan_register_nf_hook(); 82 err = ipvlan_register_nf_hook(read_pnet(&port->pnet));
73 if (!err) { 83 if (!err) {
74 mdev->l3mdev_ops = &ipvl_l3mdev_ops; 84 mdev->l3mdev_ops = &ipvl_l3mdev_ops;
75 mdev->priv_flags |= IFF_L3MDEV_MASTER; 85 mdev->priv_flags |= IFF_L3MDEV_MASTER;
@@ -78,7 +88,7 @@ static int ipvlan_set_port_mode(struct ipvl_port *port, u16 nval)
78 } else if (port->mode == IPVLAN_MODE_L3S) { 88 } else if (port->mode == IPVLAN_MODE_L3S) {
79 /* Old mode was L3S */ 89 /* Old mode was L3S */
80 mdev->priv_flags &= ~IFF_L3MDEV_MASTER; 90 mdev->priv_flags &= ~IFF_L3MDEV_MASTER;
81 ipvlan_unregister_nf_hook(); 91 ipvlan_unregister_nf_hook(read_pnet(&port->pnet));
82 mdev->l3mdev_ops = NULL; 92 mdev->l3mdev_ops = NULL;
83 } 93 }
84 list_for_each_entry(ipvlan, &port->ipvlans, pnode) { 94 list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
@@ -111,6 +121,7 @@ static int ipvlan_port_create(struct net_device *dev)
111 if (!port) 121 if (!port)
112 return -ENOMEM; 122 return -ENOMEM;
113 123
124 write_pnet(&port->pnet, dev_net(dev));
114 port->dev = dev; 125 port->dev = dev;
115 port->mode = IPVLAN_MODE_L3; 126 port->mode = IPVLAN_MODE_L3;
116 INIT_LIST_HEAD(&port->ipvlans); 127 INIT_LIST_HEAD(&port->ipvlans);
@@ -142,7 +153,7 @@ static void ipvlan_port_destroy(struct net_device *dev)
142 dev->priv_flags &= ~IFF_IPVLAN_MASTER; 153 dev->priv_flags &= ~IFF_IPVLAN_MASTER;
143 if (port->mode == IPVLAN_MODE_L3S) { 154 if (port->mode == IPVLAN_MODE_L3S) {
144 dev->priv_flags &= ~IFF_L3MDEV_MASTER; 155 dev->priv_flags &= ~IFF_L3MDEV_MASTER;
145 ipvlan_unregister_nf_hook(); 156 ipvlan_unregister_nf_hook(dev_net(dev));
146 dev->l3mdev_ops = NULL; 157 dev->l3mdev_ops = NULL;
147 } 158 }
148 netdev_rx_handler_unregister(dev); 159 netdev_rx_handler_unregister(dev);
@@ -673,6 +684,24 @@ static int ipvlan_device_event(struct notifier_block *unused,
673 ipvlan->dev); 684 ipvlan->dev);
674 break; 685 break;
675 686
687 case NETDEV_REGISTER: {
688 struct net *oldnet, *newnet = dev_net(dev);
689 struct ipvlan_netns *old_vnet;
690
691 oldnet = read_pnet(&port->pnet);
692 if (net_eq(newnet, oldnet))
693 break;
694
695 write_pnet(&port->pnet, newnet);
696
697 old_vnet = net_generic(oldnet, ipvlan_netid);
698 if (!old_vnet->ipvl_nf_hook_refcnt)
699 break;
700
701 ipvlan_register_nf_hook(newnet);
702 ipvlan_unregister_nf_hook(oldnet);
703 break;
704 }
676 case NETDEV_UNREGISTER: 705 case NETDEV_UNREGISTER:
677 if (dev->reg_state != NETREG_UNREGISTERING) 706 if (dev->reg_state != NETREG_UNREGISTERING)
678 break; 707 break;
@@ -854,6 +883,23 @@ static struct notifier_block ipvlan_addr6_notifier_block __read_mostly = {
854 .notifier_call = ipvlan_addr6_event, 883 .notifier_call = ipvlan_addr6_event,
855}; 884};
856 885
886static void ipvlan_ns_exit(struct net *net)
887{
888 struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
889
890 if (WARN_ON_ONCE(vnet->ipvl_nf_hook_refcnt)) {
891 vnet->ipvl_nf_hook_refcnt = 0;
892 nf_unregister_net_hooks(net, ipvl_nfops,
893 ARRAY_SIZE(ipvl_nfops));
894 }
895}
896
897static struct pernet_operations ipvlan_net_ops = {
898 .id = &ipvlan_netid,
899 .size = sizeof(struct ipvlan_netns),
900 .exit = ipvlan_ns_exit,
901};
902
857static int __init ipvlan_init_module(void) 903static int __init ipvlan_init_module(void)
858{ 904{
859 int err; 905 int err;
@@ -863,10 +909,16 @@ static int __init ipvlan_init_module(void)
863 register_inet6addr_notifier(&ipvlan_addr6_notifier_block); 909 register_inet6addr_notifier(&ipvlan_addr6_notifier_block);
864 register_inetaddr_notifier(&ipvlan_addr4_notifier_block); 910 register_inetaddr_notifier(&ipvlan_addr4_notifier_block);
865 911
866 err = ipvlan_link_register(&ipvlan_link_ops); 912 err = register_pernet_subsys(&ipvlan_net_ops);
867 if (err < 0) 913 if (err < 0)
868 goto error; 914 goto error;
869 915
916 err = ipvlan_link_register(&ipvlan_link_ops);
917 if (err < 0) {
918 unregister_pernet_subsys(&ipvlan_net_ops);
919 goto error;
920 }
921
870 return 0; 922 return 0;
871error: 923error:
872 unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); 924 unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block);
@@ -878,6 +930,7 @@ error:
878static void __exit ipvlan_cleanup_module(void) 930static void __exit ipvlan_cleanup_module(void)
879{ 931{
880 rtnl_link_unregister(&ipvlan_link_ops); 932 rtnl_link_unregister(&ipvlan_link_ops);
933 unregister_pernet_subsys(&ipvlan_net_ops);
881 unregister_netdevice_notifier(&ipvlan_notifier_block); 934 unregister_netdevice_notifier(&ipvlan_notifier_block);
882 unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); 935 unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block);
883 unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block); 936 unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block);