mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	mmapped netlink has a number of unresolved issues: - TX zerocopy support had to be disabled more than a year ago via commit4682a03586("netlink: Always copy on mmap TX.") because the content of the mmapped area can change after netlink attribute validation but before message processing. - RX support was implemented mainly to speed up nfqueue dumping packet payload to userspace. However, since commitae08ce0021("netfilter: nfnetlink_queue: zero copy support") we avoid one copy with the socket-based interface too (via the skb_zerocopy helper). The other problem is that skbs attached to mmaped netlink socket behave different from normal skbs: - they don't have a shinfo area, so all functions that use skb_shinfo() (e.g. skb_clone) cannot be used. - reserving headroom prevents userspace from seeing the content as it expects message to start at skb->head. See for instance commitaa3a022094("netlink: not trim skb for mmaped socket when dump"). - skbs handed e.g. to netlink_ack must have non-NULL skb->sk, else we crash because it needs the sk to check if a tx ring is attached. Also not obvious, leads to non-intuitive bug fixes such as7c7bdf359("netfilter: nfnetlink: use original skbuff when acking batches"). mmaped netlink also didn't play nicely with the skb_zerocopy helper used by nfqueue and openvswitch. Daniel Borkmann fixed this via commit6bb0fef489("netlink, mmap: fix edge-case leakages in nf queue zero-copy")' but at the cost of also needing to provide remaining length to the allocation function. nfqueue also has problems when used with mmaped rx netlink: - mmaped netlink doesn't allow use of nfqueue batch verdict messages. Problem is that in the mmap case, the allocation time also determines the ordering in which the frame will be seen by userspace (A allocating before B means that A is located in earlier ring slot, but this also means that B might get a lower sequence number then A since seqno is decided later. To fix this we would need to extend the spinlocked region to also cover the allocation and message setup which isn't desirable. - nfqueue can now be configured to queue large (GSO) skbs to userspace. Queing GSO packets is faster than having to force a software segmentation in the kernel, so this is a desirable option. However, with a mmap based ring one has to use 64kb per ring slot element, else mmap has to fall back to the socket path (NL_MMAP_STATUS_COPY) for all large packets. To use the mmap interface, userspace not only has to probe for mmap netlink support, it also has to implement a recv/socket receive path in order to handle messages that exceed the size of an rx ring element. Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: Ken-ichirou MATSUZAWA <chamaken@gmail.com> Cc: Pablo Neira Ayuso <pablo@netfilter.org> Cc: Patrick McHardy <kaber@trash.net> Cc: Thomas Graf <tgraf@suug.ch> Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: David S. Miller <davem@davemloft.net>
		
			
				
	
	
		
			74 lines
		
	
	
	
		
			1.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			74 lines
		
	
	
	
		
			1.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#ifndef _AF_NETLINK_H
 | 
						|
#define _AF_NETLINK_H
 | 
						|
 | 
						|
#include <linux/rhashtable.h>
 | 
						|
#include <linux/atomic.h>
 | 
						|
#include <net/sock.h>
 | 
						|
 | 
						|
#define NLGRPSZ(x)	(ALIGN(x, sizeof(unsigned long) * 8) / 8)
 | 
						|
#define NLGRPLONGS(x)	(NLGRPSZ(x)/sizeof(unsigned long))
 | 
						|
 | 
						|
struct netlink_ring {
 | 
						|
	void			**pg_vec;
 | 
						|
	unsigned int		head;
 | 
						|
	unsigned int		frames_per_block;
 | 
						|
	unsigned int		frame_size;
 | 
						|
	unsigned int		frame_max;
 | 
						|
 | 
						|
	unsigned int		pg_vec_order;
 | 
						|
	unsigned int		pg_vec_pages;
 | 
						|
	unsigned int		pg_vec_len;
 | 
						|
 | 
						|
	atomic_t		pending;
 | 
						|
};
 | 
						|
 | 
						|
struct netlink_sock {
 | 
						|
	/* struct sock has to be the first member of netlink_sock */
 | 
						|
	struct sock		sk;
 | 
						|
	u32			portid;
 | 
						|
	u32			dst_portid;
 | 
						|
	u32			dst_group;
 | 
						|
	u32			flags;
 | 
						|
	u32			subscriptions;
 | 
						|
	u32			ngroups;
 | 
						|
	unsigned long		*groups;
 | 
						|
	unsigned long		state;
 | 
						|
	size_t			max_recvmsg_len;
 | 
						|
	wait_queue_head_t	wait;
 | 
						|
	bool			bound;
 | 
						|
	bool			cb_running;
 | 
						|
	struct netlink_callback	cb;
 | 
						|
	struct mutex		*cb_mutex;
 | 
						|
	struct mutex		cb_def_mutex;
 | 
						|
	void			(*netlink_rcv)(struct sk_buff *skb);
 | 
						|
	int			(*netlink_bind)(struct net *net, int group);
 | 
						|
	void			(*netlink_unbind)(struct net *net, int group);
 | 
						|
	struct module		*module;
 | 
						|
 | 
						|
	struct rhash_head	node;
 | 
						|
	struct rcu_head		rcu;
 | 
						|
};
 | 
						|
 | 
						|
static inline struct netlink_sock *nlk_sk(struct sock *sk)
 | 
						|
{
 | 
						|
	return container_of(sk, struct netlink_sock, sk);
 | 
						|
}
 | 
						|
 | 
						|
struct netlink_table {
 | 
						|
	struct rhashtable	hash;
 | 
						|
	struct hlist_head	mc_list;
 | 
						|
	struct listeners __rcu	*listeners;
 | 
						|
	unsigned int		flags;
 | 
						|
	unsigned int		groups;
 | 
						|
	struct mutex		*cb_mutex;
 | 
						|
	struct module		*module;
 | 
						|
	int			(*bind)(struct net *net, int group);
 | 
						|
	void			(*unbind)(struct net *net, int group);
 | 
						|
	bool			(*compare)(struct net *net, struct sock *sock);
 | 
						|
	int			registered;
 | 
						|
};
 | 
						|
 | 
						|
extern struct netlink_table *nl_table;
 | 
						|
extern rwlock_t nl_table_lock;
 | 
						|
 | 
						|
#endif
 |