2 *------------------------------------------------------------------
3 * cnat_ports.c - port allocator
5 * Copyright (c) 2008-2014 Cisco and/or its affiliates.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at:
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *------------------------------------------------------------------
19 #include <vlib/vlib.h>
20 #include <vnet/vnet.h>
21 #include <vppinfra/vec.h>
22 #include <vppinfra/hash.h>
23 #include <vppinfra/pool.h>
24 #include <vppinfra/clib.h>
25 #include <vppinfra/bitmap.h>
28 #include "cnat_config.h"
29 #include "cnat_global.h"
30 #include "cnat_logging.h"
31 #include "spp_timers.h"
32 #include "platform_common.h"
33 #include "cgn_bitmap.h"
34 #include "spp_platform_trace_log.h"
35 #include "cnat_ports.h"
37 #if 1 /* TOBE_PORTED */
38 /* Following is defined elsewhere. */
39 #define msg_spp_err(s) \
41 fprintf(stderr,(i8 *)s); \
42 fputs("\n", stderr); \
47 #define PM_90_PERCENT_USE 58980
49 * instance number provisioned from HW
51 u8 my_instance_number = 0;
54 u32 cached_next_index;
55 /* $$$$ add data here */
57 /* convenience variables */
58 vlib_main_t * vlib_main;
59 vnet_main_t * vnet_main;
62 cnat_ports_main_t cnat_ports_main;
64 static u32 rseed_port; /* random number generator seed */
67 cnat_db_dump_portmap_for_vrf (u32 vrfmap_index)
70 cnat_vrfmap_t *my_vrfmap = cnat_map_by_vrf + vrfmap_index;
71 cnat_portmap_v2_t *pm, *my_pm __attribute__((unused));
73 pm = my_vrfmap->portmap_list;
76 for (i = 0; i < pm_len; i++) {
79 PLATFORM_DEBUG_PRINT("pm %d: IPv4 Addr 0x%x - in use %d private_ip_users_count %d\n",
80 i, my_pm->ipv4_address, my_pm->inuse,
81 my_pm->private_ip_users_count);
83 PLATFORM_DEBUG_PRINT("pm %d: IPv4 Addr 0x%x - in use %d "
84 "private_ip_users_count %d\n",
85 i, my_pm->ipv4_address, my_pm->inuse,
86 my_pm->private_ip_users_count);
91 cnat_db_dump_portmaps ()
95 for (i = 0; i < CNAT_MAX_VRFMAP_ENTRIES; i++) {
96 vrfmap_index = vrf_map_array[i];
98 if (vrfmap_index == VRF_MAP_ENTRY_EMPTY) {
102 PLATFORM_DEBUG_PRINT("\n\nDumping the port map for uidb_index %d\n", i);
103 cnat_db_dump_portmap_for_vrf(vrfmap_index);
107 #ifndef NO_BULK_LOGGING
108 static int check_if_stat_alloc_ok_for_bulk(cnat_portmap_v2_t *pm,
109 u16 i_port, bulk_alloc_size_t bulk_size,
110 u16 static_port_range)
112 uword bit_test_result;
113 if(BULK_ALLOC_SIZE_NONE == bulk_size) return 1; /* No issues */
115 if(i_port < static_port_range) return 1; /* we don't want bulk */
117 i_port = (i_port/bulk_size) * bulk_size;
118 bit_test_result = cgn_clib_bitmap_check_if_all(pm->bm, i_port, bulk_size);
119 return(bit_test_result);
122 inline static int check_if_stat_alloc_ok_for_bulk(cnat_portmap_v2_t *pm,
123 u16 i_port, bulk_alloc_size_t bulk_size,
124 u16 static_port_range)
128 #endif /* NO_BULK_LOGGING */
130 * cnat_port_alloc_static_v2
131 * public ipv4 address/port allocator for Static Port commands
132 * tries to allocate same outside port as inside port
135 cnat_static_port_alloc_v2 (
136 cnat_portmap_v2_t *pm,
138 port_pair_t pair_type,
144 u16 static_port_range
145 #ifndef NO_BULK_LOGGING
146 , bulk_alloc_size_t bulk_size,
152 u32 i, hash_value, my_index, found, max_attempts;
153 u16 start_bit, new_port;
154 cnat_portmap_v2_t *my_pm = 0;
155 u32 pm_len = vec_len(pm);
156 uword bit_test_result;
158 #ifndef NO_BULK_LOGGING
159 *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
162 if (PREDICT_FALSE(pm_len == 0)) {
163 return (CNAT_NO_POOL_ANY);
173 * Try to hash the IPv4 address to get an index value to select the pm
175 hash_value = (i_ipv4_address & 0xffff) ^
176 ((i_ipv4_address > 16) & 0xffff);
179 * If pm_len <= 256, compact the hash to 8 bits
181 if (PREDICT_TRUE(pm_len <= 256)) {
182 hash_value = (hash_value & 0xff) ^ ((hash_value > 8) & 0xff);
186 * Ensure that the hash value is in the range 0 .. (pm_len-1)
188 my_index = hash_value % pm_len;
190 for (i = 0; i < PORT_PROBE_LIMIT; i++) {
191 my_pm = pm + my_index;
192 if(PREDICT_TRUE(ip_n_to_1)) {
193 if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1)) {
195 * Try to find a PM with atlest 33% free and my_port free
197 if (PREDICT_TRUE((my_pm->inuse < ((BITS_PER_INST*2)/3)) &&
198 clib_bitmap_get_no_check(my_pm->bm,
200 #ifndef NO_BULK_LOGGING
201 && check_if_stat_alloc_ok_for_bulk(my_pm, i_port,
213 * Try to find a PM with atlest 33% free and my_port free
215 if (PREDICT_TRUE((my_pm->inuse < ((BITS_PER_INST*2)/3)) &&
216 clib_bitmap_get_no_check(my_pm->bm,
218 #ifndef NO_BULK_LOGGING
219 && check_if_stat_alloc_ok_for_bulk(my_pm, i_port,
228 my_index = (my_index + 1) % pm_len;
232 * If not found do it the hard way .
233 * "hard" way, best-fit.
236 u32 min_inuse_any, min_inuse_myport;
237 u32 min_index_any, min_index_myport;
239 min_inuse_any = min_inuse_myport = PORTS_PER_ADDR + 1;
240 min_index_any = min_index_myport = ~0;
241 for (i = 0; i < pm_len; i++) {
243 if(PREDICT_TRUE(ip_n_to_1)) {
244 if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1)) {
245 if (PREDICT_FALSE(my_pm->inuse < min_inuse_any)) {
246 min_inuse_any = my_pm->inuse;
247 min_index_any = my_pm - pm;
249 if (PREDICT_FALSE(my_pm->inuse < min_inuse_myport)) {
250 if (PREDICT_TRUE(clib_bitmap_get_no_check(
251 my_pm->bm,i_port) == 1)
252 #ifndef NO_BULK_LOGGING
253 && check_if_stat_alloc_ok_for_bulk(my_pm,
254 i_port,bulk_size,static_port_range)
257 min_inuse_myport = my_pm->inuse;
258 min_index_myport = my_pm - pm;
265 if (PREDICT_FALSE(my_pm->inuse < min_inuse_any)) {
266 min_inuse_any = my_pm->inuse;
267 min_index_any = my_pm - pm;
269 if (PREDICT_FALSE(my_pm->inuse < min_inuse_myport)) {
270 if (PREDICT_TRUE(clib_bitmap_get_no_check(
271 my_pm->bm, i_port) == 1)
272 #ifndef NO_BULK_LOGGING
273 && check_if_stat_alloc_ok_for_bulk(my_pm, i_port,
274 bulk_size, static_port_range)
277 min_inuse_myport = my_pm->inuse;
278 min_index_myport = my_pm - pm;
285 * Check if we have an exactly matching PM that has
286 * myport free. If so use it. If no such PM is
287 * available, use any PM
289 if (PREDICT_TRUE(min_inuse_myport < PORTS_PER_ADDR)) {
290 my_pm = pm + min_index_myport;
291 my_index = min_index_myport;
293 } else if (PREDICT_TRUE(min_inuse_any < PORTS_PER_ADDR)) {
294 my_pm = pm + min_index_any;
295 my_index = min_index_any;
301 return (CNAT_NO_PORT_ANY);
305 case PORT_ALLOC_DIRECTED:
307 if (PREDICT_FALSE(my_index > pm_len)) {
308 return (CNAT_INV_PORT_DIRECT);
310 my_pm = pm + my_index;
314 return (CNAT_ERR_PARSER);
317 /* Allocate a matching port if possible */
320 max_attempts = BITS_PER_INST;
321 #ifndef NO_BULK_LOGGING
322 if((BULK_ALLOC_SIZE_NONE != bulk_size) &&
323 (i_port >= static_port_range)) {
324 start_bit = (start_bit/bulk_size) * bulk_size;
325 max_attempts = BITS_PER_INST/bulk_size;
327 #endif /* NO_BULK_LOGGING */
329 for (i = 0; i < max_attempts; i++) {
330 #ifndef NO_BULK_LOGGING
331 if((BULK_ALLOC_SIZE_NONE != bulk_size) &&
332 (i_port >= static_port_range)) {
333 bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm,
334 start_bit, bulk_size);
337 #endif /* #ifndef NO_BULK_LOGGING */
338 bit_test_result = clib_bitmap_get_no_check(my_pm->bm, start_bit);
340 if (PREDICT_TRUE(bit_test_result)) {
341 #ifndef NO_BULK_LOGGING
342 if((BULK_ALLOC_SIZE_NONE != bulk_size) &&
343 (i_port >= static_port_range)) {
344 *nfv9_log_req = start_bit;
345 if(i==0) new_port = i_port; /* First go */
347 new_port = bit2port(start_bit);
348 if (pair_type == PORT_S_ODD && (new_port & 0x1) == 0)
355 #endif /* NO_BULK_LOGGING */
356 new_port = bit2port(start_bit);
357 if (pair_type == PORT_S_ODD) {
358 if ((new_port & 0x1) == 1) {
362 } else if (pair_type == PORT_S_EVEN) {
363 if ((new_port & 0x1) == 0) {
371 #ifndef NO_BULK_LOGGING
375 #ifndef NO_BULK_LOGGING
376 if((BULK_ALLOC_SIZE_NONE != bulk_size) &&
377 (i_port >= static_port_range))
378 start_bit = (start_bit + bulk_size) % BITS_PER_INST;
380 #endif /* NO_BULK_LOGGING */
381 start_bit = (start_bit + 1) % BITS_PER_INST;
382 if(PREDICT_FALSE(start_bit == 0)) {
383 start_bit = 1; /* Port 0 is invalid, so start from 1 */
385 #ifndef NO_BULK_LOGGING
388 } /* End of for loop */
391 /* Port allocation failure */
392 if (atype == PORT_ALLOC_DIRECTED) {
393 return (CNAT_NOT_FOUND_DIRECT);
395 return (CNAT_NOT_FOUND_ANY);
400 cgn_clib_bitmap_clear_no_check(my_pm->bm, new_port);
404 *o_ipv4_address = my_pm->ipv4_address;
408 return (CNAT_SUCCESS);
412 * Try to allocate a portmap structure based on atype field
415 cnat_dynamic_addr_alloc_from_pm (
416 cnat_portmap_v2_t *pm,
425 int min_inuse, min_index;
427 cnat_portmap_v2_t *my_pm = 0;
428 *err = CNAT_NO_POOL_ANY;
430 pm_len = vec_len(pm);
434 if (PREDICT_FALSE(pm_len == 0)) {
436 *err = CNAT_NO_POOL_ANY;
440 /* "Easy" way, first address with at least 200 free ports */
441 for (i = 0; i < PORT_PROBE_LIMIT; i++) {
442 *rseed_ip = randq1(*rseed_ip);
443 my_index = (*rseed_ip) % pm_len;
444 my_pm = pm + my_index;
445 if (PREDICT_FALSE(ip_n_to_1)) {
446 if(PREDICT_TRUE(ip_n_to_1 == 1)) {
447 if (PREDICT_FALSE(0 == my_pm->inuse)) {
451 if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1)) {
452 if (PREDICT_FALSE(my_pm->inuse < ((BITS_PER_INST*2)/3))) {
458 if (PREDICT_FALSE(my_pm->inuse < ((BITS_PER_INST*2)/3))) {
464 /* "hard" way, best-fit. $$$$ Throttle complaint */
465 min_inuse = PORTS_PER_ADDR + 1;
467 for (i = 0; i < pm_len; i++) {
469 if (PREDICT_FALSE(ip_n_to_1)) {
470 if(PREDICT_TRUE(ip_n_to_1 == 1)) {
471 if (PREDICT_FALSE(!my_pm->inuse)) {
472 min_inuse = my_pm->inuse;
473 min_index = my_pm - pm;
476 if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1)) {
477 if (PREDICT_TRUE(my_pm->inuse < min_inuse)) {
478 min_inuse = my_pm->inuse;
479 min_index = my_pm - pm;
486 if (PREDICT_TRUE(my_pm->inuse < min_inuse)) {
487 min_inuse = my_pm->inuse;
488 min_index = my_pm - pm;
493 if (PREDICT_TRUE(min_inuse < PORTS_PER_ADDR)) {
494 my_pm = pm + min_index;
495 my_index = min_index;
499 /* Completely out of ports */
500 #ifdef DEBUG_PRINTF_ENABLED
501 PLATFORM_DEBUG_PRINT("%s out of ports\n", __FUNCTION__);
505 *err = CNAT_NO_PORT_ANY;
509 case PORT_ALLOC_DIRECTED:
510 //ASSERT(*index < pm_len);
511 if (PREDICT_FALSE(*index > pm_len)) {
513 *err = CNAT_INV_PORT_DIRECT;
521 msg_spp_err("bad allocation type in cnat_port_alloc");
523 *err = CNAT_ERR_PARSER;
528 if (PREDICT_FALSE(my_pm == NULL)) {
532 if (PREDICT_FALSE(my_pm->inuse >= BITS_PER_INST)) {
534 if (atype == PORT_ALLOC_DIRECTED) {
535 *err = CNAT_BAD_INUSE_DIRECT;
537 *err = CNAT_BAD_INUSE_ANY;
547 * public ipv4 address/port allocator for dynamic ports
549 * 200K users / 20M translations means vec_len(cnat_portmap) will be
554 cnat_dynamic_port_alloc_v2 (
555 cnat_portmap_v2_t *pm,
557 port_pair_t pair_type,
561 u16 static_port_range
562 #ifndef NO_BULK_LOGGING
563 , bulk_alloc_size_t bulk_size,
571 cnat_errno_t my_err = CNAT_NO_POOL_ANY;
572 cnat_portmap_v2_t *my_pm = 0;
575 uword bit_test_result;
576 uword max_trys_to_find_port;
579 ASSERT(o_ipv4_address);
582 my_pm = cnat_dynamic_addr_alloc_from_pm(pm, atype, index, &my_err, ip_n_to_1,
585 if (PREDICT_FALSE(my_pm == NULL)) {
588 if(PREDICT_FALSE(my_pm->dyn_full == 1)) {
589 if (atype == PORT_ALLOC_DIRECTED) {
590 return (CNAT_NOT_FOUND_DIRECT);
592 return (CNAT_NOT_FOUND_ANY);
597 PLATFORM_DEBUG_PRINT("ALLOC_PORT_V2: My_Instance_Number %d: IP addr 0x%x, Inuse %d\n",
598 my_instance_number, my_pm->ipv4_address, my_pm->inuse);
601 rseed_port = randq1(rseed_port);
604 * Exclude the static port range for allocating dynamic ports
606 start_bit = (rseed_port) % (BITS_PER_INST - static_port_range);
607 start_bit = start_bit + static_port_range;
609 #ifndef NO_BULK_LOGGING
610 *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
611 if(BULK_ALLOC_SIZE_NONE != bulk_size)
613 /* We need the start port of the range to be alined on integer multiple
615 max_trys_to_find_port = BITS_PER_INST/bulk_size;
616 start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size;
619 #endif /* #ifndef NO_BULK_LOGGING */
620 max_trys_to_find_port = BITS_PER_INST;
622 /* Allocate a random port / port-pair */
623 for (i = 0; i < max_trys_to_find_port; i++) {
625 /* start_bit is only a u16.. so it can rollover and become zero */
626 if (PREDICT_FALSE((start_bit >= BITS_PER_INST) ||
627 (start_bit < static_port_range))) {
628 start_bit = static_port_range;
629 #ifndef NO_BULK_LOGGING
630 if(BULK_ALLOC_SIZE_NONE != bulk_size) {
631 start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size;
633 #endif /* #ifndef NO_BULK_LOGGING */
635 /* Scan forward from random position */
636 #ifndef NO_BULK_LOGGING
637 if(BULK_ALLOC_SIZE_NONE != bulk_size) {
638 bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm,
639 start_bit, bulk_size);
642 #endif /* #ifndef NO_BULK_LOGGING */
643 bit_test_result = clib_bitmap_get_no_check(my_pm->bm, start_bit);
645 if (PREDICT_TRUE(bit_test_result)) {
646 new_port = bit2port(start_bit);
647 #ifndef NO_BULK_LOGGING
648 if(BULK_ALLOC_SIZE_NONE != bulk_size)
649 *nfv9_log_req = new_port;
651 if ((pair_type == PORT_S_ODD) &&
652 (!(new_port & 0x1))) {
653 #ifndef NO_BULK_LOGGING
654 if(BULK_ALLOC_SIZE_NONE != bulk_size) {
655 start_bit++; /* Just use the next one in the bulk range */
659 #endif /* #ifndef NO_BULK_LOGGING */
661 } else if ((pair_type == PORT_S_EVEN) &&
666 /* OK we got one or two suitable ports */
671 #ifndef NO_BULK_LOGGING
672 if(BULK_ALLOC_SIZE_NONE != bulk_size)
673 start_bit += bulk_size;
675 #endif /* #ifndef NO_BULK_LOGGING */
678 } /* end of for loop */
680 /* Completely out of ports */
682 /* Port allocation failure */
683 /* set dyn_full flag. This would be used to verify
684 * for further dyn session before searching for port
686 if (atype == PORT_ALLOC_DIRECTED) {
688 return (CNAT_NOT_FOUND_DIRECT);
691 return (CNAT_NOT_FOUND_ANY);
698 cgn_clib_bitmap_clear_no_check (my_pm->bm, start_bit);
702 *o_ipv4_address = my_pm->ipv4_address;
705 return (CNAT_SUCCESS);
710 * cnat_alloc_port_from_pm
711 * Given a portmap structure find port/port_pair that are free
713 * The assumption in this function is that bit in bm corresponds
714 * to a port number. This is TRUE and hence there is no call
715 * to the function bit2port here, though it is done in other
716 * places in this file.
720 cnat_alloc_port_from_pm (
723 cnat_portmap_v2_t *my_pm,
724 port_pair_t pair_type
725 #ifndef NO_BULK_LOGGING
726 , bulk_alloc_size_t bulk_size,
728 #endif /* #ifnded NO_BULK_ALLOCATION */
733 u32 total_ports = end_port - start_port + 1;
734 uword bit_test_result;
735 uword max_trys_to_find_port;
737 rseed_port = randq1(rseed_port);
739 start_bit = rseed_port % total_ports;
740 start_bit = start_bit + start_port;
741 #ifndef NO_BULK_LOGGING
742 *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
743 if(BULK_ALLOC_SIZE_NONE != bulk_size)
745 /* We need the start port of the range to be alined on integer multiple
747 max_trys_to_find_port = total_ports/bulk_size;
748 start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size;
751 #endif /* #ifndef NO_BULK_LOGGING */
752 max_trys_to_find_port = total_ports;
754 /* Allocate a random port / port-pair */
755 for (i = 0; i < max_trys_to_find_port; i++) {
756 /* start_bit is only a u16.. so it can rollover and become zero */
757 if (PREDICT_FALSE((start_bit >= end_port) ||
758 (start_bit < start_port))) {
759 start_bit = start_port;
760 #ifndef NO_BULK_LOGGING
761 if(BULK_ALLOC_SIZE_NONE != bulk_size) {
762 start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size;
764 #endif /* #ifndef NO_BULK_LOGGING */
767 /* Scan forward from random position */
768 #ifndef NO_BULK_LOGGING
769 if(BULK_ALLOC_SIZE_NONE != bulk_size) {
770 bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm,
771 start_bit, bulk_size);
774 #endif /* #ifndef NO_BULK_LOGGING */
775 bit_test_result = clib_bitmap_get_no_check(my_pm->bm, start_bit);
777 if (PREDICT_TRUE(bit_test_result)) {
778 #ifndef NO_BULK_LOGGING
779 if(BULK_ALLOC_SIZE_NONE != bulk_size) {
780 /* Got the entire bulk range */
781 *nfv9_log_req = bit2port(start_bit);
784 #endif /* #ifndef NO_BULK_LOGGING */
786 * For PORT_PAIR, first port has to be Even
787 * subsequent port <= end_port
788 * subsequent port should be unallocated
790 if ((start_bit & 0x1) ||
791 ((start_bit + 1) > end_port) ||
792 (clib_bitmap_get_no_check(my_pm->bm,
793 (start_bit + 1)) == 0)) {
797 #ifndef NO_BULK_LOGGING
799 #endif /* #ifndef NO_BULK_LOGGING */
800 } /* if( free port found ) */
803 #ifndef NO_BULK_LOGGING
804 if(BULK_ALLOC_SIZE_NONE != bulk_size) {
805 start_bit += bulk_size;
807 #endif /* #ifndef NO_BULK_LOGGING */
811 return (BITS_PER_INST);
815 * cnat_dynamic_port_alloc_rtsp
816 * public ipv4 address/port allocator for dynamic ports
818 * 200K users / 20M translations means vec_len(cnat_portmap) will be
824 cnat_dynamic_port_alloc_rtsp (
825 cnat_portmap_v2_t *pm,
827 port_pair_t pair_type,
833 #ifndef NO_BULK_LOGGING
834 , bulk_alloc_size_t bulk_size,
841 u32 current_timestamp;
842 cnat_errno_t my_err = CNAT_NO_POOL_ANY;
843 cnat_portmap_v2_t *my_pm = 0;
847 ASSERT(o_ipv4_address);
850 my_pm = cnat_dynamic_addr_alloc_from_pm(pm, atype, index, &my_err, 0,rseed_ip);
852 if (PREDICT_FALSE(my_pm == NULL)) {
857 PLATFORM_DEBUG_PRINT("ALLOC_PORT_V2: My_Instance_Number %d: IP addr 0x%x, Inuse %d\n",
858 my_instance_number, my_pm->ipv4_address, my_pm->inuse);
862 cnat_alloc_port_from_pm(start_range, end_range, my_pm, pair_type
863 #ifndef NO_BULK_LOGGING
864 , bulk_size, nfv9_log_req
865 #endif /* #ifndef NO_BULK_LOGGING */
868 if (alloc_bit < BITS_PER_INST) {
869 if (pair_type == PORT_PAIR) {
871 cgn_clib_bitmap_clear_no_check (my_pm->bm, alloc_bit);
872 cgn_clib_bitmap_clear_no_check (my_pm->bm, alloc_bit+1);
876 cgn_clib_bitmap_clear_no_check (my_pm->bm, alloc_bit);
881 *o_ipv4_address = my_pm->ipv4_address;
883 *o_port = bit2port(alloc_bit);;
885 return (CNAT_SUCCESS);
888 /* Completely out of ports */
889 current_timestamp = spp_trace_log_get_unix_time_in_seconds();
890 if (PREDICT_FALSE((current_timestamp - my_pm->last_sent_timestamp) >
892 spp_printf(CNAT_NO_EXT_PORT_AVAILABLE, 0, NULL);
893 my_pm->last_sent_timestamp = current_timestamp;
897 /* Port allocation failure */
898 if (atype == PORT_ALLOC_DIRECTED) {
899 return (CNAT_NOT_FOUND_DIRECT);
901 return (CNAT_NOT_FOUND_ANY);
906 cnat_dynamic_port_alloc_rtsp (
907 cnat_portmap_v2_t *pm,
909 port_pair_t pair_type,
915 #ifndef NO_BULK_LOGGING
916 , bulk_alloc_size_t bulk_size,
922 return (CNAT_NOT_FOUND_ANY);
928 * cnat_mapped_static_port_alloc_v2
932 cnat_mapped_static_port_alloc_v2 (
933 cnat_portmap_v2_t *pm,
938 #ifndef NO_BULK_LOGGING
940 bulk_alloc_size_t bulk_size
948 cnat_portmap_v2_t *my_pm = 0;
954 * Map the port to the bit in the pm bitmap structure.
955 * Note that we use ports from 1024..65535, so
956 * port number x corresponds to (x-1024) position in bitmap
958 bm_bit = port2bit(port);
960 pm_len = vec_len(pm);
964 if (PREDICT_FALSE(pm_len == 0)) {
965 return (CNAT_NO_POOL_ANY);
969 * Find the pm that is allocated for this translated IP address
973 for (i = 0; i < pm_len; i++) {
975 if (PREDICT_FALSE(my_pm->ipv4_address == ipv4_address)) {
981 if ((PREDICT_FALSE(my_index >= pm_len)) ||
982 ((PREDICT_FALSE(ip_n_to_1)) && (PREDICT_TRUE(my_pm->private_ip_users_count >= ip_n_to_1)))) {
983 return (CNAT_NO_POOL_ANY);
988 case PORT_ALLOC_DIRECTED:
989 if (PREDICT_FALSE(*index > pm_len)) {
990 return (CNAT_INV_PORT_DIRECT);
994 my_pm = pm + my_index;
995 if (PREDICT_FALSE(my_pm->ipv4_address != ipv4_address)) {
996 if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) {
997 PLATFORM_DEBUG_PRINT("Delete all main db entry for that particular in ipv4 address\n");
999 return (CNAT_INV_PORT_DIRECT);
1005 msg_spp_err("bad allocation type in cnat_port_alloc");
1006 return (CNAT_ERR_PARSER);
1010 if (PREDICT_FALSE(my_pm == NULL)) {
1011 return (CNAT_NO_POOL_ANY);
1015 * Check if the port is already allocated to some other mapping
1017 if (PREDICT_FALSE(clib_bitmap_get_no_check (my_pm->bm, bm_bit) == 0)) {
1018 return (CNAT_NO_POOL_ANY);
1022 PLATFORM_DEBUG_PRINT("ALLOC_PORT_V2: My_Instance_Number %d: IP addr 0x%x, Inuse %d\n",
1023 my_instance_number, my_pm->ipv4_address, my_pm->inuse);
1027 * Indicate that the port is already allocated
1029 cgn_clib_bitmap_clear_no_check (my_pm->bm, bm_bit);
1034 return (CNAT_SUCCESS);
1037 void cnat_port_free_v2 (
1038 cnat_portmap_v2_t *pm,
1040 port_pair_t pair_type,
1042 u16 static_port_range)
1044 cnat_portmap_v2_t *my_pm;
1047 /* check for valid portmap */
1048 if (PREDICT_FALSE(index > vec_len(pm))) {
1049 spp_printf(CNAT_INVALID_INDEX_TO_FREE_PORT, 0, 0);
1054 bit = port2bit(base_port);
1057 if(clib_bitmap_get_no_check(my_pm->bm, bit))
1058 ASSERT(clib_bitmap_get_no_check(my_pm->bm, bit) == 0);
1061 cgn_clib_bitmap_set_no_check(my_pm->bm, bit);
1064 if(base_port >= static_port_range) {
1065 /* Clear the full flag. we can have a new dynamic session now */
1066 my_pm->dyn_full = 0;
1072 void cnat_portmap_dump_v2 (cnat_portmap_v2_t *pm, u16 print_limit)
1079 for (i = 0; i < BITS_PER_INST; i++) {
1080 if (PREDICT_FALSE(clib_bitmap_get_no_check (pm->bm, i) == 0)) {
1081 if (PREDICT_TRUE(inuse++ < print_limit))
1082 PLATFORM_DEBUG_PRINT(" %d", bit2port(i));
1085 if (PREDICT_FALSE(inuse >= print_limit)) {
1086 PLATFORM_DEBUG_PRINT("%d printed, print limit is %d\n",
1087 inuse, print_limit);
1089 PLATFORM_DEBUG_PRINT("\n");
1096 clib_error_t *cnat_ports_init(vlib_main_t *vm)
1098 cnat_ports_main_t *mp = &cnat_ports_main;
1101 mp->vnet_main = vnet_get_main();
1103 /* suppress crypto-random port numbering */
1105 if (spp_get_int_prop("no_crypto_random_ports") == 0)
1106 crypto_random32(&seed);
1112 VLIB_INIT_FUNCTION(cnat_ports_init);