summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Worley <sworley@nvidia.com>2021-03-19 17:30:51 +0100
committerGitHub <noreply@github.com>2021-03-19 17:30:51 +0100
commit97ec501ef0c3e18528152ac330a7e6b2dd8f7a84 (patch)
tree66412c7a0c85fc95f75f4642400a5f2d93079afb
parentMerge pull request #8286 from donaldsharp/nhrp_xlref (diff)
parentzebra: capture backup nexthop info with recursive resolution (diff)
downloadfrr-97ec501ef0c3e18528152ac330a7e6b2dd8f7a84.tar.xz
frr-97ec501ef0c3e18528152ac330a7e6b2dd8f7a84.zip
Merge pull request #8129 from mjstapp/backup_recursives
zebra: modify backup nexthop handling for recursive routes
-rw-r--r--zebra/zebra_nhg.c215
-rw-r--r--zebra/zebra_nhg.h4
-rw-r--r--zebra/zebra_vty.c16
3 files changed, 203 insertions, 32 deletions
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index f3ccf83fb..9246283fd 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -49,12 +49,23 @@ DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context");
+/* Map backup nexthop indices between two nhes */
+struct backup_nh_map_s {
+ int map_count;
+
+ struct {
+ uint8_t orig_idx;
+ uint8_t new_idx;
+ } map[MULTIPATH_NUM];
+};
+
/* id counter to keep in sync with kernel */
uint32_t id_counter;
-/* */
+/* Controlled through ui */
static bool g_nexthops_enabled = true;
static bool proto_nexthops_only;
+static bool use_recursive_backups = true;
static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi,
int type, bool from_dplane);
@@ -1626,9 +1637,10 @@ void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
nhg_connected_tree_increment_ref(&nhe->nhg_depends);
}
-static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
- struct nexthop *nexthop,
- struct zebra_sr_policy *policy)
+static struct nexthop *nexthop_set_resolved(afi_t afi,
+ const struct nexthop *newhop,
+ struct nexthop *nexthop,
+ struct zebra_sr_policy *policy)
{
struct nexthop *resolved_hop;
uint8_t num_labels = 0;
@@ -1746,6 +1758,8 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
resolved_hop->rparent = nexthop;
_nexthop_add(&nexthop->resolved, resolved_hop);
+
+ return resolved_hop;
}
/* Checks if nexthop we are trying to resolve to is valid */
@@ -1784,12 +1798,107 @@ static bool nexthop_valid_resolve(const struct nexthop *nexthop,
}
/*
- * Given a nexthop we need to properly recursively resolve
- * the route. As such, do a table lookup to find and match
- * if at all possible. Set the nexthop->ifindex and resolved_id
- * as appropriate
+ * When resolving a recursive nexthop, capture backup nexthop(s) also
+ * so they can be conveyed through the dataplane to the FIB. We'll look
+ * at the backups in the resolving nh 'nexthop' and its nhe, and copy them
+ * into the route's resolved nh 'resolved' and its nhe 'nhe'.
+ */
+static int resolve_backup_nexthops(const struct nexthop *nexthop,
+ const struct nhg_hash_entry *nhe,
+ struct nexthop *resolved,
+ struct nhg_hash_entry *resolve_nhe,
+ struct backup_nh_map_s *map)
+{
+ int i, j, idx;
+ const struct nexthop *bnh;
+ struct nexthop *nh, *newnh;
+
+ assert(nexthop->backup_num <= NEXTHOP_MAX_BACKUPS);
+
+ if (resolve_nhe->backup_info->nhe == NULL)
+ resolve_nhe->backup_info->nhe = zebra_nhg_alloc();
+
+ /* Locate backups from the original nexthop's backup index and nhe */
+ for (i = 0; i < nexthop->backup_num; i++) {
+ idx = nexthop->backup_idx[i];
+
+ /* Do we already know about this particular backup? */
+ for (j = 0; j < map->map_count; j++) {
+ if (map->map[j].orig_idx == idx)
+ break;
+ }
+
+ if (j < map->map_count) {
+ resolved->backup_idx[resolved->backup_num] =
+ map->map[j].new_idx;
+ resolved->backup_num++;
+
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug("%s: found map idx orig %d, new %d",
+ __func__, map->map[j].orig_idx,
+ map->map[j].new_idx);
+
+ continue;
+ }
+
+ /* We can't handle any new map entries at this point. */
+ if (map->map_count == MULTIPATH_NUM)
+ break;
+
+ /* Need to create/copy a new backup */
+ bnh = nhe->backup_info->nhe->nhg.nexthop;
+ for (j = 0; j < idx; j++) {
+ if (bnh == NULL)
+ break;
+ bnh = bnh->next;
+ }
+
+ /* Whoops - bad index in the nexthop? */
+ if (bnh == NULL)
+ continue;
+
+ /* Update backup info in the resolving nexthop and its nhe */
+ newnh = nexthop_dup_no_recurse(bnh, NULL);
+
+ /* Need to compute the new backup index in the new
+ * backup list, and add to map struct.
+ */
+ j = 0;
+ nh = resolve_nhe->backup_info->nhe->nhg.nexthop;
+ if (nh) {
+ while (nh->next) {
+ nh = nh->next;
+ j++;
+ }
+
+ nh->next = newnh;
+
+ } else /* First one */
+ resolve_nhe->backup_info->nhe->nhg.nexthop = newnh;
+
+ /* Capture index */
+ resolved->backup_idx[resolved->backup_num] = j;
+ resolved->backup_num++;
+
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug("%s: added idx orig %d, new %d",
+ __func__, idx, j);
+
+ /* Update map/cache */
+ map->map[map->map_count].orig_idx = idx;
+ map->map[map->map_count].new_idx = j;
+ map->map_count++;
+ }
+
+ return 0;
+}
+
+/*
+ * Given a nexthop we need to properly recursively resolve,
+ * do a table lookup to find and match if at all possible.
+ * Set the nexthop->ifindex and resolution info as appropriate.
*/
-static int nexthop_active(afi_t afi, struct nexthop *nexthop,
+static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
const struct prefix *top, int type, uint32_t flags,
uint32_t *pmtu)
{
@@ -1805,6 +1914,7 @@ static int nexthop_active(afi_t afi, struct nexthop *nexthop,
struct zebra_vrf *zvrf;
struct in_addr local_ipv4;
struct in_addr *ipv4;
+ afi_t afi = AFI_IP;
/* Reset some nexthop attributes that we'll recompute if necessary */
if ((nexthop->type == NEXTHOP_TYPE_IPV4)
@@ -1816,11 +1926,13 @@ static int nexthop_active(afi_t afi, struct nexthop *nexthop,
nexthop->resolved = NULL;
/*
+ * Set afi based on nexthop type.
* Some nexthop types get special handling, possibly skipping
* the normal processing.
*/
switch (nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
+
ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
/*
* If the interface exists and its operative or its a kernel
@@ -1838,6 +1950,8 @@ static int nexthop_active(afi_t afi, struct nexthop *nexthop,
break;
case NEXTHOP_TYPE_IPV6_IFINDEX:
+ afi = AFI_IP6;
+
if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
ifp = if_lookup_by_index(nexthop->ifindex,
nexthop->vrf_id);
@@ -1848,14 +1962,16 @@ static int nexthop_active(afi_t afi, struct nexthop *nexthop,
}
break;
- case NEXTHOP_TYPE_BLACKHOLE:
- return 1;
-
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
+ afi = AFI_IP;
+ break;
case NEXTHOP_TYPE_IPV6:
- default:
+ afi = AFI_IP6;
break;
+
+ case NEXTHOP_TYPE_BLACKHOLE:
+ return 1;
}
/*
@@ -2052,6 +2168,8 @@ static int nexthop_active(afi_t afi, struct nexthop *nexthop,
return 1;
} else if (CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
struct nexthop_group *nhg;
+ struct nexthop *resolver;
+ struct backup_nh_map_s map = {};
resolved = 0;
@@ -2081,17 +2199,29 @@ static int nexthop_active(afi_t afi, struct nexthop *nexthop,
SET_FLAG(nexthop->flags,
NEXTHOP_FLAG_RECURSIVE);
- nexthop_set_resolved(afi, newhop, nexthop,
- NULL);
+ resolver = nexthop_set_resolved(afi, newhop,
+ nexthop, NULL);
resolved = 1;
+
+ /* If there are backup nexthops, capture
+ * that info with the resolving nexthop.
+ */
+ if (resolver && newhop->backup_num > 0) {
+ resolve_backup_nexthops(newhop,
+ match->nhe,
+ resolver, nhe,
+ &map);
+ }
}
/* Examine installed backup nexthops, if any. There
* are only installed backups *if* there is a
- * dedicated fib list.
+ * dedicated fib list. The UI can also control use
+ * of backups for resolution.
*/
nhg = rib_get_fib_backup_nhg(match);
- if (nhg == NULL || nhg->nexthop == NULL)
+ if (!use_recursive_backups ||
+ nhg == NULL || nhg->nexthop == NULL)
goto done_with_match;
for (ALL_NEXTHOPS_PTR(nhg, newhop)) {
@@ -2144,14 +2274,17 @@ done_with_match:
/* This function verifies reachability of one given nexthop, which can be
* numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
* in nexthop->flags field. The nexthop->ifindex will be updated
- * appropriately as well. An existing route map can turn an
- * otherwise active nexthop into inactive, but not vice versa.
+ * appropriately as well.
+ *
+ * An existing route map can turn an otherwise active nexthop into inactive,
+ * but not vice versa.
*
* The return value is the final value of 'ACTIVE' flag.
*/
static unsigned nexthop_active_check(struct route_node *rn,
struct route_entry *re,
- struct nexthop *nexthop)
+ struct nexthop *nexthop,
+ struct nhg_hash_entry *nhe)
{
route_map_result_t ret = RMAP_PERMITMATCH;
afi_t family;
@@ -2188,7 +2321,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
switch (nexthop->type) {
case NEXTHOP_TYPE_IFINDEX:
- if (nexthop_active(AFI_IP, nexthop, &rn->p, re->type,
+ if (nexthop_active(nexthop, nhe, &rn->p, re->type,
re->flags, &mtu))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
@@ -2197,7 +2330,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
family = AFI_IP;
- if (nexthop_active(AFI_IP, nexthop, &rn->p, re->type,
+ if (nexthop_active(nexthop, nhe, &rn->p, re->type,
re->flags, &mtu))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
@@ -2205,7 +2338,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
break;
case NEXTHOP_TYPE_IPV6:
family = AFI_IP6;
- if (nexthop_active(AFI_IP6, nexthop, &rn->p, re->type,
+ if (nexthop_active(nexthop, nhe, &rn->p, re->type,
re->flags, &mtu))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
@@ -2216,7 +2349,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
if (rn->p.family != AF_INET)
family = AFI_IP6;
- if (nexthop_active(AFI_IP6, nexthop, &rn->p, re->type,
+ if (nexthop_active(nexthop, nhe, &rn->p, re->type,
re->flags, &mtu))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
else
@@ -2326,18 +2459,20 @@ done:
}
/*
- * Process a list of nexthops, given an nhg, determining
+ * Process a list of nexthops, given an nhe, determining
* whether each one is ACTIVE/installable at this time.
*/
static uint32_t nexthop_list_active_update(struct route_node *rn,
struct route_entry *re,
- struct nexthop_group *nhg)
+ struct nhg_hash_entry *nhe,
+ bool is_backup)
{
union g_addr prev_src;
unsigned int prev_active, new_active;
ifindex_t prev_index;
uint32_t counter = 0;
struct nexthop *nexthop;
+ struct nexthop_group *nhg = &nhe->nhg;
nexthop = nhg->nexthop;
@@ -2353,15 +2488,20 @@ static uint32_t nexthop_list_active_update(struct route_node *rn,
prev_src = nexthop->rmap_src;
prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
prev_index = nexthop->ifindex;
+
+ /* Include the containing nhe for primary nexthops: if there's
+ * recursive resolution, we capture the backup info also.
+ */
+ new_active =
+ nexthop_active_check(rn, re, nexthop,
+ (is_backup ? NULL : nhe));
+
/*
* We need to respect the multipath_num here
* as that what we should be able to install from
* a multipath perspective should not be a data plane
* decision point.
*/
- new_active =
- nexthop_active_check(rn, re, nexthop);
-
if (new_active && counter >= zrouter.multipath_num) {
struct nexthop *nh;
@@ -2375,7 +2515,7 @@ static uint32_t nexthop_list_active_update(struct route_node *rn,
if (new_active)
counter++;
- /* Don't allow src setting on IPv6 addr for now */
+ /* Check for changes to the nexthop - set ROUTE_ENTRY_CHANGED */
if (prev_active != new_active || prev_index != nexthop->ifindex
|| ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
&& nexthop->type < NEXTHOP_TYPE_IPV6)
@@ -2444,7 +2584,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
curr_nhe->id = 0;
/* Process nexthops */
- curr_active = nexthop_list_active_update(rn, re, &curr_nhe->nhg);
+ curr_active = nexthop_list_active_update(rn, re, curr_nhe, false);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: re %p curr_active %u", __func__, re,
@@ -2455,7 +2595,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
goto backups_done;
backup_active = nexthop_list_active_update(
- rn, re, zebra_nhg_get_backup_nhg(curr_nhe));
+ rn, re, curr_nhe->backup_info->nhe, true /*is_backup*/);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: re %p backup_active %u", __func__, re,
@@ -2834,6 +2974,17 @@ bool zebra_nhg_kernel_nexthops_enabled(void)
return g_nexthops_enabled;
}
+/* Global control for use of activated backups for recursive resolution. */
+void zebra_nhg_set_recursive_use_backups(bool set)
+{
+ use_recursive_backups = set;
+}
+
+bool zebra_nhg_recursive_use_backups(void)
+{
+ return use_recursive_backups;
+}
+
/*
* Global control to only use kernel nexthops for protocol created NHGs.
* There are some use cases where you may not want zebra to implicitly
diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h
index 2de34fec6..38015bf55 100644
--- a/zebra/zebra_nhg.h
+++ b/zebra/zebra_nhg.h
@@ -212,6 +212,10 @@ bool zebra_nhg_kernel_nexthops_enabled(void);
void zebra_nhg_set_proto_nexthops_only(bool set);
bool zebra_nhg_proto_nexthops_only(void);
+/* Global control for use of activated backups for recursive resolution. */
+void zebra_nhg_set_recursive_use_backups(bool set);
+bool zebra_nhg_recursive_use_backups(void);
+
/**
* NHE abstracted tree functions.
* Use these where possible instead of direct access.
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index f18d8fbb6..3349c1820 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -1636,6 +1636,18 @@ DEFPY_HIDDEN(proto_nexthop_group_only, proto_nexthop_group_only_cmd,
return CMD_SUCCESS;
}
+DEFPY_HIDDEN(backup_nexthop_recursive_use_enable,
+ backup_nexthop_recursive_use_enable_cmd,
+ "[no] zebra nexthop resolve-via-backup",
+ NO_STR
+ ZEBRA_STR
+ "Nexthop configuration \n"
+ "Configure use of backup nexthops in recursive resolution\n")
+{
+ zebra_nhg_set_recursive_use_backups(!no);
+ return CMD_SUCCESS;
+}
+
DEFUN (no_ip_nht_default_route,
no_ip_nht_default_route_cmd,
"no ip nht resolve-via-default",
@@ -3619,6 +3631,9 @@ static int config_write_protocol(struct vty *vty)
if (zebra_nhg_proto_nexthops_only())
vty_out(vty, "zebra nexthop proto only\n");
+ if (!zebra_nhg_recursive_use_backups())
+ vty_out(vty, "no zebra nexthop resolve-via-backup\n");
+
#ifdef HAVE_NETLINK
/* Include netlink info */
netlink_config_write_helper(vty);
@@ -4054,6 +4069,7 @@ void zebra_vty_init(void)
install_element(CONFIG_NODE, &no_zebra_packet_process_cmd);
install_element(CONFIG_NODE, &nexthop_group_use_enable_cmd);
install_element(CONFIG_NODE, &proto_nexthop_group_only_cmd);
+ install_element(CONFIG_NODE, &backup_nexthop_recursive_use_enable_cmd);
install_element(VIEW_NODE, &show_nexthop_group_cmd);
install_element(VIEW_NODE, &show_interface_nexthop_group_cmd);