Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nhrpd: Implement retrying resolution request #16788

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 72 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,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) <
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this something we should add, or at least a comment on, about what's going on here and why it's calculated this way?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'll add a comment explaining the interval calculation.

(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 +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));

aceelindem marked this conversation as resolved.
Show resolved Hide resolved
/* 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 +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))];
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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
Expand All @@ -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);
}
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
Loading