summaryrefslogtreecommitdiff
path: root/proto/rip/rip.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/rip/rip.c')
-rw-r--r--proto/rip/rip.c233
1 files changed, 124 insertions, 109 deletions
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index 7b380097..85e37cea 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -92,15 +92,6 @@ static void rip_trigger_update(struct rip_proto *p);
* RIP routes
*/
-static void
-rip_init_entry(struct fib_node *fn)
-{
- // struct rip_entry *en = (void) *fn;
-
- const uint offset = OFFSETOF(struct rip_entry, routes);
- memset((byte *)fn + offset, 0, sizeof(struct rip_entry) - offset);
-}
-
static struct rip_rte *
rip_add_rte(struct rip_proto *p, struct rip_rte **rp, struct rip_rte *src)
{
@@ -152,27 +143,20 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
if (rt)
{
/* Update */
- net *n = net_get(p->p.table, en->n.prefix, en->n.pxlen);
-
rta a0 = {
.src = p->p.main_source,
.source = RTS_RIP,
.scope = SCOPE_UNIVERSE,
- .cast = RTC_UNICAST
+ .dest = RTD_UNICAST,
};
u8 rt_metric = rt->metric;
u16 rt_tag = rt->tag;
- struct rip_rte *rt2 = rt->next;
- /* Find second valid rte */
- while (rt2 && !rip_valid_rte(rt2))
- rt2 = rt2->next;
-
- if (p->ecmp && rt2)
+ if (p->ecmp)
{
/* ECMP route */
- struct mpnh *nhs = NULL;
+ struct nexthop *nhs = NULL;
int num = 0;
for (rt = en->routes; rt && (num < p->ecmp); rt = rt->next)
@@ -180,54 +164,51 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
if (!rip_valid_rte(rt))
continue;
- struct mpnh *nh = alloca(sizeof(struct mpnh));
+ struct nexthop *nh = allocz(sizeof(struct nexthop));
+
nh->gw = rt->next_hop;
nh->iface = rt->from->nbr->iface;
nh->weight = rt->from->ifa->cf->ecmp_weight;
- mpnh_insert(&nhs, nh);
+
+ nexthop_insert(&nhs, nh);
num++;
if (rt->tag != rt_tag)
rt_tag = 0;
}
- a0.dest = RTD_MULTIPATH;
- a0.nexthops = nhs;
+ a0.nh = *nhs;
}
else
{
/* Unipath route */
- a0.dest = RTD_ROUTER;
- a0.gw = rt->next_hop;
- a0.iface = rt->from->nbr->iface;
a0.from = rt->from->nbr->addr;
+ a0.nh.gw = rt->next_hop;
+ a0.nh.iface = rt->from->nbr->iface;
}
rta *a = rta_lookup(&a0);
rte *e = rte_get_temp(a);
- e->u.rip.from = a0.iface;
+ e->u.rip.from = a0.nh.iface;
e->u.rip.metric = rt_metric;
e->u.rip.tag = rt_tag;
- e->net = n;
e->pflags = 0;
- rte_update(&p->p, n, e);
+ rte_update(&p->p, en->n.addr, e);
}
else
{
/* Withdraw */
- net *n = net_find(p->p.table, en->n.prefix, en->n.pxlen);
- rte_update(&p->p, n, NULL);
+ rte_update(&p->p, en->n.addr, NULL);
}
}
/**
* rip_update_rte - enter a route update to RIP routing table
* @p: RIP instance
- * @prefix: network prefix
- * @pxlen: network prefix length
+ * @addr: network address
* @new: a &rip_rte representing the new route
*
* The function is called by the RIP packet processing code whenever it receives
@@ -237,9 +218,9 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
* rip_withdraw_rte() should be called instead of rip_update_rte().
*/
void
-rip_update_rte(struct rip_proto *p, ip_addr *prefix, int pxlen, struct rip_rte *new)
+rip_update_rte(struct rip_proto *p, net_addr *n, struct rip_rte *new)
{
- struct rip_entry *en = fib_get(&p->rtable, prefix, pxlen);
+ struct rip_entry *en = fib_get(&p->rtable, n);
struct rip_rte *rt, **rp;
int changed = 0;
@@ -279,8 +260,7 @@ rip_update_rte(struct rip_proto *p, ip_addr *prefix, int pxlen, struct rip_rte *
/**
* rip_withdraw_rte - enter a route withdraw to RIP routing table
* @p: RIP instance
- * @prefix: network prefix
- * @pxlen: network prefix length
+ * @addr: network address
* @from: a &rip_neighbor propagating the withdraw
*
* The function is called by the RIP packet processing code whenever it receives
@@ -288,9 +268,9 @@ rip_update_rte(struct rip_proto *p, ip_addr *prefix, int pxlen, struct rip_rte *
* removed. Eventually, the change is also propagated by rip_announce_rte().
*/
void
-rip_withdraw_rte(struct rip_proto *p, ip_addr *prefix, int pxlen, struct rip_neighbor *from)
+rip_withdraw_rte(struct rip_proto *p, net_addr *n, struct rip_neighbor *from)
{
- struct rip_entry *en = fib_find(&p->rtable, prefix, pxlen);
+ struct rip_entry *en = fib_find(&p->rtable, n);
struct rip_rte *rt, **rp;
if (!en)
@@ -317,7 +297,7 @@ rip_withdraw_rte(struct rip_proto *p, ip_addr *prefix, int pxlen, struct rip_nei
* it into our data structures.
*/
static void
-rip_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *net, struct rte *new,
+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 rip_proto *p = (struct rip_proto *) P;
@@ -332,15 +312,15 @@ rip_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *net,
if (rt_metric > p->infinity)
{
- log(L_WARN "%s: Invalid rip_metric value %u for route %I/%d",
- p->p.name, rt_metric, net->n.prefix, net->n.pxlen);
+ log(L_WARN "%s: Invalid rip_metric value %u for route %N",
+ p->p.name, rt_metric, net->n.addr);
rt_metric = p->infinity;
}
if (rt_tag > 0xffff)
{
- log(L_WARN "%s: Invalid rip_tag value %u for route %I/%d",
- p->p.name, rt_tag, net->n.prefix, net->n.pxlen);
+ log(L_WARN "%s: Invalid rip_tag value %u for route %N",
+ p->p.name, rt_tag, net->n.addr);
rt_metric = p->infinity;
rt_tag = 0;
}
@@ -352,7 +332,7 @@ rip_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *net,
* collection.
*/
- en = fib_get(&p->rtable, &net->n.prefix, net->n.pxlen);
+ en = fib_get(&p->rtable, net->n.addr);
old_metric = en->valid ? en->metric : -1;
@@ -360,13 +340,13 @@ rip_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *net,
en->metric = rt_metric;
en->tag = rt_tag;
en->from = (new->attrs->src->proto == P) ? new->u.rip.from : NULL;
- en->iface = new->attrs->iface;
- en->next_hop = new->attrs->gw;
+ en->iface = new->attrs->nh.iface;
+ en->next_hop = new->attrs->nh.gw;
}
else
{
/* Withdraw */
- en = fib_find(&p->rtable, &net->n.prefix, net->n.pxlen);
+ en = fib_find(&p->rtable, net->n.addr);
if (!en || en->valid != RIP_ENTRY_VALID)
return;
@@ -384,7 +364,7 @@ rip_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *net,
/* Activate triggered updates */
if (en->metric != old_metric)
{
- en->changed = now;
+ en->changed = current_time();
rip_trigger_update(p);
}
}
@@ -526,10 +506,10 @@ rip_iface_start(struct rip_iface *ifa)
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 */
+ 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);
ifa->up = 1;
if (!ifa->cf->passive)
@@ -650,13 +630,19 @@ rip_add_iface(struct rip_proto *p, struct iface *iface, struct rip_iface_config
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);
struct object_lock *lock = olock_new(p->p.pool);
lock->type = OBJLOCK_UDP;
@@ -704,8 +690,8 @@ rip_reconfigure_iface(struct rip_proto *p, struct rip_iface *ifa, struct rip_ifa
rip_iface_update_buffers(ifa);
- if (ifa->next_regular > (now + new->update_time))
- ifa->next_regular = now + (random() % new->update_time) + 1;
+ if (ifa->next_regular > (current_time() + new->update_time))
+ ifa->next_regular = current_time() + (random() % new->update_time) + 100 MS;
if (new->check_link != old->check_link)
rip_iface_update_state(ifa);
@@ -726,7 +712,11 @@ rip_reconfigure_ifaces(struct rip_proto *p, struct rip_config *cf)
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);
@@ -764,6 +754,10 @@ rip_if_notify(struct proto *P, unsigned flags, struct iface *iface)
{
struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
+ /* Ignore ifaces without appropriate address */
+ if (rip_is_v2(p) ? !iface->addr4 : !iface->llv6)
+ return;
+
if (ic)
rip_add_iface(p, iface, ic);
@@ -822,24 +816,24 @@ rip_timer(timer *t)
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");
FIB_ITERATE_INIT(&fit, &p->rtable);
loop:
- FIB_ITERATE_START(&p->rtable, &fit, node)
+ FIB_ITERATE_START(&p->rtable, &fit, struct rip_entry, en)
{
- struct rip_entry *en = (struct rip_entry *) node;
struct rip_rte *rt, **rp;
int changed = 0;
/* 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;
@@ -859,7 +853,7 @@ rip_timer(timer *t)
* rip_rt_notify() -> p->rtable change, invalidating hidden variables.
*/
- FIB_ITERATE_PUT_NEXT(&fit, &p->rtable, node);
+ FIB_ITERATE_PUT_NEXT(&fit, &p->rtable);
rip_announce_rte(p, en);
goto loop;
}
@@ -869,9 +863,9 @@ rip_timer(timer *t)
{
expires = en->changed + cf->max_garbage_time;
- if (expires <= now)
+ if (expires <= now_)
{
- // TRACE(D_EVENTS, "entry is too old: %I/%d", en->n.prefix, en->n.pxlen);
+ // TRACE(D_EVENTS, "entry is too old: %N", en->n.addr);
en->valid = 0;
}
else
@@ -881,12 +875,12 @@ rip_timer(timer *t)
/* Remove empty nodes */
if (!en->valid && !en->routes)
{
- FIB_ITERATE_PUT(&fit, node);
- fib_delete(&p->rtable, node);
+ FIB_ITERATE_PUT(&fit);
+ fib_delete(&p->rtable, en);
goto loop;
}
}
- FIB_ITERATE_END(node);
+ FIB_ITERATE_END;
p->rt_reload = 0;
@@ -897,20 +891,20 @@ rip_timer(timer *t)
{
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);
}
/**
@@ -928,7 +922,8 @@ rip_iface_timer(timer *t)
{
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;
@@ -937,40 +932,40 @@ rip_iface_timer(timer *t)
if (ifa->tx_active)
{
- if (now < (ifa->next_regular + period))
- { tm_start(ifa->timer, 1); return; }
+ 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);
}
- 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));
+ tm_start(ifa->timer, ifa->want_triggered ? (1 S) : (ifa->next_regular - now_));
}
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 (ifa->timer->expires > (current_time() + 100 MS))
+ tm_start(ifa->timer, 100 MS);
}
static void
@@ -991,7 +986,7 @@ rip_trigger_update(struct rip_proto *p)
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);
}
@@ -1035,19 +1030,17 @@ rip_import_control(struct proto *P UNUSED, struct rte **rt, struct ea_list **att
return 0;
}
-static int
-rip_reload_routes(struct proto *P)
+static void
+rip_reload_routes(struct channel *C)
{
- struct rip_proto *p = (struct rip_proto *) P;
+ struct rip_proto *p = (struct rip_proto *) C->proto;
if (p->rt_reload)
- return 1;
+ return;
TRACE(D_EVENTS, "Scheduling route reload");
p->rt_reload = 1;
rip_kick_timer(p);
-
- return 1;
}
static struct ea_list *
@@ -1078,12 +1071,23 @@ rip_rte_same(struct rte *new, struct rte *old)
}
+static void
+rip_postconfig(struct proto_config *CF)
+{
+ // struct rip_config *cf = (void *) CF;
+
+ /* Define default channel */
+ if (EMPTY_LIST(CF->channels))
+ channel_config_new(NULL, net_label[CF->net_type], CF->net_type, CF);
+}
+
static struct proto *
-rip_init(struct proto_config *cfg)
+rip_init(struct proto_config *CF)
{
- struct proto *P = proto_new(cfg, sizeof(struct rip_proto));
+ struct proto *P = proto_new(CF);
+
+ P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
- P->accept_ra_types = RA_OPTIMAL;
P->if_notify = rip_if_notify;
P->rt_notify = rip_rt_notify;
P->neigh_notify = rip_neigh_notify;
@@ -1104,10 +1108,12 @@ rip_start(struct proto *P)
struct rip_config *cf = (void *) (P->cf);
init_list(&p->iface_list);
- fib_init(&p->rtable, P->pool, sizeof(struct rip_entry), 0, rip_init_entry);
+ 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;
p->infinity = cf->infinity;
p->triggered = 0;
@@ -1121,18 +1127,24 @@ rip_start(struct proto *P)
}
static int
-rip_reconfigure(struct proto *P, struct proto_config *c)
+rip_reconfigure(struct proto *P, struct proto_config *CF)
{
struct rip_proto *p = (void *) P;
- struct rip_config *new = (void *) c;
+ struct rip_config *new = (void *) CF;
// struct rip_config *old = (void *) (P->cf);
+ if (new->rip2 != p->rip2)
+ return 0;
+
if (new->infinity != p->infinity)
return 0;
+ if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
+ return 0;
+
TRACE(D_EVENTS, "Reconfiguring");
- p->p.cf = c;
+ p->p.cf = CF;
p->ecmp = new->ecmp;
rip_reconfigure_ifaces(p, new);
@@ -1184,7 +1196,7 @@ rip_show_interfaces(struct proto *P, char *iff)
}
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)
@@ -1197,8 +1209,9 @@ rip_show_interfaces(struct proto *P, char *iff)
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 > 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);
}
@@ -1220,7 +1233,7 @@ rip_show_neighbors(struct proto *P, char *iff)
}
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)
@@ -1233,8 +1246,8 @@ rip_show_neighbors(struct proto *P, char *iff)
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);
}
}
@@ -1250,12 +1263,11 @@ rip_dump(struct proto *P)
int i;
i = 0;
- FIB_WALK(&p->rtable, e)
+ FIB_WALK(&p->rtable, struct rip_entry, en)
{
- struct rip_entry *en = (struct rip_entry *) e;
- debug("RIP: entry #%d: %I/%d via %I dev %s valid %d metric %d age %d s\n",
- i++, en->n.prefix, en->n.pxlen, 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->name,
+ en->valid, en->metric, current_time() - en->changed);
}
FIB_WALK_END;
@@ -1274,7 +1286,10 @@ struct protocol proto_rip = {
.template = "rip%d",
.attr_class = EAP_RIP,
.preference = DEF_PREF_RIP,
+ .channel_mask = NB_IP,
+ .proto_size = sizeof(struct rip_proto),
.config_size = sizeof(struct rip_config),
+ .postconfig = rip_postconfig,
.init = rip_init,
.dump = rip_dump,
.start = rip_start,