network allocator, entirely zero-copy sniffer.
Subsystems (2)
PATCH 1/1 network allocator, entirely zero-copy sniffer.
Hello.
Attached patch implements fully zero-copy sniffer based on network allocator [1]. Userspace utlity can be found on NTA home page.
Design notes.
Network allocator steals pages from main system allocator and use them for all network allocations (it's benefits are behind the scope of zero-copy sniffer description, one can find network allocator features on project's homepage [1]), thus it is possible to mmap all stolen pages from userspace and provide special structure for each allocated chunk into userspace which include offset from the begining of the node (each node contains contiguous page-aligned memory region), node number and other info. Since network allocator tracks number of users for for each memory region, when the last one completes with data procesing (for example userspace sniffer), it must commit that area back to allocator, so NTA relies on correct values returned from userspace (if returned from userspace chunk is not valid, it will not be freed, but if userspace will not "free" chunks (by sending info about them back to kernel) eventually maximum allowed number of shared free regions is achieved and no more data will be sent to userspace (and be allowed to be shared).
Since by default network tree allocator is used for all network allocations (including unix sockets and netlink), sniffer will get all those data and must somehow differentiate between them. That task is out of the scope for this mail though, simple solution is just to attach network allocator to network device (i.e. call NTA allocation functions from netdev_alloc_skb() only).
I never run any special performance tests, but simple "top" command shows much smaller CPU usage for zero-copy sniffer (although it gets all data from every skbs in the machine) compared to tcpdump - 17% vs. 33% maximum on my test machine.
Both sniffers dump received data into /dev/null.
Server side (where sniffers run) runs epoll based trivial web server, client side runs httperf.
Machines are connected over 100mbit LAN (e100 server NIC, 8169 client NIC).
For zero-copy userspace netchannels I plan to only send to userspace information about allocations which really belong to created netchannel instead of info for each chunk.
Sending zero-copy support is in TODO.
Thank you.
1. Network (formerly tree) allocator.
http://tservice.net.ru/~s0mbre/old/?section=projects&item=nta
include/linux/skbuff.h +4 -0
@@ -327,6 +327,10 @@ #include <linux/slab.h>#include <asm/system.h> +extern void *avl_alloc (unsigned int size,gfp_t gfp_mask); +extern void avl_free (void *ptr,unsigned int size); +extern int avl_init (void ); +extern void kfree_skb (struct sk_buff *skb);extern void __kfree_skb (struct sk_buff *skb); extern struct sk_buff *__alloc_skb(unsigned int size,
net/core/Makefile +2 -0
@@ -10,6 +10,8 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core. obj-y += dev.o ethtool.o dev_mcast.o dst.o netevent.o \ neighbour.o rtnetlink.o utils.o link_watch.o filter.o +obj-y += alloc/ + obj-$(CONFIG_XFRM) += flow.o obj-$(CONFIG_SYSFS) += net-sysfs.o obj-$(CONFIG_NET_DIVERT) += dv.o
net/core/alloc/Makefile new file +3 -0
@@ -0,0 +1,3 @@ +obj-y := allocator.o + +allocator-y := avl.o zc.o
net/core/alloc/avl.c new file +730 -0
730 lines not on this page · raw message
net/core/alloc/avl.h new file +178 -0
178 lines not on this page · raw message
net/core/alloc/zc.c new file +258 -0
258 lines not on this page · raw message
net/core/skbuff.c +7 -4
@@ -156,7 +156,7 @@ struct sk_buff *__alloc_skb(unsigned int/* Get the DATA. Size must match skb_add_mtu(). */ size =SKB_DATA_ALIGN (size); - data =____kmalloc (size +sizeof (struct skb_shared_info ), gfp_mask); + data =avl_alloc (size +sizeof (struct skb_shared_info ), gfp_mask);if (!data) goto nodata;
@@ -223,7 +223,7 @@ struct sk_buff *alloc_skb_from_cache(kme/* Get the DATA. */ size =SKB_DATA_ALIGN (size); - data =kmem_cache_alloc (cp, gfp_mask); + data =avl_alloc (size, gfp_mask);if (!data) goto nodata;
@@ -313,7 +313,7 @@ static void skb_release_data(struct sk_bif (skb_shinfo (skb)->frag_list)skb_drop_fraglist (skb); -kfree (skb->head); +avl_free (skb->head, skb->end - skb->head +sizeof (struct skb_shared_info )); } }
@@ -688,7 +688,7 @@ int pskb_expand_head(struct sk_buff *skb size =SKB_DATA_ALIGN (size); - data =kmalloc (size +sizeof (struct skb_shared_info ), gfp_mask); + data =avl_alloc (size +sizeof (struct skb_shared_info ), gfp_mask);if (!data) goto nodata;
@@ -2057,6 +2057,9 @@ void __init skb_init(void) NULL, NULL);if (!skbuff_fclone_cache)panic ("cannot create skbuff cache" ); + +if (avl_init ()) +panic ("Failed to initialize network tree allocator.\n" ); }EXPORT_SYMBOL (___pskb_trim);
Signature · 1 line
Evgeniy Polyakov