blob: 446df33a0a4449d55225bce0f17b585d91eb65a9 [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
18 * @brief IPv4 Reassembly.
19 *
20 * This file contains the source code for IPv4 reassembly.
21 */
22
23#include <vppinfra/vec.h>
24#include <vnet/vnet.h>
25#include <vnet/ip/ip.h>
Klement Sekera8dcfed52018-06-28 11:16:15 +020026#include <vppinfra/bihash_16_8.h>
Klement Sekera75e7d132017-09-20 08:26:30 +020027#include <vnet/ip/ip4_reassembly.h>
28
29#define MSEC_PER_SEC 1000
30#define IP4_REASS_TIMEOUT_DEFAULT_MS 100
31#define IP4_REASS_EXPIRE_WALK_INTERVAL_DEFAULT_MS 10000 // 10 seconds default
Klement Sekera4c533132018-02-22 11:41:12 +010032#define IP4_REASS_MAX_REASSEMBLIES_DEFAULT 1024
Klement Sekera75e7d132017-09-20 08:26:30 +020033#define IP4_REASS_HT_LOAD_FACTOR (0.75)
34
35#define IP4_REASS_DEBUG_BUFFERS 0
36#if IP4_REASS_DEBUG_BUFFERS
37#define IP4_REASS_DEBUG_BUFFER(bi, what) \
38 do \
39 { \
40 u32 _bi = bi; \
41 printf (#what "buffer %u", _bi); \
42 vlib_buffer_t *_b = vlib_get_buffer (vm, _bi); \
43 while (_b->flags & VLIB_BUFFER_NEXT_PRESENT) \
44 { \
45 _bi = _b->next_buffer; \
46 printf ("[%u]", _bi); \
47 _b = vlib_get_buffer (vm, _bi); \
48 } \
49 printf ("\n"); \
50 fflush (stdout); \
51 } \
52 while (0)
53#else
54#define IP4_REASS_DEBUG_BUFFER(...)
55#endif
56
Klement Sekerad0f70a32018-12-14 17:24:13 +010057typedef enum
58{
59 IP4_REASS_RC_OK,
60 IP4_REASS_RC_INTERNAL_ERROR,
Klement Sekeraf883f6a2019-02-13 11:01:32 +010061 IP4_REASS_RC_NO_BUF,
Klement Sekerad0f70a32018-12-14 17:24:13 +010062} ip4_reass_rc_t;
Klement Sekera75e7d132017-09-20 08:26:30 +020063
64typedef struct
65{
66 union
67 {
68 struct
69 {
Klement Sekera75e7d132017-09-20 08:26:30 +020070 u32 xx_id;
71 ip4_address_t src;
72 ip4_address_t dst;
Klement Sekera8dcfed52018-06-28 11:16:15 +020073 u16 frag_id;
74 u8 proto;
75 u8 unused;
Klement Sekera75e7d132017-09-20 08:26:30 +020076 };
Klement Sekera8dcfed52018-06-28 11:16:15 +020077 u64 as_u64[2];
Klement Sekera75e7d132017-09-20 08:26:30 +020078 };
79} ip4_reass_key_t;
80
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -080081typedef union
82{
83 struct
84 {
85 u32 reass_index;
86 u32 thread_index;
87 };
88 u64 as_u64;
89} ip4_reass_val_t;
90
91typedef union
92{
93 struct
94 {
95 ip4_reass_key_t k;
96 ip4_reass_val_t v;
97 };
98 clib_bihash_kv_16_8_t kv;
99} ip4_reass_kv_t;
100
Klement Sekera75e7d132017-09-20 08:26:30 +0200101always_inline u32
Klement Sekera75e7d132017-09-20 08:26:30 +0200102ip4_reass_buffer_get_data_offset (vlib_buffer_t * b)
103{
104 vnet_buffer_opaque_t *vnb = vnet_buffer (b);
Klement Sekerad0f70a32018-12-14 17:24:13 +0100105 return vnb->ip.reass.range_first - vnb->ip.reass.fragment_first;
Klement Sekera75e7d132017-09-20 08:26:30 +0200106}
107
108always_inline u16
109ip4_reass_buffer_get_data_len (vlib_buffer_t * b)
110{
111 vnet_buffer_opaque_t *vnb = vnet_buffer (b);
Klement Sekerad0f70a32018-12-14 17:24:13 +0100112 return clib_min (vnb->ip.reass.range_last, vnb->ip.reass.fragment_last) -
113 (vnb->ip.reass.fragment_first + ip4_reass_buffer_get_data_offset (b)) + 1;
Klement Sekera75e7d132017-09-20 08:26:30 +0200114}
115
116typedef struct
117{
118 // hash table key
119 ip4_reass_key_t key;
Klement Sekera75e7d132017-09-20 08:26:30 +0200120 // time when last packet was received
121 f64 last_heard;
122 // internal id of this reassembly
Klement Sekera4c533132018-02-22 11:41:12 +0100123 u64 id;
Klement Sekera75e7d132017-09-20 08:26:30 +0200124 // buffer index of first buffer in this reassembly context
125 u32 first_bi;
126 // last octet of packet, ~0 until fragment without more_fragments arrives
127 u32 last_packet_octet;
128 // length of data collected so far
129 u32 data_len;
130 // trace operation counter
131 u32 trace_op_counter;
Klement Sekera4c533132018-02-22 11:41:12 +0100132 // next index - used by non-feature node
133 u8 next_index;
134 // minimum fragment length for this reassembly - used to estimate MTU
135 u16 min_fragment_length;
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800136
Klement Sekera75e7d132017-09-20 08:26:30 +0200137} ip4_reass_t;
138
139typedef struct
140{
Klement Sekera4c533132018-02-22 11:41:12 +0100141 ip4_reass_t *pool;
142 u32 reass_n;
Klement Sekera4c533132018-02-22 11:41:12 +0100143 u32 id_counter;
144 clib_spinlock_t lock;
145} ip4_reass_per_thread_t;
146
147typedef struct
148{
Klement Sekera75e7d132017-09-20 08:26:30 +0200149 // IPv4 config
150 u32 timeout_ms;
151 f64 timeout;
152 u32 expire_walk_interval_ms;
153 u32 max_reass_n;
154
155 // IPv4 runtime
Klement Sekera8dcfed52018-06-28 11:16:15 +0200156 clib_bihash_16_8_t hash;
Klement Sekera4c533132018-02-22 11:41:12 +0100157 // per-thread data
158 ip4_reass_per_thread_t *per_thread_data;
Klement Sekera75e7d132017-09-20 08:26:30 +0200159
160 // convenience
161 vlib_main_t *vlib_main;
162 vnet_main_t *vnet_main;
163
164 // node index of ip4-drop node
165 u32 ip4_drop_idx;
166 u32 ip4_reass_expire_node_idx;
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800167
168 /** Worker handoff */
169 u32 fq_index;
170 u32 fq_feature_index;
171
Klement Sekera75e7d132017-09-20 08:26:30 +0200172} ip4_reass_main_t;
173
Filip Tehlar26ea14e2019-03-11 05:30:21 -0700174extern ip4_reass_main_t ip4_reass_main;
175
176#ifndef CLIB_MARCH_VARIANT
Klement Sekera75e7d132017-09-20 08:26:30 +0200177ip4_reass_main_t ip4_reass_main;
Filip Tehlar26ea14e2019-03-11 05:30:21 -0700178#endif /* CLIB_MARCH_VARIANT */
Klement Sekera75e7d132017-09-20 08:26:30 +0200179
180typedef enum
181{
182 IP4_REASSEMBLY_NEXT_INPUT,
183 IP4_REASSEMBLY_NEXT_DROP,
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800184 IP4_REASSEMBLY_NEXT_HANDOFF,
Klement Sekera75e7d132017-09-20 08:26:30 +0200185 IP4_REASSEMBLY_N_NEXT,
186} ip4_reass_next_t;
187
188typedef enum
189{
190 RANGE_NEW,
191 RANGE_SHRINK,
192 RANGE_DISCARD,
193 RANGE_OVERLAP,
194 FINALIZE,
195} ip4_reass_trace_operation_e;
196
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;
205} ip4_reass_range_trace_t;
206
207typedef struct
208{
209 ip4_reass_trace_operation_e action;
Klement Sekera75e7d132017-09-20 08:26:30 +0200210 u32 reass_id;
211 ip4_reass_range_trace_t trace_range;
212 u32 size_diff;
213 u32 op_id;
214 u32 fragment_first;
215 u32 fragment_last;
216 u32 total_data_len;
217} ip4_reass_trace_t;
218
Filip Tehlar26ea14e2019-03-11 05:30:21 -0700219extern vlib_node_registration_t ip4_reass_node;
220extern vlib_node_registration_t ip4_reass_node_feature;
221
Klement Sekera4c533132018-02-22 11:41:12 +0100222static void
Klement Sekera75e7d132017-09-20 08:26:30 +0200223ip4_reass_trace_details (vlib_main_t * vm, u32 bi,
224 ip4_reass_range_trace_t * trace)
225{
226 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
227 vnet_buffer_opaque_t *vnb = vnet_buffer (b);
228 trace->range_first = vnb->ip.reass.range_first;
229 trace->range_last = vnb->ip.reass.range_last;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100230 trace->data_offset = ip4_reass_buffer_get_data_offset (b);
231 trace->data_len = ip4_reass_buffer_get_data_len (b);
Klement Sekera75e7d132017-09-20 08:26:30 +0200232 trace->range_bi = bi;
233}
234
Klement Sekera4c533132018-02-22 11:41:12 +0100235static u8 *
Klement Sekera75e7d132017-09-20 08:26:30 +0200236format_ip4_reass_range_trace (u8 * s, va_list * args)
237{
238 ip4_reass_range_trace_t *trace = va_arg (*args, ip4_reass_range_trace_t *);
239 s = 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);
242 return s;
243}
244
Filip Tehlar26ea14e2019-03-11 05:30:21 -0700245static u8 *
Klement Sekera75e7d132017-09-20 08:26:30 +0200246format_ip4_reass_trace (u8 * s, va_list * args)
247{
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 *);
250 ip4_reass_trace_t *t = va_arg (*args, ip4_reass_trace_t *);
251 s = format (s, "reass id: %u, op id: %u ", t->reass_id, t->op_id);
252 u32 indent = format_get_indent (s);
253 s = format (s, "first bi: %u, data len: %u, ip/fragment[%u, %u]",
254 t->trace_range.first_bi, t->total_data_len, t->fragment_first,
255 t->fragment_last);
256 switch (t->action)
257 {
258 case RANGE_SHRINK:
259 s = format (s, "\n%Ushrink %U by %u", format_white_space, indent,
260 format_ip4_reass_range_trace, &t->trace_range,
261 t->size_diff);
262 break;
263 case RANGE_DISCARD:
264 s = format (s, "\n%Udiscard %U", format_white_space, indent,
265 format_ip4_reass_range_trace, &t->trace_range);
266 break;
267 case RANGE_NEW:
268 s = format (s, "\n%Unew %U", format_white_space, indent,
269 format_ip4_reass_range_trace, &t->trace_range);
270 break;
271 case RANGE_OVERLAP:
272 s = format (s, "\n%Uoverlapping/ignored %U", format_white_space, indent,
273 format_ip4_reass_range_trace, &t->trace_range);
274 break;
275 case FINALIZE:
276 s = format (s, "\n%Ufinalize reassembly", format_white_space, indent);
277 break;
278 }
279 return s;
280}
281
Klement Sekera4c533132018-02-22 11:41:12 +0100282static void
Klement Sekera75e7d132017-09-20 08:26:30 +0200283ip4_reass_add_trace (vlib_main_t * vm, vlib_node_runtime_t * node,
284 ip4_reass_main_t * rm, ip4_reass_t * reass, u32 bi,
285 ip4_reass_trace_operation_e action, u32 size_diff)
286{
287 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
288 vnet_buffer_opaque_t *vnb = vnet_buffer (b);
Klement Sekera4c533132018-02-22 11:41:12 +0100289 if (pool_is_free_index (vm->trace_main.trace_buffer_pool, b->trace_index))
290 {
291 // this buffer's trace is gone
292 b->flags &= ~VLIB_BUFFER_IS_TRACED;
293 return;
294 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200295 ip4_reass_trace_t *t = vlib_add_trace (vm, node, b, sizeof (t[0]));
Klement Sekera75e7d132017-09-20 08:26:30 +0200296 t->reass_id = reass->id;
297 t->action = action;
298 ip4_reass_trace_details (vm, bi, &t->trace_range);
299 t->size_diff = size_diff;
300 t->op_id = reass->trace_op_counter;
301 ++reass->trace_op_counter;
302 t->fragment_first = vnb->ip.reass.fragment_first;
303 t->fragment_last = vnb->ip.reass.fragment_last;
304 t->trace_range.first_bi = reass->first_bi;
305 t->total_data_len = reass->data_len;
306#if 0
307 static u8 *s = NULL;
308 s = format (s, "%U", format_ip4_reass_trace, NULL, NULL, t);
309 printf ("%.*s\n", vec_len (s), s);
310 fflush (stdout);
311 vec_reset_length (s);
312#endif
313}
314
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800315
Klement Sekera4c533132018-02-22 11:41:12 +0100316always_inline void
317ip4_reass_free (ip4_reass_main_t * rm, ip4_reass_per_thread_t * rt,
318 ip4_reass_t * reass)
Klement Sekera75e7d132017-09-20 08:26:30 +0200319{
Klement Sekera8dcfed52018-06-28 11:16:15 +0200320 clib_bihash_kv_16_8_t kv;
Klement Sekera75e7d132017-09-20 08:26:30 +0200321 kv.key[0] = reass->key.as_u64[0];
322 kv.key[1] = reass->key.as_u64[1];
Klement Sekera8dcfed52018-06-28 11:16:15 +0200323 clib_bihash_add_del_16_8 (&rm->hash, &kv, 0);
Klement Sekera4c533132018-02-22 11:41:12 +0100324 pool_put (rt->pool, reass);
325 --rt->reass_n;
Klement Sekera75e7d132017-09-20 08:26:30 +0200326}
327
Klement Sekera4c533132018-02-22 11:41:12 +0100328always_inline void
Klement Sekera75e7d132017-09-20 08:26:30 +0200329ip4_reass_on_timeout (vlib_main_t * vm, ip4_reass_main_t * rm,
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100330 ip4_reass_t * reass)
Klement Sekera75e7d132017-09-20 08:26:30 +0200331{
332 u32 range_bi = reass->first_bi;
333 vlib_buffer_t *range_b;
334 vnet_buffer_opaque_t *range_vnb;
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100335 u32 *to_free = NULL;
Klement Sekera75e7d132017-09-20 08:26:30 +0200336 while (~0 != range_bi)
337 {
338 range_b = vlib_get_buffer (vm, range_bi);
339 range_vnb = vnet_buffer (range_b);
340 u32 bi = range_bi;
341 while (~0 != bi)
342 {
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100343 vec_add1 (to_free, bi);
Klement Sekera75e7d132017-09-20 08:26:30 +0200344 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
345 if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
346 {
347 bi = b->next_buffer;
348 b->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
349 }
350 else
351 {
352 bi = ~0;
353 }
354 }
355 range_bi = range_vnb->ip.reass.next_range_bi;
356 }
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100357 vlib_buffer_free (vm, to_free, vec_len (to_free));
358 vec_free (to_free);
Klement Sekera75e7d132017-09-20 08:26:30 +0200359}
360
Filip Tehlar26ea14e2019-03-11 05:30:21 -0700361static ip4_reass_t *
Klement Sekera75e7d132017-09-20 08:26:30 +0200362ip4_reass_find_or_create (vlib_main_t * vm, ip4_reass_main_t * rm,
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800363 ip4_reass_per_thread_t * rt, ip4_reass_kv_t * kv,
364 u8 * do_handoff)
Klement Sekera75e7d132017-09-20 08:26:30 +0200365{
366 ip4_reass_t *reass = NULL;
367 f64 now = vlib_time_now (rm->vlib_main);
Klement Sekera75e7d132017-09-20 08:26:30 +0200368
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800369 if (!clib_bihash_search_16_8
370 (&rm->hash, (clib_bihash_kv_16_8_t *) kv, (clib_bihash_kv_16_8_t *) kv))
Klement Sekera75e7d132017-09-20 08:26:30 +0200371 {
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800372 if (vm->thread_index != kv->v.thread_index)
373 {
374 *do_handoff = 1;
375 return NULL;
376 }
377 reass = pool_elt_at_index (rt->pool, kv->v.reass_index);
378
Klement Sekera75e7d132017-09-20 08:26:30 +0200379 if (now > reass->last_heard + rm->timeout)
380 {
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100381 ip4_reass_on_timeout (vm, rm, reass);
Klement Sekera4c533132018-02-22 11:41:12 +0100382 ip4_reass_free (rm, rt, reass);
Klement Sekera75e7d132017-09-20 08:26:30 +0200383 reass = NULL;
384 }
385 }
386
387 if (reass)
388 {
389 reass->last_heard = now;
390 return reass;
391 }
392
Klement Sekera4c533132018-02-22 11:41:12 +0100393 if (rt->reass_n >= rm->max_reass_n)
Klement Sekera75e7d132017-09-20 08:26:30 +0200394 {
395 reass = NULL;
396 return reass;
397 }
398 else
399 {
Klement Sekera4c533132018-02-22 11:41:12 +0100400 pool_get (rt->pool, reass);
Dave Barachb7b92992018-10-17 10:38:51 -0400401 clib_memset (reass, 0, sizeof (*reass));
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800402 reass->id = ((u64) vm->thread_index * 1000000000) + rt->id_counter;
Klement Sekera4c533132018-02-22 11:41:12 +0100403 ++rt->id_counter;
Klement Sekera75e7d132017-09-20 08:26:30 +0200404 reass->first_bi = ~0;
405 reass->last_packet_octet = ~0;
406 reass->data_len = 0;
Klement Sekera4c533132018-02-22 11:41:12 +0100407 ++rt->reass_n;
Klement Sekera75e7d132017-09-20 08:26:30 +0200408 }
409
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800410 reass->key.as_u64[0] = ((clib_bihash_kv_16_8_t *) kv)->key[0];
411 reass->key.as_u64[1] = ((clib_bihash_kv_16_8_t *) kv)->key[1];
412 kv->v.reass_index = (reass - rt->pool);
413 kv->v.thread_index = vm->thread_index;
Klement Sekera75e7d132017-09-20 08:26:30 +0200414 reass->last_heard = now;
415
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800416 if (clib_bihash_add_del_16_8 (&rm->hash, (clib_bihash_kv_16_8_t *) kv, 1))
Klement Sekera75e7d132017-09-20 08:26:30 +0200417 {
Klement Sekera4c533132018-02-22 11:41:12 +0100418 ip4_reass_free (rm, rt, reass);
Klement Sekera75e7d132017-09-20 08:26:30 +0200419 reass = NULL;
420 }
421
422 return reass;
423}
424
Klement Sekerad0f70a32018-12-14 17:24:13 +0100425always_inline ip4_reass_rc_t
Klement Sekera75e7d132017-09-20 08:26:30 +0200426ip4_reass_finalize (vlib_main_t * vm, vlib_node_runtime_t * node,
Klement Sekera4c533132018-02-22 11:41:12 +0100427 ip4_reass_main_t * rm, ip4_reass_per_thread_t * rt,
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100428 ip4_reass_t * reass, u32 * bi0, u32 * next0, u32 * error0,
429 bool is_feature)
Klement Sekera75e7d132017-09-20 08:26:30 +0200430{
Klement Sekera75e7d132017-09-20 08:26:30 +0200431 vlib_buffer_t *first_b = vlib_get_buffer (vm, reass->first_bi);
432 vlib_buffer_t *last_b = NULL;
433 u32 sub_chain_bi = reass->first_bi;
434 u32 total_length = 0;
435 u32 buf_cnt = 0;
Klement Sekera75e7d132017-09-20 08:26:30 +0200436 do
437 {
438 u32 tmp_bi = sub_chain_bi;
439 vlib_buffer_t *tmp = vlib_get_buffer (vm, tmp_bi);
440 ip4_header_t *ip = vlib_buffer_get_current (tmp);
Klement Sekerad0f70a32018-12-14 17:24:13 +0100441 vnet_buffer_opaque_t *vnb = vnet_buffer (tmp);
442 if (!(vnb->ip.reass.range_first >= vnb->ip.reass.fragment_first) &&
443 !(vnb->ip.reass.range_last > vnb->ip.reass.fragment_first))
444 {
445 return IP4_REASS_RC_INTERNAL_ERROR;
446 }
447
Klement Sekera75e7d132017-09-20 08:26:30 +0200448 u32 data_len = ip4_reass_buffer_get_data_len (tmp);
449 u32 trim_front =
450 ip4_header_bytes (ip) + ip4_reass_buffer_get_data_offset (tmp);
451 u32 trim_end =
452 vlib_buffer_length_in_chain (vm, tmp) - trim_front - data_len;
453 if (tmp_bi == reass->first_bi)
454 {
455 /* first buffer - keep ip4 header */
Klement Sekerad0f70a32018-12-14 17:24:13 +0100456 if (0 != ip4_reass_buffer_get_data_offset (tmp))
457 {
458 return IP4_REASS_RC_INTERNAL_ERROR;
459 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200460 trim_front = 0;
461 trim_end = vlib_buffer_length_in_chain (vm, tmp) - data_len -
462 ip4_header_bytes (ip);
Klement Sekerad0f70a32018-12-14 17:24:13 +0100463 if (!(vlib_buffer_length_in_chain (vm, tmp) - trim_end > 0))
464 {
465 return IP4_REASS_RC_INTERNAL_ERROR;
466 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200467 }
468 u32 keep_data =
469 vlib_buffer_length_in_chain (vm, tmp) - trim_front - trim_end;
470 while (1)
471 {
472 ++buf_cnt;
473 if (trim_front)
474 {
475 if (trim_front > tmp->current_length)
476 {
477 /* drop whole buffer */
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100478 vlib_buffer_free_one (vm, tmp_bi);
Klement Sekera75e7d132017-09-20 08:26:30 +0200479 trim_front -= tmp->current_length;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100480 if (!(tmp->flags & VLIB_BUFFER_NEXT_PRESENT))
481 {
482 return IP4_REASS_RC_INTERNAL_ERROR;
483 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200484 tmp->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
485 tmp_bi = tmp->next_buffer;
486 tmp = vlib_get_buffer (vm, tmp_bi);
487 continue;
488 }
489 else
490 {
491 vlib_buffer_advance (tmp, trim_front);
492 trim_front = 0;
493 }
494 }
495 if (keep_data)
496 {
497 if (last_b)
498 {
499 last_b->flags |= VLIB_BUFFER_NEXT_PRESENT;
500 last_b->next_buffer = tmp_bi;
501 }
502 last_b = tmp;
503 if (keep_data <= tmp->current_length)
504 {
505 tmp->current_length = keep_data;
506 keep_data = 0;
507 }
508 else
509 {
510 keep_data -= tmp->current_length;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100511 if (!(tmp->flags & VLIB_BUFFER_NEXT_PRESENT))
512 {
513 return IP4_REASS_RC_INTERNAL_ERROR;
514 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200515 }
516 total_length += tmp->current_length;
517 }
518 else
519 {
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100520 vlib_buffer_free_one (vm, tmp_bi);
Klement Sekerad0f70a32018-12-14 17:24:13 +0100521 if (reass->first_bi == tmp_bi)
522 {
523 return IP4_REASS_RC_INTERNAL_ERROR;
524 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200525 }
526 if (tmp->flags & VLIB_BUFFER_NEXT_PRESENT)
527 {
528 tmp_bi = tmp->next_buffer;
529 tmp = vlib_get_buffer (vm, tmp->next_buffer);
530 }
531 else
532 {
533 break;
534 }
535 }
536 sub_chain_bi =
537 vnet_buffer (vlib_get_buffer (vm, sub_chain_bi))->ip.
538 reass.next_range_bi;
539 }
540 while (~0 != sub_chain_bi);
Chris Luke30684ac2018-03-29 12:56:58 -0700541
Klement Sekerad0f70a32018-12-14 17:24:13 +0100542 if (!last_b)
543 {
544 return IP4_REASS_RC_INTERNAL_ERROR;
545 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200546 last_b->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100547 if (total_length < first_b->current_length)
548 {
549 return IP4_REASS_RC_INTERNAL_ERROR;
550 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200551 total_length -= first_b->current_length;
552 first_b->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
553 first_b->total_length_not_including_first_buffer = total_length;
554 ip4_header_t *ip = vlib_buffer_get_current (first_b);
555 ip->flags_and_fragment_offset = 0;
556 ip->length = clib_host_to_net_u16 (first_b->current_length + total_length);
557 ip->checksum = ip4_header_checksum (ip);
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100558 if (!vlib_buffer_chain_linearize (vm, first_b))
559 {
560 return IP4_REASS_RC_NO_BUF;
561 }
Klement Sekera400f6d82018-12-13 14:35:48 +0100562
Klement Sekera75e7d132017-09-20 08:26:30 +0200563 if (PREDICT_FALSE (first_b->flags & VLIB_BUFFER_IS_TRACED))
564 {
565 ip4_reass_add_trace (vm, node, rm, reass, reass->first_bi, FINALIZE, 0);
566#if 0
567 // following code does a hexdump of packet fragments to stdout ...
568 do
569 {
570 u32 bi = reass->first_bi;
571 u8 *s = NULL;
572 while (~0 != bi)
573 {
574 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
575 s = format (s, "%u: %U\n", bi, format_hexdump,
576 vlib_buffer_get_current (b), b->current_length);
577 if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
578 {
579 bi = b->next_buffer;
580 }
581 else
582 {
583 break;
584 }
585 }
586 printf ("%.*s\n", vec_len (s), s);
587 fflush (stdout);
588 vec_free (s);
589 }
590 while (0);
591#endif
592 }
593 *bi0 = reass->first_bi;
Klement Sekera4c533132018-02-22 11:41:12 +0100594 if (is_feature)
595 {
596 *next0 = IP4_REASSEMBLY_NEXT_INPUT;
597 }
598 else
599 {
600 *next0 = reass->next_index;
601 }
602 vnet_buffer (first_b)->ip.reass.estimated_mtu = reass->min_fragment_length;
Klement Sekera75e7d132017-09-20 08:26:30 +0200603 *error0 = IP4_ERROR_NONE;
Klement Sekera4c533132018-02-22 11:41:12 +0100604 ip4_reass_free (rm, rt, reass);
Klement Sekera75e7d132017-09-20 08:26:30 +0200605 reass = NULL;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100606 return IP4_REASS_RC_OK;
Klement Sekera75e7d132017-09-20 08:26:30 +0200607}
608
Klement Sekerad0f70a32018-12-14 17:24:13 +0100609always_inline ip4_reass_rc_t
Klement Sekera75e7d132017-09-20 08:26:30 +0200610ip4_reass_insert_range_in_chain (vlib_main_t * vm,
611 ip4_reass_main_t * rm,
Klement Sekera4c533132018-02-22 11:41:12 +0100612 ip4_reass_per_thread_t * rt,
Klement Sekera75e7d132017-09-20 08:26:30 +0200613 ip4_reass_t * reass,
614 u32 prev_range_bi, u32 new_next_bi)
615{
Klement Sekera75e7d132017-09-20 08:26:30 +0200616 vlib_buffer_t *new_next_b = vlib_get_buffer (vm, new_next_bi);
617 vnet_buffer_opaque_t *new_next_vnb = vnet_buffer (new_next_b);
618 if (~0 != prev_range_bi)
619 {
620 vlib_buffer_t *prev_b = vlib_get_buffer (vm, prev_range_bi);
621 vnet_buffer_opaque_t *prev_vnb = vnet_buffer (prev_b);
622 new_next_vnb->ip.reass.next_range_bi = prev_vnb->ip.reass.next_range_bi;
623 prev_vnb->ip.reass.next_range_bi = new_next_bi;
624 }
625 else
626 {
627 if (~0 != reass->first_bi)
628 {
629 new_next_vnb->ip.reass.next_range_bi = reass->first_bi;
630 }
631 reass->first_bi = new_next_bi;
632 }
Klement Sekerad0f70a32018-12-14 17:24:13 +0100633 vnet_buffer_opaque_t *vnb = vnet_buffer (new_next_b);
634 if (!(vnb->ip.reass.range_first >= vnb->ip.reass.fragment_first) &&
635 !(vnb->ip.reass.range_last > vnb->ip.reass.fragment_first))
636 {
637 return IP4_REASS_RC_INTERNAL_ERROR;
638 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200639 reass->data_len += ip4_reass_buffer_get_data_len (new_next_b);
Klement Sekerad0f70a32018-12-14 17:24:13 +0100640 return IP4_REASS_RC_OK;
Klement Sekera75e7d132017-09-20 08:26:30 +0200641}
642
Klement Sekerad0f70a32018-12-14 17:24:13 +0100643always_inline ip4_reass_rc_t
Klement Sekera75e7d132017-09-20 08:26:30 +0200644ip4_reass_remove_range_from_chain (vlib_main_t * vm,
645 vlib_node_runtime_t * node,
646 ip4_reass_main_t * rm,
Klement Sekera75e7d132017-09-20 08:26:30 +0200647 ip4_reass_t * reass, u32 prev_range_bi,
648 u32 discard_bi)
649{
650 vlib_buffer_t *discard_b = vlib_get_buffer (vm, discard_bi);
651 vnet_buffer_opaque_t *discard_vnb = vnet_buffer (discard_b);
652 if (~0 != prev_range_bi)
653 {
654 vlib_buffer_t *prev_b = vlib_get_buffer (vm, prev_range_bi);
655 vnet_buffer_opaque_t *prev_vnb = vnet_buffer (prev_b);
Klement Sekerad0f70a32018-12-14 17:24:13 +0100656 if (!(prev_vnb->ip.reass.next_range_bi == discard_bi))
657 {
658 return IP4_REASS_RC_INTERNAL_ERROR;
659 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200660 prev_vnb->ip.reass.next_range_bi = discard_vnb->ip.reass.next_range_bi;
661 }
662 else
663 {
664 reass->first_bi = discard_vnb->ip.reass.next_range_bi;
665 }
Klement Sekerad0f70a32018-12-14 17:24:13 +0100666 vnet_buffer_opaque_t *vnb = vnet_buffer (discard_b);
667 if (!(vnb->ip.reass.range_first >= vnb->ip.reass.fragment_first) &&
668 !(vnb->ip.reass.range_last > vnb->ip.reass.fragment_first))
669 {
670 return IP4_REASS_RC_INTERNAL_ERROR;
671 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200672 reass->data_len -= ip4_reass_buffer_get_data_len (discard_b);
673 while (1)
674 {
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100675 vlib_buffer_free_one (vm, discard_bi);
Klement Sekera75e7d132017-09-20 08:26:30 +0200676 if (PREDICT_FALSE (discard_b->flags & VLIB_BUFFER_IS_TRACED))
677 {
678 ip4_reass_add_trace (vm, node, rm, reass, discard_bi, RANGE_DISCARD,
679 0);
680 }
681 if (discard_b->flags & VLIB_BUFFER_NEXT_PRESENT)
682 {
683 discard_b->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
684 discard_bi = discard_b->next_buffer;
685 discard_b = vlib_get_buffer (vm, discard_bi);
686 }
687 else
688 {
689 break;
690 }
691 }
Klement Sekerad0f70a32018-12-14 17:24:13 +0100692 return IP4_REASS_RC_OK;
Klement Sekera75e7d132017-09-20 08:26:30 +0200693}
694
Klement Sekerad0f70a32018-12-14 17:24:13 +0100695always_inline ip4_reass_rc_t
Klement Sekera75e7d132017-09-20 08:26:30 +0200696ip4_reass_update (vlib_main_t * vm, vlib_node_runtime_t * node,
Klement Sekera4c533132018-02-22 11:41:12 +0100697 ip4_reass_main_t * rm, ip4_reass_per_thread_t * rt,
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100698 ip4_reass_t * reass, u32 * bi0, u32 * next0, u32 * error0,
699 bool is_feature)
Klement Sekera75e7d132017-09-20 08:26:30 +0200700{
Klement Sekerad0f70a32018-12-14 17:24:13 +0100701 ip4_reass_rc_t rc = IP4_REASS_RC_OK;
Klement Sekera75e7d132017-09-20 08:26:30 +0200702 int consumed = 0;
703 vlib_buffer_t *fb = vlib_get_buffer (vm, *bi0);
704 ip4_header_t *fip = vlib_buffer_get_current (fb);
Klement Sekera75e7d132017-09-20 08:26:30 +0200705 vnet_buffer_opaque_t *fvnb = vnet_buffer (fb);
Vijayabhaskar Katamreddyb3610762018-06-29 05:03:40 -0700706 reass->next_index = fvnb->ip.reass.next_index; // store next_index before it's overwritten
Klement Sekera14d7e902018-12-10 13:46:09 +0100707 const u32 fragment_first = ip4_get_fragment_offset_bytes (fip);
708 const u32 fragment_length =
Klement Sekera75e7d132017-09-20 08:26:30 +0200709 clib_net_to_host_u16 (fip->length) - ip4_header_bytes (fip);
Klement Sekera14d7e902018-12-10 13:46:09 +0100710 const u32 fragment_last = fragment_first + fragment_length - 1;
711 fvnb->ip.reass.fragment_first = fragment_first;
712 fvnb->ip.reass.fragment_last = fragment_last;
Klement Sekera75e7d132017-09-20 08:26:30 +0200713 int more_fragments = ip4_get_fragment_more (fip);
714 u32 candidate_range_bi = reass->first_bi;
715 u32 prev_range_bi = ~0;
716 fvnb->ip.reass.range_first = fragment_first;
717 fvnb->ip.reass.range_last = fragment_last;
718 fvnb->ip.reass.next_range_bi = ~0;
719 if (!more_fragments)
720 {
721 reass->last_packet_octet = fragment_last;
722 }
723 if (~0 == reass->first_bi)
724 {
725 // starting a new reassembly
Klement Sekerad0f70a32018-12-14 17:24:13 +0100726 rc =
727 ip4_reass_insert_range_in_chain (vm, rm, rt, reass, prev_range_bi,
728 *bi0);
729 if (IP4_REASS_RC_OK != rc)
730 {
731 return rc;
732 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200733 if (PREDICT_FALSE (fb->flags & VLIB_BUFFER_IS_TRACED))
734 {
735 ip4_reass_add_trace (vm, node, rm, reass, *bi0, RANGE_NEW, 0);
736 }
737 *bi0 = ~0;
Klement Sekera4c533132018-02-22 11:41:12 +0100738 reass->min_fragment_length = clib_net_to_host_u16 (fip->length);
Klement Sekerad0f70a32018-12-14 17:24:13 +0100739 return IP4_REASS_RC_OK;
Klement Sekera75e7d132017-09-20 08:26:30 +0200740 }
Klement Sekera4c533132018-02-22 11:41:12 +0100741 reass->min_fragment_length = clib_min (clib_net_to_host_u16 (fip->length),
742 fvnb->ip.reass.estimated_mtu);
Klement Sekera75e7d132017-09-20 08:26:30 +0200743 while (~0 != candidate_range_bi)
744 {
745 vlib_buffer_t *candidate_b = vlib_get_buffer (vm, candidate_range_bi);
746 vnet_buffer_opaque_t *candidate_vnb = vnet_buffer (candidate_b);
747 if (fragment_first > candidate_vnb->ip.reass.range_last)
748 {
749 // this fragments starts after candidate range
750 prev_range_bi = candidate_range_bi;
751 candidate_range_bi = candidate_vnb->ip.reass.next_range_bi;
752 if (candidate_vnb->ip.reass.range_last < fragment_last &&
753 ~0 == candidate_range_bi)
754 {
755 // special case - this fragment falls beyond all known ranges
Klement Sekerad0f70a32018-12-14 17:24:13 +0100756 rc =
757 ip4_reass_insert_range_in_chain (vm, rm, rt, reass,
758 prev_range_bi, *bi0);
759 if (IP4_REASS_RC_OK != rc)
760 {
761 return rc;
762 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200763 consumed = 1;
764 break;
765 }
766 continue;
767 }
768 if (fragment_last < candidate_vnb->ip.reass.range_first)
769 {
770 // this fragment ends before candidate range without any overlap
Klement Sekerad0f70a32018-12-14 17:24:13 +0100771 rc =
772 ip4_reass_insert_range_in_chain (vm, rm, rt, reass, prev_range_bi,
773 *bi0);
774 if (IP4_REASS_RC_OK != rc)
775 {
776 return rc;
777 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200778 consumed = 1;
779 }
780 else
781 {
782 if (fragment_first >= candidate_vnb->ip.reass.range_first &&
783 fragment_last <= candidate_vnb->ip.reass.range_last)
784 {
785 // this fragment is a (sub)part of existing range, ignore it
786 if (PREDICT_FALSE (fb->flags & VLIB_BUFFER_IS_TRACED))
787 {
788 ip4_reass_add_trace (vm, node, rm, reass, *bi0,
789 RANGE_OVERLAP, 0);
790 }
791 break;
792 }
793 int discard_candidate = 0;
794 if (fragment_first < candidate_vnb->ip.reass.range_first)
795 {
796 u32 overlap =
797 fragment_last - candidate_vnb->ip.reass.range_first + 1;
798 if (overlap < ip4_reass_buffer_get_data_len (candidate_b))
799 {
800 candidate_vnb->ip.reass.range_first += overlap;
Klement Sekerad0f70a32018-12-14 17:24:13 +0100801 if (reass->data_len < overlap)
802 {
803 return IP4_REASS_RC_INTERNAL_ERROR;
804 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200805 reass->data_len -= overlap;
806 if (PREDICT_FALSE (fb->flags & VLIB_BUFFER_IS_TRACED))
807 {
808 ip4_reass_add_trace (vm, node, rm, reass,
809 candidate_range_bi, RANGE_SHRINK,
810 overlap);
811 }
Klement Sekerad0f70a32018-12-14 17:24:13 +0100812 rc =
813 ip4_reass_insert_range_in_chain (vm, rm, rt, reass,
814 prev_range_bi, *bi0);
815 if (IP4_REASS_RC_OK != rc)
816 {
817 return rc;
818 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200819 consumed = 1;
820 }
821 else
822 {
823 discard_candidate = 1;
824 }
825 }
826 else if (fragment_last > candidate_vnb->ip.reass.range_last)
827 {
828 u32 overlap =
829 candidate_vnb->ip.reass.range_last - fragment_first + 1;
830 if (overlap < ip4_reass_buffer_get_data_len (candidate_b))
831 {
832 fvnb->ip.reass.range_first += overlap;
833 if (~0 != candidate_vnb->ip.reass.next_range_bi)
834 {
835 prev_range_bi = candidate_range_bi;
836 candidate_range_bi =
837 candidate_vnb->ip.reass.next_range_bi;
838 continue;
839 }
840 else
841 {
842 // special case - last range discarded
Klement Sekerad0f70a32018-12-14 17:24:13 +0100843 rc =
844 ip4_reass_insert_range_in_chain (vm, rm, rt, reass,
845 candidate_range_bi,
846 *bi0);
847 if (IP4_REASS_RC_OK != rc)
848 {
849 return rc;
850 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200851 consumed = 1;
852 }
853 }
854 else
855 {
856 discard_candidate = 1;
857 }
858 }
859 else
860 {
861 discard_candidate = 1;
862 }
863 if (discard_candidate)
864 {
865 u32 next_range_bi = candidate_vnb->ip.reass.next_range_bi;
866 // discard candidate range, probe next range
Klement Sekerad0f70a32018-12-14 17:24:13 +0100867 rc =
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100868 ip4_reass_remove_range_from_chain (vm, node, rm, reass,
Klement Sekerad0f70a32018-12-14 17:24:13 +0100869 prev_range_bi,
870 candidate_range_bi);
871 if (IP4_REASS_RC_OK != rc)
872 {
873 return rc;
874 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200875 if (~0 != next_range_bi)
876 {
877 candidate_range_bi = next_range_bi;
878 continue;
879 }
880 else
881 {
882 // special case - last range discarded
Klement Sekerad0f70a32018-12-14 17:24:13 +0100883 rc =
884 ip4_reass_insert_range_in_chain (vm, rm, rt, reass,
885 prev_range_bi, *bi0);
886 if (IP4_REASS_RC_OK != rc)
887 {
888 return rc;
889 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200890 consumed = 1;
891 }
892 }
893 }
894 break;
895 }
896 if (consumed)
897 {
898 if (PREDICT_FALSE (fb->flags & VLIB_BUFFER_IS_TRACED))
899 {
900 ip4_reass_add_trace (vm, node, rm, reass, *bi0, RANGE_NEW, 0);
901 }
902 }
903 if (~0 != reass->last_packet_octet &&
904 reass->data_len == reass->last_packet_octet + 1)
905 {
Klement Sekerad0f70a32018-12-14 17:24:13 +0100906 return ip4_reass_finalize (vm, node, rm, rt, reass, bi0, next0, error0,
Klement Sekerad0f70a32018-12-14 17:24:13 +0100907 is_feature);
Klement Sekera75e7d132017-09-20 08:26:30 +0200908 }
909 else
910 {
911 if (consumed)
912 {
913 *bi0 = ~0;
914 }
915 else
916 {
Klement Sekera4c533132018-02-22 11:41:12 +0100917 *next0 = IP4_REASSEMBLY_NEXT_DROP;
Klement Sekera75e7d132017-09-20 08:26:30 +0200918 *error0 = IP4_ERROR_REASS_DUPLICATE_FRAGMENT;
919 }
920 }
Klement Sekerad0f70a32018-12-14 17:24:13 +0100921 return rc;
Klement Sekera75e7d132017-09-20 08:26:30 +0200922}
923
924always_inline uword
Klement Sekera4c533132018-02-22 11:41:12 +0100925ip4_reassembly_inline (vlib_main_t * vm,
926 vlib_node_runtime_t * node,
927 vlib_frame_t * frame, bool is_feature)
Klement Sekera75e7d132017-09-20 08:26:30 +0200928{
929 u32 *from = vlib_frame_vector_args (frame);
930 u32 n_left_from, n_left_to_next, *to_next, next_index;
931 ip4_reass_main_t *rm = &ip4_reass_main;
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800932 ip4_reass_per_thread_t *rt = &rm->per_thread_data[vm->thread_index];
Klement Sekera4c533132018-02-22 11:41:12 +0100933 clib_spinlock_lock (&rt->lock);
Klement Sekera75e7d132017-09-20 08:26:30 +0200934
935 n_left_from = frame->n_vectors;
936 next_index = node->cached_next_index;
Klement Sekeraf883f6a2019-02-13 11:01:32 +0100937 while (n_left_from > 0)
Klement Sekera75e7d132017-09-20 08:26:30 +0200938 {
939 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
940
Klement Sekera75e7d132017-09-20 08:26:30 +0200941 while (n_left_from > 0 && n_left_to_next > 0)
942 {
943 u32 bi0;
944 vlib_buffer_t *b0;
Klement Sekera4c533132018-02-22 11:41:12 +0100945 u32 next0;
946 u32 error0 = IP4_ERROR_NONE;
Klement Sekera75e7d132017-09-20 08:26:30 +0200947
948 bi0 = from[0];
949 b0 = vlib_get_buffer (vm, bi0);
950
951 ip4_header_t *ip0 = vlib_buffer_get_current (b0);
Klement Sekera4c533132018-02-22 11:41:12 +0100952 if (!ip4_get_fragment_more (ip0) && !ip4_get_fragment_offset (ip0))
Klement Sekera75e7d132017-09-20 08:26:30 +0200953 {
Klement Sekera4c533132018-02-22 11:41:12 +0100954 // this is a whole packet - no fragmentation
955 if (is_feature)
956 {
957 next0 = IP4_REASSEMBLY_NEXT_INPUT;
958 }
959 else
960 {
961 next0 = vnet_buffer (b0)->ip.reass.next_index;
962 }
Klement Sekera75e7d132017-09-20 08:26:30 +0200963 }
964 else
965 {
Klement Sekera4ee633e2018-12-14 12:00:44 +0100966 const u32 fragment_first = ip4_get_fragment_offset_bytes (ip0);
Klement Sekera14d7e902018-12-10 13:46:09 +0100967 const u32 fragment_length =
Klement Sekera4ee633e2018-12-14 12:00:44 +0100968 clib_net_to_host_u16 (ip0->length) - ip4_header_bytes (ip0);
Klement Sekera14d7e902018-12-10 13:46:09 +0100969 const u32 fragment_last = fragment_first + fragment_length - 1;
Klement Sekera4ee633e2018-12-14 12:00:44 +0100970 if (fragment_first > fragment_last || fragment_first + fragment_length > UINT16_MAX - 20 || (fragment_length < 8 && ip4_get_fragment_more (ip0))) // 8 is minimum frag length per RFC 791
Klement Sekera4c533132018-02-22 11:41:12 +0100971 {
Klement Sekera14d7e902018-12-10 13:46:09 +0100972 next0 = IP4_REASSEMBLY_NEXT_DROP;
973 error0 = IP4_ERROR_REASS_MALFORMED_PACKET;
Klement Sekera4c533132018-02-22 11:41:12 +0100974 }
975 else
976 {
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800977 ip4_reass_kv_t kv;
978 u8 do_handoff = 0;
979
980 kv.k.as_u64[0] =
981 (u64) vec_elt (ip4_main.fib_index_by_sw_if_index,
982 vnet_buffer (b0)->sw_if_index[VLIB_RX]) |
Klement Sekerad0f70a32018-12-14 17:24:13 +0100983 (u64) ip0->src_address.as_u32 << 32;
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800984 kv.k.as_u64[1] =
Klement Sekerad0f70a32018-12-14 17:24:13 +0100985 (u64) ip0->dst_address.as_u32 |
986 (u64) ip0->fragment_id << 32 | (u64) ip0->protocol << 48;
Klement Sekera14d7e902018-12-10 13:46:09 +0100987
988 ip4_reass_t *reass =
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800989 ip4_reass_find_or_create (vm, rm, rt, &kv, &do_handoff);
Klement Sekera14d7e902018-12-10 13:46:09 +0100990
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -0800991 if (PREDICT_FALSE (do_handoff))
992 {
993 next0 = IP4_REASSEMBLY_NEXT_HANDOFF;
994 if (is_feature)
995 vnet_buffer (b0)->ip.
996 reass.owner_feature_thread_index =
997 kv.v.thread_index;
998 else
999 vnet_buffer (b0)->ip.reass.owner_thread_index =
1000 kv.v.thread_index;
1001 }
1002 else if (reass)
Klement Sekera14d7e902018-12-10 13:46:09 +01001003 {
Klement Sekerad0f70a32018-12-14 17:24:13 +01001004 switch (ip4_reass_update
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001005 (vm, node, rm, rt, reass, &bi0, &next0,
1006 &error0, is_feature))
Klement Sekerad0f70a32018-12-14 17:24:13 +01001007 {
1008 case IP4_REASS_RC_OK:
1009 /* nothing to do here */
1010 break;
Klement Sekeraf883f6a2019-02-13 11:01:32 +01001011 case IP4_REASS_RC_NO_BUF:
1012 /* fallthrough */
Klement Sekerad0f70a32018-12-14 17:24:13 +01001013 case IP4_REASS_RC_INTERNAL_ERROR:
1014 /* drop everything and start with a clean slate */
Klement Sekeraf883f6a2019-02-13 11:01:32 +01001015 ip4_reass_on_timeout (vm, rm, reass);
Klement Sekerad0f70a32018-12-14 17:24:13 +01001016 ip4_reass_free (rm, rt, reass);
1017 goto next_packet;
1018 break;
1019 }
Klement Sekera14d7e902018-12-10 13:46:09 +01001020 }
1021 else
1022 {
1023 next0 = IP4_REASSEMBLY_NEXT_DROP;
1024 error0 = IP4_ERROR_REASS_LIMIT_REACHED;
1025 }
Klement Sekera4c533132018-02-22 11:41:12 +01001026 }
1027
1028 b0->error = node->errors[error0];
1029 }
Klement Sekera75e7d132017-09-20 08:26:30 +02001030
1031 if (bi0 != ~0)
1032 {
1033 to_next[0] = bi0;
1034 to_next += 1;
1035 n_left_to_next -= 1;
Klement Sekera4c533132018-02-22 11:41:12 +01001036 if (is_feature && IP4_ERROR_NONE == error0)
1037 {
Kingwel Xiea0060652018-09-26 04:59:52 -04001038 b0 = vlib_get_buffer (vm, bi0);
Damjan Marion7d98a122018-07-19 20:42:08 +02001039 vnet_feature_next (&next0, b0);
Klement Sekera4c533132018-02-22 11:41:12 +01001040 }
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001041 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
1042 to_next, n_left_to_next,
1043 bi0, next0);
Klement Sekera75e7d132017-09-20 08:26:30 +02001044 IP4_REASS_DEBUG_BUFFER (bi0, enqueue_next);
1045 }
1046
Klement Sekerad0f70a32018-12-14 17:24:13 +01001047 next_packet:
Klement Sekera75e7d132017-09-20 08:26:30 +02001048 from += 1;
1049 n_left_from -= 1;
1050 }
1051
1052 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
1053 }
1054
Klement Sekera4c533132018-02-22 11:41:12 +01001055 clib_spinlock_unlock (&rt->lock);
Klement Sekera75e7d132017-09-20 08:26:30 +02001056 return frame->n_vectors;
1057}
1058
1059static char *ip4_reassembly_error_strings[] = {
1060#define _(sym, string) string,
1061 foreach_ip4_error
1062#undef _
1063};
1064
Filip Tehlar26ea14e2019-03-11 05:30:21 -07001065VLIB_NODE_FN (ip4_reass_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
1066 vlib_frame_t * frame)
Klement Sekera4c533132018-02-22 11:41:12 +01001067{
1068 return ip4_reassembly_inline (vm, node, frame, false /* is_feature */ );
1069}
1070
Klement Sekera75e7d132017-09-20 08:26:30 +02001071/* *INDENT-OFF* */
Filip Tehlar26ea14e2019-03-11 05:30:21 -07001072VLIB_REGISTER_NODE (ip4_reass_node) = {
Klement Sekera75e7d132017-09-20 08:26:30 +02001073 .name = "ip4-reassembly",
1074 .vector_size = sizeof (u32),
1075 .format_trace = format_ip4_reass_trace,
1076 .n_errors = ARRAY_LEN (ip4_reassembly_error_strings),
1077 .error_strings = ip4_reassembly_error_strings,
1078 .n_next_nodes = IP4_REASSEMBLY_N_NEXT,
1079 .next_nodes =
1080 {
1081 [IP4_REASSEMBLY_NEXT_INPUT] = "ip4-input",
1082 [IP4_REASSEMBLY_NEXT_DROP] = "ip4-drop",
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001083 [IP4_REASSEMBLY_NEXT_HANDOFF] = "ip4-reassembly-handoff",
1084
Klement Sekera75e7d132017-09-20 08:26:30 +02001085 },
1086};
1087/* *INDENT-ON* */
1088
Filip Tehlar26ea14e2019-03-11 05:30:21 -07001089VLIB_NODE_FN (ip4_reass_node_feature) (vlib_main_t * vm,
1090 vlib_node_runtime_t * node,
1091 vlib_frame_t * frame)
Klement Sekera4c533132018-02-22 11:41:12 +01001092{
1093 return ip4_reassembly_inline (vm, node, frame, true /* is_feature */ );
1094}
1095
1096/* *INDENT-OFF* */
Filip Tehlar26ea14e2019-03-11 05:30:21 -07001097VLIB_REGISTER_NODE (ip4_reass_node_feature) = {
Klement Sekera4c533132018-02-22 11:41:12 +01001098 .name = "ip4-reassembly-feature",
1099 .vector_size = sizeof (u32),
1100 .format_trace = format_ip4_reass_trace,
1101 .n_errors = ARRAY_LEN (ip4_reassembly_error_strings),
1102 .error_strings = ip4_reassembly_error_strings,
1103 .n_next_nodes = IP4_REASSEMBLY_N_NEXT,
1104 .next_nodes =
1105 {
1106 [IP4_REASSEMBLY_NEXT_INPUT] = "ip4-input",
1107 [IP4_REASSEMBLY_NEXT_DROP] = "ip4-drop",
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001108 [IP4_REASSEMBLY_NEXT_HANDOFF] = "ip4-reass-feature-hoff",
Klement Sekera4c533132018-02-22 11:41:12 +01001109 },
1110};
1111/* *INDENT-ON* */
1112
Klement Sekera4c533132018-02-22 11:41:12 +01001113/* *INDENT-OFF* */
1114VNET_FEATURE_INIT (ip4_reassembly_feature, static) = {
1115 .arc_name = "ip4-unicast",
1116 .node_name = "ip4-reassembly-feature",
1117 .runs_before = VNET_FEATURES ("ip4-lookup"),
1118 .runs_after = 0,
1119};
1120/* *INDENT-ON* */
1121
Filip Tehlar26ea14e2019-03-11 05:30:21 -07001122#ifndef CLIB_MARCH_VARIANT
Klement Sekera4c533132018-02-22 11:41:12 +01001123always_inline u32
1124ip4_reass_get_nbuckets ()
Klement Sekera75e7d132017-09-20 08:26:30 +02001125{
1126 ip4_reass_main_t *rm = &ip4_reass_main;
1127 u32 nbuckets;
1128 u8 i;
1129
1130 nbuckets = (u32) (rm->max_reass_n / IP4_REASS_HT_LOAD_FACTOR);
1131
1132 for (i = 0; i < 31; i++)
1133 if ((1 << i) >= nbuckets)
1134 break;
1135 nbuckets = 1 << i;
1136
1137 return nbuckets;
1138}
Filip Tehlar26ea14e2019-03-11 05:30:21 -07001139#endif /* CLIB_MARCH_VARIANT */
Klement Sekera75e7d132017-09-20 08:26:30 +02001140
1141typedef enum
1142{
1143 IP4_EVENT_CONFIG_CHANGED = 1,
1144} ip4_reass_event_t;
1145
1146typedef struct
1147{
1148 int failure;
Klement Sekera8dcfed52018-06-28 11:16:15 +02001149 clib_bihash_16_8_t *new_hash;
Klement Sekera75e7d132017-09-20 08:26:30 +02001150} ip4_rehash_cb_ctx;
1151
Filip Tehlar26ea14e2019-03-11 05:30:21 -07001152#ifndef CLIB_MARCH_VARIANT
Klement Sekera4c533132018-02-22 11:41:12 +01001153static void
Klement Sekera8dcfed52018-06-28 11:16:15 +02001154ip4_rehash_cb (clib_bihash_kv_16_8_t * kv, void *_ctx)
Klement Sekera75e7d132017-09-20 08:26:30 +02001155{
1156 ip4_rehash_cb_ctx *ctx = _ctx;
Klement Sekera8dcfed52018-06-28 11:16:15 +02001157 if (clib_bihash_add_del_16_8 (ctx->new_hash, kv, 1))
Klement Sekera75e7d132017-09-20 08:26:30 +02001158 {
1159 ctx->failure = 1;
1160 }
1161}
1162
Klement Sekera4c533132018-02-22 11:41:12 +01001163static void
1164ip4_reass_set_params (u32 timeout_ms, u32 max_reassemblies,
1165 u32 expire_walk_interval_ms)
1166{
1167 ip4_reass_main.timeout_ms = timeout_ms;
1168 ip4_reass_main.timeout = (f64) timeout_ms / (f64) MSEC_PER_SEC;
1169 ip4_reass_main.max_reass_n = max_reassemblies;
1170 ip4_reass_main.expire_walk_interval_ms = expire_walk_interval_ms;
1171}
1172
Klement Sekera75e7d132017-09-20 08:26:30 +02001173vnet_api_error_t
1174ip4_reass_set (u32 timeout_ms, u32 max_reassemblies,
1175 u32 expire_walk_interval_ms)
1176{
1177 u32 old_nbuckets = ip4_reass_get_nbuckets ();
Klement Sekera4c533132018-02-22 11:41:12 +01001178 ip4_reass_set_params (timeout_ms, max_reassemblies,
1179 expire_walk_interval_ms);
Klement Sekera75e7d132017-09-20 08:26:30 +02001180 vlib_process_signal_event (ip4_reass_main.vlib_main,
1181 ip4_reass_main.ip4_reass_expire_node_idx,
1182 IP4_EVENT_CONFIG_CHANGED, 0);
1183 u32 new_nbuckets = ip4_reass_get_nbuckets ();
Klement Sekera3ecc2212018-03-27 10:34:43 +02001184 if (ip4_reass_main.max_reass_n > 0 && new_nbuckets > old_nbuckets)
Klement Sekera75e7d132017-09-20 08:26:30 +02001185 {
Klement Sekera8dcfed52018-06-28 11:16:15 +02001186 clib_bihash_16_8_t new_hash;
Dave Barachb7b92992018-10-17 10:38:51 -04001187 clib_memset (&new_hash, 0, sizeof (new_hash));
Klement Sekera75e7d132017-09-20 08:26:30 +02001188 ip4_rehash_cb_ctx ctx;
1189 ctx.failure = 0;
1190 ctx.new_hash = &new_hash;
Klement Sekera8dcfed52018-06-28 11:16:15 +02001191 clib_bihash_init_16_8 (&new_hash, "ip4-reass", new_nbuckets,
Klement Sekera75e7d132017-09-20 08:26:30 +02001192 new_nbuckets * 1024);
Klement Sekera8dcfed52018-06-28 11:16:15 +02001193 clib_bihash_foreach_key_value_pair_16_8 (&ip4_reass_main.hash,
Klement Sekera75e7d132017-09-20 08:26:30 +02001194 ip4_rehash_cb, &ctx);
1195 if (ctx.failure)
1196 {
Klement Sekera8dcfed52018-06-28 11:16:15 +02001197 clib_bihash_free_16_8 (&new_hash);
Klement Sekera75e7d132017-09-20 08:26:30 +02001198 return -1;
1199 }
1200 else
1201 {
Klement Sekera8dcfed52018-06-28 11:16:15 +02001202 clib_bihash_free_16_8 (&ip4_reass_main.hash);
Dave Barach178cf492018-11-13 16:34:13 -05001203 clib_memcpy_fast (&ip4_reass_main.hash, &new_hash,
1204 sizeof (ip4_reass_main.hash));
Klement Sekera75e7d132017-09-20 08:26:30 +02001205 }
1206 }
1207 return 0;
1208}
1209
1210vnet_api_error_t
1211ip4_reass_get (u32 * timeout_ms, u32 * max_reassemblies,
1212 u32 * expire_walk_interval_ms)
1213{
1214 *timeout_ms = ip4_reass_main.timeout_ms;
1215 *max_reassemblies = ip4_reass_main.max_reass_n;
1216 *expire_walk_interval_ms = ip4_reass_main.expire_walk_interval_ms;
1217 return 0;
1218}
1219
Klement Sekera4c533132018-02-22 11:41:12 +01001220static clib_error_t *
Klement Sekera75e7d132017-09-20 08:26:30 +02001221ip4_reass_init_function (vlib_main_t * vm)
1222{
1223 ip4_reass_main_t *rm = &ip4_reass_main;
1224 clib_error_t *error = 0;
1225 u32 nbuckets;
Dave Barach1403fcd2018-02-05 09:45:43 -05001226 vlib_node_t *node;
Klement Sekera75e7d132017-09-20 08:26:30 +02001227
1228 rm->vlib_main = vm;
1229 rm->vnet_main = vnet_get_main ();
1230
Juraj Slobodacd806922018-10-10 10:15:54 +02001231 vec_validate (rm->per_thread_data, vlib_num_workers ());
Klement Sekera4c533132018-02-22 11:41:12 +01001232 ip4_reass_per_thread_t *rt;
1233 vec_foreach (rt, rm->per_thread_data)
1234 {
1235 clib_spinlock_init (&rt->lock);
1236 pool_alloc (rt->pool, rm->max_reass_n);
1237 }
Dave Barach1403fcd2018-02-05 09:45:43 -05001238
1239 node = vlib_get_node_by_name (vm, (u8 *) "ip4-reassembly-expire-walk");
1240 ASSERT (node);
1241 rm->ip4_reass_expire_node_idx = node->index;
1242
Klement Sekera3ecc2212018-03-27 10:34:43 +02001243 ip4_reass_set_params (IP4_REASS_TIMEOUT_DEFAULT_MS,
1244 IP4_REASS_MAX_REASSEMBLIES_DEFAULT,
1245 IP4_REASS_EXPIRE_WALK_INTERVAL_DEFAULT_MS);
1246
Klement Sekera75e7d132017-09-20 08:26:30 +02001247 nbuckets = ip4_reass_get_nbuckets ();
Klement Sekera8dcfed52018-06-28 11:16:15 +02001248 clib_bihash_init_16_8 (&rm->hash, "ip4-reass", nbuckets, nbuckets * 1024);
Klement Sekera75e7d132017-09-20 08:26:30 +02001249
Dave Barach1403fcd2018-02-05 09:45:43 -05001250 node = vlib_get_node_by_name (vm, (u8 *) "ip4-drop");
Klement Sekera75e7d132017-09-20 08:26:30 +02001251 ASSERT (node);
1252 rm->ip4_drop_idx = node->index;
Klement Sekera4c533132018-02-22 11:41:12 +01001253
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001254 rm->fq_index = vlib_frame_queue_main_init (ip4_reass_node.index, 0);
1255 rm->fq_feature_index =
1256 vlib_frame_queue_main_init (ip4_reass_node_feature.index, 0);
1257
1258
Klement Sekera75e7d132017-09-20 08:26:30 +02001259 return error;
1260}
1261
1262VLIB_INIT_FUNCTION (ip4_reass_init_function);
Filip Tehlar26ea14e2019-03-11 05:30:21 -07001263#endif /* CLIB_MARCH_VARIANT */
Klement Sekera75e7d132017-09-20 08:26:30 +02001264
1265static uword
1266ip4_reass_walk_expired (vlib_main_t * vm,
1267 vlib_node_runtime_t * node, vlib_frame_t * f)
1268{
1269 ip4_reass_main_t *rm = &ip4_reass_main;
1270 uword event_type, *event_data = 0;
1271
1272 while (true)
1273 {
1274 vlib_process_wait_for_event_or_clock (vm,
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001275 (f64)
1276 rm->expire_walk_interval_ms /
1277 (f64) MSEC_PER_SEC);
Klement Sekera75e7d132017-09-20 08:26:30 +02001278 event_type = vlib_process_get_events (vm, &event_data);
1279
1280 switch (event_type)
1281 {
1282 case ~0: /* no events => timeout */
1283 /* nothing to do here */
1284 break;
1285 case IP4_EVENT_CONFIG_CHANGED:
1286 break;
1287 default:
1288 clib_warning ("BUG: event type 0x%wx", event_type);
1289 break;
1290 }
1291 f64 now = vlib_time_now (vm);
1292
1293 ip4_reass_t *reass;
Klement Sekera75e7d132017-09-20 08:26:30 +02001294 int *pool_indexes_to_free = NULL;
1295
Klement Sekera4c533132018-02-22 11:41:12 +01001296 uword thread_index = 0;
Klement Sekera75e7d132017-09-20 08:26:30 +02001297 int index;
Juraj Slobodacd806922018-10-10 10:15:54 +02001298 const uword nthreads = vlib_num_workers () + 1;
Klement Sekera4c533132018-02-22 11:41:12 +01001299 for (thread_index = 0; thread_index < nthreads; ++thread_index)
1300 {
1301 ip4_reass_per_thread_t *rt = &rm->per_thread_data[thread_index];
1302 clib_spinlock_lock (&rt->lock);
1303
1304 vec_reset_length (pool_indexes_to_free);
1305 /* *INDENT-OFF* */
1306 pool_foreach_index (index, rt->pool, ({
1307 reass = pool_elt_at_index (rt->pool, index);
1308 if (now > reass->last_heard + rm->timeout)
1309 {
1310 vec_add1 (pool_indexes_to_free, index);
1311 }
1312 }));
1313 /* *INDENT-ON* */
1314 int *i;
1315 /* *INDENT-OFF* */
1316 vec_foreach (i, pool_indexes_to_free)
1317 {
1318 ip4_reass_t *reass = pool_elt_at_index (rt->pool, i[0]);
Klement Sekeraf883f6a2019-02-13 11:01:32 +01001319 ip4_reass_on_timeout (vm, rm, reass);
Klement Sekera4c533132018-02-22 11:41:12 +01001320 ip4_reass_free (rm, rt, reass);
1321 }
1322 /* *INDENT-ON* */
1323
1324 clib_spinlock_unlock (&rt->lock);
1325 }
Klement Sekera75e7d132017-09-20 08:26:30 +02001326
Klement Sekera75e7d132017-09-20 08:26:30 +02001327 vec_free (pool_indexes_to_free);
Klement Sekera75e7d132017-09-20 08:26:30 +02001328 if (event_data)
1329 {
1330 _vec_len (event_data) = 0;
1331 }
1332 }
1333
1334 return 0;
1335}
1336
Klement Sekera75e7d132017-09-20 08:26:30 +02001337/* *INDENT-OFF* */
1338VLIB_REGISTER_NODE (ip4_reass_expire_node, static) = {
1339 .function = ip4_reass_walk_expired,
1340 .type = VLIB_NODE_TYPE_PROCESS,
1341 .name = "ip4-reassembly-expire-walk",
1342 .format_trace = format_ip4_reass_trace,
1343 .n_errors = ARRAY_LEN (ip4_reassembly_error_strings),
1344 .error_strings = ip4_reassembly_error_strings,
1345
1346};
1347/* *INDENT-ON* */
1348
1349static u8 *
1350format_ip4_reass_key (u8 * s, va_list * args)
1351{
1352 ip4_reass_key_t *key = va_arg (*args, ip4_reass_key_t *);
1353 s = format (s, "xx_id: %u, src: %U, dst: %U, frag_id: %u, proto: %u",
1354 key->xx_id, format_ip4_address, &key->src, format_ip4_address,
1355 &key->dst, clib_net_to_host_u16 (key->frag_id), key->proto);
1356 return s;
1357}
1358
1359static u8 *
1360format_ip4_reass (u8 * s, va_list * args)
1361{
1362 vlib_main_t *vm = va_arg (*args, vlib_main_t *);
1363 ip4_reass_t *reass = va_arg (*args, ip4_reass_t *);
1364
Klement Sekera4c533132018-02-22 11:41:12 +01001365 s = format (s, "ID: %lu, key: %U\n first_bi: %u, data_len: %u, "
Klement Sekera75e7d132017-09-20 08:26:30 +02001366 "last_packet_octet: %u, trace_op_counter: %u\n",
1367 reass->id, format_ip4_reass_key, &reass->key, reass->first_bi,
1368 reass->data_len, reass->last_packet_octet,
1369 reass->trace_op_counter);
1370 u32 bi = reass->first_bi;
1371 u32 counter = 0;
1372 while (~0 != bi)
1373 {
1374 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
1375 vnet_buffer_opaque_t *vnb = vnet_buffer (b);
1376 s = format (s, " #%03u: range: [%u, %u], bi: %u, off: %d, len: %u, "
1377 "fragment[%u, %u]\n",
1378 counter, vnb->ip.reass.range_first,
1379 vnb->ip.reass.range_last, bi,
Klement Sekerad0f70a32018-12-14 17:24:13 +01001380 ip4_reass_buffer_get_data_offset (b),
1381 ip4_reass_buffer_get_data_len (b),
Klement Sekera75e7d132017-09-20 08:26:30 +02001382 vnb->ip.reass.fragment_first, vnb->ip.reass.fragment_last);
1383 if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
1384 {
1385 bi = b->next_buffer;
1386 }
1387 else
1388 {
1389 bi = ~0;
1390 }
1391 }
1392 return s;
1393}
1394
1395static clib_error_t *
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001396show_ip4_reass (vlib_main_t * vm,
1397 unformat_input_t * input,
Klement Sekera75e7d132017-09-20 08:26:30 +02001398 CLIB_UNUSED (vlib_cli_command_t * lmd))
1399{
1400 ip4_reass_main_t *rm = &ip4_reass_main;
1401
1402 vlib_cli_output (vm, "---------------------");
1403 vlib_cli_output (vm, "IP4 reassembly status");
1404 vlib_cli_output (vm, "---------------------");
Klement Sekera4c533132018-02-22 11:41:12 +01001405 bool details = false;
Klement Sekera75e7d132017-09-20 08:26:30 +02001406 if (unformat (input, "details"))
1407 {
Klement Sekera4c533132018-02-22 11:41:12 +01001408 details = true;
1409 }
1410
1411 u32 sum_reass_n = 0;
Klement Sekera4c533132018-02-22 11:41:12 +01001412 ip4_reass_t *reass;
1413 uword thread_index;
Juraj Slobodacd806922018-10-10 10:15:54 +02001414 const uword nthreads = vlib_num_workers () + 1;
Klement Sekera4c533132018-02-22 11:41:12 +01001415 for (thread_index = 0; thread_index < nthreads; ++thread_index)
1416 {
1417 ip4_reass_per_thread_t *rt = &rm->per_thread_data[thread_index];
1418 clib_spinlock_lock (&rt->lock);
1419 if (details)
1420 {
1421 /* *INDENT-OFF* */
1422 pool_foreach (reass, rt->pool, {
1423 vlib_cli_output (vm, "%U", format_ip4_reass, vm, reass);
1424 });
1425 /* *INDENT-ON* */
1426 }
1427 sum_reass_n += rt->reass_n;
Klement Sekera4c533132018-02-22 11:41:12 +01001428 clib_spinlock_unlock (&rt->lock);
Klement Sekera75e7d132017-09-20 08:26:30 +02001429 }
1430 vlib_cli_output (vm, "---------------------");
Klement Sekera4c533132018-02-22 11:41:12 +01001431 vlib_cli_output (vm, "Current IP4 reassemblies count: %lu\n",
1432 (long unsigned) sum_reass_n);
Klement Sekera75e7d132017-09-20 08:26:30 +02001433 vlib_cli_output (vm,
Klement Sekera4c533132018-02-22 11:41:12 +01001434 "Maximum configured concurrent IP4 reassemblies per worker-thread: %lu\n",
Klement Sekera75e7d132017-09-20 08:26:30 +02001435 (long unsigned) rm->max_reass_n);
Klement Sekera75e7d132017-09-20 08:26:30 +02001436 return 0;
1437}
1438
1439/* *INDENT-OFF* */
1440VLIB_CLI_COMMAND (show_ip4_reassembly_cmd, static) = {
1441 .path = "show ip4-reassembly",
1442 .short_help = "show ip4-reassembly [details]",
1443 .function = show_ip4_reass,
1444};
1445/* *INDENT-ON* */
1446
Filip Tehlar26ea14e2019-03-11 05:30:21 -07001447#ifndef CLIB_MARCH_VARIANT
Klement Sekera4c533132018-02-22 11:41:12 +01001448vnet_api_error_t
1449ip4_reass_enable_disable (u32 sw_if_index, u8 enable_disable)
1450{
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001451 return vnet_feature_enable_disable ("ip4-unicast",
1452 "ip4-reassembly-feature", sw_if_index,
1453 enable_disable, 0, 0);
Klement Sekera4c533132018-02-22 11:41:12 +01001454}
Filip Tehlar26ea14e2019-03-11 05:30:21 -07001455#endif /* CLIB_MARCH_VARIANT */
Klement Sekera4c533132018-02-22 11:41:12 +01001456
Vijayabhaskar Katamreddy470a3702019-03-01 19:57:06 -08001457
1458#define foreach_ip4_reassembly_handoff_error \
1459_(CONGESTION_DROP, "congestion drop")
1460
1461
1462typedef enum
1463{
1464#define _(sym,str) IP4_REASSEMBLY_HANDOFF_ERROR_##sym,
1465 foreach_ip4_reassembly_handoff_error
1466#undef _
1467 IP4_REASSEMBLY_HANDOFF_N_ERROR,
1468} ip4_reassembly_handoff_error_t;
1469
1470static char *ip4_reassembly_handoff_error_strings[] = {
1471#define _(sym,string) string,
1472 foreach_ip4_reassembly_handoff_error
1473#undef _
1474};
1475
1476typedef struct
1477{
1478 u32 next_worker_index;
1479} ip4_reassembly_handoff_trace_t;
1480
1481static u8 *
1482format_ip4_reassembly_handoff_trace (u8 * s, va_list * args)
1483{
1484 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
1485 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
1486 ip4_reassembly_handoff_trace_t *t =
1487 va_arg (*args, ip4_reassembly_handoff_trace_t *);
1488
1489 s =
1490 format (s, "ip4-reassembly-handoff: next-worker %d",
1491 t->next_worker_index);
1492
1493 return s;
1494}
1495
1496always_inline uword
1497ip4_reassembly_handoff_node_inline (vlib_main_t * vm,
1498 vlib_node_runtime_t * node,
1499 vlib_frame_t * frame, bool is_feature)
1500{
1501 ip4_reass_main_t *rm = &ip4_reass_main;
1502
1503 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
1504 u32 n_enq, n_left_from, *from;
1505 u16 thread_indices[VLIB_FRAME_SIZE], *ti;
1506 u32 fq_index;
1507
1508 from = vlib_frame_vector_args (frame);
1509 n_left_from = frame->n_vectors;
1510 vlib_get_buffers (vm, from, bufs, n_left_from);
1511
1512 b = bufs;
1513 ti = thread_indices;
1514
1515 fq_index = (is_feature) ? rm->fq_feature_index : rm->fq_index;
1516
1517 while (n_left_from > 0)
1518 {
1519 ti[0] =
1520 (is_feature) ? vnet_buffer (b[0])->ip.
1521 reass.owner_feature_thread_index : vnet_buffer (b[0])->ip.
1522 reass.owner_thread_index;
1523
1524 if (PREDICT_FALSE
1525 ((node->flags & VLIB_NODE_FLAG_TRACE)
1526 && (b[0]->flags & VLIB_BUFFER_IS_TRACED)))
1527 {
1528 ip4_reassembly_handoff_trace_t *t =
1529 vlib_add_trace (vm, node, b[0], sizeof (*t));
1530 t->next_worker_index = ti[0];
1531 }
1532
1533 n_left_from -= 1;
1534 ti += 1;
1535 b += 1;
1536 }
1537 n_enq =
1538 vlib_buffer_enqueue_to_thread (vm, fq_index, from, thread_indices,
1539 frame->n_vectors, 1);
1540
1541 if (n_enq < frame->n_vectors)
1542 vlib_node_increment_counter (vm, node->node_index,
1543 IP4_REASSEMBLY_HANDOFF_ERROR_CONGESTION_DROP,
1544 frame->n_vectors - n_enq);
1545 return frame->n_vectors;
1546}
1547
1548VLIB_NODE_FN (ip4_reassembly_handoff_node) (vlib_main_t * vm,
1549 vlib_node_runtime_t * node,
1550 vlib_frame_t * frame)
1551{
1552 return ip4_reassembly_handoff_node_inline (vm, node, frame,
1553 false /* is_feature */ );
1554}
1555
1556
1557/* *INDENT-OFF* */
1558VLIB_REGISTER_NODE (ip4_reassembly_handoff_node) = {
1559 .name = "ip4-reassembly-handoff",
1560 .vector_size = sizeof (u32),
1561 .n_errors = ARRAY_LEN(ip4_reassembly_handoff_error_strings),
1562 .error_strings = ip4_reassembly_handoff_error_strings,
1563 .format_trace = format_ip4_reassembly_handoff_trace,
1564
1565 .n_next_nodes = 1,
1566
1567 .next_nodes = {
1568 [0] = "error-drop",
1569 },
1570};
1571/* *INDENT-ON* */
1572
1573
1574/* *INDENT-OFF* */
1575VLIB_NODE_FN (ip4_reassembly_feature_handoff_node) (vlib_main_t * vm,
1576 vlib_node_runtime_t *
1577 node,
1578 vlib_frame_t * frame)
1579{
1580 return ip4_reassembly_handoff_node_inline (vm, node, frame,
1581 true /* is_feature */ );
1582}
1583/* *INDENT-ON* */
1584
1585
1586/* *INDENT-OFF* */
1587VLIB_REGISTER_NODE (ip4_reassembly_feature_handoff_node) = {
1588 .name = "ip4-reass-feature-hoff",
1589 .vector_size = sizeof (u32),
1590 .n_errors = ARRAY_LEN(ip4_reassembly_handoff_error_strings),
1591 .error_strings = ip4_reassembly_handoff_error_strings,
1592 .format_trace = format_ip4_reassembly_handoff_trace,
1593
1594 .n_next_nodes = 1,
1595
1596 .next_nodes = {
1597 [0] = "error-drop",
1598 },
1599};
1600/* *INDENT-ON* */
1601
Klement Sekera75e7d132017-09-20 08:26:30 +02001602/*
1603 * fd.io coding-style-patch-verification: ON
1604 *
1605 * Local Variables:
1606 * eval: (c-set-style "gnu")
1607 * End:
1608 */