]> git.puffer.fish Git - mirror/frr.git/commitdiff
bgpd: basic loc rib monitoring (no syncing yet, not rfc compliant encoding)
authorMaxence Younsi <mx.yns@outlook.fr>
Fri, 22 Jul 2022 10:12:35 +0000 (12:12 +0200)
committerMaxence Younsi <mx.yns@outlook.fr>
Sat, 4 Nov 2023 11:17:47 +0000 (12:17 +0100)
bmp loc rib monitoring rfc 9069 debuts, loc-rib monitoring draft/poc

Signed-off-by: Maxence Younsi <mx.yns@outlook.fr>
bgpd/bgp_bmp.c
bgpd/bgp_bmp.h
bgpd/bgp_route.c
bgpd/bgp_route.h

index 7270802915e6a46bffc1e17bca0583045098ec20..d1edba30f18747464ec04dbfd6a2222c3d8be1c5 100644 (file)
@@ -1051,6 +1051,7 @@ afibreak:
                        prefix_copy(&bmp->syncpos, bgp_dest_get_prefix(bn));
                }
 
+               // TODO BMP add BMP_MON_LOC_RIB case
                if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) {
                        for (bpiter = bgp_dest_get_bgp_path_info(bn); bpiter;
                             bpiter = bpiter->next) {
@@ -1116,24 +1117,123 @@ 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)
+{
+
+       zlog_info("bmp: wrqueue_locrib!");
+       struct bmp_queue_entry *bqe;
+       struct peer *peer;
+       struct bgp_dest *bn;
+       bool written = false;
+
+       bqe = bmp_pull_locrib(bmp);
+       if (!bqe)
+               return false;
+
+       zlog_info("bmp: got update from queue");
+
+       afi_t afi = bqe->afi;
+       safi_t safi = bqe->safi;
+
+       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;
+
+               // TODO BMP_MON_LOCRIB check if this is true after implenting
+               // LOCRIB syncing
+               /* currently syncing & haven't reached this prefix yet
+                * => it'll be sent as part of the table sync, no need here */
+               zlog_info(
+                       "bmp: skipping direct monitor msg bc will be sent with sync :)");
+               goto out;
+       case BMP_AFI_LIVE:
+               break;
+       }
+
+       zlog_info("passed afi state check");
+
+       peer = QOBJ_GET_TYPESAFE(bqe->peerid, peer);
+       if (!peer) {
+               zlog_info("bmp: skipping queued item for deleted peer");
+               goto out;
+       }
+       if (!peer_established(peer)) {
+               zlog_info("bmp: not established peer");
+               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) ||
+           (bqe->safi == SAFI_MPLS_VPN))
+               prd = &bqe->rd;
+
+       if (bmp->targets->afimon[afi][safi] & BMP_MON_LOC_RIB) {
+               zlog_info("bmp: loc rib monitoring on");
+               struct bgp_path_info *bpi;
+
+               // TODO BMP_MON_LOC_RIB understand this part more, why iterate
+               // through the table ?
+               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, 5, &bqe->p, prd, bpi ? bpi->attr : NULL,
+                           afi, safi, bpi ? bpi->uptime : monotime(NULL));
+               written = true;
+       }
+
+out:
+       if (!bqe->refcount)
+               XFREE(MTYPE_BMP_QUEUE, bqe);
+       return written;
+}
+
 static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
 {
        struct bmp_queue_entry *bqe;
@@ -1181,6 +1281,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
                                  &bqe->p, prd);
 
 
+       // TODO BMP add MON_BGP_LOC_RIB case
        if (bmp->targets->afimon[afi][safi] & BMP_MON_POSTPOLICY) {
                struct bgp_path_info *bpi;
 
@@ -1235,6 +1336,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;
@@ -1633,6 +1736,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 +1768,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 +2313,15 @@ 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
+DEFPY(bmp_monitor_cfg, bmp_monitor_cmd,
+      // TODO BMP add loc-rib option
+      "[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 +2334,12 @@ 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')
+       // TODO BMP set right flag
+       if (policy[0] == 'l') {
+               flag = BMP_MON_LOC_RIB;
+               vty_out(vty,
+                       "changing loc rib monitoring config for this target\n");
+       } else if (policy[1] == 'r')
                flag = BMP_MON_PREPOLICY;
        else
                flag = BMP_MON_POSTPOLICY;
@@ -2364,23 +2470,29 @@ 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 =
+                                       afimon_flag & BMP_MON_PREPOLICY
+                                               ? "pre-policy "
+                                               : "";
+                               const char *post_str =
+                                       afimon_flag & BMP_MON_POSTPOLICY
+                                               ? "post-policy "
+                                               : "";
+                               const char *locrib_str =
+                                       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");
@@ -2507,6 +2619,9 @@ static int bmp_config_write(struct bgp *bgp, struct vty *vty)
                                vty_out(vty,
                                        "  bmp monitor %s %s post-policy\n",
                                        afi2str_lower(afi), safi2str(safi));
+                       if (bt->afimon[afi][safi] & BMP_MON_LOC_RIB)
+                               vty_out(vty, "  bmp monitor %s %s loc-rib\n",
+                                       afi2str(afi), safi2str(safi));
                }
                frr_each (bmp_listeners, &bt->listeners, bl)
                        vty_out(vty, " \n  bmp listener %pSU port %d\n",
@@ -2555,6 +2670,122 @@ static int bgp_bmp_init(struct event_loop *tm)
        return 0;
 }
 
+
+// TODO remove "bn", redundant with updated_route->net ?
+static int bmp_route_update(struct bgp *bgp, afi_t afi, safi_t safi,
+                           struct bgp_dest *bn,
+                           struct bgp_path_info *updated_route, bool withdraw)
+{
+
+       zlog_info(
+               "bmp: got route update (%s) ! vrf_id=%d, afi/safi=%s, dest=%pRN, bpi=%pRN",
+               withdraw ? "withdraw" : "update", bgp->vrf_id,
+               get_afi_safi_str(afi, safi, false), bn, updated_route->net);
+
+       struct bmp_bgp *bmpbgp = bmp_bgp_get(bgp);
+       struct peer *peer = updated_route->peer;
+       const struct prefix *prefix = bgp_dest_get_prefix(updated_route->net);
+
+       zlog_info("bmp: peer %pBP", peer);
+
+       struct bmp_targets *bt;
+       struct bmp *bmp;
+
+       afi_t afi_iter;
+       safi_t safi_iter;
+
+       frr_each (bmp_targets, &bmpbgp->targets, bt) {
+               zlog_info("bmp: targets name=%s", bt->name);
+
+               FOREACH_AFI_SAFI (afi_iter, safi_iter) {
+                       if (bt->afimon[afi_iter][safi_iter])
+                               zlog_info("bmp: afi/safi=%s, flag=%d",
+                                         get_afi_safi_str(afi_iter, safi_iter,
+                                                          false),
+                                         bt->afimon[afi_iter][safi_iter]);
+               };
+
+
+               uint8_t flags = 5;
+               zlog_info("bmp wanna monitor : peer=%pBP", updated_route->peer);
+               zlog_info("flags=%d", flags);
+               zlog_info("prefix=%pFX", prefix);
+               zlog_info("attr=%p", updated_route->attr);
+               zlog_info("afi=%d safi=%d", afi, safi);
+               zlog_info("uptime=%ld", updated_route->uptime);
+
+               if (bt->afimon[afi][safi] & BMP_MON_LOC_RIB) {
+                       zlog_info("has LOC RIB monitoring on!");
+
+                       struct bmp_queue_entry *bqe, bqeref;
+                       size_t refcount;
+
+                       refcount = bmp_session_count(&bt->sessions);
+                       if (refcount == 0)
+                               return 0;
+
+                       memset(&bqeref, 0, sizeof(bqeref));
+                       prefix_copy(&bqeref.p, prefix);
+                       bqeref.peerid = peer->qobj_node.nid;
+                       bqeref.afi = afi;
+                       bqeref.safi = safi;
+
+                       zlog_info("before afi/safi check");
+                       if ((afi == AFI_L2VPN && safi == SAFI_EVPN &&
+                            bn->pdest) ||
+                           (safi == SAFI_MPLS_VPN))
+                               prefix_copy(
+                                       &bqeref.rd,
+                                       (struct prefix_rd *)bgp_dest_get_prefix(
+                                               bn->pdest));
+
+                       zlog_info("bmp: before hash check");
+                       bqe = bmp_qhash_find(&bt->locupdhash, &bqeref);
+                       uint32_t key = bmp_qhash_hkey(&bqeref);
+                       zlog_info("bmp: key = %lu", key);
+                       if (bqe) {
+                               zlog_info("bmp: prefix already registered");
+                               if (bqe->refcount >= refcount)
+                                       /* nothing to do here */
+                                       return 0;
+
+                               zlog_info("bmp: removing prefix");
+                               bmp_qlist_del(&bt->locupdlist, bqe);
+                               zlog_info("bmp: removed prefix");
+                       } else {
+                               zlog_info(
+                                       "bmp: prefix not registered in queue yet");
+                               bqe = XMALLOC(MTYPE_BMP_QUEUE, sizeof(*bqe));
+                               zlog_info("bmp: got malloc %p", bqe);
+                               memcpy(bqe, &bqeref, sizeof(*bqe));
+                               zlog_info("bmp: copied bqeref into bqe");
+
+                               bmp_qhash_add(&bt->locupdhash, bqe);
+                               zlog_info("bmp: added hash");
+                       }
+
+                       zlog_info("bmp: before list add tail");
+                       bqe->refcount = refcount;
+                       bmp_qlist_add_tail(&bt->locupdlist, bqe);
+
+                       zlog_info("bmp: before queuepos update");
+                       frr_each (bmp_session, &bt->sessions, bmp) {
+                               zlog_info("bmp: session host=%s", bmp->remote);
+
+                               if (!bmp->locrib_queuepos)
+                                       bmp->locrib_queuepos = bqe;
+
+                               pullwr_bump(bmp->pullwr);
+                       };
+
+                       zlog_info("bmp: end");
+               }
+       };
+
+       return 0;
+}
+
+
 static int bgp_bmp_module_init(void)
 {
        hook_register(bgp_packet_dump, bmp_mirror_packet);
@@ -2565,6 +2796,7 @@ 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);
        return 0;
 }
 
index ab7463fadcad9c2338198e2d82dc13e76341112e..be952b591a96ac4f648b4afe531901b6465abf2a 100644 (file)
@@ -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;
@@ -221,6 +222,9 @@ struct bmp_targets {
         */
 #define BMP_MON_PREPOLICY      (1 << 0)
 #define BMP_MON_POSTPOLICY     (1 << 1)
+
+// TODO define BMP_MON_LOC_RIB flag
+#define BMP_MON_LOC_RIB (1 << 2)
        uint8_t afimon[AFI_MAX][SAFI_MAX];
        bool mirror;
 
@@ -232,6 +236,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;
index b627487e7c2063b4b2dbcecfc95ceebafb3414e0..b206f96f41e34cac1d99673fc2e09b752c08cfea 100644 (file)
@@ -85,6 +85,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 *updated_route, bool withdraw),
+           (bgp, afi, safi, bn, updated_route, withdraw));
+
 /* Extern from bgp_dump.c */
 extern const char *bgp_origin_str[];
 extern const char *bgp_origin_long_str[];
@@ -3435,6 +3440,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) {
@@ -3447,6 +3453,16 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest,
                UNSET_FLAG(new_select->flags, BGP_PATH_LINK_BW_CHG);
        }
 
+       if (old_select || new_select) {
+               zlog_info("old_select==NULL %s | new_select==NULL %s",
+                         old_select == NULL ? "YES" : "NO",
+                         new_select == NULL ? "YES" : "NO");
+               bool is_withdraw = old_select && !new_select;
+               hook_call(bgp_route_update, bgp, afi, safi, dest,
+                         is_withdraw ? old_select : new_select, is_withdraw);
+       }
+
+
 #ifdef ENABLE_BGP_VNC
        if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
                if (old_select != new_select) {
index e9f48ea647787c0a998d0130829e885800b7ea43..b340327d3be85414fade8e4cdb580a918f1d4605 100644 (file)
@@ -674,6 +674,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 *updated_route, bool withdraw),
+            (bgp, afi, safi, bn, updated_route, withdraw));
+
 /* BGP show options */
 #define BGP_SHOW_OPT_JSON (1 << 0)
 #define BGP_SHOW_OPT_WIDE (1 << 1)