18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <net/ip_tunnels.h> 58c2ecf20Sopenharmony_ci#include <net/ip6_tunnel.h> 68c2ecf20Sopenharmony_ci#include <net/inet_ecn.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "spectrum_ipip.h" 98c2ecf20Sopenharmony_ci#include "reg.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistruct ip_tunnel_parm 128c2ecf20Sopenharmony_cimlxsw_sp_ipip_netdev_parms4(const struct net_device *ol_dev) 138c2ecf20Sopenharmony_ci{ 148c2ecf20Sopenharmony_ci struct ip_tunnel *tun = netdev_priv(ol_dev); 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci return tun->parms; 178c2ecf20Sopenharmony_ci} 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistruct __ip6_tnl_parm 208c2ecf20Sopenharmony_cimlxsw_sp_ipip_netdev_parms6(const struct net_device *ol_dev) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci struct ip6_tnl *tun = netdev_priv(ol_dev); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci return tun->parms; 258c2ecf20Sopenharmony_ci} 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic bool mlxsw_sp_ipip_parms4_has_ikey(struct ip_tunnel_parm parms) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci return !!(parms.i_flags & TUNNEL_KEY); 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic bool mlxsw_sp_ipip_parms4_has_okey(struct ip_tunnel_parm parms) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci return !!(parms.o_flags & TUNNEL_KEY); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic u32 mlxsw_sp_ipip_parms4_ikey(struct ip_tunnel_parm parms) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci return mlxsw_sp_ipip_parms4_has_ikey(parms) ? 408c2ecf20Sopenharmony_ci be32_to_cpu(parms.i_key) : 0; 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic u32 mlxsw_sp_ipip_parms4_okey(struct ip_tunnel_parm parms) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci return mlxsw_sp_ipip_parms4_has_okey(parms) ? 468c2ecf20Sopenharmony_ci be32_to_cpu(parms.o_key) : 0; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic union mlxsw_sp_l3addr 508c2ecf20Sopenharmony_cimlxsw_sp_ipip_parms4_saddr(struct ip_tunnel_parm parms) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci return (union mlxsw_sp_l3addr) { .addr4 = parms.iph.saddr }; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic union mlxsw_sp_l3addr 568c2ecf20Sopenharmony_cimlxsw_sp_ipip_parms6_saddr(struct __ip6_tnl_parm parms) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci return (union mlxsw_sp_l3addr) { .addr6 = parms.laddr }; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic union mlxsw_sp_l3addr 628c2ecf20Sopenharmony_cimlxsw_sp_ipip_parms4_daddr(struct ip_tunnel_parm parms) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci return (union mlxsw_sp_l3addr) { .addr4 = parms.iph.daddr }; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic union mlxsw_sp_l3addr 688c2ecf20Sopenharmony_cimlxsw_sp_ipip_parms6_daddr(struct __ip6_tnl_parm parms) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci return (union mlxsw_sp_l3addr) { .addr6 = parms.raddr }; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciunion mlxsw_sp_l3addr 748c2ecf20Sopenharmony_cimlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto, 758c2ecf20Sopenharmony_ci const struct net_device *ol_dev) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci struct ip_tunnel_parm parms4; 788c2ecf20Sopenharmony_ci struct __ip6_tnl_parm parms6; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci switch (proto) { 818c2ecf20Sopenharmony_ci case MLXSW_SP_L3_PROTO_IPV4: 828c2ecf20Sopenharmony_ci parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev); 838c2ecf20Sopenharmony_ci return mlxsw_sp_ipip_parms4_saddr(parms4); 848c2ecf20Sopenharmony_ci case MLXSW_SP_L3_PROTO_IPV6: 858c2ecf20Sopenharmony_ci parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev); 868c2ecf20Sopenharmony_ci return mlxsw_sp_ipip_parms6_saddr(parms6); 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci WARN_ON(1); 908c2ecf20Sopenharmony_ci return (union mlxsw_sp_l3addr) {0}; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic __be32 mlxsw_sp_ipip_netdev_daddr4(const struct net_device *ol_dev) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci struct ip_tunnel_parm parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci return mlxsw_sp_ipip_parms4_daddr(parms4).addr4; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic union mlxsw_sp_l3addr 1028c2ecf20Sopenharmony_cimlxsw_sp_ipip_netdev_daddr(enum mlxsw_sp_l3proto proto, 1038c2ecf20Sopenharmony_ci const struct net_device *ol_dev) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct ip_tunnel_parm parms4; 1068c2ecf20Sopenharmony_ci struct __ip6_tnl_parm parms6; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci switch (proto) { 1098c2ecf20Sopenharmony_ci case MLXSW_SP_L3_PROTO_IPV4: 1108c2ecf20Sopenharmony_ci parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev); 1118c2ecf20Sopenharmony_ci return mlxsw_sp_ipip_parms4_daddr(parms4); 1128c2ecf20Sopenharmony_ci case MLXSW_SP_L3_PROTO_IPV6: 1138c2ecf20Sopenharmony_ci parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev); 1148c2ecf20Sopenharmony_ci return mlxsw_sp_ipip_parms6_daddr(parms6); 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci WARN_ON(1); 1188c2ecf20Sopenharmony_ci return (union mlxsw_sp_l3addr) {0}; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cibool mlxsw_sp_l3addr_is_zero(union mlxsw_sp_l3addr addr) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci union mlxsw_sp_l3addr naddr = {0}; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return !memcmp(&addr, &naddr, sizeof(naddr)); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic int 1298c2ecf20Sopenharmony_cimlxsw_sp_ipip_nexthop_update_gre4(struct mlxsw_sp *mlxsw_sp, u32 adj_index, 1308c2ecf20Sopenharmony_ci struct mlxsw_sp_ipip_entry *ipip_entry) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb); 1338c2ecf20Sopenharmony_ci __be32 daddr4 = mlxsw_sp_ipip_netdev_daddr4(ipip_entry->ol_dev); 1348c2ecf20Sopenharmony_ci char ratr_pl[MLXSW_REG_RATR_LEN]; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci mlxsw_reg_ratr_pack(ratr_pl, MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY, 1378c2ecf20Sopenharmony_ci true, MLXSW_REG_RATR_TYPE_IPIP, 1388c2ecf20Sopenharmony_ci adj_index, rif_index); 1398c2ecf20Sopenharmony_ci mlxsw_reg_ratr_ipip4_entry_pack(ratr_pl, be32_to_cpu(daddr4)); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ratr), ratr_pl); 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic int 1458c2ecf20Sopenharmony_cimlxsw_sp_ipip_fib_entry_op_gre4_rtdp(struct mlxsw_sp *mlxsw_sp, 1468c2ecf20Sopenharmony_ci u32 tunnel_index, 1478c2ecf20Sopenharmony_ci struct mlxsw_sp_ipip_entry *ipip_entry) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci u16 rif_index = mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb); 1508c2ecf20Sopenharmony_ci u16 ul_rif_id = mlxsw_sp_ipip_lb_ul_rif_id(ipip_entry->ol_lb); 1518c2ecf20Sopenharmony_ci char rtdp_pl[MLXSW_REG_RTDP_LEN]; 1528c2ecf20Sopenharmony_ci struct ip_tunnel_parm parms; 1538c2ecf20Sopenharmony_ci unsigned int type_check; 1548c2ecf20Sopenharmony_ci bool has_ikey; 1558c2ecf20Sopenharmony_ci u32 daddr4; 1568c2ecf20Sopenharmony_ci u32 ikey; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci parms = mlxsw_sp_ipip_netdev_parms4(ipip_entry->ol_dev); 1598c2ecf20Sopenharmony_ci has_ikey = mlxsw_sp_ipip_parms4_has_ikey(parms); 1608c2ecf20Sopenharmony_ci ikey = mlxsw_sp_ipip_parms4_ikey(parms); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci mlxsw_reg_rtdp_pack(rtdp_pl, MLXSW_REG_RTDP_TYPE_IPIP, tunnel_index); 1638c2ecf20Sopenharmony_ci mlxsw_reg_rtdp_egress_router_interface_set(rtdp_pl, ul_rif_id); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci type_check = has_ikey ? 1668c2ecf20Sopenharmony_ci MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE_KEY : 1678c2ecf20Sopenharmony_ci MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* Linux demuxes tunnels based on packet SIP (which must match tunnel 1708c2ecf20Sopenharmony_ci * remote IP). Thus configure decap so that it filters out packets that 1718c2ecf20Sopenharmony_ci * are not IPv4 or have the wrong SIP. IPIP_DECAP_ERROR trap is 1728c2ecf20Sopenharmony_ci * generated for packets that fail this criterion. Linux then handles 1738c2ecf20Sopenharmony_ci * such packets in slow path and generates ICMP destination unreachable. 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci daddr4 = be32_to_cpu(mlxsw_sp_ipip_netdev_daddr4(ipip_entry->ol_dev)); 1768c2ecf20Sopenharmony_ci mlxsw_reg_rtdp_ipip4_pack(rtdp_pl, rif_index, 1778c2ecf20Sopenharmony_ci MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV4, 1788c2ecf20Sopenharmony_ci type_check, has_ikey, daddr4, ikey); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtdp), rtdp_pl); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic int 1848c2ecf20Sopenharmony_cimlxsw_sp_ipip_fib_entry_op_gre4_ralue(struct mlxsw_sp *mlxsw_sp, 1858c2ecf20Sopenharmony_ci u32 dip, u8 prefix_len, u16 ul_vr_id, 1868c2ecf20Sopenharmony_ci enum mlxsw_reg_ralue_op op, 1878c2ecf20Sopenharmony_ci u32 tunnel_index) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci char ralue_pl[MLXSW_REG_RALUE_LEN]; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci mlxsw_reg_ralue_pack4(ralue_pl, MLXSW_REG_RALXX_PROTOCOL_IPV4, op, 1928c2ecf20Sopenharmony_ci ul_vr_id, prefix_len, dip); 1938c2ecf20Sopenharmony_ci mlxsw_reg_ralue_act_ip2me_tun_pack(ralue_pl, tunnel_index); 1948c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ralue), ralue_pl); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic int mlxsw_sp_ipip_fib_entry_op_gre4(struct mlxsw_sp *mlxsw_sp, 1988c2ecf20Sopenharmony_ci struct mlxsw_sp_ipip_entry *ipip_entry, 1998c2ecf20Sopenharmony_ci enum mlxsw_reg_ralue_op op, 2008c2ecf20Sopenharmony_ci u32 tunnel_index) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci u16 ul_vr_id = mlxsw_sp_ipip_lb_ul_vr_id(ipip_entry->ol_lb); 2038c2ecf20Sopenharmony_ci __be32 dip; 2048c2ecf20Sopenharmony_ci int err; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci err = mlxsw_sp_ipip_fib_entry_op_gre4_rtdp(mlxsw_sp, tunnel_index, 2078c2ecf20Sopenharmony_ci ipip_entry); 2088c2ecf20Sopenharmony_ci if (err) 2098c2ecf20Sopenharmony_ci return err; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci dip = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4, 2128c2ecf20Sopenharmony_ci ipip_entry->ol_dev).addr4; 2138c2ecf20Sopenharmony_ci return mlxsw_sp_ipip_fib_entry_op_gre4_ralue(mlxsw_sp, be32_to_cpu(dip), 2148c2ecf20Sopenharmony_ci 32, ul_vr_id, op, 2158c2ecf20Sopenharmony_ci tunnel_index); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic bool mlxsw_sp_ipip_tunnel_complete(enum mlxsw_sp_l3proto proto, 2198c2ecf20Sopenharmony_ci const struct net_device *ol_dev) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci union mlxsw_sp_l3addr saddr = mlxsw_sp_ipip_netdev_saddr(proto, ol_dev); 2228c2ecf20Sopenharmony_ci union mlxsw_sp_l3addr daddr = mlxsw_sp_ipip_netdev_daddr(proto, ol_dev); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* Tunnels with unset local or remote address are valid in Linux and 2258c2ecf20Sopenharmony_ci * used for lightweight tunnels (LWT) and Non-Broadcast Multi-Access 2268c2ecf20Sopenharmony_ci * (NBMA) tunnels. In principle these can be offloaded, but the driver 2278c2ecf20Sopenharmony_ci * currently doesn't support this. So punt. 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_ci return !mlxsw_sp_l3addr_is_zero(saddr) && 2308c2ecf20Sopenharmony_ci !mlxsw_sp_l3addr_is_zero(daddr); 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic bool mlxsw_sp_ipip_can_offload_gre4(const struct mlxsw_sp *mlxsw_sp, 2348c2ecf20Sopenharmony_ci const struct net_device *ol_dev, 2358c2ecf20Sopenharmony_ci enum mlxsw_sp_l3proto ol_proto) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct ip_tunnel *tunnel = netdev_priv(ol_dev); 2388c2ecf20Sopenharmony_ci __be16 okflags = TUNNEL_KEY; /* We can't offload any other features. */ 2398c2ecf20Sopenharmony_ci bool inherit_ttl = tunnel->parms.iph.ttl == 0; 2408c2ecf20Sopenharmony_ci bool inherit_tos = tunnel->parms.iph.tos & 0x1; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci return (tunnel->parms.i_flags & ~okflags) == 0 && 2438c2ecf20Sopenharmony_ci (tunnel->parms.o_flags & ~okflags) == 0 && 2448c2ecf20Sopenharmony_ci inherit_ttl && inherit_tos && 2458c2ecf20Sopenharmony_ci mlxsw_sp_ipip_tunnel_complete(MLXSW_SP_L3_PROTO_IPV4, ol_dev); 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic struct mlxsw_sp_rif_ipip_lb_config 2498c2ecf20Sopenharmony_cimlxsw_sp_ipip_ol_loopback_config_gre4(struct mlxsw_sp *mlxsw_sp, 2508c2ecf20Sopenharmony_ci const struct net_device *ol_dev) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct ip_tunnel_parm parms = mlxsw_sp_ipip_netdev_parms4(ol_dev); 2538c2ecf20Sopenharmony_ci enum mlxsw_reg_ritr_loopback_ipip_type lb_ipipt; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci lb_ipipt = mlxsw_sp_ipip_parms4_has_okey(parms) ? 2568c2ecf20Sopenharmony_ci MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP : 2578c2ecf20Sopenharmony_ci MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP; 2588c2ecf20Sopenharmony_ci return (struct mlxsw_sp_rif_ipip_lb_config){ 2598c2ecf20Sopenharmony_ci .lb_ipipt = lb_ipipt, 2608c2ecf20Sopenharmony_ci .okey = mlxsw_sp_ipip_parms4_okey(parms), 2618c2ecf20Sopenharmony_ci .ul_protocol = MLXSW_SP_L3_PROTO_IPV4, 2628c2ecf20Sopenharmony_ci .saddr = mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4, 2638c2ecf20Sopenharmony_ci ol_dev), 2648c2ecf20Sopenharmony_ci }; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic int 2688c2ecf20Sopenharmony_cimlxsw_sp_ipip_ol_netdev_change_gre4(struct mlxsw_sp *mlxsw_sp, 2698c2ecf20Sopenharmony_ci struct mlxsw_sp_ipip_entry *ipip_entry, 2708c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci union mlxsw_sp_l3addr old_saddr, new_saddr; 2738c2ecf20Sopenharmony_ci union mlxsw_sp_l3addr old_daddr, new_daddr; 2748c2ecf20Sopenharmony_ci struct ip_tunnel_parm new_parms; 2758c2ecf20Sopenharmony_ci bool update_tunnel = false; 2768c2ecf20Sopenharmony_ci bool update_decap = false; 2778c2ecf20Sopenharmony_ci bool update_nhs = false; 2788c2ecf20Sopenharmony_ci int err = 0; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci new_parms = mlxsw_sp_ipip_netdev_parms4(ipip_entry->ol_dev); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci new_saddr = mlxsw_sp_ipip_parms4_saddr(new_parms); 2838c2ecf20Sopenharmony_ci old_saddr = mlxsw_sp_ipip_parms4_saddr(ipip_entry->parms4); 2848c2ecf20Sopenharmony_ci new_daddr = mlxsw_sp_ipip_parms4_daddr(new_parms); 2858c2ecf20Sopenharmony_ci old_daddr = mlxsw_sp_ipip_parms4_daddr(ipip_entry->parms4); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (!mlxsw_sp_l3addr_eq(&new_saddr, &old_saddr)) { 2888c2ecf20Sopenharmony_ci u16 ul_tb_id = mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry->ol_dev); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* Since the local address has changed, if there is another 2918c2ecf20Sopenharmony_ci * tunnel with a matching saddr, both need to be demoted. 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci if (mlxsw_sp_ipip_demote_tunnel_by_saddr(mlxsw_sp, 2948c2ecf20Sopenharmony_ci MLXSW_SP_L3_PROTO_IPV4, 2958c2ecf20Sopenharmony_ci new_saddr, ul_tb_id, 2968c2ecf20Sopenharmony_ci ipip_entry)) { 2978c2ecf20Sopenharmony_ci mlxsw_sp_ipip_entry_demote_tunnel(mlxsw_sp, ipip_entry); 2988c2ecf20Sopenharmony_ci return 0; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci update_tunnel = true; 3028c2ecf20Sopenharmony_ci } else if ((mlxsw_sp_ipip_parms4_okey(ipip_entry->parms4) != 3038c2ecf20Sopenharmony_ci mlxsw_sp_ipip_parms4_okey(new_parms)) || 3048c2ecf20Sopenharmony_ci ipip_entry->parms4.link != new_parms.link) { 3058c2ecf20Sopenharmony_ci update_tunnel = true; 3068c2ecf20Sopenharmony_ci } else if (!mlxsw_sp_l3addr_eq(&new_daddr, &old_daddr)) { 3078c2ecf20Sopenharmony_ci update_nhs = true; 3088c2ecf20Sopenharmony_ci } else if (mlxsw_sp_ipip_parms4_ikey(ipip_entry->parms4) != 3098c2ecf20Sopenharmony_ci mlxsw_sp_ipip_parms4_ikey(new_parms)) { 3108c2ecf20Sopenharmony_ci update_decap = true; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (update_tunnel) 3148c2ecf20Sopenharmony_ci err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry, 3158c2ecf20Sopenharmony_ci true, true, true, 3168c2ecf20Sopenharmony_ci extack); 3178c2ecf20Sopenharmony_ci else if (update_nhs) 3188c2ecf20Sopenharmony_ci err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry, 3198c2ecf20Sopenharmony_ci false, false, true, 3208c2ecf20Sopenharmony_ci extack); 3218c2ecf20Sopenharmony_ci else if (update_decap) 3228c2ecf20Sopenharmony_ci err = __mlxsw_sp_ipip_entry_update_tunnel(mlxsw_sp, ipip_entry, 3238c2ecf20Sopenharmony_ci false, false, false, 3248c2ecf20Sopenharmony_ci extack); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci ipip_entry->parms4 = new_parms; 3278c2ecf20Sopenharmony_ci return err; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_ipip_ops mlxsw_sp_ipip_gre4_ops = { 3318c2ecf20Sopenharmony_ci .dev_type = ARPHRD_IPGRE, 3328c2ecf20Sopenharmony_ci .ul_proto = MLXSW_SP_L3_PROTO_IPV4, 3338c2ecf20Sopenharmony_ci .nexthop_update = mlxsw_sp_ipip_nexthop_update_gre4, 3348c2ecf20Sopenharmony_ci .fib_entry_op = mlxsw_sp_ipip_fib_entry_op_gre4, 3358c2ecf20Sopenharmony_ci .can_offload = mlxsw_sp_ipip_can_offload_gre4, 3368c2ecf20Sopenharmony_ci .ol_loopback_config = mlxsw_sp_ipip_ol_loopback_config_gre4, 3378c2ecf20Sopenharmony_ci .ol_netdev_change = mlxsw_sp_ipip_ol_netdev_change_gre4, 3388c2ecf20Sopenharmony_ci}; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ciconst struct mlxsw_sp_ipip_ops *mlxsw_sp_ipip_ops_arr[] = { 3418c2ecf20Sopenharmony_ci [MLXSW_SP_IPIP_TYPE_GRE4] = &mlxsw_sp_ipip_gre4_ops, 3428c2ecf20Sopenharmony_ci}; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic int mlxsw_sp_ipip_ecn_encap_init_one(struct mlxsw_sp *mlxsw_sp, 3458c2ecf20Sopenharmony_ci u8 inner_ecn, u8 outer_ecn) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci char tieem_pl[MLXSW_REG_TIEEM_LEN]; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci mlxsw_reg_tieem_pack(tieem_pl, inner_ecn, outer_ecn); 3508c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tieem), tieem_pl); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ciint mlxsw_sp_ipip_ecn_encap_init(struct mlxsw_sp *mlxsw_sp) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci int i; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Iterate over inner ECN values */ 3588c2ecf20Sopenharmony_ci for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) { 3598c2ecf20Sopenharmony_ci u8 outer_ecn = INET_ECN_encapsulate(0, i); 3608c2ecf20Sopenharmony_ci int err; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci err = mlxsw_sp_ipip_ecn_encap_init_one(mlxsw_sp, i, outer_ecn); 3638c2ecf20Sopenharmony_ci if (err) 3648c2ecf20Sopenharmony_ci return err; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int mlxsw_sp_ipip_ecn_decap_init_one(struct mlxsw_sp *mlxsw_sp, 3718c2ecf20Sopenharmony_ci u8 inner_ecn, u8 outer_ecn) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci char tidem_pl[MLXSW_REG_TIDEM_LEN]; 3748c2ecf20Sopenharmony_ci u8 new_inner_ecn; 3758c2ecf20Sopenharmony_ci bool trap_en; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci new_inner_ecn = mlxsw_sp_tunnel_ecn_decap(outer_ecn, inner_ecn, 3788c2ecf20Sopenharmony_ci &trap_en); 3798c2ecf20Sopenharmony_ci mlxsw_reg_tidem_pack(tidem_pl, outer_ecn, inner_ecn, new_inner_ecn, 3808c2ecf20Sopenharmony_ci trap_en, trap_en ? MLXSW_TRAP_ID_DECAP_ECN0 : 0); 3818c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(tidem), tidem_pl); 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ciint mlxsw_sp_ipip_ecn_decap_init(struct mlxsw_sp *mlxsw_sp) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci int i, j, err; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* Iterate over inner ECN values */ 3898c2ecf20Sopenharmony_ci for (i = INET_ECN_NOT_ECT; i <= INET_ECN_CE; i++) { 3908c2ecf20Sopenharmony_ci /* Iterate over outer ECN values */ 3918c2ecf20Sopenharmony_ci for (j = INET_ECN_NOT_ECT; j <= INET_ECN_CE; j++) { 3928c2ecf20Sopenharmony_ci err = mlxsw_sp_ipip_ecn_decap_init_one(mlxsw_sp, i, j); 3938c2ecf20Sopenharmony_ci if (err) 3948c2ecf20Sopenharmony_ci return err; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return 0; 3998c2ecf20Sopenharmony_ci} 400