]>
Commit | Line | Data |
---|---|---|
91088554 | 1 | /* |
cf62fa4c | 2 | * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc. |
91088554 DDP |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at: | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | */ | |
16 | ||
cf62fa4c PS |
17 | #ifndef DPBUF_H |
18 | #define DPBUF_H 1 | |
91088554 | 19 | |
cf62fa4c PS |
20 | #include <stddef.h> |
21 | #include <stdint.h> | |
01961bbd DDP |
22 | |
23 | #ifdef DPDK_NETDEV | |
24 | #include <rte_config.h> | |
25 | #include <rte_mbuf.h> | |
26 | #endif | |
27 | ||
0de1b425 | 28 | #include "netdev-afxdp.h" |
01961bbd | 29 | #include "netdev-dpdk.h" |
b19bab5b | 30 | #include "openvswitch/list.h" |
cf62fa4c PS |
31 | #include "packets.h" |
32 | #include "util.h" | |
2482b0b0 | 33 | #include "flow.h" |
91088554 DDP |
34 | |
35 | #ifdef __cplusplus | |
36 | extern "C" { | |
37 | #endif | |
38 | ||
cf62fa4c PS |
39 | enum OVS_PACKED_ENUM dp_packet_source { |
40 | DPBUF_MALLOC, /* Obtained via malloc(). */ | |
41 | DPBUF_STACK, /* Un-movable stack space or static buffer. */ | |
42 | DPBUF_STUB, /* Starts on stack, may expand into heap. */ | |
43 | DPBUF_DPDK, /* buffer data is from DPDK allocated memory. | |
84b70576 FA |
44 | * ref to dp_packet_init_dpdk() in dp-packet.c. |
45 | */ | |
0de1b425 | 46 | DPBUF_AFXDP, /* Buffer data from XDP frame. */ |
cf62fa4c | 47 | }; |
91088554 | 48 | |
eb18b2a6 PS |
49 | #define DP_PACKET_CONTEXT_SIZE 64 |
50 | ||
a47e2db2 IM |
51 | #ifndef DPDK_NETDEV |
52 | /* Bit masks for the 'ol_flags' member of the 'dp_packet' structure. */ | |
53 | enum dp_packet_offload_mask { | |
54 | DP_PACKET_OL_RSS_HASH_MASK = 0x1, /* Is the 'rss_hash' valid? */ | |
0f706b37 | 55 | DP_PACKET_OL_FLOW_MARK_MASK = 0x2, /* Is the 'flow_mark' valid? */ |
a47e2db2 | 56 | }; |
9965fef8 IM |
57 | #else |
58 | /* DPDK mbuf ol_flags that are not really an offload flags. These are mostly | |
59 | * related to mbuf memory layout and OVS should not touch/clear them. */ | |
60 | #define DPDK_MBUF_NON_OFFLOADING_FLAGS (EXT_ATTACHED_MBUF | \ | |
61 | IND_ATTACHED_MBUF) | |
a47e2db2 IM |
62 | #endif |
63 | ||
82eb5b0a | 64 | /* Buffer for holding packet data. A dp_packet is automatically reallocated |
cf62fa4c | 65 | * as necessary if it grows too large for the available memory. |
2482b0b0 | 66 | * By default the packet type is set to Ethernet (PT_ETH). |
cf62fa4c | 67 | */ |
e14deea0 | 68 | struct dp_packet { |
cf62fa4c PS |
69 | #ifdef DPDK_NETDEV |
70 | struct rte_mbuf mbuf; /* DPDK mbuf */ | |
71 | #else | |
b8e57534 | 72 | void *base_; /* First byte of allocated space. */ |
11a6fbd5 | 73 | uint16_t allocated_; /* Number of bytes allocated. */ |
b8e57534 MK |
74 | uint16_t data_ofs; /* First byte actually in use. */ |
75 | uint32_t size_; /* Number of bytes in use. */ | |
a47e2db2 | 76 | uint32_t ol_flags; /* Offloading flags. */ |
2bc1bbd2 | 77 | uint32_t rss_hash; /* Packet hash. */ |
0f706b37 | 78 | uint32_t flow_mark; /* Packet flow mark. */ |
61a2647e | 79 | #endif |
cf62fa4c | 80 | enum dp_packet_source source; /* Source of memory allocated as 'base'. */ |
84b70576 FA |
81 | |
82 | /* All the following elements of this struct are copied in a single call | |
83 | * of memcpy in dp_packet_clone_with_headroom. */ | |
82eb5b0a DDP |
84 | uint8_t l2_pad_size; /* Detected l2 padding size. |
85 | * Padding is non-pullable. */ | |
86 | uint16_t l2_5_ofs; /* MPLS label stack offset, or UINT16_MAX */ | |
87 | uint16_t l3_ofs; /* Network-level header offset, | |
88 | * or UINT16_MAX. */ | |
89 | uint16_t l4_ofs; /* Transport-level header offset, | |
90 | or UINT16_MAX. */ | |
aaca4fe0 | 91 | uint32_t cutlen; /* length in bytes to cut from the end. */ |
2482b0b0 | 92 | ovs_be32 packet_type; /* Packet type as defined in OpenFlow */ |
eb18b2a6 PS |
93 | union { |
94 | struct pkt_metadata md; | |
95 | uint64_t data[DP_PACKET_CONTEXT_SIZE / 8]; | |
96 | }; | |
91088554 DDP |
97 | }; |
98 | ||
0de1b425 WT |
99 | #if HAVE_AF_XDP |
100 | struct dp_packet_afxdp { | |
101 | struct umem_pool *mpool; | |
102 | struct dp_packet packet; | |
103 | }; | |
104 | #endif | |
105 | ||
5a07c6e1 | 106 | static inline void *dp_packet_data(const struct dp_packet *); |
cf62fa4c | 107 | static inline void dp_packet_set_data(struct dp_packet *, void *); |
5a07c6e1 | 108 | static inline void *dp_packet_base(const struct dp_packet *); |
cf62fa4c PS |
109 | static inline void dp_packet_set_base(struct dp_packet *, void *); |
110 | ||
111 | static inline uint32_t dp_packet_size(const struct dp_packet *); | |
112 | static inline void dp_packet_set_size(struct dp_packet *, uint32_t); | |
113 | ||
11a6fbd5 DDP |
114 | static inline uint16_t dp_packet_get_allocated(const struct dp_packet *); |
115 | static inline void dp_packet_set_allocated(struct dp_packet *, uint16_t); | |
116 | ||
5a07c6e1 DDP |
117 | void *dp_packet_resize_l2(struct dp_packet *, int increment); |
118 | void *dp_packet_resize_l2_5(struct dp_packet *, int increment); | |
2482b0b0 | 119 | static inline void *dp_packet_eth(const struct dp_packet *); |
82eb5b0a | 120 | static inline void dp_packet_reset_offsets(struct dp_packet *); |
cf62fa4c PS |
121 | static inline uint8_t dp_packet_l2_pad_size(const struct dp_packet *); |
122 | static inline void dp_packet_set_l2_pad_size(struct dp_packet *, uint8_t); | |
5a07c6e1 | 123 | static inline void *dp_packet_l2_5(const struct dp_packet *); |
cf62fa4c | 124 | static inline void dp_packet_set_l2_5(struct dp_packet *, void *); |
5a07c6e1 | 125 | static inline void *dp_packet_l3(const struct dp_packet *); |
cf62fa4c | 126 | static inline void dp_packet_set_l3(struct dp_packet *, void *); |
5a07c6e1 | 127 | static inline void *dp_packet_l4(const struct dp_packet *); |
cf62fa4c PS |
128 | static inline void dp_packet_set_l4(struct dp_packet *, void *); |
129 | static inline size_t dp_packet_l4_size(const struct dp_packet *); | |
130 | static inline const void *dp_packet_get_tcp_payload(const struct dp_packet *); | |
131 | static inline const void *dp_packet_get_udp_payload(const struct dp_packet *); | |
132 | static inline const void *dp_packet_get_sctp_payload(const struct dp_packet *); | |
133 | static inline const void *dp_packet_get_icmp_payload(const struct dp_packet *); | |
134 | static inline const void *dp_packet_get_nd_payload(const struct dp_packet *); | |
135 | ||
136 | void dp_packet_use(struct dp_packet *, void *, size_t); | |
137 | void dp_packet_use_stub(struct dp_packet *, void *, size_t); | |
138 | void dp_packet_use_const(struct dp_packet *, const void *, size_t); | |
0de1b425 WT |
139 | #if HAVE_AF_XDP |
140 | void dp_packet_use_afxdp(struct dp_packet *, void *, size_t, size_t); | |
141 | #endif | |
3aaa6201 | 142 | void dp_packet_init_dpdk(struct dp_packet *); |
cf62fa4c PS |
143 | |
144 | void dp_packet_init(struct dp_packet *, size_t); | |
145 | void dp_packet_uninit(struct dp_packet *); | |
cf62fa4c PS |
146 | |
147 | struct dp_packet *dp_packet_new(size_t); | |
148 | struct dp_packet *dp_packet_new_with_headroom(size_t, size_t headroom); | |
149 | struct dp_packet *dp_packet_clone(const struct dp_packet *); | |
150 | struct dp_packet *dp_packet_clone_with_headroom(const struct dp_packet *, | |
5a07c6e1 | 151 | size_t headroom); |
cf62fa4c PS |
152 | struct dp_packet *dp_packet_clone_data(const void *, size_t); |
153 | struct dp_packet *dp_packet_clone_data_with_headroom(const void *, size_t, | |
5a07c6e1 | 154 | size_t headroom); |
cf62fa4c PS |
155 | static inline void dp_packet_delete(struct dp_packet *); |
156 | ||
157 | static inline void *dp_packet_at(const struct dp_packet *, size_t offset, | |
5a07c6e1 DDP |
158 | size_t size); |
159 | static inline void *dp_packet_at_assert(const struct dp_packet *, | |
160 | size_t offset, size_t size); | |
cf62fa4c PS |
161 | static inline void *dp_packet_tail(const struct dp_packet *); |
162 | static inline void *dp_packet_end(const struct dp_packet *); | |
163 | ||
164 | void *dp_packet_put_uninit(struct dp_packet *, size_t); | |
165 | void *dp_packet_put_zeros(struct dp_packet *, size_t); | |
166 | void *dp_packet_put(struct dp_packet *, const void *, size_t); | |
167 | char *dp_packet_put_hex(struct dp_packet *, const char *s, size_t *n); | |
168 | void dp_packet_reserve(struct dp_packet *, size_t); | |
5a07c6e1 DDP |
169 | void dp_packet_reserve_with_tailroom(struct dp_packet *, size_t headroom, |
170 | size_t tailroom); | |
171 | void *dp_packet_push_uninit(struct dp_packet *, size_t); | |
cf62fa4c | 172 | void *dp_packet_push_zeros(struct dp_packet *, size_t); |
5a07c6e1 | 173 | void *dp_packet_push(struct dp_packet *, const void *, size_t); |
cf62fa4c PS |
174 | |
175 | static inline size_t dp_packet_headroom(const struct dp_packet *); | |
176 | static inline size_t dp_packet_tailroom(const struct dp_packet *); | |
177 | void dp_packet_prealloc_headroom(struct dp_packet *, size_t); | |
178 | void dp_packet_prealloc_tailroom(struct dp_packet *, size_t); | |
179 | void dp_packet_shift(struct dp_packet *, int); | |
91088554 | 180 | |
cf62fa4c PS |
181 | static inline void dp_packet_clear(struct dp_packet *); |
182 | static inline void *dp_packet_pull(struct dp_packet *, size_t); | |
183 | static inline void *dp_packet_try_pull(struct dp_packet *, size_t); | |
91088554 | 184 | |
cf62fa4c | 185 | void *dp_packet_steal_data(struct dp_packet *); |
91088554 | 186 | |
5a07c6e1 DDP |
187 | static inline bool dp_packet_equal(const struct dp_packet *, |
188 | const struct dp_packet *); | |
cf62fa4c PS |
189 | |
190 | \f | |
cf62fa4c | 191 | /* Frees memory that 'b' points to, as well as 'b' itself. */ |
5a07c6e1 DDP |
192 | static inline void |
193 | dp_packet_delete(struct dp_packet *b) | |
cf62fa4c PS |
194 | { |
195 | if (b) { | |
196 | if (b->source == DPBUF_DPDK) { | |
197 | /* If this dp_packet was allocated by DPDK it must have been | |
198 | * created as a dp_packet */ | |
199 | free_dpdk_buf((struct dp_packet*) b); | |
200 | return; | |
201 | } | |
202 | ||
0de1b425 WT |
203 | if (b->source == DPBUF_AFXDP) { |
204 | free_afxdp_buf(b); | |
205 | return; | |
206 | } | |
207 | ||
cf62fa4c PS |
208 | dp_packet_uninit(b); |
209 | free(b); | |
210 | } | |
211 | } | |
212 | ||
213 | /* If 'b' contains at least 'offset + size' bytes of data, returns a pointer to | |
214 | * byte 'offset'. Otherwise, returns a null pointer. */ | |
5a07c6e1 DDP |
215 | static inline void * |
216 | dp_packet_at(const struct dp_packet *b, size_t offset, size_t size) | |
91088554 | 217 | { |
5a07c6e1 DDP |
218 | return offset + size <= dp_packet_size(b) |
219 | ? (char *) dp_packet_data(b) + offset | |
220 | : NULL; | |
cf62fa4c | 221 | } |
91088554 | 222 | |
cf62fa4c PS |
223 | /* Returns a pointer to byte 'offset' in 'b', which must contain at least |
224 | * 'offset + size' bytes of data. */ | |
5a07c6e1 DDP |
225 | static inline void * |
226 | dp_packet_at_assert(const struct dp_packet *b, size_t offset, size_t size) | |
cf62fa4c PS |
227 | { |
228 | ovs_assert(offset + size <= dp_packet_size(b)); | |
229 | return ((char *) dp_packet_data(b)) + offset; | |
230 | } | |
231 | ||
232 | /* Returns a pointer to byte following the last byte of data in use in 'b'. */ | |
5a07c6e1 DDP |
233 | static inline void * |
234 | dp_packet_tail(const struct dp_packet *b) | |
cf62fa4c PS |
235 | { |
236 | return (char *) dp_packet_data(b) + dp_packet_size(b); | |
237 | } | |
238 | ||
239 | /* Returns a pointer to byte following the last byte allocated for use (but | |
240 | * not necessarily in use) in 'b'. */ | |
5a07c6e1 DDP |
241 | static inline void * |
242 | dp_packet_end(const struct dp_packet *b) | |
cf62fa4c | 243 | { |
11a6fbd5 | 244 | return (char *) dp_packet_base(b) + dp_packet_get_allocated(b); |
cf62fa4c PS |
245 | } |
246 | ||
247 | /* Returns the number of bytes of headroom in 'b', that is, the number of bytes | |
248 | * of unused space in dp_packet 'b' before the data that is in use. (Most | |
5a07c6e1 DDP |
249 | * commonly, the data in a dp_packet is at its beginning, and thus the |
250 | * dp_packet's headroom is 0.) */ | |
251 | static inline size_t | |
252 | dp_packet_headroom(const struct dp_packet *b) | |
cf62fa4c | 253 | { |
5a07c6e1 | 254 | return (char *) dp_packet_data(b) - (char *) dp_packet_base(b); |
cf62fa4c PS |
255 | } |
256 | ||
5a07c6e1 DDP |
257 | /* Returns the number of bytes that may be appended to the tail end of |
258 | * dp_packet 'b' before the dp_packet must be reallocated. */ | |
259 | static inline size_t | |
260 | dp_packet_tailroom(const struct dp_packet *b) | |
cf62fa4c | 261 | { |
5a07c6e1 | 262 | return (char *) dp_packet_end(b) - (char *) dp_packet_tail(b); |
cf62fa4c PS |
263 | } |
264 | ||
265 | /* Clears any data from 'b'. */ | |
5a07c6e1 DDP |
266 | static inline void |
267 | dp_packet_clear(struct dp_packet *b) | |
cf62fa4c PS |
268 | { |
269 | dp_packet_set_data(b, dp_packet_base(b)); | |
270 | dp_packet_set_size(b, 0); | |
271 | } | |
272 | ||
273 | /* Removes 'size' bytes from the head end of 'b', which must contain at least | |
274 | * 'size' bytes of data. Returns the first byte of data removed. */ | |
5a07c6e1 DDP |
275 | static inline void * |
276 | dp_packet_pull(struct dp_packet *b, size_t size) | |
cf62fa4c PS |
277 | { |
278 | void *data = dp_packet_data(b); | |
279 | ovs_assert(dp_packet_size(b) - dp_packet_l2_pad_size(b) >= size); | |
5a07c6e1 | 280 | dp_packet_set_data(b, (char *) dp_packet_data(b) + size); |
cf62fa4c PS |
281 | dp_packet_set_size(b, dp_packet_size(b) - size); |
282 | return data; | |
283 | } | |
284 | ||
285 | /* If 'b' has at least 'size' bytes of data, removes that many bytes from the | |
286 | * head end of 'b' and returns the first byte removed. Otherwise, returns a | |
287 | * null pointer without modifying 'b'. */ | |
5a07c6e1 DDP |
288 | static inline void * |
289 | dp_packet_try_pull(struct dp_packet *b, size_t size) | |
cf62fa4c PS |
290 | { |
291 | return dp_packet_size(b) - dp_packet_l2_pad_size(b) >= size | |
292 | ? dp_packet_pull(b, size) : NULL; | |
293 | } | |
294 | ||
5a07c6e1 DDP |
295 | static inline bool |
296 | dp_packet_equal(const struct dp_packet *a, const struct dp_packet *b) | |
cf62fa4c PS |
297 | { |
298 | return dp_packet_size(a) == dp_packet_size(b) && | |
5a07c6e1 | 299 | !memcmp(dp_packet_data(a), dp_packet_data(b), dp_packet_size(a)); |
cf62fa4c PS |
300 | } |
301 | ||
2482b0b0 JS |
302 | static inline bool |
303 | dp_packet_is_eth(const struct dp_packet *b) | |
304 | { | |
305 | return b->packet_type == htonl(PT_ETH); | |
306 | } | |
307 | ||
308 | /* Get the start of the Ethernet frame. 'l3_ofs' marks the end of the l2 | |
cf62fa4c | 309 | * headers, so return NULL if it is not set. */ |
5a07c6e1 | 310 | static inline void * |
2482b0b0 | 311 | dp_packet_eth(const struct dp_packet *b) |
cf62fa4c | 312 | { |
2482b0b0 JS |
313 | return (dp_packet_is_eth(b) && b->l3_ofs != UINT16_MAX) |
314 | ? dp_packet_data(b) : NULL; | |
cf62fa4c PS |
315 | } |
316 | ||
82eb5b0a DDP |
317 | /* Resets all layer offsets. 'l3' offset must be set before 'l2' can be |
318 | * retrieved. */ | |
5a07c6e1 DDP |
319 | static inline void |
320 | dp_packet_reset_offsets(struct dp_packet *b) | |
cf62fa4c | 321 | { |
cf62fa4c PS |
322 | b->l2_pad_size = 0; |
323 | b->l2_5_ofs = UINT16_MAX; | |
324 | b->l3_ofs = UINT16_MAX; | |
325 | b->l4_ofs = UINT16_MAX; | |
326 | } | |
327 | ||
5a07c6e1 DDP |
328 | static inline uint8_t |
329 | dp_packet_l2_pad_size(const struct dp_packet *b) | |
cf62fa4c PS |
330 | { |
331 | return b->l2_pad_size; | |
332 | } | |
333 | ||
5a07c6e1 DDP |
334 | static inline void |
335 | dp_packet_set_l2_pad_size(struct dp_packet *b, uint8_t pad_size) | |
cf62fa4c PS |
336 | { |
337 | ovs_assert(pad_size <= dp_packet_size(b)); | |
338 | b->l2_pad_size = pad_size; | |
339 | } | |
340 | ||
5a07c6e1 DDP |
341 | static inline void * |
342 | dp_packet_l2_5(const struct dp_packet *b) | |
cf62fa4c | 343 | { |
82eb5b0a DDP |
344 | return b->l2_5_ofs != UINT16_MAX |
345 | ? (char *) dp_packet_data(b) + b->l2_5_ofs | |
346 | : NULL; | |
cf62fa4c PS |
347 | } |
348 | ||
5a07c6e1 DDP |
349 | static inline void |
350 | dp_packet_set_l2_5(struct dp_packet *b, void *l2_5) | |
cf62fa4c | 351 | { |
82eb5b0a DDP |
352 | b->l2_5_ofs = l2_5 |
353 | ? (char *) l2_5 - (char *) dp_packet_data(b) | |
354 | : UINT16_MAX; | |
cf62fa4c PS |
355 | } |
356 | ||
5a07c6e1 DDP |
357 | static inline void * |
358 | dp_packet_l3(const struct dp_packet *b) | |
cf62fa4c | 359 | { |
82eb5b0a DDP |
360 | return b->l3_ofs != UINT16_MAX |
361 | ? (char *) dp_packet_data(b) + b->l3_ofs | |
362 | : NULL; | |
cf62fa4c PS |
363 | } |
364 | ||
5a07c6e1 DDP |
365 | static inline void |
366 | dp_packet_set_l3(struct dp_packet *b, void *l3) | |
cf62fa4c | 367 | { |
82eb5b0a | 368 | b->l3_ofs = l3 ? (char *) l3 - (char *) dp_packet_data(b) : UINT16_MAX; |
cf62fa4c PS |
369 | } |
370 | ||
5a07c6e1 DDP |
371 | static inline void * |
372 | dp_packet_l4(const struct dp_packet *b) | |
cf62fa4c | 373 | { |
82eb5b0a DDP |
374 | return b->l4_ofs != UINT16_MAX |
375 | ? (char *) dp_packet_data(b) + b->l4_ofs | |
376 | : NULL; | |
cf62fa4c PS |
377 | } |
378 | ||
5a07c6e1 DDP |
379 | static inline void |
380 | dp_packet_set_l4(struct dp_packet *b, void *l4) | |
cf62fa4c | 381 | { |
82eb5b0a | 382 | b->l4_ofs = l4 ? (char *) l4 - (char *) dp_packet_data(b) : UINT16_MAX; |
cf62fa4c PS |
383 | } |
384 | ||
69c45b36 DB |
385 | /* Returns the size of the packet from the beginning of the L3 header to the |
386 | * end of the L3 payload. Hence L2 padding is not included. */ | |
387 | static inline size_t | |
388 | dp_packet_l3_size(const struct dp_packet *b) | |
389 | { | |
390 | return OVS_LIKELY(b->l3_ofs != UINT16_MAX) | |
391 | ? (const char *)dp_packet_tail(b) - (const char *)dp_packet_l3(b) | |
392 | - dp_packet_l2_pad_size(b) | |
393 | : 0; | |
394 | } | |
395 | ||
396 | /* Returns the size of the packet from the beginning of the L4 header to the | |
397 | * end of the L4 payload. Hence L2 padding is not included. */ | |
5a07c6e1 DDP |
398 | static inline size_t |
399 | dp_packet_l4_size(const struct dp_packet *b) | |
cf62fa4c | 400 | { |
69c45b36 | 401 | return OVS_LIKELY(b->l4_ofs != UINT16_MAX) |
cf62fa4c PS |
402 | ? (const char *)dp_packet_tail(b) - (const char *)dp_packet_l4(b) |
403 | - dp_packet_l2_pad_size(b) | |
404 | : 0; | |
405 | } | |
406 | ||
5a07c6e1 DDP |
407 | static inline const void * |
408 | dp_packet_get_tcp_payload(const struct dp_packet *b) | |
cf62fa4c PS |
409 | { |
410 | size_t l4_size = dp_packet_l4_size(b); | |
411 | ||
412 | if (OVS_LIKELY(l4_size >= TCP_HEADER_LEN)) { | |
413 | struct tcp_header *tcp = dp_packet_l4(b); | |
414 | int tcp_len = TCP_OFFSET(tcp->tcp_ctl) * 4; | |
415 | ||
416 | if (OVS_LIKELY(tcp_len >= TCP_HEADER_LEN && tcp_len <= l4_size)) { | |
417 | return (const char *)tcp + tcp_len; | |
418 | } | |
419 | } | |
420 | return NULL; | |
421 | } | |
422 | ||
5a07c6e1 DDP |
423 | static inline const void * |
424 | dp_packet_get_udp_payload(const struct dp_packet *b) | |
cf62fa4c PS |
425 | { |
426 | return OVS_LIKELY(dp_packet_l4_size(b) >= UDP_HEADER_LEN) | |
427 | ? (const char *)dp_packet_l4(b) + UDP_HEADER_LEN : NULL; | |
428 | } | |
429 | ||
5a07c6e1 DDP |
430 | static inline const void * |
431 | dp_packet_get_sctp_payload(const struct dp_packet *b) | |
cf62fa4c PS |
432 | { |
433 | return OVS_LIKELY(dp_packet_l4_size(b) >= SCTP_HEADER_LEN) | |
434 | ? (const char *)dp_packet_l4(b) + SCTP_HEADER_LEN : NULL; | |
435 | } | |
436 | ||
5a07c6e1 DDP |
437 | static inline const void * |
438 | dp_packet_get_icmp_payload(const struct dp_packet *b) | |
cf62fa4c PS |
439 | { |
440 | return OVS_LIKELY(dp_packet_l4_size(b) >= ICMP_HEADER_LEN) | |
441 | ? (const char *)dp_packet_l4(b) + ICMP_HEADER_LEN : NULL; | |
442 | } | |
443 | ||
5a07c6e1 DDP |
444 | static inline const void * |
445 | dp_packet_get_nd_payload(const struct dp_packet *b) | |
cf62fa4c PS |
446 | { |
447 | return OVS_LIKELY(dp_packet_l4_size(b) >= ND_MSG_LEN) | |
448 | ? (const char *)dp_packet_l4(b) + ND_MSG_LEN : NULL; | |
449 | } | |
450 | ||
451 | #ifdef DPDK_NETDEV | |
452 | BUILD_ASSERT_DECL(offsetof(struct dp_packet, mbuf) == 0); | |
453 | ||
a47e2db2 IM |
454 | static inline void |
455 | dp_packet_init_specific(struct dp_packet *p) | |
456 | { | |
457 | /* This initialization is needed for packets that do not come from DPDK | |
458 | * interfaces, when vswitchd is built with --with-dpdk. */ | |
459 | p->mbuf.tx_offload = p->mbuf.packet_type = 0; | |
460 | p->mbuf.nb_segs = 1; | |
461 | p->mbuf.next = NULL; | |
462 | } | |
463 | ||
5a07c6e1 DDP |
464 | static inline void * |
465 | dp_packet_base(const struct dp_packet *b) | |
cf62fa4c PS |
466 | { |
467 | return b->mbuf.buf_addr; | |
468 | } | |
469 | ||
5a07c6e1 DDP |
470 | static inline void |
471 | dp_packet_set_base(struct dp_packet *b, void *d) | |
cf62fa4c PS |
472 | { |
473 | b->mbuf.buf_addr = d; | |
474 | } | |
475 | ||
5a07c6e1 DDP |
476 | static inline uint32_t |
477 | dp_packet_size(const struct dp_packet *b) | |
cf62fa4c | 478 | { |
b8e57534 | 479 | return b->mbuf.pkt_len; |
cf62fa4c PS |
480 | } |
481 | ||
5a07c6e1 DDP |
482 | static inline void |
483 | dp_packet_set_size(struct dp_packet *b, uint32_t v) | |
cf62fa4c | 484 | { |
b8e57534 MK |
485 | /* netdev-dpdk does not currently support segmentation; consequently, for |
486 | * all intents and purposes, 'data_len' (16 bit) and 'pkt_len' (32 bit) may | |
487 | * be used interchangably. | |
488 | * | |
489 | * On the datapath, it is expected that the size of packets | |
490 | * (and thus 'v') will always be <= UINT16_MAX; this means that there is no | |
491 | * loss of accuracy in assigning 'v' to 'data_len'. | |
b8e57534 MK |
492 | */ |
493 | b->mbuf.data_len = (uint16_t)v; /* Current seg length. */ | |
494 | b->mbuf.pkt_len = v; /* Total length of all segments linked to | |
495 | * this segment. */ | |
cf62fa4c PS |
496 | } |
497 | ||
5a07c6e1 DDP |
498 | static inline uint16_t |
499 | __packet_data(const struct dp_packet *b) | |
cf62fa4c | 500 | { |
b8e57534 | 501 | return b->mbuf.data_off; |
cf62fa4c PS |
502 | } |
503 | ||
5a07c6e1 DDP |
504 | static inline void |
505 | __packet_set_data(struct dp_packet *b, uint16_t v) | |
cf62fa4c | 506 | { |
b8e57534 | 507 | b->mbuf.data_off = v; |
cf62fa4c PS |
508 | } |
509 | ||
5a07c6e1 DDP |
510 | static inline uint16_t |
511 | dp_packet_get_allocated(const struct dp_packet *b) | |
11a6fbd5 DDP |
512 | { |
513 | return b->mbuf.buf_len; | |
514 | } | |
515 | ||
5a07c6e1 DDP |
516 | static inline void |
517 | dp_packet_set_allocated(struct dp_packet *b, uint16_t s) | |
11a6fbd5 DDP |
518 | { |
519 | b->mbuf.buf_len = s; | |
520 | } | |
e52ad721 FL |
521 | |
522 | /* Returns the RSS hash of the packet 'p'. Note that the returned value is | |
523 | * correct only if 'dp_packet_rss_valid(p)' returns true */ | |
524 | static inline uint32_t | |
92330af5 | 525 | dp_packet_get_rss_hash(const struct dp_packet *p) |
cf62fa4c | 526 | { |
e52ad721 | 527 | return p->mbuf.hash.rss; |
cf62fa4c PS |
528 | } |
529 | ||
5a07c6e1 | 530 | static inline void |
e52ad721 | 531 | dp_packet_set_rss_hash(struct dp_packet *p, uint32_t hash) |
cf62fa4c | 532 | { |
e52ad721 FL |
533 | p->mbuf.hash.rss = hash; |
534 | p->mbuf.ol_flags |= PKT_RX_RSS_HASH; | |
cf62fa4c PS |
535 | } |
536 | ||
e52ad721 | 537 | static inline bool |
92330af5 | 538 | dp_packet_rss_valid(const struct dp_packet *p) |
cf62fa4c | 539 | { |
e52ad721 | 540 | return p->mbuf.ol_flags & PKT_RX_RSS_HASH; |
cf62fa4c PS |
541 | } |
542 | ||
5a07c6e1 | 543 | static inline void |
a47e2db2 | 544 | dp_packet_reset_offload(struct dp_packet *p) |
b8e57534 | 545 | { |
9965fef8 | 546 | p->mbuf.ol_flags &= DPDK_MBUF_NON_OFFLOADING_FLAGS; |
b8e57534 MK |
547 | } |
548 | ||
e52ad721 | 549 | static inline bool |
e030622a | 550 | dp_packet_ip_checksum_valid(const struct dp_packet *p) |
11a6fbd5 | 551 | { |
e52ad721 FL |
552 | return (p->mbuf.ol_flags & PKT_RX_IP_CKSUM_MASK) == |
553 | PKT_RX_IP_CKSUM_GOOD; | |
11a6fbd5 DDP |
554 | } |
555 | ||
e52ad721 | 556 | static inline bool |
e030622a | 557 | dp_packet_ip_checksum_bad(const struct dp_packet *p) |
11a6fbd5 | 558 | { |
e52ad721 FL |
559 | return (p->mbuf.ol_flags & PKT_RX_IP_CKSUM_MASK) == |
560 | PKT_RX_IP_CKSUM_BAD; | |
561 | } | |
562 | ||
563 | static inline bool | |
e030622a | 564 | dp_packet_l4_checksum_valid(const struct dp_packet *p) |
e52ad721 FL |
565 | { |
566 | return (p->mbuf.ol_flags & PKT_RX_L4_CKSUM_MASK) == | |
567 | PKT_RX_L4_CKSUM_GOOD; | |
568 | } | |
569 | ||
570 | static inline bool | |
e030622a | 571 | dp_packet_l4_checksum_bad(const struct dp_packet *p) |
e52ad721 FL |
572 | { |
573 | return (p->mbuf.ol_flags & PKT_RX_L4_CKSUM_MASK) == | |
574 | PKT_RX_L4_CKSUM_BAD; | |
11a6fbd5 | 575 | } |
cf62fa4c | 576 | |
e52ad721 | 577 | static inline bool |
92330af5 | 578 | dp_packet_has_flow_mark(const struct dp_packet *p, uint32_t *mark) |
aaca4fe0 | 579 | { |
e52ad721 FL |
580 | if (p->mbuf.ol_flags & PKT_RX_FDIR_ID) { |
581 | *mark = p->mbuf.hash.fdir.hi; | |
582 | return true; | |
aaca4fe0 WT |
583 | } |
584 | ||
e52ad721 | 585 | return false; |
aaca4fe0 WT |
586 | } |
587 | ||
0f706b37 IM |
588 | static inline void |
589 | dp_packet_set_flow_mark(struct dp_packet *p, uint32_t mark) | |
590 | { | |
591 | p->mbuf.hash.fdir.hi = mark; | |
592 | p->mbuf.ol_flags |= PKT_RX_FDIR_ID; | |
593 | } | |
594 | ||
e52ad721 | 595 | #else /* DPDK_NETDEV */ |
a47e2db2 IM |
596 | |
597 | static inline void | |
598 | dp_packet_init_specific(struct dp_packet *p OVS_UNUSED) | |
599 | { | |
600 | /* There are no implementation-specific fields for initialization. */ | |
601 | } | |
602 | ||
e52ad721 FL |
603 | static inline void * |
604 | dp_packet_base(const struct dp_packet *b) | |
aaca4fe0 | 605 | { |
e52ad721 FL |
606 | return b->base_; |
607 | } | |
608 | ||
609 | static inline void | |
610 | dp_packet_set_base(struct dp_packet *b, void *d) | |
611 | { | |
612 | b->base_ = d; | |
aaca4fe0 WT |
613 | } |
614 | ||
a61a2891 | 615 | static inline uint32_t |
e52ad721 | 616 | dp_packet_size(const struct dp_packet *b) |
a61a2891 | 617 | { |
e52ad721 | 618 | return b->size_; |
a61a2891 BP |
619 | } |
620 | ||
e52ad721 FL |
621 | static inline void |
622 | dp_packet_set_size(struct dp_packet *b, uint32_t v) | |
b8e57534 | 623 | { |
e52ad721 FL |
624 | b->size_ = v; |
625 | } | |
626 | ||
627 | static inline uint16_t | |
628 | __packet_data(const struct dp_packet *b) | |
629 | { | |
630 | return b->data_ofs; | |
b8e57534 MK |
631 | } |
632 | ||
5a07c6e1 | 633 | static inline void |
e52ad721 | 634 | __packet_set_data(struct dp_packet *b, uint16_t v) |
b8e57534 | 635 | { |
e52ad721 FL |
636 | b->data_ofs = v; |
637 | } | |
638 | ||
639 | static inline uint16_t | |
640 | dp_packet_get_allocated(const struct dp_packet *b) | |
641 | { | |
642 | return b->allocated_; | |
b8e57534 MK |
643 | } |
644 | ||
5a07c6e1 | 645 | static inline void |
e52ad721 | 646 | dp_packet_set_allocated(struct dp_packet *b, uint16_t s) |
cf62fa4c | 647 | { |
e52ad721 | 648 | b->allocated_ = s; |
91088554 DDP |
649 | } |
650 | ||
f2f44f5d DDP |
651 | /* Returns the RSS hash of the packet 'p'. Note that the returned value is |
652 | * correct only if 'dp_packet_rss_valid(p)' returns true */ | |
5a07c6e1 | 653 | static inline uint32_t |
92330af5 | 654 | dp_packet_get_rss_hash(const struct dp_packet *p) |
61a2647e | 655 | { |
2bc1bbd2 | 656 | return p->rss_hash; |
61a2647e DDP |
657 | } |
658 | ||
5a07c6e1 DDP |
659 | static inline void |
660 | dp_packet_set_rss_hash(struct dp_packet *p, uint32_t hash) | |
61a2647e | 661 | { |
2bc1bbd2 | 662 | p->rss_hash = hash; |
a47e2db2 | 663 | p->ol_flags |= DP_PACKET_OL_RSS_HASH_MASK; |
f2f44f5d DDP |
664 | } |
665 | ||
666 | static inline bool | |
92330af5 | 667 | dp_packet_rss_valid(const struct dp_packet *p) |
f2f44f5d | 668 | { |
a47e2db2 | 669 | return p->ol_flags & DP_PACKET_OL_RSS_HASH_MASK; |
f8121b39 DB |
670 | } |
671 | ||
f8121b39 | 672 | static inline void |
a47e2db2 | 673 | dp_packet_reset_offload(struct dp_packet *p) |
f8121b39 | 674 | { |
a47e2db2 | 675 | p->ol_flags = 0; |
61a2647e DDP |
676 | } |
677 | ||
1a2bb118 | 678 | static inline bool |
e030622a | 679 | dp_packet_ip_checksum_valid(const struct dp_packet *p OVS_UNUSED) |
1a2bb118 | 680 | { |
cfc19646 | 681 | return false; |
7451af61 SC |
682 | } |
683 | ||
684 | static inline bool | |
e030622a | 685 | dp_packet_ip_checksum_bad(const struct dp_packet *p OVS_UNUSED) |
7451af61 | 686 | { |
cfc19646 | 687 | return false; |
1a2bb118 SC |
688 | } |
689 | ||
690 | static inline bool | |
e030622a | 691 | dp_packet_l4_checksum_valid(const struct dp_packet *p OVS_UNUSED) |
1a2bb118 | 692 | { |
cfc19646 | 693 | return false; |
7451af61 SC |
694 | } |
695 | ||
696 | static inline bool | |
e030622a | 697 | dp_packet_l4_checksum_bad(const struct dp_packet *p OVS_UNUSED) |
7451af61 | 698 | { |
cfc19646 | 699 | return false; |
1a2bb118 SC |
700 | } |
701 | ||
aab96ec4 | 702 | static inline bool |
0f706b37 | 703 | dp_packet_has_flow_mark(const struct dp_packet *p, uint32_t *mark) |
aab96ec4 | 704 | { |
0f706b37 IM |
705 | if (p->ol_flags & DP_PACKET_OL_FLOW_MARK_MASK) { |
706 | *mark = p->flow_mark; | |
707 | return true; | |
708 | } | |
aab96ec4 YL |
709 | return false; |
710 | } | |
0f706b37 IM |
711 | |
712 | static inline void | |
713 | dp_packet_set_flow_mark(struct dp_packet *p, uint32_t mark) | |
714 | { | |
715 | p->flow_mark = mark; | |
716 | p->ol_flags |= DP_PACKET_OL_FLOW_MARK_MASK; | |
717 | } | |
e52ad721 FL |
718 | #endif /* DPDK_NETDEV */ |
719 | ||
720 | static inline void | |
721 | dp_packet_reset_cutlen(struct dp_packet *b) | |
722 | { | |
723 | b->cutlen = 0; | |
724 | } | |
725 | ||
726 | static inline uint32_t | |
727 | dp_packet_set_cutlen(struct dp_packet *b, uint32_t max_len) | |
728 | { | |
729 | if (max_len < ETH_HEADER_LEN) { | |
730 | max_len = ETH_HEADER_LEN; | |
731 | } | |
732 | ||
733 | if (max_len >= dp_packet_size(b)) { | |
734 | b->cutlen = 0; | |
735 | } else { | |
736 | b->cutlen = dp_packet_size(b) - max_len; | |
737 | } | |
738 | return b->cutlen; | |
739 | } | |
740 | ||
741 | static inline uint32_t | |
742 | dp_packet_get_cutlen(const struct dp_packet *b) | |
743 | { | |
744 | /* Always in valid range if user uses dp_packet_set_cutlen. */ | |
745 | return b->cutlen; | |
746 | } | |
747 | ||
748 | static inline uint32_t | |
749 | dp_packet_get_send_len(const struct dp_packet *b) | |
750 | { | |
751 | return dp_packet_size(b) - dp_packet_get_cutlen(b); | |
752 | } | |
753 | ||
754 | static inline void * | |
755 | dp_packet_data(const struct dp_packet *b) | |
756 | { | |
757 | return __packet_data(b) != UINT16_MAX | |
758 | ? (char *) dp_packet_base(b) + __packet_data(b) : NULL; | |
759 | } | |
760 | ||
761 | static inline void | |
762 | dp_packet_set_data(struct dp_packet *b, void *data) | |
763 | { | |
764 | if (data) { | |
765 | __packet_set_data(b, (char *) data - (char *) dp_packet_base(b)); | |
766 | } else { | |
767 | __packet_set_data(b, UINT16_MAX); | |
768 | } | |
769 | } | |
770 | ||
771 | static inline void | |
772 | dp_packet_reset_packet(struct dp_packet *b, int off) | |
773 | { | |
774 | dp_packet_set_size(b, dp_packet_size(b) - off); | |
775 | dp_packet_set_data(b, ((unsigned char *) dp_packet_data(b) + off)); | |
776 | dp_packet_reset_offsets(b); | |
777 | } | |
aab96ec4 | 778 | |
1895cc8d PS |
779 | enum { NETDEV_MAX_BURST = 32 }; /* Maximum number packets in a batch. */ |
780 | ||
781 | struct dp_packet_batch { | |
72c84bc2 | 782 | size_t count; |
aaca4fe0 | 783 | bool trunc; /* true if the batch needs truncate. */ |
9f17f104 | 784 | bool do_not_steal; /* Indicate that the packets should not be stolen. */ |
1895cc8d PS |
785 | struct dp_packet *packets[NETDEV_MAX_BURST]; |
786 | }; | |
787 | ||
72c84bc2 AZ |
788 | static inline void |
789 | dp_packet_batch_init(struct dp_packet_batch *batch) | |
1895cc8d | 790 | { |
72c84bc2 AZ |
791 | batch->count = 0; |
792 | batch->trunc = false; | |
9f17f104 | 793 | batch->do_not_steal = false; |
1895cc8d PS |
794 | } |
795 | ||
796 | static inline void | |
72c84bc2 AZ |
797 | dp_packet_batch_add__(struct dp_packet_batch *batch, |
798 | struct dp_packet *packet, size_t limit) | |
1895cc8d | 799 | { |
72c84bc2 AZ |
800 | if (batch->count < limit) { |
801 | batch->packets[batch->count++] = packet; | |
802 | } else { | |
803 | dp_packet_delete(packet); | |
1895cc8d | 804 | } |
1895cc8d PS |
805 | } |
806 | ||
72c84bc2 AZ |
807 | /* When the batch is full, 'packet' will be dropped and freed. */ |
808 | static inline void | |
809 | dp_packet_batch_add(struct dp_packet_batch *batch, struct dp_packet *packet) | |
810 | { | |
811 | dp_packet_batch_add__(batch, packet, NETDEV_MAX_BURST); | |
812 | } | |
813 | ||
814 | static inline size_t | |
815 | dp_packet_batch_size(const struct dp_packet_batch *batch) | |
816 | { | |
817 | return batch->count; | |
818 | } | |
819 | ||
feb86b41 IM |
820 | /* Clear 'batch' for refill. Use dp_packet_batch_refill() to add |
821 | * packets back into the 'batch'. */ | |
1895cc8d | 822 | static inline void |
72c84bc2 | 823 | dp_packet_batch_refill_init(struct dp_packet_batch *batch) |
1895cc8d | 824 | { |
72c84bc2 AZ |
825 | batch->count = 0; |
826 | }; | |
827 | ||
828 | static inline void | |
829 | dp_packet_batch_refill(struct dp_packet_batch *batch, | |
830 | struct dp_packet *packet, size_t idx) | |
831 | { | |
832 | dp_packet_batch_add__(batch, packet, MIN(NETDEV_MAX_BURST, idx + 1)); | |
833 | } | |
834 | ||
835 | static inline void | |
836 | dp_packet_batch_init_packet(struct dp_packet_batch *batch, struct dp_packet *p) | |
837 | { | |
838 | dp_packet_batch_init(batch); | |
839 | batch->count = 1; | |
840 | batch->packets[0] = p; | |
841 | } | |
842 | ||
843 | static inline bool | |
844 | dp_packet_batch_is_empty(const struct dp_packet_batch *batch) | |
845 | { | |
846 | return !dp_packet_batch_size(batch); | |
847 | } | |
848 | ||
1aa7bbca DB |
849 | static inline bool |
850 | dp_packet_batch_is_full(const struct dp_packet_batch *batch) | |
851 | { | |
852 | return dp_packet_batch_size(batch) == NETDEV_MAX_BURST; | |
853 | } | |
854 | ||
e883448e JP |
855 | #define DP_PACKET_BATCH_FOR_EACH(IDX, PACKET, BATCH) \ |
856 | for (size_t IDX = 0; IDX < dp_packet_batch_size(BATCH); IDX++) \ | |
857 | if (PACKET = BATCH->packets[IDX], true) | |
72c84bc2 AZ |
858 | |
859 | /* Use this macro for cases where some packets in the 'BATCH' may be | |
860 | * dropped after going through each packet in the 'BATCH'. | |
861 | * | |
862 | * For packets to stay in the 'BATCH', they need to be refilled back | |
863 | * into the 'BATCH' by calling dp_packet_batch_refill(). Caller owns | |
864 | * the packets that are not refilled. | |
865 | * | |
866 | * Caller needs to supply 'SIZE', that stores the current number of | |
867 | * packets in 'BATCH'. It is best to declare this variable with | |
868 | * the 'const' modifier since it should not be modified by | |
869 | * the iterator. */ | |
870 | #define DP_PACKET_BATCH_REFILL_FOR_EACH(IDX, SIZE, PACKET, BATCH) \ | |
871 | for (dp_packet_batch_refill_init(BATCH), IDX=0; IDX < SIZE; IDX++) \ | |
872 | if (PACKET = BATCH->packets[IDX], true) | |
873 | ||
874 | static inline void | |
875 | dp_packet_batch_clone(struct dp_packet_batch *dst, | |
876 | struct dp_packet_batch *src) | |
877 | { | |
878 | struct dp_packet *packet; | |
879 | ||
880 | dp_packet_batch_init(dst); | |
e883448e | 881 | DP_PACKET_BATCH_FOR_EACH (i, packet, src) { |
72c84bc2 AZ |
882 | dp_packet_batch_add(dst, dp_packet_clone(packet)); |
883 | } | |
cf4cf916 | 884 | dst->trunc = src->trunc; |
1895cc8d PS |
885 | } |
886 | ||
887 | static inline void | |
7d7ded7a | 888 | dp_packet_delete_batch(struct dp_packet_batch *batch, bool should_steal) |
1895cc8d | 889 | { |
7d7ded7a | 890 | if (should_steal) { |
72c84bc2 | 891 | struct dp_packet *packet; |
1895cc8d | 892 | |
e883448e | 893 | DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { |
72c84bc2 | 894 | dp_packet_delete(packet); |
1895cc8d | 895 | } |
72c84bc2 | 896 | dp_packet_batch_init(batch); |
1895cc8d PS |
897 | } |
898 | } | |
899 | ||
11d4c7a8 | 900 | static inline void |
75fb9148 | 901 | dp_packet_batch_init_packet_fields(struct dp_packet_batch *batch) |
11d4c7a8 DB |
902 | { |
903 | struct dp_packet *packet; | |
904 | ||
e883448e | 905 | DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { |
11d4c7a8 | 906 | dp_packet_reset_cutlen(packet); |
75fb9148 | 907 | packet->packet_type = htonl(PT_ETH); |
11d4c7a8 DB |
908 | } |
909 | } | |
910 | ||
aaca4fe0 | 911 | static inline void |
72c84bc2 | 912 | dp_packet_batch_apply_cutlen(struct dp_packet_batch *batch) |
aaca4fe0 | 913 | { |
72c84bc2 AZ |
914 | if (batch->trunc) { |
915 | struct dp_packet *packet; | |
aaca4fe0 | 916 | |
e883448e | 917 | DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { |
a61a2891 | 918 | dp_packet_set_size(packet, dp_packet_get_send_len(packet)); |
72c84bc2 AZ |
919 | dp_packet_reset_cutlen(packet); |
920 | } | |
921 | batch->trunc = false; | |
aaca4fe0 | 922 | } |
aaca4fe0 WT |
923 | } |
924 | ||
925 | static inline void | |
72c84bc2 | 926 | dp_packet_batch_reset_cutlen(struct dp_packet_batch *batch) |
aaca4fe0 | 927 | { |
72c84bc2 AZ |
928 | if (batch->trunc) { |
929 | struct dp_packet *packet; | |
aaca4fe0 | 930 | |
e883448e | 931 | DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { |
72c84bc2 AZ |
932 | dp_packet_reset_cutlen(packet); |
933 | } | |
934 | batch->trunc = false; | |
aaca4fe0 WT |
935 | } |
936 | } | |
937 | ||
91088554 DDP |
938 | #ifdef __cplusplus |
939 | } | |
940 | #endif | |
941 | ||
aaaac302 | 942 | #endif /* dp-packet.h */ |