mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-19 04:14:49 +08:00
net/mlx5e: Rearrange tc tunnel code in a modular way
Rearrange tc tunnel code so that it would be easy to add future tunnels: - Define tc tunnel object with the fields and callbacks that any tunnel must implement. - Define tc UDP tunnel object for UDP tunnels, such as VXLAN - Move each tunnel code (GRE, VXLAN) to its own separate file - Rewrite tc tunnel implementation in a general way - using only the objects and their callbacks. Reviewed-by: Oz Shlomo <ozsh@mellanox.com> Signed-off-by: Yevgeny Kliteynik <kliteyn@mellanox.com> Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
This commit is contained in:
parent
1f6da30697
commit
d386939a32
@ -32,7 +32,7 @@ mlx5_core-$(CONFIG_MLX5_EN_ARFS) += en_arfs.o
|
||||
mlx5_core-$(CONFIG_MLX5_EN_RXNFC) += en_fs_ethtool.o
|
||||
mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
|
||||
mlx5_core-$(CONFIG_MLX5_ESWITCH) += en_rep.o en_tc.o en/tc_tun.o lib/port_tun.o lag_mp.o \
|
||||
lib/geneve.o
|
||||
lib/geneve.o en/tc_tun_vxlan.o en/tc_tun_gre.o
|
||||
|
||||
#
|
||||
# Core extra
|
||||
|
@ -3,9 +3,19 @@
|
||||
|
||||
#include <net/vxlan.h>
|
||||
#include <net/gre.h>
|
||||
#include "lib/vxlan.h"
|
||||
#include "en/tc_tun.h"
|
||||
|
||||
struct mlx5e_tc_tunnel *mlx5e_get_tc_tun(struct net_device *tunnel_dev)
|
||||
{
|
||||
if (netif_is_vxlan(tunnel_dev))
|
||||
return &vxlan_tunnel;
|
||||
else if (netif_is_gretap(tunnel_dev) ||
|
||||
netif_is_ip6gretap(tunnel_dev))
|
||||
return &gre_tunnel;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int get_route_and_out_devs(struct mlx5e_priv *priv,
|
||||
struct net_device *dev,
|
||||
struct net_device **route_dev,
|
||||
@ -141,64 +151,15 @@ static int mlx5e_route_lookup_ipv6(struct mlx5e_priv *priv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx5e_gen_vxlan_header(char buf[],
|
||||
const struct ip_tunnel_key *tun_key)
|
||||
{
|
||||
__be32 tun_id = tunnel_id_to_key32(tun_key->tun_id);
|
||||
struct udphdr *udp = (struct udphdr *)(buf);
|
||||
struct vxlanhdr *vxh = (struct vxlanhdr *)
|
||||
((char *)udp + sizeof(struct udphdr));
|
||||
|
||||
udp->dest = tun_key->tp_dst;
|
||||
vxh->vx_flags = VXLAN_HF_VNI;
|
||||
vxh->vx_vni = vxlan_vni_field(tun_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx5e_gen_gre_header(char buf[], const struct ip_tunnel_key *tun_key)
|
||||
{
|
||||
__be32 tun_id = tunnel_id_to_key32(tun_key->tun_id);
|
||||
int hdr_len;
|
||||
struct gre_base_hdr *greh = (struct gre_base_hdr *)(buf);
|
||||
|
||||
/* the HW does not calculate GRE csum or sequences */
|
||||
if (tun_key->tun_flags & (TUNNEL_CSUM | TUNNEL_SEQ))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
greh->protocol = htons(ETH_P_TEB);
|
||||
|
||||
/* GRE key */
|
||||
hdr_len = gre_calc_hlen(tun_key->tun_flags);
|
||||
greh->flags = gre_tnl_flags_to_gre_flags(tun_key->tun_flags);
|
||||
if (tun_key->tun_flags & TUNNEL_KEY) {
|
||||
__be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
|
||||
|
||||
*ptr = tun_id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx5e_gen_ip_tunnel_header(char buf[], __u8 *ip_proto,
|
||||
struct mlx5e_encap_entry *e)
|
||||
{
|
||||
int err = 0;
|
||||
const struct ip_tunnel_key *key = &e->tun_info->key;
|
||||
|
||||
if (e->tunnel_type == MLX5E_TC_TUNNEL_TYPE_VXLAN) {
|
||||
*ip_proto = IPPROTO_UDP;
|
||||
err = mlx5e_gen_vxlan_header(buf, key);
|
||||
} else if (e->tunnel_type == MLX5E_TC_TUNNEL_TYPE_GRETAP) {
|
||||
*ip_proto = IPPROTO_GRE;
|
||||
err = mlx5e_gen_gre_header(buf, key);
|
||||
} else {
|
||||
pr_warn("mlx5: Cannot generate tunnel header for tunnel type (%d)\n"
|
||||
, e->tunnel_type);
|
||||
err = -EOPNOTSUPP;
|
||||
if (!e->tunnel) {
|
||||
pr_warn("mlx5: Cannot generate tunnel header for this tunnel\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return err;
|
||||
return e->tunnel->generate_ip_tun_hdr(buf, ip_proto, e);
|
||||
}
|
||||
|
||||
static char *gen_eth_tnl_hdr(char *buf, struct net_device *dev,
|
||||
@ -254,7 +215,7 @@ int mlx5e_tc_tun_create_header_ipv4(struct mlx5e_priv *priv,
|
||||
ipv4_encap_size =
|
||||
(is_vlan_dev(route_dev) ? VLAN_ETH_HLEN : ETH_HLEN) +
|
||||
sizeof(struct iphdr) +
|
||||
e->tunnel_hlen;
|
||||
e->tunnel->calc_hlen(e);
|
||||
|
||||
if (max_encap_size < ipv4_encap_size) {
|
||||
mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n",
|
||||
@ -370,7 +331,7 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv,
|
||||
ipv6_encap_size =
|
||||
(is_vlan_dev(route_dev) ? VLAN_ETH_HLEN : ETH_HLEN) +
|
||||
sizeof(struct ipv6hdr) +
|
||||
e->tunnel_hlen;
|
||||
e->tunnel->calc_hlen(e);
|
||||
|
||||
if (max_encap_size < ipv6_encap_size) {
|
||||
mlx5_core_warn(priv->mdev, "encap size %d too big, max supported is %d\n",
|
||||
@ -456,27 +417,12 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int mlx5e_tc_tun_get_type(struct net_device *tunnel_dev)
|
||||
{
|
||||
if (netif_is_vxlan(tunnel_dev))
|
||||
return MLX5E_TC_TUNNEL_TYPE_VXLAN;
|
||||
else if (netif_is_gretap(tunnel_dev) ||
|
||||
netif_is_ip6gretap(tunnel_dev))
|
||||
return MLX5E_TC_TUNNEL_TYPE_GRETAP;
|
||||
else
|
||||
return MLX5E_TC_TUNNEL_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
bool mlx5e_tc_tun_device_to_offload(struct mlx5e_priv *priv,
|
||||
struct net_device *netdev)
|
||||
{
|
||||
int tunnel_type = mlx5e_tc_tun_get_type(netdev);
|
||||
struct mlx5e_tc_tunnel *tunnel = mlx5e_get_tc_tun(netdev);
|
||||
|
||||
if (tunnel_type == MLX5E_TC_TUNNEL_TYPE_VXLAN &&
|
||||
MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap))
|
||||
return true;
|
||||
else if (tunnel_type == MLX5E_TC_TUNNEL_TYPE_GRETAP &&
|
||||
MLX5_CAP_ESW(priv->mdev, nvgre_encap_decap))
|
||||
if (tunnel && tunnel->can_offload(priv))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
@ -487,137 +433,14 @@ int mlx5e_tc_tun_init_encap_attr(struct net_device *tunnel_dev,
|
||||
struct mlx5e_encap_entry *e,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
e->tunnel_type = mlx5e_tc_tun_get_type(tunnel_dev);
|
||||
struct mlx5e_tc_tunnel *tunnel = mlx5e_get_tc_tun(tunnel_dev);
|
||||
|
||||
if (e->tunnel_type == MLX5E_TC_TUNNEL_TYPE_VXLAN) {
|
||||
int dst_port = be16_to_cpu(e->tun_info->key.tp_dst);
|
||||
|
||||
if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan, dst_port)) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"vxlan udp dport was not registered with the HW");
|
||||
netdev_warn(priv->netdev,
|
||||
"%d isn't an offloaded vxlan udp dport\n",
|
||||
dst_port);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_VXLAN;
|
||||
e->tunnel_hlen = VXLAN_HLEN;
|
||||
} else if (e->tunnel_type == MLX5E_TC_TUNNEL_TYPE_GRETAP) {
|
||||
e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_NVGRE;
|
||||
e->tunnel_hlen = gre_calc_hlen(e->tun_info->key.tun_flags);
|
||||
} else {
|
||||
if (!tunnel) {
|
||||
e->reformat_type = -1;
|
||||
e->tunnel_hlen = -1;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv,
|
||||
struct mlx5_flow_spec *spec,
|
||||
struct tc_cls_flower_offload *f,
|
||||
void *headers_c,
|
||||
void *headers_v)
|
||||
{
|
||||
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
|
||||
struct netlink_ext_ack *extack = f->common.extack;
|
||||
void *misc_c = MLX5_ADDR_OF(fte_match_param,
|
||||
spec->match_criteria,
|
||||
misc_parameters);
|
||||
void *misc_v = MLX5_ADDR_OF(fte_match_param,
|
||||
spec->match_value,
|
||||
misc_parameters);
|
||||
struct flow_match_ports enc_ports;
|
||||
|
||||
flow_rule_match_enc_ports(rule, &enc_ports);
|
||||
|
||||
/* Full udp dst port must be given */
|
||||
if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS) ||
|
||||
memchr_inv(&enc_ports.mask->dst, 0xff, sizeof(enc_ports.mask->dst))) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"VXLAN decap filter must include enc_dst_port condition");
|
||||
netdev_warn(priv->netdev,
|
||||
"VXLAN decap filter must include enc_dst_port condition\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* udp dst port must be knonwn as a VXLAN port */
|
||||
if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan, be16_to_cpu(enc_ports.key->dst))) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Matched UDP port is not registered as a VXLAN port");
|
||||
netdev_warn(priv->netdev,
|
||||
"UDP port %d is not registered as a VXLAN port\n",
|
||||
be16_to_cpu(enc_ports.key->dst));
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* dst UDP port is valid here */
|
||||
MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ip_protocol);
|
||||
MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP);
|
||||
|
||||
MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_dport,
|
||||
ntohs(enc_ports.mask->dst));
|
||||
MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
|
||||
ntohs(enc_ports.key->dst));
|
||||
|
||||
MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_sport,
|
||||
ntohs(enc_ports.mask->src));
|
||||
MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport,
|
||||
ntohs(enc_ports.key->src));
|
||||
|
||||
/* match on VNI */
|
||||
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
|
||||
struct flow_match_enc_keyid enc_keyid;
|
||||
|
||||
flow_rule_match_enc_keyid(rule, &enc_keyid);
|
||||
|
||||
MLX5_SET(fte_match_set_misc, misc_c, vxlan_vni,
|
||||
be32_to_cpu(enc_keyid.mask->keyid));
|
||||
MLX5_SET(fte_match_set_misc, misc_v, vxlan_vni,
|
||||
be32_to_cpu(enc_keyid.key->keyid));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx5e_tc_tun_parse_gretap(struct mlx5e_priv *priv,
|
||||
struct mlx5_flow_spec *spec,
|
||||
struct tc_cls_flower_offload *f,
|
||||
void *outer_headers_c,
|
||||
void *outer_headers_v)
|
||||
{
|
||||
void *misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
|
||||
misc_parameters);
|
||||
void *misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
|
||||
misc_parameters);
|
||||
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
|
||||
|
||||
if (!MLX5_CAP_ESW(priv->mdev, nvgre_encap_decap)) {
|
||||
NL_SET_ERR_MSG_MOD(f->common.extack,
|
||||
"GRE HW offloading is not supported");
|
||||
netdev_warn(priv->netdev, "GRE HW offloading is not supported\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol);
|
||||
MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v,
|
||||
ip_protocol, IPPROTO_GRE);
|
||||
|
||||
/* gre protocol*/
|
||||
MLX5_SET_TO_ONES(fte_match_set_misc, misc_c, gre_protocol);
|
||||
MLX5_SET(fte_match_set_misc, misc_v, gre_protocol, ETH_P_TEB);
|
||||
|
||||
/* gre key */
|
||||
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
|
||||
struct flow_match_enc_keyid enc_keyid;
|
||||
|
||||
flow_rule_match_enc_keyid(rule, &enc_keyid);
|
||||
MLX5_SET(fte_match_set_misc, misc_c,
|
||||
gre_key.key, be32_to_cpu(enc_keyid.mask->keyid));
|
||||
MLX5_SET(fte_match_set_misc, misc_v,
|
||||
gre_key.key, be32_to_cpu(enc_keyid.key->keyid));
|
||||
}
|
||||
|
||||
return 0;
|
||||
return tunnel->init_encap_attr(tunnel_dev, priv, e, extack);
|
||||
}
|
||||
|
||||
int mlx5e_tc_tun_parse(struct net_device *filter_dev,
|
||||
@ -627,25 +450,87 @@ int mlx5e_tc_tun_parse(struct net_device *filter_dev,
|
||||
void *headers_c,
|
||||
void *headers_v, u8 *match_level)
|
||||
{
|
||||
int tunnel_type;
|
||||
struct mlx5e_tc_tunnel *tunnel = mlx5e_get_tc_tun(filter_dev);
|
||||
int err = 0;
|
||||
|
||||
tunnel_type = mlx5e_tc_tun_get_type(filter_dev);
|
||||
if (tunnel_type == MLX5E_TC_TUNNEL_TYPE_VXLAN) {
|
||||
*match_level = MLX5_MATCH_L4;
|
||||
err = mlx5e_tc_tun_parse_vxlan(priv, spec, f,
|
||||
headers_c, headers_v);
|
||||
} else if (tunnel_type == MLX5E_TC_TUNNEL_TYPE_GRETAP) {
|
||||
*match_level = MLX5_MATCH_L3;
|
||||
err = mlx5e_tc_tun_parse_gretap(priv, spec, f,
|
||||
headers_c, headers_v);
|
||||
} else {
|
||||
if (!tunnel) {
|
||||
netdev_warn(priv->netdev,
|
||||
"decapsulation offload is not supported for %s (kind: \"%s\")\n",
|
||||
netdev_name(filter_dev),
|
||||
"decapsulation offload is not supported for %s net device\n",
|
||||
mlx5e_netdev_kind(filter_dev));
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
err = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*match_level = tunnel->match_level;
|
||||
|
||||
if (tunnel->parse_udp_ports) {
|
||||
err = tunnel->parse_udp_ports(priv, spec, f,
|
||||
headers_c, headers_v);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tunnel->parse_tunnel) {
|
||||
err = tunnel->parse_tunnel(priv, spec, f,
|
||||
headers_c, headers_v);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int mlx5e_tc_tun_parse_udp_ports(struct mlx5e_priv *priv,
|
||||
struct mlx5_flow_spec *spec,
|
||||
struct tc_cls_flower_offload *f,
|
||||
void *headers_c,
|
||||
void *headers_v)
|
||||
{
|
||||
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
|
||||
struct netlink_ext_ack *extack = f->common.extack;
|
||||
struct flow_match_ports enc_ports;
|
||||
|
||||
/* Full udp dst port must be given */
|
||||
|
||||
if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS)) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"UDP tunnel decap filter must include enc_dst_port condition");
|
||||
netdev_warn(priv->netdev,
|
||||
"UDP tunnel decap filter must include enc_dst_port condition\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
flow_rule_match_enc_ports(rule, &enc_ports);
|
||||
|
||||
if (memchr_inv(&enc_ports.mask->dst, 0xff,
|
||||
sizeof(enc_ports.mask->dst))) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"UDP tunnel decap filter must match enc_dst_port fully");
|
||||
netdev_warn(priv->netdev,
|
||||
"UDP tunnel decap filter must match enc_dst_port fully\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* match on UDP protocol and dst port number */
|
||||
|
||||
MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ip_protocol);
|
||||
MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP);
|
||||
|
||||
MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_dport,
|
||||
ntohs(enc_ports.mask->dst));
|
||||
MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
|
||||
ntohs(enc_ports.key->dst));
|
||||
|
||||
/* UDP src port on outer header is generated by HW,
|
||||
* so it is probably a bad idea to request matching it.
|
||||
* Nonetheless, it is allowed.
|
||||
*/
|
||||
|
||||
MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_sport,
|
||||
ntohs(enc_ports.mask->src));
|
||||
MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport,
|
||||
ntohs(enc_ports.key->src));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -14,9 +14,39 @@
|
||||
enum {
|
||||
MLX5E_TC_TUNNEL_TYPE_UNKNOWN,
|
||||
MLX5E_TC_TUNNEL_TYPE_VXLAN,
|
||||
MLX5E_TC_TUNNEL_TYPE_GRETAP
|
||||
MLX5E_TC_TUNNEL_TYPE_GRETAP,
|
||||
};
|
||||
|
||||
struct mlx5e_tc_tunnel {
|
||||
int tunnel_type;
|
||||
enum mlx5_flow_match_level match_level;
|
||||
|
||||
bool (*can_offload)(struct mlx5e_priv *priv);
|
||||
int (*calc_hlen)(struct mlx5e_encap_entry *e);
|
||||
int (*init_encap_attr)(struct net_device *tunnel_dev,
|
||||
struct mlx5e_priv *priv,
|
||||
struct mlx5e_encap_entry *e,
|
||||
struct netlink_ext_ack *extack);
|
||||
int (*generate_ip_tun_hdr)(char buf[],
|
||||
__u8 *ip_proto,
|
||||
struct mlx5e_encap_entry *e);
|
||||
int (*parse_udp_ports)(struct mlx5e_priv *priv,
|
||||
struct mlx5_flow_spec *spec,
|
||||
struct tc_cls_flower_offload *f,
|
||||
void *headers_c,
|
||||
void *headers_v);
|
||||
int (*parse_tunnel)(struct mlx5e_priv *priv,
|
||||
struct mlx5_flow_spec *spec,
|
||||
struct tc_cls_flower_offload *f,
|
||||
void *headers_c,
|
||||
void *headers_v);
|
||||
};
|
||||
|
||||
extern struct mlx5e_tc_tunnel vxlan_tunnel;
|
||||
extern struct mlx5e_tc_tunnel gre_tunnel;
|
||||
|
||||
struct mlx5e_tc_tunnel *mlx5e_get_tc_tun(struct net_device *tunnel_dev);
|
||||
|
||||
int mlx5e_tc_tun_init_encap_attr(struct net_device *tunnel_dev,
|
||||
struct mlx5e_priv *priv,
|
||||
struct mlx5e_encap_entry *e,
|
||||
@ -30,7 +60,6 @@ int mlx5e_tc_tun_create_header_ipv6(struct mlx5e_priv *priv,
|
||||
struct net_device *mirred_dev,
|
||||
struct mlx5e_encap_entry *e);
|
||||
|
||||
int mlx5e_tc_tun_get_type(struct net_device *tunnel_dev);
|
||||
bool mlx5e_tc_tun_device_to_offload(struct mlx5e_priv *priv,
|
||||
struct net_device *netdev);
|
||||
|
||||
@ -41,4 +70,10 @@ int mlx5e_tc_tun_parse(struct net_device *filter_dev,
|
||||
void *headers_c,
|
||||
void *headers_v, u8 *match_level);
|
||||
|
||||
int mlx5e_tc_tun_parse_udp_ports(struct mlx5e_priv *priv,
|
||||
struct mlx5_flow_spec *spec,
|
||||
struct tc_cls_flower_offload *f,
|
||||
void *headers_c,
|
||||
void *headers_v);
|
||||
|
||||
#endif //__MLX5_EN_TC_TUNNEL_H__
|
||||
|
95
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_gre.c
Normal file
95
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_gre.c
Normal file
@ -0,0 +1,95 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
|
||||
/* Copyright (c) 2018 Mellanox Technologies. */
|
||||
|
||||
#include <net/gre.h>
|
||||
#include "en/tc_tun.h"
|
||||
|
||||
static bool mlx5e_tc_tun_can_offload_gretap(struct mlx5e_priv *priv)
|
||||
{
|
||||
return !!MLX5_CAP_ESW(priv->mdev, nvgre_encap_decap);
|
||||
}
|
||||
|
||||
static int mlx5e_tc_tun_calc_hlen_gretap(struct mlx5e_encap_entry *e)
|
||||
{
|
||||
return gre_calc_hlen(e->tun_info->key.tun_flags);
|
||||
}
|
||||
|
||||
static int mlx5e_tc_tun_init_encap_attr_gretap(struct net_device *tunnel_dev,
|
||||
struct mlx5e_priv *priv,
|
||||
struct mlx5e_encap_entry *e,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
e->tunnel = &gre_tunnel;
|
||||
e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_NVGRE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx5e_gen_ip_tunnel_header_gretap(char buf[],
|
||||
__u8 *ip_proto,
|
||||
struct mlx5e_encap_entry *e)
|
||||
{
|
||||
const struct ip_tunnel_key *tun_key = &e->tun_info->key;
|
||||
struct gre_base_hdr *greh = (struct gre_base_hdr *)(buf);
|
||||
__be32 tun_id = tunnel_id_to_key32(tun_key->tun_id);
|
||||
int hdr_len;
|
||||
|
||||
*ip_proto = IPPROTO_GRE;
|
||||
|
||||
/* the HW does not calculate GRE csum or sequences */
|
||||
if (tun_key->tun_flags & (TUNNEL_CSUM | TUNNEL_SEQ))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
greh->protocol = htons(ETH_P_TEB);
|
||||
|
||||
/* GRE key */
|
||||
hdr_len = mlx5e_tc_tun_calc_hlen_gretap(e);
|
||||
greh->flags = gre_tnl_flags_to_gre_flags(tun_key->tun_flags);
|
||||
if (tun_key->tun_flags & TUNNEL_KEY) {
|
||||
__be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
|
||||
*ptr = tun_id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx5e_tc_tun_parse_gretap(struct mlx5e_priv *priv,
|
||||
struct mlx5_flow_spec *spec,
|
||||
struct tc_cls_flower_offload *f,
|
||||
void *headers_c,
|
||||
void *headers_v)
|
||||
{
|
||||
void *misc_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
|
||||
void *misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
|
||||
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
|
||||
|
||||
MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ip_protocol);
|
||||
MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_GRE);
|
||||
|
||||
/* gre protocol */
|
||||
MLX5_SET_TO_ONES(fte_match_set_misc, misc_c, gre_protocol);
|
||||
MLX5_SET(fte_match_set_misc, misc_v, gre_protocol, ETH_P_TEB);
|
||||
|
||||
/* gre key */
|
||||
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
|
||||
struct flow_match_enc_keyid enc_keyid;
|
||||
|
||||
flow_rule_match_enc_keyid(rule, &enc_keyid);
|
||||
MLX5_SET(fte_match_set_misc, misc_c,
|
||||
gre_key.key, be32_to_cpu(enc_keyid.mask->keyid));
|
||||
MLX5_SET(fte_match_set_misc, misc_v,
|
||||
gre_key.key, be32_to_cpu(enc_keyid.key->keyid));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mlx5e_tc_tunnel gre_tunnel = {
|
||||
.tunnel_type = MLX5E_TC_TUNNEL_TYPE_GRETAP,
|
||||
.match_level = MLX5_MATCH_L3,
|
||||
.can_offload = mlx5e_tc_tun_can_offload_gretap,
|
||||
.calc_hlen = mlx5e_tc_tun_calc_hlen_gretap,
|
||||
.init_encap_attr = mlx5e_tc_tun_init_encap_attr_gretap,
|
||||
.generate_ip_tun_hdr = mlx5e_gen_ip_tunnel_header_gretap,
|
||||
.parse_udp_ports = NULL,
|
||||
.parse_tunnel = mlx5e_tc_tun_parse_gretap,
|
||||
};
|
151
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c
Normal file
151
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_vxlan.c
Normal file
@ -0,0 +1,151 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
|
||||
/* Copyright (c) 2018 Mellanox Technologies. */
|
||||
|
||||
#include <net/vxlan.h>
|
||||
#include "lib/vxlan.h"
|
||||
#include "en/tc_tun.h"
|
||||
|
||||
static bool mlx5e_tc_tun_can_offload_vxlan(struct mlx5e_priv *priv)
|
||||
{
|
||||
return !!MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap);
|
||||
}
|
||||
|
||||
static int mlx5e_tc_tun_calc_hlen_vxlan(struct mlx5e_encap_entry *e)
|
||||
{
|
||||
return VXLAN_HLEN;
|
||||
}
|
||||
|
||||
static int mlx5e_tc_tun_check_udp_dport_vxlan(struct mlx5e_priv *priv,
|
||||
struct tc_cls_flower_offload *f)
|
||||
{
|
||||
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
|
||||
struct netlink_ext_ack *extack = f->common.extack;
|
||||
struct flow_match_ports enc_ports;
|
||||
|
||||
if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
flow_rule_match_enc_ports(rule, &enc_ports);
|
||||
|
||||
/* check the UDP destination port validity */
|
||||
|
||||
if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan,
|
||||
be16_to_cpu(enc_ports.key->dst))) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Matched UDP dst port is not registered as a VXLAN port");
|
||||
netdev_warn(priv->netdev,
|
||||
"UDP port %d is not registered as a VXLAN port\n",
|
||||
be16_to_cpu(enc_ports.key->dst));
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx5e_tc_tun_parse_udp_ports_vxlan(struct mlx5e_priv *priv,
|
||||
struct mlx5_flow_spec *spec,
|
||||
struct tc_cls_flower_offload *f,
|
||||
void *headers_c,
|
||||
void *headers_v)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
err = mlx5e_tc_tun_parse_udp_ports(priv, spec, f, headers_c, headers_v);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return mlx5e_tc_tun_check_udp_dport_vxlan(priv, f);
|
||||
}
|
||||
|
||||
static int mlx5e_tc_tun_init_encap_attr_vxlan(struct net_device *tunnel_dev,
|
||||
struct mlx5e_priv *priv,
|
||||
struct mlx5e_encap_entry *e,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
int dst_port = be16_to_cpu(e->tun_info->key.tp_dst);
|
||||
|
||||
e->tunnel = &vxlan_tunnel;
|
||||
|
||||
if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan, dst_port)) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"vxlan udp dport was not registered with the HW");
|
||||
netdev_warn(priv->netdev,
|
||||
"%d isn't an offloaded vxlan udp dport\n",
|
||||
dst_port);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
e->reformat_type = MLX5_REFORMAT_TYPE_L2_TO_VXLAN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx5e_gen_ip_tunnel_header_vxlan(char buf[],
|
||||
__u8 *ip_proto,
|
||||
struct mlx5e_encap_entry *e)
|
||||
{
|
||||
const struct ip_tunnel_key *tun_key = &e->tun_info->key;
|
||||
__be32 tun_id = tunnel_id_to_key32(tun_key->tun_id);
|
||||
struct udphdr *udp = (struct udphdr *)(buf);
|
||||
struct vxlanhdr *vxh;
|
||||
|
||||
vxh = (struct vxlanhdr *)((char *)udp + sizeof(struct udphdr));
|
||||
*ip_proto = IPPROTO_UDP;
|
||||
|
||||
udp->dest = tun_key->tp_dst;
|
||||
vxh->vx_flags = VXLAN_HF_VNI;
|
||||
vxh->vx_vni = vxlan_vni_field(tun_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv,
|
||||
struct mlx5_flow_spec *spec,
|
||||
struct tc_cls_flower_offload *f,
|
||||
void *headers_c,
|
||||
void *headers_v)
|
||||
{
|
||||
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
|
||||
struct netlink_ext_ack *extack = f->common.extack;
|
||||
struct flow_match_enc_keyid enc_keyid;
|
||||
void *misc_c, *misc_v;
|
||||
|
||||
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);
|
||||
|
||||
if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID))
|
||||
return 0;
|
||||
|
||||
flow_rule_match_enc_keyid(rule, &enc_keyid);
|
||||
|
||||
if (!enc_keyid.mask->keyid)
|
||||
return 0;
|
||||
|
||||
/* match on VNI is required */
|
||||
|
||||
if (!MLX5_CAP_ESW_FLOWTABLE_FDB(priv->mdev,
|
||||
ft_field_support.outer_vxlan_vni)) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Matching on VXLAN VNI is not supported");
|
||||
netdev_warn(priv->netdev,
|
||||
"Matching on VXLAN VNI is not supported\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
MLX5_SET(fte_match_set_misc, misc_c, vxlan_vni,
|
||||
be32_to_cpu(enc_keyid.mask->keyid));
|
||||
MLX5_SET(fte_match_set_misc, misc_v, vxlan_vni,
|
||||
be32_to_cpu(enc_keyid.key->keyid));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mlx5e_tc_tunnel vxlan_tunnel = {
|
||||
.tunnel_type = MLX5E_TC_TUNNEL_TYPE_VXLAN,
|
||||
.match_level = MLX5_MATCH_L4,
|
||||
.can_offload = mlx5e_tc_tun_can_offload_vxlan,
|
||||
.calc_hlen = mlx5e_tc_tun_calc_hlen_vxlan,
|
||||
.init_encap_attr = mlx5e_tc_tun_init_encap_attr_vxlan,
|
||||
.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,
|
||||
};
|
@ -155,8 +155,7 @@ struct mlx5e_encap_entry {
|
||||
|
||||
struct net_device *out_dev;
|
||||
struct net_device *route_dev;
|
||||
int tunnel_type;
|
||||
int tunnel_hlen;
|
||||
struct mlx5e_tc_tunnel *tunnel;
|
||||
int reformat_type;
|
||||
u8 flags;
|
||||
char *encap_header;
|
||||
|
@ -2569,20 +2569,20 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv,
|
||||
|
||||
struct encap_key {
|
||||
const struct ip_tunnel_key *ip_tun_key;
|
||||
int tunnel_type;
|
||||
struct mlx5e_tc_tunnel *tc_tunnel;
|
||||
};
|
||||
|
||||
static inline int cmp_encap_info(struct encap_key *a,
|
||||
struct encap_key *b)
|
||||
{
|
||||
return memcmp(a->ip_tun_key, b->ip_tun_key, sizeof(*a->ip_tun_key)) ||
|
||||
a->tunnel_type != b->tunnel_type;
|
||||
a->tc_tunnel->tunnel_type != b->tc_tunnel->tunnel_type;
|
||||
}
|
||||
|
||||
static inline int hash_encap_info(struct encap_key *key)
|
||||
{
|
||||
return jhash(key->ip_tun_key, sizeof(*key->ip_tun_key),
|
||||
key->tunnel_type);
|
||||
key->tc_tunnel->tunnel_type);
|
||||
}
|
||||
|
||||
|
||||
@ -2624,14 +2624,14 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv,
|
||||
tun_info = parse_attr->tun_info[out_index];
|
||||
family = ip_tunnel_info_af(tun_info);
|
||||
key.ip_tun_key = &tun_info->key;
|
||||
key.tunnel_type = mlx5e_tc_tun_get_type(mirred_dev);
|
||||
key.tc_tunnel = mlx5e_get_tc_tun(mirred_dev);
|
||||
|
||||
hash_key = hash_encap_info(&key);
|
||||
|
||||
hash_for_each_possible_rcu(esw->offloads.encap_tbl, e,
|
||||
encap_hlist, hash_key) {
|
||||
e_key.ip_tun_key = &e->tun_info->key;
|
||||
e_key.tunnel_type = e->tunnel_type;
|
||||
e_key.tc_tunnel = e->tunnel;
|
||||
if (!cmp_encap_info(&e_key, &key)) {
|
||||
found = true;
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user