/* * Reassemble fragments into one packet. */ struct rte_mbuf * ipv4_frag_reassemble(struct ip_frag_pkt *fp) { struct ipv4_hdr *ip_hdr; struct rte_mbuf *m, *prev; uint32_t i, n, ofs, first_len; uint32_t curr_idx = 0; first_len = fp->frags[IP_FIRST_FRAG_IDX].len; n = fp->last_idx - 1; /*start from the last fragment. */ m = fp->frags[IP_LAST_FRAG_IDX].mb; ofs = fp->frags[IP_LAST_FRAG_IDX].ofs; curr_idx = IP_LAST_FRAG_IDX; while (ofs != first_len) { prev = m; for (i = n; i != IP_FIRST_FRAG_IDX && ofs != first_len; i--) { /* previous fragment found. */ if(fp->frags[i].ofs + fp->frags[i].len == ofs) { /* adjust start of the last fragment data. */ rte_pktmbuf_adj(m, (uint16_t)(m->l2_len + m->l3_len)); rte_pktmbuf_chain(fp->frags[i].mb, m); /* this mbuf should not be accessed directly */ fp->frags[curr_idx].mb = NULL; curr_idx = i; /* update our last fragment and offset. */ m = fp->frags[i].mb; ofs = fp->frags[i].ofs; } } /* error - hole in the packet. */ if (m == prev) { return NULL; } } /* chain with the first fragment. */ rte_pktmbuf_adj(m, (uint16_t)(m->l2_len + m->l3_len)); rte_pktmbuf_chain(fp->frags[IP_FIRST_FRAG_IDX].mb, m); m = fp->frags[IP_FIRST_FRAG_IDX].mb; /* update mbuf fields for reassembled packet. */ m->ol_flags |= PKT_TX_IP_CKSUM; /* update ipv4 header for the reassmebled packet */ ip_hdr = rte_pktmbuf_mtod_offset(m, struct ipv4_hdr *, m->l2_len); ip_hdr->total_length = rte_cpu_to_be_16((uint16_t)(fp->total_size + m->l3_len)); ip_hdr->fragment_offset = (uint16_t)(ip_hdr->fragment_offset & rte_cpu_to_be_16(IPV4_HDR_DF_FLAG)); ip_hdr->hdr_checksum = 0; return m; }
/* * Reassemble fragments into one packet. */ struct rte_mbuf * ipv6_frag_reassemble(struct ip_frag_pkt *fp) { struct ipv6_hdr *ip_hdr; struct ipv6_extension_fragment *frag_hdr; struct rte_mbuf *m, *prev; uint32_t i, n, ofs, first_len; uint32_t last_len, move_len, payload_len; uint32_t curr_idx = 0; first_len = fp->frags[IP_FIRST_FRAG_IDX].len; n = fp->last_idx - 1; /*start from the last fragment. */ m = fp->frags[IP_LAST_FRAG_IDX].mb; ofs = fp->frags[IP_LAST_FRAG_IDX].ofs; last_len = fp->frags[IP_LAST_FRAG_IDX].len; curr_idx = IP_LAST_FRAG_IDX; payload_len = ofs + last_len; while (ofs != first_len) { prev = m; for (i = n; i != IP_FIRST_FRAG_IDX && ofs != first_len; i--) { /* previous fragment found. */ if (fp->frags[i].ofs + fp->frags[i].len == ofs) { /* adjust start of the last fragment data. */ rte_pktmbuf_adj(m, (uint16_t)(m->l2_len + m->l3_len)); rte_pktmbuf_chain(fp->frags[i].mb, m); /* this mbuf should not be accessed directly */ fp->frags[curr_idx].mb = NULL; curr_idx = i; /* update our last fragment and offset. */ m = fp->frags[i].mb; ofs = fp->frags[i].ofs; } } /* error - hole in the packet. */ if (m == prev) { return NULL; } } /* chain with the first fragment. */ rte_pktmbuf_adj(m, (uint16_t)(m->l2_len + m->l3_len)); rte_pktmbuf_chain(fp->frags[IP_FIRST_FRAG_IDX].mb, m); m = fp->frags[IP_FIRST_FRAG_IDX].mb; /* update mbuf fields for reassembled packet. */ m->ol_flags |= PKT_TX_IP_CKSUM; /* update ipv6 header for the reassembled datagram */ ip_hdr = rte_pktmbuf_mtod_offset(m, struct ipv6_hdr *, m->l2_len); ip_hdr->payload_len = rte_cpu_to_be_16(payload_len); /* * remove fragmentation header. note that per RFC2460, we need to update * the last non-fragmentable header with the "next header" field to contain * type of the first fragmentable header, but we currently don't support * other headers, so we assume there are no other headers and thus update * the main IPv6 header instead. */ move_len = m->l2_len + m->l3_len - sizeof(*frag_hdr); frag_hdr = (struct ipv6_extension_fragment *) (ip_hdr + 1); ip_hdr->proto = frag_hdr->next_header; ip_frag_memmove(rte_pktmbuf_mtod_offset(m, char *, sizeof(*frag_hdr)), rte_pktmbuf_mtod(m, char*), move_len); rte_pktmbuf_adj(m, sizeof(*frag_hdr)); return m; }