1b4da4235SEdward Cree // SPDX-License-Identifier: GPL-2.0-only
2b4da4235SEdward Cree /****************************************************************************
3b4da4235SEdward Cree  * Driver for Solarflare network controllers and boards
4b4da4235SEdward Cree  * Copyright 2023, Advanced Micro Devices, Inc.
5b4da4235SEdward Cree  *
6b4da4235SEdward Cree  * This program is free software; you can redistribute it and/or modify it
7b4da4235SEdward Cree  * under the terms of the GNU General Public License version 2 as published
8b4da4235SEdward Cree  * by the Free Software Foundation, incorporated herein by reference.
9b4da4235SEdward Cree  */
10b4da4235SEdward Cree 
11b4da4235SEdward Cree #include "tc_encap_actions.h"
12b4da4235SEdward Cree #include "tc.h"
13b4da4235SEdward Cree #include "mae.h"
14b4da4235SEdward Cree #include <net/vxlan.h>
15b4da4235SEdward Cree #include <net/geneve.h>
167e5e7d80SEdward Cree #include <net/netevent.h>
177e5e7d80SEdward Cree #include <net/arp.h>
187e5e7d80SEdward Cree 
197e5e7d80SEdward Cree static const struct rhashtable_params efx_neigh_ht_params = {
207e5e7d80SEdward Cree 	.key_len	= offsetof(struct efx_neigh_binder, ha),
217e5e7d80SEdward Cree 	.key_offset	= 0,
227e5e7d80SEdward Cree 	.head_offset	= offsetof(struct efx_neigh_binder, linkage),
237e5e7d80SEdward Cree };
24b4da4235SEdward Cree 
25b4da4235SEdward Cree static const struct rhashtable_params efx_tc_encap_ht_params = {
26b4da4235SEdward Cree 	.key_len	= offsetofend(struct efx_tc_encap_action, key),
27b4da4235SEdward Cree 	.key_offset	= 0,
28b4da4235SEdward Cree 	.head_offset	= offsetof(struct efx_tc_encap_action, linkage),
29b4da4235SEdward Cree };
30b4da4235SEdward Cree 
efx_tc_encap_free(void * ptr,void * __unused)31b4da4235SEdward Cree static void efx_tc_encap_free(void *ptr, void *__unused)
32b4da4235SEdward Cree {
33b4da4235SEdward Cree 	struct efx_tc_encap_action *enc = ptr;
34b4da4235SEdward Cree 
35b4da4235SEdward Cree 	WARN_ON(refcount_read(&enc->ref));
36b4da4235SEdward Cree 	kfree(enc);
37b4da4235SEdward Cree }
38b4da4235SEdward Cree 
efx_neigh_free(void * ptr,void * __unused)397e5e7d80SEdward Cree static void efx_neigh_free(void *ptr, void *__unused)
407e5e7d80SEdward Cree {
417e5e7d80SEdward Cree 	struct efx_neigh_binder *neigh = ptr;
427e5e7d80SEdward Cree 
437e5e7d80SEdward Cree 	WARN_ON(refcount_read(&neigh->ref));
447e5e7d80SEdward Cree 	WARN_ON(!list_empty(&neigh->users));
457e5e7d80SEdward Cree 	put_net_track(neigh->net, &neigh->ns_tracker);
467e5e7d80SEdward Cree 	netdev_put(neigh->egdev, &neigh->dev_tracker);
477e5e7d80SEdward Cree 	kfree(neigh);
487e5e7d80SEdward Cree }
497e5e7d80SEdward Cree 
efx_tc_init_encap_actions(struct efx_nic * efx)50b4da4235SEdward Cree int efx_tc_init_encap_actions(struct efx_nic *efx)
51b4da4235SEdward Cree {
527e5e7d80SEdward Cree 	int rc;
537e5e7d80SEdward Cree 
547e5e7d80SEdward Cree 	rc = rhashtable_init(&efx->tc->neigh_ht, &efx_neigh_ht_params);
557e5e7d80SEdward Cree 	if (rc < 0)
567e5e7d80SEdward Cree 		goto fail_neigh_ht;
577e5e7d80SEdward Cree 	rc = rhashtable_init(&efx->tc->encap_ht, &efx_tc_encap_ht_params);
587e5e7d80SEdward Cree 	if (rc < 0)
597e5e7d80SEdward Cree 		goto fail_encap_ht;
607e5e7d80SEdward Cree 	return 0;
617e5e7d80SEdward Cree fail_encap_ht:
627e5e7d80SEdward Cree 	rhashtable_destroy(&efx->tc->neigh_ht);
637e5e7d80SEdward Cree fail_neigh_ht:
647e5e7d80SEdward Cree 	return rc;
65b4da4235SEdward Cree }
66b4da4235SEdward Cree 
67b4da4235SEdward Cree /* Only call this in init failure teardown.
68b4da4235SEdward Cree  * Normal exit should fini instead as there may be entries in the table.
69b4da4235SEdward Cree  */
efx_tc_destroy_encap_actions(struct efx_nic * efx)70b4da4235SEdward Cree void efx_tc_destroy_encap_actions(struct efx_nic *efx)
71b4da4235SEdward Cree {
72b4da4235SEdward Cree 	rhashtable_destroy(&efx->tc->encap_ht);
737e5e7d80SEdward Cree 	rhashtable_destroy(&efx->tc->neigh_ht);
74b4da4235SEdward Cree }
75b4da4235SEdward Cree 
efx_tc_fini_encap_actions(struct efx_nic * efx)76b4da4235SEdward Cree void efx_tc_fini_encap_actions(struct efx_nic *efx)
77b4da4235SEdward Cree {
78b4da4235SEdward Cree 	rhashtable_free_and_destroy(&efx->tc->encap_ht, efx_tc_encap_free, NULL);
797e5e7d80SEdward Cree 	rhashtable_free_and_destroy(&efx->tc->neigh_ht, efx_neigh_free, NULL);
807e5e7d80SEdward Cree }
817e5e7d80SEdward Cree 
827e5e7d80SEdward Cree static void efx_neigh_update(struct work_struct *work);
837e5e7d80SEdward Cree 
efx_bind_neigh(struct efx_nic * efx,struct efx_tc_encap_action * encap,struct net * net,struct netlink_ext_ack * extack)847e5e7d80SEdward Cree static int efx_bind_neigh(struct efx_nic *efx,
857e5e7d80SEdward Cree 			  struct efx_tc_encap_action *encap, struct net *net,
867e5e7d80SEdward Cree 			  struct netlink_ext_ack *extack)
877e5e7d80SEdward Cree {
887e5e7d80SEdward Cree 	struct efx_neigh_binder *neigh, *old;
897e5e7d80SEdward Cree 	struct flowi6 flow6 = {};
907e5e7d80SEdward Cree 	struct flowi4 flow4 = {};
917e5e7d80SEdward Cree 	int rc;
927e5e7d80SEdward Cree 
937e5e7d80SEdward Cree 	/* GCC stupidly thinks that only values explicitly listed in the enum
947e5e7d80SEdward Cree 	 * definition can _possibly_ be sensible case values, so without this
957e5e7d80SEdward Cree 	 * cast it complains about the IPv6 versions.
967e5e7d80SEdward Cree 	 */
977e5e7d80SEdward Cree 	switch ((int)encap->type) {
987e5e7d80SEdward Cree 	case EFX_ENCAP_TYPE_VXLAN:
997e5e7d80SEdward Cree 	case EFX_ENCAP_TYPE_GENEVE:
1007e5e7d80SEdward Cree 		flow4.flowi4_proto = IPPROTO_UDP;
1017e5e7d80SEdward Cree 		flow4.fl4_dport = encap->key.tp_dst;
1027e5e7d80SEdward Cree 		flow4.flowi4_tos = encap->key.tos;
1037e5e7d80SEdward Cree 		flow4.daddr = encap->key.u.ipv4.dst;
1047e5e7d80SEdward Cree 		flow4.saddr = encap->key.u.ipv4.src;
1057e5e7d80SEdward Cree 		break;
1067e5e7d80SEdward Cree 	case EFX_ENCAP_TYPE_VXLAN | EFX_ENCAP_FLAG_IPV6:
1077e5e7d80SEdward Cree 	case EFX_ENCAP_TYPE_GENEVE | EFX_ENCAP_FLAG_IPV6:
1087e5e7d80SEdward Cree 		flow6.flowi6_proto = IPPROTO_UDP;
1097e5e7d80SEdward Cree 		flow6.fl6_dport = encap->key.tp_dst;
1107e5e7d80SEdward Cree 		flow6.flowlabel = ip6_make_flowinfo(encap->key.tos,
1117e5e7d80SEdward Cree 						    encap->key.label);
1127e5e7d80SEdward Cree 		flow6.daddr = encap->key.u.ipv6.dst;
1137e5e7d80SEdward Cree 		flow6.saddr = encap->key.u.ipv6.src;
1147e5e7d80SEdward Cree 		break;
1157e5e7d80SEdward Cree 	default:
1167e5e7d80SEdward Cree 		NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported encap type %d",
1177e5e7d80SEdward Cree 				       (int)encap->type);
1187e5e7d80SEdward Cree 		return -EOPNOTSUPP;
1197e5e7d80SEdward Cree 	}
1207e5e7d80SEdward Cree 
1217e5e7d80SEdward Cree 	neigh = kzalloc(sizeof(*neigh), GFP_KERNEL_ACCOUNT);
1227e5e7d80SEdward Cree 	if (!neigh)
1237e5e7d80SEdward Cree 		return -ENOMEM;
1247e5e7d80SEdward Cree 	neigh->net = get_net_track(net, &neigh->ns_tracker, GFP_KERNEL_ACCOUNT);
1257e5e7d80SEdward Cree 	neigh->dst_ip = flow4.daddr;
1267e5e7d80SEdward Cree 	neigh->dst_ip6 = flow6.daddr;
1277e5e7d80SEdward Cree 
1287e5e7d80SEdward Cree 	old = rhashtable_lookup_get_insert_fast(&efx->tc->neigh_ht,
1297e5e7d80SEdward Cree 						&neigh->linkage,
1307e5e7d80SEdward Cree 						efx_neigh_ht_params);
1317e5e7d80SEdward Cree 	if (old) {
1327e5e7d80SEdward Cree 		/* don't need our new entry */
1337e5e7d80SEdward Cree 		put_net_track(neigh->net, &neigh->ns_tracker);
1347e5e7d80SEdward Cree 		kfree(neigh);
135*fc21f083SEdward Cree 		if (IS_ERR(old)) /* oh dear, it's actually an error */
136*fc21f083SEdward Cree 			return PTR_ERR(old);
1377e5e7d80SEdward Cree 		if (!refcount_inc_not_zero(&old->ref))
1387e5e7d80SEdward Cree 			return -EAGAIN;
1397e5e7d80SEdward Cree 		/* existing entry found, ref taken */
1407e5e7d80SEdward Cree 		neigh = old;
1417e5e7d80SEdward Cree 	} else {
1427e5e7d80SEdward Cree 		/* New entry.  We need to initiate a lookup */
1437e5e7d80SEdward Cree 		struct neighbour *n;
1447e5e7d80SEdward Cree 		struct rtable *rt;
1457e5e7d80SEdward Cree 
1467e5e7d80SEdward Cree 		if (encap->type & EFX_ENCAP_FLAG_IPV6) {
1477e5e7d80SEdward Cree #if IS_ENABLED(CONFIG_IPV6)
1487e5e7d80SEdward Cree 			struct dst_entry *dst;
1497e5e7d80SEdward Cree 
1507e5e7d80SEdward Cree 			dst = ipv6_stub->ipv6_dst_lookup_flow(net, NULL, &flow6,
1517e5e7d80SEdward Cree 							      NULL);
1527e5e7d80SEdward Cree 			rc = PTR_ERR_OR_ZERO(dst);
1537e5e7d80SEdward Cree 			if (rc) {
1547e5e7d80SEdward Cree 				NL_SET_ERR_MSG_MOD(extack, "Failed to lookup route for IPv6 encap");
1557e5e7d80SEdward Cree 				goto out_free;
1567e5e7d80SEdward Cree 			}
1577e5e7d80SEdward Cree 			neigh->egdev = dst->dev;
1587e5e7d80SEdward Cree 			netdev_hold(neigh->egdev, &neigh->dev_tracker,
1597e5e7d80SEdward Cree 				    GFP_KERNEL_ACCOUNT);
1607e5e7d80SEdward Cree 			neigh->ttl = ip6_dst_hoplimit(dst);
1617e5e7d80SEdward Cree 			n = dst_neigh_lookup(dst, &flow6.daddr);
1627e5e7d80SEdward Cree 			dst_release(dst);
1637e5e7d80SEdward Cree #else
1647e5e7d80SEdward Cree 			/* We shouldn't ever get here, because if IPv6 isn't
1657e5e7d80SEdward Cree 			 * enabled how did someone create an IPv6 tunnel_key?
1667e5e7d80SEdward Cree 			 */
1677e5e7d80SEdward Cree 			rc = -EOPNOTSUPP;
1687e5e7d80SEdward Cree 			NL_SET_ERR_MSG_MOD(extack, "No IPv6 support (neigh bind)");
169f61d2d5cSArnd Bergmann 			goto out_free;
1707e5e7d80SEdward Cree #endif
1717e5e7d80SEdward Cree 		} else {
1727e5e7d80SEdward Cree 			rt = ip_route_output_key(net, &flow4);
1737e5e7d80SEdward Cree 			if (IS_ERR_OR_NULL(rt)) {
1747e5e7d80SEdward Cree 				rc = PTR_ERR_OR_ZERO(rt);
1757e5e7d80SEdward Cree 				if (!rc)
1767e5e7d80SEdward Cree 					rc = -EIO;
1777e5e7d80SEdward Cree 				NL_SET_ERR_MSG_MOD(extack, "Failed to lookup route for encap");
1787e5e7d80SEdward Cree 				goto out_free;
1797e5e7d80SEdward Cree 			}
1807e5e7d80SEdward Cree 			neigh->egdev = rt->dst.dev;
1817e5e7d80SEdward Cree 			netdev_hold(neigh->egdev, &neigh->dev_tracker,
1827e5e7d80SEdward Cree 				    GFP_KERNEL_ACCOUNT);
1837e5e7d80SEdward Cree 			neigh->ttl = ip4_dst_hoplimit(&rt->dst);
1847e5e7d80SEdward Cree 			n = dst_neigh_lookup(&rt->dst, &flow4.daddr);
1857e5e7d80SEdward Cree 			ip_rt_put(rt);
1867e5e7d80SEdward Cree 		}
1877e5e7d80SEdward Cree 		if (!n) {
1887e5e7d80SEdward Cree 			rc = -ENETUNREACH;
1897e5e7d80SEdward Cree 			NL_SET_ERR_MSG_MOD(extack, "Failed to lookup neighbour for encap");
1907e5e7d80SEdward Cree 			netdev_put(neigh->egdev, &neigh->dev_tracker);
1917e5e7d80SEdward Cree 			goto out_free;
1927e5e7d80SEdward Cree 		}
1937e5e7d80SEdward Cree 		refcount_set(&neigh->ref, 1);
1947e5e7d80SEdward Cree 		INIT_LIST_HEAD(&neigh->users);
1957e5e7d80SEdward Cree 		read_lock_bh(&n->lock);
1967e5e7d80SEdward Cree 		ether_addr_copy(neigh->ha, n->ha);
1977e5e7d80SEdward Cree 		neigh->n_valid = n->nud_state & NUD_VALID;
1987e5e7d80SEdward Cree 		read_unlock_bh(&n->lock);
1997e5e7d80SEdward Cree 		rwlock_init(&neigh->lock);
2007e5e7d80SEdward Cree 		INIT_WORK(&neigh->work, efx_neigh_update);
2017e5e7d80SEdward Cree 		neigh->efx = efx;
2027e5e7d80SEdward Cree 		neigh->used = jiffies;
2037e5e7d80SEdward Cree 		if (!neigh->n_valid)
2047e5e7d80SEdward Cree 			/* Prod ARP to find us a neighbour */
2057e5e7d80SEdward Cree 			neigh_event_send(n, NULL);
2067e5e7d80SEdward Cree 		neigh_release(n);
2077e5e7d80SEdward Cree 	}
2087e5e7d80SEdward Cree 	/* Add us to this neigh */
2097e5e7d80SEdward Cree 	encap->neigh = neigh;
2107e5e7d80SEdward Cree 	list_add_tail(&encap->list, &neigh->users);
2117e5e7d80SEdward Cree 	return 0;
2127e5e7d80SEdward Cree 
2137e5e7d80SEdward Cree out_free:
2147e5e7d80SEdward Cree 	/* cleanup common to several error paths */
2157e5e7d80SEdward Cree 	rhashtable_remove_fast(&efx->tc->neigh_ht, &neigh->linkage,
2167e5e7d80SEdward Cree 			       efx_neigh_ht_params);
2177e5e7d80SEdward Cree 	synchronize_rcu();
2187e5e7d80SEdward Cree 	put_net_track(net, &neigh->ns_tracker);
2197e5e7d80SEdward Cree 	kfree(neigh);
2207e5e7d80SEdward Cree 	return rc;
2217e5e7d80SEdward Cree }
2227e5e7d80SEdward Cree 
efx_free_neigh(struct efx_neigh_binder * neigh)2237e5e7d80SEdward Cree static void efx_free_neigh(struct efx_neigh_binder *neigh)
2247e5e7d80SEdward Cree {
2257e5e7d80SEdward Cree 	struct efx_nic *efx = neigh->efx;
2267e5e7d80SEdward Cree 
2277e5e7d80SEdward Cree 	rhashtable_remove_fast(&efx->tc->neigh_ht, &neigh->linkage,
2287e5e7d80SEdward Cree 			       efx_neigh_ht_params);
2297e5e7d80SEdward Cree 	synchronize_rcu();
2307e5e7d80SEdward Cree 	netdev_put(neigh->egdev, &neigh->dev_tracker);
2317e5e7d80SEdward Cree 	put_net_track(neigh->net, &neigh->ns_tracker);
2327e5e7d80SEdward Cree 	kfree(neigh);
2337e5e7d80SEdward Cree }
2347e5e7d80SEdward Cree 
efx_release_neigh(struct efx_nic * efx,struct efx_tc_encap_action * encap)2357e5e7d80SEdward Cree static void efx_release_neigh(struct efx_nic *efx,
2367e5e7d80SEdward Cree 			      struct efx_tc_encap_action *encap)
2377e5e7d80SEdward Cree {
2387e5e7d80SEdward Cree 	struct efx_neigh_binder *neigh = encap->neigh;
2397e5e7d80SEdward Cree 
2407e5e7d80SEdward Cree 	if (!neigh)
2417e5e7d80SEdward Cree 		return;
2427e5e7d80SEdward Cree 	list_del(&encap->list);
2437e5e7d80SEdward Cree 	encap->neigh = NULL;
2447e5e7d80SEdward Cree 	if (!refcount_dec_and_test(&neigh->ref))
2457e5e7d80SEdward Cree 		return; /* still in use */
2467e5e7d80SEdward Cree 	efx_free_neigh(neigh);
2477e5e7d80SEdward Cree }
2487e5e7d80SEdward Cree 
efx_gen_tun_header_eth(struct efx_tc_encap_action * encap,u16 proto)249a1e82162SEdward Cree static void efx_gen_tun_header_eth(struct efx_tc_encap_action *encap, u16 proto)
2507e5e7d80SEdward Cree {
251a1e82162SEdward Cree 	struct efx_neigh_binder *neigh = encap->neigh;
252a1e82162SEdward Cree 	struct ethhdr *eth;
253a1e82162SEdward Cree 
254a1e82162SEdward Cree 	encap->encap_hdr_len = sizeof(*eth);
255a1e82162SEdward Cree 	eth = (struct ethhdr *)encap->encap_hdr;
256a1e82162SEdward Cree 
257a1e82162SEdward Cree 	if (encap->neigh->n_valid)
258a1e82162SEdward Cree 		ether_addr_copy(eth->h_dest, neigh->ha);
259a1e82162SEdward Cree 	else
260a1e82162SEdward Cree 		eth_zero_addr(eth->h_dest);
261a1e82162SEdward Cree 	ether_addr_copy(eth->h_source, neigh->egdev->dev_addr);
262a1e82162SEdward Cree 	eth->h_proto = htons(proto);
263a1e82162SEdward Cree }
264a1e82162SEdward Cree 
efx_gen_tun_header_ipv4(struct efx_tc_encap_action * encap,u8 ipproto,u8 len)265a1e82162SEdward Cree static void efx_gen_tun_header_ipv4(struct efx_tc_encap_action *encap, u8 ipproto, u8 len)
266a1e82162SEdward Cree {
267a1e82162SEdward Cree 	struct efx_neigh_binder *neigh = encap->neigh;
268a1e82162SEdward Cree 	struct ip_tunnel_key *key = &encap->key;
269a1e82162SEdward Cree 	struct iphdr *ip;
270a1e82162SEdward Cree 
271a1e82162SEdward Cree 	ip = (struct iphdr *)(encap->encap_hdr + encap->encap_hdr_len);
272a1e82162SEdward Cree 	encap->encap_hdr_len += sizeof(*ip);
273a1e82162SEdward Cree 
274a1e82162SEdward Cree 	ip->daddr = key->u.ipv4.dst;
275a1e82162SEdward Cree 	ip->saddr = key->u.ipv4.src;
276a1e82162SEdward Cree 	ip->ttl = neigh->ttl;
277a1e82162SEdward Cree 	ip->protocol = ipproto;
278a1e82162SEdward Cree 	ip->version = 0x4;
279a1e82162SEdward Cree 	ip->ihl = 0x5;
280a1e82162SEdward Cree 	ip->tot_len = cpu_to_be16(ip->ihl * 4 + len);
281a1e82162SEdward Cree 	ip_send_check(ip);
282a1e82162SEdward Cree }
283a1e82162SEdward Cree 
284a1e82162SEdward Cree #ifdef CONFIG_IPV6
efx_gen_tun_header_ipv6(struct efx_tc_encap_action * encap,u8 ipproto,u8 len)285a1e82162SEdward Cree static void efx_gen_tun_header_ipv6(struct efx_tc_encap_action *encap, u8 ipproto, u8 len)
286a1e82162SEdward Cree {
287a1e82162SEdward Cree 	struct efx_neigh_binder *neigh = encap->neigh;
288a1e82162SEdward Cree 	struct ip_tunnel_key *key = &encap->key;
289a1e82162SEdward Cree 	struct ipv6hdr *ip;
290a1e82162SEdward Cree 
291a1e82162SEdward Cree 	ip = (struct ipv6hdr *)(encap->encap_hdr + encap->encap_hdr_len);
292a1e82162SEdward Cree 	encap->encap_hdr_len += sizeof(*ip);
293a1e82162SEdward Cree 
294a1e82162SEdward Cree 	ip6_flow_hdr(ip, key->tos, key->label);
295a1e82162SEdward Cree 	ip->daddr = key->u.ipv6.dst;
296a1e82162SEdward Cree 	ip->saddr = key->u.ipv6.src;
297a1e82162SEdward Cree 	ip->hop_limit = neigh->ttl;
298a1e82162SEdward Cree 	ip->nexthdr = ipproto;
299a1e82162SEdward Cree 	ip->version = 0x6;
300a1e82162SEdward Cree 	ip->payload_len = cpu_to_be16(len);
301a1e82162SEdward Cree }
302a1e82162SEdward Cree #endif
303a1e82162SEdward Cree 
efx_gen_tun_header_udp(struct efx_tc_encap_action * encap,u8 len)304a1e82162SEdward Cree static void efx_gen_tun_header_udp(struct efx_tc_encap_action *encap, u8 len)
305a1e82162SEdward Cree {
306a1e82162SEdward Cree 	struct ip_tunnel_key *key = &encap->key;
307a1e82162SEdward Cree 	struct udphdr *udp;
308a1e82162SEdward Cree 
309a1e82162SEdward Cree 	udp = (struct udphdr *)(encap->encap_hdr + encap->encap_hdr_len);
310a1e82162SEdward Cree 	encap->encap_hdr_len += sizeof(*udp);
311a1e82162SEdward Cree 
312a1e82162SEdward Cree 	udp->dest = key->tp_dst;
313a1e82162SEdward Cree 	udp->len = cpu_to_be16(sizeof(*udp) + len);
314a1e82162SEdward Cree }
315a1e82162SEdward Cree 
efx_gen_tun_header_vxlan(struct efx_tc_encap_action * encap)316a1e82162SEdward Cree static void efx_gen_tun_header_vxlan(struct efx_tc_encap_action *encap)
317a1e82162SEdward Cree {
318a1e82162SEdward Cree 	struct ip_tunnel_key *key = &encap->key;
319a1e82162SEdward Cree 	struct vxlanhdr *vxlan;
320a1e82162SEdward Cree 
321a1e82162SEdward Cree 	vxlan = (struct vxlanhdr *)(encap->encap_hdr + encap->encap_hdr_len);
322a1e82162SEdward Cree 	encap->encap_hdr_len += sizeof(*vxlan);
323a1e82162SEdward Cree 
324a1e82162SEdward Cree 	vxlan->vx_flags = VXLAN_HF_VNI;
325a1e82162SEdward Cree 	vxlan->vx_vni = vxlan_vni_field(tunnel_id_to_key32(key->tun_id));
326a1e82162SEdward Cree }
327a1e82162SEdward Cree 
efx_gen_tun_header_geneve(struct efx_tc_encap_action * encap)328a1e82162SEdward Cree static void efx_gen_tun_header_geneve(struct efx_tc_encap_action *encap)
329a1e82162SEdward Cree {
330a1e82162SEdward Cree 	struct ip_tunnel_key *key = &encap->key;
331a1e82162SEdward Cree 	struct genevehdr *geneve;
332a1e82162SEdward Cree 	u32 vni;
333a1e82162SEdward Cree 
334a1e82162SEdward Cree 	geneve = (struct genevehdr *)(encap->encap_hdr + encap->encap_hdr_len);
335a1e82162SEdward Cree 	encap->encap_hdr_len += sizeof(*geneve);
336a1e82162SEdward Cree 
337a1e82162SEdward Cree 	geneve->proto_type = htons(ETH_P_TEB);
338a1e82162SEdward Cree 	/* convert tun_id to host-endian so we can use host arithmetic to
339a1e82162SEdward Cree 	 * extract individual bytes.
340a1e82162SEdward Cree 	 */
341a1e82162SEdward Cree 	vni = ntohl(tunnel_id_to_key32(key->tun_id));
342a1e82162SEdward Cree 	geneve->vni[0] = vni >> 16;
343a1e82162SEdward Cree 	geneve->vni[1] = vni >> 8;
344a1e82162SEdward Cree 	geneve->vni[2] = vni;
345a1e82162SEdward Cree }
346a1e82162SEdward Cree 
347a1e82162SEdward Cree #define vxlan_header_l4_len	(sizeof(struct udphdr) + sizeof(struct vxlanhdr))
348a1e82162SEdward Cree #define vxlan4_header_len	(sizeof(struct ethhdr) + sizeof(struct iphdr) + vxlan_header_l4_len)
efx_gen_vxlan_header_ipv4(struct efx_tc_encap_action * encap)349a1e82162SEdward Cree static void efx_gen_vxlan_header_ipv4(struct efx_tc_encap_action *encap)
350a1e82162SEdward Cree {
351a1e82162SEdward Cree 	BUILD_BUG_ON(sizeof(encap->encap_hdr) < vxlan4_header_len);
352a1e82162SEdward Cree 	efx_gen_tun_header_eth(encap, ETH_P_IP);
353a1e82162SEdward Cree 	efx_gen_tun_header_ipv4(encap, IPPROTO_UDP, vxlan_header_l4_len);
354a1e82162SEdward Cree 	efx_gen_tun_header_udp(encap, sizeof(struct vxlanhdr));
355a1e82162SEdward Cree 	efx_gen_tun_header_vxlan(encap);
356a1e82162SEdward Cree }
357a1e82162SEdward Cree 
358a1e82162SEdward Cree #define geneve_header_l4_len	(sizeof(struct udphdr) + sizeof(struct genevehdr))
359a1e82162SEdward Cree #define geneve4_header_len	(sizeof(struct ethhdr) + sizeof(struct iphdr) + geneve_header_l4_len)
efx_gen_geneve_header_ipv4(struct efx_tc_encap_action * encap)360a1e82162SEdward Cree static void efx_gen_geneve_header_ipv4(struct efx_tc_encap_action *encap)
361a1e82162SEdward Cree {
362a1e82162SEdward Cree 	BUILD_BUG_ON(sizeof(encap->encap_hdr) < geneve4_header_len);
363a1e82162SEdward Cree 	efx_gen_tun_header_eth(encap, ETH_P_IP);
364a1e82162SEdward Cree 	efx_gen_tun_header_ipv4(encap, IPPROTO_UDP, geneve_header_l4_len);
365a1e82162SEdward Cree 	efx_gen_tun_header_udp(encap, sizeof(struct genevehdr));
366a1e82162SEdward Cree 	efx_gen_tun_header_geneve(encap);
367a1e82162SEdward Cree }
368a1e82162SEdward Cree 
369a1e82162SEdward Cree #ifdef CONFIG_IPV6
370a1e82162SEdward Cree #define vxlan6_header_len	(sizeof(struct ethhdr) + sizeof(struct ipv6hdr) + vxlan_header_l4_len)
efx_gen_vxlan_header_ipv6(struct efx_tc_encap_action * encap)371a1e82162SEdward Cree static void efx_gen_vxlan_header_ipv6(struct efx_tc_encap_action *encap)
372a1e82162SEdward Cree {
373a1e82162SEdward Cree 	BUILD_BUG_ON(sizeof(encap->encap_hdr) < vxlan6_header_len);
374a1e82162SEdward Cree 	efx_gen_tun_header_eth(encap, ETH_P_IPV6);
375a1e82162SEdward Cree 	efx_gen_tun_header_ipv6(encap, IPPROTO_UDP, vxlan_header_l4_len);
376a1e82162SEdward Cree 	efx_gen_tun_header_udp(encap, sizeof(struct vxlanhdr));
377a1e82162SEdward Cree 	efx_gen_tun_header_vxlan(encap);
378a1e82162SEdward Cree }
379a1e82162SEdward Cree 
380a1e82162SEdward Cree #define geneve6_header_len	(sizeof(struct ethhdr) + sizeof(struct ipv6hdr) + geneve_header_l4_len)
efx_gen_geneve_header_ipv6(struct efx_tc_encap_action * encap)381a1e82162SEdward Cree static void efx_gen_geneve_header_ipv6(struct efx_tc_encap_action *encap)
382a1e82162SEdward Cree {
383a1e82162SEdward Cree 	BUILD_BUG_ON(sizeof(encap->encap_hdr) < geneve6_header_len);
384a1e82162SEdward Cree 	efx_gen_tun_header_eth(encap, ETH_P_IPV6);
385a1e82162SEdward Cree 	efx_gen_tun_header_ipv6(encap, IPPROTO_UDP, geneve_header_l4_len);
386a1e82162SEdward Cree 	efx_gen_tun_header_udp(encap, sizeof(struct genevehdr));
387a1e82162SEdward Cree 	efx_gen_tun_header_geneve(encap);
388a1e82162SEdward Cree }
389a1e82162SEdward Cree #endif
390a1e82162SEdward Cree 
efx_gen_encap_header(struct efx_nic * efx,struct efx_tc_encap_action * encap)391a1e82162SEdward Cree static void efx_gen_encap_header(struct efx_nic *efx,
392a1e82162SEdward Cree 				 struct efx_tc_encap_action *encap)
393a1e82162SEdward Cree {
394a1e82162SEdward Cree 	encap->n_valid = encap->neigh->n_valid;
395a1e82162SEdward Cree 
396a1e82162SEdward Cree 	/* GCC stupidly thinks that only values explicitly listed in the enum
397a1e82162SEdward Cree 	 * definition can _possibly_ be sensible case values, so without this
398a1e82162SEdward Cree 	 * cast it complains about the IPv6 versions.
399a1e82162SEdward Cree 	 */
400a1e82162SEdward Cree 	switch ((int)encap->type) {
401a1e82162SEdward Cree 	case EFX_ENCAP_TYPE_VXLAN:
402a1e82162SEdward Cree 		efx_gen_vxlan_header_ipv4(encap);
403a1e82162SEdward Cree 		break;
404a1e82162SEdward Cree 	case EFX_ENCAP_TYPE_GENEVE:
405a1e82162SEdward Cree 		efx_gen_geneve_header_ipv4(encap);
406a1e82162SEdward Cree 		break;
407a1e82162SEdward Cree #ifdef CONFIG_IPV6
408a1e82162SEdward Cree 	case EFX_ENCAP_TYPE_VXLAN | EFX_ENCAP_FLAG_IPV6:
409a1e82162SEdward Cree 		efx_gen_vxlan_header_ipv6(encap);
410a1e82162SEdward Cree 		break;
411a1e82162SEdward Cree 	case EFX_ENCAP_TYPE_GENEVE | EFX_ENCAP_FLAG_IPV6:
412a1e82162SEdward Cree 		efx_gen_geneve_header_ipv6(encap);
413a1e82162SEdward Cree 		break;
414a1e82162SEdward Cree #endif
415a1e82162SEdward Cree 	default:
416a1e82162SEdward Cree 		/* unhandled encap type, can't happen */
417a1e82162SEdward Cree 		if (net_ratelimit())
418a1e82162SEdward Cree 			netif_err(efx, drv, efx->net_dev,
419a1e82162SEdward Cree 				  "Bogus encap type %d, can't generate\n",
420a1e82162SEdward Cree 				  encap->type);
421a1e82162SEdward Cree 
422a1e82162SEdward Cree 		/* Use fallback action. */
4237e5e7d80SEdward Cree 		encap->n_valid = false;
424a1e82162SEdward Cree 		break;
425a1e82162SEdward Cree 	}
4267e5e7d80SEdward Cree }
4277e5e7d80SEdward Cree 
efx_tc_update_encap(struct efx_nic * efx,struct efx_tc_encap_action * encap)4287e5e7d80SEdward Cree static void efx_tc_update_encap(struct efx_nic *efx,
4297e5e7d80SEdward Cree 				struct efx_tc_encap_action *encap)
4307e5e7d80SEdward Cree {
4317e5e7d80SEdward Cree 	struct efx_tc_action_set_list *acts, *fallback;
4327e5e7d80SEdward Cree 	struct efx_tc_flow_rule *rule;
4337e5e7d80SEdward Cree 	struct efx_tc_action_set *act;
4347e5e7d80SEdward Cree 	int rc;
4357e5e7d80SEdward Cree 
4367e5e7d80SEdward Cree 	if (encap->n_valid) {
4377e5e7d80SEdward Cree 		/* Make sure no rules are using this encap while we change it */
4387e5e7d80SEdward Cree 		list_for_each_entry(act, &encap->users, encap_user) {
4397e5e7d80SEdward Cree 			acts = act->user;
4407e5e7d80SEdward Cree 			if (WARN_ON(!acts)) /* can't happen */
4417e5e7d80SEdward Cree 				continue;
4427e5e7d80SEdward Cree 			rule = container_of(acts, struct efx_tc_flow_rule, acts);
4437e5e7d80SEdward Cree 			if (rule->fallback)
4447e5e7d80SEdward Cree 				fallback = rule->fallback;
4457e5e7d80SEdward Cree 			else /* fallback fallback: deliver to PF */
4467e5e7d80SEdward Cree 				fallback = &efx->tc->facts.pf;
4477e5e7d80SEdward Cree 			rc = efx_mae_update_rule(efx, fallback->fw_id,
4487e5e7d80SEdward Cree 						 rule->fw_id);
4497e5e7d80SEdward Cree 			if (rc)
4507e5e7d80SEdward Cree 				netif_err(efx, drv, efx->net_dev,
4517e5e7d80SEdward Cree 					  "Failed to update (f) rule %08x rc %d\n",
4527e5e7d80SEdward Cree 					  rule->fw_id, rc);
4537e5e7d80SEdward Cree 			else
4547e5e7d80SEdward Cree 				netif_dbg(efx, drv, efx->net_dev, "Updated (f) rule %08x\n",
4557e5e7d80SEdward Cree 					  rule->fw_id);
4567e5e7d80SEdward Cree 		}
4577e5e7d80SEdward Cree 	}
4587e5e7d80SEdward Cree 
459a1e82162SEdward Cree 	/* Make sure we don't leak arbitrary bytes on the wire;
460a1e82162SEdward Cree 	 * set an all-0s ethernet header.  A successful call to
461a1e82162SEdward Cree 	 * efx_gen_encap_header() will overwrite this.
462a1e82162SEdward Cree 	 */
463a1e82162SEdward Cree 	memset(encap->encap_hdr, 0, sizeof(encap->encap_hdr));
464a1e82162SEdward Cree 	encap->encap_hdr_len = ETH_HLEN;
465a1e82162SEdward Cree 
4667e5e7d80SEdward Cree 	if (encap->neigh) {
4677e5e7d80SEdward Cree 		read_lock_bh(&encap->neigh->lock);
468a1e82162SEdward Cree 		efx_gen_encap_header(efx, encap);
4697e5e7d80SEdward Cree 		read_unlock_bh(&encap->neigh->lock);
4707e5e7d80SEdward Cree 	} else {
4717e5e7d80SEdward Cree 		encap->n_valid = false;
4727e5e7d80SEdward Cree 	}
4737e5e7d80SEdward Cree 
4747e5e7d80SEdward Cree 	rc = efx_mae_update_encap_md(efx, encap);
4757e5e7d80SEdward Cree 	if (rc) {
4767e5e7d80SEdward Cree 		netif_err(efx, drv, efx->net_dev,
4777e5e7d80SEdward Cree 			  "Failed to update encap hdr %08x rc %d\n",
4787e5e7d80SEdward Cree 			  encap->fw_id, rc);
4797e5e7d80SEdward Cree 		return;
4807e5e7d80SEdward Cree 	}
4817e5e7d80SEdward Cree 	netif_dbg(efx, drv, efx->net_dev, "Updated encap hdr %08x\n",
4827e5e7d80SEdward Cree 		  encap->fw_id);
4837e5e7d80SEdward Cree 	if (!encap->n_valid)
4847e5e7d80SEdward Cree 		return;
4857e5e7d80SEdward Cree 	/* Update rule users: use the action if they are now ready */
4867e5e7d80SEdward Cree 	list_for_each_entry(act, &encap->users, encap_user) {
4877e5e7d80SEdward Cree 		acts = act->user;
4887e5e7d80SEdward Cree 		if (WARN_ON(!acts)) /* can't happen */
4897e5e7d80SEdward Cree 			continue;
4907e5e7d80SEdward Cree 		rule = container_of(acts, struct efx_tc_flow_rule, acts);
4917e5e7d80SEdward Cree 		if (!efx_tc_check_ready(efx, rule))
4927e5e7d80SEdward Cree 			continue;
4937e5e7d80SEdward Cree 		rc = efx_mae_update_rule(efx, acts->fw_id, rule->fw_id);
4947e5e7d80SEdward Cree 		if (rc)
4957e5e7d80SEdward Cree 			netif_err(efx, drv, efx->net_dev,
4967e5e7d80SEdward Cree 				  "Failed to update rule %08x rc %d\n",
4977e5e7d80SEdward Cree 				  rule->fw_id, rc);
4987e5e7d80SEdward Cree 		else
4997e5e7d80SEdward Cree 			netif_dbg(efx, drv, efx->net_dev, "Updated rule %08x\n",
5007e5e7d80SEdward Cree 				  rule->fw_id);
5017e5e7d80SEdward Cree 	}
5027e5e7d80SEdward Cree }
5037e5e7d80SEdward Cree 
efx_neigh_update(struct work_struct * work)5047e5e7d80SEdward Cree static void efx_neigh_update(struct work_struct *work)
5057e5e7d80SEdward Cree {
5067e5e7d80SEdward Cree 	struct efx_neigh_binder *neigh = container_of(work, struct efx_neigh_binder, work);
5077e5e7d80SEdward Cree 	struct efx_tc_encap_action *encap;
5087e5e7d80SEdward Cree 	struct efx_nic *efx = neigh->efx;
5097e5e7d80SEdward Cree 
5107e5e7d80SEdward Cree 	mutex_lock(&efx->tc->mutex);
5117e5e7d80SEdward Cree 	list_for_each_entry(encap, &neigh->users, list)
5127e5e7d80SEdward Cree 		efx_tc_update_encap(neigh->efx, encap);
5137e5e7d80SEdward Cree 	/* release ref taken in efx_neigh_event() */
5147e5e7d80SEdward Cree 	if (refcount_dec_and_test(&neigh->ref))
5157e5e7d80SEdward Cree 		efx_free_neigh(neigh);
5167e5e7d80SEdward Cree 	mutex_unlock(&efx->tc->mutex);
5177e5e7d80SEdward Cree }
5187e5e7d80SEdward Cree 
efx_neigh_event(struct efx_nic * efx,struct neighbour * n)5197e5e7d80SEdward Cree static int efx_neigh_event(struct efx_nic *efx, struct neighbour *n)
5207e5e7d80SEdward Cree {
5217e5e7d80SEdward Cree 	struct efx_neigh_binder keys = {NULL}, *neigh;
5227e5e7d80SEdward Cree 	bool n_valid, ipv6 = false;
5237e5e7d80SEdward Cree 	char ha[ETH_ALEN];
5247e5e7d80SEdward Cree 	size_t keysize;
5257e5e7d80SEdward Cree 
5267e5e7d80SEdward Cree 	if (WARN_ON(!efx->tc))
5277e5e7d80SEdward Cree 		return NOTIFY_DONE;
5287e5e7d80SEdward Cree 
5297e5e7d80SEdward Cree 	if (n->tbl == &arp_tbl) {
5307e5e7d80SEdward Cree 		keysize = sizeof(keys.dst_ip);
5317e5e7d80SEdward Cree #if IS_ENABLED(CONFIG_IPV6)
5327e5e7d80SEdward Cree 	} else if (n->tbl == ipv6_stub->nd_tbl) {
5337e5e7d80SEdward Cree 		ipv6 = true;
5347e5e7d80SEdward Cree 		keysize = sizeof(keys.dst_ip6);
5357e5e7d80SEdward Cree #endif
5367e5e7d80SEdward Cree 	} else {
5377e5e7d80SEdward Cree 		return NOTIFY_DONE;
5387e5e7d80SEdward Cree 	}
5397e5e7d80SEdward Cree 	if (!n->parms) {
5407e5e7d80SEdward Cree 		netif_warn(efx, drv, efx->net_dev, "neigh_event with no parms!\n");
5417e5e7d80SEdward Cree 		return NOTIFY_DONE;
5427e5e7d80SEdward Cree 	}
5437e5e7d80SEdward Cree 	keys.net = read_pnet(&n->parms->net);
5447e5e7d80SEdward Cree 	if (n->tbl->key_len != keysize) {
5457e5e7d80SEdward Cree 		netif_warn(efx, drv, efx->net_dev, "neigh_event with bad key_len %u\n",
5467e5e7d80SEdward Cree 			   n->tbl->key_len);
5477e5e7d80SEdward Cree 		return NOTIFY_DONE;
5487e5e7d80SEdward Cree 	}
5497e5e7d80SEdward Cree 	read_lock_bh(&n->lock); /* Get a consistent view */
5507e5e7d80SEdward Cree 	memcpy(ha, n->ha, ETH_ALEN);
5517e5e7d80SEdward Cree 	n_valid = (n->nud_state & NUD_VALID) && !n->dead;
5527e5e7d80SEdward Cree 	read_unlock_bh(&n->lock);
5537e5e7d80SEdward Cree 	if (ipv6)
5547e5e7d80SEdward Cree 		memcpy(&keys.dst_ip6, n->primary_key, n->tbl->key_len);
5557e5e7d80SEdward Cree 	else
5567e5e7d80SEdward Cree 		memcpy(&keys.dst_ip, n->primary_key, n->tbl->key_len);
5577e5e7d80SEdward Cree 	rcu_read_lock();
5587e5e7d80SEdward Cree 	neigh = rhashtable_lookup_fast(&efx->tc->neigh_ht, &keys,
5597e5e7d80SEdward Cree 				       efx_neigh_ht_params);
5607e5e7d80SEdward Cree 	if (!neigh || neigh->dying)
5617e5e7d80SEdward Cree 		/* We're not interested in this neighbour */
5627e5e7d80SEdward Cree 		goto done;
5637e5e7d80SEdward Cree 	write_lock_bh(&neigh->lock);
5647e5e7d80SEdward Cree 	if (n_valid == neigh->n_valid && !memcmp(ha, neigh->ha, ETH_ALEN)) {
5657e5e7d80SEdward Cree 		write_unlock_bh(&neigh->lock);
5667e5e7d80SEdward Cree 		/* Nothing has changed; no work to do */
5677e5e7d80SEdward Cree 		goto done;
5687e5e7d80SEdward Cree 	}
5697e5e7d80SEdward Cree 	neigh->n_valid = n_valid;
5707e5e7d80SEdward Cree 	memcpy(neigh->ha, ha, ETH_ALEN);
5717e5e7d80SEdward Cree 	write_unlock_bh(&neigh->lock);
5727e5e7d80SEdward Cree 	if (refcount_inc_not_zero(&neigh->ref)) {
5737e5e7d80SEdward Cree 		rcu_read_unlock();
5747e5e7d80SEdward Cree 		if (!schedule_work(&neigh->work))
5757e5e7d80SEdward Cree 			/* failed to schedule, release the ref we just took */
5767e5e7d80SEdward Cree 			if (refcount_dec_and_test(&neigh->ref))
5777e5e7d80SEdward Cree 				efx_free_neigh(neigh);
5787e5e7d80SEdward Cree 	} else {
5797e5e7d80SEdward Cree done:
5807e5e7d80SEdward Cree 		rcu_read_unlock();
5817e5e7d80SEdward Cree 	}
5827e5e7d80SEdward Cree 	return NOTIFY_DONE;
583b4da4235SEdward Cree }
584b4da4235SEdward Cree 
efx_tc_check_ready(struct efx_nic * efx,struct efx_tc_flow_rule * rule)585b4da4235SEdward Cree bool efx_tc_check_ready(struct efx_nic *efx, struct efx_tc_flow_rule *rule)
586b4da4235SEdward Cree {
587b4da4235SEdward Cree 	struct efx_tc_action_set *act;
588b4da4235SEdward Cree 
589b4da4235SEdward Cree 	/* Encap actions can only be offloaded if they have valid
590b4da4235SEdward Cree 	 * neighbour info for the outer Ethernet header.
591b4da4235SEdward Cree 	 */
592b4da4235SEdward Cree 	list_for_each_entry(act, &rule->acts.list, list)
5937e5e7d80SEdward Cree 		if (act->encap_md && !act->encap_md->n_valid)
594b4da4235SEdward Cree 			return false;
595b4da4235SEdward Cree 	return true;
596b4da4235SEdward Cree }
597b4da4235SEdward Cree 
efx_tc_flower_create_encap_md(struct efx_nic * efx,const struct ip_tunnel_info * info,struct net_device * egdev,struct netlink_ext_ack * extack)598b4da4235SEdward Cree struct efx_tc_encap_action *efx_tc_flower_create_encap_md(
599b4da4235SEdward Cree 			struct efx_nic *efx, const struct ip_tunnel_info *info,
600b4da4235SEdward Cree 			struct net_device *egdev, struct netlink_ext_ack *extack)
601b4da4235SEdward Cree {
602b4da4235SEdward Cree 	enum efx_encap_type type = efx_tc_indr_netdev_type(egdev);
603b4da4235SEdward Cree 	struct efx_tc_encap_action *encap, *old;
6047e5e7d80SEdward Cree 	struct efx_rep *to_efv;
605b4da4235SEdward Cree 	s64 rc;
606b4da4235SEdward Cree 
607b4da4235SEdward Cree 	if (type == EFX_ENCAP_TYPE_NONE) {
608b4da4235SEdward Cree 		/* dest is not an encap device */
609b4da4235SEdward Cree 		NL_SET_ERR_MSG_MOD(extack, "Not a (supported) tunnel device but tunnel_key is set");
610b4da4235SEdward Cree 		return ERR_PTR(-EOPNOTSUPP);
611b4da4235SEdward Cree 	}
612b4da4235SEdward Cree 	rc = efx_mae_check_encap_type_supported(efx, type);
613b4da4235SEdward Cree 	if (rc < 0) {
614b4da4235SEdward Cree 		NL_SET_ERR_MSG_MOD(extack, "Firmware reports no support for this tunnel type");
615b4da4235SEdward Cree 		return ERR_PTR(rc);
616b4da4235SEdward Cree 	}
617b4da4235SEdward Cree 	/* No support yet for Geneve options */
618b4da4235SEdward Cree 	if (info->options_len) {
619b4da4235SEdward Cree 		NL_SET_ERR_MSG_MOD(extack, "Unsupported tunnel options");
620b4da4235SEdward Cree 		return ERR_PTR(-EOPNOTSUPP);
621b4da4235SEdward Cree 	}
622b4da4235SEdward Cree 	switch (info->mode) {
623b4da4235SEdward Cree 	case IP_TUNNEL_INFO_TX:
624b4da4235SEdward Cree 		break;
625b4da4235SEdward Cree 	case IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_IPV6:
626b4da4235SEdward Cree 		type |= EFX_ENCAP_FLAG_IPV6;
627b4da4235SEdward Cree 		break;
628b4da4235SEdward Cree 	default:
629b4da4235SEdward Cree 		NL_SET_ERR_MSG_FMT_MOD(extack, "Unsupported tunnel mode %u",
630b4da4235SEdward Cree 				       info->mode);
631b4da4235SEdward Cree 		return ERR_PTR(-EOPNOTSUPP);
632b4da4235SEdward Cree 	}
633b4da4235SEdward Cree 	encap = kzalloc(sizeof(*encap), GFP_KERNEL_ACCOUNT);
634b4da4235SEdward Cree 	if (!encap)
635b4da4235SEdward Cree 		return ERR_PTR(-ENOMEM);
636b4da4235SEdward Cree 	encap->type = type;
637b4da4235SEdward Cree 	encap->key = info->key;
6387e5e7d80SEdward Cree 	INIT_LIST_HEAD(&encap->users);
639b4da4235SEdward Cree 	old = rhashtable_lookup_get_insert_fast(&efx->tc->encap_ht,
640b4da4235SEdward Cree 						&encap->linkage,
641b4da4235SEdward Cree 						efx_tc_encap_ht_params);
642b4da4235SEdward Cree 	if (old) {
643b4da4235SEdward Cree 		/* don't need our new entry */
644b4da4235SEdward Cree 		kfree(encap);
645*fc21f083SEdward Cree 		if (IS_ERR(old)) /* oh dear, it's actually an error */
646*fc21f083SEdward Cree 			return ERR_CAST(old);
647b4da4235SEdward Cree 		if (!refcount_inc_not_zero(&old->ref))
648b4da4235SEdward Cree 			return ERR_PTR(-EAGAIN);
649b4da4235SEdward Cree 		/* existing entry found, ref taken */
650b4da4235SEdward Cree 		return old;
651b4da4235SEdward Cree 	}
652b4da4235SEdward Cree 
6537e5e7d80SEdward Cree 	rc = efx_bind_neigh(efx, encap, dev_net(egdev), extack);
6547e5e7d80SEdward Cree 	if (rc < 0)
6557e5e7d80SEdward Cree 		goto out_remove;
6567e5e7d80SEdward Cree 	to_efv = efx_tc_flower_lookup_efv(efx, encap->neigh->egdev);
6577e5e7d80SEdward Cree 	if (IS_ERR(to_efv)) {
6587e5e7d80SEdward Cree 		/* neigh->egdev isn't ours */
6597e5e7d80SEdward Cree 		NL_SET_ERR_MSG_MOD(extack, "Tunnel egress device not on switch");
6607e5e7d80SEdward Cree 		rc = PTR_ERR(to_efv);
6617e5e7d80SEdward Cree 		goto out_release;
6627e5e7d80SEdward Cree 	}
6637e5e7d80SEdward Cree 	rc = efx_tc_flower_external_mport(efx, to_efv);
6647e5e7d80SEdward Cree 	if (rc < 0) {
6657e5e7d80SEdward Cree 		NL_SET_ERR_MSG_MOD(extack, "Failed to identify tunnel egress m-port");
6667e5e7d80SEdward Cree 		goto out_release;
6677e5e7d80SEdward Cree 	}
6687e5e7d80SEdward Cree 	encap->dest_mport = rc;
6697e5e7d80SEdward Cree 	read_lock_bh(&encap->neigh->lock);
670a1e82162SEdward Cree 	efx_gen_encap_header(efx, encap);
6717e5e7d80SEdward Cree 	read_unlock_bh(&encap->neigh->lock);
6727e5e7d80SEdward Cree 
6737e5e7d80SEdward Cree 	rc = efx_mae_allocate_encap_md(efx, encap);
6747e5e7d80SEdward Cree 	if (rc < 0) {
6757e5e7d80SEdward Cree 		NL_SET_ERR_MSG_MOD(extack, "Failed to write tunnel header to hw");
6767e5e7d80SEdward Cree 		goto out_release;
6777e5e7d80SEdward Cree 	}
6787e5e7d80SEdward Cree 
679b4da4235SEdward Cree 	/* ref and return */
680b4da4235SEdward Cree 	refcount_set(&encap->ref, 1);
681b4da4235SEdward Cree 	return encap;
6827e5e7d80SEdward Cree out_release:
6837e5e7d80SEdward Cree 	efx_release_neigh(efx, encap);
6847e5e7d80SEdward Cree out_remove:
6857e5e7d80SEdward Cree 	rhashtable_remove_fast(&efx->tc->encap_ht, &encap->linkage,
6867e5e7d80SEdward Cree 			       efx_tc_encap_ht_params);
6877e5e7d80SEdward Cree 	kfree(encap);
6887e5e7d80SEdward Cree 	return ERR_PTR(rc);
689b4da4235SEdward Cree }
690b4da4235SEdward Cree 
efx_tc_flower_release_encap_md(struct efx_nic * efx,struct efx_tc_encap_action * encap)691b4da4235SEdward Cree void efx_tc_flower_release_encap_md(struct efx_nic *efx,
692b4da4235SEdward Cree 				    struct efx_tc_encap_action *encap)
693b4da4235SEdward Cree {
694b4da4235SEdward Cree 	if (!refcount_dec_and_test(&encap->ref))
695b4da4235SEdward Cree 		return; /* still in use */
6967e5e7d80SEdward Cree 	efx_release_neigh(efx, encap);
697b4da4235SEdward Cree 	rhashtable_remove_fast(&efx->tc->encap_ht, &encap->linkage,
698b4da4235SEdward Cree 			       efx_tc_encap_ht_params);
6997e5e7d80SEdward Cree 	efx_mae_free_encap_md(efx, encap);
700b4da4235SEdward Cree 	kfree(encap);
701b4da4235SEdward Cree }
7027e5e7d80SEdward Cree 
efx_tc_remove_neigh_users(struct efx_nic * efx,struct efx_neigh_binder * neigh)7037e5e7d80SEdward Cree static void efx_tc_remove_neigh_users(struct efx_nic *efx, struct efx_neigh_binder *neigh)
7047e5e7d80SEdward Cree {
7057e5e7d80SEdward Cree 	struct efx_tc_encap_action *encap, *next;
7067e5e7d80SEdward Cree 
7077e5e7d80SEdward Cree 	list_for_each_entry_safe(encap, next, &neigh->users, list) {
7087e5e7d80SEdward Cree 		/* Should cause neigh usage count to fall to zero, freeing it */
7097e5e7d80SEdward Cree 		efx_release_neigh(efx, encap);
7107e5e7d80SEdward Cree 		/* The encap has lost its neigh, so it's now unready */
7117e5e7d80SEdward Cree 		efx_tc_update_encap(efx, encap);
7127e5e7d80SEdward Cree 	}
7137e5e7d80SEdward Cree }
7147e5e7d80SEdward Cree 
efx_tc_unregister_egdev(struct efx_nic * efx,struct net_device * net_dev)7157e5e7d80SEdward Cree void efx_tc_unregister_egdev(struct efx_nic *efx, struct net_device *net_dev)
7167e5e7d80SEdward Cree {
7177e5e7d80SEdward Cree 	struct efx_neigh_binder *neigh;
7187e5e7d80SEdward Cree 	struct rhashtable_iter walk;
7197e5e7d80SEdward Cree 
7207e5e7d80SEdward Cree 	mutex_lock(&efx->tc->mutex);
7217e5e7d80SEdward Cree 	rhashtable_walk_enter(&efx->tc->neigh_ht, &walk);
7227e5e7d80SEdward Cree 	rhashtable_walk_start(&walk);
7237e5e7d80SEdward Cree 	while ((neigh = rhashtable_walk_next(&walk)) != NULL) {
7247e5e7d80SEdward Cree 		if (IS_ERR(neigh))
7257e5e7d80SEdward Cree 			continue;
7267e5e7d80SEdward Cree 		if (neigh->egdev != net_dev)
7277e5e7d80SEdward Cree 			continue;
7287e5e7d80SEdward Cree 		neigh->dying = true;
7297e5e7d80SEdward Cree 		rhashtable_walk_stop(&walk);
7307e5e7d80SEdward Cree 		synchronize_rcu(); /* Make sure any updates see dying flag */
7317e5e7d80SEdward Cree 		efx_tc_remove_neigh_users(efx, neigh); /* might sleep */
7327e5e7d80SEdward Cree 		rhashtable_walk_start(&walk);
7337e5e7d80SEdward Cree 	}
7347e5e7d80SEdward Cree 	rhashtable_walk_stop(&walk);
7357e5e7d80SEdward Cree 	rhashtable_walk_exit(&walk);
7367e5e7d80SEdward Cree 	mutex_unlock(&efx->tc->mutex);
7377e5e7d80SEdward Cree }
7387e5e7d80SEdward Cree 
efx_tc_netevent_event(struct efx_nic * efx,unsigned long event,void * ptr)7397e5e7d80SEdward Cree int efx_tc_netevent_event(struct efx_nic *efx, unsigned long event,
7407e5e7d80SEdward Cree 			  void *ptr)
7417e5e7d80SEdward Cree {
7427e5e7d80SEdward Cree 	if (efx->type->is_vf)
7437e5e7d80SEdward Cree 		return NOTIFY_DONE;
7447e5e7d80SEdward Cree 
7457e5e7d80SEdward Cree 	switch (event) {
7467e5e7d80SEdward Cree 	case NETEVENT_NEIGH_UPDATE:
7477e5e7d80SEdward Cree 		return efx_neigh_event(efx, ptr);
7487e5e7d80SEdward Cree 	default:
7497e5e7d80SEdward Cree 		return NOTIFY_DONE;
7507e5e7d80SEdward Cree 	}
7517e5e7d80SEdward Cree }
752