mirror of
https://github.com/torvalds/linux.git
synced 2026-03-13 22:36:17 +01:00
ipv4: fib_rules: Add DSCP mask matching
Extend IPv4 FIB rules to match on DSCP using a mask. The mask is only set in rules that match on DSCP (not TOS) and initialized to cover the entire DSCP field if the mask attribute is not specified. 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-3-idosch@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
ca4edd969a
commit
2ae00699b3
1 changed files with 44 additions and 3 deletions
|
|
@ -37,6 +37,7 @@ struct fib4_rule {
|
|||
u8 dst_len;
|
||||
u8 src_len;
|
||||
dscp_t dscp;
|
||||
dscp_t dscp_mask;
|
||||
u8 dscp_full:1; /* DSCP or TOS selector */
|
||||
__be32 src;
|
||||
__be32 srcmask;
|
||||
|
|
@ -192,7 +193,8 @@ INDIRECT_CALLABLE_SCOPE int fib4_rule_match(struct fib_rule *rule,
|
|||
* to mask the upper three DSCP bits prior to matching to maintain
|
||||
* legacy behavior.
|
||||
*/
|
||||
if (r->dscp_full && r->dscp != inet_dsfield_to_dscp(fl4->flowi4_tos))
|
||||
if (r->dscp_full &&
|
||||
(r->dscp ^ inet_dsfield_to_dscp(fl4->flowi4_tos)) & r->dscp_mask)
|
||||
return 0;
|
||||
else if (!r->dscp_full && r->dscp &&
|
||||
!fib_dscp_masked_match(r->dscp, fl4))
|
||||
|
|
@ -235,11 +237,35 @@ static int fib4_nl2rule_dscp(const struct nlattr *nla, struct fib4_rule *rule4,
|
|||
}
|
||||
|
||||
rule4->dscp = inet_dsfield_to_dscp(nla_get_u8(nla) << 2);
|
||||
rule4->dscp_mask = inet_dsfield_to_dscp(INET_DSCP_MASK);
|
||||
rule4->dscp_full = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fib4_nl2rule_dscp_mask(const struct nlattr *nla,
|
||||
struct fib4_rule *rule4,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
dscp_t dscp_mask;
|
||||
|
||||
if (!rule4->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 (rule4->dscp & ~dscp_mask) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, nla, "Invalid DSCP mask");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rule4->dscp_mask = dscp_mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
|
||||
struct fib_rule_hdr *frh,
|
||||
struct nlattr **tb,
|
||||
|
|
@ -271,6 +297,10 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
|
|||
fib4_nl2rule_dscp(tb[FRA_DSCP], rule4, extack) < 0)
|
||||
goto errout;
|
||||
|
||||
if (tb[FRA_DSCP_MASK] &&
|
||||
fib4_nl2rule_dscp_mask(tb[FRA_DSCP_MASK], rule4, extack) < 0)
|
||||
goto errout;
|
||||
|
||||
/* split local/main if they are not already split */
|
||||
err = fib_unmerge(net);
|
||||
if (err)
|
||||
|
|
@ -366,6 +396,14 @@ static int fib4_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 (!rule4->dscp_full || rule4->dscp_mask != dscp_mask)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IP_ROUTE_CLASSID
|
||||
if (tb[FRA_FLOW] && (rule4->tclassid != nla_get_u32(tb[FRA_FLOW])))
|
||||
return 0;
|
||||
|
|
@ -391,7 +429,9 @@ static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
|
|||
if (rule4->dscp_full) {
|
||||
frh->tos = 0;
|
||||
if (nla_put_u8(skb, FRA_DSCP,
|
||||
inet_dscp_to_dsfield(rule4->dscp) >> 2))
|
||||
inet_dscp_to_dsfield(rule4->dscp) >> 2) ||
|
||||
nla_put_u8(skb, FRA_DSCP_MASK,
|
||||
inet_dscp_to_dsfield(rule4->dscp_mask) >> 2))
|
||||
goto nla_put_failure;
|
||||
} else {
|
||||
frh->tos = inet_dscp_to_dsfield(rule4->dscp);
|
||||
|
|
@ -418,7 +458,8 @@ static size_t fib4_rule_nlmsg_payload(struct fib_rule *rule)
|
|||
return nla_total_size(4) /* dst */
|
||||
+ nla_total_size(4) /* src */
|
||||
+ nla_total_size(4) /* flow */
|
||||
+ nla_total_size(1); /* dscp */
|
||||
+ nla_total_size(1) /* dscp */
|
||||
+ nla_total_size(1); /* dscp mask */
|
||||
}
|
||||
|
||||
static void fib4_rule_flush_cache(struct fib_rules_ops *ops)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue