brintos

brintos / linux-shallow public Read only

0
0
Text · 19.3 KiB · 7ea798a Raw
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