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 <[email protected]> --- 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
