[PATCH v2 2/2] babel: Add source-specific routing support
Toke Høiland-Jørgensen
toke at toke.dk
Mon Feb 5 22:09:06 CET 2018
This adds support for source-specific routing to the babel protocol. It
changes the protocol to always use a NET_SADR_IP6 channel for IPv6
addresses, and just treats non-source-specific routes as source-specific
routes with sadr prefix 0. This means that almost all changes in this
patch is to the packet parsing and serialising code.
Signed-off-by: Toke Høiland-Jørgensen <toke at toke.dk>
---
proto/babel/babel.c | 20 +++----
proto/babel/babel.h | 14 ++++-
proto/babel/packets.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 175 insertions(+), 20 deletions(-)
diff --git a/proto/babel/babel.c b/proto/babel/babel.c
index aa7e8b68..5f02c3a2 100644
--- a/proto/babel/babel.c
+++ b/proto/babel/babel.c
@@ -1950,13 +1950,13 @@ babel_show_entries_(struct babel_proto *p UNUSED, struct fib *rtable)
srcs++;
if (e->valid)
- cli_msg(-1025, "%-24N %-23lR %6u %5u %7u %7u",
+ cli_msg(-1025, "%-50N %-23lR %6u %5u %7u %7u",
e->n.addr, e->router_id, e->metric, e->seqno, rts, srcs);
else if (r = e->selected)
- cli_msg(-1025, "%-24N %-23lR %6u %5u %7u %7u",
+ cli_msg(-1025, "%-50N %-23lR %6u %5u %7u %7u",
e->n.addr, r->router_id, r->metric, r->seqno, rts, srcs);
else
- cli_msg(-1025, "%-24N %-23s %6s %5s %7u %7u",
+ cli_msg(-1025, "%-50N %-23s %6s %5s %7u %7u",
e->n.addr, "<none>", "-", "-", rts, srcs);
}
FIB_WALK_END;
@@ -1975,7 +1975,7 @@ babel_show_entries(struct proto *P)
}
cli_msg(-1025, "%s:", p->p.name);
- cli_msg(-1025, "%-24s %-23s %6s %5s %7s %7s",
+ cli_msg(-1025, "%-50s %-23s %6s %5s %7s %7s",
"Prefix", "Router ID", "Metric", "Seqno", "Routes", "Sources");
babel_show_entries_(p, &p->ip4_rtable);
@@ -1994,7 +1994,7 @@ babel_show_routes_(struct babel_proto *p UNUSED, struct fib *rtable)
{
char c = (r == e->selected) ? '*' : (r->feasible ? '+' : ' ');
btime time = r->expires ? r->expires - current_time() : 0;
- cli_msg(-1025, "%-24N %-25I %-10s %5u %c %5u %7t",
+ cli_msg(-1025, "%-50N %-25I %-10s %5u %c %5u %7t",
e->n.addr, r->next_hop, r->neigh->ifa->ifname,
r->metric, c, r->seqno, MAX(time, 0));
}
@@ -2015,7 +2015,7 @@ babel_show_routes(struct proto *P)
}
cli_msg(-1025, "%s:", p->p.name);
- cli_msg(-1025, "%-24s %-25s %-9s %6s F %5s %7s",
+ cli_msg(-1025, "%-50s %-25s %-9s %6s F %5s %7s",
"Prefix", "Nexthop", "Interface", "Metric", "Seqno", "Expires");
babel_show_routes_(p, &p->ip4_rtable);
@@ -2189,7 +2189,7 @@ babel_init(struct proto_config *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));
+ proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6_SADR));
P->if_notify = babel_if_notify;
P->rt_notify = babel_rt_notify;
@@ -2210,7 +2210,7 @@ babel_start(struct proto *P)
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),
+ fib_init(&p->ip6_rtable, P->pool, NET_IP6_SADR, sizeof(struct babel_entry),
OFFSETOF(struct babel_entry, n), 0, babel_init_entry);
init_list(&p->interfaces);
@@ -2262,7 +2262,7 @@ babel_reconfigure(struct proto *P, struct proto_config *CF)
TRACE(D_EVENTS, "Reconfiguring");
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)))
+ !proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6_SADR)))
return 0;
p->p.cf = CF;
@@ -2280,7 +2280,7 @@ struct protocol proto_babel = {
.template = "babel%d",
.attr_class = EAP_BABEL,
.preference = DEF_PREF_BABEL,
- .channel_mask = NB_IP,
+ .channel_mask = (NB_IP4 | NB_IP6_SADR),
.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 1128d261..0902241a 100644
--- a/proto/babel/babel.h
+++ b/proto/babel/babel.h
@@ -85,7 +85,10 @@ enum babel_tlv_type {
enum babel_subtlv_type {
BABEL_SUBTLV_PAD1 = 0,
- BABEL_SUBTLV_PADN = 1
+ BABEL_SUBTLV_PADN = 1,
+
+ /* mandatory subtlvs */
+ BABEL_SUBTLV_SOURCE_PREFIX = 128,
};
enum babel_iface_type {
@@ -303,7 +306,10 @@ struct babel_msg_update {
u16 seqno;
u16 metric;
u64 router_id;
+ union {
net_addr net;
+ net_addr_ip6_sadr net_sadr;
+ };
ip_addr next_hop;
ip_addr sender;
};
@@ -311,7 +317,10 @@ struct babel_msg_update {
struct babel_msg_route_request {
u8 type;
u8 full;
+ union {
net_addr net;
+ net_addr_ip6_sadr net_sadr;
+ };
};
struct babel_msg_seqno_request {
@@ -319,7 +328,10 @@ struct babel_msg_seqno_request {
u8 hop_count;
u16 seqno;
u64 router_id;
+ union {
net_addr net;
+ net_addr_ip6_sadr net_sadr;
+ };
ip_addr sender;
};
diff --git a/proto/babel/packets.c b/proto/babel/packets.c
index dd86222a..2d78d4cb 100644
--- a/proto/babel/packets.c
+++ b/proto/babel/packets.c
@@ -105,6 +105,13 @@ struct babel_tlv_seqno_request {
u8 addr[0];
} PACKED;
+struct babel_subtlv_source_prefix {
+ u8 type;
+ u8 length;
+ u8 plen;
+ u8 addr[0];
+} PACKED;
+
/* Hello flags */
#define BABEL_HF_UNICAST 0x8000
@@ -201,7 +208,7 @@ read_ip6_px(net_addr *n, const void *p, uint plen)
{
ip6_addr addr = IPA_NONE;
memcpy(&addr, p, BYTES(plen));
- net_fill_ip6(n, ip6_ntoh(addr), plen);
+ net_fill_ip6_sadr(n, ip6_ntoh(addr), plen, IPA_NONE6, 0);
}
static inline void
@@ -237,6 +244,8 @@ static int babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *msg, stru
static int babel_read_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
static int babel_read_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
static int babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
+static int babel_read_source_prefix(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
+
static uint babel_write_ack(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
static uint babel_write_hello(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
@@ -244,6 +253,7 @@ static uint babel_write_ihu(struct babel_tlv *hdr, union babel_msg *msg, struct
static uint babel_write_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
static uint babel_write_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
static uint babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
+static int babel_write_source_prefix(struct babel_tlv *hdr, net_addr *net, uint max_len);
struct babel_tlv_data {
u8 min_length;
@@ -638,7 +648,7 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
memcpy(buf + tlv->omitted, tlv->addr, len);
ip6_addr prefix6 = get_ip6(buf);
- net_fill_ip6(&msg->net, prefix6, tlv->plen);
+ net_fill_ip6_sadr(&msg->net, prefix6, tlv->plen, IPA_NONE6, 0);
if (tlv->flags & BABEL_UF_DEF_PREFIX)
{
@@ -739,11 +749,13 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
}
else
{
+ u8 buf[16], omit;
+ int l;
+
tlv->ae = BABEL_AE_IP6;
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);
@@ -764,6 +776,12 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
put_ip6(state->def_ip6_prefix, net6_prefix(&msg->net));
state->def_ip6_pxlen = tlv->plen;
}
+
+ l = babel_write_source_prefix(hdr, &msg->net, max_len - len - len0);
+ if (l < 0)
+ return 0;
+
+ len += l;
}
put_time16(&tlv->interval, msg->interval);
@@ -851,9 +869,17 @@ babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m,
}
else
{
+ int l;
+
tlv->ae = BABEL_AE_IP6;
tlv->plen = net6_pxlen(&msg->net);
put_ip6_px(tlv->addr, &msg->net);
+
+ l = babel_write_source_prefix(hdr, &msg->net, max_len - len);
+ if (l < 0)
+ return 0;
+
+ len += l;
}
return len;
@@ -920,6 +946,7 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
struct babel_msg_seqno_request *msg = &m->seqno_request;
uint len = sizeof(struct babel_tlv_seqno_request) + NET_SIZE(&msg->net);
+ int l;
if (len > max_len)
return 0;
@@ -943,34 +970,150 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
tlv->hop_count = msg->hop_count;
put_u64(&tlv->router_id, msg->router_id);
+ l = babel_write_source_prefix(hdr, &msg->net, max_len - len);
+ if (l < 0)
+ return 0;
+
+ return len + l;
+}
+
+/* Add a subtlv to the tlv pointed to by header, with the specified subtlv type
+ and len. The length of the surrounding TLV is expanded.
+
+ Caller must ensure the buffer has enough space. */
+static struct babel_tlv *
+babel_add_subtlv(struct babel_tlv *hdr,
+ u8 type,
+ u8 len)
+{
+ struct babel_tlv *subtlv = (struct babel_tlv *) ((byte *) hdr + TLV_LENGTH(hdr));
+ hdr->length += len;
+ TLV_HDR(subtlv, type, len);
+ return subtlv;
+}
+
+static int
+babel_write_source_prefix(struct babel_tlv *hdr,
+ net_addr *net,
+ uint max_len)
+{
+ struct babel_subtlv_source_prefix *tlv;
+ struct net_addr_ip6_sadr *adr = (void *) net;
+ uint len;
+
+ if (!net_is_sadr_set(net))
+ return 0;
+
+ len = sizeof(*tlv) + BYTES(adr->src_pxlen);
+
+ if (len > max_len)
+ return -1;
+
+ tlv = (void *) babel_add_subtlv(hdr, BABEL_SUBTLV_SOURCE_PREFIX, len);
+ net_addr_ip6 sadr = NET_ADDR_IP6(adr->src_prefix, adr->src_pxlen);
+ tlv->plen = adr->src_pxlen;
+ put_ip6_px(tlv->addr, (void *) &sadr);
+
return len;
}
+static int
+babel_read_source_prefix(struct babel_tlv *hdr,
+ union babel_msg *msg,
+ struct babel_parse_state *state UNUSED)
+{
+ struct babel_subtlv_source_prefix *tlv = (void *) hdr;
+ struct net_addr_ip6_sadr *adr;
+ struct net_addr_ip6_sadr sadr;
+
+ if (tlv->length < BYTES(tlv->plen) + 1 ||
+ tlv->plen > IP6_MAX_PREFIX_LENGTH)
+ return PARSE_ERROR;
+
+ /* plen MUST NOT be 0 */
+ if (tlv->plen == 0)
+ return PARSE_IGNORE;
+
+ switch(msg->type) {
+ case BABEL_TLV_UPDATE:
+ /* wildcard updates with source prefix MUST be silently ignored */
+ if (msg->update.wildcard)
+ return PARSE_IGNORE;
+
+ adr = (void *) &msg->update.net;
+ break;
+
+ case BABEL_TLV_ROUTE_REQUEST:
+ /* wildcard requests with source addresses MUST be silently ignored */
+ if (msg->route_request.full)
+ return PARSE_IGNORE;
+
+ adr = (void *) &msg->route_request.net;
+ break;
+
+ case BABEL_TLV_SEQNO_REQUEST:
+ adr = (void *) &msg->seqno_request.net;
+ break;
+
+ default:
+ return PARSE_ERROR;
+ }
+
+ if (!net_is_sadr((net_addr *) adr))
+ return PARSE_ERROR;
+
+ /* Duplicate source prefix subtlv; SHOULD ignore TLV */
+ if (adr->src_pxlen > 0)
+ return PARSE_IGNORE;
+
+ /* read_ip6_px() reads a prefix into a net_addr_ip6_sadr struct, which in this
+ case is the sadr */
+ read_ip6_px((void *) &sadr, tlv->addr, tlv->plen);
+ adr->src_prefix = sadr.dst_prefix;
+ adr->src_pxlen = sadr.dst_pxlen;
+
+ return PARSE_SUCCESS;
+}
+
static inline int
babel_read_subtlvs(struct babel_tlv *hdr,
- union babel_msg *msg UNUSED,
+ union babel_msg *msg,
struct babel_parse_state *state)
{
struct babel_tlv *tlv;
+ byte *pos, *end = (byte *) hdr + TLV_LENGTH(hdr);
+ int res;
for (tlv = (void *) hdr + state->current_tlv_endpos;
- (void *) tlv < (void *) hdr + TLV_LENGTH(hdr);
+ (byte *) tlv < end;
tlv = NEXT_TLV(tlv))
{
+ if (tlv->type == BABEL_TLV_PAD1)
+ continue;
+
+ pos = (byte *)tlv + sizeof(struct babel_tlv);
+ if ((pos > end) || (pos + tlv->length > end))
+ {
+ DBG("Babel: subtlv framing error.\n");
+ return PARSE_ERROR;
+ }
+
/*
* 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() */
+ case BABEL_SUBTLV_SOURCE_PREFIX:
+ res = babel_read_source_prefix(tlv, msg, state);
+ if (res != PARSE_SUCCESS)
+ return res;
break;
+ case BABEL_SUBTLV_PADN:
default:
/* Unknown mandatory subtlv; PARSE_IGNORE ignores the whole TLV */
- if (tlv->type > 128)
+ if (tlv->type >= 128)
{
DBG("Babel: Mandatory subtlv %d found; skipping TLV\n", tlv->type);
return PARSE_IGNORE;
--
2.16.1
More information about the Bird-users
mailing list