Skip to content

Commit 2cf6300

Browse files
idoschkuba-moo
authored andcommitted
ipv6: fib_rules: Add DSCP selector support
Implement support for the new DSCP selector that allows IPv6 FIB rules to match on the entire DSCP field. This is done despite the fact that the above can be achieved using the existing TOS selector, so that user space program will be able to work with IPv4 and IPv6 rules in the same way. Differentiate between both selectors by adding a new bit in the IPv6 FIB rule structure that is only set when the 'FRA_DSCP' attribute is specified by user space. Reject rules that use both selectors. Signed-off-by: Ido Schimmel <idosch@nvidia.com> Reviewed-by: Guillaume Nault <gnault@redhat.com> Reviewed-by: David Ahern <dsahern@kernel.org> Link: https://patch.msgid.link/20240911093748.3662015-4-idosch@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent b9455fe commit 2cf6300

1 file changed

Lines changed: 40 additions & 3 deletions

File tree

net/ipv6/fib6_rules.c

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ struct fib6_rule {
2727
struct rt6key src;
2828
struct rt6key dst;
2929
dscp_t dscp;
30+
u8 dscp_full:1; /* DSCP or TOS selector */
3031
};
3132

3233
static bool fib6_rule_matchall(const struct fib_rule *rule)
@@ -345,6 +346,20 @@ INDIRECT_CALLABLE_SCOPE int fib6_rule_match(struct fib_rule *rule,
345346
return 1;
346347
}
347348

349+
static int fib6_nl2rule_dscp(const struct nlattr *nla, struct fib6_rule *rule6,
350+
struct netlink_ext_ack *extack)
351+
{
352+
if (rule6->dscp) {
353+
NL_SET_ERR_MSG(extack, "Cannot specify both TOS and DSCP");
354+
return -EINVAL;
355+
}
356+
357+
rule6->dscp = inet_dsfield_to_dscp(nla_get_u8(nla) << 2);
358+
rule6->dscp_full = true;
359+
360+
return 0;
361+
}
362+
348363
static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
349364
struct fib_rule_hdr *frh,
350365
struct nlattr **tb,
@@ -361,6 +376,9 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
361376
}
362377
rule6->dscp = inet_dsfield_to_dscp(frh->tos);
363378

379+
if (tb[FRA_DSCP] && fib6_nl2rule_dscp(tb[FRA_DSCP], rule6, extack) < 0)
380+
goto errout;
381+
364382
if (rule->action == FR_ACT_TO_TBL && !rule->l3mdev) {
365383
if (rule->table == RT6_TABLE_UNSPEC) {
366384
NL_SET_ERR_MSG(extack, "Invalid table");
@@ -413,9 +431,19 @@ static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
413431
if (frh->dst_len && (rule6->dst.plen != frh->dst_len))
414432
return 0;
415433

416-
if (frh->tos && inet_dscp_to_dsfield(rule6->dscp) != frh->tos)
434+
if (frh->tos &&
435+
(rule6->dscp_full ||
436+
inet_dscp_to_dsfield(rule6->dscp) != frh->tos))
417437
return 0;
418438

439+
if (tb[FRA_DSCP]) {
440+
dscp_t dscp;
441+
442+
dscp = inet_dsfield_to_dscp(nla_get_u8(tb[FRA_DSCP]) << 2);
443+
if (!rule6->dscp_full || rule6->dscp != dscp)
444+
return 0;
445+
}
446+
419447
if (frh->src_len &&
420448
nla_memcmp(tb[FRA_SRC], &rule6->src.addr, sizeof(struct in6_addr)))
421449
return 0;
@@ -434,7 +462,15 @@ static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
434462

435463
frh->dst_len = rule6->dst.plen;
436464
frh->src_len = rule6->src.plen;
437-
frh->tos = inet_dscp_to_dsfield(rule6->dscp);
465+
466+
if (rule6->dscp_full) {
467+
frh->tos = 0;
468+
if (nla_put_u8(skb, FRA_DSCP,
469+
inet_dscp_to_dsfield(rule6->dscp) >> 2))
470+
goto nla_put_failure;
471+
} else {
472+
frh->tos = inet_dscp_to_dsfield(rule6->dscp);
473+
}
438474

439475
if ((rule6->dst.plen &&
440476
nla_put_in6_addr(skb, FRA_DST, &rule6->dst.addr)) ||
@@ -450,7 +486,8 @@ static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
450486
static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule)
451487
{
452488
return nla_total_size(16) /* dst */
453-
+ nla_total_size(16); /* src */
489+
+ nla_total_size(16) /* src */
490+
+ nla_total_size(1); /* dscp */
454491
}
455492

456493
static void fib6_rule_flush_cache(struct fib_rules_ops *ops)

0 commit comments

Comments
 (0)