]>
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 | ||
29bb3093 WT |
51 | #ifdef DPDK_NETDEV |
52 | #define DEF_OL_FLAG(NAME, DPDK_DEF, GENERIC_DEF) NAME = DPDK_DEF | |
53 | #else | |
54 | #define DEF_OL_FLAG(NAME, DPDK_DEF, GENERIC_DEF) NAME = GENERIC_DEF | |
55 | #endif | |
56 | ||
a47e2db2 IM |
57 | /* Bit masks for the 'ol_flags' member of the 'dp_packet' structure. */ |
58 | enum dp_packet_offload_mask { | |
29bb3093 WT |
59 | /* Value 0 is not used. */ |
60 | /* Is the 'rss_hash' valid? */ | |
61 | DEF_OL_FLAG(DP_PACKET_OL_RSS_HASH, PKT_RX_RSS_HASH, 0x1), | |
62 | /* Is the 'flow_mark' valid? */ | |
63 | DEF_OL_FLAG(DP_PACKET_OL_FLOW_MARK, PKT_RX_FDIR_ID, 0x2), | |
64 | /* Bad L4 checksum in the packet. */ | |
65 | DEF_OL_FLAG(DP_PACKET_OL_RX_L4_CKSUM_BAD, PKT_RX_L4_CKSUM_BAD, 0x4), | |
66 | /* Bad IP checksum in the packet. */ | |
67 | DEF_OL_FLAG(DP_PACKET_OL_RX_IP_CKSUM_BAD, PKT_RX_IP_CKSUM_BAD, 0x8), | |
68 | /* Valid L4 checksum in the packet. */ | |
69 | DEF_OL_FLAG(DP_PACKET_OL_RX_L4_CKSUM_GOOD, PKT_RX_L4_CKSUM_GOOD, 0x10), | |
70 | /* Valid IP checksum in the packet. */ | |
71 | DEF_OL_FLAG(DP_PACKET_OL_RX_IP_CKSUM_GOOD, PKT_RX_IP_CKSUM_GOOD, 0x20), | |
72 | /* TCP Segmentation Offload. */ | |
73 | DEF_OL_FLAG(DP_PACKET_OL_TX_TCP_SEG, PKT_TX_TCP_SEG, 0x40), | |
74 | /* Offloaded packet is IPv4. */ | |
75 | DEF_OL_FLAG(DP_PACKET_OL_TX_IPV4, PKT_TX_IPV4, 0x80), | |
76 | /* Offloaded packet is IPv6. */ | |
77 | DEF_OL_FLAG(DP_PACKET_OL_TX_IPV6, PKT_TX_IPV6, 0x100), | |
78 | /* Offload TCP checksum. */ | |
79 | DEF_OL_FLAG(DP_PACKET_OL_TX_TCP_CKSUM, PKT_TX_TCP_CKSUM, 0x200), | |
80 | /* Offload UDP checksum. */ | |
81 | DEF_OL_FLAG(DP_PACKET_OL_TX_UDP_CKSUM, PKT_TX_UDP_CKSUM, 0x400), | |
82 | /* Offload SCTP checksum. */ | |
83 | DEF_OL_FLAG(DP_PACKET_OL_TX_SCTP_CKSUM, PKT_TX_SCTP_CKSUM, 0x800), | |
84 | /* Adding new field requires adding to DP_PACKET_OL_SUPPORTED_MASK. */ | |
a47e2db2 | 85 | }; |
29bb3093 WT |
86 | |
87 | #define DP_PACKET_OL_SUPPORTED_MASK (DP_PACKET_OL_RSS_HASH | \ | |
88 | DP_PACKET_OL_FLOW_MARK | \ | |
89 | DP_PACKET_OL_RX_L4_CKSUM_BAD | \ | |
90 | DP_PACKET_OL_RX_IP_CKSUM_BAD | \ | |
91 | DP_PACKET_OL_RX_L4_CKSUM_GOOD | \ | |
92 | DP_PACKET_OL_RX_IP_CKSUM_GOOD | \ | |
93 | DP_PACKET_OL_TX_TCP_SEG | \ | |
94 | DP_PACKET_OL_TX_IPV4 | \ | |
95 | DP_PACKET_OL_TX_IPV6 | \ | |
96 | DP_PACKET_OL_TX_TCP_CKSUM | \ | |
97 | DP_PACKET_OL_TX_UDP_CKSUM | \ | |
98 | DP_PACKET_OL_TX_SCTP_CKSUM) | |
99 | ||
100 | #define DP_PACKET_OL_TX_L4_MASK (DP_PACKET_OL_TX_TCP_CKSUM | \ | |
101 | DP_PACKET_OL_TX_UDP_CKSUM | \ | |
102 | DP_PACKET_OL_TX_SCTP_CKSUM) | |
103 | #define DP_PACKET_OL_RX_IP_CKSUM_MASK (DP_PACKET_OL_RX_IP_CKSUM_GOOD | \ | |
104 | DP_PACKET_OL_RX_IP_CKSUM_BAD) | |
105 | #define DP_PACKET_OL_RX_L4_CKSUM_MASK (DP_PACKET_OL_RX_L4_CKSUM_GOOD | \ | |
106 | DP_PACKET_OL_RX_L4_CKSUM_BAD) | |
a47e2db2 | 107 | |
82eb5b0a | 108 | /* Buffer for holding packet data. A dp_packet is automatically reallocated |
cf62fa4c | 109 | * as necessary if it grows too large for the available memory. |
2482b0b0 | 110 | * By default the packet type is set to Ethernet (PT_ETH). |
cf62fa4c | 111 | */ |
e14deea0 | 112 | struct dp_packet { |
cf62fa4c PS |
113 | #ifdef DPDK_NETDEV |
114 | struct rte_mbuf mbuf; /* DPDK mbuf */ | |
115 | #else | |
b8e57534 | 116 | void *base_; /* First byte of allocated space. */ |
11a6fbd5 | 117 | uint16_t allocated_; /* Number of bytes allocated. */ |
b8e57534 MK |
118 | uint16_t data_ofs; /* First byte actually in use. */ |
119 | uint32_t size_; /* Number of bytes in use. */ | |
a47e2db2 | 120 | uint32_t ol_flags; /* Offloading flags. */ |
2bc1bbd2 | 121 | uint32_t rss_hash; /* Packet hash. */ |
0f706b37 | 122 | uint32_t flow_mark; /* Packet flow mark. */ |
61a2647e | 123 | #endif |
cf62fa4c | 124 | enum dp_packet_source source; /* Source of memory allocated as 'base'. */ |
84b70576 FA |
125 | |
126 | /* All the following elements of this struct are copied in a single call | |
127 | * of memcpy in dp_packet_clone_with_headroom. */ | |
82eb5b0a DDP |
128 | uint8_t l2_pad_size; /* Detected l2 padding size. |
129 | * Padding is non-pullable. */ | |
130 | uint16_t l2_5_ofs; /* MPLS label stack offset, or UINT16_MAX */ | |
131 | uint16_t l3_ofs; /* Network-level header offset, | |
132 | * or UINT16_MAX. */ | |
133 | uint16_t l4_ofs; /* Transport-level header offset, | |
134 | or UINT16_MAX. */ | |
aaca4fe0 | 135 | uint32_t cutlen; /* length in bytes to cut from the end. */ |
2482b0b0 | 136 | ovs_be32 packet_type; /* Packet type as defined in OpenFlow */ |
eb18b2a6 PS |
137 | union { |
138 | struct pkt_metadata md; | |
139 | uint64_t data[DP_PACKET_CONTEXT_SIZE / 8]; | |
140 | }; | |
91088554 DDP |
141 | }; |
142 | ||
0de1b425 WT |
143 | #if HAVE_AF_XDP |
144 | struct dp_packet_afxdp { | |
145 | struct umem_pool *mpool; | |
146 | struct dp_packet packet; | |
147 | }; | |
148 | #endif | |
149 | ||
5a07c6e1 | 150 | static inline void *dp_packet_data(const struct dp_packet *); |
cf62fa4c | 151 | static inline void dp_packet_set_data(struct dp_packet *, void *); |
5a07c6e1 | 152 | static inline void *dp_packet_base(const struct dp_packet *); |
cf62fa4c PS |
153 | static inline void dp_packet_set_base(struct dp_packet *, void *); |
154 | ||
155 | static inline uint32_t dp_packet_size(const struct dp_packet *); | |
156 | static inline void dp_packet_set_size(struct dp_packet *, uint32_t); | |
157 | ||
11a6fbd5 DDP |
158 | static inline uint16_t dp_packet_get_allocated(const struct dp_packet *); |
159 | static inline void dp_packet_set_allocated(struct dp_packet *, uint16_t); | |
160 | ||
5a07c6e1 DDP |
161 | void *dp_packet_resize_l2(struct dp_packet *, int increment); |
162 | void *dp_packet_resize_l2_5(struct dp_packet *, int increment); | |
2482b0b0 | 163 | static inline void *dp_packet_eth(const struct dp_packet *); |
82eb5b0a | 164 | static inline void dp_packet_reset_offsets(struct dp_packet *); |
cf62fa4c PS |
165 | static inline uint8_t dp_packet_l2_pad_size(const struct dp_packet *); |
166 | static inline void dp_packet_set_l2_pad_size(struct dp_packet *, uint8_t); | |
5a07c6e1 | 167 | static inline void *dp_packet_l2_5(const struct dp_packet *); |
cf62fa4c | 168 | static inline void dp_packet_set_l2_5(struct dp_packet *, void *); |
5a07c6e1 | 169 | static inline void *dp_packet_l3(const struct dp_packet *); |
cf62fa4c | 170 | static inline void dp_packet_set_l3(struct dp_packet *, void *); |
5a07c6e1 | 171 | static inline void *dp_packet_l4(const struct dp_packet *); |
cf62fa4c PS |
172 | static inline void dp_packet_set_l4(struct dp_packet *, void *); |
173 | static inline size_t dp_packet_l4_size(const struct dp_packet *); | |
174 | static inline const void *dp_packet_get_tcp_payload(const struct dp_packet *); | |
175 | static inline const void *dp_packet_get_udp_payload(const struct dp_packet *); | |
176 | static inline const void *dp_packet_get_sctp_payload(const struct dp_packet *); | |
177 | static inline const void *dp_packet_get_icmp_payload(const struct dp_packet *); | |
178 | static inline const void *dp_packet_get_nd_payload(const struct dp_packet *); | |
179 | ||
180 | void dp_packet_use(struct dp_packet *, void *, size_t); | |
181 | void dp_packet_use_stub(struct dp_packet *, void *, size_t); | |
182 | void dp_packet_use_const(struct dp_packet *, const void *, size_t); | |
0de1b425 WT |
183 | #if HAVE_AF_XDP |
184 | void dp_packet_use_afxdp(struct dp_packet *, void *, size_t, size_t); | |
185 | #endif | |
3aaa6201 | 186 | void dp_packet_init_dpdk(struct dp_packet *); |
cf62fa4c PS |
187 | |
188 | void dp_packet_init(struct dp_packet *, size_t); | |
189 | void dp_packet_uninit(struct dp_packet *); | |
cf62fa4c PS |
190 | |
191 | struct dp_packet *dp_packet_new(size_t); | |
192 | struct dp_packet *dp_packet_new_with_headroom(size_t, size_t headroom); | |
193 | struct dp_packet *dp_packet_clone(const struct dp_packet *); | |
194 | struct dp_packet *dp_packet_clone_with_headroom(const struct dp_packet *, | |
5a07c6e1 | 195 | size_t headroom); |
cf62fa4c PS |
196 | struct dp_packet *dp_packet_clone_data(const void *, size_t); |
197 | struct dp_packet *dp_packet_clone_data_with_headroom(const void *, size_t, | |
5a07c6e1 | 198 | size_t headroom); |
73858f9d FL |
199 | void dp_packet_resize(struct dp_packet *b, size_t new_headroom, |
200 | size_t new_tailroom); | |
cf62fa4c PS |
201 | static inline void dp_packet_delete(struct dp_packet *); |
202 | ||
203 | static inline void *dp_packet_at(const struct dp_packet *, size_t offset, | |
5a07c6e1 DDP |
204 | size_t size); |
205 | static inline void *dp_packet_at_assert(const struct dp_packet *, | |
206 | size_t offset, size_t size); | |
cf62fa4c PS |
207 | static inline void *dp_packet_tail(const struct dp_packet *); |
208 | static inline void *dp_packet_end(const struct dp_packet *); | |
209 | ||
210 | void *dp_packet_put_uninit(struct dp_packet *, size_t); | |
211 | void *dp_packet_put_zeros(struct dp_packet *, size_t); | |
212 | void *dp_packet_put(struct dp_packet *, const void *, size_t); | |
213 | char *dp_packet_put_hex(struct dp_packet *, const char *s, size_t *n); | |
214 | void dp_packet_reserve(struct dp_packet *, size_t); | |
5a07c6e1 DDP |
215 | void dp_packet_reserve_with_tailroom(struct dp_packet *, size_t headroom, |
216 | size_t tailroom); | |
217 | void *dp_packet_push_uninit(struct dp_packet *, size_t); | |
cf62fa4c | 218 | void *dp_packet_push_zeros(struct dp_packet *, size_t); |
5a07c6e1 | 219 | void *dp_packet_push(struct dp_packet *, const void *, size_t); |
cf62fa4c PS |
220 | |
221 | static inline size_t dp_packet_headroom(const struct dp_packet *); | |
222 | static inline size_t dp_packet_tailroom(const struct dp_packet *); | |
223 | void dp_packet_prealloc_headroom(struct dp_packet *, size_t); | |
224 | void dp_packet_prealloc_tailroom(struct dp_packet *, size_t); | |
225 | void dp_packet_shift(struct dp_packet *, int); | |
91088554 | 226 | |
cf62fa4c PS |
227 | static inline void dp_packet_clear(struct dp_packet *); |
228 | static inline void *dp_packet_pull(struct dp_packet *, size_t); | |
229 | static inline void *dp_packet_try_pull(struct dp_packet *, size_t); | |
91088554 | 230 | |
cf62fa4c | 231 | void *dp_packet_steal_data(struct dp_packet *); |
91088554 | 232 | |
5a07c6e1 DDP |
233 | static inline bool dp_packet_equal(const struct dp_packet *, |
234 | const struct dp_packet *); | |
cf62fa4c PS |
235 | |
236 | \f | |
cf62fa4c | 237 | /* Frees memory that 'b' points to, as well as 'b' itself. */ |
5a07c6e1 DDP |
238 | static inline void |
239 | dp_packet_delete(struct dp_packet *b) | |
cf62fa4c PS |
240 | { |
241 | if (b) { | |
242 | if (b->source == DPBUF_DPDK) { | |
243 | /* If this dp_packet was allocated by DPDK it must have been | |
244 | * created as a dp_packet */ | |
245 | free_dpdk_buf((struct dp_packet*) b); | |
246 | return; | |
247 | } | |
248 | ||
0de1b425 WT |
249 | if (b->source == DPBUF_AFXDP) { |
250 | free_afxdp_buf(b); | |
251 | return; | |
252 | } | |
253 | ||
cf62fa4c PS |
254 | dp_packet_uninit(b); |
255 | free(b); | |
256 | } | |
257 | } | |
258 | ||
259 | /* If 'b' contains at least 'offset + size' bytes of data, returns a pointer to | |
260 | * byte 'offset'. Otherwise, returns a null pointer. */ | |
5a07c6e1 DDP |
261 | static inline void * |
262 | dp_packet_at(const struct dp_packet *b, size_t offset, size_t size) | |
91088554 | 263 | { |
5a07c6e1 DDP |
264 | return offset + size <= dp_packet_size(b) |
265 | ? (char *) dp_packet_data(b) + offset | |
266 | : NULL; | |
cf62fa4c | 267 | } |
91088554 | 268 | |
cf62fa4c PS |
269 | /* Returns a pointer to byte 'offset' in 'b', which must contain at least |
270 | * 'offset + size' bytes of data. */ | |
5a07c6e1 DDP |
271 | static inline void * |
272 | dp_packet_at_assert(const struct dp_packet *b, size_t offset, size_t size) | |
cf62fa4c PS |
273 | { |
274 | ovs_assert(offset + size <= dp_packet_size(b)); | |
275 | return ((char *) dp_packet_data(b)) + offset; | |
276 | } | |
277 | ||
278 | /* Returns a pointer to byte following the last byte of data in use in 'b'. */ | |
5a07c6e1 DDP |
279 | static inline void * |
280 | dp_packet_tail(const struct dp_packet *b) | |
cf62fa4c PS |
281 | { |
282 | return (char *) dp_packet_data(b) + dp_packet_size(b); | |
283 | } | |
284 | ||
285 | /* Returns a pointer to byte following the last byte allocated for use (but | |
286 | * not necessarily in use) in 'b'. */ | |
5a07c6e1 DDP |
287 | static inline void * |
288 | dp_packet_end(const struct dp_packet *b) | |
cf62fa4c | 289 | { |
11a6fbd5 | 290 | return (char *) dp_packet_base(b) + dp_packet_get_allocated(b); |
cf62fa4c PS |
291 | } |
292 | ||
293 | /* Returns the number of bytes of headroom in 'b', that is, the number of bytes | |
294 | * of unused space in dp_packet 'b' before the data that is in use. (Most | |
5a07c6e1 DDP |
295 | * commonly, the data in a dp_packet is at its beginning, and thus the |
296 | * dp_packet's headroom is 0.) */ | |
297 | static inline size_t | |
298 | dp_packet_headroom(const struct dp_packet *b) | |
cf62fa4c | 299 | { |
5a07c6e1 | 300 | return (char *) dp_packet_data(b) - (char *) dp_packet_base(b); |
cf62fa4c PS |
301 | } |
302 | ||
5a07c6e1 DDP |
303 | /* Returns the number of bytes that may be appended to the tail end of |
304 | * dp_packet 'b' before the dp_packet must be reallocated. */ | |
305 | static inline size_t | |
306 | dp_packet_tailroom(const struct dp_packet *b) | |
cf62fa4c | 307 | { |
5a07c6e1 | 308 | return (char *) dp_packet_end(b) - (char *) dp_packet_tail(b); |
cf62fa4c PS |
309 | } |
310 | ||
311 | /* Clears any data from 'b'. */ | |
5a07c6e1 DDP |
312 | static inline void |
313 | dp_packet_clear(struct dp_packet *b) | |
cf62fa4c PS |
314 | { |
315 | dp_packet_set_data(b, dp_packet_base(b)); | |
316 | dp_packet_set_size(b, 0); | |
317 | } | |
318 | ||
319 | /* Removes 'size' bytes from the head end of 'b', which must contain at least | |
320 | * 'size' bytes of data. Returns the first byte of data removed. */ | |
5a07c6e1 DDP |
321 | static inline void * |
322 | dp_packet_pull(struct dp_packet *b, size_t size) | |
cf62fa4c PS |
323 | { |
324 | void *data = dp_packet_data(b); | |
325 | ovs_assert(dp_packet_size(b) - dp_packet_l2_pad_size(b) >= size); | |
5a07c6e1 | 326 | dp_packet_set_data(b, (char *) dp_packet_data(b) + size); |
cf62fa4c PS |
327 | dp_packet_set_size(b, dp_packet_size(b) - size); |
328 | return data; | |
329 | } | |
330 | ||
331 | /* If 'b' has at least 'size' bytes of data, removes that many bytes from the | |
332 | * head end of 'b' and returns the first byte removed. Otherwise, returns a | |
333 | * null pointer without modifying 'b'. */ | |
5a07c6e1 DDP |
334 | static inline void * |
335 | dp_packet_try_pull(struct dp_packet *b, size_t size) | |
cf62fa4c PS |
336 | { |
337 | return dp_packet_size(b) - dp_packet_l2_pad_size(b) >= size | |
338 | ? dp_packet_pull(b, size) : NULL; | |
339 | } | |
340 | ||
5a07c6e1 DDP |
341 | static inline bool |
342 | dp_packet_equal(const struct dp_packet *a, const struct dp_packet *b) | |
cf62fa4c PS |
343 | { |
344 | return dp_packet_size(a) == dp_packet_size(b) && | |
5a07c6e1 | 345 | !memcmp(dp_packet_data(a), dp_packet_data(b), dp_packet_size(a)); |
cf62fa4c PS |
346 | } |
347 | ||
2482b0b0 JS |
348 | static inline bool |
349 | dp_packet_is_eth(const struct dp_packet *b) | |
350 | { | |
351 | return b->packet_type == htonl(PT_ETH); | |
352 | } | |
353 | ||
354 | /* Get the start of the Ethernet frame. 'l3_ofs' marks the end of the l2 | |
cf62fa4c | 355 | * headers, so return NULL if it is not set. */ |
5a07c6e1 | 356 | static inline void * |
2482b0b0 | 357 | dp_packet_eth(const struct dp_packet *b) |
cf62fa4c | 358 | { |
2482b0b0 JS |
359 | return (dp_packet_is_eth(b) && b->l3_ofs != UINT16_MAX) |
360 | ? dp_packet_data(b) : NULL; | |
cf62fa4c PS |
361 | } |
362 | ||
82eb5b0a DDP |
363 | /* Resets all layer offsets. 'l3' offset must be set before 'l2' can be |
364 | * retrieved. */ | |
5a07c6e1 DDP |
365 | static inline void |
366 | dp_packet_reset_offsets(struct dp_packet *b) | |
cf62fa4c | 367 | { |
cf62fa4c PS |
368 | b->l2_pad_size = 0; |
369 | b->l2_5_ofs = UINT16_MAX; | |
370 | b->l3_ofs = UINT16_MAX; | |
371 | b->l4_ofs = UINT16_MAX; | |
372 | } | |
373 | ||
5a07c6e1 DDP |
374 | static inline uint8_t |
375 | dp_packet_l2_pad_size(const struct dp_packet *b) | |
cf62fa4c PS |
376 | { |
377 | return b->l2_pad_size; | |
378 | } | |
379 | ||
5a07c6e1 DDP |
380 | static inline void |
381 | dp_packet_set_l2_pad_size(struct dp_packet *b, uint8_t pad_size) | |
cf62fa4c PS |
382 | { |
383 | ovs_assert(pad_size <= dp_packet_size(b)); | |
384 | b->l2_pad_size = pad_size; | |
385 | } | |
386 | ||
5a07c6e1 DDP |
387 | static inline void * |
388 | dp_packet_l2_5(const struct dp_packet *b) | |
cf62fa4c | 389 | { |
82eb5b0a DDP |
390 | return b->l2_5_ofs != UINT16_MAX |
391 | ? (char *) dp_packet_data(b) + b->l2_5_ofs | |
392 | : NULL; | |
cf62fa4c PS |
393 | } |
394 | ||
5a07c6e1 DDP |
395 | static inline void |
396 | dp_packet_set_l2_5(struct dp_packet *b, void *l2_5) | |
cf62fa4c | 397 | { |
82eb5b0a DDP |
398 | b->l2_5_ofs = l2_5 |
399 | ? (char *) l2_5 - (char *) dp_packet_data(b) | |
400 | : UINT16_MAX; | |
cf62fa4c PS |
401 | } |
402 | ||
5a07c6e1 DDP |
403 | static inline void * |
404 | dp_packet_l3(const struct dp_packet *b) | |
cf62fa4c | 405 | { |
82eb5b0a DDP |
406 | return b->l3_ofs != UINT16_MAX |
407 | ? (char *) dp_packet_data(b) + b->l3_ofs | |
408 | : NULL; | |
cf62fa4c PS |
409 | } |
410 | ||
5a07c6e1 DDP |
411 | static inline void |
412 | dp_packet_set_l3(struct dp_packet *b, void *l3) | |
cf62fa4c | 413 | { |
82eb5b0a | 414 | b->l3_ofs = l3 ? (char *) l3 - (char *) dp_packet_data(b) : UINT16_MAX; |
cf62fa4c PS |
415 | } |
416 | ||
5a07c6e1 DDP |
417 | static inline void * |
418 | dp_packet_l4(const struct dp_packet *b) | |
cf62fa4c | 419 | { |
82eb5b0a DDP |
420 | return b->l4_ofs != UINT16_MAX |
421 | ? (char *) dp_packet_data(b) + b->l4_ofs | |
422 | : NULL; | |
cf62fa4c PS |
423 | } |
424 | ||
5a07c6e1 DDP |
425 | static inline void |
426 | dp_packet_set_l4(struct dp_packet *b, void *l4) | |
cf62fa4c | 427 | { |
82eb5b0a | 428 | b->l4_ofs = l4 ? (char *) l4 - (char *) dp_packet_data(b) : UINT16_MAX; |
cf62fa4c PS |
429 | } |
430 | ||
69c45b36 DB |
431 | /* Returns the size of the packet from the beginning of the L3 header to the |
432 | * end of the L3 payload. Hence L2 padding is not included. */ | |
433 | static inline size_t | |
434 | dp_packet_l3_size(const struct dp_packet *b) | |
435 | { | |
436 | return OVS_LIKELY(b->l3_ofs != UINT16_MAX) | |
437 | ? (const char *)dp_packet_tail(b) - (const char *)dp_packet_l3(b) | |
438 | - dp_packet_l2_pad_size(b) | |
439 | : 0; | |
440 | } | |
441 | ||
442 | /* Returns the size of the packet from the beginning of the L4 header to the | |
443 | * end of the L4 payload. Hence L2 padding is not included. */ | |
5a07c6e1 DDP |
444 | static inline size_t |
445 | dp_packet_l4_size(const struct dp_packet *b) | |
cf62fa4c | 446 | { |
69c45b36 | 447 | return OVS_LIKELY(b->l4_ofs != UINT16_MAX) |
cf62fa4c PS |
448 | ? (const char *)dp_packet_tail(b) - (const char *)dp_packet_l4(b) |
449 | - dp_packet_l2_pad_size(b) | |
450 | : 0; | |
451 | } | |
452 | ||
5a07c6e1 DDP |
453 | static inline const void * |
454 | dp_packet_get_tcp_payload(const struct dp_packet *b) | |
cf62fa4c PS |
455 | { |
456 | size_t l4_size = dp_packet_l4_size(b); | |
457 | ||
458 | if (OVS_LIKELY(l4_size >= TCP_HEADER_LEN)) { | |
459 | struct tcp_header *tcp = dp_packet_l4(b); | |
460 | int tcp_len = TCP_OFFSET(tcp->tcp_ctl) * 4; | |
461 | ||
462 | if (OVS_LIKELY(tcp_len >= TCP_HEADER_LEN && tcp_len <= l4_size)) { | |
463 | return (const char *)tcp + tcp_len; | |
464 | } | |
465 | } | |
466 | return NULL; | |
467 | } | |
468 | ||
5a07c6e1 DDP |
469 | static inline const void * |
470 | dp_packet_get_udp_payload(const struct dp_packet *b) | |
cf62fa4c PS |
471 | { |
472 | return OVS_LIKELY(dp_packet_l4_size(b) >= UDP_HEADER_LEN) | |
473 | ? (const char *)dp_packet_l4(b) + UDP_HEADER_LEN : NULL; | |
474 | } | |
475 | ||
5a07c6e1 DDP |
476 | static inline const void * |
477 | dp_packet_get_sctp_payload(const struct dp_packet *b) | |
cf62fa4c PS |
478 | { |
479 | return OVS_LIKELY(dp_packet_l4_size(b) >= SCTP_HEADER_LEN) | |
480 | ? (const char *)dp_packet_l4(b) + SCTP_HEADER_LEN : NULL; | |
481 | } | |
482 | ||
5a07c6e1 DDP |
483 | static inline const void * |
484 | dp_packet_get_icmp_payload(const struct dp_packet *b) | |
cf62fa4c PS |
485 | { |
486 | return OVS_LIKELY(dp_packet_l4_size(b) >= ICMP_HEADER_LEN) | |
487 | ? (const char *)dp_packet_l4(b) + ICMP_HEADER_LEN : NULL; | |
488 | } | |
489 | ||
5a07c6e1 DDP |
490 | static inline const void * |
491 | dp_packet_get_nd_payload(const struct dp_packet *b) | |
cf62fa4c PS |
492 | { |
493 | return OVS_LIKELY(dp_packet_l4_size(b) >= ND_MSG_LEN) | |
494 | ? (const char *)dp_packet_l4(b) + ND_MSG_LEN : NULL; | |
495 | } | |
496 | ||
29bb3093 WT |
497 | #ifdef DPDK_NETDEV |
498 | static inline uint64_t * | |
499 | dp_packet_ol_flags_ptr(const struct dp_packet *b) | |
500 | { | |
501 | return CONST_CAST(uint64_t *, &b->mbuf.ol_flags); | |
502 | } | |
503 | ||
504 | static inline uint32_t * | |
505 | dp_packet_rss_ptr(const struct dp_packet *b) | |
506 | { | |
507 | return CONST_CAST(uint32_t *, &b->mbuf.hash.rss); | |
508 | } | |
509 | ||
510 | static inline uint32_t * | |
511 | dp_packet_flow_mark_ptr(const struct dp_packet *b) | |
512 | { | |
513 | return CONST_CAST(uint32_t *, &b->mbuf.hash.fdir.hi); | |
514 | } | |
515 | ||
516 | #else | |
517 | static inline uint32_t * | |
518 | dp_packet_ol_flags_ptr(const struct dp_packet *b) | |
519 | { | |
520 | return CONST_CAST(uint32_t *, &b->ol_flags); | |
521 | } | |
522 | ||
523 | static inline uint32_t * | |
524 | dp_packet_rss_ptr(const struct dp_packet *b) | |
525 | { | |
526 | return CONST_CAST(uint32_t *, &b->rss_hash); | |
527 | } | |
528 | ||
529 | static inline uint32_t * | |
530 | dp_packet_flow_mark_ptr(const struct dp_packet *b) | |
531 | { | |
532 | return CONST_CAST(uint32_t *, &b->flow_mark); | |
533 | } | |
534 | #endif | |
535 | ||
cf62fa4c PS |
536 | #ifdef DPDK_NETDEV |
537 | BUILD_ASSERT_DECL(offsetof(struct dp_packet, mbuf) == 0); | |
538 | ||
a47e2db2 IM |
539 | static inline void |
540 | dp_packet_init_specific(struct dp_packet *p) | |
541 | { | |
542 | /* This initialization is needed for packets that do not come from DPDK | |
543 | * interfaces, when vswitchd is built with --with-dpdk. */ | |
29cf9c1b | 544 | p->mbuf.ol_flags = p->mbuf.tx_offload = p->mbuf.packet_type = 0; |
a47e2db2 IM |
545 | p->mbuf.nb_segs = 1; |
546 | p->mbuf.next = NULL; | |
547 | } | |
548 | ||
5a07c6e1 DDP |
549 | static inline void * |
550 | dp_packet_base(const struct dp_packet *b) | |
cf62fa4c PS |
551 | { |
552 | return b->mbuf.buf_addr; | |
553 | } | |
554 | ||
5a07c6e1 DDP |
555 | static inline void |
556 | dp_packet_set_base(struct dp_packet *b, void *d) | |
cf62fa4c PS |
557 | { |
558 | b->mbuf.buf_addr = d; | |
559 | } | |
560 | ||
5a07c6e1 DDP |
561 | static inline uint32_t |
562 | dp_packet_size(const struct dp_packet *b) | |
cf62fa4c | 563 | { |
b8e57534 | 564 | return b->mbuf.pkt_len; |
cf62fa4c PS |
565 | } |
566 | ||
5a07c6e1 DDP |
567 | static inline void |
568 | dp_packet_set_size(struct dp_packet *b, uint32_t v) | |
cf62fa4c | 569 | { |
b8e57534 MK |
570 | /* netdev-dpdk does not currently support segmentation; consequently, for |
571 | * all intents and purposes, 'data_len' (16 bit) and 'pkt_len' (32 bit) may | |
572 | * be used interchangably. | |
573 | * | |
574 | * On the datapath, it is expected that the size of packets | |
575 | * (and thus 'v') will always be <= UINT16_MAX; this means that there is no | |
576 | * loss of accuracy in assigning 'v' to 'data_len'. | |
b8e57534 MK |
577 | */ |
578 | b->mbuf.data_len = (uint16_t)v; /* Current seg length. */ | |
579 | b->mbuf.pkt_len = v; /* Total length of all segments linked to | |
580 | * this segment. */ | |
cf62fa4c PS |
581 | } |
582 | ||
5a07c6e1 DDP |
583 | static inline uint16_t |
584 | __packet_data(const struct dp_packet *b) | |
cf62fa4c | 585 | { |
b8e57534 | 586 | return b->mbuf.data_off; |
cf62fa4c PS |
587 | } |
588 | ||
5a07c6e1 DDP |
589 | static inline void |
590 | __packet_set_data(struct dp_packet *b, uint16_t v) | |
cf62fa4c | 591 | { |
b8e57534 | 592 | b->mbuf.data_off = v; |
cf62fa4c PS |
593 | } |
594 | ||
5a07c6e1 DDP |
595 | static inline uint16_t |
596 | dp_packet_get_allocated(const struct dp_packet *b) | |
11a6fbd5 DDP |
597 | { |
598 | return b->mbuf.buf_len; | |
599 | } | |
600 | ||
5a07c6e1 DDP |
601 | static inline void |
602 | dp_packet_set_allocated(struct dp_packet *b, uint16_t s) | |
11a6fbd5 DDP |
603 | { |
604 | b->mbuf.buf_len = s; | |
605 | } | |
e52ad721 | 606 | |
e52ad721 | 607 | #else /* DPDK_NETDEV */ |
a47e2db2 IM |
608 | |
609 | static inline void | |
610 | dp_packet_init_specific(struct dp_packet *p OVS_UNUSED) | |
611 | { | |
612 | /* There are no implementation-specific fields for initialization. */ | |
613 | } | |
614 | ||
e52ad721 FL |
615 | static inline void * |
616 | dp_packet_base(const struct dp_packet *b) | |
aaca4fe0 | 617 | { |
e52ad721 FL |
618 | return b->base_; |
619 | } | |
620 | ||
621 | static inline void | |
622 | dp_packet_set_base(struct dp_packet *b, void *d) | |
623 | { | |
624 | b->base_ = d; | |
aaca4fe0 WT |
625 | } |
626 | ||
a61a2891 | 627 | static inline uint32_t |
e52ad721 | 628 | dp_packet_size(const struct dp_packet *b) |
a61a2891 | 629 | { |
e52ad721 | 630 | return b->size_; |
a61a2891 BP |
631 | } |
632 | ||
e52ad721 FL |
633 | static inline void |
634 | dp_packet_set_size(struct dp_packet *b, uint32_t v) | |
b8e57534 | 635 | { |
e52ad721 FL |
636 | b->size_ = v; |
637 | } | |
638 | ||
639 | static inline uint16_t | |
640 | __packet_data(const struct dp_packet *b) | |
641 | { | |
642 | return b->data_ofs; | |
b8e57534 MK |
643 | } |
644 | ||
5a07c6e1 | 645 | static inline void |
e52ad721 | 646 | __packet_set_data(struct dp_packet *b, uint16_t v) |
b8e57534 | 647 | { |
e52ad721 FL |
648 | b->data_ofs = v; |
649 | } | |
650 | ||
651 | static inline uint16_t | |
652 | dp_packet_get_allocated(const struct dp_packet *b) | |
653 | { | |
654 | return b->allocated_; | |
b8e57534 MK |
655 | } |
656 | ||
5a07c6e1 | 657 | static inline void |
e52ad721 | 658 | dp_packet_set_allocated(struct dp_packet *b, uint16_t s) |
cf62fa4c | 659 | { |
e52ad721 | 660 | b->allocated_ = s; |
91088554 DDP |
661 | } |
662 | ||
e52ad721 FL |
663 | #endif /* DPDK_NETDEV */ |
664 | ||
665 | static inline void | |
666 | dp_packet_reset_cutlen(struct dp_packet *b) | |
667 | { | |
668 | b->cutlen = 0; | |
669 | } | |
670 | ||
671 | static inline uint32_t | |
672 | dp_packet_set_cutlen(struct dp_packet *b, uint32_t max_len) | |
673 | { | |
674 | if (max_len < ETH_HEADER_LEN) { | |
675 | max_len = ETH_HEADER_LEN; | |
676 | } | |
677 | ||
678 | if (max_len >= dp_packet_size(b)) { | |
679 | b->cutlen = 0; | |
680 | } else { | |
681 | b->cutlen = dp_packet_size(b) - max_len; | |
682 | } | |
683 | return b->cutlen; | |
684 | } | |
685 | ||
686 | static inline uint32_t | |
687 | dp_packet_get_cutlen(const struct dp_packet *b) | |
688 | { | |
689 | /* Always in valid range if user uses dp_packet_set_cutlen. */ | |
690 | return b->cutlen; | |
691 | } | |
692 | ||
693 | static inline uint32_t | |
694 | dp_packet_get_send_len(const struct dp_packet *b) | |
695 | { | |
696 | return dp_packet_size(b) - dp_packet_get_cutlen(b); | |
697 | } | |
698 | ||
699 | static inline void * | |
700 | dp_packet_data(const struct dp_packet *b) | |
701 | { | |
702 | return __packet_data(b) != UINT16_MAX | |
703 | ? (char *) dp_packet_base(b) + __packet_data(b) : NULL; | |
704 | } | |
705 | ||
706 | static inline void | |
707 | dp_packet_set_data(struct dp_packet *b, void *data) | |
708 | { | |
709 | if (data) { | |
710 | __packet_set_data(b, (char *) data - (char *) dp_packet_base(b)); | |
711 | } else { | |
712 | __packet_set_data(b, UINT16_MAX); | |
713 | } | |
714 | } | |
715 | ||
716 | static inline void | |
717 | dp_packet_reset_packet(struct dp_packet *b, int off) | |
718 | { | |
719 | dp_packet_set_size(b, dp_packet_size(b) - off); | |
720 | dp_packet_set_data(b, ((unsigned char *) dp_packet_data(b) + off)); | |
721 | dp_packet_reset_offsets(b); | |
722 | } | |
aab96ec4 | 723 | |
1895cc8d PS |
724 | enum { NETDEV_MAX_BURST = 32 }; /* Maximum number packets in a batch. */ |
725 | ||
726 | struct dp_packet_batch { | |
72c84bc2 | 727 | size_t count; |
aaca4fe0 | 728 | bool trunc; /* true if the batch needs truncate. */ |
9f17f104 | 729 | bool do_not_steal; /* Indicate that the packets should not be stolen. */ |
1895cc8d PS |
730 | struct dp_packet *packets[NETDEV_MAX_BURST]; |
731 | }; | |
732 | ||
72c84bc2 AZ |
733 | static inline void |
734 | dp_packet_batch_init(struct dp_packet_batch *batch) | |
1895cc8d | 735 | { |
72c84bc2 AZ |
736 | batch->count = 0; |
737 | batch->trunc = false; | |
9f17f104 | 738 | batch->do_not_steal = false; |
1895cc8d PS |
739 | } |
740 | ||
741 | static inline void | |
72c84bc2 AZ |
742 | dp_packet_batch_add__(struct dp_packet_batch *batch, |
743 | struct dp_packet *packet, size_t limit) | |
1895cc8d | 744 | { |
72c84bc2 AZ |
745 | if (batch->count < limit) { |
746 | batch->packets[batch->count++] = packet; | |
747 | } else { | |
748 | dp_packet_delete(packet); | |
1895cc8d | 749 | } |
1895cc8d PS |
750 | } |
751 | ||
72c84bc2 AZ |
752 | /* When the batch is full, 'packet' will be dropped and freed. */ |
753 | static inline void | |
754 | dp_packet_batch_add(struct dp_packet_batch *batch, struct dp_packet *packet) | |
755 | { | |
756 | dp_packet_batch_add__(batch, packet, NETDEV_MAX_BURST); | |
757 | } | |
758 | ||
759 | static inline size_t | |
760 | dp_packet_batch_size(const struct dp_packet_batch *batch) | |
761 | { | |
762 | return batch->count; | |
763 | } | |
764 | ||
feb86b41 IM |
765 | /* Clear 'batch' for refill. Use dp_packet_batch_refill() to add |
766 | * packets back into the 'batch'. */ | |
1895cc8d | 767 | static inline void |
72c84bc2 | 768 | dp_packet_batch_refill_init(struct dp_packet_batch *batch) |
1895cc8d | 769 | { |
72c84bc2 AZ |
770 | batch->count = 0; |
771 | }; | |
772 | ||
773 | static inline void | |
774 | dp_packet_batch_refill(struct dp_packet_batch *batch, | |
775 | struct dp_packet *packet, size_t idx) | |
776 | { | |
777 | dp_packet_batch_add__(batch, packet, MIN(NETDEV_MAX_BURST, idx + 1)); | |
778 | } | |
779 | ||
780 | static inline void | |
781 | dp_packet_batch_init_packet(struct dp_packet_batch *batch, struct dp_packet *p) | |
782 | { | |
783 | dp_packet_batch_init(batch); | |
784 | batch->count = 1; | |
785 | batch->packets[0] = p; | |
786 | } | |
787 | ||
788 | static inline bool | |
789 | dp_packet_batch_is_empty(const struct dp_packet_batch *batch) | |
790 | { | |
791 | return !dp_packet_batch_size(batch); | |
792 | } | |
793 | ||
1aa7bbca DB |
794 | static inline bool |
795 | dp_packet_batch_is_full(const struct dp_packet_batch *batch) | |
796 | { | |
797 | return dp_packet_batch_size(batch) == NETDEV_MAX_BURST; | |
798 | } | |
799 | ||
e883448e JP |
800 | #define DP_PACKET_BATCH_FOR_EACH(IDX, PACKET, BATCH) \ |
801 | for (size_t IDX = 0; IDX < dp_packet_batch_size(BATCH); IDX++) \ | |
802 | if (PACKET = BATCH->packets[IDX], true) | |
72c84bc2 AZ |
803 | |
804 | /* Use this macro for cases where some packets in the 'BATCH' may be | |
805 | * dropped after going through each packet in the 'BATCH'. | |
806 | * | |
807 | * For packets to stay in the 'BATCH', they need to be refilled back | |
808 | * into the 'BATCH' by calling dp_packet_batch_refill(). Caller owns | |
809 | * the packets that are not refilled. | |
810 | * | |
811 | * Caller needs to supply 'SIZE', that stores the current number of | |
812 | * packets in 'BATCH'. It is best to declare this variable with | |
813 | * the 'const' modifier since it should not be modified by | |
814 | * the iterator. */ | |
815 | #define DP_PACKET_BATCH_REFILL_FOR_EACH(IDX, SIZE, PACKET, BATCH) \ | |
816 | for (dp_packet_batch_refill_init(BATCH), IDX=0; IDX < SIZE; IDX++) \ | |
817 | if (PACKET = BATCH->packets[IDX], true) | |
818 | ||
819 | static inline void | |
820 | dp_packet_batch_clone(struct dp_packet_batch *dst, | |
821 | struct dp_packet_batch *src) | |
822 | { | |
823 | struct dp_packet *packet; | |
824 | ||
825 | dp_packet_batch_init(dst); | |
e883448e | 826 | DP_PACKET_BATCH_FOR_EACH (i, packet, src) { |
c7240129 FL |
827 | if (i + 1 < dp_packet_batch_size(src)) { |
828 | OVS_PREFETCH(src->packets[i + 1]); | |
829 | } | |
830 | ||
d4877184 FL |
831 | uint32_t headroom = dp_packet_headroom(packet); |
832 | struct dp_packet *pkt_clone; | |
833 | ||
834 | pkt_clone = dp_packet_clone_with_headroom(packet, headroom); | |
835 | dp_packet_batch_add(dst, pkt_clone); | |
72c84bc2 | 836 | } |
cf4cf916 | 837 | dst->trunc = src->trunc; |
1895cc8d PS |
838 | } |
839 | ||
840 | static inline void | |
7d7ded7a | 841 | dp_packet_delete_batch(struct dp_packet_batch *batch, bool should_steal) |
1895cc8d | 842 | { |
7d7ded7a | 843 | if (should_steal) { |
72c84bc2 | 844 | struct dp_packet *packet; |
1895cc8d | 845 | |
e883448e | 846 | DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { |
72c84bc2 | 847 | dp_packet_delete(packet); |
1895cc8d | 848 | } |
72c84bc2 | 849 | dp_packet_batch_init(batch); |
1895cc8d PS |
850 | } |
851 | } | |
852 | ||
11d4c7a8 | 853 | static inline void |
75fb9148 | 854 | dp_packet_batch_init_packet_fields(struct dp_packet_batch *batch) |
11d4c7a8 DB |
855 | { |
856 | struct dp_packet *packet; | |
857 | ||
e883448e | 858 | DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { |
11d4c7a8 | 859 | dp_packet_reset_cutlen(packet); |
75fb9148 | 860 | packet->packet_type = htonl(PT_ETH); |
11d4c7a8 DB |
861 | } |
862 | } | |
863 | ||
aaca4fe0 | 864 | static inline void |
72c84bc2 | 865 | dp_packet_batch_apply_cutlen(struct dp_packet_batch *batch) |
aaca4fe0 | 866 | { |
72c84bc2 AZ |
867 | if (batch->trunc) { |
868 | struct dp_packet *packet; | |
aaca4fe0 | 869 | |
e883448e | 870 | DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { |
a61a2891 | 871 | dp_packet_set_size(packet, dp_packet_get_send_len(packet)); |
72c84bc2 AZ |
872 | dp_packet_reset_cutlen(packet); |
873 | } | |
874 | batch->trunc = false; | |
aaca4fe0 | 875 | } |
aaca4fe0 WT |
876 | } |
877 | ||
878 | static inline void | |
72c84bc2 | 879 | dp_packet_batch_reset_cutlen(struct dp_packet_batch *batch) |
aaca4fe0 | 880 | { |
72c84bc2 AZ |
881 | if (batch->trunc) { |
882 | struct dp_packet *packet; | |
aaca4fe0 | 883 | |
e883448e | 884 | DP_PACKET_BATCH_FOR_EACH (i, packet, batch) { |
72c84bc2 AZ |
885 | dp_packet_reset_cutlen(packet); |
886 | } | |
887 | batch->trunc = false; | |
aaca4fe0 WT |
888 | } |
889 | } | |
890 | ||
29bb3093 WT |
891 | /* Returns the RSS hash of the packet 'p'. Note that the returned value is |
892 | * correct only if 'dp_packet_rss_valid(p)' returns 'true'. */ | |
893 | static inline uint32_t | |
894 | dp_packet_get_rss_hash(const struct dp_packet *p) | |
895 | { | |
896 | return *dp_packet_rss_ptr(p); | |
897 | } | |
898 | ||
899 | static inline void | |
900 | dp_packet_set_rss_hash(struct dp_packet *p, uint32_t hash) | |
901 | { | |
902 | *dp_packet_rss_ptr(p) = hash; | |
903 | *dp_packet_ol_flags_ptr(p) |= DP_PACKET_OL_RSS_HASH; | |
904 | } | |
905 | ||
906 | static inline bool | |
907 | dp_packet_rss_valid(const struct dp_packet *p) | |
908 | { | |
909 | return *dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_RSS_HASH; | |
910 | } | |
911 | ||
912 | static inline void | |
913 | dp_packet_reset_offload(struct dp_packet *p) | |
914 | { | |
915 | *dp_packet_ol_flags_ptr(p) &= ~DP_PACKET_OL_SUPPORTED_MASK; | |
916 | } | |
917 | ||
918 | static inline bool | |
919 | dp_packet_has_flow_mark(const struct dp_packet *p, uint32_t *mark) | |
920 | { | |
921 | if (*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_FLOW_MARK) { | |
922 | *mark = *dp_packet_flow_mark_ptr(p); | |
923 | return true; | |
924 | } | |
925 | ||
926 | return false; | |
927 | } | |
928 | ||
929 | static inline void | |
930 | dp_packet_set_flow_mark(struct dp_packet *p, uint32_t mark) | |
931 | { | |
932 | *dp_packet_flow_mark_ptr(p) = mark; | |
933 | *dp_packet_ol_flags_ptr(p) |= DP_PACKET_OL_FLOW_MARK; | |
934 | } | |
935 | ||
936 | /* Returns the L4 cksum offload bitmask. */ | |
937 | static inline uint64_t | |
938 | dp_packet_hwol_l4_mask(const struct dp_packet *b) | |
939 | { | |
940 | return *dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_L4_MASK; | |
941 | } | |
942 | ||
29cf9c1b FL |
943 | /* Return true if the packet 'b' requested L4 checksum offload. */ |
944 | static inline bool | |
945 | dp_packet_hwol_tx_l4_checksum(const struct dp_packet *b) | |
946 | { | |
947 | return !!dp_packet_hwol_l4_mask(b); | |
948 | } | |
949 | ||
29bb3093 WT |
950 | /* Returns 'true' if packet 'b' is marked for TCP segmentation offloading. */ |
951 | static inline bool | |
952 | dp_packet_hwol_is_tso(const struct dp_packet *b) | |
953 | { | |
954 | return !!(*dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_TCP_SEG); | |
955 | } | |
956 | ||
957 | /* Returns 'true' if packet 'b' is marked for IPv4 checksum offloading. */ | |
958 | static inline bool | |
959 | dp_packet_hwol_is_ipv4(const struct dp_packet *b) | |
960 | { | |
961 | return !!(*dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_IPV4); | |
962 | } | |
963 | ||
964 | /* Returns 'true' if packet 'b' is marked for TCP checksum offloading. */ | |
965 | static inline bool | |
966 | dp_packet_hwol_l4_is_tcp(const struct dp_packet *b) | |
967 | { | |
968 | return (*dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_L4_MASK) == | |
969 | DP_PACKET_OL_TX_TCP_CKSUM; | |
970 | } | |
971 | ||
972 | /* Returns 'true' if packet 'b' is marked for UDP checksum offloading. */ | |
973 | static inline bool | |
974 | dp_packet_hwol_l4_is_udp(struct dp_packet *b) | |
975 | { | |
976 | return (*dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_L4_MASK) == | |
977 | DP_PACKET_OL_TX_UDP_CKSUM; | |
978 | } | |
979 | ||
980 | /* Returns 'true' if packet 'b' is marked for SCTP checksum offloading. */ | |
981 | static inline bool | |
982 | dp_packet_hwol_l4_is_sctp(struct dp_packet *b) | |
983 | { | |
984 | return (*dp_packet_ol_flags_ptr(b) & DP_PACKET_OL_TX_L4_MASK) == | |
985 | DP_PACKET_OL_TX_SCTP_CKSUM; | |
986 | } | |
987 | ||
988 | /* Mark packet 'b' for IPv4 checksum offloading. */ | |
989 | static inline void | |
990 | dp_packet_hwol_set_tx_ipv4(struct dp_packet *b) | |
991 | { | |
992 | *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_IPV4; | |
993 | } | |
994 | ||
995 | /* Mark packet 'b' for IPv6 checksum offloading. */ | |
996 | static inline void | |
997 | dp_packet_hwol_set_tx_ipv6(struct dp_packet *b) | |
998 | { | |
999 | *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_IPV6; | |
1000 | } | |
1001 | ||
1002 | /* Mark packet 'b' for TCP checksum offloading. It implies that either | |
1003 | * the packet 'b' is marked for IPv4 or IPv6 checksum offloading. */ | |
1004 | static inline void | |
1005 | dp_packet_hwol_set_csum_tcp(struct dp_packet *b) | |
1006 | { | |
1007 | *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_TCP_CKSUM; | |
1008 | } | |
1009 | ||
1010 | /* Mark packet 'b' for UDP checksum offloading. It implies that either | |
1011 | * the packet 'b' is marked for IPv4 or IPv6 checksum offloading. */ | |
1012 | static inline void | |
1013 | dp_packet_hwol_set_csum_udp(struct dp_packet *b) | |
1014 | { | |
1015 | *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_UDP_CKSUM; | |
1016 | } | |
1017 | ||
1018 | /* Mark packet 'b' for SCTP checksum offloading. It implies that either | |
1019 | * the packet 'b' is marked for IPv4 or IPv6 checksum offloading. */ | |
1020 | static inline void | |
1021 | dp_packet_hwol_set_csum_sctp(struct dp_packet *b) | |
1022 | { | |
1023 | *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_SCTP_CKSUM; | |
1024 | } | |
1025 | ||
1026 | /* Mark packet 'b' for TCP segmentation offloading. It implies that | |
1027 | * either the packet 'b' is marked for IPv4 or IPv6 checksum offloading | |
1028 | * and also for TCP checksum offloading. */ | |
1029 | static inline void | |
1030 | dp_packet_hwol_set_tcp_seg(struct dp_packet *b) | |
1031 | { | |
1032 | *dp_packet_ol_flags_ptr(b) |= DP_PACKET_OL_TX_TCP_SEG; | |
1033 | } | |
1034 | ||
1035 | static inline bool | |
1036 | dp_packet_ip_checksum_valid(const struct dp_packet *p) | |
1037 | { | |
1038 | return (*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_RX_IP_CKSUM_MASK) == | |
1039 | DP_PACKET_OL_RX_IP_CKSUM_GOOD; | |
1040 | } | |
1041 | ||
1042 | static inline bool | |
1043 | dp_packet_ip_checksum_bad(const struct dp_packet *p) | |
1044 | { | |
1045 | return (*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_RX_IP_CKSUM_MASK) == | |
1046 | DP_PACKET_OL_RX_IP_CKSUM_BAD; | |
1047 | } | |
1048 | ||
1049 | static inline bool | |
1050 | dp_packet_l4_checksum_valid(const struct dp_packet *p) | |
1051 | { | |
1052 | return (*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_RX_L4_CKSUM_MASK) == | |
1053 | DP_PACKET_OL_RX_L4_CKSUM_GOOD; | |
1054 | } | |
1055 | ||
1056 | static inline bool | |
1057 | dp_packet_l4_checksum_bad(const struct dp_packet *p) | |
1058 | { | |
1059 | return (*dp_packet_ol_flags_ptr(p) & DP_PACKET_OL_RX_L4_CKSUM_MASK) == | |
1060 | DP_PACKET_OL_RX_L4_CKSUM_BAD; | |
1061 | } | |
1062 | ||
91088554 DDP |
1063 | #ifdef __cplusplus |
1064 | } | |
1065 | #endif | |
1066 | ||
aaaac302 | 1067 | #endif /* dp-packet.h */ |