]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | /* SPDX-License-Identifier: BSD-3-Clause |
2 | * Copyright(c) 2010-2014 Intel Corporation | |
7c673cae FG |
3 | */ |
4 | ||
5 | #include <stddef.h> | |
6 | ||
7 | #include <rte_memcpy.h> | |
8 | ||
9 | #include "ip_frag_common.h" | |
10 | ||
11 | /** | |
12 | * @file | |
13 | * IPv6 reassemble | |
14 | * | |
15 | * Implementation of IPv6 reassembly. | |
16 | * | |
17 | */ | |
18 | ||
19 | static inline void | |
20 | ip_frag_memmove(char *dst, char *src, int len) | |
21 | { | |
22 | int i; | |
23 | ||
24 | /* go backwards to make sure we don't overwrite anything important */ | |
25 | for (i = len - 1; i >= 0; i--) | |
26 | dst[i] = src[i]; | |
27 | } | |
28 | ||
29 | /* | |
30 | * Reassemble fragments into one packet. | |
31 | */ | |
32 | struct rte_mbuf * | |
33 | ipv6_frag_reassemble(struct ip_frag_pkt *fp) | |
34 | { | |
f67539c2 | 35 | struct rte_ipv6_hdr *ip_hdr; |
7c673cae FG |
36 | struct ipv6_extension_fragment *frag_hdr; |
37 | struct rte_mbuf *m, *prev; | |
38 | uint32_t i, n, ofs, first_len; | |
39 | uint32_t last_len, move_len, payload_len; | |
40 | uint32_t curr_idx = 0; | |
41 | ||
42 | first_len = fp->frags[IP_FIRST_FRAG_IDX].len; | |
43 | n = fp->last_idx - 1; | |
44 | ||
45 | /*start from the last fragment. */ | |
46 | m = fp->frags[IP_LAST_FRAG_IDX].mb; | |
47 | ofs = fp->frags[IP_LAST_FRAG_IDX].ofs; | |
48 | last_len = fp->frags[IP_LAST_FRAG_IDX].len; | |
49 | curr_idx = IP_LAST_FRAG_IDX; | |
50 | ||
51 | payload_len = ofs + last_len; | |
52 | ||
53 | while (ofs != first_len) { | |
54 | ||
55 | prev = m; | |
56 | ||
57 | for (i = n; i != IP_FIRST_FRAG_IDX && ofs != first_len; i--) { | |
58 | ||
59 | /* previous fragment found. */ | |
60 | if (fp->frags[i].ofs + fp->frags[i].len == ofs) { | |
61 | ||
9f95a23c TL |
62 | RTE_ASSERT(curr_idx != i); |
63 | ||
7c673cae | 64 | /* adjust start of the last fragment data. */ |
9f95a23c TL |
65 | rte_pktmbuf_adj(m, |
66 | (uint16_t)(m->l2_len + m->l3_len)); | |
7c673cae FG |
67 | rte_pktmbuf_chain(fp->frags[i].mb, m); |
68 | ||
69 | /* this mbuf should not be accessed directly */ | |
70 | fp->frags[curr_idx].mb = NULL; | |
71 | curr_idx = i; | |
72 | ||
73 | /* update our last fragment and offset. */ | |
74 | m = fp->frags[i].mb; | |
75 | ofs = fp->frags[i].ofs; | |
76 | } | |
77 | } | |
78 | ||
79 | /* error - hole in the packet. */ | |
80 | if (m == prev) { | |
81 | return NULL; | |
82 | } | |
83 | } | |
84 | ||
85 | /* chain with the first fragment. */ | |
86 | rte_pktmbuf_adj(m, (uint16_t)(m->l2_len + m->l3_len)); | |
87 | rte_pktmbuf_chain(fp->frags[IP_FIRST_FRAG_IDX].mb, m); | |
11fdf7f2 | 88 | fp->frags[curr_idx].mb = NULL; |
7c673cae | 89 | m = fp->frags[IP_FIRST_FRAG_IDX].mb; |
11fdf7f2 | 90 | fp->frags[IP_FIRST_FRAG_IDX].mb = NULL; |
7c673cae | 91 | |
7c673cae | 92 | /* update ipv6 header for the reassembled datagram */ |
f67539c2 | 93 | ip_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv6_hdr *, m->l2_len); |
7c673cae FG |
94 | |
95 | ip_hdr->payload_len = rte_cpu_to_be_16(payload_len); | |
96 | ||
97 | /* | |
98 | * remove fragmentation header. note that per RFC2460, we need to update | |
99 | * the last non-fragmentable header with the "next header" field to contain | |
100 | * type of the first fragmentable header, but we currently don't support | |
101 | * other headers, so we assume there are no other headers and thus update | |
102 | * the main IPv6 header instead. | |
103 | */ | |
104 | move_len = m->l2_len + m->l3_len - sizeof(*frag_hdr); | |
105 | frag_hdr = (struct ipv6_extension_fragment *) (ip_hdr + 1); | |
106 | ip_hdr->proto = frag_hdr->next_header; | |
107 | ||
108 | ip_frag_memmove(rte_pktmbuf_mtod_offset(m, char *, sizeof(*frag_hdr)), | |
109 | rte_pktmbuf_mtod(m, char*), move_len); | |
110 | ||
111 | rte_pktmbuf_adj(m, sizeof(*frag_hdr)); | |
112 | ||
113 | return m; | |
114 | } | |
115 | ||
116 | /* | |
117 | * Process new mbuf with fragment of IPV6 datagram. | |
118 | * Incoming mbuf should have its l2_len/l3_len fields setup correctly. | |
119 | * @param tbl | |
120 | * Table where to lookup/add the fragmented packet. | |
121 | * @param mb | |
122 | * Incoming mbuf with IPV6 fragment. | |
123 | * @param tms | |
124 | * Fragment arrival timestamp. | |
125 | * @param ip_hdr | |
126 | * Pointer to the IPV6 header. | |
127 | * @param frag_hdr | |
128 | * Pointer to the IPV6 fragment extension header. | |
129 | * @return | |
130 | * Pointer to mbuf for reassembled packet, or NULL if: | |
11fdf7f2 | 131 | * - an error occurred. |
7c673cae FG |
132 | * - not all fragments of the packet are collected yet. |
133 | */ | |
134 | #define MORE_FRAGS(x) (((x) & 0x100) >> 8) | |
135 | #define FRAG_OFFSET(x) (rte_cpu_to_be_16(x) >> 3) | |
136 | struct rte_mbuf * | |
137 | rte_ipv6_frag_reassemble_packet(struct rte_ip_frag_tbl *tbl, | |
9f95a23c | 138 | struct rte_ip_frag_death_row *dr, struct rte_mbuf *mb, uint64_t tms, |
f67539c2 | 139 | struct rte_ipv6_hdr *ip_hdr, struct ipv6_extension_fragment *frag_hdr) |
7c673cae FG |
140 | { |
141 | struct ip_frag_pkt *fp; | |
142 | struct ip_frag_key key; | |
9f95a23c TL |
143 | uint16_t ip_ofs; |
144 | int32_t ip_len; | |
7c673cae FG |
145 | |
146 | rte_memcpy(&key.src_dst[0], ip_hdr->src_addr, 16); | |
147 | rte_memcpy(&key.src_dst[2], ip_hdr->dst_addr, 16); | |
148 | ||
149 | key.id = frag_hdr->id; | |
150 | key.key_len = IPV6_KEYLEN; | |
151 | ||
152 | ip_ofs = FRAG_OFFSET(frag_hdr->frag_data) * 8; | |
153 | ||
154 | /* | |
9f95a23c TL |
155 | * as per RFC2460, payload length contains all extension headers |
156 | * as well. | |
157 | * since we don't support anything but frag headers, | |
158 | * this is what we remove from the payload len. | |
7c673cae FG |
159 | */ |
160 | ip_len = rte_be_to_cpu_16(ip_hdr->payload_len) - sizeof(*frag_hdr); | |
161 | ||
162 | IP_FRAG_LOG(DEBUG, "%s:%d:\n" | |
163 | "mbuf: %p, tms: %" PRIu64 | |
9f95a23c TL |
164 | ", key: <" IPv6_KEY_BYTES_FMT ", %#x>, " |
165 | "ofs: %u, len: %d, flags: %#x\n" | |
7c673cae FG |
166 | "tbl: %p, max_cycles: %" PRIu64 ", entry_mask: %#x, " |
167 | "max_entries: %u, use_entries: %u\n\n", | |
168 | __func__, __LINE__, | |
169 | mb, tms, IPv6_KEY_BYTES(key.src_dst), key.id, ip_ofs, ip_len, | |
170 | RTE_IPV6_GET_MF(frag_hdr->frag_data), | |
171 | tbl, tbl->max_cycles, tbl->entry_mask, tbl->max_entries, | |
172 | tbl->use_entries); | |
173 | ||
9f95a23c TL |
174 | /* check that fragment length is greater then zero. */ |
175 | if (ip_len <= 0) { | |
176 | IP_FRAG_MBUF2DR(dr, mb); | |
177 | return NULL; | |
178 | } | |
179 | ||
7c673cae FG |
180 | /* try to find/add entry into the fragment's table. */ |
181 | fp = ip_frag_find(tbl, dr, &key, tms); | |
182 | if (fp == NULL) { | |
183 | IP_FRAG_MBUF2DR(dr, mb); | |
184 | return NULL; | |
185 | } | |
186 | ||
187 | IP_FRAG_LOG(DEBUG, "%s:%d:\n" | |
188 | "tbl: %p, max_entries: %u, use_entries: %u\n" | |
189 | "ipv6_frag_pkt: %p, key: <" IPv6_KEY_BYTES_FMT ", %#x>, start: %" PRIu64 | |
190 | ", total_size: %u, frag_size: %u, last_idx: %u\n\n", | |
191 | __func__, __LINE__, | |
192 | tbl, tbl->max_entries, tbl->use_entries, | |
193 | fp, IPv6_KEY_BYTES(fp->key.src_dst), fp->key.id, fp->start, | |
194 | fp->total_size, fp->frag_size, fp->last_idx); | |
195 | ||
196 | ||
197 | /* process the fragmented packet. */ | |
198 | mb = ip_frag_process(fp, dr, mb, ip_ofs, ip_len, | |
199 | MORE_FRAGS(frag_hdr->frag_data)); | |
200 | ip_frag_inuse(tbl, fp); | |
201 | ||
202 | IP_FRAG_LOG(DEBUG, "%s:%d:\n" | |
203 | "mbuf: %p\n" | |
204 | "tbl: %p, max_entries: %u, use_entries: %u\n" | |
205 | "ipv6_frag_pkt: %p, key: <" IPv6_KEY_BYTES_FMT ", %#x>, start: %" PRIu64 | |
206 | ", total_size: %u, frag_size: %u, last_idx: %u\n\n", | |
207 | __func__, __LINE__, mb, | |
208 | tbl, tbl->max_entries, tbl->use_entries, | |
209 | fp, IPv6_KEY_BYTES(fp->key.src_dst), fp->key.id, fp->start, | |
210 | fp->total_size, fp->frag_size, fp->last_idx); | |
211 | ||
212 | return mb; | |
213 | } |