struct nexthop *nh = allocz(sizeof(struct nexthop));
nh->gw = rt->next_hop;
- nh->iface = rt->from->nbr->iface;
+ nh->iface = rt->from->ifa->iface;
nh->weight = rt->from->ifa->cf->ecmp_weight;
nexthop_insert(&nhs, nh);
/* Unipath route */
a0.from = rt->from->nbr->addr;
a0.nh.gw = rt->next_hop;
- a0.nh.iface = rt->from->nbr->iface;
+ a0.nh.iface = rt->from->ifa->iface;
}
rta *a = rta_lookup(&a0);
e->u.rip.from = a0.nh.iface;
e->u.rip.metric = rt_metric;
e->u.rip.tag = rt_tag;
-
- e->pflags = 0;
+ e->pflags = EA_ID_FLAG(EA_RIP_METRIC) | EA_ID_FLAG(EA_RIP_TAG);
rte_update(&p->p, en->n.addr, e);
}
*/
static void
rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, struct rte *new,
- struct rte *old UNUSED, struct ea_list *attrs)
+ struct rte *old UNUSED)
{
struct rip_proto *p = (struct rip_proto *) P;
struct rip_entry *en;
if (new)
{
/* Update */
- u32 rt_metric = ea_get_int(attrs, EA_RIP_METRIC, 1);
- u32 rt_tag = ea_get_int(attrs, EA_RIP_TAG, 0);
+ u32 rt_metric = ea_get_int(new->attrs->eattrs, EA_RIP_METRIC, 1);
+ u32 rt_tag = ea_get_int(new->attrs->eattrs, EA_RIP_TAG, 0);
if (rt_metric > p->infinity)
{
/* Activate triggered updates */
if (en->metric != old_metric)
{
- en->changed = now;
+ en->changed = current_time();
rip_trigger_update(p);
}
}
+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
struct rip_neighbor *
rip_get_neighbor(struct rip_proto *p, ip_addr *a, struct rip_iface *ifa)
{
- neighbor *nbr = neigh_find2(&p->p, a, ifa->iface, 0);
+ neighbor *nbr = neigh_find(&p->p, *a, ifa->iface, 0);
if (!nbr || (nbr->scope == SCOPE_HOST) || !rip_iface_link_up(ifa))
return NULL;
{
neighbor *nbr = n->nbr;
- TRACE(D_EVENTS, "Removing neighbor %I on %s", nbr->addr, nbr->iface->name);
+ TRACE(D_EVENTS, "Removing neighbor %I on %s", nbr->addr, nbr->ifreq->name);
rem_node(NODE n);
n->ifa = NULL;
*/
ip_addr saddr = rip_is_v2(p) ? n->ifa->sk->saddr : n->nbr->ifa->ip;
n->bfd_req = bfd_request_session(p->p.pool, n->nbr->addr, saddr,
- n->nbr->iface, rip_bfd_notify, n);
+ n->nbr->iface, p->p.vrf,
+ rip_bfd_notify, n);
}
if (!use_bfd && n->bfd_req)
TRACE(D_EVENTS, "Starting interface %s", ifa->iface->name);
- ifa->next_regular = now + (random() % ifa->cf->update_time) + 1;
- ifa->next_triggered = now; /* Available immediately */
- ifa->want_triggered = 1; /* All routes in triggered update */
- tm_start(ifa->timer, 1); /* Or 100 ms */
+ if (! ifa->cf->demand_circuit)
+ {
+ ifa->next_regular = current_time() + (random() % ifa->cf->update_time) + 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);
+ if (ifa->cf->passive)
+ return;
+
+ rip_send_request(p, ifa);
+ rip_send_table(p, ifa, ifa->addr, 0);
}
static void
rip_reset_tx_session(p, ifa);
+ ifa->next_regular = 0;
+ ifa->next_triggered = 0;
+ ifa->want_triggered = 0;
+
+ if (ifa->tx_pending)
+ ifa->tx_seqnum++;
+
+ ifa->tx_pending = 0;
+ ifa->req_pending = 0;
+
+ if (ifa->cf->demand_circuit && !ifa->cf->passive)
+ rip_send_flush(p, ifa);
+
WALK_LIST_FIRST(n, ifa->neigh_list)
rip_remove_neighbor(p, n);
tm_stop(ifa->timer);
+ tm_stop(ifa->rxmt_timer);
ifa->up = 0;
}
else if (ic->mode == RIP_IM_MULTICAST)
ifa->addr = rip_is_v2(p) ? IP4_RIP_ROUTERS : IP6_RIP_ROUTERS;
else /* Broadcast */
- ifa->addr = iface->addr->brd;
+ ifa->addr = iface->addr4->brd;
+ /*
+ * The above is just a workaround for BSD as it can't send broadcasts
+ * to 255.255.255.255. BSD systems need the network broadcast address instead.
+ *
+ * TODO: move this to sysdep code
+ */
init_list(&ifa->neigh_list);
add_tail(&p->iface_list, NODE ifa);
- ifa->timer = tm_new_set(p->p.pool, rip_iface_timer, ifa, 0, 0);
+ 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;
(new->port != old->port) ||
(new->tx_tos != old->tx_tos) ||
(new->tx_priority != old->tx_priority) ||
- (new->ttl_security != old->ttl_security))
+ (new->ttl_security != old->ttl_security) ||
+ (new->demand_circuit != old->demand_circuit))
return 0;
TRACE(D_EVENTS, "Reconfiguring interface %s", ifa->iface->name);
rip_iface_update_buffers(ifa);
- if (ifa->next_regular > (now + new->update_time))
- ifa->next_regular = now + (random() % new->update_time) + 1;
+ if ((! ifa->cf->demand_circuit) &&
+ (ifa->next_regular > (current_time() + new->update_time)))
+ ifa->next_regular = current_time() + (random() % new->update_time) + 100 MS;
+
+ if (ifa->up && new->demand_circuit && (new->passive != old->passive))
+ {
+ if (new->passive)
+ rip_send_flush(p, ifa);
+ else
+ {
+ rip_send_request(p, ifa);
+ rip_send_table(p, ifa, ifa->addr, 0);
+ }
+ }
if (new->check_link != old->check_link)
rip_iface_update_state(ifa);
WALK_LIST(iface, iface_list)
{
- if (! (iface->flags & IF_UP))
+ if (!(iface->flags & IF_UP))
+ continue;
+
+ /* Ignore ifaces without appropriate address */
+ if (rip_is_v2(p) ? !iface->addr4 : !iface->llv6)
continue;
struct rip_iface *ifa = rip_find_iface(p, iface);
{
struct rip_proto *p = (void *) P;
struct rip_config *cf = (void *) P->cf;
+ struct rip_iface *ifa = rip_find_iface(p, iface);
if (iface->flags & IF_IGNORE)
return;
- if (flags & IF_CHANGE_UP)
+ /* Add, remove or restart interface */
+ if (flags & (IF_CHANGE_UPDOWN | (rip_is_v2(p) ? IF_CHANGE_ADDR4 : IF_CHANGE_LLV6)))
{
- struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
+ if (ifa)
+ rip_remove_iface(p, ifa);
+
+ if (!(iface->flags & IF_UP))
+ return;
+
+ /* Ignore ifaces without appropriate address */
+ if (rip_is_v2(p) ? !iface->addr4 : !iface->llv6)
+ return;
+ struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
if (ic)
rip_add_iface(p, iface, ic);
return;
}
- struct rip_iface *ifa = rip_find_iface(p, iface);
-
if (!ifa)
return;
- if (flags & IF_CHANGE_DOWN)
- {
- rip_remove_iface(p, ifa);
- return;
- }
-
if (flags & IF_CHANGE_MTU)
rip_iface_update_buffers(ifa);
struct rip_iface *ifa;
struct rip_neighbor *n, *nn;
struct fib_iterator fit;
- bird_clock_t next = now + MIN(cf->min_timeout_time, cf->max_garbage_time);
- bird_clock_t expires = 0;
+ btime now_ = current_time();
+ btime next = now_ + MIN(cf->min_timeout_time, cf->max_garbage_time);
+ btime expires = 0;
TRACE(D_EVENTS, "Main timer fired");
/* Checking received routes for timeout and for dead neighbors */
for (rp = &en->routes; rt = *rp; /* rp = &rt->next */)
{
- if (!rip_valid_rte(rt) || (rt->expires <= now))
+ if (!rip_valid_rte(rt) || (rt->expires <= now_))
{
rip_remove_rte(p, rp);
changed = 1;
{
expires = en->changed + cf->max_garbage_time;
- if (expires <= now)
+ if (expires <= now_)
{
// TRACE(D_EVENTS, "entry is too old: %N", en->n.addr);
en->valid = 0;
/* 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)
{
expires = n->last_seen + n->ifa->cf->timeout_time;
- if (expires <= now)
+ if (expires <= now_)
rip_remove_neighbor(p, n);
else
next = MIN(next, expires);
}
+ }
- tm_start(p->timer, MAX(next - now, 1));
+ tm_start(p->timer, MAX(next - now_, 100 MS));
}
static inline void
rip_kick_timer(struct rip_proto *p)
{
- if (p->timer->expires > (now + 1))
- tm_start(p->timer, 1); /* Or 100 ms */
+ if ((p->timer->expires > (current_time() + 100 MS)))
+ tm_start(p->timer, 100 MS);
}
/**
{
struct rip_iface *ifa = t->data;
struct rip_proto *p = ifa->rip;
- bird_clock_t period = ifa->cf->update_time;
+ btime now_ = current_time();
+ btime period = ifa->cf->update_time;
if (ifa->cf->passive)
return;
if (ifa->tx_active)
{
- if (now < (ifa->next_regular + period))
- { tm_start(ifa->timer, 1); 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)
+ if (now_ >= ifa->next_regular)
{
/* Send regular update, set timer for next period (or following one if necessay) */
TRACE(D_EVENTS, "Sending regular updates for %s", ifa->iface->name);
rip_send_table(p, ifa, ifa->addr, 0);
- ifa->next_regular += period * (1 + ((now - ifa->next_regular) / period));
+ ifa->next_regular += period * (1 + ((now_ - ifa->next_regular) / period));
ifa->want_triggered = 0;
p->triggered = 0;
}
- else if (ifa->want_triggered && (now >= ifa->next_triggered))
+ else if (ifa->want_triggered && (now_ >= ifa->next_triggered))
{
/* Send triggered update, enforce interval between triggered updates */
TRACE(D_EVENTS, "Sending triggered updates for %s", ifa->iface->name);
rip_send_table(p, ifa, ifa->addr, ifa->want_triggered);
- ifa->next_triggered = now + MIN(5, period / 2 + 1);
+ ifa->next_triggered = now_ + MIN(5 S, period / 2);
ifa->want_triggered = 0;
p->triggered = 0;
}
- tm_start(ifa->timer, ifa->want_triggered ? 1 : (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 > (now + 1))
- tm_start(ifa->timer, 1); /* Or 100 ms */
+ if ((! tm_active(ifa->timer)) || (ifa->timer->expires > (current_time() + 100 MS)))
+ tm_start(ifa->timer, 100 MS);
}
static void
continue;
TRACE(D_EVENTS, "Scheduling triggered updates for %s", ifa->iface->name);
- ifa->want_triggered = now;
+ ifa->want_triggered = current_time();
rip_iface_kick_timer(ifa);
+ p->triggered = 1;
}
-
- p->triggered = 1;
}
* RIP protocol glue
*/
-static struct ea_list *
-rip_prepare_attrs(struct linpool *pool, ea_list *next, u8 metric, u16 tag)
-{
- struct ea_list *l = lp_alloc(pool, sizeof(struct ea_list) + 2 * sizeof(eattr));
-
- l->next = next;
- l->flags = EALF_SORTED;
- l->count = 2;
-
- l->attrs[0].id = EA_RIP_METRIC;
- l->attrs[0].flags = 0;
- l->attrs[0].type = EAF_TYPE_INT | EAF_TEMP;
- l->attrs[0].u.data = metric;
-
- l->attrs[1].id = EA_RIP_TAG;
- l->attrs[1].flags = 0;
- l->attrs[1].type = EAF_TYPE_INT | EAF_TEMP;
- l->attrs[1].u.data = tag;
-
- return l;
-}
-
-static int
-rip_import_control(struct proto *P UNUSED, struct rte **rt, struct ea_list **attrs, struct linpool *pool)
-{
- /* Prepare attributes with initial values */
- if ((*rt)->attrs->source != RTS_RIP)
- *attrs = rip_prepare_attrs(pool, *attrs, 1, 0);
-
- return 0;
-}
-
static void
rip_reload_routes(struct channel *C)
{
rip_kick_timer(p);
}
-static struct ea_list *
+static void
rip_make_tmp_attrs(struct rte *rt, struct linpool *pool)
{
- return rip_prepare_attrs(pool, NULL, rt->u.rip.metric, rt->u.rip.tag);
+ rte_init_tmp_attrs(rt, pool, 2);
+ rte_make_tmp_attr(rt, EA_RIP_METRIC, EAF_TYPE_INT, rt->u.rip.metric);
+ rte_make_tmp_attr(rt, EA_RIP_TAG, EAF_TYPE_INT, rt->u.rip.tag);
}
static void
-rip_store_tmp_attrs(struct rte *rt, struct ea_list *attrs)
+rip_store_tmp_attrs(struct rte *rt, struct linpool *pool)
{
- rt->u.rip.metric = ea_get_int(attrs, EA_RIP_METRIC, 1);
- rt->u.rip.tag = ea_get_int(attrs, EA_RIP_TAG, 0);
+ rte_init_tmp_attrs(rt, pool, 2);
+ rt->u.rip.metric = rte_store_tmp_attr(rt, EA_RIP_METRIC);
+ rt->u.rip.tag = rte_store_tmp_attr(rt, EA_RIP_TAG);
}
static int
/* Define default channel */
if (EMPTY_LIST(CF->channels))
- channel_config_new(NULL, CF->net_type, CF);
+ channel_config_new(NULL, net_label[CF->net_type], CF->net_type, CF);
}
static struct proto *
P->if_notify = rip_if_notify;
P->rt_notify = rip_rt_notify;
P->neigh_notify = rip_neigh_notify;
- P->import_control = rip_import_control;
P->reload_routes = rip_reload_routes;
P->make_tmp_attrs = rip_make_tmp_attrs;
P->store_tmp_attrs = rip_store_tmp_attrs;
fib_init(&p->rtable, P->pool, cf->rip2 ? NET_IP4 : NET_IP6,
sizeof(struct rip_entry), OFFSETOF(struct rip_entry, n), 0, NULL);
p->rte_slab = sl_new(P->pool, sizeof(struct rip_rte));
- p->timer = tm_new_set(P->pool, rip_timer, p, 0, 0);
+ p->timer = tm_new_init(P->pool, rip_timer, p, 0, 0);
p->rip2 = cf->rip2;
p->ecmp = cf->ecmp;
return PS_UP;
}
+static int
+rip_shutdown(struct proto *P)
+{
+ struct rip_proto *p = (void *) P;
+
+ TRACE(D_EVENTS, "Shutdown requested");
+
+ struct rip_iface *ifa;
+ WALK_LIST(ifa, p->iface_list)
+ rip_iface_stop(ifa);
+
+ return PS_DOWN;
+}
+
static int
rip_reconfigure(struct proto *P, struct proto_config *CF)
{
}
static void
-rip_get_route_info(rte *rte, byte *buf, ea_list *attrs UNUSED)
+rip_get_route_info(rte *rte, byte *buf)
{
buf += bsprintf(buf, " (%d/%d)", rte->pref, rte->u.rip.metric);
}
static int
-rip_get_attr(eattr *a, byte *buf, int buflen UNUSED)
+rip_get_attr(const eattr *a, byte *buf, int buflen UNUSED)
{
switch (a->id)
{
}
void
-rip_show_interfaces(struct proto *P, char *iff)
+rip_show_interfaces(struct proto *P, const char *iff)
{
struct rip_proto *p = (void *) P;
struct rip_iface *ifa = NULL;
}
cli_msg(-1021, "%s:", p->p.name);
- cli_msg(-1021, "%-10s %-6s %6s %6s %6s",
+ cli_msg(-1021, "%-10s %-6s %6s %6s %7s",
"Interface", "State", "Metric", "Nbrs", "Timer");
WALK_LIST(ifa, p->iface_list)
if (n->last_seen)
nbrs++;
- int timer = MAX(ifa->next_regular - now, 0);
- cli_msg(-1021, "%-10s %-6s %6u %6u %6u",
+ btime now_ = current_time();
+ 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);
}
}
void
-rip_show_neighbors(struct proto *P, char *iff)
+rip_show_neighbors(struct proto *P, const char *iff)
{
struct rip_proto *p = (void *) P;
struct rip_iface *ifa = NULL;
}
cli_msg(-1022, "%s:", p->p.name);
- cli_msg(-1022, "%-25s %-10s %6s %6s %6s",
+ cli_msg(-1022, "%-25s %-10s %6s %6s %7s",
"IP address", "Interface", "Metric", "Routes", "Seen");
WALK_LIST(ifa, p->iface_list)
if (!n->last_seen)
continue;
- int timer = now - n->last_seen;
- cli_msg(-1022, "%-25I %-10s %6u %6u %6u",
+ btime timer = current_time() - n->last_seen;
+ cli_msg(-1022, "%-25I %-10s %6u %6u %7t",
n->nbr->addr, ifa->iface->name, ifa->cf->metric, n->uc, timer);
}
}
i = 0;
FIB_WALK(&p->rtable, struct rip_entry, en)
{
- debug("RIP: entry #%d: %N via %I dev %s valid %d metric %d age %d s\n",
- i++, en->n.addr, en->next_hop, en->iface->name,
- en->valid, en->metric, now - en->changed);
+ debug("RIP: entry #%d: %N via %I dev %s valid %d metric %d age %t\n",
+ i++, en->n.addr, en->next_hop, en->iface ? en->iface->name : "(null)",
+ en->valid, en->metric, current_time() - en->changed);
+
+ for (struct rip_rte *e = en->routes; e; e = e->next)
+ debug("RIP: via %I metric %d expires %t\n",
+ e->next_hop, e->metric, e->expires - current_time());
}
FIB_WALK_END;
struct protocol proto_rip = {
.name = "RIP",
.template = "rip%d",
- .attr_class = EAP_RIP,
+ .class = PROTOCOL_RIP,
.preference = DEF_PREF_RIP,
.channel_mask = NB_IP,
.proto_size = sizeof(struct rip_proto),
.init = rip_init,
.dump = rip_dump,
.start = rip_start,
+ .shutdown = rip_shutdown,
.reconfigure = rip_reconfigure,
.get_route_info = rip_get_route_info,
.get_attr = rip_get_attr