#include <vnet/dpo/drop_dpo.h>
#include <cnat/cnat_translation.h>
+#include <cnat/cnat_maglev.h>
#include <cnat/cnat_session.h>
#include <cnat/cnat_client.h>
cnat_translation_t *cnat_translation_pool;
clib_bihash_8_8_t cnat_translation_db;
addr_resolution_t *tr_resolutions;
-
-typedef void (*cnat_if_addr_add_cb_t) (addr_resolution_t * ar,
- ip_address_t * address, u8 is_del);
cnat_if_addr_add_cb_t *cnat_if_addr_add_cbs;
static fib_node_type_t cnat_translation_fib_node_type;
clib_bihash_add_del_8_8 (&cnat_translation_db, &bkey, 0);
}
-typedef struct
-{
- cnat_ep_trk_t *trk;
- u32 index;
- u32 offset;
- u32 skip;
-} cnat_maglev_entry_t;
-
-static int
-cnat_maglev_entry_compare (void *_a, void *_b)
-{
- cnat_ep_trk_t *a = ((cnat_maglev_entry_t *) _a)->trk;
- cnat_ep_trk_t *b = ((cnat_maglev_entry_t *) _b)->trk;
- int rv = 0;
- if ((rv =
- ip_address_cmp (&a->ct_ep[VLIB_TX].ce_ip, &b->ct_ep[VLIB_TX].ce_ip)))
- return rv;
- if ((rv = a->ct_ep[VLIB_TX].ce_port - a->ct_ep[VLIB_TX].ce_port))
- return rv;
- if ((rv =
- ip_address_cmp (&a->ct_ep[VLIB_RX].ce_ip, &b->ct_ep[VLIB_RX].ce_ip)))
- return rv;
- if ((rv = a->ct_ep[VLIB_RX].ce_port - a->ct_ep[VLIB_RX].ce_port))
- return rv;
- return 0;
-}
-
-static void
-cnat_translation_init_maglev (cnat_translation_t *ct)
-{
- cnat_maglev_entry_t *backends = NULL, *bk;
- cnat_main_t *cm = &cnat_main;
- u32 done = 0;
- cnat_ep_trk_t *trk;
- int ep_idx = 0;
-
- vec_foreach (trk, ct->ct_active_paths)
- {
- cnat_maglev_entry_t bk;
- u32 h1, h2;
-
- if (AF_IP4 == ip_addr_version (&trk->ct_ep[VLIB_TX].ce_ip))
- {
- u32 a, b, c;
- a = ip_addr_v4 (&trk->ct_ep[VLIB_TX].ce_ip).data_u32;
- b = trk->ct_ep[VLIB_TX].ce_port << 16 | trk->ct_ep[VLIB_RX].ce_port;
- c = ip_addr_v4 (&trk->ct_ep[VLIB_RX].ce_ip).data_u32;
- hash_v3_mix32 (a, b, c);
- hash_v3_finalize32 (a, b, c);
- h1 = c;
- h2 = b;
- }
- else
- {
- u64 a, b, c;
- a = ip_addr_v6 (&trk->ct_ep[VLIB_TX].ce_ip).as_u64[0] ^
- ip_addr_v6 (&trk->ct_ep[VLIB_TX].ce_ip).as_u64[1];
- b = trk->ct_ep[VLIB_TX].ce_port << 16 | trk->ct_ep[VLIB_RX].ce_port;
- c = ip_addr_v6 (&trk->ct_ep[VLIB_RX].ce_ip).as_u64[0] ^
- ip_addr_v6 (&trk->ct_ep[VLIB_RX].ce_ip).as_u64[1];
- hash_mix64 (a, b, c);
- h1 = c;
- h2 = b;
- }
-
- bk.offset = h1 % cm->maglev_len;
- bk.skip = h2 % (cm->maglev_len - 1) + 1;
- bk.index = ep_idx++;
- bk.trk = trk;
- vec_add1 (backends, bk);
- }
-
- if (0 == ep_idx)
- return;
-
- vec_sort_with_function (backends, cnat_maglev_entry_compare);
-
- /* Don't free if previous vector exists, just zero */
- vec_validate (ct->lb_maglev, cm->maglev_len);
- vec_set (ct->lb_maglev, -1);
-
- while (1)
- {
- vec_foreach (bk, backends)
- {
- u32 next = 0;
- u32 c = (bk->offset + next * bk->skip) % cm->maglev_len;
- while (ct->lb_maglev[c] != (u32) -1)
- {
- next++;
- c = (bk->offset + next * bk->skip) % cm->maglev_len;
- }
- ct->lb_maglev[c] = bk->index;
- done++;
- if (done == cm->maglev_len)
- goto finished;
- }
- }
-finished:
- vec_free (backends);
-}
static void
cnat_translation_stack (cnat_translation_t * ct)
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;
+ ct->flags |= CNAT_TR_FLAG_STACKED;
}
int
}
vec_reset_length (ct->ct_paths);
- ct->flags &= ~CNAT_TRANSLATION_STACKED;
+ ct->flags &= ~CNAT_TR_FLAG_STACKED;
u64 path_idx = 0;
vec_foreach (path, paths)
/* 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))
+ if (!(ct->flags & CNAT_TR_FLAG_STACKED))
return (FIB_NODE_BACK_WALK_CONTINUE);
cnat_translation_stack (ct);
ep->ce_flags |= CNAT_EP_FLAG_RESOLVED;
}
- ct->flags &= ~CNAT_TRANSLATION_STACKED;
+ ct->flags &= ~CNAT_TR_FLAG_STACKED;
cnat_tracker_track (ar->cti, trk);
cnat_translation_stack (ct);
- ct->flags |= CNAT_TRANSLATION_STACKED;
-}
-
-static void
-cnat_if_addr_add_del_snat_cb (addr_resolution_t * ar, ip_address_t * address,
- u8 is_del)
-{
- cnat_endpoint_t *ep;
- ep = AF_IP4 == ar->af ? &cnat_main.snat_ip4 : &cnat_main.snat_ip6;
-
- if (!is_del && ep->ce_flags & CNAT_EP_FLAG_RESOLVED)
- return;
-
- if (is_del)
- {
- ep->ce_flags &= ~CNAT_EP_FLAG_RESOLVED;
- /* Are there remaining addresses ? */
- if (0 == cnat_resolve_addr (ar->sw_if_index, ar->af, address))
- is_del = 0;
- }
-
- if (!is_del)
- {
- ip_address_copy (&ep->ce_ip, address);
- ep->ce_flags |= CNAT_EP_FLAG_RESOLVED;
- }
-
+ ct->flags |= CNAT_TR_FLAG_STACKED;
}
static void
cnat_if_addr_add_del_callback (sw_if_index, &addr, is_del);
}
+void
+cnat_translation_register_addr_add_cb (cnat_addr_resol_type_t typ,
+ cnat_if_addr_add_cb_t fn)
+{
+ vec_validate (cnat_if_addr_add_cbs, CNAT_ADDR_N_RESOLUTIONS);
+ cnat_if_addr_add_cbs[typ] = fn;
+}
+
static clib_error_t *
cnat_translation_init (vlib_main_t * vm)
{
ip6_main_t *i6m = &ip6_main;
cnat_main_t *cm = &cnat_main;
cnat_translation_fib_node_type =
- fib_node_register_new_type (&cnat_translation_vft);
+ fib_node_register_new_type ("cnat-translation", &cnat_translation_vft);
clib_bihash_init_8_8 (&cnat_translation_db, "CNat translation DB",
cm->translation_hash_buckets,
cb6.function = cnat_ip6_if_addr_add_del_callback;
vec_add1 (i6m->add_del_interface_address_callbacks, cb6);
- vec_validate (cnat_if_addr_add_cbs, CNAT_ADDR_N_RESOLUTIONS);
- cnat_if_addr_add_cbs[CNAT_RESOLV_ADDR_BACKEND] =
- cnat_if_addr_add_del_backend_cb;
- cnat_if_addr_add_cbs[CNAT_RESOLV_ADDR_SNAT] = cnat_if_addr_add_del_snat_cb;
- cnat_if_addr_add_cbs[CNAT_RESOLV_ADDR_TRANSLATION] =
- cnat_if_addr_add_del_translation_cb;
+ cnat_translation_register_addr_add_cb (CNAT_RESOLV_ADDR_BACKEND,
+ cnat_if_addr_add_del_backend_cb);
+ cnat_translation_register_addr_add_cb (CNAT_RESOLV_ADDR_TRANSLATION,
+ cnat_if_addr_add_del_translation_cb);
+
return (NULL);
}