Skip to content

Commit b3f63c3

Browse files
finlaymdavem330
authored andcommitted
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>
1 parent 1afff42 commit b3f63c3

File tree

6 files changed

+332
-3
lines changed

6 files changed

+332
-3
lines changed

drivers/net/ethernet/mellanox/mlx5/core/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
66

77
mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o \
88
en_main.o en_fs.o en_ethtool.o en_tx.o en_rx.o \
9-
en_txrx.o en_clock.o
9+
en_txrx.o en_clock.o vxlan.o
1010

1111
mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o

drivers/net/ethernet/mellanox/mlx5/core/cmd.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
2+
* Copyright (c) 2013-2016, Mellanox Technologies. All rights reserved.
33
*
44
* This software is available to you under a choice of one of two
55
* licenses. You may choose to be licensed under the terms of the GNU
@@ -566,6 +566,12 @@ const char *mlx5_command_str(int command)
566566
case MLX5_CMD_OP_QUERY_WOL_ROL:
567567
return "QUERY_WOL_ROL";
568568

569+
case MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT:
570+
return "ADD_VXLAN_UDP_DPORT";
571+
572+
case MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT:
573+
return "DELETE_VXLAN_UDP_DPORT";
574+
569575
default: return "unknown command opcode";
570576
}
571577
}

drivers/net/ethernet/mellanox/mlx5/core/en.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,11 @@ struct mlx5e_vlan_db {
501501
bool filter_disabled;
502502
};
503503

504+
struct mlx5e_vxlan_db {
505+
spinlock_t lock; /* protect vxlan table */
506+
struct radix_tree_root tree;
507+
};
508+
504509
struct mlx5e_flow_table {
505510
int num_groups;
506511
struct mlx5_flow_table *t;
@@ -535,6 +540,7 @@ struct mlx5e_priv {
535540
struct mlx5e_flow_tables fts;
536541
struct mlx5e_eth_addr_db eth_addr;
537542
struct mlx5e_vlan_db vlan;
543+
struct mlx5e_vxlan_db vxlan;
538544

539545
struct mlx5e_params params;
540546
spinlock_t async_events_spinlock; /* sync hw events */

drivers/net/ethernet/mellanox/mlx5/core/en_main.c

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, Mellanox Technologies. All rights reserved.
2+
* Copyright (c) 2015-2016, Mellanox Technologies. All rights reserved.
33
*
44
* This software is available to you under a choice of one of two
55
* licenses. You may choose to be licensed under the terms of the GNU
@@ -31,8 +31,10 @@
3131
*/
3232

3333
#include <linux/mlx5/fs.h>
34+
#include <net/vxlan.h>
3435
#include "en.h"
3536
#include "eswitch.h"
37+
#include "vxlan.h"
3638

3739
struct mlx5e_rq_param {
3840
u32 rqc[MLX5_ST_SZ_DW(rqc)];
@@ -2078,6 +2080,78 @@ static int mlx5e_get_vf_stats(struct net_device *dev,
20782080
vf_stats);
20792081
}
20802082

2083+
static void mlx5e_add_vxlan_port(struct net_device *netdev,
2084+
sa_family_t sa_family, __be16 port)
2085+
{
2086+
struct mlx5e_priv *priv = netdev_priv(netdev);
2087+
2088+
if (!mlx5e_vxlan_allowed(priv->mdev))
2089+
return;
2090+
2091+
mlx5e_vxlan_add_port(priv, be16_to_cpu(port));
2092+
}
2093+
2094+
static void mlx5e_del_vxlan_port(struct net_device *netdev,
2095+
sa_family_t sa_family, __be16 port)
2096+
{
2097+
struct mlx5e_priv *priv = netdev_priv(netdev);
2098+
2099+
if (!mlx5e_vxlan_allowed(priv->mdev))
2100+
return;
2101+
2102+
mlx5e_vxlan_del_port(priv, be16_to_cpu(port));
2103+
}
2104+
2105+
static netdev_features_t mlx5e_vxlan_features_check(struct mlx5e_priv *priv,
2106+
struct sk_buff *skb,
2107+
netdev_features_t features)
2108+
{
2109+
struct udphdr *udph;
2110+
u16 proto;
2111+
u16 port = 0;
2112+
2113+
switch (vlan_get_protocol(skb)) {
2114+
case htons(ETH_P_IP):
2115+
proto = ip_hdr(skb)->protocol;
2116+
break;
2117+
case htons(ETH_P_IPV6):
2118+
proto = ipv6_hdr(skb)->nexthdr;
2119+
break;
2120+
default:
2121+
goto out;
2122+
}
2123+
2124+
if (proto == IPPROTO_UDP) {
2125+
udph = udp_hdr(skb);
2126+
port = be16_to_cpu(udph->dest);
2127+
}
2128+
2129+
/* Verify if UDP port is being offloaded by HW */
2130+
if (port && mlx5e_vxlan_lookup_port(priv, port))
2131+
return features;
2132+
2133+
out:
2134+
/* Disable CSUM and GSO if the udp dport is not offloaded by HW */
2135+
return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
2136+
}
2137+
2138+
static netdev_features_t mlx5e_features_check(struct sk_buff *skb,
2139+
struct net_device *netdev,
2140+
netdev_features_t features)
2141+
{
2142+
struct mlx5e_priv *priv = netdev_priv(netdev);
2143+
2144+
features = vlan_features_check(skb, features);
2145+
features = vxlan_features_check(skb, features);
2146+
2147+
/* Validate if the tunneled packet is being offloaded by HW */
2148+
if (skb->encapsulation &&
2149+
(features & NETIF_F_CSUM_MASK || features & NETIF_F_GSO_MASK))
2150+
return mlx5e_vxlan_features_check(priv, skb, features);
2151+
2152+
return features;
2153+
}
2154+
20812155
static const struct net_device_ops mlx5e_netdev_ops_basic = {
20822156
.ndo_open = mlx5e_open,
20832157
.ndo_stop = mlx5e_close,
@@ -2108,6 +2182,9 @@ static const struct net_device_ops mlx5e_netdev_ops_sriov = {
21082182
.ndo_set_features = mlx5e_set_features,
21092183
.ndo_change_mtu = mlx5e_change_mtu,
21102184
.ndo_do_ioctl = mlx5e_ioctl,
2185+
.ndo_add_vxlan_port = mlx5e_add_vxlan_port,
2186+
.ndo_del_vxlan_port = mlx5e_del_vxlan_port,
2187+
.ndo_features_check = mlx5e_features_check,
21112188
.ndo_set_vf_mac = mlx5e_set_vf_mac,
21122189
.ndo_set_vf_vlan = mlx5e_set_vf_vlan,
21132190
.ndo_get_vf_config = mlx5e_get_vf_config,
@@ -2264,6 +2341,16 @@ static void mlx5e_build_netdev(struct net_device *netdev)
22642341
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
22652342
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
22662343

2344+
if (mlx5e_vxlan_allowed(mdev)) {
2345+
netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
2346+
netdev->hw_enc_features |= NETIF_F_IP_CSUM;
2347+
netdev->hw_enc_features |= NETIF_F_RXCSUM;
2348+
netdev->hw_enc_features |= NETIF_F_TSO;
2349+
netdev->hw_enc_features |= NETIF_F_TSO6;
2350+
netdev->hw_enc_features |= NETIF_F_RXHASH;
2351+
netdev->hw_enc_features |= NETIF_F_GSO_UDP_TUNNEL;
2352+
}
2353+
22672354
netdev->features = netdev->hw_features;
22682355
if (!priv->params.lro_en)
22692356
netdev->features &= ~NETIF_F_LRO;
@@ -2387,6 +2474,8 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev)
23872474

23882475
mlx5e_init_eth_addr(priv);
23892476

2477+
mlx5e_vxlan_init(priv);
2478+
23902479
#ifdef CONFIG_MLX5_CORE_EN_DCB
23912480
mlx5e_dcbnl_ieee_setets_core(priv, &priv->params.ets);
23922481
#endif
@@ -2397,6 +2486,9 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev)
23972486
goto err_destroy_flow_tables;
23982487
}
23992488

2489+
if (mlx5e_vxlan_allowed(mdev))
2490+
vxlan_get_rx_port(netdev);
2491+
24002492
mlx5e_enable_async_events(priv);
24012493
schedule_work(&priv->set_rx_mode_work);
24022494

@@ -2449,6 +2541,7 @@ static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv)
24492541
mlx5e_disable_async_events(priv);
24502542
flush_scheduled_work();
24512543
unregister_netdev(netdev);
2544+
mlx5e_vxlan_cleanup(priv);
24522545
mlx5e_destroy_flow_tables(priv);
24532546
mlx5e_destroy_tirs(priv);
24542547
mlx5e_destroy_rqt(priv, MLX5E_SINGLE_RQ_RQT);
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/*
2+
* Copyright (c) 2016, Mellanox Technologies, Ltd. All rights reserved.
3+
*
4+
* This software is available to you under a choice of one of two
5+
* licenses. You may choose to be licensed under the terms of the GNU
6+
* General Public License (GPL) Version 2, available from the file
7+
* COPYING in the main directory of this source tree, or the
8+
* OpenIB.org BSD license below:
9+
*
10+
* Redistribution and use in source and binary forms, with or
11+
* without modification, are permitted provided that the following
12+
* conditions are met:
13+
*
14+
* - Redistributions of source code must retain the above
15+
* copyright notice, this list of conditions and the following
16+
* disclaimer.
17+
*
18+
* - Redistributions in binary form must reproduce the above
19+
* copyright notice, this list of conditions and the following
20+
* disclaimer in the documentation and/or other materials
21+
* provided with the distribution.
22+
*
23+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27+
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28+
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30+
* SOFTWARE.
31+
*/
32+
33+
#include <linux/kernel.h>
34+
#include <linux/module.h>
35+
#include <linux/mlx5/driver.h>
36+
#include "mlx5_core.h"
37+
#include "vxlan.h"
38+
39+
void mlx5e_vxlan_init(struct mlx5e_priv *priv)
40+
{
41+
struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
42+
43+
spin_lock_init(&vxlan_db->lock);
44+
INIT_RADIX_TREE(&vxlan_db->tree, GFP_ATOMIC);
45+
}
46+
47+
static int mlx5e_vxlan_core_add_port_cmd(struct mlx5_core_dev *mdev, u16 port)
48+
{
49+
struct mlx5_outbox_hdr *hdr;
50+
int err;
51+
52+
u32 in[MLX5_ST_SZ_DW(add_vxlan_udp_dport_in)];
53+
u32 out[MLX5_ST_SZ_DW(add_vxlan_udp_dport_out)];
54+
55+
memset(in, 0, sizeof(in));
56+
memset(out, 0, sizeof(out));
57+
58+
MLX5_SET(add_vxlan_udp_dport_in, in, opcode,
59+
MLX5_CMD_OP_ADD_VXLAN_UDP_DPORT);
60+
MLX5_SET(add_vxlan_udp_dport_in, in, vxlan_udp_port, port);
61+
62+
err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
63+
if (err)
64+
return err;
65+
66+
hdr = (struct mlx5_outbox_hdr *)out;
67+
return hdr->status ? -ENOMEM : 0;
68+
}
69+
70+
static int mlx5e_vxlan_core_del_port_cmd(struct mlx5_core_dev *mdev, u16 port)
71+
{
72+
u32 in[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_in)];
73+
u32 out[MLX5_ST_SZ_DW(delete_vxlan_udp_dport_out)];
74+
75+
memset(&in, 0, sizeof(in));
76+
memset(&out, 0, sizeof(out));
77+
78+
MLX5_SET(delete_vxlan_udp_dport_in, in, opcode,
79+
MLX5_CMD_OP_DELETE_VXLAN_UDP_DPORT);
80+
MLX5_SET(delete_vxlan_udp_dport_in, in, vxlan_udp_port, port);
81+
82+
return mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out,
83+
sizeof(out));
84+
}
85+
86+
struct mlx5e_vxlan *mlx5e_vxlan_lookup_port(struct mlx5e_priv *priv, u16 port)
87+
{
88+
struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
89+
struct mlx5e_vxlan *vxlan;
90+
91+
spin_lock(&vxlan_db->lock);
92+
vxlan = radix_tree_lookup(&vxlan_db->tree, port);
93+
spin_unlock(&vxlan_db->lock);
94+
95+
return vxlan;
96+
}
97+
98+
int mlx5e_vxlan_add_port(struct mlx5e_priv *priv, u16 port)
99+
{
100+
struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
101+
struct mlx5e_vxlan *vxlan;
102+
int err;
103+
104+
err = mlx5e_vxlan_core_add_port_cmd(priv->mdev, port);
105+
if (err)
106+
return err;
107+
108+
vxlan = kzalloc(sizeof(*vxlan), GFP_KERNEL);
109+
if (!vxlan) {
110+
err = -ENOMEM;
111+
goto err_delete_port;
112+
}
113+
114+
vxlan->udp_port = port;
115+
116+
spin_lock_irq(&vxlan_db->lock);
117+
err = radix_tree_insert(&vxlan_db->tree, vxlan->udp_port, vxlan);
118+
spin_unlock_irq(&vxlan_db->lock);
119+
if (err)
120+
goto err_free;
121+
122+
return 0;
123+
124+
err_free:
125+
kfree(vxlan);
126+
err_delete_port:
127+
mlx5e_vxlan_core_del_port_cmd(priv->mdev, port);
128+
return err;
129+
}
130+
131+
static void __mlx5e_vxlan_core_del_port(struct mlx5e_priv *priv, u16 port)
132+
{
133+
struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
134+
struct mlx5e_vxlan *vxlan;
135+
136+
spin_lock_irq(&vxlan_db->lock);
137+
vxlan = radix_tree_delete(&vxlan_db->tree, port);
138+
spin_unlock_irq(&vxlan_db->lock);
139+
140+
if (!vxlan)
141+
return;
142+
143+
mlx5e_vxlan_core_del_port_cmd(priv->mdev, vxlan->udp_port);
144+
145+
kfree(vxlan);
146+
}
147+
148+
void mlx5e_vxlan_del_port(struct mlx5e_priv *priv, u16 port)
149+
{
150+
if (!mlx5e_vxlan_lookup_port(priv, port))
151+
return;
152+
153+
__mlx5e_vxlan_core_del_port(priv, port);
154+
}
155+
156+
void mlx5e_vxlan_cleanup(struct mlx5e_priv *priv)
157+
{
158+
struct mlx5e_vxlan_db *vxlan_db = &priv->vxlan;
159+
struct mlx5e_vxlan *vxlan;
160+
unsigned int port = 0;
161+
162+
spin_lock_irq(&vxlan_db->lock);
163+
while (radix_tree_gang_lookup(&vxlan_db->tree, (void **)&vxlan, port, 1)) {
164+
port = vxlan->udp_port;
165+
spin_unlock_irq(&vxlan_db->lock);
166+
__mlx5e_vxlan_core_del_port(priv, (u16)port);
167+
spin_lock_irq(&vxlan_db->lock);
168+
}
169+
spin_unlock_irq(&vxlan_db->lock);
170+
}

0 commit comments

Comments
 (0)