cnat: fixes & prepare maglev
[vpp.git] / src / plugins / cnat / cnat_translation.c
index b128679..65c44d8 100644 (file)
@@ -68,13 +68,12 @@ cnat_translation_unwatch_addr (u32 cti, cnat_addr_resol_type_t type)
   /* Delete tr resolution entries matching translation index */
   addr_resolution_t *ar;
   index_t *indexes = 0, *ari;
-  /* *INDENT-OFF* */
-  pool_foreach (ar, tr_resolutions, ({
-    if ((cti == INDEX_INVALID || ar->cti == cti) &&
-      (ar->type == type || CNAT_RESOLV_ADDR_ANY == type))
-      vec_add1(indexes, ar - tr_resolutions);
-  }));
-  /* *INDENT-ON* */
+  pool_foreach (ar, tr_resolutions)
+    {
+      if ((cti == INDEX_INVALID || ar->cti == cti) &&
+         (ar->type == type || CNAT_RESOLV_ADDR_ANY == type))
+       vec_add1 (indexes, ar - tr_resolutions);
+    }
   vec_foreach (ari, indexes) pool_put_index (tr_resolutions, *ari);
 
   vec_free (indexes);
@@ -84,7 +83,7 @@ static void
 cnat_tracker_release (cnat_ep_trk_t * trk)
 {
   /* We only track fully resolved endpoints */
-  if (!trk->is_active)
+  if (!(trk->ct_flags & CNAT_TRK_ACTIVE))
     return;
   fib_entry_untrack (trk->ct_fei, trk->ct_sibling);
 }
@@ -94,10 +93,14 @@ cnat_tracker_track (index_t cti, cnat_ep_trk_t * trk)
 {
   fib_prefix_t pfx;
   /* We only track fully resolved endpoints */
-  trk->is_active = trk->ct_ep[VLIB_TX].ce_flags & CNAT_EP_FLAG_RESOLVED
-    && trk->ct_ep[VLIB_RX].ce_flags & CNAT_EP_FLAG_RESOLVED;
-  if (!trk->is_active)
-    return;
+  if (trk->ct_ep[VLIB_TX].ce_flags & CNAT_EP_FLAG_RESOLVED &&
+      trk->ct_ep[VLIB_RX].ce_flags & CNAT_EP_FLAG_RESOLVED)
+    trk->ct_flags |= CNAT_TRK_ACTIVE;
+  else
+    {
+      trk->ct_flags &= ~CNAT_TRK_ACTIVE;
+      return;
+    }
 
   ip_address_to_fib_prefix (&trk->ct_ep[VLIB_TX].ce_ip, &pfx);
   trk->ct_fei = fib_entry_track (CNAT_FIB_TABLE,
@@ -180,24 +183,28 @@ cnat_translation_stack (cnat_translation_t * ct)
   fib_protocol_t fproto;
   cnat_ep_trk_t *trk;
   dpo_proto_t dproto;
-  u8 ep_idx = 0;
+  u32 ep_idx = 0;
   index_t lbi;
 
   fproto = ip_address_family_to_fib_proto (ct->ct_vip.ce_ip.version);
   dproto = fib_proto_to_dpo (fproto);
 
-  vec_foreach (trk, ct->ct_paths) if (trk->is_active)
-    ep_idx++;
+  vec_reset_length (ct->ct_active_paths);
 
-  lbi = load_balance_create (ep_idx, fib_proto_to_dpo (fproto),
-                            IP_FLOW_HASH_DEFAULT);
+  vec_foreach (trk, ct->ct_paths)
+    if (trk->ct_flags & CNAT_TRK_ACTIVE)
+      vec_add1 (ct->ct_active_paths, *trk);
+
+  lbi = load_balance_create (vec_len (ct->ct_active_paths),
+                            fib_proto_to_dpo (fproto), IP_FLOW_HASH_DEFAULT);
 
   ep_idx = 0;
-  vec_foreach (trk, ct->ct_paths) if (trk->is_active)
+  vec_foreach (trk, ct->ct_active_paths)
     load_balance_set_bucket (lbi, ep_idx++, &trk->ct_dpo);
 
   dpo_set (&ct->ct_lb, DPO_LOAD_BALANCE, dproto, lbi);
   dpo_stack (cnat_client_dpo, dproto, &ct->ct_lb, &ct->ct_lb);
+  ct->flags |= CNAT_TRANSLATION_STACKED;
 }
 
 int
@@ -213,7 +220,8 @@ cnat_translation_delete (u32 id)
 
   dpo_reset (&ct->ct_lb);
 
-  vec_foreach (trk, ct->ct_paths) cnat_tracker_release (trk);
+  vec_foreach (trk, ct->ct_active_paths)
+    cnat_tracker_release (trk);
 
   cnat_remove_translation_from_db (ct->ct_cci, &ct->ct_vip, ct->ct_proto);
   cnat_client_translation_deleted (ct->ct_cci);
@@ -277,6 +285,7 @@ cnat_translation_update (cnat_endpoint_t * vip,
   }
 
   vec_reset_length (ct->ct_paths);
+  ct->flags &= ~CNAT_TRANSLATION_STACKED;
 
   u64 path_idx = 0;
   vec_foreach (path, paths)
@@ -310,13 +319,11 @@ cnat_translation_walk (cnat_translation_walk_cb_t cb, void *ctx)
 {
   u32 api;
 
-  /* *INDENT-OFF* */
-  pool_foreach_index(api, cnat_translation_pool,
-  ({
+  pool_foreach_index (api, cnat_translation_pool)
+   {
     if (!cb(api, ctx))
       break;
-  }));
-  /* *INDENT-ON* */
+  }
 }
 
 static u8 *
@@ -378,13 +385,11 @@ cnat_translation_show (vlib_main_t * vm,
 
   if (INDEX_INVALID == cti)
     {
-      /* *INDENT-OFF* */
-      pool_foreach_index(cti, cnat_translation_pool,
-      ({
+      pool_foreach_index (cti, cnat_translation_pool)
+       {
        ct = pool_elt_at_index (cnat_translation_pool, cti);
         vlib_cli_output(vm, "%U", format_cnat_translation, ct);
-      }));
-      /* *INDENT-ON* */
+      }
     }
   else
     {
@@ -400,12 +405,10 @@ cnat_translation_purge (void)
   /* purge all the translations */
   index_t tri, *trp, *trs = NULL;
 
-  /* *INDENT-OFF* */
-  pool_foreach_index(tri, cnat_translation_pool,
-  ({
+  pool_foreach_index (tri, cnat_translation_pool)
+   {
     vec_add1(trs, tri);
-  }));
-  /* *INDENT-ON* */
+  }
 
   vec_foreach (trp, trs) cnat_translation_delete (*trp);
 
@@ -416,14 +419,12 @@ cnat_translation_purge (void)
   return (0);
 }
 
-/* *INDENT-OFF* */
 VLIB_CLI_COMMAND (cnat_translation_show_cmd_node, static) = {
   .path = "show cnat translation",
   .function = cnat_translation_show,
   .short_help = "show cnat translation <VIP>",
   .is_mp_safe = 1,
 };
-/* *INDENT-ON* */
 
 static fib_node_t *
 cnat_translation_get_node (fib_node_index_t index)
@@ -457,6 +458,12 @@ cnat_translation_back_walk_notify (fib_node_t * node,
    */
   cnat_translation_t *ct = cnat_translation_get_from_node (node);
 
+  /* If we have more than FIB_PATH_LIST_POPULAR paths
+   * we might get called during path tracking
+   * (cnat_tracker_track) */
+  if (!(ct->flags & CNAT_TRANSLATION_STACKED))
+    return (FIB_NODE_BACK_WALK_CONTINUE);
+
   cnat_translation_stack (ct);
 
   return (FIB_NODE_BACK_WALK_CONTINUE);
@@ -481,27 +488,37 @@ cnat_translation_cli_add_del (vlib_main_t * vm,
   cnat_endpoint_t vip;
   u8 flags = CNAT_FLAG_EXCLUSIVE;
   cnat_endpoint_tuple_t tmp, *paths = NULL, *path;
+  unformat_input_t _line_input, *line_input = &_line_input;
+  clib_error_t *e = 0;
 
-  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+  /* 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 (input, "add"))
+      if (unformat (line_input, "add"))
        del_index = INDEX_INVALID;
-      else if (unformat (input, "del %d", &del_index))
+      else if (unformat (line_input, "del %d", &del_index))
        ;
-      else if (unformat (input, "proto %U", unformat_ip_protocol, &proto))
+      else
+       if (unformat (line_input, "proto %U", unformat_ip_protocol, &proto))
        ;
-      else if (unformat (input, "vip %U", unformat_cnat_ep, &vip))
+      else if (unformat (line_input, "vip %U", unformat_cnat_ep, &vip))
        flags = CNAT_FLAG_EXCLUSIVE;
-      else if (unformat (input, "real %U", unformat_cnat_ep, &vip))
+      else if (unformat (line_input, "real %U", unformat_cnat_ep, &vip))
        flags = 0;
-      else if (unformat (input, "to %U", unformat_cnat_ep_tuple, &tmp))
+      else if (unformat (line_input, "to %U", unformat_cnat_ep_tuple, &tmp))
        {
-         pool_get (paths, path);
+         vec_add2 (paths, path, 1);
          clib_memcpy (path, &tmp, sizeof (cnat_endpoint_tuple_t));
        }
       else
-       return (clib_error_return (0, "unknown input '%U'",
-                                  format_unformat_error, input));
+       {
+         e = clib_error_return (0, "unknown input '%U'",
+                                format_unformat_error, line_input);
+         goto done;
+       }
     }
 
   if (INDEX_INVALID == del_index)
@@ -509,18 +526,18 @@ cnat_translation_cli_add_del (vlib_main_t * vm,
   else
     cnat_translation_delete (del_index);
 
-  pool_free (paths);
-  return (NULL);
+done:
+  vec_free (paths);
+  unformat_free (line_input);
+  return (e);
 }
 
-/* *INDENT-OFF* */
 VLIB_CLI_COMMAND (cnat_translation_cli_add_del_command, static) =
 {
   .path = "cnat translation",
   .short_help = "cnat translation [add|del] proto [TCP|UDP] [vip|real] [ip|sw_if_index [v6]] [port] [to [ip|sw_if_index [v6]] [port]->[ip|sw_if_index [v6]] [port]]",
   .function = cnat_translation_cli_add_del,
 };
-/* *INDENT-ON* */
 
 static void
 cnat_if_addr_add_del_translation_cb (addr_resolution_t * ar,
@@ -589,9 +606,12 @@ cnat_if_addr_add_del_backend_cb (addr_resolution_t * ar,
       ip_address_copy (&ep->ce_ip, address);
       ep->ce_flags |= CNAT_EP_FLAG_RESOLVED;
     }
+
+  ct->flags &= ~CNAT_TRANSLATION_STACKED;
   cnat_tracker_track (ar->cti, trk);
 
   cnat_translation_stack (ct);
+  ct->flags |= CNAT_TRANSLATION_STACKED;
 }
 
 static void
@@ -625,15 +645,14 @@ cnat_if_addr_add_del_callback (u32 sw_if_index, ip_address_t * address,
                               u8 is_del)
 {
   addr_resolution_t *ar;
-  /* *INDENT-OFF* */
-  pool_foreach (ar, tr_resolutions, ({
-    if (ar->sw_if_index != sw_if_index)
-      continue;
-    if (ar->af != ip_addr_version (address))
-      continue;
-    cnat_if_addr_add_cbs[ar->type] (ar, address, is_del);
-  }));
-  /* *INDENT-ON* */
+  pool_foreach (ar, tr_resolutions)
+    {
+      if (ar->sw_if_index != sw_if_index)
+       continue;
+      if (ar->af != ip_addr_version (address))
+       continue;
+      cnat_if_addr_add_cbs[ar->type](ar, address, is_del);
+    }
 }
 
 static void
@@ -673,11 +692,11 @@ cnat_translation_init (vlib_main_t * vm)
                        cm->translation_hash_buckets,
                        cm->translation_hash_memory);
 
-  ip4_add_del_interface_address_callback_t cb4;
+  ip4_add_del_interface_address_callback_t cb4 = { 0 };
   cb4.function = cnat_ip4_if_addr_add_del_callback;
   vec_add1 (i4m->add_del_interface_address_callbacks, cb4);
 
-  ip6_add_del_interface_address_callback_t cb6;
+  ip6_add_del_interface_address_callback_t cb6 = { 0 };
   cb6.function = cnat_ip6_if_addr_add_del_callback;
   vec_add1 (i6m->add_del_interface_address_callbacks, cb6);