All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC iproute2-next v2] seg6: add counters support for SRv6 Behaviors
@ 2021-04-15 18:06 Paolo Lungaroni
  2021-04-15 21:23 ` Stephen Hemminger
  0 siblings, 1 reply; 3+ messages in thread
From: Paolo Lungaroni @ 2021-04-15 18:06 UTC (permalink / raw)
  To: David Ahern, netdev
  Cc: Jakub Kicinski, Stefano Salsano, Ahmed Abdelsalam, Andrea Mayer,
	Paolo Lungaroni

We introduce the "count" optional attribute for supporting counters in SRv6
Behaviors as defined in [1], section 6. For each SRv6 Behavior instance,
counters defined in [1] are:

 - the total number of packets that have been correctly processed;
 - the total amount of traffic in bytes of all packets that have been
   correctly processed;

In addition, we introduce a new counter that counts the number of packets
that have NOT been properly processed (i.e. errors) by an SRv6 Behavior
instance.

Each SRv6 Behavior instance can be configured, at the time of its creation,
to make use of counters specifing the "count" attribute as follows:

 $ ip -6 route add 2001:db8::1 encap seg6local action End count dev eth0

per-behavior counters can be shown by adding "-s" to the iproute2 command
line, i.e.:

 $ ip -s -6 route show 2001:db8::1
 2001:db8::1 encap seg6local action End packets 0 bytes 0 errors 0 dev eth0

[1] https://www.rfc-editor.org/rfc/rfc8986.html#name-counters

Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
Signed-off-by: Paolo Lungaroni <paolo.lungaroni@uniroma2.it>
---
 include/uapi/linux/seg6_local.h | 30 +++++++++++++
 ip/iproute_lwtunnel.c           | 80 ++++++++++++++++++++++++++++++++-
 2 files changed, 109 insertions(+), 1 deletion(-)

diff --git a/include/uapi/linux/seg6_local.h b/include/uapi/linux/seg6_local.h
index bb5c8ddf..85955514 100644
--- a/include/uapi/linux/seg6_local.h
+++ b/include/uapi/linux/seg6_local.h
@@ -27,6 +27,7 @@ enum {
 	SEG6_LOCAL_OIF,
 	SEG6_LOCAL_BPF,
 	SEG6_LOCAL_VRFTABLE,
+	SEG6_LOCAL_COUNTERS,
 	__SEG6_LOCAL_MAX,
 };
 #define SEG6_LOCAL_MAX (__SEG6_LOCAL_MAX - 1)
@@ -78,4 +79,33 @@ enum {
 
 #define SEG6_LOCAL_BPF_PROG_MAX (__SEG6_LOCAL_BPF_PROG_MAX - 1)
 
+/* SRv6 Behavior counters are encoded as netlink attributes guaranteeing the
+ * correct alignment.
+ * Each counter is identified by a different attribute type (i.e.
+ * SEG6_LOCAL_CNT_PACKETS).
+ *
+ * - SEG6_LOCAL_CNT_PACKETS: identifies a counter that counts the number of
+ *   packets that have been CORRECTLY processed by an SRv6 Behavior instance
+ *   (i.e., packets that generate errors or are dropped are NOT counted).
+ *
+ * - SEG6_LOCAL_CNT_BYTES: identifies a counter that counts the total amount
+ *   of traffic in bytes of all packets that have been CORRECTLY processed by
+ *   an SRv6 Behavior instance (i.e., packets that generate errors or are
+ *   dropped are NOT counted).
+ *
+ * - SEG6_LOCAL_CNT_ERRORS: identifies a counter that counts the number of
+ *   packets that have NOT been properly processed by an SRv6 Behavior instance
+ *   (i.e., packets that generate errors or are dropped).
+ */
+enum {
+	SEG6_LOCAL_CNT_UNSPEC,
+	SEG6_LOCAL_CNT_PAD,		/* pad for 64 bits values */
+	SEG6_LOCAL_CNT_PACKETS,
+	SEG6_LOCAL_CNT_BYTES,
+	SEG6_LOCAL_CNT_ERRORS,
+	__SEG6_LOCAL_CNT_MAX,
+};
+
+#define SEG6_LOCAL_CNT_MAX (__SEG6_LOCAL_CNT_MAX - 1)
+
 #endif
diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c
index 566fc7ea..6edffd9e 100644
--- a/ip/iproute_lwtunnel.c
+++ b/ip/iproute_lwtunnel.c
@@ -266,6 +266,50 @@ static void print_encap_bpf_prog(FILE *fp, struct rtattr *encap,
 	}
 }
 
+static void print_seg6_local_counters(FILE *fp, struct rtattr *encap)
+{
+	__u64 packets = 0, bytes = 0, errors = 0;
+	struct rtattr *tb[SEG6_LOCAL_CNT_MAX + 1];
+
+	parse_rtattr_nested(tb, SEG6_LOCAL_CNT_MAX, encap);
+
+	if (is_json_context())
+		open_json_object("stats64");
+
+	if (tb[SEG6_LOCAL_CNT_PACKETS]) {
+		packets = rta_getattr_u64(tb[SEG6_LOCAL_CNT_PACKETS]);
+		if (is_json_context()) {
+			print_u64(PRINT_JSON, "packets", NULL, packets);
+		} else {
+			print_string(PRINT_FP, NULL, "%s ", "packets");
+			print_num(fp, 1, packets);
+		}
+	}
+
+	if (tb[SEG6_LOCAL_CNT_BYTES]) {
+		bytes = rta_getattr_u64(tb[SEG6_LOCAL_CNT_BYTES]);
+		if (is_json_context()) {
+			print_u64(PRINT_JSON, "bytes", NULL, bytes);
+		} else {
+			print_string(PRINT_FP, NULL, "%s ", "bytes");
+			print_num(fp, 1, bytes);
+		}
+	}
+
+	if (tb[SEG6_LOCAL_CNT_ERRORS]) {
+		errors = rta_getattr_u64(tb[SEG6_LOCAL_CNT_ERRORS]);
+		if (is_json_context()) {
+			print_u64(PRINT_JSON, "errors", NULL, errors);
+		} else {
+			print_string(PRINT_FP, NULL, "%s ", "errors");
+			print_num(fp, 1, errors);
+		}
+	}
+
+	if (is_json_context())
+		close_json_object();
+}
+
 static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
 {
 	struct rtattr *tb[SEG6_LOCAL_MAX + 1];
@@ -325,6 +369,9 @@ static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
 
 	if (tb[SEG6_LOCAL_BPF])
 		print_encap_bpf_prog(fp, tb[SEG6_LOCAL_BPF], "endpoint");
+
+	if (tb[SEG6_LOCAL_COUNTERS] && show_stats)
+		print_seg6_local_counters(fp, tb[SEG6_LOCAL_COUNTERS]);
 }
 
 static void print_encap_mpls(FILE *fp, struct rtattr *encap)
@@ -862,13 +909,39 @@ static int lwt_parse_bpf(struct rtattr *rta, size_t len,
 	return 0;
 }
 
+/* for the moment, counters are always initialized to zero by the kernel; so we
+ * do not expect to parse any argument here.
+ */
+static int seg6local_fill_counters(struct rtattr *rta, size_t len, int attr)
+{
+	struct rtattr *nest;
+	int ret;
+
+	nest = rta_nest(rta, len, attr);
+
+	ret = rta_addattr64(rta, len, SEG6_LOCAL_CNT_PACKETS, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = rta_addattr64(rta, len, SEG6_LOCAL_CNT_BYTES, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = rta_addattr64(rta, len, SEG6_LOCAL_CNT_ERRORS, 0);
+	if (ret < 0)
+		return ret;
+
+	rta_nest_end(rta, nest);
+	return 0;
+}
+
 static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
 				 char ***argvp)
 {
 	int segs_ok = 0, hmac_ok = 0, table_ok = 0, vrftable_ok = 0;
+	int action_ok = 0, srh_ok = 0, bpf_ok = 0, counters_ok = 0;
 	int nh4_ok = 0, nh6_ok = 0, iif_ok = 0, oif_ok = 0;
 	__u32 action = 0, table, vrftable, iif, oif;
-	int action_ok = 0, srh_ok = 0, bpf_ok = 0;
 	struct ipv6_sr_hdr *srh;
 	char **argv = *argvp;
 	int argc = *argcp;
@@ -932,6 +1005,11 @@ static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
 			if (!oif)
 				exit(nodev(*argv));
 			ret = rta_addattr32(rta, len, SEG6_LOCAL_OIF, oif);
+		} else if (strcmp(*argv, "count") == 0) {
+			if (counters_ok++)
+				duparg2("count", *argv);
+			ret = seg6local_fill_counters(rta, len,
+						      SEG6_LOCAL_COUNTERS);
 		} else if (strcmp(*argv, "srh") == 0) {
 			NEXT_ARG();
 			if (srh_ok++)
-- 
2.20.1


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

* Re: [RFC iproute2-next v2] seg6: add counters support for SRv6 Behaviors
  2021-04-15 18:06 [RFC iproute2-next v2] seg6: add counters support for SRv6 Behaviors Paolo Lungaroni
@ 2021-04-15 21:23 ` Stephen Hemminger
  2021-04-17 23:36   ` Paolo Lungaroni
  0 siblings, 1 reply; 3+ messages in thread
From: Stephen Hemminger @ 2021-04-15 21:23 UTC (permalink / raw)
  To: Paolo Lungaroni
  Cc: David Ahern, netdev, Jakub Kicinski, Stefano Salsano,
	Ahmed Abdelsalam, Andrea Mayer

On Thu, 15 Apr 2021 20:06:43 +0200
Paolo Lungaroni <paolo.lungaroni@uniroma2.it> wrote:

> +	if (is_json_context())
> +		open_json_object("stats64");
> +
> +	if (tb[SEG6_LOCAL_CNT_PACKETS]) {
> +		packets = rta_getattr_u64(tb[SEG6_LOCAL_CNT_PACKETS]);
> +		if (is_json_context()) {
> +			print_u64(PRINT_JSON, "packets", NULL, packets);
> +		} else {
> +			print_string(PRINT_FP, NULL, "%s ", "packets");
> +			print_num(fp, 1, packets);
> +		}
> +	}
> +
> +	if (tb[SEG6_LOCAL_CNT_BYTES]) {
> +		bytes = rta_getattr_u64(tb[SEG6_LOCAL_CNT_BYTES]);
> +		if (is_json_context()) {
> +			print_u64(PRINT_JSON, "bytes", NULL, bytes);
> +		} else {
> +			print_string(PRINT_FP, NULL, "%s ", "bytes");
> +			print_num(fp, 1, bytes);
> +		}
> +	}
> +
> +	if (tb[SEG6_LOCAL_CNT_ERRORS]) {
> +		errors = rta_getattr_u64(tb[SEG6_LOCAL_CNT_ERRORS]);
> +		if (is_json_context()) {
> +			print_u64(PRINT_JSON, "errors", NULL, errors);
> +		} else {
> +			print_string(PRINT_FP, NULL, "%s ", "errors");
> +			print_num(fp, 1, errors);
> +		}
> +	}
> +
> +	if (is_json_context())
> +		close_json_object();


The code would be cleaner with doing if (is_json_context()) once at outer loop.
See print_vf_stats64.

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

* Re: [RFC iproute2-next v2] seg6: add counters support for SRv6 Behaviors
  2021-04-15 21:23 ` Stephen Hemminger
@ 2021-04-17 23:36   ` Paolo Lungaroni
  0 siblings, 0 replies; 3+ messages in thread
From: Paolo Lungaroni @ 2021-04-17 23:36 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: David Ahern, netdev, Jakub Kicinski, Stefano Salsano,
	Ahmed Abdelsalam, Andrea Mayer, Paolo Lungaroni

Quoting Stephen Hemminger <stephen@networkplumber.org>:

> On Thu, 15 Apr 2021 20:06:43 +0200
> Paolo Lungaroni <paolo.lungaroni@uniroma2.it> wrote:
>
>> +	if (is_json_context())
>> +		open_json_object("stats64");
>> +
>> +	if (tb[SEG6_LOCAL_CNT_PACKETS]) {
>> +		packets = rta_getattr_u64(tb[SEG6_LOCAL_CNT_PACKETS]);
>> +		if (is_json_context()) {
>> +			print_u64(PRINT_JSON, "packets", NULL, packets);
>> +		} else {
>> +			print_string(PRINT_FP, NULL, "%s ", "packets");
>> +			print_num(fp, 1, packets);
>> +		}
>> +	}
>> +
>> +	if (tb[SEG6_LOCAL_CNT_BYTES]) {
>> +		bytes = rta_getattr_u64(tb[SEG6_LOCAL_CNT_BYTES]);
>> +		if (is_json_context()) {
>> +			print_u64(PRINT_JSON, "bytes", NULL, bytes);
>> +		} else {
>> +			print_string(PRINT_FP, NULL, "%s ", "bytes");
>> +			print_num(fp, 1, bytes);
>> +		}
>> +	}
>> +
>> +	if (tb[SEG6_LOCAL_CNT_ERRORS]) {
>> +		errors = rta_getattr_u64(tb[SEG6_LOCAL_CNT_ERRORS]);
>> +		if (is_json_context()) {
>> +			print_u64(PRINT_JSON, "errors", NULL, errors);
>> +		} else {
>> +			print_string(PRINT_FP, NULL, "%s ", "errors");
>> +			print_num(fp, 1, errors);
>> +		}
>> +	}
>> +
>> +	if (is_json_context())
>> +		close_json_object();
>
>
> The code would be cleaner with doing if (is_json_context()) once at  
> outer loop.
> See print_vf_stats64.

Hi Stephen,

thank you for your suggestion. We will change the code as you suggest.

Paolo.




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

end of thread, other threads:[~2021-04-17 23:36 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-15 18:06 [RFC iproute2-next v2] seg6: add counters support for SRv6 Behaviors Paolo Lungaroni
2021-04-15 21:23 ` Stephen Hemminger
2021-04-17 23:36   ` Paolo Lungaroni

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.