]> git.puffer.fish Git - mirror/frr.git/commitdiff
bgpd: bmp: add support for L2VPN/EVPN routes 6590/head
authorstreambinder <posta@davidepucci.it>
Tue, 30 Jun 2020 12:37:00 +0000 (14:37 +0200)
committerstreambinder <posta@davidepucci.it>
Tue, 30 Jun 2020 12:37:00 +0000 (14:37 +0200)
Co-authored-by: giacomo270197 <gcasoni@hotmail.it>
Signed-off-by: streambinder <posta@davidepucci.it>
bgpd/bgp_bmp.c
bgpd/bgp_bmp.h

index c3fc230512d96db2feaaa17107410315c1d44a61..f1ad6a1e756414e300202c45ff118f0edbafd622 100644 (file)
@@ -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" <unicast|multicast> <pre-policy|post-policy>$policy",
+      "[no] bmp monitor <ipv4|ipv6|l2vpn> <unicast|multicast|evpn> <pre-policy|post-policy>$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")
 {
index 94a17f70da2071a1ede105b793a7910246d6d863..9032da55bf26d0c4efc9308769659a1bf70c4ca2 100644 (file)
@@ -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];