2 *------------------------------------------------------------------
3 * cnat_bulk_ports.c - wrappers for bulk port allocation
5 * Copyright (c) 2011-2013 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 *------------------------------------------------------------------
21 #include <vlib/vlib.h>
22 #include <vnet/vnet.h>
23 #include <vppinfra/error.h>
24 #include <vnet/buffer.h>
25 #include <vppinfra/vec.h>
26 #include <vppinfra/hash.h>
27 #include <vppinfra/pool.h>
28 #include <vppinfra/bitmap.h>
31 #include "cnat_config.h"
32 #include "cnat_global.h"
33 #include "cnat_logging.h"
34 #include "spp_timers.h"
35 #include "platform_common.h"
36 #include "cgn_bitmap.h"
37 #include "spp_platform_trace_log.h"
38 #include "cnat_ports.h"
40 #ifndef NO_BULK_LOGGING
42 #define PORT_TO_CACHE(y, z) ((y)/(z))
43 /* The last bit (MSB) is used to indicate whether the cache entry is full */
44 #define CACHE_TO_PORT(x, z) (((x)& 0x7FFF) * (z))
45 #define IS_CACHE_ENTRY_FULL(x) ((x) & 0x8000)
46 #define MARK_CACHE_ENTRY_AS_FULL(x) ((x) = ((x) | 0x8000))
47 #define UNMARK_CACHE_ENTRY_AS_FULL(x) ((x) = ((x) & 0x7FFF))
48 #define CACHE_ENTRY_WITHOUT_FULL_STAT(x) ((x) & 0x7FFF)
51 #define NUM_BULK_CHECK 128 /* max number of previous chache to check.
52 * somewhat orbirtrary.. assume 64 as bulk size.. can handle up
53 * to 128*64 ports allocated by a single subscriber */
55 /* #define DEBUG_BULK_PORT 1 */
56 /* #define DEBUG_BULK_PORT_DETAIL 1 */
57 #define HAVE_BULK_PORT_STATS 1
59 #ifdef HAVE_BULK_PORT_STATS
60 static uword bulk_cache_hit_count;
61 static uword bulk_port_use_count;
62 static uword bulk_port_alloc_count;
63 static uword mapped_port_alloc_count;
64 #endif /* HAVE_BULK_PORT_STATS */
66 static u32 bulk_port_rand_across;
68 void show_bulk_port_allocation(u16 in_vrfid, u32 inside_ip)
70 cnat_db_key_bucket_t u_ki;
71 cnat_user_db_entry_t *udb;
74 cnat_main_db_entry_t *db = NULL;
75 i16 printed_so_far = 0; /* entries printed so far */
76 u16 prev_bulks[NUM_BULK_CHECK];
77 cnat_vrfmap_t *my_vrfmap = 0;
78 cnat_vrfmap_t *vrfmap = 0;
79 bulk_alloc_size_t bulk_size;
81 u_ki.k.k.vrf = in_vrfid;
82 u_ki.k.k.ipv4 = inside_ip;
85 PLATFORM_DEBUG_PRINT("Searching for user %x in invrf %d\n",
87 udb = cnat_user_db_lookup_entry(&u_ki);
89 PLATFORM_DEBUG_PRINT("No such user\n"); return;
92 pool_foreach (vrfmap, cnat_map_by_vrf, ({
93 if(vrfmap->i_vrf == in_vrfid) {
99 PLATFORM_DEBUG_PRINT("Vrf map not found\n");
102 bulk_size = BULKSIZE_FROM_VRFMAP(my_vrfmap);
104 if(bulk_size == BULK_ALLOC_SIZE_NONE) {
105 PLATFORM_DEBUG_PRINT("Bulk allocation not enabled\n");
109 PLATFORM_DEBUG_PRINT("\nBulk cache for subscriber 0x%x: ", inside_ip);
110 for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
111 PLATFORM_DEBUG_PRINT("%d , ",
112 CACHE_TO_PORT(udb->bulk_port_range_cache[i], bulk_size));
114 PLATFORM_DEBUG_PRINT("\nNon cached bulk allocation for subscriber 0x%x:\n",
117 memset(prev_bulks, 0,sizeof(prev_bulks));
119 head = udb->translation_list_head_index;
120 if(PREDICT_FALSE(head == EMPTY)) {
123 db = cnat_main_db + head;
125 /* skip static ports - static ports may not belong to bulk pool*/
126 if(db->out2in_key.k.port < cnat_static_port_range) goto next_entry;
128 u16 bm_index = PORT_TO_CACHE(db->out2in_key.k.port, bulk_size);
130 /*Check if we have already tested this bulk */
131 for(i=0; i < printed_so_far; i++) {
132 if(prev_bulks[i] == bm_index) goto next_entry;
135 /*Check if this base port is already part of cache */
136 for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
137 if(CACHE_ENTRY_WITHOUT_FULL_STAT(udb->bulk_port_range_cache[i])
142 /* this is not in chache already */
143 PLATFORM_DEBUG_PRINT("%d ", CACHE_TO_PORT(bm_index, bulk_size));
144 if(printed_so_far < NUM_BULK_CHECK) {
145 prev_bulks[printed_so_far] = bm_index;
150 db = cnat_main_db + db->user_ports.next;
152 * its a circular list, so if we have reached the head again
153 * all the entries for that user have been read
155 if (db == (cnat_main_db + head)) {
158 } /* while loop for db entries */
160 PLATFORM_DEBUG_PRINT("\n");
164 void show_bulk_port_stats()
167 cnat_vrfmap_t *my_vrfmap = 0;
168 PLATFORM_DEBUG_PRINT("Bulk size settings of each inside vrf ...\n");
169 pool_foreach (my_vrfmap, cnat_map_by_vrf, ({
170 PLATFORM_DEBUG_PRINT("vrf id %d, bulk size %d\n", my_vrfmap->i_vrf,
171 BULKSIZE_FROM_VRFMAP(my_vrfmap));
174 #ifdef HAVE_BULK_PORT_STATS
175 PLATFORM_DEBUG_PRINT("\nBulk port allocation, use and cache hit statistics\n");
176 PLATFORM_DEBUG_PRINT("Number of times bulk ports allocated %lld\n",
177 bulk_port_alloc_count);
178 PLATFORM_DEBUG_PRINT("Number of times pre-allocated ports used %lld\n",
179 bulk_port_use_count);
180 PLATFORM_DEBUG_PRINT(
181 "Number of times pre-allocated bulk port found from cache %lld\n",
182 bulk_cache_hit_count);
183 PLATFORM_DEBUG_PRINT(
184 "Number of times mapped port (static) allocations made %lld\n",
185 mapped_port_alloc_count);
187 PLATFORM_DEBUG_PRINT("\nNat44 bulk port statistics not turned on\n");
188 #endif /* HAVE_BULK_PORT_STATS */
191 void clear_bulk_port_stats()
193 #ifdef HAVE_BULK_PORT_STATS
194 bulk_port_alloc_count = 0;
195 bulk_port_use_count = 0;
196 bulk_cache_hit_count = 0;
197 mapped_port_alloc_count = 0;
198 #endif /* HAVE_BULK_PORT_STATS */
202 void cnat_update_bulk_range_cache(cnat_user_db_entry_t *udb, u16 o_port,
203 bulk_alloc_size_t bulk_size)
207 #ifdef DEBUG_BULK_PORT
208 PLATFORM_DEBUG_PRINT("%s, null udb!\n", __func__);
212 if(BULK_ALLOC_SIZE_NONE == bulk_size) { /* no bulk logging */
216 /* Take care of caching */
220 if(PREDICT_FALSE(o_port <= 0)) {
221 #ifdef DEBUG_BULK_PORT
222 PLATFORM_DEBUG_PRINT("%s invalid port: %d\n", __func__, o_port);
227 /* First preference is for the cache entry's that are not used yet */
228 for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
230 udb->bulk_port_range_cache[i] == (i16)BULK_RANGE_INVALID)) {
231 udb->bulk_port_range_cache[i] = PORT_TO_CACHE(o_port, bulk_size);
236 /* Now check if any cache entry is full and if it can be replaced */
237 for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
238 if(PREDICT_FALSE(IS_CACHE_ENTRY_FULL(udb->bulk_port_range_cache[i]))) {
239 udb->bulk_port_range_cache[i] = PORT_TO_CACHE(o_port, bulk_size);
248 void cnat_port_free_v2_bulk (
249 cnat_portmap_v2_t *pm,
253 cnat_user_db_entry_t *udb,
254 u16 static_port_range,
255 bulk_alloc_size_t bulk_size,
258 cnat_portmap_v2_t *my_pm;
261 int unmark_full_status = 0;
263 *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
265 /* First free up the port */
266 cnat_port_free_v2(pm, index, ptype, base_port, static_port_range);
267 if(BULK_ALLOC_SIZE_NONE == bulk_size) /* no bulk logging */
269 if(PREDICT_FALSE(!udb)) {
270 #ifdef DEBUG_BULK_PORT
271 PLATFORM_DEBUG_PRINT("%s udb is null\n", __func__);
275 if(PREDICT_FALSE(base_port < static_port_range)) {
278 /* Now check if cache needs to be removed */
280 base_port = base_port/bulk_size;
281 base_port = base_port * bulk_size; /*Align it to multiples of bulk_size */
282 if(PREDICT_TRUE(!cgn_clib_bitmap_check_if_all(
283 my_pm->bm, base_port, bulk_size))) {
284 *nfv9_log_req = CACHE_ALLOC_NO_LOG_REQUIRED;
285 unmark_full_status = 1;
286 /* One or more ports are still in use */
288 *nfv9_log_req = base_port; /* logging required now. indicate base port*/
290 bm_index = PORT_TO_CACHE(base_port, bulk_size);
291 /* Now check if this is in the cache */
292 for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
294 CACHE_ENTRY_WITHOUT_FULL_STAT(udb->bulk_port_range_cache[i]))
296 if(unmark_full_status) {
297 /* Unmark full stat.. if it was marked so..*/
298 UNMARK_CACHE_ENTRY_AS_FULL(udb->bulk_port_range_cache[i]);
300 udb->bulk_port_range_cache[i] = (i16)BULK_RANGE_INVALID;
301 #ifdef DEBUG_BULK_PORT
302 PLATFORM_DEBUG_PRINT(
303 "Clearing cache for client 0x%x, bulk port %d\n",
304 my_pm->ipv4_address, base_port);
314 /* Get suitable port from range */
315 static i16 get_suiting_port_pos_from_range(cnat_portmap_v2_t *my_pm,
316 u16 bulk_start, i16 bulk_size, port_pair_t pair_type)
318 i16 num_pos = 0, num_bits, iterations;
321 i16 num_uwords = bulk_size/BITS(my_pm->bm[0]);
323 if(PREDICT_FALSE(!num_uwords)) {
325 num_bits = bulk_size;
328 bulk_port_rand_across = randq1(bulk_port_rand_across);
329 iterations = bulk_port_rand_across % num_uwords;
330 num_bits = BITS(my_pm->bm[0]);
334 bulk_ports = cgn_clib_bitmap_get_bits(my_pm->bm,
335 (bulk_start + iterations * BITS(my_pm->bm[0])), num_bits);
336 #ifdef DEBUG_BULK_PORT_DETAIL
337 PLATFORM_DEBUG_PRINT("%s %d, bulk start %d, num_bits %d, ports %lld \n",
338 __func__, __LINE__, bulk_start, num_bits, bulk_ports);
339 #endif /* DEBUG_BULK_PORT_DETAIL */
340 if(PREDICT_FALSE(!bulk_ports)) goto next_uword;
341 if(PREDICT_TRUE((pair_type == PORT_SINGLE)
342 || (pair_type == PORT_PAIR))) {
345 } else if(pair_type == PORT_S_ODD) {
348 } else if(pair_type == PORT_S_EVEN) {
353 for(; num_pos < num_bits; num_pos = num_pos + inc) {
354 if(!((bulk_ports >> num_pos) & 1))
355 continue; /* In use */
356 /* Check if the available port meets our
357 * criteria such as add, even, pair etc */
358 else if(PREDICT_FALSE(
359 (pair_type == PORT_PAIR) && ((num_pos & 0x1) ||
360 (!((bulk_ports >> (num_pos + 1)) & 1)))))
362 else break; /* Found one that meets the criteria */
364 if(num_pos < num_bits)
365 return (num_pos + iterations * BITS(my_pm->bm[0]));
367 num_bits = BITS(my_pm->bm[0]);
368 bulk_size -= BITS(my_pm->bm[0]);
370 if(iterations >= num_uwords) iterations = 0;
371 } while (bulk_size > 0);
373 return -2; /* nothing found */
376 static cnat_errno_t try_bulk_port_from_non_cache(
377 cnat_user_db_entry_t *udb,
378 cnat_portmap_v2_t *my_pm,
379 port_pair_t pair_type,
380 bulk_alloc_size_t bulk_size,
382 u16 static_port_range
386 1. user should have existing translations.. otherwise, we wouldn't get here.
387 2. For each, get the outside port. get the base port.
388 check if it is already in cache
389 3. if not, we stand chance.
390 4. Check for availability from this non cached pool.
391 5. if found, repalce this with one of the cache that is invalid or full??
392 6. if we are replacing the cache.. it has to be governed by user
393 preference on prefer oldest pool or prefer newest pool
396 cnat_main_db_entry_t *db = NULL;
397 u16 bulk_start; /* start point in 64 bitmap array to search for port */
398 i16 port_pos; /* indicates the position of available port in bulk */
399 i16 i; /* just a counter */
400 i16 attempts_so_far = 0; /* (futile-;) attemps so far..*/
401 u16 prev_bulks[NUM_BULK_CHECK];
403 memset(prev_bulks, 0,sizeof(prev_bulks));
405 head = udb->translation_list_head_index;
406 if(PREDICT_FALSE(head == EMPTY)) return CNAT_NO_PRE_ALLOCATED_BULK_PORTS;
408 db = cnat_main_db + head;
409 while (1) { //what should be the limit??
411 /* skip static ports - static ports may not belong to bulk pool*/
412 if(db->out2in_key.k.port < static_port_range) goto next_entry;
414 u16 bm_index = PORT_TO_CACHE(db->out2in_key.k.port, bulk_size);
416 /*Check if we have already tested this bulk */
417 for(i=0; i < attempts_so_far; i++) {
418 if(prev_bulks[i] == bm_index) {
423 /*Check if this base port is already part of cache */
424 for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
425 if(CACHE_ENTRY_WITHOUT_FULL_STAT(udb->bulk_port_range_cache[i])
430 /* this is not in chache already */
431 bulk_start = CACHE_TO_PORT(bm_index, bulk_size);
432 port_pos = get_suiting_port_pos_from_range(my_pm,
433 bulk_start, bulk_size, pair_type);
435 if(port_pos < 0) { /* no port available in this range */
436 /* Mark this bulk so that we don't have to try this again */
437 if(attempts_so_far < NUM_BULK_CHECK) {
438 prev_bulks[attempts_so_far] = bm_index;
444 /* Got one...Get the port number */
445 *port_available = bulk_start + port_pos;
447 /* Check to see if we shoud replace one of the cache */
448 for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
449 if(PREDICT_FALSE((udb->bulk_port_range_cache[i]
450 == (i16)BULK_RANGE_INVALID) || (
451 IS_CACHE_ENTRY_FULL(udb->bulk_port_range_cache[i])))) {
452 udb->bulk_port_range_cache[i] = bm_index;
456 /* Check to replace an existing (in use) entry */
457 /* TODO: enforce policy */
458 /* order of looping should depend on policy */
463 db = cnat_main_db + db->user_ports.next;
465 * its a circular list, so if we have reached the head again
466 * all the entries for that user have been read
468 if (db == (cnat_main_db + head)) {
471 } /* while loop for db entries */
472 /* no ports available from pre allocated bulk pool */
473 return CNAT_NO_PORT_FROM_BULK;
477 cnat_dynamic_port_alloc_v2_bulk (
478 cnat_portmap_v2_t *pm,
480 port_pair_t pair_type,
484 u16 static_port_range,
485 cnat_user_db_entry_t *udb,
486 bulk_alloc_size_t bulk_size,
494 u16 port_available = 0;
496 cnat_portmap_v2_t *my_pm;
498 if((BULK_ALLOC_SIZE_NONE != bulk_size) /* bulk logging enabled */
499 && (udb)) { /* This user does have translations already */
504 /* We have a case to check if bulk allocated ports can be used */
505 /* TODO: order of looping to be based on policy
506 * like prefer older or prefer newer ??
507 * For now, start with most recent cache entry
508 * so that we stand a better chance of
511 for(i= 0; i < BULK_RANGE_CACHE_SIZE; i++) {
512 if(PREDICT_TRUE((udb->bulk_port_range_cache[i] ==
513 (i16)BULK_RANGE_INVALID) ||
514 IS_CACHE_ENTRY_FULL(udb->bulk_port_range_cache[i]))) {
515 continue; /* This range is not initialized yet or it is full */
517 bulk_start = CACHE_TO_PORT(udb->bulk_port_range_cache[i],
519 port_pos = get_suiting_port_pos_from_range(my_pm,
520 bulk_start, bulk_size, pair_type);
521 if(PREDICT_FALSE(port_pos < 0)) {
522 /* Mark this cache entry as full so that we do not
523 * waste time on this entry again */
524 MARK_CACHE_ENTRY_AS_FULL(udb->bulk_port_range_cache[i]);
525 #ifdef DEBUG_BULK_PORT
526 PLATFORM_DEBUG_PRINT("Marked bulk cache entry %d as full for %x \n",
527 i, my_pm->ipv4_address);
528 #endif /* #ifdef DEBUG_BULK_PORT */
531 /* Get the port number */
532 port_available = bulk_start+ port_pos;
533 #ifdef DEBUG_BULK_PORT
534 PLATFORM_DEBUG_PRINT(
535 "Found port from cache : IP 0x%x, port %d %d iterations\n",
536 my_pm->ipv4_address, port_available, i)
538 #ifdef HAVE_BULK_PORT_STATS
539 bulk_cache_hit_count++;
540 #endif /* HAVE_BULK_PORT_STATS */
542 } /* end of for loop for cache check */
543 /* If we have not found a port yet, check if we can have
544 * pre allocated bulk port from non-cache */
545 if(PREDICT_FALSE(i == BULK_RANGE_CACHE_SIZE)) {
546 if( try_bulk_port_from_non_cache(udb, my_pm, pair_type,
547 bulk_size, &port_available,
548 static_port_range) != CNAT_SUCCESS ) {
549 goto ALLCOATE_NEW_BULK;
551 #ifdef DEBUG_BULK_PORT
552 PLATFORM_DEBUG_PRINT("Found port from non-cache : IP 0x%x, port %d\n",
553 my_pm->ipv4_address, port_available);
556 /* Assign the port, mark it as in use */
557 cgn_clib_bitmap_clear_no_check(my_pm->bm, port_available);
559 if(PREDICT_FALSE(pair_type == PORT_PAIR)) {/* Mark the next one too */
560 cgn_clib_bitmap_clear_no_check(my_pm->bm, port_available + 1);
563 *o_ipv4_address = my_pm->ipv4_address;
564 *o_port = port_available;
565 *nfv9_log_req = CACHE_ALLOC_NO_LOG_REQUIRED;
566 #ifdef HAVE_BULK_PORT_STATS
567 bulk_port_use_count++;
568 #endif /* HAVE_BULK_PORT_STATS */
569 return (CNAT_SUCCESS);
572 #ifdef DEBUG_BULK_PORT
573 if(BULK_ALLOC_SIZE_NONE != bulk_size) {
574 PLATFORM_DEBUG_PRINT(
575 "No port available from bulk cache, bulk size %d\n", bulk_size);
578 /* For whatever reason, we have not got a port yet */
579 rv = cnat_dynamic_port_alloc_v2(pm, atype, pair_type, index,
580 o_ipv4_address, o_port, static_port_range, bulk_size, nfv9_log_req,
581 ip_n_to_1, rseed_ip);
582 if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
585 /* Take care of caching */
586 if(PREDICT_FALSE(udb != NULL)) {
587 /* Predict false because, we usually allocate for new users */
588 cnat_update_bulk_range_cache(udb, *o_port, bulk_size);
590 #ifdef HAVE_BULK_PORT_STATS
591 bulk_port_alloc_count++;
592 #endif /* HAVE_BULK_PORT_STATS */
593 return (CNAT_SUCCESS);
598 cnat_static_port_alloc_v2_bulk (
599 cnat_portmap_v2_t *pm,
601 port_pair_t pair_type,
607 u16 static_port_range,
608 cnat_user_db_entry_t *udb,
609 bulk_alloc_size_t bulk_size,
617 * 1. If the port allocated is below dyn start, it should be individual
619 * 2. If NOT, it should be bulk allocated
620 * 3. Try and keep the inside port same as outside port in both the
621 * cases (best effort)
624 * 1. Check if it is below stat port start or user is new or bulk is
625 * disabled. If yes, call existing function
626 * 2. If not, see if we can pick from bulk and yet try to keep the port
627 * same - difficult thing - check if the port is free - then check if the
628 * entire bulk is free - if not check if bulk is owned by the user already.
629 * If all of these fail, call existing function to allocate a new bulk
630 * 3. Update cache, etc return log requirements
636 cnat_portmap_v2_t *my_pm;
637 uword bit_test_result, start_bit;
638 cnat_main_db_entry_t *db = NULL;
640 if((BULK_ALLOC_SIZE_NONE != bulk_size) /* bulk logging enabled */
641 && (udb) && /* This user does have translations already */
642 i_port >= static_port_range ) { /* It is outside stat port range*/
645 /* We have a case to check if bulk allocated ports can be used */
647 /* First check if the required port is available. */
648 if(PREDICT_FALSE(clib_bitmap_get_no_check(my_pm->bm, i_port) == 0)) {
649 goto ALLOCATE_NEW_BULK_STATIC;
652 /* Port is free.. check if the bulk is also free */
653 start_bit= ((i_port/bulk_size) * bulk_size);
654 bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm,
655 start_bit, bulk_size);
656 if(PREDICT_TRUE(bit_test_result)) { /* bulk is available, grab it */
657 goto ALLOCATE_NEW_BULK_STATIC;
660 /* else, bulk is taken by someone. check if it is me */
661 /* Check if we own the bulk by any chance */
662 for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
663 if(udb->bulk_port_range_cache[i] == start_bit) break;
665 if(i == BULK_RANGE_CACHE_SIZE) { /* no luck with cache */
666 head = udb->translation_list_head_index;
667 if(PREDICT_FALSE(head == EMPTY))
668 goto ALLOCATE_NEW_BULK_STATIC;
669 db = cnat_main_db + head;
672 if((db->out2in_key.k.port/bulk_size) * bulk_size == start_bit) {
673 i = 1; /* Just to indicate it is found */
676 db = cnat_main_db + db->user_ports.next;
678 * its a circular list, so if we have reached the head again
679 * all the entries for that user have been read
681 if (db == (cnat_main_db + head)) break;
682 } /* while loop for db entries */
684 goto ALLOCATE_NEW_BULK_STATIC;
687 /* Assign the port, mark it as in use */
688 cgn_clib_bitmap_clear_no_check(my_pm->bm, i_port);
690 *o_ipv4_address = my_pm->ipv4_address;
692 *nfv9_log_req = CACHE_ALLOC_NO_LOG_REQUIRED;
693 #ifdef HAVE_BULK_PORT_STATS
694 bulk_port_use_count++;
695 #endif /* HAVE_BULK_PORT_STATS */
697 #ifdef DEBUG_BULK_PORT
698 PLATFORM_DEBUG_PRINT("%s, %d, found stat port from bulk: %x, %d\n",
700 __LINE__, *o_ipv4_address, *o_port);
701 #endif /* DEBUG_BULK_PORT */
702 return (CNAT_SUCCESS);
705 ALLOCATE_NEW_BULK_STATIC:
706 #ifdef DEBUG_BULK_PORT
707 PLATFORM_DEBUG_PRINT("%s No port available from bulk cache, bulk size %d\n",
710 /* For whatever reason, we have not got a port yet */
711 rv = cnat_static_port_alloc_v2(pm, atype, pair_type, i_ipv4_address,
712 i_port, index, o_ipv4_address, o_port, static_port_range,
713 bulk_size, nfv9_log_req,ip_n_to_1);
714 if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
717 /* Take care of caching only if it was a bulk alloc */
718 if(PREDICT_FALSE(udb && (BULK_ALLOC_NOT_ATTEMPTED != *nfv9_log_req))) {
719 cnat_update_bulk_range_cache(udb, *o_port, bulk_size);
721 #ifdef HAVE_BULK_PORT_STATS
722 bulk_port_alloc_count++;
723 #endif /* HAVE_BULK_PORT_STATS */
724 return (CNAT_SUCCESS);
729 cnat_mapped_static_port_alloc_v2_bulk (
730 cnat_portmap_v2_t *pm,
735 cnat_user_db_entry_t *udb,
736 bulk_alloc_size_t bulk_size,
742 * 1. Check if bulk allocation is required.
743 * 2. Call cnat_mapped_static_port_alloc_v2 to allocate
744 * 3. Decide if alloc has to be cached
745 * 4. Update nfv9_log_req
748 rv = cnat_mapped_static_port_alloc_v2 (pm,
749 atype, index, ipv4_address, port, nfv9_log_req, bulk_size, ip_n_to_1);
750 if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
753 /* Take care of caching only if it was a bulk alloc */
754 if(PREDICT_FALSE(udb && (BULK_ALLOC_NOT_ATTEMPTED != *nfv9_log_req))) {
756 port = port*bulk_size;
757 port = port/bulk_size; /* align it to bulk size boundary */
758 for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
759 if(CACHE_ENTRY_WITHOUT_FULL_STAT(udb->bulk_port_range_cache[i])
760 == PORT_TO_CACHE(port, bulk_size))
763 if( i == BULK_RANGE_CACHE_SIZE) { /* else, it is alredy in cache */
764 cnat_update_bulk_range_cache(udb, port, bulk_size);
767 #ifdef HAVE_BULK_PORT_STATS
768 mapped_port_alloc_count++;
769 #endif /* HAVE_BULK_PORT_STATS */
770 return (CNAT_SUCCESS);
775 cnat_dynamic_port_alloc_rtsp_bulk (
776 cnat_portmap_v2_t *pm,
778 port_pair_t pair_type,
783 u16 static_port_range,
784 cnat_user_db_entry_t *udb,
785 bulk_alloc_size_t bulk_size,
792 * 1. Compute the range of ports required based on the number of digits
793 * in the port request made by the client.
794 * 2. Check if bulk logging is enabled. If not, use the existing method.
795 * 3. Check if there are 2 adjacent ports available that meet the above
796 * criteria in any of the bulk allocations made already.
797 * 4. If yes, mark them in use and return.
798 * 5. If not allocate a new bulk and pick 2 ports in it
802 cnat_portmap_v2_t *my_pm = 0;
803 u32 start_port1, end_port1, start_port2, end_port2;
807 u16 port_available = 0;
810 ASSERT(o_ipv4_address);
814 * Check if the port is 4 digit or 5 digit. I am assuming we are
815 * not getting 3 (or 2 or 1) digit ports, which we cannot anyway
816 * allocate same sized outside ports - as outside ports start from 1024
818 * Static Port has its own reserved range. Ensure that the range is
819 * such that atleast few 4 digit ports are available for RTSP. If
820 * not it does not make sense to do special allocation for RTSP.
822 if (PREDICT_TRUE(static_port_range < MIN_STATIC_PORT_RANGE_FOR_RTSP)) {
824 * 4 digit port or less
826 if (i_port <= 9999) {
827 start_port1 = static_port_range;
831 end_port2 = PORTS_PER_ADDR - 1;
832 } else { /* 5 digit port */
834 end_port1 = PORTS_PER_ADDR - 1;
836 start_port2 = static_port_range;
839 } else { /* Static port range is too big */
840 start_port1 = static_port_range;
841 end_port1 = PORTS_PER_ADDR - 1;
844 * PORTS_PER_ADDR is just a placeholder for
845 * INVALID_PORT, valid ports are b/w 1 and PORTS_PER_ADDR
847 start_port2 = PORTS_PER_ADDR;
848 end_port2 = PORTS_PER_ADDR;
852 if(PREDICT_TRUE(udb != NULL)) {
856 /* Now check if this user already owns a bulk range that is
857 * within start range 1
860 u32 start_range = start_port1;
861 u32 end_range = end_port1;
862 for(range_loop = 0; range_loop < 2; range_loop++) {
863 if((BULK_ALLOC_SIZE_NONE == bulk_size) || (!udb)) {
864 goto ALLOCATE_NEW_RTSP_PORTS;
866 for(i= 0; i < BULK_RANGE_CACHE_SIZE; i++) {
867 if(PREDICT_TRUE((udb->bulk_port_range_cache[i] ==
868 (i16)BULK_RANGE_INVALID) ||
869 IS_CACHE_ENTRY_FULL(udb->bulk_port_range_cache[i]))) {
870 continue; /* This range is not initialized yet or it is full */
873 bulk_start = CACHE_TO_PORT(udb->bulk_port_range_cache[i],
875 if(bulk_start < start_port1 || bulk_start >= end_port1) {
876 continue; /* Not in the range */
879 port_pos = get_suiting_port_pos_from_range(my_pm,
880 bulk_start, bulk_size, pair_type);
881 if(PREDICT_FALSE(port_pos < 0)) {
882 /* Not Marking this cache entry as full as it failed
883 * for pair type. It might have individual entries
887 /* Get the port number */
888 port_available = bulk_start+ port_pos;
889 #ifdef DEBUG_BULK_PORT
890 PLATFORM_DEBUG_PRINT(
891 "Found port from cache : IP 0x%x, port %d %d iterations\n",
892 my_pm->ipv4_address, port_available, i)
894 #ifdef HAVE_BULK_PORT_STATS
895 bulk_cache_hit_count += 2;
896 #endif /* HAVE_BULK_PORT_STATS */
898 } /* end of for loop for cache check */
900 if(PREDICT_FALSE(i == BULK_RANGE_CACHE_SIZE)) {
901 /* we have not found a port yet, but to do not want to try
902 * non-cache bulks.. because, it is a very low probability and
903 * do not want to tweak that code for this special case
904 * The impact of non checking the non-cache is, we give this
905 * user few extra ports .. which is OK
907 goto ALLOCATE_NEW_RTSP_PORTS;
909 #ifdef DEBUG_BULK_PORT
910 PLATFORM_DEBUG_PRINT("RTSP: Found port from non-cache : IP 0x%x, port %d\n",
911 my_pm->ipv4_address, port_available);
914 /* Assign the port, mark it as in use */
915 cgn_clib_bitmap_clear_no_check(my_pm->bm, port_available);
917 cgn_clib_bitmap_clear_no_check(my_pm->bm, port_available + 1);
920 *o_ipv4_address = my_pm->ipv4_address;
921 *o_port = port_available;
922 *nfv9_log_req = CACHE_ALLOC_NO_LOG_REQUIRED;
923 #ifdef HAVE_BULK_PORT_STATS
924 bulk_port_use_count += 2;
925 #endif /* HAVE_BULK_PORT_STATS */
926 return (CNAT_SUCCESS);
928 ALLOCATE_NEW_RTSP_PORTS:
929 /* No luck. Let's try allocating new bulk.. */
930 if(PREDICT_TRUE(CNAT_SUCCESS == cnat_dynamic_port_alloc_rtsp
931 (pm, atype, pair_type,
932 start_range, end_range,index, o_ipv4_address,
933 o_port, bulk_size, nfv9_log_req,rseed_ip))) {
934 if(PREDICT_FALSE(udb &&
935 (BULK_ALLOC_NOT_ATTEMPTED != *nfv9_log_req))) {
936 cnat_update_bulk_range_cache(udb, *o_port, bulk_size);
938 #ifdef HAVE_BULK_PORT_STATS
939 bulk_port_alloc_count++;
940 #endif /* HAVE_BULK_PORT_STATS */
944 /* Could not allocate in range 1.. so move to range 2. */
945 start_range = start_port2;
946 end_range = end_port2;
950 return (CNAT_NOT_FOUND_DIRECT); /* if we are here, we could not get any ports */
954 #else /* Dummy definitions */
955 void show_bulk_port_stats()
957 PLATFORM_DEBUG_PRINT("\nBulk logging feature not included\n");
960 void clear_bulk_port_stats()
962 PLATFORM_DEBUG_PRINT("\nBulk logging feature not included\n");
964 #endif /* NO_BULK_LOGGING */