drivers/net/ethernet/sfc/tc_encap_actions.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/sfc/tc_encap_actions.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/sfc/tc_encap_actions.c
Extension
.c
Size
22094 bytes
Lines
753
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (encap->type & EFX_ENCAP_FLAG_IPV6) {
#if IS_ENABLED(CONFIG_IPV6)
			struct dst_entry *dst;

			dst = ip6_dst_lookup_flow(net, NULL, &flow6, NULL);
			rc = PTR_ERR_OR_ZERO(dst);
			if (rc) {
				NL_SET_ERR_MSG_MOD(extack, "Failed to lookup route for IPv6 encap");
				goto out_free;
			}
			neigh->egdev = dst->dev;
			netdev_hold(neigh->egdev, &neigh->dev_tracker,
				    GFP_KERNEL_ACCOUNT);
			neigh->ttl = ip6_dst_hoplimit(dst);
			n = dst_neigh_lookup(dst, &flow6.daddr);
			dst_release(dst);
#else
			/* We shouldn't ever get here, because if IPv6 isn't
			 * enabled how did someone create an IPv6 tunnel_key?
			 */
			rc = -EOPNOTSUPP;
			NL_SET_ERR_MSG_MOD(extack, "No IPv6 support (neigh bind)");
			goto out_free;
#endif
		} else {
			rt = ip_route_output_key(net, &flow4);
			if (IS_ERR_OR_NULL(rt)) {
				rc = PTR_ERR_OR_ZERO(rt);
				if (!rc)
					rc = -EIO;
				NL_SET_ERR_MSG_MOD(extack, "Failed to lookup route for encap");
				goto out_free;
			}
			neigh->egdev = rt->dst.dev;
			netdev_hold(neigh->egdev, &neigh->dev_tracker,
				    GFP_KERNEL_ACCOUNT);
			neigh->ttl = ip4_dst_hoplimit(&rt->dst);
			n = dst_neigh_lookup(&rt->dst, &flow4.daddr);
			ip_rt_put(rt);
		}
		if (!n) {
			rc = -ENETUNREACH;
			NL_SET_ERR_MSG_MOD(extack, "Failed to lookup neighbour for encap");
			netdev_put(neigh->egdev, &neigh->dev_tracker);
			goto out_free;
		}
		refcount_set(&neigh->ref, 1);
		INIT_LIST_HEAD(&neigh->users);
		read_lock_bh(&n->lock);
		ether_addr_copy(neigh->ha, n->ha);
		neigh->n_valid = n->nud_state & NUD_VALID;
		read_unlock_bh(&n->lock);
		rwlock_init(&neigh->lock);
		INIT_WORK(&neigh->work, efx_neigh_update);
		neigh->efx = efx;
		neigh->used = jiffies;
		if (!neigh->n_valid)
			/* Prod ARP to find us a neighbour */
			neigh_event_send(n, NULL);
		neigh_release(n);
	}
	/* Add us to this neigh */
	encap->neigh = neigh;
	list_add_tail(&encap->list, &neigh->users);
	return 0;

out_free:
	/* cleanup common to several error paths */
	rhashtable_remove_fast(&efx->tc->neigh_ht, &neigh->linkage,
			       efx_neigh_ht_params);
	synchronize_rcu();
	put_net_track(net, &neigh->ns_tracker);
	kfree(neigh);
	return rc;
}

static void efx_free_neigh(struct efx_neigh_binder *neigh)
{
	struct efx_nic *efx = neigh->efx;

	rhashtable_remove_fast(&efx->tc->neigh_ht, &neigh->linkage,
			       efx_neigh_ht_params);
	synchronize_rcu();
	netdev_put(neigh->egdev, &neigh->dev_tracker);
	put_net_track(neigh->net, &neigh->ns_tracker);
	kfree(neigh);
}

static void efx_release_neigh(struct efx_nic *efx,
			      struct efx_tc_encap_action *encap)

Annotation

Implementation Notes