diff options
author | David S. Miller <davem@davemloft.net> | 2014-01-06 19:48:38 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-01-06 19:48:38 -0500 |
commit | 39b6b2992f9dc65d1de5c66e7ec2271b8a5fac33 (patch) | |
tree | c0fc4e2be0429bb4d7643e6b6f8f5a56212f9284 /net/core | |
parent | 56a4342dfe3145cd66f766adccb28fd9b571606d (diff) | |
parent | 443cd88c8a31379e95326428bbbd40af25c1d440 (diff) |
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>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/skbuff.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index eb96c2c22400..1d641e781f85 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -2121,6 +2121,91 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, | |||
2121 | } | 2121 | } |
2122 | EXPORT_SYMBOL(skb_copy_and_csum_bits); | 2122 | EXPORT_SYMBOL(skb_copy_and_csum_bits); |
2123 | 2123 | ||
2124 | /** | ||
2125 | * skb_zerocopy_headlen - Calculate headroom needed for skb_zerocopy() | ||
2126 | * @from: source buffer | ||
2127 | * | ||
2128 | * Calculates the amount of linear headroom needed in the 'to' skb passed | ||
2129 | * into skb_zerocopy(). | ||
2130 | */ | ||
2131 | unsigned int | ||
2132 | skb_zerocopy_headlen(const struct sk_buff *from) | ||
2133 | { | ||
2134 | unsigned int hlen = 0; | ||
2135 | |||
2136 | if (!from->head_frag || | ||
2137 | skb_headlen(from) < L1_CACHE_BYTES || | ||
2138 | skb_shinfo(from)->nr_frags >= MAX_SKB_FRAGS) | ||
2139 | hlen = skb_headlen(from); | ||
2140 | |||
2141 | if (skb_has_frag_list(from)) | ||
2142 | hlen = from->len; | ||
2143 | |||
2144 | return hlen; | ||
2145 | } | ||
2146 | EXPORT_SYMBOL_GPL(skb_zerocopy_headlen); | ||
2147 | |||
2148 | /** | ||
2149 | * skb_zerocopy - Zero copy skb to skb | ||
2150 | * @to: destination buffer | ||
2151 | * @source: source buffer | ||
2152 | * @len: number of bytes to copy from source buffer | ||
2153 | * @hlen: size of linear headroom in destination buffer | ||
2154 | * | ||
2155 | * Copies up to `len` bytes from `from` to `to` by creating references | ||
2156 | * to the frags in the source buffer. | ||
2157 | * | ||
2158 | * The `hlen` as calculated by skb_zerocopy_headlen() specifies the | ||
2159 | * headroom in the `to` buffer. | ||
2160 | */ | ||
2161 | void | ||
2162 | skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen) | ||
2163 | { | ||
2164 | int i, j = 0; | ||
2165 | int plen = 0; /* length of skb->head fragment */ | ||
2166 | struct page *page; | ||
2167 | unsigned int offset; | ||
2168 | |||
2169 | BUG_ON(!from->head_frag && !hlen); | ||
2170 | |||
2171 | /* dont bother with small payloads */ | ||
2172 | if (len <= skb_tailroom(to)) { | ||
2173 | skb_copy_bits(from, 0, skb_put(to, len), len); | ||
2174 | return; | ||
2175 | } | ||
2176 | |||
2177 | if (hlen) { | ||
2178 | skb_copy_bits(from, 0, skb_put(to, hlen), hlen); | ||
2179 | len -= hlen; | ||
2180 | } else { | ||
2181 | plen = min_t(int, skb_headlen(from), len); | ||
2182 | if (plen) { | ||
2183 | page = virt_to_head_page(from->head); | ||
2184 | offset = from->data - (unsigned char *)page_address(page); | ||
2185 | __skb_fill_page_desc(to, 0, page, offset, plen); | ||
2186 | get_page(page); | ||
2187 | j = 1; | ||
2188 | len -= plen; | ||
2189 | } | ||
2190 | } | ||
2191 | |||
2192 | to->truesize += len + plen; | ||
2193 | to->len += len + plen; | ||
2194 | to->data_len += len + plen; | ||
2195 | |||
2196 | for (i = 0; i < skb_shinfo(from)->nr_frags; i++) { | ||
2197 | if (!len) | ||
2198 | break; | ||
2199 | skb_shinfo(to)->frags[j] = skb_shinfo(from)->frags[i]; | ||
2200 | skb_shinfo(to)->frags[j].size = min_t(int, skb_shinfo(to)->frags[j].size, len); | ||
2201 | len -= skb_shinfo(to)->frags[j].size; | ||
2202 | skb_frag_ref(to, j); | ||
2203 | j++; | ||
2204 | } | ||
2205 | skb_shinfo(to)->nr_frags = j; | ||
2206 | } | ||
2207 | EXPORT_SYMBOL_GPL(skb_zerocopy); | ||
2208 | |||
2124 | void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to) | 2209 | void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to) |
2125 | { | 2210 | { |
2126 | __wsum csum; | 2211 | __wsum csum; |