Mailing List Archive

[PATCH v4 2/3] bgpd: multiple label stack support
From: David Lamparter <equinox@opensourcerouting.org>

Support for multiple label support handling in NLRI messages.
Ability to receive and sent BGP updates with NLRI containing multiple
labels. The commit follows label encoding rules, contained in RFC3107.

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Signed-off-by: Christian Franke <chris@opensourcerouting.org>
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
---
bgpd/bgp_attr.c | 28 +++++++---
bgpd/bgp_attr.h | 6 +--
bgpd/bgp_encap.c | 4 +-
bgpd/bgp_mplsvpn.c | 148 +++++++++++++++++++++++++++++++++--------------------
bgpd/bgp_mplsvpn.h | 4 +-
bgpd/bgp_packet.c | 29 +++++++----
bgpd/bgp_route.c | 144 ++++++++++++++++++++++++++++++++++-----------------
bgpd/bgp_route.h | 15 ++++--
8 files changed, 245 insertions(+), 133 deletions(-)

diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index f6d5d8e7b454..26b513aef7ca 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -2482,13 +2482,24 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi,
void
bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi,
struct prefix *p, struct prefix_rd *prd,
- u_char *tag)
+ uint32_t *labels, size_t nlabels)
{
if (safi == SAFI_MPLS_VPN)
{
- /* Tag, RD, Prefix write. */
- stream_putc (s, p->prefixlen + 88);
- stream_put (s, tag, 3);
+ if (nlabels != 0)
+ {
+ size_t i;
+ /* Tag, RD, Prefix write. */
+ stream_putc (s, p->prefixlen + 8 * (8 + 3 * nlabels));
+ for (i = 0; i < nlabels; i++)
+ stream_put3 (s, labels[i]);
+ }
+ else
+ {
+ /* Withdraw, put bottom of stack as only label */
+ stream_putc (s, p->prefixlen + 8 * (8 + 3));
+ stream_put3 (s, 0x1);
+ }
stream_put (s, prd->val, 8);
stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
}
@@ -2604,7 +2615,8 @@ bgp_size_t
bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
struct stream *s, struct attr *attr,
struct prefix *p, afi_t afi, safi_t safi,
- struct peer *from, struct prefix_rd *prd, u_char *tag)
+ struct peer *from, struct prefix_rd *prd,
+ uint32_t *labels, size_t nlabels)
{
size_t cp;
size_t aspath_sizep;
@@ -2623,7 +2635,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
{
size_t mpattrlen_pos = 0;
mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi, attr);
- bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag);
+ bgp_packet_mpattr_prefix(s, afi, safi, p, prd, labels, nlabels);
bgp_packet_mpattr_end(s, mpattrlen_pos);
}

@@ -2984,9 +2996,9 @@ bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi)
void
bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p,
afi_t afi, safi_t safi, struct prefix_rd *prd,
- u_char *tag)
+ uint32_t *labels, size_t nlabels)
{
- bgp_packet_mpattr_prefix (s, afi, safi, p, prd, tag);
+ bgp_packet_mpattr_prefix (s, afi, safi, p, prd, labels, nlabels);
}

void
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 8457f4022437..3bd7aface174 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -173,7 +173,7 @@ extern bgp_size_t bgp_packet_attribute (struct bgp *bgp, struct peer *,
struct stream *, struct attr *,
struct prefix *, afi_t, safi_t,
struct peer *, struct prefix_rd *,
- u_char *);
+ uint32_t *labels, size_t nlabels);
extern void bgp_dump_routes_attr (struct stream *, struct attr *,
struct prefix *);
extern int attrhash_cmp (const void *, const void *);
@@ -220,7 +220,7 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, afi_t afi, safi_t safi,
struct attr *attr);
extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
struct prefix *p, struct prefix_rd *prd,
- u_char *tag);
+ uint32_t *labels, size_t nlabels);
extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi,
struct prefix *p);
extern void bgp_packet_mpattr_end(struct stream *s, size_t sizep);
@@ -229,7 +229,7 @@ extern size_t bgp_packet_mpunreach_start (struct stream *s, afi_t afi,
safi_t safi);
extern void bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p,
afi_t afi, safi_t safi, struct prefix_rd *prd,
- u_char *tag);
+ uint32_t *labels, size_t nlabels);
extern void bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt);

#endif /* _QUAGGA_BGP_ATTR_H */
diff --git a/bgpd/bgp_encap.c b/bgpd/bgp_encap.c
index edd9d7675811..37fca47597b6 100644
--- a/bgpd/bgp_encap.c
+++ b/bgpd/bgp_encap.c
@@ -228,10 +228,10 @@ bgp_nlri_parse_encap(

if (attr) {
bgp_update (peer, &p, attr, afi, SAFI_ENCAP,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0);
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0, 0);
} else {
bgp_withdraw (peer, &p, attr, afi, SAFI_ENCAP,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL);
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, NULL, 0);
}
}

diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 047105d79130..143d5d9b3fee 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -45,17 +45,6 @@ decode_rd_type (u_char *pnt)
return v;
}

-u_int32_t
-decode_label (u_char *pnt)
-{
- u_int32_t l;
-
- l = ((u_int32_t) *pnt++ << 12);
- l |= (u_int32_t) *pnt++ << 4;
- l |= (u_int32_t) ((*pnt & 0xf0) >> 4);
- return l;
-}
-
/* type == RD_TYPE_AS */
static void
decode_rd_as (u_char *pnt, struct rd_as *rd_as)
@@ -93,12 +82,31 @@ decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip)
rd_ip->val |= (u_int16_t) *pnt;
}

+char *
+labels2str (char *str, size_t size, uint32_t *labels, size_t nlabels)
+{
+ size_t i;
+ if (nlabels == 0)
+ {
+ snprintf (str, size, ":");
+ return str;
+ }
+ char *pos = str;
+ for (i = 0; i < nlabels; i++)
+ {
+ snprintf (pos, str + size - pos, "%s%d", (i > 0) ? ":" : "",
+ labels[i] >> 4);
+ pos += strlen(pos);
+ }
+ return str;
+}
+
int
bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr,
struct bgp_nlri *packet)
{
- u_char *pnt;
- u_char *lim;
+ u_char *pnt, *pnt2;
+ u_char *lim, *lim2;
struct prefix p;
int psize = 0;
int prefixlen;
@@ -106,7 +114,8 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr,
struct rd_as rd_as;
struct rd_ip rd_ip;
struct prefix_rd prd;
- u_char *tagpnt;
+ uint32_t labels[BGP_MAX_LABELS];
+ size_t nlabels;

/* Check peer status. */
if (peer->status != Established)
@@ -118,8 +127,8 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr,

pnt = packet->nlri;
lim = pnt + packet->length;
-
-#define VPN_PREFIXLEN_MIN_BYTES (3 + 8) /* label + RD */
+#define VPN_LABEL_SIZE 3
+#define VPN_PREFIXLEN_MIN_BYTES (VPN_LABEL_SIZE + BGP_RD_SIZE) /* label + RD */
for (; pnt < lim; pnt += psize)
{
/* Clear prefix structure. */
@@ -129,7 +138,6 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr,
prefixlen = *pnt++;
p.family = afi2family (packet->afi);
psize = PSIZE (prefixlen);
-
/* sanity check against packet data */
if (prefixlen < VPN_PREFIXLEN_MIN_BYTES*8)
{
@@ -146,53 +154,77 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr,
" (psize %u exceeds packet size (%u)",
peer->host,
prefixlen, (uint)(lim-pnt));
- return -1;
+ continue;
}
-
+ lim2 = pnt + psize;
+ nlabels = 0;
+ pnt2 = pnt;
+ while (1)
+ {
+ if (pnt2 + VPN_LABEL_SIZE > lim2)
+ {
+ zlog_err ("label stack running past prefix length");
+ return -1;
+ }
+ uint32_t label = (pnt2[0] << 16) + (pnt2[1] << 8) + pnt2[2];
+ pnt2 += VPN_LABEL_SIZE;
+ if (nlabels == BGP_MAX_LABELS)
+ {
+ zlog_err ("label stack too deep");
+ return -1;
+ }
+ labels[nlabels++] = label;
+ if (label == 0 || label == 0x800000 || label & 0x000001)
+ break;
+ }
+
/* sanity check against storage for the IP address portion */
- if ((psize - VPN_PREFIXLEN_MIN_BYTES) > (ssize_t) sizeof(p.u))
+ if (pnt + VPN_PREFIXLEN_MIN_BYTES + (nlabels - 1)*VPN_LABEL_SIZE > lim)
+ {
+ zlog_err ("not enough bytes for RD left in NLRI?");
+ return -1;
+ }
+ if ((psize - VPN_PREFIXLEN_MIN_BYTES - (nlabels - 1)*VPN_LABEL_SIZE) > (ssize_t) sizeof(p.u))
{
plog_err (peer->log,
"%s [Error] Update packet error / VPNv4"
" (psize %u exceeds storage size (%zu)",
peer->host,
- prefixlen - VPN_PREFIXLEN_MIN_BYTES*8, sizeof(p.u));
- return -1;
+ (unsigned int)(prefixlen - VPN_PREFIXLEN_MIN_BYTES*8 -
+ (nlabels - 1)*VPN_LABEL_SIZE*8),
+ sizeof(p.u));
+ continue;
}
-
/* Sanity check against max bitlen of the address family */
- if ((psize - VPN_PREFIXLEN_MIN_BYTES) > prefix_blen (&p))
+ if ((psize - VPN_PREFIXLEN_MIN_BYTES - (nlabels - 1)*VPN_LABEL_SIZE) > (unsigned int)prefix_blen (&p))
{
plog_err (peer->log,
"%s [Error] Update packet error / VPNv4"
" (psize %u exceeds family (%u) max byte len %u)",
peer->host,
- prefixlen - VPN_PREFIXLEN_MIN_BYTES*8,
- p.family, prefix_blen (&p));
- return -1;
+ (unsigned int)(prefixlen - VPN_PREFIXLEN_MIN_BYTES*8
+ - (nlabels - 1)*VPN_LABEL_SIZE*8),
+ p.family, (unsigned int) prefix_blen (&p));
+ continue;
}

- /* Copyr label to prefix. */
- tagpnt = pnt;
-
/* Copy routing distinguisher to rd. */
- memcpy (&prd.val, pnt + 3, 8);
-
+ memcpy (&prd.val, pnt + VPN_LABEL_SIZE*nlabels, BGP_RD_SIZE);
/* Decode RD type. */
- type = decode_rd_type (pnt + 3);
+ type = decode_rd_type (pnt + VPN_LABEL_SIZE*nlabels);

switch (type)
{
case RD_TYPE_AS:
- decode_rd_as (pnt + 5, &rd_as);
+ decode_rd_as (pnt + VPN_LABEL_SIZE*nlabels + 2, &rd_as);
break;

case RD_TYPE_AS4:
- decode_rd_as4 (pnt + 5, &rd_as);
+ decode_rd_as4 (pnt + VPN_LABEL_SIZE*nlabels + 2, &rd_as);
break;

case RD_TYPE_IP:
- decode_rd_ip (pnt + 5, &rd_ip);
+ decode_rd_ip (pnt + VPN_LABEL_SIZE*nlabels + 2, &rd_ip);
break;

default:
@@ -200,16 +232,16 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr,
break; /* just report */
}

- p.prefixlen = prefixlen - VPN_PREFIXLEN_MIN_BYTES*8;
- memcpy (&p.u.prefix, pnt + VPN_PREFIXLEN_MIN_BYTES,
- psize - VPN_PREFIXLEN_MIN_BYTES);
+ p.prefixlen = prefixlen - VPN_PREFIXLEN_MIN_BYTES*8 - (nlabels - 1)*VPN_LABEL_SIZE*8;
+ memcpy (&p.u.prefix, pnt + VPN_PREFIXLEN_MIN_BYTES + (nlabels - 1)*VPN_LABEL_SIZE,
+ psize - VPN_PREFIXLEN_MIN_BYTES - (nlabels - 1)*VPN_LABEL_SIZE);

if (attr)
bgp_update (peer, &p, attr, packet->afi, SAFI_MPLS_VPN,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0);
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, labels, nlabels, 0);
else
bgp_withdraw (peer, &p, attr, packet->afi, SAFI_MPLS_VPN,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt);
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, labels, nlabels);
}
/* Packet length consistency check. */
if (pnt != lim)
@@ -223,6 +255,7 @@ bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr,

return 0;
#undef VPN_PREFIXLEN_MIN_BYTES
+#undef VPN_LABEL_SIZE
}

int
@@ -286,28 +319,33 @@ out:
}

int
-str2tag (const char *str, u_char *tag)
+str2labels (const char *str, uint32_t*labels, size_t *nlabels)
{
unsigned long l;
char *endptr;
- u_int32_t t;

if (*str == '-')
return 0;

- errno = 0;
- l = strtoul (str, &endptr, 10);
+ if (str[0] == ':' && str[1] == '\0')
+ return 1;

- if (*endptr != '\0' || errno || l > UINT32_MAX)
- return 0;
-
- t = (u_int32_t) l;
-
- tag[0] = (u_char)(t >> 12);
- tag[1] = (u_char)(t >> 4);
- tag[2] = (u_char)(t << 4);
-
- return 1;
+ *nlabels = 0;
+ while (*nlabels < BGP_MAX_LABELS)
+ {
+ errno = 0;
+ l = strtoul (str, &endptr, 0);
+ if (endptr == str || (*endptr != '\0' && *endptr != ':') || l >= 0x100000)
+ return 0;
+ labels[*nlabels] = l << 4;
+ (*nlabels)++;
+ if (*endptr == '\0')
+ {
+ labels[*nlabels - 1] |= 1;
+ break;
+ }
+ }
+ return *endptr == '\0';
}

char *
diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h
index 3299b9cb9a04..bfa9caef616b 100644
--- a/bgpd/bgp_mplsvpn.h
+++ b/bgpd/bgp_mplsvpn.h
@@ -43,9 +43,9 @@ struct rd_ip

extern void bgp_mplsvpn_init (void);
extern int bgp_nlri_parse_vpn (struct peer *, struct attr *, struct bgp_nlri *);
-extern u_int32_t decode_label (u_char *);
extern int str2prefix_rd (const char *, struct prefix_rd *);
-extern int str2tag (const char *, u_char *);
+extern int str2labels (const char *str, uint32_t *labels, size_t *nlabels);
+extern char *labels2str (char *str, size_t size, uint32_t *labels, size_t nlabels);
extern char *prefix_rd2str (struct prefix_rd *, char *, size_t);

#endif /* _QUAGGA_BGP_MPLSVPN_H */
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index f42e544b4b8b..8e315d1dbc80 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -185,7 +185,8 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
if (stream_empty (s))
{
struct prefix_rd *prd = NULL;
- u_char *tag = NULL;
+ uint32_t *labels = NULL;
+ size_t nlabels = 0;
struct peer *from = NULL;

if (rn->prn)
@@ -194,7 +195,10 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
{
from = binfo->peer;
if (binfo->extra)
- tag = binfo->extra->tag;
+ {
+ labels = binfo->extra->labels;
+ nlabels = binfo->extra->nlabels;
+ }
}

/* 1: Write the BGP message header - 16 bytes marker, 2 bytes length,
@@ -218,10 +222,10 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
/* 5: Encode all the attributes, except MP_REACH_NLRI attr. */
total_attr_len = bgp_packet_attribute (NULL, peer, s,
adv->baa->attr,
- ((afi == AFI_IP && safi == SAFI_UNICAST) ?
+ ((afi == AFI_IP && safi == SAFI_UNICAST) ?
&rn->p : NULL),
afi, safi,
- from, prd, tag);
+ from, prd, labels, nlabels);
space_remaining = STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) -
BGP_MAX_PACKET_SIZE_OVERFLOW;
space_needed = BGP_NLRI_LENGTH + bgp_packet_mpattr_prefix_size (afi, safi, &rn->p);;
@@ -237,7 +241,6 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
adv = bgp_advertise_clean (peer, adv->adj, afi, safi);
return NULL;
}
-
}

if (afi == AFI_IP && safi == SAFI_UNICAST)
@@ -246,17 +249,21 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
{
/* Encode the prefix in MP_REACH_NLRI attribute */
struct prefix_rd *prd = NULL;
- u_char *tag = NULL;
+ uint32_t *labels = NULL;
+ size_t nlabels = 0;

if (rn->prn)
prd = (struct prefix_rd *) &rn->prn->p;
if (binfo && binfo->extra)
- tag = binfo->extra->tag;
+ {
+ labels = binfo->extra->labels;
+ nlabels = binfo->extra->nlabels;
+ }

if (stream_empty(snlri))
mpattrlen_pos = bgp_packet_mpattr_start(snlri, afi, safi,
adv->baa->attr);
- bgp_packet_mpattr_prefix(snlri, afi, safi, &rn->p, prd, tag);
+ bgp_packet_mpattr_prefix(snlri, afi, safi, &rn->p, prd, labels, nlabels);
}
if (BGP_DEBUG (update, UPDATE_OUT))
{
@@ -415,7 +422,7 @@ bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi)
mplen_pos = bgp_packet_mpunreach_start(s, afi, safi);
}

- bgp_packet_mpunreach_prefix(s, &rn->p, afi, safi, prd, NULL);
+ bgp_packet_mpunreach_prefix(s, &rn->p, afi, safi, prd, NULL, 0);
}

if (BGP_DEBUG (update, UPDATE_OUT))
@@ -503,7 +510,7 @@ bgp_default_update_send (struct peer *peer, struct attr *attr,
/* Make place for total attribute length. */
pos = stream_get_endp (s);
stream_putw (s, 0);
- total_attr_len = bgp_packet_attribute (NULL, peer, s, attr, &p, afi, safi, from, NULL, NULL);
+ total_attr_len = bgp_packet_attribute (NULL, peer, s, attr, &p, afi, safi, from, NULL, NULL, 0);

/* Set Total Path Attribute Length. */
stream_putw_at (s, pos, total_attr_len);
@@ -585,7 +592,7 @@ bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi)
stream_putw (s, 0);
mp_start = stream_get_endp (s);
mplen_pos = bgp_packet_mpunreach_start(s, afi, safi);
- bgp_packet_mpunreach_prefix(s, &p, afi, safi, NULL, NULL);
+ bgp_packet_mpunreach_prefix(s, &p, afi, safi, NULL, NULL, 0);

/* Set the mp_unreach attr's length */
bgp_packet_mpunreach_end(s, mplen_pos);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 4cb6c141bcdc..3a77ac14b71e 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1898,10 +1898,33 @@ info_make (int type, int sub_type, struct peer *peer, struct attr *attr,
return new;
}

+static bool
+labels_equal(struct bgp_info *info, uint32_t *labels, size_t nlabels)
+{
+ uint32_t *info_labels;
+ size_t info_nlabels;
+
+ if (!info->extra) {
+ info_labels = NULL;
+ info_nlabels = 0;
+ } else {
+ info_labels = info->extra->labels;
+ info_nlabels = info->extra->nlabels;
+ }
+
+ if (info_nlabels != nlabels)
+ return false;
+
+ if (!nlabels)
+ return true;
+
+ return !memcmp(labels, info_labels, nlabels * sizeof(labels[0]));
+}
+
static void
bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
struct attr *attr, struct peer *peer, struct prefix *p, int type,
- int sub_type, struct prefix_rd *prd, u_char *tag)
+ int sub_type, struct prefix_rd *prd, uint32_t *labels, size_t nlabels)
{
struct bgp_node *rn;
struct bgp *bgp;
@@ -1987,7 +2010,8 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,

/* Same attribute comes in. */
if (!CHECK_FLAG(ri->flags, BGP_INFO_REMOVED)
- && attrhash_cmp (ri->attr, attr_new))
+ && attrhash_cmp (ri->attr, attr_new)
+ && labels_equal (ri, labels, nlabels))
{


@@ -2022,9 +2046,14 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
bgp_attr_unintern (&ri->attr);
ri->attr = attr_new;

- /* Update MPLS tag. */
- if (safi == SAFI_MPLS_VPN)
- memcpy ((bgp_info_extra_get (ri))->tag, tag, 3);
+ /* Update MPLS tag. */
+ if (nlabels)
+ {
+ bgp_info_extra_get (ri)->nlabels = nlabels;
+ memcpy (ri->extra->labels, labels, sizeof(*labels) * nlabels);
+ }
+ else if (ri->extra)
+ ri->extra->nlabels = 0;

bgp_info_set_flag (rn, ri, BGP_INFO_VALID);

@@ -2047,8 +2076,11 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
new = info_make(type, sub_type, peer, attr_new, rn);

/* Update MPLS tag. */
- if (safi == SAFI_MPLS_VPN)
- memcpy ((bgp_info_extra_get (new))->tag, tag, 3);
+ if (nlabels)
+ {
+ bgp_info_extra_get (ri)->nlabels = nlabels;
+ memcpy (ri->extra->labels, labels, sizeof(*labels) * nlabels);
+ }

bgp_info_set_flag (rn, new, BGP_INFO_VALID);

@@ -2084,7 +2116,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
static void
bgp_withdraw_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
struct peer *peer, struct prefix *p, int type, int sub_type,
- struct prefix_rd *prd, u_char *tag)
+ struct prefix_rd *prd)
{
struct bgp_node *rn;
struct bgp_info *ri;
@@ -2116,7 +2148,8 @@ bgp_withdraw_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
static int
bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
afi_t afi, safi_t safi, int type, int sub_type,
- struct prefix_rd *prd, u_char *tag, int soft_reconfig)
+ struct prefix_rd *prd, uint32_t *labels, size_t nlabels,
+ int soft_reconfig)
{
int ret;
int aspath_loop_count = 0;
@@ -2231,7 +2264,8 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,

/* Same attribute comes in. */
if (!CHECK_FLAG (ri->flags, BGP_INFO_REMOVED)
- && attrhash_cmp (ri->attr, attr_new))
+ && attrhash_cmp (ri->attr, attr_new)
+ && labels_equal (ri, labels, nlabels))
{
if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
&& peer->sort == BGP_PEER_EBGP
@@ -2317,9 +2351,14 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
bgp_attr_unintern (&ri->attr);
ri->attr = attr_new;

- /* Update MPLS tag. */
- if (safi == SAFI_MPLS_VPN)
- memcpy ((bgp_info_extra_get (ri))->tag, tag, 3);
+ /* Update MPLS tag. */
+ if (nlabels)
+ {
+ bgp_info_extra_get (ri)->nlabels = nlabels;
+ memcpy (ri->extra->labels, labels, sizeof(*labels) * nlabels);
+ }
+ else if (ri->extra)
+ ri->extra->nlabels = 0;

bgp_attr_flush (&new_attr);

@@ -2385,8 +2424,11 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
new = info_make(type, sub_type, peer, attr_new, rn);

/* Update MPLS tag. */
- if (safi == SAFI_MPLS_VPN)
- memcpy ((bgp_info_extra_get (new))->tag, tag, 3);
+ if (nlabels)
+ {
+ bgp_info_extra_get (new)->nlabels = nlabels;
+ memcpy (new->extra->labels, labels, sizeof(*labels) * nlabels);
+ }

/* Nexthop reachability check. */
if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST)
@@ -2456,15 +2498,16 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
int
bgp_update (struct peer *peer, struct prefix *p, struct attr *attr,
afi_t afi, safi_t safi, int type, int sub_type,
- struct prefix_rd *prd, u_char *tag, int soft_reconfig)
+ struct prefix_rd *prd, uint32_t *labels, size_t nlabels,
+ int soft_reconfig)
{
struct peer *rsclient;
struct listnode *node, *nnode;
struct bgp *bgp;
int ret;

- ret = bgp_update_main (peer, p, attr, afi, safi, type, sub_type, prd, tag,
- soft_reconfig);
+ ret = bgp_update_main (peer, p, attr, afi, safi, type, sub_type, prd,
+ labels, nlabels, soft_reconfig);

bgp = peer->bgp;

@@ -2473,7 +2516,7 @@ bgp_update (struct peer *peer, struct prefix *p, struct attr *attr,
{
if (CHECK_FLAG (rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
bgp_update_rsclient (rsclient, afi, safi, attr, peer, p, type,
- sub_type, prd, tag);
+ sub_type, prd, labels, nlabels);
}

return ret;
@@ -2482,7 +2525,7 @@ bgp_update (struct peer *peer, struct prefix *p, struct attr *attr,
int
bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr,
afi_t afi, safi_t safi, int type, int sub_type,
- struct prefix_rd *prd, u_char *tag)
+ struct prefix_rd *prd, uint32_t *labels, size_t nlabels)
{
struct bgp *bgp;
char buf[SU_ADDRSTRLEN];
@@ -2518,7 +2561,7 @@ bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr,
for (ALL_LIST_ELEMENTS (bgp->rsclient, node, nnode, rsclient))
{
if (CHECK_FLAG (rsclient->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
- bgp_withdraw_rsclient (rsclient, afi, safi, peer, p, type, sub_type, prd, tag);
+ bgp_withdraw_rsclient (rsclient, afi, safi, peer, p, type, sub_type, prd);
}

/* Logging. */
@@ -2738,10 +2781,11 @@ bgp_soft_reconfig_table_rsclient (struct peer *rsclient, afi_t afi,
for (ain = rn->adj_in; ain; ain = ain->next)
{
struct bgp_info *ri = rn->info;
- u_char *tag = (ri && ri->extra) ? ri->extra->tag : NULL;
+ uint32_t *labels = (ri && ri->extra) ? ri->extra->labels : NULL;
+ size_t nlabels = (ri && ri->extra) ? ri->extra->nlabels : 0;

bgp_update_rsclient (rsclient, afi, safi, ain->attr, ain->peer,
- &rn->p, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, prd, tag);
+ &rn->p, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, prd, labels, nlabels);
}
}

@@ -2785,11 +2829,12 @@ bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi,
if (ain->peer == peer)
{
struct bgp_info *ri = rn->info;
- u_char *tag = (ri && ri->extra) ? ri->extra->tag : NULL;
+ uint32_t *labels = (ri && ri->extra) ? ri->extra->labels : NULL;
+ size_t nlabels = (ri && ri->extra) ? ri->extra->nlabels : 0;

ret = bgp_update (peer, &rn->p, ain->attr, afi, safi,
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
- prd, tag, 1);
+ prd, labels, nlabels, 1);

if (ret < 0)
{
@@ -3351,10 +3396,10 @@ bgp_nlri_parse_ip (struct peer *peer, struct attr *attr,
/* Normal process. */
if (attr)
ret = bgp_update (peer, &p, attr, packet->afi, packet->safi,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, 0);
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, 0, 0);
else
ret = bgp_withdraw (peer, &p, attr, packet->afi, packet->safi,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL);
+ ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, 0);

/* Address family configuration mismatch or maximum-prefix count
overflow. */
@@ -3827,7 +3872,8 @@ bgp_check_local_routes_rsclient (struct peer *rsclient, afi_t afi, safi_t safi)
*/
static void
bgp_static_withdraw_safi (struct bgp *bgp, struct prefix *p, afi_t afi,
- safi_t safi, struct prefix_rd *prd, u_char *tag)
+ safi_t safi, struct prefix_rd *prd,
+ uint32_t *labels, size_t nlabels)
{
struct bgp_node *rn;
struct bgp_info *ri;
@@ -3898,7 +3944,7 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p,
aspath_unintern (&attr.aspath);
bgp_attr_extra_free (&attr);
bgp_static_withdraw_safi (bgp, p, afi, safi, &bgp_static->prd,
- bgp_static->tag);
+ bgp_static->labels, bgp_static->nlabels);
return;
}

@@ -3955,7 +4001,9 @@ bgp_static_update_safi (struct bgp *bgp, struct prefix *p,
attr_new, rn);
SET_FLAG (new->flags, BGP_INFO_VALID);
new->extra = bgp_info_extra_new();
- memcpy (new->extra->tag, bgp_static->tag, 3);
+ new->extra->nlabels = bgp_static->nlabels;
+ memcpy (new->extra->labels, bgp_static->labels,
+ sizeof(*bgp_static->labels) * bgp_static->nlabels);

/* Aggregate address increment. */
bgp_aggregate_increment (bgp, p, new, afi, safi);
@@ -4138,7 +4186,8 @@ bgp_static_delete (struct bgp *bgp)
bgp_static_withdraw_safi (bgp, &rm->p,
AFI_IP, safi,
(struct prefix_rd *)&rn->p,
- bgp_static->tag);
+ bgp_static->labels,
+ bgp_static->nlabels);
bgp_static_free (bgp_static);
rn->info = NULL;
bgp_unlock_node (rn);
@@ -4173,7 +4222,8 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str,
struct bgp_node *rn;
struct bgp_table *table;
struct bgp_static *bgp_static;
- u_char tag[3];
+ uint32_t labels[BGP_MAX_LABELS];
+ size_t nlabels;

bgp = vty->index;

@@ -4192,8 +4242,7 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str,
return CMD_WARNING;
}

- ret = str2tag (tag_str, tag);
- if (! ret)
+ if (! str2labels (tag_str, labels, &nlabels))
{
vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -4222,7 +4271,8 @@ bgp_static_set_safi (safi_t safi, struct vty *vty, const char *ip_str,
bgp_static->valid = 0;
bgp_static->igpmetric = 0;
bgp_static->igpnexthop.s_addr = 0;
- memcpy(bgp_static->tag, tag, 3);
+ memcpy(bgp_static->labels, labels, sizeof(labels[0]) * nlabels);
+ bgp_static->nlabels = nlabels;
bgp_static->prd = prd;

if (rmap_str)
@@ -4254,7 +4304,8 @@ bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str,
struct bgp_node *rn;
struct bgp_table *table;
struct bgp_static *bgp_static;
- u_char tag[3];
+ uint32_t labels[BGP_MAX_LABELS];
+ size_t nlabels;

bgp = vty->index;

@@ -4274,8 +4325,7 @@ bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str,
return CMD_WARNING;
}

- ret = str2tag (tag_str, tag);
- if (! ret)
+ if (! str2labels (tag_str, labels, &nlabels))
{
vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE);
return CMD_WARNING;
@@ -4293,7 +4343,7 @@ bgp_static_unset_safi(safi_t safi, struct vty *vty, const char *ip_str,

if (rn)
{
- bgp_static_withdraw_safi (bgp, &p, AFI_IP, safi, &prd, tag);
+ bgp_static_withdraw_safi (bgp, &p, AFI_IP, safi, &prd, labels, nlabels);

bgp_static = rn->info;
bgp_static_free (bgp_static);
@@ -6123,7 +6173,6 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
struct bgp_info *binfo, int display, safi_t safi)
{
struct attr *attr;
- u_int32_t label = 0;

if (!binfo->extra)
return;
@@ -6168,9 +6217,9 @@ route_vty_out_tag (struct vty *vty, struct prefix *p,
}
}

- label = decode_label (binfo->extra->tag);
-
- vty_out (vty, "notag/%d", label);
+ char buf[BUFSIZ];
+ vty_out (vty, ":/%s", labels2str (buf, sizeof(buf),
+ binfo->extra->labels, binfo->extra->nlabels));

vty_out (vty, "%s", VTY_NEWLINE);
}
@@ -16046,9 +16095,9 @@ bgp_config_write_network_vpnv4 (struct vty *vty, struct bgp *bgp,
struct prefix *p;
struct prefix_rd *prd;
struct bgp_static *bgp_static;
- u_int32_t label;
char buf[SU_ADDRSTRLEN];
char rdbuf[RD_ADDRSTRLEN];
+ char lblbuf[BUFSIZ];

/* Network configuration. */
for (prn = bgp_table_top (bgp->route[afi][safi]); prn; prn = bgp_route_next (prn))
@@ -16064,12 +16113,13 @@ bgp_config_write_network_vpnv4 (struct vty *vty, struct bgp *bgp,

/* "network" configuration display. */
prefix_rd2str (prd, rdbuf, RD_ADDRSTRLEN);
- label = decode_label (bgp_static->tag);
+ labels2str (lblbuf, sizeof(lblbuf),
+ bgp_static->labels, bgp_static->nlabels);

- vty_out (vty, " network %s/%d rd %s tag %d",
+ vty_out (vty, " network %s/%d rd %s tag %s",
inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
p->prefixlen,
- rdbuf, label);
+ rdbuf, lblbuf);
vty_out (vty, "%s", VTY_NEWLINE);
}
return 0;
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 332714c4f845..a254e0e3af7e 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -24,6 +24,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "queue.h"
#include "bgp_table.h"

+#define BGP_MAX_LABELS 6
+
struct bgp_nexthop_cache;

/* Ancillary information to struct bgp_info,
@@ -42,7 +44,8 @@ struct bgp_info_extra
u_int32_t igpmetric;

/* MPLS label. */
- u_char tag[3];
+ uint32_t labels[BGP_MAX_LABELS];
+ size_t nlabels;
};

struct bgp_info
@@ -135,8 +138,9 @@ struct bgp_static
/* Route Distinguisher */
struct prefix_rd prd;

- /* MPLS label. */
- u_char tag[3];
+ /* MPLS label. */
+ uint32_t labels[BGP_MAX_LABELS];
+ size_t nlabels;
};

#define BGP_INFO_COUNTABLE(BI) \
@@ -243,9 +247,10 @@ extern int bgp_static_unset_safi (safi_t safi, struct vty *, const char *,
/* this is primarily for MPLS-VPN */
extern int bgp_update (struct peer *, struct prefix *, struct attr *,
afi_t, safi_t, int, int, struct prefix_rd *,
- u_char *, int);
+ uint32_t *labels, size_t nlabels, int);
extern int bgp_withdraw (struct peer *, struct prefix *, struct attr *,
- afi_t, safi_t, int, int, struct prefix_rd *, u_char *);
+ afi_t, safi_t, int, int, struct prefix_rd *,
+ uint32_t *labels, size_t nlabels);

/* for bgp_nexthop and bgp_damp */
extern void bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t);
--
2.1.4


_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
https://lists.quagga.net/mailman/listinfo/quagga-dev