Skip to content

Commit 3133822

Browse files
Florian Westphaldavem330
authored andcommitted
ipvlan: use pernet operations and restrict l3s hooks to master netns
commit 4fbae7d ("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>
1 parent 86a5df1 commit 3133822

File tree

2 files changed

+70
-15
lines changed

2 files changed

+70
-15
lines changed

drivers/net/ipvlan/ipvlan.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <linux/netfilter.h>
2727
#include <net/ip.h>
2828
#include <net/ip6_route.h>
29+
#include <net/netns/generic.h>
2930
#include <net/rtnetlink.h>
3031
#include <net/route.h>
3132
#include <net/addrconf.h>
@@ -91,6 +92,7 @@ struct ipvl_addr {
9192

9293
struct ipvl_port {
9394
struct net_device *dev;
95+
possible_net_t pnet;
9496
struct hlist_head hlhead[IPVLAN_HASH_SIZE];
9597
struct list_head ipvlans;
9698
u16 mode;

drivers/net/ipvlan/ipvlan_main.c

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@
99

1010
#include "ipvlan.h"
1111

12-
static u32 ipvl_nf_hook_refcnt = 0;
12+
static unsigned int ipvlan_netid __read_mostly;
13+
14+
struct ipvlan_netns {
15+
unsigned int ipvl_nf_hook_refcnt;
16+
};
1317

1418
static struct nf_hook_ops ipvl_nfops[] __read_mostly = {
1519
{
@@ -35,28 +39,34 @@ static void ipvlan_adjust_mtu(struct ipvl_dev *ipvlan, struct net_device *dev)
3539
ipvlan->dev->mtu = dev->mtu;
3640
}
3741

38-
static int ipvlan_register_nf_hook(void)
42+
static int ipvlan_register_nf_hook(struct net *net)
3943
{
44+
struct ipvlan_netns *vnet = net_generic(net, ipvlan_netid);
4045
int err = 0;
4146

42-
if (!ipvl_nf_hook_refcnt) {
43-
err = _nf_register_hooks(ipvl_nfops, ARRAY_SIZE(ipvl_nfops));
47+
if (!vnet->ipvl_nf_hook_refcnt) {
48+
err = nf_register_net_hooks(net, ipvl_nfops,
49+
ARRAY_SIZE(ipvl_nfops));
4450
if (!err)
45-
ipvl_nf_hook_refcnt = 1;
51+
vnet->ipvl_nf_hook_refcnt = 1;
4652
} else {
47-
ipvl_nf_hook_refcnt++;
53+
vnet->ipvl_nf_hook_refcnt++;
4854
}
4955

5056
return err;
5157
}
5258

53-
static void ipvlan_unregister_nf_hook(void)
59+
static void ipvlan_unregister_nf_hook(struct net *net)
5460
{
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;
5665

57-
ipvl_nf_hook_refcnt--;
58-
if (!ipvl_nf_hook_refcnt)
59-
_nf_unregister_hooks(ipvl_nfops, ARRAY_SIZE(ipvl_nfops));
66+
vnet->ipvl_nf_hook_refcnt--;
67+
if (!vnet->ipvl_nf_hook_refcnt)
68+
nf_unregister_net_hooks(net, ipvl_nfops,
69+
ARRAY_SIZE(ipvl_nfops));
6070
}
6171

6272
static 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)
6979
if (port->mode != nval) {
7080
if (nval == IPVLAN_MODE_L3S) {
7181
/* New mode is L3S */
72-
err = ipvlan_register_nf_hook();
82+
err = ipvlan_register_nf_hook(read_pnet(&port->pnet));
7383
if (!err) {
7484
mdev->l3mdev_ops = &ipvl_l3mdev_ops;
7585
mdev->priv_flags |= IFF_L3MDEV_MASTER;
@@ -78,7 +88,7 @@ static int ipvlan_set_port_mode(struct ipvl_port *port, u16 nval)
7888
} else if (port->mode == IPVLAN_MODE_L3S) {
7989
/* Old mode was L3S */
8090
mdev->priv_flags &= ~IFF_L3MDEV_MASTER;
81-
ipvlan_unregister_nf_hook();
91+
ipvlan_unregister_nf_hook(read_pnet(&port->pnet));
8292
mdev->l3mdev_ops = NULL;
8393
}
8494
list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
@@ -111,6 +121,7 @@ static int ipvlan_port_create(struct net_device *dev)
111121
if (!port)
112122
return -ENOMEM;
113123

124+
write_pnet(&port->pnet, dev_net(dev));
114125
port->dev = dev;
115126
port->mode = IPVLAN_MODE_L3;
116127
INIT_LIST_HEAD(&port->ipvlans);
@@ -142,7 +153,7 @@ static void ipvlan_port_destroy(struct net_device *dev)
142153
dev->priv_flags &= ~IFF_IPVLAN_MASTER;
143154
if (port->mode == IPVLAN_MODE_L3S) {
144155
dev->priv_flags &= ~IFF_L3MDEV_MASTER;
145-
ipvlan_unregister_nf_hook();
156+
ipvlan_unregister_nf_hook(dev_net(dev));
146157
dev->l3mdev_ops = NULL;
147158
}
148159
netdev_rx_handler_unregister(dev);
@@ -673,6 +684,24 @@ static int ipvlan_device_event(struct notifier_block *unused,
673684
ipvlan->dev);
674685
break;
675686

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+
}
676705
case NETDEV_UNREGISTER:
677706
if (dev->reg_state != NETREG_UNREGISTERING)
678707
break;
@@ -854,6 +883,23 @@ static struct notifier_block ipvlan_addr6_notifier_block __read_mostly = {
854883
.notifier_call = ipvlan_addr6_event,
855884
};
856885

886+
static 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+
897+
static struct pernet_operations ipvlan_net_ops = {
898+
.id = &ipvlan_netid,
899+
.size = sizeof(struct ipvlan_netns),
900+
.exit = ipvlan_ns_exit,
901+
};
902+
857903
static int __init ipvlan_init_module(void)
858904
{
859905
int err;
@@ -863,10 +909,16 @@ static int __init ipvlan_init_module(void)
863909
register_inet6addr_notifier(&ipvlan_addr6_notifier_block);
864910
register_inetaddr_notifier(&ipvlan_addr4_notifier_block);
865911

866-
err = ipvlan_link_register(&ipvlan_link_ops);
912+
err = register_pernet_subsys(&ipvlan_net_ops);
867913
if (err < 0)
868914
goto error;
869915

916+
err = ipvlan_link_register(&ipvlan_link_ops);
917+
if (err < 0) {
918+
unregister_pernet_subsys(&ipvlan_net_ops);
919+
goto error;
920+
}
921+
870922
return 0;
871923
error:
872924
unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block);
@@ -878,6 +930,7 @@ static int __init ipvlan_init_module(void)
878930
static void __exit ipvlan_cleanup_module(void)
879931
{
880932
rtnl_link_unregister(&ipvlan_link_ops);
933+
unregister_pernet_subsys(&ipvlan_net_ops);
881934
unregister_netdevice_notifier(&ipvlan_notifier_block);
882935
unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block);
883936
unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block);

0 commit comments

Comments
 (0)