File Index
Files and directories
Sign in
FILE

tunnel_conf.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c C
   1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
   2/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
   3
   4#include <linux/etherdevice.h>
   5#include <linux/inetdevice.h>
   6#include <net/netevent.h>
   7#include <linux/idr.h>
   8#include <net/dst_metadata.h>
   9#include <net/arp.h>
  10
  11#include "cmsg.h"
  12#include "main.h"
  13#include "../nfp_net_repr.h"
  14#include "../nfp_net.h"
  15
  16#define NFP_FL_MAX_ROUTES               32
  17
  18#define NFP_TUN_PRE_TUN_RULE_LIMIT	32
  19#define NFP_TUN_PRE_TUN_RULE_DEL	BIT(0)
  20#define NFP_TUN_PRE_TUN_IDX_BIT		BIT(3)
  21#define NFP_TUN_PRE_TUN_IPV6_BIT	BIT(7)
  22
  23/**
  24 * struct nfp_tun_pre_tun_rule - rule matched before decap
  25 * @flags:		options for the rule offset
  26 * @port_idx:		index of destination MAC address for the rule
  27 * @vlan_tci:		VLAN info associated with MAC
  28 * @host_ctx_id:	stats context of rule to update
  29 */
  30struct nfp_tun_pre_tun_rule {
  31	__be32 flags;
  32	__be16 port_idx;
  33	__be16 vlan_tci;
  34	__be32 host_ctx_id;
  35};
  36
  37/**
  38 * struct nfp_tun_active_tuns - periodic message of active tunnels
  39 * @seq:		sequence number of the message
  40 * @count:		number of tunnels report in message
  41 * @flags:		options part of the request
  42 * @tun_info.ipv4:		dest IPv4 address of active route
  43 * @tun_info.egress_port:	port the encapsulated packet egressed
  44 * @tun_info.extra:		reserved for future use
  45 * @tun_info:		tunnels that have sent traffic in reported period
  46 */
  47struct nfp_tun_active_tuns {
  48	__be32 seq;
  49	__be32 count;
  50	__be32 flags;
  51	struct route_ip_info {
  52		__be32 ipv4;
  53		__be32 egress_port;
  54		__be32 extra[2];
  55	} tun_info[];
  56};
  57
  58/**
  59 * struct nfp_tun_active_tuns_v6 - periodic message of active IPv6 tunnels
  60 * @seq:		sequence number of the message
  61 * @count:		number of tunnels report in message
  62 * @flags:		options part of the request
  63 * @tun_info.ipv6:		dest IPv6 address of active route
  64 * @tun_info.egress_port:	port the encapsulated packet egressed
  65 * @tun_info.extra:		reserved for future use
  66 * @tun_info:		tunnels that have sent traffic in reported period
  67 */
  68struct nfp_tun_active_tuns_v6 {
  69	__be32 seq;
  70	__be32 count;
  71	__be32 flags;
  72	struct route_ip_info_v6 {
  73		struct in6_addr ipv6;
  74		__be32 egress_port;
  75		__be32 extra[2];
  76	} tun_info[];
  77};
  78
  79/**
  80 * struct nfp_tun_req_route_ipv4 - NFP requests a route/neighbour lookup
  81 * @ingress_port:	ingress port of packet that signalled request
  82 * @ipv4_addr:		destination ipv4 address for route
  83 * @reserved:		reserved for future use
  84 */
  85struct nfp_tun_req_route_ipv4 {
  86	__be32 ingress_port;
  87	__be32 ipv4_addr;
  88	__be32 reserved[2];
  89};
  90
  91/**
  92 * struct nfp_tun_req_route_ipv6 - NFP requests an IPv6 route/neighbour lookup
  93 * @ingress_port:	ingress port of packet that signalled request
  94 * @ipv6_addr:		destination ipv6 address for route
  95 */
  96struct nfp_tun_req_route_ipv6 {
  97	__be32 ingress_port;
  98	struct in6_addr ipv6_addr;
  99};
 100
 101/**
 102 * struct nfp_offloaded_route - routes that are offloaded to the NFP
 103 * @list:	list pointer
 104 * @ip_add:	destination of route - can be IPv4 or IPv6
 105 */
 106struct nfp_offloaded_route {
 107	struct list_head list;
 108	u8 ip_add[];
 109};
 110
 111#define NFP_FL_IPV4_ADDRS_MAX        32
 112
 113/**
 114 * struct nfp_tun_ipv4_addr - set the IP address list on the NFP
 115 * @count:	number of IPs populated in the array
 116 * @ipv4_addr:	array of IPV4_ADDRS_MAX 32 bit IPv4 addresses
 117 */
 118struct nfp_tun_ipv4_addr {
 119	__be32 count;
 120	__be32 ipv4_addr[NFP_FL_IPV4_ADDRS_MAX];
 121};
 122
 123/**
 124 * struct nfp_ipv4_addr_entry - cached IPv4 addresses
 125 * @ipv4_addr:	IP address
 126 * @ref_count:	number of rules currently using this IP
 127 * @list:	list pointer
 128 */
 129struct nfp_ipv4_addr_entry {
 130	__be32 ipv4_addr;
 131	int ref_count;
 132	struct list_head list;
 133};
 134
 135#define NFP_FL_IPV6_ADDRS_MAX        4
 136
 137/**
 138 * struct nfp_tun_ipv6_addr - set the IP address list on the NFP
 139 * @count:	number of IPs populated in the array
 140 * @ipv6_addr:	array of IPV6_ADDRS_MAX 128 bit IPv6 addresses
 141 */
 142struct nfp_tun_ipv6_addr {
 143	__be32 count;
 144	struct in6_addr ipv6_addr[NFP_FL_IPV6_ADDRS_MAX];
 145};
 146
 147#define NFP_TUN_MAC_OFFLOAD_DEL_FLAG	0x2
 148
 149/**
 150 * struct nfp_tun_mac_addr_offload - configure MAC address of tunnel EP on NFP
 151 * @flags:	MAC address offload options
 152 * @count:	number of MAC addresses in the message (should be 1)
 153 * @index:	index of MAC address in the lookup table
 154 * @addr:	interface MAC address
 155 */
 156struct nfp_tun_mac_addr_offload {
 157	__be16 flags;
 158	__be16 count;
 159	__be16 index;
 160	u8 addr[ETH_ALEN];
 161};
 162
 163/**
 164 * struct nfp_neigh_update_work - update neighbour information to nfp
 165 * @work:	Work queue for writing neigh to the nfp
 166 * @n:		neighbour entry
 167 * @app:	Back pointer to app
 168 */
 169struct nfp_neigh_update_work {
 170	struct work_struct work;
 171	struct neighbour *n;
 172	struct nfp_app *app;
 173};
 174
 175enum nfp_flower_mac_offload_cmd {
 176	NFP_TUNNEL_MAC_OFFLOAD_ADD =		0,
 177	NFP_TUNNEL_MAC_OFFLOAD_DEL =		1,
 178	NFP_TUNNEL_MAC_OFFLOAD_MOD =		2,
 179};
 180
 181#define NFP_MAX_MAC_INDEX       0xff
 182
 183/**
 184 * struct nfp_tun_offloaded_mac - hashtable entry for an offloaded MAC
 185 * @ht_node:		Hashtable entry
 186 * @addr:		Offloaded MAC address
 187 * @index:		Offloaded index for given MAC address
 188 * @ref_count:		Number of devs using this MAC address
 189 * @repr_list:		List of reprs sharing this MAC address
 190 * @bridge_count:	Number of bridge/internal devs with MAC
 191 */
 192struct nfp_tun_offloaded_mac {
 193	struct rhash_head ht_node;
 194	u8 addr[ETH_ALEN];
 195	u16 index;
 196	int ref_count;
 197	struct list_head repr_list;
 198	int bridge_count;
 199};
 200
 201static const struct rhashtable_params offloaded_macs_params = {
 202	.key_offset	= offsetof(struct nfp_tun_offloaded_mac, addr),
 203	.head_offset	= offsetof(struct nfp_tun_offloaded_mac, ht_node),
 204	.key_len	= ETH_ALEN,
 205	.automatic_shrinking	= true,
 206};
 207
 208void nfp_tunnel_keep_alive(struct nfp_app *app, struct sk_buff *skb)
 209{
 210	struct nfp_tun_active_tuns *payload;
 211	struct net_device *netdev;
 212	int count, i, pay_len;
 213	struct neighbour *n;
 214	__be32 ipv4_addr;
 215	u32 port;
 216
 217	payload = nfp_flower_cmsg_get_data(skb);
 218	count = be32_to_cpu(payload->count);
 219	if (count > NFP_FL_MAX_ROUTES) {
 220		nfp_flower_cmsg_warn(app, "Tunnel keep-alive request exceeds max routes.\n");
 221		return;
 222	}
 223
 224	pay_len = nfp_flower_cmsg_get_data_len(skb);
 225	if (pay_len != struct_size(payload, tun_info, count)) {
 226		nfp_flower_cmsg_warn(app, "Corruption in tunnel keep-alive message.\n");
 227		return;
 228	}
 229
 230	rcu_read_lock();
 231	for (i = 0; i < count; i++) {
 232		ipv4_addr = payload->tun_info[i].ipv4;
 233		port = be32_to_cpu(payload->tun_info[i].egress_port);
 234		netdev = nfp_app_dev_get(app, port, NULL);
 235		if (!netdev)
 236			continue;
 237
 238		n = neigh_lookup(&arp_tbl, &ipv4_addr, netdev);
 239		if (!n)
 240			continue;
 241
 242		/* Update the used timestamp of neighbour */
 243		neigh_event_send(n, NULL);
 244		neigh_release(n);
 245	}
 246	rcu_read_unlock();
 247}
 248
 249void nfp_tunnel_keep_alive_v6(struct nfp_app *app, struct sk_buff *skb)
 250{
 251#if IS_ENABLED(CONFIG_IPV6)
 252	struct nfp_tun_active_tuns_v6 *payload;
 253	struct net_device *netdev;
 254	int count, i, pay_len;
 255	struct neighbour *n;
 256	void *ipv6_add;
 257	u32 port;
 258
 259	payload = nfp_flower_cmsg_get_data(skb);
 260	count = be32_to_cpu(payload->count);
 261	if (count > NFP_FL_IPV6_ADDRS_MAX) {
 262		nfp_flower_cmsg_warn(app, "IPv6 tunnel keep-alive request exceeds max routes.\n");
 263		return;
 264	}
 265
 266	pay_len = nfp_flower_cmsg_get_data_len(skb);
 267	if (pay_len != struct_size(payload, tun_info, count)) {
 268		nfp_flower_cmsg_warn(app, "Corruption in tunnel keep-alive message.\n");
 269		return;
 270	}
 271
 272	rcu_read_lock();
 273	for (i = 0; i < count; i++) {
 274		ipv6_add = &payload->tun_info[i].ipv6;
 275		port = be32_to_cpu(payload->tun_info[i].egress_port);
 276		netdev = nfp_app_dev_get(app, port, NULL);
 277		if (!netdev)
 278			continue;
 279
 280		n = neigh_lookup(&nd_tbl, ipv6_add, netdev);
 281		if (!n)
 282			continue;
 283
 284		/* Update the used timestamp of neighbour */
 285		neigh_event_send(n, NULL);
 286		neigh_release(n);
 287	}
 288	rcu_read_unlock();
 289#endif
 290}
 291
 292static int
 293nfp_flower_xmit_tun_conf(struct nfp_app *app, u8 mtype, u16 plen, void *pdata,
 294			 gfp_t flag)
 295{
 296	struct nfp_flower_priv *priv = app->priv;
 297	struct sk_buff *skb;
 298	unsigned char *msg;
 299
 300	if (!(priv->flower_ext_feats & NFP_FL_FEATS_DECAP_V2) &&
 301	    (mtype == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH ||
 302	     mtype == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6))
 303		plen -= sizeof(struct nfp_tun_neigh_ext);
 304
 305	if (!(priv->flower_ext_feats & NFP_FL_FEATS_TUNNEL_NEIGH_LAG) &&
 306	    (mtype == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH ||
 307	     mtype == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6))
 308		plen -= sizeof(struct nfp_tun_neigh_lag);
 309
 310	skb = nfp_flower_cmsg_alloc(app, plen, mtype, flag);
 311	if (!skb)
 312		return -ENOMEM;
 313
 314	msg = nfp_flower_cmsg_get_data(skb);
 315	memcpy(msg, pdata, nfp_flower_cmsg_get_data_len(skb));
 316
 317	nfp_ctrl_tx(app->ctrl, skb);
 318	return 0;
 319}
 320
 321static void
 322nfp_tun_mutual_link(struct nfp_predt_entry *predt,
 323		    struct nfp_neigh_entry *neigh)
 324{
 325	struct nfp_fl_payload *flow_pay = predt->flow_pay;
 326	struct nfp_tun_neigh_ext *ext;
 327	struct nfp_tun_neigh *common;
 328
 329	if (flow_pay->pre_tun_rule.is_ipv6 != neigh->is_ipv6)
 330		return;
 331
 332	/* In the case of bonding it is possible that there might already
 333	 * be a flow linked (as the MAC address gets shared). If a flow
 334	 * is already linked just return.
 335	 */
 336	if (neigh->flow)
 337		return;
 338
 339	common = neigh->is_ipv6 ?
 340		 &((struct nfp_tun_neigh_v6 *)neigh->payload)->common :
 341		 &((struct nfp_tun_neigh_v4 *)neigh->payload)->common;
 342	ext = neigh->is_ipv6 ?
 343		 &((struct nfp_tun_neigh_v6 *)neigh->payload)->ext :
 344		 &((struct nfp_tun_neigh_v4 *)neigh->payload)->ext;
 345
 346	if (memcmp(flow_pay->pre_tun_rule.loc_mac,
 347		   common->src_addr, ETH_ALEN) ||
 348	    memcmp(flow_pay->pre_tun_rule.rem_mac,
 349		   common->dst_addr, ETH_ALEN))
 350		return;
 351
 352	list_add(&neigh->list_head, &predt->nn_list);
 353	neigh->flow = predt;
 354	ext->host_ctx = flow_pay->meta.host_ctx_id;
 355	ext->vlan_tci = flow_pay->pre_tun_rule.vlan_tci;
 356	ext->vlan_tpid = flow_pay->pre_tun_rule.vlan_tpid;
 357}
 358
 359static void
 360nfp_tun_link_predt_entries(struct nfp_app *app,
 361			   struct nfp_neigh_entry *nn_entry)
 362{
 363	struct nfp_flower_priv *priv = app->priv;
 364	struct nfp_predt_entry *predt, *tmp;
 365
 366	list_for_each_entry_safe(predt, tmp, &priv->predt_list, list_head) {
 367		nfp_tun_mutual_link(predt, nn_entry);
 368	}
 369}
 370
 371void nfp_tun_link_and_update_nn_entries(struct nfp_app *app,
 372					struct nfp_predt_entry *predt)
 373{
 374	struct nfp_flower_priv *priv = app->priv;
 375	struct nfp_neigh_entry *nn_entry;
 376	struct rhashtable_iter iter;
 377	size_t neigh_size;
 378	u8 type;
 379
 380	rhashtable_walk_enter(&priv->neigh_table, &iter);
 381	rhashtable_walk_start(&iter);
 382	while ((nn_entry = rhashtable_walk_next(&iter)) != NULL) {
 383		if (IS_ERR(nn_entry))
 384			continue;
 385		nfp_tun_mutual_link(predt, nn_entry);
 386		neigh_size = nn_entry->is_ipv6 ?
 387			     sizeof(struct nfp_tun_neigh_v6) :
 388			     sizeof(struct nfp_tun_neigh_v4);
 389		type = nn_entry->is_ipv6 ? NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6 :
 390					   NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
 391		nfp_flower_xmit_tun_conf(app, type, neigh_size,
 392					 nn_entry->payload,
 393					 GFP_ATOMIC);
 394	}
 395	rhashtable_walk_stop(&iter);
 396	rhashtable_walk_exit(&iter);
 397}
 398
 399static void nfp_tun_cleanup_nn_entries(struct nfp_app *app)
 400{
 401	struct nfp_flower_priv *priv = app->priv;
 402	struct nfp_neigh_entry *neigh;
 403	struct nfp_tun_neigh_ext *ext;
 404	struct rhashtable_iter iter;
 405	size_t neigh_size;
 406	u8 type;
 407
 408	rhashtable_walk_enter(&priv->neigh_table, &iter);
 409	rhashtable_walk_start(&iter);
 410	while ((neigh = rhashtable_walk_next(&iter)) != NULL) {
 411		if (IS_ERR(neigh))
 412			continue;
 413		ext = neigh->is_ipv6 ?
 414			 &((struct nfp_tun_neigh_v6 *)neigh->payload)->ext :
 415			 &((struct nfp_tun_neigh_v4 *)neigh->payload)->ext;
 416		ext->host_ctx = cpu_to_be32(U32_MAX);
 417		ext->vlan_tpid = cpu_to_be16(U16_MAX);
 418		ext->vlan_tci = cpu_to_be16(U16_MAX);
 419
 420		neigh_size = neigh->is_ipv6 ?
 421			     sizeof(struct nfp_tun_neigh_v6) :
 422			     sizeof(struct nfp_tun_neigh_v4);
 423		type = neigh->is_ipv6 ? NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6 :
 424					   NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
 425		nfp_flower_xmit_tun_conf(app, type, neigh_size, neigh->payload,
 426					 GFP_ATOMIC);
 427
 428		rhashtable_remove_fast(&priv->neigh_table, &neigh->ht_node,
 429				       neigh_table_params);
 430		if (neigh->flow)
 431			list_del(&neigh->list_head);
 432		kfree(neigh);
 433	}
 434	rhashtable_walk_stop(&iter);
 435	rhashtable_walk_exit(&iter);
 436}
 437
 438void nfp_tun_unlink_and_update_nn_entries(struct nfp_app *app,
 439					  struct nfp_predt_entry *predt)
 440{
 441	struct nfp_neigh_entry *neigh, *tmp;
 442	struct nfp_tun_neigh_ext *ext;
 443	size_t neigh_size;
 444	u8 type;
 445
 446	list_for_each_entry_safe(neigh, tmp, &predt->nn_list, list_head) {
 447		ext = neigh->is_ipv6 ?
 448			 &((struct nfp_tun_neigh_v6 *)neigh->payload)->ext :
 449			 &((struct nfp_tun_neigh_v4 *)neigh->payload)->ext;
 450		neigh->flow = NULL;
 451		ext->host_ctx = cpu_to_be32(U32_MAX);
 452		ext->vlan_tpid = cpu_to_be16(U16_MAX);
 453		ext->vlan_tci = cpu_to_be16(U16_MAX);
 454		list_del(&neigh->list_head);
 455		neigh_size = neigh->is_ipv6 ?
 456			     sizeof(struct nfp_tun_neigh_v6) :
 457			     sizeof(struct nfp_tun_neigh_v4);
 458		type = neigh->is_ipv6 ? NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6 :
 459					   NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
 460		nfp_flower_xmit_tun_conf(app, type, neigh_size, neigh->payload,
 461					 GFP_ATOMIC);
 462	}
 463}
 464
 465static void
 466nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
 467		    void *flow, struct neighbour *neigh, bool is_ipv6,
 468		    bool override)
 469{
 470	bool neigh_invalid = !(neigh->nud_state & NUD_VALID) || neigh->dead;
 471	size_t neigh_size = is_ipv6 ? sizeof(struct nfp_tun_neigh_v6) :
 472			    sizeof(struct nfp_tun_neigh_v4);
 473	unsigned long cookie = (unsigned long)neigh;
 474	struct nfp_flower_priv *priv = app->priv;
 475	struct nfp_tun_neigh_lag lag_info;
 476	struct nfp_neigh_entry *nn_entry;
 477	u32 port_id;
 478	u8 mtype;
 479
 480	port_id = nfp_flower_get_port_id_from_netdev(app, netdev);
 481	if (!port_id)
 482		return;
 483
 484	if ((port_id & NFP_FL_LAG_OUT) == NFP_FL_LAG_OUT) {
 485		memset(&lag_info, 0, sizeof(struct nfp_tun_neigh_lag));
 486		nfp_flower_lag_get_info_from_netdev(app, netdev, &lag_info);
 487	}
 488
 489	spin_lock_bh(&priv->predt_lock);
 490	nn_entry = rhashtable_lookup_fast(&priv->neigh_table, &cookie,
 491					  neigh_table_params);
 492	if (!nn_entry && !neigh_invalid) {
 493		struct nfp_tun_neigh_ext *ext;
 494		struct nfp_tun_neigh_lag *lag;
 495		struct nfp_tun_neigh *common;
 496
 497		nn_entry = kzalloc(sizeof(*nn_entry) + neigh_size,
 498				   GFP_ATOMIC);
 499		if (!nn_entry)
 500			goto err;
 501
 502		nn_entry->payload = (char *)&nn_entry[1];
 503		nn_entry->neigh_cookie = cookie;
 504		nn_entry->is_ipv6 = is_ipv6;
 505		nn_entry->flow = NULL;
 506		if (is_ipv6) {
 507			struct flowi6 *flowi6 = (struct flowi6 *)flow;
 508			struct nfp_tun_neigh_v6 *payload;
 509
 510			payload = (struct nfp_tun_neigh_v6 *)nn_entry->payload;
 511			payload->src_ipv6 = flowi6->saddr;
 512			payload->dst_ipv6 = flowi6->daddr;
 513			common = &payload->common;
 514			ext = &payload->ext;
 515			lag = &payload->lag;
 516			mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6;
 517		} else {
 518			struct flowi4 *flowi4 = (struct flowi4 *)flow;
 519			struct nfp_tun_neigh_v4 *payload;
 520
 521			payload = (struct nfp_tun_neigh_v4 *)nn_entry->payload;
 522			payload->src_ipv4 = flowi4->saddr;
 523			payload->dst_ipv4 = flowi4->daddr;
 524			common = &payload->common;
 525			ext = &payload->ext;
 526			lag = &payload->lag;
 527			mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
 528		}
 529		ext->host_ctx = cpu_to_be32(U32_MAX);
 530		ext->vlan_tpid = cpu_to_be16(U16_MAX);
 531		ext->vlan_tci = cpu_to_be16(U16_MAX);
 532		ether_addr_copy(common->src_addr, netdev->dev_addr);
 533		neigh_ha_snapshot(common->dst_addr, neigh, netdev);
 534
 535		if ((port_id & NFP_FL_LAG_OUT) == NFP_FL_LAG_OUT)
 536			memcpy(lag, &lag_info, sizeof(struct nfp_tun_neigh_lag));
 537		common->port_id = cpu_to_be32(port_id);
 538
 539		if (rhashtable_insert_fast(&priv->neigh_table,
 540					   &nn_entry->ht_node,
 541					   neigh_table_params))
 542			goto err;
 543
 544		nfp_tun_link_predt_entries(app, nn_entry);
 545		nfp_flower_xmit_tun_conf(app, mtype, neigh_size,
 546					 nn_entry->payload,
 547					 GFP_ATOMIC);
 548	} else if (nn_entry && neigh_invalid) {
 549		if (is_ipv6) {
 550			struct flowi6 *flowi6 = (struct flowi6 *)flow;
 551			struct nfp_tun_neigh_v6 *payload;
 552
 553			payload = (struct nfp_tun_neigh_v6 *)nn_entry->payload;
 554			memset(payload, 0, sizeof(struct nfp_tun_neigh_v6));
 555			payload->dst_ipv6 = flowi6->daddr;
 556			mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6;
 557		} else {
 558			struct flowi4 *flowi4 = (struct flowi4 *)flow;
 559			struct nfp_tun_neigh_v4 *payload;
 560
 561			payload = (struct nfp_tun_neigh_v4 *)nn_entry->payload;
 562			memset(payload, 0, sizeof(struct nfp_tun_neigh_v4));
 563			payload->dst_ipv4 = flowi4->daddr;
 564			mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
 565		}
 566		/* Trigger ARP to verify invalid neighbour state. */
 567		neigh_event_send(neigh, NULL);
 568		rhashtable_remove_fast(&priv->neigh_table,
 569				       &nn_entry->ht_node,
 570				       neigh_table_params);
 571
 572		nfp_flower_xmit_tun_conf(app, mtype, neigh_size,
 573					 nn_entry->payload,
 574					 GFP_ATOMIC);
 575
 576		if (nn_entry->flow)
 577			list_del(&nn_entry->list_head);
 578		kfree(nn_entry);
 579	} else if (nn_entry && !neigh_invalid) {
 580		struct nfp_tun_neigh *common;
 581		u8 dst_addr[ETH_ALEN];
 582		bool is_mac_change;
 583
 584		if (is_ipv6) {
 585			struct nfp_tun_neigh_v6 *payload;
 586
 587			payload = (struct nfp_tun_neigh_v6 *)nn_entry->payload;
 588			common = &payload->common;
 589			mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6;
 590		} else {
 591			struct nfp_tun_neigh_v4 *payload;
 592
 593			payload = (struct nfp_tun_neigh_v4 *)nn_entry->payload;
 594			common = &payload->common;
 595			mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
 596		}
 597
 598		ether_addr_copy(dst_addr, common->dst_addr);
 599		neigh_ha_snapshot(common->dst_addr, neigh, netdev);
 600		is_mac_change = !ether_addr_equal(dst_addr, common->dst_addr);
 601		if (override || is_mac_change) {
 602			if (is_mac_change && nn_entry->flow) {
 603				list_del(&nn_entry->list_head);
 604				nn_entry->flow = NULL;
 605			}
 606			nfp_tun_link_predt_entries(app, nn_entry);
 607			nfp_flower_xmit_tun_conf(app, mtype, neigh_size,
 608						 nn_entry->payload,
 609						 GFP_ATOMIC);
 610		}
 611	}
 612
 613	spin_unlock_bh(&priv->predt_lock);
 614	return;
 615
 616err:
 617	kfree(nn_entry);
 618	spin_unlock_bh(&priv->predt_lock);
 619	nfp_flower_cmsg_warn(app, "Neighbour configuration failed.\n");
 620}
 621
 622static void
 623nfp_tun_release_neigh_update_work(struct nfp_neigh_update_work *update_work)
 624{
 625	neigh_release(update_work->n);
 626	kfree(update_work);
 627}
 628
 629static void nfp_tun_neigh_update(struct work_struct *work)
 630{
 631	struct nfp_neigh_update_work *update_work;
 632	struct nfp_app *app;
 633	struct neighbour *n;
 634	bool neigh_invalid;
 635	int err;
 636
 637	update_work = container_of(work, struct nfp_neigh_update_work, work);
 638	app = update_work->app;
 639	n = update_work->n;
 640
 641	if (!nfp_flower_get_port_id_from_netdev(app, n->dev))
 642		goto out;
 643
 644#if IS_ENABLED(CONFIG_INET)
 645	neigh_invalid = !(n->nud_state & NUD_VALID) || n->dead;
 646	if (n->tbl->family == AF_INET6) {
 647#if IS_ENABLED(CONFIG_IPV6)
 648		struct flowi6 flow6 = {};
 649
 650		flow6.daddr = *(struct in6_addr *)n->primary_key;
 651		if (!neigh_invalid) {
 652			struct dst_entry *dst;
 653			/* Use ipv6_dst_lookup_flow to populate flow6->saddr
 654			 * and other fields. This information is only needed
 655			 * for new entries, lookup can be skipped when an entry
 656			 * gets invalidated - as only the daddr is needed for
 657			 * deleting.
 658			 */
 659			dst = ip6_dst_lookup_flow(dev_net(n->dev), NULL,
 660						  &flow6, NULL);
 661			if (IS_ERR(dst))
 662				goto out;
 663
 664			dst_release(dst);
 665		}
 666		nfp_tun_write_neigh(n->dev, app, &flow6, n, true, false);
 667#endif /* CONFIG_IPV6 */
 668	} else {
 669		struct flowi4 flow4 = {};
 670
 671		flow4.daddr = *(__be32 *)n->primary_key;
 672		if (!neigh_invalid) {
 673			struct rtable *rt;
 674			/* Use ip_route_output_key to populate flow4->saddr and
 675			 * other fields. This information is only needed for
 676			 * new entries, lookup can be skipped when an entry
 677			 * gets invalidated - as only the daddr is needed for
 678			 * deleting.
 679			 */
 680			rt = ip_route_output_key(dev_net(n->dev), &flow4);
 681			err = PTR_ERR_OR_ZERO(rt);
 682			if (err)
 683				goto out;
 684
 685			ip_rt_put(rt);
 686		}
 687		nfp_tun_write_neigh(n->dev, app, &flow4, n, false, false);
 688	}
 689#endif /* CONFIG_INET */
 690out:
 691	nfp_tun_release_neigh_update_work(update_work);
 692}
 693
 694static struct nfp_neigh_update_work *
 695nfp_tun_alloc_neigh_update_work(struct nfp_app *app, struct neighbour *n)
 696{
 697	struct nfp_neigh_update_work *update_work;
 698
 699	update_work = kzalloc(sizeof(*update_work), GFP_ATOMIC);
 700	if (!update_work)
 701		return NULL;
 702
 703	INIT_WORK(&update_work->work, nfp_tun_neigh_update);
 704	neigh_hold(n);
 705	update_work->n = n;
 706	update_work->app = app;
 707
 708	return update_work;
 709}
 710
 711static int
 712nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
 713			    void *ptr)
 714{
 715	struct nfp_neigh_update_work *update_work;
 716	struct nfp_flower_priv *app_priv;
 717	struct netevent_redirect *redir;
 718	struct neighbour *n;
 719	struct nfp_app *app;
 720
 721	switch (event) {
 722	case NETEVENT_REDIRECT:
 723		redir = (struct netevent_redirect *)ptr;
 724		n = redir->neigh;
 725		break;
 726	case NETEVENT_NEIGH_UPDATE:
 727		n = (struct neighbour *)ptr;
 728		break;
 729	default:
 730		return NOTIFY_DONE;
 731	}
 732#if IS_ENABLED(CONFIG_IPV6)
 733	if (n->tbl != ipv6_stub->nd_tbl && n->tbl != &arp_tbl)
 734#else
 735	if (n->tbl != &arp_tbl)
 736#endif
 737		return NOTIFY_DONE;
 738
 739	app_priv = container_of(nb, struct nfp_flower_priv, tun.neigh_nb);
 740	app = app_priv->app;
 741	update_work = nfp_tun_alloc_neigh_update_work(app, n);
 742	if (!update_work)
 743		return NOTIFY_DONE;
 744
 745	queue_work(system_highpri_wq, &update_work->work);
 746
 747	return NOTIFY_DONE;
 748}
 749
 750void nfp_tunnel_request_route_v4(struct nfp_app *app, struct sk_buff *skb)
 751{
 752	struct nfp_tun_req_route_ipv4 *payload;
 753	struct net_device *netdev;
 754	struct flowi4 flow = {};
 755	struct neighbour *n;
 756	struct rtable *rt;
 757	int err;
 758
 759	payload = nfp_flower_cmsg_get_data(skb);
 760
 761	rcu_read_lock();
 762	netdev = nfp_app_dev_get(app, be32_to_cpu(payload->ingress_port), NULL);
 763	if (!netdev)
 764		goto fail_rcu_unlock;
 765	dev_hold(netdev);
 766
 767	flow.daddr = payload->ipv4_addr;
 768	flow.flowi4_proto = IPPROTO_UDP;
 769
 770#if IS_ENABLED(CONFIG_INET)
 771	/* Do a route lookup on same namespace as ingress port. */
 772	rt = ip_route_output_key(dev_net(netdev), &flow);
 773	err = PTR_ERR_OR_ZERO(rt);
 774	if (err)
 775		goto fail_rcu_unlock;
 776#else
 777	goto fail_rcu_unlock;
 778#endif
 779
 780	/* Get the neighbour entry for the lookup */
 781	n = dst_neigh_lookup(&rt->dst, &flow.daddr);
 782	ip_rt_put(rt);
 783	if (!n)
 784		goto fail_rcu_unlock;
 785	rcu_read_unlock();
 786
 787	nfp_tun_write_neigh(n->dev, app, &flow, n, false, true);
 788	neigh_release(n);
 789	dev_put(netdev);
 790	return;
 791
 792fail_rcu_unlock:
 793	rcu_read_unlock();
 794	dev_put(netdev);
 795	nfp_flower_cmsg_warn(app, "Requested route not found.\n");
 796}
 797
 798void nfp_tunnel_request_route_v6(struct nfp_app *app, struct sk_buff *skb)
 799{
 800	struct nfp_tun_req_route_ipv6 *payload;
 801	struct net_device *netdev;
 802	struct flowi6 flow = {};
 803	struct dst_entry *dst;
 804	struct neighbour *n;
 805
 806	payload = nfp_flower_cmsg_get_data(skb);
 807
 808	rcu_read_lock();
 809	netdev = nfp_app_dev_get(app, be32_to_cpu(payload->ingress_port), NULL);
 810	if (!netdev)
 811		goto fail_rcu_unlock;
 812	dev_hold(netdev);
 813
 814	flow.daddr = payload->ipv6_addr;
 815	flow.flowi6_proto = IPPROTO_UDP;
 816
 817#if IS_ENABLED(CONFIG_INET) && IS_ENABLED(CONFIG_IPV6)
 818	dst = ipv6_stub->ipv6_dst_lookup_flow(dev_net(netdev), NULL, &flow,
 819					      NULL);
 820	if (IS_ERR(dst))
 821		goto fail_rcu_unlock;
 822#else
 823	goto fail_rcu_unlock;
 824#endif
 825
 826	n = dst_neigh_lookup(dst, &flow.daddr);
 827	dst_release(dst);
 828	if (!n)
 829		goto fail_rcu_unlock;
 830	rcu_read_unlock();
 831
 832	nfp_tun_write_neigh(n->dev, app, &flow, n, true, true);
 833	neigh_release(n);
 834	dev_put(netdev);
 835	return;
 836
 837fail_rcu_unlock:
 838	rcu_read_unlock();
 839	dev_put(netdev);
 840	nfp_flower_cmsg_warn(app, "Requested IPv6 route not found.\n");
 841}
 842
 843static void nfp_tun_write_ipv4_list(struct nfp_app *app)
 844{
 845	struct nfp_flower_priv *priv = app->priv;
 846	struct nfp_ipv4_addr_entry *entry;
 847	struct nfp_tun_ipv4_addr payload;
 848	struct list_head *ptr, *storage;
 849	int count;
 850
 851	memset(&payload, 0, sizeof(struct nfp_tun_ipv4_addr));
 852	mutex_lock(&priv->tun.ipv4_off_lock);
 853	count = 0;
 854	list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) {
 855		if (count >= NFP_FL_IPV4_ADDRS_MAX) {
 856			mutex_unlock(&priv->tun.ipv4_off_lock);
 857			nfp_flower_cmsg_warn(app, "IPv4 offload exceeds limit.\n");
 858			return;
 859		}
 860		entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
 861		payload.ipv4_addr[count++] = entry->ipv4_addr;
 862	}
 863	payload.count = cpu_to_be32(count);
 864	mutex_unlock(&priv->tun.ipv4_off_lock);
 865
 866	nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_IPS,
 867				 sizeof(struct nfp_tun_ipv4_addr),
 868				 &payload, GFP_KERNEL);
 869}
 870
 871void nfp_tunnel_add_ipv4_off(struct nfp_app *app, __be32 ipv4)
 872{
 873	struct nfp_flower_priv *priv = app->priv;
 874	struct nfp_ipv4_addr_entry *entry;
 875	struct list_head *ptr, *storage;
 876
 877	mutex_lock(&priv->tun.ipv4_off_lock);
 878	list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) {
 879		entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
 880		if (entry->ipv4_addr == ipv4) {
 881			entry->ref_count++;
 882			mutex_unlock(&priv->tun.ipv4_off_lock);
 883			return;
 884		}
 885	}
 886
 887	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 888	if (!entry) {
 889		mutex_unlock(&priv->tun.ipv4_off_lock);
 890		nfp_flower_cmsg_warn(app, "Mem error when offloading IP address.\n");
 891		return;
 892	}
 893	entry->ipv4_addr = ipv4;
 894	entry->ref_count = 1;
 895	list_add_tail(&entry->list, &priv->tun.ipv4_off_list);
 896	mutex_unlock(&priv->tun.ipv4_off_lock);
 897
 898	nfp_tun_write_ipv4_list(app);
 899}
 900
 901void nfp_tunnel_del_ipv4_off(struct nfp_app *app, __be32 ipv4)
 902{
 903	struct nfp_flower_priv *priv = app->priv;
 904	struct nfp_ipv4_addr_entry *entry;
 905	struct list_head *ptr, *storage;
 906
 907	mutex_lock(&priv->tun.ipv4_off_lock);
 908	list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) {
 909		entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
 910		if (entry->ipv4_addr == ipv4) {
 911			entry->ref_count--;
 912			if (!entry->ref_count) {
 913				list_del(&entry->list);
 914				kfree(entry);
 915			}
 916			break;
 917		}
 918	}
 919	mutex_unlock(&priv->tun.ipv4_off_lock);
 920
 921	nfp_tun_write_ipv4_list(app);
 922}
 923
 924static void nfp_tun_write_ipv6_list(struct nfp_app *app)
 925{
 926	struct nfp_flower_priv *priv = app->priv;
 927	struct nfp_ipv6_addr_entry *entry;
 928	struct nfp_tun_ipv6_addr payload;
 929	int count = 0;
 930
 931	memset(&payload, 0, sizeof(struct nfp_tun_ipv6_addr));
 932	mutex_lock(&priv->tun.ipv6_off_lock);
 933	list_for_each_entry(entry, &priv->tun.ipv6_off_list, list) {
 934		if (count >= NFP_FL_IPV6_ADDRS_MAX) {
 935			nfp_flower_cmsg_warn(app, "Too many IPv6 tunnel endpoint addresses, some cannot be offloaded.\n");
 936			break;
 937		}
 938		payload.ipv6_addr[count++] = entry->ipv6_addr;
 939	}
 940	mutex_unlock(&priv->tun.ipv6_off_lock);
 941	payload.count = cpu_to_be32(count);
 942
 943	nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_IPS_V6,
 944				 sizeof(struct nfp_tun_ipv6_addr),
 945				 &payload, GFP_KERNEL);
 946}
 947
 948struct nfp_ipv6_addr_entry *
 949nfp_tunnel_add_ipv6_off(struct nfp_app *app, struct in6_addr *ipv6)
 950{
 951	struct nfp_flower_priv *priv = app->priv;
 952	struct nfp_ipv6_addr_entry *entry;
 953
 954	mutex_lock(&priv->tun.ipv6_off_lock);
 955	list_for_each_entry(entry, &priv->tun.ipv6_off_list, list)
 956		if (!memcmp(&entry->ipv6_addr, ipv6, sizeof(*ipv6))) {
 957			entry->ref_count++;
 958			mutex_unlock(&priv->tun.ipv6_off_lock);
 959			return entry;
 960		}
 961
 962	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 963	if (!entry) {
 964		mutex_unlock(&priv->tun.ipv6_off_lock);
 965		nfp_flower_cmsg_warn(app, "Mem error when offloading IP address.\n");
 966		return NULL;
 967	}
 968	entry->ipv6_addr = *ipv6;
 969	entry->ref_count = 1;
 970	list_add_tail(&entry->list, &priv->tun.ipv6_off_list);
 971	mutex_unlock(&priv->tun.ipv6_off_lock);
 972
 973	nfp_tun_write_ipv6_list(app);
 974
 975	return entry;
 976}
 977
 978void
 979nfp_tunnel_put_ipv6_off(struct nfp_app *app, struct nfp_ipv6_addr_entry *entry)
 980{
 981	struct nfp_flower_priv *priv = app->priv;
 982	bool freed = false;
 983
 984	mutex_lock(&priv->tun.ipv6_off_lock);
 985	if (!--entry->ref_count) {
 986		list_del(&entry->list);
 987		kfree(entry);
 988		freed = true;
 989	}
 990	mutex_unlock(&priv->tun.ipv6_off_lock);
 991
 992	if (freed)
 993		nfp_tun_write_ipv6_list(app);
 994}
 995
 996static int
 997__nfp_tunnel_offload_mac(struct nfp_app *app, const u8 *mac, u16 idx, bool del)
 998{
 999	struct nfp_tun_mac_addr_offload payload;
1000
1001	memset(&payload, 0, sizeof(payload));
1002
1003	if (del)
1004		payload.flags = cpu_to_be16(NFP_TUN_MAC_OFFLOAD_DEL_FLAG);
1005
1006	/* FW supports multiple MACs per cmsg but restrict to single. */
1007	payload.count = cpu_to_be16(1);
1008	payload.index = cpu_to_be16(idx);
1009	ether_addr_copy(payload.addr, mac);
1010
1011	return nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_TUN_MAC,
1012					sizeof(struct nfp_tun_mac_addr_offload),
1013					&payload, GFP_KERNEL);
1014}
1015
1016static bool nfp_tunnel_port_is_phy_repr(int port)
1017{
1018	if (FIELD_GET(NFP_FLOWER_CMSG_PORT_TYPE, port) ==
1019	    NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT)
1020		return true;
1021
1022	return false;
1023}
1024
1025static u16 nfp_tunnel_get_mac_idx_from_phy_port_id(int port)
1026{
1027	return port << 8 | NFP_FLOWER_CMSG_PORT_TYPE_PHYS_PORT;
1028}
1029
1030static u16 nfp_tunnel_get_global_mac_idx_from_ida(int id)
1031{
1032	return id << 8 | NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT;
1033}
1034
1035static int nfp_tunnel_get_ida_from_global_mac_idx(u16 nfp_mac_idx)
1036{
1037	return nfp_mac_idx >> 8;
1038}
1039
1040static bool nfp_tunnel_is_mac_idx_global(u16 nfp_mac_idx)
1041{
1042	return (nfp_mac_idx & 0xff) == NFP_FLOWER_CMSG_PORT_TYPE_OTHER_PORT;
1043}
1044
1045static struct nfp_tun_offloaded_mac *
1046nfp_tunnel_lookup_offloaded_macs(struct nfp_app *app, const u8 *mac)
1047{
1048	struct nfp_flower_priv *priv = app->priv;
1049
1050	return rhashtable_lookup_fast(&priv->tun.offloaded_macs, mac,
1051				      offloaded_macs_params);
1052}
1053
1054static void
1055nfp_tunnel_offloaded_macs_inc_ref_and_link(struct nfp_tun_offloaded_mac *entry,
1056					   struct net_device *netdev, bool mod)
1057{
1058	if (nfp_netdev_is_nfp_repr(netdev)) {
1059		struct nfp_flower_repr_priv *repr_priv;
1060		struct nfp_repr *repr;
1061
1062		repr = netdev_priv(netdev);
1063		repr_priv = repr->app_priv;
1064
1065		/* If modifing MAC, remove repr from old list first. */
1066		if (mod)
1067			list_del(&repr_priv->mac_list);
1068
1069		list_add_tail(&repr_priv->mac_list, &entry->repr_list);
1070	} else if (nfp_flower_is_supported_bridge(netdev)) {
1071		entry->bridge_count++;
1072	}
1073
1074	entry->ref_count++;
1075}
1076
1077static int
1078nfp_tunnel_add_shared_mac(struct nfp_app *app, struct net_device *netdev,
1079			  int port, bool mod)
1080{
1081	struct nfp_flower_priv *priv = app->priv;
1082	struct nfp_tun_offloaded_mac *entry;
1083	int ida_idx = -1, err;
1084	u16 nfp_mac_idx = 0;
1085
1086	entry = nfp_tunnel_lookup_offloaded_macs(app, netdev->dev_addr);
1087	if (entry && (nfp_tunnel_is_mac_idx_global(entry->index) || netif_is_lag_port(netdev))) {
1088		if (entry->bridge_count ||
1089		    !nfp_flower_is_supported_bridge(netdev)) {
1090			nfp_tunnel_offloaded_macs_inc_ref_and_link(entry,
1091								   netdev, mod);
1092			return 0;
1093		}
1094
1095		/* MAC is global but matches need to go to pre_tun table. */
1096		nfp_mac_idx = entry->index | NFP_TUN_PRE_TUN_IDX_BIT;
1097	}
1098
1099	if (!nfp_mac_idx) {
1100		/* Assign a global index if non-repr or MAC is now shared. */
1101		if (entry || !port) {
1102			ida_idx = ida_alloc_max(&priv->tun.mac_off_ids,
1103						NFP_MAX_MAC_INDEX, GFP_KERNEL);
1104			if (ida_idx < 0)
1105				return ida_idx;
1106
1107			nfp_mac_idx =
1108				nfp_tunnel_get_global_mac_idx_from_ida(ida_idx);
1109
1110			if (nfp_flower_is_supported_bridge(netdev))
1111				nfp_mac_idx |= NFP_TUN_PRE_TUN_IDX_BIT;
1112
1113		} else {
1114			nfp_mac_idx =
1115				nfp_tunnel_get_mac_idx_from_phy_port_id(port);
1116		}
1117	}
1118
1119	if (!entry) {
1120		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1121		if (!entry) {
1122			err = -ENOMEM;
1123			goto err_free_ida;
1124		}
1125
1126		ether_addr_copy(entry->addr, netdev->dev_addr);
1127		INIT_LIST_HEAD(&entry->repr_list);
1128
1129		if (rhashtable_insert_fast(&priv->tun.offloaded_macs,
1130					   &entry->ht_node,
1131					   offloaded_macs_params)) {
1132			err = -ENOMEM;
1133			goto err_free_entry;
1134		}
1135	}
1136
1137	err = __nfp_tunnel_offload_mac(app, netdev->dev_addr,
1138				       nfp_mac_idx, false);
1139	if (err) {
1140		/* If not shared then free. */
1141		if (!entry->ref_count)
1142			goto err_remove_hash;
1143		goto err_free_ida;
1144	}
1145
1146	entry->index = nfp_mac_idx;
1147	nfp_tunnel_offloaded_macs_inc_ref_and_link(entry, netdev, mod);
1148
1149	return 0;
1150
1151err_remove_hash:
1152	rhashtable_remove_fast(&priv->tun.offloaded_macs, &entry->ht_node,
1153			       offloaded_macs_params);
1154err_free_entry:
1155	kfree(entry);
1156err_free_ida:
1157	if (ida_idx != -1)
1158		ida_free(&priv->tun.mac_off_ids, ida_idx);
1159
1160	return err;
1161}
1162
1163static int
1164nfp_tunnel_del_shared_mac(struct nfp_app *app, struct net_device *netdev,
1165			  const u8 *mac, bool mod)
1166{
1167	struct nfp_flower_priv *priv = app->priv;
1168	struct nfp_flower_repr_priv *repr_priv;
1169	struct nfp_tun_offloaded_mac *entry;
1170	struct nfp_repr *repr;
1171	u16 nfp_mac_idx;
1172	int ida_idx;
1173
1174	entry = nfp_tunnel_lookup_offloaded_macs(app, mac);
1175	if (!entry)
1176		return 0;
1177
1178	entry->ref_count--;
1179	/* If del is part of a mod then mac_list is still in use elsewhere. */
1180	if (nfp_netdev_is_nfp_repr(netdev) && !mod) {
1181		repr = netdev_priv(netdev);
1182		repr_priv = repr->app_priv;
1183		list_del(&repr_priv->mac_list);
1184	}
1185
1186	if (nfp_flower_is_supported_bridge(netdev)) {
1187		entry->bridge_count--;
1188
1189		if (!entry->bridge_count && entry->ref_count) {
1190			nfp_mac_idx = entry->index & ~NFP_TUN_PRE_TUN_IDX_BIT;
1191			if (__nfp_tunnel_offload_mac(app, mac, nfp_mac_idx,
1192						     false)) {
1193				nfp_flower_cmsg_warn(app, "MAC offload index revert failed on %s.\n",
1194						     netdev_name(netdev));
1195				return 0;
1196			}
1197
1198			entry->index = nfp_mac_idx;
1199			return 0;
1200		}
1201	}
1202
1203	/* If MAC is now used by 1 repr set the offloaded MAC index to port. */
1204	if (entry->ref_count == 1 && list_is_singular(&entry->repr_list)) {
1205		int port, err;
1206
1207		repr_priv = list_first_entry(&entry->repr_list,
1208					     struct nfp_flower_repr_priv,
1209					     mac_list);
1210		repr = repr_priv->nfp_repr;
1211		port = nfp_repr_get_port_id(repr->netdev);
1212		nfp_mac_idx = nfp_tunnel_get_mac_idx_from_phy_port_id(port);
1213		err = __nfp_tunnel_offload_mac(app, mac, nfp_mac_idx, false);
1214		if (err) {
1215			nfp_flower_cmsg_warn(app, "MAC offload index revert failed on %s.\n",
1216					     netdev_name(netdev));
1217			return 0;
1218		}
1219
1220		ida_idx = nfp_tunnel_get_ida_from_global_mac_idx(entry->index);
1221		ida_free(&priv->tun.mac_off_ids, ida_idx);
1222		entry->index = nfp_mac_idx;
1223		return 0;
1224	}
1225
1226	if (entry->ref_count)
1227		return 0;
1228
1229	WARN_ON_ONCE(rhashtable_remove_fast(&priv->tun.offloaded_macs,
1230					    &entry->ht_node,
1231					    offloaded_macs_params));
1232
1233	if (nfp_flower_is_supported_bridge(netdev))
1234		nfp_mac_idx = entry->index & ~NFP_TUN_PRE_TUN_IDX_BIT;
1235	else
1236		nfp_mac_idx = entry->index;
1237
1238	/* If MAC has global ID then extract and free the ida entry. */
1239	if (nfp_tunnel_is_mac_idx_global(nfp_mac_idx)) {
1240		ida_idx = nfp_tunnel_get_ida_from_global_mac_idx(entry->index);
1241		ida_free(&priv->tun.mac_off_ids, ida_idx);
1242	}
1243
1244	kfree(entry);
1245
1246	return __nfp_tunnel_offload_mac(app, mac, 0, true);
1247}
1248
1249static int
1250nfp_tunnel_offload_mac(struct nfp_app *app, struct net_device *netdev,
1251		       enum nfp_flower_mac_offload_cmd cmd)
1252{
1253	struct nfp_flower_non_repr_priv *nr_priv = NULL;
1254	bool non_repr = false, *mac_offloaded;
1255	u8 *off_mac = NULL;
1256	int err, port = 0;
1257
1258	if (nfp_netdev_is_nfp_repr(netdev)) {
1259		struct nfp_flower_repr_priv *repr_priv;
1260		struct nfp_repr *repr;
1261
1262		repr = netdev_priv(netdev);
1263		if (repr->app != app)
1264			return 0;
1265
1266		repr_priv = repr->app_priv;
1267		if (repr_priv->on_bridge)
1268			return 0;
1269
1270		mac_offloaded = &repr_priv->mac_offloaded;
1271		off_mac = &repr_priv->offloaded_mac_addr[0];
1272		port = nfp_repr_get_port_id(netdev);
1273		if (!nfp_tunnel_port_is_phy_repr(port))
1274			return 0;
1275	} else if (nfp_fl_is_netdev_to_offload(netdev)) {
1276		nr_priv = nfp_flower_non_repr_priv_get(app, netdev);
1277		if (!nr_priv)
1278			return -ENOMEM;
1279
1280		mac_offloaded = &nr_priv->mac_offloaded;
1281		off_mac = &nr_priv->offloaded_mac_addr[0];
1282		non_repr = true;
1283	} else {
1284		return 0;
1285	}
1286
1287	if (!is_valid_ether_addr(netdev->dev_addr)) {
1288		err = -EINVAL;
1289		goto err_put_non_repr_priv;
1290	}
1291
1292	if (cmd == NFP_TUNNEL_MAC_OFFLOAD_MOD && !*mac_offloaded)
1293		cmd = NFP_TUNNEL_MAC_OFFLOAD_ADD;
1294
1295	switch (cmd) {
1296	case NFP_TUNNEL_MAC_OFFLOAD_ADD:
1297		err = nfp_tunnel_add_shared_mac(app, netdev, port, false);
1298		if (err)
1299			goto err_put_non_repr_priv;
1300
1301		if (non_repr)
1302			__nfp_flower_non_repr_priv_get(nr_priv);
1303
1304		*mac_offloaded = true;
1305		ether_addr_copy(off_mac, netdev->dev_addr);
1306		break;
1307	case NFP_TUNNEL_MAC_OFFLOAD_DEL:
1308		/* Only attempt delete if add was successful. */
1309		if (!*mac_offloaded)
1310			break;
1311
1312		if (non_repr)
1313			__nfp_flower_non_repr_priv_put(nr_priv);
1314
1315		*mac_offloaded = false;
1316
1317		err = nfp_tunnel_del_shared_mac(app, netdev, netdev->dev_addr,
1318						false);
1319		if (err)
1320			goto err_put_non_repr_priv;
1321
1322		break;
1323	case NFP_TUNNEL_MAC_OFFLOAD_MOD:
1324		/* Ignore if changing to the same address. */
1325		if (ether_addr_equal(netdev->dev_addr, off_mac))
1326			break;
1327
1328		err = nfp_tunnel_add_shared_mac(app, netdev, port, true);
1329		if (err)
1330			goto err_put_non_repr_priv;
1331
1332		/* Delete the previous MAC address. */
1333		err = nfp_tunnel_del_shared_mac(app, netdev, off_mac, true);
1334		if (err)
1335			nfp_flower_cmsg_warn(app, "Failed to remove offload of replaced MAC addr on %s.\n",
1336					     netdev_name(netdev));
1337
1338		ether_addr_copy(off_mac, netdev->dev_addr);
1339		break;
1340	default:
1341		err = -EINVAL;
1342		goto err_put_non_repr_priv;
1343	}
1344
1345	if (non_repr)
1346		__nfp_flower_non_repr_priv_put(nr_priv);
1347
1348	return 0;
1349
1350err_put_non_repr_priv:
1351	if (non_repr)
1352		__nfp_flower_non_repr_priv_put(nr_priv);
1353
1354	return err;
1355}
1356
1357int nfp_tunnel_mac_event_handler(struct nfp_app *app,
1358				 struct net_device *netdev,
1359				 unsigned long event, void *ptr)
1360{
1361	int err;
1362
1363	if (event == NETDEV_DOWN) {
1364		err = nfp_tunnel_offload_mac(app, netdev,
1365					     NFP_TUNNEL_MAC_OFFLOAD_DEL);
1366		if (err)
1367			nfp_flower_cmsg_warn(app, "Failed to delete offload MAC on %s.\n",
1368					     netdev_name(netdev));
1369	} else if (event == NETDEV_UP) {
1370		err = nfp_tunnel_offload_mac(app, netdev,
1371					     NFP_TUNNEL_MAC_OFFLOAD_ADD);
1372		if (err)
1373			nfp_flower_cmsg_warn(app, "Failed to offload MAC on %s.\n",
1374					     netdev_name(netdev));
1375	} else if (event == NETDEV_CHANGEADDR) {
1376		/* Only offload addr change if netdev is already up. */
1377		if (!(netdev->flags & IFF_UP))
1378			return NOTIFY_OK;
1379
1380		err = nfp_tunnel_offload_mac(app, netdev,
1381					     NFP_TUNNEL_MAC_OFFLOAD_MOD);
1382		if (err)
1383			nfp_flower_cmsg_warn(app, "Failed to offload MAC change on %s.\n",
1384					     netdev_name(netdev));
1385	} else if (event == NETDEV_CHANGEUPPER) {
1386		/* If a repr is attached to a bridge then tunnel packets
1387		 * entering the physical port are directed through the bridge
1388		 * datapath and cannot be directly detunneled. Therefore,
1389		 * associated offloaded MACs and indexes should not be used
1390		 * by fw for detunneling.
1391		 */
1392		struct netdev_notifier_changeupper_info *info = ptr;
1393		struct net_device *upper = info->upper_dev;
1394		struct nfp_flower_repr_priv *repr_priv;
1395		struct nfp_repr *repr;
1396
1397		if (!nfp_netdev_is_nfp_repr(netdev) ||
1398		    !nfp_flower_is_supported_bridge(upper))
1399			return NOTIFY_OK;
1400
1401		repr = netdev_priv(netdev);
1402		if (repr->app != app)
1403			return NOTIFY_OK;
1404
1405		repr_priv = repr->app_priv;
1406
1407		if (info->linking) {
1408			if (nfp_tunnel_offload_mac(app, netdev,
1409						   NFP_TUNNEL_MAC_OFFLOAD_DEL))
1410				nfp_flower_cmsg_warn(app, "Failed to delete offloaded MAC on %s.\n",
1411						     netdev_name(netdev));
1412			repr_priv->on_bridge = true;
1413		} else {
1414			repr_priv->on_bridge = false;
1415
1416			if (!(netdev->flags & IFF_UP))
1417				return NOTIFY_OK;
1418
1419			if (nfp_tunnel_offload_mac(app, netdev,
1420						   NFP_TUNNEL_MAC_OFFLOAD_ADD))
1421				nfp_flower_cmsg_warn(app, "Failed to offload MAC on %s.\n",
1422						     netdev_name(netdev));
1423		}
1424	}
1425	return NOTIFY_OK;
1426}
1427
1428int nfp_flower_xmit_pre_tun_flow(struct nfp_app *app,
1429				 struct nfp_fl_payload *flow)
1430{
1431	struct nfp_flower_priv *app_priv = app->priv;
1432	struct nfp_tun_offloaded_mac *mac_entry;
1433	struct nfp_flower_meta_tci *key_meta;
1434	struct nfp_tun_pre_tun_rule payload;
1435	struct net_device *internal_dev;
1436	int err;
1437
1438	if (app_priv->pre_tun_rule_cnt == NFP_TUN_PRE_TUN_RULE_LIMIT)
1439		return -ENOSPC;
1440
1441	memset(&payload, 0, sizeof(struct nfp_tun_pre_tun_rule));
1442
1443	internal_dev = flow->pre_tun_rule.dev;
1444	payload.vlan_tci = flow->pre_tun_rule.vlan_tci;
1445	payload.host_ctx_id = flow->meta.host_ctx_id;
1446
1447	/* Lookup MAC index for the pre-tunnel rule egress device.
1448	 * Note that because the device is always an internal port, it will
1449	 * have a constant global index so does not need to be tracked.
1450	 */
1451	mac_entry = nfp_tunnel_lookup_offloaded_macs(app,
1452						     internal_dev->dev_addr);
1453	if (!mac_entry)
1454		return -ENOENT;
1455
1456	/* Set/clear IPV6 bit. cpu_to_be16() swap will lead to MSB being
1457	 * set/clear for port_idx.
1458	 */
1459	key_meta = (struct nfp_flower_meta_tci *)flow->unmasked_data;
1460	if (key_meta->nfp_flow_key_layer & NFP_FLOWER_LAYER_IPV6)
1461		mac_entry->index |= NFP_TUN_PRE_TUN_IPV6_BIT;
1462	else
1463		mac_entry->index &= ~NFP_TUN_PRE_TUN_IPV6_BIT;
1464
1465	payload.port_idx = cpu_to_be16(mac_entry->index);
1466
1467	/* Copy mac id and vlan to flow - dev may not exist at delete time. */
1468	flow->pre_tun_rule.vlan_tci = payload.vlan_tci;
1469	flow->pre_tun_rule.port_idx = payload.port_idx;
1470
1471	err = nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_PRE_TUN_RULE,
1472				       sizeof(struct nfp_tun_pre_tun_rule),
1473				       (unsigned char *)&payload, GFP_KERNEL);
1474	if (err)
1475		return err;
1476
1477	app_priv->pre_tun_rule_cnt++;
1478
1479	return 0;
1480}
1481
1482int nfp_flower_xmit_pre_tun_del_flow(struct nfp_app *app,
1483				     struct nfp_fl_payload *flow)
1484{
1485	struct nfp_flower_priv *app_priv = app->priv;
1486	struct nfp_tun_pre_tun_rule payload;
1487	u32 tmp_flags = 0;
1488	int err;
1489
1490	memset(&payload, 0, sizeof(struct nfp_tun_pre_tun_rule));
1491
1492	tmp_flags |= NFP_TUN_PRE_TUN_RULE_DEL;
1493	payload.flags = cpu_to_be32(tmp_flags);
1494	payload.vlan_tci = flow->pre_tun_rule.vlan_tci;
1495	payload.port_idx = flow->pre_tun_rule.port_idx;
1496
1497	err = nfp_flower_xmit_tun_conf(app, NFP_FLOWER_CMSG_TYPE_PRE_TUN_RULE,
1498				       sizeof(struct nfp_tun_pre_tun_rule),
1499				       (unsigned char *)&payload, GFP_KERNEL);
1500	if (err)
1501		return err;
1502
1503	app_priv->pre_tun_rule_cnt--;
1504
1505	return 0;
1506}
1507
1508int nfp_tunnel_config_start(struct nfp_app *app)
1509{
1510	struct nfp_flower_priv *priv = app->priv;
1511	int err;
1512
1513	/* Initialise rhash for MAC offload tracking. */
1514	err = rhashtable_init(&priv->tun.offloaded_macs,
1515			      &offloaded_macs_params);
1516	if (err)
1517		return err;
1518
1519	ida_init(&priv->tun.mac_off_ids);
1520
1521	/* Initialise priv data for IPv4/v6 offloading. */
1522	mutex_init(&priv->tun.ipv4_off_lock);
1523	INIT_LIST_HEAD(&priv->tun.ipv4_off_list);
1524	mutex_init(&priv->tun.ipv6_off_lock);
1525	INIT_LIST_HEAD(&priv->tun.ipv6_off_list);
1526
1527	/* Initialise priv data for neighbour offloading. */
1528	priv->tun.neigh_nb.notifier_call = nfp_tun_neigh_event_handler;
1529
1530	err = register_netevent_notifier(&priv->tun.neigh_nb);
1531	if (err) {
1532		rhashtable_free_and_destroy(&priv->tun.offloaded_macs,
1533					    nfp_check_rhashtable_empty, NULL);
1534		return err;
1535	}
1536
1537	return 0;
1538}
1539
1540void nfp_tunnel_config_stop(struct nfp_app *app)
1541{
1542	struct nfp_flower_priv *priv = app->priv;
1543	struct nfp_ipv4_addr_entry *ip_entry;
1544	struct list_head *ptr, *storage;
1545
1546	unregister_netevent_notifier(&priv->tun.neigh_nb);
1547
1548	ida_destroy(&priv->tun.mac_off_ids);
1549
1550	/* Free any memory that may be occupied by ipv4 list. */
1551	list_for_each_safe(ptr, storage, &priv->tun.ipv4_off_list) {
1552		ip_entry = list_entry(ptr, struct nfp_ipv4_addr_entry, list);
1553		list_del(&ip_entry->list);
1554		kfree(ip_entry);
1555	}
1556
1557	mutex_destroy(&priv->tun.ipv6_off_lock);
1558
1559	/* Destroy rhash. Entries should be cleaned on netdev notifier unreg. */
1560	rhashtable_free_and_destroy(&priv->tun.offloaded_macs,
1561				    nfp_check_rhashtable_empty, NULL);
1562
1563	nfp_tun_cleanup_nn_entries(app);
1564}
~/ Read-only file preview.