datapath: Orphan frags in skb_zerocopy and handle errors
[cascardo/ovs.git] / datapath / linux / compat / skbuff-openvswitch.c
1 #include <linux/module.h>
2 #include <linux/netdevice.h>
3 #include <linux/skbuff.h>
4
5 #if !defined(HAVE_SKB_WARN_LRO) && defined(NETIF_F_LRO)
6
7 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8
9 void __skb_warn_lro_forwarding(const struct sk_buff *skb)
10 {
11         if (net_ratelimit())
12                 pr_warn("%s: received packets cannot be forwarded while LRO is enabled\n",
13                         skb->dev->name);
14 }
15
16 #endif
17
18 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
19
20 static inline bool head_frag(const struct sk_buff *skb)
21 {
22 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0)
23         return skb->head_frag;
24 #else
25         return false;
26 #endif
27 }
28
29  /**
30  *      skb_zerocopy_headlen - Calculate headroom needed for skb_zerocopy()
31  *      @from: source buffer
32  *
33  *      Calculates the amount of linear headroom needed in the 'to' skb passed
34  *      into skb_zerocopy().
35  */
36 unsigned int
37 skb_zerocopy_headlen(const struct sk_buff *from)
38 {
39         unsigned int hlen = 0;
40
41         if (!head_frag(from) ||
42             skb_headlen(from) < L1_CACHE_BYTES ||
43             skb_shinfo(from)->nr_frags >= MAX_SKB_FRAGS)
44                 hlen = skb_headlen(from);
45
46         if (skb_has_frag_list(from))
47                 hlen = from->len;
48
49         return hlen;
50 }
51
52 /**
53  *      skb_zerocopy - Zero copy skb to skb
54  *      @to: destination buffer
55  *      @source: source buffer
56  *      @len: number of bytes to copy from source buffer
57  *      @hlen: size of linear headroom in destination buffer
58  *
59  *      Copies up to `len` bytes from `from` to `to` by creating references
60  *      to the frags in the source buffer.
61  *
62  *      The `hlen` as calculated by skb_zerocopy_headlen() specifies the
63  *      headroom in the `to` buffer.
64  *
65  *      Return value:
66  *      0: everything is OK
67  *      -ENOMEM: couldn't orphan frags of @from due to lack of memory
68  *      -EFAULT: skb_copy_bits() found some problem with skb geometry
69  */
70 int
71 skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
72 {
73         int i, j = 0;
74         int plen = 0; /* length of skb->head fragment */
75         int ret;
76         struct page *page;
77         unsigned int offset;
78
79         BUG_ON(!head_frag(from) && !hlen);
80
81         /* dont bother with small payloads */
82         if (len <= skb_tailroom(to))
83                 return skb_copy_bits(from, 0, skb_put(to, len), len);
84
85         if (hlen) {
86                 ret = skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
87                 if (unlikely(ret))
88                         return ret;
89                 len -= hlen;
90         } else {
91                 plen = min_t(int, skb_headlen(from), len);
92                 if (plen) {
93                         page = virt_to_head_page(from->head);
94                         offset = from->data - (unsigned char *)page_address(page);
95                         __skb_fill_page_desc(to, 0, page, offset, plen);
96                         get_page(page);
97                         j = 1;
98                         len -= plen;
99                 }
100         }
101
102         to->truesize += len + plen;
103         to->len += len + plen;
104         to->data_len += len + plen;
105
106         if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) {
107                 skb_tx_error(from);
108                 return -ENOMEM;
109         }
110
111         for (i = 0; i < skb_shinfo(from)->nr_frags; i++) {
112                 if (!len)
113                         break;
114                 skb_shinfo(to)->frags[j] = skb_shinfo(from)->frags[i];
115                 skb_shinfo(to)->frags[j].size = min_t(int, skb_shinfo(to)->frags[j].size, len);
116                 len -= skb_shinfo(to)->frags[j].size;
117                 skb_frag_ref(to, j);
118                 j++;
119         }
120         skb_shinfo(to)->nr_frags = j;
121
122         return 0;
123 }
124 #endif