]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
ipv6: Handle multipath route deletion notification
authorIdo Schimmel <idosch@mellanox.com>
Mon, 23 Dec 2019 13:28:18 +0000 (15:28 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 25 Dec 2019 06:37:30 +0000 (22:37 -0800)
When an entire multipath route is deleted, only emit a notification if
it is the first route in the node. Emit a replace notification in case
the last sibling is followed by another route. Otherwise, emit a delete
notification.

Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Reviewed-by: Jiri Pirko <jiri@mellanox.com>
Reviewed-by: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv6/route.c

index c0809f52f9eff9486ff955cdf173fcf273fd2a91..646716a47cc9a8111a5237e524d3fe2976ba8e3c 100644 (file)
@@ -3749,6 +3749,7 @@ static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)
 
        if (rt->fib6_nsiblings && cfg->fc_delete_all_nh) {
                struct fib6_info *sibling, *next_sibling;
+               struct fib6_node *fn;
 
                /* prefer to send a single notification with all hops */
                skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
@@ -3764,7 +3765,32 @@ static int __ip6_del_rt_siblings(struct fib6_info *rt, struct fib6_config *cfg)
                                info->skip_notify = 1;
                }
 
+               /* 'rt' points to the first sibling route. If it is not the
+                * leaf, then we do not need to send a notification. Otherwise,
+                * we need to check if the last sibling has a next route or not
+                * and emit a replace or delete notification, respectively.
+                */
                info->skip_notify_kernel = 1;
+               fn = rcu_dereference_protected(rt->fib6_node,
+                                           lockdep_is_held(&table->tb6_lock));
+               if (rcu_access_pointer(fn->leaf) == rt) {
+                       struct fib6_info *last_sibling, *replace_rt;
+
+                       last_sibling = list_last_entry(&rt->fib6_siblings,
+                                                      struct fib6_info,
+                                                      fib6_siblings);
+                       replace_rt = rcu_dereference_protected(
+                                           last_sibling->fib6_next,
+                                           lockdep_is_held(&table->tb6_lock));
+                       if (replace_rt)
+                               call_fib6_entry_notifiers_replace(net,
+                                                                 replace_rt);
+                       else
+                               call_fib6_multipath_entry_notifiers(net,
+                                                      FIB_EVENT_ENTRY_DEL_TMP,
+                                                      rt, rt->fib6_nsiblings,
+                                                      NULL);
+               }
                call_fib6_multipath_entry_notifiers(net,
                                                    FIB_EVENT_ENTRY_DEL,
                                                    rt,