From 41367172d812354c05b11818346f0d49c2245aef Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 6 Aug 2007 15:24:51 +0000 Subject: [bgpd] Add support for AS_PATHLIMIT / draft-ietf-idr-as-pathlimit 2007-07-31 Paul Jakma * (general) Support for draft-ietf-idr-as-pathlimit-03. * bgp_attr.h: (struct attr) Add pathlimit struct bgp_attr.c: (attr_str) Add BGP_ATTR_AS_PATHLIMIT string. (attrhash_key_make) tally pathlimit too (attrhash_cmp) cmp pathlimit attr (bgp_attr_aspathlimit) New, parse AS_PATHLIMIT attr. (bgp_attr_parse) ditto (bgp_packet_attribute) Write out AS_PATHLIMIT when set (bgp_dump_routes_attr) ditto * bgp_route.h: (struct bgp_static) Add TTL field * bgp_route.c: (bgp_announce_check) Drop paths that are over their hop-count TTL before sending via EBGP. Mangle ASN in pathlimit for confeds/private as best we can. (bgp_static_update_{rsclient,main}) Add any configure pathlimit information. (bgp_pathlimit_update_parents) New, update atomic-aggr setting for parents of an aspathlimit'ed static. (bgp_static_set) Add TTL argument, for all the 'bgp network' commands. Call previous for TTL changed statics. (bgp_static_unset) Call pathlimit_update_parents. (various bgp network commands) Add 'pathlimit <0-255>' qualifier to all the various forms, bar route-map - which can set ttl itself. * bgp_routemap.c: (general) Add support for 'set pathlimit ttl' and 'match pathlimit as'. * doc/bgpd.texi: Document 'network ... pathlimit ' --- bgpd/ChangeLog | 29 ++++ bgpd/bgp_attr.c | 82 ++++++++++- bgpd/bgp_attr.h | 8 +- bgpd/bgp_route.c | 418 ++++++++++++++++++++++++++++++++++++++++++++++++---- bgpd/bgp_route.h | 6 + bgpd/bgp_routemap.c | 169 ++++++++++++++++++++- bgpd/bgpd.h | 1 + 7 files changed, 683 insertions(+), 30 deletions(-) (limited to 'bgpd') diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog index 7a93a90b..26614ced 100644 --- a/bgpd/ChangeLog +++ b/bgpd/ChangeLog @@ -1,3 +1,32 @@ +2007-07-31 Paul Jakma + + * (general) Support for draft-ietf-idr-as-pathlimit-03. + * bgp_attr.h: (struct attr) Add pathlimit struct + bgp_attr.c: (attr_str) Add BGP_ATTR_AS_PATHLIMIT string. + (attrhash_key_make) tally pathlimit too + (attrhash_cmp) cmp pathlimit attr + (bgp_attr_aspathlimit) New, parse AS_PATHLIMIT attr. + (bgp_attr_parse) ditto + (bgp_packet_attribute) Write out AS_PATHLIMIT when set + (bgp_dump_routes_attr) ditto + * bgp_route.h: (struct bgp_static) Add TTL field + * bgp_route.c: (bgp_announce_check) Drop paths that are over + their hop-count TTL before sending via EBGP. + Mangle ASN in pathlimit for confeds/private as best we can. + (bgp_static_update_{rsclient,main}) Add any configure pathlimit + information. + (bgp_pathlimit_update_parents) New, update atomic-aggr setting for + parents of an aspathlimit'ed static. + (bgp_static_set) Add TTL argument, for all the 'bgp network' + commands. + Call previous for TTL changed statics. + (bgp_static_unset) Call pathlimit_update_parents. + (various bgp network commands) Add 'pathlimit <0-255>' qualifier + to all the various forms, bar route-map - which can set ttl + itself. + * bgp_routemap.c: (general) Add support for 'set pathlimit ttl' and + 'match pathlimit as'. + 2007-07-26 Paul Jakma * (general) Clean up and compact capability parsing slightly. diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 07c94130..23d95865 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -56,6 +56,8 @@ static struct message attr_str [] = { BGP_ATTR_RCID_PATH, "RCID_PATH" }, { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" }, { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" }, + { BGP_ATTR_EXT_COMMUNITIES, "BGP_ATTR_EXT_COMMUNITIES" }, + { BGP_ATTR_AS_PATHLIMIT, "BGP_ATTR_AS_PATHLIMIT" }, { 0, NULL } }; int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]); @@ -345,6 +347,11 @@ attrhash_key_make (void *p) key += attr->nexthop.s_addr; key += attr->med; key += attr->local_pref; + if (attr->pathlimit.as) + { + key += attr->pathlimit.ttl; + key += attr->pathlimit.as; + } if (attr->extra) { @@ -396,7 +403,9 @@ attrhash_cmp (void *p1, void *p2) && attr1->aspath == attr2->aspath && attr1->community == attr2->community && attr1->med == attr2->med - && attr1->local_pref == attr2->local_pref) + && attr1->local_pref == attr2->local_pref + && attr1->pathlimit.ttl == attr2->pathlimit.ttl + && attr1->pathlimit.as == attr2->pathlimit.as) { struct attr_extra *ae1 = attr1->extra; struct attr_extra *ae2 = attr2->extra; @@ -676,6 +685,42 @@ bgp_attr_flush (struct attr *attr) } } +/* Parse AS_PATHLIMIT attribute in an UPDATE */ +static int +bgp_attr_aspathlimit (struct peer *peer, bgp_size_t length, + struct attr *attr, u_char flag, u_char *startp) +{ + bgp_size_t total; + + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + + if (flag != (BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL)) + { + zlog (peer->log, LOG_ERR, + "AS-Pathlimit attribute flag isn't transitive %d", flag); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + return -1; + } + + if (length != 5) + { + zlog (peer->log, LOG_ERR, + "AS-Pathlimit length, %u, is not 5", length); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + return -1; + } + + attr->pathlimit.ttl = stream_getc (BGP_INPUT(peer)); + attr->pathlimit.as = stream_getl (BGP_INPUT(peer)); + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT); + return 0; +} /* Get origin attribute of the update message. */ static int bgp_attr_origin (struct peer *peer, bgp_size_t length, @@ -1290,7 +1335,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, { /* XXX warning: long int format, int arg (arg 5) */ zlog (peer->log, LOG_WARNING, - "%s error BGP attribute length %ld is smaller than min len", + "%s error BGP attribute length %lu is smaller than min len", peer->host, endp - STREAM_PNT (BGP_INPUT (peer))); bgp_notify_send (peer, @@ -1386,6 +1431,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, case BGP_ATTR_EXT_COMMUNITIES: ret = bgp_attr_ext_communities (peer, length, attr, flag); break; + case BGP_ATTR_AS_PATHLIMIT: + ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp); + break; default: ret = bgp_attr_unknown (peer, attr, flag, type, length, startp); break; @@ -1824,7 +1872,25 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer, } } } - + + /* AS-Pathlimit */ + if (attr->pathlimit.ttl) + { + u_int32_t as = attr->pathlimit.as; + + /* should already have been done in announce_check(), + * but just in case.. + */ + if (!as) + as = peer->local_as; + + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_AS_PATHLIMIT); + stream_putc (s, 5); + stream_putc (s, attr->pathlimit.ttl); + stream_putl (s, as); + } + /* Unknown transit attribute. */ if (attr->extra && attr->extra->transit) stream_put (s, attr->extra->transit->val, attr->extra->transit->length); @@ -2034,6 +2100,16 @@ bgp_dump_routes_attr (struct stream *s, struct attr *attr, } #endif /* HAVE_IPV6 */ + /* AS-Pathlimit */ + if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT)) + { + stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS); + stream_putc (s, BGP_ATTR_AS_PATHLIMIT); + stream_putc (s, 5); + stream_putc (s, attr->pathlimit.ttl); + stream_putl (s, attr->pathlimit.as); + } + /* 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 ac14947f..1af9ce30 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -109,7 +109,13 @@ struct attr struct in_addr nexthop; u_int32_t med; u_int32_t local_pref; - + + /* AS-Pathlimit */ + struct { + u_int32_t as; + u_char ttl; + } pathlimit; + /* Path origin attribute */ u_char origin; }; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 1c0e6f1a..0f4da980 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -883,7 +883,20 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, return 0; } } - + + /* AS-Pathlimit check */ + if (ri->attr->pathlimit.ttl && peer_sort (peer) == BGP_PEER_EBGP) + /* Our ASN has not yet been pre-pended, that's done in packet_attribute + * on output. Hence the test here is for >=. + */ + if (aspath_count_hops (ri->attr->aspath) >= ri->attr->pathlimit.ttl) + { + if (BGP_DEBUG (filter, FILTER)) + zlog_info ("%s [Update:SEND] suppressed, AS-Pathlimit TTL %u exceeded", + peer->host, ri->attr->pathlimit.ttl); + return 0; + } + /* For modify attribute, copy it to temporary structure. */ bgp_attr_dup (attr, ri->attr); @@ -988,6 +1001,39 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p, } #endif /* HAVE_IPV6 */ + /* AS-Pathlimit: Check ASN for private/confed */ + if (attr->pathlimit.ttl) + { + /* locally originated update */ + if (!attr->pathlimit.as) + attr->pathlimit.as = peer->local_as; + + /* if the AS_PATHLIMIT attribute is attached to a prefix by a + member of a confederation, then when the prefix is advertised outside + of the confederation boundary, then the AS number of the + confederation member inside of the AS_PATHLIMIT attribute should be + replaced by the confederation's AS number. */ + if (peer_sort (from) == BGP_PEER_CONFED + && peer_sort (peer) != BGP_PEER_CONFED) + attr->pathlimit.as = peer->local_as; + + /* Private ASN should be updated whenever announcement leaves + * private space. This is deliberately done after simple confed + * based update.. + */ + if (attr->pathlimit.as >= BGP_PRIVATE_AS_MIN + && attr->pathlimit.as <= BGP_PRIVATE_AS_MAX) + { + if (peer->local_as < BGP_PRIVATE_AS_MIN + || peer->local_as > BGP_PRIVATE_AS_MAX) + attr->pathlimit.as = peer->local_as; + /* Ours is private, try using theirs.. */ + else if (peer->as < BGP_PRIVATE_AS_MIN + || peer->local_as > BGP_PRIVATE_AS_MAX) + attr->pathlimit.as = peer->as; + } + } + /* If this is EBGP peer and remove-private-AS is set. */ if (peer_sort (peer) == BGP_PEER_EBGP && peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS) @@ -3151,7 +3197,18 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p, attr.nexthop = bgp_static->igpnexthop; attr.med = bgp_static->igpmetric; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); - + + if (bgp_static->ttl) + { + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT); + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); + attr.pathlimit.as = 0; + attr.pathlimit.ttl = bgp_static->ttl; + } + + if (bgp_static->atomic) + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); + /* Apply network route-map for export to this rsclient. */ if (bgp_static->rmap.name) { @@ -3297,6 +3354,17 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p, attr.med = bgp_static->igpmetric; attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); + if (bgp_static->ttl) + { + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT); + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); + attr.pathlimit.as = 0; + attr.pathlimit.ttl = bgp_static->ttl; + } + + if (bgp_static->atomic) + attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); + /* Apply route-map. */ if (bgp_static->rmap.name) { @@ -3517,17 +3585,44 @@ bgp_static_withdraw_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi, bgp_unlock_node (rn); } +static void +bgp_pathlimit_update_parents (struct bgp *bgp, struct bgp_node *rn, + int ttl_edge) +{ + struct bgp_node *parent = rn; + struct bgp_static *sp; + + /* Existing static changed TTL, search parents and adjust their atomic */ + while ((parent = parent->parent)) + if ((sp = parent->info)) + { + int sp_level = (sp->atomic ? 1 : 0); + ttl_edge ? sp->atomic++ : sp->atomic--; + + /* did we change state of parent whether atomic is set or not? */ + if (sp_level != (sp->atomic ? 1 : 0)) + { + bgp_static_update (bgp, &parent->p, sp, + rn->table->afi, rn->table->safi); + } + } +} + /* Configure static BGP network. When user don't run zebra, static route should be installed as valid. */ static int bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str, - u_int16_t afi, u_char safi, const char *rmap, int backdoor) + u_int16_t afi, u_char safi, const char *rmap, int backdoor, + u_char ttl) { int ret; struct prefix p; struct bgp_static *bgp_static; struct bgp_node *rn; - int need_update = 0; + u_char need_update = 0; + u_char ttl_change = 0; + u_char ttl_edge = (ttl ? 1 : 0); + u_char new = 0; /* Convert IP prefix string to struct prefix. */ ret = str2prefix (ip_str, &p); @@ -3556,10 +3651,22 @@ bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str, bgp_static = rn->info; /* Check previous routes are installed into BGP. */ - if (! bgp_static->backdoor && bgp_static->valid) - need_update = 1; - + if (bgp_static->valid) + { + if (bgp_static->backdoor != backdoor + || bgp_static->ttl != ttl) + need_update = 1; + } + + /* need to catch TTL set/unset transitions for handling of + * ATOMIC_AGGREGATE + */ + if ((bgp_static->ttl ? 1 : 0) != ttl_edge) + ttl_change = 1; + bgp_static->backdoor = backdoor; + bgp_static->ttl = ttl; + if (rmap) { if (bgp_static->rmap.name) @@ -3585,6 +3692,10 @@ bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str, bgp_static->valid = 0; bgp_static->igpmetric = 0; bgp_static->igpnexthop.s_addr = 0; + bgp_static->ttl = ttl; + ttl_change = ttl_edge; + new = 1; + if (rmap) { if (bgp_static->rmap.name) @@ -3595,6 +3706,39 @@ bgp_static_set (struct vty *vty, struct bgp *bgp, const char *ip_str, rn->info = bgp_static; } + /* ".. sites that choose to advertise the + * AS_PATHLIMIT path attribute SHOULD advertise the ATOMIC_AGGREGATE on + * all less specific covering prefixes as well as the more specific + * prefixes." + * + * So: + * Prefix that has just had pathlimit set/unset: + * - Must bump ATOMIC refcount on all parents. + * + * To catch less specific prefixes: + * - Must search children for ones with TTL, bump atomic refcount + * (we dont care if we're deleting a less specific prefix..) + */ + if (ttl_change) + { + /* Existing static changed TTL, search parents and adjust their atomic */ + bgp_pathlimit_update_parents (bgp, rn, ttl_edge); + } + + if (new) + { + struct bgp_node *child; + struct bgp_static *sc; + + /* New static, search children and bump this statics atomic.. */ + child = bgp_lock_node (rn); /* route_next_until unlocks it.. */ + while ((child = bgp_route_next_until (child, rn))) + { + if ((sc = child->info) && sc->ttl) + bgp_static->atomic++; + } + } + /* If BGP scan is not enabled, we should install this route here. */ if (! bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)) { @@ -3647,7 +3791,10 @@ bgp_static_unset (struct vty *vty, struct bgp *bgp, const char *ip_str, } bgp_static = rn->info; - + + /* decrement atomic in parents, see bgp_static_set */ + bgp_pathlimit_update_parents (bgp, rn, 0); + /* Update BGP RIB. */ if (! bgp_static->backdoor) bgp_static_withdraw (bgp, &p, afi, safi); @@ -3844,10 +3991,23 @@ DEFUN (bgp_network, "Specify a network to announce via BGP\n" "IP prefix /, e.g., 35.0.0.0/8\n") { + u_char ttl = 0; + + if (argc == 2) + VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[1], 1, 255); + return bgp_static_set (vty, vty->index, argv[0], - AFI_IP, bgp_node_safi (vty), NULL, 0); + AFI_IP, bgp_node_safi (vty), NULL, 0, ttl); } +ALIAS (bgp_network, + bgp_network_ttl_cmd, + "network A.B.C.D/M pathlimit <0-255>", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "AS-Path hopcount limit attribute\n" + "AS-Pathlimit TTL, in number of AS-Path hops\n") + DEFUN (bgp_network_route_map, bgp_network_route_map_cmd, "network A.B.C.D/M route-map WORD", @@ -3857,7 +4017,7 @@ DEFUN (bgp_network_route_map, "Name of the route map\n") { return bgp_static_set (vty, vty->index, argv[0], - AFI_IP, bgp_node_safi (vty), argv[1], 0); + AFI_IP, bgp_node_safi (vty), argv[1], 0, 0); } DEFUN (bgp_network_backdoor, @@ -3867,9 +4027,24 @@ DEFUN (bgp_network_backdoor, "IP prefix /, e.g., 35.0.0.0/8\n" "Specify a BGP backdoor route\n") { - return bgp_static_set (vty, vty->index, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1); + u_char ttl = 0; + + if (argc == 2) + VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[1], 1, 255); + + return bgp_static_set (vty, vty->index, argv[0], AFI_IP, SAFI_UNICAST, + NULL, 1, ttl); } +ALIAS (bgp_network_backdoor, + bgp_network_backdoor_ttl_cmd, + "network A.B.C.D/M backdoor pathlimit <0-255>", + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify a BGP backdoor route\n" + "AS-Path hopcount limit attribute\n" + "AS-Pathlimit TTL, in number of AS-Path hops\n") + DEFUN (bgp_network_mask, bgp_network_mask_cmd, "network A.B.C.D mask A.B.C.D", @@ -3880,7 +4055,11 @@ DEFUN (bgp_network_mask, { int ret; char prefix_str[BUFSIZ]; - + u_char ttl = 0; + + if (argc == 3) + VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[2], 1, 255); + ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); if (! ret) { @@ -3889,9 +4068,19 @@ DEFUN (bgp_network_mask, } return bgp_static_set (vty, vty->index, prefix_str, - AFI_IP, bgp_node_safi (vty), NULL, 0); + AFI_IP, bgp_node_safi (vty), NULL, 0, ttl); } +ALIAS (bgp_network_mask, + bgp_network_mask_ttl_cmd, + "network A.B.C.D mask A.B.C.D pathlimit <0-255>", + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n" + "AS-Path hopcount limit attribute\n" + "AS-Pathlimit TTL, in number of AS-Path hops\n") + DEFUN (bgp_network_mask_route_map, bgp_network_mask_route_map_cmd, "network A.B.C.D mask A.B.C.D route-map WORD", @@ -3904,7 +4093,7 @@ DEFUN (bgp_network_mask_route_map, { int ret; char prefix_str[BUFSIZ]; - + ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); if (! ret) { @@ -3913,7 +4102,7 @@ DEFUN (bgp_network_mask_route_map, } return bgp_static_set (vty, vty->index, prefix_str, - AFI_IP, bgp_node_safi (vty), argv[2], 0); + AFI_IP, bgp_node_safi (vty), argv[2], 0, 0); } DEFUN (bgp_network_mask_backdoor, @@ -3927,6 +4116,10 @@ DEFUN (bgp_network_mask_backdoor, { int ret; char prefix_str[BUFSIZ]; + u_char ttl = 0; + + if (argc == 3) + VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[2], 1, 255); ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str); if (! ret) @@ -3935,9 +4128,21 @@ DEFUN (bgp_network_mask_backdoor, return CMD_WARNING; } - return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1); + return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, + NULL, 1, ttl); } +ALIAS (bgp_network_mask_backdoor, + bgp_network_mask_backdoor_ttl_cmd, + "network A.B.C.D mask A.B.C.D backdoor pathlimit <0-255>", + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n" + "Specify a BGP backdoor route\n" + "AS-Path hopcount limit attribute\n" + "AS-Pathlimit TTL, in number of AS-Path hops\n") + DEFUN (bgp_network_mask_natural, bgp_network_mask_natural_cmd, "network A.B.C.D", @@ -3946,6 +4151,10 @@ DEFUN (bgp_network_mask_natural, { int ret; char prefix_str[BUFSIZ]; + u_char ttl = 0; + + if (argc == 2) + VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[1], 1, 255); ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); if (! ret) @@ -3955,9 +4164,17 @@ DEFUN (bgp_network_mask_natural, } return bgp_static_set (vty, vty->index, prefix_str, - AFI_IP, bgp_node_safi (vty), NULL, 0); + AFI_IP, bgp_node_safi (vty), NULL, 0, ttl); } +ALIAS (bgp_network_mask_natural, + bgp_network_mask_natural_ttl_cmd, + "network A.B.C.D pathlimit <0-255>", + "Specify a network to announce via BGP\n" + "Network number\n" + "AS-Path hopcount limit attribute\n" + "AS-Pathlimit TTL, in number of AS-Path hops\n") + DEFUN (bgp_network_mask_natural_route_map, bgp_network_mask_natural_route_map_cmd, "network A.B.C.D route-map WORD", @@ -3977,7 +4194,7 @@ DEFUN (bgp_network_mask_natural_route_map, } return bgp_static_set (vty, vty->index, prefix_str, - AFI_IP, bgp_node_safi (vty), argv[1], 0); + AFI_IP, bgp_node_safi (vty), argv[1], 0, 0); } DEFUN (bgp_network_mask_natural_backdoor, @@ -3989,6 +4206,10 @@ DEFUN (bgp_network_mask_natural_backdoor, { int ret; char prefix_str[BUFSIZ]; + u_char ttl = 0; + + if (argc == 2) + VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[1], 1, 255); ret = netmask_str2prefix_str (argv[0], NULL, prefix_str); if (! ret) @@ -3997,9 +4218,19 @@ DEFUN (bgp_network_mask_natural_backdoor, return CMD_WARNING; } - return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1); + return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, + NULL, 1, ttl); } +ALIAS (bgp_network_mask_natural_backdoor, + bgp_network_mask_natural_backdoor_ttl_cmd, + "network A.B.C.D backdoor pathlimit (1-255>", + "Specify a network to announce via BGP\n" + "Network number\n" + "Specify a BGP backdoor route\n" + "AS-Path hopcount limit attribute\n" + "AS-Pathlimit TTL, in number of AS-Path hops\n") + DEFUN (no_bgp_network, no_bgp_network_cmd, "no network A.B.C.D/M", @@ -4011,6 +4242,15 @@ DEFUN (no_bgp_network, bgp_node_safi (vty)); } +ALIAS (no_bgp_network, + no_bgp_network_ttl_cmd, + "no network A.B.C.D/M pathlimit <0-255>", + NO_STR + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "AS-Path hopcount limit attribute\n" + "AS-Pathlimit TTL, in number of AS-Path hops\n") + ALIAS (no_bgp_network, no_bgp_network_route_map_cmd, "no network A.B.C.D/M route-map WORD", @@ -4028,6 +4268,16 @@ ALIAS (no_bgp_network, "IP prefix /, e.g., 35.0.0.0/8\n" "Specify a BGP backdoor route\n") +ALIAS (no_bgp_network, + no_bgp_network_backdoor_ttl_cmd, + "no network A.B.C.D/M backdoor pathlimit <0-255>", + NO_STR + "Specify a network to announce via BGP\n" + "IP prefix /, e.g., 35.0.0.0/8\n" + "Specify a BGP backdoor route\n" + "AS-Path hopcount limit attribute\n" + "AS-Pathlimit TTL, in number of AS-Path hops\n") + DEFUN (no_bgp_network_mask, no_bgp_network_mask_cmd, "no network A.B.C.D mask A.B.C.D", @@ -4051,6 +4301,17 @@ DEFUN (no_bgp_network_mask, bgp_node_safi (vty)); } +ALIAS (no_bgp_network, + no_bgp_network_mask_ttl_cmd, + "no network A.B.C.D mask A.B.C.D pathlimit <0-255>", + NO_STR + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n" + "AS-Path hopcount limit attribute\n" + "AS-Pathlimit TTL, in number of AS-Path hops\n") + ALIAS (no_bgp_network_mask, no_bgp_network_mask_route_map_cmd, "no network A.B.C.D mask A.B.C.D route-map WORD", @@ -4072,6 +4333,18 @@ ALIAS (no_bgp_network_mask, "Network mask\n" "Specify a BGP backdoor route\n") +ALIAS (no_bgp_network_mask, + no_bgp_network_mask_backdoor_ttl_cmd, + "no network A.B.C.D mask A.B.C.D backdoor pathlimit <0-255>", + NO_STR + "Specify a network to announce via BGP\n" + "Network number\n" + "Network mask\n" + "Network mask\n" + "Specify a BGP backdoor route\n" + "AS-Path hopcount limit attribute\n" + "AS-Pathlimit TTL, in number of AS-Path hops\n") + DEFUN (no_bgp_network_mask_natural, no_bgp_network_mask_natural_cmd, "no network A.B.C.D", @@ -4110,6 +4383,25 @@ ALIAS (no_bgp_network_mask_natural, "Network number\n" "Specify a BGP backdoor route\n") +ALIAS (no_bgp_network_mask_natural, + no_bgp_network_mask_natural_ttl_cmd, + "no network A.B.C.D pathlimit <0-255>", + NO_STR + "Specify a network to announce via BGP\n" + "Network number\n" + "AS-Path hopcount limit attribute\n" + "AS-Pathlimit TTL, in number of AS-Path hops\n") + +ALIAS (no_bgp_network_mask_natural, + no_bgp_network_mask_natural_backdoor_ttl_cmd, + "no network A.B.C.D backdoor pathlimit <0-255>", + NO_STR + "Specify a network to announce via BGP\n" + "Network number\n" + "Specify a BGP backdoor route\n" + "AS-Path hopcount limit attribute\n" + "AS-Pathlimit TTL, in number of AS-Path hops\n") + #ifdef HAVE_IPV6 DEFUN (ipv6_bgp_network, ipv6_bgp_network_cmd, @@ -4117,9 +4409,23 @@ DEFUN (ipv6_bgp_network, "Specify a network to announce via BGP\n" "IPv6 prefix /\n") { - return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0); + u_char ttl = 0; + + if (argc == 2) + VTY_GET_INTEGER_RANGE ("Pathlimit TTL", ttl, argv[1], 1, 255); + + return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST, + NULL, 0, ttl); } +ALIAS (ipv6_bgp_network, + ipv6_bgp_network_ttl_cmd, + "network X:X::X:X/M pathlimit <0-255>", + "Specify a network to announce via BGP\n" + "IPv6 prefix /\n" + "AS-Path hopcount limit attribute\n" + "AS-Pathlimit TTL, in number of AS-Path hops\n") + DEFUN (ipv6_bgp_network_route_map, ipv6_bgp_network_route_map_cmd, "network X:X::X:X/M route-map WORD", @@ -4129,7 +4435,7 @@ DEFUN (ipv6_bgp_network_route_map, "Name of the route map\n") { return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, - bgp_node_safi (vty), argv[1], 0); + bgp_node_safi (vty), argv[1], 0, 0); } DEFUN (no_ipv6_bgp_network, @@ -4151,6 +4457,15 @@ ALIAS (no_ipv6_bgp_network, "Route-map to modify the attributes\n" "Name of the route map\n") +ALIAS (no_ipv6_bgp_network, + no_ipv6_bgp_network_ttl_cmd, + "no network X:X::X:X/M pathlimit <0-255>", + NO_STR + "Specify a network to announce via BGP\n" + "IPv6 prefix /\n" + "AS-Path hopcount limit attribute\n" + "AS-Pathlimit TTL, in number of AS-Path hops\n") + ALIAS (ipv6_bgp_network, old_ipv6_bgp_network_cmd, "ipv6 bgp network X:X::X:X/M", @@ -5777,7 +6092,18 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, } vty_out (vty, "%s", VTY_NEWLINE); } - + + /* 7: AS Pathlimit */ + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AS_PATHLIMIT)) + { + + vty_out (vty, " AS-Pathlimit: %u", + attr->pathlimit.ttl); + if (attr->pathlimit.as) + vty_out (vty, " (%u)", attr->pathlimit.as); + vty_out (vty, "%s", VTY_NEWLINE); + } + if (binfo->extra && binfo->extra->damp_info) bgp_damp_info_vty (vty, binfo); @@ -11166,8 +11492,13 @@ bgp_config_write_network (struct vty *vty, struct bgp *bgp, if (bgp_static->rmap.name) vty_out (vty, " route-map %s", bgp_static->rmap.name); - else if (bgp_static->backdoor) - vty_out (vty, " backdoor"); + else + { + if (bgp_static->backdoor) + vty_out (vty, " backdoor"); + if (bgp_static->ttl) + vty_out (vty, " pathlimit %u", bgp_static->ttl); + } vty_out (vty, "%s", VTY_NEWLINE); } @@ -11255,6 +11586,12 @@ bgp_route_init () install_element (BGP_NODE, &bgp_network_backdoor_cmd); install_element (BGP_NODE, &bgp_network_mask_backdoor_cmd); install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_cmd); + install_element (BGP_NODE, &bgp_network_ttl_cmd); + install_element (BGP_NODE, &bgp_network_mask_ttl_cmd); + install_element (BGP_NODE, &bgp_network_mask_natural_ttl_cmd); + install_element (BGP_NODE, &bgp_network_backdoor_ttl_cmd); + install_element (BGP_NODE, &bgp_network_mask_backdoor_ttl_cmd); + install_element (BGP_NODE, &bgp_network_mask_natural_backdoor_ttl_cmd); install_element (BGP_NODE, &no_bgp_network_cmd); install_element (BGP_NODE, &no_bgp_network_mask_cmd); install_element (BGP_NODE, &no_bgp_network_mask_natural_cmd); @@ -11264,6 +11601,12 @@ bgp_route_init () install_element (BGP_NODE, &no_bgp_network_backdoor_cmd); install_element (BGP_NODE, &no_bgp_network_mask_backdoor_cmd); install_element (BGP_NODE, &no_bgp_network_mask_natural_backdoor_cmd); + install_element (BGP_NODE, &no_bgp_network_ttl_cmd); + install_element (BGP_NODE, &no_bgp_network_mask_ttl_cmd); + install_element (BGP_NODE, &no_bgp_network_mask_natural_ttl_cmd); + install_element (BGP_NODE, &no_bgp_network_backdoor_ttl_cmd); + install_element (BGP_NODE, &no_bgp_network_mask_backdoor_ttl_cmd); + install_element (BGP_NODE, &no_bgp_network_mask_natural_backdoor_ttl_cmd); install_element (BGP_NODE, &aggregate_address_cmd); install_element (BGP_NODE, &aggregate_address_mask_cmd); @@ -11293,12 +11636,23 @@ bgp_route_init () install_element (BGP_IPV4_NODE, &bgp_network_route_map_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_route_map_cmd); install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_route_map_cmd); - install_element (BGP_IPV4_NODE, &no_bgp_network_cmd); + install_element (BGP_IPV4_NODE, &bgp_network_ttl_cmd); + install_element (BGP_IPV4_NODE, &bgp_network_mask_ttl_cmd); + install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_ttl_cmd); + install_element (BGP_IPV4_NODE, &bgp_network_backdoor_ttl_cmd); + install_element (BGP_IPV4_NODE, &bgp_network_mask_backdoor_ttl_cmd); + install_element (BGP_IPV4_NODE, &bgp_network_mask_natural_backdoor_ttl_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_route_map_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_route_map_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_route_map_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_ttl_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_mask_ttl_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_ttl_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_backdoor_ttl_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_mask_backdoor_ttl_cmd); + install_element (BGP_IPV4_NODE, &no_bgp_network_mask_natural_backdoor_ttl_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_cmd); install_element (BGP_IPV4_NODE, &aggregate_address_cmd); install_element (BGP_IPV4_NODE, &aggregate_address_mask_cmd); install_element (BGP_IPV4_NODE, &aggregate_address_summary_only_cmd); @@ -11327,12 +11681,24 @@ bgp_route_init () install_element (BGP_IPV4M_NODE, &bgp_network_route_map_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_mask_route_map_cmd); install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_route_map_cmd); + install_element (BGP_IPV4M_NODE, &bgp_network_ttl_cmd); + install_element (BGP_IPV4M_NODE, &bgp_network_mask_ttl_cmd); + install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_ttl_cmd); + install_element (BGP_IPV4M_NODE, &bgp_network_backdoor_ttl_cmd); + install_element (BGP_IPV4M_NODE, &bgp_network_mask_backdoor_ttl_cmd); + install_element (BGP_IPV4M_NODE, &bgp_network_mask_natural_backdoor_ttl_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_route_map_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_route_map_cmd); install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_route_map_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_ttl_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_ttl_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_ttl_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_backdoor_ttl_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_backdoor_ttl_cmd); + install_element (BGP_IPV4M_NODE, &no_bgp_network_mask_natural_backdoor_ttl_cmd); install_element (BGP_IPV4_NODE, &no_bgp_network_cmd); install_element (BGP_IPV4M_NODE, &aggregate_address_cmd); install_element (BGP_IPV4M_NODE, &aggregate_address_mask_cmd); install_element (BGP_IPV4M_NODE, &aggregate_address_summary_only_cmd); @@ -11518,8 +11884,10 @@ bgp_route_init () /* New config IPv6 BGP commands. */ install_element (BGP_IPV6_NODE, &ipv6_bgp_network_cmd); install_element (BGP_IPV6_NODE, &ipv6_bgp_network_route_map_cmd); + install_element (BGP_IPV6_NODE, &ipv6_bgp_network_ttl_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_cmd); install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_route_map_cmd); + install_element (BGP_IPV6_NODE, &no_ipv6_bgp_network_ttl_cmd); install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_cmd); install_element (BGP_IPV6_NODE, &ipv6_aggregate_address_summary_only_cmd); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index c7eb8c6c..e5987972 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -104,6 +104,9 @@ struct bgp_static /* IGP nexthop. */ struct in_addr igpnexthop; + /* Atomic set reference count (ie cause of pathlimit) */ + u_int32_t atomic; + /* BGP redistribute route-map. */ struct { @@ -113,6 +116,9 @@ struct bgp_static /* MPLS label. */ u_char tag[3]; + + /* AS-Pathlimit TTL */ + u_char ttl; }; /* Flags which indicate a route is unuseable in some form */ diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 6a44c479..305d6796 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -87,14 +87,106 @@ o Cisco route-map origin : Done tag : (This will not be implemented by bgpd) weight : Done + pathlimit : Done o Local extention set ipv6 next-hop global: Done set ipv6 next-hop local : Done + set pathlimit ttl : Done + match pathlimit as : Done */ +/* Compiles either AS or TTL argument. It is amused the VTY code + * has already range-checked the values to be suitable as TTL or ASN + */ +static void * +route_pathlimit_compile (const char *arg) +{ + unsigned long tmp; + u_int32_t *val; + char *endptr = NULL; + + /* TTL or AS value shoud be integer. */ + if (! all_digit (arg)) + return NULL; + + tmp = strtoul (arg, &endptr, 10); + if (*endptr != '\0' || tmp == ULONG_MAX || tmp > UINT32_MAX) + return NULL; + + if (!(val = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)))) + return NULL; + + *val = tmp; + + return val; +} + +static void +route_pathlimit_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +static route_map_result_t +route_match_pathlimit_as (void *rule, struct prefix *prefix, route_map_object_t type, + void *object) +{ + struct bgp_info *info = object; + struct attr *attr = info->attr; + uint32_t as = *(uint32_t *)rule; + + if (type != RMAP_BGP) + return RMAP_NOMATCH; + + if (!attr->pathlimit.as) + return RMAP_NOMATCH; + + if (as == attr->pathlimit.as) + return RMAP_MATCH; + + return RMAP_NOMATCH; +} + +/* 'match pathlimit as' */ +struct route_map_rule_cmd route_match_pathlimit_as_cmd = +{ + "pathlimit as", + route_match_pathlimit_as, + route_pathlimit_compile, + route_pathlimit_free +}; + +/* Set pathlimit TTL. */ +static route_map_result_t +route_set_pathlimit_ttl (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct bgp_info *info = object; + struct attr *attr = info->attr; + u_char ttl = *(uint32_t *)rule; + + if (type == RMAP_BGP) + { + attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT); + attr->pathlimit.ttl = ttl; + attr->pathlimit.as = 0; + } + + return RMAP_OKAY; +} + +/* Set local preference rule structure. */ +struct route_map_rule_cmd route_set_pathlimit_ttl_cmd = +{ + "pathlimit ttl", + route_set_pathlimit_ttl, + route_pathlimit_compile, + route_pathlimit_free, +}; + /* 'match peer (A.B.C.D|X:X::X:X)' */ /* Compares the peer specified in the 'match peer' clause with the peer @@ -3538,6 +3630,70 @@ ALIAS (no_set_originator_id, "BGP originator ID attribute\n" "IP address of originator\n") +DEFUN (set_pathlimit_ttl, + set_pathlimit_ttl_cmd, + "set pathlimit ttl <1-255>", + SET_STR + "BGP AS-Pathlimit attribute\n" + "Set AS-Path Hop-count TTL\n") +{ + return bgp_route_set_add (vty, vty->index, "pathlimit ttl", argv[0]); +} + +DEFUN (no_set_pathlimit_ttl, + no_set_pathlimit_ttl_cmd, + "no set pathlimit ttl", + NO_STR + SET_STR + "BGP AS-Pathlimit attribute\n" + "Set AS-Path Hop-count TTL\n") +{ + if (argc == 0) + return bgp_route_set_delete (vty, vty->index, "pathlimit ttl", NULL); + + return bgp_route_set_delete (vty, vty->index, "pathlimit ttl", argv[0]); +} + +ALIAS (no_set_pathlimit_ttl, + no_set_pathlimit_ttl_val_cmd, + "no set pathlimit ttl <1-255>", + NO_STR + MATCH_STR + "BGP AS-Pathlimit attribute\n" + "Set AS-Path Hop-count TTL\n") + +DEFUN (match_pathlimit_as, + match_pathlimit_as_cmd, + "match pathlimit as <1-65535>", + MATCH_STR + "BGP AS-Pathlimit attribute\n" + "Match Pathlimit AS number\n") +{ + return bgp_route_match_add (vty, vty->index, "pathlimit as", argv[0]); +} + +DEFUN (no_match_pathlimit_as, + no_match_pathlimit_as_cmd, + "no match pathlimit as", + NO_STR + MATCH_STR + "BGP AS-Pathlimit attribute\n" + "Match Pathlimit AS number\n") +{ + if (argc == 0) + return bgp_route_match_delete (vty, vty->index, "pathlimit as", NULL); + + return bgp_route_match_delete (vty, vty->index, "pathlimit as", argv[0]); +} + +ALIAS (no_match_pathlimit_as, + no_match_pathlimit_as_val_cmd, + "no match pathlimit as <1-65535>", + NO_STR + MATCH_STR + "BGP AS-Pathlimit attribute\n" + "Match Pathlimit ASN\n") + /* Initialization of route map. */ void @@ -3671,7 +3827,7 @@ bgp_route_map_init (void) route_map_install_match (&route_match_ipv6_address_prefix_list_cmd); route_map_install_set (&route_set_ipv6_nexthop_global_cmd); route_map_install_set (&route_set_ipv6_nexthop_local_cmd); - + install_element (RMAP_NODE, &match_ipv6_address_cmd); install_element (RMAP_NODE, &no_match_ipv6_address_cmd); install_element (RMAP_NODE, &match_ipv6_next_hop_cmd); @@ -3685,4 +3841,15 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd); #endif /* HAVE_IPV6 */ + + /* AS-Pathlimit */ + route_map_install_match (&route_match_pathlimit_as_cmd); + route_map_install_set (&route_set_pathlimit_ttl_cmd); + + install_element (RMAP_NODE, &set_pathlimit_ttl_cmd); + install_element (RMAP_NODE, &no_set_pathlimit_ttl_cmd); + install_element (RMAP_NODE, &no_set_pathlimit_ttl_val_cmd); + install_element (RMAP_NODE, &match_pathlimit_as_cmd); + install_element (RMAP_NODE, &no_match_pathlimit_as_cmd); + install_element (RMAP_NODE, &no_match_pathlimit_as_val_cmd); } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 8b180a43..3fba6042 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -591,6 +591,7 @@ struct bgp_nlri #define BGP_ATTR_MP_REACH_NLRI 14 #define BGP_ATTR_MP_UNREACH_NLRI 15 #define BGP_ATTR_EXT_COMMUNITIES 16 +#define BGP_ATTR_AS_PATHLIMIT 21 /* BGP update origin. */ #define BGP_ORIGIN_IGP 0 -- cgit v1.2.1