aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c')
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c249
1 files changed, 249 insertions, 0 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c
new file mode 100644
index 000000000000..d21c7be5b1c9
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_nve_vxlan.c
@@ -0,0 +1,249 @@
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
3
4#include <linux/netdevice.h>
5#include <linux/netlink.h>
6#include <linux/random.h>
7#include <net/vxlan.h>
8
9#include "reg.h"
10#include "spectrum_nve.h"
11
12/* Eth (18B) | IPv6 (40B) | UDP (8B) | VxLAN (8B) | Eth (14B) | IPv6 (40B)
13 *
14 * In the worst case - where we have a VLAN tag on the outer Ethernet
15 * header and IPv6 in overlay and underlay - we need to parse 128 bytes
16 */
17#define MLXSW_SP_NVE_VXLAN_PARSING_DEPTH 128
18#define MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH 96
19
20#define MLXSW_SP_NVE_VXLAN_SUPPORTED_FLAGS VXLAN_F_UDP_ZERO_CSUM_TX
21
22static bool mlxsw_sp1_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve,
23 const struct net_device *dev,
24 struct netlink_ext_ack *extack)
25{
26 struct vxlan_dev *vxlan = netdev_priv(dev);
27 struct vxlan_config *cfg = &vxlan->cfg;
28
29 if (cfg->saddr.sa.sa_family != AF_INET) {
30 NL_SET_ERR_MSG_MOD(extack, "VxLAN: Only IPv4 underlay is supported");
31 return false;
32 }
33
34 if (vxlan_addr_multicast(&cfg->remote_ip)) {
35 NL_SET_ERR_MSG_MOD(extack, "VxLAN: Multicast destination IP is not supported");
36 return false;
37 }
38
39 if (vxlan_addr_any(&cfg->saddr)) {
40 NL_SET_ERR_MSG_MOD(extack, "VxLAN: Source address must be specified");
41 return false;
42 }
43
44 if (cfg->remote_ifindex) {
45 NL_SET_ERR_MSG_MOD(extack, "VxLAN: Local interface is not supported");
46 return false;
47 }
48
49 if (cfg->port_min || cfg->port_max) {
50 NL_SET_ERR_MSG_MOD(extack, "VxLAN: Only default UDP source port range is supported");
51 return false;
52 }
53
54 if (cfg->tos != 1) {
55 NL_SET_ERR_MSG_MOD(extack, "VxLAN: TOS must be configured to inherit");
56 return false;
57 }
58
59 if (cfg->flags & VXLAN_F_TTL_INHERIT) {
60 NL_SET_ERR_MSG_MOD(extack, "VxLAN: TTL must not be configured to inherit");
61 return false;
62 }
63
64 if (cfg->flags & VXLAN_F_LEARN) {
65 NL_SET_ERR_MSG_MOD(extack, "VxLAN: Learning is not supported");
66 return false;
67 }
68
69 if (!(cfg->flags & VXLAN_F_UDP_ZERO_CSUM_TX)) {
70 NL_SET_ERR_MSG_MOD(extack, "VxLAN: UDP checksum is not supported");
71 return false;
72 }
73
74 if (cfg->flags & ~MLXSW_SP_NVE_VXLAN_SUPPORTED_FLAGS) {
75 NL_SET_ERR_MSG_MOD(extack, "VxLAN: Unsupported flag");
76 return false;
77 }
78
79 if (cfg->ttl == 0) {
80 NL_SET_ERR_MSG_MOD(extack, "VxLAN: TTL must not be configured to 0");
81 return false;
82 }
83
84 if (cfg->label != 0) {
85 NL_SET_ERR_MSG_MOD(extack, "VxLAN: Flow label must be configured to 0");
86 return false;
87 }
88
89 return true;
90}
91
92static void mlxsw_sp_nve_vxlan_config(const struct mlxsw_sp_nve *nve,
93 const struct net_device *dev,
94 struct mlxsw_sp_nve_config *config)
95{
96 struct vxlan_dev *vxlan = netdev_priv(dev);
97 struct vxlan_config *cfg = &vxlan->cfg;
98
99 config->type = MLXSW_SP_NVE_TYPE_VXLAN;
100 config->ttl = cfg->ttl;
101 config->flowlabel = cfg->label;
102 config->learning_en = cfg->flags & VXLAN_F_LEARN ? 1 : 0;
103 config->ul_tb_id = RT_TABLE_MAIN;
104 config->ul_proto = MLXSW_SP_L3_PROTO_IPV4;
105 config->ul_sip.addr4 = cfg->saddr.sin.sin_addr.s_addr;
106 config->udp_dport = cfg->dst_port;
107}
108
109static int mlxsw_sp_nve_parsing_set(struct mlxsw_sp *mlxsw_sp,
110 unsigned int parsing_depth,
111 __be16 udp_dport)
112{
113 char mprs_pl[MLXSW_REG_MPRS_LEN];
114
115 mlxsw_reg_mprs_pack(mprs_pl, parsing_depth, be16_to_cpu(udp_dport));
116 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mprs), mprs_pl);
117}
118
119static int
120mlxsw_sp1_nve_vxlan_config_set(struct mlxsw_sp *mlxsw_sp,
121 const struct mlxsw_sp_nve_config *config)
122{
123 char tngcr_pl[MLXSW_REG_TNGCR_LEN];
124 u16 ul_vr_id;
125 u8 udp_sport;
126 int err;
127
128 err = mlxsw_sp_router_tb_id_vr_id(mlxsw_sp, config->ul_tb_id,
129 &ul_vr_id);
130 if (err)
131 return err;
132
133 mlxsw_reg_tngcr_pack(tngcr_pl, MLXSW_REG_TNGCR_TYPE_VXLAN, true,
134 config->ttl);
135 /* VxLAN driver's default UDP source port range is 32768 (0x8000)
136 * to 60999 (0xee47). Set the upper 8 bits of the UDP source port
137 * to a random number between 0x80 and 0xee
138 */
139 get_random_bytes(&udp_sport, sizeof(udp_sport));
140 udp_sport = (udp_sport % (0xee - 0x80 + 1)) + 0x80;
141 mlxsw_reg_tngcr_nve_udp_sport_prefix_set(tngcr_pl, udp_sport);
142 mlxsw_reg_tngcr_learn_enable_set(tngcr_pl, config->learning_en);
143 mlxsw_reg_tngcr_underlay_virtual_router_set(tngcr_pl, ul_vr_id);
144 mlxsw_reg_tngcr_usipv4_set(tngcr_pl, be32_to_cpu(config->ul_sip.addr4));
145
146 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tngcr), tngcr_pl);
147}
148
149static void mlxsw_sp1_nve_vxlan_config_clear(struct mlxsw_sp *mlxsw_sp)
150{
151 char tngcr_pl[MLXSW_REG_TNGCR_LEN];
152
153 mlxsw_reg_tngcr_pack(tngcr_pl, MLXSW_REG_TNGCR_TYPE_VXLAN, false, 0);
154
155 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tngcr), tngcr_pl);
156}
157
158static int mlxsw_sp1_nve_vxlan_rtdp_set(struct mlxsw_sp *mlxsw_sp,
159 unsigned int tunnel_index)
160{
161 char rtdp_pl[MLXSW_REG_RTDP_LEN];
162
163 mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_NVE, tunnel_index);
164
165 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), rtdp_pl);
166}
167
168static int mlxsw_sp1_nve_vxlan_init(struct mlxsw_sp_nve *nve,
169 const struct mlxsw_sp_nve_config *config)
170{
171 struct mlxsw_sp *mlxsw_sp = nve->mlxsw_sp;
172 int err;
173
174 err = mlxsw_sp_nve_parsing_set(mlxsw_sp,
175 MLXSW_SP_NVE_VXLAN_PARSING_DEPTH,
176 config->udp_dport);
177 if (err)
178 return err;
179
180 err = mlxsw_sp1_nve_vxlan_config_set(mlxsw_sp, config);
181 if (err)
182 goto err_config_set;
183
184 err = mlxsw_sp1_nve_vxlan_rtdp_set(mlxsw_sp, nve->tunnel_index);
185 if (err)
186 goto err_rtdp_set;
187
188 err = mlxsw_sp_router_nve_promote_decap(mlxsw_sp, config->ul_tb_id,
189 config->ul_proto,
190 &config->ul_sip,
191 nve->tunnel_index);
192 if (err)
193 goto err_promote_decap;
194
195 return 0;
196
197err_promote_decap:
198err_rtdp_set:
199 mlxsw_sp1_nve_vxlan_config_clear(mlxsw_sp);
200err_config_set:
201 mlxsw_sp_nve_parsing_set(mlxsw_sp, MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH,
202 config->udp_dport);
203 return err;
204}
205
206static void mlxsw_sp1_nve_vxlan_fini(struct mlxsw_sp_nve *nve)
207{
208 struct mlxsw_sp_nve_config *config = &nve->config;
209 struct mlxsw_sp *mlxsw_sp = nve->mlxsw_sp;
210
211 mlxsw_sp_router_nve_demote_decap(mlxsw_sp, config->ul_tb_id,
212 config->ul_proto, &config->ul_sip);
213 mlxsw_sp1_nve_vxlan_config_clear(mlxsw_sp);
214 mlxsw_sp_nve_parsing_set(mlxsw_sp, MLXSW_SP_NVE_DEFAULT_PARSING_DEPTH,
215 config->udp_dport);
216}
217
218const struct mlxsw_sp_nve_ops mlxsw_sp1_nve_vxlan_ops = {
219 .type = MLXSW_SP_NVE_TYPE_VXLAN,
220 .can_offload = mlxsw_sp1_nve_vxlan_can_offload,
221 .nve_config = mlxsw_sp_nve_vxlan_config,
222 .init = mlxsw_sp1_nve_vxlan_init,
223 .fini = mlxsw_sp1_nve_vxlan_fini,
224};
225
226static bool mlxsw_sp2_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve,
227 const struct net_device *dev,
228 struct netlink_ext_ack *extack)
229{
230 return false;
231}
232
233static int mlxsw_sp2_nve_vxlan_init(struct mlxsw_sp_nve *nve,
234 const struct mlxsw_sp_nve_config *config)
235{
236 return -EOPNOTSUPP;
237}
238
239static void mlxsw_sp2_nve_vxlan_fini(struct mlxsw_sp_nve *nve)
240{
241}
242
243const struct mlxsw_sp_nve_ops mlxsw_sp2_nve_vxlan_ops = {
244 .type = MLXSW_SP_NVE_TYPE_VXLAN,
245 .can_offload = mlxsw_sp2_nve_vxlan_can_offload,
246 .nve_config = mlxsw_sp_nve_vxlan_config,
247 .init = mlxsw_sp2_nve_vxlan_init,
248 .fini = mlxsw_sp2_nve_vxlan_fini,
249};