Plumb a bool value throughout the various nexthop removal functions, determined in the innermost __remove_nexthop_fib() (which still does the FIB flushing) and propagated up all callers. The next patch will make use of this signal to optimize the removal of multiple nexthops by moving the FIB flushing up the call hierarchy. Signed-off-by: Cosmin Ratiu --- net/ipv4/nexthop.c | 50 +++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c index f92fcc39fc4c..7177092d2605 100644 --- a/net/ipv4/nexthop.c +++ b/net/ipv4/nexthop.c @@ -20,7 +20,7 @@ #define NH_RES_DEFAULT_IDLE_TIMER (120 * HZ) #define NH_RES_DEFAULT_UNBALANCED_TIMER 0 /* No forced rebalancing. */ -static void remove_nexthop(struct net *net, struct nexthop *nh, +static bool remove_nexthop(struct net *net, struct nexthop *nh, struct nl_info *nlinfo); #define NH_DEV_HASHBITS 8 @@ -2016,7 +2016,7 @@ static void nh_hthr_group_rebalance(struct nh_group *nhg) } } -static void remove_nh_grp_entry(struct net *net, struct nh_grp_entry *nhge, +static bool remove_nh_grp_entry(struct net *net, struct nh_grp_entry *nhge, struct nl_info *nlinfo, struct list_head *deferred_free) { @@ -2033,10 +2033,8 @@ static void remove_nh_grp_entry(struct net *net, struct nh_grp_entry *nhge, newg = nhg->spare; /* last entry, keep it visible and remove the parent */ - if (nhg->num_nh == 1) { - remove_nexthop(net, nhp, nlinfo); - return; - } + if (nhg->num_nh == 1) + return remove_nexthop(net, nhp, nlinfo); newg->has_v4 = false; newg->is_multipath = nhg->is_multipath; @@ -2093,22 +2091,26 @@ static void remove_nh_grp_entry(struct net *net, struct nh_grp_entry *nhge, if (nlinfo) nexthop_notify(RTM_NEWNEXTHOP, nhp, nlinfo); + + return false; } -static void remove_nexthop_from_groups(struct net *net, struct nexthop *nh, +static bool remove_nexthop_from_groups(struct net *net, struct nexthop *nh, struct nl_info *nlinfo) { struct nh_grp_entry *nhge, *tmp; LIST_HEAD(deferred_free); + bool need_flush = false; /* If there is nothing to do, let's avoid the costly call to * synchronize_net() */ if (list_empty(&nh->grp_list)) - return; + return false; list_for_each_entry_safe(nhge, tmp, &nh->grp_list, nh_list) - remove_nh_grp_entry(net, nhge, nlinfo, &deferred_free); + need_flush |= remove_nh_grp_entry(net, nhge, nlinfo, + &deferred_free); /* make sure all see the newly published array before releasing rtnl */ synchronize_net(); @@ -2118,6 +2120,8 @@ static void remove_nexthop_from_groups(struct net *net, struct nexthop *nh, list_del(&nhge->nh_list); free_percpu(nhge->stats); } + + return need_flush; } static void remove_nexthop_group(struct nexthop *nh, struct nl_info *nlinfo) @@ -2142,17 +2146,15 @@ static void remove_nexthop_group(struct nexthop *nh, struct nl_info *nlinfo) } /* not called for nexthop replace */ -static void __remove_nexthop_fib(struct net *net, struct nexthop *nh) +static bool __remove_nexthop_fib(struct net *net, struct nexthop *nh) { + bool need_flush = !list_empty(&nh->fi_list); struct fib6_info *f6i; - bool do_flush = false; struct fib_info *fi; - list_for_each_entry(fi, &nh->fi_list, nh_list) { + list_for_each_entry(fi, &nh->fi_list, nh_list) fi->fib_flags |= RTNH_F_DEAD; - do_flush = true; - } - if (do_flush) + if (need_flush) fib_flush(net); spin_lock_bh(&nh->lock); @@ -2173,12 +2175,14 @@ static void __remove_nexthop_fib(struct net *net, struct nexthop *nh) } spin_unlock_bh(&nh->lock); + + return need_flush; } -static void __remove_nexthop(struct net *net, struct nexthop *nh, +static bool __remove_nexthop(struct net *net, struct nexthop *nh, struct nl_info *nlinfo) { - __remove_nexthop_fib(net, nh); + bool need_flush = __remove_nexthop_fib(net, nh); if (nh->is_group) { remove_nexthop_group(nh, nlinfo); @@ -2189,13 +2193,17 @@ static void __remove_nexthop(struct net *net, struct nexthop *nh, if (nhi->fib_nhc.nhc_dev) hlist_del(&nhi->dev_hash); - remove_nexthop_from_groups(net, nh, nlinfo); + need_flush |= remove_nexthop_from_groups(net, nh, nlinfo); } + + return need_flush; } -static void remove_nexthop(struct net *net, struct nexthop *nh, +static bool remove_nexthop(struct net *net, struct nexthop *nh, struct nl_info *nlinfo) { + bool need_flush; + call_nexthop_notifiers(net, NEXTHOP_EVENT_DEL, nh, NULL); /* remove from the tree */ @@ -2204,10 +2212,12 @@ static void remove_nexthop(struct net *net, struct nexthop *nh, if (nlinfo) nexthop_notify(RTM_DELNEXTHOP, nh, nlinfo); - __remove_nexthop(net, nh, nlinfo); + need_flush = __remove_nexthop(net, nh, nlinfo); nh_base_seq_inc(net); nexthop_put(nh); + + return need_flush; } /* if any FIB entries reference this nexthop, any dst entries -- 2.53.0