diff options
| author | Mark Stapp <mjs@voltanet.io> | 2020-01-16 16:25:22 -0500 | 
|---|---|---|
| committer | Mark Stapp <mjs@voltanet.io> | 2020-03-27 09:39:14 -0400 | 
| commit | 0a8881b4b54a0b1ad756f000db25161d8d89cff7 (patch) | |
| tree | e378945b530e925c66db3cb2cc9084b7bc95a83a | |
| parent | 62e46303f45e063e82abc600fc412c6765daf300 (diff) | |
lib: support backup nexthops in nexthop-groups and zapi
Add vty support for backup nexthops in nexthop groups. Capture
backup nexthop info in zapi route messages.
Signed-off-by: Mark Stapp <mjs@voltanet.io>
| -rw-r--r-- | lib/nexthop_group.c | 90 | ||||
| -rw-r--r-- | lib/nexthop_group.h | 7 | ||||
| -rw-r--r-- | lib/zclient.c | 27 | ||||
| -rw-r--r-- | lib/zclient.h | 6 | 
4 files changed, 118 insertions, 12 deletions
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index c6479cf4ff..8c3bbbdcd4 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -43,8 +43,12 @@ struct nexthop_hold {  	char *intf;  	char *labels;  	uint32_t weight; +	int backup_idx; /* Index of backup nexthop, if >= 0 */  }; +/* Invalid/unset value for nexthop_hold's backup_idx */ +#define NHH_BACKUP_IDX_INVALID -1 +  struct nexthop_group_hooks {  	void (*new)(const char *name);  	void (*add_nexthop)(const struct nexthop_group_cmd *nhg, @@ -571,11 +575,36 @@ DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NHGNAME",  	return CMD_SUCCESS;  } +DEFPY(nexthop_group_backup, nexthop_group_backup_cmd, +      "backup-group WORD$name", +      "Specify a group name containing backup nexthops\n" +      "The name of the backup group\n") +{ +	VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc); + +	strlcpy(nhgc->backup_list_name, name, sizeof(nhgc->backup_list_name)); + +	return CMD_SUCCESS; +} + +DEFPY(no_nexthop_group_backup, no_nexthop_group_backup_cmd, +      "no backup-group [WORD$name]", +      NO_STR +      "Clear group name containing backup nexthops\n" +      "The name of the backup group\n") +{ +	VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc); + +	nhgc->backup_list_name[0] = 0; + +	return CMD_SUCCESS; +} +  static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,  				    const char *nhvrf_name,  				    const union sockunion *addr,  				    const char *intf, const char *labels, -				    const uint32_t weight) +				    const uint32_t weight, int backup_idx)  {  	struct nexthop_hold *nh; @@ -592,6 +621,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,  	nh->weight = weight; +	nh->backup_idx = backup_idx; +  	listnode_add_sort(nhgc->nhg_list, nh);  } @@ -633,7 +664,7 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,  					const union sockunion *addr,  					const char *intf, const char *name,  					const char *labels, int *lbl_ret, -					uint32_t weight) +					uint32_t weight, int backup_idx)  {  	int ret = 0;  	struct vrf *vrf; @@ -692,6 +723,15 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,  	nhop->weight = weight; +	if (backup_idx != NHH_BACKUP_IDX_INVALID) { +		/* Validate index value */ +		if (backup_idx > NEXTHOP_BACKUP_IDX_MAX) +			return false; + +		SET_FLAG(nhop->flags, NEXTHOP_FLAG_HAS_BACKUP); +		nhop->backup_idx = backup_idx; +	} +  	return true;  } @@ -703,7 +743,7 @@ static bool nexthop_group_parse_nhh(struct nexthop *nhop,  {  	return (nexthop_group_parse_nexthop(nhop, nhh->addr, nhh->intf,  					    nhh->nhvrf_name, nhh->labels, NULL, -					    nhh->weight)); +					    nhh->weight, nhh->backup_idx));  }  DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, @@ -716,6 +756,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,  	   nexthop-vrf NAME$vrf_name \  	   |label WORD \             |weight (1-255) \ +           |backup-idx$bi_str (0-254)$idx \  	}]",        NO_STR        "Specify one of the nexthops in this ECMP group\n" @@ -728,16 +769,23 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,        "Specify label(s) for this nexthop\n"        "One or more labels in the range (16-1048575) separated by '/'\n"        "Weight to be used by the nexthop for purposes of ECMP\n" -      "Weight value to be used\n") +      "Weight value to be used\n" +      "Backup nexthop index in another group\n" +      "Nexthop index value\n")  {  	VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);  	struct nexthop nhop;  	struct nexthop *nh;  	int lbl_ret = 0;  	bool legal; +	int backup_idx = idx; +	bool add_update = false; + +	if (bi_str == NULL) +		backup_idx = NHH_BACKUP_IDX_INVALID;  	legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name, label, -					    &lbl_ret, weight); +					    &lbl_ret, weight, backup_idx);  	if (nhop.type == NEXTHOP_TYPE_IPV6  	    && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) { @@ -769,19 +817,30 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,  	nh = nexthop_exists(&nhgc->nhg, &nhop); -	if (no) { +	if (no || nh) { +		/* Remove or replace cases */ + +		/* Remove existing config */  		nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf, label,  					  weight);  		if (nh) { +			/* Remove nexthop object */  			_nexthop_del(&nhgc->nhg, nh);  			if (nhg_hooks.del_nexthop)  				nhg_hooks.del_nexthop(nhgc, nh);  			nexthop_free(nh); +			nh = NULL;  		} -	} else if (!nh) { -		/* must be adding new nexthop since !no and !nexthop_exists */ +	} + +	add_update = !no; + +	if (add_update) { +		/* Add or replace cases */ + +		/* If valid config, add nexthop object */  		if (legal) {  			nh = nexthop_new(); @@ -789,8 +848,9 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,  			_nexthop_add(&nhgc->nhg.nexthop, nh);  		} +		/* Save config always */  		nexthop_group_save_nhop(nhgc, vrf_name, addr, intf, label, -					weight); +					weight, backup_idx);  		if (legal && nhg_hooks.add_nexthop)  			nhg_hooks.add_nexthop(nhgc, nh); @@ -853,6 +913,9 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)  	if (nh->weight)  		vty_out(vty, " weight %u", nh->weight); +	if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) +		vty_out(vty, " backup-idx %d", nh->backup_idx); +  	vty_out(vty, "\n");  } @@ -878,6 +941,9 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty,  	if (nh->weight)  		vty_out(vty, " weight %u", nh->weight); +	if (nh->backup_idx != NHH_BACKUP_IDX_INVALID) +		vty_out(vty, " backup-idx %d", nh->backup_idx); +  	vty_out(vty, "\n");  } @@ -891,6 +957,10 @@ static int nexthop_group_write(struct vty *vty)  		vty_out(vty, "nexthop-group %s\n", nhgc->name); +		if (nhgc->backup_list_name[0]) +			vty_out(vty, " backup-group %s\n", +				nhgc->backup_list_name); +  		for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {  			vty_out(vty, " ");  			nexthop_group_write_nexthop_internal(vty, nh); @@ -1071,6 +1141,8 @@ void nexthop_group_init(void (*new)(const char *name),  	install_element(CONFIG_NODE, &no_nexthop_group_cmd);  	install_default(NH_GROUP_NODE); +	install_element(NH_GROUP_NODE, &nexthop_group_backup_cmd); +	install_element(NH_GROUP_NODE, &no_nexthop_group_backup_cmd);  	install_element(NH_GROUP_NODE, &ecmp_nexthops_cmd);  	memset(&nhg_hooks, 0, sizeof(nhg_hooks)); diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 76e1e64ca5..3a5a1299c1 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -81,11 +81,16 @@ void nexthop_group_add_sorted(struct nexthop_group *nhg,  	(nhop) = nexthop_next(nhop) +#define NHGC_NAME_SIZE 80 +  struct nexthop_group_cmd {  	RB_ENTRY(nexthop_group_cmd) nhgc_entry; -	char name[80]; +	char name[NHGC_NAME_SIZE]; + +	/* Name of group containing backup nexthops (if set) */ +	char backup_list_name[NHGC_NAME_SIZE];  	struct nexthop_group nhg; diff --git a/lib/zclient.c b/lib/zclient.c index 53ca4e1327..55b8d29a4d 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -904,6 +904,7 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,  		}  	} +	/* If present, set 'weight' flag before encoding flags */  	if (api_nh->weight)  		SET_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_WEIGHT); @@ -1479,6 +1480,11 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh)  				   znh->labels);  	} +	if (CHECK_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) { +		SET_FLAG(n->flags, NEXTHOP_FLAG_HAS_BACKUP); +		n->backup_idx = znh->backup_idx; +	} +  	return n;  } @@ -1510,10 +1516,31 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,  		SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_LABEL);  	} +	if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) { +		SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP); +		znh->backup_idx = nh->backup_idx; +	} +  	return 0;  }  /* + * Wrapper that converts backup nexthop + */ +int zapi_backup_nexthop_from_nexthop(struct zapi_nexthop *znh, +				     const struct nexthop *nh) +{ +	int ret; + +	/* Ensure that zapi flags are correct: backups don't have backups */ +	ret = zapi_nexthop_from_nexthop(znh, nh); +	if (ret == 0) +		UNSET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP); + +	return ret; +} + +/*   * Decode the nexthop-tracking update message   */  bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr) diff --git a/lib/zclient.h b/lib/zclient.h index a2ee264be3..e747809f16 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -783,10 +783,12 @@ bool zapi_iptable_notify_decode(struct stream *s,  		uint32_t *unique,  		enum zapi_iptable_notify_owner *note); -extern struct nexthop *nexthop_from_zapi_nexthop( -	const struct zapi_nexthop *znh); +extern struct nexthop * +nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh);  int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,  			      const struct nexthop *nh); +int zapi_backup_nexthop_from_nexthop(struct zapi_nexthop *znh, +				     const struct nexthop *nh);  extern bool zapi_nexthop_update_decode(struct stream *s,  				       struct zapi_route *nhr);  | 
