aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/core/skbuff.c85
-rw-r--r--net/netfilter/nfnetlink_queue_core.c59
2 files changed, 89 insertions, 55 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;
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c
index 21258cf70091..615ee12647ae 100644
--- a/net/netfilter/nfnetlink_queue_core.c
+++ b/net/netfilter/nfnetlink_queue_core.c
@@ -235,51 +235,6 @@ nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data)
235 spin_unlock_bh(&queue->lock); 235 spin_unlock_bh(&queue->lock);
236} 236}
237 237
238static void
239nfqnl_zcopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
240{
241 int i, j = 0;
242 int plen = 0; /* length of skb->head fragment */
243 struct page *page;
244 unsigned int offset;
245
246 /* dont bother with small payloads */
247 if (len <= skb_tailroom(to)) {
248 skb_copy_bits(from, 0, skb_put(to, len), len);
249 return;
250 }
251
252 if (hlen) {
253 skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
254 len -= hlen;
255 } else {
256 plen = min_t(int, skb_headlen(from), len);
257 if (plen) {
258 page = virt_to_head_page(from->head);
259 offset = from->data - (unsigned char *)page_address(page);
260 __skb_fill_page_desc(to, 0, page, offset, plen);
261 get_page(page);
262 j = 1;
263 len -= plen;
264 }
265 }
266
267 to->truesize += len + plen;
268 to->len += len + plen;
269 to->data_len += len + plen;
270
271 for (i = 0; i < skb_shinfo(from)->nr_frags; i++) {
272 if (!len)
273 break;
274 skb_shinfo(to)->frags[j] = skb_shinfo(from)->frags[i];
275 skb_shinfo(to)->frags[j].size = min_t(int, skb_shinfo(to)->frags[j].size, len);
276 len -= skb_shinfo(to)->frags[j].size;
277 skb_frag_ref(to, j);
278 j++;
279 }
280 skb_shinfo(to)->nr_frags = j;
281}
282
283static int 238static int
284nfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet, 239nfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet,
285 bool csum_verify) 240 bool csum_verify)
@@ -304,7 +259,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
304{ 259{
305 size_t size; 260 size_t size;
306 size_t data_len = 0, cap_len = 0; 261 size_t data_len = 0, cap_len = 0;
307 int hlen = 0; 262 unsigned int hlen = 0;
308 struct sk_buff *skb; 263 struct sk_buff *skb;
309 struct nlattr *nla; 264 struct nlattr *nla;
310 struct nfqnl_msg_packet_hdr *pmsg; 265 struct nfqnl_msg_packet_hdr *pmsg;
@@ -356,14 +311,8 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
356 if (data_len > entskb->len) 311 if (data_len > entskb->len)
357 data_len = entskb->len; 312 data_len = entskb->len;
358 313
359 if (!entskb->head_frag || 314 hlen = skb_zerocopy_headlen(entskb);
360 skb_headlen(entskb) < L1_CACHE_BYTES || 315 hlen = min_t(unsigned int, hlen, data_len);
361 skb_shinfo(entskb)->nr_frags >= MAX_SKB_FRAGS)
362 hlen = skb_headlen(entskb);
363
364 if (skb_has_frag_list(entskb))
365 hlen = entskb->len;
366 hlen = min_t(int, data_len, hlen);
367 size += sizeof(struct nlattr) + hlen; 316 size += sizeof(struct nlattr) + hlen;
368 cap_len = entskb->len; 317 cap_len = entskb->len;
369 break; 318 break;
@@ -504,7 +453,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
504 nla->nla_type = NFQA_PAYLOAD; 453 nla->nla_type = NFQA_PAYLOAD;
505 nla->nla_len = nla_attr_size(data_len); 454 nla->nla_len = nla_attr_size(data_len);
506 455
507 nfqnl_zcopy(skb, entskb, data_len, hlen); 456 skb_zerocopy(skb, entskb, data_len, hlen);
508 } 457 }
509 458
510 nlh->nlmsg_len = skb->len; 459 nlh->nlmsg_len = skb->len;