nat: VRF routing & FIB improvements
[vpp.git] / src / plugins / nat / nat44-ed / nat44_ed_cli.c
index 9b3480c..bddd635 100644 (file)
@@ -38,23 +38,15 @@ nat44_ed_enable_disable_command_fn (vlib_main_t *vm, unformat_input_t *input,
   clib_error_t *error = 0;
 
   nat44_config_t c = { 0 };
-  u8 enable_set = 0, enable = 0, mode_set = 0;
+  u8 enable_set = 0, enable = 0;
 
   if (!unformat_user (input, unformat_line_input, line_input))
     return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT);
 
   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     {
-      if (!mode_set && unformat (line_input, "static-mapping-only"))
-       {
-         mode_set = 1;
-         c.static_mapping_only = 1;
-         if (unformat (line_input, "connection-tracking"))
-           {
-             c.connection_tracking = 1;
-           }
-       }
-      else if (unformat (line_input, "inside-vrf %u", &c.inside_vrf));
+      if (unformat (line_input, "inside-vrf %u", &c.inside_vrf))
+       ;
       else if (unformat (line_input, "outside-vrf %u", &c.outside_vrf));
       else if (unformat (line_input, "sessions %u", &c.sessions));
       else if (!enable_set)
@@ -162,8 +154,8 @@ done:
 }
 
 static clib_error_t *
-nat_show_workers_commnad_fn (vlib_main_t * vm, unformat_input_t * input,
-                            vlib_cli_command_t * cmd)
+nat_show_workers_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                            vlib_cli_command_t *cmd)
 {
   snat_main_t *sm = &snat_main;
   u32 *worker;
@@ -283,12 +275,7 @@ nat44_show_hash_command_fn (vlib_main_t * vm, unformat_input_t * input,
   else if (unformat (input, "verbose"))
     verbose = 2;
 
-  vlib_cli_output (vm, "%U", format_bihash_8_8, &sm->static_mapping_by_local,
-                  verbose);
-  vlib_cli_output (vm, "%U",
-                  format_bihash_8_8, &sm->static_mapping_by_external,
-                  verbose);
-      vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->flow_hash, verbose);
+  vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->flow_hash, verbose);
   vec_foreach_index (i, sm->per_thread_data)
   {
     vlib_cli_output (vm, "-------- thread %d %s --------\n",
@@ -296,8 +283,7 @@ nat44_show_hash_command_fn (vlib_main_t * vm, unformat_input_t * input,
     vlib_cli_output (vm, "%U", format_bihash_16_8, &sm->flow_hash, verbose);
   }
 
-      vlib_cli_output (vm, "%U", format_bihash_16_8, &nam->affinity_hash,
-                      verbose);
+  vlib_cli_output (vm, "%U", format_bihash_16_8, &nam->affinity_hash, verbose);
 
   vlib_cli_output (vm, "-------- hash table parameters --------\n");
   vlib_cli_output (vm, "translation buckets: %u", sm->translation_buckets);
@@ -356,7 +342,6 @@ add_address_command_fn (vlib_main_t * vm,
                        unformat_input_t * input, vlib_cli_command_t * cmd)
 {
   unformat_input_t _line_input, *line_input = &_line_input;
-  snat_main_t *sm = &snat_main;
   ip4_address_t start_addr, end_addr, this_addr;
   u32 start_host_order, end_host_order;
   u32 vrf_id = ~0;
@@ -392,12 +377,6 @@ add_address_command_fn (vlib_main_t * vm,
        }
     }
 
-  if (sm->static_mapping_only)
-    {
-      error = clib_error_return (0, "static mapping only mode");
-      goto done;
-    }
-
   start_host_order = clib_host_to_net_u32 (start_addr.as_u32);
   end_host_order = clib_host_to_net_u32 (end_addr.as_u32);
 
@@ -419,9 +398,13 @@ add_address_command_fn (vlib_main_t * vm,
   for (i = 0; i < count; i++)
     {
       if (is_add)
-       rv = snat_add_address (sm, &this_addr, vrf_id, twice_nat);
+       {
+         rv = nat44_ed_add_address (&this_addr, vrf_id, twice_nat);
+       }
       else
-       rv = snat_del_address (sm, this_addr, 0, twice_nat);
+       {
+         rv = nat44_ed_del_address (this_addr, twice_nat);
+       }
 
       switch (rv)
        {
@@ -495,15 +478,12 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
   u64 now = vlib_time_now (vm);
   u64 sess_timeout_time = 0;
 
-  u32 udp_sessions = 0;
-  u32 tcp_sessions = 0;
-  u32 icmp_sessions = 0;
-
-  u32 timed_out = 0;
-  u32 transitory = 0;
-  u32 transitory_wait_closed = 0;
-  u32 transitory_closed = 0;
-  u32 established = 0;
+  struct
+  {
+    u32 total;
+    u32 timed_out;
+  } udp = { 0 }, tcp = { 0 }, tcp_established = { 0 }, tcp_transitory = { 0 },
+    icmp = { 0 }, other = { 0 };
 
   u32 fib;
 
@@ -517,45 +497,48 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
         {
           pool_foreach (s, tsm->sessions)
            {
-            sess_timeout_time = s->last_heard +
-             (f64) nat44_session_get_timeout (sm, s);
-            if (now >= sess_timeout_time)
-              timed_out++;
-
-            switch (s->nat_proto)
-              {
-              case NAT_PROTOCOL_ICMP:
-                icmp_sessions++;
-                break;
-              case NAT_PROTOCOL_TCP:
-                tcp_sessions++;
-                if (s->state)
-                  {
-                    if (s->tcp_closed_timestamp)
-                      {
-                        if (now >= s->tcp_closed_timestamp)
-                          {
-                            ++transitory_closed;
-                          }
-                        else
-                          {
-                            ++transitory_wait_closed;
-                          }
-                      }
-                    transitory++;
-                  }
-                else
-                  established++;
-                break;
-              case NAT_PROTOCOL_UDP:
-              default:
-                udp_sessions++;
-                break;
-              }
-          }
-          nat44_show_lru_summary (vm, tsm, now, sess_timeout_time);
-          count += pool_elts (tsm->sessions);
-        }
+            sess_timeout_time =
+              s->last_heard + (f64) nat44_session_get_timeout (sm, s);
+
+            switch (s->proto)
+              {
+              case IP_PROTOCOL_ICMP:
+                ++icmp.total;
+                if (now >= sess_timeout_time)
+                  ++icmp.timed_out;
+                break;
+              case IP_PROTOCOL_TCP:
+                ++tcp.total;
+                if (now >= sess_timeout_time)
+                  ++tcp.timed_out;
+                if (nat44_ed_tcp_is_established (s->tcp_state))
+                  {
+                    ++tcp_established.total;
+                    if (now >= sess_timeout_time)
+                      ++tcp_established.timed_out;
+                  }
+                else
+                  {
+                    ++tcp_transitory.total;
+                    if (now >= sess_timeout_time)
+                      ++tcp_transitory.timed_out;
+                  }
+                break;
+              case IP_PROTOCOL_UDP:
+                ++udp.total;
+                if (now >= sess_timeout_time)
+                  ++udp.timed_out;
+                break;
+              default:
+                ++other.total;
+                if (now >= sess_timeout_time)
+                  ++other.timed_out;
+                break;
+              }
+          }
+         nat44_show_lru_summary (vm, tsm, now, sess_timeout_time);
+         count += pool_elts (tsm->sessions);
+       }
     }
   else
     {
@@ -564,55 +547,66 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
        {
         sess_timeout_time = s->last_heard +
            (f64) nat44_session_get_timeout (sm, s);
-        if (now >= sess_timeout_time)
-          timed_out++;
-
-        switch (s->nat_proto)
-          {
-          case NAT_PROTOCOL_ICMP:
-            icmp_sessions++;
-            break;
-          case NAT_PROTOCOL_TCP:
-            tcp_sessions++;
-            if (s->state)
-              {
-                if (s->tcp_closed_timestamp)
-                  {
-                    if (now >= s->tcp_closed_timestamp)
-                      {
-                        ++transitory_closed;
-                      }
-                    else
-                      {
-                        ++transitory_wait_closed;
-                      }
-                  }
-                transitory++;
-              }
-            else
-              established++;
-            break;
-          case NAT_PROTOCOL_UDP:
-          default:
-            udp_sessions++;
-            break;
-          }
+
+       switch (s->proto)
+         {
+         case IP_PROTOCOL_ICMP:
+           ++icmp.total;
+           if (now >= sess_timeout_time)
+             ++icmp.timed_out;
+           break;
+         case IP_PROTOCOL_TCP:
+           ++tcp.total;
+           if (now >= sess_timeout_time)
+             ++tcp.timed_out;
+           if (nat44_ed_tcp_is_established (s->tcp_state))
+             {
+               ++tcp_established.total;
+               if (now >= sess_timeout_time)
+                 ++tcp_established.timed_out;
+             }
+           else
+             {
+               ++tcp_transitory.total;
+               if (now >= sess_timeout_time)
+                 ++tcp_transitory.timed_out;
+             }
+           break;
+         case IP_PROTOCOL_UDP:
+           ++udp.total;
+           if (now >= sess_timeout_time)
+             ++udp.timed_out;
+           break;
+         default:
+           ++other.total;
+           if (now >= sess_timeout_time)
+             ++other.timed_out;
+           break;
+         }
       }
       nat44_show_lru_summary (vm, tsm, now, sess_timeout_time);
       count = pool_elts (tsm->sessions);
     }
 
-  vlib_cli_output (vm, "total timed out sessions: %u", timed_out);
-  vlib_cli_output (vm, "total sessions: %u", count);
-  vlib_cli_output (vm, "total tcp sessions: %u", tcp_sessions);
-  vlib_cli_output (vm, "total tcp established sessions: %u", established);
-  vlib_cli_output (vm, "total tcp transitory sessions: %u", transitory);
-  vlib_cli_output (vm, "total tcp transitory (WAIT-CLOSED) sessions: %u",
-                  transitory_wait_closed);
-  vlib_cli_output (vm, "total tcp transitory (CLOSED) sessions: %u",
-                  transitory_closed);
-  vlib_cli_output (vm, "total udp sessions: %u", udp_sessions);
-  vlib_cli_output (vm, "total icmp sessions: %u", icmp_sessions);
+  u32 timed_out =
+    tcp.timed_out + icmp.timed_out + udp.timed_out + other.timed_out;
+  vlib_cli_output (vm, "total sessions: %u (timed out: %u)", count, timed_out);
+  vlib_cli_output (vm, "tcp sessions:");
+  vlib_cli_output (vm, "    total: %u (timed out: %u)", tcp.total,
+                  tcp.timed_out);
+  vlib_cli_output (vm, "        established: %u (timed out: %u)",
+                  tcp_established.total, tcp_established.timed_out);
+  vlib_cli_output (vm, "        transitory: %u (timed out: %u)",
+                  tcp_transitory.total, tcp_transitory.timed_out);
+  vlib_cli_output (vm, "udp sessions:");
+  vlib_cli_output (vm, "    total: %u (timed out: %u)", udp.total,
+                  udp.timed_out);
+  vlib_cli_output (vm, "icmp sessions:");
+  vlib_cli_output (vm, "    total: %u (timed out: %u)", icmp.total,
+                  icmp.timed_out);
+  vlib_cli_output (vm, "other sessions:");
+  vlib_cli_output (vm, "    total: %u (timed out: %u)", other.total,
+                  other.timed_out);
   return 0;
 }
 
@@ -628,14 +622,14 @@ nat44_show_addresses_command_fn (vlib_main_t * vm, unformat_input_t * input,
     {
       vlib_cli_output (vm, "%U", format_ip4_address, &ap->addr);
       if (ap->fib_index != ~0)
-          vlib_cli_output (vm, "  tenant VRF: %u",
-            fib_table_get(ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id);
+       vlib_cli_output (
+         vm, "  tenant VRF: %u",
+         fib_table_get (ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id);
       else
         vlib_cli_output (vm, "  tenant VRF independent");
-    #define _(N, i, n, s) \
-      vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
-      foreach_nat_protocol
-    #undef _
+
+      if (ap->addr_len != ~0)
+       vlib_cli_output (vm, "  synced with interface address");
     }
   vlib_cli_output (vm, "NAT44 twice-nat pool addresses:");
   vec_foreach (ap, sm->twice_nat_addresses)
@@ -646,10 +640,9 @@ nat44_show_addresses_command_fn (vlib_main_t * vm, unformat_input_t * input,
             fib_table_get(ap->fib_index, FIB_PROTOCOL_IP4)->ft_table_id);
       else
         vlib_cli_output (vm, "  tenant VRF independent");
-    #define _(N, i, n, s) \
-      vlib_cli_output (vm, "  %d busy %s ports", ap->busy_##n##_ports, s);
-      foreach_nat_protocol
-    #undef _
+
+      if (ap->addr_len != ~0)
+       vlib_cli_output (vm, "  synced with interface address");
     }
   return 0;
 }
@@ -804,21 +797,22 @@ nat44_show_interfaces_command_fn (vlib_main_t * vm, unformat_input_t * input,
   vlib_cli_output (vm, "NAT44 interfaces:");
   pool_foreach (i, sm->interfaces)
    {
-    vlib_cli_output (vm, " %U %s", format_vnet_sw_if_index_name, vnm,
-                     i->sw_if_index,
-                     (nat_interface_is_inside(i) &&
-                      nat_interface_is_outside(i)) ? "in out" :
-                     (nat_interface_is_inside(i) ? "in" : "out"));
+     vlib_cli_output (vm, " %U %s", format_vnet_sw_if_index_name, vnm,
+                     i->sw_if_index,
+                     (nat44_ed_is_interface_inside (i) &&
+                      nat44_ed_is_interface_outside (i)) ?
+                       "in out" :
+                       (nat44_ed_is_interface_inside (i) ? "in" : "out"));
   }
 
   pool_foreach (i, sm->output_feature_interfaces)
    {
-    vlib_cli_output (vm, " %U output-feature %s",
-                     format_vnet_sw_if_index_name, vnm,
-                     i->sw_if_index,
-                     (nat_interface_is_inside(i) &&
-                      nat_interface_is_outside(i)) ? "in out" :
-                     (nat_interface_is_inside(i) ? "in" : "out"));
+     vlib_cli_output (vm, " %U output-feature %s",
+                     format_vnet_sw_if_index_name, vnm, i->sw_if_index,
+                     (nat44_ed_is_interface_inside (i) &&
+                      nat44_ed_is_interface_outside (i)) ?
+                       "in out" :
+                       (nat44_ed_is_interface_inside (i) ? "in" : "out"));
   }
 
   return 0;
@@ -832,14 +826,13 @@ add_static_mapping_command_fn (vlib_main_t * vm,
   unformat_input_t _line_input, *line_input = &_line_input;
   vnet_main_t *vnm = vnet_get_main ();
   clib_error_t *error = 0;
-  int rv;
-
-  nat_protocol_t proto = NAT_PROTOCOL_OTHER;
   ip4_address_t l_addr, e_addr, pool_addr;
   u32 l_port = 0, e_port = 0, vrf_id = ~0;
   u8 l_port_set = 0, e_port_set = 0;
-  u32 sw_if_index, flags = 0;
-  int is_add = 1;
+  int is_add = 1, rv;
+  u32 flags = 0;
+  u32 sw_if_index = ~0;
+  ip_protocol_t proto = 0;
 
   if (!unformat_user (input, unformat_line_input, line_input))
     return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT);
@@ -881,7 +874,7 @@ add_static_mapping_command_fn (vlib_main_t * vm,
        }
       else if (unformat (line_input, "vrf %u", &vrf_id))
        ;
-      else if (unformat (line_input, "%U", unformat_nat_protocol, &proto))
+      else if (unformat (line_input, "%U", unformat_ip_protocol, &proto))
        ;
       else if (unformat (line_input, "self-twice-nat"))
        {
@@ -923,8 +916,6 @@ add_static_mapping_command_fn (vlib_main_t * vm,
       e_port = clib_host_to_net_u16 (e_port);
     }
 
-  // TODO: specific pool_addr for both pool & twice nat pool ?
-
   if (is_add)
     {
       rv =
@@ -937,25 +928,17 @@ add_static_mapping_command_fn (vlib_main_t * vm,
                                        vrf_id, sw_if_index, flags);
     }
 
-  // TODO: fix returns
-
   switch (rv)
     {
-    case VNET_API_ERROR_INVALID_VALUE:
-      error = clib_error_return (0, "External port already in use.");
-      goto done;
+    case VNET_API_ERROR_UNSUPPORTED:
+      error = clib_error_return (0, "Plugin disabled.");
+      break;
     case VNET_API_ERROR_NO_SUCH_ENTRY:
-      if (is_add)
-       error = clib_error_return (0, "External address must be allocated.");
-      else
-       error = clib_error_return (0, "Mapping not exist.");
-      goto done;
-    case VNET_API_ERROR_NO_SUCH_FIB:
-      error = clib_error_return (0, "No such VRF id.");
-      goto done;
+      error = clib_error_return (0, "Mapping not exist.");
+      break;
     case VNET_API_ERROR_VALUE_EXIST:
       error = clib_error_return (0, "Mapping already exist.");
-      goto done;
+      break;
     default:
       break;
     }
@@ -966,7 +949,6 @@ done:
   return error;
 }
 
-// TODO: either delete this bullshit or update it
 static clib_error_t *
 add_identity_mapping_command_fn (vlib_main_t * vm,
                                 unformat_input_t * input,
@@ -978,12 +960,11 @@ add_identity_mapping_command_fn (vlib_main_t * vm,
 
   int rv, is_add = 1, port_set = 0;
   u32 sw_if_index, port, flags, vrf_id = ~0;
-  nat_protocol_t proto;
+  ip_protocol_t proto = 0;
   ip4_address_t addr;
 
   flags = NAT_SM_FLAG_IDENTITY_NAT;
 
-  /* Get a line of input. */
   if (!unformat_user (input, unformat_line_input, line_input))
     return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT);
 
@@ -998,7 +979,7 @@ add_identity_mapping_command_fn (vlib_main_t * vm,
        }
       else if (unformat (line_input, "vrf %u", &vrf_id))
        ;
-      else if (unformat (line_input, "%U %u", unformat_nat_protocol, &proto,
+      else if (unformat (line_input, "%U %u", unformat_ip_protocol, &proto,
                         &port))
        {
          port_set = 1;
@@ -1036,25 +1017,17 @@ add_identity_mapping_command_fn (vlib_main_t * vm,
                                        sw_if_index, flags);
     }
 
-  // TODO: fix returns
-
   switch (rv)
     {
-    case VNET_API_ERROR_INVALID_VALUE:
-      error = clib_error_return (0, "External port already in use.");
-      goto done;
+    case VNET_API_ERROR_UNSUPPORTED:
+      error = clib_error_return (0, "Plugin disabled.");
+      break;
     case VNET_API_ERROR_NO_SUCH_ENTRY:
-      if (is_add)
-       error = clib_error_return (0, "External address must be allocated.");
-      else
-       error = clib_error_return (0, "Mapping not exist.");
-      goto done;
-    case VNET_API_ERROR_NO_SUCH_FIB:
-      error = clib_error_return (0, "No such VRF id.");
-      goto done;
+      error = clib_error_return (0, "Mapping not exist.");
+      break;
     case VNET_API_ERROR_VALUE_EXIST:
       error = clib_error_return (0, "Mapping already exist.");
-      goto done;
+      break;
     default:
       break;
     }
@@ -1075,12 +1048,11 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm,
   ip4_address_t l_addr, e_addr;
   u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0, affinity = 0;
   u8 proto_set = 0;
-  nat_protocol_t proto;
+  ip_protocol_t proto;
   nat44_lb_addr_port_t *locals = 0, local;
   int rv, is_add = 1;
   u32 flags = 0;
 
-  /* Get a line of input. */
   if (!unformat_user (input, unformat_line_input, line_input))
     return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT);
 
@@ -1109,7 +1081,7 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm,
       else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
                         &e_addr, &e_port))
        ;
-      else if (unformat (line_input, "protocol %U", unformat_nat_protocol,
+      else if (unformat (line_input, "protocol %U", unformat_ip_protocol,
                         &proto))
        {
          proto_set = 1;
@@ -1197,7 +1169,7 @@ add_lb_backend_command_fn (vlib_main_t * vm,
   u32 l_port = 0, e_port = 0, vrf_id = 0, probability = 0;
   int is_add = 1;
   int rv;
-  nat_protocol_t proto;
+  ip_protocol_t proto;
   u8 proto_set = 0;
 
   /* Get a line of input. */
@@ -1216,7 +1188,7 @@ add_lb_backend_command_fn (vlib_main_t * vm,
       else if (unformat (line_input, "external %U:%u", unformat_ip4_address,
                         &e_addr, &e_port))
        ;
-      else if (unformat (line_input, "protocol %U", unformat_nat_protocol,
+      else if (unformat (line_input, "protocol %U", unformat_ip_protocol,
                         &proto))
        proto_set = 1;
       else if (unformat (line_input, "del"))
@@ -1276,14 +1248,14 @@ nat44_show_static_mappings_command_fn (vlib_main_t * vm,
 {
   snat_main_t *sm = &snat_main;
   snat_static_mapping_t *m;
-  snat_static_map_resolve_t *rp;
+  snat_static_mapping_resolve_t *rp;
 
   vlib_cli_output (vm, "NAT44 static mappings:");
   pool_foreach (m, sm->static_mappings)
    {
     vlib_cli_output (vm, " %U", format_snat_static_mapping, m);
   }
-  vec_foreach (rp, sm->to_resolve)
+  vec_foreach (rp, sm->sm_to_resolve)
     vlib_cli_output (vm, " %U", format_snat_static_map_to_resolve, rp);
 
   return 0;
@@ -1294,15 +1266,13 @@ snat_add_interface_address_command_fn (vlib_main_t * vm,
                                       unformat_input_t * input,
                                       vlib_cli_command_t * cmd)
 {
-  snat_main_t *sm = &snat_main;
   unformat_input_t _line_input, *line_input = &_line_input;
-  u32 sw_if_index;
-  int rv;
-  int is_del = 0;
+  snat_main_t *sm = &snat_main;
   clib_error_t *error = 0;
+  int rv, is_del = 0;
   u8 twice_nat = 0;
+  u32 sw_if_index;
 
-  /* Get a line of input. */
   if (!unformat_user (input, unformat_line_input, line_input))
     return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT);
 
@@ -1312,9 +1282,13 @@ snat_add_interface_address_command_fn (vlib_main_t * vm,
                    sm->vnet_main, &sw_if_index))
        ;
       else if (unformat (line_input, "twice-nat"))
-       twice_nat = 1;
+       {
+         twice_nat = 1;
+       }
       else if (unformat (line_input, "del"))
-       is_del = 1;
+       {
+         is_del = 1;
+       }
       else
        {
          error = clib_error_return (0, "unknown input '%U'",
@@ -1323,25 +1297,179 @@ snat_add_interface_address_command_fn (vlib_main_t * vm,
        }
     }
 
-  rv = snat_add_interface_address (sm, sw_if_index, is_del, twice_nat);
+  if (!is_del)
+    {
+      rv = nat44_ed_add_interface_address (sw_if_index, twice_nat);
+      if (rv)
+       {
+         error = clib_error_return (0, "add address returned %d", rv);
+       }
+    }
+  else
+    {
+      rv = nat44_ed_del_interface_address (sw_if_index, twice_nat);
+      if (rv)
+       {
+         error = clib_error_return (0, "del address returned %d", rv);
+       }
+    }
 
-  switch (rv)
+done:
+  unformat_free (line_input);
+
+  return error;
+}
+
+static clib_error_t *
+nat44_ed_add_del_vrf_table_command_fn (vlib_main_t *vm,
+                                      unformat_input_t *input,
+                                      vlib_cli_command_t *cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  clib_error_t *error = 0;
+  bool is_add = true, not_set = true;
+  u32 vrf_id = ~0;
+  int rv;
+
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT);
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     {
-    case 0:
-      break;
+      if (unformat (line_input, "%u", &vrf_id))
+       ;
+      else if (not_set)
+       {
+         if (unformat (line_input, "add"))
+           {
+             is_add = true;
+           }
+         else if (unformat (line_input, "del"))
+           {
+             is_add = false;
+           }
+         not_set = false;
+       }
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
 
-    default:
-      error = clib_error_return (0, "snat_add_interface_address returned %d",
-                                rv);
+  if (not_set)
+    {
+      error = clib_error_return (0, "missing required parameter");
+      goto done;
+    }
+
+  if (~0 == vrf_id)
+    {
+      error = clib_error_return (0, "missing vrf id");
       goto done;
     }
 
+  rv = nat44_ed_add_del_vrf_table (vrf_id, is_add);
+  if (rv)
+    {
+      error = clib_error_return (0, "%s vrf table returned %d",
+                                is_add ? "add" : "del", rv);
+    }
+
 done:
   unformat_free (line_input);
 
   return error;
 }
 
+static clib_error_t *
+nat44_ed_add_del_vrf_route_command_fn (vlib_main_t *vm,
+                                      unformat_input_t *input,
+                                      vlib_cli_command_t *cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  clib_error_t *error = 0;
+  bool is_add = true, not_set = true;
+  u32 vrf_id = ~0, table_vrf_id = ~0;
+  int rv;
+
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return clib_error_return (0, NAT44_ED_EXPECTED_ARGUMENT);
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "table %u", &table_vrf_id))
+       ;
+      else if (unformat (line_input, "%u", &vrf_id))
+       ;
+      else if (not_set)
+       {
+         if (unformat (line_input, "add"))
+           {
+             is_add = true;
+           }
+         else if (unformat (line_input, "del"))
+           {
+             is_add = false;
+           }
+         not_set = false;
+       }
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  if (not_set)
+    {
+      error = clib_error_return (0, "missing required parameter");
+      goto done;
+    }
+
+  if ((~0 == vrf_id) || (~0 == table_vrf_id))
+    {
+      error = clib_error_return (0, "missing vrf id");
+      goto done;
+    }
+
+  rv = nat44_ed_add_del_vrf_route (table_vrf_id, vrf_id, is_add);
+  if (rv)
+    {
+      error = clib_error_return (0, "%s vrf table returned %d",
+                                is_add ? "add" : "del", rv);
+    }
+
+done:
+  unformat_free (line_input);
+
+  return error;
+}
+
+static clib_error_t *
+nat44_ed_show_vrf_tables_command_fn (vlib_main_t *vm, unformat_input_t *input,
+                                    vlib_cli_command_t *cmd)
+{
+  snat_main_t *sm = &snat_main;
+  vrf_table_t *t;
+  vrf_route_t *r;
+  int i = 0;
+
+  pool_foreach (t, sm->vrf_tables)
+    {
+      vlib_cli_output (vm, "table %u:", t->table_vrf_id);
+      pool_foreach (r, t->routes)
+       {
+         vlib_cli_output (vm, "[%u] vrf-id %u", i, r->vrf_id);
+         i++;
+       }
+    }
+
+  return 0;
+}
+
 static clib_error_t *
 nat44_show_interface_address_command_fn (vlib_main_t * vm,
                                         unformat_input_t * input,
@@ -1349,21 +1477,14 @@ nat44_show_interface_address_command_fn (vlib_main_t * vm,
 {
   snat_main_t *sm = &snat_main;
   vnet_main_t *vnm = vnet_get_main ();
-  u32 *sw_if_index;
+  snat_address_resolve_t *ap;
 
   vlib_cli_output (vm, "NAT44 pool address interfaces:");
-  vec_foreach (sw_if_index, sm->auto_add_sw_if_indices)
+  vec_foreach (ap, sm->addr_to_resolve)
     {
-      vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnm,
-                       *sw_if_index);
+      vlib_cli_output (vm, " %U%s", format_vnet_sw_if_index_name, vnm,
+                      ap->sw_if_index, ap->is_twice_nat ? " twice-nat" : "");
     }
-  vlib_cli_output (vm, "NAT44 twice-nat pool address interfaces:");
-  vec_foreach (sw_if_index, sm->auto_add_sw_if_indices_twice_nat)
-    {
-      vlib_cli_output (vm, " %U", format_vnet_sw_if_index_name, vnm,
-                       *sw_if_index);
-    }
-
   return 0;
 }
 
@@ -1375,22 +1496,61 @@ nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input,
   clib_error_t *error = 0;
   snat_main_per_thread_data_t *tsm;
   snat_main_t *sm = &snat_main;
-
-  int i = 0;
+  ip4_address_t i2o_sa, i2o_da, o2i_sa, o2i_da;
+  u8 filter_i2o_sa = 0, filter_i2o_da = 0;
+  u8 filter_o2i_sa = 0, filter_o2i_da = 0;
+  u16 i2o_sp, i2o_dp, o2i_sp, o2i_dp;
+  u8 filter_i2o_sp = 0, filter_i2o_dp = 0;
+  u8 filter_o2i_sp = 0, filter_o2i_dp = 0;
+  ip_protocol_t proto;
+  u8 filter_proto = 0;
+  u8 had_input = 1, filtering = 0;
+  int i = 0, showed_sessions;
 
   if (!unformat_user (input, unformat_line_input, line_input))
-    goto print;
+    {
+      had_input = 0;
+      goto print;
+    }
 
   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     {
-      error = clib_error_return (0, "unknown input '%U'",
-                                format_unformat_error, line_input);
-      break;
+      if (unformat (line_input, "filter i2o saddr %U", unformat_ip4_address,
+                   &i2o_sa))
+       filter_i2o_sa = filtering = 1;
+      else if (unformat (line_input, "filter i2o daddr %U",
+                        unformat_ip4_address, &i2o_da))
+       filter_i2o_da = filtering = 1;
+      else if (unformat (line_input, "filter o2i saddr %U",
+                        unformat_ip4_address, &o2i_sa))
+       filter_o2i_sa = filtering = 1;
+      else if (unformat (line_input, "filter o2i daddr %U",
+                        unformat_ip4_address, &o2i_da))
+       filter_o2i_da = filtering = 1;
+      else if (unformat (line_input, "filter i2o sport %u", &i2o_sp))
+       filter_i2o_sp = filtering = 1;
+      else if (unformat (line_input, "filter i2o dport %u", &i2o_dp))
+       filter_i2o_dp = filtering = 1;
+      else if (unformat (line_input, "filter o2i sport %u", &o2i_sp))
+       filter_o2i_sp = filtering = 1;
+      else if (unformat (line_input, "filter o2i dport %u", &o2i_dp))
+       filter_o2i_dp = filtering = 1;
+      else if (unformat (line_input, "filter i2o proto %U",
+                        unformat_ip_protocol, &proto))
+       filter_proto = filtering = 1;
+      else if (unformat (line_input, "filter o2i proto %U",
+                        unformat_ip_protocol, &proto))
+       filter_proto = filtering = 1;
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
     }
-  unformat_free (line_input);
 
 print:
-    vlib_cli_output (vm, "NAT44 ED sessions:");
+  vlib_cli_output (vm, "NAT44 ED sessions:");
 
   vec_foreach_index (i, sm->per_thread_data)
     {
@@ -1400,12 +1560,53 @@ print:
                        i, vlib_worker_threads[i].name,
                        pool_elts (tsm->sessions));
 
-          snat_session_t *s;
-          pool_foreach (s, tsm->sessions)
-           {
-            vlib_cli_output (vm, "  %U\n", format_snat_session, tsm, s);
-          }
+      showed_sessions = 0;
+      snat_session_t *s;
+      pool_foreach (s, tsm->sessions)
+       {
+         if (filtering)
+           {
+             if (filter_i2o_sa && i2o_sa.as_u32 != s->i2o.match.saddr.as_u32)
+               continue;
+             if (filter_i2o_da && i2o_da.as_u32 != s->i2o.match.daddr.as_u32)
+               continue;
+             if (filter_o2i_sa && o2i_sa.as_u32 != s->o2i.match.saddr.as_u32)
+               continue;
+             if (filter_o2i_da && o2i_da.as_u32 != s->o2i.match.daddr.as_u32)
+               continue;
+             if (filter_i2o_sp &&
+                 i2o_sp != clib_net_to_host_u16 (s->i2o.match.sport))
+               continue;
+             if (filter_i2o_dp &&
+                 i2o_dp != clib_net_to_host_u16 (s->i2o.match.dport))
+               continue;
+             if (filter_o2i_sp &&
+                 o2i_sp != clib_net_to_host_u16 (s->o2i.match.sport))
+               continue;
+             if (filter_o2i_dp &&
+                 o2i_dp != clib_net_to_host_u16 (s->o2i.match.dport))
+               continue;
+             if (filter_proto && proto != s->proto)
+               continue;
+             showed_sessions++;
+           }
+         vlib_cli_output (vm, "  %U\n", format_snat_session, sm, tsm, s,
+                          vlib_time_now (vm));
+       }
+      if (filtering)
+       {
+         vlib_cli_output (vm,
+                          "Showed: %d, Filtered: %d of total %d "
+                          "sessions of thread %d\n\n",
+                          showed_sessions,
+                          pool_elts (tsm->sessions) - showed_sessions,
+                          pool_elts (tsm->sessions), i);
+       }
     }
+
+done:
+  if (had_input)
+    unformat_free (line_input);
   return error;
 }
 
@@ -1457,7 +1658,7 @@ nat44_del_session_command_fn (vlib_main_t * vm,
   u32 port = 0, eh_port = 0, vrf_id = sm->outside_vrf_id;
   clib_error_t *error = 0;
   ip4_address_t addr, eh_addr;
-  nat_protocol_t proto;
+  ip_protocol_t proto;
   int is_in = 0;
   int rv;
 
@@ -1466,9 +1667,8 @@ nat44_del_session_command_fn (vlib_main_t * vm,
 
   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
     {
-      if (unformat
-         (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port,
-          unformat_nat_protocol, &proto))
+      if (unformat (line_input, "%U:%u %U", unformat_ip4_address, &addr, &port,
+                   unformat_ip_protocol, &proto))
        ;
       else if (unformat (line_input, "in"))
        {
@@ -1494,8 +1694,8 @@ nat44_del_session_command_fn (vlib_main_t * vm,
     }
 
   rv = nat44_ed_del_session (sm, &addr, clib_host_to_net_u16 (port), &eh_addr,
-                            clib_host_to_net_u16 (eh_port),
-                            nat_proto_to_ip_proto (proto), vrf_id, is_in);
+                            clib_host_to_net_u16 (eh_port), proto, vrf_id,
+                            is_in);
 
   switch (rv)
     {
@@ -1650,16 +1850,13 @@ done:
  *  vpp# nat44 enable
  * To disable nat44-ed, use:
  *  vpp# nat44 disable
- * To enable nat44-ed static mapping with connection tracking, use:
- *  vpp# nat44-ed enable static-mapping connection-tracking
  * To set inside-vrf outside-vrf, use:
  *  vpp# nat44 enable inside-vrf <id> outside-vrf <id>
  * @cliexend
 ?*/
 VLIB_CLI_COMMAND (nat44_ed_enable_disable_command, static) = {
   .path = "nat44",
-  .short_help = "nat44 <enable [sessions <max-number>] [static-mapping-only "
-               "connection-tracking] [inside-vrf <vrf-id>] "
+  .short_help = "nat44 <enable [sessions <max-number>] [inside-vrf <vrf-id>] "
                "[outside-vrf <vrf-id>]>|disable",
   .function = nat44_ed_enable_disable_command_fn,
 };
@@ -1690,7 +1887,7 @@ VLIB_CLI_COMMAND (set_workers_command, static) = {
 VLIB_CLI_COMMAND (nat_show_workers_command, static) = {
   .path = "show nat workers",
   .short_help = "show nat workers",
-  .function = nat_show_workers_commnad_fn,
+  .function = nat_show_workers_command_fn,
 };
 
 /*?
@@ -2023,6 +2220,45 @@ VLIB_CLI_COMMAND (snat_add_interface_address_command, static) = {
     .function = snat_add_interface_address_command_fn,
 };
 
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 vrf table}
+ * Add empty inter VRF routing table
+ *  vpp# nat44 vrf table add 10
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ed_add_del_vrf_table_command, static) = {
+  .path = "nat44 vrf table",
+  .short_help = "nat44 vrf table [add|del] <vrf-id>",
+  .function = nat44_ed_add_del_vrf_table_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{nat44 vrf route}
+ * Add inter VRF route record to VRF routing table
+ *  vpp# nat44 vrf route add table 10 20
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ed_add_del_vrf_route_command, static) = {
+  .path = "nat44 vrf route",
+  .short_help = "nat44 vrf route [add|del] table <vrf-id> <vrf-id>",
+  .function = nat44_ed_add_del_vrf_route_command_fn,
+};
+
+/*?
+ * @cliexpar
+ * @cliexstart{show nat44 vrf tables}
+ * Show inter VRF route tables
+ *  vpp# show nat44 vrf tables
+ * @cliexend
+?*/
+VLIB_CLI_COMMAND (nat44_ed_show_vrf_tables_command, static) = {
+  .path = "show nat44 vrf tables",
+  .short_help = "show nat44 vrf tables",
+  .function = nat44_ed_show_vrf_tables_command_fn,
+};
+
 /*?
  * @cliexpar
  * @cliexstart{show nat44 interface address}
@@ -2048,7 +2284,9 @@ VLIB_CLI_COMMAND (nat44_show_interface_address_command, static) = {
 ?*/
 VLIB_CLI_COMMAND (nat44_show_sessions_command, static) = {
   .path = "show nat44 sessions",
-  .short_help = "show nat44 sessions",
+  .short_help = "show nat44 sessions [filter {i2o | o2i} {saddr <ip4-addr> "
+               "| sport <n> | daddr <ip4-addr> | dport <n> | proto <proto>} "
+               "[filter .. [..]]]",
   .function = nat44_show_sessions_command_fn,
 };