162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <net/ip_tunnels.h> 562306a36Sopenharmony_ci#include <net/ip6_tunnel.h> 662306a36Sopenharmony_ci#include <net/inet_ecn.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "spectrum_ipip.h" 962306a36Sopenharmony_ci#include "reg.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistruct ip_tunnel_parm 1262306a36Sopenharmony_cimlxsw_sp_ipip_netdev_parms4(const struct net_device *ol_dev) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci struct ip_tunnel *tun = netdev_priv(ol_dev); 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci return tun->parms; 1762306a36Sopenharmony_ci} 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistruct __ip6_tnl_parm 2062306a36Sopenharmony_cimlxsw_sp_ipip_netdev_parms6(const struct net_device *ol_dev) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci struct ip6_tnl *tun = netdev_priv(ol_dev); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci return tun->parms; 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic bool mlxsw_sp_ipip_parms4_has_ikey(const struct ip_tunnel_parm *parms) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci return !!(parms->i_flags & TUNNEL_KEY); 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic bool mlxsw_sp_ipip_parms6_has_ikey(const struct __ip6_tnl_parm *parms) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci return !!(parms->i_flags & TUNNEL_KEY); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic bool mlxsw_sp_ipip_parms4_has_okey(const struct ip_tunnel_parm *parms) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci return !!(parms->o_flags & TUNNEL_KEY); 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic bool mlxsw_sp_ipip_parms6_has_okey(const struct __ip6_tnl_parm *parms) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci return !!(parms->o_flags & TUNNEL_KEY); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic u32 mlxsw_sp_ipip_parms4_ikey(const struct ip_tunnel_parm *parms) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci return mlxsw_sp_ipip_parms4_has_ikey(parms) ? 5062306a36Sopenharmony_ci be32_to_cpu(parms->i_key) : 0; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic u32 mlxsw_sp_ipip_parms6_ikey(const struct __ip6_tnl_parm *parms) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci return mlxsw_sp_ipip_parms6_has_ikey(parms) ? 5662306a36Sopenharmony_ci be32_to_cpu(parms->i_key) : 0; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic u32 mlxsw_sp_ipip_parms4_okey(const struct ip_tunnel_parm *parms) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci return mlxsw_sp_ipip_parms4_has_okey(parms) ? 6262306a36Sopenharmony_ci be32_to_cpu(parms->o_key) : 0; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic u32 mlxsw_sp_ipip_parms6_okey(const struct __ip6_tnl_parm *parms) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci return mlxsw_sp_ipip_parms6_has_okey(parms) ? 6862306a36Sopenharmony_ci be32_to_cpu(parms->o_key) : 0; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic union mlxsw_sp_l3addr 7262306a36Sopenharmony_cimlxsw_sp_ipip_parms4_saddr(const struct ip_tunnel_parm *parms) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci return (union mlxsw_sp_l3addr) { .addr4 = parms->iph.saddr }; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic union mlxsw_sp_l3addr 7862306a36Sopenharmony_cimlxsw_sp_ipip_parms6_saddr(const struct __ip6_tnl_parm *parms) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci return (union mlxsw_sp_l3addr) { .addr6 = parms->laddr }; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic union mlxsw_sp_l3addr 8462306a36Sopenharmony_cimlxsw_sp_ipip_parms4_daddr(const struct ip_tunnel_parm *parms) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci return (union mlxsw_sp_l3addr) { .addr4 = parms->iph.daddr }; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic union mlxsw_sp_l3addr 9062306a36Sopenharmony_cimlxsw_sp_ipip_parms6_daddr(const struct __ip6_tnl_parm *parms) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci return (union mlxsw_sp_l3addr) { .addr6 = parms->raddr }; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ciunion mlxsw_sp_l3addr 9662306a36Sopenharmony_cimlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto, 9762306a36Sopenharmony_ci const struct net_device *ol_dev) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct ip_tunnel_parm parms4; 10062306a36Sopenharmony_ci struct __ip6_tnl_parm parms6; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci switch (proto) { 10362306a36Sopenharmony_ci case MLXSW_SP_L3_PROTO_IPV4: 10462306a36Sopenharmony_ci parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev); 10562306a36Sopenharmony_ci return mlxsw_sp_ipip_parms4_saddr(&parms4); 10662306a36Sopenharmony_ci case MLXSW_SP_L3_PROTO_IPV6: 10762306a36Sopenharmony_ci parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev); 10862306a36Sopenharmony_ci return mlxsw_sp_ipip_parms6_saddr(&parms6); 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci WARN_ON(1); 11262306a36Sopenharmony_ci return (union mlxsw_sp_l3addr) {0}; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic __be32 mlxsw_sp_ipip_netdev_daddr4(const struct net_device *ol_dev) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci struct ip_tunnel_parm parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci return mlxsw_sp_ipip_parms4_daddr(&parms4).addr4; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic union mlxsw_sp_l3addr 12462306a36Sopenharmony_cimlxsw_sp_ipip_netdev_daddr(enum mlxsw_sp_l3proto proto, 12562306a36Sopenharmony_ci const struct net_device *ol_dev) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci struct ip_tunnel_parm parms4; 12862306a36Sopenharmony_ci struct __ip6_tnl_parm parms6; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci switch (proto) { 13162306a36Sopenharmony_ci case MLXSW_SP_L3_PROTO_IPV4: 13262306a36Sopenharmony_ci parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev); 13362306a36Sopenharmony_ci return mlxsw_sp_ipip_parms4_daddr(&parms4); 13462306a36Sopenharmony_ci case MLXSW_SP_L3_PROTO_IPV6: 13562306a36Sopenharmony_ci parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev); 13662306a36Sopenharmony_ci return mlxsw_sp_ipip_parms6_daddr(&parms6); 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci WARN_ON(1); 14062306a36Sopenharmony_ci return (union mlxsw_sp_l3addr) {0}; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cibool mlxsw_sp_l3addr_is_zero(union mlxsw_sp_l3addr addr) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci union mlxsw_sp_l3addr naddr = {0}; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci return !memcmp(&addr, &naddr, sizeof(naddr)); 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic struct mlxsw_sp_ipip_parms 15162306a36Sopenharmony_cimlxsw_sp_ipip_netdev_parms_init_gre4(const struct net_device *ol_dev) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct ip_tunnel_parm parms = mlxsw_sp_ipip_netdev_parms4(ol_dev); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return (struct mlxsw_sp_ipip_parms) { 15662306a36Sopenharmony_ci .proto = MLXSW_SP_L3_PROTO_IPV4, 15762306a36Sopenharmony_ci .saddr = mlxsw_sp_ipip_parms4_saddr(&parms), 15862306a36Sopenharmony_ci .daddr = mlxsw_sp_ipip_parms4_daddr(&parms), 15962306a36Sopenharmony_ci .link = parms.link, 16062306a36Sopenharmony_ci .ikey = mlxsw_sp_ipip_parms4_ikey(&parms), 16162306a36Sopenharmony_ci .okey = mlxsw_sp_ipip_parms4_okey(&parms), 16262306a36Sopenharmony_ci }; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic int 16662306a36Sopenharmony_cimlxsw_sp_ipip_nexthop_update_gre4(struct mlxsw_sp *mlxsw_sp, u32 adj_index, 16762306a36Sopenharmony_ci struct mlxsw_sp_ipip_entry *ipip_entry, 16862306a36Sopenharmony_ci bool force, char *ratr_pl) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb); 17162306a36Sopenharmony_ci __be32 daddr4 = mlxsw_sp_ipip_netdev_daddr4(ipip_entry->ol_dev); 17262306a36Sopenharmony_ci enum mlxsw_reg_ratr_op op; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci op = force ? MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY : 17562306a36Sopenharmony_ci MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY_ON_ACTIVITY; 17662306a36Sopenharmony_ci mlxsw_reg_ratr_pack(ratr_pl, op, true, MLXSW_REG_RATR_TYPE_IPIP, 17762306a36Sopenharmony_ci adj_index, rif_index); 17862306a36Sopenharmony_ci mlxsw_reg_ratr_ipip4_entry_pack(ratr_pl, be32_to_cpu(daddr4)); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl); 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic int 18462306a36Sopenharmony_cimlxsw_sp_ipip_decap_config_gre4(struct mlxsw_sp *mlxsw_sp, 18562306a36Sopenharmony_ci struct mlxsw_sp_ipip_entry *ipip_entry, 18662306a36Sopenharmony_ci u32 tunnel_index) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb); 18962306a36Sopenharmony_ci u16 ul_rif_id = mlxsw_sp_ipip_lb_ul_rif_id(ipip_entry->ol_lb); 19062306a36Sopenharmony_ci char rtdp_pl[MLXSW_REG_RTDP_LEN]; 19162306a36Sopenharmony_ci struct ip_tunnel_parm parms; 19262306a36Sopenharmony_ci unsigned int type_check; 19362306a36Sopenharmony_ci bool has_ikey; 19462306a36Sopenharmony_ci u32 daddr4; 19562306a36Sopenharmony_ci u32 ikey; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci parms = mlxsw_sp_ipip_netdev_parms4(ipip_entry->ol_dev); 19862306a36Sopenharmony_ci has_ikey = mlxsw_sp_ipip_parms4_has_ikey(&parms); 19962306a36Sopenharmony_ci ikey = mlxsw_sp_ipip_parms4_ikey(&parms); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_IPIP, tunnel_index); 20262306a36Sopenharmony_ci mlxsw_reg_rtdp_egress_router_interface_set(rtdp_pl, ul_rif_id); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci type_check = has_ikey ? 20562306a36Sopenharmony_ci MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE_KEY : 20662306a36Sopenharmony_ci MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* Linux demuxes tunnels based on packet SIP (which must match tunnel 20962306a36Sopenharmony_ci * remote IP). Thus configure decap so that it filters out packets that 21062306a36Sopenharmony_ci * are not IPv4 or have the wrong SIP. IPIP_DECAP_ERROR trap is 21162306a36Sopenharmony_ci * generated for packets that fail this criterion. Linux then handles 21262306a36Sopenharmony_ci * such packets in slow path and generates ICMP destination unreachable. 21362306a36Sopenharmony_ci */ 21462306a36Sopenharmony_ci daddr4 = be32_to_cpu(mlxsw_sp_ipip_netdev_daddr4(ipip_entry->ol_dev)); 21562306a36Sopenharmony_ci mlxsw_reg_rtdp_ipip4_pack(rtdp_pl, rif_index, 21662306a36Sopenharmony_ci MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV4, 21762306a36Sopenharmony_ci type_check, has_ikey, daddr4, ikey); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), rtdp_pl); 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic bool mlxsw_sp_ipip_tunnel_complete(enum mlxsw_sp_l3proto proto, 22362306a36Sopenharmony_ci const struct net_device *ol_dev) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci union mlxsw_sp_l3addr saddr = mlxsw_sp_ipip_netdev_saddr(proto, ol_dev); 22662306a36Sopenharmony_ci union mlxsw_sp_l3addr daddr = mlxsw_sp_ipip_netdev_daddr(proto, ol_dev); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* Tunnels with unset local or remote address are valid in Linux and 22962306a36Sopenharmony_ci * used for lightweight tunnels (LWT) and Non-Broadcast Multi-Access 23062306a36Sopenharmony_ci * (NBMA) tunnels. In principle these can be offloaded, but the driver 23162306a36Sopenharmony_ci * currently doesn't support this. So punt. 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci return !mlxsw_sp_l3addr_is_zero(saddr) && 23462306a36Sopenharmony_ci !mlxsw_sp_l3addr_is_zero(daddr); 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic bool mlxsw_sp_ipip_can_offload_gre4(const struct mlxsw_sp *mlxsw_sp, 23862306a36Sopenharmony_ci const struct net_device *ol_dev) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci struct ip_tunnel *tunnel = netdev_priv(ol_dev); 24162306a36Sopenharmony_ci __be16 okflags = TUNNEL_KEY; /* We can't offload any other features. */ 24262306a36Sopenharmony_ci bool inherit_ttl = tunnel->parms.iph.ttl == 0; 24362306a36Sopenharmony_ci bool inherit_tos = tunnel->parms.iph.tos & 0x1; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci return (tunnel->parms.i_flags & ~okflags) == 0 && 24662306a36Sopenharmony_ci (tunnel->parms.o_flags & ~okflags) == 0 && 24762306a36Sopenharmony_ci inherit_ttl && inherit_tos && 24862306a36Sopenharmony_ci mlxsw_sp_ipip_tunnel_complete(MLXSW_SP_L3_PROTO_IPV4, ol_dev); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic struct mlxsw_sp_rif_ipip_lb_config 25262306a36Sopenharmony_cimlxsw_sp_ipip_ol_loopback_config_gre4(struct mlxsw_sp *mlxsw_sp, 25362306a36Sopenharmony_ci const struct net_device *ol_dev) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct ip_tunnel_parm parms = mlxsw_sp_ipip_netdev_parms4(ol_dev); 25662306a36Sopenharmony_ci enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci lb_ipipt = mlxsw_sp_ipip_parms4_has_okey(&parms) ? 25962306a36Sopenharmony_ci MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP : 26062306a36Sopenharmony_ci MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP; 26162306a36Sopenharmony_ci return (struct mlxsw_sp_rif_ipip_lb_config){ 26262306a36Sopenharmony_ci .lb_ipipt = lb_ipipt, 26362306a36Sopenharmony_ci .okey = mlxsw_sp_ipip_parms4_okey(&parms), 26462306a36Sopenharmony_ci .ul_protocol = MLXSW_SP_L3_PROTO_IPV4, 26562306a36Sopenharmony_ci .saddr = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4, 26662306a36Sopenharmony_ci ol_dev), 26762306a36Sopenharmony_ci }; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic int 27162306a36Sopenharmony_cimlxsw_sp_ipip_ol_netdev_change_gre(struct mlxsw_sp *mlxsw_sp, 27262306a36Sopenharmony_ci struct mlxsw_sp_ipip_entry *ipip_entry, 27362306a36Sopenharmony_ci const struct mlxsw_sp_ipip_parms *new_parms, 27462306a36Sopenharmony_ci struct netlink_ext_ack *extack) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci const struct mlxsw_sp_ipip_parms *old_parms = &ipip_entry->parms; 27762306a36Sopenharmony_ci bool update_tunnel = false; 27862306a36Sopenharmony_ci bool update_decap = false; 27962306a36Sopenharmony_ci bool update_nhs = false; 28062306a36Sopenharmony_ci int err = 0; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (!mlxsw_sp_l3addr_eq(&new_parms->saddr, &old_parms->saddr)) { 28362306a36Sopenharmony_ci u16 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry->ol_dev); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* Since the local address has changed, if there is another 28662306a36Sopenharmony_ci * tunnel with a matching saddr, both need to be demoted. 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_ci if (mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp, 28962306a36Sopenharmony_ci new_parms->proto, 29062306a36Sopenharmony_ci new_parms->saddr, 29162306a36Sopenharmony_ci ul_tb_id, 29262306a36Sopenharmony_ci ipip_entry)) { 29362306a36Sopenharmony_ci mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry); 29462306a36Sopenharmony_ci return 0; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci update_tunnel = true; 29862306a36Sopenharmony_ci } else if (old_parms->okey != new_parms->okey || 29962306a36Sopenharmony_ci old_parms->link != new_parms->link) { 30062306a36Sopenharmony_ci update_tunnel = true; 30162306a36Sopenharmony_ci } else if (!mlxsw_sp_l3addr_eq(&new_parms->daddr, &old_parms->daddr)) { 30262306a36Sopenharmony_ci update_nhs = true; 30362306a36Sopenharmony_ci } else if (old_parms->ikey != new_parms->ikey) { 30462306a36Sopenharmony_ci update_decap = true; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (update_tunnel) 30862306a36Sopenharmony_ci err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry, 30962306a36Sopenharmony_ci true, true, true, 31062306a36Sopenharmony_ci extack); 31162306a36Sopenharmony_ci else if (update_nhs) 31262306a36Sopenharmony_ci err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry, 31362306a36Sopenharmony_ci false, false, true, 31462306a36Sopenharmony_ci extack); 31562306a36Sopenharmony_ci else if (update_decap) 31662306a36Sopenharmony_ci err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry, 31762306a36Sopenharmony_ci false, false, false, 31862306a36Sopenharmony_ci extack); 31962306a36Sopenharmony_ci if (err) 32062306a36Sopenharmony_ci return err; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci ipip_entry->parms = *new_parms; 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic int 32762306a36Sopenharmony_cimlxsw_sp_ipip_ol_netdev_change_gre4(struct mlxsw_sp *mlxsw_sp, 32862306a36Sopenharmony_ci struct mlxsw_sp_ipip_entry *ipip_entry, 32962306a36Sopenharmony_ci struct netlink_ext_ack *extack) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct mlxsw_sp_ipip_parms new_parms; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci new_parms = mlxsw_sp_ipip_netdev_parms_init_gre4(ipip_entry->ol_dev); 33462306a36Sopenharmony_ci return mlxsw_sp_ipip_ol_netdev_change_gre(mlxsw_sp, ipip_entry, 33562306a36Sopenharmony_ci &new_parms, extack); 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic int 33962306a36Sopenharmony_cimlxsw_sp_ipip_rem_addr_set_gre4(struct mlxsw_sp *mlxsw_sp, 34062306a36Sopenharmony_ci struct mlxsw_sp_ipip_entry *ipip_entry) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci return 0; 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic void 34662306a36Sopenharmony_cimlxsw_sp_ipip_rem_addr_unset_gre4(struct mlxsw_sp *mlxsw_sp, 34762306a36Sopenharmony_ci const struct mlxsw_sp_ipip_entry *ipip_entry) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic const struct mlxsw_sp_ipip_ops mlxsw_sp_ipip_gre4_ops = { 35262306a36Sopenharmony_ci .dev_type = ARPHRD_IPGRE, 35362306a36Sopenharmony_ci .ul_proto = MLXSW_SP_L3_PROTO_IPV4, 35462306a36Sopenharmony_ci .inc_parsing_depth = false, 35562306a36Sopenharmony_ci .parms_init = mlxsw_sp_ipip_netdev_parms_init_gre4, 35662306a36Sopenharmony_ci .nexthop_update = mlxsw_sp_ipip_nexthop_update_gre4, 35762306a36Sopenharmony_ci .decap_config = mlxsw_sp_ipip_decap_config_gre4, 35862306a36Sopenharmony_ci .can_offload = mlxsw_sp_ipip_can_offload_gre4, 35962306a36Sopenharmony_ci .ol_loopback_config = mlxsw_sp_ipip_ol_loopback_config_gre4, 36062306a36Sopenharmony_ci .ol_netdev_change = mlxsw_sp_ipip_ol_netdev_change_gre4, 36162306a36Sopenharmony_ci .rem_ip_addr_set = mlxsw_sp_ipip_rem_addr_set_gre4, 36262306a36Sopenharmony_ci .rem_ip_addr_unset = mlxsw_sp_ipip_rem_addr_unset_gre4, 36362306a36Sopenharmony_ci}; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic struct mlxsw_sp_ipip_parms 36662306a36Sopenharmony_cimlxsw_sp_ipip_netdev_parms_init_gre6(const struct net_device *ol_dev) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct __ip6_tnl_parm parms = mlxsw_sp_ipip_netdev_parms6(ol_dev); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return (struct mlxsw_sp_ipip_parms) { 37162306a36Sopenharmony_ci .proto = MLXSW_SP_L3_PROTO_IPV6, 37262306a36Sopenharmony_ci .saddr = mlxsw_sp_ipip_parms6_saddr(&parms), 37362306a36Sopenharmony_ci .daddr = mlxsw_sp_ipip_parms6_daddr(&parms), 37462306a36Sopenharmony_ci .link = parms.link, 37562306a36Sopenharmony_ci .ikey = mlxsw_sp_ipip_parms6_ikey(&parms), 37662306a36Sopenharmony_ci .okey = mlxsw_sp_ipip_parms6_okey(&parms), 37762306a36Sopenharmony_ci }; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic int 38162306a36Sopenharmony_cimlxsw_sp_ipip_nexthop_update_gre6(struct mlxsw_sp *mlxsw_sp, u32 adj_index, 38262306a36Sopenharmony_ci struct mlxsw_sp_ipip_entry *ipip_entry, 38362306a36Sopenharmony_ci bool force, char *ratr_pl) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb); 38662306a36Sopenharmony_ci enum mlxsw_reg_ratr_op op; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci op = force ? MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY : 38962306a36Sopenharmony_ci MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY_ON_ACTIVITY; 39062306a36Sopenharmony_ci mlxsw_reg_ratr_pack(ratr_pl, op, true, MLXSW_REG_RATR_TYPE_IPIP, 39162306a36Sopenharmony_ci adj_index, rif_index); 39262306a36Sopenharmony_ci mlxsw_reg_ratr_ipip6_entry_pack(ratr_pl, 39362306a36Sopenharmony_ci ipip_entry->dip_kvdl_index); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl); 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic int 39962306a36Sopenharmony_cimlxsw_sp_ipip_decap_config_gre6(struct mlxsw_sp *mlxsw_sp, 40062306a36Sopenharmony_ci struct mlxsw_sp_ipip_entry *ipip_entry, 40162306a36Sopenharmony_ci u32 tunnel_index) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb); 40462306a36Sopenharmony_ci u16 ul_rif_id = mlxsw_sp_ipip_lb_ul_rif_id(ipip_entry->ol_lb); 40562306a36Sopenharmony_ci char rtdp_pl[MLXSW_REG_RTDP_LEN]; 40662306a36Sopenharmony_ci struct __ip6_tnl_parm parms; 40762306a36Sopenharmony_ci unsigned int type_check; 40862306a36Sopenharmony_ci bool has_ikey; 40962306a36Sopenharmony_ci u32 ikey; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci parms = mlxsw_sp_ipip_netdev_parms6(ipip_entry->ol_dev); 41262306a36Sopenharmony_ci has_ikey = mlxsw_sp_ipip_parms6_has_ikey(&parms); 41362306a36Sopenharmony_ci ikey = mlxsw_sp_ipip_parms6_ikey(&parms); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_IPIP, tunnel_index); 41662306a36Sopenharmony_ci mlxsw_reg_rtdp_egress_router_interface_set(rtdp_pl, ul_rif_id); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci type_check = has_ikey ? 41962306a36Sopenharmony_ci MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE_KEY : 42062306a36Sopenharmony_ci MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* Linux demuxes tunnels based on packet SIP (which must match tunnel 42362306a36Sopenharmony_ci * remote IP). Thus configure decap so that it filters out packets that 42462306a36Sopenharmony_ci * are not IPv6 or have the wrong SIP. IPIP_DECAP_ERROR trap is 42562306a36Sopenharmony_ci * generated for packets that fail this criterion. Linux then handles 42662306a36Sopenharmony_ci * such packets in slow path and generates ICMP destination unreachable. 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_ci mlxsw_reg_rtdp_ipip6_pack(rtdp_pl, rif_index, 42962306a36Sopenharmony_ci MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV6, 43062306a36Sopenharmony_ci type_check, has_ikey, 43162306a36Sopenharmony_ci ipip_entry->dip_kvdl_index, ikey); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), rtdp_pl); 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic bool mlxsw_sp_ipip_can_offload_gre6(const struct mlxsw_sp *mlxsw_sp, 43762306a36Sopenharmony_ci const struct net_device *ol_dev) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct __ip6_tnl_parm tparm = mlxsw_sp_ipip_netdev_parms6(ol_dev); 44062306a36Sopenharmony_ci bool inherit_tos = tparm.flags & IP6_TNL_F_USE_ORIG_TCLASS; 44162306a36Sopenharmony_ci bool inherit_ttl = tparm.hop_limit == 0; 44262306a36Sopenharmony_ci __be16 okflags = TUNNEL_KEY; /* We can't offload any other features. */ 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci return (tparm.i_flags & ~okflags) == 0 && 44562306a36Sopenharmony_ci (tparm.o_flags & ~okflags) == 0 && 44662306a36Sopenharmony_ci inherit_ttl && inherit_tos && 44762306a36Sopenharmony_ci mlxsw_sp_ipip_tunnel_complete(MLXSW_SP_L3_PROTO_IPV6, ol_dev); 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic struct mlxsw_sp_rif_ipip_lb_config 45162306a36Sopenharmony_cimlxsw_sp_ipip_ol_loopback_config_gre6(struct mlxsw_sp *mlxsw_sp, 45262306a36Sopenharmony_ci const struct net_device *ol_dev) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct __ip6_tnl_parm parms = mlxsw_sp_ipip_netdev_parms6(ol_dev); 45562306a36Sopenharmony_ci enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci lb_ipipt = mlxsw_sp_ipip_parms6_has_okey(&parms) ? 45862306a36Sopenharmony_ci MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP : 45962306a36Sopenharmony_ci MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP; 46062306a36Sopenharmony_ci return (struct mlxsw_sp_rif_ipip_lb_config){ 46162306a36Sopenharmony_ci .lb_ipipt = lb_ipipt, 46262306a36Sopenharmony_ci .okey = mlxsw_sp_ipip_parms6_okey(&parms), 46362306a36Sopenharmony_ci .ul_protocol = MLXSW_SP_L3_PROTO_IPV6, 46462306a36Sopenharmony_ci .saddr = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV6, 46562306a36Sopenharmony_ci ol_dev), 46662306a36Sopenharmony_ci }; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic int 47062306a36Sopenharmony_cimlxsw_sp_ipip_ol_netdev_change_gre6(struct mlxsw_sp *mlxsw_sp, 47162306a36Sopenharmony_ci struct mlxsw_sp_ipip_entry *ipip_entry, 47262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci struct mlxsw_sp_ipip_parms new_parms; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci new_parms = mlxsw_sp_ipip_netdev_parms_init_gre6(ipip_entry->ol_dev); 47762306a36Sopenharmony_ci return mlxsw_sp_ipip_ol_netdev_change_gre(mlxsw_sp, ipip_entry, 47862306a36Sopenharmony_ci &new_parms, extack); 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic int 48262306a36Sopenharmony_cimlxsw_sp_ipip_rem_addr_set_gre6(struct mlxsw_sp *mlxsw_sp, 48362306a36Sopenharmony_ci struct mlxsw_sp_ipip_entry *ipip_entry) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci return mlxsw_sp_ipv6_addr_kvdl_index_get(mlxsw_sp, 48662306a36Sopenharmony_ci &ipip_entry->parms.daddr.addr6, 48762306a36Sopenharmony_ci &ipip_entry->dip_kvdl_index); 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic void 49162306a36Sopenharmony_cimlxsw_sp_ipip_rem_addr_unset_gre6(struct mlxsw_sp *mlxsw_sp, 49262306a36Sopenharmony_ci const struct mlxsw_sp_ipip_entry *ipip_entry) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci mlxsw_sp_ipv6_addr_put(mlxsw_sp, &ipip_entry->parms.daddr.addr6); 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic const struct mlxsw_sp_ipip_ops mlxsw_sp1_ipip_gre6_ops = { 49862306a36Sopenharmony_ci .dev_type = ARPHRD_IP6GRE, 49962306a36Sopenharmony_ci .ul_proto = MLXSW_SP_L3_PROTO_IPV6, 50062306a36Sopenharmony_ci .inc_parsing_depth = true, 50162306a36Sopenharmony_ci .double_rif_entry = true, 50262306a36Sopenharmony_ci .parms_init = mlxsw_sp_ipip_netdev_parms_init_gre6, 50362306a36Sopenharmony_ci .nexthop_update = mlxsw_sp_ipip_nexthop_update_gre6, 50462306a36Sopenharmony_ci .decap_config = mlxsw_sp_ipip_decap_config_gre6, 50562306a36Sopenharmony_ci .can_offload = mlxsw_sp_ipip_can_offload_gre6, 50662306a36Sopenharmony_ci .ol_loopback_config = mlxsw_sp_ipip_ol_loopback_config_gre6, 50762306a36Sopenharmony_ci .ol_netdev_change = mlxsw_sp_ipip_ol_netdev_change_gre6, 50862306a36Sopenharmony_ci .rem_ip_addr_set = mlxsw_sp_ipip_rem_addr_set_gre6, 50962306a36Sopenharmony_ci .rem_ip_addr_unset = mlxsw_sp_ipip_rem_addr_unset_gre6, 51062306a36Sopenharmony_ci}; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ciconst struct mlxsw_sp_ipip_ops *mlxsw_sp1_ipip_ops_arr[] = { 51362306a36Sopenharmony_ci [MLXSW_SP_IPIP_TYPE_GRE4] = &mlxsw_sp_ipip_gre4_ops, 51462306a36Sopenharmony_ci [MLXSW_SP_IPIP_TYPE_GRE6] = &mlxsw_sp1_ipip_gre6_ops, 51562306a36Sopenharmony_ci}; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic const struct mlxsw_sp_ipip_ops mlxsw_sp2_ipip_gre6_ops = { 51862306a36Sopenharmony_ci .dev_type = ARPHRD_IP6GRE, 51962306a36Sopenharmony_ci .ul_proto = MLXSW_SP_L3_PROTO_IPV6, 52062306a36Sopenharmony_ci .inc_parsing_depth = true, 52162306a36Sopenharmony_ci .parms_init = mlxsw_sp_ipip_netdev_parms_init_gre6, 52262306a36Sopenharmony_ci .nexthop_update = mlxsw_sp_ipip_nexthop_update_gre6, 52362306a36Sopenharmony_ci .decap_config = mlxsw_sp_ipip_decap_config_gre6, 52462306a36Sopenharmony_ci .can_offload = mlxsw_sp_ipip_can_offload_gre6, 52562306a36Sopenharmony_ci .ol_loopback_config = mlxsw_sp_ipip_ol_loopback_config_gre6, 52662306a36Sopenharmony_ci .ol_netdev_change = mlxsw_sp_ipip_ol_netdev_change_gre6, 52762306a36Sopenharmony_ci .rem_ip_addr_set = mlxsw_sp_ipip_rem_addr_set_gre6, 52862306a36Sopenharmony_ci .rem_ip_addr_unset = mlxsw_sp_ipip_rem_addr_unset_gre6, 52962306a36Sopenharmony_ci}; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ciconst struct mlxsw_sp_ipip_ops *mlxsw_sp2_ipip_ops_arr[] = { 53262306a36Sopenharmony_ci [MLXSW_SP_IPIP_TYPE_GRE4] = &mlxsw_sp_ipip_gre4_ops, 53362306a36Sopenharmony_ci [MLXSW_SP_IPIP_TYPE_GRE6] = &mlxsw_sp2_ipip_gre6_ops, 53462306a36Sopenharmony_ci}; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic int mlxsw_sp_ipip_ecn_encap_init_one(struct mlxsw_sp *mlxsw_sp, 53762306a36Sopenharmony_ci u8 inner_ecn, u8 outer_ecn) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci char tieem_pl[MLXSW_REG_TIEEM_LEN]; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci mlxsw_reg_tieem_pack(tieem_pl, inner_ecn, outer_ecn); 54262306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tieem), tieem_pl); 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ciint mlxsw_sp_ipip_ecn_encap_init(struct mlxsw_sp *mlxsw_sp) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci int i; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci /* Iterate over inner ECN values */ 55062306a36Sopenharmony_ci for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) { 55162306a36Sopenharmony_ci u8 outer_ecn = INET_ECN_encapsulate(0, i); 55262306a36Sopenharmony_ci int err; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci err = mlxsw_sp_ipip_ecn_encap_init_one(mlxsw_sp, i, outer_ecn); 55562306a36Sopenharmony_ci if (err) 55662306a36Sopenharmony_ci return err; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci return 0; 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic int mlxsw_sp_ipip_ecn_decap_init_one(struct mlxsw_sp *mlxsw_sp, 56362306a36Sopenharmony_ci u8 inner_ecn, u8 outer_ecn) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci char tidem_pl[MLXSW_REG_TIDEM_LEN]; 56662306a36Sopenharmony_ci u8 new_inner_ecn; 56762306a36Sopenharmony_ci bool trap_en; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci new_inner_ecn = mlxsw_sp_tunnel_ecn_decap(outer_ecn, inner_ecn, 57062306a36Sopenharmony_ci &trap_en); 57162306a36Sopenharmony_ci mlxsw_reg_tidem_pack(tidem_pl, outer_ecn, inner_ecn, new_inner_ecn, 57262306a36Sopenharmony_ci trap_en, trap_en ? MLXSW_TRAP_ID_DECAP_ECN0 : 0); 57362306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tidem), tidem_pl); 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ciint mlxsw_sp_ipip_ecn_decap_init(struct mlxsw_sp *mlxsw_sp) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci int i, j, err; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* Iterate over inner ECN values */ 58162306a36Sopenharmony_ci for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) { 58262306a36Sopenharmony_ci /* Iterate over outer ECN values */ 58362306a36Sopenharmony_ci for (j = INET_ECN_NOT_ECT; j <= INET_ECN_CE; j++) { 58462306a36Sopenharmony_ci err = mlxsw_sp_ipip_ecn_decap_init_one(mlxsw_sp, i, j); 58562306a36Sopenharmony_ci if (err) 58662306a36Sopenharmony_ci return err; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return 0; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistruct net_device * 59462306a36Sopenharmony_cimlxsw_sp_ipip_netdev_ul_dev_get(const struct net_device *ol_dev) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci struct net *net = dev_net(ol_dev); 59762306a36Sopenharmony_ci struct ip_tunnel *tun4; 59862306a36Sopenharmony_ci struct ip6_tnl *tun6; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci switch (ol_dev->type) { 60162306a36Sopenharmony_ci case ARPHRD_IPGRE: 60262306a36Sopenharmony_ci tun4 = netdev_priv(ol_dev); 60362306a36Sopenharmony_ci return dev_get_by_index_rcu(net, tun4->parms.link); 60462306a36Sopenharmony_ci case ARPHRD_IP6GRE: 60562306a36Sopenharmony_ci tun6 = netdev_priv(ol_dev); 60662306a36Sopenharmony_ci return dev_get_by_index_rcu(net, tun6->parms.link); 60762306a36Sopenharmony_ci default: 60862306a36Sopenharmony_ci return NULL; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci} 611