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