4 * Copyright(c) 2010-2013 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #ifndef _IPV4_RSMBL_H_
35 #define _IPV4_RSMBL_H_
41 * Implementation of IPv4 reassemble.
59 * Use <src addr, dst_addr, id> to uniquely indetify fragmented datagram.
61 struct ipv4_frag_key {
66 #define IPV4_FRAG_KEY_INVALIDATE(k) ((k)->src_dst = 0)
67 #define IPV4_FRAG_KEY_EMPTY(k) ((k)->src_dst == 0)
69 #define IPV4_FRAG_KEY_CMP(k1, k2) \
70 (((k1)->src_dst ^ (k2)->src_dst) | ((k1)->id ^ (k2)->id))
74 * Fragmented packet to reassemble.
75 * First two entries in the frags[] array are for the last and first fragments.
77 struct ipv4_frag_pkt {
78 TAILQ_ENTRY(ipv4_frag_pkt) lru; /* LRU list */
79 struct ipv4_frag_key key;
80 uint64_t start; /* creation timestamp */
81 uint32_t total_size; /* expected reassembled size */
82 uint32_t frag_size; /* size of fragments received */
83 uint32_t last_idx; /* index of next entry to fill */
84 struct ipv4_frag frags[MAX_FRAG_NUM];
85 } __rte_cache_aligned;
88 struct ipv4_frag_death_row {
90 struct rte_mbuf *row[MAX_PKT_BURST * (MAX_FRAG_NUM + 1)];
93 #define IPV4_FRAG_MBUF2DR(dr, mb) ((dr)->row[(dr)->cnt++] = (mb))
97 #ifdef IPV4_FRAG_DEBUG
98 #define IPV4_FRAG_LOG(lvl, fmt, args...) RTE_LOG(lvl, USER1, fmt, ##args)
100 #define IPV4_FRAG_LOG(lvl, fmt, args...) do {} while(0)
101 #endif /* IPV4_FRAG_DEBUG */
105 ipv4_frag_reset(struct ipv4_frag_pkt *fp, uint64_t tms)
107 static const struct ipv4_frag zero_frag = {
114 fp->total_size = UINT32_MAX;
116 fp->last_idx = MIN_FRAG_NUM;
117 fp->frags[LAST_FRAG_IDX] = zero_frag;
118 fp->frags[FIRST_FRAG_IDX] = zero_frag;
122 ipv4_frag_free(struct ipv4_frag_pkt *fp, struct ipv4_frag_death_row *dr)
127 for (i = 0; i != fp->last_idx; i++) {
128 if (fp->frags[i].mb != NULL) {
129 dr->row[k++] = fp->frags[i].mb;
130 fp->frags[i].mb = NULL;
139 ipv4_frag_free_death_row(struct ipv4_frag_death_row *dr, uint32_t prefetch)
143 k = RTE_MIN(prefetch, dr->cnt);
146 for (i = 0; i != k; i++)
147 rte_prefetch0(dr->row[i]);
149 for (i = 0; i != n - k; i++) {
150 rte_prefetch0(dr->row[i + k]);
151 rte_pktmbuf_free(dr->row[i]);
155 rte_pktmbuf_free(dr->row[i]);
162 * Takes 2 mbufs that represents two framents of the same packet and
163 * chains them into one mbuf.
166 ipv4_frag_chain(struct rte_mbuf *mn, struct rte_mbuf *mp)
170 /* adjust start of the last fragment data. */
171 rte_pktmbuf_adj(mp, (uint16_t)(mp->pkt.vlan_macip.f.l2_len +
172 mp->pkt.vlan_macip.f.l3_len));
174 /* chain two fragments. */
175 ms = rte_pktmbuf_lastseg(mn);
178 /* accumulate number of segments and total length. */
179 mn->pkt.nb_segs = (uint8_t)(mn->pkt.nb_segs + mp->pkt.nb_segs);
180 mn->pkt.pkt_len += mp->pkt.pkt_len;
182 /* reset pkt_len and nb_segs for chained fragment. */
183 mp->pkt.pkt_len = mp->pkt.data_len;
188 * Reassemble fragments into one packet.
190 static inline struct rte_mbuf *
191 ipv4_frag_reassemble(const struct ipv4_frag_pkt *fp)
193 struct ipv4_hdr *ip_hdr;
194 struct rte_mbuf *m, *prev;
195 uint32_t i, n, ofs, first_len;
197 first_len = fp->frags[FIRST_FRAG_IDX].len;
198 n = fp->last_idx - 1;
200 /*start from the last fragment. */
201 m = fp->frags[LAST_FRAG_IDX].mb;
202 ofs = fp->frags[LAST_FRAG_IDX].ofs;
204 while (ofs != first_len) {
208 for (i = n; i != FIRST_FRAG_IDX && ofs != first_len; i--) {
210 /* previous fragment found. */
211 if(fp->frags[i].ofs + fp->frags[i].len == ofs) {
213 ipv4_frag_chain(fp->frags[i].mb, m);
215 /* update our last fragment and offset. */
217 ofs = fp->frags[i].ofs;
221 /* error - hole in the packet. */
227 /* chain with the first fragment. */
228 ipv4_frag_chain(fp->frags[FIRST_FRAG_IDX].mb, m);
229 m = fp->frags[FIRST_FRAG_IDX].mb;
231 /* update mbuf fields for reassembled packet. */
232 m->ol_flags |= PKT_TX_IP_CKSUM;
234 /* update ipv4 header for the reassmebled packet */
235 ip_hdr = (struct ipv4_hdr*)(rte_pktmbuf_mtod(m, uint8_t *) +
236 m->pkt.vlan_macip.f.l2_len);
238 ip_hdr->total_length = rte_cpu_to_be_16((uint16_t)(fp->total_size +
239 m->pkt.vlan_macip.f.l3_len));
240 ip_hdr->fragment_offset = (uint16_t)(ip_hdr->fragment_offset &
241 rte_cpu_to_be_16(IPV4_HDR_DF_FLAG));
242 ip_hdr->hdr_checksum = 0;
247 static inline struct rte_mbuf *
248 ipv4_frag_process(struct ipv4_frag_pkt *fp, struct ipv4_frag_death_row *dr,
249 struct rte_mbuf *mb, uint16_t ofs, uint16_t len, uint16_t more_frags)
253 fp->frag_size += len;
255 /* this is the first fragment. */
257 idx = (fp->frags[FIRST_FRAG_IDX].mb == NULL) ?
258 FIRST_FRAG_IDX : UINT32_MAX;
260 /* this is the last fragment. */
261 } else if (more_frags == 0) {
262 fp->total_size = ofs + len;
263 idx = (fp->frags[LAST_FRAG_IDX].mb == NULL) ?
264 LAST_FRAG_IDX : UINT32_MAX;
266 /* this is the intermediate fragment. */
267 } else if ((idx = fp->last_idx) <
268 sizeof (fp->frags) / sizeof (fp->frags[0])) {
273 * errorneous packet: either exceeed max allowed number of fragments,
274 * or duplicate first/last fragment encountered.
276 if (idx >= sizeof (fp->frags) / sizeof (fp->frags[0])) {
278 /* report an error. */
279 IPV4_FRAG_LOG(DEBUG, "%s:%d invalid fragmented packet:\n"
280 "ipv4_frag_pkt: %p, key: <%" PRIx64 ", %#x>, "
281 "total_size: %u, frag_size: %u, last_idx: %u\n"
282 "first fragment: ofs: %u, len: %u\n"
283 "last fragment: ofs: %u, len: %u\n\n",
285 fp, fp->key.src_dst, fp->key.id,
286 fp->total_size, fp->frag_size, fp->last_idx,
287 fp->frags[FIRST_FRAG_IDX].ofs,
288 fp->frags[FIRST_FRAG_IDX].len,
289 fp->frags[LAST_FRAG_IDX].ofs,
290 fp->frags[LAST_FRAG_IDX].len);
292 /* free all fragments, invalidate the entry. */
293 ipv4_frag_free(fp, dr);
294 IPV4_FRAG_KEY_INVALIDATE(&fp->key);
295 IPV4_FRAG_MBUF2DR(dr, mb);
300 fp->frags[idx].ofs = ofs;
301 fp->frags[idx].len = len;
302 fp->frags[idx].mb = mb;
306 /* not all fragments are collected yet. */
307 if (likely (fp->frag_size < fp->total_size)) {
310 /* if we collected all fragments, then try to reassemble. */
311 } else if (fp->frag_size == fp->total_size &&
312 fp->frags[FIRST_FRAG_IDX].mb != NULL) {
313 mb = ipv4_frag_reassemble(fp);
316 /* errorenous set of fragments. */
319 /* report an error. */
320 IPV4_FRAG_LOG(DEBUG, "%s:%d invalid fragmented packet:\n"
321 "ipv4_frag_pkt: %p, key: <%" PRIx64 ", %#x>, "
322 "total_size: %u, frag_size: %u, last_idx: %u\n"
323 "first fragment: ofs: %u, len: %u\n"
324 "last fragment: ofs: %u, len: %u\n\n",
326 fp, fp->key.src_dst, fp->key.id,
327 fp->total_size, fp->frag_size, fp->last_idx,
328 fp->frags[FIRST_FRAG_IDX].ofs,
329 fp->frags[FIRST_FRAG_IDX].len,
330 fp->frags[LAST_FRAG_IDX].ofs,
331 fp->frags[LAST_FRAG_IDX].len);
333 /* free associated resources. */
334 ipv4_frag_free(fp, dr);
337 /* we are done with that entry, invalidate it. */
338 IPV4_FRAG_KEY_INVALIDATE(&fp->key);
342 #include "ipv4_frag_tbl.h"
345 * Process new mbuf with fragment of IPV4 packet.
346 * Incoming mbuf should have it's l2_len/l3_len fields setuped correclty.
348 * Table where to lookup/add the fragmented packet.
350 * Incoming mbuf with IPV4 fragment.
352 * Fragment arrival timestamp.
354 * Pointer to the IPV4 header inside the fragment.
356 * Fragment's offset (as extracted from the header).
358 * Fragment's MF flag.
360 * Pointer to mbuf for reassebled packet, or NULL if:
361 * - an error occured.
362 * - not all fragments of the packet are collected yet.
364 static inline struct rte_mbuf *
365 ipv4_frag_mbuf(struct ipv4_frag_tbl *tbl, struct ipv4_frag_death_row *dr,
366 struct rte_mbuf *mb, uint64_t tms, struct ipv4_hdr *ip_hdr,
367 uint16_t ip_ofs, uint16_t ip_flag)
369 struct ipv4_frag_pkt *fp;
370 struct ipv4_frag_key key;
374 psd = (uint64_t *)&ip_hdr->src_addr;
375 key.src_dst = psd[0];
376 key.id = ip_hdr->packet_id;
378 ip_ofs *= IPV4_HDR_OFFSET_UNITS;
379 ip_len = (uint16_t)(rte_be_to_cpu_16(ip_hdr->total_length) -
380 mb->pkt.vlan_macip.f.l3_len);
382 IPV4_FRAG_LOG(DEBUG, "%s:%d:\n"
383 "mbuf: %p, tms: %" PRIu64
384 ", key: <%" PRIx64 ", %#x>, ofs: %u, len: %u, flags: %#x\n"
385 "tbl: %p, max_cycles: %" PRIu64 ", entry_mask: %#x, "
386 "max_entries: %u, use_entries: %u\n\n",
388 mb, tms, key.src_dst, key.id, ip_ofs, ip_len, ip_flag,
389 tbl, tbl->max_cycles, tbl->entry_mask, tbl->max_entries,
392 /* try to find/add entry into the fragment's table. */
393 if ((fp = ipv4_frag_find(tbl, dr, &key, tms)) == NULL) {
394 IPV4_FRAG_MBUF2DR(dr, mb);
398 IPV4_FRAG_LOG(DEBUG, "%s:%d:\n"
399 "tbl: %p, max_entries: %u, use_entries: %u\n"
400 "ipv4_frag_pkt: %p, key: <%" PRIx64 ", %#x>, start: %" PRIu64
401 ", total_size: %u, frag_size: %u, last_idx: %u\n\n",
403 tbl, tbl->max_entries, tbl->use_entries,
404 fp, fp->key.src_dst, fp->key.id, fp->start,
405 fp->total_size, fp->frag_size, fp->last_idx);
408 /* process the fragmented packet. */
409 mb = ipv4_frag_process(fp, dr, mb, ip_ofs, ip_len, ip_flag);
410 ipv4_frag_inuse(tbl, fp);
412 IPV4_FRAG_LOG(DEBUG, "%s:%d:\n"
414 "tbl: %p, max_entries: %u, use_entries: %u\n"
415 "ipv4_frag_pkt: %p, key: <%" PRIx64 ", %#x>, start: %" PRIu64
416 ", total_size: %u, frag_size: %u, last_idx: %u\n\n",
417 __func__, __LINE__, mb,
418 tbl, tbl->max_entries, tbl->use_entries,
419 fp, fp->key.src_dst, fp->key.id, fp->start,
420 fp->total_size, fp->frag_size, fp->last_idx);
425 #endif /* _IPV4_RSMBL_H_ */