summaryrefslogtreecommitdiff
path: root/bgpd
diff options
context:
space:
mode:
authorRuss White <russ@riw.us>2021-09-21 11:36:53 -0400
committerGitHub <noreply@github.com>2021-09-21 11:36:53 -0400
commit2075387e77c06218eebcee597664f09c3724781e (patch)
tree0d0015c2c72193f336ab68f75d2244849c39d634 /bgpd
parent48f23c8879754262b359fb7cc1a9cdf43ed574a7 (diff)
parent242302ffb2edebd250a7ab10533ba08e0babc59d (diff)
Merge pull request #9546 from proelbtn/add-support-for-perfix-sid-type-5
Add support for Prefix-SID (Type 5)
Diffstat (limited to 'bgpd')
-rw-r--r--bgpd/bgp_attr.c247
-rw-r--r--bgpd/bgp_attr.h23
-rw-r--r--bgpd/bgp_mplsvpn.c101
-rw-r--r--bgpd/bgp_mplsvpn.h2
-rw-r--r--bgpd/bgp_route.c65
-rw-r--r--bgpd/bgp_route.h10
-rw-r--r--bgpd/bgp_zebra.c5
-rw-r--r--bgpd/bgpd.h1
-rw-r--r--bgpd/rfapi/rfapi_vty.c12
9 files changed, 398 insertions, 68 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index eeb0ac5c6a..7de7a6628f 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -530,6 +530,12 @@ static uint32_t srv6_l3vpn_hash_key_make(const void *p)
key = jhash(&l3vpn->sid, 16, key);
key = jhash_1word(l3vpn->sid_flags, key);
key = jhash_1word(l3vpn->endpoint_behavior, key);
+ key = jhash_1word(l3vpn->loc_block_len, key);
+ key = jhash_1word(l3vpn->loc_node_len, key);
+ key = jhash_1word(l3vpn->func_len, key);
+ key = jhash_1word(l3vpn->arg_len, key);
+ key = jhash_1word(l3vpn->transposition_len, key);
+ key = jhash_1word(l3vpn->transposition_offset, key);
return key;
}
@@ -540,7 +546,13 @@ static bool srv6_l3vpn_hash_cmp(const void *p1, const void *p2)
return sid_same(&l3vpn1->sid, &l3vpn2->sid)
&& l3vpn1->sid_flags == l3vpn2->sid_flags
- && l3vpn1->endpoint_behavior == l3vpn2->endpoint_behavior;
+ && l3vpn1->endpoint_behavior == l3vpn2->endpoint_behavior
+ && l3vpn1->loc_block_len == l3vpn2->loc_block_len
+ && l3vpn1->loc_node_len == l3vpn2->loc_node_len
+ && l3vpn1->func_len == l3vpn2->func_len
+ && l3vpn1->arg_len == l3vpn2->arg_len
+ && l3vpn1->transposition_len == l3vpn2->transposition_len
+ && l3vpn1->transposition_offset == l3vpn2->transposition_offset;
}
static bool srv6_l3vpn_same(const struct bgp_attr_srv6_l3vpn *h1,
@@ -2533,6 +2545,172 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */
return 0;
}
+
+/* SRv6 Service Data Sub-Sub-TLV attribute
+ * draft-ietf-bess-srv6-services-07
+ */
+static bgp_attr_parse_ret_t
+bgp_attr_srv6_service_data(struct bgp_attr_parser_args *args)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ uint8_t type, loc_block_len, loc_node_len, func_len, arg_len,
+ transposition_len, transposition_offset;
+ uint16_t length;
+ size_t headersz = sizeof(type) + sizeof(length);
+
+ if (STREAM_READABLE(peer->curr) < headersz) {
+ flog_err(
+ EC_BGP_ATTR_LEN,
+ "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
+ headersz, STREAM_READABLE(peer->curr));
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ type = stream_getc(peer->curr);
+ length = stream_getw(peer->curr);
+
+ if (STREAM_READABLE(peer->curr) < length) {
+ flog_err(
+ EC_BGP_ATTR_LEN,
+ "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
+ length, STREAM_READABLE(peer->curr));
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE) {
+ loc_block_len = stream_getc(peer->curr);
+ loc_node_len = stream_getc(peer->curr);
+ func_len = stream_getc(peer->curr);
+ arg_len = stream_getc(peer->curr);
+ transposition_len = stream_getc(peer->curr);
+ transposition_offset = stream_getc(peer->curr);
+
+ /* Log SRv6 Service Data Sub-Sub-TLV */
+ if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
+ zlog_debug(
+ "%s: srv6-l3-srv-data loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u, transposition-len=%u, transposition-offset=%u",
+ __func__, loc_block_len, loc_node_len, func_len,
+ arg_len, transposition_len,
+ transposition_offset);
+ }
+
+ attr->srv6_l3vpn->loc_block_len = loc_block_len;
+ attr->srv6_l3vpn->loc_node_len = loc_node_len;
+ attr->srv6_l3vpn->func_len = func_len;
+ attr->srv6_l3vpn->arg_len = arg_len;
+ attr->srv6_l3vpn->transposition_len = transposition_len;
+ attr->srv6_l3vpn->transposition_offset = transposition_offset;
+ }
+
+ else {
+ if (bgp_debug_update(peer, NULL, NULL, 1))
+ zlog_debug(
+ "%s attr SRv6 Service Data Sub-Sub-TLV sub-sub-type=%u is not supported, skipped",
+ peer->host, type);
+
+ stream_forward_getp(peer->curr, length);
+ }
+
+ return BGP_ATTR_PARSE_PROCEED;
+}
+
+/* SRv6 Service Sub-TLV attribute
+ * draft-ietf-bess-srv6-services-07
+ */
+static bgp_attr_parse_ret_t
+bgp_attr_srv6_service(struct bgp_attr_parser_args *args)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ struct in6_addr ipv6_sid;
+ uint8_t type, sid_flags;
+ uint16_t length, endpoint_behavior;
+ size_t headersz = sizeof(type) + sizeof(length);
+ bgp_attr_parse_ret_t err;
+ char buf[BUFSIZ];
+
+ if (STREAM_READABLE(peer->curr) < headersz) {
+ flog_err(
+ EC_BGP_ATTR_LEN,
+ "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
+ headersz, STREAM_READABLE(peer->curr));
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ type = stream_getc(peer->curr);
+ length = stream_getw(peer->curr);
+
+ if (STREAM_READABLE(peer->curr) < length) {
+ flog_err(
+ EC_BGP_ATTR_LEN,
+ "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
+ length, STREAM_READABLE(peer->curr));
+ return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO) {
+ stream_getc(peer->curr);
+ stream_get(&ipv6_sid, peer->curr, sizeof(ipv6_sid));
+ sid_flags = stream_getc(peer->curr);
+ endpoint_behavior = stream_getw(peer->curr);
+ stream_getc(peer->curr);
+
+ /* Log SRv6 Service Sub-TLV */
+ if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
+ inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf));
+ zlog_debug(
+ "%s: srv6-l3-srv sid %s, sid-flags 0x%02x, end-behaviour 0x%04x",
+ __func__, buf, sid_flags, endpoint_behavior);
+ }
+
+ /* Configure from Info */
+ if (attr->srv6_l3vpn) {
+ flog_err(EC_BGP_ATTRIBUTE_REPEATED,
+ "Prefix SID SRv6 L3VPN field repeated");
+ return bgp_attr_malformed(
+ args, BGP_NOTIFY_UPDATE_MAL_ATTR, args->total);
+ }
+ attr->srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,
+ sizeof(struct bgp_attr_srv6_l3vpn));
+ sid_copy(&attr->srv6_l3vpn->sid, &ipv6_sid);
+ attr->srv6_l3vpn->sid_flags = sid_flags;
+ attr->srv6_l3vpn->endpoint_behavior = endpoint_behavior;
+ attr->srv6_l3vpn->loc_block_len = 0;
+ attr->srv6_l3vpn->loc_node_len = 0;
+ attr->srv6_l3vpn->func_len = 0;
+ attr->srv6_l3vpn->arg_len = 0;
+ attr->srv6_l3vpn->transposition_len = 0;
+ attr->srv6_l3vpn->transposition_offset = 0;
+
+ // Sub-Sub-TLV found
+ if (length > BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH) {
+ err = bgp_attr_srv6_service_data(args);
+
+ if (err != BGP_ATTR_PARSE_PROCEED)
+ return err;
+ }
+
+ attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn);
+ }
+
+ /* Placeholder code for unsupported type */
+ else {
+ if (bgp_debug_update(peer, NULL, NULL, 1))
+ zlog_debug(
+ "%s attr SRv6 Service Sub-TLV sub-type=%u is not supported, skipped",
+ peer->host, type);
+
+ stream_forward_getp(peer->curr, length);
+ }
+
+ return BGP_ATTR_PARSE_PROCEED;
+}
+
/*
* Read an individual SID value returning how much data we have read
* Returns 0 if there was an error that needs to be passed up the stack
@@ -2548,7 +2726,6 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,
uint32_t srgb_range;
int srgb_count;
uint8_t sid_type, sid_flags;
- uint16_t endpoint_behavior;
char buf[BUFSIZ];
if (type == BGP_PREFIX_SID_LABEL_INDEX) {
@@ -2703,45 +2880,20 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,
/* Placeholder code for the SRv6 L3 Service type */
else if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE) {
- if (STREAM_READABLE(peer->curr) < length
- || length != BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH) {
- flog_err(EC_BGP_ATTR_LEN,
- "Prefix SID SRv6 L3-Service length is %hu instead of %u",
- length, BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH);
+ if (STREAM_READABLE(peer->curr) < length) {
+ flog_err(
+ EC_BGP_ATTR_LEN,
+ "Prefix SID SRv6 L3-Service length is %hu, but only %zu bytes remain",
+ length, STREAM_READABLE(peer->curr));
return bgp_attr_malformed(args,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
}
- /* Parse L3-SERVICE Sub-TLV */
- stream_getc(peer->curr); /* reserved */
- stream_get(&ipv6_sid, peer->curr,
- sizeof(ipv6_sid)); /* sid_value */
- sid_flags = stream_getc(peer->curr); /* sid_flags */
- endpoint_behavior = stream_getw(peer->curr); /* endpoint */
- stream_getc(peer->curr); /* reserved */
-
- /* Log L3-SERVICE Sub-TLV */
- if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
- inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf));
- zlog_debug(
- "%s: srv6-l3-srv sid %s, sid-flags 0x%02x, end-behaviour 0x%04x",
- __func__, buf, sid_flags, endpoint_behavior);
- }
+ /* ignore reserved */
+ stream_getc(peer->curr);
- /* Configure from Info */
- if (attr->srv6_l3vpn) {
- flog_err(EC_BGP_ATTRIBUTE_REPEATED,
- "Prefix SID SRv6 L3VPN field repeated");
- return bgp_attr_malformed(
- args, BGP_NOTIFY_UPDATE_MAL_ATTR, args->total);
- }
- attr->srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,
- sizeof(struct bgp_attr_srv6_l3vpn));
- attr->srv6_l3vpn->sid_flags = sid_flags;
- attr->srv6_l3vpn->endpoint_behavior = endpoint_behavior;
- sid_copy(&attr->srv6_l3vpn->sid, &ipv6_sid);
- attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn);
+ return bgp_attr_srv6_service(args);
}
/* Placeholder code for Unsupported TLV */
@@ -4123,18 +4275,39 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
/* SRv6 Service Information Attribute. */
if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_MPLS_VPN) {
if (attr->srv6_l3vpn) {
+ uint8_t subtlv_len =
+ BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
+ + BGP_ATTR_MIN_LEN
+ + BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH;
+ uint8_t tlv_len = subtlv_len + BGP_ATTR_MIN_LEN + 1;
+ uint8_t attr_len = tlv_len + BGP_ATTR_MIN_LEN;
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_PREFIX_SID);
- stream_putc(s, 24); /* tlv len */
+ stream_putc(s, attr_len);
stream_putc(s, BGP_PREFIX_SID_SRV6_L3_SERVICE);
- stream_putw(s, 21); /* sub-tlv len */
+ stream_putw(s, tlv_len);
+ stream_putc(s, 0); /* reserved */
+ stream_putc(s, BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO);
+ stream_putw(s, subtlv_len);
stream_putc(s, 0); /* reserved */
stream_put(s, &attr->srv6_l3vpn->sid,
sizeof(attr->srv6_l3vpn->sid)); /* sid */
stream_putc(s, 0); /* sid_flags */
stream_putw(s, 0xffff); /* endpoint */
stream_putc(s, 0); /* reserved */
+ stream_putc(
+ s,
+ BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE);
+ stream_putw(
+ s,
+ BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH);
+ stream_putc(s, attr->srv6_l3vpn->loc_block_len);
+ stream_putc(s, attr->srv6_l3vpn->loc_node_len);
+ stream_putc(s, attr->srv6_l3vpn->func_len);
+ stream_putc(s, attr->srv6_l3vpn->arg_len);
+ stream_putc(s, attr->srv6_l3vpn->transposition_len);
+ stream_putc(s, attr->srv6_l3vpn->transposition_offset);
} else if (attr->srv6_vpn) {
stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
| BGP_ATTR_FLAG_TRANS);
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 6c49cf509f..3573c2ae03 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -71,7 +71,22 @@
#define BGP_PREFIX_SID_IPV6_LENGTH 19
#define BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH 6
#define BGP_PREFIX_SID_VPN_SID_LENGTH 19
-#define BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH 21
+
+/* SRv6 Service Sub-TLV types */
+#define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO 1
+#define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH 21
+
+/* SRv6 Service Data Sub-Sub-TLV types */
+#define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE 1
+#define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH 6
+
+/* SRv6 SID Structure default values */
+#define BGP_PREFIX_SID_SRV6_LOCATOR_BLOCK_LENGTH 40
+#define BGP_PREFIX_SID_SRV6_LOCATOR_NODE_LENGTH 24
+#define BGP_PREFIX_SID_SRV6_FUNCTION_LENGTH 16
+#define BGP_PREFIX_SID_SRV6_ARGUMENT_LENGTH 0
+#define BGP_PREFIX_SID_SRV6_TRANSPOSITION_LENGTH 16
+#define BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET 64
#define BGP_ATTR_NH_AFI(afi, attr) \
((afi != AFI_L2VPN) ? afi : \
@@ -136,6 +151,12 @@ struct bgp_attr_srv6_l3vpn {
uint8_t sid_flags;
uint16_t endpoint_behavior;
struct in6_addr sid;
+ uint8_t loc_block_len;
+ uint8_t loc_node_len;
+ uint8_t func_len;
+ uint8_t arg_len;
+ uint8_t transposition_len;
+ uint8_t transposition_offset;
};
/* BGP core attribute structure. */
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index b0bab02fb8..659029b04c 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -522,13 +522,14 @@ static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid)
* if index != 0: try to allocate as index-mode
* else: try to allocate as auto-mode
*/
-static bool alloc_new_sid(struct bgp *bgp, uint32_t index,
- struct in6_addr *sid)
+static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index,
+ struct in6_addr *sid)
{
struct listnode *node;
struct prefix_ipv6 *chunk;
struct in6_addr sid_buf;
bool alloced = false;
+ int label;
if (!bgp || !sid)
return false;
@@ -536,7 +537,8 @@ static bool alloc_new_sid(struct bgp *bgp, uint32_t index,
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) {
sid_buf = chunk->prefix;
if (index != 0) {
- sid_buf.s6_addr[15] = index;
+ label = index << 12;
+ transpose_sid(&sid_buf, label, 64, 16);
if (sid_exist(bgp, &sid_buf))
return false;
alloced = true;
@@ -544,9 +546,8 @@ static bool alloc_new_sid(struct bgp *bgp, uint32_t index,
}
for (size_t i = 1; i < 255; i++) {
- sid_buf.s6_addr[15] = (i & 0xff00) >> 8;
- sid_buf.s6_addr[14] = (i & 0x00ff);
-
+ label = i << 12;
+ transpose_sid(&sid_buf, label, 64, 16);
if (sid_exist(bgp, &sid_buf))
continue;
alloced = true;
@@ -555,20 +556,19 @@ static bool alloc_new_sid(struct bgp *bgp, uint32_t index,
}
if (!alloced)
- return false;
+ return 0;
sid_register(bgp, &sid_buf, bgp->srv6_locator_name);
*sid = sid_buf;
- return true;
+ return label;
}
void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
- bool alloced = false;
char buf[256];
struct in6_addr *sid;
- uint32_t tovpn_sid_index = 0;
+ uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
bool tovpn_sid_auto = false;
if (debug)
@@ -602,8 +602,9 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
}
sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
- alloced = alloc_new_sid(bgp_vpn, tovpn_sid_index, sid);
- if (!alloced) {
+ tovpn_sid_transpose_label =
+ alloc_new_sid(bgp_vpn, tovpn_sid_index, sid);
+ if (tovpn_sid_transpose_label == 0) {
zlog_debug("%s: not allocated new sid for vrf %s: afi %s",
__func__, bgp_vrf->name_pretty, afi2str(afi));
return;
@@ -615,9 +616,22 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
__func__, buf, bgp_vrf->name_pretty,
afi2str(afi));
}
+ bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label =
+ tovpn_sid_transpose_label;
bgp_vrf->vpn_policy[afi].tovpn_sid = sid;
}
+void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset,
+ uint8_t len)
+{
+ for (uint8_t idx = 0; idx < len; idx++) {
+ uint8_t tidx = offset + idx;
+ sid->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8));
+ if (label >> (19 - idx) & 0x1)
+ sid->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8);
+ }
+}
+
static bool ecom_intersect(struct ecommunity *e1, struct ecommunity *e2)
{
uint32_t i, j;
@@ -710,7 +724,7 @@ static void setsids(struct bgp_path_info *bpi,
extra = bgp_path_info_extra_get(bpi);
for (i = 0; i < num_sids; i++)
- memcpy(&extra->sid[i], &sid[i], sizeof(struct in6_addr));
+ memcpy(&extra->sid[i].sid, &sid[i], sizeof(struct in6_addr));
extra->num_sids = num_sids;
}
@@ -738,6 +752,7 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
struct bgp_path_info *bpi;
struct bgp_path_info *bpi_ultimate;
struct bgp_path_info *new;
+ struct bgp_path_info_extra *extra;
uint32_t num_sids = 0;
if (new_attr->srv6_l3vpn || new_attr->srv6_vpn)
@@ -824,10 +839,31 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
* rewrite sid
*/
if (num_sids) {
- if (new_attr->srv6_l3vpn)
+ if (new_attr->srv6_l3vpn) {
setsids(bpi, &new_attr->srv6_l3vpn->sid,
num_sids);
- else if (new_attr->srv6_vpn)
+
+ extra = bgp_path_info_extra_get(bpi);
+
+ extra->sid[0].loc_block_len =
+ new_attr->srv6_l3vpn->loc_block_len;
+ extra->sid[0].loc_node_len =
+ new_attr->srv6_l3vpn->loc_node_len;
+ extra->sid[0].func_len =
+ new_attr->srv6_l3vpn->func_len;
+ extra->sid[0].arg_len =
+ new_attr->srv6_l3vpn->arg_len;
+
+ if (new_attr->srv6_l3vpn->transposition_len
+ != 0)
+ transpose_sid(
+ &extra->sid[0].sid,
+ decode_label(label),
+ new_attr->srv6_l3vpn
+ ->transposition_offset,
+ new_attr->srv6_l3vpn
+ ->transposition_len);
+ } else if (new_attr->srv6_vpn)
setsids(bpi, &new_attr->srv6_vpn->sid,
num_sids);
} else
@@ -910,9 +946,26 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
* rewrite sid
*/
if (num_sids) {
- if (new_attr->srv6_l3vpn)
+ if (new_attr->srv6_l3vpn) {
setsids(new, &new_attr->srv6_l3vpn->sid, num_sids);
- else if (new_attr->srv6_vpn)
+
+ extra = bgp_path_info_extra_get(new);
+
+ extra->sid[0].loc_block_len =
+ new_attr->srv6_l3vpn->loc_block_len;
+ extra->sid[0].loc_node_len =
+ new_attr->srv6_l3vpn->loc_node_len;
+ extra->sid[0].func_len = new_attr->srv6_l3vpn->func_len;
+ extra->sid[0].arg_len = new_attr->srv6_l3vpn->arg_len;
+
+ if (new_attr->srv6_l3vpn->transposition_len != 0)
+ transpose_sid(&extra->sid[0].sid,
+ decode_label(label),
+ new_attr->srv6_l3vpn
+ ->transposition_offset,
+ new_attr->srv6_l3vpn
+ ->transposition_len);
+ } else if (new_attr->srv6_vpn)
setsids(new, &new_attr->srv6_vpn->sid, num_sids);
} else
unsetsids(new);
@@ -1186,10 +1239,24 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */
/* Set SID for SRv6 VPN */
if (bgp_vrf->vpn_policy[afi].tovpn_sid) {
+ encode_label(bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label,
+ &label);
static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,
sizeof(struct bgp_attr_srv6_l3vpn));
static_attr.srv6_l3vpn->sid_flags = 0x00;
static_attr.srv6_l3vpn->endpoint_behavior = 0xffff;
+ static_attr.srv6_l3vpn->loc_block_len =
+ BGP_PREFIX_SID_SRV6_LOCATOR_BLOCK_LENGTH;
+ static_attr.srv6_l3vpn->loc_node_len =
+ BGP_PREFIX_SID_SRV6_LOCATOR_NODE_LENGTH;
+ static_attr.srv6_l3vpn->func_len =
+ BGP_PREFIX_SID_SRV6_FUNCTION_LENGTH;
+ static_attr.srv6_l3vpn->arg_len =
+ BGP_PREFIX_SID_SRV6_ARGUMENT_LENGTH;
+ static_attr.srv6_l3vpn->transposition_len =
+ BGP_PREFIX_SID_SRV6_TRANSPOSITION_LENGTH;
+ static_attr.srv6_l3vpn->transposition_offset =
+ BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET;
memcpy(&static_attr.srv6_l3vpn->sid,
bgp_vrf->vpn_policy[afi].tovpn_sid,
sizeof(static_attr.srv6_l3vpn->sid));
diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h
index b0e0f74f77..b0d586223f 100644
--- a/bgpd/bgp_mplsvpn.h
+++ b/bgpd/bgp_mplsvpn.h
@@ -81,6 +81,8 @@ extern void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi);
extern void vpn_leak_zebra_vrf_sid_withdraw(struct bgp *bgp, afi_t afi);
extern int vpn_leak_label_callback(mpls_label_t label, void *lblid, bool alloc);
extern void ensure_vrf_tovpn_sid(struct bgp *vpn, struct bgp *vrf, afi_t afi);
+extern void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset,
+ uint8_t size);
extern void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
afi_t afi, safi_t safi);
void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 5a16fecc26..647ad55306 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -4042,15 +4042,48 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
/* Update SRv6 SID */
if (attr->srv6_l3vpn) {
extra = bgp_path_info_extra_get(pi);
- if (sid_diff(&extra->sid[0], &attr->srv6_l3vpn->sid)) {
- sid_copy(&extra->sid[0],
+ if (sid_diff(&extra->sid[0].sid,
+ &attr->srv6_l3vpn->sid)) {
+ sid_copy(&extra->sid[0].sid,
&attr->srv6_l3vpn->sid);
extra->num_sids = 1;
+
+ extra->sid[0].loc_block_len = 0;
+ extra->sid[0].loc_node_len = 0;
+ extra->sid[0].func_len = 0;
+ extra->sid[0].arg_len = 0;
+
+ if (attr->srv6_l3vpn->loc_block_len != 0) {
+ extra->sid[0].loc_block_len =
+ attr->srv6_l3vpn->loc_block_len;
+ extra->sid[0].loc_node_len =
+ attr->srv6_l3vpn->loc_node_len;
+ extra->sid[0].func_len =
+ attr->srv6_l3vpn->func_len;
+ extra->sid[0].arg_len =
+ attr->srv6_l3vpn->arg_len;
+ }
+
+ /*
+ * draft-ietf-bess-srv6-services-07
+ * The part of SRv6 SID may be encoded as MPLS
+ * Label for the efficient packing.
+ */
+ if (attr->srv6_l3vpn->transposition_len != 0)
+ transpose_sid(
+ &extra->sid[0].sid,
+ decode_label(label),
+ attr->srv6_l3vpn
+ ->transposition_offset,
+ attr->srv6_l3vpn
+ ->transposition_len);
}
} else if (attr->srv6_vpn) {
extra = bgp_path_info_extra_get(pi);
- if (sid_diff(&extra->sid[0], &attr->srv6_vpn->sid)) {
- sid_copy(&extra->sid[0], &attr->srv6_vpn->sid);
+ if (sid_diff(&extra->sid[0].sid,
+ &attr->srv6_vpn->sid)) {
+ sid_copy(&extra->sid[0].sid,
+ &attr->srv6_vpn->sid);
extra->num_sids = 1;
}
}
@@ -4231,10 +4264,28 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
if (safi == SAFI_MPLS_VPN) {
extra = bgp_path_info_extra_get(new);
if (attr->srv6_l3vpn) {
- sid_copy(&extra->sid[0], &attr->srv6_l3vpn->sid);
+ sid_copy(&extra->sid[0].sid, &attr->srv6_l3vpn->sid);
extra->num_sids = 1;
+
+ extra->sid[0].loc_block_len =
+ attr->srv6_l3vpn->loc_block_len;
+ extra->sid[0].loc_node_len =
+ attr->srv6_l3vpn->loc_node_len;
+ extra->sid[0].func_len = attr->srv6_l3vpn->func_len;
+ extra->sid[0].arg_len = attr->srv6_l3vpn->arg_len;
+
+ /*
+ * draft-ietf-bess-srv6-services-07
+ * The part of SRv6 SID may be encoded as MPLS Label for
+ * the efficient packing.
+ */
+ if (attr->srv6_l3vpn->transposition_len != 0)
+ transpose_sid(
+ &extra->sid[0].sid, decode_label(label),
+ attr->srv6_l3vpn->transposition_offset,
+ attr->srv6_l3vpn->transposition_len);
} else if (attr->srv6_vpn) {
- sid_copy(&extra->sid[0], &attr->srv6_vpn->sid);
+ sid_copy(&extra->sid[0].sid, &attr->srv6_vpn->sid);
extra->num_sids = 1;
}
}
@@ -10450,7 +10501,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
/* Remote SID */
if (path->extra && path->extra->num_sids > 0 && safi != SAFI_EVPN) {
- inet_ntop(AF_INET6, &path->extra->sid, buf, sizeof(buf));
+ inet_ntop(AF_INET6, &path->extra->sid[0].sid, buf, sizeof(buf));
if (json_paths)
json_object_string_add(json_path, "remoteSid", buf);
else
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index d052a3f408..7609f7196d 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -145,6 +145,14 @@ struct bgp_path_mh_info {
struct bgp_path_evpn_nh_info *nh_info;
};
+struct bgp_sid_info {
+ struct in6_addr sid;
+ uint8_t loc_block_len;
+ uint8_t loc_node_len;
+ uint8_t func_len;
+ uint8_t arg_len;
+};
+
/* Ancillary information to struct bgp_path_info,
* used for uncommonly used data (aggregation, MPLS, etc.)
* and lazily allocated to save memory.
@@ -168,7 +176,7 @@ struct bgp_path_info_extra {
#define BGP_EVPN_MACIP_TYPE_SVI_IP (1 << 0)
/* SRv6 SID(s) for SRv6-VPN */
- struct in6_addr sid[BGP_MAX_SIDS];
+ struct bgp_sid_info sid[BGP_MAX_SIDS];
uint32_t num_sids;
#ifdef ENABLE_BGP_VNC
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index b367b393d9..e8ca544c23 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1451,11 +1451,10 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
api_nh->weight = nh_weight;
- if (mpinfo->extra
- && !sid_zero(&mpinfo->extra->sid[0])
+ if (mpinfo->extra && !sid_zero(&mpinfo->extra->sid[0].sid)
&& !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) {
has_valid_sid = 1;
- memcpy(&api_nh->seg6_segs, &mpinfo->extra->sid[0],
+ memcpy(&api_nh->seg6_segs, &mpinfo->extra->sid[0].sid,
sizeof(api_nh->seg6_segs));
}
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 13b530a613..5e1eacbb9e 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -241,6 +241,7 @@ struct vpn_policy {
*/
uint32_t tovpn_sid_index; /* unset => set to 0 */
struct in6_addr *tovpn_sid;
+ uint32_t tovpn_sid_transpose_label;
struct in6_addr *tovpn_zebra_vrf_sid_last_sent;
};
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index 45ef7230b5..6762c2b4a2 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -435,8 +435,16 @@ void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p,
char buf[BUFSIZ];
vty_out(vty, " sid=%s",
- inet_ntop(AF_INET6, &bpi->extra->sid[0], buf,
- sizeof(buf)));
+ inet_ntop(AF_INET6, &bpi->extra->sid[0].sid,
+ buf, sizeof(buf)));
+
+ if (bpi->extra->sid[0].loc_block_len != 0) {
+ vty_out(vty, " sid_structure=[%d,%d,%d,%d]",
+ bpi->extra->sid[0].loc_block_len,
+ bpi->extra->sid[0].loc_node_len,
+ bpi->extra->sid[0].func_len,
+ bpi->extra->sid[0].arg_len);
+ }
}
}