diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 04:24:34 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 04:24:34 +0000 |
commit | 137ce8dd46d313f15ee93ddbb5428d702aa61ed8 (patch) | |
tree | a49f76849019651842962dff2197b705e33831e7 /bgpd | |
parent | Releasing progress-linux version 9.1-0.1~progress7.99u1. (diff) | |
download | frr-137ce8dd46d313f15ee93ddbb5428d702aa61ed8.tar.xz frr-137ce8dd46d313f15ee93ddbb5428d702aa61ed8.zip |
Merging upstream version 10.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'bgpd')
84 files changed, 5302 insertions, 2181 deletions
diff --git a/bgpd/bgp_addpath.c b/bgpd/bgp_addpath.c index de4b4a4..f391c13 100644 --- a/bgpd/bgp_addpath.c +++ b/bgpd/bgp_addpath.c @@ -10,6 +10,8 @@ #include "bgp_addpath.h" #include "bgp_route.h" +#include "bgp_open.h" +#include "bgp_packet.h" static const struct bgp_addpath_strategy_names strat_names[BGP_ADDPATH_MAX] = { { @@ -359,6 +361,31 @@ void bgp_addpath_type_changed(struct bgp *bgp) } } +int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, + uint8_t paths) +{ + int action = CAPABILITY_ACTION_UNSET; + + switch (addpath_type) { + case BGP_ADDPATH_ALL: + case BGP_ADDPATH_BEST_PER_AS: + action = CAPABILITY_ACTION_SET; + break; + case BGP_ADDPATH_BEST_SELECTED: + if (paths) + action = CAPABILITY_ACTION_SET; + else + action = CAPABILITY_ACTION_UNSET; + break; + case BGP_ADDPATH_NONE: + case BGP_ADDPATH_MAX: + action = CAPABILITY_ACTION_UNSET; + break; + } + + return action; +} + /* * Change the addpath type assigned to a peer, or peer group. In addition to * adjusting the counts, peer sessions will be reset as needed to make the @@ -373,6 +400,7 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi, struct listnode *node, *nnode; struct peer *tmp_peer; struct peer_group *group; + int action = bgp_addpath_capability_action(addpath_type, paths); if (safi == SAFI_LABELED_UNICAST) safi = SAFI_UNICAST; @@ -430,9 +458,12 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi, } } } else { - peer_change_action(peer, afi, safi, peer_change_reset); + if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) && + !CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV)) + peer_change_action(peer, afi, safi, peer_change_reset); } + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ADDPATH, action); } /* diff --git a/bgpd/bgp_addpath.h b/bgpd/bgp_addpath.h index 2b91d45..d562000 100644 --- a/bgpd/bgp_addpath.h +++ b/bgpd/bgp_addpath.h @@ -15,6 +15,12 @@ #include "bgpd/bgp_table.h" #include "lib/json.h" +struct bgp_addpath_capability { + uint16_t afi; + uint8_t safi; + uint8_t flags; +}; + #define BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE 1 void bgp_addpath_init_bgp_data(struct bgp_addpath_bgp_data *d); @@ -57,4 +63,6 @@ void bgp_addpath_update_ids(struct bgp *bgp, struct bgp_dest *dest, afi_t afi, safi_t safi); void bgp_addpath_type_changed(struct bgp *bgp); +extern int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, + uint8_t paths); #endif diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index 17d6592..a81f288 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -36,6 +36,8 @@ struct bgp_advertise_attr *bgp_advertise_attr_new(void) void bgp_advertise_attr_free(struct bgp_advertise_attr *baa) { + bgp_advertise_attr_fifo_fini(&baa->fifo); + XFREE(MTYPE_BGP_ADVERTISE_ATTR, baa); } @@ -46,6 +48,9 @@ static void *bgp_advertise_attr_hash_alloc(void *p) baa = bgp_advertise_attr_new(); baa->attr = ref->attr; + + bgp_advertise_attr_fifo_init(&baa->fifo); + return baa; } @@ -83,36 +88,13 @@ void bgp_advertise_free(struct bgp_advertise *adv) void bgp_advertise_add(struct bgp_advertise_attr *baa, struct bgp_advertise *adv) { - struct bgp_advertise *spot, *prev = NULL; - - spot = baa->adv; - - while (spot) { - prev = spot; - spot = spot->next; - } - - if (prev) { - prev->next = adv; - adv->prev = prev; - } else - adv->prev = NULL; - - adv->next = NULL; - - if (!baa->adv) - baa->adv = adv; + bgp_advertise_attr_fifo_add_tail(&baa->fifo, adv); } void bgp_advertise_delete(struct bgp_advertise_attr *baa, struct bgp_advertise *adv) { - if (adv->next) - adv->next->prev = adv->prev; - if (adv->prev) - adv->prev->next = adv->next; - else - baa->adv = adv->next; + bgp_advertise_attr_fifo_del(&baa->fifo, adv); } struct bgp_advertise_attr *bgp_advertise_attr_intern(struct hash *hash, @@ -187,7 +169,7 @@ void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr, for (adj = dest->adj_in; adj; adj = adj->next) { if (adj->peer == peer && adj->addpath_rx_id == addpath_id) { - if (adj->attr != attr) { + if (!attrhash_cmp(adj->attr, attr)) { bgp_attr_unintern(&adj->attr); adj->attr = bgp_attr_intern(attr); } diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h index 94168e2..4982106 100644 --- a/bgpd/bgp_advertise.h +++ b/bgpd/bgp_advertise.h @@ -11,26 +11,19 @@ PREDECL_DLIST(bgp_adv_fifo); struct update_subgroup; +struct bgp_advertise; -/* BGP advertise attribute. */ -struct bgp_advertise_attr { - /* Head of advertisement pointer. */ - struct bgp_advertise *adv; - - /* Reference counter. */ - unsigned long refcnt; +PREDECL_DLIST(bgp_advertise_attr_fifo); - /* Attribute pointer to be announced. */ - struct attr *attr; -}; +struct bgp_advertise_attr; +/* BGP advertise attribute. */ struct bgp_advertise { /* FIFO for advertisement. */ struct bgp_adv_fifo_item fifo; - /* Link list for same attribute advertise. */ - struct bgp_advertise *next; - struct bgp_advertise *prev; + /* FIFO for this item in the bgp_advertise_attr fifo */ + struct bgp_advertise_attr_fifo_item item; /* Prefix information. */ struct bgp_dest *dest; @@ -45,8 +38,21 @@ struct bgp_advertise { struct bgp_path_info *pathi; }; +DECLARE_DLIST(bgp_advertise_attr_fifo, struct bgp_advertise, item); DECLARE_DLIST(bgp_adv_fifo, struct bgp_advertise, fifo); +/* BGP advertise attribute. */ +struct bgp_advertise_attr { + /* Head of advertisement pointer. */ + struct bgp_advertise_attr_fifo_head fifo; + + /* Reference counter. */ + unsigned long refcnt; + + /* Attribute pointer to be announced. */ + struct attr *attr; +}; + /* BGP adjacency out. */ struct bgp_adj_out { /* RB Tree of adjacency entries */ @@ -63,14 +69,14 @@ struct bgp_adj_out { uint32_t addpath_tx_id; + /* Attribute hash */ + uint32_t attr_hash; + /* Advertised attribute. */ struct attr *attr; /* Advertisement information. */ struct bgp_advertise *adv; - - /* Attribute hash */ - uint32_t attr_hash; }; RB_HEAD(bgp_adj_out_rb, bgp_adj_out); diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 0e70de9..bc7e893 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1407,7 +1407,8 @@ struct aspath *aspath_remove_private_asns(struct aspath *aspath, as_t peer_asn) last_new_seg = new_seg; seg = seg->next; } - + if (!aspath->refcnt) + aspath_free(aspath); aspath_str_update(new, false); return new; } @@ -1892,7 +1893,7 @@ struct aspath *aspath_reconcile_as4(struct aspath *aspath, "[AS4] AS4PATHmangle: AS_CONFED_SEQUENCE falls across 2/4 ASN boundary somewhere, broken.."); hops = seg->length; } - /* fallthru */ + fallthrough; case AS_SEQUENCE: cpasns = MIN(seg->length, hops); hops -= seg->length; diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index ebfc7d0..2a831c3 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -65,6 +65,14 @@ struct aspath { #define ASPATH_STR_DEFAULT_LEN 32 +/* `set as-path exclude ASn' */ +struct aspath_exclude { + struct aspath *aspath; + bool exclude_all; + char *exclude_aspath_acl_name; + struct as_list *exclude_aspath_acl; +}; + /* Prototypes. */ extern void aspath_init(void); extern void aspath_finish(void); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 56e77eb..53420b4 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -864,6 +864,7 @@ bool attrhash_cmp(const void *p1, const void *p2) attr1->df_alg == attr2->df_alg && attr1->nh_ifindex == attr2->nh_ifindex && attr1->nh_lla_ifindex == attr2->nh_lla_ifindex && + attr1->nh_flags == attr2->nh_flags && attr1->distance == attr2->distance && srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn) && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn) && @@ -1381,6 +1382,15 @@ bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode, (args->startp - STREAM_DATA(BGP_INPUT(peer))) + args->total); + /* Partial optional attributes that are malformed should not cause + * the whole session to be reset. Instead treat it as a withdrawal + * of the routes, if possible. + */ + if (CHECK_FLAG(flags, BGP_ATTR_FLAG_TRANS) && + CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL) && + CHECK_FLAG(flags, BGP_ATTR_FLAG_PARTIAL)) + return BGP_ATTR_PARSE_WITHDRAW; + switch (args->type) { /* where an attribute is relatively inconsequential, e.g. it does not * affect route selection, and can be safely ignored, then any such @@ -1390,6 +1400,7 @@ bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode, case BGP_ATTR_AS4_AGGREGATOR: case BGP_ATTR_AGGREGATOR: case BGP_ATTR_ATOMIC_AGGREGATE: + case BGP_ATTR_PREFIX_SID: return BGP_ATTR_PARSE_PROCEED; /* Core attributes, particularly ones which may influence route @@ -1417,19 +1428,21 @@ bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode, BGP_NOTIFY_UPDATE_ERR, subcode, notify_datap, length); return BGP_ATTR_PARSE_ERROR; + default: + /* Unknown attributes, that are handled by this function + * should be treated as withdraw, to prevent one more CVE + * from being introduced. + * RFC 7606 says: + * The "treat-as-withdraw" approach is generally preferred + * and the "session reset" approach is discouraged. + */ + flog_err(EC_BGP_ATTR_FLAG, + "%s(%u) attribute received, while it is not known how to handle it, treating as withdraw", + lookup_msg(attr_str, args->type, NULL), args->type); + break; } - /* Partial optional attributes that are malformed should not cause - * the whole session to be reset. Instead treat it as a withdrawal - * of the routes, if possible. - */ - if (CHECK_FLAG(flags, BGP_ATTR_FLAG_TRANS) - && CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL) - && CHECK_FLAG(flags, BGP_ATTR_FLAG_PARTIAL)) - return BGP_ATTR_PARSE_WITHDRAW; - - /* default to reset */ - return BGP_ATTR_PARSE_ERROR_NOTIFYPLS; + return BGP_ATTR_PARSE_WITHDRAW; } /* Find out what is wrong with the path attribute flag bits and log the error. @@ -1839,7 +1852,9 @@ bgp_attr_local_pref(struct bgp_attr_parser_args *args) * UPDATE message SHALL be handled using the approach of "treat-as- * withdraw". */ - if (peer->sort == BGP_PEER_IBGP && length != 4) { + if ((peer->sort == BGP_PEER_IBGP || + peer->sub_sort == BGP_PEER_EBGP_OAD) && + length != 4) { flog_err(EC_BGP_ATTR_LEN, "LOCAL_PREF attribute length isn't 4 [%u]", length); return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, @@ -1849,7 +1864,7 @@ bgp_attr_local_pref(struct bgp_attr_parser_args *args) /* If it is contained in an UPDATE message that is received from an external peer, then this attribute MUST be ignored by the receiving speaker. */ - if (peer->sort == BGP_PEER_EBGP) { + if (peer->sort == BGP_PEER_EBGP && peer->sub_sort != BGP_PEER_EBGP_OAD) { STREAM_FORWARD_GETP(peer->curr, length); return BGP_ATTR_PARSE_PROCEED; } @@ -2321,11 +2336,8 @@ int bgp_mp_reach_parse(struct bgp_attr_parser_args *args, /* * NOTE: intentional fall through * - for consistency in rx processing - * - * The following comment is to signal GCC this intention - * and suppress the warning */ - /* FALLTHRU */ + fallthrough; case BGP_ATTR_NHLEN_IPV4: stream_get(&attr->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN); /* Probably needed for RFC 2283 */ @@ -3144,8 +3156,6 @@ enum bgp_attr_parse_ret bgp_attr_prefix_sid(struct bgp_attr_parser_args *args) struct attr *const attr = args->attr; enum bgp_attr_parse_ret ret; - attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID); - uint8_t type; uint16_t length; size_t headersz = sizeof(type) + sizeof(length); @@ -3195,6 +3205,8 @@ enum bgp_attr_parse_ret bgp_attr_prefix_sid(struct bgp_attr_parser_args *args) } } + SET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)); + return BGP_ATTR_PARSE_PROCEED; } @@ -3267,7 +3279,8 @@ static enum bgp_attr_parse_ret bgp_attr_aigp(struct bgp_attr_parser_args *args) * the default value of AIGP_SESSION SHOULD be "enabled". */ if (peer->sort == BGP_PEER_EBGP && - !CHECK_FLAG(peer->flags, PEER_FLAG_AIGP)) { + (!CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) || + peer->sub_sort != BGP_PEER_EBGP_OAD)) { zlog_warn( "%pBP received AIGP attribute, but eBGP peer do not support it", peer); @@ -4492,7 +4505,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, } /* Local preference. */ - if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { + if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED || + peer->sub_sort == BGP_PEER_EBGP_OAD) { stream_putc(s, BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_LOCAL_PREF); stream_putc(s, 4); @@ -4858,6 +4872,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, /* AIGP */ if (bpi && attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) && (CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) || + peer->sub_sort == BGP_PEER_EBGP_OAD || peer->sort != BGP_PEER_EBGP)) { /* At the moment only AIGP Metric TLV exists for AIGP * attribute. If more comes in, do not forget to update diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index d30155e..d78f04c 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -155,10 +155,56 @@ struct attr { uint32_t med; uint32_t local_pref; ifindex_t nh_ifindex; + uint8_t nh_flags; + +#define BGP_ATTR_NH_VALID 0x01 /* Path origin attribute */ uint8_t origin; + /* ES info */ + uint8_t es_flags; + /* Path is not "locally-active" on the advertising VTEP. This is + * translated into an ARP-ND ECOM. + */ +#define ATTR_ES_PROXY_ADVERT (1 << 0) + /* Destination ES is present locally. This flag is set on local + * paths and sync paths + */ +#define ATTR_ES_IS_LOCAL (1 << 1) + /* There are one or more non-best paths from ES peers. Note that + * this flag is only set on the local MAC-IP paths in the VNI + * route table (not set in the global routing table). And only + * non-proxy advertisements from an ES peer can result in this + * flag being set. + */ +#define ATTR_ES_PEER_ACTIVE (1 << 2) + /* There are one or more non-best proxy paths from ES peers */ +#define ATTR_ES_PEER_PROXY (1 << 3) + /* An ES peer has router bit set - only applicable if + * ATTR_ES_PEER_ACTIVE is set + */ +#define ATTR_ES_PEER_ROUTER (1 << 4) + + /* These two flags are only set on L3 routes installed in a + * VRF as a result of EVPN MAC-IP route + * XXX - while splitting up per-family attrs these need to be + * classified as non-EVPN + */ +#define ATTR_ES_L3_NHG_USE (1 << 5) +#define ATTR_ES_L3_NHG_ACTIVE (1 << 6) +#define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE) + + /* NA router flag (R-bit) support in EVPN */ + uint8_t router_flag; + + /* Distance as applied by Route map */ + uint8_t distance; + + /* EVPN DF preference for DF election on local ESs */ + uint8_t df_alg; + uint16_t df_pref; + /* PMSI tunnel type (RFC 6514). */ enum pta_type pmsi_tnl_type; @@ -173,6 +219,9 @@ struct attr { /* ifIndex corresponding to mp_nexthop_local. */ ifindex_t nh_lla_ifindex; + /* MPLS label */ + mpls_label_t label; + /* Extended Communities attribute. */ struct ecommunity *ecommunity; @@ -214,58 +263,18 @@ struct attr { /* Flag for default gateway extended community in EVPN */ uint8_t default_gw; - /* NA router flag (R-bit) support in EVPN */ - uint8_t router_flag; - - /* ES info */ - uint8_t es_flags; - /* Path is not "locally-active" on the advertising VTEP. This is - * translated into an ARP-ND ECOM. - */ -#define ATTR_ES_PROXY_ADVERT (1 << 0) - /* Destination ES is present locally. This flag is set on local - * paths and sync paths - */ -#define ATTR_ES_IS_LOCAL (1 << 1) - /* There are one or more non-best paths from ES peers. Note that - * this flag is only set on the local MAC-IP paths in the VNI - * route table (not set in the global routing table). And only - * non-proxy advertisements from an ES peer can result in this - * flag being set. - */ -#define ATTR_ES_PEER_ACTIVE (1 << 2) - /* There are one or more non-best proxy paths from ES peers */ -#define ATTR_ES_PEER_PROXY (1 << 3) - /* An ES peer has router bit set - only applicable if - * ATTR_ES_PEER_ACTIVE is set - */ -#define ATTR_ES_PEER_ROUTER (1 << 4) - - /* These two flags are only set on L3 routes installed in a - * VRF as a result of EVPN MAC-IP route - * XXX - while splitting up per-family attrs these need to be - * classified as non-EVPN - */ -#define ATTR_ES_L3_NHG_USE (1 << 5) -#define ATTR_ES_L3_NHG_ACTIVE (1 << 6) -#define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE) - /* route tag */ route_tag_t tag; /* Label index */ uint32_t label_index; - /* MPLS label */ - mpls_label_t label; - /* SRv6 VPN SID */ struct bgp_attr_srv6_vpn *srv6_vpn; /* SRv6 L3VPN SID */ struct bgp_attr_srv6_l3vpn *srv6_l3vpn; - uint16_t encap_tunneltype; /* grr */ struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */ #ifdef ENABLE_BGP_VNC @@ -287,8 +296,7 @@ struct attr { /* EVPN local router-mac */ struct ethaddr rmac; - /* Distance as applied by Route map */ - uint8_t distance; + uint16_t encap_tunneltype; /* rmap set table */ uint32_t rmap_table_id; @@ -302,10 +310,6 @@ struct attr { /* SR-TE Color */ uint32_t srte_color; - /* EVPN DF preference and algorithm for DF election on local ESs */ - uint16_t df_pref; - uint8_t df_alg; - /* Nexthop type */ enum nexthop_types_t nh_type; diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 7270802..1de48a0 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -240,60 +240,115 @@ static void bmp_free(struct bmp *bmp) XFREE(MTYPE_BMP_CONN, bmp); } +#define BMP_PEER_TYPE_GLOBAL_INSTANCE 0 +#define BMP_PEER_TYPE_RD_INSTANCE 1 +#define BMP_PEER_TYPE_LOCAL_INSTANCE 2 +#define BMP_PEER_TYPE_LOC_RIB_INSTANCE 3 + +static inline int bmp_get_peer_distinguisher(struct bmp *bmp, afi_t afi, + uint8_t peer_type, + uint64_t *result_ref) +{ + + /* remove this check when the other peer types get correct peer dist. + *(RFC7854) impl. + * for now, always return no error and 0 peer distinguisher as before + */ + if (peer_type != BMP_PEER_TYPE_LOC_RIB_INSTANCE) + return (*result_ref = 0); + + /* sending vrf_id or rd could be turned into an option at some point */ + struct bgp *bgp = bmp->targets->bgp; + + /* vrf default => ok, distinguisher 0 */ + if (bgp->inst_type == VRF_DEFAULT) + return (*result_ref = 0); + + /* use RD if set in VRF config for this AFI */ + struct prefix_rd *prd = &bgp->vpn_policy[afi].tovpn_rd; + + if (CHECK_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_RD_SET)) { + memcpy(result_ref, prd->val, sizeof(prd->val)); + return 0; + } + + /* VRF has no id => error => message should be skipped */ + if (bgp->vrf_id == VRF_UNKNOWN) + return 1; + + /* use VRF id converted to ::vrf_id 64bits format */ + *result_ref = ((uint64_t)htonl(bgp->vrf_id)) << 32; + return 0; +} + static void bmp_common_hdr(struct stream *s, uint8_t ver, uint8_t type) { stream_putc(s, ver); - stream_putl(s, 0); //dummy message length. will be set later. + stream_putl(s, 0); /* dummy message length. will be set later. */ stream_putc(s, type); } -static void bmp_per_peer_hdr(struct stream *s, struct peer *peer, - uint8_t flags, const struct timeval *tv) +static void bmp_per_peer_hdr(struct stream *s, struct bgp *bgp, + struct peer *peer, uint8_t flags, + uint8_t peer_type_flag, + uint64_t peer_distinguisher, + const struct timeval *tv) { - char peer_distinguisher[8]; - -#define BMP_PEER_TYPE_GLOBAL_INSTANCE 0 -#define BMP_PEER_TYPE_RD_INSTANCE 1 -#define BMP_PEER_TYPE_LOCAL_INSTANCE 2 - #define BMP_PEER_FLAG_V (1 << 7) #define BMP_PEER_FLAG_L (1 << 6) #define BMP_PEER_FLAG_A (1 << 5) + bool is_locrib = peer_type_flag == BMP_PEER_TYPE_LOC_RIB_INSTANCE; + /* Peer Type */ - stream_putc(s, BMP_PEER_TYPE_GLOBAL_INSTANCE); + stream_putc(s, peer_type_flag); /* Peer Flags */ - if (peer->connection->su.sa.sa_family == AF_INET6) + if (!is_locrib && peer->connection->su.sa.sa_family == AF_INET6) SET_FLAG(flags, BMP_PEER_FLAG_V); else UNSET_FLAG(flags, BMP_PEER_FLAG_V); stream_putc(s, flags); /* Peer Distinguisher */ - memset (&peer_distinguisher[0], 0, 8); - stream_put(s, &peer_distinguisher[0], 8); + stream_put(s, (uint8_t *)&peer_distinguisher, 8); /* Peer Address */ - if (peer->connection->su.sa.sa_family == AF_INET6) - stream_put(s, &peer->connection->su.sin6.sin6_addr, 16); - else if (peer->connection->su.sa.sa_family == AF_INET) { + /* Set to 0 if it's a LOC-RIB INSTANCE (RFC 9069) or if it's not an + * IPv4/6 address + */ + if (is_locrib || (peer->connection->su.sa.sa_family != AF_INET6 && + peer->connection->su.sa.sa_family != AF_INET)) { stream_putl(s, 0); stream_putl(s, 0); stream_putl(s, 0); - stream_put_in_addr(s, &peer->connection->su.sin.sin_addr); - } else { stream_putl(s, 0); + } else if (peer->connection->su.sa.sa_family == AF_INET6) + stream_put(s, &peer->connection->su.sin6.sin6_addr, IPV6_MAX_BYTELEN); + else if (peer->connection->su.sa.sa_family == AF_INET) { stream_putl(s, 0); stream_putl(s, 0); stream_putl(s, 0); + stream_put_in_addr(s, &peer->connection->su.sin.sin_addr); } /* Peer AS */ - stream_putl(s, peer->as); + /* set peer ASN but for LOC-RIB INSTANCE (RFC 9069) put the local bgp + * ASN + */ + as_t asn = !is_locrib ? peer->as : bgp->as; + + stream_putl(s, asn); /* Peer BGP ID */ - stream_put_in_addr(s, &peer->remote_id); + /* set router-id but for LOC-RIB INSTANCE (RFC 9069) put the instance + * router-id + */ + struct in_addr *bgp_id = + !is_locrib ? &peer->remote_id : &bgp->router_id; + + stream_put_in_addr(s, bgp_id); /* Timestamp */ if (tv) { @@ -314,11 +369,26 @@ static void bmp_put_info_tlv(struct stream *s, uint16_t type, stream_put(s, string, len); } +static void __attribute__((unused)) +bmp_put_vrftablename_info_tlv(struct stream *s, struct bmp *bmp) +{ + +#define BMP_INFO_TYPE_VRFTABLENAME 3 + const char *vrftablename = "global"; + if (bmp->targets->bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT) { + struct vrf *vrf = vrf_lookup_by_id(bmp->targets->bgp->vrf_id); + + vrftablename = vrf ? vrf->name : NULL; + } + if (vrftablename != NULL) + bmp_put_info_tlv(s, BMP_INFO_TYPE_VRFTABLENAME, vrftablename); +} + static int bmp_send_initiation(struct bmp *bmp) { int len; - struct stream *s; - s = stream_new(BGP_MAX_PACKET_SIZE); + struct stream *s = stream_new(BGP_MAX_PACKET_SIZE); + bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_INITIATION); #define BMP_INFO_TYPE_SYSDESCR 1 @@ -328,7 +398,7 @@ static int bmp_send_initiation(struct bmp *bmp) bmp_put_info_tlv(s, BMP_INFO_TYPE_SYSNAME, cmd_hostname_get()); len = stream_get_endp(s); - stream_putl_at(s, BMP_LENGTH_POS, len); //message length is set. + stream_putl_at(s, BMP_LENGTH_POS, len); /* message length is set. */ pullwr_write_stream(bmp->pullwr, s); stream_free(s); @@ -375,7 +445,9 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_PEER_UP_NOTIFICATION); - bmp_per_peer_hdr(s, peer, 0, &uptime_real); + bmp_per_peer_hdr(s, peer->bgp, peer, 0, + BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, + &uptime_real); /* Local Address (16 bytes) */ if (peer->su_local->sa.sa_family == AF_INET6) @@ -428,7 +500,9 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_PEER_DOWN_NOTIFICATION); - bmp_per_peer_hdr(s, peer, 0, &uptime_real); + bmp_per_peer_hdr(s, peer->bgp, peer, 0, + BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, + &uptime_real); type_pos = stream_get_endp(s); stream_putc(s, 0); /* placeholder for down reason */ @@ -460,7 +534,7 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) } len = stream_get_endp(s); - stream_putl_at(s, BMP_LENGTH_POS, len); //message length is set. + stream_putl_at(s, BMP_LENGTH_POS, len); /* message length is set. */ return s; } @@ -618,7 +692,8 @@ static void bmp_wrmirror_lost(struct bmp *bmp, struct pullwr *pullwr) s = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_ROUTE_MIRRORING); - bmp_per_peer_hdr(s, bmp->targets->bgp->peer_self, 0, &tv); + bmp_per_peer_hdr(s, bmp->targets->bgp, bmp->targets->bgp->peer_self, 0, + BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, &tv); stream_putw(s, BMP_MIRROR_TLV_TYPE_INFO); stream_putw(s, 2); @@ -656,7 +731,8 @@ static bool bmp_wrmirror(struct bmp *bmp, struct pullwr *pullwr) s = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_ROUTE_MIRRORING); - bmp_per_peer_hdr(s, peer, 0, &bmq->tv); + bmp_per_peer_hdr(s, bmp->targets->bgp, peer, 0, + BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, &bmq->tv); /* BMP Mirror TLV. */ stream_putw(s, BMP_MIRROR_TLV_TYPE_BGP_MESSAGE); @@ -763,7 +839,8 @@ static int bmp_peer_backward(struct peer *peer) return 0; } -static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags) +static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags, + uint8_t peer_type_flag) { struct peer *peer; struct listnode *node; @@ -771,7 +848,7 @@ static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags) iana_afi_t pkt_afi = IANA_AFI_IPV4; iana_safi_t pkt_safi = IANA_SAFI_UNICAST; - frrtrace(3, frr_bgp, bmp_eor, afi, safi, flags); + frrtrace(4, frr_bgp, bmp_eor, afi, safi, flags, peer_type_flag); s = stream_new(BGP_MAX_PACKET_SIZE); @@ -803,11 +880,22 @@ static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags) if (!peer->afc_nego[afi][safi]) continue; + uint64_t peer_distinguisher = 0; + /* skip this message if peer distinguisher is not available */ + if (bmp_get_peer_distinguisher(bmp, afi, peer_type_flag, + &peer_distinguisher)) { + zlog_warn( + "skipping bmp message for reason: can't get peer distinguisher"); + continue; + } + s2 = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(s2, BMP_VERSION_3, BMP_TYPE_ROUTE_MONITORING); - bmp_per_peer_hdr(s2, peer, flags, NULL); + + bmp_per_peer_hdr(s2, bmp->targets->bgp, peer, flags, + peer_type_flag, peer_distinguisher, NULL); stream_putl_at(s2, BMP_LENGTH_POS, stream_get_endp(s) + stream_get_endp(s2)); @@ -912,14 +1000,23 @@ static struct stream *bmp_withdraw(const struct prefix *p, } static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags, - const struct prefix *p, struct prefix_rd *prd, - struct attr *attr, afi_t afi, safi_t safi, - time_t uptime) + 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) { struct stream *hdr, *msg; struct timeval tv = { .tv_sec = uptime, .tv_usec = 0 }; struct timeval uptime_real; + uint64_t peer_distinguisher = 0; + /* skip this message if peer distinguisher is not available */ + if (bmp_get_peer_distinguisher(bmp, afi, peer_type_flag, + &peer_distinguisher)) { + zlog_warn( + "skipping bmp message for reason: can't get peer distinguisher"); + return; + } + monotime_to_realtime(&tv, &uptime_real); if (attr) msg = bmp_update(p, prd, peer, attr, afi, safi); @@ -928,7 +1025,9 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags, hdr = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(hdr, BMP_VERSION_3, BMP_TYPE_ROUTE_MONITORING); - bmp_per_peer_hdr(hdr, peer, flags, &uptime_real); + bmp_per_peer_hdr(hdr, bmp->targets->bgp, peer, flags, peer_type_flag, + peer_distinguisher, + uptime == (time_t)(-1L) ? NULL : &uptime_real); stream_putl_at(hdr, BMP_LENGTH_POS, stream_get_endp(hdr) + stream_get_endp(msg)); @@ -1039,8 +1138,13 @@ afibreak: zlog_info("bmp[%s] %s %s table completed (EoR)", bmp->remote, afi2str(afi), safi2str(safi)); - bmp_eor(bmp, afi, safi, BMP_PEER_FLAG_L); - bmp_eor(bmp, afi, safi, 0); + + bmp_eor(bmp, afi, safi, BMP_PEER_FLAG_L, + BMP_PEER_TYPE_GLOBAL_INSTANCE); + bmp_eor(bmp, afi, safi, 0, + BMP_PEER_TYPE_GLOBAL_INSTANCE); + bmp_eor(bmp, afi, safi, 0, + BMP_PEER_TYPE_LOC_RIB_INSTANCE); bmp->afistate[afi][safi] = BMP_AFI_LIVE; bmp->syncafi = AFI_MAX; @@ -1051,10 +1155,16 @@ afibreak: prefix_copy(&bmp->syncpos, bgp_dest_get_prefix(bn)); } - if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) { + if (CHECK_FLAG(bmp->targets->afimon[afi][safi], + BMP_MON_POSTPOLICY) || + CHECK_FLAG(bmp->targets->afimon[afi][safi], + BMP_MON_LOC_RIB)) { for (bpiter = bgp_dest_get_bgp_path_info(bn); bpiter; bpiter = bpiter->next) { - if (!CHECK_FLAG(bpiter->flags, BGP_PATH_VALID)) + if (!CHECK_FLAG(bpiter->flags, + BGP_PATH_VALID) && + !CHECK_FLAG(bpiter->flags, + BGP_PATH_SELECTED)) continue; if (bpiter->peer->qobj_node.nid <= bmp->syncpeerid) @@ -1065,7 +1175,8 @@ afibreak: bpi = bpiter; } } - if (bmp->targets->afimon[afi][safi] & BMP_MON_PREPOLICY) { + if (CHECK_FLAG(bmp->targets->afimon[afi][safi], + BMP_MON_PREPOLICY)) { for (adjiter = bn->adj_in; adjiter; adjiter = adjiter->next) { if (adjiter->peer->qobj_node.nid @@ -1103,12 +1214,23 @@ afibreak: (safi == SAFI_MPLS_VPN)) prd = (struct prefix_rd *)bgp_dest_get_prefix(bmp->syncrdpos); - if (bpi) - bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, bn_p, prd, - bpi->attr, afi, safi, bpi->uptime); + 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)); + } + + 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); + if (adjin) - bmp_monitor(bmp, adjin->peer, 0, bn_p, prd, adjin->attr, afi, - safi, adjin->uptime); + bmp_monitor(bmp, adjin->peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, + bn_p, prd, adjin->attr, afi, safi, adjin->uptime); if (bn) bgp_dest_unlock_node(bn); @@ -1116,24 +1238,124 @@ afibreak: return true; } -static struct bmp_queue_entry *bmp_pull(struct bmp *bmp) +static struct bmp_queue_entry * +bmp_pull_from_queue(struct bmp_qlist_head *list, struct bmp_qhash_head *hash, + struct bmp_queue_entry **queuepos_ptr) { struct bmp_queue_entry *bqe; - bqe = bmp->queuepos; + bqe = *queuepos_ptr; if (!bqe) return NULL; - bmp->queuepos = bmp_qlist_next(&bmp->targets->updlist, bqe); + *queuepos_ptr = bmp_qlist_next(list, bqe); bqe->refcount--; if (!bqe->refcount) { - bmp_qhash_del(&bmp->targets->updhash, bqe); - bmp_qlist_del(&bmp->targets->updlist, bqe); + bmp_qhash_del(hash, bqe); + bmp_qlist_del(list, bqe); } return bqe; } +static inline struct bmp_queue_entry *bmp_pull(struct bmp *bmp) +{ + return bmp_pull_from_queue(&bmp->targets->updlist, + &bmp->targets->updhash, &bmp->queuepos); +} + +static inline struct bmp_queue_entry *bmp_pull_locrib(struct bmp *bmp) +{ + return bmp_pull_from_queue(&bmp->targets->locupdlist, + &bmp->targets->locupdhash, + &bmp->locrib_queuepos); +} + +/* TODO BMP_MON_LOCRIB find a way to merge properly this function with + * bmp_wrqueue or abstract it if possible + */ +static bool bmp_wrqueue_locrib(struct bmp *bmp, struct pullwr *pullwr) +{ + + struct bmp_queue_entry *bqe; + struct peer *peer; + struct bgp_dest *bn = NULL; + bool written = false; + + bqe = bmp_pull_locrib(bmp); + if (!bqe) + return false; + + afi_t afi = bqe->afi; + safi_t safi = bqe->safi; + + if (!CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_LOC_RIB)) + goto out; + + switch (bmp->afistate[afi][safi]) { + case BMP_AFI_INACTIVE: + case BMP_AFI_NEEDSYNC: + goto out; + case BMP_AFI_SYNC: + if (prefix_cmp(&bqe->p, &bmp->syncpos) <= 0) + /* currently syncing but have already passed this + * prefix => send it. + */ + break; + + /* currently syncing & haven't reached this prefix yet + * => it'll be sent as part of the table sync, no need here + */ + goto out; + case BMP_AFI_LIVE: + break; + } + + peer = QOBJ_GET_TYPESAFE(bqe->peerid, peer); + if (!peer) { + /* skipping queued item for deleted peer + */ + goto out; + } + if (peer != bmp->targets->bgp->peer_self && !peer_established(peer->connection)) { + /* peer is neither self, nor established + */ + goto out; + } + + bool is_vpn = (bqe->afi == AFI_L2VPN && bqe->safi == SAFI_EVPN) || + (bqe->safi == SAFI_MPLS_VPN); + + struct prefix_rd *prd = is_vpn ? &bqe->rd : NULL; + + bn = bgp_safi_node_lookup(bmp->targets->bgp->rib[afi][safi], safi, + &bqe->p, prd); + + struct bgp_path_info *bpi; + + for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { + if (!CHECK_FLAG(bpi->flags, BGP_PATH_SELECTED)) + continue; + if (bpi->peer == peer) + break; + } + + 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)); + written = true; + +out: + if (!bqe->refcount) + XFREE(MTYPE_BMP_QUEUE, bqe); + + if (bn) + bgp_dest_unlock_node(bn); + + return written; +} + static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) { struct bmp_queue_entry *bqe; @@ -1180,11 +1402,10 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) bn = bgp_safi_node_lookup(bmp->targets->bgp->rib[afi][safi], safi, &bqe->p, prd); - - if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) { + if (CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_POSTPOLICY)) { struct bgp_path_info *bpi; - for (bpi = bn ? bgp_dest_get_bgp_path_info(bn) : NULL; bpi; + for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { if (!CHECK_FLAG(bpi->flags, BGP_PATH_VALID)) continue; @@ -1192,13 +1413,14 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) break; } - bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, &bqe->p, prd, + 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)); written = true; } - if (bmp->targets->afimon[afi][safi] & BMP_MON_PREPOLICY) { + if (CHECK_FLAG(bmp->targets->afimon[afi][safi], BMP_MON_PREPOLICY)) { struct bgp_adj_in *adjin; for (adjin = bn ? bn->adj_in : NULL; adjin; @@ -1206,8 +1428,8 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) if (adjin->peer == peer) break; } - bmp_monitor(bmp, peer, 0, &bqe->p, prd, - adjin ? adjin->attr : NULL, afi, safi, + bmp_monitor(bmp, peer, 0, BMP_PEER_TYPE_GLOBAL_INSTANCE, + &bqe->p, prd, adjin ? adjin->attr : NULL, afi, safi, adjin ? adjin->uptime : monotime(NULL)); written = true; } @@ -1235,6 +1457,8 @@ static void bmp_wrfill(struct bmp *bmp, struct pullwr *pullwr) break; if (bmp_wrqueue(bmp, pullwr)) break; + if (bmp_wrqueue_locrib(bmp, pullwr)) + break; if (bmp_wrsync(bmp, pullwr)) break; break; @@ -1253,16 +1477,17 @@ static void bmp_wrerr(struct bmp *bmp, struct pullwr *pullwr, bool eof) bmp_free(bmp); } -static void bmp_process_one(struct bmp_targets *bt, struct bgp *bgp, afi_t afi, - safi_t safi, struct bgp_dest *bn, struct peer *peer) +static struct bmp_queue_entry * +bmp_process_one(struct bmp_targets *bt, struct bmp_qhash_head *updhash, + struct bmp_qlist_head *updlist, struct bgp *bgp, afi_t afi, + safi_t safi, struct bgp_dest *bn, struct peer *peer) { - struct bmp *bmp; struct bmp_queue_entry *bqe, bqeref; size_t refcount; refcount = bmp_session_count(&bt->sessions); if (refcount == 0) - return; + return NULL; memset(&bqeref, 0, sizeof(bqeref)); prefix_copy(&bqeref.p, bgp_dest_get_prefix(bn)); @@ -1275,26 +1500,28 @@ static void bmp_process_one(struct bmp_targets *bt, struct bgp *bgp, afi_t afi, prefix_copy(&bqeref.rd, (struct prefix_rd *)bgp_dest_get_prefix(bn->pdest)); - bqe = bmp_qhash_find(&bt->updhash, &bqeref); + bqe = bmp_qhash_find(updhash, &bqeref); if (bqe) { if (bqe->refcount >= refcount) /* nothing to do here */ - return; + return NULL; - bmp_qlist_del(&bt->updlist, bqe); + bmp_qlist_del(updlist, bqe); } else { bqe = XMALLOC(MTYPE_BMP_QUEUE, sizeof(*bqe)); memcpy(bqe, &bqeref, sizeof(*bqe)); - bmp_qhash_add(&bt->updhash, bqe); + bmp_qhash_add(updhash, bqe); } bqe->refcount = refcount; - bmp_qlist_add_tail(&bt->updlist, bqe); + bmp_qlist_add_tail(updlist, bqe); + + return bqe; - frr_each (bmp_session, &bt->sessions, bmp) - if (!bmp->queuepos) - bmp->queuepos = bqe; + /* need to update correct queue pos for all sessions of the target after + * a call to this function + */ } static int bmp_process(struct bgp *bgp, afi_t afi, safi_t safi, @@ -1316,12 +1543,26 @@ static int bmp_process(struct bgp *bgp, afi_t afi, safi_t safi, return 0; frr_each(bmp_targets, &bmpbgp->targets, bt) { - if (!bt->afimon[afi][safi]) + /* check if any monitoring is enabled (ignoring loc-rib since it + * uses another hook & queue + */ + if (!CHECK_FLAG(bt->afimon[afi][safi], ~BMP_MON_LOC_RIB)) continue; - bmp_process_one(bt, bgp, afi, safi, bn, peer); + struct bmp_queue_entry *last_item = + bmp_process_one(bt, &bt->updhash, &bt->updlist, bgp, + afi, safi, bn, peer); + + /* if bmp_process_one returns NULL + * we don't have anything to do next + */ + if (!last_item) + continue; frr_each(bmp_session, &bt->sessions, bmp) { + if (!bmp->queuepos) + bmp->queuepos = last_item; + pullwr_bump(bmp->pullwr); } } @@ -1360,7 +1601,8 @@ static void bmp_stats(struct event *thread) s = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(s, BMP_VERSION_3, BMP_TYPE_STATISTICS_REPORT); - bmp_per_peer_hdr(s, peer, 0, &tv); + bmp_per_peer_hdr(s, bt->bgp, peer, 0, + BMP_PEER_TYPE_GLOBAL_INSTANCE, 0, &tv); count_pos = stream_get_endp(s); stream_putl(s, 0); @@ -1530,6 +1772,9 @@ static void bmp_close(struct bmp *bmp) while ((bqe = bmp_pull(bmp))) if (!bqe->refcount) XFREE(MTYPE_BMP_QUEUE, bqe); + while ((bqe = bmp_pull_locrib(bmp))) + if (!bqe->refcount) + XFREE(MTYPE_BMP_QUEUE, bqe); EVENT_OFF(bmp->t_read); pullwr_del(bmp->pullwr); @@ -1633,6 +1878,8 @@ static struct bmp_targets *bmp_targets_get(struct bgp *bgp, const char *name) bmp_session_init(&bt->sessions); bmp_qhash_init(&bt->updhash); bmp_qlist_init(&bt->updlist); + bmp_qhash_init(&bt->locupdhash); + bmp_qlist_init(&bt->locupdlist); bmp_actives_init(&bt->actives); bmp_listeners_init(&bt->listeners); @@ -1663,6 +1910,8 @@ static void bmp_targets_put(struct bmp_targets *bt) bmp_actives_fini(&bt->actives); bmp_qhash_fini(&bt->updhash); bmp_qlist_fini(&bt->updlist); + bmp_qhash_fini(&bt->locupdhash); + bmp_qlist_fini(&bt->locupdlist); XFREE(MTYPE_BMP_ACLNAME, bt->acl_name); XFREE(MTYPE_BMP_ACLNAME, bt->acl6_name); @@ -2206,21 +2455,17 @@ DEFPY(bmp_stats_cfg, return CMD_SUCCESS; } -DEFPY(bmp_monitor_cfg, - bmp_monitor_cmd, - "[no] bmp monitor <ipv4|ipv6|l2vpn> <unicast|multicast|evpn|vpn> <pre-policy|post-policy>$policy", - NO_STR - BMP_STR - "Send BMP route monitoring messages\n" - BGP_AF_STR - BGP_AF_STR - BGP_AF_STR - BGP_AF_STR - BGP_AF_STR - BGP_AF_STR - BGP_AF_STR +#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 */ + +DEFPY(bmp_monitor_cfg, bmp_monitor_cmd, + "[no] bmp monitor <ipv4|ipv6|l2vpn> <unicast|multicast|evpn|vpn> <pre-policy|post-policy|loc-rib>$policy", + NO_STR BMP_STR + "Send BMP route monitoring messages\n" BGP_AF_STR BGP_AF_STR BGP_AF_STR + BGP_AF_STR BGP_AF_STR BGP_AF_STR BGP_AF_STR "Send state before policy and filter processing\n" - "Send state with policy and filters applied\n") + "Send state with policy and filters applied\n" + "Send state after decision process is applied\n") { int index = 0; uint8_t flag, prev; @@ -2233,7 +2478,9 @@ DEFPY(bmp_monitor_cfg, argv_find_and_parse_afi(argv, argc, &index, &afi); argv_find_and_parse_safi(argv, argc, &index, &safi); - if (policy[1] == 'r') + if (BMP_POLICY_IS_LOCRIB(policy)) + flag = BMP_MON_LOC_RIB; + else if (BMP_POLICY_IS_PRE(policy)) flag = BMP_MON_PREPOLICY; else flag = BMP_MON_POSTPOLICY; @@ -2364,23 +2611,31 @@ DEFPY(show_bmp, safi_t safi; FOREACH_AFI_SAFI (afi, safi) { - const char *str = NULL; - - switch (bt->afimon[afi][safi]) { - case BMP_MON_PREPOLICY: - str = "pre-policy"; - break; - case BMP_MON_POSTPOLICY: - str = "post-policy"; - break; - case BMP_MON_PREPOLICY | BMP_MON_POSTPOLICY: - str = "pre-policy and post-policy"; - break; - } - if (!str) + + uint8_t afimon_flag = bt->afimon[afi][safi]; + + if (!afimon_flag) continue; - vty_out(vty, " Route Monitoring %s %s %s\n", - afi2str(afi), safi2str(safi), str); + + const char *pre_str = + CHECK_FLAG(afimon_flag, + BMP_MON_PREPOLICY) + ? "pre-policy " + : ""; + const char *post_str = + CHECK_FLAG(afimon_flag, + BMP_MON_POSTPOLICY) + ? "post-policy " + : ""; + const char *locrib_str = + CHECK_FLAG(afimon_flag, BMP_MON_LOC_RIB) + ? "loc-rib" + : ""; + + vty_out(vty, + " Route Monitoring %s %s %s%s%s\n", + afi2str(afi), safi2str(safi), pre_str, + post_str, locrib_str); } vty_out(vty, " Listeners:\n"); @@ -2500,13 +2755,18 @@ static int bmp_config_write(struct bgp *bgp, struct vty *vty) vty_out(vty, " bmp mirror\n"); FOREACH_AFI_SAFI (afi, safi) { - if (bt->afimon[afi][safi] & BMP_MON_PREPOLICY) + if (CHECK_FLAG(bt->afimon[afi][safi], + BMP_MON_PREPOLICY)) vty_out(vty, " bmp monitor %s %s pre-policy\n", afi2str_lower(afi), safi2str(safi)); - if (bt->afimon[afi][safi] & BMP_MON_POSTPOLICY) + if (CHECK_FLAG(bt->afimon[afi][safi], + BMP_MON_POSTPOLICY)) vty_out(vty, " bmp monitor %s %s post-policy\n", afi2str_lower(afi), safi2str(safi)); + if (CHECK_FLAG(bt->afimon[afi][safi], BMP_MON_LOC_RIB)) + vty_out(vty, " bmp monitor %s %s loc-rib\n", + afi2str_lower(afi), safi2str(safi)); } frr_each (bmp_listeners, &bt->listeners, bl) vty_out(vty, " \n bmp listener %pSU port %d\n", @@ -2555,6 +2815,82 @@ static int bgp_bmp_init(struct event_loop *tm) return 0; } +static int bmp_route_update(struct bgp *bgp, afi_t afi, safi_t safi, + struct bgp_dest *bn, + struct bgp_path_info *old_route, + struct bgp_path_info *new_route) +{ + bool is_locribmon_enabled = false; + bool is_withdraw = old_route && !new_route; + struct bgp_path_info *updated_route = + is_withdraw ? old_route : new_route; + + + /* this should never happen */ + if (!updated_route) { + zlog_warn("%s: no updated route found!", __func__); + return 0; + } + + struct bmp_bgp *bmpbgp = bmp_bgp_get(bgp); + struct peer *peer = updated_route->peer; + struct bmp_targets *bt; + struct bmp *bmp; + + frr_each (bmp_targets, &bmpbgp->targets, bt) { + if (CHECK_FLAG(bt->afimon[afi][safi], BMP_MON_LOC_RIB)) { + is_locribmon_enabled = true; + break; + } + } + + if (!is_locribmon_enabled) + return 0; + + /* route is not installed in locrib anymore and rib uptime was saved */ + if (old_route && old_route->extra) + bgp_path_info_extra_get(old_route)->bgp_rib_uptime = + (time_t)(-1L); + + /* route is installed in locrib from now on so + * save rib uptime in bgp_path_info_extra + */ + if (new_route) + bgp_path_info_extra_get(new_route)->bgp_rib_uptime = + monotime(NULL); + + frr_each (bmp_targets, &bmpbgp->targets, bt) { + if (CHECK_FLAG(bt->afimon[afi][safi], BMP_MON_LOC_RIB)) { + + struct bmp_queue_entry *last_item = bmp_process_one( + bt, &bt->locupdhash, &bt->locupdlist, bgp, afi, + safi, bn, peer); + + /* if bmp_process_one returns NULL + * we don't have anything to do next + */ + if (!last_item) + continue; + + frr_each (bmp_session, &bt->sessions, bmp) { + if (!bmp->locrib_queuepos) + bmp->locrib_queuepos = last_item; + + pullwr_bump(bmp->pullwr); + }; + } + }; + + return 0; +} + +static int bgp_bmp_early_fini(void) +{ + resolver_terminate(); + + return 0; +} + static int bgp_bmp_module_init(void) { hook_register(bgp_packet_dump, bmp_mirror_packet); @@ -2565,6 +2901,8 @@ static int bgp_bmp_module_init(void) hook_register(bgp_inst_config_write, bmp_config_write); hook_register(bgp_inst_delete, bmp_bgp_del); hook_register(frr_late_init, bgp_bmp_init); + hook_register(bgp_route_update, bmp_route_update); + hook_register(frr_early_fini, bgp_bmp_early_fini); return 0; } diff --git a/bgpd/bgp_bmp.h b/bgpd/bgp_bmp.h index ab7463f..dadd99e 100644 --- a/bgpd/bgp_bmp.h +++ b/bgpd/bgp_bmp.h @@ -124,6 +124,7 @@ struct bmp { * ahead we need to make sure that refcount is decremented. Also, on * disconnects we need to walk the queue and drop our reference. */ + struct bmp_queue_entry *locrib_queuepos; struct bmp_queue_entry *queuepos; struct bmp_mirrorq *mirrorpos; bool mirror_lost; @@ -215,12 +216,14 @@ struct bmp_targets { int stat_msec; /* only supporting: - * - IPv4 / unicast & multicast - * - IPv6 / unicast & multicast + * - IPv4 / unicast & multicast & VPN + * - IPv6 / unicast & multicast & VPN * - L2VPN / EVPN */ #define BMP_MON_PREPOLICY (1 << 0) #define BMP_MON_POSTPOLICY (1 << 1) +#define BMP_MON_LOC_RIB (1 << 2) + uint8_t afimon[AFI_MAX][SAFI_MAX]; bool mirror; @@ -232,6 +235,9 @@ struct bmp_targets { struct bmp_qhash_head updhash; struct bmp_qlist_head updlist; + struct bmp_qhash_head locupdhash; + struct bmp_qlist_head locupdlist; + uint64_t cnt_accept, cnt_aclrefused; QOBJ_FIELDS; diff --git a/bgpd/bgp_btoa.c b/bgpd/bgp_btoa.c index 8e27d97..1d5034e 100644 --- a/bgpd/bgp_btoa.c +++ b/bgpd/bgp_btoa.c @@ -4,6 +4,7 @@ */ #include <zebra.h> +#include <fcntl.h> #include "zebra.h" #include "stream.h" diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index e522307..8336d6f 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -128,6 +128,7 @@ static void community_entry_free(struct community_entry *entry) XFREE(MTYPE_COMMUNITY_LIST_CONFIG, entry->config); if (entry->reg) bgp_regex_free(entry->reg); + break; default: break; } diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c index 6ed0dd7..2d96b44 100644 --- a/bgpd/bgp_conditional_adv.c +++ b/bgpd/bgp_conditional_adv.c @@ -122,8 +122,9 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi, if (update_type == UPDATE_TYPE_ADVERTISE && subgroup_announce_check(dest, pi, subgrp, dest_p, &attr, &advmap_attr)) { - bgp_adj_out_set_subgroup(dest, subgrp, &attr, - pi); + if (!bgp_adj_out_set_subgroup(dest, subgrp, + &attr, pi)) + bgp_attr_flush(&attr); } else { /* If default originate is enabled for * the peer, do not send explicit diff --git a/bgpd/bgp_damp.h b/bgpd/bgp_damp.h index 5708e6f..6033c34 100644 --- a/bgpd/bgp_damp.h +++ b/bgpd/bgp_damp.h @@ -65,7 +65,6 @@ struct bgp_damp_config { /* Non-configurable parameters but fixed at implementation time. * To change this values, init_bgp_damp() should be modified. */ - time_t tmax; /* Max time previous instability retained */ unsigned int reuse_list_size; /* Number of reuse lists */ unsigned int reuse_index_size; /* Size of reuse index array */ @@ -75,8 +74,8 @@ struct bgp_damp_config { unsigned int ceiling; /* Max value a penalty can attain */ unsigned int decay_rate_per_tick; /* Calculated from half-life */ unsigned int decay_array_size; /* Calculated using config parameters */ - double scale_factor; unsigned int reuse_scale_factor; + double scale_factor; /* Decay array per-set based. */ double *decay_array; @@ -87,6 +86,7 @@ struct bgp_damp_config { /* Reuse list array per-set based. */ struct bgp_damp_info **reuse_list; int reuse_offset; + safi_t safi; /* All dampening information which is not on reuse list. */ struct bgp_damp_info *no_reuse_list; @@ -95,7 +95,6 @@ struct bgp_damp_config { struct event *t_reuse; afi_t afi; - safi_t safi; }; #define BGP_DAMP_NONE 0 diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 123a1ca..3ecdc0d 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -16,6 +16,7 @@ #include "memory.h" #include "queue.h" #include "filter.h" +#include "hook.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_aspath.h" @@ -37,6 +38,9 @@ #include "bgpd/bgp_debug_clippy.c" +DEFINE_HOOK(bgp_hook_config_write_debug, (struct vty *vty, bool running), + (vty, running)); + unsigned long conf_bgp_debug_as4; unsigned long conf_bgp_debug_neighbor_events; unsigned long conf_bgp_debug_events; @@ -216,6 +220,7 @@ static void bgp_debug_list_free(struct list *list) listnode_delete(list, filter); prefix_free(&filter->p); XFREE(MTYPE_BGP_DEBUG_STR, filter->host); + XFREE(MTYPE_BGP_DEBUG_STR, filter->plist_name); XFREE(MTYPE_BGP_DEBUG_FILTER, filter); } } @@ -233,15 +238,21 @@ static void bgp_debug_list_print(struct vty *vty, const char *desc, vty_out(vty, "%s", desc); if (list && !list_isempty(list)) { - vty_out(vty, " for"); + vty_out(vty, " for:\n"); for (ALL_LIST_ELEMENTS(list, node, nnode, filter)) { if (filter->host) - vty_out(vty, " %s", filter->host); + vty_out(vty, " %s", filter->host); + + if (filter->plist_name) + vty_out(vty, " with prefix-list %s", + filter->plist_name); if (filter->p && filter->p->family == AF_EVPN) bgp_debug_print_evpn_prefix(vty, "", filter->p); else if (filter->p) vty_out(vty, " %pFX", filter->p); + + vty_out(vty, "\n"); } } @@ -261,7 +272,11 @@ static int bgp_debug_list_conf_print(struct vty *vty, const char *desc, if (list && !list_isempty(list)) { for (ALL_LIST_ELEMENTS(list, node, nnode, filter)) { - if (filter->host) { + if (filter->host && filter->plist_name) { + vty_out(vty, "%s %s prefix-list %s\n", desc, + filter->host, filter->plist_name); + write++; + } else if (filter->host) { vty_out(vty, "%s %s\n", desc, filter->host); write++; } @@ -286,7 +301,8 @@ static int bgp_debug_list_conf_print(struct vty *vty, const char *desc, } static void bgp_debug_list_add_entry(struct list *list, const char *host, - const struct prefix *p) + const struct prefix *p, + const char *plist_name) { struct bgp_debug_filter *filter; @@ -295,13 +311,27 @@ static void bgp_debug_list_add_entry(struct list *list, const char *host, if (host) { filter->host = XSTRDUP(MTYPE_BGP_DEBUG_STR, host); + filter->plist_name = NULL; + filter->plist_v4 = NULL; + filter->plist_v6 = NULL; filter->p = NULL; } else if (p) { filter->host = NULL; + filter->plist_name = NULL; + filter->plist_v4 = NULL; + filter->plist_v6 = NULL; filter->p = prefix_new(); prefix_copy(filter->p, p); } + if (plist_name) { + filter->plist_name = XSTRDUP(MTYPE_BGP_DEBUG_STR, plist_name); + filter->plist_v4 = prefix_list_lookup(AFI_IP, + filter->plist_name); + filter->plist_v6 = prefix_list_lookup(AFI_IP6, + filter->plist_name); + } + listnode_add(list, filter); } @@ -315,6 +345,7 @@ static bool bgp_debug_list_remove_entry(struct list *list, const char *host, if (host && strcmp(filter->host, host) == 0) { listnode_delete(list, filter); XFREE(MTYPE_BGP_DEBUG_STR, filter->host); + XFREE(MTYPE_BGP_DEBUG_STR, filter->plist_name); XFREE(MTYPE_BGP_DEBUG_FILTER, filter); return true; } else if (p && filter->p->prefixlen == p->prefixlen @@ -330,16 +361,20 @@ static bool bgp_debug_list_remove_entry(struct list *list, const char *host, } static bool bgp_debug_list_has_entry(struct list *list, const char *host, - const struct prefix *p) + const struct prefix *p, + const char *plist_name) { struct bgp_debug_filter *filter; struct listnode *node, *nnode; for (ALL_LIST_ELEMENTS(list, node, nnode, filter)) { - if (host) { - if (strcmp(filter->host, host) == 0) { + if (host && plist_name) { + if (strmatch(filter->host, host) && filter->plist_name && + strmatch(filter->plist_name, plist_name)) + return true; + } else if (host) { + if (strmatch(filter->host, host)) return true; - } } else if (p) { if (filter->p->prefixlen == p->prefixlen && prefix_match(filter->p, p)) { @@ -353,7 +388,7 @@ static bool bgp_debug_list_has_entry(struct list *list, const char *host, bool bgp_debug_peer_updout_enabled(char *host) { - return (bgp_debug_list_has_entry(bgp_debug_update_out_peers, host, + return (bgp_debug_list_has_entry(bgp_debug_update_out_peers, host, NULL, NULL)); } @@ -780,14 +815,15 @@ DEFUN (debug_bgp_neighbor_events_peer, bgp_debug_neighbor_events_peers = list_new(); if (bgp_debug_list_has_entry(bgp_debug_neighbor_events_peers, host, - NULL)) { + NULL, NULL)) { vty_out(vty, "BGP neighbor-events debugging is already enabled for %s\n", host); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_neighbor_events_peers, host, NULL); + bgp_debug_list_add_entry(bgp_debug_neighbor_events_peers, host, NULL, + NULL); if (vty->node == CONFIG_NODE) DEBUG_ON(neighbor_events, NEIGHBOR_EVENTS); @@ -927,14 +963,15 @@ DEFUN (debug_bgp_keepalive_peer, if (!bgp_debug_keepalive_peers) bgp_debug_keepalive_peers = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_keepalive_peers, host, NULL)) { + if (bgp_debug_list_has_entry(bgp_debug_keepalive_peers, host, NULL, + NULL)) { vty_out(vty, "BGP keepalive debugging is already enabled for %s\n", host); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_keepalive_peers, host, NULL); + bgp_debug_list_add_entry(bgp_debug_keepalive_peers, host, NULL, NULL); if (vty->node == CONFIG_NODE) DEBUG_ON(keepalive, KEEPALIVE); @@ -1015,15 +1052,16 @@ DEFPY (debug_bgp_bestpath_prefix, if (!bgp_debug_bestpath_prefixes) bgp_debug_bestpath_prefixes = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_bestpath_prefixes, NULL, - prefix)) { + if (bgp_debug_list_has_entry(bgp_debug_bestpath_prefixes, NULL, prefix, + NULL)) { vty_out(vty, "BGP bestpath debugging is already enabled for %s\n", prefix_str); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_bestpath_prefixes, NULL, prefix); + bgp_debug_list_add_entry(bgp_debug_bestpath_prefixes, NULL, prefix, + NULL); if (vty->node == CONFIG_NODE) { DEBUG_ON(bestpath, BESTPATH); @@ -1116,6 +1154,31 @@ DEFUN (debug_bgp_update, return CMD_SUCCESS; } +DEFPY (debug_bgp_update_detail, + debug_bgp_update_detail_cmd, + "[no] debug bgp updates detail", + NO_STR + DEBUG_STR + BGP_STR + "BGP updates\n" + "Show detailed information about updates\n") +{ + if (vty->node == CONFIG_NODE) { + if (no) + DEBUG_OFF(update, UPDATE_DETAIL); + else + DEBUG_ON(update, UPDATE_DETAIL); + } else { + if (no) + TERM_DEBUG_OFF(update, UPDATE_DETAIL); + else + TERM_DEBUG_ON(update, UPDATE_DETAIL); + vty_out(vty, "BGP updates detail debugging is on\n"); + } + + return CMD_SUCCESS; +} + DEFUN (debug_bgp_update_direct, debug_bgp_update_direct_cmd, "debug bgp updates <in|out>", @@ -1150,9 +1213,9 @@ DEFUN (debug_bgp_update_direct, return CMD_SUCCESS; } -DEFUN (debug_bgp_update_direct_peer, +DEFPY (debug_bgp_update_direct_peer, debug_bgp_update_direct_peer_cmd, - "debug bgp updates <in|out> <A.B.C.D|X:X::X:X|WORD>", + "debug bgp updates <in|out> <A.B.C.D|X:X::X:X|WORD> [prefix-list PREFIXLIST_NAME$plist]", DEBUG_STR BGP_STR "BGP updates\n" @@ -1160,7 +1223,9 @@ DEFUN (debug_bgp_update_direct_peer, "Outbound updates\n" "BGP neighbor IP address to debug\n" "BGP IPv6 neighbor to debug\n" - "BGP neighbor on interface to debug\n") + "BGP neighbor on interface to debug\n" + "Use prefix-list to filter prefixes to debug\n" + "Name of prefix-list\n") { int idx_in_out = 3; int idx_peer = 4; @@ -1180,7 +1245,7 @@ DEFUN (debug_bgp_update_direct_peer, if (inbound) { if (bgp_debug_list_has_entry(bgp_debug_update_in_peers, host, - NULL)) { + NULL, plist)) { vty_out(vty, "BGP inbound update debugging is already enabled for %s\n", host); @@ -1190,7 +1255,7 @@ DEFUN (debug_bgp_update_direct_peer, else { if (bgp_debug_list_has_entry(bgp_debug_update_out_peers, host, - NULL)) { + NULL, plist)) { vty_out(vty, "BGP outbound update debugging is already enabled for %s\n", host); @@ -1199,14 +1264,15 @@ DEFUN (debug_bgp_update_direct_peer, } if (inbound) - bgp_debug_list_add_entry(bgp_debug_update_in_peers, host, NULL); + bgp_debug_list_add_entry(bgp_debug_update_in_peers, host, NULL, + plist); else { struct peer *peer; struct peer_af *paf; int afidx; - bgp_debug_list_add_entry(bgp_debug_update_out_peers, host, - NULL); + bgp_debug_list_add_entry(bgp_debug_update_out_peers, host, NULL, + plist); peer = bgp_find_peer(vty, host); if (peer) { @@ -1283,7 +1349,7 @@ DEFUN (no_debug_bgp_update_direct, DEFUN (no_debug_bgp_update_direct_peer, no_debug_bgp_update_direct_peer_cmd, - "no debug bgp updates <in|out> <A.B.C.D|X:X::X:X|WORD>", + "no debug bgp updates <in|out> <A.B.C.D|X:X::X:X|WORD> [prefix-list PREFIXLIST_NAME]", NO_STR DEBUG_STR BGP_STR @@ -1292,7 +1358,9 @@ DEFUN (no_debug_bgp_update_direct_peer, "Outbound updates\n" "BGP neighbor IP address to debug\n" "BGP IPv6 neighbor to debug\n" - "BGP neighbor on interface to debug\n") + "BGP neighbor on interface to debug\n" + "Use prefix-list to filter prefixes to debug\n" + "Name of prefix-list\n") { int idx_in_out = 4; int idx_peer = 5; @@ -1414,15 +1482,15 @@ DEFPY (debug_bgp_update_prefix_afi_safi, if (!bgp_debug_update_prefixes) bgp_debug_update_prefixes = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, - &argv_p)) { + if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, &argv_p, + NULL)) { vty_out(vty, "BGP updates debugging is already enabled for %pFX\n", &argv_p); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, &argv_p); + bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, &argv_p, NULL); if (vty->node == CONFIG_NODE) { DEBUG_ON(update, UPDATE_PREFIX); @@ -1510,14 +1578,15 @@ DEFPY (debug_bgp_update_prefix, if (!bgp_debug_update_prefixes) bgp_debug_update_prefixes = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, prefix)) { + if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, prefix, + NULL)) { vty_out(vty, "BGP updates debugging is already enabled for %s\n", prefix_str); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, prefix); + bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, prefix, NULL); if (vty->node == CONFIG_NODE) { DEBUG_ON(update, UPDATE_PREFIX); @@ -1647,13 +1716,14 @@ DEFPY (debug_bgp_zebra_prefix, if (!bgp_debug_zebra_prefixes) bgp_debug_zebra_prefixes = list_new(); - if (bgp_debug_list_has_entry(bgp_debug_zebra_prefixes, NULL, prefix)) { + if (bgp_debug_list_has_entry(bgp_debug_zebra_prefixes, NULL, prefix, + NULL)) { vty_out(vty, "BGP zebra debugging is already enabled for %s\n", prefix_str); return CMD_SUCCESS; } - bgp_debug_list_add_entry(bgp_debug_zebra_prefixes, NULL, prefix); + bgp_debug_list_add_entry(bgp_debug_zebra_prefixes, NULL, prefix, NULL); if (vty->node == CONFIG_NODE) DEBUG_ON(zebra, ZEBRA); @@ -2206,6 +2276,8 @@ DEFUN_NOSH (show_debugging_bgp, cmd_show_lib_debugs(vty); + hook_call(bgp_hook_config_write_debug, vty, false); + return CMD_SUCCESS; } @@ -2265,6 +2337,11 @@ static int bgp_config_write_debug(struct vty *vty) bgp_debug_update_out_peers); } + if (CONF_BGP_DEBUG(update, UPDATE_DETAIL)) { + vty_out(vty, "debug bgp updates detail\n"); + write++; + } + if (CONF_BGP_DEBUG(zebra, ZEBRA)) { if (!bgp_debug_zebra_prefixes || list_isempty(bgp_debug_zebra_prefixes)) { @@ -2340,6 +2417,9 @@ static int bgp_config_write_debug(struct vty *vty) write++; } + if (hook_call(bgp_hook_config_write_debug, vty, true)) + write++; + return write; } @@ -2370,6 +2450,8 @@ void bgp_debug_init(void) install_element(CONFIG_NODE, &debug_bgp_keepalive_cmd); install_element(ENABLE_NODE, &debug_bgp_update_cmd); install_element(CONFIG_NODE, &debug_bgp_update_cmd); + install_element(ENABLE_NODE, &debug_bgp_update_detail_cmd); + install_element(CONFIG_NODE, &debug_bgp_update_detail_cmd); install_element(ENABLE_NODE, &debug_bgp_zebra_cmd); install_element(CONFIG_NODE, &debug_bgp_zebra_cmd); install_element(ENABLE_NODE, &debug_bgp_update_groups_cmd); @@ -2510,7 +2592,8 @@ static int bgp_debug_per_prefix(const struct prefix *p, /* Return true if this peer is on the per_peer_list of peers to debug * for BGP_DEBUG_TYPE */ -static bool bgp_debug_per_peer(char *host, unsigned long term_bgp_debug_type, +static bool bgp_debug_per_peer(char *host, const struct prefix *p, + unsigned long term_bgp_debug_type, unsigned int BGP_DEBUG_TYPE, struct list *per_peer_list) { @@ -2522,17 +2605,28 @@ static bool bgp_debug_per_peer(char *host, unsigned long term_bgp_debug_type, if (!per_peer_list || list_isempty(per_peer_list)) return true; - else { - if (!host) - return false; + if (!host) + return false; - for (ALL_LIST_ELEMENTS(per_peer_list, node, nnode, - filter)) - if (strcmp(filter->host, host) == 0) - return true; + for (ALL_LIST_ELEMENTS(per_peer_list, node, nnode, filter)) + if (strmatch(filter->host, host) && + filter->plist_name && p) { + struct prefix_list *plist; + afi_t afi = family2afi(p->family); - return false; - } + plist = (afi == AFI_IP) ? filter->plist_v4 + : filter->plist_v6; + + if (!plist) + continue; + + return prefix_list_apply(plist, p) == + PREFIX_PERMIT; + } else if (strmatch(filter->host, host)) { + return true; + } + + return false; } return false; @@ -2545,7 +2639,7 @@ bool bgp_debug_neighbor_events(const struct peer *peer) if (peer) host = peer->host; - return bgp_debug_per_peer(host, term_bgp_debug_neighbor_events, + return bgp_debug_per_peer(host, NULL, term_bgp_debug_neighbor_events, BGP_DEBUG_NEIGHBOR_EVENTS, bgp_debug_neighbor_events_peers); } @@ -2557,7 +2651,7 @@ bool bgp_debug_keepalive(const struct peer *peer) if (peer) host = peer->host; - return bgp_debug_per_peer(host, term_bgp_debug_keepalive, + return bgp_debug_per_peer(host, NULL, term_bgp_debug_keepalive, BGP_DEBUG_KEEPALIVE, bgp_debug_keepalive_peers); } @@ -2571,7 +2665,7 @@ bool bgp_debug_update(const struct peer *peer, const struct prefix *p, host = peer->host; if (inbound) { - if (bgp_debug_per_peer(host, term_bgp_debug_update, + if (bgp_debug_per_peer(host, p, term_bgp_debug_update, BGP_DEBUG_UPDATE_IN, bgp_debug_update_in_peers)) return true; @@ -2579,7 +2673,7 @@ bool bgp_debug_update(const struct peer *peer, const struct prefix *p, /* outbound */ else { - if (bgp_debug_per_peer(host, term_bgp_debug_update, + if (bgp_debug_per_peer(host, p, term_bgp_debug_update, BGP_DEBUG_UPDATE_OUT, bgp_debug_update_out_peers)) return true; diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index 118325e..5b09501 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -6,9 +6,15 @@ #ifndef _QUAGGA_BGP_DEBUG_H #define _QUAGGA_BGP_DEBUG_H +#include "hook.h" +#include "vty.h" + #include "bgp_attr.h" #include "bgp_updgrp.h" +DECLARE_HOOK(bgp_hook_config_write_debug, (struct vty *vty, bool running), + (vty, running)); + /* sort of packet direction */ #define DUMP_ON 1 #define DUMP_SEND 2 @@ -96,6 +102,9 @@ extern struct list *bgp_debug_zebra_prefixes; struct bgp_debug_filter { char *host; + char *plist_name; + struct prefix_list *plist_v4; + struct prefix_list *plist_v6; struct prefix *p; }; @@ -109,6 +118,7 @@ struct bgp_debug_filter { #define BGP_DEBUG_UPDATE_IN 0x01 #define BGP_DEBUG_UPDATE_OUT 0x02 #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 @@ -124,9 +134,6 @@ struct bgp_debug_filter { #define BGP_DEBUG_EVPN_MH_ES 0x01 #define BGP_DEBUG_EVPN_MH_RT 0x02 -#define BGP_DEBUG_PACKET_SEND 0x01 -#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02 - #define BGP_DEBUG_GRACEFUL_RESTART 0x01 #define BGP_DEBUG_BFD_LIB 0x01 diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c index 529713e..53b5212 100644 --- a/bgpd/bgp_dump.c +++ b/bgpd/bgp_dump.c @@ -4,6 +4,7 @@ */ #include <zebra.h> +#include <sys/stat.h> #include "log.h" #include "stream.h" diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index c408edb..a8ae177 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -1042,6 +1042,34 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt, return len; } +bool ecommunity_has_route_target(struct ecommunity *ecom) +{ + uint32_t i; + uint8_t *pnt; + uint8_t type = 0; + uint8_t sub_type = 0; + + if (!ecom) + return false; + for (i = 0; i < ecom->size; i++) { + /* Retrieve value field */ + pnt = ecom->val + (i * ecom->unit_size); + + /* High-order octet is the type */ + type = *pnt++; + + if (type == ECOMMUNITY_ENCODE_AS || + type == ECOMMUNITY_ENCODE_IP || + type == ECOMMUNITY_ENCODE_AS4) { + /* Low-order octet of type. */ + sub_type = *pnt++; + if (sub_type == ECOMMUNITY_ROUTE_TARGET) + return true; + } + } + return false; +} + /* Convert extended community attribute to string. * Due to historical reason of industry standard implementation, there * are three types of format: @@ -1581,8 +1609,8 @@ int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, * in the 'Network Address of Next- Hop' * field of the associated MP_REACH_NLRI. */ - struct ecommunity_ip *ip_ecom = (struct ecommunity_ip *) - ecom_eval + 2; + struct ecommunity_ip *ip_ecom = + (struct ecommunity_ip *)&ecom_eval->val[2]; api->u.zr.redirect_ip_v4 = ip_ecom->ip; } else diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 7dc04d2..62e0430 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -117,6 +117,9 @@ struct ecommunity { */ uint8_t unit_size; + /* Disable IEEE floating-point encoding for extended community */ + bool disable_ieee_floating; + /* Size of Extended Communities attribute. */ uint32_t size; @@ -125,9 +128,6 @@ struct ecommunity { /* Human readable format string. */ char *str; - - /* Disable IEEE floating-point encoding for extended community */ - bool disable_ieee_floating; }; struct ecommunity_as { @@ -341,6 +341,7 @@ extern struct ecommunity *ecommunity_str2com(const char *, int, int); extern struct ecommunity *ecommunity_str2com_ipv6(const char *str, int type, int keyword_included); extern char *ecommunity_ecom2str(struct ecommunity *, int, int); +extern bool ecommunity_has_route_target(struct ecommunity *ecom); extern void ecommunity_strfree(char **s); extern bool ecommunity_include(struct ecommunity *e1, struct ecommunity *e2); extern bool ecommunity_match(const struct ecommunity *, diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index ad101f1..a846484 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -311,6 +311,49 @@ static int is_vni_present_in_irt_vnis(struct list *vnis, struct bgpevpn *vpn) return 0; } +/* Flag if the route is injectable into EVPN. + * This would be following category: + * Non-imported route, + * Non-EVPN imported route, + */ +bool is_route_injectable_into_evpn_non_supp(struct bgp_path_info *pi) +{ + struct bgp_path_info *parent_pi; + struct bgp_table *table; + struct bgp_dest *dest; + + if (pi->sub_type != BGP_ROUTE_IMPORTED || !pi->extra || + !pi->extra->vrfleak || !pi->extra->vrfleak->parent) + return true; + + parent_pi = (struct bgp_path_info *)pi->extra->vrfleak->parent; + dest = parent_pi->net; + if (!dest) + return true; + table = bgp_dest_table(dest); + if (table && + table->afi == AFI_L2VPN && + table->safi == SAFI_EVPN) + return false; + + return true; +} + +/* Flag if the route is injectable into EVPN. + * This would be following category: + * Non-imported route, + * Non-EVPN imported route, + * Non Aggregate suppressed route. + */ +bool is_route_injectable_into_evpn(struct bgp_path_info *pi) +{ + /* do not import aggr suppressed routes */ + if (bgp_path_suppressed(pi)) + return false; + + return is_route_injectable_into_evpn_non_supp(pi); +} + /* * Compare Route Targets. */ @@ -881,7 +924,7 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, zclient_create_header( s, add ? ZEBRA_REMOTE_MACIP_ADD : ZEBRA_REMOTE_MACIP_DEL, bgp->vrf_id); - stream_putl(s, vpn->vni); + stream_putl(s, vpn ? vpn->vni : 0); if (mac) /* Mac Addr */ stream_put(s, &mac->octet, ETH_ALEN); @@ -927,7 +970,7 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, snprintf(esi_buf, sizeof(esi_buf), "-"); zlog_debug( "Tx %s MACIP, VNI %u MAC %pEA IP %pIA flags 0x%x seq %u remote VTEP %pI4 esi %s", - add ? "ADD" : "DEL", vpn->vni, + add ? "ADD" : "DEL", (vpn ? vpn->vni : 0), (mac ? mac : &p->prefix.macip_addr.mac), &p->prefix.macip_addr.ip, flags, seq, &remote_vtep_ip, esi_buf); @@ -970,14 +1013,14 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, zclient_create_header( s, add ? ZEBRA_REMOTE_VTEP_ADD : ZEBRA_REMOTE_VTEP_DEL, bgp->vrf_id); - stream_putl(s, vpn->vni); + stream_putl(s, vpn ? vpn->vni : 0); if (is_evpn_prefix_ipaddr_v4(p)) stream_put_in_addr(s, &p->prefix.imet_addr.ip.ipaddr_v4); else if (is_evpn_prefix_ipaddr_v6(p)) { flog_err( EC_BGP_VTEP_INVALID, "Bad remote IP when trying to %s remote VTEP for VNI %u", - add ? "ADD" : "DEL", vpn->vni); + add ? "ADD" : "DEL", (vpn ? vpn->vni : 0)); return -1; } stream_putl(s, flood_control); @@ -986,7 +1029,7 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, if (bgp_debug_zebra(NULL)) zlog_debug("Tx %s Remote VTEP, VNI %u remote VTEP %pI4", - add ? "ADD" : "DEL", vpn->vni, + add ? "ADD" : "DEL", (vpn ? vpn->vni : 0), &p->prefix.imet_addr.ip.ipaddr_v4); frrtrace(3, frr_bgp, evpn_bum_vtep_zsend, add, vpn, p); @@ -1638,6 +1681,9 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp, vrf_id_to_name(bgp_vrf->vrf_id), evp, &attr.rmac, &attr.nexthop); + frrtrace(4, frr_bgp, evpn_advertise_type5, bgp_vrf->vrf_id, evp, + &attr.rmac, attr.nexthop); + attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; if (src_afi == AFI_IP6 && @@ -2280,6 +2326,8 @@ static int delete_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp) if (!dest) return 0; + frrtrace(2, frr_bgp, evpn_withdraw_type5, bgp_vrf->vrf_id, evp); + delete_evpn_route_entry(bgp_evpn, afi, safi, dest, &pi); if (pi) bgp_process(bgp_evpn, dest, afi, safi); @@ -3029,11 +3077,22 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, /* Process for route leaking. */ vpn_leak_from_vrf_update(bgp_get_default(), bgp_vrf, pi); - if (bgp_debug_zebra(NULL)) - zlog_debug("... %s pi dest %p (l %d) pi %p (l %d, f 0x%x)", - new_pi ? "new" : "update", dest, + if (bgp_debug_zebra(NULL)) { + struct ipaddr nhip = {}; + + if (pi->net->rn->p.family == AF_INET6) { + SET_IPADDR_V6(&nhip); + IPV6_ADDR_COPY(&nhip.ipaddr_v6, &pi->attr->mp_nexthop_global); + } else { + SET_IPADDR_V4(&nhip); + IPV4_ADDR_COPY(&nhip.ipaddr_v4, &pi->attr->nexthop); + } + zlog_debug("... %s pi %s dest %p (l %d) pi %p (l %d, f 0x%x) nh %pIA", + new_pi ? "new" : "update", + bgp_vrf->name_pretty, dest, bgp_dest_get_lock_count(dest), pi, pi->lock, - pi->flags); + pi->flags, &nhip); + } bgp_dest_unlock_node(dest); @@ -3342,10 +3401,22 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, return 0; } - if (bgp_debug_zebra(NULL)) - zlog_debug("... delete dest %p (l %d) pi %p (l %d, f 0x%x)", - dest, bgp_dest_get_lock_count(dest), pi, pi->lock, - pi->flags); + if (bgp_debug_zebra(NULL)) { + struct ipaddr nhip = {}; + + if (pi->net->rn->p.family == AF_INET6) { + SET_IPADDR_V6(&nhip); + IPV6_ADDR_COPY(&nhip.ipaddr_v6, &pi->attr->mp_nexthop_global); + } else { + SET_IPADDR_V4(&nhip); + IPV4_ADDR_COPY(&nhip.ipaddr_v4, &pi->attr->nexthop); + } + + zlog_debug("... delete pi %s dest %p (l %d) pi %p (l %d, f 0x%x) nh %pIA", + bgp_vrf->name_pretty, dest, + bgp_dest_get_lock_count(dest), pi, pi->lock, + pi->flags, &nhip); + } /* Process for route leaking. */ vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp_vrf, pi); @@ -3590,7 +3661,7 @@ static bool bgp_evpn_route_matches_macvrf_soo(struct bgp_path_info *pi, struct ecommunity *macvrf_soo; bool ret = false; - if (!bgp_evpn->evpn_info) + if (!bgp_evpn || !bgp_evpn->evpn_info) return false; /* We only stamp the mac-vrf soo on routes from our local L2VNI. @@ -6097,7 +6168,7 @@ void bgp_evpn_derive_auto_rd(struct bgp *bgp, struct bgpevpn *vpn) snprintfrr(buf, sizeof(buf), "%pI4:%hu", &bgp->router_id, vpn->rd_id); (void)str2prefix_rd(buf, &vpn->prd); if (vpn->prd_pretty) - XFREE(MTYPE_BGP, vpn->prd_pretty); + XFREE(MTYPE_BGP_NAME, vpn->prd_pretty); UNSET_FLAG(vpn->flags, VNI_FLAG_RD_CFGD); } @@ -6203,7 +6274,7 @@ void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn) hash_release(bgp->vni_svi_hash, vpn); hash_release(bgp->vnihash, vpn); if (vpn->prd_pretty) - XFREE(MTYPE_BGP, vpn->prd_pretty); + XFREE(MTYPE_BGP_NAME, vpn->prd_pretty); QOBJ_UNREG(vpn); XFREE(MTYPE_BGP_EVPN, vpn); } @@ -7080,7 +7151,7 @@ void bgp_evpn_cleanup(struct bgp *bgp) } if (bgp->vrf_prd_pretty) - XFREE(MTYPE_BGP, bgp->vrf_prd_pretty); + XFREE(MTYPE_BGP_NAME, bgp->vrf_prd_pretty); } /* @@ -7650,3 +7721,64 @@ bool bgp_evpn_mpath_has_dvni(const struct bgp *bgp_vrf, return false; } + +/* Upon aggregate set trigger unimport suppressed routes + * from EVPN + */ +void bgp_aggr_supp_withdraw_from_evpn(struct bgp *bgp, afi_t afi, safi_t safi) +{ + struct bgp_dest *agg_dest, *dest, *top; + const struct prefix *aggr_p; + struct bgp_aggregate *bgp_aggregate; + struct bgp_table *table; + struct bgp_path_info *pi; + + if (!bgp_get_evpn() && !advertise_type5_routes(bgp, afi)) + return; + + /* Aggregate-address table walk. */ + table = bgp->rib[afi][safi]; + for (agg_dest = bgp_table_top(bgp->aggregate[afi][safi]); agg_dest; + agg_dest = bgp_route_next(agg_dest)) { + bgp_aggregate = bgp_dest_get_bgp_aggregate_info(agg_dest); + + if (bgp_aggregate == NULL) + continue; + + aggr_p = bgp_dest_get_prefix(agg_dest); + + /* Look all nodes below the aggregate prefix in + * global AFI/SAFI table (IPv4/IPv6). + * Trigger withdrawal (this will be Type-5 routes only) + * from EVPN Global table. + */ + top = bgp_node_get(table, aggr_p); + for (dest = bgp_node_get(table, aggr_p); dest; + dest = bgp_route_next_until(dest, top)) { + const struct prefix *dest_p = bgp_dest_get_prefix(dest); + + if (dest_p->prefixlen <= aggr_p->prefixlen) + continue; + + for (pi = bgp_dest_get_bgp_path_info(dest); pi; + pi = pi->next) { + if (pi->sub_type == BGP_ROUTE_AGGREGATE) + continue; + + /* Only Suppressed route remove from EVPN */ + if (!bgp_path_suppressed(pi)) + continue; + + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s aggregated %pFX remove suppressed route %pFX", + __func__, aggr_p, dest_p); + + if (!is_route_injectable_into_evpn_non_supp(pi)) + continue; + + bgp_evpn_withdraw_type5_route(bgp, dest_p, afi, + safi); + } + } + } +} diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 5547446..c641a64 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -94,31 +94,6 @@ static inline bool is_pi_family_evpn(struct bgp_path_info *pi) return is_pi_family_matching(pi, AFI_L2VPN, SAFI_EVPN); } -/* Flag if the route is injectable into EVPN. This would be either a - * non-imported route or a non-EVPN imported route. - */ -static inline bool is_route_injectable_into_evpn(struct bgp_path_info *pi) -{ - struct bgp_path_info *parent_pi; - struct bgp_table *table; - struct bgp_dest *dest; - - if (pi->sub_type != BGP_ROUTE_IMPORTED || !pi->extra || - !pi->extra->vrfleak || !pi->extra->vrfleak->parent) - return true; - - parent_pi = (struct bgp_path_info *)pi->extra->vrfleak->parent; - dest = parent_pi->net; - if (!dest) - return true; - table = bgp_dest_table(dest); - if (table && - table->afi == AFI_L2VPN && - table->safi == SAFI_EVPN) - return false; - return true; -} - static inline bool evpn_resolve_overlay_index(void) { struct bgp *bgp = NULL; @@ -206,5 +181,9 @@ extern mpls_label_t *bgp_evpn_path_info_labels_get_l3vni(mpls_label_t *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); +extern bool is_route_injectable_into_evpn(struct bgp_path_info *pi); +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); #endif /* _QUAGGA_BGP_EVPN_H */ diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index ffb1b17..d88c52d 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -37,7 +37,7 @@ #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_addpath.h" #include "bgpd/bgp_label.h" -#include "bgpd/bgp_nht.h" +#include "bgpd/bgp_nhg.h" #include "bgpd/bgp_mpath.h" #include "bgpd/bgp_trace.h" @@ -441,6 +441,10 @@ int bgp_evpn_mh_route_update(struct bgp *bgp, struct bgp_evpn_es *es, ? "esr" : (vpn ? "ead-evi" : "ead-es"), &attr->mp_nexthop_global_in); + + frrtrace(4, frr_bgp, evpn_mh_local_ead_es_evi_route_upd, + &es->esi, (vpn ? vpn->vni : 0), evp->prefix.route_type, + attr->mp_nexthop_global_in); } /* Return back the route entry. */ @@ -491,6 +495,8 @@ static int bgp_evpn_mh_route_delete(struct bgp *bgp, struct bgp_evpn_es *es, : (vpn ? "ead-evi" : "ead-es"), &es->originator_ip); + frrtrace(4, frr_bgp, evpn_mh_local_ead_es_evi_route_del, &es->esi, + (vpn ? vpn->vni : 0), p->prefix.route_type, es->originator_ip); /* Next, locate route node in the global EVPN routing table. * Note that this table is a 2-level tree (RD-level + Prefix-level) */ @@ -2999,8 +3005,8 @@ static struct bgp_evpn_es_vrf *bgp_evpn_es_vrf_create(struct bgp_evpn_es *es, listnode_add(es->es_vrf_list, &es_vrf->es_listnode); /* setup the L3 NHG id for the ES */ - es_vrf->nhg_id = bgp_l3nhg_id_alloc(); - es_vrf->v6_nhg_id = bgp_l3nhg_id_alloc(); + es_vrf->nhg_id = bgp_nhg_id_alloc(); + es_vrf->v6_nhg_id = bgp_nhg_id_alloc(); if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) zlog_debug("es %s vrf %u nhg %u v6_nhg %d create", es->esi_str, @@ -3028,10 +3034,10 @@ static void bgp_evpn_es_vrf_delete(struct bgp_evpn_es_vrf *es_vrf) /* Remove the NHG resources */ bgp_evpn_l3nhg_deactivate(es_vrf); if (es_vrf->nhg_id) - bgp_l3nhg_id_free(es_vrf->nhg_id); + bgp_nhg_id_free(es_vrf->nhg_id); es_vrf->nhg_id = 0; if (es_vrf->v6_nhg_id) - bgp_l3nhg_id_free(es_vrf->v6_nhg_id); + bgp_nhg_id_free(es_vrf->v6_nhg_id); es_vrf->v6_nhg_id = 0; /* remove from the ES's VRF list */ @@ -3460,6 +3466,10 @@ static void bgp_evpn_es_evi_vtep_add(struct bgp *bgp, evi_vtep->es_evi->vpn->vni, &evi_vtep->vtep_ip, ead_es ? "ead_es" : "ead_evi"); + frrtrace(4, frr_bgp, evpn_mh_es_evi_vtep_add, + &evi_vtep->es_evi->es->esi, evi_vtep->es_evi->vpn->vni, + evi_vtep->vtep_ip, ead_es); + if (ead_es) SET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_ES); else @@ -3484,6 +3494,10 @@ static void bgp_evpn_es_evi_vtep_del(struct bgp *bgp, evi_vtep->es_evi->vpn->vni, &evi_vtep->vtep_ip, ead_es ? "ead_es" : "ead_evi"); + frrtrace(4, frr_bgp, evpn_mh_es_evi_vtep_del, + &evi_vtep->es_evi->es->esi, evi_vtep->es_evi->vpn->vni, + evi_vtep->vtep_ip, ead_es); + if (ead_es) UNSET_FLAG(evi_vtep->flags, BGP_EVPN_EVI_VTEP_EAD_PER_ES); else @@ -4443,13 +4457,13 @@ static void bgp_evpn_nh_zebra_update_send(struct bgp_evpn_nh *nh, bool add) stream_putw_at(s, 0, stream_get_endp(s)); - if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) { + if (BGP_DEBUG(evpn_mh, EVPN_MH_ES) || bgp_debug_zebra(NULL)) { if (add) - zlog_debug("evpn vrf %s nh %s rmac %pEA add to zebra", + zlog_debug("evpn %s nh %s rmac %pEA add to zebra", nh->bgp_vrf->name_pretty, nh->nh_str, &nh->rmac); - else if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) - zlog_debug("evpn vrf %s nh %s del to zebra", + else + zlog_debug("evpn %s nh %s del to zebra", nh->bgp_vrf->name_pretty, nh->nh_str); } @@ -4632,7 +4646,7 @@ static void bgp_evpn_nh_update_ref_pi(struct bgp_evpn_nh *nh) continue; if (BGP_DEBUG(evpn_mh, EVPN_MH_ES)) - zlog_debug("evpn vrf %s nh %s ref_pi update", + zlog_debug("evpn %s nh %s ref_pi update", nh->bgp_vrf->name_pretty, nh->nh_str); nh->ref_pi = pi; /* If we have a new pi copy rmac from it and update @@ -4710,11 +4724,12 @@ static void bgp_evpn_path_nh_unlink(struct bgp_path_evpn_nh_info *nh_info) pi = nh_info->pi; if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) - zlog_debug("path %s unlinked from nh %s %s", + zlog_debug("path %s unlinked from %s nh %s pathcount %u", pi->net ? prefix2str(&pi->net->rn->p, prefix_buf, sizeof(prefix_buf)) : "", - nh->bgp_vrf->name_pretty, nh->nh_str); + nh->bgp_vrf->name_pretty, nh->nh_str, + listcount(nh->pi_list)); list_delete_node(nh->pi_list, &nh_info->nh_listnode); @@ -4745,7 +4760,7 @@ static void bgp_evpn_path_nh_link(struct bgp *bgp_vrf, struct bgp_path_info *pi) if (!bgp_vrf->evpn_nh_table) { if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) - zlog_debug("path %pFX linked to vrf %s failed", + zlog_debug("path %pFX linked to %s failed", &pi->net->rn->p, bgp_vrf->name_pretty); return; } @@ -4793,8 +4808,9 @@ static void bgp_evpn_path_nh_link(struct bgp *bgp_vrf, struct bgp_path_info *pi) bgp_evpn_path_nh_unlink(nh_info); if (BGP_DEBUG(evpn_mh, EVPN_MH_RT)) - zlog_debug("path %pFX linked to nh %s %s", &pi->net->rn->p, - nh->bgp_vrf->name_pretty, nh->nh_str); + zlog_debug("path %pFX linked to %s nh %s pathcount %u", + &pi->net->rn->p, nh->bgp_vrf->name_pretty, + nh->nh_str, listcount(nh->pi_list)); /* link mac-ip path to the new nh */ nh_info->nh = nh; diff --git a/bgpd/bgp_evpn_mh.h b/bgpd/bgp_evpn_mh.h index ee1f749..cebabb9 100644 --- a/bgpd/bgp_evpn_mh.h +++ b/bgpd/bgp_evpn_mh.h @@ -388,11 +388,6 @@ static inline bool bgp_evpn_attr_is_local_es(struct attr *attr) return attr ? !!(attr->es_flags & ATTR_ES_IS_LOCAL) : false; } -static inline uint32_t bgp_evpn_attr_get_df_pref(struct attr *attr) -{ - return (attr) ? attr->df_pref : 0; -} - static inline bool bgp_evpn_local_es_is_active(struct bgp_evpn_es *es) { return (es->flags & BGP_EVPNES_OPER_UP) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index eb9f34e..846a82b 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -2294,11 +2294,11 @@ static void evpn_configure_vrf_rd(struct bgp *bgp_vrf, struct prefix_rd *rd, bgp_evpn_handle_vrf_rd_change(bgp_vrf, 1); if (bgp_vrf->vrf_prd_pretty) - XFREE(MTYPE_BGP, bgp_vrf->vrf_prd_pretty); + XFREE(MTYPE_BGP_NAME, bgp_vrf->vrf_prd_pretty); /* update RD */ memcpy(&bgp_vrf->vrf_prd, rd, sizeof(struct prefix_rd)); - bgp_vrf->vrf_prd_pretty = XSTRDUP(MTYPE_BGP, rd_pretty); + bgp_vrf->vrf_prd_pretty = XSTRDUP(MTYPE_BGP_NAME, rd_pretty); SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD); /* We have a new RD for VRF. @@ -2321,7 +2321,7 @@ static void evpn_unconfigure_vrf_rd(struct bgp *bgp_vrf) bgp_evpn_derive_auto_rd_for_vrf(bgp_vrf); UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD); if (bgp_vrf->vrf_prd_pretty) - XFREE(MTYPE_BGP, bgp_vrf->vrf_prd_pretty); + XFREE(MTYPE_BGP_NAME, bgp_vrf->vrf_prd_pretty); /* We have a new RD for VRF. * Advertise all type-5 routes again with the new RD */ @@ -2343,7 +2343,7 @@ static void evpn_configure_rd(struct bgp *bgp, struct bgpevpn *vpn, /* update RD */ memcpy(&vpn->prd, rd, sizeof(struct prefix_rd)); - vpn->prd_pretty = XSTRDUP(MTYPE_BGP, rd_pretty); + vpn->prd_pretty = XSTRDUP(MTYPE_BGP_NAME, rd_pretty); SET_FLAG(vpn->flags, VNI_FLAG_RD_CFGD); if (is_vni_live(vpn)) diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index ad541b6..a851179 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -205,8 +205,17 @@ static struct as_list *as_list_new(void) static void as_list_free(struct as_list *aslist) { - XFREE(MTYPE_AS_STR, aslist->name); - XFREE(MTYPE_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); } /* Insert new AS list to list of as_list. Each as_list is sorted by @@ -290,6 +299,7 @@ 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; @@ -308,6 +318,12 @@ 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); } diff --git a/bgpd/bgp_filter.h b/bgpd/bgp_filter.h index 1890fd3..2d9f07c 100644 --- a/bgpd/bgp_filter.h +++ b/bgpd/bgp_filter.h @@ -25,6 +25,11 @@ struct as_filter { int64_t seq; }; +struct aspath_exclude_list { + struct aspath_exclude_list *next; + struct aspath_exclude *bp_as_excl; +}; + /* AS path filter list. */ struct as_list { char *name; @@ -34,6 +39,7 @@ struct as_list { struct as_filter *head; struct as_filter *tail; + struct aspath_exclude_list *exclude_list; }; diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index a295ec5..d4ccca8 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -547,7 +547,7 @@ static int bgp_fs_local_install_interface(struct bgp *bgp, return CMD_SUCCESS; pbr_if = XCALLOC(MTYPE_TMP, sizeof(struct bgp_pbr_interface)); - strlcpy(pbr_if->name, ifname, INTERFACE_NAMSIZ); + strlcpy(pbr_if->name, ifname, IFNAMSIZ); RB_INSERT(bgp_pbr_interface_head, head, pbr_if); *bgp_pbr_interface_any = false; } else { diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index eef3b64..234dbb0 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -445,7 +445,7 @@ void bgp_timer_set(struct peer_connection *connection) EVENT_OFF(peer->connection->t_pmax_restart); EVENT_OFF(peer->t_refresh_stalepath); - /* fallthru */ + fallthrough; case Clearing: EVENT_OFF(connection->t_start); EVENT_OFF(connection->t_connect); @@ -562,42 +562,45 @@ void bgp_delayopen_timer(struct event *thread) } /* BGP Peer Down Cause */ -const char *const peer_down_str[] = {"", - "Router ID changed", - "Remote AS changed", - "Local AS change", - "Cluster ID changed", - "Confederation identifier changed", - "Confederation peer changed", - "RR client config change", - "RS client config change", - "Update source change", - "Address family activated", - "Admin. shutdown", - "User reset", - "BGP Notification received", - "BGP Notification send", - "Peer closed the session", - "Neighbor deleted", - "Peer-group add member", - "Peer-group delete member", - "Capability changed", - "Passive config change", - "Multihop config change", - "NSF peer closed the session", - "Intf peering v6only config change", - "BFD down received", - "Interface down", - "Neighbor address lost", - "No path to specified Neighbor", - "Waiting for Peer IPv6 LLA", - "Waiting for VRF to be initialized", - "No AFI/SAFI activated for peer", - "AS Set config change", - "Waiting for peer OPEN", - "Reached received prefix count", - "Socket Error", - "Admin. shutdown (RTT)"}; +const char *const peer_down_str[] = { + "", + "Router ID changed", + "Remote AS changed", + "Local AS change", + "Cluster ID changed", + "Confederation identifier changed", + "Confederation peer changed", + "RR client config change", + "RS client config change", + "Update source change", + "Address family activated", + "Admin. shutdown", + "User reset", + "BGP Notification received", + "BGP Notification send", + "Peer closed the session", + "Neighbor deleted", + "Peer-group add member", + "Peer-group delete member", + "Capability changed", + "Passive config change", + "Multihop config change", + "NSF peer closed the session", + "Intf peering v6only config change", + "BFD down received", + "Interface down", + "Neighbor address lost", + "No path to specified Neighbor", + "Waiting for Peer IPv6 LLA", + "Waiting for VRF to be initialized", + "No AFI/SAFI activated for peer", + "AS Set config change", + "Waiting for peer OPEN", + "Reached received prefix count", + "Socket Error", + "Admin. shutdown (RTT)", + "Suppress Fib Turned On or Off", +}; static void bgp_graceful_restart_timer_off(struct peer_connection *connection, struct peer *peer) @@ -2384,6 +2387,7 @@ void bgp_fsm_nht_update(struct peer_connection *connection, struct peer *peer, && (peer->gtsm_hops == BGP_GTSM_HOPS_CONNECTED || peer->bgp->fast_convergence)) BGP_EVENT_ADD(connection, TCP_fatal_error); + break; case Clearing: case Deleted: case BGP_STATUS_MAX: @@ -2716,7 +2720,7 @@ int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp, return BGP_GR_SUCCESS; } -int bgp_gr_update_all(struct bgp *bgp, int global_gr_cmd) +int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd) { enum global_mode global_new_state = GLOBAL_INVALID; enum global_mode global_old_state = GLOBAL_INVALID; @@ -2870,7 +2874,8 @@ enum peer_mode bgp_peer_gr_mode_get(struct peer *peer) return peer->peer_gr_present_state; } -int bgp_neighbor_graceful_restart(struct peer *peer, int peer_gr_cmd) +int bgp_neighbor_graceful_restart(struct peer *peer, + enum peer_gr_command peer_gr_cmd) { enum peer_mode peer_new_state = PEER_INVALID; enum peer_mode peer_old_state = PEER_INVALID; @@ -2929,8 +2934,8 @@ int bgp_neighbor_graceful_restart(struct peer *peer, int peer_gr_cmd) return result; } -unsigned int bgp_peer_gr_action(struct peer *peer, int old_peer_state, - int new_peer_state) +unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_peer_state, + enum peer_mode new_peer_state) { if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) zlog_debug( @@ -2938,7 +2943,7 @@ unsigned int bgp_peer_gr_action(struct peer *peer, int old_peer_state, __func__, print_peer_gr_mode(old_peer_state), print_peer_gr_mode(new_peer_state)); - int bgp_gr_global_mode = GLOBAL_INVALID; + enum global_mode bgp_gr_global_mode = GLOBAL_INVALID; unsigned int ret = BGP_GR_FAILURE; if (old_peer_state == new_peer_state) { @@ -2970,10 +2975,10 @@ unsigned int bgp_peer_gr_action(struct peer *peer, int old_peer_state, BGP_PEER_GR_GLOBAL_INHERIT_UNSET(peer); - if (new_peer_state == bgp_gr_global_mode) { - /*This is incremental updates i.e no tear down - *of the existing session - *as the peer is already working in the same mode. + if ((int)new_peer_state == (int)bgp_gr_global_mode) { + /* This is incremental updates i.e no tear down + * of the existing session + * as the peer is already working in the same mode. */ ret = BGP_GR_SUCCESS; } else { @@ -3000,8 +3005,7 @@ unsigned int bgp_peer_gr_action(struct peer *peer, int old_peer_state, BGP_PEER_GR_GLOBAL_INHERIT_SET(peer); - if (old_peer_state == bgp_gr_global_mode) { - + if ((int)old_peer_state == (int)bgp_gr_global_mode) { /* This is incremental updates *i.e no tear down of the existing session *as the peer is already working in the same mode. diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index fd46b79..2e96ac4 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -143,10 +143,11 @@ extern void bgp_adjust_routeadv(struct peer *); DECLARE_HOOK(peer_backward_transition, (struct peer *peer), (peer)); DECLARE_HOOK(peer_established, (struct peer *peer), (peer)); -int bgp_gr_update_all(struct bgp *bgp, int global_gr_cmd); -int bgp_neighbor_graceful_restart(struct peer *peer, int peer_gr_cmd); -unsigned int bgp_peer_gr_action(struct peer *peer, - int old_peer_state, int new_peer_state); +int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd); +int bgp_neighbor_graceful_restart(struct peer *peer, + enum peer_gr_command peer_gr_cmd); +unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_peer_state, + enum peer_mode new_peer_state); void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state); unsigned int bgp_peer_gr_helper_enable(struct peer *peer); unsigned int bgp_peer_gr_enable(struct peer *peer); diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index b8ce1ae..7327ab5 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -132,9 +132,8 @@ static void bgp_send_fec_register_label_msg(struct bgp_dest *dest, bool reg, return; if (BGP_DEBUG(labelpool, LABELPOOL)) - zlog_debug("%s: FEC %sregister %pRN label_index=%u label=%u", - __func__, reg ? "" : "un", bgp_dest_to_rnode(dest), - label_index, label); + zlog_debug("%s: FEC %sregister %pBD label_index=%u label=%u", + __func__, reg ? "" : "un", dest, label_index, label); /* If the route node has a local_label assigned or the * path node has an MPLS SR label index allowing zebra to * derive the label, proceed with registration. */ @@ -199,8 +198,8 @@ int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid, assert(dest); if (BGP_DEBUG(labelpool, LABELPOOL)) - zlog_debug("%s: FEC %pRN label=%u, allocated=%d", __func__, - bgp_dest_to_rnode(dest), new_label, allocated); + zlog_debug("%s: FEC %pBD label=%u, allocated=%d", __func__, + dest, new_label, allocated); if (!allocated) { /* diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c index 8833386..23e0c19 100644 --- a/bgpd/bgp_labelpool.c +++ b/bgpd/bgp_labelpool.c @@ -36,6 +36,8 @@ static void lptest_init(void); static void lptest_finish(void); #endif +static void bgp_sync_label_manager(struct event *e); + /* * Remember where pool data are kept */ @@ -448,13 +450,16 @@ void bgp_lp_get( if (lp_fifo_count(&lp->requests) > lp->pending_count) { if (!bgp_zebra_request_label_range(MPLS_LABEL_BASE_ANY, - lp->next_chunksize)) + lp->next_chunksize, true)) return; lp->pending_count += lp->next_chunksize; if ((lp->next_chunksize << 1) <= LP_CHUNK_SIZE_MAX) lp->next_chunksize <<= 1; } + + event_add_timer(bm->master, bgp_sync_label_manager, NULL, 1, + &bm->t_bgp_sync_label_manager); } void bgp_lp_release( @@ -494,8 +499,18 @@ void bgp_lp_release( bf_release_index(chunk->allocated_map, index); chunk->nfree += 1; deallocated = true; + break; } assert(deallocated); + if (deallocated && + chunk->nfree == chunk->last - chunk->first + 1 && + lp_fifo_count(&lp->requests) == 0) { + bgp_zebra_release_label_range(chunk->first, + chunk->last); + list_delete_node(lp->chunks, node); + lp_chunk_free(chunk); + lp->next_chunksize = LP_CHUNK_SIZE_MIN; + } } } } @@ -547,6 +562,10 @@ static void bgp_sync_label_manager(struct event *e) zlog_debug("%s: out of labels, await more", __func__); } + + lp_fifo_add_tail(&lp->requests, lf); + event_add_timer(bm->master, bgp_sync_label_manager, + NULL, 1, &bm->t_bgp_sync_label_manager); break; } @@ -572,9 +591,6 @@ static void bgp_sync_label_manager(struct event *e) finishedrequest: XFREE(MTYPE_BGP_LABEL_FIFO, lf); } - - event_add_timer(bm->master, bgp_sync_label_manager, NULL, 1, - &bm->t_bgp_sync_label_manager); } void bgp_lp_event_chunk(uint32_t first, uint32_t last) @@ -642,7 +658,7 @@ void bgp_lp_event_zebra_up(void) } /* round up */ - chunks_needed = (labels_needed / lp->next_chunksize) + 1; + chunks_needed = (labels_needed + lp->next_chunksize - 1) / lp->next_chunksize; labels_needed = chunks_needed * lp->next_chunksize; /* @@ -650,10 +666,10 @@ void bgp_lp_event_zebra_up(void) */ list_delete_all_node(lp->chunks); - if (!bgp_zebra_request_label_range(MPLS_LABEL_BASE_ANY, labels_needed)) + if (labels_needed && !bgp_zebra_request_label_range(MPLS_LABEL_BASE_ANY, + labels_needed, true)) return; - - lp->pending_count = labels_needed; + lp->pending_count += labels_needed; /* * Invalidate any existing labels and requeue them as requests diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 11917c6..851c488 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -47,14 +47,20 @@ #include "bgpd/bgp_errors.h" #include "bgpd/bgp_script.h" #include "bgpd/bgp_evpn_mh.h" -#include "bgpd/bgp_nht.h" +#include "bgpd/bgp_nhg.h" #include "bgpd/bgp_routemap_nb.h" #include "bgpd/bgp_community_alias.h" +DEFINE_HOOK(bgp_hook_config_write_vrf, (struct vty *vty, struct vrf *vrf), + (vty, vrf)); + #ifdef ENABLE_BGP_VNC #include "bgpd/rfapi/rfapi_backend.h" #endif +DEFINE_HOOK(bgp_hook_vrf_update, (struct vrf *vrf, bool enabled), + (vrf, enabled)); + /* bgpd options, we use GNU getopt library. */ static const struct option longopts[] = { { "bgp_port", required_argument, NULL, 'p' }, @@ -199,7 +205,7 @@ static __attribute__((__noreturn__)) void bgp_exit(int status) bgp_delete(bgp_default); bgp_evpn_mh_finish(); - bgp_l3nhg_finish(); + bgp_nhg_finish(); /* reverse bgp_dump_init */ bgp_dump_finish(); @@ -287,6 +293,7 @@ static int bgp_vrf_enable(struct vrf *vrf) bgp_handle_socket(bgp, vrf, old_vrf_id, true); bgp_instance_up(bgp); + hook_call(bgp_hook_vrf_update, vrf, true); 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); @@ -333,15 +340,36 @@ static int bgp_vrf_disable(struct vrf *vrf) * "down". */ bgp_instance_down(bgp); bgp_vrf_unlink(bgp, vrf); + hook_call(bgp_hook_vrf_update, vrf, false); } /* Note: This is a callback, the VRF will be deleted by the caller. */ return 0; } +static int bgp_vrf_config_write(struct vty *vty) +{ + struct vrf *vrf; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + if (vrf->vrf_id == VRF_DEFAULT) { + vty_out(vty, "!\n"); + continue; + } + vty_out(vty, "vrf %s\n", vrf->name); + + hook_call(bgp_hook_config_write_vrf, vty, vrf); + + vty_out(vty, "exit-vrf\n!\n"); + } + + return 0; +} + static void bgp_vrf_init(void) { vrf_init(bgp_vrf_new, bgp_vrf_enable, bgp_vrf_disable, bgp_vrf_delete); + vrf_cmd_init(bgp_vrf_config_write); } static void bgp_vrf_terminate(void) @@ -357,15 +385,20 @@ static const struct frr_yang_module_info *const bgpd_yang_modules[] = { &frr_bgp_route_map_info, }; -FRR_DAEMON_INFO(bgpd, BGP, .vty_port = BGP_VTY_PORT, +/* clang-format off */ +FRR_DAEMON_INFO(bgpd, BGP, + .vty_port = BGP_VTY_PORT, + .proghelp = "Implementation of the BGP routing protocol.", - .proghelp = "Implementation of the BGP routing protocol.", + .signals = bgp_signals, + .n_signals = array_size(bgp_signals), - .signals = bgp_signals, .n_signals = array_size(bgp_signals), + .privs = &bgpd_privs, - .privs = &bgpd_privs, .yang_modules = bgpd_yang_modules, - .n_yang_modules = array_size(bgpd_yang_modules), + .yang_modules = bgpd_yang_modules, + .n_yang_modules = array_size(bgpd_yang_modules), ); +/* clang-format on */ #define DEPRECATED_OPTIONS "" diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index 5c3067f..0764f1e 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -15,6 +15,7 @@ DEFINE_MGROUP(BGPD, "bgpd"); DEFINE_MTYPE(BGPD, BGP, "BGP instance"); +DEFINE_MTYPE(BGPD, BGP_NAME, "BGP Name data"); DEFINE_MTYPE(BGPD, BGP_LISTENER, "BGP listen socket details"); DEFINE_MTYPE(BGPD, BGP_PEER, "BGP peer"); DEFINE_MTYPE(BGPD, BGP_PEER_CONNECTION, "BGP peer connection"); @@ -41,6 +42,7 @@ DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA, "BGP ancillary route info"); DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_EVPN, "BGP extra info for EVPN"); DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_FS, "BGP extra info for flowspec"); DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_VRFLEAK, "BGP extra info for vrf leaking"); +DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_VNC, "BGP extra info for vnc"); DEFINE_MTYPE(BGPD, BGP_CONN, "BGP connected"); DEFINE_MTYPE(BGPD, BGP_STATIC, "BGP static"); DEFINE_MTYPE(BGPD, BGP_ADVERTISE_ATTR, "BGP adv attr"); diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index 7acb41e..29584cd 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -11,6 +11,7 @@ DECLARE_MGROUP(BGPD); DECLARE_MTYPE(BGP); +DECLARE_MTYPE(BGP_NAME); DECLARE_MTYPE(BGP_LISTENER); DECLARE_MTYPE(BGP_PEER); DECLARE_MTYPE(BGP_PEER_CONNECTION); @@ -37,6 +38,7 @@ DECLARE_MTYPE(BGP_ROUTE_EXTRA); DECLARE_MTYPE(BGP_ROUTE_EXTRA_EVPN); DECLARE_MTYPE(BGP_ROUTE_EXTRA_FS); DECLARE_MTYPE(BGP_ROUTE_EXTRA_VRFLEAK); +DECLARE_MTYPE(BGP_ROUTE_EXTRA_VNC); DECLARE_MTYPE(BGP_CONN); DECLARE_MTYPE(BGP_STATIC); DECLARE_MTYPE(BGP_ADVERTISE_ATTR); diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index f2d1ee0..c773c21 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -554,12 +554,11 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, } if (debug) - zlog_debug( - "%pRN(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw %" PRIu64, - bgp_dest_to_rnode(dest), bgp->name_pretty, - new_best ? new_best->peer->host : "NONE", - mp_list ? listcount(mp_list) : 0, old_mpath_count, - old_cum_bw); + zlog_debug("%pBD(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw %" PRIu64, + dest, bgp->name_pretty, + new_best ? new_best->peer->host : "NONE", + mp_list ? listcount(mp_list) : 0, old_mpath_count, + old_cum_bw); /* * We perform an ordered walk through both lists in parallel. @@ -590,11 +589,10 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, tmp_info = mp_node ? listgetdata(mp_node) : NULL; if (debug) - zlog_debug( - "%pRN(%s): comparing candidate %s with existing mpath %s", - bgp_dest_to_rnode(dest), bgp->name_pretty, - tmp_info ? tmp_info->peer->host : "NONE", - cur_mpath ? cur_mpath->peer->host : "NONE"); + zlog_debug("%pBD(%s): comparing candidate %s with existing mpath %s", + dest, bgp->name_pretty, + tmp_info ? tmp_info->peer->host : "NONE", + cur_mpath ? cur_mpath->peer->host : "NONE"); /* * If equal, the path was a multipath and is still a multipath. @@ -622,10 +620,8 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, bgp_path_info_path_with_addpath_rx_str( cur_mpath, path_buf, sizeof(path_buf)); - zlog_debug( - "%pRN: %s is still multipath, cur count %d", - bgp_dest_to_rnode(dest), - path_buf, mpath_count); + zlog_debug("%pBD: %s is still multipath, cur count %d", + dest, path_buf, mpath_count); } } else { mpath_changed = 1; @@ -633,12 +629,10 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, bgp_path_info_path_with_addpath_rx_str( cur_mpath, path_buf, sizeof(path_buf)); - zlog_debug( - "%pRN: remove mpath %s nexthop %pI4, cur count %d", - bgp_dest_to_rnode(dest), - path_buf, - &cur_mpath->attr->nexthop, - mpath_count); + zlog_debug("%pBD: remove mpath %s nexthop %pI4, cur count %d", + dest, path_buf, + &cur_mpath->attr->nexthop, + mpath_count); } } mp_node = mp_next_node; @@ -663,10 +657,10 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, if (debug) { bgp_path_info_path_with_addpath_rx_str( cur_mpath, path_buf, sizeof(path_buf)); - zlog_debug( - "%pRN: remove mpath %s nexthop %pI4, cur count %d", - bgp_dest_to_rnode(dest), path_buf, - &cur_mpath->attr->nexthop, mpath_count); + zlog_debug("%pBD: remove mpath %s nexthop %pI4, cur count %d", + dest, path_buf, + &cur_mpath->attr->nexthop, + mpath_count); } cur_mpath = next_mpath; } else { @@ -713,12 +707,10 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, bgp_path_info_path_with_addpath_rx_str( new_mpath, path_buf, sizeof(path_buf)); - zlog_debug( - "%pRN: add mpath %s nexthop %pI4, cur count %d", - bgp_dest_to_rnode(dest), - path_buf, - &new_mpath->attr->nexthop, - mpath_count); + zlog_debug("%pBD: add mpath %s nexthop %pI4, cur count %d", + dest, path_buf, + &new_mpath->attr->nexthop, + mpath_count); } } mp_node = mp_next_node; @@ -737,11 +729,10 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, all_paths_lb, cum_bw); if (debug) - zlog_debug( - "%pRN(%s): New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw %" PRIu64, - bgp_dest_to_rnode(dest), bgp->name_pretty, - mpath_count, mpath_changed ? "YES" : "NO", - all_paths_lb, cum_bw); + zlog_debug("%pBD(%s): New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw %" PRIu64, + dest, bgp->name_pretty, mpath_count, + mpath_changed ? "YES" : "NO", all_paths_lb, + cum_bw); if (mpath_changed || (bgp_path_info_mpath_count(new_best) != old_mpath_count)) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 18d9f64..af8990a 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -300,7 +300,7 @@ void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi) return; } - if (vpn_leak_to_vpn_active(bgp, afi, NULL)) { + if (vpn_leak_to_vpn_active(bgp, afi, NULL, false)) { label = bgp->vpn_policy[afi].tovpn_label; } @@ -388,6 +388,9 @@ void vpn_leak_zebra_vrf_sid_update_per_af(struct bgp *bgp, afi_t afi) tovpn_sid_ls = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr)); *tovpn_sid_ls = *tovpn_sid; + if (bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent) + XFREE(MTYPE_BGP_SRV6_SID, + bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent); bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent = tovpn_sid_ls; } @@ -435,6 +438,8 @@ void vpn_leak_zebra_vrf_sid_update_per_vrf(struct bgp *bgp) tovpn_sid_ls = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr)); *tovpn_sid_ls = *tovpn_sid; + if (bgp->tovpn_zebra_vrf_sid_last_sent) + XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent); bgp->tovpn_zebra_vrf_sid_last_sent = tovpn_sid_ls; } @@ -482,6 +487,7 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi) bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC, NULL); XFREE(MTYPE_BGP_SRV6_SID, bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent); + bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent = NULL; } /* @@ -508,6 +514,7 @@ void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp) bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC, NULL); XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent); + bgp->tovpn_zebra_vrf_sid_last_sent = NULL; } /* @@ -596,6 +603,11 @@ static void sid_register(struct bgp *bgp, const struct in6_addr *sid, listnode_add(bgp->srv6_functions, func); } +void srv6_function_free(struct bgp_srv6_function *func) +{ + XFREE(MTYPE_BGP_SRV6_FUNCTION, func); +} + void sid_unregister(struct bgp *bgp, const struct in6_addr *sid) { struct listnode *node, *nnode; @@ -604,7 +616,7 @@ void sid_unregister(struct bgp *bgp, const struct in6_addr *sid) for (ALL_LIST_ELEMENTS(bgp->srv6_functions, node, nnode, func)) if (sid_same(&func->sid, sid)) { listnode_delete(bgp->srv6_functions, func); - XFREE(MTYPE_BGP_SRV6_FUNCTION, func); + srv6_function_free(func); } } @@ -1006,9 +1018,11 @@ static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn, { struct bgp_path_info *bpi_ultimate; struct bgp *bgp_nexthop; + struct bgp_table *table; bool nh_valid; bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi); + table = bgp_dest_table(bpi_ultimate->net); if (bpi->extra && bpi->extra->vrfleak && bpi->extra->vrfleak->bgp_orig) bgp_nexthop = bpi->extra->vrfleak->bgp_orig; @@ -1024,7 +1038,23 @@ static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn, is_pi_family_evpn(bpi_ultimate) || CHECK_FLAG(bpi_ultimate->flags, BGP_PATH_ACCEPT_OWN)) nh_valid = true; - else + else if (bpi_ultimate->type == ZEBRA_ROUTE_BGP && + bpi_ultimate->sub_type == BGP_ROUTE_STATIC && table && + (table->safi == SAFI_UNICAST || + table->safi == SAFI_LABELED_UNICAST)) { + /* the route is defined with the "network <prefix>" command */ + + if (CHECK_FLAG(bgp_nexthop->flags, BGP_FLAG_IMPORT_CHECK)) + nh_valid = bgp_find_or_add_nexthop(to_bgp, bgp_nexthop, + afi, SAFI_UNICAST, + bpi_ultimate, NULL, + 0, p); + else + /* if "no bgp network import-check" is set, + * then mark the nexthop as valid. + */ + nh_valid = true; + } else /* * TBD do we need to do anything about the * 'connected' parameter? @@ -1225,8 +1255,9 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, new->extra->vrfleak->parent = bgp_path_info_lock(parent); bgp_dest_lock_node( (struct bgp_dest *)parent->net); - if (bgp_orig) - new->extra->vrfleak->bgp_orig = bgp_lock(bgp_orig); + + new->extra->vrfleak->bgp_orig = bgp_lock(bgp_orig); + if (nexthop_orig) new->extra->vrfleak->nexthop_orig = *nexthop_orig; @@ -1532,6 +1563,9 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */ struct bgp_dest *bn; const char *debugmsg; int nexthop_self_flag = 0; + struct ecommunity *old_ecom; + struct ecommunity *new_ecom = NULL; + struct ecommunity *rtlist_ecom; if (debug) zlog_debug("%s: from vrf %s", __func__, from_bgp->name_pretty); @@ -1559,7 +1593,7 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */ if (!is_route_injectable_into_vpn(path_vrf)) return; - if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg)) { + if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg, false)) { if (debug) zlog_debug("%s: %s skipping: %s", __func__, from_bgp->name, debugmsg); @@ -1569,32 +1603,6 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */ /* shallow copy */ static_attr = *path_vrf->attr; - /* - * route map handling - */ - if (from_bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN]) { - struct bgp_path_info info; - route_map_result_t ret; - - memset(&info, 0, sizeof(info)); - info.peer = to_bgp->peer_self; - info.attr = &static_attr; - ret = route_map_apply(from_bgp->vpn_policy[afi] - .rmap[BGP_VPN_POLICY_DIR_TOVPN], - p, &info); - if (RMAP_DENYMATCH == ret) { - bgp_attr_flush(&static_attr); /* free any added parts */ - if (debug) - zlog_debug( - "%s: vrf %s route map \"%s\" says DENY, returning", - __func__, from_bgp->name_pretty, - from_bgp->vpn_policy[afi] - .rmap[BGP_VPN_POLICY_DIR_TOVPN] - ->name); - return; - } - } - if (debug && bgp_attr_get_ecommunity(&static_attr)) { char *s = ecommunity_ecom2str( bgp_attr_get_ecommunity(&static_attr), @@ -1608,29 +1616,62 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */ /* * Add the vpn-policy rt-list */ - struct ecommunity *old_ecom; - struct ecommunity *new_ecom; /* Export with the 'from' instance's export RTs. */ /* If doing VRF-to-VRF leaking, strip existing RTs first. */ old_ecom = bgp_attr_get_ecommunity(&static_attr); + rtlist_ecom = from_bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN]; if (old_ecom) { new_ecom = ecommunity_dup(old_ecom); if (CHECK_FLAG(from_bgp->af_flags[afi][SAFI_UNICAST], BGP_CONFIG_VRF_TO_VRF_EXPORT)) ecommunity_strip_rts(new_ecom); - new_ecom = ecommunity_merge( - new_ecom, from_bgp->vpn_policy[afi] - .rtlist[BGP_VPN_POLICY_DIR_TOVPN]); + if (rtlist_ecom) + new_ecom = ecommunity_merge(new_ecom, rtlist_ecom); if (!old_ecom->refcnt) ecommunity_free(&old_ecom); + } else if (rtlist_ecom) { + new_ecom = ecommunity_dup(rtlist_ecom); } else { - new_ecom = ecommunity_dup( - from_bgp->vpn_policy[afi] - .rtlist[BGP_VPN_POLICY_DIR_TOVPN]); + new_ecom = NULL; } + bgp_attr_set_ecommunity(&static_attr, new_ecom); + /* + * route map handling + */ + if (from_bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN]) { + struct bgp_path_info info; + route_map_result_t ret; + + memset(&info, 0, sizeof(info)); + info.peer = to_bgp->peer_self; + info.attr = &static_attr; + ret = route_map_apply(from_bgp->vpn_policy[afi] + .rmap[BGP_VPN_POLICY_DIR_TOVPN], + p, &info); + if (RMAP_DENYMATCH == ret) { + bgp_attr_flush(&static_attr); /* free any added parts */ + if (debug) + zlog_debug("%s: vrf %s route map \"%s\" says DENY, returning", + __func__, from_bgp->name_pretty, + from_bgp->vpn_policy[afi] + .rmap[BGP_VPN_POLICY_DIR_TOVPN] + ->name); + return; + } + } + + new_ecom = bgp_attr_get_ecommunity(&static_attr); + if (!ecommunity_has_route_target(new_ecom)) { + ecommunity_free(&new_ecom); + if (debug) + zlog_debug("%s: %s skipping: waiting for a valid export rt list.", + __func__, from_bgp->name_pretty); + return; + } + if (debug && bgp_attr_get_ecommunity(&static_attr)) { char *s = ecommunity_ecom2str( bgp_attr_get_ecommunity(&static_attr), @@ -1884,20 +1925,20 @@ void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp, /* to */ if (!is_route_injectable_into_vpn(path_vrf)) return; - if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg)) { + if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg, true)) { if (debug) zlog_debug("%s: skipping: %s", __func__, debugmsg); return; } - if (debug) - zlog_debug("%s: withdrawing (path_vrf=%p)", __func__, path_vrf); - - bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, - &(from_bgp->vpn_policy[afi].tovpn_rd)); + bn = bgp_safi_node_lookup(to_bgp->rib[afi][safi], safi, p, + &(from_bgp->vpn_policy[afi].tovpn_rd)); if (!bn) return; + if (debug) + zlog_debug("%s: withdrawing (path_vrf=%p)", __func__, path_vrf); + /* * vrf -> vpn * match original bpi imported from @@ -2056,6 +2097,7 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ uint32_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; @@ -2145,6 +2187,20 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ community_strip_accept_own(&static_attr); + bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL); + + for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { + if (bpi->extra && bpi->extra->vrfleak && + bpi->extra->vrfleak->parent == path_vpn) + break; + } + + if (bpi && leak_update_nexthop_valid(to_bgp, bn, &static_attr, afi, safi, + path_vpn, bpi, src_vrf, p, debug)) + SET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_VALID); + else + UNSET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_VALID); + /* * Nexthop: stash and clear * @@ -2160,12 +2216,22 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ /* If the path has accept-own community and the source VRF * is valid, reset next-hop to self, to allow importing own * routes between different VRFs on the same node. - * Set the nh ifindex to VRF's interface, not the real interface. + */ + + if (src_bgp) + subgroup_announce_reset_nhop(nhfamily, &static_attr); + + bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn); + + /* The nh ifindex may not be defined (when the route is + * imported from the network statement => BGP_ROUTE_STATIC) + * or to the real interface. + * Rewrite the nh ifindex to VRF's interface. * Let the kernel to decide with double lookup the real next-hop * interface when installing the route. */ - if (src_bgp) { - subgroup_announce_reset_nhop(nhfamily, &static_attr); + if (src_bgp || bpi_ultimate->sub_type == BGP_ROUTE_STATIC || + bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE) { ifp = if_get_vrf_loopback(src_vrf->vrf_id); if (ifp) static_attr.nh_ifindex = ifp->ifindex; @@ -2237,8 +2303,6 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ new_attr = bgp_attr_intern(&static_attr); bgp_attr_flush(&static_attr); - bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL); - /* * ensure labels are copied * @@ -2253,9 +2317,6 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ */ if (!CHECK_FLAG(to_bgp->af_flags[afi][safi], BGP_CONFIG_VRF_TO_VRF_IMPORT)) { - /* work back to original route */ - bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn); - /* * if original route was unicast, * then it did not arrive over vpn @@ -2665,7 +2726,7 @@ void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw, edir = BGP_VPN_POLICY_DIR_TOVPN; for (afi = 0; afi < AFI_MAX; ++afi) { - if (!vpn_leak_to_vpn_active(bgp, afi, NULL)) + if (!vpn_leak_to_vpn_active(bgp, afi, NULL, false)) continue; if (withdraw) { diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h index 19b6f4e..cd25899 100644 --- a/bgpd/bgp_mplsvpn.h +++ b/bgpd/bgp_mplsvpn.h @@ -13,6 +13,7 @@ #include "bgpd/bgp_rd.h" #include "bgpd/bgp_zebra.h" #include "bgpd/bgp_vty.h" +#include "bgpd/bgp_label.h" #define MPLS_LABEL_IS_SPECIAL(label) ((label) <= MPLS_LABEL_EXTENSION) #define MPLS_LABEL_IS_NULL(label) \ @@ -112,7 +113,8 @@ static inline bool is_bgp_vrf_mplsvpn(struct bgp *bgp) } static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi, - const char **pmsg) + const char **pmsg, + bool ignore_export_rt_list) { if (bgp_vrf->inst_type != BGP_INSTANCE_TYPE_VRF && bgp_vrf->inst_type != BGP_INSTANCE_TYPE_DEFAULT) { @@ -132,8 +134,21 @@ static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi, return 0; } - /* Is there an RT list set? */ - if (!bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN]) { + /* Before performing withdrawal, VPN activation is checked; however, + * when the route-map modifies the export route-target (RT) list, it + * becomes challenging to determine if VPN prefixes were previously + * present, or not. The 'ignore_export_rt_list' parameter will be + * used to force the withdraw operation by not checking the possible + * route-map changes. + * Of the 'ignore_export_rt_list' is set to false, check the following: + * - Is there an RT list set? + * - Is there a route-map that sets RT communities + */ + if (!ignore_export_rt_list && + !bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_TOVPN] && + (!bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN] || + !bgp_route_map_has_extcommunity_rt( + bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN]))) { if (pmsg) *pmsg = "rtlist tovpn not defined"; return 0; @@ -165,6 +180,25 @@ static inline int vpn_leak_to_vpn_active(struct bgp *bgp_vrf, afi_t afi, 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) && + bgp_vrf->vpn_policy[afi].tovpn_label != BGP_PREVENT_VRF_2_VRF_LEAK && + bgp_vrf->vpn_policy[afi].tovpn_label != MPLS_LABEL_NONE && + (bgp_vrf->vpn_policy[afi].tovpn_label >= MPLS_LABEL_UNRESERVED_MIN && + !CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG))) { + if (!bgp_zebra_request_label_range(bgp_vrf->vpn_policy[afi] + .tovpn_label, + 1, false)) { + if (pmsg) + *pmsg = "manual label could not be allocated"; + return 0; + } + SET_FLAG(bgp_vrf->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG); + } + return 1; } @@ -226,8 +260,7 @@ static inline void vpn_leak_prechange(enum vpn_policy_direction direction, vpn_leak_to_vrf_withdraw_all(bgp_vrf, afi); } if ((direction == BGP_VPN_POLICY_DIR_TOVPN) && - vpn_leak_to_vpn_active(bgp_vrf, afi, NULL)) { - + vpn_leak_to_vpn_active(bgp_vrf, afi, NULL, true)) { vpn_leak_from_vrf_withdraw_all(bgp_vpn, bgp_vrf, afi); } } diff --git a/bgpd/bgp_mplsvpn_snmp.c b/bgpd/bgp_mplsvpn_snmp.c index 0208a6f..3344e9e 100644 --- a/bgpd/bgp_mplsvpn_snmp.c +++ b/bgpd/bgp_mplsvpn_snmp.c @@ -511,8 +511,8 @@ static int bgp_init_snmp_stats(struct bgp *bgp) { if (is_bgp_vrf_mplsvpn(bgp)) { if (bgp->snmp_stats == NULL) { - bgp->snmp_stats = XCALLOC( - MTYPE_BGP, sizeof(struct bgp_snmp_stats)); + bgp->snmp_stats = XCALLOC(MTYPE_BGP_NAME, + sizeof(struct bgp_snmp_stats)); /* fix up added routes */ if (bgp->snmp_stats) { bgp->snmp_stats->routes_added = @@ -523,7 +523,7 @@ static int bgp_init_snmp_stats(struct bgp *bgp) } } else { if (bgp->snmp_stats) { - XFREE(MTYPE_BGP, bgp->snmp_stats); + XFREE(MTYPE_BGP_NAME, bgp->snmp_stats); bgp->snmp_stats = NULL; } } diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index d831c6a..dbb34b0 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -484,10 +484,23 @@ static void bgp_accept(struct event *thread) /* Dynamic neighbor has been created, let it proceed */ connection1->fd = bgp_sock; + if (bgp_set_socket_ttl(connection1) < 0) { + peer1->last_reset = PEER_DOWN_SOCKET_ERROR; + zlog_err("%s: Unable to set min/max TTL on peer %s (dynamic), error received: %s(%d)", + __func__, peer1->host, + safe_strerror(errno), errno); + return; + } + /* Set the user configured MSS to TCP socket */ if (CHECK_FLAG(peer1->flags, PEER_FLAG_TCP_MSS)) sockopt_tcp_mss_set(bgp_sock, peer1->tcp_mss); + frr_with_privs (&bgpd_privs) { + vrf_bind(peer1->bgp->vrf_id, bgp_sock, + bgp_get_bound_name(connection1)); + } + bgp_peer_reg_with_nht(peer1); bgp_fsm_change_status(connection1, Active); EVENT_OFF(connection1->t_start); @@ -693,7 +706,6 @@ int bgp_update_address(struct interface *ifp, const union sockunion *dst, { struct prefix *p, *sel, d; struct connected *connected; - struct listnode *node; int common; if (!sockunion2hostprefix(dst, &d)) @@ -702,7 +714,7 @@ int bgp_update_address(struct interface *ifp, const union sockunion *dst, sel = NULL; common = -1; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { + frr_each (if_connected, ifp->connected, connected) { p = connected->address; if (p->family != d.family) continue; diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 49cbbaf..8308838 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -26,6 +26,8 @@ PREDECL_RBTREE_UNIQ(bgp_nexthop_cache); /* BGP nexthop cache value structure. */ struct bgp_nexthop_cache { + afi_t afi; + /* The ifindex of the outgoing interface *if* it's a v6 LL */ ifindex_t ifindex_ipv6_ll; @@ -37,6 +39,18 @@ struct bgp_nexthop_cache { /* Nexthop number and nexthop linked list.*/ uint8_t nexthop_num; + + /* This flag is set to TRUE for a bnc that is gateway IP overlay index + * nexthop. + */ + bool is_evpn_gwip_nexthop; + + uint16_t change_flags; +#define BGP_NEXTHOP_CHANGED (1 << 0) +#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1) +#define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2) +#define BGP_NEXTHOP_MACIP_CHANGED (1 << 3) + struct nexthop *nexthop; time_t last_update; uint16_t flags; @@ -70,27 +84,16 @@ struct bgp_nexthop_cache { */ #define BGP_NEXTHOP_EVPN_INCOMPLETE (1 << 7) - uint16_t change_flags; - -#define BGP_NEXTHOP_CHANGED (1 << 0) -#define BGP_NEXTHOP_METRIC_CHANGED (1 << 1) -#define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2) -#define BGP_NEXTHOP_MACIP_CHANGED (1 << 3) + uint32_t srte_color; /* Back pointer to the cache tree this entry belongs to. */ struct bgp_nexthop_cache_head *tree; - uint32_t srte_color; struct prefix prefix; void *nht_info; /* In BGP, peer session */ LIST_HEAD(path_list, bgp_path_info) paths; unsigned int path_count; struct bgp *bgp; - - /* This flag is set to TRUE for a bnc that is gateway IP overlay index - * nexthop. - */ - bool is_evpn_gwip_nexthop; }; extern int bgp_nexthop_cache_compare(const struct bgp_nexthop_cache *a, diff --git a/bgpd/bgp_nhg.c b/bgpd/bgp_nhg.c new file mode 100644 index 0000000..bf0ba77 --- /dev/null +++ b/bgpd/bgp_nhg.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* BGP Nexthop Group Support + * Copyright (C) 2023 NVIDIA Corporation + * Copyright (C) 2023 6WIND + */ + +#include <zebra.h> + +#include <bgpd/bgpd.h> +#include <bgpd/bgp_debug.h> +#include <bgpd/bgp_nhg.h> + + +/**************************************************************************** + * L3 NHGs are used for fast failover of nexthops in the dplane. These are + * the APIs for allocating L3 NHG ids. Management of the L3 NHG itself is + * left to the application using it. + * PS: Currently EVPN host routes is the only app using L3 NHG for fast + * failover of remote ES links. + ***************************************************************************/ +static bitfield_t bgp_nh_id_bitmap; +static uint32_t bgp_nhg_start; + +/* XXX - currently we do nothing on the callbacks */ +static void bgp_nhg_add_cb(const char *name) +{ +} + +static void bgp_nhg_modify_cb(const struct nexthop_group_cmd *nhgc) +{ +} + +static void bgp_nhg_add_nexthop_cb(const struct nexthop_group_cmd *nhgc, + const struct nexthop *nhop) +{ +} + +static void bgp_nhg_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, + const struct nexthop *nhop) +{ +} + +static void bgp_nhg_del_cb(const char *name) +{ +} + +static void bgp_nhg_zebra_init(void) +{ + static bool bgp_nhg_zebra_inited; + + if (bgp_nhg_zebra_inited) + return; + + bgp_nhg_zebra_inited = true; + bgp_nhg_start = zclient_get_nhg_start(ZEBRA_ROUTE_BGP); + nexthop_group_init(bgp_nhg_add_cb, bgp_nhg_modify_cb, + bgp_nhg_add_nexthop_cb, bgp_nhg_del_nexthop_cb, + bgp_nhg_del_cb); +} + +void bgp_nhg_init(void) +{ + uint32_t id_max; + + id_max = MIN(ZEBRA_NHG_PROTO_SPACING - 1, 16 * 1024); + bf_init(bgp_nh_id_bitmap, id_max); + bf_assign_zero_index(bgp_nh_id_bitmap); + + if (BGP_DEBUG(nht, NHT) || BGP_DEBUG(evpn_mh, EVPN_MH_ES)) + zlog_debug("bgp nhg range %u - %u", bgp_nhg_start + 1, + bgp_nhg_start + id_max); +} + +void bgp_nhg_finish(void) +{ + bf_free(bgp_nh_id_bitmap); +} + +uint32_t bgp_nhg_id_alloc(void) +{ + uint32_t nhg_id = 0; + + bgp_nhg_zebra_init(); + bf_assign_index(bgp_nh_id_bitmap, nhg_id); + if (nhg_id) + nhg_id += bgp_nhg_start; + + return nhg_id; +} + +void bgp_nhg_id_free(uint32_t nhg_id) +{ + if (!nhg_id || (nhg_id <= bgp_nhg_start)) + return; + + nhg_id -= bgp_nhg_start; + + bf_release_index(bgp_nh_id_bitmap, nhg_id); +} diff --git a/bgpd/bgp_nhg.h b/bgpd/bgp_nhg.h new file mode 100644 index 0000000..370e8ab --- /dev/null +++ b/bgpd/bgp_nhg.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* BGP Nexthop Group Support + * Copyright (C) 2023 NVIDIA Corporation + * Copyright (C) 2023 6WIND + */ + +#ifndef _BGP_NHG_H +#define _BGP_NHG_H + +#include "nexthop_group.h" + +/* APIs for setting up and allocating L3 nexthop group ids */ +extern uint32_t bgp_nhg_id_alloc(void); +extern void bgp_nhg_id_free(uint32_t nhg_id); +extern void bgp_nhg_init(void); +void bgp_nhg_finish(void); + +#endif /* _BGP_NHG_H */ diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 60d6f74..e2c103b 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -386,6 +386,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, bnc = bnc_find(tree, &p, srte_color, ifindex); if (!bnc) { bnc = bnc_new(tree, &p, srte_color, ifindex); + bnc->afi = afi; bnc->bgp = bgp_nexthop; if (BGP_DEBUG(nht, NHT)) zlog_debug("Allocated bnc %pFX(%d)(%u)(%s) peer %p", @@ -405,7 +406,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, if (pi && is_route_parent_evpn(pi)) bnc->is_evpn_gwip_nexthop = true; - if (is_bgp_static_route) { + if (is_bgp_static_route && !CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE)) { SET_FLAG(bnc->flags, BGP_STATIC_ROUTE); /* If we're toggling the type, re-register */ @@ -897,52 +898,60 @@ void bgp_nht_interface_events(struct peer *peer) bnc->ifindex_ipv6_ll, NULL); } -void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) +void bgp_nexthop_update(struct vrf *vrf, struct prefix *match, + struct zapi_route *nhr) { struct bgp_nexthop_cache_head *tree = NULL; struct bgp_nexthop_cache *bnc_nhc, *bnc_import; - struct bgp *bgp; - struct prefix match; - struct zapi_route nhr; + struct bgp *bgp, *bgp_default; + struct bgp_path_info *pi; + struct bgp_dest *dest; + safi_t safi; afi_t afi; - bgp = bgp_lookup_by_vrf_id(vrf_id); - if (!bgp) { - flog_err( - EC_BGP_NH_UPD, - "parse nexthop update: instance not found for vrf_id %u", - vrf_id); - return; - } - - if (!zapi_nexthop_update_decode(zclient->ibuf, &match, &nhr)) { - zlog_err("%s[%s]: Failure to decode nexthop update", __func__, - bgp->name_pretty); + if (!vrf->info) { + flog_err(EC_BGP_NH_UPD, + "parse nexthop update: instance not found for vrf_id %u", + vrf->vrf_id); return; } - afi = family2afi(match.family); + bgp = (struct bgp *)vrf->info; + afi = family2afi(match->family); tree = &bgp->nexthop_cache_table[afi]; - bnc_nhc = bnc_find(tree, &match, nhr.srte_color, 0); - if (!bnc_nhc) { - if (BGP_DEBUG(nht, NHT)) - zlog_debug( - "parse nexthop update %pFX(%u)(%s): bnc info not found for nexthop cache", - &nhr.prefix, nhr.srte_color, bgp->name_pretty); - } else - bgp_process_nexthop_update(bnc_nhc, &nhr, false); + bnc_nhc = bnc_find(tree, match, nhr->srte_color, 0); + if (bnc_nhc) + bgp_process_nexthop_update(bnc_nhc, nhr, false); + else if (BGP_DEBUG(nht, NHT)) + zlog_debug("parse nexthop update %pFX(%u)(%s): bnc info not found for nexthop cache", + &nhr->prefix, nhr->srte_color, + bgp->name_pretty); tree = &bgp->import_check_table[afi]; - bnc_import = bnc_find(tree, &match, nhr.srte_color, 0); - if (!bnc_import) { - if (BGP_DEBUG(nht, NHT)) - zlog_debug( - "parse nexthop update %pFX(%u)(%s): bnc info not found for import check", - &nhr.prefix, nhr.srte_color, bgp->name_pretty); - } else - bgp_process_nexthop_update(bnc_import, &nhr, true); + bnc_import = bnc_find(tree, match, nhr->srte_color, 0); + if (bnc_import) { + bgp_process_nexthop_update(bnc_import, nhr, true); + + bgp_default = bgp_get_default(); + safi = nhr->safi; + if (bgp != bgp_default && bgp->rib[afi][safi]) { + dest = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, + match, NULL); + + for (pi = bgp_dest_get_bgp_path_info(dest); pi; + pi = pi->next) + if (pi->peer == bgp->peer_self && + pi->type == ZEBRA_ROUTE_BGP && + pi->sub_type == BGP_ROUTE_STATIC) + vpn_leak_from_vrf_update(bgp_default, + bgp, pi); + } + } else if (BGP_DEBUG(nht, NHT)) + zlog_debug("parse nexthop update %pFX(%u)(%s): bnc info not found for import check", + &nhr->prefix, nhr->srte_color, + bgp->name_pretty); /* * HACK: if any BGP route is dependant on an SR-policy that doesn't @@ -955,7 +964,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) * 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 && bnc_nhc) { struct bgp_nexthop_cache *bnc_iter; frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi], @@ -965,7 +974,7 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) CHECK_FLAG(bnc_iter->flags, BGP_NEXTHOP_VALID)) continue; - bgp_process_nexthop_update(bnc_iter, &nhr, false); + bgp_process_nexthop_update(bnc_iter, nhr, false); } } } @@ -1170,6 +1179,11 @@ static void register_zebra_rnh(struct bgp_nexthop_cache *bnc) */ static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc) { + struct bgp_nexthop_cache *import; + struct bgp_nexthop_cache *nexthop; + + struct bgp *bgp = bnc->bgp; + /* Check if we have already registered */ if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED)) return; @@ -1179,6 +1193,19 @@ static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc) return; } + import = bnc_find(&bgp->import_check_table[bnc->afi], &bnc->prefix, 0, + 0); + nexthop = bnc_find(&bgp->nexthop_cache_table[bnc->afi], &bnc->prefix, 0, + 0); + + /* + * If this entry has both a import and a nexthop entry + * then let's not send the unregister quite as of yet + * wait until we only have 1 left + */ + if (import && nexthop) + return; + sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_UNREGISTER); } @@ -1558,90 +1585,3 @@ void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer) 0); } } - -/**************************************************************************** - * L3 NHGs are used for fast failover of nexthops in the dplane. These are - * the APIs for allocating L3 NHG ids. Management of the L3 NHG itself is - * left to the application using it. - * PS: Currently EVPN host routes is the only app using L3 NHG for fast - * failover of remote ES links. - ***************************************************************************/ -static bitfield_t bgp_nh_id_bitmap; -static uint32_t bgp_l3nhg_start; - -/* XXX - currently we do nothing on the callbacks */ -static void bgp_l3nhg_add_cb(const char *name) -{ -} - -static void bgp_l3nhg_modify_cb(const struct nexthop_group_cmd *nhgc) -{ -} - -static void bgp_l3nhg_add_nexthop_cb(const struct nexthop_group_cmd *nhgc, - const struct nexthop *nhop) -{ -} - -static void bgp_l3nhg_del_nexthop_cb(const struct nexthop_group_cmd *nhgc, - const struct nexthop *nhop) -{ -} - -static void bgp_l3nhg_del_cb(const char *name) -{ -} - -static void bgp_l3nhg_zebra_init(void) -{ - static bool bgp_l3nhg_zebra_inited; - if (bgp_l3nhg_zebra_inited) - return; - - bgp_l3nhg_zebra_inited = true; - bgp_l3nhg_start = zclient_get_nhg_start(ZEBRA_ROUTE_BGP); - nexthop_group_init(bgp_l3nhg_add_cb, bgp_l3nhg_modify_cb, - bgp_l3nhg_add_nexthop_cb, bgp_l3nhg_del_nexthop_cb, - bgp_l3nhg_del_cb); -} - - -void bgp_l3nhg_init(void) -{ - uint32_t id_max; - - id_max = MIN(ZEBRA_NHG_PROTO_SPACING - 1, 16 * 1024); - bf_init(bgp_nh_id_bitmap, id_max); - bf_assign_zero_index(bgp_nh_id_bitmap); - - if (BGP_DEBUG(nht, NHT) || BGP_DEBUG(evpn_mh, EVPN_MH_ES)) - zlog_debug("bgp l3_nhg range %u - %u", bgp_l3nhg_start + 1, - bgp_l3nhg_start + id_max); -} - -void bgp_l3nhg_finish(void) -{ - bf_free(bgp_nh_id_bitmap); -} - -uint32_t bgp_l3nhg_id_alloc(void) -{ - uint32_t nhg_id = 0; - - bgp_l3nhg_zebra_init(); - bf_assign_index(bgp_nh_id_bitmap, nhg_id); - if (nhg_id) - nhg_id += bgp_l3nhg_start; - - return nhg_id; -} - -void bgp_l3nhg_id_free(uint32_t nhg_id) -{ - if (!nhg_id || (nhg_id <= bgp_l3nhg_start)) - return; - - nhg_id -= bgp_l3nhg_start; - - bf_release_index(bgp_nh_id_bitmap, nhg_id); -} diff --git a/bgpd/bgp_nht.h b/bgpd/bgp_nht.h index 0758a0c..e7c6fdc 100644 --- a/bgpd/bgp_nht.h +++ b/bgpd/bgp_nht.h @@ -7,9 +7,10 @@ #define _BGP_NHT_H /** - * bgp_parse_nexthop_update() - parse a nexthop update message from Zebra. + * bgp_nexthop_update() - process a nexthop update message from Zebra. */ -extern void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id); +extern void bgp_nexthop_update(struct vrf *vrf, struct prefix *match, + struct zapi_route *nhr); /** * bgp_find_or_add_nexthop() - lookup the nexthop cache table for the bnc @@ -78,12 +79,6 @@ extern void bgp_nht_reg_enhe_cap_intfs(struct peer *peer); extern void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer); extern void evaluate_paths(struct bgp_nexthop_cache *bnc); -/* APIs for setting up and allocating L3 nexthop group ids */ -extern uint32_t bgp_l3nhg_id_alloc(void); -extern void bgp_l3nhg_id_free(uint32_t nhg_id); -extern void bgp_l3nhg_init(void); -void bgp_l3nhg_finish(void); - extern void bgp_nht_ifp_up(struct interface *ifp); extern void bgp_nht_ifp_down(struct interface *ifp); diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index b030c45..6447586 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -340,15 +340,14 @@ static void bgp_capability_orf_not_support(struct peer *peer, iana_afi_t afi, peer->host, afi, safi, type, mode); } -static const struct message orf_type_str[] = { - {ORF_TYPE_RESERVED, "Reserved"}, - {ORF_TYPE_PREFIX, "Prefixlist"}, - {0}}; +const struct message orf_type_str[] = { { ORF_TYPE_RESERVED, "Reserved" }, + { ORF_TYPE_PREFIX, "Prefixlist" }, + { 0 } }; -static const struct message orf_mode_str[] = {{ORF_MODE_RECEIVE, "Receive"}, - {ORF_MODE_SEND, "Send"}, - {ORF_MODE_BOTH, "Both"}, - {0}}; +const struct message orf_mode_str[] = { { ORF_MODE_RECEIVE, "Receive" }, + { ORF_MODE_SEND, "Send" }, + { ORF_MODE_BOTH, "Both" }, + { 0 } }; static int bgp_capability_orf_entry(struct peer *peer, struct capability_header *hdr) @@ -623,17 +622,17 @@ static int bgp_capability_llgr(struct peer *peer, /* Unlike other capability parsing routines, this one returns 0 on error */ static as_t bgp_capability_as4(struct peer *peer, struct capability_header *hdr) { - SET_FLAG(peer->cap, PEER_CAP_AS4_RCV); - if (hdr->length != CAPABILITY_CODE_AS4_LEN) { flog_err(EC_BGP_PKT_OPEN, "%s AS4 capability has incorrect data length %d", peer->host, hdr->length); - return 0; + return -1; } as_t as4 = stream_getl(BGP_INPUT(peer)); + SET_FLAG(peer->cap, PEER_CAP_AS4_RCV); + if (BGP_DEBUG(as4, AS4)) zlog_debug( "%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u", @@ -663,10 +662,8 @@ static int bgp_capability_addpath(struct peer *peer, struct stream *s = BGP_INPUT(peer); size_t end = stream_get_getp(s) + hdr->length; - SET_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV); - /* Verify length is a multiple of 4 */ - if (hdr->length % 4) { + if (hdr->length % CAPABILITY_CODE_ADDPATH_LEN) { flog_warn( EC_BGP_CAPABILITY_INVALID_LENGTH, "Add Path: Received invalid length %d, non-multiple of 4", @@ -674,23 +671,38 @@ static int bgp_capability_addpath(struct peer *peer, return -1; } - while (stream_get_getp(s) + 4 <= end) { + SET_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV); + + while (stream_get_getp(s) + CAPABILITY_CODE_ADDPATH_LEN <= end) { afi_t afi; safi_t safi; iana_afi_t pkt_afi = stream_getw(s); iana_safi_t pkt_safi = stream_getc(s); uint8_t send_receive = stream_getc(s); + /* If any other value (other than 1-3) is received, then + * the capability SHOULD be treated as not understood + * and ignored. + */ + if (!send_receive || send_receive > 3) { + flog_warn(EC_BGP_CAPABILITY_INVALID_DATA, + "Add Path: Received invalid send/receive value %u in Add Path capability", + send_receive); + continue; + } + if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s OPEN has %s capability for afi/safi: %s/%s%s%s", - peer->host, - lookup_msg(capcode_str, hdr->code, NULL), - iana_afi2str(pkt_afi), iana_safi2str(pkt_safi), - (send_receive & BGP_ADDPATH_RX) ? ", receive" - : "", - (send_receive & BGP_ADDPATH_TX) ? ", transmit" - : ""); + zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s%s%s", + peer->host, + lookup_msg(capcode_str, hdr->code, NULL), + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi), + CHECK_FLAG(send_receive, BGP_ADDPATH_RX) + ? ", receive" + : "", + CHECK_FLAG(send_receive, BGP_ADDPATH_TX) + ? ", transmit" + : ""); /* Convert AFI, SAFI to internal values, check. */ if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) { @@ -709,13 +721,19 @@ static int bgp_capability_addpath(struct peer *peer, continue; } - if (send_receive & BGP_ADDPATH_RX) + if (CHECK_FLAG(send_receive, BGP_ADDPATH_RX)) SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_RCV); + else + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_RCV); - if (send_receive & BGP_ADDPATH_TX) + if (CHECK_FLAG(send_receive, BGP_ADDPATH_TX)) SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_RCV); + else + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_RCV); } return 0; @@ -800,8 +818,6 @@ static int bgp_capability_hostname(struct peer *peer, size_t end = stream_get_getp(s) + hdr->length; uint8_t len; - SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_RCV); - len = stream_getc(s); if (stream_get_getp(s) + len > end) { flog_warn( @@ -859,6 +875,8 @@ static int bgp_capability_hostname(struct peer *peer, peer->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, str); } + SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_RCV); + if (bgp_debug_neighbor_events(peer)) { zlog_debug("%s received hostname %s, domainname %s", peer->host, peer->hostname, peer->domainname); @@ -869,14 +887,16 @@ static int bgp_capability_hostname(struct peer *peer, static int bgp_capability_role(struct peer *peer, struct capability_header *hdr) { - SET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); if (hdr->length != CAPABILITY_CODE_ROLE_LEN) { flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, "Role: Received invalid length %d", hdr->length); return -1; } + uint8_t role = stream_getc(BGP_INPUT(peer)); + SET_FLAG(peer->cap, PEER_CAP_ROLE_RCV); + peer->remote_role = role; return 0; } @@ -1020,6 +1040,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length, BGP_NOTIFY_OPEN_MALFORMED_ATTR); return -1; } + break; /* we deliberately ignore unknown codes, see below */ default: break; @@ -1876,8 +1897,9 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer, stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN); } - /* Hostname capability */ - if (cmd_hostname_get()) { + /* FQDN capability */ + if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_FQDN) + && cmd_hostname_get()) { SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); rcapp = stream_get_endp(s); /* Ptr to length placeholder */ @@ -1929,8 +1951,7 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer, * or disable its use, and that switch MUST be off by default. */ if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_SOFT_VERSION) || - CHECK_FLAG(peer->bgp->flags, BGP_FLAG_SOFT_VERSION_CAPABILITY) || - peer->sort == BGP_PEER_IBGP) { + peer->sort == BGP_PEER_IBGP || peer->sub_sort == BGP_PEER_EBGP_OAD) { SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); rcapp = stream_get_endp(s); diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index a92c56d..34f4b76 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -108,5 +108,7 @@ extern void bgp_capability_vty_out(struct vty *vty, struct peer *peer, bool use_json, json_object *json_neigh); 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[]; #endif /* _QUAGGA_BGP_OPEN_H */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index cae82cb..1f808ee 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -24,6 +24,7 @@ #include "lib_errors.h" #include "bgpd/bgpd.h" +#include "bgpd/bgp_addpath.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_dump.h" #include "bgpd/bgp_bmp.h" @@ -1211,8 +1212,14 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, unsigned long cap_len; uint16_t len; uint32_t gr_restart_time; + uint8_t addpath_afi_safi_count = 0; + bool adv_addpath_tx = false; + unsigned long number_of_orfs_p; + uint8_t number_of_orfs = 0; const char *capability = lookup_msg(capcode_str, capability_code, "Unknown"); + const char *hostname = cmd_hostname_get(); + const char *domainname = cmd_domainname_get(); if (!peer_established(peer->connection)) return; @@ -1232,7 +1239,6 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, /* Encode MP_EXT capability. */ switch (capability_code) { case CAPABILITY_CODE_SOFT_VERSION: - SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_ADV); stream_putc(s, action); stream_putc(s, CAPABILITY_CODE_SOFT_VERSION); cap_len = stream_get_endp(s); @@ -1263,6 +1269,9 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, : "Removing", capability, iana_afi2str(pkt_afi), iana_safi2str(pkt_safi)); + + COND_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_ADV, + action == CAPABILITY_ACTION_SET); break; case CAPABILITY_CODE_MP: stream_putc(s, action); @@ -1282,11 +1291,6 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, iana_safi2str(pkt_safi)); break; case CAPABILITY_CODE_RESTART: - if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) && - !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) - return; - - SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV); stream_putc(s, action); stream_putc(s, CAPABILITY_CODE_RESTART); cap_len = stream_get_endp(s); @@ -1335,13 +1339,10 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, capability, iana_afi2str(pkt_afi), iana_safi2str(pkt_safi)); + COND_FLAG(peer->cap, PEER_CAP_RESTART_ADV, + action == CAPABILITY_ACTION_SET); break; case CAPABILITY_CODE_LLGR: - if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV)) - return; - - SET_FLAG(peer->cap, PEER_CAP_LLGR_ADV); - stream_putc(s, action); stream_putc(s, CAPABILITY_CODE_LLGR); cap_len = stream_get_endp(s); @@ -1373,25 +1374,214 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, : "Removing", capability, iana_afi2str(pkt_afi), iana_safi2str(pkt_safi)); + + COND_FLAG(peer->cap, PEER_CAP_LLGR_ADV, + action == CAPABILITY_ACTION_SET); + break; + case CAPABILITY_CODE_ADDPATH: + FOREACH_AFI_SAFI (afi, safi) { + if (peer->afc[afi][safi]) { + addpath_afi_safi_count++; + + /* Only advertise addpath TX if a feature that + * will use it is + * configured */ + if (peer->addpath_type[afi][safi] != + BGP_ADDPATH_NONE) + adv_addpath_tx = true; + + /* If we have enabled labeled unicast, we MUST check + * against unicast SAFI because addpath IDs are + * allocated under unicast SAFI, the same as the RIB + * is managed in unicast SAFI. + */ + if (safi == SAFI_LABELED_UNICAST) + if (peer->addpath_type[afi][SAFI_UNICAST] != + BGP_ADDPATH_NONE) + adv_addpath_tx = true; + } + } + + stream_putc(s, action); + stream_putc(s, CAPABILITY_CODE_ADDPATH); + stream_putc(s, CAPABILITY_CODE_ADDPATH_LEN * + addpath_afi_safi_count); + + FOREACH_AFI_SAFI (afi, safi) { + if (peer->afc[afi][safi]) { + bool adv_addpath_rx = + !CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_DISABLE_ADDPATH_RX); + uint8_t flags = 0; + + /* Convert AFI, SAFI to values for packet. */ + bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, + &pkt_safi); + + stream_putw(s, pkt_afi); + stream_putc(s, pkt_safi); + + if (adv_addpath_rx) { + SET_FLAG(flags, BGP_ADDPATH_RX); + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_ADV); + } else { + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_ADV); + } + + if (adv_addpath_tx) { + SET_FLAG(flags, BGP_ADDPATH_TX); + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_ADV); + if (safi == SAFI_LABELED_UNICAST) + SET_FLAG(peer->af_cap[afi] + [SAFI_UNICAST], + PEER_CAP_ADDPATH_AF_TX_ADV); + } else { + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_ADV); + } + + stream_putc(s, flags); + } + } + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s", + peer, + action == CAPABILITY_ACTION_SET + ? "Advertising" + : "Removing", + capability, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + + COND_FLAG(peer->cap, PEER_CAP_ADDPATH_ADV, + action == CAPABILITY_ACTION_SET); break; - case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_ORF: + /* Convert AFI, SAFI to values for packet. */ + bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); + + stream_putc(s, action); + stream_putc(s, CAPABILITY_CODE_ORF); + cap_len = stream_get_endp(s); + stream_putc(s, 0); + + stream_putw(s, pkt_afi); /* Address Family Identifier */ + stream_putc(s, 0); /* Reserved */ + stream_putc(s, + pkt_safi); /* Subsequent Address Family Identifier */ + + number_of_orfs_p = + stream_get_endp(s); /* Number of ORFs pointer */ + stream_putc(s, 0); /* Number of ORFs */ + + /* Address Prefix ORF */ + if (CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_ORF_PREFIX_SM) || + CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_ORF_PREFIX_RM)) { + stream_putc(s, ORF_TYPE_PREFIX); + + if (CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_ORF_PREFIX_SM) && + CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_ORF_PREFIX_RM)) { + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_SM_ADV); + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_RM_ADV); + stream_putc(s, ORF_MODE_BOTH); + } else if (CHECK_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_ORF_PREFIX_SM)) { + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_SM_ADV); + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_RM_ADV); + stream_putc(s, ORF_MODE_SEND); + } else { + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_RM_ADV); + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_SM_ADV); + stream_putc(s, ORF_MODE_RECEIVE); + } + number_of_orfs++; + } else { + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_SM_ADV); + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ORF_PREFIX_RM_ADV); + } + + /* Total Number of ORFs. */ + stream_putc_at(s, number_of_orfs_p, number_of_orfs); + + len = stream_get_endp(s) - cap_len - 1; + stream_putc_at(s, cap_len, len); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s", + peer, + action == CAPABILITY_ACTION_SET + ? "Advertising" + : "Removing", + capability, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + break; + case CAPABILITY_CODE_FQDN: + stream_putc(s, action); + stream_putc(s, CAPABILITY_CODE_FQDN); + cap_len = stream_get_endp(s); + stream_putc(s, 0); /* Capability Length */ + + len = strlen(hostname); + if (len > BGP_MAX_HOSTNAME) + len = BGP_MAX_HOSTNAME; + + stream_putc(s, len); + stream_put(s, hostname, len); + + if (domainname) { + len = strlen(domainname); + if (len > BGP_MAX_HOSTNAME) + len = BGP_MAX_HOSTNAME; + + stream_putc(s, len); + stream_put(s, domainname, len); + } else + stream_putc(s, 0); + + len = stream_get_endp(s) - cap_len - 1; + stream_putc_at(s, cap_len, len); + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s", + peer, + action == CAPABILITY_ACTION_SET + ? "Advertising" + : "Removing", + capability, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + + COND_FLAG(peer->cap, PEER_CAP_HOSTNAME_ADV, + action == CAPABILITY_ACTION_SET); + break; + case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_AS4: case CAPABILITY_CODE_DYNAMIC: - case CAPABILITY_CODE_ADDPATH: case CAPABILITY_CODE_ENHANCED_RR: - case CAPABILITY_CODE_FQDN: case CAPABILITY_CODE_ENHE: case CAPABILITY_CODE_EXT_MESSAGE: break; case CAPABILITY_CODE_ROLE: - if (peer->local_role != ROLE_UNDEFINED) { - SET_FLAG(peer->cap, PEER_CAP_ROLE_ADV); - stream_putc(s, action); - stream_putc(s, CAPABILITY_CODE_ROLE); - stream_putc(s, CAPABILITY_CODE_ROLE_LEN); - stream_putc(s, peer->local_role); - } + stream_putc(s, action); + stream_putc(s, CAPABILITY_CODE_ROLE); + stream_putc(s, CAPABILITY_CODE_ROLE_LEN); + stream_putc(s, peer->local_role); + COND_FLAG(peer->cap, PEER_CAP_ROLE_ADV, + action == CAPABILITY_ACTION_SET); break; default: break; @@ -2155,7 +2345,8 @@ static int bgp_update_receive(struct peer_connection *connection, "%pBP rcvd UPDATE with errors in attr(s)!! Withdrawing route.", peer); - if (ret && bgp_debug_update(peer, NULL, NULL, 1)) { + if (ret && bgp_debug_update(peer, NULL, NULL, 1) && + BGP_DEBUG(update, UPDATE_DETAIL)) { zlog_debug("%pBP rcvd UPDATE w/ attr: %s", peer, peer->rcvd_attr_str); peer->rcvd_attr_printed = 1; @@ -2190,7 +2381,7 @@ static int bgp_update_receive(struct peer_connection *connection, } } - if (BGP_DEBUG(update, UPDATE_IN)) + if (BGP_DEBUG(update, UPDATE_IN) && BGP_DEBUG(update, UPDATE_DETAIL)) zlog_debug("%pBP rcvd UPDATE wlen %d attrlen %d alen %d", peer, withdraw_len, attribute_len, update_len); @@ -2872,6 +3063,304 @@ static int bgp_route_refresh_receive(struct peer_connection *connection, return BGP_PACKET_NOOP; } +static void bgp_dynamic_capability_addpath(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_ADDPATH_LEN) { + flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, + "Add Path: Received invalid length %zu, non-multiple of 4", + len); + return; + } + + SET_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV); + + while (data + CAPABILITY_CODE_ADDPATH_LEN <= end) { + afi_t afi; + safi_t safi; + iana_afi_t pkt_afi; + iana_safi_t pkt_safi; + struct bgp_addpath_capability bac; + + memcpy(&bac, data, sizeof(bac)); + pkt_afi = ntohs(bac.afi); + pkt_safi = safi_int2iana(bac.safi); + + /* If any other value (other than 1-3) is received, + * then the capability SHOULD be treated as not + * understood and ignored. + */ + if (!bac.flags || bac.flags > 3) { + flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, + "Add Path: Received invalid send/receive value %u in Add Path capability", + bac.flags); + goto ignore; + } + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s%s%s", + peer->host, + lookup_msg(capcode_str, hdr->code, + NULL), + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi), + (bac.flags & BGP_ADDPATH_RX) + ? ", receive" + : "", + (bac.flags & BGP_ADDPATH_TX) + ? ", transmit" + : ""); + + 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 Addpath Attribute 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 AddPath capability for this AFI/SAFI", + peer->host, + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + goto ignore; + } + + if (CHECK_FLAG(bac.flags, BGP_ADDPATH_RX)) + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_RCV); + else + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_RCV); + + if (CHECK_FLAG(bac.flags, BGP_ADDPATH_TX)) + SET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_RCV); + else + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_RCV); + +ignore: + data += CAPABILITY_CODE_ADDPATH_LEN; + } + } else { + FOREACH_AFI_SAFI (afi, safi) { + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_RCV); + UNSET_FLAG(peer->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_RCV); + } + + UNSET_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV); + } +} + +static void bgp_dynamic_capability_orf(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; + + struct capability_mp_data mpc; + uint8_t num; + iana_afi_t pkt_afi; + afi_t afi; + iana_safi_t pkt_safi; + safi_t safi; + uint8_t type; + uint8_t mode; + uint16_t sm_cap = PEER_CAP_ORF_PREFIX_SM_RCV; + uint16_t rm_cap = PEER_CAP_ORF_PREFIX_RM_RCV; + int i; + + if (data + CAPABILITY_CODE_ORF_LEN > end) { + flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH, + "ORF: Received invalid length %zu, less than %d", len, + CAPABILITY_CODE_ORF_LEN); + return; + } + + /* ORF Entry header */ + memcpy(&mpc, data, sizeof(mpc)); + data += sizeof(mpc); + num = *data++; + pkt_afi = ntohs(mpc.afi); + pkt_safi = mpc.safi; + + /* Convert AFI, SAFI to internal values, check. */ + if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) { + zlog_info("%pBP Addr-family %d/%d not supported. Ignoring the ORF capability", + peer, pkt_afi, pkt_safi); + return; + } + + /* validate number field */ + if (CAPABILITY_CODE_ORF_LEN + (num * 2) > hdr->length) { + zlog_info("%pBP ORF Capability entry length error, Cap length %u, num %u", + peer, hdr->length, num); + return; + } + + if (action == CAPABILITY_ACTION_UNSET) { + UNSET_FLAG(peer->af_cap[afi][safi], sm_cap); + UNSET_FLAG(peer->af_cap[afi][safi], rm_cap); + return; + } + + for (i = 0; i < num; i++) { + if (data + 1 > end) { + flog_err(EC_BGP_CAPABILITY_INVALID_LENGTH, + "%pBP ORF Capability entry length (type) error, Cap length %u, num %u", + peer, hdr->length, num); + return; + } + type = *data++; + + if (data + 1 > end) { + flog_err(EC_BGP_CAPABILITY_INVALID_LENGTH, + "%pBP ORF Capability entry length (mode) error, Cap length %u, num %u", + peer, hdr->length, num); + return; + } + mode = *data++; + + /* ORF Mode error check */ + switch (mode) { + case ORF_MODE_BOTH: + case ORF_MODE_SEND: + case ORF_MODE_RECEIVE: + break; + default: + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP Addr-family %d/%d has ORF type/mode %d/%d not supported", + peer, afi, safi, type, mode); + continue; + } + + if (!((afi == AFI_IP && safi == SAFI_UNICAST) || + (afi == AFI_IP && safi == SAFI_MULTICAST) || + (afi == AFI_IP6 && safi == SAFI_UNICAST))) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP Addr-family %d/%d unsupported AFI/SAFI received", + peer, afi, safi); + continue; + } + + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP OPEN has %s ORF capability as %s for afi/safi: %s/%s", + peer, lookup_msg(orf_type_str, type, NULL), + lookup_msg(orf_mode_str, mode, NULL), + iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + + switch (mode) { + case ORF_MODE_BOTH: + SET_FLAG(peer->af_cap[afi][safi], sm_cap); + SET_FLAG(peer->af_cap[afi][safi], rm_cap); + break; + case ORF_MODE_SEND: + SET_FLAG(peer->af_cap[afi][safi], sm_cap); + UNSET_FLAG(peer->af_cap[afi][safi], rm_cap); + break; + case ORF_MODE_RECEIVE: + SET_FLAG(peer->af_cap[afi][safi], rm_cap); + UNSET_FLAG(peer->af_cap[afi][safi], sm_cap); + break; + } + } +} + +static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action, + struct capability_header *hdr, + struct peer *peer) +{ + uint8_t *data = pnt + 3; + uint8_t *end = data + hdr->length; + char str[BGP_MAX_HOSTNAME + 1] = {}; + uint8_t len; + + if (action == CAPABILITY_ACTION_SET) { + /* hostname */ + if (data + 1 > end) { + zlog_err("%pBP: Received invalid FQDN capability (host name length)", + peer); + return; + } + + len = *data; + if (data + len > end) { + zlog_err("%pBP: Received invalid FQDN capability length (host name) %d", + peer, hdr->length); + return; + } + data++; + + if (len > BGP_MAX_HOSTNAME) { + memcpy(&str, data, BGP_MAX_HOSTNAME); + str[BGP_MAX_HOSTNAME] = '\0'; + } else if (len) { + memcpy(&str, data, len); + str[len] = '\0'; + } + data += len; + + if (len) { + XFREE(MTYPE_BGP_PEER_HOST, peer->hostname); + XFREE(MTYPE_BGP_PEER_HOST, peer->domainname); + + peer->hostname = XSTRDUP(MTYPE_BGP_PEER_HOST, str); + } + + if (data + 1 > end) { + zlog_err("%pBP: Received invalid FQDN capability (domain name length)", + peer); + return; + } + + /* domainname */ + len = *data; + if (data + len > end) { + zlog_err("%pBP: Received invalid FQDN capability length (domain name) %d", + peer, len); + return; + } + data++; + + if (len > BGP_MAX_HOSTNAME) { + memcpy(&str, data, BGP_MAX_HOSTNAME); + str[BGP_MAX_HOSTNAME] = '\0'; + } else if (len) { + memcpy(&str, data, len); + str[len] = '\0'; + } + /* data += len; In case new code is ever added */ + + if (len) { + XFREE(MTYPE_BGP_PEER_HOST, peer->domainname); + + peer->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, str); + } + + SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_RCV); + } else { + UNSET_FLAG(peer->cap, PEER_CAP_HOSTNAME_RCV); + XFREE(MTYPE_BGP_PEER_HOST, peer->hostname); + XFREE(MTYPE_BGP_PEER_HOST, peer->domainname); + } +} + static void bgp_dynamic_capability_llgr(uint8_t *pnt, int action, struct capability_header *hdr, struct peer *peer) @@ -3121,6 +3610,7 @@ 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; return BGP_Stop; } action = *pnt; @@ -3133,7 +3623,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, action); bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); - return BGP_Stop; + goto done; } if (bgp_debug_neighbor_events(peer)) @@ -3145,12 +3635,13 @@ 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; return BGP_Stop; } /* Ignore capability when override-capability is set. */ if (CHECK_FLAG(peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) - continue; + goto done; capability = lookup_msg(capcode_str, hdr->code, "Unknown"); @@ -3165,7 +3656,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, peer, capability, sizeof(struct capability_mp_data), hdr->length); - return BGP_Stop; + goto done; } memcpy(&mpc, pnt + 3, sizeof(struct capability_mp_data)); @@ -3180,7 +3671,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, peer, capability, iana_afi2str(pkt_afi), iana_safi2str(pkt_safi)); - continue; + goto done; } /* Address family check. */ @@ -3207,7 +3698,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, if (peer_active_nego(peer)) bgp_clear_route(peer, afi, safi); else - return BGP_Stop; + goto done; } break; case CAPABILITY_CODE_RESTART: @@ -3217,7 +3708,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); - return BGP_Stop; + goto done; } bgp_dynamic_capability_graceful_restart(pnt, action, @@ -3226,13 +3717,19 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, case CAPABILITY_CODE_LLGR: bgp_dynamic_capability_llgr(pnt, action, hdr, peer); break; - case CAPABILITY_CODE_REFRESH: + case CAPABILITY_CODE_ADDPATH: + bgp_dynamic_capability_addpath(pnt, action, hdr, peer); + break; case CAPABILITY_CODE_ORF: + bgp_dynamic_capability_orf(pnt, action, hdr, peer); + break; + case CAPABILITY_CODE_FQDN: + bgp_dynamic_capability_fqdn(pnt, action, hdr, peer); + break; + case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_AS4: case CAPABILITY_CODE_DYNAMIC: - case CAPABILITY_CODE_ADDPATH: case CAPABILITY_CODE_ENHANCED_RR: - case CAPABILITY_CODE_FQDN: case CAPABILITY_CODE_ENHE: case CAPABILITY_CODE_EXT_MESSAGE: break; @@ -3243,7 +3740,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_SUBCODE_UNSPECIFIC); - return BGP_Stop; + goto done; } uint8_t role; @@ -3265,6 +3762,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt, break; } +done: pnt += hdr->length + 3; } diff --git a/bgpd/bgp_pbr.h b/bgpd/bgp_pbr.h index ed143d9..cb16c4d 100644 --- a/bgpd/bgp_pbr.h +++ b/bgpd/bgp_pbr.h @@ -134,7 +134,7 @@ struct bgp_pbr_entry_main { struct bgp_pbr_interface { RB_ENTRY(bgp_pbr_interface) id_entry; - char name[INTERFACE_NAMSIZ]; + char name[IFNAMSIZ]; }; RB_HEAD(bgp_pbr_interface_head, bgp_pbr_interface); diff --git a/bgpd/bgp_rd.h b/bgpd/bgp_rd.h index e38c2fa..93dda17 100644 --- a/bgpd/bgp_rd.h +++ b/bgpd/bgp_rd.h @@ -41,8 +41,8 @@ struct rd_as { struct rd_ip { uint16_t type; - struct in_addr ip; uint16_t val; + struct in_addr ip; }; #ifdef ENABLE_BGP_VNC diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 3a850a4..38983e2 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -28,6 +28,8 @@ #include "lib/json.h" #include "lib_errors.h" #include "zclient.h" +#include "frrdistance.h" + #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgpd/bgp_route.h" @@ -85,6 +87,11 @@ DEFINE_HOOK(bgp_rpki_prefix_status, const struct prefix *prefix), (peer, attr, prefix)); +DEFINE_HOOK(bgp_route_update, + (struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_dest *bn, + struct bgp_path_info *old_route, struct bgp_path_info *new_route), + (bgp, afi, safi, bn, old_route, new_route)); + /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; extern const char *bgp_origin_long_str[]; @@ -113,7 +120,7 @@ DEFINE_HOOK(bgp_process, (bgp, afi, safi, bn, peer, withdraw)); /** Test if path is suppressed. */ -static bool bgp_path_suppressed(struct bgp_path_info *pi) +bool bgp_path_suppressed(struct bgp_path_info *pi) { if (pi->extra == NULL || pi->extra->aggr_suppressors == NULL) return false; @@ -256,6 +263,10 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra) XFREE(MTYPE_BGP_ROUTE_EXTRA_FS, e->flowspec); if (e->vrfleak) XFREE(MTYPE_BGP_ROUTE_EXTRA_VRFLEAK, e->vrfleak); +#ifdef ENABLE_BGP_VNC + if (e->vnc) + XFREE(MTYPE_BGP_ROUTE_EXTRA_VNC, e->vnc); +#endif XFREE(MTYPE_BGP_ROUTE_EXTRA, *extra); } @@ -606,6 +617,8 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, struct attr *newattr, *existattr; enum bgp_peer_sort new_sort; enum bgp_peer_sort exist_sort; + enum bgp_peer_sub_sort new_sub_sort; + enum bgp_peer_sub_sort exist_sub_sort; uint32_t new_pref; uint32_t exist_pref; uint32_t new_med; @@ -1140,26 +1153,34 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, /* 7. Peer type check. */ new_sort = peer_new->sort; exist_sort = peer_exist->sort; + new_sub_sort = peer_new->sub_sort; + exist_sub_sort = peer_exist->sub_sort; - if (new_sort == BGP_PEER_EBGP - && (exist_sort == BGP_PEER_IBGP || exist_sort == BGP_PEER_CONFED)) { + if (new_sort == BGP_PEER_EBGP && + (exist_sort == BGP_PEER_IBGP || exist_sort == BGP_PEER_CONFED || + exist_sub_sort == BGP_PEER_EBGP_OAD)) { *reason = bgp_path_selection_peer; if (debug) - zlog_debug( - "%s: %s wins over %s due to eBGP peer > iBGP peer", - pfx_buf, new_buf, exist_buf); + zlog_debug("%s: %s wins over %s due to eBGP peer > %s peer", + pfx_buf, new_buf, exist_buf, + (exist_sub_sort == BGP_PEER_EBGP_OAD) + ? "eBGP-OAD" + : "iBGP"); if (!CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX)) return 1; peer_sort_ret = 1; } - if (exist_sort == BGP_PEER_EBGP - && (new_sort == BGP_PEER_IBGP || new_sort == BGP_PEER_CONFED)) { + if (exist_sort == BGP_PEER_EBGP && + (new_sort == BGP_PEER_IBGP || new_sort == BGP_PEER_CONFED || + new_sub_sort == BGP_PEER_EBGP_OAD)) { *reason = bgp_path_selection_peer; if (debug) - zlog_debug( - "%s: %s loses to %s due to iBGP peer < eBGP peer", - pfx_buf, new_buf, exist_buf); + zlog_debug("%s: %s loses to %s due to %s peer < eBGP peer", + pfx_buf, new_buf, exist_buf, + (exist_sub_sort == BGP_PEER_EBGP_OAD) + ? "eBGP-OAD" + : "iBGP"); if (!CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX)) return 0; peer_sort_ret = 0; @@ -2162,9 +2183,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, * configured for default-originate */ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) { - if (p->family == AF_INET && p->u.prefix4.s_addr == INADDR_ANY) - return false; - else if (p->family == AF_INET6 && p->prefixlen == 0) + if ((p->family == AF_INET || p->family == AF_INET6) && p->prefixlen == 0) return false; } @@ -2299,8 +2318,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, /* Remove MED if its an EBGP peer - will get overwritten by route-maps */ - if (peer->sort == BGP_PEER_EBGP - && attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) { + if (peer->sort == BGP_PEER_EBGP && peer->sub_sort != BGP_PEER_EBGP_OAD && + attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) { if (from != bgp->peer_self && !transparent && !CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED)) @@ -2514,8 +2533,9 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, return false; if (bgp_in_graceful_shutdown(bgp)) { - if (peer->sort == BGP_PEER_IBGP - || peer->sort == BGP_PEER_CONFED) { + if (peer->sort == BGP_PEER_IBGP || + peer->sort == BGP_PEER_CONFED || + peer->sub_sort == BGP_PEER_EBGP_OAD) { attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF); attr->local_pref = BGP_GSHUT_LOCAL_PREF; } else { @@ -2645,17 +2665,25 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, /* If this is an iBGP, send Origin Validation State (OVS) * extended community (rfc8097). + * draft-uttaro-idr-bgp-oad states: + * For example, the Origin Validation State Extended Community, + * defined as non-transitive in [RFC8097], can be advertised to + * peers in the same OAD. */ - if (peer->sort == BGP_PEER_IBGP) { + if ((peer->sort == BGP_PEER_IBGP || + peer->sub_sort == BGP_PEER_EBGP_OAD) && + peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_SEND_EXT_COMMUNITY_RPKI)) { enum rpki_states rpki_state = RPKI_NOT_BEING_USED; rpki_state = hook_call(bgp_rpki_prefix_status, peer, attr, p); if (rpki_state != RPKI_NOT_BEING_USED) - bgp_attr_set_ecommunity( - attr, ecommunity_add_origin_validation_state( - rpki_state, - bgp_attr_get_ecommunity(attr))); + bgp_attr_set_ecommunity(attr, + ecommunity_add_origin_validation_state( + rpki_state, + bgp_attr_get_ecommunity( + attr))); } /* @@ -2816,18 +2844,18 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, /* reap REMOVED routes, if needs be * selected route must stay for a while longer though */ - if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED) && - (pi != old_select)) { - dest = bgp_path_info_reap(dest, pi); - assert(dest); - } - if (debug) zlog_debug( "%s: %pBD(%s) pi from %s in holddown", __func__, dest, bgp->name_pretty, pi->peer->host); + if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED) && + (pi != old_select)) { + dest = bgp_path_info_reap(dest, pi); + assert(dest); + } + continue; } @@ -2958,7 +2986,7 @@ void subgroup_process_announce_selected(struct update_subgroup *subgrp, { const struct prefix *p; struct peer *onlypeer; - struct attr attr; + struct attr attr = { 0 }, *pattr = &attr; struct bgp *bgp; bool advertise; @@ -2986,26 +3014,30 @@ void subgroup_process_announce_selected(struct update_subgroup *subgrp, advertise = bgp_check_advertise(bgp, dest, safi); if (selected) { - if (subgroup_announce_check(dest, selected, subgrp, p, &attr, + if (subgroup_announce_check(dest, selected, subgrp, p, pattr, NULL)) { /* Route is selected, if the route is already installed * in FIB, then it is advertised */ if (advertise) { if (!bgp_check_withdrawal(bgp, dest, safi)) { - struct attr *adv_attr = - bgp_attr_intern(&attr); - - bgp_adj_out_set_subgroup(dest, subgrp, - adv_attr, - selected); - } else + if (!bgp_adj_out_set_subgroup(dest, + subgrp, + pattr, + selected)) + bgp_attr_flush(pattr); + } else { bgp_adj_out_unset_subgroup( dest, subgrp, 1, addpath_tx_id); - } - } else + bgp_attr_flush(pattr); + } + } else + bgp_attr_flush(pattr); + } else { bgp_adj_out_unset_subgroup(dest, subgrp, 1, addpath_tx_id); + bgp_attr_flush(pattr); + } } /* If selected is NULL we must withdraw the path using addpath_tx_id */ @@ -3434,6 +3466,7 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, &bgp->t_rmap_def_originate_eval); } + /* TODO BMP insert rib update hook */ if (old_select) bgp_path_info_unset_flag(dest, old_select, BGP_PATH_SELECTED); if (new_select) { @@ -3446,6 +3479,15 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, UNSET_FLAG(new_select->flags, BGP_PATH_LINK_BW_CHG); } + /* call bmp hook for loc-rib route update / withdraw after flags were + * set + */ + if (old_select || new_select) { + hook_call(bgp_route_update, bgp, afi, safi, dest, old_select, + new_select); + } + + #ifdef ENABLE_BGP_VNC if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) { if (old_select != new_select) { @@ -3463,14 +3505,6 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, } #endif - group_announce_route(bgp, afi, safi, dest, new_select); - - /* unicast routes must also be annouced to labeled-unicast update-groups - */ - if (safi == SAFI_UNICAST) - group_announce_route(bgp, afi, SAFI_LABELED_UNICAST, dest, - new_select); - /* FIB update. */ if (bgp_fibupd_safi(safi) && (bgp->inst_type != BGP_INSTANCE_TYPE_VIEW) && !bgp_option_check(BGP_OPT_NO_FIB)) { @@ -3486,7 +3520,8 @@ 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, safi); + bgp_zebra_withdraw(p, old_select, bgp, afi, + safi); bgp_zebra_announce(dest, p, new_select, bgp, afi, safi); } else { @@ -3496,10 +3531,20 @@ 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, safi); + bgp_zebra_withdraw(p, old_select, bgp, afi, + safi); } } + group_announce_route(bgp, afi, safi, dest, new_select); + + /* unicast routes must also be annouced to labeled-unicast update-groups + */ + if (safi == SAFI_UNICAST) + group_announce_route(bgp, afi, SAFI_LABELED_UNICAST, dest, + new_select); + + bgp_process_evpn_route_injection(bgp, afi, safi, dest, new_select, old_select); @@ -4151,7 +4196,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, int aspath_loop_count = 0; struct bgp_dest *dest; struct bgp *bgp; - struct attr new_attr; + struct attr new_attr = {}; struct attr *attr_new; struct bgp_path_info *pi; struct bgp_path_info *new = NULL; @@ -4184,10 +4229,6 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, if (orig_safi == SAFI_LABELED_UNICAST) safi = SAFI_UNICAST; - memset(&new_attr, 0, sizeof(new_attr)); - new_attr.label_index = BGP_INVALID_LABEL_INDEX; - new_attr.label = MPLS_INVALID_LABEL; - 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" */ @@ -4397,7 +4438,7 @@ 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, safi); + bgp_zebra_withdraw(p, pi, bgp, afi, safi); } if (peer->sort == BGP_PEER_EBGP) { @@ -4490,12 +4531,12 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, hook_call(bgp_process, bgp, afi, safi, dest, peer, true); /* Same attribute comes in. */ - if (!CHECK_FLAG(pi->flags, BGP_PATH_REMOVED) - && same_attr - && (!has_valid_label - || memcmp(&(bgp_path_info_extra_get(pi))->label, label, - num_labels * sizeof(mpls_label_t)) - == 0)) { + 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 @@ -4680,7 +4721,9 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, /* Update MPLS label */ if (has_valid_label) { extra = bgp_path_info_extra_get(pi); - if (extra->label != label) { + 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; @@ -4761,9 +4804,10 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, BGP_PATH_VALID); } else { if (BGP_DEBUG(nht, NHT)) { - zlog_debug("%s(%pI4): NH unresolved", + zlog_debug("%s(%pI4): NH unresolved for existing %pFX pi %p flags 0x%x", __func__, - (in_addr_t *)&attr_new->nexthop); + (in_addr_t *)&attr_new->nexthop, + p, pi, pi->flags); } bgp_path_info_unset_flag(dest, pi, BGP_PATH_VALID); @@ -4808,10 +4852,23 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, * updating * the attributes for the route in the VNI(s). */ - if (safi == SAFI_EVPN && - (!same_attr || force_evpn_import) && - CHECK_FLAG(pi->flags, BGP_PATH_VALID)) - bgp_evpn_import_route(bgp, afi, safi, p, pi); + if (safi == SAFI_EVPN) { + if ((!same_attr || force_evpn_import) && + CHECK_FLAG(pi->flags, BGP_PATH_VALID)) + bgp_evpn_import_route(bgp, afi, safi, p, pi); + + /* If existing path is marked invalid then unimport the + * path from EVPN prefix. This will ensure EVPN route + * has only valid paths and path refcount maintained in + * EVPN nexthop is decremented appropriately. + */ + else if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID)) { + if (BGP_DEBUG(nht, NHT)) + zlog_debug("%s unimport EVPN %pFX as pi %p is not VALID", + __func__, p, pi); + bgp_evpn_unimport_route(bgp, afi, safi, p, pi); + } + } /* Process change. */ bgp_aggregate_increment(bgp, p, pi, afi, safi); @@ -4865,7 +4922,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, /* Update MPLS label */ if (has_valid_label) { extra = bgp_path_info_extra_get(new); - if (extra->label != label) { + 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; @@ -5146,7 +5204,7 @@ void bgp_withdraw(struct peer *peer, const struct prefix *p, } void bgp_default_originate(struct peer *peer, afi_t afi, safi_t safi, - int withdraw) + bool withdraw) { struct update_subgroup *subgrp; subgrp = peer_subgroup(peer, afi, safi); @@ -5960,10 +6018,10 @@ bool bgp_outbound_policy_exists(struct peer *peer, struct bgp_filter *filter) if (peer->sort == BGP_PEER_IBGP) return true; - if (peer->sort == BGP_PEER_EBGP - && (ROUTE_MAP_OUT_NAME(filter) || PREFIX_LIST_OUT_NAME(filter) - || FILTER_LIST_OUT_NAME(filter) - || DISTRIBUTE_OUT_NAME(filter))) + if (peer->sort == BGP_PEER_EBGP && + (ROUTE_MAP_OUT_NAME(filter) || PREFIX_LIST_OUT_NAME(filter) || + FILTER_LIST_OUT_NAME(filter) || DISTRIBUTE_OUT_NAME(filter) || + UNSUPPRESS_MAP_NAME(filter))) return true; return false; } @@ -5982,7 +6040,7 @@ bool bgp_inbound_policy_exists(struct peer *peer, struct bgp_filter *filter) } static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table, - safi_t safi) + afi_t afi, safi_t safi) { struct bgp_dest *dest; struct bgp_path_info *pi; @@ -6006,7 +6064,8 @@ 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, safi); + bgp_zebra_withdraw(p, pi, bgp, afi, + safi); } dest = bgp_path_info_reap(dest, pi); @@ -6024,7 +6083,7 @@ void bgp_cleanup_routes(struct bgp *bgp) for (afi = AFI_IP; afi < AFI_MAX; ++afi) { if (afi == AFI_L2VPN) continue; - bgp_cleanup_table(bgp, bgp->rib[afi][SAFI_UNICAST], + bgp_cleanup_table(bgp, bgp->rib[afi][SAFI_UNICAST], afi, SAFI_UNICAST); /* * VPN and ENCAP and EVPN tables are two-level (RD is top level) @@ -6036,7 +6095,7 @@ void bgp_cleanup_routes(struct bgp *bgp) dest = bgp_route_next(dest)) { table = bgp_dest_get_bgp_table_info(dest); if (table != NULL) { - bgp_cleanup_table(bgp, table, safi); + bgp_cleanup_table(bgp, table, afi, safi); bgp_table_finish(&table); bgp_dest_set_bgp_table_info(dest, NULL); dest = bgp_dest_unlock_node(dest); @@ -6049,7 +6108,7 @@ void bgp_cleanup_routes(struct bgp *bgp) dest = bgp_route_next(dest)) { table = bgp_dest_get_bgp_table_info(dest); if (table != NULL) { - bgp_cleanup_table(bgp, table, safi); + bgp_cleanup_table(bgp, table, afi, safi); bgp_table_finish(&table); bgp_dest_set_bgp_table_info(dest, NULL); dest = bgp_dest_unlock_node(dest); @@ -6063,7 +6122,7 @@ void bgp_cleanup_routes(struct bgp *bgp) dest = bgp_route_next(dest)) { table = bgp_dest_get_bgp_table_info(dest); if (table != NULL) { - bgp_cleanup_table(bgp, table, SAFI_EVPN); + bgp_cleanup_table(bgp, table, afi, SAFI_EVPN); bgp_table_finish(&table); bgp_dest_set_bgp_table_info(dest, NULL); dest = bgp_dest_unlock_node(dest); @@ -6239,13 +6298,14 @@ static void bgp_nexthop_reachability_check(afi_t afi, safi_t safi, struct bgp_path_info *bpi, const struct prefix *p, struct bgp_dest *dest, - struct bgp *bgp) + struct bgp *bgp, + struct bgp *bgp_nexthop) { /* Nexthop reachability check. */ if (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST) { if (CHECK_FLAG(bgp->flags, BGP_FLAG_IMPORT_CHECK)) { - if (bgp_find_or_add_nexthop(bgp, bgp, afi, safi, bpi, - NULL, 0, p)) + if (bgp_find_or_add_nexthop(bgp, bgp_nexthop, afi, safi, + bpi, NULL, 0, p)) bgp_path_info_set_flag(dest, bpi, BGP_PATH_VALID); else { @@ -6283,7 +6343,7 @@ static void bgp_static_free(struct bgp_static *bgp_static) route_map_counter_decrement(bgp_static->rmap.map); if (bgp_static->prd_pretty) - XFREE(MTYPE_BGP, bgp_static->prd_pretty); + XFREE(MTYPE_BGP_NAME, bgp_static->prd_pretty); XFREE(MTYPE_ATTR, bgp_static->eth_s_id); XFREE(MTYPE_BGP_STATIC, bgp_static); } @@ -6303,6 +6363,7 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, mpls_label_t label = 0; #endif uint32_t num_labels = 0; + struct bgp *bgp_nexthop = bgp; assert(bgp_static); @@ -6457,9 +6518,11 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, &pi->extra->label[0]); } #endif + if (pi->extra && pi->extra->vrfleak->bgp_orig) + bgp_nexthop = pi->extra->vrfleak->bgp_orig; bgp_nexthop_reachability_check(afi, safi, pi, p, dest, - bgp); + bgp, bgp_nexthop); /* Process change. */ bgp_aggregate_increment(bgp, p, pi, afi, safi); @@ -6509,7 +6572,7 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p, #endif } - bgp_nexthop_reachability_check(afi, safi, new, p, dest, bgp); + bgp_nexthop_reachability_check(afi, safi, new, p, dest, bgp, bgp); /* Aggregate address increment. */ bgp_aggregate_increment(bgp, p, new, afi, safi); @@ -7322,8 +7385,9 @@ static void bgp_aggregate_install( * If the aggregate information has not changed * no need to re-install it again. */ - if (pi && bgp_aggregate_info_same(pi, origin, aspath, community, - ecommunity, lcommunity)) { + if (pi && (!aggregate->rmap.changed && + bgp_aggregate_info_same(pi, origin, aspath, community, + ecommunity, lcommunity))) { bgp_dest_unlock_node(dest); if (aspath) @@ -7577,7 +7641,6 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, */ aggregate->count = 0; aggregate->incomplete_origin_count = 0; - aggregate->incomplete_origin_count = 0; aggregate->egp_origin_count = 0; /* ORIGIN attribute: If at least one route among routes that are @@ -7752,6 +7815,9 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, lcommunity = lcommunity_dup(aggregate->lcommunity); } + /* Unimport suppressed routes from EVPN */ + bgp_aggr_supp_withdraw_from_evpn(bgp, afi, safi); + bgp_aggregate_install(bgp, afi, safi, p, origin, aspath, community, ecommunity, lcommunity, atomic_aggregate, aggregate); @@ -8331,6 +8397,7 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, aggregate->rmap.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); aggregate->rmap.map = route_map_lookup_by_name(rmap); + aggregate->rmap.changed = true; route_map_counter_increment(aggregate->rmap.map); } @@ -9465,14 +9532,12 @@ void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest, const struct prefix *p, struct attr *attr, safi_t safi, bool use_json, json_object *json_ar, bool wide) { - json_object *json_status = NULL; json_object *json_net = NULL; int len; char buff[BUFSIZ]; /* Route status display. */ if (use_json) { - json_status = json_object_new_object(); json_net = json_object_new_object(); } else { vty_out(vty, " *"); @@ -9539,11 +9604,6 @@ void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest, attr->aspath->str); /* Print origin */ -#if CONFDATE > 20231208 -CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs") -#endif - json_object_string_add(json_net, "bgpOriginCode", - bgp_origin_str[attr->origin]); json_object_string_add( json_net, "origin", bgp_origin_long_str[attr->origin]); @@ -9599,20 +9659,11 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs") if (use_json) { struct bgp_path_info *bpi = bgp_dest_get_bgp_path_info(dest); -#if CONFDATE > 20231208 -CPP_NOTICE("Drop `bgpStatusCodes` from JSON outputs") -#endif - json_object_boolean_true_add(json_status, "*"); - json_object_boolean_true_add(json_status, ">"); json_object_boolean_true_add(json_net, "valid"); json_object_boolean_true_add(json_net, "best"); - if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_MULTIPATH)) { - json_object_boolean_true_add(json_status, "="); + if (bpi && CHECK_FLAG(bpi->flags, BGP_PATH_MULTIPATH)) json_object_boolean_true_add(json_net, "multipath"); - } - json_object_object_add(json_net, "appliedStatusSymbols", - json_status); json_object_object_addf(json_ar, json_net, "%pFX", p); } else vty_out(vty, "\n"); @@ -10661,9 +10712,17 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } else { if (json_paths) json_object_string_add( - json_peer, "type", "external"); + json_peer, "type", + (path->peer->sub_sort == + BGP_PEER_EBGP_OAD) + ? "external (oad)" + : "external"); else - vty_out(vty, ", external"); + vty_out(vty, ", %s", + (path->peer->sub_sort == + BGP_PEER_EBGP_OAD) + ? "external (oad)" + : "external"); } } } else if (path->sub_type == BGP_ROUTE_AGGREGATE) { @@ -11599,7 +11658,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa total_count); } else vty_out(vty, - "\nDisplayed %ld routes and %ld total paths\n", + "\nDisplayed %ld routes and %ld total paths\n", output_count, total_count); } } @@ -11650,7 +11709,7 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, total_cum); else vty_out(vty, - "\nDisplayed %ld routes and %ld total paths\n", + "\nDisplayed %ld routes and %ld total paths\n", output_cum, total_cum); } else { if (use_json && output_cum == 0 && json_header_depth == 0) @@ -13925,9 +13984,7 @@ DEFUN (show_bgp_l2vpn_evpn_route_prefix, static void show_adj_route_header(struct vty *vty, struct peer *peer, struct bgp_table *table, int *header1, - int *header2, json_object *json, - json_object *json_scode, - json_object *json_ocode, bool wide, + int *header2, json_object *json, bool wide, bool detail) { uint64_t version = table ? table->version : 0; @@ -13943,10 +14000,6 @@ static void show_adj_route_header(struct vty *vty, struct peer *peer, peer->change_local_as ? peer->change_local_as : peer->local_as); - json_object_object_add(json, "bgpStatusCodes", - json_scode); - json_object_object_add(json, "bgpOriginCodes", - json_ocode); } else { vty_out(vty, "BGP table version is %" PRIu64 @@ -13983,7 +14036,6 @@ static void show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, afi_t afi, safi_t safi, enum bgp_show_adj_route_type type, const char *rmap_name, json_object *json, json_object *json_ar, - json_object *json_scode, json_object *json_ocode, uint16_t show_flags, int *header1, int *header2, char *rd_str, const struct prefix *match, unsigned long *output_count, unsigned long *filtered_count) @@ -14078,8 +14130,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, if (ret != RMAP_DENY) { show_adj_route_header(vty, peer, table, header1, - header2, json, json_scode, - json_ocode, wide, detail); + header2, json, wide, detail); if (use_json) json_net = json_object_new_object(); @@ -14116,10 +14167,6 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, peer->change_local_as ? peer->change_local_as : peer->local_as); - json_object_object_add(json, "bgpStatusCodes", - json_scode); - json_object_object_add(json, "bgpOriginCodes", - json_ocode); json_object_string_add( json, "bgpOriginatingDefaultNetwork", (afi == AFI_IP) ? "0.0.0.0/0" : "::/0"); @@ -14159,8 +14206,8 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, if (ain->peer != peer) continue; show_adj_route_header(vty, peer, table, header1, - header2, json, json_scode, - json_ocode, wide, detail); + header2, json, wide, + detail); if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_ENCAP) @@ -14244,10 +14291,10 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, if (paf->peer != peer || !adj->attr) continue; - show_adj_route_header( - vty, peer, table, header1, - header2, json, json_scode, - json_ocode, wide, detail); + show_adj_route_header(vty, peer, table, + header1, header2, + json, wide, + detail); const struct prefix *rn_p = bgp_dest_get_prefix(dest); @@ -14311,8 +14358,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, struct bgp_path_info *pi; show_adj_route_header(vty, peer, table, header1, - header2, json, json_scode, - json_ocode, wide, detail); + header2, json, wide, detail); const struct prefix *rn_p = bgp_dest_get_prefix(dest); @@ -14355,8 +14401,6 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, struct bgp *bgp; struct bgp_table *table; json_object *json = NULL; - json_object *json_scode = NULL; - json_object *json_ocode = NULL; json_object *json_ar = NULL; bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); @@ -14385,28 +14429,6 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, if (use_json) { json = json_object_new_object(); json_ar = json_object_new_object(); - json_scode = json_object_new_object(); - json_ocode = json_object_new_object(); -#if CONFDATE > 20231208 -CPP_NOTICE("Drop `bgpStatusCodes` from JSON outputs") -#endif - json_object_string_add(json_scode, "suppressed", "s"); - json_object_string_add(json_scode, "damped", "d"); - json_object_string_add(json_scode, "history", "h"); - json_object_string_add(json_scode, "valid", "*"); - json_object_string_add(json_scode, "best", ">"); - json_object_string_add(json_scode, "multipath", "="); - json_object_string_add(json_scode, "internal", "i"); - json_object_string_add(json_scode, "ribFailure", "r"); - json_object_string_add(json_scode, "stale", "S"); - json_object_string_add(json_scode, "removed", "R"); - -#if CONFDATE > 20231208 -CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs") -#endif - json_object_string_add(json_ocode, "igp", "i"); - json_object_string_add(json_ocode, "egp", "e"); - json_object_string_add(json_ocode, "incomplete", "?"); } if (!peer || !peer->afc[afi][safi]) { @@ -14417,8 +14439,6 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs") vty_out(vty, "%s\n", json_object_to_json_string(json)); json_object_free(json); json_object_free(json_ar); - json_object_free(json_scode); - json_object_free(json_ocode); } else vty_out(vty, "%% No such neighbor or address family\n"); @@ -14436,8 +14456,6 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs") vty_out(vty, "%s\n", json_object_to_json_string(json)); json_object_free(json); json_object_free(json_ar); - json_object_free(json_scode); - json_object_free(json_ocode); } else vty_out(vty, "%% Inbound soft reconfiguration not enabled\n"); @@ -14477,11 +14495,11 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs") prefix_rd2str(prd, rd_str, sizeof(rd_str), bgp->asnotation); - show_adj_route( - vty, peer, table, afi, safi, type, rmap_name, - json, json_routes, json_scode, json_ocode, - show_flags, &header1, &header2, rd_str, match, - &output_count_per_rd, &filtered_count_per_rd); + show_adj_route(vty, peer, table, afi, safi, type, + rmap_name, json, json_routes, show_flags, + &header1, &header2, rd_str, match, + &output_count_per_rd, + &filtered_count_per_rd); /* Don't include an empty RD in the output! */ if (json_routes && (output_count_per_rd > 0)) @@ -14493,9 +14511,8 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs") } } else show_adj_route(vty, peer, table, afi, safi, type, rmap_name, - json, json_ar, json_scode, json_ocode, - show_flags, &header1, &header2, rd_str, match, - &output_count, &filtered_count); + json, json_ar, show_flags, &header1, &header2, + rd_str, match, &output_count, &filtered_count); if (use_json) { if (type == bgp_show_adj_route_advertised) @@ -14507,16 +14524,6 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs") json_object_int_add(json, "filteredPrefixCounter", filtered_count); - /* - * These fields only give up ownership to `json` when `header1` - * is used (set to zero). See code in `show_adj_route` and - * `show_adj_route_header`. - */ - if (header1 == 1) { - json_object_free(json_scode); - json_object_free(json_ocode); - } - /* * This is an extremely expensive operation at scale * and non-pretty reduces memory footprint significantly. diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index e9f48ea..2d82f0f 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -193,30 +193,9 @@ struct bgp_path_info_extra_vrfleak { struct prefix nexthop_orig; }; -/* Ancillary information to struct bgp_path_info, - * used for uncommonly used data (aggregation, MPLS, etc.) - * and lazily allocated to save memory. - */ -struct bgp_path_info_extra { - /* Pointer to dampening structure. */ - struct bgp_damp_info *damp_info; - - /** List of aggregations that suppress this path. */ - struct list *aggr_suppressors; - - /* Nexthop reachability check. */ - uint32_t igpmetric; - - /* MPLS label(s) - VNI(s) for EVPN-VxLAN */ - mpls_label_t label[BGP_MAX_LABELS]; - uint32_t num_labels; - - /*For EVPN*/ - struct bgp_path_info_extra_evpn *evpn; - #ifdef ENABLE_BGP_VNC +struct bgp_path_info_extra_vnc { union { - struct { void *rfapi_handle; /* export: NVE advertising this route */ @@ -239,8 +218,36 @@ struct bgp_path_info_extra { struct prefix aux_prefix; /* AFI_L2VPN: the IP addr, if family set */ } import; - } vnc; +}; +#endif + +/* Ancillary information to struct bgp_path_info, + * used for uncommonly used data (aggregation, MPLS, etc.) + * and lazily allocated to save memory. + */ +struct bgp_path_info_extra { + /* Pointer to dampening structure. */ + struct bgp_damp_info *damp_info; + + /** List of aggregations that suppress this path. */ + struct list *aggr_suppressors; + + /* Nexthop reachability check. */ + uint32_t igpmetric; + + /* MPLS label(s) - VNI(s) for EVPN-VxLAN */ + mpls_label_t label[BGP_MAX_LABELS]; + uint32_t num_labels; + + /* timestamp of the rib installation */ + time_t bgp_rib_uptime; + + /*For EVPN*/ + struct bgp_path_info_extra_evpn *evpn; + +#ifdef ENABLE_BGP_VNC + struct bgp_path_info_extra_vnc *vnc; #endif /* For flowspec*/ @@ -366,6 +373,8 @@ struct bgp_static { /* Import check status. */ uint8_t valid; + uint16_t encap_tunneltype; + /* IGP metric. */ uint32_t igpmetric; @@ -391,7 +400,6 @@ struct bgp_static { /* EVPN */ esi_t *eth_s_id; struct ethaddr *router_mac; - uint16_t encap_tunneltype; struct prefix gatewayIp; }; @@ -412,10 +420,22 @@ struct bgp_aggregate { /* AS set generation. */ uint8_t as_set; + /* Optional modify flag to override ORIGIN */ + uint8_t origin; + + /** Are there MED mismatches? */ + bool med_mismatched; + /* MED matching state. */ + /** Did we get the first MED value? */ + bool med_initialized; + /** Match only equal MED. */ + bool match_med; + /* Route-map for aggregated route. */ struct { char *name; struct route_map *map; + bool changed; } rmap; /* Suppress-count. */ @@ -427,9 +447,6 @@ struct bgp_aggregate { /* Count of routes of origin type egp under this aggregate. */ unsigned long egp_origin_count; - /* Optional modify flag to override ORIGIN */ - uint8_t origin; - /* Hash containing the communities of all the * routes under this aggregate. */ @@ -465,13 +482,6 @@ struct bgp_aggregate { /* SAFI configuration. */ safi_t safi; - /** Match only equal MED. */ - bool match_med; - /* MED matching state. */ - /** Did we get the first MED value? */ - bool med_initialized; - /** Are there MED mismatches? */ - bool med_mismatched; /** MED value found in current group. */ uint32_t med_matched_value; @@ -674,6 +684,12 @@ DECLARE_HOOK(bgp_process, struct peer *peer, bool withdraw), (bgp, afi, safi, bn, peer, withdraw)); +/* called when a route is updated in the rib */ +DECLARE_HOOK(bgp_route_update, + (struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_dest *bn, + struct bgp_path_info *old_route, struct bgp_path_info *new_route), + (bgp, afi, safi, bn, old_route, new_route)); + /* BGP show options */ #define BGP_SHOW_OPT_JSON (1 << 0) #define BGP_SHOW_OPT_WIDE (1 << 1) @@ -698,7 +714,8 @@ extern void bgp_announce_route(struct peer *peer, afi_t afi, safi_t safi, bool force); extern void bgp_stop_announce_route_timer(struct peer_af *paf); extern void bgp_announce_route_all(struct peer *); -extern void bgp_default_originate(struct peer *, afi_t, safi_t, int); +extern void bgp_default_originate(struct peer *peer, afi_t afi, safi_t safi, + bool withdraw); extern void bgp_soft_reconfig_table_task_cancel(const struct bgp *bgp, const struct bgp_table *table, const struct peer *peer); @@ -905,6 +922,7 @@ extern void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate, extern void subgroup_announce_reset_nhop(uint8_t family, struct attr *attr); const char * bgp_path_selection_reason2str(enum bgp_path_selection_reason reason); +extern bool bgp_path_suppressed(struct bgp_path_info *pi); extern bool bgp_addpath_encode_rx(struct peer *peer, afi_t afi, safi_t safi); extern const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest, safi_t safi); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index e0db43f..d604a7a 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2323,17 +2323,10 @@ static const struct route_map_rule_cmd route_set_aspath_prepend_cmd = { route_set_aspath_prepend_free, }; -/* `set as-path exclude ASn' */ -struct aspath_exclude { - struct aspath *aspath; - bool exclude_all; - char *exclude_aspath_acl_name; - struct as_list *exclude_aspath_acl; -}; - static void *route_aspath_exclude_compile(const char *arg) { struct aspath_exclude *ase; + struct aspath_exclude_list *ael; const char *str = arg; static const char asp_acl[] = "as-path-access-list"; @@ -2348,16 +2341,41 @@ static void *route_aspath_exclude_compile(const char *arg) ase->exclude_aspath_acl = as_list_lookup(str); } 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; 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); } @@ -4442,6 +4460,13 @@ static void bgp_route_map_update_peer_group(const char *rmap_name, filter->map[direct].name) == 0)) filter->map[direct].map = map; + + if (group->conf->default_rmap[afi][safi].name && + strmatch(group->conf->default_rmap[afi][safi] + .name, + rmap_name)) + group->conf->default_rmap[afi][safi].map = + map; } if (filter->usmap.name @@ -4596,6 +4621,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name, route_map_counter_increment(map); aggregate->rmap.map = map; + aggregate->rmap.changed = true; matched = true; } @@ -4743,6 +4769,24 @@ static void bgp_route_map_delete(const char *rmap_name) route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED); } +bool bgp_route_map_has_extcommunity_rt(const struct route_map *map) +{ + struct route_map_index *index = NULL; + struct route_map_rule *set = NULL; + + assert(map); + + for (index = map->head; index; index = index->next) { + for (set = index->set_list.head; set; set = set->next) { + if (set->cmd && set->cmd->str && + (strmatch(set->cmd->str, "extcommunity rt") || + strmatch(set->cmd->str, "extended-comm-list"))) + return true; + } + } + return false; +} + static void bgp_route_map_event(const char *rmap_name) { if (route_map_mark_updated(rmap_name) == 0) diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c index abebfe5..096502a 100644 --- a/bgpd/bgp_routemap_nb.c +++ b/bgpd/bgp_routemap_nb.c @@ -147,6 +147,8 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { { .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list", .cbs = { + .create = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy, .apply_finish = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish, } }, @@ -154,7 +156,6 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name", .cbs = { .modify = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_modify, - .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy, } }, { @@ -356,6 +357,8 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator", .cbs = { + .create = lib_route_map_entry_set_action_rmap_set_action_aggregator_create, + .destroy = lib_route_map_entry_set_action_rmap_set_action_aggregator_destroy, .apply_finish = lib_route_map_entry_set_action_rmap_set_action_aggregator_finish, } }, @@ -363,14 +366,12 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-asn", .cbs = { .modify = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify, - .destroy = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy, } }, { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-address", .cbs = { .modify = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_modify, - .destroy = lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy, } }, { @@ -390,6 +391,8 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb", .cbs = { + .create = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_create, + .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_destroy, .apply_finish = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish, } }, @@ -397,7 +400,6 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/lb-type", .cbs = { .modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify, - .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy, } }, { @@ -418,7 +420,6 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/two-octet-as-specific", .cbs = { .modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_modify, - .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy, } }, { diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h index 28e4188..d7f0cea 100644 --- a/bgpd/bgp_routemap_nb.h +++ b/bgpd/bgp_routemap_nb.h @@ -60,9 +60,12 @@ int lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_mod int lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create( + struct nb_cb_create_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy( + struct nb_cb_destroy_args *args); void lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish(struct nb_cb_apply_finish_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_modify(struct nb_cb_modify_args *args); -int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_modify( @@ -127,24 +130,28 @@ int lib_route_map_entry_set_action_rmap_set_action_large_community_none_modify(s int lib_route_map_entry_set_action_rmap_set_action_large_community_none_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_large_community_string_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_large_community_string_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_aggregator_create( + struct nb_cb_create_args *args); +int lib_route_map_entry_set_action_rmap_set_action_aggregator_destroy( + struct nb_cb_destroy_args *args); void lib_route_map_entry_set_action_rmap_set_action_aggregator_finish(struct nb_cb_apply_finish_args *args); int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify(struct nb_cb_modify_args *args); -int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_modify(struct nb_cb_modify_args *args); -int lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_extended_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_num_extended_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_name_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_comm_list_name_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_create( + struct nb_cb_create_args *args); +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_destroy( + struct nb_cb_destroy_args *args); void lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish(struct nb_cb_apply_finish_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify(struct nb_cb_modify_args *args); -int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_modify(struct nb_cb_modify_args *args); -int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_none_modify( struct nb_cb_modify_args *args); int lib_route_map_entry_set_action_rmap_set_action_extcommunity_none_destroy( diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c index 370295b..c1d6ee1 100644 --- a/bgpd/bgp_routemap_nb_config.c +++ b/bgpd/bgp_routemap_nb_config.c @@ -522,6 +522,7 @@ lib_route_map_entry_match_condition_rmap_match_condition_probability_destroy( case NB_EV_VALIDATE: case NB_EV_PREPARE: case NB_EV_ABORT: + break; case NB_EV_APPLY: return lib_route_map_entry_match_destroy(args); } @@ -1120,6 +1121,27 @@ lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_des /* * XPath = /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list */ +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create( + struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + void lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish( struct nb_cb_apply_finish_args *args) @@ -1135,14 +1157,14 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish( /* Add configuration. */ rhc = nb_running_get_entry(args->dnode, NULL, true); - value = yang_dnode_get_string(args->dnode, "./comm-list-name"); + value = yang_dnode_get_string(args->dnode, "comm-list-name"); - if (yang_dnode_exists(args->dnode, "./comm-list-name-exact-match")) + if (yang_dnode_exists(args->dnode, "comm-list-name-exact-match")) exact_match = yang_dnode_get_bool( args->dnode, "./comm-list-name-exact-match"); - if (yang_dnode_exists(args->dnode, "./comm-list-name-any")) - any = yang_dnode_get_bool(args->dnode, "./comm-list-name-any"); + if (yang_dnode_exists(args->dnode, "comm-list-name-any")) + any = yang_dnode_get_bool(args->dnode, "comm-list-name-any"); if (exact_match) { argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, @@ -1210,23 +1232,6 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_nam return NB_OK; } -int -lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy( - struct nb_cb_destroy_args *args) -{ - switch (args->event) { - case NB_EV_VALIDATE: - case NB_EV_PREPARE: - case NB_EV_ABORT: - break; - case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); - } - - return NB_OK; - -} - /* * XPath: * /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any @@ -1252,9 +1257,8 @@ int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list case NB_EV_VALIDATE: case NB_EV_PREPARE: case NB_EV_ABORT: - break; case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); + break; } return NB_OK; @@ -1286,9 +1290,8 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_nam case NB_EV_VALIDATE: case NB_EV_PREPARE: case NB_EV_ABORT: - break; case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); + break; } return NB_OK; @@ -1450,7 +1453,7 @@ int lib_route_map_entry_set_action_rmap_set_action_distance_destroy( case NB_EV_ABORT: break; case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); + return lib_route_map_entry_set_destroy(args); } return NB_OK; @@ -1504,7 +1507,7 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_rt_destroy( case NB_EV_ABORT: break; case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); + return lib_route_map_entry_set_destroy(args); } return NB_OK; @@ -1556,7 +1559,7 @@ int lib_route_map_entry_set_action_rmap_set_action_extcommunity_nt_destroy( case NB_EV_ABORT: break; case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); + return lib_route_map_entry_set_destroy(args); } return NB_OK; @@ -1611,7 +1614,7 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_soo_destroy( case NB_EV_ABORT: break; case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); + return lib_route_map_entry_set_destroy(args); } return NB_OK; @@ -1747,7 +1750,7 @@ int lib_route_map_entry_set_action_rmap_set_action_ipv6_address_modify( || IN6_IS_ADDR_LINKLOCAL(&i6a)) return NB_ERR_VALIDATION; } - /* FALLTHROUGH */ + return NB_OK; case NB_EV_PREPARE: case NB_EV_ABORT: return NB_OK; @@ -2734,6 +2737,27 @@ lib_route_map_entry_set_action_rmap_set_action_large_community_string_destroy( * xpath = * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator */ +int lib_route_map_entry_set_action_rmap_set_action_aggregator_create( + struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_aggregator_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + void lib_route_map_entry_set_action_rmap_set_action_aggregator_finish( struct nb_cb_apply_finish_args *args) { @@ -2745,8 +2769,8 @@ void lib_route_map_entry_set_action_rmap_set_action_aggregator_finish( /* Add configuration. */ rhc = nb_running_get_entry(args->dnode, NULL, true); - asn = yang_dnode_get_string(args->dnode, "./aggregator-asn"); - addr = yang_dnode_get_string(args->dnode, "./aggregator-address"); + asn = yang_dnode_get_string(args->dnode, "aggregator-asn"); + addr = yang_dnode_get_string(args->dnode, "aggregator-address"); argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, strlen(asn) + strlen(addr) + 2); @@ -2798,22 +2822,6 @@ lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_modify( return NB_OK; } -int -lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_asn_destroy( - struct nb_cb_destroy_args *args) -{ - switch (args->event) { - case NB_EV_VALIDATE: - case NB_EV_PREPARE: - case NB_EV_ABORT: - break; - case NB_EV_APPLY: - return lib_route_map_entry_set_destroy(args); - } - - return NB_OK; -} - /* * XPath: * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aggregator/aggregator-address @@ -2833,22 +2841,6 @@ lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_mod return NB_OK; } -int -lib_route_map_entry_set_action_rmap_set_action_aggregator_aggregator_address_destroy( - struct nb_cb_destroy_args *args) -{ - switch (args->event) { - case NB_EV_VALIDATE: - case NB_EV_PREPARE: - case NB_EV_ABORT: - break; - case NB_EV_APPLY: - return lib_route_map_entry_set_destroy(args); - } - - return NB_OK; -} - /* * XPath: * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:comm-list-name @@ -2917,6 +2909,27 @@ lib_route_map_entry_set_action_rmap_set_action_comm_list_name_destroy( * XPath: * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb */ +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_create( + struct nb_cb_create_args *args) +{ + return NB_OK; +} + +int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_set_destroy(args); + } + + return NB_OK; +} + void lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish( struct nb_cb_apply_finish_args *args) @@ -2929,7 +2942,7 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish( /* Add configuration. */ rhc = nb_running_get_entry(args->dnode, NULL, true); - lb_type = yang_dnode_get_enum(args->dnode, "./lb-type"); + lb_type = yang_dnode_get_enum(args->dnode, "lb-type"); /* Set destroy information. */ rhc->rhc_shook = generic_set_delete; @@ -2938,7 +2951,7 @@ 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"); + bandwidth = yang_dnode_get_uint16(args->dnode, "bandwidth"); snprintf(str, sizeof(str), "%d", bandwidth); break; case CUMULATIVE_BANDWIDTH: @@ -2948,7 +2961,7 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish( snprintf(str, sizeof(str), "%s", "num-multipaths"); } - if (yang_dnode_get_bool(args->dnode, "./two-octet-as-specific")) + if (yang_dnode_get_bool(args->dnode, "two-octet-as-specific")) strlcat(str, " non-transitive", sizeof(str)); ret = generic_set_add(rhc->rhc_rmi, "extcommunity bandwidth", str, @@ -2972,13 +2985,6 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_modify( return NB_OK; } -int -lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_lb_type_destroy( - struct nb_cb_destroy_args *args) -{ - return lib_route_map_entry_set_destroy(args); -} - /* * XPath: * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb/bandwidth @@ -2994,7 +3000,7 @@ int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_destroy( struct nb_cb_destroy_args *args) { - return lib_route_map_entry_set_destroy(args); + return NB_OK; } /* @@ -3043,7 +3049,7 @@ int lib_route_map_entry_set_action_rmap_set_action_extcommunity_color_destroy( case NB_EV_ABORT: break; case NB_EV_APPLY: - return lib_route_map_entry_match_destroy(args); + return lib_route_map_entry_set_destroy(args); } return NB_OK; @@ -3060,13 +3066,6 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_spec return NB_OK; } -int -lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy( - struct nb_cb_destroy_args *args) -{ - return lib_route_map_entry_set_destroy(args); -} - /* * XPath: * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-none diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index f0b2ffd..22f78fb 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -25,6 +25,7 @@ #include "memory.h" #include "frrevent.h" #include "filter.h" +#include "lib_errors.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_table.h" #include "bgp_advertise.h" @@ -33,6 +34,7 @@ #include "bgpd/bgp_aspath.h" #include "bgpd/bgp_route.h" #include "bgpd/bgp_rpki.h" +#include "bgpd/bgp_debug.h" #include "northbound_cli.h" #include "lib/network.h" @@ -43,27 +45,33 @@ #include "bgpd/bgp_rpki_clippy.c" +DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_TEMP, "BGP RPKI Intermediate Buffer"); DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE, "BGP RPKI Cache server"); DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group"); DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_RTRLIB, "BGP RPKI RTRLib"); DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_REVALIDATE, "BGP RPKI Revalidation"); +#define STR_SEPARATOR 10 + #define POLLING_PERIOD_DEFAULT 3600 #define EXPIRE_INTERVAL_DEFAULT 7200 #define RETRY_INTERVAL_DEFAULT 600 #define BGP_RPKI_CACHE_SERVER_SYNC_RETRY_TIMEOUT 3 -static struct event *t_rpki_sync; - #define RPKI_DEBUG(...) \ - if (rpki_debug) { \ + if (rpki_debug_conf || rpki_debug_term) { \ zlog_debug("RPKI: " __VA_ARGS__); \ } #define RPKI_OUTPUT_STRING "Control rpki specific settings\n" struct cache { - enum { TCP, SSH } type; + enum { + TCP, +#if defined(FOUND_SSH) + SSH +#endif + } type; struct tr_socket *tr_socket; union { struct tr_tcp_config *tcp_config; @@ -71,6 +79,7 @@ struct cache { } tr_config; struct rtr_socket *rtr_socket; uint8_t preference; + struct rpki_vrf *rpki_vrf; }; enum return_values { SUCCESS = 0, ERROR = -1 }; @@ -83,32 +92,61 @@ struct rpki_for_each_record_arg { enum asnotation_mode asnotation; }; -static int start(void); -static void stop(void); -static int reset(bool force); -static struct rtr_mgr_group *get_connected_group(void); -static void print_prefix_table(struct vty *vty, json_object *json); +struct rpki_vrf { + struct rtr_mgr_config *rtr_config; + struct list *cache_list; + bool rtr_is_running; + bool rtr_is_stopping; + bool rtr_is_synced; + _Atomic int rtr_update_overflow; + unsigned int polling_period; + unsigned int expire_interval; + unsigned int retry_interval; + int rpki_sync_socket_rtr; + int rpki_sync_socket_bgpd; + char *vrfname; + struct event *t_rpki_sync; + + QOBJ_FIELDS; +}; + +static pthread_key_t rpki_pthread; + +static struct rpki_vrf *find_rpki_vrf(const char *vrfname); +static int bgp_rpki_vrf_update(struct vrf *vrf, bool enabled); +static int bgp_rpki_write_vrf(struct vty *vty, struct vrf *vrf); +static int bgp_rpki_hook_write_vrf(struct vty *vty, struct vrf *vrf); +static int bgp_rpki_write_debug(struct vty *vty, bool running); +static int start(struct rpki_vrf *rpki_vrf); +static void stop(struct rpki_vrf *rpki_vrf); +static int reset(bool force, struct rpki_vrf *rpki_vrf); +static struct rtr_mgr_group *get_connected_group(struct rpki_vrf *rpki_vrf); +static void print_prefix_table(struct vty *vty, struct rpki_vrf *rpki_vrf, + json_object *json, bool count_only); static void install_cli_commands(void); static int config_write(struct vty *vty); static int config_on_exit(struct vty *vty); static void free_cache(struct cache *cache); -static struct rtr_mgr_group *get_groups(void); +static struct rtr_mgr_group *get_groups(struct list *cache_list); #if defined(FOUND_SSH) -static int add_ssh_cache(const char *host, const unsigned int port, - const char *username, const char *client_privkey_path, +static int add_ssh_cache(struct rpki_vrf *rpki_vrf, const char *host, + const unsigned int port, const char *username, + const char *client_privkey_path, const char *server_pubkey_path, const uint8_t preference, const char *bindaddr); #endif static struct rtr_socket *create_rtr_socket(struct tr_socket *tr_socket); -static struct cache *find_cache(const uint8_t preference); -static void rpki_delete_all_cache_nodes(void); -static int add_tcp_cache(const char *host, const char *port, - const uint8_t preference, const char *bindaddr); +static struct cache *find_cache(const uint8_t preference, + struct list *cache_list); +static void rpki_delete_all_cache_nodes(struct rpki_vrf *rpki_vrf); +static int add_tcp_cache(struct rpki_vrf *rpki_vrf, const char *host, + const char *port, const uint8_t preference, + const char *bindaddr); static void print_record(const struct pfx_record *record, struct vty *vty, json_object *json, enum asnotation_mode asnotation); -static bool is_synchronized(void); -static bool is_running(void); -static bool is_stopping(void); +static bool is_synchronized(struct rpki_vrf *rpki_vrf); +static bool is_running(struct rpki_vrf *rpki_vrf); +static bool is_stopping(struct rpki_vrf *rpki_vrf); static void route_match_free(void *rule); static enum route_map_cmd_result_t route_match(void *rule, const struct prefix *prefix, @@ -116,20 +154,14 @@ static enum route_map_cmd_result_t route_match(void *rule, void *object); static void *route_match_compile(const char *arg); static void revalidate_bgp_node(struct bgp_dest *dest, afi_t afi, safi_t safi); -static void revalidate_all_routes(void); - -static struct rtr_mgr_config *rtr_config; -static struct list *cache_list; -static bool rtr_is_running; -static bool rtr_is_stopping; -static bool rtr_is_synced; -static _Atomic int rtr_update_overflow; -static bool rpki_debug; -static unsigned int polling_period; -static unsigned int expire_interval; -static unsigned int retry_interval; -static int rpki_sync_socket_rtr; -static int rpki_sync_socket_bgpd; +static void revalidate_all_routes(struct rpki_vrf *rpki_vrf); + +static bool rpki_debug_conf, rpki_debug_term; + +DECLARE_QOBJ_TYPE(rpki_vrf); +DEFINE_QOBJ_TYPE(rpki_vrf); + +struct list *rpki_vrf_list; static struct cmd_node rpki_node = { .name = "rpki", @@ -139,6 +171,16 @@ static struct cmd_node rpki_node = { .config_write = config_write, .node_exit = config_on_exit, }; + +static struct cmd_node rpki_vrf_node = { + .name = "rpki", + .node = RPKI_VRF_NODE, + .parent_node = VRF_NODE, + .prompt = "%s(config-vrf-rpki)# ", + .config_write = NULL, + .node_exit = config_on_exit, +}; + static const struct route_map_rule_cmd route_match_rpki_cmd = { "rpki", route_match, route_match_compile, route_match_free}; @@ -246,10 +288,141 @@ static struct rtr_socket *create_rtr_socket(struct tr_socket *tr_socket) return rtr_socket; } -static struct cache *find_cache(const uint8_t preference) +static int bgp_rpki_vrf_update(struct vrf *vrf, bool enabled) +{ + struct rpki_vrf *rpki; + + if (vrf->vrf_id == VRF_DEFAULT) + rpki = find_rpki_vrf(NULL); + else + rpki = find_rpki_vrf(vrf->name); + if (!rpki) + return 0; + + if (enabled) + start(rpki); + else + stop(rpki); + return 1; +} + +/* tcp identifier : <HOST>:<PORT> + * ssh identifier : <user>@<HOST>:<PORT> + */ +static struct rpki_vrf *find_rpki_vrf_from_ident(const char *ident) { +#if defined(FOUND_SSH) + struct tr_ssh_config *ssh_config; +#endif + struct tr_tcp_config *tcp_config; + struct listnode *rpki_vrf_nnode; + unsigned int cache_port, port; struct listnode *cache_node; + struct rpki_vrf *rpki_vrf; struct cache *cache; + bool is_tcp = true; + size_t host_len; + char *endptr; + char *host; + char *ptr; + char *buf; + + /* extract the <SOCKET> */ + ptr = strrchr(ident, ':'); + if (!ptr) + return NULL; + + ptr++; + /* extract port */ + port = atoi(ptr); + if (port == 0) + /* not ours */ + return NULL; + + /* extract host */ + ptr--; + host_len = (size_t)(ptr - ident); + buf = XCALLOC(MTYPE_BGP_RPKI_TEMP, host_len + 1); + memcpy(buf, ident, host_len); + buf[host_len] = '\0'; + endptr = strrchr(buf, '@'); + + /* ssh session */ + if (endptr) { + host = XCALLOC(MTYPE_BGP_RPKI_TEMP, + (size_t)(buf + host_len - endptr) + 1); + memcpy(host, endptr + 1, (size_t)(buf + host_len - endptr) + 1); + is_tcp = false; + } else { + host = buf; + buf = NULL; + } + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf_list, rpki_vrf_nnode, rpki_vrf)) { + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, + cache)) { + if ((cache->type == TCP && !is_tcp) +#if defined(FOUND_SSH) + || (cache->type == SSH && is_tcp) +#endif + ) + continue; + + if (is_tcp) { + tcp_config = cache->tr_config.tcp_config; + cache_port = atoi(tcp_config->port); + if (cache_port != port) + continue; + if (strlen(tcp_config->host) != strlen(host)) + continue; + if (memcmp(tcp_config->host, host, host_len) == + 0) + break; + } +#if defined(FOUND_SSH) + else { + ssh_config = cache->tr_config.ssh_config; + if (port != ssh_config->port) + continue; + if (strmatch(ssh_config->host, host)) + break; + } +#endif + } + if (cache) + break; + } + if (host) + XFREE(MTYPE_BGP_RPKI_TEMP, host); + if (buf) + XFREE(MTYPE_BGP_RPKI_TEMP, buf); + return rpki_vrf; +} + +static struct rpki_vrf *find_rpki_vrf(const char *vrfname) +{ + struct listnode *rpki_vrf_nnode; + struct rpki_vrf *rpki_vrf; + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf_list, rpki_vrf_nnode, rpki_vrf)) { + if (!vrfname && !rpki_vrf->vrfname) + /* rpki_vrf struct of the default VRF */ + return rpki_vrf; + if (vrfname && rpki_vrf->vrfname && + strmatch(vrfname, rpki_vrf->vrfname)) + return rpki_vrf; + } + return NULL; +} + +static struct cache *find_cache(const uint8_t preference, + struct list *cache_list) +{ + struct listnode *cache_node; + struct cache *cache; + + if (!cache_list) + return NULL; for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { if (cache->preference == preference) @@ -258,14 +431,15 @@ static struct cache *find_cache(const uint8_t preference) return NULL; } -static void rpki_delete_all_cache_nodes(void) +static void rpki_delete_all_cache_nodes(struct rpki_vrf *rpki_vrf) { struct listnode *cache_node, *cache_next; struct cache *cache; - for (ALL_LIST_ELEMENTS(cache_list, cache_node, cache_next, cache)) { - rtr_mgr_remove_group(rtr_config, cache->preference); - listnode_delete(cache_list, cache); + for (ALL_LIST_ELEMENTS(rpki_vrf->cache_list, cache_node, cache_next, + cache)) { + rtr_mgr_remove_group(rpki_vrf->rtr_config, cache->preference); + listnode_delete(rpki_vrf->cache_list, cache); } } @@ -315,7 +489,14 @@ static void print_record_cb(const struct pfx_record *record, void *data) print_record(record, vty, arg->json, arg->asnotation); } -static struct rtr_mgr_group *get_groups(void) +static void count_record_cb(const struct pfx_record *record, void *data) +{ + struct rpki_for_each_record_arg *arg = data; + + (*arg->prefix_amount)++; +} + +static struct rtr_mgr_group *get_groups(struct list *cache_list) { struct listnode *cache_node; struct rtr_mgr_group *rtr_mgr_groups; @@ -344,19 +525,19 @@ static struct rtr_mgr_group *get_groups(void) return rtr_mgr_groups; } -inline bool is_synchronized(void) +inline bool is_synchronized(struct rpki_vrf *rpki_vrf) { - return rtr_is_synced; + return rpki_vrf->rtr_is_synced; } -inline bool is_running(void) +inline bool is_running(struct rpki_vrf *rpki_vrf) { - return rtr_is_running; + return rpki_vrf->rtr_is_running; } -inline bool is_stopping(void) +inline bool is_stopping(struct rpki_vrf *rpki_vrf) { - return rtr_is_stopping; + return rpki_vrf->rtr_is_stopping; } static void pfx_record_to_prefix(struct pfx_record *record, @@ -408,23 +589,26 @@ static void bgpd_sync_callback(struct event *thread) struct listnode *node; struct prefix prefix; struct pfx_record rec; + struct rpki_vrf *rpki_vrf = EVENT_ARG(thread); + struct vrf *vrf = NULL; - event_add_read(bm->master, bgpd_sync_callback, NULL, - rpki_sync_socket_bgpd, NULL); + event_add_read(bm->master, bgpd_sync_callback, rpki_vrf, + rpki_vrf->rpki_sync_socket_bgpd, NULL); - if (atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst)) { - while (read(rpki_sync_socket_bgpd, &rec, + if (atomic_load_explicit(&rpki_vrf->rtr_update_overflow, + memory_order_seq_cst)) { + while (read(rpki_vrf->rpki_sync_socket_bgpd, &rec, sizeof(struct pfx_record)) != -1) ; - atomic_store_explicit(&rtr_update_overflow, 0, + atomic_store_explicit(&rpki_vrf->rtr_update_overflow, 0, memory_order_seq_cst); - revalidate_all_routes(); + revalidate_all_routes(rpki_vrf); return; } - int retval = - read(rpki_sync_socket_bgpd, &rec, sizeof(struct pfx_record)); + int retval = read(rpki_vrf->rpki_sync_socket_bgpd, &rec, + sizeof(struct pfx_record)); if (retval != sizeof(struct pfx_record)) { RPKI_DEBUG("Could not read from rpki_sync_socket_bgpd"); return; @@ -433,9 +617,23 @@ static void bgpd_sync_callback(struct event *thread) afi_t afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6; + if (rpki_vrf->vrfname) { + vrf = vrf_lookup_by_name(rpki_vrf->vrfname); + if (!vrf) { + zlog_err("%s(): vrf for rpki %s not found", __func__, + rpki_vrf->vrfname); + return; + } + } + for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) { safi_t safi; + if (!vrf && bgp->vrf_id != VRF_DEFAULT) + continue; + if (vrf && bgp->vrf_id != vrf->vrf_id) + continue; + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { struct bgp_table *table = bgp->rib[afi][safi]; struct rpki_revalidate_prefix *rrp; @@ -501,15 +699,30 @@ static void bgp_rpki_revalidate_peer(struct event *thread) XFREE(MTYPE_BGP_RPKI_REVALIDATE, rvp); } -static void revalidate_all_routes(void) +static void revalidate_all_routes(struct rpki_vrf *rpki_vrf) { struct bgp *bgp; struct listnode *node; + struct vrf *vrf = NULL; + + if (rpki_vrf->vrfname) { + vrf = vrf_lookup_by_name(rpki_vrf->vrfname); + if (!vrf) { + zlog_err("%s(): vrf for rpki %s not found", __func__, + rpki_vrf->vrfname); + return; + } + } for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) { struct peer *peer; struct listnode *peer_listnode; + if (!vrf && bgp->vrf_id != VRF_DEFAULT) + continue; + if (vrf && bgp->vrf_id != vrf->vrf_id) + continue; + for (ALL_LIST_ELEMENTS_RO(bgp->peer, peer_listnode, peer)) { afi_t afi; safi_t safi; @@ -542,21 +755,49 @@ static void rpki_update_cb_sync_rtr(struct pfx_table *p __attribute__((unused)), const struct pfx_record rec, const bool added __attribute__((unused))) { - if (is_stopping() || - atomic_load_explicit(&rtr_update_overflow, memory_order_seq_cst)) + struct rpki_vrf *rpki_vrf; + const char *msg; + const struct rtr_socket *rtr = rec.socket; + const char *ident; + + if (!rtr) { + msg = "could not find rtr_socket from cb_sync_rtr"; + goto err; + } + if (!rtr->tr_socket) { + msg = "could not find tr_socket from cb_sync_rtr"; + goto err; + } + ident = rtr->tr_socket->ident_fp(rtr->tr_socket->socket); + if (!ident) { + msg = "could not find ident from cb_sync_rtr"; + goto err; + } + rpki_vrf = find_rpki_vrf_from_ident(ident); + if (!rpki_vrf) { + msg = "could not find rpki_vrf"; + goto err; + } + + if (is_stopping(rpki_vrf) || + atomic_load_explicit(&rpki_vrf->rtr_update_overflow, + memory_order_seq_cst)) return; - int retval = - write(rpki_sync_socket_rtr, &rec, sizeof(struct pfx_record)); + int retval = write(rpki_vrf->rpki_sync_socket_rtr, &rec, + sizeof(struct pfx_record)); if (retval == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) - atomic_store_explicit(&rtr_update_overflow, 1, + atomic_store_explicit(&rpki_vrf->rtr_update_overflow, 1, memory_order_seq_cst); else if (retval != sizeof(struct pfx_record)) RPKI_DEBUG("Could not write to rpki_sync_socket_rtr"); + return; +err: + zlog_err("RPKI: %s", msg); } -static void rpki_init_sync_socket(void) +static void rpki_init_sync_socket(struct rpki_vrf *rpki_vrf) { int fds[2]; const char *msg; @@ -566,22 +807,22 @@ static void rpki_init_sync_socket(void) msg = "could not open rpki sync socketpair"; goto err; } - rpki_sync_socket_rtr = fds[0]; - rpki_sync_socket_bgpd = fds[1]; + rpki_vrf->rpki_sync_socket_rtr = fds[0]; + rpki_vrf->rpki_sync_socket_bgpd = fds[1]; - if (set_nonblocking(rpki_sync_socket_rtr) != 0) { + if (set_nonblocking(rpki_vrf->rpki_sync_socket_rtr) != 0) { msg = "could not set rpki_sync_socket_rtr to non blocking"; goto err; } - if (set_nonblocking(rpki_sync_socket_bgpd) != 0) { + if (set_nonblocking(rpki_vrf->rpki_sync_socket_bgpd) != 0) { msg = "could not set rpki_sync_socket_bgpd to non blocking"; goto err; } - event_add_read(bm->master, bgpd_sync_callback, NULL, - rpki_sync_socket_bgpd, NULL); + event_add_read(bm->master, bgpd_sync_callback, rpki_vrf, + rpki_vrf->rpki_sync_socket_bgpd, NULL); return; @@ -591,139 +832,195 @@ err: } +static struct rpki_vrf *bgp_rpki_allocate(const char *vrfname) +{ + struct rpki_vrf *rpki_vrf; + + /* initialise default vrf cache list */ + rpki_vrf = XCALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct rpki_vrf)); + + rpki_vrf->cache_list = list_new(); + rpki_vrf->cache_list->del = (void (*)(void *)) & free_cache; + rpki_vrf->polling_period = POLLING_PERIOD_DEFAULT; + rpki_vrf->expire_interval = EXPIRE_INTERVAL_DEFAULT; + rpki_vrf->retry_interval = RETRY_INTERVAL_DEFAULT; + + if (vrfname && !strmatch(vrfname, VRF_DEFAULT_NAME)) + rpki_vrf->vrfname = XSTRDUP(MTYPE_BGP_RPKI_CACHE, vrfname); + QOBJ_REG(rpki_vrf, rpki_vrf); + listnode_add(rpki_vrf_list, rpki_vrf); + + return rpki_vrf; +} + static int bgp_rpki_init(struct event_loop *master) { - rpki_debug = false; - rtr_is_running = false; - rtr_is_stopping = false; - rtr_is_synced = false; + rpki_debug_conf = false; + rpki_debug_term = false; - cache_list = list_new(); - cache_list->del = (void (*)(void *)) & free_cache; + rpki_vrf_list = list_new(); - polling_period = POLLING_PERIOD_DEFAULT; - expire_interval = EXPIRE_INTERVAL_DEFAULT; - retry_interval = RETRY_INTERVAL_DEFAULT; install_cli_commands(); - rpki_init_sync_socket(); + return 0; } static int bgp_rpki_fini(void) { - stop(); - list_delete(&cache_list); + struct listnode *node, *nnode; + struct rpki_vrf *rpki_vrf; + + for (ALL_LIST_ELEMENTS(rpki_vrf_list, node, nnode, rpki_vrf)) { + stop(rpki_vrf); + list_delete(&rpki_vrf->cache_list); - close(rpki_sync_socket_rtr); - close(rpki_sync_socket_bgpd); + close(rpki_vrf->rpki_sync_socket_rtr); + close(rpki_vrf->rpki_sync_socket_bgpd); + + listnode_delete(rpki_vrf_list, rpki_vrf); + QOBJ_UNREG(rpki_vrf); + if (rpki_vrf->vrfname) + XFREE(MTYPE_BGP_RPKI_CACHE, rpki_vrf->vrfname); + XFREE(MTYPE_BGP_RPKI_CACHE, rpki_vrf); + } return 0; } static int bgp_rpki_module_init(void) { + pthread_key_create(&rpki_pthread, NULL); + lrtr_set_alloc_functions(malloc_wrapper, realloc_wrapper, free_wrapper); hook_register(bgp_rpki_prefix_status, rpki_validate_prefix); hook_register(frr_late_init, bgp_rpki_init); hook_register(frr_early_fini, bgp_rpki_fini); + hook_register(bgp_hook_config_write_debug, &bgp_rpki_write_debug); + hook_register(bgp_hook_vrf_update, &bgp_rpki_vrf_update); + hook_register(bgp_hook_config_write_vrf, &bgp_rpki_hook_write_vrf); return 0; } static void sync_expired(struct event *thread) { - if (!rtr_mgr_conf_in_sync(rtr_config)) { + struct rpki_vrf *rpki_vrf = EVENT_ARG(thread); + + if (!rtr_mgr_conf_in_sync(rpki_vrf->rtr_config)) { RPKI_DEBUG("rtr_mgr is not synced, retrying."); - event_add_timer(bm->master, sync_expired, NULL, + event_add_timer(bm->master, sync_expired, rpki_vrf, BGP_RPKI_CACHE_SERVER_SYNC_RETRY_TIMEOUT, - &t_rpki_sync); + &rpki_vrf->t_rpki_sync); return; } RPKI_DEBUG("rtr_mgr sync is done."); - rtr_is_synced = true; + rpki_vrf->rtr_is_synced = true; } -static int start(void) +static int start(struct rpki_vrf *rpki_vrf) { + struct list *cache_list = NULL; + struct vrf *vrf; int ret; - rtr_is_stopping = false; - rtr_is_synced = false; - rtr_update_overflow = 0; + rpki_vrf->rtr_is_stopping = false; + rpki_vrf->rtr_is_synced = false; + rpki_vrf->rtr_update_overflow = 0; + cache_list = rpki_vrf->cache_list; + rpki_vrf->rtr_update_overflow = 0; - if (list_isempty(cache_list)) { + if (!cache_list || list_isempty(cache_list)) { RPKI_DEBUG( "No caches were found in config. Prefix validation is off."); return ERROR; } - RPKI_DEBUG("Init rtr_mgr."); + + if (rpki_vrf->vrfname) + vrf = vrf_lookup_by_name(rpki_vrf->vrfname); + else + vrf = vrf_lookup_by_id(VRF_DEFAULT); + if (!vrf || !CHECK_FLAG(vrf->status, VRF_ACTIVE)) { + RPKI_DEBUG("VRF %s not present or disabled", rpki_vrf->vrfname); + return ERROR; + } + + RPKI_DEBUG("Init rtr_mgr (%s).", vrf->name); int groups_len = listcount(cache_list); - struct rtr_mgr_group *groups = get_groups(); + struct rtr_mgr_group *groups = get_groups(rpki_vrf->cache_list); - RPKI_DEBUG("Polling period: %d", polling_period); - ret = rtr_mgr_init(&rtr_config, groups, groups_len, polling_period, - expire_interval, retry_interval, - rpki_update_cb_sync_rtr, NULL, NULL, NULL); + RPKI_DEBUG("Polling period: %d", rpki_vrf->polling_period); + ret = rtr_mgr_init(&rpki_vrf->rtr_config, groups, groups_len, + rpki_vrf->polling_period, rpki_vrf->expire_interval, + rpki_vrf->retry_interval, rpki_update_cb_sync_rtr, + NULL, NULL, NULL); if (ret == RTR_ERROR) { - RPKI_DEBUG("Init rtr_mgr failed."); + RPKI_DEBUG("Init rtr_mgr failed (%s).", vrf->name); return ERROR; } - RPKI_DEBUG("Starting rtr_mgr."); - ret = rtr_mgr_start(rtr_config); + RPKI_DEBUG("Starting rtr_mgr (%s).", vrf->name); + ret = rtr_mgr_start(rpki_vrf->rtr_config); if (ret == RTR_ERROR) { - RPKI_DEBUG("Starting rtr_mgr failed."); - rtr_mgr_free(rtr_config); + RPKI_DEBUG("Starting rtr_mgr failed (%s).", vrf->name); + rtr_mgr_free(rpki_vrf->rtr_config); return ERROR; } - event_add_timer(bm->master, sync_expired, NULL, 0, &t_rpki_sync); + event_add_timer(bm->master, sync_expired, rpki_vrf, 0, + &rpki_vrf->t_rpki_sync); XFREE(MTYPE_BGP_RPKI_CACHE_GROUP, groups); - rtr_is_running = true; + rpki_vrf->rtr_is_running = true; return SUCCESS; } -static void stop(void) +static void stop(struct rpki_vrf *rpki_vrf) { - rtr_is_stopping = true; - if (is_running()) { - EVENT_OFF(t_rpki_sync); - rtr_mgr_stop(rtr_config); - rtr_mgr_free(rtr_config); - rtr_is_running = false; + rpki_vrf->rtr_is_stopping = true; + if (is_running(rpki_vrf)) { + EVENT_OFF(rpki_vrf->t_rpki_sync); + rtr_mgr_stop(rpki_vrf->rtr_config); + rtr_mgr_free(rpki_vrf->rtr_config); + rpki_vrf->rtr_is_running = false; } } -static int reset(bool force) +static int reset(bool force, struct rpki_vrf *rpki_vrf) { - if (is_running() && !force) + if (is_running(rpki_vrf) && !force) return SUCCESS; RPKI_DEBUG("Resetting RPKI Session"); - stop(); - return start(); + stop(rpki_vrf); + return start(rpki_vrf); } -static struct rtr_mgr_group *get_connected_group(void) +static struct rtr_mgr_group *get_connected_group(struct rpki_vrf *rpki_vrf) { + struct list *cache_list; + + if (!rpki_vrf) + return NULL; + + cache_list = rpki_vrf->cache_list; if (!cache_list || list_isempty(cache_list)) return NULL; - return rtr_mgr_get_first_group(rtr_config); + return rtr_mgr_get_first_group(rpki_vrf->rtr_config); } static void print_prefix_table_by_asn(struct vty *vty, as_t as, + struct rpki_vrf *rpki_vrf, json_object *json) { unsigned int number_of_ipv4_prefixes = 0; unsigned int number_of_ipv6_prefixes = 0; - struct rtr_mgr_group *group = get_connected_group(); + struct rtr_mgr_group *group = get_connected_group(rpki_vrf); struct rpki_for_each_record_arg arg; json_object *json_records = NULL; @@ -732,8 +1029,14 @@ static void print_prefix_table_by_asn(struct vty *vty, as_t as, arg.json = NULL; arg.asnotation = bgp_get_asnotation(bgp_lookup_by_vrf_id(VRF_DEFAULT)); + if (!rpki_vrf) + return; + if (!group) { - if (!json) + if (json) { + json_object_string_add(json, "error", "Cannot find a connected group."); + vty_json(vty, json); + } else vty_out(vty, "Cannot find a connected group.\n"); return; } @@ -772,42 +1075,58 @@ static void print_prefix_table_by_asn(struct vty *vty, as_t as, vty_json(vty, json); } -static void print_prefix_table(struct vty *vty, json_object *json) +static void print_prefix_table(struct vty *vty, struct rpki_vrf *rpki_vrf, + json_object *json, bool count_only) { struct rpki_for_each_record_arg arg; unsigned int number_of_ipv4_prefixes = 0; unsigned int number_of_ipv6_prefixes = 0; - struct rtr_mgr_group *group = get_connected_group(); + struct rtr_mgr_group *group = get_connected_group(rpki_vrf); json_object *json_records = NULL; + if (!rpki_vrf) + return; + + group = get_connected_group(rpki_vrf); arg.vty = vty; arg.json = NULL; arg.asnotation = bgp_get_asnotation(bgp_lookup_by_vrf_id(VRF_DEFAULT)); if (!group) { - if (!json) + if (json) { + json_object_string_add(json, "error", "Cannot find a connected group."); + vty_json(vty, json); + } else vty_out(vty, "Cannot find a connected group.\n"); return; } struct pfx_table *pfx_table = group->sockets[0]->pfx_table; - if (!json) { - vty_out(vty, "RPKI/RTR prefix table\n"); - vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", - "Origin-AS"); - } else { - json_records = json_object_new_array(); - json_object_object_add(json, "prefixes", json_records); - arg.json = json_records; + if (!count_only) { + if (!json) { + vty_out(vty, "RPKI/RTR prefix table\n"); + vty_out(vty, "%-40s %s %s\n", "Prefix", + "Prefix Length", "Origin-AS"); + } else { + json_records = json_object_new_array(); + json_object_object_add(json, "prefixes", json_records); + arg.json = json_records; + } } arg.prefix_amount = &number_of_ipv4_prefixes; - pfx_table_for_each_ipv4_record(pfx_table, print_record_cb, &arg); + if (count_only) + pfx_table_for_each_ipv4_record(pfx_table, count_record_cb, &arg); + else + pfx_table_for_each_ipv4_record(pfx_table, print_record_cb, &arg); arg.prefix_amount = &number_of_ipv6_prefixes; - pfx_table_for_each_ipv6_record(pfx_table, print_record_cb, &arg); + if (count_only) + pfx_table_for_each_ipv6_record(pfx_table, count_record_cb, &arg); + else + pfx_table_for_each_ipv6_record(pfx_table, print_record_cb, &arg); if (!json) { vty_out(vty, "Number of IPv4 Prefixes: %u\n", @@ -832,8 +1151,25 @@ static int rpki_validate_prefix(struct peer *peer, struct attr *attr, as_t as_number = 0; struct lrtr_ip_addr ip_addr_prefix; enum pfxv_state result; + struct bgp *bgp = peer->bgp; + struct vrf *vrf; + struct rpki_vrf *rpki_vrf; + + if (!bgp) + return 0; + + vrf = vrf_lookup_by_id(bgp->vrf_id); + if (!vrf) + return 0; + + if (vrf->vrf_id == VRF_DEFAULT) + rpki_vrf = find_rpki_vrf(NULL); + else + rpki_vrf = find_rpki_vrf(vrf->name); + if (!rpki_vrf || !is_synchronized(rpki_vrf)) + return 0; - if (!is_synchronized()) + if (!is_synchronized(rpki_vrf)) return RPKI_NOT_BEING_USED; // No aspath means route comes from iBGP @@ -878,7 +1214,7 @@ static int rpki_validate_prefix(struct peer *peer, struct attr *attr, } // Do the actual validation - rtr_mgr_validate(rtr_config, as_number, &ip_addr_prefix, + rtr_mgr_validate(rpki_vrf->rtr_config, as_number, &ip_addr_prefix, prefix->prefixlen, &result); // Print Debug output @@ -911,15 +1247,26 @@ static int add_cache(struct cache *cache) { uint8_t preference = cache->preference; struct rtr_mgr_group group; + struct list *cache_list; + struct rpki_vrf *rpki_vrf; + + rpki_vrf = cache->rpki_vrf; + if (!rpki_vrf) + return ERROR; group.preference = preference; group.sockets_len = 1; group.sockets = &cache->rtr_socket; - if (is_running()) { + cache_list = rpki_vrf->cache_list; + if (!cache_list) + return ERROR; + + if (is_running(rpki_vrf)) { init_tr_socket(cache); - if (rtr_mgr_add_group(rtr_config, &group) != RTR_SUCCESS) { + if (rtr_mgr_add_group(rpki_vrf->rtr_config, &group) != + RTR_SUCCESS) { free_tr_socket(cache); return ERROR; } @@ -930,8 +1277,165 @@ static int add_cache(struct cache *cache) return SUCCESS; } -static int add_tcp_cache(const char *host, const char *port, - const uint8_t preference, const char *bindaddr) +static int rpki_create_socket(void *_cache) +{ + struct timeval prev_snd_tmout, prev_rcv_tmout, timeout; + struct cache *cache = (struct cache *)_cache; + struct rpki_vrf *rpki_vrf; + struct tr_tcp_config *tcp_config; + struct addrinfo *res = NULL; + struct addrinfo hints = {}; + socklen_t optlen; + char *host, *port; + struct vrf *vrf; + int cancel_state; + int socket; + int ret; +#if defined(FOUND_SSH) + struct tr_ssh_config *ssh_config; + char s_port[10]; +#endif + + if (!cache) + return -1; + + rpki_vrf = cache->rpki_vrf; + + /* + * the rpki infrastructure can call this function + * multiple times per pthread. Why? I have absolutely + * no idea, and I am not sure I care a whole bunch. + * Why does this matter? Well when we attempt to + * hook this pthread into the rcu structure multiple + * times the rcu code asserts on shutdown. Clearly + * upset that you have rcu data associated with a pthread + * that has not been cleaned up. And frankly this is rightly so. + * + * At this point we know that this function is not + * called a million bajillion times so let's just + * add a bit of insurance by looking to see if + * some thread specific code has been set for this + * pthread. If not, hook into the rcu code and + * make things happy. + * + * IF YOU PUT A ZLOG_XXXX prior to the call into + * frr_pthread_non_controlled_startup in this function + * BGP WILL CRASH. You have been warned. + */ + if (!pthread_getspecific(rpki_pthread) && + frr_pthread_non_controlled_startup(cache->rtr_socket->thread_id, + "RPKI RTRLIB socket", + "rpki_create_socket") < 0) + return -1; + + pthread_setspecific(rpki_pthread, &rpki_pthread); + + if (rpki_vrf->vrfname == NULL) + vrf = vrf_lookup_by_id(VRF_DEFAULT); + else + vrf = vrf_lookup_by_name(rpki_vrf->vrfname); + if (!vrf) + return -1; + + if (!CHECK_FLAG(vrf->status, VRF_ACTIVE) || vrf->vrf_id == VRF_UNKNOWN) + return -1; + + if (cache->type == TCP) { + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG; + + tcp_config = cache->tr_config.tcp_config; + host = tcp_config->host; + port = tcp_config->port; + } +#if defined(FOUND_SSH) + else { + ssh_config = cache->tr_config.ssh_config; + host = ssh_config->host; + snprintf(s_port, sizeof(s_port), "%u", ssh_config->port); + port = s_port; + + hints.ai_flags |= AI_NUMERICHOST; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + } +#endif + + frr_with_privs (&bgpd_privs) { + ret = vrf_getaddrinfo(host, port, &hints, &res, vrf->vrf_id); + } + if (ret != 0) { + flog_err_sys(EC_LIB_SOCKET, "getaddrinfo: %s", + gai_strerror(ret)); + return -1; + } + + frr_with_privs (&bgpd_privs) { + socket = vrf_socket(res->ai_family, res->ai_socktype, + res->ai_protocol, vrf->vrf_id, NULL); + } + if (socket < 0) { + freeaddrinfo(res); + return -1; + } + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancel_state); + timeout.tv_sec = 30; + timeout.tv_usec = 0; + + optlen = sizeof(prev_rcv_tmout); + ret = getsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &prev_rcv_tmout, + &optlen); + if (ret < 0) + zlog_warn("%s: failed to getsockopt SO_RCVTIMEO for socket %d", + __func__, socket); + ret = getsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &prev_snd_tmout, + &optlen); + if (ret < 0) + zlog_warn("%s: failed to getsockopt SO_SNDTIMEO for socket %d", + __func__, socket); + ret = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, + sizeof(timeout)); + if (ret < 0) + zlog_warn("%s: failed to setsockopt SO_RCVTIMEO for socket %d", + __func__, socket); + + ret = setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, + sizeof(timeout)); + if (ret < 0) + zlog_warn("%s: failed to setsockopt SO_SNDTIMEO for socket %d", + __func__, socket); + + if (connect(socket, res->ai_addr, res->ai_addrlen) == -1) { + freeaddrinfo(res); + close(socket); + pthread_setcancelstate(cancel_state, NULL); + return -1; + } + + freeaddrinfo(res); + pthread_setcancelstate(cancel_state, NULL); + + ret = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &prev_rcv_tmout, + sizeof(prev_rcv_tmout)); + if (ret < 0) + zlog_warn("%s: failed to setsockopt SO_RCVTIMEO for socket %d", + __func__, socket); + + ret = setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &prev_snd_tmout, + sizeof(prev_snd_tmout)); + if (ret < 0) + zlog_warn("%s: failed to setsockopt SO_SNDTIMEO for socket %d", + __func__, socket); + + return socket; +} + +static int add_tcp_cache(struct rpki_vrf *rpki_vrf, const char *host, + const char *port, const uint8_t preference, + const char *bindaddr) { struct rtr_socket *rtr_socket; struct tr_tcp_config *tcp_config = @@ -948,8 +1452,11 @@ static int add_tcp_cache(const char *host, const char *port, else tcp_config->bindaddr = NULL; + tcp_config->data = cache; + tcp_config->new_socket = rpki_create_socket; rtr_socket = create_rtr_socket(tr_socket); + cache->rpki_vrf = rpki_vrf; cache->type = TCP; cache->tr_socket = tr_socket; cache->tr_config.tcp_config = tcp_config; @@ -958,15 +1465,16 @@ static int add_tcp_cache(const char *host, const char *port, int ret = add_cache(cache); if (ret != SUCCESS) { + tcp_config->data = NULL; free_cache(cache); } - return ret; } #if defined(FOUND_SSH) -static int add_ssh_cache(const char *host, const unsigned int port, - const char *username, const char *client_privkey_path, +static int add_ssh_cache(struct rpki_vrf *rpki_vrf, const char *host, + const unsigned int port, const char *username, + const char *client_privkey_path, const char *server_pubkey_path, const uint8_t preference, const char *bindaddr) { @@ -984,6 +1492,8 @@ static int add_ssh_cache(const char *host, const unsigned int port, ssh_config->bindaddr = XSTRDUP(MTYPE_BGP_RPKI_CACHE, bindaddr); else ssh_config->bindaddr = NULL; + ssh_config->data = cache; + ssh_config->new_socket = rpki_create_socket; ssh_config->username = XSTRDUP(MTYPE_BGP_RPKI_CACHE, username); ssh_config->client_privkey_path = @@ -993,6 +1503,7 @@ static int add_ssh_cache(const char *host, const unsigned int port, rtr_socket = create_rtr_socket(tr_socket); + cache->rpki_vrf = rpki_vrf; cache->type = SSH; cache->tr_socket = tr_socket; cache->tr_config.ssh_config = ssh_config; @@ -1001,6 +1512,7 @@ static int add_ssh_cache(const char *host, const unsigned int port, int ret = add_cache(cache); if (ret != SUCCESS) { + ssh_config->data = NULL; free_cache(cache); } @@ -1036,25 +1548,72 @@ static void free_cache(struct cache *cache) XFREE(MTYPE_BGP_RPKI_CACHE, cache); } -static int config_write(struct vty *vty) +static int bgp_rpki_write_debug(struct vty *vty, bool running) { - struct listnode *cache_node; - struct cache *cache; - - if (rpki_debug) + if (rpki_debug_conf && running) { vty_out(vty, "debug rpki\n"); + return 1; + } + if ((rpki_debug_conf || rpki_debug_term) && !running) { + vty_out(vty, " BGP RPKI debugging is on\n"); + return 1; + } + return 0; +} - vty_out(vty, "!\n"); - vty_out(vty, "rpki\n"); +static int bgp_rpki_hook_write_vrf(struct vty *vty, struct vrf *vrf) +{ + int ret; - if (polling_period != POLLING_PERIOD_DEFAULT) - vty_out(vty, " rpki polling_period %d\n", polling_period); - if (retry_interval != RETRY_INTERVAL_DEFAULT) - vty_out(vty, " rpki retry_interval %d\n", retry_interval); - if (expire_interval != EXPIRE_INTERVAL_DEFAULT) - vty_out(vty, " rpki expire_interval %d\n", expire_interval); + ret = bgp_rpki_write_vrf(vty, vrf); + if (ret == ERROR) + return 0; + return ret; +} - for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { +static int bgp_rpki_write_vrf(struct vty *vty, struct vrf *vrf) +{ + struct listnode *cache_node; + struct cache *cache; + struct rpki_vrf *rpki_vrf = NULL; + char sep[STR_SEPARATOR]; + vrf_id_t vrf_id = VRF_DEFAULT; + + if (!vrf) { + rpki_vrf = find_rpki_vrf(NULL); + snprintf(sep, sizeof(sep), "%s", ""); + } else if (vrf->vrf_id != VRF_DEFAULT) { + rpki_vrf = find_rpki_vrf(vrf->name); + snprintf(sep, sizeof(sep), "%s", " "); + vrf_id = vrf->vrf_id; + } else + return ERROR; + + if (!rpki_vrf) + return ERROR; + + if (rpki_vrf->cache_list && list_isempty(rpki_vrf->cache_list) && + rpki_vrf->polling_period == POLLING_PERIOD_DEFAULT && + rpki_vrf->retry_interval == RETRY_INTERVAL_DEFAULT && + rpki_vrf->expire_interval == EXPIRE_INTERVAL_DEFAULT) + /* do not display the default config values */ + return 0; + + if (vrf_id == VRF_DEFAULT) + vty_out(vty, "%s!\n", sep); + vty_out(vty, "%srpki\n", sep); + + if (rpki_vrf->polling_period != POLLING_PERIOD_DEFAULT) + vty_out(vty, "%s rpki polling_period %d\n", sep, + rpki_vrf->polling_period); + if (rpki_vrf->retry_interval != RETRY_INTERVAL_DEFAULT) + vty_out(vty, "%s rpki retry_interval %d\n", sep, + rpki_vrf->retry_interval); + if (rpki_vrf->expire_interval != EXPIRE_INTERVAL_DEFAULT) + vty_out(vty, "%s rpki expire_interval %d\n", sep, + rpki_vrf->expire_interval); + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, cache)) { switch (cache->type) { struct tr_tcp_config *tcp_config; #if defined(FOUND_SSH) @@ -1062,8 +1621,8 @@ static int config_write(struct vty *vty) #endif case TCP: tcp_config = cache->tr_config.tcp_config; - vty_out(vty, " rpki cache %s %s ", tcp_config->host, - tcp_config->port); + vty_out(vty, "%s rpki cache %s %s ", sep, + tcp_config->host, tcp_config->port); if (tcp_config->bindaddr) vty_out(vty, "source %s ", tcp_config->bindaddr); @@ -1071,13 +1630,13 @@ static int config_write(struct vty *vty) #if defined(FOUND_SSH) case SSH: ssh_config = cache->tr_config.ssh_config; - vty_out(vty, " rpki cache %s %u %s %s %s ", + vty_out(vty, "%s rpki cache %s %u %s %s %s ", sep, ssh_config->host, ssh_config->port, ssh_config->username, ssh_config->client_privkey_path, ssh_config->server_hostkey_path != NULL ? ssh_config->server_hostkey_path - : " "); + : ""); if (ssh_config->bindaddr) vty_out(vty, "source %s ", ssh_config->bindaddr); @@ -1089,17 +1648,66 @@ static int config_write(struct vty *vty) vty_out(vty, "preference %hhu\n", cache->preference); } - vty_out(vty, "exit\n"); + + vty_out(vty, "%sexit\n%s", sep, vrf_id == VRF_DEFAULT ? "!\n" : ""); return 1; } +static int config_write(struct vty *vty) +{ + return bgp_rpki_write_vrf(vty, NULL); +} + +static struct rpki_vrf *get_rpki_vrf(const char *vrfname) +{ + struct rpki_vrf *rpki_vrf = NULL; + struct vrf *vrf = NULL; + + if (vrfname && !strmatch(vrfname, VRF_DEFAULT_NAME)) { + vrf = vrf_lookup_by_name(vrfname); + if (!vrf) + return NULL; + rpki_vrf = find_rpki_vrf(vrf->name); + } else + /* default VRF */ + rpki_vrf = find_rpki_vrf(NULL); + + return rpki_vrf; +} + DEFUN_NOSH (rpki, rpki_cmd, "rpki", "Enable rpki and enter rpki configuration mode\n") { - vty->node = RPKI_NODE; + struct rpki_vrf *rpki_vrf; + char *vrfname = NULL; + struct vrf *vrf; + + if (vty->node == CONFIG_NODE) + vty->node = RPKI_NODE; + else { + vrf = VTY_GET_CONTEXT(vrf); + + if (!vrf) + return CMD_WARNING; + + vty->node = RPKI_VRF_NODE; + if (vrf->vrf_id != VRF_DEFAULT) + vrfname = vrf->name; + } + + rpki_vrf = find_rpki_vrf(vrfname); + if (!rpki_vrf) { + rpki_vrf = bgp_rpki_allocate(vrfname); + + rpki_init_sync_socket(rpki_vrf); + } + if (vty->node == RPKI_VRF_NODE) + VTY_PUSH_CONTEXT_SUB(vty->node, rpki_vrf); + else + VTY_PUSH_CONTEXT(vty->node, rpki_vrf); return CMD_SUCCESS; } @@ -1109,23 +1717,49 @@ DEFPY (no_rpki, NO_STR "Enable rpki and enter rpki configuration mode\n") { - rpki_delete_all_cache_nodes(); - stop(); + struct rpki_vrf *rpki_vrf; + char *vrfname = NULL; + + if (vty->node == VRF_NODE) { + VTY_DECLVAR_CONTEXT(vrf, vrf); + + if (vrf->vrf_id != VRF_DEFAULT) + vrfname = vrf->name; + } + + rpki_vrf = find_rpki_vrf(vrfname); + + rpki_delete_all_cache_nodes(rpki_vrf); + stop(rpki_vrf); + rpki_vrf->polling_period = POLLING_PERIOD_DEFAULT; + rpki_vrf->expire_interval = EXPIRE_INTERVAL_DEFAULT; + rpki_vrf->retry_interval = RETRY_INTERVAL_DEFAULT; + return CMD_SUCCESS; } -DEFUN (bgp_rpki_start, +DEFPY (bgp_rpki_start, bgp_rpki_start_cmd, - "rpki start", + "rpki start [vrf NAME$vrfname]", RPKI_OUTPUT_STRING - "start rpki support\n") + "start rpki support\n" + VRF_CMD_HELP_STR) { - if (listcount(cache_list) == 0) + struct list *cache_list = NULL; + struct rpki_vrf *rpki_vrf; + + rpki_vrf = get_rpki_vrf(vrfname); + + if (!rpki_vrf) + return CMD_WARNING; + + cache_list = rpki_vrf->cache_list; + if (!cache_list || listcount(cache_list) == 0) vty_out(vty, "Could not start rpki because no caches are configured\n"); - if (!is_running()) { - if (start() == ERROR) { + if (!is_running(rpki_vrf)) { + if (start(rpki_vrf) == ERROR) { RPKI_DEBUG("RPKI failed to start"); return CMD_WARNING; } @@ -1133,14 +1767,19 @@ DEFUN (bgp_rpki_start, return CMD_SUCCESS; } -DEFUN (bgp_rpki_stop, +DEFPY (bgp_rpki_stop, bgp_rpki_stop_cmd, - "rpki stop", + "rpki stop [vrf NAME$vrfname]", RPKI_OUTPUT_STRING - "start rpki support\n") + "start rpki support\n" + VRF_CMD_HELP_STR) { - if (is_running()) - stop(); + struct rpki_vrf *rpki_vrf; + + rpki_vrf = get_rpki_vrf(vrfname); + + if (rpki_vrf && is_running(rpki_vrf)) + stop(rpki_vrf); return CMD_SUCCESS; } @@ -1152,7 +1791,17 @@ DEFPY (rpki_polling_period, "Set polling period\n" "Polling period value\n") { - polling_period = pp; + struct rpki_vrf *rpki_vrf; + + 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; + + rpki_vrf->polling_period = pp; return CMD_SUCCESS; } @@ -1164,7 +1813,17 @@ DEFUN (no_rpki_polling_period, "Set polling period back to default\n" "Polling period value\n") { - polling_period = POLLING_PERIOD_DEFAULT; + struct rpki_vrf *rpki_vrf; + + 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; + + rpki_vrf->polling_period = POLLING_PERIOD_DEFAULT; return CMD_SUCCESS; } @@ -1175,8 +1834,18 @@ DEFPY (rpki_expire_interval, "Set expire interval\n" "Expire interval value\n") { - if ((unsigned int)tmp >= polling_period) { - expire_interval = tmp; + struct rpki_vrf *rpki_vrf; + + 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 ((unsigned int)tmp >= rpki_vrf->polling_period) { + rpki_vrf->expire_interval = tmp; return CMD_SUCCESS; } @@ -1192,7 +1861,17 @@ DEFUN (no_rpki_expire_interval, "Set expire interval back to default\n" "Expire interval value\n") { - expire_interval = polling_period * 2; + struct rpki_vrf *rpki_vrf; + + 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; + + rpki_vrf->expire_interval = rpki_vrf->polling_period * 2; return CMD_SUCCESS; } @@ -1203,7 +1882,17 @@ DEFPY (rpki_retry_interval, "Set retry interval\n" "retry interval value\n") { - retry_interval = tmp; + struct rpki_vrf *rpki_vrf; + + 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; + + rpki_vrf->retry_interval = tmp; return CMD_SUCCESS; } @@ -1215,7 +1904,17 @@ DEFUN (no_rpki_retry_interval, "Set retry interval back to default\n" "retry interval value\n") { - retry_interval = RETRY_INTERVAL_DEFAULT; + struct rpki_vrf *rpki_vrf; + + 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; + + rpki_vrf->retry_interval = RETRY_INTERVAL_DEFAULT; return CMD_SUCCESS; } @@ -1238,8 +1937,24 @@ DEFPY(rpki_cache, rpki_cache_cmd, int return_value; struct listnode *cache_node; struct cache *current_cache; + struct rpki_vrf *rpki_vrf; + bool init; - for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, current_cache)) { + 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", @@ -1248,21 +1963,20 @@ DEFPY(rpki_cache, rpki_cache_cmd, } } - // use ssh connection if (ssh_uname) { #if defined(FOUND_SSH) - return_value = - add_ssh_cache(cache, sshport, ssh_uname, ssh_privkey, - server_pubkey, preference, bindaddr_str); + return_value = add_ssh_cache(rpki_vrf, cache, sshport, ssh_uname, + ssh_privkey, server_pubkey, + 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 } else { // use tcp connection - return_value = - add_tcp_cache(cache, tcpport, preference, bindaddr_str); + return_value = add_tcp_cache(rpki_vrf, cache, tcpport, + preference, bindaddr_str); } if (return_value == ERROR) { @@ -1270,6 +1984,9 @@ DEFPY(rpki_cache, rpki_cache_cmd, return CMD_WARNING; } + if (init) + start(rpki_vrf); + return CMD_SUCCESS; } @@ -1291,18 +2008,31 @@ DEFPY (no_rpki_cache, "Preference of the cache server\n" "Preference value\n") { - struct cache *cache_p = find_cache(preference); + struct cache *cache_p; + struct list *cache_list = NULL; + struct rpki_vrf *rpki_vrf; + + if (vty->node == RPKI_VRF_NODE) + rpki_vrf = VTY_GET_CONTEXT_SUB(rpki_vrf); + else + rpki_vrf = VTY_GET_CONTEXT(rpki_vrf); - if (!cache_p) { + if (!rpki_vrf) + return CMD_WARNING_CONFIG_FAILED; + + cache_list = rpki_vrf->cache_list; + cache_p = find_cache(preference, cache_list); + if (!rpki_vrf || !cache_p) { vty_out(vty, "Could not find cache with preference %ld\n", preference); return CMD_WARNING; } - if (is_running() && listcount(cache_list) == 1) { - stop(); - } else if (is_running()) { - if (rtr_mgr_remove_group(rtr_config, preference) == RTR_ERROR) { + if (is_running(rpki_vrf) && listcount(cache_list) == 1) { + stop(rpki_vrf); + } else if (is_running(rpki_vrf)) { + if (rtr_mgr_remove_group(rpki_vrf->rtr_config, preference) == + RTR_ERROR) { vty_out(vty, "Could not remove cache with preference %ld\n", preference); @@ -1318,68 +2048,107 @@ DEFPY (no_rpki_cache, DEFPY (show_rpki_prefix_table, show_rpki_prefix_table_cmd, - "show rpki prefix-table [json$uj]", + "show rpki <prefix-table|prefix-count>$prefixkind [vrf NAME$vrfname] [json$uj]", SHOW_STR RPKI_OUTPUT_STRING "Show validated prefixes which were received from RPKI Cache\n" + "Show prefixes count which were received from RPKI Cache\n" + VRF_CMD_HELP_STR JSON_STR) { struct json_object *json = NULL; + struct rpki_vrf *rpki_vrf; + + if (uj) + json = json_object_new_object(); + + rpki_vrf = get_rpki_vrf(vrfname); + if (!rpki_vrf) { + if (uj) + vty_json(vty, json); + return CMD_SUCCESS; + } - if (!is_synchronized()) { - if (!uj) + if (is_synchronized(rpki_vrf)) { + if (strmatch(prefixkind, "prefix-count")) + print_prefix_table(vty, rpki_vrf, json, true); + else + print_prefix_table(vty, rpki_vrf, json, false); + } else { + if (json) { + json_object_string_add(json, "error", "No Connection to RPKI cache server."); + vty_json(vty, json); + } else vty_out(vty, "No connection to RPKI cache server.\n"); return CMD_WARNING; } - if (uj) - json = json_object_new_object(); - - print_prefix_table(vty, json); return CMD_SUCCESS; } DEFPY (show_rpki_as_number, show_rpki_as_number_cmd, - "show rpki as-number ASNUM$by_asn [json$uj]", + "show rpki as-number ASNUM$by_asn [vrf NAME$vrfname] [json$uj]", SHOW_STR RPKI_OUTPUT_STRING "Lookup by ASN in prefix table\n" "AS Number\n" + VRF_CMD_HELP_STR JSON_STR) { struct json_object *json = NULL; + struct rpki_vrf *rpki_vrf; + + if (uj) + json = json_object_new_object(); + + rpki_vrf = get_rpki_vrf(vrfname); + if (!rpki_vrf) { + if (uj) + vty_json(vty, json); + return CMD_SUCCESS; + } - if (!is_synchronized()) { - if (!uj) + if (!is_synchronized(rpki_vrf)) { + if (json) { + json_object_string_add(json, "error", "No Connection to RPKI cache server."); + vty_json(vty, json); + } else vty_out(vty, "No Connection to RPKI cache server.\n"); return CMD_WARNING; } - if (uj) - json = json_object_new_object(); - - print_prefix_table_by_asn(vty, by_asn, json); + print_prefix_table_by_asn(vty, by_asn, 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] [json$uj]", + "show rpki prefix <A.B.C.D/M|X:X::X:X/M> [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\n" + VRF_CMD_HELP_STR JSON_STR) { json_object *json = NULL; json_object *json_records = NULL; enum asnotation_mode asnotation; + struct rpki_vrf *rpki_vrf; - if (!is_synchronized()) { - if (!uj) + if (uj) + json = json_object_new_object(); + + rpki_vrf = get_rpki_vrf(vrfname); + + if (!rpki_vrf || !is_synchronized(rpki_vrf)) { + if (json) { + json_object_string_add(json, "error", "No Connection to RPKI cache server."); + vty_json(vty, json); + } else vty_out(vty, "No Connection to RPKI cache server.\n"); return CMD_WARNING; } @@ -1392,7 +2161,10 @@ DEFPY (show_rpki_prefix, memcpy(addr_str, prefix_str, addr_len); if (lrtr_ip_str_to_addr(addr_str, &addr) != 0) { - if (!json) + if (json) { + json_object_string_add(json, "error", "Invalid IP prefix."); + vty_json(vty, json); + } else vty_out(vty, "Invalid IP prefix\n"); return CMD_WARNING; } @@ -1401,16 +2173,17 @@ DEFPY (show_rpki_prefix, unsigned int match_count = 0; enum pfxv_state result; - if (pfx_table_validate_r(rtr_config->pfx_table, &matches, &match_count, - asn, &addr, prefix->prefixlen, + if (pfx_table_validate_r(rpki_vrf->rtr_config->pfx_table, &matches, + &match_count, asn, &addr, prefix->prefixlen, &result) != PFX_SUCCESS) { - if (!json) + if (json) { + json_object_string_add(json, "error", "Prefix lookup failed."); + vty_json(vty, json); + } else vty_out(vty, "Prefix lookup failed\n"); return CMD_WARNING; } - if (uj) - json = json_object_new_object(); if (!json) { vty_out(vty, "%-40s %s %s\n", "Prefix", "Prefix Length", @@ -1439,10 +2212,11 @@ DEFPY (show_rpki_prefix, DEFPY (show_rpki_cache_server, show_rpki_cache_server_cmd, - "show rpki cache-server [json$uj]", + "show rpki cache-server [vrf NAME$vrfname] [json$uj]", SHOW_STR RPKI_OUTPUT_STRING "Show configured cache server\n" + VRF_CMD_HELP_STR JSON_STR) { struct json_object *json = NULL; @@ -1450,6 +2224,7 @@ DEFPY (show_rpki_cache_server, struct json_object *json_servers = NULL; struct listnode *cache_node; struct cache *cache; + struct rpki_vrf *rpki_vrf; if (uj) { json = json_object_new_object(); @@ -1457,7 +2232,14 @@ DEFPY (show_rpki_cache_server, json_object_object_add(json, "servers", json_servers); } - for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { + rpki_vrf = get_rpki_vrf(vrfname); + if (!rpki_vrf) { + if (json) + vty_json(vty, json); + return CMD_SUCCESS; + } + + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, cache)) { if (cache->type == TCP) { if (!json) { vty_out(vty, @@ -1532,10 +2314,11 @@ DEFPY (show_rpki_cache_server, DEFPY (show_rpki_cache_connection, show_rpki_cache_connection_cmd, - "show rpki cache-connection [json$uj]", + "show rpki cache-connection [vrf NAME$vrfname] [json$uj]", SHOW_STR RPKI_OUTPUT_STRING "Show to which RPKI Cache Servers we have a connection\n" + VRF_CMD_HELP_STR JSON_STR) { struct json_object *json = NULL; @@ -1544,25 +2327,35 @@ DEFPY (show_rpki_cache_connection, struct listnode *cache_node; struct cache *cache; struct rtr_mgr_group *group; + struct rpki_vrf *rpki_vrf; if (uj) json = json_object_new_object(); - if (!is_synchronized()) { - if (!json) - vty_out(vty, "No connection to RPKI cache server.\n"); - else + rpki_vrf = get_rpki_vrf(vrfname); + if (!rpki_vrf) { + if (json) vty_json(vty, json); + return CMD_SUCCESS; + } + + if (!is_synchronized(rpki_vrf)) { + if (json) { + json_object_string_add(json, "error", "No connection to RPKI cache server."); + vty_json(vty, json); + } else + vty_out(vty, "No connection to RPKI cache server.\n"); return CMD_SUCCESS; } - group = get_connected_group(); + group = get_connected_group(rpki_vrf); if (!group) { - if (!json) - vty_out(vty, "Cannot find a connected group.\n"); - else + if (json) { + json_object_string_add(json, "error", "Cannot find a connected group."); vty_json(vty, json); + } else + vty_out(vty, "Cannot find a connected group.\n"); return CMD_SUCCESS; } @@ -1575,7 +2368,7 @@ DEFPY (show_rpki_cache_connection, json_object_object_add(json, "connections", json_conns); } - for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) { + for (ALL_LIST_ELEMENTS_RO(rpki_vrf->cache_list, cache_node, cache)) { struct tr_tcp_config *tcp_config; #if defined(FOUND_SSH) struct tr_ssh_config *ssh_config; @@ -1656,19 +2449,110 @@ DEFPY (show_rpki_cache_connection, return CMD_SUCCESS; } +DEFPY(show_rpki_configuration, show_rpki_configuration_cmd, + "show rpki configuration [vrf NAME$vrfname] [json$uj]", + SHOW_STR RPKI_OUTPUT_STRING + "Show RPKI configuration\n" + VRF_CMD_HELP_STR + JSON_STR) +{ + struct json_object *json = NULL; + struct rpki_vrf *rpki_vrf; + + if (uj) + json = json_object_new_object(); + + rpki_vrf = find_rpki_vrf(vrfname); + if (!rpki_vrf) { + if (uj) + vty_json(vty, json); + return CMD_SUCCESS; + } + + if (uj) { + json_object_boolean_add(json, "enabled", + !!listcount(rpki_vrf->cache_list)); + json_object_int_add(json, "serversCount", + listcount(rpki_vrf->cache_list)); + json_object_int_add(json, "pollingPeriodSeconds", + rpki_vrf->polling_period); + json_object_int_add(json, "retryIntervalSeconds", + rpki_vrf->retry_interval); + json_object_int_add(json, "expireIntervalSeconds", + rpki_vrf->expire_interval); + + vty_json(vty, json); + + return CMD_SUCCESS; + } + + vty_out(vty, "rpki is %s", + listcount(rpki_vrf->cache_list) ? "Enabled" : "Disabled"); + + if (list_isempty(rpki_vrf->cache_list)) { + vty_out(vty, "\n"); + return CMD_SUCCESS; + } + + vty_out(vty, " (%d cache servers configured)", + listcount(rpki_vrf->cache_list)); + vty_out(vty, "\n"); + vty_out(vty, "\tpolling period %d\n", rpki_vrf->polling_period); + vty_out(vty, "\tretry interval %d\n", rpki_vrf->retry_interval); + vty_out(vty, "\texpire interval %d\n", rpki_vrf->expire_interval); + + return CMD_SUCCESS; +} + static int config_on_exit(struct vty *vty) { - reset(false); + struct rpki_vrf *rpki_vrf; + + 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; + + reset(false, rpki_vrf); return 1; } -DEFUN (rpki_reset, +DEFPY(rpki_reset, rpki_reset_cmd, + "rpki reset [vrf NAME$vrfname]", + RPKI_OUTPUT_STRING + "reset rpki\n" + VRF_CMD_HELP_STR) +{ + struct rpki_vrf *rpki_vrf; + + rpki_vrf = find_rpki_vrf(vrfname); + if (!rpki_vrf) + return CMD_WARNING; + + return reset(true, rpki_vrf) == SUCCESS ? CMD_SUCCESS : CMD_WARNING; +} + +DEFPY (rpki_reset_config_mode, + rpki_reset_config_mode_cmd, "rpki reset", RPKI_OUTPUT_STRING "reset rpki\n") { - return reset(true) == SUCCESS ? CMD_SUCCESS : CMD_WARNING; + struct rpki_vrf *rpki_vrf; + + 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; + + return reset(true, rpki_vrf) == SUCCESS ? CMD_SUCCESS : CMD_WARNING; } DEFUN (debug_rpki, @@ -1677,7 +2561,10 @@ DEFUN (debug_rpki, DEBUG_STR "Enable debugging for rpki\n") { - rpki_debug = true; + if (vty->node == CONFIG_NODE) + rpki_debug_conf = true; + else + rpki_debug_term = true; return CMD_SUCCESS; } @@ -1688,7 +2575,10 @@ DEFUN (no_debug_rpki, DEBUG_STR "Disable debugging for rpki\n") { - rpki_debug = false; + if (vty->node == CONFIG_NODE) + rpki_debug_conf = false; + else + rpki_debug_term = false; return CMD_SUCCESS; } @@ -1735,8 +2625,9 @@ static void install_cli_commands(void) // TODO: make config write work install_node(&rpki_node); install_default(RPKI_NODE); + install_node(&rpki_vrf_node); + install_default(RPKI_VRF_NODE); install_element(CONFIG_NODE, &rpki_cmd); - install_element(ENABLE_NODE, &rpki_cmd); install_element(CONFIG_NODE, &no_rpki_cmd); @@ -1745,7 +2636,7 @@ static void install_cli_commands(void) /* Install rpki reset command */ install_element(ENABLE_NODE, &rpki_reset_cmd); - install_element(RPKI_NODE, &rpki_reset_cmd); + install_element(RPKI_NODE, &rpki_reset_config_mode_cmd); /* Install rpki polling period commands */ install_element(RPKI_NODE, &rpki_polling_period_cmd); @@ -1763,12 +2654,35 @@ static void install_cli_commands(void) install_element(RPKI_NODE, &rpki_cache_cmd); install_element(RPKI_NODE, &no_rpki_cache_cmd); + /* RPKI_VRF_NODE commands */ + install_element(VRF_NODE, &rpki_cmd); + install_element(VRF_NODE, &no_rpki_cmd); + /* Install rpki reset command */ + install_element(RPKI_VRF_NODE, &rpki_reset_config_mode_cmd); + + /* Install rpki polling period commands */ + install_element(RPKI_VRF_NODE, &rpki_polling_period_cmd); + install_element(RPKI_VRF_NODE, &no_rpki_polling_period_cmd); + + /* Install rpki expire interval commands */ + install_element(RPKI_VRF_NODE, &rpki_expire_interval_cmd); + install_element(RPKI_VRF_NODE, &no_rpki_expire_interval_cmd); + + /* Install rpki retry interval commands */ + install_element(RPKI_VRF_NODE, &rpki_retry_interval_cmd); + install_element(RPKI_VRF_NODE, &no_rpki_retry_interval_cmd); + + /* Install rpki cache commands */ + install_element(RPKI_VRF_NODE, &rpki_cache_cmd); + install_element(RPKI_VRF_NODE, &no_rpki_cache_cmd); + /* Install show commands */ install_element(VIEW_NODE, &show_rpki_prefix_table_cmd); install_element(VIEW_NODE, &show_rpki_cache_connection_cmd); install_element(VIEW_NODE, &show_rpki_cache_server_cmd); install_element(VIEW_NODE, &show_rpki_prefix_cmd); install_element(VIEW_NODE, &show_rpki_as_number_cmd); + install_element(VIEW_NODE, &show_rpki_configuration_cmd); /* Install debug commands */ install_element(CONFIG_NODE, &debug_rpki_cmd); diff --git a/bgpd/bgp_rpki.h b/bgpd/bgp_rpki.h index de28715..4f2f87d 100644 --- a/bgpd/bgp_rpki.h +++ b/bgpd/bgp_rpki.h @@ -8,6 +8,8 @@ #ifndef __BGP_RPKI_H__ #define __BGP_RPKI_H__ +extern struct zebra_privs_t bgpd_privs; + enum rpki_states { RPKI_NOT_BEING_USED, RPKI_VALID, diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index ce9442c..065ea76 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -29,10 +29,93 @@ #include "bgpd/bgp_snmp_bgp4.h" #include "bgpd/bgp_snmp_bgp4v2.h" #include "bgpd/bgp_mplsvpn_snmp.h" +#include "bgpd/bgp_snmp_clippy.c" + + + +static int bgp_cli_snmp_traps_config_write(struct vty *vty); + +DEFPY(bgp_snmp_traps_rfc4273, bgp_snmp_traps_rfc4273_cmd, + "[no$no] bgp snmp traps rfc4273", + NO_STR BGP_STR + "Configure BGP SNMP\n" + "Configure SNMP traps for BGP\n" + "Configure use of rfc4273 SNMP traps for BGP\n") +{ + if (no) { + UNSET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273); + return CMD_SUCCESS; + } + SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273); + return CMD_SUCCESS; +} + +DEFPY(bgp_snmp_traps_bgp4_mibv2, bgp_snmp_traps_bgp4_mibv2_cmd, + "[no$no] bgp snmp traps bgp4-mibv2", + NO_STR BGP_STR + "Configure BGP SNMP\n" + "Configure SNMP traps for BGP\n" + "Configure use of BGP4-MIBv2 SNMP traps for BGP\n") +{ + if (no) { + UNSET_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2); + return CMD_SUCCESS; + } + SET_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2); + return CMD_SUCCESS; +} + +static void bgp_snmp_traps_init(void) +{ + install_element(CONFIG_NODE, &bgp_snmp_traps_rfc4273_cmd); + install_element(CONFIG_NODE, &bgp_snmp_traps_bgp4_mibv2_cmd); + + SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273); + /* BGP4MIBv2 traps are disabled by default */ +} + +int bgp_cli_snmp_traps_config_write(struct vty *vty) +{ + int write = 0; + + if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273)) { + vty_out(vty, "no bgp snmp traps rfc4273\n"); + write++; + } + if (CHECK_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2)) { + vty_out(vty, "bgp snmp traps bgp4-mibv2\n"); + write++; + } + + return write; +} + +int bgpTrapEstablished(struct peer *peer) +{ + if (CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273)) + bgp4TrapEstablished(peer); + + if (CHECK_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2)) + bgpv2TrapEstablished(peer); + + return 0; +} + +int bgpTrapBackwardTransition(struct peer *peer) +{ + if (CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273)) + bgp4TrapBackwardTransition(peer); + + if (CHECK_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2)) + bgpv2TrapBackwardTransition(peer); + + return 0; +} static int bgp_snmp_init(struct event_loop *tm) { smux_init(tm); + bgp_snmp_traps_init(); bgp_snmp_bgp4_init(tm); bgp_snmp_bgp4v2_init(tm); bgp_mpls_l3vpn_module_init(); @@ -44,6 +127,8 @@ static int bgp_snmp_module_init(void) hook_register(peer_status_changed, bgpTrapEstablished); hook_register(peer_backward_transition, bgpTrapBackwardTransition); hook_register(frr_late_init, bgp_snmp_init); + hook_register(bgp_snmp_traps_config_write, + bgp_cli_snmp_traps_config_write); return 0; } diff --git a/bgpd/bgp_snmp.h b/bgpd/bgp_snmp.h index d324782..12ec652 100644 --- a/bgpd/bgp_snmp.h +++ b/bgpd/bgp_snmp.h @@ -15,4 +15,7 @@ #define IPADDRESS ASN_IPADDRESS #define GAUGE32 ASN_UNSIGNED +extern int bgpTrapEstablished(struct peer *peer); +extern int bgpTrapBackwardTransition(struct peer *peer); + #endif /* _FRR_BGP_SNMP_H_ */ diff --git a/bgpd/bgp_snmp_bgp4.c b/bgpd/bgp_snmp_bgp4.c index 692e232..3d04dc2 100644 --- a/bgpd/bgp_snmp_bgp4.c +++ b/bgpd/bgp_snmp_bgp4.c @@ -757,7 +757,7 @@ static struct variable bgp_variables[] = { {6, 1, 14}}, }; -int bgpTrapEstablished(struct peer *peer) +int bgp4TrapEstablished(struct peer *peer) { int ret; struct in_addr addr; @@ -782,7 +782,7 @@ int bgpTrapEstablished(struct peer *peer) return 0; } -int bgpTrapBackwardTransition(struct peer *peer) +int bgp4TrapBackwardTransition(struct peer *peer) { int ret; struct in_addr addr; diff --git a/bgpd/bgp_snmp_bgp4.h b/bgpd/bgp_snmp_bgp4.h index ccf00d6..67f7cc6 100644 --- a/bgpd/bgp_snmp_bgp4.h +++ b/bgpd/bgp_snmp_bgp4.h @@ -69,8 +69,8 @@ #define BGP4PATHATTRBEST 13 #define BGP4PATHATTRUNKNOWN 14 -extern int bgpTrapEstablished(struct peer *peer); -extern int bgpTrapBackwardTransition(struct peer *peer); +extern int bgp4TrapEstablished(struct peer *peer); +extern int bgp4TrapBackwardTransition(struct peer *peer); extern int bgp_snmp_bgp4_init(struct event_loop *tm); #endif /* _FRR_BGP_SNMP_BGP4_H_ */ diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c index f022284..0c8ed33 100644 --- a/bgpd/bgp_snmp_bgp4v2.c +++ b/bgpd/bgp_snmp_bgp4v2.c @@ -32,6 +32,7 @@ SNMP_LOCAL_VARIABLES static oid bgpv2_oid[] = {BGP4V2MIB}; +static oid bgpv2_trap_oid[] = { BGP4V2MIB, 0 }; static struct in_addr bgp_empty_addr = {}; static struct peer *peer_lookup_all_vrf(struct ipaddr *addr) @@ -435,7 +436,6 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, struct bgp_path_info *path, *min; struct bgp_dest *dest; union sockunion su; - unsigned int len; struct ipaddr paddr = {}; size_t namelen = v ? v->namelen : BGP4V2_NLRI_ENTRY_OFFSET; sa_family_t family; @@ -445,20 +445,28 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, size_t afi_len; long prefix_type = 0; long peer_addr_type = 0; + long nrli_index = 1; + long cur_index = 0; /* Bgp4V2AddressFamilyIdentifierTC limited to IPv6 */ if (name[namelen - 1] > IANA_AFI_IPV6) return NULL; afi = afi_iana2int(name[namelen - 1]); afi_len = afi == AFI_IP ? IN_ADDR_SIZE : IN6_ADDR_SIZE; + assert(IS_VALID_AFI(afi)); #define BGP_NLRI_ENTRY_OFFSET namelen +#define BGP4V2_NLRI_V4_V4_OFFSET IN_ADDR_SIZE + IN_ADDR_SIZE + 5 +#define BGP4V2_NLRI_V4_V6_OFFSET IN_ADDR_SIZE + IN6_ADDR_SIZE + 5 +#define BGP4V2_NLRI_V6_V6_OFFSET IN6_ADDR_SIZE + IN6_ADDR_SIZE + 5 sockunion_init(&su); if (exact) { - if (*length - namelen != BGP_NLRI_ENTRY_OFFSET) + if (*length - namelen != BGP4V2_NLRI_V4_V4_OFFSET && + *length - namelen != BGP4V2_NLRI_V4_V6_OFFSET && + *length - namelen != BGP4V2_NLRI_V6_V6_OFFSET) return NULL; /* Set OID offset for prefix type */ @@ -502,12 +510,17 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, su.sin.sin_family = family; /* get bgp4V2PeerRemoteAddr*/ - if (family == AF_INET) + if (family == AF_INET) { oid2in_addr(offset, IN_ADDR_SIZE, &su.sin.sin_addr); - else + offset += IN_ADDR_SIZE; + } else { oid2in6_addr(offset, &su.sin6.sin6_addr); + offset += IN6_ADDR_SIZE; + } - /* bgp4V2NlriIndex currently ignored */ + /* bgp4V2NlriIndex */ + nrli_index = *offset; + offset++; /* Lookup node */ dest = bgp_node_lookup(bgp->rib[afi][safi], addr); @@ -515,8 +528,11 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, for (path = bgp_dest_get_bgp_path_info(dest); path; path = path->next) if (sockunion_same(&path->peer->connection->su, - &su)) - return path; + &su)) { + cur_index++; + if (cur_index == nrli_index) + return path; + } bgp_dest_unlock_node(dest); } @@ -527,11 +543,9 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, /* Set OID offset for prefix type */ offset = name + namelen; offsetlen = *length - namelen; - len = offsetlen; if (offsetlen == 0) { dest = bgp_table_top(bgp->rib[afi][SAFI_UNICAST]); - safi = SAFI_UNICAST; } else { /* bgp4V2NlriAfi is already get */ @@ -571,18 +585,13 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, offsetlen--; /* get node */ - dest = bgp_node_get(bgp->rib[afi][safi], addr); + dest = bgp_node_lookup(bgp->rib[afi][safi], addr); } if (!dest) return NULL; if (offsetlen > 0) { - len = offsetlen; - if (len > afi_len) - len = afi_len; - - /* get bgp4V2PeerRemoteAddrType */ peer_addr_type = *offset; if (peer_addr_type == IANA_AFI_IPV4) @@ -591,10 +600,17 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, family = AF_INET6; offset++; - if (family == AF_INET) + if (family == AF_INET) { oid2in_addr(offset, IN_ADDR_SIZE, &paddr.ip._v4_addr); - else + offset += IN_ADDR_SIZE; + } else { oid2in6_addr(offset, &paddr.ip._v6_addr); + offset += IN6_ADDR_SIZE; + } + /* get bgp4V2NlriIndex */ + nrli_index = *offset; + offset++; + } else { /* default case start with ipv4*/ if (afi == AFI_IP) @@ -602,11 +618,13 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, else family = AF_INET6; memset(&paddr.ip, 0, sizeof(paddr.ip)); + nrli_index = 1; } do { min = NULL; min_family = 0; + cur_index = 0; for (path = bgp_dest_get_bgp_path_info(dest); path; path = path->next) { @@ -616,19 +634,44 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, if (path_family < family) continue; - if (family == AF_INET - && IPV4_ADDR_CMP(&paddr.ip._v4_addr, - &path->peer->connection->su.sin.sin_addr) - >= 0) + if (family == AF_INET && + IPV4_ADDR_CMP(&paddr.ip._v4_addr, + &path->peer->connection->su.sin + .sin_addr) > 0) + continue; + else if (family == AF_INET6 && + IPV6_ADDR_CMP(&paddr.ip._v6_addr, + &path->peer->connection->su.sin6 + .sin6_addr) > 0) + continue; + + if (family == AF_INET && + IPV4_ADDR_CMP(&paddr.ip._v4_addr, + &path->peer->connection->su.sin + .sin_addr) == 0) { + if (cur_index == nrli_index) { + min = path; + min_family = family; + nrli_index++; + break; + } + cur_index++; continue; - else if (family == AF_INET6 - && IPV6_ADDR_CMP( - &paddr.ip._v6_addr, - &path->peer->connection->su.sin6.sin6_addr) - >= 0) + } else if (family == AF_INET6 && + IPV6_ADDR_CMP(&paddr.ip._v6_addr, + &path->peer->connection->su + .sin6.sin6_addr) == 0) { + if (cur_index == nrli_index) { + min = path; + min_family = family; + nrli_index++; + break; + } + cur_index++; continue; + } - /* first valid path its the min*/ + /* first valid path its the min peer addr*/ if (!min) { min = path; min_family = path_family; @@ -704,7 +747,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, /* Encode bgp4V2NlriIndex*/ - *offset = 1; + *offset = nrli_index; offset++; *length = offset - name; @@ -718,6 +761,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length, } memset(&paddr.ip, 0, sizeof(paddr.ip)); + nrli_index = 1; } while ((dest = bgp_route_next(dest))); @@ -896,6 +940,37 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[], return NULL; } +/* BGP V2 Traps. */ +static struct trap_object bgpv2TrapEstListv4[] = { + { 6, { 1, 2, 1, BGP4V2_PEER_STATE, 1, 1 } }, + { 6, { 1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 1, 1 } }, + { 6, { 1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 1, 1 } } +}; + +static struct trap_object bgpv2TrapEstListv6[] = { + { 6, { 1, 2, 1, BGP4V2_PEER_STATE, 1, 2 } }, + { 6, { 1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 1, 2 } }, + { 6, { 1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 1, 2 } } +}; + +static struct trap_object bgpv2TrapBackListv4[] = { + { 6, { 1, 2, 1, BGP4V2_PEER_STATE, 1, 1 } }, + { 6, { 1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 1, 1 } }, + { 6, { 1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 1, 1 } }, + { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, 1, 1 } }, + { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, 1, 1 } }, + { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, 1, 1 } } +}; + +static struct trap_object bgpv2TrapBackListv6[] = { + { 6, { 1, 2, 1, BGP4V2_PEER_STATE, 1, 2 } }, + { 6, { 1, 2, 1, BGP4V2_PEER_LOCAL_PORT, 1, 2 } }, + { 6, { 1, 2, 1, BGP4V2_PEER_REMOTE_PORT, 1, 2 } }, + { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, 1, 2 } }, + { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, 1, 2 } }, + { 6, { 1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, 1, 2 } } +}; + static struct variable bgpv2_variables[] = { /* bgp4V2PeerEntry */ {BGP4V2_PEER_INSTANCE, @@ -1515,6 +1590,79 @@ static struct variable bgpv2_variables[] = { {1, 9, 1, BGP4V2_NLRI_PATH_ATTR_UNKNOWN, 1, 2}}, }; +int bgpv2TrapEstablished(struct peer *peer) +{ + oid index[sizeof(oid) * IN6_ADDR_SIZE]; + size_t length; + + if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2)) + return 0; + + /* Check if this peer just went to Established */ + if ((peer->connection->ostatus != OpenConfirm) || + !(peer_established(peer->connection))) + return 0; + + switch (sockunion_family(&peer->connection->su)) { + case AF_INET: + oid_copy_in_addr(index, &peer->connection->su.sin.sin_addr); + length = IN_ADDR_SIZE; + smux_trap(bgpv2_variables, array_size(bgpv2_variables), + bgpv2_trap_oid, array_size(bgpv2_trap_oid), bgpv2_oid, + sizeof(bgpv2_oid) / sizeof(oid), index, length, + bgpv2TrapEstListv4, array_size(bgpv2TrapEstListv4), + BGP4V2ESTABLISHED); + break; + case AF_INET6: + oid_copy_in6_addr(index, &peer->connection->su.sin6.sin6_addr); + length = IN6_ADDR_SIZE; + smux_trap(bgpv2_variables, array_size(bgpv2_variables), + bgpv2_trap_oid, array_size(bgpv2_trap_oid), bgpv2_oid, + sizeof(bgpv2_oid) / sizeof(oid), index, length, + bgpv2TrapEstListv6, array_size(bgpv2TrapEstListv6), + BGP4V2ESTABLISHED); + break; + default: + break; + } + + return 0; +} + +int bgpv2TrapBackwardTransition(struct peer *peer) +{ + oid index[sizeof(oid) * IN6_ADDR_SIZE]; + size_t length; + + if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_BGP4MIBV2)) + return 0; + + switch (sockunion_family(&peer->connection->su)) { + case AF_INET: + oid_copy_in_addr(index, &peer->connection->su.sin.sin_addr); + length = IN_ADDR_SIZE; + smux_trap(bgpv2_variables, array_size(bgpv2_variables), + bgpv2_trap_oid, array_size(bgpv2_trap_oid), bgpv2_oid, + sizeof(bgpv2_oid) / sizeof(oid), index, length, + bgpv2TrapBackListv4, array_size(bgpv2TrapBackListv4), + BGP4V2BACKWARDTRANSITION); + break; + case AF_INET6: + oid_copy_in6_addr(index, &peer->connection->su.sin6.sin6_addr); + length = IN6_ADDR_SIZE; + smux_trap(bgpv2_variables, array_size(bgpv2_variables), + bgpv2_trap_oid, array_size(bgpv2_trap_oid), bgpv2_oid, + sizeof(bgpv2_oid) / sizeof(oid), index, length, + bgpv2TrapBackListv6, array_size(bgpv2TrapBackListv6), + BGP4V2BACKWARDTRANSITION); + break; + default: + break; + } + + return 0; +} + int bgp_snmp_bgp4v2_init(struct event_loop *tm) { REGISTER_MIB("mibII/bgpv2", bgpv2_variables, variable, bgpv2_oid); diff --git a/bgpd/bgp_snmp_bgp4v2.h b/bgpd/bgp_snmp_bgp4v2.h index 6587a82..ca35533 100644 --- a/bgpd/bgp_snmp_bgp4v2.h +++ b/bgpd/bgp_snmp_bgp4v2.h @@ -16,6 +16,14 @@ * offset 1.3.6.1.3.5.1.1.2.1.x.(1|2).(4|16) = 13 * offset 1.3.6.1.4.1.7336.3.2.1.1.2.1.x.1.(1|2) = 16 */ + + +/* bgpTraps */ +#define BGP4V2ESTABLISHED 1 +#define BGP4V2BACKWARDTRANSITION 2 + +/* bgpPeerTable */ + #define BGP4V2_PEER_ENTRY_OFFSET 13 #define BGP4V2_PEER_INSTANCE 1 #define BGP4V2_PEER_LOCAL_ADDR_TYPE 2 @@ -84,5 +92,7 @@ #define BGP4V2_BACKWARD_TRANSITION_NOTIFICATION 2 extern int bgp_snmp_bgp4v2_init(struct event_loop *tm); +extern int bgpv2TrapEstablished(struct peer *peer); +extern int bgpv2TrapBackwardTransition(struct peer *peer); #endif /* _FRR_BGP_SNMP_BGP4V2_H_ */ diff --git a/bgpd/bgp_trace.h b/bgpd/bgp_trace.h index 964393a..a77a25e 100644 --- a/bgpd/bgp_trace.h +++ b/bgpd/bgp_trace.h @@ -135,11 +135,12 @@ TRACEPOINT_LOGLEVEL(frr_bgp, bmp_mirror_packet, TRACE_INFO) TRACEPOINT_EVENT( frr_bgp, bmp_eor, - TP_ARGS(afi_t, afi, safi_t, safi, uint8_t, flags), + TP_ARGS(afi_t, afi, safi_t, safi, uint8_t, flags, uint8_t, peer_type_flag), TP_FIELDS( ctf_integer(afi_t, afi, afi) ctf_integer(safi_t, safi, safi) ctf_integer(uint8_t, flags, flags) + ctf_integer(uint8_t, peer_type_flag, peer_type_flag) ) ) @@ -307,7 +308,8 @@ TRACEPOINT_EVENT( struct in_addr, vtep, esi_t *, esi), TP_FIELDS( ctf_string(action, add ? "add" : "del") - ctf_integer(vni_t, vni, vpn->vni) + ctf_integer(vni_t, vni, (vpn ? vpn->vni : 0)) + ctf_integer(uint32_t, eth_tag, &pfx->prefix.macip_addr.eth_tag) ctf_array(unsigned char, mac, &pfx->prefix.macip_addr.mac, sizeof(struct ethaddr)) ctf_array(unsigned char, ip, &pfx->prefix.macip_addr.ip, @@ -325,7 +327,7 @@ TRACEPOINT_EVENT( const struct prefix_evpn *, pfx), TP_FIELDS( ctf_string(action, add ? "add" : "del") - ctf_integer(vni_t, vni, vpn->vni) + ctf_integer(vni_t, vni, (vpn ? vpn->vni : 0)) ctf_integer_network_hex(unsigned int, vtep, pfx->prefix.imet_addr.ip.ipaddr_v4.s_addr) ) @@ -436,6 +438,64 @@ TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_local_es_evi_del_zrecv, TRACE_INFO) TRACEPOINT_EVENT( frr_bgp, + evpn_mh_es_evi_vtep_add, + TP_ARGS(esi_t *, esi, vni_t, vni, struct in_addr, vtep, + uint8_t, ead_es), + TP_FIELDS( + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + ctf_integer(vni_t, vni, vni) + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + ctf_integer(uint8_t, ead_es, ead_es) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_es_evi_vtep_add, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_mh_es_evi_vtep_del, + TP_ARGS(esi_t *, esi, vni_t, vni, struct in_addr, vtep, + uint8_t, ead_es), + TP_FIELDS( + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + ctf_integer(vni_t, vni, vni) + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + ctf_integer(uint8_t, ead_es, ead_es) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_es_evi_vtep_del, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_mh_local_ead_es_evi_route_upd, + TP_ARGS(esi_t *, esi, vni_t, vni, + uint8_t, route_type, + struct in_addr, vtep), + TP_FIELDS( + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + ctf_integer(vni_t, vni, vni) + ctf_integer(uint8_t, route_type, route_type) + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_local_ead_es_evi_route_upd, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_mh_local_ead_es_evi_route_del, + TP_ARGS(esi_t *, esi, vni_t, vni, + uint8_t, route_type, + struct in_addr, vtep), + TP_FIELDS( + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + ctf_integer(vni_t, vni, vni) + ctf_integer(uint8_t, route_type, route_type) + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_local_ead_es_evi_route_del, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, evpn_local_vni_add_zrecv, TP_ARGS(vni_t, vni, struct in_addr, vtep, vrf_id_t, vrf, struct in_addr, mc_grp), @@ -496,6 +556,34 @@ TRACEPOINT_LOGLEVEL(frr_bgp, evpn_local_macip_del_zrecv, TRACE_INFO) TRACEPOINT_EVENT( frr_bgp, + evpn_advertise_type5, + TP_ARGS(vrf_id_t, vrf, const struct prefix_evpn *, pfx, + struct ethaddr *, rmac, struct in_addr, vtep), + TP_FIELDS( + ctf_integer(int, vrf_id, vrf) + ctf_array(unsigned char, ip, &pfx->prefix.prefix_addr.ip, + sizeof(struct ipaddr)) + ctf_array(unsigned char, rmac, rmac, + sizeof(struct ethaddr)) + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_advertise_type5, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_withdraw_type5, + TP_ARGS(vrf_id_t, vrf, const struct prefix_evpn *, pfx), + TP_FIELDS( + ctf_integer(int, vrf_id, vrf) + ctf_array(unsigned char, ip, &pfx->prefix.prefix_addr.ip, + sizeof(struct ipaddr)) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_withdraw_type5, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, evpn_local_l3vni_add_zrecv, TP_ARGS(vni_t, vni, vrf_id_t, vrf, struct ethaddr *, svi_rmac, diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index a2006c3..d13515a 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -128,6 +128,7 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi, dst->bgp = src->bgp; dst->sort = src->sort; + dst->sub_sort = src->sub_sort; dst->as = src->as; dst->v_routeadv = src->v_routeadv; dst->flags = src->flags; @@ -342,6 +343,7 @@ static unsigned int updgrp_hash_key_make(const void *p) key = 0; key = jhash_1word(peer->sort, key); /* EBGP or IBGP */ + key = jhash_1word(peer->sub_sort, key); /* OAD */ key = jhash_1word((peer->flags & PEER_UPDGRP_FLAGS), key); key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key); key = jhash_1word((uint32_t)peer->addpath_type[afi][safi], key); @@ -447,19 +449,18 @@ static unsigned int updgrp_hash_key_make(const void *p) * STATEMENT STAYS UP TO DATE */ if (bgp_debug_neighbor_events(peer)) { - zlog_debug( - "%pBP Update Group Hash: sort: %d UpdGrpFlags: %ju UpdGrpAFFlags: %ju", - peer, peer->sort, - (intmax_t)CHECK_FLAG(peer->flags, PEER_UPDGRP_FLAGS), - (intmax_t)CHECK_FLAG(flags, PEER_UPDGRP_AF_FLAGS)); - zlog_debug( - "%pBP Update Group Hash: addpath: %u UpdGrpCapFlag: %u UpdGrpCapAFFlag: %u route_adv: %u change local as: %u, as_path_loop_detection: %d", - peer, (uint32_t)peer->addpath_type[afi][safi], - CHECK_FLAG(peer->cap, PEER_UPDGRP_CAP_FLAGS), - CHECK_FLAG(peer->af_cap[afi][safi], - PEER_UPDGRP_AF_CAP_FLAGS), - peer->v_routeadv, peer->change_local_as, - peer->as_path_loop_detection); + zlog_debug("%pBP Update Group Hash: sort: %d sub_sort: %d UpdGrpFlags: %ju UpdGrpAFFlags: %ju", + peer, peer->sort, peer->sub_sort, + (intmax_t)CHECK_FLAG(peer->flags, PEER_UPDGRP_FLAGS), + (intmax_t)CHECK_FLAG(flags, PEER_UPDGRP_AF_FLAGS)); + zlog_debug("%pBP Update Group Hash: addpath: %u UpdGrpCapFlag: %ju UpdGrpCapAFFlag: %u route_adv: %u change local as: %u, as_path_loop_detection: %d", + peer, (uint32_t)peer->addpath_type[afi][safi], + (intmax_t)CHECK_FLAG(peer->cap, + PEER_UPDGRP_CAP_FLAGS), + CHECK_FLAG(peer->af_cap[afi][safi], + PEER_UPDGRP_AF_CAP_FLAGS), + peer->v_routeadv, peer->change_local_as, + peer->as_path_loop_detection); 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], @@ -1698,14 +1699,14 @@ static int updgrp_policy_update_walkcb(struct update_group *updgrp, void *arg) */ UNSET_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE); - subgroup_default_originate(subgrp, 0); + subgroup_default_originate(subgrp, false); } else { /* * This is a explicit withdraw, since the * routemap is not present in routemap lib. need - * to pass 1 for withdraw arg. + * to pass `true` for withdraw arg. */ - subgroup_default_originate(subgrp, 1); + subgroup_default_originate(subgrp, true); } } update_subgroup_set_needs_refresh(subgrp, 0); @@ -2101,7 +2102,7 @@ update_group_default_originate_route_map_walkcb(struct update_group *updgrp, */ UNSET_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE); - subgroup_default_originate(subgrp, 0); + subgroup_default_originate(subgrp, false); } } diff --git a/bgpd/bgp_updgrp.h b/bgpd/bgp_updgrp.h index 0d866f3..5e8b537 100644 --- a/bgpd/bgp_updgrp.h +++ b/bgpd/bgp_updgrp.h @@ -40,17 +40,16 @@ (PEER_FLAG_LOCAL_AS_NO_PREPEND | PEER_FLAG_LOCAL_AS_REPLACE_AS) #define PEER_UPDGRP_AF_FLAGS \ - (PEER_FLAG_SEND_COMMUNITY | PEER_FLAG_SEND_EXT_COMMUNITY \ - | PEER_FLAG_SEND_LARGE_COMMUNITY \ - | PEER_FLAG_DEFAULT_ORIGINATE | PEER_FLAG_REFLECTOR_CLIENT \ - | PEER_FLAG_RSERVER_CLIENT | PEER_FLAG_NEXTHOP_SELF \ - | PEER_FLAG_NEXTHOP_UNCHANGED | PEER_FLAG_FORCE_NEXTHOP_SELF \ - | PEER_FLAG_AS_PATH_UNCHANGED | PEER_FLAG_MED_UNCHANGED \ - | PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED | PEER_FLAG_REMOVE_PRIVATE_AS \ - | PEER_FLAG_REMOVE_PRIVATE_AS_ALL \ - | PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE \ - | PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE \ - | PEER_FLAG_AS_OVERRIDE) + (PEER_FLAG_SEND_COMMUNITY | PEER_FLAG_SEND_EXT_COMMUNITY | \ + PEER_FLAG_SEND_EXT_COMMUNITY_RPKI | PEER_FLAG_SEND_LARGE_COMMUNITY | \ + PEER_FLAG_DEFAULT_ORIGINATE | PEER_FLAG_REFLECTOR_CLIENT | \ + PEER_FLAG_RSERVER_CLIENT | PEER_FLAG_NEXTHOP_SELF | \ + PEER_FLAG_NEXTHOP_UNCHANGED | PEER_FLAG_FORCE_NEXTHOP_SELF | \ + PEER_FLAG_AS_PATH_UNCHANGED | PEER_FLAG_MED_UNCHANGED | \ + PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED | PEER_FLAG_REMOVE_PRIVATE_AS | \ + PEER_FLAG_REMOVE_PRIVATE_AS_ALL | \ + PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE | \ + PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE | PEER_FLAG_AS_OVERRIDE) #define PEER_UPDGRP_CAP_FLAGS (PEER_CAP_AS4_RCV) @@ -428,7 +427,7 @@ extern void subgroup_announce_route(struct update_subgroup *subgrp); extern void subgroup_announce_all(struct update_subgroup *subgrp); extern void subgroup_default_originate(struct update_subgroup *subgrp, - int withdraw); + bool withdraw); extern void group_announce_route(struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_dest *dest, struct bgp_path_info *pi); @@ -442,7 +441,7 @@ extern struct bgp_adj_out *bgp_adj_out_alloc(struct update_subgroup *subgrp, extern void bgp_adj_out_remove_subgroup(struct bgp_dest *dest, struct bgp_adj_out *adj, struct update_subgroup *subgrp); -extern void bgp_adj_out_set_subgroup(struct bgp_dest *dest, +extern bool bgp_adj_out_set_subgroup(struct bgp_dest *dest, struct update_subgroup *subgrp, struct attr *attr, struct bgp_path_info *path); diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index ccbb23e..267a756 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -198,9 +198,8 @@ static int group_announce_route_walkcb(struct update_group *updgrp, void *arg) addpath_capable = bgp_addpath_encode_tx(peer, afi, safi); if (BGP_DEBUG(update, UPDATE_OUT)) - zlog_debug("%s: afi=%s, safi=%s, p=%pRN", __func__, - afi2str(afi), safi2str(safi), - bgp_dest_to_rnode(ctx->dest)); + zlog_debug("%s: afi=%s, safi=%s, p=%pBD", __func__, + afi2str(afi), safi2str(safi), ctx->dest); UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) { /* @@ -479,7 +478,7 @@ bgp_advertise_clean_subgroup(struct update_subgroup *subgrp, bgp_advertise_delete(baa, adv); /* Fetch next advertise candidate. */ - next = baa->adv; + next = bgp_advertise_attr_fifo_first(&baa->fifo); /* Unintern BGP advertise attribute. */ bgp_advertise_attr_unintern(subgrp->hash, baa); @@ -497,7 +496,7 @@ bgp_advertise_clean_subgroup(struct update_subgroup *subgrp, return next; } -void bgp_adj_out_set_subgroup(struct bgp_dest *dest, +bool bgp_adj_out_set_subgroup(struct bgp_dest *dest, struct update_subgroup *subgrp, struct attr *attr, struct bgp_path_info *path) { @@ -517,7 +516,7 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest, bgp = SUBGRP_INST(subgrp); if (DISABLE_BGP_ANNOUNCE) - return; + return false; /* Look for adjacency information. */ adj = adj_lookup( @@ -533,7 +532,7 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest, bgp_addpath_id_for_peer(peer, afi, safi, &path->tx_addpath)); if (!adj) - return; + return false; subgrp->pscount++; } @@ -572,7 +571,7 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest, * will never be able to coalesce the 3rd peer down */ subgrp->version = MAX(subgrp->version, dest->version); - return; + return false; } if (adj->adv) @@ -620,6 +619,8 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest, bgp_adv_fifo_add_tail(&subgrp->sync->update, adv); subgrp->version = MAX(subgrp->version, dest->version); + + return true; } /* The only time 'withdraw' will be false is if we are sending @@ -734,7 +735,7 @@ void subgroup_announce_table(struct update_subgroup *subgrp, if (safi != SAFI_MPLS_VPN && safi != SAFI_ENCAP && safi != SAFI_EVPN && CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)) - subgroup_default_originate(subgrp, 0); + subgroup_default_originate(subgrp, false); subgrp->pscount = 0; SET_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING); @@ -826,11 +827,12 @@ void subgroup_announce_route(struct update_subgroup *subgrp) } } -void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) +void subgroup_default_originate(struct update_subgroup *subgrp, bool withdraw) { struct bgp *bgp; - struct attr attr; + struct attr attr = { 0 }; struct attr *new_attr = &attr; + struct aspath *aspath; struct prefix p; struct peer *from; struct bgp_dest *dest; @@ -868,6 +870,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) /* make coverity happy */ assert(attr.aspath); + aspath = attr.aspath; attr.med = 0; attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC); @@ -915,8 +918,8 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) bgp_attr_flush(new_attr); new_attr = bgp_attr_intern( tmp_pi.attr); - bgp_attr_flush(tmp_pi.attr); } + bgp_attr_flush(tmp_pi.attr); subgroup_announce_reset_nhop( (peer_cap_enhe(peer, afi, safi) ? AF_INET6 @@ -941,7 +944,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) SUBGRP_STATUS_DEFAULT_ORIGINATE))) SET_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE); - withdraw = 1; + withdraw = true; } } @@ -968,18 +971,19 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) if (dest) { for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { - if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) - if (subgroup_announce_check( - dest, pi, subgrp, - bgp_dest_get_prefix(dest), - &attr, NULL)) { - struct attr *default_attr = - bgp_attr_intern(&attr); - - bgp_adj_out_set_subgroup( - dest, subgrp, - default_attr, pi); - } + if (!CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) + continue; + + if (subgroup_announce_check(dest, pi, subgrp, + bgp_dest_get_prefix( + dest), + &attr, NULL)) { + if (!bgp_adj_out_set_subgroup(dest, + subgrp, + &attr, pi)) + bgp_attr_flush(&attr); + } else + bgp_attr_flush(&attr); } bgp_dest_unlock_node(dest); } @@ -1023,7 +1027,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) } } - aspath_unintern(&attr.aspath); + aspath_unintern(&aspath); } /* diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c index 0ed1d04..8fe24eb 100644 --- a/bgpd/bgp_vpn.c +++ b/bgpd/bgp_vpn.c @@ -30,8 +30,6 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, int rd_header; int header = 1; json_object *json = NULL; - json_object *json_scode = NULL; - json_object *json_ocode = NULL; json_object *json_adv = NULL; json_object *json_routes = NULL; char rd_str[BUFSIZ]; @@ -47,21 +45,8 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, } if (use_json) { - json_scode = json_object_new_object(); - json_ocode = json_object_new_object(); json = json_object_new_object(); json_adv = json_object_new_object(); - - json_object_string_add(json_scode, "suppressed", "s"); - json_object_string_add(json_scode, "damped", "d"); - json_object_string_add(json_scode, "history", "h"); - json_object_string_add(json_scode, "valid", "*"); - json_object_string_add(json_scode, "best", ">"); - json_object_string_add(json_scode, "internal", "i"); - - json_object_string_add(json_ocode, "igp", "i"); - json_object_string_add(json_ocode, "egp", "e"); - json_object_string_add(json_ocode, "incomplete", "?"); } for (dest = bgp_table_top(bgp->rib[afi][safi]); dest; @@ -117,12 +102,6 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, json_object_int_add( json, "localAS", bgp->as); - json_object_object_add(json, - "bgpStatusCodes", - json_scode); - json_object_object_add(json, - "bgpOriginCodes", - json_ocode); } else { vty_out(vty, "BGP table version is 0, local router ID is %pI4\n", diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index e49baff..9530a66 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -5,6 +5,10 @@ #include <zebra.h> +#ifdef GNU_LINUX +#include <linux/rtnetlink.h> //RT_TABLE_XXX +#endif + #include "command.h" #include "lib/json.h" #include "lib/sockopt.h" @@ -122,12 +126,17 @@ FRR_CFG_DEFAULT_BOOL(BGP_SOFT_VERSION_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 }, +); DEFINE_HOOK(bgp_inst_config_write, (struct bgp *bgp, struct vty *vty), (bgp, vty)); DEFINE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp)); DEFINE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp)); +DEFINE_HOOK(bgp_snmp_traps_config_write, (struct vty * vty), (vty)); static struct peer_group *listen_range_exists(struct bgp *bgp, struct prefix *range, int exact); @@ -310,7 +319,7 @@ static int bgp_srv6_locator_unset(struct bgp *bgp) /* refresh functions */ for (ALL_LIST_ELEMENTS(bgp->srv6_functions, node, nnode, func)) { listnode_delete(bgp->srv6_functions, func); - XFREE(MTYPE_BGP_SRV6_FUNCTION, func); + srv6_function_free(func); } /* refresh tovpn_sid */ @@ -614,6 +623,8 @@ 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_ENFORCE_FIRST_AS) + SET_FLAG((*bgp)->flags, BGP_FLAG_ENFORCE_FIRST_AS); ret = BGP_SUCCESS; } @@ -1591,8 +1602,9 @@ DEFUN_NOSH (router_bgp, * - update asnotation if explicitly mentioned */ if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) { - XFREE(MTYPE_BGP, bgp->as_pretty); - bgp->as_pretty = XSTRDUP(MTYPE_BGP, argv[idx_asn]->arg); + XFREE(MTYPE_BGP_NAME, bgp->as_pretty); + bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, + argv[idx_asn]->arg); if (!CHECK_FLAG(bgp->config, BGP_CONFIG_ASNOTATION) && asnotation != ASNOTATION_UNDEFINED) { SET_FLAG(bgp->config, BGP_CONFIG_ASNOTATION); @@ -2827,6 +2839,23 @@ DEFUN(no_bgp_ebgp_requires_policy, no_bgp_ebgp_requires_policy_cmd, return CMD_SUCCESS; } +DEFPY(bgp_enforce_first_as, + bgp_enforce_first_as_cmd, + "[no] bgp enforce-first-as", + NO_STR + BGP_STR + "Enforce the first AS for EBGP routes\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + if (no) + UNSET_FLAG(bgp->flags, BGP_FLAG_ENFORCE_FIRST_AS); + else + SET_FLAG(bgp->flags, BGP_FLAG_ENFORCE_FIRST_AS); + + return CMD_SUCCESS; +} + DEFPY(bgp_lu_uses_explicit_null, bgp_lu_uses_explicit_null_cmd, "[no] bgp labeled-unicast <explicit-null|ipv4-explicit-null|ipv6-explicit-null>$value", NO_STR BGP_STR @@ -3231,6 +3260,8 @@ DEFUN (bgp_graceful_restart_disable, GR_DISABLE) { int ret = BGP_GR_FAILURE; + struct listnode *node, *nnode; + struct peer *peer; if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) zlog_debug( @@ -3249,6 +3280,15 @@ DEFUN (bgp_graceful_restart_disable, 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); + } + return bgp_vty_return(vty, ret); } @@ -5706,6 +5746,37 @@ DEFUN (no_neighbor_dont_capability_negotiate, PEER_FLAG_DONT_CAPABILITY); } +/* neighbor capability fqdn */ +DEFPY (neighbor_capability_fqdn, + neighbor_capability_fqdn_cmd, + "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor capability fqdn", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Advertise capability to the peer\n" + "Advertise fqdn capability to the peer\n") +{ + struct peer *peer; + int ret; + + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + if (no) + ret = peer_flag_unset_vty(vty, neighbor, + PEER_FLAG_CAPABILITY_FQDN); + else + ret = peer_flag_set_vty(vty, neighbor, + PEER_FLAG_CAPABILITY_FQDN); + + bgp_capability_send(peer, AFI_IP, SAFI_UNICAST, CAPABILITY_CODE_FQDN, + no ? CAPABILITY_ACTION_UNSET + : CAPABILITY_ACTION_SET); + + return ret; +} + /* neighbor capability extended next hop encoding */ DEFUN (neighbor_capability_enhe, neighbor_capability_enhe_cmd, @@ -5831,24 +5902,37 @@ DEFUN (neighbor_capability_orf_prefix, 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, peer_str); if (!peer) return CMD_WARNING_CONFIG_FAILED; - if (strmatch(argv[idx_send_recv]->text, "send")) - return peer_af_flag_set_vty(vty, peer_str, afi, safi, - PEER_FLAG_ORF_PREFIX_SM); + if (strmatch(argv[idx_send_recv]->text, "send")) { + ret = peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_SM); + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF, + CAPABILITY_ACTION_SET); + return ret; + } - if (strmatch(argv[idx_send_recv]->text, "receive")) - return peer_af_flag_set_vty(vty, peer_str, afi, safi, - PEER_FLAG_ORF_PREFIX_RM); + if (strmatch(argv[idx_send_recv]->text, "receive")) { + ret = peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_RM); + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF, + CAPABILITY_ACTION_SET); + return ret; + } - if (strmatch(argv[idx_send_recv]->text, "both")) - return peer_af_flag_set_vty(vty, peer_str, afi, safi, - PEER_FLAG_ORF_PREFIX_SM) - | peer_af_flag_set_vty(vty, peer_str, afi, safi, - PEER_FLAG_ORF_PREFIX_RM); + if (strmatch(argv[idx_send_recv]->text, "both")) { + ret = peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_SM) | + peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_RM); + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF, + CAPABILITY_ACTION_SET); + return ret; + } return CMD_WARNING_CONFIG_FAILED; } @@ -5883,24 +5967,37 @@ DEFUN (no_neighbor_capability_orf_prefix, 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, peer_str); if (!peer) return CMD_WARNING_CONFIG_FAILED; - if (strmatch(argv[idx_send_recv]->text, "send")) - return peer_af_flag_unset_vty(vty, peer_str, afi, safi, - PEER_FLAG_ORF_PREFIX_SM); + if (strmatch(argv[idx_send_recv]->text, "send")) { + ret = peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_SM); + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF, + CAPABILITY_ACTION_UNSET); + return ret; + } - if (strmatch(argv[idx_send_recv]->text, "receive")) - return peer_af_flag_unset_vty(vty, peer_str, afi, safi, - PEER_FLAG_ORF_PREFIX_RM); + if (strmatch(argv[idx_send_recv]->text, "receive")) { + ret = peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_RM); + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF, + CAPABILITY_ACTION_UNSET); + return ret; + } - if (strmatch(argv[idx_send_recv]->text, "both")) - return peer_af_flag_unset_vty(vty, peer_str, afi, safi, - PEER_FLAG_ORF_PREFIX_SM) - | peer_af_flag_unset_vty(vty, peer_str, afi, safi, - PEER_FLAG_ORF_PREFIX_RM); + if (strmatch(argv[idx_send_recv]->text, "both")) { + ret = peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_SM) | + peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_ORF_PREFIX_RM); + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ORF, + CAPABILITY_ACTION_UNSET); + return ret; + } return CMD_WARNING_CONFIG_FAILED; } @@ -6387,6 +6484,32 @@ ALIAS_HIDDEN( "Send Standard Community attributes\n" "Send Large Community attributes\n") +DEFPY (neighbor_ecommunity_rpki, + neighbor_ecommunity_rpki_cmd, + "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor send-community extended rpki", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Send Community attribute to this neighbor\n" + "Send Extended Community attributes\n" + "Send RPKI Extended Community attributes\n") +{ + struct peer *peer; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); + + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + if (no) + return peer_af_flag_unset_vty(vty, neighbor, afi, safi, + PEER_FLAG_SEND_EXT_COMMUNITY_RPKI); + else + return peer_af_flag_set_vty(vty, neighbor, afi, safi, + PEER_FLAG_SEND_EXT_COMMUNITY_RPKI); +} + /* neighbor soft-reconfig. */ DEFUN (neighbor_soft_reconfiguration, neighbor_soft_reconfiguration_cmd, @@ -6900,6 +7023,28 @@ DEFPY(no_neighbor_role, return ret; } +DEFPY (neighbor_oad, + neighbor_oad_cmd, + "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor oad", + NO_STR + NEIGHBOR_STR + NEIGHBOR_ADDR_STR2 + "Set peering session type to EBGP-OAD\n") +{ + struct peer *peer; + + peer = peer_and_group_lookup_vty(vty, neighbor); + if (!peer) + return CMD_WARNING_CONFIG_FAILED; + + if (no) + peer->sub_sort = 0; + else if (peer->sort == BGP_PEER_EBGP) + peer->sub_sort = BGP_PEER_EBGP_OAD; + + return CMD_SUCCESS; +} + /* disable-connected-check */ DEFUN (neighbor_disable_connected_check, neighbor_disable_connected_check_cmd, @@ -8840,13 +8985,21 @@ DEFUN(neighbor_disable_addpath_rx, struct peer *peer; afi_t afi = bgp_node_afi(vty); safi_t safi = bgp_node_safi(vty); + int ret; + int action; peer = peer_and_group_lookup_vty(vty, peer_str); if (!peer) return CMD_WARNING_CONFIG_FAILED; - return peer_af_flag_set_vty(vty, peer_str, afi, safi, - PEER_FLAG_DISABLE_ADDPATH_RX); + action = bgp_addpath_capability_action(peer->addpath_type[afi][safi], 0); + + ret = peer_af_flag_set_vty(vty, peer_str, afi, safi, + PEER_FLAG_DISABLE_ADDPATH_RX); + + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ADDPATH, action); + + return ret; } DEFUN(no_neighbor_disable_addpath_rx, @@ -8861,13 +9014,21 @@ DEFUN(no_neighbor_disable_addpath_rx, struct peer *peer; afi_t afi = bgp_node_afi(vty); safi_t safi = bgp_node_safi(vty); + int ret; + int action; peer = peer_and_group_lookup_vty(vty, peer_str); if (!peer) return CMD_WARNING_CONFIG_FAILED; - return peer_af_flag_unset_vty(vty, peer_str, afi, safi, - PEER_FLAG_DISABLE_ADDPATH_RX); + action = bgp_addpath_capability_action(peer->addpath_type[afi][safi], 0); + + ret = peer_af_flag_unset_vty(vty, peer_str, afi, safi, + PEER_FLAG_DISABLE_ADDPATH_RX); + + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ADDPATH, action); + + return ret; } DEFUN (neighbor_addpath_tx_all_paths, @@ -8879,13 +9040,15 @@ DEFUN (neighbor_addpath_tx_all_paths, { int idx_peer = 1; struct peer *peer; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty), - BGP_ADDPATH_ALL, 0); + bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_ALL, 0); + return CMD_SUCCESS; } @@ -8905,20 +9068,20 @@ DEFUN (no_neighbor_addpath_tx_all_paths, { int idx_peer = 2; struct peer *peer; + afi_t afi = bgp_node_afi(vty); + safi_t safi = bgp_node_safi(vty); peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - if (peer->addpath_type[bgp_node_afi(vty)][bgp_node_safi(vty)] - != BGP_ADDPATH_ALL) { + if (peer->addpath_type[afi][safi] != BGP_ADDPATH_ALL) { vty_out(vty, "%% Peer not currently configured to transmit all paths."); return CMD_WARNING_CONFIG_FAILED; } - bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty), - BGP_ADDPATH_NONE, 0); + bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_NONE, 0); return CMD_SUCCESS; } @@ -9298,13 +9461,13 @@ DEFPY (af_rd_vpn_export, bgp_get_default(), bgp); if (yes) { - bgp->vpn_policy[afi].tovpn_rd_pretty = - XSTRDUP(MTYPE_BGP, rd_str); + bgp->vpn_policy[afi].tovpn_rd_pretty = XSTRDUP(MTYPE_BGP_NAME, + rd_str); bgp->vpn_policy[afi].tovpn_rd = prd; SET_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_RD_SET); } else { - XFREE(MTYPE_BGP, bgp->vpn_policy[afi].tovpn_rd_pretty); + XFREE(MTYPE_BGP_NAME, bgp->vpn_policy[afi].tovpn_rd_pretty); UNSET_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_RD_SET); } @@ -9394,7 +9557,7 @@ DEFPY (af_label_vpn_export, "Automatically assign a label\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); - mpls_label_t label = MPLS_LABEL_NONE; + mpls_label_t label = (mpls_label_t)label_val; afi_t afi; int idx = 0; bool yes = true; @@ -9402,24 +9565,28 @@ DEFPY (af_label_vpn_export, if (argv_find(argv, argc, "no", &idx)) yes = false; - /* If "no ...", squash trailing parameter */ - if (!yes) - label_auto = NULL; - - if (yes) { - if (!label_auto) - label = label_val; /* parser should force unsigned */ - } - afi = vpn_policy_getafi(vty, bgp, false); if (afi == AFI_MAX) return CMD_WARNING_CONFIG_FAILED; - - if (label_auto && CHECK_FLAG(bgp->vpn_policy[afi].flags, - BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) - /* no change */ - return CMD_SUCCESS; + if (yes) { + if (label_auto && CHECK_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) + /* no change */ + return CMD_SUCCESS; + if (!label_auto && label == bgp->vpn_policy[afi].tovpn_label) + /* no change */ + return CMD_SUCCESS; + } else { + if (label_auto && !CHECK_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) + /* no match */ + return CMD_WARNING_CONFIG_FAILED; + if (!label_auto && label_val && + label != bgp->vpn_policy[afi].tovpn_label) + /* no change */ + return CMD_WARNING_CONFIG_FAILED; + } /* * pre-change: un-export vpn routes (vpn->vrf routes unaffected) @@ -9427,9 +9594,16 @@ DEFPY (af_label_vpn_export, vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi, bgp_get_default(), bgp); - if (!label_auto && CHECK_FLAG(bgp->vpn_policy[afi].flags, - BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) { + if (CHECK_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG)) { + bgp_zebra_release_label_range(bgp->vpn_policy[afi].tovpn_label, + bgp->vpn_policy[afi].tovpn_label); + UNSET_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG); + } else if (CHECK_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) { + /* release any previous auto label */ if (bgp->vpn_policy[afi].tovpn_label != MPLS_LABEL_NONE) { /* @@ -9446,16 +9620,32 @@ DEFPY (af_label_vpn_export, &bgp->vpn_policy[afi], bgp->vpn_policy[afi].tovpn_label); } - UNSET_FLAG(bgp->vpn_policy[afi].flags, - BGP_VPN_POLICY_TOVPN_LABEL_AUTO); } - bgp->vpn_policy[afi].tovpn_label = label; - if (label_auto) { - SET_FLAG(bgp->vpn_policy[afi].flags, - BGP_VPN_POLICY_TOVPN_LABEL_AUTO); - bgp_lp_get(LP_TYPE_VRF, &bgp->vpn_policy[afi], - vpn_leak_label_callback); + if (yes) { + if (label_auto) { + SET_FLAG(bgp->vpn_policy[afi].flags, + 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, + BGP_VPN_POLICY_TOVPN_LABEL_AUTO); + if (bgp->vpn_policy[afi].tovpn_label >= + MPLS_LABEL_UNRESERVED_MIN && + bgp_zebra_request_label_range(bgp->vpn_policy[afi] + .tovpn_label, + 1, false)) + SET_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG); + } + } else { + UNSET_FLAG(bgp->vpn_policy[afi].flags, + BGP_VPN_POLICY_TOVPN_LABEL_AUTO); + bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE; } /* post-change: re-export vpn routes */ @@ -10506,7 +10696,7 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name, /* one clear bgp command to rule them all */ DEFUN (clear_ip_bgp_all, clear_ip_bgp_all_cmd, - "clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|ASNUM|external|peer-group PGNAME> [<soft [<in|out>]|in [prefix-filter]|out|message-stats>]", + "clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|ASNUM|external|peer-group PGNAME> [<soft [<in|out>]|in [prefix-filter]|out|message-stats|capabilities>]", CLEAR_STR IP_STR BGP_STR @@ -10529,7 +10719,8 @@ DEFUN (clear_ip_bgp_all, BGP_SOFT_IN_STR "Push out prefix-list ORF and do inbound soft reconfig\n" BGP_SOFT_OUT_STR - "Reset message statistics\n") + "Reset message statistics\n" + "Resend capabilities\n") { char *vrf = NULL; @@ -10586,7 +10777,7 @@ DEFUN (clear_ip_bgp_all, clr_sort = clear_external; } - /* [<soft [<in|out>]|in [prefix-filter]|out|message-stats>] */ + /* [<soft [<in|out>]|in [prefix-filter]|out|message-stats|capabilities>] */ if (argv_find(argv, argc, "soft", &idx)) { if (argv_find(argv, argc, "in", &idx) || argv_find(argv, argc, "out", &idx)) @@ -10603,6 +10794,8 @@ DEFUN (clear_ip_bgp_all, clr_type = BGP_CLEAR_SOFT_OUT; } else if (argv_find(argv, argc, "message-stats", &idx)) { clr_type = BGP_CLEAR_MESSAGE_STATS; + } else if (argv_find(argv, argc, "capabilities", &idx)) { + clr_type = BGP_CLEAR_CAPABILITIES; } else clr_type = BGP_CLEAR_SOFT_NONE; @@ -11534,8 +11727,9 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, : bgp->name); } else { vty_out(vty, - "BGP router identifier %pI4, local AS number %s vrf-id %d", + "BGP router identifier %pI4, local AS number %s %s vrf-id %d", &bgp->router_id, bgp->as_pretty, + bgp->name_pretty, bgp->vrf_id == VRF_UNKNOWN ? -1 : (int)bgp->vrf_id); @@ -12152,12 +12346,10 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi, safi, true)); } else { - vty_out(vty, - "\n%s Summary (%s):\n", + vty_out(vty, "\n%s Summary:\n", get_afi_safi_str(afi, safi, - false), - bgp->name_pretty); + false)); } } bgp_show_summary(vty, bgp, afi, safi, fpeer, @@ -16780,10 +16972,11 @@ ALIAS_HIDDEN( DEFUN (bgp_redistribute_ipv4_ospf, bgp_redistribute_ipv4_ospf_cmd, - "redistribute <ospf|table> (1-65535)", + "redistribute <ospf|table|table-direct> (1-65535)", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); @@ -16803,7 +16996,18 @@ DEFUN (bgp_redistribute_ipv4_ospf, argv[idx_ospf_table]->arg); return CMD_WARNING_CONFIG_FAILED; } - protocol = ZEBRA_ROUTE_TABLE; + if (strncmp(argv[idx_ospf_table]->arg, "table-direct", + strlen("table-direct")) == 0) { + protocol = ZEBRA_ROUTE_TABLE_DIRECT; + if (instance == RT_TABLE_MAIN || + instance == RT_TABLE_LOCAL) { + vty_out(vty, + "%% 'table-direct', can not use %u routing table\n", + instance); + return CMD_WARNING_CONFIG_FAILED; + } + } else + protocol = ZEBRA_ROUTE_TABLE; } bgp_redist_add(bgp, AFI_IP, protocol, instance); @@ -16811,18 +17015,20 @@ DEFUN (bgp_redistribute_ipv4_ospf, } ALIAS_HIDDEN(bgp_redistribute_ipv4_ospf, bgp_redistribute_ipv4_ospf_hidden_cmd, - "redistribute <ospf|table> (1-65535)", + "redistribute <ospf|table|table-direct> (1-65535)", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n") DEFUN (bgp_redistribute_ipv4_ospf_rmap, bgp_redistribute_ipv4_ospf_rmap_cmd, - "redistribute <ospf|table> (1-65535) route-map RMAP_NAME", + "redistribute <ospf|table|table-direct> (1-65535) route-map RMAP_NAME", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Route map reference\n" "Pointer to route-map entries\n") @@ -16838,6 +17044,8 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap, struct route_map *route_map = route_map_lookup_warn_noexist(vty, argv[idx_word]->arg); + instance = strtoul(argv[idx_number]->arg, NULL, 10); + if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0) protocol = ZEBRA_ROUTE_OSPF; else { @@ -16847,10 +17055,20 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap, argv[idx_ospf_table]->arg); return CMD_WARNING_CONFIG_FAILED; } - protocol = ZEBRA_ROUTE_TABLE; + if (strncmp(argv[idx_ospf_table]->arg, "table-direct", + strlen("table-direct")) == 0) { + protocol = ZEBRA_ROUTE_TABLE_DIRECT; + if (instance == RT_TABLE_MAIN || + instance == RT_TABLE_LOCAL) { + vty_out(vty, + "%% 'table-direct', can not use %u routing table\n", + instance); + return CMD_WARNING_CONFIG_FAILED; + } + } else + protocol = ZEBRA_ROUTE_TABLE; } - instance = strtoul(argv[idx_number]->arg, NULL, 10); red = bgp_redist_add(bgp, AFI_IP, protocol, instance); changed = bgp_redistribute_rmap_set(red, argv[idx_word]->arg, route_map); @@ -16859,20 +17077,22 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap, ALIAS_HIDDEN(bgp_redistribute_ipv4_ospf_rmap, bgp_redistribute_ipv4_ospf_rmap_hidden_cmd, - "redistribute <ospf|table> (1-65535) route-map RMAP_NAME", + "redistribute <ospf|table|table-direct> (1-65535) route-map RMAP_NAME", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Route map reference\n" "Pointer to route-map entries\n") DEFUN (bgp_redistribute_ipv4_ospf_metric, bgp_redistribute_ipv4_ospf_metric_cmd, - "redistribute <ospf|table> (1-65535) metric (0-4294967295)", + "redistribute <ospf|table|table-direct> (1-65535) metric (0-4294967295)", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Metric for redistributed routes\n" "Default metric\n") @@ -16887,6 +17107,8 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric, int protocol; bool changed; + instance = strtoul(argv[idx_number]->arg, NULL, 10); + if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0) protocol = ZEBRA_ROUTE_OSPF; else { @@ -16896,10 +17118,20 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric, argv[idx_ospf_table]->arg); return CMD_WARNING_CONFIG_FAILED; } - protocol = ZEBRA_ROUTE_TABLE; + if (strncmp(argv[idx_ospf_table]->arg, "table-direct", + strlen("table-direct")) == 0) { + protocol = ZEBRA_ROUTE_TABLE_DIRECT; + if (instance == RT_TABLE_MAIN || + instance == RT_TABLE_LOCAL) { + vty_out(vty, + "%% 'table-direct', can not use %u routing table\n", + instance); + return CMD_WARNING_CONFIG_FAILED; + } + } else + protocol = ZEBRA_ROUTE_TABLE; } - instance = strtoul(argv[idx_number]->arg, NULL, 10); metric = strtoul(argv[idx_number_2]->arg, NULL, 10); red = bgp_redist_add(bgp, AFI_IP, protocol, instance); @@ -16910,20 +17142,22 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric, ALIAS_HIDDEN(bgp_redistribute_ipv4_ospf_metric, bgp_redistribute_ipv4_ospf_metric_hidden_cmd, - "redistribute <ospf|table> (1-65535) metric (0-4294967295)", + "redistribute <ospf|table|table-direct> (1-65535) metric (0-4294967295)", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Metric for redistributed routes\n" "Default metric\n") DEFUN (bgp_redistribute_ipv4_ospf_rmap_metric, bgp_redistribute_ipv4_ospf_rmap_metric_cmd, - "redistribute <ospf|table> (1-65535) route-map RMAP_NAME metric (0-4294967295)", + "redistribute <ospf|table|table-direct> (1-65535) route-map RMAP_NAME metric (0-4294967295)", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Route map reference\n" "Pointer to route-map entries\n" @@ -16943,6 +17177,8 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap_metric, struct route_map *route_map = route_map_lookup_warn_noexist(vty, argv[idx_word]->arg); + instance = strtoul(argv[idx_number]->arg, NULL, 10); + if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0) protocol = ZEBRA_ROUTE_OSPF; else { @@ -16952,10 +17188,20 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap_metric, argv[idx_ospf_table]->arg); return CMD_WARNING_CONFIG_FAILED; } - protocol = ZEBRA_ROUTE_TABLE; + if (strncmp(argv[idx_ospf_table]->arg, "table-direct", + strlen("table-direct")) == 0) { + protocol = ZEBRA_ROUTE_TABLE_DIRECT; + if (instance == RT_TABLE_MAIN || + instance == RT_TABLE_LOCAL) { + vty_out(vty, + "%% 'table-direct', can not use %u routing table\n", + instance); + return CMD_WARNING_CONFIG_FAILED; + } + } else + protocol = ZEBRA_ROUTE_TABLE; } - instance = strtoul(argv[idx_number]->arg, NULL, 10); metric = strtoul(argv[idx_number_2]->arg, NULL, 10); red = bgp_redist_add(bgp, AFI_IP, protocol, instance); @@ -16969,10 +17215,11 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap_metric, ALIAS_HIDDEN( bgp_redistribute_ipv4_ospf_rmap_metric, bgp_redistribute_ipv4_ospf_rmap_metric_hidden_cmd, - "redistribute <ospf|table> (1-65535) route-map RMAP_NAME metric (0-4294967295)", + "redistribute <ospf|table|table-direct> (1-65535) route-map RMAP_NAME metric (0-4294967295)", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Route map reference\n" "Pointer to route-map entries\n" @@ -16981,10 +17228,11 @@ ALIAS_HIDDEN( DEFUN (bgp_redistribute_ipv4_ospf_metric_rmap, bgp_redistribute_ipv4_ospf_metric_rmap_cmd, - "redistribute <ospf|table> (1-65535) metric (0-4294967295) route-map RMAP_NAME", + "redistribute <ospf|table|table-direct> (1-65535) metric (0-4294967295) route-map RMAP_NAME", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Metric for redistributed routes\n" "Default metric\n" @@ -17004,6 +17252,8 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric_rmap, struct route_map *route_map = route_map_lookup_warn_noexist(vty, argv[idx_word]->arg); + instance = strtoul(argv[idx_number]->arg, NULL, 10); + if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0) protocol = ZEBRA_ROUTE_OSPF; else { @@ -17012,8 +17262,18 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric_rmap, "%% Only default BGP instance can use '%s'\n", argv[idx_ospf_table]->arg); return CMD_WARNING_CONFIG_FAILED; - } - protocol = ZEBRA_ROUTE_TABLE; + } else if (strncmp(argv[idx_ospf_table]->arg, "table-direct", + strlen("table-direct")) == 0) { + protocol = ZEBRA_ROUTE_TABLE_DIRECT; + if (instance == RT_TABLE_MAIN || + instance == RT_TABLE_LOCAL) { + vty_out(vty, + "%% 'table-direct', can not use %u routing table\n", + instance); + return CMD_WARNING_CONFIG_FAILED; + } + } else + protocol = ZEBRA_ROUTE_TABLE; } instance = strtoul(argv[idx_number]->arg, NULL, 10); @@ -17030,10 +17290,11 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric_rmap, ALIAS_HIDDEN( bgp_redistribute_ipv4_ospf_metric_rmap, bgp_redistribute_ipv4_ospf_metric_rmap_hidden_cmd, - "redistribute <ospf|table> (1-65535) metric (0-4294967295) route-map RMAP_NAME", + "redistribute <ospf|table|table-direct> (1-65535) metric (0-4294967295) route-map RMAP_NAME", "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Metric for redistributed routes\n" "Default metric\n" @@ -17042,11 +17303,12 @@ ALIAS_HIDDEN( DEFUN (no_bgp_redistribute_ipv4_ospf, no_bgp_redistribute_ipv4_ospf_cmd, - "no redistribute <ospf|table> (1-65535) [{metric (0-4294967295)|route-map RMAP_NAME}]", + "no redistribute <ospf|table|table-direct> (1-65535) [{metric (0-4294967295)|route-map RMAP_NAME}]", NO_STR "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Metric for redistributed routes\n" "Default metric\n" @@ -17059,6 +17321,8 @@ DEFUN (no_bgp_redistribute_ipv4_ospf, unsigned short instance; int protocol; + instance = strtoul(argv[idx_number]->arg, NULL, 10); + if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0) protocol = ZEBRA_ROUTE_OSPF; else { @@ -17068,21 +17332,32 @@ DEFUN (no_bgp_redistribute_ipv4_ospf, argv[idx_ospf_table]->arg); return CMD_WARNING_CONFIG_FAILED; } - protocol = ZEBRA_ROUTE_TABLE; + if (strncmp(argv[idx_ospf_table]->arg, "table-direct", + strlen("table-direct")) == 0) { + protocol = ZEBRA_ROUTE_TABLE_DIRECT; + if (instance == RT_TABLE_MAIN || + instance == RT_TABLE_LOCAL) { + vty_out(vty, + "%% 'table-direct', can not use %u routing table\n", + instance); + return CMD_WARNING_CONFIG_FAILED; + } + } else + protocol = ZEBRA_ROUTE_TABLE; } - instance = strtoul(argv[idx_number]->arg, NULL, 10); bgp_redistribute_unset(bgp, AFI_IP, protocol, instance); return CMD_SUCCESS; } ALIAS_HIDDEN( no_bgp_redistribute_ipv4_ospf, no_bgp_redistribute_ipv4_ospf_hidden_cmd, - "no redistribute <ospf|table> (1-65535) [{metric (0-4294967295)|route-map RMAP_NAME}]", + "no redistribute <ospf|table|table-direct> (1-65535) [{metric (0-4294967295)|route-map RMAP_NAME}]", NO_STR "Redistribute information from another routing protocol\n" "Open Shortest Path First (OSPFv2)\n" "Non-main Kernel Routing Table\n" + "Non-main Kernel Routing Table - Direct\n" "Instance ID/Table ID\n" "Metric for redistributed routes\n" "Default metric\n" @@ -17427,8 +17702,8 @@ bool peergroup_flag_check(struct peer *peer, uint64_t flag) return !!CHECK_FLAG(peer->flags_override, flag); } -static bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, - uint64_t flag) +bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, + uint64_t flag) { if (!peer_group_active(peer)) { if (CHECK_FLAG(peer->af_flags_invert[afi][safi], flag)) @@ -17876,6 +18151,9 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, ? " strict-mode" : ""); + if (peer->sub_sort == BGP_PEER_EBGP_OAD) + vty_out(vty, " neighbor %s oad\n", addr); + /* ttl-security hops */ if (peer->gtsm_hops != BGP_GTSM_HOPS_DISABLED) { if (!peer_group_active(peer) @@ -17900,8 +18178,13 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, addr); /* enforce-first-as */ - if (peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS)) - vty_out(vty, " neighbor %s enforce-first-as\n", addr); + if (CHECK_FLAG(bgp->flags, BGP_FLAG_ENFORCE_FIRST_AS)) { + if (!peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS)) + vty_out(vty, " no neighbor %s enforce-first-as\n", addr); + } else { + if (peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS)) + vty_out(vty, " neighbor %s enforce-first-as\n", addr); + } /* update-source */ if (peergroup_flag_check(peer, PEER_FLAG_UPDATE_SOURCE)) { @@ -17966,14 +18249,30 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, } /* capability software-version */ - if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_SOFT_VERSION)) - vty_out(vty, " neighbor %s capability software-version\n", - addr); + if (CHECK_FLAG(bgp->flags, BGP_FLAG_SOFT_VERSION_CAPABILITY)) { + if (!peergroup_flag_check(peer, + PEER_FLAG_CAPABILITY_SOFT_VERSION)) + vty_out(vty, + " no neighbor %s capability software-version\n", + addr); + } else { + if (peergroup_flag_check(peer, + PEER_FLAG_CAPABILITY_SOFT_VERSION)) + vty_out(vty, + " neighbor %s capability software-version\n", + addr); + } /* dont-capability-negotiation */ if (peergroup_flag_check(peer, PEER_FLAG_DONT_CAPABILITY)) vty_out(vty, " neighbor %s dont-capability-negotiate\n", addr); + /* capability fqdn */ + if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_FQDN)) + vty_out(vty, + " no neighbor %s capability fqdn\n", + addr); + /* override-capability */ if (peergroup_flag_check(peer, PEER_FLAG_OVERRIDE_CAPABILITY)) vty_out(vty, " neighbor %s override-capability\n", addr); @@ -18190,6 +18489,12 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp, if (flag_slcomm) vty_out(vty, " no neighbor %s send-community large\n", addr); + + if (peergroup_af_flag_check(peer, afi, safi, + PEER_FLAG_SEND_EXT_COMMUNITY_RPKI)) + vty_out(vty, + " no neighbor %s send-community extended rpki\n", + addr); } /* Default information */ @@ -18434,6 +18739,8 @@ int bgp_config_write(struct vty *vty) safi_t safi; uint32_t tovpn_sid_index = 0; + hook_call(bgp_snmp_traps_config_write, vty); + if (bm->rmap_update_timer != RMAP_DEFAULT_UPDATE_TIMER) vty_out(vty, "bgp route-map delay-timer %u\n", bm->rmap_update_timer); @@ -18524,6 +18831,15 @@ int bgp_config_write(struct vty *vty) ? "" : "no "); + /* bgp enforce-first-as */ + if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_ENFORCE_FIRST_AS) != + SAVE_BGP_ENFORCE_FIRST_AS) + vty_out(vty, " %sbgp enforce-first-as\n", + CHECK_FLAG(bgp->flags, + BGP_FLAG_ENFORCE_FIRST_AS) + ? "" + : "no "); + if (!!CHECK_FLAG(bgp->flags, BGP_FLAG_LU_IPV4_EXPLICIT_NULL) && !!CHECK_FLAG(bgp->flags, BGP_FLAG_LU_IPV6_EXPLICIT_NULL)) vty_out(vty, " bgp labeled-unicast explicit-null\n"); @@ -19443,6 +19759,9 @@ void bgp_vty_init(void) install_element(BGP_NODE, &neighbor_role_strict_cmd); install_element(BGP_NODE, &no_neighbor_role_cmd); + /* "neighbor oad" commands. */ + install_element(BGP_NODE, &neighbor_oad_cmd); + /* "neighbor aigp" commands. */ install_element(BGP_NODE, &neighbor_aigp_cmd); @@ -19516,6 +19835,9 @@ void bgp_vty_init(void) install_element(BGP_NODE, &bgp_ebgp_requires_policy_cmd); install_element(BGP_NODE, &no_bgp_ebgp_requires_policy_cmd); + /* bgp enforce-first-as */ + install_element(BGP_NODE, &bgp_enforce_first_as_cmd); + /* bgp labeled-unicast explicit-null */ install_element(BGP_NODE, &bgp_lu_uses_explicit_null_cmd); @@ -20058,6 +20380,15 @@ void bgp_vty_init(void) install_element(BGP_VPNV6_NODE, &neighbor_send_community_type_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_send_community_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_send_community_type_cmd); + install_element(BGP_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_IPV4_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_IPV4M_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_IPV4L_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_IPV6_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_IPV6M_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_IPV6L_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_VPNV4_NODE, &neighbor_ecommunity_rpki_cmd); + install_element(BGP_VPNV6_NODE, &neighbor_ecommunity_rpki_cmd); /* "neighbor route-reflector" commands.*/ install_element(BGP_NODE, &neighbor_route_reflector_client_hidden_cmd); @@ -20293,6 +20624,9 @@ void bgp_vty_init(void) install_element(BGP_NODE, &neighbor_dont_capability_negotiate_cmd); install_element(BGP_NODE, &no_neighbor_dont_capability_negotiate_cmd); + /* "neighbor capability fqdn" command. */ + install_element(BGP_NODE, &neighbor_capability_fqdn_cmd); + /* "neighbor ebgp-multihop" commands. */ install_element(BGP_NODE, &neighbor_ebgp_multihop_cmd); install_element(BGP_NODE, &neighbor_ebgp_multihop_ttl_cmd); diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index a105b6d..4955e4c 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -171,5 +171,7 @@ extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, safi_t safi, const char *neighbor, int as_type, as_t as, uint16_t show_flags); extern bool peergroup_flag_check(struct peer *peer, uint64_t flag); +extern bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, + uint64_t flag); #endif /* _QUAGGA_BGP_VTY_H */ diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 5b69de0..87f2e55 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -24,6 +24,7 @@ #include "mpls.h" #include "vxlan.h" #include "pbr.h" +#include "frrdistance.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_route.h" @@ -72,9 +73,10 @@ static inline bool bgp_install_info_to_zebra(struct bgp *bgp) return false; if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) { - zlog_debug( - "%s: No zebra instance to talk to, not installing information", - __func__); + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug( + "%s: No zebra instance to talk to, not installing information", + __func__); return false; } @@ -98,13 +100,6 @@ static int bgp_router_id_update(ZAPI_CALLBACK_ARGS) return 0; } -/* Nexthop update message from zebra. */ -static int bgp_read_nexthop_update(ZAPI_CALLBACK_ARGS) -{ - bgp_parse_nexthop_update(cmd, vrf_id); - return 0; -} - /* Set or clear interface on which unnumbered neighbor is configured. This * would in turn cause BGP to initiate or turn off IPv6 RAs on this * interface. @@ -151,7 +146,6 @@ static void bgp_start_interface_nbrs(struct bgp *bgp, struct interface *ifp) static void bgp_nbr_connected_add(struct bgp *bgp, struct nbr_connected *ifc) { - struct listnode *node; struct connected *connected; struct interface *ifp; struct prefix *p; @@ -160,7 +154,7 @@ static void bgp_nbr_connected_add(struct bgp *bgp, struct nbr_connected *ifc) * valid local address on the interface. */ ifp = ifc->ifp; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { + frr_each (if_connected, ifp->connected, connected) { p = connected->address; if (p->family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) @@ -232,7 +226,7 @@ static int bgp_ifp_up(struct interface *ifp) if (!bgp) return 0; - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, c)) + frr_each (if_connected, ifp->connected, c) bgp_connected_add(bgp, c); for (ALL_LIST_ELEMENTS(ifp->nbr_connected, node, nnode, nc)) @@ -263,7 +257,7 @@ static int bgp_ifp_down(struct interface *ifp) if (!bgp) return 0; - for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, c)) + frr_each (if_connected, ifp->connected, c) bgp_connected_delete(bgp, c); for (ALL_LIST_ELEMENTS(ifp->nbr_connected, node, nnode, nc)) @@ -564,7 +558,6 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS) struct interface *if_lookup_by_ipv4(struct in_addr *addr, vrf_id_t vrf_id) { struct vrf *vrf; - struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix_ipv4 p; @@ -579,7 +572,7 @@ struct interface *if_lookup_by_ipv4(struct in_addr *addr, vrf_id_t vrf_id) p.prefixlen = IPV4_MAX_BITLEN; FOR_ALL_INTERFACES (vrf, ifp) { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET) @@ -593,7 +586,6 @@ struct interface *if_lookup_by_ipv4(struct in_addr *addr, vrf_id_t vrf_id) struct interface *if_lookup_by_ipv4_exact(struct in_addr *addr, vrf_id_t vrf_id) { struct vrf *vrf; - struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix *cp; @@ -603,7 +595,7 @@ struct interface *if_lookup_by_ipv4_exact(struct in_addr *addr, vrf_id_t vrf_id) return NULL; FOR_ALL_INTERFACES (vrf, ifp) { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET) @@ -618,7 +610,6 @@ struct interface *if_lookup_by_ipv6(struct in6_addr *addr, ifindex_t ifindex, vrf_id_t vrf_id) { struct vrf *vrf; - struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix_ipv6 p; @@ -633,7 +624,7 @@ struct interface *if_lookup_by_ipv6(struct in6_addr *addr, ifindex_t ifindex, p.prefixlen = IPV6_MAX_BITLEN; FOR_ALL_INTERFACES (vrf, ifp) { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET6) @@ -654,7 +645,6 @@ struct interface *if_lookup_by_ipv6_exact(struct in6_addr *addr, ifindex_t ifindex, vrf_id_t vrf_id) { struct vrf *vrf; - struct listnode *cnode; struct interface *ifp; struct connected *connected; struct prefix *cp; @@ -664,7 +654,7 @@ struct interface *if_lookup_by_ipv6_exact(struct in6_addr *addr, return NULL; FOR_ALL_INTERFACES (vrf, ifp) { - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET6) @@ -683,11 +673,10 @@ struct interface *if_lookup_by_ipv6_exact(struct in6_addr *addr, static int if_get_ipv6_global(struct interface *ifp, struct in6_addr *addr) { - struct listnode *cnode; struct connected *connected; struct prefix *cp; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET6) @@ -701,11 +690,10 @@ static int if_get_ipv6_global(struct interface *ifp, struct in6_addr *addr) static bool if_get_ipv6_local(struct interface *ifp, struct in6_addr *addr) { - struct listnode *cnode; struct connected *connected; struct prefix *cp; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if (cp->family == AF_INET6) @@ -719,11 +707,10 @@ static bool if_get_ipv6_local(struct interface *ifp, struct in6_addr *addr) static int if_get_ipv4_address(struct interface *ifp, struct in_addr *addr) { - struct listnode *cnode; struct connected *connected; struct prefix *cp; - for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) { + frr_each (if_connected, ifp->connected, connected) { cp = connected->address; if ((cp->family == AF_INET) && !ipv4_martian(&(cp->u.prefix4))) { @@ -1207,83 +1194,49 @@ 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, - uint64_t tot_bw, uint32_t *nh_weight) + uint32_t *nh_weight) { - uint32_t bw; - uint64_t tmp; - - bw = attr->link_bw; /* zero link-bandwidth and link-bandwidth not present are treated * as the same situation. */ - if (!bw) { + if (!attr->link_bw) { /* the only situations should be if we're either told * to skip or use default weight. */ if (bgp->lb_handling == BGP_LINK_BW_SKIP_MISSING) return false; *nh_weight = BGP_ZEBRA_DEFAULT_NHOP_WEIGHT; - } else { - tmp = (uint64_t)bw * 100; - *nh_weight = ((uint32_t)(tmp / tot_bw)); - } + } else + *nh_weight = attr->link_bw; return true; } -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 void bgp_zebra_announce_parse_nexthop( + struct bgp_path_info *info, const struct prefix *p, struct bgp *bgp, + struct zapi_route *api, unsigned int *valid_nh_count, afi_t afi, + safi_t safi, uint32_t *nhg_id, uint32_t *metric, route_tag_t *tag, + bool *allow_recursion) { - struct zapi_route api = { 0 }; struct zapi_nexthop *api_nh; int nh_family; - unsigned int valid_nh_count = 0; - bool allow_recursion = false; - uint8_t distance; - struct peer *peer; struct bgp_path_info *mpinfo; struct bgp *bgp_orig; - uint32_t metric; struct attr local_attr; struct bgp_path_info local_info; struct bgp_path_info *mpinfo_cp = &local_info; - route_tag_t tag; mpls_label_t *labels; uint32_t num_labels = 0; mpls_label_t nh_label; int nh_othervrf = 0; bool nh_updated = false; bool do_wt_ecmp; - uint64_t cum_bw = 0; - uint32_t nhg_id = 0; - bool is_add; uint32_t ttl = 0; uint32_t bos = 0; uint32_t exp = 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; - - if (safi == SAFI_FLOWSPEC) { - bgp_pbr_update_entry(bgp, bgp_dest_get_prefix(dest), info, afi, - safi, true); - return; - } + /* Determine if we're doing weighted ECMP or not */ + do_wt_ecmp = bgp_path_info_mpath_chkwtd(bgp, info); /* * vrf leaking support (will have only one nexthop) @@ -1292,62 +1245,10 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, info->extra->vrfleak->bgp_orig) nh_othervrf = 1; - /* Make Zebra API structure. */ - api.vrf_id = bgp->vrf_id; - api.type = ZEBRA_ROUTE_BGP; - api.safi = safi; - api.prefix = *p; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - - peer = info->peer; - - if (info->type == ZEBRA_ROUTE_BGP - && info->sub_type == BGP_ROUTE_IMPORTED) { - - /* Obtain peer from parent */ - if (info->extra && info->extra->vrfleak && - info->extra->vrfleak->parent) - peer = ((struct bgp_path_info *)(info->extra->vrfleak - ->parent)) - ->peer; - } - - tag = info->attr->tag; - - if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED - || info->sub_type == BGP_ROUTE_AGGREGATE) { - SET_FLAG(api.flags, ZEBRA_FLAG_IBGP); - SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); - } - - if ((peer->sort == BGP_PEER_EBGP && peer->ttl != BGP_DEFAULT_TTL) - || CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) - || CHECK_FLAG(bgp->flags, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) - - allow_recursion = true; - - if (info->attr->rmap_table_id) { - SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID); - api.tableid = info->attr->rmap_table_id; - } - - if (CHECK_FLAG(info->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_SRTE_COLOR))) - SET_FLAG(api.message, ZAPI_MESSAGE_SRTE); - - /* Metric is currently based on the best-path only */ - metric = info->attr->med; - - /* Determine if we're doing weighted ECMP or not */ - do_wt_ecmp = bgp_path_info_mpath_chkwtd(bgp, info); - if (do_wt_ecmp) - cum_bw = bgp_path_info_mpath_cumbw(info); - /* EVPN MAC-IP routes are installed with a L3 NHG id */ - if (bgp_evpn_path_es_use_nhg(bgp, info, &nhg_id)) { + if (nhg_id && bgp_evpn_path_es_use_nhg(bgp, info, nhg_id)) { mpinfo = NULL; - api.nhgid = nhg_id; - if (nhg_id) - SET_FLAG(api.message, ZAPI_MESSAGE_NHG); + zapi_route_set_nhg_id(api, nhg_id); } else { mpinfo = info; } @@ -1359,7 +1260,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, bool is_evpn; bool is_parent_evpn; - if (valid_nh_count >= multipath_num) + if (*valid_nh_count >= multipath_num) break; *mpinfo_cp = *mpinfo; @@ -1382,16 +1283,19 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, */ if (do_wt_ecmp) { if (!bgp_zebra_use_nhop_weighted(bgp, mpinfo->attr, - cum_bw, &nh_weight)) + &nh_weight)) continue; } - api_nh = &api.nexthops[valid_nh_count]; + if (CHECK_FLAG(info->flags, BGP_PATH_SELECTED)) + api_nh = &api->nexthops[*valid_nh_count]; + else + api_nh = &api->backup_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); - if (bgp_debug_zebra(&api.prefix)) { + if (bgp_debug_zebra(&api->prefix)) { if (mpinfo->extra) { zlog_debug("%s: p=%pFX, bgp_is_valid_label: %d", __func__, p, @@ -1416,8 +1320,10 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, /* metric/tag is only allowed to be * overridden on 1st nexthop */ if (mpinfo == info) { - metric = mpinfo_cp->attr->med; - tag = mpinfo_cp->attr->tag; + if (metric) + *metric = mpinfo_cp->attr->med; + if (tag) + *tag = mpinfo_cp->attr->tag; } } @@ -1458,11 +1364,11 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, /* Allow recursion if it is a multipath group with both * eBGP and iBGP paths. */ - if (!allow_recursion - && CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX) - && (mpinfo->peer->sort == BGP_PEER_IBGP - || mpinfo->peer->sort == BGP_PEER_CONFED)) - allow_recursion = true; + if (allow_recursion && !*allow_recursion && + CHECK_FLAG(bgp->flags, BGP_FLAG_PEERTYPE_MULTIPATH_RELAX) && + (mpinfo->peer->sort == BGP_PEER_IBGP || + mpinfo->peer->sort == BGP_PEER_CONFED)) + *allow_recursion = true; if (mpinfo->extra) { labels = mpinfo->extra->label; @@ -1515,7 +1421,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, &exp, &bos); if (nh_label < MPLS_LABEL_UNRESERVED_MIN) { - if (bgp_debug_zebra(&api.prefix)) + if (bgp_debug_zebra(&api->prefix)) zlog_debug( "skip invalid SRv6 routes: transposition scheme is used, but label is too small"); continue; @@ -1532,8 +1438,156 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6); } - valid_nh_count++; + (*valid_nh_count)++; + } +} + +static void bgp_debug_zebra_nh(struct zapi_route *api) +{ + int i; + int nh_family; + char nh_buf[INET6_ADDRSTRLEN]; + char eth_buf[ETHER_ADDR_STRLEN + 7] = { '\0' }; + char buf1[ETHER_ADDR_STRLEN]; + char label_buf[20]; + char sid_buf[20]; + char segs_buf[256]; + struct zapi_nexthop *api_nh; + int count; + + count = api->nexthop_num; + for (i = 0; i < count; i++) { + api_nh = &api->nexthops[i]; + switch (api_nh->type) { + case NEXTHOP_TYPE_IFINDEX: + nh_buf[0] = '\0'; + break; + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + nh_family = AF_INET; + inet_ntop(nh_family, &api_nh->gate, nh_buf, + sizeof(nh_buf)); + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + nh_family = AF_INET6; + inet_ntop(nh_family, &api_nh->gate, nh_buf, + sizeof(nh_buf)); + break; + case NEXTHOP_TYPE_BLACKHOLE: + strlcpy(nh_buf, "blackhole", sizeof(nh_buf)); + break; + default: + /* Note: add new nexthop case */ + assert(0); + break; + } + + label_buf[0] = '\0'; + eth_buf[0] = '\0'; + segs_buf[0] = '\0'; + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL) && + !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) + snprintf(label_buf, sizeof(label_buf), "label %u", + api_nh->labels[0]); + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6) && + !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) { + inet_ntop(AF_INET6, &api_nh->seg6_segs[0], sid_buf, + sizeof(sid_buf)); + snprintf(segs_buf, sizeof(segs_buf), "segs %s", sid_buf); + } + if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN) && + !is_zero_mac(&api_nh->rmac)) + 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, + 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) +{ + struct bgp_path_info *bpi_ultimate; + struct zapi_route api = { 0 }; + unsigned int valid_nh_count = 0; + bool allow_recursion = false; + uint8_t distance; + struct peer *peer; + uint32_t metric; + 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; + + if (safi == SAFI_FLOWSPEC) { + bgp_pbr_update_entry(bgp, bgp_dest_get_prefix(dest), info, afi, + safi, true); + return; + } + + /* Make Zebra API structure. */ + api.vrf_id = bgp->vrf_id; + api.type = ZEBRA_ROUTE_BGP; + api.safi = safi; + api.prefix = *p; + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + + peer = info->peer; + + if (info->type == ZEBRA_ROUTE_BGP) { + bpi_ultimate = bgp_get_imported_bpi_ultimate(info); + peer = bpi_ultimate->peer; + } + + tag = info->attr->tag; + + if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED + || info->sub_type == BGP_ROUTE_AGGREGATE) { + SET_FLAG(api.flags, ZEBRA_FLAG_IBGP); + SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); + } + + if ((peer->sort == BGP_PEER_EBGP && peer->ttl != BGP_DEFAULT_TTL) + || CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) + || CHECK_FLAG(bgp->flags, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) + + allow_recursion = true; + + if (info->attr->rmap_table_id) { + SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID); + api.tableid = info->attr->rmap_table_id; + } + + if (CHECK_FLAG(info->attr->flag, ATTR_FLAG_BIT(BGP_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); is_add = (valid_nh_count || nhg_id) ? true : false; @@ -1593,75 +1647,12 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, } if (bgp_debug_zebra(p)) { - char nh_buf[INET6_ADDRSTRLEN]; - char eth_buf[ETHER_ADDR_STRLEN + 7] = {'\0'}; - char buf1[ETHER_ADDR_STRLEN]; - char label_buf[20]; - char sid_buf[20]; - char segs_buf[256]; - int i; - zlog_debug( "Tx route %s VRF %u %pFX metric %u tag %" ROUTE_TAG_PRI " count %d nhg %d", is_add ? "add" : "delete", bgp->vrf_id, &api.prefix, api.metric, api.tag, api.nexthop_num, nhg_id); - for (i = 0; i < api.nexthop_num; i++) { - api_nh = &api.nexthops[i]; - - switch (api_nh->type) { - case NEXTHOP_TYPE_IFINDEX: - nh_buf[0] = '\0'; - break; - case NEXTHOP_TYPE_IPV4: - case NEXTHOP_TYPE_IPV4_IFINDEX: - nh_family = AF_INET; - inet_ntop(nh_family, &api_nh->gate, nh_buf, - sizeof(nh_buf)); - break; - case NEXTHOP_TYPE_IPV6: - case NEXTHOP_TYPE_IPV6_IFINDEX: - nh_family = AF_INET6; - inet_ntop(nh_family, &api_nh->gate, nh_buf, - sizeof(nh_buf)); - break; - case NEXTHOP_TYPE_BLACKHOLE: - strlcpy(nh_buf, "blackhole", sizeof(nh_buf)); - break; - default: - /* Note: add new nexthop case */ - assert(0); - break; - } - - label_buf[0] = '\0'; - eth_buf[0] = '\0'; - segs_buf[0] = '\0'; - if (CHECK_FLAG(api_nh->flags, - ZAPI_NEXTHOP_FLAG_LABEL) && - !CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN)) - snprintf(label_buf, sizeof(label_buf), - "label %u", api_nh->labels[0]); - if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6) && - !CHECK_FLAG(api_nh->flags, - ZAPI_NEXTHOP_FLAG_EVPN)) { - inet_ntop(AF_INET6, &api_nh->seg6_segs[0], - sid_buf, sizeof(sid_buf)); - snprintf(segs_buf, sizeof(segs_buf), "segs %s", - sid_buf); - } - if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_EVPN) && - !is_zero_mac(&api_nh->rmac)) - 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, api_nh->weight, - label_buf, segs_buf, eth_buf); - } - - int recursion_flag = 0; + bgp_debug_zebra_nh(&api); if (CHECK_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION)) recursion_flag = 1; @@ -1728,7 +1719,7 @@ void bgp_zebra_announce_table_all_subtypes(struct bgp *bgp, afi_t afi, } void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info, - struct bgp *bgp, safi_t safi) + struct bgp *bgp, afi_t afi, safi_t safi) { struct zapi_route api; struct peer *peer; @@ -1747,7 +1738,7 @@ void bgp_zebra_withdraw(const struct prefix *p, struct bgp_path_info *info, if (safi == SAFI_FLOWSPEC) { peer = info->peer; - bgp_pbr_update_entry(peer->bgp, p, info, AFI_IP, safi, false); + bgp_pbr_update_entry(peer->bgp, p, info, afi, safi, false); return; } @@ -1788,7 +1779,7 @@ void bgp_zebra_withdraw_table_all_subtypes(struct bgp *bgp, afi_t afi, safi_t sa if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED) && (pi->type == ZEBRA_ROUTE_BGP)) bgp_zebra_withdraw(bgp_dest_get_prefix(dest), - pi, bgp, safi); + pi, bgp, afi, safi); } } } @@ -2060,7 +2051,8 @@ void bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type, struct listnode *node, *nnode; struct bgp_redist *red; - if (type != ZEBRA_ROUTE_TABLE || instance != 0) + if ((type != ZEBRA_ROUTE_TABLE && type != ZEBRA_ROUTE_TABLE_DIRECT) || + instance != 0) return _bgp_redistribute_unset(bgp, afi, type, instance); /* walk over instance */ @@ -2359,7 +2351,7 @@ static int rule_notify_owner(ZAPI_CALLBACK_ARGS) enum zapi_rule_notify_owner note; struct bgp_pbr_action *bgp_pbra; struct bgp_pbr_rule *bgp_pbr = NULL; - char ifname[INTERFACE_NAMSIZ + 1]; + char ifname[IFNAMSIZ + 1]; if (!zapi_rule_notify_decode(zclient->ibuf, &seqno, &priority, &unique, ifname, ¬e)) @@ -2605,8 +2597,12 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, /* Find the bgp route node */ dest = bgp_safi_node_lookup(bgp->rib[afi][safi], safi, &p, &bgp->vrf_prd); - if (!dest) + if (!dest) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s: %pFX does not exist in the BGP table, nothing to do for %u", + __func__, &p, note); return -1; + } switch (note) { case ZAPI_ROUTE_INSTALLED: @@ -2615,7 +2611,7 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("route %pRN : INSTALLED", (void *)dest); + zlog_debug("route %pBD : INSTALLED", dest); /* Find the best route */ for (pi = dest->info; pi; pi = pi->next) { /* Process aggregate route */ @@ -2628,7 +2624,7 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, group_announce_route(bgp, afi, safi, dest, new_select); else { flog_err(EC_BGP_INVALID_ROUTE, - "selected route %pRN not found", (void *)dest); + "selected route %pBD not found", dest); bgp_dest_unlock_node(dest); return -1; @@ -2641,13 +2637,13 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, */ UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("route %pRN: Removed from Fib", (void *)dest); + zlog_debug("route %pBD: Removed from Fib", dest); break; case ZAPI_ROUTE_FAIL_INSTALL: new_select = NULL; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("route: %pRN Failed to Install into Fib", - (void *)dest); + zlog_debug("route: %pBD Failed to Install into Fib", + dest); UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { @@ -2660,8 +2656,8 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, break; case ZAPI_ROUTE_BETTER_ADMIN_WON: if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("route: %pRN removed due to better admin won", - (void *)dest); + zlog_debug("route: %pBD removed due to better admin won", + dest); new_select = NULL; UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); @@ -2675,8 +2671,7 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, /* No action required */ break; case ZAPI_ROUTE_REMOVE_FAIL: - zlog_warn("%s: Route %pRN failure to remove", - __func__, (void *)dest); + zlog_warn("%s: Route %pBD failure to remove", __func__, dest); break; } @@ -2958,12 +2953,11 @@ static int bgp_zebra_process_local_l3vni(ZAPI_CALLBACK_ARGS) is_anycast_mac = stream_getl(s); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug( - "Rx L3-VNI ADD VRF %s VNI %u Originator-IP %pI4 RMAC svi-mac %pEA vrr-mac %pEA filter %s svi-if %u", - vrf_id_to_name(vrf_id), l3vni, &originator_ip, - &svi_rmac, &vrr_rmac, - filter ? "prefix-routes-only" : "none", - svi_ifindex); + zlog_debug("Rx L3VNI ADD VRF %s VNI %u Originator-IP %pI4 RMAC svi-mac %pEA vrr-mac %pEA filter %s svi-if %u", + vrf_id_to_name(vrf_id), l3vni, + &originator_ip, &svi_rmac, &vrr_rmac, + filter ? "prefix-routes-only" : "none", + svi_ifindex); frrtrace(8, frr_bgp, evpn_local_l3vni_add_zrecv, l3vni, vrf_id, &svi_rmac, &vrr_rmac, filter, originator_ip, @@ -2974,7 +2968,7 @@ static int bgp_zebra_process_local_l3vni(ZAPI_CALLBACK_ARGS) is_anycast_mac); } else { if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx L3-VNI DEL VRF %s VNI %u", + zlog_debug("Rx L3VNI DEL VRF %s VNI %u", vrf_id_to_name(vrf_id), l3vni); frrtrace(2, frr_bgp, evpn_local_l3vni_del_zrecv, l3vni, vrf_id); @@ -3235,7 +3229,7 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS) if (prefix_match((struct prefix *)&loc.prefix, (struct prefix *)&tmp_prefi)) { listnode_delete(bgp->srv6_functions, func); - XFREE(MTYPE_BGP_SRV6_FUNCTION, func); + srv6_function_free(func); } } @@ -3339,7 +3333,6 @@ static zclient_handler *const bgp_handlers[] = { [ZEBRA_INTERFACE_NBR_ADDRESS_DELETE] = bgp_interface_nbr_address_delete, [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = zebra_read_route, [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = zebra_read_route, - [ZEBRA_NEXTHOP_UPDATE] = bgp_read_nexthop_update, [ZEBRA_FEC_UPDATE] = bgp_read_fec_update, [ZEBRA_LOCAL_ES_ADD] = bgp_zebra_process_local_es_add, [ZEBRA_LOCAL_ES_DEL] = bgp_zebra_process_local_es_del, @@ -3432,6 +3425,9 @@ static bool bgp_zebra_label_manager_connect(void) /* tell label pool that zebra is connected */ bgp_lp_event_zebra_up(); + /* tell BGP L3VPN that label manager is available */ + if (bgp_get_default()) + vpn_leak_postchange_all(); return true; } @@ -3442,13 +3438,12 @@ static void bgp_zebra_capabilities(struct zclient_capabilities *cap) void bgp_zebra_init(struct event_loop *master, unsigned short instance) { - struct zclient_options options = zclient_options_default; - - options.synchronous = true; zclient_num_connects = 0; - if_zapi_callbacks(bgp_ifp_create, bgp_ifp_up, - bgp_ifp_down, bgp_ifp_destroy); + hook_register_prio(if_real, 0, bgp_ifp_create); + hook_register_prio(if_up, 0, bgp_ifp_up); + hook_register_prio(if_down, 0, bgp_ifp_down); + hook_register_prio(if_unreal, 0, bgp_ifp_destroy); /* Set default values. */ zclient = zclient_new(master, &zclient_options_default, bgp_handlers, @@ -3456,10 +3451,11 @@ void bgp_zebra_init(struct event_loop *master, unsigned short instance) zclient_init(zclient, ZEBRA_ROUTE_BGP, 0, &bgpd_privs); zclient->zebra_connected = bgp_zebra_connected; zclient->zebra_capabilities = bgp_zebra_capabilities; + zclient->nexthop_update = bgp_nexthop_update; zclient->instance = instance; /* Initialize special zclient for synchronous message exchanges. */ - zclient_sync = zclient_new(master, &options, NULL, 0); + zclient_sync = zclient_new(master, &zclient_options_sync, NULL, 0); zclient_sync->sock = -1; zclient_sync->redist_default = ZEBRA_ROUTE_BGP; zclient_sync->instance = instance; @@ -3930,7 +3926,8 @@ void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label, zebra_send_mpls_labels(zclient, cmd, &zl); } -bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size) +bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size, + bool label_auto) { int ret; uint32_t start, end; @@ -3952,7 +3949,13 @@ bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size) return false; } - bgp_lp_event_chunk(start, end); + if (label_auto) + /* label automatic is serviced by the bgp label pool + * manager, which allocates label chunks in + * pre-pools, and which needs to be notified about + * new chunks availability + */ + bgp_lp_event_chunk(start, end); return true; } diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 0edae04..396c833 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -34,7 +34,7 @@ extern void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, 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, - safi_t safi); + 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, @@ -124,6 +124,7 @@ extern void bgp_zebra_send_nexthop_label(int cmd, mpls_label_t label, enum lsp_types_t ltype, struct prefix *p, uint32_t num_labels, mpls_label_t out_labels[]); -extern bool bgp_zebra_request_label_range(uint32_t base, uint32_t chunk_size); +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); #endif /* _QUAGGA_BGP_ZEBRA_H */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 4b72798..1a03a06 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -63,6 +63,7 @@ #include "bgpd/bgp_vty.h" #include "bgpd/bgp_mpath.h" #include "bgpd/bgp_nht.h" +#include "bgpd/bgp_nhg.h" #include "bgpd/bgp_updgrp.h" #include "bgpd/bgp_bfd.h" #include "bgpd/bgp_memory.h" @@ -186,7 +187,6 @@ int bgp_option_set(int flag) int bgp_option_unset(int flag) { switch (flag) { - /* Fall through. */ case BGP_OPT_NO_ZEBRA: case BGP_OPT_NO_FIB: UNSET_FLAG(bm->options, flag); @@ -410,6 +410,9 @@ void bgp_router_id_static_set(struct bgp *bgp, struct in_addr id) void bm_wait_for_fib_set(bool set) { bool send_msg = false; + struct bgp *bgp; + struct peer *peer; + struct listnode *next, *node; if (bm->wait_for_fib == set) return; @@ -428,12 +431,32 @@ void bm_wait_for_fib_set(bool set) if (send_msg && zclient) zebra_route_notify_send(ZEBRA_ROUTE_NOTIFY_REQUEST, zclient, set); + + /* + * If this is configed at a time when peers are already set + * FRR needs to reset the connection(s) as that some installs + * may have already happened in some shape fashion or form + * let's just start over + */ + for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) { + for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + if (!BGP_IS_VALID_STATE_FOR_NOTIF( + peer->connection->status)) + continue; + + peer->last_reset = PEER_DOWN_SUPPRESS_FIB_PENDING; + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } + } } /* Set the suppress fib pending for the bgp configuration */ void bgp_suppress_fib_pending_set(struct bgp *bgp, bool set) { bool send_msg = false; + struct peer *peer; + struct listnode *node; if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW) return; @@ -465,6 +488,21 @@ void bgp_suppress_fib_pending_set(struct bgp *bgp, bool set) zebra_route_notify_send(ZEBRA_ROUTE_NOTIFY_REQUEST, zclient, set); } + + /* + * If this is configed at a time when peers are already set + * FRR needs to reset the connection as that some installs + * may have already happened in some shape fashion or form + * let's just start over + */ + for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + if (!BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) + continue; + + peer->last_reset = PEER_DOWN_SUPPRESS_FIB_PENDING; + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + } } /* BGP's cluster-id control. */ @@ -577,8 +615,8 @@ void bgp_confederation_id_set(struct bgp *bgp, as_t as, const char *as_str) already_confed = bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION); bgp->confed_id = as; if (bgp->confed_id_pretty) - XFREE(MTYPE_BGP, bgp->confed_id_pretty); - bgp->confed_id_pretty = XSTRDUP(MTYPE_BGP, as_str); + XFREE(MTYPE_BGP_NAME, bgp->confed_id_pretty); + bgp->confed_id_pretty = XSTRDUP(MTYPE_BGP_NAME, as_str); bgp_config_set(bgp, BGP_CONFIG_CONFEDERATION); /* If we were doing confederation already, this is just an external @@ -631,7 +669,7 @@ void bgp_confederation_id_unset(struct bgp *bgp) struct listnode *node, *nnode; bgp->confed_id = 0; - XFREE(MTYPE_BGP, bgp->confed_id_pretty); + XFREE(MTYPE_BGP_NAME, bgp->confed_id_pretty); bgp_config_unset(bgp, BGP_CONFIG_CONFEDERATION); for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { @@ -685,7 +723,7 @@ void bgp_confederation_peers_add(struct bgp *bgp, as_t as, const char *as_str) bgp->confed_peers[bgp->confed_peers_cnt].as = as; bgp->confed_peers[bgp->confed_peers_cnt].as_pretty = - XSTRDUP(MTYPE_BGP, as_str); + XSTRDUP(MTYPE_BGP_NAME, as_str); bgp->confed_peers_cnt++; if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)) { @@ -723,7 +761,7 @@ void bgp_confederation_peers_remove(struct bgp *bgp, as_t as) for (i = 0; i < bgp->confed_peers_cnt; i++) if (bgp->confed_peers[i].as == as) { - XFREE(MTYPE_BGP, bgp->confed_peers[i].as_pretty); + XFREE(MTYPE_BGP_NAME, bgp->confed_peers[i].as_pretty); for (j = i + 1; j < bgp->confed_peers_cnt; j++) { bgp->confed_peers[j - 1].as = bgp->confed_peers[j].as; @@ -1266,9 +1304,9 @@ static void peer_free(struct peer *peer) bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_NONE, 0); if (peer->change_local_as_pretty) - XFREE(MTYPE_BGP, peer->change_local_as_pretty); + XFREE(MTYPE_BGP_NAME, peer->change_local_as_pretty); if (peer->as_pretty) - XFREE(MTYPE_BGP, peer->as_pretty); + XFREE(MTYPE_BGP_NAME, peer->as_pretty); bgp_peer_connection_free(&peer->connection); @@ -1428,7 +1466,9 @@ static void bgp_srv6_init(struct bgp *bgp) bgp->srv6_enabled = false; memset(bgp->srv6_locator_name, 0, sizeof(bgp->srv6_locator_name)); bgp->srv6_locator_chunks = list_new(); + bgp->srv6_locator_chunks->del = srv6_locator_chunk_list_free; bgp->srv6_functions = list_new(); + bgp->srv6_functions->del = (void (*)(void *))srv6_function_free; } static void bgp_srv6_cleanup(struct bgp *bgp) @@ -1473,6 +1513,8 @@ struct peer *peer_new(struct bgp *bgp) SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY); SET_FLAG(peer->af_flags[afi][safi], + PEER_FLAG_SEND_EXT_COMMUNITY_RPKI); + SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY); SET_FLAG(peer->af_flags_invert[afi][safi], @@ -1480,6 +1522,8 @@ struct peer *peer_new(struct bgp *bgp) SET_FLAG(peer->af_flags_invert[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY); SET_FLAG(peer->af_flags_invert[afi][safi], + PEER_FLAG_SEND_EXT_COMMUNITY_RPKI); + SET_FLAG(peer->af_flags_invert[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY); peer->addpath_type[afi][safi] = BGP_ADDPATH_NONE; peer->addpath_best_selected[afi][safi] = 0; @@ -1492,6 +1536,15 @@ struct peer *peer_new(struct bgp *bgp) SET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN); + if (CHECK_FLAG(bgp->flags, BGP_FLAG_ENFORCE_FIRST_AS)) + SET_FLAG(peer->flags, PEER_FLAG_ENFORCE_FIRST_AS); + + if (CHECK_FLAG(bgp->flags, BGP_FLAG_SOFT_VERSION_CAPABILITY)) + SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_SOFT_VERSION); + + SET_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_FQDN); + SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_FQDN); + /* Initialize per peer bgp GR FSM */ bgp_peer_gr_init(peer); @@ -1538,6 +1591,7 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src) /* copy tcp_mss value */ peer_dst->tcp_mss = peer_src->tcp_mss; (void)peer_sort(peer_dst); + peer_dst->sub_sort = peer_src->sub_sort; peer_dst->rmap_type = peer_src->rmap_type; peer_dst->local_role = peer_src->local_role; @@ -1603,6 +1657,7 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src) XSTRDUP(MTYPE_BGP_PEER_IFNAME, peer_src->ifname); } peer_dst->ttl = peer_src->ttl; + peer_dst->gtsm_hops = peer_src->gtsm_hops; } static int bgp_peer_conf_if_to_su_update_v4(struct peer_connection *connection, @@ -1611,12 +1666,11 @@ static int bgp_peer_conf_if_to_su_update_v4(struct peer_connection *connection, struct connected *ifc; struct prefix p; uint32_t addr; - struct listnode *node; /* If our IPv4 address on the interface is /30 or /31, we can derive the * IPv4 address of the other end. */ - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + frr_each (if_connected, ifp->connected, ifc) { if (ifc->address && (ifc->address->family == AF_INET)) { prefix_copy(&p, CONNECTED_PREFIX(ifc)); if (p.prefixlen == 30) { @@ -1863,7 +1917,7 @@ struct peer *peer_create(union sockunion *su, const char *conf_if, peer->as = remote_as; /* internal and external values do not use as_pretty */ if (as_str && asn_str2asn(as_str, NULL)) - peer->as_pretty = XSTRDUP(MTYPE_BGP, as_str); + peer->as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_str); peer->as_type = as_type; peer->local_id = bgp->router_id; peer->v_holdtime = bgp->default_holdtime; @@ -1985,10 +2039,10 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified, peer->as = as; if (as_specified == AS_SPECIFIED && as_str) { if (peer->as_pretty) - XFREE(MTYPE_BGP, peer->as_pretty); - peer->as_pretty = XSTRDUP(MTYPE_BGP, as_str); + XFREE(MTYPE_BGP_NAME, peer->as_pretty); + peer->as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_str); } else if (peer->as_type == AS_UNSPECIFIED && peer->as_pretty) - XFREE(MTYPE_BGP, peer->as_pretty); + XFREE(MTYPE_BGP_NAME, peer->as_pretty); peer->as_type = as_specified; if (bgp_config_check(peer->bgp, BGP_CONFIG_CONFEDERATION) @@ -3147,6 +3201,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, peer->as_type = group->conf->as_type; peer->as = group->conf->as; peer->sort = group->conf->sort; + peer->sub_sort = group->conf->sub_sort; } ptype = peer_sort(peer); @@ -3287,9 +3342,9 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp)); bgp->as = *as; if (as_pretty) - bgp->as_pretty = XSTRDUP(MTYPE_BGP, as_pretty); + bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_pretty); else - bgp->as_pretty = XSTRDUP(MTYPE_BGP, asn_asn2asplain(*as)); + bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, asn_asn2asplain(*as)); if (asnotation != ASNOTATION_UNDEFINED) { bgp->asnotation = asnotation; @@ -3418,14 +3473,14 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp_mplsvpn_nh_label_bind_cache_init(&bgp->mplsvpn_nh_label_bind); if (name) - bgp->name = XSTRDUP(MTYPE_BGP, name); + bgp->name = XSTRDUP(MTYPE_BGP_NAME, name); event_add_timer(bm->master, bgp_startup_timer_expire, bgp, bgp->restart_time, &bgp->t_startup); /* printable name we can use in debug messages */ if (inst_type == BGP_INSTANCE_TYPE_DEFAULT) { - bgp->name_pretty = XSTRDUP(MTYPE_BGP, "VRF default"); + bgp->name_pretty = XSTRDUP(MTYPE_BGP_NAME, "VRF default"); } else { const char *n; int len; @@ -3437,7 +3492,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, len = 4 + 1 + strlen(n) + 1; /* "view foo\0" */ - bgp->name_pretty = XCALLOC(MTYPE_BGP, len); + bgp->name_pretty = XCALLOC(MTYPE_BGP_NAME, len); snprintf(bgp->name_pretty, len, "%s %s", (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) ? "VRF" @@ -4040,7 +4095,8 @@ void bgp_free(struct bgp *bgp) if (bgp->vpn_policy[afi].rtlist[dir]) ecommunity_free(&bgp->vpn_policy[afi].rtlist[dir]); if (bgp->vpn_policy[afi].tovpn_rd_pretty) - XFREE(MTYPE_BGP, bgp->vpn_policy[afi].tovpn_rd_pretty); + XFREE(MTYPE_BGP_NAME, + bgp->vpn_policy[afi].tovpn_rd_pretty); if (bgp->vpn_policy[afi].tovpn_sid_locator != NULL) srv6_locator_chunk_free( &bgp->vpn_policy[afi].tovpn_sid_locator); @@ -4057,10 +4113,14 @@ void bgp_free(struct bgp *bgp) bgp_srv6_cleanup(bgp); bgp_confederation_id_unset(bgp); - XFREE(MTYPE_BGP, bgp->as_pretty); - XFREE(MTYPE_BGP, bgp->name); - XFREE(MTYPE_BGP, bgp->name_pretty); - XFREE(MTYPE_BGP, bgp->snmp_stats); + for (int i = 0; i < bgp->confed_peers_cnt; i++) + XFREE(MTYPE_BGP_NAME, bgp->confed_peers[i].as_pretty); + + XFREE(MTYPE_BGP_NAME, bgp->as_pretty); + XFREE(MTYPE_BGP_NAME, bgp->name); + XFREE(MTYPE_BGP_NAME, bgp->name_pretty); + XFREE(MTYPE_BGP_NAME, bgp->snmp_stats); + XFREE(MTYPE_BGP_CONFED_LIST, bgp->confed_peers); XFREE(MTYPE_BGP, bgp); } @@ -4522,6 +4582,7 @@ static const struct peer_flag_action peer_flag_action_list[] = { {PEER_FLAG_AIGP, 0, peer_change_none}, {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}, {0, 0, 0}}; static const struct peer_flag_action peer_af_flag_action_list[] = { @@ -4552,9 +4613,10 @@ static const struct peer_flag_action peer_af_flag_action_list[] = { {PEER_FLAG_AS_OVERRIDE, 1, peer_change_reset_out}, {PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE, 1, peer_change_reset_out}, {PEER_FLAG_WEIGHT, 0, peer_change_reset_in}, - {PEER_FLAG_DISABLE_ADDPATH_RX, 0, peer_change_reset}, + {PEER_FLAG_DISABLE_ADDPATH_RX, 0, peer_change_none}, {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}, {0, 0, 0}}; /* Proper action set. */ @@ -4979,6 +5041,16 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, else if (flag == PEER_FLAG_ORF_PREFIX_RM) peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + /* We should not reset the session if + * dynamic capability is enabled and we + * are changing the ORF prefix flags. + */ + if ((CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) && + CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV)) && + (flag == PEER_FLAG_ORF_PREFIX_RM || + flag == PEER_FLAG_ORF_PREFIX_SM)) + action.type = peer_change_none; + peer_change_action(peer, afi, safi, action.type); } } @@ -5039,6 +5111,18 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, member->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + /* We should not reset the session if + * dynamic capability is enabled and we + * are changing the ORF prefix flags. + */ + if ((CHECK_FLAG(peer->cap, + PEER_CAP_DYNAMIC_RCV) && + CHECK_FLAG(peer->cap, + PEER_CAP_DYNAMIC_ADV)) && + (flag == PEER_FLAG_ORF_PREFIX_RM || + flag == PEER_FLAG_ORF_PREFIX_SM)) + action.type = peer_change_none; + peer_change_action(member, afi, safi, action.type); } @@ -5624,7 +5708,7 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi, if (peer_established(peer->connection) && peer->afc_nego[afi][safi]) { update_group_adjust_peer(peer_af_find(peer, afi, safi)); - bgp_default_originate(peer, afi, safi, 0); + bgp_default_originate(peer, afi, safi, false); bgp_announce_route(peer, afi, safi, false); } @@ -5667,7 +5751,7 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi, member->afc_nego[afi][safi]) { update_group_adjust_peer( peer_af_find(member, afi, safi)); - bgp_default_originate(member, afi, safi, 0); + bgp_default_originate(member, afi, safi, false); bgp_announce_route(member, afi, safi, false); } } @@ -5712,7 +5796,7 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi) if (peer_established(peer->connection) && peer->afc_nego[afi][safi]) { update_group_adjust_peer(peer_af_find(peer, afi, safi)); - bgp_default_originate(peer, afi, safi, 1); + bgp_default_originate(peer, afi, safi, true); bgp_announce_route(peer, afi, safi, false); } @@ -5751,7 +5835,7 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi) if (peer_established(member->connection) && member->afc_nego[afi][safi]) { update_group_adjust_peer(peer_af_find(member, afi, safi)); - bgp_default_originate(member, afi, safi, 1); + bgp_default_originate(member, afi, safi, true); bgp_announce_route(member, afi, safi, false); } } @@ -6440,8 +6524,8 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend, peer->change_local_as = as; if (as_str) { if (peer->change_local_as_pretty) - XFREE(MTYPE_BGP, peer->change_local_as_pretty); - peer->change_local_as_pretty = XSTRDUP(MTYPE_BGP, as_str); + XFREE(MTYPE_BGP_NAME, peer->change_local_as_pretty); + peer->change_local_as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_str); } (void)peer_sort(peer); @@ -6478,8 +6562,8 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend, replace_as); member->change_local_as = as; if (as_str) - member->change_local_as_pretty = - XSTRDUP(MTYPE_BGP, as_str); + member->change_local_as_pretty = XSTRDUP(MTYPE_BGP_NAME, + as_str); } return 0; @@ -6505,7 +6589,7 @@ int peer_local_as_unset(struct peer *peer) peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND); peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS); peer->change_local_as = 0; - XFREE(MTYPE_BGP, peer->change_local_as_pretty); + XFREE(MTYPE_BGP_NAME, peer->change_local_as_pretty); } /* Check if handling a regular peer. */ @@ -6536,7 +6620,7 @@ int peer_local_as_unset(struct peer *peer) UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND); UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); member->change_local_as = 0; - XFREE(MTYPE_BGP, member->change_local_as_pretty); + XFREE(MTYPE_BGP_NAME, member->change_local_as_pretty); /* Send notification or stop peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { @@ -8024,6 +8108,16 @@ static void peer_reset_message_stats(struct peer *peer) } } +/* Helper function to resend some BGP capabilities that are uncontrolled. + * For instance, FQDN capability, that can't be turned off, but let's say + * we changed the hostname, we need to resend it. + */ +static void peer_clear_capabilities(struct peer *peer, afi_t afi, safi_t safi) +{ + bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_FQDN, + CAPABILITY_ACTION_SET); +} + /* * If peer clear is invoked in a loop for all peers on the BGP instance, * it may end up freeing the doppelganger, and if this was the next node @@ -8132,6 +8226,9 @@ int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi, if (stype == BGP_CLEAR_MESSAGE_STATS) peer_reset_message_stats(peer); + if (stype == BGP_CLEAR_CAPABILITIES) + peer_clear_capabilities(peer, afi, safi); + return 0; } @@ -8220,7 +8317,7 @@ void bgp_master_init(struct event_loop *master, const int buffer_size, /* mpls label dynamic allocation pool */ bgp_lp_init(bm->master, &bm->labelpool); - bgp_l3nhg_init(); + bgp_nhg_init(); bgp_evpn_mh_init(); QOBJ_REG(bm, bgp_master); } @@ -8240,10 +8337,9 @@ static void bgp_if_finish(struct bgp *bgp) return; FOR_ALL_INTERFACES (vrf, ifp) { - struct listnode *c_node, *c_nnode; struct connected *c; - for (ALL_LIST_ELEMENTS(ifp->connected, c_node, c_nnode, c)) + frr_each_safe (if_connected, ifp->connected, c) bgp_connected_delete(bgp, c); } } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index ca1411a..0f69095 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -34,6 +34,9 @@ #include "lib/bfd.h" +DECLARE_HOOK(bgp_hook_config_write_vrf, (struct vty *vty, struct vrf *vrf), + (vty, vrf)); + #define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */ #define BGP_PEER_MAX_HASH_SIZE 16384 @@ -121,6 +124,8 @@ struct bgp_master { #define BGP_OPT_NO_FIB (1 << 0) #define BGP_OPT_NO_LISTEN (1 << 1) #define BGP_OPT_NO_ZEBRA (1 << 2) +#define BGP_OPT_TRAPS_RFC4273 (1 << 3) +#define BGP_OPT_TRAPS_BGP4MIBV2 (1 << 4) uint64_t updgrp_idspace; uint64_t subgrp_idspace; @@ -217,6 +222,8 @@ struct vpn_policy { #define BGP_VPN_POLICY_TOVPN_NEXTHOP_SET (1 << 2) #define BGP_VPN_POLICY_TOVPN_SID_AUTO (1 << 3) #define BGP_VPN_POLICY_TOVPN_LABEL_PER_NEXTHOP (1 << 4) +/* Manual label is registered with zebra label manager */ +#define BGP_VPN_POLICY_TOVPN_LABEL_MANUAL_REG (1 << 5) /* * If we are importing another vrf into us keep a list of @@ -514,6 +521,7 @@ struct bgp { /* For BGP-LU, force IPv6 local prefixes to use ipv6-explicit-null label */ #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) /* BGP default address-families. * New peers inherit enabled afi/safis from bgp instance. @@ -832,7 +840,10 @@ DECLARE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp)); DECLARE_HOOK(bgp_inst_config_write, (struct bgp *bgp, struct vty *vty), (bgp, vty)); +DECLARE_HOOK(bgp_snmp_traps_config_write, (struct vty *vty), (vty)); DECLARE_HOOK(bgp_config_end, (struct bgp *bgp), (bgp)); +DECLARE_HOOK(bgp_hook_vrf_update, (struct vrf *vrf, bool enabled), + (vrf, enabled)); /* Thread callback information */ struct afi_safi_info { @@ -877,10 +888,10 @@ struct peer_group { struct bgp_notify { uint8_t code; uint8_t subcode; - char *data; bgp_size_t length; - uint8_t *raw_data; bool hard_reset; + char *data; + uint8_t *raw_data; }; /* Next hop self address. */ @@ -971,6 +982,14 @@ enum bgp_peer_sort { BGP_PEER_CONFED, }; +/* BGP peering sub-types + * E.g.: + * EBGP-OAD - https://datatracker.ietf.org/doc/html/draft-uttaro-idr-bgp-oad + */ +enum bgp_peer_sub_sort { + BGP_PEER_EBGP_OAD = 1, +}; + /* BGP message header and packet size. */ #define BGP_MARKER_SIZE 16 #define BGP_HEADER_SIZE 19 @@ -1032,7 +1051,8 @@ enum peer_gr_command { NO_PEER_HELPER_CMD }; -typedef unsigned int (*bgp_peer_gr_action_ptr)(struct peer *, int, int); +typedef unsigned int (*bgp_peer_gr_action_ptr)(struct peer *, enum peer_mode, + enum peer_mode); struct bgp_peer_gr { enum peer_mode next_state; @@ -1129,6 +1149,11 @@ struct peer_connection { int fd; + /* Thread flags */ + _Atomic uint32_t thread_flags; +#define PEER_THREAD_WRITES_ON (1U << 0) +#define PEER_THREAD_READS_ON (1U << 1) + /* Packet receive and send buffer. */ pthread_mutex_t io_mtx; // guards ibuf, obuf struct stream_fifo *ibuf; // packets waiting to be processed @@ -1159,11 +1184,6 @@ struct peer_connection { union sockunion su; #define BGP_CONNECTION_SU_UNSPEC(connection) \ (connection->su.sa.sa_family == AF_UNSPEC) - - /* Thread flags */ - _Atomic uint32_t thread_flags; -#define PEER_THREAD_WRITES_ON (1U << 0) -#define PEER_THREAD_READS_ON (1U << 1) }; extern struct peer_connection *bgp_peer_connection_new(struct peer *peer); extern void bgp_peer_connection_free(struct peer_connection **connection); @@ -1197,6 +1217,7 @@ struct peer { as_t local_as; enum bgp_peer_sort sort; + enum bgp_peer_sub_sort sub_sort; /* Peer's Change local AS number. */ as_t change_local_as; @@ -1279,39 +1300,39 @@ struct peer { uint8_t afc_recv[AFI_MAX][SAFI_MAX]; /* Capability flags (reset in bgp_stop) */ - uint32_t cap; -#define PEER_CAP_REFRESH_ADV (1U << 0) /* refresh advertised */ -#define PEER_CAP_REFRESH_RCV (1U << 2) /* refresh rfc received */ -#define PEER_CAP_DYNAMIC_ADV (1U << 3) /* dynamic advertised */ -#define PEER_CAP_DYNAMIC_RCV (1U << 4) /* dynamic received */ -#define PEER_CAP_RESTART_ADV (1U << 5) /* restart advertised */ -#define PEER_CAP_RESTART_RCV (1U << 6) /* restart received */ -#define PEER_CAP_AS4_ADV (1U << 7) /* as4 advertised */ -#define PEER_CAP_AS4_RCV (1U << 8) /* as4 received */ + uint64_t cap; +#define PEER_CAP_REFRESH_ADV (1ULL << 0) /* refresh advertised */ +#define PEER_CAP_REFRESH_RCV (1ULL << 2) /* refresh rfc received */ +#define PEER_CAP_DYNAMIC_ADV (1ULL << 3) /* dynamic advertised */ +#define PEER_CAP_DYNAMIC_RCV (1ULL << 4) /* dynamic received */ +#define PEER_CAP_RESTART_ADV (1ULL << 5) /* restart advertised */ +#define PEER_CAP_RESTART_RCV (1ULL << 6) /* restart received */ +#define PEER_CAP_AS4_ADV (1ULL << 7) /* as4 advertised */ +#define PEER_CAP_AS4_RCV (1ULL << 8) /* as4 received */ /* sent graceful-restart restart (R) bit */ -#define PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV (1U << 9) +#define PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV (1ULL << 9) /* received graceful-restart restart (R) bit */ -#define PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV (1U << 10) -#define PEER_CAP_ADDPATH_ADV (1U << 11) /* addpath advertised */ -#define PEER_CAP_ADDPATH_RCV (1U << 12) /* addpath received */ -#define PEER_CAP_ENHE_ADV (1U << 13) /* Extended nexthop advertised */ -#define PEER_CAP_ENHE_RCV (1U << 14) /* Extended nexthop received */ -#define PEER_CAP_HOSTNAME_ADV (1U << 15) /* hostname advertised */ -#define PEER_CAP_HOSTNAME_RCV (1U << 16) /* hostname received */ -#define PEER_CAP_ENHANCED_RR_ADV (1U << 17) /* enhanced rr advertised */ -#define PEER_CAP_ENHANCED_RR_RCV (1U << 18) /* enhanced rr received */ -#define PEER_CAP_EXTENDED_MESSAGE_ADV (1U << 19) -#define PEER_CAP_EXTENDED_MESSAGE_RCV (1U << 20) -#define PEER_CAP_LLGR_ADV (1U << 21) -#define PEER_CAP_LLGR_RCV (1U << 22) +#define PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV (1ULL << 10) +#define PEER_CAP_ADDPATH_ADV (1ULL << 11) /* addpath advertised */ +#define PEER_CAP_ADDPATH_RCV (1ULL << 12) /* addpath received */ +#define PEER_CAP_ENHE_ADV (1ULL << 13) /* Extended nexthop advertised */ +#define PEER_CAP_ENHE_RCV (1ULL << 14) /* Extended nexthop received */ +#define PEER_CAP_HOSTNAME_ADV (1ULL << 15) /* hostname advertised */ +#define PEER_CAP_HOSTNAME_RCV (1ULL << 16) /* hostname received */ +#define PEER_CAP_ENHANCED_RR_ADV (1ULL << 17) /* enhanced rr advertised */ +#define PEER_CAP_ENHANCED_RR_RCV (1ULL << 18) /* enhanced rr received */ +#define PEER_CAP_EXTENDED_MESSAGE_ADV (1ULL << 19) +#define PEER_CAP_EXTENDED_MESSAGE_RCV (1ULL << 20) +#define PEER_CAP_LLGR_ADV (1ULL << 21) +#define PEER_CAP_LLGR_RCV (1ULL << 22) /* sent graceful-restart notification (N) bit */ -#define PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV (1U << 23) +#define PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV (1ULL << 23) /* received graceful-restart notification (N) bit */ -#define PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV (1U << 24) -#define PEER_CAP_ROLE_ADV (1U << 25) /* role advertised */ -#define PEER_CAP_ROLE_RCV (1U << 26) /* role received */ -#define PEER_CAP_SOFT_VERSION_ADV (1U << 27) -#define PEER_CAP_SOFT_VERSION_RCV (1U << 28) +#define PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV (1ULL << 24) +#define PEER_CAP_ROLE_ADV (1ULL << 25) /* role advertised */ +#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) /* Capability flags (reset in bgp_stop) */ uint32_t af_cap[AFI_MAX][SAFI_MAX]; @@ -1439,6 +1460,7 @@ struct peer { #define PEER_FLAG_AIGP (1ULL << 34) #define PEER_FLAG_GRACEFUL_SHUTDOWN (1ULL << 35) #define PEER_FLAG_CAPABILITY_SOFT_VERSION (1ULL << 36) +#define PEER_FLAG_CAPABILITY_FQDN (1ULL << 37) /* fqdn capability */ /* *GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART @@ -1505,6 +1527,7 @@ struct peer { #define PEER_FLAG_MAX_PREFIX_FORCE (1ULL << 26) #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_ACCEPT_OWN (1ULL << 63) enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX]; @@ -1742,6 +1765,7 @@ struct peer { #define PEER_DOWN_PFX_COUNT 33U /* Reached received prefix count */ #define PEER_DOWN_SOCKET_ERROR 34U /* Some socket error happened */ #define PEER_DOWN_RTT_SHUTDOWN 35U /* Automatically shutdown due to RTT */ +#define PEER_DOWN_SUPPRESS_FIB_PENDING 36U /* Suppress fib pending changed */ /* * Remember to update peer_down_str in bgp_fsm.c when you add * a new value to the last_reset reason @@ -1868,11 +1892,11 @@ struct bgp_nlri { /* SAFI. */ uint8_t safi; /* iana_safi_t */ - /* Pointer to NLRI byte stream. */ - uint8_t *nlri; - /* Length of whole NLRI. */ bgp_size_t length; + + /* Pointer to NLRI byte stream. */ + uint8_t *nlri; }; /* BGP versions. */ @@ -2042,7 +2066,6 @@ struct bgp_nlri { #define BGP_UPTIME_LEN 25 /* Default configuration settings for bgpd. */ -#define BGP_VTY_PORT 2605 #define BGP_DEFAULT_CONFIG "bgpd.conf" /* BGP Dynamic Neighbors feature */ @@ -2064,7 +2087,8 @@ enum bgp_clear_type { BGP_CLEAR_SOFT_IN, BGP_CLEAR_SOFT_BOTH, BGP_CLEAR_SOFT_IN_ORF_PREFIX, - BGP_CLEAR_MESSAGE_STATS + BGP_CLEAR_MESSAGE_STATS, + BGP_CLEAR_CAPABILITIES, }; /* Macros. */ @@ -2430,6 +2454,8 @@ extern enum asnotation_mode bgp_get_asnotation(struct bgp *bgp); extern void bgp_route_map_terminate(void); +extern bool bgp_route_map_has_extcommunity_rt(const struct route_map *map); + extern int peer_cmp(struct peer *p1, struct peer *p2); extern int bgp_map_afi_safi_iana2int(iana_afi_t pkt_afi, iana_safi_t pkt_safi, @@ -2721,6 +2747,9 @@ extern bool bgp_path_attribute_discard(struct peer *peer, char *buf, size_t size); extern bool bgp_path_attribute_treat_as_withdraw(struct peer *peer, char *buf, size_t size); + +extern void srv6_function_free(struct bgp_srv6_function *func); + #ifdef _FRR_ATTRIBUTE_PRINTFRR /* clang-format off */ #pragma FRR printfrr_ext "%pBP" (struct peer *) diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c index 5b6961d..a452ebe 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.c +++ b/bgpd/rfapi/bgp_rfapi_cfg.c @@ -531,7 +531,7 @@ rfapi_group_new(struct bgp *bgp, rfapi_group_cfg_type_t type, const char *name) rfg = XCALLOC(MTYPE_RFAPI_GROUP_CFG, sizeof(struct rfapi_nve_group_cfg)); rfg->type = type; - rfg->name = strdup(name); + rfg->name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, name); /* add to tail of list */ listnode_add(bgp->rfapi_cfg->nve_groups_sequential, rfg); rfg->label = MPLS_LABEL_NONE; @@ -832,8 +832,8 @@ DEFUN (vnc_redistribute_protocol, if (bgp->rfapi_cfg->redist_bgp_exterior_view_name) { VNC_REDIST_DISABLE(bgp, afi, type); /* disabled view implicitly */ - free(bgp->rfapi_cfg->redist_bgp_exterior_view_name); - bgp->rfapi_cfg->redist_bgp_exterior_view_name = NULL; + XFREE(MTYPE_RFAPI_GROUP_CFG, + bgp->rfapi_cfg->redist_bgp_exterior_view_name); } bgp->rfapi_cfg->redist_bgp_exterior_view = bgp; } @@ -873,10 +873,8 @@ DEFUN (vnc_no_redistribute_protocol, VNC_REDIST_DISABLE(bgp, afi, type); if (type == ZEBRA_ROUTE_BGP_DIRECT_EXT) { - if (bgp->rfapi_cfg->redist_bgp_exterior_view_name) { - free(bgp->rfapi_cfg->redist_bgp_exterior_view_name); - bgp->rfapi_cfg->redist_bgp_exterior_view_name = NULL; - } + XFREE(MTYPE_RFAPI_GROUP_CFG, + bgp->rfapi_cfg->redist_bgp_exterior_view_name); bgp->rfapi_cfg->redist_bgp_exterior_view = NULL; } @@ -905,9 +903,10 @@ DEFUN (vnc_redistribute_bgp_exterior, return CMD_WARNING_CONFIG_FAILED; } - if (bgp->rfapi_cfg->redist_bgp_exterior_view_name) - free(bgp->rfapi_cfg->redist_bgp_exterior_view_name); - bgp->rfapi_cfg->redist_bgp_exterior_view_name = strdup(argv[5]->arg); + XFREE(MTYPE_RFAPI_GROUP_CFG, + bgp->rfapi_cfg->redist_bgp_exterior_view_name); + bgp->rfapi_cfg->redist_bgp_exterior_view_name = + XSTRDUP(MTYPE_RFAPI_GROUP_CFG, argv[5]->arg); /* could be NULL if name is not defined yet */ bgp->rfapi_cfg->redist_bgp_exterior_view = bgp_lookup_by_name(argv[5]->arg); @@ -935,9 +934,9 @@ DEFUN (vnc_redistribute_nvegroup, */ bgp->rfapi_cfg->rfg_redist = bgp_rfapi_cfg_match_byname( bgp, argv[3]->arg, RFAPI_GROUP_CFG_NVE); - if (bgp->rfapi_cfg->rfg_redist_name) - free(bgp->rfapi_cfg->rfg_redist_name); - bgp->rfapi_cfg->rfg_redist_name = strdup(argv[3]->arg); + XFREE(MTYPE_RFAPI_GROUP_CFG, bgp->rfapi_cfg->rfg_redist_name); + bgp->rfapi_cfg->rfg_redist_name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[3]->arg); vnc_redistribute_postchange(bgp); @@ -959,9 +958,7 @@ DEFUN (vnc_redistribute_no_nvegroup, vnc_redistribute_prechange(bgp); bgp->rfapi_cfg->rfg_redist = NULL; - if (bgp->rfapi_cfg->rfg_redist_name) - free(bgp->rfapi_cfg->rfg_redist_name); - bgp->rfapi_cfg->rfg_redist_name = NULL; + XFREE(MTYPE_RFAPI_GROUP_CFG, bgp->rfapi_cfg->rfg_redist_name); vnc_redistribute_postchange(bgp); @@ -1030,9 +1027,7 @@ DEFUN (vnc_redist_bgpdirect_no_prefixlist, vnc_redistribute_prechange(bgp); - if (hc->plist_redist_name[route_type][afi]) - free(hc->plist_redist_name[route_type][afi]); - hc->plist_redist_name[route_type][afi] = NULL; + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->plist_redist_name[route_type][afi]); hc->plist_redist[route_type][afi] = NULL; vnc_redistribute_postchange(bgp); @@ -1074,9 +1069,9 @@ DEFUN (vnc_redist_bgpdirect_prefixlist, vnc_redistribute_prechange(bgp); - if (hc->plist_redist_name[route_type][afi]) - free(hc->plist_redist_name[route_type][afi]); - hc->plist_redist_name[route_type][afi] = strdup(argv[5]->arg); + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->plist_redist_name[route_type][afi]); + hc->plist_redist_name[route_type][afi] = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[5]->arg); hc->plist_redist[route_type][afi] = prefix_list_lookup(afi, argv[5]->arg); @@ -1110,9 +1105,7 @@ DEFUN (vnc_redist_bgpdirect_no_routemap, vnc_redistribute_prechange(bgp); - if (hc->routemap_redist_name[route_type]) - free(hc->routemap_redist_name[route_type]); - hc->routemap_redist_name[route_type] = NULL; + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->routemap_redist_name[route_type]); hc->routemap_redist[route_type] = NULL; vnc_redistribute_postchange(bgp); @@ -1144,15 +1137,16 @@ DEFUN (vnc_redist_bgpdirect_routemap, vnc_redistribute_prechange(bgp); - if (hc->routemap_redist_name[route_type]) - free(hc->routemap_redist_name[route_type]); + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->routemap_redist_name[route_type]); /* If the old route map config overwrite with new * route map config , old routemap counter have to be * reduced. */ route_map_counter_decrement(hc->routemap_redist[route_type]); - hc->routemap_redist_name[route_type] = strdup(argv[4]->arg); + hc->routemap_redist_name[route_type] = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[4]->arg); + hc->routemap_redist[route_type] = route_map_lookup_by_name(argv[4]->arg); route_map_counter_increment(hc->routemap_redist[route_type]); @@ -1197,9 +1191,8 @@ DEFUN (vnc_nve_group_redist_bgpdirect_no_prefixlist, vnc_redistribute_prechange(bgp); - if (rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]) - free(rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]); - rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi] = NULL; + XFREE(MTYPE_RFAPI_GROUP_CFG, + rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]); rfg->plist_redist[ZEBRA_ROUTE_BGP_DIRECT][afi] = NULL; vnc_redistribute_postchange(bgp); @@ -1238,10 +1231,10 @@ DEFUN (vnc_nve_group_redist_bgpdirect_prefixlist, vnc_redistribute_prechange(bgp); - if (rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]) - free(rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]); + XFREE(MTYPE_RFAPI_GROUP_CFG, + rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]); rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi] = - strdup(argv[4]->arg); + XSTRDUP(MTYPE_RFAPI_GROUP_CFG, argv[4]->arg); rfg->plist_redist[ZEBRA_ROUTE_BGP_DIRECT][afi] = prefix_list_lookup(afi, argv[4]->arg); @@ -1272,11 +1265,10 @@ DEFUN (vnc_nve_group_redist_bgpdirect_no_routemap, vnc_redistribute_prechange(bgp); - if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]) - free(rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]); + XFREE(MTYPE_RFAPI_GROUP_CFG, + rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]); route_map_counter_decrement( rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT]); - rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT] = NULL; rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT] = NULL; vnc_redistribute_postchange(bgp); @@ -1305,12 +1297,12 @@ DEFUN (vnc_nve_group_redist_bgpdirect_routemap, vnc_redistribute_prechange(bgp); - if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]) - free(rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]); + XFREE(MTYPE_RFAPI_GROUP_CFG, + rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]); route_map_counter_decrement( rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT]); rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT] = - strdup(argv[3]->arg); + XSTRDUP(MTYPE_RFAPI_GROUP_CFG, argv[3]->arg); rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT] = route_map_lookup_by_name(argv[3]->arg); route_map_counter_increment( @@ -1451,7 +1443,7 @@ DEFUN (vnc_export_nvegroup, } rfgn = rfgn_new(); - rfgn->name = strdup(argv[5]->arg); + rfgn->name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, argv[5]->arg); rfgn->rfg = rfg_new; /* OK if not set yet */ listnode_add(bgp->rfapi_cfg->rfg_export_direct_bgp_l, rfgn); @@ -1487,7 +1479,7 @@ DEFUN (vnc_export_nvegroup, } rfgn = rfgn_new(); - rfgn->name = strdup(argv[5]->arg); + rfgn->name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, argv[5]->arg); rfgn->rfg = rfg_new; /* OK if not set yet */ listnode_add(bgp->rfapi_cfg->rfg_export_zebra_l, rfgn); @@ -1531,7 +1523,7 @@ DEFUN (vnc_no_export_nvegroup, if (rfgn->rfg) vnc_direct_bgp_del_group(bgp, rfgn->rfg); - free(rfgn->name); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfgn->name); list_delete_node( bgp->rfapi_cfg->rfg_export_direct_bgp_l, node); @@ -1548,7 +1540,7 @@ DEFUN (vnc_no_export_nvegroup, if (rfgn->name && !strcmp(rfgn->name, argv[6]->arg)) { if (rfgn->rfg) vnc_zebra_del_group(bgp, rfgn->rfg); - free(rfgn->name); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfgn->name); list_delete_node( bgp->rfapi_cfg->rfg_export_zebra_l, node); @@ -1612,9 +1604,8 @@ DEFUN (vnc_nve_group_export_no_prefixlist, || (rfg->plist_export_zebra_name[afi] && strmatch(argv[idx]->arg, rfg->plist_export_zebra_name[afi]))) { - if (rfg->plist_export_zebra_name[afi]) - free(rfg->plist_export_zebra_name[afi]); - rfg->plist_export_zebra_name[afi] = NULL; + XFREE(MTYPE_RFAPI_GROUP_CFG, + rfg->plist_export_zebra_name[afi]); rfg->plist_export_zebra[afi] = NULL; vnc_zebra_reexport_group_afi(bgp, rfg, afi); @@ -1667,18 +1658,18 @@ DEFUN (vnc_nve_group_export_prefixlist, idx = argc - 1; if (is_bgp) { - if (rfg->plist_export_bgp_name[afi]) - free(rfg->plist_export_bgp_name[afi]); - rfg->plist_export_bgp_name[afi] = strdup(argv[idx]->arg); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfg->plist_export_bgp_name[afi]); + rfg->plist_export_bgp_name[afi] = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[idx]->arg); rfg->plist_export_bgp[afi] = prefix_list_lookup(afi, argv[idx]->arg); vnc_direct_bgp_reexport_group_afi(bgp, rfg, afi); } else { - if (rfg->plist_export_zebra_name[afi]) - free(rfg->plist_export_zebra_name[afi]); - rfg->plist_export_zebra_name[afi] = strdup(argv[idx]->arg); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfg->plist_export_zebra_name[afi]); + rfg->plist_export_zebra_name[afi] = + XSTRDUP(MTYPE_RFAPI_GROUP_CFG, argv[idx]->arg); rfg->plist_export_zebra[afi] = prefix_list_lookup(afi, argv[idx]->arg); @@ -1720,7 +1711,8 @@ DEFUN (vnc_nve_group_export_no_routemap, switch (argv[idx]->text[0]) { case 'z': is_bgp = 0; - /* fall thru */ + idx += 2; + break; case 'b': idx += 2; break; @@ -1734,10 +1726,9 @@ DEFUN (vnc_nve_group_export_no_routemap, || (rfg->routemap_export_bgp_name && strmatch(argv[idx]->arg, rfg->routemap_export_bgp_name))) { - if (rfg->routemap_export_bgp_name) - free(rfg->routemap_export_bgp_name); + XFREE(MTYPE_RFAPI_GROUP_CFG, + rfg->routemap_export_bgp_name); route_map_counter_decrement(rfg->routemap_export_bgp); - rfg->routemap_export_bgp_name = NULL; rfg->routemap_export_bgp = NULL; vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP); @@ -1748,10 +1739,8 @@ DEFUN (vnc_nve_group_export_no_routemap, || (rfg->routemap_export_zebra_name && strmatch(argv[idx]->arg, rfg->routemap_export_zebra_name))) { - if (rfg->routemap_export_zebra_name) - free(rfg->routemap_export_zebra_name); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfg->routemap_export_zebra_name); route_map_counter_decrement(rfg->routemap_export_zebra); - rfg->routemap_export_zebra_name = NULL; rfg->routemap_export_zebra = NULL; vnc_zebra_reexport_group_afi(bgp, rfg, AFI_IP); @@ -1795,20 +1784,20 @@ DEFUN (vnc_nve_group_export_routemap, idx = argc - 1; if (is_bgp) { - if (rfg->routemap_export_bgp_name) - free(rfg->routemap_export_bgp_name); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfg->routemap_export_bgp_name); route_map_counter_decrement(rfg->routemap_export_bgp); - rfg->routemap_export_bgp_name = strdup(argv[idx]->arg); + rfg->routemap_export_bgp_name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[idx]->arg); rfg->routemap_export_bgp = route_map_lookup_by_name(argv[idx]->arg); route_map_counter_increment(rfg->routemap_export_bgp); vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP); vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP6); } else { - if (rfg->routemap_export_zebra_name) - free(rfg->routemap_export_zebra_name); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfg->routemap_export_zebra_name); route_map_counter_decrement(rfg->routemap_export_zebra); - rfg->routemap_export_zebra_name = strdup(argv[idx]->arg); + rfg->routemap_export_zebra_name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[idx]->arg); rfg->routemap_export_zebra = route_map_lookup_by_name(argv[idx]->arg); route_map_counter_increment(rfg->routemap_export_zebra); @@ -1853,9 +1842,8 @@ DEFUN (vnc_nve_export_no_prefixlist, if (((argc > 6) && hc->plist_export_bgp_name[afi] && strmatch(argv[6]->text, hc->plist_export_bgp_name[afi])) || (argc <= 6)) { - - free(hc->plist_export_bgp_name[afi]); - hc->plist_export_bgp_name[afi] = NULL; + XFREE(MTYPE_RFAPI_GROUP_CFG, + hc->plist_export_bgp_name[afi]); hc->plist_export_bgp[afi] = NULL; vnc_direct_bgp_reexport(bgp, afi); } @@ -1864,9 +1852,8 @@ DEFUN (vnc_nve_export_no_prefixlist, && strmatch(argv[6]->text, hc->plist_export_zebra_name[afi])) || (argc <= 6)) { - - free(hc->plist_export_zebra_name[afi]); - hc->plist_export_zebra_name[afi] = NULL; + XFREE(MTYPE_RFAPI_GROUP_CFG, + hc->plist_export_zebra_name[afi]); hc->plist_export_zebra[afi] = NULL; /* TBD vnc_zebra_rh_reexport(bgp, afi); */ } @@ -1899,16 +1886,16 @@ DEFUN (vnc_nve_export_prefixlist, } if (argv[2]->arg[0] == 'b') { - if (hc->plist_export_bgp_name[afi]) - free(hc->plist_export_bgp_name[afi]); - hc->plist_export_bgp_name[afi] = strdup(argv[5]->arg); + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->plist_export_bgp_name[afi]); + hc->plist_export_bgp_name[afi] = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[5]->arg); hc->plist_export_bgp[afi] = prefix_list_lookup(afi, argv[5]->arg); vnc_direct_bgp_reexport(bgp, afi); } else { - if (hc->plist_export_zebra_name[afi]) - free(hc->plist_export_zebra_name[afi]); - hc->plist_export_zebra_name[afi] = strdup(argv[5]->arg); + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->plist_export_zebra_name[afi]); + hc->plist_export_zebra_name[afi] = + XSTRDUP(MTYPE_RFAPI_GROUP_CFG, argv[5]->arg); hc->plist_export_zebra[afi] = prefix_list_lookup(afi, argv[5]->arg); /* TBD vnc_zebra_rh_reexport(bgp, afi); */ @@ -1936,10 +1923,9 @@ DEFUN (vnc_nve_export_no_routemap, if (((argc > 5) && hc->routemap_export_bgp_name && strmatch(argv[5]->text, hc->routemap_export_bgp_name)) || (argc <= 5)) { - - free(hc->routemap_export_bgp_name); + XFREE(MTYPE_RFAPI_GROUP_CFG, + hc->routemap_export_bgp_name); route_map_counter_decrement(hc->routemap_export_bgp); - hc->routemap_export_bgp_name = NULL; hc->routemap_export_bgp = NULL; vnc_direct_bgp_reexport(bgp, AFI_IP); vnc_direct_bgp_reexport(bgp, AFI_IP6); @@ -1949,9 +1935,8 @@ DEFUN (vnc_nve_export_no_routemap, && strmatch(argv[5]->text, hc->routemap_export_zebra_name)) || (argc <= 5)) { - free(hc->routemap_export_zebra_name); + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->routemap_export_zebra_name); route_map_counter_decrement(hc->routemap_export_zebra); - hc->routemap_export_zebra_name = NULL; hc->routemap_export_zebra = NULL; /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP); */ /* TBD vnc_zebra_rh_reexport(bgp, AFI_IP6); */ @@ -1976,20 +1961,20 @@ DEFUN (vnc_nve_export_routemap, hc = bgp->rfapi_cfg; if (argv[2]->arg[0] == 'b') { - if (hc->routemap_export_bgp_name) - free(hc->routemap_export_bgp_name); + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->routemap_export_bgp_name); route_map_counter_decrement(hc->routemap_export_bgp); - hc->routemap_export_bgp_name = strdup(argv[4]->arg); + hc->routemap_export_bgp_name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[4]->arg); hc->routemap_export_bgp = route_map_lookup_by_name(argv[4]->arg); route_map_counter_increment(hc->routemap_export_bgp); vnc_direct_bgp_reexport(bgp, AFI_IP); vnc_direct_bgp_reexport(bgp, AFI_IP6); } else { - if (hc->routemap_export_zebra_name) - free(hc->routemap_export_zebra_name); + XFREE(MTYPE_RFAPI_GROUP_CFG, hc->routemap_export_zebra_name); route_map_counter_decrement(hc->routemap_export_zebra); - hc->routemap_export_zebra_name = strdup(argv[4]->arg); + hc->routemap_export_zebra_name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, + argv[4]->arg); hc->routemap_export_zebra = route_map_lookup_by_name(argv[4]->arg); route_map_counter_increment(hc->routemap_export_zebra); @@ -2319,7 +2304,7 @@ static void bgp_rfapi_delete_nve_group(struct vty *vty, /* NULL = no output */ } /* delete it */ - free(rfg->name); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfg->name); if (rfg->rfapi_import_table) rfapiImportTableRefDelByIt(bgp, rfg->rfapi_import_table); if (rfg->rt_import_list) @@ -3410,7 +3395,7 @@ DEFUN_NOSH (vnc_l2_group, vty_out(vty, "Can't allocate memory for L2 group\n"); return CMD_WARNING_CONFIG_FAILED; } - rfg->name = strdup(argv[2]->arg); + rfg->name = XSTRDUP(MTYPE_RFAPI_GROUP_CFG, argv[2]->arg); /* add to tail of list */ listnode_add(bgp->rfapi_cfg->l2_groups, rfg); } @@ -3428,7 +3413,7 @@ static void bgp_rfapi_delete_l2_group(struct vty *vty, /* NULL = no output */ struct rfapi_l2_group_cfg *rfg) { /* delete it */ - free(rfg->name); + XFREE(MTYPE_RFAPI_GROUP_CFG, rfg->name); if (rfg->rt_import_list) ecommunity_free(&rfg->rt_import_list); if (rfg->rt_export_list) @@ -3590,7 +3575,9 @@ DEFUN (vnc_l2_group_rt, switch (argv[1]->arg[0]) { case 'b': - do_export = 1; /* fall through */ + do_export = 1; + do_import = 1; + break; case 'i': do_import = 1; break; @@ -3840,7 +3827,8 @@ struct rfapi_cfg *bgp_rfapi_cfg_new(struct rfapi_rfp_cfg *cfg) static void bgp_rfapi_rfgn_list_delete(void *data) { struct rfapi_rfg_name *rfgn = data; - free(rfgn->name); + + XFREE(MTYPE_RFAPI_GROUP_CFG, rfgn->name); rfgn_free(rfgn); } diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c index ff7137b..382af05 100644 --- a/bgpd/rfapi/rfapi.c +++ b/bgpd/rfapi/rfapi.c @@ -46,11 +46,6 @@ #include "bgpd/rfapi/rfapi_encap_tlv.h" #include "bgpd/rfapi/vnc_debug.h" -#ifdef HAVE_GLIBC_BACKTRACE -/* for backtrace and friends */ -#include <execinfo.h> -#endif /* HAVE_GLIBC_BACKTRACE */ - #define DEBUG_CLEANUP 0 struct ethaddr rfapi_ethaddr0 = {{0}}; @@ -371,20 +366,19 @@ void del_vnc_route(struct rfapi_descriptor *rfd, for (bpi = (bn ? bgp_dest_get_bgp_path_info(bn) : NULL); bpi; bpi = bpi->next) { - vnc_zlog_debug_verbose( "%s: trying bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p, local_pref=%" PRIu64, __func__, bpi, bpi->peer, bpi->type, bpi->sub_type, - (bpi->extra ? bpi->extra->vnc.export.rfapi_handle + (bpi->extra ? bpi->extra->vnc->vnc.export.rfapi_handle : NULL), CHECK_FLAG(bpi->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF) - ? bpi->attr->local_pref : 0)); - - if (bpi->peer == peer && bpi->type == type - && bpi->sub_type == sub_type && bpi->extra - && bpi->extra->vnc.export.rfapi_handle == (void *)rfd) { + ? bpi->attr->local_pref + : 0)); + if (bpi->peer == peer && bpi->type == type && + bpi->sub_type == sub_type && bpi->extra && + bpi->extra->vnc->vnc.export.rfapi_handle == (void *)rfd) { vnc_zlog_debug_verbose("%s: matched it", __func__); break; @@ -397,8 +391,8 @@ void del_vnc_route(struct rfapi_descriptor *rfd, * route. Leave the route itself in place. * TBD add return code reporting of success/failure */ - if (!bpi || !bpi->extra - || !bpi->extra->vnc.export.local_nexthops) { + if (!bpi || !bpi->extra || + !bpi->extra->vnc->vnc.export.local_nexthops) { /* * no local nexthops */ @@ -414,16 +408,16 @@ void del_vnc_route(struct rfapi_descriptor *rfd, struct listnode *node; struct rfapi_nexthop *pLnh = NULL; - for (ALL_LIST_ELEMENTS_RO(bpi->extra->vnc.export.local_nexthops, + for (ALL_LIST_ELEMENTS_RO(bpi->extra->vnc->vnc.export + .local_nexthops, node, pLnh)) { - if (prefix_same(&pLnh->addr, &lnh->addr)) { break; } } if (pLnh) { - listnode_delete(bpi->extra->vnc.export.local_nexthops, + listnode_delete(bpi->extra->vnc->vnc.export.local_nexthops, pLnh); /* silly rabbit, listnode_delete doesn't invoke @@ -464,8 +458,8 @@ void del_vnc_route(struct rfapi_descriptor *rfd, /* * Delete local_nexthops list */ - if (bpi->extra && bpi->extra->vnc.export.local_nexthops) - list_delete(&bpi->extra->vnc.export.local_nexthops); + if (bpi->extra && bpi->extra->vnc->vnc.export.local_nexthops) + list_delete(&bpi->extra->vnc->vnc.export.local_nexthops); bgp_aggregate_decrement(bgp, p, bpi, afi, safi); bgp_path_info_delete(bn, bpi); @@ -907,11 +901,10 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ */ for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { /* probably only need to check - * bpi->extra->vnc.export.rfapi_handle */ - if (bpi->peer == rfd->peer && bpi->type == type - && bpi->sub_type == sub_type && bpi->extra - && bpi->extra->vnc.export.rfapi_handle == (void *)rfd) { - + * bpi->extra->vnc->vnc.export.rfapi_handle */ + if (bpi->peer == rfd->peer && bpi->type == type && + bpi->sub_type == sub_type && bpi->extra && + bpi->extra->vnc->vnc.export.rfapi_handle == (void *)rfd) { break; } } @@ -923,11 +916,11 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ * what is advertised via BGP */ if (lnh) { - if (!bpi->extra->vnc.export.local_nexthops) { + if (!bpi->extra->vnc->vnc.export.local_nexthops) { /* TBD make arrangements to free when needed */ - bpi->extra->vnc.export.local_nexthops = + bpi->extra->vnc->vnc.export.local_nexthops = list_new(); - bpi->extra->vnc.export.local_nexthops->del = + bpi->extra->vnc->vnc.export.local_nexthops->del = rfapi_nexthop_free; } @@ -937,10 +930,9 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ struct listnode *node; struct rfapi_nexthop *pLnh = NULL; - for (ALL_LIST_ELEMENTS_RO( - bpi->extra->vnc.export.local_nexthops, - node, pLnh)) { - + for (ALL_LIST_ELEMENTS_RO(bpi->extra->vnc->vnc.export + .local_nexthops, + node, pLnh)) { if (prefix_same(&pLnh->addr, &lnh->addr)) { break; } @@ -951,9 +943,9 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ */ if (!pLnh) { pLnh = rfapi_nexthop_new(lnh); - listnode_add( - bpi->extra->vnc.export.local_nexthops, - pLnh); + listnode_add(bpi->extra->vnc->vnc.export + .local_nexthops, + pLnh); } } @@ -1025,7 +1017,9 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */ /* save backref to rfapi handle */ bgp_path_info_extra_get(new); - new->extra->vnc.export.rfapi_handle = (void *)rfd; + 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]); /* debug */ @@ -2091,24 +2085,7 @@ int rfapi_close(void *handle) vnc_zlog_debug_verbose("%s: rfd=%p", __func__, rfd); #ifdef RFAPI_WHO_IS_CALLING_ME -#ifdef HAVE_GLIBC_BACKTRACE -#define RFAPI_DEBUG_BACKTRACE_NENTRIES 5 - { - void *buf[RFAPI_DEBUG_BACKTRACE_NENTRIES]; - char **syms; - int i; - size_t size; - - size = backtrace(buf, RFAPI_DEBUG_BACKTRACE_NENTRIES); - syms = backtrace_symbols(buf, size); - for (i = 0; i < size && i < RFAPI_DEBUG_BACKTRACE_NENTRIES; - ++i) { - vnc_zlog_debug_verbose("backtrace[%2d]: %s", i, - syms[i]); - } - free(syms); - } -#endif + zlog_backtrace(LOG_INFO); #endif bgp = rfd->bgp; diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c index a93e186..168b8e4 100644 --- a/bgpd/rfapi/rfapi_import.c +++ b/bgpd/rfapi/rfapi_import.c @@ -44,11 +44,6 @@ #include "bgpd/rfapi/rfapi_encap_tlv.h" #include "bgpd/rfapi/vnc_debug.h" -#ifdef HAVE_GLIBC_BACKTRACE -/* for backtrace and friends */ -#include <execinfo.h> -#endif /* HAVE_GLIBC_BACKTRACE */ - #undef DEBUG_MONITOR_MOVE_SHORTER #undef DEBUG_RETURNED_NHL #undef DEBUG_ROUTE_COUNTERS @@ -79,32 +74,6 @@ struct rfapi_withdraw { /* * DEBUG FUNCTION - * It's evil and fiendish. It's compiler-dependent. - * ? Might need LDFLAGS -rdynamic to produce all function names - */ -void rfapiDebugBacktrace(void) -{ -#ifdef HAVE_GLIBC_BACKTRACE -#define RFAPI_DEBUG_BACKTRACE_NENTRIES 200 - void *buf[RFAPI_DEBUG_BACKTRACE_NENTRIES]; - char **syms; - size_t i; - size_t size; - - size = backtrace(buf, RFAPI_DEBUG_BACKTRACE_NENTRIES); - syms = backtrace_symbols(buf, size); - - for (i = 0; i < size && i < RFAPI_DEBUG_BACKTRACE_NENTRIES; ++i) { - vnc_zlog_debug_verbose("backtrace[%2zu]: %s", i, syms[i]); - } - - free(syms); -#else -#endif -} - -/* - * DEBUG FUNCTION * Count remote routes and compare with actively-maintained values. * Abort if they disagree. */ @@ -428,18 +397,22 @@ int rfapiGetUnAddrOfVpnBi(struct bgp_path_info *bpi, struct prefix *p) * advertisement */ if (bpi->extra) { - switch (bpi->extra->vnc.import.un_family) { + switch (bpi->extra->vnc->vnc.import.un_family) { case AF_INET: if (p) { - p->family = bpi->extra->vnc.import.un_family; - p->u.prefix4 = bpi->extra->vnc.import.un.addr4; + p->family = + bpi->extra->vnc->vnc.import.un_family; + p->u.prefix4 = + bpi->extra->vnc->vnc.import.un.addr4; p->prefixlen = IPV4_MAX_BITLEN; } return 0; case AF_INET6: if (p) { - p->family = bpi->extra->vnc.import.un_family; - p->u.prefix6 = bpi->extra->vnc.import.un.addr6; + p->family = + bpi->extra->vnc->vnc.import.un_family; + p->u.prefix6 = + bpi->extra->vnc->vnc.import.un.addr6; p->prefixlen = IPV6_MAX_BITLEN; } return 0; @@ -475,9 +448,11 @@ static struct bgp_path_info *rfapiBgpInfoCreate(struct attr *attr, new->attr = bgp_attr_intern(attr); bgp_path_info_extra_get(new); + new->extra->vnc = XCALLOC(MTYPE_BGP_ROUTE_EXTRA_VNC, + sizeof(struct bgp_path_info_extra_vnc)); if (prd) { - new->extra->vnc.import.rd = *prd; - new->extra->vnc.import.create_time = monotime(NULL); + 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]); @@ -842,13 +817,13 @@ static void rfapiBgpInfoChainFree(struct bgp_path_info *bpi) * If there is a timer waiting to delete this bpi, cancel * the timer and delete immediately */ - if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) - && bpi->extra->vnc.import.timer) { + if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && + bpi->extra->vnc->vnc.import.timer) { struct rfapi_withdraw *wcb = - EVENT_ARG(bpi->extra->vnc.import.timer); + EVENT_ARG(bpi->extra->vnc->vnc.import.timer); XFREE(MTYPE_RFAPI_WITHDRAW, wcb); - EVENT_OFF(bpi->extra->vnc.import.timer); + EVENT_OFF(bpi->extra->vnc->vnc.import.timer); } next = bpi->next; @@ -1136,15 +1111,15 @@ static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1, */ if (rfapiGetVncTunnelUnAddr(bpi1->attr, &pfx_un1)) { if (bpi1->extra) { - pfx_un1.family = bpi1->extra->vnc.import.un_family; - switch (bpi1->extra->vnc.import.un_family) { + pfx_un1.family = bpi1->extra->vnc->vnc.import.un_family; + switch (bpi1->extra->vnc->vnc.import.un_family) { case AF_INET: pfx_un1.u.prefix4 = - bpi1->extra->vnc.import.un.addr4; + bpi1->extra->vnc->vnc.import.un.addr4; break; case AF_INET6: pfx_un1.u.prefix6 = - bpi1->extra->vnc.import.un.addr6; + bpi1->extra->vnc->vnc.import.un.addr6; break; default: pfx_un1.family = AF_UNSPEC; @@ -1155,15 +1130,15 @@ static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1, if (rfapiGetVncTunnelUnAddr(bpi2->attr, &pfx_un2)) { if (bpi2->extra) { - pfx_un2.family = bpi2->extra->vnc.import.un_family; - switch (bpi2->extra->vnc.import.un_family) { + pfx_un2.family = bpi2->extra->vnc->vnc.import.un_family; + switch (bpi2->extra->vnc->vnc.import.un_family) { case AF_INET: pfx_un2.u.prefix4 = - bpi2->extra->vnc.import.un.addr4; + bpi2->extra->vnc->vnc.import.un.addr4; break; case AF_INET6: pfx_un2.u.prefix6 = - bpi2->extra->vnc.import.un.addr6; + bpi2->extra->vnc->vnc.import.un.addr6; break; default: pfx_un2.family = AF_UNSPEC; @@ -1268,9 +1243,8 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, new->prefix = *rprefix; - if (bpi->extra - && decode_rd_type(bpi->extra->vnc.import.rd.val) - == RD_TYPE_VNC_ETH) { + if (bpi->extra && decode_rd_type(bpi->extra->vnc->vnc.import.rd.val) == + RD_TYPE_VNC_ETH) { /* ethernet */ struct rfapi_vn_option *vo; @@ -1289,7 +1263,8 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, &vo->v.l2addr.tag_id); /* local_nve_id comes from lower byte of RD type */ - vo->v.l2addr.local_nve_id = bpi->extra->vnc.import.rd.val[1]; + vo->v.l2addr.local_nve_id = + 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]); @@ -1300,8 +1275,9 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, * If there is an auxiliary prefix (i.e., host IP address), * use it as the nexthop prefix instead of the query prefix */ - if (bpi->extra->vnc.import.aux_prefix.family) { - rfapiQprefix2Rprefix(&bpi->extra->vnc.import.aux_prefix, + if (bpi->extra->vnc->vnc.import.aux_prefix.family) { + rfapiQprefix2Rprefix(&bpi->extra->vnc->vnc.import + .aux_prefix, &new->prefix); } } @@ -1402,15 +1378,16 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix, /* * use cached UN address from ENCAP route */ - new->un_address.addr_family = bpi->extra->vnc.import.un_family; + new->un_address.addr_family = + bpi->extra->vnc->vnc.import.un_family; switch (new->un_address.addr_family) { case AF_INET: new->un_address.addr.v4 = - bpi->extra->vnc.import.un.addr4; + bpi->extra->vnc->vnc.import.un.addr4; break; case AF_INET6: new->un_address.addr.v6 = - bpi->extra->vnc.import.un.addr6; + bpi->extra->vnc->vnc.import.un.addr6; break; default: zlog_warn("%s: invalid UN addr family (%d) for bpi %p", @@ -1537,7 +1514,7 @@ static int rfapiNhlAddNodeRoutes( if (is_l2) { /* L2 routes: semantic nexthop in aux_prefix; VN addr * ain't it */ - pfx_vn = bpi->extra->vnc.import.aux_prefix; + pfx_vn = bpi->extra->vnc->vnc.import.aux_prefix; } else { rfapiNexthop2Prefix(bpi->attr, &pfx_vn); } @@ -1709,7 +1686,7 @@ struct rfapi_next_hop_entry *rfapiRouteNode2NextHopList( #ifdef DEBUG_RETURNED_NHL vnc_zlog_debug_verbose("%s: called with node pfx=%rRN", __func__, rn); - rfapiDebugBacktrace(); + zlog_backtrace(LOG_INFO); #endif rfapiQprefix2Rprefix(p, &rprefix); @@ -2011,9 +1988,10 @@ static int rfapi_bi_peer_rd_cmp(const void *b1, const void *b2) /* * compare RDs */ - return vnc_prefix_cmp( - (const struct prefix *)&bpi1->extra->vnc.import.rd, - (const struct prefix *)&bpi2->extra->vnc.import.rd); + return vnc_prefix_cmp((const struct prefix *)&bpi1->extra->vnc->vnc + .import.rd, + (const struct prefix *)&bpi2->extra->vnc->vnc + .import.rd); } /* @@ -2038,8 +2016,8 @@ static int rfapi_bi_peer_rd_aux_cmp(const void *b1, const void *b2) /* * compare RDs */ - rc = vnc_prefix_cmp((struct prefix *)&bpi1->extra->vnc.import.rd, - (struct prefix *)&bpi2->extra->vnc.import.rd); + rc = vnc_prefix_cmp((struct prefix *)&bpi1->extra->vnc->vnc.import.rd, + (struct prefix *)&bpi2->extra->vnc->vnc.import.rd); if (rc) { return rc; } @@ -2056,19 +2034,18 @@ static int rfapi_bi_peer_rd_aux_cmp(const void *b1, const void *b2) * because there is no guarantee of the order the test key and * the real key will be passed) */ - if ((bpi1->extra->vnc.import.aux_prefix.family == AF_ETHERNET - && (bpi1->extra->vnc.import.aux_prefix.prefixlen == 1)) - || (bpi2->extra->vnc.import.aux_prefix.family == AF_ETHERNET - && (bpi2->extra->vnc.import.aux_prefix.prefixlen == 1))) { - + if ((bpi1->extra->vnc->vnc.import.aux_prefix.family == AF_ETHERNET && + (bpi1->extra->vnc->vnc.import.aux_prefix.prefixlen == 1)) || + (bpi2->extra->vnc->vnc.import.aux_prefix.family == AF_ETHERNET && + (bpi2->extra->vnc->vnc.import.aux_prefix.prefixlen == 1))) { /* * wildcard aux address specified */ return 0; } - return vnc_prefix_cmp(&bpi1->extra->vnc.import.aux_prefix, - &bpi2->extra->vnc.import.aux_prefix); + return vnc_prefix_cmp(&bpi1->extra->vnc->vnc.import.aux_prefix, + &bpi2->extra->vnc->vnc.import.aux_prefix); } @@ -2086,7 +2063,7 @@ static void rfapiItBiIndexAdd(struct agg_node *rn, /* Import table VPN node */ assert(bpi->extra); vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRDP", __func__, bpi, - bpi->peer, &bpi->extra->vnc.import.rd); + bpi->peer, &bpi->extra->vnc->vnc.import.rd); sl = RFAPI_RDINDEX_W_ALLOC(rn); if (!sl) { @@ -2123,11 +2100,10 @@ static void rfapiItBiIndexDump(struct agg_node *rn) char buf[RD_ADDRSTRLEN]; char buf_aux_pfx[PREFIX_STRLEN]; - prefix_rd2str( - &k->extra->vnc.import.rd, buf, sizeof(buf), - bgp_get_asnotation(k->peer ? k->peer->bgp : NULL)); - if (k->extra->vnc.import.aux_prefix.family) { - prefix2str(&k->extra->vnc.import.aux_prefix, + prefix_rd2str(&k->extra->vnc->vnc.import.rd, buf, sizeof(buf), + bgp_get_asnotation(k->peer ? k->peer->bgp : NULL)); + if (k->extra->vnc->vnc.import.aux_prefix.family) { + prefix2str(&k->extra->vnc->vnc.import.aux_prefix, buf_aux_pfx, sizeof(buf_aux_pfx)); } else strlcpy(buf_aux_pfx, "(none)", sizeof(buf_aux_pfx)); @@ -2146,6 +2122,7 @@ static struct bgp_path_info *rfapiItBiIndexSearch( int rc; struct bgp_path_info bpi_fake = {0}; struct bgp_path_info_extra bpi_extra = {0}; + struct bgp_path_info_extra_vnc bpi_extra_vnc = { 0 }; struct bgp_path_info *bpi_result; sl = RFAPI_RDINDEX(rn); @@ -2178,27 +2155,25 @@ static struct bgp_path_info *rfapiItBiIndexSearch( for (bpi_result = rn->info; bpi_result; bpi_result = bpi_result->next) { #ifdef DEBUG_BI_SEARCH - vnc_zlog_debug_verbose( - "%s: bpi has prd=%pRDP, peer=%p", __func__, - &bpi_result->extra->vnc.import.rd, - bpi_result->peer); + vnc_zlog_debug_verbose("%s: bpi has prd=%pRDP, peer=%p", + __func__, + &bpi_result->extra->vnc->vnc + .import.rd, + bpi_result->peer); #endif - if (peer == bpi_result->peer - && !prefix_cmp((struct prefix *)&bpi_result->extra - ->vnc.import.rd, - (struct prefix *)prd)) { - + if (peer == bpi_result->peer && + !prefix_cmp((struct prefix *)&bpi_result->extra->vnc + ->vnc.import.rd, + (struct prefix *)prd)) { #ifdef DEBUG_BI_SEARCH vnc_zlog_debug_verbose( "%s: peer and RD same, doing aux_prefix check", __func__); #endif - if (!aux_prefix - || !prefix_cmp( - aux_prefix, - &bpi_result->extra->vnc.import - .aux_prefix)) { - + if (!aux_prefix || + !prefix_cmp(aux_prefix, + &bpi_result->extra->vnc->vnc + .import.aux_prefix)) { #ifdef DEBUG_BI_SEARCH vnc_zlog_debug_verbose("%s: match", __func__); @@ -2212,13 +2187,14 @@ static struct bgp_path_info *rfapiItBiIndexSearch( bpi_fake.peer = peer; bpi_fake.extra = &bpi_extra; - bpi_fake.extra->vnc.import.rd = *prd; + bpi_fake.extra->vnc = &bpi_extra_vnc; + bpi_fake.extra->vnc->vnc.import.rd = *prd; if (aux_prefix) { - bpi_fake.extra->vnc.import.aux_prefix = *aux_prefix; + bpi_fake.extra->vnc->vnc.import.aux_prefix = *aux_prefix; } else { /* wildcard */ - bpi_fake.extra->vnc.import.aux_prefix.family = AF_ETHERNET; - bpi_fake.extra->vnc.import.aux_prefix.prefixlen = 1; + bpi_fake.extra->vnc->vnc.import.aux_prefix.family = AF_ETHERNET; + bpi_fake.extra->vnc->vnc.import.aux_prefix.prefixlen = 1; } rc = skiplist_search(sl, (void *)&bpi_fake, (void *)&bpi_result); @@ -2244,7 +2220,7 @@ static void rfapiItBiIndexDel(struct agg_node *rn, /* Import table VPN node */ int rc; vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRDP", __func__, bpi, - bpi->peer, &bpi->extra->vnc.import.rd); + bpi->peer, &bpi->extra->vnc->vnc.import.rd); sl = RFAPI_RDINDEX(rn); assert(sl); @@ -2292,11 +2268,10 @@ rfapiMonitorEncapAdd(struct rfapi_import_table *import_table, RFAPI_MONITOR_ENCAP_W_ALLOC(rn) = m; /* for easy lookup when deleting vpn route */ - vpn_bpi->extra->vnc.import.hme = m; + vpn_bpi->extra->vnc->vnc.import.hme = m; - vnc_zlog_debug_verbose( - "%s: it=%p, vpn_bpi=%p, afi=%d, encap rn=%p, setting vpn_bpi->extra->vnc.import.hme=%p", - __func__, import_table, vpn_bpi, afi, rn, m); + vnc_zlog_debug_verbose("%s: it=%p, vpn_bpi=%p, afi=%d, encap rn=%p, setting vpn_bpi->extra->vnc->vnc.import.hme=%p", + __func__, import_table, vpn_bpi, afi, rn, m); RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, 0); bgp_attr_intern(vpn_bpi->attr); @@ -2310,7 +2285,7 @@ static void rfapiMonitorEncapDelete(struct bgp_path_info *vpn_bpi) vnc_zlog_debug_verbose("%s: vpn_bpi=%p", __func__, vpn_bpi); if (vpn_bpi->extra) { struct rfapi_monitor_encap *hme = - vpn_bpi->extra->vnc.import.hme; + vpn_bpi->extra->vnc->vnc.import.hme; if (hme) { @@ -2334,7 +2309,7 @@ static void rfapiMonitorEncapDelete(struct bgp_path_info *vpn_bpi) agg_unlock_node(hme->rn); /* decr ref count */ XFREE(MTYPE_RFAPI_MONITOR_ENCAP, hme); - vpn_bpi->extra->vnc.import.hme = NULL; + vpn_bpi->extra->vnc->vnc.import.hme = NULL; } } } @@ -2573,21 +2548,21 @@ static void rfapiCopyUnEncap2VPN(struct bgp_path_info *encap_bpi, vnc_zlog_debug_verbose("%s: vpn_bpi->extra=%p", __func__, vpn_bpi->extra); - vpn_bpi->extra->vnc.import.un_family = AF_INET; - vpn_bpi->extra->vnc.import.un.addr4 = + vpn_bpi->extra->vnc->vnc.import.un_family = AF_INET; + vpn_bpi->extra->vnc->vnc.import.un.addr4 = encap_bpi->attr->mp_nexthop_global_in; break; case AF_INET6: - vpn_bpi->extra->vnc.import.un_family = AF_INET6; - vpn_bpi->extra->vnc.import.un.addr6 = + vpn_bpi->extra->vnc->vnc.import.un_family = AF_INET6; + vpn_bpi->extra->vnc->vnc.import.un.addr6 = encap_bpi->attr->mp_nexthop_global; break; default: zlog_warn("%s: invalid encap nexthop length: %d", __func__, encap_bpi->attr->mp_nexthop_len); - vpn_bpi->extra->vnc.import.un_family = AF_UNSPEC; + vpn_bpi->extra->vnc->vnc.import.un_family = AF_UNSPEC; break; } } @@ -2612,9 +2587,9 @@ rfapiWithdrawEncapUpdateCachedUn(struct rfapi_import_table *import_table, __func__); return 1; } - vpn_bpi->extra->vnc.import.un_family = AF_UNSPEC; - memset(&vpn_bpi->extra->vnc.import.un, 0, - sizeof(vpn_bpi->extra->vnc.import.un)); + vpn_bpi->extra->vnc->vnc.import.un_family = AF_UNSPEC; + memset(&vpn_bpi->extra->vnc->vnc.import.un, 0, + sizeof(vpn_bpi->extra->vnc->vnc.import.un)); if (CHECK_FLAG(vpn_bpi->flags, BGP_PATH_VALID)) { if (rfapiGetVncTunnelUnAddr(vpn_bpi->attr, NULL)) { UNSET_FLAG(vpn_bpi->flags, BGP_PATH_VALID); @@ -2785,9 +2760,9 @@ rfapiBiStartWithdrawTimer(struct rfapi_import_table *import_table, assert(bpi->extra); if (lifetime > UINT32_MAX / 1001) { /* sub-optimal case, but will probably never happen */ - bpi->extra->vnc.import.timer = NULL; + bpi->extra->vnc->vnc.import.timer = NULL; event_add_timer(bm->master, timer_service_func, wcb, lifetime, - &bpi->extra->vnc.import.timer); + &bpi->extra->vnc->vnc.import.timer); } else { static uint32_t jitter; uint32_t lifetime_msec; @@ -2801,10 +2776,10 @@ rfapiBiStartWithdrawTimer(struct rfapi_import_table *import_table, lifetime_msec = (lifetime * 1000) + jitter; - bpi->extra->vnc.import.timer = NULL; + bpi->extra->vnc->vnc.import.timer = NULL; event_add_timer_msec(bm->master, timer_service_func, wcb, lifetime_msec, - &bpi->extra->vnc.import.timer); + &bpi->extra->vnc->vnc.import.timer); } /* re-sort route list (BGP_PATH_REMOVED routes are last) */ @@ -3017,17 +2992,16 @@ static void rfapiBgpInfoFilteredImportEncap( * Compare RDs * * RD of import table bpi is in - * bpi->extra->vnc.import.rd RD of info_orig is in prd + * bpi->extra->vnc->vnc.import.rd RD of info_orig is in prd */ if (!bpi->extra) { vnc_zlog_debug_verbose("%s: no bpi->extra", __func__); continue; } - if (prefix_cmp( - (struct prefix *)&bpi->extra->vnc.import.rd, - (struct prefix *)prd)) { - + if (prefix_cmp((struct prefix *)&bpi->extra->vnc->vnc + .import.rd, + (struct prefix *)prd)) { vnc_zlog_debug_verbose("%s: prd does not match", __func__); continue; @@ -3071,13 +3045,14 @@ static void rfapiBgpInfoFilteredImportEncap( * a previous withdraw, we must cancel its * timer. */ - if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) - && bpi->extra->vnc.import.timer) { + if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && + bpi->extra->vnc->vnc.import.timer) { struct rfapi_withdraw *wcb = EVENT_ARG( - bpi->extra->vnc.import.timer); + bpi->extra->vnc->vnc.import.timer); XFREE(MTYPE_RFAPI_WITHDRAW, wcb); - EVENT_OFF(bpi->extra->vnc.import.timer); + EVENT_OFF(bpi->extra->vnc->vnc.import + .timer); } if (action == FIF_ACTION_UPDATE) { @@ -3163,12 +3138,12 @@ static void rfapiBgpInfoFilteredImportEncap( vnc_zlog_debug_verbose( "%s: removing holddown bpi matching NVE of new route", __func__); - if (bpi->extra->vnc.import.timer) { + if (bpi->extra->vnc->vnc.import.timer) { struct rfapi_withdraw *wcb = - EVENT_ARG(bpi->extra->vnc.import.timer); + EVENT_ARG(bpi->extra->vnc->vnc.import.timer); XFREE(MTYPE_RFAPI_WITHDRAW, wcb); - EVENT_OFF(bpi->extra->vnc.import.timer); + EVENT_OFF(bpi->extra->vnc->vnc.import.timer); } rfapiExpireEncapNow(import_table, rn, bpi); } @@ -3523,13 +3498,14 @@ void rfapiBgpInfoFilteredImportVPN( * a previous withdraw, we must cancel its * timer. */ - if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) - && bpi->extra->vnc.import.timer) { + if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && + bpi->extra->vnc->vnc.import.timer) { struct rfapi_withdraw *wcb = EVENT_ARG( - bpi->extra->vnc.import.timer); + bpi->extra->vnc->vnc.import.timer); XFREE(MTYPE_RFAPI_WITHDRAW, wcb); - EVENT_OFF(bpi->extra->vnc.import.timer); + EVENT_OFF(bpi->extra->vnc->vnc.import + .timer); import_table->holddown_count[afi] -= 1; RFAPI_UPDATE_ITABLE_COUNT( @@ -3602,7 +3578,7 @@ void rfapiBgpInfoFilteredImportVPN( /* Not a big deal, just means VPN route got here first */ vnc_zlog_debug_verbose("%s: no encap route for vn addr %pFX", __func__, &vn_prefix); - info_new->extra->vnc.import.un_family = AF_UNSPEC; + info_new->extra->vnc->vnc.import.un_family = AF_UNSPEC; } if (rn) { @@ -3624,7 +3600,7 @@ void rfapiBgpInfoFilteredImportVPN( vnc_zlog_debug_verbose("%s: setting BPI's aux_prefix", __func__); - info_new->extra->vnc.import.aux_prefix = *aux_prefix; + info_new->extra->vnc->vnc.import.aux_prefix = *aux_prefix; } vnc_zlog_debug_verbose("%s: inserting bpi %p at prefix %pRN #%d", @@ -3742,12 +3718,12 @@ void rfapiBgpInfoFilteredImportVPN( vnc_zlog_debug_verbose( "%s: removing holddown bpi matching NVE of new route", __func__); - if (bpi->extra->vnc.import.timer) { + if (bpi->extra->vnc->vnc.import.timer) { struct rfapi_withdraw *wcb = - EVENT_ARG(bpi->extra->vnc.import.timer); + EVENT_ARG(bpi->extra->vnc->vnc.import.timer); XFREE(MTYPE_RFAPI_WITHDRAW, wcb); - EVENT_OFF(bpi->extra->vnc.import.timer); + EVENT_OFF(bpi->extra->vnc->vnc.import.timer); } rfapiExpireVpnNow(import_table, rn, bpi, 0); } @@ -4479,12 +4455,10 @@ static void rfapiDeleteRemotePrefixesIt( if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { if (!delete_holddown) continue; - if (bpi->extra->vnc.import.timer) { - struct rfapi_withdraw *wcb = - EVENT_ARG( - bpi->extra->vnc - .import - .timer); + if (bpi->extra->vnc->vnc.import.timer) { + struct rfapi_withdraw *wcb = EVENT_ARG( + bpi->extra->vnc->vnc + .import.timer); wcb->import_table ->holddown_count[afi] -= @@ -4494,8 +4468,8 @@ static void rfapiDeleteRemotePrefixesIt( afi, 1); XFREE(MTYPE_RFAPI_WITHDRAW, wcb); - EVENT_OFF(bpi->extra->vnc.import - .timer); + EVENT_OFF(bpi->extra->vnc->vnc + .import.timer); } } else { if (!delete_active) diff --git a/bgpd/rfapi/rfapi_import.h b/bgpd/rfapi/rfapi_import.h index dd06afe..1a37e1c 100644 --- a/bgpd/rfapi/rfapi_import.h +++ b/bgpd/rfapi/rfapi_import.h @@ -57,8 +57,6 @@ struct rfapi_import_table { extern uint8_t rfapiRfpCost(struct attr *attr); -extern void rfapiDebugBacktrace(void); - extern void rfapiCheckRouteCount(void); /* diff --git a/bgpd/rfapi/rfapi_monitor.c b/bgpd/rfapi/rfapi_monitor.c index 3fe957b..146e0d1 100644 --- a/bgpd/rfapi/rfapi_monitor.c +++ b/bgpd/rfapi/rfapi_monitor.c @@ -354,7 +354,7 @@ struct agg_node *rfapiMonitorGetAttachNode(struct rfapi_descriptor *rfd, * If there is a cached ENCAP UN address, it's a usable * VPN route */ - if (bpi->extra && bpi->extra->vnc.import.un_family) { + if (bpi->extra && bpi->extra->vnc->vnc.import.un_family) { break; } diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c index 5784f95..316904e 100644 --- a/bgpd/rfapi/rfapi_rib.c +++ b/bgpd/rfapi/rfapi_rib.c @@ -663,9 +663,8 @@ static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri, /* * VN options */ - if (bpi->extra - && decode_rd_type(bpi->extra->vnc.import.rd.val) - == RD_TYPE_VNC_ETH) { + if (bpi->extra && decode_rd_type(bpi->extra->vnc->vnc.import.rd.val) == + RD_TYPE_VNC_ETH) { /* ethernet route */ struct rfapi_vn_option *vo; @@ -678,8 +677,8 @@ static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri, /* copy from RD already stored in bpi, so we don't need it_node */ - memcpy(&vo->v.l2addr.macaddr, bpi->extra->vnc.import.rd.val + 2, - ETH_ALEN); + memcpy(&vo->v.l2addr.macaddr, + bpi->extra->vnc->vnc.import.rd.val + 2, ETH_ALEN); (void)rfapiEcommunityGetLNI(bgp_attr_get_ecommunity(bpi->attr), &vo->v.l2addr.logical_net_id); @@ -688,7 +687,8 @@ static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri, &vo->v.l2addr.tag_id); /* local_nve_id comes from RD */ - vo->v.l2addr.local_nve_id = bpi->extra->vnc.import.rd.val[1]; + vo->v.l2addr.local_nve_id = + 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]); @@ -701,8 +701,8 @@ static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri, /* * If there is an auxiliary IP address (L2 can have it), copy it */ - if (bpi->extra && bpi->extra->vnc.import.aux_prefix.family) { - ri->rk.aux_prefix = bpi->extra->vnc.import.aux_prefix; + if (bpi->extra && bpi->extra->vnc->vnc.import.aux_prefix.family) { + ri->rk.aux_prefix = bpi->extra->vnc->vnc.import.aux_prefix; } } @@ -746,13 +746,13 @@ int rfapiRibPreloadBi( memset((void *)&rk, 0, sizeof(rk)); rk.vn = *pfx_vn; - rk.rd = bpi->extra->vnc.import.rd; + rk.rd = bpi->extra->vnc->vnc.import.rd; /* * If there is an auxiliary IP address (L2 can have it), copy it */ - if (bpi->extra->vnc.import.aux_prefix.family) { - rk.aux_prefix = bpi->extra->vnc.import.aux_prefix; + if (bpi->extra->vnc->vnc.import.aux_prefix.family) { + rk.aux_prefix = bpi->extra->vnc->vnc.import.aux_prefix; } /* @@ -1629,12 +1629,13 @@ void rfapiRibUpdatePendingNode( ri = rfapi_info_new(); ri->rk.vn = pfx_nh; - ri->rk.rd = bpi->extra->vnc.import.rd; + ri->rk.rd = bpi->extra->vnc->vnc.import.rd; /* * If there is an auxiliary IP address (L2 can have it), copy it */ - if (bpi->extra->vnc.import.aux_prefix.family) { - ri->rk.aux_prefix = bpi->extra->vnc.import.aux_prefix; + if (bpi->extra->vnc->vnc.import.aux_prefix.family) { + ri->rk.aux_prefix = + bpi->extra->vnc->vnc.import.aux_prefix; } if (rfapiGetUnAddrOfVpnBi(bpi, &ri->un)) { diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 252b6d6..5da99db 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -419,22 +419,21 @@ void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p, else vty_out(vty, " label=%u", decode_label(&bpi->extra->label[0])); + } - if (bpi->attr->srv6_l3vpn || bpi->attr->srv6_vpn) { - struct in6_addr *sid_tmp = - bpi->attr->srv6_l3vpn - ? (&bpi->attr->srv6_l3vpn->sid) - : (&bpi->attr->srv6_vpn->sid); - vty_out(vty, " sid=%pI6", sid_tmp); - - if (bpi->attr->srv6_l3vpn && - bpi->attr->srv6_l3vpn->loc_block_len != 0) { - vty_out(vty, " sid_structure=[%d,%d,%d,%d]", - bpi->attr->srv6_l3vpn->loc_block_len, - bpi->attr->srv6_l3vpn->loc_node_len, - bpi->attr->srv6_l3vpn->func_len, - bpi->attr->srv6_l3vpn->arg_len); - } + if (bpi->attr->srv6_l3vpn || bpi->attr->srv6_vpn) { + struct in6_addr *sid_tmp = + bpi->attr->srv6_l3vpn ? (&bpi->attr->srv6_l3vpn->sid) + : (&bpi->attr->srv6_vpn->sid); + vty_out(vty, " sid=%pI6", sid_tmp); + + if (bpi->attr->srv6_l3vpn && + bpi->attr->srv6_l3vpn->loc_block_len != 0) { + vty_out(vty, " sid_structure=[%d,%d,%d,%d]", + bpi->attr->srv6_l3vpn->loc_block_len, + bpi->attr->srv6_l3vpn->loc_node_len, + bpi->attr->srv6_l3vpn->func_len, + bpi->attr->srv6_l3vpn->arg_len); } } @@ -519,9 +518,10 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi) if (!bpi) return; - if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && bpi->extra - && bpi->extra->vnc.import.timer) { - struct event *t = (struct event *)bpi->extra->vnc.import.timer; + if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && bpi->extra && + bpi->extra->vnc->vnc.import.timer) { + struct event *t = + (struct event *)bpi->extra->vnc->vnc.import.timer; r = snprintf(p, REMAIN, " [%4lu] ", event_timer_remain_second(t)); @@ -534,12 +534,12 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi) if (bpi->extra) { /* TBD This valid only for SAFI_MPLS_VPN, but not for encap */ - if (decode_rd_type(bpi->extra->vnc.import.rd.val) - == RD_TYPE_VNC_ETH) { + if (decode_rd_type(bpi->extra->vnc->vnc.import.rd.val) == + RD_TYPE_VNC_ETH) { has_macaddr = 1; - memcpy(macaddr.octet, bpi->extra->vnc.import.rd.val + 2, - 6); - l2hid = bpi->extra->vnc.import.rd.val[1]; + memcpy(macaddr.octet, + bpi->extra->vnc->vnc.import.rd.val + 2, 6); + l2hid = bpi->extra->vnc->vnc.import.rd.val[1]; } } @@ -670,11 +670,11 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi) l2o_buf.label, l2o_buf.logical_net_id, l2o_buf.local_nve_id, HVTYNL); } - if (bpi->extra && bpi->extra->vnc.import.aux_prefix.family) { + if (bpi->extra && bpi->extra->vnc->vnc.import.aux_prefix.family) { const char *sp; - sp = rfapi_ntop(bpi->extra->vnc.import.aux_prefix.family, - &bpi->extra->vnc.import.aux_prefix.u.prefix, + sp = rfapi_ntop(bpi->extra->vnc->vnc.import.aux_prefix.family, + &bpi->extra->vnc->vnc.import.aux_prefix.u.prefix, buf, BUFSIZ); buf[BUFSIZ - 1] = 0; if (sp) { @@ -1097,14 +1097,14 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, fp(out, "%-10s ", buf_lifetime); } - if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && bpi->extra - && bpi->extra->vnc.import.timer) { - + if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && bpi->extra && + bpi->extra->vnc->vnc.import.timer) { uint32_t remaining; time_t age; char buf_age[BUFSIZ]; - struct event *t = (struct event *)bpi->extra->vnc.import.timer; + struct event *t = + (struct event *)bpi->extra->vnc->vnc.import.timer; remaining = event_timer_remain_second(t); #ifdef RFAPI_REGISTRATIONS_REPORT_AGE @@ -1125,11 +1125,10 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, fp(out, "%-10s ", buf_age); } else if (RFAPI_LOCAL_BI(bpi)) { - char buf_age[BUFSIZ]; - if (bpi->extra && bpi->extra->vnc.import.create_time) { - rfapiFormatAge(bpi->extra->vnc.import.create_time, + if (bpi->extra && bpi->extra->vnc->vnc.import.create_time) { + rfapiFormatAge(bpi->extra->vnc->vnc.import.create_time, buf_age, BUFSIZ); } else { buf_age[0] = '?'; @@ -1145,13 +1144,14 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream, * print that on the next line */ - if (bpi->extra && bpi->extra->vnc.import.aux_prefix.family) { + if (bpi->extra && bpi->extra->vnc->vnc.import.aux_prefix.family) { const char *sp; - sp = rfapi_ntop( - bpi->extra->vnc.import.aux_prefix.family, - &bpi->extra->vnc.import.aux_prefix.u.prefix, - buf_ntop, BUFSIZ); + sp = rfapi_ntop(bpi->extra->vnc->vnc.import.aux_prefix + .family, + &bpi->extra->vnc->vnc.import.aux_prefix + .u.prefix, + buf_ntop, BUFSIZ); buf_ntop[BUFSIZ - 1] = 0; if (sp && strcmp(buf_vn, sp) != 0) { @@ -1545,10 +1545,9 @@ void rfapiPrintAdvertisedInfo(struct vty *vty, struct rfapi_descriptor *rfd, vty_out(vty, " bd=%p%s", bd, HVTYNL); for (bpi = bgp_dest_get_bgp_path_info(bd); bpi; bpi = bpi->next) { - if (bpi->peer == rfd->peer && bpi->type == type - && bpi->sub_type == BGP_ROUTE_RFP && bpi->extra - && bpi->extra->vnc.export.rfapi_handle == (void *)rfd) { - + if (bpi->peer == rfd->peer && bpi->type == type && + bpi->sub_type == BGP_ROUTE_RFP && bpi->extra && + bpi->extra->vnc->vnc.export.rfapi_handle == (void *)rfd) { rfapiPrintBi(vty, bpi); printed = 1; } @@ -4151,6 +4150,7 @@ static int rfapi_vty_show_nve_summary(struct vty *vty, case SHOW_NVE_SUMMARY_RESPONSES: rfapiRibShowResponsesSummary(vty); + break; case SHOW_NVE_SUMMARY_UNKNOWN_NVES: case SHOW_NVE_SUMMARY_MAX: diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c index 3fcc0e6..c067b7a 100644 --- a/bgpd/rfapi/vnc_import_bgp.c +++ b/bgpd/rfapi/vnc_import_bgp.c @@ -1696,8 +1696,8 @@ static void vnc_import_bgp_exterior_add_route_it( have_usable_route = 1; if (bpi_interior->extra) { - prd = &bpi_interior->extra->vnc.import - .rd; + prd = &bpi_interior->extra->vnc->vnc + .import.rd; label = decode_label( &bpi_interior->extra->label[0]); } else @@ -1865,8 +1865,8 @@ void vnc_import_bgp_exterior_del_route( have_usable_route = 1; if (bpi_interior->extra) { - prd = &bpi_interior->extra->vnc.import - .rd; + prd = &bpi_interior->extra->vnc->vnc + .import.rd; label = decode_label( &bpi_interior->extra->label[0]); } else @@ -2013,7 +2013,7 @@ void vnc_import_bgp_exterior_add_route_interior( assert(pfx_exterior); if (bpi_interior->extra) { - prd = &bpi_interior->extra->vnc.import.rd; + prd = &bpi_interior->extra->vnc->vnc.import.rd; label = decode_label( &bpi_interior->extra->label[0]); } else @@ -2126,8 +2126,8 @@ void vnc_import_bgp_exterior_add_route_interior( for (bpi = par->info; bpi; bpi = bpi->next) { if (bpi->extra) { - prd = &bpi->extra->vnc.import - .rd; + prd = &bpi->extra->vnc->vnc + .import.rd; label = decode_label( &bpi->extra->label[0]); } else @@ -2148,8 +2148,8 @@ void vnc_import_bgp_exterior_add_route_interior( * the new interior route at longer prefix. */ if (bpi_interior->extra) { - prd = &bpi_interior->extra->vnc.import - .rd; + prd = &bpi_interior->extra->vnc->vnc + .import.rd; label = decode_label( &bpi_interior->extra->label[0]); } else @@ -2267,7 +2267,7 @@ void vnc_import_bgp_exterior_add_route_interior( * new interior route at the longer prefix. */ if (bpi_interior->extra) { - prd = &bpi_interior->extra->vnc.import.rd; + prd = &bpi_interior->extra->vnc->vnc.import.rd; label = decode_label( &bpi_interior->extra->label[0]); } else @@ -2375,7 +2375,7 @@ void vnc_import_bgp_exterior_del_route_interior( uint32_t label = 0; if (bpi_interior->extra) { - prd = &bpi_interior->extra->vnc.import.rd; + prd = &bpi_interior->extra->vnc->vnc.import.rd; label = decode_label(&bpi_interior->extra->label[0]); } else prd = NULL; @@ -2452,7 +2452,7 @@ void vnc_import_bgp_exterior_del_route_interior( continue; if (bpi->extra) { - prd = &bpi->extra->vnc.import.rd; + prd = &bpi->extra->vnc->vnc.import.rd; label = decode_label( &bpi->extra->label[0]); } else @@ -2805,14 +2805,14 @@ void vnc_import_bgp_redist_disable(struct bgp *bgp, afi_t afi) assert(bpi->extra); - rfd = bpi->extra->vnc.export.rfapi_handle; + rfd = bpi->extra->vnc->vnc.export.rfapi_handle; vnc_zlog_debug_verbose( - "%s: deleting bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p [passing rfd=%p]", + "%s: deleting bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc->vnc.export.rfapi_handle=%p [passing rfd=%p]", __func__, bpi, bpi->peer, bpi->type, bpi->sub_type, - (bpi->extra ? bpi->extra->vnc.export - .rfapi_handle + (bpi->extra ? bpi->extra->vnc->vnc + .export.rfapi_handle : NULL), rfd); diff --git a/bgpd/rfapi/vnc_zebra.c b/bgpd/rfapi/vnc_zebra.c index c886bee..82c08ca 100644 --- a/bgpd/rfapi/vnc_zebra.c +++ b/bgpd/rfapi/vnc_zebra.c @@ -872,7 +872,7 @@ static zclient_handler *const vnc_handlers[] = { void vnc_zebra_init(struct event_loop *master) { /* Set default values. */ - zclient_vnc = zclient_new(master, &zclient_options_default, + zclient_vnc = zclient_new(master, &zclient_options_auxiliary, vnc_handlers, array_size(vnc_handlers)); zclient_init(zclient_vnc, ZEBRA_ROUTE_VNC, 0, &bgpd_privs); } diff --git a/bgpd/subdir.am b/bgpd/subdir.am index c2dd207..6d6fad0 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -77,6 +77,7 @@ bgpd_libbgp_a_SOURCES = \ bgpd/bgp_zebra.c \ bgpd/bgpd.c \ bgpd/bgp_trace.c \ + bgpd/bgp_nhg.c \ # end if ENABLE_BGP_VNC @@ -160,6 +161,7 @@ noinst_HEADERS += \ bgpd/bgp_zebra.h \ bgpd/bgpd.h \ bgpd/bgp_trace.h \ + bgpd/bgp_nhg.h \ \ bgpd/rfapi/bgp_rfapi_cfg.h \ bgpd/rfapi/rfapi_import.h \ @@ -214,6 +216,7 @@ clippy_scan += \ bgpd/bgp_rpki.c \ bgpd/bgp_vty.c \ bgpd/bgp_nexthop.c \ + bgpd/bgp_snmp.c \ # end nodist_bgpd_bgpd_SOURCES = \ |