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);
}
}
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);
}
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);
}
}
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);
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);
}
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
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;
!= 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;
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);
* - 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))];
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();
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
* 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);
}