blob: bba11e52959a1d41e43c42b8c3bcc973e6274072 [file] [log] [blame]
Klement Sekera75e7d132017-09-20 08:26:30 +02001/*
2 * Copyright (c) 2017 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16/**
17 * @file
Klement Sekera896c8962019-06-24 11:52:49 +000018 * @brief IPv6 Full Reassembly.
Klement Sekera75e7d132017-09-20 08:26:30 +020019 *
Klement Sekera896c8962019-06-24 11:52:49 +000020 * This file contains the source code for IPv6 full reassembly.
Klement Sekera75e7d132017-09-20 08:26:30 +020021 */
22
23#include <vppinfra/vec.h>
24#include <vnet/vnet.h>
25#include <vnet/ip/ip.h>
26#include <vppinfra/bihash_48_8.h>
Klement Sekera896c8962019-06-24 11:52:49 +000027#include <vnet/ip/reass/ip6_full_reass.h>
Klement Sekera75e7d132017-09-20 08:26:30 +020028
29#define MSEC_PER_SEC 1000
Klement Sekera896c8962019-06-24 11:52:49 +000030#define IP6_FULL_REASS_TIMEOUT_DEFAULT_MS 100
31#define IP6_FULL_REASS_EXPIRE_WALK_INTERVAL_DEFAULT_MS 10000 // 10 seconds default
32#define IP6_FULL_REASS_MAX_REASSEMBLIES_DEFAULT 1024
33#define IP6_FULL_REASS_MAX_REASSEMBLY_LENGTH_DEFAULT 3
34#define IP6_FULL_REASS_HT_LOAD_FACTOR (0.75)
Klement Sekera75e7d132017-09-20 08:26:30 +020035
Klement Sekerad0f70a32018-12-14 17:24:13 +010036typedef enum
37{
Klement Sekera896c8962019-06-24 11:52:49 +000038 IP6_FULL_REASS_RC_OK,
39 IP6_FULL_REASS_RC_INTERNAL_ERROR,
40 IP6_FULL_REASS_RC_TOO_MANY_FRAGMENTS,
41 IP6_FULL_REASS_RC_NO_BUF,
42 IP6_FULL_REASS_RC_HANDOFF,
43} ip6_full_reass_rc_t;
Klement Sekera75e7d132017-09-20 08:26:30 +020044
45typedef struct
46{
47 union
48 {
49 struct
50 {
51 ip6_address_t src;
52 ip6_address_t dst;
Klement Sekera75e7d132017-09-20 08:26:30 +020053 u32 xx_id;
Klement Sekera75e7d132017-09-20 08:26:30 +020054 u32 frag_id;
Klement Sekera8dcfed52018-06-28 11:16:15 +020055 u8 unused[7];
56 u8 proto;
Klement Sekera75e7d132017-09-20 08:26:30 +020057 };
58 u64 as_u64[6];
59 };
Klement Sekera896c8962019-06-24 11:52:49 +000060} ip6_full_reass_key_t;
Klement Sekera75e7d132017-09-20 08:26:30 +020061
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -080062typedef union
63{
64 struct
65 {
66 u32 reass_index;
Klement Sekera630ab582019-07-19 09:14:19 +000067 u32 memory_owner_thread_index;
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -080068 };
69 u64 as_u64;
Klement Sekera896c8962019-06-24 11:52:49 +000070} ip6_full_reass_val_t;
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -080071
72typedef union
73{
74 struct
75 {
Klement Sekera896c8962019-06-24 11:52:49 +000076 ip6_full_reass_key_t k;
77 ip6_full_reass_val_t v;
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -080078 };
79 clib_bihash_kv_48_8_t kv;
Klement Sekera896c8962019-06-24 11:52:49 +000080} ip6_full_reass_kv_t;
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -080081
82
Klement Sekera75e7d132017-09-20 08:26:30 +020083always_inline u32
Klement Sekera896c8962019-06-24 11:52:49 +000084ip6_full_reass_buffer_get_data_offset (vlib_buffer_t * b)
Klement Sekera75e7d132017-09-20 08:26:30 +020085{
86 vnet_buffer_opaque_t *vnb = vnet_buffer (b);
Klement Sekerad0f70a32018-12-14 17:24:13 +010087 return vnb->ip.reass.range_first - vnb->ip.reass.fragment_first;
Klement Sekera75e7d132017-09-20 08:26:30 +020088}
89
90always_inline u16
Klement Sekera896c8962019-06-24 11:52:49 +000091ip6_full_reass_buffer_get_data_len (vlib_buffer_t * b)
Klement Sekera75e7d132017-09-20 08:26:30 +020092{
93 vnet_buffer_opaque_t *vnb = vnet_buffer (b);
Klement Sekerad0f70a32018-12-14 17:24:13 +010094 return clib_min (vnb->ip.reass.range_last, vnb->ip.reass.fragment_last) -
Klement Sekera896c8962019-06-24 11:52:49 +000095 (vnb->ip.reass.fragment_first +
96 ip6_full_reass_buffer_get_data_offset (b)) + 1;
Klement Sekera75e7d132017-09-20 08:26:30 +020097}
98
99typedef struct
100{
101 // hash table key
Klement Sekera896c8962019-06-24 11:52:49 +0000102 ip6_full_reass_key_t key;
Klement Sekera75e7d132017-09-20 08:26:30 +0200103 // time when last packet was received
104 f64 last_heard;
105 // internal id of this reassembly
Klement Sekera4c533132018-02-22 11:41:12 +0100106 u64 id;
Klement Sekera75e7d132017-09-20 08:26:30 +0200107 // buffer index of first buffer in this reassembly context
108 u32 first_bi;
109 // last octet of packet, ~0 until fragment without more_fragments arrives
110 u32 last_packet_octet;
111 // length of data collected so far
112 u32 data_len;
113 // trace operation counter
114 u32 trace_op_counter;
Klement Sekerae8498652019-06-17 12:23:15 +0000115 // next index - used by custom apps (~0 if not set)
Klement Sekera21aa8f12019-05-20 12:27:33 +0200116 u32 next_index;
Klement Sekerae8498652019-06-17 12:23:15 +0000117 // error next index - used by custom apps (~0 if not set)
Klement Sekera21aa8f12019-05-20 12:27:33 +0200118 u32 error_next_index;
Klement Sekera4c533132018-02-22 11:41:12 +0100119 // minimum fragment length for this reassembly - used to estimate MTU
120 u16 min_fragment_length;
Klement Sekera3a343d42019-05-16 14:35:46 +0200121 // number of fragments for this reassembly
122 u32 fragments_n;
Klement Sekera630ab582019-07-19 09:14:19 +0000123 // thread owning memory for this context (whose pool contains this ctx)
124 u32 memory_owner_thread_index;
125 // thread which received fragment with offset 0 and which sends out the
126 // completed reassembly
127 u32 sendout_thread_index;
Klement Sekera896c8962019-06-24 11:52:49 +0000128} ip6_full_reass_t;
Klement Sekera75e7d132017-09-20 08:26:30 +0200129
130typedef struct
131{
Klement Sekera896c8962019-06-24 11:52:49 +0000132 ip6_full_reass_t *pool;
Klement Sekera4c533132018-02-22 11:41:12 +0100133 u32 reass_n;
Klement Sekera4c533132018-02-22 11:41:12 +0100134 u32 id_counter;
135 clib_spinlock_t lock;
Klement Sekera896c8962019-06-24 11:52:49 +0000136} ip6_full_reass_per_thread_t;
Klement Sekera4c533132018-02-22 11:41:12 +0100137
138typedef struct
139{
Klement Sekera75e7d132017-09-20 08:26:30 +0200140 // IPv6 config
141 u32 timeout_ms;
142 f64 timeout;
143 u32 expire_walk_interval_ms;
Klement Sekera3a343d42019-05-16 14:35:46 +0200144 // maximum number of fragments in one reassembly
145 u32 max_reass_len;
146 // maximum number of reassemblies
Klement Sekera75e7d132017-09-20 08:26:30 +0200147 u32 max_reass_n;
148
149 // IPv6 runtime
Klement Sekera75e7d132017-09-20 08:26:30 +0200150 clib_bihash_48_8_t hash;
Klement Sekera4c533132018-02-22 11:41:12 +0100151
152 // per-thread data
Klement Sekera896c8962019-06-24 11:52:49 +0000153 ip6_full_reass_per_thread_t *per_thread_data;
Klement Sekera75e7d132017-09-20 08:26:30 +0200154
155 // convenience
156 vlib_main_t *vlib_main;
Klement Sekera75e7d132017-09-20 08:26:30 +0200157
158 // node index of ip6-drop node
159 u32 ip6_drop_idx;
160 u32 ip6_icmp_error_idx;
Klement Sekera896c8962019-06-24 11:52:49 +0000161 u32 ip6_full_reass_expire_node_idx;
Klement Sekera75e7d132017-09-20 08:26:30 +0200162
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800163 /** Worker handoff */
164 u32 fq_index;
165 u32 fq_feature_index;
166
Klement Sekera7b2e9fb2019-10-01 13:00:22 +0000167 // reference count for enabling/disabling feature - per interface
168 u32 *feature_use_refcount_per_intf;
Klement Sekera896c8962019-06-24 11:52:49 +0000169} ip6_full_reass_main_t;
Klement Sekera75e7d132017-09-20 08:26:30 +0200170
Klement Sekera896c8962019-06-24 11:52:49 +0000171extern ip6_full_reass_main_t ip6_full_reass_main;
Filip Tehlar26ea14e2019-03-11 05:30:21 -0700172
173#ifndef CLIB_MARCH_VARIANT
Klement Sekera896c8962019-06-24 11:52:49 +0000174ip6_full_reass_main_t ip6_full_reass_main;
Filip Tehlar26ea14e2019-03-11 05:30:21 -0700175#endif /* CLIB_MARCH_VARIANT */
Klement Sekera75e7d132017-09-20 08:26:30 +0200176
177typedef enum
178{
Klement Sekera896c8962019-06-24 11:52:49 +0000179 IP6_FULL_REASSEMBLY_NEXT_INPUT,
180 IP6_FULL_REASSEMBLY_NEXT_DROP,
181 IP6_FULL_REASSEMBLY_NEXT_ICMP_ERROR,
182 IP6_FULL_REASSEMBLY_NEXT_HANDOFF,
183 IP6_FULL_REASSEMBLY_N_NEXT,
184} ip6_full_reass_next_t;
Klement Sekera75e7d132017-09-20 08:26:30 +0200185
186typedef enum
187{
188 RANGE_NEW,
189 RANGE_OVERLAP,
190 ICMP_ERROR_RT_EXCEEDED,
191 ICMP_ERROR_FL_TOO_BIG,
192 ICMP_ERROR_FL_NOT_MULT_8,
193 FINALIZE,
Klement Sekera630ab582019-07-19 09:14:19 +0000194 HANDOFF,
Klement Sekera896c8962019-06-24 11:52:49 +0000195} ip6_full_reass_trace_operation_e;
Klement Sekera75e7d132017-09-20 08:26:30 +0200196
197typedef struct
198{
199 u16 range_first;
200 u16 range_last;
201 u32 range_bi;
202 i32 data_offset;
203 u32 data_len;
204 u32 first_bi;
Klement Sekera896c8962019-06-24 11:52:49 +0000205} ip6_full_reass_range_trace_t;
Klement Sekera75e7d132017-09-20 08:26:30 +0200206
207typedef struct
208{
Klement Sekera896c8962019-06-24 11:52:49 +0000209 ip6_full_reass_trace_operation_e action;
Klement Sekera75e7d132017-09-20 08:26:30 +0200210 u32 reass_id;
Klement Sekera896c8962019-06-24 11:52:49 +0000211 ip6_full_reass_range_trace_t trace_range;
Klement Sekera75e7d132017-09-20 08:26:30 +0200212 u32 op_id;
213 u32 fragment_first;
214 u32 fragment_last;
215 u32 total_data_len;
Klement Sekera630ab582019-07-19 09:14:19 +0000216 u32 thread_id;
217 u32 thread_id_to;
Klement Sekera896c8962019-06-24 11:52:49 +0000218} ip6_full_reass_trace_t;
Klement Sekera75e7d132017-09-20 08:26:30 +0200219
220static void
Klement Sekera896c8962019-06-24 11:52:49 +0000221ip6_full_reass_trace_details (vlib_main_t * vm, u32 bi,
222 ip6_full_reass_range_trace_t * trace)
Klement Sekera75e7d132017-09-20 08:26:30 +0200223{
224 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
225 vnet_buffer_opaque_t *vnb = vnet_buffer (b);
226 trace->range_first = vnb->ip.reass.range_first;
227 trace->range_last = vnb->ip.reass.range_last;
Klement Sekera896c8962019-06-24 11:52:49 +0000228 trace->data_offset = ip6_full_reass_buffer_get_data_offset (b);
229 trace->data_len = ip6_full_reass_buffer_get_data_len (b);
Klement Sekera75e7d132017-09-20 08:26:30 +0200230 trace->range_bi = bi;
231}
232
Klement Sekera4c533132018-02-22 11:41:12 +0100233static u8 *
Klement Sekera896c8962019-06-24 11:52:49 +0000234format_ip6_full_reass_range_trace (u8 * s, va_list * args)
Klement Sekera75e7d132017-09-20 08:26:30 +0200235{
Klement Sekera896c8962019-06-24 11:52:49 +0000236 ip6_full_reass_range_trace_t *trace =
237 va_arg (*args, ip6_full_reass_range_trace_t *);
238 s =
239 format (s, "range: [%u, %u], off %d, len %u, bi %u", trace->range_first,
240 trace->range_last, trace->data_offset, trace->data_len,
241 trace->range_bi);
Klement Sekera75e7d132017-09-20 08:26:30 +0200242 return s;
243}
244
Klement Sekera4c533132018-02-22 11:41:12 +0100245static u8 *
Klement Sekera896c8962019-06-24 11:52:49 +0000246format_ip6_full_reass_trace (u8 * s, va_list * args)
Klement Sekera75e7d132017-09-20 08:26:30 +0200247{
248 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
249 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Klement Sekera896c8962019-06-24 11:52:49 +0000250 ip6_full_reass_trace_t *t = va_arg (*args, ip6_full_reass_trace_t *);
Klement Sekera630ab582019-07-19 09:14:19 +0000251 u32 indent = 0;
252 if (~0 != t->reass_id)
253 {
254 s = format (s, "reass id: %u, op id: %u ", t->reass_id, t->op_id);
255 indent = format_get_indent (s);
256 s = format (s, "first bi: %u, data len: %u, ip/fragment[%u, %u]",
257 t->trace_range.first_bi, t->total_data_len,
258 t->fragment_first, t->fragment_last);
259 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200260 switch (t->action)
261 {
262 case RANGE_NEW:
263 s = format (s, "\n%Unew %U", format_white_space, indent,
Klement Sekera896c8962019-06-24 11:52:49 +0000264 format_ip6_full_reass_range_trace, &t->trace_range);
Klement Sekera75e7d132017-09-20 08:26:30 +0200265 break;
266 case RANGE_OVERLAP:
267 s = format (s, "\n%Uoverlap %U", format_white_space, indent,
Klement Sekera896c8962019-06-24 11:52:49 +0000268 format_ip6_full_reass_range_trace, &t->trace_range);
Klement Sekera75e7d132017-09-20 08:26:30 +0200269 break;
270 case ICMP_ERROR_FL_TOO_BIG:
271 s = format (s, "\n%Uicmp-error - frag_len > 65535 %U",
Klement Sekera896c8962019-06-24 11:52:49 +0000272 format_white_space, indent,
273 format_ip6_full_reass_range_trace, &t->trace_range);
Klement Sekera75e7d132017-09-20 08:26:30 +0200274 break;
275 case ICMP_ERROR_FL_NOT_MULT_8:
276 s = format (s, "\n%Uicmp-error - frag_len mod 8 != 0 %U",
Klement Sekera896c8962019-06-24 11:52:49 +0000277 format_white_space, indent,
278 format_ip6_full_reass_range_trace, &t->trace_range);
Klement Sekera75e7d132017-09-20 08:26:30 +0200279 break;
280 case ICMP_ERROR_RT_EXCEEDED:
281 s = format (s, "\n%Uicmp-error - reassembly time exceeded",
282 format_white_space, indent);
283 break;
284 case FINALIZE:
285 s = format (s, "\n%Ufinalize reassembly", format_white_space, indent);
286 break;
Klement Sekera630ab582019-07-19 09:14:19 +0000287 case HANDOFF:
288 s =
289 format (s, "handoff from thread #%u to thread #%u", t->thread_id,
290 t->thread_id_to);
291 break;
Klement Sekera75e7d132017-09-20 08:26:30 +0200292 }
293 return s;
294}
295
296static void
Klement Sekera896c8962019-06-24 11:52:49 +0000297ip6_full_reass_add_trace (vlib_main_t * vm, vlib_node_runtime_t * node,
298 ip6_full_reass_main_t * rm,
299 ip6_full_reass_t * reass, u32 bi,
300 ip6_full_reass_trace_operation_e action,
301 u32 thread_id_to)
Klement Sekera75e7d132017-09-20 08:26:30 +0200302{
303 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
304 vnet_buffer_opaque_t *vnb = vnet_buffer (b);
Klement Sekera896c8962019-06-24 11:52:49 +0000305 ip6_full_reass_trace_t *t = vlib_add_trace (vm, node, b, sizeof (t[0]));
306 if (reass)
307 {
308 t->reass_id = reass->id;
309 t->op_id = reass->trace_op_counter;
310 t->trace_range.first_bi = reass->first_bi;
311 t->total_data_len = reass->data_len;
312 ++reass->trace_op_counter;
313 }
314 else
315 {
316 t->reass_id = ~0;
317 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200318 t->action = action;
Klement Sekera630ab582019-07-19 09:14:19 +0000319 t->thread_id = vm->thread_index;
320 t->thread_id_to = thread_id_to;
Klement Sekera896c8962019-06-24 11:52:49 +0000321 ip6_full_reass_trace_details (vm, bi, &t->trace_range);
Klement Sekera75e7d132017-09-20 08:26:30 +0200322 t->fragment_first = vnb->ip.reass.fragment_first;
323 t->fragment_last = vnb->ip.reass.fragment_last;
Klement Sekera75e7d132017-09-20 08:26:30 +0200324#if 0
325 static u8 *s = NULL;
Klement Sekera896c8962019-06-24 11:52:49 +0000326 s = format (s, "%U", format_ip6_full_reass_trace, NULL, NULL, t);
Klement Sekera75e7d132017-09-20 08:26:30 +0200327 printf ("%.*s\n", vec_len (s), s);
328 fflush (stdout);
329 vec_reset_length (s);
330#endif
331}
332
Klement Sekera4c533132018-02-22 11:41:12 +0100333always_inline void
Klement Sekera896c8962019-06-24 11:52:49 +0000334ip6_full_reass_free_ctx (ip6_full_reass_per_thread_t * rt,
335 ip6_full_reass_t * reass)
Klement Sekera630ab582019-07-19 09:14:19 +0000336{
337 pool_put (rt->pool, reass);
338 --rt->reass_n;
339}
340
341always_inline void
Klement Sekera896c8962019-06-24 11:52:49 +0000342ip6_full_reass_free (ip6_full_reass_main_t * rm,
343 ip6_full_reass_per_thread_t * rt,
344 ip6_full_reass_t * reass)
Klement Sekera75e7d132017-09-20 08:26:30 +0200345{
346 clib_bihash_kv_48_8_t kv;
347 kv.key[0] = reass->key.as_u64[0];
348 kv.key[1] = reass->key.as_u64[1];
349 kv.key[2] = reass->key.as_u64[2];
350 kv.key[3] = reass->key.as_u64[3];
351 kv.key[4] = reass->key.as_u64[4];
352 kv.key[5] = reass->key.as_u64[5];
353 clib_bihash_add_del_48_8 (&rm->hash, &kv, 0);
Klement Sekera896c8962019-06-24 11:52:49 +0000354 ip6_full_reass_free_ctx (rt, reass);
Klement Sekera75e7d132017-09-20 08:26:30 +0200355}
356
Klement Sekera4c533132018-02-22 11:41:12 +0100357always_inline void
Klement Sekera896c8962019-06-24 11:52:49 +0000358ip6_full_reass_drop_all (vlib_main_t * vm, vlib_node_runtime_t * node,
359 ip6_full_reass_main_t * rm, ip6_full_reass_t * reass)
Klement Sekera75e7d132017-09-20 08:26:30 +0200360{
361 u32 range_bi = reass->first_bi;
362 vlib_buffer_t *range_b;
363 vnet_buffer_opaque_t *range_vnb;
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100364 u32 *to_free = NULL;
Klement Sekera75e7d132017-09-20 08:26:30 +0200365 while (~0 != range_bi)
366 {
367 range_b = vlib_get_buffer (vm, range_bi);
368 range_vnb = vnet_buffer (range_b);
369 u32 bi = range_bi;
370 while (~0 != bi)
371 {
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100372 vec_add1 (to_free, bi);
Klement Sekera75e7d132017-09-20 08:26:30 +0200373 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
374 if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
375 {
376 bi = b->next_buffer;
377 b->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
378 }
379 else
380 {
381 bi = ~0;
382 }
383 }
384 range_bi = range_vnb->ip.reass.next_range_bi;
385 }
Klement Sekera21aa8f12019-05-20 12:27:33 +0200386 /* send to next_error_index */
Klement Sekerae8498652019-06-17 12:23:15 +0000387 if (~0 != reass->error_next_index)
Klement Sekera21aa8f12019-05-20 12:27:33 +0200388 {
389 u32 n_left_to_next, *to_next, next_index;
390
391 next_index = reass->error_next_index;
392 u32 bi = ~0;
393
394 while (vec_len (to_free) > 0)
395 {
396 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
397
398 while (vec_len (to_free) > 0 && n_left_to_next > 0)
399 {
400 bi = vec_pop (to_free);
401
402 if (~0 != bi)
403 {
404 to_next[0] = bi;
405 to_next += 1;
406 n_left_to_next -= 1;
Klement Sekera21aa8f12019-05-20 12:27:33 +0200407 }
408 }
409 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
410 }
411 }
412 else
413 {
414 vlib_buffer_free (vm, to_free, vec_len (to_free));
415 }
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100416 vec_free (to_free);
Klement Sekera75e7d132017-09-20 08:26:30 +0200417}
418
Klement Sekera4c533132018-02-22 11:41:12 +0100419always_inline void
Klement Sekera896c8962019-06-24 11:52:49 +0000420ip6_full_reass_on_timeout (vlib_main_t * vm, vlib_node_runtime_t * node,
421 ip6_full_reass_main_t * rm,
422 ip6_full_reass_t * reass, u32 * icmp_bi)
Klement Sekera75e7d132017-09-20 08:26:30 +0200423{
424 if (~0 == reass->first_bi)
425 {
426 return;
427 }
Klement Sekerae8498652019-06-17 12:23:15 +0000428 if (~0 == reass->next_index) // custom apps don't want icmp
Klement Sekera75e7d132017-09-20 08:26:30 +0200429 {
Klement Sekera21aa8f12019-05-20 12:27:33 +0200430 vlib_buffer_t *b = vlib_get_buffer (vm, reass->first_bi);
431 if (0 == vnet_buffer (b)->ip.reass.fragment_first)
Klement Sekera75e7d132017-09-20 08:26:30 +0200432 {
Klement Sekera21aa8f12019-05-20 12:27:33 +0200433 *icmp_bi = reass->first_bi;
434 if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
435 {
Klement Sekera896c8962019-06-24 11:52:49 +0000436 ip6_full_reass_add_trace (vm, node, rm, reass, reass->first_bi,
437 ICMP_ERROR_RT_EXCEEDED, ~0);
Klement Sekera21aa8f12019-05-20 12:27:33 +0200438 }
439 // fragment with offset zero received - send icmp message back
440 if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
441 {
442 // separate first buffer from chain and steer it towards icmp node
443 b->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
444 reass->first_bi = b->next_buffer;
445 }
446 else
447 {
448 reass->first_bi = vnet_buffer (b)->ip.reass.next_range_bi;
449 }
450 icmp6_error_set_vnet_buffer (b, ICMP6_time_exceeded,
451 ICMP6_time_exceeded_fragment_reassembly_time_exceeded,
452 0);
Klement Sekera75e7d132017-09-20 08:26:30 +0200453 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200454 }
Klement Sekera896c8962019-06-24 11:52:49 +0000455 ip6_full_reass_drop_all (vm, node, rm, reass);
Klement Sekera75e7d132017-09-20 08:26:30 +0200456}
457
Klement Sekera896c8962019-06-24 11:52:49 +0000458always_inline ip6_full_reass_t *
459ip6_full_reass_find_or_create (vlib_main_t * vm, vlib_node_runtime_t * node,
460 ip6_full_reass_main_t * rm,
461 ip6_full_reass_per_thread_t * rt,
462 ip6_full_reass_kv_t * kv, u32 * icmp_bi,
463 u8 * do_handoff)
Klement Sekera75e7d132017-09-20 08:26:30 +0200464{
Klement Sekera896c8962019-06-24 11:52:49 +0000465 ip6_full_reass_t *reass;
Klement Sekera630ab582019-07-19 09:14:19 +0000466 f64 now;
467
468again:
469
470 reass = NULL;
471 now = vlib_time_now (vm);
Klement Sekera75e7d132017-09-20 08:26:30 +0200472
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800473 if (!clib_bihash_search_48_8
474 (&rm->hash, (clib_bihash_kv_48_8_t *) kv, (clib_bihash_kv_48_8_t *) kv))
Klement Sekera75e7d132017-09-20 08:26:30 +0200475 {
Klement Sekera630ab582019-07-19 09:14:19 +0000476 reass =
477 pool_elt_at_index (rm->per_thread_data
478 [kv->v.memory_owner_thread_index].pool,
479 kv->v.reass_index);
480 if (vm->thread_index != kv->v.memory_owner_thread_index)
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800481 {
482 *do_handoff = 1;
Klement Sekera630ab582019-07-19 09:14:19 +0000483 return reass;
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800484 }
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800485
Klement Sekera75e7d132017-09-20 08:26:30 +0200486 if (now > reass->last_heard + rm->timeout)
487 {
Klement Sekera896c8962019-06-24 11:52:49 +0000488 ip6_full_reass_on_timeout (vm, node, rm, reass, icmp_bi);
489 ip6_full_reass_free (rm, rt, reass);
Klement Sekera75e7d132017-09-20 08:26:30 +0200490 reass = NULL;
491 }
492 }
493
494 if (reass)
495 {
496 reass->last_heard = now;
497 return reass;
498 }
499
Klement Sekera4c533132018-02-22 11:41:12 +0100500 if (rt->reass_n >= rm->max_reass_n)
Klement Sekera75e7d132017-09-20 08:26:30 +0200501 {
502 reass = NULL;
503 return reass;
504 }
505 else
506 {
Klement Sekera4c533132018-02-22 11:41:12 +0100507 pool_get (rt->pool, reass);
Dave Barachb7b92992018-10-17 10:38:51 -0400508 clib_memset (reass, 0, sizeof (*reass));
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800509 reass->id = ((u64) vm->thread_index * 1000000000) + rt->id_counter;
Klement Sekera4c533132018-02-22 11:41:12 +0100510 ++rt->id_counter;
Klement Sekera75e7d132017-09-20 08:26:30 +0200511 reass->first_bi = ~0;
512 reass->last_packet_octet = ~0;
513 reass->data_len = 0;
Klement Sekerae8498652019-06-17 12:23:15 +0000514 reass->next_index = ~0;
515 reass->error_next_index = ~0;
Klement Sekera4c533132018-02-22 11:41:12 +0100516 ++rt->reass_n;
Klement Sekera75e7d132017-09-20 08:26:30 +0200517 }
518
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800519 reass->key.as_u64[0] = ((clib_bihash_kv_48_8_t *) kv)->key[0];
520 reass->key.as_u64[1] = ((clib_bihash_kv_48_8_t *) kv)->key[1];
521 reass->key.as_u64[2] = ((clib_bihash_kv_48_8_t *) kv)->key[2];
522 reass->key.as_u64[3] = ((clib_bihash_kv_48_8_t *) kv)->key[3];
523 reass->key.as_u64[4] = ((clib_bihash_kv_48_8_t *) kv)->key[4];
524 reass->key.as_u64[5] = ((clib_bihash_kv_48_8_t *) kv)->key[5];
525 kv->v.reass_index = (reass - rt->pool);
Klement Sekera630ab582019-07-19 09:14:19 +0000526 kv->v.memory_owner_thread_index = vm->thread_index;
Klement Sekera75e7d132017-09-20 08:26:30 +0200527 reass->last_heard = now;
528
Klement Sekera630ab582019-07-19 09:14:19 +0000529 int rv =
530 clib_bihash_add_del_48_8 (&rm->hash, (clib_bihash_kv_48_8_t *) kv, 2);
531 if (rv)
Klement Sekera75e7d132017-09-20 08:26:30 +0200532 {
Klement Sekera896c8962019-06-24 11:52:49 +0000533 ip6_full_reass_free (rm, rt, reass);
Klement Sekera75e7d132017-09-20 08:26:30 +0200534 reass = NULL;
Klement Sekera630ab582019-07-19 09:14:19 +0000535 // if other worker created a context already work with the other copy
536 if (-2 == rv)
537 goto again;
Klement Sekera75e7d132017-09-20 08:26:30 +0200538 }
539
540 return reass;
541}
542
Klement Sekera896c8962019-06-24 11:52:49 +0000543always_inline ip6_full_reass_rc_t
544ip6_full_reass_finalize (vlib_main_t * vm, vlib_node_runtime_t * node,
545 ip6_full_reass_main_t * rm,
546 ip6_full_reass_per_thread_t * rt,
547 ip6_full_reass_t * reass, u32 * bi0, u32 * next0,
548 u32 * error0, bool is_custom_app)
Klement Sekera75e7d132017-09-20 08:26:30 +0200549{
Klement Sekera75e7d132017-09-20 08:26:30 +0200550 *bi0 = reass->first_bi;
Klement Sekera75e7d132017-09-20 08:26:30 +0200551 *error0 = IP6_ERROR_NONE;
552 ip6_frag_hdr_t *frag_hdr;
553 vlib_buffer_t *last_b = NULL;
554 u32 sub_chain_bi = reass->first_bi;
555 u32 total_length = 0;
556 u32 buf_cnt = 0;
557 u32 dropped_cnt = 0;
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100558 u32 *vec_drop_compress = NULL;
Klement Sekera896c8962019-06-24 11:52:49 +0000559 ip6_full_reass_rc_t rv = IP6_FULL_REASS_RC_OK;
Klement Sekera75e7d132017-09-20 08:26:30 +0200560 do
561 {
562 u32 tmp_bi = sub_chain_bi;
563 vlib_buffer_t *tmp = vlib_get_buffer (vm, tmp_bi);
Klement Sekerad0f70a32018-12-14 17:24:13 +0100564 vnet_buffer_opaque_t *vnb = vnet_buffer (tmp);
565 if (!(vnb->ip.reass.range_first >= vnb->ip.reass.fragment_first) &&
566 !(vnb->ip.reass.range_last > vnb->ip.reass.fragment_first))
567 {
Klement Sekera896c8962019-06-24 11:52:49 +0000568 rv = IP6_FULL_REASS_RC_INTERNAL_ERROR;
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100569 goto free_buffers_and_return;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100570 }
571
Klement Sekera896c8962019-06-24 11:52:49 +0000572 u32 data_len = ip6_full_reass_buffer_get_data_len (tmp);
Klement Sekera75e7d132017-09-20 08:26:30 +0200573 u32 trim_front = vnet_buffer (tmp)->ip.reass.ip6_frag_hdr_offset +
Klement Sekera896c8962019-06-24 11:52:49 +0000574 sizeof (*frag_hdr) + ip6_full_reass_buffer_get_data_offset (tmp);
Klement Sekera75e7d132017-09-20 08:26:30 +0200575 u32 trim_end =
576 vlib_buffer_length_in_chain (vm, tmp) - trim_front - data_len;
577 if (tmp_bi == reass->first_bi)
578 {
579 /* first buffer - keep ip6 header */
Klement Sekera896c8962019-06-24 11:52:49 +0000580 if (0 != ip6_full_reass_buffer_get_data_offset (tmp))
Klement Sekerad0f70a32018-12-14 17:24:13 +0100581 {
Klement Sekera896c8962019-06-24 11:52:49 +0000582 rv = IP6_FULL_REASS_RC_INTERNAL_ERROR;
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100583 goto free_buffers_and_return;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100584 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200585 trim_front = 0;
586 trim_end = vlib_buffer_length_in_chain (vm, tmp) - data_len -
587 (vnet_buffer (tmp)->ip.reass.ip6_frag_hdr_offset +
588 sizeof (*frag_hdr));
Klement Sekerad0f70a32018-12-14 17:24:13 +0100589 if (!(vlib_buffer_length_in_chain (vm, tmp) - trim_end > 0))
590 {
Klement Sekera896c8962019-06-24 11:52:49 +0000591 rv = IP6_FULL_REASS_RC_INTERNAL_ERROR;
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100592 goto free_buffers_and_return;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100593 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200594 }
595 u32 keep_data =
596 vlib_buffer_length_in_chain (vm, tmp) - trim_front - trim_end;
597 while (1)
598 {
599 ++buf_cnt;
600 if (trim_front)
601 {
602 if (trim_front > tmp->current_length)
603 {
604 /* drop whole buffer */
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100605 vec_add1 (vec_drop_compress, tmp_bi);
Klement Sekera75e7d132017-09-20 08:26:30 +0200606 trim_front -= tmp->current_length;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100607 if (!(tmp->flags & VLIB_BUFFER_NEXT_PRESENT))
608 {
Klement Sekera896c8962019-06-24 11:52:49 +0000609 rv = IP6_FULL_REASS_RC_INTERNAL_ERROR;
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100610 goto free_buffers_and_return;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100611 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200612 tmp->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
613 tmp_bi = tmp->next_buffer;
614 tmp = vlib_get_buffer (vm, tmp_bi);
615 continue;
616 }
617 else
618 {
619 vlib_buffer_advance (tmp, trim_front);
620 trim_front = 0;
621 }
622 }
623 if (keep_data)
624 {
625 if (last_b)
626 {
627 last_b->flags |= VLIB_BUFFER_NEXT_PRESENT;
628 last_b->next_buffer = tmp_bi;
629 }
630 last_b = tmp;
631 if (keep_data <= tmp->current_length)
632 {
633 tmp->current_length = keep_data;
634 keep_data = 0;
635 }
636 else
637 {
638 keep_data -= tmp->current_length;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100639 if (!(tmp->flags & VLIB_BUFFER_NEXT_PRESENT))
640 {
Klement Sekera896c8962019-06-24 11:52:49 +0000641 rv = IP6_FULL_REASS_RC_INTERNAL_ERROR;
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100642 goto free_buffers_and_return;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100643 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200644 }
645 total_length += tmp->current_length;
646 }
647 else
648 {
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100649 vec_add1 (vec_drop_compress, tmp_bi);
Klement Sekerad0f70a32018-12-14 17:24:13 +0100650 if (reass->first_bi == tmp_bi)
651 {
Klement Sekera896c8962019-06-24 11:52:49 +0000652 rv = IP6_FULL_REASS_RC_INTERNAL_ERROR;
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100653 goto free_buffers_and_return;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100654 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200655 ++dropped_cnt;
656 }
657 if (tmp->flags & VLIB_BUFFER_NEXT_PRESENT)
658 {
659 tmp_bi = tmp->next_buffer;
660 tmp = vlib_get_buffer (vm, tmp->next_buffer);
661 }
662 else
663 {
664 break;
665 }
666 }
667 sub_chain_bi =
668 vnet_buffer (vlib_get_buffer (vm, sub_chain_bi))->ip.
669 reass.next_range_bi;
670 }
671 while (~0 != sub_chain_bi);
Chris Luke30684ac2018-03-29 12:56:58 -0700672
Klement Sekerad0f70a32018-12-14 17:24:13 +0100673 if (!last_b)
674 {
Klement Sekera896c8962019-06-24 11:52:49 +0000675 rv = IP6_FULL_REASS_RC_INTERNAL_ERROR;
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100676 goto free_buffers_and_return;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100677 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200678 last_b->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
679 vlib_buffer_t *first_b = vlib_get_buffer (vm, reass->first_bi);
Klement Sekerad0f70a32018-12-14 17:24:13 +0100680 if (total_length < first_b->current_length)
681 {
Klement Sekera896c8962019-06-24 11:52:49 +0000682 rv = IP6_FULL_REASS_RC_INTERNAL_ERROR;
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100683 goto free_buffers_and_return;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100684 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200685 total_length -= first_b->current_length;
686 first_b->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
687 first_b->total_length_not_including_first_buffer = total_length;
688 // drop fragment header
689 vnet_buffer_opaque_t *first_b_vnb = vnet_buffer (first_b);
690 ip6_header_t *ip = vlib_buffer_get_current (first_b);
691 u16 ip6_frag_hdr_offset = first_b_vnb->ip.reass.ip6_frag_hdr_offset;
692 ip6_ext_header_t *prev_hdr;
Klement Sekera769145c2019-03-06 11:59:57 +0100693 frag_hdr =
694 ip6_ext_header_find (vm, first_b, ip, IP_PROTOCOL_IPV6_FRAGMENTATION,
695 &prev_hdr);
Klement Sekera75e7d132017-09-20 08:26:30 +0200696 if (prev_hdr)
697 {
698 prev_hdr->next_hdr = frag_hdr->next_hdr;
699 }
700 else
701 {
702 ip->protocol = frag_hdr->next_hdr;
703 }
Klement Sekerad0f70a32018-12-14 17:24:13 +0100704 if (!((u8 *) frag_hdr - (u8 *) ip == ip6_frag_hdr_offset))
705 {
Klement Sekera896c8962019-06-24 11:52:49 +0000706 rv = IP6_FULL_REASS_RC_INTERNAL_ERROR;
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100707 goto free_buffers_and_return;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100708 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200709 memmove (frag_hdr, (u8 *) frag_hdr + sizeof (*frag_hdr),
710 first_b->current_length - ip6_frag_hdr_offset -
711 sizeof (ip6_frag_hdr_t));
712 first_b->current_length -= sizeof (*frag_hdr);
713 ip->payload_length =
714 clib_host_to_net_u16 (total_length + first_b->current_length -
715 sizeof (*ip));
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100716 if (!vlib_buffer_chain_linearize (vm, first_b))
717 {
Klement Sekera896c8962019-06-24 11:52:49 +0000718 rv = IP6_FULL_REASS_RC_NO_BUF;
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100719 goto free_buffers_and_return;
720 }
Vijayabhaskar Katamreddy90556d62019-05-23 13:02:28 -0700721 first_b->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
Klement Sekera75e7d132017-09-20 08:26:30 +0200722 if (PREDICT_FALSE (first_b->flags & VLIB_BUFFER_IS_TRACED))
723 {
Klement Sekera896c8962019-06-24 11:52:49 +0000724 ip6_full_reass_add_trace (vm, node, rm, reass, reass->first_bi,
725 FINALIZE, ~0);
Klement Sekera75e7d132017-09-20 08:26:30 +0200726#if 0
727 // following code does a hexdump of packet fragments to stdout ...
728 do
729 {
730 u32 bi = reass->first_bi;
731 u8 *s = NULL;
732 while (~0 != bi)
733 {
734 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
735 s = format (s, "%u: %U\n", bi, format_hexdump,
736 vlib_buffer_get_current (b), b->current_length);
737 if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
738 {
739 bi = b->next_buffer;
740 }
741 else
742 {
743 break;
744 }
745 }
746 printf ("%.*s\n", vec_len (s), s);
747 fflush (stdout);
748 vec_free (s);
749 }
750 while (0);
751#endif
752 }
Klement Sekerae8498652019-06-17 12:23:15 +0000753 if (!is_custom_app)
Klement Sekera4c533132018-02-22 11:41:12 +0100754 {
Klement Sekera896c8962019-06-24 11:52:49 +0000755 *next0 = IP6_FULL_REASSEMBLY_NEXT_INPUT;
Klement Sekera4c533132018-02-22 11:41:12 +0100756 }
757 else
758 {
759 *next0 = reass->next_index;
760 }
761 vnet_buffer (first_b)->ip.reass.estimated_mtu = reass->min_fragment_length;
Klement Sekera896c8962019-06-24 11:52:49 +0000762 ip6_full_reass_free (rm, rt, reass);
Klement Sekera75e7d132017-09-20 08:26:30 +0200763 reass = NULL;
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100764free_buffers_and_return:
765 vlib_buffer_free (vm, vec_drop_compress, vec_len (vec_drop_compress));
766 vec_free (vec_drop_compress);
767 return rv;
Klement Sekera75e7d132017-09-20 08:26:30 +0200768}
769
Klement Sekera4c533132018-02-22 11:41:12 +0100770always_inline void
Klement Sekera896c8962019-06-24 11:52:49 +0000771ip6_full_reass_insert_range_in_chain (vlib_main_t * vm,
772 ip6_full_reass_main_t * rm,
773 ip6_full_reass_per_thread_t * rt,
774 ip6_full_reass_t * reass,
775 u32 prev_range_bi, u32 new_next_bi)
Klement Sekera75e7d132017-09-20 08:26:30 +0200776{
777
778 vlib_buffer_t *new_next_b = vlib_get_buffer (vm, new_next_bi);
779 vnet_buffer_opaque_t *new_next_vnb = vnet_buffer (new_next_b);
780 if (~0 != prev_range_bi)
781 {
782 vlib_buffer_t *prev_b = vlib_get_buffer (vm, prev_range_bi);
783 vnet_buffer_opaque_t *prev_vnb = vnet_buffer (prev_b);
784 new_next_vnb->ip.reass.next_range_bi = prev_vnb->ip.reass.next_range_bi;
785 prev_vnb->ip.reass.next_range_bi = new_next_bi;
786 }
787 else
788 {
789 if (~0 != reass->first_bi)
790 {
791 new_next_vnb->ip.reass.next_range_bi = reass->first_bi;
792 }
793 reass->first_bi = new_next_bi;
794 }
Klement Sekera896c8962019-06-24 11:52:49 +0000795 reass->data_len += ip6_full_reass_buffer_get_data_len (new_next_b);
Klement Sekera75e7d132017-09-20 08:26:30 +0200796}
797
Klement Sekera896c8962019-06-24 11:52:49 +0000798always_inline ip6_full_reass_rc_t
799ip6_full_reass_update (vlib_main_t * vm, vlib_node_runtime_t * node,
800 ip6_full_reass_main_t * rm,
801 ip6_full_reass_per_thread_t * rt,
802 ip6_full_reass_t * reass, u32 * bi0, u32 * next0,
803 u32 * error0, ip6_frag_hdr_t * frag_hdr,
804 bool is_custom_app, u32 * handoff_thread_idx)
Klement Sekera75e7d132017-09-20 08:26:30 +0200805{
806 int consumed = 0;
807 vlib_buffer_t *fb = vlib_get_buffer (vm, *bi0);
808 vnet_buffer_opaque_t *fvnb = vnet_buffer (fb);
Klement Sekerae8498652019-06-17 12:23:15 +0000809 if (is_custom_app)
810 {
811 reass->next_index = fvnb->ip.reass.next_index; // store next_index before it's overwritten
812 reass->error_next_index = fvnb->ip.reass.error_next_index; // store error_next_index before it is overwritten
813 }
Klement Sekera21aa8f12019-05-20 12:27:33 +0200814
Klement Sekera75e7d132017-09-20 08:26:30 +0200815 fvnb->ip.reass.ip6_frag_hdr_offset =
816 (u8 *) frag_hdr - (u8 *) vlib_buffer_get_current (fb);
817 ip6_header_t *fip = vlib_buffer_get_current (fb);
Klement Sekerad0f70a32018-12-14 17:24:13 +0100818 if (fb->current_length < sizeof (*fip) ||
819 fvnb->ip.reass.ip6_frag_hdr_offset == 0 ||
820 fvnb->ip.reass.ip6_frag_hdr_offset >= fb->current_length)
821 {
Klement Sekera896c8962019-06-24 11:52:49 +0000822 return IP6_FULL_REASS_RC_INTERNAL_ERROR;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100823 }
824
Klement Sekera75e7d132017-09-20 08:26:30 +0200825 u32 fragment_first = fvnb->ip.reass.fragment_first =
826 ip6_frag_hdr_offset_bytes (frag_hdr);
827 u32 fragment_length =
828 vlib_buffer_length_in_chain (vm, fb) -
829 (fvnb->ip.reass.ip6_frag_hdr_offset + sizeof (*frag_hdr));
830 u32 fragment_last = fvnb->ip.reass.fragment_last =
831 fragment_first + fragment_length - 1;
832 int more_fragments = ip6_frag_hdr_more (frag_hdr);
833 u32 candidate_range_bi = reass->first_bi;
834 u32 prev_range_bi = ~0;
835 fvnb->ip.reass.range_first = fragment_first;
836 fvnb->ip.reass.range_last = fragment_last;
837 fvnb->ip.reass.next_range_bi = ~0;
Klement Sekera75e7d132017-09-20 08:26:30 +0200838 if (!more_fragments)
839 {
840 reass->last_packet_octet = fragment_last;
841 }
842 if (~0 == reass->first_bi)
843 {
844 // starting a new reassembly
Klement Sekera896c8962019-06-24 11:52:49 +0000845 ip6_full_reass_insert_range_in_chain (vm, rm, rt, reass, prev_range_bi,
846 *bi0);
Klement Sekera4c533132018-02-22 11:41:12 +0100847 reass->min_fragment_length = clib_net_to_host_u16 (fip->payload_length);
Klement Sekeraf1b4e522019-02-19 14:47:25 +0100848 consumed = 1;
Klement Sekera3a343d42019-05-16 14:35:46 +0200849 reass->fragments_n = 1;
Klement Sekeraf1b4e522019-02-19 14:47:25 +0100850 goto check_if_done_maybe;
Klement Sekera75e7d132017-09-20 08:26:30 +0200851 }
Klement Sekera4c533132018-02-22 11:41:12 +0100852 reass->min_fragment_length =
Klement Sekera75e7d132017-09-20 08:26:30 +0200853 clib_min (clib_net_to_host_u16 (fip->payload_length),
854 fvnb->ip.reass.estimated_mtu);
855 while (~0 != candidate_range_bi)
856 {
857 vlib_buffer_t *candidate_b = vlib_get_buffer (vm, candidate_range_bi);
858 vnet_buffer_opaque_t *candidate_vnb = vnet_buffer (candidate_b);
859 if (fragment_first > candidate_vnb->ip.reass.range_last)
860 {
861 // this fragments starts after candidate range
862 prev_range_bi = candidate_range_bi;
863 candidate_range_bi = candidate_vnb->ip.reass.next_range_bi;
864 if (candidate_vnb->ip.reass.range_last < fragment_last &&
865 ~0 == candidate_range_bi)
866 {
867 // special case - this fragment falls beyond all known ranges
Klement Sekera896c8962019-06-24 11:52:49 +0000868 ip6_full_reass_insert_range_in_chain (vm, rm, rt, reass,
869 prev_range_bi, *bi0);
Klement Sekera75e7d132017-09-20 08:26:30 +0200870 consumed = 1;
871 break;
872 }
873 continue;
874 }
875 if (fragment_last < candidate_vnb->ip.reass.range_first)
876 {
877 // this fragment ends before candidate range without any overlap
Klement Sekera896c8962019-06-24 11:52:49 +0000878 ip6_full_reass_insert_range_in_chain (vm, rm, rt, reass,
879 prev_range_bi, *bi0);
Klement Sekera75e7d132017-09-20 08:26:30 +0200880 consumed = 1;
881 }
882 else if (fragment_first == candidate_vnb->ip.reass.range_first &&
883 fragment_last == candidate_vnb->ip.reass.range_last)
884 {
885 // duplicate fragment - ignore
886 }
887 else
888 {
889 // overlapping fragment - not allowed by RFC 8200
Klement Sekera75e7d132017-09-20 08:26:30 +0200890 if (PREDICT_FALSE (fb->flags & VLIB_BUFFER_IS_TRACED))
891 {
Klement Sekera896c8962019-06-24 11:52:49 +0000892 ip6_full_reass_add_trace (vm, node, rm, reass, *bi0,
893 RANGE_OVERLAP, ~0);
Klement Sekera75e7d132017-09-20 08:26:30 +0200894 }
Benoît Ganne2d0ebd72019-07-19 13:42:12 +0200895 ip6_full_reass_drop_all (vm, node, rm, reass);
896 ip6_full_reass_free (rm, rt, reass);
Klement Sekera896c8962019-06-24 11:52:49 +0000897 *next0 = IP6_FULL_REASSEMBLY_NEXT_DROP;
Klement Sekera75e7d132017-09-20 08:26:30 +0200898 *error0 = IP6_ERROR_REASS_OVERLAPPING_FRAGMENT;
Klement Sekera896c8962019-06-24 11:52:49 +0000899 return IP6_FULL_REASS_RC_OK;
Klement Sekera75e7d132017-09-20 08:26:30 +0200900 }
901 break;
902 }
Klement Sekera3a343d42019-05-16 14:35:46 +0200903 ++reass->fragments_n;
Klement Sekeraf1b4e522019-02-19 14:47:25 +0100904check_if_done_maybe:
Klement Sekera75e7d132017-09-20 08:26:30 +0200905 if (consumed)
906 {
907 if (PREDICT_FALSE (fb->flags & VLIB_BUFFER_IS_TRACED))
908 {
Klement Sekera896c8962019-06-24 11:52:49 +0000909 ip6_full_reass_add_trace (vm, node, rm, reass, *bi0, RANGE_NEW, ~0);
Klement Sekera75e7d132017-09-20 08:26:30 +0200910 }
911 }
912 if (~0 != reass->last_packet_octet &&
913 reass->data_len == reass->last_packet_octet + 1)
914 {
Klement Sekera630ab582019-07-19 09:14:19 +0000915 *handoff_thread_idx = reass->sendout_thread_index;
Benoît Ganne2d0ebd72019-07-19 13:42:12 +0200916 int handoff =
917 reass->memory_owner_thread_index != reass->sendout_thread_index;
Klement Sekera896c8962019-06-24 11:52:49 +0000918 ip6_full_reass_rc_t rc =
919 ip6_full_reass_finalize (vm, node, rm, rt, reass, bi0, next0, error0,
920 is_custom_app);
Benoît Ganne2d0ebd72019-07-19 13:42:12 +0200921 if (IP6_FULL_REASS_RC_OK == rc && handoff)
Klement Sekera630ab582019-07-19 09:14:19 +0000922 {
Klement Sekera896c8962019-06-24 11:52:49 +0000923 return IP6_FULL_REASS_RC_HANDOFF;
Klement Sekera630ab582019-07-19 09:14:19 +0000924 }
925 return rc;
Klement Sekera75e7d132017-09-20 08:26:30 +0200926 }
927 else
928 {
929 if (consumed)
930 {
931 *bi0 = ~0;
Klement Sekera3a343d42019-05-16 14:35:46 +0200932 if (reass->fragments_n > rm->max_reass_len)
933 {
Klement Sekera896c8962019-06-24 11:52:49 +0000934 return IP6_FULL_REASS_RC_TOO_MANY_FRAGMENTS;
Klement Sekera3a343d42019-05-16 14:35:46 +0200935 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200936 }
937 else
938 {
Klement Sekera896c8962019-06-24 11:52:49 +0000939 *next0 = IP6_FULL_REASSEMBLY_NEXT_DROP;
Klement Sekera75e7d132017-09-20 08:26:30 +0200940 *error0 = IP6_ERROR_REASS_DUPLICATE_FRAGMENT;
941 }
942 }
Klement Sekera896c8962019-06-24 11:52:49 +0000943 return IP6_FULL_REASS_RC_OK;
Klement Sekera75e7d132017-09-20 08:26:30 +0200944}
945
Klement Sekera4c533132018-02-22 11:41:12 +0100946always_inline bool
Klement Sekera896c8962019-06-24 11:52:49 +0000947ip6_full_reass_verify_upper_layer_present (vlib_node_runtime_t * node,
948 vlib_buffer_t * b,
949 ip6_frag_hdr_t * frag_hdr)
Klement Sekera4c533132018-02-22 11:41:12 +0100950{
951 ip6_ext_header_t *tmp = (ip6_ext_header_t *) frag_hdr;
952 while (ip6_ext_hdr (tmp->next_hdr))
953 {
954 tmp = ip6_ext_next_header (tmp);
955 }
956 if (IP_PROTOCOL_IP6_NONXT == tmp->next_hdr)
957 {
958 icmp6_error_set_vnet_buffer (b, ICMP6_parameter_problem,
959 ICMP6_parameter_problem_first_fragment_has_incomplete_header_chain,
960 0);
961 b->error = node->errors[IP6_ERROR_REASS_MISSING_UPPER];
962
963 return false;
964 }
965 return true;
966}
967
968always_inline bool
Klement Sekera896c8962019-06-24 11:52:49 +0000969ip6_full_reass_verify_fragment_multiple_8 (vlib_main_t * vm,
970 vlib_node_runtime_t * node,
971 vlib_buffer_t * b,
972 ip6_frag_hdr_t * frag_hdr)
Klement Sekera4c533132018-02-22 11:41:12 +0100973{
974 vnet_buffer_opaque_t *vnb = vnet_buffer (b);
975 ip6_header_t *ip = vlib_buffer_get_current (b);
976 int more_fragments = ip6_frag_hdr_more (frag_hdr);
977 u32 fragment_length =
978 vlib_buffer_length_in_chain (vm, b) -
979 (vnb->ip.reass.ip6_frag_hdr_offset + sizeof (*frag_hdr));
980 if (more_fragments && 0 != fragment_length % 8)
981 {
982 icmp6_error_set_vnet_buffer (b, ICMP6_parameter_problem,
983 ICMP6_parameter_problem_erroneous_header_field,
984 (u8 *) & ip->payload_length - (u8 *) ip);
985 return false;
986 }
987 return true;
988}
989
990always_inline bool
Klement Sekera896c8962019-06-24 11:52:49 +0000991ip6_full_reass_verify_packet_size_lt_64k (vlib_main_t * vm,
992 vlib_node_runtime_t * node,
993 vlib_buffer_t * b,
994 ip6_frag_hdr_t * frag_hdr)
Klement Sekera4c533132018-02-22 11:41:12 +0100995{
996 vnet_buffer_opaque_t *vnb = vnet_buffer (b);
997 u32 fragment_first = ip6_frag_hdr_offset_bytes (frag_hdr);
998 u32 fragment_length =
999 vlib_buffer_length_in_chain (vm, b) -
1000 (vnb->ip.reass.ip6_frag_hdr_offset + sizeof (*frag_hdr));
1001 if (fragment_first + fragment_length > 65535)
1002 {
1003 ip6_header_t *ip0 = vlib_buffer_get_current (b);
1004 icmp6_error_set_vnet_buffer (b, ICMP6_parameter_problem,
1005 ICMP6_parameter_problem_erroneous_header_field,
1006 (u8 *) & frag_hdr->fragment_offset_and_more
1007 - (u8 *) ip0);
1008 return false;
1009 }
1010 return true;
1011}
1012
Klement Sekera75e7d132017-09-20 08:26:30 +02001013always_inline uword
Klement Sekera896c8962019-06-24 11:52:49 +00001014ip6_full_reassembly_inline (vlib_main_t * vm,
1015 vlib_node_runtime_t * node,
1016 vlib_frame_t * frame, bool is_feature,
1017 bool is_custom_app)
Klement Sekera75e7d132017-09-20 08:26:30 +02001018{
1019 u32 *from = vlib_frame_vector_args (frame);
1020 u32 n_left_from, n_left_to_next, *to_next, next_index;
Klement Sekera896c8962019-06-24 11:52:49 +00001021 ip6_full_reass_main_t *rm = &ip6_full_reass_main;
1022 ip6_full_reass_per_thread_t *rt = &rm->per_thread_data[vm->thread_index];
Klement Sekera4c533132018-02-22 11:41:12 +01001023 clib_spinlock_lock (&rt->lock);
Klement Sekera75e7d132017-09-20 08:26:30 +02001024
1025 n_left_from = frame->n_vectors;
1026 next_index = node->cached_next_index;
Klement Sekeraf883f6a2019-02-13 11:01:32 +01001027 while (n_left_from > 0)
Klement Sekera75e7d132017-09-20 08:26:30 +02001028 {
1029 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
1030
Klement Sekera75e7d132017-09-20 08:26:30 +02001031 while (n_left_from > 0 && n_left_to_next > 0)
1032 {
1033 u32 bi0;
1034 vlib_buffer_t *b0;
Klement Sekera896c8962019-06-24 11:52:49 +00001035 u32 next0 = IP6_FULL_REASSEMBLY_NEXT_DROP;
Klement Sekera4c533132018-02-22 11:41:12 +01001036 u32 error0 = IP6_ERROR_NONE;
1037 u32 icmp_bi = ~0;
Klement Sekera75e7d132017-09-20 08:26:30 +02001038
1039 bi0 = from[0];
1040 b0 = vlib_get_buffer (vm, bi0);
1041
1042 ip6_header_t *ip0 = vlib_buffer_get_current (b0);
Klement Sekera3ecc2212018-03-27 10:34:43 +02001043 ip6_frag_hdr_t *frag_hdr = NULL;
Klement Sekera75e7d132017-09-20 08:26:30 +02001044 ip6_ext_header_t *prev_hdr;
Klement Sekera3ecc2212018-03-27 10:34:43 +02001045 if (ip6_ext_hdr (ip0->protocol))
1046 {
Klement Sekera769145c2019-03-06 11:59:57 +01001047 frag_hdr =
1048 ip6_ext_header_find (vm, b0, ip0,
1049 IP_PROTOCOL_IPV6_FRAGMENTATION,
1050 &prev_hdr);
Klement Sekera3ecc2212018-03-27 10:34:43 +02001051 }
Klement Sekera4c533132018-02-22 11:41:12 +01001052 if (!frag_hdr)
1053 {
1054 // this is a regular packet - no fragmentation
Klement Sekera896c8962019-06-24 11:52:49 +00001055 next0 = IP6_FULL_REASSEMBLY_NEXT_INPUT;
Klement Sekera4c533132018-02-22 11:41:12 +01001056 goto skip_reass;
1057 }
Klement Sekera75e7d132017-09-20 08:26:30 +02001058 if (0 == ip6_frag_hdr_offset (frag_hdr))
1059 {
1060 // first fragment - verify upper-layer is present
Klement Sekera896c8962019-06-24 11:52:49 +00001061 if (!ip6_full_reass_verify_upper_layer_present
1062 (node, b0, frag_hdr))
Klement Sekera75e7d132017-09-20 08:26:30 +02001063 {
Klement Sekera896c8962019-06-24 11:52:49 +00001064 next0 = IP6_FULL_REASSEMBLY_NEXT_ICMP_ERROR;
Klement Sekera4c533132018-02-22 11:41:12 +01001065 goto skip_reass;
Klement Sekera75e7d132017-09-20 08:26:30 +02001066 }
Klement Sekera4c533132018-02-22 11:41:12 +01001067 }
Klement Sekera896c8962019-06-24 11:52:49 +00001068 if (!ip6_full_reass_verify_fragment_multiple_8
1069 (vm, node, b0, frag_hdr)
1070 || !ip6_full_reass_verify_packet_size_lt_64k (vm, node, b0,
1071 frag_hdr))
Klement Sekera4c533132018-02-22 11:41:12 +01001072 {
Klement Sekera896c8962019-06-24 11:52:49 +00001073 next0 = IP6_FULL_REASSEMBLY_NEXT_ICMP_ERROR;
Klement Sekera4c533132018-02-22 11:41:12 +01001074 goto skip_reass;
Klement Sekera75e7d132017-09-20 08:26:30 +02001075 }
1076 vnet_buffer (b0)->ip.reass.ip6_frag_hdr_offset =
1077 (u8 *) frag_hdr - (u8 *) ip0;
1078
Klement Sekera896c8962019-06-24 11:52:49 +00001079 ip6_full_reass_kv_t kv;
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001080 u8 do_handoff = 0;
Klement Sekera75e7d132017-09-20 08:26:30 +02001081
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001082 kv.k.as_u64[0] = ip0->src_address.as_u64[0];
1083 kv.k.as_u64[1] = ip0->src_address.as_u64[1];
1084 kv.k.as_u64[2] = ip0->dst_address.as_u64[0];
1085 kv.k.as_u64[3] = ip0->dst_address.as_u64[1];
1086 kv.k.as_u64[4] =
1087 ((u64) vec_elt (ip6_main.fib_index_by_sw_if_index,
1088 vnet_buffer (b0)->sw_if_index[VLIB_RX])) << 32 |
1089 (u64) frag_hdr->identification;
1090 kv.k.as_u64[5] = ip0->protocol;
1091
Klement Sekera896c8962019-06-24 11:52:49 +00001092 ip6_full_reass_t *reass =
1093 ip6_full_reass_find_or_create (vm, node, rm, rt, &kv, &icmp_bi,
1094 &do_handoff);
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001095
Klement Sekera630ab582019-07-19 09:14:19 +00001096 if (reass)
1097 {
1098 const u32 fragment_first = ip6_frag_hdr_offset (frag_hdr);
1099 if (0 == fragment_first)
1100 {
1101 reass->sendout_thread_index = vm->thread_index;
1102 }
1103 }
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001104 if (PREDICT_FALSE (do_handoff))
1105 {
Klement Sekera896c8962019-06-24 11:52:49 +00001106 next0 = IP6_FULL_REASSEMBLY_NEXT_HANDOFF;
Klement Sekerade34c352019-06-25 11:19:22 +00001107 vnet_buffer (b0)->ip.reass.owner_thread_index =
1108 kv.v.memory_owner_thread_index;
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001109 }
1110 else if (reass)
Klement Sekera75e7d132017-09-20 08:26:30 +02001111 {
Klement Sekera630ab582019-07-19 09:14:19 +00001112 u32 handoff_thread_idx;
Klement Sekera896c8962019-06-24 11:52:49 +00001113 switch (ip6_full_reass_update
1114 (vm, node, rm, rt, reass, &bi0, &next0, &error0,
1115 frag_hdr, is_custom_app, &handoff_thread_idx))
Klement Sekerad0f70a32018-12-14 17:24:13 +01001116 {
Klement Sekera896c8962019-06-24 11:52:49 +00001117 case IP6_FULL_REASS_RC_OK:
Klement Sekerad0f70a32018-12-14 17:24:13 +01001118 /* nothing to do here */
1119 break;
Klement Sekera896c8962019-06-24 11:52:49 +00001120 case IP6_FULL_REASS_RC_HANDOFF:
1121 next0 = IP6_FULL_REASSEMBLY_NEXT_HANDOFF;
Klement Sekera630ab582019-07-19 09:14:19 +00001122 b0 = vlib_get_buffer (vm, bi0);
Klement Sekerade34c352019-06-25 11:19:22 +00001123 vnet_buffer (b0)->ip.reass.owner_thread_index =
1124 handoff_thread_idx;
Klement Sekera630ab582019-07-19 09:14:19 +00001125 break;
Klement Sekera896c8962019-06-24 11:52:49 +00001126 case IP6_FULL_REASS_RC_TOO_MANY_FRAGMENTS:
Klement Sekera3a343d42019-05-16 14:35:46 +02001127 vlib_node_increment_counter (vm, node->node_index,
1128 IP6_ERROR_REASS_FRAGMENT_CHAIN_TOO_LONG,
1129 1);
Klement Sekera896c8962019-06-24 11:52:49 +00001130 ip6_full_reass_drop_all (vm, node, rm, reass);
1131 ip6_full_reass_free (rm, rt, reass);
Klement Sekera3a343d42019-05-16 14:35:46 +02001132 goto next_packet;
1133 break;
Klement Sekera896c8962019-06-24 11:52:49 +00001134 case IP6_FULL_REASS_RC_NO_BUF:
Klement Sekera3a343d42019-05-16 14:35:46 +02001135 vlib_node_increment_counter (vm, node->node_index,
1136 IP6_ERROR_REASS_NO_BUF, 1);
Klement Sekera896c8962019-06-24 11:52:49 +00001137 ip6_full_reass_drop_all (vm, node, rm, reass);
1138 ip6_full_reass_free (rm, rt, reass);
Klement Sekera3a343d42019-05-16 14:35:46 +02001139 goto next_packet;
1140 break;
Klement Sekera896c8962019-06-24 11:52:49 +00001141 case IP6_FULL_REASS_RC_INTERNAL_ERROR:
Klement Sekera3a343d42019-05-16 14:35:46 +02001142 vlib_node_increment_counter (vm, node->node_index,
1143 IP6_ERROR_REASS_INTERNAL_ERROR,
1144 1);
Klement Sekera896c8962019-06-24 11:52:49 +00001145 ip6_full_reass_drop_all (vm, node, rm, reass);
1146 ip6_full_reass_free (rm, rt, reass);
Klement Sekerad0f70a32018-12-14 17:24:13 +01001147 goto next_packet;
1148 break;
1149 }
Klement Sekera75e7d132017-09-20 08:26:30 +02001150 }
1151 else
1152 {
Klement Sekera21aa8f12019-05-20 12:27:33 +02001153 if (is_feature)
1154 {
Klement Sekera896c8962019-06-24 11:52:49 +00001155 next0 = IP6_FULL_REASSEMBLY_NEXT_DROP;
Klement Sekera21aa8f12019-05-20 12:27:33 +02001156 }
1157 else
1158 {
1159 vnet_buffer_opaque_t *fvnb = vnet_buffer (b0);
1160 next0 = fvnb->ip.reass.error_next_index;
1161 }
Klement Sekera75e7d132017-09-20 08:26:30 +02001162 error0 = IP6_ERROR_REASS_LIMIT_REACHED;
1163 }
1164
1165 b0->error = node->errors[error0];
1166
1167 if (~0 != bi0)
1168 {
Klement Sekera4c533132018-02-22 11:41:12 +01001169 skip_reass:
Klement Sekera75e7d132017-09-20 08:26:30 +02001170 to_next[0] = bi0;
1171 to_next += 1;
1172 n_left_to_next -= 1;
Klement Sekera896c8962019-06-24 11:52:49 +00001173 if (next0 == IP6_FULL_REASSEMBLY_NEXT_HANDOFF)
Klement Sekera630ab582019-07-19 09:14:19 +00001174 {
1175 if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
1176 {
Klement Sekerade34c352019-06-25 11:19:22 +00001177 ip6_full_reass_add_trace (vm, node, rm, NULL, bi0,
1178 HANDOFF,
1179 vnet_buffer (b0)->ip.
1180 reass.owner_thread_index);
Klement Sekera630ab582019-07-19 09:14:19 +00001181 }
1182 }
1183 else if (is_feature && IP6_ERROR_NONE == error0)
Klement Sekera4c533132018-02-22 11:41:12 +01001184 {
Kingwel Xiea0060652018-09-26 04:59:52 -04001185 b0 = vlib_get_buffer (vm, bi0);
Damjan Marion7d98a122018-07-19 20:42:08 +02001186 vnet_feature_next (&next0, b0);
Klement Sekera4c533132018-02-22 11:41:12 +01001187 }
Klement Sekera75e7d132017-09-20 08:26:30 +02001188 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1189 n_left_to_next, bi0, next0);
1190 }
1191
1192 if (~0 != icmp_bi)
1193 {
Klement Sekera896c8962019-06-24 11:52:49 +00001194 next0 = IP6_FULL_REASSEMBLY_NEXT_ICMP_ERROR;
Klement Sekera75e7d132017-09-20 08:26:30 +02001195 to_next[0] = icmp_bi;
1196 to_next += 1;
1197 n_left_to_next -= 1;
1198 vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
1199 n_left_to_next, icmp_bi,
1200 next0);
1201 }
Klement Sekerad0f70a32018-12-14 17:24:13 +01001202 next_packet:
Klement Sekera75e7d132017-09-20 08:26:30 +02001203 from += 1;
1204 n_left_from -= 1;
1205 }
1206
1207 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1208 }
1209
Klement Sekera4c533132018-02-22 11:41:12 +01001210 clib_spinlock_unlock (&rt->lock);
Klement Sekera75e7d132017-09-20 08:26:30 +02001211 return frame->n_vectors;
1212}
1213
Klement Sekera896c8962019-06-24 11:52:49 +00001214static char *ip6_full_reassembly_error_strings[] = {
Klement Sekera75e7d132017-09-20 08:26:30 +02001215#define _(sym, string) string,
1216 foreach_ip6_error
1217#undef _
1218};
1219
Klement Sekera896c8962019-06-24 11:52:49 +00001220VLIB_NODE_FN (ip6_full_reass_node) (vlib_main_t * vm,
1221 vlib_node_runtime_t * node,
1222 vlib_frame_t * frame)
Klement Sekera4c533132018-02-22 11:41:12 +01001223{
Klement Sekera896c8962019-06-24 11:52:49 +00001224 return ip6_full_reassembly_inline (vm, node, frame, false /* is_feature */ ,
1225 false /* is_custom_app */ );
Klement Sekera4c533132018-02-22 11:41:12 +01001226}
1227
Klement Sekera75e7d132017-09-20 08:26:30 +02001228/* *INDENT-OFF* */
Klement Sekera896c8962019-06-24 11:52:49 +00001229VLIB_REGISTER_NODE (ip6_full_reass_node) = {
1230 .name = "ip6-full-reassembly",
Klement Sekera75e7d132017-09-20 08:26:30 +02001231 .vector_size = sizeof (u32),
Klement Sekera896c8962019-06-24 11:52:49 +00001232 .format_trace = format_ip6_full_reass_trace,
1233 .n_errors = ARRAY_LEN (ip6_full_reassembly_error_strings),
1234 .error_strings = ip6_full_reassembly_error_strings,
1235 .n_next_nodes = IP6_FULL_REASSEMBLY_N_NEXT,
Klement Sekera75e7d132017-09-20 08:26:30 +02001236 .next_nodes =
1237 {
Klement Sekera896c8962019-06-24 11:52:49 +00001238 [IP6_FULL_REASSEMBLY_NEXT_INPUT] = "ip6-input",
1239 [IP6_FULL_REASSEMBLY_NEXT_DROP] = "ip6-drop",
1240 [IP6_FULL_REASSEMBLY_NEXT_ICMP_ERROR] = "ip6-icmp-error",
1241 [IP6_FULL_REASSEMBLY_NEXT_HANDOFF] = "ip6-full-reassembly-handoff",
Klement Sekera75e7d132017-09-20 08:26:30 +02001242 },
1243};
1244/* *INDENT-ON* */
1245
Klement Sekera896c8962019-06-24 11:52:49 +00001246VLIB_NODE_FN (ip6_full_reass_node_feature) (vlib_main_t * vm,
1247 vlib_node_runtime_t * node,
1248 vlib_frame_t * frame)
Klement Sekera4c533132018-02-22 11:41:12 +01001249{
Klement Sekera896c8962019-06-24 11:52:49 +00001250 return ip6_full_reassembly_inline (vm, node, frame, true /* is_feature */ ,
1251 false /* is_custom_app */ );
Klement Sekera4c533132018-02-22 11:41:12 +01001252}
1253
1254/* *INDENT-OFF* */
Klement Sekera896c8962019-06-24 11:52:49 +00001255VLIB_REGISTER_NODE (ip6_full_reass_node_feature) = {
1256 .name = "ip6-full-reassembly-feature",
Klement Sekera4c533132018-02-22 11:41:12 +01001257 .vector_size = sizeof (u32),
Klement Sekera896c8962019-06-24 11:52:49 +00001258 .format_trace = format_ip6_full_reass_trace,
1259 .n_errors = ARRAY_LEN (ip6_full_reassembly_error_strings),
1260 .error_strings = ip6_full_reassembly_error_strings,
1261 .n_next_nodes = IP6_FULL_REASSEMBLY_N_NEXT,
Klement Sekera4c533132018-02-22 11:41:12 +01001262 .next_nodes =
1263 {
Klement Sekera896c8962019-06-24 11:52:49 +00001264 [IP6_FULL_REASSEMBLY_NEXT_INPUT] = "ip6-input",
1265 [IP6_FULL_REASSEMBLY_NEXT_DROP] = "ip6-drop",
1266 [IP6_FULL_REASSEMBLY_NEXT_ICMP_ERROR] = "ip6-icmp-error",
1267 [IP6_FULL_REASSEMBLY_NEXT_HANDOFF] = "ip6-full-reass-feature-hoff",
Klement Sekera4c533132018-02-22 11:41:12 +01001268 },
1269};
1270/* *INDENT-ON* */
1271
Klement Sekera4c533132018-02-22 11:41:12 +01001272/* *INDENT-OFF* */
Klement Sekera896c8962019-06-24 11:52:49 +00001273VNET_FEATURE_INIT (ip6_full_reassembly_feature, static) = {
Klement Sekera4c533132018-02-22 11:41:12 +01001274 .arc_name = "ip6-unicast",
Klement Sekera896c8962019-06-24 11:52:49 +00001275 .node_name = "ip6-full-reassembly-feature",
Neale Ranns14046982019-07-29 14:49:52 +00001276 .runs_before = VNET_FEATURES ("ip6-lookup",
Neale Ranns2be3eb62019-08-02 01:17:13 -07001277 "ipsec6-input-feature"),
Klement Sekera4c533132018-02-22 11:41:12 +01001278 .runs_after = 0,
1279};
1280/* *INDENT-ON* */
1281
Filip Tehlar26ea14e2019-03-11 05:30:21 -07001282#ifndef CLIB_MARCH_VARIANT
Klement Sekera4c533132018-02-22 11:41:12 +01001283static u32
Klement Sekera896c8962019-06-24 11:52:49 +00001284ip6_full_reass_get_nbuckets ()
Klement Sekera75e7d132017-09-20 08:26:30 +02001285{
Klement Sekera896c8962019-06-24 11:52:49 +00001286 ip6_full_reass_main_t *rm = &ip6_full_reass_main;
Klement Sekera75e7d132017-09-20 08:26:30 +02001287 u32 nbuckets;
1288 u8 i;
1289
Klement Sekera896c8962019-06-24 11:52:49 +00001290 nbuckets = (u32) (rm->max_reass_n / IP6_FULL_REASS_HT_LOAD_FACTOR);
Klement Sekera75e7d132017-09-20 08:26:30 +02001291
1292 for (i = 0; i < 31; i++)
1293 if ((1 << i) >= nbuckets)
1294 break;
1295 nbuckets = 1 << i;
1296
1297 return nbuckets;
1298}
Filip Tehlar26ea14e2019-03-11 05:30:21 -07001299#endif /* CLIB_MARCH_VARIANT */
Klement Sekera75e7d132017-09-20 08:26:30 +02001300
1301typedef enum
1302{
1303 IP6_EVENT_CONFIG_CHANGED = 1,
Klement Sekera896c8962019-06-24 11:52:49 +00001304} ip6_full_reass_event_t;
Klement Sekera75e7d132017-09-20 08:26:30 +02001305
Filip Tehlar26ea14e2019-03-11 05:30:21 -07001306#ifndef CLIB_MARCH_VARIANT
Klement Sekera75e7d132017-09-20 08:26:30 +02001307typedef struct
1308{
1309 int failure;
1310 clib_bihash_48_8_t *new_hash;
1311} ip6_rehash_cb_ctx;
1312
Klement Sekera4c533132018-02-22 11:41:12 +01001313static void
Klement Sekera75e7d132017-09-20 08:26:30 +02001314ip6_rehash_cb (clib_bihash_kv_48_8_t * kv, void *_ctx)
1315{
1316 ip6_rehash_cb_ctx *ctx = _ctx;
1317 if (clib_bihash_add_del_48_8 (ctx->new_hash, kv, 1))
1318 {
1319 ctx->failure = 1;
1320 }
1321}
1322
Klement Sekera4c533132018-02-22 11:41:12 +01001323static void
Klement Sekera896c8962019-06-24 11:52:49 +00001324ip6_full_reass_set_params (u32 timeout_ms, u32 max_reassemblies,
1325 u32 max_reassembly_length,
1326 u32 expire_walk_interval_ms)
Klement Sekera4c533132018-02-22 11:41:12 +01001327{
Klement Sekera896c8962019-06-24 11:52:49 +00001328 ip6_full_reass_main.timeout_ms = timeout_ms;
1329 ip6_full_reass_main.timeout = (f64) timeout_ms / (f64) MSEC_PER_SEC;
1330 ip6_full_reass_main.max_reass_n = max_reassemblies;
1331 ip6_full_reass_main.max_reass_len = max_reassembly_length;
1332 ip6_full_reass_main.expire_walk_interval_ms = expire_walk_interval_ms;
Klement Sekera4c533132018-02-22 11:41:12 +01001333}
1334
Klement Sekera75e7d132017-09-20 08:26:30 +02001335vnet_api_error_t
Klement Sekera896c8962019-06-24 11:52:49 +00001336ip6_full_reass_set (u32 timeout_ms, u32 max_reassemblies,
1337 u32 max_reassembly_length, u32 expire_walk_interval_ms)
Klement Sekera75e7d132017-09-20 08:26:30 +02001338{
Klement Sekera896c8962019-06-24 11:52:49 +00001339 u32 old_nbuckets = ip6_full_reass_get_nbuckets ();
1340 ip6_full_reass_set_params (timeout_ms, max_reassemblies,
1341 max_reassembly_length, expire_walk_interval_ms);
1342 vlib_process_signal_event (ip6_full_reass_main.vlib_main,
1343 ip6_full_reass_main.ip6_full_reass_expire_node_idx,
Klement Sekera75e7d132017-09-20 08:26:30 +02001344 IP6_EVENT_CONFIG_CHANGED, 0);
Klement Sekera896c8962019-06-24 11:52:49 +00001345 u32 new_nbuckets = ip6_full_reass_get_nbuckets ();
1346 if (ip6_full_reass_main.max_reass_n > 0 && new_nbuckets > old_nbuckets)
Klement Sekera75e7d132017-09-20 08:26:30 +02001347 {
1348 clib_bihash_48_8_t new_hash;
Dave Barachb7b92992018-10-17 10:38:51 -04001349 clib_memset (&new_hash, 0, sizeof (new_hash));
Klement Sekera75e7d132017-09-20 08:26:30 +02001350 ip6_rehash_cb_ctx ctx;
1351 ctx.failure = 0;
1352 ctx.new_hash = &new_hash;
Klement Sekera896c8962019-06-24 11:52:49 +00001353 clib_bihash_init_48_8 (&new_hash, "ip6-full-reass", new_nbuckets,
Klement Sekera75e7d132017-09-20 08:26:30 +02001354 new_nbuckets * 1024);
Klement Sekera896c8962019-06-24 11:52:49 +00001355 clib_bihash_foreach_key_value_pair_48_8 (&ip6_full_reass_main.hash,
Klement Sekera75e7d132017-09-20 08:26:30 +02001356 ip6_rehash_cb, &ctx);
1357 if (ctx.failure)
1358 {
1359 clib_bihash_free_48_8 (&new_hash);
1360 return -1;
1361 }
1362 else
1363 {
Klement Sekera896c8962019-06-24 11:52:49 +00001364 clib_bihash_free_48_8 (&ip6_full_reass_main.hash);
1365 clib_memcpy_fast (&ip6_full_reass_main.hash, &new_hash,
1366 sizeof (ip6_full_reass_main.hash));
1367 clib_bihash_copied (&ip6_full_reass_main.hash, &new_hash);
Klement Sekera75e7d132017-09-20 08:26:30 +02001368 }
1369 }
1370 return 0;
1371}
1372
1373vnet_api_error_t
Klement Sekera896c8962019-06-24 11:52:49 +00001374ip6_full_reass_get (u32 * timeout_ms, u32 * max_reassemblies,
1375 u32 * max_reassembly_length,
1376 u32 * expire_walk_interval_ms)
Klement Sekera75e7d132017-09-20 08:26:30 +02001377{
Klement Sekera896c8962019-06-24 11:52:49 +00001378 *timeout_ms = ip6_full_reass_main.timeout_ms;
1379 *max_reassemblies = ip6_full_reass_main.max_reass_n;
1380 *max_reassembly_length = ip6_full_reass_main.max_reass_len;
1381 *expire_walk_interval_ms = ip6_full_reass_main.expire_walk_interval_ms;
Klement Sekera75e7d132017-09-20 08:26:30 +02001382 return 0;
1383}
1384
Klement Sekera4c533132018-02-22 11:41:12 +01001385static clib_error_t *
Klement Sekera896c8962019-06-24 11:52:49 +00001386ip6_full_reass_init_function (vlib_main_t * vm)
Klement Sekera75e7d132017-09-20 08:26:30 +02001387{
Klement Sekera896c8962019-06-24 11:52:49 +00001388 ip6_full_reass_main_t *rm = &ip6_full_reass_main;
Klement Sekera75e7d132017-09-20 08:26:30 +02001389 clib_error_t *error = 0;
1390 u32 nbuckets;
Dave Barach1403fcd2018-02-05 09:45:43 -05001391 vlib_node_t *node;
Klement Sekera75e7d132017-09-20 08:26:30 +02001392
1393 rm->vlib_main = vm;
Klement Sekera75e7d132017-09-20 08:26:30 +02001394
Juraj Slobodacd806922018-10-10 10:15:54 +02001395 vec_validate (rm->per_thread_data, vlib_num_workers ());
Klement Sekera896c8962019-06-24 11:52:49 +00001396 ip6_full_reass_per_thread_t *rt;
Klement Sekera4c533132018-02-22 11:41:12 +01001397 vec_foreach (rt, rm->per_thread_data)
1398 {
1399 clib_spinlock_init (&rt->lock);
1400 pool_alloc (rt->pool, rm->max_reass_n);
1401 }
Dave Barach1403fcd2018-02-05 09:45:43 -05001402
Klement Sekera896c8962019-06-24 11:52:49 +00001403 node = vlib_get_node_by_name (vm, (u8 *) "ip6-full-reassembly-expire-walk");
Dave Barach1403fcd2018-02-05 09:45:43 -05001404 ASSERT (node);
Klement Sekera896c8962019-06-24 11:52:49 +00001405 rm->ip6_full_reass_expire_node_idx = node->index;
Dave Barach1403fcd2018-02-05 09:45:43 -05001406
Klement Sekera896c8962019-06-24 11:52:49 +00001407 ip6_full_reass_set_params (IP6_FULL_REASS_TIMEOUT_DEFAULT_MS,
1408 IP6_FULL_REASS_MAX_REASSEMBLIES_DEFAULT,
1409 IP6_FULL_REASS_MAX_REASSEMBLY_LENGTH_DEFAULT,
1410 IP6_FULL_REASS_EXPIRE_WALK_INTERVAL_DEFAULT_MS);
Klement Sekera3ecc2212018-03-27 10:34:43 +02001411
Klement Sekera896c8962019-06-24 11:52:49 +00001412 nbuckets = ip6_full_reass_get_nbuckets ();
1413 clib_bihash_init_48_8 (&rm->hash, "ip6-full-reass", nbuckets,
1414 nbuckets * 1024);
Klement Sekera75e7d132017-09-20 08:26:30 +02001415
Dave Barach1403fcd2018-02-05 09:45:43 -05001416 node = vlib_get_node_by_name (vm, (u8 *) "ip6-drop");
Klement Sekera75e7d132017-09-20 08:26:30 +02001417 ASSERT (node);
1418 rm->ip6_drop_idx = node->index;
Klement Sekera75e7d132017-09-20 08:26:30 +02001419 node = vlib_get_node_by_name (vm, (u8 *) "ip6-icmp-error");
1420 ASSERT (node);
1421 rm->ip6_icmp_error_idx = node->index;
1422
1423 if ((error = vlib_call_init_function (vm, ip_main_init)))
1424 return error;
1425 ip6_register_protocol (IP_PROTOCOL_IPV6_FRAGMENTATION,
Klement Sekera896c8962019-06-24 11:52:49 +00001426 ip6_full_reass_node.index);
Klement Sekera4c533132018-02-22 11:41:12 +01001427
Klement Sekera896c8962019-06-24 11:52:49 +00001428 rm->fq_index = vlib_frame_queue_main_init (ip6_full_reass_node.index, 0);
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001429 rm->fq_feature_index =
Klement Sekera896c8962019-06-24 11:52:49 +00001430 vlib_frame_queue_main_init (ip6_full_reass_node_feature.index, 0);
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001431
Klement Sekera7b2e9fb2019-10-01 13:00:22 +00001432 rm->feature_use_refcount_per_intf = NULL;
Klement Sekera75e7d132017-09-20 08:26:30 +02001433 return error;
1434}
1435
Klement Sekera896c8962019-06-24 11:52:49 +00001436VLIB_INIT_FUNCTION (ip6_full_reass_init_function);
Filip Tehlar26ea14e2019-03-11 05:30:21 -07001437#endif /* CLIB_MARCH_VARIANT */
Klement Sekera75e7d132017-09-20 08:26:30 +02001438
1439static uword
Klement Sekera896c8962019-06-24 11:52:49 +00001440ip6_full_reass_walk_expired (vlib_main_t * vm,
1441 vlib_node_runtime_t * node, vlib_frame_t * f)
Klement Sekera75e7d132017-09-20 08:26:30 +02001442{
Klement Sekera896c8962019-06-24 11:52:49 +00001443 ip6_full_reass_main_t *rm = &ip6_full_reass_main;
Klement Sekera75e7d132017-09-20 08:26:30 +02001444 uword event_type, *event_data = 0;
1445
1446 while (true)
1447 {
1448 vlib_process_wait_for_event_or_clock (vm,
1449 (f64) rm->expire_walk_interval_ms
1450 / (f64) MSEC_PER_SEC);
1451 event_type = vlib_process_get_events (vm, &event_data);
1452
1453 switch (event_type)
1454 {
1455 case ~0: /* no events => timeout */
1456 /* nothing to do here */
1457 break;
1458 case IP6_EVENT_CONFIG_CHANGED:
1459 break;
1460 default:
1461 clib_warning ("BUG: event type 0x%wx", event_type);
1462 break;
1463 }
1464 f64 now = vlib_time_now (vm);
1465
Klement Sekera896c8962019-06-24 11:52:49 +00001466 ip6_full_reass_t *reass;
Klement Sekera75e7d132017-09-20 08:26:30 +02001467 int *pool_indexes_to_free = NULL;
1468
Klement Sekera4c533132018-02-22 11:41:12 +01001469 uword thread_index = 0;
Klement Sekera75e7d132017-09-20 08:26:30 +02001470 int index;
Juraj Slobodacd806922018-10-10 10:15:54 +02001471 const uword nthreads = vlib_num_workers () + 1;
Klement Sekera75e7d132017-09-20 08:26:30 +02001472 u32 *vec_icmp_bi = NULL;
Klement Sekera4c533132018-02-22 11:41:12 +01001473 for (thread_index = 0; thread_index < nthreads; ++thread_index)
1474 {
Klement Sekera896c8962019-06-24 11:52:49 +00001475 ip6_full_reass_per_thread_t *rt =
1476 &rm->per_thread_data[thread_index];
Klement Sekera4c533132018-02-22 11:41:12 +01001477 clib_spinlock_lock (&rt->lock);
1478
1479 vec_reset_length (pool_indexes_to_free);
1480 /* *INDENT-OFF* */
1481 pool_foreach_index (index, rt->pool, ({
1482 reass = pool_elt_at_index (rt->pool, index);
1483 if (now > reass->last_heard + rm->timeout)
1484 {
1485 vec_add1 (pool_indexes_to_free, index);
1486 }
1487 }));
1488 /* *INDENT-ON* */
1489 int *i;
1490 /* *INDENT-OFF* */
1491 vec_foreach (i, pool_indexes_to_free)
Klement Sekera75e7d132017-09-20 08:26:30 +02001492 {
Klement Sekera896c8962019-06-24 11:52:49 +00001493 ip6_full_reass_t *reass = pool_elt_at_index (rt->pool, i[0]);
Klement Sekera4c533132018-02-22 11:41:12 +01001494 u32 icmp_bi = ~0;
Klement Sekera896c8962019-06-24 11:52:49 +00001495 ip6_full_reass_on_timeout (vm, node, rm, reass, &icmp_bi);
Klement Sekera4c533132018-02-22 11:41:12 +01001496 if (~0 != icmp_bi)
Dave Baracha638c182019-06-21 18:24:07 -04001497 vec_add1 (vec_icmp_bi, icmp_bi);
1498
Klement Sekera896c8962019-06-24 11:52:49 +00001499 ip6_full_reass_free (rm, rt, reass);
Klement Sekera75e7d132017-09-20 08:26:30 +02001500 }
Klement Sekera4c533132018-02-22 11:41:12 +01001501 /* *INDENT-ON* */
1502
1503 clib_spinlock_unlock (&rt->lock);
1504 }
Klement Sekera75e7d132017-09-20 08:26:30 +02001505
Klement Sekera75e7d132017-09-20 08:26:30 +02001506 while (vec_len (vec_icmp_bi) > 0)
1507 {
1508 vlib_frame_t *f =
1509 vlib_get_frame_to_node (vm, rm->ip6_icmp_error_idx);
1510 u32 *to_next = vlib_frame_vector_args (f);
1511 u32 n_left_to_next = VLIB_FRAME_SIZE - f->n_vectors;
Klement Sekera4c533132018-02-22 11:41:12 +01001512 int trace_frame = 0;
Klement Sekera75e7d132017-09-20 08:26:30 +02001513 while (vec_len (vec_icmp_bi) > 0 && n_left_to_next > 0)
1514 {
1515 u32 bi = vec_pop (vec_icmp_bi);
1516 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
1517 if (PREDICT_FALSE (b->flags & VLIB_BUFFER_IS_TRACED))
Dave Baracha638c182019-06-21 18:24:07 -04001518 trace_frame = 1;
Klement Sekera75e7d132017-09-20 08:26:30 +02001519 b->error = node->errors[IP6_ERROR_REASS_TIMEOUT];
1520 to_next[0] = bi;
1521 ++f->n_vectors;
1522 to_next += 1;
1523 n_left_to_next -= 1;
Klement Sekera75e7d132017-09-20 08:26:30 +02001524 }
Damjan Marion633b6fd2018-09-14 14:38:53 +02001525 f->frame_flags |= (trace_frame * VLIB_FRAME_TRACE);
Klement Sekera75e7d132017-09-20 08:26:30 +02001526 vlib_put_frame_to_node (vm, rm->ip6_icmp_error_idx, f);
1527 }
1528
1529 vec_free (pool_indexes_to_free);
Klement Sekera75e7d132017-09-20 08:26:30 +02001530 vec_free (vec_icmp_bi);
1531 if (event_data)
1532 {
1533 _vec_len (event_data) = 0;
1534 }
1535 }
1536
1537 return 0;
1538}
1539
Klement Sekera75e7d132017-09-20 08:26:30 +02001540/* *INDENT-OFF* */
Klement Sekera896c8962019-06-24 11:52:49 +00001541VLIB_REGISTER_NODE (ip6_full_reass_expire_node) = {
1542 .function = ip6_full_reass_walk_expired,
1543 .format_trace = format_ip6_full_reass_trace,
Klement Sekera75e7d132017-09-20 08:26:30 +02001544 .type = VLIB_NODE_TYPE_PROCESS,
Klement Sekera896c8962019-06-24 11:52:49 +00001545 .name = "ip6-full-reassembly-expire-walk",
Klement Sekera75e7d132017-09-20 08:26:30 +02001546
Klement Sekera896c8962019-06-24 11:52:49 +00001547 .n_errors = ARRAY_LEN (ip6_full_reassembly_error_strings),
1548 .error_strings = ip6_full_reassembly_error_strings,
Klement Sekera75e7d132017-09-20 08:26:30 +02001549
1550};
1551/* *INDENT-ON* */
1552
1553static u8 *
Klement Sekera896c8962019-06-24 11:52:49 +00001554format_ip6_full_reass_key (u8 * s, va_list * args)
Klement Sekera75e7d132017-09-20 08:26:30 +02001555{
Klement Sekera896c8962019-06-24 11:52:49 +00001556 ip6_full_reass_key_t *key = va_arg (*args, ip6_full_reass_key_t *);
Klement Sekera75e7d132017-09-20 08:26:30 +02001557 s = format (s, "xx_id: %u, src: %U, dst: %U, frag_id: %u, proto: %u",
1558 key->xx_id, format_ip6_address, &key->src, format_ip6_address,
1559 &key->dst, clib_net_to_host_u16 (key->frag_id), key->proto);
1560 return s;
1561}
1562
1563static u8 *
Klement Sekera896c8962019-06-24 11:52:49 +00001564format_ip6_full_reass (u8 * s, va_list * args)
Klement Sekera75e7d132017-09-20 08:26:30 +02001565{
1566 vlib_main_t *vm = va_arg (*args, vlib_main_t *);
Klement Sekera896c8962019-06-24 11:52:49 +00001567 ip6_full_reass_t *reass = va_arg (*args, ip6_full_reass_t *);
Klement Sekera75e7d132017-09-20 08:26:30 +02001568
Klement Sekera4c533132018-02-22 11:41:12 +01001569 s = format (s, "ID: %lu, key: %U\n first_bi: %u, data_len: %u, "
Klement Sekera75e7d132017-09-20 08:26:30 +02001570 "last_packet_octet: %u, trace_op_counter: %u\n",
Klement Sekera896c8962019-06-24 11:52:49 +00001571 reass->id, format_ip6_full_reass_key, &reass->key,
1572 reass->first_bi, reass->data_len, reass->last_packet_octet,
Klement Sekera75e7d132017-09-20 08:26:30 +02001573 reass->trace_op_counter);
1574 u32 bi = reass->first_bi;
1575 u32 counter = 0;
1576 while (~0 != bi)
1577 {
1578 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
1579 vnet_buffer_opaque_t *vnb = vnet_buffer (b);
1580 s = format (s, " #%03u: range: [%u, %u], bi: %u, off: %d, len: %u, "
1581 "fragment[%u, %u]\n",
1582 counter, vnb->ip.reass.range_first,
1583 vnb->ip.reass.range_last, bi,
Klement Sekera896c8962019-06-24 11:52:49 +00001584 ip6_full_reass_buffer_get_data_offset (b),
1585 ip6_full_reass_buffer_get_data_len (b),
Klement Sekera75e7d132017-09-20 08:26:30 +02001586 vnb->ip.reass.fragment_first, vnb->ip.reass.fragment_last);
1587 if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
1588 {
1589 bi = b->next_buffer;
1590 }
1591 else
1592 {
1593 bi = ~0;
1594 }
1595 }
1596 return s;
1597}
1598
1599static clib_error_t *
Klement Sekera896c8962019-06-24 11:52:49 +00001600show_ip6_full_reass (vlib_main_t * vm, unformat_input_t * input,
1601 CLIB_UNUSED (vlib_cli_command_t * lmd))
Klement Sekera75e7d132017-09-20 08:26:30 +02001602{
Klement Sekera896c8962019-06-24 11:52:49 +00001603 ip6_full_reass_main_t *rm = &ip6_full_reass_main;
Klement Sekera75e7d132017-09-20 08:26:30 +02001604
1605 vlib_cli_output (vm, "---------------------");
1606 vlib_cli_output (vm, "IP6 reassembly status");
1607 vlib_cli_output (vm, "---------------------");
Klement Sekera4c533132018-02-22 11:41:12 +01001608 bool details = false;
Klement Sekera75e7d132017-09-20 08:26:30 +02001609 if (unformat (input, "details"))
1610 {
Klement Sekera4c533132018-02-22 11:41:12 +01001611 details = true;
1612 }
1613
1614 u32 sum_reass_n = 0;
1615 u64 sum_buffers_n = 0;
Klement Sekera896c8962019-06-24 11:52:49 +00001616 ip6_full_reass_t *reass;
Klement Sekera4c533132018-02-22 11:41:12 +01001617 uword thread_index;
Juraj Slobodacd806922018-10-10 10:15:54 +02001618 const uword nthreads = vlib_num_workers () + 1;
Klement Sekera4c533132018-02-22 11:41:12 +01001619 for (thread_index = 0; thread_index < nthreads; ++thread_index)
1620 {
Klement Sekera896c8962019-06-24 11:52:49 +00001621 ip6_full_reass_per_thread_t *rt = &rm->per_thread_data[thread_index];
Klement Sekera4c533132018-02-22 11:41:12 +01001622 clib_spinlock_lock (&rt->lock);
1623 if (details)
1624 {
1625 /* *INDENT-OFF* */
1626 pool_foreach (reass, rt->pool, {
Klement Sekera896c8962019-06-24 11:52:49 +00001627 vlib_cli_output (vm, "%U", format_ip6_full_reass, vm, reass);
Klement Sekera4c533132018-02-22 11:41:12 +01001628 });
1629 /* *INDENT-ON* */
1630 }
1631 sum_reass_n += rt->reass_n;
Klement Sekera4c533132018-02-22 11:41:12 +01001632 clib_spinlock_unlock (&rt->lock);
Klement Sekera75e7d132017-09-20 08:26:30 +02001633 }
1634 vlib_cli_output (vm, "---------------------");
Klement Sekera4c533132018-02-22 11:41:12 +01001635 vlib_cli_output (vm, "Current IP6 reassemblies count: %lu\n",
1636 (long unsigned) sum_reass_n);
1637 vlib_cli_output (vm, "Maximum configured concurrent IP6 reassemblies per "
1638 "worker-thread: %lu\n", (long unsigned) rm->max_reass_n);
Klement Sekera75e7d132017-09-20 08:26:30 +02001639 vlib_cli_output (vm, "Buffers in use: %lu\n",
Klement Sekera4c533132018-02-22 11:41:12 +01001640 (long unsigned) sum_buffers_n);
Klement Sekera75e7d132017-09-20 08:26:30 +02001641 return 0;
1642}
1643
1644/* *INDENT-OFF* */
Klement Sekera896c8962019-06-24 11:52:49 +00001645VLIB_CLI_COMMAND (show_ip6_full_reassembly_cmd, static) = {
1646 .path = "show ip6-full-reassembly",
1647 .short_help = "show ip6-full-reassembly [details]",
1648 .function = show_ip6_full_reass,
Klement Sekera75e7d132017-09-20 08:26:30 +02001649};
1650/* *INDENT-ON* */
1651
Filip Tehlar26ea14e2019-03-11 05:30:21 -07001652#ifndef CLIB_MARCH_VARIANT
Klement Sekera4c533132018-02-22 11:41:12 +01001653vnet_api_error_t
Klement Sekera896c8962019-06-24 11:52:49 +00001654ip6_full_reass_enable_disable (u32 sw_if_index, u8 enable_disable)
Klement Sekera4c533132018-02-22 11:41:12 +01001655{
Klement Sekera896c8962019-06-24 11:52:49 +00001656 return vnet_feature_enable_disable ("ip6-unicast",
1657 "ip6-full-reassembly-feature",
Klement Sekera4c533132018-02-22 11:41:12 +01001658 sw_if_index, enable_disable, 0, 0);
1659}
Filip Tehlar26ea14e2019-03-11 05:30:21 -07001660#endif /* CLIB_MARCH_VARIANT */
Klement Sekera4c533132018-02-22 11:41:12 +01001661
Klement Sekera896c8962019-06-24 11:52:49 +00001662#define foreach_ip6_full_reassembly_handoff_error \
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001663_(CONGESTION_DROP, "congestion drop")
1664
1665
1666typedef enum
1667{
Klement Sekera896c8962019-06-24 11:52:49 +00001668#define _(sym,str) IP6_FULL_REASSEMBLY_HANDOFF_ERROR_##sym,
1669 foreach_ip6_full_reassembly_handoff_error
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001670#undef _
Klement Sekera896c8962019-06-24 11:52:49 +00001671 IP6_FULL_REASSEMBLY_HANDOFF_N_ERROR,
1672} ip6_full_reassembly_handoff_error_t;
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001673
Klement Sekera896c8962019-06-24 11:52:49 +00001674static char *ip6_full_reassembly_handoff_error_strings[] = {
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001675#define _(sym,string) string,
Klement Sekera896c8962019-06-24 11:52:49 +00001676 foreach_ip6_full_reassembly_handoff_error
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001677#undef _
1678};
1679
1680typedef struct
1681{
1682 u32 next_worker_index;
Klement Sekera896c8962019-06-24 11:52:49 +00001683} ip6_full_reassembly_handoff_trace_t;
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001684
1685static u8 *
Klement Sekera896c8962019-06-24 11:52:49 +00001686format_ip6_full_reassembly_handoff_trace (u8 * s, va_list * args)
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001687{
1688 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1689 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
Klement Sekera896c8962019-06-24 11:52:49 +00001690 ip6_full_reassembly_handoff_trace_t *t =
1691 va_arg (*args, ip6_full_reassembly_handoff_trace_t *);
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001692
1693 s =
Klement Sekera896c8962019-06-24 11:52:49 +00001694 format (s, "ip6-full-reassembly-handoff: next-worker %d",
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001695 t->next_worker_index);
1696
1697 return s;
1698}
1699
1700always_inline uword
Klement Sekera896c8962019-06-24 11:52:49 +00001701ip6_full_reassembly_handoff_inline (vlib_main_t * vm,
1702 vlib_node_runtime_t * node,
1703 vlib_frame_t * frame, bool is_feature)
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001704{
Klement Sekera896c8962019-06-24 11:52:49 +00001705 ip6_full_reass_main_t *rm = &ip6_full_reass_main;
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001706
1707 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1708 u32 n_enq, n_left_from, *from;
1709 u16 thread_indices[VLIB_FRAME_SIZE], *ti;
1710 u32 fq_index;
1711
1712 from = vlib_frame_vector_args (frame);
1713 n_left_from = frame->n_vectors;
1714 vlib_get_buffers (vm, from, bufs, n_left_from);
1715
1716 b = bufs;
1717 ti = thread_indices;
1718
1719 fq_index = (is_feature) ? rm->fq_feature_index : rm->fq_index;
1720
1721 while (n_left_from > 0)
1722 {
Klement Sekerade34c352019-06-25 11:19:22 +00001723 ti[0] = vnet_buffer (b[0])->ip.reass.owner_thread_index;
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001724
1725 if (PREDICT_FALSE
1726 ((node->flags & VLIB_NODE_FLAG_TRACE)
1727 && (b[0]->flags & VLIB_BUFFER_IS_TRACED)))
1728 {
Klement Sekera896c8962019-06-24 11:52:49 +00001729 ip6_full_reassembly_handoff_trace_t *t =
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001730 vlib_add_trace (vm, node, b[0], sizeof (*t));
1731 t->next_worker_index = ti[0];
1732 }
1733
1734 n_left_from -= 1;
1735 ti += 1;
1736 b += 1;
1737 }
1738 n_enq =
1739 vlib_buffer_enqueue_to_thread (vm, fq_index, from, thread_indices,
1740 frame->n_vectors, 1);
1741
1742 if (n_enq < frame->n_vectors)
1743 vlib_node_increment_counter (vm, node->node_index,
Klement Sekera896c8962019-06-24 11:52:49 +00001744 IP6_FULL_REASSEMBLY_HANDOFF_ERROR_CONGESTION_DROP,
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001745 frame->n_vectors - n_enq);
1746 return frame->n_vectors;
1747}
1748
Klement Sekera896c8962019-06-24 11:52:49 +00001749VLIB_NODE_FN (ip6_full_reassembly_handoff_node) (vlib_main_t * vm,
1750 vlib_node_runtime_t * node,
1751 vlib_frame_t * frame)
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001752{
Klement Sekera896c8962019-06-24 11:52:49 +00001753 return ip6_full_reassembly_handoff_inline (vm, node, frame,
1754 false /* is_feature */ );
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001755}
1756
1757/* *INDENT-OFF* */
Klement Sekera896c8962019-06-24 11:52:49 +00001758VLIB_REGISTER_NODE (ip6_full_reassembly_handoff_node) = {
1759 .name = "ip6-full-reassembly-handoff",
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001760 .vector_size = sizeof (u32),
Klement Sekera896c8962019-06-24 11:52:49 +00001761 .n_errors = ARRAY_LEN(ip6_full_reassembly_handoff_error_strings),
1762 .error_strings = ip6_full_reassembly_handoff_error_strings,
1763 .format_trace = format_ip6_full_reassembly_handoff_trace,
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001764
1765 .n_next_nodes = 1,
1766
1767 .next_nodes = {
1768 [0] = "error-drop",
1769 },
1770};
1771
1772
Klement Sekera896c8962019-06-24 11:52:49 +00001773VLIB_NODE_FN (ip6_full_reassembly_feature_handoff_node) (vlib_main_t * vm,
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001774 vlib_node_runtime_t * node, vlib_frame_t * frame)
1775{
Klement Sekera896c8962019-06-24 11:52:49 +00001776 return ip6_full_reassembly_handoff_inline (vm, node, frame, true /* is_feature */ );
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001777}
1778
1779
1780/* *INDENT-OFF* */
Klement Sekera896c8962019-06-24 11:52:49 +00001781VLIB_REGISTER_NODE (ip6_full_reassembly_feature_handoff_node) = {
1782 .name = "ip6-full-reass-feature-hoff",
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001783 .vector_size = sizeof (u32),
Klement Sekera896c8962019-06-24 11:52:49 +00001784 .n_errors = ARRAY_LEN(ip6_full_reassembly_handoff_error_strings),
1785 .error_strings = ip6_full_reassembly_handoff_error_strings,
1786 .format_trace = format_ip6_full_reassembly_handoff_trace,
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001787
1788 .n_next_nodes = 1,
1789
1790 .next_nodes = {
1791 [0] = "error-drop",
1792 },
1793};
1794/* *INDENT-ON* */
1795
Klement Sekera7b2e9fb2019-10-01 13:00:22 +00001796#ifndef CLIB_MARCH_VARIANT
1797int
1798ip6_full_reass_enable_disable_with_refcnt (u32 sw_if_index, int is_enable)
1799{
1800 ip6_full_reass_main_t *rm = &ip6_full_reass_main;
1801 vec_validate (rm->feature_use_refcount_per_intf, sw_if_index);
1802 if (is_enable)
1803 {
1804 if (!rm->feature_use_refcount_per_intf[sw_if_index])
1805 {
1806 ++rm->feature_use_refcount_per_intf[sw_if_index];
1807 return vnet_feature_enable_disable ("ip6-unicast",
1808 "ip6-full-reassembly-feature",
1809 sw_if_index, 1, 0, 0);
1810 }
1811 ++rm->feature_use_refcount_per_intf[sw_if_index];
1812 }
1813 else
1814 {
1815 --rm->feature_use_refcount_per_intf[sw_if_index];
1816 if (!rm->feature_use_refcount_per_intf[sw_if_index])
1817 return vnet_feature_enable_disable ("ip6-unicast",
1818 "ip6-full-reassembly-feature",
1819 sw_if_index, 0, 0, 0);
1820 }
1821 return -1;
1822}
1823#endif
1824
Klement Sekera75e7d132017-09-20 08:26:30 +02001825/*
1826 * fd.io coding-style-patch-verification: ON
1827 *
1828 * Local Variables:
1829 * eval: (c-set-style "gnu")
1830 * End:
1831 */