diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 3495bba410e345bdf0c30461cce870266c026d1e..1c85c39d1d03704c56ae7c6d6313b16d3398cb21 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1968,26 +1968,50 @@ static bool flow_is_multicast_only(struct ib_flow_attr *ib_attr) is_multicast_ether_addr(eth_spec->val.dst_mac); } -static bool is_valid_attr(const struct ib_flow_attr *flow_attr) +static bool is_valid_ethertype(const struct ib_flow_attr *flow_attr, + bool check_inner) { union ib_flow_spec *ib_spec = (union ib_flow_spec *)(flow_attr + 1); - bool has_ipv4_spec = false; - bool eth_type_ipv4 = true; + int inner_bit = check_inner ? IB_FLOW_SPEC_INNER : 0; + bool ipv4_spec_valid, ipv6_spec_valid; + unsigned int ip_spec_type = 0; + bool has_ethertype = false; unsigned int spec_index; + bool mask_valid = true; + u16 eth_type = 0; + bool type_valid; /* Validate that ethertype is correct */ for (spec_index = 0; spec_index < flow_attr->num_of_specs; spec_index++) { - if (ib_spec->type == IB_FLOW_SPEC_ETH && + if ((ib_spec->type == (IB_FLOW_SPEC_ETH | inner_bit)) && ib_spec->eth.mask.ether_type) { - if (!((ib_spec->eth.mask.ether_type == htons(0xffff)) && - ib_spec->eth.val.ether_type == htons(ETH_P_IP))) - eth_type_ipv4 = false; - } else if (ib_spec->type == IB_FLOW_SPEC_IPV4) { - has_ipv4_spec = true; + mask_valid = (ib_spec->eth.mask.ether_type == + htons(0xffff)); + has_ethertype = true; + eth_type = ntohs(ib_spec->eth.val.ether_type); + } else if ((ib_spec->type == (IB_FLOW_SPEC_IPV4 | inner_bit)) || + (ib_spec->type == (IB_FLOW_SPEC_IPV6 | inner_bit))) { + ip_spec_type = ib_spec->type; } ib_spec = (void *)ib_spec + ib_spec->size; } - return !has_ipv4_spec || eth_type_ipv4; + + type_valid = (!has_ethertype) || (!ip_spec_type); + if (!type_valid && mask_valid) { + ipv4_spec_valid = (eth_type == ETH_P_IP) && + (ip_spec_type == (IB_FLOW_SPEC_IPV4 | inner_bit)); + ipv6_spec_valid = (eth_type == ETH_P_IPV6) && + (ip_spec_type == (IB_FLOW_SPEC_IPV6 | inner_bit)); + type_valid = ipv4_spec_valid || ipv6_spec_valid; + } + + return type_valid; +} + +static bool is_valid_attr(const struct ib_flow_attr *flow_attr) +{ + return is_valid_ethertype(flow_attr, false) && + is_valid_ethertype(flow_attr, true); } static void put_flow_table(struct mlx5_ib_dev *dev,