nat: VRF routing & FIB improvements
[vpp.git] / src / plugins / nat / nat44-ed / nat44_ed_cli.c
index 9743ce6..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)
@@ -350,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;
@@ -386,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);
 
@@ -418,7 +403,7 @@ add_address_command_fn (vlib_main_t * vm,
        }
       else
        {
-         rv = nat44_ed_del_address (this_addr, 0, twice_nat);
+         rv = nat44_ed_del_address (this_addr, twice_nat);
        }
 
       switch (rv)
@@ -493,16 +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 other_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;
 
@@ -516,43 +497,44 @@ 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->proto)
-             {
-             case IP_PROTOCOL_ICMP:
-               icmp_sessions++;
-               break;
-             case IP_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 IP_PROTOCOL_UDP:
-               udp_sessions++;
-               break;
-             default:
-               ++other_sessions;
-               break;
-             }
+            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);
@@ -565,39 +547,40 @@ 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->proto)
          {
          case IP_PROTOCOL_ICMP:
-           icmp_sessions++;
+           ++icmp.total;
+           if (now >= sess_timeout_time)
+             ++icmp.timed_out;
            break;
          case IP_PROTOCOL_TCP:
-           tcp_sessions++;
-           if (s->state)
+           ++tcp.total;
+           if (now >= sess_timeout_time)
+             ++tcp.timed_out;
+           if (nat44_ed_tcp_is_established (s->tcp_state))
              {
-               if (s->tcp_closed_timestamp)
-                 {
-                   if (now >= s->tcp_closed_timestamp)
-                     {
-                       ++transitory_closed;
-                     }
-                   else
-                     {
-                       ++transitory_wait_closed;
-                     }
-                 }
-               transitory++;
+               ++tcp_established.total;
+               if (now >= sess_timeout_time)
+                 ++tcp_established.timed_out;
              }
            else
-             established++;
+             {
+               ++tcp_transitory.total;
+               if (now >= sess_timeout_time)
+                 ++tcp_transitory.timed_out;
+             }
            break;
          case IP_PROTOCOL_UDP:
-           udp_sessions++;
+           ++udp.total;
+           if (now >= sess_timeout_time)
+             ++udp.timed_out;
            break;
          default:
-           ++other_sessions;
+           ++other.total;
+           if (now >= sess_timeout_time)
+             ++other.timed_out;
            break;
          }
       }
@@ -605,18 +588,25 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input,
       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);
-  vlib_cli_output (vm, "total other sessions: %u", other_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;
 }
 
@@ -926,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 =
@@ -940,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;
     }
@@ -969,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,
@@ -986,7 +965,6 @@ add_identity_mapping_command_fn (vlib_main_t * vm,
 
   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);
 
@@ -1039,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;
     }
@@ -1083,7 +1053,6 @@ add_lb_static_mapping_command_fn (vlib_main_t * vm,
   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);
 
@@ -1279,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;
@@ -1351,6 +1320,156 @@ done:
   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)
+    {
+      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)
+    {
+      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,
@@ -1358,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;
 }
 
@@ -1478,7 +1590,8 @@ print:
                continue;
              showed_sessions++;
            }
-         vlib_cli_output (vm, "  %U\n", format_snat_session, tsm, s);
+         vlib_cli_output (vm, "  %U\n", format_snat_session, sm, tsm, s,
+                          vlib_time_now (vm));
        }
       if (filtering)
        {
@@ -1737,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,
 };
@@ -2110,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}