mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 10:01:39 -05:00
ipv6: fib_rules: Add DSCP mask matching
Extend IPv6 FIB rules to match on DSCP using a mask. Unlike IPv4, also initialize the DSCP mask when a non-zero 'tos' is specified as there is no difference in matching between 'tos' and 'dscp'. As a side effect, this makes it possible to match on 'dscp 0', like in IPv4. Reviewed-by: Petr Machata <petrm@nvidia.com> Signed-off-by: Ido Schimmel <idosch@nvidia.com> Reviewed-by: Guillaume Nault <gnault@redhat.com> Link: https://patch.msgid.link/20250220080525.831924-4-idosch@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
2ae00699b3
commit
c29165c272
@@ -29,6 +29,7 @@ struct fib6_rule {
|
||||
__be32 flowlabel;
|
||||
__be32 flowlabel_mask;
|
||||
dscp_t dscp;
|
||||
dscp_t dscp_mask;
|
||||
u8 dscp_full:1; /* DSCP or TOS selector */
|
||||
};
|
||||
|
||||
@@ -331,7 +332,7 @@ INDIRECT_CALLABLE_SCOPE int fib6_rule_match(struct fib_rule *rule,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (r->dscp && r->dscp != ip6_dscp(fl6->flowlabel))
|
||||
if ((r->dscp ^ ip6_dscp(fl6->flowlabel)) & r->dscp_mask)
|
||||
return 0;
|
||||
|
||||
if ((r->flowlabel ^ flowi6_get_flowlabel(fl6)) & r->flowlabel_mask)
|
||||
@@ -360,11 +361,35 @@ static int fib6_nl2rule_dscp(const struct nlattr *nla, struct fib6_rule *rule6,
|
||||
}
|
||||
|
||||
rule6->dscp = inet_dsfield_to_dscp(nla_get_u8(nla) << 2);
|
||||
rule6->dscp_mask = inet_dsfield_to_dscp(INET_DSCP_MASK);
|
||||
rule6->dscp_full = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fib6_nl2rule_dscp_mask(const struct nlattr *nla,
|
||||
struct fib6_rule *rule6,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
dscp_t dscp_mask;
|
||||
|
||||
if (!rule6->dscp_full) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, nla,
|
||||
"Cannot specify DSCP mask without DSCP value");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dscp_mask = inet_dsfield_to_dscp(nla_get_u8(nla) << 2);
|
||||
if (rule6->dscp & ~dscp_mask) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, nla, "Invalid DSCP mask");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rule6->dscp_mask = dscp_mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fib6_nl2rule_flowlabel(struct nlattr **tb, struct fib6_rule *rule6,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
@@ -409,10 +434,15 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
|
||||
goto errout;
|
||||
}
|
||||
rule6->dscp = inet_dsfield_to_dscp(frh->tos);
|
||||
rule6->dscp_mask = frh->tos ? inet_dsfield_to_dscp(INET_DSCP_MASK) : 0;
|
||||
|
||||
if (tb[FRA_DSCP] && fib6_nl2rule_dscp(tb[FRA_DSCP], rule6, extack) < 0)
|
||||
goto errout;
|
||||
|
||||
if (tb[FRA_DSCP_MASK] &&
|
||||
fib6_nl2rule_dscp_mask(tb[FRA_DSCP_MASK], rule6, extack) < 0)
|
||||
goto errout;
|
||||
|
||||
if ((tb[FRA_FLOWLABEL] || tb[FRA_FLOWLABEL_MASK]) &&
|
||||
fib6_nl2rule_flowlabel(tb, rule6, extack) < 0)
|
||||
goto errout;
|
||||
@@ -482,6 +512,14 @@ static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tb[FRA_DSCP_MASK]) {
|
||||
dscp_t dscp_mask;
|
||||
|
||||
dscp_mask = inet_dsfield_to_dscp(nla_get_u8(tb[FRA_DSCP_MASK]) << 2);
|
||||
if (!rule6->dscp_full || rule6->dscp_mask != dscp_mask)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tb[FRA_FLOWLABEL] &&
|
||||
nla_get_be32(tb[FRA_FLOWLABEL]) != rule6->flowlabel)
|
||||
return 0;
|
||||
@@ -512,7 +550,9 @@ static int fib6_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
|
||||
if (rule6->dscp_full) {
|
||||
frh->tos = 0;
|
||||
if (nla_put_u8(skb, FRA_DSCP,
|
||||
inet_dscp_to_dsfield(rule6->dscp) >> 2))
|
||||
inet_dscp_to_dsfield(rule6->dscp) >> 2) ||
|
||||
nla_put_u8(skb, FRA_DSCP_MASK,
|
||||
inet_dscp_to_dsfield(rule6->dscp_mask) >> 2))
|
||||
goto nla_put_failure;
|
||||
} else {
|
||||
frh->tos = inet_dscp_to_dsfield(rule6->dscp);
|
||||
@@ -539,6 +579,7 @@ static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule)
|
||||
return nla_total_size(16) /* dst */
|
||||
+ nla_total_size(16) /* src */
|
||||
+ nla_total_size(1) /* dscp */
|
||||
+ nla_total_size(1) /* dscp mask */
|
||||
+ nla_total_size(4) /* flowlabel */
|
||||
+ nla_total_size(4); /* flowlabel mask */
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user