]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
New IOAM6 encap type for routes
authorJustin Iurman <justin.iurman@uliege.be>
Sun, 1 Aug 2021 12:45:51 +0000 (14:45 +0200)
committerStephen Hemminger <stephen@networkplumber.org>
Wed, 1 Sep 2021 19:51:44 +0000 (12:51 -0700)
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 <justin.iurman@uliege.be>
Signed-off-by: David Ahern <dsahern@kernel.org>
ip/iproute.c
ip/iproute_lwtunnel.c

index 1ccf51a56d3472de72580841fb63002091ffe931..1e5e2002d2edf2faa62360121dde4dcfc9699932 100644 (file)
@@ -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);
 }
index c4bae68d68d5678ce418d15e27ed76893604ee71..218d508672a822194031f4c7281245127c2c1df3 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/seg6_hmac.h>
 #include <linux/seg6_local.h>
 #include <linux/if_tunnel.h>
+#include <linux/ioam6.h>
+#include <linux/ioam6_iptunnel.h>
 
 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;