/* Determine whether a given request should be forwarded. */ int request_redundant(struct interface *ifp, const unsigned char *prefix, unsigned char plen, const unsigned char *src_prefix, unsigned char src_plen, unsigned short seqno, const unsigned char *id) { struct resend *request; request = find_request(prefix, plen, src_prefix, src_plen, NULL); if(request == NULL || resend_expired(request)) return 0; if(memcmp(request->id, id, 8) == 0 && seqno_compare(request->seqno, seqno) > 0) return 0; if(request->ifp != NULL && request->ifp != ifp) return 0; if(request->max > 0) /* Will be resent. */ return 1; if(timeval_minus_msec(&now, &request->time) < (ifp ? MIN(ifp->hello_interval, 1000) : 1000)) /* Fairly recent. */ return 1; return 0; }
int satisfy_request(const unsigned char *prefix, unsigned char plen, const unsigned char *src_prefix, unsigned char src_plen, unsigned short seqno, const unsigned char *id, struct interface *ifp) { struct resend *request, *previous; request = find_request(prefix, plen, src_prefix, src_plen, &previous); if(request == NULL) return 0; if(ifp != NULL && request->ifp != ifp) return 0; if(memcmp(request->id, id, 8) != 0 || seqno_compare(request->seqno, seqno) <= 0) { /* We cannot remove the request, as we may be walking the list right now. Mark it as expired, so that expire_resend will remove it. */ request->max = 0; request->time.tv_sec = 0; recompute_resend_time(); return 1; } return 0; }
int unsatisfied_request(const unsigned char *prefix, unsigned char plen, unsigned short seqno, const unsigned char *id) { struct resend *request; request = find_request(prefix, plen, NULL); if(request == NULL || resend_expired(request)) return 0; if(memcmp(request->id, id, 8) != 0 || seqno_compare(request->seqno, seqno) <= 0) return 1; return 0; }
void update_source(struct source *src, unsigned short seqno, unsigned short metric) { if(metric >= INFINITY) return; /* If a source is expired, pretend that it doesn't exist and update it unconditionally. This makes ensures that old data will eventually be overridden, and prevents us from getting stuck if a router loses its sequence number. */ if(src->time < now.tv_sec - SOURCE_GC_TIME || seqno_compare(src->seqno, seqno) < 0 || (src->seqno == seqno && src->metric > metric)) { src->seqno = seqno; src->metric = metric; } src->time = now.tv_sec; }
int record_resend(int kind, const unsigned char *prefix, unsigned char plen, const unsigned char *src_prefix, unsigned char src_plen, unsigned short seqno, const unsigned char *id, struct interface *ifp, int delay) { struct resend *resend; unsigned int ifindex = ifp ? ifp->ifindex : 0; if((kind == RESEND_REQUEST && input_filter(NULL, prefix, plen, src_prefix, src_plen, NULL, ifindex) >= INFINITY) || (kind == RESEND_UPDATE && output_filter(NULL, prefix, plen, src_prefix, src_plen, ifindex) >= INFINITY)) return 0; if(delay >= 0xFFFF) delay = 0xFFFF; resend = find_resend(kind, prefix, plen, src_prefix, src_plen, NULL); if(resend) { if(resend->delay && delay) resend->delay = MIN(resend->delay, delay); else if(delay) resend->delay = delay; resend->time = now; resend->max = RESEND_MAX; if(id && memcmp(resend->id, id, 8) == 0 && seqno_compare(resend->seqno, seqno) > 0) { return 0; } if(id) memcpy(resend->id, id, 8); else memset(resend->id, 0, 8); resend->seqno = seqno; if(resend->ifp != ifp) resend->ifp = NULL; } else { resend = calloc(1, sizeof(struct resend)); if(resend == NULL) return -1; resend->kind = kind; resend->max = RESEND_MAX; resend->delay = delay; memcpy(resend->prefix, prefix, 16); resend->plen = plen; memcpy(resend->src_prefix, src_prefix, 16); resend->src_plen = src_plen; resend->seqno = seqno; if(id) memcpy(resend->id, id, 8); resend->ifp = ifp; resend->time = now; resend->next = to_resend; to_resend = resend; } if(resend->delay) { struct timeval timeout; timeval_add_msec(&timeout, &resend->time, resend->delay); timeval_min(&resend_time, &timeout); } return 1; }