net/mlx5: HWS, Harden IP version definer checks
authorVlad Dogaru <vdogaru@nvidia.com>
Tue, 22 Apr 2025 09:25:39 +0000 (12:25 +0300)
committerJakub Kicinski <kuba@kernel.org>
Thu, 24 Apr 2025 01:48:11 +0000 (18:48 -0700)
Replicate some sanity checks that firmware does, since hardware steering
does not go through firmware.

When creating a definer, disallow matching on IP addresses without also
matching on IP version. The latter can be satisfied by matching either
on the version field in the IP header, or on the ethertype field.

Also refuse to match IPv4 IHL alongside IPv6.

Signed-off-by: Vlad Dogaru <vdogaru@nvidia.com>
Reviewed-by: Yevgeny Kliteynik <kliteyn@nvidia.com>
Signed-off-by: Mark Bloch <mbloch@nvidia.com>
Link: https://patch.msgid.link/20250422092540.182091-3-mbloch@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.c

index 5257e706dde2d54924b21c887eb0f7ed8f9f30b8..1061a46811ac08bea0c4b1a07727393116b60350 100644 (file)
@@ -509,9 +509,9 @@ static int
 hws_definer_conv_outer(struct mlx5hws_definer_conv_data *cd,
                       u32 *match_param)
 {
+       bool is_ipv6, smac_set, dmac_set, ip_addr_set, ip_ver_set;
        struct mlx5hws_definer_fc *fc = cd->fc;
        struct mlx5hws_definer_fc *curr_fc;
-       bool is_ipv6, smac_set, dmac_set;
        u32 *s_ipv6, *d_ipv6;
 
        if (HWS_IS_FLD_SET_SZ(match_param, outer_headers.l4_type, 0x2) ||
@@ -521,6 +521,20 @@ hws_definer_conv_outer(struct mlx5hws_definer_conv_data *cd,
                return -EINVAL;
        }
 
+       ip_addr_set = HWS_IS_FLD_SET_SZ(match_param,
+                                       outer_headers.src_ipv4_src_ipv6,
+                                       0x80) ||
+                     HWS_IS_FLD_SET_SZ(match_param,
+                                       outer_headers.dst_ipv4_dst_ipv6, 0x80);
+       ip_ver_set = HWS_IS_FLD_SET(match_param, outer_headers.ip_version) ||
+                    HWS_IS_FLD_SET(match_param, outer_headers.ethertype);
+
+       if (ip_addr_set && !ip_ver_set) {
+               mlx5hws_err(cd->ctx,
+                           "Unsupported match on IP address without version or ethertype\n");
+               return -EINVAL;
+       }
+
        /* L2 Check ethertype */
        HWS_SET_HDR(fc, match_param, ETH_TYPE_O,
                    outer_headers.ethertype,
@@ -573,6 +587,12 @@ hws_definer_conv_outer(struct mlx5hws_definer_conv_data *cd,
        is_ipv6 = s_ipv6[0] || s_ipv6[1] || s_ipv6[2] ||
                  d_ipv6[0] || d_ipv6[1] || d_ipv6[2];
 
+       /* IHL is an IPv4-specific field. */
+       if (is_ipv6 && HWS_IS_FLD_SET(match_param, outer_headers.ipv4_ihl)) {
+               mlx5hws_err(cd->ctx, "Unsupported match on IPv6 address and IPv4 IHL\n");
+               return -EINVAL;
+       }
+
        if (is_ipv6) {
                /* Handle IPv6 source address */
                HWS_SET_HDR(fc, match_param, IPV6_SRC_127_96_O,
@@ -662,9 +682,9 @@ static int
 hws_definer_conv_inner(struct mlx5hws_definer_conv_data *cd,
                       u32 *match_param)
 {
+       bool is_ipv6, smac_set, dmac_set, ip_addr_set, ip_ver_set;
        struct mlx5hws_definer_fc *fc = cd->fc;
        struct mlx5hws_definer_fc *curr_fc;
-       bool is_ipv6, smac_set, dmac_set;
        u32 *s_ipv6, *d_ipv6;
 
        if (HWS_IS_FLD_SET_SZ(match_param, inner_headers.l4_type, 0x2) ||
@@ -674,6 +694,20 @@ hws_definer_conv_inner(struct mlx5hws_definer_conv_data *cd,
                return -EINVAL;
        }
 
+       ip_addr_set = HWS_IS_FLD_SET_SZ(match_param,
+                                       inner_headers.src_ipv4_src_ipv6,
+                                       0x80) ||
+                     HWS_IS_FLD_SET_SZ(match_param,
+                                       inner_headers.dst_ipv4_dst_ipv6, 0x80);
+       ip_ver_set = HWS_IS_FLD_SET(match_param, inner_headers.ip_version) ||
+                    HWS_IS_FLD_SET(match_param, inner_headers.ethertype);
+
+       if (ip_addr_set && !ip_ver_set) {
+               mlx5hws_err(cd->ctx,
+                           "Unsupported match on IP address without version or ethertype\n");
+               return -EINVAL;
+       }
+
        /* L2 Check ethertype */
        HWS_SET_HDR(fc, match_param, ETH_TYPE_I,
                    inner_headers.ethertype,
@@ -728,6 +762,12 @@ hws_definer_conv_inner(struct mlx5hws_definer_conv_data *cd,
        is_ipv6 = s_ipv6[0] || s_ipv6[1] || s_ipv6[2] ||
                  d_ipv6[0] || d_ipv6[1] || d_ipv6[2];
 
+       /* IHL is an IPv4-specific field. */
+       if (is_ipv6 && HWS_IS_FLD_SET(match_param, inner_headers.ipv4_ihl)) {
+               mlx5hws_err(cd->ctx, "Unsupported match on IPv6 address and IPv4 IHL\n");
+               return -EINVAL;
+       }
+
        if (is_ipv6) {
                /* Handle IPv6 source address */
                HWS_SET_HDR(fc, match_param, IPV6_SRC_127_96_I,