@@ -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+
518551static 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