Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 39b6b299 authored by David S. Miller's avatar David S. Miller
Browse files


Jesse Gross says:

====================
[GIT net-next] Open vSwitch

Open vSwitch changes for net-next/3.14. Highlights are:
 * Performance improvements in the mechanism to get packets to userspace
   using memory mapped netlink and skb zero copy where appropriate.
 * Per-cpu flow stats in situations where flows are likely to be shared
   across CPUs. Standard flow stats are used in other situations to save
   memory and allocation time.
 * A handful of code cleanups and rationalization.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 56a4342d 443cd88c
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -2445,6 +2445,9 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
		    struct pipe_inode_info *pipe, unsigned int len,
		    struct pipe_inode_info *pipe, unsigned int len,
		    unsigned int flags);
		    unsigned int flags);
void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
unsigned int skb_zerocopy_headlen(const struct sk_buff *from);
void skb_zerocopy(struct sk_buff *to, const struct sk_buff *from,
		  int len, int hlen);
void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len);
void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len);
int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
void skb_scrub_packet(struct sk_buff *skb, bool xnet);
void skb_scrub_packet(struct sk_buff *skb, bool xnet);
+4 −0
Original line number Original line Diff line number Diff line
@@ -73,6 +73,7 @@ struct genl_family {
 * @attrs: netlink attributes
 * @attrs: netlink attributes
 * @_net: network namespace
 * @_net: network namespace
 * @user_ptr: user pointers
 * @user_ptr: user pointers
 * @dst_sk: destination socket
 */
 */
struct genl_info {
struct genl_info {
	u32			snd_seq;
	u32			snd_seq;
@@ -85,6 +86,7 @@ struct genl_info {
	struct net *		_net;
	struct net *		_net;
#endif
#endif
	void *			user_ptr[2];
	void *			user_ptr[2];
	struct sock *		dst_sk;
};
};


static inline struct net *genl_info_net(struct genl_info *info)
static inline struct net *genl_info_net(struct genl_info *info)
@@ -177,6 +179,8 @@ void genl_notify(struct genl_family *family,
		 struct sk_buff *skb, struct net *net, u32 portid,
		 struct sk_buff *skb, struct net *net, u32 portid,
		 u32 group, struct nlmsghdr *nlh, gfp_t flags);
		 u32 group, struct nlmsghdr *nlh, gfp_t flags);


struct sk_buff *genlmsg_new_unicast(size_t payload, struct genl_info *info,
				    gfp_t flags);
void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
		  struct genl_family *family, int flags, u8 cmd);
		  struct genl_family *family, int flags, u8 cmd);


+13 −1
Original line number Original line Diff line number Diff line
@@ -40,7 +40,15 @@ struct ovs_header {


#define OVS_DATAPATH_FAMILY  "ovs_datapath"
#define OVS_DATAPATH_FAMILY  "ovs_datapath"
#define OVS_DATAPATH_MCGROUP "ovs_datapath"
#define OVS_DATAPATH_MCGROUP "ovs_datapath"
#define OVS_DATAPATH_VERSION 0x1

/* V2:
 *   - API users are expected to provide OVS_DP_ATTR_USER_FEATURES
 *     when creating the datapath.
 */
#define OVS_DATAPATH_VERSION 2

/* First OVS datapath version to support features */
#define OVS_DP_VER_FEATURES 2


enum ovs_datapath_cmd {
enum ovs_datapath_cmd {
	OVS_DP_CMD_UNSPEC,
	OVS_DP_CMD_UNSPEC,
@@ -75,6 +83,7 @@ enum ovs_datapath_attr {
	OVS_DP_ATTR_UPCALL_PID,		/* Netlink PID to receive upcalls */
	OVS_DP_ATTR_UPCALL_PID,		/* Netlink PID to receive upcalls */
	OVS_DP_ATTR_STATS,		/* struct ovs_dp_stats */
	OVS_DP_ATTR_STATS,		/* struct ovs_dp_stats */
	OVS_DP_ATTR_MEGAFLOW_STATS,	/* struct ovs_dp_megaflow_stats */
	OVS_DP_ATTR_MEGAFLOW_STATS,	/* struct ovs_dp_megaflow_stats */
	OVS_DP_ATTR_USER_FEATURES,	/* OVS_DP_F_*  */
	__OVS_DP_ATTR_MAX
	__OVS_DP_ATTR_MAX
};
};


@@ -106,6 +115,9 @@ struct ovs_vport_stats {
	__u64   tx_dropped;		/* no space available in linux  */
	__u64   tx_dropped;		/* no space available in linux  */
};
};


/* Allow last Netlink attribute to be unaligned */
#define OVS_DP_F_UNALIGNED	(1 << 0)

/* Fixed logical ports. */
/* Fixed logical ports. */
#define OVSP_LOCAL      ((__u32)0)
#define OVSP_LOCAL      ((__u32)0)


+85 −0
Original line number Original line Diff line number Diff line
@@ -2121,6 +2121,91 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
}
}
EXPORT_SYMBOL(skb_copy_and_csum_bits);
EXPORT_SYMBOL(skb_copy_and_csum_bits);


 /**
 *	skb_zerocopy_headlen - Calculate headroom needed for skb_zerocopy()
 *	@from: source buffer
 *
 *	Calculates the amount of linear headroom needed in the 'to' skb passed
 *	into skb_zerocopy().
 */
unsigned int
skb_zerocopy_headlen(const struct sk_buff *from)
{
	unsigned int hlen = 0;

	if (!from->head_frag ||
	    skb_headlen(from) < L1_CACHE_BYTES ||
	    skb_shinfo(from)->nr_frags >= MAX_SKB_FRAGS)
		hlen = skb_headlen(from);

	if (skb_has_frag_list(from))
		hlen = from->len;

	return hlen;
}
EXPORT_SYMBOL_GPL(skb_zerocopy_headlen);

/**
 *	skb_zerocopy - Zero copy skb to skb
 *	@to: destination buffer
 *	@source: source buffer
 *	@len: number of bytes to copy from source buffer
 *	@hlen: size of linear headroom in destination buffer
 *
 *	Copies up to `len` bytes from `from` to `to` by creating references
 *	to the frags in the source buffer.
 *
 *	The `hlen` as calculated by skb_zerocopy_headlen() specifies the
 *	headroom in the `to` buffer.
 */
void
skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
{
	int i, j = 0;
	int plen = 0; /* length of skb->head fragment */
	struct page *page;
	unsigned int offset;

	BUG_ON(!from->head_frag && !hlen);

	/* dont bother with small payloads */
	if (len <= skb_tailroom(to)) {
		skb_copy_bits(from, 0, skb_put(to, len), len);
		return;
	}

	if (hlen) {
		skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
		len -= hlen;
	} else {
		plen = min_t(int, skb_headlen(from), len);
		if (plen) {
			page = virt_to_head_page(from->head);
			offset = from->data - (unsigned char *)page_address(page);
			__skb_fill_page_desc(to, 0, page, offset, plen);
			get_page(page);
			j = 1;
			len -= plen;
		}
	}

	to->truesize += len + plen;
	to->len += len + plen;
	to->data_len += len + plen;

	for (i = 0; i < skb_shinfo(from)->nr_frags; i++) {
		if (!len)
			break;
		skb_shinfo(to)->frags[j] = skb_shinfo(from)->frags[i];
		skb_shinfo(to)->frags[j].size = min_t(int, skb_shinfo(to)->frags[j].size, len);
		len -= skb_shinfo(to)->frags[j].size;
		skb_frag_ref(to, j);
		j++;
	}
	skb_shinfo(to)->nr_frags = j;
}
EXPORT_SYMBOL_GPL(skb_zerocopy);

void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
{
{
	__wsum csum;
	__wsum csum;
+4 −55
Original line number Original line Diff line number Diff line
@@ -236,51 +236,6 @@ nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data)
	spin_unlock_bh(&queue->lock);
	spin_unlock_bh(&queue->lock);
}
}


static void
nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
{
	int i, j = 0;
	int plen = 0; /* length of skb->head fragment */
	struct page *page;
	unsigned int offset;

	/* dont bother with small payloads */
	if (len <= skb_tailroom(to)) {
		skb_copy_bits(from, 0, skb_put(to, len), len);
		return;
	}

	if (hlen) {
		skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
		len -= hlen;
	} else {
		plen = min_t(int, skb_headlen(from), len);
		if (plen) {
			page = virt_to_head_page(from->head);
			offset = from->data - (unsigned char *)page_address(page);
			__skb_fill_page_desc(to, 0, page, offset, plen);
			get_page(page);
			j = 1;
			len -= plen;
		}
	}

	to->truesize += len + plen;
	to->len += len + plen;
	to->data_len += len + plen;

	for (i = 0; i < skb_shinfo(from)->nr_frags; i++) {
		if (!len)
			break;
		skb_shinfo(to)->frags[j] = skb_shinfo(from)->frags[i];
		skb_shinfo(to)->frags[j].size = min_t(int, skb_shinfo(to)->frags[j].size, len);
		len -= skb_shinfo(to)->frags[j].size;
		skb_frag_ref(to, j);
		j++;
	}
	skb_shinfo(to)->nr_frags = j;
}

static int
static int
nfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet,
nfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet,
		      bool csum_verify)
		      bool csum_verify)
@@ -330,7 +285,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
{
{
	size_t size;
	size_t size;
	size_t data_len = 0, cap_len = 0;
	size_t data_len = 0, cap_len = 0;
	int hlen = 0;
	unsigned int hlen = 0;
	struct sk_buff *skb;
	struct sk_buff *skb;
	struct nlattr *nla;
	struct nlattr *nla;
	struct nfqnl_msg_packet_hdr *pmsg;
	struct nfqnl_msg_packet_hdr *pmsg;
@@ -382,14 +337,8 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
		if (data_len > entskb->len)
		if (data_len > entskb->len)
			data_len = entskb->len;
			data_len = entskb->len;


		if (!entskb->head_frag ||
		hlen = skb_zerocopy_headlen(entskb);
		    skb_headlen(entskb) < L1_CACHE_BYTES ||
		hlen = min_t(unsigned int, hlen, data_len);
		    skb_shinfo(entskb)->nr_frags >= MAX_SKB_FRAGS)
			hlen = skb_headlen(entskb);

		if (skb_has_frag_list(entskb))
			hlen = entskb->len;
		hlen = min_t(int, data_len, hlen);
		size += sizeof(struct nlattr) + hlen;
		size += sizeof(struct nlattr) + hlen;
		cap_len = entskb->len;
		cap_len = entskb->len;
		break;
		break;
@@ -539,7 +488,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
		nla->nla_type = NFQA_PAYLOAD;
		nla->nla_type = NFQA_PAYLOAD;
		nla->nla_len = nla_attr_size(data_len);
		nla->nla_len = nla_attr_size(data_len);


		nfqnl_zcopy(skb, entskb, data_len, hlen);
		skb_zerocopy(skb, entskb, data_len, hlen);
	}
	}


	nlh->nlmsg_len = skb->len;
	nlh->nlmsg_len = skb->len;
Loading