#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
}
}
-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)
{
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;
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();
list_del(&nhge->nh_list);
free_percpu(nhge->stats);
}
+
+ return need_flush;
}
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);
}
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);
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 */
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