diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
index f8d1696ab5eb..5d42c681dc7b 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
@@ -46,7 +46,8 @@ mlx5_core-$(CONFIG_MLX5_CLS_ACT) += en_tc.o en/rep/tc.o en/rep/neigh.o \
lib/fs_chains.o en/tc_tun.o \
esw/indir_table.o en/tc_tun_encap.o \
en/tc_tun_vxlan.o en/tc_tun_gre.o en/tc_tun_geneve.o \
- en/tc_tun_mplsoudp.o diag/en_tc_tracepoint.o \
+ en/tc_tun_mplsoudp.o en/tc_tun_gtp.o \
+ diag/en_tc_tracepoint.o \
en/tc/post_act.o en/tc/int_port.o en/tc/meter.o \
en/tc/post_meter.o en/tc/act_stats.o
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
index de74dbfe7b20..921af801d4d4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.c
@@ -7,6 +7,7 @@
#include <net/gre.h>
#include <net/geneve.h>
#include <net/bareudp.h>
+#include <net/gtp.h>
#include "en/tc_tun.h"
#include "en/tc_priv.h"
#include "en_tc.h"
@@ -996,3 +997,90 @@ int mlx5e_tc_tun_parse_udp_ports(struct mlx5e_priv *priv,
return 0;
}
+
+/* Without a tunnel device the outer headers name the tunnel */
+static struct mlx5e_tc_tunnel *
+mlx5e_tc_tun_outer_lookup(struct flow_rule *rule)
+{
+ struct flow_match_basic basic;
+ struct flow_match_ports ports;
+
+ if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC))
+ return NULL;
+
+ flow_rule_match_basic(rule, &basic);
+ if (basic.key->ip_proto == IPPROTO_GRE)
+ return &gre_tunnel;
+
+ if (basic.key->ip_proto != IPPROTO_UDP ||
+ !flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS))
+ return NULL;
+
+ flow_rule_match_ports(rule, &ports);
+ /* Only an exact port names a tunnel */
+ if (ports.mask->dst != htons(U16_MAX))
+ return NULL;
+
+ switch (ntohs(ports.key->dst)) {
+ case GTP1U_PORT:
+ return >p_tunnel;
+ case IANA_VXLAN_UDP_PORT:
+ return &vxlan_tunnel;
+ case GENEVE_UDP_PORT:
+ return &geneve_tunnel;
+ default:
+ return NULL;
+ }
+}
+
+static bool
+mlx5e_tc_tun_has_decap(struct flow_rule *rule)
+{
+ const struct flow_action_entry *act;
+ int i;
+
+ flow_action_for_each(i, act, &rule->action) {
+ if (act->id == FLOW_ACTION_TUNNEL_DECAP)
+ return true;
+ }
+
+ return false;
+}
+
+/* Without a tunnel device only the hardware can read the tunnel key */
+int
+mlx5e_tc_tun_parse_outer_key(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct flow_cls_offload *f,
+ enum fs_flow_table_type fs_type)
+{
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
+ struct netlink_ext_ack *extack = f->common.extack;
+ struct flow_match_enc_keyid enc_keyid;
+ struct mlx5e_tc_tunnel *tunnel;
+
+ if (!f->common.skip_sw) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "enc_key_id without a tunnel device requires skip_sw");
+ return -EOPNOTSUPP;
+ }
+
+ if (mlx5e_tc_tun_has_decap(rule)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "enc_key_id without a tunnel device cannot decap");
+ return -EOPNOTSUPP;
+ }
+
+ tunnel = mlx5e_tc_tun_outer_lookup(rule);
+ if (!tunnel) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "enc_key_id needs ip_proto 0x2f or the exact dst_port of a supported tunnel");
+ return -EOPNOTSUPP;
+ }
+
+ flow_rule_match_enc_keyid(rule, &enc_keyid);
+ return tunnel->parse_outer_key(priv, spec, extack,
+ be32_to_cpu(enc_keyid.key->keyid),
+ be32_to_cpu(enc_keyid.mask->keyid),
+ fs_type);
+}diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h
index d7c778bbb2ef..8eccaecb70b2 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun.h
@@ -52,6 +52,11 @@ struct mlx5e_tc_tunnel {
struct flow_cls_offload *f,
void *headers_c,
void *headers_v);
+ int (*parse_outer_key)(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct netlink_ext_ack *extack,
+ u32 key, u32 mask,
+ enum fs_flow_table_type fs_type);
bool (*encap_info_equal)(struct mlx5e_encap_key *a,
struct mlx5e_encap_key *b);
int (*get_remote_ifindex)(struct net_device *mirred_dev);@@ -61,6 +66,7 @@ extern struct mlx5e_tc_tunnel vxlan_tunnel;
extern struct mlx5e_tc_tunnel geneve_tunnel;
extern struct mlx5e_tc_tunnel gre_tunnel;
extern struct mlx5e_tc_tunnel mplsoudp_tunnel;
+extern struct mlx5e_tc_tunnel gtp_tunnel;
struct mlx5e_tc_tunnel *mlx5e_get_tc_tun(struct net_device *tunnel_dev);
@@ -115,6 +121,11 @@ int mlx5e_tc_tun_parse_udp_ports(struct mlx5e_priv *priv,
void *headers_c,
void *headers_v);
+int mlx5e_tc_tun_parse_outer_key(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct flow_cls_offload *f,
+ enum fs_flow_table_type fs_type);
+
bool mlx5e_tc_tun_encap_info_equal_generic(struct mlx5e_encap_key *a,
struct mlx5e_encap_key *b);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_geneve.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_geneve.c
index ee04fcdca6ff..9a2f7a409a82 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_geneve.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_geneve.c
@@ -4,6 +4,7 @@
#include <net/geneve.h>
#include "lib/geneve.h"
#include "en/tc_tun.h"
+#include "fs_core.h"
#define MLX5E_GENEVE_VER 0
@@ -350,6 +351,42 @@ static bool mlx5e_tc_tun_encap_info_equal_geneve(struct mlx5e_encap_key *a,
IP_TUNNEL_GENEVE_OPT_BIT);
}
+static int
+mlx5e_tc_tun_parse_outer_key_geneve(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct netlink_ext_ack *extack,
+ u32 key, u32 mask,
+ enum fs_flow_table_type fs_type)
+{
+ void *misc_c, *misc_v;
+
+ if (key >= MLX5E_TC_TUN_N_VNI) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Tunnel key does not fit the 24 bit VNI");
+ return -EOPNOTSUPP;
+ }
+
+ if (!mlx5e_tc_tun_can_offload_geneve(priv) ||
+ !MLX5_CAP_FLOWTABLE_TYPE(priv->mdev,
+ ft_field_support.outer_geneve_vni,
+ fs_type)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Matching on GENEVE VNI is not supported");
+ return -EOPNOTSUPP;
+ }
+
+ misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
+ misc_parameters);
+ misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
+ misc_parameters);
+
+ MLX5_SET(fte_match_set_misc, misc_c, geneve_vni, mask);
+ MLX5_SET(fte_match_set_misc, misc_v, geneve_vni, key);
+ spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
+
+ return 0;
+}
+
struct mlx5e_tc_tunnel geneve_tunnel = {
.tunnel_type = MLX5E_TC_TUNNEL_TYPE_GENEVE,
.match_level = MLX5_MATCH_L4,@@ -359,5 +396,6 @@ struct mlx5e_tc_tunnel geneve_tunnel = {
.generate_ip_tun_hdr = mlx5e_gen_ip_tunnel_header_geneve,
.parse_udp_ports = mlx5e_tc_tun_parse_udp_ports_geneve,
.parse_tunnel = mlx5e_tc_tun_parse_geneve,
+ .parse_outer_key = mlx5e_tc_tun_parse_outer_key_geneve,
.encap_info_equal = mlx5e_tc_tun_encap_info_equal_geneve,
};diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_gre.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_gre.c
index 579eda89fc76..1a3d329408f4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_gre.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_gre.c
@@ -3,6 +3,7 @@
#include <net/gre.h>
#include "en/tc_tun.h"
+#include "fs_core.h"
static bool mlx5e_tc_tun_can_offload_gretap(struct mlx5e_priv *priv)
{@@ -89,6 +90,35 @@ static int mlx5e_tc_tun_parse_gretap(struct mlx5e_priv *priv,
return 0;
}
+static int
+mlx5e_tc_tun_parse_outer_key_gre(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct netlink_ext_ack *extack,
+ u32 key, u32 mask,
+ enum fs_flow_table_type fs_type)
+{
+ void *misc_c, *misc_v;
+
+ if (!MLX5_CAP_FLOWTABLE_TYPE(priv->mdev,
+ ft_field_support.outer_gre_key,
+ fs_type)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Matching on GRE key is not supported");
+ return -EOPNOTSUPP;
+ }
+
+ misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
+ misc_parameters);
+ misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
+ misc_parameters);
+
+ MLX5_SET(fte_match_set_misc, misc_c, gre_key.key, mask);
+ MLX5_SET(fte_match_set_misc, misc_v, gre_key.key, key);
+ spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
+
+ return 0;
+}
+
struct mlx5e_tc_tunnel gre_tunnel = {
.tunnel_type = MLX5E_TC_TUNNEL_TYPE_GRETAP,
.match_level = MLX5_MATCH_L3,@@ -98,5 +128,6 @@ struct mlx5e_tc_tunnel gre_tunnel = {
.generate_ip_tun_hdr = mlx5e_gen_ip_tunnel_header_gretap,
.parse_udp_ports = NULL,
.parse_tunnel = mlx5e_tc_tun_parse_gretap,
+ .parse_outer_key = mlx5e_tc_tun_parse_outer_key_gre,
.encap_info_equal = mlx5e_tc_tun_encap_info_equal_generic,
};diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_gtp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_gtp.c
new file mode 100644
index 000000000000..19c9bc1a30f5
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_gtp.c
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+
+#include "en/tc_tun.h"
+
+static int
+mlx5e_tc_tun_parse_outer_key_gtp(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct netlink_ext_ack *extack,
+ u32 key, u32 mask,
+ enum fs_flow_table_type fs_type)
+{
+ void *misc3_c, *misc3_v;
+
+ if (!(MLX5_CAP_GEN(priv->mdev, flex_parser_protocols) &
+ MLX5_FLEX_PARSER_GTPU_TEID_ENABLED)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Matching on GTP-U TEID is not supported");
+ return -EOPNOTSUPP;
+ }
+
+ misc3_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
+ misc_parameters_3);
+ misc3_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
+ misc_parameters_3);
+
+ MLX5_SET(fte_match_set_misc3, misc3_c, gtpu_teid, mask);
+ MLX5_SET(fte_match_set_misc3, misc3_v, gtpu_teid, key);
+ spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS_3;
+
+ return 0;
+}
+
+/* The driver offloads no GTP device so this only matches on the wire */
+struct mlx5e_tc_tunnel gtp_tunnel = {
+ .parse_outer_key = mlx5e_tc_tun_parse_outer_key_gtp,
+};diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c
index 33911e72d20d..610e2bbc21f1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c
@@ -5,6 +5,7 @@
#include <net/vxlan.h>
#include "lib/vxlan.h"
#include "en/tc_tun.h"
+#include "fs_core.h"
static bool mlx5e_tc_tun_can_offload_vxlan(struct mlx5e_priv *priv)
{@@ -261,6 +262,41 @@ static int mlx5e_tc_tun_get_remote_ifindex(struct net_device *mirred_dev)
return ifindex;
}
+static int
+mlx5e_tc_tun_parse_outer_key_vxlan(struct mlx5e_priv *priv,
+ struct mlx5_flow_spec *spec,
+ struct netlink_ext_ack *extack,
+ u32 key, u32 mask,
+ enum fs_flow_table_type fs_type)
+{
+ void *misc_c, *misc_v;
+
+ if (key >= MLX5E_TC_TUN_N_VNI) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Tunnel key does not fit the 24 bit VNI");
+ return -EOPNOTSUPP;
+ }
+
+ if (!MLX5_CAP_FLOWTABLE_TYPE(priv->mdev,
+ ft_field_support.outer_vxlan_vni,
+ fs_type)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Matching on VXLAN VNI is not supported");
+ return -EOPNOTSUPP;
+ }
+
+ misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
+ misc_parameters);
+ misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
+ misc_parameters);
+
+ MLX5_SET(fte_match_set_misc, misc_c, vxlan_vni, mask);
+ MLX5_SET(fte_match_set_misc, misc_v, vxlan_vni, key);
+ spec->match_criteria_enable |= MLX5_MATCH_MISC_PARAMETERS;
+
+ return 0;
+}
+
struct mlx5e_tc_tunnel vxlan_tunnel = {
.tunnel_type = MLX5E_TC_TUNNEL_TYPE_VXLAN,
.match_level = MLX5_MATCH_L4,@@ -270,6 +306,7 @@ struct mlx5e_tc_tunnel vxlan_tunnel = {
.generate_ip_tun_hdr = mlx5e_gen_ip_tunnel_header_vxlan,
.parse_udp_ports = mlx5e_tc_tun_parse_udp_ports_vxlan,
.parse_tunnel = mlx5e_tc_tun_parse_vxlan,
+ .parse_outer_key = mlx5e_tc_tun_parse_outer_key_vxlan,
.encap_info_equal = mlx5e_tc_tun_encap_info_equal_vxlan,
.get_remote_ifindex = mlx5e_tc_tun_get_remote_ifindex,
};diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index 3823ccc60dd3..6780e54a0cb9 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -2786,6 +2786,10 @@ static int __parse_cls_flower(struct mlx5e_priv *priv,
err = mlx5e_tc_verify_tunnel_ecn(priv, f, &match_inner_ecn);
if (err)
return err;
+ } else if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
+ err = mlx5e_tc_tun_parse_outer_key(priv, spec, f, fs_type);
+ if (err)
+ return err;
}
err = mlx5e_flower_parse_meta(filter_dev, f);--
2.43.0