Merge pull request #6590 from streambinder/master

bgpd: bmp: add support for L2VPN/EVPN routes
This commit is contained in:
Donald Sharp 2020-07-02 07:56:08 -04:00 committed by GitHub
commit 63aaee3629
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 107 additions and 27 deletions

View File

@ -149,6 +149,16 @@ static int bmp_qhash_cmp(const struct bmp_queue_entry *a,
const struct bmp_queue_entry *b) const struct bmp_queue_entry *b)
{ {
int ret; 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); ret = prefix_cmp(&a->p, &b->p);
if (ret) if (ret)
return 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 = prefix_hash_key((void *)&e->p);
key = jhash(&e->peerid, key = jhash(&e->peerid,
offsetof(struct bmp_queue_entry, refcount) - offsetof(struct bmp_queue_entry, refcount)
offsetof(struct bmp_queue_entry, peerid), - offsetof(struct bmp_queue_entry, peerid),
key); 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; 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); stream_free(s);
} }
static struct stream *bmp_update(const struct prefix *p, struct peer *peer, static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd,
struct attr *attr, afi_t afi, safi_t safi) struct peer *peer, struct attr *attr,
afi_t afi, safi_t safi)
{ {
struct bpacket_attr_vec_arr vecarr; struct bpacket_attr_vec_arr vecarr;
struct stream *s; 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, mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi,
&vecarr, attr); &vecarr, attr);
bgp_packet_mpattr_prefix(s, afi, safi, p, NULL, NULL, 0, bgp_packet_mpattr_prefix(s, afi, safi, p, prd, NULL, 0, 0, 0,
0, 0, attr); attr);
bgp_packet_mpattr_end(s, mpattrlen_pos); bgp_packet_mpattr_end(s, mpattrlen_pos);
total_attr_len += stream_get_endp(s) - p1; 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; 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) safi_t safi)
{ {
struct stream *s; 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); mp_start = stream_get_endp(s);
mplen_pos = bgp_packet_mpunreach_start(s, afi, safi); mplen_pos = bgp_packet_mpunreach_start(s, afi, safi);
bgp_packet_mpunreach_prefix(s, p, afi, safi, NULL, NULL, 0, bgp_packet_mpunreach_prefix(s, p, afi, safi, prd, NULL, 0, 0, 0,
0, 0, NULL); NULL);
/* Set the mp_unreach attr's length */ /* Set the mp_unreach attr's length */
bgp_packet_mpunreach_end(s, mplen_pos); 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, static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags,
const struct prefix *p, struct attr *attr, afi_t afi, const struct prefix *p, struct prefix_rd *prd,
safi_t safi, time_t uptime) struct attr *attr, afi_t afi, safi_t safi,
time_t uptime)
{ {
struct stream *hdr, *msg; struct stream *hdr, *msg;
struct timeval tv = { .tv_sec = uptime, .tv_usec = 0 }; 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); monotime_to_realtime(&tv, &uptime_real);
if (attr) if (attr)
msg = bmp_update(p, peer, attr, afi, safi); msg = bmp_update(p, prd, peer, attr, afi, safi);
else else
msg = bmp_withdraw(p, afi, safi); msg = bmp_withdraw(p, prd, afi, safi);
hdr = stream_new(BGP_MAX_PACKET_SIZE); hdr = stream_new(BGP_MAX_PACKET_SIZE);
bmp_common_hdr(hdr, BMP_VERSION_3, BMP_TYPE_ROUTE_MONITORING); 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; bmp->syncpeerid = 0;
memset(&bmp->syncpos, 0, sizeof(bmp->syncpos)); memset(&bmp->syncpos, 0, sizeof(bmp->syncpos));
bmp->syncpos.family = afi2family(afi); bmp->syncpos.family = afi2family(afi);
bmp->syncrdpos = NULL;
zlog_info("bmp[%s] %s %s sending table", zlog_info("bmp[%s] %s %s sending table",
bmp->remote, bmp->remote,
afi2str(bmp->syncafi), afi2str(bmp->syncafi),
@ -926,11 +947,51 @@ afibreak:
struct bgp_path_info *bpi = NULL, *bpiter; struct bgp_path_info *bpi = NULL, *bpiter;
struct bgp_adj_in *adjin = NULL, *adjiter; 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); bn = bgp_node_lookup(table, &bmp->syncpos);
do { do {
if (!bn) { if (!bn) {
bn = bgp_table_get_next(table, &bmp->syncpos); bn = bgp_table_get_next(table, &bmp->syncpos);
if (!bn) { 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)", zlog_info("bmp[%s] %s %s table completed (EoR)",
bmp->remote, afi2str(afi), bmp->remote, afi2str(afi),
safi2str(safi)); safi2str(safi));
@ -947,7 +1008,8 @@ afibreak:
} }
if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) { 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)) if (!CHECK_FLAG(bpiter->flags, BGP_PATH_VALID))
continue; continue;
if (bpiter->peer->qobj_node.nid if (bpiter->peer->qobj_node.nid
@ -992,13 +1054,16 @@ afibreak:
} }
const struct prefix *bn_p = bgp_dest_get_prefix(bn); 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) if (bpi)
bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, bn_p, bpi->attr, bmp_monitor(bmp, bpi->peer, BMP_PEER_FLAG_L, bn_p, prd,
afi, safi, bpi->uptime); bpi->attr, afi, safi, bpi->uptime);
if (adjin) if (adjin)
bmp_monitor(bmp, adjin->peer, 0, bn_p, adjin->attr, afi, safi, bmp_monitor(bmp, adjin->peer, 0, bn_p, prd, adjin->attr, afi,
adjin->uptime); safi, adjin->uptime);
return true; return true;
} }
@ -1061,18 +1126,22 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
goto out; goto out;
bn = bgp_node_lookup(bmp->targets->bgp->rib[afi][safi], &bqe->p); 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) { if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) {
struct bgp_path_info *bpi; 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)) if (!CHECK_FLAG(bpi->flags, BGP_PATH_VALID))
continue; continue;
if (bpi->peer == peer) if (bpi->peer == peer)
break; 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->attr : NULL, afi, safi,
bpi ? bpi->uptime : monotime(NULL)); bpi ? bpi->uptime : monotime(NULL));
written = true; written = true;
@ -1086,7 +1155,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
if (adjin->peer == peer) if (adjin->peer == peer)
break; 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->attr : NULL, afi, safi,
adjin ? adjin->uptime : monotime(NULL)); adjin ? adjin->uptime : monotime(NULL));
written = true; 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.afi = afi;
bqeref.safi = safi; 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); bqe = bmp_qhash_find(&bt->updhash, &bqeref);
if (bqe) { if (bqe) {
if (bqe->refcount >= refcount) if (bqe->refcount >= refcount)
@ -1960,13 +2033,12 @@ DEFPY(bmp_stats_cfg,
DEFPY(bmp_monitor_cfg, DEFPY(bmp_monitor_cfg,
bmp_monitor_cmd, bmp_monitor_cmd,
"[no] bmp monitor "BGP_AFI_CMD_STR" <unicast|multicast> <pre-policy|post-policy>$policy", "[no] bmp monitor <ipv4|ipv6|l2vpn> <unicast|multicast|evpn> <pre-policy|post-policy>$policy",
NO_STR NO_STR
BMP_STR BMP_STR
"Send BMP route monitoring messages\n" "Send BMP route monitoring messages\n"
BGP_AFI_HELP_STR "Address Family\nAddress Family\nAddress Family\n"
"Address family modifier\n" "Address Family\nAddress Family\nAddress Family\n"
"Address family modifier\n"
"Send state before policy and filter processing\n" "Send state before policy and filter processing\n"
"Send state with policy and filters applied\n") "Send state with policy and filters applied\n")
{ {

View File

@ -79,6 +79,9 @@ struct bmp_queue_entry {
safi_t safi; safi_t safi;
size_t refcount; 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 /* 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 * table entry, the sync* fields note down what we sent last
*/ */
struct prefix syncpos; struct prefix syncpos;
struct bgp_node *syncrdpos;
uint64_t syncpeerid; uint64_t syncpeerid;
afi_t syncafi; afi_t syncafi;
safi_t syncsafi; safi_t syncsafi;
@ -221,7 +225,11 @@ struct bmp_targets {
#define BMP_STAT_DEFAULT_TIMER 60000 #define BMP_STAT_DEFAULT_TIMER 60000
int stat_msec; 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_PREPOLICY (1 << 0)
#define BMP_MON_POSTPOLICY (1 << 1) #define BMP_MON_POSTPOLICY (1 << 1)
uint8_t afimon[AFI_MAX][SAFI_MAX]; uint8_t afimon[AFI_MAX][SAFI_MAX];