summaryrefslogtreecommitdiffstats
path: root/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_inside_input_exception.c
blob: 9b5e280e571f3b51aa1506e7ab4c87922ce5e293 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/* 
 *---------------------------------------------------------------------------
 * cnat_ipv4_icmp_query_inside_input_exception.c - cnat_ipv4_icmp_query_inside_input_exception node pipeline stage functions
 *
 * Copyright (c) 2008-2014 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 "cnat_ipv4_icmp.h"

#define foreach_cnat_ipv4_icmp_q_inside_input_exc_error                  	\
_(CNAT_V4_ICMP_Q_I2O_E_T_PKT, "v4 icmp query i2o-e transmit")                         \
_(CNAT_V4_ICMP_Q_I2O_E_G_PKT, "v4 icmp query i2o-e gen icmp msg")                             \
_(CNAT_V4_ICMP_Q_I2O_E_D_PKT, "v4 icmp query i2o-e pkt drop")                  \
_(CNAT_V4_ICMP_Q_I2O_E_DC_PKT, "v4 icmp query i2o-e drop (no config)")                \
_(CNAT_V4_ICMP_Q_I2O_E_DR_PKT, "v4 icmp query i2o-e drop (not in run state)")         \
_(CNAT_V4_ICMP_Q_I2O_E_DD_PKT, "v4 icmp query i2o-e drop (no direct port)")         \
_(CNAT_V4_ICMP_Q_I2O_E_DA_PKT, "v4 icmp query i2o-e drop (no any port)")         \
_(CNAT_V4_ICMP_Q_I2O_E_DO_PKT, "v4 icmp query i2o-e drop (out of port limit)")         \
_(CNAT_V4_ICMP_Q_I2O_E_DS_PKT, "v4 icmp query i2o_e drop (out of session db)")

typedef enum {
#define _(sym,str) sym,
  foreach_cnat_ipv4_icmp_q_inside_input_exc_error
#undef _
  CNAT_IPV4_ICMP_Q_INSIDE_INPUT_EXCEPTIONS_N_ERROR,
} cnat_ipv4_icmp_q_inside_input_exc_error_t;


static char * cnat_ipv4_icmp_q_inside_input_exc_error_strings[] = {
#define _(sym,string) string,
  foreach_cnat_ipv4_icmp_q_inside_input_exc_error
#undef _
};

typedef struct {
  u32 cached_next_index;
  /* $$$$ add data here */

  /* convenience variables */
  vlib_main_t * vlib_main;
  vnet_main_t * vnet_main;
} cnat_ipv4_icmp_q_inside_input_exc_main_t;

typedef enum {
    CNAT_V4_ICMP_Q_E_I2O_T,
    //CNAT_V4_ICMP_Q_E_I2O_GEN,
    CNAT_V4_ICMP_Q_E_I2O_D, 
    CNAT_V4_ICMP_Q_E_I2O_NEXT,
} cnat_ipv4_icmp_q_inside_input_exc_next_t;

#define CNAT_V4_ICMP_Q_E_I2O_GEN CNAT_V4_ICMP_Q_E_I2O_T

cnat_ipv4_icmp_q_inside_input_exc_main_t cnat_ipv4_icmp_q_inside_input_exc_main;
vlib_node_registration_t cnat_ipv4_icmp_q_inside_input_exc_node;

#define NSTAGES 2

/*
 * Use the generic buffer metadata + first line of packet data prefetch
 * stage function from <api/pipeline.h>. This is usually a Good Idea.
 */
#define stage0 generic_stage0

static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
                              u32 bi)
{
    vlib_buffer_t *b0 = vlib_get_buffer (vm, bi);
    int disposition = CNAT_V4_ICMP_Q_E_I2O_T;
    int counter = CNAT_V4_ICMP_Q_I2O_E_T_PKT;

    ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0);
    u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
    icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len);
    vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_icmp_q_inside_input_exc_node.index);
    u32 node_counter_base_index = n->error_heap_index;
    vlib_error_main_t * em = &vm->error_main;

    cnat_key_t dest_info;
    cnat_gen_icmp_info info;
    cnat_db_key_bucket_t ki;
    cnat_main_db_entry_t *db = NULL;

    PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX],
                        ki.k.k.vrf, CNAT_ICMP)

    ki.k.k.ipv4  =
         clib_net_to_host_u32(ip->src_addr);
    ki.k.k.port = 
         clib_net_to_host_u16(icmp->identifier);

    dest_info.k.port = 0;
    dest_info.k.ipv4 = clib_net_to_host_u32(ip->dest_addr);
    PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX],
                            dest_info.k.vrf, CNAT_ICMP)

    db = cnat_get_main_db_entry_v2(&ki, PORT_SINGLE, PORT_TYPE_DYNAMIC,
                                &info, &dest_info);
    if (PREDICT_TRUE(db != 0)) {

        if (PREDICT_FALSE(icmp_debug_flag)) {
            printf("\nDUMPING ICMP PKT BEFORE\n");
            print_icmp_pkt(ip);
        }

        if (PLATFORM_HANDLE_TTL_DECREMENT) {
            /*
             * Decrement TTL and update IPv4 checksum
             */
            ipv4_decr_ttl_n_calc_csum(ip);
        }

        /*
         * step 6 do nat before fwd pkt
         */
        swap_ip_src_icmp_id(ip, icmp, db, db->in2out_key.k.vrf);

        if (PREDICT_FALSE(icmp_debug_flag)) {
            printf("\nDUMPING ICMP PKT AFTER\n");
            print_icmp_pkt(ip);
        }

        /*
         * update db for this pkt
         */
        CNAT_DB_UPDATE_IN2OUT_TIMER 
        in2out_forwarding_count++;

    } else {
        switch (info.error) {
        case (CNAT_NO_VRF_RUN):
            counter = CNAT_V4_ICMP_Q_I2O_E_DR_PKT;
            break;
        case (CNAT_OUT_LIMIT):
            counter = CNAT_V4_ICMP_Q_I2O_E_DO_PKT;
            break;
        case (CNAT_NO_PORT_ANY):
        case (CNAT_NO_POOL_ANY):
        case (CNAT_BAD_INUSE_ANY):
        case (CNAT_NOT_FOUND_ANY):
            counter = CNAT_V4_ICMP_Q_I2O_E_DA_PKT;
            break;
        case (CNAT_INV_PORT_DIRECT):
        case (CNAT_DEL_PORT_DIRECT):
        case (CNAT_BAD_INUSE_DIRECT):
        case (CNAT_NOT_FOUND_DIRECT):
            counter = CNAT_V4_ICMP_Q_I2O_E_DD_PKT;
            break;
        case (CNAT_ERR_NO_SESSION_DB):
            counter = CNAT_V4_ICMP_Q_I2O_E_DS_PKT;
            break;
        default:
            counter = CNAT_V4_ICMP_Q_I2O_E_DC_PKT;
            break;
        }
        /*
         * send to icmp msg generate node
         */
        if (info.gen_icmp_msg == CNAT_ICMP_MSG) {
            #if 0
            u32 *fd = (u32*)ctx->feature_data;
            fd[0] = info.svi_addr;
            fd[1] = CNAT_ICMP_DEST_UNREACHABLE;
            #endif
            disposition = CNAT_V4_ICMP_Q_E_I2O_GEN;
            counter = CNAT_V4_ICMP_Q_I2O_E_G_PKT;
        } else {
            disposition = CNAT_V4_ICMP_Q_E_I2O_D;
            counter = CNAT_V4_ICMP_Q_I2O_E_D_PKT;
        }
        DEBUG_I2O_DROP(CNAT_DEBUG_DROP_ICMP)
    }
            
    em->counters[node_counter_base_index + counter] += 1;
    
    return disposition;
}

#include <vnet/pipeline.h>

static uword cnat_ipv4_icmp_q_inside_input_exc_node_fn (vlib_main_t * vm,
                              vlib_node_runtime_t * node,
                              vlib_frame_t * frame)
{
    return dispatch_pipeline (vm, node, frame);
}

VLIB_REGISTER_NODE (cnat_ipv4_icmp_q_inside_input_exc_node) = {
  .function = cnat_ipv4_icmp_q_inside_input_exc_node_fn,
  .name = "vcgn-v4-icmp-q-i2o-e",
  .vector_size = sizeof (u32),
  .type = VLIB_NODE_TYPE_INTERNAL,

  .n_errors = ARRAY_LEN(cnat_ipv4_icmp_q_inside_input_exc_error_strings),
  .error_strings = cnat_ipv4_icmp_q_inside_input_exc_error_strings,

  .n_next_nodes = CNAT_V4_ICMP_Q_E_I2O_NEXT,

  /* edit / add dispositions here */
  .next_nodes = {
        //[CNAT_V4_ICMP_Q_E_I2O_GEN] = "icmp_msg_gen", /* Currently it will go
        //to ip4-input node. We have to port icmp msg generator node */
        [CNAT_V4_ICMP_Q_E_I2O_T] = "ip4-input",
        [CNAT_V4_ICMP_Q_E_I2O_D] = "error-drop",
  },
};


clib_error_t *cnat_ipv4_icmp_q_inside_input_exc_init (vlib_main_t *vm)
{
  cnat_ipv4_icmp_q_inside_input_exc_main_t * mp = &cnat_ipv4_icmp_q_inside_input_exc_main;

  mp->vlib_main = vm;
  mp->vnet_main = vnet_get_main();

  return 0;
}

VLIB_INIT_FUNCTION (cnat_ipv4_icmp_q_inside_input_exc_init);
ic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
/* 
 *------------------------------------------------------------------
 * cnat_ports.c - port allocator
 *
 * Copyright (c) 2008-2014 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/vec.h>
#include <vppinfra/hash.h>
#include <vppinfra/pool.h>
#include <vppinfra/clib.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"

#if 1 /* TOBE_PORTED */
/* Following is defined elsewhere. */
#define msg_spp_err(s)                          \
do {                                            \
    fprintf(stderr,(i8 *)s);                    \
    fputs("\n", stderr);                        \
} while(0);
#endif


#define PM_90_PERCENT_USE 58980
/*
 * instance number provisioned from HW
 */
u8 my_instance_number = 0;

typedef struct {
  u32 cached_next_index;
  /* $$$$ add data here */

  /* convenience variables */
  vlib_main_t * vlib_main;
  vnet_main_t * vnet_main;
} cnat_ports_main_t;

cnat_ports_main_t cnat_ports_main;

static u32 rseed_port;          /* random number generator seed */

void
cnat_db_dump_portmap_for_vrf (u32 vrfmap_index)
{
    u32 i, pm_len;
    cnat_vrfmap_t *my_vrfmap = cnat_map_by_vrf + vrfmap_index;
    cnat_portmap_v2_t *pm, *my_pm __attribute__((unused));

    pm = my_vrfmap->portmap_list; 
    pm_len = vec_len(pm);

    for (i = 0; i < pm_len; i++) {
        my_pm = pm + i;

        PLATFORM_DEBUG_PRINT("pm %d: IPv4 Addr 0x%x - in use %d private_ip_users_count %d\n",
               i, my_pm->ipv4_address, my_pm->inuse, 
	       my_pm->private_ip_users_count);

	PLATFORM_DEBUG_PRINT("pm %d: IPv4 Addr 0x%x - in use %d "
			     "private_ip_users_count %d\n",
			     i, my_pm->ipv4_address, my_pm->inuse, 
			     my_pm->private_ip_users_count);
    }
}

void
cnat_db_dump_portmaps ()
{
    u32 i, vrfmap_index;

    for (i = 0; i < CNAT_MAX_VRFMAP_ENTRIES; i++) {
        vrfmap_index = vrf_map_array[i];

        if (vrfmap_index == VRF_MAP_ENTRY_EMPTY) {
            continue;
        }

        PLATFORM_DEBUG_PRINT("\n\nDumping the port map for uidb_index %d\n", i);
        cnat_db_dump_portmap_for_vrf(vrfmap_index);
    }
}

#ifndef NO_BULK_LOGGING
static int check_if_stat_alloc_ok_for_bulk(cnat_portmap_v2_t *pm,
            u16 i_port, bulk_alloc_size_t bulk_size,
            u16 static_port_range)
{
    uword bit_test_result;
    if(BULK_ALLOC_SIZE_NONE == bulk_size) return 1; /* No issues */

    if(i_port < static_port_range) return 1; /* we don't want bulk */

    i_port = (i_port/bulk_size) * bulk_size;
    bit_test_result = cgn_clib_bitmap_check_if_all(pm->bm, i_port, bulk_size);
    return(bit_test_result);
}
#else /* dummy */
inline static int check_if_stat_alloc_ok_for_bulk(cnat_portmap_v2_t *pm,
            u16 i_port, bulk_alloc_size_t bulk_size, 
            u16 static_port_range)
{   
    return 1;
}
#endif /* NO_BULK_LOGGING */
/*
 * cnat_port_alloc_static_v2
 * public ipv4 address/port allocator for Static Port commands
 * tries to allocate same outside port as inside port
 */
cnat_errno_t
cnat_static_port_alloc_v2 (
                 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
#ifndef NO_BULK_LOGGING
                 , bulk_alloc_size_t    bulk_size,
                 int *nfv9_log_req
#endif 
		 , u16                   ip_n_to_1
                 )
{
    u32 i, hash_value, my_index, found, max_attempts;
    u16 start_bit, new_port;
    cnat_portmap_v2_t *my_pm = 0;
    u32 pm_len = vec_len(pm);
    uword bit_test_result;

#ifndef NO_BULK_LOGGING
    *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
#endif 

    if (PREDICT_FALSE(pm_len == 0)) {
        return (CNAT_NO_POOL_ANY);
    }

    switch (atype) {

    case PORT_ALLOC_ANY:

        found = 0;

        /*
         * Try to hash the IPv4 address to get an index value to select the pm
         */
        hash_value = (i_ipv4_address & 0xffff) ^
	                ((i_ipv4_address > 16) & 0xffff);

        /*
         * If pm_len <= 256, compact the hash to 8 bits
         */
        if (PREDICT_TRUE(pm_len <= 256)) {
            hash_value = (hash_value & 0xff) ^ ((hash_value > 8) & 0xff);
        }

        /*
         * Ensure that the hash value is in the range 0 .. (pm_len-1)
         */
        my_index = hash_value % pm_len;

        for (i = 0; i < PORT_PROBE_LIMIT; i++) {
            my_pm = pm + my_index;
	    if(PREDICT_TRUE(ip_n_to_1)) {
		if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1)) {
		    /*
		     * Try to find a PM with atlest 33% free and my_port free
		     */
		    if (PREDICT_TRUE((my_pm->inuse < ((BITS_PER_INST*2)/3)) &&
				     clib_bitmap_get_no_check(my_pm->bm, 
							      i_port) == 1) 
#ifndef NO_BULK_LOGGING
			&& check_if_stat_alloc_ok_for_bulk(my_pm, i_port,
							   bulk_size, 
							   static_port_range)
#endif 
			) {
			found = 1;
			break;
		    }
		}
		
	    } else {
		/*
		 * Try to find a PM with atlest 33% free and my_port free
		 */
		if (PREDICT_TRUE((my_pm->inuse < ((BITS_PER_INST*2)/3)) &&
				 clib_bitmap_get_no_check(my_pm->bm, 
							  i_port) == 1) 
#ifndef NO_BULK_LOGGING
		    && check_if_stat_alloc_ok_for_bulk(my_pm, i_port,
						       bulk_size, 
						       static_port_range)
#endif 
                    ) {
		    found = 1;
		    break;
		}
	    }
            my_index = (my_index + 1) % pm_len;
        }

        /*
         * If not found do it the hard way .
         * "hard" way, best-fit.
         */
        if (!found) {
            u32 min_inuse_any, min_inuse_myport;
            u32 min_index_any, min_index_myport;

            min_inuse_any = min_inuse_myport = PORTS_PER_ADDR + 1;
            min_index_any = min_index_myport = ~0;
            for (i = 0; i < pm_len; i++) {
                my_pm = pm + i;
		if(PREDICT_TRUE(ip_n_to_1)) {
		    if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1))                     {
			if (PREDICT_FALSE(my_pm->inuse < min_inuse_any)) {
			    min_inuse_any = my_pm->inuse;
			    min_index_any = my_pm - pm;
			}
			if (PREDICT_FALSE(my_pm->inuse < min_inuse_myport)) {
			    if (PREDICT_TRUE(clib_bitmap_get_no_check(
					     my_pm->bm,i_port) == 1) 
#ifndef NO_BULK_LOGGING
				&& check_if_stat_alloc_ok_for_bulk(my_pm, 
					    i_port,bulk_size,static_port_range)
#endif 
				) {
				min_inuse_myport = my_pm->inuse;
				min_index_myport = my_pm - pm;
			    }
			}
			
		    } 
		    
		} else {
		    if (PREDICT_FALSE(my_pm->inuse < min_inuse_any)) {
			min_inuse_any = my_pm->inuse;
			min_index_any = my_pm - pm;
		    }
		    if (PREDICT_FALSE(my_pm->inuse < min_inuse_myport)) {
			if (PREDICT_TRUE(clib_bitmap_get_no_check(
					 my_pm->bm, i_port) == 1) 
#ifndef NO_BULK_LOGGING
			    && check_if_stat_alloc_ok_for_bulk(my_pm, i_port,
						 bulk_size, static_port_range)
#endif 
			    ) {
			    min_inuse_myport = my_pm->inuse;
			    min_index_myport = my_pm - pm;
			}
		    }
		}
            }

            /*
             * Check if we have an exactly matching PM that has
             * myport free.  If so use it.  If no such PM is
             * available, use any PM
             */
            if (PREDICT_TRUE(min_inuse_myport < PORTS_PER_ADDR)) {
                my_pm = pm + min_index_myport;
                my_index = min_index_myport;
                found = 1;
            } else if (PREDICT_TRUE(min_inuse_any < PORTS_PER_ADDR)) {
                my_pm = pm + min_index_any;
                my_index = min_index_any;
                found = 1;
            }
        }

        if (!found) {
            return (CNAT_NO_PORT_ANY);
        }
        break;

    case PORT_ALLOC_DIRECTED:
        my_index = *index;
        if (PREDICT_FALSE(my_index > pm_len)) {
            return (CNAT_INV_PORT_DIRECT);
        }
        my_pm = pm + my_index;
        break;

    default:
        return (CNAT_ERR_PARSER);
    }

    /* Allocate a matching port if possible */
    start_bit = i_port;
    found = 0;
    max_attempts = BITS_PER_INST;
#ifndef NO_BULK_LOGGING
    if((BULK_ALLOC_SIZE_NONE != bulk_size) && 
        (i_port >= static_port_range)) {
        start_bit =  (start_bit/bulk_size) * bulk_size;
        max_attempts = BITS_PER_INST/bulk_size;
    }
#endif /* NO_BULK_LOGGING */

    for (i = 0; i < max_attempts; i++) {
#ifndef NO_BULK_LOGGING
        if((BULK_ALLOC_SIZE_NONE != bulk_size) &&
            (i_port >= static_port_range)) {
            bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm, 
                        start_bit, bulk_size);
        }
        else
#endif /* #ifndef NO_BULK_LOGGING */
        bit_test_result = clib_bitmap_get_no_check(my_pm->bm, start_bit);

        if (PREDICT_TRUE(bit_test_result)) {
#ifndef NO_BULK_LOGGING
        if((BULK_ALLOC_SIZE_NONE != bulk_size) && 
            (i_port >= static_port_range)) {
            *nfv9_log_req = start_bit;
            if(i==0) new_port = i_port; /* First go */
            else {
                new_port = bit2port(start_bit);
                if (pair_type == PORT_S_ODD &&  (new_port & 0x1) == 0)
                    new_port++;                    
            }
            found = 1;
            break;
        }
        else {
#endif  /* NO_BULK_LOGGING */
            new_port = bit2port(start_bit);
            if (pair_type == PORT_S_ODD) {
                if ((new_port & 0x1) == 1) {
                    found = 1;
                    break;
                }
            } else if (pair_type == PORT_S_EVEN) {
                if ((new_port & 0x1) == 0) {
                    found = 1;
                    break;
                }
            } else {
                found = 1;
                break;
            }
#ifndef NO_BULK_LOGGING
        }
#endif 
        }
#ifndef NO_BULK_LOGGING
        if((BULK_ALLOC_SIZE_NONE != bulk_size) &&
                (i_port >= static_port_range))
            start_bit = (start_bit + bulk_size) % BITS_PER_INST;
        else {
#endif /* NO_BULK_LOGGING */
            start_bit = (start_bit + 1) % BITS_PER_INST;
            if(PREDICT_FALSE(start_bit == 0)) {
                start_bit = 1; /* Port 0 is invalid, so start from 1 */
            }
#ifndef NO_BULK_LOGGING
        }
#endif 
    } /* End of for loop */

    if (!found) {
        /* Port allocation failure */
        if (atype == PORT_ALLOC_DIRECTED) {
            return (CNAT_NOT_FOUND_DIRECT);
        } else {
            return (CNAT_NOT_FOUND_ANY);
        }
    }

    /* Accounting */
    cgn_clib_bitmap_clear_no_check(my_pm->bm, new_port);
    (my_pm->inuse)++;

    *index = my_pm - pm;
    *o_ipv4_address = my_pm->ipv4_address;

    *o_port = new_port;

    return (CNAT_SUCCESS);
}

/*
 * Try to allocate a portmap structure based on atype field
 */
cnat_portmap_v2_t *
cnat_dynamic_addr_alloc_from_pm (
                 cnat_portmap_v2_t    *pm,
                 port_alloc_t          atype,
                 u32                  *index,
                 cnat_errno_t         *err,
                 u16                   ip_n_to_1,
                 u32                  *rseed_ip)
{
    u32 i, pm_len;
    int my_index;
    int min_inuse, min_index;

    cnat_portmap_v2_t *my_pm = 0;
    *err = CNAT_NO_POOL_ANY;

    pm_len = vec_len(pm);

    switch(atype) {
    case PORT_ALLOC_ANY:
        if (PREDICT_FALSE(pm_len == 0)) {
	    my_pm = 0;
            *err = CNAT_NO_POOL_ANY;
            goto done;
        }

        /* "Easy" way, first address with at least 200 free ports */
        for (i = 0; i < PORT_PROBE_LIMIT; i++) {
            *rseed_ip = randq1(*rseed_ip);
            my_index = (*rseed_ip) % pm_len;
            my_pm = pm + my_index;
            if (PREDICT_FALSE(ip_n_to_1)) {
		if(PREDICT_TRUE(ip_n_to_1 == 1)) {
		    if (PREDICT_FALSE(0 == my_pm->inuse)) {	
			goto done;		
		    }					    
		} else {
		    if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1))                     {
			if (PREDICT_FALSE(my_pm->inuse < ((BITS_PER_INST*2)/3)))                        {
			    goto done;
			}
		    } 
		}
            } else {
                if (PREDICT_FALSE(my_pm->inuse < ((BITS_PER_INST*2)/3))) {
                    goto done;
                }
            }
        }  

        /* "hard" way, best-fit. $$$$ Throttle complaint */
        min_inuse = PORTS_PER_ADDR + 1;
        min_index = ~0;
        for (i = 0; i < pm_len; i++) {
            my_pm = pm + i;
            if (PREDICT_FALSE(ip_n_to_1)) {
	       if(PREDICT_TRUE(ip_n_to_1 == 1)) {
		   if (PREDICT_FALSE(!my_pm->inuse)) {
		       min_inuse = my_pm->inuse;
		       min_index = my_pm - pm;
		   } 
	       } else {
		   if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1)) {
		       if (PREDICT_TRUE(my_pm->inuse < min_inuse)) {
			   min_inuse = my_pm->inuse;
			   min_index = my_pm - pm;
		       }

		   } 
	       }

            } else {
                if (PREDICT_TRUE(my_pm->inuse < min_inuse)) {
                    min_inuse = my_pm->inuse;
                    min_index = my_pm - pm;
                }
            }
        }

        if (PREDICT_TRUE(min_inuse < PORTS_PER_ADDR)) {
            my_pm = pm + min_index;
            my_index = min_index;
            goto done;
        }

        /* Completely out of ports */
#ifdef DEBUG_PRINTF_ENABLED
        PLATFORM_DEBUG_PRINT("%s out of ports\n", __FUNCTION__);
#endif

	my_pm = 0;
        *err = CNAT_NO_PORT_ANY;
        break;


    case PORT_ALLOC_DIRECTED:
        //ASSERT(*index < pm_len);
        if (PREDICT_FALSE(*index > pm_len)) {
	    my_pm = 0;
            *err = CNAT_INV_PORT_DIRECT;
            goto done;
        }
        my_pm = pm + *index;
        my_index = *index;
        break;

    default:
        msg_spp_err("bad allocation type in cnat_port_alloc");
        my_pm = 0;
        *err = CNAT_ERR_PARSER;
        break;
    }

 done:
    if (PREDICT_FALSE(my_pm == NULL)) {
        return (my_pm);
    }

    if (PREDICT_FALSE(my_pm->inuse >= BITS_PER_INST)) {
        my_pm = 0;
        if (atype == PORT_ALLOC_DIRECTED) {
            *err = CNAT_BAD_INUSE_DIRECT;
        } else {
            *err = CNAT_BAD_INUSE_ANY;
        }
    }

    return (my_pm);
}


/*
 * cnat_port_alloc_v2
 * public ipv4 address/port allocator for dynamic ports
 *
 * 200K users / 20M translations means vec_len(cnat_portmap) will be
 * around 300.
 *
 */
cnat_errno_t
cnat_dynamic_port_alloc_v2 (
                 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
#ifndef NO_BULK_LOGGING
                 , bulk_alloc_size_t    bulk_size,
                  int *nfv9_log_req
#endif
                 , u16                   ip_n_to_1,
                  u32                  *rseed_ip
                 )
{
    int i;
    cnat_errno_t       my_err = CNAT_NO_POOL_ANY;
    cnat_portmap_v2_t *my_pm = 0;
    u16 start_bit;
    u16 new_port;
    uword bit_test_result;
    uword max_trys_to_find_port;

    ASSERT(index);
    ASSERT(o_ipv4_address);
    ASSERT(o_port);

    my_pm = cnat_dynamic_addr_alloc_from_pm(pm, atype, index, &my_err, ip_n_to_1, 
            rseed_ip);

    if (PREDICT_FALSE(my_pm == NULL)) {
        return (my_err);
    }
    if(PREDICT_FALSE(my_pm->dyn_full == 1)) {
        if (atype == PORT_ALLOC_DIRECTED) {
            return (CNAT_NOT_FOUND_DIRECT);
        } else {
            return (CNAT_NOT_FOUND_ANY);
        }
    }

#if DEBUG > 1
    PLATFORM_DEBUG_PRINT("ALLOC_PORT_V2: My_Instance_Number %d: IP addr 0x%x, Inuse %d\n",
           my_instance_number, my_pm->ipv4_address, my_pm->inuse);
#endif

    rseed_port = randq1(rseed_port);

    /*
     * Exclude the static port range for allocating dynamic ports
     */
    start_bit = (rseed_port) % (BITS_PER_INST - static_port_range);
    start_bit = start_bit + static_port_range;

#ifndef NO_BULK_LOGGING
    *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
    if(BULK_ALLOC_SIZE_NONE != bulk_size)
    {
        /* We need the start port of the range to be alined on integer multiple
         * of bulk_size */
        max_trys_to_find_port = BITS_PER_INST/bulk_size;
        start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size;
    }
    else
#endif /* #ifndef NO_BULK_LOGGING */
    max_trys_to_find_port = BITS_PER_INST;

    /* Allocate a random port / port-pair */
    for (i = 0; i < max_trys_to_find_port;  i++) {

    /* start_bit is only a u16.. so it can rollover and become zero */
    if (PREDICT_FALSE( /* (start_bit >= BITS_PER_INST) || FIXME u16 cannot be >= 65536 */
                    (start_bit < static_port_range))) {
                    start_bit = static_port_range;
#ifndef NO_BULK_LOGGING
        if(BULK_ALLOC_SIZE_NONE != bulk_size) {
            start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size;
        }
#endif /* #ifndef NO_BULK_LOGGING */
    }
        /* Scan forward from random position */
#ifndef NO_BULK_LOGGING
        if(BULK_ALLOC_SIZE_NONE != bulk_size) {
            bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm,
            start_bit, bulk_size);
        }
        else
#endif /* #ifndef NO_BULK_LOGGING */
        bit_test_result = clib_bitmap_get_no_check(my_pm->bm, start_bit);
        
        if (PREDICT_TRUE(bit_test_result)) {
            new_port = bit2port(start_bit);
#ifndef NO_BULK_LOGGING
            if(BULK_ALLOC_SIZE_NONE != bulk_size)
                *nfv9_log_req = new_port;
#endif
            if ((pair_type == PORT_S_ODD) &&
                       (!(new_port & 0x1))) {
#ifndef NO_BULK_LOGGING
                if(BULK_ALLOC_SIZE_NONE != bulk_size) {
                    start_bit++; /* Just use the next one in the bulk range */
                    new_port++;
                    goto found2;
                }
#endif /* #ifndef NO_BULK_LOGGING */
                        goto notfound;
            } else if ((pair_type == PORT_S_EVEN) &&
                       (new_port & 0x1)) {
                        goto notfound;
            }

            /* OK we got one or two suitable ports */
            goto found2;
        }

    notfound:
#ifndef NO_BULK_LOGGING
    if(BULK_ALLOC_SIZE_NONE != bulk_size)
        start_bit += bulk_size;
    else
#endif /* #ifndef NO_BULK_LOGGING */
    start_bit++;

    } /* end of for loop */

    /* Completely out of ports */

    /* Port allocation failure */
    /* set dyn_full flag. This would be used to verify
     * for further dyn session before searching for port
     */
    if (atype == PORT_ALLOC_DIRECTED) {
        my_pm->dyn_full = 1;
        return (CNAT_NOT_FOUND_DIRECT);
    } else {
        my_pm->dyn_full = 1;
        return (CNAT_NOT_FOUND_ANY);
    }
  

 found2:

    /* Accounting */
    cgn_clib_bitmap_clear_no_check (my_pm->bm, start_bit);
    (my_pm->inuse)++;

    *index = my_pm - pm;
    *o_ipv4_address = my_pm->ipv4_address;

    *o_port = new_port;
    return (CNAT_SUCCESS);
}

#ifdef TOBE_PORTED
/*
 * cnat_alloc_port_from_pm
 * Given a portmap structure find port/port_pair that are free
 *
 * The assumption in this function is that bit in bm corresponds
 * to a port number.   This is TRUE and hence there is no call
 * to the function bit2port here, though it is done in other 
 * places in this file.
 *
 */
static u32
cnat_alloc_port_from_pm (
    u32 start_port,
    u32 end_port,
    cnat_portmap_v2_t *my_pm,
    port_pair_t       pair_type
#ifndef NO_BULK_LOGGING
    , bulk_alloc_size_t    bulk_size,
    int                  *nfv9_log_req
#endif /* #ifnded NO_BULK_ALLOCATION */
    )
{
    u32 i;
    u32 start_bit;
    u32 total_ports = end_port - start_port + 1;
    uword bit_test_result;
    uword max_trys_to_find_port;

    rseed_port = randq1(rseed_port);

    start_bit = rseed_port % total_ports;
    start_bit = start_bit + start_port;
#ifndef NO_BULK_LOGGING
    *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
    if(BULK_ALLOC_SIZE_NONE != bulk_size)
    {
        /* We need the start port of the range to be alined on integer multiple
         * of bulk_size */
        max_trys_to_find_port = total_ports/bulk_size;
        start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size;
    }
    else
#endif /* #ifndef NO_BULK_LOGGING */
    max_trys_to_find_port = total_ports;

    /* Allocate a random port / port-pair */
    for (i = 0; i < max_trys_to_find_port; i++) {
        /* start_bit is only a u16.. so it can rollover and become zero */
        if (PREDICT_FALSE((start_bit >= end_port) ||
                    (start_bit < start_port))) {
                    start_bit = start_port;
#ifndef NO_BULK_LOGGING
            if(BULK_ALLOC_SIZE_NONE != bulk_size) {
                start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size;
            }
#endif /* #ifndef NO_BULK_LOGGING */
        }

        /* Scan forward from random position */
#ifndef NO_BULK_LOGGING
        if(BULK_ALLOC_SIZE_NONE != bulk_size) {
            bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm,
            start_bit, bulk_size);
        }
        else
#endif /* #ifndef NO_BULK_LOGGING */
            bit_test_result = clib_bitmap_get_no_check(my_pm->bm, start_bit);
        
            if (PREDICT_TRUE(bit_test_result)) {
#ifndef NO_BULK_LOGGING
                if(BULK_ALLOC_SIZE_NONE != bulk_size) {
                    /* Got the entire bulk range */
                    *nfv9_log_req = bit2port(start_bit);
                    return start_bit;
                } else { 
#endif /* #ifndef NO_BULK_LOGGING */
		        /*
		         * For PORT_PAIR, first port has to be Even
		         * subsequent port <= end_port
		         * subsequent port should be unallocated
		         */
                if ((start_bit & 0x1) ||
                    ((start_bit + 1) > end_port) ||
		            (clib_bitmap_get_no_check(my_pm->bm,
		                    (start_bit + 1)) == 0)) {
                        goto notfound;
                }
                return (start_bit);
#ifndef NO_BULK_LOGGING
            }
#endif /* #ifndef NO_BULK_LOGGING */
        } /* if( free port found ) */

notfound:
#ifndef NO_BULK_LOGGING
        if(BULK_ALLOC_SIZE_NONE != bulk_size) {
            start_bit += bulk_size;
        } else
#endif /* #ifndef NO_BULK_LOGGING */
            start_bit++;

    }
    return (BITS_PER_INST);
}

/*
 * cnat_dynamic_port_alloc_rtsp
 * public ipv4 address/port allocator for dynamic ports
 *
 * 200K users / 20M translations means vec_len(cnat_portmap) will be
 * around 300.
 *
 */

cnat_errno_t
cnat_dynamic_port_alloc_rtsp (
                            cnat_portmap_v2_t *pm,
                            port_alloc_t       atype,
                            port_pair_t        pair_type,
                            u16                start_range,
                            u16                end_range,
                            u32               *index,
                            u32               *o_ipv4_address,
                            u16               *o_port
#ifndef NO_BULK_LOGGING
                            , bulk_alloc_size_t bulk_size,
                            int *nfv9_log_req
#endif
                            , u32               *rseed_ip
            )
{

    u32 current_timestamp;
    cnat_errno_t       my_err = CNAT_NO_POOL_ANY;
    cnat_portmap_v2_t *my_pm = 0;
    u32 alloc_bit;

    ASSERT(index);
    ASSERT(o_ipv4_address);
    ASSERT(o_port);

    my_pm = cnat_dynamic_addr_alloc_from_pm(pm, atype, index, &my_err, 0,rseed_ip);

    if (PREDICT_FALSE(my_pm == NULL)) {
        return (my_err);
    }

#if DEBUG > 1
    PLATFORM_DEBUG_PRINT("ALLOC_PORT_V2: My_Instance_Number %d: IP addr 0x%x, Inuse %d\n",
           my_instance_number, my_pm->ipv4_address, my_pm->inuse);
#endif

    alloc_bit = 
	cnat_alloc_port_from_pm(start_range, end_range, my_pm, pair_type
#ifndef NO_BULK_LOGGING
         , bulk_size, nfv9_log_req
#endif /* #ifndef NO_BULK_LOGGING */
        );

    if (alloc_bit < BITS_PER_INST) {
	if (pair_type == PORT_PAIR) {
	    /* Accounting */
	    cgn_clib_bitmap_clear_no_check (my_pm->bm, alloc_bit);
	    cgn_clib_bitmap_clear_no_check (my_pm->bm, alloc_bit+1);
	    (my_pm->inuse) += 2;
	} else {
	    /* Accounting */
	    cgn_clib_bitmap_clear_no_check (my_pm->bm, alloc_bit);
	    (my_pm->inuse)++;
	}

	*index = my_pm - pm;
	*o_ipv4_address = my_pm->ipv4_address;

	*o_port = bit2port(alloc_bit);;

	return (CNAT_SUCCESS);
    }

    /* Completely out of ports */
    current_timestamp = spp_trace_log_get_unix_time_in_seconds();
    if (PREDICT_FALSE((current_timestamp - my_pm->last_sent_timestamp) >
                1000)) {
        spp_printf(CNAT_NO_EXT_PORT_AVAILABLE, 0, NULL);
        my_pm->last_sent_timestamp = current_timestamp;
    }


    /* Port allocation failure */
    if (atype == PORT_ALLOC_DIRECTED) {
        return (CNAT_NOT_FOUND_DIRECT);
    } else {
        return (CNAT_NOT_FOUND_ANY);
    }
}
#else
cnat_errno_t
cnat_dynamic_port_alloc_rtsp (
                            cnat_portmap_v2_t *pm,
                            port_alloc_t       atype,
                            port_pair_t        pair_type,
                            u16                start_range,
                            u16                end_range,
                            u32               *index,
                            u32               *o_ipv4_address,
                            u16               *o_port
#ifndef NO_BULK_LOGGING
                            , bulk_alloc_size_t bulk_size,
                            int *nfv9_log_req
#endif
                            , u32               *rseed_ip
            )
{
    return (CNAT_NOT_FOUND_ANY);
}
#endif


/*
 * cnat_mapped_static_port_alloc_v2
 * /
 */
cnat_errno_t
cnat_mapped_static_port_alloc_v2 (
             cnat_portmap_v2_t    *pm, 
		     port_alloc_t         atype, 
		     u32                  *index,
		     u32                   ipv4_address,
		     u16                   port
#ifndef NO_BULK_LOGGING
            , int *nfv9_log_req,
            bulk_alloc_size_t bulk_size
#endif
	    , u16                   ip_n_to_1
                )
{
    int i;
    u32 pm_len;
    u16 bm_bit;
    cnat_portmap_v2_t *my_pm = 0;
    u32 my_index;

    ASSERT(index);

    /*
     * Map the port to the bit in the pm bitmap structure.
     * Note that we use ports from 1024..65535, so 
     * port number x corresponds to (x-1024) position in bitmap
     */
    bm_bit = port2bit(port);

    pm_len = vec_len(pm);

    switch(atype) {
    case PORT_ALLOC_ANY:
        if (PREDICT_FALSE(pm_len == 0)) {
            return (CNAT_NO_POOL_ANY);
        }

	    /*
	     * Find the pm that is allocated for this translated IP address
	     */
	    my_index = pm_len;

        for (i = 0; i < pm_len; i++) {
	        my_pm = pm + i;
	        if (PREDICT_FALSE(my_pm->ipv4_address == ipv4_address)) {
		        my_index = i;
		        break;
	        }
	    }

	    if ((PREDICT_FALSE(my_index >= pm_len)) || 
		((PREDICT_FALSE(ip_n_to_1)) && (PREDICT_TRUE(my_pm->private_ip_users_count >= ip_n_to_1)))) {
		return (CNAT_NO_POOL_ANY);
	    }

	    break;

    case PORT_ALLOC_DIRECTED:
        if (PREDICT_FALSE(*index > pm_len)) {
            return (CNAT_INV_PORT_DIRECT);
        }

        my_index = *index;
        my_pm = pm + my_index;
        if (PREDICT_FALSE(my_pm->ipv4_address != ipv4_address)) {
            if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) { 
                PLATFORM_DEBUG_PRINT("Delete all main db entry for that particular in ipv4 address\n");
            }
            return (CNAT_INV_PORT_DIRECT);
        }
        
        break;

    default:
        msg_spp_err("bad allocation type in cnat_port_alloc");
        return (CNAT_ERR_PARSER);
    }


    if (PREDICT_FALSE(my_pm == NULL)) {
	    return (CNAT_NO_POOL_ANY);
    }

    /*
     * Check if the port is already allocated to some other mapping
     */
    if (PREDICT_FALSE(clib_bitmap_get_no_check (my_pm->bm, bm_bit) == 0)) {
	    return (CNAT_NO_POOL_ANY);
    }

#if DEBUG > 1
    PLATFORM_DEBUG_PRINT("ALLOC_PORT_V2: My_Instance_Number %d: IP addr 0x%x, Inuse %d\n",
           my_instance_number, my_pm->ipv4_address, my_pm->inuse);
#endif

    /*
     * Indicate that the port is already allocated
     */
    cgn_clib_bitmap_clear_no_check (my_pm->bm, bm_bit);
    (my_pm->inuse)++;

    *index = my_index;

    return (CNAT_SUCCESS);
}

void cnat_port_free_v2 (
         cnat_portmap_v2_t *pm,
    	 int                index,
         port_pair_t        pair_type,
         u16                base_port,
         u16                static_port_range)
{
    cnat_portmap_v2_t *my_pm;
    uword bit;

    /* check for valid portmap */   
    if (PREDICT_FALSE(index > vec_len(pm))) {
        spp_printf(CNAT_INVALID_INDEX_TO_FREE_PORT, 0, 0);
        return;
    }

    my_pm = pm + index;
    bit = port2bit(base_port);

#if DEBUG > 0
    if(clib_bitmap_get_no_check(my_pm->bm, bit))
        ASSERT(clib_bitmap_get_no_check(my_pm->bm, bit) == 0); 
#endif

    cgn_clib_bitmap_set_no_check(my_pm->bm, bit);

    my_pm->inuse -= 1;
    if(base_port >= static_port_range) {
        /* Clear the full flag. we can have a new dynamic session now */
        my_pm->dyn_full = 0;
    }

    return;
}

void cnat_portmap_dump_v2 (cnat_portmap_v2_t *pm, u16 print_limit)
{
    int i;
    u32 inuse =0;

    ASSERT(pm);

    for (i = 0; i < BITS_PER_INST; i++) {
        if (PREDICT_FALSE(clib_bitmap_get_no_check (pm->bm, i) == 0)) {
            if (PREDICT_TRUE(inuse++ < print_limit))
                PLATFORM_DEBUG_PRINT(" %d", bit2port(i));
        }
    }
    if (PREDICT_FALSE(inuse >= print_limit)) {
        PLATFORM_DEBUG_PRINT("%d printed, print limit is %d\n",
                inuse, print_limit);
    }
    PLATFORM_DEBUG_PRINT("\n");
}


/*
 * cnat_ports_init
 */
clib_error_t *cnat_ports_init(vlib_main_t *vm)
{
    cnat_ports_main_t *mp = &cnat_ports_main;

    mp->vlib_main = vm;
    mp->vnet_main = vnet_get_main();

    /* suppress crypto-random port numbering */
#ifdef SOON
    if (spp_get_int_prop("no_crypto_random_ports") == 0)
        crypto_random32(&seed);
#endif

    return 0;
}

VLIB_INIT_FUNCTION(cnat_ports_init);