From: Justin Iurman Date: Sun, 1 Aug 2021 12:45:51 +0000 (+0200) Subject: New IOAM6 encap type for routes X-Git-Tag: v5.15.0~25 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2d83c71082460ed3490db32f200959bb76df5bd2;p=thirdparty%2Fiproute2.git New IOAM6 encap type for routes This patch provides a new encap type for routes to insert an IOAM pre-allocated trace: $ ip -6 ro ad fc00::1/128 encap ioam6 trace prealloc type 0x800000 ns 1 size 12 dev eth0 where: - "trace" and "prealloc" may appear as useless but just anticipate for future implementations of other ioam option types. - "type" is a bitfield (=u32) defining the IOAM pre-allocated trace type (see the corresponding uapi). - "ns" is an IOAM namespace ID attached to the pre-allocated trace. - "size" is the trace pre-allocated size in bytes; must be a 4-octet multiple; limited size (see IOAM6_TRACE_DATA_SIZE_MAX). Signed-off-by: Justin Iurman Signed-off-by: David Ahern --- diff --git a/ip/iproute.c b/ip/iproute.c index 1ccf51a56..1e5e2002d 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -101,8 +101,8 @@ static void usage(void) "TIME := NUMBER[s|ms]\n" "BOOL := [1|0]\n" "FEATURES := ecn\n" - "ENCAPTYPE := [ mpls | ip | ip6 | seg6 | seg6local | rpl ]\n" - "ENCAPHDR := [ MPLSLABEL | SEG6HDR | SEG6LOCAL ]\n" + "ENCAPTYPE := [ mpls | ip | ip6 | seg6 | seg6local | rpl | ioam6 ]\n" + "ENCAPHDR := [ MPLSLABEL | SEG6HDR | SEG6LOCAL | IOAM6HDR ]\n" "SEG6HDR := [ mode SEGMODE ] segs ADDR1,ADDRi,ADDRn [hmac HMACKEYID] [cleanup]\n" "SEGMODE := [ encap | inline ]\n" "SEG6LOCAL := action ACTION [ OPTIONS ] [ count ]\n" @@ -112,6 +112,7 @@ static void usage(void) "OPTIONS := OPTION [ OPTIONS ]\n" "OPTION := { srh SEG6HDR | nh4 ADDR | nh6 ADDR | iif DEV | oif DEV |\n" " table TABLEID | vrftable TABLEID | endpoint PROGNAME }\n" + "IOAM6HDR := trace prealloc type IOAM6_TRACE_TYPE ns IOAM6_NAMESPACE size IOAM6_TRACE_SIZE\n" "ROUTE_GET_FLAGS := [ fibmatch ]\n"); exit(-1); } diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index c4bae68d6..218d50867 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include static const char *format_encap_type(int type) { @@ -54,6 +56,8 @@ static const char *format_encap_type(int type) return "seg6local"; case LWTUNNEL_ENCAP_RPL: return "rpl"; + case LWTUNNEL_ENCAP_IOAM6: + return "ioam6"; default: return "unknown"; } @@ -90,6 +94,8 @@ static int read_encap_type(const char *name) return LWTUNNEL_ENCAP_SEG6_LOCAL; else if (strcmp(name, "rpl") == 0) return LWTUNNEL_ENCAP_RPL; + else if (strcmp(name, "ioam6") == 0) + return LWTUNNEL_ENCAP_IOAM6; else if (strcmp(name, "help") == 0) encap_type_usage(); @@ -204,6 +210,25 @@ static void print_encap_rpl(FILE *fp, struct rtattr *encap) print_rpl_srh(fp, srh); } +static void print_encap_ioam6(FILE *fp, struct rtattr *encap) +{ + struct rtattr *tb[IOAM6_IPTUNNEL_MAX + 1]; + struct ioam6_trace_hdr *trace; + + parse_rtattr_nested(tb, IOAM6_IPTUNNEL_MAX, encap); + + if (!tb[IOAM6_IPTUNNEL_TRACE]) + return; + + trace = RTA_DATA(tb[IOAM6_IPTUNNEL_TRACE]); + + print_null(PRINT_ANY, "trace", "trace ", NULL); + print_null(PRINT_ANY, "prealloc", "prealloc ", NULL); + print_hex(PRINT_ANY, "type", "type %#08x ", ntohl(trace->type_be32) >> 8); + print_uint(PRINT_ANY, "ns", "ns %u ", ntohs(trace->namespace_id)); + print_uint(PRINT_ANY, "size", "size %u ", trace->remlen * 4); +} + static const char *seg6_action_names[SEG6_LOCAL_ACTION_MAX + 1] = { [SEG6_LOCAL_ACTION_END] = "End", [SEG6_LOCAL_ACTION_END_X] = "End.X", @@ -657,6 +682,9 @@ void lwt_print_encap(FILE *fp, struct rtattr *encap_type, case LWTUNNEL_ENCAP_RPL: print_encap_rpl(fp, encap); break; + case LWTUNNEL_ENCAP_IOAM6: + print_encap_ioam6(fp, encap); + break; } } @@ -853,6 +881,102 @@ out: return ret; } +static int parse_encap_ioam6(struct rtattr *rta, size_t len, int *argcp, + char ***argvp) +{ + struct ioam6_trace_hdr *trace; + char **argv = *argvp; + int argc = *argcp; + int ns_found = 0; + __u16 size = 0; + __u32 type = 0; + __u16 ns; + + trace = calloc(1, sizeof(*trace)); + if (!trace) + return -1; + + if (strcmp(*argv, "trace")) + missarg("trace"); + + NEXT_ARG(); + if (strcmp(*argv, "prealloc")) + missarg("prealloc"); + + while (NEXT_ARG_OK()) { + NEXT_ARG_FWD(); + + if (strcmp(*argv, "type") == 0) { + NEXT_ARG(); + + if (type) + duparg2("type", *argv); + + if (get_u32(&type, *argv, 0) || !type) + invarg("Invalid type", *argv); + + trace->type_be32 = htonl(type << 8); + + } else if (strcmp(*argv, "ns") == 0) { + NEXT_ARG(); + + if (ns_found++) + duparg2("ns", *argv); + + if (!type) + missarg("type"); + + if (get_u16(&ns, *argv, 0)) + invarg("Invalid namespace ID", *argv); + + trace->namespace_id = htons(ns); + + } else if (strcmp(*argv, "size") == 0) { + NEXT_ARG(); + + if (size) + duparg2("size", *argv); + + if (!type) + missarg("type"); + if (!ns_found) + missarg("ns"); + + 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); + + } else { + break; + } + } + + if (!type) + missarg("type"); + if (!ns_found) + missarg("ns"); + if (!size) + missarg("size"); + + if (rta_addattr_l(rta, len, IOAM6_IPTUNNEL_TRACE, trace, + sizeof(*trace))) { + free(trace); + return -1; + } + + *argcp = argc + 1; + *argvp = argv - 1; + + free(trace); + return 0; +} + struct lwt_x { struct rtattr *rta; size_t len; @@ -1744,6 +1868,9 @@ int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp, case LWTUNNEL_ENCAP_RPL: ret = parse_encap_rpl(rta, len, &argc, &argv); break; + case LWTUNNEL_ENCAP_IOAM6: + ret = parse_encap_ioam6(rta, len, &argc, &argv); + break; default: fprintf(stderr, "Error: unsupported encap type\n"); break;