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)
{
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;
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
}
#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. */
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 */
/* 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;
/* 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 */
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));
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;
/* 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,
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;
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