From: Justin Iurman Date: Tue, 5 Oct 2021 15:10:19 +0000 (+0200) Subject: Add support for IOAM encap modes X-Git-Tag: v5.16.0~29^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8fb522cde3a88f2a48d1dd7afc730d3a757823b3;p=thirdparty%2Fiproute2.git Add support for IOAM encap modes This patch adds support for the three IOAM encap modes that were introduced: inline, encap and auto. Signed-off-by: Justin Iurman Signed-off-by: David Ahern --- diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index 218d50867..b05dffc69 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -210,16 +210,54 @@ static void print_encap_rpl(FILE *fp, struct rtattr *encap) print_rpl_srh(fp, srh); } +static const char *ioam6_mode_types[IOAM6_IPTUNNEL_MODE_MAX + 1] = { + [IOAM6_IPTUNNEL_MODE_INLINE] = "inline", + [IOAM6_IPTUNNEL_MODE_ENCAP] = "encap", + [IOAM6_IPTUNNEL_MODE_AUTO] = "auto", +}; + +static const char *format_ioam6mode_type(int mode) +{ + if (mode < IOAM6_IPTUNNEL_MODE_MIN || + mode > IOAM6_IPTUNNEL_MODE_MAX || + !ioam6_mode_types[mode]) + return ""; + + return ioam6_mode_types[mode]; +} + +static __u8 read_ioam6mode_type(const char *mode) +{ + __u8 i; + + for (i = IOAM6_IPTUNNEL_MODE_MIN; i <= IOAM6_IPTUNNEL_MODE_MAX; i++) { + if (ioam6_mode_types[i] && !strcmp(mode, ioam6_mode_types[i])) + return i; + } + + return 0; +} + static void print_encap_ioam6(FILE *fp, struct rtattr *encap) { struct rtattr *tb[IOAM6_IPTUNNEL_MAX + 1]; struct ioam6_trace_hdr *trace; + __u8 mode; parse_rtattr_nested(tb, IOAM6_IPTUNNEL_MAX, encap); + if (!tb[IOAM6_IPTUNNEL_MODE] || !tb[IOAM6_IPTUNNEL_TRACE]) + return; - if (!tb[IOAM6_IPTUNNEL_TRACE]) + mode = rta_getattr_u8(tb[IOAM6_IPTUNNEL_MODE]); + if (!tb[IOAM6_IPTUNNEL_DST] && mode != IOAM6_IPTUNNEL_MODE_INLINE) return; + print_string(PRINT_ANY, "mode", "mode %s ", format_ioam6mode_type(mode)); + + if (mode != IOAM6_IPTUNNEL_MODE_INLINE) + print_string(PRINT_ANY, "tundst", "tundst %s ", + rt_addr_n2a_rta(AF_INET6, tb[IOAM6_IPTUNNEL_DST])); + trace = RTA_DATA(tb[IOAM6_IPTUNNEL_TRACE]); print_null(PRINT_ANY, "trace", "trace ", NULL); @@ -884,23 +922,48 @@ out: static int parse_encap_ioam6(struct rtattr *rta, size_t len, int *argcp, char ***argvp) { + int ns_found = 0, argc = *argcp; + __u16 trace_ns, trace_size = 0; struct ioam6_trace_hdr *trace; char **argv = *argvp; - int argc = *argcp; - int ns_found = 0; - __u16 size = 0; - __u32 type = 0; - __u16 ns; + __u32 trace_type = 0; + inet_prefix addr; + __u8 mode; - trace = calloc(1, sizeof(*trace)); - if (!trace) - return -1; + if (strcmp(*argv, "mode") != 0) { + mode = IOAM6_IPTUNNEL_MODE_INLINE; + } else { + NEXT_ARG(); - if (strcmp(*argv, "trace")) + mode = read_ioam6mode_type(*argv); + if (!mode) + invarg("Invalid mode", *argv); + + NEXT_ARG(); + } + + if (strcmp(*argv, "tundst") != 0) { + if (mode != IOAM6_IPTUNNEL_MODE_INLINE) + missarg("tundst"); + } else { + if (mode == IOAM6_IPTUNNEL_MODE_INLINE) + invarg("Inline mode does not need tundst", *argv); + + NEXT_ARG(); + + get_addr(&addr, *argv, AF_INET6); + if (addr.family != AF_INET6 || addr.bytelen != 16) + invarg("Invalid IPv6 address for tundst", *argv); + + NEXT_ARG(); + } + + if (strcmp(*argv, "trace") != 0) missarg("trace"); NEXT_ARG(); - if (strcmp(*argv, "prealloc")) + + if (strcmp(*argv, "prealloc") != 0) missarg("prealloc"); while (NEXT_ARG_OK()) { @@ -909,63 +972,58 @@ static int parse_encap_ioam6(struct rtattr *rta, size_t len, int *argcp, if (strcmp(*argv, "type") == 0) { NEXT_ARG(); - if (type) + if (trace_type) duparg2("type", *argv); - if (get_u32(&type, *argv, 0) || !type) - invarg("Invalid type", *argv); - - trace->type_be32 = htonl(type << 8); - + if (get_u32(&trace_type, *argv, 0) || !trace_type) + invarg("Invalid trace type", *argv); } else if (strcmp(*argv, "ns") == 0) { NEXT_ARG(); if (ns_found++) duparg2("ns", *argv); - if (!type) - missarg("type"); - - if (get_u16(&ns, *argv, 0)) + if (get_u16(&trace_ns, *argv, 0)) invarg("Invalid namespace ID", *argv); - - trace->namespace_id = htons(ns); - } else if (strcmp(*argv, "size") == 0) { NEXT_ARG(); - if (size) + if (trace_size) duparg2("size", *argv); - if (!type) - missarg("type"); - if (!ns_found) - missarg("ns"); + if (get_u16(&trace_size, *argv, 0) || !trace_size) + invarg("Invalid trace size", *argv); - if (get_u16(&size, *argv, 0) || !size) - invarg("Invalid size", *argv); - - if (size % 4) - invarg("Size must be a 4-octet multiple", *argv); - if (size > IOAM6_TRACE_DATA_SIZE_MAX) - invarg("Size too big", *argv); - - trace->remlen = (__u8)(size / 4); + if (trace_size % 4) + invarg("Trace size must be a 4-octet multiple", + *argv); + if (trace_size > IOAM6_TRACE_DATA_SIZE_MAX) + invarg("Trace size is too big", *argv); } else { break; } } - if (!type) + if (!trace_type) missarg("type"); if (!ns_found) missarg("ns"); - if (!size) + if (!trace_size) missarg("size"); - if (rta_addattr_l(rta, len, IOAM6_IPTUNNEL_TRACE, trace, - sizeof(*trace))) { + trace = calloc(1, sizeof(*trace)); + if (!trace) + return -1; + + trace->type_be32 = htonl(trace_type << 8); + trace->namespace_id = htons(trace_ns); + trace->remlen = (__u8)(trace_size / 4); + + if (rta_addattr8(rta, len, IOAM6_IPTUNNEL_MODE, mode) || + (mode != IOAM6_IPTUNNEL_MODE_INLINE && + rta_addattr_l(rta, len, IOAM6_IPTUNNEL_DST, &addr.data, addr.bytelen)) || + rta_addattr_l(rta, len, IOAM6_IPTUNNEL_TRACE, trace, sizeof(*trace))) { free(trace); return -1; }