834 lines · 21.6 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* bpf/cpumap.c * * Copyright (c) 2017 Jesper Dangaard Brouer, Red Hat Inc. */ /** * DOC: cpu map * The 'cpumap' is primarily used as a backend map for XDP BPF helper * call bpf_redirect_map() and XDP_REDIRECT action, like 'devmap'. * * Unlike devmap which redirects XDP frames out to another NIC device, * this map type redirects raw XDP frames to another CPU.  The remote * CPU will do SKB-allocation and call the normal network stack. *//* * This is a scalability and isolation mechanism, that allow * separating the early driver network XDP layer, from the rest of the * netstack, and assigning dedicated CPUs for this stage.  This * basically allows for 10G wirespeed pre-filtering via bpf. */#include <linux/bitops.h>#include <linux/bpf.h>#include <linux/filter.h>#include <linux/ptr_ring.h>#include <net/xdp.h>#include <net/hotdata.h> #include <linux/sched.h>#include <linux/workqueue.h>#include <linux/kthread.h>#include <linux/local_lock.h>#include <linux/completion.h>#include <trace/events/xdp.h>#include <linux/btf_ids.h> #include <linux/netdevice.h>#include <net/gro.h> /* General idea: XDP packets getting XDP redirected to another CPU, * will maximum be stored/queued for one driver ->poll() call.  It is * guaranteed that queueing the frame and the flush operation happen on * same CPU.  Thus, cpu_map_flush operation can deduct via this_cpu_ptr() * which queue in bpf_cpu_map_entry contains packets. */ #define CPU_MAP_BULK_SIZE 8  /* 8 == one cacheline on 64-bit archs */struct bpf_cpu_map_entry;struct bpf_cpu_map; struct xdp_bulk_queue {	void *q[CPU_MAP_BULK_SIZE];	struct list_head flush_node;	struct bpf_cpu_map_entry *obj;	unsigned int count;	local_lock_t bq_lock;}; /* Struct for every remote "destination" CPU in map */struct bpf_cpu_map_entry {	u32 cpu;    /* kthread CPU and map index */	int map_id; /* Back reference to map */ 	/* XDP can run multiple RX-ring queues, need __percpu enqueue store */	struct xdp_bulk_queue __percpu *bulkq; 	/* Queue with potential multi-producers, and single-consumer kthread */	struct ptr_ring *queue;	struct task_struct *kthread; 	struct bpf_cpumap_val value;	struct bpf_prog *prog;	struct gro_node gro; 	struct completion kthread_running;	struct rcu_work free_work;}; struct bpf_cpu_map {	struct bpf_map map;	/* Below members specific for map type */	struct bpf_cpu_map_entry __rcu **cpu_map;}; static struct bpf_map *cpu_map_alloc(union bpf_attr *attr){	u32 value_size = attr->value_size;	struct bpf_cpu_map *cmap; 	/* check sanity of attributes */	if (attr->max_entries == 0 || attr->key_size != 4 ||	    (value_size != offsetofend(struct bpf_cpumap_val, qsize) &&	     value_size != offsetofend(struct bpf_cpumap_val, bpf_prog.fd)) ||	    attr->map_flags & ~BPF_F_NUMA_NODE)		return ERR_PTR(-EINVAL); 	/* Pre-limit array size based on NR_CPUS, not final CPU check */	if (attr->max_entries > NR_CPUS)		return ERR_PTR(-E2BIG); 	cmap = bpf_map_area_alloc(sizeof(*cmap), NUMA_NO_NODE);	if (!cmap)		return ERR_PTR(-ENOMEM); 	bpf_map_init_from_attr(&cmap->map, attr); 	/* Alloc array for possible remote "destination" CPUs */	cmap->cpu_map = bpf_map_area_alloc(cmap->map.max_entries *					   sizeof(struct bpf_cpu_map_entry *),					   cmap->map.numa_node);	if (!cmap->cpu_map) {		bpf_map_area_free(cmap);		return ERR_PTR(-ENOMEM);	} 	return &cmap->map;} static void __cpu_map_ring_cleanup(struct ptr_ring *ring){	/* The tear-down procedure should have made sure that queue is	 * empty.  See __cpu_map_entry_replace() and work-queue	 * invoked cpu_map_kthread_stop(). Catch any broken behaviour	 * gracefully and warn once.	 */	void *ptr; 	while ((ptr = ptr_ring_consume(ring))) {		WARN_ON_ONCE(1);		if (unlikely(__ptr_test_bit(0, &ptr))) {			__ptr_clear_bit(0, &ptr);			kfree_skb(ptr);			continue;		}		xdp_return_frame(ptr);	}} static u32 cpu_map_bpf_prog_run_skb(struct bpf_cpu_map_entry *rcpu,				    void **skbs, u32 skb_n,				    struct xdp_cpumap_stats *stats){	struct xdp_buff xdp;	u32 act, pass = 0;	int err; 	for (u32 i = 0; i < skb_n; i++) {		struct sk_buff *skb = skbs[i]; 		act = bpf_prog_run_generic_xdp(skb, &xdp, rcpu->prog);		switch (act) {		case XDP_PASS:			skbs[pass++] = skb;			break;		case XDP_REDIRECT:			err = xdp_do_generic_redirect(skb->dev, skb, &xdp,						      rcpu->prog);			if (unlikely(err)) {				kfree_skb(skb);				stats->drop++;			} else {				stats->redirect++;			}			break;		default:			bpf_warn_invalid_xdp_action(NULL, rcpu->prog, act);			fallthrough;		case XDP_ABORTED:			trace_xdp_exception(skb->dev, rcpu->prog, act);			fallthrough;		case XDP_DROP:			napi_consume_skb(skb, true);			stats->drop++;			break;		}	} 	stats->pass += pass; 	return pass;} static int cpu_map_bpf_prog_run_xdp(struct bpf_cpu_map_entry *rcpu,				    void **frames, int n,				    struct xdp_cpumap_stats *stats){	struct xdp_rxq_info rxq = {};	struct xdp_buff xdp;	int i, nframes = 0; 	xdp.rxq = &rxq; 	for (i = 0; i < n; i++) {		struct xdp_frame *xdpf = frames[i];		u32 act;		int err; 		rxq.dev = xdpf->dev_rx;		rxq.mem.type = xdpf->mem_type;		/* TODO: report queue_index to xdp_rxq_info */ 		xdp_convert_frame_to_buff(xdpf, &xdp); 		act = bpf_prog_run_xdp(rcpu->prog, &xdp);		switch (act) {		case XDP_PASS:			err = xdp_update_frame_from_buff(&xdp, xdpf);			if (err < 0) {				xdp_return_frame(xdpf);				stats->drop++;			} else {				frames[nframes++] = xdpf;			}			break;		case XDP_REDIRECT:			err = xdp_do_redirect(xdpf->dev_rx, &xdp,					      rcpu->prog);			if (unlikely(err)) {				xdp_return_frame(xdpf);				stats->drop++;			} else {				stats->redirect++;			}			break;		default:			bpf_warn_invalid_xdp_action(xdpf->dev_rx, rcpu->prog, act);			fallthrough;		case XDP_ABORTED:			trace_xdp_exception(xdpf->dev_rx, rcpu->prog, act);			fallthrough;		case XDP_DROP:			xdp_return_frame(xdpf);			stats->drop++;			break;		}	} 	stats->pass += nframes; 	return nframes;} #define CPUMAP_BATCH 8 struct cpu_map_ret {	u32 xdp_n;	u32 skb_n;}; static void cpu_map_bpf_prog_run(struct bpf_cpu_map_entry *rcpu, void **frames,				 void **skbs, struct cpu_map_ret *ret,				 struct xdp_cpumap_stats *stats){	struct bpf_net_context __bpf_net_ctx, *bpf_net_ctx; 	if (!rcpu->prog)		goto out; 	rcu_read_lock();	bpf_net_ctx = bpf_net_ctx_set(&__bpf_net_ctx);	xdp_set_return_frame_no_direct(); 	ret->xdp_n = cpu_map_bpf_prog_run_xdp(rcpu, frames, ret->xdp_n, stats);	if (unlikely(ret->skb_n))		ret->skb_n = cpu_map_bpf_prog_run_skb(rcpu, skbs, ret->skb_n,						      stats); 	if (stats->redirect)		xdp_do_flush(); 	xdp_clear_return_frame_no_direct();	bpf_net_ctx_clear(bpf_net_ctx);	rcu_read_unlock(); out:	if (unlikely(ret->skb_n) && ret->xdp_n)		memmove(&skbs[ret->xdp_n], skbs, ret->skb_n * sizeof(*skbs));} static void cpu_map_gro_flush(struct bpf_cpu_map_entry *rcpu, bool empty){	/*	 * If the ring is not empty, there'll be a new iteration soon, and we	 * only need to do a full flush if a tick is long (> 1 ms).	 * If the ring is empty, to not hold GRO packets in the stack for too	 * long, do a full flush.	 * This is equivalent to how NAPI decides whether to perform a full	 * flush.	 */	gro_flush_normal(&rcpu->gro, !empty && HZ >= 1000);} static int cpu_map_kthread_run(void *data){	struct bpf_cpu_map_entry *rcpu = data;	unsigned long last_qs = jiffies;	u32 packets = 0; 	complete(&rcpu->kthread_running);	set_current_state(TASK_INTERRUPTIBLE); 	/* When kthread gives stop order, then rcpu have been disconnected	 * from map, thus no new packets can enter. Remaining in-flight	 * per CPU stored packets are flushed to this queue.  Wait honoring	 * kthread_stop signal until queue is empty.	 */	while (!kthread_should_stop() || !__ptr_ring_empty(rcpu->queue)) {		struct xdp_cpumap_stats stats = {}; /* zero stats */		unsigned int kmem_alloc_drops = 0, sched = 0;		struct cpu_map_ret ret = { };		void *frames[CPUMAP_BATCH];		void *skbs[CPUMAP_BATCH];		u32 i, n, m;		bool empty; 		/* Release CPU reschedule checks */		if (__ptr_ring_empty(rcpu->queue)) {			set_current_state(TASK_INTERRUPTIBLE);			/* Recheck to avoid lost wake-up */			if (__ptr_ring_empty(rcpu->queue)) {				schedule();				sched = 1;				last_qs = jiffies;			} else {				__set_current_state(TASK_RUNNING);			}		} else {			rcu_softirq_qs_periodic(last_qs);			sched = cond_resched();		} 		/*		 * The bpf_cpu_map_entry is single consumer, with this		 * kthread CPU pinned. Lockless access to ptr_ring		 * consume side valid as no-resize allowed of queue.		 */		n = __ptr_ring_consume_batched(rcpu->queue, frames,					       CPUMAP_BATCH);		for (i = 0; i < n; i++) {			void *f = frames[i];			struct page *page; 			if (unlikely(__ptr_test_bit(0, &f))) {				struct sk_buff *skb = f; 				__ptr_clear_bit(0, &skb);				skbs[ret.skb_n++] = skb;				continue;			} 			frames[ret.xdp_n++] = f;			page = virt_to_page(f); 			/* Bring struct page memory area to curr CPU. Read by			 * build_skb_around via page_is_pfmemalloc(), and when			 * freed written by page_frag_free call.			 */			prefetchw(page);		} 		local_bh_disable(); 		/* Support running another XDP prog on this CPU */		cpu_map_bpf_prog_run(rcpu, frames, skbs, &ret, &stats);		if (!ret.xdp_n)			goto stats; 		m = napi_skb_cache_get_bulk(skbs, ret.xdp_n);		if (unlikely(m < ret.xdp_n)) {			for (i = m; i < ret.xdp_n; i++)				xdp_return_frame(frames[i]); 			if (ret.skb_n)				memmove(&skbs[m], &skbs[ret.xdp_n],					ret.skb_n * sizeof(*skbs)); 			kmem_alloc_drops += ret.xdp_n - m;			ret.xdp_n = m;		} 		for (i = 0; i < ret.xdp_n; i++) {			struct xdp_frame *xdpf = frames[i]; 			/* Can fail only when !skb -- already handled above */			__xdp_build_skb_from_frame(xdpf, skbs[i], xdpf->dev_rx);		} stats:		/* Feedback loop via tracepoint.		 * NB: keep before recv to allow measuring enqueue/dequeue latency.		 */		trace_xdp_cpumap_kthread(rcpu->map_id, n, kmem_alloc_drops,					 sched, &stats); 		for (i = 0; i < ret.xdp_n + ret.skb_n; i++)			gro_receive_skb(&rcpu->gro, skbs[i]); 		/* Flush either every 64 packets or in case of empty ring */		packets += n;		empty = __ptr_ring_empty(rcpu->queue);		if (packets >= NAPI_POLL_WEIGHT || empty) {			cpu_map_gro_flush(rcpu, empty);			packets = 0;		} 		local_bh_enable(); /* resched point, may call do_softirq() */	}	__set_current_state(TASK_RUNNING); 	return 0;} static int __cpu_map_load_bpf_program(struct bpf_cpu_map_entry *rcpu,				      struct bpf_map *map, int fd){	struct bpf_prog *prog; 	prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP);	if (IS_ERR(prog))		return PTR_ERR(prog); 	if (prog->expected_attach_type != BPF_XDP_CPUMAP ||	    !bpf_prog_map_compatible(map, prog)) {		bpf_prog_put(prog);		return -EINVAL;	} 	rcpu->value.bpf_prog.id = prog->aux->id;	rcpu->prog = prog; 	return 0;} static struct bpf_cpu_map_entry *__cpu_map_entry_alloc(struct bpf_map *map, struct bpf_cpumap_val *value,		      u32 cpu){	int numa, err = -ENOMEM, i, fd = value->bpf_prog.fd;	gfp_t gfp = GFP_KERNEL | __GFP_NOWARN;	struct bpf_cpu_map_entry *rcpu;	struct xdp_bulk_queue *bq; 	/* Have map->numa_node, but choose node of redirect target CPU */	numa = cpu_to_node(cpu); 	rcpu = bpf_map_kmalloc_node(map, sizeof(*rcpu), gfp | __GFP_ZERO, numa);	if (!rcpu)		return ERR_PTR(err); 	/* Alloc percpu bulkq */	rcpu->bulkq = bpf_map_alloc_percpu(map, sizeof(*rcpu->bulkq),					   sizeof(void *), gfp);	if (!rcpu->bulkq)		goto free_rcu; 	for_each_possible_cpu(i) {		bq = per_cpu_ptr(rcpu->bulkq, i);		bq->obj = rcpu;		local_lock_init(&bq->bq_lock);	} 	/* Alloc queue */	rcpu->queue = bpf_map_kmalloc_node(map, sizeof(*rcpu->queue), gfp,					   numa);	if (!rcpu->queue)		goto free_bulkq; 	err = ptr_ring_init(rcpu->queue, value->qsize, gfp);	if (err)		goto free_queue; 	rcpu->cpu    = cpu;	rcpu->map_id = map->id;	rcpu->value.qsize  = value->qsize;	gro_init(&rcpu->gro); 	if (fd > 0) {		err = __cpu_map_load_bpf_program(rcpu, map, fd);		if (err)			goto free_ptr_ring;	} 	/* Setup kthread */	init_completion(&rcpu->kthread_running);	rcpu->kthread = kthread_create_on_node(cpu_map_kthread_run, rcpu, numa,					       "cpumap/%d/map:%d", cpu,					       map->id);	if (IS_ERR(rcpu->kthread)) {		err = PTR_ERR(rcpu->kthread);		goto free_prog;	} 	/* Make sure kthread runs on a single CPU */	kthread_bind(rcpu->kthread, cpu);	wake_up_process(rcpu->kthread); 	/* Make sure kthread has been running, so kthread_stop() will not	 * stop the kthread prematurely and all pending frames or skbs	 * will be handled by the kthread before kthread_stop() returns.	 */

Lines 1–500 of 834.