summaryrefslogtreecommitdiff
path: root/proto/babel
diff options
context:
space:
mode:
Diffstat (limited to 'proto/babel')
-rw-r--r--proto/babel/Makefile9
-rw-r--r--proto/babel/babel.c334
-rw-r--r--proto/babel/babel.h42
-rw-r--r--proto/babel/config.Y6
-rw-r--r--proto/babel/packets.c353
5 files changed, 538 insertions, 206 deletions
diff --git a/proto/babel/Makefile b/proto/babel/Makefile
index 400ffbac..a5b4a13b 100644
--- a/proto/babel/Makefile
+++ b/proto/babel/Makefile
@@ -1,5 +1,6 @@
-source=babel.c packets.c
-root-rel=../../
-dir-name=proto/babel
+src := babel.c packets.c
+obj := $(src-o-files)
+$(all-daemon)
+$(cf-local)
-include ../../Rules
+tests_objs := $(tests_objs) $(src-o-files) \ No newline at end of file
diff --git a/proto/babel/babel.c b/proto/babel/babel.c
index 38be6909..67a59df6 100644
--- a/proto/babel/babel.c
+++ b/proto/babel/babel.c
@@ -53,8 +53,7 @@ static void babel_dump_route(struct babel_route *r);
static void babel_select_route(struct babel_entry *e);
static void babel_send_route_request(struct babel_entry *e, struct babel_neighbor *n);
static void babel_send_wildcard_request(struct babel_iface *ifa);
-static int babel_cache_seqno_request(struct babel_proto *p, ip_addr prefix, u8 plen,
- u64 router_id, u16 seqno);
+static int babel_cache_seqno_request(struct babel_proto *p, net_addr *n, u64 router_id, u16 seqno);
static void babel_trigger_iface_update(struct babel_iface *ifa);
static void babel_trigger_update(struct babel_proto *p);
static void babel_send_seqno_request(struct babel_entry *e);
@@ -67,27 +66,27 @@ static inline void babel_iface_kick_timer(struct babel_iface *ifa);
*/
static void
-babel_init_entry(struct fib_node *n)
+babel_init_entry(void *E)
{
- struct babel_entry *e = (void *) n;
- e->proto = NULL;
- e->selected_in = NULL;
- e->selected_out = NULL;
+ struct babel_entry *e = E;
+
e->updated = now;
init_list(&e->sources);
init_list(&e->routes);
}
static inline struct babel_entry *
-babel_find_entry(struct babel_proto *p, ip_addr prefix, u8 plen)
+babel_find_entry(struct babel_proto *p, const net_addr *n)
{
- return fib_find(&p->rtable, &prefix, plen);
+ struct fib *rtable = (n->type == NET_IP4) ? &p->ip4_rtable : &p->ip6_rtable;
+ return fib_find(rtable, n);
}
static struct babel_entry *
-babel_get_entry(struct babel_proto *p, ip_addr prefix, u8 plen)
+babel_get_entry(struct babel_proto *p, const net_addr *n)
{
- struct babel_entry *e = fib_get(&p->rtable, &prefix, plen);
+ struct fib *rtable = (n->type == NET_IP4) ? &p->ip4_rtable : &p->ip6_rtable;
+ struct babel_entry *e = fib_get(rtable, n);
e->proto = p;
return e;
}
@@ -180,8 +179,8 @@ babel_flush_route(struct babel_route *r)
{
struct babel_proto *p = r->e->proto;
- DBG("Babel: Flush route %I/%d router_id %lR neigh %I\n",
- r->e->n.prefix, r->e->n.pxlen, r->router_id, r->neigh ? r->neigh->addr : IPA_NONE);
+ DBG("Babel: Flush route %N router_id %lR neigh %I\n",
+ r->e->n.addr, r->router_id, r->neigh ? r->neigh->addr : IPA_NONE);
rem_node(NODE r);
@@ -203,8 +202,8 @@ babel_expire_route(struct babel_route *r)
struct babel_proto *p = r->e->proto;
struct babel_entry *e = r->e;
- TRACE(D_EVENTS, "Route expiry timer for %I/%d router-id %lR fired",
- e->n.prefix, e->n.pxlen, r->router_id);
+ TRACE(D_EVENTS, "Route expiry timer for %N router-id %lR fired",
+ e->n.addr, r->router_id);
if (r->metric < BABEL_INFINITY)
{
@@ -227,18 +226,16 @@ babel_refresh_route(struct babel_route *r)
}
static void
-babel_expire_routes(struct babel_proto *p)
+babel_expire_routes_(struct babel_proto *p UNUSED, struct fib *rtable)
{
- struct babel_entry *e;
struct babel_route *r, *rx;
struct fib_iterator fit;
- FIB_ITERATE_INIT(&fit, &p->rtable);
+ FIB_ITERATE_INIT(&fit, rtable);
loop:
- FIB_ITERATE_START(&p->rtable, &fit, n)
+ FIB_ITERATE_START(rtable, &fit, struct babel_entry, e)
{
- e = (struct babel_entry *) n;
int changed = 0;
WALK_LIST_DELSAFE(r, rx, e->routes)
@@ -258,10 +255,10 @@ loop:
/*
* We have to restart the iteration because there may be a cascade of
* synchronous events babel_select_route() -> nest table change ->
- * babel_rt_notify() -> p->rtable change, invalidating hidden variables.
+ * babel_rt_notify() -> rtable change, invalidating hidden variables.
*/
- FIB_ITERATE_PUT(&fit, n);
+ FIB_ITERATE_PUT(&fit);
babel_select_route(e);
goto loop;
}
@@ -271,12 +268,19 @@ loop:
/* Remove empty entries */
if (EMPTY_LIST(e->sources) && EMPTY_LIST(e->routes))
{
- FIB_ITERATE_PUT(&fit, n);
- fib_delete(&p->rtable, e);
+ FIB_ITERATE_PUT(&fit);
+ fib_delete(rtable, e);
goto loop;
}
}
- FIB_ITERATE_END(n);
+ FIB_ITERATE_END;
+}
+
+static void
+babel_expire_routes(struct babel_proto *p)
+{
+ babel_expire_routes_(p, &p->ip4_rtable);
+ babel_expire_routes_(p, &p->ip6_rtable);
}
static struct babel_neighbor *
@@ -473,38 +477,35 @@ static void
babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
{
struct babel_route *r = e->selected_in;
+ struct channel *c = (e->n.addr->type == NET_IP4) ? p->ip4_channel : p->ip6_channel;
if (r)
{
- net *n = net_get(p->p.table, e->n.prefix, e->n.pxlen);
- rta A = {
+ rta *ap0 = allocz(RTA_MAX_SIZE);
+ *ap0 = (rta) {
.src = p->p.main_source,
.source = RTS_BABEL,
.scope = SCOPE_UNIVERSE,
- .cast = RTC_UNICAST,
- .dest = r->metric == BABEL_INFINITY ? RTD_UNREACHABLE : RTD_ROUTER,
- .flags = 0,
+ .dest = r->metric == BABEL_INFINITY ? RTD_UNREACHABLE : RTD_UNICAST,
.from = r->neigh->addr,
- .iface = r->neigh->ifa->iface,
+ .nh.iface = r->neigh->ifa->iface,
};
if (r->metric < BABEL_INFINITY)
- A.gw = r->next_hop;
+ ap0->nh.gw = r->next_hop;
- rta *a = rta_lookup(&A);
+ rta *a = rta_lookup(ap0);
rte *rte = rte_get_temp(a);
rte->u.babel.metric = r->metric;
rte->u.babel.router_id = r->router_id;
- rte->net = n;
rte->pflags = 0;
- rte_update(&p->p, n, rte);
+ rte_update2(c, e->n.addr, rte, p->p.main_source);
}
else
{
/* Retraction */
- net *n = net_find(p->p.table, e->n.prefix, e->n.pxlen);
- rte_update(&p->p, n, NULL);
+ rte_update2(c, e->n.addr, NULL, p->p.main_source);
}
}
@@ -541,8 +542,8 @@ babel_select_route(struct babel_entry *e)
((!e->selected_in && cur->metric < BABEL_INFINITY) ||
(e->selected_in && cur->metric < e->selected_in->metric)))
{
- TRACE(D_EVENTS, "Picked new route for prefix %I/%d: router id %lR metric %d",
- e->n.prefix, e->n.pxlen, cur->router_id, cur->metric);
+ TRACE(D_EVENTS, "Picked new route for prefix %N: router id %lR metric %d",
+ e->n.addr, cur->router_id, cur->metric);
e->selected_in = cur;
e->updated = now;
@@ -557,8 +558,8 @@ babel_select_route(struct babel_entry *e)
babel_build_rte() will set the unreachable flag if the metric is BABEL_INFINITY.*/
if (e->selected_in)
{
- TRACE(D_EVENTS, "Lost feasible route for prefix %I/%d",
- e->n.prefix, e->n.pxlen);
+ TRACE(D_EVENTS, "Lost feasible route for prefix %N",
+ e->n.addr);
e->selected_in->metric = BABEL_INFINITY;
e->updated = now;
@@ -576,7 +577,7 @@ babel_select_route(struct babel_entry *e)
/* No route currently selected, and no new one selected; this means we
don't have a route to this destination anymore (and were probably
called from an expiry timer). Remove the route from the nest. */
- TRACE(D_EVENTS, "Flushing route for prefix %I/%d", e->n.prefix, e->n.pxlen);
+ TRACE(D_EVENTS, "Flushing route for prefix %N", e->n.addr);
e->selected_in = NULL;
e->updated = now;
@@ -663,12 +664,11 @@ babel_send_route_request(struct babel_entry *e, struct babel_neighbor *n)
struct babel_iface *ifa = n->ifa;
union babel_msg msg = {};
- TRACE(D_PACKETS, "Sending route request for %I/%d to %I",
- e->n.prefix, e->n.pxlen, n->addr);
+ TRACE(D_PACKETS, "Sending route request for %N to %I",
+ e->n.addr, n->addr);
msg.type = BABEL_TLV_ROUTE_REQUEST;
- msg.route_request.prefix = e->n.prefix;
- msg.route_request.plen = e->n.pxlen;
+ net_copy(&msg.route_request.net, e->n.addr);
babel_send_unicast(&msg, ifa, n->addr);
}
@@ -698,18 +698,17 @@ babel_send_seqno_request(struct babel_entry *e)
union babel_msg msg = {};
s = babel_find_source(e, r->router_id);
- if (!s || !babel_cache_seqno_request(p, e->n.prefix, e->n.pxlen, r->router_id, s->seqno + 1))
+ if (!s || !babel_cache_seqno_request(p, e->n.addr, r->router_id, s->seqno + 1))
return;
- TRACE(D_PACKETS, "Sending seqno request for %I/%d router-id %lR seqno %d",
- e->n.prefix, e->n.pxlen, r->router_id, s->seqno + 1);
+ TRACE(D_PACKETS, "Sending seqno request for %N router-id %lR seqno %d",
+ e->n.addr, r->router_id, s->seqno + 1);
msg.type = BABEL_TLV_SEQNO_REQUEST;
- msg.seqno_request.plen = e->n.pxlen;
- msg.seqno_request.seqno = s->seqno + 1;
msg.seqno_request.hop_count = BABEL_INITIAL_HOP_COUNT;
+ msg.seqno_request.seqno = s->seqno + 1;
msg.seqno_request.router_id = r->router_id;
- msg.seqno_request.prefix = e->n.prefix;
+ net_copy(&msg.seqno_request.net, e->n.addr);
WALK_LIST(ifa, p->interfaces)
babel_enqueue(&msg, ifa);
@@ -725,18 +724,17 @@ babel_unicast_seqno_request(struct babel_route *r)
union babel_msg msg = {};
s = babel_find_source(e, r->router_id);
- if (!s || !babel_cache_seqno_request(p, e->n.prefix, e->n.pxlen, r->router_id, s->seqno + 1))
+ if (!s || !babel_cache_seqno_request(p, e->n.addr, r->router_id, s->seqno + 1))
return;
- TRACE(D_PACKETS, "Sending seqno request for %I/%d router-id %lR seqno %d",
- e->n.prefix, e->n.pxlen, r->router_id, s->seqno + 1);
+ TRACE(D_PACKETS, "Sending seqno request for %N router-id %lR seqno %d",
+ e->n.addr, r->router_id, s->seqno + 1);
msg.type = BABEL_TLV_SEQNO_REQUEST;
- msg.seqno_request.plen = e->n.pxlen;
- msg.seqno_request.seqno = s->seqno + 1;
msg.seqno_request.hop_count = BABEL_INITIAL_HOP_COUNT;
+ msg.seqno_request.seqno = s->seqno + 1;
msg.seqno_request.router_id = r->router_id;
- msg.seqno_request.prefix = e->n.prefix;
+ net_copy(&msg.seqno_request.net, e->n.addr);
babel_send_unicast(&msg, ifa, r->neigh->addr);
}
@@ -752,13 +750,12 @@ babel_unicast_seqno_request(struct babel_route *r)
* transmitted entry is updated.
*/
static void
-babel_send_update(struct babel_iface *ifa, bird_clock_t changed)
+babel_send_update_(struct babel_iface *ifa, bird_clock_t changed, struct fib *rtable)
{
struct babel_proto *p = ifa->proto;
- FIB_WALK(&p->rtable, n)
+ FIB_WALK(rtable, struct babel_entry, e)
{
- struct babel_entry *e = (void *) n;
struct babel_route *r = e->selected_out;
if (!r)
@@ -776,17 +773,19 @@ babel_send_update(struct babel_iface *ifa, bird_clock_t changed)
if (e->updated < changed)
continue;
- TRACE(D_PACKETS, "Sending update for %I/%d router-id %lR seqno %d metric %d",
- e->n.prefix, e->n.pxlen, r->router_id, r->seqno, r->metric);
+ TRACE(D_PACKETS, "Sending update for %N router-id %lR seqno %d metric %d",
+ e->n.addr, r->router_id, r->seqno, r->metric);
union babel_msg msg = {};
msg.type = BABEL_TLV_UPDATE;
- msg.update.plen = e->n.pxlen;
msg.update.interval = ifa->cf->update_interval;
msg.update.seqno = r->seqno;
msg.update.metric = r->metric;
- msg.update.prefix = e->n.prefix;
msg.update.router_id = r->router_id;
+ net_copy(&msg.update.net, e->n.addr);
+
+ msg.update.next_hop = ((e->n.addr->type == NET_IP4) ?
+ ifa->next_hop_ip4 : ifa->next_hop_ip6);
babel_enqueue(&msg, ifa);
@@ -808,6 +807,15 @@ babel_send_update(struct babel_iface *ifa, bird_clock_t changed)
}
static void
+babel_send_update(struct babel_iface *ifa, bird_clock_t changed)
+{
+ struct babel_proto *p = ifa->proto;
+
+ babel_send_update_(ifa, changed, &p->ip4_rtable);
+ babel_send_update_(ifa, changed, &p->ip6_rtable);
+}
+
+static void
babel_trigger_iface_update(struct babel_iface *ifa)
{
struct babel_proto *p = ifa->proto;
@@ -839,20 +847,18 @@ babel_trigger_update(struct babel_proto *p)
/* A retraction is an update with an infinite metric */
static void
-babel_send_retraction(struct babel_iface *ifa, ip_addr prefix, int plen)
+babel_send_retraction(struct babel_iface *ifa, net_addr *n)
{
struct babel_proto *p = ifa->proto;
union babel_msg msg = {};
- TRACE(D_PACKETS, "Sending retraction for %I/%d seqno %d",
- prefix, plen, p->update_seqno);
+ TRACE(D_PACKETS, "Sending retraction for %N seqno %d", n, p->update_seqno);
msg.type = BABEL_TLV_UPDATE;
- msg.update.plen = plen;
msg.update.interval = ifa->cf->update_interval;
msg.update.seqno = p->update_seqno;
msg.update.metric = BABEL_INFINITY;
- msg.update.prefix = prefix;
+ msg.update.net = *n;
babel_enqueue(&msg, ifa);
}
@@ -941,22 +947,20 @@ babel_expire_seqno_requests(struct babel_proto *p)
* found. Otherwise, a new entry is stored in the cache.
*/
static int
-babel_cache_seqno_request(struct babel_proto *p, ip_addr prefix, u8 plen,
+babel_cache_seqno_request(struct babel_proto *p, net_addr *n,
u64 router_id, u16 seqno)
{
struct babel_seqno_request *r;
WALK_LIST(r, p->seqno_cache)
{
- if (ipa_equal(r->prefix, prefix) && (r->plen == plen) &&
- (r->router_id == router_id) && (r->seqno == seqno))
+ if (net_equal(&r->net, n) && (r->router_id == router_id) && (r->seqno == seqno))
return 0;
}
/* no entries found */
r = sl_alloc(p->seqno_slab);
- r->prefix = prefix;
- r->plen = plen;
+ net_copy(&r->net, n);
r->router_id = router_id;
r->seqno = seqno;
r->updated = now;
@@ -973,8 +977,8 @@ babel_forward_seqno_request(struct babel_entry *e,
struct babel_proto *p = e->proto;
struct babel_route *r;
- TRACE(D_PACKETS, "Forwarding seqno request for %I/%d router-id %lR seqno %d",
- e->n.prefix, e->n.pxlen, in->router_id, in->seqno);
+ TRACE(D_PACKETS, "Forwarding seqno request for %N router-id %lR seqno %d",
+ e->n.addr, in->router_id, in->seqno);
WALK_LIST(r, e->routes)
{
@@ -982,16 +986,15 @@ babel_forward_seqno_request(struct babel_entry *e,
!OUR_ROUTE(r) &&
!ipa_equal(r->neigh->addr, sender))
{
- if (!babel_cache_seqno_request(p, e->n.prefix, e->n.pxlen, in->router_id, in->seqno))
+ if (!babel_cache_seqno_request(p, e->n.addr, in->router_id, in->seqno))
return;
union babel_msg msg = {};
msg.type = BABEL_TLV_SEQNO_REQUEST;
- msg.seqno_request.plen = in->plen;
- msg.seqno_request.seqno = in->seqno;
msg.seqno_request.hop_count = in->hop_count-1;
+ msg.seqno_request.seqno = in->seqno;
msg.seqno_request.router_id = in->router_id;
- msg.seqno_request.prefix = e->n.prefix;
+ net_copy(&msg.seqno_request.net, e->n.addr);
babel_send_unicast(&msg, r->neigh->ifa, r->neigh->addr);
return;
@@ -1073,8 +1076,11 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
node *n;
int feasible;
- TRACE(D_PACKETS, "Handling update for %I/%d with seqno %d metric %d",
- msg->prefix, msg->plen, msg->seqno, msg->metric);
+ if (msg->wildcard)
+ TRACE(D_PACKETS, "Handling wildcard retraction", msg->seqno);
+ else
+ TRACE(D_PACKETS, "Handling update for %N with seqno %d metric %d",
+ &msg->net, msg->seqno, msg->metric);
nbr = babel_find_neighbor(ifa, msg->sender);
if (!nbr)
@@ -1089,6 +1095,13 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
return;
}
+ struct channel *c = (msg->net.type == NET_IP4) ? p->ip4_channel : p->ip6_channel;
+ if (!c || (c->channel_state != CS_UP))
+ {
+ DBG("Babel: Ignoring update for inactive address family.\n");
+ return;
+ }
+
/*
* RFC section 3.5.4:
*
@@ -1140,7 +1153,7 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
}
else
{
- e = babel_find_entry(p, msg->prefix, msg->plen);
+ e = babel_find_entry(p, &msg->net);
if (!e)
return;
@@ -1159,7 +1172,7 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
return;
}
- e = babel_get_entry(p, msg->prefix, msg->plen);
+ e = babel_get_entry(p, &msg->net);
r = babel_find_route(e, nbr); /* the route entry indexed by neighbour */
s = babel_find_source(e, msg->router_id); /* for feasibility */
feasible = babel_is_feasible(s, msg->seqno, msg->metric);
@@ -1231,14 +1244,14 @@ babel_handle_route_request(union babel_msg *m, struct babel_iface *ifa)
return;
}
- TRACE(D_PACKETS, "Handling route request for %I/%d", msg->prefix, msg->plen);
+ TRACE(D_PACKETS, "Handling route request for %N", &msg->net);
/* Non-wildcard request - see if we have an entry for the route.
If not, send a retraction, otherwise send an update. */
- struct babel_entry *e = babel_find_entry(p, msg->prefix, msg->plen);
+ struct babel_entry *e = babel_find_entry(p, &msg->net);
if (!e)
{
- babel_send_retraction(ifa, msg->prefix, msg->plen);
+ babel_send_retraction(ifa, &msg->net);
}
else
{
@@ -1256,11 +1269,11 @@ babel_handle_seqno_request(union babel_msg *m, struct babel_iface *ifa)
/* RFC 6126 3.8.1.2 */
- TRACE(D_PACKETS, "Handling seqno request for %I/%d router-id %lR seqno %d hop count %d",
- msg->prefix, msg->plen, msg->router_id, msg->seqno, msg->hop_count);
+ TRACE(D_PACKETS, "Handling seqno request for %N router-id %lR seqno %d hop count %d",
+ &msg->net, msg->router_id, msg->seqno, msg->hop_count);
/* Ignore if we have no such entry or entry has infinite metric */
- struct babel_entry *e = babel_find_entry(p, msg->prefix, msg->plen);
+ struct babel_entry *e = babel_find_entry(p, &msg->net);
if (!e || !e->selected_out || (e->selected_out->metric == BABEL_INFINITY))
return;
@@ -1491,14 +1504,26 @@ babel_add_iface(struct babel_proto *p, struct iface *new, struct babel_iface_con
add_tail(&p->interfaces, NODE ifa);
+ ip_addr addr4 = IPA_NONE;
struct ifa *addr;
WALK_LIST(addr, new->addrs)
+ {
if (ipa_is_link_local(addr->ip))
ifa->addr = addr->ip;
+ if (ipa_zero(addr4) && ipa_is_ip4(addr->ip))
+ addr4 = addr->ip;
+ }
+
+ ifa->next_hop_ip4 = ipa_nonzero(ic->next_hop_ip4) ? ic->next_hop_ip4 : addr4;
+ ifa->next_hop_ip6 = ipa_nonzero(ic->next_hop_ip6) ? ic->next_hop_ip6 : ifa->addr;
+
if (ipa_zero(ifa->addr))
log(L_WARN "%s: Cannot find link-local addr on %s", p->p.name, new->name);
+ if (ipa_zero(ifa->next_hop_ip4) && p->ip4_channel)
+ log(L_WARN "%s: Cannot find IPv4 next hop addr on %s", p->p.name, new->name);
+
init_list(&ifa->neigh_list);
ifa->hello_seqno = 1;
@@ -1590,6 +1615,26 @@ babel_reconfigure_iface(struct babel_proto *p, struct babel_iface *ifa, struct b
ifa->cf = new;
+ if (ipa_nonzero(new->next_hop_ip4))
+ ifa->next_hop_ip4 = new->next_hop_ip4;
+ else
+ {
+ ifa->next_hop_ip4 = IPA_NONE;
+
+ struct ifa *addr;
+ WALK_LIST(addr, ifa->iface->addrs)
+ if (ipa_is_ip4(addr->ip))
+ {
+ ifa->next_hop_ip4 = addr->ip;
+ break;
+ }
+ }
+
+ ifa->next_hop_ip6 = ipa_nonzero(new->next_hop_ip6) ? new->next_hop_ip6 : ifa->addr;
+
+ if (ipa_zero(ifa->next_hop_ip4) && p->ip4_channel)
+ log(L_WARN "%s: Cannot find IPv4 next hop addr on %s", p->p.name, ifa->ifname);
+
if (ifa->next_hello > (now + new->hello_interval))
ifa->next_hello = now + (random() % new->hello_interval) + 1;
@@ -1668,7 +1713,7 @@ babel_dump_entry(struct babel_entry *e)
struct babel_source *s;
struct babel_route *r;
- debug("Babel: Entry %I/%d:\n", e->n.prefix, e->n.pxlen);
+ debug("Babel: Entry %N:\n", e->n.addr);
WALK_LIST(s,e->sources)
{ debug(" "); babel_dump_source(s); }
@@ -1696,9 +1741,10 @@ babel_dump_iface(struct babel_iface *ifa)
{
struct babel_neighbor *n;
- debug("Babel: Interface %s addr %I rxcost %d type %d hello seqno %d intervals %d %d\n",
+ debug("Babel: Interface %s addr %I rxcost %d type %d hello seqno %d intervals %d %d",
ifa->ifname, ifa->addr, ifa->cf->rxcost, ifa->cf->type, ifa->hello_seqno,
ifa->cf->hello_interval, ifa->cf->update_interval);
+ debug(" next hop v4 %I next hop v6 %I\n", ifa->next_hop_ip4, ifa->next_hop_ip6);
WALK_LIST(n, ifa->neigh_list)
{ debug(" "); babel_dump_neighbor(n); }
@@ -1715,9 +1761,14 @@ babel_dump(struct proto *P)
WALK_LIST(ifa, p->interfaces)
babel_dump_iface(ifa);
- FIB_WALK(&p->rtable, n)
+ FIB_WALK(&p->ip4_rtable, struct babel_entry, e)
{
- babel_dump_entry((struct babel_entry *) n);
+ babel_dump_entry(e);
+ }
+ FIB_WALK_END;
+ FIB_WALK(&p->ip6_rtable, struct babel_entry, e)
+ {
+ babel_dump_entry(e);
}
FIB_WALK_END;
}
@@ -1765,8 +1816,9 @@ babel_show_interfaces(struct proto *P, char *iff)
}
cli_msg(-1023, "%s:", p->p.name);
- cli_msg(-1023, "%-10s %-6s %7s %6s %6s",
- "Interface", "State", "RX cost", "Nbrs", "Timer");
+ cli_msg(-1023, "%-10s %-6s %7s %6s %6s %-15s %s",
+ "Interface", "State", "RX cost", "Nbrs", "Timer",
+ "Next hop (v4)", "Next hop (v6)");
WALK_LIST(ifa, p->interfaces)
{
@@ -1778,8 +1830,10 @@ babel_show_interfaces(struct proto *P, char *iff)
nbrs++;
int timer = MIN(ifa->next_regular, ifa->next_hello) - now;
- cli_msg(-1023, "%-10s %-6s %7u %6u %6u",
- ifa->iface->name, (ifa->up ? "Up" : "Down"), ifa->cf->rxcost, nbrs, MAX(timer, 0));
+ cli_msg(-1023, "%-10s %-6s %7u %6u %6u %-15I %I",
+ ifa->iface->name, (ifa->up ? "Up" : "Down"),
+ ifa->cf->rxcost, nbrs, MAX(timer, 0),
+ ifa->next_hop_ip4, ifa->next_hop_ip6);
}
cli_msg(0, "");
@@ -1824,39 +1878,22 @@ babel_show_neighbors(struct proto *P, char *iff)
cli_msg(0, "");
}
-void
-babel_show_entries(struct proto *P)
+static void
+babel_show_entries_(struct babel_proto *p, struct fib *rtable)
{
- struct babel_proto *p = (void *) P;
- struct babel_entry *e = NULL;
struct babel_source *s = NULL;
struct babel_route *r = NULL;
- char ipbuf[STD_ADDRESS_P_LENGTH+5];
char ridbuf[ROUTER_ID_64_LENGTH+1];
- if (p->p.proto_state != PS_UP)
+ FIB_WALK(rtable, struct babel_entry, e)
{
- cli_msg(-1025, "%s: is not up", p->p.name);
- cli_msg(0, "");
- return;
- }
-
- cli_msg(-1025, "%s:", p->p.name);
- cli_msg(-1025, "%-29s %-23s %6s %5s %7s %7s",
- "Prefix", "Router ID", "Metric", "Seqno", "Expires", "Sources");
-
- FIB_WALK(&p->rtable, n)
- {
- e = (struct babel_entry *) n;
r = e->selected_in ? e->selected_in : e->selected_out;
int srcs = 0;
WALK_LIST(s, e->sources)
srcs++;
- bsprintf(ipbuf, "%I/%u", e->n.prefix, e->n.pxlen);
-
if (r)
{
if (r->router_id == p->router_id)
@@ -1865,15 +1902,35 @@ babel_show_entries(struct proto *P)
bsprintf(ridbuf, "%lR", r->router_id);
int time = r->expires ? r->expires - now : 0;
- cli_msg(-1025, "%-29s %-23s %6u %5u %7u %7u",
- ipbuf, ridbuf, r->metric, r->seqno, MAX(time, 0), srcs);
+ cli_msg(-1025, "%-29N %-23s %6u %5u %7u %7u",
+ e->n.addr, ridbuf, r->metric, r->seqno, MAX(time, 0), srcs);
}
else
{
- cli_msg(-1025, "%-29s %-44s %7u", ipbuf, "<pending>", srcs);
+ cli_msg(-1025, "%-29N %-44s %7u", e->n.addr, "<pending>", srcs);
}
}
FIB_WALK_END;
+}
+
+void
+babel_show_entries(struct proto *P)
+{
+ struct babel_proto *p = (void *) P;
+
+ if (p->p.proto_state != PS_UP)
+ {
+ cli_msg(-1025, "%s: is not up", p->p.name);
+ cli_msg(0, "");
+ return;
+ }
+
+ cli_msg(-1025, "%s:", p->p.name);
+ cli_msg(-1025, "%-29s %-23s %6s %5s %7s %7s",
+ "Prefix", "Router ID", "Metric", "Seqno", "Expires", "Sources");
+
+ babel_show_entries_(p, &p->ip4_rtable);
+ babel_show_entries_(p, &p->ip6_rtable);
cli_msg(0, "");
}
@@ -1964,7 +2021,7 @@ babel_store_tmp_attrs(struct rte *rt, struct ea_list *attrs)
* so store it into our data structures.
*/
static void
-babel_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *net,
+babel_rt_notify(struct proto *P, struct channel *c UNUSED, struct network *net,
struct rte *new, struct rte *old UNUSED, struct ea_list *attrs UNUSED)
{
struct babel_proto *p = (void *) P;
@@ -1974,7 +2031,7 @@ babel_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *ne
if (new)
{
/* Update */
- e = babel_get_entry(p, net->n.prefix, net->n.pxlen);
+ e = babel_get_entry(p, net->n.addr);
if (new->attrs->src->proto != P)
{
@@ -1996,7 +2053,7 @@ babel_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *ne
else
{
/* Withdraw */
- e = babel_find_entry(p, net->n.prefix, net->n.pxlen);
+ e = babel_find_entry(p, net->n.addr);
if (!e || !e->selected_out)
return;
@@ -2046,11 +2103,14 @@ babel_rte_same(struct rte *new, struct rte *old)
static struct proto *
-babel_init(struct proto_config *cfg)
+babel_init(struct proto_config *CF)
{
- struct proto *P = proto_new(cfg, sizeof(struct babel_proto));
+ struct proto *P = proto_new(CF);
+ struct babel_proto *p = (void *) P;
+
+ proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4));
+ proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6));
- P->accept_ra_types = RA_OPTIMAL;
P->if_notify = babel_if_notify;
P->rt_notify = babel_rt_notify;
P->import_control = babel_import_control;
@@ -2068,7 +2128,11 @@ babel_start(struct proto *P)
struct babel_proto *p = (void *) P;
struct babel_config *cf = (void *) P->cf;
- fib_init(&p->rtable, P->pool, sizeof(struct babel_entry), 0, babel_init_entry);
+ fib_init(&p->ip4_rtable, P->pool, NET_IP4, sizeof(struct babel_entry),
+ OFFSETOF(struct babel_entry, n), 0, babel_init_entry);
+ fib_init(&p->ip6_rtable, P->pool, NET_IP6, sizeof(struct babel_entry),
+ OFFSETOF(struct babel_entry, n), 0, babel_init_entry);
+
init_list(&p->interfaces);
p->timer = tm_new_set(P->pool, babel_timer, p, 0, 1);
tm_start(p->timer, 2);
@@ -2111,14 +2175,18 @@ babel_shutdown(struct proto *P)
}
static int
-babel_reconfigure(struct proto *P, struct proto_config *c)
+babel_reconfigure(struct proto *P, struct proto_config *CF)
{
struct babel_proto *p = (void *) P;
- struct babel_config *new = (void *) c;
+ struct babel_config *new = (void *) CF;
TRACE(D_EVENTS, "Reconfiguring");
- p->p.cf = c;
+ if (!proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4)) ||
+ !proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6)))
+ return 0;
+
+ p->p.cf = CF;
babel_reconfigure_ifaces(p, new);
babel_trigger_update(p);
@@ -2133,6 +2201,8 @@ struct protocol proto_babel = {
.template = "babel%d",
.attr_class = EAP_BABEL,
.preference = DEF_PREF_BABEL,
+ .channel_mask = NB_IP,
+ .proto_size = sizeof(struct babel_proto),
.config_size = sizeof(struct babel_config),
.init = babel_init,
.dump = babel_dump,
diff --git a/proto/babel/babel.h b/proto/babel/babel.h
index 6a95d82f..fccb60c9 100644
--- a/proto/babel/babel.h
+++ b/proto/babel/babel.h
@@ -21,11 +21,7 @@
#include "lib/lists.h"
#include "lib/socket.h"
#include "lib/string.h"
-#include "lib/timer.h"
-
-#ifndef IPV6
-#error "The Babel protocol only speaks IPv6"
-#endif
+#include "sysdep/unix/timer.h"
#define EA_BABEL_METRIC EA_CODE(EAP_BABEL, 0)
#define EA_BABEL_ROUTER_ID EA_CODE(EAP_BABEL, 1)
@@ -56,7 +52,7 @@
/* Max interval that will not overflow when carried as 16-bit centiseconds */
#define BABEL_MAX_INTERVAL (0xFFFF/BABEL_TIME_UNITS)
-#define BABEL_OVERHEAD (SIZE_OF_IP_HEADER+UDP_HEADER_LENGTH)
+#define BABEL_OVERHEAD (IP6_HEADER_LENGTH+UDP_HEADER_LENGTH)
#define BABEL_MIN_MTU (512 + BABEL_OVERHEAD)
@@ -82,6 +78,11 @@ enum babel_tlv_type {
BABEL_TLV_MAX
};
+enum babel_subtlv_type {
+ BABEL_SUBTLV_PAD1 = 0,
+ BABEL_SUBTLV_PADN = 1
+};
+
enum babel_iface_type {
/* In practice, UNDEF and WIRED give equivalent behaviour */
BABEL_IFACE_TYPE_UNDEF = 0,
@@ -120,12 +121,20 @@ struct babel_iface_config {
u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */
int tx_tos;
int tx_priority;
+
+ ip_addr next_hop_ip4;
+ ip_addr next_hop_ip6;
};
struct babel_proto {
struct proto p;
timer *timer;
- struct fib rtable;
+ struct fib ip4_rtable;
+ struct fib ip6_rtable;
+
+ struct channel *ip4_channel;
+ struct channel *ip6_channel;
+
list interfaces; /* Interfaces we really know about (struct babel_iface) */
u64 router_id;
u16 update_seqno; /* To be increased on request */
@@ -155,6 +164,8 @@ struct babel_iface {
char *ifname;
sock *sk;
ip_addr addr;
+ ip_addr next_hop_ip4;
+ ip_addr next_hop_ip6;
int tx_length;
list neigh_list; /* List of neighbors seen on this iface (struct babel_neighbor) */
list msg_queue;
@@ -212,7 +223,6 @@ struct babel_route {
};
struct babel_entry {
- struct fib_node n;
struct babel_proto *proto;
struct babel_route *selected_in;
struct babel_route *selected_out;
@@ -221,13 +231,14 @@ struct babel_entry {
list sources; /* Source entries for this prefix (struct babel_source). */
list routes; /* Routes for this prefix (struct babel_route) */
+
+ struct fib_node n;
};
/* Stores forwarded seqno requests for duplicate suppression. */
struct babel_seqno_request {
node n;
- ip_addr prefix;
- u8 plen;
+ net_addr net;
u64 router_id;
u16 seqno;
bird_clock_t updated;
@@ -269,12 +280,11 @@ struct babel_msg_ihu {
struct babel_msg_update {
u8 type;
u8 wildcard;
- u8 plen;
u16 interval;
u16 seqno;
u16 metric;
- ip_addr prefix;
u64 router_id;
+ net_addr net;
ip_addr next_hop;
ip_addr sender;
};
@@ -282,17 +292,15 @@ struct babel_msg_update {
struct babel_msg_route_request {
u8 type;
u8 full;
- u8 plen;
- ip_addr prefix;
+ net_addr net;
};
struct babel_msg_seqno_request {
u8 type;
- u8 plen;
- u16 seqno;
u8 hop_count;
+ u16 seqno;
u64 router_id;
- ip_addr prefix;
+ net_addr net;
ip_addr sender;
};
diff --git a/proto/babel/config.Y b/proto/babel/config.Y
index b6170852..93c92790 100644
--- a/proto/babel/config.Y
+++ b/proto/babel/config.Y
@@ -21,7 +21,8 @@ CF_DEFINES
CF_DECLS
CF_KEYWORDS(BABEL, METRIC, RXCOST, HELLO, UPDATE, INTERVAL, PORT, WIRED,
-WIRELESS, RX, TX, BUFFER, LENGTH, CHECK, LINK, BABEL_METRIC)
+ WIRELESS, RX, TX, BUFFER, LENGTH, CHECK, LINK, BABEL_METRIC, NEXT, HOP,
+ IPV4, IPV6)
CF_GRAMMAR
@@ -35,6 +36,7 @@ babel_proto_start: proto_start BABEL
babel_proto_item:
proto_item
+ | proto_channel
| INTERFACE babel_iface
;
@@ -96,6 +98,8 @@ babel_iface_item:
| TX tos { BABEL_IFACE->tx_tos = $2; }
| TX PRIORITY expr { BABEL_IFACE->tx_priority = $3; }
| CHECK LINK bool { BABEL_IFACE->check_link = $3; }
+ | NEXT HOP IPV4 ipa { BABEL_IFACE->next_hop_ip4 = $4; if (!ipa_is_ip4($4)) cf_error("Must be an IPv4 address"); }
+ | NEXT HOP IPV6 ipa { BABEL_IFACE->next_hop_ip6 = $4; if (!ipa_is_ip6($4)) cf_error("Must be an IPv6 address"); }
;
babel_iface_opts:
diff --git a/proto/babel/packets.c b/proto/babel/packets.c
index 08054832..78c133e0 100644
--- a/proto/babel/packets.c
+++ b/proto/babel/packets.c
@@ -112,13 +112,15 @@ struct babel_parse_state {
struct babel_proto *proto;
struct babel_iface *ifa;
ip_addr saddr;
- ip_addr next_hop;
+ ip_addr next_hop_ip4;
+ ip_addr next_hop_ip6;
u64 router_id; /* Router ID used in subsequent updates */
u8 def_ip6_prefix[16]; /* Implicit IPv6 prefix in network order */
u8 def_ip4_prefix[4]; /* Implicit IPv4 prefix in network order */
u8 router_id_seen; /* router_id field is valid */
u8 def_ip6_prefix_seen; /* def_ip6_prefix is valid */
u8 def_ip4_prefix_seen; /* def_ip4_prefix is valid */
+ u8 current_tlv_endpos; /* End of self-terminating TLVs (offset from start) */
};
enum parse_result {
@@ -130,7 +132,10 @@ enum parse_result {
struct babel_write_state {
u64 router_id;
u8 router_id_seen;
-// ip_addr next_hop;
+ ip_addr next_hop_ip4;
+ ip_addr next_hop_ip6;
+ u8 def_ip6_prefix[16]; /* Implicit IPv6 prefix in network order */
+ u8 def_ip6_pxlen;
};
@@ -146,7 +151,16 @@ struct babel_write_state {
#define TLV_HDR(tlv,t,l) ({ tlv->type = t; tlv->length = l - sizeof(struct babel_tlv); })
#define TLV_HDR0(tlv,t) TLV_HDR(tlv, t, tlv_data[t].min_length)
-#define BYTES(n) ((((uint) n) + 7) / 8)
+#define NET_SIZE(n) BYTES(net_pxlen(n))
+
+static inline uint
+bytes_equal(u8 *b1, u8 *b2, uint maxlen)
+{
+ uint i;
+ for (i = 0; (i < maxlen) && (*b1 == *b2); i++, b1++, b2++)
+ ;
+ return i;
+}
static inline u16
get_time16(const void *p)
@@ -161,19 +175,34 @@ put_time16(void *p, u16 v)
put_u16(p, v * BABEL_TIME_UNITS);
}
-static inline ip6_addr
-get_ip6_px(const void *p, uint plen)
+static inline void
+read_ip4_px(net_addr *n, const void *p, uint plen)
+{
+ ip4_addr addr = {0};
+ memcpy(&addr, p, BYTES(plen));
+ net_fill_ip4(n, ip4_ntoh(addr), plen);
+}
+
+static inline void
+put_ip4_px(void *p, net_addr *n)
+{
+ ip4_addr addr = ip4_hton(net4_prefix(n));
+ memcpy(p, &addr, NET_SIZE(n));
+}
+
+static inline void
+read_ip6_px(net_addr *n, const void *p, uint plen)
{
ip6_addr addr = IPA_NONE;
memcpy(&addr, p, BYTES(plen));
- return ip6_ntoh(addr);
+ net_fill_ip6(n, ip6_ntoh(addr), plen);
}
static inline void
-put_ip6_px(void *p, ip6_addr addr, uint plen)
+put_ip6_px(void *p, net_addr *n)
{
- addr = ip6_hton(addr);
- memcpy(p, &addr, BYTES(plen));
+ ip6_addr addr = ip6_hton(net6_prefix(n));
+ memcpy(p, &addr, NET_SIZE(n));
}
static inline ip6_addr
@@ -351,14 +380,33 @@ babel_read_ihu(struct babel_tlv *hdr, union babel_msg *m,
if (msg->ae >= BABEL_AE_MAX)
return PARSE_IGNORE;
- // We handle link-local IPs. In every other case, the addr field will be 0 but
- // validation will succeed. The handler takes care of these cases.
- if (msg->ae == BABEL_AE_IP6_LL)
+ /*
+ * We only actually read link-local IPs. In every other case, the addr field
+ * will be 0 but validation will succeed. The handler takes care of these
+ * cases. We handle them here anyway because we need the length for parsing
+ * subtlvs.
+ */
+ switch (msg->ae)
{
+ case BABEL_AE_IP4:
+ if (TLV_OPT_LENGTH(tlv) < 4)
+ return PARSE_ERROR;
+ state->current_tlv_endpos += 4;
+ break;
+
+ case BABEL_AE_IP6:
+ if (TLV_OPT_LENGTH(tlv) < 16)
+ return PARSE_ERROR;
+ state->current_tlv_endpos += 16;
+ break;
+
+ case BABEL_AE_IP6_LL:
if (TLV_OPT_LENGTH(tlv) < 8)
return PARSE_ERROR;
msg->addr = ipa_from_ip6(get_ip6_ll(&tlv->addr));
+ state->current_tlv_endpos += 8;
+ break;
}
return PARSE_SUCCESS;
@@ -431,21 +479,27 @@ babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED,
return PARSE_ERROR;
case BABEL_AE_IP4:
- /* TODO */
+ if (TLV_OPT_LENGTH(tlv) < sizeof(ip4_addr))
+ return PARSE_ERROR;
+
+ state->next_hop_ip4 = ipa_from_ip4(get_ip4(&tlv->addr));
+ state->current_tlv_endpos += sizeof(ip4_addr);
return PARSE_IGNORE;
case BABEL_AE_IP6:
if (TLV_OPT_LENGTH(tlv) < sizeof(ip6_addr))
return PARSE_ERROR;
- state->next_hop = ipa_from_ip6(get_ip6(&tlv->addr));
+ state->next_hop_ip6 = ipa_from_ip6(get_ip6(&tlv->addr));
+ state->current_tlv_endpos += sizeof(ip6_addr);
return PARSE_IGNORE;
case BABEL_AE_IP6_LL:
if (TLV_OPT_LENGTH(tlv) < 8)
return PARSE_ERROR;
- state->next_hop = ipa_from_ip6(get_ip6_ll(&tlv->addr));
+ state->next_hop_ip6 = ipa_from_ip6(get_ip6_ll(&tlv->addr));
+ state->current_tlv_endpos += 8;
return PARSE_IGNORE;
default:
@@ -455,6 +509,51 @@ babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED,
return PARSE_IGNORE;
}
+/* This is called directly from babel_write_update() and returns -1 if a next
+ hop should be written but there is not enough space. */
+static int
+babel_write_next_hop(struct babel_tlv *hdr, ip_addr addr,
+ struct babel_write_state *state, uint max_len)
+{
+ struct babel_tlv_next_hop *tlv = (void *) hdr;
+
+ if (ipa_zero(addr))
+ {
+ /* Should not happen */
+ return 0;
+ }
+ else if (ipa_is_ip4(addr) && !ipa_equal(addr, state->next_hop_ip4))
+ {
+ uint len = sizeof(struct babel_tlv_next_hop) + sizeof(ip4_addr);
+ if (len > max_len)
+ return -1;
+
+ TLV_HDR(tlv, BABEL_TLV_NEXT_HOP, len);
+
+ tlv->ae = BABEL_AE_IP4;
+ put_ip4(&tlv->addr, ipa_to_ip4(addr));
+ state->next_hop_ip4 = addr;
+
+ return len;
+ }
+ else if (ipa_is_ip6(addr) && !ipa_equal(addr, state->next_hop_ip6))
+ {
+ uint len = sizeof(struct babel_tlv_next_hop) + sizeof(ip6_addr);
+ if (len > max_len)
+ return -1;
+
+ TLV_HDR(tlv, BABEL_TLV_NEXT_HOP, len);
+
+ tlv->ae = BABEL_AE_IP6;
+ put_ip6(&tlv->addr, ipa_to_ip6(addr));
+ state->next_hop_ip6 = addr;
+
+ return len;
+ }
+
+ return 0;
+}
+
static int
babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
struct babel_parse_state *state)
@@ -480,15 +579,43 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
if (tlv->plen > 0)
return PARSE_ERROR;
+ if (msg->metric != 65535)
+ return PARSE_ERROR;
+
msg->wildcard = 1;
break;
case BABEL_AE_IP4:
- /* TODO */
- return PARSE_IGNORE;
+ if (tlv->plen > IP4_MAX_PREFIX_LENGTH)
+ return PARSE_ERROR;
+
+ /* Cannot omit data if there is no saved prefix */
+ if (tlv->omitted && !state->def_ip4_prefix_seen)
+ return PARSE_ERROR;
+
+ /* Need next hop for v4 routes */
+ if (ipa_zero(state->next_hop_ip4))
+ return PARSE_ERROR;
+
+ /* Merge saved prefix and received prefix parts */
+ memcpy(buf, state->def_ip4_prefix, tlv->omitted);
+ memcpy(buf + tlv->omitted, tlv->addr, len);
+
+ ip4_addr prefix4 = get_ip4(buf);
+ net_fill_ip4(&msg->net, prefix4, tlv->plen);
+
+ if (tlv->flags & BABEL_FLAG_DEF_PREFIX)
+ {
+ put_ip4(state->def_ip4_prefix, prefix4);
+ state->def_ip4_prefix_seen = 1;
+ }
+
+ msg->next_hop = state->next_hop_ip4;
+
+ break;
case BABEL_AE_IP6:
- if (tlv->plen > MAX_PREFIX_LENGTH)
+ if (tlv->plen > IP6_MAX_PREFIX_LENGTH)
return PARSE_ERROR;
/* Cannot omit data if there is no saved prefix */
@@ -499,20 +626,23 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
memcpy(buf, state->def_ip6_prefix, tlv->omitted);
memcpy(buf + tlv->omitted, tlv->addr, len);
- msg->plen = tlv->plen;
- msg->prefix = ipa_from_ip6(get_ip6(buf));
+ ip6_addr prefix6 = get_ip6(buf);
+ net_fill_ip6(&msg->net, prefix6, tlv->plen);
if (tlv->flags & BABEL_FLAG_DEF_PREFIX)
{
- put_ip6(state->def_ip6_prefix, msg->prefix);
+ put_ip6(state->def_ip6_prefix, prefix6);
state->def_ip6_prefix_seen = 1;
}
if (tlv->flags & BABEL_FLAG_ROUTER_ID)
{
- state->router_id = ((u64) _I2(msg->prefix)) << 32 | _I3(msg->prefix);
+ state->router_id = ((u64) _I2(prefix6)) << 32 | _I3(prefix6);
state->router_id_seen = 1;
}
+
+ msg->next_hop = state->next_hop_ip6;
+
break;
case BABEL_AE_IP6_LL:
@@ -531,8 +661,8 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
}
msg->router_id = state->router_id;
- msg->next_hop = state->next_hop;
msg->sender = state->saddr;
+ state->current_tlv_endpos += len;
return PARSE_SUCCESS;
}
@@ -541,7 +671,6 @@ static uint
babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
struct babel_write_state *state, uint max_len)
{
- struct babel_tlv_update *tlv = (void *) hdr;
struct babel_msg_update *msg = &m->update;
uint len0 = 0;
@@ -550,16 +679,35 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
* both of them. There is enough space for the Router-ID TLV, because
* sizeof(struct babel_tlv_router_id) == sizeof(struct babel_tlv_update).
*
- * Router ID is not used for retractions, so do not us it in such case.
+ * Router ID is not used for retractions, so do not use it in such case.
*/
if ((msg->metric < BABEL_INFINITY) &&
(!state->router_id_seen || (msg->router_id != state->router_id)))
{
len0 = babel_write_router_id(hdr, msg->router_id, state, max_len);
- tlv = (struct babel_tlv_update *) NEXT_TLV(tlv);
+ hdr = NEXT_TLV(hdr);
}
- uint len = sizeof(struct babel_tlv_update) + BYTES(msg->plen);
+ /*
+ * We also may add Next Hop TLV for regular updates. It may fail for not
+ * enough space or it may be unnecessary as the next hop is the same as the
+ * last one already announced. So we handle all three cases.
+ */
+ if (msg->metric < BABEL_INFINITY)
+ {
+ int l = babel_write_next_hop(hdr, msg->next_hop, state, max_len - len0);
+ if (l < 0)
+ return 0;
+
+ if (l)
+ {
+ len0 += l;
+ hdr = NEXT_TLV(hdr);
+ }
+ }
+
+ struct babel_tlv_update *tlv = (void *) hdr;
+ uint len = sizeof(struct babel_tlv_update) + NET_SIZE(&msg->net);
if (len0 + len > max_len)
return 0;
@@ -572,11 +720,39 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
tlv->ae = BABEL_AE_WILDCARD;
tlv->plen = 0;
}
+ else if (msg->net.type == NET_IP4)
+ {
+ tlv->ae = BABEL_AE_IP4;
+ tlv->plen = net4_pxlen(&msg->net);
+ put_ip4_px(tlv->addr, &msg->net);
+ }
else
{
tlv->ae = BABEL_AE_IP6;
- tlv->plen = msg->plen;
- put_ip6_px(tlv->addr, msg->prefix, msg->plen);
+ tlv->plen = net6_pxlen(&msg->net);
+
+ /* Address compression - omit initial matching bytes */
+ u8 buf[16], omit;
+ put_ip6(buf, net6_prefix(&msg->net));
+ omit = bytes_equal(buf, state->def_ip6_prefix,
+ MIN(tlv->plen, state->def_ip6_pxlen) / 8);
+
+ if (omit > 0)
+ {
+ memcpy(tlv->addr, buf + omit, NET_SIZE(&msg->net) - omit);
+
+ tlv->omitted = omit;
+ tlv->length -= omit;
+ len -= omit;
+ }
+ else
+ {
+ put_ip6_px(tlv->addr, &msg->net);
+ tlv->flags |= BABEL_FLAG_DEF_PREFIX;
+
+ put_ip6(state->def_ip6_prefix, net6_prefix(&msg->net));
+ state->def_ip6_pxlen = tlv->plen;
+ }
}
put_time16(&tlv->interval, msg->interval);
@@ -606,18 +782,25 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
return PARSE_SUCCESS;
case BABEL_AE_IP4:
- /* TODO */
- return PARSE_IGNORE;
+ if (tlv->plen > IP4_MAX_PREFIX_LENGTH)
+ return PARSE_ERROR;
+
+ if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen))
+ return PARSE_ERROR;
+
+ read_ip4_px(&msg->net, tlv->addr, tlv->plen);
+ state->current_tlv_endpos += BYTES(tlv->plen);
+ return PARSE_SUCCESS;
case BABEL_AE_IP6:
- if (tlv->plen > MAX_PREFIX_LENGTH)
+ if (tlv->plen > IP6_MAX_PREFIX_LENGTH)
return PARSE_ERROR;
if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen))
return PARSE_ERROR;
- msg->plen = tlv->plen;
- msg->prefix = get_ip6_px(tlv->addr, tlv->plen);
+ read_ip6_px(&msg->net, tlv->addr, tlv->plen);
+ state->current_tlv_endpos += BYTES(tlv->plen);
return PARSE_SUCCESS;
case BABEL_AE_IP6_LL:
@@ -637,7 +820,7 @@ babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m,
struct babel_tlv_route_request *tlv = (void *) hdr;
struct babel_msg_route_request *msg = &m->route_request;
- uint len = sizeof(struct babel_tlv_route_request) + BYTES(msg->plen);
+ uint len = sizeof(struct babel_tlv_route_request) + NET_SIZE(&msg->net);
if (len > max_len)
return 0;
@@ -649,11 +832,17 @@ babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m,
tlv->ae = BABEL_AE_WILDCARD;
tlv->plen = 0;
}
+ else if (msg->net.type == NET_IP4)
+ {
+ tlv->ae = BABEL_AE_IP4;
+ tlv->plen = net4_pxlen(&msg->net);
+ put_ip4_px(tlv->addr, &msg->net);
+ }
else
{
tlv->ae = BABEL_AE_IP6;
- tlv->plen = msg->plen;
- put_ip6_px(tlv->addr, msg->prefix, msg->plen);
+ tlv->plen = net6_pxlen(&msg->net);
+ put_ip6_px(tlv->addr, &msg->net);
}
return len;
@@ -681,18 +870,25 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
return PARSE_ERROR;
case BABEL_AE_IP4:
- /* TODO */
- return PARSE_IGNORE;
+ if (tlv->plen > IP4_MAX_PREFIX_LENGTH)
+ return PARSE_ERROR;
+
+ if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen))
+ return PARSE_ERROR;
+
+ read_ip4_px(&msg->net, tlv->addr, tlv->plen);
+ state->current_tlv_endpos += BYTES(tlv->plen);
+ return PARSE_SUCCESS;
case BABEL_AE_IP6:
- if (tlv->plen > MAX_PREFIX_LENGTH)
+ if (tlv->plen > IP6_MAX_PREFIX_LENGTH)
return PARSE_ERROR;
if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen))
return PARSE_ERROR;
- msg->plen = tlv->plen;
- msg->prefix = get_ip6_px(tlv->addr, tlv->plen);
+ read_ip6_px(&msg->net, tlv->addr, tlv->plen);
+ state->current_tlv_endpos += BYTES(tlv->plen);
return PARSE_SUCCESS;
case BABEL_AE_IP6_LL:
@@ -712,23 +908,70 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
struct babel_tlv_seqno_request *tlv = (void *) hdr;
struct babel_msg_seqno_request *msg = &m->seqno_request;
- uint len = sizeof(struct babel_tlv_seqno_request) + BYTES(msg->plen);
+ uint len = sizeof(struct babel_tlv_seqno_request) + NET_SIZE(&msg->net);
if (len > max_len)
return 0;
TLV_HDR(tlv, BABEL_TLV_SEQNO_REQUEST, len);
- tlv->ae = BABEL_AE_IP6;
- tlv->plen = msg->plen;
+
+ if (msg->net.type == NET_IP4)
+ {
+ tlv->ae = BABEL_AE_IP4;
+ tlv->plen = net4_pxlen(&msg->net);
+ put_ip4_px(tlv->addr, &msg->net);
+ }
+ else
+ {
+ tlv->ae = BABEL_AE_IP6;
+ tlv->plen = net6_pxlen(&msg->net);
+ put_ip6_px(tlv->addr, &msg->net);
+ }
+
put_u16(&tlv->seqno, msg->seqno);
tlv->hop_count = msg->hop_count;
put_u64(&tlv->router_id, msg->router_id);
- put_ip6_px(tlv->addr, msg->prefix, msg->plen);
return len;
}
static inline int
+babel_read_subtlvs(struct babel_tlv *hdr,
+ union babel_msg *msg UNUSED,
+ struct babel_parse_state *state)
+{
+ struct babel_tlv *tlv;
+
+ for (tlv = (void *) hdr + state->current_tlv_endpos;
+ (void *) tlv < (void *) hdr + TLV_LENGTH(hdr);
+ tlv = NEXT_TLV(tlv))
+ {
+ /*
+ * The subtlv type space is non-contiguous (due to the mandatory bit), so
+ * use a switch for dispatch instead of the mapping array we use for TLVs
+ */
+ switch (tlv->type)
+ {
+ case BABEL_SUBTLV_PAD1:
+ case BABEL_SUBTLV_PADN:
+ /* FIXME: Framing errors in PADN are silently ignored, see babel_process_packet() */
+ break;
+
+ default:
+ /* Unknown mandatory subtlv; PARSE_IGNORE ignores the whole TLV */
+ if (tlv->type > 128)
+ {
+ DBG("Babel: Mandatory subtlv %d found; skipping TLV\n", tlv->type);
+ return PARSE_IGNORE;
+ }
+ break;
+ }
+ }
+
+ return PARSE_SUCCESS;
+}
+
+static inline int
babel_read_tlv(struct babel_tlv *hdr,
union babel_msg *msg,
struct babel_parse_state *state)
@@ -741,8 +984,14 @@ babel_read_tlv(struct babel_tlv *hdr,
if (TLV_LENGTH(hdr) < tlv_data[hdr->type].min_length)
return PARSE_ERROR;
+ state->current_tlv_endpos = tlv_data[hdr->type].min_length;
memset(msg, 0, sizeof(*msg));
- return tlv_data[hdr->type].read_tlv(hdr, msg, state);
+
+ int res = tlv_data[hdr->type].read_tlv(hdr, msg, state);
+ if (res != PARSE_SUCCESS)
+ return res;
+
+ return babel_read_subtlvs(hdr, msg, state);
}
static uint
@@ -797,7 +1046,7 @@ static uint
babel_write_queue(struct babel_iface *ifa, list *queue)
{
struct babel_proto *p = ifa->proto;
- struct babel_write_state state = {};
+ struct babel_write_state state = { .next_hop_ip6 = ifa->addr };
if (EMPTY_LIST(*queue))
return 0;
@@ -933,10 +1182,10 @@ babel_process_packet(struct babel_pkt_header *pkt, int len,
byte *end = (byte *)pkt + plen;
struct babel_parse_state state = {
- .proto = p,
- .ifa = ifa,
- .saddr = saddr,
- .next_hop = saddr,
+ .proto = p,
+ .ifa = ifa,
+ .saddr = saddr,
+ .next_hop_ip6 = saddr,
};
if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION))