]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
Add support for IOAM encap modes
authorJustin Iurman <justin.iurman@uliege.be>
Tue, 5 Oct 2021 15:10:19 +0000 (17:10 +0200)
committerDavid Ahern <dsahern@kernel.org>
Sat, 9 Oct 2021 23:35:29 +0000 (17:35 -0600)
This patch adds support for the three IOAM encap modes that were introduced:
inline, encap and auto.

Signed-off-by: Justin Iurman <justin.iurman@uliege.be>
Signed-off-by: David Ahern <dsahern@kernel.org>
ip/iproute_lwtunnel.c

index 218d508672a822194031f4c7281245127c2c1df3..b05dffc69b3f6b845cc83a8584ef768be1e89832 100644 (file)
@@ -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 "<unknown>";
+
+       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;
        }