net/core/netpoll.c

Source file repositories/reference/linux-study-clean/net/core/netpoll.c

File Facts

System
Linux kernel
Corpus path
net/core/netpoll.c
Extension
.c
Size
16441 bytes
Lines
702
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: operation-table or driver-model contract
Status
pattern 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

const struct net_device_ops *ops;

	/* Don't do any rx activity if the dev_lock mutex is held
	 * the dev_open/close paths use this to block netpoll activity
	 * while changing device state
	 */
	if (!ni || down_trylock(&ni->dev_lock))
		return;

	/* Some drivers will take the same locks in poll and xmit,
	 * we can't poll if local CPU is already in xmit.
	 */
	if (!netif_running(dev) || netif_local_xmit_active(dev)) {
		up(&ni->dev_lock);
		return;
	}

	ops = dev->netdev_ops;
	if (ops->ndo_poll_controller)
		ops->ndo_poll_controller(dev);

	poll_napi(dev);

	up(&ni->dev_lock);

	netpoll_zap_completion_queue();
}
EXPORT_SYMBOL(netpoll_poll_dev);

void netpoll_poll_disable(struct net_device *dev)
{
	struct netpoll_info *ni;

	might_sleep();
	ni = rtnl_dereference(dev->npinfo);
	if (ni)
		down(&ni->dev_lock);
}

void netpoll_poll_enable(struct net_device *dev)
{
	struct netpoll_info *ni;

	ni = rtnl_dereference(dev->npinfo);
	if (ni)
		up(&ni->dev_lock);
}

static void refill_skbs(struct netpoll *np)
{
	struct sk_buff_head *skb_pool;
	struct sk_buff *skb;

	skb_pool = &np->skb_pool;

	while (READ_ONCE(skb_pool->qlen) < MAX_SKBS) {
		skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
		if (!skb)
			break;

		skb_queue_tail(skb_pool, skb);
	}
}

void netpoll_zap_completion_queue(void)
{
	unsigned long flags;
	struct softnet_data *sd = &get_cpu_var(softnet_data);

	if (sd->completion_queue) {
		struct sk_buff *clist;

		local_irq_save(flags);
		clist = sd->completion_queue;
		sd->completion_queue = NULL;
		local_irq_restore(flags);

		while (clist != NULL) {
			struct sk_buff *skb = clist;
			clist = clist->next;
			if (!skb_irq_freeable(skb)) {
				refcount_set(&skb->users, 1);
				dev_kfree_skb_any(skb); /* put this one back */
			} else {
				__kfree_skb(skb);
			}
		}
	}

	put_cpu_var(softnet_data);

Annotation

Implementation Notes