Skip to content

Commit 6b3099e

Browse files
author
Paolo Abeni
committed
Merge branch 'net-fib_rules-add-flow-label-selector-support'
Ido Schimmel says: ==================== net: fib_rules: Add flow label selector support In some deployments users would like to encode path information into certain bits of the IPv6 flow label, the UDP source port and the DSCP and use this information to route packets accordingly. Redirecting traffic to a routing table based on the flow label is not currently possible with Linux as FIB rules cannot match on it despite the flow label being available in the IPv6 flow key. This patchset extends FIB rules to match on the flow label with a mask. Future patches will add mask attributes to L4 ports and DSCP matches. Patches #1-#5 gradually extend FIB rules to match on the flow label. Patches #6-#7 allow user space to specify a flow label in route get requests. This is useful for both debugging and testing. Patch #8 adjusts the fib6_table_lookup tracepoint to print the flow label to the trace buffer for better observability. Patch #9 extends the FIB rule selftest with flow label test cases while utilizing the route get functionality from patch #6. ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents 4fefbc6 + 5760711 commit 6b3099e

File tree

10 files changed

+140
-6
lines changed

10 files changed

+140
-6
lines changed

Documentation/netlink/specs/rt_route.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,11 @@ attribute-sets:
177177
-
178178
name: rta-nh-id
179179
type: u32
180+
-
181+
name: rta-flowlabel
182+
type: u32
183+
byte-order: big-endian
184+
display-hint: hex
180185
-
181186
name: rta-metrics
182187
attributes:
@@ -260,6 +265,7 @@ operations:
260265
- rta-dport
261266
- rta-mark
262267
- rta-uid
268+
- rta-flowlabel
263269
reply:
264270
value: 24
265271
attributes: &all-route-attrs
@@ -299,6 +305,7 @@ operations:
299305
- rta-sport
300306
- rta-dport
301307
- rta-nh-id
308+
- rta-flowlabel
302309
dump:
303310
request:
304311
value: 26

Documentation/netlink/specs/rt_rule.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,16 @@ attribute-sets:
172172
-
173173
name: dscp
174174
type: u8
175+
-
176+
name: flowlabel
177+
type: u32
178+
byte-order: big-endian
179+
display-hint: hex
180+
-
181+
name: flowlabel-mask
182+
type: u32
183+
byte-order: big-endian
184+
display-hint: hex
175185

176186
operations:
177187
enum-model: directional
@@ -203,6 +213,8 @@ operations:
203213
- sport-range
204214
- dport-range
205215
- dscp
216+
- flowlabel
217+
- flowlabel-mask
206218
-
207219
name: newrule-ntf
208220
doc: Notify a rule creation

include/trace/events/fib6.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ TRACE_EVENT(fib6_table_lookup,
2222
__field( int, err )
2323
__field( int, oif )
2424
__field( int, iif )
25+
__field( u32, flowlabel )
2526
__field( __u8, tos )
2627
__field( __u8, scope )
2728
__field( __u8, flags )
@@ -42,6 +43,7 @@ TRACE_EVENT(fib6_table_lookup,
4243
__entry->err = ip6_rt_type_to_error(res->fib6_type);
4344
__entry->oif = flp->flowi6_oif;
4445
__entry->iif = flp->flowi6_iif;
46+
__entry->flowlabel = ntohl(flowi6_get_flowlabel(flp));
4547
__entry->tos = ip6_tclass(flp->flowlabel);
4648
__entry->scope = flp->flowi6_scope;
4749
__entry->flags = flp->flowi6_flags;
@@ -76,11 +78,11 @@ TRACE_EVENT(fib6_table_lookup,
7678
}
7779
),
7880

79-
TP_printk("table %3u oif %d iif %d proto %u %pI6c/%u -> %pI6c/%u tos %d scope %d flags %x ==> dev %s gw %pI6c err %d",
81+
TP_printk("table %3u oif %d iif %d proto %u %pI6c/%u -> %pI6c/%u flowlabel %#x tos %d scope %d flags %x ==> dev %s gw %pI6c err %d",
8082
__entry->tb_id, __entry->oif, __entry->iif, __entry->proto,
8183
__entry->src, __entry->sport, __entry->dst, __entry->dport,
82-
__entry->tos, __entry->scope, __entry->flags,
83-
__entry->name, __entry->gw, __entry->err)
84+
__entry->flowlabel, __entry->tos, __entry->scope,
85+
__entry->flags, __entry->name, __entry->gw, __entry->err)
8486
);
8587

8688
#endif /* _TRACE_FIB6_H */

include/uapi/linux/fib_rules.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ enum {
6868
FRA_SPORT_RANGE, /* sport */
6969
FRA_DPORT_RANGE, /* dport */
7070
FRA_DSCP, /* dscp */
71+
FRA_FLOWLABEL, /* flowlabel */
72+
FRA_FLOWLABEL_MASK, /* flowlabel mask */
7173
__FRA_MAX
7274
};
7375

include/uapi/linux/rtnetlink.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ enum rtattr_type_t {
393393
RTA_SPORT,
394394
RTA_DPORT,
395395
RTA_NH_ID,
396+
RTA_FLOWLABEL,
396397
__RTA_MAX
397398
};
398399

net/core/fib_rules.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,8 @@ static const struct nla_policy fib_rule_policy[FRA_MAX + 1] = {
770770
[FRA_SPORT_RANGE] = { .len = sizeof(struct fib_rule_port_range) },
771771
[FRA_DPORT_RANGE] = { .len = sizeof(struct fib_rule_port_range) },
772772
[FRA_DSCP] = NLA_POLICY_MAX(NLA_U8, INET_DSCP_MASK >> 2),
773+
[FRA_FLOWLABEL] = { .type = NLA_BE32 },
774+
[FRA_FLOWLABEL_MASK] = { .type = NLA_BE32 },
773775
};
774776

775777
int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh,

net/ipv4/fib_rules.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,12 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
249249
int err = -EINVAL;
250250
struct fib4_rule *rule4 = (struct fib4_rule *) rule;
251251

252+
if (tb[FRA_FLOWLABEL] || tb[FRA_FLOWLABEL_MASK]) {
253+
NL_SET_ERR_MSG(extack,
254+
"Flow label cannot be specified for IPv4 FIB rules");
255+
goto errout;
256+
}
257+
252258
if (!inet_validate_dscp(frh->tos)) {
253259
NL_SET_ERR_MSG(extack,
254260
"Invalid dsfield (tos): ECN bits must be 0");

net/ipv6/fib6_rules.c

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ struct fib6_rule {
2626
struct fib_rule common;
2727
struct rt6key src;
2828
struct rt6key dst;
29+
__be32 flowlabel;
30+
__be32 flowlabel_mask;
2931
dscp_t dscp;
3032
u8 dscp_full:1; /* DSCP or TOS selector */
3133
};
@@ -34,7 +36,7 @@ static bool fib6_rule_matchall(const struct fib_rule *rule)
3436
{
3537
struct fib6_rule *r = container_of(rule, struct fib6_rule, common);
3638

37-
if (r->dst.plen || r->src.plen || r->dscp)
39+
if (r->dst.plen || r->src.plen || r->dscp || r->flowlabel_mask)
3840
return false;
3941
return fib_rule_matchall(rule);
4042
}
@@ -332,6 +334,9 @@ INDIRECT_CALLABLE_SCOPE int fib6_rule_match(struct fib_rule *rule,
332334
if (r->dscp && r->dscp != ip6_dscp(fl6->flowlabel))
333335
return 0;
334336

337+
if ((r->flowlabel ^ flowi6_get_flowlabel(fl6)) & r->flowlabel_mask)
338+
return 0;
339+
335340
if (rule->ip_proto && (rule->ip_proto != fl6->flowi6_proto))
336341
return 0;
337342

@@ -360,6 +365,35 @@ static int fib6_nl2rule_dscp(const struct nlattr *nla, struct fib6_rule *rule6,
360365
return 0;
361366
}
362367

368+
static int fib6_nl2rule_flowlabel(struct nlattr **tb, struct fib6_rule *rule6,
369+
struct netlink_ext_ack *extack)
370+
{
371+
__be32 flowlabel, flowlabel_mask;
372+
373+
if (NL_REQ_ATTR_CHECK(extack, NULL, tb, FRA_FLOWLABEL) ||
374+
NL_REQ_ATTR_CHECK(extack, NULL, tb, FRA_FLOWLABEL_MASK))
375+
return -EINVAL;
376+
377+
flowlabel = nla_get_be32(tb[FRA_FLOWLABEL]);
378+
flowlabel_mask = nla_get_be32(tb[FRA_FLOWLABEL_MASK]);
379+
380+
if (flowlabel_mask & ~IPV6_FLOWLABEL_MASK) {
381+
NL_SET_ERR_MSG_ATTR(extack, tb[FRA_FLOWLABEL_MASK],
382+
"Invalid flow label mask");
383+
return -EINVAL;
384+
}
385+
386+
if (flowlabel & ~flowlabel_mask) {
387+
NL_SET_ERR_MSG(extack, "Flow label and mask do not match");
388+
return -EINVAL;
389+
}
390+
391+
rule6->flowlabel = flowlabel;
392+
rule6->flowlabel_mask = flowlabel_mask;
393+
394+
return 0;
395+
}
396+
363397
static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
364398
struct fib_rule_hdr *frh,
365399
struct nlattr **tb,
@@ -379,6 +413,10 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
379413
if (tb[FRA_DSCP] && fib6_nl2rule_dscp(tb[FRA_DSCP], rule6, extack) < 0)
380414
goto errout;
381415

416+
if ((tb[FRA_FLOWLABEL] || tb[FRA_FLOWLABEL_MASK]) &&
417+
fib6_nl2rule_flowlabel(tb, rule6, extack) < 0)
418+
goto errout;
419+
382420
if (rule->action == FR_ACT_TO_TBL && !rule->l3mdev) {
383421
if (rule->table == RT6_TABLE_UNSPEC) {
384422
NL_SET_ERR_MSG(extack, "Invalid table");
@@ -444,6 +482,14 @@ static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
444482
return 0;
445483
}
446484

485+
if (tb[FRA_FLOWLABEL] &&
486+
nla_get_be32(tb[FRA_FLOWLABEL]) != rule6->flowlabel)
487+
return 0;
488+
489+
if (tb[FRA_FLOWLABEL_MASK] &&
490+
nla_get_be32(tb[FRA_FLOWLABEL_MASK]) != rule6->flowlabel_mask)
491+
return 0;
492+
447493
if (frh->src_len &&
448494
nla_memcmp(tb[FRA_SRC], &rule6->src.addr, sizeof(struct in6_addr)))
449495
return 0;
@@ -472,6 +518,11 @@ static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
472518
frh->tos = inet_dscp_to_dsfield(rule6->dscp);
473519
}
474520

521+
if (rule6->flowlabel_mask &&
522+
(nla_put_be32(skb, FRA_FLOWLABEL, rule6->flowlabel) ||
523+
nla_put_be32(skb, FRA_FLOWLABEL_MASK, rule6->flowlabel_mask)))
524+
goto nla_put_failure;
525+
475526
if ((rule6->dst.plen &&
476527
nla_put_in6_addr(skb, FRA_DST, &rule6->dst.addr)) ||
477528
(rule6->src.plen &&
@@ -487,7 +538,9 @@ static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule)
487538
{
488539
return nla_total_size(16) /* dst */
489540
+ nla_total_size(16) /* src */
490-
+ nla_total_size(1); /* dscp */
541+
+ nla_total_size(1) /* dscp */
542+
+ nla_total_size(4) /* flowlabel */
543+
+ nla_total_size(4); /* flowlabel mask */
491544
}
492545

493546
static void fib6_rule_flush_cache(struct fib_rules_ops *ops)

net/ipv6/route.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5005,6 +5005,7 @@ static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
50055005
[RTA_SPORT] = { .type = NLA_U16 },
50065006
[RTA_DPORT] = { .type = NLA_U16 },
50075007
[RTA_NH_ID] = { .type = NLA_U32 },
5008+
[RTA_FLOWLABEL] = { .type = NLA_BE32 },
50085009
};
50095010

50105011
static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -5030,6 +5031,12 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
50305031
goto errout;
50315032
}
50325033

5034+
if (tb[RTA_FLOWLABEL]) {
5035+
NL_SET_ERR_MSG_ATTR(extack, tb[RTA_FLOWLABEL],
5036+
"Flow label cannot be specified for this operation");
5037+
goto errout;
5038+
}
5039+
50335040
*cfg = (struct fib6_config){
50345041
.fc_table = rtm->rtm_table,
50355042
.fc_dst_len = rtm->rtm_dst_len,
@@ -6013,6 +6020,13 @@ static int inet6_rtm_valid_getroute_req(struct sk_buff *skb,
60136020
return -EINVAL;
60146021
}
60156022

6023+
if (tb[RTA_FLOWLABEL] &&
6024+
(nla_get_be32(tb[RTA_FLOWLABEL]) & ~IPV6_FLOWLABEL_MASK)) {
6025+
NL_SET_ERR_MSG_ATTR(extack, tb[RTA_FLOWLABEL],
6026+
"Invalid flow label");
6027+
return -EINVAL;
6028+
}
6029+
60166030
for (i = 0; i <= RTA_MAX; i++) {
60176031
if (!tb[i])
60186032
continue;
@@ -6027,6 +6041,7 @@ static int inet6_rtm_valid_getroute_req(struct sk_buff *skb,
60276041
case RTA_SPORT:
60286042
case RTA_DPORT:
60296043
case RTA_IP_PROTO:
6044+
case RTA_FLOWLABEL:
60306045
break;
60316046
default:
60326047
NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in get route request");
@@ -6049,6 +6064,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
60496064
struct sk_buff *skb;
60506065
struct rtmsg *rtm;
60516066
struct flowi6 fl6 = {};
6067+
__be32 flowlabel;
60526068
bool fibmatch;
60536069

60546070
err = inet6_rtm_valid_getroute_req(in_skb, nlh, tb, extack);
@@ -6057,7 +6073,6 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
60576073

60586074
err = -EINVAL;
60596075
rtm = nlmsg_data(nlh);
6060-
fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0);
60616076
fibmatch = !!(rtm->rtm_flags & RTM_F_FIB_MATCH);
60626077

60636078
if (tb[RTA_SRC]) {
@@ -6103,6 +6118,9 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
61036118
goto errout;
61046119
}
61056120

6121+
flowlabel = nla_get_be32_default(tb[RTA_FLOWLABEL], 0);
6122+
fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, flowlabel);
6123+
61066124
if (iif) {
61076125
struct net_device *dev;
61086126
int flags = 0;

tools/testing/selftests/net/fib_rule_tests.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,37 @@ fib_rule6_test()
291291
"$getnomatch" "iif dscp redirect to table" \
292292
"iif dscp no redirect to table"
293293
fi
294+
295+
fib_check_iproute_support "flowlabel" "flowlabel"
296+
if [ $? -eq 0 ]; then
297+
match="flowlabel 0xfffff"
298+
getmatch="flowlabel 0xfffff"
299+
getnomatch="flowlabel 0xf"
300+
fib_rule6_test_match_n_redirect "$match" "$getmatch" \
301+
"$getnomatch" "flowlabel redirect to table" \
302+
"flowlabel no redirect to table"
303+
304+
match="flowlabel 0xfffff"
305+
getmatch="from $SRC_IP6 iif $DEV flowlabel 0xfffff"
306+
getnomatch="from $SRC_IP6 iif $DEV flowlabel 0xf"
307+
fib_rule6_test_match_n_redirect "$match" "$getmatch" \
308+
"$getnomatch" "iif flowlabel redirect to table" \
309+
"iif flowlabel no redirect to table"
310+
311+
match="flowlabel 0x08000/0x08000"
312+
getmatch="flowlabel 0xfffff"
313+
getnomatch="flowlabel 0xf7fff"
314+
fib_rule6_test_match_n_redirect "$match" "$getmatch" \
315+
"$getnomatch" "flowlabel masked redirect to table" \
316+
"flowlabel masked no redirect to table"
317+
318+
match="flowlabel 0x08000/0x08000"
319+
getmatch="from $SRC_IP6 iif $DEV flowlabel 0xfffff"
320+
getnomatch="from $SRC_IP6 iif $DEV flowlabel 0xf7fff"
321+
fib_rule6_test_match_n_redirect "$match" "$getmatch" \
322+
"$getnomatch" "iif flowlabel masked redirect to table" \
323+
"iif flowlabel masked no redirect to table"
324+
fi
294325
}
295326

296327
fib_rule6_vrf_test()

0 commit comments

Comments
 (0)