drivers/net/ethernet/mellanox/mlx5/core/en/rep/neigh.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/mellanox/mlx5/core/en/rep/neigh.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/mellanox/mlx5/core/en/rep/neigh.c
Extension
.c
Size
10889 bytes
Lines
400
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

struct neigh_update_work {
	struct work_struct work;
	struct neighbour *n;
	struct mlx5e_neigh_hash_entry *nhe;
};

static void mlx5e_release_neigh_update_work(struct neigh_update_work *update_work)
{
	neigh_release(update_work->n);
	mlx5e_rep_neigh_entry_release(update_work->nhe);
	kfree(update_work);
}

static void mlx5e_rep_neigh_update(struct work_struct *work)
{
	struct neigh_update_work *update_work = container_of(work, struct neigh_update_work,
							     work);
	struct mlx5e_neigh_hash_entry *nhe = update_work->nhe;
	struct neighbour *n = update_work->n;
	struct mlx5e_encap_entry *e = NULL;
	bool neigh_connected, same_dev;
	unsigned char ha[ETH_ALEN];
	u8 nud_state, dead;

	rtnl_lock();

	/* If these parameters are changed after we release the lock,
	 * we'll receive another event letting us know about it.
	 * We use this lock to avoid inconsistency between the neigh validity
	 * and it's hw address.
	 */
	read_lock_bh(&n->lock);
	memcpy(ha, n->ha, ETH_ALEN);
	nud_state = n->nud_state;
	dead = n->dead;
	same_dev = READ_ONCE(nhe->neigh_dev) == n->dev;
	read_unlock_bh(&n->lock);

	neigh_connected = (nud_state & NUD_VALID) && !dead;

	trace_mlx5e_rep_neigh_update(nhe, ha, neigh_connected);

	if (!same_dev)
		goto out;

	/* mlx5e_get_next_init_encap() releases previous encap before returning
	 * the next one.
	 */
	while ((e = mlx5e_get_next_init_encap(nhe, e)) != NULL)
		mlx5e_rep_update_flows(netdev_priv(e->out_dev), e, neigh_connected, ha);

out:
	rtnl_unlock();
	mlx5e_release_neigh_update_work(update_work);
}

static struct neigh_update_work *mlx5e_alloc_neigh_update_work(struct mlx5e_priv *priv,
							       struct neighbour *n)
{
	struct neigh_update_work *update_work;
	struct mlx5e_neigh_hash_entry *nhe;
	struct mlx5e_neigh m_neigh = {};

	update_work = kzalloc_obj(*update_work, GFP_ATOMIC);
	if (WARN_ON(!update_work))
		return NULL;

	m_neigh.family = n->ops->family;
	memcpy(&m_neigh.dst_ip, n->primary_key, n->tbl->key_len);

	/* Obtain reference to nhe as last step in order not to release it in
	 * atomic context.
	 */
	rcu_read_lock();
	nhe = mlx5e_rep_neigh_entry_lookup(priv, &m_neigh);
	rcu_read_unlock();
	if (!nhe) {
		kfree(update_work);
		return NULL;
	}

	INIT_WORK(&update_work->work, mlx5e_rep_neigh_update);
	neigh_hold(n);
	update_work->n = n;
	update_work->nhe = nhe;

	return update_work;
}

static int mlx5e_rep_netevent_event(struct notifier_block *nb,

Annotation

Implementation Notes