diff options
Diffstat (limited to 'plugins/vcgn-plugin/vcgn/cnat_bulk_port.c')
-rw-r--r-- | plugins/vcgn-plugin/vcgn/cnat_bulk_port.c | 964 |
1 files changed, 0 insertions, 964 deletions
diff --git a/plugins/vcgn-plugin/vcgn/cnat_bulk_port.c b/plugins/vcgn-plugin/vcgn/cnat_bulk_port.c deleted file mode 100644 index d8894eb8..00000000 --- a/plugins/vcgn-plugin/vcgn/cnat_bulk_port.c +++ /dev/null @@ -1,964 +0,0 @@ -/* - *------------------------------------------------------------------ - * cnat_bulk_ports.c - wrappers for bulk port allocation - * - * Copyright (c) 2011-2013 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------ - */ - - -#include <vlib/vlib.h> -#include <vnet/vnet.h> -#include <vppinfra/error.h> -#include <vnet/buffer.h> -#include <vppinfra/vec.h> -#include <vppinfra/hash.h> -#include <vppinfra/pool.h> -#include <vppinfra/bitmap.h> - -#include "cnat_db.h" -#include "cnat_config.h" -#include "cnat_global.h" -#include "cnat_logging.h" -#include "spp_timers.h" -#include "platform_common.h" -#include "cgn_bitmap.h" -#include "spp_platform_trace_log.h" -#include "cnat_ports.h" - -#ifndef NO_BULK_LOGGING - -#define PORT_TO_CACHE(y, z) ((y)/(z)) -/* The last bit (MSB) is used to indicate whether the cache entry is full */ -#define CACHE_TO_PORT(x, z) (((x)& 0x7FFF) * (z)) -#define IS_CACHE_ENTRY_FULL(x) ((x) & 0x8000) -#define MARK_CACHE_ENTRY_AS_FULL(x) ((x) = ((x) | 0x8000)) -#define UNMARK_CACHE_ENTRY_AS_FULL(x) ((x) = ((x) & 0x7FFF)) -#define CACHE_ENTRY_WITHOUT_FULL_STAT(x) ((x) & 0x7FFF) - - -#define NUM_BULK_CHECK 128 /* max number of previous chache to check. - * somewhat orbirtrary.. assume 64 as bulk size.. can handle up - * to 128*64 ports allocated by a single subscriber */ - -/* #define DEBUG_BULK_PORT 1 */ -/* #define DEBUG_BULK_PORT_DETAIL 1 */ -#define HAVE_BULK_PORT_STATS 1 - -#ifdef HAVE_BULK_PORT_STATS -static uword bulk_cache_hit_count; -static uword bulk_port_use_count; -static uword bulk_port_alloc_count; -static uword mapped_port_alloc_count; -#endif /* HAVE_BULK_PORT_STATS */ - -static u32 bulk_port_rand_across; - -void show_bulk_port_allocation(u16 in_vrfid, u32 inside_ip) -{ - cnat_db_key_bucket_t u_ki; - cnat_user_db_entry_t *udb; - int i; - u32 head; - cnat_main_db_entry_t *db = NULL; - i16 printed_so_far = 0; /* entries printed so far */ - u16 prev_bulks[NUM_BULK_CHECK]; - cnat_vrfmap_t *my_vrfmap = 0; - cnat_vrfmap_t *vrfmap = 0; - bulk_alloc_size_t bulk_size; - - u_ki.k.k.vrf = in_vrfid; - u_ki.k.k.ipv4 = inside_ip; - u_ki.k.k.port = 0; - - PLATFORM_DEBUG_PRINT("Searching for user %x in invrf %d\n", - inside_ip, in_vrfid); - udb = cnat_user_db_lookup_entry(&u_ki); - if(!udb) { - PLATFORM_DEBUG_PRINT("No such user\n"); return; - } - - pool_foreach (vrfmap, cnat_map_by_vrf, ({ - if(vrfmap->i_vrf == in_vrfid) { - my_vrfmap = vrfmap; - break; - }})); - - if(!my_vrfmap) { - PLATFORM_DEBUG_PRINT("Vrf map not found\n"); - return; - } - bulk_size = BULKSIZE_FROM_VRFMAP(my_vrfmap); - - if(bulk_size == BULK_ALLOC_SIZE_NONE) { - PLATFORM_DEBUG_PRINT("Bulk allocation not enabled\n"); - return; - } - - PLATFORM_DEBUG_PRINT("\nBulk cache for subscriber 0x%x: ", inside_ip); - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - PLATFORM_DEBUG_PRINT("%d , ", - CACHE_TO_PORT(udb->bulk_port_range_cache[i], bulk_size)); - } - PLATFORM_DEBUG_PRINT("\nNon cached bulk allocation for subscriber 0x%x:\n", - inside_ip); - ASSERT(udb); - memset(prev_bulks, 0,sizeof(prev_bulks)); - - head = udb->translation_list_head_index; - if(PREDICT_FALSE(head == EMPTY)) { - return; - } - db = cnat_main_db + head; - while (1) { - /* skip static ports - static ports may not belong to bulk pool*/ - if(db->out2in_key.k.port < cnat_static_port_range) goto next_entry; - - u16 bm_index = PORT_TO_CACHE(db->out2in_key.k.port, bulk_size); - - /*Check if we have already tested this bulk */ - for(i=0; i < printed_so_far; i++) { - if(prev_bulks[i] == bm_index) goto next_entry; - } - - /*Check if this base port is already part of cache */ - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(CACHE_ENTRY_WITHOUT_FULL_STAT(udb->bulk_port_range_cache[i]) - == bm_index) { - goto next_entry; - } - } - /* this is not in chache already */ - PLATFORM_DEBUG_PRINT("%d ", CACHE_TO_PORT(bm_index, bulk_size)); - if(printed_so_far < NUM_BULK_CHECK) { - prev_bulks[printed_so_far] = bm_index; - printed_so_far++; - } - -next_entry: - db = cnat_main_db + db->user_ports.next; - /* - * its a circular list, so if we have reached the head again - * all the entries for that user have been read - */ - if (db == (cnat_main_db + head)) { - break; - } - } /* while loop for db entries */ - - PLATFORM_DEBUG_PRINT("\n"); - return; -} - -void show_bulk_port_stats() -{ - - cnat_vrfmap_t *my_vrfmap = 0; - PLATFORM_DEBUG_PRINT("Bulk size settings of each inside vrf ...\n"); - pool_foreach (my_vrfmap, cnat_map_by_vrf, ({ - PLATFORM_DEBUG_PRINT("vrf id %d, bulk size %d\n", my_vrfmap->i_vrf, - BULKSIZE_FROM_VRFMAP(my_vrfmap)); - })); - -#ifdef HAVE_BULK_PORT_STATS - PLATFORM_DEBUG_PRINT("\nBulk port allocation, use and cache hit statistics\n"); - PLATFORM_DEBUG_PRINT("Number of times bulk ports allocated %lld\n", - bulk_port_alloc_count); - PLATFORM_DEBUG_PRINT("Number of times pre-allocated ports used %lld\n", - bulk_port_use_count); - PLATFORM_DEBUG_PRINT( - "Number of times pre-allocated bulk port found from cache %lld\n", - bulk_cache_hit_count); - PLATFORM_DEBUG_PRINT( - "Number of times mapped port (static) allocations made %lld\n", - mapped_port_alloc_count); -#else - PLATFORM_DEBUG_PRINT("\nNat44 bulk port statistics not turned on\n"); -#endif /* HAVE_BULK_PORT_STATS */ -} - -void clear_bulk_port_stats() -{ -#ifdef HAVE_BULK_PORT_STATS - bulk_port_alloc_count = 0; - bulk_port_use_count = 0; - bulk_cache_hit_count = 0; - mapped_port_alloc_count = 0; -#endif /* HAVE_BULK_PORT_STATS */ - return; -} - -void cnat_update_bulk_range_cache(cnat_user_db_entry_t *udb, u16 o_port, - bulk_alloc_size_t bulk_size) -{ - i16 i; - if(!udb) { -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT("%s, null udb!\n", __func__); -#endif - return; - } - if(BULK_ALLOC_SIZE_NONE == bulk_size) { /* no bulk logging */ - return; - } - - /* Take care of caching */ - if(o_port & 0x1) { - o_port--; - } - if(PREDICT_FALSE(o_port <= 0)) { -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT("%s invalid port: %d\n", __func__, o_port); -#endif - return; - } - - /* First preference is for the cache entry's that are not used yet */ - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(PREDICT_FALSE( - udb->bulk_port_range_cache[i] == (i16)BULK_RANGE_INVALID)) { - udb->bulk_port_range_cache[i] = PORT_TO_CACHE(o_port, bulk_size); - return; - } - } - - /* Now check if any cache entry is full and if it can be replaced */ - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(PREDICT_FALSE(IS_CACHE_ENTRY_FULL(udb->bulk_port_range_cache[i]))) { - udb->bulk_port_range_cache[i] = PORT_TO_CACHE(o_port, bulk_size); - return; - } - } - - return; -} - - -void cnat_port_free_v2_bulk ( - cnat_portmap_v2_t *pm, - int index, - port_pair_t ptype, - u16 base_port, - cnat_user_db_entry_t *udb, - u16 static_port_range, - bulk_alloc_size_t bulk_size, - int *nfv9_log_req) -{ - cnat_portmap_v2_t *my_pm; - i16 bm_index; - i16 i; - int unmark_full_status = 0; - - *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED; - - /* First free up the port */ - cnat_port_free_v2(pm, index, ptype, base_port, static_port_range); - if(BULK_ALLOC_SIZE_NONE == bulk_size) /* no bulk logging */ - return; - if(PREDICT_FALSE(!udb)) { -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT("%s udb is null\n", __func__); -#endif - } - - if(PREDICT_FALSE(base_port < static_port_range)) { - return; - } - /* Now check if cache needs to be removed */ - my_pm = pm + index; - base_port = base_port/bulk_size; - base_port = base_port * bulk_size; /*Align it to multiples of bulk_size */ - if(PREDICT_TRUE(!cgn_clib_bitmap_check_if_all( - my_pm->bm, base_port, bulk_size))) { - *nfv9_log_req = CACHE_ALLOC_NO_LOG_REQUIRED; - unmark_full_status = 1; - /* One or more ports are still in use */ - } else { - *nfv9_log_req = base_port; /* logging required now. indicate base port*/ - } - bm_index = PORT_TO_CACHE(base_port, bulk_size); - /* Now check if this is in the cache */ - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(PREDICT_FALSE( - CACHE_ENTRY_WITHOUT_FULL_STAT(udb->bulk_port_range_cache[i])) - == bm_index) { - if(unmark_full_status) { - /* Unmark full stat.. if it was marked so..*/ - UNMARK_CACHE_ENTRY_AS_FULL(udb->bulk_port_range_cache[i]); - } else { - udb->bulk_port_range_cache[i] = (i16)BULK_RANGE_INVALID; -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT( - "Clearing cache for client 0x%x, bulk port %d\n", - my_pm->ipv4_address, base_port); -#endif - } - break; - } - } - return; -} - - -/* Get suitable port from range */ -static i16 get_suiting_port_pos_from_range(cnat_portmap_v2_t *my_pm, - u16 bulk_start, i16 bulk_size, port_pair_t pair_type) -{ - i16 num_pos = 0, num_bits, iterations; - uword bulk_ports; - i16 inc = 0; - i16 num_uwords = bulk_size/BITS(my_pm->bm[0]); - - if(PREDICT_FALSE(!num_uwords)) { - iterations = 0; - num_bits = bulk_size; - bulk_size = 0; - } else { - bulk_port_rand_across = randq1(bulk_port_rand_across); - iterations = bulk_port_rand_across % num_uwords; - num_bits = BITS(my_pm->bm[0]); - } - - do { - bulk_ports = cgn_clib_bitmap_get_bits(my_pm->bm, - (bulk_start + iterations * BITS(my_pm->bm[0])), num_bits); -#ifdef DEBUG_BULK_PORT_DETAIL - PLATFORM_DEBUG_PRINT("%s %d, bulk start %d, num_bits %d, ports %lld \n", - __func__, __LINE__, bulk_start, num_bits, bulk_ports); -#endif /* DEBUG_BULK_PORT_DETAIL */ - if(PREDICT_FALSE(!bulk_ports)) goto next_uword; - if(PREDICT_TRUE((pair_type == PORT_SINGLE) - || (pair_type == PORT_PAIR))) { - num_pos =0; - inc = 1; - } else if(pair_type == PORT_S_ODD) { - num_pos = 1; - inc = 2; - } else if(pair_type == PORT_S_EVEN) { - num_pos =0; - inc = 2; - } - - for(; num_pos < num_bits; num_pos = num_pos + inc) { - if(!((bulk_ports >> num_pos) & 1)) - continue; /* In use */ - /* Check if the available port meets our - * criteria such as add, even, pair etc */ - else if(PREDICT_FALSE( - (pair_type == PORT_PAIR) && ((num_pos & 0x1) || - (!((bulk_ports >> (num_pos + 1)) & 1))))) - continue; - else break; /* Found one that meets the criteria */ - } - if(num_pos < num_bits) - return (num_pos + iterations * BITS(my_pm->bm[0])); -next_uword: - num_bits = BITS(my_pm->bm[0]); - bulk_size -= BITS(my_pm->bm[0]); - iterations++; - if(iterations >= num_uwords) iterations = 0; - } while (bulk_size > 0); - - return -2; /* nothing found */ -} - -static cnat_errno_t try_bulk_port_from_non_cache( - cnat_user_db_entry_t *udb, - cnat_portmap_v2_t *my_pm, - port_pair_t pair_type, - bulk_alloc_size_t bulk_size, - u16 *port_available, - u16 static_port_range - ) -{ - /**** - 1. user should have existing translations.. otherwise, we wouldn't get here. - 2. For each, get the outside port. get the base port. - check if it is already in cache - 3. if not, we stand chance. - 4. Check for availability from this non cached pool. - 5. if found, repalce this with one of the cache that is invalid or full?? - 6. if we are replacing the cache.. it has to be governed by user - preference on prefer oldest pool or prefer newest pool - ********/ - u32 head; - cnat_main_db_entry_t *db = NULL; - u16 bulk_start; /* start point in 64 bitmap array to search for port */ - i16 port_pos; /* indicates the position of available port in bulk */ - i16 i; /* just a counter */ - i16 attempts_so_far = 0; /* (futile-;) attemps so far..*/ - u16 prev_bulks[NUM_BULK_CHECK]; - ASSERT(udb); - memset(prev_bulks, 0,sizeof(prev_bulks)); - - head = udb->translation_list_head_index; - if(PREDICT_FALSE(head == EMPTY)) return CNAT_NO_PRE_ALLOCATED_BULK_PORTS; - - db = cnat_main_db + head; - while (1) { //what should be the limit?? - - /* skip static ports - static ports may not belong to bulk pool*/ - if(db->out2in_key.k.port < static_port_range) goto next_entry; - - u16 bm_index = PORT_TO_CACHE(db->out2in_key.k.port, bulk_size); - - /*Check if we have already tested this bulk */ - for(i=0; i < attempts_so_far; i++) { - if(prev_bulks[i] == bm_index) { - goto next_entry; - } - } - - /*Check if this base port is already part of cache */ - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(CACHE_ENTRY_WITHOUT_FULL_STAT(udb->bulk_port_range_cache[i]) - == bm_index) - goto next_entry; - } - - /* this is not in chache already */ - bulk_start = CACHE_TO_PORT(bm_index, bulk_size); - port_pos = get_suiting_port_pos_from_range(my_pm, - bulk_start, bulk_size, pair_type); - - if(port_pos < 0) { /* no port available in this range */ - /* Mark this bulk so that we don't have to try this again */ - if(attempts_so_far < NUM_BULK_CHECK) { - prev_bulks[attempts_so_far] = bm_index; - attempts_so_far++; - } - goto next_entry; - } - - /* Got one...Get the port number */ - *port_available = bulk_start + port_pos; - - /* Check to see if we shoud replace one of the cache */ - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(PREDICT_FALSE((udb->bulk_port_range_cache[i] - == (i16)BULK_RANGE_INVALID) || ( - IS_CACHE_ENTRY_FULL(udb->bulk_port_range_cache[i])))) { - udb->bulk_port_range_cache[i] = bm_index; - return CNAT_SUCCESS; - } - } - /* Check to replace an existing (in use) entry */ - /* TODO: enforce policy */ - /* order of looping should depend on policy */ - - return CNAT_SUCCESS; - -next_entry: - db = cnat_main_db + db->user_ports.next; - /* - * its a circular list, so if we have reached the head again - * all the entries for that user have been read - */ - if (db == (cnat_main_db + head)) { - break; - } - } /* while loop for db entries */ - /* no ports available from pre allocated bulk pool */ - return CNAT_NO_PORT_FROM_BULK; -} - -cnat_errno_t -cnat_dynamic_port_alloc_v2_bulk ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port, - u16 static_port_range, - cnat_user_db_entry_t *udb, - bulk_alloc_size_t bulk_size, - int *nfv9_log_req, - u16 ip_n_to_1, - u32 *rseed_ip - ) -{ - - cnat_errno_t rv; - u16 port_available = 0; - i16 i; - cnat_portmap_v2_t *my_pm; - - if((BULK_ALLOC_SIZE_NONE != bulk_size) /* bulk logging enabled */ - && (udb)) { /* This user does have translations already */ - u16 bulk_start; - i16 port_pos; - - my_pm = pm + *index; - /* We have a case to check if bulk allocated ports can be used */ - /* TODO: order of looping to be based on policy - * like prefer older or prefer newer ?? - * For now, start with most recent cache entry - * so that we stand a better chance of - * finding a port - */ - for(i= 0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(PREDICT_TRUE((udb->bulk_port_range_cache[i] == - (i16)BULK_RANGE_INVALID) || - IS_CACHE_ENTRY_FULL(udb->bulk_port_range_cache[i]))) { - continue; /* This range is not initialized yet or it is full */ - } - bulk_start = CACHE_TO_PORT(udb->bulk_port_range_cache[i], - bulk_size); - port_pos = get_suiting_port_pos_from_range(my_pm, - bulk_start, bulk_size, pair_type); - if(PREDICT_FALSE(port_pos < 0)) { - /* Mark this cache entry as full so that we do not - * waste time on this entry again */ - MARK_CACHE_ENTRY_AS_FULL(udb->bulk_port_range_cache[i]); -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT("Marked bulk cache entry %d as full for %x \n", - i, my_pm->ipv4_address); -#endif /* #ifdef DEBUG_BULK_PORT */ - continue; - } - /* Get the port number */ - port_available = bulk_start+ port_pos; -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT( - "Found port from cache : IP 0x%x, port %d %d iterations\n", - my_pm->ipv4_address, port_available, i) -#endif -#ifdef HAVE_BULK_PORT_STATS - bulk_cache_hit_count++; -#endif /* HAVE_BULK_PORT_STATS */ - break; - } /* end of for loop for cache check */ - /* If we have not found a port yet, check if we can have - * pre allocated bulk port from non-cache */ - if(PREDICT_FALSE(i == BULK_RANGE_CACHE_SIZE)) { - if( try_bulk_port_from_non_cache(udb, my_pm, pair_type, - bulk_size, &port_available, - static_port_range) != CNAT_SUCCESS ) { - goto ALLCOATE_NEW_BULK; - } -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT("Found port from non-cache : IP 0x%x, port %d\n", - my_pm->ipv4_address, port_available); -#endif - } - /* Assign the port, mark it as in use */ - cgn_clib_bitmap_clear_no_check(my_pm->bm, port_available); - (my_pm->inuse)++; - if(PREDICT_FALSE(pair_type == PORT_PAIR)) {/* Mark the next one too */ - cgn_clib_bitmap_clear_no_check(my_pm->bm, port_available + 1); - (my_pm->inuse)++; - } - *o_ipv4_address = my_pm->ipv4_address; - *o_port = port_available; - *nfv9_log_req = CACHE_ALLOC_NO_LOG_REQUIRED; -#ifdef HAVE_BULK_PORT_STATS - bulk_port_use_count++; -#endif /* HAVE_BULK_PORT_STATS */ - return (CNAT_SUCCESS); - } -ALLCOATE_NEW_BULK: -#ifdef DEBUG_BULK_PORT - if(BULK_ALLOC_SIZE_NONE != bulk_size) { - PLATFORM_DEBUG_PRINT( - "No port available from bulk cache, bulk size %d\n", bulk_size); - } -#endif - /* For whatever reason, we have not got a port yet */ - rv = cnat_dynamic_port_alloc_v2(pm, atype, pair_type, index, - o_ipv4_address, o_port, static_port_range, bulk_size, nfv9_log_req, - ip_n_to_1, rseed_ip); - if (PREDICT_FALSE(rv != CNAT_SUCCESS)) { - return rv; - } - /* Take care of caching */ - if(PREDICT_FALSE(udb != NULL)) { - /* Predict false because, we usually allocate for new users */ - cnat_update_bulk_range_cache(udb, *o_port, bulk_size); - } -#ifdef HAVE_BULK_PORT_STATS - bulk_port_alloc_count++; -#endif /* HAVE_BULK_PORT_STATS */ - return (CNAT_SUCCESS); -} - - -cnat_errno_t -cnat_static_port_alloc_v2_bulk ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u32 i_ipv4_address, - u16 i_port, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port, - u16 static_port_range, - cnat_user_db_entry_t *udb, - bulk_alloc_size_t bulk_size, - int *nfv9_log_req, - u16 ip_n_to_1 - ) -{ - - /*** - * Requirements - - * 1. If the port allocated is below dyn start, it should be individual - * port (not bulk) - * 2. If NOT, it should be bulk allocated - * 3. Try and keep the inside port same as outside port in both the - * cases (best effort) - - * Algorithm - * 1. Check if it is below stat port start or user is new or bulk is - * disabled. If yes, call existing function - * 2. If not, see if we can pick from bulk and yet try to keep the port - * same - difficult thing - check if the port is free - then check if the - * entire bulk is free - if not check if bulk is owned by the user already. - * If all of these fail, call existing function to allocate a new bulk - * 3. Update cache, etc return log requirements - *****/ - - cnat_errno_t rv; - i16 i; - u32 head; - cnat_portmap_v2_t *my_pm; - uword bit_test_result, start_bit; - cnat_main_db_entry_t *db = NULL; - - if((BULK_ALLOC_SIZE_NONE != bulk_size) /* bulk logging enabled */ - && (udb) && /* This user does have translations already */ - i_port >= static_port_range ) { /* It is outside stat port range*/ - - my_pm = pm + *index; - /* We have a case to check if bulk allocated ports can be used */ - - /* First check if the required port is available. */ - if(PREDICT_FALSE(clib_bitmap_get_no_check(my_pm->bm, i_port) == 0)) { - goto ALLOCATE_NEW_BULK_STATIC; - } - - /* Port is free.. check if the bulk is also free */ - start_bit= ((i_port/bulk_size) * bulk_size); - bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm, - start_bit, bulk_size); - if(PREDICT_TRUE(bit_test_result)) { /* bulk is available, grab it */ - goto ALLOCATE_NEW_BULK_STATIC; - } - - /* else, bulk is taken by someone. check if it is me */ - /* Check if we own the bulk by any chance */ - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(udb->bulk_port_range_cache[i] == start_bit) break; - } - if(i == BULK_RANGE_CACHE_SIZE) { /* no luck with cache */ - head = udb->translation_list_head_index; - if(PREDICT_FALSE(head == EMPTY)) - goto ALLOCATE_NEW_BULK_STATIC; - db = cnat_main_db + head; - i = 0; - while(1) { - if((db->out2in_key.k.port/bulk_size) * bulk_size == start_bit) { - i = 1; /* Just to indicate it is found */ - break; - } - db = cnat_main_db + db->user_ports.next; - /* - * its a circular list, so if we have reached the head again - * all the entries for that user have been read - */ - if (db == (cnat_main_db + head)) break; - } /* while loop for db entries */ - if(!i) { - goto ALLOCATE_NEW_BULK_STATIC; - } - } - /* Assign the port, mark it as in use */ - cgn_clib_bitmap_clear_no_check(my_pm->bm, i_port); - (my_pm->inuse)++; - *o_ipv4_address = my_pm->ipv4_address; - *o_port = i_port; - *nfv9_log_req = CACHE_ALLOC_NO_LOG_REQUIRED; -#ifdef HAVE_BULK_PORT_STATS - bulk_port_use_count++; -#endif /* HAVE_BULK_PORT_STATS */ - -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT("%s, %d, found stat port from bulk: %x, %d\n", - __func__, - __LINE__, *o_ipv4_address, *o_port); -#endif /* DEBUG_BULK_PORT */ - return (CNAT_SUCCESS); - } - -ALLOCATE_NEW_BULK_STATIC: -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT("%s No port available from bulk cache, bulk size %d\n", - __func__,bulk_size); -#endif - /* For whatever reason, we have not got a port yet */ - rv = cnat_static_port_alloc_v2(pm, atype, pair_type, i_ipv4_address, - i_port, index, o_ipv4_address, o_port, static_port_range, - bulk_size, nfv9_log_req,ip_n_to_1); - if (PREDICT_FALSE(rv != CNAT_SUCCESS)) { - return rv; - } - /* Take care of caching only if it was a bulk alloc */ - if(PREDICT_FALSE(udb && (BULK_ALLOC_NOT_ATTEMPTED != *nfv9_log_req))) { - cnat_update_bulk_range_cache(udb, *o_port, bulk_size); - } -#ifdef HAVE_BULK_PORT_STATS - bulk_port_alloc_count++; -#endif /* HAVE_BULK_PORT_STATS */ - return (CNAT_SUCCESS); - -} - -cnat_errno_t -cnat_mapped_static_port_alloc_v2_bulk ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - u32 *index, - u32 ipv4_address, - u16 port, - cnat_user_db_entry_t *udb, - bulk_alloc_size_t bulk_size, - int *nfv9_log_req, - u16 ip_n_to_1 - ) -{ - /* Requirements : - * 1. Check if bulk allocation is required. - * 2. Call cnat_mapped_static_port_alloc_v2 to allocate - * 3. Decide if alloc has to be cached - * 4. Update nfv9_log_req - */ - cnat_errno_t rv; - rv = cnat_mapped_static_port_alloc_v2 (pm, - atype, index, ipv4_address, port, nfv9_log_req, bulk_size, ip_n_to_1); - if (PREDICT_FALSE(rv != CNAT_SUCCESS)) { - return rv; - } - /* Take care of caching only if it was a bulk alloc */ - if(PREDICT_FALSE(udb && (BULK_ALLOC_NOT_ATTEMPTED != *nfv9_log_req))) { - int i; - port = port*bulk_size; - port = port/bulk_size; /* align it to bulk size boundary */ - for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(CACHE_ENTRY_WITHOUT_FULL_STAT(udb->bulk_port_range_cache[i]) - == PORT_TO_CACHE(port, bulk_size)) - break; - } - if( i == BULK_RANGE_CACHE_SIZE) { /* else, it is alredy in cache */ - cnat_update_bulk_range_cache(udb, port, bulk_size); - } - } -#ifdef HAVE_BULK_PORT_STATS - mapped_port_alloc_count++; -#endif /* HAVE_BULK_PORT_STATS */ - return (CNAT_SUCCESS); -} - - -cnat_errno_t -cnat_dynamic_port_alloc_rtsp_bulk ( - cnat_portmap_v2_t *pm, - port_alloc_t atype, - port_pair_t pair_type, - u16 i_port, - u32 *index, - u32 *o_ipv4_address, - u16 *o_port, - u16 static_port_range, - cnat_user_db_entry_t *udb, - bulk_alloc_size_t bulk_size, - int *nfv9_log_req, - u32 *rseed_ip) -{ - - /*** - * Algorithm - * 1. Compute the range of ports required based on the number of digits - * in the port request made by the client. - * 2. Check if bulk logging is enabled. If not, use the existing method. - * 3. Check if there are 2 adjacent ports available that meet the above - * criteria in any of the bulk allocations made already. - * 4. If yes, mark them in use and return. - * 5. If not allocate a new bulk and pick 2 ports in it - ***/ - - i16 i; - cnat_portmap_v2_t *my_pm = 0; - u32 start_port1, end_port1, start_port2, end_port2; - int range_loop; - u16 bulk_start; - i16 port_pos; - u16 port_available = 0; - - ASSERT(index); - ASSERT(o_ipv4_address); - ASSERT(o_port); - - /* - * Check if the port is 4 digit or 5 digit. I am assuming we are - * not getting 3 (or 2 or 1) digit ports, which we cannot anyway - * allocate same sized outside ports - as outside ports start from 1024 - * - * Static Port has its own reserved range. Ensure that the range is - * such that atleast few 4 digit ports are available for RTSP. If - * not it does not make sense to do special allocation for RTSP. - */ - if (PREDICT_TRUE(static_port_range < MIN_STATIC_PORT_RANGE_FOR_RTSP)) { - /* - * 4 digit port or less - */ - if (i_port <= 9999) { - start_port1 = static_port_range; - end_port1 = 9999; - - start_port2 = 10000; - end_port2 = PORTS_PER_ADDR - 1; - } else { /* 5 digit port */ - start_port1 = 10000; - end_port1 = PORTS_PER_ADDR - 1; - - start_port2 = static_port_range; - end_port2 = 9999; - } - } else { /* Static port range is too big */ - start_port1 = static_port_range; - end_port1 = PORTS_PER_ADDR - 1; - - /* - * PORTS_PER_ADDR is just a placeholder for - * INVALID_PORT, valid ports are b/w 1 and PORTS_PER_ADDR - */ - start_port2 = PORTS_PER_ADDR; - end_port2 = PORTS_PER_ADDR; - } - - - if(PREDICT_TRUE(udb != NULL)) { - my_pm = pm + *index; - } - - /* Now check if this user already owns a bulk range that is - * within start range 1 - */ - - u32 start_range = start_port1; - u32 end_range = end_port1; - for(range_loop = 0; range_loop < 2; range_loop++) { - if((BULK_ALLOC_SIZE_NONE == bulk_size) || (!udb)) { - goto ALLOCATE_NEW_RTSP_PORTS; - } - for(i= 0; i < BULK_RANGE_CACHE_SIZE; i++) { - if(PREDICT_TRUE((udb->bulk_port_range_cache[i] == - (i16)BULK_RANGE_INVALID) || - IS_CACHE_ENTRY_FULL(udb->bulk_port_range_cache[i]))) { - continue; /* This range is not initialized yet or it is full */ - } - - bulk_start = CACHE_TO_PORT(udb->bulk_port_range_cache[i], - bulk_size); - if(bulk_start < start_port1 || bulk_start >= end_port1) { - continue; /* Not in the range */ - } - - port_pos = get_suiting_port_pos_from_range(my_pm, - bulk_start, bulk_size, pair_type); - if(PREDICT_FALSE(port_pos < 0)) { - /* Not Marking this cache entry as full as it failed - * for pair type. It might have individual entries - */ - continue; - } - /* Get the port number */ - port_available = bulk_start+ port_pos; -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT( - "Found port from cache : IP 0x%x, port %d %d iterations\n", - my_pm->ipv4_address, port_available, i) -#endif -#ifdef HAVE_BULK_PORT_STATS - bulk_cache_hit_count += 2; -#endif /* HAVE_BULK_PORT_STATS */ - break; - } /* end of for loop for cache check */ - - if(PREDICT_FALSE(i == BULK_RANGE_CACHE_SIZE)) { - /* we have not found a port yet, but to do not want to try - * non-cache bulks.. because, it is a very low probability and - * do not want to tweak that code for this special case - * The impact of non checking the non-cache is, we give this - * user few extra ports .. which is OK - */ - goto ALLOCATE_NEW_RTSP_PORTS; - } -#ifdef DEBUG_BULK_PORT - PLATFORM_DEBUG_PRINT("RTSP: Found port from non-cache : IP 0x%x, port %d\n", - my_pm->ipv4_address, port_available); -#endif - - /* Assign the port, mark it as in use */ - cgn_clib_bitmap_clear_no_check(my_pm->bm, port_available); - (my_pm->inuse)++; - cgn_clib_bitmap_clear_no_check(my_pm->bm, port_available + 1); - (my_pm->inuse)++; - - *o_ipv4_address = my_pm->ipv4_address; - *o_port = port_available; - *nfv9_log_req = CACHE_ALLOC_NO_LOG_REQUIRED; -#ifdef HAVE_BULK_PORT_STATS - bulk_port_use_count += 2; -#endif /* HAVE_BULK_PORT_STATS */ - return (CNAT_SUCCESS); - -ALLOCATE_NEW_RTSP_PORTS: - /* No luck. Let's try allocating new bulk.. */ - if(PREDICT_TRUE(CNAT_SUCCESS == cnat_dynamic_port_alloc_rtsp - (pm, atype, pair_type, - start_range, end_range,index, o_ipv4_address, - o_port, bulk_size, nfv9_log_req,rseed_ip))) { - if(PREDICT_FALSE(udb && - (BULK_ALLOC_NOT_ATTEMPTED != *nfv9_log_req))) { - cnat_update_bulk_range_cache(udb, *o_port, bulk_size); - } -#ifdef HAVE_BULK_PORT_STATS - bulk_port_alloc_count++; -#endif /* HAVE_BULK_PORT_STATS */ - return CNAT_SUCCESS; - } - - /* Could not allocate in range 1.. so move to range 2. */ - start_range = start_port2; - end_range = end_port2; - - } - - return (CNAT_NOT_FOUND_DIRECT); /* if we are here, we could not get any ports */ - -} - -#else /* Dummy definitions */ -void show_bulk_port_stats() -{ - PLATFORM_DEBUG_PRINT("\nBulk logging feature not included\n"); -} - - void clear_bulk_port_stats() -{ - PLATFORM_DEBUG_PRINT("\nBulk logging feature not included\n"); -} -#endif /* NO_BULK_LOGGING */ |