diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-05 09:56:23 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-05 09:56:23 +0000 |
commit | c15d6efd40655f717841d00839a43df1ead5cb26 (patch) | |
tree | 35d579f9a19170e2b39085669ca92533c2d161b4 /bgpd | |
parent | Adding upstream version 10.0.1. (diff) | |
download | frr-c15d6efd40655f717841d00839a43df1ead5cb26.tar.xz frr-c15d6efd40655f717841d00839a43df1ead5cb26.zip |
Adding upstream version 10.1.upstream/10.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'bgpd')
67 files changed, 4518 insertions, 1943 deletions
diff --git a/bgpd/bgp_addpath.h b/bgpd/bgp_addpath.h index d562000..c267ebe 100644 --- a/bgpd/bgp_addpath.h +++ b/bgpd/bgp_addpath.h @@ -21,6 +21,12 @@ struct bgp_addpath_capability { uint8_t flags; }; +struct bgp_paths_limit_capability { + uint16_t afi; + uint8_t safi; + uint16_t paths_limit; +} __attribute__((packed)); + #define BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE 1 void bgp_addpath_init_bgp_data(struct bgp_addpath_bgp_data *d); diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index a81f288..d5c7e18 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -163,7 +163,7 @@ bool bgp_adj_out_lookup(struct peer *peer, struct bgp_dest *dest, void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr, - uint32_t addpath_id) + uint32_t addpath_id, struct bgp_labels *labels) { struct bgp_adj_in *adj; @@ -173,6 +173,10 @@ void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr, bgp_attr_unintern(&adj->attr); adj->attr = bgp_attr_intern(attr); } + if (!bgp_labels_cmp(adj->labels, labels)) { + bgp_labels_unintern(&adj->labels); + adj->labels = bgp_labels_intern(labels); + } return; } } @@ -181,13 +185,18 @@ void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr, adj->attr = bgp_attr_intern(attr); adj->uptime = monotime(NULL); adj->addpath_rx_id = addpath_id; + adj->labels = bgp_labels_intern(labels); BGP_ADJ_IN_ADD(dest, adj); + peer->stat_pfx_adj_rib_in++; bgp_dest_lock_node(dest); } void bgp_adj_in_remove(struct bgp_dest **dest, struct bgp_adj_in *bai) { bgp_attr_unintern(&bai->attr); + bgp_labels_unintern(&bai->labels); + if (bai->peer) + bai->peer->stat_pfx_adj_rib_in--; BGP_ADJ_IN_DEL(*dest, bai); *dest = bgp_dest_unlock_node(*dest); peer_unlock(bai->peer); /* adj_in peer reference */ diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h index 4982106..8c83189 100644 --- a/bgpd/bgp_advertise.h +++ b/bgpd/bgp_advertise.h @@ -75,6 +75,9 @@ struct bgp_adj_out { /* Advertised attribute. */ struct attr *attr; + /* VPN label information */ + struct bgp_labels *labels; + /* Advertisement information. */ struct bgp_advertise *adv; }; @@ -95,6 +98,9 @@ struct bgp_adj_in { /* Received attribute. */ struct attr *attr; + /* VPN label information */ + struct bgp_labels *labels; + /* timestamp (monotime) */ time_t uptime; @@ -135,7 +141,8 @@ struct bgp_synchronize { extern bool bgp_adj_out_lookup(struct peer *peer, struct bgp_dest *dest, uint32_t addpath_tx_id); extern void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, - struct attr *attr, uint32_t addpath_id); + struct attr *attr, uint32_t addpath_id, + struct bgp_labels *labels); extern bool bgp_adj_in_unset(struct bgp_dest **dest, struct peer *peer, uint32_t addpath_id); extern void bgp_adj_in_remove(struct bgp_dest **dest, struct bgp_adj_in *bai); diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index bc7e893..4c1615a 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -77,6 +77,9 @@ static struct hash *ashash; /* Stream for SNMP. See aspath_snmp_pathseg */ static struct stream *snmp_stream; +/* as-path orphan exclude list */ +static struct as_list_list_head as_exclude_list_orphan; + /* Callers are required to initialize the memory */ static as_t *assegment_data_new(int num) { @@ -1558,6 +1561,38 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2) /* Not reached */ } +/* insert aspath exclude in head of orphan exclude list*/ +void as_exclude_set_orphan(struct aspath_exclude *ase) +{ + ase->exclude_aspath_acl = NULL; + as_list_list_add_head(&as_exclude_list_orphan, ase); +} + +void as_exclude_remove_orphan(struct aspath_exclude *ase) +{ + if (as_list_list_count(&as_exclude_list_orphan)) + as_list_list_del(&as_exclude_list_orphan, ase); +} + +/* currently provide only one exclude, not a list */ +struct aspath_exclude *as_exclude_lookup_orphan(const char *acl_name) +{ + struct aspath_exclude *ase = NULL; + char *name = NULL; + + frr_each (as_list_list, &as_exclude_list_orphan, ase) { + if (ase->exclude_aspath_acl_name) { + name = ase->exclude_aspath_acl_name; + if (!strcmp(name, acl_name)) + break; + } + } + if (ase) + as_exclude_remove_orphan(ase); + + return ase; +} + /* Iterate over AS_PATH segments and wipe all occurrences of the * listed AS numbers. Hence some segments may lose some or even * all data on the way, the operation is implemented as a smarter @@ -2236,20 +2271,32 @@ void aspath_init(void) { ashash = hash_create_size(32768, aspath_key_make, aspath_cmp, "BGP AS Path"); + + as_list_list_init(&as_exclude_list_orphan); } void aspath_finish(void) { + struct aspath_exclude *ase; + hash_clean_and_free(&ashash, (void (*)(void *))aspath_free); if (snmp_stream) stream_free(snmp_stream); + + while ((ase = as_list_list_pop(&as_exclude_list_orphan))) { + aspath_free(ase->aspath); + if (ase->exclude_aspath_acl_name) + XFREE(MTYPE_TMP, ase->exclude_aspath_acl_name); + XFREE(MTYPE_ROUTE_MAP_COMPILED, ase); + } + as_list_list_fini(&as_exclude_list_orphan); } /* return and as path value */ const char *aspath_print(struct aspath *as) { - return (as ? as->str : NULL); + return as ? as->str : "(null)"; } /* Printing functions */ diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index 2a831c3..f7e57fd 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -9,6 +9,7 @@ #include "lib/json.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_filter.h" +#include <typesafe.h> /* AS path segment type. */ #define AS_SET 1 @@ -67,11 +68,14 @@ struct aspath { /* `set as-path exclude ASn' */ struct aspath_exclude { + struct as_list_list_item exclude_list; struct aspath *aspath; bool exclude_all; char *exclude_aspath_acl_name; struct as_list *exclude_aspath_acl; }; +DECLARE_DLIST(as_list_list, struct aspath_exclude, exclude_list); + /* Prototypes. */ extern void aspath_init(void); @@ -83,6 +87,9 @@ extern struct aspath *aspath_parse(struct stream *s, size_t length, extern struct aspath *aspath_dup(struct aspath *aspath); extern struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2); extern struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2); +extern void as_exclude_set_orphan(struct aspath_exclude *ase); +extern void as_exclude_remove_orphan(struct aspath_exclude *ase); +extern struct aspath_exclude *as_exclude_lookup_orphan(const char *acl_name); extern struct aspath *aspath_filter_exclude(struct aspath *source, struct aspath *exclude_list); extern struct aspath *aspath_filter_exclude_all(struct aspath *source); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 40e074d..e4ee589 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -911,9 +911,17 @@ static void attr_show_all_iterator(struct hash_bucket *bucket, struct vty *vty) vty_out(vty, "\tflags: %" PRIu64 - " distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %pI6\n", + " distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %pI6 aigp_metric: %" PRIu64 + "\n", attr->flag, attr->distance, attr->med, attr->local_pref, - attr->origin, attr->weight, attr->label, sid); + attr->origin, attr->weight, attr->label, sid, attr->aigp_metric); + vty_out(vty, "\taspath: %s Community: %s Large Community: %s\n", + aspath_print(attr->aspath), + community_str(attr->community, false, false), + lcommunity_str(attr->lcommunity, false, false)); + vty_out(vty, "\tExtended Community: %s Extended IPv6 Community: %s\n", + ecommunity_str(attr->ecommunity), + ecommunity_str(attr->ipv6_ecommunity)); } void attr_show_all(struct vty *vty) @@ -2368,6 +2376,12 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, return BGP_ATTR_PARSE_WITHDRAW; } attr->nh_ifindex = peer->nexthop.ifp->ifindex; + if (if_is_operative(peer->nexthop.ifp)) + SET_FLAG(attr->nh_flags, + BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(attr->nh_flags, + BGP_ATTR_NH_IF_OPERSTATE); } break; case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: @@ -2385,6 +2399,12 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, return BGP_ATTR_PARSE_WITHDRAW; } attr->nh_ifindex = peer->nexthop.ifp->ifindex; + if (if_is_operative(peer->nexthop.ifp)) + SET_FLAG(attr->nh_flags, + BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(attr->nh_flags, + BGP_ATTR_NH_IF_OPERSTATE); } if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { @@ -2640,10 +2660,7 @@ bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args) if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type]) goto ipv6_ext_community_ignore; - ipv6_ecomm = ecommunity_parse_ipv6( - stream_pnt(peer->curr), length, - CHECK_FLAG(peer->flags, - PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE)); + ipv6_ecomm = ecommunity_parse_ipv6(stream_pnt(peer->curr), length); bgp_attr_set_ipv6_ecommunity(attr, ipv6_ecomm); /* XXX: fix ecommunity_parse to use stream API */ @@ -2653,6 +2670,10 @@ bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args) return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total); + /* Extract link bandwidth, if any. */ + (void)ecommunity_linkbw_present(bgp_attr_get_ipv6_ecommunity(attr), + &attr->link_bw); + return BGP_ATTR_PARSE_PROCEED; ipv6_ext_community_ignore: @@ -2700,17 +2721,20 @@ static int bgp_attr_encap(struct bgp_attr_parser_args *args) } } - while (length >= 4) { + while (STREAM_READABLE(BGP_INPUT(peer)) >= 4) { uint16_t subtype = 0; uint16_t sublength = 0; struct bgp_attr_encap_subtlv *tlv; if (BGP_ATTR_ENCAP == type) { subtype = stream_getc(BGP_INPUT(peer)); - sublength = (subtype < 128) - ? stream_getc(BGP_INPUT(peer)) - : stream_getw(BGP_INPUT(peer)); - length -= 2; + if (subtype < 128) { + sublength = stream_getc(BGP_INPUT(peer)); + length -= 2; + } else { + sublength = stream_getw(BGP_INPUT(peer)); + length -= 3; + } #ifdef ENABLE_BGP_VNC } else { subtype = stream_getw(BGP_INPUT(peer)); @@ -2727,6 +2751,14 @@ static int bgp_attr_encap(struct bgp_attr_parser_args *args) args->total); } + if (STREAM_READABLE(BGP_INPUT(peer)) < sublength) { + zlog_err("Tunnel Encap attribute sub-tlv length %d exceeds remaining stream length %zu", + sublength, STREAM_READABLE(BGP_INPUT(peer))); + return bgp_attr_malformed(args, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + args->total); + } + /* alloc and copy sub-tlv */ /* TBD make sure these are freed when attributes are released */ tlv = XCALLOC(MTYPE_ENCAP_TLV, @@ -4137,7 +4169,7 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, const struct prefix *p, const struct prefix_rd *prd, mpls_label_t *label, - uint32_t num_labels, bool addpath_capable, + uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct attr *attr) { switch (safi) { @@ -4344,13 +4376,76 @@ static bool bgp_append_local_as(struct peer *peer, afi_t afi, safi_t safi) return false; } +static void bgp_packet_ecommunity_attribute(struct stream *s, struct peer *peer, + struct ecommunity *ecomm, + bool transparent, int attribute) +{ + if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED || + peer->sub_sort == BGP_PEER_EBGP_OAD || transparent) { + if (ecomm->size * ecomm->unit_size > 255) { + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | + BGP_ATTR_FLAG_TRANS | + BGP_ATTR_FLAG_EXTLEN); + stream_putc(s, attribute); + stream_putw(s, ecomm->size * ecomm->unit_size); + } else { + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | + BGP_ATTR_FLAG_TRANS); + stream_putc(s, attribute); + stream_putc(s, ecomm->size * ecomm->unit_size); + } + stream_put(s, ecomm->val, ecomm->size * ecomm->unit_size); + } else { + uint8_t *pnt; + int tbit; + int ecom_tr_size = 0; + uint32_t i; + + for (i = 0; i < ecomm->size; i++) { + pnt = ecomm->val + (i * ecomm->unit_size); + tbit = *pnt; + + if (CHECK_FLAG(tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE)) + continue; + + ecom_tr_size++; + } + + if (ecom_tr_size) { + if (ecom_tr_size * ecomm->unit_size > 255) { + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | + BGP_ATTR_FLAG_TRANS | + BGP_ATTR_FLAG_EXTLEN); + stream_putc(s, attribute); + stream_putw(s, ecom_tr_size * ecomm->unit_size); + } else { + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | + BGP_ATTR_FLAG_TRANS); + stream_putc(s, attribute); + stream_putc(s, ecom_tr_size * ecomm->unit_size); + } + + for (i = 0; i < ecomm->size; i++) { + pnt = ecomm->val + (i * ecomm->unit_size); + tbit = *pnt; + + if (CHECK_FLAG(tbit, + ECOMMUNITY_FLAG_NON_TRANSITIVE)) + continue; + + stream_put(s, pnt, ecomm->unit_size); + } + } + } +} + /* Make attribute packet. */ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr, struct bpacket_attr_vec_arr *vecarr, struct prefix *p, afi_t afi, safi_t safi, struct peer *from, struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct bgp_path_info *bpi) { @@ -4646,82 +4741,31 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, } } - /* Extended Communities attribute. */ - if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) - && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { - struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr); + /* Extended IPv6/Communities attributes. */ + if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)) { bool transparent = CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT) && from && CHECK_FLAG(from->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT); - if (peer->sort == BGP_PEER_IBGP || - peer->sort == BGP_PEER_CONFED || transparent) { - if (ecomm->size * 8 > 255) { - stream_putc(s, - BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_TRANS - | BGP_ATTR_FLAG_EXTLEN); - stream_putc(s, BGP_ATTR_EXT_COMMUNITIES); - stream_putw(s, ecomm->size * 8); - } else { - stream_putc(s, - BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_TRANS); - stream_putc(s, BGP_ATTR_EXT_COMMUNITIES); - stream_putc(s, ecomm->size * 8); - } - stream_put(s, ecomm->val, ecomm->size * 8); - } else { - uint8_t *pnt; - int tbit; - int ecom_tr_size = 0; - uint32_t i; - - for (i = 0; i < ecomm->size; i++) { - pnt = ecomm->val + (i * 8); - tbit = *pnt; + if (CHECK_FLAG(attr->flag, + ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { + struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr); - if (CHECK_FLAG(tbit, - ECOMMUNITY_FLAG_NON_TRANSITIVE)) - continue; + bgp_packet_ecommunity_attribute(s, peer, ecomm, + transparent, + BGP_ATTR_EXT_COMMUNITIES); + } - ecom_tr_size++; - } + if (CHECK_FLAG(attr->flag, + ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES))) { + struct ecommunity *ecomm = + bgp_attr_get_ipv6_ecommunity(attr); - if (ecom_tr_size) { - if (ecom_tr_size * 8 > 255) { - stream_putc( - s, - BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_TRANS - | BGP_ATTR_FLAG_EXTLEN); - stream_putc(s, - BGP_ATTR_EXT_COMMUNITIES); - stream_putw(s, ecom_tr_size * 8); - } else { - stream_putc( - s, - BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_TRANS); - stream_putc(s, - BGP_ATTR_EXT_COMMUNITIES); - stream_putc(s, ecom_tr_size * 8); - } - - for (i = 0; i < ecomm->size; i++) { - pnt = ecomm->val + (i * 8); - tbit = *pnt; - - if (CHECK_FLAG( - tbit, - ECOMMUNITY_FLAG_NON_TRANSITIVE)) - continue; - - stream_put(s, pnt, 8); - } - } + bgp_packet_ecommunity_attribute(s, peer, ecomm, + transparent, + BGP_ATTR_IPV6_EXT_COMMUNITIES); } } @@ -4930,7 +4974,7 @@ size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi) void bgp_packet_mpunreach_prefix(struct stream *s, const struct prefix *p, afi_t afi, safi_t safi, const struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct attr *attr) { diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index d78f04c..f353e76 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -158,6 +158,8 @@ struct attr { uint8_t nh_flags; #define BGP_ATTR_NH_VALID 0x01 +#define BGP_ATTR_NH_IF_OPERSTATE 0x02 +#define BGP_ATTR_NH_MP_PREFER_GLOBAL 0x04 /* MP Nexthop preference */ /* Path origin attribute */ uint8_t origin; @@ -254,9 +256,6 @@ struct attr { /* MP Nexthop length */ uint8_t mp_nexthop_len; - /* MP Nexthop preference */ - uint8_t mp_nexthop_prefer_global; - /* Static MAC for EVPN */ uint8_t sticky; @@ -302,7 +301,7 @@ struct attr { uint32_t rmap_table_id; /* Link bandwidth value, if any. */ - uint32_t link_bw; + uint64_t link_bw; /* EVPN ES */ esi_t esi; @@ -394,7 +393,7 @@ extern bgp_size_t bgp_packet_attribute( struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr, struct bpacket_attr_vec_arr *vecarr, struct prefix *p, afi_t afi, safi_t safi, struct peer *from, struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, bool addpath_capable, + mpls_label_t *label, uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct bgp_path_info *bpi); extern void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi, const struct prefix *p); @@ -452,7 +451,7 @@ extern size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi, const struct prefix *p, const struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct attr *); extern size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi, @@ -463,7 +462,7 @@ extern size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi); extern void bgp_packet_mpunreach_prefix( struct stream *s, const struct prefix *p, afi_t afi, safi_t safi, - const struct prefix_rd *prd, mpls_label_t *label, uint32_t num_labels, + const struct prefix_rd *prd, mpls_label_t *label, uint8_t num_labels, bool addpath_capable, uint32_t addpath_tx_id, struct attr *attr); extern void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt); diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index 21864cf..14ff5f2 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -597,6 +597,9 @@ DEFUN(no_neighbor_bfd_profile, no_neighbor_bfd_profile_cmd, if (!peer) return CMD_WARNING_CONFIG_FAILED; + if (!peer->bfd_config) + return CMD_SUCCESS; + if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) bgp_group_configure_bfd(peer); else diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 1de48a0..43f8006 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -38,6 +38,7 @@ #include "bgpd/bgp_vty.h" #include "bgpd/bgp_trace.h" #include "bgpd/bgp_network.h" +#include "bgpd/bgp_label.h" static void bmp_close(struct bmp *bmp); static struct bmp_bgp *bmp_bgp_find(struct bgp *bgp); @@ -391,11 +392,11 @@ static int bmp_send_initiation(struct bmp *bmp) bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_INITIATION); -#define BMP_INFO_TYPE_SYSDESCR 1 -#define BMP_INFO_TYPE_SYSNAME 2 - bmp_put_info_tlv(s, BMP_INFO_TYPE_SYSDESCR, - FRR_FULL_NAME " " FRR_VER_SHORT); - bmp_put_info_tlv(s, BMP_INFO_TYPE_SYSNAME, cmd_hostname_get()); +#define BMP_INIT_INFO_TYPE_SYSDESCR 1 +#define BMP_INIT_INFO_TYPE_SYSNAME 2 + bmp_put_info_tlv(s, BMP_INIT_INFO_TYPE_SYSDESCR, + FRR_FULL_NAME " " FRR_VER_SHORT); + bmp_put_info_tlv(s, BMP_INIT_INFO_TYPE_SYSNAME, cmd_hostname_get()); len = stream_get_endp(s); stream_putl_at(s, BMP_LENGTH_POS, len); /* message length is set. */ @@ -438,6 +439,7 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) monotime_to_realtime(&uptime, &uptime_real); #define BGP_BMP_MAX_PACKET_SIZE 1024 +#define BMP_PEERUP_INFO_TYPE_STRING 0 s = stream_new(BGP_MAX_PACKET_SIZE); if (peer_established(peer->connection) && !down) { @@ -493,7 +495,8 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) } if (peer->desc) - bmp_put_info_tlv(s, 0, peer->desc); + bmp_put_info_tlv(s, BMP_PEERUP_INFO_TYPE_STRING, + peer->desc); } else { uint8_t type; size_t type_pos; @@ -910,7 +913,8 @@ static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags, static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd, struct peer *peer, struct attr *attr, - afi_t afi, safi_t safi) + afi_t afi, safi_t safi, mpls_label_t *label, + uint32_t num_labels) { struct bpacket_attr_vec_arr vecarr; struct stream *s; @@ -946,8 +950,8 @@ static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd, mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi, &vecarr, attr); - bgp_packet_mpattr_prefix(s, afi, safi, p, prd, NULL, 0, 0, 0, - attr); + bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label, + num_labels, 0, 0, attr); bgp_packet_mpattr_end(s, mpattrlen_pos); total_attr_len += stream_get_endp(s) - p1; } @@ -1002,7 +1006,8 @@ static struct stream *bmp_withdraw(const struct prefix *p, static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags, uint8_t peer_type_flag, const struct prefix *p, struct prefix_rd *prd, struct attr *attr, afi_t afi, - safi_t safi, time_t uptime) + safi_t safi, time_t uptime, mpls_label_t *label, + uint32_t num_labels) { struct stream *hdr, *msg; struct timeval tv = { .tv_sec = uptime, .tv_usec = 0 }; @@ -1019,7 +1024,8 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags, monotime_to_realtime(&tv, &uptime_real); if (attr) - msg = bmp_update(p, prd, peer, attr, afi, safi); + msg = bmp_update(p, prd, peer, attr, afi, safi, label, + num_labels); else msg = bmp_withdraw(p, prd, afi, safi); @@ -1041,6 +1047,7 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags, static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) { + uint8_t bpi_num_labels; afi_t afi; safi_t safi; @@ -1214,23 +1221,31 @@ afibreak: (safi == SAFI_MPLS_VPN)) prd = (struct prefix_rd *)bgp_dest_get_prefix(bmp->syncrdpos); + bpi_num_labels = bgp_path_info_num_labels(bpi); + if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_SELECTED) && CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_LOC_RIB)) { bmp_monitor(bmp, bpi->peer, 0, BMP_PEER_TYPE_LOC_RIB_INSTANCE, bn_p, prd, bpi->attr, afi, safi, bpi && bpi->extra ? bpi->extra->bgp_rib_uptime - : (time_t)(-1L)); + : (time_t)(-1L), + bpi_num_labels ? bpi->extra->labels->label : NULL, + bpi_num_labels); } if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_VALID) && CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_POSTPOLICY)) bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, BMP_PEER_TYPE_GLOBAL_INSTANCE, bn_p, prd, bpi->attr, - afi, safi, bpi->uptime); + afi, safi, bpi->uptime, + bpi_num_labels ? bpi->extra->labels->label : NULL, + bpi_num_labels); if (adjin) + /* TODO: set label here when adjin supports labels */ bmp_monitor(bmp, adjin->peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, - bn_p, prd, adjin->attr, afi, safi, adjin->uptime); + bn_p, prd, adjin->attr, afi, safi, adjin->uptime, + NULL, 0); if (bn) bgp_dest_unlock_node(bn); @@ -1281,6 +1296,7 @@ static bool bmp_wrqueue_locrib(struct bmp *bmp, struct pullwr *pullwr) struct peer *peer; struct bgp_dest *bn = NULL; bool written = false; + uint8_t bpi_num_labels; bqe = bmp_pull_locrib(bmp); if (!bqe) @@ -1340,10 +1356,14 @@ static bool bmp_wrqueue_locrib(struct bmp *bmp, struct pullwr *pullwr) break; } + bpi_num_labels = bgp_path_info_num_labels(bpi); + bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_LOC_RIB_INSTANCE, &bqe->p, prd, bpi ? bpi->attr : NULL, afi, safi, bpi && bpi->extra ? bpi->extra->bgp_rib_uptime - : (time_t)(-1L)); + : (time_t)(-1L), + bpi_num_labels ? bpi->extra->labels->label : NULL, + bpi_num_labels); written = true; out: @@ -1362,6 +1382,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) struct peer *peer; struct bgp_dest *bn = NULL; bool written = false; + uint8_t bpi_num_labels; bqe = bmp_pull(bmp); if (!bqe) @@ -1413,10 +1434,14 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) break; } + bpi_num_labels = bgp_path_info_num_labels(bpi); + bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, BMP_PEER_TYPE_GLOBAL_INSTANCE, &bqe->p, prd, bpi ? bpi->attr : NULL, afi, safi, - bpi ? bpi->uptime : monotime(NULL)); + bpi ? bpi->uptime : monotime(NULL), + bpi_num_labels ? bpi->extra->labels->label : NULL, + bpi_num_labels); written = true; } @@ -1428,9 +1453,10 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) if (adjin->peer == peer) break; } + /* TODO: set label here when adjin supports labels */ bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, &bqe->p, prd, adjin ? adjin->attr : NULL, afi, safi, - adjin ? adjin->uptime : monotime(NULL)); + adjin ? adjin->uptime : monotime(NULL), NULL, 0); written = true; } @@ -1578,6 +1604,15 @@ static void bmp_stat_put_u32(struct stream *s, size_t *cnt, uint16_t type, (*cnt)++; } +static void bmp_stat_put_u64(struct stream *s, size_t *cnt, uint16_t type, + uint64_t value) +{ + stream_putw(s, type); + stream_putw(s, 8); + stream_putq(s, value); + (*cnt)++; +} + static void bmp_stats(struct event *thread) { struct bmp_targets *bt = EVENT_ARG(thread); @@ -1619,8 +1654,13 @@ static void bmp_stats(struct event *thread) peer->stat_pfx_dup_withdraw); bmp_stat_put_u32(s, &count, BMP_STATS_UPD_7606_WITHDRAW, peer->stat_upd_7606); - bmp_stat_put_u32(s, &count, BMP_STATS_FRR_NH_INVALID, - peer->stat_pfx_nh_invalid); + if (bt->stats_send_experimental) + bmp_stat_put_u32(s, &count, BMP_STATS_FRR_NH_INVALID, + peer->stat_pfx_nh_invalid); + bmp_stat_put_u64(s, &count, BMP_STATS_SIZE_ADJ_RIB_IN, + peer->stat_pfx_adj_rib_in); + bmp_stat_put_u64(s, &count, BMP_STATS_SIZE_LOC_RIB, + peer->stat_pfx_loc_rib); stream_putl_at(s, count_pos, count); @@ -1875,6 +1915,7 @@ static struct bmp_targets *bmp_targets_get(struct bgp *bgp, const char *name) bt->name = XSTRDUP(MTYPE_BMP_TARGETSNAME, name); bt->bgp = bgp; bt->bmpbgp = bmp_bgp_get(bgp); + bt->stats_send_experimental = true; bmp_session_init(&bt->sessions); bmp_qhash_init(&bt->updhash); bmp_qlist_init(&bt->updlist); @@ -2455,6 +2496,21 @@ DEFPY(bmp_stats_cfg, return CMD_SUCCESS; } +DEFPY(bmp_stats_send_experimental, + bmp_stats_send_experimental_cmd, + "[no] bmp stats send-experimental", + NO_STR + BMP_STR + "Send BMP statistics messages\n" + "Send experimental BMP stats [65531-65534]\n") +{ + VTY_DECLVAR_CONTEXT_SUB(bmp_targets, bt); + + bt->stats_send_experimental = !no; + + return CMD_SUCCESS; +} + #define BMP_POLICY_IS_LOCRIB(str) ((str)[0] == 'l') /* __l__oc-rib */ #define BMP_POLICY_IS_PRE(str) ((str)[1] == 'r') /* p__r__e-policy */ @@ -2747,6 +2803,9 @@ static int bmp_config_write(struct bgp *bgp, struct vty *vty) if (bt->acl_name) vty_out(vty, " ip access-list %s\n", bt->acl_name); + if (!bt->stats_send_experimental) + vty_out(vty, " no bmp stats send-experimental\n"); + if (bt->stat_msec) vty_out(vty, " bmp stats interval %d\n", bt->stat_msec); @@ -2802,6 +2861,7 @@ static int bgp_bmp_init(struct event_loop *tm) install_element(BMP_NODE, &no_bmp_listener_cmd); install_element(BMP_NODE, &bmp_connect_cmd); install_element(BMP_NODE, &bmp_acl_cmd); + install_element(BMP_NODE, &bmp_stats_send_experimental_cmd); install_element(BMP_NODE, &bmp_stats_cmd); install_element(BMP_NODE, &bmp_monitor_cmd); install_element(BMP_NODE, &bmp_mirror_cmd); diff --git a/bgpd/bgp_bmp.h b/bgpd/bgp_bmp.h index dadd99e..33247c4 100644 --- a/bgpd/bgp_bmp.h +++ b/bgpd/bgp_bmp.h @@ -240,6 +240,8 @@ struct bmp_targets { uint64_t cnt_accept, cnt_aclrefused; + bool stats_send_experimental; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(bmp_targets); diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 8336d6f..153cbd6 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -904,9 +904,9 @@ int community_list_set(struct community_list_handler *ch, const char *name, } /* Unset community-list */ -int community_list_unset(struct community_list_handler *ch, const char *name, - const char *str, const char *seq, int direct, - int style) +void community_list_unset(struct community_list_handler *ch, const char *name, + const char *str, const char *seq, int direct, + int style) { struct community_list_master *cm = NULL; struct community_entry *entry = NULL; @@ -916,14 +916,14 @@ int community_list_unset(struct community_list_handler *ch, const char *name, /* Lookup community list. */ list = community_list_lookup(ch, name, 0, COMMUNITY_LIST_MASTER); if (list == NULL) - return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + return; cm = community_list_master_lookup(ch, COMMUNITY_LIST_MASTER); /* Delete all of entry belongs to this community-list. */ if (!str) { community_list_delete(cm, list); route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED); - return 0; + return; } if (style == COMMUNITY_LIST_STANDARD) @@ -936,12 +936,10 @@ int community_list_unset(struct community_list_handler *ch, const char *name, entry = community_list_entry_lookup(list, str, direct); if (!entry) - return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + return; community_list_entry_delete(cm, list, entry); route_map_notify_dependencies(name, RMAP_EVENT_CLIST_DELETED); - - return 0; } bool lcommunity_list_any_match(struct lcommunity *lcom, @@ -1172,9 +1170,9 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name, /* Unset community-list. When str is NULL, delete all of community-list entry belongs to the specified name. */ -int lcommunity_list_unset(struct community_list_handler *ch, const char *name, - const char *str, const char *seq, int direct, - int style) +void lcommunity_list_unset(struct community_list_handler *ch, const char *name, + const char *str, const char *seq, int direct, + int style) { struct community_list_master *cm = NULL; struct community_entry *entry = NULL; @@ -1185,14 +1183,14 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name, /* Lookup community list. */ list = community_list_lookup(ch, name, 0, LARGE_COMMUNITY_LIST_MASTER); if (list == NULL) - return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + return; cm = community_list_master_lookup(ch, LARGE_COMMUNITY_LIST_MASTER); /* Delete all of entry belongs to this community-list. */ if (!str) { community_list_delete(cm, list); route_map_notify_dependencies(name, RMAP_EVENT_LLIST_DELETED); - return 0; + return; } if (style == LARGE_COMMUNITY_LIST_STANDARD) @@ -1201,7 +1199,7 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name, regex = bgp_regcomp(str); if (!lcom && !regex) - return COMMUNITY_LIST_ERR_MALFORMED_VAL; + return; if (lcom) entry = community_list_entry_lookup(list, lcom, direct); @@ -1214,12 +1212,10 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name, bgp_regex_free(regex); if (!entry) - return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + return; community_list_entry_delete(cm, list, entry); route_map_notify_dependencies(name, RMAP_EVENT_LLIST_DELETED); - - return 0; } /* Set extcommunity-list. */ @@ -1299,9 +1295,9 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name, * When str is NULL, delete all extcommunity-list entries belonging to the * specified name. */ -int extcommunity_list_unset(struct community_list_handler *ch, const char *name, - const char *str, const char *seq, int direct, - int style) +void extcommunity_list_unset(struct community_list_handler *ch, + const char *name, const char *str, const char *seq, + int direct, int style) { struct community_list_master *cm = NULL; struct community_entry *entry = NULL; @@ -1311,14 +1307,14 @@ int extcommunity_list_unset(struct community_list_handler *ch, const char *name, /* Lookup extcommunity list. */ list = community_list_lookup(ch, name, 0, EXTCOMMUNITY_LIST_MASTER); if (list == NULL) - return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + return; cm = community_list_master_lookup(ch, EXTCOMMUNITY_LIST_MASTER); /* Delete all of entry belongs to this extcommunity-list. */ if (!str) { community_list_delete(cm, list); route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED); - return 0; + return; } if (style == EXTCOMMUNITY_LIST_STANDARD) @@ -1331,12 +1327,10 @@ int extcommunity_list_unset(struct community_list_handler *ch, const char *name, entry = community_list_entry_lookup(list, str, direct); if (!entry) - return COMMUNITY_LIST_ERR_CANT_FIND_LIST; + return; community_list_entry_delete(cm, list, entry); route_map_notify_dependencies(name, RMAP_EVENT_ECLIST_DELETED); - - return 0; } /* Initializa community-list. Return community-list handler. */ diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h index a435b92..29bd880 100644 --- a/bgpd/bgp_clist.h +++ b/bgpd/bgp_clist.h @@ -109,11 +109,9 @@ struct community_list_handler { }; /* Error code of community-list. */ -#define COMMUNITY_LIST_ERR_CANT_FIND_LIST -1 -#define COMMUNITY_LIST_ERR_MALFORMED_VAL -2 -#define COMMUNITY_LIST_ERR_STANDARD_CONFLICT -3 -#define COMMUNITY_LIST_ERR_EXPANDED_CONFLICT -4 - +#define COMMUNITY_LIST_ERR_MALFORMED_VAL -1 +#define COMMUNITY_LIST_ERR_STANDARD_CONFLICT -2 +#define COMMUNITY_LIST_ERR_EXPANDED_CONFLICT -3 /* Handler. */ extern struct community_list_handler *bgp_clist; @@ -124,22 +122,22 @@ extern void community_list_terminate(struct community_list_handler *ch); extern int community_list_set(struct community_list_handler *ch, const char *name, const char *str, const char *seq, int direct, int style); -extern int community_list_unset(struct community_list_handler *ch, - const char *name, const char *str, - const char *seq, int direct, int style); +extern void community_list_unset(struct community_list_handler *ch, + const char *name, const char *str, + const char *seq, int direct, int style); extern int extcommunity_list_set(struct community_list_handler *ch, const char *name, const char *str, const char *seq, int direct, int style); -extern int extcommunity_list_unset(struct community_list_handler *ch, - const char *name, const char *str, - const char *seq, int direct, int style); +extern void extcommunity_list_unset(struct community_list_handler *ch, + const char *name, const char *str, + const char *seq, int direct, int style); extern int lcommunity_list_set(struct community_list_handler *ch, const char *name, const char *str, const char *seq, int direct, int style); extern bool lcommunity_list_valid(const char *community, int style); -extern int lcommunity_list_unset(struct community_list_handler *ch, - const char *name, const char *str, - const char *seq, int direct, int style); +extern void lcommunity_list_unset(struct community_list_handler *ch, + const char *name, const char *str, + const char *seq, int direct, int style); extern struct community_list_master * community_list_master_lookup(struct community_list_handler *ch, int master); diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index 80425eb..339bfae 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -22,19 +22,76 @@ #include "bgpd/bgp_advertise.h" #include "bgpd/bgp_vty.h" -/* Global variable to access damping configuration */ -static struct bgp_damp_config damp[AFI_MAX][SAFI_MAX]; +static void bgp_reuselist_add(struct reuselist *list, struct bgp_damp_info *info) +{ + assert(info); + SLIST_INSERT_HEAD(list, info, entry); +} + +static void bgp_reuselist_del(struct reuselist *list, struct bgp_damp_info *info) +{ + assert(info); + SLIST_REMOVE(list, info, bgp_damp_info, entry); +} -/* Utility macro to add and delete BGP dampening information to no - used list. */ -#define BGP_DAMP_LIST_ADD(N, A) BGP_PATH_INFO_ADD(N, A, no_reuse_list) -#define BGP_DAMP_LIST_DEL(N, A) BGP_PATH_INFO_DEL(N, A, no_reuse_list) +static void bgp_reuselist_switch(struct reuselist *source, + struct bgp_damp_info *info, + struct reuselist *target) +{ + assert(source && target && info); + SLIST_REMOVE(source, info, bgp_damp_info, entry); + SLIST_INSERT_HEAD(target, info, entry); +} + +static void bgp_damp_info_unclaim(struct bgp_damp_info *bdi, + struct reuselist *list) +{ + assert(bdi && bdi->config); + if (bdi->index == BGP_DAMP_NO_REUSE_LIST_INDEX) + bgp_reuselist_del(&bdi->config->no_reuse_list, bdi); + else + bgp_reuselist_del(list ? list + : &bdi->config->reuse_list[bdi->index], + bdi); + bdi->config = NULL; +} + +static void bgp_damp_info_claim(struct bgp_damp_info *bdi, + struct bgp_damp_config *bdc) +{ + assert(bdc && bdi); + if (bdi->config == NULL) { + bdi->config = bdc; + return; + } + bgp_damp_info_unclaim(bdi, NULL); + bdi->config = bdc; + bdi->afi = bdc->afi; + bdi->safi = bdc->safi; +} + +struct bgp_damp_config *get_active_bdc_from_pi(struct bgp_path_info *pi, + afi_t afi, safi_t safi) +{ + if (!pi) + return NULL; + if (CHECK_FLAG(pi->peer->af_flags[afi][safi], + PEER_FLAG_CONFIG_DAMPENING)) + return &pi->peer->damp[afi][safi]; + if (peer_group_active(pi->peer)) + if (CHECK_FLAG(pi->peer->group->conf->af_flags[afi][safi], + PEER_FLAG_CONFIG_DAMPENING)) + return &pi->peer->group->conf->damp[afi][safi]; + if (CHECK_FLAG(pi->peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) + return &pi->peer->bgp->damp[afi][safi]; + return NULL; +} /* Calculate reuse list index by penalty value. */ static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc) { unsigned int i; - int index; + unsigned int index; /* * reuse_limit can't be zero, this is for Coverity @@ -57,27 +114,28 @@ static int bgp_reuse_index(int penalty, struct bgp_damp_config *bdc) static void bgp_reuse_list_add(struct bgp_damp_info *bdi, struct bgp_damp_config *bdc) { - int index; - - index = bdi->index = bgp_reuse_index(bdi->penalty, bdc); - - bdi->prev = NULL; - bdi->next = bdc->reuse_list[index]; - if (bdc->reuse_list[index]) - bdc->reuse_list[index]->prev = bdi; - bdc->reuse_list[index] = bdi; + bgp_damp_info_claim(bdi, bdc); + bdi->index = bgp_reuse_index(bdi->penalty, bdc); + bgp_reuselist_add(&bdc->reuse_list[bdi->index], bdi); } /* Delete BGP dampening information from reuse list. */ -static void bgp_reuse_list_delete(struct bgp_damp_info *bdi, +static void bgp_reuse_list_delete(struct bgp_damp_info *bdi) +{ + bgp_damp_info_unclaim(bdi, NULL); +} + +static void bgp_no_reuse_list_add(struct bgp_damp_info *bdi, struct bgp_damp_config *bdc) { - if (bdi->next) - bdi->next->prev = bdi->prev; - if (bdi->prev) - bdi->prev->next = bdi->next; - else - bdc->reuse_list[bdi->index] = bdi->next; + bgp_damp_info_claim(bdi, bdc); + bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX; + bgp_reuselist_add(&bdc->no_reuse_list, bdi); +} + +static void bgp_no_reuse_list_delete(struct bgp_damp_info *bdi) +{ + bgp_damp_info_unclaim(bdi, NULL); } /* Return decayed penalty value. */ @@ -100,10 +158,10 @@ int bgp_damp_decay(time_t tdiff, int penalty, struct bgp_damp_config *bdc) is evaluated. RFC2439 Section 4.8.7. */ static void bgp_reuse_timer(struct event *t) { - struct bgp_damp_info *bdi; - struct bgp_damp_info *next; + struct bgp_damp_info *bdi, *bdi_next; + struct reuselist plist; + struct bgp *bgp; time_t t_now, t_diff; - struct bgp_damp_config *bdc = EVENT_ARG(t); bdc->t_reuse = NULL; @@ -112,20 +170,20 @@ static void bgp_reuse_timer(struct event *t) t_now = monotime(NULL); - /* 1. save a pointer to the current zeroth queue head and zero the - list head entry. */ - bdi = bdc->reuse_list[bdc->reuse_offset]; - bdc->reuse_list[bdc->reuse_offset] = NULL; + /* 1. save a pointer to the current queue head and zero the list head + * list head entry. */ + assert(bdc->reuse_offset < bdc->reuse_list_size); + plist = bdc->reuse_list[bdc->reuse_offset]; + SLIST_INIT(&bdc->reuse_list[bdc->reuse_offset]); /* 2. set offset = modulo reuse-list-size ( offset + 1 ), thereby rotating the circular queue of list-heads. */ bdc->reuse_offset = (bdc->reuse_offset + 1) % bdc->reuse_list_size; + assert(bdc->reuse_offset < bdc->reuse_list_size); /* 3. if ( the saved list head pointer is non-empty ) */ - for (; bdi; bdi = next) { - struct bgp *bgp = bdi->path->peer->bgp; - - next = bdi->next; + SLIST_FOREACH_SAFE (bdi, &plist, entry, bdi_next) { + bgp = bdi->path->peer->bgp; /* Set t-diff = t-now - t-updated. */ t_diff = t_now - bdi->t_updated; @@ -150,19 +208,27 @@ static void bgp_reuse_timer(struct event *t) bgp_aggregate_increment( bgp, bgp_dest_get_prefix(bdi->dest), bdi->path, bdi->afi, bdi->safi); - bgp_process(bgp, bdi->dest, bdi->afi, + bgp_process(bgp, bdi->dest, bdi->path, bdi->afi, bdi->safi); } - if (bdi->penalty <= bdc->reuse_limit / 2.0) - bgp_damp_info_free(bdi, 1, bdc->afi, bdc->safi); - else - BGP_DAMP_LIST_ADD(bdc, bdi); - } else + if (bdi->penalty <= bdc->reuse_limit / 2.0) { + bgp_damp_info_free(bdi, &plist, 1); + } else { + bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX; + bgp_reuselist_switch(&plist, bdi, + &bdc->no_reuse_list); + } + } else { /* Re-insert into another list (See RFC2439 Section * 4.8.6). */ - bgp_reuse_list_add(bdi, bdc); + bdi->index = bgp_reuse_index(bdi->penalty, bdc); + bgp_reuselist_switch(&plist, bdi, + &bdc->reuse_list[bdi->index]); + } } + + assert(SLIST_EMPTY(&plist)); } /* A route becomes unreachable (RFC2439 Section 4.8.2). */ @@ -172,10 +238,13 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest, time_t t_now; struct bgp_damp_info *bdi = NULL; unsigned int last_penalty = 0; - struct bgp_damp_config *bdc = &damp[afi][safi]; + struct bgp_damp_config *bdc; - t_now = monotime(NULL); + bdc = get_active_bdc_from_pi(path, afi, safi); + if (!bdc) + return BGP_DAMP_USED; + t_now = monotime(NULL); /* Processing Unreachable Messages. */ if (path->extra) bdi = path->extra->damp_info; @@ -197,12 +266,20 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest, bdi->flap = 1; bdi->start_time = t_now; bdi->suppress_time = 0; - bdi->index = -1; + bdi->index = BGP_DAMP_NO_REUSE_LIST_INDEX; bdi->afi = afi; bdi->safi = safi; (bgp_path_info_extra_get(path))->damp_info = bdi; - BGP_DAMP_LIST_ADD(bdc, bdi); + bgp_no_reuse_list_add(bdi, bdc); } else { + if (bdi->config != bdc) { + bgp_damp_info_claim(bdi, bdc); + if (bdi->index == BGP_DAMP_NO_REUSE_LIST_INDEX) + bgp_reuselist_add(&bdc->no_reuse_list, bdi); + else + bgp_reuselist_add(&bdc->reuse_list[bdi->index], + bdi); + } last_penalty = bdi->penalty; /* 1. Set t-diff = t-now - t-updated. */ @@ -228,8 +305,8 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest, /* Remove the route from a reuse list if it is on one. */ if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED)) { /* If decay rate isn't equal to 0, reinsert brn. */ - if (bdi->penalty != last_penalty && bdi->index >= 0) { - bgp_reuse_list_delete(bdi, bdc); + if (bdi->penalty != last_penalty) { + bgp_reuse_list_delete(bdi); bgp_reuse_list_add(bdi, bdc); } return BGP_DAMP_SUPPRESSED; @@ -240,10 +317,9 @@ int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest, if (bdi->penalty >= bdc->suppress_value) { bgp_path_info_set_flag(dest, path, BGP_PATH_DAMPED); bdi->suppress_time = t_now; - BGP_DAMP_LIST_DEL(bdc, bdi); + bgp_no_reuse_list_delete(bdi); bgp_reuse_list_add(bdi, bdc); } - return BGP_DAMP_USED; } @@ -253,7 +329,10 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest, time_t t_now; struct bgp_damp_info *bdi; int status; - struct bgp_damp_config *bdc = &damp[afi][safi]; + struct bgp_damp_config *bdc; + + bdc = get_active_bdc_from_pi(path, afi, safi); + assert(bdc); if (!path->extra || !((bdi = path->extra->damp_info))) return BGP_DAMP_USED; @@ -271,8 +350,8 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest, else if (CHECK_FLAG(bdi->path->flags, BGP_PATH_DAMPED) && (bdi->penalty < bdc->reuse_limit)) { bgp_path_info_unset_flag(dest, path, BGP_PATH_DAMPED); - bgp_reuse_list_delete(bdi, bdc); - BGP_DAMP_LIST_ADD(bdc, bdi); + bgp_reuse_list_delete(bdi); + bgp_no_reuse_list_add(bdi, bdc); bdi->suppress_time = 0; status = BGP_DAMP_USED; } else @@ -281,33 +360,32 @@ int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest, if (bdi->penalty > bdc->reuse_limit / 2.0) bdi->t_updated = t_now; else - bgp_damp_info_free(bdi, 0, afi, safi); + bgp_damp_info_free(bdi, NULL, 0); return status; } -void bgp_damp_info_free(struct bgp_damp_info *bdi, int withdraw, afi_t afi, - safi_t safi) +void bgp_damp_info_free(struct bgp_damp_info *bdi, struct reuselist *list, + int withdraw) { - struct bgp_path_info *path; - struct bgp_damp_config *bdc = &damp[afi][safi]; - - if (!bdi) - return; - - path = bdi->path; - path->extra->damp_info = NULL; - - if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)) - bgp_reuse_list_delete(bdi, bdc); - else - BGP_DAMP_LIST_DEL(bdc, bdi); - - bgp_path_info_unset_flag(bdi->dest, path, - BGP_PATH_HISTORY | BGP_PATH_DAMPED); - - if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw) - bgp_path_info_delete(bdi->dest, path); + assert(bdi); + + afi_t afi = bdi->afi; + safi_t safi = bdi->safi; + struct bgp_path_info *bpi = bdi->path; + struct bgp_dest *dest = bdi->dest; + struct bgp *bgp = bpi->peer->bgp; + const struct prefix *p = bgp_dest_get_prefix(bdi->dest); + + bgp_damp_info_unclaim(bdi, list); + + bpi->extra->damp_info = NULL; + bgp_path_info_unset_flag(dest, bpi, BGP_PATH_HISTORY | BGP_PATH_DAMPED); + if (bdi->lastrecord == BGP_RECORD_WITHDRAW && withdraw) { + bgp_aggregate_decrement(bgp, p, bpi, afi, SAFI_UNICAST); + bgp_path_info_delete(dest, bpi); + bgp_process(bgp, dest, bpi, afi, safi); + } XFREE(MTYPE_BGP_DAMP_INFO, bdi); } @@ -353,8 +431,7 @@ static void bgp_damp_parameter_set(time_t hlife, unsigned int reuse, bdc->reuse_list = XCALLOC(MTYPE_BGP_DAMP_ARRAY, - bdc->reuse_list_size * sizeof(struct bgp_reuse_node *)); - + bdc->reuse_list_size * sizeof(struct reuselist)); /* Reuse-array computations */ bdc->reuse_index = XCALLOC(MTYPE_BGP_DAMP_ARRAY, sizeof(int) * bdc->reuse_index_size); @@ -381,7 +458,7 @@ static void bgp_damp_parameter_set(time_t hlife, unsigned int reuse, int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half, unsigned int reuse, unsigned int suppress, time_t max) { - struct bgp_damp_config *bdc = &damp[afi][safi]; + struct bgp_damp_config *bdc = &bgp->damp[afi][safi]; if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) { if (bdc->half_life == half && bdc->reuse_limit == reuse @@ -393,6 +470,8 @@ int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half, SET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING); bgp_damp_parameter_set(half, reuse, suppress, max, bdc); + bdc->afi = afi; + bdc->safi = safi; /* Register reuse timer. */ event_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE, @@ -401,8 +480,34 @@ int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half, return 0; } -static void bgp_damp_config_clean(struct bgp_damp_config *bdc) +/* Clean all the bgp_damp_info stored in reuse_list and no_reuse_list. */ +void bgp_damp_info_clean(struct bgp *bgp, struct bgp_damp_config *bdc, + afi_t afi, safi_t safi) { + struct bgp_damp_info *bdi; + struct reuselist *list; + unsigned int i; + + bdc->reuse_offset = 0; + for (i = 0; i < bdc->reuse_list_size; ++i) { + list = &bdc->reuse_list[i]; + while ((bdi = SLIST_FIRST(list)) != NULL) { + if (bdi->lastrecord == BGP_RECORD_UPDATE) { + bgp_aggregate_increment(bgp, + bgp_dest_get_prefix( + bdi->dest), + bdi->path, bdi->afi, + bdi->safi); + bgp_process(bgp, bdi->dest, bdi->path, bdi->afi, + bdi->safi); + } + bgp_damp_info_free(bdi, list, 1); + } + } + + while ((bdi = SLIST_FIRST(&bdc->no_reuse_list)) != NULL) + bgp_damp_info_free(bdi, &bdc->no_reuse_list, 1); + /* Free decay array */ XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->decay_array); bdc->decay_array_size = 0; @@ -411,41 +516,25 @@ static void bgp_damp_config_clean(struct bgp_damp_config *bdc) XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_index); bdc->reuse_index_size = 0; - /* Free reuse list array. */ XFREE(MTYPE_BGP_DAMP_ARRAY, bdc->reuse_list); bdc->reuse_list_size = 0; -} - -/* Clean all the bgp_damp_info stored in reuse_list. */ -void bgp_damp_info_clean(afi_t afi, safi_t safi) -{ - unsigned int i; - struct bgp_damp_info *bdi, *next; - struct bgp_damp_config *bdc = &damp[afi][safi]; - - bdc->reuse_offset = 0; - for (i = 0; i < bdc->reuse_list_size; i++) { - if (!bdc->reuse_list[i]) - continue; - - for (bdi = bdc->reuse_list[i]; bdi; bdi = next) { - next = bdi->next; - bgp_damp_info_free(bdi, 1, afi, safi); - } - bdc->reuse_list[i] = NULL; - } - - for (bdi = bdc->no_reuse_list; bdi; bdi = next) { - next = bdi->next; - bgp_damp_info_free(bdi, 1, afi, safi); - } - bdc->no_reuse_list = NULL; + EVENT_OFF(bdc->t_reuse); } +/* Disable route flap dampening for a bgp instance. + * + * Please note that this function also gets used to free memory when deleting a + * bgp instance. + */ int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi) { - struct bgp_damp_config *bdc = &damp[afi][safi]; + struct bgp_damp_config *bdc; + + bdc = &bgp->damp[afi][safi]; + if (!bdc) + return 0; + /* If it wasn't enabled, there's nothing to do. */ if (!CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) return 0; @@ -454,54 +543,51 @@ int bgp_damp_disable(struct bgp *bgp, afi_t afi, safi_t safi) EVENT_OFF(bdc->t_reuse); /* Clean BGP dampening information. */ - bgp_damp_info_clean(afi, safi); - - /* Clear configuration */ - bgp_damp_config_clean(bdc); + bgp_damp_info_clean(bgp, bdc, afi, safi); UNSET_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING); + return 0; } -void bgp_config_write_damp(struct vty *vty, afi_t afi, safi_t safi) +void bgp_config_write_damp(struct vty *vty, struct bgp *bgp, afi_t afi, + safi_t safi) { - if (damp[afi][safi].half_life == DEFAULT_HALF_LIFE * 60 - && damp[afi][safi].reuse_limit == DEFAULT_REUSE - && damp[afi][safi].suppress_value == DEFAULT_SUPPRESS - && damp[afi][safi].max_suppress_time - == damp[afi][safi].half_life * 4) + struct bgp_damp_config *bdc; + + bdc = &bgp->damp[afi][safi]; + if (bdc->half_life == DEFAULT_HALF_LIFE * 60 && + bdc->reuse_limit == DEFAULT_REUSE && + bdc->suppress_value == DEFAULT_SUPPRESS && + bdc->max_suppress_time == bdc->half_life * 4) vty_out(vty, " bgp dampening\n"); - else if (damp[afi][safi].half_life != DEFAULT_HALF_LIFE * 60 - && damp[afi][safi].reuse_limit == DEFAULT_REUSE - && damp[afi][safi].suppress_value == DEFAULT_SUPPRESS - && damp[afi][safi].max_suppress_time - == damp[afi][safi].half_life * 4) - vty_out(vty, " bgp dampening %lld\n", - damp[afi][safi].half_life / 60LL); + else if (bdc->half_life != DEFAULT_HALF_LIFE * 60 && + bdc->reuse_limit == DEFAULT_REUSE && + bdc->suppress_value == DEFAULT_SUPPRESS && + bdc->max_suppress_time == bdc->half_life * 4) + vty_out(vty, " bgp dampening %lld\n", bdc->half_life / 60LL); else vty_out(vty, " bgp dampening %lld %d %d %lld\n", - damp[afi][safi].half_life / 60LL, - damp[afi][safi].reuse_limit, - damp[afi][safi].suppress_value, - damp[afi][safi].max_suppress_time / 60LL); + bdc->half_life / 60LL, bdc->reuse_limit, + bdc->suppress_value, bdc->max_suppress_time / 60LL); } -static const char *bgp_get_reuse_time(unsigned int penalty, char *buf, - size_t len, afi_t afi, safi_t safi, - bool use_json, json_object *json) +static const char *bgp_get_reuse_time(struct bgp_damp_config *bdc, + unsigned int penalty, char *buf, + size_t len, bool use_json, + json_object *json) { time_t reuse_time = 0; struct tm tm; int time_store = 0; - if (penalty > damp[afi][safi].reuse_limit) { - reuse_time = (int)(DELTA_T - * ((log((double)damp[afi][safi].reuse_limit - / penalty)) - / (log(damp[afi][safi].decay_array[1])))); + if (penalty > bdc->reuse_limit) { + reuse_time = (int)(DELTA_T * + ((log((double)bdc->reuse_limit / penalty)) / + (log(bdc->decay_array[1])))); - if (reuse_time > damp[afi][safi].max_suppress_time) - reuse_time = damp[afi][safi].max_suppress_time; + if (reuse_time > bdc->max_suppress_time) + reuse_time = bdc->max_suppress_time; gmtime_r(&reuse_time, &tm); } else @@ -553,14 +639,15 @@ static const char *bgp_get_reuse_time(unsigned int penalty, char *buf, return buf; } -void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi, - safi_t safi, json_object *json_path) +void bgp_damp_info_vty(struct vty *vty, struct bgp *bgp, + struct bgp_path_info *path, afi_t afi, safi_t safi, + json_object *json_path) { struct bgp_damp_info *bdi; time_t t_now, t_diff; char timebuf[BGP_UPTIME_LEN] = {}; int penalty; - struct bgp_damp_config *bdc = &damp[afi][safi]; + struct bgp_damp_config *bdc = &bgp->damp[afi][safi]; if (!path->extra) return; @@ -588,8 +675,8 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi, if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED) && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) - bgp_get_reuse_time(penalty, timebuf, BGP_UPTIME_LEN, - afi, safi, 1, json_path); + bgp_get_reuse_time(bdc, penalty, timebuf, + BGP_UPTIME_LEN, 1, json_path); } else { vty_out(vty, " Dampinfo: penalty %d, flapped %d times in %s", @@ -600,14 +687,15 @@ void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, afi_t afi, if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED) && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) vty_out(vty, ", reuse in %s", - bgp_get_reuse_time(penalty, timebuf, - BGP_UPTIME_LEN, afi, safi, 0, + bgp_get_reuse_time(bdc, penalty, timebuf, + BGP_UPTIME_LEN, 0, json_path)); vty_out(vty, "\n"); } } + const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path, char *timebuf, size_t len, afi_t afi, safi_t safi, bool use_json, @@ -616,7 +704,11 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path, struct bgp_damp_info *bdi; time_t t_now, t_diff; int penalty; - struct bgp_damp_config *bdc = &damp[afi][safi]; + struct bgp_damp_config *bdc; + + bdc = get_active_bdc_from_pi(path, afi, safi); + if (!bdc) + return NULL; if (!path->extra) return NULL; @@ -636,15 +728,15 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path, t_diff = t_now - bdi->t_updated; penalty = bgp_damp_decay(t_diff, bdi->penalty, bdc); - return bgp_get_reuse_time(penalty, timebuf, len, afi, safi, use_json, - json); + return bgp_get_reuse_time(bdc, penalty, timebuf, len, use_json, json); } + static int bgp_print_dampening_parameters(struct bgp *bgp, struct vty *vty, afi_t afi, safi_t safi, bool use_json) { if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) { - struct bgp_damp_config *bdc = &damp[afi][safi]; + struct bgp_damp_config *bdc = &bgp->damp[afi][safi]; if (use_json) { json_object *json = json_object_new_object(); @@ -687,7 +779,6 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi, bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); bgp = bgp_get_default(); - if (bgp == NULL) { vty_out(vty, "No BGP process is configured\n"); return CMD_WARNING; @@ -729,3 +820,130 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi, } return CMD_SUCCESS; } + +void bgp_peer_damp_enable(struct peer *peer, afi_t afi, safi_t safi, time_t half, + unsigned int reuse, unsigned int suppress, time_t max) +{ + struct bgp_damp_config *bdc; + + if (!peer) + return; + bdc = &peer->damp[afi][safi]; + if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_CONFIG_DAMPENING)) { + if (bdc->half_life == half && bdc->reuse_limit == reuse && + bdc->suppress_value == suppress && + bdc->max_suppress_time == max) + return; + bgp_peer_damp_disable(peer, afi, safi); + } + SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING); + bgp_damp_parameter_set(half, reuse, suppress, max, bdc); + bdc->afi = afi; + bdc->safi = safi; + event_add_timer(bm->master, bgp_reuse_timer, bdc, DELTA_REUSE, + &bdc->t_reuse); +} + +/* Disable route flap dampening for a peer. + * + * Please note that this function also gets used to free memory when deleting a + * peer or peer group. + */ +void bgp_peer_damp_disable(struct peer *peer, afi_t afi, safi_t safi) +{ + struct bgp_damp_config *bdc; + + if (!peer_af_flag_check(peer, afi, safi, PEER_FLAG_CONFIG_DAMPENING)) + return; + bdc = &peer->damp[afi][safi]; + if (!bdc) + return; + bgp_damp_info_clean(peer->bgp, bdc, afi, safi); + UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING); +} + +void bgp_config_write_peer_damp(struct vty *vty, struct peer *peer, afi_t afi, + safi_t safi) +{ + struct bgp_damp_config *bdc; + + bdc = &peer->damp[afi][safi]; + if (bdc->half_life == DEFAULT_HALF_LIFE * 60 && + bdc->reuse_limit == DEFAULT_REUSE && + bdc->suppress_value == DEFAULT_SUPPRESS && + bdc->max_suppress_time == bdc->half_life * 4) + vty_out(vty, " neighbor %s dampening\n", peer->host); + else if (bdc->half_life != DEFAULT_HALF_LIFE * 60 && + bdc->reuse_limit == DEFAULT_REUSE && + bdc->suppress_value == DEFAULT_SUPPRESS && + bdc->max_suppress_time == bdc->half_life * 4) + vty_out(vty, " neighbor %s dampening %lld\n", peer->host, + bdc->half_life / 60LL); + else + vty_out(vty, " neighbor %s dampening %lld %d %d %lld\n", + peer->host, bdc->half_life / 60LL, bdc->reuse_limit, + bdc->suppress_value, bdc->max_suppress_time / 60LL); +} + +static void bgp_print_peer_dampening_parameters(struct vty *vty, + struct peer *peer, afi_t afi, + safi_t safi, bool use_json, + json_object *json) +{ + struct bgp_damp_config *bdc; + + if (!peer) + return; + if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_CONFIG_DAMPENING)) { + bdc = &peer->damp[afi][safi]; + if (!bdc) + return; + if (use_json) { + json_object_int_add(json, "halfLifeSecs", + bdc->half_life); + json_object_int_add(json, "reusePenalty", + bdc->reuse_limit); + json_object_int_add(json, "suppressPenalty", + bdc->suppress_value); + json_object_int_add(json, "maxSuppressTimeSecs", + bdc->max_suppress_time); + json_object_int_add(json, "maxSuppressPenalty", + bdc->ceiling); + } else { + vty_out(vty, "Half-life time: %lld min\n", + (long long)bdc->half_life / 60); + vty_out(vty, "Reuse penalty: %d\n", bdc->reuse_limit); + vty_out(vty, "Suppress penalty: %d\n", + bdc->suppress_value); + vty_out(vty, "Max suppress time: %lld min\n", + (long long)bdc->max_suppress_time / 60); + vty_out(vty, "Max suppress penalty: %u\n", bdc->ceiling); + vty_out(vty, "\n"); + } + } else if (!use_json) + vty_out(vty, "neighbor dampening not enabled for %s\n", + get_afi_safi_str(afi, safi, false)); +} + +void bgp_show_peer_dampening_parameters(struct vty *vty, struct peer *peer, + afi_t afi, safi_t safi, bool use_json) +{ + json_object *json; + + if (use_json) { + json = json_object_new_object(); + json_object_string_add(json, "addressFamily", + get_afi_safi_str(afi, safi, false)); + bgp_print_peer_dampening_parameters(vty, peer, afi, safi, true, + json); + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } else { + vty_out(vty, "\nFor address family: %s\n", + get_afi_safi_str(afi, safi, false)); + bgp_print_peer_dampening_parameters(vty, peer, afi, safi, false, + NULL); + } +} diff --git a/bgpd/bgp_damp.h b/bgpd/bgp_damp.h index 6033c34..851c6f9 100644 --- a/bgpd/bgp_damp.h +++ b/bgpd/bgp_damp.h @@ -10,11 +10,6 @@ /* Structure maintained on a per-route basis. */ struct bgp_damp_info { - /* Doubly linked list. This information must be linked to - reuse_list or no_reuse_list. */ - struct bgp_damp_info *next; - struct bgp_damp_info *prev; - /* Figure-of-merit. */ unsigned int penalty; @@ -30,6 +25,9 @@ struct bgp_damp_info { /* Time of route start to be suppressed. */ time_t suppress_time; + /* Back reference to associated dampening configuration. */ + struct bgp_damp_config *config; + /* Back reference to bgp_path_info. */ struct bgp_path_info *path; @@ -38,6 +36,8 @@ struct bgp_damp_info { /* Current index in the reuse_list. */ int index; +#define BGP_DAMP_NO_REUSE_LIST_INDEX \ + (-1) /* index for elements on no_reuse_list */ /* Last time message type. */ uint8_t lastrecord; @@ -46,8 +46,12 @@ struct bgp_damp_info { afi_t afi; safi_t safi; + + SLIST_ENTRY(bgp_damp_info) entry; }; +SLIST_HEAD(reuselist, bgp_damp_info); + /* Specified parameter set configuration. */ struct bgp_damp_config { /* Value over which routes suppressed. */ @@ -84,12 +88,12 @@ struct bgp_damp_config { int *reuse_index; /* Reuse list array per-set based. */ - struct bgp_damp_info **reuse_list; - int reuse_offset; + struct reuselist *reuse_list; + unsigned int reuse_offset; safi_t safi; /* All dampening information which is not on reuse list. */ - struct bgp_damp_info *no_reuse_list; + struct reuselist no_reuse_list; /* Reuse timer thread per-set base. */ struct event *t_reuse; @@ -116,6 +120,8 @@ struct bgp_damp_config { #define REUSE_LIST_SIZE 256 #define REUSE_ARRAY_SIZE 1024 +extern struct bgp_damp_config *get_active_bdc_from_pi(struct bgp_path_info *pi, + afi_t afi, safi_t safi); extern int bgp_damp_enable(struct bgp *bgp, afi_t afi, safi_t safi, time_t half, unsigned int reuse, unsigned int suppress, time_t max); @@ -124,14 +130,18 @@ extern int bgp_damp_withdraw(struct bgp_path_info *path, struct bgp_dest *dest, afi_t afi, safi_t safi, int attr_change); extern int bgp_damp_update(struct bgp_path_info *path, struct bgp_dest *dest, afi_t afi, safi_t saff); -extern void bgp_damp_info_free(struct bgp_damp_info *path, int withdraw, - afi_t afi, safi_t safi); -extern void bgp_damp_info_clean(afi_t afi, safi_t safi); +extern void bgp_damp_info_free(struct bgp_damp_info *bdi, + struct reuselist *list, int withdraw); +extern void bgp_damp_info_clean(struct bgp *bgp, struct bgp_damp_config *bdc, + afi_t afi, safi_t safi); +extern void bgp_damp_config_clean(struct bgp_damp_config *bdc); extern int bgp_damp_decay(time_t tdiff, int penalty, - struct bgp_damp_config *damp); -extern void bgp_config_write_damp(struct vty *vty, afi_t afi, safi_t safi); -extern void bgp_damp_info_vty(struct vty *vty, struct bgp_path_info *path, - afi_t afi, safi_t safi, json_object *json_path); + struct bgp_damp_config *bdc); +extern void bgp_config_write_damp(struct vty *vty, struct bgp *bgp, afi_t afi, + safi_t safi); +extern void bgp_damp_info_vty(struct vty *vty, struct bgp *bgp, + struct bgp_path_info *path, afi_t afi, + safi_t safi, json_object *json_path); extern const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path, char *timebuf, size_t len, afi_t afi, @@ -139,5 +149,14 @@ extern const char *bgp_damp_reuse_time_vty(struct vty *vty, json_object *json); extern int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi, uint16_t show_flags); +extern void bgp_peer_damp_enable(struct peer *peer, afi_t afi, safi_t safi, + time_t half, unsigned int reuse, + unsigned int suppress, time_t max); +extern void bgp_peer_damp_disable(struct peer *peer, afi_t afi, safi_t safi); +extern void bgp_config_write_peer_damp(struct vty *vty, struct peer *peer, + afi_t afi, safi_t safi); +extern void bgp_show_peer_dampening_parameters(struct vty *vty, + struct peer *peer, afi_t afi, + safi_t safi, bool use_json); #endif /* _QUAGGA_BGP_DAMP_H */ diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 3ecdc0d..6228432 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -50,7 +50,6 @@ unsigned long conf_bgp_debug_keepalive; unsigned long conf_bgp_debug_update; unsigned long conf_bgp_debug_bestpath; unsigned long conf_bgp_debug_zebra; -unsigned long conf_bgp_debug_allow_martians; unsigned long conf_bgp_debug_nht; unsigned long conf_bgp_debug_update_groups; unsigned long conf_bgp_debug_vpn; @@ -71,7 +70,6 @@ unsigned long term_bgp_debug_keepalive; unsigned long term_bgp_debug_update; unsigned long term_bgp_debug_bestpath; unsigned long term_bgp_debug_zebra; -unsigned long term_bgp_debug_allow_martians; unsigned long term_bgp_debug_nht; unsigned long term_bgp_debug_update_groups; unsigned long term_bgp_debug_vpn; @@ -116,6 +114,7 @@ static const struct message bgp_notify_msg[] = { {BGP_NOTIFY_FSM_ERR, "Neighbor Events Error"}, {BGP_NOTIFY_CEASE, "Cease"}, {BGP_NOTIFY_ROUTE_REFRESH_ERR, "ROUTE-REFRESH Message Error"}, + {BGP_NOTIFY_SEND_HOLD_ERR, "Send Hold Timer Expired"}, {0}}; static const struct message bgp_notify_head_msg[] = { @@ -515,6 +514,7 @@ const char *bgp_notify_subcode_str(char code, char subcode) return lookup_msg(bgp_notify_update_msg, subcode, "Unrecognized Error Subcode"); case BGP_NOTIFY_HOLD_ERR: + case BGP_NOTIFY_SEND_HOLD_ERR: break; case BGP_NOTIFY_FSM_ERR: return lookup_msg(bgp_notify_fsm_msg, subcode, @@ -2163,7 +2163,6 @@ DEFUN (no_debug_bgp, TERM_DEBUG_OFF(as4, AS4_SEGMENT); TERM_DEBUG_OFF(neighbor_events, NEIGHBOR_EVENTS); TERM_DEBUG_OFF(zebra, ZEBRA); - TERM_DEBUG_OFF(allow_martians, ALLOW_MARTIANS); TERM_DEBUG_OFF(nht, NHT); TERM_DEBUG_OFF(vpn, VPN_LEAK_FROM_VRF); TERM_DEBUG_OFF(vpn, VPN_LEAK_TO_VRF); @@ -2239,9 +2238,6 @@ DEFUN_NOSH (show_debugging_bgp, if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) vty_out(vty, " BGP graceful-restart debugging is on\n"); - if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) - vty_out(vty, " BGP allow martian next hop debugging is on\n"); - if (BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)) vty_out(vty, " BGP route leak from vrf to vpn debugging is on\n"); @@ -2354,11 +2350,6 @@ static int bgp_config_write_debug(struct vty *vty) } } - if (CONF_BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) { - vty_out(vty, "debug bgp allow-martians\n"); - write++; - } - if (CONF_BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)) { vty_out(vty, "debug bgp vpn leak-from-vrf\n"); write++; @@ -2722,7 +2713,7 @@ bool bgp_debug_zebra(const struct prefix *p) const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi, const struct prefix_rd *prd, union prefixconstptr pu, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, int addpath_valid, uint32_t addpath_id, struct bgp_route_evpn *overlay_index, char *str, int size) diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index 5b09501..061d966 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -61,7 +61,6 @@ extern unsigned long conf_bgp_debug_keepalive; extern unsigned long conf_bgp_debug_update; extern unsigned long conf_bgp_debug_bestpath; extern unsigned long conf_bgp_debug_zebra; -extern unsigned long conf_bgp_debug_allow_martians; extern unsigned long conf_bgp_debug_nht; extern unsigned long conf_bgp_debug_update_groups; extern unsigned long conf_bgp_debug_vpn; @@ -80,7 +79,6 @@ extern unsigned long term_bgp_debug_keepalive; extern unsigned long term_bgp_debug_update; extern unsigned long term_bgp_debug_bestpath; extern unsigned long term_bgp_debug_zebra; -extern unsigned long term_bgp_debug_allow_martians; extern unsigned long term_bgp_debug_nht; extern unsigned long term_bgp_debug_update_groups; extern unsigned long term_bgp_debug_vpn; @@ -120,7 +118,6 @@ struct bgp_debug_filter { #define BGP_DEBUG_UPDATE_PREFIX 0x04 #define BGP_DEBUG_UPDATE_DETAIL 0x08 #define BGP_DEBUG_ZEBRA 0x01 -#define BGP_DEBUG_ALLOW_MARTIANS 0x01 #define BGP_DEBUG_NHT 0x01 #define BGP_DEBUG_UPDATE_GROUPS 0x01 #define BGP_DEBUG_VPN_LEAK_FROM_VRF 0x01 @@ -156,8 +153,8 @@ struct bgp_debug_filter { TERM_DEBUG_OFF(a, b); \ } while (0) -#define BGP_DEBUG(a, b) (term_bgp_debug_ ## a & BGP_DEBUG_ ## b) -#define CONF_BGP_DEBUG(a, b) (conf_bgp_debug_ ## a & BGP_DEBUG_ ## b) +#define BGP_DEBUG(a, b) (unlikely(term_bgp_debug_##a & BGP_DEBUG_##b)) +#define CONF_BGP_DEBUG(a, b) (unlikely(conf_bgp_debug_##a & BGP_DEBUG_##b)) extern const char *const bgp_type_str[]; @@ -178,7 +175,7 @@ extern bool bgp_debug_zebra(const struct prefix *p); extern const char *bgp_debug_rdpfxpath2str( afi_t afi, safi_t safi, const struct prefix_rd *prd, - union prefixconstptr pu, mpls_label_t *label, uint32_t num_labels, + union prefixconstptr pu, mpls_label_t *label, uint8_t num_labels, int addpath_valid, uint32_t addpath_id, struct bgp_route_evpn *overlay_index, char *str, int size); const char *bgp_notify_admin_message(char *buf, size_t bufsz, uint8_t *data, diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index a8ae177..1beb030 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -237,11 +237,10 @@ struct ecommunity *ecommunity_parse(uint8_t *pnt, unsigned short length, disable_ieee_floating); } -struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt, unsigned short length, - bool disable_ieee_floating) +struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt, unsigned short length) { return ecommunity_parse_internal(pnt, length, IPV6_ECOMMUNITY_SIZE, - disable_ieee_floating); + false); } /* Duplicate the Extended Communities Attribute structure. */ @@ -263,8 +262,11 @@ struct ecommunity *ecommunity_dup(struct ecommunity *ecom) } /* Return string representation of ecommunities attribute. */ -char *ecommunity_str(struct ecommunity *ecom) +const char *ecommunity_str(struct ecommunity *ecom) { + if (!ecom) + return "(null)"; + if (!ecom->str) ecom->str = ecommunity_ecom2str(ecom, ECOMMUNITY_FORMAT_DISPLAY, 0); @@ -724,15 +726,21 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr, memset(buf, 0, INET_ADDRSTRLEN + 1); memcpy(buf, str, p - str); - if (dot) { + if (dot == 3) { /* Parsing A.B.C.D in: * A.B.C.D:MN */ ret = inet_aton(buf, &ip); if (ret == 0) goto error; + } else if (dot == 1) { + /* Parsing A.B AS number in: + * A.B:MN + */ + if (!asn_str2asn(buf, &as)) + goto error; } else { - /* ASN */ + /* Parsing A AS number in A:MN */ errno = 0; tmp_as = strtoul(buf, &endptr, 10); /* 'unsigned long' is a uint64 on 64-bit @@ -750,8 +758,11 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr, } else if (*p == '.') { if (separator) goto error; + /* either IP or AS format */ dot++; - if (dot > 4) + if (dot > 1) + ecomm_type = ECOMMUNITY_ENCODE_IP; + if (dot >= 4) goto error; } else { digit = 1; @@ -776,19 +787,18 @@ static const char *ecommunity_gettoken(const char *str, void *eval_ptr, if (!digit && (!separator || !val_color_set)) goto error; - /* Encode result into extended community. */ - if (dot) - ecomm_type = ECOMMUNITY_ENCODE_IP; - else if (as > BGP_AS_MAX) - ecomm_type = ECOMMUNITY_ENCODE_AS4; - else if (as > 0) - ecomm_type = ECOMMUNITY_ENCODE_AS; - else if (val_color) { - ecomm_type = ECOMMUNITY_ENCODE_OPAQUE; - sub_type = ECOMMUNITY_COLOR; - val = val_color; + if (ecomm_type != ECOMMUNITY_ENCODE_IP) { + /* Encode result into extended community for AS format or color. */ + if (as > BGP_AS_MAX) + ecomm_type = ECOMMUNITY_ENCODE_AS4; + else if (as > 0) + ecomm_type = ECOMMUNITY_ENCODE_AS; + else if (val_color) { + ecomm_type = ECOMMUNITY_ENCODE_OPAQUE; + sub_type = ECOMMUNITY_COLOR; + val = val_color; + } } - if (ecommunity_encode(ecomm_type, sub_type, 1, as, ip, val, eval)) goto error; *token = ecommunity_token_val; @@ -1015,10 +1025,6 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt, uint32_t bw_tmp, bw; char bps_buf[20] = {0}; -#define ONE_GBPS_BYTES (1000 * 1000 * 1000 / 8) -#define ONE_MBPS_BYTES (1000 * 1000 / 8) -#define ONE_KBPS_BYTES (1000 / 8) - as = (*pnt++ << 8); as |= (*pnt++); (void)ptr_get_be32(pnt, &bw_tmp); @@ -1042,6 +1048,38 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt, return len; } +static int ipv6_ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt, + size_t length) +{ + int len = 0; + as_t as = 0; + uint64_t bw = 0; + char bps_buf[20] = { 0 }; + + if (length < IPV6_ECOMMUNITY_SIZE) + goto done; + + pnt += 2; /* Reserved */ + pnt = ptr_get_be64(pnt, &bw); + (void)ptr_get_be32(pnt, &as); + + if (bw >= ONE_GBPS_BYTES) + snprintf(bps_buf, sizeof(bps_buf), "%.3f Gbps", + (float)(bw / ONE_GBPS_BYTES)); + else if (bw >= ONE_MBPS_BYTES) + snprintf(bps_buf, sizeof(bps_buf), "%.3f Mbps", + (float)(bw / ONE_MBPS_BYTES)); + else if (bw >= ONE_KBPS_BYTES) + snprintf(bps_buf, sizeof(bps_buf), "%.3f Kbps", + (float)(bw / ONE_KBPS_BYTES)); + else + snprintfrr(bps_buf, sizeof(bps_buf), "%" PRIu64 " bps", bw * 8); + +done: + len = snprintfrr(buf, bufsz, "LB:%u:%" PRIu64 " (%s)", as, bw, bps_buf); + return len; +} + bool ecommunity_has_route_target(struct ecommunity *ecom) { uint32_t i; @@ -1110,7 +1148,7 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) char encbuf[128]; for (i = 0; i < ecom->size; i++) { - int unk_ecom = 0; + bool unk_ecom = false; memset(encbuf, 0x00, sizeof(encbuf)); /* Space between each value. */ @@ -1120,6 +1158,18 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) /* Retrieve value field */ pnt = ecom->val + (i * ecom->unit_size); + uint8_t *data = pnt; + uint8_t *end = data + ecom->unit_size; + size_t len = end - data; + + /* Sanity check for extended communities lenght, to avoid + * overrun when dealing with bits, e.g. ptr_get_be64(). + */ + if (len < ecom->unit_size) { + unk_ecom = true; + goto unknown; + } + /* High-order octet is the type */ type = *pnt++; @@ -1142,13 +1192,19 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) ecommunity_lb_str( encbuf, sizeof(encbuf), pnt, ecom->disable_ieee_floating); + } else if (sub_type == + ECOMMUNITY_EXTENDED_LINK_BANDWIDTH && + type == ECOMMUNITY_ENCODE_AS4) { + ipv6_ecommunity_lb_str(encbuf, + sizeof(encbuf), + pnt, len); } else if (sub_type == ECOMMUNITY_NODE_TARGET && type == ECOMMUNITY_ENCODE_IP) { ecommunity_node_target_str( encbuf, sizeof(encbuf), pnt, format); } else - unk_ecom = 1; + unk_ecom = true; } else { ecommunity_rt_soo_str(encbuf, sizeof(encbuf), pnt, type, sub_type, @@ -1171,7 +1227,7 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) ecommunity_color_str(encbuf, sizeof(encbuf), pnt); } else { - unk_ecom = 1; + unk_ecom = true; } } else if (type == ECOMMUNITY_ENCODE_EVPN) { if (filter == ECOMMUNITY_ROUTE_TARGET) @@ -1264,14 +1320,14 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) "DF: (alg: %u, pref: %u)", alg, pref); } else - unk_ecom = 1; + unk_ecom = true; } else if (type == ECOMMUNITY_ENCODE_REDIRECT_IP_NH) { sub_type = *pnt++; if (sub_type == ECOMMUNITY_REDIRECT_IP_NH) { snprintf(encbuf, sizeof(encbuf), "FS:redirect IP 0x%x", *(pnt + 5)); } else - unk_ecom = 1; + unk_ecom = true; } else if (type == ECOMMUNITY_ENCODE_TRANS_EXP || type == ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 || type == ECOMMUNITY_EXTENDED_COMMUNITY_PART_3) { @@ -1318,7 +1374,7 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) snprintf(encbuf, sizeof(encbuf), "FS:redirect VRF %s", buf); } else if (type != ECOMMUNITY_ENCODE_TRANS_EXP) - unk_ecom = 1; + unk_ecom = true; else if (sub_type == ECOMMUNITY_TRAFFIC_ACTION) { char action[64]; @@ -1351,33 +1407,37 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) snprintf(encbuf, sizeof(encbuf), "FS:marking %u", *(pnt + 5)); } else - unk_ecom = 1; + unk_ecom = true; } else if (type == ECOMMUNITY_ENCODE_AS_NON_TRANS) { sub_type = *pnt++; if (sub_type == ECOMMUNITY_LINK_BANDWIDTH) ecommunity_lb_str(encbuf, sizeof(encbuf), pnt, ecom->disable_ieee_floating); + else if (sub_type == ECOMMUNITY_EXTENDED_LINK_BANDWIDTH) + ipv6_ecommunity_lb_str(encbuf, sizeof(encbuf), + pnt, len); else - unk_ecom = 1; + unk_ecom = true; } else if (type == ECOMMUNITY_ENCODE_IP_NON_TRANS) { sub_type = *pnt++; if (sub_type == ECOMMUNITY_NODE_TARGET) ecommunity_node_target_str( encbuf, sizeof(encbuf), pnt, format); else - unk_ecom = 1; + unk_ecom = true; } else if (type == ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS) { sub_type = *pnt++; if (sub_type == ECOMMUNITY_ORIGIN_VALIDATION_STATE) ecommunity_origin_validation_state_str( encbuf, sizeof(encbuf), pnt); else - unk_ecom = 1; + unk_ecom = true; } else { sub_type = *pnt++; - unk_ecom = 1; + unk_ecom = true; } +unknown: if (unk_ecom) snprintf(encbuf, sizeof(encbuf), "UNK:%d, %d", type, sub_type); @@ -1794,9 +1854,9 @@ ecommunity_add_origin_validation_state(enum rpki_states rpki_state, * return the BGP link bandwidth extended community, if present; * the actual bandwidth is returned via param */ -const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw) +const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint64_t *bw) { - const uint8_t *eval; + const uint8_t *data; uint32_t i; if (bw) @@ -1808,24 +1868,49 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw) for (i = 0; i < ecom->size; i++) { const uint8_t *pnt; uint8_t type, sub_type; - uint32_t bwval; - eval = pnt = (ecom->val + (i * ECOMMUNITY_SIZE)); + data = pnt = (ecom->val + (i * ecom->unit_size)); type = *pnt++; sub_type = *pnt++; + const uint8_t *end = data + ecom->unit_size; + size_t len = end - data; + + /* Sanity check for extended communities lenght, to avoid + * overrun when dealing with bits, e.g. ptr_get_be64(). + */ + if (len < ecom->unit_size) + return NULL; + if ((type == ECOMMUNITY_ENCODE_AS || type == ECOMMUNITY_ENCODE_AS_NON_TRANS) && sub_type == ECOMMUNITY_LINK_BANDWIDTH) { + uint32_t bwval; + pnt += 2; /* bandwidth is encoded as AS:val */ pnt = ptr_get_be32(pnt, &bwval); (void)pnt; /* consume value */ if (bw) - *bw = ecom->disable_ieee_floating - ? bwval - : ieee_float_uint32_to_uint32( - bwval); - return eval; + *bw = (uint64_t)(ecom->disable_ieee_floating + ? bwval + : ieee_float_uint32_to_uint32( + bwval)); + return data; + } else if (type == ECOMMUNITY_ENCODE_AS4 && + sub_type == ECOMMUNITY_EXTENDED_LINK_BANDWIDTH) { + uint64_t bwval; + + if (len < IPV6_ECOMMUNITY_SIZE) + return NULL; + + pnt += 2; /* Reserved */ + pnt = ptr_get_be64(pnt, &bwval); + (void)pnt; + + if (bw) + *bw = bwval; + + return data; } } @@ -1835,13 +1920,13 @@ const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw) struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom, uint64_t cum_bw, - bool disable_ieee_floating) + bool disable_ieee_floating, + bool extended) { struct ecommunity *new; - struct ecommunity_val lb_eval; const uint8_t *eval; uint8_t type; - uint32_t cur_bw; + uint64_t cur_bw; /* Nothing to replace if link-bandwidth doesn't exist or * is non-transitive - just return existing extcommunity. @@ -1865,10 +1950,21 @@ struct ecommunity *ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom, */ if (cum_bw > 0xFFFFFFFF) cum_bw = 0xFFFFFFFF; - encode_lb_extcomm(as > BGP_AS_MAX ? BGP_AS_TRANS : as, cum_bw, false, - &lb_eval, disable_ieee_floating); - new = ecommunity_dup(ecom); - ecommunity_add_val(new, &lb_eval, true, true); + + if (extended) { + struct ecommunity_val_ipv6 lb_eval; + + encode_lb_extended_extcomm(as, cum_bw, false, &lb_eval); + new = ecommunity_dup(ecom); + ecommunity_add_val_ipv6(new, &lb_eval, true, true); + } else { + struct ecommunity_val lb_eval; + + encode_lb_extcomm(as > BGP_AS_MAX ? BGP_AS_TRANS : as, cum_bw, + false, &lb_eval, disable_ieee_floating); + new = ecommunity_dup(ecom); + ecommunity_add_val(new, &lb_eval, true, true); + } return new; } diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 62e0430..929e4e6 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -10,6 +10,10 @@ #include "bgpd/bgp_rpki.h" #include "bgpd/bgpd.h" +#define ONE_GBPS_BYTES (1000 * 1000 * 1000 / 8) +#define ONE_MBPS_BYTES (1000 * 1000 / 8) +#define ONE_KBPS_BYTES (1000 / 8) + /* Refer to rfc7153 for the IANA registry definitions. These are * updated by other standards like rfc7674. */ @@ -52,10 +56,14 @@ * 0x0c Flow-spec Redirect to IPv4 - draft-ietf-idr-flowspec-redirect */ #define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4 0x0c -/* from draft-ietf-idr-flow-spec-v6-09 - * 0x0b Flow-spec Redirect to IPv6 +/* RFC 8956 */ +#define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6 0x0d + +/* https://datatracker.ietf.org/doc/html/draft-li-idr-link-bandwidth-ext-01 + * Sub-type is allocated by IANA, just the draft is not yet updated with the + * new value. */ -#define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6 0x0b +#define ECOMMUNITY_EXTENDED_LINK_BANDWIDTH 0x0006 /* Low-order octet of the Extended Communities type field for EVPN types */ #define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY 0x00 @@ -226,12 +234,13 @@ static uint32_t uint32_to_ieee_float_uint32(uint32_t u) * Encode BGP Link Bandwidth extended community * bandwidth (bw) is in bytes-per-sec */ -static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans, +static inline void encode_lb_extcomm(as_t as, uint64_t bw, bool non_trans, struct ecommunity_val *eval, bool disable_ieee_floating) { - uint32_t bandwidth = - disable_ieee_floating ? bw : uint32_to_ieee_float_uint32(bw); + uint64_t bandwidth = disable_ieee_floating + ? bw + : uint32_to_ieee_float_uint32(bw); memset(eval, 0, sizeof(*eval)); eval->val[0] = ECOMMUNITY_ENCODE_AS; @@ -246,6 +255,33 @@ static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans, eval->val[7] = bandwidth & 0xff; } +/* + * Encode BGP Link Bandwidth inside IPv6 Extended Community, + * bandwidth is in bytes per second. + */ +static inline void encode_lb_extended_extcomm(as_t as, uint64_t bandwidth, + bool non_trans, + struct ecommunity_val_ipv6 *eval) +{ + memset(eval, 0, sizeof(*eval)); + eval->val[0] = ECOMMUNITY_ENCODE_AS4; + if (non_trans) + eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE; + eval->val[1] = ECOMMUNITY_EXTENDED_LINK_BANDWIDTH; + eval->val[4] = (bandwidth >> 56) & 0xff; + eval->val[5] = (bandwidth >> 48) & 0xff; + eval->val[6] = (bandwidth >> 40) & 0xff; + eval->val[7] = (bandwidth >> 32) & 0xff; + eval->val[8] = (bandwidth >> 24) & 0xff; + eval->val[9] = (bandwidth >> 16) & 0xff; + eval->val[10] = (bandwidth >> 8) & 0xff; + eval->val[11] = bandwidth & 0xff; + eval->val[12] = (as >> 24) & 0xff; + eval->val[13] = (as >> 16) & 0xff; + eval->val[14] = (as >> 8) & 0xff; + eval->val[15] = as & 0xff; +} + static inline void encode_origin_validation_state(enum rpki_states state, struct ecommunity_val *eval) { @@ -327,8 +363,7 @@ extern void ecommunity_free(struct ecommunity **); extern struct ecommunity *ecommunity_parse(uint8_t *, unsigned short, bool disable_ieee_floating); extern struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt, - unsigned short length, - bool disable_ieee_floating); + unsigned short length); extern struct ecommunity *ecommunity_dup(struct ecommunity *); extern struct ecommunity *ecommunity_merge(struct ecommunity *, struct ecommunity *); @@ -346,7 +381,7 @@ extern void ecommunity_strfree(char **s); extern bool ecommunity_include(struct ecommunity *e1, struct ecommunity *e2); extern bool ecommunity_match(const struct ecommunity *, const struct ecommunity *); -extern char *ecommunity_str(struct ecommunity *ecom); +extern const char *ecommunity_str(struct ecommunity *ecom); extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *, uint8_t, uint8_t); @@ -387,11 +422,10 @@ extern void bgp_remove_ecomm_from_aggregate_hash( struct ecommunity *ecommunity); extern void bgp_aggr_ecommunity_remove(void *arg); extern const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, - uint32_t *bw); -extern struct ecommunity *ecommunity_replace_linkbw(as_t as, - struct ecommunity *ecom, - uint64_t cum_bw, - bool disable_ieee_floating); + uint64_t *bw); +extern struct ecommunity * +ecommunity_replace_linkbw(as_t as, struct ecommunity *ecom, uint64_t cum_bw, + bool disable_ieee_floating, bool extended); extern bool soo_in_ecom(struct ecommunity *ecom, struct ecommunity *soo); diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index a846484..e660ca5 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -892,11 +892,10 @@ struct bgp_dest *bgp_evpn_vni_node_lookup(const struct bgpevpn *vpn, /* * Add (update) or delete MACIP from zebra. */ -static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p, - const struct ethaddr *mac, - struct in_addr remote_vtep_ip, int add, - uint8_t flags, uint32_t seq, esi_t *esi) +static enum zclient_send_status bgp_zebra_send_remote_macip( + struct bgp *bgp, struct bgpevpn *vpn, const struct prefix_evpn *p, + const struct ethaddr *mac, struct in_addr remote_vtep_ip, int add, + uint8_t flags, uint32_t seq, esi_t *esi) { struct stream *s; uint16_t ipa_len; @@ -904,8 +903,12 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, bool esi_valid; /* Check socket. */ - if (!zclient || zclient->sock < 0) - return 0; + if (!zclient || zclient->sock < 0) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s: No zclient or zclient->sock exists", + __func__); + return ZCLIENT_SEND_SUCCESS; + } /* Don't try to register if Zebra doesn't know of this instance. */ if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) { @@ -913,7 +916,7 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, zlog_debug( "%s: No zebra instance to talk to, not installing remote macip", __func__); - return 0; + return ZCLIENT_SEND_SUCCESS; } if (!esi) @@ -979,24 +982,26 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, frrtrace(5, frr_bgp, evpn_mac_ip_zsend, add, vpn, p, remote_vtep_ip, esi); - if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE) - return -1; - - return 0; + return zclient_send_message(zclient); } /* * Add (update) or delete remote VTEP from zebra. */ -static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p, - int flood_control, int add) +static enum zclient_send_status +bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, + const struct prefix_evpn *p, int flood_control, + int add) { struct stream *s; /* Check socket. */ - if (!zclient || zclient->sock < 0) - return 0; + if (!zclient || zclient->sock < 0) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s: No zclient or zclient->sock exists", + __func__); + return ZCLIENT_SEND_SUCCESS; + } /* Don't try to register if Zebra doesn't know of this instance. */ if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) { @@ -1004,7 +1009,7 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, zlog_debug( "%s: No zebra instance to talk to, not installing remote vtep", __func__); - return 0; + return ZCLIENT_SEND_SUCCESS; } s = zclient->obuf; @@ -1021,7 +1026,7 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, EC_BGP_VTEP_INVALID, "Bad remote IP when trying to %s remote VTEP for VNI %u", add ? "ADD" : "DEL", (vpn ? vpn->vni : 0)); - return -1; + return ZCLIENT_SEND_FAILURE; } stream_putl(s, flood_control); @@ -1034,10 +1039,7 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, frrtrace(3, frr_bgp, evpn_bum_vtep_zsend, add, vpn, p); - if (zclient_send_message(zclient) == ZCLIENT_SEND_FAILURE) - return -1; - - return 0; + return zclient_send_message(zclient); } /* @@ -1263,14 +1265,14 @@ static void add_mac_mobility_to_attr(uint32_t seq_num, struct attr *attr) } /* Install EVPN route into zebra. */ -static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p, - struct bgp_path_info *pi) +enum zclient_send_status evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, + const struct prefix_evpn *p, + struct bgp_path_info *pi) { - int ret; uint8_t flags; int flood_control = VXLAN_FLOOD_DISABLED; uint32_t seq; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { flags = 0; @@ -1348,6 +1350,7 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, flood_control = VXLAN_FLOOD_DISABLED; break; } + ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, flood_control, 1); } @@ -1355,11 +1358,13 @@ static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn, } /* Uninstall EVPN route from zebra. */ -static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p, - struct bgp_path_info *pi, bool is_sync) +enum zclient_send_status evpn_zebra_uninstall(struct bgp *bgp, + struct bgpevpn *vpn, + const struct prefix_evpn *p, + struct bgp_path_info *pi, + bool is_sync) { - int ret; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) ret = bgp_zebra_send_remote_macip( @@ -1374,7 +1379,7 @@ static int evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn, ret = bgp_evpn_remote_es_evi_del(bgp, vpn, p); else ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, - VXLAN_FLOOD_DISABLED, 0); + VXLAN_FLOOD_DISABLED, 0); return ret; } @@ -1424,7 +1429,7 @@ static void evpn_delete_old_local_route(struct bgp *bgp, struct bgpevpn *vpn, * this table. */ if (pi) - bgp_process(bgp, global_dest, afi, safi); + bgp_process(bgp, global_dest, pi, afi, safi); bgp_dest_unlock_node(global_dest); } @@ -1438,14 +1443,29 @@ static void evpn_delete_old_local_route(struct bgp *bgp, struct bgpevpn *vpn, * Note: vpn is NULL for local EAD-ES routes. */ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, - struct bgp_dest *dest) + struct bgp_dest *dest, struct bgp_path_info *pi) { - struct bgp_path_info *old_select, *new_select; + struct bgp_path_info *old_select, *new_select, *first; struct bgp_path_info_pair old_and_new; afi_t afi = AFI_L2VPN; safi_t safi = SAFI_EVPN; int ret = 0; + first = bgp_dest_get_bgp_path_info(dest); + SET_FLAG(pi->flags, BGP_PATH_UNSORTED); + if (pi != first) { + if (pi->next) + pi->next->prev = pi->prev; + if (pi->prev) + pi->prev->next = pi->next; + + if (first) + first->prev = pi; + pi->next = first; + pi->prev = NULL; + bgp_dest_set_bgp_path_info(dest, pi); + } + /* Compute the best path. */ bgp_best_selection(bgp, dest, &bgp->maxpaths[afi][safi], &old_and_new, afi, safi); @@ -1465,12 +1485,19 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, && !CHECK_FLAG(dest->flags, BGP_NODE_USER_CLEAR) && !CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED) && !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) { - if (bgp_zebra_has_route_changed(old_select)) - ret = evpn_zebra_install( - bgp, vpn, - (const struct prefix_evpn *)bgp_dest_get_prefix( - dest), - old_select); + if (bgp_zebra_has_route_changed(old_select)) { + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) + ret = evpn_zebra_install(bgp, vpn, + (const struct prefix_evpn + *) + bgp_dest_get_prefix( + dest), + old_select); + else + bgp_zebra_route_install(dest, old_select, bgp, + true, vpn, false); + } + UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG); UNSET_FLAG(old_select->flags, BGP_PATH_LINK_BW_CHG); bgp_zebra_clear_route_change_flags(dest); @@ -1502,10 +1529,15 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, if (new_select && new_select->type == ZEBRA_ROUTE_BGP && (new_select->sub_type == BGP_ROUTE_IMPORTED || bgp_evpn_attr_is_sync(new_select->attr))) { - ret = evpn_zebra_install( - bgp, vpn, - (struct prefix_evpn *)bgp_dest_get_prefix(dest), - new_select); + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) + ret = evpn_zebra_install(bgp, vpn, + (const struct prefix_evpn *) + bgp_dest_get_prefix( + dest), + new_select); + else + bgp_zebra_route_install(dest, new_select, bgp, true, + vpn, false); /* If an old best existed and it was a "local" route, the only * reason @@ -1522,13 +1554,20 @@ int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, evpn_delete_old_local_route(bgp, vpn, dest, old_select, new_select); } else { - if (old_select && old_select->type == ZEBRA_ROUTE_BGP - && old_select->sub_type == BGP_ROUTE_IMPORTED) - ret = evpn_zebra_uninstall( - bgp, vpn, - (const struct prefix_evpn *)bgp_dest_get_prefix( - dest), - old_select, false); + if (old_select && old_select->type == ZEBRA_ROUTE_BGP && + old_select->sub_type == BGP_ROUTE_IMPORTED) { + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) || + CHECK_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN)) + ret = evpn_zebra_uninstall(bgp, vpn, + (const struct prefix_evpn + *) + bgp_dest_get_prefix( + dest), + old_select, false); + else + bgp_zebra_route_install(dest, old_select, bgp, + false, vpn, false); + } } /* Clear any route change flags. */ @@ -1561,11 +1600,12 @@ static struct bgp_path_info *bgp_evpn_route_get_local_path( static int update_evpn_type5_route_entry(struct bgp *bgp_evpn, struct bgp *bgp_vrf, afi_t afi, safi_t safi, struct bgp_dest *dest, - struct attr *attr, int *route_changed) + struct attr *attr, int *route_changed, + struct bgp_path_info **entry) { struct attr *attr_new = NULL; struct bgp_path_info *pi = NULL; - mpls_label_t label = MPLS_INVALID_LABEL; + struct bgp_labels bgp_labels = {}; struct bgp_path_info *local_pi = NULL; struct bgp_path_info *tmp_pi = NULL; @@ -1593,14 +1633,19 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn, /* Type-5 routes advertise the L3-VNI */ bgp_path_info_extra_get(pi); - vni2label(bgp_vrf->l3vni, &label); - memcpy(&pi->extra->label, &label, sizeof(label)); - pi->extra->num_labels = 1; + vni2label(bgp_vrf->l3vni, &bgp_labels.label[0]); + bgp_labels.num_labels = 1; + if (!bgp_path_info_labels_same(pi, &bgp_labels.label[0], + bgp_labels.num_labels)) { + bgp_labels_unintern(&pi->extra->labels); + pi->extra->labels = bgp_labels_intern(&bgp_labels); + } + /* add the route entry to route node*/ bgp_path_info_add(dest, pi); + *entry = pi; } else { - tmp_pi = local_pi; if (!attrhash_cmp(tmp_pi->attr, attr)) { @@ -1622,6 +1667,7 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn, tmp_pi->attr = attr_new; tmp_pi->uptime = monotime(NULL); } + *entry = local_pi; } return 0; } @@ -1637,6 +1683,7 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp, struct bgp_dest *dest = NULL; struct bgp *bgp_evpn = NULL; int route_changed = 0; + struct bgp_path_info *pi = NULL; bgp_evpn = bgp_get_evpn(); if (!bgp_evpn) @@ -1718,11 +1765,11 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp, /* create or update the route entry within the route node */ update_evpn_type5_route_entry(bgp_evpn, bgp_vrf, afi, safi, dest, &attr, - &route_changed); + &route_changed, &pi); /* schedule for processing and unlock node */ if (route_changed) { - bgp_process(bgp_evpn, dest, afi, safi); + bgp_process(bgp_evpn, dest, pi, afi, safi); bgp_dest_unlock_node(dest); } @@ -1891,15 +1938,13 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, struct bgp_path_info *local_pi; struct attr *attr_new; struct attr local_attr; - mpls_label_t label[BGP_MAX_LABELS]; - uint32_t num_labels = 1; + struct bgp_labels bgp_labels = {}; int route_change = 1; uint8_t sticky = 0; const struct prefix_evpn *evp; *pi = NULL; evp = (const struct prefix_evpn *)bgp_dest_get_prefix(dest); - memset(&label, 0, sizeof(label)); /* See if this is an update of an existing route, or a new add. */ local_pi = bgp_evpn_route_get_local_path(bgp, dest); @@ -1941,7 +1986,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, bgp_path_info_extra_get(tmp_pi); /* The VNI goes into the 'label' field of the route */ - vni2label(vpn->vni, &label[0]); + vni2label(vpn->vni, &bgp_labels.label[0]); + bgp_labels.num_labels = 1; /* Type-2 routes may carry a second VNI - the L3-VNI. * Only attach second label if we are advertising two labels for @@ -1953,13 +1999,16 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, l3vni = bgpevpn_get_l3vni(vpn); if (l3vni) { - vni2label(l3vni, &label[1]); - num_labels++; + vni2label(l3vni, &bgp_labels.label[1]); + bgp_labels.num_labels++; } } - memcpy(&tmp_pi->extra->label, label, sizeof(label)); - tmp_pi->extra->num_labels = num_labels; + if (!bgp_path_info_labels_same(tmp_pi, &bgp_labels.label[0], + bgp_labels.num_labels)) { + bgp_labels_unintern(&tmp_pi->extra->labels); + tmp_pi->extra->labels = bgp_labels_intern(&bgp_labels); + } if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { if (mac) @@ -1983,7 +2032,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, * The attributes have changed, type-2 routes needs to * be advertised with right labels. */ - vni2label(vpn->vni, &label[0]); + vni2label(vpn->vni, &bgp_labels.label[0]); + bgp_labels.num_labels = 1; if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE && CHECK_FLAG(vpn->flags, VNI_FLAG_USE_TWO_LABELS)) { @@ -1991,12 +2041,17 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, l3vni = bgpevpn_get_l3vni(vpn); if (l3vni) { - vni2label(l3vni, &label[1]); - num_labels++; + vni2label(l3vni, &bgp_labels.label[1]); + bgp_labels.num_labels++; } } - memcpy(&tmp_pi->extra->label, label, sizeof(label)); - tmp_pi->extra->num_labels = num_labels; + if (!bgp_path_info_labels_same(tmp_pi, + &bgp_labels.label[0], + bgp_labels.num_labels)) { + bgp_labels_unintern(&tmp_pi->extra->labels); + tmp_pi->extra->labels = + bgp_labels_intern(&bgp_labels); + } if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) { if (mac) @@ -2062,9 +2117,19 @@ static void evpn_zebra_reinstall_best_route(struct bgp *bgp, if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP && (curr_select->sub_type == BGP_ROUTE_IMPORTED || bgp_evpn_attr_is_sync(curr_select->attr))) - evpn_zebra_install(bgp, vpn, - (const struct prefix_evpn *)bgp_dest_get_prefix(dest), - curr_select); + if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP && + (curr_select->sub_type == BGP_ROUTE_IMPORTED || + bgp_evpn_attr_is_sync(curr_select->attr))) { + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) + evpn_zebra_install(bgp, vpn, + (const struct prefix_evpn *) + bgp_dest_get_prefix( + dest), + curr_select); + else + bgp_zebra_route_install(dest, curr_select, bgp, + true, vpn, false); + } } /* @@ -2222,7 +2287,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, * route would win, and we should evict the defunct local route * and (re)install the remote route into zebra. */ - evpn_route_select_install(bgp, vpn, dest); + evpn_route_select_install(bgp, vpn, dest, pi); /* * If the new local route was not selected evict it and tell zebra * to re-add the best remote dest. BGP doesn't retain non-best local @@ -2245,8 +2310,16 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, * has been removed. */ new_is_sync = bgp_evpn_attr_is_sync(pi->attr); - if (!new_is_sync && old_is_sync) - evpn_zebra_uninstall(bgp, vpn, p, pi, true); + if (!new_is_sync && old_is_sync) { + if (CHECK_FLAG(bgp->flags, + BGP_FLAG_DELETE_IN_PROGRESS)) + evpn_zebra_uninstall(bgp, vpn, p, pi, + true); + else + bgp_zebra_route_install(dest, pi, bgp, + false, vpn, + true); + } } } bgp_path_info_unlock(pi); @@ -2270,7 +2343,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, false /* setup_sync */, NULL /* old_is_sync */); /* Schedule for processing and unlock node. */ - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, global_pi, afi, safi); bgp_dest_unlock_node(dest); } @@ -2330,7 +2403,7 @@ static int delete_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp) delete_evpn_route_entry(bgp_evpn, afi, safi, dest, &pi); if (pi) - bgp_process(bgp_evpn, dest, afi, safi); + bgp_process(bgp_evpn, dest, pi, afi, safi); bgp_dest_unlock_node(dest); return 0; } @@ -2370,7 +2443,7 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, * this table. */ if (pi) - bgp_process(bgp, global_dest, afi, safi); + bgp_process(bgp, global_dest, pi, afi, safi); bgp_dest_unlock_node(global_dest); } @@ -2378,9 +2451,8 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, */ delete_evpn_route_entry(bgp, afi, safi, dest, &pi); if (pi) { - dest = bgp_path_info_reap(dest, pi); - assert(dest); - evpn_route_select_install(bgp, vpn, dest); + bgp_path_info_delete(dest, pi); + evpn_route_select_install(bgp, vpn, dest, pi); } /* dest should still exist due to locking make coverity happy */ @@ -2494,7 +2566,7 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, * advertised to peers; otherwise, ensure it is evicted and * (re)install the remote route into zebra. */ - evpn_route_select_install(bgp, vpn, dest); + evpn_route_select_install(bgp, vpn, dest, pi); if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) { route_change = 0; @@ -2512,8 +2584,17 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, * has been removed. */ new_is_sync = bgp_evpn_attr_is_sync(pi->attr); - if (!new_is_sync && old_is_sync) - evpn_zebra_uninstall(bgp, vpn, &evp, pi, true); + if (!new_is_sync && old_is_sync) { + if (CHECK_FLAG(bgp->flags, + BGP_FLAG_DELETE_IN_PROGRESS)) + (void)evpn_zebra_uninstall(bgp, vpn, + &evp, pi, + true); + else + bgp_zebra_route_install(dest, pi, bgp, + false, vpn, + true); + } } } @@ -2533,7 +2614,7 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, NULL /* old_is_sync */); /* Schedule for processing and unlock node. */ - bgp_process(bgp, global_dest, afi, safi); + bgp_process(bgp, global_dest, global_pi, afi, safi); bgp_dest_unlock_node(global_dest); } @@ -2618,7 +2699,7 @@ static void delete_global_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) delete_evpn_route_entry(bgp, afi, safi, dest, &pi); if (pi) - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, pi, afi, safi); } /* Unlock RD node. */ @@ -2795,7 +2876,22 @@ static int delete_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) delete_all_type2_routes(bgp, vpn); build_evpn_type3_prefix(&p, vpn->originator_ip); + + /* + * To handle the following scenario: + * - Say, the new zebra announce fifo list has few vni Evpn prefixes yet + * to be sent to zebra. + * - At this point if we have triggers like "no advertise-all-vni" or + * "networking restart", where a vni is going down. + * + * Perform the below + * 1) send withdraw routes to zebra immediately in case it is installed. + * 2) before we blow up the vni table, we need to walk the list and + * pop all the dest whose za_vpn points to this vni. + */ + SET_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN); ret = delete_evpn_route(bgp, vpn, &p); + UNSET_FLAG(bgp->flags, BGP_FLAG_VNI_DOWN); if (ret) return ret; @@ -2903,12 +2999,11 @@ bgp_create_evpn_bgp_path_info(struct bgp_path_info *parent_pi, sizeof(struct bgp_path_info_extra_vrfleak)); pi->extra->vrfleak->parent = bgp_path_info_lock(parent_pi); bgp_dest_lock_node((struct bgp_dest *)parent_pi->net); - if (parent_pi->extra) { - memcpy(&pi->extra->label, &parent_pi->extra->label, - sizeof(pi->extra->label)); - pi->extra->num_labels = parent_pi->extra->num_labels; + if (parent_pi->extra) pi->extra->igpmetric = parent_pi->extra->igpmetric; - } + + if (bgp_path_info_num_labels(parent_pi)) + pi->extra->labels = bgp_labels_intern(parent_pi->extra->labels); bgp_path_info_add(dest, pi); @@ -2945,6 +3040,9 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, vrf_id_to_name(bgp_vrf->vrf_id), evp, parent_pi, parent_pi->flags); + if (bgp_vrf->vrf_id == VRF_UNKNOWN) + return -1; + /* Create (or fetch) route within the VRF. */ /* NOTE: There is no RD here. */ if (is_evpn_prefix_ipaddr_v4(evp)) { @@ -3072,7 +3170,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, safi); /* Perform route selection and update zebra, if required. */ - bgp_process(bgp_vrf, dest, afi, safi); + bgp_process(bgp_vrf, dest, pi, afi, safi); /* Process for route leaking. */ vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi); @@ -3184,7 +3282,7 @@ static int install_evpn_route_entry_in_vni_common( bgp_evpn_remote_ip_hash_add(vpn, pi); /* Perform route selection and update zebra, if required. */ - ret = evpn_route_select_install(bgp, vpn, dest); + ret = evpn_route_select_install(bgp, vpn, dest, pi); /* if the best path is a local path with a non-zero ES * sync info against the local path may need to be updated @@ -3226,7 +3324,7 @@ static int uninstall_evpn_route_entry_in_vni_common( bgp_path_info_delete(dest, pi); /* Perform route selection and update zebra, if required. */ - ret = evpn_route_select_install(bgp, vpn, dest); + ret = evpn_route_select_install(bgp, vpn, dest, pi); /* if the best path is a local path with a non-zero ES * sync info against the local path may need to be updated @@ -3434,7 +3532,7 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, bgp_evpn_path_nh_del(bgp_vrf, pi); /* Perform route selection and update zebra, if required. */ - bgp_process(bgp_vrf, dest, afi, safi); + bgp_process(bgp_vrf, dest, pi, afi, safi); /* Unlock route node. */ bgp_dest_unlock_node(dest); @@ -3799,7 +3897,7 @@ int bgp_evpn_route_entry_install_if_vrf_match(struct bgp *bgp_vrf, * Install or uninstall mac-ip routes are appropriate for this * particular VRF. */ -static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install) +static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, bool install) { afi_t afi; safi_t safi; @@ -3863,9 +3961,7 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install) * particular VNI. */ static int install_uninstall_routes_for_vni(struct bgp *bgp, - struct bgpevpn *vpn, - bgp_evpn_route_type rtype, - int install) + struct bgpevpn *vpn, bool install) { afi_t afi; safi_t safi; @@ -3896,7 +3992,9 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp, (const struct prefix_evpn *)bgp_dest_get_prefix( dest); - if (evp->prefix.route_type != rtype) + if (evp->prefix.route_type != BGP_EVPN_IMET_ROUTE && + evp->prefix.route_type != BGP_EVPN_AD_ROUTE && + evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE) continue; for (pi = bgp_dest_get_bgp_path_info(dest); pi; @@ -3923,16 +4021,16 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp, bgp, vpn, evp, pi); if (ret) { - flog_err( - EC_BGP_EVPN_FAIL, - "%u: Failed to %s EVPN %s route in VNI %u", - bgp->vrf_id, - install ? "install" - : "uninstall", - rtype == BGP_EVPN_MAC_IP_ROUTE - ? "MACIP" - : "IMET", - vpn->vni); + flog_err(EC_BGP_EVPN_FAIL, + "%u: Failed to %s EVPN %s route in VNI %u", + bgp->vrf_id, + install ? "install" + : "uninstall", + evp->prefix.route_type == + BGP_EVPN_MAC_IP_ROUTE + ? "MACIP" + : "IMET", + vpn->vni); bgp_dest_unlock_node(rd_dest); bgp_dest_unlock_node(dest); @@ -3950,7 +4048,7 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp, */ static int install_routes_for_vrf(struct bgp *bgp_vrf) { - install_uninstall_routes_for_vrf(bgp_vrf, 1); + install_uninstall_routes_for_vrf(bgp_vrf, true); return 0; } @@ -3961,29 +4059,17 @@ static int install_routes_for_vrf(struct bgp *bgp_vrf) */ static int install_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) { - int ret; - - /* Install type-3 routes followed by type-2 routes - the ones applicable + /* + * Install type-3 routes followed by type-2 routes - the ones applicable * for this VNI. */ - ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_IMET_ROUTE, - 1); - if (ret) - return ret; - - ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_AD_ROUTE, - 1); - if (ret) - return ret; - - return install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_MAC_IP_ROUTE, - 1); + return install_uninstall_routes_for_vni(bgp, vpn, true); } /* uninstall routes from l3vni vrf. */ static int uninstall_routes_for_vrf(struct bgp *bgp_vrf) { - install_uninstall_routes_for_vrf(bgp_vrf, 0); + install_uninstall_routes_for_vrf(bgp_vrf, false); return 0; } @@ -3993,25 +4079,11 @@ static int uninstall_routes_for_vrf(struct bgp *bgp_vrf) */ static int uninstall_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn) { - int ret; - - /* Uninstall type-2 routes followed by type-3 routes - the ones - * applicable - * for this VNI. + /* + * Uninstall type-2 routes followed by type-3 routes - the ones + * applicable for this VNI. */ - ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_MAC_IP_ROUTE, - 0); - if (ret) - return ret; - - ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_AD_ROUTE, - 0); - if (ret) - return ret; - - - return install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_IMET_ROUTE, - 0); + return install_uninstall_routes_for_vni(bgp, vpn, false); } /* @@ -4431,7 +4503,7 @@ static void update_advertise_vni_route(struct bgp *bgp, struct bgpevpn *vpn, } /* Schedule for processing and unlock node. */ - bgp_process(bgp, global_dest, afi, safi); + bgp_process(bgp, global_dest, global_pi, afi, safi); bgp_dest_unlock_node(global_dest); } @@ -4481,7 +4553,7 @@ static void update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) false /* setup_sync */, NULL /* old_is_sync */); /* Schedule for processing and unlock node. */ - bgp_process(bgp, global_dest, afi, safi); + bgp_process(bgp, global_dest, pi, afi, safi); bgp_dest_unlock_node(global_dest); } @@ -4526,7 +4598,7 @@ static int delete_withdraw_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) * this table. */ if (pi) - bgp_process(bgp, global_dest, afi, safi); + bgp_process(bgp, global_dest, pi, afi, safi); bgp_dest_unlock_node(global_dest); } @@ -4622,7 +4694,7 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, uint8_t macaddr_len; /* holds the VNI(s) as in packet */ mpls_label_t label[BGP_MAX_LABELS] = {}; - uint32_t num_labels = 0; + uint8_t num_labels = 0; uint32_t eth_tag; int ret = 0; @@ -4965,7 +5037,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p, const struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, struct attr *attr) { int len; @@ -5755,7 +5827,7 @@ int bgp_evpn_uninstall_routes(struct bgp *bgp, struct bgpevpn *vpn) /* * TODO: Hardcoded for a maximum of 2 VNIs right now */ -char *bgp_evpn_label2str(mpls_label_t *label, uint32_t num_labels, char *buf, +char *bgp_evpn_label2str(mpls_label_t *label, uint8_t num_labels, char *buf, int len) { vni_t vni1, vni2; @@ -5839,7 +5911,7 @@ void bgp_evpn_route2json(const struct prefix_evpn *p, json_object *json) */ void bgp_evpn_encode_prefix(struct stream *s, const struct prefix *p, const struct prefix_rd *prd, mpls_label_t *label, - uint32_t num_labels, struct attr *attr, + uint8_t num_labels, struct attr *attr, bool addpath_capable, uint32_t addpath_tx_id) { struct prefix_evpn *evp = (struct prefix_evpn *)p; @@ -6262,6 +6334,19 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni, */ void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn) { + struct bgp_dest *dest = NULL; + struct bgp_dest *dest_next = NULL; + + for (dest = zebra_announce_first(&bm->zebra_announce_head); dest; + dest = dest_next) { + dest_next = zebra_announce_next(&bm->zebra_announce_head, dest); + if (dest->za_vpn == vpn) { + zebra_announce_del(&bm->zebra_announce_head, dest); + bgp_path_info_unlock(dest->za_bgp_pi); + bgp_dest_unlock_node(dest); + } + } + bgp_evpn_remote_ip_hash_destroy(vpn); bgp_evpn_vni_es_cleanup(vpn); bgpevpn_unlink_from_l3vni(vpn); @@ -6425,9 +6510,10 @@ void bgp_filter_evpn_routes_upon_martian_change( for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { + struct bgp_path_info *next; - for (pi = bgp_dest_get_bgp_path_info(dest); pi; - pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); + (pi != NULL) && (next = pi->next, 1); pi = next) { bool affected = false; const struct prefix *p; @@ -6904,6 +6990,17 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id) } /* + * When bgp instance goes down also clean up what might have been left over + * from evpn. + */ +void bgp_evpn_instance_down(struct bgp *bgp) +{ + /* If we have a stale local vni, delete it */ + if (bgp->l3vni) + bgp_evpn_local_l3vni_del(bgp->l3vni, bgp->vrf_id); +} + +/* * Handle del of a local VNI. */ int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni) @@ -7669,7 +7766,7 @@ void bgp_evpn_handle_resolve_overlay_index_unset(struct hash_bucket *bucket, * */ mpls_label_t *bgp_evpn_path_info_labels_get_l3vni(mpls_label_t *labels, - uint32_t num_labels) + uint8_t num_labels) { if (!labels) return NULL; @@ -7688,8 +7785,10 @@ vni_t bgp_evpn_path_info_get_l3vni(const struct bgp_path_info *pi) if (!pi->extra) return 0; - return label2vni(bgp_evpn_path_info_labels_get_l3vni( - pi->extra->label, pi->extra->num_labels)); + return label2vni( + bgp_evpn_path_info_labels_get_l3vni(pi->extra->labels->label, + pi->extra->labels + ->num_labels)); } /* diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index c641a64..dc82bcf 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -115,12 +115,12 @@ extern void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi); extern void bgp_evpn_vrf_delete(struct bgp *bgp_vrf); extern void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw); -extern char *bgp_evpn_label2str(mpls_label_t *label, uint32_t num_labels, +extern char *bgp_evpn_label2str(mpls_label_t *label, uint8_t num_labels, char *buf, int len); extern void bgp_evpn_route2json(const struct prefix_evpn *p, json_object *json); extern void bgp_evpn_encode_prefix(struct stream *s, const struct prefix *p, const struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, struct attr *attr, bool addpath_capable, uint32_t addpath_tx_id); extern int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr, @@ -153,6 +153,7 @@ extern int bgp_evpn_local_l3vni_add(vni_t vni, vrf_id_t vrf_id, struct in_addr originator_ip, int filter, ifindex_t svi_ifindex, bool is_anycast_mac); extern int bgp_evpn_local_l3vni_del(vni_t vni, vrf_id_t vrf_id); +extern void bgp_evpn_instance_down(struct bgp *bgp); extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni); extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, struct in_addr originator_ip, @@ -177,7 +178,7 @@ extern void bgp_evpn_handle_resolve_overlay_index_unset(struct hash_bucket *bucket, void *arg); extern mpls_label_t *bgp_evpn_path_info_labels_get_l3vni(mpls_label_t *labels, - uint32_t num_labels); + uint8_t num_labels); extern vni_t bgp_evpn_path_info_get_l3vni(const struct bgp_path_info *pi); extern bool bgp_evpn_mpath_has_dvni(const struct bgp *bgp_vrf, struct bgp_path_info *mpinfo); @@ -186,4 +187,12 @@ extern bool is_route_injectable_into_evpn_non_supp(struct bgp_path_info *pi); extern void bgp_aggr_supp_withdraw_from_evpn(struct bgp *bgp, afi_t afi, safi_t safi); +extern enum zclient_send_status evpn_zebra_install(struct bgp *bgp, + struct bgpevpn *vpn, + const struct prefix_evpn *p, + struct bgp_path_info *pi); +extern enum zclient_send_status +evpn_zebra_uninstall(struct bgp *bgp, struct bgpevpn *vpn, + const struct prefix_evpn *p, struct bgp_path_info *pi, + bool is_sync); #endif /* _QUAGGA_BGP_EVPN_H */ diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index d88c52d..d723a2b 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -45,13 +45,14 @@ static void bgp_evpn_local_es_down(struct bgp *bgp, struct bgp_evpn_es *es); static void bgp_evpn_local_type1_evi_route_del(struct bgp *bgp, struct bgp_evpn_es *es); -static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp, +static struct bgp_evpn_es_vtep * +bgp_evpn_es_vtep_add(struct bgp *bgp, struct bgp_evpn_es *es, + struct in_addr vtep_ip, bool esr, uint8_t df_alg, + uint16_t df_pref, int *zret); +static enum zclient_send_status bgp_evpn_es_vtep_del(struct bgp *bgp, struct bgp_evpn_es *es, struct in_addr vtep_ip, - bool esr, uint8_t df_alg, - uint16_t df_pref); -static void bgp_evpn_es_vtep_del(struct bgp *bgp, - struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr); + bool esr); static void bgp_evpn_es_cons_checks_pend_add(struct bgp_evpn_es *es); static void bgp_evpn_es_cons_checks_pend_del(struct bgp_evpn_es *es); static struct bgp_evpn_es_evi * @@ -91,15 +92,19 @@ static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info *nh_info); */ static int bgp_evpn_es_route_select_install(struct bgp *bgp, struct bgp_evpn_es *es, - struct bgp_dest *dest) + struct bgp_dest *dest, + struct bgp_path_info *pi) { int ret = 0; + int zret = 0; afi_t afi = AFI_L2VPN; safi_t safi = SAFI_EVPN; struct bgp_path_info *old_select; /* old best */ struct bgp_path_info *new_select; /* new best */ struct bgp_path_info_pair old_and_new; + SET_FLAG(pi->flags, BGP_PATH_UNSORTED); + /* Compute the best path. */ bgp_best_selection(bgp, dest, &bgp->maxpaths[afi][safi], &old_and_new, afi, safi); @@ -120,7 +125,7 @@ static int bgp_evpn_es_route_select_install(struct bgp *bgp, bgp_evpn_es_vtep_add(bgp, es, old_select->attr->nexthop, true /*esr*/, old_select->attr->df_alg, - old_select->attr->df_pref); + old_select->attr->df_pref, &zret); } UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG); bgp_zebra_clear_route_change_flags(dest); @@ -149,7 +154,7 @@ static int bgp_evpn_es_route_select_install(struct bgp *bgp, && new_select->sub_type == BGP_ROUTE_IMPORTED) { bgp_evpn_es_vtep_add(bgp, es, new_select->attr->nexthop, true /*esr */, new_select->attr->df_alg, - new_select->attr->df_pref); + new_select->attr->df_pref, &zret); } else { if (old_select && old_select->type == ZEBRA_ROUTE_BGP && old_select->sub_type == BGP_ROUTE_IMPORTED) @@ -231,7 +236,7 @@ static int bgp_evpn_es_route_install(struct bgp *bgp, } /* Perform route selection and update zebra, if required. */ - ret = bgp_evpn_es_route_select_install(bgp, es, dest); + ret = bgp_evpn_es_route_select_install(bgp, es, dest, pi); bgp_dest_unlock_node(dest); @@ -272,7 +277,7 @@ static int bgp_evpn_es_route_uninstall(struct bgp *bgp, struct bgp_evpn_es *es, bgp_path_info_delete(dest, pi); /* Perform route selection and update zebra, if required. */ - ret = bgp_evpn_es_route_select_install(bgp, es, dest); + ret = bgp_evpn_es_route_select_install(bgp, es, dest, pi); /* Unlock route node. */ bgp_dest_unlock_node(dest); @@ -353,6 +358,7 @@ int bgp_evpn_mh_route_update(struct bgp *bgp, struct bgp_evpn_es *es, struct bgp_path_info *tmp_pi = NULL; struct bgp_path_info *local_pi = NULL; /* local route entry if any */ struct bgp_path_info *remote_pi = NULL; /* remote route entry if any */ + struct bgp_labels bgp_labels = {}; struct attr *attr_new = NULL; struct prefix_evpn *evp; @@ -399,11 +405,16 @@ int bgp_evpn_mh_route_update(struct bgp *bgp, struct bgp_evpn_es *es, if (evp->prefix.route_type == BGP_EVPN_AD_ROUTE) { bgp_path_info_extra_get(tmp_pi); - tmp_pi->extra->num_labels = 1; + bgp_labels.num_labels = 1; if (vpn) - vni2label(vpn->vni, &tmp_pi->extra->label[0]); - else - tmp_pi->extra->label[0] = 0; + vni2label(vpn->vni, &bgp_labels.label[0]); + if (!bgp_path_info_labels_same(tmp_pi, + &bgp_labels.label[0], + bgp_labels.num_labels)) { + bgp_labels_unintern(&tmp_pi->extra->labels); + tmp_pi->extra->labels = + bgp_labels_intern(&bgp_labels); + } } /* add the newly created path to the route-node */ @@ -447,7 +458,7 @@ int bgp_evpn_mh_route_update(struct bgp *bgp, struct bgp_evpn_es *es, attr->mp_nexthop_global_in); } - /* Return back the route entry. */ + /* Return back th*e route entry. */ *ri = tmp_pi; return 0; } @@ -511,7 +522,7 @@ static int bgp_evpn_mh_route_delete(struct bgp *bgp, struct bgp_evpn_es *es, * this table. */ if (pi) - bgp_process(bgp, global_dest, afi, safi); + bgp_process(bgp, global_dest, pi, afi, safi); bgp_dest_unlock_node(global_dest); } @@ -562,7 +573,7 @@ int delete_global_ead_evi_routes(struct bgp *bgp, struct bgpevpn *vpn) delete_evpn_route_entry(bgp, afi, safi, bd, &pi); if (pi) - bgp_process(bgp, bd, afi, safi); + bgp_process(bgp, bd, pi, afi, safi); } } @@ -668,7 +679,7 @@ static int bgp_evpn_type4_route_update(struct bgp *bgp, * this is just to set the flags correctly * as local route in the ES always wins. */ - bgp_evpn_es_route_select_install(bgp, es, dest); + bgp_evpn_es_route_select_install(bgp, es, dest, pi); bgp_dest_unlock_node(dest); /* If this is a new route or some attribute has changed, export the @@ -686,7 +697,7 @@ static int bgp_evpn_type4_route_update(struct bgp *bgp, attr_new, &global_pi, &route_changed); /* Schedule for processing and unlock node. */ - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, global_pi, afi, safi); bgp_dest_unlock_node(dest); } @@ -1008,7 +1019,7 @@ static int bgp_evpn_type1_route_update(struct bgp *bgp, struct bgp_evpn_es *es, * this is just to set the flags correctly as local route in * the ES always wins. */ - evpn_route_select_install(bgp, vpn, dest); + evpn_route_select_install(bgp, vpn, dest, pi); bgp_dest_unlock_node(dest); /* If this is a new route or some attribute has changed, export the @@ -1025,7 +1036,7 @@ static int bgp_evpn_type1_route_update(struct bgp *bgp, struct bgp_evpn_es *es, attr_new, &global_pi, &route_changed); /* Schedule for processing and unlock node. */ - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, global_pi, afi, safi); bgp_dest_unlock_node(dest); } @@ -1371,23 +1382,28 @@ static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_find(struct bgp_evpn_es *es, } /* Send the remote ES to zebra for NHG programming */ -static int bgp_zebra_send_remote_es_vtep(struct bgp *bgp, - struct bgp_evpn_es_vtep *es_vtep, bool add) +static enum zclient_send_status +bgp_zebra_send_remote_es_vtep(struct bgp *bgp, struct bgp_evpn_es_vtep *es_vtep, + bool add) { struct bgp_evpn_es *es = es_vtep->es; struct stream *s; uint32_t flags = 0; /* Check socket. */ - if (!zclient || zclient->sock < 0) - return 0; + if (!zclient || zclient->sock < 0) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s: No zclient or zclient->sock exists", + __func__); + return ZCLIENT_SEND_SUCCESS; + } /* Don't try to register if Zebra doesn't know of this instance. */ if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) { if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("No zebra instance, not installing remote es %s", es->esi_str); - return 0; + return ZCLIENT_SEND_SUCCESS; } if (es_vtep->flags & BGP_EVPNES_VTEP_ESR) @@ -1418,12 +1434,12 @@ static int bgp_zebra_send_remote_es_vtep(struct bgp *bgp, return zclient_send_message(zclient); } -static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp, - struct bgp_evpn_es_vtep *es_vtep, - bool param_change) +static enum zclient_send_status bgp_evpn_es_vtep_re_eval_active( + struct bgp *bgp, struct bgp_evpn_es_vtep *es_vtep, bool param_change) { bool old_active; bool new_active; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; old_active = CHECK_FLAG(es_vtep->flags, BGP_EVPNES_VTEP_ACTIVE); /* currently we need an active EVI reference to use the VTEP as @@ -1445,7 +1461,7 @@ static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp, es_vtep->df_alg, es_vtep->df_pref); /* send remote ES to zebra */ - bgp_zebra_send_remote_es_vtep(bgp, es_vtep, new_active); + ret = bgp_zebra_send_remote_es_vtep(bgp, es_vtep, new_active); /* The NHG is updated first for efficient failover handling. * Note the NHG can be de-activated while there are bgp @@ -1457,13 +1473,14 @@ static void bgp_evpn_es_vtep_re_eval_active(struct bgp *bgp, /* queue up the es for background consistency checks */ bgp_evpn_es_cons_checks_pend_add(es_vtep->es); } + + return ret; } -static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp, - struct bgp_evpn_es *es, - struct in_addr vtep_ip, - bool esr, uint8_t df_alg, - uint16_t df_pref) +static struct bgp_evpn_es_vtep * +bgp_evpn_es_vtep_add(struct bgp *bgp, struct bgp_evpn_es *es, + struct in_addr vtep_ip, bool esr, uint8_t df_alg, + uint16_t df_pref, int *zret) { struct bgp_evpn_es_vtep *es_vtep; bool param_change = false; @@ -1490,15 +1507,17 @@ static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_add(struct bgp *bgp, ++es_vtep->evi_cnt; } - bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change); + *zret = bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change); return es_vtep; } -static void bgp_evpn_es_vtep_do_del(struct bgp *bgp, - struct bgp_evpn_es_vtep *es_vtep, bool esr) +static enum zclient_send_status +bgp_evpn_es_vtep_do_del(struct bgp *bgp, struct bgp_evpn_es_vtep *es_vtep, + bool esr) { bool param_change = false; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug("es %s vtep %pI4 del %s", es_vtep->es->esi_str, @@ -1515,18 +1534,25 @@ static void bgp_evpn_es_vtep_do_del(struct bgp *bgp, --es_vtep->evi_cnt; } - bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change); + ret = bgp_evpn_es_vtep_re_eval_active(bgp, es_vtep, param_change); bgp_evpn_es_vtep_free(es_vtep); + + return ret; } -static void bgp_evpn_es_vtep_del(struct bgp *bgp, - struct bgp_evpn_es *es, struct in_addr vtep_ip, bool esr) +static enum zclient_send_status bgp_evpn_es_vtep_del(struct bgp *bgp, + struct bgp_evpn_es *es, + struct in_addr vtep_ip, + bool esr) { struct bgp_evpn_es_vtep *es_vtep; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; es_vtep = bgp_evpn_es_vtep_find(es, vtep_ip); if (es_vtep) - bgp_evpn_es_vtep_do_del(bgp, es_vtep, esr); + ret = bgp_evpn_es_vtep_do_del(bgp, es_vtep, esr); + + return ret; } /********************** ES MAC-IP paths ************************************* @@ -2435,7 +2461,7 @@ static void bgp_evpn_es_frag_show_detail(struct vty *vty, } static char *bgp_evpn_es_vteps_str(char *vtep_str, struct bgp_evpn_es *es, - uint8_t vtep_str_size) + size_t vtep_str_size) { char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ]; struct listnode *node; @@ -3399,12 +3425,14 @@ static struct bgp_evpn_es_evi_vtep *bgp_evpn_es_evi_vtep_find( /* A VTEP can be added as "active" attach to an ES if EAD-per-ES and * EAD-per-EVI routes are rxed from it. */ -static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp, - struct bgp_evpn_es_evi_vtep *evi_vtep) +static enum zclient_send_status +bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp, + struct bgp_evpn_es_evi_vtep *evi_vtep) { bool old_active; bool new_active; uint32_t ead_activity_flags; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; old_active = CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE); @@ -3425,7 +3453,7 @@ static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp, new_active = CHECK_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_ACTIVE); if (old_active == new_active) - return; + return ret; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug("es %s evi %u vtep %pI4 %s", @@ -3434,24 +3462,27 @@ static void bgp_evpn_es_evi_vtep_re_eval_active(struct bgp *bgp, new_active ? "active" : "inactive"); /* add VTEP to parent es */ - if (new_active) - evi_vtep->es_vtep = bgp_evpn_es_vtep_add( - bgp, evi_vtep->es_evi->es, evi_vtep->vtep_ip, - false /*esr*/, 0, 0); - else { + if (new_active) { + evi_vtep->es_vtep = + bgp_evpn_es_vtep_add(bgp, evi_vtep->es_evi->es, + evi_vtep->vtep_ip, false /*esr*/, + 0, 0, &ret); + } else { if (evi_vtep->es_vtep) { - bgp_evpn_es_vtep_do_del(bgp, evi_vtep->es_vtep, - false /*esr*/); + ret = bgp_evpn_es_vtep_do_del(bgp, evi_vtep->es_vtep, + false /*esr*/); evi_vtep->es_vtep = NULL; } } /* queue up the parent es for background consistency checks */ bgp_evpn_es_cons_checks_pend_add(evi_vtep->es_evi->es); + + return ret; } -static void bgp_evpn_es_evi_vtep_add(struct bgp *bgp, - struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip, - bool ead_es) +static enum zclient_send_status +bgp_evpn_es_evi_vtep_add(struct bgp *bgp, struct bgp_evpn_es_evi *es_evi, + struct in_addr vtep_ip, bool ead_es) { struct bgp_evpn_es_evi_vtep *evi_vtep; @@ -3475,18 +3506,19 @@ static void bgp_evpn_es_evi_vtep_add(struct bgp *bgp, else SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI); - bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep); + return bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep); } -static void bgp_evpn_es_evi_vtep_del(struct bgp *bgp, - struct bgp_evpn_es_evi *es_evi, struct in_addr vtep_ip, - bool ead_es) +static enum zclient_send_status +bgp_evpn_es_evi_vtep_del(struct bgp *bgp, struct bgp_evpn_es_evi *es_evi, + struct in_addr vtep_ip, bool ead_es) { struct bgp_evpn_es_evi_vtep *evi_vtep; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; evi_vtep = bgp_evpn_es_evi_vtep_find(es_evi, vtep_ip); if (!evi_vtep) - return; + return ret; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug("del es %s evi %u vtep %pI4 %s", @@ -3503,8 +3535,10 @@ static void bgp_evpn_es_evi_vtep_del(struct bgp *bgp, else UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_EVI); - bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep); + ret = bgp_evpn_es_evi_vtep_re_eval_active(bgp, evi_vtep); bgp_evpn_es_evi_vtep_free(evi_vtep); + + return ret; } /* compare ES-IDs for the ES-EVI RB tree maintained per-VNI */ @@ -3780,18 +3814,20 @@ int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni) /* Add remote ES-EVI entry. This is actually the remote VTEP add and the * ES-EVI is implicity created on first VTEP's reference. */ -int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p) +enum zclient_send_status bgp_evpn_remote_es_evi_add(struct bgp *bgp, + struct bgpevpn *vpn, + const struct prefix_evpn *p) { char buf[ESI_STR_LEN]; struct bgp_evpn_es *es; struct bgp_evpn_es_evi *es_evi; bool ead_es; const esi_t *esi = &p->prefix.ead_addr.esi; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; if (!vpn) /* local EAD-ES need not be sent back to zebra */ - return 0; + return ret; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug("add remote %s es %s evi %u vtep %pI4", @@ -3808,27 +3844,29 @@ int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn, es_evi = bgp_evpn_es_evi_new(es, vpn); ead_es = !!p->prefix.ead_addr.eth_tag; - bgp_evpn_es_evi_vtep_add(bgp, es_evi, p->prefix.ead_addr.ip.ipaddr_v4, - ead_es); + ret = bgp_evpn_es_evi_vtep_add(bgp, es_evi, + p->prefix.ead_addr.ip.ipaddr_v4, ead_es); bgp_evpn_es_evi_remote_info_re_eval(es_evi); - return 0; + return ret; } /* A remote VTEP has withdrawn. The es-evi-vtep will be deleted and the * parent es-evi freed up implicitly in last VTEP's deref. */ -int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p) +enum zclient_send_status bgp_evpn_remote_es_evi_del(struct bgp *bgp, + struct bgpevpn *vpn, + const struct prefix_evpn *p) { char buf[ESI_STR_LEN]; struct bgp_evpn_es *es; struct bgp_evpn_es_evi *es_evi; bool ead_es; + enum zclient_send_status ret = ZCLIENT_SEND_SUCCESS; if (!vpn) /* local EAD-ES need not be sent back to zebra */ - return 0; + return ret; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug( @@ -3847,7 +3885,7 @@ int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn, esi_to_str(&p->prefix.ead_addr.esi, buf, sizeof(buf)), vpn->vni, &p->prefix.ead_addr.ip.ipaddr_v4); - return 0; + return ret; } es_evi = bgp_evpn_es_evi_find(es, vpn); if (!es_evi) { @@ -3860,14 +3898,15 @@ int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn, sizeof(buf)), vpn->vni, &p->prefix.ead_addr.ip.ipaddr_v4); - return 0; + return ret; } ead_es = !!p->prefix.ead_addr.eth_tag; - bgp_evpn_es_evi_vtep_del(bgp, es_evi, p->prefix.ead_addr.ip.ipaddr_v4, - ead_es); + ret = bgp_evpn_es_evi_vtep_del(bgp, es_evi, + p->prefix.ead_addr.ip.ipaddr_v4, ead_es); bgp_evpn_es_evi_remote_info_re_eval(es_evi); - return 0; + + return ret; } /* If a VNI is being deleted we need to force del all remote VTEPs */ @@ -3923,7 +3962,7 @@ void bgp_evpn_vni_es_cleanup(struct bgpevpn *vpn) static char *bgp_evpn_es_evi_vteps_str(char *vtep_str, struct bgp_evpn_es_evi *es_evi, - uint8_t vtep_str_size) + size_t vtep_str_size) { char vtep_flag_str[BGP_EVPN_FLAG_STR_SZ]; struct listnode *node; diff --git a/bgpd/bgp_evpn_mh.h b/bgpd/bgp_evpn_mh.h index cebabb9..5d393c3 100644 --- a/bgpd/bgp_evpn_mh.h +++ b/bgpd/bgp_evpn_mh.h @@ -418,10 +418,12 @@ extern int bgp_evpn_local_es_add(struct bgp *bgp, esi_t *esi, extern int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi); extern int bgp_evpn_local_es_evi_add(struct bgp *bgp, esi_t *esi, vni_t vni); extern int bgp_evpn_local_es_evi_del(struct bgp *bgp, esi_t *esi, vni_t vni); -extern int bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p); -extern int bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn, - const struct prefix_evpn *p); +extern enum zclient_send_status +bgp_evpn_remote_es_evi_add(struct bgp *bgp, struct bgpevpn *vpn, + const struct prefix_evpn *p); +extern enum zclient_send_status +bgp_evpn_remote_es_evi_del(struct bgp *bgp, struct bgpevpn *vpn, + const struct prefix_evpn *p); extern void bgp_evpn_mh_init(void); extern void bgp_evpn_mh_finish(void); void bgp_evpn_vni_es_init(struct bgpevpn *vpn); diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 5af99af..07bba9b 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -716,7 +716,8 @@ extern void delete_evpn_route_entry(struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_path_info **pi); int vni_list_cmp(void *p1, void *p2); extern int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, - struct bgp_dest *dest); + struct bgp_dest *dest, + struct bgp_path_info *pi); extern struct bgp_dest * bgp_evpn_global_node_get(struct bgp_table *table, afi_t afi, safi_t safi, const struct prefix_evpn *evp, struct prefix_rd *prd, diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index a851179..002f054 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -16,7 +16,7 @@ #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_regex.h" -/* List of AS filter list. */ +/* List of AS list. */ struct as_list_list { struct as_list *head; struct as_list *tail; @@ -205,14 +205,6 @@ static struct as_list *as_list_new(void) static void as_list_free(struct as_list *aslist) { - struct aspath_exclude_list *cur_bp = aslist->exclude_list; - struct aspath_exclude_list *next_bp = NULL; - - while (cur_bp) { - next_bp = cur_bp->next; - XFREE(MTYPE_ROUTE_MAP_COMPILED, cur_bp); - cur_bp = next_bp; - } XFREE (MTYPE_AS_STR, aslist->name); XFREE (MTYPE_AS_LIST, aslist); @@ -299,7 +291,6 @@ static void as_list_delete(struct as_list *aslist) { struct as_list_list *list; struct as_filter *filter, *next; - struct aspath_exclude_list *cur_bp; for (filter = aslist->head; filter; filter = next) { next = filter->next; @@ -318,12 +309,6 @@ static void as_list_delete(struct as_list *aslist) else list->head = aslist->next; - cur_bp = aslist->exclude_list; - while (cur_bp) { - cur_bp->bp_as_excl->exclude_aspath_acl = NULL; - cur_bp = cur_bp->next; - } - as_list_free(aslist); } @@ -431,6 +416,7 @@ DEFUN(as_path, bgp_as_path_cmd, enum as_filter_type type; struct as_filter *asfilter; struct as_list *aslist; + struct aspath_exclude *ase; regex_t *regex; char *regstr; int64_t seqnum = ASPATH_SEQ_NUMBER_AUTO; @@ -482,6 +468,22 @@ DEFUN(as_path, bgp_as_path_cmd, else as_list_filter_add(aslist, asfilter); + /* init the exclude rule list*/ + as_list_list_init(&aslist->exclude_rule); + + /* get aspath orphan exclude that are using this acl */ + ase = as_exclude_lookup_orphan(alname); + if (ase) { + as_list_list_add_head(&aslist->exclude_rule, ase); + /* set reverse pointer */ + ase->exclude_aspath_acl = aslist; + /* set list of aspath excludes using that acl */ + while ((ase = as_exclude_lookup_orphan(alname))) { + as_list_list_add_head(&aslist->exclude_rule, ase); + ase->exclude_aspath_acl = aslist; + } + } + return CMD_SUCCESS; } @@ -502,6 +504,7 @@ DEFUN(no_as_path, no_bgp_as_path_cmd, enum as_filter_type type; struct as_filter *asfilter; struct as_list *aslist; + struct aspath_exclude *ase; char *regstr; regex_t *regex; @@ -556,6 +559,12 @@ DEFUN(no_as_path, no_bgp_as_path_cmd, XFREE(MTYPE_TMP, regstr); + /* put aspath exclude list into orphan */ + if (as_list_list_count(&aslist->exclude_rule)) + while ((ase = as_list_list_pop(&aslist->exclude_rule))) + as_exclude_set_orphan(ase); + + as_list_list_fini(&aslist->exclude_rule); as_list_filter_delete(aslist, asfilter); return CMD_SUCCESS; diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h index 2d9f07c..77a3f3c 100644 --- a/bgpd/bgp_filter.h +++ b/bgpd/bgp_filter.h @@ -6,11 +6,12 @@ #ifndef _QUAGGA_BGP_FILTER_H #define _QUAGGA_BGP_FILTER_H +#include <typesafe.h> + #define ASPATH_SEQ_NUMBER_AUTO -1 enum as_filter_type { AS_FILTER_DENY, AS_FILTER_PERMIT }; - /* Element of AS path filter. */ struct as_filter { struct as_filter *next; @@ -25,11 +26,7 @@ struct as_filter { int64_t seq; }; -struct aspath_exclude_list { - struct aspath_exclude_list *next; - struct aspath_exclude *bp_as_excl; -}; - +PREDECL_DLIST(as_list_list); /* AS path filter list. */ struct as_list { char *name; @@ -39,7 +36,9 @@ struct as_list { struct as_filter *head; struct as_filter *tail; - struct aspath_exclude_list *exclude_list; + + /* Changes in AS path */ + struct as_list_list_head exclude_rule; }; diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 5043439..d41ef8a 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -260,6 +260,8 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) peer->afc_recv[afi][safi] = from_peer->afc_recv[afi][safi]; peer->orf_plist[afi][safi] = from_peer->orf_plist[afi][safi]; peer->llgr[afi][safi] = from_peer->llgr[afi][safi]; + peer->addpath_paths_limit[afi][safi] = + from_peer->addpath_paths_limit[afi][safi]; } if (bgp_getsockname(peer) < 0) { @@ -1239,7 +1241,7 @@ void bgp_fsm_change_status(struct peer_connection *connection, /* Transition into Clearing or Deleted must /always/ clear all routes.. * (and must do so before actually changing into Deleted.. */ - if (status >= Clearing) { + if (status >= Clearing && (peer->established || peer == bgp->peer_self)) { bgp_clear_route_all(peer); /* If no route was queued for the clear-node processing, @@ -1587,7 +1589,7 @@ bgp_stop_with_error(struct peer_connection *connection) /* something went wrong, send notify and tear down */ -static enum bgp_fsm_state_progress +enum bgp_fsm_state_progress bgp_stop_with_notify(struct peer_connection *connection, uint8_t code, uint8_t sub_code) { @@ -1794,6 +1796,26 @@ bgp_connect_fail(struct peer_connection *connection) return bgp_stop(connection); } +/* after connect is called(), getpeername is able to return + * port and address on non established streams + */ +static void bgp_connect_in_progress_update_connection(struct peer *peer) +{ + if (bgp_getsockname(peer) < 0) { + if (!peer->su_remote && + !BGP_CONNECTION_SU_UNSPEC(peer->connection)) { + /* if connect initiated, then dest port and dest addresses are well known */ + peer->su_remote = sockunion_dup(&peer->connection->su); + if (sockunion_family(peer->su_remote) == AF_INET) + peer->su_remote->sin.sin_port = + htons(peer->port); + else if (sockunion_family(peer->su_remote) == AF_INET6) + peer->su_remote->sin6.sin6_port = + htons(peer->port); + } + } +} + /* This function is the first starting point of all BGP connection. It * try to connect to remote peer with non-blocking IO. */ @@ -1890,6 +1912,8 @@ static enum bgp_fsm_state_progress bgp_start(struct peer_connection *connection) __func__, peer->connection->fd); return BGP_FSM_FAILURE; } + bgp_connect_in_progress_update_connection(peer); + /* * - when the socket becomes ready, poll() will signify POLLOUT * - if it fails to connect, poll() will signify POLLHUP diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index 2e96ac4..bcdd491 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -122,6 +122,9 @@ extern void bgp_maxmed_update(struct bgp *); extern bool bgp_maxmed_onstartup_configured(struct bgp *); extern bool bgp_maxmed_onstartup_active(struct bgp *); extern int bgp_fsm_error_subcode(int status); +extern enum bgp_fsm_state_progress +bgp_stop_with_notify(struct peer_connection *connection, uint8_t code, + uint8_t sub_code); /** * Start the route advertisement timer (that honors MRAI) for all the diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index 7327ab5..839437e 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -15,6 +15,7 @@ #include "memory.h" #include "nexthop.h" #include "mpls.h" +#include "jhash.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" @@ -27,6 +28,124 @@ extern struct zclient *zclient; + +/* MPLS Labels hash routines. */ +static struct hash *labels_hash; + +static void *bgp_labels_hash_alloc(void *p) +{ + const struct bgp_labels *labels = p; + struct bgp_labels *new; + uint8_t i; + + new = XMALLOC(MTYPE_BGP_LABELS, sizeof(struct bgp_labels)); + + new->num_labels = labels->num_labels; + for (i = 0; i < labels->num_labels; i++) + new->label[i] = labels->label[i]; + + return new; +} + +static uint32_t bgp_labels_hash_key_make(const void *p) +{ + const struct bgp_labels *labels = p; + uint32_t key = 0; + + if (labels->num_labels) + key = jhash(&labels->label, + labels->num_labels * sizeof(mpls_label_t), key); + + return key; +} + +static bool bgp_labels_hash_cmp(const void *p1, const void *p2) +{ + return bgp_labels_cmp(p1, p2); +} + +void bgp_labels_init(void) +{ + labels_hash = hash_create(bgp_labels_hash_key_make, bgp_labels_hash_cmp, + "BGP Labels hash"); +} + +/* + * special for hash_clean below + */ +static void bgp_labels_free(void *labels) +{ + XFREE(MTYPE_BGP_LABELS, labels); +} + +void bgp_labels_finish(void) +{ + hash_clean_and_free(&labels_hash, bgp_labels_free); +} + +struct bgp_labels *bgp_labels_intern(struct bgp_labels *labels) +{ + struct bgp_labels *find; + + if (!labels) + return NULL; + + if (!labels->num_labels) + /* do not intern void labels structure */ + return NULL; + + find = (struct bgp_labels *)hash_get(labels_hash, labels, + bgp_labels_hash_alloc); + find->refcnt++; + + return find; +} + +void bgp_labels_unintern(struct bgp_labels **plabels) +{ + struct bgp_labels *labels = *plabels; + struct bgp_labels *ret; + + if (!*plabels) + return; + + /* Decrement labels reference. */ + labels->refcnt--; + + /* If reference becomes zero then free labels object. */ + if (labels->refcnt == 0) { + ret = hash_release(labels_hash, labels); + assert(ret != NULL); + bgp_labels_free(labels); + *plabels = NULL; + } +} + +bool bgp_labels_cmp(const struct bgp_labels *labels1, + const struct bgp_labels *labels2) +{ + uint8_t i; + + if (!labels1 && !labels2) + return true; + + if (!labels1 && labels2) + return false; + + if (labels1 && !labels2) + return false; + + if (labels1->num_labels != labels2->num_labels) + return false; + + for (i = 0; i < labels1->num_labels; i++) { + if (labels1->label[i] != labels2->label[i]) + return false; + } + + return true; +} + int bgp_parse_fec_update(void) { struct stream *s; @@ -74,7 +193,7 @@ int bgp_parse_fec_update(void) bgp_set_valid_label(&dest->local_label); } SET_FLAG(dest->flags, BGP_NODE_LABEL_CHANGED); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, NULL, afi, safi); bgp_dest_unlock_node(dest); return 1; } @@ -89,7 +208,9 @@ mpls_label_t bgp_adv_label(struct bgp_dest *dest, struct bgp_path_info *pi, if (!dest || !pi || !to) return MPLS_INVALID_LABEL; - remote_label = pi->extra ? pi->extra->label[0] : MPLS_INVALID_LABEL; + remote_label = bgp_path_info_num_labels(pi) + ? pi->extra->labels->label[0] + : MPLS_INVALID_LABEL; from = pi->peer; reflect = ((from->sort == BGP_PEER_IBGP) && (to->sort == BGP_PEER_IBGP)); @@ -471,8 +592,8 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, return BGP_NLRI_PARSE_OK; } -bool bgp_labels_same(const mpls_label_t *tbl_a, const uint32_t num_labels_a, - const mpls_label_t *tbl_b, const uint32_t num_labels_b) +bool bgp_labels_same(const mpls_label_t *tbl_a, const uint8_t num_labels_a, + const mpls_label_t *tbl_b, const uint8_t num_labels_b) { uint32_t i; diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h index b54403e..2ffd5b6 100644 --- a/bgpd/bgp_label.h +++ b/bgpd/bgp_label.h @@ -15,6 +15,26 @@ struct bgp_dest; struct bgp_path_info; struct peer; +/* Maximum number of labels we can process or send with a prefix. We + * really do only 1 for MPLS (BGP-LU) but we can do 2 for EVPN-VxLAN. + */ +#define BGP_MAX_LABELS 2 + +/* MPLS label(s) - VNI(s) for EVPN-VxLAN */ +struct bgp_labels { + mpls_label_t label[BGP_MAX_LABELS]; + uint8_t num_labels; + + unsigned long refcnt; +}; + +extern void bgp_labels_init(void); +extern void bgp_labels_finish(void); +extern struct bgp_labels *bgp_labels_intern(struct bgp_labels *labels); +extern void bgp_labels_unintern(struct bgp_labels **plabels); +extern bool bgp_labels_cmp(const struct bgp_labels *labels1, + const struct bgp_labels *labels2); + extern int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid, bool allocated); extern void bgp_reg_dereg_for_label(struct bgp_dest *dest, @@ -27,9 +47,9 @@ extern mpls_label_t bgp_adv_label(struct bgp_dest *dest, extern int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, struct bgp_nlri *packet); extern bool bgp_labels_same(const mpls_label_t *tbl_a, - const uint32_t num_labels_a, + const uint8_t num_labels_a, const mpls_label_t *tbl_b, - const uint32_t num_labels_b); + const uint8_t num_labels_b); static inline int bgp_labeled_safi(safi_t safi) { diff --git a/bgpd/bgp_mac.c b/bgpd/bgp_mac.c index e629732..31e84d1 100644 --- a/bgpd/bgp_mac.c +++ b/bgpd/bgp_mac.c @@ -14,6 +14,7 @@ #include "bgpd/bgpd.h" #include "bgpd/bgp_mac.h" #include "bgpd/bgp_memory.h" +#include "bgpd/bgp_label.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_rd.h" @@ -125,6 +126,8 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, { struct bgp_dest *pdest, *dest; struct bgp_path_info *pi; + uint8_t num_labels; + mpls_label_t *label_pnt; for (pdest = bgp_table_top(table); pdest; pdest = bgp_route_next(pdest)) { @@ -140,8 +143,6 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, const struct prefix *p = bgp_dest_get_prefix(dest); struct prefix_evpn *pevpn = (struct prefix_evpn *)dest; struct prefix_rd prd; - uint32_t num_labels = 0; - mpls_label_t *label_pnt = NULL; struct bgp_route_evpn *evpn; if (pevpn->family == AF_EVPN @@ -169,10 +170,9 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer, && !dest_affected) continue; - if (pi->extra) - num_labels = pi->extra->num_labels; - if (num_labels) - label_pnt = &pi->extra->label[0]; + num_labels = bgp_path_info_num_labels(pi); + label_pnt = num_labels ? &pi->extra->labels->label[0] + : NULL; prd.family = AF_UNSPEC; prd.prefixlen = 64; diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 851c488..97658d3 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -26,6 +26,7 @@ #include "bfd.h" #include "libfrr.h" #include "ns.h" +#include "libagentx.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" @@ -207,6 +208,8 @@ static __attribute__((__noreturn__)) void bgp_exit(int status) bgp_evpn_mh_finish(); bgp_nhg_finish(); + zebra_announce_fini(&bm->zebra_announce_head); + /* reverse bgp_dump_init */ bgp_dump_finish(); @@ -222,6 +225,9 @@ static __attribute__((__noreturn__)) void bgp_exit(int status) /* reverse bgp_attr_init */ bgp_attr_finish(); + /* reverse bgp_labels_init */ + bgp_labels_finish(); + /* stop pthreads */ bgp_pthreads_finish(); @@ -514,8 +520,10 @@ int main(int argc, char **argv) bgp_option_set(BGP_OPT_NO_ZEBRA); bgp_error_init(); /* Initializations. */ + libagentx_init(); bgp_vrf_init(); + #ifdef HAVE_SCRIPTING bgp_script_init(); #endif diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index 0764f1e..c1804fb 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -91,6 +91,7 @@ DEFINE_MTYPE(BGPD, PEER_UPDATE_SOURCE, "BGP peer update interface"); DEFINE_MTYPE(BGPD, PEER_CONF_IF, "BGP peer config interface"); DEFINE_MTYPE(BGPD, BGP_DAMP_INFO, "Dampening info"); DEFINE_MTYPE(BGPD, BGP_DAMP_ARRAY, "BGP Dampening array"); +DEFINE_MTYPE(BGPD, BGP_DAMP_REUSELIST, "BGP Dampening reuse list"); DEFINE_MTYPE(BGPD, BGP_REGEXP, "BGP regexp"); DEFINE_MTYPE(BGPD, BGP_AGGREGATE, "BGP aggregate"); DEFINE_MTYPE(BGPD, BGP_ADDR, "BGP own address"); @@ -101,6 +102,8 @@ DEFINE_MTYPE(BGPD, BGP_FILTER_NAME, "BGP Filter Information"); DEFINE_MTYPE(BGPD, BGP_DUMP_STR, "BGP Dump String Information"); DEFINE_MTYPE(BGPD, ENCAP_TLV, "ENCAP TLV"); +DEFINE_MTYPE(BGPD, BGP_LABELS, "BGP LABELS"); + DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS, "BGP TEA Options"); DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value"); diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index 29584cd..4ae49a2 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -87,6 +87,7 @@ DECLARE_MTYPE(PEER_UPDATE_SOURCE); DECLARE_MTYPE(PEER_CONF_IF); DECLARE_MTYPE(BGP_DAMP_INFO); DECLARE_MTYPE(BGP_DAMP_ARRAY); +DECLARE_MTYPE(BGP_DAMP_REUSELIST); DECLARE_MTYPE(BGP_REGEXP); DECLARE_MTYPE(BGP_AGGREGATE); DECLARE_MTYPE(BGP_ADDR); @@ -97,6 +98,8 @@ DECLARE_MTYPE(BGP_FILTER_NAME); DECLARE_MTYPE(BGP_DUMP_STR); DECLARE_MTYPE(ENCAP_TLV); +DECLARE_MTYPE(BGP_LABELS); + DECLARE_MTYPE(BGP_TEA_OPTIONS); DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE); diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index c773c21..e12d84b 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -129,15 +129,19 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1, &bpi2->attr->mp_nexthop_global); break; case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: - addr1 = (bpi1->attr->mp_nexthop_prefer_global) + addr1 = (CHECK_FLAG(bpi1->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) ? bpi1->attr->mp_nexthop_global : bpi1->attr->mp_nexthop_local; - addr2 = (bpi2->attr->mp_nexthop_prefer_global) + addr2 = (CHECK_FLAG(bpi2->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) ? bpi2->attr->mp_nexthop_global : bpi2->attr->mp_nexthop_local; - if (!bpi1->attr->mp_nexthop_prefer_global - && !bpi2->attr->mp_nexthop_prefer_global) + if (!CHECK_FLAG(bpi1->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL) && + !CHECK_FLAG(bpi2->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) compare = !bgp_interface_same( bpi1->peer->ifp, bpi2->peer->ifp); @@ -517,7 +521,7 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, struct bgp_maxpaths_cfg *mpath_cfg) { uint16_t maxpaths, mpath_count, old_mpath_count; - uint32_t bwval; + uint64_t bwval; uint64_t cum_bw, old_cum_bw; struct listnode *mp_node, *mp_next_node; struct bgp_path_info *cur_mpath, *new_mpath, *next_mpath, *prev_mpath; @@ -609,8 +613,11 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, cur_mpath); prev_mpath = cur_mpath; mpath_count++; - if (ecommunity_linkbw_present( - bgp_attr_get_ecommunity( + if (ecommunity_linkbw_present(bgp_attr_get_ecommunity( + cur_mpath->attr), + &bwval) || + ecommunity_linkbw_present( + bgp_attr_get_ipv6_ecommunity( cur_mpath->attr), &bwval)) cum_bw += bwval; @@ -696,8 +703,11 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, prev_mpath = new_mpath; mpath_changed = 1; mpath_count++; - if (ecommunity_linkbw_present( - bgp_attr_get_ecommunity( + if (ecommunity_linkbw_present(bgp_attr_get_ecommunity( + new_mpath->attr), + &bwval) || + ecommunity_linkbw_present( + bgp_attr_get_ipv6_ecommunity( new_mpath->attr), &bwval)) cum_bw += bwval; @@ -720,8 +730,12 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, if (new_best) { bgp_path_info_mpath_count_set(new_best, mpath_count - 1); if (mpath_count <= 1 || - !ecommunity_linkbw_present( - bgp_attr_get_ecommunity(new_best->attr), &bwval)) + (!ecommunity_linkbw_present(bgp_attr_get_ecommunity( + new_best->attr), + &bwval) && + !ecommunity_linkbw_present(bgp_attr_get_ipv6_ecommunity( + new_best->attr), + &bwval))) all_paths_lb = false; else cum_bw += bwval; diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 58e3097..1bc1a47 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -964,50 +964,6 @@ void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset, } } -static bool labels_same(struct bgp_path_info *bpi, mpls_label_t *label, - uint32_t n) -{ - if (!bpi->extra) { - if (!n) - return true; - else - return false; - } - - return bgp_labels_same((const mpls_label_t *)bpi->extra->label, - bpi->extra->num_labels, - (const mpls_label_t *)label, n); -} - -/* - * make encoded route labels match specified encoded label set - */ -static void setlabels(struct bgp_path_info *bpi, - mpls_label_t *label, /* array of labels */ - uint32_t num_labels) -{ - if (num_labels) - assert(label); - assert(num_labels <= BGP_MAX_LABELS); - - if (!num_labels) { - if (bpi->extra) - bpi->extra->num_labels = 0; - return; - } - - struct bgp_path_info_extra *extra = bgp_path_info_extra_get(bpi); - uint32_t i; - - for (i = 0; i < num_labels; ++i) { - extra->label[i] = label[i]; - if (!bgp_is_valid_label(&label[i])) { - bgp_set_valid_label(&extra->label[i]); - } - } - extra->num_labels = num_labels; -} - static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn, struct attr *new_attr, afi_t afi, safi_t safi, @@ -1086,7 +1042,7 @@ static struct bgp_path_info * leak_update(struct bgp *to_bgp, struct bgp_dest *bn, struct attr *new_attr, /* already interned */ afi_t afi, safi_t safi, struct bgp_path_info *source_bpi, - mpls_label_t *label, uint32_t num_labels, struct bgp *bgp_orig, + mpls_label_t *label, uint8_t num_labels, struct bgp *bgp_orig, struct prefix *nexthop_orig, int nexthop_self_flag, int debug) { const struct prefix *p = bgp_dest_get_prefix(bn); @@ -1094,6 +1050,9 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, struct bgp_path_info *new; struct bgp_path_info_extra *extra; struct bgp_path_info *parent = source_bpi; + struct bgp_labels bgp_labels = {}; + bool labelssame; + uint8_t i; if (debug) zlog_debug( @@ -1128,8 +1087,15 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, break; } + bgp_labels.num_labels = num_labels; + for (i = 0; i < num_labels; i++) { + bgp_labels.label[i] = label[i]; + bgp_set_valid_label(&bgp_labels.label[i]); + } + if (bpi) { - bool labelssame = labels_same(bpi, label, num_labels); + labelssame = bgp_path_info_labels_same(bpi, bgp_labels.label, + bgp_labels.num_labels); if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED) && CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { @@ -1187,11 +1153,13 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, bpi->uptime = monotime(NULL); /* - * rewrite labels + * update labels */ - if (!labelssame) - setlabels(bpi, label, num_labels); - + if (!labelssame) { + bgp_path_info_extra_get(bpi); + bgp_labels_unintern(&bpi->extra->labels); + bpi->extra->labels = bgp_labels_intern(&bgp_labels); + } if (nexthop_self_flag) bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF); @@ -1208,7 +1176,7 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, /* Process change. */ bgp_aggregate_increment(to_bgp, p, bpi, afi, safi); - bgp_process(to_bgp, bn, afi, safi); + bgp_process(to_bgp, bn, bpi, afi, safi); if (debug) zlog_debug("%s: ->%s: %pBD Found route, changed attr", @@ -1249,8 +1217,8 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN)) bgp_path_info_set_flag(bn, new, BGP_PATH_ACCEPT_OWN); - if (num_labels) - setlabels(new, label, num_labels); + if (bgp_labels.num_labels) + new->extra->labels = bgp_labels_intern(&bgp_labels); new->extra->vrfleak->parent = bgp_path_info_lock(parent); bgp_dest_lock_node( @@ -1270,7 +1238,7 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, bgp_aggregate_increment(to_bgp, p, new, afi, safi); bgp_path_info_add(bn, new); - bgp_process(to_bgp, bn, afi, safi); + bgp_process(to_bgp, bn, new, afi, safi); if (debug) zlog_debug("%s: ->%s: %pBD: Added new route", __func__, @@ -1441,6 +1409,16 @@ _vpn_leak_from_vrf_get_per_nexthop_label(struct bgp_path_info *pi, return blnc->label; } +static mpls_label_t bgp_mplsvpn_get_vpn_label(struct vpn_policy *bgp_policy) +{ + if (bgp_policy->tovpn_label == MPLS_LABEL_NONE && + CHECK_FLAG(bgp_policy->flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) { + bgp_lp_get(LP_TYPE_VRF, bgp_policy, vpn_leak_label_callback); + return MPLS_INVALID_LABEL; + } + return bgp_policy->tovpn_label; +} + /* Filter out all the cases where a per nexthop label is not possible: * - return an invalid label when the nexthop is invalid * - return the per VRF label when the per nexthop label is not supported @@ -1469,7 +1447,7 @@ vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi, * Fallback to the per VRF label. */ bgp_mplsvpn_path_nh_label_unlink(pi); - return from_bgp->vpn_policy[afi].tovpn_label; + return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]); } if (is_bgp_static_route == false && afi == AFI_IP && @@ -1481,7 +1459,7 @@ vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi, * Fallback to the per VRF label. */ bgp_mplsvpn_path_nh_label_unlink(pi); - return from_bgp->vpn_policy[afi].tovpn_label; + return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]); } if (is_bgp_static_route == false && afi == AFI_IP6 && @@ -1495,7 +1473,7 @@ vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi, * Fallback to the per VRF label. */ bgp_mplsvpn_path_nh_label_unlink(pi); - return from_bgp->vpn_policy[afi].tovpn_label; + return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]); } /* Check the next-hop reachability. @@ -1517,7 +1495,7 @@ vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi, * table. Fallback to the per-vrf label */ bgp_mplsvpn_path_nh_label_unlink(pi); - return from_bgp->vpn_policy[afi].tovpn_label; + return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]); } if (!nh_valid || !pi->nexthop || pi->nexthop->nexthop_num == 0 || @@ -1540,7 +1518,7 @@ vpn_leak_from_vrf_get_per_nexthop_label(afi_t afi, struct bgp_path_info *pi, * Fallback to per-vrf label. */ bgp_mplsvpn_path_nh_label_unlink(pi); - return from_bgp->vpn_policy[afi].tovpn_label; + return bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]); } return _vpn_leak_from_vrf_get_per_nexthop_label(pi, to_bgp, from_bgp, @@ -1755,12 +1733,10 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */ label_val = vpn_leak_from_vrf_get_per_nexthop_label( afi, path_vrf, from_bgp, to_bgp); else - /* per VRF label mode */ - label_val = from_bgp->vpn_policy[afi].tovpn_label; + label_val = + bgp_mplsvpn_get_vpn_label(&from_bgp->vpn_policy[afi]); - if (label_val == MPLS_INVALID_LABEL && - CHECK_FLAG(from_bgp->vpn_policy[afi].flags, - BGP_VPN_POLICY_TOVPN_LABEL_PER_NEXTHOP)) { + if (label_val == MPLS_INVALID_LABEL) { /* no valid label for the moment * when the 'bgp_mplsvpn_get_label_per_nexthop_cb' callback gets * a valid label value, it will call the current function again. @@ -1956,7 +1932,7 @@ void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp, /* to */ bgp_aggregate_decrement(to_bgp, p, bpi, afi, safi); bgp_path_info_delete(bn, bpi); - bgp_process(to_bgp, bn, afi, safi); + bgp_process(to_bgp, bn, bpi, afi, safi); } bgp_dest_unlock_node(bn); } @@ -1976,7 +1952,7 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp, struct bgp *from_bgp, struct bgp_table *table; struct bgp_dest *bn; - struct bgp_path_info *bpi; + struct bgp_path_info *bpi, *next; /* This is the per-RD table of prefixes */ table = bgp_dest_get_bgp_table_info(pdest); @@ -1991,7 +1967,8 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp, struct bgp *from_bgp, __func__, bn); } - for (; bpi; bpi = bpi->next) { + for (; (bpi != NULL) && (next = bpi->next, 1); + bpi = next) { if (debug) zlog_debug("%s: type %d, sub_type %d", __func__, bpi->type, @@ -2012,7 +1989,7 @@ void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp, struct bgp *from_bgp, to_bgp, bgp_dest_get_prefix(bn), bpi, afi, safi); bgp_path_info_delete(bn, bpi); - bgp_process(to_bgp, bn, afi, safi); + bgp_process(to_bgp, bn, bpi, afi, safi); bgp_mplsvpn_path_nh_label_unlink( bpi->extra->vrfleak->parent); } @@ -2093,15 +2070,16 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ safi_t safi = SAFI_UNICAST; const char *debugmsg; struct prefix nexthop_orig; - mpls_label_t *pLabels = NULL; - uint32_t num_labels = 0; + mpls_label_t *label_pnt = NULL; + uint8_t num_labels = 0; int nexthop_self_flag = 1; struct bgp_path_info *bpi_ultimate = NULL; struct bgp_path_info *bpi; int origin_local = 0; struct bgp *src_vrf; - struct interface *ifp; + struct interface *ifp = NULL; char rd_buf[RD_ADDRSTRLEN]; + int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); if (!vpn_leak_from_vpn_active(to_bgp, afi, &debugmsg)) { @@ -2268,6 +2246,15 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ break; } + if (!ifp && static_attr.nh_ifindex) + ifp = if_lookup_by_index(static_attr.nh_ifindex, + src_vrf->vrf_id); + + if (ifp && if_is_operative(ifp)) + SET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE); + /* * route map handling */ @@ -2330,21 +2317,16 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ origin_local = 1; } - /* copy labels */ - if (!origin_local && path_vpn->extra - && path_vpn->extra->num_labels) { - num_labels = path_vpn->extra->num_labels; - if (num_labels > BGP_MAX_LABELS) - num_labels = BGP_MAX_LABELS; - pLabels = path_vpn->extra->label; - } + num_labels = origin_local ? 0 + : bgp_path_info_num_labels(path_vpn); + label_pnt = num_labels ? path_vpn->extra->labels->label : NULL; } if (debug) zlog_debug("%s: pfx %pBD: num_labels %d", __func__, path_vpn->net, num_labels); - if (!leak_update(to_bgp, bn, new_attr, afi, safi, path_vpn, pLabels, + if (!leak_update(to_bgp, bn, new_attr, afi, safi, path_vpn, label_pnt, num_labels, src_vrf, &nexthop_orig, nexthop_self_flag, debug)) bgp_dest_unlock_node(bn); @@ -2497,7 +2479,7 @@ void vpn_leak_to_vrf_withdraw(struct bgp_path_info *path_vpn) bpi); bgp_aggregate_decrement(bgp, p, bpi, afi, safi); bgp_path_info_delete(bn, bpi); - bgp_process(bgp, bn, afi, safi); + bgp_process(bgp, bn, bpi, afi, safi); } bgp_dest_unlock_node(bn); } @@ -2506,7 +2488,7 @@ void vpn_leak_to_vrf_withdraw(struct bgp_path_info *path_vpn) void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi) { struct bgp_dest *bn; - struct bgp_path_info *bpi; + struct bgp_path_info *bpi, *next; safi_t safi = SAFI_UNICAST; int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); @@ -2517,9 +2499,8 @@ void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi) */ for (bn = bgp_table_top(to_bgp->rib[afi][safi]); bn; bn = bgp_route_next(bn)) { - - for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; - bpi = bpi->next) { + for (bpi = bgp_dest_get_bgp_path_info(bn); + (bpi != NULL) && (next = bpi->next, 1); bpi = next) { if (bpi->extra && bpi->extra->vrfleak && bpi->extra->vrfleak->bgp_orig != to_bgp && bpi->extra->vrfleak->parent && @@ -2529,7 +2510,7 @@ void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi) bgp_dest_get_prefix(bn), bpi, afi, safi); bgp_path_info_delete(bn, bpi); - bgp_process(to_bgp, bn, afi, safi); + bgp_process(to_bgp, bn, bpi, afi, safi); } } } @@ -2558,8 +2539,11 @@ void vpn_leak_no_retain(struct bgp *to_bgp, struct bgp *vpn_from, afi_t afi) continue; for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) { - for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; - bpi = bpi->next) { + struct bgp_path_info *next; + + for (bpi = bgp_dest_get_bgp_path_info(bn); + (bpi != NULL) && (next = bpi->next, 1); + bpi = next) { if (bpi->extra && bpi->extra->vrfleak && bpi->extra->vrfleak->bgp_orig == to_bgp) continue; @@ -3746,6 +3730,9 @@ void vpn_leak_postchange_all(void) if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF) continue; + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + vpn_leak_postchange( BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, @@ -3765,6 +3752,9 @@ void vpn_leak_postchange_all(void) if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF) continue; + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + vpn_leak_postchange( BGP_VPN_POLICY_DIR_FROMVPN, AFI_IP, @@ -3974,7 +3964,7 @@ static void bgp_mplsvpn_nh_label_bind_send_nexthop_label( struct bgp_mplsvpn_nh_label_bind_cache *bmnc, int cmd) { struct prefix pfx_nh, *p = NULL; - uint32_t num_labels = 0, lsp_num_labels; + uint8_t num_labels = 0, lsp_num_labels; mpls_label_t label[MPLS_MAX_LABELS]; struct nexthop *nh; ifindex_t ifindex = IFINDEX_INTERNAL; @@ -4109,7 +4099,7 @@ bool bgp_mplsvpn_path_uses_valid_mpls_label(struct bgp_path_info *pi) /* prefix_sid attribute */ return false; - if (!pi->extra || !bgp_is_valid_label(&pi->extra->label[0])) + if (!bgp_path_info_has_valid_label(pi)) /* invalid MPLS label */ return false; return true; @@ -4180,7 +4170,7 @@ static int bgp_mplsvpn_nh_label_bind_get_local_label_cb(mpls_label_t label, if (!table) continue; SET_FLAG(pi->net->flags, BGP_NODE_LABEL_CHANGED); - bgp_process(table->bgp, pi->net, table->afi, table->safi); + bgp_process(table->bgp, pi->net, pi, table->afi, table->safi); } return 0; @@ -4216,14 +4206,17 @@ void bgp_mplsvpn_nh_label_bind_register_local_label(struct bgp *bgp, { struct bgp_mplsvpn_nh_label_bind_cache *bmnc; struct bgp_mplsvpn_nh_label_bind_cache_head *tree; + mpls_label_t label; + + label = bgp_path_info_num_labels(pi) + ? decode_label(&pi->extra->labels->label[0]) + : MPLS_INVALID_LABEL; tree = &bgp->mplsvpn_nh_label_bind; - bmnc = bgp_mplsvpn_nh_label_bind_find( - tree, &pi->nexthop->prefix, decode_label(&pi->extra->label[0])); + bmnc = bgp_mplsvpn_nh_label_bind_find(tree, &pi->nexthop->prefix, label); if (!bmnc) { - bmnc = bgp_mplsvpn_nh_label_bind_new( - tree, &pi->nexthop->prefix, - decode_label(&pi->extra->label[0])); + bmnc = bgp_mplsvpn_nh_label_bind_new(tree, &pi->nexthop->prefix, + label); bmnc->bgp_vpn = bgp; bmnc->allocation_in_progress = true; bgp_lp_get(LP_TYPE_BGP_L3VPN_BIND, bmnc, diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index cd25899..92a9fba 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -170,16 +170,6 @@ static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi, return 0; } - /* Is there an "auto" export label that isn't allocated yet? */ - if (CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags, - BGP_VPN_POLICY_TOVPN_LABEL_AUTO) && - (bgp_vrf->vpn_policy[afi].tovpn_label == MPLS_LABEL_NONE)) { - - if (pmsg) - *pmsg = "auto label not allocated"; - return 0; - } - /* Is there a "manual" export label that isn't allocated yet? */ if (!CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO) && diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index dbb34b0..e09dbc2 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -817,9 +817,9 @@ int bgp_connect(struct peer_connection *connection) #ifdef IPTOS_PREC_INTERNETCONTROL frr_with_privs(&bgpd_privs) { if (sockunion_family(&connection->su) == AF_INET) - setsockopt_ipv4_tos(connection->fd, bm->tcp_dscp); + setsockopt_ipv4_tos(connection->fd, bm->ip_tos); else if (sockunion_family(&connection->su) == AF_INET6) - setsockopt_ipv6_tclass(connection->fd, bm->tcp_dscp); + setsockopt_ipv6_tclass(connection->fd, bm->ip_tos); } #endif @@ -875,11 +875,7 @@ int bgp_getsockname(struct peer *peer) } peer->su_local = sockunion_getsockname(peer->connection->fd); - if (!peer->su_local) - return -1; peer->su_remote = sockunion_getpeername(peer->connection->fd); - if (!peer->su_remote) - return -1; if (!bgp_zebra_nexthop_set(peer->su_local, peer->su_remote, &peer->nexthop, peer)) { @@ -909,9 +905,9 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen, #ifdef IPTOS_PREC_INTERNETCONTROL if (sa->sa_family == AF_INET) - setsockopt_ipv4_tos(sock, bm->tcp_dscp); + setsockopt_ipv4_tos(sock, bm->ip_tos); else if (sa->sa_family == AF_INET6) - setsockopt_ipv6_tclass(sock, bm->tcp_dscp); + setsockopt_ipv6_tclass(sock, bm->ip_tos); #endif sockopt_v6only(sa->sa_family, sock); diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index d12dc22..98eb956 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -1003,6 +1003,8 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, if (bnc->is_evpn_gwip_nexthop) json_object_boolean_true_add(json_nexthop, "isEvpnGatewayIp"); + json_object_string_addf(json, "resolvedPrefix", "%pFX", + &bnc->resolved_prefix); } else { vty_out(vty, " %s valid [IGP metric %d], #paths %d", buf, bnc->metric, bnc->path_count); @@ -1010,6 +1012,8 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp, vty_out(vty, ", peer %s", peer->host); if (bnc->is_evpn_gwip_nexthop) vty_out(vty, " EVPN Gateway IP"); + vty_out(vty, "\n Resolved prefix %pFX", + &bnc->resolved_prefix); vty_out(vty, "\n"); } bgp_show_nexthops_detail(vty, bgp, bnc, json_nexthop); diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 8308838..430c8f1 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -90,6 +90,7 @@ struct bgp_nexthop_cache { struct bgp_nexthop_cache_head *tree; struct prefix prefix; + struct prefix resolved_prefix; void *nht_info; /* In BGP, peer session */ LIST_HEAD(path_list, bgp_path_info) paths; unsigned int path_count; diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index e2c103b..8ce4555 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -116,24 +116,36 @@ static int bgp_isvalid_nexthop_for_mplsovergre(struct bgp_nexthop_cache *bnc, static int bgp_isvalid_nexthop_for_mpls(struct bgp_nexthop_cache *bnc, struct bgp_path_info *path) { + return (bnc && (bnc->nexthop_num > 0 && + (CHECK_FLAG(path->flags, BGP_PATH_ACCEPT_OWN) || + CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) || + bgp_isvalid_nexthop_for_ebgp(bnc, path) || + bgp_isvalid_nexthop_for_mplsovergre(bnc, path)))); +} + +static bool bgp_isvalid_nexthop_for_l3vpn(struct bgp_nexthop_cache *bnc, + struct bgp_path_info *path) +{ + if (bgp_zebra_num_connects() == 0) + return 1; + + if (path->attr->srv6_l3vpn || path->attr->srv6_vpn) { + /* In the case of SRv6-VPN, we need to track the reachability to the + * SID (in other words, IPv6 address). We check that the SID is + * available in the BGP update; then if it is available, we check + * for the nexthop reachability. + */ + if (bnc && (bnc->nexthop_num > 0 && bgp_isvalid_nexthop(bnc))) + return 1; + return 0; + } /* - * - In the case of MPLS-VPN, the label is learned from LDP or other + * In the case of MPLS-VPN, the label is learned from LDP or other * protocols, and nexthop tracking is enabled for the label. * The value is recorded as BGP_NEXTHOP_LABELED_VALID. - * - In the case of SRv6-VPN, we need to track the reachability to the - * SID (in other words, IPv6 address). As in MPLS, we need to record - * the value as BGP_NEXTHOP_SID_VALID. However, this function is - * currently not implemented, and this function assumes that all - * Transit routes for SRv6-VPN are valid. * - Otherwise check for mpls-gre acceptance */ - return (bgp_zebra_num_connects() == 0 || - (bnc && (bnc->nexthop_num > 0 && - (CHECK_FLAG(path->flags, BGP_PATH_ACCEPT_OWN) || - CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) || - bnc->bgp->srv6_enabled || - bgp_isvalid_nexthop_for_ebgp(bnc, path) || - bgp_isvalid_nexthop_for_mplsovergre(bnc, path))))); + return bgp_isvalid_nexthop_for_mpls(bnc, path); } static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc) @@ -308,11 +320,6 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, afi = BGP_ATTR_MP_NEXTHOP_LEN_IP6(pi->attr) ? AFI_IP6 : AFI_IP; - /* Validation for the ipv4 mapped ipv6 nexthop. */ - if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) { - afi = AFI_IP; - } - /* This will return true if the global IPv6 NH is a link local * addr */ if (make_prefix(afi, pi, &p) < 0) @@ -345,9 +352,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, return 0; } - if (CHECK_FLAG(pi->attr->flag, - ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR))) - srte_color = bgp_attr_get_color(pi->attr); + srte_color = bgp_attr_get_color(pi->attr); } else if (peer) { /* @@ -494,9 +499,9 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) return 1; else if (safi == SAFI_UNICAST && pi && - pi->sub_type == BGP_ROUTE_IMPORTED && pi->extra && - pi->extra->num_labels && !bnc->is_evpn_gwip_nexthop) - return bgp_isvalid_nexthop_for_mpls(bnc, pi); + pi->sub_type == BGP_ROUTE_IMPORTED && + bgp_path_info_num_labels(pi) && !bnc->is_evpn_gwip_nexthop) + return bgp_isvalid_nexthop_for_l3vpn(bnc, pi); else if (safi == SAFI_MPLS_VPN && pi && pi->sub_type != BGP_ROUTE_IMPORTED) /* avoid not redistributing mpls vpn routes */ @@ -614,6 +619,8 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc, } else if (nhr->nexthop_num) { struct peer *peer = bnc->nht_info; + prefix_copy(&bnc->resolved_prefix, &nhr->prefix); + /* notify bgp fsm if nbr ip goes from invalid->valid */ if (!bnc->nexthop_num) UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED); @@ -719,6 +726,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc, } } } else { + memset(&bnc->resolved_prefix, 0, sizeof(bnc->resolved_prefix)); bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE; bnc->flags &= ~BGP_NEXTHOP_VALID; bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID; @@ -964,14 +972,13 @@ void bgp_nexthop_update(struct vrf *vrf, struct prefix *match, * which should provide a better infrastructure to solve this issue in * a more efficient and elegant way. */ - if (nhr->srte_color == 0 && bnc_nhc) { + if (nhr->srte_color == 0) { struct bgp_nexthop_cache *bnc_iter; frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi], bnc_iter) { - if (!prefix_same(&bnc_nhc->prefix, &bnc_iter->prefix) || - bnc_iter->srte_color == 0 || - CHECK_FLAG(bnc_iter->flags, BGP_NEXTHOP_VALID)) + if (!prefix_same(match, &bnc_iter->prefix) || + bnc_iter->srte_color == 0) continue; bgp_process_nexthop_update(bnc_iter, nhr, false); @@ -1028,52 +1035,57 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) p->u.prefix4 = p_orig->u.prefix4; p->prefixlen = p_orig->prefixlen; } else { - if (IS_MAPPED_IPV6(&pi->attr->mp_nexthop_global)) { - ipv4_mapped_ipv6_to_ipv4( - &pi->attr->mp_nexthop_global, &ipv4); - p->u.prefix4 = ipv4; - p->prefixlen = IPV4_MAX_BITLEN; - } else { - if (p_orig->family == AF_EVPN) - p->u.prefix4 = - pi->attr->mp_nexthop_global_in; - else - p->u.prefix4 = pi->attr->nexthop; - p->prefixlen = IPV4_MAX_BITLEN; - } + if (p_orig->family == AF_EVPN) + p->u.prefix4 = pi->attr->mp_nexthop_global_in; + else + p->u.prefix4 = pi->attr->nexthop; + p->prefixlen = IPV4_MAX_BITLEN; } break; case AFI_IP6: p->family = AF_INET6; - - if (is_bgp_static) { + if (pi->attr->srv6_l3vpn) { + IPV6_ADDR_COPY(&(p->u.prefix6), + &(pi->attr->srv6_l3vpn->sid)); + p->prefixlen = IPV6_MAX_BITLEN; + } else if (is_bgp_static) { p->u.prefix6 = p_orig->u.prefix6; p->prefixlen = p_orig->prefixlen; } else { /* If we receive MP_REACH nexthop with ::(LL) * or LL(LL), use LL address as nexthop cache. */ - if (pi->attr->mp_nexthop_len - == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL - && (IN6_IS_ADDR_UNSPECIFIED( - &pi->attr->mp_nexthop_global) - || IN6_IS_ADDR_LINKLOCAL( - &pi->attr->mp_nexthop_global))) + p->prefixlen = IPV6_MAX_BITLEN; + if (pi->attr && + pi->attr->mp_nexthop_len == + BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL && + (IN6_IS_ADDR_UNSPECIFIED( + &pi->attr->mp_nexthop_global) || + IN6_IS_ADDR_LINKLOCAL(&pi->attr->mp_nexthop_global))) p->u.prefix6 = pi->attr->mp_nexthop_local; /* If we receive MR_REACH with (GA)::(LL) * then check for route-map to choose GA or LL */ - else if (pi->attr->mp_nexthop_len - == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { - if (pi->attr->mp_nexthop_prefer_global) - p->u.prefix6 = - pi->attr->mp_nexthop_global; - else + else if (pi->attr && + pi->attr->mp_nexthop_len == + BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { + if (CHECK_FLAG(pi->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) { + if (IS_MAPPED_IPV6( + &pi->attr->mp_nexthop_global)) { + ipv4_mapped_ipv6_to_ipv4( + &pi->attr->mp_nexthop_global, + &ipv4); + p->u.prefix4 = ipv4; + p->prefixlen = IPV4_MAX_BITLEN; + } else + p->u.prefix6 = + pi->attr->mp_nexthop_global; + } else p->u.prefix6 = pi->attr->mp_nexthop_local; } else p->u.prefix6 = pi->attr->mp_nexthop_global; - p->prefixlen = IPV6_MAX_BITLEN; } break; default: @@ -1289,13 +1301,14 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc) bool bnc_is_valid_nexthop = false; bool path_valid = false; - if (safi == SAFI_UNICAST && path->sub_type == BGP_ROUTE_IMPORTED - && path->extra && path->extra->num_labels - && (path->attr->evpn_overlay.type - != OVERLAY_INDEX_GATEWAY_IP)) { + if (safi == SAFI_UNICAST && + path->sub_type == BGP_ROUTE_IMPORTED && + bgp_path_info_num_labels(path) && + (path->attr->evpn_overlay.type != OVERLAY_INDEX_GATEWAY_IP)) { bnc_is_valid_nexthop = - bgp_isvalid_nexthop_for_mpls(bnc, path) ? true - : false; + bgp_isvalid_nexthop_for_l3vpn(bnc, path) + ? true + : false; } else if (safi == SAFI_MPLS_VPN && path->sub_type != BGP_ROUTE_IMPORTED) { /* avoid not redistributing mpls vpn routes */ @@ -1414,7 +1427,7 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc) } } - bgp_process(bgp_path, dest, afi, safi); + bgp_process(bgp_path, dest, path, afi, safi); } if (peer) { diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 6c96ffc..248d478 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -42,25 +42,27 @@ const struct message capcode_str[] = { { CAPABILITY_CODE_LLGR, "Long-lived BGP Graceful Restart" }, { CAPABILITY_CODE_ROLE, "Role" }, { CAPABILITY_CODE_SOFT_VERSION, "Software Version" }, + { CAPABILITY_CODE_PATHS_LIMIT, "Paths-Limit" }, { 0 } }; /* Minimum sizes for length field of each cap (so not inc. the header) */ -static const size_t cap_minsizes[] = { - [CAPABILITY_CODE_MP] = CAPABILITY_CODE_MP_LEN, - [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN, - [CAPABILITY_CODE_ORF] = CAPABILITY_CODE_ORF_LEN, - [CAPABILITY_CODE_RESTART] = CAPABILITY_CODE_RESTART_LEN, - [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN, - [CAPABILITY_CODE_ADDPATH] = CAPABILITY_CODE_ADDPATH_LEN, - [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN, - [CAPABILITY_CODE_ENHE] = CAPABILITY_CODE_ENHE_LEN, - [CAPABILITY_CODE_FQDN] = CAPABILITY_CODE_MIN_FQDN_LEN, - [CAPABILITY_CODE_ENHANCED_RR] = CAPABILITY_CODE_ENHANCED_LEN, - [CAPABILITY_CODE_EXT_MESSAGE] = CAPABILITY_CODE_EXT_MESSAGE_LEN, - [CAPABILITY_CODE_LLGR] = CAPABILITY_CODE_LLGR_LEN, - [CAPABILITY_CODE_ROLE] = CAPABILITY_CODE_ROLE_LEN, - [CAPABILITY_CODE_SOFT_VERSION] = CAPABILITY_CODE_SOFT_VERSION_LEN, +const size_t cap_minsizes[] = { + [CAPABILITY_CODE_MP] = CAPABILITY_CODE_MP_LEN, + [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN, + [CAPABILITY_CODE_ORF] = CAPABILITY_CODE_ORF_LEN, + [CAPABILITY_CODE_RESTART] = CAPABILITY_CODE_RESTART_LEN, + [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN, + [CAPABILITY_CODE_ADDPATH] = CAPABILITY_CODE_ADDPATH_LEN, + [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN, + [CAPABILITY_CODE_ENHE] = CAPABILITY_CODE_ENHE_LEN, + [CAPABILITY_CODE_FQDN] = CAPABILITY_CODE_MIN_FQDN_LEN, + [CAPABILITY_CODE_ENHANCED_RR] = CAPABILITY_CODE_ENHANCED_LEN, + [CAPABILITY_CODE_EXT_MESSAGE] = CAPABILITY_CODE_EXT_MESSAGE_LEN, + [CAPABILITY_CODE_LLGR] = CAPABILITY_CODE_LLGR_LEN, + [CAPABILITY_CODE_ROLE] = CAPABILITY_CODE_ROLE_LEN, + [CAPABILITY_CODE_SOFT_VERSION] = CAPABILITY_CODE_SOFT_VERSION_LEN, + [CAPABILITY_CODE_PATHS_LIMIT] = CAPABILITY_CODE_PATHS_LIMIT_LEN, }; /* value the capability must be a multiple of. @@ -68,21 +70,22 @@ static const size_t cap_minsizes[] = { * Other capabilities whose data doesn't fall on convenient boundaries for this * table should be set to 1. */ -static const size_t cap_modsizes[] = { - [CAPABILITY_CODE_MP] = 4, - [CAPABILITY_CODE_REFRESH] = 1, - [CAPABILITY_CODE_ORF] = 1, - [CAPABILITY_CODE_RESTART] = 1, - [CAPABILITY_CODE_AS4] = 4, - [CAPABILITY_CODE_ADDPATH] = 4, - [CAPABILITY_CODE_DYNAMIC] = 1, - [CAPABILITY_CODE_ENHE] = 6, - [CAPABILITY_CODE_FQDN] = 1, - [CAPABILITY_CODE_ENHANCED_RR] = 1, - [CAPABILITY_CODE_EXT_MESSAGE] = 1, - [CAPABILITY_CODE_LLGR] = 1, - [CAPABILITY_CODE_ROLE] = 1, - [CAPABILITY_CODE_SOFT_VERSION] = 1, +const size_t cap_modsizes[] = { + [CAPABILITY_CODE_MP] = 4, + [CAPABILITY_CODE_REFRESH] = 1, + [CAPABILITY_CODE_ORF] = 1, + [CAPABILITY_CODE_RESTART] = 1, + [CAPABILITY_CODE_AS4] = 4, + [CAPABILITY_CODE_ADDPATH] = 4, + [CAPABILITY_CODE_DYNAMIC] = 1, + [CAPABILITY_CODE_ENHE] = 6, + [CAPABILITY_CODE_FQDN] = 1, + [CAPABILITY_CODE_ENHANCED_RR] = 1, + [CAPABILITY_CODE_EXT_MESSAGE] = 1, + [CAPABILITY_CODE_LLGR] = 1, + [CAPABILITY_CODE_ROLE] = 1, + [CAPABILITY_CODE_SOFT_VERSION] = 1, + [CAPABILITY_CODE_PATHS_LIMIT] = 5, }; /* BGP-4 Multiprotocol Extentions lead us to the complex world. We can @@ -739,6 +742,62 @@ static int bgp_capability_addpath(struct peer *peer, return 0; } +static int bgp_capability_paths_limit(struct peer *peer, + struct capability_header *hdr) +{ + struct stream *s = BGP_INPUT(peer); + size_t end = stream_get_getp(s) + hdr->length; + + if (hdr->length % CAPABILITY_CODE_PATHS_LIMIT_LEN) { + flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, + "Paths-Limit: Received invalid length %d, non-multiple of %d", + hdr->length, CAPABILITY_CODE_PATHS_LIMIT_LEN); + return -1; + } + + if (!CHECK_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV)) { + flog_warn(EC_BGP_CAPABILITY_INVALID_DATA, + "Paths-Limit: Received Paths-Limit capability without Add-Path capability"); + return -1; + } + + SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV); + + while (stream_get_getp(s) + CAPABILITY_CODE_PATHS_LIMIT_LEN <= end) { + afi_t afi; + safi_t safi; + iana_afi_t pkt_afi = stream_getw(s); + iana_safi_t pkt_safi = stream_getc(s); + uint16_t paths_limit = stream_getw(s); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s limit: %u", + peer->host, + lookup_msg(capcode_str, hdr->code, NULL), + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi), paths_limit); + + if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Addr-family %s/%s(afi/safi) not supported. Ignore the Paths-Limit capability for this AFI/SAFI", + peer->host, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + continue; + } else if (!peer->afc[afi][safi]) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Addr-family %s/%s(afi/safi) not enabled. Ignore the Paths-Limit capability for this AFI/SAFI", + peer->host, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + continue; + } + + SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_PATHS_LIMIT_AF_RCV); + peer->addpath_paths_limit[afi][safi].receive = paths_limit; + } + + return 0; +} + static int bgp_capability_enhe(struct peer *peer, struct capability_header *hdr) { struct stream *s = BGP_INPUT(peer); @@ -1012,6 +1071,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length, case CAPABILITY_CODE_EXT_MESSAGE: case CAPABILITY_CODE_ROLE: case CAPABILITY_CODE_SOFT_VERSION: + case CAPABILITY_CODE_PATHS_LIMIT: /* Check length. */ if (caphdr.length < cap_minsizes[caphdr.code]) { zlog_info( @@ -1113,6 +1173,9 @@ static int bgp_capability_parse(struct peer *peer, size_t length, case CAPABILITY_CODE_SOFT_VERSION: ret = bgp_capability_software_version(peer, &caphdr); break; + case CAPABILITY_CODE_PATHS_LIMIT: + ret = bgp_capability_paths_limit(peer, &caphdr); + break; default: if (caphdr.code > 128) { /* We don't send Notification for unknown vendor @@ -1389,8 +1452,10 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length, /* All OPEN option is parsed. Check capability when strict compare flag is enabled.*/ if (CHECK_FLAG(peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) { - /* If Unsupported Capability exists. */ - if (error != error_data) { + /* If Unsupported Capability exists or local capability does + * not negotiated with remote peer + */ + if (error != error_data || !strict_capability_same(peer)) { bgp_notify_send_with_data(peer->connection, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_CAPBL, @@ -1398,14 +1463,6 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length, error - error_data); return -1; } - - /* Check local capability does not negotiated with remote - peer. */ - if (!strict_capability_same(peer)) { - bgp_notify_send(peer->connection, BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNSUP_CAPBL); - return -1; - } } /* Extended Message Support */ @@ -1440,17 +1497,11 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length, "%s [Error] Configured AFI/SAFIs do not overlap with received MP capabilities", peer->host); - if (error != error_data) - bgp_notify_send_with_data(peer->connection, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNSUP_CAPBL, - error_data, - error - error_data); - else - bgp_notify_send(peer->connection, - BGP_NOTIFY_OPEN_ERR, - BGP_NOTIFY_OPEN_UNSUP_CAPBL); - return -1; + bgp_notify_send_with_data(peer->connection, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_UNSUP_CAPBL, + error_data, + error - error_data); } } return 0; @@ -1874,6 +1925,31 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer, } } + /* Paths-Limit capability */ + SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_ADV); + stream_putc(s, BGP_OPEN_OPT_CAP); + ext_opt_params ? stream_putw(s, (CAPABILITY_CODE_PATHS_LIMIT_LEN * + afi_safi_count) + + 2) + : stream_putc(s, (CAPABILITY_CODE_PATHS_LIMIT_LEN * + afi_safi_count) + + 2); + stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT); + stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT_LEN * afi_safi_count); + + FOREACH_AFI_SAFI (afi, safi) { + if (!peer->afc[afi][safi]) + continue; + + bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); + + stream_putw(s, pkt_afi); + stream_putc(s, pkt_safi); + stream_putw(s, peer->addpath_paths_limit[afi][safi].send); + + SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_PATHS_LIMIT_AF_ADV); + } + /* ORF capability. */ FOREACH_AFI_SAFI (afi, safi) { if (CHECK_FLAG(peer->af_flags[afi][safi], @@ -1887,7 +1963,7 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer, } /* Dynamic capability. */ - if (CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) { + if (peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY)) { SET_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); ext_opt_params diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index 34f4b76..3a8cba9 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -53,6 +53,7 @@ struct graceful_restart_af { #define CAPABILITY_CODE_ENHE 5 /* Extended Next Hop Encoding */ #define CAPABILITY_CODE_EXT_MESSAGE 6 /* Extended Message Support */ #define CAPABILITY_CODE_ROLE 9 /* Role Capability */ +#define CAPABILITY_CODE_PATHS_LIMIT 76 /* Paths Limit Capability */ /* Capability Length */ #define CAPABILITY_CODE_MP_LEN 4 @@ -61,6 +62,7 @@ struct graceful_restart_af { #define CAPABILITY_CODE_RESTART_LEN 2 /* Receiving only case */ #define CAPABILITY_CODE_AS4_LEN 4 #define CAPABILITY_CODE_ADDPATH_LEN 4 +#define CAPABILITY_CODE_PATHS_LIMIT_LEN 5 #define CAPABILITY_CODE_ENHE_LEN 6 /* NRLI AFI = 2, SAFI = 2, Nexthop AFI = 2 */ #define CAPABILITY_CODE_MIN_FQDN_LEN 2 #define CAPABILITY_CODE_ENHANCED_LEN 0 @@ -110,5 +112,7 @@ extern as_t peek_for_as4_capability(struct peer *peer, uint16_t length); extern const struct message capcode_str[]; extern const struct message orf_type_str[]; extern const struct message orf_mode_str[]; +extern const size_t cap_minsizes[]; +extern const size_t cap_modsizes[]; #endif /* _QUAGGA_BGP_OPEN_H */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 1f808ee..010a31a 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -148,7 +148,8 @@ static void bgp_packet_add(struct peer_connection *connection, EC_BGP_SENDQ_STUCK_PROPER, "%pBP has not made any SendQ progress for 2 holdtimes (%jds), terminating session", peer, sendholdtime); - BGP_EVENT_ADD(connection, TCP_fatal_error); + bgp_stop_with_notify(connection, + BGP_NOTIFY_SEND_HOLD_ERR, 0); } else if (delta > (intmax_t)holdtime && monotime(NULL) - peer->last_sendq_warn > 5) { flog_warn( @@ -559,40 +560,37 @@ void bgp_generate_updgrp_packets(struct event *thread) } } - if (CHECK_FLAG(peer->cap, - PEER_CAP_RESTART_RCV)) { - if (!(PAF_SUBGRP(paf))->t_coalesce - && peer->afc_nego[afi][safi] - && peer->synctime - && !CHECK_FLAG( - peer->af_sflags[afi][safi], - PEER_STATUS_EOR_SEND)) { - /* If EOR is disabled, - * the message is not sent - */ - if (BGP_SEND_EOR(peer->bgp, afi, - safi)) { - SET_FLAG( - peer->af_sflags - [afi] - [safi], - PEER_STATUS_EOR_SEND); - - /* Update EOR - * send time - */ - peer->eor_stime[afi] - [safi] = - monotime(NULL); - - BGP_UPDATE_EOR_PKT( - peer, afi, safi, - s); - bgp_process_pending_refresh( - peer, afi, - safi); - } - } + /* rfc4724 says: + * Although the End-of-RIB marker is + * specified for the purpose of BGP + * graceful restart, it is noted that + * the generation of such a marker upon + * completion of the initial update would + * be useful for routing convergence in + * general, and thus the practice is + * recommended. + */ + if (!(PAF_SUBGRP(paf))->t_coalesce && + peer->afc_nego[afi][safi] && + peer->synctime && + !CHECK_FLAG(peer->af_sflags[afi][safi], + PEER_STATUS_EOR_SEND)) { + /* If EOR is disabled, the message is + * not sent. + */ + if (!BGP_SEND_EOR(peer->bgp, afi, safi)) + continue; + + SET_FLAG(peer->af_sflags[afi][safi], + PEER_STATUS_EOR_SEND); + + /* Update EOR send time */ + peer->eor_stime[afi][safi] = + monotime(NULL); + + BGP_UPDATE_EOR_PKT(peer, afi, safi, s); + bgp_process_pending_refresh(peer, afi, + safi); } continue; } @@ -1224,7 +1222,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, if (!peer_established(peer->connection)) return; - if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) && + if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) || !CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV)) return; @@ -1459,6 +1457,49 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, COND_FLAG(peer->cap, PEER_CAP_ADDPATH_ADV, action == CAPABILITY_ACTION_SET); break; + case CAPABILITY_CODE_PATHS_LIMIT: + FOREACH_AFI_SAFI (afi, safi) { + if (!peer->afc[afi][safi]) + continue; + + addpath_afi_safi_count++; + } + + stream_putc(s, action); + stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT); + stream_putc(s, CAPABILITY_CODE_PATHS_LIMIT_LEN * + addpath_afi_safi_count); + + FOREACH_AFI_SAFI (afi, safi) { + if (!peer->afc[afi][safi]) + continue; + + bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, + &pkt_safi); + + stream_putw(s, pkt_afi); + stream_putc(s, pkt_safi); + stream_putw(s, + peer->addpath_paths_limit[afi][safi].send); + + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s, limit: %u", + peer, + action == CAPABILITY_ACTION_SET + ? "Advertising" + : "Removing", + capability, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi), + peer->addpath_paths_limit[afi][safi] + .send); + } + + COND_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_ADV, + action == CAPABILITY_ACTION_SET); + break; case CAPABILITY_CODE_ORF: /* Convert AFI, SAFI to values for packet. */ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); @@ -3165,6 +3206,86 @@ ignore: } } +static void bgp_dynamic_capability_paths_limit(uint8_t *pnt, int action, + struct capability_header *hdr, + struct peer *peer) +{ + uint8_t *data = pnt + 3; + uint8_t *end = data + hdr->length; + size_t len = end - data; + afi_t afi; + safi_t safi; + + if (action == CAPABILITY_ACTION_SET) { + if (len % CAPABILITY_CODE_PATHS_LIMIT_LEN) { + flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, + "Paths-Limit: Received invalid length %zu, non-multiple of %d", + len, CAPABILITY_CODE_PATHS_LIMIT_LEN); + return; + } + + if (!CHECK_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV)) { + flog_warn(EC_BGP_CAPABILITY_INVALID_DATA, + "Paths-Limit: Received Paths-Limit capability without Add-Path capability"); + goto ignore; + } + + SET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV); + + while (data + CAPABILITY_CODE_PATHS_LIMIT_LEN <= end) { + afi_t afi; + safi_t safi; + iana_afi_t pkt_afi; + iana_safi_t pkt_safi; + uint16_t paths_limit = 0; + struct bgp_paths_limit_capability bpl = {}; + + memcpy(&bpl, data, sizeof(bpl)); + pkt_afi = ntohs(bpl.afi); + pkt_safi = safi_int2iana(bpl.safi); + paths_limit = ntohs(bpl.paths_limit); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s limit: %u", + peer->host, + lookup_msg(capcode_str, hdr->code, + NULL), + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi), paths_limit); + + if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, + &safi)) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Addr-family %s/%s(afi/safi) not supported. Ignore the Paths-Limit capability for this AFI/SAFI", + peer->host, + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + goto ignore; + } else if (!peer->afc[afi][safi]) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Addr-family %s/%s(afi/safi) not enabled. Ignore the Paths-Limit capability for this AFI/SAFI", + peer->host, + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + goto ignore; + } + + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV); + peer->addpath_paths_limit[afi][safi].receive = + paths_limit; +ignore: + data += CAPABILITY_CODE_PATHS_LIMIT_LEN; + } + } else { + FOREACH_AFI_SAFI (afi, safi) + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV); + + UNSET_FLAG(peer->cap, PEER_CAP_PATHS_LIMIT_RCV); + } +} + static void bgp_dynamic_capability_orf(uint8_t *pnt, int action, struct capability_header *hdr, struct peer *peer) @@ -3282,6 +3403,22 @@ static void bgp_dynamic_capability_orf(uint8_t *pnt, int action, } } +static void bgp_dynamic_capability_role(uint8_t *pnt, int action, + struct peer *peer) +{ + uint8_t role; + + if (action == CAPABILITY_ACTION_SET) { + SET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); + memcpy(&role, pnt + 3, sizeof(role)); + + peer->remote_role = role; + } else { + UNSET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); + peer->remote_role = ROLE_UNDEFINED; + } +} + static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action, struct capability_header *hdr, struct peer *peer) @@ -3293,14 +3430,14 @@ static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action, if (action == CAPABILITY_ACTION_SET) { /* hostname */ - if (data + 1 > end) { + if (data + 1 >= end) { zlog_err("%pBP: Received invalid FQDN capability (host name length)", peer); return; } len = *data; - if (data + len > end) { + if (data + len + 1 > end) { zlog_err("%pBP: Received invalid FQDN capability length (host name) %d", peer, hdr->length); return; @@ -3323,7 +3460,7 @@ static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action, peer->hostname = XSTRDUP(MTYPE_BGP_PEER_HOST, str); } - if (data + 1 > end) { + if (data + 1 >= end) { zlog_err("%pBP: Received invalid FQDN capability (domain name length)", peer); return; @@ -3331,7 +3468,7 @@ static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action, /* domainname */ len = *data; - if (data + len > end) { + if (data + len + 1 > end) { zlog_err("%pBP: Received invalid FQDN capability length (domain name) %d", peer, len); return; @@ -3557,7 +3694,7 @@ static void bgp_dynamic_capability_software_version(uint8_t *pnt, int action, char soft_version[BGP_MAX_SOFT_VERSION + 1] = {}; if (action == CAPABILITY_ACTION_SET) { - if (data + len > end) { + if (data + len + 1 > end) { zlog_err("%pBP: Received invalid Software Version capability length %d", peer, len); return; @@ -3610,7 +3747,10 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, zlog_err("%pBP: Capability length error", peer); bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); - pnt += length; + /* + * If we did not return then + * pnt += length; + */ return BGP_Stop; } action = *pnt; @@ -3635,7 +3775,10 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, zlog_err("%pBP: Capability length error", peer); bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); - pnt += length; + /* + * If we did not return then + * pnt += length; + */ return BGP_Stop; } @@ -3645,6 +3788,46 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, capability = lookup_msg(capcode_str, hdr->code, "Unknown"); + /* Length sanity check, type-specific, for known capabilities */ + switch (hdr->code) { + case CAPABILITY_CODE_MP: + case CAPABILITY_CODE_REFRESH: + case CAPABILITY_CODE_ORF: + case CAPABILITY_CODE_RESTART: + case CAPABILITY_CODE_AS4: + case CAPABILITY_CODE_ADDPATH: + case CAPABILITY_CODE_DYNAMIC: + case CAPABILITY_CODE_ENHE: + case CAPABILITY_CODE_FQDN: + case CAPABILITY_CODE_ENHANCED_RR: + case CAPABILITY_CODE_EXT_MESSAGE: + case CAPABILITY_CODE_ROLE: + case CAPABILITY_CODE_SOFT_VERSION: + case CAPABILITY_CODE_PATHS_LIMIT: + if (hdr->length < cap_minsizes[hdr->code]) { + zlog_info("%pBP: %s Capability length error: got %u, expected at least %u", + peer, capability, hdr->length, + (unsigned int)cap_minsizes[hdr->code]); + bgp_notify_send(peer->connection, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_MALFORMED_ATTR); + goto done; + } + if (hdr->length && + hdr->length % cap_modsizes[hdr->code] != 0) { + zlog_info("%pBP %s Capability length error: got %u, expected a multiple of %u", + peer, capability, hdr->length, + (unsigned int)cap_modsizes[hdr->code]); + bgp_notify_send(peer->connection, + BGP_NOTIFY_OPEN_ERR, + BGP_NOTIFY_OPEN_MALFORMED_ATTR); + goto done; + } + break; + default: + break; + } + switch (hdr->code) { case CAPABILITY_CODE_SOFT_VERSION: bgp_dynamic_capability_software_version(pnt, action, @@ -3702,15 +3885,6 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, } break; case CAPABILITY_CODE_RESTART: - if ((hdr->length - 2) % 4) { - zlog_err("%pBP: Received invalid Graceful-Restart capability length %d", - peer, hdr->length); - bgp_notify_send(peer->connection, - BGP_NOTIFY_CEASE, - BGP_NOTIFY_SUBCODE_UNSPECIFIC); - goto done; - } - bgp_dynamic_capability_graceful_restart(pnt, action, hdr, peer); break; @@ -3720,6 +3894,10 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, case CAPABILITY_CODE_ADDPATH: bgp_dynamic_capability_addpath(pnt, action, hdr, peer); break; + case CAPABILITY_CODE_PATHS_LIMIT: + bgp_dynamic_capability_paths_limit(pnt, action, hdr, + peer); + break; case CAPABILITY_CODE_ORF: bgp_dynamic_capability_orf(pnt, action, hdr, peer); break; @@ -3734,26 +3912,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, case CAPABILITY_CODE_EXT_MESSAGE: break; case CAPABILITY_CODE_ROLE: - if (hdr->length != CAPABILITY_CODE_ROLE_LEN) { - zlog_err("%pBP: Capability (%s) length error", - peer, capability); - bgp_notify_send(peer->connection, - BGP_NOTIFY_CEASE, - BGP_NOTIFY_SUBCODE_UNSPECIFIC); - goto done; - } - - uint8_t role; - - if (action == CAPABILITY_ACTION_SET) { - SET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); - memcpy(&role, pnt + 3, sizeof(role)); - - peer->remote_role = role; - } else { - UNSET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); - peer->remote_role = ROLE_UNDEFINED; - } + bgp_dynamic_capability_role(pnt, action, peer); break; default: flog_warn(EC_BGP_UNRECOGNIZED_CAPABILITY, @@ -3790,8 +3949,8 @@ int bgp_capability_receive(struct peer_connection *connection, if (bgp_debug_neighbor_events(peer)) zlog_debug("%s rcv CAPABILITY", peer->host); - /* If peer does not have the capability, send notification. */ - if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV)) { + if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV) || + !CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV)) { flog_err(EC_BGP_NO_CAP, "%s [Error] BGP dynamic capability is not enabled", peer->host); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index a69d6ee..f6fe87e 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -114,6 +114,46 @@ static const struct message bgp_pmsi_tnltype_str[] = { #define VRFID_NONE_STR "-" #define SOFT_RECONFIG_TASK_MAX_PREFIX 25000 +static inline char *bgp_route_dump_path_info_flags(struct bgp_path_info *pi, + char *buf, size_t len) +{ + uint32_t flags = pi->flags; + + if (flags == 0) { + snprintfrr(buf, len, "None "); + return buf; + } + + snprintfrr(buf, len, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + CHECK_FLAG(flags, BGP_PATH_IGP_CHANGED) ? "IGP Changed " : "", + CHECK_FLAG(flags, BGP_PATH_DAMPED) ? "Damped" : "", + CHECK_FLAG(flags, BGP_PATH_HISTORY) ? "History " : "", + CHECK_FLAG(flags, BGP_PATH_SELECTED) ? "Selected " : "", + CHECK_FLAG(flags, BGP_PATH_VALID) ? "Valid " : "", + CHECK_FLAG(flags, BGP_PATH_ATTR_CHANGED) ? "Attr Changed " + : "", + CHECK_FLAG(flags, BGP_PATH_DMED_CHECK) ? "Dmed Check " : "", + CHECK_FLAG(flags, BGP_PATH_DMED_SELECTED) ? "Dmed Selected " + : "", + CHECK_FLAG(flags, BGP_PATH_STALE) ? "Stale " : "", + CHECK_FLAG(flags, BGP_PATH_REMOVED) ? "Removed " : "", + CHECK_FLAG(flags, BGP_PATH_COUNTED) ? "Counted " : "", + CHECK_FLAG(flags, BGP_PATH_MULTIPATH) ? "Mpath " : "", + CHECK_FLAG(flags, BGP_PATH_MULTIPATH_CHG) ? "Mpath Chg " : "", + CHECK_FLAG(flags, BGP_PATH_RIB_ATTR_CHG) ? "Rib Chg " : "", + CHECK_FLAG(flags, BGP_PATH_ANNC_NH_SELF) ? "NH Self " : "", + CHECK_FLAG(flags, BGP_PATH_LINK_BW_CHG) ? "LinkBW Chg " : "", + CHECK_FLAG(flags, BGP_PATH_ACCEPT_OWN) ? "Accept Own " : "", + CHECK_FLAG(flags, BGP_PATH_MPLSVPN_LABEL_NH) ? "MPLS Label " + : "", + CHECK_FLAG(flags, BGP_PATH_MPLSVPN_NH_LABEL_BIND) + ? "MPLS Label Bind " + : "", + CHECK_FLAG(flags, BGP_PATH_UNSORTED) ? "Unsorted " : ""); + + return buf; +} + DEFINE_HOOK(bgp_process, (struct bgp * bgp, afi_t afi, safi_t safi, struct bgp_dest *bn, struct peer *peer, bool withdraw), @@ -195,8 +235,6 @@ static struct bgp_path_info_extra *bgp_path_info_extra_new(void) struct bgp_path_info_extra *new; new = XCALLOC(MTYPE_BGP_ROUTE_EXTRA, sizeof(struct bgp_path_info_extra)); - new->label[0] = MPLS_INVALID_LABEL; - new->num_labels = 0; new->flowspec = NULL; return new; } @@ -209,10 +247,9 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra) return; e = *extra; - if (e->damp_info) - bgp_damp_info_free(e->damp_info, 0, e->damp_info->afi, - e->damp_info->safi); + if (e->damp_info) + bgp_damp_info_free(e->damp_info, NULL, 0); e->damp_info = NULL; if (e->vrfleak && e->vrfleak->parent) { struct bgp_path_info *bpi = @@ -268,6 +305,9 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra) XFREE(MTYPE_BGP_ROUTE_EXTRA_VNC, e->vnc); #endif + if (e->labels) + bgp_labels_unintern(&e->labels); + XFREE(MTYPE_BGP_ROUTE_EXTRA, *extra); } @@ -285,6 +325,41 @@ struct bgp_path_info_extra *bgp_path_info_extra_get(struct bgp_path_info *pi) return pi->extra; } +bool bgp_path_info_has_valid_label(const struct bgp_path_info *path) +{ + if (!bgp_path_info_num_labels(path)) + return false; + + return bgp_is_valid_label(&path->extra->labels->label[0]); +} + +bool bgp_path_info_labels_same(const struct bgp_path_info *bpi, + const mpls_label_t *label, uint32_t n) +{ + uint8_t bpi_num_labels; + const mpls_label_t *bpi_label; + + bpi_num_labels = bgp_path_info_num_labels(bpi); + bpi_label = bpi_num_labels ? bpi->extra->labels->label : NULL; + + return bgp_labels_same(bpi_label, bpi_num_labels, + (const mpls_label_t *)label, n); +} + +uint8_t bgp_path_info_num_labels(const struct bgp_path_info *pi) +{ + if (!pi) + return 0; + + if (!pi->extra) + return 0; + + if (!pi->extra->labels) + return 0; + + return pi->extra->labels->num_labels; +} + /* Free bgp route information. */ void bgp_path_info_free_with_caller(const char *name, struct bgp_path_info *path) @@ -442,10 +517,13 @@ void bgp_path_info_add_with_caller(const char *name, struct bgp_dest *dest, top->prev = pi; bgp_dest_set_bgp_path_info(dest, pi); + SET_FLAG(pi->flags, BGP_PATH_UNSORTED); bgp_path_info_lock(pi); bgp_dest_lock_node(dest); peer_lock(pi->peer); /* bgp_path_info peer reference */ bgp_dest_set_defer_flag(dest, false); + if (pi->peer) + pi->peer->stat_pfx_loc_rib++; hook_call(bgp_snmp_update_stats, dest, pi, true); } @@ -462,8 +540,30 @@ struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest, bgp_dest_set_bgp_path_info(dest, pi->next); bgp_path_info_mpath_dequeue(pi); + + pi->next = NULL; + pi->prev = NULL; + + if (pi->peer) + pi->peer->stat_pfx_loc_rib--; + hook_call(bgp_snmp_update_stats, dest, pi, false); + bgp_path_info_unlock(pi); + return bgp_dest_unlock_node(dest); +} + +static struct bgp_dest *bgp_path_info_reap_unsorted(struct bgp_dest *dest, + struct bgp_path_info *pi) +{ + bgp_path_info_mpath_dequeue(pi); + + pi->next = NULL; + pi->prev = NULL; + + if (pi->peer) + pi->peer->stat_pfx_loc_rib--; hook_call(bgp_snmp_update_stats, dest, pi, false); + bgp_path_info_unlock(pi); return bgp_dest_unlock_node(dest); } @@ -581,6 +681,11 @@ void bgp_path_info_path_with_addpath_rx_str(struct bgp_path_info *pi, char *buf, { struct peer *peer; + if (!pi) { + snprintf(buf, buf_len, "NONE"); + return; + } + if (pi->sub_type == BGP_ROUTE_IMPORTED && bgp_get_imported_bpi_ultimate(pi)) peer = bgp_get_imported_bpi_ultimate(pi)->peer; @@ -683,12 +788,18 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (debug) { + char buf1[256], buf2[256]; + bpi_ultimate = bgp_get_imported_bpi_ultimate(exist); bgp_path_info_path_with_addpath_rx_str(bpi_ultimate, exist_buf, sizeof(exist_buf)); - zlog_debug("%s(%s): Comparing %s flags 0x%x with %s flags 0x%x", - pfx_buf, bgp->name_pretty, new_buf, new->flags, - exist_buf, exist->flags); + zlog_debug("%s(%s): Comparing %s flags %s with %s flags %s", + pfx_buf, bgp->name_pretty, new_buf, + bgp_route_dump_path_info_flags(new, buf1, + sizeof(buf1)), + exist_buf, + bgp_route_dump_path_info_flags(exist, buf2, + sizeof(buf2))); } newattr = new->attr; @@ -1284,25 +1395,18 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, /* If one path has a label but the other does not, do not treat * them as equals for multipath */ - int newl, existl; - - newl = existl = 0; - - if (new->extra) - newl = new->extra->num_labels; - if (exist->extra) - existl = exist->extra->num_labels; - if (((new->extra &&bgp_is_valid_label(&new->extra->label[0])) != - (exist->extra && - bgp_is_valid_label(&exist->extra->label[0]))) || - (newl != existl)) { + bool new_label_valid, exist_label_valid; + + new_label_valid = bgp_path_info_has_valid_label(new); + exist_label_valid = bgp_path_info_has_valid_label(exist); + + if (new_label_valid != exist_label_valid) { if (debug) zlog_debug( "%s: %s and %s cannot be multipath, one has a label while the other does not", pfx_buf, new_buf, exist_buf); } else if (CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) { - /* * For the two paths, all comparison steps till IGP * metric @@ -1768,11 +1872,12 @@ static bool bgp_check_role_applicability(afi_t afi, safi_t safi) static int bgp_input_modifier(struct peer *peer, const struct prefix *p, struct attr *attr, afi_t afi, safi_t safi, const char *rmap_name, mpls_label_t *label, - uint32_t num_labels, struct bgp_dest *dest) + uint8_t num_labels, struct bgp_dest *dest) { struct bgp_filter *filter; struct bgp_path_info rmap_path = { 0 }; struct bgp_path_info_extra extra = { 0 }; + struct bgp_labels bgp_labels = {}; route_map_result_t ret; struct route_map *rmap = NULL; @@ -1804,11 +1909,12 @@ static int bgp_input_modifier(struct peer *peer, const struct prefix *p, rmap_path.attr = attr; rmap_path.extra = &extra; rmap_path.net = dest; + extra.labels = &bgp_labels; - extra.num_labels = num_labels; + bgp_labels.num_labels = num_labels; if (label && num_labels && num_labels <= BGP_MAX_LABELS) - memcpy(extra.label, label, - num_labels * sizeof(mpls_label_t)); + memcpy(bgp_labels.label, label, + num_labels * sizeof(mpls_label_t)); SET_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN); @@ -2143,8 +2249,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, * off box as that the RT and RD created are localy * significant and globaly useless. */ - if (safi == SAFI_MPLS_VPN && pi->extra && pi->extra->num_labels - && pi->extra->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK) + if (safi == SAFI_MPLS_VPN && bgp_path_info_num_labels(pi) && + pi->extra->labels->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK) return false; /* If it's labeled safi, make sure the route has a valid label. */ @@ -2246,7 +2352,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, } /* AS path loop check. */ - if (peer->as_path_loop_detection && + if (CHECK_FLAG(peer->flags, PEER_FLAG_AS_LOOP_DETECTION) && aspath_loop_check(piattr->aspath, peer->as)) { if (bgp_debug_update(NULL, p, subgrp->update_group, 0)) zlog_debug( @@ -2701,17 +2807,26 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, * the most sense. However, don't modify if the link-bandwidth has * been explicitly set by user policy. */ - if (nh_reset && - bgp_path_info_mpath_chkwtd(bgp, pi) && + if (nh_reset && bgp_path_info_mpath_chkwtd(bgp, pi) && (cum_bw = bgp_path_info_mpath_cumbw(pi)) != 0 && - !CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_LINK_BW_SET)) - bgp_attr_set_ecommunity( - attr, - ecommunity_replace_linkbw( - bgp->as, bgp_attr_get_ecommunity(attr), cum_bw, - CHECK_FLAG( - peer->flags, - PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE))); + !CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_LINK_BW_SET)) { + if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_LINK_BANDWIDTH)) + bgp_attr_set_ipv6_ecommunity( + attr, + ecommunity_replace_linkbw(bgp->as, + bgp_attr_get_ipv6_ecommunity( + attr), + cum_bw, false, true)); + else + bgp_attr_set_ecommunity( + attr, + ecommunity_replace_linkbw( + bgp->as, bgp_attr_get_ecommunity(attr), + cum_bw, + CHECK_FLAG(peer->flags, + PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE), + false)); + } return true; } @@ -2740,17 +2855,18 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, struct bgp_path_info_pair *result, afi_t afi, safi_t safi) { - struct bgp_path_info *new_select; - struct bgp_path_info *old_select; + struct bgp_path_info *new_select, *look_thru; + struct bgp_path_info *old_select, *worse, *first; struct bgp_path_info *pi; struct bgp_path_info *pi1; struct bgp_path_info *pi2; - struct bgp_path_info *nextpi = NULL; int paths_eq, do_mpath; - bool debug; + bool debug, any_comparisons; struct list mp_list; char pfx_buf[PREFIX2STR_BUFFER] = {}; char path_buf[PATH_ADDPATH_STR_BUFFER]; + enum bgp_path_selection_reason reason = bgp_path_selection_none; + bool unsorted_items = true; bgp_mp_list_init(&mp_list); do_mpath = @@ -2761,16 +2877,16 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, if (debug) prefix2str(bgp_dest_get_prefix(dest), pfx_buf, sizeof(pfx_buf)); - dest->reason = bgp_path_selection_none; /* bgp deterministic-med */ new_select = NULL; if (CHECK_FLAG(bgp->flags, BGP_FLAG_DETERMINISTIC_MED)) { - /* Clear BGP_PATH_DMED_SELECTED for all paths */ for (pi1 = bgp_dest_get_bgp_path_info(dest); pi1; - pi1 = pi1->next) + pi1 = pi1->next) { bgp_path_info_unset_flag(dest, pi1, BGP_PATH_DMED_SELECTED); + UNSET_FLAG(pi1->flags, BGP_PATH_DMED_CHECK); + } for (pi1 = bgp_dest_get_bgp_path_info(dest); pi1; pi1 = pi1->next) { @@ -2786,41 +2902,35 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, } new_select = pi1; - if (pi1->next) { - for (pi2 = pi1->next; pi2; pi2 = pi2->next) { - if (CHECK_FLAG(pi2->flags, - BGP_PATH_DMED_CHECK)) - continue; - if (BGP_PATH_HOLDDOWN(pi2)) - continue; - if (pi2->peer != bgp->peer_self && - !CHECK_FLAG(pi2->peer->sflags, - PEER_STATUS_NSF_WAIT) && - !peer_established( - pi2->peer->connection)) - continue; - - if (!aspath_cmp_left(pi1->attr->aspath, - pi2->attr->aspath) - && !aspath_cmp_left_confed( - pi1->attr->aspath, - pi2->attr->aspath)) - continue; + for (pi2 = pi1->next; pi2; pi2 = pi2->next) { + if (CHECK_FLAG(pi2->flags, BGP_PATH_DMED_CHECK)) + continue; + if (BGP_PATH_HOLDDOWN(pi2)) + continue; + if (pi2->peer != bgp->peer_self && + !CHECK_FLAG(pi2->peer->sflags, + PEER_STATUS_NSF_WAIT) && + !peer_established(pi2->peer->connection)) + continue; - if (bgp_path_info_cmp( - bgp, pi2, new_select, - &paths_eq, mpath_cfg, debug, - pfx_buf, afi, safi, - &dest->reason)) { - bgp_path_info_unset_flag( - dest, new_select, - BGP_PATH_DMED_SELECTED); - new_select = pi2; - } + if (!aspath_cmp_left(pi1->attr->aspath, + pi2->attr->aspath) && + !aspath_cmp_left_confed(pi1->attr->aspath, + pi2->attr->aspath)) + continue; - bgp_path_info_set_flag( - dest, pi2, BGP_PATH_DMED_CHECK); + if (bgp_path_info_cmp(bgp, pi2, new_select, + &paths_eq, mpath_cfg, + debug, pfx_buf, afi, safi, + &dest->reason)) { + bgp_path_info_unset_flag(dest, + new_select, + BGP_PATH_DMED_SELECTED); + new_select = pi2; } + + bgp_path_info_set_flag(dest, pi2, + BGP_PATH_DMED_CHECK); } bgp_path_info_set_flag(dest, new_select, BGP_PATH_DMED_CHECK); @@ -2839,69 +2949,273 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, } } - /* Check old selected route and new selected route. */ + /* + * Let's grab the unsorted items from the list + */ + struct bgp_path_info *unsorted_list = NULL; + struct bgp_path_info *unsorted_list_spot = NULL; + struct bgp_path_info *unsorted_holddown = NULL; + old_select = NULL; - new_select = NULL; - for (pi = bgp_dest_get_bgp_path_info(dest); - (pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) { - enum bgp_path_selection_reason reason; + pi = bgp_dest_get_bgp_path_info(dest); + while (pi && CHECK_FLAG(pi->flags, BGP_PATH_UNSORTED)) { + struct bgp_path_info *next = pi->next; if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) old_select = pi; - if (BGP_PATH_HOLDDOWN(pi)) { - /* reap REMOVED routes, if needs be + /* + * Pull off pi off the list + */ + if (pi->next) + pi->next->prev = NULL; + + bgp_dest_set_bgp_path_info(dest, pi->next); + pi->next = NULL; + pi->prev = NULL; + + /* + * Place it on the unsorted list + */ + if (unsorted_list_spot) { + unsorted_list_spot->next = pi; + pi->prev = unsorted_list_spot; + pi->next = NULL; + } else { + unsorted_list = pi; + + pi->next = NULL; + pi->prev = NULL; + } + + unsorted_list_spot = pi; + pi = next; + } + + if (!old_select) { + old_select = bgp_dest_get_bgp_path_info(dest); + if (old_select && + !CHECK_FLAG(old_select->flags, BGP_PATH_SELECTED)) + old_select = NULL; + } + + if (!unsorted_list) + unsorted_items = true; + else + unsorted_items = false; + + any_comparisons = false; + worse = NULL; + while (unsorted_list) { + first = unsorted_list; + unsorted_list = unsorted_list->next; + + if (unsorted_list) + unsorted_list->prev = NULL; + first->next = NULL; + first->prev = NULL; + + /* + * It's not likely that the just received unsorted entry + * is in holddown and scheduled for removal but we should + * check + */ + if (BGP_PATH_HOLDDOWN(first)) { + /* + * reap REMOVED routes, if needs be * selected route must stay for a while longer though */ if (debug) - zlog_debug( - "%s: %pBD(%s) pi from %s in holddown", - __func__, dest, bgp->name_pretty, - pi->peer->host); + zlog_debug("%s: %pBD(%s) pi %p from %s in holddown", + __func__, dest, bgp->name_pretty, + first, first->peer->host); - if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED) && - (pi != old_select)) { - dest = bgp_path_info_reap(dest, pi); + if (old_select != first && + CHECK_FLAG(first->flags, BGP_PATH_REMOVED)) { + dest = bgp_path_info_reap_unsorted(dest, first); assert(dest); - } + } else { + /* + * We are in hold down, so we cannot sort this + * item yet. Let's wait, so hold the unsorted + * to the side + */ + if (unsorted_holddown) { + first->next = unsorted_holddown; + unsorted_holddown->prev = first; + unsorted_holddown = first; + } else + unsorted_holddown = first; + UNSET_FLAG(first->flags, BGP_PATH_UNSORTED); + } continue; } - if (pi->peer && pi->peer != bgp->peer_self - && !CHECK_FLAG(pi->peer->sflags, PEER_STATUS_NSF_WAIT)) - if (!peer_established(pi->peer->connection)) { + bgp_path_info_unset_flag(dest, first, BGP_PATH_DMED_CHECK); + + worse = NULL; + + struct bgp_path_info *look_thru_next; + + for (look_thru = bgp_dest_get_bgp_path_info(dest); look_thru; + look_thru = look_thru_next) { + /* look thru can be reaped save the next pointer */ + look_thru_next = look_thru->next; + + /* + * Now we have the first unsorted and the best selected + * Let's do best path comparison + */ + if (BGP_PATH_HOLDDOWN(look_thru)) { + /* reap REMOVED routes, if needs be + * selected route must stay for a while longer though + */ if (debug) - zlog_debug( - "%s: %pBD(%s) non self peer %s not estab state", - __func__, dest, - bgp->name_pretty, - pi->peer->host); + zlog_debug("%s: %pBD(%s) pi from %s %p in holddown", + __func__, dest, + bgp->name_pretty, + look_thru->peer->host, + look_thru); + + if (CHECK_FLAG(look_thru->flags, + BGP_PATH_REMOVED) && + (look_thru != old_select)) { + dest = bgp_path_info_reap(dest, + look_thru); + assert(dest); + } continue; } - if (CHECK_FLAG(bgp->flags, BGP_FLAG_DETERMINISTIC_MED) - && (!CHECK_FLAG(pi->flags, BGP_PATH_DMED_SELECTED))) { - bgp_path_info_unset_flag(dest, pi, BGP_PATH_DMED_CHECK); - if (debug) - zlog_debug("%s: %pBD(%s) pi %s dmed", __func__, - dest, bgp->name_pretty, - pi->peer->host); - continue; + if (look_thru->peer && + look_thru->peer != bgp->peer_self && + !CHECK_FLAG(look_thru->peer->sflags, + PEER_STATUS_NSF_WAIT)) + if (!peer_established( + look_thru->peer->connection)) { + if (debug) + zlog_debug("%s: %pBD(%s) non self peer %s not estab state", + __func__, dest, + bgp->name_pretty, + look_thru->peer->host); + + continue; + } + + bgp_path_info_unset_flag(dest, look_thru, + BGP_PATH_DMED_CHECK); + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DETERMINISTIC_MED) && + (!CHECK_FLAG(look_thru->flags, + BGP_PATH_DMED_SELECTED))) { + bgp_path_info_unset_flag(dest, look_thru, + BGP_PATH_DMED_CHECK); + if (debug) + zlog_debug("%s: %pBD(%s) pi %s dmed", + __func__, dest, + bgp->name_pretty, + look_thru->peer->host); + + worse = look_thru; + continue; + } + + reason = dest->reason; + any_comparisons = true; + if (bgp_path_info_cmp(bgp, first, look_thru, &paths_eq, + mpath_cfg, debug, pfx_buf, afi, + safi, &reason)) { + first->reason = reason; + worse = look_thru; + /* + * We can stop looking + */ + break; + } + + look_thru->reason = reason; } - bgp_path_info_unset_flag(dest, pi, BGP_PATH_DMED_CHECK); + if (!any_comparisons) + first->reason = bgp_path_selection_first; + + /* + * At this point worse if NON-NULL is where the first + * pointer should be before. if worse is NULL then + * first is bestpath too. Let's remove first from the + * list and place it in the right spot + */ + + if (!worse) { + struct bgp_path_info *end = + bgp_dest_get_bgp_path_info(dest); + + for (; end && end->next != NULL; end = end->next) + ; + + if (end) + end->next = first; + else + bgp_dest_set_bgp_path_info(dest, first); + first->prev = end; + first->next = NULL; + + dest->reason = first->reason; + } else { + if (worse->prev) + worse->prev->next = first; + first->next = worse; + if (worse) { + first->prev = worse->prev; + worse->prev = first; + } else + first->prev = NULL; - reason = dest->reason; - if (bgp_path_info_cmp(bgp, pi, new_select, &paths_eq, mpath_cfg, - debug, pfx_buf, afi, safi, - &dest->reason)) { - if (new_select == NULL && - reason != bgp_path_selection_none) - dest->reason = reason; - new_select = pi; + if (dest->info == worse) { + bgp_dest_set_bgp_path_info(dest, first); + dest->reason = first->reason; + } } + UNSET_FLAG(first->flags, BGP_PATH_UNSORTED); + } + + if (!unsorted_items) { + new_select = bgp_dest_get_bgp_path_info(dest); + while (new_select && BGP_PATH_HOLDDOWN(new_select)) + new_select = new_select->next; + + if (new_select) { + if (new_select->reason == bgp_path_selection_none) + new_select->reason = bgp_path_selection_first; + else if (new_select == bgp_dest_get_bgp_path_info(dest) && + new_select->next == NULL) + new_select->reason = bgp_path_selection_first; + dest->reason = new_select->reason; + } else + dest->reason = bgp_path_selection_none; + } else + new_select = old_select; + + + /* + * Reinsert all the unsorted_holddown items for future processing + * at the end of the list. + */ + if (unsorted_holddown) { + struct bgp_path_info *top = bgp_dest_get_bgp_path_info(dest); + struct bgp_path_info *prev = NULL; + + while (top != NULL) { + prev = top; + top = top->next; + } + + if (prev) { + prev->next = unsorted_holddown; + unsorted_holddown->prev = prev; + } else + bgp_dest_set_bgp_path_info(dest, unsorted_holddown); } /* Now that we know which path is the bestpath see if any of the other @@ -2909,11 +3223,8 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, * qualify as multipaths */ if (debug) { - if (new_select) - bgp_path_info_path_with_addpath_rx_str( - new_select, path_buf, sizeof(path_buf)); - else - snprintf(path_buf, sizeof(path_buf), "NONE"); + bgp_path_info_path_with_addpath_rx_str(new_select, path_buf, + sizeof(path_buf)); zlog_debug( "%pBD(%s): After path selection, newbest is %s oldbest was %s", dest, bgp->name_pretty, path_buf, @@ -2921,9 +3232,7 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, } if (do_mpath && new_select) { - for (pi = bgp_dest_get_bgp_path_info(dest); - (pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) { - + for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { if (debug) bgp_path_info_path_with_addpath_rx_str( pi, path_buf, sizeof(path_buf)); @@ -3177,8 +3486,7 @@ static bool bgp_lu_need_null_label(struct bgp *bgp, || new_select->sub_type == BGP_ROUTE_AGGREGATE || new_select->sub_type == BGP_ROUTE_REDISTRIBUTE) goto need_null_label; - else if (new_select->extra && - bgp_is_valid_label(&new_select->extra->label[0])) + else if (bgp_path_info_has_valid_label(new_select)) return false; need_null_label: if (label == NULL) @@ -3355,7 +3663,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, return; } +#ifdef ENABLE_BGP_VNC const struct prefix *p = bgp_dest_get_prefix(dest); +#endif debug = bgp_debug_bestpath(dest); if (debug) @@ -3418,9 +3728,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, && (new_select->sub_type == BGP_ROUTE_NORMAL || new_select->sub_type == BGP_ROUTE_IMPORTED)) - - bgp_zebra_announce(dest, p, old_select, - bgp, afi, safi); + bgp_zebra_route_install(dest, old_select, + bgp, true, NULL, + false); } } @@ -3480,7 +3790,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, bgp_path_info_unset_flag(dest, old_select, BGP_PATH_SELECTED); if (new_select) { if (debug) - zlog_debug("%s: setting SELECTED flag", __func__); + zlog_debug("%s: %pBD setting SELECTED flag", __func__, + dest); bgp_path_info_set_flag(dest, new_select, BGP_PATH_SELECTED); bgp_path_info_unset_flag(dest, new_select, BGP_PATH_ATTR_CHANGED); @@ -3529,10 +3840,10 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, */ if (old_select && is_route_parent_evpn(old_select)) - bgp_zebra_withdraw(p, old_select, bgp, afi, - safi); + bgp_zebra_withdraw_actual(dest, old_select, bgp); - bgp_zebra_announce(dest, p, new_select, bgp, afi, safi); + bgp_zebra_route_install(dest, new_select, bgp, true, + NULL, false); } else { /* Withdraw the route from the kernel. */ if (old_select && old_select->type == ZEBRA_ROUTE_BGP @@ -3540,8 +3851,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, || old_select->sub_type == BGP_ROUTE_AGGREGATE || old_select->sub_type == BGP_ROUTE_IMPORTED)) - bgp_zebra_withdraw(p, old_select, bgp, afi, - safi); + bgp_zebra_route_install(dest, old_select, bgp, + false, NULL, false); } } @@ -3704,13 +4015,38 @@ static struct bgp_process_queue *bgp_processq_alloc(struct bgp *bgp) return pqnode; } -void bgp_process(struct bgp *bgp, struct bgp_dest *dest, afi_t afi, safi_t safi) +void bgp_process(struct bgp *bgp, struct bgp_dest *dest, + struct bgp_path_info *pi, afi_t afi, safi_t safi) { #define ARBITRARY_PROCESS_QLEN 10000 struct work_queue *wq = bgp->process_queue; struct bgp_process_queue *pqnode; int pqnode_reuse = 0; + /* + * Indicate that *this* pi is in an unsorted + * situation, even if the node is already + * scheduled. + */ + if (pi) { + struct bgp_path_info *first = bgp_dest_get_bgp_path_info(dest); + + SET_FLAG(pi->flags, BGP_PATH_UNSORTED); + + if (pi != first) { + if (pi->next) + pi->next->prev = pi->prev; + if (pi->prev) + pi->prev->next = pi->next; + + if (first) + first->prev = pi; + pi->next = first; + pi->prev = NULL; + bgp_dest_set_bgp_path_info(dest, pi); + } + } + /* already scheduled for processing? */ if (CHECK_FLAG(dest->flags, BGP_NODE_PROCESS_SCHEDULED)) return; @@ -3959,7 +4295,7 @@ void bgp_rib_remove(struct bgp_dest *dest, struct bgp_path_info *pi, } hook_call(bgp_process, peer->bgp, afi, safi, dest, peer, true); - bgp_process(peer->bgp, dest, afi, safi); + bgp_process(peer->bgp, dest, pi, afi, safi); } static void bgp_rib_withdraw(struct bgp_dest *dest, struct bgp_path_info *pi, @@ -3971,14 +4307,16 @@ static void bgp_rib_withdraw(struct bgp_dest *dest, struct bgp_path_info *pi, /* apply dampening, if result is suppressed, we'll be retaining * the bgp_path_info in the RIB for historical reference. */ - if (CHECK_FLAG(peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) - && peer->sort == BGP_PEER_EBGP) - if ((bgp_damp_withdraw(pi, dest, afi, safi, 0)) - == BGP_DAMP_SUPPRESSED) { - bgp_aggregate_decrement(peer->bgp, p, pi, afi, - safi); - return; + if (peer->sort == BGP_PEER_EBGP) { + if (get_active_bdc_from_pi(pi, afi, safi)) { + if (bgp_damp_withdraw(pi, dest, afi, safi, 0) == + BGP_DAMP_SUPPRESSED) { + bgp_aggregate_decrement(peer->bgp, p, pi, afi, + safi); + return; + } } + } #ifdef ENABLE_BGP_VNC if (safi == SAFI_MPLS_VPN) { @@ -4198,7 +4536,7 @@ static bool bgp_accept_own(struct peer *peer, afi_t afi, safi_t safi, void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, mpls_label_t *label, - uint32_t num_labels, int soft_reconfig, + uint8_t num_labels, int soft_reconfig, struct bgp_route_evpn *evpn) { int ret; @@ -4209,16 +4547,16 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, struct attr *attr_new; struct bgp_path_info *pi; struct bgp_path_info *new = NULL; - struct bgp_path_info_extra *extra; const char *reason; char pfx_buf[BGP_PRD_PATH_STRLEN]; int connected = 0; int do_loop_check = 1; - int has_valid_label = 0; afi_t nh_afi; bool force_evpn_import = false; safi_t orig_safi = safi; int allowas_in = 0; + struct bgp_labels bgp_labels = {}; + uint8_t i; if (frrtrace_enabled(frr_bgp, process_update)) { char pfxprint[PREFIX2STR_BUFFER]; @@ -4240,15 +4578,12 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, bgp = peer->bgp; dest = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, prd); - /* TODO: Check to see if we can get rid of "is_valid_label" */ - if (afi == AFI_L2VPN && safi == SAFI_EVPN) - has_valid_label = (num_labels > 0) ? 1 : 0; - else - has_valid_label = bgp_is_valid_label(label); - - if (has_valid_label) - assert(label != NULL); + if ((afi == AFI_L2VPN && safi == SAFI_EVPN) || + bgp_is_valid_label(&label[0])) + bgp_labels.num_labels = num_labels; + for (i = 0; i < bgp_labels.num_labels; i++) + bgp_labels.label[i] = label[i]; /* When peer's soft reconfiguration enabled. Record input packet in Adj-RIBs-In. */ @@ -4265,7 +4600,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, memcpy(&attr->evpn_overlay, evpn, sizeof(struct bgp_route_evpn)); } - bgp_adj_in_set(dest, peer, attr, addpath_id); + bgp_adj_in_set(dest, peer, attr, addpath_id, &bgp_labels); } /* Update permitted loop count */ @@ -4447,7 +4782,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, if (pi && pi->attr->rmap_table_id != new_attr.rmap_table_id) { if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) /* remove from RIB previous entry */ - bgp_zebra_withdraw(p, pi, bgp, afi, safi); + bgp_zebra_route_install(dest, pi, bgp, false, NULL, + false); } if (peer->sort == BGP_PEER_EBGP) { @@ -4541,15 +4877,12 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, /* Same attribute comes in. */ if (!CHECK_FLAG(pi->flags, BGP_PATH_REMOVED) && same_attr && - (!has_valid_label || - (bgp_path_info_extra_get(pi) && - bgp_labels_same((const mpls_label_t *)pi->extra->label, - pi->extra->num_labels, label, - num_labels)))) { - if (CHECK_FLAG(bgp->af_flags[afi][safi], - BGP_CONFIG_DAMPENING) - && peer->sort == BGP_PEER_EBGP - && CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) { + (!bgp_labels.num_labels || + bgp_path_info_labels_same(pi, bgp_labels.label, + bgp_labels.num_labels))) { + if (get_active_bdc_from_pi(pi, afi, safi) && + peer->sort == BGP_PEER_EBGP && + CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) { if (bgp_debug_update(peer, p, NULL, 1)) { bgp_debug_rdpfxpath2str( afi, safi, prd, p, label, @@ -4564,7 +4897,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, != BGP_DAMP_SUPPRESSED) { bgp_aggregate_increment(bgp, p, pi, afi, safi); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, pi, afi, safi); } } else /* Duplicate - odd */ { @@ -4592,7 +4925,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, bgp_path_info_unset_flag( dest, pi, BGP_PATH_STALE); bgp_dest_set_defer_flag(dest, false); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, pi, afi, safi); } } @@ -4650,11 +4983,11 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, bgp_path_info_set_flag(dest, pi, BGP_PATH_ATTR_CHANGED); /* Update bgp route dampening information. */ - if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) - && peer->sort == BGP_PEER_EBGP) { + if (get_active_bdc_from_pi(pi, afi, safi) && + peer->sort == BGP_PEER_EBGP) { /* This is implicit withdraw so we should update - dampening - information. */ + * dampening information. + */ if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) bgp_damp_withdraw(pi, dest, afi, safi, 1); } @@ -4728,17 +5061,11 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, pi->attr = attr_new; /* Update MPLS label */ - if (has_valid_label) { - extra = bgp_path_info_extra_get(pi); - if (!bgp_labels_same((const mpls_label_t *)extra->label, - extra->num_labels, label, - num_labels)) { - memcpy(&extra->label, label, - num_labels * sizeof(mpls_label_t)); - extra->num_labels = num_labels; - } - if (!(afi == AFI_L2VPN && safi == SAFI_EVPN)) - bgp_set_valid_label(&extra->label[0]); + if (!bgp_path_info_labels_same(pi, &bgp_labels.label[0], + bgp_labels.num_labels)) { + bgp_path_info_extra_get(pi); + bgp_labels_unintern(&pi->extra->labels); + pi->extra->labels = bgp_labels_intern(&bgp_labels); } #ifdef ENABLE_BGP_VNC @@ -4765,8 +5092,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, #endif /* Update bgp route dampening information. */ - if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING) - && peer->sort == BGP_PEER_EBGP) { + if (get_active_bdc_from_pi(pi, afi, safi) && + peer->sort == BGP_PEER_EBGP) { /* Now we do normal update dampening. */ ret = bgp_damp_update(pi, dest, afi, safi); if (ret == BGP_DAMP_SUPPRESSED) { @@ -4882,7 +5209,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, /* Process change. */ bgp_aggregate_increment(bgp, p, pi, afi, safi); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, pi, afi, safi); bgp_dest_unlock_node(dest); if (SAFI_UNICAST == safi @@ -4929,17 +5256,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, new = info_make(type, sub_type, 0, peer, attr_new, dest); /* Update MPLS label */ - if (has_valid_label) { - extra = bgp_path_info_extra_get(new); - if (!bgp_labels_same((const mpls_label_t *)extra->label, - extra->num_labels, label, num_labels)) { - memcpy(&extra->label, label, - num_labels * sizeof(mpls_label_t)); - extra->num_labels = num_labels; - } - if (!(afi == AFI_L2VPN && safi == SAFI_EVPN)) - bgp_set_valid_label(&extra->label[0]); - } + bgp_path_info_extra_get(new); + new->extra->labels = bgp_labels_intern(&bgp_labels); /* Nexthop reachability check. */ if (((afi == AFI_IP || afi == AFI_IP6) && @@ -5027,7 +5345,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, hook_call(bgp_process, bgp, afi, safi, dest, peer, false); /* Process change. */ - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, new, afi, safi); if (SAFI_UNICAST == safi && (bgp->inst_type == BGP_INSTANCE_TYPE_VRF @@ -5120,7 +5438,7 @@ filtered: void bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, mpls_label_t *label, - uint32_t num_labels, struct bgp_route_evpn *evpn) + uint8_t num_labels, struct bgp_route_evpn *evpn) { struct bgp *bgp; char pfx_buf[BGP_PRD_PATH_STRLEN]; @@ -5347,18 +5665,16 @@ static void bgp_soft_reconfig_table_update(struct peer *peer, safi_t safi, struct prefix_rd *prd) { struct bgp_path_info *pi; - uint32_t num_labels = 0; - mpls_label_t *label_pnt = NULL; + uint8_t num_labels; + mpls_label_t *label_pnt; struct bgp_route_evpn evpn; for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) if (pi->peer == peer) break; - if (pi && pi->extra) - num_labels = pi->extra->num_labels; - if (num_labels) - label_pnt = &pi->extra->label[0]; + num_labels = ain->labels ? ain->labels->num_labels : 0; + label_pnt = num_labels ? &ain->labels->label[0] : NULL; if (pi) memcpy(&evpn, bgp_attr_get_evpn_overlay(pi->attr), sizeof(evpn)); @@ -5598,7 +5914,7 @@ static wq_item_status bgp_clear_route_node(struct work_queue *wq, void *data) struct bgp_clear_node_queue *cnq = data; struct bgp_dest *dest = cnq->dest; struct peer *peer = wq->spec.data; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; struct bgp *bgp; afi_t afi = bgp_dest_table(dest)->afi; safi_t safi = bgp_dest_table(dest)->safi; @@ -5609,7 +5925,8 @@ static wq_item_status bgp_clear_route_node(struct work_queue *wq, void *data) /* It is possible that we have multiple paths for a prefix from a peer * if that peer is using AddPath. */ - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); + (pi != NULL) && (next = pi->next, 1); pi = next) { if (pi->peer != peer) continue; @@ -5871,7 +6188,7 @@ void bgp_clear_adj_in(struct peer *peer, afi_t afi, safi_t safi) void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) { struct bgp_dest *dest; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; struct bgp_table *table; if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) { @@ -5886,8 +6203,9 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) - for (pi = bgp_dest_get_bgp_path_info(rm); pi; - pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(rm); + (pi != NULL) && (next = pi->next, 1); + pi = next) { if (pi->peer != peer) continue; if (CHECK_FLAG( @@ -5920,8 +6238,8 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) } else { for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest; dest = bgp_route_next(dest)) - for (pi = bgp_dest_get_bgp_path_info(dest); pi; - pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); + (pi != NULL) && (next = pi->next, 1); pi = next) { if (pi->peer != peer) continue; if (CHECK_FLAG(peer->af_sflags[afi][safi], @@ -6024,7 +6342,8 @@ void bgp_set_stale_route(struct peer *peer, afi_t afi, safi_t safi) bool bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter) { - if (peer->sort == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_CONFED || peer->sort == BGP_PEER_IBGP || + peer->sub_sort == BGP_PEER_EBGP_OAD) return true; if (peer->sort == BGP_PEER_EBGP && @@ -6037,7 +6356,8 @@ bool bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter) bool bgp_inbound_policy_exists(struct peer *peer, struct bgp_filter *filter) { - if (peer->sort == BGP_PEER_IBGP) + if (peer->sort == BGP_PEER_CONFED || peer->sort == BGP_PEER_IBGP || + peer->sub_sort == BGP_PEER_EBGP_OAD) return true; if (peer->sort == BGP_PEER_EBGP @@ -6073,8 +6393,7 @@ static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table, || pi->sub_type == BGP_ROUTE_IMPORTED)) { if (bgp_fibupd_safi(safi)) - bgp_zebra_withdraw(p, pi, bgp, afi, - safi); + bgp_zebra_withdraw_actual(dest, pi, bgp); } dest = bgp_path_info_reap(dest, pi); @@ -6369,10 +6688,11 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, route_map_result_t ret; #ifdef ENABLE_BGP_VNC int vnc_implicit_withdraw = 0; - mpls_label_t label = 0; + mpls_label_t label = MPLS_INVALID_LABEL; #endif - uint32_t num_labels = 0; + uint8_t num_labels = 0; struct bgp *bgp_nexthop = bgp; + struct bgp_labels labels = {}; assert(bgp_static); @@ -6522,9 +6842,9 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, bgp, p, pi); } } else { - if (pi->extra) + if (bgp_path_info_num_labels(pi)) label = decode_label( - &pi->extra->label[0]); + &pi->extra->labels->label[0]); } #endif if (pi->extra && pi->extra->vrfleak->bgp_orig) @@ -6535,7 +6855,7 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, /* Process change. */ bgp_aggregate_increment(bgp, p, pi, afi, safi); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, pi, afi, safi); if (SAFI_MPLS_VPN == safi && bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) { @@ -6573,8 +6893,9 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, SET_FLAG(new->flags, BGP_PATH_VALID); bgp_path_info_extra_get(new); if (num_labels) { - new->extra->label[0] = bgp_static->label; - new->extra->num_labels = num_labels; + labels.num_labels = num_labels; + labels.label[0] = bgp_static->label; + new->extra->labels = bgp_labels_intern(&labels); } #ifdef ENABLE_BGP_VNC label = decode_label(&bgp_static->label); @@ -6593,7 +6914,7 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, bgp_dest_unlock_node(dest); /* Process change. */ - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, new, afi, safi); if (SAFI_UNICAST == safi && (bgp->inst_type == BGP_INSTANCE_TYPE_VRF || @@ -6632,6 +6953,7 @@ void bgp_static_withdraw(struct bgp *bgp, const struct prefix *p, afi_t afi, /* Withdraw static BGP route from routing table. */ if (pi) { + SET_FLAG(pi->flags, BGP_PATH_UNSORTED); #ifdef ENABLE_BGP_VNC if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) rfapiProcessWithdraw(pi->peer, NULL, p, prd, pi->attr, @@ -6650,7 +6972,7 @@ void bgp_static_withdraw(struct bgp *bgp, const struct prefix *p, afi_t afi, bgp_aggregate_decrement(bgp, p, pi, afi, safi); bgp_unlink_nexthop(pi); bgp_path_info_delete(dest, pi); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, pi, afi, safi); } /* Unlock bgp_node_lookup. */ @@ -7055,7 +7377,7 @@ static void bgp_purge_af_static_redist_routes(struct bgp *bgp, afi_t afi, safi); bgp_unlink_nexthop(pi); bgp_path_info_delete(dest, pi); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, pi, afi, safi); } } } @@ -7418,8 +7740,10 @@ static void bgp_aggregate_install( /* * Mark the old as unusable */ - if (pi) + if (pi) { bgp_path_info_delete(dest, pi); + bgp_process(bgp, dest, pi, afi, safi); + } attr = bgp_attr_aggregate_intern( bgp, origin, aspath, community, ecommunity, lcommunity, @@ -7444,7 +7768,7 @@ static void bgp_aggregate_install( SET_FLAG(new->flags, BGP_PATH_VALID); bgp_path_info_add(dest, new); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, new, afi, safi); } else { uninstall_aggregate_route: for (pi = orig; pi; pi = pi->next) @@ -7456,7 +7780,7 @@ static void bgp_aggregate_install( /* Withdraw static BGP route from routing table. */ if (pi) { bgp_path_info_delete(dest, pi); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, pi, afi, safi); } } @@ -7542,7 +7866,6 @@ void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate, const struct prefix *dest_p; struct bgp_dest *dest, *top; struct bgp_path_info *pi; - bool toggle_suppression; /* We've found a different MED we must revert any suppressed routes. */ top = bgp_node_get(table, p); @@ -7552,7 +7875,6 @@ void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate, if (dest_p->prefixlen <= p->prefixlen) continue; - toggle_suppression = false; for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { if (BGP_PATH_HOLDDOWN(pi)) continue; @@ -7563,17 +7885,14 @@ void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate, if (suppress) { /* Suppress route if not suppressed already. */ if (aggr_suppress_path(aggregate, pi)) - toggle_suppression = true; + bgp_process(bgp, dest, pi, afi, safi); continue; } /* Install route if there is no more suppression. */ if (aggr_unsuppress_path(aggregate, pi)) - toggle_suppression = true; + bgp_process(bgp, dest, pi, afi, safi); } - - if (toggle_suppression) - bgp_process(bgp, dest, afi, safi); } bgp_dest_unlock_node(top); } @@ -7632,7 +7951,6 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, struct ecommunity *ecommunity = NULL; struct lcommunity *lcommunity = NULL; struct bgp_path_info *pi; - unsigned long match = 0; uint8_t atomic_aggregate = 0; /* If the bgp instance is being deleted or self peer is deleted @@ -7682,8 +8000,6 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, if (!bgp_check_advertise(bgp, dest, safi)) continue; - match = 0; - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { if (BGP_PATH_HOLDDOWN(pi)) continue; @@ -7707,7 +8023,7 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, if (aggregate->summary_only && AGGREGATE_MED_VALID(aggregate)) { if (aggr_suppress_path(aggregate, pi)) - match++; + bgp_process(bgp, dest, pi, afi, safi); } /* @@ -7723,7 +8039,7 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, && AGGREGATE_MED_VALID(aggregate) && aggr_suppress_map_test(bgp, aggregate, pi)) { if (aggr_suppress_path(aggregate, pi)) - match++; + bgp_process(bgp, dest, pi, afi, safi); } aggregate->count++; @@ -7784,8 +8100,6 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, aggregate, bgp_attr_get_lcommunity(pi->attr)); } - if (match) - bgp_process(bgp, dest, afi, safi); } if (aggregate->as_set) { bgp_compute_aggregate_aspath_val(aggregate); @@ -7845,7 +8159,6 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi, struct bgp_dest *top; struct bgp_dest *dest; struct bgp_path_info *pi; - unsigned long match; table = bgp->rib[afi][safi]; @@ -7857,7 +8170,6 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi, if (dest_p->prefixlen <= p->prefixlen) continue; - match = 0; for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { if (BGP_PATH_HOLDDOWN(pi)) @@ -7875,10 +8187,11 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi, if (pi->extra && pi->extra->aggr_suppressors && listcount(pi->extra->aggr_suppressors)) { if (aggr_unsuppress_path(aggregate, pi)) - match++; + bgp_process(bgp, dest, pi, afi, safi); } - aggregate->count--; + if (aggregate->count > 0) + aggregate->count--; if (pi->attr->origin == BGP_ORIGIN_INCOMPLETE) aggregate->incomplete_origin_count--; @@ -7917,10 +8230,6 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi, pi->attr)); } } - - /* If this node was suppressed, process the change. */ - if (match) - bgp_process(bgp, dest, afi, safi); } if (aggregate->as_set) { aspath_free(aggregate->aspath); @@ -8069,7 +8378,6 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi, struct community *community = NULL; struct ecommunity *ecommunity = NULL; struct lcommunity *lcommunity = NULL; - unsigned long match = 0; /* If the bgp instance is being deleted or self peer is deleted * then do not create aggregate route @@ -8086,12 +8394,12 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi, if (aggregate->summary_only && AGGREGATE_MED_VALID(aggregate)) if (aggr_unsuppress_path(aggregate, pi)) - match++; + bgp_process(bgp, pi->net, pi, afi, safi); if (aggregate->suppress_map_name && AGGREGATE_MED_VALID(aggregate) && aggr_suppress_map_test(bgp, aggregate, pi)) if (aggr_unsuppress_path(aggregate, pi)) - match++; + bgp_process(bgp, pi->net, pi, afi, safi); /* * This must be called after `summary`, `suppress-map` check to avoid @@ -8133,10 +8441,6 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi, aggregate, bgp_attr_get_lcommunity(pi->attr)); } - /* If this node was suppressed, process the change. */ - if (match) - bgp_process(bgp, pi->net, afi, safi); - origin = BGP_ORIGIN_IGP; if (aggregate->incomplete_origin_count > 0) origin = BGP_ORIGIN_INCOMPLETE; @@ -8594,6 +8898,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, afi_t afi; route_map_result_t ret; struct bgp_redist *red; + struct interface *ifp; if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) || bgp->peer_self == NULL) @@ -8653,6 +8958,11 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, } attr.nh_type = nhtype; attr.nh_ifindex = ifindex; + ifp = if_lookup_by_index(ifindex, bgp->vrf_id); + if (ifp && if_is_operative(ifp)) + SET_FLAG(attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE); + else + UNSET_FLAG(attr.nh_flags, BGP_ATTR_NH_IF_OPERSTATE); attr.med = metric; attr.distance = distance; @@ -8740,7 +9050,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, /* Process change. */ bgp_aggregate_increment(bgp, p, bpi, afi, SAFI_UNICAST); - bgp_process(bgp, bn, afi, SAFI_UNICAST); + bgp_process(bgp, bn, bpi, afi, SAFI_UNICAST); bgp_dest_unlock_node(bn); aspath_unintern(&attr.aspath); @@ -8763,7 +9073,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, bgp_path_info_add(bn, new); bgp_dest_unlock_node(bn); SET_FLAG(bn->flags, BGP_NODE_FIB_INSTALLED); - bgp_process(bgp, bn, afi, SAFI_UNICAST); + bgp_process(bgp, bn, new, afi, SAFI_UNICAST); if ((bgp->inst_type == BGP_INSTANCE_TYPE_VRF) || (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) { @@ -8804,7 +9114,7 @@ void bgp_redistribute_delete(struct bgp *bgp, struct prefix *p, uint8_t type, } bgp_aggregate_decrement(bgp, p, pi, afi, SAFI_UNICAST); bgp_path_info_delete(dest, pi); - bgp_process(bgp, dest, afi, SAFI_UNICAST); + bgp_process(bgp, dest, pi, afi, SAFI_UNICAST); } bgp_dest_unlock_node(dest); } @@ -8838,7 +9148,7 @@ void bgp_redistribute_withdraw(struct bgp *bgp, afi_t afi, int type, bgp_path_info_delete(dest, pi); if (!CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS)) - bgp_process(bgp, dest, afi, SAFI_UNICAST); + bgp_process(bgp, dest, pi, afi, SAFI_UNICAST); else { dest = bgp_path_info_reap(dest, pi); assert(dest); @@ -8984,6 +9294,9 @@ static void route_vty_short_status_out(struct vty *vty, if (path->extra && bgp_path_suppressed(path)) json_object_boolean_true_add(json_path, "suppressed"); + if (CHECK_FLAG(path->flags, BGP_PATH_UNSORTED)) + json_object_boolean_true_add(json_path, "unsorted"); + if (CHECK_FLAG(path->flags, BGP_PATH_VALID) && !CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) json_object_boolean_true_add(json_path, "valid"); @@ -9046,6 +9359,8 @@ static void route_vty_short_status_out(struct vty *vty, /* Selected */ if (CHECK_FLAG(path->flags, BGP_PATH_HISTORY)) vty_out(vty, "h"); + else if (CHECK_FLAG(path->flags, BGP_PATH_UNSORTED)) + vty_out(vty, "u"); else if (CHECK_FLAG(path->flags, BGP_PATH_DAMPED)) vty_out(vty, "d"); else if (CHECK_FLAG(path->flags, BGP_PATH_SELECTED)) @@ -9061,6 +9376,9 @@ static void route_vty_short_status_out(struct vty *vty, vty_out(vty, "i"); else vty_out(vty, " "); + + /* adding space between next column */ + vty_out(vty, " "); } static char *bgp_nexthop_hostname(struct peer *peer, @@ -9341,10 +9659,8 @@ void route_vty_out(struct vty *vty, const struct prefix *p, json_object_string_add(json_nexthop_ll, "scope", "link-local"); - if ((IPV6_ADDR_CMP(&attr->mp_nexthop_global, - &attr->mp_nexthop_local) - != 0) - && !attr->mp_nexthop_prefer_global) + if (!CHECK_FLAG(attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) json_object_boolean_true_add( json_nexthop_ll, "used"); else @@ -9356,10 +9672,11 @@ void route_vty_out(struct vty *vty, const struct prefix *p, } else { /* Display LL if LL/Global both in table unless * prefer-global is set */ - if (((attr->mp_nexthop_len - == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) - && !attr->mp_nexthop_prefer_global) - || (path->peer->conf_if)) { + if (((attr->mp_nexthop_len == + BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) && + !CHECK_FLAG(attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) || + (path->peer->conf_if)) { if (path->peer->conf_if) { len = vty_out(vty, "%s", path->peer->conf_if); @@ -9764,8 +10081,8 @@ void route_vty_out_tag(struct vty *vty, const struct prefix *p, } } - if (bgp_is_valid_label(&path->extra->label[0])) { - label = decode_label(&path->extra->label[0]); + if (bgp_path_info_has_valid_label(path)) { + label = decode_label(&path->extra->labels->label[0]); if (json) { json_object_int_add(json_out, "notag", label); json_object_array_add(json, json_out); @@ -10155,7 +10472,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_object *json_paths) { char buf[INET6_ADDRSTRLEN]; - char tag_buf[30]; + char vni_buf[30] = {}; struct attr *attr = path->attr; time_t tbuf; char timebuf[32]; @@ -10163,6 +10480,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_object *json_cluster_list = NULL; json_object *json_cluster_list_list = NULL; json_object *json_ext_community = NULL; + json_object *json_ext_ipv6_community = NULL; json_object *json_last_update = NULL; json_object *json_pmsi = NULL; json_object *json_nexthop_global = NULL; @@ -10187,7 +10505,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, uint32_t bos = 0; uint32_t exp = 0; mpls_label_t label = MPLS_INVALID_LABEL; - tag_buf[0] = '\0'; struct bgp_path_info *bpi_ultimate = bgp_get_imported_bpi_ultimate(path); @@ -10197,26 +10514,22 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_nexthop_global = json_object_new_object(); } + if (bgp_path_info_num_labels(path)) { + bgp_evpn_label2str(path->extra->labels->label, + path->extra->labels->num_labels, vni_buf, + sizeof(vni_buf)); + } + if (safi == SAFI_EVPN) { if (!json_paths) vty_out(vty, " Route %pFX", p); - } - if (path->extra) { - if (path->extra && path->extra->num_labels) { - bgp_evpn_label2str(path->extra->label, - path->extra->num_labels, tag_buf, - sizeof(tag_buf)); - } - if (safi == SAFI_EVPN) { - if (!json_paths) { - if (tag_buf[0] != '\0') - vty_out(vty, " VNI %s", tag_buf); - } else { - if (tag_buf[0]) - json_object_string_add(json_path, "vni", - tag_buf); - } + if (vni_buf[0]) { + if (json_paths) + json_object_string_add(json_path, "vni", + vni_buf); + else + vty_out(vty, " VNI %s", vni_buf); } } @@ -10256,7 +10569,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, vty_out(vty, ":%pFX, VNI %s", (struct prefix_evpn *) bgp_dest_get_prefix(dest), - tag_buf); + vni_buf); if (CHECK_FLAG(attr->es_flags, ATTR_ES_L3_NHG)) vty_out(vty, ", L3NHG %s", CHECK_FLAG( @@ -10612,7 +10925,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_object_boolean_true_add(json_nexthop_ll, "accessible"); - if (!attr->mp_nexthop_prefer_global) + if (!CHECK_FLAG(attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) json_object_boolean_true_add(json_nexthop_ll, "used"); else @@ -10622,7 +10936,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, vty_out(vty, " (%s) %s\n", inet_ntop(AF_INET6, &attr->mp_nexthop_local, buf, INET6_ADDRSTRLEN), - attr->mp_nexthop_prefer_global + CHECK_FLAG(attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL) ? "(prefer-global)" : "(used)"); } @@ -10869,6 +11184,21 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } } + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_IPV6_EXT_COMMUNITIES)) { + if (json_paths) { + json_ext_ipv6_community = json_object_new_object(); + json_object_string_add(json_ext_ipv6_community, "string", + bgp_attr_get_ipv6_ecommunity(attr) + ->str); + json_object_object_add(json_path, + "extendedIpv6Community", + json_ext_ipv6_community); + } else { + vty_out(vty, " Extended IPv6 Community: %s\n", + bgp_attr_get_ipv6_ecommunity(attr)->str); + } + } + /* Line 6 display Large community */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) { if (json_paths) { @@ -10948,13 +11278,13 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } if (path->extra && path->extra->damp_info) - bgp_damp_info_vty(vty, path, afi, safi, json_path); + bgp_damp_info_vty(vty, bgp, path, afi, safi, json_path); /* Remote Label */ - if (path->extra && bgp_is_valid_label(&path->extra->label[0]) - && (safi != SAFI_EVPN && !is_route_parent_evpn(path))) { - mpls_lse_decode(path->extra->label[0], &label, &ttl, &exp, - &bos); + if (bgp_path_info_has_valid_label(path) && + (safi != SAFI_EVPN && !is_route_parent_evpn(path))) { + mpls_lse_decode(path->extra->labels->label[0], &label, &ttl, + &exp, &bos); if (json_paths) json_object_int_add(json_path, "remoteLabel", label); @@ -13686,21 +14016,23 @@ enum bgp_pcounts { PCOUNT_COUNTED, PCOUNT_BPATH_SELECTED, PCOUNT_PFCNT, /* the figure we display to users */ + PCOUNT_UNSORTED, PCOUNT_MAX, }; static const char *const pcount_strs[] = { - [PCOUNT_ADJ_IN] = "Adj-in", - [PCOUNT_DAMPED] = "Damped", - [PCOUNT_REMOVED] = "Removed", - [PCOUNT_HISTORY] = "History", - [PCOUNT_STALE] = "Stale", - [PCOUNT_VALID] = "Valid", - [PCOUNT_ALL] = "All RIB", - [PCOUNT_COUNTED] = "PfxCt counted", - [PCOUNT_BPATH_SELECTED] = "PfxCt Best Selected", - [PCOUNT_PFCNT] = "Useable", - [PCOUNT_MAX] = NULL, + [PCOUNT_ADJ_IN] = "Adj-in", + [PCOUNT_DAMPED] = "Damped", + [PCOUNT_REMOVED] = "Removed", + [PCOUNT_HISTORY] = "History", + [PCOUNT_STALE] = "Stale", + [PCOUNT_VALID] = "Valid", + [PCOUNT_ALL] = "All RIB", + [PCOUNT_COUNTED] = "PfxCt counted", + [PCOUNT_BPATH_SELECTED] = "PfxCt Best Selected", + [PCOUNT_PFCNT] = "Useable", + [PCOUNT_UNSORTED] = "Unsorted", + [PCOUNT_MAX] = NULL, }; struct peer_pcounts { @@ -13741,6 +14073,8 @@ static void bgp_peer_count_proc(struct bgp_dest *rn, struct peer_pcounts *pc) pc->count[PCOUNT_PFCNT]++; if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) pc->count[PCOUNT_BPATH_SELECTED]++; + if (CHECK_FLAG(pi->flags, BGP_PATH_UNSORTED)) + pc->count[PCOUNT_UNSORTED]++; if (CHECK_FLAG(pi->flags, BGP_PATH_COUNTED)) { pc->count[PCOUNT_COUNTED]++; @@ -15496,9 +15830,8 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name, while (pi) { if (pi->extra && pi->extra->damp_info) { pi_temp = pi->next; - bgp_damp_info_free( - pi->extra->damp_info, - 1, afi, safi); + bgp_damp_info_free(pi->extra->damp_info, + NULL, 1); pi = pi_temp; } else pi = pi->next; @@ -15509,26 +15842,38 @@ static int bgp_clear_damp_route(struct vty *vty, const char *view_name, } } else { dest = bgp_node_match(bgp->rib[afi][safi], &match); - if (dest != NULL) { - const struct prefix *dest_p = bgp_dest_get_prefix(dest); + if (!dest) + return CMD_SUCCESS; - if (!prefix_check - || dest_p->prefixlen == match.prefixlen) { - pi = bgp_dest_get_bgp_path_info(dest); - while (pi) { - if (pi->extra && pi->extra->damp_info) { - pi_temp = pi->next; - bgp_damp_info_free( - pi->extra->damp_info, - 1, afi, safi); - pi = pi_temp; - } else - pi = pi->next; - } + const struct prefix *dest_p = bgp_dest_get_prefix(dest); + + if (prefix_check || dest_p->prefixlen != match.prefixlen) + return CMD_SUCCESS; + + pi = bgp_dest_get_bgp_path_info(dest); + while (pi) { + if (!(pi->extra && pi->extra->damp_info)) { + pi = pi->next; + continue; } - bgp_dest_unlock_node(dest); + pi_temp = pi->next; + struct bgp_damp_info *bdi = pi->extra->damp_info; + + if (bdi->lastrecord != BGP_RECORD_UPDATE) + continue; + + bgp_aggregate_increment(bgp, + bgp_dest_get_prefix(bdi->dest), + bdi->path, bdi->afi, bdi->safi); + bgp_process(bgp, bdi->dest, bdi->path, bdi->afi, + bdi->safi); + + bgp_damp_info_free(pi->extra->damp_info, NULL, 1); + pi = pi_temp; } + + bgp_dest_unlock_node(dest); } return CMD_SUCCESS; @@ -15542,7 +15887,9 @@ DEFUN (clear_ip_bgp_dampening, BGP_STR "Clear route flap dampening information\n") { - bgp_damp_info_clean(AFI_IP, SAFI_UNICAST); + VTY_DECLVAR_CONTEXT(bgp, bgp); + bgp_damp_info_clean(bgp, &bgp->damp[AFI_IP][SAFI_UNICAST], AFI_IP, + SAFI_UNICAST); return CMD_SUCCESS; } diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 2929c75..89449ac 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -59,20 +59,15 @@ enum bgp_show_adj_route_type { #define BGP_SHOW_SCODE_HEADER \ "Status codes: s suppressed, d damped, " \ - "h history, * valid, > best, = multipath,\n" \ + "h history, u unsorted, * valid, > best, = multipath,\n" \ " i internal, r RIB-failure, S Stale, R Removed\n" #define BGP_SHOW_OCODE_HEADER \ "Origin codes: i - IGP, e - EGP, ? - incomplete\n" #define BGP_SHOW_NCODE_HEADER "Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self\n" #define BGP_SHOW_RPKI_HEADER \ "RPKI validation codes: V valid, I invalid, N Not found\n\n" -#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path\n" -#define BGP_SHOW_HEADER_WIDE " Network Next Hop Metric LocPrf Weight Path\n" - -/* Maximum number of labels we can process or send with a prefix. We - * really do only 1 for MPLS (BGP-LU) but we can do 2 for EVPN-VxLAN. - */ -#define BGP_MAX_LABELS 2 +#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path\n" +#define BGP_SHOW_HEADER_WIDE " Network Next Hop Metric LocPrf Weight Path\n" /* Maximum number of sids we can process or send with a prefix. */ #define BGP_MAX_SIDS 6 @@ -237,8 +232,7 @@ struct bgp_path_info_extra { uint32_t igpmetric; /* MPLS label(s) - VNI(s) for EVPN-VxLAN */ - mpls_label_t label[BGP_MAX_LABELS]; - uint32_t num_labels; + struct bgp_labels *labels; /* timestamp of the rib installation */ time_t bgp_rib_uptime; @@ -327,6 +321,7 @@ struct bgp_path_info { #define BGP_PATH_ACCEPT_OWN (1 << 16) #define BGP_PATH_MPLSVPN_LABEL_NH (1 << 17) #define BGP_PATH_MPLSVPN_NH_LABEL_BIND (1 << 18) +#define BGP_PATH_UNSORTED (1 << 19) /* BGP route type. This can be static, RIP, OSPF, BGP etc. */ uint8_t type; @@ -345,6 +340,8 @@ struct bgp_path_info { unsigned short instance; + enum bgp_path_selection_reason reason; + /* Addpath identifiers */ uint32_t addpath_rx_id; struct bgp_addpath_info_data tx_addpath; @@ -750,12 +747,16 @@ extern void bgp_path_info_delete(struct bgp_dest *dest, struct bgp_path_info *pi); extern struct bgp_path_info_extra * bgp_path_info_extra_get(struct bgp_path_info *path); +extern bool bgp_path_info_has_valid_label(const struct bgp_path_info *path); +extern uint8_t bgp_path_info_num_labels(const struct bgp_path_info *pi); extern void bgp_path_info_set_flag(struct bgp_dest *dest, struct bgp_path_info *path, uint32_t flag); extern void bgp_path_info_unset_flag(struct bgp_dest *dest, struct bgp_path_info *path, uint32_t flag); extern void bgp_path_info_path_with_addpath_rx_str(struct bgp_path_info *pi, char *buf, size_t buf_len); +extern bool bgp_path_info_labels_same(const struct bgp_path_info *bpi, + const mpls_label_t *label, uint32_t n); extern int bgp_nlri_parse_ip(struct peer *, struct attr *, struct bgp_nlri *); @@ -792,16 +793,17 @@ extern void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, struct attr *attr, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, mpls_label_t *label, - uint32_t num_labels, int soft_reconfig, + uint8_t num_labels, int soft_reconfig, struct bgp_route_evpn *evpn); extern void bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id, afi_t afi, safi_t safi, int type, int sub_type, struct prefix_rd *prd, - mpls_label_t *label, uint32_t num_labels, + mpls_label_t *label, uint8_t num_labels, struct bgp_route_evpn *evpn); /* for bgp_nexthop and bgp_damp */ -extern void bgp_process(struct bgp *, struct bgp_dest *, afi_t, safi_t); +extern void bgp_process(struct bgp *bgp, struct bgp_dest *dest, + struct bgp_path_info *pi, afi_t afi, safi_t safi); /* * Add an end-of-initial-update marker to the process queue. This is just a diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index dbc3d64..97ae92c 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1056,7 +1056,7 @@ static enum route_map_cmd_result_t route_match_vni(void *rule, const struct prefix *prefix, void *object) { vni_t vni = 0; - unsigned int label_cnt = 0; + unsigned int label_cnt; struct bgp_path_info *path = NULL; struct prefix_evpn *evp = (struct prefix_evpn *) prefix; @@ -1081,13 +1081,10 @@ route_match_vni(void *rule, const struct prefix *prefix, void *object) && evp->prefix.route_type != BGP_EVPN_IP_PREFIX_ROUTE)) return RMAP_NOOP; - if (path->extra == NULL) - return RMAP_NOMATCH; - - for (; - label_cnt < BGP_MAX_LABELS && label_cnt < path->extra->num_labels; + for (label_cnt = 0; label_cnt < BGP_MAX_LABELS && + label_cnt < bgp_path_info_num_labels(path); label_cnt++) { - if (vni == label2vni(&path->extra->label[label_cnt])) + if (vni == label2vni(&path->extra->labels->label[label_cnt])) return RMAP_MATCH; } @@ -1944,7 +1941,6 @@ route_set_srte_color(void *rule, const struct prefix *prefix, void *object) path = object; path->attr->srte_color = *srte_color; - path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR); return RMAP_OKAY; } @@ -2326,7 +2322,7 @@ static const struct route_map_rule_cmd route_set_aspath_prepend_cmd = { static void *route_aspath_exclude_compile(const char *arg) { struct aspath_exclude *ase; - struct aspath_exclude_list *ael; + struct as_list *aux_aslist; const char *str = arg; static const char asp_acl[] = "as-path-access-list"; @@ -2338,44 +2334,37 @@ static void *route_aspath_exclude_compile(const char *arg) while (*str == ' ') str++; ase->exclude_aspath_acl_name = XSTRDUP(MTYPE_TMP, str); - ase->exclude_aspath_acl = as_list_lookup(str); + aux_aslist = as_list_lookup(str); + if (!aux_aslist) + /* new orphan filter */ + as_exclude_set_orphan(ase); + else + as_list_list_add_head(&aux_aslist->exclude_rule, ase); + + ase->exclude_aspath_acl = aux_aslist; } else ase->aspath = aspath_str2aspath(str, bgp_get_asnotation(NULL)); - if (ase->exclude_aspath_acl) { - ael = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, - sizeof(struct aspath_exclude_list)); - ael->bp_as_excl = ase; - ael->next = ase->exclude_aspath_acl->exclude_list; - ase->exclude_aspath_acl->exclude_list = ael; - } - return ase; } static void route_aspath_exclude_free(void *rule) { struct aspath_exclude *ase = rule; - struct aspath_exclude_list *cur_ael = NULL; - struct aspath_exclude_list *prev_ael = NULL; + struct as_list *acl; + + /* manage references to that rule*/ + if (ase->exclude_aspath_acl) { + acl = ase->exclude_aspath_acl; + as_list_list_del(&acl->exclude_rule, ase); + } else { + /* no ref to acl, this aspath exclude is orphan */ + as_exclude_remove_orphan(ase); + } aspath_free(ase->aspath); if (ase->exclude_aspath_acl_name) XFREE(MTYPE_TMP, ase->exclude_aspath_acl_name); - if (ase->exclude_aspath_acl) - cur_ael = ase->exclude_aspath_acl->exclude_list; - while (cur_ael) { - if (cur_ael->bp_as_excl == ase) { - if (prev_ael) - prev_ael->next = cur_ael->next; - else - ase->exclude_aspath_acl->exclude_list = NULL; - XFREE(MTYPE_ROUTE_MAP_COMPILED, cur_ael); - break; - } - prev_ael = cur_ael; - cur_ael = cur_ael->next; - } XFREE(MTYPE_ROUTE_MAP_COMPILED, ase); } @@ -2410,16 +2399,10 @@ route_set_aspath_exclude(void *rule, const struct prefix *dummy, void *object) else if (ase->exclude_all) path->attr->aspath = aspath_filter_exclude_all(new_path); - else if (ase->exclude_aspath_acl_name) { - if (!ase->exclude_aspath_acl) - ase->exclude_aspath_acl = - as_list_lookup(ase->exclude_aspath_acl_name); - if (ase->exclude_aspath_acl) - path->attr->aspath = - aspath_filter_exclude_acl(new_path, - ase->exclude_aspath_acl); - } - + else if (ase->exclude_aspath_acl) + path->attr->aspath = + aspath_filter_exclude_acl(new_path, + ase->exclude_aspath_acl); return RMAP_OKAY; } @@ -3196,7 +3179,7 @@ struct rmap_ecomm_lb_set { #define RMAP_ECOMM_LB_SET_CUMUL 2 #define RMAP_ECOMM_LB_SET_NUM_MPATH 3 bool non_trans; - uint32_t bw; + uint64_t bw; }; static enum route_map_cmd_result_t @@ -3206,8 +3189,7 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object) struct bgp_path_info *path; struct peer *peer; struct ecommunity ecom_lb = {0}; - struct ecommunity_val lb_eval; - uint32_t bw_bytes = 0; + uint64_t bw_bytes = 0; uint16_t mpath_count = 0; struct ecommunity *new_ecom; struct ecommunity *old_ecom; @@ -3221,13 +3203,13 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object) /* Build link bandwidth extended community */ as = (peer->bgp->as > BGP_AS_MAX) ? BGP_AS_TRANS : peer->bgp->as; if (rels->lb_type == RMAP_ECOMM_LB_SET_VALUE) { - bw_bytes = ((uint64_t)rels->bw * 1000 * 1000) / 8; + bw_bytes = (rels->bw * 1000 * 1000) / 8; } else if (rels->lb_type == RMAP_ECOMM_LB_SET_CUMUL) { /* process this only for the best path. */ if (!CHECK_FLAG(path->flags, BGP_PATH_SELECTED)) return RMAP_OKAY; - bw_bytes = (uint32_t)bgp_path_info_mpath_cumbw(path); + bw_bytes = bgp_path_info_mpath_cumbw(path); if (!bw_bytes) return RMAP_OKAY; @@ -3237,31 +3219,53 @@ route_set_ecommunity_lb(void *rule, const struct prefix *prefix, void *object) if (!CHECK_FLAG(path->flags, BGP_PATH_SELECTED)) return RMAP_OKAY; - bw_bytes = ((uint64_t)peer->bgp->lb_ref_bw * 1000 * 1000) / 8; + bw_bytes = (peer->bgp->lb_ref_bw * 1000 * 1000) / 8; mpath_count = bgp_path_info_mpath_count(path) + 1; bw_bytes *= mpath_count; } - encode_lb_extcomm(as, bw_bytes, rels->non_trans, &lb_eval, - CHECK_FLAG(peer->flags, - PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE)); + if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_LINK_BANDWIDTH)) { + struct ecommunity_val_ipv6 lb_eval; - /* add to route or merge with existing */ - old_ecom = bgp_attr_get_ecommunity(path->attr); - if (old_ecom) { - new_ecom = ecommunity_dup(old_ecom); - ecommunity_add_val(new_ecom, &lb_eval, true, true); - if (!old_ecom->refcnt) - ecommunity_free(&old_ecom); + encode_lb_extended_extcomm(as, bw_bytes, rels->non_trans, + &lb_eval); + + old_ecom = bgp_attr_get_ipv6_ecommunity(path->attr); + if (old_ecom) { + new_ecom = ecommunity_dup(old_ecom); + ecommunity_add_val_ipv6(new_ecom, &lb_eval, true, true); + if (!old_ecom->refcnt) + ecommunity_free(&old_ecom); + } else { + ecom_lb.size = 1; + ecom_lb.unit_size = IPV6_ECOMMUNITY_SIZE; + ecom_lb.val = (uint8_t *)lb_eval.val; + new_ecom = ecommunity_dup(&ecom_lb); + } + + bgp_attr_set_ipv6_ecommunity(path->attr, new_ecom); } else { - ecom_lb.size = 1; - ecom_lb.unit_size = ECOMMUNITY_SIZE; - ecom_lb.val = (uint8_t *)lb_eval.val; - new_ecom = ecommunity_dup(&ecom_lb); - } + struct ecommunity_val lb_eval; + + encode_lb_extcomm(as, bw_bytes, rels->non_trans, &lb_eval, + CHECK_FLAG(peer->flags, + PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE)); + + old_ecom = bgp_attr_get_ecommunity(path->attr); + if (old_ecom) { + new_ecom = ecommunity_dup(old_ecom); + ecommunity_add_val(new_ecom, &lb_eval, true, true); + if (!old_ecom->refcnt) + ecommunity_free(&old_ecom); + } else { + ecom_lb.size = 1; + ecom_lb.unit_size = ECOMMUNITY_SIZE; + ecom_lb.val = (uint8_t *)lb_eval.val; + new_ecom = ecommunity_dup(&ecom_lb); + } - /* new_ecom will be intern()'d or attr_flush()'d in call stack */ - bgp_attr_set_ecommunity(path->attr, new_ecom); + bgp_attr_set_ecommunity(path->attr, new_ecom); + } /* Mark that route-map has set link bandwidth; used in attribute * setting decisions. @@ -3275,7 +3279,7 @@ static void *route_set_ecommunity_lb_compile(const char *arg) { struct rmap_ecomm_lb_set *rels; uint8_t lb_type; - uint32_t bw = 0; + uint64_t bw = 0; char bw_str[40] = {0}; char *p, *str; bool non_trans = false; @@ -3317,13 +3321,8 @@ static enum route_map_cmd_result_t route_set_ecommunity_color(void *rule, const struct prefix *prefix, void *object) { - struct bgp_path_info *path; - - path = object; - route_set_ecommunity(rule, prefix, object); - path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR); return RMAP_OKAY; } @@ -3953,11 +3952,11 @@ route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix, if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN) || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) { /* Set next hop preference to global */ - path->attr->mp_nexthop_prefer_global = true; + SET_FLAG(path->attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL); SET_FLAG(path->attr->rmap_change_flags, BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED); } else { - path->attr->mp_nexthop_prefer_global = false; + UNSET_FLAG(path->attr->nh_flags, BGP_ATTR_NH_MP_PREFER_GLOBAL); SET_FLAG(path->attr->rmap_change_flags, BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED); } @@ -6880,7 +6879,7 @@ DEFUN_YANG(no_set_ecommunity_none, no_set_ecommunity_none_cmd, DEFUN_YANG (set_ecommunity_lb, set_ecommunity_lb_cmd, - "set extcommunity bandwidth <(1-25600)|cumulative|num-multipaths> [non-transitive]", + "set extcommunity bandwidth <(1-4294967295)|cumulative|num-multipaths> [non-transitive]", SET_STR "BGP extended community attribute\n" "Link bandwidth extended community\n" @@ -6934,7 +6933,7 @@ DEFUN_YANG (set_ecommunity_lb, DEFUN_YANG (no_set_ecommunity_lb, no_set_ecommunity_lb_cmd, - "no set extcommunity bandwidth <(1-25600)|cumulative|num-multipaths> [non-transitive]", + "no set extcommunity bandwidth <(1-4294967295)|cumulative|num-multipaths> [non-transitive]", NO_STR SET_STR "BGP extended community attribute\n" diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c index c1d6ee1..15c32ea 100644 --- a/bgpd/bgp_routemap_nb_config.c +++ b/bgpd/bgp_routemap_nb_config.c @@ -2937,7 +2937,7 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish( struct routemap_hook_context *rhc; enum ecommunity_lb_type lb_type; char str[VTY_BUFSIZ]; - uint16_t bandwidth; + uint32_t bandwidth; int ret; /* Add configuration. */ @@ -2951,8 +2951,8 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish( switch (lb_type) { case EXPLICIT_BANDWIDTH: - bandwidth = yang_dnode_get_uint16(args->dnode, "bandwidth"); - snprintf(str, sizeof(str), "%d", bandwidth); + bandwidth = yang_dnode_get_uint32(args->dnode, "bandwidth"); + snprintf(str, sizeof(str), "%u", bandwidth); break; case CUMULATIVE_BANDWIDTH: snprintf(str, sizeof(str), "%s", "cumulative"); diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 22f78fb..a487f49 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -29,6 +29,7 @@ #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgp_advertise.h" +#include "bgp_label.h" #include "bgpd/bgp_debug.h" #include "bgpd/bgp_attr.h" #include "bgpd/bgp_aspath.h" @@ -656,17 +657,16 @@ static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi, safi_t safi) { struct bgp_adj_in *ain; + mpls_label_t *label; + uint8_t num_labels; for (ain = bgp_dest->adj_in; ain; ain = ain->next) { struct bgp_path_info *path = bgp_dest_get_bgp_path_info(bgp_dest); - mpls_label_t *label = NULL; - uint32_t num_labels = 0; - if (path && path->extra) { - label = path->extra->label; - num_labels = path->extra->num_labels; - } + num_labels = bgp_path_info_num_labels(path); + label = num_labels ? path->extra->labels->label : NULL; + (void)bgp_update(ain->peer, bgp_dest_get_prefix(bgp_dest), ain->addpath_rx_id, ain->attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label, @@ -1082,7 +1082,7 @@ static void print_prefix_table(struct vty *vty, struct rpki_vrf *rpki_vrf, unsigned int number_of_ipv4_prefixes = 0; unsigned int number_of_ipv6_prefixes = 0; - struct rtr_mgr_group *group = get_connected_group(rpki_vrf); + struct rtr_mgr_group *group; json_object *json_records = NULL; if (!rpki_vrf) @@ -1621,7 +1621,7 @@ static int bgp_rpki_write_vrf(struct vty *vty, struct vrf *vrf) #endif case TCP: tcp_config = cache->tr_config.tcp_config; - vty_out(vty, "%s rpki cache %s %s ", sep, + vty_out(vty, "%s rpki cache tcp %s %s ", sep, tcp_config->host, tcp_config->port); if (tcp_config->bindaddr) vty_out(vty, "source %s ", @@ -1630,7 +1630,7 @@ static int bgp_rpki_write_vrf(struct vty *vty, struct vrf *vrf) #if defined(FOUND_SSH) case SSH: ssh_config = cache->tr_config.ssh_config; - vty_out(vty, "%s rpki cache %s %u %s %s %s ", sep, + vty_out(vty, "%s rpki cache ssh %s %u %s %s %s ", sep, ssh_config->host, ssh_config->port, ssh_config->username, ssh_config->client_privkey_path, @@ -1918,8 +1918,11 @@ DEFUN (no_rpki_retry_interval, return CMD_SUCCESS; } +#if CONFDATE > 20240916 +CPP_NOTICE("Remove rpki_cache_cmd") +#endif DEFPY(rpki_cache, rpki_cache_cmd, - "rpki cache <A.B.C.D|WORD> <TCPPORT|(1-65535)$sshport SSH_UNAME SSH_PRIVKEY [SERVER_PUBKEY]> [source <A.B.C.D>$bindaddr] preference (1-255)", + "rpki cache <A.B.C.D|WORD> <TCPPORT|(1-65535)$sshport SSH_UNAME SSH_PRIVKEY [KNOWN_HOSTS_PATH]> [source <A.B.C.D>$bindaddr] preference (1-255)", RPKI_OUTPUT_STRING "Install a cache server to current group\n" "IP address of cache server\n" @@ -1928,7 +1931,7 @@ DEFPY(rpki_cache, rpki_cache_cmd, "SSH port number\n" "SSH user name\n" "Path to own SSH private key\n" - "Path to Public key of cache server\n" + "Path to the known hosts file\n" "Configure source IP address of RPKI connection\n" "Define a Source IP Address\n" "Preference of the cache server\n" @@ -1967,7 +1970,7 @@ DEFPY(rpki_cache, rpki_cache_cmd, if (ssh_uname) { #if defined(FOUND_SSH) return_value = add_ssh_cache(rpki_vrf, cache, sshport, ssh_uname, - ssh_privkey, server_pubkey, + ssh_privkey, known_hosts_path, preference, bindaddr_str); #else return_value = SUCCESS; @@ -1990,19 +1993,143 @@ DEFPY(rpki_cache, rpki_cache_cmd, return CMD_SUCCESS; } +DEFPY(rpki_cache_tcp, rpki_cache_tcp_cmd, + "rpki cache tcp <A.B.C.D|WORD>$cache TCPPORT [source <A.B.C.D>$bindaddr] preference (1-255)", + RPKI_OUTPUT_STRING + "Install a cache server to current group\n" + "Use TCP\n" + "IP address of cache server\n" + "Hostname of cache server\n" + "TCP port number\n" + "Configure source IP address of RPKI connection\n" + "Define a Source IP Address\n" + "Preference of the cache server\n" + "Preference value\n") +{ + int return_value; + struct listnode *cache_node; + struct cache *current_cache; + struct rpki_vrf *rpki_vrf; + bool init; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); + + if (!rpki_vrf) + return CMD_WARNING_CONFIG_FAILED; + + if (!rpki_vrf || !rpki_vrf->cache_list) + return CMD_WARNING; + + init = !!list_isempty(rpki_vrf->cache_list); + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, + current_cache)) { + if (current_cache->preference == preference) { + vty_out(vty, + "Cache with preference %ld is already configured\n", + preference); + return CMD_WARNING; + } + } + + return_value = add_tcp_cache(rpki_vrf, cache, tcpport, preference, + bindaddr_str); + + if (return_value == ERROR) { + vty_out(vty, "Could not create new rpki cache\n"); + return CMD_WARNING; + } + + if (init) + start(rpki_vrf); + + return CMD_SUCCESS; +} + +DEFPY(rpki_cache_ssh, rpki_cache_ssh_cmd, + "rpki cache ssh <A.B.C.D|WORD>$cache (1-65535)$sshport SSH_UNAME SSH_PRIVKEY [KNOWN_HOSTS_PATH] [source <A.B.C.D>$bindaddr] preference (1-255)", + RPKI_OUTPUT_STRING + "Install a cache server to current group\n" + "Use SSH\n" + "IP address of cache server\n" + "Hostname of cache server\n" + "SSH port number\n" + "SSH user name\n" + "Path to own SSH private key\n" + "Path to the known hosts file\n" + "Configure source IP address of RPKI connection\n" + "Define a Source IP Address\n" + "Preference of the cache server\n" + "Preference value\n") +{ + int return_value; + struct listnode *cache_node; + struct cache *current_cache; + struct rpki_vrf *rpki_vrf; + bool init; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); + + if (!rpki_vrf) + return CMD_WARNING_CONFIG_FAILED; + + if (!rpki_vrf || !rpki_vrf->cache_list) + return CMD_WARNING; + + init = !!list_isempty(rpki_vrf->cache_list); + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, + current_cache)) { + if (current_cache->preference == preference) { + vty_out(vty, + "Cache with preference %ld is already configured\n", + preference); + return CMD_WARNING; + } + } + +#if defined(FOUND_SSH) + return_value = add_ssh_cache(rpki_vrf, cache, sshport, ssh_uname, + ssh_privkey, known_hosts_path, preference, + bindaddr_str); +#else + return_value = SUCCESS; + vty_out(vty, + "ssh sockets are not supported. Please recompile rtrlib and frr with ssh support. If you want to use it\n"); +#endif + + if (return_value == ERROR) { + vty_out(vty, "Could not create new rpki cache\n"); + return CMD_WARNING; + } + + if (init) + start(rpki_vrf); + + return CMD_SUCCESS; +} + DEFPY (no_rpki_cache, no_rpki_cache_cmd, - "no rpki cache <A.B.C.D|WORD> <TCPPORT|(1-65535)$sshport SSH_UNAME SSH_PRIVKEY [SERVER_PUBKEY]> [source <A.B.C.D>$bindaddr] preference (1-255)", + "no rpki cache <tcp|ssh> <A.B.C.D|WORD> <TCPPORT|(1-65535)$sshport SSH_UNAME SSH_PRIVKEY [KNOWN_HOSTS_PATH]> [source <A.B.C.D>$bindaddr] preference (1-255)", NO_STR RPKI_OUTPUT_STRING "Install a cache server to current group\n" + "Use TCP\n" + "Use SSH\n" "IP address of cache server\n" "Hostname of cache server\n" "TCP port number\n" "SSH port number\n" "SSH user name\n" "Path to own SSH private key\n" - "Path to Public key of cache server\n" + "Path to the known hosts file\n" "Configure source IP address of RPKI connection\n" "Define a Source IP Address\n" "Preference of the cache server\n" @@ -2088,16 +2215,18 @@ DEFPY (show_rpki_prefix_table, DEFPY (show_rpki_as_number, show_rpki_as_number_cmd, - "show rpki as-number ASNUM$by_asn [vrf NAME$vrfname] [json$uj]", + "show rpki as-number <0$zero|ASNUM$by_asn> [vrf NAME$vrfname] [json$uj]", SHOW_STR RPKI_OUTPUT_STRING "Lookup by ASN in prefix table\n" + "AS Number of 0, see RFC-7607\n" "AS Number\n" VRF_CMD_HELP_STR JSON_STR) { struct json_object *json = NULL; struct rpki_vrf *rpki_vrf; + as_t as; if (uj) json = json_object_new_object(); @@ -2118,18 +2247,24 @@ DEFPY (show_rpki_as_number, return CMD_WARNING; } - print_prefix_table_by_asn(vty, by_asn, rpki_vrf, json); + if (zero) + as = 0; + else + as = by_asn; + + print_prefix_table_by_asn(vty, as, rpki_vrf, json); return CMD_SUCCESS; } DEFPY (show_rpki_prefix, show_rpki_prefix_cmd, - "show rpki prefix <A.B.C.D/M|X:X::X:X/M> [ASNUM$asn] [vrf NAME$vrfname] [json$uj]", + "show rpki prefix <A.B.C.D/M|X:X::X:X/M> [0$zero|ASNUM$asn] [vrf NAME$vrfname] [json$uj]", SHOW_STR RPKI_OUTPUT_STRING "Lookup IP prefix and optionally ASN in prefix table\n" "IPv4 prefix\n" "IPv6 prefix\n" + "AS Number of 0, see RFC-7607\n" "AS Number\n" VRF_CMD_HELP_STR JSON_STR) @@ -2138,6 +2273,7 @@ DEFPY (show_rpki_prefix, json_object *json_records = NULL; enum asnotation_mode asnotation; struct rpki_vrf *rpki_vrf; + as_t as; if (uj) json = json_object_new_object(); @@ -2153,6 +2289,11 @@ DEFPY (show_rpki_prefix, return CMD_WARNING; } + if (zero) + as = 0; + else + as = asn; + struct lrtr_ip_addr addr; char addr_str[INET6_ADDRSTRLEN]; size_t addr_len = strchr(prefix_str, '/') - prefix_str; @@ -2174,7 +2315,7 @@ DEFPY (show_rpki_prefix, enum pfxv_state result; if (pfx_table_validate_r(rpki_vrf->rtr_config->pfx_table, &matches, - &match_count, asn, &addr, prefix->prefixlen, + &match_count, as, &addr, prefix->prefixlen, &result) != PFX_SUCCESS) { if (json) { json_object_string_add(json, "error", "Prefix lookup failed."); @@ -2198,7 +2339,7 @@ DEFPY (show_rpki_prefix, const struct pfx_record *record = &matches[i]; if (record->max_len >= prefix->prefixlen && - ((asn != 0 && (uint32_t)asn == record->asn) || asn == 0)) { + ((as != 0 && (uint32_t)as == record->asn) || asn == 0)) { print_record(&matches[i], vty, json_records, asnotation); } @@ -2243,10 +2384,16 @@ DEFPY (show_rpki_cache_server, if (cache->type == TCP) { if (!json) { vty_out(vty, - "host: %s port: %s, preference: %hhu\n", + "host: %s port: %s, preference: %hhu, protocol: tcp", cache->tr_config.tcp_config->host, cache->tr_config.tcp_config->port, cache->preference); + if (cache->tr_config.tcp_config->bindaddr) + vty_out(vty, ", source: %s\n", + cache->tr_config.tcp_config + ->bindaddr); + else + vty_out(vty, "\n"); } else { json_server = json_object_new_object(); json_object_string_add(json_server, "mode", @@ -2259,6 +2406,12 @@ DEFPY (show_rpki_cache_server, cache->tr_config.tcp_config->port); json_object_int_add(json_server, "preference", cache->preference); + if (cache->tr_config.tcp_config->bindaddr) + json_object_string_add(json_server, + "source", + cache->tr_config + .tcp_config + ->bindaddr); json_object_array_add(json_servers, json_server); } @@ -2267,7 +2420,7 @@ DEFPY (show_rpki_cache_server, } else if (cache->type == SSH) { if (!json) { vty_out(vty, - "host: %s port: %d username: %s server_hostkey_path: %s client_privkey_path: %s, preference: %hhu\n", + "host: %s, port: %d, username: %s, server_hostkey_path: %s, client_privkey_path: %s, preference: %hhu, protocol: ssh", cache->tr_config.ssh_config->host, cache->tr_config.ssh_config->port, cache->tr_config.ssh_config->username, @@ -2276,6 +2429,12 @@ DEFPY (show_rpki_cache_server, cache->tr_config.ssh_config ->client_privkey_path, cache->preference); + if (cache->tr_config.ssh_config->bindaddr) + vty_out(vty, ", source: %s\n", + cache->tr_config.ssh_config + ->bindaddr); + else + vty_out(vty, "\n"); } else { json_server = json_object_new_object(); json_object_string_add(json_server, "mode", @@ -2299,6 +2458,12 @@ DEFPY (show_rpki_cache_server, ->client_privkey_path); json_object_int_add(json_server, "preference", cache->preference); + if (cache->tr_config.ssh_config->bindaddr) + json_object_string_add(json_server, + "source", + cache->tr_config + .ssh_config + ->bindaddr); json_object_array_add(json_servers, json_server); } @@ -2651,6 +2816,8 @@ static void install_cli_commands(void) install_element(RPKI_NODE, &no_rpki_retry_interval_cmd); /* Install rpki cache commands */ + install_element(RPKI_NODE, &rpki_cache_tcp_cmd); + install_element(RPKI_NODE, &rpki_cache_ssh_cmd); install_element(RPKI_NODE, &rpki_cache_cmd); install_element(RPKI_NODE, &no_rpki_cache_cmd); @@ -2673,6 +2840,8 @@ static void install_cli_commands(void) install_element(RPKI_VRF_NODE, &no_rpki_retry_interval_cmd); /* Install rpki cache commands */ + install_element(RPKI_VRF_NODE, &rpki_cache_tcp_cmd); + install_element(RPKI_VRF_NODE, &rpki_cache_ssh_cmd); install_element(RPKI_VRF_NODE, &rpki_cache_cmd); install_element(RPKI_VRF_NODE, &no_rpki_cache_cmd); diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c index 0c8ed33..7036910 100644 --- a/bgpd/bgp_snmp_bgp4v2.c +++ b/bgpd/bgp_snmp_bgp4v2.c @@ -853,7 +853,8 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[], case BGP_ATTR_NHLEN_IPV6_GLOBAL: return SNMP_INTEGER(2); case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: - if (path->attr->mp_nexthop_prefer_global) + if (CHECK_FLAG(path->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) return SNMP_INTEGER(2); else return SNMP_INTEGER(4); @@ -867,7 +868,8 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[], case BGP_ATTR_NHLEN_IPV6_GLOBAL: return SNMP_IP6ADDRESS(path->attr->mp_nexthop_global); case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: - if (path->attr->mp_nexthop_prefer_global) + if (CHECK_FLAG(path->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) return SNMP_IP6ADDRESS( path->attr->mp_nexthop_global); else diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index 8465ada..781909b 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -239,7 +239,11 @@ static ssize_t printfrr_bd(struct fbuf *buf, struct printfrr_eargs *ea, if (!dest) return bputs(buf, "(null)"); +#if !defined(DEV_BUILD) /* need to get the real length even if buffer too small */ prefix2str(p, cbuf, sizeof(cbuf)); return bputs(buf, cbuf); +#else + return bprintfrr(buf, "%s(%p)", prefix2str(p, cbuf, sizeof(cbuf)), dest); +#endif } diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index 5b4c3be..130f5ca 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -76,6 +76,11 @@ struct bgp_dest { STAILQ_ENTRY(bgp_dest) pq; + struct zebra_announce_item zai; + struct bgp_path_info *za_bgp_pi; + struct bgpevpn *za_vpn; + bool za_is_sync; + uint64_t version; mpls_label_t local_label; @@ -91,12 +96,16 @@ struct bgp_dest { #define BGP_NODE_LABEL_REQUESTED (1 << 7) #define BGP_NODE_SOFT_RECONFIG (1 << 8) #define BGP_NODE_PROCESS_CLEAR (1 << 9) +#define BGP_NODE_SCHEDULE_FOR_INSTALL (1 << 10) +#define BGP_NODE_SCHEDULE_FOR_DELETE (1 << 11) struct bgp_addpath_node_data tx_addpath; enum bgp_path_selection_reason reason; }; +DECLARE_LIST(zebra_announce, struct bgp_dest, zai); + extern void bgp_delete_listnode(struct bgp_dest *dest); /* * bgp_table_iter_t diff --git a/bgpd/bgp_trace.c b/bgpd/bgp_trace.c index 02afbeb..af45e7a 100644 --- a/bgpd/bgp_trace.c +++ b/bgpd/bgp_trace.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + #define TRACEPOINT_CREATE_PROBES #define TRACEPOINT_DEFINE diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index d13515a..124e7a3 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -145,11 +145,12 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi, dst->addpath_type[afi][safi] = src->addpath_type[afi][safi]; dst->addpath_best_selected[afi][safi] = src->addpath_best_selected[afi][safi]; + dst->addpath_paths_limit[afi][safi] = + src->addpath_paths_limit[afi][safi]; dst->local_as = src->local_as; dst->change_local_as = src->change_local_as; dst->shared_network = src->shared_network; dst->local_role = src->local_role; - dst->as_path_loop_detection = src->as_path_loop_detection; if (src->soo[afi][safi]) { ecommunity_free(&dst->soo[afi][safi]); @@ -348,6 +349,8 @@ static unsigned int updgrp_hash_key_make(const void *p) key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key); key = jhash_1word((uint32_t)peer->addpath_type[afi][safi], key); key = jhash_1word(peer->addpath_best_selected[afi][safi], key); + key = jhash_1word(peer->addpath_paths_limit[afi][safi].receive, key); + key = jhash_1word(peer->addpath_paths_limit[afi][safi].send, key); key = jhash_1word((peer->cap & PEER_UPDGRP_CAP_FLAGS), key); key = jhash_1word((peer->af_cap[afi][safi] & PEER_UPDGRP_AF_CAP_FLAGS), key); @@ -356,9 +359,12 @@ static unsigned int updgrp_hash_key_make(const void *p) key = jhash_1word(peer->max_packet_size, key); key = jhash_1word(peer->pmax_out[afi][safi], key); - if (peer->as_path_loop_detection) - key = jhash_2words(peer->as, peer->as_path_loop_detection, key); + if (CHECK_FLAG(peer->flags, PEER_FLAG_AS_LOOP_DETECTION)) + key = jhash_2words(peer->as, + CHECK_FLAG(peer->flags, + PEER_FLAG_AS_LOOP_DETECTION), + key); if (peer->group) key = jhash_1word(jhash(peer->group->name, strlen(peer->group->name), SEED1), @@ -439,7 +445,7 @@ static unsigned int updgrp_hash_key_make(const void *p) key = jhash_1word((peer->flags & PEER_FLAG_AIGP), key); if (peer->soo[afi][safi]) { - char *soo_str = ecommunity_str(peer->soo[afi][safi]); + const char *soo_str = ecommunity_str(peer->soo[afi][safi]); key = jhash_1word(jhash(soo_str, strlen(soo_str), SEED1), key); } @@ -460,7 +466,11 @@ static unsigned int updgrp_hash_key_make(const void *p) CHECK_FLAG(peer->af_cap[afi][safi], PEER_UPDGRP_AF_CAP_FLAGS), peer->v_routeadv, peer->change_local_as, - peer->as_path_loop_detection); + !!CHECK_FLAG(peer->flags, + PEER_FLAG_AS_LOOP_DETECTION)); + zlog_debug("%pBP Update Group Hash: addpath paths-limit: (send %u, receive %u)", + peer, peer->addpath_paths_limit[afi][safi].send, + peer->addpath_paths_limit[afi][safi].receive); zlog_debug( "%pBP Update Group Hash: max packet size: %u pmax_out: %u Peer Group: %s rmap out: %s", peer, peer->max_packet_size, peer->pmax_out[afi][safi], @@ -1722,18 +1732,6 @@ static int update_group_walkcb(struct hash_bucket *bucket, void *arg) return ret; } -static int update_group_periodic_merge_walkcb(struct update_group *updgrp, - void *arg) -{ - struct update_subgroup *subgrp; - struct update_subgroup *tmp_subgrp; - const char *reason = arg; - - UPDGRP_FOREACH_SUBGRP_SAFE (updgrp, subgrp, tmp_subgrp) - update_subgroup_check_merge(subgrp, reason); - return UPDWALK_CONTINUE; -} - /******************** * PUBLIC FUNCTIONS ********************/ @@ -2072,14 +2070,6 @@ void update_group_walk(struct bgp *bgp, updgrp_walkcb cb, void *ctx) } } -void update_group_periodic_merge(struct bgp *bgp) -{ - char reason[] = "periodic merge check"; - - update_group_walk(bgp, update_group_periodic_merge_walkcb, - (void *)reason); -} - static int update_group_default_originate_route_map_walkcb(struct update_group *updgrp, void *arg) diff --git a/bgpd/bgp_updgrp.h b/bgpd/bgp_updgrp.h index 5e8b537..d0fd226 100644 --- a/bgpd/bgp_updgrp.h +++ b/bgpd/bgp_updgrp.h @@ -369,7 +369,6 @@ extern void update_group_policy_update(struct bgp *bgp, extern void update_group_af_walk(struct bgp *bgp, afi_t afi, safi_t safi, updgrp_walkcb cb, void *ctx); extern void update_group_walk(struct bgp *bgp, updgrp_walkcb cb, void *ctx); -extern void update_group_periodic_merge(struct bgp *bgp); extern void update_group_refresh_default_originate_route_map(struct event *thread); extern void update_group_start_advtimer(struct bgp *bgp); diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 9d62265..250378a 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -78,6 +78,8 @@ static inline struct bgp_adj_out *adj_lookup(struct bgp_dest *dest, static void adj_free(struct bgp_adj_out *adj) { + bgp_labels_unintern(&adj->labels); + TAILQ_REMOVE(&(adj->subgroup->adjq), adj, subgrp_adj_train); SUBGRP_DECR_STAT(adj->subgroup, adj_count); @@ -97,13 +99,19 @@ subgrp_announce_addpath_best_selected(struct bgp_dest *dest, enum bgp_path_selection_reason reason; char pfx_buf[PREFIX2STR_BUFFER] = {}; int paths_eq = 0; - int best_path_count = 0; struct list *list = list_new(); struct bgp_path_info *pi = NULL; + uint16_t paths_count = 0; + uint16_t paths_limit = peer->addpath_paths_limit[afi][safi].receive; if (peer->addpath_type[afi][safi] == BGP_ADDPATH_BEST_SELECTED) { - while (best_path_count++ < - peer->addpath_best_selected[afi][safi]) { + paths_limit = + paths_limit + ? MIN(paths_limit, + peer->addpath_best_selected[afi][safi]) + : peer->addpath_best_selected[afi][safi]; + + while (paths_count++ < paths_limit) { struct bgp_path_info *exist = NULL; for (pi = bgp_dest_get_bgp_path_info(dest); pi; @@ -139,8 +147,26 @@ subgrp_announce_addpath_best_selected(struct bgp_dest *dest, subgroup_process_announce_selected( subgrp, NULL, dest, afi, safi, id); } else { - subgroup_process_announce_selected(subgrp, pi, dest, - afi, safi, id); + /* No Paths-Limit involved */ + if (!paths_limit) { + subgroup_process_announce_selected(subgrp, pi, + dest, afi, + safi, id); + continue; + } + + /* If we have Paths-Limit capability, we MUST + * not send more than the number of paths expected + * by the peer. + */ + if (paths_count++ < paths_limit) + subgroup_process_announce_selected(subgrp, pi, + dest, afi, + safi, id); + else + subgroup_process_announce_selected(subgrp, NULL, + dest, afi, + safi, id); } } @@ -509,7 +535,7 @@ bool bgp_adj_out_set_subgroup(struct bgp_dest *dest, struct peer *adv_peer; struct peer_af *paf; struct bgp *bgp; - uint32_t attr_hash = attrhash_key_make(attr); + uint32_t attr_hash = 0; peer = SUBGRP_PEER(subgrp); afi = SUBGRP_AFI(subgrp); @@ -544,9 +570,13 @@ bool bgp_adj_out_set_subgroup(struct bgp_dest *dest, * the route wasn't changed actually. * Do not suppress BGP UPDATES for route-refresh. */ - if (CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES) - && !CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES) - && adj->attr_hash == attr_hash) { + if (likely(CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_DUPLICATES))) + attr_hash = attrhash_key_make(attr); + + if (!CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES) && + attr_hash && adj->attr_hash == attr_hash && + bgp_labels_cmp(path->extra ? path->extra->labels : NULL, + adj->labels)) { if (BGP_DEBUG(update, UPDATE_OUT)) { char attr_str[BUFSIZ] = {0}; @@ -588,6 +618,10 @@ bool bgp_adj_out_set_subgroup(struct bgp_dest *dest, adv->baa = bgp_advertise_attr_intern(subgrp->hash, attr); adv->adj = adj; adj->attr_hash = attr_hash; + if (path->extra) + adj->labels = bgp_labels_intern(path->extra->labels); + else + adj->labels = NULL; /* Add new advertisement to advertisement attribute list. */ bgp_advertise_add(adv->baa, adv); diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index 7502bf2..6e30d4f 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -523,11 +523,13 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, gnh_modified = 1; } - if (IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg)) { - if (peer->nexthop.v4.s_addr != INADDR_ANY) { - ipv4_to_ipv4_mapped_ipv6(mod_v6nhg, - peer->nexthop.v4); - } + if (peer->nexthop.v4.s_addr != INADDR_ANY && + (IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg) || + (IN6_IS_ADDR_LINKLOCAL(mod_v6nhg) && + peer->connection->su.sa.sa_family == AF_INET6 && + paf->afi == AFI_IP))) { + ipv4_to_ipv4_mapped_ipv6(mod_v6nhg, peer->nexthop.v4); + gnh_modified = 1; } if (IS_MAPPED_IPV6(&peer->nexthop.v6_global)) { @@ -665,7 +667,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) uint32_t addpath_tx_id = 0; struct prefix_rd *prd = NULL; mpls_label_t label = MPLS_INVALID_LABEL, *label_pnt = NULL; - uint32_t num_labels = 0; + uint8_t num_labels = 0; if (!subgrp) return NULL; @@ -812,9 +814,12 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp) path); label_pnt = &label; num_labels = 1; - } else if (path && path->extra) { - label_pnt = &path->extra->label[0]; - num_labels = path->extra->num_labels; + } else { + num_labels = bgp_path_info_num_labels(path); + label_pnt = + num_labels + ? &path->extra->labels->label[0] + : NULL; } if (stream_empty(snlri)) @@ -1081,7 +1086,7 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp, struct bpacket_attr_vec_arr vecarr; bool addpath_capable = false; mpls_label_t label = MPLS_LABEL_IMPLICIT_NULL; - uint32_t num_labels = 0; + uint8_t num_labels = 0; if (DISABLE_BGP_ANNOUNCE) return; diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 9530a66..1a87799 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -126,6 +126,10 @@ FRR_CFG_DEFAULT_BOOL(BGP_SOFT_VERSION_CAPABILITY, { .val_bool = true, .match_profile = "datacenter", }, { .val_bool = false }, ); +FRR_CFG_DEFAULT_BOOL(BGP_DYNAMIC_CAPABILITY, + { .val_bool = true, .match_profile = "datacenter", }, + { .val_bool = false }, +); FRR_CFG_DEFAULT_BOOL(BGP_ENFORCE_FIRST_AS, { .val_bool = false, .match_version = "< 9.1", }, { .val_bool = true }, @@ -623,6 +627,9 @@ int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name, if (DFLT_BGP_SOFT_VERSION_CAPABILITY) SET_FLAG((*bgp)->flags, BGP_FLAG_SOFT_VERSION_CAPABILITY); + if (DFLT_BGP_DYNAMIC_CAPABILITY) + SET_FLAG((*bgp)->flags, + BGP_FLAG_DYNAMIC_CAPABILITY); if (DFLT_BGP_ENFORCE_FIRST_AS) SET_FLAG((*bgp)->flags, BGP_FLAG_ENFORCE_FIRST_AS); @@ -1694,6 +1701,10 @@ DEFUN (no_router_bgp, for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, tmp_bgp)) { if (tmp_bgp->inst_type != BGP_INSTANCE_TYPE_VRF) continue; + + if (CHECK_FLAG(tmp_bgp->vrf_flags, BGP_VRF_AUTO)) + bgp_delete(tmp_bgp); + if (CHECK_FLAG( tmp_bgp->af_flags[AFI_IP] [SAFI_UNICAST], @@ -1753,10 +1764,10 @@ DEFPY (bgp_session_dscp, bgp_session_dscp_cmd, "bgp session-dscp (0-63)$dscp", BGP_STR - "Override default (C6) bgp TCP session DSCP value\n" - "Manually configured dscp parameter\n") + "Override default (CS6) DSCP for BGP connections\n" + "Manually configured DSCP value\n") { - bm->tcp_dscp = dscp << 2; + bm->ip_tos = dscp << 2; return CMD_SUCCESS; } @@ -1766,10 +1777,10 @@ DEFPY (no_bgp_session_dscp, "no bgp session-dscp [(0-63)]", NO_STR BGP_STR - "Override default (C6) bgp TCP session DSCP value\n" - "Manually configured dscp parameter\n") + "Override default (CS6) DSCP for BGP connections\n" + "Manually configured DSCP value\n") { - bm->tcp_dscp = IPTOS_PREC_INTERNETCONTROL; + bm->ip_tos = IPTOS_PREC_INTERNETCONTROL; return CMD_SUCCESS; } @@ -3028,14 +3039,17 @@ DEFUN (bgp_graceful_restart, VTY_DECLVAR_CONTEXT(bgp, bgp); ret = bgp_gr_update_all(bgp, GLOBAL_GR_CMD); - - VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer, - ret); + if (ret == BGP_GR_SUCCESS) { + VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, + bgp->peer, + ret); + vty_out(vty, + "Graceful restart configuration changed, reset all peers to take effect\n"); + } if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset all peers to take effect\n"); + return bgp_vty_return(vty, ret); } @@ -3055,14 +3069,16 @@ DEFUN (no_bgp_graceful_restart, int ret = BGP_GR_FAILURE; ret = bgp_gr_update_all(bgp, NO_GLOBAL_GR_CMD); - - VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer, - ret); + if (ret == BGP_GR_SUCCESS) { + VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, + bgp->peer, + ret); + vty_out(vty, + "Graceful restart configuration changed, reset all peers to take effect\n"); + } if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset all peers to take effect\n"); return bgp_vty_return(vty, ret); } @@ -3270,24 +3286,25 @@ DEFUN (bgp_graceful_restart_disable, VTY_DECLVAR_CONTEXT(bgp, bgp); ret = bgp_gr_update_all(bgp, GLOBAL_DISABLE_CMD); + if (ret == BGP_GR_SUCCESS) { + VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, + bgp->peer, + ret); + vty_out(vty, + "Graceful restart configuration changed, reset all peers to take effect\n"); - VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, - bgp->peer, ret); + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_RESTART, + CAPABILITY_ACTION_UNSET); + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, + CAPABILITY_CODE_LLGR, + CAPABILITY_ACTION_UNSET); + } + } if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] bgp_graceful_restart_disable_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset all peers to take effect\n"); - - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, - CAPABILITY_CODE_RESTART, - CAPABILITY_ACTION_UNSET); - bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, - CAPABILITY_CODE_LLGR, - CAPABILITY_ACTION_UNSET); - } + zlog_debug("[BGP_GR] bgp_graceful_restart_disable_cmd : END "); return bgp_vty_return(vty, ret); } @@ -3309,15 +3326,17 @@ DEFUN (no_bgp_graceful_restart_disable, int ret = BGP_GR_FAILURE; ret = bgp_gr_update_all(bgp, NO_GLOBAL_DISABLE_CMD); - - VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer, - ret); + if (ret == BGP_GR_SUCCESS) { + VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, + bgp->peer, + ret); + vty_out(vty, + "Graceful restart configuration changed, reset all peers to take effect\n"); + } if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) zlog_debug( "[BGP_GR] no_bgp_graceful_restart_disable_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset all peers to take effect\n"); return bgp_vty_return(vty, ret); } @@ -3332,7 +3351,7 @@ DEFUN (bgp_neighbor_graceful_restart_set, { int idx_peer = 1; struct peer *peer; - int ret = BGP_GR_FAILURE; + int result = BGP_GR_FAILURE, ret = BGP_GR_SUCCESS; VTY_BGP_GR_DEFINE_LOOP_VARIABLE; @@ -3344,18 +3363,23 @@ DEFUN (bgp_neighbor_graceful_restart_set, if (!peer) return CMD_WARNING_CONFIG_FAILED; - ret = bgp_neighbor_graceful_restart(peer, PEER_GR_CMD); - - VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); - VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + result = bgp_neighbor_graceful_restart(peer, PEER_GR_CMD); + if (result == BGP_GR_SUCCESS) { + VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); + VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + vty_out(vty, + "Graceful restart configuration changed, reset this peer to take effect\n"); + } if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) zlog_debug( "[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); - return bgp_vty_return(vty, ret); + if (ret != BGP_GR_SUCCESS) + vty_out(vty, + "As part of configuring graceful-restart, capability send to zebra failed\n"); + + return bgp_vty_return(vty, result); } DEFUN (no_bgp_neighbor_graceful_restart, @@ -3368,7 +3392,7 @@ DEFUN (no_bgp_neighbor_graceful_restart, ) { int idx_peer = 2; - int ret = BGP_GR_FAILURE; + int result = BGP_GR_FAILURE, ret = BGP_GR_SUCCESS; struct peer *peer; VTY_BGP_GR_DEFINE_LOOP_VARIABLE; @@ -3381,18 +3405,23 @@ DEFUN (no_bgp_neighbor_graceful_restart, zlog_debug( "[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : START "); - ret = bgp_neighbor_graceful_restart(peer, NO_PEER_GR_CMD); - - VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); - VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + result = bgp_neighbor_graceful_restart(peer, NO_PEER_GR_CMD); + if (ret == BGP_GR_SUCCESS) { + VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); + VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + vty_out(vty, + "Graceful restart configuration changed, reset this peer to take effect\n"); + } if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) zlog_debug( "[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); - return bgp_vty_return(vty, ret); + if (ret != BGP_GR_SUCCESS) + vty_out(vty, + "As part of configuring graceful-restart, capability send to zebra failed\n"); + + return bgp_vty_return(vty, result); } DEFUN (bgp_neighbor_graceful_restart_helper_set, @@ -3420,15 +3449,16 @@ DEFUN (bgp_neighbor_graceful_restart_helper_set, ret = bgp_neighbor_graceful_restart(peer, PEER_HELPER_CMD); - - VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); - VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + if (ret == BGP_GR_SUCCESS) { + VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); + VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + vty_out(vty, + "Graceful restart configuration changed, reset this peer to take effect\n"); + } if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) zlog_debug( "[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); return bgp_vty_return(vty, ret); } @@ -3457,15 +3487,16 @@ DEFUN (no_bgp_neighbor_graceful_restart_helper, "[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : START "); ret = bgp_neighbor_graceful_restart(peer, NO_PEER_HELPER_CMD); - - VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); - VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + if (ret == BGP_GR_SUCCESS) { + VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); + VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + vty_out(vty, + "Graceful restart configuration changed, reset this peer to take effect\n"); + } if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) zlog_debug( "[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); return bgp_vty_return(vty, ret); } @@ -3493,18 +3524,19 @@ DEFUN (bgp_neighbor_graceful_restart_disable_set, return CMD_WARNING_CONFIG_FAILED; ret = bgp_neighbor_graceful_restart(peer, PEER_DISABLE_CMD); + if (ret == BGP_GR_SUCCESS) { + if (peer->bgp->t_startup) + bgp_peer_gr_flags_update(peer); - if (peer->bgp->t_startup) - bgp_peer_gr_flags_update(peer); - - VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); - VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); + VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + vty_out(vty, + "Graceful restart configuration changed, reset this peer to take effect\n"); + } if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) zlog_debug( "[BGP_GR]bgp_neighbor_graceful_restart_disable_set_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); return bgp_vty_return(vty, ret); } @@ -3533,15 +3565,16 @@ DEFUN (no_bgp_neighbor_graceful_restart_disable, "[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : START "); ret = bgp_neighbor_graceful_restart(peer, NO_PEER_DISABLE_CMD); - - VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); - VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + if (ret == BGP_GR_SUCCESS) { + VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer); + VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret); + vty_out(vty, + "Graceful restart configuration changed, reset this peer to take effect\n"); + } if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) zlog_debug( "[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : END "); - vty_out(vty, - "Graceful restart configuration changed, reset this peer to take effect\n"); return bgp_vty_return(vty, ret); } @@ -4298,6 +4331,24 @@ DEFPY (bgp_default_software_version_capability, return CMD_SUCCESS; } +DEFPY (bgp_default_dynamic_capability, + bgp_default_dynamic_capability_cmd, + "[no] bgp default dynamic-capability", + NO_STR + BGP_STR + "Configure BGP defaults\n" + "Advertise dynamic capability for all neighbors\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + if (no) + UNSET_FLAG(bgp->flags, BGP_FLAG_DYNAMIC_CAPABILITY); + else + SET_FLAG(bgp->flags, BGP_FLAG_DYNAMIC_CAPABILITY); + + return CMD_SUCCESS; +} + /* "bgp network import-check" configuration. */ DEFUN (bgp_network_import_check, bgp_network_import_check_cmd, @@ -4315,6 +4366,9 @@ DEFUN (bgp_network_import_check, return CMD_SUCCESS; } +#if CONFDATE > 20241013 +CPP_NOTICE("Drop `bgp network import-check exact` command") +#endif ALIAS_HIDDEN(bgp_network_import_check, bgp_network_import_check_exact_cmd, "bgp network import-check exact", BGP_STR @@ -5077,6 +5131,8 @@ DEFUN (no_neighbor, struct peer_group *group; struct peer *peer; struct peer *other; + afi_t afi; + int lr_count; ret = str2sockunion(argv[idx_peer]->arg, &su); if (ret < 0) { @@ -5094,6 +5150,15 @@ DEFUN (no_neighbor, group = peer_group_lookup(bgp, argv[idx_peer]->arg); if (group) { + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + lr_count = listcount(group->listen_range[afi]); + if (lr_count) { + vty_out(vty, + "%%Peer-group %s is attached to %d listen-range(s), delete them first\n", + group->name, lr_count); + return CMD_WARNING_CONFIG_FAILED; + } + } peer_group_notify_unconfig(group); peer_group_delete(group); } else { @@ -5171,9 +5236,20 @@ DEFUN (no_neighbor_peer_group, VTY_DECLVAR_CONTEXT(bgp, bgp); int idx_word = 2; struct peer_group *group; + afi_t afi; + int lr_count; group = peer_group_lookup(bgp, argv[idx_word]->arg); if (group) { + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + lr_count = listcount(group->listen_range[afi]); + if (lr_count) { + vty_out(vty, + "%%Peer-group %s is attached to %d listen-range(s), delete them first\n", + group->name, lr_count); + return CMD_WARNING_CONFIG_FAILED; + } + } peer_group_notify_unconfig(group); peer_group_delete(group); } else { @@ -7073,6 +7149,26 @@ DEFUN (no_neighbor_disable_connected_check, PEER_FLAG_DISABLE_CONNECTED_CHECK); } +DEFPY(neighbor_extended_link_bw, + neighbor_extended_link_bw_cmd, + "[no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor extended-link-bandwidth", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Send Extended (64-bit) version of encoding for Link-Bandwidth\n") +{ + int ret; + + if (no) + ret = peer_flag_unset_vty(vty, neighbor, + PEER_FLAG_EXTENDED_LINK_BANDWIDTH); + else + ret = peer_flag_set_vty(vty, neighbor, + PEER_FLAG_EXTENDED_LINK_BANDWIDTH); + + return ret; +} + /* disable-link-bw-encoding-ieee */ DEFUN(neighbor_disable_link_bw_encoding_ieee, neighbor_disable_link_bw_encoding_ieee_cmd, @@ -9198,15 +9294,64 @@ DEFPY( NEIGHBOR_ADDR_STR2 "Detect AS loops before sending to neighbor\n") { + return peer_flag_set_vty(vty, neighbor, PEER_FLAG_AS_LOOP_DETECTION); +} + +DEFPY (neighbor_addpath_paths_limit, + neighbor_addpath_paths_limit_cmd, + "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor addpath-rx-paths-limit (1-65535)$paths_limit", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Paths Limit for Addpath to receive from the peer\n" + "Maximum number of paths\n") +{ struct peer *peer; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); + int ret; peer = peer_and_group_lookup_vty(vty, neighbor); if (!peer) return CMD_WARNING_CONFIG_FAILED; - peer->as_path_loop_detection = true; + ret = peer_af_flag_set_vty(vty, neighbor, afi, safi, + PEER_FLAG_ADDPATH_RX_PATHS_LIMIT); - return CMD_SUCCESS; + peer->addpath_paths_limit[afi][safi].send = paths_limit; + + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_PATHS_LIMIT, + CAPABILITY_ACTION_SET); + + return ret; +} + +DEFPY (no_neighbor_addpath_paths_limit, + no_neighbor_addpath_paths_limit_cmd, + "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor addpath-rx-paths-limit [(1-65535)]", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Paths Limit for Addpath to receive from the peer\n" + "Maximum number of paths\n") +{ + struct peer *peer; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); + int ret; + + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + ret = peer_af_flag_unset_vty(vty, neighbor, afi, safi, + PEER_FLAG_ADDPATH_RX_PATHS_LIMIT); + + peer->addpath_paths_limit[afi][safi].send = 0; + + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_PATHS_LIMIT, + CAPABILITY_ACTION_SET); + + return ret; } DEFPY( @@ -9218,15 +9363,7 @@ DEFPY( NEIGHBOR_ADDR_STR2 "Detect AS loops before sending to neighbor\n") { - struct peer *peer; - - peer = peer_and_group_lookup_vty(vty, neighbor); - if (!peer) - return CMD_WARNING_CONFIG_FAILED; - - peer->as_path_loop_detection = false; - - return CMD_SUCCESS; + return peer_flag_unset_vty(vty, neighbor, PEER_FLAG_AS_LOOP_DETECTION); } DEFPY(neighbor_path_attribute_discard, @@ -9343,6 +9480,92 @@ DEFPY(no_neighbor_path_attribute_treat_as_withdraw, return CMD_SUCCESS; } +DEFPY(neighbor_damp, + neighbor_damp_cmd, + "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor dampening [(1-45)$half [(1-20000)$reuse (1-20000)$suppress (1-255)$max]]", + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Enable neighbor route-flap dampening\n" + "Half-life time for the penalty\n" + "Value to start reusing a route\n" + "Value to start suppressing a route\n" + "Maximum duration to suppress a stable route\n") +{ + struct peer *peer = peer_and_group_lookup_vty(vty, neighbor); + + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + if (!half) + half = DEFAULT_HALF_LIFE; + if (!reuse) { + reuse = DEFAULT_REUSE; + suppress = DEFAULT_SUPPRESS; + max = half * 4; + } + if (suppress < reuse) { + vty_out(vty, "Suppress value cannot be less than reuse value\n"); + return CMD_WARNING_CONFIG_FAILED; + } + bgp_peer_damp_enable(peer, bgp_node_afi(vty), bgp_node_safi(vty), + half * 60, reuse, suppress, max * 60); + return CMD_SUCCESS; +} + +DEFPY(no_neighbor_damp, + no_neighbor_damp_cmd, + "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor dampening [HALF [REUSE SUPPRESS MAX]]", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Enable neighbor route-flap dampening\n" + "Half-life time for the penalty\n" + "Value to start reusing a route\n" + "Value to start suppressing a route\n" + "Maximum duration to suppress a stable route\n") +{ + struct peer *peer = peer_and_group_lookup_vty(vty, neighbor); + + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + bgp_peer_damp_disable(peer, bgp_node_afi(vty), bgp_node_safi(vty)); + return CMD_SUCCESS; +} + +DEFPY (show_ip_bgp_neighbor_damp_param, + show_ip_bgp_neighbor_damp_param_cmd, + "show [ip] bgp [<ipv4|ipv6> [unicast]] neighbors <A.B.C.D|X:X::X:X|WORD>$neighbor dampening parameters [json]$json", + SHOW_STR + IP_STR + BGP_STR + BGP_AFI_HELP_STR + "Address Family modifier\n" + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Neighbor route-flap dampening information\n" + "Display detail of configured dampening parameters\n" + JSON_STR) +{ + bool use_json = false; + int idx = 0; + afi_t afi = AFI_IP; + safi_t safi = SAFI_UNICAST; + struct peer *peer; + + if (argv_find(argv, argc, "ip", &idx)) + afi = AFI_IP; + if (argv_find(argv, argc, "ipv4", &idx)) + afi = AFI_IP; + if (argv_find(argv, argc, "ipv6", &idx)) + afi = AFI_IP6; + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING; + if (json) + use_json = true; + bgp_show_peer_dampening_parameters(vty, peer, afi, safi, use_json); + return CMD_SUCCESS; +} + static int set_ecom_list(struct vty *vty, int argc, struct cmd_token **argv, struct ecommunity **list, bool is_rt6) { @@ -9628,8 +9851,6 @@ DEFPY (af_label_vpn_export, BGP_VPN_POLICY_TOVPN_LABEL_AUTO); /* fetch a label */ bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE; - bgp_lp_get(LP_TYPE_VRF, &bgp->vpn_policy[afi], - vpn_leak_label_callback); } else { bgp->vpn_policy[afi].tovpn_label = label; UNSET_FLAG(bgp->vpn_policy[afi].flags, @@ -10218,12 +10439,20 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd, vrf_bgp = bgp_lookup_by_name(import_name); if (!vrf_bgp) { - if (strcmp(import_name, VRF_DEFAULT_NAME) == 0) + if (strcmp(import_name, VRF_DEFAULT_NAME) == 0) { vrf_bgp = bgp_default; - else + } else { /* Auto-create assuming the same AS */ ret = bgp_get_vty(&vrf_bgp, &as, import_name, bgp_type, NULL, ASNOTATION_UNDEFINED); + + /* Auto created VRF instances should be marked + * properly, otherwise we have a state after bgpd + * restart where VRF instance has default VRF's ASN. + */ + SET_FLAG(vrf_bgp->vrf_flags, BGP_VRF_AUTO); + } + if (ret) { vty_out(vty, "VRF %s is not configured as a bgp instance\n", @@ -10672,7 +10901,10 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name, if (rm_p->prefixlen == match.prefixlen) { SET_FLAG(rm->flags, BGP_NODE_USER_CLEAR); - bgp_process(bgp, rm, afi, safi); + bgp_process(bgp, rm, + bgp_dest_get_bgp_path_info( + rm), + afi, safi); } bgp_dest_unlock_node(rm); } @@ -10684,7 +10916,9 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name, if (dest_p->prefixlen == match.prefixlen) { SET_FLAG(dest->flags, BGP_NODE_USER_CLEAR); - bgp_process(bgp, dest, afi, safi); + bgp_process(bgp, dest, + bgp_dest_get_bgp_path_info(dest), + afi, safi); } bgp_dest_unlock_node(dest); } @@ -11439,10 +11673,9 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer, BGP_NOTIFY_CEASE_HARD_RESET) : ""); } else { - vty_out(vty, " %s (%s)\n", + vty_out(vty, " %s (%s)\n", peer_down_str[(int)peer->last_reset], - peer->soft_version ? peer->soft_version - : "n/a"); + peer->soft_version ? peer->soft_version : "n/a"); } } } @@ -12392,6 +12625,9 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi, vty_out(vty, "{\n"); for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + nbr_output = true; if (use_json) { if (!is_first) @@ -12684,7 +12920,7 @@ static void bgp_show_neighbor_graceful_restart_remote_mode(struct vty *vty, if (json) json_object_string_add(json, "remoteGrMode", mode); else - vty_out(vty, "%s\n", mode); + vty_out(vty, "%s", mode); } static void bgp_show_neighbor_graceful_restart_local_mode(struct vty *vty, @@ -12716,7 +12952,7 @@ static void bgp_show_neighbor_graceful_restart_local_mode(struct vty *vty, if (json) json_object_string_add(json, "localGrMode", mode); else - vty_out(vty, "%s\n", mode); + vty_out(vty, "%s", mode); } static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi( @@ -14070,33 +14306,28 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, CHECK_FLAG( p->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_RCV)) { - if (CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_ADV) && - CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_RCV)) - json_object_boolean_true_add( - json_sub, - "txAdvertisedAndReceived"); - else if ( - CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_ADV)) - json_object_boolean_true_add( - json_sub, - "txAdvertised"); - else if ( - CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_RCV)) - json_object_boolean_true_add( - json_sub, - "txReceived"); + json_object_boolean_add( + json_sub, + "txAdvertisedAndReceived", + CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_TX_ADV) && + CHECK_FLAG( + p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_TX_RCV)); + + json_object_boolean_add( + json_sub, "txAdvertised", + CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_TX_ADV)); + + json_object_boolean_add( + json_sub, "txReceived", + CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_TX_RCV)); } if (CHECK_FLAG( @@ -14105,33 +14336,28 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, CHECK_FLAG( p->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_RCV)) { - if (CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_ADV) && - CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_RCV)) - json_object_boolean_true_add( - json_sub, - "rxAdvertisedAndReceived"); - else if ( - CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_ADV)) - json_object_boolean_true_add( - json_sub, - "rxAdvertised"); - else if ( - CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_RCV)) - json_object_boolean_true_add( - json_sub, - "rxReceived"); + json_object_boolean_add( + json_sub, + "rxAdvertisedAndReceived", + CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_RX_ADV) && + CHECK_FLAG( + p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_RX_RCV)); + + json_object_boolean_add( + json_sub, "rxAdvertised", + CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_RX_ADV)); + + json_object_boolean_add( + json_sub, "rxReceived", + CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_RX_RCV)); } if (CHECK_FLAG( @@ -14157,6 +14383,86 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, json_add); } + /* Paths-Limit */ + if (CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_ADV)) { + json_object *json_add = NULL; + const char *print_store; + + json_add = json_object_new_object(); + + FOREACH_AFI_SAFI (afi, safi) { + json_object *json_sub = NULL; + + json_sub = json_object_new_object(); + print_store = get_afi_safi_str(afi, safi, + true); + + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV) || + CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) { + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV) && + CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) { + json_object_boolean_true_add( + json_sub, + "advertisedAndReceived"); + json_object_int_add( + json_sub, + "advertisedPathsLimit", + p->addpath_paths_limit + [afi][safi] + .send); + json_object_int_add( + json_sub, + "receivedPathsLimit", + p->addpath_paths_limit + [afi][safi] + .receive); + } else if (CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_PATHS_LIMIT_AF_ADV)) { + json_object_boolean_true_add( + json_sub, + "advertised"); + json_object_int_add( + json_sub, + "advertisedPathsLimit", + p->addpath_paths_limit + [afi][safi] + .send); + } else if (CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) { + json_object_boolean_true_add( + json_sub, + "received"); + json_object_int_add( + json_sub, + "receivedPathsLimit", + p->addpath_paths_limit + [afi][safi] + .receive); + } + } + + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV) || + CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) + json_object_object_add(json_add, + print_store, + json_sub); + else + json_object_free(json_sub); + } + + json_object_object_add(json_cap, "pathsLimit", + json_add); + } + /* Dynamic */ if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) || CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) { @@ -14610,6 +14916,47 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, } } + /* Paths-Limit */ + if (CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_PATHS_LIMIT_ADV)) { + vty_out(vty, " Paths-Limit:\n"); + + FOREACH_AFI_SAFI (afi, safi) { + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV) || + CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) { + vty_out(vty, " %s: ", + get_afi_safi_str(afi, + safi, + false)); + + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_ADV)) + vty_out(vty, + "advertised (%u)", + p->addpath_paths_limit + [afi][safi] + .send); + + if (CHECK_FLAG(p->af_cap[afi][safi], + PEER_CAP_PATHS_LIMIT_AF_RCV)) + vty_out(vty, + "%sreceived (%u)", + CHECK_FLAG(p->af_cap[afi] + [safi], + PEER_CAP_PATHS_LIMIT_AF_ADV) + ? " and " + : "", + p->addpath_paths_limit + [afi][safi] + .receive); + + vty_out(vty, "\n"); + } + } + } + /* Dynamic */ if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) || CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) { @@ -15662,6 +16009,9 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty, vty_out(vty, "{\n"); for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + nbr_output = true; if (use_json) { if (!(json = json_object_new_object())) { @@ -16221,6 +16571,9 @@ static int bgp_show_all_instance_route_leak_vty(struct vty *vty, afi_t afi, if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) vrf_name = bgp->name; + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + if (use_json) { json_vrf = json_object_new_object(); } else { @@ -16311,6 +16664,9 @@ static void bgp_show_all_instances_updgrps_vty(struct vty *vty, afi_t afi, struct bgp *bgp; for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; + if (!uj) vty_out(vty, "\nInstance %s:\n", (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) @@ -17512,6 +17868,76 @@ DEFUN (bgp_redistribute_ipv6_rmap_metric, return bgp_redistribute_set(bgp, AFI_IP6, type, 0, changed); } +DEFPY(bgp_redistribute_ipv6_table, bgp_redistribute_ipv6_table_cmd, + "redistribute table-direct (1-65535)$table_id [{metric$metric (0-4294967295)$metric_val|route-map WORD$rmap}]", + "Redistribute information from another routing protocol\n" + "Non-main Kernel Routing Table - Direct\n" + "Table ID\n" + "Metric for redistributed routes\n" + "Default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + bool changed = false; + struct route_map *route_map = NULL; + struct bgp_redist *red; + + if (rmap) + route_map = route_map_lookup_warn_noexist(vty, rmap); + + if (bgp->vrf_id != VRF_DEFAULT) { + vty_out(vty, + "%% Only default BGP instance can use 'table-direct'\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (table_id == RT_TABLE_MAIN || table_id == RT_TABLE_LOCAL) { + vty_out(vty, + "%% 'table-direct', can not use %lu routing table\n", + table_id); + return CMD_WARNING_CONFIG_FAILED; + } + + red = bgp_redist_add(bgp, AFI_IP6, ZEBRA_ROUTE_TABLE_DIRECT, table_id); + if (rmap) + changed = bgp_redistribute_rmap_set(red, rmap, route_map); + if (metric) + changed |= bgp_redistribute_metric_set(bgp, red, AFI_IP6, + ZEBRA_ROUTE_TABLE_DIRECT, + metric_val); + return bgp_redistribute_set(bgp, AFI_IP6, ZEBRA_ROUTE_TABLE_DIRECT, + table_id, changed); +} + +DEFPY(no_bgp_redistribute_ipv6_table, no_bgp_redistribute_ipv6_table_cmd, + "no redistribute table-direct (1-65535)$table_id [{metric (0-4294967295)|route-map WORD}]", + NO_STR + "Redistribute information from another routing protocol\n" + "Non-main Kernel Routing Table - Direct\n" + "Table ID\n" + "Metric for redistributed routes\n" + "Default metric\n" + "Route map reference\n" + "Pointer to route-map entries\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + if (bgp->vrf_id != VRF_DEFAULT) { + vty_out(vty, + "%% Only default BGP instance can use 'table-direct'\n"); + return CMD_WARNING_CONFIG_FAILED; + } + if (table_id == RT_TABLE_MAIN || table_id == RT_TABLE_LOCAL) { + vty_out(vty, + "%% 'table-direct', can not use %lu routing table\n", + table_id); + return CMD_WARNING_CONFIG_FAILED; + } + + bgp_redistribute_unset(bgp, AFI_IP6, ZEBRA_ROUTE_TABLE_DIRECT, table_id); + return CMD_SUCCESS; +} + DEFUN (bgp_redistribute_ipv6_metric_rmap, bgp_redistribute_ipv6_metric_rmap_cmd, "redistribute " FRR_IP6_REDIST_STR_BGPD " metric (0-4294967295) route-map RMAP_NAME", @@ -18172,6 +18598,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s disable-link-bw-encoding-ieee\n", addr); + if (peergroup_flag_check(peer, PEER_FLAG_EXTENDED_LINK_BANDWIDTH)) + vty_out(vty, " neighbor %s extended-link-bandwidth\n", addr); + /* extended-optional-parameters */ if (peergroup_flag_check(peer, PEER_FLAG_EXTENDED_OPT_PARAMS)) vty_out(vty, " neighbor %s extended-optional-parameters\n", @@ -18231,9 +18660,15 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s timers delayopen %u\n", addr, peer->bgp->default_delayopen); - /* capability dynamic */ - if (peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY)) - vty_out(vty, " neighbor %s capability dynamic\n", addr); + /* capability software-version */ + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DYNAMIC_CAPABILITY)) { + if (!peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY)) + vty_out(vty, " no neighbor %s capability dynamic\n", + addr); + } else { + if (peergroup_flag_check(peer, PEER_FLAG_DYNAMIC_CAPABILITY)) + vty_out(vty, " neighbor %s capability dynamic\n", addr); + } /* capability extended-nexthop */ if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_ENHE)) { @@ -18282,7 +18717,7 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s strict-capability-match\n", addr); /* Sender side AS path loop detection. */ - if (peer->as_path_loop_detection) + if (peergroup_flag_check(peer, PEER_FLAG_AS_LOOP_DETECTION)) vty_out(vty, " neighbor %s sender-as-path-loop-detection\n", addr); @@ -18404,6 +18839,11 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DISABLE_ADDPATH_RX)) vty_out(vty, " neighbor %s disable-addpath-rx\n", addr); + if (CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_ADDPATH_RX_PATHS_LIMIT)) + vty_out(vty, " neighbor %s addpath-rx-paths-limit %u\n", addr, + peer->addpath_paths_limit[afi][safi].send); + /* ORF capability. */ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM) || peergroup_af_flag_check(peer, afi, safi, @@ -18679,7 +19119,16 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi, /* BGP flag dampening. */ if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) - bgp_config_write_damp(vty, afi, safi); + bgp_config_write_damp(vty, bgp, afi, safi); + for (ALL_LIST_ELEMENTS_RO(bgp->group, node, group)) + if (peer_af_flag_check(group->conf, afi, safi, + PEER_FLAG_CONFIG_DAMPENING)) + bgp_config_write_peer_damp(vty, group->conf, afi, safi); + for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) + if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) && + peer_af_flag_check(peer, afi, safi, + PEER_FLAG_CONFIG_DAMPENING)) + bgp_config_write_peer_damp(vty, peer, afi, safi); for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) bgp_config_write_peer_af(vty, bgp, group->conf, afi, safi); @@ -18765,9 +19214,9 @@ int bgp_config_write(struct vty *vty) if (CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) vty_out(vty, "bgp send-extra-data zebra\n"); - /* BGP session DSCP value */ - if (bm->tcp_dscp != IPTOS_PREC_INTERNETCONTROL) - vty_out(vty, "bgp session-dscp %u\n", bm->tcp_dscp >> 2); + /* DSCP value for outgoing packets in BGP connections */ + if (bm->ip_tos != IPTOS_PREC_INTERNETCONTROL) + vty_out(vty, "bgp session-dscp %u\n", bm->ip_tos >> 2); /* BGP InQ limit */ if (bm->inq_limit != BM_DEFAULT_Q_LIMIT) @@ -18919,6 +19368,15 @@ int bgp_config_write(struct vty *vty) ? "" : "no "); + if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_DYNAMIC_CAPABILITY) != + SAVE_BGP_DYNAMIC_CAPABILITY) + vty_out(vty, + " %sbgp default dynamic-capability\n", + CHECK_FLAG(bgp->flags, + BGP_FLAG_DYNAMIC_CAPABILITY) + ? "" + : "no "); + /* BGP default subgroup-pkt-queue-max. */ if (bgp->default_subgroup_pkt_queue_max != BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX) @@ -19967,6 +20425,9 @@ void bgp_vty_init(void) /* bgp default software-version-capability */ install_element(BGP_NODE, &bgp_default_software_version_capability_cmd); + /* bgp default dynamic-capability */ + install_element(BGP_NODE, &bgp_default_dynamic_capability_cmd); + /* "bgp default subgroup-pkt-queue-max" commands. */ install_element(BGP_NODE, &bgp_default_subgroup_pkt_queue_max_cmd); install_element(BGP_NODE, &no_bgp_default_subgroup_pkt_queue_max_cmd); @@ -20565,6 +21026,26 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &no_neighbor_addpath_tx_bestpath_per_as_cmd); + /* "neighbor addpath-rx-paths-limit" commands.*/ + install_element(BGP_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4M_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4M_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4L_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV4L_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6M_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6M_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6L_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_IPV6L_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_VPNV4_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_VPNV4_NODE, &no_neighbor_addpath_paths_limit_cmd); + install_element(BGP_VPNV6_NODE, &neighbor_addpath_paths_limit_cmd); + install_element(BGP_VPNV6_NODE, &no_neighbor_addpath_paths_limit_cmd); + /* "neighbor sender-as-path-loop-detection" commands. */ install_element(BGP_NODE, &neighbor_aspath_loop_detection_cmd); install_element(BGP_NODE, &no_neighbor_aspath_loop_detection_cmd); @@ -20641,6 +21122,9 @@ void bgp_vty_init(void) install_element(BGP_NODE, &no_neighbor_disable_link_bw_encoding_ieee_cmd); + + install_element(BGP_NODE, &neighbor_extended_link_bw_cmd); + /* "neighbor extended-optional-parameters" commands. */ install_element(BGP_NODE, &neighbor_extended_optional_parameters_cmd); install_element(BGP_NODE, @@ -20967,6 +21451,15 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &neighbor_maximum_prefix_threshold_restart_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_cmd); + install_element(BGP_EVPN_NODE, &neighbor_maximum_prefix_cmd); + install_element(BGP_EVPN_NODE, &neighbor_maximum_prefix_threshold_cmd); + install_element(BGP_EVPN_NODE, &neighbor_maximum_prefix_warning_cmd); + install_element(BGP_EVPN_NODE, + &neighbor_maximum_prefix_threshold_warning_cmd); + install_element(BGP_EVPN_NODE, &neighbor_maximum_prefix_restart_cmd); + install_element(BGP_EVPN_NODE, + &neighbor_maximum_prefix_threshold_restart_cmd); + install_element(BGP_EVPN_NODE, &no_neighbor_maximum_prefix_cmd); /* "neighbor allowas-in" */ install_element(BGP_NODE, &neighbor_allowas_in_hidden_cmd); @@ -21014,6 +21507,23 @@ void bgp_vty_init(void) install_element(BGP_EVPN_NODE, &neighbor_soo_cmd); install_element(BGP_EVPN_NODE, &no_neighbor_soo_cmd); + /* "neighbor dampening" commands. */ + install_element(BGP_NODE, &neighbor_damp_cmd); + install_element(BGP_NODE, &no_neighbor_damp_cmd); + install_element(BGP_IPV4_NODE, &neighbor_damp_cmd); + install_element(BGP_IPV4_NODE, &no_neighbor_damp_cmd); + install_element(BGP_IPV4M_NODE, &neighbor_damp_cmd); + install_element(BGP_IPV4M_NODE, &no_neighbor_damp_cmd); + install_element(BGP_IPV4L_NODE, &neighbor_damp_cmd); + install_element(BGP_IPV4L_NODE, &no_neighbor_damp_cmd); + install_element(BGP_IPV6_NODE, &neighbor_damp_cmd); + install_element(BGP_IPV6_NODE, &no_neighbor_damp_cmd); + install_element(BGP_IPV6M_NODE, &neighbor_damp_cmd); + install_element(BGP_IPV6M_NODE, &no_neighbor_damp_cmd); + install_element(BGP_IPV6L_NODE, &neighbor_damp_cmd); + install_element(BGP_IPV6L_NODE, &no_neighbor_damp_cmd); + install_element(VIEW_NODE, &show_ip_bgp_neighbor_damp_param_cmd); + /* address-family commands. */ install_element(BGP_NODE, &address_family_ipv4_safi_cmd); install_element(BGP_NODE, &address_family_ipv6_safi_cmd); @@ -21117,6 +21627,8 @@ void bgp_vty_init(void) install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_cmd); install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_rmap_metric_cmd); install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_metric_rmap_cmd); + install_element(BGP_IPV6_NODE, &bgp_redistribute_ipv6_table_cmd); + install_element(BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_table_cmd); /* import|export vpn [route-map RMAP_NAME] */ install_element(BGP_IPV4_NODE, &bgp_imexport_vpn_cmd); @@ -21226,9 +21738,6 @@ static const char *community_direct_str(int direct) static void community_list_perror(struct vty *vty, int ret) { switch (ret) { - case COMMUNITY_LIST_ERR_CANT_FIND_LIST: - vty_out(vty, "%% Can't find community-list\n"); - break; case COMMUNITY_LIST_ERR_MALFORMED_VAL: vty_out(vty, "%% Malformed community-list value\n"); break; @@ -21338,16 +21847,11 @@ DEFUN (no_community_list_standard_all, argv_find(argv, argc, "COMMUNITY_LIST_NAME", &idx); cl_name_or_number = argv[idx]->arg; - int ret = community_list_unset(bgp_clist, cl_name_or_number, str, seq, - direct, style); + community_list_unset(bgp_clist, cl_name_or_number, str, seq, direct, + style); XFREE(MTYPE_TMP, str); - if (ret < 0) { - community_list_perror(vty, ret); - return CMD_WARNING_CONFIG_FAILED; - } - return CMD_SUCCESS; } @@ -21451,16 +21955,11 @@ DEFUN (no_community_list_expanded_all, argv_find(argv, argc, "COMMUNITY_LIST_NAME", &idx); cl_name_or_number = argv[idx]->arg; - int ret = community_list_unset(bgp_clist, cl_name_or_number, str, seq, - direct, style); + community_list_unset(bgp_clist, cl_name_or_number, str, seq, direct, + style); XFREE(MTYPE_TMP, str); - if (ret < 0) { - community_list_perror(vty, ret); - return CMD_WARNING_CONFIG_FAILED; - } - return CMD_SUCCESS; } @@ -21616,7 +22115,6 @@ static int lcommunity_list_set_vty(struct vty *vty, int argc, static int lcommunity_list_unset_vty(struct vty *vty, int argc, struct cmd_token **argv, int style) { - int ret; int direct = 0; char *str = NULL; int idx = 0; @@ -21649,18 +22147,13 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc, argv_find(argv, argc, "LCOMMUNITY_LIST_NAME", &idx); /* Unset community list. */ - ret = lcommunity_list_unset(bgp_clist, argv[idx]->arg, str, seq, direct, - style); + lcommunity_list_unset(bgp_clist, argv[idx]->arg, str, seq, direct, + style); /* Free temporary community list string allocated by argv_concat(). */ XFREE(MTYPE_TMP, str); - if (ret < 0) { - community_list_perror(vty, ret); - return CMD_WARNING_CONFIG_FAILED; - } - return CMD_SUCCESS; } @@ -22057,16 +22550,11 @@ DEFUN (no_extcommunity_list_standard_all, argv_find(argv, argc, "EXTCOMMUNITY_LIST_NAME", &idx); cl_number_or_name = argv[idx]->arg; - int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str, - seq, direct, style); + extcommunity_list_unset(bgp_clist, cl_number_or_name, str, seq, direct, + style); XFREE(MTYPE_TMP, str); - if (ret < 0) { - community_list_perror(vty, ret); - return CMD_WARNING_CONFIG_FAILED; - } - return CMD_SUCCESS; } @@ -22122,16 +22610,11 @@ DEFUN (no_extcommunity_list_expanded_all, argv_find(argv, argc, "EXTCOMMUNITY_LIST_NAME", &idx); cl_number_or_name = argv[idx]->arg; - int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str, - seq, direct, style); + extcommunity_list_unset(bgp_clist, cl_number_or_name, str, seq, direct, + style); XFREE(MTYPE_TMP, str); - if (ret < 0) { - community_list_perror(vty, ret); - return CMD_WARNING_CONFIG_FAILED; - } - return CMD_SUCCESS; } diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index 4955e4c..addd717 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -13,8 +13,6 @@ struct bgp; #define BGP_INSTANCE_HELP_STR "BGP view\nBGP VRF\nView/VRF name\n" #define BGP_INSTANCE_ALL_HELP_STR "BGP view\nBGP VRF\nAll Views/VRFs\n" -#define BGP_AF_STR "Address Family\n" -#define BGP_AF_MODIFIER_STR "Address Family modifier\n" #define BGP_AFI_CMD_STR "<ipv4|ipv6>" #define BGP_AFI_HELP_STR BGP_AF_STR BGP_AF_STR #define BGP_SAFI_CMD_STR "<unicast|multicast|vpn>" diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index fe29662..5bb177b 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -235,6 +235,14 @@ static int bgp_ifp_up(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_up(ifp); + if (bgp_get_default() && if_is_loopback(ifp)) { + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } @@ -282,16 +290,25 @@ static int bgp_ifp_down(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_down(ifp); + if (bgp_get_default() && if_is_loopback(ifp)) { + vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) { - struct connected *ifc; + struct connected *ifc, *connected; struct bgp *bgp; struct peer *peer; struct prefix *addr; struct listnode *node, *nnode; + bool v6_ll_in_nh_global; afi_t afi; safi_t safi; @@ -309,56 +326,70 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) if (!bgp) return 0; - if (if_is_operative(ifc->ifp)) { - bgp_connected_add(bgp, ifc); + if (!if_is_operative(ifc->ifp)) + return 0; - /* If we have learnt of any neighbors on this interface, - * check to kick off any BGP interface-based neighbors, - * but only if this is a link-local address. - */ - if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) - && !list_isempty(ifc->ifp->nbr_connected)) - bgp_start_interface_nbrs(bgp, ifc->ifp); - else { - addr = ifc->address; + bgp_connected_add(bgp, ifc); - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - if (addr->family == AF_INET) - continue; + /* If we have learnt of any neighbors on this interface, + * check to kick off any BGP interface-based neighbors, + * but only if this is a link-local address. + */ + if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) && + !list_isempty(ifc->ifp->nbr_connected)) + bgp_start_interface_nbrs(bgp, ifc->ifp); + else if (ifc->address->family == AF_INET6 && + !IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)) { + addr = ifc->address; - /* - * If the Peer's interface name matches the - * interface name for which BGP received the - * update and if the received interface address - * is a globalV6 and if the peer is currently - * using a v4-mapped-v6 addr or a link local - * address, then copy the Rxed global v6 addr - * into peer's v6_global and send updates out - * with new nexthop addr. - */ - if ((peer->conf_if && - (strcmp(peer->conf_if, ifc->ifp->name) == - 0)) && - !IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6) && - ((IS_MAPPED_IPV6( - &peer->nexthop.v6_global)) || - IN6_IS_ADDR_LINKLOCAL( - &peer->nexthop.v6_global))) { - - if (bgp_debug_zebra(ifc->address)) { - zlog_debug( - "Update peer %pBP's current intf addr %pI6 and send updates", - peer, - &peer->nexthop - .v6_global); - } - memcpy(&peer->nexthop.v6_global, - &addr->u.prefix6, - IPV6_MAX_BYTELEN); - FOREACH_AFI_SAFI (afi, safi) - bgp_announce_route(peer, afi, - safi, true); + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + v6_ll_in_nh_global = false; + + if (IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global)) { + frr_each (if_connected, ifc->ifp->connected, + connected) { + if (connected->address->family != + AF_INET6) + continue; + if (!IPV6_ADDR_SAME(&connected->address + ->u.prefix6, + &peer->nexthop + .v6_global)) + continue; + /* peer->nexthop.v6_global contains a link-local address + * that needs to be replaced by the global address. + */ + v6_ll_in_nh_global = true; + break; + } + } + + /* + * If the Peer's interface name matches the + * interface name for which BGP received the + * update and if the received interface address + * is a globalV6 and if the peer is currently + * using a v4-mapped-v6 addr or a link local + * address, then copy the Rxed global v6 addr + * into peer's v6_global and send updates out + * with new nexthop addr. + */ + if (v6_ll_in_nh_global || + (peer->conf_if && + strcmp(peer->conf_if, ifc->ifp->name) == 0 && + (IS_MAPPED_IPV6(&peer->nexthop.v6_global) || + IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_global)))) { + if (bgp_debug_zebra(ifc->address)) { + zlog_debug("Update peer %pBP's current intf global addr from %pI6 to %pI6 and send updates", + peer, + &peer->nexthop.v6_global, + &addr->u.prefix6); } + memcpy(&peer->nexthop.v6_global, + &addr->u.prefix6, IPV6_MAX_BYTELEN); + FOREACH_AFI_SAFI (afi, safi) + bgp_announce_route(peer, afi, safi, + true); } } } @@ -369,10 +400,14 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) { struct listnode *node, *nnode; - struct connected *ifc; + struct connected *ifc, *connected; struct peer *peer; struct bgp *bgp; struct prefix *addr; + struct in6_addr *v6_global = NULL; + struct in6_addr *v6_local = NULL; + afi_t afi; + safi_t safi; bgp = bgp_lookup_by_vrf_id(vrf_id); @@ -391,7 +426,18 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) addr = ifc->address; - if (bgp) { + if (bgp && addr->family == AF_INET6 && + !IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6)) { + /* find another IPv6 global if possible and find the IPv6 link-local */ + frr_each (if_connected, ifc->ifp->connected, connected) { + if (connected->address->family != AF_INET6) + continue; + if (IN6_IS_ADDR_LINKLOCAL(&connected->address->u.prefix6)) + v6_local = &connected->address->u.prefix6; + else + v6_global = &connected->address->u.prefix6; + } + /* * When we are using the v6 global as part of the peering * nexthops and we are removing it, then we need to @@ -400,17 +446,17 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) * we do not want the peering to bounce. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - afi_t afi; - safi_t safi; - - if (addr->family == AF_INET) - continue; - - if (!IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6) - && memcmp(&peer->nexthop.v6_global, - &addr->u.prefix6, 16) - == 0) { - memset(&peer->nexthop.v6_global, 0, 16); + if (IPV6_ADDR_SAME(&peer->nexthop.v6_global, + &addr->u.prefix6)) { + if (v6_global) + IPV6_ADDR_COPY(&peer->nexthop.v6_global, + v6_global); + else if (v6_local) + IPV6_ADDR_COPY(&peer->nexthop.v6_global, + v6_local); + else + memset(&peer->nexthop.v6_global, 0, + IPV6_MAX_BYTELEN); FOREACH_AFI_SAFI (afi, safi) bgp_announce_route(peer, afi, safi, true); @@ -927,7 +973,8 @@ bgp_path_info_to_ipv6_nexthop(struct bgp_path_info *path, ifindex_t *ifindex) || path->attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { /* Check if route-map is set to prefer global over link-local */ - if (path->attr->mp_nexthop_prefer_global) { + if (CHECK_FLAG(path->attr->nh_flags, + BGP_ATTR_NH_MP_PREFER_GLOBAL)) { nexthop = &path->attr->mp_nexthop_global; if (IN6_IS_ADDR_LINKLOCAL(nexthop)) *ifindex = path->attr->nh_ifindex; @@ -1194,7 +1241,7 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, } static bool bgp_zebra_use_nhop_weighted(struct bgp *bgp, struct attr *attr, - uint32_t *nh_weight) + uint64_t *nh_weight) { /* zero link-bandwidth and link-bandwidth not present are treated * as the same situation. @@ -1226,7 +1273,7 @@ static void bgp_zebra_announce_parse_nexthop( struct bgp_path_info local_info; struct bgp_path_info *mpinfo_cp = &local_info; mpls_label_t *labels; - uint32_t num_labels = 0; + uint8_t num_labels = 0; mpls_label_t nh_label; int nh_othervrf = 0; bool nh_updated = false; @@ -1254,9 +1301,7 @@ static void bgp_zebra_announce_parse_nexthop( } for (; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) { - labels = NULL; - num_labels = 0; - uint32_t nh_weight; + uint64_t nh_weight; bool is_evpn; bool is_parent_evpn; @@ -1286,25 +1331,19 @@ static void bgp_zebra_announce_parse_nexthop( &nh_weight)) continue; } - if (CHECK_FLAG(info->flags, BGP_PATH_SELECTED)) - api_nh = &api->nexthops[*valid_nh_count]; - else - api_nh = &api->backup_nexthops[*valid_nh_count]; + api_nh = &api->nexthops[*valid_nh_count]; - if (CHECK_FLAG(info->attr->flag, - ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR))) - api_nh->srte_color = bgp_attr_get_color(info->attr); + api_nh->srte_color = bgp_attr_get_color(info->attr); if (bgp_debug_zebra(&api->prefix)) { - if (mpinfo->extra) { + if (bgp_path_info_num_labels(mpinfo)) { zlog_debug("%s: p=%pFX, bgp_is_valid_label: %d", __func__, p, bgp_is_valid_label( - &mpinfo->extra->label[0])); + &mpinfo->extra->labels + ->label[0])); } else { - zlog_debug( - "%s: p=%pFX, extra is NULL, no label", - __func__, p); + zlog_debug("%s: p=%pFX, no label", __func__, p); } } @@ -1370,13 +1409,10 @@ static void bgp_zebra_announce_parse_nexthop( mpinfo->peer->sort == BGP_PEER_CONFED)) *allow_recursion = true; - if (mpinfo->extra) { - labels = mpinfo->extra->label; - num_labels = mpinfo->extra->num_labels; - } + num_labels = bgp_path_info_num_labels(mpinfo); + labels = num_labels ? mpinfo->extra->labels->label : NULL; - if (labels && (num_labels > 0) && - (is_evpn || bgp_is_valid_label(&labels[0]))) { + if (num_labels && (is_evpn || bgp_is_valid_label(&labels[0]))) { enum lsp_types_t nh_label_type = ZEBRA_LSP_NONE; if (is_evpn) { @@ -1501,15 +1537,16 @@ static void bgp_debug_zebra_nh(struct zapi_route *api) snprintf(eth_buf, sizeof(eth_buf), " RMAC %s", prefix_mac2str(&api_nh->rmac, buf1, sizeof(buf1))); - zlog_debug(" nhop [%d]: %s if %u VRF %u wt %u %s %s %s", i + 1, - nh_buf, api_nh->ifindex, api_nh->vrf_id, + zlog_debug(" nhop [%d]: %s if %u VRF %u wt %" PRIu64 + " %s %s %s", + i + 1, nh_buf, api_nh->ifindex, api_nh->vrf_id, api_nh->weight, label_buf, segs_buf, eth_buf); } } -void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, - struct bgp_path_info *info, struct bgp *bgp, afi_t afi, - safi_t safi) +static enum zclient_send_status +bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, + struct bgp *bgp) { struct bgp_path_info *bpi_ultimate; struct zapi_route api = { 0 }; @@ -1521,35 +1558,19 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, route_tag_t tag; bool is_add; uint32_t nhg_id = 0; - uint32_t recursion_flag = 0; - - /* - * BGP is installing this route and bgp has been configured - * to suppress announcements until the route has been installed - * let's set the fact that we expect this route to be installed - */ - if (BGP_SUPPRESS_FIB_ENABLED(bgp)) - SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); - - /* Don't try to install if we're not connected to Zebra or Zebra doesn't - * know of this instance. - */ - if (!bgp_install_info_to_zebra(bgp)) - return; - - if (bgp->main_zebra_update_hold) - return; + struct bgp_table *table = bgp_dest_table(dest); + const struct prefix *p = bgp_dest_get_prefix(dest); - if (safi == SAFI_FLOWSPEC) { - bgp_pbr_update_entry(bgp, bgp_dest_get_prefix(dest), info, afi, - safi, true); - return; + if (table->safi == SAFI_FLOWSPEC) { + bgp_pbr_update_entry(bgp, p, info, table->afi, table->safi, + true); + return ZCLIENT_SEND_SUCCESS; } /* Make Zebra API structure. */ api.vrf_id = bgp->vrf_id; api.type = ZEBRA_ROUTE_BGP; - api.safi = safi; + api.safi = table->safi; api.prefix = *p; SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); @@ -1579,15 +1600,15 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, api.tableid = info->attr->rmap_table_id; } - if (CHECK_FLAG(info->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR))) + if (info->attr->srte_color) SET_FLAG(api.message, ZAPI_MESSAGE_SRTE); /* Metric is currently based on the best-path only */ metric = info->attr->med; bgp_zebra_announce_parse_nexthop(info, p, bgp, &api, &valid_nh_count, - afi, safi, &nhg_id, &metric, &tag, - &allow_recursion); + table->afi, table->safi, &nhg_id, + &metric, &tag, &allow_recursion); is_add = (valid_nh_count || nhg_id) ? true : false; @@ -1640,7 +1661,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, api.tag = tag; } - distance = bgp_distance_apply(p, info, afi, safi, bgp); + distance = bgp_distance_apply(p, info, table->afi, table->safi, bgp); if (distance) { SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE); api.distance = distance; @@ -1654,16 +1675,14 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, api.metric, api.tag, api.nexthop_num, nhg_id); bgp_debug_zebra_nh(&api); - if (CHECK_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION)) - recursion_flag = 1; - zlog_debug("%s: %pFX: announcing to zebra (recursion %sset)", - __func__, p, (recursion_flag ? "" : "NOT ")); + __func__, p, (allow_recursion ? "" : "NOT ")); } - zclient_route_send(is_add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, - zclient, &api); + return zclient_route_send(is_add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, + zclient, &api); } + /* Announce all routes of a table to zebra */ void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi) { @@ -1684,14 +1703,11 @@ void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi) for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) && - (pi->type == ZEBRA_ROUTE_BGP && (pi->sub_type == BGP_ROUTE_NORMAL || pi->sub_type == BGP_ROUTE_IMPORTED))) - - bgp_zebra_announce(dest, - bgp_dest_get_prefix(dest), - pi, bgp, afi, safi); + bgp_zebra_route_install(dest, pi, bgp, true, + NULL, false); } /* Announce routes of any bgp subtype of a table to zebra */ @@ -1713,39 +1729,30 @@ void bgp_zebra_announce_table_all_subtypes(struct bgp *bgp, afi_t afi, for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) && pi->type == ZEBRA_ROUTE_BGP) - bgp_zebra_announce(dest, - bgp_dest_get_prefix(dest), - pi, bgp, afi, safi); + bgp_zebra_route_install(dest, pi, bgp, true, + NULL, false); } -void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info, - struct bgp *bgp, afi_t afi, safi_t safi) +enum zclient_send_status bgp_zebra_withdraw_actual(struct bgp_dest *dest, + struct bgp_path_info *info, + struct bgp *bgp) { struct zapi_route api; struct peer *peer; + struct bgp_table *table = bgp_dest_table(dest); + const struct prefix *p = bgp_dest_get_prefix(dest); - /* - * If we are withdrawing the route, we don't need to have this - * flag set. So unset it. - */ - UNSET_FLAG(info->net->flags, BGP_NODE_FIB_INSTALL_PENDING); - - /* Don't try to install if we're not connected to Zebra or Zebra doesn't - * know of this instance. - */ - if (!bgp_install_info_to_zebra(bgp)) - return; - - if (safi == SAFI_FLOWSPEC) { + if (table->safi == SAFI_FLOWSPEC) { peer = info->peer; - bgp_pbr_update_entry(peer->bgp, p, info, afi, safi, false); - return; + bgp_pbr_update_entry(peer->bgp, p, info, table->afi, + table->safi, false); + return ZCLIENT_SEND_SUCCESS; } memset(&api, 0, sizeof(api)); api.vrf_id = bgp->vrf_id; api.type = ZEBRA_ROUTE_BGP; - api.safi = safi; + api.safi = table->safi; api.prefix = *p; if (info->attr->rmap_table_id) { @@ -1757,7 +1764,218 @@ void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info, zlog_debug("Tx route delete VRF %u %pFX", bgp->vrf_id, &api.prefix); - zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); + return zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); +} + +/* + * Walk the new Fifo list one by one and invoke bgp_zebra_announce/withdraw + * to install/withdraw the routes to zebra. + * + * If status = ZCLIENT_SEND_SUCCESS (Buffer empt)y i.e. Zebra is free to + * receive more incoming data, then pick the next item on the list and + * continue processing. + * + * If status = ZCLIENT_SEND_BUFFERED (Buffer pending) i.e. Zebra is busy, + * break and bail out of the function because once at some point when zebra + * is free, a callback is triggered which inturn call this same function and + * continue processing items on list. + */ +#define ZEBRA_ANNOUNCEMENTS_LIMIT 1000 +static void bgp_handle_route_announcements_to_zebra(struct event *e) +{ + bool is_evpn = false; + uint32_t count = 0; + struct bgp_dest *dest = NULL; + struct bgp_table *table = NULL; + enum zclient_send_status status = ZCLIENT_SEND_SUCCESS; + bool install; + const struct prefix_evpn *evp = NULL; + + while (count < ZEBRA_ANNOUNCEMENTS_LIMIT) { + is_evpn = false; + + dest = zebra_announce_pop(&bm->zebra_announce_head); + + if (!dest) + break; + + table = bgp_dest_table(dest); + install = CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL); + if (table->afi == AFI_L2VPN && table->safi == SAFI_EVPN) { + is_evpn = true; + evp = (const struct prefix_evpn *)bgp_dest_get_prefix( + dest); + } + + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("BGP %s route %pBD(%s) with dest %p and flags 0x%x to zebra", + install ? "announcing" : "withdrawing", dest, + table->bgp->name_pretty, dest, dest->flags); + + if (install) { + if (is_evpn) + status = + evpn_zebra_install(table->bgp, + dest->za_vpn, + (const struct prefix_evpn + *) + bgp_dest_get_prefix( + dest), + dest->za_bgp_pi); + else + status = bgp_zebra_announce_actual(dest, + dest->za_bgp_pi, + table->bgp); + UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL); + } else { + if (is_evpn) + status = evpn_zebra_uninstall( + table->bgp, dest->za_vpn, + (const struct prefix_evpn *) + bgp_dest_get_prefix(dest), + dest->za_bgp_pi, false); + else + status = bgp_zebra_withdraw_actual(dest, + dest->za_bgp_pi, + table->bgp); + + UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE); + } + + if (is_evpn && status == ZCLIENT_SEND_FAILURE) + flog_err(EC_BGP_EVPN_FAIL, + "%s (%u): Failed to %s EVPN %pFX %s route in VNI %u", + vrf_id_to_name(table->bgp->vrf_id), + table->bgp->vrf_id, + install ? "install" : "uninstall", evp, + evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE + ? "MACIP" + : "IMET", + dest->za_vpn->vni); + + bgp_path_info_unlock(dest->za_bgp_pi); + dest->za_bgp_pi = NULL; + dest->za_vpn = NULL; + bgp_dest_unlock_node(dest); + + if (status == ZCLIENT_SEND_BUFFERED) + break; + + count++; + } + + if (status != ZCLIENT_SEND_BUFFERED && + zebra_announce_count(&bm->zebra_announce_head)) + event_add_event(bm->master, + bgp_handle_route_announcements_to_zebra, NULL, + 0, &bm->t_bgp_zebra_route); +} + +/* + * Callback function invoked when zclient_flush_data() receives a BUFFER_EMPTY + * i.e. zebra is free to receive more incoming data. + */ +static void bgp_zebra_buffer_write_ready(void) +{ + bgp_handle_route_announcements_to_zebra(NULL); +} + +/* + * BGP is now keeping a list of dests with the dest having a pointer + * to the bgp_path_info that it will be working on. + * Here is the sequence of events that should happen: + * + * Current State New State Action + * ------------- --------- ------ + * ---- Install Place dest on list, save pi, mark + * as going to be installed + * ---- Withdrawal Place dest on list, save pi, mark + * as going to be deleted + * + * Install Install Leave dest on list, release old pi, + * save new pi, mark as going to be + * Installed + * Install Withdrawal Leave dest on list, release old pi, + * save new pi, mark as going to be + * withdrawan, remove install flag + * + * Withdrawal Install Leave dest on list, release old pi, + * save new pi, mark as going to be + * installed. + * Withdrawal Withdrawal Leave dest on list, release old pi, + * save new pi, mark as going to be + * withdrawn. + */ +void bgp_zebra_route_install(struct bgp_dest *dest, struct bgp_path_info *info, + struct bgp *bgp, bool install, struct bgpevpn *vpn, + bool is_sync) +{ + bool is_evpn = false; + struct bgp_table *table = NULL; + + table = bgp_dest_table(dest); + if (table && table->afi == AFI_L2VPN && table->safi == SAFI_EVPN) + is_evpn = true; + + /* + * BGP is installing this route and bgp has been configured + * to suppress announcements until the route has been installed + * let's set the fact that we expect this route to be installed + */ + if (install) { + if (BGP_SUPPRESS_FIB_ENABLED(bgp)) + SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); + + if (bgp->main_zebra_update_hold && !is_evpn) + return; + } else { + UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); + } + + /* + * Don't try to install if we're not connected to Zebra or Zebra doesn't + * know of this instance. + */ + if (!bgp_install_info_to_zebra(bgp) && !is_evpn) + return; + + if (!CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL) && + !CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE)) { + zebra_announce_add_tail(&bm->zebra_announce_head, dest); + /* + * If neither flag is set and za_bgp_pi is not set then it is a bug + */ + assert(!dest->za_bgp_pi); + bgp_path_info_lock(info); + bgp_dest_lock_node(dest); + dest->za_bgp_pi = info; + } else if (CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL)) { + assert(dest->za_bgp_pi); + bgp_path_info_unlock(dest->za_bgp_pi); + bgp_path_info_lock(info); + dest->za_bgp_pi = info; + } else if (CHECK_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE)) { + assert(dest->za_bgp_pi); + bgp_path_info_unlock(dest->za_bgp_pi); + bgp_path_info_lock(info); + dest->za_bgp_pi = info; + } + + if (is_evpn) { + dest->za_vpn = vpn; + dest->za_is_sync = is_sync; + } + + if (install) { + UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE); + SET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL); + } else { + UNSET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_INSTALL); + SET_FLAG(dest->flags, BGP_NODE_SCHEDULE_FOR_DELETE); + } + + event_add_event(bm->master, bgp_handle_route_announcements_to_zebra, + NULL, 0, &bm->t_bgp_zebra_route); } /* Withdraw all entries in a BGP instances RIB table from Zebra */ @@ -1778,8 +1996,8 @@ void bgp_zebra_withdraw_table_all_subtypes(struct bgp *bgp, afi_t afi, safi_t sa for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) && (pi->type == ZEBRA_ROUTE_BGP)) - bgp_zebra_withdraw(bgp_dest_get_prefix(dest), - pi, bgp, afi, safi); + bgp_zebra_route_install(dest, pi, bgp, false, + NULL, false); } } } @@ -1964,7 +2182,7 @@ bool bgp_redistribute_metric_set(struct bgp *bgp, struct bgp_redist *red, bgp_path_info_set_flag(dest, pi, BGP_PATH_ATTR_CHANGED); - bgp_process(bgp, dest, afi, SAFI_UNICAST); + bgp_process(bgp, dest, pi, afi, SAFI_UNICAST); } } } @@ -3148,6 +3366,15 @@ static int bgp_ifp_create(struct interface *ifp) bgp_update_interface_nbrs(bgp, ifp, ifp); hook_call(bgp_vrf_status_changed, bgp, ifp); + + if (bgp_get_default() && if_is_loopback(ifp)) { + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); + vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP6); + vpn_leak_postchange_all(); + } + return 0; } @@ -3452,6 +3679,7 @@ void bgp_zebra_init(struct event_loop *master, unsigned short instance) zclient = zclient_new(master, &zclient_options_default, bgp_handlers, array_size(bgp_handlers)); zclient_init(zclient, ZEBRA_ROUTE_BGP, 0, &bgpd_privs); + zclient->zebra_buffer_write_ready = bgp_zebra_buffer_write_ready; zclient->zebra_connected = bgp_zebra_connected; zclient->zebra_capabilities = bgp_zebra_capabilities; zclient->nexthop_update = bgp_nexthop_update; @@ -3892,8 +4120,7 @@ int bgp_zebra_srv6_manager_release_locator_chunk(const char *name) void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label, ifindex_t ifindex, vrf_id_t vrf_id, enum lsp_types_t ltype, struct prefix *p, - uint32_t num_labels, - mpls_label_t out_labels[]) + uint8_t num_labels, mpls_label_t out_labels[]) { struct zapi_labels zl = {}; struct zapi_nexthop *znh; diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 396c833..55a4185 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -28,13 +28,11 @@ extern void bgp_zebra_destroy(void); extern int bgp_zebra_get_table_range(struct zclient *zc, uint32_t chunk_size, uint32_t *start, uint32_t *end); extern int bgp_if_update_all(void); -extern void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, - struct bgp_path_info *path, struct bgp *bgp, - afi_t afi, safi_t safi); +extern void bgp_zebra_route_install(struct bgp_dest *dest, + struct bgp_path_info *path, struct bgp *bgp, + bool install, struct bgpevpn *vpn, + bool is_sync); extern void bgp_zebra_announce_table(struct bgp *bgp, afi_t afi, safi_t safi); -extern void bgp_zebra_withdraw(const struct prefix *p, - struct bgp_path_info *path, struct bgp *bgp, - afi_t afi, safi_t safi); /* Announce routes of any bgp subtype of a table to zebra */ extern void bgp_zebra_announce_table_all_subtypes(struct bgp *bgp, afi_t afi, @@ -122,9 +120,12 @@ extern int bgp_zebra_srv6_manager_release_locator_chunk(const char *name); extern void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label, ifindex_t index, vrf_id_t vrfid, enum lsp_types_t ltype, - struct prefix *p, uint32_t num_labels, + struct prefix *p, uint8_t num_labels, mpls_label_t out_labels[]); extern bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size, bool label_auto); extern void bgp_zebra_release_label_range(uint32_t start, uint32_t end); +extern enum zclient_send_status +bgp_zebra_withdraw_actual(struct bgp_dest *dest, struct bgp_path_info *info, + struct bgp *bgp); #endif /* _QUAGGA_BGP_ZEBRA_H */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index d6d874b..894226a 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1377,7 +1377,7 @@ int bgp_global_gr_init(struct bgp *bgp) /*GLOBAL_GR_cmd */ /*no_Global_GR_cmd*/ GLOBAL_GR, GLOBAL_INVALID, /*GLOBAL_DISABLE_cmd*//*no_Global_Disable_cmd*/ - GLOBAL_INVALID, GLOBAL_HELPER + GLOBAL_DISABLE, GLOBAL_HELPER }, /* GLOBAL_INVALID Mode */ { @@ -1411,13 +1411,13 @@ int bgp_peer_gr_init(struct peer *peer) /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */ {PEER_DISABLE, bgp_peer_gr_action }, {PEER_INVALID, NULL }, /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */ - { PEER_INVALID, NULL }, {PEER_GLOBAL_INHERIT, + { PEER_HELPER, NULL }, {PEER_GLOBAL_INHERIT, bgp_peer_gr_action } }, { /* PEER_GR Mode */ /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */ - { PEER_INVALID, NULL }, { PEER_GLOBAL_INHERIT, + { PEER_GR, NULL }, { PEER_GLOBAL_INHERIT, bgp_peer_gr_action }, /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */ {PEER_DISABLE, bgp_peer_gr_action }, { PEER_INVALID, NULL }, @@ -1429,7 +1429,7 @@ int bgp_peer_gr_init(struct peer *peer) /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */ { PEER_GR, bgp_peer_gr_action }, { PEER_INVALID, NULL }, /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */ - { PEER_INVALID, NULL }, { PEER_GLOBAL_INHERIT, + { PEER_DISABLE, NULL }, { PEER_GLOBAL_INHERIT, bgp_peer_gr_action }, /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */ { PEER_HELPER, bgp_peer_gr_action }, { PEER_INVALID, NULL } @@ -1550,6 +1550,8 @@ struct peer *peer_new(struct bgp *bgp) PEER_FLAG_SEND_LARGE_COMMUNITY); peer->addpath_type[afi][safi] = BGP_ADDPATH_NONE; peer->addpath_best_selected[afi][safi] = 0; + peer->addpath_paths_limit[afi][safi].receive = 0; + peer->addpath_paths_limit[afi][safi].send = 0; peer->soo[afi][safi] = NULL; } @@ -1565,6 +1567,9 @@ struct peer *peer_new(struct bgp *bgp) if (CHECK_FLAG(bgp->flags, BGP_FLAG_SOFT_VERSION_CAPABILITY)) peer_flag_set(peer, PEER_FLAG_CAPABILITY_SOFT_VERSION); + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DYNAMIC_CAPABILITY)) + peer_flag_set(peer, PEER_FLAG_DYNAMIC_CAPABILITY); + SET_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_FQDN); SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_FQDN); @@ -1646,6 +1651,8 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src) peer_dst->weight[afi][safi] = peer_src->weight[afi][safi]; peer_dst->addpath_type[afi][safi] = peer_src->addpath_type[afi][safi]; + peer_dst->addpath_paths_limit[afi][safi] = + peer_src->addpath_paths_limit[afi][safi]; } for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) { @@ -1869,21 +1876,31 @@ void bgp_peer_conf_if_to_su_update(struct peer_connection *connection) void bgp_recalculate_afi_safi_bestpaths(struct bgp *bgp, afi_t afi, safi_t safi) { struct bgp_dest *dest, *ndest; + struct bgp_path_info *pi, *next; struct bgp_table *table; for (dest = bgp_table_top(bgp->rib[afi][safi]); dest; dest = bgp_route_next(dest)) { table = bgp_dest_get_bgp_table_info(dest); - if (table != NULL) { - /* Special handling for 2-level routing - * tables. */ - if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP - || safi == SAFI_EVPN) { - for (ndest = bgp_table_top(table); ndest; - ndest = bgp_route_next(ndest)) - bgp_process(bgp, ndest, afi, safi); - } else - bgp_process(bgp, dest, afi, safi); + + if (!table) + continue; + + /* Special handling for 2-level routing + * tables. */ + if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP + || safi == SAFI_EVPN) { + for (ndest = bgp_table_top(table); ndest; + ndest = bgp_route_next(ndest)) { + for (pi = bgp_dest_get_bgp_path_info(ndest); + (pi != NULL) && (next = pi->next, 1); + pi = next) + bgp_process(bgp, ndest, pi, afi, safi); + } + } else { + for (pi = bgp_dest_get_bgp_path_info(dest); + (pi != NULL) && (next = pi->next, 1); pi = next) + bgp_process(bgp, dest, pi, afi, safi); } } } @@ -2691,6 +2708,14 @@ int peer_delete(struct peer *peer) if (peer->bfd_config) bgp_peer_remove_bfd_config(peer); + /* Delete peer route flap dampening configuration. This needs to happen + * before removing the peer from peer groups. + */ + FOREACH_AFI_SAFI (afi, safi) + if (peer_af_flag_check(peer, afi, safi, + PEER_FLAG_CONFIG_DAMPENING)) + bgp_peer_damp_disable(peer, afi, safi); + /* If this peer belongs to peer group, clear up the relationship. */ if (peer->group) { @@ -2938,6 +2963,13 @@ static void peer_group2peer_config_copy(struct peer_group *group, SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_SOFT_VERSION); + /* capability dynamic apply */ + if (!CHECK_FLAG(peer->flags_override, + PEER_FLAG_DYNAMIC_CAPABILITY)) + if (CHECK_FLAG(conf->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) + SET_FLAG(peer->flags, + PEER_FLAG_DYNAMIC_CAPABILITY); + /* password apply */ if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_PASSWORD)) PEER_STR_ATTR_INHERIT(peer, group, password, @@ -2992,9 +3024,21 @@ int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as, peer_as_change(group->conf, *as, as_type, as_str); for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { - if (((peer->as_type == AS_SPECIFIED) && peer->as != *as) - || (peer->as_type != as_type)) + if (((peer->as_type == AS_SPECIFIED) && peer->as != *as) || + (peer->as_type != as_type)) { peer_as_change(peer, *as, as_type, as_str); + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s peer %s set to as_type %u curr status %s trigger BGP_Start", + __func__, peer->host, peer->as_type, + lookup_msg(bgp_status_msg, + peer->connection->status, NULL)); + /* Start Peer FSM to form neighbor using new as, + * NOTE: the connection is triggered upon start + * timer expiry. + */ + if (!BGP_PEER_START_SUPPRESSED(peer)) + BGP_EVENT_ADD(peer->connection, BGP_Start); + } } return 0; @@ -3089,7 +3133,7 @@ int peer_group_delete(struct peer_group *group) int peer_group_remote_as_delete(struct peer_group *group) { - struct peer *peer, *other; + struct peer *peer; struct listnode *node, *nnode; if ((group->conf->as_type == AS_UNSPECIFIED) @@ -3097,19 +3141,12 @@ int peer_group_remote_as_delete(struct peer_group *group) return 0; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { - other = peer->doppelganger; - if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE)) bgp_zebra_terminate_radv(peer->bgp, peer); - peer_delete(peer); - - if (other && other->connection->status != Deleted) { - other->group = NULL; - peer_delete(other); - } + /* reset existing peer connection */ + peer_as_change(peer, 0, AS_UNSPECIFIED, NULL); } - list_delete_all_node(group->peer); group->conf->as = 0; group->conf->as_type = AS_UNSPECIFIED; @@ -3583,10 +3620,13 @@ struct bgp *bgp_lookup_by_name(const char *name) struct bgp *bgp; struct listnode *node, *nnode; - for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) + continue; if ((bgp->name == NULL && name == NULL) || (bgp->name && name && strcmp(bgp->name, name) == 0)) return bgp; + } return NULL; } @@ -3835,6 +3875,9 @@ void bgp_instance_down(struct bgp *bgp) struct listnode *node; struct listnode *next; + /* Cleanup evpn instance state */ + bgp_evpn_instance_down(bgp); + /* Stop timers. */ if (bgp->t_rmap_def_originate_eval) EVENT_OFF(bgp->t_rmap_def_originate_eval); @@ -3869,10 +3912,35 @@ int bgp_delete(struct bgp *bgp) afi_t afi; safi_t safi; int i; + struct bgp_dest *dest = NULL; + struct bgp_dest *dest_next = NULL; + struct bgp_table *dest_table = NULL; struct graceful_restart_info *gr_info; + uint32_t cnt_before, cnt_after; assert(bgp); + /* + * Iterate the pending dest list and remove all the dest pertaininig to + * the bgp under delete. + */ + cnt_before = zebra_announce_count(&bm->zebra_announce_head); + for (dest = zebra_announce_first(&bm->zebra_announce_head); dest; + dest = dest_next) { + dest_next = zebra_announce_next(&bm->zebra_announce_head, dest); + dest_table = bgp_dest_table(dest); + if (dest_table->bgp == bgp) { + zebra_announce_del(&bm->zebra_announce_head, dest); + bgp_path_info_unlock(dest->za_bgp_pi); + bgp_dest_unlock_node(dest); + } + } + + cnt_after = zebra_announce_count(&bm->zebra_announce_head); + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("Zebra Announce Fifo cleanup count before %u and after %u during BGP %s deletion", + cnt_before, cnt_after, bgp->name_pretty); + bgp_soft_reconfig_table_task_cancel(bgp, NULL, NULL); /* make sure we withdraw any exported routes */ @@ -3921,6 +3989,11 @@ int bgp_delete(struct bgp *bgp) EVENT_OFF(gr_info->t_route_select); } + /* Delete route flap dampening configuration */ + FOREACH_AFI_SAFI (afi, safi) { + bgp_damp_disable(bgp, afi, safi); + } + if (BGP_DEBUG(zebra, ZEBRA)) { if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) zlog_debug("Deleting Default VRF"); @@ -4385,6 +4458,11 @@ struct peer *peer_lookup_dynamic_neighbor(struct bgp *bgp, union sockunion *su) zlog_debug("%s Dynamic Neighbor added, group %s count %d", peer->host, group->name, dncount); + if (dncount == gbgp->dynamic_neighbors_limit) { + zlog_warn("Dynamic Neighbor %s added as last connection. Peer-group %s reached maximum listen limit %d", + peer->host, group->name, + gbgp->dynamic_neighbors_limit); + } return peer; } @@ -4571,7 +4649,7 @@ static const struct peer_flag_action peer_flag_action_list[] = { {PEER_FLAG_DONT_CAPABILITY, 0, peer_change_none}, {PEER_FLAG_OVERRIDE_CAPABILITY, 0, peer_change_none}, {PEER_FLAG_STRICT_CAP_MATCH, 0, peer_change_none}, - {PEER_FLAG_DYNAMIC_CAPABILITY, 0, peer_change_reset}, + {PEER_FLAG_DYNAMIC_CAPABILITY, 0, peer_change_none}, {PEER_FLAG_DISABLE_CONNECTED_CHECK, 0, peer_change_reset}, {PEER_FLAG_CAPABILITY_ENHE, 0, peer_change_reset}, {PEER_FLAG_ENFORCE_FIRST_AS, 0, peer_change_reset_in}, @@ -4594,6 +4672,8 @@ static const struct peer_flag_action peer_flag_action_list[] = { {PEER_FLAG_GRACEFUL_SHUTDOWN, 0, peer_change_none}, {PEER_FLAG_CAPABILITY_SOFT_VERSION, 0, peer_change_none}, {PEER_FLAG_CAPABILITY_FQDN, 0, peer_change_none}, + {PEER_FLAG_AS_LOOP_DETECTION, 0, peer_change_none}, + {PEER_FLAG_EXTENDED_LINK_BANDWIDTH, 0, peer_change_none}, {0, 0, 0}}; static const struct peer_flag_action peer_af_flag_action_list[] = { @@ -4628,6 +4708,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] = { {PEER_FLAG_SOO, 0, peer_change_reset}, {PEER_FLAG_ACCEPT_OWN, 0, peer_change_reset}, {PEER_FLAG_SEND_EXT_COMMUNITY_RPKI, 1, peer_change_reset_out}, + {PEER_FLAG_ADDPATH_RX_PATHS_LIMIT, 0, peer_change_none}, {0, 0, 0}}; /* Proper action set. */ @@ -4758,6 +4839,8 @@ void bgp_shutdown_enable(struct bgp *bgp, const char *msg) /* iterate through peers of BGP instance */ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + peer->last_reset = PEER_DOWN_USER_SHUTDOWN; + /* continue, if peer is already in administrative shutdown. */ if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)) continue; @@ -4812,8 +4895,10 @@ void bgp_shutdown_disable(struct bgp *bgp) /* clear the BGP instances shutdown flag */ UNSET_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN); - for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) + for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { bgp_timer_set(peer->connection); + peer->last_reset = PEER_DOWN_WAITING_OPEN; + } } /* Change specified peer flag. */ @@ -4885,6 +4970,10 @@ static int peer_flag_modify(struct peer *peer, uint64_t flag, int set) bgp_zebra_terminate_radv(peer->bgp, peer); } + if (flag == PEER_FLAG_SHUTDOWN) + peer->last_reset = set ? PEER_DOWN_USER_SHUTDOWN + : PEER_DOWN_WAITING_OPEN; + /* Execute flag action on peer. */ if (action.type == peer_change_reset) peer_flag_modify_action(peer, flag); @@ -4920,6 +5009,10 @@ static int peer_flag_modify(struct peer *peer, uint64_t flag, int set) set ? bgp_zebra_initiate_radv(member->bgp, member) : bgp_zebra_terminate_radv(member->bgp, member); + if (flag == PEER_FLAG_SHUTDOWN) + member->last_reset = set ? PEER_DOWN_USER_SHUTDOWN + : PEER_DOWN_WAITING_OPEN; + /* Execute flag action on peer-group member. */ if (action.type == peer_change_reset) peer_flag_modify_action(member, flag); @@ -8298,6 +8391,8 @@ void bgp_master_init(struct event_loop *master, const int buffer_size, memset(&bgp_master, 0, sizeof(bgp_master)); bm = &bgp_master; + + zebra_announce_init(&bm->zebra_announce_head); bm->bgp = list_new(); bm->listen_sockets = list_new(); bm->port = BGP_PORT_DEFAULT; @@ -8311,11 +8406,12 @@ void bgp_master_init(struct event_loop *master, const int buffer_size, bm->terminating = false; bm->socket_buffer = buffer_size; bm->wait_for_fib = false; - bm->tcp_dscp = IPTOS_PREC_INTERNETCONTROL; + bm->ip_tos = IPTOS_PREC_INTERNETCONTROL; bm->inq_limit = BM_DEFAULT_Q_LIMIT; bm->outq_limit = BM_DEFAULT_Q_LIMIT; bm->t_bgp_sync_label_manager = NULL; bm->t_bgp_start_label_manager = NULL; + bm->t_bgp_zebra_route = NULL; bgp_mac_init(); /* init the rd id space. @@ -8482,6 +8578,7 @@ void bgp_init(unsigned short instance) /* BGP inits. */ bgp_attr_init(); + bgp_labels_init(); bgp_debug_init(); bgp_community_alias_init(); bgp_dump_init(); @@ -8566,6 +8663,7 @@ void bgp_terminate(void) EVENT_OFF(bm->t_rmap_update); EVENT_OFF(bm->t_bgp_sync_label_manager); EVENT_OFF(bm->t_bgp_start_label_manager); + EVENT_OFF(bm->t_bgp_zebra_route); bgp_mac_finish(); } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 0f69095..1f8cc53 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -18,6 +18,8 @@ #include "iana_afi.h" #include "asn.h" +PREDECL_LIST(zebra_announce); + /* For union sockunion. */ #include "queue.h" #include "sockunion.h" @@ -31,6 +33,7 @@ #include "bgp_addpath_types.h" #include "bgp_nexthop.h" #include "bgp_io.h" +#include "bgp_damp.h" #include "lib/bfd.h" @@ -163,8 +166,8 @@ struct bgp_master { bool terminating; /* global flag that sigint terminate seen */ - /* DSCP value for TCP sessions */ - uint8_t tcp_dscp; + /* TOS value for outgoing packets in BGP connections */ + uint8_t ip_tos; #define BM_DEFAULT_Q_LIMIT 10000 uint32_t inq_limit; @@ -173,8 +176,13 @@ struct bgp_master { struct event *t_bgp_sync_label_manager; struct event *t_bgp_start_label_manager; + struct event *t_bgp_zebra_route; + bool v6_with_v4_nexthops; + /* To preserve ordering of installations into zebra across all Vrfs */ + struct zebra_announce_head zebra_announce_head; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(bgp_master); @@ -471,7 +479,7 @@ struct bgp { * factor (e.g., number of multipaths for the prefix) * Value is in Mbps */ - uint32_t lb_ref_bw; + uint64_t lb_ref_bw; #define BGP_LINK_BW_REF_BW 1 /* BGP flags. */ @@ -522,6 +530,8 @@ struct bgp { #define BGP_FLAG_LU_IPV6_EXPLICIT_NULL (1ULL << 34) #define BGP_FLAG_SOFT_VERSION_CAPABILITY (1ULL << 35) #define BGP_FLAG_ENFORCE_FIRST_AS (1ULL << 36) +#define BGP_FLAG_DYNAMIC_CAPABILITY (1ULL << 37) +#define BGP_FLAG_VNI_DOWN (1ULL << 38) /* BGP default address-families. * New peers inherit enabled afi/safis from bgp instance. @@ -825,6 +835,9 @@ struct bgp { enum asnotation_mode asnotation; + /* BGP route flap dampening configuration */ + struct bgp_damp_config damp[AFI_MAX][SAFI_MAX]; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(bgp); @@ -1140,6 +1153,11 @@ struct llgr_info { uint8_t flags; }; +struct addpath_paths_limit { + uint16_t send; + uint16_t receive; +}; + struct peer_connection { struct peer *peer; @@ -1333,6 +1351,8 @@ struct peer { #define PEER_CAP_ROLE_RCV (1ULL << 26) /* role received */ #define PEER_CAP_SOFT_VERSION_ADV (1ULL << 27) #define PEER_CAP_SOFT_VERSION_RCV (1ULL << 28) +#define PEER_CAP_PATHS_LIMIT_ADV (1U << 29) +#define PEER_CAP_PATHS_LIMIT_RCV (1U << 30) /* Capability flags (reset in bgp_stop) */ uint32_t af_cap[AFI_MAX][SAFI_MAX]; @@ -1351,6 +1371,8 @@ struct peer { #define PEER_CAP_ENHE_AF_NEGO (1U << 14) /* Extended nexthop afi/safi negotiated */ #define PEER_CAP_LLGR_AF_ADV (1U << 15) #define PEER_CAP_LLGR_AF_RCV (1U << 16) +#define PEER_CAP_PATHS_LIMIT_AF_ADV (1U << 17) +#define PEER_CAP_PATHS_LIMIT_AF_RCV (1U << 18) /* Global configuration flags. */ /* @@ -1461,6 +1483,8 @@ struct peer { #define PEER_FLAG_GRACEFUL_SHUTDOWN (1ULL << 35) #define PEER_FLAG_CAPABILITY_SOFT_VERSION (1ULL << 36) #define PEER_FLAG_CAPABILITY_FQDN (1ULL << 37) /* fqdn capability */ +#define PEER_FLAG_AS_LOOP_DETECTION (1ULL << 38) /* as path loop detection */ +#define PEER_FLAG_EXTENDED_LINK_BANDWIDTH (1ULL << 39) /* *GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART @@ -1488,6 +1512,9 @@ struct peer { /* Last update packet sent time */ time_t pkt_stime[AFI_MAX][SAFI_MAX]; + /* Peer / peer group route flap dampening configuration */ + struct bgp_damp_config damp[AFI_MAX][SAFI_MAX]; + /* Peer Per AF flags */ /* * Please consult the comments for *flags_override*, *flags_invert* and @@ -1528,6 +1555,8 @@ struct peer { #define PEER_FLAG_DISABLE_ADDPATH_RX (1ULL << 27) #define PEER_FLAG_SOO (1ULL << 28) #define PEER_FLAG_SEND_EXT_COMMUNITY_RPKI (1ULL << 29) +#define PEER_FLAG_ADDPATH_RX_PATHS_LIMIT (1ULL << 30) +#define PEER_FLAG_CONFIG_DAMPENING (1U << 31) #define PEER_FLAG_ACCEPT_OWN (1ULL << 63) enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX]; @@ -1647,6 +1676,8 @@ struct peer { uint32_t stat_pfx_nh_invalid; uint32_t stat_pfx_dup_withdraw; uint32_t stat_upd_7606; /* RFC7606: treat-as-withdraw */ + uint64_t stat_pfx_loc_rib; /* RFC7854 : Number of routes in Loc-RIB */ + uint64_t stat_pfx_adj_rib_in; /* RFC7854 : Number of routes in Adj-RIBs-In */ /* BGP state count */ uint32_t established; /* Established */ @@ -1813,9 +1844,6 @@ struct peer { char *hostname; char *domainname; - /* Sender side AS path loop detection. */ - bool as_path_loop_detection; - /* Extended Message Support */ uint16_t max_packet_size; @@ -1845,6 +1873,9 @@ struct peer { /* Add-Path Best selected paths number to advertise */ uint8_t addpath_best_selected[AFI_MAX][SAFI_MAX]; + /* Add-Path Paths-Limit */ + struct addpath_paths_limit addpath_paths_limit[AFI_MAX][SAFI_MAX]; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(peer); @@ -1951,7 +1982,6 @@ struct bgp_nlri { #define BGP_ATTR_LARGE_COMMUNITIES 32 #define BGP_ATTR_OTC 35 #define BGP_ATTR_PREFIX_SID 40 -#define BGP_ATTR_SRTE_COLOR 51 #ifdef ENABLE_BGP_VNC_ATTR #define BGP_ATTR_VNC 255 #endif @@ -1970,6 +2000,7 @@ struct bgp_nlri { #define BGP_NOTIFY_FSM_ERR 5 #define BGP_NOTIFY_CEASE 6 #define BGP_NOTIFY_ROUTE_REFRESH_ERR 7 +#define BGP_NOTIFY_SEND_HOLD_ERR 8 /* Subcodes for BGP Finite State Machine Error */ #define BGP_NOTIFY_FSM_ERR_SUBCODE_UNSPECIFIC 0 diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index 382af05..23e3eb4 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -463,7 +463,7 @@ void del_vnc_route(struct rfapi_descriptor *rfd, bgp_aggregate_decrement(bgp, p, bpi, afi, safi); bgp_path_info_delete(bn, bpi); - bgp_process(bgp, bn, afi, safi); + bgp_process(bgp, bn, bpi, afi, safi); } else { vnc_zlog_debug_verbose( "%s: Couldn't find route (safi=%d) at prefix %pFX", @@ -549,6 +549,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ int flags) { afi_t afi; /* of the VN address */ + struct bgp_labels bgp_labels = {}; struct bgp_path_info *new; struct bgp_path_info *bpi; struct bgp_dest *bn; @@ -592,7 +593,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ } } - if (label) + if (label && *label != MPLS_INVALID_LABEL) label_val = *label; else label_val = MPLS_LABEL_IMPLICIT_NULL; @@ -1001,7 +1002,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ /* Process change. */ bgp_aggregate_increment(bgp, p, bpi, afi, safi); - bgp_process(bgp, bn, afi, safi); + bgp_process(bgp, bn, bpi, afi, safi); bgp_dest_unlock_node(bn); vnc_zlog_debug_any( @@ -1020,7 +1021,10 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ new->extra->vnc = XCALLOC(MTYPE_BGP_ROUTE_EXTRA_VNC, sizeof(struct bgp_path_info_extra_vnc)); new->extra->vnc->vnc.export.rfapi_handle = (void *)rfd; - encode_label(label_val, &new->extra->label[0]); + + encode_label(label_val, &bgp_labels.label[0]); + bgp_labels.num_labels = 1; + new->extra->labels = bgp_labels_intern(&bgp_labels); /* debug */ @@ -1046,7 +1050,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ } bgp_dest_unlock_node(bn); - bgp_process(bgp, bn, afi, safi); + bgp_process(bgp, bn, new, afi, safi); vnc_zlog_debug_any( "%s: Added route (safi=%s) at prefix %s (bn=%p, prd=%pRDP)", diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index 168b8e4..2afcb2f 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -442,6 +442,7 @@ static struct bgp_path_info *rfapiBgpInfoCreate(struct attr *attr, uint32_t *label) { struct bgp_path_info *new; + struct bgp_labels bgp_labels = {}; new = info_make(type, sub_type, 0, peer, attr, NULL); @@ -454,8 +455,11 @@ static struct bgp_path_info *rfapiBgpInfoCreate(struct attr *attr, new->extra->vnc->vnc.import.rd = *prd; new->extra->vnc->vnc.import.create_time = monotime(NULL); } - if (label) - encode_label(*label, &new->extra->label[0]); + if (label && *label != MPLS_INVALID_LABEL) { + encode_label(*label, &bgp_labels.label[0]); + bgp_labels.num_labels = 1; + new->extra->labels = bgp_labels_intern(&bgp_labels); + } peer_lock(peer); @@ -1267,7 +1271,10 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, bpi->extra->vnc->vnc.import.rd.val[1]; /* label comes from MP_REACH_NLRI label */ - vo->v.l2addr.label = decode_label(&bpi->extra->label[0]); + vo->v.l2addr.label = + bgp_path_info_num_labels(bpi) + ? decode_label(&bpi->extra->labels->label[0]) + : MPLS_INVALID_LABEL; new->vn_options = vo; @@ -4154,15 +4161,16 @@ static void rfapiBgpTableFilteredImport(struct bgp *bgp, for (bpi = bgp_dest_get_bgp_path_info(dest2); bpi; bpi = bpi->next) { - uint32_t label = 0; + uint32_t label = MPLS_INVALID_LABEL; if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) continue; - if (bpi->extra) + if (bgp_path_info_num_labels(bpi)) label = decode_label( - &bpi->extra->label[0]); + &bpi->extra->labels + ->label[0]); (*rfapiBgpInfoFilteredImportFunction( safi))( it, /* which import table */ diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c index 316904e..a0bdf49 100644 --- a/bgpd/rfapi/rfapi_rib.c +++ b/bgpd/rfapi/rfapi_rib.c @@ -691,7 +691,10 @@ static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri, bpi->extra->vnc->vnc.import.rd.val[1]; /* label comes from MP_REACH_NLRI label */ - vo->v.l2addr.label = decode_label(&bpi->extra->label[0]); + vo->v.l2addr.label = + bgp_path_info_num_labels(bpi) + ? decode_label(&bpi->extra->labels->label[0]) + : MPLS_INVALID_LABEL; rfapi_vn_options_free( ri->vn_options); /* maybe free old version */ diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 5da99db..9bfb6c4 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -413,12 +413,12 @@ void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p, XFREE(MTYPE_ECOMMUNITY_STR, s); } - if (bpi->extra != NULL) { - if (bpi->extra->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK) + if (bgp_path_info_num_labels(bpi)) { + if (bpi->extra->labels->label[0] == BGP_PREVENT_VRF_2_VRF_LEAK) vty_out(vty, " label=VRF2VRF"); else vty_out(vty, " label=%u", - decode_label(&bpi->extra->label[0])); + decode_label(&bpi->extra->labels->label[0])); } if (bpi->attr->srv6_l3vpn || bpi->attr->srv6_vpn) { @@ -1052,8 +1052,8 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, snprintf(buf_un, sizeof(buf_un), "%s", inet_ntop(pfx_vn.family, &pfx_vn.u.prefix, buf_ntop, sizeof(buf_ntop))); - if (bpi->extra) { - uint32_t l = decode_label(&bpi->extra->label[0]); + if (bgp_path_info_num_labels(bpi)) { + uint32_t l = decode_label(&bpi->extra->labels->label[0]); snprintf(buf_vn, sizeof(buf_vn), "Label: %d", l); } else /* should never happen */ { @@ -1161,8 +1161,8 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, } } } - if (tun_type != BGP_ENCAP_TYPE_MPLS && bpi->extra) { - uint32_t l = decode_label(&bpi->extra->label[0]); + if (tun_type != BGP_ENCAP_TYPE_MPLS && bgp_path_info_num_labels(bpi)) { + uint32_t l = decode_label(&bpi->extra->labels->label[0]); if (!MPLS_LABEL_IS_NULL(l)) { fp(out, " Label: %d", l); diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c index c067b7a..2bb7c1b 100644 --- a/bgpd/rfapi/vnc_import_bgp.c +++ b/bgpd/rfapi/vnc_import_bgp.c @@ -414,7 +414,7 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi( uint32_t lifetime; uint32_t *plifetime; struct bgp_attr_encap_subtlv *encaptlvs; - uint32_t label = 0; + uint32_t label; struct rfapi_un_option optary[3]; struct rfapi_un_option *opt = NULL; @@ -470,16 +470,19 @@ static void vnc_import_bgp_add_route_mode_resolve_nve_one_bi( if (bgp_attr_get_ecommunity(bpi->attr)) ecommunity_merge(new_ecom, bgp_attr_get_ecommunity(bpi->attr)); - if (bpi->extra) - label = decode_label(&bpi->extra->label[0]); + if (bgp_path_info_num_labels(bpi)) + label = decode_label(&bpi->extra->labels->label[0]); + else + label = MPLS_INVALID_LABEL; add_vnc_route(&vncHDResolveNve, bgp, SAFI_MPLS_VPN, - prefix, /* unicast route prefix */ + prefix, /* unicast route prefix */ prd, &nexthop_h, /* new nexthop */ local_pref, plifetime, (struct bgp_tea_options *)encaptlvs, /* RFP options */ opt, NULL, new_ecom, med, /* NULL => don't set med */ - (label ? &label : NULL), /* NULL= default */ + ((label != MPLS_INVALID_LABEL) ? &label + : NULL), /* NULL= default */ ZEBRA_ROUTE_BGP_DIRECT, BGP_ROUTE_REDISTRIBUTE, RFAPI_AHR_RFPOPT_IS_VNCTLV); /* flags */ @@ -1678,7 +1681,7 @@ static void vnc_import_bgp_exterior_add_route_it( bpi_interior = bpi_interior->next) { struct prefix_rd *prd; struct attr new_attr; - uint32_t label = 0; + uint32_t label; if (!is_usable_interior_route(bpi_interior)) continue; @@ -1695,14 +1698,19 @@ static void vnc_import_bgp_exterior_add_route_it( */ have_usable_route = 1; - if (bpi_interior->extra) { + if (bpi_interior->extra) prd = &bpi_interior->extra->vnc->vnc .import.rd; - label = decode_label( - &bpi_interior->extra->label[0]); - } else + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels + ->label[0]); + else + label = MPLS_INVALID_LABEL; + /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(new_attr)); new_attr = *bpi_interior->attr; @@ -1851,7 +1859,7 @@ void vnc_import_bgp_exterior_del_route( for (bpi_interior = rn->info; bpi_interior; bpi_interior = bpi_interior->next) { struct prefix_rd *prd; - uint32_t label = 0; + uint32_t label; if (!is_usable_interior_route(bpi_interior)) continue; @@ -1864,14 +1872,19 @@ void vnc_import_bgp_exterior_del_route( */ have_usable_route = 1; - if (bpi_interior->extra) { + if (bpi_interior->extra) prd = &bpi_interior->extra->vnc->vnc .import.rd; - label = decode_label( - &bpi_interior->extra->label[0]); - } else + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels + ->label[0]); + else + label = MPLS_INVALID_LABEL; + rfapiBgpInfoFilteredImportVPN( it, FIF_ACTION_KILL, bpi_interior->peer, NULL, /* rfd */ @@ -2007,18 +2020,22 @@ void vnc_import_bgp_exterior_add_route_interior( struct prefix_rd *prd; struct attr new_attr; - uint32_t label = 0; + uint32_t label; assert(bpi_exterior); assert(pfx_exterior); - if (bpi_interior->extra) { + if (bpi_interior->extra) prd = &bpi_interior->extra->vnc->vnc.import.rd; - label = decode_label( - &bpi_interior->extra->label[0]); - } else + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels->label[0]); + else + label = MPLS_INVALID_LABEL; + /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(struct attr)); new_attr = *bpi_interior->attr; @@ -2097,7 +2114,7 @@ void vnc_import_bgp_exterior_add_route_interior( struct bgp_path_info *bpi; struct prefix_rd *prd; struct attr new_attr; - uint32_t label = 0; + uint32_t label; /* do pull-down */ @@ -2124,15 +2141,19 @@ void vnc_import_bgp_exterior_add_route_interior( * parent routes. */ for (bpi = par->info; bpi; bpi = bpi->next) { - - if (bpi->extra) { + if (bpi->extra) prd = &bpi->extra->vnc->vnc .import.rd; - label = decode_label( - &bpi->extra->label[0]); - } else + else prd = NULL; + if (bgp_path_info_num_labels(bpi)) + label = decode_label( + &bpi->extra->labels + ->label[0]); + else + label = MPLS_INVALID_LABEL; + rfapiBgpInfoFilteredImportVPN( it, FIF_ACTION_KILL, bpi->peer, NULL, /* rfd */ @@ -2147,14 +2168,19 @@ void vnc_import_bgp_exterior_add_route_interior( * Add constructed exterior routes based on * the new interior route at longer prefix. */ - if (bpi_interior->extra) { + if (bpi_interior->extra) prd = &bpi_interior->extra->vnc->vnc .import.rd; - label = decode_label( - &bpi_interior->extra->label[0]); - } else + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels + ->label[0]); + else + label = MPLS_INVALID_LABEL; + /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(struct attr)); new_attr = *bpi_interior->attr; @@ -2237,7 +2263,7 @@ void vnc_import_bgp_exterior_add_route_interior( struct prefix_rd *prd; struct attr new_attr; - uint32_t label = 0; + uint32_t label; /* do pull-down */ @@ -2266,13 +2292,17 @@ void vnc_import_bgp_exterior_add_route_interior( * Add constructed exterior routes based on the * new interior route at the longer prefix. */ - if (bpi_interior->extra) { + if (bpi_interior->extra) prd = &bpi_interior->extra->vnc->vnc.import.rd; - label = decode_label( - &bpi_interior->extra->label[0]); - } else + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels->label[0]); + else + label = MPLS_INVALID_LABEL; + /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(struct attr)); new_attr = *bpi_interior->attr; @@ -2372,14 +2402,19 @@ void vnc_import_bgp_exterior_del_route_interior( &cursor)) { struct prefix_rd *prd; - uint32_t label = 0; + uint32_t label; - if (bpi_interior->extra) { + if (bpi_interior->extra) prd = &bpi_interior->extra->vnc->vnc.import.rd; - label = decode_label(&bpi_interior->extra->label[0]); - } else + else prd = NULL; + if (bgp_path_info_num_labels(bpi_interior)) + label = decode_label( + &bpi_interior->extra->labels->label[0]); + else + label = MPLS_INVALID_LABEL; + rfapiBgpInfoFilteredImportVPN( it, FIF_ACTION_KILL, bpi_interior->peer, NULL, /* rfd */ pfx_exterior, NULL, afi, prd, bpi_interior->attr, @@ -2446,18 +2481,22 @@ void vnc_import_bgp_exterior_del_route_interior( struct prefix_rd *prd; struct attr new_attr; - uint32_t label = 0; + uint32_t label; if (bpi->type == ZEBRA_ROUTE_BGP_DIRECT_EXT) continue; - if (bpi->extra) { + if (bpi->extra) prd = &bpi->extra->vnc->vnc.import.rd; - label = decode_label( - &bpi->extra->label[0]); - } else + else prd = NULL; + if (bgp_path_info_num_labels(bpi)) + label = decode_label( + &bpi->extra->labels->label[0]); + else + label = MPLS_INVALID_LABEL; + /* use local_pref from unicast route */ memset(&new_attr, 0, sizeof(new_attr)); new_attr = *bpi->attr; |