GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum_ipip.c
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(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(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(&parms4);
106         case MLXSW_SP_L3_PROTO_IPV6:
107                 parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev);
108                 return mlxsw_sp_ipip_parms6_saddr(&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(&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(&parms4);
134         case MLXSW_SP_L3_PROTO_IPV6:
135                 parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev);
136                 return mlxsw_sp_ipip_parms6_daddr(&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(&addr, &naddr, 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),
158                 .daddr = mlxsw_sp_ipip_parms4_daddr(&parms),
159                 .link = parms.link,
160                 .ikey = mlxsw_sp_ipip_parms4_ikey(&parms),
161                 .okey = mlxsw_sp_ipip_parms4_okey(&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(ipip_entry->ol_lb);
171         __be32 daddr4 = mlxsw_sp_ipip_netdev_daddr4(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(ratr_pl, op, true, MLXSW_REG_RATR_TYPE_IPIP,
177                             adj_index, rif_index);
178         mlxsw_reg_ratr_ipip4_entry_pack(ratr_pl, be32_to_cpu(daddr4));
179
180         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), 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(ipip_entry->ol_lb);
189         u16 ul_rif_id = mlxsw_sp_ipip_lb_ul_rif_id(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(ipip_entry->ol_dev);
198         has_ikey = mlxsw_sp_ipip_parms4_has_ikey(&parms);
199         ikey = mlxsw_sp_ipip_parms4_ikey(&parms);
200
201         mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_IPIP, tunnel_index);
202         mlxsw_reg_rtdp_egress_router_interface_set(rtdp_pl, 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(rtdp_pl, rif_index,
216                                   MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV4,
217                                   type_check, has_ikey, daddr4, ikey);
218
219         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), 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(saddr) &&
234                !mlxsw_sp_l3addr_is_zero(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(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(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) ?
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),
264                 .ul_protocol = MLXSW_SP_L3_PROTO_IPV4,
265                 .saddr = mlxsw_sp_ipip_netdev_saddr(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(&new_parms->saddr, &old_parms->saddr)) {
283                 u16 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(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                                                          new_parms->proto,
290                                                          new_parms->saddr,
291                                                          ul_tb_id,
292                                                          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(&new_parms->daddr, &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                                                           true, true, true,
310                                                           extack);
311         else if (update_nhs)
312                 err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
313                                                           false, false, true,
314                                                           extack);
315         else if (update_decap)
316                 err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry,
317                                                           false, false, 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(ipip_entry->ol_dev);
334         return mlxsw_sp_ipip_ol_netdev_change_gre(mlxsw_sp, ipip_entry,
335                                                   &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),
373                 .daddr = mlxsw_sp_ipip_parms6_daddr(&parms),
374                 .link = parms.link,
375                 .ikey = mlxsw_sp_ipip_parms6_ikey(&parms),
376                 .okey = mlxsw_sp_ipip_parms6_okey(&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(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(ratr_pl, op, true, MLXSW_REG_RATR_TYPE_IPIP,
391                             adj_index, rif_index);
392         mlxsw_reg_ratr_ipip6_entry_pack(ratr_pl,
393                                         ipip_entry->dip_kvdl_index);
394
395         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), 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(ipip_entry->ol_lb);
404         u16 ul_rif_id = mlxsw_sp_ipip_lb_ul_rif_id(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(ipip_entry->ol_dev);
412         has_ikey = mlxsw_sp_ipip_parms6_has_ikey(&parms);
413         ikey = mlxsw_sp_ipip_parms6_ikey(&parms);
414
415         mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_IPIP, tunnel_index);
416         mlxsw_reg_rtdp_egress_router_interface_set(rtdp_pl, 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(rtdp_pl, rif_index,
429                                   MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV6,
430                                   type_check, has_ikey,
431                                   ipip_entry->dip_kvdl_index, ikey);
432
433         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), 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(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) ?
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),
463                 .ul_protocol = MLXSW_SP_L3_PROTO_IPV6,
464                 .saddr = mlxsw_sp_ipip_netdev_saddr(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(ipip_entry->ol_dev);
477         return mlxsw_sp_ipip_ol_netdev_change_gre(mlxsw_sp, ipip_entry,
478                                                   &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                                                  &ipip_entry->parms.daddr.addr6,
487                                                  &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, &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(tieem_pl, inner_ecn, outer_ecn);
542         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tieem), 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(0, i);
552                 int err;
553
554                 err = mlxsw_sp_ipip_ecn_encap_init_one(mlxsw_sp, 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);
571         mlxsw_reg_tidem_pack(tidem_pl, outer_ecn, inner_ecn, new_inner_ecn,
572                              trap_en, trap_en ? MLXSW_TRAP_ID_DECAP_ECN0 : 0);
573         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tidem), 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, i, 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(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(ol_dev);
603                 return dev_get_by_index_rcu(net, tun4->parms.link);
604         case ARPHRD_IP6GRE:
605                 tun6 = netdev_priv(ol_dev);
606                 return dev_get_by_index_rcu(net, tun6->parms.link);
607         default:
608                 return NULL;
609         }
610 }