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 <idosch@nvidia.com>
Reviewed-by: Guillaume Nault <gnault@redhat.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
This commit is contained in:
committed by
David Ahern
parent
35ae138e2c
commit
0bd19d4645
66
ip/iprule.c
66
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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user