From 7fd077aadd54598f8764003d9b96fde1e30c2701 Mon Sep 17 00:00:00 2001 From: vivek Date: Sun, 4 Mar 2018 03:28:50 +0000 Subject: [PATCH] bgpd: Parse PMSI Tunnel Attribute and display Received PMSI tunnel attributes (in EVPN type-3 route) were not recognized. Parse them and display the tunnel type when looking at routes. Note that the only tunnel type currently supported is ingress replication (IR). A warning message will be logged if the received tunnel type is something else, but the attribute is otherwise ignored. Updates: a21bd7a (bgpd: add PMSI_TUNNEL_ATTRIBUTE to EVPN IMET routes) Signed-off-by: Vivek Venkatraman --- bgpd/bgp_attr.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++- bgpd/bgp_attr.h | 17 ++++++++++++++++ bgpd/bgp_debug.c | 7 +++++++ bgpd/bgp_evpn.c | 14 ++++++++++++++ bgpd/bgp_route.c | 17 ++++++++++++++++ 5 files changed, 104 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 3f3acbe0e2..56303a3df5 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2114,6 +2114,51 @@ bgp_attr_prefix_sid(struct bgp_attr_parser_args *args, return BGP_ATTR_PARSE_PROCEED; } +/* PMSI tunnel attribute (RFC 6514) + * Basic validation checks done here. + */ +static bgp_attr_parse_ret_t +bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args) +{ + struct peer *const peer = args->peer; + struct attr *const attr = args->attr; + const bgp_size_t length = args->length; + u_int8_t tnl_type; + + /* Verify that the receiver is expecting "ingress replication" as we + * can only support that. + */ + if (length < 2) { + zlog_err("Bad PMSI tunnel attribute length %d", length); + return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + args->total); + } + stream_getc(peer->curr); /* Flags */ + tnl_type = stream_getc(peer->curr); + if (tnl_type > PMSI_TNLTYPE_MAX) { + zlog_err("Invalid PMSI tunnel attribute type %d", tnl_type); + return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + args->total); + } + if (tnl_type == PMSI_TNLTYPE_INGR_REPL) { + if (length != 9) { + zlog_err("Bad PMSI tunnel attribute length %d for IR", + length); + return bgp_attr_malformed(args, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, + args->total); + } + } + + attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL); + attr->pmsi_tnl_type = tnl_type; + + /* Forward read pointer of input stream. */ + stream_forward_getp(peer->curr, length - 2); + + return BGP_ATTR_PARSE_PROCEED; +} + /* BGP unknown attribute treatment. */ static bgp_attr_parse_ret_t bgp_attr_unknown(struct bgp_attr_parser_args *args) { @@ -2447,6 +2492,9 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr, case BGP_ATTR_PREFIX_SID: ret = bgp_attr_prefix_sid(&attr_args, mp_update); break; + case BGP_ATTR_PMSI_TUNNEL: + ret = bgp_attr_pmsi_tunnel(&attr_args); + break; default: ret = bgp_attr_unknown(&attr_args); break; @@ -3263,7 +3311,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, stream_putc(s, BGP_ATTR_PMSI_TUNNEL); stream_putc(s, 9); // Length stream_putc(s, 0); // Flags - stream_putc(s, 6); // Tunnel type: Ingress Replication (6) + stream_putc(s, PMSI_TNLTYPE_INGR_REPL); // IR (6) stream_put(s, &(attr->label), BGP_LABEL_BYTES); // MPLS Label / VXLAN VNI stream_put_ipv4(s, attr->nexthop.s_addr); // Unicast tunnel endpoint IP address } diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 1b1471a198..c60fbd323d 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -66,6 +66,8 @@ #define BGP_PREFIX_SID_IPV6_LENGTH 19 #define BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH 6 +/* PMSI tunnel types (RFC 6514) */ + struct bgp_attr_encap_subtlv { struct bgp_attr_encap_subtlv *next; /* for chaining */ /* Reference count of this attribute. */ @@ -96,6 +98,18 @@ struct overlay_index { union gw_addr gw_ip; }; +enum pta_type { + PMSI_TNLTYPE_NO_INFO, + PMSI_TNLTYPE_RSVP_TE_P2MP, + PMSI_TNLTYPE_MLDP_P2MP, + PMSI_TNLTYPE_PIM_SSM, + PMSI_TNLTYPE_PIM_SM, + PMSI_TNLTYPE_PIM_BIDIR, + PMSI_TNLTYPE_INGR_REPL, + PMSI_TNLTYPE_MLDP_MP2MP, + PMSI_TNLTYPE_MAX = PMSI_TNLTYPE_MLDP_MP2MP +}; + /* BGP core attribute structure. */ struct attr { /* AS Path structure */ @@ -119,6 +133,9 @@ struct attr { /* Path origin attribute */ u_char origin; + /* PMSI tunnel type (RFC 6514). */ + enum pta_type pmsi_tnl_type; + /* has the route-map changed any attribute? Used on the peer outbound side. */ u_int32_t rmap_change_flags; diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index e89f399e41..1c9c92044c 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -159,6 +159,9 @@ static const struct message bgp_notify_capability_msg[] = { /* Origin strings. */ const char *bgp_origin_str[] = {"i", "e", "?"}; const char *bgp_origin_long_str[] = {"IGP", "EGP", "incomplete"}; +const char *pmsi_tnltype_str[] = {"No info", "RSVP-TE P2MP", "mLDP P2MP", + "PIM-SSM", "PIM-SM", "PIM-BIDIR", + "Ingress Replication", "mLDP MP2MP"}; /* Given a string return a pointer the corresponding peer structure */ @@ -415,6 +418,10 @@ int bgp_dump_attr(struct attr *attr, char *buf, size_t size) inet_ntoa(attr->cluster->list[i])); } + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) + snprintf(buf + strlen(buf), size - strlen(buf), ", pmsi tnltype %u", + attr->pmsi_tnl_type); + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))) snprintf(buf + strlen(buf), size - strlen(buf), ", path %s", aspath_print(attr->aspath)); diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index a8ee14c72e..9e4a5172df 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -2932,6 +2932,20 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi, return -1; } + /* If PMSI is present, log if it is anything other than IR. + * Note: We just simply ignore the values as it is not clear if + * doing anything else is better. + */ + if (attr && + (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL))) { + if (attr->pmsi_tnl_type != PMSI_TNLTYPE_INGR_REPL) { + zlog_warn("%u:%s - Rx EVPN Type-3 NLRI with " + "unsupported PTA %d", + peer->bgp->vrf_id, peer->host, + attr->pmsi_tnl_type); + } + } + /* Make prefix_rd */ prd.family = AF_UNSPEC; prd.prefixlen = 64; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 20bf9635a3..93570f4a3c 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -81,6 +81,7 @@ /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; extern const char *bgp_origin_long_str[]; +extern const char *pmsi_tnltype_str[]; struct bgp_node *bgp_afi_node_get(struct bgp_table *table, afi_t afi, safi_t safi, struct prefix *p, @@ -7035,6 +7036,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, json_object *json_ext_community = NULL; json_object *json_lcommunity = NULL; json_object *json_last_update = NULL; + json_object *json_pmsi = NULL; json_object *json_nexthop_global = NULL; json_object *json_nexthop_ll = NULL; json_object *json_nexthops = NULL; @@ -7787,6 +7789,21 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, json_last_update); } else vty_out(vty, " Last update: %s", ctime(&tbuf)); + + /* Line 10 display PMSI tunnel attribute, if present */ + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) { + if (json_paths) { + json_pmsi = json_object_new_object(); + json_object_string_add( + json_pmsi, "tunnelType", + pmsi_tnltype_str[attr->pmsi_tnl_type]); + json_object_object_add(json_path, "pmsi", + json_pmsi); + } else + vty_out(vty, " PMSI Tunnel Type: %s\n", + pmsi_tnltype_str[attr->pmsi_tnl_type]); + } + } /* We've constructed the json object for this path, add it to the json -- 2.39.5