net/mlx5e: Add netdev support for VXLAN tunneling
If a VXLAN udp dport is added to device it will: - Configure the hardware to offload the port (up to the max supported). - Advertise NETIF_F_GSO_UDP_TUNNEL and supported hw_enc_features. Signed-off-by: Matthew Finlay <matt@mellanox.com> Signed-off-by: Saeed Mahameed <saeedm@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
1afff42c06
commit
b3f63c3d5e
|
@ -6,6 +6,6 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
|
|||
|
||||
mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o \
|
||||
en_main.o en_fs.o en_ethtool.o en_tx.o en_rx.o \
|
||||
en_txrx.o en_clock.o
|
||||
en_txrx.o en_clock.o vxlan.o
|
||||
|
||||
mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
|
||||
* Copyright (c) 2013-2016, Mellanox Technologies. All rights reserved.
|
||||
*
|
||||
* This software is available to you under a choice of one of two
|
||||
* licenses. You may choose to be licensed under the terms of the GNU
|
||||
|
@ -566,6 +566,12 @@ const char *mlx5_command_str(int command)
|
|||
case MLX5_CMD_OP_QUERY_WOL_ROL:
|
||||
return "QUERY_WOL_ROL";
|
||||
|
||||
case MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT:
|
||||
return "ADD_VXLAN_UDP_DPORT";
|
||||
|
||||
case MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT:
|
||||
return "DELETE_VXLAN_UDP_DPORT";
|
||||
|
||||
default: return "unknown command opcode";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -501,6 +501,11 @@ struct mlx5e_vlan_db {
|
|||
bool filter_disabled;
|
||||
};
|
||||
|
||||
struct mlx5e_vxlan_db {
|
||||
spinlock_t lock; /* protect vxlan table */
|
||||
struct radix_tree_root tree;
|
||||
};
|
||||
|
||||
struct mlx5e_flow_table {
|
||||
int num_groups;
|
||||
struct mlx5_flow_table *t;
|
||||
|
@ -535,6 +540,7 @@ struct mlx5e_priv {
|
|||
struct mlx5e_flow_tables fts;
|
||||
struct mlx5e_eth_addr_db eth_addr;
|
||||
struct mlx5e_vlan_db vlan;
|
||||
struct mlx5e_vxlan_db vxlan;
|
||||
|
||||
struct mlx5e_params params;
|
||||
spinlock_t async_events_spinlock; /* sync hw events */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Mellanox Technologies. All rights reserved.
|
||||
* Copyright (c) 2015-2016, Mellanox Technologies. All rights reserved.
|
||||
*
|
||||
* This software is available to you under a choice of one of two
|
||||
* licenses. You may choose to be licensed under the terms of the GNU
|
||||
|
@ -31,8 +31,10 @@
|
|||
*/
|
||||
|
||||
#include <linux/mlx5/fs.h>
|
||||
#include <net/vxlan.h>
|
||||
#include "en.h"
|
||||
#include "eswitch.h"
|
||||
#include "vxlan.h"
|
||||
|
||||
struct mlx5e_rq_param {
|
||||
u32 rqc[MLX5_ST_SZ_DW(rqc)];
|
||||
|
@ -2078,6 +2080,78 @@ static int mlx5e_get_vf_stats(struct net_device *dev,
|
|||
vf_stats);
|
||||
}
|
||||
|
||||
static void mlx5e_add_vxlan_port(struct net_device *netdev,
|
||||
sa_family_t sa_family, __be16 port)
|
||||
{
|
||||
struct mlx5e_priv *priv = netdev_priv(netdev);
|
||||
|
||||
if (!mlx5e_vxlan_allowed(priv->mdev))
|
||||
return;
|
||||
|
||||
mlx5e_vxlan_add_port(priv, be16_to_cpu(port));
|
||||
}
|
||||
|
||||
static void mlx5e_del_vxlan_port(struct net_device *netdev,
|
||||
sa_family_t sa_family, __be16 port)
|
||||
{
|
||||
struct mlx5e_priv *priv = netdev_priv(netdev);
|
||||
|
||||
if (!mlx5e_vxlan_allowed(priv->mdev))
|
||||
return;
|
||||
|
||||
mlx5e_vxlan_del_port(priv, be16_to_cpu(port));
|
||||
}
|
||||
|
||||
static netdev_features_t mlx5e_vxlan_features_check(struct mlx5e_priv *priv,
|
||||
struct sk_buff *skb,
|
||||
netdev_features_t features)
|
||||
{
|
||||
struct udphdr *udph;
|
||||
u16 proto;
|
||||
u16 port = 0;
|
||||
|
||||
switch (vlan_get_protocol(skb)) {
|
||||
case htons(ETH_P_IP):
|
||||
proto = ip_hdr(skb)->protocol;
|
||||
break;
|
||||
case htons(ETH_P_IPV6):
|
||||
proto = ipv6_hdr(skb)->nexthdr;
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (proto == IPPROTO_UDP) {
|
||||
udph = udp_hdr(skb);
|
||||
port = be16_to_cpu(udph->dest);
|
||||
}
|
||||
|
||||
/* Verify if UDP port is being offloaded by HW */
|
||||
if (port && mlx5e_vxlan_lookup_port(priv, port))
|
||||
return features;
|
||||
|
||||
out:
|
||||
/* Disable CSUM and GSO if the udp dport is not offloaded by HW */
|
||||
return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
|
||||
}
|
||||
|
||||
static netdev_features_t mlx5e_features_check(struct sk_buff *skb,
|
||||
struct net_device *netdev,
|
||||
netdev_features_t features)
|
||||
{
|
||||
struct mlx5e_priv *priv = netdev_priv(netdev);
|
||||
|
||||
features = vlan_features_check(skb, features);
|
||||
features = vxlan_features_check(skb, features);
|
||||
|
||||
/* Validate if the tunneled packet is being offloaded by HW */
|
||||
if (skb->encapsulation &&
|
||||
(features & NETIF_F_CSUM_MASK || features & NETIF_F_GSO_MASK))
|
||||
return mlx5e_vxlan_features_check(priv, skb, features);
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
static const struct net_device_ops mlx5e_netdev_ops_basic = {
|
||||
.ndo_open = mlx5e_open,
|
||||
.ndo_stop = mlx5e_close,
|
||||
|
@ -2108,6 +2182,9 @@ static const struct net_device_ops mlx5e_netdev_ops_sriov = {
|
|||
.ndo_set_features = mlx5e_set_features,
|
||||
.ndo_change_mtu = mlx5e_change_mtu,
|
||||
.ndo_do_ioctl = mlx5e_ioctl,
|
||||
.ndo_add_vxlan_port = mlx5e_add_vxlan_port,
|
||||
.ndo_del_vxlan_port = mlx5e_del_vxlan_port,
|
||||
.ndo_features_check = mlx5e_features_check,
|
||||
.ndo_set_vf_mac = mlx5e_set_vf_mac,
|
||||
.ndo_set_vf_vlan = mlx5e_set_vf_vlan,
|
||||
.ndo_get_vf_config = mlx5e_get_vf_config,
|
||||
|
@ -2264,6 +2341,16 @@ static void mlx5e_build_netdev(struct net_device *netdev)
|
|||
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
|
||||
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
|
||||
|
||||
if (mlx5e_vxlan_allowed(mdev)) {
|
||||
netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
|
||||
netdev->hw_enc_features |= NETIF_F_IP_CSUM;
|
||||
netdev->hw_enc_features |= NETIF_F_RXCSUM;
|
||||
netdev->hw_enc_features |= NETIF_F_TSO;
|
||||
netdev->hw_enc_features |= NETIF_F_TSO6;
|
||||
netdev->hw_enc_features |= NETIF_F_RXHASH;
|
||||
netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL;
|
||||
}
|
||||
|
||||
netdev->features = netdev->hw_features;
|
||||
if (!priv->params.lro_en)
|
||||
netdev->features &= ~NETIF_F_LRO;
|
||||
|
@ -2387,6 +2474,8 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev)
|
|||
|
||||
mlx5e_init_eth_addr(priv);
|
||||
|
||||
mlx5e_vxlan_init(priv);
|
||||
|
||||
#ifdef CONFIG_MLX5_CORE_EN_DCB
|
||||
mlx5e_dcbnl_ieee_setets_core(priv, &priv->params.ets);
|
||||
#endif
|
||||
|
@ -2397,6 +2486,9 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev)
|
|||
goto err_destroy_flow_tables;
|
||||
}
|
||||
|
||||
if (mlx5e_vxlan_allowed(mdev))
|
||||
vxlan_get_rx_port(netdev);
|
||||
|
||||
mlx5e_enable_async_events(priv);
|
||||
schedule_work(&priv->set_rx_mode_work);
|
||||
|
||||
|
@ -2449,6 +2541,7 @@ static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv)
|
|||
mlx5e_disable_async_events(priv);
|
||||
flush_scheduled_work();
|
||||
unregister_netdev(netdev);
|
||||
mlx5e_vxlan_cleanup(priv);
|
||||
mlx5e_destroy_flow_tables(priv);
|
||||
mlx5e_destroy_tirs(priv);
|
||||
mlx5e_destroy_rqt(priv, MLX5E_SINGLE_RQ_RQT);
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Mellanox Technologies, Ltd. All rights reserved.
|
||||
*
|
||||
* This software is available to you under a choice of one of two
|
||||
* licenses. You may choose to be licensed under the terms of the GNU
|
||||
* General Public License (GPL) Version 2, available from the file
|
||||
* COPYING in the main directory of this source tree, or the
|
||||
* OpenIB.org BSD license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mlx5/driver.h>
|
||||
#include "mlx5_core.h"
|
||||
#include "vxlan.h"
|
||||
|
||||
void mlx5e_vxlan_init(struct mlx5e_priv *priv)
|
||||
{
|
||||
struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
|
||||
|
||||
spin_lock_init(&vxlan_db->lock);
|
||||
INIT_RADIX_TREE(&vxlan_db->tree, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
static int mlx5e_vxlan_core_add_port_cmd(struct mlx5_core_dev *mdev, u16 port)
|
||||
{
|
||||
struct mlx5_outbox_hdr *hdr;
|
||||
int err;
|
||||
|
||||
u32 in[MLX5_ST_SZ_DW(add_vxlan_udp_dport_in)];
|
||||
u32 out[MLX5_ST_SZ_DW(add_vxlan_udp_dport_out)];
|
||||
|
||||
memset(in, 0, sizeof(in));
|
||||
memset(out, 0, sizeof(out));
|
||||
|
||||
MLX5_SET(add_vxlan_udp_dport_in, in, opcode,
|
||||
MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT);
|
||||
MLX5_SET(add_vxlan_udp_dport_in, in, vxlan_udp_port, port);
|
||||
|
||||
err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
hdr = (struct mlx5_outbox_hdr *)out;
|
||||
return hdr->status ? -ENOMEM : 0;
|
||||
}
|
||||
|
||||
static int mlx5e_vxlan_core_del_port_cmd(struct mlx5_core_dev *mdev, u16 port)
|
||||
{
|
||||
u32 in[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_in)];
|
||||
u32 out[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_out)];
|
||||
|
||||
memset(&in, 0, sizeof(in));
|
||||
memset(&out, 0, sizeof(out));
|
||||
|
||||
MLX5_SET(delete_vxlan_udp_dport_in, in, opcode,
|
||||
MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT);
|
||||
MLX5_SET(delete_vxlan_udp_dport_in, in, vxlan_udp_port, port);
|
||||
|
||||
return mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out,
|
||||
sizeof(out));
|
||||
}
|
||||
|
||||
struct mlx5e_vxlan *mlx5e_vxlan_lookup_port(struct mlx5e_priv *priv, u16 port)
|
||||
{
|
||||
struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
|
||||
struct mlx5e_vxlan *vxlan;
|
||||
|
||||
spin_lock(&vxlan_db->lock);
|
||||
vxlan = radix_tree_lookup(&vxlan_db->tree, port);
|
||||
spin_unlock(&vxlan_db->lock);
|
||||
|
||||
return vxlan;
|
||||
}
|
||||
|
||||
int mlx5e_vxlan_add_port(struct mlx5e_priv *priv, u16 port)
|
||||
{
|
||||
struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
|
||||
struct mlx5e_vxlan *vxlan;
|
||||
int err;
|
||||
|
||||
err = mlx5e_vxlan_core_add_port_cmd(priv->mdev, port);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
vxlan = kzalloc(sizeof(*vxlan), GFP_KERNEL);
|
||||
if (!vxlan) {
|
||||
err = -ENOMEM;
|
||||
goto err_delete_port;
|
||||
}
|
||||
|
||||
vxlan->udp_port = port;
|
||||
|
||||
spin_lock_irq(&vxlan_db->lock);
|
||||
err = radix_tree_insert(&vxlan_db->tree, vxlan->udp_port, vxlan);
|
||||
spin_unlock_irq(&vxlan_db->lock);
|
||||
if (err)
|
||||
goto err_free;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
kfree(vxlan);
|
||||
err_delete_port:
|
||||
mlx5e_vxlan_core_del_port_cmd(priv->mdev, port);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __mlx5e_vxlan_core_del_port(struct mlx5e_priv *priv, u16 port)
|
||||
{
|
||||
struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
|
||||
struct mlx5e_vxlan *vxlan;
|
||||
|
||||
spin_lock_irq(&vxlan_db->lock);
|
||||
vxlan = radix_tree_delete(&vxlan_db->tree, port);
|
||||
spin_unlock_irq(&vxlan_db->lock);
|
||||
|
||||
if (!vxlan)
|
||||
return;
|
||||
|
||||
mlx5e_vxlan_core_del_port_cmd(priv->mdev, vxlan->udp_port);
|
||||
|
||||
kfree(vxlan);
|
||||
}
|
||||
|
||||
void mlx5e_vxlan_del_port(struct mlx5e_priv *priv, u16 port)
|
||||
{
|
||||
if (!mlx5e_vxlan_lookup_port(priv, port))
|
||||
return;
|
||||
|
||||
__mlx5e_vxlan_core_del_port(priv, port);
|
||||
}
|
||||
|
||||
void mlx5e_vxlan_cleanup(struct mlx5e_priv *priv)
|
||||
{
|
||||
struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
|
||||
struct mlx5e_vxlan *vxlan;
|
||||
unsigned int port = 0;
|
||||
|
||||
spin_lock_irq(&vxlan_db->lock);
|
||||
while (radix_tree_gang_lookup(&vxlan_db->tree, (void **)&vxlan, port, 1)) {
|
||||
port = vxlan->udp_port;
|
||||
spin_unlock_irq(&vxlan_db->lock);
|
||||
__mlx5e_vxlan_core_del_port(priv, (u16)port);
|
||||
spin_lock_irq(&vxlan_db->lock);
|
||||
}
|
||||
spin_unlock_irq(&vxlan_db->lock);
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Mellanox Technologies, Ltd. All rights reserved.
|
||||
*
|
||||
* This software is available to you under a choice of one of two
|
||||
* licenses. You may choose to be licensed under the terms of the GNU
|
||||
* General Public License (GPL) Version 2, available from the file
|
||||
* COPYING in the main directory of this source tree, or the
|
||||
* OpenIB.org BSD license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#ifndef __MLX5_VXLAN_H__
|
||||
#define __MLX5_VXLAN_H__
|
||||
|
||||
#include <linux/mlx5/driver.h>
|
||||
#include "en.h"
|
||||
|
||||
struct mlx5e_vxlan {
|
||||
u16 udp_port;
|
||||
};
|
||||
|
||||
static inline bool mlx5e_vxlan_allowed(struct mlx5_core_dev *mdev)
|
||||
{
|
||||
return (MLX5_CAP_ETH(mdev, tunnel_stateless_vxlan) &&
|
||||
mlx5_core_is_pf(mdev));
|
||||
}
|
||||
|
||||
void mlx5e_vxlan_init(struct mlx5e_priv *priv);
|
||||
int mlx5e_vxlan_add_port(struct mlx5e_priv *priv, u16 port);
|
||||
void mlx5e_vxlan_del_port(struct mlx5e_priv *priv, u16 port);
|
||||
struct mlx5e_vxlan *mlx5e_vxlan_lookup_port(struct mlx5e_priv *priv, u16 port);
|
||||
void mlx5e_vxlan_cleanup(struct mlx5e_priv *priv);
|
||||
|
||||
#endif /* __MLX5_VXLAN_H__ */
|
Loading…
Reference in New Issue