Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/jesse/openvswitch
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: David S. Miller <davem@davemloft.net>
This commit is contained in:
@ -2121,6 +2121,91 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
|
||||
}
|
||||
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)
|
||||
{
|
||||
__wsum csum;
|
||||
|
Reference in New Issue
Block a user