Commit | Line | Data |
---|---|---|
6e6030bd IS |
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> | |
36952911 IS |
6 | #include <linux/random.h> |
7 | #include <net/vxlan.h> | |
6e6030bd | 8 | |
36952911 | 9 | #include "reg.h" |
4ee70efa | 10 | #include "spectrum.h" |
6e6030bd IS |
11 | #include "spectrum_nve.h" |
12 | ||
720d683c | 13 | #define MLXSW_SP_NVE_VXLAN_IPV4_SUPPORTED_FLAGS (VXLAN_F_UDP_ZERO_CSUM_TX | \ |
37ff78e9 IS |
14 | VXLAN_F_LEARN | \ |
15 | VXLAN_F_LOCALBYPASS) | |
06c08f86 AC |
16 | #define MLXSW_SP_NVE_VXLAN_IPV6_SUPPORTED_FLAGS (VXLAN_F_IPV6 | \ |
17 | VXLAN_F_UDP_ZERO_CSUM6_TX | \ | |
37ff78e9 IS |
18 | VXLAN_F_UDP_ZERO_CSUM6_RX | \ |
19 | VXLAN_F_LOCALBYPASS) | |
36952911 | 20 | |
720d683c AC |
21 | static bool mlxsw_sp_nve_vxlan_ipv4_flags_check(const struct vxlan_config *cfg, |
22 | struct netlink_ext_ack *extack) | |
23 | { | |
24 | if (!(cfg->flags & VXLAN_F_UDP_ZERO_CSUM_TX)) { | |
25 | NL_SET_ERR_MSG_MOD(extack, "VxLAN: Zero UDP checksum must be allowed for TX"); | |
26 | return false; | |
27 | } | |
28 | ||
29 | if (cfg->flags & ~MLXSW_SP_NVE_VXLAN_IPV4_SUPPORTED_FLAGS) { | |
30 | NL_SET_ERR_MSG_MOD(extack, "VxLAN: Unsupported flag"); | |
31 | return false; | |
32 | } | |
33 | ||
34 | return true; | |
35 | } | |
36 | ||
06c08f86 AC |
37 | static bool mlxsw_sp_nve_vxlan_ipv6_flags_check(const struct vxlan_config *cfg, |
38 | struct netlink_ext_ack *extack) | |
39 | { | |
40 | if (!(cfg->flags & VXLAN_F_UDP_ZERO_CSUM6_TX)) { | |
41 | NL_SET_ERR_MSG_MOD(extack, "VxLAN: Zero UDP checksum must be allowed for TX"); | |
42 | return false; | |
43 | } | |
44 | ||
45 | if (!(cfg->flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) { | |
46 | NL_SET_ERR_MSG_MOD(extack, "VxLAN: Zero UDP checksum must be allowed for RX"); | |
47 | return false; | |
48 | } | |
49 | ||
50 | if (cfg->flags & ~MLXSW_SP_NVE_VXLAN_IPV6_SUPPORTED_FLAGS) { | |
51 | NL_SET_ERR_MSG_MOD(extack, "VxLAN: Unsupported flag"); | |
52 | return false; | |
53 | } | |
54 | ||
55 | return true; | |
56 | } | |
57 | ||
02d21b59 | 58 | static bool mlxsw_sp_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve, |
efbcb673 | 59 | const struct mlxsw_sp_nve_params *params, |
02d21b59 | 60 | struct netlink_ext_ack *extack) |
6e6030bd | 61 | { |
efbcb673 | 62 | struct vxlan_dev *vxlan = netdev_priv(params->dev); |
36952911 IS |
63 | struct vxlan_config *cfg = &vxlan->cfg; |
64 | ||
36952911 IS |
65 | if (vxlan_addr_multicast(&cfg->remote_ip)) { |
66 | NL_SET_ERR_MSG_MOD(extack, "VxLAN: Multicast destination IP is not supported"); | |
67 | return false; | |
68 | } | |
69 | ||
70 | if (vxlan_addr_any(&cfg->saddr)) { | |
71 | NL_SET_ERR_MSG_MOD(extack, "VxLAN: Source address must be specified"); | |
72 | return false; | |
73 | } | |
74 | ||
75 | if (cfg->remote_ifindex) { | |
76 | NL_SET_ERR_MSG_MOD(extack, "VxLAN: Local interface is not supported"); | |
77 | return false; | |
78 | } | |
79 | ||
80 | if (cfg->port_min || cfg->port_max) { | |
81 | NL_SET_ERR_MSG_MOD(extack, "VxLAN: Only default UDP source port range is supported"); | |
82 | return false; | |
83 | } | |
84 | ||
85 | if (cfg->tos != 1) { | |
86 | NL_SET_ERR_MSG_MOD(extack, "VxLAN: TOS must be configured to inherit"); | |
87 | return false; | |
88 | } | |
89 | ||
90 | if (cfg->flags & VXLAN_F_TTL_INHERIT) { | |
91 | NL_SET_ERR_MSG_MOD(extack, "VxLAN: TTL must not be configured to inherit"); | |
92 | return false; | |
93 | } | |
94 | ||
720d683c AC |
95 | switch (cfg->saddr.sa.sa_family) { |
96 | case AF_INET: | |
97 | if (!mlxsw_sp_nve_vxlan_ipv4_flags_check(cfg, extack)) | |
98 | return false; | |
99 | break; | |
06c08f86 AC |
100 | case AF_INET6: |
101 | if (!mlxsw_sp_nve_vxlan_ipv6_flags_check(cfg, extack)) | |
102 | return false; | |
103 | break; | |
36952911 IS |
104 | } |
105 | ||
106 | if (cfg->ttl == 0) { | |
107 | NL_SET_ERR_MSG_MOD(extack, "VxLAN: TTL must not be configured to 0"); | |
108 | return false; | |
109 | } | |
110 | ||
111 | if (cfg->label != 0) { | |
112 | NL_SET_ERR_MSG_MOD(extack, "VxLAN: Flow label must be configured to 0"); | |
113 | return false; | |
114 | } | |
115 | ||
116 | return true; | |
6e6030bd IS |
117 | } |
118 | ||
efbcb673 AC |
119 | static bool mlxsw_sp1_nve_vxlan_can_offload(const struct mlxsw_sp_nve *nve, |
120 | const struct mlxsw_sp_nve_params *params, | |
121 | struct netlink_ext_ack *extack) | |
122 | { | |
123 | if (params->ethertype == ETH_P_8021AD) { | |
124 | NL_SET_ERR_MSG_MOD(extack, "VxLAN: 802.1ad bridge is not supported with VxLAN"); | |
125 | return false; | |
126 | } | |
127 | ||
128 | return mlxsw_sp_nve_vxlan_can_offload(nve, params, extack); | |
129 | } | |
130 | ||
06c08f86 AC |
131 | static void |
132 | mlxsw_sp_nve_vxlan_ul_proto_sip_config(const struct vxlan_config *cfg, | |
133 | struct mlxsw_sp_nve_config *config) | |
134 | { | |
135 | switch (cfg->saddr.sa.sa_family) { | |
136 | case AF_INET: | |
137 | config->ul_proto = MLXSW_SP_L3_PROTO_IPV4; | |
138 | config->ul_sip.addr4 = cfg->saddr.sin.sin_addr.s_addr; | |
139 | break; | |
140 | case AF_INET6: | |
141 | config->ul_proto = MLXSW_SP_L3_PROTO_IPV6; | |
142 | config->ul_sip.addr6 = cfg->saddr.sin6.sin6_addr; | |
143 | break; | |
144 | } | |
145 | } | |
146 | ||
6e6030bd | 147 | static void mlxsw_sp_nve_vxlan_config(const struct mlxsw_sp_nve *nve, |
49d18964 | 148 | const struct mlxsw_sp_nve_params *params, |
6e6030bd IS |
149 | struct mlxsw_sp_nve_config *config) |
150 | { | |
49d18964 | 151 | struct vxlan_dev *vxlan = netdev_priv(params->dev); |
36952911 IS |
152 | struct vxlan_config *cfg = &vxlan->cfg; |
153 | ||
154 | config->type = MLXSW_SP_NVE_TYPE_VXLAN; | |
155 | config->ttl = cfg->ttl; | |
156 | config->flowlabel = cfg->label; | |
157 | config->learning_en = cfg->flags & VXLAN_F_LEARN ? 1 : 0; | |
158 | config->ul_tb_id = RT_TABLE_MAIN; | |
06c08f86 | 159 | mlxsw_sp_nve_vxlan_ul_proto_sip_config(cfg, config); |
36952911 IS |
160 | config->udp_dport = cfg->dst_port; |
161 | } | |
162 | ||
3179a56f IS |
163 | static void |
164 | mlxsw_sp_nve_vxlan_config_prepare(char *tngcr_pl, | |
165 | const struct mlxsw_sp_nve_config *config) | |
166 | { | |
06c08f86 | 167 | struct in6_addr addr6; |
3179a56f IS |
168 | u8 udp_sport; |
169 | ||
170 | mlxsw_reg_tngcr_pack(tngcr_pl, MLXSW_REG_TNGCR_TYPE_VXLAN, true, | |
171 | config->ttl); | |
172 | /* VxLAN driver's default UDP source port range is 32768 (0x8000) | |
173 | * to 60999 (0xee47). Set the upper 8 bits of the UDP source port | |
174 | * to a random number between 0x80 and 0xee | |
175 | */ | |
176 | get_random_bytes(&udp_sport, sizeof(udp_sport)); | |
177 | udp_sport = (udp_sport % (0xee - 0x80 + 1)) + 0x80; | |
178 | mlxsw_reg_tngcr_nve_udp_sport_prefix_set(tngcr_pl, udp_sport); | |
06c08f86 AC |
179 | |
180 | switch (config->ul_proto) { | |
181 | case MLXSW_SP_L3_PROTO_IPV4: | |
182 | mlxsw_reg_tngcr_usipv4_set(tngcr_pl, | |
183 | be32_to_cpu(config->ul_sip.addr4)); | |
184 | break; | |
185 | case MLXSW_SP_L3_PROTO_IPV6: | |
186 | addr6 = config->ul_sip.addr6; | |
187 | mlxsw_reg_tngcr_usipv6_memcpy_to(tngcr_pl, | |
188 | (const char *)&addr6); | |
189 | break; | |
190 | } | |
3179a56f IS |
191 | } |
192 | ||
36952911 IS |
193 | static int |
194 | mlxsw_sp1_nve_vxlan_config_set(struct mlxsw_sp *mlxsw_sp, | |
195 | const struct mlxsw_sp_nve_config *config) | |
196 | { | |
197 | char tngcr_pl[MLXSW_REG_TNGCR_LEN]; | |
198 | u16 ul_vr_id; | |
36952911 IS |
199 | int err; |
200 | ||
201 | err = mlxsw_sp_router_tb_id_vr_id(mlxsw_sp, config->ul_tb_id, | |
202 | &ul_vr_id); | |
203 | if (err) | |
204 | return err; | |
205 | ||
3179a56f | 206 | mlxsw_sp_nve_vxlan_config_prepare(tngcr_pl, config); |
36952911 IS |
207 | mlxsw_reg_tngcr_learn_enable_set(tngcr_pl, config->learning_en); |
208 | mlxsw_reg_tngcr_underlay_virtual_router_set(tngcr_pl, ul_vr_id); | |
36952911 IS |
209 | |
210 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tngcr), tngcr_pl); | |
211 | } | |
212 | ||
213 | static void mlxsw_sp1_nve_vxlan_config_clear(struct mlxsw_sp *mlxsw_sp) | |
214 | { | |
215 | char tngcr_pl[MLXSW_REG_TNGCR_LEN]; | |
216 | ||
217 | mlxsw_reg_tngcr_pack(tngcr_pl, MLXSW_REG_TNGCR_TYPE_VXLAN, false, 0); | |
218 | ||
219 | mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tngcr), tngcr_pl); | |
220 | } | |
221 | ||
222 | static int mlxsw_sp1_nve_vxlan_rtdp_set(struct mlxsw_sp *mlxsw_sp, | |
223 | unsigned int tunnel_index) | |
224 | { | |
225 | char rtdp_pl[MLXSW_REG_RTDP_LEN]; | |
226 | ||
227 | mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_NVE, tunnel_index); | |
228 | ||
229 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), rtdp_pl); | |
6e6030bd IS |
230 | } |
231 | ||
232 | static int mlxsw_sp1_nve_vxlan_init(struct mlxsw_sp_nve *nve, | |
233 | const struct mlxsw_sp_nve_config *config) | |
234 | { | |
36952911 IS |
235 | struct mlxsw_sp *mlxsw_sp = nve->mlxsw_sp; |
236 | int err; | |
237 | ||
0071e7cd | 238 | err = mlxsw_sp_parsing_vxlan_udp_dport_set(mlxsw_sp, config->udp_dport); |
36952911 IS |
239 | if (err) |
240 | return err; | |
241 | ||
0071e7cd AC |
242 | err = mlxsw_sp_parsing_depth_inc(mlxsw_sp); |
243 | if (err) | |
244 | goto err_parsing_depth_inc; | |
245 | ||
36952911 IS |
246 | err = mlxsw_sp1_nve_vxlan_config_set(mlxsw_sp, config); |
247 | if (err) | |
248 | goto err_config_set; | |
249 | ||
250 | err = mlxsw_sp1_nve_vxlan_rtdp_set(mlxsw_sp, nve->tunnel_index); | |
251 | if (err) | |
252 | goto err_rtdp_set; | |
253 | ||
254 | err = mlxsw_sp_router_nve_promote_decap(mlxsw_sp, config->ul_tb_id, | |
255 | config->ul_proto, | |
256 | &config->ul_sip, | |
257 | nve->tunnel_index); | |
258 | if (err) | |
259 | goto err_promote_decap; | |
260 | ||
261 | return 0; | |
262 | ||
263 | err_promote_decap: | |
264 | err_rtdp_set: | |
265 | mlxsw_sp1_nve_vxlan_config_clear(mlxsw_sp); | |
266 | err_config_set: | |
0071e7cd AC |
267 | mlxsw_sp_parsing_depth_dec(mlxsw_sp); |
268 | err_parsing_depth_inc: | |
269 | mlxsw_sp_parsing_vxlan_udp_dport_set(mlxsw_sp, 0); | |
36952911 | 270 | return err; |
6e6030bd IS |
271 | } |
272 | ||
273 | static void mlxsw_sp1_nve_vxlan_fini(struct mlxsw_sp_nve *nve) | |
274 | { | |
36952911 IS |
275 | struct mlxsw_sp_nve_config *config = &nve->config; |
276 | struct mlxsw_sp *mlxsw_sp = nve->mlxsw_sp; | |
277 | ||
278 | mlxsw_sp_router_nve_demote_decap(mlxsw_sp, config->ul_tb_id, | |
279 | config->ul_proto, &config->ul_sip); | |
280 | mlxsw_sp1_nve_vxlan_config_clear(mlxsw_sp); | |
0071e7cd AC |
281 | mlxsw_sp_parsing_depth_dec(mlxsw_sp); |
282 | mlxsw_sp_parsing_vxlan_udp_dport_set(mlxsw_sp, 0); | |
6e6030bd IS |
283 | } |
284 | ||
a6ef5a48 | 285 | static int |
d907f58f PM |
286 | mlxsw_sp_nve_vxlan_fdb_replay(const struct net_device *nve_dev, __be32 vni, |
287 | struct netlink_ext_ack *extack) | |
a6ef5a48 PM |
288 | { |
289 | if (WARN_ON(!netif_is_vxlan(nve_dev))) | |
290 | return -EINVAL; | |
4c59b7d1 PM |
291 | return vxlan_fdb_replay(nve_dev, vni, &mlxsw_sp_switchdev_notifier, |
292 | extack); | |
a6ef5a48 PM |
293 | } |
294 | ||
b73ef0e0 PM |
295 | static void |
296 | mlxsw_sp_nve_vxlan_clear_offload(const struct net_device *nve_dev, __be32 vni) | |
297 | { | |
298 | if (WARN_ON(!netif_is_vxlan(nve_dev))) | |
299 | return; | |
300 | vxlan_fdb_clear_offload(nve_dev, vni); | |
301 | } | |
302 | ||
6e6030bd IS |
303 | const struct mlxsw_sp_nve_ops mlxsw_sp1_nve_vxlan_ops = { |
304 | .type = MLXSW_SP_NVE_TYPE_VXLAN, | |
efbcb673 | 305 | .can_offload = mlxsw_sp1_nve_vxlan_can_offload, |
6e6030bd IS |
306 | .nve_config = mlxsw_sp_nve_vxlan_config, |
307 | .init = mlxsw_sp1_nve_vxlan_init, | |
308 | .fini = mlxsw_sp1_nve_vxlan_fini, | |
a6ef5a48 | 309 | .fdb_replay = mlxsw_sp_nve_vxlan_fdb_replay, |
b73ef0e0 | 310 | .fdb_clear_offload = mlxsw_sp_nve_vxlan_clear_offload, |
6e6030bd IS |
311 | }; |
312 | ||
1e0b72a2 DC |
313 | static int mlxsw_sp2_nve_vxlan_learning_set(struct mlxsw_sp *mlxsw_sp, |
314 | bool learning_en) | |
4ee70efa IS |
315 | { |
316 | char tnpc_pl[MLXSW_REG_TNPC_LEN]; | |
317 | ||
02c3b5c5 | 318 | mlxsw_reg_tnpc_pack(tnpc_pl, MLXSW_REG_TUNNEL_PORT_NVE, |
4ee70efa IS |
319 | learning_en); |
320 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tnpc), tnpc_pl); | |
321 | } | |
322 | ||
0b5ec8f2 | 323 | static int |
bf677bd2 | 324 | mlxsw_sp2_nve_decap_ethertype_set(struct mlxsw_sp *mlxsw_sp) |
0b5ec8f2 AC |
325 | { |
326 | char spvid_pl[MLXSW_REG_SPVID_LEN] = {}; | |
0b5ec8f2 AC |
327 | |
328 | mlxsw_reg_spvid_tport_set(spvid_pl, true); | |
329 | mlxsw_reg_spvid_local_port_set(spvid_pl, | |
330 | MLXSW_REG_TUNNEL_PORT_NVE); | |
bf677bd2 | 331 | mlxsw_reg_spvid_egr_et_set_set(spvid_pl, true); |
0b5ec8f2 AC |
332 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvid), spvid_pl); |
333 | } | |
334 | ||
4ee70efa IS |
335 | static int |
336 | mlxsw_sp2_nve_vxlan_config_set(struct mlxsw_sp *mlxsw_sp, | |
337 | const struct mlxsw_sp_nve_config *config) | |
338 | { | |
339 | char tngcr_pl[MLXSW_REG_TNGCR_LEN]; | |
0b5ec8f2 | 340 | char spvtr_pl[MLXSW_REG_SPVTR_LEN]; |
4ee70efa IS |
341 | u16 ul_rif_index; |
342 | int err; | |
343 | ||
344 | err = mlxsw_sp_router_ul_rif_get(mlxsw_sp, config->ul_tb_id, | |
345 | &ul_rif_index); | |
346 | if (err) | |
347 | return err; | |
348 | mlxsw_sp->nve->ul_rif_index = ul_rif_index; | |
349 | ||
350 | err = mlxsw_sp2_nve_vxlan_learning_set(mlxsw_sp, config->learning_en); | |
351 | if (err) | |
352 | goto err_vxlan_learning_set; | |
353 | ||
354 | mlxsw_sp_nve_vxlan_config_prepare(tngcr_pl, config); | |
355 | mlxsw_reg_tngcr_underlay_rif_set(tngcr_pl, ul_rif_index); | |
356 | ||
357 | err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tngcr), tngcr_pl); | |
358 | if (err) | |
359 | goto err_tngcr_write; | |
360 | ||
0b5ec8f2 AC |
361 | mlxsw_reg_spvtr_pack(spvtr_pl, true, MLXSW_REG_TUNNEL_PORT_NVE, |
362 | MLXSW_REG_SPVTR_IPVID_MODE_ALWAYS_PUSH_VLAN); | |
363 | err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvtr), spvtr_pl); | |
364 | if (err) | |
365 | goto err_spvtr_write; | |
366 | ||
bf677bd2 | 367 | err = mlxsw_sp2_nve_decap_ethertype_set(mlxsw_sp); |
0b5ec8f2 AC |
368 | if (err) |
369 | goto err_decap_ethertype_set; | |
370 | ||
4ee70efa IS |
371 | return 0; |
372 | ||
0b5ec8f2 AC |
373 | err_decap_ethertype_set: |
374 | mlxsw_reg_spvtr_pack(spvtr_pl, true, MLXSW_REG_TUNNEL_PORT_NVE, | |
375 | MLXSW_REG_SPVTR_IPVID_MODE_IEEE_COMPLIANT_PVID); | |
376 | mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvtr), spvtr_pl); | |
377 | err_spvtr_write: | |
378 | mlxsw_reg_tngcr_pack(tngcr_pl, MLXSW_REG_TNGCR_TYPE_VXLAN, false, 0); | |
379 | mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tngcr), tngcr_pl); | |
4ee70efa IS |
380 | err_tngcr_write: |
381 | mlxsw_sp2_nve_vxlan_learning_set(mlxsw_sp, false); | |
382 | err_vxlan_learning_set: | |
383 | mlxsw_sp_router_ul_rif_put(mlxsw_sp, ul_rif_index); | |
384 | return err; | |
385 | } | |
386 | ||
387 | static void mlxsw_sp2_nve_vxlan_config_clear(struct mlxsw_sp *mlxsw_sp) | |
388 | { | |
0b5ec8f2 | 389 | char spvtr_pl[MLXSW_REG_SPVTR_LEN]; |
4ee70efa IS |
390 | char tngcr_pl[MLXSW_REG_TNGCR_LEN]; |
391 | ||
0b5ec8f2 AC |
392 | mlxsw_reg_spvtr_pack(spvtr_pl, true, MLXSW_REG_TUNNEL_PORT_NVE, |
393 | MLXSW_REG_SPVTR_IPVID_MODE_IEEE_COMPLIANT_PVID); | |
394 | mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(spvtr), spvtr_pl); | |
4ee70efa IS |
395 | mlxsw_reg_tngcr_pack(tngcr_pl, MLXSW_REG_TNGCR_TYPE_VXLAN, false, 0); |
396 | mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tngcr), tngcr_pl); | |
397 | mlxsw_sp2_nve_vxlan_learning_set(mlxsw_sp, false); | |
398 | mlxsw_sp_router_ul_rif_put(mlxsw_sp, mlxsw_sp->nve->ul_rif_index); | |
399 | } | |
400 | ||
401 | static int mlxsw_sp2_nve_vxlan_rtdp_set(struct mlxsw_sp *mlxsw_sp, | |
402 | unsigned int tunnel_index, | |
403 | u16 ul_rif_index) | |
404 | { | |
405 | char rtdp_pl[MLXSW_REG_RTDP_LEN]; | |
406 | ||
407 | mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_NVE, tunnel_index); | |
408 | mlxsw_reg_rtdp_egress_router_interface_set(rtdp_pl, ul_rif_index); | |
409 | ||
410 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), rtdp_pl); | |
411 | } | |
412 | ||
6e6030bd IS |
413 | static int mlxsw_sp2_nve_vxlan_init(struct mlxsw_sp_nve *nve, |
414 | const struct mlxsw_sp_nve_config *config) | |
415 | { | |
4ee70efa IS |
416 | struct mlxsw_sp *mlxsw_sp = nve->mlxsw_sp; |
417 | int err; | |
418 | ||
0071e7cd | 419 | err = mlxsw_sp_parsing_vxlan_udp_dport_set(mlxsw_sp, config->udp_dport); |
4ee70efa IS |
420 | if (err) |
421 | return err; | |
422 | ||
0071e7cd AC |
423 | err = mlxsw_sp_parsing_depth_inc(mlxsw_sp); |
424 | if (err) | |
425 | goto err_parsing_depth_inc; | |
426 | ||
4ee70efa IS |
427 | err = mlxsw_sp2_nve_vxlan_config_set(mlxsw_sp, config); |
428 | if (err) | |
429 | goto err_config_set; | |
430 | ||
431 | err = mlxsw_sp2_nve_vxlan_rtdp_set(mlxsw_sp, nve->tunnel_index, | |
432 | nve->ul_rif_index); | |
433 | if (err) | |
434 | goto err_rtdp_set; | |
435 | ||
436 | err = mlxsw_sp_router_nve_promote_decap(mlxsw_sp, config->ul_tb_id, | |
437 | config->ul_proto, | |
438 | &config->ul_sip, | |
439 | nve->tunnel_index); | |
440 | if (err) | |
441 | goto err_promote_decap; | |
442 | ||
443 | return 0; | |
444 | ||
445 | err_promote_decap: | |
446 | err_rtdp_set: | |
447 | mlxsw_sp2_nve_vxlan_config_clear(mlxsw_sp); | |
448 | err_config_set: | |
0071e7cd AC |
449 | mlxsw_sp_parsing_depth_dec(mlxsw_sp); |
450 | err_parsing_depth_inc: | |
451 | mlxsw_sp_parsing_vxlan_udp_dport_set(mlxsw_sp, 0); | |
4ee70efa | 452 | return err; |
6e6030bd IS |
453 | } |
454 | ||
455 | static void mlxsw_sp2_nve_vxlan_fini(struct mlxsw_sp_nve *nve) | |
456 | { | |
4ee70efa IS |
457 | struct mlxsw_sp_nve_config *config = &nve->config; |
458 | struct mlxsw_sp *mlxsw_sp = nve->mlxsw_sp; | |
459 | ||
460 | mlxsw_sp_router_nve_demote_decap(mlxsw_sp, config->ul_tb_id, | |
461 | config->ul_proto, &config->ul_sip); | |
462 | mlxsw_sp2_nve_vxlan_config_clear(mlxsw_sp); | |
0071e7cd AC |
463 | mlxsw_sp_parsing_depth_dec(mlxsw_sp); |
464 | mlxsw_sp_parsing_vxlan_udp_dport_set(mlxsw_sp, 0); | |
6e6030bd IS |
465 | } |
466 | ||
467 | const struct mlxsw_sp_nve_ops mlxsw_sp2_nve_vxlan_ops = { | |
468 | .type = MLXSW_SP_NVE_TYPE_VXLAN, | |
02d21b59 | 469 | .can_offload = mlxsw_sp_nve_vxlan_can_offload, |
6e6030bd IS |
470 | .nve_config = mlxsw_sp_nve_vxlan_config, |
471 | .init = mlxsw_sp2_nve_vxlan_init, | |
472 | .fini = mlxsw_sp2_nve_vxlan_fini, | |
a6ef5a48 | 473 | .fdb_replay = mlxsw_sp_nve_vxlan_fdb_replay, |
b73ef0e0 | 474 | .fdb_clear_offload = mlxsw_sp_nve_vxlan_clear_offload, |
6e6030bd | 475 | }; |