diff options
| author | Renato Westphal <renato@opensourcerouting.org> | 2019-12-06 11:17:10 -0300 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-12-06 11:17:10 -0300 | 
| commit | 6f0af4c0697d18e6b48390caf446a076fd3dc31b (patch) | |
| tree | 4a5e1653bc0aa8d431ba043c17b1ac00bf26d41f /lib/nexthop_group.c | |
| parent | b0a89c27ad2e7f980d6bf9c78c6ff6a5cfe058c7 (diff) | |
| parent | db2fede9904d5b2cb51abf7fa071fca27c37104d (diff) | |
Merge pull request #5439 from mjstapp/nhg_add_labels
lib: support labelled nexthops in nexthop_groups
Diffstat (limited to 'lib/nexthop_group.c')
| -rw-r--r-- | lib/nexthop_group.c | 133 | 
1 files changed, 114 insertions, 19 deletions
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 3e08f1811e..b810d13a5a 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -34,6 +34,16 @@  DEFINE_MTYPE_STATIC(LIB, NEXTHOP_GROUP, "Nexthop Group") +/* + * Internal struct used to hold nhg config strings + */ +struct nexthop_hold { +	char *nhvrf_name; +	union sockunion *addr; +	char *intf; +	char *labels; +}; +  struct nexthop_group_hooks {  	void (*new)(const char *name);  	void (*add_nexthop)(const struct nexthop_group_cmd *nhg, @@ -425,7 +435,11 @@ static int nhgl_cmp(struct nexthop_hold *nh1, struct nexthop_hold *nh2)  	if (ret)  		return ret; -	return nhgc_cmp_helper(nh1->nhvrf_name, nh2->nhvrf_name); +	ret = nhgc_cmp_helper(nh1->nhvrf_name, nh2->nhvrf_name); +	if (ret) +		return ret; + +	return nhgc_cmp_helper(nh1->labels, nh2->labels);  }  static void nhgl_delete(struct nexthop_hold *nh) @@ -437,6 +451,8 @@ static void nhgl_delete(struct nexthop_hold *nh)  	if (nh->addr)  		sockunion_free(nh->addr); +	XFREE(MTYPE_TMP, nh->labels); +  	XFREE(MTYPE_TMP, nh);  } @@ -510,7 +526,8 @@ DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NHGNAME",  static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,  				    const char *nhvrf_name,  				    const union sockunion *addr, -				    const char *intf) +				    const char *intf, +				    const char *labels)  {  	struct nexthop_hold *nh; @@ -522,6 +539,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,  		nh->intf = XSTRDUP(MTYPE_TMP, intf);  	if (addr)  		nh->addr = sockunion_dup(addr); +	if (labels) +		nh->labels = XSTRDUP(MTYPE_TMP, labels);  	listnode_add_sort(nhgc->nhg_list, nh);  } @@ -529,7 +548,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,  static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,  				      const char *nhvrf_name,  				      const union sockunion *addr, -				      const char *intf) +				      const char *intf, +				      const char *labels)  {  	struct nexthop_hold *nh;  	struct listnode *node; @@ -537,7 +557,8 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,  	for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {  		if (nhgc_cmp_helper(nhvrf_name, nh->nhvrf_name) == 0 &&  		    nhgc_addr_cmp_helper(addr, nh->addr) == 0 && -		    nhgc_cmp_helper(intf, nh->intf) == 0) +		    nhgc_cmp_helper(intf, nh->intf) == 0 && +		    nhgc_cmp_helper(labels, nh->labels) == 0)  			break;  	} @@ -551,10 +572,19 @@ static void nexthop_group_unsave_nhop(struct nexthop_group_cmd *nhgc,  	nhgl_delete(nh);  } +/* + * Parse the config strings we support for a single nexthop. This gets used + * in a couple of different ways, and we distinguish between transient + * failures - such as a still-unprocessed interface - and fatal errors + * from label-string parsing. + */  static bool nexthop_group_parse_nexthop(struct nexthop *nhop,  					const union sockunion *addr, -					const char *intf, const char *name) +					const char *intf, const char *name, +					const char *labels, +					int *lbl_ret)  { +	int ret = 0;  	struct vrf *vrf;  	memset(nhop, 0, sizeof(*nhop)); @@ -592,16 +622,49 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,  	} else  		nhop->type = NEXTHOP_TYPE_IFINDEX; +	if (labels) { +		uint8_t num = 0; +		mpls_label_t larray[MPLS_MAX_LABELS]; + +		ret = mpls_str2label(labels, &num, larray); + +		/* Return label parse result */ +		if (lbl_ret) +			*lbl_ret = ret; + +		if (ret < 0) +			return false; +		else if (num > 0) +			nexthop_add_labels(nhop, ZEBRA_LSP_NONE, +					   num, larray); +	} +  	return true;  } +/* + * Wrapper to parse the strings in a 'nexthop_hold' + */ +static bool nexthop_group_parse_nhh(struct nexthop *nhop, +				    const struct nexthop_hold *nhh) +{ +	return (nexthop_group_parse_nexthop(nhop, nhh->addr, +					    nhh->intf, +					    nhh->nhvrf_name, +					    nhh->labels, +					    NULL)); +} +  DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,        "[no] nexthop\          <\  	  <A.B.C.D|X:X::X:X>$addr [INTERFACE$intf]\  	  |INTERFACE$intf\  	>\ -	[nexthop-vrf NAME$vrf_name]", +	[{ \ +	   nexthop-vrf NAME$vrf_name \ +	   |label WORD \ +	}]",        NO_STR        "Specify one of the nexthops in this ECMP group\n"        "v4 Address\n" @@ -609,14 +672,18 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,        "Interface to use\n"        "Interface to use\n"        "If the nexthop is in a different vrf tell us\n" -      "The nexthop-vrf Name\n") +      "The nexthop-vrf Name\n" +      "Specify label(s) for this nexthop\n" +      "One or more labels in the range (16-1048575) separated by '/'\n")  {  	VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);  	struct nexthop nhop;  	struct nexthop *nh; +	int lbl_ret = 0;  	bool legal; -	legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name); +	legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name, +					    label, &lbl_ret);  	if (nhop.type == NEXTHOP_TYPE_IPV6  	    && IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) { @@ -625,10 +692,31 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,  		return CMD_WARNING_CONFIG_FAILED;  	} +	/* Handle label-string errors */ +	if (!legal && lbl_ret < 0) { +		switch (lbl_ret) { +		case -1: +			vty_out(vty, "%% Malformed label(s)\n"); +			break; +		case -2: +			vty_out(vty, +				"%% Cannot use reserved label(s) (%d-%d)\n", +				MPLS_LABEL_RESERVED_MIN, +				MPLS_LABEL_RESERVED_MAX); +			break; +		case -3: +			vty_out(vty, +				"%% Too many labels. Enter %d or fewer\n", +				MPLS_MAX_LABELS); +			break; +		} +		return CMD_WARNING_CONFIG_FAILED; +	} +  	nh = nexthop_exists(&nhgc->nhg, &nhop);  	if (no) { -		nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf); +		nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf, label);  		if (nh) {  			_nexthop_del(&nhgc->nhg, nh); @@ -646,7 +734,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,  			_nexthop_add(&nhgc->nhg.nexthop, nh);  		} -		nexthop_group_save_nhop(nhgc, vrf_name, addr, intf); +		nexthop_group_save_nhop(nhgc, vrf_name, addr, intf, label);  		if (legal && nhg_hooks.add_nexthop)  			nhg_hooks.add_nexthop(nhgc, nh); @@ -696,6 +784,16 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)  		vrf = vrf_lookup_by_id(nh->vrf_id);  		vty_out(vty, " nexthop-vrf %s", vrf->name);  	} + +	if (nh->nh_label && nh->nh_label->num_labels > 0) { +		char buf[200]; + +		mpls_label2str(nh->nh_label->num_labels, +			       nh->nh_label->label, +			       buf, sizeof(buf), 0); +		vty_out(vty, " label %s", buf); +	} +  	vty_out(vty, "\n");  } @@ -715,6 +813,9 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty,  	if (nh->nhvrf_name)  		vty_out(vty, " nexthop-vrf %s", nh->nhvrf_name); +	if (nh->labels) +		vty_out(vty, " label %s", nh->labels); +  	vty_out(vty, "\n");  } @@ -751,9 +852,7 @@ void nexthop_group_enable_vrf(struct vrf *vrf)  			struct nexthop nhop;  			struct nexthop *nh; -			if (!nexthop_group_parse_nexthop(&nhop, nhh->addr, -							 nhh->intf, -							 nhh->nhvrf_name)) +			if (!nexthop_group_parse_nhh(&nhop, nhh))  				continue;  			nh = nexthop_exists(&nhgc->nhg, &nhop); @@ -787,9 +886,7 @@ void nexthop_group_disable_vrf(struct vrf *vrf)  			struct nexthop nhop;  			struct nexthop *nh; -			if (!nexthop_group_parse_nexthop(&nhop, nhh->addr, -							 nhh->intf, -							 nhh->nhvrf_name)) +			if (!nexthop_group_parse_nhh(&nhop, nhh))  				continue;  			nh = nexthop_exists(&nhgc->nhg, &nhop); @@ -824,9 +921,7 @@ void nexthop_group_interface_state_change(struct interface *ifp,  			for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nhh)) {  				struct nexthop nhop; -				if (!nexthop_group_parse_nexthop( -					    &nhop, nhh->addr, nhh->intf, -					    nhh->nhvrf_name)) +				if (!nexthop_group_parse_nhh(&nhop, nhh))  					continue;  				switch (nhop.type) {  | 
