All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH iproute2-next v2 0/3] Provide support for IOAM
@ 2021-07-24 17:21 Justin Iurman
  2021-07-24 17:21 ` [PATCH iproute2-next v2 1/3] Add, show, link, remove IOAM namespaces and schemas Justin Iurman
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Justin Iurman @ 2021-07-24 17:21 UTC (permalink / raw)
  To: netdev; +Cc: stephen, justin.iurman

v2:
 - Use print_{hex,0xhex} instead of print_string when possible (patch #1)

The IOAM patchset was merged yesterday (see net-next commits [1,2,3,4,5,6]).
Therefore, this patchset provides support for IOAM inside iproute2, as well as
manpage documentation. Here is a summary of added features inside iproute2.

(1) configure IOAM namespaces and schemas:

$ ip ioam
Usage:	ip ioam { COMMAND | help }
	ip ioam namespace show
	ip ioam namespace add ID [ data DATA32 ] [ wide DATA64 ]
	ip ioam namespace del ID
	ip ioam schema show
	ip ioam schema add ID DATA
	ip ioam schema del ID
	ip ioam namespace set ID schema { ID | none }
	
(2) provide a new encap type to insert the IOAM pre-allocated trace:

$ ip -6 ro ad fc00::1/128 encap ioam6 trace type 0x800000 ns 1 size 12 dev eth0

  [1] db67f219fc9365a0c456666ed7c134d43ab0be8a
  [2] 9ee11f0fff205b4b3df9750bff5e94f97c71b6a0
  [3] 8c6f6fa6772696be0c047a711858084b38763728
  [4] 3edede08ff37c6a9370510508d5eeb54890baf47
  [5] de8e80a54c96d2b75377e0e5319a64d32c88c690
  [6] 968691c777af78d2daa2ee87cfaeeae825255a58

Justin Iurman (3):
  Add, show, link, remove IOAM namespaces and schemas
  New IOAM6 encap type for routes
  IOAM man8

 include/uapi/linux/ioam6.h          | 133 +++++++++++
 include/uapi/linux/ioam6_genl.h     |  52 +++++
 include/uapi/linux/ioam6_iptunnel.h |  20 ++
 include/uapi/linux/lwtunnel.h       |   1 +
 ip/Makefile                         |   2 +-
 ip/ip.c                             |   3 +-
 ip/ip_common.h                      |   1 +
 ip/ipioam6.c                        | 343 ++++++++++++++++++++++++++++
 ip/iproute.c                        |   5 +-
 ip/iproute_lwtunnel.c               | 121 ++++++++++
 man/man8/ip-ioam.8                  |  72 ++++++
 man/man8/ip-route.8.in              |  35 ++-
 man/man8/ip.8                       |   7 +-
 13 files changed, 789 insertions(+), 6 deletions(-)
 create mode 100644 include/uapi/linux/ioam6.h
 create mode 100644 include/uapi/linux/ioam6_genl.h
 create mode 100644 include/uapi/linux/ioam6_iptunnel.h
 create mode 100644 ip/ipioam6.c
 create mode 100644 man/man8/ip-ioam.8

-- 
2.25.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH iproute2-next v2 1/3] Add, show, link, remove IOAM namespaces and schemas
  2021-07-24 17:21 [PATCH iproute2-next v2 0/3] Provide support for IOAM Justin Iurman
@ 2021-07-24 17:21 ` Justin Iurman
  2021-07-29  2:41   ` David Ahern
  2021-08-11  3:46   ` Stephen Hemminger
  2021-07-24 17:21 ` [PATCH iproute2-next v2 2/3] New IOAM6 encap type for routes Justin Iurman
  2021-07-24 17:21 ` [PATCH iproute2-next v2 3/3] IOAM man8 Justin Iurman
  2 siblings, 2 replies; 13+ messages in thread
From: Justin Iurman @ 2021-07-24 17:21 UTC (permalink / raw)
  To: netdev; +Cc: stephen, justin.iurman

This patch provides support for adding, listing and removing IOAM namespaces
and schemas with iproute2. When adding an IOAM namespace, both "data" (=u32)
and "wide" (=u64) are optional. Therefore, you can either have none, one of
them, or both at the same time. When adding an IOAM schema, there is no
restriction on "DATA" except its size (see IOAM6_MAX_SCHEMA_DATA_LEN). By
default, an IOAM namespace has no active IOAM schema (meaning an IOAM namespace
is not linked to an IOAM schema), and an IOAM schema is not considered
as "active" (meaning an IOAM schema is not linked to an IOAM namespace). It is
possible to link an IOAM namespace with an IOAM schema, thanks to the last
command below (meaning the IOAM schema will be considered as "active" for the
specific IOAM namespace).

$ ip ioam
Usage:	ip ioam { COMMAND | help }
	ip ioam namespace show
	ip ioam namespace add ID [ data DATA32 ] [ wide DATA64 ]
	ip ioam namespace del ID
	ip ioam schema show
	ip ioam schema add ID DATA
	ip ioam schema del ID
	ip ioam namespace set ID schema { ID | none }

Signed-off-by: Justin Iurman <justin.iurman@uliege.be>
---
 include/uapi/linux/ioam6_genl.h |  52 +++++
 ip/Makefile                     |   2 +-
 ip/ip.c                         |   3 +-
 ip/ip_common.h                  |   1 +
 ip/ipioam6.c                    | 343 ++++++++++++++++++++++++++++++++
 5 files changed, 399 insertions(+), 2 deletions(-)
 create mode 100644 include/uapi/linux/ioam6_genl.h
 create mode 100644 ip/ipioam6.c

diff --git a/include/uapi/linux/ioam6_genl.h b/include/uapi/linux/ioam6_genl.h
new file mode 100644
index 00000000..ca4b2283
--- /dev/null
+++ b/include/uapi/linux/ioam6_genl.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ *  IPv6 IOAM Generic Netlink API
+ *
+ *  Author:
+ *  Justin Iurman <justin.iurman@uliege.be>
+ */
+
+#ifndef _UAPI_LINUX_IOAM6_GENL_H
+#define _UAPI_LINUX_IOAM6_GENL_H
+
+#define IOAM6_GENL_NAME "IOAM6"
+#define IOAM6_GENL_VERSION 0x1
+
+enum {
+	IOAM6_ATTR_UNSPEC,
+
+	IOAM6_ATTR_NS_ID,	/* u16 */
+	IOAM6_ATTR_NS_DATA,	/* u32 */
+	IOAM6_ATTR_NS_DATA_WIDE,/* u64 */
+
+#define IOAM6_MAX_SCHEMA_DATA_LEN (255 * 4)
+	IOAM6_ATTR_SC_ID,	/* u32 */
+	IOAM6_ATTR_SC_DATA,	/* Binary */
+	IOAM6_ATTR_SC_NONE,	/* Flag */
+
+	IOAM6_ATTR_PAD,
+
+	__IOAM6_ATTR_MAX,
+};
+
+#define IOAM6_ATTR_MAX (__IOAM6_ATTR_MAX - 1)
+
+enum {
+	IOAM6_CMD_UNSPEC,
+
+	IOAM6_CMD_ADD_NAMESPACE,
+	IOAM6_CMD_DEL_NAMESPACE,
+	IOAM6_CMD_DUMP_NAMESPACES,
+
+	IOAM6_CMD_ADD_SCHEMA,
+	IOAM6_CMD_DEL_SCHEMA,
+	IOAM6_CMD_DUMP_SCHEMAS,
+
+	IOAM6_CMD_NS_SET_SCHEMA,
+
+	__IOAM6_CMD_MAX,
+};
+
+#define IOAM6_CMD_MAX (__IOAM6_CMD_MAX - 1)
+
+#endif /* _UAPI_LINUX_IOAM6_GENL_H */
diff --git a/ip/Makefile b/ip/Makefile
index b03af29b..2ae9df89 100644
--- a/ip/Makefile
+++ b/ip/Makefile
@@ -11,7 +11,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
     iplink_bridge.o iplink_bridge_slave.o ipfou.o iplink_ipvlan.o \
     iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o ipmacsec.o ipila.o \
     ipvrf.o iplink_xstats.o ipseg6.o iplink_netdevsim.o iplink_rmnet.o \
-    ipnexthop.o ipmptcp.o iplink_bareudp.o iplink_wwan.o
+    ipnexthop.o ipmptcp.o iplink_bareudp.o iplink_wwan.o ipioam6.o
 
 RTMONOBJ=rtmon.o
 
diff --git a/ip/ip.c b/ip/ip.c
index 8e4c6eb5..e7ffeaff 100644
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -64,7 +64,7 @@ static void usage(void)
 	fprintf(stderr,
 		"Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }\n"
 		"       ip [ -force ] -batch filename\n"
-		"where  OBJECT := { address | addrlabel | fou | help | ila | l2tp | link |\n"
+		"where  OBJECT := { address | addrlabel | fou | help | ila | ioam | l2tp | link |\n"
 		"                   macsec | maddress | monitor | mptcp | mroute | mrule |\n"
 		"                   neighbor | neighbour | netconf | netns | nexthop | ntable |\n"
 		"                   ntbl | route | rule | sr | tap | tcpmetrics |\n"
@@ -121,6 +121,7 @@ static const struct cmd {
 	{ "sr",		do_seg6 },
 	{ "nexthop",	do_ipnh },
 	{ "mptcp",	do_mptcp },
+	{ "ioam",	do_ioam6 },
 	{ "help",	do_help },
 	{ 0 }
 };
diff --git a/ip/ip_common.h b/ip/ip_common.h
index b5b2b082..ad018183 100644
--- a/ip/ip_common.h
+++ b/ip/ip_common.h
@@ -90,6 +90,7 @@ int netns_identify_pid(const char *pidstr, char *name, int len);
 int do_seg6(int argc, char **argv);
 int do_ipnh(int argc, char **argv);
 int do_mptcp(int argc, char **argv);
+int do_ioam6(int argc, char **argv);
 
 int iplink_get(char *name, __u32 filt_mask);
 int iplink_ifla_xstats(int argc, char **argv);
diff --git a/ip/ipioam6.c b/ip/ipioam6.c
new file mode 100644
index 00000000..291fe5ba
--- /dev/null
+++ b/ip/ipioam6.c
@@ -0,0 +1,343 @@
+/*
+ * ioam6.c "ip ioam"
+ *
+ *	  This program is free software; you can redistribute it and/or
+ *	  modify it under the terms of the GNU General Public License
+ *	  version 2 as published by the Free Software Foundation;
+ *
+ * Author: Justin Iurman <justin.iurman@uliege.be>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <linux/genetlink.h>
+#include <linux/ioam6_genl.h>
+
+#include "utils.h"
+#include "ip_common.h"
+#include "libgenl.h"
+#include "json_print.h"
+
+static void usage(void)
+{
+	fprintf(stderr,
+		"Usage:	ip ioam { COMMAND | help }\n"
+		"	ip ioam namespace show\n"
+		"	ip ioam namespace add ID [ data DATA32 ] [ wide DATA64 ]\n"
+		"	ip ioam namespace del ID\n"
+		"	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");
+	exit(-1);
+}
+
+static struct rtnl_handle grth = { .fd = -1 };
+static int genl_family = -1;
+
+#define IOAM6_REQUEST(_req, _bufsiz, _cmd, _flags) \
+	 GENL_REQUEST(_req, _bufsiz, genl_family, 0, \
+				IOAM6_GENL_VERSION, _cmd, _flags)
+
+static struct {
+	unsigned int cmd;
+	__u32 sc_id;
+	__u32 ns_data;
+	__u64 ns_data_wide;
+	__u16 ns_id;
+	bool has_ns_data;
+	bool has_ns_data_wide;
+	bool sc_none;
+	__u8 sc_data[IOAM6_MAX_SCHEMA_DATA_LEN];
+} opts;
+
+static void print_namespace(struct rtattr *attrs[])
+{
+	print_uint(PRINT_ANY, "namespace", "namespace %u",
+		   rta_getattr_u16(attrs[IOAM6_ATTR_NS_ID]));
+
+	if (attrs[IOAM6_ATTR_SC_ID])
+		print_uint(PRINT_ANY, "schema", " [schema %u]",
+			   rta_getattr_u32(attrs[IOAM6_ATTR_SC_ID]));
+
+	if (!attrs[IOAM6_ATTR_NS_DATA])
+		print_null(PRINT_ANY, "data", "", NULL);
+	else
+		print_hex(PRINT_ANY, "data", ", data %#010x",
+			  rta_getattr_u32(attrs[IOAM6_ATTR_NS_DATA]));
+
+	if (!attrs[IOAM6_ATTR_NS_DATA_WIDE])
+		print_null(PRINT_ANY, "wide", "", NULL);
+	else
+		print_0xhex(PRINT_ANY, "wide", ", wide %#018lx",
+			    rta_getattr_u64(attrs[IOAM6_ATTR_NS_DATA_WIDE]));
+
+	print_null(PRINT_ANY, "", "\n", NULL);
+}
+
+static void print_schema(struct rtattr *attrs[])
+{
+	__u8 data[IOAM6_MAX_SCHEMA_DATA_LEN + 1];
+	int len;
+
+	print_uint(PRINT_ANY, "schema", "schema %u",
+		   rta_getattr_u32(attrs[IOAM6_ATTR_SC_ID]));
+
+	if (attrs[IOAM6_ATTR_NS_ID])
+		print_uint(PRINT_ANY, "namespace", " [namespace %u]",
+			   rta_getattr_u16(attrs[IOAM6_ATTR_NS_ID]));
+
+	len = RTA_PAYLOAD(attrs[IOAM6_ATTR_SC_DATA]);
+	memcpy(data, RTA_DATA(attrs[IOAM6_ATTR_SC_DATA]), len);
+	data[len] = '\0';
+
+	print_string(PRINT_ANY, "data", ", data \"%s\"", (const char *)data);
+	print_null(PRINT_ANY, "", "\n", NULL);
+}
+
+static int process_msg(struct nlmsghdr *n, void *arg)
+{
+	struct rtattr *attrs[IOAM6_ATTR_MAX + 1];
+	struct genlmsghdr *ghdr;
+	int len = n->nlmsg_len;
+
+	if (n->nlmsg_type != genl_family)
+		return -1;
+
+	len -= NLMSG_LENGTH(GENL_HDRLEN);
+	if (len < 0)
+		return -1;
+
+	ghdr = NLMSG_DATA(n);
+	parse_rtattr(attrs, IOAM6_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len);
+
+	open_json_object(NULL);
+	switch (ghdr->cmd) {
+	case IOAM6_CMD_DUMP_NAMESPACES:
+		print_namespace(attrs);
+		break;
+	case IOAM6_CMD_DUMP_SCHEMAS:
+		print_schema(attrs);
+		break;
+	}
+	close_json_object();
+
+	return 0;
+}
+
+static int ioam6_do_cmd(void)
+{
+	IOAM6_REQUEST(req, 1036, opts.cmd, NLM_F_REQUEST);
+	int dump = 0;
+
+	if (genl_family < 0) {
+		if (rtnl_open_byproto(&grth, 0, NETLINK_GENERIC) < 0) {
+			fprintf(stderr, "Cannot open generic netlink socket\n");
+			exit(1);
+		}
+		genl_family = genl_resolve_family(&grth, IOAM6_GENL_NAME);
+		if (genl_family < 0)
+			exit(1);
+		req.n.nlmsg_type = genl_family;
+	}
+
+	switch (opts.cmd) {
+	case IOAM6_CMD_ADD_NAMESPACE:
+		addattr16(&req.n, sizeof(req), IOAM6_ATTR_NS_ID, opts.ns_id);
+		if (opts.has_ns_data)
+			addattr32(&req.n, sizeof(req), IOAM6_ATTR_NS_DATA,
+				  opts.ns_data);
+		if (opts.has_ns_data_wide)
+			addattr64(&req.n, sizeof(req), IOAM6_ATTR_NS_DATA_WIDE,
+				  opts.ns_data_wide);
+		break;
+	case IOAM6_CMD_DEL_NAMESPACE:
+		addattr16(&req.n, sizeof(req), IOAM6_ATTR_NS_ID, opts.ns_id);
+		break;
+	case IOAM6_CMD_DUMP_NAMESPACES:
+	case IOAM6_CMD_DUMP_SCHEMAS:
+		dump = 1;
+		break;
+	case IOAM6_CMD_ADD_SCHEMA:
+		addattr32(&req.n, sizeof(req), IOAM6_ATTR_SC_ID, opts.sc_id);
+		addattr_l(&req.n, sizeof(req), IOAM6_ATTR_SC_DATA, opts.sc_data,
+			  strlen((const char *)opts.sc_data));
+		break;
+	case IOAM6_CMD_DEL_SCHEMA:
+		addattr32(&req.n, sizeof(req), IOAM6_ATTR_SC_ID, opts.sc_id);
+		break;
+	case IOAM6_CMD_NS_SET_SCHEMA:
+		addattr16(&req.n, sizeof(req), IOAM6_ATTR_NS_ID, opts.ns_id);
+		if (opts.sc_none)
+			addattr(&req.n, sizeof(req), IOAM6_ATTR_SC_NONE);
+		else
+			addattr32(&req.n, sizeof(req), IOAM6_ATTR_SC_ID,
+				  opts.sc_id);
+		break;
+	}
+
+	if (!dump) {
+		if (rtnl_talk(&grth, &req.n, NULL) < 0)
+			return -1;
+	} else {
+		req.n.nlmsg_flags |= NLM_F_DUMP;
+		req.n.nlmsg_seq = grth.dump = ++grth.seq;
+		if (rtnl_send(&grth, &req, req.n.nlmsg_len) < 0) {
+			perror("Failed to send dump request");
+			exit(1);
+		}
+
+		new_json_obj(json);
+		if (rtnl_dump_filter(&grth, process_msg, stdout) < 0) {
+			fprintf(stderr, "Dump terminated\n");
+			exit(1);
+		}
+		delete_json_obj();
+		fflush(stdout);
+	}
+
+	return 0;
+}
+
+int do_ioam6(int argc, char **argv)
+{
+	bool maybe_wide = false;
+
+	if (argc < 1 || matches(*argv, "help") == 0)
+		usage();
+
+	memset(&opts, 0, sizeof(opts));
+
+	if (matches(*argv, "namespace") == 0) {
+		NEXT_ARG();
+
+		if (matches(*argv, "show") == 0) {
+			opts.cmd = IOAM6_CMD_DUMP_NAMESPACES;
+
+		} else if (matches(*argv, "add") == 0) {
+			NEXT_ARG();
+
+			if (get_u16(&opts.ns_id, *argv, 0))
+				invarg("Invalid namespace ID", *argv);
+
+			if (NEXT_ARG_OK()) {
+				NEXT_ARG_FWD();
+
+				if (matches(*argv, "data") == 0) {
+					NEXT_ARG();
+
+					if (get_u32(&opts.ns_data, *argv, 0))
+						invarg("Invalid data", *argv);
+
+					maybe_wide = true;
+					opts.has_ns_data = true;
+
+				} else if (matches(*argv, "wide") == 0) {
+					NEXT_ARG();
+
+					if (get_u64(&opts.ns_data_wide, *argv, 16))
+						invarg("Invalid wide data", *argv);
+
+					opts.has_ns_data_wide = true;
+
+				} else {
+					invarg("Invalid argument", *argv);
+				}
+			}
+
+			if (NEXT_ARG_OK()) {
+				NEXT_ARG_FWD();
+
+				if (!maybe_wide || matches(*argv, "wide") != 0)
+					invarg("Unexpected argument", *argv);
+
+				NEXT_ARG();
+
+				if (get_u64(&opts.ns_data_wide, *argv, 16))
+					invarg("Invalid wide data", *argv);
+
+				opts.has_ns_data_wide = true;
+			}
+
+			opts.cmd = IOAM6_CMD_ADD_NAMESPACE;
+
+		} else if (matches(*argv, "del") == 0) {
+			NEXT_ARG();
+
+			if (get_u16(&opts.ns_id, *argv, 0))
+				invarg("Invalid namespace ID", *argv);
+
+			opts.cmd = IOAM6_CMD_DEL_NAMESPACE;
+
+		} else if (matches(*argv, "set") == 0) {
+			NEXT_ARG();
+
+			if (get_u16(&opts.ns_id, *argv, 0))
+				invarg("Invalid namespace ID", *argv);
+
+			NEXT_ARG();
+
+			if (matches(*argv, "schema") != 0)
+				invarg("Unknown", *argv);
+
+			NEXT_ARG();
+
+			if (matches(*argv, "none") == 0) {
+				opts.sc_none = true;
+
+			} else {
+				if (get_u32(&opts.sc_id, *argv, 0))
+					invarg("Invalid schema ID", *argv);
+
+				opts.sc_none = false;
+			}
+
+			opts.cmd = IOAM6_CMD_NS_SET_SCHEMA;
+
+		} else {
+			invarg("Unknown", *argv);
+		}
+
+	} else if (matches(*argv, "schema") == 0) {
+		NEXT_ARG();
+
+		if (matches(*argv, "show") == 0) {
+			opts.cmd = IOAM6_CMD_DUMP_SCHEMAS;
+
+		} else if (matches(*argv, "add") == 0) {
+			NEXT_ARG();
+
+			if (get_u32(&opts.sc_id, *argv, 0))
+				invarg("Invalid schema ID", *argv);
+
+			NEXT_ARG();
+
+			if (strlen(*argv) > IOAM6_MAX_SCHEMA_DATA_LEN)
+				invarg("Schema DATA too big", *argv);
+
+			memcpy(opts.sc_data, *argv, strlen(*argv));
+			opts.cmd = IOAM6_CMD_ADD_SCHEMA;
+
+		} else if (matches(*argv, "del") == 0) {
+			NEXT_ARG();
+
+			if (get_u32(&opts.sc_id, *argv, 0))
+				invarg("Invalid schema ID", *argv);
+
+			opts.cmd = IOAM6_CMD_DEL_SCHEMA;
+
+		} else {
+			invarg("Unknown", *argv);
+		}
+
+	} else {
+		invarg("Unknown", *argv);
+	}
+
+	return ioam6_do_cmd();
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH iproute2-next v2 2/3] New IOAM6 encap type for routes
  2021-07-24 17:21 [PATCH iproute2-next v2 0/3] Provide support for IOAM Justin Iurman
  2021-07-24 17:21 ` [PATCH iproute2-next v2 1/3] Add, show, link, remove IOAM namespaces and schemas Justin Iurman
@ 2021-07-24 17:21 ` Justin Iurman
  2021-07-27 13:42   ` Justin Iurman
  2021-07-24 17:21 ` [PATCH iproute2-next v2 3/3] IOAM man8 Justin Iurman
  2 siblings, 1 reply; 13+ messages in thread
From: Justin Iurman @ 2021-07-24 17:21 UTC (permalink / raw)
  To: netdev; +Cc: stephen, justin.iurman

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 type 0x800000 ns 1 size 12 dev eth0

where:
 - "trace" may appear as useless but just anticipates 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>
---
 include/uapi/linux/ioam6.h          | 133 ++++++++++++++++++++++++++++
 include/uapi/linux/ioam6_iptunnel.h |  20 +++++
 include/uapi/linux/lwtunnel.h       |   1 +
 ip/iproute.c                        |   5 +-
 ip/iproute_lwtunnel.c               | 121 +++++++++++++++++++++++++
 5 files changed, 278 insertions(+), 2 deletions(-)
 create mode 100644 include/uapi/linux/ioam6.h
 create mode 100644 include/uapi/linux/ioam6_iptunnel.h

diff --git a/include/uapi/linux/ioam6.h b/include/uapi/linux/ioam6.h
new file mode 100644
index 00000000..0a2cc17d
--- /dev/null
+++ b/include/uapi/linux/ioam6.h
@@ -0,0 +1,133 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ *  IPv6 IOAM implementation
+ *
+ *  Author:
+ *  Justin Iurman <justin.iurman@uliege.be>
+ */
+
+#ifndef _UAPI_LINUX_IOAM6_H
+#define _UAPI_LINUX_IOAM6_H
+
+#include <asm/byteorder.h>
+#include <linux/types.h>
+
+#define IOAM6_U16_UNAVAILABLE U16_MAX
+#define IOAM6_U32_UNAVAILABLE U32_MAX
+#define IOAM6_U64_UNAVAILABLE U64_MAX
+
+#define IOAM6_DEFAULT_ID (IOAM6_U32_UNAVAILABLE >> 8)
+#define IOAM6_DEFAULT_ID_WIDE (IOAM6_U64_UNAVAILABLE >> 8)
+#define IOAM6_DEFAULT_IF_ID IOAM6_U16_UNAVAILABLE
+#define IOAM6_DEFAULT_IF_ID_WIDE IOAM6_U32_UNAVAILABLE
+
+/*
+ * IPv6 IOAM Option Header
+ */
+struct ioam6_hdr {
+	__u8 opt_type;
+	__u8 opt_len;
+	__u8 :8;				/* reserved */
+#define IOAM6_TYPE_PREALLOC 0
+	__u8 type;
+} __attribute__((__packed__));
+
+/*
+ * IOAM Trace Header
+ */
+struct ioam6_trace_hdr {
+	__be16	namespace_id;
+
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+
+	__u8	:1,				/* unused */
+		:1,				/* unused */
+		overflow:1,
+		nodelen:5;
+
+	__u8	remlen:7,
+		:1;				/* unused */
+
+	union {
+		__be32 type_be32;
+
+		struct {
+			__u32	bit7:1,
+				bit6:1,
+				bit5:1,
+				bit4:1,
+				bit3:1,
+				bit2:1,
+				bit1:1,
+				bit0:1,
+				bit15:1,	/* unused */
+				bit14:1,	/* unused */
+				bit13:1,	/* unused */
+				bit12:1,	/* unused */
+				bit11:1,
+				bit10:1,
+				bit9:1,
+				bit8:1,
+				bit23:1,	/* reserved */
+				bit22:1,
+				bit21:1,	/* unused */
+				bit20:1,	/* unused */
+				bit19:1,	/* unused */
+				bit18:1,	/* unused */
+				bit17:1,	/* unused */
+				bit16:1,	/* unused */
+				:8;		/* reserved */
+		} type;
+	};
+
+#elif defined(__BIG_ENDIAN_BITFIELD)
+
+	__u8	nodelen:5,
+		overflow:1,
+		:1,				/* unused */
+		:1;				/* unused */
+
+	__u8	:1,				/* unused */
+		remlen:7;
+
+	union {
+		__be32 type_be32;
+
+		struct {
+			__u32	bit0:1,
+				bit1:1,
+				bit2:1,
+				bit3:1,
+				bit4:1,
+				bit5:1,
+				bit6:1,
+				bit7:1,
+				bit8:1,
+				bit9:1,
+				bit10:1,
+				bit11:1,
+				bit12:1,	/* unused */
+				bit13:1,	/* unused */
+				bit14:1,	/* unused */
+				bit15:1,	/* unused */
+				bit16:1,	/* unused */
+				bit17:1,	/* unused */
+				bit18:1,	/* unused */
+				bit19:1,	/* unused */
+				bit20:1,	/* unused */
+				bit21:1,	/* unused */
+				bit22:1,
+				bit23:1,	/* reserved */
+				:8;		/* reserved */
+		} type;
+	};
+
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+
+#define IOAM6_TRACE_DATA_SIZE_MAX 244
+	__u8	data[0];
+} __attribute__((__packed__));
+
+#endif /* _UAPI_LINUX_IOAM6_H */
diff --git a/include/uapi/linux/ioam6_iptunnel.h b/include/uapi/linux/ioam6_iptunnel.h
new file mode 100644
index 00000000..bae14636
--- /dev/null
+++ b/include/uapi/linux/ioam6_iptunnel.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ *  IPv6 IOAM Lightweight Tunnel API
+ *
+ *  Author:
+ *  Justin Iurman <justin.iurman@uliege.be>
+ */
+
+#ifndef _UAPI_LINUX_IOAM6_IPTUNNEL_H
+#define _UAPI_LINUX_IOAM6_IPTUNNEL_H
+
+enum {
+	IOAM6_IPTUNNEL_UNSPEC,
+	IOAM6_IPTUNNEL_TRACE,		/* struct ioam6_trace_hdr */
+	__IOAM6_IPTUNNEL_MAX,
+};
+
+#define IOAM6_IPTUNNEL_MAX (__IOAM6_IPTUNNEL_MAX - 1)
+
+#endif /* _UAPI_LINUX_IOAM6_IPTUNNEL_H */
diff --git a/include/uapi/linux/lwtunnel.h b/include/uapi/linux/lwtunnel.h
index b7c0191f..78f0ecd1 100644
--- a/include/uapi/linux/lwtunnel.h
+++ b/include/uapi/linux/lwtunnel.h
@@ -14,6 +14,7 @@ enum lwtunnel_encap_types {
 	LWTUNNEL_ENCAP_BPF,
 	LWTUNNEL_ENCAP_SEG6_LOCAL,
 	LWTUNNEL_ENCAP_RPL,
+	LWTUNNEL_ENCAP_IOAM6,
 	__LWTUNNEL_ENCAP_MAX,
 };
 
diff --git a/ip/iproute.c b/ip/iproute.c
index bdeb9644..330203b0 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 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 c4bae68d..f1e001c4 100644
--- a/ip/iproute_lwtunnel.c
+++ b/ip/iproute_lwtunnel.c
@@ -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,23 @@ 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_hex(PRINT_ANY, "type", "type %#06x ", 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 +680,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 +879,98 @@ 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");
+
+	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 +1862,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;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH iproute2-next v2 3/3] IOAM man8
  2021-07-24 17:21 [PATCH iproute2-next v2 0/3] Provide support for IOAM Justin Iurman
  2021-07-24 17:21 ` [PATCH iproute2-next v2 1/3] Add, show, link, remove IOAM namespaces and schemas Justin Iurman
  2021-07-24 17:21 ` [PATCH iproute2-next v2 2/3] New IOAM6 encap type for routes Justin Iurman
@ 2021-07-24 17:21 ` Justin Iurman
  2 siblings, 0 replies; 13+ messages in thread
From: Justin Iurman @ 2021-07-24 17:21 UTC (permalink / raw)
  To: netdev; +Cc: stephen, justin.iurman

This patch provides man8 documentation for IOAM inside ip, ip-ioam and ip-route.

Signed-off-by: Justin Iurman <justin.iurman@uliege.be>
---
 man/man8/ip-ioam.8     | 72 ++++++++++++++++++++++++++++++++++++++++++
 man/man8/ip-route.8.in | 35 +++++++++++++++++++-
 man/man8/ip.8          |  7 +++-
 3 files changed, 112 insertions(+), 2 deletions(-)
 create mode 100644 man/man8/ip-ioam.8

diff --git a/man/man8/ip-ioam.8 b/man/man8/ip-ioam.8
new file mode 100644
index 00000000..1bdc0ece
--- /dev/null
+++ b/man/man8/ip-ioam.8
@@ -0,0 +1,72 @@
+.TH IP\-IOAM 8 "05 Jul 2021" "iproute2" "Linux"
+.SH "NAME"
+ip-ioam \- IPv6 In-situ OAM (IOAM)
+.SH SYNOPSIS
+.sp
+.ad l
+.in +8
+.ti -8
+.B ip ioam
+.RI " { " COMMAND " | "
+.BR help " }"
+.sp
+.ti -8
+
+.ti -8
+.B ip ioam namespace show
+
+.ti -8
+.B ip ioam namespace add
+.I ID
+.BR " [ "
+.B data
+.I DATA32
+.BR "]"
+.BR " [ "
+.B wide
+.I DATA64
+.BR "]"
+
+.ti -8
+.B ip ioam namespace del
+.I ID
+
+.ti -8
+.B ip ioam schema show
+
+.ti -8
+.B ip ioam schema add
+.I ID DATA
+
+.ti -8
+.B ip ioam schema del
+.I ID
+
+.ti -8
+.B ip ioam namespace set
+.I ID
+.B schema
+.RI " { " ID " | "
+.BR none " }"
+
+.SH DESCRIPTION
+The \fBip ioam\fR command is used to configure IPv6 In-situ OAM (IOAM6)
+internal parameters, namely IOAM namespaces and schemas.
+.PP
+Those parameters also include the mapping between an IOAM namespace and an IOAM
+schema.
+
+.SH EXAMPLES
+.PP
+.SS Configure an IOAM namespace (ID = 1) with both data (32 bits) and wide data (64 bits)
+.nf
+# ip ioam namespace add 1 data 0xdeadbeef wide 0xcafec0caf00dc0de
+.PP
+.SS Link an existing IOAM schema (ID = 7) to an existing IOAM namespace (ID = 1)
+.nf
+# ip ioam namespace set 1 schema 7
+.SH SEE ALSO
+.br
+.BR ip-route (8)
+.SH AUTHOR
+Justin Iurman <justin.iurman@uliege.be>
diff --git a/man/man8/ip-route.8.in b/man/man8/ip-route.8.in
index 4b1947ab..e12ccf6b 100644
--- a/man/man8/ip-route.8.in
+++ b/man/man8/ip-route.8.in
@@ -190,7 +190,7 @@ throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]"
 .ti -8
 .IR ENCAP " := [ "
 .IR ENCAP_MPLS " | " ENCAP_IP " | " ENCAP_BPF " | "
-.IR ENCAP_SEG6 " | " ENCAP_SEG6LOCAL " ] "
+.IR ENCAP_SEG6 " | " ENCAP_SEG6LOCAL " | " ENCAP_IOAM6 " ] "
 
 .ti -8
 .IR ENCAP_MPLS " := "
@@ -243,6 +243,17 @@ throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]"
 .IR SEG6_ACTION_PARAM " ] [ "
 .BR count " ] "
 
+.ti -8
+.IR ENCAP_IOAM6 " := "
+.B ioam6
+.BR trace
+.BR type
+.IR IOAM6_TRACE_TYPE
+.BR ns
+.IR IOAM6_NAMESPACE
+.BR size
+.IR IOAM6_TRACE_SIZE
+
 .ti -8
 .IR ROUTE_GET_FLAGS " := "
 .BR " [ "
@@ -717,6 +728,9 @@ is a string specifying the supported encapsulation type. Namely:
 .sp
 .BI seg6local
 - local SRv6 segment processing
+.sp
+.BI ioam6
+- encapsulation type IPv6 IOAM
 
 .in -8
 .I ENCAPHDR
@@ -896,6 +910,20 @@ Additionally, encapsulate the matching packet within an outer IPv6 header
 followed by the specified SRH. The destination address of the outer IPv6
 header is set to the first segment of the new SRH. The source
 address is set as described in \fBip-sr\fR(8).
+.in -2
+
+.B ioam6
+.in +2
+.I IOAM6_TRACE_TYPE
+- List of IOAM data required in the trace, represented by a bitfield (24 bits).
+.sp
+
+.I IOAM6_NAMESPACE
+- Numerical value to represent an IOAM namespace. See \fBip-ioam\fR(8).
+.sp
+
+.I IOAM6_TRACE_SIZE
+- Size, in octets, of the pre-allocated trace data block.
 .in -4
 
 .in -8
@@ -1220,6 +1248,11 @@ ip -6 route add 2001:db8:1::/64 encap seg6local action End.DT46 vrftable 100 dev
 Adds an IPv6 route with SRv6 decapsulation and forward with lookup in VRF table.
 .RE
 .PP
+ip -6 route add 2001:db8:1::/64 encap ioam6 trace type 0x800000 ns 1 size 12 dev eth0
+.RS 4
+Adds an IPv6 route with an IOAM Pre-allocated Trace encapsulation that only includes the hop limit and the node id, configured for the IOAM namespace 1 and a pre-allocated data block of 12 octets.
+.RE
+.PP
 ip route add 10.1.1.0/30 nhid 10
 .RS 4
 Adds an ipv4 route using nexthop object with id 10.
diff --git a/man/man8/ip.8 b/man/man8/ip.8
index c9f7671e..87cd2df8 100644
--- a/man/man8/ip.8
+++ b/man/man8/ip.8
@@ -22,7 +22,7 @@ ip \- show / manipulate routing, network devices, interfaces and tunnels
 .BR link " | " address " | " addrlabel " | " route " | " rule " | " neigh " | "\
  ntable " | " tunnel " | " tuntap " | " maddress " | "  mroute " | " mrule " | "\
  monitor " | " xfrm " | " netns " | "  l2tp " | "  tcp_metrics " | " token " | "\
- macsec " | " vrf " | " mptcp " }"
+ macsec " | " vrf " | " mptcp " | " ioam " }"
 .sp
 
 .ti -8
@@ -252,6 +252,10 @@ readability.
 .B addrlabel
 - label configuration for protocol address selection.
 
+.TP
+.B ioam
+- manage IOAM namespaces and IOAM schemas.
+
 .TP
 .B l2tp
 - tunnel ethernet over IP (L2TPv3).
@@ -405,6 +409,7 @@ was written by Alexey N. Kuznetsov and added in Linux 2.2.
 .SH SEE ALSO
 .BR ip-address (8),
 .BR ip-addrlabel (8),
+.BR ip-ioam (8),
 .BR ip-l2tp (8),
 .BR ip-link (8),
 .BR ip-maddress (8),
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH iproute2-next v2 2/3] New IOAM6 encap type for routes
  2021-07-24 17:21 ` [PATCH iproute2-next v2 2/3] New IOAM6 encap type for routes Justin Iurman
@ 2021-07-27 13:42   ` Justin Iurman
  2021-07-29  2:44     ` David Ahern
  0 siblings, 1 reply; 13+ messages in thread
From: Justin Iurman @ 2021-07-27 13:42 UTC (permalink / raw)
  To: netdev; +Cc: stephen

> 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 type 0x800000 ns 1 size 12 dev eth0
> 
> where:
> - "trace" may appear as useless but just anticipates 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>
> ---
> include/uapi/linux/ioam6.h          | 133 ++++++++++++++++++++++++++++
> include/uapi/linux/ioam6_iptunnel.h |  20 +++++
> include/uapi/linux/lwtunnel.h       |   1 +
> ip/iproute.c                        |   5 +-
> ip/iproute_lwtunnel.c               | 121 +++++++++++++++++++++++++
> 5 files changed, 278 insertions(+), 2 deletions(-)
> create mode 100644 include/uapi/linux/ioam6.h
> create mode 100644 include/uapi/linux/ioam6_iptunnel.h
> 
> diff --git a/include/uapi/linux/ioam6.h b/include/uapi/linux/ioam6.h
> new file mode 100644
> index 00000000..0a2cc17d
> --- /dev/null
> +++ b/include/uapi/linux/ioam6.h
> @@ -0,0 +1,133 @@
> +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
> +/*
> + *  IPv6 IOAM implementation
> + *
> + *  Author:
> + *  Justin Iurman <justin.iurman@uliege.be>
> + */
> +
> +#ifndef _UAPI_LINUX_IOAM6_H
> +#define _UAPI_LINUX_IOAM6_H
> +
> +#include <asm/byteorder.h>
> +#include <linux/types.h>
> +
> +#define IOAM6_U16_UNAVAILABLE U16_MAX
> +#define IOAM6_U32_UNAVAILABLE U32_MAX
> +#define IOAM6_U64_UNAVAILABLE U64_MAX
> +
> +#define IOAM6_DEFAULT_ID (IOAM6_U32_UNAVAILABLE >> 8)
> +#define IOAM6_DEFAULT_ID_WIDE (IOAM6_U64_UNAVAILABLE >> 8)
> +#define IOAM6_DEFAULT_IF_ID IOAM6_U16_UNAVAILABLE
> +#define IOAM6_DEFAULT_IF_ID_WIDE IOAM6_U32_UNAVAILABLE
> +
> +/*
> + * IPv6 IOAM Option Header
> + */
> +struct ioam6_hdr {
> +	__u8 opt_type;
> +	__u8 opt_len;
> +	__u8 :8;				/* reserved */
> +#define IOAM6_TYPE_PREALLOC 0
> +	__u8 type;
> +} __attribute__((__packed__));
> +
> +/*
> + * IOAM Trace Header
> + */
> +struct ioam6_trace_hdr {
> +	__be16	namespace_id;
> +
> +#if defined(__LITTLE_ENDIAN_BITFIELD)
> +
> +	__u8	:1,				/* unused */
> +		:1,				/* unused */
> +		overflow:1,
> +		nodelen:5;
> +
> +	__u8	remlen:7,
> +		:1;				/* unused */
> +
> +	union {
> +		__be32 type_be32;
> +
> +		struct {
> +			__u32	bit7:1,
> +				bit6:1,
> +				bit5:1,
> +				bit4:1,
> +				bit3:1,
> +				bit2:1,
> +				bit1:1,
> +				bit0:1,
> +				bit15:1,	/* unused */
> +				bit14:1,	/* unused */
> +				bit13:1,	/* unused */
> +				bit12:1,	/* unused */
> +				bit11:1,
> +				bit10:1,
> +				bit9:1,
> +				bit8:1,
> +				bit23:1,	/* reserved */
> +				bit22:1,
> +				bit21:1,	/* unused */
> +				bit20:1,	/* unused */
> +				bit19:1,	/* unused */
> +				bit18:1,	/* unused */
> +				bit17:1,	/* unused */
> +				bit16:1,	/* unused */
> +				:8;		/* reserved */
> +		} type;
> +	};
> +
> +#elif defined(__BIG_ENDIAN_BITFIELD)
> +
> +	__u8	nodelen:5,
> +		overflow:1,
> +		:1,				/* unused */
> +		:1;				/* unused */
> +
> +	__u8	:1,				/* unused */
> +		remlen:7;
> +
> +	union {
> +		__be32 type_be32;
> +
> +		struct {
> +			__u32	bit0:1,
> +				bit1:1,
> +				bit2:1,
> +				bit3:1,
> +				bit4:1,
> +				bit5:1,
> +				bit6:1,
> +				bit7:1,
> +				bit8:1,
> +				bit9:1,
> +				bit10:1,
> +				bit11:1,
> +				bit12:1,	/* unused */
> +				bit13:1,	/* unused */
> +				bit14:1,	/* unused */
> +				bit15:1,	/* unused */
> +				bit16:1,	/* unused */
> +				bit17:1,	/* unused */
> +				bit18:1,	/* unused */
> +				bit19:1,	/* unused */
> +				bit20:1,	/* unused */
> +				bit21:1,	/* unused */
> +				bit22:1,
> +				bit23:1,	/* reserved */
> +				:8;		/* reserved */
> +		} type;
> +	};
> +
> +#else
> +#error "Please fix <asm/byteorder.h>"
> +#endif
> +
> +#define IOAM6_TRACE_DATA_SIZE_MAX 244
> +	__u8	data[0];
> +} __attribute__((__packed__));
> +
> +#endif /* _UAPI_LINUX_IOAM6_H */
> diff --git a/include/uapi/linux/ioam6_iptunnel.h
> b/include/uapi/linux/ioam6_iptunnel.h
> new file mode 100644
> index 00000000..bae14636
> --- /dev/null
> +++ b/include/uapi/linux/ioam6_iptunnel.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
> +/*
> + *  IPv6 IOAM Lightweight Tunnel API
> + *
> + *  Author:
> + *  Justin Iurman <justin.iurman@uliege.be>
> + */
> +
> +#ifndef _UAPI_LINUX_IOAM6_IPTUNNEL_H
> +#define _UAPI_LINUX_IOAM6_IPTUNNEL_H
> +
> +enum {
> +	IOAM6_IPTUNNEL_UNSPEC,
> +	IOAM6_IPTUNNEL_TRACE,		/* struct ioam6_trace_hdr */
> +	__IOAM6_IPTUNNEL_MAX,
> +};
> +
> +#define IOAM6_IPTUNNEL_MAX (__IOAM6_IPTUNNEL_MAX - 1)
> +
> +#endif /* _UAPI_LINUX_IOAM6_IPTUNNEL_H */
> diff --git a/include/uapi/linux/lwtunnel.h b/include/uapi/linux/lwtunnel.h
> index b7c0191f..78f0ecd1 100644
> --- a/include/uapi/linux/lwtunnel.h
> +++ b/include/uapi/linux/lwtunnel.h
> @@ -14,6 +14,7 @@ enum lwtunnel_encap_types {
> 	LWTUNNEL_ENCAP_BPF,
> 	LWTUNNEL_ENCAP_SEG6_LOCAL,
> 	LWTUNNEL_ENCAP_RPL,
> +	LWTUNNEL_ENCAP_IOAM6,
> 	__LWTUNNEL_ENCAP_MAX,
> };
> 
> diff --git a/ip/iproute.c b/ip/iproute.c
> index bdeb9644..330203b0 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 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 c4bae68d..f1e001c4 100644
> --- a/ip/iproute_lwtunnel.c
> +++ b/ip/iproute_lwtunnel.c
> @@ -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,23 @@ 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_hex(PRINT_ANY, "type", "type %#06x ", ntohl(trace->type_be32) >> 8);

Uh oh... Should be %#08x instead, sorry for that. Should I submit a v3 to reflect it?

> +	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 +680,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 +879,98 @@ 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");
> +
> +	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 +1862,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;
> --
> 2.25.1

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH iproute2-next v2 1/3] Add, show, link, remove IOAM namespaces and schemas
  2021-07-24 17:21 ` [PATCH iproute2-next v2 1/3] Add, show, link, remove IOAM namespaces and schemas Justin Iurman
@ 2021-07-29  2:41   ` David Ahern
  2021-07-29  9:51     ` Justin Iurman
  2021-08-11  3:46   ` Stephen Hemminger
  1 sibling, 1 reply; 13+ messages in thread
From: David Ahern @ 2021-07-29  2:41 UTC (permalink / raw)
  To: Justin Iurman, netdev; +Cc: stephen

On 7/24/21 11:21 AM, Justin Iurman wrote:
> +static void print_schema(struct rtattr *attrs[])
> +{
> +	__u8 data[IOAM6_MAX_SCHEMA_DATA_LEN + 1];
> +	int len;
> +
> +	print_uint(PRINT_ANY, "schema", "schema %u",
> +		   rta_getattr_u32(attrs[IOAM6_ATTR_SC_ID]));
> +
> +	if (attrs[IOAM6_ATTR_NS_ID])
> +		print_uint(PRINT_ANY, "namespace", " [namespace %u]",
> +			   rta_getattr_u16(attrs[IOAM6_ATTR_NS_ID]));
> +
> +	len = RTA_PAYLOAD(attrs[IOAM6_ATTR_SC_DATA]);
> +	memcpy(data, RTA_DATA(attrs[IOAM6_ATTR_SC_DATA]), len);
> +	data[len] = '\0';
> +
> +	print_string(PRINT_ANY, "data", ", data \"%s\"", (const char *)data);

The attribute descriptions shows this as binary data, not a string.

> +	print_null(PRINT_ANY, "", "\n", NULL);
> +}
> +
> +static int process_msg(struct nlmsghdr *n, void *arg)
> +{
> +	struct rtattr *attrs[IOAM6_ATTR_MAX + 1];
> +	struct genlmsghdr *ghdr;
> +	int len = n->nlmsg_len;
> +
> +	if (n->nlmsg_type != genl_family)
> +		return -1;
> +
> +	len -= NLMSG_LENGTH(GENL_HDRLEN);
> +	if (len < 0)
> +		return -1;
> +
> +	ghdr = NLMSG_DATA(n);
> +	parse_rtattr(attrs, IOAM6_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len);
> +
> +	open_json_object(NULL);
> +	switch (ghdr->cmd) {
> +	case IOAM6_CMD_DUMP_NAMESPACES:
> +		print_namespace(attrs);
> +		break;
> +	case IOAM6_CMD_DUMP_SCHEMAS:
> +		print_schema(attrs);
> +		break;
> +	}
> +	close_json_object();
> +
> +	return 0;
> +}
> +
> +static int ioam6_do_cmd(void)
> +{
> +	IOAM6_REQUEST(req, 1036, opts.cmd, NLM_F_REQUEST);
> +	int dump = 0;
> +
> +	if (genl_family < 0) {
> +		if (rtnl_open_byproto(&grth, 0, NETLINK_GENERIC) < 0) {
> +			fprintf(stderr, "Cannot open generic netlink socket\n");
> +			exit(1);
> +		}
> +		genl_family = genl_resolve_family(&grth, IOAM6_GENL_NAME);

The above 2 calls can be done with genl_init_handle.

> +		if (genl_family < 0)
> +			exit(1);
> +		req.n.nlmsg_type = genl_family;
> +	}
> +


> +int do_ioam6(int argc, char **argv)
> +{
> +	bool maybe_wide = false;
> +
> +	if (argc < 1 || matches(*argv, "help") == 0)
> +		usage();
> +
> +	memset(&opts, 0, sizeof(opts));
> +
> +	if (matches(*argv, "namespace") == 0) {

matches has been shown to be quite frail. Convenient for shorthand
typing commands, but frail in the big picture. We should stop using it -
especially for new commands.




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH iproute2-next v2 2/3] New IOAM6 encap type for routes
  2021-07-27 13:42   ` Justin Iurman
@ 2021-07-29  2:44     ` David Ahern
  0 siblings, 0 replies; 13+ messages in thread
From: David Ahern @ 2021-07-29  2:44 UTC (permalink / raw)
  To: Justin Iurman, netdev; +Cc: stephen

On 7/27/21 7:42 AM, Justin Iurman wrote:
>> +	trace = RTA_DATA(tb[IOAM6_IPTUNNEL_TRACE]);
>> +
>> +	print_hex(PRINT_ANY, "type", "type %#06x ", ntohl(trace->type_be32) >> 8);
> Uh oh... Should be %#08x instead, sorry for that. Should I submit a v3 to reflect it?
> 
>> +	print_uint(PRINT_ANY, "ns", "ns %u ", ntohs(trace->namespace_id));
>> +	print_uint(PRINT_ANY, "size", "size %u ", trace->remlen * 4);
>> +}
>> +

roll it into v3.

(also, please chop unrelated content in the reply; it is easy to miss
that one line comment scrolling the long message)

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH iproute2-next v2 1/3] Add, show, link, remove IOAM namespaces and schemas
  2021-07-29  2:41   ` David Ahern
@ 2021-07-29  9:51     ` Justin Iurman
  2021-07-29 14:32       ` David Ahern
  0 siblings, 1 reply; 13+ messages in thread
From: Justin Iurman @ 2021-07-29  9:51 UTC (permalink / raw)
  To: David Ahern; +Cc: netdev, stephen

Hi David,

>> +static void print_schema(struct rtattr *attrs[])
>> +{
>> +	__u8 data[IOAM6_MAX_SCHEMA_DATA_LEN + 1];
>> +	int len;
>> +
>> +	print_uint(PRINT_ANY, "schema", "schema %u",
>> +		   rta_getattr_u32(attrs[IOAM6_ATTR_SC_ID]));
>> +
>> +	if (attrs[IOAM6_ATTR_NS_ID])
>> +		print_uint(PRINT_ANY, "namespace", " [namespace %u]",
>> +			   rta_getattr_u16(attrs[IOAM6_ATTR_NS_ID]));
>> +
>> +	len = RTA_PAYLOAD(attrs[IOAM6_ATTR_SC_DATA]);
>> +	memcpy(data, RTA_DATA(attrs[IOAM6_ATTR_SC_DATA]), len);
>> +	data[len] = '\0';
>> +
>> +	print_string(PRINT_ANY, "data", ", data \"%s\"", (const char *)data);
> 
> The attribute descriptions shows this as binary data, not a string.

Indeed. Maybe should I print it as hex... What do you think is more appropriate for this?


>> +static int ioam6_do_cmd(void)
>> +{
>> +	IOAM6_REQUEST(req, 1036, opts.cmd, NLM_F_REQUEST);
>> +	int dump = 0;
>> +
>> +	if (genl_family < 0) {
>> +		if (rtnl_open_byproto(&grth, 0, NETLINK_GENERIC) < 0) {
>> +			fprintf(stderr, "Cannot open generic netlink socket\n");
>> +			exit(1);
>> +		}
>> +		genl_family = genl_resolve_family(&grth, IOAM6_GENL_NAME);
> 
> The above 2 calls can be done with genl_init_handle.

Didn't know that one, thx for the pointer.


>> +int do_ioam6(int argc, char **argv)
>> +{
>> +	bool maybe_wide = false;
>> +
>> +	if (argc < 1 || matches(*argv, "help") == 0)
>> +		usage();
>> +
>> +	memset(&opts, 0, sizeof(opts));
>> +
>> +	if (matches(*argv, "namespace") == 0) {
> 
> matches has been shown to be quite frail. Convenient for shorthand
> typing commands, but frail in the big picture. We should stop using it -
> especially for new commands.

Sure. What do you suggest as an alternative?

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH iproute2-next v2 1/3] Add, show, link, remove IOAM namespaces and schemas
  2021-07-29  9:51     ` Justin Iurman
@ 2021-07-29 14:32       ` David Ahern
  2021-07-29 16:41         ` Justin Iurman
  0 siblings, 1 reply; 13+ messages in thread
From: David Ahern @ 2021-07-29 14:32 UTC (permalink / raw)
  To: Justin Iurman; +Cc: netdev, stephen

On 7/29/21 3:51 AM, Justin Iurman wrote:
> Hi David,
> 
>>> +static void print_schema(struct rtattr *attrs[])
>>> +{
>>> +	__u8 data[IOAM6_MAX_SCHEMA_DATA_LEN + 1];
>>> +	int len;
>>> +
>>> +	print_uint(PRINT_ANY, "schema", "schema %u",
>>> +		   rta_getattr_u32(attrs[IOAM6_ATTR_SC_ID]));
>>> +
>>> +	if (attrs[IOAM6_ATTR_NS_ID])
>>> +		print_uint(PRINT_ANY, "namespace", " [namespace %u]",
>>> +			   rta_getattr_u16(attrs[IOAM6_ATTR_NS_ID]));
>>> +
>>> +	len = RTA_PAYLOAD(attrs[IOAM6_ATTR_SC_DATA]);
>>> +	memcpy(data, RTA_DATA(attrs[IOAM6_ATTR_SC_DATA]), len);
>>> +	data[len] = '\0';
>>> +
>>> +	print_string(PRINT_ANY, "data", ", data \"%s\"", (const char *)data);
>>
>> The attribute descriptions shows this as binary data, not a string.
> 
> Indeed. Maybe should I print it as hex... What do you think is more appropriate for this?

./tc/em_meta.c has print_binary() but it is not json aware.

devlink has pr_out_binary_value which is close. You could probably take
this one and generalize it.


> 
> 
>>> +static int ioam6_do_cmd(void)
>>> +{
>>> +	IOAM6_REQUEST(req, 1036, opts.cmd, NLM_F_REQUEST);
>>> +	int dump = 0;
>>> +
>>> +	if (genl_family < 0) {
>>> +		if (rtnl_open_byproto(&grth, 0, NETLINK_GENERIC) < 0) {
>>> +			fprintf(stderr, "Cannot open generic netlink socket\n");
>>> +			exit(1);
>>> +		}
>>> +		genl_family = genl_resolve_family(&grth, IOAM6_GENL_NAME);
>>
>> The above 2 calls can be done with genl_init_handle.
> 
> Didn't know that one, thx for the pointer.
> 
> 
>>> +int do_ioam6(int argc, char **argv)
>>> +{
>>> +	bool maybe_wide = false;
>>> +
>>> +	if (argc < 1 || matches(*argv, "help") == 0)
>>> +		usage();
>>> +
>>> +	memset(&opts, 0, sizeof(opts));
>>> +
>>> +	if (matches(*argv, "namespace") == 0) {
>>
>> matches has been shown to be quite frail. Convenient for shorthand
>> typing commands, but frail in the big picture. We should stop using it -
>> especially for new commands.
> 
> Sure. What do you suggest as an alternative?
> 

full strcmp.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH iproute2-next v2 1/3] Add, show, link, remove IOAM namespaces and schemas
  2021-07-29 14:32       ` David Ahern
@ 2021-07-29 16:41         ` Justin Iurman
  2021-07-30 14:39           ` David Ahern
  0 siblings, 1 reply; 13+ messages in thread
From: Justin Iurman @ 2021-07-29 16:41 UTC (permalink / raw)
  To: David Ahern; +Cc: netdev, stephen

>>>> +static void print_schema(struct rtattr *attrs[])
>>>> +{
>>>> +	__u8 data[IOAM6_MAX_SCHEMA_DATA_LEN + 1];
>>>> +	int len;
>>>> +
>>>> +	print_uint(PRINT_ANY, "schema", "schema %u",
>>>> +		   rta_getattr_u32(attrs[IOAM6_ATTR_SC_ID]));
>>>> +
>>>> +	if (attrs[IOAM6_ATTR_NS_ID])
>>>> +		print_uint(PRINT_ANY, "namespace", " [namespace %u]",
>>>> +			   rta_getattr_u16(attrs[IOAM6_ATTR_NS_ID]));
>>>> +
>>>> +	len = RTA_PAYLOAD(attrs[IOAM6_ATTR_SC_DATA]);
>>>> +	memcpy(data, RTA_DATA(attrs[IOAM6_ATTR_SC_DATA]), len);
>>>> +	data[len] = '\0';
>>>> +
>>>> +	print_string(PRINT_ANY, "data", ", data \"%s\"", (const char *)data);
>>>
>>> The attribute descriptions shows this as binary data, not a string.
>> 
>> Indeed. Maybe should I print it as hex... What do you think is more appropriate
>> for this?
> 
> ./tc/em_meta.c has print_binary() but it is not json aware.
> 
> devlink has pr_out_binary_value which is close. You could probably take
> this one and generalize it.

Right, I'll take a look.

>>>> +int do_ioam6(int argc, char **argv)
>>>> +{
>>>> +	bool maybe_wide = false;
>>>> +
>>>> +	if (argc < 1 || matches(*argv, "help") == 0)
>>>> +		usage();
>>>> +
>>>> +	memset(&opts, 0, sizeof(opts));
>>>> +
>>>> +	if (matches(*argv, "namespace") == 0) {
>>>
>>> matches has been shown to be quite frail. Convenient for shorthand
>>> typing commands, but frail in the big picture. We should stop using it -
>>> especially for new commands.
>> 
>> Sure. What do you suggest as an alternative?
>> 
> 
> full strcmp.

I see. But, in that case, I'm wondering if it wouldn't be better to directly modify "matches" internally so that we keep consistency between modules without changing everything.

Thoughts?

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH iproute2-next v2 1/3] Add, show, link, remove IOAM namespaces and schemas
  2021-07-29 16:41         ` Justin Iurman
@ 2021-07-30 14:39           ` David Ahern
  2021-08-11  3:47             ` Stephen Hemminger
  0 siblings, 1 reply; 13+ messages in thread
From: David Ahern @ 2021-07-30 14:39 UTC (permalink / raw)
  To: Justin Iurman; +Cc: netdev, stephen

On 7/29/21 10:41 AM, Justin Iurman wrote:
> I see. But, in that case, I'm wondering if it wouldn't be better to directly modify "matches" internally so that we keep consistency between modules without changing everything.
> 
> Thoughts?

matches() can not be changed.

iproute_lwtunnel code uses full strcmp. The  new ioam command can start
off the same way.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH iproute2-next v2 1/3] Add, show, link, remove IOAM namespaces and schemas
  2021-07-24 17:21 ` [PATCH iproute2-next v2 1/3] Add, show, link, remove IOAM namespaces and schemas Justin Iurman
  2021-07-29  2:41   ` David Ahern
@ 2021-08-11  3:46   ` Stephen Hemminger
  1 sibling, 0 replies; 13+ messages in thread
From: Stephen Hemminger @ 2021-08-11  3:46 UTC (permalink / raw)
  To: Justin Iurman; +Cc: netdev

On Sat, 24 Jul 2021 19:21:06 +0200
Justin Iurman <justin.iurman@uliege.be> wrote:

> +	print_null(PRINT_ANY, "", "\n", NULL);

Use print_nl() since it handles the case of oneline output.
Plus in JSON the newline is meaningless.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH iproute2-next v2 1/3] Add, show, link, remove IOAM namespaces and schemas
  2021-07-30 14:39           ` David Ahern
@ 2021-08-11  3:47             ` Stephen Hemminger
  0 siblings, 0 replies; 13+ messages in thread
From: Stephen Hemminger @ 2021-08-11  3:47 UTC (permalink / raw)
  To: David Ahern; +Cc: Justin Iurman, netdev

On Fri, 30 Jul 2021 08:39:50 -0600
David Ahern <dsahern@gmail.com> wrote:

> On 7/29/21 10:41 AM, Justin Iurman wrote:
> > I see. But, in that case, I'm wondering if it wouldn't be better to directly modify "matches" internally so that we keep consistency between modules without changing everything.
> > 
> > Thoughts?  
> 
> matches() can not be changed.
> 
> iproute_lwtunnel code uses full strcmp. The  new ioam command can start
> off the same way.

Agreed.
Although "ip l s" is cool to impress people it is a maintenance nightmare
as more things get added.

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2021-08-11  3:47 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-24 17:21 [PATCH iproute2-next v2 0/3] Provide support for IOAM Justin Iurman
2021-07-24 17:21 ` [PATCH iproute2-next v2 1/3] Add, show, link, remove IOAM namespaces and schemas Justin Iurman
2021-07-29  2:41   ` David Ahern
2021-07-29  9:51     ` Justin Iurman
2021-07-29 14:32       ` David Ahern
2021-07-29 16:41         ` Justin Iurman
2021-07-30 14:39           ` David Ahern
2021-08-11  3:47             ` Stephen Hemminger
2021-08-11  3:46   ` Stephen Hemminger
2021-07-24 17:21 ` [PATCH iproute2-next v2 2/3] New IOAM6 encap type for routes Justin Iurman
2021-07-27 13:42   ` Justin Iurman
2021-07-29  2:44     ` David Ahern
2021-07-24 17:21 ` [PATCH iproute2-next v2 3/3] IOAM man8 Justin Iurman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.