1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include <stddef.h> 6 7 #include <rte_debug.h> 8 9 #include "ip_frag_common.h" 10 11 /* 12 * Reassemble fragments into one packet. 13 */ 14 struct rte_mbuf * 15 ipv4_frag_reassemble(struct ip_frag_pkt *fp) 16 { 17 struct rte_ipv4_hdr *ip_hdr; 18 struct rte_mbuf *m, *prev; 19 uint32_t i, n, ofs, first_len; 20 uint32_t curr_idx = 0; 21 22 first_len = fp->frags[IP_FIRST_FRAG_IDX].len; 23 n = fp->last_idx - 1; 24 25 /*start from the last fragment. */ 26 m = fp->frags[IP_LAST_FRAG_IDX].mb; 27 ofs = fp->frags[IP_LAST_FRAG_IDX].ofs; 28 curr_idx = IP_LAST_FRAG_IDX; 29 30 while (ofs != first_len) { 31 32 prev = m; 33 34 for (i = n; i != IP_FIRST_FRAG_IDX && ofs != first_len; i--) { 35 36 /* previous fragment found. */ 37 if(fp->frags[i].ofs + fp->frags[i].len == ofs) { 38 39 RTE_ASSERT(curr_idx != i); 40 41 /* adjust start of the last fragment data. */ 42 rte_pktmbuf_adj(m, 43 (uint16_t)(m->l2_len + m->l3_len)); 44 rte_pktmbuf_chain(fp->frags[i].mb, m); 45 46 /* this mbuf should not be accessed directly */ 47 fp->frags[curr_idx].mb = NULL; 48 curr_idx = i; 49 50 /* update our last fragment and offset. */ 51 m = fp->frags[i].mb; 52 ofs = fp->frags[i].ofs; 53 } 54 } 55 56 /* error - hole in the packet. */ 57 if (m == prev) { 58 return NULL; 59 } 60 } 61 62 /* chain with the first fragment. */ 63 rte_pktmbuf_adj(m, (uint16_t)(m->l2_len + m->l3_len)); 64 rte_pktmbuf_chain(fp->frags[IP_FIRST_FRAG_IDX].mb, m); 65 fp->frags[curr_idx].mb = NULL; 66 m = fp->frags[IP_FIRST_FRAG_IDX].mb; 67 fp->frags[IP_FIRST_FRAG_IDX].mb = NULL; 68 69 /* update ipv4 header for the reassembled packet */ 70 ip_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *, m->l2_len); 71 72 ip_hdr->total_length = rte_cpu_to_be_16((uint16_t)(fp->total_size + 73 m->l3_len)); 74 ip_hdr->fragment_offset = (uint16_t)(ip_hdr->fragment_offset & 75 rte_cpu_to_be_16(RTE_IPV4_HDR_DF_FLAG)); 76 ip_hdr->hdr_checksum = 0; 77 78 return m; 79 } 80 81 /* 82 * Process new mbuf with fragment of IPV4 packet. 83 * Incoming mbuf should have it's l2_len/l3_len fields setup correctly. 84 * @param tbl 85 * Table where to lookup/add the fragmented packet. 86 * @param mb 87 * Incoming mbuf with IPV4 fragment. 88 * @param tms 89 * Fragment arrival timestamp. 90 * @param ip_hdr 91 * Pointer to the IPV4 header inside the fragment. 92 * @return 93 * Pointer to mbuf for reassembled packet, or NULL if: 94 * - an error occurred. 95 * - not all fragments of the packet are collected yet. 96 */ 97 struct rte_mbuf * 98 rte_ipv4_frag_reassemble_packet(struct rte_ip_frag_tbl *tbl, 99 struct rte_ip_frag_death_row *dr, struct rte_mbuf *mb, uint64_t tms, 100 struct rte_ipv4_hdr *ip_hdr) 101 { 102 struct ip_frag_pkt *fp; 103 struct ip_frag_key key; 104 uint16_t flag_offset, ip_ofs, ip_flag; 105 int32_t ip_len; 106 int32_t trim; 107 108 flag_offset = rte_be_to_cpu_16(ip_hdr->fragment_offset); 109 ip_ofs = (uint16_t)(flag_offset & RTE_IPV4_HDR_OFFSET_MASK); 110 ip_flag = (uint16_t)(flag_offset & RTE_IPV4_HDR_MF_FLAG); 111 112 /* use first 8 bytes only */ 113 memcpy(&key.src_dst[0], &ip_hdr->src_addr, 8); 114 key.id = ip_hdr->packet_id; 115 key.key_len = IPV4_KEYLEN; 116 117 ip_ofs *= RTE_IPV4_HDR_OFFSET_UNITS; 118 ip_len = rte_be_to_cpu_16(ip_hdr->total_length) - mb->l3_len; 119 trim = mb->pkt_len - (ip_len + mb->l3_len + mb->l2_len); 120 121 IP_FRAG_LOG(DEBUG, "%s:%d:\n" 122 "mbuf: %p, tms: %" PRIu64 ", key: <%" PRIx64 ", %#x>" 123 "ofs: %u, len: %d, padding: %d, flags: %#x\n" 124 "tbl: %p, max_cycles: %" PRIu64 ", entry_mask: %#x, " 125 "max_entries: %u, use_entries: %u\n\n", 126 __func__, __LINE__, 127 mb, tms, key.src_dst[0], key.id, ip_ofs, ip_len, trim, ip_flag, 128 tbl, tbl->max_cycles, tbl->entry_mask, tbl->max_entries, 129 tbl->use_entries); 130 131 /* check that fragment length is greater then zero. */ 132 if (ip_len <= 0) { 133 IP_FRAG_MBUF2DR(dr, mb); 134 return NULL; 135 } 136 137 if (unlikely(trim > 0)) 138 rte_pktmbuf_trim(mb, trim); 139 140 /* try to find/add entry into the fragment's table. */ 141 if ((fp = ip_frag_find(tbl, dr, &key, tms)) == NULL) { 142 IP_FRAG_MBUF2DR(dr, mb); 143 return NULL; 144 } 145 146 IP_FRAG_LOG(DEBUG, "%s:%d:\n" 147 "tbl: %p, max_entries: %u, use_entries: %u\n" 148 "ipv4_frag_pkt: %p, key: <%" PRIx64 ", %#x>, start: %" PRIu64 149 ", total_size: %u, frag_size: %u, last_idx: %u\n\n", 150 __func__, __LINE__, 151 tbl, tbl->max_entries, tbl->use_entries, 152 fp, fp->key.src_dst[0], fp->key.id, fp->start, 153 fp->total_size, fp->frag_size, fp->last_idx); 154 155 156 /* process the fragmented packet. */ 157 mb = ip_frag_process(fp, dr, mb, ip_ofs, ip_len, ip_flag); 158 ip_frag_inuse(tbl, fp); 159 160 IP_FRAG_LOG(DEBUG, "%s:%d:\n" 161 "mbuf: %p\n" 162 "tbl: %p, max_entries: %u, use_entries: %u\n" 163 "ipv4_frag_pkt: %p, key: <%" PRIx64 ", %#x>, start: %" PRIu64 164 ", total_size: %u, frag_size: %u, last_idx: %u\n\n", 165 __func__, __LINE__, mb, 166 tbl, tbl->max_entries, tbl->use_entries, 167 fp, fp->key.src_dst[0], fp->key.id, fp->start, 168 fp->total_size, fp->frag_size, fp->last_idx); 169 170 return mb; 171 } 172