+static_always_inline u16
+snat_random_port (u16 min, u16 max)
+{
+ snat_main_t *sm = &snat_main;
+ return min + random_u32 (&sm->random_seed) /
+ (random_u32_max () / (max - min + 1) + 1);
+}
+
+static int
+nat_alloc_addr_and_port_ed (snat_address_t * addresses, u32 fib_index,
+ u32 thread_index, nat_ed_ses_key_t * key,
+ snat_session_key_t * key1, u16 port_per_thread,
+ u32 snat_thread_index)
+{
+ int i;
+ snat_address_t *a, *ga = 0;
+ u32 portnum;
+
+ const u16 port_thread_offset = (port_per_thread * snat_thread_index) + 1024;
+ ed_bihash_kv_t bihash_key;
+ clib_memset (&bihash_key, 0, sizeof (bihash_key));
+ bihash_key.k.dst_address = key->r_addr.as_u32;
+ bihash_key.k.dst_port = key->r_port;
+ bihash_key.k.protocol = key1->protocol;
+
+ for (i = 0; i < vec_len (addresses); i++)
+ {
+ a = addresses + i;
+ switch (key1->protocol)
+ {
+#define _(N, j, n, s) \
+ case SNAT_PROTOCOL_##N: \
+ if (a->fib_index == fib_index) \
+ { \
+ bihash_key.k.src_address = a->addr.as_u32; \
+ u16 port = snat_random_port (1, port_per_thread); \
+ u16 attempts = port_per_thread; \
+ while (attempts > 0) \
+ { \
+ --attempts; \
+ portnum = port_thread_offset + port; \
+ bihash_key.k.src_port = clib_host_to_net_u16 (portnum); \
+ int rv = clib_bihash_add_del_16_8 ( \
+ &snat_main.ed_ext_ports, &bihash_key.kv, 2 /* is_add */); \
+ if (0 == rv) \
+ { \
+ ++a->busy_##n##_port_refcounts[portnum]; \
+ a->busy_##n##_ports_per_thread[thread_index]++; \
+ a->busy_##n##_ports++; \
+ key1->addr = a->addr; \
+ key1->port = clib_host_to_net_u16 (portnum); \
+ return 0; \
+ } \
+ port = (port + 1) % port_per_thread; \
+ } \
+ } \
+ else if (a->fib_index == ~0) \
+ { \
+ ga = a; \
+ } \
+ break;
+
+ foreach_snat_protocol;
+ default:
+ nat_elog_info ("unknown protocol");
+ return 1;
+ }
+ }
+
+ if (ga)
+ {
+ /* fake fib_index to reuse macro */
+ fib_index = ~0;
+ a = ga;
+ switch (key1->protocol)
+ {
+ foreach_snat_protocol;
+ default:
+ nat_elog_info ("unknown protocol");
+ return 1;
+ }
+ }
+
+#undef _
+
+ /* Totally out of translations to use... */
+ snat_ipfix_logging_addresses_exhausted (thread_index, 0);
+ return 1;
+}
+