1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ |
3 | |
4 | #include <net/ip_tunnels.h> |
5 | #include <net/ip6_tunnel.h> |
6 | #include <net/inet_ecn.h> |
7 | |
8 | #include "spectrum_ipip.h" |
9 | #include "reg.h" |
10 | |
11 | struct ip_tunnel_parm |
12 | mlxsw_sp_ipip_netdev_parms4(const struct net_device *ol_dev) |
13 | { |
14 | struct ip_tunnel *tun = netdev_priv(dev: ol_dev); |
15 | |
16 | return tun->parms; |
17 | } |
18 | |
19 | struct __ip6_tnl_parm |
20 | mlxsw_sp_ipip_netdev_parms6(const struct net_device *ol_dev) |
21 | { |
22 | struct ip6_tnl *tun = netdev_priv(dev: ol_dev); |
23 | |
24 | return tun->parms; |
25 | } |
26 | |
27 | static bool mlxsw_sp_ipip_parms4_has_ikey(const struct ip_tunnel_parm *parms) |
28 | { |
29 | return !!(parms->i_flags & TUNNEL_KEY); |
30 | } |
31 | |
32 | static bool mlxsw_sp_ipip_parms6_has_ikey(const struct __ip6_tnl_parm *parms) |
33 | { |
34 | return !!(parms->i_flags & TUNNEL_KEY); |
35 | } |
36 | |
37 | static bool mlxsw_sp_ipip_parms4_has_okey(const struct ip_tunnel_parm *parms) |
38 | { |
39 | return !!(parms->o_flags & TUNNEL_KEY); |
40 | } |
41 | |
42 | static bool mlxsw_sp_ipip_parms6_has_okey(const struct __ip6_tnl_parm *parms) |
43 | { |
44 | return !!(parms->o_flags & TUNNEL_KEY); |
45 | } |
46 | |
47 | static u32 mlxsw_sp_ipip_parms4_ikey(const struct ip_tunnel_parm *parms) |
48 | { |
49 | return mlxsw_sp_ipip_parms4_has_ikey(parms) ? |
50 | be32_to_cpu(parms->i_key) : 0; |
51 | } |
52 | |
53 | static u32 mlxsw_sp_ipip_parms6_ikey(const struct __ip6_tnl_parm *parms) |
54 | { |
55 | return mlxsw_sp_ipip_parms6_has_ikey(parms) ? |
56 | be32_to_cpu(parms->i_key) : 0; |
57 | } |
58 | |
59 | static u32 mlxsw_sp_ipip_parms4_okey(const struct ip_tunnel_parm *parms) |
60 | { |
61 | return mlxsw_sp_ipip_parms4_has_okey(parms) ? |
62 | be32_to_cpu(parms->o_key) : 0; |
63 | } |
64 | |
65 | static u32 mlxsw_sp_ipip_parms6_okey(const struct __ip6_tnl_parm *parms) |
66 | { |
67 | return mlxsw_sp_ipip_parms6_has_okey(parms) ? |
68 | be32_to_cpu(parms->o_key) : 0; |
69 | } |
70 | |
71 | static union mlxsw_sp_l3addr |
72 | mlxsw_sp_ipip_parms4_saddr(const struct ip_tunnel_parm *parms) |
73 | { |
74 | return (union mlxsw_sp_l3addr) { .addr4 = parms->iph.saddr }; |
75 | } |
76 | |
77 | static union mlxsw_sp_l3addr |
78 | mlxsw_sp_ipip_parms6_saddr(const struct __ip6_tnl_parm *parms) |
79 | { |
80 | return (union mlxsw_sp_l3addr) { .addr6 = parms->laddr }; |
81 | } |
82 | |
83 | static union mlxsw_sp_l3addr |
84 | mlxsw_sp_ipip_parms4_daddr(const struct ip_tunnel_parm *parms) |
85 | { |
86 | return (union mlxsw_sp_l3addr) { .addr4 = parms->iph.daddr }; |
87 | } |
88 | |
89 | static union mlxsw_sp_l3addr |
90 | mlxsw_sp_ipip_parms6_daddr(const struct __ip6_tnl_parm *parms) |
91 | { |
92 | return (union mlxsw_sp_l3addr) { .addr6 = parms->raddr }; |
93 | } |
94 | |
95 | union mlxsw_sp_l3addr |
96 | mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto, |
97 | const struct net_device *ol_dev) |
98 | { |
99 | struct ip_tunnel_parm parms4; |
100 | struct __ip6_tnl_parm parms6; |
101 | |
102 | switch (proto) { |
103 | case MLXSW_SP_L3_PROTO_IPV4: |
104 | parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev); |
105 | return mlxsw_sp_ipip_parms4_saddr(parms: &parms4); |
106 | case MLXSW_SP_L3_PROTO_IPV6: |
107 | parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev); |
108 | return mlxsw_sp_ipip_parms6_saddr(parms: &parms6); |
109 | } |
110 | |
111 | WARN_ON(1); |
112 | return (union mlxsw_sp_l3addr) {0}; |
113 | } |
114 | |
115 | static __be32 mlxsw_sp_ipip_netdev_daddr4(const struct net_device *ol_dev) |
116 | { |
117 | |
118 | struct ip_tunnel_parm parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev); |
119 | |
120 | return mlxsw_sp_ipip_parms4_daddr(parms: &parms4).addr4; |
121 | } |
122 | |
123 | static union mlxsw_sp_l3addr |
124 | mlxsw_sp_ipip_netdev_daddr(enum mlxsw_sp_l3proto proto, |
125 | const struct net_device *ol_dev) |
126 | { |
127 | struct ip_tunnel_parm parms4; |
128 | struct __ip6_tnl_parm parms6; |
129 | |
130 | switch (proto) { |
131 | case MLXSW_SP_L3_PROTO_IPV4: |
132 | parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev); |
133 | return mlxsw_sp_ipip_parms4_daddr(parms: &parms4); |
134 | case MLXSW_SP_L3_PROTO_IPV6: |
135 | parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev); |
136 | return mlxsw_sp_ipip_parms6_daddr(parms: &parms6); |
137 | } |
138 | |
139 | WARN_ON(1); |
140 | return (union mlxsw_sp_l3addr) {0}; |
141 | } |
142 | |
143 | bool mlxsw_sp_l3addr_is_zero(union mlxsw_sp_l3addr addr) |
144 | { |
145 | union mlxsw_sp_l3addr naddr = {0}; |
146 | |
147 | return !memcmp(p: &addr, q: &naddr, size: sizeof(naddr)); |
148 | } |
149 | |
150 | static struct mlxsw_sp_ipip_parms |
151 | mlxsw_sp_ipip_netdev_parms_init_gre4(const struct net_device *ol_dev) |
152 | { |
153 | struct ip_tunnel_parm parms = mlxsw_sp_ipip_netdev_parms4(ol_dev); |
154 | |
155 | return (struct mlxsw_sp_ipip_parms) { |
156 | .proto = MLXSW_SP_L3_PROTO_IPV4, |
157 | .saddr = mlxsw_sp_ipip_parms4_saddr(parms: &parms), |
158 | .daddr = mlxsw_sp_ipip_parms4_daddr(parms: &parms), |
159 | .link = parms.link, |
160 | .ikey = mlxsw_sp_ipip_parms4_ikey(parms: &parms), |
161 | .okey = mlxsw_sp_ipip_parms4_okey(parms: &parms), |
162 | }; |
163 | } |
164 | |
165 | static int |
166 | mlxsw_sp_ipip_nexthop_update_gre4(struct mlxsw_sp *mlxsw_sp, u32 adj_index, |
167 | struct mlxsw_sp_ipip_entry *ipip_entry, |
168 | bool force, char *ratr_pl) |
169 | { |
170 | u16 rif_index = mlxsw_sp_ipip_lb_rif_index(rif: ipip_entry->ol_lb); |
171 | __be32 daddr4 = mlxsw_sp_ipip_netdev_daddr4(ol_dev: ipip_entry->ol_dev); |
172 | enum mlxsw_reg_ratr_op op; |
173 | |
174 | op = force ? MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY : |
175 | MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY_ON_ACTIVITY; |
176 | mlxsw_reg_ratr_pack(payload: ratr_pl, op, valid: true, type: MLXSW_REG_RATR_TYPE_IPIP, |
177 | adjacency_index: adj_index, egress_rif: rif_index); |
178 | mlxsw_reg_ratr_ipip4_entry_pack(payload: ratr_pl, be32_to_cpu(daddr4)); |
179 | |
180 | return mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(ratr), payload: ratr_pl); |
181 | } |
182 | |
183 | static int |
184 | mlxsw_sp_ipip_decap_config_gre4(struct mlxsw_sp *mlxsw_sp, |
185 | struct mlxsw_sp_ipip_entry *ipip_entry, |
186 | u32 tunnel_index) |
187 | { |
188 | u16 rif_index = mlxsw_sp_ipip_lb_rif_index(rif: ipip_entry->ol_lb); |
189 | u16 ul_rif_id = mlxsw_sp_ipip_lb_ul_rif_id(lb_rif: ipip_entry->ol_lb); |
190 | char rtdp_pl[MLXSW_REG_RTDP_LEN]; |
191 | struct ip_tunnel_parm parms; |
192 | unsigned int type_check; |
193 | bool has_ikey; |
194 | u32 daddr4; |
195 | u32 ikey; |
196 | |
197 | parms = mlxsw_sp_ipip_netdev_parms4(ol_dev: ipip_entry->ol_dev); |
198 | has_ikey = mlxsw_sp_ipip_parms4_has_ikey(parms: &parms); |
199 | ikey = mlxsw_sp_ipip_parms4_ikey(parms: &parms); |
200 | |
201 | mlxsw_reg_rtdp_pack(payload: rtdp_pl, type: MLXSW_REG_RTDP_TYPE_IPIP, tunnel_index); |
202 | mlxsw_reg_rtdp_egress_router_interface_set(buf: rtdp_pl, val: ul_rif_id); |
203 | |
204 | type_check = has_ikey ? |
205 | MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE_KEY : |
206 | MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE; |
207 | |
208 | /* Linux demuxes tunnels based on packet SIP (which must match tunnel |
209 | * remote IP). Thus configure decap so that it filters out packets that |
210 | * are not IPv4 or have the wrong SIP. IPIP_DECAP_ERROR trap is |
211 | * generated for packets that fail this criterion. Linux then handles |
212 | * such packets in slow path and generates ICMP destination unreachable. |
213 | */ |
214 | daddr4 = be32_to_cpu(mlxsw_sp_ipip_netdev_daddr4(ipip_entry->ol_dev)); |
215 | mlxsw_reg_rtdp_ipip4_pack(payload: rtdp_pl, irif: rif_index, |
216 | sip_check: MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV4, |
217 | type_check, gre_key_check: has_ikey, ipv4_usip: daddr4, expected_gre_key: ikey); |
218 | |
219 | return mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(rtdp), payload: rtdp_pl); |
220 | } |
221 | |
222 | static bool mlxsw_sp_ipip_tunnel_complete(enum mlxsw_sp_l3proto proto, |
223 | const struct net_device *ol_dev) |
224 | { |
225 | union mlxsw_sp_l3addr saddr = mlxsw_sp_ipip_netdev_saddr(proto, ol_dev); |
226 | union mlxsw_sp_l3addr daddr = mlxsw_sp_ipip_netdev_daddr(proto, ol_dev); |
227 | |
228 | /* Tunnels with unset local or remote address are valid in Linux and |
229 | * used for lightweight tunnels (LWT) and Non-Broadcast Multi-Access |
230 | * (NBMA) tunnels. In principle these can be offloaded, but the driver |
231 | * currently doesn't support this. So punt. |
232 | */ |
233 | return !mlxsw_sp_l3addr_is_zero(addr: saddr) && |
234 | !mlxsw_sp_l3addr_is_zero(addr: daddr); |
235 | } |
236 | |
237 | static bool mlxsw_sp_ipip_can_offload_gre4(const struct mlxsw_sp *mlxsw_sp, |
238 | const struct net_device *ol_dev) |
239 | { |
240 | struct ip_tunnel *tunnel = netdev_priv(dev: ol_dev); |
241 | __be16 okflags = TUNNEL_KEY; /* We can't offload any other features. */ |
242 | bool inherit_ttl = tunnel->parms.iph.ttl == 0; |
243 | bool inherit_tos = tunnel->parms.iph.tos & 0x1; |
244 | |
245 | return (tunnel->parms.i_flags & ~okflags) == 0 && |
246 | (tunnel->parms.o_flags & ~okflags) == 0 && |
247 | inherit_ttl && inherit_tos && |
248 | mlxsw_sp_ipip_tunnel_complete(proto: MLXSW_SP_L3_PROTO_IPV4, ol_dev); |
249 | } |
250 | |
251 | static struct mlxsw_sp_rif_ipip_lb_config |
252 | mlxsw_sp_ipip_ol_loopback_config_gre4(struct mlxsw_sp *mlxsw_sp, |
253 | const struct net_device *ol_dev) |
254 | { |
255 | struct ip_tunnel_parm parms = mlxsw_sp_ipip_netdev_parms4(ol_dev); |
256 | enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt; |
257 | |
258 | lb_ipipt = mlxsw_sp_ipip_parms4_has_okey(parms: &parms) ? |
259 | MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP : |
260 | MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP; |
261 | return (struct mlxsw_sp_rif_ipip_lb_config){ |
262 | .lb_ipipt = lb_ipipt, |
263 | .okey = mlxsw_sp_ipip_parms4_okey(parms: &parms), |
264 | .ul_protocol = MLXSW_SP_L3_PROTO_IPV4, |
265 | .saddr = mlxsw_sp_ipip_netdev_saddr(proto: MLXSW_SP_L3_PROTO_IPV4, |
266 | ol_dev), |
267 | }; |
268 | } |
269 | |
270 | static int |
271 | mlxsw_sp_ipip_ol_netdev_change_gre(struct mlxsw_sp *mlxsw_sp, |
272 | struct mlxsw_sp_ipip_entry *ipip_entry, |
273 | const struct mlxsw_sp_ipip_parms *new_parms, |
274 | struct netlink_ext_ack *extack) |
275 | { |
276 | const struct mlxsw_sp_ipip_parms *old_parms = &ipip_entry->parms; |
277 | bool update_tunnel = false; |
278 | bool update_decap = false; |
279 | bool update_nhs = false; |
280 | int err = 0; |
281 | |
282 | if (!mlxsw_sp_l3addr_eq(addr1: &new_parms->saddr, addr2: &old_parms->saddr)) { |
283 | u16 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ol_dev: ipip_entry->ol_dev); |
284 | |
285 | /* Since the local address has changed, if there is another |
286 | * tunnel with a matching saddr, both need to be demoted. |
287 | */ |
288 | if (mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp, |
289 | ul_proto: new_parms->proto, |
290 | saddr: new_parms->saddr, |
291 | ul_tb_id, |
292 | except: ipip_entry)) { |
293 | mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry); |
294 | return 0; |
295 | } |
296 | |
297 | update_tunnel = true; |
298 | } else if (old_parms->okey != new_parms->okey || |
299 | old_parms->link != new_parms->link) { |
300 | update_tunnel = true; |
301 | } else if (!mlxsw_sp_l3addr_eq(addr1: &new_parms->daddr, addr2: &old_parms->daddr)) { |
302 | update_nhs = true; |
303 | } else if (old_parms->ikey != new_parms->ikey) { |
304 | update_decap = true; |
305 | } |
306 | |
307 | if (update_tunnel) |
308 | err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry, |
309 | recreate_loopback: true, keep_encap: true, update_nexthops: true, |
310 | extack); |
311 | else if (update_nhs) |
312 | err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry, |
313 | recreate_loopback: false, keep_encap: false, update_nexthops: true, |
314 | extack); |
315 | else if (update_decap) |
316 | err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry, |
317 | recreate_loopback: false, keep_encap: false, update_nexthops: false, |
318 | extack); |
319 | if (err) |
320 | return err; |
321 | |
322 | ipip_entry->parms = *new_parms; |
323 | return 0; |
324 | } |
325 | |
326 | static int |
327 | mlxsw_sp_ipip_ol_netdev_change_gre4(struct mlxsw_sp *mlxsw_sp, |
328 | struct mlxsw_sp_ipip_entry *ipip_entry, |
329 | struct netlink_ext_ack *extack) |
330 | { |
331 | struct mlxsw_sp_ipip_parms new_parms; |
332 | |
333 | new_parms = mlxsw_sp_ipip_netdev_parms_init_gre4(ol_dev: ipip_entry->ol_dev); |
334 | return mlxsw_sp_ipip_ol_netdev_change_gre(mlxsw_sp, ipip_entry, |
335 | new_parms: &new_parms, extack); |
336 | } |
337 | |
338 | static int |
339 | mlxsw_sp_ipip_rem_addr_set_gre4(struct mlxsw_sp *mlxsw_sp, |
340 | struct mlxsw_sp_ipip_entry *ipip_entry) |
341 | { |
342 | return 0; |
343 | } |
344 | |
345 | static void |
346 | mlxsw_sp_ipip_rem_addr_unset_gre4(struct mlxsw_sp *mlxsw_sp, |
347 | const struct mlxsw_sp_ipip_entry *ipip_entry) |
348 | { |
349 | } |
350 | |
351 | static const struct mlxsw_sp_ipip_ops mlxsw_sp_ipip_gre4_ops = { |
352 | .dev_type = ARPHRD_IPGRE, |
353 | .ul_proto = MLXSW_SP_L3_PROTO_IPV4, |
354 | .inc_parsing_depth = false, |
355 | .parms_init = mlxsw_sp_ipip_netdev_parms_init_gre4, |
356 | .nexthop_update = mlxsw_sp_ipip_nexthop_update_gre4, |
357 | .decap_config = mlxsw_sp_ipip_decap_config_gre4, |
358 | .can_offload = mlxsw_sp_ipip_can_offload_gre4, |
359 | .ol_loopback_config = mlxsw_sp_ipip_ol_loopback_config_gre4, |
360 | .ol_netdev_change = mlxsw_sp_ipip_ol_netdev_change_gre4, |
361 | .rem_ip_addr_set = mlxsw_sp_ipip_rem_addr_set_gre4, |
362 | .rem_ip_addr_unset = mlxsw_sp_ipip_rem_addr_unset_gre4, |
363 | }; |
364 | |
365 | static struct mlxsw_sp_ipip_parms |
366 | mlxsw_sp_ipip_netdev_parms_init_gre6(const struct net_device *ol_dev) |
367 | { |
368 | struct __ip6_tnl_parm parms = mlxsw_sp_ipip_netdev_parms6(ol_dev); |
369 | |
370 | return (struct mlxsw_sp_ipip_parms) { |
371 | .proto = MLXSW_SP_L3_PROTO_IPV6, |
372 | .saddr = mlxsw_sp_ipip_parms6_saddr(parms: &parms), |
373 | .daddr = mlxsw_sp_ipip_parms6_daddr(parms: &parms), |
374 | .link = parms.link, |
375 | .ikey = mlxsw_sp_ipip_parms6_ikey(parms: &parms), |
376 | .okey = mlxsw_sp_ipip_parms6_okey(parms: &parms), |
377 | }; |
378 | } |
379 | |
380 | static int |
381 | mlxsw_sp_ipip_nexthop_update_gre6(struct mlxsw_sp *mlxsw_sp, u32 adj_index, |
382 | struct mlxsw_sp_ipip_entry *ipip_entry, |
383 | bool force, char *ratr_pl) |
384 | { |
385 | u16 rif_index = mlxsw_sp_ipip_lb_rif_index(rif: ipip_entry->ol_lb); |
386 | enum mlxsw_reg_ratr_op op; |
387 | |
388 | op = force ? MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY : |
389 | MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY_ON_ACTIVITY; |
390 | mlxsw_reg_ratr_pack(payload: ratr_pl, op, valid: true, type: MLXSW_REG_RATR_TYPE_IPIP, |
391 | adjacency_index: adj_index, egress_rif: rif_index); |
392 | mlxsw_reg_ratr_ipip6_entry_pack(payload: ratr_pl, |
393 | ipv6_ptr: ipip_entry->dip_kvdl_index); |
394 | |
395 | return mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(ratr), payload: ratr_pl); |
396 | } |
397 | |
398 | static int |
399 | mlxsw_sp_ipip_decap_config_gre6(struct mlxsw_sp *mlxsw_sp, |
400 | struct mlxsw_sp_ipip_entry *ipip_entry, |
401 | u32 tunnel_index) |
402 | { |
403 | u16 rif_index = mlxsw_sp_ipip_lb_rif_index(rif: ipip_entry->ol_lb); |
404 | u16 ul_rif_id = mlxsw_sp_ipip_lb_ul_rif_id(lb_rif: ipip_entry->ol_lb); |
405 | char rtdp_pl[MLXSW_REG_RTDP_LEN]; |
406 | struct __ip6_tnl_parm parms; |
407 | unsigned int type_check; |
408 | bool has_ikey; |
409 | u32 ikey; |
410 | |
411 | parms = mlxsw_sp_ipip_netdev_parms6(ol_dev: ipip_entry->ol_dev); |
412 | has_ikey = mlxsw_sp_ipip_parms6_has_ikey(parms: &parms); |
413 | ikey = mlxsw_sp_ipip_parms6_ikey(parms: &parms); |
414 | |
415 | mlxsw_reg_rtdp_pack(payload: rtdp_pl, type: MLXSW_REG_RTDP_TYPE_IPIP, tunnel_index); |
416 | mlxsw_reg_rtdp_egress_router_interface_set(buf: rtdp_pl, val: ul_rif_id); |
417 | |
418 | type_check = has_ikey ? |
419 | MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE_KEY : |
420 | MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE; |
421 | |
422 | /* Linux demuxes tunnels based on packet SIP (which must match tunnel |
423 | * remote IP). Thus configure decap so that it filters out packets that |
424 | * are not IPv6 or have the wrong SIP. IPIP_DECAP_ERROR trap is |
425 | * generated for packets that fail this criterion. Linux then handles |
426 | * such packets in slow path and generates ICMP destination unreachable. |
427 | */ |
428 | mlxsw_reg_rtdp_ipip6_pack(payload: rtdp_pl, irif: rif_index, |
429 | sip_check: MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV6, |
430 | type_check, gre_key_check: has_ikey, |
431 | ipv6_usip_ptr: ipip_entry->dip_kvdl_index, expected_gre_key: ikey); |
432 | |
433 | return mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(rtdp), payload: rtdp_pl); |
434 | } |
435 | |
436 | static bool mlxsw_sp_ipip_can_offload_gre6(const struct mlxsw_sp *mlxsw_sp, |
437 | const struct net_device *ol_dev) |
438 | { |
439 | struct __ip6_tnl_parm tparm = mlxsw_sp_ipip_netdev_parms6(ol_dev); |
440 | bool inherit_tos = tparm.flags & IP6_TNL_F_USE_ORIG_TCLASS; |
441 | bool inherit_ttl = tparm.hop_limit == 0; |
442 | __be16 okflags = TUNNEL_KEY; /* We can't offload any other features. */ |
443 | |
444 | return (tparm.i_flags & ~okflags) == 0 && |
445 | (tparm.o_flags & ~okflags) == 0 && |
446 | inherit_ttl && inherit_tos && |
447 | mlxsw_sp_ipip_tunnel_complete(proto: MLXSW_SP_L3_PROTO_IPV6, ol_dev); |
448 | } |
449 | |
450 | static struct mlxsw_sp_rif_ipip_lb_config |
451 | mlxsw_sp_ipip_ol_loopback_config_gre6(struct mlxsw_sp *mlxsw_sp, |
452 | const struct net_device *ol_dev) |
453 | { |
454 | struct __ip6_tnl_parm parms = mlxsw_sp_ipip_netdev_parms6(ol_dev); |
455 | enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt; |
456 | |
457 | lb_ipipt = mlxsw_sp_ipip_parms6_has_okey(parms: &parms) ? |
458 | MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP : |
459 | MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP; |
460 | return (struct mlxsw_sp_rif_ipip_lb_config){ |
461 | .lb_ipipt = lb_ipipt, |
462 | .okey = mlxsw_sp_ipip_parms6_okey(parms: &parms), |
463 | .ul_protocol = MLXSW_SP_L3_PROTO_IPV6, |
464 | .saddr = mlxsw_sp_ipip_netdev_saddr(proto: MLXSW_SP_L3_PROTO_IPV6, |
465 | ol_dev), |
466 | }; |
467 | } |
468 | |
469 | static int |
470 | mlxsw_sp_ipip_ol_netdev_change_gre6(struct mlxsw_sp *mlxsw_sp, |
471 | struct mlxsw_sp_ipip_entry *ipip_entry, |
472 | struct netlink_ext_ack *extack) |
473 | { |
474 | struct mlxsw_sp_ipip_parms new_parms; |
475 | |
476 | new_parms = mlxsw_sp_ipip_netdev_parms_init_gre6(ol_dev: ipip_entry->ol_dev); |
477 | return mlxsw_sp_ipip_ol_netdev_change_gre(mlxsw_sp, ipip_entry, |
478 | new_parms: &new_parms, extack); |
479 | } |
480 | |
481 | static int |
482 | mlxsw_sp_ipip_rem_addr_set_gre6(struct mlxsw_sp *mlxsw_sp, |
483 | struct mlxsw_sp_ipip_entry *ipip_entry) |
484 | { |
485 | return mlxsw_sp_ipv6_addr_kvdl_index_get(mlxsw_sp, |
486 | addr6: &ipip_entry->parms.daddr.addr6, |
487 | p_kvdl_index: &ipip_entry->dip_kvdl_index); |
488 | } |
489 | |
490 | static void |
491 | mlxsw_sp_ipip_rem_addr_unset_gre6(struct mlxsw_sp *mlxsw_sp, |
492 | const struct mlxsw_sp_ipip_entry *ipip_entry) |
493 | { |
494 | mlxsw_sp_ipv6_addr_put(mlxsw_sp, addr6: &ipip_entry->parms.daddr.addr6); |
495 | } |
496 | |
497 | static const struct mlxsw_sp_ipip_ops mlxsw_sp1_ipip_gre6_ops = { |
498 | .dev_type = ARPHRD_IP6GRE, |
499 | .ul_proto = MLXSW_SP_L3_PROTO_IPV6, |
500 | .inc_parsing_depth = true, |
501 | .double_rif_entry = true, |
502 | .parms_init = mlxsw_sp_ipip_netdev_parms_init_gre6, |
503 | .nexthop_update = mlxsw_sp_ipip_nexthop_update_gre6, |
504 | .decap_config = mlxsw_sp_ipip_decap_config_gre6, |
505 | .can_offload = mlxsw_sp_ipip_can_offload_gre6, |
506 | .ol_loopback_config = mlxsw_sp_ipip_ol_loopback_config_gre6, |
507 | .ol_netdev_change = mlxsw_sp_ipip_ol_netdev_change_gre6, |
508 | .rem_ip_addr_set = mlxsw_sp_ipip_rem_addr_set_gre6, |
509 | .rem_ip_addr_unset = mlxsw_sp_ipip_rem_addr_unset_gre6, |
510 | }; |
511 | |
512 | const struct mlxsw_sp_ipip_ops *mlxsw_sp1_ipip_ops_arr[] = { |
513 | [MLXSW_SP_IPIP_TYPE_GRE4] = &mlxsw_sp_ipip_gre4_ops, |
514 | [MLXSW_SP_IPIP_TYPE_GRE6] = &mlxsw_sp1_ipip_gre6_ops, |
515 | }; |
516 | |
517 | static const struct mlxsw_sp_ipip_ops mlxsw_sp2_ipip_gre6_ops = { |
518 | .dev_type = ARPHRD_IP6GRE, |
519 | .ul_proto = MLXSW_SP_L3_PROTO_IPV6, |
520 | .inc_parsing_depth = true, |
521 | .parms_init = mlxsw_sp_ipip_netdev_parms_init_gre6, |
522 | .nexthop_update = mlxsw_sp_ipip_nexthop_update_gre6, |
523 | .decap_config = mlxsw_sp_ipip_decap_config_gre6, |
524 | .can_offload = mlxsw_sp_ipip_can_offload_gre6, |
525 | .ol_loopback_config = mlxsw_sp_ipip_ol_loopback_config_gre6, |
526 | .ol_netdev_change = mlxsw_sp_ipip_ol_netdev_change_gre6, |
527 | .rem_ip_addr_set = mlxsw_sp_ipip_rem_addr_set_gre6, |
528 | .rem_ip_addr_unset = mlxsw_sp_ipip_rem_addr_unset_gre6, |
529 | }; |
530 | |
531 | const struct mlxsw_sp_ipip_ops *mlxsw_sp2_ipip_ops_arr[] = { |
532 | [MLXSW_SP_IPIP_TYPE_GRE4] = &mlxsw_sp_ipip_gre4_ops, |
533 | [MLXSW_SP_IPIP_TYPE_GRE6] = &mlxsw_sp2_ipip_gre6_ops, |
534 | }; |
535 | |
536 | static int mlxsw_sp_ipip_ecn_encap_init_one(struct mlxsw_sp *mlxsw_sp, |
537 | u8 inner_ecn, u8 outer_ecn) |
538 | { |
539 | char tieem_pl[MLXSW_REG_TIEEM_LEN]; |
540 | |
541 | mlxsw_reg_tieem_pack(payload: tieem_pl, overlay_ecn: inner_ecn, underlay_ecn: outer_ecn); |
542 | return mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(tieem), payload: tieem_pl); |
543 | } |
544 | |
545 | int mlxsw_sp_ipip_ecn_encap_init(struct mlxsw_sp *mlxsw_sp) |
546 | { |
547 | int i; |
548 | |
549 | /* Iterate over inner ECN values */ |
550 | for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) { |
551 | u8 outer_ecn = INET_ECN_encapsulate(outer: 0, inner: i); |
552 | int err; |
553 | |
554 | err = mlxsw_sp_ipip_ecn_encap_init_one(mlxsw_sp, inner_ecn: i, outer_ecn); |
555 | if (err) |
556 | return err; |
557 | } |
558 | |
559 | return 0; |
560 | } |
561 | |
562 | static int mlxsw_sp_ipip_ecn_decap_init_one(struct mlxsw_sp *mlxsw_sp, |
563 | u8 inner_ecn, u8 outer_ecn) |
564 | { |
565 | char tidem_pl[MLXSW_REG_TIDEM_LEN]; |
566 | u8 new_inner_ecn; |
567 | bool trap_en; |
568 | |
569 | new_inner_ecn = mlxsw_sp_tunnel_ecn_decap(outer_ecn, inner_ecn, |
570 | trap_en: &trap_en); |
571 | mlxsw_reg_tidem_pack(payload: tidem_pl, underlay_ecn: outer_ecn, overlay_ecn: inner_ecn, eip_ecn: new_inner_ecn, |
572 | trap_en, trap_id: trap_en ? MLXSW_TRAP_ID_DECAP_ECN0 : 0); |
573 | return mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(tidem), payload: tidem_pl); |
574 | } |
575 | |
576 | int mlxsw_sp_ipip_ecn_decap_init(struct mlxsw_sp *mlxsw_sp) |
577 | { |
578 | int i, j, err; |
579 | |
580 | /* Iterate over inner ECN values */ |
581 | for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) { |
582 | /* Iterate over outer ECN values */ |
583 | for (j = INET_ECN_NOT_ECT; j <= INET_ECN_CE; j++) { |
584 | err = mlxsw_sp_ipip_ecn_decap_init_one(mlxsw_sp, inner_ecn: i, outer_ecn: j); |
585 | if (err) |
586 | return err; |
587 | } |
588 | } |
589 | |
590 | return 0; |
591 | } |
592 | |
593 | struct net_device * |
594 | mlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device *ol_dev) |
595 | { |
596 | struct net *net = dev_net(dev: ol_dev); |
597 | struct ip_tunnel *tun4; |
598 | struct ip6_tnl *tun6; |
599 | |
600 | switch (ol_dev->type) { |
601 | case ARPHRD_IPGRE: |
602 | tun4 = netdev_priv(dev: ol_dev); |
603 | return dev_get_by_index_rcu(net, ifindex: tun4->parms.link); |
604 | case ARPHRD_IP6GRE: |
605 | tun6 = netdev_priv(dev: ol_dev); |
606 | return dev_get_by_index_rcu(net, ifindex: tun6->parms.link); |
607 | default: |
608 | return NULL; |
609 | } |
610 | } |
611 | |