Skip to content

Commit

Permalink
nhrpd: Implement retrying resolution request
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
jmuthiilabn committed Sep 17, 2024
1 parent 5989d1c commit 949feea
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 24 deletions.
93 changes: 71 additions & 22 deletions nhrpd/nhrp_shortcut.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand All @@ -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);
}
Expand Down Expand Up @@ -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);
}
}

Expand All @@ -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);
Expand All @@ -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);
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -389,6 +396,21 @@ 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 retry 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;

Expand All @@ -401,9 +423,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);
Expand All @@ -412,7 +448,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))];
Expand Down Expand Up @@ -456,13 +492,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();
Expand Down Expand Up @@ -503,13 +551,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
Expand All @@ -518,8 +567,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);
}
Expand Down
7 changes: 5 additions & 2 deletions nhrpd/nhrpd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down

0 comments on commit 949feea

Please sign in to comment.