From 87102aa00518ffed524eff6691cc66dd9152a67f Mon Sep 17 00:00:00 2001 From: streambinder Date: Tue, 30 Jun 2020 14:37:00 +0200 Subject: [PATCH] bgpd: bmp: add support for L2VPN/EVPN routes Co-authored-by: giacomo270197 Signed-off-by: streambinder --- bgpd/bgp_bmp.c | 124 ++++++++++++++++++++++++++++++++++++++----------- bgpd/bgp_bmp.h | 10 +++- 2 files changed, 107 insertions(+), 27 deletions(-) diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index c3fc230512..f1ad6a1e75 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -149,6 +149,16 @@ static int bmp_qhash_cmp(const struct bmp_queue_entry *a, const struct bmp_queue_entry *b) { int ret; + if (a->afi == AFI_L2VPN && a->safi == SAFI_EVPN && b->afi == AFI_L2VPN + && b->safi == SAFI_EVPN) { + ret = prefix_cmp(&a->rd, &b->rd); + if (ret) + return ret; + } else if (a->afi == AFI_L2VPN && a->safi == SAFI_EVPN) + return 1; + else if (b->afi == AFI_L2VPN && b->safi == SAFI_EVPN) + return -1; + ret = prefix_cmp(&a->p, &b->p); if (ret) return ret; @@ -164,9 +174,16 @@ static uint32_t bmp_qhash_hkey(const struct bmp_queue_entry *e) key = prefix_hash_key((void *)&e->p); key = jhash(&e->peerid, - offsetof(struct bmp_queue_entry, refcount) - - offsetof(struct bmp_queue_entry, peerid), - key); + offsetof(struct bmp_queue_entry, refcount) + - offsetof(struct bmp_queue_entry, peerid), + key); + if (e->afi == AFI_L2VPN && e->safi == SAFI_EVPN) + key = jhash(&e->rd, + offsetof(struct bmp_queue_entry, rd) + - offsetof(struct bmp_queue_entry, refcount) + + PSIZE(e->rd.prefixlen), + key); + return key; } @@ -765,8 +782,9 @@ static void bmp_eor(struct bmp *bmp, afi_t afi, safi_t safi, uint8_t flags) stream_free(s); } -static struct stream *bmp_update(const struct prefix *p, struct peer *peer, - struct attr *attr, afi_t afi, safi_t safi) +static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd, + struct peer *peer, struct attr *attr, + afi_t afi, safi_t safi) { struct bpacket_attr_vec_arr vecarr; struct stream *s; @@ -801,8 +819,8 @@ static struct stream *bmp_update(const struct prefix *p, struct peer *peer, mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi, &vecarr, attr); - bgp_packet_mpattr_prefix(s, afi, safi, p, NULL, NULL, 0, - 0, 0, attr); + bgp_packet_mpattr_prefix(s, afi, safi, p, prd, NULL, 0, 0, 0, + attr); bgp_packet_mpattr_end(s, mpattrlen_pos); total_attr_len += stream_get_endp(s) - p1; } @@ -813,7 +831,8 @@ static struct stream *bmp_update(const struct prefix *p, struct peer *peer, return s; } -static struct stream *bmp_withdraw(const struct prefix *p, afi_t afi, +static struct stream *bmp_withdraw(const struct prefix *p, + struct prefix_rd *prd, afi_t afi, safi_t safi) { struct stream *s; @@ -839,8 +858,8 @@ static struct stream *bmp_withdraw(const struct prefix *p, afi_t afi, mp_start = stream_get_endp(s); mplen_pos = bgp_packet_mpunreach_start(s, afi, safi); - bgp_packet_mpunreach_prefix(s, p, afi, safi, NULL, NULL, 0, - 0, 0, NULL); + bgp_packet_mpunreach_prefix(s, p, afi, safi, prd, NULL, 0, 0, 0, + NULL); /* Set the mp_unreach attr's length */ bgp_packet_mpunreach_end(s, mplen_pos); @@ -854,8 +873,9 @@ static struct stream *bmp_withdraw(const struct prefix *p, afi_t afi, } static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags, - const struct prefix *p, struct attr *attr, afi_t afi, - safi_t safi, time_t uptime) + 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 }; @@ -863,9 +883,9 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags, monotime_to_realtime(&tv, &uptime_real); if (attr) - msg = bmp_update(p, peer, attr, afi, safi); + msg = bmp_update(p, prd, peer, attr, afi, safi); else - msg = bmp_withdraw(p, afi, safi); + msg = bmp_withdraw(p, prd, afi, safi); hdr = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(hdr, BMP_VERSION_3, BMP_TYPE_ROUTE_MONITORING); @@ -898,6 +918,7 @@ static bool bmp_wrsync(struct bmp *bmp, struct pullwr *pullwr) bmp->syncpeerid = 0; memset(&bmp->syncpos, 0, sizeof(bmp->syncpos)); bmp->syncpos.family = afi2family(afi); + bmp->syncrdpos = NULL; zlog_info("bmp[%s] %s %s sending table", bmp->remote, afi2str(bmp->syncafi), @@ -926,11 +947,51 @@ afibreak: struct bgp_path_info *bpi = NULL, *bpiter; struct bgp_adj_in *adjin = NULL, *adjiter; + if (afi == AFI_L2VPN && safi == SAFI_EVPN) { + /* initialize syncrdpos to the first + * mid-layer table entry + */ + if (!bmp->syncrdpos) + bmp->syncrdpos = bgp_table_top(table); + + /* look for a valid mid-layer table */ + do { + table = bgp_dest_get_bgp_table_info(bmp->syncrdpos); + if (table) { + break; + } + bmp->syncrdpos = bgp_route_next(bmp->syncrdpos); + } while (bmp->syncrdpos); + + /* mid-layer table completed */ + if (!bmp->syncrdpos) + goto eor; + } + bn = bgp_node_lookup(table, &bmp->syncpos); do { if (!bn) { bn = bgp_table_get_next(table, &bmp->syncpos); if (!bn) { + if (afi == AFI_L2VPN && safi == SAFI_EVPN) { + /* reset bottom-layer pointer */ + memset(&bmp->syncpos, 0, + sizeof(bmp->syncpos)); + bmp->syncpos.family = afi2family(afi); + /* check whethere there is a valid + * next mid-layer table, otherwise + * declare table completed (eor) + */ + for (bmp->syncrdpos = bgp_route_next( + bmp->syncrdpos); + bmp->syncrdpos; + bmp->syncrdpos = bgp_route_next( + bmp->syncrdpos)) + if (bgp_dest_get_bgp_table_info( + bmp->syncrdpos)) + return true; + } + eor: zlog_info("bmp[%s] %s %s table completed (EoR)", bmp->remote, afi2str(afi), safi2str(safi)); @@ -947,7 +1008,8 @@ afibreak: } if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) { - for (bpiter = bn->info; bpiter; bpiter = bpiter->next) { + for (bpiter = bgp_dest_get_bgp_path_info(bn); bpiter; + bpiter = bpiter->next) { if (!CHECK_FLAG(bpiter->flags, BGP_PATH_VALID)) continue; if (bpiter->peer->qobj_node.nid @@ -992,13 +1054,16 @@ afibreak: } const struct prefix *bn_p = bgp_dest_get_prefix(bn); + struct prefix_rd *prd = NULL; + if (afi == AFI_L2VPN && safi == SAFI_EVPN) + prd = (struct prefix_rd *)bgp_dest_get_prefix(bmp->syncrdpos); if (bpi) - bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, bn_p, bpi->attr, - afi, safi, bpi->uptime); + bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, bn_p, prd, + bpi->attr, afi, safi, bpi->uptime); if (adjin) - bmp_monitor(bmp, adjin->peer, 0, bn_p, adjin->attr, afi, safi, - adjin->uptime); + bmp_monitor(bmp, adjin->peer, 0, bn_p, prd, adjin->attr, afi, + safi, adjin->uptime); return true; } @@ -1061,18 +1126,22 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) goto out; bn = bgp_node_lookup(bmp->targets->bgp->rib[afi][safi], &bqe->p); + struct prefix_rd *prd = NULL; + if (bqe->afi == AFI_L2VPN && bqe->safi == SAFI_EVPN) + prd = &bqe->rd; if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) { struct bgp_path_info *bpi; - for (bpi = bn ? bn->info : NULL; bpi; bpi = bpi->next) { + for (bpi = bn ? bgp_dest_get_bgp_path_info(bn) : NULL; bpi; + bpi = bpi->next) { if (!CHECK_FLAG(bpi->flags, BGP_PATH_VALID)) continue; if (bpi->peer == peer) break; } - bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, &bqe->p, + bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, &bqe->p, prd, bpi ? bpi->attr : NULL, afi, safi, bpi ? bpi->uptime : monotime(NULL)); written = true; @@ -1086,7 +1155,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr) if (adjin->peer == peer) break; } - bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, &bqe->p, + bmp_monitor(bmp, peer, BMP_PEER_FLAG_L, &bqe->p, prd, adjin ? adjin->attr : NULL, afi, safi, adjin ? adjin->uptime : monotime(NULL)); written = true; @@ -1146,6 +1215,10 @@ static void bmp_process_one(struct bmp_targets *bt, struct bgp *bgp, afi_t afi, bqeref.afi = afi; bqeref.safi = safi; + if (afi == AFI_L2VPN && safi == SAFI_EVPN && bn->pdest) + prefix_copy(&bqeref.rd, + (struct prefix_rd *)bgp_dest_get_prefix(bn->pdest)); + bqe = bmp_qhash_find(&bt->updhash, &bqeref); if (bqe) { if (bqe->refcount >= refcount) @@ -1960,13 +2033,12 @@ DEFPY(bmp_stats_cfg, DEFPY(bmp_monitor_cfg, bmp_monitor_cmd, - "[no] bmp monitor "BGP_AFI_CMD_STR" $policy", + "[no] bmp monitor $policy", NO_STR BMP_STR "Send BMP route monitoring messages\n" - BGP_AFI_HELP_STR - "Address family modifier\n" - "Address family modifier\n" + "Address Family\nAddress Family\nAddress Family\n" + "Address Family\nAddress Family\nAddress Family\n" "Send state before policy and filter processing\n" "Send state with policy and filters applied\n") { diff --git a/bgpd/bgp_bmp.h b/bgpd/bgp_bmp.h index 94a17f70da..9032da55bf 100644 --- a/bgpd/bgp_bmp.h +++ b/bgpd/bgp_bmp.h @@ -79,6 +79,9 @@ struct bmp_queue_entry { safi_t safi; size_t refcount; + + /* initialized only for L2VPN/EVPN (S)AFIs */ + struct prefix_rd rd; }; /* This is for BMP Route Mirroring, which feeds fully raw BGP PDUs out to BMP @@ -153,6 +156,7 @@ struct bmp { * table entry, the sync* fields note down what we sent last */ struct prefix syncpos; + struct bgp_node *syncrdpos; uint64_t syncpeerid; afi_t syncafi; safi_t syncsafi; @@ -221,7 +225,11 @@ struct bmp_targets { #define BMP_STAT_DEFAULT_TIMER 60000 int stat_msec; - /* only IPv4 & IPv6 / unicast & multicast supported for now */ + /* only supporting: + * - IPv4 / unicast & multicast + * - IPv6 / unicast & multicast + * - L2VPN / EVPN + */ #define BMP_MON_PREPOLICY (1 << 0) #define BMP_MON_POSTPOLICY (1 << 1) uint8_t afimon[AFI_MAX][SAFI_MAX]; -- 2.39.5