[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250807055634.113753-1-dongml2@chinatelecom.cn>
Date: Thu, 7 Aug 2025 13:56:34 +0800
From: Menglong Dong <menglong8.dong@...il.com>
To: idosch@...sch.org
Cc: dsahern@...nel.org,
andrew+netdev@...n.ch,
davem@...emloft.net,
edumazet@...gle.com,
kuba@...nel.org,
pabeni@...hat.com,
horms@...nel.org,
sdf@...ichev.me,
kuniyu@...gle.com,
ahmed.zaki@...el.com,
aleksander.lobakin@...el.com,
netdev@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: [PATCH net-next v2] net: vrf: don't down the interface when add slave
For now, cycle_netdev() will be called to flush the neighbor cache when
add slave by downing and upping the slave netdev. When the slave has
vlan devices, the data transmission can interrupted.
Optimize it by introducing the NETDEV_VRF_MASTER event. When a net device
is added to the slave of the vrf, the NETDEV_VRF_MASTER event will be
triggered, and the neighbor cache will be flushed, and the routes will be
moved to the corresponding table.
The moving of the routes across tables is tested with following command:
$ ip link add name dummy1 up type dummy
$ sysctl -wq net.ipv6.conf.dummy1.keep_addr_on_down=1
$ ip address add 192.0.2.1/24 dev dummy1
$ ip address add 2001:db8:1::1/64 dev dummy1
$ ip link add name vrf1 up type vrf table 100
$ ip link set dev dummy1 master vrf1
$ ip -6 r show table 100
local 2001:db8:1::1 dev dummy1 proto kernel metric 0 pref medium
2001:db8:1::/64 dev dummy1 proto kernel metric 256 pref medium
local fe80::cc26:8ff:fe02:ae95 dev dummy1 proto kernel metric 0 pref medium
fe80::/64 dev dummy1 proto kernel metric 256 pref medium
multicast ff00::/8 dev dummy1 proto kernel metric 256 pref medium
$ ip -4 r show table 100
192.0.2.0/24 dev dummy1 proto kernel scope link src 192.0.2.1
local 192.0.2.1 dev dummy1 proto kernel scope host src 192.0.2.1
broadcast 192.0.2.255 dev dummy1 proto kernel scope link src 192.0.2.1
Signed-off-by: Menglong Dong <dongml2@...natelecom.cn>
---
v2:
- introduce the NETDEV_VRF_MASTER
---
drivers/net/vrf.c | 6 ++----
include/linux/netdevice.h | 1 +
net/core/dev.c | 2 +-
net/ipv4/arp.c | 1 +
net/ipv4/fib_frontend.c | 3 +++
net/ipv6/addrconf.c | 6 +++++-
net/ipv6/ndisc.c | 1 +
7 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 3ccd649913b5..0fee1f46ef97 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -1042,15 +1042,13 @@ static int vrf_rtable_create(struct net_device *dev)
static void cycle_netdev(struct net_device *dev,
struct netlink_ext_ack *extack)
{
- unsigned int flags = dev->flags;
int ret;
if (!netif_running(dev))
return;
- ret = dev_change_flags(dev, flags & ~IFF_UP, extack);
- if (ret >= 0)
- ret = dev_change_flags(dev, flags, extack);
+ ret = call_netdevice_notifiers(NETDEV_VRF_MASTER, dev);
+ ret = notifier_to_errno(ret);
if (ret < 0) {
netdev_err(dev,
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 5e5de4b0a433..62f0f7f7bcee 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3159,6 +3159,7 @@ enum netdev_cmd {
NETDEV_OFFLOAD_XSTATS_REPORT_USED,
NETDEV_OFFLOAD_XSTATS_REPORT_DELTA,
NETDEV_XDP_FEAT_CHANGE,
+ NETDEV_VRF_MASTER,
};
const char *netdev_cmd_to_name(enum netdev_cmd cmd);
diff --git a/net/core/dev.c b/net/core/dev.c
index b28ce68830b2..cd5c3ae08487 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1853,7 +1853,7 @@ const char *netdev_cmd_to_name(enum netdev_cmd cmd)
N(SVLAN_FILTER_PUSH_INFO) N(SVLAN_FILTER_DROP_INFO)
N(PRE_CHANGEADDR) N(OFFLOAD_XSTATS_ENABLE) N(OFFLOAD_XSTATS_DISABLE)
N(OFFLOAD_XSTATS_REPORT_USED) N(OFFLOAD_XSTATS_REPORT_DELTA)
- N(XDP_FEAT_CHANGE)
+ N(XDP_FEAT_CHANGE) N(VRF_MASTER)
}
#undef N
return "UNKNOWN_NETDEV_EVENT";
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 5cfc1c939673..67d7c4c949a2 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1328,6 +1328,7 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event,
bool evict_nocarrier;
switch (event) {
+ case NETDEV_VRF_MASTER:
case NETDEV_CHANGEADDR:
neigh_changeaddr(&arp_tbl, dev);
rt_cache_flush(dev_net(dev));
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 6e1b94796f67..53de7b11e731 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -1510,6 +1510,9 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
return NOTIFY_DONE;
switch (event) {
+ case NETDEV_VRF_MASTER:
+ fib_disable_ip(dev, event, false);
+ fallthrough;
case NETDEV_UP:
in_dev_for_each_ifa_rtnl(ifa, in_dev) {
fib_add_ifaddr(ifa);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index f17a5dd4789f..c1f8c8a3e394 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3677,6 +3677,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
run_pending = 1;
fallthrough;
+ case NETDEV_VRF_MASTER:
case NETDEV_UP:
case NETDEV_CHANGE:
if (idev && idev->cnf.disable_ipv6)
@@ -3689,7 +3690,10 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
break;
}
- if (event == NETDEV_UP) {
+ if (event == NETDEV_VRF_MASTER)
+ addrconf_ifdown(dev, false);
+
+ if (event == NETDEV_UP || event == NETDEV_VRF_MASTER) {
/* restore routes for permanent addresses */
addrconf_permanent_addr(net, dev);
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 7d5abb3158ec..8db8c34b9108 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1858,6 +1858,7 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
bool evict_nocarrier;
switch (event) {
+ case NETDEV_VRF_MASTER:
case NETDEV_CHANGEADDR:
neigh_changeaddr(&nd_tbl, dev);
fib6_run_gc(0, net, false);
--
2.50.1
Powered by blists - more mailing lists