Commit 535cd159 authored by Ondrej Zajicek (work)'s avatar Ondrej Zajicek (work)
Browse files

RIP: Demand circuit support (RFC 2091)

parent d2a8b191
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -90,6 +90,8 @@ void fit_init(struct fib_iterator *, struct fib *); /* Internal functions, don't
struct fib_node *fit_get(struct fib *, struct fib_iterator *);
void fit_put(struct fib_iterator *, struct fib_node *);
void fit_put_next(struct fib *f, struct fib_iterator *i, struct fib_node *n, uint hpos);
void fit_put_end(struct fib_iterator *i);
void fit_copy(struct fib *f, struct fib_iterator *dst, struct fib_iterator *src);


#define FIB_WALK(fib, type, z) do {				\
@@ -130,8 +132,12 @@ void fit_put_next(struct fib *f, struct fib_iterator *i, struct fib_node *n, uin

#define FIB_ITERATE_PUT_NEXT(it, fib) fit_put_next(fib, it, fn_, hpos_)

#define FIB_ITERATE_PUT_END(it) fit_put_end(it)

#define FIB_ITERATE_UNLINK(it, fib) fit_get(fib, it)

#define FIB_ITERATE_COPY(dst, src, fib) fit_copy(fib, dst, src)


/*
 *	Master Routing Tables. Generally speaking, each of them contains a FIB
+34 −0
Original line number Diff line number Diff line
@@ -546,6 +546,40 @@ found:
  fit_put(i, n);
}

void
fit_put_end(struct fib_iterator *i)
{
  i->prev = i->next = NULL;
  i->node = NULL;
  i->hash = ~0 - 1;
}

void
fit_copy(struct fib *f, struct fib_iterator *dst, struct fib_iterator *src)
{
  struct fib_iterator *nxt = src->next;

  fit_get(f, dst);

  if (!src->prev)
  {
    /* We are at the end */
    fit_put_end(dst);
    return;
  }

  src->next = dst;
  dst->prev = src;

  dst->next = nxt;
  if (nxt)
    nxt->prev = dst;

  dst->node = src->node;
  dst->hash = src->hash;
}


#ifdef DEBUGGING

/**
+5 −1
Original line number Diff line number Diff line
@@ -36,7 +36,8 @@ CF_KEYWORDS(RIP, NG, ECMP, LIMIT, WEIGHT, INFINITY, METRIC, UPDATE, TIMEOUT,
	    GARBAGE, PORT, ADDRESS, MODE, BROADCAST, MULTICAST, PASSIVE,
	    VERSION, SPLIT, HORIZON, POISON, REVERSE, CHECK, ZERO, TIME, BFD,
	    AUTHENTICATION, NONE, PLAINTEXT, CRYPTOGRAPHIC, MD5, TTL, SECURITY,
	    RX, TX, BUFFER, LENGTH, PRIORITY, ONLY, LINK, RIP_METRIC, RIP_TAG)
	    RX, TX, BUFFER, LENGTH, PRIORITY, ONLY, LINK, DEMAND, CIRCUIT,
	    RIP_METRIC, RIP_TAG)

%type <i> rip_variant rip_auth

@@ -102,6 +103,7 @@ rip_iface_start:
  RIP_IFACE->update_time = RIP_DEFAULT_UPDATE_TIME;
  RIP_IFACE->timeout_time = RIP_DEFAULT_TIMEOUT_TIME;
  RIP_IFACE->garbage_time = RIP_DEFAULT_GARBAGE_TIME;
  RIP_IFACE->rxmt_time = RIP_DEFAULT_RXMT_TIME;
};

rip_iface_finish:
@@ -149,9 +151,11 @@ rip_iface_item:
 | SPLIT HORIZON bool	{ RIP_IFACE->split_horizon = $3; }
 | POISON REVERSE bool	{ RIP_IFACE->poison_reverse = $3; }
 | CHECK ZERO bool	{ RIP_IFACE->check_zero = $3; }
 | DEMAND CIRCUIT bool	{ RIP_IFACE->demand_circuit = $3; }
 | UPDATE TIME expr	{ RIP_IFACE->update_time = $3 S_; if ($3<=0) cf_error("Update time must be positive"); }
 | TIMEOUT TIME expr	{ RIP_IFACE->timeout_time = $3 S_; if ($3<=0) cf_error("Timeout time must be positive"); }
 | GARBAGE TIME expr	{ RIP_IFACE->garbage_time = $3 S_; if ($3<=0) cf_error("Garbage time must be positive"); }
 | RETRANSMIT TIME expr_us { RIP_IFACE->rxmt_time = $3; if ($3<=0) cf_error("Retransmit time must be positive"); }
 | ECMP WEIGHT expr	{ RIP_IFACE->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); }
 | RX BUFFER expr	{ RIP_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX length must be in range 256-65535"); }
 | TX LENGTH expr	{ RIP_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); }
+261 −33
Original line number Diff line number Diff line
@@ -18,12 +18,18 @@
#define RIP_CMD_REQUEST		1	/* want info */
#define RIP_CMD_RESPONSE	2	/* responding to request */

#define RIP_CMD_UPDATE_REQUEST	9
#define RIP_CMD_UPDATE_RESPONSE	10
#define RIP_CMD_UPDATE_ACK	11

#define RIP_BLOCK_LENGTH	20
#define RIP_PASSWD_LENGTH	16

#define RIP_AF_IPV4		2
#define RIP_AF_AUTH		0xffff

#define RIP_UPDATE_VERSION	1


/* RIP packet header */
struct rip_packet
@@ -33,6 +39,14 @@ struct rip_packet
  u16 unused;
};

/* Triggered RIP update header (RFC 2091) */
struct rip_update_hdr
{
  u8 version;
  u8 flush;
  u16 seqnum;
};

/* RTE block for RIPv2 */
struct rip_block_v2
{
@@ -89,6 +103,8 @@ struct rip_block
  ip_addr next_hop;
};

static int
rip_send_ack(struct rip_proto *p, struct rip_iface *ifa, uint flush, uint seqnum);

#define DROP(DSC,VAL) do { err_dsc = DSC; err_val = VAL; goto drop; } while(0)
#define DROP1(DSC) do { err_dsc = DSC; goto drop; } while(0)
@@ -107,8 +123,27 @@ struct rip_block
static inline void * rip_tx_buffer(struct rip_iface *ifa)
{ return ifa->sk->tbuf; }

static inline uint rip_pkt_hdrlen(struct rip_iface *ifa)
{ return sizeof(struct rip_packet) + (ifa->cf->auth_type ? RIP_BLOCK_LENGTH : 0); }
static inline uint
rip_pkt_hdrlen(struct rip_iface *ifa)
{
  return sizeof(struct rip_packet) +
    (ifa->cf->demand_circuit ? sizeof(struct rip_update_hdr) : 0) +
    (ifa->cf->auth_type ? RIP_BLOCK_LENGTH : 0);
}

static inline struct rip_update_hdr *
rip_get_update_hdr(struct rip_packet *pkt)
{
  return (void *) ((byte *) pkt + sizeof(struct rip_packet));
}

static inline struct rip_block_auth *
rip_get_auth_block(struct rip_iface *ifa, struct rip_packet *pkt)
{
  return (void *) ((byte *) pkt + sizeof(struct rip_packet) +
		   (ifa->cf->demand_circuit ? sizeof(struct rip_update_hdr) : 0));
}


static inline void
rip_put_block(struct rip_proto *p, byte *pos, struct rip_block *rte)
@@ -199,10 +234,31 @@ rip_update_csn(struct rip_proto *p UNUSED, struct rip_iface *ifa)
  }
}

static inline void
rip_fill_header(struct rip_iface *ifa, struct rip_packet *pkt, uint cmd)
{
  *pkt = (struct rip_packet) {
    .command = cmd,
    .version = ifa->cf->version
  };
}

static inline void
rip_fill_update_hdr(struct rip_packet *pkt, uint flush, uint seqnum)
{
  struct rip_update_hdr *hdr = rip_get_update_hdr(pkt);

  *hdr = (struct rip_update_hdr) {
    .version = RIP_UPDATE_VERSION,
    .flush = flush,
    .seqnum = htons(seqnum)
  };
}

static void
rip_fill_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_packet *pkt, uint *plen)
{
  struct rip_block_auth *auth = (void *) (pkt + 1);
  struct rip_block_auth *auth = rip_get_auth_block(ifa, pkt);
  struct password_item *pass = password_find(ifa->cf->passwords, 0);

  if (!pass)
@@ -271,16 +327,16 @@ rip_fill_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_p
}

static int
rip_check_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_packet *pkt, uint *plen, struct rip_neighbor *n)
rip_check_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_packet *pkt, uint *plen, uint hdr_len, struct rip_neighbor *n)
{
  struct rip_block_auth *auth = (void *) (pkt + 1);
  struct rip_block_auth *auth = (void *) ((byte *) pkt + hdr_len);
  struct password_item *pass = NULL;
  const char *err_dsc = NULL;
  uint err_val = 0;
  uint auth_type = 0;

  /* Check for authentication entry */
  if ((*plen >= (sizeof(struct rip_packet) + sizeof(struct rip_block_auth))) &&
  if ((*plen >= (hdr_len + sizeof(struct rip_block_auth))) &&
      (auth->must_be_ffff == htons(0xffff)))
    auth_type = ntohs(auth->auth_type);

@@ -376,17 +432,31 @@ rip_send_to(struct rip_proto *p, struct rip_iface *ifa, struct rip_packet *pkt,
  return sk_send_to(ifa->sk, plen, dst, 0);
}

static inline void
rip_kick_rxmt_timer(struct rip_iface *ifa)
{
  if (! tm_active(ifa->rxmt_timer))
    tm_start(ifa->rxmt_timer, ifa->cf->rxmt_time);
}


void
rip_send_request(struct rip_proto *p, struct rip_iface *ifa)
{
  byte *pos = rip_tx_buffer(ifa);
  struct rip_packet *pkt = rip_tx_buffer(ifa);
  byte *pos = (byte *) pkt + rip_pkt_hdrlen(ifa);

  rip_fill_header(ifa, pkt, RIP_CMD_REQUEST);

  if (ifa->cf->demand_circuit)
  {
    pkt->command = RIP_CMD_UPDATE_REQUEST;
    rip_fill_update_hdr(pkt, 0, 0);

  struct rip_packet *pkt = (void *) pos;
  pkt->command = RIP_CMD_REQUEST;
  pkt->version = ifa->cf->version;
  pkt->unused = 0;
  pos += rip_pkt_hdrlen(ifa);
    /* Must be acknowledged by update response */
    ifa->req_pending = 1;
    rip_kick_rxmt_timer(ifa);
  }

  struct rip_block b = { .no_af = 1, .metric = p->infinity };
  rip_put_block(p, pos, &b);
@@ -437,18 +507,25 @@ rip_send_response(struct rip_proto *p, struct rip_iface *ifa)
  if (! ifa->tx_active)
    return 0;

  byte *pos = rip_tx_buffer(ifa);
  byte *max = rip_tx_buffer(ifa) + ifa->tx_plen -
  /* In demand circuit mode, we may wait for ACK */
  if (ifa->tx_pending)
    return 0;

  struct rip_packet *pkt = rip_tx_buffer(ifa);
  byte *pos = (byte *) pkt + rip_pkt_hdrlen(ifa);
  byte *max = (byte *) pkt + ifa->tx_plen -
    (rip_is_v2(p) ? RIP_BLOCK_LENGTH : 2*RIP_BLOCK_LENGTH);
  ip_addr last_next_hop = IPA_NONE;
  btime now_ = current_time();
  int send = 0;

  struct rip_packet *pkt = (void *) pos;
  pkt->command = RIP_CMD_RESPONSE;
  pkt->version = ifa->cf->version;
  pkt->unused = 0;
  pos += rip_pkt_hdrlen(ifa);
  rip_fill_header(ifa, pkt, RIP_CMD_RESPONSE);

  if (ifa->cf->demand_circuit)
  {
    pkt->command = RIP_CMD_UPDATE_RESPONSE;
    rip_fill_update_hdr(pkt, ifa->tx_flush, ifa->tx_seqnum);
  }

  FIB_ITERATE_START(&p->rtable, &ifa->tx_fit, struct rip_entry, en)
  {
@@ -469,7 +546,7 @@ rip_send_response(struct rip_proto *p, struct rip_iface *ifa)
    if (pos > max)
    {
      FIB_ITERATE_PUT(&ifa->tx_fit);
      goto break_loop;
      goto send_pkt;
    }

    struct rip_block rte = {
@@ -522,13 +599,31 @@ rip_send_response(struct rip_proto *p, struct rip_iface *ifa)
  next_entry: ;
  }
  FIB_ITERATE_END;
  ifa->tx_active = 0;

  if (send)
  {
    FIB_ITERATE_PUT_END(&ifa->tx_fit);
    goto send_pkt;
  }

  /* Do not send empty packet */
  if (!send)

  ifa->tx_active = 0;

  /* Unlink second iterator */
  FIB_ITERATE_UNLINK(&ifa->tx_done, &p->rtable);

  return 0;

break_loop:
send_pkt:

  /* Waiting for ack or timeout */
  if (ifa->cf->demand_circuit)
  {
    ifa->tx_pending = 1;
    rip_kick_rxmt_timer(ifa);
  }

  TRACE(D_PACKETS, "Sending response via %s", ifa->iface->name);
  return rip_send_to(p, ifa, pkt, pos - (byte *) pkt, ifa->tx_addr);
}
@@ -558,6 +653,10 @@ rip_send_table(struct rip_proto *p, struct rip_iface *ifa, ip_addr addr, btime c
  ifa->tx_addr = addr;
  ifa->tx_changed = changed;
  FIB_ITERATE_INIT(&ifa->tx_fit, &p->rtable);
  FIB_ITERATE_INIT(&ifa->tx_done, &p->rtable);

  if (ifa->cf->demand_circuit)
    ifa->tx_flush = ! changed;

  rip_update_csn(p, ifa);

@@ -597,9 +696,27 @@ rip_receive_response(struct rip_proto *p, struct rip_iface *ifa, struct rip_pack

  TRACE(D_PACKETS, "Response received from %I on %s", from->nbr->addr, ifa->iface->name);

  byte *pos = (byte *) pkt + sizeof(struct rip_packet);
  byte *pos = (byte *) pkt + rip_pkt_hdrlen(ifa);
  byte *end = (byte *) pkt + plen;
  btime now_ = current_time();

  btime expires = current_time() + ifa->cf->timeout_time;

  if (pkt->command == RIP_CMD_UPDATE_RESPONSE)
  {
    struct rip_update_hdr *hdr = rip_get_update_hdr(pkt);
    rip_send_ack(p, ifa, hdr->flush, ntohs(hdr->seqnum));
    expires = TIME_INFINITY;

    /* Handle flush bit */
    if (hdr->flush)
    {
      /* Flush old routes */
      rip_flush_table(p, from);

      /* Acknowledge pending request */
      ifa->req_pending = 0;
    }
  }

  for (; pos < end; pos += RIP_BLOCK_LENGTH)
  {
@@ -647,7 +764,7 @@ rip_receive_response(struct rip_proto *p, struct rip_iface *ifa, struct rip_pack
	.next_hop = ipa_nonzero(rte.next_hop) ? rte.next_hop : from->nbr->addr,
	.metric = rte.metric,
	.tag = rte.tag,
	.expires = now_ + ifa->cf->timeout_time
	.expires = expires
      };

      rip_update_rte(p, &rte.net, &new);
@@ -663,6 +780,85 @@ rip_receive_response(struct rip_proto *p, struct rip_iface *ifa, struct rip_pack
  }
}


static int
rip_send_ack(struct rip_proto *p, struct rip_iface *ifa, uint flush, uint seqnum)
{
  struct rip_packet *pkt = rip_tx_buffer(ifa);

  rip_fill_header(ifa, pkt, RIP_CMD_UPDATE_ACK);
  rip_fill_update_hdr(pkt, flush, seqnum);

  TRACE(D_PACKETS, "Sending acknowledge via %s", ifa->iface->name);
  return rip_send_to(p, ifa, pkt, rip_pkt_hdrlen(ifa), ifa->tx_addr);
}

static void
rip_receive_ack(struct rip_proto *p, struct rip_iface *ifa, struct rip_packet *pkt, uint plen UNUSED, struct rip_neighbor *from)
{
  TRACE(D_PACKETS, "Acknowledge received from %I on %s", from->nbr->addr, ifa->iface->name);

  struct rip_update_hdr *hdr = rip_get_update_hdr(pkt);
  uint seqnum = ntohs(hdr->seqnum);

  if (! ifa->tx_active || ! ifa->tx_pending)
  {
    LOG_PKT("Bad acknowledge packet from %I via %s - no pending response",
	    from->nbr->addr, ifa->iface->name);
    return;
  }

  if (seqnum != ifa->tx_seqnum)
  {
    LOG_PKT("Bad acknowledge packet from %I via %s - "
	    "mismatched sequence number (rcv %u, old %u)",
	    from->nbr->addr, ifa->iface->name, seqnum, (uint) ifa->tx_seqnum);
    return;
  }

  /* Move acked position */
  FIB_ITERATE_COPY(&ifa->tx_done, &ifa->tx_fit, &p->rtable);

  /* Packet is no longer pending */
  ifa->tx_pending = 0;
  ifa->tx_seqnum++;

  /* Next one does not have flush bit */
  ifa->tx_flush = 0;

  rip_send_response(p, ifa);
}

/**
 * rip_rxmt_timeout - RIP retransmission timer hook
 * @t: timer
 *
 * In Demand Circuit mode, update packets must be acknowledged to ensure
 * reliability. If they are not acknowledged, we need to retransmit them.
 */
void
rip_rxmt_timeout(timer *t)
{
  struct rip_iface *ifa = t->data;
  struct rip_proto *p = ifa->rip;

  if (ifa->req_pending)
    rip_send_request(p, ifa);

  if (ifa->tx_pending)
  {
    /* Revert to acked position */
    FIB_ITERATE_COPY(&ifa->tx_fit, &ifa->tx_done, &p->rtable);

    /* Packet is no longer pending */
    ifa->tx_pending = 0;
    ifa->tx_seqnum++;

    rip_send_response(p, ifa);
  }
}


static int
rip_rx_hook(sock *sk, uint len)
{
@@ -702,17 +898,43 @@ rip_rx_hook(sock *sk, uint len)
    DROP("truncated", len);

  struct rip_packet *pkt = (struct rip_packet *) sk->rbuf;
  uint plen = len;
  uint pkt_len = len;
  uint hdr_len = sizeof(struct rip_packet);
  uint update_msg = 0;

  if (!pkt->version || (ifa->cf->version_only && (pkt->version != ifa->cf->version)))
    DROP("wrong version", pkt->version);

  /* Update packets (RFC 2091) have additional header even before auth data */
  if ((pkt->command == RIP_CMD_UPDATE_REQUEST) ||
      (pkt->command == RIP_CMD_UPDATE_RESPONSE) ||
      (pkt->command == RIP_CMD_UPDATE_ACK))
  {
    hdr_len += sizeof(struct rip_update_hdr);

    if (len < hdr_len)
      DROP("too short", len);

    struct rip_update_hdr *hdr = rip_get_update_hdr(pkt);

    if (hdr->version != RIP_UPDATE_VERSION)
      DROP("wrong update header version", hdr->version);

    if (hdr->flush > 1)
      DROP("wrong flush value", hdr->flush);

    update_msg = 1;
  }

  /* rip_check_authentication() has its own error logging */
  if (rip_is_v2(p) && !rip_check_authentication(p, ifa, pkt, &plen, n))
  if (rip_is_v2(p) && !rip_check_authentication(p, ifa, pkt, &pkt_len, hdr_len, n))
    return 1;

  if ((plen - sizeof(struct rip_packet)) % RIP_BLOCK_LENGTH)
    DROP("invalid length", plen);
  if ((pkt_len - hdr_len) % RIP_BLOCK_LENGTH)
    DROP("invalid length", pkt_len);

  if (update_msg != ifa->cf->demand_circuit)
    DROP("demand circuit mode mismatch", update_msg);

  n->last_seen = current_time();
  rip_update_bfd(p, n);
@@ -720,11 +942,17 @@ rip_rx_hook(sock *sk, uint len)
  switch (pkt->command)
  {
  case RIP_CMD_REQUEST:
    rip_receive_request(p, ifa, pkt, plen, n);
  case RIP_CMD_UPDATE_REQUEST:
    rip_receive_request(p, ifa, pkt, pkt_len, n);
    break;

  case RIP_CMD_RESPONSE:
    rip_receive_response(p, ifa, pkt, plen, n);
  case RIP_CMD_UPDATE_RESPONSE:
    rip_receive_response(p, ifa, pkt, pkt_len, n);
    break;

  case RIP_CMD_UPDATE_ACK:
    rip_receive_ack(p, ifa, pkt, pkt_len, n);
    break;

  default:
+53 −17
Original line number Diff line number Diff line
@@ -369,6 +369,20 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s
  }
}

void
rip_flush_table(struct rip_proto *p, struct rip_neighbor *n)
{
  btime expires = current_time() + n->ifa->cf->timeout_time;

  FIB_WALK(&p->rtable, struct rip_entry, en)
  {
    for (struct rip_rte *e = en->routes; e; e = e->next)
      if ((e->from == n) && (e->expires == TIME_INFINITY))
	e->expires = expires;
  }
  FIB_WALK_END;
}


/*
 *	RIP neighbors
@@ -506,14 +520,20 @@ rip_iface_start(struct rip_iface *ifa)

  TRACE(D_EVENTS, "Starting interface %s", ifa->iface->name);

  if (! ifa->cf->demand_circuit)
  {
    ifa->next_regular = current_time() + (random() % ifa->cf->update_time) + 100 MS;
  ifa->next_triggered = current_time();	/* Available immediately */
  ifa->want_triggered = 1;		/* All routes in triggered update */
  tm_start(ifa->timer, 100 MS);
    tm_set(ifa->timer, ifa->next_regular);
  }
  else
  {
    ifa->next_regular = TIME_INFINITY;
  }

  ifa->up = 1;

  if (!ifa->cf->passive)
    rip_send_request(ifa->rip, ifa);
  rip_send_request(p, ifa);
  rip_send_table(p, ifa, ifa->addr, 0);
}

static void
@@ -526,10 +546,18 @@ rip_iface_stop(struct rip_iface *ifa)

  rip_reset_tx_session(p, ifa);

  ifa->next_regular = 0;
  ifa->next_triggered = 0;
  ifa->want_triggered = 0;

  ifa->tx_pending = 0;
  ifa->req_pending = 0;

  WALK_LIST_FIRST(n, ifa->neigh_list)
    rip_remove_neighbor(p, n);

  tm_stop(ifa->timer);
  tm_stop(ifa->rxmt_timer);
  ifa->up = 0;
}

@@ -643,6 +671,7 @@ rip_add_iface(struct rip_proto *p, struct iface *iface, struct rip_iface_config
  add_tail(&p->iface_list, NODE ifa);

  ifa->timer = tm_new_init(p->p.pool, rip_iface_timer, ifa, 0, 0);
  ifa->rxmt_timer = tm_new_init(p->p.pool, rip_rxmt_timeout, ifa, 0, 0);

  struct object_lock *lock = olock_new(p->p.pool);
  lock->type = OBJLOCK_UDP;
@@ -886,6 +915,11 @@ rip_timer(timer *t)

  /* Handling neighbor expiration */
  WALK_LIST(ifa, p->iface_list)
  {
    /* No expiration for demand circuit ifaces */
    if (ifa->cf->demand_circuit)
      continue;

    WALK_LIST_DELSAFE(n, nn, ifa->neigh_list)
      if (n->last_seen)
      {
@@ -896,6 +930,7 @@ rip_timer(timer *t)
	else
	  next = MIN(next, expires);
      }
  }

  tm_start(p->timer, MAX(next - now_, 100 MS));
}
@@ -903,7 +938,7 @@ rip_timer(timer *t)
static inline void
rip_kick_timer(struct rip_proto *p)
{
  if (p->timer->expires > (current_time() + 100 MS))
  if ((p->timer->expires > (current_time() + 100 MS)))
    tm_start(p->timer, 100 MS);
}

@@ -932,11 +967,8 @@ rip_iface_timer(timer *t)

  if (ifa->tx_active)
  {
    if (now_ < (ifa->next_regular + period))
    { tm_start(ifa->timer, 100 MS); return; }

    /* We are too late, reset is done by rip_send_table() */
    log(L_WARN "%s: Too slow update on %s, resetting", p->p.name, ifa->iface->name);
    tm_start(ifa->timer, 100 MS);
    return;
  }

  if (now_ >= ifa->next_regular)
@@ -958,13 +990,17 @@ rip_iface_timer(timer *t)
    p->triggered = 0;
  }

  tm_start(ifa->timer, ifa->want_triggered ? (1 S) : (ifa->next_regular - now_));
  if (ifa->want_triggered && (ifa->next_triggered < ifa->next_regular))
    tm_set(ifa->timer, ifa->next_triggered);
  else if (ifa->next_regular != TIME_INFINITY)
    tm_set(ifa->timer, ifa->next_regular);
}


static inline void
rip_iface_kick_timer(struct rip_iface *ifa)
{
  if (ifa->timer->expires > (current_time() + 100 MS))
  if ((! tm_active(ifa->timer)) || (ifa->timer->expires > (current_time() + 100 MS)))
    tm_start(ifa->timer, 100 MS);
}

@@ -988,10 +1024,9 @@ rip_trigger_update(struct rip_proto *p)
    TRACE(D_EVENTS, "Scheduling triggered updates for %s", ifa->iface->name);
    ifa->want_triggered = current_time();
    rip_iface_kick_timer(ifa);
  }

    p->triggered = 1;
  }
}


/*
@@ -1210,7 +1245,8 @@ rip_show_interfaces(struct proto *P, char *iff)
	nbrs++;

    btime now_ = current_time();
    btime timer = (ifa->next_regular > now_) ? (ifa->next_regular - now_) : 0;
    btime timer = ((ifa->next_regular < TIME_INFINITY) && (ifa->next_regular > now_)) ?
      (ifa->next_regular - now_) : 0;
    cli_msg(-1021, "%-10s %-6s %6u %6u %7t",
	    ifa->iface->name, (ifa->up ? "Up" : "Down"), ifa->cf->metric, nbrs, timer);
  }
Loading