]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
ip: ioam6: add monitor command
authorJustin Iurman <justin.iurman@uliege.be>
Thu, 22 Feb 2024 15:45:38 +0000 (16:45 +0100)
committerDavid Ahern <dsahern@kernel.org>
Sun, 3 Mar 2024 22:29:19 +0000 (22:29 +0000)
Add the "ip ioam monitor" command to be able to read all IOAM data
received. This is based on a netlink multicast group.

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

index b63d7d5c9b399d61ace36610245c465f0f575552..188609892150fd2bc6cd272d387dc93aed613aed 100644 (file)
@@ -13,6 +13,7 @@
 #include <inttypes.h>
 
 #include <linux/genetlink.h>
+#include <linux/ioam6.h>
 #include <linux/ioam6_genl.h>
 
 #include "utils.h"
@@ -30,7 +31,8 @@ static void usage(void)
                "       ip ioam schema show\n"
                "       ip ioam schema add ID DATA\n"
                "       ip ioam schema del ID\n"
-               "       ip ioam namespace set ID schema { ID | none }\n");
+               "       ip ioam namespace set ID schema { ID | none }\n"
+               "       ip ioam monitor\n");
        exit(-1);
 }
 
@@ -42,6 +44,7 @@ static int genl_family = -1;
                                IOAM6_GENL_VERSION, _cmd, _flags)
 
 static struct {
+       bool monitor;
        unsigned int cmd;
        __u32 sc_id;
        __u32 ns_data;
@@ -96,6 +99,37 @@ static void print_schema(struct rtattr *attrs[])
        print_nl();
 }
 
+static void print_trace(struct rtattr *attrs[])
+{
+       __u8 data[IOAM6_TRACE_DATA_SIZE_MAX];
+       int len, i = 0;
+
+       printf("[TRACE] ");
+
+       if (attrs[IOAM6_EVENT_ATTR_TRACE_NAMESPACE])
+               printf("Namespace=%u ",
+                      rta_getattr_u16(attrs[IOAM6_EVENT_ATTR_TRACE_NAMESPACE]));
+
+       if (attrs[IOAM6_EVENT_ATTR_TRACE_NODELEN])
+               printf("NodeLen=%u ",
+                      rta_getattr_u8(attrs[IOAM6_EVENT_ATTR_TRACE_NODELEN]));
+
+       if (attrs[IOAM6_EVENT_ATTR_TRACE_TYPE])
+               printf("Type=%#08x ",
+                      rta_getattr_u32(attrs[IOAM6_EVENT_ATTR_TRACE_TYPE]));
+
+       len = RTA_PAYLOAD(attrs[IOAM6_EVENT_ATTR_TRACE_DATA]);
+       memcpy(data, RTA_DATA(attrs[IOAM6_EVENT_ATTR_TRACE_DATA]), len);
+
+       printf("Data=");
+       while (i < len) {
+               printf("%02x", data[i]);
+               i++;
+       }
+
+       printf("\n");
+}
+
 static int process_msg(struct nlmsghdr *n, void *arg)
 {
        struct rtattr *attrs[IOAM6_ATTR_MAX + 1];
@@ -126,6 +160,32 @@ static int process_msg(struct nlmsghdr *n, void *arg)
        return 0;
 }
 
+static int ioam6_monitor_msg(struct rtnl_ctrl_data *ctrl, struct nlmsghdr *n,
+                             void *arg)
+{
+       struct rtattr *attrs[IOAM6_EVENT_ATTR_MAX + 1];
+       const struct genlmsghdr *ghdr = NLMSG_DATA(n);
+       int len = n->nlmsg_len;
+
+       if (n->nlmsg_type != genl_family)
+               return -1;
+
+       len -= NLMSG_LENGTH(GENL_HDRLEN);
+       if (len < 0)
+               return -1;
+
+       parse_rtattr(attrs, IOAM6_EVENT_ATTR_MAX,
+                    (void *)ghdr + GENL_HDRLEN, len);
+
+       switch (ghdr->cmd) {
+       case IOAM6_EVENT_TRACE:
+               print_trace(attrs);
+               break;
+       }
+
+       return 0;
+}
+
 static int ioam6_do_cmd(void)
 {
        IOAM6_REQUEST(req, 1056, opts.cmd, NLM_F_REQUEST);
@@ -134,6 +194,19 @@ static int ioam6_do_cmd(void)
        if (genl_init_handle(&grth, IOAM6_GENL_NAME, &genl_family))
                exit(1);
 
+       if (opts.monitor) {
+               if (genl_add_mcast_grp(&grth, genl_family,
+                                       IOAM6_GENL_EV_GRP_NAME) < 0) {
+                       perror("can't subscribe to ioam6 events");
+                       exit(1);
+               }
+
+               if (rtnl_listen(&grth, ioam6_monitor_msg, stdout) < 0)
+                       exit(1);
+
+               return 0;
+       }
+
        req.n.nlmsg_type = genl_family;
 
        switch (opts.cmd) {
@@ -325,6 +398,9 @@ int do_ioam6(int argc, char **argv)
                        invarg("Unknown", *argv);
                }
 
+       } else if (strcmp(*argv, "monitor") == 0) {
+               opts.monitor = true;
+
        } else {
                invarg("Unknown", *argv);
        }