aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
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/netfilter
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/netfilter')
-rw-r--r--net/netfilter/nfnetlink_queue_core.c59
1 files changed, 4 insertions, 55 deletions
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;