summaryrefslogtreecommitdiff
path: root/proto/babel
diff options
context:
space:
mode:
Diffstat (limited to 'proto/babel')
-rw-r--r--proto/babel/babel.c156
-rw-r--r--proto/babel/babel.h12
-rw-r--r--proto/babel/config.Y6
-rw-r--r--proto/babel/packets.c199
4 files changed, 307 insertions, 66 deletions
diff --git a/proto/babel/babel.c b/proto/babel/babel.c
index 1b1d9f62..67a59df6 100644
--- a/proto/babel/babel.c
+++ b/proto/babel/babel.c
@@ -78,13 +78,15 @@ babel_init_entry(void *E)
static inline struct babel_entry *
babel_find_entry(struct babel_proto *p, const net_addr *n)
{
- return fib_find(&p->rtable, n);
+ 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, const net_addr *n)
{
- struct babel_entry *e = fib_get(&p->rtable, n);
+ 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;
}
@@ -224,15 +226,15 @@ 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_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, struct babel_entry, e)
+ FIB_ITERATE_START(rtable, &fit, struct babel_entry, e)
{
int changed = 0;
@@ -253,7 +255,7 @@ 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);
@@ -267,13 +269,20 @@ loop:
if (EMPTY_LIST(e->sources) && EMPTY_LIST(e->routes))
{
FIB_ITERATE_PUT(&fit);
- fib_delete(&p->rtable, e);
+ fib_delete(rtable, e);
goto loop;
}
}
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 *
babel_find_neighbor(struct babel_iface *ifa, ip_addr addr)
{
@@ -468,6 +477,7 @@ 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)
{
@@ -490,12 +500,12 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
rte->u.babel.router_id = r->router_id;
rte->pflags = 0;
- rte_update(&p->p, e->n.addr, rte);
+ rte_update2(c, e->n.addr, rte, p->p.main_source);
}
else
{
/* Retraction */
- rte_update(&p->p, e->n.addr, NULL);
+ rte_update2(c, e->n.addr, NULL, p->p.main_source);
}
}
@@ -740,11 +750,11 @@ 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, struct babel_entry, e)
+ FIB_WALK(rtable, struct babel_entry, e)
{
struct babel_route *r = e->selected_out;
@@ -774,6 +784,9 @@ babel_send_update(struct babel_iface *ifa, bird_clock_t changed)
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);
/* Update feasibility distance for redistributed routes */
@@ -794,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;
@@ -1073,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:
*
@@ -1475,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;
@@ -1574,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;
@@ -1680,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); }
@@ -1699,7 +1761,12 @@ babel_dump(struct proto *P)
WALK_LIST(ifa, p->interfaces)
babel_dump_iface(ifa);
- FIB_WALK(&p->rtable, struct babel_entry, e)
+ FIB_WALK(&p->ip4_rtable, struct babel_entry, e)
+ {
+ babel_dump_entry(e);
+ }
+ FIB_WALK_END;
+ FIB_WALK(&p->ip6_rtable, struct babel_entry, e)
{
babel_dump_entry(e);
}
@@ -1749,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)
{
@@ -1762,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, "");
@@ -1808,27 +1878,15 @@ 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_source *s = NULL;
struct babel_route *r = NULL;
char ridbuf[ROUTER_ID_64_LENGTH+1];
- 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");
-
- FIB_WALK(&p->rtable, struct babel_entry, e)
+ FIB_WALK(rtable, struct babel_entry, e)
{
r = e->selected_in ? e->selected_in : e->selected_out;
@@ -1853,6 +1911,26 @@ babel_show_entries(struct proto *P)
}
}
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, "");
}
@@ -2028,8 +2106,10 @@ static struct proto *
babel_init(struct proto_config *CF)
{
struct proto *P = proto_new(CF);
+ struct babel_proto *p = (void *) P;
- P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
+ 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->if_notify = babel_if_notify;
P->rt_notify = babel_rt_notify;
@@ -2048,8 +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, NET_IP6, sizeof(struct babel_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);
@@ -2099,7 +2182,8 @@ babel_reconfigure(struct proto *P, struct proto_config *CF)
TRACE(D_EVENTS, "Reconfiguring");
- if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
+ 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;
@@ -2117,7 +2201,7 @@ struct protocol proto_babel = {
.template = "babel%d",
.attr_class = EAP_BABEL,
.preference = DEF_PREF_BABEL,
- .channel_mask = NB_IP6,
+ .channel_mask = NB_IP,
.proto_size = sizeof(struct babel_proto),
.config_size = sizeof(struct babel_config),
.init = babel_init,
diff --git a/proto/babel/babel.h b/proto/babel/babel.h
index 792c9d60..26f52455 100644
--- a/proto/babel/babel.h
+++ b/proto/babel/babel.h
@@ -116,12 +116,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 */
@@ -151,6 +159,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;
diff --git a/proto/babel/config.Y b/proto/babel/config.Y
index cf8983fa..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
@@ -30,7 +31,6 @@ CF_ADDTO(proto, babel_proto)
babel_proto_start: proto_start BABEL
{
this_proto = proto_config_new(&proto_babel, $1);
- this_proto->net_type = NET_IP6;
init_list(&BABEL_CFG->iface_list);
};
@@ -98,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 70cfc196..b52c2ddf 100644
--- a/proto/babel/packets.c
+++ b/proto/babel/packets.c
@@ -112,7 +112,8 @@ 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 */
@@ -130,7 +131,8 @@ 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;
};
@@ -163,6 +165,21 @@ put_time16(void *p, u16 v)
}
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;
@@ -432,21 +449,24 @@ 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));
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));
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));
return PARSE_IGNORE;
default:
@@ -456,6 +476,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)
@@ -488,8 +553,33 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
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 > IP6_MAX_PREFIX_LENGTH)
@@ -503,20 +593,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);
- ip6_addr prefix = get_ip6(buf);
- net_fill_ip6(&msg->net, prefix, tlv->plen);
+ 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, 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(prefix)) << 32 | _I3(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:
@@ -535,7 +628,6 @@ 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;
return PARSE_SUCCESS;
@@ -545,7 +637,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;
@@ -554,15 +645,34 @@ 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);
}
+ /*
+ * 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)
@@ -576,6 +686,12 @@ 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;
@@ -610,8 +726,14 @@ 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);
+ return PARSE_SUCCESS;
case BABEL_AE_IP6:
if (tlv->plen > IP6_MAX_PREFIX_LENGTH)
@@ -652,6 +774,12 @@ 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;
@@ -684,8 +812,14 @@ 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);
+ return PARSE_SUCCESS;
case BABEL_AE_IP6:
if (tlv->plen > IP6_MAX_PREFIX_LENGTH)
@@ -720,12 +854,23 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
return 0;
TLV_HDR(tlv, BABEL_TLV_SEQNO_REQUEST, len);
- tlv->ae = BABEL_AE_IP6;
- tlv->plen = net6_pxlen(&msg->net);
+
+ 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->net);
return len;
}
@@ -799,7 +944,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;
@@ -935,10 +1080,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))