Skip to content

Commit abcec3e

Browse files
committed
Merge branch 'net-mlx5-hws-improve-ip-version-handling'
Mark Bloch says: ==================== net/mlx5: HWS, Improve IP version handling This small series hardens our checks against a single matcher containing rules that match on IPv4 and IPv6. This scenario is not supported by hardware steering and the implementation now signals this instead of failing silently. Patches: * Patch 1 forbids a single definer to match on mixed IP versions for source and destination address. * Patch 2 reproduces a couple of firmware checks: it forbids creating a definer that matches on IP address without matching on IP version, and also disallows matching on IPv6 addresses and the IPv4 IHL fields in the same definer. * Patch 3 forbids mixing rules that match on IPv4 and IPv6 addresses in the same matcher. The underlying definer mechanism does not support that. ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents b5cdb9b + f41f3ed commit abcec3e

File tree

4 files changed

+216
-22
lines changed

4 files changed

+216
-22
lines changed

drivers/net/ethernet/mellanox/mlx5/core/steering/hws/definer.c

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ static int
509509
hws_definer_conv_outer(struct mlx5hws_definer_conv_data *cd,
510510
u32 *match_param)
511511
{
512-
bool is_s_ipv6, is_d_ipv6, smac_set, dmac_set;
512+
bool is_ipv6, smac_set, dmac_set, ip_addr_set, ip_ver_set;
513513
struct mlx5hws_definer_fc *fc = cd->fc;
514514
struct mlx5hws_definer_fc *curr_fc;
515515
u32 *s_ipv6, *d_ipv6;
@@ -521,6 +521,20 @@ hws_definer_conv_outer(struct mlx5hws_definer_conv_data *cd,
521521
return -EINVAL;
522522
}
523523

524+
ip_addr_set = HWS_IS_FLD_SET_SZ(match_param,
525+
outer_headers.src_ipv4_src_ipv6,
526+
0x80) ||
527+
HWS_IS_FLD_SET_SZ(match_param,
528+
outer_headers.dst_ipv4_dst_ipv6, 0x80);
529+
ip_ver_set = HWS_IS_FLD_SET(match_param, outer_headers.ip_version) ||
530+
HWS_IS_FLD_SET(match_param, outer_headers.ethertype);
531+
532+
if (ip_addr_set && !ip_ver_set) {
533+
mlx5hws_err(cd->ctx,
534+
"Unsupported match on IP address without version or ethertype\n");
535+
return -EINVAL;
536+
}
537+
524538
/* L2 Check ethertype */
525539
HWS_SET_HDR(fc, match_param, ETH_TYPE_O,
526540
outer_headers.ethertype,
@@ -570,10 +584,16 @@ hws_definer_conv_outer(struct mlx5hws_definer_conv_data *cd,
570584
outer_headers.dst_ipv4_dst_ipv6.ipv6_layout);
571585

572586
/* Assume IPv6 is used if ipv6 bits are set */
573-
is_s_ipv6 = s_ipv6[0] || s_ipv6[1] || s_ipv6[2];
574-
is_d_ipv6 = d_ipv6[0] || d_ipv6[1] || d_ipv6[2];
587+
is_ipv6 = s_ipv6[0] || s_ipv6[1] || s_ipv6[2] ||
588+
d_ipv6[0] || d_ipv6[1] || d_ipv6[2];
575589

576-
if (is_s_ipv6) {
590+
/* IHL is an IPv4-specific field. */
591+
if (is_ipv6 && HWS_IS_FLD_SET(match_param, outer_headers.ipv4_ihl)) {
592+
mlx5hws_err(cd->ctx, "Unsupported match on IPv6 address and IPv4 IHL\n");
593+
return -EINVAL;
594+
}
595+
596+
if (is_ipv6) {
577597
/* Handle IPv6 source address */
578598
HWS_SET_HDR(fc, match_param, IPV6_SRC_127_96_O,
579599
outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_127_96,
@@ -587,13 +607,6 @@ hws_definer_conv_outer(struct mlx5hws_definer_conv_data *cd,
587607
HWS_SET_HDR(fc, match_param, IPV6_SRC_31_0_O,
588608
outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0,
589609
ipv6_src_outer.ipv6_address_31_0);
590-
} else {
591-
/* Handle IPv4 source address */
592-
HWS_SET_HDR(fc, match_param, IPV4_SRC_O,
593-
outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0,
594-
ipv4_src_dest_outer.source_address);
595-
}
596-
if (is_d_ipv6) {
597610
/* Handle IPv6 destination address */
598611
HWS_SET_HDR(fc, match_param, IPV6_DST_127_96_O,
599612
outer_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_127_96,
@@ -608,6 +621,10 @@ hws_definer_conv_outer(struct mlx5hws_definer_conv_data *cd,
608621
outer_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_31_0,
609622
ipv6_dst_outer.ipv6_address_31_0);
610623
} else {
624+
/* Handle IPv4 source address */
625+
HWS_SET_HDR(fc, match_param, IPV4_SRC_O,
626+
outer_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0,
627+
ipv4_src_dest_outer.source_address);
611628
/* Handle IPv4 destination address */
612629
HWS_SET_HDR(fc, match_param, IPV4_DST_O,
613630
outer_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_31_0,
@@ -665,7 +682,7 @@ static int
665682
hws_definer_conv_inner(struct mlx5hws_definer_conv_data *cd,
666683
u32 *match_param)
667684
{
668-
bool is_s_ipv6, is_d_ipv6, smac_set, dmac_set;
685+
bool is_ipv6, smac_set, dmac_set, ip_addr_set, ip_ver_set;
669686
struct mlx5hws_definer_fc *fc = cd->fc;
670687
struct mlx5hws_definer_fc *curr_fc;
671688
u32 *s_ipv6, *d_ipv6;
@@ -677,6 +694,20 @@ hws_definer_conv_inner(struct mlx5hws_definer_conv_data *cd,
677694
return -EINVAL;
678695
}
679696

697+
ip_addr_set = HWS_IS_FLD_SET_SZ(match_param,
698+
inner_headers.src_ipv4_src_ipv6,
699+
0x80) ||
700+
HWS_IS_FLD_SET_SZ(match_param,
701+
inner_headers.dst_ipv4_dst_ipv6, 0x80);
702+
ip_ver_set = HWS_IS_FLD_SET(match_param, inner_headers.ip_version) ||
703+
HWS_IS_FLD_SET(match_param, inner_headers.ethertype);
704+
705+
if (ip_addr_set && !ip_ver_set) {
706+
mlx5hws_err(cd->ctx,
707+
"Unsupported match on IP address without version or ethertype\n");
708+
return -EINVAL;
709+
}
710+
680711
/* L2 Check ethertype */
681712
HWS_SET_HDR(fc, match_param, ETH_TYPE_I,
682713
inner_headers.ethertype,
@@ -728,10 +759,16 @@ hws_definer_conv_inner(struct mlx5hws_definer_conv_data *cd,
728759
inner_headers.dst_ipv4_dst_ipv6.ipv6_layout);
729760

730761
/* Assume IPv6 is used if ipv6 bits are set */
731-
is_s_ipv6 = s_ipv6[0] || s_ipv6[1] || s_ipv6[2];
732-
is_d_ipv6 = d_ipv6[0] || d_ipv6[1] || d_ipv6[2];
762+
is_ipv6 = s_ipv6[0] || s_ipv6[1] || s_ipv6[2] ||
763+
d_ipv6[0] || d_ipv6[1] || d_ipv6[2];
733764

734-
if (is_s_ipv6) {
765+
/* IHL is an IPv4-specific field. */
766+
if (is_ipv6 && HWS_IS_FLD_SET(match_param, inner_headers.ipv4_ihl)) {
767+
mlx5hws_err(cd->ctx, "Unsupported match on IPv6 address and IPv4 IHL\n");
768+
return -EINVAL;
769+
}
770+
771+
if (is_ipv6) {
735772
/* Handle IPv6 source address */
736773
HWS_SET_HDR(fc, match_param, IPV6_SRC_127_96_I,
737774
inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_127_96,
@@ -745,13 +782,6 @@ hws_definer_conv_inner(struct mlx5hws_definer_conv_data *cd,
745782
HWS_SET_HDR(fc, match_param, IPV6_SRC_31_0_I,
746783
inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0,
747784
ipv6_src_inner.ipv6_address_31_0);
748-
} else {
749-
/* Handle IPv4 source address */
750-
HWS_SET_HDR(fc, match_param, IPV4_SRC_I,
751-
inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0,
752-
ipv4_src_dest_inner.source_address);
753-
}
754-
if (is_d_ipv6) {
755785
/* Handle IPv6 destination address */
756786
HWS_SET_HDR(fc, match_param, IPV6_DST_127_96_I,
757787
inner_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_127_96,
@@ -766,6 +796,10 @@ hws_definer_conv_inner(struct mlx5hws_definer_conv_data *cd,
766796
inner_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_31_0,
767797
ipv6_dst_inner.ipv6_address_31_0);
768798
} else {
799+
/* Handle IPv4 source address */
800+
HWS_SET_HDR(fc, match_param, IPV4_SRC_I,
801+
inner_headers.src_ipv4_src_ipv6.ipv6_simple_layout.ipv6_31_0,
802+
ipv4_src_dest_inner.source_address);
769803
/* Handle IPv4 destination address */
770804
HWS_SET_HDR(fc, match_param, IPV4_DST_I,
771805
inner_headers.dst_ipv4_dst_ipv6.ipv6_simple_layout.ipv6_31_0,

drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,30 @@ static int hws_matcher_bind_at(struct mlx5hws_matcher *matcher)
385385
return 0;
386386
}
387387

388+
static void hws_matcher_set_ip_version_match(struct mlx5hws_matcher *matcher)
389+
{
390+
int i;
391+
392+
for (i = 0; i < matcher->mt->fc_sz; i++) {
393+
switch (matcher->mt->fc[i].fname) {
394+
case MLX5HWS_DEFINER_FNAME_ETH_TYPE_O:
395+
matcher->matches_outer_ethertype = 1;
396+
break;
397+
case MLX5HWS_DEFINER_FNAME_ETH_L3_TYPE_O:
398+
matcher->matches_outer_ip_version = 1;
399+
break;
400+
case MLX5HWS_DEFINER_FNAME_ETH_TYPE_I:
401+
matcher->matches_inner_ethertype = 1;
402+
break;
403+
case MLX5HWS_DEFINER_FNAME_ETH_L3_TYPE_I:
404+
matcher->matches_inner_ip_version = 1;
405+
break;
406+
default:
407+
break;
408+
}
409+
}
410+
}
411+
388412
static int hws_matcher_bind_mt(struct mlx5hws_matcher *matcher)
389413
{
390414
struct mlx5hws_context *ctx = matcher->tbl->ctx;
@@ -401,6 +425,8 @@ static int hws_matcher_bind_mt(struct mlx5hws_matcher *matcher)
401425
}
402426
}
403427

428+
hws_matcher_set_ip_version_match(matcher);
429+
404430
/* Create an STE pool per matcher*/
405431
pool_attr.table_type = matcher->tbl->type;
406432
pool_attr.pool_type = MLX5HWS_POOL_TYPE_STE;

drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ struct mlx5hws_matcher_match_ste {
5050
struct mlx5hws_pool *pool;
5151
};
5252

53+
enum {
54+
MLX5HWS_MATCHER_IPV_UNSET = 0,
55+
MLX5HWS_MATCHER_IPV_4 = 1,
56+
MLX5HWS_MATCHER_IPV_6 = 2,
57+
};
58+
5359
struct mlx5hws_matcher {
5460
struct mlx5hws_table *tbl;
5561
struct mlx5hws_matcher_attr attr;
@@ -61,6 +67,12 @@ struct mlx5hws_matcher {
6167
u8 num_of_action_stes;
6268
/* enum mlx5hws_matcher_flags */
6369
u8 flags;
70+
u8 matches_outer_ethertype:1;
71+
u8 matches_outer_ip_version:1;
72+
u8 matches_inner_ethertype:1;
73+
u8 matches_inner_ip_version:1;
74+
u8 outer_ip_version:2;
75+
u8 inner_ip_version:2;
6476
u32 end_ft_id;
6577
struct mlx5hws_matcher *col_matcher;
6678
struct mlx5hws_matcher *resize_dst;

drivers/net/ethernet/mellanox/mlx5/core/steering/hws/rule.c

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,124 @@ int mlx5hws_rule_move_hws_add(struct mlx5hws_rule *rule,
655655
return 0;
656656
}
657657

658+
static u8 hws_rule_ethertype_to_matcher_ipv(u32 ethertype)
659+
{
660+
switch (ethertype) {
661+
case ETH_P_IP:
662+
return MLX5HWS_MATCHER_IPV_4;
663+
case ETH_P_IPV6:
664+
return MLX5HWS_MATCHER_IPV_6;
665+
default:
666+
return MLX5HWS_MATCHER_IPV_UNSET;
667+
}
668+
}
669+
670+
static u8 hws_rule_ip_version_to_matcher_ipv(u32 ip_version)
671+
{
672+
switch (ip_version) {
673+
case 4:
674+
return MLX5HWS_MATCHER_IPV_4;
675+
case 6:
676+
return MLX5HWS_MATCHER_IPV_6;
677+
default:
678+
return MLX5HWS_MATCHER_IPV_UNSET;
679+
}
680+
}
681+
682+
static int hws_rule_check_outer_ip_version(struct mlx5hws_matcher *matcher,
683+
u32 *match_param)
684+
{
685+
struct mlx5hws_context *ctx = matcher->tbl->ctx;
686+
u8 outer_ipv_ether = MLX5HWS_MATCHER_IPV_UNSET;
687+
u8 outer_ipv_ip = MLX5HWS_MATCHER_IPV_UNSET;
688+
u8 outer_ipv, ver;
689+
690+
if (matcher->matches_outer_ethertype) {
691+
ver = MLX5_GET(fte_match_param, match_param,
692+
outer_headers.ethertype);
693+
outer_ipv_ether = hws_rule_ethertype_to_matcher_ipv(ver);
694+
}
695+
if (matcher->matches_outer_ip_version) {
696+
ver = MLX5_GET(fte_match_param, match_param,
697+
outer_headers.ip_version);
698+
outer_ipv_ip = hws_rule_ip_version_to_matcher_ipv(ver);
699+
}
700+
701+
if (outer_ipv_ether != MLX5HWS_MATCHER_IPV_UNSET &&
702+
outer_ipv_ip != MLX5HWS_MATCHER_IPV_UNSET &&
703+
outer_ipv_ether != outer_ipv_ip) {
704+
mlx5hws_err(ctx, "Rule matches on inconsistent outer ethertype and ip version\n");
705+
return -EINVAL;
706+
}
707+
708+
outer_ipv = outer_ipv_ether != MLX5HWS_MATCHER_IPV_UNSET ?
709+
outer_ipv_ether : outer_ipv_ip;
710+
if (outer_ipv != MLX5HWS_MATCHER_IPV_UNSET &&
711+
matcher->outer_ip_version != MLX5HWS_MATCHER_IPV_UNSET &&
712+
outer_ipv != matcher->outer_ip_version) {
713+
mlx5hws_err(ctx, "Matcher and rule disagree on outer IP version\n");
714+
return -EINVAL;
715+
}
716+
matcher->outer_ip_version = outer_ipv;
717+
718+
return 0;
719+
}
720+
721+
static int hws_rule_check_inner_ip_version(struct mlx5hws_matcher *matcher,
722+
u32 *match_param)
723+
{
724+
struct mlx5hws_context *ctx = matcher->tbl->ctx;
725+
u8 inner_ipv_ether = MLX5HWS_MATCHER_IPV_UNSET;
726+
u8 inner_ipv_ip = MLX5HWS_MATCHER_IPV_UNSET;
727+
u8 inner_ipv, ver;
728+
729+
if (matcher->matches_inner_ethertype) {
730+
ver = MLX5_GET(fte_match_param, match_param,
731+
inner_headers.ethertype);
732+
inner_ipv_ether = hws_rule_ethertype_to_matcher_ipv(ver);
733+
}
734+
if (matcher->matches_inner_ip_version) {
735+
ver = MLX5_GET(fte_match_param, match_param,
736+
inner_headers.ip_version);
737+
inner_ipv_ip = hws_rule_ip_version_to_matcher_ipv(ver);
738+
}
739+
740+
if (inner_ipv_ether != MLX5HWS_MATCHER_IPV_UNSET &&
741+
inner_ipv_ip != MLX5HWS_MATCHER_IPV_UNSET &&
742+
inner_ipv_ether != inner_ipv_ip) {
743+
mlx5hws_err(ctx, "Rule matches on inconsistent inner ethertype and ip version\n");
744+
return -EINVAL;
745+
}
746+
747+
inner_ipv = inner_ipv_ether != MLX5HWS_MATCHER_IPV_UNSET ?
748+
inner_ipv_ether : inner_ipv_ip;
749+
if (inner_ipv != MLX5HWS_MATCHER_IPV_UNSET &&
750+
matcher->inner_ip_version != MLX5HWS_MATCHER_IPV_UNSET &&
751+
inner_ipv != matcher->inner_ip_version) {
752+
mlx5hws_err(ctx, "Matcher and rule disagree on inner IP version\n");
753+
return -EINVAL;
754+
}
755+
matcher->inner_ip_version = inner_ipv;
756+
757+
return 0;
758+
}
759+
760+
static int hws_rule_check_ip_version(struct mlx5hws_matcher *matcher,
761+
u32 *match_param)
762+
{
763+
int ret;
764+
765+
ret = hws_rule_check_outer_ip_version(matcher, match_param);
766+
if (unlikely(ret))
767+
return ret;
768+
769+
ret = hws_rule_check_inner_ip_version(matcher, match_param);
770+
if (unlikely(ret))
771+
return ret;
772+
773+
return 0;
774+
}
775+
658776
int mlx5hws_rule_create(struct mlx5hws_matcher *matcher,
659777
u8 mt_idx,
660778
u32 *match_param,
@@ -665,6 +783,10 @@ int mlx5hws_rule_create(struct mlx5hws_matcher *matcher,
665783
{
666784
int ret;
667785

786+
ret = hws_rule_check_ip_version(matcher, match_param);
787+
if (unlikely(ret))
788+
return ret;
789+
668790
rule_handle->matcher = matcher;
669791

670792
ret = hws_rule_enqueue_precheck_create(rule_handle, attr);

0 commit comments

Comments
 (0)