239bc70d8360ce5d7cedf5185094c57b68cd76de
[vpp.git] / src / plugins / nat / nat_reass.c
1 /*
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  * @file
17  * @brief NAT plugin virtual fragmentation reassembly
18  */
19
20 #include <vnet/vnet.h>
21 #include <nat/nat_reass.h>
22
23 nat_reass_main_t nat_reass_main;
24
25 static u32
26 nat_reass_get_nbuckets (u8 is_ip6)
27 {
28   nat_reass_main_t *srm = &nat_reass_main;
29   u32 nbuckets;
30   u8 i;
31
32   if (is_ip6)
33     nbuckets = (u32) (srm->ip6_max_reass / NAT_REASS_HT_LOAD_FACTOR);
34   else
35     nbuckets = (u32) (srm->ip4_max_reass / NAT_REASS_HT_LOAD_FACTOR);
36
37   for (i = 0; i < 31; i++)
38     if ((1 << i) >= nbuckets)
39       break;
40   nbuckets = 1 << i;
41
42   return nbuckets;
43 }
44
45 static_always_inline void
46 nat_ip4_reass_get_frags_inline (nat_reass_ip4_t * reass, u32 ** bi)
47 {
48   nat_reass_main_t *srm = &nat_reass_main;
49   u32 elt_index;
50   dlist_elt_t *elt;
51
52   while ((elt_index =
53           clib_dlist_remove_head (srm->ip4_frags_list_pool,
54                                   reass->frags_per_reass_list_head_index)) !=
55          ~0)
56     {
57       elt = pool_elt_at_index (srm->ip4_frags_list_pool, elt_index);
58       vec_add1 (*bi, elt->value);
59       reass->frag_n--;
60       pool_put_index (srm->ip4_frags_list_pool, elt_index);
61     }
62 }
63
64 static_always_inline void
65 nat_ip6_reass_get_frags_inline (nat_reass_ip6_t * reass, u32 ** bi)
66 {
67   nat_reass_main_t *srm = &nat_reass_main;
68   u32 elt_index;
69   dlist_elt_t *elt;
70
71   while ((elt_index =
72           clib_dlist_remove_head (srm->ip6_frags_list_pool,
73                                   reass->frags_per_reass_list_head_index)) !=
74          ~0)
75     {
76       elt = pool_elt_at_index (srm->ip6_frags_list_pool, elt_index);
77       vec_add1 (*bi, elt->value);
78       reass->frag_n--;
79       pool_put_index (srm->ip6_frags_list_pool, elt_index);
80     }
81 }
82
83 int
84 nat_reass_set (u32 timeout, u16 max_reass, u8 max_frag, u8 drop_frag,
85                u8 is_ip6)
86 {
87   nat_reass_main_t *srm = &nat_reass_main;
88   u32 nbuckets;
89
90   if (is_ip6)
91     {
92       if (srm->ip6_max_reass != max_reass)
93         {
94           clib_spinlock_lock_if_init (&srm->ip6_reass_lock);
95
96           srm->ip6_max_reass = max_reass;
97           pool_free (srm->ip6_reass_pool);
98           pool_alloc (srm->ip6_reass_pool, srm->ip4_max_reass);
99           nbuckets = nat_reass_get_nbuckets (0);
100           clib_bihash_free_48_8 (&srm->ip6_reass_hash);
101           clib_bihash_init_48_8 (&srm->ip6_reass_hash, "nat-ip6-reass",
102                                  nbuckets, nbuckets * 1024);
103
104           clib_spinlock_unlock_if_init (&srm->ip6_reass_lock);
105         }
106       srm->ip6_timeout = timeout;
107       srm->ip6_max_frag = max_frag;
108       srm->ip6_drop_frag = drop_frag;
109     }
110   else
111     {
112       if (srm->ip4_max_reass != max_reass)
113         {
114           clib_spinlock_lock_if_init (&srm->ip4_reass_lock);
115
116           srm->ip4_max_reass = max_reass;
117           pool_free (srm->ip4_reass_pool);
118           pool_alloc (srm->ip4_reass_pool, srm->ip4_max_reass);
119           nbuckets = nat_reass_get_nbuckets (0);
120           clib_bihash_free_16_8 (&srm->ip4_reass_hash);
121           clib_bihash_init_16_8 (&srm->ip4_reass_hash, "nat-ip4-reass",
122                                  nbuckets, nbuckets * 1024);
123           clib_spinlock_unlock_if_init (&srm->ip4_reass_lock);
124         }
125       srm->ip4_timeout = timeout;
126       srm->ip4_max_frag = max_frag;
127       srm->ip4_drop_frag = drop_frag;
128     }
129
130   return 0;
131 }
132
133 u32
134 nat_reass_get_timeout (u8 is_ip6)
135 {
136   nat_reass_main_t *srm = &nat_reass_main;
137
138   if (is_ip6)
139     return srm->ip6_timeout;
140
141   return srm->ip4_timeout;
142 }
143
144 u16
145 nat_reass_get_max_reass (u8 is_ip6)
146 {
147   nat_reass_main_t *srm = &nat_reass_main;
148
149   if (is_ip6)
150     return srm->ip6_max_reass;
151
152   return srm->ip4_max_reass;
153 }
154
155 u8
156 nat_reass_get_max_frag (u8 is_ip6)
157 {
158   nat_reass_main_t *srm = &nat_reass_main;
159
160   if (is_ip6)
161     return srm->ip6_max_frag;
162
163   return srm->ip4_max_frag;
164 }
165
166 u8
167 nat_reass_is_drop_frag (u8 is_ip6)
168 {
169   nat_reass_main_t *srm = &nat_reass_main;
170
171   if (is_ip6)
172     return srm->ip6_drop_frag;
173
174   return srm->ip4_drop_frag;
175 }
176
177 static_always_inline nat_reass_ip4_t *
178 nat_ip4_reass_lookup (nat_reass_ip4_key_t * k, f64 now)
179 {
180   nat_reass_main_t *srm = &nat_reass_main;
181   clib_bihash_kv_16_8_t kv, value;
182   nat_reass_ip4_t *reass;
183
184   kv.key[0] = k->as_u64[0];
185   kv.key[1] = k->as_u64[1];
186
187   if (clib_bihash_search_16_8 (&srm->ip4_reass_hash, &kv, &value))
188     return 0;
189
190   reass = pool_elt_at_index (srm->ip4_reass_pool, value.value);
191   if (now < reass->last_heard + (f64) srm->ip4_timeout)
192     return reass;
193
194   return 0;
195 }
196
197 nat_reass_ip4_t *
198 nat_ip4_reass_find_or_create (ip4_address_t src, ip4_address_t dst,
199                               u16 frag_id, u8 proto, u8 reset_timeout,
200                               u32 ** bi_to_drop)
201 {
202   nat_reass_main_t *srm = &nat_reass_main;
203   nat_reass_ip4_t *reass = 0;
204   nat_reass_ip4_key_t k;
205   f64 now = vlib_time_now (srm->vlib_main);
206   dlist_elt_t *oldest_elt, *elt;
207   dlist_elt_t *per_reass_list_head_elt;
208   u32 oldest_index, elt_index;
209   clib_bihash_kv_16_8_t kv;
210
211   k.src.as_u32 = src.as_u32;
212   k.dst.as_u32 = dst.as_u32;
213   k.frag_id = frag_id;
214   k.proto = proto;
215
216   clib_spinlock_lock_if_init (&srm->ip4_reass_lock);
217
218   reass = nat_ip4_reass_lookup (&k, now);
219   if (reass)
220     {
221       if (reset_timeout)
222         {
223           reass->last_heard = now;
224           clib_dlist_remove (srm->ip4_reass_lru_list_pool,
225                              reass->lru_list_index);
226           clib_dlist_addtail (srm->ip4_reass_lru_list_pool,
227                               srm->ip4_reass_head_index,
228                               reass->lru_list_index);
229         }
230       goto unlock;
231     }
232
233   if (srm->ip4_reass_n >= srm->ip4_max_reass)
234     {
235       oldest_index =
236         clib_dlist_remove_head (srm->ip4_reass_lru_list_pool,
237                                 srm->ip4_reass_head_index);
238       ASSERT (oldest_index != ~0);
239       oldest_elt =
240         pool_elt_at_index (srm->ip4_reass_lru_list_pool, oldest_index);
241       reass = pool_elt_at_index (srm->ip4_reass_pool, oldest_elt->value);
242       if (now < reass->last_heard + (f64) srm->ip4_timeout)
243         {
244           clib_dlist_addhead (srm->ip4_reass_lru_list_pool,
245                               srm->ip4_reass_head_index, oldest_index);
246           clib_warning ("no free resassembly slot");
247           reass = 0;
248           goto unlock;
249         }
250
251       clib_dlist_addtail (srm->ip4_reass_lru_list_pool,
252                           srm->ip4_reass_head_index, oldest_index);
253
254       kv.key[0] = k.as_u64[0];
255       kv.key[1] = k.as_u64[1];
256       if (clib_bihash_add_del_16_8 (&srm->ip4_reass_hash, &kv, 0))
257         {
258           reass = 0;
259           goto unlock;
260         }
261
262       nat_ip4_reass_get_frags_inline (reass, bi_to_drop);
263     }
264   else
265     {
266       pool_get (srm->ip4_reass_pool, reass);
267       pool_get (srm->ip4_reass_lru_list_pool, elt);
268       reass->lru_list_index = elt_index = elt - srm->ip4_reass_lru_list_pool;
269       clib_dlist_init (srm->ip4_reass_lru_list_pool, elt_index);
270       elt->value = reass - srm->ip4_reass_pool;
271       clib_dlist_addtail (srm->ip4_reass_lru_list_pool,
272                           srm->ip4_reass_head_index, elt_index);
273       pool_get (srm->ip4_frags_list_pool, per_reass_list_head_elt);
274       reass->frags_per_reass_list_head_index =
275         per_reass_list_head_elt - srm->ip4_frags_list_pool;
276       clib_dlist_init (srm->ip4_frags_list_pool,
277                        reass->frags_per_reass_list_head_index);
278       srm->ip4_reass_n++;
279     }
280
281   reass->key.as_u64[0] = kv.key[0] = k.as_u64[0];
282   reass->key.as_u64[1] = kv.key[1] = k.as_u64[1];
283   kv.value = reass - srm->ip4_reass_pool;
284   reass->sess_index = (u32) ~ 0;
285   reass->last_heard = now;
286
287   if (clib_bihash_add_del_16_8 (&srm->ip4_reass_hash, &kv, 1))
288     {
289       reass = 0;
290       goto unlock;
291     }
292
293 unlock:
294   clib_spinlock_unlock_if_init (&srm->ip4_reass_lock);
295   return reass;
296 }
297
298 int
299 nat_ip4_reass_add_fragment (nat_reass_ip4_t * reass, u32 bi)
300 {
301   nat_reass_main_t *srm = &nat_reass_main;
302   dlist_elt_t *elt;
303   u32 elt_index;
304
305   if (reass->frag_n >= srm->ip4_max_frag)
306     return -1;
307
308   clib_spinlock_lock_if_init (&srm->ip4_reass_lock);
309
310   pool_get (srm->ip4_frags_list_pool, elt);
311   elt_index = elt - srm->ip4_frags_list_pool;
312   clib_dlist_init (srm->ip4_frags_list_pool, elt_index);
313   elt->value = bi;
314   clib_dlist_addtail (srm->ip4_frags_list_pool,
315                       reass->frags_per_reass_list_head_index, elt_index);
316   reass->frag_n++;
317
318   clib_spinlock_unlock_if_init (&srm->ip4_reass_lock);
319
320   return 0;
321 }
322
323 void
324 nat_ip4_reass_get_frags (nat_reass_ip4_t * reass, u32 ** bi)
325 {
326   nat_reass_main_t *srm = &nat_reass_main;
327
328   clib_spinlock_lock_if_init (&srm->ip4_reass_lock);
329
330   nat_ip4_reass_get_frags_inline (reass, bi);
331
332   clib_spinlock_unlock_if_init (&srm->ip4_reass_lock);
333 }
334
335 void
336 nat_ip4_reass_walk (nat_ip4_reass_walk_fn_t fn, void *ctx)
337 {
338   nat_reass_ip4_t *reass;
339   nat_reass_main_t *srm = &nat_reass_main;
340   f64 now = vlib_time_now (srm->vlib_main);
341
342   /* *INDENT-OFF* */
343   pool_foreach (reass, srm->ip4_reass_pool,
344   ({
345     if (now < reass->last_heard + (f64) srm->ip4_timeout)
346       {
347         if (fn (reass, ctx))
348           return;
349       }
350   }));
351   /* *INDENT-ON* */
352 }
353
354 static_always_inline nat_reass_ip6_t *
355 nat_ip6_reass_lookup (nat_reass_ip6_key_t * k, f64 now)
356 {
357   nat_reass_main_t *srm = &nat_reass_main;
358   clib_bihash_kv_48_8_t kv, value;
359   nat_reass_ip6_t *reass;
360
361   k->unused = 0;
362   kv.key[0] = k->as_u64[0];
363   kv.key[1] = k->as_u64[1];
364   kv.key[2] = k->as_u64[2];
365   kv.key[3] = k->as_u64[3];
366   kv.key[4] = k->as_u64[4];
367   kv.key[5] = k->as_u64[5];
368
369   if (clib_bihash_search_48_8 (&srm->ip6_reass_hash, &kv, &value))
370     return 0;
371
372   reass = pool_elt_at_index (srm->ip6_reass_pool, value.value);
373   if (now < reass->last_heard + (f64) srm->ip6_timeout)
374     return reass;
375
376   return 0;
377 }
378
379 nat_reass_ip6_t *
380 nat_ip6_reass_find_or_create (ip6_address_t src, ip6_address_t dst,
381                               u32 frag_id, u8 proto, u8 reset_timeout,
382                               u32 ** bi_to_drop)
383 {
384   nat_reass_main_t *srm = &nat_reass_main;
385   nat_reass_ip6_t *reass = 0;
386   nat_reass_ip6_key_t k;
387   f64 now = vlib_time_now (srm->vlib_main);
388   dlist_elt_t *oldest_elt, *elt;
389   dlist_elt_t *per_reass_list_head_elt;
390   u32 oldest_index, elt_index;
391   clib_bihash_kv_48_8_t kv;
392
393   k.src.as_u64[0] = src.as_u64[0];
394   k.src.as_u64[1] = src.as_u64[1];
395   k.dst.as_u64[0] = dst.as_u64[0];
396   k.dst.as_u64[1] = dst.as_u64[1];
397   k.frag_id = frag_id;
398   k.proto = proto;
399   k.unused = 0;
400
401   clib_spinlock_lock_if_init (&srm->ip6_reass_lock);
402
403   reass = nat_ip6_reass_lookup (&k, now);
404   if (reass)
405     {
406       if (reset_timeout)
407         {
408           reass->last_heard = now;
409           clib_dlist_remove (srm->ip6_reass_lru_list_pool,
410                              reass->lru_list_index);
411           clib_dlist_addtail (srm->ip6_reass_lru_list_pool,
412                               srm->ip6_reass_head_index,
413                               reass->lru_list_index);
414         }
415       goto unlock;
416     }
417
418   if (srm->ip6_reass_n >= srm->ip6_max_reass)
419     {
420       oldest_index =
421         clib_dlist_remove_head (srm->ip6_reass_lru_list_pool,
422                                 srm->ip6_reass_head_index);
423       ASSERT (oldest_index != ~0);
424       oldest_elt =
425         pool_elt_at_index (srm->ip4_reass_lru_list_pool, oldest_index);
426       reass = pool_elt_at_index (srm->ip6_reass_pool, oldest_elt->value);
427       if (now < reass->last_heard + (f64) srm->ip6_timeout)
428         {
429           clib_dlist_addhead (srm->ip6_reass_lru_list_pool,
430                               srm->ip6_reass_head_index, oldest_index);
431           clib_warning ("no free resassembly slot");
432           reass = 0;
433           goto unlock;
434         }
435
436       clib_dlist_addtail (srm->ip6_reass_lru_list_pool,
437                           srm->ip6_reass_head_index, oldest_index);
438
439       kv.key[0] = k.as_u64[0];
440       kv.key[1] = k.as_u64[1];
441       kv.key[2] = k.as_u64[2];
442       kv.key[3] = k.as_u64[4];
443       kv.key[4] = k.as_u64[5];
444       if (clib_bihash_add_del_48_8 (&srm->ip6_reass_hash, &kv, 0))
445         {
446           reass = 0;
447           goto unlock;
448         }
449
450       nat_ip6_reass_get_frags_inline (reass, bi_to_drop);
451     }
452   else
453     {
454       pool_get (srm->ip6_reass_pool, reass);
455       pool_get (srm->ip6_reass_lru_list_pool, elt);
456       reass->lru_list_index = elt_index = elt - srm->ip6_reass_lru_list_pool;
457       clib_dlist_init (srm->ip6_reass_lru_list_pool, elt_index);
458       elt->value = reass - srm->ip6_reass_pool;
459       clib_dlist_addtail (srm->ip6_reass_lru_list_pool,
460                           srm->ip6_reass_head_index, elt_index);
461       pool_get (srm->ip6_frags_list_pool, per_reass_list_head_elt);
462       reass->frags_per_reass_list_head_index =
463         per_reass_list_head_elt - srm->ip6_frags_list_pool;
464       clib_dlist_init (srm->ip6_frags_list_pool,
465                        reass->frags_per_reass_list_head_index);
466       srm->ip6_reass_n++;
467     }
468
469   reass->key.as_u64[0] = kv.key[0] = k.as_u64[0];
470   reass->key.as_u64[1] = kv.key[1] = k.as_u64[1];
471   reass->key.as_u64[2] = kv.key[2] = k.as_u64[2];
472   reass->key.as_u64[3] = kv.key[3] = k.as_u64[3];
473   reass->key.as_u64[4] = kv.key[4] = k.as_u64[4];
474   reass->key.as_u64[5] = kv.key[5] = k.as_u64[5];
475   kv.value = reass - srm->ip6_reass_pool;
476   reass->sess_index = (u32) ~ 0;
477   reass->last_heard = now;
478
479   if (clib_bihash_add_del_48_8 (&srm->ip6_reass_hash, &kv, 1))
480     {
481       reass = 0;
482       goto unlock;
483     }
484
485 unlock:
486   clib_spinlock_unlock_if_init (&srm->ip6_reass_lock);
487   return reass;
488 }
489
490 int
491 nat_ip6_reass_add_fragment (nat_reass_ip6_t * reass, u32 bi)
492 {
493   nat_reass_main_t *srm = &nat_reass_main;
494   dlist_elt_t *elt;
495   u32 elt_index;
496
497   if (reass->frag_n >= srm->ip6_max_frag)
498     return -1;
499
500   clib_spinlock_lock_if_init (&srm->ip6_reass_lock);
501
502   pool_get (srm->ip6_frags_list_pool, elt);
503   elt_index = elt - srm->ip6_frags_list_pool;
504   clib_dlist_init (srm->ip6_frags_list_pool, elt_index);
505   elt->value = bi;
506   clib_dlist_addtail (srm->ip6_frags_list_pool,
507                       reass->frags_per_reass_list_head_index, elt_index);
508   reass->frag_n++;
509
510   clib_spinlock_unlock_if_init (&srm->ip6_reass_lock);
511
512   return 0;
513 }
514
515 void
516 nat_ip6_reass_get_frags (nat_reass_ip6_t * reass, u32 ** bi)
517 {
518   nat_reass_main_t *srm = &nat_reass_main;
519
520   clib_spinlock_lock_if_init (&srm->ip6_reass_lock);
521
522   nat_ip6_reass_get_frags_inline (reass, bi);
523
524   clib_spinlock_unlock_if_init (&srm->ip6_reass_lock);
525 }
526
527 void
528 nat_ip6_reass_walk (nat_ip6_reass_walk_fn_t fn, void *ctx)
529 {
530   nat_reass_ip6_t *reass;
531   nat_reass_main_t *srm = &nat_reass_main;
532   f64 now = vlib_time_now (srm->vlib_main);
533
534   /* *INDENT-OFF* */
535   pool_foreach (reass, srm->ip6_reass_pool,
536   ({
537     if (now < reass->last_heard + (f64) srm->ip4_timeout)
538       {
539         if (fn (reass, ctx))
540           return;
541       }
542   }));
543   /* *INDENT-ON* */
544 }
545
546 clib_error_t *
547 nat_reass_init (vlib_main_t * vm)
548 {
549   nat_reass_main_t *srm = &nat_reass_main;
550   vlib_thread_main_t *tm = vlib_get_thread_main ();
551   clib_error_t *error = 0;
552   dlist_elt_t *head;
553   u32 nbuckets, head_index;
554
555   srm->vlib_main = vm;
556   srm->vnet_main = vnet_get_main ();
557
558   /* IPv4 */
559   srm->ip4_timeout = NAT_REASS_TIMEOUT_DEFAULT;
560   srm->ip4_max_reass = NAT_MAX_REASS_DEAFULT;
561   srm->ip4_max_frag = NAT_MAX_FRAG_DEFAULT;
562   srm->ip4_drop_frag = 0;
563   srm->ip4_reass_n = 0;
564
565   if (tm->n_vlib_mains > 1)
566     clib_spinlock_init (&srm->ip4_reass_lock);
567
568   pool_alloc (srm->ip4_reass_pool, srm->ip4_max_reass);
569
570   nbuckets = nat_reass_get_nbuckets (0);
571   clib_bihash_init_16_8 (&srm->ip4_reass_hash, "nat-ip4-reass", nbuckets,
572                          nbuckets * 1024);
573
574   pool_get (srm->ip4_reass_lru_list_pool, head);
575   srm->ip4_reass_head_index = head_index =
576     head - srm->ip4_reass_lru_list_pool;
577   clib_dlist_init (srm->ip4_reass_lru_list_pool, head_index);
578
579   /* IPv6 */
580   srm->ip6_timeout = NAT_REASS_TIMEOUT_DEFAULT;
581   srm->ip6_max_reass = NAT_MAX_REASS_DEAFULT;
582   srm->ip6_max_frag = NAT_MAX_FRAG_DEFAULT;
583   srm->ip6_drop_frag = 0;
584   srm->ip6_reass_n = 0;
585
586   if (tm->n_vlib_mains > 1)
587     clib_spinlock_init (&srm->ip6_reass_lock);
588
589   pool_alloc (srm->ip6_reass_pool, srm->ip6_max_reass);
590
591   nbuckets = nat_reass_get_nbuckets (1);
592   clib_bihash_init_48_8 (&srm->ip6_reass_hash, "nat-ip6-reass", nbuckets,
593                          nbuckets * 1024);
594
595   pool_get (srm->ip6_reass_lru_list_pool, head);
596   srm->ip6_reass_head_index = head_index =
597     head - srm->ip6_reass_lru_list_pool;
598   clib_dlist_init (srm->ip6_reass_lru_list_pool, head_index);
599
600   return error;
601 }
602
603 static clib_error_t *
604 nat_reass_command_fn (vlib_main_t * vm, unformat_input_t * input,
605                       vlib_cli_command_t * cmd)
606 {
607   clib_error_t *error = 0;
608   unformat_input_t _line_input, *line_input = &_line_input;
609   u32 timeout = 0, max_reass = 0, max_frag = 0;
610   u8 drop_frag = (u8) ~ 0, is_ip6 = 0;
611   int rv;
612
613   /* Get a line of input. */
614   if (!unformat_user (input, unformat_line_input, line_input))
615     return 0;
616
617   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
618     {
619       if (unformat (line_input, "max-reassemblies %u", &max_reass))
620         ;
621       else if (unformat (line_input, "max-fragments %u", &max_frag))
622         ;
623       else if (unformat (line_input, "timeout %u", &timeout))
624         ;
625       else if (unformat (line_input, "enable"))
626         drop_frag = 0;
627       else if (unformat (line_input, "disable"))
628         drop_frag = 1;
629       else if (unformat (line_input, "ip4"))
630         is_ip6 = 0;
631       else if (unformat (line_input, "ip6"))
632         is_ip6 = 1;
633       else
634         {
635           error = clib_error_return (0, "unknown input '%U'",
636                                      format_unformat_error, line_input);
637           goto done;
638         }
639     }
640
641   if (!timeout)
642     timeout = nat_reass_get_timeout (is_ip6);
643   if (!max_reass)
644     max_reass = nat_reass_get_max_reass (is_ip6);
645   if (!max_frag)
646     max_frag = nat_reass_get_max_frag (is_ip6);
647   if (drop_frag == (u8) ~ 0)
648     drop_frag = nat_reass_is_drop_frag (is_ip6);
649
650   rv =
651     nat_reass_set (timeout, (u16) max_reass, (u8) max_frag, drop_frag,
652                    is_ip6);
653   if (rv)
654     {
655       error = clib_error_return (0, "nat_set_reass return %d", rv);
656       goto done;
657     }
658
659 done:
660   unformat_free (line_input);
661
662   return error;
663 }
664
665 static int
666 nat_ip4_reass_walk_cli (nat_reass_ip4_t * reass, void *ctx)
667 {
668   vlib_main_t *vm = ctx;
669
670   vlib_cli_output (vm, "  src %U dst %U proto %u id 0x%04x cached %u",
671                    format_ip4_address, &reass->key.src,
672                    format_ip4_address, &reass->key.dst,
673                    reass->key.proto,
674                    clib_net_to_host_u16 (reass->key.frag_id), reass->frag_n);
675
676   return 0;
677 }
678
679 static int
680 nat_ip6_reass_walk_cli (nat_reass_ip6_t * reass, void *ctx)
681 {
682   vlib_main_t *vm = ctx;
683
684   vlib_cli_output (vm, "  src %U dst %U proto %u id 0x%08x cached %u",
685                    format_ip6_address, &reass->key.src,
686                    format_ip6_address, &reass->key.dst,
687                    reass->key.proto,
688                    clib_net_to_host_u32 (reass->key.frag_id), reass->frag_n);
689
690   return 0;
691 }
692
693 static clib_error_t *
694 show_nat_reass_command_fn (vlib_main_t * vm, unformat_input_t * input,
695                            vlib_cli_command_t * cmd)
696 {
697   vlib_cli_output (vm, "NAT IPv4 virtual fragmentation reassembly is %s",
698                    nat_reass_is_drop_frag (0) ? "DISABLED" : "ENABLED");
699   vlib_cli_output (vm, " max-reasssemblies %u", nat_reass_get_max_reass (0));
700   vlib_cli_output (vm, " max-fragments %u", nat_reass_get_max_frag (0));
701   vlib_cli_output (vm, " timeout %usec", nat_reass_get_timeout (0));
702   vlib_cli_output (vm, " reassemblies:");
703   nat_ip4_reass_walk (nat_ip4_reass_walk_cli, vm);
704
705   vlib_cli_output (vm, "NAT IPv6 virtual fragmentation reassembly is %s",
706                    nat_reass_is_drop_frag (1) ? "DISABLED" : "ENABLED");
707   vlib_cli_output (vm, " max-reasssemblies %u", nat_reass_get_max_reass (1));
708   vlib_cli_output (vm, " max-fragments %u", nat_reass_get_max_frag (1));
709   vlib_cli_output (vm, " timeout %usec", nat_reass_get_timeout (1));
710   vlib_cli_output (vm, " reassemblies:");
711   nat_ip6_reass_walk (nat_ip6_reass_walk_cli, vm);
712
713   return 0;
714 }
715
716 /* *INDENT-OFF* */
717 VLIB_CLI_COMMAND (nat_reass_command, static) =
718 {
719   .path = "nat virtual-reassembly",
720   .short_help = "nat virtual-reassembly ip4|ip6 [max-reassemblies <n>] "
721                 "[max-fragments <n>] [timeout <sec>] [enable|disable]",
722   .function = nat_reass_command_fn,
723 };
724
725 VLIB_CLI_COMMAND (show_nat_reass_command, static) =
726 {
727   .path = "show nat virtual-reassembly",
728   .short_help = "show nat virtual-reassembly",
729   .function = show_nat_reass_command_fn,
730 };
731 /* *INDENT-ON* */
732
733 /*
734  * fd.io coding-style-patch-verification: ON
735  *
736  * Local Variables:
737  * eval: (c-set-style "gnu")
738  * End:
739  */