Skip to content

Commit 16a16cd

Browse files
David Aherndavem330
authored andcommitted
net: ipv6: Change notifications for multipath delete to RTA_MULTIPATH
If an entire multipath route is deleted using prefix and len (without any nexthops), send a single RTM_DELROUTE notification with the full route using RTA_MULTIPATH. This is done by generating the skb before the route delete when all of the sibling routes are still present but sending it after the route has been removed from the FIB. The skip_notify flag is used to tell the lower fib code not to send notifications for the individual nexthop routes. If a route is deleted using RTA_MULTIPATH for any nexthops or a single nexthop entry is deleted, then the nexthops are deleted one at a time with notifications sent as each hop is deleted. This is necessary given that IPv6 allows individual hops within a route to be deleted. Signed-off-by: David Ahern <dsa@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 3b1137f commit 16a16cd

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

net/ipv6/ip6_fib.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1454,7 +1454,8 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
14541454

14551455
fib6_purge_rt(rt, fn, net);
14561456

1457-
inet6_rt_notify(RTM_DELROUTE, rt, info, 0);
1457+
if (!info->skip_notify)
1458+
inet6_rt_notify(RTM_DELROUTE, rt, info, 0);
14581459
rt6_release(rt);
14591460
}
14601461

net/ipv6/route.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
9898
struct sk_buff *skb);
9999
static void rt6_dst_from_metrics_check(struct rt6_info *rt);
100100
static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
101+
static size_t rt6_nlmsg_size(struct rt6_info *rt);
102+
static int rt6_fill_node(struct net *net,
103+
struct sk_buff *skb, struct rt6_info *rt,
104+
struct in6_addr *dst, struct in6_addr *src,
105+
int iif, int type, u32 portid, u32 seq,
106+
unsigned int flags);
101107

102108
#ifdef CONFIG_IPV6_ROUTE_INFO
103109
static struct rt6_info *rt6_add_route_info(struct net *net,
@@ -2146,6 +2152,7 @@ int ip6_del_rt(struct rt6_info *rt)
21462152
static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
21472153
{
21482154
struct nl_info *info = &cfg->fc_nlinfo;
2155+
struct sk_buff *skb = NULL;
21492156
struct fib6_table *table;
21502157
int err;
21512158

@@ -2155,6 +2162,20 @@ static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
21552162
if (rt->rt6i_nsiblings && cfg->fc_delete_all_nh) {
21562163
struct rt6_info *sibling, *next_sibling;
21572164

2165+
/* prefer to send a single notification with all hops */
2166+
skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
2167+
if (skb) {
2168+
u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
2169+
2170+
if (rt6_fill_node(info->nl_net, skb, rt,
2171+
NULL, NULL, 0, RTM_DELROUTE,
2172+
info->portid, seq, 0) < 0) {
2173+
kfree_skb(skb);
2174+
skb = NULL;
2175+
} else
2176+
info->skip_notify = 1;
2177+
}
2178+
21582179
list_for_each_entry_safe(sibling, next_sibling,
21592180
&rt->rt6i_siblings,
21602181
rt6i_siblings) {
@@ -2168,6 +2189,11 @@ static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
21682189
out:
21692190
write_unlock_bh(&table->tb6_lock);
21702191
ip6_rt_put(rt);
2192+
2193+
if (skb) {
2194+
rtnl_notify(skb, info->nl_net, info->portid, RTNLGRP_IPV6_ROUTE,
2195+
info->nlh, gfp_any());
2196+
}
21712197
return err;
21722198
}
21732199

0 commit comments

Comments
 (0)