Skip to content

Commit da76659

Browse files
idoschkuba-moo
authored andcommitted
net: fib_rules: Add port mask support
Add support for configuring and deleting rules that match on source and destination ports using a mask as well as support for dumping such rules to user space. Reviewed-by: Petr Machata <petrm@nvidia.com> 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/20250217134109.311176-3-idosch@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 39f970a commit da76659

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

include/net/fib_rules.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ struct fib_rule {
4343
struct fib_kuid_range uid_range;
4444
struct fib_rule_port_range sport_range;
4545
struct fib_rule_port_range dport_range;
46+
u16 sport_mask;
47+
u16 dport_mask;
4648
struct rcu_head rcu;
4749
};
4850

@@ -159,6 +161,12 @@ static inline bool fib_rule_port_range_compare(struct fib_rule_port_range *a,
159161
a->end == b->end;
160162
}
161163

164+
static inline bool
165+
fib_rule_port_is_range(const struct fib_rule_port_range *range)
166+
{
167+
return range->start != range->end;
168+
}
169+
162170
static inline bool fib_rule_requires_fldissect(struct fib_rule *rule)
163171
{
164172
return rule->iifindex != LOOPBACK_IFINDEX && (rule->ip_proto ||

net/core/fib_rules.c

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,11 +481,17 @@ static struct fib_rule *rule_find(struct fib_rules_ops *ops,
481481
&rule->sport_range))
482482
continue;
483483

484+
if (rule->sport_mask && r->sport_mask != rule->sport_mask)
485+
continue;
486+
484487
if (fib_rule_port_range_set(&rule->dport_range) &&
485488
!fib_rule_port_range_compare(&r->dport_range,
486489
&rule->dport_range))
487490
continue;
488491

492+
if (rule->dport_mask && r->dport_mask != rule->dport_mask)
493+
continue;
494+
489495
if (!ops->compare(r, frh, tb))
490496
continue;
491497
return r;
@@ -515,6 +521,33 @@ static int fib_nl2rule_l3mdev(struct nlattr *nla, struct fib_rule *nlrule,
515521
}
516522
#endif
517523

524+
static int fib_nl2rule_port_mask(const struct nlattr *mask_attr,
525+
const struct fib_rule_port_range *range,
526+
u16 *port_mask,
527+
struct netlink_ext_ack *extack)
528+
{
529+
if (!fib_rule_port_range_valid(range)) {
530+
NL_SET_ERR_MSG_ATTR(extack, mask_attr,
531+
"Cannot specify port mask without port value");
532+
return -EINVAL;
533+
}
534+
535+
if (fib_rule_port_is_range(range)) {
536+
NL_SET_ERR_MSG_ATTR(extack, mask_attr,
537+
"Cannot specify port mask for port range");
538+
return -EINVAL;
539+
}
540+
541+
if (range->start & ~nla_get_u16(mask_attr)) {
542+
NL_SET_ERR_MSG_ATTR(extack, mask_attr, "Invalid port mask");
543+
return -EINVAL;
544+
}
545+
546+
*port_mask = nla_get_u16(mask_attr);
547+
548+
return 0;
549+
}
550+
518551
static int fib_nl2rule(struct net *net, struct nlmsghdr *nlh,
519552
struct netlink_ext_ack *extack,
520553
struct fib_rules_ops *ops,
@@ -644,6 +677,16 @@ static int fib_nl2rule(struct net *net, struct nlmsghdr *nlh,
644677
NL_SET_ERR_MSG(extack, "Invalid sport range");
645678
goto errout_free;
646679
}
680+
if (!fib_rule_port_is_range(&nlrule->sport_range))
681+
nlrule->sport_mask = U16_MAX;
682+
}
683+
684+
if (tb[FRA_SPORT_MASK]) {
685+
err = fib_nl2rule_port_mask(tb[FRA_SPORT_MASK],
686+
&nlrule->sport_range,
687+
&nlrule->sport_mask, extack);
688+
if (err)
689+
goto errout_free;
647690
}
648691

649692
if (tb[FRA_DPORT_RANGE]) {
@@ -653,6 +696,16 @@ static int fib_nl2rule(struct net *net, struct nlmsghdr *nlh,
653696
NL_SET_ERR_MSG(extack, "Invalid dport range");
654697
goto errout_free;
655698
}
699+
if (!fib_rule_port_is_range(&nlrule->dport_range))
700+
nlrule->dport_mask = U16_MAX;
701+
}
702+
703+
if (tb[FRA_DPORT_MASK]) {
704+
err = fib_nl2rule_port_mask(tb[FRA_DPORT_MASK],
705+
&nlrule->dport_range,
706+
&nlrule->dport_mask, extack);
707+
if (err)
708+
goto errout_free;
656709
}
657710

658711
*rule = nlrule;
@@ -751,10 +804,16 @@ static int rule_exists(struct fib_rules_ops *ops, struct fib_rule_hdr *frh,
751804
&rule->sport_range))
752805
continue;
753806

807+
if (r->sport_mask != rule->sport_mask)
808+
continue;
809+
754810
if (!fib_rule_port_range_compare(&r->dport_range,
755811
&rule->dport_range))
756812
continue;
757813

814+
if (r->dport_mask != rule->dport_mask)
815+
continue;
816+
758817
if (!ops->compare(r, frh, tb))
759818
continue;
760819
return 1;
@@ -1051,7 +1110,9 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops,
10511110
+ nla_total_size(1) /* FRA_PROTOCOL */
10521111
+ nla_total_size(1) /* FRA_IP_PROTO */
10531112
+ nla_total_size(sizeof(struct fib_rule_port_range)) /* FRA_SPORT_RANGE */
1054-
+ nla_total_size(sizeof(struct fib_rule_port_range)); /* FRA_DPORT_RANGE */
1113+
+ nla_total_size(sizeof(struct fib_rule_port_range)) /* FRA_DPORT_RANGE */
1114+
+ nla_total_size(2) /* FRA_SPORT_MASK */
1115+
+ nla_total_size(2); /* FRA_DPORT_MASK */
10551116

10561117
if (ops->nlmsg_payload)
10571118
payload += ops->nlmsg_payload(rule);
@@ -1119,8 +1180,12 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
11191180
nla_put_uid_range(skb, &rule->uid_range)) ||
11201181
(fib_rule_port_range_set(&rule->sport_range) &&
11211182
nla_put_port_range(skb, FRA_SPORT_RANGE, &rule->sport_range)) ||
1183+
(rule->sport_mask && nla_put_u16(skb, FRA_SPORT_MASK,
1184+
rule->sport_mask)) ||
11221185
(fib_rule_port_range_set(&rule->dport_range) &&
11231186
nla_put_port_range(skb, FRA_DPORT_RANGE, &rule->dport_range)) ||
1187+
(rule->dport_mask && nla_put_u16(skb, FRA_DPORT_MASK,
1188+
rule->dport_mask)) ||
11241189
(rule->ip_proto && nla_put_u8(skb, FRA_IP_PROTO, rule->ip_proto)))
11251190
goto nla_put_failure;
11261191

0 commit comments

Comments
 (0)