]> git.puffer.fish Git - mirror/frr.git/commitdiff
nhrpd: Implement retrying resolution request 16788/head
authorJoshua Muthii <jmuthii@labn.net>
Sun, 1 Sep 2024 13:28:16 +0000 (09:28 -0400)
committerJoshua Muthii <jmuthii@labn.net>
Tue, 17 Sep 2024 16:44:41 +0000 (12:44 -0400)
In the event that a resolution request is sent and
and resolution reply is never received, resolution
requests will continue to be sent until either the
newly created shortcut has been purged or a resolution
reply is finally received.

NHRPD_DEFAULT_PURGE_TIME and NHRPD_PURGE_EXPIRE are values
that were previously hardcoded and  moved into macros for
the sake of readability.

Signed-off-by: Joshua Muthii <jmuthii@labn.net>
nhrpd/nhrp_shortcut.c
nhrpd/nhrpd.h

index 9b47d974c3403b61c420b14b7a0c7bc6f509a8e2..55d61a90b8dddfa6f416734619487f7603adbba5 100644 (file)
@@ -21,14 +21,16 @@ static struct route_table *shortcut_rib[AFI_MAX];
 static void nhrp_shortcut_do_purge(struct event *t);
 static void nhrp_shortcut_delete(struct nhrp_shortcut *s,
                                 void *arg __attribute__((__unused__)));
-static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s);
+static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s,
+                                             bool retry);
+static void nhrp_shortcut_retry_resolution_req(struct event *t);
 
 static void nhrp_shortcut_check_use(struct nhrp_shortcut *s)
 {
        if (s->expiring && s->cache && s->cache->used) {
                debugf(NHRP_DEBUG_ROUTE, "Shortcut %pFX used and expiring",
                       s->p);
-               nhrp_shortcut_send_resolution_req(s);
+               nhrp_shortcut_send_resolution_req(s, false);
        }
 }
 
@@ -37,7 +39,7 @@ static void nhrp_shortcut_do_expire(struct event *t)
        struct nhrp_shortcut *s = EVENT_ARG(t);
 
        event_add_timer(master, nhrp_shortcut_do_purge, s, s->holding_time / 3,
-                       &s->t_timer);
+                       &s->t_shortcut_purge);
        s->expiring = 1;
        nhrp_shortcut_check_use(s);
 }
@@ -124,12 +126,12 @@ static void nhrp_shortcut_update_binding(struct nhrp_shortcut *s,
                s->route_installed = 0;
        }
 
-       EVENT_OFF(s->t_timer);
+       EVENT_OFF(s->t_shortcut_purge);
        if (holding_time) {
                s->expiring = 0;
                s->holding_time = holding_time;
                event_add_timer(master, nhrp_shortcut_do_expire, s,
-                               2 * holding_time / 3, &s->t_timer);
+                               2 * holding_time / 3, &s->t_shortcut_purge);
        }
 }
 
@@ -139,7 +141,8 @@ static void nhrp_shortcut_delete(struct nhrp_shortcut *s,
        struct route_node *rn;
        afi_t afi = family2afi(PREFIX_FAMILY(s->p));
 
-       EVENT_OFF(s->t_timer);
+       EVENT_OFF(s->t_shortcut_purge);
+       EVENT_OFF(s->t_retry_resolution);
        nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid);
 
        debugf(NHRP_DEBUG_ROUTE, "Shortcut %pFX purged", s->p);
@@ -159,7 +162,8 @@ static void nhrp_shortcut_delete(struct nhrp_shortcut *s,
 static void nhrp_shortcut_do_purge(struct event *t)
 {
        struct nhrp_shortcut *s = EVENT_ARG(t);
-       s->t_timer = NULL;
+       s->t_shortcut_purge = NULL;
+       EVENT_OFF(s->t_retry_resolution);
        nhrp_shortcut_delete(s, NULL);
 }
 
@@ -206,8 +210,10 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid,
        int holding_time = pp->if_ad->holdtime;
 
        nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid);
-       EVENT_OFF(s->t_timer);
-       event_add_timer(master, nhrp_shortcut_do_purge, s, 1, &s->t_timer);
+       EVENT_OFF(s->t_shortcut_purge);
+       EVENT_OFF(s->t_retry_resolution);
+       event_add_timer(master, nhrp_shortcut_do_purge, s, 1,
+                       &s->t_shortcut_purge);
 
        if (pp->hdr->type != NHRP_PACKET_RESOLUTION_REPLY) {
                if (pp->hdr->type == NHRP_PACKET_ERROR_INDICATION
@@ -374,7 +380,8 @@ static void nhrp_shortcut_recv_resolution_rep(struct nhrp_reqid *reqid,
        debugf(NHRP_DEBUG_COMMON, "Shortcut: Resolution reply handled");
 }
 
-static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s)
+static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s,
+                                             bool retry)
 {
        struct zbuf *zb;
        struct nhrp_packet_header *hdr;
@@ -389,6 +396,22 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s)
            != NHRP_ROUTE_NBMA_NEXTHOP)
                return;
 
+       /*Retry interval for NHRP resolution request
+        * will start at 1 second and will be doubled every time
+        * another resolution request is sent, until it is
+        * eventually upper-bounded by the purge time of
+        * the shortcut.
+        */
+       if (!retry)
+               s->retry_interval = 1;
+       event_add_timer(master, nhrp_shortcut_retry_resolution_req, s,
+                       s->retry_interval, &s->t_retry_resolution);
+       if (s->retry_interval != (NHRPD_DEFAULT_PURGE_TIME / 4))
+               s->retry_interval = ((s->retry_interval * 2) <
+                                    (NHRPD_DEFAULT_PURGE_TIME / 4))
+                                           ? (s->retry_interval * 2)
+                                           : (NHRPD_DEFAULT_PURGE_TIME / 4);
+
        if (s->type == NHRP_CACHE_INVALID || s->type == NHRP_CACHE_NEGATIVE)
                s->type = NHRP_CACHE_INCOMPLETE;
 
@@ -401,9 +424,23 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s)
                zb, NHRP_PACKET_RESOLUTION_REQUEST, &nifp->nbma,
                &nifp->afi[family2afi(sockunion_family(&s->addr))].addr,
                &s->addr);
-       hdr->u.request_id =
-               htonl(nhrp_reqid_alloc(&nhrp_packet_reqid, &s->reqid,
-                                      nhrp_shortcut_recv_resolution_rep));
+
+       /* RFC2332 - The value is taken from a 32 bit counter that is incremented
+        * each time a new "request" is transmitted.  The same value MUST
+        * be used when resending a "request", i.e., when a "reply" has not been
+        * received for a "request" and a retry is sent after an
+        * appropriate interval
+        */
+       if (!retry)
+               hdr->u.request_id = htonl(
+                       nhrp_reqid_alloc(&nhrp_packet_reqid, &s->reqid,
+                                        nhrp_shortcut_recv_resolution_rep));
+       else
+               /* Just pull request_id from existing incomplete
+                * shortcut in the case of a retry
+                */
+               hdr->u.request_id = htonl(s->reqid.request_id);
+
        hdr->flags = htons(NHRP_FLAG_RESOLUTION_SOURCE_IS_ROUTER
                           | NHRP_FLAG_RESOLUTION_AUTHORATIVE
                           | NHRP_FLAG_RESOLUTION_SOURCE_STABLE);
@@ -412,7 +449,7 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s)
         *  - Prefix length: widest acceptable prefix we accept (if U set, 0xff)
         *  - MTU: MTU of the source station
         *  - Holding Time: Max time to cache the source information
-        * */
+        */
        /* FIXME: push CIE for each local protocol address */
        cie = nhrp_cie_push(zb, NHRP_CODE_SUCCESS, NULL, NULL);
        if_ad = &nifp->afi[family2afi(sockunion_family(&s->addr))];
@@ -456,13 +493,25 @@ void nhrp_shortcut_initiate(union sockunion *addr)
        s = nhrp_shortcut_get(&p);
        if (s && s->type != NHRP_CACHE_INCOMPLETE) {
                s->addr = *addr;
-               EVENT_OFF(s->t_timer);
-               event_add_timer(master, nhrp_shortcut_do_purge, s, 30,
-                               &s->t_timer);
-               nhrp_shortcut_send_resolution_req(s);
+               EVENT_OFF(s->t_shortcut_purge);
+               EVENT_OFF(s->t_retry_resolution);
+
+               event_add_timer(master, nhrp_shortcut_do_purge, s,
+                               NHRPD_DEFAULT_PURGE_TIME, &s->t_shortcut_purge);
+               nhrp_shortcut_send_resolution_req(s, false);
        }
 }
 
+static void nhrp_shortcut_retry_resolution_req(struct event *t)
+{
+       struct nhrp_shortcut *s = EVENT_ARG(t);
+
+       EVENT_OFF(s->t_retry_resolution);
+       debugf(NHRP_DEBUG_COMMON, "Shortcut: Retrying Resolution Request");
+       nhrp_shortcut_send_resolution_req(s, true);
+}
+
+
 void nhrp_shortcut_init(void)
 {
        shortcut_rib[AFI_IP] = route_table_init();
@@ -503,13 +552,14 @@ struct purge_ctx {
 
 void nhrp_shortcut_purge(struct nhrp_shortcut *s, int force)
 {
-       EVENT_OFF(s->t_timer);
+       EVENT_OFF(s->t_shortcut_purge);
+       EVENT_OFF(s->t_retry_resolution);
        nhrp_reqid_free(&nhrp_packet_reqid, &s->reqid);
 
        if (force) {
                /* Immediate purge on route with draw or pending shortcut */
                event_add_timer_msec(master, nhrp_shortcut_do_purge, s, 5,
-                                    &s->t_timer);
+                                    &s->t_shortcut_purge);
        } else {
                /* Soft expire - force immediate renewal, but purge
                 * in few seconds to make sure stale route is not
@@ -518,8 +568,8 @@ void nhrp_shortcut_purge(struct nhrp_shortcut *s, int force)
                 * This allows to keep nhrp route up, and to not
                 * cause temporary rerouting via hubs causing latency
                 * jitter. */
-               event_add_timer_msec(master, nhrp_shortcut_do_purge, s, 3000,
-                                    &s->t_timer);
+               event_add_timer_msec(master, nhrp_shortcut_do_purge, s,
+                                    NHRPD_PURGE_EXPIRE, &s->t_shortcut_purge);
                s->expiring = 1;
                nhrp_shortcut_check_use(s);
        }
index 344e1d51780ffe20cdb7e7680df8218c8068c1f3..6cab7b3a1d89afff17b02311ea9d48f8a41afbdd 100644 (file)
@@ -15,7 +15,8 @@
 DECLARE_MGROUP(NHRPD);
 
 #define NHRPD_DEFAULT_HOLDTIME 7200
-
+#define NHRPD_DEFAULT_PURGE_TIME 30
+#define NHRPD_PURGE_EXPIRE      3000
 #define NHRP_DEFAULT_CONFIG    "nhrpd.conf"
 
 extern struct event_loop *master;
@@ -250,10 +251,12 @@ struct nhrp_shortcut {
        union sockunion addr;
 
        struct nhrp_reqid reqid;
-       struct event *t_timer;
+       struct event *t_shortcut_purge;
+       struct event *t_retry_resolution;
 
        enum nhrp_cache_type type;
        unsigned int holding_time;
+       unsigned int retry_interval;
        unsigned route_installed : 1;
        unsigned expiring : 1;