Skip to content

Commit

Permalink
ipv6: fib_rules: Add DSCP mask matching
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Ido Schimmel <[email protected]>
Reviewed-by: Guillaume Nault <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Jakub Kicinski <[email protected]>
  • Loading branch information
idosch authored and kuba-moo committed Feb 22, 2025
1 parent 2ae0069 commit c29165c
Showing 1 changed file with 43 additions and 2 deletions.
45 changes: 43 additions & 2 deletions net/ipv6/fib6_rules.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
};

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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 */
}
Expand Down

0 comments on commit c29165c

Please sign in to comment.