aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2013-12-13 09:22:17 -0500
committerJesse Gross <jesse@nicira.com>2014-01-06 18:52:42 -0500
commitaf2806f8f90a150160be898cd85332459c83c5cb (patch)
treed3476ee225083ad769e8d2374b840a4af0816560 /net/core
parent5f03f47c9c05086e181db3ec7a809f8454e28370 (diff)
net: Export skb_zerocopy() to zerocopy from one skb to another
Make the skb zerocopy logic written for nfnetlink queue available for use by other modules. Signed-off-by: Thomas Graf <tgraf@suug.ch> Reviewed-by: Daniel Borkmann <dborkman@redhat.com> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: Jesse Gross <jesse@nicira.com>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/skbuff.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 2718fed53d8c..55859cb8b83d 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2122,6 +2122,91 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
2122} 2122}
2123EXPORT_SYMBOL(skb_copy_and_csum_bits); 2123EXPORT_SYMBOL(skb_copy_and_csum_bits);
2124 2124
2125 /**
2126 * skb_zerocopy_headlen - Calculate headroom needed for skb_zerocopy()
2127 * @from: source buffer
2128 *
2129 * Calculates the amount of linear headroom needed in the 'to' skb passed
2130 * into skb_zerocopy().
2131 */
2132unsigned int
2133skb_zerocopy_headlen(const struct sk_buff *from)
2134{
2135 unsigned int hlen = 0;
2136
2137 if (!from->head_frag ||
2138 skb_headlen(from) < L1_CACHE_BYTES ||
2139 skb_shinfo(from)->nr_frags >= MAX_SKB_FRAGS)
2140 hlen = skb_headlen(from);
2141
2142 if (skb_has_frag_list(from))
2143 hlen = from->len;
2144
2145 return hlen;
2146}
2147EXPORT_SYMBOL_GPL(skb_zerocopy_headlen);
2148
2149/**
2150 * skb_zerocopy - Zero copy skb to skb
2151 * @to: destination buffer
2152 * @source: source buffer
2153 * @len: number of bytes to copy from source buffer
2154 * @hlen: size of linear headroom in destination buffer
2155 *
2156 * Copies up to `len` bytes from `from` to `to` by creating references
2157 * to the frags in the source buffer.
2158 *
2159 * The `hlen` as calculated by skb_zerocopy_headlen() specifies the
2160 * headroom in the `to` buffer.
2161 */
2162void
2163skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
2164{
2165 int i, j = 0;
2166 int plen = 0; /* length of skb->head fragment */
2167 struct page *page;
2168 unsigned int offset;
2169
2170 BUG_ON(!from->head_frag && !hlen);
2171
2172 /* dont bother with small payloads */
2173 if (len <= skb_tailroom(to)) {
2174 skb_copy_bits(from, 0, skb_put(to, len), len);
2175 return;
2176 }
2177
2178 if (hlen) {
2179 skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
2180 len -= hlen;
2181 } else {
2182 plen = min_t(int, skb_headlen(from), len);
2183 if (plen) {
2184 page = virt_to_head_page(from->head);
2185 offset = from->data - (unsigned char *)page_address(page);
2186 __skb_fill_page_desc(to, 0, page, offset, plen);
2187 get_page(page);
2188 j = 1;
2189 len -= plen;
2190 }
2191 }
2192
2193 to->truesize += len + plen;
2194 to->len += len + plen;
2195 to->data_len += len + plen;
2196
2197 for (i = 0; i < skb_shinfo(from)->nr_frags; i++) {
2198 if (!len)
2199 break;
2200 skb_shinfo(to)->frags[j] = skb_shinfo(from)->frags[i];
2201 skb_shinfo(to)->frags[j].size = min_t(int, skb_shinfo(to)->frags[j].size, len);
2202 len -= skb_shinfo(to)->frags[j].size;
2203 skb_frag_ref(to, j);
2204 j++;
2205 }
2206 skb_shinfo(to)->nr_frags = j;
2207}
2208EXPORT_SYMBOL_GPL(skb_zerocopy);
2209
2125void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to) 2210void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
2126{ 2211{
2127 __wsum csum; 2212 __wsum csum;