aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/nat/nat_reass.c
diff options
context:
space:
mode:
authorMatus Fabian <matfabia@cisco.com>2017-08-15 06:59:19 -0700
committerOle Trøan <otroan@employees.org>2017-11-07 21:58:31 +0000
commitefcd1e9e1d7dda4e4ea3db5750925cd8f6894f4d (patch)
tree63c07cf6a94820a5fb2c3935082b6a02f6d210d3 /src/plugins/nat/nat_reass.c
parent20ab0a4943f7509f6e07d6c614eee90c80c8b963 (diff)
SNAT: IP fragmentation (VPP-890)
Translation of fragmented packets. Change-Id: I9b1f2e9433ce273638080f32c2d3bff39c49899d Signed-off-by: Matus Fabian <matfabia@cisco.com>
Diffstat (limited to 'src/plugins/nat/nat_reass.c')
-rw-r--r--src/plugins/nat/nat_reass.c739
1 files changed, 739 insertions, 0 deletions
diff --git a/src/plugins/nat/nat_reass.c b/src/plugins/nat/nat_reass.c
new file mode 100644
index 00000000000..239bc70d836
--- /dev/null
+++ b/src/plugins/nat/nat_reass.c
@@ -0,0 +1,739 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file
+ * @brief NAT plugin virtual fragmentation reassembly
+ */
+
+#include <vnet/vnet.h>
+#include <nat/nat_reass.h>
+
+nat_reass_main_t nat_reass_main;
+
+static u32
+nat_reass_get_nbuckets (u8 is_ip6)
+{
+ nat_reass_main_t *srm = &nat_reass_main;
+ u32 nbuckets;
+ u8 i;
+
+ if (is_ip6)
+ nbuckets = (u32) (srm->ip6_max_reass / NAT_REASS_HT_LOAD_FACTOR);
+ else
+ nbuckets = (u32) (srm->ip4_max_reass / NAT_REASS_HT_LOAD_FACTOR);
+
+ for (i = 0; i < 31; i++)
+ if ((1 << i) >= nbuckets)
+ break;
+ nbuckets = 1 << i;
+
+ return nbuckets;
+}
+
+static_always_inline void
+nat_ip4_reass_get_frags_inline (nat_reass_ip4_t * reass, u32 ** bi)
+{
+ nat_reass_main_t *srm = &nat_reass_main;
+ u32 elt_index;
+ dlist_elt_t *elt;
+
+ while ((elt_index =
+ clib_dlist_remove_head (srm->ip4_frags_list_pool,
+ reass->frags_per_reass_list_head_index)) !=
+ ~0)
+ {
+ elt = pool_elt_at_index (srm->ip4_frags_list_pool, elt_index);
+ vec_add1 (*bi, elt->value);
+ reass->frag_n--;
+ pool_put_index (srm->ip4_frags_list_pool, elt_index);
+ }
+}
+
+static_always_inline void
+nat_ip6_reass_get_frags_inline (nat_reass_ip6_t * reass, u32 ** bi)
+{
+ nat_reass_main_t *srm = &nat_reass_main;
+ u32 elt_index;
+ dlist_elt_t *elt;
+
+ while ((elt_index =
+ clib_dlist_remove_head (srm->ip6_frags_list_pool,
+ reass->frags_per_reass_list_head_index)) !=
+ ~0)
+ {
+ elt = pool_elt_at_index (srm->ip6_frags_list_pool, elt_index);
+ vec_add1 (*bi, elt->value);
+ reass->frag_n--;
+ pool_put_index (srm->ip6_frags_list_pool, elt_index);
+ }
+}
+
+int
+nat_reass_set (u32 timeout, u16 max_reass, u8 max_frag, u8 drop_frag,
+ u8 is_ip6)
+{
+ nat_reass_main_t *srm = &nat_reass_main;
+ u32 nbuckets;
+
+ if (is_ip6)
+ {
+ if (srm->ip6_max_reass != max_reass)
+ {
+ clib_spinlock_lock_if_init (&srm->ip6_reass_lock);
+
+ srm->ip6_max_reass = max_reass;
+ pool_free (srm->ip6_reass_pool);
+ pool_alloc (srm->ip6_reass_pool, srm->ip4_max_reass);
+ nbuckets = nat_reass_get_nbuckets (0);
+ clib_bihash_free_48_8 (&srm->ip6_reass_hash);
+ clib_bihash_init_48_8 (&srm->ip6_reass_hash, "nat-ip6-reass",
+ nbuckets, nbuckets * 1024);
+
+ clib_spinlock_unlock_if_init (&srm->ip6_reass_lock);
+ }
+ srm->ip6_timeout = timeout;
+ srm->ip6_max_frag = max_frag;
+ srm->ip6_drop_frag = drop_frag;
+ }
+ else
+ {
+ if (srm->ip4_max_reass != max_reass)
+ {
+ clib_spinlock_lock_if_init (&srm->ip4_reass_lock);
+
+ srm->ip4_max_reass = max_reass;
+ pool_free (srm->ip4_reass_pool);
+ pool_alloc (srm->ip4_reass_pool, srm->ip4_max_reass);
+ nbuckets = nat_reass_get_nbuckets (0);
+ clib_bihash_free_16_8 (&srm->ip4_reass_hash);
+ clib_bihash_init_16_8 (&srm->ip4_reass_hash, "nat-ip4-reass",
+ nbuckets, nbuckets * 1024);
+ clib_spinlock_unlock_if_init (&srm->ip4_reass_lock);
+ }
+ srm->ip4_timeout = timeout;
+ srm->ip4_max_frag = max_frag;
+ srm->ip4_drop_frag = drop_frag;
+ }
+
+ return 0;
+}
+
+u32
+nat_reass_get_timeout (u8 is_ip6)
+{
+ nat_reass_main_t *srm = &nat_reass_main;
+
+ if (is_ip6)
+ return srm->ip6_timeout;
+
+ return srm->ip4_timeout;
+}
+
+u16
+nat_reass_get_max_reass (u8 is_ip6)
+{
+ nat_reass_main_t *srm = &nat_reass_main;
+
+ if (is_ip6)
+ return srm->ip6_max_reass;
+
+ return srm->ip4_max_reass;
+}
+
+u8
+nat_reass_get_max_frag (u8 is_ip6)
+{
+ nat_reass_main_t *srm = &nat_reass_main;
+
+ if (is_ip6)
+ return srm->ip6_max_frag;
+
+ return srm->ip4_max_frag;
+}
+
+u8
+nat_reass_is_drop_frag (u8 is_ip6)
+{
+ nat_reass_main_t *srm = &nat_reass_main;
+
+ if (is_ip6)
+ return srm->ip6_drop_frag;
+
+ return srm->ip4_drop_frag;
+}
+
+static_always_inline nat_reass_ip4_t *
+nat_ip4_reass_lookup (nat_reass_ip4_key_t * k, f64 now)
+{
+ nat_reass_main_t *srm = &nat_reass_main;
+ clib_bihash_kv_16_8_t kv, value;
+ nat_reass_ip4_t *reass;
+
+ kv.key[0] = k->as_u64[0];
+ kv.key[1] = k->as_u64[1];
+
+ if (clib_bihash_search_16_8 (&srm->ip4_reass_hash, &kv, &value))
+ return 0;
+
+ reass = pool_elt_at_index (srm->ip4_reass_pool, value.value);
+ if (now < reass->last_heard + (f64) srm->ip4_timeout)
+ return reass;
+
+ return 0;
+}
+
+nat_reass_ip4_t *
+nat_ip4_reass_find_or_create (ip4_address_t src, ip4_address_t dst,
+ u16 frag_id, u8 proto, u8 reset_timeout,
+ u32 ** bi_to_drop)
+{
+ nat_reass_main_t *srm = &nat_reass_main;
+ nat_reass_ip4_t *reass = 0;
+ nat_reass_ip4_key_t k;
+ f64 now = vlib_time_now (srm->vlib_main);
+ dlist_elt_t *oldest_elt, *elt;
+ dlist_elt_t *per_reass_list_head_elt;
+ u32 oldest_index, elt_index;
+ clib_bihash_kv_16_8_t kv;
+
+ k.src.as_u32 = src.as_u32;
+ k.dst.as_u32 = dst.as_u32;
+ k.frag_id = frag_id;
+ k.proto = proto;
+
+ clib_spinlock_lock_if_init (&srm->ip4_reass_lock);
+
+ reass = nat_ip4_reass_lookup (&k, now);
+ if (reass)
+ {
+ if (reset_timeout)
+ {
+ reass->last_heard = now;
+ clib_dlist_remove (srm->ip4_reass_lru_list_pool,
+ reass->lru_list_index);
+ clib_dlist_addtail (srm->ip4_reass_lru_list_pool,
+ srm->ip4_reass_head_index,
+ reass->lru_list_index);
+ }
+ goto unlock;
+ }
+
+ if (srm->ip4_reass_n >= srm->ip4_max_reass)
+ {
+ oldest_index =
+ clib_dlist_remove_head (srm->ip4_reass_lru_list_pool,
+ srm->ip4_reass_head_index);
+ ASSERT (oldest_index != ~0);
+ oldest_elt =
+ pool_elt_at_index (srm->ip4_reass_lru_list_pool, oldest_index);
+ reass = pool_elt_at_index (srm->ip4_reass_pool, oldest_elt->value);
+ if (now < reass->last_heard + (f64) srm->ip4_timeout)
+ {
+ clib_dlist_addhead (srm->ip4_reass_lru_list_pool,
+ srm->ip4_reass_head_index, oldest_index);
+ clib_warning ("no free resassembly slot");
+ reass = 0;
+ goto unlock;
+ }
+
+ clib_dlist_addtail (srm->ip4_reass_lru_list_pool,
+ srm->ip4_reass_head_index, oldest_index);
+
+ kv.key[0] = k.as_u64[0];
+ kv.key[1] = k.as_u64[1];
+ if (clib_bihash_add_del_16_8 (&srm->ip4_reass_hash, &kv, 0))
+ {
+ reass = 0;
+ goto unlock;
+ }
+
+ nat_ip4_reass_get_frags_inline (reass, bi_to_drop);
+ }
+ else
+ {
+ pool_get (srm->ip4_reass_pool, reass);
+ pool_get (srm->ip4_reass_lru_list_pool, elt);
+ reass->lru_list_index = elt_index = elt - srm->ip4_reass_lru_list_pool;
+ clib_dlist_init (srm->ip4_reass_lru_list_pool, elt_index);
+ elt->value = reass - srm->ip4_reass_pool;
+ clib_dlist_addtail (srm->ip4_reass_lru_list_pool,
+ srm->ip4_reass_head_index, elt_index);
+ pool_get (srm->ip4_frags_list_pool, per_reass_list_head_elt);
+ reass->frags_per_reass_list_head_index =
+ per_reass_list_head_elt - srm->ip4_frags_list_pool;
+ clib_dlist_init (srm->ip4_frags_list_pool,
+ reass->frags_per_reass_list_head_index);
+ srm->ip4_reass_n++;
+ }
+
+ reass->key.as_u64[0] = kv.key[0] = k.as_u64[0];
+ reass->key.as_u64[1] = kv.key[1] = k.as_u64[1];
+ kv.value = reass - srm->ip4_reass_pool;
+ reass->sess_index = (u32) ~ 0;
+ reass->last_heard = now;
+
+ if (clib_bihash_add_del_16_8 (&srm->ip4_reass_hash, &kv, 1))
+ {
+ reass = 0;
+ goto unlock;
+ }
+
+unlock:
+ clib_spinlock_unlock_if_init (&srm->ip4_reass_lock);
+ return reass;
+}
+
+int
+nat_ip4_reass_add_fragment (nat_reass_ip4_t * reass, u32 bi)
+{
+ nat_reass_main_t *srm = &nat_reass_main;
+ dlist_elt_t *elt;
+ u32 elt_index;
+
+ if (reass->frag_n >= srm->ip4_max_frag)
+ return -1;
+
+ clib_spinlock_lock_if_init (&srm->ip4_reass_lock);
+
+ pool_get (srm->ip4_frags_list_pool, elt);
+ elt_index = elt - srm->ip4_frags_list_pool;
+ clib_dlist_init (srm->ip4_frags_list_pool, elt_index);
+ elt->value = bi;
+ clib_dlist_addtail (srm->ip4_frags_list_pool,
+ reass->frags_per_reass_list_head_index, elt_index);
+ reass->frag_n++;
+
+ clib_spinlock_unlock_if_init (&srm->ip4_reass_lock);
+
+ return 0;
+}
+
+void
+nat_ip4_reass_get_frags (nat_reass_ip4_t * reass, u32 ** bi)
+{
+ nat_reass_main_t *srm = &nat_reass_main;
+
+ clib_spinlock_lock_if_init (&srm->ip4_reass_lock);
+
+ nat_ip4_reass_get_frags_inline (reass, bi);
+
+ clib_spinlock_unlock_if_init (&srm->ip4_reass_lock);
+}
+
+void
+nat_ip4_reass_walk (nat_ip4_reass_walk_fn_t fn, void *ctx)
+{
+ nat_reass_ip4_t *reass;
+ nat_reass_main_t *srm = &nat_reass_main;
+ f64 now = vlib_time_now (srm->vlib_main);
+
+ /* *INDENT-OFF* */
+ pool_foreach (reass, srm->ip4_reass_pool,
+ ({
+ if (now < reass->last_heard + (f64) srm->ip4_timeout)
+ {
+ if (fn (reass, ctx))
+ return;
+ }
+ }));
+ /* *INDENT-ON* */
+}
+
+static_always_inline nat_reass_ip6_t *
+nat_ip6_reass_lookup (nat_reass_ip6_key_t * k, f64 now)
+{
+ nat_reass_main_t *srm = &nat_reass_main;
+ clib_bihash_kv_48_8_t kv, value;
+ nat_reass_ip6_t *reass;
+
+ k->unused = 0;
+ kv.key[0] = k->as_u64[0];
+ kv.key[1] = k->as_u64[1];
+ kv.key[2] = k->as_u64[2];
+ kv.key[3] = k->as_u64[3];
+ kv.key[4] = k->as_u64[4];
+ kv.key[5] = k->as_u64[5];
+
+ if (clib_bihash_search_48_8 (&srm->ip6_reass_hash, &kv, &value))
+ return 0;
+
+ reass = pool_elt_at_index (srm->ip6_reass_pool, value.value);
+ if (now < reass->last_heard + (f64) srm->ip6_timeout)
+ return reass;
+
+ return 0;
+}
+
+nat_reass_ip6_t *
+nat_ip6_reass_find_or_create (ip6_address_t src, ip6_address_t dst,
+ u32 frag_id, u8 proto, u8 reset_timeout,
+ u32 ** bi_to_drop)
+{
+ nat_reass_main_t *srm = &nat_reass_main;
+ nat_reass_ip6_t *reass = 0;
+ nat_reass_ip6_key_t k;
+ f64 now = vlib_time_now (srm->vlib_main);
+ dlist_elt_t *oldest_elt, *elt;
+ dlist_elt_t *per_reass_list_head_elt;
+ u32 oldest_index, elt_index;
+ clib_bihash_kv_48_8_t kv;
+
+ k.src.as_u64[0] = src.as_u64[0];
+ k.src.as_u64[1] = src.as_u64[1];
+ k.dst.as_u64[0] = dst.as_u64[0];
+ k.dst.as_u64[1] = dst.as_u64[1];
+ k.frag_id = frag_id;
+ k.proto = proto;
+ k.unused = 0;
+
+ clib_spinlock_lock_if_init (&srm->ip6_reass_lock);
+
+ reass = nat_ip6_reass_lookup (&k, now);
+ if (reass)
+ {
+ if (reset_timeout)
+ {
+ reass->last_heard = now;
+ clib_dlist_remove (srm->ip6_reass_lru_list_pool,
+ reass->lru_list_index);
+ clib_dlist_addtail (srm->ip6_reass_lru_list_pool,
+ srm->ip6_reass_head_index,
+ reass->lru_list_index);
+ }
+ goto unlock;
+ }
+
+ if (srm->ip6_reass_n >= srm->ip6_max_reass)
+ {
+ oldest_index =
+ clib_dlist_remove_head (srm->ip6_reass_lru_list_pool,
+ srm->ip6_reass_head_index);
+ ASSERT (oldest_index != ~0);
+ oldest_elt =
+ pool_elt_at_index (srm->ip4_reass_lru_list_pool, oldest_index);
+ reass = pool_elt_at_index (srm->ip6_reass_pool, oldest_elt->value);
+ if (now < reass->last_heard + (f64) srm->ip6_timeout)
+ {
+ clib_dlist_addhead (srm->ip6_reass_lru_list_pool,
+ srm->ip6_reass_head_index, oldest_index);
+ clib_warning ("no free resassembly slot");
+ reass = 0;
+ goto unlock;
+ }
+
+ clib_dlist_addtail (srm->ip6_reass_lru_list_pool,
+ srm->ip6_reass_head_index, oldest_index);
+
+ kv.key[0] = k.as_u64[0];
+ kv.key[1] = k.as_u64[1];
+ kv.key[2] = k.as_u64[2];
+ kv.key[3] = k.as_u64[4];
+ kv.key[4] = k.as_u64[5];
+ if (clib_bihash_add_del_48_8 (&srm->ip6_reass_hash, &kv, 0))
+ {
+ reass = 0;
+ goto unlock;
+ }
+
+ nat_ip6_reass_get_frags_inline (reass, bi_to_drop);
+ }
+ else
+ {
+ pool_get (srm->ip6_reass_pool, reass);
+ pool_get (srm->ip6_reass_lru_list_pool, elt);
+ reass->lru_list_index = elt_index = elt - srm->ip6_reass_lru_list_pool;
+ clib_dlist_init (srm->ip6_reass_lru_list_pool, elt_index);
+ elt->value = reass - srm->ip6_reass_pool;
+ clib_dlist_addtail (srm->ip6_reass_lru_list_pool,
+ srm->ip6_reass_head_index, elt_index);
+ pool_get (srm->ip6_frags_list_pool, per_reass_list_head_elt);
+ reass->frags_per_reass_list_head_index =
+ per_reass_list_head_elt - srm->ip6_frags_list_pool;
+ clib_dlist_init (srm->ip6_frags_list_pool,
+ reass->frags_per_reass_list_head_index);
+ srm->ip6_reass_n++;
+ }
+
+ reass->key.as_u64[0] = kv.key[0] = k.as_u64[0];
+ reass->key.as_u64[1] = kv.key[1] = k.as_u64[1];
+ reass->key.as_u64[2] = kv.key[2] = k.as_u64[2];
+ reass->key.as_u64[3] = kv.key[3] = k.as_u64[3];
+ reass->key.as_u64[4] = kv.key[4] = k.as_u64[4];
+ reass->key.as_u64[5] = kv.key[5] = k.as_u64[5];
+ kv.value = reass - srm->ip6_reass_pool;
+ reass->sess_index = (u32) ~ 0;
+ reass->last_heard = now;
+
+ if (clib_bihash_add_del_48_8 (&srm->ip6_reass_hash, &kv, 1))
+ {
+ reass = 0;
+ goto unlock;
+ }
+
+unlock:
+ clib_spinlock_unlock_if_init (&srm->ip6_reass_lock);
+ return reass;
+}
+
+int
+nat_ip6_reass_add_fragment (nat_reass_ip6_t * reass, u32 bi)
+{
+ nat_reass_main_t *srm = &nat_reass_main;
+ dlist_elt_t *elt;
+ u32 elt_index;
+
+ if (reass->frag_n >= srm->ip6_max_frag)
+ return -1;
+
+ clib_spinlock_lock_if_init (&srm->ip6_reass_lock);
+
+ pool_get (srm->ip6_frags_list_pool, elt);
+ elt_index = elt - srm->ip6_frags_list_pool;
+ clib_dlist_init (srm->ip6_frags_list_pool, elt_index);
+ elt->value = bi;
+ clib_dlist_addtail (srm->ip6_frags_list_pool,
+ reass->frags_per_reass_list_head_index, elt_index);
+ reass->frag_n++;
+
+ clib_spinlock_unlock_if_init (&srm->ip6_reass_lock);
+
+ return 0;
+}
+
+void
+nat_ip6_reass_get_frags (nat_reass_ip6_t * reass, u32 ** bi)
+{
+ nat_reass_main_t *srm = &nat_reass_main;
+
+ clib_spinlock_lock_if_init (&srm->ip6_reass_lock);
+
+ nat_ip6_reass_get_frags_inline (reass, bi);
+
+ clib_spinlock_unlock_if_init (&srm->ip6_reass_lock);
+}
+
+void
+nat_ip6_reass_walk (nat_ip6_reass_walk_fn_t fn, void *ctx)
+{
+ nat_reass_ip6_t *reass;
+ nat_reass_main_t *srm = &nat_reass_main;
+ f64 now = vlib_time_now (srm->vlib_main);
+
+ /* *INDENT-OFF* */
+ pool_foreach (reass, srm->ip6_reass_pool,
+ ({
+ if (now < reass->last_heard + (f64) srm->ip4_timeout)
+ {
+ if (fn (reass, ctx))
+ return;
+ }
+ }));
+ /* *INDENT-ON* */
+}
+
+clib_error_t *
+nat_reass_init (vlib_main_t * vm)
+{
+ nat_reass_main_t *srm = &nat_reass_main;
+ vlib_thread_main_t *tm = vlib_get_thread_main ();
+ clib_error_t *error = 0;
+ dlist_elt_t *head;
+ u32 nbuckets, head_index;
+
+ srm->vlib_main = vm;
+ srm->vnet_main = vnet_get_main ();
+
+ /* IPv4 */
+ srm->ip4_timeout = NAT_REASS_TIMEOUT_DEFAULT;
+ srm->ip4_max_reass = NAT_MAX_REASS_DEAFULT;
+ srm->ip4_max_frag = NAT_MAX_FRAG_DEFAULT;
+ srm->ip4_drop_frag = 0;
+ srm->ip4_reass_n = 0;
+
+ if (tm->n_vlib_mains > 1)
+ clib_spinlock_init (&srm->ip4_reass_lock);
+
+ pool_alloc (srm->ip4_reass_pool, srm->ip4_max_reass);
+
+ nbuckets = nat_reass_get_nbuckets (0);
+ clib_bihash_init_16_8 (&srm->ip4_reass_hash, "nat-ip4-reass", nbuckets,
+ nbuckets * 1024);
+
+ pool_get (srm->ip4_reass_lru_list_pool, head);
+ srm->ip4_reass_head_index = head_index =
+ head - srm->ip4_reass_lru_list_pool;
+ clib_dlist_init (srm->ip4_reass_lru_list_pool, head_index);
+
+ /* IPv6 */
+ srm->ip6_timeout = NAT_REASS_TIMEOUT_DEFAULT;
+ srm->ip6_max_reass = NAT_MAX_REASS_DEAFULT;
+ srm->ip6_max_frag = NAT_MAX_FRAG_DEFAULT;
+ srm->ip6_drop_frag = 0;
+ srm->ip6_reass_n = 0;
+
+ if (tm->n_vlib_mains > 1)
+ clib_spinlock_init (&srm->ip6_reass_lock);
+
+ pool_alloc (srm->ip6_reass_pool, srm->ip6_max_reass);
+
+ nbuckets = nat_reass_get_nbuckets (1);
+ clib_bihash_init_48_8 (&srm->ip6_reass_hash, "nat-ip6-reass", nbuckets,
+ nbuckets * 1024);
+
+ pool_get (srm->ip6_reass_lru_list_pool, head);
+ srm->ip6_reass_head_index = head_index =
+ head - srm->ip6_reass_lru_list_pool;
+ clib_dlist_init (srm->ip6_reass_lru_list_pool, head_index);
+
+ return error;
+}
+
+static clib_error_t *
+nat_reass_command_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ clib_error_t *error = 0;
+ unformat_input_t _line_input, *line_input = &_line_input;
+ u32 timeout = 0, max_reass = 0, max_frag = 0;
+ u8 drop_frag = (u8) ~ 0, is_ip6 = 0;
+ int rv;
+
+ /* Get a line of input. */
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return 0;
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "max-reassemblies %u", &max_reass))
+ ;
+ else if (unformat (line_input, "max-fragments %u", &max_frag))
+ ;
+ else if (unformat (line_input, "timeout %u", &timeout))
+ ;
+ else if (unformat (line_input, "enable"))
+ drop_frag = 0;
+ else if (unformat (line_input, "disable"))
+ drop_frag = 1;
+ else if (unformat (line_input, "ip4"))
+ is_ip6 = 0;
+ else if (unformat (line_input, "ip6"))
+ is_ip6 = 1;
+ else
+ {
+ error = clib_error_return (0, "unknown input '%U'",
+ format_unformat_error, line_input);
+ goto done;
+ }
+ }
+
+ if (!timeout)
+ timeout = nat_reass_get_timeout (is_ip6);
+ if (!max_reass)
+ max_reass = nat_reass_get_max_reass (is_ip6);
+ if (!max_frag)
+ max_frag = nat_reass_get_max_frag (is_ip6);
+ if (drop_frag == (u8) ~ 0)
+ drop_frag = nat_reass_is_drop_frag (is_ip6);
+
+ rv =
+ nat_reass_set (timeout, (u16) max_reass, (u8) max_frag, drop_frag,
+ is_ip6);
+ if (rv)
+ {
+ error = clib_error_return (0, "nat_set_reass return %d", rv);
+ goto done;
+ }
+
+done:
+ unformat_free (line_input);
+
+ return error;
+}
+
+static int
+nat_ip4_reass_walk_cli (nat_reass_ip4_t * reass, void *ctx)
+{
+ vlib_main_t *vm = ctx;
+
+ vlib_cli_output (vm, " src %U dst %U proto %u id 0x%04x cached %u",
+ format_ip4_address, &reass->key.src,
+ format_ip4_address, &reass->key.dst,
+ reass->key.proto,
+ clib_net_to_host_u16 (reass->key.frag_id), reass->frag_n);
+
+ return 0;
+}
+
+static int
+nat_ip6_reass_walk_cli (nat_reass_ip6_t * reass, void *ctx)
+{
+ vlib_main_t *vm = ctx;
+
+ vlib_cli_output (vm, " src %U dst %U proto %u id 0x%08x cached %u",
+ format_ip6_address, &reass->key.src,
+ format_ip6_address, &reass->key.dst,
+ reass->key.proto,
+ clib_net_to_host_u32 (reass->key.frag_id), reass->frag_n);
+
+ return 0;
+}
+
+static clib_error_t *
+show_nat_reass_command_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ vlib_cli_output (vm, "NAT IPv4 virtual fragmentation reassembly is %s",
+ nat_reass_is_drop_frag (0) ? "DISABLED" : "ENABLED");
+ vlib_cli_output (vm, " max-reasssemblies %u", nat_reass_get_max_reass (0));
+ vlib_cli_output (vm, " max-fragments %u", nat_reass_get_max_frag (0));
+ vlib_cli_output (vm, " timeout %usec", nat_reass_get_timeout (0));
+ vlib_cli_output (vm, " reassemblies:");
+ nat_ip4_reass_walk (nat_ip4_reass_walk_cli, vm);
+
+ vlib_cli_output (vm, "NAT IPv6 virtual fragmentation reassembly is %s",
+ nat_reass_is_drop_frag (1) ? "DISABLED" : "ENABLED");
+ vlib_cli_output (vm, " max-reasssemblies %u", nat_reass_get_max_reass (1));
+ vlib_cli_output (vm, " max-fragments %u", nat_reass_get_max_frag (1));
+ vlib_cli_output (vm, " timeout %usec", nat_reass_get_timeout (1));
+ vlib_cli_output (vm, " reassemblies:");
+ nat_ip6_reass_walk (nat_ip6_reass_walk_cli, vm);
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (nat_reass_command, static) =
+{
+ .path = "nat virtual-reassembly",
+ .short_help = "nat virtual-reassembly ip4|ip6 [max-reassemblies <n>] "
+ "[max-fragments <n>] [timeout <sec>] [enable|disable]",
+ .function = nat_reass_command_fn,
+};
+
+VLIB_CLI_COMMAND (show_nat_reass_command, static) =
+{
+ .path = "show nat virtual-reassembly",
+ .short_help = "show nat virtual-reassembly",
+ .function = show_nat_reass_command_fn,
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */