All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ido Schimmel <idosch@nvidia.com>
To: <netdev@vger.kernel.org>
Cc: <dsahern@gmail.com>, <stephen@networkplumber.org>,
	<petrm@nvidia.com>, <gnault@redhat.com>,
	Ido Schimmel <idosch@nvidia.com>
Subject: [PATCH iproute2-next 3/3] iprule: Add flow label support
Date: Mon, 23 Dec 2024 10:26:42 +0200	[thread overview]
Message-ID: <20241223082642.48634-4-idosch@nvidia.com> (raw)
In-Reply-To: <20241223082642.48634-1-idosch@nvidia.com>

Add support for 'flowlabel' selector in ip-rule.

Rules can be added with or without a mask in which case exact match is
used:

 # ip -6 rule add flowlabel 0x12345 table 100
 # ip -6 rule add flowlabel 0x11/0xff table 200
 # ip -6 rule add flowlabel 0x54321 table 300
 # ip -6 rule del flowlabel 0x54321 table 300

Dump output:

 $ ip -6 rule show
 0:      from all lookup local
 32764:  from all lookup 200 flowlabel 0x11/0xff
 32765:  from all lookup 100 flowlabel 0x12345
 32766:  from all lookup main

Dump can be filtered by flow label value and mask:

 $ ip -6 rule show flowlabel 0x12345
 32765:  from all lookup 100 flowlabel 0x12345
 $ ip -6 rule show flowlabel 0x11/0xff
 32764:  from all lookup 200 flowlabel 0x11/0xff

JSON output:

 $ ip -6 -j -p rule show flowlabel 0x12345
 [ {
         "priority": 32765,
         "src": "all",
         "table": "100",
         "flowlabel": "0x12345",
         "flowlabel_mask": "0xfffff"
     } ]
 $ ip -6 -j -p rule show flowlabel 0x11/0xff
 [ {
         "priority": 32764,
         "src": "all",
         "table": "200",
         "flowlabel": "0x11",
         "flowlabel_mask": "0xff"
     } ]

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
---
 ip/iprule.c           | 66 ++++++++++++++++++++++++++++++++++++++++++-
 man/man8/ip-rule.8.in |  8 +++++-
 2 files changed, 72 insertions(+), 2 deletions(-)

diff --git a/ip/iprule.c b/ip/iprule.c
index ae067c72a66d..f239f91573a7 100644
--- a/ip/iprule.c
+++ b/ip/iprule.c
@@ -46,7 +46,7 @@ static void usage(void)
 		"            [ ipproto PROTOCOL ]\n"
 		"            [ sport [ NUMBER | NUMBER-NUMBER ]\n"
 		"            [ dport [ NUMBER | NUMBER-NUMBER ] ]\n"
-		"            [ dscp DSCP ]\n"
+		"            [ dscp DSCP ] [ flowlabel FLOWLABEL[/MASK] ]\n"
 		"ACTION := [ table TABLE_ID ]\n"
 		"          [ protocol PROTO ]\n"
 		"          [ nat ADDRESS ]\n"
@@ -69,6 +69,7 @@ static struct
 	unsigned int pref, prefmask;
 	unsigned int fwmark, fwmask;
 	unsigned int dscp, dscpmask;
+	__u32 flowlabel, flowlabel_mask;
 	uint64_t tun_id;
 	char iif[IFNAMSIZ];
 	char oif[IFNAMSIZ];
@@ -232,6 +233,19 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
 		}
 	}
 
+	if (filter.flowlabel_mask) {
+		__u32 flowlabel, flowlabel_mask;
+
+		if (!tb[FRA_FLOWLABEL] || !tb[FRA_FLOWLABEL_MASK])
+			return false;
+		flowlabel = rta_getattr_be32(tb[FRA_FLOWLABEL]);
+		flowlabel_mask = rta_getattr_be32(tb[FRA_FLOWLABEL_MASK]);
+
+		if (filter.flowlabel != flowlabel ||
+		    filter.flowlabel_mask != flowlabel_mask)
+			return false;
+	}
+
 	table = frh_get_table(frh, tb);
 	if (filter.tb > 0 && filter.tb ^ table)
 		return false;
@@ -489,6 +503,23 @@ int print_rule(struct nlmsghdr *n, void *arg)
 			     rtnl_dscp_n2a(dscp, b1, sizeof(b1)));
 	}
 
+	/* The kernel will either provide both attributes, or none */
+	if (tb[FRA_FLOWLABEL] && tb[FRA_FLOWLABEL_MASK]) {
+		__u32 flowlabel, flowlabel_mask;
+
+		flowlabel = rta_getattr_be32(tb[FRA_FLOWLABEL]);
+		flowlabel_mask = rta_getattr_be32(tb[FRA_FLOWLABEL_MASK]);
+
+		print_0xhex(PRINT_ANY, "flowlabel", " flowlabel %#llx",
+			    flowlabel);
+		if (flowlabel_mask == LABEL_MAX_MASK)
+			print_0xhex(PRINT_JSON, "flowlabel_mask", NULL,
+				    flowlabel_mask);
+		else
+			print_0xhex(PRINT_ANY, "flowlabel_mask", "/%#llx",
+				    flowlabel_mask);
+	}
+
 	print_string(PRINT_FP, NULL, "\n", "");
 	close_json_object();
 	fflush(fp);
@@ -569,6 +600,24 @@ static int flush_rule(struct nlmsghdr *n, void *arg)
 	return 0;
 }
 
+static void iprule_flowlabel_parse(char *arg, __u32 *flowlabel,
+				   __u32 *flowlabel_mask)
+{
+	char *slash;
+
+	slash = strchr(arg, '/');
+	if (slash != NULL)
+		*slash = '\0';
+	if (get_u32(flowlabel, arg, 0))
+		invarg("invalid flowlabel\n", arg);
+	if (slash) {
+		if (get_u32(flowlabel_mask, slash + 1, 0))
+			invarg("invalid flowlabel mask\n", slash + 1);
+	} else {
+		*flowlabel_mask = LABEL_MAX_MASK;
+	}
+}
+
 static int iprule_list_flush_or_save(int argc, char **argv, int action)
 {
 	rtnl_filter_t filter_fn;
@@ -726,6 +775,11 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
 				invarg("invalid dscp\n", *argv);
 			filter.dscp = dscp;
 			filter.dscpmask = 1;
+		} else if (strcmp(*argv, "flowlabel") == 0) {
+			NEXT_ARG();
+
+			iprule_flowlabel_parse(*argv, &filter.flowlabel,
+					       &filter.flowlabel_mask);
 		} else {
 			if (matches(*argv, "dst") == 0 ||
 			    matches(*argv, "to") == 0) {
@@ -1011,6 +1065,16 @@ static int iprule_modify(int cmd, int argc, char **argv)
 			if (rtnl_dscp_a2n(&dscp, *argv))
 				invarg("invalid dscp\n", *argv);
 			addattr8(&req.n, sizeof(req), FRA_DSCP, dscp);
+		} else if (strcmp(*argv, "flowlabel") == 0) {
+			__u32 flowlabel, flowlabel_mask;
+
+			NEXT_ARG();
+			iprule_flowlabel_parse(*argv, &flowlabel,
+					       &flowlabel_mask);
+			addattr32(&req.n, sizeof(req), FRA_FLOWLABEL,
+				  htonl(flowlabel));
+			addattr32(&req.n, sizeof(req), FRA_FLOWLABEL_MASK,
+				  htonl(flowlabel_mask));
 		} else {
 			int type;
 
diff --git a/man/man8/ip-rule.8.in b/man/man8/ip-rule.8.in
index 51f3050ae8f8..6fc741d4f470 100644
--- a/man/man8/ip-rule.8.in
+++ b/man/man8/ip-rule.8.in
@@ -58,7 +58,9 @@ ip-rule \- routing policy database management
 .IR NUMBER " | "
 .IR NUMBER "-" NUMBER " ] ] [ "
 .B  tun_id
-.IR TUN_ID " ]"
+.IR TUN_ID " ] [ "
+.B  flowlabel
+.IR FLOWLABEL\fR[\fB/\fIMASK "] ]"
 .BR
 
 
@@ -322,6 +324,10 @@ In the last case the router does not translate the packets, but
 masquerades them to this address.
 Using map-to instead of nat means the same thing.
 
+.TP
+.BI flowlabel " FLOWLABEL\fR[\fB/\fIMASK\fR]"
+select the IPv6 flow label to match with an optional mask.
+
 .B Warning:
 Changes to the RPDB made with these commands do not become active
 immediately. It is assumed that after a script finishes a batch of
-- 
2.47.1


  parent reply	other threads:[~2024-12-23  8:30 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-12-23  8:26 [PATCH iproute2-next 0/3] Add flow label support to ip-rule and route get Ido Schimmel
2024-12-23  8:26 ` [PATCH iproute2-next 1/3] Sync uAPI headers Ido Schimmel
2024-12-23  8:26 ` [PATCH iproute2-next 2/3] ip: route: Add IPv6 flow label support Ido Schimmel
2024-12-23  8:26 ` Ido Schimmel [this message]
2024-12-24 19:34   ` [PATCH iproute2-next 3/3] iprule: Add " Stephen Hemminger
2024-12-23 14:59 ` [PATCH iproute2-next 0/3] Add flow label support to ip-rule and route get Guillaume Nault

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20241223082642.48634-4-idosch@nvidia.com \
    --to=idosch@nvidia.com \
    --cc=dsahern@gmail.com \
    --cc=gnault@redhat.com \
    --cc=netdev@vger.kernel.org \
    --cc=petrm@nvidia.com \
    --cc=stephen@networkplumber.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.