+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_ed_alloc_addr_and_port (snat_main_t * sm, u32 rx_fib_index,
+ u32 snat_proto, u32 thread_index,
+ ip4_address_t r_addr, u16 r_port, u8 proto,
+ u16 port_per_thread, u32 snat_thread_index,
+ snat_session_t * s,
+ ip4_address_t * allocated_addr,
+ u16 * allocated_port,
+ clib_bihash_kv_16_8_t * out2in_ed_kv)
+{
+ int i;
+ snat_address_t *a, *ga = 0;
+ u32 portnum;
+ snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index];
+
+ const u16 port_thread_offset = (port_per_thread * snat_thread_index) + 1024;
+
+ for (i = 0; i < vec_len (sm->addresses); i++)
+ {
+ a = sm->addresses + i;
+ switch (snat_proto)
+ {
+#define _(N, j, n, unused) \
+ case SNAT_PROTOCOL_##N: \
+ if (a->fib_index == rx_fib_index) \
+ { \
+ u16 port = snat_random_port (1, port_per_thread); \
+ u16 attempts = port_per_thread; \
+ while (attempts > 0) \
+ { \
+ --attempts; \
+ portnum = port_thread_offset + port; \
+ make_ed_kv (&a->addr, &r_addr, proto, s->out2in.fib_index, \
+ clib_host_to_net_u16 (portnum), r_port, \
+ s - tsm->sessions, out2in_ed_kv); \
+ int rv = clib_bihash_add_del_16_8 (&tsm->out2in_ed, out2in_ed_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++; \
+ *allocated_addr = a->addr; \
+ *allocated_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 */
+ rx_fib_index = ~0;
+ a = ga;
+ switch (snat_proto)
+ {
+ 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;
+}
+