4 * Copyright(c) 2010-2014 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_
37 #include "ip_frag_common.h"
43 * Implementation of IPv4 reassemble.
61 * Use <src addr, dst_addr, id> to uniquely indetify fragmented datagram.
68 #define IP_FRAG_KEY_INVALIDATE(k) ((k)->src_dst = 0)
69 #define IP_FRAG_KEY_EMPTY(k) ((k)->src_dst == 0)
71 #define IP_FRAG_KEY_CMP(k1, k2) \
72 (((k1)->src_dst ^ (k2)->src_dst) | ((k1)->id ^ (k2)->id))
76 * Fragmented packet to reassemble.
77 * First two entries in the frags[] array are for the last and first fragments.
80 TAILQ_ENTRY(ip_frag_pkt) lru; /* LRU list */
81 struct ip_frag_key key;
82 uint64_t start; /* creation timestamp */
83 uint32_t total_size; /* expected reassembled size */
84 uint32_t frag_size; /* size of fragments received */
85 uint32_t last_idx; /* index of next entry to fill */
86 struct ip_frag frags[MAX_FRAG_NUM];
87 } __rte_cache_aligned;
90 struct ip_frag_death_row {
92 struct rte_mbuf *row[MAX_PKT_BURST * (MAX_FRAG_NUM + 1)];
95 #define IP_FRAG_MBUF2DR(dr, mb) ((dr)->row[(dr)->cnt++] = (mb))
100 #define IP_FRAG_LOG(lvl, fmt, args...) RTE_LOG(lvl, USER1, fmt, ##args)
102 #define IP_FRAG_LOG(lvl, fmt, args...) do {} while(0)
103 #endif /* IP_FRAG_DEBUG */
107 ip_frag_reset(struct ip_frag_pkt *fp, uint64_t tms)
109 static const struct ip_frag zero_frag = {
116 fp->total_size = UINT32_MAX;
118 fp->last_idx = MIN_FRAG_NUM;
119 fp->frags[LAST_FRAG_IDX] = zero_frag;
120 fp->frags[FIRST_FRAG_IDX] = zero_frag;
124 ip_frag_free(struct ip_frag_pkt *fp, struct ip_frag_death_row *dr)
129 for (i = 0; i != fp->last_idx; i++) {
130 if (fp->frags[i].mb != NULL) {
131 dr->row[k++] = fp->frags[i].mb;
132 fp->frags[i].mb = NULL;
141 rte_ip_frag_free_death_row(struct ip_frag_death_row *dr, uint32_t prefetch)
145 k = RTE_MIN(prefetch, dr->cnt);
148 for (i = 0; i != k; i++)
149 rte_prefetch0(dr->row[i]);
151 for (i = 0; i != n - k; i++) {
152 rte_prefetch0(dr->row[i + k]);
153 rte_pktmbuf_free(dr->row[i]);
157 rte_pktmbuf_free(dr->row[i]);
164 * Takes 2 mbufs that represents two framents of the same packet and
165 * chains them into one mbuf.
168 ip_frag_chain(struct rte_mbuf *mn, struct rte_mbuf *mp)
172 /* adjust start of the last fragment data. */
173 rte_pktmbuf_adj(mp, (uint16_t)(mp->pkt.vlan_macip.f.l2_len +
174 mp->pkt.vlan_macip.f.l3_len));
176 /* chain two fragments. */
177 ms = rte_pktmbuf_lastseg(mn);
180 /* accumulate number of segments and total length. */
181 mn->pkt.nb_segs = (uint8_t)(mn->pkt.nb_segs + mp->pkt.nb_segs);
182 mn->pkt.pkt_len += mp->pkt.pkt_len;
184 /* reset pkt_len and nb_segs for chained fragment. */
185 mp->pkt.pkt_len = mp->pkt.data_len;
190 * Reassemble fragments into one packet.
192 static inline struct rte_mbuf *
193 ipv4_frag_reassemble(const struct ip_frag_pkt *fp)
195 struct ipv4_hdr *ip_hdr;
196 struct rte_mbuf *m, *prev;
197 uint32_t i, n, ofs, first_len;
199 first_len = fp->frags[FIRST_FRAG_IDX].len;
200 n = fp->last_idx - 1;
202 /*start from the last fragment. */
203 m = fp->frags[LAST_FRAG_IDX].mb;
204 ofs = fp->frags[LAST_FRAG_IDX].ofs;
206 while (ofs != first_len) {
210 for (i = n; i != FIRST_FRAG_IDX && ofs != first_len; i--) {
212 /* previous fragment found. */
213 if(fp->frags[i].ofs + fp->frags[i].len == ofs) {
215 ip_frag_chain(fp->frags[i].mb, m);
217 /* update our last fragment and offset. */
219 ofs = fp->frags[i].ofs;
223 /* error - hole in the packet. */
229 /* chain with the first fragment. */
230 ip_frag_chain(fp->frags[FIRST_FRAG_IDX].mb, m);
231 m = fp->frags[FIRST_FRAG_IDX].mb;
233 /* update mbuf fields for reassembled packet. */
234 m->ol_flags |= PKT_TX_IP_CKSUM;
236 /* update ipv4 header for the reassmebled packet */
237 ip_hdr = (struct ipv4_hdr *)(rte_pktmbuf_mtod(m, uint8_t *) +
238 m->pkt.vlan_macip.f.l2_len);
240 ip_hdr->total_length = rte_cpu_to_be_16((uint16_t)(fp->total_size +
241 m->pkt.vlan_macip.f.l3_len));
242 ip_hdr->fragment_offset = (uint16_t)(ip_hdr->fragment_offset &
243 rte_cpu_to_be_16(IPV4_HDR_DF_FLAG));
244 ip_hdr->hdr_checksum = 0;
249 static inline struct rte_mbuf *
250 ip_frag_process(struct ip_frag_pkt *fp, struct ip_frag_death_row *dr,
251 struct rte_mbuf *mb, uint16_t ofs, uint16_t len, uint16_t more_frags)
255 fp->frag_size += len;
257 /* this is the first fragment. */
259 idx = (fp->frags[FIRST_FRAG_IDX].mb == NULL) ?
260 FIRST_FRAG_IDX : UINT32_MAX;
262 /* this is the last fragment. */
263 } else if (more_frags == 0) {
264 fp->total_size = ofs + len;
265 idx = (fp->frags[LAST_FRAG_IDX].mb == NULL) ?
266 LAST_FRAG_IDX : UINT32_MAX;
268 /* this is the intermediate fragment. */
269 } else if ((idx = fp->last_idx) <
270 sizeof (fp->frags) / sizeof (fp->frags[0])) {
275 * errorneous packet: either exceeed max allowed number of fragments,
276 * or duplicate first/last fragment encountered.
278 if (idx >= sizeof (fp->frags) / sizeof (fp->frags[0])) {
280 /* report an error. */
281 IP_FRAG_LOG(DEBUG, "%s:%d invalid fragmented packet:\n"
282 "ipv4_frag_pkt: %p, key: <%" PRIx64 ", %#x>, "
283 "total_size: %u, frag_size: %u, last_idx: %u\n"
284 "first fragment: ofs: %u, len: %u\n"
285 "last fragment: ofs: %u, len: %u\n\n",
287 fp, fp->key.src_dst, fp->key.id,
288 fp->total_size, fp->frag_size, fp->last_idx,
289 fp->frags[FIRST_FRAG_IDX].ofs,
290 fp->frags[FIRST_FRAG_IDX].len,
291 fp->frags[LAST_FRAG_IDX].ofs,
292 fp->frags[LAST_FRAG_IDX].len);
294 /* free all fragments, invalidate the entry. */
295 ip_frag_free(fp, dr);
296 IP_FRAG_KEY_INVALIDATE(&fp->key);
297 IP_FRAG_MBUF2DR(dr, mb);
302 fp->frags[idx].ofs = ofs;
303 fp->frags[idx].len = len;
304 fp->frags[idx].mb = mb;
308 /* not all fragments are collected yet. */
309 if (likely (fp->frag_size < fp->total_size)) {
312 /* if we collected all fragments, then try to reassemble. */
313 } else if (fp->frag_size == fp->total_size &&
314 fp->frags[FIRST_FRAG_IDX].mb != NULL) {
315 mb = ipv4_frag_reassemble(fp);
318 /* errorenous set of fragments. */
321 /* report an error. */
322 IP_FRAG_LOG(DEBUG, "%s:%d invalid fragmented packet:\n"
323 "ipv4_frag_pkt: %p, key: <%" PRIx64 ", %#x>, "
324 "total_size: %u, frag_size: %u, last_idx: %u\n"
325 "first fragment: ofs: %u, len: %u\n"
326 "last fragment: ofs: %u, len: %u\n\n",
328 fp, fp->key.src_dst, fp->key.id,
329 fp->total_size, fp->frag_size, fp->last_idx,
330 fp->frags[FIRST_FRAG_IDX].ofs,
331 fp->frags[FIRST_FRAG_IDX].len,
332 fp->frags[LAST_FRAG_IDX].ofs,
333 fp->frags[LAST_FRAG_IDX].len);
335 /* free associated resources. */
336 ip_frag_free(fp, dr);
339 /* we are done with that entry, invalidate it. */
340 IP_FRAG_KEY_INVALIDATE(&fp->key);
344 #include "ipv4_frag_tbl.h"
347 * Process new mbuf with fragment of IPV4 packet.
348 * Incoming mbuf should have it's l2_len/l3_len fields setuped correclty.
350 * Table where to lookup/add the fragmented packet.
352 * Incoming mbuf with IPV4 fragment.
354 * Fragment arrival timestamp.
356 * Pointer to the IPV4 header inside the fragment.
358 * Fragment's offset (as extracted from the header).
360 * Fragment's MF flag.
362 * Pointer to mbuf for reassebled packet, or NULL if:
363 * - an error occured.
364 * - not all fragments of the packet are collected yet.
366 static inline struct rte_mbuf *
367 rte_ipv4_reassemble_packet(struct ip_frag_tbl *tbl,
368 struct ip_frag_death_row *dr, struct rte_mbuf *mb, uint64_t tms,
369 struct ipv4_hdr *ip_hdr, uint16_t ip_ofs, uint16_t ip_flag)
371 struct ip_frag_pkt *fp;
372 struct ip_frag_key key;
376 psd = (uint64_t *)&ip_hdr->src_addr;
377 key.src_dst = psd[0];
378 key.id = ip_hdr->packet_id;
380 ip_ofs *= IPV4_HDR_OFFSET_UNITS;
381 ip_len = (uint16_t)(rte_be_to_cpu_16(ip_hdr->total_length) -
382 mb->pkt.vlan_macip.f.l3_len);
384 IP_FRAG_LOG(DEBUG, "%s:%d:\n"
385 "mbuf: %p, tms: %" PRIu64
386 ", key: <%" PRIx64 ", %#x>, ofs: %u, len: %u, flags: %#x\n"
387 "tbl: %p, max_cycles: %" PRIu64 ", entry_mask: %#x, "
388 "max_entries: %u, use_entries: %u\n\n",
390 mb, tms, key.src_dst, key.id, ip_ofs, ip_len, ip_flag,
391 tbl, tbl->max_cycles, tbl->entry_mask, tbl->max_entries,
394 /* try to find/add entry into the fragment's table. */
395 if ((fp = ip_frag_find(tbl, dr, &key, tms)) == NULL) {
396 IP_FRAG_MBUF2DR(dr, mb);
400 IP_FRAG_LOG(DEBUG, "%s:%d:\n"
401 "tbl: %p, max_entries: %u, use_entries: %u\n"
402 "ipv4_frag_pkt: %p, key: <%" PRIx64 ", %#x>, start: %" PRIu64
403 ", total_size: %u, frag_size: %u, last_idx: %u\n\n",
405 tbl, tbl->max_entries, tbl->use_entries,
406 fp, fp->key.src_dst, fp->key.id, fp->start,
407 fp->total_size, fp->frag_size, fp->last_idx);
410 /* process the fragmented packet. */
411 mb = ip_frag_process(fp, dr, mb, ip_ofs, ip_len, ip_flag);
412 ip_frag_inuse(tbl, fp);
414 IP_FRAG_LOG(DEBUG, "%s:%d:\n"
416 "tbl: %p, max_entries: %u, use_entries: %u\n"
417 "ipv4_frag_pkt: %p, key: <%" PRIx64 ", %#x>, start: %" PRIu64
418 ", total_size: %u, frag_size: %u, last_idx: %u\n\n",
419 __func__, __LINE__, mb,
420 tbl, tbl->max_entries, tbl->use_entries,
421 fp, fp->key.src_dst, fp->key.id, fp->start,
422 fp->total_size, fp->frag_size, fp->last_idx);
427 #endif /* _IPV4_RSMBL_H_ */