All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC net-next 0/8] nexthop: Add support for active-backup nexthop type
@ 2020-06-10  3:49 David Ahern
  2020-06-10  3:49 ` [PATCH RFC net-next 1/8] nexthop: Rename nexthop_free_mpath David Ahern
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: David Ahern @ 2020-06-10  3:49 UTC (permalink / raw
  To: netdev; +Cc: davem, kuba, assogba.emery, dsahern, David Ahern

This set adds support for a new nexthop group - active-backup.
The intent is that the group describes a primary nexthop with a backup
option if the primary is not available. Since nexthop code removes
entries on carrier or admin down this really means the backup applies
when the neighbor entry for the active becomes invalid. In that case,
the lookup atomically switches to use the backup. I mentioned this use
case at LPC2019[0] as a follow on use case for the nexthop code.

The first 6 patches refactor existing code to get ready for a new
group type. The a-b group is added in patch 7 with selftests in
patch 8.

[0] https://linuxplumbersconf.org/event/4/contributions/434/attachments/251/436/nexthop-objects-talk.pdf

David Ahern (8):
  nexthop: Rename nexthop_free_mpath
  nexthop: Refactor nexthop_select_path
  nexthop: Refactor nexthop_for_each_fib6_nh
  nexthop: Move nexthop_get_nhc_lookup to nexthop.c
  nexthop: Move nexthop_uses_dev to nexthop.c
  nexthop: Add primary_only argument to nexthop_for_each_fib6_nh
  nexthop: Add support for active-backup nexthop type
  selftests: Add active-backup nexthop tests

 include/net/nexthop.h                       | 106 +++---
 include/uapi/linux/nexthop.h                |   1 +
 net/ipv4/fib_semantics.c                    |   6 +-
 net/ipv4/nexthop.c                          | 356 +++++++++++++++++---
 net/ipv6/ip6_fib.c                          |   4 +-
 net/ipv6/route.c                            |  37 +-
 tools/testing/selftests/net/fib_nexthops.sh | 334 +++++++++++++++++-
 7 files changed, 713 insertions(+), 131 deletions(-)

-- 
2.21.1 (Apple Git-122.3)


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH RFC net-next 1/8] nexthop: Rename nexthop_free_mpath
  2020-06-10  3:49 [PATCH RFC net-next 0/8] nexthop: Add support for active-backup nexthop type David Ahern
@ 2020-06-10  3:49 ` David Ahern
  2020-06-10  3:49 ` [PATCH RFC net-next 2/8] nexthop: Refactor nexthop_select_path David Ahern
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: David Ahern @ 2020-06-10  3:49 UTC (permalink / raw
  To: netdev; +Cc: davem, kuba, assogba.emery, dsahern, David Ahern

nexthop_free_mpath really should be nexthop_free_group. Rename it.

Signed-off-by: David Ahern <dsahern@kernel.org>
---
 net/ipv4/nexthop.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c
index 400a9f89ebdb..5ebc47d5ec56 100644
--- a/net/ipv4/nexthop.c
+++ b/net/ipv4/nexthop.c
@@ -69,7 +69,7 @@ static void nexthop_devhash_add(struct net *net, struct nh_info *nhi)
 	hlist_add_head(&nhi->dev_hash, head);
 }
 
-static void nexthop_free_mpath(struct nexthop *nh)
+static void nexthop_free_group(struct nexthop *nh)
 {
 	struct nh_group *nhg;
 	int i;
@@ -109,7 +109,7 @@ void nexthop_free_rcu(struct rcu_head *head)
 	struct nexthop *nh = container_of(head, struct nexthop, rcu);
 
 	if (nh->is_group)
-		nexthop_free_mpath(nh);
+		nexthop_free_group(nh);
 	else
 		nexthop_free_single(nh);
 
-- 
2.21.1 (Apple Git-122.3)


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH RFC net-next 2/8] nexthop: Refactor nexthop_select_path
  2020-06-10  3:49 [PATCH RFC net-next 0/8] nexthop: Add support for active-backup nexthop type David Ahern
  2020-06-10  3:49 ` [PATCH RFC net-next 1/8] nexthop: Rename nexthop_free_mpath David Ahern
@ 2020-06-10  3:49 ` David Ahern
  2020-06-10  3:49 ` [PATCH RFC net-next 3/8] nexthop: Refactor nexthop_for_each_fib6_nh David Ahern
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: David Ahern @ 2020-06-10  3:49 UTC (permalink / raw
  To: netdev; +Cc: davem, kuba, assogba.emery, dsahern, David Ahern

Move the ipv{4,6}_good_nh calls to a separate helper.

Signed-off-by: David Ahern <dsahern@kernel.org>
---
 net/ipv4/nexthop.c | 47 +++++++++++++++++++++++++++-------------------
 1 file changed, 28 insertions(+), 19 deletions(-)

diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c
index 5ebc47d5ec56..7d0a170821f3 100644
--- a/net/ipv4/nexthop.c
+++ b/net/ipv4/nexthop.c
@@ -536,6 +536,29 @@ static bool ipv4_good_nh(const struct fib_nh *nh)
 	return !!(state & NUD_VALID);
 }
 
+/* nexthops always check if it is good and does
+ * not rely on a sysctl for this behavior
+ */
+static bool good_nh(struct nexthop *nh)
+{
+	struct nh_info *nhi;
+	bool rc = false;
+
+	nhi = rcu_dereference(nh->nh_info);
+	switch (nhi->family) {
+	case AF_INET:
+		if (ipv4_good_nh(&nhi->fib_nh))
+			rc = true;
+		break;
+	case AF_INET6:
+		if (ipv6_good_nh(&nhi->fib6_nh))
+			rc = true;
+		break;
+	}
+
+	return rc;
+}
+
 struct nexthop *nexthop_select_path(struct nexthop *nh, int hash)
 {
 	struct nexthop *rc = NULL;
@@ -548,31 +571,17 @@ struct nexthop *nexthop_select_path(struct nexthop *nh, int hash)
 	nhg = rcu_dereference(nh->nh_grp);
 	for (i = 0; i < nhg->num_nh; ++i) {
 		struct nh_grp_entry *nhge = &nhg->nh_entries[i];
-		struct nh_info *nhi;
+		struct nexthop *nh;
 
 		if (hash > atomic_read(&nhge->upper_bound))
 			continue;
 
-		if (nhge->nh->is_fdb_nh)
-			return nhge->nh;
-
-		/* nexthops always check if it is good and does
-		 * not rely on a sysctl for this behavior
-		 */
-		nhi = rcu_dereference(nhge->nh->nh_info);
-		switch (nhi->family) {
-		case AF_INET:
-			if (ipv4_good_nh(&nhi->fib_nh))
-				return nhge->nh;
-			break;
-		case AF_INET6:
-			if (ipv6_good_nh(&nhi->fib6_nh))
-				return nhge->nh;
-			break;
-		}
+		nh = nhge->nh;
+		if (nh->is_fdb_nh || good_nh(nh))
+			return nh;
 
 		if (!rc)
-			rc = nhge->nh;
+			rc = nh;
 	}
 
 	return rc;
-- 
2.21.1 (Apple Git-122.3)


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH RFC net-next 3/8] nexthop: Refactor nexthop_for_each_fib6_nh
  2020-06-10  3:49 [PATCH RFC net-next 0/8] nexthop: Add support for active-backup nexthop type David Ahern
  2020-06-10  3:49 ` [PATCH RFC net-next 1/8] nexthop: Rename nexthop_free_mpath David Ahern
  2020-06-10  3:49 ` [PATCH RFC net-next 2/8] nexthop: Refactor nexthop_select_path David Ahern
@ 2020-06-10  3:49 ` David Ahern
  2020-06-10  3:49 ` [PATCH RFC net-next 4/8] nexthop: Move nexthop_get_nhc_lookup to nexthop.c David Ahern
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: David Ahern @ 2020-06-10  3:49 UTC (permalink / raw
  To: netdev; +Cc: davem, kuba, assogba.emery, dsahern, David Ahern

Refactor nexthop_for_each_fib6_nh moving standalone and group processing
into helpers. Prepatory patch for adding active-backup group.

Signed-off-by: David Ahern <dsahern@kernel.org>
---
 net/ipv4/nexthop.c | 48 +++++++++++++++++++++++++++++++---------------
 1 file changed, 33 insertions(+), 15 deletions(-)

diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c
index 7d0a170821f3..940f46a7d533 100644
--- a/net/ipv4/nexthop.c
+++ b/net/ipv4/nexthop.c
@@ -588,34 +588,52 @@ struct nexthop *nexthop_select_path(struct nexthop *nh, int hash)
 }
 EXPORT_SYMBOL_GPL(nexthop_select_path);
 
+static int nexthop_fib6_nh_cb(struct nexthop *nh,
+			      int (*cb)(struct fib6_nh *nh, void *arg),
+			      void *arg)
+{
+	struct nh_info *nhi;
+
+	nhi = rcu_dereference_rtnl(nh->nh_info);
+
+	return cb(&nhi->fib6_nh, arg);
+}
+
+static int nexthop_fib6_nhg_cb(struct nh_group *nhg,
+			       int (*cb)(struct fib6_nh *nh, void *arg),
+			       void *arg)
+{
+	int err;
+	int i;
+
+	for (i = 0; i < nhg->num_nh; i++) {
+		struct nh_grp_entry *nhge = &nhg->nh_entries[i];
+		struct nexthop *nh = nhge->nh;
+
+		err = nexthop_fib6_nh_cb(nh, cb, arg);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
 int nexthop_for_each_fib6_nh(struct nexthop *nh,
 			     int (*cb)(struct fib6_nh *nh, void *arg),
 			     void *arg)
 {
-	struct nh_info *nhi;
 	int err;
 
 	if (nh->is_group) {
 		struct nh_group *nhg;
-		int i;
 
 		nhg = rcu_dereference_rtnl(nh->nh_grp);
-		for (i = 0; i < nhg->num_nh; i++) {
-			struct nh_grp_entry *nhge = &nhg->nh_entries[i];
-
-			nhi = rcu_dereference_rtnl(nhge->nh->nh_info);
-			err = cb(&nhi->fib6_nh, arg);
-			if (err)
-				return err;
-		}
+		err = nexthop_fib6_nhg_cb(nhg, cb, arg);
 	} else {
-		nhi = rcu_dereference_rtnl(nh->nh_info);
-		err = cb(&nhi->fib6_nh, arg);
-		if (err)
-			return err;
+		err = nexthop_fib6_nh_cb(nh, cb, arg);
 	}
 
-	return 0;
+	return err;
 }
 EXPORT_SYMBOL_GPL(nexthop_for_each_fib6_nh);
 
-- 
2.21.1 (Apple Git-122.3)


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH RFC net-next 4/8] nexthop: Move nexthop_get_nhc_lookup to nexthop.c
  2020-06-10  3:49 [PATCH RFC net-next 0/8] nexthop: Add support for active-backup nexthop type David Ahern
                   ` (2 preceding siblings ...)
  2020-06-10  3:49 ` [PATCH RFC net-next 3/8] nexthop: Refactor nexthop_for_each_fib6_nh David Ahern
@ 2020-06-10  3:49 ` David Ahern
  2020-06-10  3:49 ` [PATCH RFC net-next 5/8] nexthop: Move nexthop_uses_dev " David Ahern
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: David Ahern @ 2020-06-10  3:49 UTC (permalink / raw
  To: netdev; +Cc: davem, kuba, assogba.emery, dsahern, David Ahern

nexthop_get_nhc_lookup is long enough for an inline and the
a-b checks are going to make it worse. Move to nexthop.c and
in the process refactor so that mpath code reuses single nh
lookup. Prepatory patch for adding active-backup group.

Signed-off-by: David Ahern <dsahern@kernel.org>
---
 include/net/nexthop.h | 29 +------------------------
 net/ipv4/nexthop.c    | 50 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+), 28 deletions(-)

diff --git a/include/net/nexthop.h b/include/net/nexthop.h
index e5122ba78efe..e95800798aa5 100644
--- a/include/net/nexthop.h
+++ b/include/net/nexthop.h
@@ -261,37 +261,10 @@ struct fib_nh_common *nexthop_fib_nhc(struct nexthop *nh, int nhsel)
 }
 
 /* called from fib_table_lookup with rcu_lock */
-static inline
 struct fib_nh_common *nexthop_get_nhc_lookup(const struct nexthop *nh,
 					     int fib_flags,
 					     const struct flowi4 *flp,
-					     int *nhsel)
-{
-	struct nh_info *nhi;
-
-	if (nh->is_group) {
-		struct nh_group *nhg = rcu_dereference(nh->nh_grp);
-		int i;
-
-		for (i = 0; i < nhg->num_nh; i++) {
-			struct nexthop *nhe = nhg->nh_entries[i].nh;
-
-			nhi = rcu_dereference(nhe->nh_info);
-			if (fib_lookup_good_nhc(&nhi->fib_nhc, fib_flags, flp)) {
-				*nhsel = i;
-				return &nhi->fib_nhc;
-			}
-		}
-	} else {
-		nhi = rcu_dereference(nh->nh_info);
-		if (fib_lookup_good_nhc(&nhi->fib_nhc, fib_flags, flp)) {
-			*nhsel = 0;
-			return &nhi->fib_nhc;
-		}
-	}
-
-	return NULL;
-}
+					     int *nhsel);
 
 static inline bool nexthop_uses_dev(const struct nexthop *nh,
 				    const struct net_device *dev)
diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c
index 940f46a7d533..c58ecc86b7a1 100644
--- a/net/ipv4/nexthop.c
+++ b/net/ipv4/nexthop.c
@@ -588,6 +588,56 @@ struct nexthop *nexthop_select_path(struct nexthop *nh, int hash)
 }
 EXPORT_SYMBOL_GPL(nexthop_select_path);
 
+static struct fib_nh_common *nhc_lookup_single(const struct nexthop *nh,
+					       int fib_flags,
+					       const struct flowi4 *flp,
+					       int *nhsel)
+{
+	struct nh_info *nhi;
+
+	nhi = rcu_dereference(nh->nh_info);
+	if (fib_lookup_good_nhc(&nhi->fib_nhc, fib_flags, flp)) {
+		*nhsel = 0;
+		return &nhi->fib_nhc;
+	}
+	return NULL;
+}
+
+static struct fib_nh_common *nhc_lookup_mpath(const struct nh_group *nhg,
+					      int fib_flags,
+					      const struct flowi4 *flp,
+					      int *nhsel)
+{
+	struct fib_nh_common *nhc;
+	int i;
+
+	for (i = 0; i < nhg->num_nh; i++) {
+		struct nexthop *nhe = nhg->nh_entries[i].nh;
+
+		nhc = nhc_lookup_single(nhe, fib_flags, flp, nhsel);
+		if (nhc) {
+			*nhsel = i;
+			return nhc;
+		}
+	}
+
+	return NULL;
+}
+
+struct fib_nh_common *nexthop_get_nhc_lookup(const struct nexthop *nh,
+					     int fib_flags,
+					     const struct flowi4 *flp,
+					     int *nhsel)
+{
+	if (nh->is_group) {
+		const struct nh_group *nhg = rcu_dereference(nh->nh_grp);
+
+		return nhc_lookup_mpath(nhg, fib_flags, flp, nhsel);
+	}
+
+	return nhc_lookup_single(nh, fib_flags, flp, nhsel);
+}
+
 static int nexthop_fib6_nh_cb(struct nexthop *nh,
 			      int (*cb)(struct fib6_nh *nh, void *arg),
 			      void *arg)
-- 
2.21.1 (Apple Git-122.3)


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH RFC net-next 5/8] nexthop: Move nexthop_uses_dev to nexthop.c
  2020-06-10  3:49 [PATCH RFC net-next 0/8] nexthop: Add support for active-backup nexthop type David Ahern
                   ` (3 preceding siblings ...)
  2020-06-10  3:49 ` [PATCH RFC net-next 4/8] nexthop: Move nexthop_get_nhc_lookup to nexthop.c David Ahern
@ 2020-06-10  3:49 ` David Ahern
  2020-06-10  3:49 ` [PATCH RFC net-next 6/8] nexthop: Add primary_only argument to nexthop_for_each_fib6_nh David Ahern
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: David Ahern @ 2020-06-10  3:49 UTC (permalink / raw
  To: netdev; +Cc: davem, kuba, assogba.emery, dsahern, David Ahern

nexthop_uses_dev is long enough for an inline and the a-b checks are
going to make it worse. Move to nexthop.c and in the process refactor
so that mpath code reuses single nh lookup. Prepatory patch for adding
active-backup group.

Signed-off-by: David Ahern <dsahern@kernel.org>
---
 include/net/nexthop.h | 25 +------------------------
 net/ipv4/nexthop.c    | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 24 deletions(-)

diff --git a/include/net/nexthop.h b/include/net/nexthop.h
index e95800798aa5..271d2cb92954 100644
--- a/include/net/nexthop.h
+++ b/include/net/nexthop.h
@@ -266,30 +266,7 @@ struct fib_nh_common *nexthop_get_nhc_lookup(const struct nexthop *nh,
 					     const struct flowi4 *flp,
 					     int *nhsel);
 
-static inline bool nexthop_uses_dev(const struct nexthop *nh,
-				    const struct net_device *dev)
-{
-	struct nh_info *nhi;
-
-	if (nh->is_group) {
-		struct nh_group *nhg = rcu_dereference(nh->nh_grp);
-		int i;
-
-		for (i = 0; i < nhg->num_nh; i++) {
-			struct nexthop *nhe = nhg->nh_entries[i].nh;
-
-			nhi = rcu_dereference(nhe->nh_info);
-			if (nhc_l3mdev_matches_dev(&nhi->fib_nhc, dev))
-				return true;
-		}
-	} else {
-		nhi = rcu_dereference(nh->nh_info);
-		if (nhc_l3mdev_matches_dev(&nhi->fib_nhc, dev))
-			return true;
-	}
-
-	return false;
-}
+bool nexthop_uses_dev(const struct nexthop *nh, const struct net_device *dev);
 
 static inline unsigned int fib_info_num_path(const struct fib_info *fi)
 {
diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c
index c58ecc86b7a1..0020ea2ecc9f 100644
--- a/net/ipv4/nexthop.c
+++ b/net/ipv4/nexthop.c
@@ -638,6 +638,41 @@ struct fib_nh_common *nexthop_get_nhc_lookup(const struct nexthop *nh,
 	return nhc_lookup_single(nh, fib_flags, flp, nhsel);
 }
 
+static bool nh_uses_dev_single(const struct nexthop *nh,
+			       const struct net_device *dev)
+{
+	const struct nh_info *nhi;
+
+	nhi = rcu_dereference(nh->nh_info);
+	return nhc_l3mdev_matches_dev(&nhi->fib_nhc, dev);
+}
+
+static bool nh_uses_dev_mpath(const struct nh_group *nhg,
+			      const struct net_device *dev)
+{
+	int i;
+
+	for (i = 0; i < nhg->num_nh; i++) {
+		struct nexthop *nhe = nhg->nh_entries[i].nh;
+
+		if (nh_uses_dev_single(nhe, dev))
+			return true;
+	}
+
+	return false;
+}
+
+bool nexthop_uses_dev(const struct nexthop *nh, const struct net_device *dev)
+{
+	if (nh->is_group) {
+		const struct nh_group *nhg = rcu_dereference(nh->nh_grp);
+
+		return nh_uses_dev_mpath(nhg, dev);
+	}
+
+	return nh_uses_dev_single(nh, dev);
+}
+
 static int nexthop_fib6_nh_cb(struct nexthop *nh,
 			      int (*cb)(struct fib6_nh *nh, void *arg),
 			      void *arg)
-- 
2.21.1 (Apple Git-122.3)


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH RFC net-next 6/8] nexthop: Add primary_only argument to nexthop_for_each_fib6_nh
  2020-06-10  3:49 [PATCH RFC net-next 0/8] nexthop: Add support for active-backup nexthop type David Ahern
                   ` (4 preceding siblings ...)
  2020-06-10  3:49 ` [PATCH RFC net-next 5/8] nexthop: Move nexthop_uses_dev " David Ahern
@ 2020-06-10  3:49 ` David Ahern
  2020-06-10  3:49 ` [PATCH RFC net-next 7/8] nexthop: Add support for active-backup nexthop type David Ahern
  2020-06-10  3:49 ` [PATCH RFC net-next 8/8] selftests: Add active-backup nexthop tests David Ahern
  7 siblings, 0 replies; 9+ messages in thread
From: David Ahern @ 2020-06-10  3:49 UTC (permalink / raw
  To: netdev; +Cc: davem, kuba, assogba.emery, dsahern, David Ahern

Follow on patch adds support for active-backup nexthops. Control
planes needs to always analyze all legs of the nexthops, but
datapath only wants to consider the primary.

Signed-off-by: David Ahern <dsahern@kernel.org>
---
 include/net/nexthop.h |  2 +-
 net/ipv4/nexthop.c    |  6 +++---
 net/ipv6/ip6_fib.c    |  4 ++--
 net/ipv6/route.c      | 37 ++++++++++++++++++++-----------------
 4 files changed, 26 insertions(+), 23 deletions(-)

diff --git a/include/net/nexthop.h b/include/net/nexthop.h
index 271d2cb92954..8cedadb902b6 100644
--- a/include/net/nexthop.h
+++ b/include/net/nexthop.h
@@ -346,7 +346,7 @@ static inline void nexthop_path_fib6_result(struct fib6_result *res, int hash)
 	}
 }
 
-int nexthop_for_each_fib6_nh(struct nexthop *nh,
+int nexthop_for_each_fib6_nh(struct nexthop *nh, bool primary_only,
 			     int (*cb)(struct fib6_nh *nh, void *arg),
 			     void *arg);
 
diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c
index 0020ea2ecc9f..8984e1e4058b 100644
--- a/net/ipv4/nexthop.c
+++ b/net/ipv4/nexthop.c
@@ -684,7 +684,7 @@ static int nexthop_fib6_nh_cb(struct nexthop *nh,
 	return cb(&nhi->fib6_nh, arg);
 }
 
-static int nexthop_fib6_nhg_cb(struct nh_group *nhg,
+static int nexthop_fib6_nhg_cb(struct nh_group *nhg, bool primary_only,
 			       int (*cb)(struct fib6_nh *nh, void *arg),
 			       void *arg)
 {
@@ -703,7 +703,7 @@ static int nexthop_fib6_nhg_cb(struct nh_group *nhg,
 	return 0;
 }
 
-int nexthop_for_each_fib6_nh(struct nexthop *nh,
+int nexthop_for_each_fib6_nh(struct nexthop *nh, bool primary_only,
 			     int (*cb)(struct fib6_nh *nh, void *arg),
 			     void *arg)
 {
@@ -713,7 +713,7 @@ int nexthop_for_each_fib6_nh(struct nexthop *nh,
 		struct nh_group *nhg;
 
 		nhg = rcu_dereference_rtnl(nh->nh_grp);
-		err = nexthop_fib6_nhg_cb(nhg, cb, arg);
+		err = nexthop_fib6_nhg_cb(nhg, primary_only, cb, arg);
 	} else {
 		err = nexthop_fib6_nh_cb(nh, cb, arg);
 	}
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 49ee89bbcba0..7e593f9d519d 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -1009,8 +1009,8 @@ static void fib6_drop_pcpu_from(struct fib6_info *f6i,
 			.table = table
 		};
 
-		nexthop_for_each_fib6_nh(f6i->nh, fib6_nh_drop_pcpu_from,
-					 &arg);
+		nexthop_for_each_fib6_nh(f6i->nh, false,
+					 fib6_nh_drop_pcpu_from, &arg);
 	} else {
 		struct fib6_nh *fib6_nh;
 
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 82cbb46a2a4f..e2bd3dc7194d 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -526,7 +526,7 @@ static struct fib6_nh *rt6_nh_dev_match(struct net *net, struct nexthop *nh,
 	if (nexthop_is_blackhole(nh))
 		return NULL;
 
-	if (nexthop_for_each_fib6_nh(nh, __rt6_nh_dev_match, &arg))
+	if (nexthop_for_each_fib6_nh(nh, true, __rt6_nh_dev_match, &arg))
 		return arg.nh;
 
 	return NULL;
@@ -827,7 +827,8 @@ static void __find_rr_leaf(struct fib6_info *f6i_start,
 				res->nh = nexthop_fib6_nh(f6i->nh);
 				return;
 			}
-			if (nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_find_match,
+			if (nexthop_for_each_fib6_nh(f6i->nh, true,
+						     rt6_nh_find_match,
 						     &arg)) {
 				matched = true;
 				nh = arg.nh;
@@ -1774,8 +1775,8 @@ static int rt6_nh_flush_exceptions(struct fib6_nh *nh, void *arg)
 void rt6_flush_exceptions(struct fib6_info *f6i)
 {
 	if (f6i->nh)
-		nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_flush_exceptions,
-					 f6i);
+		nexthop_for_each_fib6_nh(f6i->nh, false,
+					 rt6_nh_flush_exceptions, f6i);
 	else
 		fib6_nh_flush_exceptions(f6i->fib6_nh, f6i);
 }
@@ -1897,7 +1898,7 @@ static int rt6_remove_exception_rt(struct rt6_info *rt)
 		int rc;
 
 		/* rc = 1 means an entry was found */
-		rc = nexthop_for_each_fib6_nh(from->nh,
+		rc = nexthop_for_each_fib6_nh(from->nh, false,
 					      rt6_nh_remove_exception_rt,
 					      &arg);
 		return rc ? 0 : -ENOENT;
@@ -1973,7 +1974,8 @@ static void rt6_update_exception_stamp_rt(struct rt6_info *rt)
 			.gw = &rt->rt6i_gateway,
 		};
 
-		nexthop_for_each_fib6_nh(from->nh, fib6_nh_find_match, &arg);
+		nexthop_for_each_fib6_nh(from->nh, false, fib6_nh_find_match,
+					 &arg);
 
 		if (!arg.match)
 			goto unlock;
@@ -2166,8 +2168,8 @@ void rt6_age_exceptions(struct fib6_info *f6i,
 			.now = now
 		};
 
-		nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_age_exceptions,
-					 &arg);
+		nexthop_for_each_fib6_nh(f6i->nh, false,
+					 rt6_nh_age_exceptions, &arg);
 	} else {
 		fib6_nh_age_exceptions(f6i->fib6_nh, gc_args, now);
 	}
@@ -2768,7 +2770,7 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
 				.gw = &rt6->rt6i_gateway,
 			};
 
-			nexthop_for_each_fib6_nh(res.f6i->nh,
+			nexthop_for_each_fib6_nh(res.f6i->nh, true,
 						 fib6_nh_find_match, &arg);
 
 			/* fib6_info uses a nexthop that does not have fib6_nh
@@ -2959,7 +2961,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
 			if (nexthop_is_blackhole(rt->nh))
 				continue;
 			/* on match, res->nh is filled in and potentially ret */
-			if (nexthop_for_each_fib6_nh(rt->nh,
+			if (nexthop_for_each_fib6_nh(rt->nh, true,
 						     fib6_nh_redirect_match,
 						     &arg))
 				goto out;
@@ -3906,7 +3908,8 @@ static int ip6_del_cached_rt_nh(struct fib6_config *cfg, struct fib6_info *f6i)
 		.f6i = f6i
 	};
 
-	return nexthop_for_each_fib6_nh(f6i->nh, fib6_nh_del_cached_rt, &arg);
+	return nexthop_for_each_fib6_nh(f6i->nh, false,
+					fib6_nh_del_cached_rt, &arg);
 }
 
 static int ip6_route_del(struct fib6_config *cfg,
@@ -4096,7 +4099,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
 			.gw = &rt->rt6i_gateway,
 		};
 
-		nexthop_for_each_fib6_nh(res.f6i->nh,
+		nexthop_for_each_fib6_nh(res.f6i->nh, true,
 					 fib6_nh_find_match, &arg);
 
 		/* fib6_info uses a nexthop that does not have fib6_nh
@@ -4835,8 +4838,8 @@ static int rt6_mtu_change_route(struct fib6_info *f6i, void *p_arg)
 	arg->f6i = f6i;
 	if (f6i->nh) {
 		/* fib6_nh_mtu_change only returns 0, so this is safe */
-		return nexthop_for_each_fib6_nh(f6i->nh, fib6_nh_mtu_change,
-						arg);
+		return nexthop_for_each_fib6_nh(f6i->nh, false,
+						fib6_nh_mtu_change, arg);
 	}
 
 	return fib6_nh_mtu_change(f6i->fib6_nh, arg);
@@ -5381,7 +5384,7 @@ static size_t rt6_nlmsg_size(struct fib6_info *f6i)
 
 	if (f6i->nh) {
 		nexthop_len = nla_total_size(4); /* RTA_NH_ID */
-		nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_nlmsg_size,
+		nexthop_for_each_fib6_nh(f6i->nh, false, rt6_nh_nlmsg_size,
 					 &nexthop_len);
 	} else {
 		struct fib6_nh *nh = f6i->fib6_nh;
@@ -5636,7 +5639,7 @@ static bool fib6_info_uses_dev(const struct fib6_info *f6i,
 	if (f6i->nh) {
 		struct net_device *_dev = (struct net_device *)dev;
 
-		return !!nexthop_for_each_fib6_nh(f6i->nh,
+		return !!nexthop_for_each_fib6_nh(f6i->nh, true,
 						  fib6_info_nh_uses_dev,
 						  _dev);
 	}
@@ -5769,7 +5772,7 @@ int rt6_dump_route(struct fib6_info *rt, void *p_arg, unsigned int skip)
 
 		rcu_read_lock();
 		if (rt->nh) {
-			err = nexthop_for_each_fib6_nh(rt->nh,
+			err = nexthop_for_each_fib6_nh(rt->nh, false,
 						       rt6_nh_dump_exceptions,
 						       &w);
 		} else {
-- 
2.21.1 (Apple Git-122.3)


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH RFC net-next 7/8] nexthop: Add support for active-backup nexthop type
  2020-06-10  3:49 [PATCH RFC net-next 0/8] nexthop: Add support for active-backup nexthop type David Ahern
                   ` (5 preceding siblings ...)
  2020-06-10  3:49 ` [PATCH RFC net-next 6/8] nexthop: Add primary_only argument to nexthop_for_each_fib6_nh David Ahern
@ 2020-06-10  3:49 ` David Ahern
  2020-06-10  3:49 ` [PATCH RFC net-next 8/8] selftests: Add active-backup nexthop tests David Ahern
  7 siblings, 0 replies; 9+ messages in thread
From: David Ahern @ 2020-06-10  3:49 UTC (permalink / raw
  To: netdev; +Cc: davem, kuba, assogba.emery, dsahern, David Ahern

Add new active-backup group type. The intent is that the group describes
a primary nexthop with a backup option if the primary is not available.
Since nexthop code removes entries on carrier or admin down this really
means the backup applies when the neighbor entry for the active becomes
invalid. In that case the lookup atomically switches to use the backup.

Conceptually, the linkage is like this. For single path routes, a FIB
entry references a nexthop that is a an active-backup pair:
                                nexthop active
  { prefix }  -> a-b nexthop -<
                                nexthop backup

Alternatively, an active-backup nexthop can be one more entries in a
multipath route:
                                                     nexthop active
                                   nexthop 1 (ab) -<
  { prefix }  -> mpath nexthop -<    ...             nexthop backup
                                   nexthop N

The intent is to provide a fast failover option for routing daemons -
the primary goes down, notification is sent to userspace, and the backup
takes over until the daemon can adjust the routes.

For multipath routes this has the added benefit of providing an option
to limit the flows affected by a carrier or admin down event. Currently,
flows are hashed over the N-paths of a multipath route. If a path goes
dead, the leg is effectively removed and all flows are potentially
affected as the hashing consides now N-1 paths. With active-backup
nexthops an admin can setup a backup for each leg to minimize the
affected flows.

Most of this change is updating the group handling to account for
the a-b pair, especially in nexthop groups. Datapath lookups should
only consider the active nexthop unless it is determined bad. Route
notifications and lookups will only show the existence of the
active nexthop.

Signed-off-by: ASSOGBA Emery <assogba.emery@gmail.com>
Co-developed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David Ahern <dsahern@kernel.org>
---
 include/net/nexthop.h        |  50 ++++++++--
 include/uapi/linux/nexthop.h |   1 +
 net/ipv4/fib_semantics.c     |   6 +-
 net/ipv4/nexthop.c           | 186 ++++++++++++++++++++++++++++++++---
 4 files changed, 217 insertions(+), 26 deletions(-)

diff --git a/include/net/nexthop.h b/include/net/nexthop.h
index 8cedadb902b6..aee870bc8c0e 100644
--- a/include/net/nexthop.h
+++ b/include/net/nexthop.h
@@ -76,6 +76,7 @@ struct nh_group {
 	struct nh_group		*spare; /* spare group for removals */
 	u16			num_nh;
 	bool			mpath;
+	bool			active_backup;
 	bool			has_v4;
 	struct nh_grp_entry	nh_entries[];
 };
@@ -158,6 +159,17 @@ static inline bool nexthop_is_multipath(const struct nexthop *nh)
 	return false;
 }
 
+static inline bool nexthop_is_active_backup(const struct nexthop *nh)
+{
+	if (nh->is_group) {
+		struct nh_group *nh_grp;
+
+		nh_grp = rcu_dereference_rtnl(nh->nh_grp);
+		return nh_grp->active_backup;
+	}
+	return false;
+}
+
 struct nexthop *nexthop_select_path(struct nexthop *nh, int hash);
 
 static inline unsigned int nexthop_num_path(const struct nexthop *nh)
@@ -168,8 +180,7 @@ static inline unsigned int nexthop_num_path(const struct nexthop *nh)
 		struct nh_group *nh_grp;
 
 		nh_grp = rcu_dereference_rtnl(nh->nh_grp);
-		if (nh_grp->mpath)
-			rc = nh_grp->num_nh;
+		rc = nh_grp->num_nh;
 	}
 
 	return rc;
@@ -196,9 +207,18 @@ int nexthop_mpath_fill_node(struct sk_buff *skb, struct nexthop *nh,
 
 	for (i = 0; i < nhg->num_nh; i++) {
 		struct nexthop *nhe = nhg->nh_entries[i].nh;
-		struct nh_info *nhi = rcu_dereference_rtnl(nhe->nh_info);
-		struct fib_nh_common *nhc = &nhi->fib_nhc;
 		int weight = nhg->nh_entries[i].weight;
+		struct fib_nh_common *nhc;
+		struct nh_info *nhi;
+
+		if (nhe->is_group) {
+			struct nh_group *nhg_ab = rtnl_dereference(nhe->nh_grp);
+
+			/* group in group is active-backup. take primary */
+			nhe = nhg_ab->nh_entries[0].nh;
+		}
+		nhi = rcu_dereference_rtnl(nhe->nh_info);
+		nhc = &nhi->fib_nhc;
 
 		if (fib_add_nexthop(skb, nhc, weight, rt_family) < 0)
 			return -EMSGSIZE;
@@ -216,7 +236,7 @@ static inline bool nexthop_is_blackhole(const struct nexthop *nh)
 		struct nh_group *nh_grp;
 
 		nh_grp = rcu_dereference_rtnl(nh->nh_grp);
-		if (nh_grp->num_nh > 1)
+		if (nh_grp->active_backup || nh_grp->num_nh > 1)
 			return false;
 
 		nh = nh_grp->nh_entries[0].nh;
@@ -253,6 +273,16 @@ struct fib_nh_common *nexthop_fib_nhc(struct nexthop *nh, int nhsel)
 			nh = nexthop_mpath_select(nh_grp, nhsel);
 			if (!nh)
 				return NULL;
+
+			/* multipath with a-b path */
+			if (nh->is_group) {
+				nh_grp = rcu_dereference_rtnl(nh->nh_grp);
+				nh = nh_grp->nh_entries[0].nh;
+			}
+		} else if (nh_grp->active_backup) {
+			if (nhsel > 0)
+				return NULL;
+			nh = nh_grp->nh_entries[0].nh;
 		}
 	}
 
@@ -309,9 +339,13 @@ static inline struct fib6_nh *nexthop_fib6_nh(struct nexthop *nh)
 		struct nh_group *nh_grp;
 
 		nh_grp = rcu_dereference_rtnl(nh->nh_grp);
-		nh = nexthop_mpath_select(nh_grp, 0);
-		if (!nh)
-			return NULL;
+		nh = nh_grp->nh_entries[0].nh;
+
+		/* mpath with active-backup path */
+		if (nh->is_group) {
+			nh_grp = rcu_dereference_rtnl(nh->nh_grp);
+			nh = nh_grp->nh_entries[0].nh;
+		}
 	}
 
 	nhi = rcu_dereference_rtnl(nh->nh_info);
diff --git a/include/uapi/linux/nexthop.h b/include/uapi/linux/nexthop.h
index 2d4a1e784cf0..9566e1ac07fe 100644
--- a/include/uapi/linux/nexthop.h
+++ b/include/uapi/linux/nexthop.h
@@ -22,6 +22,7 @@ struct nexthop_grp {
 
 enum {
 	NEXTHOP_GRP_TYPE_MPATH,  /* default type if not specified */
+	NEXTHOP_GRP_TYPE_ACTIVE_BACKUP,
 	__NEXTHOP_GRP_TYPE_MAX,
 };
 
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index e53871e4a097..a218cd912de9 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -480,10 +480,10 @@ static inline size_t fib_nlmsg_size(struct fib_info *fi)
 		nhsize += 2 * nla_total_size(4);
 
 		/* grab encap info */
-		for (i = 0; i < fib_info_num_path(fi); i++) {
+		for (i = 0; i < nhs; i++) {
 			struct fib_nh_common *nhc = fib_info_nhc(fi, i);
 
-			if (nhc->nhc_lwtstate) {
+			if (nhc && nhc->nhc_lwtstate) {
 				/* RTA_ENCAP_TYPE */
 				nh_encapsize += lwtunnel_get_encap_size(
 						nhc->nhc_lwtstate);
@@ -1780,6 +1780,8 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
 			goto nla_put_failure;
 		if (nexthop_is_blackhole(fi->nh))
 			rtm->rtm_type = RTN_BLACKHOLE;
+		else if (nexthop_is_active_backup(fi->nh))
+			nhs = 1;
 		if (!fi->fib_net->ipv4.sysctl_nexthop_compat_mode)
 			goto offload;
 	}
diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c
index 8984e1e4058b..e7335a81198f 100644
--- a/net/ipv4/nexthop.c
+++ b/net/ipv4/nexthop.c
@@ -204,6 +204,9 @@ static int nla_put_nh_group(struct sk_buff *skb, struct nh_group *nhg)
 	if (nhg->mpath)
 		group_type = NEXTHOP_GRP_TYPE_MPATH;
 
+	if (nhg->active_backup)
+		group_type = NEXTHOP_GRP_TYPE_ACTIVE_BACKUP;
+
 	if (nla_put_u16(skb, NHA_GROUP_TYPE, group_type))
 		goto nla_put_failure;
 
@@ -433,6 +436,7 @@ static int nh_check_attr_fdb_group(struct nexthop *nh, u8 *nh_family,
 }
 
 static int nh_check_attr_group(struct net *net, struct nlattr *tb[],
+			       u16 nh_grp_type,
 			       struct netlink_ext_ack *extack)
 {
 	unsigned int len = nla_len(tb[NHA_GROUP]);
@@ -451,6 +455,13 @@ static int nh_check_attr_group(struct net *net, struct nlattr *tb[],
 	len /= sizeof(*nhg);
 
 	nhg = nla_data(tb[NHA_GROUP]);
+
+	if (nh_grp_type == NEXTHOP_GRP_TYPE_ACTIVE_BACKUP &&
+	    (len != 2 || nhg[0].weight || nhg[1].weight)) {
+		NL_SET_ERR_MSG(extack, "Active/backup group must have 2 nexthops and weight can not be set");
+		return -EINVAL;
+	}
+
 	for (i = 0; i < len; ++i) {
 		if (nhg[i].resvd1 || nhg[i].resvd2) {
 			NL_SET_ERR_MSG(extack, "Reserved fields in nexthop_grp must be 0");
@@ -468,8 +479,14 @@ static int nh_check_attr_group(struct net *net, struct nlattr *tb[],
 		}
 	}
 
-	if (tb[NHA_FDB])
+	if (tb[NHA_FDB]) {
+		if (nh_grp_type == NEXTHOP_GRP_TYPE_ACTIVE_BACKUP) {
+			NL_SET_ERR_MSG(extack, "Active/backup group not valid with fdb entries");
+			return -EINVAL;
+		}
 		nhg_fdb = 1;
+	}
+
 	nhg = nla_data(tb[NHA_GROUP]);
 	for (i = 0; i < len; ++i) {
 		struct nexthop *nh;
@@ -559,16 +576,43 @@ static bool good_nh(struct nexthop *nh)
 	return rc;
 }
 
-struct nexthop *nexthop_select_path(struct nexthop *nh, int hash)
+static struct nexthop *nh_select_path_ab(struct nh_group *nhg, int hash)
 {
 	struct nexthop *rc = NULL;
-	struct nh_group *nhg;
-	int i;
+	struct nexthop *p, *b;
+
+	switch (nhg->num_nh) {
+	case 2:
+		/* if primary is good, use it */
+		p = nhg->nh_entries[0].nh;
+		if (good_nh(p)) {
+			rc = p;
+			break;
+		}
 
-	if (!nh->is_group)
-		return nh;
+		/* try backup */
+		b = nhg->nh_entries[1].nh;
+		if (good_nh(b))
+			rc = b;
+		break;
+	case 1:
+		p = nhg->nh_entries[0].nh;
+		if (good_nh(p))
+			rc = p;
+		break;
+	default:
+		WARN_ON_ONCE(1);
+		break;
+	}
+
+	return rc;
+}
+
+static struct nexthop *nh_select_path_mpath(struct nh_group *nhg, int hash)
+{
+	struct nexthop *rc = NULL;
+	int i;
 
-	nhg = rcu_dereference(nh->nh_grp);
 	for (i = 0; i < nhg->num_nh; ++i) {
 		struct nh_grp_entry *nhge = &nhg->nh_entries[i];
 		struct nexthop *nh;
@@ -577,8 +621,17 @@ struct nexthop *nexthop_select_path(struct nexthop *nh, int hash)
 			continue;
 
 		nh = nhge->nh;
-		if (nh->is_fdb_nh || good_nh(nh))
+
+		/* group in a group; inner one is active/backup pair */
+		if (unlikely(nh->is_group)) {
+			struct nh_group *nhg = rcu_dereference(nh->nh_grp);
+
+			nh = nh_select_path_ab(nhg, hash);
+			if (nh)
+				return nh;
+		} else if (good_nh(nh)) {
 			return nh;
+		}
 
 		if (!rc)
 			rc = nh;
@@ -586,6 +639,23 @@ struct nexthop *nexthop_select_path(struct nexthop *nh, int hash)
 
 	return rc;
 }
+
+struct nexthop *nexthop_select_path(struct nexthop *nh, int hash)
+{
+	struct nh_group *nhg;
+	struct nexthop *rc;
+
+	if (!nh->is_group)
+		return nh;
+
+	nhg = rcu_dereference(nh->nh_grp);
+	if (nhg->active_backup)
+		rc = nh_select_path_ab(nhg, hash);
+	else
+		rc = nh_select_path_mpath(nhg, hash);
+
+	return rc;
+}
 EXPORT_SYMBOL_GPL(nexthop_select_path);
 
 static struct fib_nh_common *nhc_lookup_single(const struct nexthop *nh,
@@ -603,6 +673,17 @@ static struct fib_nh_common *nhc_lookup_single(const struct nexthop *nh,
 	return NULL;
 }
 
+/* active-backup only looks at primary */
+static struct fib_nh_common *nhc_lookup_ab(const struct nh_group *nhg,
+					   int fib_flags,
+					   const struct flowi4 *flp,
+					   int *nhsel)
+{
+	struct nexthop *nhe = nhg->nh_entries[0].nh;
+
+	return nhc_lookup_single(nhe, fib_flags, flp, nhsel);
+}
+
 static struct fib_nh_common *nhc_lookup_mpath(const struct nh_group *nhg,
 					      int fib_flags,
 					      const struct flowi4 *flp,
@@ -614,7 +695,14 @@ static struct fib_nh_common *nhc_lookup_mpath(const struct nh_group *nhg,
 	for (i = 0; i < nhg->num_nh; i++) {
 		struct nexthop *nhe = nhg->nh_entries[i].nh;
 
-		nhc = nhc_lookup_single(nhe, fib_flags, flp, nhsel);
+		if (nhe->is_group) {
+			const struct nh_group *nhg_ab;
+
+			nhg_ab = rcu_dereference(nhe->nh_grp);
+			nhc = nhc_lookup_ab(nhg_ab, fib_flags, flp, nhsel);
+		} else {
+			nhc = nhc_lookup_single(nhe, fib_flags, flp, nhsel);
+		}
 		if (nhc) {
 			*nhsel = i;
 			return nhc;
@@ -632,7 +720,10 @@ struct fib_nh_common *nexthop_get_nhc_lookup(const struct nexthop *nh,
 	if (nh->is_group) {
 		const struct nh_group *nhg = rcu_dereference(nh->nh_grp);
 
-		return nhc_lookup_mpath(nhg, fib_flags, flp, nhsel);
+		if (nhg->mpath)
+			return nhc_lookup_mpath(nhg, fib_flags, flp, nhsel);
+
+		return nhc_lookup_ab(nhg, fib_flags, flp, nhsel);
 	}
 
 	return nhc_lookup_single(nh, fib_flags, flp, nhsel);
@@ -647,6 +738,15 @@ static bool nh_uses_dev_single(const struct nexthop *nh,
 	return nhc_l3mdev_matches_dev(&nhi->fib_nhc, dev);
 }
 
+/* active-backup only looks at primary */
+static bool nh_uses_dev_ab(const struct nh_group *nhg,
+			   const struct net_device *dev)
+{
+	struct nexthop *nhe = nhg->nh_entries[0].nh;
+
+	return nh_uses_dev_single(nhe, dev);
+}
+
 static bool nh_uses_dev_mpath(const struct nh_group *nhg,
 			      const struct net_device *dev)
 {
@@ -655,8 +755,15 @@ static bool nh_uses_dev_mpath(const struct nh_group *nhg,
 	for (i = 0; i < nhg->num_nh; i++) {
 		struct nexthop *nhe = nhg->nh_entries[i].nh;
 
-		if (nh_uses_dev_single(nhe, dev))
+		if (nhe->is_group) {
+			const struct nh_group *nhg_ab;
+
+			nhg_ab = rcu_dereference(nhe->nh_grp);
+			if (nh_uses_dev_ab(nhg_ab, dev))
+				return true;
+		} else if (nh_uses_dev_single(nhe, dev)) {
 			return true;
+		}
 	}
 
 	return false;
@@ -667,7 +774,9 @@ bool nexthop_uses_dev(const struct nexthop *nh, const struct net_device *dev)
 	if (nh->is_group) {
 		const struct nh_group *nhg = rcu_dereference(nh->nh_grp);
 
-		return nh_uses_dev_mpath(nhg, dev);
+		if (nhg->mpath)
+			return nh_uses_dev_mpath(nhg, dev);
+		return nh_uses_dev_ab(nhg, dev);
 	}
 
 	return nh_uses_dev_single(nh, dev);
@@ -684,6 +793,28 @@ static int nexthop_fib6_nh_cb(struct nexthop *nh,
 	return cb(&nhi->fib6_nh, arg);
 }
 
+static int nexthop_fib6_ab_nhg_cb(struct nh_group *nhg, bool primary_only,
+				  int (*cb)(struct fib6_nh *nh, void *arg),
+				  void *arg)
+{
+	int err;
+	int i;
+
+	for (i = 0; i < nhg->num_nh; i++) {
+		struct nh_grp_entry *nhge = &nhg->nh_entries[i];
+		struct nexthop *nh = nhge->nh;
+
+		err = nexthop_fib6_nh_cb(nh, cb, arg);
+		if (err)
+			return err;
+
+		if (primary_only)
+			break;
+	}
+
+	return 0;
+}
+
 static int nexthop_fib6_nhg_cb(struct nh_group *nhg, bool primary_only,
 			       int (*cb)(struct fib6_nh *nh, void *arg),
 			       void *arg)
@@ -695,7 +826,17 @@ static int nexthop_fib6_nhg_cb(struct nh_group *nhg, bool primary_only,
 		struct nh_grp_entry *nhge = &nhg->nh_entries[i];
 		struct nexthop *nh = nhge->nh;
 
-		err = nexthop_fib6_nh_cb(nh, cb, arg);
+		if (unlikely(nh->is_group)) {
+			struct nh_group *nhg2;
+
+			nhg2 = rcu_dereference(nh->nh_grp);
+			/* group in group is active/backup */
+			err = nexthop_fib6_ab_nhg_cb(nhg2, primary_only,
+						     cb, arg);
+		} else {
+			err = nexthop_fib6_nh_cb(nh, cb, arg);
+		}
+
 		if (err)
 			return err;
 	}
@@ -899,6 +1040,7 @@ static void remove_nh_grp_entry(struct net *net, struct nh_grp_entry *nhge,
 
 	newg->has_v4 = nhg->has_v4;
 	newg->mpath = nhg->mpath;
+	newg->active_backup = nhg->active_backup;
 	newg->num_nh = nhg->num_nh;
 
 	/* copy old entries to new except the one getting removed */
@@ -941,7 +1083,8 @@ static void remove_nexthop_from_groups(struct net *net, struct nexthop *nh,
 	synchronize_rcu();
 }
 
-static void remove_nexthop_group(struct nexthop *nh, struct nl_info *nlinfo)
+static void remove_nexthop_group(struct net *net, struct nexthop *nh,
+				 struct nl_info *nlinfo)
 {
 	struct nh_group *nhg = rcu_dereference_rtnl(nh->nh_grp);
 	int i, num_nh = nhg->num_nh;
@@ -954,6 +1097,9 @@ static void remove_nexthop_group(struct nexthop *nh, struct nl_info *nlinfo)
 
 		list_del_init(&nhge->nh_list);
 	}
+
+	if (nhg->active_backup)
+		remove_nexthop_from_groups(net, nh, nlinfo);
 }
 
 /* not called for nexthop replace */
@@ -987,7 +1133,7 @@ static void __remove_nexthop(struct net *net, struct nexthop *nh,
 	__remove_nexthop_fib(net, nh);
 
 	if (nh->is_group) {
-		remove_nexthop_group(nh, nlinfo);
+		remove_nexthop_group(net, nh, nlinfo);
 	} else {
 		struct nh_info *nhi;
 
@@ -1043,6 +1189,11 @@ static int replace_nexthop_grp(struct net *net, struct nexthop *old,
 	oldg = rtnl_dereference(old->nh_grp);
 	newg = rtnl_dereference(new->nh_grp);
 
+	if (oldg->active_backup ^ newg->active_backup) {
+		NL_SET_ERR_MSG(extack, "Can not change group type with replace");
+		return -EINVAL;
+	}
+
 	/* update parents - used by nexthop code for cleanup */
 	for (i = 0; i < newg->num_nh; i++)
 		newg->nh_entries[i].nh_parent = old;
@@ -1330,6 +1481,9 @@ static struct nexthop *nexthop_create_group(struct net *net,
 	if (cfg->nh_fdb)
 		nh->is_fdb_nh = 1;
 
+	if (cfg->nh_grp_type == NEXTHOP_GRP_TYPE_ACTIVE_BACKUP)
+		nhg->active_backup = 1;
+
 	rcu_assign_pointer(nh->nh_grp, nhg);
 
 	return nh;
@@ -1594,7 +1748,7 @@ static int rtm_to_nh_config(struct net *net, struct sk_buff *skb,
 			NL_SET_ERR_MSG(extack, "Invalid group type");
 			goto out;
 		}
-		err = nh_check_attr_group(net, tb, extack);
+		err = nh_check_attr_group(net, tb, cfg->nh_grp_type, extack);
 
 		/* no other attributes should be set */
 		goto out;
-- 
2.21.1 (Apple Git-122.3)


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH RFC net-next 8/8] selftests: Add active-backup nexthop tests
  2020-06-10  3:49 [PATCH RFC net-next 0/8] nexthop: Add support for active-backup nexthop type David Ahern
                   ` (6 preceding siblings ...)
  2020-06-10  3:49 ` [PATCH RFC net-next 7/8] nexthop: Add support for active-backup nexthop type David Ahern
@ 2020-06-10  3:49 ` David Ahern
  7 siblings, 0 replies; 9+ messages in thread
From: David Ahern @ 2020-06-10  3:49 UTC (permalink / raw
  To: netdev; +Cc: davem, kuba, assogba.emery, dsahern, David Ahern

Signed-off-by: David Ahern <dsahern@kernel.org>
---
 tools/testing/selftests/net/fib_nexthops.sh | 334 +++++++++++++++++++-
 1 file changed, 330 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh
index dee567f7576a..4db390438885 100755
--- a/tools/testing/selftests/net/fib_nexthops.sh
+++ b/tools/testing/selftests/net/fib_nexthops.sh
@@ -5,11 +5,21 @@
 #   2001:db8:91::1     |       2001:db8:91::2  |
 #   172.16.1.1         |       172.16.1.2      |
 #            veth1 <---|---> veth2             |
-#                      |              veth5 <--|--> veth6  172.16.101.1
+#                      |              veth6 <--|--> veth5  172.16.101.1
 #            veth3 <---|---> veth4             |           2001:db8:101::1
 #   172.16.2.1         |       172.16.2.2      |
 #   2001:db8:92::1     |       2001:db8:92::2  |
 #
+# For active/backup testing:
+# ns: me               | ns: peer2             | ns: remote
+#   2001:db8:81::1     |       2001:db8:81::2  |
+#   172.16.81.1        |       172.16.81.2     |
+#           veth21 <---|---> veth22            |
+#                      |             veth26 <--|--> veth25 <--> br
+#           veth23 <---|---> veth24            |
+#   172.16.82.1        |       172.16.82.2     |
+#   2001:db8:82::1     |       2001:db8:82::2  |
+#
 # This test is for checking IPv4 and IPv6 FIB behavior with nexthop
 # objects. Device reference counts and network namespace cleanup tested
 # by use of network namespace for peer.
@@ -19,8 +29,8 @@ ret=0
 ksft_skip=4
 
 # all tests in this script. Can be overridden with -t option
-IPV4_TESTS="ipv4_fcnal ipv4_grp_fcnal ipv4_withv6_fcnal ipv4_fcnal_runtime ipv4_large_grp ipv4_compat_mode ipv4_fdb_grp_fcnal ipv4_torture"
-IPV6_TESTS="ipv6_fcnal ipv6_grp_fcnal ipv6_fcnal_runtime ipv6_large_grp ipv6_compat_mode ipv6_fdb_grp_fcnal ipv6_torture"
+IPV4_TESTS="ipv4_fcnal ipv4_grp_fcnal ipv4_withv6_fcnal ipv4_fcnal_runtime ipv4_large_grp ipv4_compat_mode ipv4_fdb_grp_fcnal ipv4_torture ipv4_ab_group"
+IPV6_TESTS="ipv6_fcnal ipv6_grp_fcnal ipv6_fcnal_runtime ipv6_large_grp ipv6_compat_mode ipv6_fdb_grp_fcnal ipv6_torture ipv6_ab_group"
 
 ALL_TESTS="basic ${IPV4_TESTS} ${IPV6_TESTS}"
 TESTS="${ALL_TESTS}"
@@ -179,11 +189,60 @@ setup()
 	set +e
 }
 
+setup_ab()
+{
+	create_ns peer2
+
+	set -e
+	$IP li add veth21 type veth peer name veth22
+	$IP li set veth21 up
+	$IP addr add 172.16.81.1/24 dev veth21
+	$IP -6 addr add 2001:db8:81::1/64 dev veth21 nodad
+
+	$IP li add veth23 type veth peer name veth24
+	$IP li set veth23 up
+	$IP addr add 172.16.82.1/24 dev veth23
+	$IP -6 addr add 2001:db8:82::1/64 dev veth23 nodad
+
+	$IP li set veth22 netns peer2 up
+	ip -netns peer2 addr add 172.16.81.2/24 dev veth22
+	ip -netns peer2 -6 addr add 2001:db8:81::2/64 dev veth22 nodad
+
+	$IP li set veth24 netns peer2 up
+	ip -netns peer2 addr add 172.16.82.2/24 dev veth24
+	ip -netns peer2 -6 addr add 2001:db8:82::2/64 dev veth24 nodad
+
+	ip -netns remote li set veth5 down
+	ip -netns remote addr flush dev veth5
+	ip -netns remote li add br0 type bridge
+	ip -netns remote li add veth25 type veth peer name veth26
+	ip -netns remote li set veth25 master br0 up
+	ip -netns remote li set veth5 master br0 up
+	ip -netns remote li set br0 up
+
+	ip -netns remote addr add dev br0 172.16.101.1/24
+	ip -netns remote -6 addr add dev br0 2001:db8:101::1/64 nodad
+
+	ip -netns remote li set veth26 netns peer2 up
+	ip -netns peer2 addr add dev veth26 172.16.101.3/24
+	ip -netns peer2 -6 addr add dev veth26 2001:db8:101::3/64 nodad
+
+	ip -netns remote ro add 172.16.1.0/24 nexthop via 172.16.101.2
+	ip -netns remote ro add 172.16.2.0/24 nexthop via 172.16.101.2
+	ip -netns remote ro add 172.16.81.0/24 nexthop via 172.16.101.3
+	ip -netns remote ro add 172.16.82.0/24 nexthop via 172.16.101.3
+	ip -netns remote -6 ro add 2001:db8:91::/64 nexthop via 2001:db8:101::2
+	ip -netns remote -6 ro add 2001:db8:92::/64 nexthop via 2001:db8:101::2
+	ip -netns remote -6 ro add 2001:db8:81::/64 nexthop via 2001:db8:101::3
+	ip -netns remote -6 ro add 2001:db8:82::/64 nexthop via 2001:db8:101::3
+	set +e
+}
+
 cleanup()
 {
 	local ns
 
-	for ns in me peer remote; do
+	for ns in me peer peer2 remote; do
 		ip netns del ${ns} 2>/dev/null
 	done
 }
@@ -335,6 +394,273 @@ stop_ip_monitor()
 	return $rc
 }
 
+################################################################################
+# active-backup nexthops
+
+check_nexthop_ab_support()
+{
+	$IP nexthop help 2>&1 | grep -q active-backup
+	if [ $? -ne 0 ]; then
+		echo "SKIP: iproute2 too old, missing active-backup nexthop support"
+		return $ksft_skip
+	fi
+}
+
+ipv6_ab_group()
+{
+	local rc
+
+	echo
+	echo "IPv6 active-backup groups"
+	echo "-------------------------"
+
+	check_nexthop_ab_support
+	if [ $? -eq $ksft_skip ]; then
+		return $ksft_skip
+	fi
+
+	setup_ab
+
+	run_cmd "$IP nexthop add id 11 via 2001:db8:91::2 dev veth1"
+	run_cmd "$IP nexthop add id 12 via 2001:db8:81::2 dev veth21"
+	run_cmd "$IP nexthop add id 101 group 11/12 active-backup"
+	check_nexthop "id 101" "id 101 group 11/12 active-backup"
+	log_test $? 0 "Create active-backup group"
+
+	run_cmd "$IP ro add 2001:db8:101::/64 nhid 101"
+	check_route6 "2001:db8:101::1" "2001:db8:101::/64 nhid 101 via 2001:db8:91::2 dev veth1 metric 1024"
+	log_test $? 0 "Route list shows active device"
+
+	$IP -o ro get 2001:db8:101::1 2>/dev/null | grep -q "dev veth1"
+	log_test $? 0 "Route get shows active device"
+
+	# carrier down or admin down on nexthop device removes that entry
+	run_cmd "ip -netns peer li set veth2 down"
+	check_nexthop "id 101" "id 101 group 12 active-backup"
+	log_test $? 0 "Carrier down removes active"
+
+	$IP -o ro get 2001:db8:101::1 2>/dev/null | grep -q "dev veth21"
+	log_test $? 0 "Route get shows backup device"
+
+	run_cmd "$IP li set veth21 down"
+	$IP nexthop sh id 101 2>/dev/null
+	log_test $? 2 "Link down on backup removes nexthop"
+
+	check_route "2001:db8:101::1" ""
+	log_test $? 0 "Route removed after a-b nexthop removed"
+
+	# restore device state
+	run_cmd "ip -netns peer li set veth2 up"
+	run_cmd "$IP li set veth21 up"
+
+	# a/b with mpath
+	run_cmd "$IP nexthop flush"
+	run_cmd "$IP nexthop add id 11 via 2001:db8:91::2 dev veth1"
+	run_cmd "$IP nexthop add id 12 via 2001:db8:92::2 dev veth3"
+	run_cmd "$IP nexthop add id 21 via 2001:db8:81::2 dev veth21"
+	run_cmd "$IP nexthop add id 22 via 2001:db8:82::2 dev veth23"
+	run_cmd "$IP nexthop add id 101 group 11/21 active-backup"
+	run_cmd "$IP nexthop add id 102 group 12/22 active-backup"
+	run_cmd "$IP nexthop add id 103 group 101/102"
+	log_test $? 0 "Multipath with active-backup paths"
+
+	run_cmd "$IP nexthop ls"
+	run_cmd "$IP ro add 2001:db8:101::/64 nhid 103"
+	run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
+	log_test $? 0 "ping with multipath containing active-backup paths"
+
+	run_cmd "ip -netns peer li set veth2 down"
+	check_nexthop "id 103" "id 103 group 101/102"
+	log_test $? 0 "Multipath still shows 2 paths after carrier down in a/b"
+
+	run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
+	log_test $? 0 "ping with still works after carrier down"
+
+	run_cmd "ip -netns peer li set veth2 up"
+	run_cmd "$IP nexthop ls"
+	run_cmd "$IP -6 ro ls"
+
+	run_cmd "$IP li set veth21 down"
+	check_nexthop "id 103" "id 103 group 102"
+	log_test $? 0 "Multipath shows 1 path after admin down on new active"
+	run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
+	log_test $? 0 "ping with still works after mpath loss of a-b path"
+
+	run_cmd "$IP li set veth21 up"
+	run_cmd "$IP nexthop ls"
+	run_cmd "$IP -6 ro ls"
+
+	#
+	# negative tests
+	#
+	# active points to invalid gw
+	run_cmd "$IP nexthop flush"
+	run_cmd "$IP nexthop add id 11 via 2001:db8:91::3 dev veth1"
+	run_cmd "$IP nexthop add id 12 via 2001:db8:81::2 dev veth21"
+	run_cmd "$IP nexthop add id 101 group 11/12 active-backup"
+	run_cmd "$IP ro add 2001:db8:101::/64 nhid 101"
+
+	# failed neigh for gateway - should fallback to backup
+	run_cmd "${IP} -6 neigh add 2001:db8:91::3 dev veth1 nud failed"
+	$IP -o ro get 2001:db8:101::1 2>/dev/null | grep -q "dev veth21"
+	log_test $? 0 "Route get shows backup device with invalid neigh"
+
+	run_cmd "$IP nexthop flush"
+	run_cmd "$IP nexthop add id 11 via 2001:db8:91::2 dev veth1"
+	run_cmd "$IP nexthop add id 12 via 2001:db8:92::2 dev veth3"
+	run_cmd "$IP nexthop add id 13 blackhole"
+	run_cmd "$IP nexthop add id 21 via 2001:db8:81::2 dev veth21"
+	run_cmd "$IP nexthop add id 22 via 2001:db8:82::2 dev veth23"
+
+	# must have 2 entries of equal weight
+	run_cmd "$IP nexthop add id 101 group 11 active-backup"
+	log_test $? 2 "Active-backup nexthop can not have 1 entry"
+	run_cmd "$IP nexthop add id 101 group 11/12/21 active-backup"
+	log_test $? 2 "Active-backup nexthop can not have more than 2 entries"
+	run_cmd "$IP nexthop add id 101 group 11,5/21,4 active-backup"
+	log_test $? 2 "Active-backup nexthops must have equal weight"
+	run_cmd "$IP nexthop add id 101 group 11,3/21,3 active-backup"
+	log_test $? 2 "Active-backup nexthops must have default weight"
+
+	# can not replace a/b group with mpath
+	run_cmd "$IP nexthop add id 101 group 11/21 active-backup"
+	run_cmd "$IP nexthop replace id 101 group 11/21 mpath"
+	log_test $? 2 "Can not change group type"
+
+	# a/b group can not have blackhole
+	run_cmd "$IP nexthop add id 102 group 11/13 active-backup"
+	log_test $? 2 "Active-backup can use blackhole as a path"
+}
+
+ipv4_ab_group()
+{
+	local rc
+
+	echo
+	echo "IPv4 active-backup groups"
+	echo "-------------------------"
+
+	check_nexthop_ab_support
+	if [ $? -eq $ksft_skip ]; then
+		return $ksft_skip
+	fi
+
+	setup_ab
+
+	run_cmd "$IP nexthop add id 11 via 172.16.1.2 dev veth1"
+	run_cmd "$IP nexthop add id 12 via 172.16.81.2 dev veth21"
+	run_cmd "$IP nexthop add id 101 group 11/12 active-backup"
+	check_nexthop "id 101" "id 101 group 11/12 active-backup"
+	log_test $? 0 "Create active-backup group"
+
+	run_cmd "$IP ro add 172.16.101.0/24 nhid 101"
+	check_route "172.16.101.1" "172.16.101.0/24 nhid 101 via 172.16.1.2 dev veth1"
+	log_test $? 0 "Route list shows active device"
+
+	$IP -o ro get 172.16.101.1 2>/dev/null | grep -q "dev veth1"
+	log_test $? 0 "Route get shows active device"
+
+	# carrier down or admin down on nexthop device removes that entry
+	run_cmd "ip -netns peer li set veth2 down"
+	check_nexthop "id 101" "id 101 group 12 active-backup"
+	log_test $? 0 "Carrier down removes active"
+
+	$IP -o ro get 172.16.101.1 2>/dev/null | grep -q "dev veth21"
+	log_test $? 0 "Route get shows backup device"
+
+	run_cmd "$IP li set veth21 down"
+	$IP nexthop sh id 101 2>/dev/null
+	log_test $? 2 "Link down on backup removes nexthop"
+
+	check_route "172.16.101.1" ""
+	log_test $? 0 "Route removed after a-b nexthop removed"
+
+	# restore device state
+	run_cmd "ip -netns peer li set veth2 up"
+	run_cmd "$IP li set veth21 up"
+
+	# a/b with mpath
+	run_cmd "$IP nexthop flush"
+	run_cmd "$IP nexthop add id 11 via 172.16.1.2 dev veth1"
+	run_cmd "$IP nexthop add id 12 via 172.16.2.2 dev veth3"
+	run_cmd "$IP nexthop add id 21 via 172.16.81.2 dev veth21"
+	run_cmd "$IP nexthop add id 22 via 172.16.82.2 dev veth23"
+	run_cmd "$IP nexthop add id 101 group 11/21 active-backup"
+	run_cmd "$IP nexthop add id 102 group 12/22 active-backup"
+	run_cmd "$IP nexthop add id 103 group 101/102"
+	log_test $? 0 "Multipath with active-backup paths"
+
+	run_cmd "$IP nexthop ls"
+	run_cmd "$IP ro add 172.16.101.0/24 nhid 103"
+	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
+	log_test $? 0 "ping with multipath containing active-backup paths"
+
+	run_cmd "ip -netns peer li set veth2 down"
+	check_nexthop "id 103" "id 103 group 101/102"
+	log_test $? 0 "Multipath still shows 2 paths after carrier down in a/b"
+
+	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
+	log_test $? 0 "ping with still works after carrier down"
+
+	run_cmd "ip -netns peer li set veth2 up"
+	run_cmd "$IP nexthop ls"
+	run_cmd "$IP ro ls"
+
+	run_cmd "$IP li set veth21 down"
+	check_nexthop "id 103" "id 103 group 102"
+	log_test $? 0 "Multipath shows 1 path after admin down on new active"
+	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
+	log_test $? 0 "ping with still works after mpath loss of a-b path"
+
+	run_cmd "$IP li set veth21 up"
+	run_cmd "$IP nexthop ls"
+	run_cmd "$IP ro ls"
+
+	#
+	# negative tests
+	#
+	# active points to invalid gw
+	run_cmd "$IP nexthop flush"
+	run_cmd "$IP nexthop add id 11 via 172.16.1.3 dev veth1"
+	run_cmd "$IP nexthop add id 12 via 172.16.81.2 dev veth21"
+	run_cmd "$IP nexthop add id 101 group 11/12 active-backup"
+	run_cmd "$IP ro add 172.16.101.0/24 nhid 101"
+
+	# failed neigh for gateway - should fallback to backup
+	run_cmd "${IP} neigh add 172.16.1.3 dev veth1 nud failed"
+	$IP -o ro get 172.16.101.1 2>/dev/null | grep -q "dev veth21"
+	log_test $? 0 "Route get shows backup device with invalid neigh"
+
+	run_cmd "$IP nexthop flush"
+	run_cmd "$IP nexthop add id 11 via 172.16.1.2 dev veth1"
+	run_cmd "$IP nexthop add id 12 via 172.16.2.2 dev veth3"
+	run_cmd "$IP nexthop add id 13 blackhole"
+	run_cmd "$IP nexthop add id 21 via 172.16.81.2 dev veth21"
+	run_cmd "$IP nexthop add id 22 via 172.16.82.2 dev veth23"
+
+	# must have 2 entries of equal weight
+	run_cmd "$IP nexthop add id 101 group 11 active-backup"
+	log_test $? 2 "Active-backup nexthop can not have 1 entry"
+	run_cmd "$IP nexthop add id 101 group 11/12/21 active-backup"
+	log_test $? 2 "Active-backup nexthop can not have more than 2 entries"
+	run_cmd "$IP nexthop add id 101 group 11,5/21,4 active-backup"
+	log_test $? 2 "Active-backup nexthops must have equal weight"
+	run_cmd "$IP nexthop add id 101 group 11,3/21,3 active-backup"
+	log_test $? 2 "Active-backup nexthops must have default weight"
+
+	# can not replace a/b group with mpath
+	run_cmd "$IP nexthop add id 101 group 11/21 active-backup"
+	run_cmd "$IP nexthop replace id 101 group 11/21 mpath"
+	log_test $? 2 "Can not change group type"
+
+	# a/b group can not have blackhole
+	run_cmd "$IP nexthop add id 102 group 11/13 active-backup"
+	log_test $? 2 "Active-backup can use blackhole as a path"
+}
+
+################################################################################
+# fdb nexthops
+
 check_nexthop_fdb_support()
 {
 	$IP nexthop help 2>&1 | grep -q fdb
-- 
2.21.1 (Apple Git-122.3)


^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2020-06-10  3:50 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-06-10  3:49 [PATCH RFC net-next 0/8] nexthop: Add support for active-backup nexthop type David Ahern
2020-06-10  3:49 ` [PATCH RFC net-next 1/8] nexthop: Rename nexthop_free_mpath David Ahern
2020-06-10  3:49 ` [PATCH RFC net-next 2/8] nexthop: Refactor nexthop_select_path David Ahern
2020-06-10  3:49 ` [PATCH RFC net-next 3/8] nexthop: Refactor nexthop_for_each_fib6_nh David Ahern
2020-06-10  3:49 ` [PATCH RFC net-next 4/8] nexthop: Move nexthop_get_nhc_lookup to nexthop.c David Ahern
2020-06-10  3:49 ` [PATCH RFC net-next 5/8] nexthop: Move nexthop_uses_dev " David Ahern
2020-06-10  3:49 ` [PATCH RFC net-next 6/8] nexthop: Add primary_only argument to nexthop_for_each_fib6_nh David Ahern
2020-06-10  3:49 ` [PATCH RFC net-next 7/8] nexthop: Add support for active-backup nexthop type David Ahern
2020-06-10  3:49 ` [PATCH RFC net-next 8/8] selftests: Add active-backup nexthop tests David Ahern

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.