From 6cf48acc1c17d590da4101fa5e0a2764cb931a9c Mon Sep 17 00:00:00 2001 From: Vivek Venkatraman Date: Thu, 9 Mar 2017 12:22:04 -0500 Subject: [PATCH] bgpd: This patch implements the exchange of the BGP-Prefix-SID label index attr Implement BGP Prefix-SID IETF draft to be able to signal a labeled-unicast prefix with a label index (segment ID). This makes it easier to deploy global MPLS labels with BGP, even without other aspects of Segment Routing implemented. Signed-off-by: Vivek Venkatraman --- bgpd/bgp_attr.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_attr.h | 3 ++ bgpd/bgp_debug.c | 4 +++ bgpd/bgp_label.c | 5 +++ bgpd/bgp_route.c | 36 ++++++++++++++++++++-- bgpd/bgp_table.h | 1 + bgpd/bgpd.h | 1 + 7 files changed, 127 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 2c6bb5de0e..acc08184b9 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -676,6 +676,7 @@ attrhash_key_make (void *p) MIX(extra->mp_nexthop_global_in.s_addr); MIX(extra->originator_id.s_addr); MIX(extra->tag); + MIX(extra->label_index); } if (attr->aspath) @@ -730,6 +731,7 @@ attrhash_cmp (const void *p1, const void *p2) && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr && ae1->weight == ae2->weight && ae1->tag == ae2->tag + && ae1->label_index == ae2->label_index && ae1->mp_nexthop_len == ae2->mp_nexthop_len && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global) && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local) @@ -1287,6 +1289,7 @@ const u_int8_t attr_flags_values [] = { [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, [BGP_ATTR_AS4_AGGREGATOR] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, [BGP_ATTR_LARGE_COMMUNITIES]= BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, + [BGP_ATTR_LABEL_INDEX] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS, }; static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1; @@ -2274,6 +2277,52 @@ bgp_attr_encap( return 0; } +/* Label index attribute */ +static bgp_attr_parse_ret_t +bgp_attr_label_index (struct bgp_attr_parser_args *args, struct bgp_nlri *mp_update) +{ + struct peer *const peer = args->peer; + struct attr *const attr = args->attr; + const bgp_size_t length = args->length; + u_int32_t label_index; + + /* Length check. */ + if (length != 8) + { + zlog_err ("Bad label index length %d", length); + + return bgp_attr_malformed (args, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + args->total); + } + + /* First u32 is currently unused - reserved and flags (undefined) */ + stream_getl (peer->ibuf); + + /* Fetch the label index and see if it is valid. */ + label_index = stream_getl (peer->ibuf); + if (label_index == BGP_INVALID_LABEL_INDEX) + return bgp_attr_malformed (args, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + args->total); + + /* Store label index; subsequently, we'll check on address-family */ + (bgp_attr_extra_get (attr))->label_index = label_index; + + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX); + + /* + * Ignore the Label index attribute unless received for labeled-unicast + * SAFI. We reset the flag, though it is probably unnecesary. + */ + if (!mp_update->length || mp_update->afi != SAFI_LABELED_UNICAST) + { + attr->extra->label_index = BGP_INVALID_LABEL_INDEX; + attr->flag &= ~ATTR_FLAG_BIT(BGP_ATTR_LABEL_INDEX); + } + return BGP_ATTR_PARSE_PROCEED; +} + /* BGP unknown attribute treatment. */ static bgp_attr_parse_ret_t bgp_attr_unknown (struct bgp_attr_parser_args *args) @@ -2572,6 +2621,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, case BGP_ATTR_ENCAP: ret = bgp_attr_encap (type, peer, length, attr, flag, startp); break; + case BGP_ATTR_LABEL_INDEX: + ret = bgp_attr_label_index (&attr_args, mp_update); + break; default: ret = bgp_attr_unknown (&attr_args); break; @@ -3355,6 +3407,23 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, } } + /* Label index attribute. */ + if (safi == SAFI_LABELED_UNICAST) + { + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)) + { + u_int32_t label_index; + + assert (attr->extra); + label_index = attr->extra->label_index; + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_LABEL_INDEX); + stream_putc (s, 8); + stream_putl (s, 0); + stream_putl (s, label_index); + } + } + if ( send_as4_path ) { /* If the peer is NOT As4 capable, AND */ @@ -3638,6 +3707,17 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1); } + /* Label index */ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)) + { + assert (attr->extra); + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_LABEL_INDEX); + stream_putc (s, 8); + stream_putl (s, 0); + stream_putl (s, attr->extra->label_index); + } + /* Return total size of attribute. */ len = stream_get_endp (s) - cp - 2; stream_putw_at (s, cp, len); diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 015039c6cd..310fc0215d 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -134,6 +134,9 @@ struct attr_extra /* route tag */ route_tag_t tag; + /* Label index */ + u_int32_t label_index; + uint16_t encap_tunneltype; /* grr */ struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */ diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 232f53c778..8e4d8bf4f2 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -450,6 +450,10 @@ bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size) snprintf (buf + strlen (buf), size - strlen (buf), ", path %s", aspath_print (attr->aspath)); + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))) + snprintf (buf + strlen (buf), size - strlen (buf), ", label-index %u", + attr->extra->label_index); + if (strlen (buf) > 1) return 1; else diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index 283afbc922..e2c4a54044 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -143,6 +143,11 @@ bgp_reg_dereg_for_label (struct bgp_node *rn, int reg) stream_putw(s, PREFIX_FAMILY(p)); stream_put_prefix(s, p); stream_putw_at (s, 0, stream_get_endp (s)); + + if (reg) + SET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL); + else + UNSET_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL); zclient_send_message(zclient); return; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 0c29254f3f..451b54edab 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1942,9 +1942,21 @@ bgp_process_main (struct work_queue *wq, void *data) { label_valid = bgp_is_valid_label (rn->local_label); if (!old_select && new_select && !label_valid) - bgp_register_for_label (rn); + { + if (new_select->sub_type == BGP_ROUTE_STATIC && + new_select->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX)) + { + label_ntop (MPLS_IMP_NULL_LABEL, 1, rn->local_label); + bgp_set_valid_label(rn->local_label); + } + else + bgp_register_for_label (rn); + } else if (old_select && !new_select) - bgp_unregister_for_label (rn); + { + if (CHECK_FLAG (rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) + bgp_unregister_for_label (rn); + } } /* If best route remains the same and this is not due to user-initiated @@ -3792,6 +3804,13 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, if (bgp_static->atomic) attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); + /* Store label index, if required. */ + if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX) + { + (bgp_attr_extra_get (&attr))->label_index = bgp_static->label_index; + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX); + } + /* Apply route-map. */ if (bgp_static->rmap.name) { @@ -7631,9 +7650,20 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (json_paths) json_object_int_add(json_path, "remote-label", label); else - vty_out(vty, " Remote label: %d%s", label, VTY_NEWLINE); + vty_out(vty, " Remote label: %d", label); } + if (CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LABEL_INDEX))) + { + if (json_paths) + json_object_int_add(json_path, "label-index", attr->extra->label_index); + else + vty_out(vty, ", Label Index: %d", attr->extra->label_index); + } + + if (!json_paths) + vty_out (vty, "%s", VTY_NEWLINE); + /* Line 8 display Addpath IDs */ if (binfo->addpath_rx_id || binfo->addpath_tx_id) { diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 2b874f66a6..a6b99a53d6 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -63,6 +63,7 @@ struct bgp_node #define BGP_NODE_PROCESS_SCHEDULED (1 << 0) #define BGP_NODE_USER_CLEAR (1 << 1) #define BGP_NODE_LABEL_CHANGED (1 << 2) +#define BGP_NODE_REGISTERED_FOR_LABEL (1 << 3) }; /* diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index e95d059227..83c5d90ddf 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -972,6 +972,7 @@ struct bgp_nlri #define BGP_ATTR_AS4_AGGREGATOR 18 #define BGP_ATTR_AS_PATHLIMIT 21 #define BGP_ATTR_ENCAP 23 +#define BGP_ATTR_LABEL_INDEX 30 #define BGP_ATTR_LARGE_COMMUNITIES 32 #if ENABLE_BGP_VNC #define BGP_ATTR_VNC 255 -- 2.39.5