]>
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 | ||
28 | #include "netdev-dpdk.h" | |
b19bab5b | 29 | #include "openvswitch/list.h" |
cf62fa4c PS |
30 | #include "packets.h" |
31 | #include "util.h" | |
2482b0b0 | 32 | #include "flow.h" |
91088554 DDP |
33 | |
34 | #ifdef __cplusplus | |
35 | extern "C" { | |
36 | #endif | |
37 | ||
cf62fa4c PS |
38 | enum OVS_PACKED_ENUM dp_packet_source { |
39 | DPBUF_MALLOC, /* Obtained via malloc(). */ | |
40 | DPBUF_STACK, /* Un-movable stack space or static buffer. */ | |
41 | DPBUF_STUB, /* Starts on stack, may expand into heap. */ | |
42 | DPBUF_DPDK, /* buffer data is from DPDK allocated memory. | |
88cbc2dd | 43 | * ref to dp_packet_init_dpdk() in dp-packet.c. */ |
cf62fa4c | 44 | }; |
91088554 | 45 | |
eb18b2a6 PS |
46 | #define DP_PACKET_CONTEXT_SIZE 64 |
47 | ||
82eb5b0a | 48 | /* Buffer for holding packet data. A dp_packet is automatically reallocated |
cf62fa4c | 49 | * as necessary if it grows too large for the available memory. |
2482b0b0 | 50 | * By default the packet type is set to Ethernet (PT_ETH). |
cf62fa4c | 51 | */ |
e14deea0 | 52 | struct dp_packet { |
cf62fa4c PS |
53 | #ifdef DPDK_NETDEV |
54 | struct rte_mbuf mbuf; /* DPDK mbuf */ | |
55 | #else | |
b8e57534 | 56 | void *base_; /* First byte of allocated space. */ |
11a6fbd5 | 57 | uint16_t allocated_; /* Number of bytes allocated. */ |
b8e57534 MK |
58 | uint16_t data_ofs; /* First byte actually in use. */ |
59 | uint32_t size_; /* Number of bytes in use. */ | |
2bc1bbd2 | 60 | uint32_t rss_hash; /* Packet hash. */ |
f2f44f5d | 61 | bool rss_hash_valid; /* Is the 'rss_hash' valid? */ |
61a2647e | 62 | #endif |
cf62fa4c | 63 | enum dp_packet_source source; /* Source of memory allocated as 'base'. */ |
82eb5b0a DDP |
64 | uint8_t l2_pad_size; /* Detected l2 padding size. |
65 | * Padding is non-pullable. */ | |
66 | uint16_t l2_5_ofs; /* MPLS label stack offset, or UINT16_MAX */ | |
67 | uint16_t l3_ofs; /* Network-level header offset, | |
68 | * or UINT16_MAX. */ | |
69 | uint16_t l4_ofs; /* Transport-level header offset, | |
70 | or UINT16_MAX. */ | |
aaca4fe0 | 71 | uint32_t cutlen; /* length in bytes to cut from the end. */ |
2482b0b0 | 72 | ovs_be32 packet_type; /* Packet type as defined in OpenFlow */ |
eb18b2a6 PS |
73 | union { |
74 | struct pkt_metadata md; | |
75 | uint64_t data[DP_PACKET_CONTEXT_SIZE / 8]; | |
76 | }; | |
91088554 DDP |
77 | }; |
78 | ||
5a07c6e1 | 79 | static inline void *dp_packet_data(const struct dp_packet *); |
cf62fa4c | 80 | static inline void dp_packet_set_data(struct dp_packet *, void *); |
5a07c6e1 | 81 | static inline void *dp_packet_base(const struct dp_packet *); |
cf62fa4c PS |
82 | static inline void dp_packet_set_base(struct dp_packet *, void *); |
83 | ||
84 | static inline uint32_t dp_packet_size(const struct dp_packet *); | |
85 | static inline void dp_packet_set_size(struct dp_packet *, uint32_t); | |
86 | ||
11a6fbd5 DDP |
87 | static inline uint16_t dp_packet_get_allocated(const struct dp_packet *); |
88 | static inline void dp_packet_set_allocated(struct dp_packet *, uint16_t); | |
89 | ||
5a07c6e1 DDP |
90 | void *dp_packet_resize_l2(struct dp_packet *, int increment); |
91 | void *dp_packet_resize_l2_5(struct dp_packet *, int increment); | |
2482b0b0 | 92 | static inline void *dp_packet_eth(const struct dp_packet *); |
82eb5b0a | 93 | static inline void dp_packet_reset_offsets(struct dp_packet *); |
cf62fa4c PS |
94 | static inline uint8_t dp_packet_l2_pad_size(const struct dp_packet *); |
95 | static inline void dp_packet_set_l2_pad_size(struct dp_packet *, uint8_t); | |
5a07c6e1 | 96 | static inline void *dp_packet_l2_5(const struct dp_packet *); |
cf62fa4c | 97 | static inline void dp_packet_set_l2_5(struct dp_packet *, void *); |
5a07c6e1 | 98 | static inline void *dp_packet_l3(const struct dp_packet *); |
cf62fa4c | 99 | static inline void dp_packet_set_l3(struct dp_packet *, void *); |
5a07c6e1 | 100 | static inline void *dp_packet_l4(const struct dp_packet *); |
cf62fa4c PS |
101 | static inline void dp_packet_set_l4(struct dp_packet *, void *); |
102 | static inline size_t dp_packet_l4_size(const struct dp_packet *); | |
103 | static inline const void *dp_packet_get_tcp_payload(const struct dp_packet *); | |
104 | static inline const void *dp_packet_get_udp_payload(const struct dp_packet *); | |
105 | static inline const void *dp_packet_get_sctp_payload(const struct dp_packet *); | |
106 | static inline const void *dp_packet_get_icmp_payload(const struct dp_packet *); | |
107 | static inline const void *dp_packet_get_nd_payload(const struct dp_packet *); | |
108 | ||
109 | void dp_packet_use(struct dp_packet *, void *, size_t); | |
110 | void dp_packet_use_stub(struct dp_packet *, void *, size_t); | |
111 | void dp_packet_use_const(struct dp_packet *, const void *, size_t); | |
112 | ||
5a07c6e1 | 113 | void dp_packet_init_dpdk(struct dp_packet *, size_t allocated); |
cf62fa4c PS |
114 | |
115 | void dp_packet_init(struct dp_packet *, size_t); | |
116 | void dp_packet_uninit(struct dp_packet *); | |
cf62fa4c PS |
117 | |
118 | struct dp_packet *dp_packet_new(size_t); | |
119 | struct dp_packet *dp_packet_new_with_headroom(size_t, size_t headroom); | |
120 | struct dp_packet *dp_packet_clone(const struct dp_packet *); | |
121 | struct dp_packet *dp_packet_clone_with_headroom(const struct dp_packet *, | |
5a07c6e1 | 122 | size_t headroom); |
cf62fa4c PS |
123 | struct dp_packet *dp_packet_clone_data(const void *, size_t); |
124 | struct dp_packet *dp_packet_clone_data_with_headroom(const void *, size_t, | |
5a07c6e1 | 125 | size_t headroom); |
cf62fa4c PS |
126 | static inline void dp_packet_delete(struct dp_packet *); |
127 | ||
128 | static inline void *dp_packet_at(const struct dp_packet *, size_t offset, | |
5a07c6e1 DDP |
129 | size_t size); |
130 | static inline void *dp_packet_at_assert(const struct dp_packet *, | |
131 | size_t offset, size_t size); | |
cf62fa4c PS |
132 | static inline void *dp_packet_tail(const struct dp_packet *); |
133 | static inline void *dp_packet_end(const struct dp_packet *); | |
134 | ||
135 | void *dp_packet_put_uninit(struct dp_packet *, size_t); | |
136 | void *dp_packet_put_zeros(struct dp_packet *, size_t); | |
137 | void *dp_packet_put(struct dp_packet *, const void *, size_t); | |
138 | char *dp_packet_put_hex(struct dp_packet *, const char *s, size_t *n); | |
139 | void dp_packet_reserve(struct dp_packet *, size_t); | |
5a07c6e1 DDP |
140 | void dp_packet_reserve_with_tailroom(struct dp_packet *, size_t headroom, |
141 | size_t tailroom); | |
142 | void *dp_packet_push_uninit(struct dp_packet *, size_t); | |
cf62fa4c | 143 | void *dp_packet_push_zeros(struct dp_packet *, size_t); |
5a07c6e1 | 144 | void *dp_packet_push(struct dp_packet *, const void *, size_t); |
cf62fa4c PS |
145 | |
146 | static inline size_t dp_packet_headroom(const struct dp_packet *); | |
147 | static inline size_t dp_packet_tailroom(const struct dp_packet *); | |
148 | void dp_packet_prealloc_headroom(struct dp_packet *, size_t); | |
149 | void dp_packet_prealloc_tailroom(struct dp_packet *, size_t); | |
150 | void dp_packet_shift(struct dp_packet *, int); | |
91088554 | 151 | |
cf62fa4c PS |
152 | static inline void dp_packet_clear(struct dp_packet *); |
153 | static inline void *dp_packet_pull(struct dp_packet *, size_t); | |
154 | static inline void *dp_packet_try_pull(struct dp_packet *, size_t); | |
91088554 | 155 | |
cf62fa4c | 156 | void *dp_packet_steal_data(struct dp_packet *); |
91088554 | 157 | |
5a07c6e1 DDP |
158 | static inline bool dp_packet_equal(const struct dp_packet *, |
159 | const struct dp_packet *); | |
cf62fa4c PS |
160 | |
161 | \f | |
cf62fa4c | 162 | /* Frees memory that 'b' points to, as well as 'b' itself. */ |
5a07c6e1 DDP |
163 | static inline void |
164 | dp_packet_delete(struct dp_packet *b) | |
cf62fa4c PS |
165 | { |
166 | if (b) { | |
167 | if (b->source == DPBUF_DPDK) { | |
168 | /* If this dp_packet was allocated by DPDK it must have been | |
169 | * created as a dp_packet */ | |
170 | free_dpdk_buf((struct dp_packet*) b); | |
171 | return; | |
172 | } | |
173 | ||
174 | dp_packet_uninit(b); | |
175 | free(b); | |
176 | } | |
177 | } | |
178 | ||
179 | /* If 'b' contains at least 'offset + size' bytes of data, returns a pointer to | |
180 | * byte 'offset'. Otherwise, returns a null pointer. */ | |
5a07c6e1 DDP |
181 | static inline void * |
182 | dp_packet_at(const struct dp_packet *b, size_t offset, size_t size) | |
91088554 | 183 | { |
5a07c6e1 DDP |
184 | return offset + size <= dp_packet_size(b) |
185 | ? (char *) dp_packet_data(b) + offset | |
186 | : NULL; | |
cf62fa4c | 187 | } |
91088554 | 188 | |
cf62fa4c PS |
189 | /* Returns a pointer to byte 'offset' in 'b', which must contain at least |
190 | * 'offset + size' bytes of data. */ | |
5a07c6e1 DDP |
191 | static inline void * |
192 | dp_packet_at_assert(const struct dp_packet *b, size_t offset, size_t size) | |
cf62fa4c PS |
193 | { |
194 | ovs_assert(offset + size <= dp_packet_size(b)); | |
195 | return ((char *) dp_packet_data(b)) + offset; | |
196 | } | |
197 | ||
198 | /* Returns a pointer to byte following the last byte of data in use in 'b'. */ | |
5a07c6e1 DDP |
199 | static inline void * |
200 | dp_packet_tail(const struct dp_packet *b) | |
cf62fa4c PS |
201 | { |
202 | return (char *) dp_packet_data(b) + dp_packet_size(b); | |
203 | } | |
204 | ||
205 | /* Returns a pointer to byte following the last byte allocated for use (but | |
206 | * not necessarily in use) in 'b'. */ | |
5a07c6e1 DDP |
207 | static inline void * |
208 | dp_packet_end(const struct dp_packet *b) | |
cf62fa4c | 209 | { |
11a6fbd5 | 210 | return (char *) dp_packet_base(b) + dp_packet_get_allocated(b); |
cf62fa4c PS |
211 | } |
212 | ||
213 | /* Returns the number of bytes of headroom in 'b', that is, the number of bytes | |
214 | * of unused space in dp_packet 'b' before the data that is in use. (Most | |
5a07c6e1 DDP |
215 | * commonly, the data in a dp_packet is at its beginning, and thus the |
216 | * dp_packet's headroom is 0.) */ | |
217 | static inline size_t | |
218 | dp_packet_headroom(const struct dp_packet *b) | |
cf62fa4c | 219 | { |
5a07c6e1 | 220 | return (char *) dp_packet_data(b) - (char *) dp_packet_base(b); |
cf62fa4c PS |
221 | } |
222 | ||
5a07c6e1 DDP |
223 | /* Returns the number of bytes that may be appended to the tail end of |
224 | * dp_packet 'b' before the dp_packet must be reallocated. */ | |
225 | static inline size_t | |
226 | dp_packet_tailroom(const struct dp_packet *b) | |
cf62fa4c | 227 | { |
5a07c6e1 | 228 | return (char *) dp_packet_end(b) - (char *) dp_packet_tail(b); |
cf62fa4c PS |
229 | } |
230 | ||
231 | /* Clears any data from 'b'. */ | |
5a07c6e1 DDP |
232 | static inline void |
233 | dp_packet_clear(struct dp_packet *b) | |
cf62fa4c PS |
234 | { |
235 | dp_packet_set_data(b, dp_packet_base(b)); | |
236 | dp_packet_set_size(b, 0); | |
237 | } | |
238 | ||
239 | /* Removes 'size' bytes from the head end of 'b', which must contain at least | |
240 | * 'size' bytes of data. Returns the first byte of data removed. */ | |
5a07c6e1 DDP |
241 | static inline void * |
242 | dp_packet_pull(struct dp_packet *b, size_t size) | |
cf62fa4c PS |
243 | { |
244 | void *data = dp_packet_data(b); | |
245 | ovs_assert(dp_packet_size(b) - dp_packet_l2_pad_size(b) >= size); | |
5a07c6e1 | 246 | dp_packet_set_data(b, (char *) dp_packet_data(b) + size); |
cf62fa4c PS |
247 | dp_packet_set_size(b, dp_packet_size(b) - size); |
248 | return data; | |
249 | } | |
250 | ||
251 | /* If 'b' has at least 'size' bytes of data, removes that many bytes from the | |
252 | * head end of 'b' and returns the first byte removed. Otherwise, returns a | |
253 | * null pointer without modifying 'b'. */ | |
5a07c6e1 DDP |
254 | static inline void * |
255 | dp_packet_try_pull(struct dp_packet *b, size_t size) | |
cf62fa4c PS |
256 | { |
257 | return dp_packet_size(b) - dp_packet_l2_pad_size(b) >= size | |
258 | ? dp_packet_pull(b, size) : NULL; | |
259 | } | |
260 | ||
5a07c6e1 DDP |
261 | static inline bool |
262 | dp_packet_equal(const struct dp_packet *a, const struct dp_packet *b) | |
cf62fa4c PS |
263 | { |
264 | return dp_packet_size(a) == dp_packet_size(b) && | |
5a07c6e1 | 265 | !memcmp(dp_packet_data(a), dp_packet_data(b), dp_packet_size(a)); |
cf62fa4c PS |
266 | } |
267 | ||
2482b0b0 JS |
268 | static inline bool |
269 | dp_packet_is_eth(const struct dp_packet *b) | |
270 | { | |
271 | return b->packet_type == htonl(PT_ETH); | |
272 | } | |
273 | ||
274 | /* Get the start of the Ethernet frame. 'l3_ofs' marks the end of the l2 | |
cf62fa4c | 275 | * headers, so return NULL if it is not set. */ |
5a07c6e1 | 276 | static inline void * |
2482b0b0 | 277 | dp_packet_eth(const struct dp_packet *b) |
cf62fa4c | 278 | { |
2482b0b0 JS |
279 | return (dp_packet_is_eth(b) && b->l3_ofs != UINT16_MAX) |
280 | ? dp_packet_data(b) : NULL; | |
cf62fa4c PS |
281 | } |
282 | ||
82eb5b0a DDP |
283 | /* Resets all layer offsets. 'l3' offset must be set before 'l2' can be |
284 | * retrieved. */ | |
5a07c6e1 DDP |
285 | static inline void |
286 | dp_packet_reset_offsets(struct dp_packet *b) | |
cf62fa4c | 287 | { |
cf62fa4c PS |
288 | b->l2_pad_size = 0; |
289 | b->l2_5_ofs = UINT16_MAX; | |
290 | b->l3_ofs = UINT16_MAX; | |
291 | b->l4_ofs = UINT16_MAX; | |
292 | } | |
293 | ||
5a07c6e1 DDP |
294 | static inline uint8_t |
295 | dp_packet_l2_pad_size(const struct dp_packet *b) | |
cf62fa4c PS |
296 | { |
297 | return b->l2_pad_size; | |
298 | } | |
299 | ||
5a07c6e1 DDP |
300 | static inline void |
301 | dp_packet_set_l2_pad_size(struct dp_packet *b, uint8_t pad_size) | |
cf62fa4c PS |
302 | { |
303 | ovs_assert(pad_size <= dp_packet_size(b)); | |
304 | b->l2_pad_size = pad_size; | |
305 | } | |
306 | ||
5a07c6e1 DDP |
307 | static inline void * |
308 | dp_packet_l2_5(const struct dp_packet *b) | |
cf62fa4c | 309 | { |
82eb5b0a DDP |
310 | return b->l2_5_ofs != UINT16_MAX |
311 | ? (char *) dp_packet_data(b) + b->l2_5_ofs | |
312 | : NULL; | |
cf62fa4c PS |
313 | } |
314 | ||
5a07c6e1 DDP |
315 | static inline void |
316 | dp_packet_set_l2_5(struct dp_packet *b, void *l2_5) | |
cf62fa4c | 317 | { |
82eb5b0a DDP |
318 | b->l2_5_ofs = l2_5 |
319 | ? (char *) l2_5 - (char *) dp_packet_data(b) | |
320 | : UINT16_MAX; | |
cf62fa4c PS |
321 | } |
322 | ||
5a07c6e1 DDP |
323 | static inline void * |
324 | dp_packet_l3(const struct dp_packet *b) | |
cf62fa4c | 325 | { |
82eb5b0a DDP |
326 | return b->l3_ofs != UINT16_MAX |
327 | ? (char *) dp_packet_data(b) + b->l3_ofs | |
328 | : NULL; | |
cf62fa4c PS |
329 | } |
330 | ||
5a07c6e1 DDP |
331 | static inline void |
332 | dp_packet_set_l3(struct dp_packet *b, void *l3) | |
cf62fa4c | 333 | { |
82eb5b0a | 334 | b->l3_ofs = l3 ? (char *) l3 - (char *) dp_packet_data(b) : UINT16_MAX; |
cf62fa4c PS |
335 | } |
336 | ||
5a07c6e1 DDP |
337 | static inline void * |
338 | dp_packet_l4(const struct dp_packet *b) | |
cf62fa4c | 339 | { |
82eb5b0a DDP |
340 | return b->l4_ofs != UINT16_MAX |
341 | ? (char *) dp_packet_data(b) + b->l4_ofs | |
342 | : NULL; | |
cf62fa4c PS |
343 | } |
344 | ||
5a07c6e1 DDP |
345 | static inline void |
346 | dp_packet_set_l4(struct dp_packet *b, void *l4) | |
cf62fa4c | 347 | { |
82eb5b0a | 348 | b->l4_ofs = l4 ? (char *) l4 - (char *) dp_packet_data(b) : UINT16_MAX; |
cf62fa4c PS |
349 | } |
350 | ||
5a07c6e1 DDP |
351 | static inline size_t |
352 | dp_packet_l4_size(const struct dp_packet *b) | |
cf62fa4c PS |
353 | { |
354 | return b->l4_ofs != UINT16_MAX | |
355 | ? (const char *)dp_packet_tail(b) - (const char *)dp_packet_l4(b) | |
356 | - dp_packet_l2_pad_size(b) | |
357 | : 0; | |
358 | } | |
359 | ||
5a07c6e1 DDP |
360 | static inline const void * |
361 | dp_packet_get_tcp_payload(const struct dp_packet *b) | |
cf62fa4c PS |
362 | { |
363 | size_t l4_size = dp_packet_l4_size(b); | |
364 | ||
365 | if (OVS_LIKELY(l4_size >= TCP_HEADER_LEN)) { | |
366 | struct tcp_header *tcp = dp_packet_l4(b); | |
367 | int tcp_len = TCP_OFFSET(tcp->tcp_ctl) * 4; | |
368 | ||
369 | if (OVS_LIKELY(tcp_len >= TCP_HEADER_LEN && tcp_len <= l4_size)) { | |
370 | return (const char *)tcp + tcp_len; | |
371 | } | |
372 | } | |
373 | return NULL; | |
374 | } | |
375 | ||
5a07c6e1 DDP |
376 | static inline const void * |
377 | dp_packet_get_udp_payload(const struct dp_packet *b) | |
cf62fa4c PS |
378 | { |
379 | return OVS_LIKELY(dp_packet_l4_size(b) >= UDP_HEADER_LEN) | |
380 | ? (const char *)dp_packet_l4(b) + UDP_HEADER_LEN : NULL; | |
381 | } | |
382 | ||
5a07c6e1 DDP |
383 | static inline const void * |
384 | dp_packet_get_sctp_payload(const struct dp_packet *b) | |
cf62fa4c PS |
385 | { |
386 | return OVS_LIKELY(dp_packet_l4_size(b) >= SCTP_HEADER_LEN) | |
387 | ? (const char *)dp_packet_l4(b) + SCTP_HEADER_LEN : NULL; | |
388 | } | |
389 | ||
5a07c6e1 DDP |
390 | static inline const void * |
391 | dp_packet_get_icmp_payload(const struct dp_packet *b) | |
cf62fa4c PS |
392 | { |
393 | return OVS_LIKELY(dp_packet_l4_size(b) >= ICMP_HEADER_LEN) | |
394 | ? (const char *)dp_packet_l4(b) + ICMP_HEADER_LEN : NULL; | |
395 | } | |
396 | ||
5a07c6e1 DDP |
397 | static inline const void * |
398 | dp_packet_get_nd_payload(const struct dp_packet *b) | |
cf62fa4c PS |
399 | { |
400 | return OVS_LIKELY(dp_packet_l4_size(b) >= ND_MSG_LEN) | |
401 | ? (const char *)dp_packet_l4(b) + ND_MSG_LEN : NULL; | |
402 | } | |
403 | ||
404 | #ifdef DPDK_NETDEV | |
405 | BUILD_ASSERT_DECL(offsetof(struct dp_packet, mbuf) == 0); | |
406 | ||
5a07c6e1 DDP |
407 | static inline void * |
408 | dp_packet_base(const struct dp_packet *b) | |
cf62fa4c PS |
409 | { |
410 | return b->mbuf.buf_addr; | |
411 | } | |
412 | ||
5a07c6e1 DDP |
413 | static inline void |
414 | dp_packet_set_base(struct dp_packet *b, void *d) | |
cf62fa4c PS |
415 | { |
416 | b->mbuf.buf_addr = d; | |
417 | } | |
418 | ||
5a07c6e1 DDP |
419 | static inline uint32_t |
420 | dp_packet_size(const struct dp_packet *b) | |
cf62fa4c | 421 | { |
b8e57534 | 422 | return b->mbuf.pkt_len; |
cf62fa4c PS |
423 | } |
424 | ||
5a07c6e1 DDP |
425 | static inline void |
426 | dp_packet_set_size(struct dp_packet *b, uint32_t v) | |
cf62fa4c | 427 | { |
b8e57534 MK |
428 | /* netdev-dpdk does not currently support segmentation; consequently, for |
429 | * all intents and purposes, 'data_len' (16 bit) and 'pkt_len' (32 bit) may | |
430 | * be used interchangably. | |
431 | * | |
432 | * On the datapath, it is expected that the size of packets | |
433 | * (and thus 'v') will always be <= UINT16_MAX; this means that there is no | |
434 | * loss of accuracy in assigning 'v' to 'data_len'. | |
b8e57534 MK |
435 | */ |
436 | b->mbuf.data_len = (uint16_t)v; /* Current seg length. */ | |
437 | b->mbuf.pkt_len = v; /* Total length of all segments linked to | |
438 | * this segment. */ | |
cf62fa4c PS |
439 | } |
440 | ||
5a07c6e1 DDP |
441 | static inline uint16_t |
442 | __packet_data(const struct dp_packet *b) | |
cf62fa4c | 443 | { |
b8e57534 | 444 | return b->mbuf.data_off; |
cf62fa4c PS |
445 | } |
446 | ||
5a07c6e1 DDP |
447 | static inline void |
448 | __packet_set_data(struct dp_packet *b, uint16_t v) | |
cf62fa4c | 449 | { |
b8e57534 | 450 | b->mbuf.data_off = v; |
cf62fa4c PS |
451 | } |
452 | ||
5a07c6e1 DDP |
453 | static inline uint16_t |
454 | dp_packet_get_allocated(const struct dp_packet *b) | |
11a6fbd5 DDP |
455 | { |
456 | return b->mbuf.buf_len; | |
457 | } | |
458 | ||
5a07c6e1 DDP |
459 | static inline void |
460 | dp_packet_set_allocated(struct dp_packet *b, uint16_t s) | |
11a6fbd5 DDP |
461 | { |
462 | b->mbuf.buf_len = s; | |
463 | } | |
b8e57534 | 464 | #else |
5a07c6e1 DDP |
465 | static inline void * |
466 | dp_packet_base(const struct dp_packet *b) | |
cf62fa4c PS |
467 | { |
468 | return b->base_; | |
469 | } | |
470 | ||
5a07c6e1 DDP |
471 | static inline void |
472 | dp_packet_set_base(struct dp_packet *b, void *d) | |
cf62fa4c PS |
473 | { |
474 | b->base_ = d; | |
475 | } | |
476 | ||
5a07c6e1 DDP |
477 | static inline uint32_t |
478 | dp_packet_size(const struct dp_packet *b) | |
cf62fa4c PS |
479 | { |
480 | return b->size_; | |
481 | } | |
482 | ||
5a07c6e1 DDP |
483 | static inline void |
484 | dp_packet_set_size(struct dp_packet *b, uint32_t v) | |
cf62fa4c PS |
485 | { |
486 | b->size_ = v; | |
487 | } | |
b8e57534 | 488 | |
5a07c6e1 DDP |
489 | static inline uint16_t |
490 | __packet_data(const struct dp_packet *b) | |
b8e57534 MK |
491 | { |
492 | return b->data_ofs; | |
493 | } | |
494 | ||
5a07c6e1 DDP |
495 | static inline void |
496 | __packet_set_data(struct dp_packet *b, uint16_t v) | |
b8e57534 MK |
497 | { |
498 | b->data_ofs = v; | |
499 | } | |
500 | ||
5a07c6e1 DDP |
501 | static inline uint16_t |
502 | dp_packet_get_allocated(const struct dp_packet *b) | |
11a6fbd5 DDP |
503 | { |
504 | return b->allocated_; | |
505 | } | |
506 | ||
5a07c6e1 DDP |
507 | static inline void |
508 | dp_packet_set_allocated(struct dp_packet *b, uint16_t s) | |
11a6fbd5 DDP |
509 | { |
510 | b->allocated_ = s; | |
511 | } | |
cf62fa4c PS |
512 | #endif |
513 | ||
aaca4fe0 WT |
514 | static inline void |
515 | dp_packet_reset_cutlen(struct dp_packet *b) | |
516 | { | |
517 | b->cutlen = 0; | |
518 | } | |
519 | ||
520 | static inline uint32_t | |
521 | dp_packet_set_cutlen(struct dp_packet *b, uint32_t max_len) | |
522 | { | |
523 | if (max_len < ETH_HEADER_LEN) { | |
524 | max_len = ETH_HEADER_LEN; | |
525 | } | |
526 | ||
527 | if (max_len >= dp_packet_size(b)) { | |
528 | b->cutlen = 0; | |
529 | } else { | |
530 | b->cutlen = dp_packet_size(b) - max_len; | |
531 | } | |
532 | return b->cutlen; | |
533 | } | |
534 | ||
535 | static inline uint32_t | |
536 | dp_packet_get_cutlen(struct dp_packet *b) | |
537 | { | |
538 | /* Always in valid range if user uses dp_packet_set_cutlen. */ | |
539 | return b->cutlen; | |
540 | } | |
541 | ||
5a07c6e1 DDP |
542 | static inline void * |
543 | dp_packet_data(const struct dp_packet *b) | |
b8e57534 | 544 | { |
5a07c6e1 DDP |
545 | return __packet_data(b) != UINT16_MAX |
546 | ? (char *) dp_packet_base(b) + __packet_data(b) : NULL; | |
b8e57534 MK |
547 | } |
548 | ||
5a07c6e1 DDP |
549 | static inline void |
550 | dp_packet_set_data(struct dp_packet *b, void *data) | |
b8e57534 MK |
551 | { |
552 | if (data) { | |
5a07c6e1 | 553 | __packet_set_data(b, (char *) data - (char *) dp_packet_base(b)); |
b8e57534 MK |
554 | } else { |
555 | __packet_set_data(b, UINT16_MAX); | |
556 | } | |
557 | } | |
558 | ||
5a07c6e1 DDP |
559 | static inline void |
560 | dp_packet_reset_packet(struct dp_packet *b, int off) | |
cf62fa4c PS |
561 | { |
562 | dp_packet_set_size(b, dp_packet_size(b) - off); | |
82eb5b0a | 563 | dp_packet_set_data(b, ((unsigned char *) dp_packet_data(b) + off)); |
b513ea34 | 564 | dp_packet_reset_offsets(b); |
91088554 DDP |
565 | } |
566 | ||
f2f44f5d DDP |
567 | /* Returns the RSS hash of the packet 'p'. Note that the returned value is |
568 | * correct only if 'dp_packet_rss_valid(p)' returns true */ | |
5a07c6e1 DDP |
569 | static inline uint32_t |
570 | dp_packet_get_rss_hash(struct dp_packet *p) | |
61a2647e DDP |
571 | { |
572 | #ifdef DPDK_NETDEV | |
b8e57534 | 573 | return p->mbuf.hash.rss; |
61a2647e | 574 | #else |
2bc1bbd2 | 575 | return p->rss_hash; |
61a2647e DDP |
576 | #endif |
577 | } | |
578 | ||
5a07c6e1 DDP |
579 | static inline void |
580 | dp_packet_set_rss_hash(struct dp_packet *p, uint32_t hash) | |
61a2647e DDP |
581 | { |
582 | #ifdef DPDK_NETDEV | |
b8e57534 | 583 | p->mbuf.hash.rss = hash; |
f2f44f5d | 584 | p->mbuf.ol_flags |= PKT_RX_RSS_HASH; |
61a2647e | 585 | #else |
2bc1bbd2 | 586 | p->rss_hash = hash; |
f2f44f5d DDP |
587 | p->rss_hash_valid = true; |
588 | #endif | |
589 | } | |
590 | ||
591 | static inline bool | |
592 | dp_packet_rss_valid(struct dp_packet *p) | |
593 | { | |
594 | #ifdef DPDK_NETDEV | |
595 | return p->mbuf.ol_flags & PKT_RX_RSS_HASH; | |
596 | #else | |
597 | return p->rss_hash_valid; | |
598 | #endif | |
599 | } | |
600 | ||
601 | static inline void | |
602 | dp_packet_rss_invalidate(struct dp_packet *p) | |
603 | { | |
604 | #ifdef DPDK_NETDEV | |
605 | p->mbuf.ol_flags &= ~PKT_RX_RSS_HASH; | |
606 | #else | |
607 | p->rss_hash_valid = false; | |
61a2647e DDP |
608 | #endif |
609 | } | |
610 | ||
1a2bb118 SC |
611 | static inline bool |
612 | dp_packet_ip_checksum_valid(struct dp_packet *p) | |
613 | { | |
614 | #ifdef DPDK_NETDEV | |
615 | return p->mbuf.ol_flags & PKT_RX_IP_CKSUM_GOOD; | |
616 | #else | |
617 | return 0 && p; | |
618 | #endif | |
619 | } | |
620 | ||
621 | static inline bool | |
622 | dp_packet_l4_checksum_valid(struct dp_packet *p) | |
623 | { | |
624 | #ifdef DPDK_NETDEV | |
625 | return p->mbuf.ol_flags & PKT_RX_L4_CKSUM_GOOD; | |
626 | #else | |
627 | return 0 && p; | |
628 | #endif | |
629 | } | |
630 | ||
631 | #ifdef DPDK_NETDEV | |
632 | static inline void | |
633 | reset_dp_packet_checksum_ol_flags(struct dp_packet *p) | |
634 | { | |
635 | p->mbuf.ol_flags &= ~(PKT_RX_L4_CKSUM_GOOD | PKT_RX_L4_CKSUM_BAD | | |
636 | PKT_RX_IP_CKSUM_GOOD | PKT_RX_IP_CKSUM_BAD); | |
637 | } | |
638 | #else | |
639 | #define reset_dp_packet_checksum_ol_flags(arg) | |
640 | #endif | |
641 | ||
1895cc8d PS |
642 | enum { NETDEV_MAX_BURST = 32 }; /* Maximum number packets in a batch. */ |
643 | ||
644 | struct dp_packet_batch { | |
72c84bc2 | 645 | size_t count; |
aaca4fe0 | 646 | bool trunc; /* true if the batch needs truncate. */ |
1895cc8d PS |
647 | struct dp_packet *packets[NETDEV_MAX_BURST]; |
648 | }; | |
649 | ||
72c84bc2 AZ |
650 | static inline void |
651 | dp_packet_batch_init(struct dp_packet_batch *batch) | |
1895cc8d | 652 | { |
72c84bc2 AZ |
653 | batch->count = 0; |
654 | batch->trunc = false; | |
1895cc8d PS |
655 | } |
656 | ||
657 | static inline void | |
72c84bc2 AZ |
658 | dp_packet_batch_add__(struct dp_packet_batch *batch, |
659 | struct dp_packet *packet, size_t limit) | |
1895cc8d | 660 | { |
72c84bc2 AZ |
661 | if (batch->count < limit) { |
662 | batch->packets[batch->count++] = packet; | |
663 | } else { | |
664 | dp_packet_delete(packet); | |
1895cc8d | 665 | } |
1895cc8d PS |
666 | } |
667 | ||
72c84bc2 AZ |
668 | /* When the batch is full, 'packet' will be dropped and freed. */ |
669 | static inline void | |
670 | dp_packet_batch_add(struct dp_packet_batch *batch, struct dp_packet *packet) | |
671 | { | |
672 | dp_packet_batch_add__(batch, packet, NETDEV_MAX_BURST); | |
673 | } | |
674 | ||
675 | static inline size_t | |
676 | dp_packet_batch_size(const struct dp_packet_batch *batch) | |
677 | { | |
678 | return batch->count; | |
679 | } | |
680 | ||
681 | /* | |
682 | * Clear 'batch' for refill. Use dp_packet_batch_refill() to add | |
683 | * packets back into the 'batch'. | |
684 | * | |
685 | * Return the original size of the 'batch'. */ | |
1895cc8d | 686 | static inline void |
72c84bc2 | 687 | dp_packet_batch_refill_init(struct dp_packet_batch *batch) |
1895cc8d | 688 | { |
72c84bc2 AZ |
689 | batch->count = 0; |
690 | }; | |
691 | ||
692 | static inline void | |
693 | dp_packet_batch_refill(struct dp_packet_batch *batch, | |
694 | struct dp_packet *packet, size_t idx) | |
695 | { | |
696 | dp_packet_batch_add__(batch, packet, MIN(NETDEV_MAX_BURST, idx + 1)); | |
697 | } | |
698 | ||
699 | static inline void | |
700 | dp_packet_batch_init_packet(struct dp_packet_batch *batch, struct dp_packet *p) | |
701 | { | |
702 | dp_packet_batch_init(batch); | |
703 | batch->count = 1; | |
704 | batch->packets[0] = p; | |
705 | } | |
706 | ||
707 | static inline bool | |
708 | dp_packet_batch_is_empty(const struct dp_packet_batch *batch) | |
709 | { | |
710 | return !dp_packet_batch_size(batch); | |
711 | } | |
712 | ||
713 | #define DP_PACKET_BATCH_FOR_EACH(PACKET, BATCH) \ | |
714 | for (size_t i = 0; i < dp_packet_batch_size(BATCH); i++) \ | |
715 | if (PACKET = BATCH->packets[i], true) | |
716 | ||
717 | /* Use this macro for cases where some packets in the 'BATCH' may be | |
718 | * dropped after going through each packet in the 'BATCH'. | |
719 | * | |
720 | * For packets to stay in the 'BATCH', they need to be refilled back | |
721 | * into the 'BATCH' by calling dp_packet_batch_refill(). Caller owns | |
722 | * the packets that are not refilled. | |
723 | * | |
724 | * Caller needs to supply 'SIZE', that stores the current number of | |
725 | * packets in 'BATCH'. It is best to declare this variable with | |
726 | * the 'const' modifier since it should not be modified by | |
727 | * the iterator. */ | |
728 | #define DP_PACKET_BATCH_REFILL_FOR_EACH(IDX, SIZE, PACKET, BATCH) \ | |
729 | for (dp_packet_batch_refill_init(BATCH), IDX=0; IDX < SIZE; IDX++) \ | |
730 | if (PACKET = BATCH->packets[IDX], true) | |
731 | ||
732 | static inline void | |
733 | dp_packet_batch_clone(struct dp_packet_batch *dst, | |
734 | struct dp_packet_batch *src) | |
735 | { | |
736 | struct dp_packet *packet; | |
737 | ||
738 | dp_packet_batch_init(dst); | |
739 | DP_PACKET_BATCH_FOR_EACH (packet, src) { | |
740 | dp_packet_batch_add(dst, dp_packet_clone(packet)); | |
741 | } | |
1895cc8d PS |
742 | } |
743 | ||
744 | static inline void | |
745 | dp_packet_delete_batch(struct dp_packet_batch *batch, bool may_steal) | |
746 | { | |
747 | if (may_steal) { | |
72c84bc2 | 748 | struct dp_packet *packet; |
1895cc8d | 749 | |
72c84bc2 AZ |
750 | DP_PACKET_BATCH_FOR_EACH (packet, batch) { |
751 | dp_packet_delete(packet); | |
1895cc8d | 752 | } |
72c84bc2 | 753 | dp_packet_batch_init(batch); |
1895cc8d PS |
754 | } |
755 | } | |
756 | ||
aaca4fe0 | 757 | static inline void |
72c84bc2 | 758 | dp_packet_batch_apply_cutlen(struct dp_packet_batch *batch) |
aaca4fe0 | 759 | { |
72c84bc2 AZ |
760 | if (batch->trunc) { |
761 | struct dp_packet *packet; | |
aaca4fe0 | 762 | |
72c84bc2 AZ |
763 | DP_PACKET_BATCH_FOR_EACH (packet, batch) { |
764 | uint32_t cutlen = dp_packet_get_cutlen(packet); | |
aaca4fe0 | 765 | |
72c84bc2 AZ |
766 | dp_packet_set_size(packet, dp_packet_size(packet) - cutlen); |
767 | dp_packet_reset_cutlen(packet); | |
768 | } | |
769 | batch->trunc = false; | |
aaca4fe0 | 770 | } |
aaca4fe0 WT |
771 | } |
772 | ||
773 | static inline void | |
72c84bc2 | 774 | dp_packet_batch_reset_cutlen(struct dp_packet_batch *batch) |
aaca4fe0 | 775 | { |
72c84bc2 AZ |
776 | if (batch->trunc) { |
777 | struct dp_packet *packet; | |
aaca4fe0 | 778 | |
72c84bc2 AZ |
779 | DP_PACKET_BATCH_FOR_EACH (packet, batch) { |
780 | dp_packet_reset_cutlen(packet); | |
781 | } | |
782 | batch->trunc = false; | |
aaca4fe0 WT |
783 | } |
784 | } | |
785 | ||
91088554 DDP |
786 | #ifdef __cplusplus |
787 | } | |
788 | #endif | |
789 | ||
aaaac302 | 790 | #endif /* dp-packet.h */ |