Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/core/gso.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
#include <linux/skbuff.h>
3
#include <linux/sctp.h>
4
#include <net/gso.h>
5
#include <net/gro.h>
6
7
/**
8
* skb_eth_gso_segment - segmentation handler for ethernet protocols.
9
* @skb: buffer to segment
10
* @features: features for the output path (see dev->features)
11
* @type: Ethernet Protocol ID
12
*/
13
struct sk_buff *skb_eth_gso_segment(struct sk_buff *skb,
14
netdev_features_t features, __be16 type)
15
{
16
struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
17
struct packet_offload *ptype;
18
19
rcu_read_lock();
20
list_for_each_entry_rcu(ptype, &net_hotdata.offload_base, list) {
21
if (ptype->type == type && ptype->callbacks.gso_segment) {
22
segs = ptype->callbacks.gso_segment(skb, features);
23
break;
24
}
25
}
26
rcu_read_unlock();
27
28
return segs;
29
}
30
EXPORT_SYMBOL(skb_eth_gso_segment);
31
32
/**
33
* skb_mac_gso_segment - mac layer segmentation handler.
34
* @skb: buffer to segment
35
* @features: features for the output path (see dev->features)
36
*/
37
struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
38
netdev_features_t features)
39
{
40
struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
41
struct packet_offload *ptype;
42
int vlan_depth = skb->mac_len;
43
__be16 type = skb_network_protocol(skb, &vlan_depth);
44
45
if (unlikely(!type))
46
return ERR_PTR(-EINVAL);
47
48
__skb_pull(skb, vlan_depth);
49
50
rcu_read_lock();
51
list_for_each_entry_rcu(ptype, &net_hotdata.offload_base, list) {
52
if (ptype->type == type && ptype->callbacks.gso_segment) {
53
segs = ptype->callbacks.gso_segment(skb, features);
54
break;
55
}
56
}
57
rcu_read_unlock();
58
59
__skb_push(skb, skb->data - skb_mac_header(skb));
60
61
return segs;
62
}
63
EXPORT_SYMBOL(skb_mac_gso_segment);
64
/* openvswitch calls this on rx path, so we need a different check.
65
*/
66
static bool skb_needs_check(const struct sk_buff *skb, bool tx_path)
67
{
68
if (tx_path)
69
return skb->ip_summed != CHECKSUM_PARTIAL &&
70
skb->ip_summed != CHECKSUM_UNNECESSARY;
71
72
return skb->ip_summed == CHECKSUM_NONE;
73
}
74
75
/**
76
* __skb_gso_segment - Perform segmentation on skb.
77
* @skb: buffer to segment
78
* @features: features for the output path (see dev->features)
79
* @tx_path: whether it is called in TX path
80
*
81
* This function segments the given skb and returns a list of segments.
82
*
83
* It may return NULL if the skb requires no segmentation. This is
84
* only possible when GSO is used for verifying header integrity.
85
*
86
* Segmentation preserves SKB_GSO_CB_OFFSET bytes of previous skb cb.
87
*/
88
struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
89
netdev_features_t features, bool tx_path)
90
{
91
struct sk_buff *segs;
92
93
if (unlikely(skb_needs_check(skb, tx_path))) {
94
int err;
95
96
/* We're going to init ->check field in TCP or UDP header */
97
err = skb_cow_head(skb, 0);
98
if (err < 0)
99
return ERR_PTR(err);
100
}
101
102
/* Only report GSO partial support if it will enable us to
103
* support segmentation on this frame without needing additional
104
* work.
105
*/
106
if (features & NETIF_F_GSO_PARTIAL) {
107
netdev_features_t partial_features = NETIF_F_GSO_ROBUST;
108
struct net_device *dev = skb->dev;
109
110
partial_features |= dev->features & dev->gso_partial_features;
111
if (!skb_gso_ok(skb, features | partial_features))
112
features &= ~NETIF_F_GSO_PARTIAL;
113
}
114
115
BUILD_BUG_ON(SKB_GSO_CB_OFFSET +
116
sizeof(*SKB_GSO_CB(skb)) > sizeof(skb->cb));
117
118
SKB_GSO_CB(skb)->mac_offset = skb_headroom(skb);
119
SKB_GSO_CB(skb)->encap_level = 0;
120
121
skb_reset_mac_header(skb);
122
skb_reset_mac_len(skb);
123
124
segs = skb_mac_gso_segment(skb, features);
125
126
if (segs != skb && unlikely(skb_needs_check(skb, tx_path) && !IS_ERR(segs)))
127
skb_warn_bad_offload(skb);
128
129
return segs;
130
}
131
EXPORT_SYMBOL(__skb_gso_segment);
132
133
/**
134
* skb_gso_transport_seglen - Return length of individual segments of a gso packet
135
*
136
* @skb: GSO skb
137
*
138
* skb_gso_transport_seglen is used to determine the real size of the
139
* individual segments, including Layer4 headers (TCP/UDP).
140
*
141
* The MAC/L2 or network (IP, IPv6) headers are not accounted for.
142
*/
143
static unsigned int skb_gso_transport_seglen(const struct sk_buff *skb)
144
{
145
const struct skb_shared_info *shinfo = skb_shinfo(skb);
146
unsigned int thlen = 0;
147
148
if (skb->encapsulation) {
149
thlen = skb_inner_transport_header(skb) -
150
skb_transport_header(skb);
151
152
if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))
153
thlen += inner_tcp_hdrlen(skb);
154
} else if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
155
thlen = tcp_hdrlen(skb);
156
} else if (unlikely(skb_is_gso_sctp(skb))) {
157
thlen = sizeof(struct sctphdr);
158
} else if (shinfo->gso_type & SKB_GSO_UDP_L4) {
159
thlen = sizeof(struct udphdr);
160
}
161
/* UFO sets gso_size to the size of the fragmentation
162
* payload, i.e. the size of the L4 (UDP) header is already
163
* accounted for.
164
*/
165
return thlen + shinfo->gso_size;
166
}
167
168
/**
169
* skb_gso_network_seglen - Return length of individual segments of a gso packet
170
*
171
* @skb: GSO skb
172
*
173
* skb_gso_network_seglen is used to determine the real size of the
174
* individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP).
175
*
176
* The MAC/L2 header is not accounted for.
177
*/
178
static unsigned int skb_gso_network_seglen(const struct sk_buff *skb)
179
{
180
unsigned int hdr_len = skb_transport_header(skb) -
181
skb_network_header(skb);
182
183
return hdr_len + skb_gso_transport_seglen(skb);
184
}
185
186
/**
187
* skb_gso_mac_seglen - Return length of individual segments of a gso packet
188
*
189
* @skb: GSO skb
190
*
191
* skb_gso_mac_seglen is used to determine the real size of the
192
* individual segments, including MAC/L2, Layer3 (IP, IPv6) and L4
193
* headers (TCP/UDP).
194
*/
195
static unsigned int skb_gso_mac_seglen(const struct sk_buff *skb)
196
{
197
unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
198
199
return hdr_len + skb_gso_transport_seglen(skb);
200
}
201
202
/**
203
* skb_gso_size_check - check the skb size, considering GSO_BY_FRAGS
204
*
205
* There are a couple of instances where we have a GSO skb, and we
206
* want to determine what size it would be after it is segmented.
207
*
208
* We might want to check:
209
* - L3+L4+payload size (e.g. IP forwarding)
210
* - L2+L3+L4+payload size (e.g. sanity check before passing to driver)
211
*
212
* This is a helper to do that correctly considering GSO_BY_FRAGS.
213
*
214
* @skb: GSO skb
215
*
216
* @seg_len: The segmented length (from skb_gso_*_seglen). In the
217
* GSO_BY_FRAGS case this will be [header sizes + GSO_BY_FRAGS].
218
*
219
* @max_len: The maximum permissible length.
220
*
221
* Returns true if the segmented length <= max length.
222
*/
223
static inline bool skb_gso_size_check(const struct sk_buff *skb,
224
unsigned int seg_len,
225
unsigned int max_len) {
226
const struct skb_shared_info *shinfo = skb_shinfo(skb);
227
const struct sk_buff *iter;
228
229
if (shinfo->gso_size != GSO_BY_FRAGS)
230
return seg_len <= max_len;
231
232
/* Undo this so we can re-use header sizes */
233
seg_len -= GSO_BY_FRAGS;
234
235
skb_walk_frags(skb, iter) {
236
if (seg_len + skb_headlen(iter) > max_len)
237
return false;
238
}
239
240
return true;
241
}
242
243
/**
244
* skb_gso_validate_network_len - Will a split GSO skb fit into a given MTU?
245
*
246
* @skb: GSO skb
247
* @mtu: MTU to validate against
248
*
249
* skb_gso_validate_network_len validates if a given skb will fit a
250
* wanted MTU once split. It considers L3 headers, L4 headers, and the
251
* payload.
252
*/
253
bool skb_gso_validate_network_len(const struct sk_buff *skb, unsigned int mtu)
254
{
255
return skb_gso_size_check(skb, skb_gso_network_seglen(skb), mtu);
256
}
257
EXPORT_SYMBOL_GPL(skb_gso_validate_network_len);
258
259
/**
260
* skb_gso_validate_mac_len - Will a split GSO skb fit in a given length?
261
*
262
* @skb: GSO skb
263
* @len: length to validate against
264
*
265
* skb_gso_validate_mac_len validates if a given skb will fit a wanted
266
* length once split, including L2, L3 and L4 headers and the payload.
267
*/
268
bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len)
269
{
270
return skb_gso_size_check(skb, skb_gso_mac_seglen(skb), len);
271
}
272
EXPORT_SYMBOL_GPL(skb_gso_validate_mac_len);
273
274
275