net/devlink/netlink.c

Source file repositories/reference/linux-study-clean/net/devlink/netlink.c

File Facts

System
Linux kernel
Corpus path
net/devlink/netlink.c
Extension
.c
Size
10700 bytes
Lines
413
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

struct devlink_nl_sock_priv {
	struct devlink_obj_desc __rcu *flt;
	spinlock_t flt_lock; /* Protects flt. */
};

static void devlink_nl_sock_priv_init(void *priv)
{
	struct devlink_nl_sock_priv *sk_priv = priv;

	spin_lock_init(&sk_priv->flt_lock);
}

static void devlink_nl_sock_priv_destroy(void *priv)
{
	struct devlink_nl_sock_priv *sk_priv = priv;
	struct devlink_obj_desc *flt;

	flt = rcu_dereference_protected(sk_priv->flt, true);
	kfree_rcu(flt, rcu);
}

int devlink_nl_notify_filter_set_doit(struct sk_buff *skb,
				      struct genl_info *info)
{
	struct devlink_nl_sock_priv *sk_priv;
	struct nlattr **attrs = info->attrs;
	struct devlink_obj_desc *flt;
	size_t data_offset = 0;
	size_t data_size = 0;
	char *pos;

	if (attrs[DEVLINK_ATTR_BUS_NAME])
		data_size = size_add(data_size,
				     nla_len(attrs[DEVLINK_ATTR_BUS_NAME]) + 1);
	if (attrs[DEVLINK_ATTR_DEV_NAME])
		data_size = size_add(data_size,
				     nla_len(attrs[DEVLINK_ATTR_DEV_NAME]) + 1);

	flt = kzalloc(size_add(sizeof(*flt), data_size), GFP_KERNEL);
	if (!flt)
		return -ENOMEM;

	pos = (char *) flt->data;
	if (attrs[DEVLINK_ATTR_BUS_NAME]) {
		data_offset += nla_strscpy(pos,
					   attrs[DEVLINK_ATTR_BUS_NAME],
					   data_size) + 1;
		flt->bus_name = pos;
		pos += data_offset;
	}
	if (attrs[DEVLINK_ATTR_DEV_NAME]) {
		nla_strscpy(pos, attrs[DEVLINK_ATTR_DEV_NAME],
			    data_size - data_offset);
		flt->dev_name = pos;
	}

	if (attrs[DEVLINK_ATTR_INDEX]) {
		flt->devlink_index = nla_get_uint(attrs[DEVLINK_ATTR_INDEX]);
		flt->devlink_index_valid = true;
	}

	if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
		flt->port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
		flt->port_index_valid = true;
	}

	/* Don't attach empty filter. */
	if (!flt->bus_name && !flt->dev_name &&
	    !flt->devlink_index_valid && !flt->port_index_valid) {
		kfree(flt);
		flt = NULL;
	}

	sk_priv = genl_sk_priv_get(&devlink_nl_family, NETLINK_CB(skb).sk);
	if (IS_ERR(sk_priv)) {
		kfree(flt);
		return PTR_ERR(sk_priv);
	}
	spin_lock(&sk_priv->flt_lock);
	flt = rcu_replace_pointer(sk_priv->flt, flt,
				  lockdep_is_held(&sk_priv->flt_lock));
	spin_unlock(&sk_priv->flt_lock);
	kfree_rcu(flt, rcu);
	return 0;
}

static bool devlink_obj_desc_match(const struct devlink_obj_desc *desc,
				   const struct devlink_obj_desc *flt)
{
	if (desc->devlink_index_valid && flt->devlink_index_valid &&

Annotation

Implementation Notes