Skip to content

Commit

Permalink
Allow shorthand delete of all nexthops in multipath IPv6 routes (#111)
Browse files Browse the repository at this point in the history
* Adding support for shorthand delete of all nexthops in multipath IPv6
route delete since FRR fills only prefix information for deleting IPv6
multipath route.
This was already supported by IPv4 but missing for IPv6. This commit
brings shorthand delete of IPv6 multipath routes.

Backporting changes from newer linux kernel
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/net/ipv6/route.c?h=v4.14.144&id=0ae8133586ad1c9be894411aaf8b17bb58c8efe5
  • Loading branch information
preetham-singh authored and lguohan committed Nov 7, 2019
1 parent feb42b0 commit 886d46f
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 0 deletions.
140 changes: 140 additions & 0 deletions patch/0001-net-ipv6-Allow-shorthand-delete-of-all-nexthops-in-m.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
From 055d25a3f712c2fcb16a171786e487739953d471 Mon Sep 17 00:00:00 2001
From: Preetham Singh <[email protected]>
Date: Wed, 18 Sep 2019 02:54:13 -0700
Subject: [PATCH] net: ipv6: Allow shorthand delete of all
nexthops in multipath route

This was already supported by IPv4 but missing for IPv6. This commit
brings shorthand delete of IPv6 multipath routes in kernel.

Successive delete of multi-path routes(32 paths) was not clearing all routes in kernel though frr was sending RTM_DELROUTE when last nexthop was getting deleted. Reason being For IPv6 delete route in kernel, expects all nhops to be sent. On counter part, IPv4 route delete in kernel does NOT expect all nhops to be sent. FRR currently doesnt send any nhops when operation is RTM_DELROUTE for both IPv4 & IPv6.

back porting below changes from newer version of kernel
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/net/ipv6/route.c?h=v4.14.144&id=0ae8133586ad1c9be894411aaf8b17bb58c8efe5

After importing above patch, there were no stale IPv6 routes in kernel.

Signed-off-by: Preetham Singh <[email protected]>
---
include/net/ip6_fib.h | 4 ++-
net/ipv6/route.c | 67 +++++++++++++++++++++++++++++++++++++++++--
2 files changed, 68 insertions(+), 3 deletions(-)

diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index a6bcb18..82ef4ba 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -37,7 +37,9 @@ struct fib6_config {
int fc_ifindex;
u32 fc_flags;
u32 fc_protocol;
- u32 fc_type; /* only 8 bits are used */
+ u16 fc_type; /* only 8 bits are used */
+ u16 fc_delete_all_nh : 1,
+ __unused : 15;

struct in6_addr fc_dst;
struct in6_addr fc_src;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 7dcd34f..9743662 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -98,6 +98,12 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk,
struct sk_buff *skb);
static void rt6_dst_from_metrics_check(struct rt6_info *rt);
static int rt6_score_route(struct rt6_info *rt, int oif, int strict);
+static size_t rt6_nlmsg_size(struct rt6_info *rt);
+static int rt6_fill_node(struct net *net,
+ struct sk_buff *skb, struct rt6_info *rt,
+ struct in6_addr *dst, struct in6_addr *src,
+ int iif, int type, u32 portid, u32 seq,
+ int prefix, int nowait, unsigned int flags);

#ifdef CONFIG_IPV6_ROUTE_INFO
static struct rt6_info *rt6_add_route_info(struct net *net,
@@ -2183,6 +2189,57 @@ int ip6_del_rt(struct rt6_info *rt)
return __ip6_del_rt(rt, &info);
}

+static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
+{
+ struct nl_info *info = &cfg->fc_nlinfo;
+ struct net *net = info->nl_net;
+ struct sk_buff *skb = NULL;
+ struct fib6_table *table;
+ int err = -ENOENT;
+
+ if (rt == net->ipv6.ip6_null_entry)
+ goto out_put;
+ table = rt->rt6i_table;
+ write_lock_bh(&table->tb6_lock);
+
+ if (rt->rt6i_nsiblings && cfg->fc_delete_all_nh) {
+ struct rt6_info *sibling, *next_sibling;
+
+ /* prefer to send a single notification with all hops */
+ skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any());
+ if (skb) {
+ u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
+
+ if (rt6_fill_node(net, skb, rt,
+ NULL, NULL, 0, RTM_DELROUTE,
+ info->portid, seq, 0, 0, 0) < 0) {
+ kfree_skb(skb);
+ skb = NULL;
+ }
+ }
+
+ list_for_each_entry_safe(sibling, next_sibling,
+ &rt->rt6i_siblings,
+ rt6i_siblings) {
+ err = fib6_del(sibling, info);
+ if (err)
+ goto out_unlock;
+ }
+ }
+
+ err = fib6_del(rt, info);
+out_unlock:
+ write_unlock_bh(&table->tb6_lock);
+out_put:
+ ip6_rt_put(rt);
+
+ if (skb) {
+ rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE,
+ info->nlh, gfp_any());
+ }
+ return err;
+}
+
static int ip6_route_del(struct fib6_config *cfg)
{
struct fib6_table *table;
@@ -2219,7 +2276,11 @@ static int ip6_route_del(struct fib6_config *cfg)
dst_hold(&rt->dst);
read_unlock_bh(&table->tb6_lock);

- return __ip6_del_rt(rt, &cfg->fc_nlinfo);
+ /* if gateway was specified only delete the one hop */
+ if (cfg->fc_flags & RTF_GATEWAY)
+ return __ip6_del_rt(rt, &cfg->fc_nlinfo);
+
+ return __ip6_del_rt_siblings(rt, cfg);
}
}
read_unlock_bh(&table->tb6_lock);
@@ -3167,8 +3228,10 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh)

if (cfg.fc_mp)
return ip6_route_multipath_del(&cfg);
- else
+ else {
+ cfg.fc_delete_all_nh = 1;
return ip6_route_del(&cfg);
+ }
}

static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh)
--
2.18.0

1 change: 1 addition & 0 deletions patch/series
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ mellanox-backport-introduce-tc-sample-action.patch
kernel-enable-psample-and-act_sample-drivers.patch
0000-net-Fix-netdev-adjacency-tracking.patch
0000-net-ipv6-ll-anycast-mcast-routes-on-dev.patch
0001-net-ipv6-Allow-shorthand-delete-of-all-nexthops-in-m.patch
#
# This series applies on GIT commit 1451b36b2b0d62178e42f648d8a18131af18f7d8
# Tkernel-sched-core-fix-cgroup-fork-race.patch
Expand Down

0 comments on commit 886d46f

Please sign in to comment.