diff options
Diffstat (limited to 'proto/babel')
-rw-r--r-- | proto/babel/Makefile | 9 | ||||
-rw-r--r-- | proto/babel/babel.c | 334 | ||||
-rw-r--r-- | proto/babel/babel.h | 42 | ||||
-rw-r--r-- | proto/babel/config.Y | 6 | ||||
-rw-r--r-- | proto/babel/packets.c | 353 |
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)) |