]> git.itanic.dy.fi Git - linux-stable/commitdiff
ipv4/fib: send notify when delete source address routes
authorHangbin Liu <liuhangbin@gmail.com>
Fri, 22 Sep 2023 07:55:08 +0000 (15:55 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 3 Oct 2023 07:00:40 +0000 (09:00 +0200)
After deleting an interface address in fib_del_ifaddr(), the function
scans the fib_info list for stray entries and calls fib_flush() and
fib_table_flush(). Then the stray entries will be deleted silently and no
RTM_DELROUTE notification will be sent.

This lack of notification can make routing daemons, or monitor like
`ip monitor route` miss the routing changes. e.g.

+ ip link add dummy1 type dummy
+ ip link add dummy2 type dummy
+ ip link set dummy1 up
+ ip link set dummy2 up
+ ip addr add 192.168.5.5/24 dev dummy1
+ ip route add 7.7.7.0/24 dev dummy2 src 192.168.5.5
+ ip -4 route
7.7.7.0/24 dev dummy2 scope link src 192.168.5.5
192.168.5.0/24 dev dummy1 proto kernel scope link src 192.168.5.5
+ ip monitor route
+ ip addr del 192.168.5.5/24 dev dummy1
Deleted 192.168.5.0/24 dev dummy1 proto kernel scope link src 192.168.5.5
Deleted broadcast 192.168.5.255 dev dummy1 table local proto kernel scope link src 192.168.5.5
Deleted local 192.168.5.5 dev dummy1 table local proto kernel scope host src 192.168.5.5

As Ido reminded, fib_table_flush() isn't only called when an address is
deleted, but also when an interface is deleted or put down. The lack of
notification in these cases is deliberate. And commit 7c6bb7d2faaf
("net/ipv6: Add knob to skip DELROUTE message on device down") introduced
a sysctl to make IPv6 behave like IPv4 in this regard. So we can't send
the route delete notify blindly in fib_table_flush().

To fix this issue, let's add a new flag in "struct fib_info" to track the
deleted prefer source address routes, and only send notify for them.

After update:
+ ip monitor route
+ ip addr del 192.168.5.5/24 dev dummy1
Deleted 192.168.5.0/24 dev dummy1 proto kernel scope link src 192.168.5.5
Deleted broadcast 192.168.5.255 dev dummy1 table local proto kernel scope link src 192.168.5.5
Deleted local 192.168.5.5 dev dummy1 table local proto kernel scope host src 192.168.5.5
Deleted 7.7.7.0/24 dev dummy2 scope link src 192.168.5.5

Suggested-by: Thomas Haller <thaller@redhat.com>
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
Acked-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Link: https://lore.kernel.org/r/20230922075508.848925-1-liuhangbin@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
include/net/ip_fib.h
net/ipv4/fib_semantics.c
net/ipv4/fib_trie.c

index f0c13864180e23e43fe065494fe4e42114c6ecd1..15de07d36540526fd4ede91f77af17eaf9ea1a45 100644 (file)
@@ -154,6 +154,7 @@ struct fib_info {
        int                     fib_nhs;
        bool                    fib_nh_is_v6;
        bool                    nh_updated;
+       bool                    pfsrc_removed;
        struct nexthop          *nh;
        struct rcu_head         rcu;
        struct fib_nh           fib_nh[];
index eafa4a033515782b4ade9a81ec12cb22f5e51e35..1ea82bc33ef14bd4411204c58ea5fece02783b35 100644 (file)
@@ -1887,6 +1887,7 @@ int fib_sync_down_addr(struct net_device *dev, __be32 local)
                        continue;
                if (fi->fib_prefsrc == local) {
                        fi->fib_flags |= RTNH_F_DEAD;
+                       fi->pfsrc_removed = true;
                        ret++;
                }
        }
index d13fb9e76b9718c674b82ea9069f98fb29f06425..9bdfdab906fe00cb048718eef932892181723a40 100644 (file)
@@ -2027,6 +2027,7 @@ void fib_table_flush_external(struct fib_table *tb)
 int fib_table_flush(struct net *net, struct fib_table *tb, bool flush_all)
 {
        struct trie *t = (struct trie *)tb->tb_data;
+       struct nl_info info = { .nl_net = net };
        struct key_vector *pn = t->kv;
        unsigned long cindex = 1;
        struct hlist_node *tmp;
@@ -2089,6 +2090,9 @@ int fib_table_flush(struct net *net, struct fib_table *tb, bool flush_all)
 
                        fib_notify_alias_delete(net, n->key, &n->leaf, fa,
                                                NULL);
+                       if (fi->pfsrc_removed)
+                               rtmsg_fib(RTM_DELROUTE, htonl(n->key), fa,
+                                         KEYLENGTH - fa->fa_slen, tb->tb_id, &info, 0);
                        hlist_del_rcu(&fa->fa_list);
                        fib_release_info(fa->fa_info);
                        alias_free_mem_rcu(fa);