diff options
author | Thomas Graf <tgraf@suug.ch> | 2013-12-13 09:22:17 -0500 |
---|---|---|
committer | Jesse Gross <jesse@nicira.com> | 2014-01-06 18:52:42 -0500 |
commit | af2806f8f90a150160be898cd85332459c83c5cb (patch) | |
tree | d3476ee225083ad769e8d2374b840a4af0816560 /net/core | |
parent | 5f03f47c9c05086e181db3ec7a809f8454e28370 (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.c | 85 |
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 | } |
2123 | EXPORT_SYMBOL(skb_copy_and_csum_bits); | 2123 | EXPORT_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 | */ | ||
2132 | unsigned int | ||
2133 | skb_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 | } | ||
2147 | EXPORT_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 | */ | ||
2162 | void | ||
2163 | skb_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 | } | ||
2208 | EXPORT_SYMBOL_GPL(skb_zerocopy); | ||
2209 | |||
2125 | void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to) | 2210 | void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to) |
2126 | { | 2211 | { |
2127 | __wsum csum; | 2212 | __wsum csum; |