From: Ido Schimmel Date: Mon, 30 Dec 2024 08:58:10 +0000 (+0200) Subject: iprule: Add flow label support X-Git-Tag: v6.14.0~8^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0bd19d4645ce5bf3ad809f895859ba7a9c8d838e;p=thirdparty%2Fiproute2.git iprule: Add flow label support 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 Reviewed-by: Guillaume Nault Signed-off-by: David Ahern --- diff --git a/ip/iprule.c b/ip/iprule.c index ae067c72..ea30d418 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", arg); + if (slash) { + if (get_u32(flowlabel_mask, slash + 1, 0)) + invarg("invalid flowlabel mask", 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 51f3050a..6fc741d4 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