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