[PATCH 0/3] babel: Add compression and support for subtlvs
This patch series adds compression of outgoing IPv6 prefixes to the Babel protocol, and also adds support to the parser for parsing subtlvs as per RFC6126 bis (see https://tools.ietf.org/html/draft-ietf-babel-rfc6126bis-02#section-4.4). These patches apply to 2.0.0-pre1, and on top of the previously posted patch that adds dualstack support to Babel. I'll roll that up into this series as well once the patches have been reviewed. Toke Høiland-Jørgensen (3): lib: Add ip6_common_octets function babel: Implement IPv6 prefix compression on outgoing updates babel: Parse subtlvs and skip TLVs with a mandatory subtlv lib/ip.c | 14 +++++++ lib/ip.h | 1 + proto/babel/babel.h | 5 +++ proto/babel/packets.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 119 insertions(+), 5 deletions(-) -- 2.13.0
RFC6126bis formally introduces subtlvs to the Babel protocol, including mandatory subtlvs. This adds support for parsing subtlvs to the Babel protocol and skips TLVs that contain mandatory subtlvs, as per the spec. For details, see section 4.4 of https://tools.ietf.org/html/draft-ietf-babel-rfc6126bis-02 Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk> --- proto/babel/babel.h | 5 ++++ proto/babel/packets.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 79 insertions(+), 4 deletions(-) diff --git a/proto/babel/babel.h b/proto/babel/babel.h index 236c1a3b..b6332446 100644 --- a/proto/babel/babel.h +++ b/proto/babel/babel.h @@ -78,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, diff --git a/proto/babel/packets.c b/proto/babel/packets.c index da7d8a50..4c0d88df 100644 --- a/proto/babel/packets.c +++ b/proto/babel/packets.c @@ -120,6 +120,7 @@ struct babel_parse_state { 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 { @@ -370,14 +371,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; @@ -454,6 +474,7 @@ babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED, return PARSE_ERROR; state->next_hop_v4 = ipa_from_ip4(get_ip4(&tlv->addr)); + state->current_tlv_endpos += sizeof(ip4_addr); return PARSE_IGNORE; case BABEL_AE_IP6: @@ -461,6 +482,7 @@ babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED, return PARSE_ERROR; state->next_hop_v6 = ipa_from_ip6(get_ip6(&tlv->addr)); + state->current_tlv_endpos += sizeof(ip6_addr); return PARSE_IGNORE; case BABEL_AE_IP6_LL: @@ -468,6 +490,7 @@ babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED, return PARSE_ERROR; state->next_hop_v6 = ipa_from_ip6(get_ip6_ll(&tlv->addr)); + state->current_tlv_endpos += 8; return PARSE_IGNORE; default: @@ -626,6 +649,7 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m, msg->router_id = state->router_id; msg->sender = state->saddr; + state->current_tlv_endpos += len; return PARSE_SUCCESS; } @@ -745,6 +769,7 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m, 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: @@ -755,6 +780,7 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m, return PARSE_ERROR; read_ip6_px(&msg->net, tlv->addr, tlv->plen); + state->current_tlv_endpos += BYTES(tlv->plen); return PARSE_SUCCESS; case BABEL_AE_IP6_LL: @@ -831,6 +857,7 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m, 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: @@ -841,6 +868,7 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m, return PARSE_ERROR; read_ip6_px(&msg->net, tlv->addr, tlv->plen); + state->current_tlv_endpos += BYTES(tlv->plen); return PARSE_SUCCESS; case BABEL_AE_IP6_LL: @@ -886,10 +914,45 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m, } static inline int +babel_read_subtlvs(struct babel_tlv *hdr, + union babel_msg *msg UNUSED, + struct babel_parse_state *state) +{ + struct babel_tlv *subtlv; + + for (subtlv = (void *) hdr + state->current_tlv_endpos; + subtlv < hdr + TLV_LENGTH(hdr); + subtlv = NEXT_TLV(subtlv)) + { + /* + * 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 (subtlv->type) + { + case BABEL_SUBTLV_PAD1: + case BABEL_SUBTLV_PADN: + break; + default: + /* unknown mandatory subtlv; PARSE_IGNORE ignores the whole TLV */ + if (subtlv->type > 128) + { + DBG("babel: Mandatory subtlv %d found; skipping TLV\n", subtlv->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) { + int res; if ((hdr->type <= BABEL_TLV_PADN) || (hdr->type >= BABEL_TLV_MAX) || !tlv_data[hdr->type].read_tlv) @@ -898,8 +961,15 @@ 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); + 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 -- 2.13.0
On Mon, Jun 05, 2017 at 11:49:54PM +0200, Toke Høiland-Jørgensen wrote:
RFC6126bis formally introduces subtlvs to the Babel protocol, including mandatory subtlvs. This adds support for parsing subtlvs to the Babel protocol and skips TLVs that contain mandatory subtlvs, as per the spec.
Thanks, merged.
static inline int +babel_read_subtlvs(struct babel_tlv *hdr, + union babel_msg *msg UNUSED, + struct babel_parse_state *state) +{ + struct babel_tlv *subtlv; + + for (subtlv = (void *) hdr + state->current_tlv_endpos; + subtlv < hdr + TLV_LENGTH(hdr); + subtlv = NEXT_TLV(subtlv)) + { + /* + * 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 (subtlv->type) + { + case BABEL_SUBTLV_PAD1: + case BABEL_SUBTLV_PADN: + break;
Note that it ignores framing errors in BABEL_SUBTLV_PADN. Not a big problem, i kept that, but we should fix it when adding some more sub-TLV support. -- Elen sila lumenn' omentielvo Ondrej 'Santiago' Zajicek (email: santiago@crfreenet.org) OpenPGP encrypted e-mails preferred (KeyID 0x11DEADC3, wwwkeys.pgp.net) "To err is human -- to blame it on a computer is even more so."
On Mon, Jun 05, 2017 at 11:49:51PM +0200, Toke Høiland-Jørgensen wrote:
This patch series adds compression of outgoing IPv6 prefixes to the Babel protocol, and also adds support to the parser for parsing subtlvs as per RFC6126 bis (see https://tools.ietf.org/html/draft-ietf-babel-rfc6126bis-02#section-4.4).
Hi The subtlv parser looks OK. W.r.t. prefix compression i would prefer if it would be done in the same manner as in the other direction (parsing), i.e. having u8 def_ip6_prefix[16] in network order in babel_write_state and using a memcmp()-like function that returns first differing byte instead of using ip6_common_octets(). + omit = MIN(omit, + MIN(tlv->plen, net6_pxlen(&state->def_ip6_prefix)) / 8); Note that MIN() is a macro that expands its arguments two times, so it is not a good idea to nest them. -- Elen sila lumenn' omentielvo Ondrej 'Santiago' Zajicek (email: santiago@crfreenet.org) OpenPGP encrypted e-mails preferred (KeyID 0x11DEADC3, wwwkeys.pgp.net) "To err is human -- to blame it on a computer is even more so."
participants (2)
-
Ondrej Zajicek -
Toke Høiland-Jørgensen