Skip to content

Commit d2f0c9b

Browse files
idoschdavem330
authored andcommitted
ipv6: Handle route deletion notification
For the purpose of route offload, when a single route is deleted, it is only of interest if it is the first route in the node or if it is sibling to such a route. In the first case, distinguish between several possibilities: 1. Route is the last route in the node. Emit a delete notification 2. Route is followed by a non-multipath route. Emit a replace notification for the non-multipath route. 3. Route is followed by a multipath route. Emit a replace notification for the multipath route. In the second case, only emit a delete notification to ensure the route is no longer used as a valid nexthop. Signed-off-by: Ido Schimmel <[email protected]> Reviewed-by: Jiri Pirko <[email protected]> Reviewed-by: David Ahern <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 9c6ecd3 commit d2f0c9b

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

include/net/ip6_fib.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@ int call_fib6_multipath_entry_notifiers(struct net *net,
487487
struct fib6_info *rt,
488488
unsigned int nsiblings,
489489
struct netlink_ext_ack *extack);
490+
int call_fib6_entry_notifiers_replace(struct net *net, struct fib6_info *rt);
490491
void fib6_rt_update(struct net *net, struct fib6_info *rt,
491492
struct nl_info *info);
492493
void inet6_rt_notify(int event, struct fib6_info *rt, struct nl_info *info,

net/ipv6/ip6_fib.c

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,18 @@ int call_fib6_multipath_entry_notifiers(struct net *net,
415415
return call_fib6_notifiers(net, event_type, &info.info);
416416
}
417417

418+
int call_fib6_entry_notifiers_replace(struct net *net, struct fib6_info *rt)
419+
{
420+
struct fib6_entry_notifier_info info = {
421+
.rt = rt,
422+
.nsiblings = rt->fib6_nsiblings,
423+
};
424+
425+
rt->fib6_table->fib_seq++;
426+
return call_fib6_notifiers(net, FIB_EVENT_ENTRY_REPLACE_TMP,
427+
&info.info);
428+
}
429+
418430
struct fib6_dump_arg {
419431
struct net *net;
420432
struct notifier_block *nb;
@@ -1910,13 +1922,29 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
19101922
static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
19111923
struct fib6_info __rcu **rtp, struct nl_info *info)
19121924
{
1925+
struct fib6_info *leaf, *replace_rt = NULL;
19131926
struct fib6_walker *w;
19141927
struct fib6_info *rt = rcu_dereference_protected(*rtp,
19151928
lockdep_is_held(&table->tb6_lock));
19161929
struct net *net = info->nl_net;
1930+
bool notify_del = false;
19171931

19181932
RT6_TRACE("fib6_del_route\n");
19191933

1934+
/* If the deleted route is the first in the node and it is not part of
1935+
* a multipath route, then we need to replace it with the next route
1936+
* in the node, if exists.
1937+
*/
1938+
leaf = rcu_dereference_protected(fn->leaf,
1939+
lockdep_is_held(&table->tb6_lock));
1940+
if (leaf == rt && !rt->fib6_nsiblings) {
1941+
if (rcu_access_pointer(rt->fib6_next))
1942+
replace_rt = rcu_dereference_protected(rt->fib6_next,
1943+
lockdep_is_held(&table->tb6_lock));
1944+
else
1945+
notify_del = true;
1946+
}
1947+
19201948
/* Unlink it */
19211949
*rtp = rt->fib6_next;
19221950
rt->fib6_node = NULL;
@@ -1934,6 +1962,14 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
19341962
if (rt->fib6_nsiblings) {
19351963
struct fib6_info *sibling, *next_sibling;
19361964

1965+
/* The route is deleted from a multipath route. If this
1966+
* multipath route is the first route in the node, then we need
1967+
* to emit a delete notification. Otherwise, we need to skip
1968+
* the notification.
1969+
*/
1970+
if (rt->fib6_metric == leaf->fib6_metric &&
1971+
rt6_qualify_for_ecmp(leaf))
1972+
notify_del = true;
19371973
list_for_each_entry_safe(sibling, next_sibling,
19381974
&rt->fib6_siblings, fib6_siblings)
19391975
sibling->fib6_nsiblings--;
@@ -1969,8 +2005,14 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
19692005

19702006
fib6_purge_rt(rt, fn, net);
19712007

1972-
if (!info->skip_notify_kernel)
2008+
if (!info->skip_notify_kernel) {
2009+
if (notify_del)
2010+
call_fib6_entry_notifiers(net, FIB_EVENT_ENTRY_DEL_TMP,
2011+
rt, NULL);
2012+
else if (replace_rt)
2013+
call_fib6_entry_notifiers_replace(net, replace_rt);
19732014
call_fib6_entry_notifiers(net, FIB_EVENT_ENTRY_DEL, rt, NULL);
2015+
}
19742016
if (!info->skip_notify)
19752017
inet6_rt_notify(RTM_DELROUTE, rt, info, 0);
19762018

0 commit comments

Comments
 (0)