2b43849dca3baf2cd5e3cf2171774b674a874ba2
[vpp.git] / plugins / plugins / vcgn / cnat_db_v2.c
1 /* 
2  *------------------------------------------------------------------
3  * cnat_db_v2.c - translation database definitions
4  *
5  * Copyright (c) 2007-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:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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  *------------------------------------------------------------------
18  */
19 #include <vlib/vlib.h>
20 #include <vnet/vnet.h>
21 #include <vppinfra/vec.h>
22 #include <vppinfra/bitmap.h>
23 #include <vppinfra/hash.h>
24 #include <vppinfra/pool.h>
25 #include <vppinfra/clib.h>
26 #include <vppinfra/error.h>
27
28 #include "cnat_db.h"
29 #include "cnat_config.h"
30 #include "cnat_global.h"
31 #include "cnat_v4_functions.h"
32 #include "cnat_log_api.h"
33 #include "cnat_cli.h"
34 #include "spp_platform_trace_log.h"
35 #include "cnat_bulk_port.h"
36 #include "nat64_db.h"
37 #include "dslite_db.h"
38 #include "cnat_config_api.h"
39
40 #define HASH_TABLE_SIZE  8192 // hash table size
41 #define THROTTLE_TIME  180 // throttle time value for out of port msg/user
42
43 u8 cnat_db_init_done = 0;
44
45 typedef struct {
46   /* Locks for multi thread support */
47   CLIB_CACHE_LINE_ALIGN_MARK(cacheline0);
48   pthread_spinlock_t *main_db_lockp;
49   pthread_spinlock_t *user_db_lockp;
50   pthread_spinlock_t *session_db_lockp;
51
52   u32 cached_next_index;
53   /* $$$$ add data here */
54
55   /* convenience variables */
56   vlib_main_t * vlib_main;
57   vnet_main_t * vnet_main;
58 } cnat_db_v2_main_t;
59
60 cnat_db_v2_main_t cnat_db_v2_main;
61
62 #if 1
63 /* TOBE_PORTED : Remove the following once fixed */
64 #undef PREDICT_TRUE
65 #undef PREDICT_FALSE
66 #define PREDICT_TRUE(x) (x)
67 #define PREDICT_FALSE(x) (x)
68 #endif
69
70 #define foreach_cnat_db_v2_error \
71 _(DROP, "error-drop packets")
72
73 typedef enum {
74 #define _(sym,str) CNAT_DB_V2_##sym,
75   foreach_cnat_db_v2_error
76 #undef _
77   CNAT_DB_V2_N_ERROR,
78 } cnat_db_v2_error_t;
79
80 static char * cnat_db_v2_error_strings[] __attribute__((unused)) = {
81 #define _(sym,string) string,
82   foreach_cnat_db_v2_error
83 #undef _
84 };
85
86
87 void cnat_table_entry_fill_map(u32 start_addr, u32 end_addr,
88         cnat_portmap_v2_t **port_map_holder)
89 {
90     u32 this_start_addr, this_end_addr, this_addr, new;
91     u32 loop_count;
92     u32 pm_len, i;
93     cnat_portmap_v2_t *my_pm =0;
94     cnat_portmap_v2_t *pm = 0;
95     
96     my_instance_number = 0; 
97
98     this_start_addr = start_addr;
99     this_end_addr   = end_addr;    
100
101     /*
102      * How many new addresses are getting added ??
103      */
104      /* commenting this. Right now end - start will be for this vCGN instance */
105     //new = ((this_end_addr - this_start_addr) / MAX_CORES_PER_PARTITION) + 1;
106     new = (this_end_addr - this_start_addr) + 1;
107
108     pm = *port_map_holder;
109     pm_len = vec_len(pm);
110 #if DEBUG_NOT_COMMENTED
111     printf("this_start_addr = 0x%08X, this_end_addr = 0x%08X, Num Addr = %d\n",
112         this_start_addr, this_end_addr, new);
113     printf("pm_len = %d\n", pm_len);
114 #endif
115     /* Check whether the address pool add requested already exists */
116     my_pm = pm;
117     for(i = 0; i< pm_len; i++) {
118         if(my_pm->ipv4_address == this_start_addr) {
119             printf("address pool with addr 0x%08X exists\n", this_start_addr);
120             return;
121         }
122         my_pm++;
123     }
124
125     /*
126      * For now give a warning message only....
127      */
128 #if 0
129     if ((total_address_pool_allocated + new) >
130         CNAT_MAX_ADDR_POOL_SIZE_PER_CORE) {
131         printf("address pool size (%d) would cross permissible limit (%u) \n",
132             (total_address_pool_allocated + new),
133             CNAT_MAX_ADDR_POOL_SIZE_PER_CORE);
134     }
135 #endif
136
137     total_address_pool_allocated += new;
138     vec_add2(pm, my_pm, new);
139
140 #if DEBUG_NOT_COMMENTED
141     printf("total_address_pool_allocated changed from %d to %d (added %d)",
142         (total_address_pool_allocated - new),
143         total_address_pool_allocated, new);
144     printf("vec add is ok\n");
145 #endif
146
147     memset(my_pm, 0, new*sizeof(*my_pm));
148     this_addr = this_start_addr;
149     loop_count = 0; /* Sanity counter */
150
151     while (this_addr <= this_end_addr) {
152 #if DEBUG_NOT_COMMENTED
153         printf("loop %d: this addr = 0x%08X\n", loop_count+1, this_addr);
154 #endif
155         my_pm->ipv4_address = this_addr;
156         /*
157          * Set all bits to "1" indicating all ports are free
158          */
159         memset(my_pm->bm, 0xff,
160             (((BITS_PER_INST + BITS(uword)-1)/BITS(uword))*(sizeof(uword))));
161         //this_addr += MAX_CORES_PER_PARTITION;
162         this_addr += 1;
163         my_pm++;
164         loop_count++;
165     }
166     /*
167      * We should have loop_count same as the new value
168      */
169     if (loop_count != new) {
170         printf("Mismatch in loop_count (%d) != new (%d)\n",
171             loop_count, new);
172     }
173
174     *port_map_holder = pm;
175
176 #if DEBUG_NOT_COMMENTED
177     printf("revised pm len %d\n", vec_len(*port_map_holder));
178 #endif
179
180     return;
181 }
182
183  
184 void cnat_delete_session_db_entry (cnat_session_entry_t *ep, u8 log);
185 void handle_cnat_port_exceeded_logging(
186     cnat_user_db_entry_t *udb,
187     cnat_key_t   * key,
188     cnat_vrfmap_t *vrfmap);
189
190 cnat_global_counters_t cnat_global_counters;
191 u32  last_log_timestamp = 0;
192 u32  last_user_dyn_port_exc_timestamp = 0;
193 u32  last_user_stat_port_exc_timestamp = 0; 
194
195 index_slist_t *cnat_out2in_hash;
196 index_slist_t *cnat_in2out_hash;
197 index_slist_t *cnat_user_hash;
198 index_slist_t *cnat_timeout_hash;
199 index_slist_t *cnat_session_hash;
200
201 cnat_main_db_entry_t *cnat_main_db;
202 cnat_user_db_entry_t *cnat_user_db;
203 cnat_session_entry_t *cnat_session_db;
204 cnat_timeout_db_entry_t *cnat_timeout_db;
205
206 cgse_nat_db_entry_t   *cgse_nat_db;
207 cgse_nat_user_db_entry_t *cgse_user_db;
208 cgse_nat_session_db_entry_t *cgse_session_db;
209
210 nat44_dslite_common_stats_t nat44_dslite_common_stats[255]; /* 0 is for nat44 */
211 nat44_dslite_global_stats_t nat44_dslite_global_stats[2]; /* 0 for nat44 and 1 for dslite */
212 nat44_counters_stats_t      nat44_counters_stats[CNAT_MAX_VRFMAP_ENTRIES];
213 /*For displaying show cgn <cgn-name> inside-vrf <vrf-name> counters */
214
215 /*
216  * This is the pool of vrf map structures used by latest main-db functions
217  */
218 cnat_vrfmap_t *cnat_map_by_vrf;
219
220 /*
221  * Have a mapping table of vrf_id-->vrf_map_index
222  * This helps in easily getting the vrf_map structure during
223  * main-db create paths
224  */
225 u16 vrf_map_array[CNAT_MAX_VRFMAP_ENTRIES];
226 cnat_svi_params_entry svi_params_array[CNAT_MAX_VRFMAP_ENTRIES];
227 cnat_ingress_vrfid_name_entry vrfid_name_map[MAX_VRFID] = {{0}};
228 u64 in2out_drops_port_limit_exceeded;
229 u64 in2out_drops_system_limit_reached;
230 u64 in2out_drops_resource_depletion;
231 u64 no_translation_entry_drops;
232 u32 no_sessions;
233
234 #define CNAT_SET_ICMP_MSG_INFO \
235 if (PREDICT_TRUE((my_vrfmap->i_vrf < CNAT_MAX_VRFMAP_ENTRIES) &&             \
236     (svi_params_array[my_vrfmap->i_vrf].ipv4_addr))) {                       \
237     info->gen_icmp_msg = icmp_msg_gen_allowed();  \
238     info->svi_addr = svi_params_array[my_vrfmap->i_vrf].ipv4_addr;           \
239 }
240
241 #define CNAT_DEBUG_INSIDE_ERR(err) \
242 if (((protocol == CNAT_UDP) && \
243      (debug_i_flag & CNAT_DEBUG_ERR_UDP)) || \
244     ((protocol == CNAT_TCP) && \
245      (debug_i_flag & CNAT_DEBUG_ERR_TCP)) || \
246     ((protocol == CNAT_ICMP) && \
247      (debug_i_flag & CNAT_DEBUG_ERR_ICMP))) { \
248     cnat_db_debug_error(&u_ki, err); \
249 }
250
251 #define DSLITE_DEBUG_INSIDE_ERR(err) \
252 if (((protocol == CNAT_UDP) && \
253      (debug_i_flag & CNAT_DEBUG_ERR_UDP)) || \
254     ((protocol == CNAT_TCP) && \
255      (debug_i_flag & CNAT_DEBUG_ERR_TCP)) || \
256     ((protocol == CNAT_ICMP) && \
257      (debug_i_flag & CNAT_DEBUG_ERR_ICMP))) { \
258     dslite_db_debug_error(&u_ki, err); \
259 }
260
261 #define PORT_LIMIT_LOW_THRESHOLD_FOR_SYSLOG    7
262 /* If the max_limit is less than 10, no meaningful throttling can be 
263  * done.. so, log only once per user and never clear the flag 
264  * once the user exceeds limit
265  */
266 #define CHECK_CLEAR_PORT_LIMIT_EXCEED_FLAG(udb, max_limit) \
267     if(PREDICT_FALSE(udb->flags & CNAT_USER_DB_PORT_LIMIT_EXCEEDED)) { \
268         if(udb->ntranslations < \
269             ((max_limit/10)*PORT_LIMIT_LOW_THRESHOLD_FOR_SYSLOG) && \
270             max_limit >= 10) { \
271             udb->flags = udb->flags & (~CNAT_USER_DB_PORT_LIMIT_EXCEEDED); \
272         } \
273     } 
274
275 #ifdef TOBE_PORTED
276 /* Commented to remove unused variable warning */
277 static char *debug_db_error[] = {
278     "no error", /* CNAT_SUCCESS */
279     "no config", /*CNAT_NO_CONFIG*/
280     "not in run state", /*CNAT_NO_VRF_RUN*/
281     "no pool for any", /*CNAT_NO_POOL_ANY*/
282     "no port for any", /*CNAT_NO_PORT_ANY*/
283     "bad in use for any", /*CNAT_BAD_INUSE_ANY*/
284     "not found for any", /*CNAT_NOT_FOUND_ANY*/
285     "invalid index for direct", /*CNAT_INV_PORT_DIRECT*/
286     "deleted addr for direct", /*CNAT_DEL_PORT_DIRECT*/
287     "bad in use for direct",/*CNAT_BAD_INUSE_DIRECT*/
288     "not found for direct",/*CNAT_NOT_FOUND_DIRECT*/
289     "out of port limit", /*CNAT_OUT_LIMIT*/
290     "main db limit", /*CNAT_MAIN_DB_LIMIT*/
291     "user db limit", /*CNAT_USER_DB_LIMIT*/
292     "not static port", /*CNAT_NOT_STATIC_PORT*/
293     "bad static port request", /*CNAT_BAD_STATIC_PORT_REQ*/
294     "not this core", /*CNAT_NOT_THIS_CORE*/
295     "parser error", /*CNAT_ERR_PARSER*/
296     "invalid msg id", /*CNAT_ERR_INVALID_MSG_ID*/
297     "invalid msg size", /*CNAT_ERR_INVALID_MSG_SIZE*/
298     "invalid payload size", /*CNAT_ERR_INVALID_PAYLOAD_SIZE*/
299     "bad tcp udp port", /*CNAT_ERR_BAD_TCP_UDP_PORT*/
300     "bulk single failure", /*CNAT_ERR_BULK_SINGLE_FAILURE*/
301     "xlat id invalid", /*CNAT_ERR_XLAT_ID_INVALID*/
302     "xlat v6 prefix invalid", /*CNAT_ERR_XLAT_V6_PREFIX_INVALID*/
303     "xlat v4 prefix invalid", /*CNAT_ERR_XLAT_V4_PREFIX_INVALID*/
304     "xlat tcp mss invalid", /*CNAT_ERR_XLAT_TCP_MSS_INVALID*/
305     "6rd id invalid", /*CNAT_ERR_6RD_ID_INVALID*/
306     "6rd v4 tunnel src invalid", /*CNAT_ERR_6RD_V4_TUNNEL_SRC_INVALID*/
307     "6rd v6 prefix invalid", /*CNAT_ERR_6RD_V6_PREFIX_INVALID*/
308     "6rd v6 BR unicast invalid", /*CNAT_ERR_6RD_V6_BR_UNICAST_INVALID*/
309     "6rd v4 prefix masklen invalid", /*CNAT_ERR_6RD_V4_PREFIX_MASK_LEN_INVALID*/
310     "6rd v4 suffix masklen invalid", /*CNAT_ERR_6RD_V4_SUFFIX_MASK_LEN_INVALID*/
311     "6rd v4 combo masklen invalid", /*CNAT_ERR_6RD_V4_COMBO_MASK_LEN_INVALID*/
312     "6rd tunnel mtu invalid", /*CNAT_ERR_6RD_TUNNEL_MTU_INVALID*/
313     "6rd tunnel ttl invalid", /*CNAT_ERR_6RD_TUNNEL_TTL_INVALID*/
314     "6rd tunnel tos invalid", /*CNAT_ERR_6RD_TUNNEL_TOS_INVALID*/
315 };
316 #endif
317
318 f64 port_log_timestamps[HASH_TABLE_SIZE]; /* 32 KB array per core */
319
320 void port_exceeded_msg_log (u32 src_addr, u16 i_vrf)
321 {
322     u32 hash_value;
323     f64 current_timestamp;
324     vlib_main_t  *vlib_main;
325
326     vlib_main = vlib_get_main();
327     current_timestamp = vlib_time_now((vlib_main_t *) vlib_main);
328
329     hash_value = ((src_addr >> 16) ^ ((src_addr & 0xffff) ^ i_vrf)) % (1024*8); 
330
331     if (PREDICT_FALSE((current_timestamp - port_log_timestamps[hash_value]) > THROTTLE_TIME)) {
332         u32 arg[2] = {i_vrf, src_addr};
333         /* update timestamp */
334         port_log_timestamps[hash_value] = current_timestamp;
335         spp_printf(CNAT_USER_OUT_OF_PORTS, 2, arg);
336     }
337
338     return ;
339 }
340
341 static void log_port_alloc_error(cnat_errno_t error, cnat_key_t *k)
342 {
343     u32 error_code;
344     u32 arr[] = {k->k.vrf, k->k.ipv4, k->k.port};
345     switch (error)
346     {
347     case CNAT_NO_POOL_ANY:
348         error_code = CNAT_NO_POOL_FOR_ANY_ERROR;
349         break;
350     case CNAT_NO_PORT_ANY:
351         error_code = CNAT_NO_PORT_FOR_ANY_ERROR;
352         break;
353     case CNAT_ERR_PARSER:
354         error_code = CNAT_WRONG_PORT_ALLOC_TYPE;
355         break;
356     case CNAT_BAD_INUSE_ANY:
357         error_code = CNAT_BAD_INUSE_ANY_ERROR;
358         break;
359     case CNAT_BAD_INUSE_DIRECT:
360         error_code = CNAT_BAD_INUSE_DIRECT_ERROR;
361         break;
362     case CNAT_NOT_FOUND_ANY:
363         error_code = CNAT_NOT_FOUND_ANY_ERROR;
364         break;
365     case CNAT_NOT_FOUND_DIRECT:
366         error_code = CNAT_NOT_FOUND_DIRECT_ERROR;
367         break;
368     case CNAT_INV_PORT_DIRECT:
369         error_code = CNAT_INV_PORT_FOR_DIRECT_ERROR;
370         break;
371     default:
372         error_code = CNAT_NEW_PORT_ALLOC_ERROR; /* If this code is seen in the log,
373        it means, new error codes are to be added here */
374        break;
375     }
376     spp_printf(error_code, 3, arr);
377 }
378
379 void cnat_db_debug_error(cnat_db_key_bucket_t *u_ki, 
380                          cnat_errno_t  error)
381 {
382     if (PREDICT_FALSE((u_ki->k.k.vrf == debug_i_vrf) &&
383         ((u_ki->k.k.ipv4 >= debug_i_addr_start) &&
384          (u_ki->k.k.ipv4 <= debug_i_addr_end)))) { 
385 #ifdef DEBUG_PRINTF_ENABLED
386             PLATFORM_DEBUG_PRINT("failed to allocate port due to %s "
387            "for i-vrf 0x%x addr 0x%x port 0x%x\n",
388             debug_db_error[error], u_ki->k.k.vrf,
389                u_ki->k.k.ipv4, u_ki->k.k.port);
390 #endif
391         {
392             u32 arg[] = {u_ki->k.k.vrf, u_ki->k.k.ipv4,  u_ki->k.k.port};
393             spp_printf(error, 3, arg);
394         }
395     }
396 }
397
398 void dslite_db_debug_error(dslite_db_key_bucket_t *u_ki,
399                          cnat_errno_t  error)
400 {
401     if (PREDICT_FALSE((u_ki->dk.ipv4_key.k.vrf == debug_i_vrf) &&
402         ((u_ki->dk.ipv4_key.k.ipv4 >= debug_i_addr_start) &&
403          (u_ki->dk.ipv4_key.k.ipv4 <= debug_i_addr_end)))) {
404 #ifdef DEBUG_PRINTF_ENABLED
405             PLATFORM_DEBUG_PRINT("failed to allocate port due to %s "
406            "for i-vrf 0x%x addr 0x%x port 0x%x\n",
407             debug_db_error[error], u_ki->dk.ipv4_key.k.vrf,
408                u_ki->dk.ipv4_key.k.ipv4, u_ki->dk.ipv4_key.k.port);
409 #endif
410         {
411             u32 arg[] = {u_ki->dk.ipv4_key.k.vrf, u_ki->dk.ipv4_key.k.ipv4,  u_ki->dk.ipv4_key.k.port};
412             spp_printf(error, 3, arg);
413         }
414     }
415 }
416
417 void cnat_db_debug_i2o_drop(cnat_db_key_bucket_t *ki)
418 {
419     if (PREDICT_FALSE(((ki->k.k.vrf & CNAT_VRF_MASK) == debug_i_vrf) && 
420         ((ki->k.k.ipv4 >= debug_i_addr_start) &&
421         (ki->k.k.ipv4 <= debug_i_addr_end)))) {
422 #ifdef DEBUG_PRINTF_ENABLED
423         PLATFORM_DEBUG_PRINT("pakcet[i-vrf 0x%x addr 0x%x port 0x%x] dropped\n", 
424            ki->k.k.vrf, ki->k.k.ipv4, ki->k.k.port);
425 #endif
426         {
427             u32 arg[] = {ki->k.k.vrf, ki->k.k.ipv4, ki->k.k.port};
428             spp_printf(CNAT_PACKET_DROP_ERROR, 3, arg);
429         }
430     }
431 }
432
433 void cnat_db_in2out_hash_delete (cnat_main_db_entry_t *ep, cnat_user_db_entry_t *up)
434 {
435     u64 a, b, c;
436     u32 index, bucket;
437     cnat_main_db_entry_t *this, *prev;
438
439 #ifdef DSLITE_DEF
440     if (PREDICT_FALSE(ep->flags & CNAT_DB_DSLITE_FLAG)) {
441         dslite_key_t dk = { 
442                               {up->ipv6[0], up->ipv6[1], up->ipv6[2], up->ipv6[3]} ,
443                               {ep->in2out_key.k.ipv4, ep->in2out_key.k.port, ep->in2out_key.k.vrf}
444                           };
445         DSLITE_V6_GET_HASH((&dk),
446                      bucket,
447                      CNAT_MAIN_HASH_MASK);
448         DSLITE_PRINTF(1, "Delete1 DSL main hash bucket ..%u\n", bucket);
449     } else {
450         CNAT_V4_GET_HASH(ep->in2out_key.key64,
451                          bucket, CNAT_MAIN_HASH_MASK)
452         DSLITE_PRINTF(1, "Delete1 NAT44 main hash bucket ..%u\n", bucket);
453     }
454 #else
455     CNAT_V4_GET_HASH(ep->in2out_key.key64,
456                      bucket, CNAT_MAIN_HASH_MASK)
457 #endif
458     
459     index = cnat_in2out_hash[bucket].next;
460
461     ASSERT(index != EMPTY);
462
463     prev = 0;
464     do {
465         this = cnat_main_db + index;
466         if (PREDICT_TRUE(this == ep)) {
467             if (prev == 0) {
468                 cnat_in2out_hash[bucket].next = ep->in2out_hash.next;
469                 return;
470             } else {
471                 prev->in2out_hash.next = ep->in2out_hash.next;
472                 return;
473             }
474         }
475         prev = this;
476         index = this->in2out_hash.next;
477     } while (index != EMPTY);
478
479     ASSERT(0);
480 }
481
482 void cnat_db_out2in_hash_delete (cnat_main_db_entry_t *ep)
483 {
484     u64 a, b, c;
485     u32 index, bucket;
486     cnat_main_db_entry_t *this, *prev;
487
488     CNAT_V4_GET_HASH(ep->out2in_key.key64,
489                         bucket, CNAT_MAIN_HASH_MASK)
490
491     index = cnat_out2in_hash[bucket].next;
492
493     ASSERT(index != EMPTY);
494
495     prev = 0;
496     do {
497         this = cnat_main_db + index;
498         if (PREDICT_TRUE(this == ep)) {
499             if (prev == 0) {
500                 cnat_out2in_hash[bucket].next = ep->out2in_hash.next;
501                 return;
502             } else {
503                 prev->out2in_hash.next = ep->out2in_hash.next;
504                 return;
505             }
506         }
507         prev = this;
508         index = this->out2in_hash.next;
509     } while (index != EMPTY);
510
511     ASSERT(0);
512 }
513
514 cnat_main_db_entry_t*
515 cnat_main_db_lookup_entry(cnat_db_key_bucket_t *ki)
516 {
517     u64 a, b, c;
518     u32 index;
519     cnat_main_db_entry_t *db;
520
521     CNAT_V4_GET_HASH(ki->k.key64, 
522                      ki->bucket,
523                      CNAT_MAIN_HASH_MASK);
524  
525     index = cnat_in2out_hash[ki->bucket].next;
526     if (PREDICT_TRUE(index == EMPTY)) {
527         return (NULL);
528     }
529
530     do {
531         db = cnat_main_db + index;
532         if (PREDICT_TRUE(db->in2out_key.key64 == ki->k.key64)) {
533             return db;
534         }
535         index = db->in2out_hash.next;
536     } while (index != EMPTY);
537
538     return (NULL);
539 }
540
541 void cnat_user_db_delete (cnat_user_db_entry_t *up)
542 {
543     u64 a, b, c;
544     u32 index, bucket;
545     cnat_user_db_entry_t *this, *prev;
546     
547     if (PREDICT_FALSE(up->flags & CNAT_USER_DB_NAT64_FLAG) != 0) {
548        /* Preventive check - Not a NAT44 entry */
549         return;
550     }
551
552     pthread_spin_lock(cnat_db_v2_main.user_db_lockp);
553 #if 1
554     if(PREDICT_FALSE(up->flags & CNAT_USER_DB_DSLITE_FLAG)) {
555         dslite_key_t dk = {
556                               {up->ipv6[0], up->ipv6[1], up->ipv6[2], up->ipv6[3]} ,
557                               {{up->key.k.ipv4, up->key.k.port, up->key.k.vrf}}
558                           };
559
560         DSLITE_V6_GET_HASH((&dk),
561                      bucket,
562                      CNAT_USER_HASH_MASK); 
563         DSLITE_PRINTF(1, "Delete1 DSL user hash bucket ..%u\n", bucket);
564     } else {
565         CNAT_V4_GET_HASH(up->key.key64,
566                        bucket, CNAT_USER_HASH_MASK)
567         DSLITE_PRINTF(1, "Delete1 NAT44 user hash bucket ..%u\n", bucket);
568     }
569 #else
570     CNAT_V4_GET_HASH(up->key.key64,
571                      bucket, CNAT_USER_HASH_MASK)
572     DSLITE_PRINTF(1, "Delete2 NAT44 user hash bucket ..%u\n", bucket);
573 #endif
574
575     index = cnat_user_hash[bucket].next;
576
577     ASSERT(index != EMPTY);
578
579     prev = 0;
580     do {
581         this = cnat_user_db + index;
582         if (PREDICT_TRUE(this == up)) {
583             if (prev == 0) {
584                 cnat_user_hash[bucket].next = up->user_hash.next;
585                 goto found;
586             } else {
587                 prev->user_hash.next = up->user_hash.next;
588                 goto found;
589             }
590         }
591         prev = this;
592         index = this->user_hash.next;
593     } while (index != EMPTY);
594
595     ASSERT(0);
596
597  found:
598     pool_put(cnat_user_db, up);    
599     pthread_spin_unlock(cnat_db_v2_main.user_db_lockp);
600 }
601
602 cnat_user_db_entry_t*
603 cnat_user_db_lookup_entry(cnat_db_key_bucket_t *uki) 
604 {
605     u64 a, b, c;
606     u32 index;
607     cnat_user_db_entry_t *udb=NULL;
608
609     CNAT_V4_GET_HASH(uki->k.key64, 
610                      uki->bucket,
611                      CNAT_USER_HASH_MASK)
612
613     /* now: index in user vector */
614     index = cnat_user_hash[uki->bucket].next;
615     if (PREDICT_TRUE(index != EMPTY)) {
616         do {
617             udb = cnat_user_db + index;
618             if (PREDICT_FALSE(udb->key.key64 == uki->k.key64)) {
619                 return udb;
620             }
621             index = udb->user_hash.next;
622         } while (index != EMPTY);
623     }
624     return (NULL);
625 }
626
627 cnat_user_db_entry_t*
628 cnat_user_db_create_entry(cnat_db_key_bucket_t *uki,
629                           u32 portmap_index)
630 {
631     cnat_user_db_entry_t *udb = NULL;
632
633     pthread_spin_lock(cnat_db_v2_main.user_db_lockp);
634     pool_get(cnat_user_db, udb);
635     memset(udb, 0, sizeof(*udb));
636
637     udb->ntranslations = 1; 
638     udb->portmap_index = portmap_index;
639     udb->key.key64 = uki->k.key64;
640     /* Add this user to the head of the bucket chain */
641     udb->user_hash.next = 
642              cnat_user_hash[uki->bucket].next;
643     cnat_user_hash[uki->bucket].next = udb - cnat_user_db;
644
645 #ifndef NO_BULK_LOGGING
646     INIT_BULK_CACHE(udb)
647 #endif /* NO_BULK_LOGGING */
648     pthread_spin_unlock(cnat_db_v2_main.user_db_lockp);
649     return udb;
650 }
651
652 cnat_main_db_entry_t*
653 cnat_create_main_db_entry_and_hash(cnat_db_key_bucket_t *ki,
654                                    cnat_db_key_bucket_t *ko,
655                                    cnat_user_db_entry_t *udb)
656 {
657     u64 a, b, c;
658     u32 db_index;
659     cnat_main_db_entry_t *db = NULL;
660
661     pool_get(cnat_main_db, db);
662     memset(db, 0, sizeof(*db));
663
664     db_index = db - cnat_main_db;
665     db->in2out_key.k.ipv4 = ki->k.k.ipv4;
666     db->in2out_key.k.port = ki->k.k.port;
667     db->in2out_key.k.vrf = ki->k.k.vrf;
668     db->out2in_key.k.ipv4 = ko->k.k.ipv4;
669     db->out2in_key.k.port = ko->k.k.port;
670     db->out2in_key.k.vrf = ko->k.k.vrf;
671
672     db->user_ports.next = db_index;
673     db->user_ports.prev = db_index;
674     db->user_index = udb - cnat_user_db;
675     //db->portmap_index = udb->portmap_index;
676     db->flags &= ~(CNAT_DB_DSLITE_FLAG); // Mark that it is not dslite
677     if (PREDICT_FALSE(udb->ntranslations == 1)) {
678         /*
679          * first port for this src vrf/src ip addr
680          */
681         udb->translation_list_head_index = db_index;
682     } else {
683         index_dlist_addtail(udb->translation_list_head_index,
684                             (u8 *)cnat_main_db, sizeof(cnat_main_db[0]),
685                             STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports),
686                             db_index);
687     }
688
689     /* 
690      * setup o2i hash key
691      */
692     CNAT_V4_GET_HASH(ko->k.key64, 
693                      ko->bucket,
694                      CNAT_MAIN_HASH_MASK)
695     db->out2in_hash.next = cnat_out2in_hash[ko->bucket].next;
696     cnat_out2in_hash[ko->bucket].next = db_index;
697     /*
698      * setup i2o hash key, bucket is already calculate
699      */
700     db->in2out_hash.next = cnat_in2out_hash[ki->bucket].next;
701     cnat_in2out_hash[ki->bucket].next = db_index;
702
703 #if DEBUG > 1
704     printf("\nMy_Instance_Number %d: Bucket %d, Db_Index %d",
705            my_instance_number, ki->bucket, db_index);
706     printf("\nInside (VRF 0x%x, IP 0x%x, PORT 0x%x)",
707            db->in2out_key.k.vrf, db->in2out_key.k.ipv4, db->in2out_key.k.port);
708     printf("\nOutside (VRF 0x%x, IP 0x%x, PORT 0x%x)",
709            db->out2in_key.k.vrf, db->out2in_key.k.ipv4, db->out2in_key.k.port);
710     printf("\nUser Index %d, IP 0x%x",
711            db->user_index, udb->key.k.ipv4);
712 #endif
713
714     NAT44_COMMON_STATS.active_translations++;
715
716     return db;
717 }
718
719 static inline void pptp_clear_all_channels(
720          cnat_main_db_entry_t *db)
721 {
722    u32 db_index, current_db_index;
723    cnat_main_db_entry_t *temp_db;
724
725    /* clear all channels */
726   
727    db_index = db->proto_data.pptp_list.next;
728    current_db_index  = db - cnat_main_db;
729
730    while( db_index != EMPTY) {
731        temp_db = cnat_main_db + db_index;
732        db_index = temp_db->proto_data.pptp_list.next;
733        temp_db->entry_expires = 0;
734        if(PREDICT_FALSE(temp_db->proto_data.pptp_list.prev 
735            == current_db_index)) { // Decouple child GREs from parent
736            temp_db->proto_data.pptp_list.prev = EMPTY; 
737        }
738    }
739
740    db->proto_data.pptp_list.next = EMPTY;
741 }
742
743 void pptp_remove_channel_from_tunnel(cnat_main_db_entry_t *db) {
744    
745     cnat_main_db_entry_t *prev_db, *next_db;
746     
747     prev_db = cnat_main_db + db->proto_data.pptp_list.prev;
748     next_db = cnat_main_db + db->proto_data.pptp_list.next;
749   
750     /* remove entry from the tunnel list */ 
751     if(PREDICT_TRUE(db->proto_data.pptp_list.prev != EMPTY)) {
752         prev_db->proto_data.pptp_list.next =
753                  db->proto_data.pptp_list.next ;  
754     }
755
756     if(db->proto_data.pptp_list.next != EMPTY) {
757        next_db->proto_data.pptp_list.prev
758                 = db->proto_data.pptp_list.prev;
759     }
760
761 }
762
763 void cnat_delete_main_db_entry_v2 (cnat_main_db_entry_t *ep)
764 {
765     u32 main_db_index;
766     u32 vrfmap_len, udb_len;
767     cnat_user_db_entry_t *up =0;
768     cnat_portmap_v2_t *pm =0;
769     cnat_portmap_v2_t *my_pm =0;
770     cnat_vrfmap_t       *my_vrfmap =0;
771     u16 static_port_range;
772 #ifndef NO_BULK_LOGGING
773     bulk_alloc_size_t bulk_size;
774     int nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
775 #endif
776     pool_header_t *h = pool_header(cnat_user_db);
777     u16 instance = 0;
778     u32                 my_index;
779
780
781     if (PREDICT_FALSE(ep->flags & CNAT_DB_NAT64_FLAG) != 0) {
782         /* Preventive check - Not a NAT44 entry */
783         return;
784     }
785
786    pthread_spin_lock(cnat_db_v2_main.main_db_lockp);
787    if(PREDICT_FALSE(ep->flags & 
788         CNAT_DB_FLAG_PPTP_TUNNEL_ACTIVE)) {
789       pptp_clear_all_channels(ep);
790       PPTP_DECR(active_tunnels);
791    }
792
793    if(PREDICT_FALSE(ep->flags &
794         CNAT_DB_FLAG_PPTP_GRE_ENTRY)) {
795         pptp_remove_channel_from_tunnel(ep);
796         PPTP_DECR(active_channels);
797    }
798
799     /* This function gets called from various locations..
800      * many times from config handler.. so we
801      * to ensure that multiple sessions if any are
802      * released
803      */
804
805     if(PREDICT_FALSE(ep->nsessions > 1)) {
806         cnat_session_entry_t *sdb;
807         while(ep->nsessions > 1 &&
808             ep->session_head_index != EMPTY) {
809             sdb = cnat_session_db + ep->session_head_index;
810             cnat_delete_session_db_entry(sdb, TRUE);
811         }
812     }
813
814     /* Find the set of portmaps for the outside vrf */
815     vrfmap_len = vec_len(cnat_map_by_vrf);
816     udb_len = vec_len(cnat_user_db);
817
818     /* In case of invalid user just return, deleting only main db
819      * is not a good idea, since some valid user db entry might be pointing 
820      * to that main db and hence leave the dbs in a inconsistent state
821      */
822     if (PREDICT_FALSE((ep->user_index >= udb_len) || 
823                     (clib_bitmap_get(h->free_bitmap, ep->user_index)))) {
824 #ifdef DEBUG_PRINTF_ENABLED
825         printf("invalid/unused user index in db %d\n", ep->user_index);
826 #endif
827         spp_printf(CNAT_INV_UNUSED_USR_INDEX, 1, (u32 *) &(ep->user_index));
828         cnat_main_db_entry_dump(ep);
829         goto unlock;
830     }
831
832     up = cnat_user_db + ep->user_index;
833
834 /* Point to the right portmap list */
835 if (PREDICT_FALSE(ep->flags & CNAT_DB_DSLITE_FLAG)) {
836     instance = ep->dslite_nat44_inst_id;
837     pm = dslite_table_db_ptr[instance].portmap_list;
838     if(PREDICT_FALSE((pm == NULL))) {
839         DSLITE_PRINTF(3, "NULL portmap list for dslite_id %u, state %u\n",
840                       instance,  dslite_table_db_ptr[instance].state);
841         cnat_main_db_entry_dump(ep);
842         goto delete_entry;
843     }
844     static_port_range = 
845     STAT_PORT_RANGE_FROM_INST_PTR(&(dslite_table_db_ptr[instance]));
846     /*
847      * Netflow logging API for delete event 
848      */
849     bulk_size = 
850         BULKSIZE_FROM_VRFMAP(&(dslite_table_db_ptr[instance]));
851 } else {
852     if (PREDICT_FALSE(ep->vrfmap_index >= vrfmap_len)) {
853 #ifdef DEBUG_PRINTF_ENABLED
854         printf("invalid vrfmap index in db\n");
855 #endif
856         spp_printf(CNAT_INVALID_VRFMAP_INDEX, 0, NULL);
857         cnat_main_db_entry_dump(ep);
858         goto delete_entry;
859     }
860     instance = NAT44_RESERVED_INST_ID;
861     my_vrfmap = cnat_map_by_vrf + ep->vrfmap_index;
862     pm = my_vrfmap->portmap_list;
863     static_port_range = cnat_static_port_range;
864     bulk_size = BULKSIZE_FROM_VRFMAP(my_vrfmap);
865 }
866  
867     if (PREDICT_FALSE(ep->flags & CNAT_DB_FLAG_PORT_PAIR)) {
868         /* Give back the port(s) */
869         cnat_port_free_v2_bulk(pm, up->portmap_index,
870             PORT_PAIR, ep->out2in_key.k.port, up, static_port_range
871 #ifndef NO_BULK_LOGGING
872             , bulk_size, &nfv9_log_req
873 #endif
874             );
875     } else {
876         /* Give back the port(s) */
877         cnat_port_free_v2_bulk (pm, up->portmap_index,
878             PORT_SINGLE, ep->out2in_key.k.port, up, static_port_range
879 #ifndef NO_BULK_LOGGING
880             , bulk_size, &nfv9_log_req
881 #endif
882             );
883     }
884
885     if (PREDICT_TRUE(!(ep->flags & CNAT_DB_DSLITE_FLAG))) {
886         if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) {
887             if(PREDICT_FALSE(my_vrfmap->nf_logging_policy == SESSION_LOG_ENABLE)) {
888                 if(ep->nsessions != 0) {
889                     cnat_nfv9_nat44_log_session_delete(ep, NULL, my_vrfmap);
890                 }
891             } else {
892                 cnat_nfv9_log_mapping_delete(ep, my_vrfmap
893 #ifndef NO_BULK_LOGGING
894                 , nfv9_log_req
895 #endif
896                 );
897             }
898             if(PREDICT_TRUE((my_vrfmap->syslog_logging_policy != SESSION_LOG_ENABLE) ||
899                             (ep->nsessions != 0))) {
900                 cnat_syslog_nat44_mapping_delete(ep, my_vrfmap, NULL
901 #ifndef NO_BULK_LOGGING
902                 , nfv9_log_req
903 #endif
904                 );
905             }
906         }
907     } else {
908         if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) {
909             if(PREDICT_FALSE( dslite_table_db_ptr[instance].nf_logging_policy ==
910                                       SESSION_LOG_ENABLE)) {
911                 cnat_nfv9_ds_lite_log_session_delete(ep, 
912                                 (dslite_table_db_ptr + instance),NULL);
913             } else {
914                 cnat_nfv9_ds_lite_mapping_delete(ep,
915                                 (dslite_table_db_ptr + instance)
916 #ifndef NO_BULK_LOGGING
917                 , nfv9_log_req
918 #endif
919                 );
920             }
921 #ifdef TOBE_PORTED
922             cnat_syslog_ds_lite_mapping_delete(ep,
923                                 (dslite_table_db_ptr + instance), NULL
924 #ifndef NO_BULK_LOGGING
925             , nfv9_log_req
926 #endif
927             );
928 #endif /* TOBE_PORTED */
929         }
930     }
931
932 delete_entry:
933
934     main_db_index = ep - cnat_main_db;
935
936     pthread_spin_lock(cnat_db_v2_main.user_db_lockp);
937     up->ntranslations--;
938     pthread_spin_unlock(cnat_db_v2_main.user_db_lockp);
939
940     /*
941      * when user reaches max allowed port limit
942      * we generate icmp msg and inc the counter
943      * when counter reach the icmp msg rate limit
944      * we stop icmp msg gen
945      * when a user port is freed
946      * that means we need to clear the msg gen counter
947      * so that next time 
948      * reach max port limit, we can generate new icmp msg again
949      */
950     up->icmp_msg_count = 0;
951
952     up->translation_list_head_index = index_dlist_remelem (
953         up->translation_list_head_index, (u8 *)cnat_main_db,
954         sizeof (cnat_main_db[0]),
955         STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports),
956         main_db_index);
957
958     cnat_db_in2out_hash_delete(ep, up);
959
960     if (PREDICT_FALSE(up->ntranslations == 0)) {
961         ASSERT(up->translation_list_head_index == EMPTY);
962         nat44_dslite_common_stats[instance].num_subscribers--;
963         my_index = up->portmap_index;
964         my_pm = pm + my_index;
965         if(PREDICT_TRUE(my_pm->private_ip_users_count)) {
966             my_pm->private_ip_users_count--;
967 #ifdef DEBUG_PRINTF_IP_N_TO_1_ENABLED
968             PLATFORM_DEBUG_PRINT("\n cnat_delete_main_db_entry_v2 "
969                                  "private_ip_users_count = %d",
970                                  my_pm->private_ip_users_count);
971 #endif
972             
973         }
974         cnat_user_db_delete(up);
975         
976     }
977
978     /* Remove from main DB hashes */
979     //cnat_db_in2out_hash_delete(ep);
980     cnat_db_out2in_hash_delete(ep);
981
982     pool_put(cnat_main_db, ep);
983
984     if(PREDICT_FALSE(ep->flags & CNAT_DB_FLAG_STATIC_PORT)) {
985             nat44_dslite_common_stats[instance].num_static_translations--;
986     } else {
987             nat44_dslite_common_stats[instance].num_dynamic_translations--;
988     }
989     nat44_dslite_common_stats[instance].active_translations--;
990     nat44_dslite_global_stats[!!(instance - 1)].translation_delete_count ++;
991 unlock:
992     pthread_spin_unlock(cnat_db_v2_main.main_db_lockp);
993 }
994
995 cnat_main_db_entry_t*
996 cnat_main_db_lookup_entry_out2in (cnat_db_key_bucket_t *ko)
997 {
998     u64 a, b, c;
999     u32 index;
1000     cnat_main_db_entry_t *db;
1001
1002     CNAT_V4_GET_HASH(ko->k.key64,
1003                      ko->bucket,
1004                      CNAT_MAIN_HASH_MASK);
1005
1006     index = cnat_out2in_hash[ko->bucket].next;
1007     if (PREDICT_TRUE(index == EMPTY)) {
1008         return (NULL);
1009     }
1010
1011     do {
1012         db = cnat_main_db + index;
1013         if (PREDICT_TRUE(db->out2in_key.key64 == ko->k.key64)) {
1014             return db;
1015         }
1016         index = db->out2in_hash.next;
1017     } while (index != EMPTY);
1018
1019     return (NULL);
1020 }
1021
1022 /* Creates 2 sessions.
1023  * Moves the default dest info from mdb to first session
1024  * Fills the dest_info details in to second session and
1025  * returns the pointer to second session
1026  */
1027 cnat_session_entry_t *cnat_handle_1to2_session(
1028     cnat_main_db_entry_t *mdb,
1029     cnat_key_t *dest_info)
1030 {
1031     cnat_key_t old_dest_info;
1032     pool_header_t        *h;
1033     u32 free_session = 0;
1034     u16 instance;
1035     cnat_session_entry_t *session_db1 = NULL, *session_db2 = NULL;
1036
1037     h = pool_header(cnat_session_db);
1038     free_session = vec_len(h->free_indices) - 1;
1039
1040     if (PREDICT_FALSE(free_session < 2)) {
1041        if (mdb->flags & CNAT_DB_DSLITE_FLAG) {
1042         instance = mdb->dslite_nat44_inst_id;
1043        } else {
1044         instance = NAT44_RESERVED_INST_ID;
1045        }
1046
1047         /* we need 2 sessions here, return NULL */
1048         nat44_dslite_common_stats[instance].drops_sessiondb_limit_exceeded++;
1049         return NULL;
1050     }
1051
1052     old_dest_info.k.ipv4 = mdb->dst_ipv4;
1053     old_dest_info.k.port = mdb->dst_port;
1054     old_dest_info.k.vrf = mdb->in2out_key.k.vrf;
1055
1056     /* create 2 new sessions */
1057     session_db1 = cnat_create_session_db_entry(&old_dest_info,
1058             mdb, FALSE);
1059
1060     if(PREDICT_FALSE(session_db1 == NULL)) {
1061         return NULL;
1062     }
1063
1064     /* update pkt info to session 2 */
1065     session_db2 = cnat_create_session_db_entry(dest_info,
1066             mdb, TRUE);
1067
1068     if(PREDICT_FALSE(session_db2 == NULL)) {
1069         cnat_delete_session_db_entry(session_db1, FALSE);
1070         return NULL;
1071     }
1072     /* update main db info to session 1 */
1073     cnat_dest_update_main2session(mdb, session_db1);
1074
1075     return session_db2;
1076 }
1077
1078 /* The below function shold be called only
1079  * when a NAT44 STATIC entry received traffic
1080  * for the first time. This is to ensure
1081  * the destination is noted and logged
1082  */
1083 void cnat_add_dest_n_log(
1084     cnat_main_db_entry_t *mdb,
1085     cnat_key_t *dest_info)
1086 {
1087
1088     if(PREDICT_FALSE(mdb->nsessions != 0)) {
1089         return; /* Should not have been called */
1090     }
1091
1092     mdb->dst_ipv4 = dest_info->k.ipv4;
1093     mdb->dst_port = dest_info->k.port;
1094     mdb->nsessions = 1;
1095     mdb->entry_expires = cnat_current_time;
1096     u16 instance;
1097
1098     if (mdb->flags & CNAT_DB_DSLITE_FLAG) {
1099         instance = mdb->dslite_nat44_inst_id;
1100         cnat_session_log_ds_lite_mapping_create(mdb,
1101              (dslite_table_db_ptr + instance),NULL);
1102     } else {
1103         instance = NAT44_RESERVED_INST_ID;
1104         cnat_vrfmap_t *my_vrfmap = cnat_map_by_vrf + mdb->vrfmap_index;
1105         cnat_session_log_nat44_mapping_create(mdb, 0, my_vrfmap);
1106     }
1107 }
1108
1109 /*
1110  * this function is called by exception node
1111  * when lookup is fialed in i2o node
1112  *
1113  * if reash per user port limit, 
1114  * set user_db_entry pointer, and error == CNAT_OUT_LIMIT
1115  */
1116 static cnat_main_db_entry_t*
1117 _cnat_get_main_db_entry_v2(cnat_db_key_bucket_t *ki,
1118                           port_pair_t port_pair_type,
1119                           port_type_t port_type,
1120                           cnat_gen_icmp_info *info,
1121                           cnat_key_t *dest_info)
1122 {
1123     u16 protocol;
1124     cnat_errno_t rv;
1125     cnat_db_key_bucket_t u_ki, ko;
1126     u32                 my_index, free_main, free_user;
1127     u32                 current_timestamp;
1128     u16                 my_vrfmap_index;
1129     u16                 my_vrfmap_entry_found = 0;
1130     cnat_vrfmap_t       *my_vrfmap =0;
1131     cnat_portmap_v2_t   *pm =0;
1132     cnat_user_db_entry_t *udb = 0;
1133     cnat_main_db_entry_t *db = 0;
1134     pool_header_t        *h;
1135     u16                 port_limit;
1136     cnat_portmap_v2_t *my_pm = 0;
1137
1138 #ifndef NO_BULK_LOGGING
1139     int                 nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
1140 #endif
1141
1142
1143     /* 
1144      * need to try lookup again because 
1145      * second pkt may come here before the entry is created
1146      * by receiving first pkt due to high line rate.
1147      */
1148     info->gen_icmp_msg = CNAT_NO_ICMP_MSG;
1149     info->error = CNAT_SUCCESS;
1150     db = cnat_main_db_lookup_entry(ki);
1151     if (PREDICT_TRUE(db)) {
1152         /* what if the source is talking to a
1153          * new dest now? We will have to handle this case and
1154          * take care of - creating session db and logging
1155          */
1156         if(PREDICT_FALSE((!dest_info->k.ipv4) && (!dest_info->k.port))) {
1157             return db;  /* if dest_info is null don't create session */
1158         }
1159         if(PREDICT_TRUE((db->dst_ipv4 == dest_info->k.ipv4) &&
1160             (db->dst_port == dest_info->k.port))) {
1161             return db;
1162         }
1163         dest_info->k.vrf = db->in2out_key.k.vrf;
1164         /* Src is indeed talking to a different dest */
1165         cnat_session_entry_t *session_db2 = NULL;
1166         if(PREDICT_TRUE(db->nsessions == 1)) {
1167             session_db2 = cnat_handle_1to2_session(db, dest_info);
1168             if(PREDICT_TRUE(session_db2 != NULL)) {
1169                 CNAT_DB_TIMEOUT_RST(session_db2);
1170                 return db;
1171             } else {
1172                 info->error = CNAT_ERR_NO_SESSION_DB;
1173                 return NULL;
1174             }
1175         } else if(PREDICT_FALSE(db->nsessions == 0)) {
1176             /* Should be static entry.. should never happen
1177              */
1178             if(PREDICT_TRUE(dest_info->k.ipv4 != 0)) {
1179                 cnat_add_dest_n_log(db, dest_info);
1180             }
1181             return db;
1182         } else {
1183             /* The src has already created multiple sessions.. very rare
1184              */
1185             session_db2 = cnat_create_session_db_entry(dest_info,
1186                         db, TRUE);
1187             if(PREDICT_TRUE(session_db2 != NULL)) {
1188                 CNAT_DB_TIMEOUT_RST(session_db2);
1189                return db;
1190             } else {
1191                 info->error = CNAT_ERR_NO_SESSION_DB;
1192                 return NULL;
1193             }
1194         }
1195
1196     }
1197
1198     /* 
1199      * step 1. check if outside vrf is configured or not
1200      *         and Find the set of portmaps for the outside vrf
1201      * insider vrf is one to one mappted to outside vrf
1202      * key is vrf and ip only
1203      * ki.k.k.vrf has protocol bits, mask out 
1204      */
1205     protocol = ki->k.k.vrf & CNAT_PRO_MASK;
1206     u_ki.k.k.vrf = ki->k.k.vrf & CNAT_VRF_MASK;
1207     u_ki.k.k.ipv4 = ki->k.k.ipv4;
1208     u_ki.k.k.port = 0;
1209
1210     my_vrfmap_index = vrf_map_array[u_ki.k.k.vrf];
1211     my_vrfmap = cnat_map_by_vrf + my_vrfmap_index;
1212
1213     my_vrfmap_entry_found = ((my_vrfmap_index != VRF_MAP_ENTRY_EMPTY) &&
1214                              (my_vrfmap->status == S_RUN) &&
1215                              (my_vrfmap->i_vrf == u_ki.k.k.vrf));
1216
1217     if (PREDICT_FALSE(!my_vrfmap_entry_found)) {
1218         u32 arr[] = {ki->k.k.vrf, ki->k.k.ipv4, ki->k.k.port};
1219         if ((my_vrfmap_index == VRF_MAP_ENTRY_EMPTY) || 
1220             (my_vrfmap->i_vrf == u_ki.k.k.vrf)) {
1221             info->error = CNAT_NO_CONFIG;
1222             CNAT_DEBUG_INSIDE_ERR(CNAT_NO_CONFIG)
1223         spp_printf(CNAT_NO_CONFIG_ERROR, 3, arr);
1224         } else {
1225             info->error = CNAT_NO_VRF_RUN;
1226             CNAT_DEBUG_INSIDE_ERR(CNAT_NO_VRF_RUN)
1227         spp_printf(CNAT_NO_VRF_RUN_ERROR, 3, arr);
1228         }
1229
1230         return (NULL);
1231     }
1232
1233     pm = my_vrfmap->portmap_list;
1234
1235     port_limit = my_vrfmap->port_limit;
1236     if(PREDICT_FALSE(!port_limit)) {
1237       port_limit = cnat_main_db_max_ports_per_user;
1238     }
1239     /*
1240      * set o2i key with protocl bits
1241      */
1242     ko.k.k.vrf = my_vrfmap->o_vrf | protocol;
1243
1244     /*
1245      * step 2. check if src vrf, src ip addr is alreay 
1246      *         in the user db
1247      * if yes, use PORT_ALLOC_DIRECTED
1248      * if no, use PORT_ALLOC_ANY since it is first time
1249      */
1250     udb = cnat_user_db_lookup_entry(&u_ki);
1251     if (PREDICT_TRUE(udb)) {
1252         /*
1253          * not first time allocate port for this user
1254          * check limit
1255          */
1256           if (PREDICT_FALSE(udb->ntranslations >=
1257                 port_limit)) { 
1258             /* Check for the port type here. If we are getting
1259              * a STATIC PORT, allow the config.
1260              */
1261             if (PREDICT_TRUE(port_type != PORT_TYPE_STATIC)) {
1262                info->error = CNAT_OUT_LIMIT;
1263                CNAT_SET_ICMP_MSG_INFO
1264                CNAT_DEBUG_INSIDE_ERR(CNAT_OUT_LIMIT)
1265                port_exceeded_msg_log(u_ki.k.k.ipv4, u_ki.k.k.vrf);
1266                in2out_drops_port_limit_exceeded ++;
1267                u_ki.k.k.port = ki->k.k.port;
1268                u_ki.k.k.vrf = ki->k.k.vrf;
1269                handle_cnat_port_exceeded_logging(udb, &u_ki.k, my_vrfmap);
1270                return (NULL);
1271             }
1272         }
1273         CHECK_CLEAR_PORT_LIMIT_EXCEED_FLAG(udb,
1274                 port_limit)
1275
1276         /* 
1277          * check if main db has space to accomodate new entry
1278          */
1279         h = pool_header(cnat_main_db);
1280
1281         free_main = vec_len(h->free_indices) - 1;
1282         if (PREDICT_FALSE(!free_main)) {
1283             info->error = CNAT_MAIN_DB_LIMIT;
1284             CNAT_SET_ICMP_MSG_INFO
1285             in2out_drops_system_limit_reached ++;
1286             CNAT_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT)
1287
1288             current_timestamp = spp_trace_log_get_unix_time_in_seconds();
1289             if (PREDICT_FALSE((current_timestamp - last_log_timestamp) >
1290                     1800)) {
1291                 spp_printf(CNAT_SESSION_THRESH_EXCEEDED, 0, NULL);
1292                 last_log_timestamp = current_timestamp;
1293             }
1294
1295 #ifdef UT_TEST_CODE
1296             printf("Limit reached : OLD USER");
1297 #endif
1298             return NULL;
1299         }
1300
1301         /*
1302          * allocate port, from existing mapping 
1303          */
1304         my_index = udb->portmap_index;
1305
1306         if (PREDICT_FALSE(port_type == PORT_TYPE_STATIC)) {
1307             rv = cnat_static_port_alloc_v2_bulk(pm,
1308                         PORT_ALLOC_DIRECTED,
1309                         port_pair_type,
1310                         ki->k.k.ipv4,
1311                         ki->k.k.port,
1312                         &my_index,
1313                         &(ko.k.k.ipv4),
1314                         &(ko.k.k.port),
1315                         cnat_static_port_range
1316 #ifndef NO_BULK_LOGGING
1317                         ,
1318                         udb, BULKSIZE_FROM_VRFMAP(my_vrfmap),
1319                         &nfv9_log_req
1320 #endif
1321                         , my_vrfmap->ip_n_to_1
1322                         );
1323
1324         }  else if (PREDICT_TRUE(port_type != PORT_TYPE_RTSP) ) {
1325
1326             rv = cnat_dynamic_port_alloc_v2_bulk(pm,
1327                         PORT_ALLOC_DIRECTED,
1328                         port_pair_type,
1329                         &my_index,
1330                         &(ko.k.k.ipv4),
1331                         &(ko.k.k.port),
1332                         cnat_static_port_range
1333 #ifndef NO_BULK_LOGGING
1334                         ,
1335                         udb, BULKSIZE_FROM_VRFMAP(my_vrfmap),
1336                         &nfv9_log_req
1337 #endif
1338                         , my_vrfmap->ip_n_to_1,
1339                         &(my_vrfmap->rseed_ip)
1340                         );
1341
1342         } else {
1343             /*
1344              * For RTSP, two translation entries are created, 
1345              * check if main db has space to accomodate two new entry
1346              */
1347             free_main =  free_main - 1;
1348             if (PREDICT_FALSE(!free_main)) {
1349                 info->error = CNAT_MAIN_DB_LIMIT;
1350                 CNAT_SET_ICMP_MSG_INFO
1351                 in2out_drops_system_limit_reached ++;
1352                 CNAT_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT)
1353
1354                 return NULL;
1355             } else {
1356                 rv = cnat_dynamic_port_alloc_rtsp_bulk(pm,
1357                             PORT_ALLOC_DIRECTED,
1358                             port_pair_type,
1359                             ki->k.k.port,
1360                             &my_index,
1361                             &(ko.k.k.ipv4),
1362                             &(ko.k.k.port),
1363                             cnat_static_port_range
1364 #ifndef NO_BULK_LOGGING
1365                             ,
1366                             udb, BULKSIZE_FROM_VRFMAP(my_vrfmap),
1367                             &nfv9_log_req
1368 #endif
1369                             , &(my_vrfmap->rseed_ip)
1370                             );
1371             }
1372         }
1373
1374
1375         if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
1376             info->error = rv;
1377             CNAT_SET_ICMP_MSG_INFO
1378             CNAT_DEBUG_INSIDE_ERR(rv)
1379             in2out_drops_resource_depletion++;
1380             log_port_alloc_error(rv, &(ki->k));
1381             return (NULL);
1382         }
1383         /*
1384          * increment port in use for this user
1385          */
1386         pthread_spin_lock(cnat_db_v2_main.user_db_lockp);
1387         udb->ntranslations += 1;
1388         pthread_spin_unlock(cnat_db_v2_main.user_db_lockp);
1389         
1390     } else {
1391         /*
1392          * first time allocate port for this user
1393          */
1394      
1395         /*
1396          * Do not create entry if port limit is invalid
1397          */
1398         
1399         if (PREDICT_FALSE(!port_limit)) {
1400             if (PREDICT_TRUE(port_type != PORT_TYPE_STATIC)) {
1401                 info->error = CNAT_OUT_LIMIT;
1402                 in2out_drops_port_limit_exceeded ++;
1403                 port_exceeded_msg_log(u_ki.k.k.ipv4, u_ki.k.k.vrf);
1404                 CNAT_SET_ICMP_MSG_INFO
1405                 CNAT_DEBUG_INSIDE_ERR(CNAT_OUT_LIMIT)
1406                 return (NULL);
1407             }
1408         }
1409
1410         /*
1411          * Check if main db has space for new entry
1412          * Allowing a user db entry to be created if main db is not free
1413          * will cause a port to be allocated to that user, which results in  
1414          * wastage of that port, hence the check is done here.
1415          */
1416         h = pool_header(cnat_main_db);
1417         free_main = vec_len(h->free_indices) - 1;
1418         h = pool_header(cnat_user_db);
1419             free_user = vec_len(h->free_indices) - 1;
1420
1421            /*
1422             * If either main_db or user_db does not have entries
1423             * bail out, with appropriate error
1424             */
1425         if (PREDICT_FALSE(!(free_main && free_user))) {
1426             u32 log_error;
1427             if(free_main) {
1428                 info->error = CNAT_USER_DB_LIMIT;
1429                 log_error = CNAT_USER_DB_LIMIT_ERROR;
1430             } else {
1431                    info->error = CNAT_MAIN_DB_LIMIT;
1432                    log_error = CNAT_MAIN_DB_LIMIT_ERROR;
1433             }
1434             in2out_drops_system_limit_reached ++;
1435             CNAT_SET_ICMP_MSG_INFO 
1436             CNAT_DEBUG_INSIDE_ERR(info->error)
1437             spp_printf(log_error, 0, 0);
1438             return NULL;
1439         }
1440
1441         if (PREDICT_FALSE(port_type == PORT_TYPE_STATIC)) {
1442             rv = cnat_static_port_alloc_v2_bulk(pm,
1443                         PORT_ALLOC_ANY,
1444                         port_pair_type,
1445                         ki->k.k.ipv4,
1446                         ki->k.k.port,
1447                         &my_index,
1448                         &(ko.k.k.ipv4),
1449                         &(ko.k.k.port),
1450                         cnat_static_port_range
1451 #ifndef NO_BULK_LOGGING
1452                         ,
1453                         udb, BULKSIZE_FROM_VRFMAP(my_vrfmap),
1454                         &nfv9_log_req
1455 #endif
1456                         , my_vrfmap->ip_n_to_1
1457                         );
1458
1459         }  else if (PREDICT_TRUE(port_type != PORT_TYPE_RTSP)) {
1460             rv = cnat_dynamic_port_alloc_v2_bulk(pm,
1461                         PORT_ALLOC_ANY,
1462                         port_pair_type,
1463                         &my_index,
1464                         &(ko.k.k.ipv4),
1465                         &(ko.k.k.port),
1466                         cnat_static_port_range
1467 #ifndef NO_BULK_LOGGING
1468                         , NULL, BULKSIZE_FROM_VRFMAP(my_vrfmap),
1469                         &nfv9_log_req
1470 #endif
1471                         , my_vrfmap->ip_n_to_1,
1472                         &(my_vrfmap->rseed_ip)
1473                         );
1474         } else {
1475             /*
1476              * For RTSP, two translation entries are created,
1477              * check if main db has space to accomodate two new entry
1478              */
1479             free_main =  free_main - 1;
1480             if (PREDICT_FALSE(!free_main)) {
1481                 info->error = CNAT_MAIN_DB_LIMIT;
1482                 CNAT_SET_ICMP_MSG_INFO
1483                 in2out_drops_system_limit_reached ++;
1484                 CNAT_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT)
1485
1486                 return NULL;
1487             } else {
1488
1489                 rv = cnat_dynamic_port_alloc_rtsp_bulk(pm,
1490                             PORT_ALLOC_ANY,
1491                             port_pair_type,
1492                             ki->k.k.port,
1493                             &my_index,
1494                             &(ko.k.k.ipv4),
1495                             &(ko.k.k.port),
1496                             cnat_static_port_range
1497 #ifndef NO_BULK_LOGGING
1498                             , NULL, BULKSIZE_FROM_VRFMAP(my_vrfmap),
1499                             &nfv9_log_req
1500 #endif
1501                             , &(my_vrfmap->rseed_ip)
1502                     );
1503                 /* TODO: Add the port pair flag here */
1504             }
1505         }
1506
1507
1508
1509         if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
1510             info->error = rv;
1511             in2out_drops_resource_depletion ++;
1512             CNAT_SET_ICMP_MSG_INFO
1513             CNAT_DEBUG_INSIDE_ERR(rv) 
1514             log_port_alloc_error(rv, &(ki->k));
1515             return (NULL);
1516         }
1517         /* 
1518          * create entry in user db
1519          */
1520         udb = cnat_user_db_create_entry(&u_ki, my_index);
1521         NAT44_COMMON_STATS.num_subscribers++;
1522         my_pm = pm + my_index;
1523         if(PREDICT_TRUE(my_pm->private_ip_users_count < PORTS_PER_ADDR)) {
1524             my_pm->private_ip_users_count++;
1525 #ifdef DEBUG_PRINTF_IP_N_TO_1_ENABLED
1526             PLATFORM_DEBUG_PRINT("\n cnat_get_main_db_entry_v2 "
1527                                  "dynamic alloc private_ip_users_count = %d",
1528                                  my_pm->private_ip_users_count);
1529 #endif
1530         } else {
1531             PLATFORM_DEBUG_PRINT("\n ERROR: private_ip_users_count has "
1532                                  "reached MAX PORTS_PER_ADDR");
1533         }
1534 #ifndef NO_BULK_LOGGING
1535         if(PREDICT_TRUE(udb && (BULK_ALLOC_NOT_ATTEMPTED != nfv9_log_req))) {
1536             cnat_update_bulk_range_cache(udb, ko.k.k.port,
1537                 BULKSIZE_FROM_VRFMAP(my_vrfmap));
1538         }
1539 #endif /*  #ifndef NO_BULK_LOGGING */
1540
1541     }
1542
1543     /*
1544      * step 3:
1545      * outside port is allocated for this src vrf/src ip addr
1546      * 1)create a new entry in main db
1547      * 2)setup cnat_out2in_hash key
1548      * 3)setup cnat_in2out_hash key
1549      */
1550     db = cnat_create_main_db_entry_and_hash(ki, &ko, udb);
1551
1552     translation_create_count ++;
1553 #ifdef DSLITE_DEF 
1554     db->dslite_nat44_inst_id = NAT44_RESERVED_INST_ID;
1555 #endif
1556     db->vrfmap_index = my_vrfmap - cnat_map_by_vrf;
1557
1558     /*
1559      * don't forget logging
1560      * logging API is unconditional, 
1561      * logging configuration check is done inside the inline function
1562      */
1563
1564     db->dst_ipv4 = dest_info->k.ipv4;
1565     db->dst_port = dest_info->k.port;
1566     if(PREDICT_TRUE(db->dst_ipv4 || db->dst_port)) {
1567         db->nsessions++;
1568     }
1569
1570     if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) {
1571         if(PREDICT_FALSE(my_vrfmap->nf_logging_policy == SESSION_LOG_ENABLE)) {
1572                 /* do not log for static entries.. we will log when traffic flows */
1573                 if(PREDICT_TRUE(db->dst_ipv4 || db->dst_port)) {
1574                         cnat_nfv9_nat44_log_session_create(db, 0, my_vrfmap);
1575                 }
1576         } else {
1577                 cnat_nfv9_log_mapping_create(db, my_vrfmap
1578 #ifndef NO_BULK_LOGGING
1579                 , nfv9_log_req
1580 #endif
1581                 );
1582         }
1583         if(PREDICT_TRUE((my_vrfmap->syslog_logging_policy != SESSION_LOG_ENABLE) ||
1584                         (db->dst_ipv4 || db->dst_port))) {
1585             cnat_syslog_nat44_mapping_create(db, my_vrfmap, 0
1586 #ifndef NO_BULK_LOGGING
1587             , nfv9_log_req
1588 #endif
1589             );
1590         }
1591     }
1592     if (PREDICT_FALSE(port_pair_type == PORT_PAIR)) {
1593        cnat_main_db_entry_t *db2 = 0;
1594        cnat_db_key_bucket_t new_ki = *ki;
1595        u64 a, b, c;
1596
1597        new_ki.k.k.port += 1;
1598        ko.k.k.port += 1;
1599
1600        CNAT_V4_GET_HASH(new_ki.k.key64, new_ki.bucket, 
1601                         CNAT_MAIN_HASH_MASK);
1602
1603        db2 = cnat_create_main_db_entry_and_hash(&new_ki, &ko, udb);
1604
1605        translation_create_count ++;
1606 #ifdef DSLITE_DEF 
1607        db2->dslite_nat44_inst_id = NAT44_RESERVED_INST_ID;
1608 #endif
1609        db2->vrfmap_index = my_vrfmap - cnat_map_by_vrf;
1610        db2->entry_expires = cnat_current_time;
1611        db2->flags |= CNAT_DB_FLAG_ALG_ENTRY;
1612        pthread_spin_lock(cnat_db_v2_main.user_db_lockp);
1613        udb->ntranslations += 1;
1614        pthread_spin_unlock(cnat_db_v2_main.user_db_lockp);
1615        db2->dst_ipv4 = dest_info->k.ipv4;
1616        db2->dst_port = dest_info->k.port;
1617        db2->nsessions = 0; /* For ALG db, set sessions to 0 - CSCuf78420 */
1618
1619        if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) {
1620            if(PREDICT_FALSE(my_vrfmap->nf_logging_policy == SESSION_LOG_ENABLE)) {
1621                /* do not log for static entries.. we will log when traffic flows */
1622                if(PREDICT_TRUE(db2->dst_ipv4 || db2->dst_port)) {
1623                    cnat_nfv9_nat44_log_session_create(db2, 0, my_vrfmap);
1624                }
1625            } else {
1626                cnat_nfv9_log_mapping_create(db2, my_vrfmap
1627 #ifndef NO_BULK_LOGGING
1628                , nfv9_log_req
1629 #endif
1630                );
1631            }
1632            if(PREDICT_TRUE((my_vrfmap->syslog_logging_policy != SESSION_LOG_ENABLE) ||
1633                            (db2->dst_ipv4 || db2->dst_port))) {
1634                cnat_syslog_nat44_mapping_create(db2, my_vrfmap, 0
1635 #ifndef NO_BULK_LOGGING
1636                , nfv9_log_req
1637 #endif
1638                );
1639            }
1640        }
1641     }
1642
1643     return db;
1644 }
1645
1646 cnat_main_db_entry_t*
1647 cnat_get_main_db_entry_v2(cnat_db_key_bucket_t *ki,
1648                           port_pair_t port_pair_type,
1649                           port_type_t port_type,
1650                           cnat_gen_icmp_info *info,
1651                           cnat_key_t *dest_info)
1652 {
1653
1654     cnat_main_db_entry_t *db;
1655     pthread_spin_lock(cnat_db_v2_main.main_db_lockp);
1656     db = _cnat_get_main_db_entry_v2(ki, port_pair_type,
1657         port_type, info, dest_info);
1658     pthread_spin_unlock(cnat_db_v2_main.main_db_lockp);
1659     return db;
1660 }
1661
1662 /*
1663  * this function is called from config handler only
1664  * to allocate a static port based db entry
1665  *
1666  * the actual mapped address and port are already specified
1667  */
1668 cnat_main_db_entry_t*
1669 cnat_create_static_main_db_entry_v2 (cnat_db_key_bucket_t *ki,
1670                                      cnat_db_key_bucket_t *ko,
1671                                      cnat_vrfmap_t        *my_vrfmap,
1672                                      cnat_gen_icmp_info   *info)
1673 {
1674     u16 protocol;
1675     u32 head;
1676     cnat_errno_t rv;
1677     cnat_db_key_bucket_t u_ki;
1678     u32                 my_index, free_main, free_user;
1679     cnat_portmap_v2_t   *pm =0;
1680     cnat_portmap_v2_t   *my_pm =0;
1681     cnat_user_db_entry_t *udb = 0;
1682     cnat_main_db_entry_t *db = 0;
1683     pool_header_t        *h;
1684 #ifndef NO_BULK_LOGGING
1685     int                 nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
1686 #endif
1687
1688     /* UNUSED. Therefore not ported to be multi-thread friendly */
1689     ASSERT(0);
1690
1691     /* 
1692      * need to try lookup again because 
1693      * second pkt may come here before the entry is created
1694      * by receiving first pkt due to high line rate.
1695      */
1696     info->gen_icmp_msg = CNAT_NO_ICMP_MSG;
1697     info->error = CNAT_SUCCESS;
1698     db = cnat_main_db_lookup_entry(ki);
1699
1700     /*
1701      * If we already have an entry with this inside address, port
1702      * check delete the entry and proceed further.  This should
1703      * If yes, something is terribly wrong.  Bail out
1704      */
1705     if (PREDICT_FALSE(db)) {
1706
1707         if (db->flags & CNAT_DB_FLAG_STATIC_PORT) {
1708
1709             if ((db->out2in_key.k.ipv4 == ko->k.k.ipv4) &&
1710                 (db->out2in_key.k.port == ko->k.k.port) &&
1711                 (db->out2in_key.k.vrf  == ko->k.k.vrf)) {
1712
1713 #ifdef DEBUG_PRINTF_ENABLED
1714                 printf("Same Static Port Exists ki 0x%16llx ko 0x%16llx",
1715                        ki->k, ko->k);
1716 #endif
1717                 /*
1718                  * We have already programmed this, return
1719                  */
1720                 return (db);
1721             }
1722
1723             /*
1724              * We already have a static port with different mapping
1725              * Return an error for this case.
1726              */
1727             info->error = CNAT_ERR_PARSER;
1728
1729 #ifdef DEBUG_PRINTF_ENABLED
1730             printf("Static Port Existing and Diff ki 0x%16llx ko 0x%16llx",
1731                        ki, db->out2in_key);
1732 #endif
1733         {
1734             u32 arr[] = {STAT_PORT_CONFIG_IN_USE, (ki->k.k.vrf & CNAT_VRF_MASK),
1735                 ki->k.k.ipv4, ki->k.k.port, (ki->k.k.vrf & CNAT_PRO_MASK) };
1736             spp_printf(CNAT_CONFIG_ERROR, 5, arr);
1737         }
1738             return (db);
1739         }
1740
1741 #ifdef DEBUG_PRINTF_ENABLED
1742         printf("Deleting Dynamic entry  ki 0x%16llx ko 0x%16llx",
1743                        ki, db->out2in_key);
1744 #endif
1745
1746         /*
1747          * If for some reason we have dynamic entries, just delete them
1748          * and proceed.
1749          */
1750         cnat_delete_main_db_entry_v2(db);
1751         
1752         db = NULL;
1753     }
1754
1755     protocol = ki->k.k.vrf & CNAT_PRO_MASK;
1756     u_ki.k.k.vrf = ki->k.k.vrf & CNAT_VRF_MASK;
1757     u_ki.k.k.ipv4 = ki->k.k.ipv4;
1758     u_ki.k.k.port = 0;
1759
1760     pm = my_vrfmap->portmap_list;
1761
1762     /*
1763      * check if src vrf, src ip addr is already 
1764      *         in the user db
1765      * if yes, use PORT_ALLOC_DIRECTED
1766      * if no, use PORT_ALLOC_ANY since it is first time
1767      */
1768     udb = cnat_user_db_lookup_entry(&u_ki);
1769     if (PREDICT_TRUE(udb)) {
1770         /* 
1771          * check if main db has space to accomodate new entry
1772          */
1773         h = pool_header(cnat_main_db);
1774
1775         free_main = vec_len(h->free_indices) - 1;
1776         if (PREDICT_FALSE(!free_main)) {
1777             info->error = CNAT_MAIN_DB_LIMIT;
1778             CNAT_SET_ICMP_MSG_INFO
1779             in2out_drops_system_limit_reached ++;
1780             CNAT_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT)
1781 #ifdef UT_TEST_CODE
1782             printf("Limit reached : OLD USER");
1783 #endif
1784             spp_printf(CNAT_MAIN_DB_LIMIT_ERROR, 0, 0);
1785             return NULL;
1786         }
1787
1788         /*
1789          * allocate port, from existing mapping 
1790          */
1791         my_index = udb->portmap_index;
1792         my_pm = pm + my_index;
1793        /* It is quite possible that we hit the scenario of CSCtj17774.
1794         * Delete all the main db entries and add the ipv4 address sent by
1795         * CGN-MA as Static port alloc any
1796         */
1797
1798         if (PREDICT_FALSE(my_pm->ipv4_address != ko->k.k.ipv4)) {
1799             if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) {
1800                 printf("Delete Main db entry and check for"
1801                         " ipv4 address sanity pm add = 0x%x ip add = 0x%x\n",
1802                         my_pm->ipv4_address,  ko->k.k.ipv4);
1803             }
1804             do {
1805                  /* udb is not NULL when we begin with for sure */
1806                  head = udb->translation_list_head_index;
1807                  db = cnat_main_db + head;
1808                  cnat_delete_main_db_entry_v2(db);
1809             } while (!pool_is_free(cnat_user_db, udb));
1810
1811             rv = cnat_mapped_static_port_alloc_v2_bulk (pm,
1812                  PORT_ALLOC_ANY, &my_index, ko->k.k.ipv4, ko->k.k.port,
1813                  udb, BULKSIZE_FROM_VRFMAP(my_vrfmap), &nfv9_log_req, 
1814                                                         my_vrfmap->ip_n_to_1);
1815
1816             if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
1817              info->error = rv;
1818              in2out_drops_resource_depletion ++;
1819              CNAT_SET_ICMP_MSG_INFO
1820              CNAT_DEBUG_INSIDE_ERR(rv)
1821              return (NULL);
1822             }
1823          /*
1824          * create entry in user db
1825          */
1826         udb = cnat_user_db_create_entry(&u_ki, my_index);
1827         my_pm = pm + my_index;
1828         if(PREDICT_TRUE(my_pm->private_ip_users_count < PORTS_PER_ADDR)) {
1829             my_pm->private_ip_users_count++;
1830 #ifdef DEBUG_PRINTF_IP_N_TO_1_ENABLED
1831             PLATFORM_DEBUG_PRINT("\n cnat_create_static_main_db_entry_v2 "
1832                                  "static del n alloc private_ip_users_count = "
1833                                  "%d",my_pm->private_ip_users_count);
1834 #endif
1835         } else {
1836             PLATFORM_DEBUG_PRINT("\n ERROR: private_ip_users_count has "
1837                                  "reached MAX PORTS_PER_ADDR");
1838         }
1839         NAT44_COMMON_STATS.num_subscribers++;
1840 #ifndef NO_BULK_LOGGING
1841         cnat_update_bulk_range_cache(udb, ko->k.k.port,
1842             BULKSIZE_FROM_VRFMAP(my_vrfmap));
1843 #endif /*  #ifndef NO_BULK_LOGGING */
1844       } else {
1845
1846         rv = cnat_mapped_static_port_alloc_v2_bulk (pm,
1847             PORT_ALLOC_DIRECTED, &my_index, ko->k.k.ipv4, ko->k.k.port,
1848             udb, BULKSIZE_FROM_VRFMAP(my_vrfmap), &nfv9_log_req, 
1849                                                     my_vrfmap->ip_n_to_1);
1850
1851         if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
1852             info->error = rv;
1853             CNAT_SET_ICMP_MSG_INFO
1854             CNAT_DEBUG_INSIDE_ERR(rv)
1855             log_port_alloc_error(rv, &(ki->k));
1856             return (NULL);
1857         }
1858
1859         /*
1860          * increment port in use for this user
1861          */
1862         udb->ntranslations += 1;
1863       }
1864     } else {
1865         if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) {
1866             printf ("Static port alloc any\n");
1867         }
1868         /*
1869          * first time allocate port for this user
1870          */
1871      
1872         /*
1873          * Check if main db has space for new entry
1874          * Allowing a user db entry to be created if main db is not free
1875          * will cause a port to be allocated to that user, which results in  
1876          * wastage of that port, hence the check is done here.
1877          */
1878         h = pool_header(cnat_main_db);
1879         free_main = vec_len(h->free_indices) - 1;
1880         h = pool_header(cnat_user_db);
1881             free_user = vec_len(h->free_indices) - 1;
1882
1883         /*
1884          * If either main_db or user_db does not have entries
1885          * bail out, with appropriate error
1886          */
1887         if (PREDICT_FALSE(!(free_main && free_user))) {
1888             u32 log_error;
1889             if(free_main) {
1890                 info->error = CNAT_USER_DB_LIMIT;
1891                 log_error = CNAT_USER_DB_LIMIT_ERROR;
1892             } else {
1893                 info->error = CNAT_MAIN_DB_LIMIT;
1894                 log_error = CNAT_MAIN_DB_LIMIT_ERROR;
1895             }
1896             in2out_drops_system_limit_reached ++;
1897             CNAT_SET_ICMP_MSG_INFO 
1898             CNAT_DEBUG_INSIDE_ERR(info->error)
1899             spp_printf(log_error, 0, 0);
1900             return NULL;
1901         }
1902
1903         rv = cnat_mapped_static_port_alloc_v2_bulk (pm,
1904             PORT_ALLOC_ANY, &my_index, ko->k.k.ipv4, ko->k.k.port,
1905             udb, BULKSIZE_FROM_VRFMAP(my_vrfmap), &nfv9_log_req, 
1906                                                     my_vrfmap->ip_n_to_1);
1907
1908         if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
1909             info->error = rv;
1910             in2out_drops_resource_depletion ++;
1911             CNAT_SET_ICMP_MSG_INFO
1912             CNAT_DEBUG_INSIDE_ERR(rv) 
1913             log_port_alloc_error(rv, &(ki->k));
1914             return (NULL);
1915         }
1916         /* 
1917          * create entry in user db
1918          */
1919         udb = cnat_user_db_create_entry(&u_ki, my_index);
1920         my_pm = pm + my_index;
1921         if(PREDICT_TRUE(my_pm->private_ip_users_count < PORTS_PER_ADDR)) {
1922             my_pm->private_ip_users_count++;
1923 #ifdef DEBUG_PRINTF_IP_N_TO_1_ENABLED
1924             PLATFORM_DEBUG_PRINT("\n cnat_create_static_main_db_entry_v2 "
1925                                  "static alloc private_ip_users_count = %d",
1926                                  my_pm->private_ip_users_count);
1927 #endif
1928         } else {
1929             PLATFORM_DEBUG_PRINT("\n ERROR: private_ip_users_count has "
1930                                  "reached MAX PORTS_PER_ADDR");
1931         }
1932         NAT44_COMMON_STATS.num_subscribers++;
1933 #ifndef NO_BULK_LOGGING
1934         cnat_update_bulk_range_cache(udb, ko->k.k.port,
1935             BULKSIZE_FROM_VRFMAP(my_vrfmap));
1936 #endif /*  #ifndef NO_BULK_LOGGING */
1937     }
1938
1939     /*
1940      * step 3:
1941      * outside port is allocated for this src vrf/src ip addr
1942      * 1)create a new entry in main db
1943      * 2)setup cnat_out2in_hash key
1944      * 3)setup cnat_in2out_hash key
1945      */
1946     db = cnat_create_main_db_entry_and_hash(ki, ko, udb);
1947
1948     translation_create_count ++;
1949     db->vrfmap_index = my_vrfmap - cnat_map_by_vrf;
1950
1951     /*
1952      * don't forget logging
1953      * logging API is unconditional, 
1954      * logging configuration check is done inside the inline function
1955      */
1956
1957         if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) {
1958         /* if session logging is enabled .. do not log  as there is no
1959          * traffic yet
1960          */
1961             if(PREDICT_FALSE(my_vrfmap->nf_logging_policy != SESSION_LOG_ENABLE)) {
1962                 cnat_nfv9_log_mapping_create(db, my_vrfmap
1963 #ifndef NO_BULK_LOGGING
1964                 , nfv9_log_req
1965 #endif
1966                 );
1967             }
1968             if(PREDICT_FALSE(my_vrfmap->syslog_logging_policy != SESSION_LOG_ENABLE)) {
1969                 cnat_syslog_nat44_mapping_create(db, my_vrfmap, 0
1970 #ifndef NO_BULK_LOGGING
1971                 , nfv9_log_req
1972 #endif
1973                 );
1974             }
1975         }
1976
1977     return db;
1978 }
1979
1980
1981 cnat_main_db_entry_t*
1982 dslite_main_db_lookup_entry(dslite_db_key_bucket_t *ki);
1983
1984 cnat_user_db_entry_t*
1985 dslite_user_db_lookup_entry(dslite_db_key_bucket_t *uki);
1986
1987 cnat_user_db_entry_t*
1988 dslite_user_db_create_entry(dslite_db_key_bucket_t *uki, u32 portmap_index);
1989
1990 cnat_main_db_entry_t*
1991 dslite_create_main_db_entry_and_hash(dslite_db_key_bucket_t *ki,
1992                                    cnat_db_key_bucket_t *ko,
1993                                    cnat_user_db_entry_t *udb);
1994
1995 #ifdef TOBE_PORTED
1996 /*
1997  * this function is called from config handler only
1998  * to allocate a static port based db entry
1999  *
2000  * the actual mapped address and port are already specified
2001  */
2002 cnat_main_db_entry_t*
2003 dslite_create_static_main_db_entry_v2 (dslite_db_key_bucket_t *ki,
2004                                      cnat_db_key_bucket_t *ko,
2005                                      dslite_table_entry_t *dslite_entry_ptr,
2006                                      cnat_gen_icmp_info   *info)
2007 {
2008     u16 protocol;
2009     u32 head;
2010     cnat_errno_t rv;
2011     dslite_db_key_bucket_t u_ki;
2012     u32                 my_index, free_main, free_user;
2013     cnat_portmap_v2_t   *pm =0;
2014     cnat_portmap_v2_t   *my_pm =0;
2015     cnat_user_db_entry_t *udb = 0;
2016     cnat_main_db_entry_t *db = 0;
2017     pool_header_t        *h;
2018     u16 dslite_id = dslite_entry_ptr->dslite_id;
2019 #ifndef NO_BULK_LOGGING
2020     int                 nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
2021 #endif
2022     cnat_vrfmap_t       *my_vrfmap =0;
2023     u16                 my_vrfmap_index;    
2024
2025     /* UNUSED. Therefore not ported to be multi-thread friendly */
2026     ASSERT(0);
2027     /* 
2028      * need to try lookup again because 
2029      * second pkt may come here before the entry is created
2030      * by receiving first pkt due to high line rate.
2031      */
2032     info->gen_icmp_msg = CNAT_NO_ICMP_MSG;
2033     info->error = CNAT_SUCCESS;
2034     db = dslite_main_db_lookup_entry(ki);
2035
2036     /*
2037      * If we already have an entry with this inside address, port
2038      * check delete the entry and proceed further.  This should
2039      * If yes, something is terribly wrong.  Bail out
2040      */
2041     if (PREDICT_FALSE(db)) {
2042
2043         if (db->flags & CNAT_DB_FLAG_STATIC_PORT) {
2044
2045             if ((db->out2in_key.k.ipv4 == ko->k.k.ipv4) &&
2046                 (db->out2in_key.k.port == ko->k.k.port) &&
2047                 (db->out2in_key.k.vrf  == ko->k.k.vrf)) {
2048
2049 #ifdef DEBUG_PRINTF_ENABLED
2050                 printf("Same Static Port Exists ki 0x%16llx ko 0x%16llx",
2051                        ki->k, ko->k);
2052 #endif
2053                 /*
2054                  * We have already programmed this, return
2055                  */
2056                 return (db);
2057             }
2058
2059             /*
2060              * We already have a static port with different mapping
2061              * Return an error for this case.
2062              */
2063             info->error = CNAT_ERR_PARSER;
2064
2065 #ifdef DEBUG_PRINTF_ENABLED
2066             printf("Static Port Existing and Diff ki 0x%16llx ko 0x%16llx",
2067                        ki, db->out2in_key);
2068 #endif
2069         {
2070             u32 arr[] = {STAT_PORT_CONFIG_IN_USE, (ki->dk.ipv4_key.k.vrf & CNAT_VRF_MASK),
2071                 ki->dk.ipv4_key.k.ipv4, ki->dk.ipv4_key.k.port, (ki->dk.ipv4_key.k.vrf & CNAT_PRO_MASK) };
2072             spp_printf(CNAT_CONFIG_ERROR, 5, arr);
2073         }
2074             return (db);
2075         }
2076
2077 #ifdef DEBUG_PRINTF_ENABLED
2078         printf("Deleting Dynamic entry  ki 0x%16llx ko 0x%16llx",
2079                        ki, db->out2in_key);
2080 #endif
2081
2082         /*
2083          * If for some reason we have dynamic entries, just delete them
2084          * and proceed.
2085          */
2086         cnat_delete_main_db_entry_v2(db);
2087         
2088         db = NULL;
2089     }
2090     
2091
2092     protocol = ki->dk.ipv4_key.k.vrf & CNAT_PRO_MASK;
2093     u_ki.dk.ipv4_key.k.vrf = ki->dk.ipv4_key.k.vrf & CNAT_VRF_MASK;
2094     u_ki.dk.ipv4_key.k.ipv4 = ki->dk.ipv4_key.k.ipv4;
2095     u_ki.dk.ipv4_key.k.port = 0;
2096     u_ki.dk.ipv6[0] =       ki->dk.ipv6[0];
2097     u_ki.dk.ipv6[1] =       ki->dk.ipv6[1];
2098     u_ki.dk.ipv6[2] =       ki->dk.ipv6[2];
2099     u_ki.dk.ipv6[3] =       ki->dk.ipv6[3];
2100
2101     my_vrfmap_index = vrf_map_array[u_ki.dk.ipv4_key.k.vrf];
2102     my_vrfmap = cnat_map_by_vrf + my_vrfmap_index;
2103
2104     pm = dslite_entry_ptr->portmap_list;
2105
2106     /*
2107      * check if src vrf, src ip addr is already 
2108      *         in the user db
2109      * if yes, use PORT_ALLOC_DIRECTED
2110      * if no, use PORT_ALLOC_ANY since it is first time
2111      */
2112     udb = dslite_user_db_lookup_entry(&u_ki);
2113     if (PREDICT_TRUE(udb)) {
2114         /* 
2115          * check if main db has space to accomodate new entry
2116          */
2117         h = pool_header(cnat_main_db);
2118
2119         free_main = vec_len(h->free_indices) - 1;
2120         if (PREDICT_FALSE(!free_main)) {
2121             info->error = CNAT_MAIN_DB_LIMIT;
2122             nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++;
2123             DSLITE_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT)
2124 #ifdef UT_TEST_CODE
2125             printf("Limit reached : OLD USER");
2126 #endif
2127             spp_printf(CNAT_MAIN_DB_LIMIT_ERROR, 0, 0);
2128             return NULL;
2129         }
2130
2131         /*
2132          * allocate port, from existing mapping 
2133          */
2134         my_index = udb->portmap_index;
2135         my_pm = pm + my_index;
2136        /* It is quite possible that we hit the scenario of CSCtj17774.
2137         * Delete all the main db entries and add the ipv4 address sent by
2138         * CGN-MA as Static port alloc any
2139         */
2140
2141         if (PREDICT_FALSE(my_pm->ipv4_address != ko->k.k.ipv4)) {
2142             if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) {
2143                 printf("Delete Main db entry and check for"
2144                         " ipv4 address sanity pm add = 0x%x ip add = 0x%x\n",
2145                         my_pm->ipv4_address,  ko->k.k.ipv4);
2146             }
2147             do {
2148                  /* udb is not NULL when we begin with for sure */
2149                  head = udb->translation_list_head_index;
2150                  db = cnat_main_db + head;
2151                  cnat_delete_main_db_entry_v2(db);
2152             } while (!pool_is_free(cnat_user_db, udb));
2153
2154             rv = cnat_mapped_static_port_alloc_v2_bulk (pm,
2155                  PORT_ALLOC_ANY, &my_index, ko->k.k.ipv4, ko->k.k.port,
2156                  udb, BULKSIZE_FROM_VRFMAP(dslite_entry_ptr), &nfv9_log_req, 
2157                                                         my_vrfmap->ip_n_to_1);
2158
2159             if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
2160              info->error = rv;
2161              nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++;
2162              DSLITE_DEBUG_INSIDE_ERR(rv)
2163              return (NULL);
2164             }
2165         /*
2166          * create entry in user db
2167          */
2168         udb = dslite_user_db_create_entry(&u_ki, my_index);
2169         nat44_dslite_common_stats[dslite_id].num_subscribers++;
2170 #ifndef NO_BULK_LOGGING
2171         if(PREDICT_FALSE(udb && (BULK_ALLOC_NOT_ATTEMPTED != nfv9_log_req))) {
2172             cnat_update_bulk_range_cache(udb, ko->k.k.port,
2173             BULKSIZE_FROM_VRFMAP(dslite_entry_ptr));
2174         }
2175 #endif /*  #ifndef NO_BULK_LOGGING */
2176       } else {
2177
2178         rv = cnat_mapped_static_port_alloc_v2_bulk (pm,
2179             PORT_ALLOC_DIRECTED, &my_index, ko->k.k.ipv4, ko->k.k.port,
2180             udb, BULKSIZE_FROM_VRFMAP(dslite_entry_ptr), &nfv9_log_req, 
2181             my_vrfmap->ip_n_to_1);
2182
2183         if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
2184             info->error = rv;
2185             DSLITE_DEBUG_INSIDE_ERR(rv)
2186             log_port_alloc_error(rv, &(ki->dk.ipv4_key));
2187             return (NULL);
2188         }
2189
2190         /*
2191          * increment port in use for this user
2192          */
2193         udb->ntranslations += 1;
2194       }
2195     } else {
2196         if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) {
2197             printf ("Static port alloc any\n");
2198         }
2199         /*
2200          * first time allocate port for this user
2201          */
2202      
2203         /*
2204          * Check if main db has space for new entry
2205          * Allowing a user db entry to be created if main db is not free
2206          * will cause a port to be allocated to that user, which results in  
2207          * wastage of that port, hence the check is done here.
2208          */
2209         h = pool_header(cnat_main_db);
2210         free_main = vec_len(h->free_indices) - 1;
2211         h = pool_header(cnat_user_db);
2212             free_user = vec_len(h->free_indices) - 1;
2213
2214         /*
2215          * If either main_db or user_db does not have entries
2216          * bail out, with appropriate error
2217          */
2218         if (PREDICT_FALSE(!(free_main && free_user))) {
2219             u32 log_error;
2220             if(free_main) {
2221                 info->error = CNAT_USER_DB_LIMIT;
2222                 log_error = CNAT_USER_DB_LIMIT_ERROR;
2223             } else {
2224                 info->error = CNAT_MAIN_DB_LIMIT;
2225                 log_error = CNAT_MAIN_DB_LIMIT_ERROR;
2226             }
2227             nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++;
2228             DSLITE_DEBUG_INSIDE_ERR(info->error)
2229             spp_printf(log_error, 0, 0);
2230             return NULL;
2231         }
2232
2233         rv = cnat_mapped_static_port_alloc_v2_bulk (pm,
2234             PORT_ALLOC_ANY, &my_index, ko->k.k.ipv4, ko->k.k.port,
2235             udb, BULKSIZE_FROM_VRFMAP(dslite_entry_ptr), &nfv9_log_req,
2236             my_vrfmap->ip_n_to_1);
2237
2238         if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
2239             info->error = rv;
2240             nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++;
2241             DSLITE_DEBUG_INSIDE_ERR(rv) 
2242             log_port_alloc_error(rv, &(ki->dk.ipv4_key));
2243             return (NULL);
2244         }
2245         /* 
2246          * create entry in user db
2247          */
2248         udb = dslite_user_db_create_entry(&u_ki, my_index);
2249         nat44_dslite_common_stats[dslite_id].num_subscribers++;
2250 #ifndef NO_BULK_LOGGING
2251         if(PREDICT_FALSE(udb && (BULK_ALLOC_NOT_ATTEMPTED != nfv9_log_req))) {
2252             cnat_update_bulk_range_cache(udb, ko->k.k.port,
2253             BULKSIZE_FROM_VRFMAP(dslite_entry_ptr));
2254         }
2255 #endif /*  #ifndef NO_BULK_LOGGING */
2256     }
2257
2258     /*
2259      * step 3:
2260      * outside port is allocated for this src vrf/src ip addr
2261      * 1)create a new entry in main db
2262      * 2)setup cnat_out2in_hash key
2263      * 3)setup cnat_in2out_hash key
2264      */
2265     db = dslite_create_main_db_entry_and_hash(ki, ko, udb);
2266     db->dslite_nat44_inst_id = dslite_id;
2267     nat44_dslite_common_stats[dslite_id].active_translations++;
2268     dslite_translation_create_count++;
2269
2270     /*
2271      * don't forget logging
2272      * logging API is unconditional, 
2273      * logging configuration check is done inside the inline function
2274      */
2275 #if 0 /* TBD - NEED TO DECIDE ON LOGGING */
2276         if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) {
2277         /* if session logging is enabled .. do not log  as there is no
2278          * traffic yet
2279          */
2280 #endif /* #if 0 - this has to be removed later */
2281
2282     return db;
2283 }
2284 #endif /* TOBE_PORTED */
2285
2286
2287 /* Per port/ip timeout related routines */
2288 static
2289 u32 cnat_timeout_db_hash_lookup (cnat_key_t t_key)
2290 {
2291     cnat_key_t key;
2292     u64 a, b, c;
2293     u32 index;
2294     cnat_timeout_db_entry_t *db;
2295
2296     key.k.ipv4 = t_key.k.ipv4;
2297     key.k.port = t_key.k.port;
2298     key.k.vrf = t_key.k.vrf;
2299
2300     CNAT_V4_GET_HASH(key.key64,
2301                      index, CNAT_TIMEOUT_HASH_MASK)
2302
2303
2304     index = cnat_timeout_hash[index].next;
2305
2306     if (PREDICT_FALSE(index == EMPTY))
2307         return EMPTY;
2308
2309     do {
2310         db = cnat_timeout_db + index;
2311         if (PREDICT_TRUE((db->t_key.timeout_key.key64 & CNAT_TIMEOUT_FULL_MASK)
2312                == (key.key64 & CNAT_TIMEOUT_FULL_MASK)))
2313             break;
2314         index = db->t_hash.next;
2315     } while (index != EMPTY);
2316
2317     return index;
2318 }
2319
2320 /* Pass db_type as MAIN_DB_TYPE if you are passing
2321  * cnat_main_db_entry_t * casted as void * for db
2322  * else pass db_type as SESSION_DB_TYPE
2323  */
2324 u16
2325 query_and_update_db_timeout(void *db, u8 db_type)
2326 {
2327     cnat_key_t t_search_key;
2328     u32 index;
2329     cnat_timeout_db_entry_t *timeout_db_entry;
2330     pool_header_t     *h;
2331     u32  free;
2332
2333     cnat_main_db_entry_t *mdb = NULL;
2334     cnat_session_entry_t *sdb = NULL;
2335
2336     if(PREDICT_TRUE(db_type == MAIN_DB_TYPE)) {
2337         mdb = (cnat_main_db_entry_t *)db;
2338     } else if(db_type == SESSION_DB_TYPE) {
2339         sdb = (cnat_session_entry_t *)db;
2340     } else {
2341         return 0;
2342     }
2343
2344     h = pool_header(cnat_timeout_db);
2345     free = vec_len(h->free_indices) - 1;
2346
2347     if(free == CNAT_TIMEOUT_HASH_SIZE) {
2348         /* No timeout db configured */
2349         return 0; 
2350     }
2351
2352     /* First search for ip/port pair */
2353     if(PREDICT_TRUE(db_type == MAIN_DB_TYPE)) {
2354         t_search_key.k.ipv4 = mdb->dst_ipv4;
2355         t_search_key.k.port = mdb->dst_port;
2356         t_search_key.k.vrf = mdb->in2out_key.k.vrf;
2357     } else {
2358         t_search_key.k.ipv4 = sdb->v4_dest_key.k.ipv4;
2359         t_search_key.k.port = sdb->v4_dest_key.k.port;
2360         t_search_key.k.vrf = sdb->v4_dest_key.k.vrf;
2361     }
2362
2363     index = cnat_timeout_db_hash_lookup(t_search_key);
2364
2365     if(index == EMPTY) {
2366         /* Search for port map */
2367         t_search_key.k.ipv4 = 0;
2368
2369         index = cnat_timeout_db_hash_lookup(t_search_key);
2370
2371         if(index == EMPTY) {
2372             /* Search for ip only map */
2373             if(PREDICT_TRUE(db_type == MAIN_DB_TYPE)) {
2374                 t_search_key.k.ipv4 = mdb->dst_ipv4;
2375             } else {
2376                 t_search_key.k.ipv4 = sdb->v4_dest_key.k.ipv4;
2377             }
2378             t_search_key.k.port = 0; 
2379
2380             index = cnat_timeout_db_hash_lookup(t_search_key);
2381             if(index != EMPTY) {
2382 #ifdef DEBUG_PRINTF_ENABLED
2383               printf("%s: ip only map sucess\n","query_and_update_db_timeout");
2384 #endif
2385             }
2386         } else {
2387 #ifdef DEBUG_PRINTF_ENABLED
2388             printf("%s: port only map sucess\n", "query_and_update_db_timeout");
2389 #endif
2390         }
2391
2392     } else {
2393 #ifdef DEBUG_PRINTF_ENABLED
2394         printf("%s: ip  port map sucess\n","query_and_update_db_timeout");
2395 #endif
2396
2397     }
2398
2399     if(index == EMPTY) {
2400         /* No match found, clear timeout */
2401         if(PREDICT_TRUE(db_type == MAIN_DB_TYPE)) {
2402             mdb->timeout = 0;
2403         } else {
2404             sdb->timeout = 0;
2405         }
2406 #ifdef DEBUG_PRINTF_ENABLED
2407         printf("%s: No match\n","query_and_update_db_timeout");
2408 #endif
2409     } else {
2410         /* Match found, update timeout */
2411         timeout_db_entry = cnat_timeout_db + index;
2412         if(PREDICT_TRUE(db_type == MAIN_DB_TYPE)) {
2413             mdb->timeout = timeout_db_entry->t_key.timeout_value;
2414         } else {
2415             sdb->timeout =  timeout_db_entry->t_key.timeout_value;
2416         }
2417         return timeout_db_entry->t_key.timeout_value;
2418     }
2419     return 0;
2420 }
2421
2422
2423
2424 static
2425 void cnat_timeout_db_hash_add (cnat_timeout_db_entry_t *t_entry)
2426 {
2427     cnat_key_t key;
2428     u64 a, b, c;
2429     u32 index, bucket;
2430     cnat_key_t t_key = t_entry->t_key.timeout_key;
2431
2432     key.k.ipv4 = t_key.k.ipv4;
2433     key.k.port = t_key.k.port;
2434     key.k.vrf = t_key.k.vrf;
2435
2436     CNAT_V4_GET_HASH(key.key64,
2437                      bucket, CNAT_TIMEOUT_HASH_MASK)
2438
2439
2440     index = cnat_timeout_hash[bucket].next;
2441
2442     /* Add this db entry to the head of the bucket chain */
2443     t_entry->t_hash.next = index;
2444     cnat_timeout_hash[bucket].next = t_entry - cnat_timeout_db;
2445 }
2446
2447
2448
2449 u16
2450 cnat_timeout_db_create (cnat_timeout_t t_entry)
2451 {
2452     cnat_timeout_db_entry_t *db;
2453     cnat_key_t t_key = t_entry.timeout_key;
2454     u32 db_index;
2455
2456     pool_header_t        *h;
2457     u32                  free;
2458
2459     /* UNUSED. Therefore not ported to be multi-thread friendly */
2460     ASSERT(0);
2461
2462     db_index = cnat_timeout_db_hash_lookup(t_key);
2463
2464     if(db_index != EMPTY) {
2465         /* Entry already exists. Check if it is replay or update */
2466         db = cnat_timeout_db + db_index;
2467         db->t_key.timeout_value = t_entry.timeout_value;
2468         return CNAT_SUCCESS;
2469     }
2470
2471     h = pool_header(cnat_timeout_db);
2472     free = vec_len(h->free_indices) - 1;
2473     
2474     if(free == 0) {
2475         return CNAT_OUT_LIMIT;
2476     }
2477
2478
2479     pool_get(cnat_timeout_db, db);
2480     ASSERT(db);
2481
2482     memset(db, 0, sizeof(*db));
2483
2484     db_index = db - cnat_timeout_db;
2485
2486     db->t_key.timeout_key.k.ipv4 = t_key.k.ipv4;
2487     db->t_key.timeout_key.k.port = t_key.k.port;
2488     db->t_key.timeout_key.k.vrf = t_key.k.vrf;
2489     db->t_key.timeout_value  = t_entry.timeout_value;
2490
2491
2492     cnat_timeout_db_hash_add(db);
2493     return CNAT_SUCCESS;
2494 }
2495
2496 void cnat_timeout_db_delete(cnat_key_t t_key)
2497 {
2498     cnat_key_t key;
2499     u64 a, b, c;
2500     u32 index, bucket;
2501     cnat_timeout_db_entry_t *this, *prev;
2502
2503     /* UNUSED. Therefore not ported to be multi-thread friendly */
2504     ASSERT(0);
2505
2506     key.k.ipv4 = t_key.k.ipv4;
2507     key.k.port = t_key.k.port;
2508     key.k.vrf = t_key.k.vrf;
2509
2510
2511     CNAT_V4_GET_HASH(key.key64,
2512                      bucket, CNAT_TIMEOUT_HASH_MASK)
2513
2514
2515     index = cnat_timeout_hash[bucket].next;
2516
2517     if(index == EMPTY) return;
2518
2519     prev = 0;
2520     do {
2521         this = cnat_timeout_db + index;
2522         if (PREDICT_TRUE(
2523             (this->t_key.timeout_key.key64 & CNAT_TIMEOUT_FULL_MASK) ==
2524                   (key.key64 & CNAT_TIMEOUT_FULL_MASK))) {
2525             if (prev == 0) {
2526                 cnat_timeout_hash[bucket].next = this->t_hash.next;
2527                 goto found;
2528              } else {
2529                 prev->t_hash.next = this->t_hash.next;
2530                 goto found;
2531             }
2532         }
2533
2534         prev = this;
2535         index = this->t_hash.next;
2536     } while (index != EMPTY);
2537
2538     if(index == EMPTY) return;
2539
2540  found:
2541     pool_put(cnat_timeout_db, this);
2542
2543 }
2544
2545 void cnat_session_db_hash_delete (cnat_session_entry_t *ep)
2546 {
2547     u32 a, b, c;
2548     u32 index, bucket;
2549     cnat_session_entry_t *this, *prev;
2550
2551     CNAT_V4_GET_SESSION_HASH(ep->main_db_index, ep->v4_dest_key.k.ipv4,
2552                     ep->v4_dest_key.k.port, ep->v4_dest_key.k.vrf, bucket,
2553                     CNAT_SESSION_HASH_MASK)
2554
2555
2556     index = cnat_session_hash[bucket].next;
2557
2558     ASSERT(index != EMPTY);
2559
2560     prev = 0;
2561     do {
2562         this = cnat_session_db + index;
2563         if (PREDICT_TRUE(this == ep)) {
2564             if (prev == 0) {
2565                 cnat_session_hash[bucket].next =
2566                               ep->cnat_session_hash.next;
2567                 return;
2568             } else {
2569                 prev->cnat_session_hash.next =
2570                               ep->cnat_session_hash.next;
2571                 return;
2572             }
2573         }
2574         prev = this;
2575         index = this->cnat_session_hash.next;
2576     } while (index != EMPTY);
2577
2578     ASSERT(0);
2579
2580 }
2581
2582 cnat_session_entry_t *
2583 cnat_session_db_edm_lookup_entry(cnat_key_t *ko,u32 session_head_index, 
2584                                  u32 main_db_index)
2585 {
2586     u32 index;
2587     cnat_session_entry_t *db;
2588
2589
2590     index = session_head_index;
2591     if (PREDICT_TRUE(index == EMPTY)) {
2592         return (NULL);
2593     }
2594
2595     do {
2596         db = cnat_session_db + index;
2597         if(PREDICT_TRUE((db->main_db_index == main_db_index) &&
2598               (db->v4_dest_key.k.vrf == ko->k.vrf) &&
2599               (db->v4_dest_key.k.ipv4 == ko->k.ipv4))) {
2600
2601                 return db;
2602         }
2603         index = db->cnat_session_hash.next;
2604     } while (index != EMPTY);
2605  
2606     return (NULL);
2607 }
2608
2609
2610
2611 cnat_session_entry_t *
2612 cnat_session_db_lookup_entry(cnat_key_t *ko,u32 main_db_index)
2613 {
2614     u32 a, b, c;
2615     u32 index, bucket;
2616     cnat_session_entry_t *db;
2617
2618     CNAT_V4_GET_SESSION_HASH(main_db_index, ko->k.ipv4, ko->k.port,
2619                      ko->k.vrf, bucket, CNAT_SESSION_HASH_MASK)
2620
2621
2622     index = cnat_session_hash[bucket].next;
2623     if (PREDICT_TRUE(index == EMPTY)) {
2624         return (NULL);
2625     }
2626
2627     do {
2628         db = cnat_session_db + index;
2629         if(PREDICT_TRUE((db->main_db_index == main_db_index) &&
2630               (db->v4_dest_key.k.vrf == ko->k.vrf) &&
2631               (db->v4_dest_key.k.port == ko->k.port) &&
2632               (db->v4_dest_key.k.ipv4 == ko->k.ipv4))) {
2633
2634                 return db;
2635         }
2636         index = db->cnat_session_hash.next;
2637     } while (index != EMPTY);
2638
2639     return (NULL);
2640 }
2641
2642 cnat_session_entry_t *
2643 cnat_create_session_db_entry(cnat_key_t *ko,
2644                              cnat_main_db_entry_t *bdb, u8 log)
2645 {
2646     u32 a, b, c;
2647     u32 db_index, bucket_out;
2648     cnat_session_entry_t *db = NULL;
2649     pool_header_t        *h;
2650     u32 free_session;
2651     u16 instance;
2652
2653     db = cnat_session_db_lookup_entry(ko, bdb - cnat_main_db);
2654     if (PREDICT_FALSE(db != NULL)) {
2655         /*printf("Create Session - Entry already Exists\n");*/
2656         return db;
2657     }
2658
2659     h = pool_header(cnat_session_db);
2660     free_session = vec_len(h->free_indices) - 1;
2661
2662     if (bdb->flags & CNAT_DB_DSLITE_FLAG) {
2663         instance = bdb->dslite_nat44_inst_id;
2664     } else {
2665         instance = NAT44_RESERVED_INST_ID;
2666     }
2667
2668     if (PREDICT_FALSE(!free_session)) {
2669       nat44_dslite_common_stats[instance].drops_sessiondb_limit_exceeded++;
2670         return NULL;
2671     }
2672
2673     if( PREDICT_FALSE(bdb->nsessions == CNAT_MAX_SESSIONS_PER_BIB)) {
2674         /* printf("Create Session - Max sessions per BIB reached\n"); */
2675         return NULL;
2676     }
2677
2678     pthread_spin_lock(cnat_db_v2_main.session_db_lockp);
2679     pool_get(cnat_session_db, db);
2680     memset(db, 0, sizeof(*db));
2681
2682     db_index = db - cnat_session_db;
2683     db->v4_dest_key.k.port = ko->k.port;
2684     db->v4_dest_key.k.ipv4 = ko->k.ipv4;
2685     db->v4_dest_key.k.vrf = ko->k.vrf;
2686
2687     db->main_list.next = db_index;
2688     db->main_list.prev = db_index;
2689     db->main_db_index = bdb - cnat_main_db;
2690
2691     db->tcp_seq_num = 0;
2692     db->ack_no      = 0;
2693     db->window      = 0;
2694
2695     if(PREDICT_FALSE(log)) {
2696         bdb->nsessions++;
2697         query_and_update_db_timeout(db, SESSION_DB_TYPE);
2698     }
2699
2700     if (PREDICT_FALSE(bdb->nsessions == 1)) {
2701         /*
2702          * first port for this src vrf/src ip addr
2703          */
2704         bdb->session_head_index = db_index;
2705     } else {
2706         index_dlist_addtail(bdb->session_head_index,
2707                             (u8 *)cnat_session_db, sizeof(cnat_session_db[0]),
2708                             STRUCT_OFFSET_OF(cnat_session_entry_t, main_list),
2709                             db_index);
2710     }
2711
2712     /*
2713      * setup o2i hash key
2714      */
2715     CNAT_V4_GET_SESSION_HASH(db->main_db_index, ko->k.ipv4, ko->k.port,
2716                      ko->k.vrf, bucket_out, CNAT_SESSION_HASH_MASK)
2717
2718
2719     db->cnat_session_hash.next =
2720                           cnat_session_hash[bucket_out].next;
2721     cnat_session_hash[bucket_out].next = db_index;
2722
2723
2724     if(PREDICT_FALSE(log)) {
2725         if (bdb->flags & CNAT_DB_DSLITE_FLAG) {
2726             cnat_session_log_ds_lite_mapping_create(bdb,
2727                                 (dslite_table_db_ptr + instance),db);
2728         } else {
2729             cnat_vrfmap_t *my_vrfmap = cnat_map_by_vrf + bdb->vrfmap_index;
2730             cnat_session_log_nat44_mapping_create(bdb, db, my_vrfmap);
2731         }
2732     }
2733
2734     /* Need to set entry_expires here, as we need to override 0 check for
2735        newly established sessions */
2736     db->entry_expires = cnat_current_time;
2737     nat44_dslite_common_stats[instance].sessions++;
2738     pthread_spin_unlock(cnat_db_v2_main.session_db_lockp);
2739     return db;
2740 }
2741
2742 void
2743 cnat_dest_update_main2session(cnat_main_db_entry_t *mdb,
2744                  cnat_session_entry_t *sdb)
2745 {
2746
2747     sdb->flags = mdb->flags;
2748     sdb->timeout = mdb->timeout;
2749     sdb->entry_expires = mdb->entry_expires;
2750     sdb->alg.delta = mdb->alg.delta;
2751     sdb->tcp_seq_num = mdb->proto_data.seq_pcp.tcp_seq_num;
2752
2753     /* Reset Main db values to 0 */
2754     /* Reset only session specific flags */
2755     mdb->flags &= ~(CNAT_DB_FLAG_TCP_ACTIVE | CNAT_DB_FLAG_UDP_ACTIVE
2756                         | CNAT_DB_FLAG_ALG_ENTRY | CNAT_DB_FLAG_ALG_CTRL_FLOW);
2757     mdb->timeout = 0;
2758     mdb->entry_expires = 0;
2759     mdb->alg.delta = 0;
2760     if(PREDICT_FALSE(!((mdb->flags & CNAT_DB_FLAG_PPTP_TUNNEL_ACTIVE) ||
2761             (mdb->flags & CNAT_DB_FLAG_PPTP_TUNNEL_INIT)))) {
2762         mdb->proto_data.seq_pcp.tcp_seq_num = 0;
2763     }
2764
2765     mdb->dst_ipv4 = 0;
2766     mdb->dst_port = 0;
2767 }
2768
2769
2770 void
2771 cnat_dest_update_session2main(cnat_main_db_entry_t *mdb,
2772                  cnat_session_entry_t *sdb)
2773 {
2774
2775     u16 flags = sdb->flags & (CNAT_DB_FLAG_TCP_ACTIVE |
2776         CNAT_DB_FLAG_UDP_ACTIVE | CNAT_DB_FLAG_ALG_ENTRY |
2777         CNAT_DB_FLAG_ALG_CTRL_FLOW);
2778     mdb->flags |= flags;
2779     mdb->timeout = sdb->timeout;
2780     mdb->entry_expires = sdb->entry_expires;
2781     mdb->alg.delta = sdb->alg.delta;
2782     if(PREDICT_FALSE(!((mdb->flags & CNAT_DB_FLAG_PPTP_TUNNEL_ACTIVE) ||
2783             (mdb->flags & CNAT_DB_FLAG_PPTP_TUNNEL_INIT)))) {
2784             mdb->proto_data.seq_pcp.tcp_seq_num = sdb->tcp_seq_num;
2785     }
2786     mdb->dst_ipv4 = sdb->v4_dest_key.k.ipv4;
2787     mdb->dst_port = sdb->v4_dest_key.k.port;
2788 }
2789
2790 static void
2791 _cnat_delete_session_db_entry (cnat_session_entry_t *ep, u8 log)
2792 {
2793     u32  session_db_index;
2794     u32  bdb_len;
2795     cnat_main_db_entry_t *be =0;
2796     cnat_session_entry_t *sdb_last = NULL;
2797     u16 instance;
2798
2799     if (PREDICT_FALSE(ep->flags & CNAT_DB_NAT64_FLAG) != 0) {
2800         /* Preventive check - Not a NAT44 entry */
2801         return;
2802     }
2803
2804     pool_header_t *h = pool_header(cnat_main_db);
2805
2806      /* Validate .. just in case we are trying to delete a non existing one */
2807     bdb_len = vec_len(cnat_main_db);
2808
2809     /* In case of invalid user just return, deleting only main db
2810      * is not a good idea, since some valid user db entry might be pointing
2811      * to that main db and hence leave the dbs in a inconsistent state
2812      */
2813     if (PREDICT_FALSE((ep->main_db_index >= bdb_len) ||
2814                     (clib_bitmap_get(h->free_bitmap, ep->main_db_index)))) {
2815 #ifdef DEBUG_PRINTF_ENABLED
2816         printf("invalid/unused user index in db %d\n", ep->main_db_index);
2817 #endif
2818         spp_printf(CNAT_INV_UNUSED_USR_INDEX, 1, (u32 *) &(ep->main_db_index));
2819         return;
2820     }
2821
2822     be = cnat_main_db + ep->main_db_index;
2823
2824     session_db_index = ep - cnat_session_db;
2825
2826     be->session_head_index = index_dlist_remelem (
2827         be->session_head_index, (u8 *)cnat_session_db,
2828         sizeof (cnat_session_db[0]),
2829         STRUCT_OFFSET_OF(cnat_session_entry_t, main_list),
2830         session_db_index);
2831
2832     if (be->flags & CNAT_DB_DSLITE_FLAG) {
2833         instance = be->dslite_nat44_inst_id;
2834     } else {
2835         instance = NAT44_RESERVED_INST_ID;
2836     }    
2837
2838     if(PREDICT_TRUE(log)) {
2839         if (be->flags & CNAT_DB_DSLITE_FLAG) {
2840             cnat_session_log_ds_lite_mapping_delete(be, 
2841                                 (dslite_table_db_ptr + instance),ep);
2842         } else {
2843             cnat_vrfmap_t *my_vrfmap = cnat_map_by_vrf + be->vrfmap_index;
2844             cnat_session_log_nat44_mapping_delete(be, ep, my_vrfmap);
2845         }
2846         be->nsessions--;
2847     }
2848
2849     if (PREDICT_FALSE(be->nsessions == 1 && log)) {
2850         /* There is only 1 session left
2851          * Copy the info back to main db and release the last
2852          * existing session
2853          */
2854
2855         sdb_last = cnat_session_db + be->session_head_index;
2856         ASSERT(sdb_last != NULL);
2857
2858         cnat_dest_update_session2main(be, sdb_last);
2859         _cnat_delete_session_db_entry(sdb_last, FALSE);
2860     }
2861
2862     /* Remove from session DB hashes */
2863     cnat_session_db_hash_delete(ep);
2864     nat44_dslite_common_stats[instance].sessions--;
2865
2866     pool_put(cnat_session_db, ep);
2867 }
2868
2869 void cnat_delete_session_db_entry (cnat_session_entry_t *ep, u8 log)
2870 {
2871     pthread_spin_lock(cnat_db_v2_main.session_db_lockp);
2872     _cnat_delete_session_db_entry (ep, log);
2873     pthread_spin_unlock(cnat_db_v2_main.session_db_lockp);
2874 }
2875
2876 cnat_main_db_entry_t*
2877 dslite_main_db_lookup_entry(dslite_db_key_bucket_t *ki)
2878 {
2879     u64 a, b, c;
2880     u32 index;
2881     cnat_main_db_entry_t *db;
2882     cnat_user_db_entry_t *userdb;
2883
2884     DSLITE_V6_GET_HASH((&(ki->dk)),
2885                      ki->bucket,
2886                      CNAT_MAIN_HASH_MASK);
2887
2888     DSLITE_PRINTF(1,"MDBLU hash..%u\n", ki->bucket);
2889  
2890     index = cnat_in2out_hash[ki->bucket].next;
2891     if (PREDICT_TRUE(index == EMPTY)) {
2892         DSLITE_PRINTF(1,"MDBLU index MT..\n");
2893         return (NULL);
2894     }
2895
2896     do {
2897 /* We can add a flag here to indicate if the db entry is for nat44 or 
2898  * dslite. If the db entry is for nat44 then we can simply move to the
2899  * one.
2900  */
2901         db = cnat_main_db + index;
2902         userdb = cnat_user_db + db->user_index;
2903         if (PREDICT_TRUE(db->in2out_key.key64 == ki->dk.ipv4_key.key64)
2904             && userdb->ipv6[0] == ki->dk.ipv6[0]
2905             && userdb->ipv6[1] == ki->dk.ipv6[1]
2906             && userdb->ipv6[2] == ki->dk.ipv6[2]
2907             && userdb->ipv6[3] == ki->dk.ipv6[3]) {
2908             DSLITE_PRINTF(1,"MDBLU success..%u\n", index);
2909             return db;
2910         }
2911         index = db->in2out_hash.next;
2912     } while (index != EMPTY);
2913
2914     DSLITE_PRINTF(1,"MDBLU Entry does not exist..\n");
2915     return (NULL);
2916 }
2917
2918 cnat_user_db_entry_t*
2919 dslite_user_db_lookup_entry(dslite_db_key_bucket_t *uki) 
2920 {
2921     u64 a, b, c;
2922     u32 index;
2923     cnat_user_db_entry_t *udb=NULL;
2924
2925     DSLITE_V6_GET_HASH((&(uki->dk)), 
2926                      uki->bucket,
2927                      CNAT_USER_HASH_MASK)
2928
2929     DSLITE_PRINTF(1,"UDBLU hash..%u\n", uki->bucket);
2930
2931     /* now: index in user vector */
2932     index = cnat_user_hash[uki->bucket].next;
2933     if (PREDICT_TRUE(index != EMPTY)) {
2934         DSLITE_PRINTF(1,"UDBLU hash table entry not MT..\n");
2935         do {
2936             udb = cnat_user_db + index;
2937             if (PREDICT_FALSE(udb->key.key64 == uki->dk.ipv4_key.key64)
2938              && udb->ipv6[0] == uki->dk.ipv6[0]
2939              && udb->ipv6[1] == uki->dk.ipv6[1]
2940              && udb->ipv6[2] == uki->dk.ipv6[2]
2941              && udb->ipv6[3] == uki->dk.ipv6[3]) {
2942                 DSLITE_PRINTF(1,"UDBLU success..%u\n", index);
2943                 return udb;
2944             }
2945             index = udb->user_hash.next;
2946         } while (index != EMPTY);
2947     }
2948     DSLITE_PRINTF(1,"UDBLU Entry doesnt exist..\n");
2949     return (NULL);
2950 }
2951
2952 cnat_user_db_entry_t*
2953 dslite_user_db_create_entry(dslite_db_key_bucket_t *uki,
2954                           u32 portmap_index)
2955 {
2956     cnat_user_db_entry_t *udb = NULL;
2957
2958     /* UNUSED. Therefore not ported to be multi-thread friendly */
2959     ASSERT(0);
2960
2961     pool_get(cnat_user_db, udb);
2962     memset(udb, 0, sizeof(*udb));
2963
2964     udb->ntranslations = 1; 
2965     udb->portmap_index = portmap_index;
2966 //    udb->key.key64 = uki->k.key64;
2967
2968     udb->key.key64 = uki->dk.ipv4_key.key64;
2969     udb->ipv6[0] = uki->dk.ipv6[0];
2970     udb->ipv6[1] = uki->dk.ipv6[1];
2971     udb->ipv6[2] = uki->dk.ipv6[2];
2972     udb->ipv6[3] = uki->dk.ipv6[3];
2973  
2974     udb->flags |= CNAT_USER_DB_DSLITE_FLAG;
2975     /* Add this user to the head of the bucket chain */
2976     udb->user_hash.next = 
2977              cnat_user_hash[uki->bucket].next;
2978     cnat_user_hash[uki->bucket].next = udb - cnat_user_db;
2979
2980 #ifndef NO_BULK_LOGGING
2981     INIT_BULK_CACHE(udb)
2982 #endif /* NO_BULK_LOGGING */
2983
2984     return udb;
2985 }
2986
2987 #ifndef TOBE_PORTED
2988 cnat_main_db_entry_t*
2989 dslite_create_main_db_entry_and_hash(dslite_db_key_bucket_t *ki,
2990                                    cnat_db_key_bucket_t *ko,
2991                                    cnat_user_db_entry_t *udb)
2992 {
2993     return 0;
2994 }
2995 #else
2996 cnat_main_db_entry_t*
2997 dslite_create_main_db_entry_and_hash(dslite_db_key_bucket_t *ki,
2998                                    cnat_db_key_bucket_t *ko,
2999                                    cnat_user_db_entry_t *udb)
3000 {
3001     u64 a, b, c;
3002     u32 db_index;
3003     cnat_main_db_entry_t *db = NULL;
3004
3005     /* UNUSED. Therefore not ported to be multi-thread friendly */
3006     ASSERT(0);
3007
3008     pool_get(cnat_main_db, db);
3009     memset(db, 0, sizeof(*db));
3010
3011     db_index = db - cnat_main_db;
3012     db->in2out_key.k.ipv4 = ki->dk.ipv4_key.k.ipv4;
3013     db->in2out_key.k.port = ki->dk.ipv4_key.k.port;
3014     db->in2out_key.k.vrf =  ki->dk.ipv4_key.k.vrf;
3015     db->out2in_key.k.ipv4 = ko->k.k.ipv4;
3016     db->out2in_key.k.port = ko->k.k.port;
3017     db->out2in_key.k.vrf = ko->k.k.vrf;
3018
3019     db->user_ports.next = db_index;
3020     db->user_ports.prev = db_index;
3021     db->user_index = udb - cnat_user_db;
3022     //db->portmap_index = udb->portmap_index;
3023    db->flags |= CNAT_DB_DSLITE_FLAG;
3024
3025     if (PREDICT_FALSE(udb->ntranslations == 1)) {
3026         /*
3027          * first port for this src vrf/src ip addr
3028          */
3029         udb->translation_list_head_index = db_index;
3030         DSLITE_PRINTF(1,"First translation of this user..\n");
3031     } else {
3032         index_dlist_addtail(udb->translation_list_head_index,
3033                             (u8 *)cnat_main_db, sizeof(cnat_main_db[0]),
3034                             STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports),
3035                             db_index);
3036     }
3037
3038     /* 
3039      * setup o2i hash key
3040      */
3041     CNAT_V4_GET_HASH(ko->k.key64, 
3042                      ko->bucket,
3043                      CNAT_MAIN_HASH_MASK)
3044     db->out2in_hash.next = cnat_out2in_hash[ko->bucket].next;
3045     cnat_out2in_hash[ko->bucket].next = db_index;
3046     /*
3047      * setup i2o hash key, bucket is already calculate
3048      */
3049     db->in2out_hash.next = cnat_in2out_hash[ki->bucket].next;
3050     cnat_in2out_hash[ki->bucket].next = db_index;
3051
3052     DSLITE_PRINTF(1,"Create main db and hash..%u %u %u %u %x\n", 
3053                   ki->bucket, ko->bucket, 
3054                   db_index, db->user_index, ko->k.key64);
3055
3056 #if DEBUG > 1
3057     printf("\nMy_Instance_Number %d: Bucket %d, Db_Index %d",
3058            my_instance_number, ki->bucket, db_index);
3059     printf("\nInside (VRF 0x%x, IP 0x%x, PORT 0x%x)",
3060            db->in2out_key.k.vrf, db->in2out_key.k.ipv4, db->in2out_key.k.port);
3061     printf("\nOutside (VRF 0x%x, IP 0x%x, PORT 0x%x)",
3062            db->out2in_key.k.vrf, db->out2in_key.k.ipv4, db->out2in_key.k.port);
3063     printf("\nUser Index %d, IP 0x%x",
3064            db->user_index, udb->key.k.ipv4);
3065 #endif
3066
3067     //nat44_dslite_common_stats[DSLITE_COMMON_STATS].active_translations++;
3068
3069     return db;
3070 }
3071
3072 static inline void handle_dslite_port_exceeded_logging(
3073     cnat_user_db_entry_t *udb, 
3074     dslite_key_t   * key,
3075     dslite_table_entry_t *dslite_entry_ptr)
3076 {
3077
3078     if(PREDICT_TRUE(udb->flags & CNAT_USER_DB_PORT_LIMIT_EXCEEDED)) {
3079         /* Already logged ..*/
3080         return;
3081     }
3082
3083     /* else, set the flag and call the log API */
3084     udb->flags = udb->flags | CNAT_USER_DB_PORT_LIMIT_EXCEEDED;
3085     cnat_log_ds_lite_port_limit_exceeded(key, dslite_entry_ptr);
3086     return;
3087 }
3088 #endif
3089
3090 void handle_cnat_port_exceeded_logging(
3091     cnat_user_db_entry_t *udb,
3092     cnat_key_t   * key,
3093     cnat_vrfmap_t *vrfmap)
3094 {
3095
3096     if(PREDICT_TRUE(udb->flags & CNAT_USER_DB_PORT_LIMIT_EXCEEDED)) {
3097         /* Already logged ..*/
3098         return;
3099     }
3100
3101     /* else, set the flag and call the log API */
3102     udb->flags = udb->flags | CNAT_USER_DB_PORT_LIMIT_EXCEEDED;
3103     cnat_log_nat44_port_limit_exceeded(key,vrfmap);
3104     return;
3105 }
3106
3107 #ifndef TOBE_PORTED
3108 cnat_main_db_entry_t*
3109 dslite_get_main_db_entry_v2(dslite_db_key_bucket_t *ki,
3110                           port_pair_t port_pair_type,
3111                           port_type_t port_type,
3112                           cnat_gen_icmp_info *info,
3113                           dslite_table_entry_t *dslite_entry_ptr,
3114                           cnat_key_t *dest_info)
3115 {
3116     return 0;
3117 }
3118 #else
3119 /*
3120  * this function is called by exception node
3121  * when lookup is fialed in i2o node
3122  *
3123  * if reash per user port limit, 
3124  * set user_db_entry pointer, and error == CNAT_OUT_LIMIT
3125  */
3126 cnat_main_db_entry_t*
3127 dslite_get_main_db_entry_v2(dslite_db_key_bucket_t *ki,
3128                           port_pair_t port_pair_type,
3129                           port_type_t port_type,
3130                           cnat_gen_icmp_info *info,
3131                           dslite_table_entry_t *dslite_entry_ptr,
3132                           cnat_key_t *dest_info)
3133 {
3134     u16 protocol;
3135     cnat_errno_t rv;
3136     dslite_db_key_bucket_t u_ki;
3137     cnat_db_key_bucket_t ko;
3138     u32                 my_index, free_main, free_user;
3139     u32                 current_timestamp;
3140     cnat_vrfmap_t       *my_vrfmap =0;
3141     u16                 my_vrfmap_index;
3142     cnat_portmap_v2_t   *pm =0;
3143     cnat_user_db_entry_t *udb = 0;
3144     cnat_main_db_entry_t *db = 0;
3145     pool_header_t        *h;
3146     u16 dslite_id = dslite_entry_ptr->dslite_id;
3147
3148 #ifndef NO_BULK_LOGGING
3149     int nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
3150 #endif
3151
3152     /* UNUSED. Therefore not ported to be multi-thread friendly */
3153     ASSERT(0);
3154
3155     /* 
3156      * need to try lookup again because 
3157      * second pkt may come here before the entry is created
3158      * by receiving first pkt due to high line rate.
3159      */
3160     info->gen_icmp_msg = CNAT_NO_ICMP_MSG;
3161     info->error = CNAT_SUCCESS;
3162     db = dslite_main_db_lookup_entry(ki);
3163     if (PREDICT_TRUE(db)) {
3164         /* what if the source is talking to a
3165          * new dest now? We will have to handle this case and
3166          * take care of - creating session db and logging
3167          */
3168         if(PREDICT_FALSE((!dest_info->k.ipv4) && (!dest_info->k.port))) {
3169             return db;  /* if dest_info is null don't create session */
3170         }
3171
3172         if(PREDICT_TRUE((db->dst_ipv4 == dest_info->k.ipv4) &&
3173             (db->dst_port == dest_info->k.port))) {
3174             return db;
3175         }
3176         dest_info->k.vrf = db->in2out_key.k.vrf;
3177         /* Src is indeed talking to a different dest */
3178         cnat_session_entry_t *session_db2 = NULL;
3179         if(PREDICT_TRUE(db->nsessions == 1)) {
3180             session_db2 = cnat_handle_1to2_session(db, dest_info);
3181             if(PREDICT_TRUE(session_db2 != NULL)) {
3182                 CNAT_DB_TIMEOUT_RST(session_db2);
3183                 return db;
3184             } else {
3185                 info->error = CNAT_ERR_NO_SESSION_DB;
3186                 return NULL;
3187             }
3188         } else if(PREDICT_FALSE(db->nsessions == 0)) {
3189             /* Should be static entry.. should never happen
3190              */
3191             if(PREDICT_TRUE(dest_info->k.ipv4 != 0)) {
3192                 cnat_add_dest_n_log(db, dest_info);
3193             }
3194             return db;
3195         } else {
3196             /* The src has already created multiple sessions.. very rare
3197              */
3198             session_db2 = cnat_create_session_db_entry(dest_info,
3199                         db, TRUE);
3200             if(PREDICT_TRUE(session_db2 != NULL)) {
3201                 CNAT_DB_TIMEOUT_RST(session_db2);
3202                return db;
3203             } else {
3204                 info->error = CNAT_ERR_NO_SESSION_DB;
3205                 return NULL;
3206             }
3207         }
3208
3209     }
3210
3211     /* 
3212      * step 1. check if outside vrf is configured or not
3213      *         and Find the set of portmaps for the outside vrf
3214      * insider vrf is one to one mappted to outside vrf
3215      * key is vrf and ip only
3216      * ki.k.k.vrf has protocol bits, mask out 
3217      */
3218     protocol =              ki->dk.ipv4_key.k.vrf & CNAT_PRO_MASK;
3219     u_ki.dk.ipv4_key.k.vrf =  ki->dk.ipv4_key.k.vrf & CNAT_VRF_MASK;
3220 #ifdef DSLITE_USER_IPV4
3221     u_ki.dk.ipv4_key.k.ipv4 = ki->dk.ipv4_key.k.ipv4;
3222 #else
3223    /*
3224     * Inside ipv4 address should be masked, if port limit
3225     * need to be done at B4 element level.
3226     */ 
3227     u_ki.dk.ipv4_key.k.ipv4 = 0;
3228 #endif
3229     u_ki.dk.ipv4_key.k.port = 0;
3230
3231     u_ki.dk.ipv6[0] =       ki->dk.ipv6[0];
3232     u_ki.dk.ipv6[1] =       ki->dk.ipv6[1];
3233     u_ki.dk.ipv6[2] =       ki->dk.ipv6[2];
3234     u_ki.dk.ipv6[3] =       ki->dk.ipv6[3];
3235
3236     my_vrfmap_index = vrf_map_array[u_ki.dk.ipv4_key.k.vrf];
3237     my_vrfmap = cnat_map_by_vrf + my_vrfmap_index;
3238 /*  Checking if the inst entry is active or not is done much earlier
3239  */
3240 #if 0
3241     my_vrfmap_index = vrf_map_array[u_ki.k.k.vrf];
3242     my_vrfmap = cnat_map_by_vrf + my_vrfmap_index;
3243     my_vrfmap_entry_found = ((my_vrfmap_index != VRF_MAP_ENTRY_EMPTY) &&
3244                              (my_vrfmap->status == S_RUN) &&
3245                              (my_vrfmap->i_vrf == u_ki.k.k.vrf));
3246
3247     if (PREDICT_FALSE(!my_vrfmap_entry_found)) {
3248         u32 arr[] = {ki->k.k.vrf, ki->k.k.ipv4, ki->k.k.port};
3249         if ((my_vrfmap_index == VRF_MAP_ENTRY_EMPTY) || 
3250             (my_vrfmap->i_vrf == u_ki.k.k.vrf)) {
3251             info->error = CNAT_NO_CONFIG;
3252             CNAT_DEBUG_INSIDE_ERR(CNAT_NO_CONFIG)
3253         spp_printf(CNAT_NO_CONFIG_ERROR, 3, arr);
3254         } else {
3255             info->error = CNAT_NO_VRF_RUN;
3256             CNAT_DEBUG_INSIDE_ERR(CNAT_NO_VRF_RUN)
3257         spp_printf(CNAT_NO_VRF_RUN_ERROR, 3, arr);
3258         }
3259
3260         return (NULL);
3261     }
3262 #endif
3263 /*
3264     dslite_inst_ptr = dslite_nat44_config_table[dslite_inst_id];
3265 */
3266     pm = dslite_entry_ptr->portmap_list;
3267     //pm = my_vrfmap->portmap_list;
3268
3269     /*
3270      * set o2i key with protocl bits
3271      */
3272     ko.k.k.vrf = dslite_entry_ptr->o_vrf | protocol;
3273     //ko.k.k.vrf = my_vrfmap->o_vrf | protocol;
3274
3275     /*
3276      * step 2. check if src vrf, src ip addr is alreay 
3277      *         in the user db
3278      * if yes, use PORT_ALLOC_DIRECTED
3279      * if no, use PORT_ALLOC_ANY since it is first time
3280      */
3281     udb = dslite_user_db_lookup_entry(&u_ki);
3282     if (PREDICT_TRUE(udb)) {
3283         /*
3284          * not first time allocate port for this user
3285          * check limit
3286          */
3287         if (PREDICT_FALSE(udb->ntranslations >= 
3288              dslite_entry_ptr->cnat_main_db_max_ports_per_user)) {
3289              //cnat_main_db_max_ports_per_user)) 
3290
3291             /* Check for the port type here. If we are getting
3292              * a STATIC PORT, allow the config.
3293              */
3294             if (PREDICT_TRUE(port_type != PORT_TYPE_STATIC)) {
3295                info->error = CNAT_OUT_LIMIT;
3296                DSLITE_DEBUG_INSIDE_ERR(CNAT_OUT_LIMIT)
3297                port_exceeded_msg_log(u_ki.dk.ipv4_key.k.ipv4, u_ki.dk.ipv4_key.k.vrf);
3298                nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++;
3299                u_ki.dk.ipv4_key.k.vrf =  ki->dk.ipv4_key.k.vrf;
3300                u_ki.dk.ipv4_key.k.port = ki->dk.ipv4_key.k.port;
3301                handle_dslite_port_exceeded_logging(udb, &u_ki.dk, dslite_entry_ptr); 
3302                return (NULL);
3303             }
3304         }
3305
3306         CHECK_CLEAR_PORT_LIMIT_EXCEED_FLAG(udb, 
3307             dslite_entry_ptr->cnat_main_db_max_ports_per_user)
3308
3309         /* 
3310          * check if main db has space to accomodate new entry
3311          */
3312         h = pool_header(cnat_main_db);
3313
3314         free_main = vec_len(h->free_indices) - 1;
3315         if (PREDICT_FALSE(!free_main)) {
3316             info->error = CNAT_MAIN_DB_LIMIT;
3317             nat44_dslite_common_stats[dslite_id].in2out_drops_system_limit_reached ++;
3318             DSLITE_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT)
3319
3320             current_timestamp = spp_trace_log_get_unix_time_in_seconds();
3321             if (PREDICT_FALSE((current_timestamp - last_log_timestamp) >
3322                     1800)) {
3323                 spp_printf(CNAT_SESSION_THRESH_EXCEEDED, 0, NULL);
3324                 last_log_timestamp = current_timestamp;
3325             }
3326
3327 #ifdef UT_TEST_CODE
3328             printf("Limit reached : OLD USER");
3329 #endif
3330             return NULL;
3331         }
3332
3333         /*
3334          * allocate port, from existing mapping 
3335          */
3336         my_index = udb->portmap_index;
3337
3338         if (PREDICT_FALSE(port_type == PORT_TYPE_STATIC)) {
3339             rv = cnat_static_port_alloc_v2_bulk(pm,
3340                         PORT_ALLOC_DIRECTED,
3341                         port_pair_type,
3342                         ki->dk.ipv4_key.k.ipv4,
3343                         ki->dk.ipv4_key.k.port,
3344                         &my_index,
3345                         &(ko.k.k.ipv4),
3346                         &(ko.k.k.port),
3347                         STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr)
3348 #ifndef NO_BULK_LOGGING
3349                         , udb,
3350                         BULKSIZE_FROM_VRFMAP(dslite_entry_ptr),
3351                         &nfv9_log_req
3352 #endif
3353                         , my_vrfmap->ip_n_to_1
3354                         );
3355         }  else if (PREDICT_TRUE(port_type != PORT_TYPE_RTSP) ) {
3356
3357             rv = cnat_dynamic_port_alloc_v2_bulk(pm,
3358                         PORT_ALLOC_DIRECTED,
3359                         port_pair_type,
3360                         &my_index,
3361                         &(ko.k.k.ipv4),
3362                         &(ko.k.k.port), 
3363                         STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr)
3364 #ifndef NO_BULK_LOGGING
3365                         , udb,
3366                         BULKSIZE_FROM_VRFMAP(dslite_entry_ptr),
3367                         &nfv9_log_req
3368 #endif
3369                         , 0,
3370                         &(dslite_entry_ptr->rseed_ip)
3371                         );
3372             DSLITE_PRINTF(1,"D_PORT_ALLOC %x %u\n", ko.k.k.ipv4, ko.k.k.port);
3373         } else {
3374             /*
3375              * For RTSP, two translation entries are created, 
3376              * check if main db has space to accomodate two new entry
3377              */
3378             free_main = free_main  - 1; 
3379
3380             if (PREDICT_FALSE(!free_main)) {
3381                 info->error = CNAT_MAIN_DB_LIMIT;
3382                 nat44_dslite_common_stats[dslite_id].in2out_drops_system_limit_reached ++;
3383                 DSLITE_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT)
3384
3385                 return NULL;
3386             } else {    
3387
3388                 rv = cnat_dynamic_port_alloc_rtsp_bulk(pm,
3389                             PORT_ALLOC_DIRECTED,
3390                             port_pair_type,
3391                             ki->dk.ipv4_key.k.port,
3392                             &my_index,
3393                             &(ko.k.k.ipv4),
3394                             &(ko.k.k.port),
3395                             STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr)
3396 #ifndef NO_BULK_LOGGING
3397                             , udb,
3398                             BULKSIZE_FROM_VRFMAP(dslite_entry_ptr),
3399                             &nfv9_log_req
3400 #endif
3401                          , &(dslite_entry_ptr->rseed_ip)
3402                         );
3403             }
3404         }
3405
3406         if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
3407             DSLITE_PRINTF(1,"D_PORT_ALLOC port alloc error\n");
3408             info->error = rv;
3409             DSLITE_DEBUG_INSIDE_ERR(rv)
3410             nat44_dslite_common_stats[dslite_id].in2out_drops_resource_depletion ++;
3411             log_port_alloc_error(rv, &(ki->dk.ipv4_key));
3412             return (NULL);
3413         }
3414         /*
3415          * increment port in use for this user
3416          */
3417         udb->ntranslations += 1;
3418     } else {
3419         /*
3420          * first time allocate port for this user
3421          */
3422      
3423         /*
3424          * Do not create entry if port limit is invalid
3425          */
3426         if (PREDICT_FALSE(!(dslite_entry_ptr->cnat_main_db_max_ports_per_user))) {
3427             if (PREDICT_TRUE(port_type != PORT_TYPE_STATIC)) {
3428                 info->error = CNAT_OUT_LIMIT;
3429                 nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++;
3430                 port_exceeded_msg_log(u_ki.dk.ipv4_key.k.ipv4, u_ki.dk.ipv4_key.k.vrf);
3431                 DSLITE_DEBUG_INSIDE_ERR(CNAT_OUT_LIMIT)
3432                 return (NULL);
3433             }
3434         }
3435
3436         /*
3437          * Check if main db has space for new entry
3438          * Allowing a user db entry to be created if main db is not free
3439          * will cause a port to be allocated to that user, which results in  
3440          * wastage of that port, hence the check is done here.
3441          */
3442         h = pool_header(cnat_main_db);
3443         free_main = vec_len(h->free_indices) - 1;
3444
3445         h = pool_header(cnat_user_db);
3446             free_user = vec_len(h->free_indices) - 1;
3447
3448         /*
3449          * If either main_db or user_db does not have entries
3450          * bail out, with appropriate error
3451          */
3452         if (PREDICT_FALSE(!(free_main && free_user))) {
3453             u32 log_error;
3454             if(free_main) {
3455                 info->error = CNAT_USER_DB_LIMIT;
3456                 log_error = CNAT_USER_DB_LIMIT_ERROR;
3457             } else {
3458                    info->error = CNAT_MAIN_DB_LIMIT;
3459                    log_error = CNAT_MAIN_DB_LIMIT_ERROR;
3460             }
3461             nat44_dslite_common_stats[dslite_id].in2out_drops_system_limit_reached ++;
3462             DSLITE_DEBUG_INSIDE_ERR(info->error)
3463             spp_printf(log_error, 0, 0);
3464             return NULL;
3465         }
3466
3467         if (PREDICT_FALSE(port_type == PORT_TYPE_STATIC)) {
3468             rv = cnat_static_port_alloc_v2_bulk(pm,
3469                         PORT_ALLOC_ANY,
3470                         port_pair_type,
3471                         ki->dk.ipv4_key.k.ipv4,
3472                         ki->dk.ipv4_key.k.port,
3473                         &my_index,
3474                         &(ko.k.k.ipv4),
3475                         &(ko.k.k.port),
3476                         STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr)
3477 #ifndef NO_BULK_LOGGING
3478                         , NULL,
3479                         BULKSIZE_FROM_VRFMAP(dslite_entry_ptr), 
3480                         &nfv9_log_req
3481 #endif
3482                         , my_vrfmap->ip_n_to_1
3483                       
3484                         );
3485         }  else if (PREDICT_TRUE(port_type != PORT_TYPE_RTSP)) {
3486             rv = cnat_dynamic_port_alloc_v2_bulk(pm,
3487                         PORT_ALLOC_ANY,
3488                         port_pair_type,
3489                         &my_index,
3490                         &(ko.k.k.ipv4),
3491                         &(ko.k.k.port),
3492                         STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr)
3493 #ifndef NO_BULK_LOGGING
3494                         , NULL,
3495                         BULKSIZE_FROM_VRFMAP(dslite_entry_ptr),
3496                         &nfv9_log_req
3497 #endif
3498                         , 0,
3499                         &(dslite_entry_ptr->rseed_ip)
3500                         );
3501             DSLITE_PRINTF(1,"NU:D PORT ALLOC..%x %u\n", ko.k.k.ipv4,
3502                              ko.k.k.port);
3503
3504         } else {
3505             /*
3506              * For RTSP, two translation entries are created,
3507              * check if main db has space to accomodate two new entry
3508              */
3509             free_main = free_main  - 1;
3510
3511             if (PREDICT_FALSE(!free_main)) {
3512                 info->error = CNAT_MAIN_DB_LIMIT;
3513                 nat44_dslite_common_stats[dslite_id].in2out_drops_system_limit_reached ++;
3514                 DSLITE_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT)
3515
3516                 return NULL;
3517             } else {
3518
3519                 rv = cnat_dynamic_port_alloc_rtsp_bulk(pm,
3520                             PORT_ALLOC_DIRECTED,
3521                             port_pair_type,
3522                             ki->dk.ipv4_key.k.port,
3523                             &my_index,
3524                             &(ko.k.k.ipv4),
3525                             &(ko.k.k.port),
3526                             STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr)
3527 #ifndef NO_BULK_LOGGING
3528                             , NULL,
3529                             BULKSIZE_FROM_VRFMAP(dslite_entry_ptr),
3530                             &nfv9_log_req
3531 #endif
3532                             , &(dslite_entry_ptr->rseed_ip)
3533                         );
3534             /* TODO: Add the port pair flag here */
3535             }
3536         }
3537
3538
3539
3540         if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
3541             DSLITE_PRINTF(1,"NU:D_PORT_ALLOC port alloc error\n");
3542             info->error = rv;
3543             nat44_dslite_common_stats[dslite_id].in2out_drops_resource_depletion ++;
3544             DSLITE_DEBUG_INSIDE_ERR(rv) 
3545             log_port_alloc_error(rv, &(ki->dk.ipv4_key));
3546             return (NULL);
3547         }
3548         /* 
3549          * create entry in user db
3550          */
3551         udb = dslite_user_db_create_entry(&u_ki, my_index);
3552         nat44_dslite_common_stats[dslite_id].num_subscribers++;
3553         DSLITE_PRINTF(1,"UDB crete entry done..\n");
3554 #ifndef NO_BULK_LOGGING
3555         if(PREDICT_TRUE(udb && (BULK_ALLOC_NOT_ATTEMPTED != nfv9_log_req))) {
3556             cnat_update_bulk_range_cache(udb, ko.k.k.port,
3557             BULKSIZE_FROM_VRFMAP(dslite_entry_ptr));
3558         }
3559 #endif /*  #ifndef NO_BULK_LOGGING */
3560     }
3561
3562     /*
3563      * step 3:
3564      * outside port is allocated for this src vrf/src ip addr
3565      * 1)create a new entry in main db
3566      * 2)setup cnat_out2in_hash key
3567      * 3)setup cnat_in2out_hash key
3568      */
3569     db = dslite_create_main_db_entry_and_hash(ki, &ko, udb);
3570     DSLITE_PRINTF(1,"dslite_create_main_db_entry_and_hash done..\n");
3571     //db->vrfmap_index = my_vrfmap - cnat_map_by_vrf;
3572     db->dslite_nat44_inst_id = dslite_id;
3573     nat44_dslite_common_stats[dslite_id].active_translations++;
3574     if (PREDICT_FALSE(port_type == PORT_TYPE_STATIC)) {
3575         nat44_dslite_common_stats[dslite_id].num_static_translations++;
3576     } else {
3577         nat44_dslite_common_stats[dslite_id].num_dynamic_translations++;
3578     }
3579
3580     dslite_translation_create_count++;
3581
3582     db->dst_ipv4 = dest_info->k.ipv4;
3583     db->dst_port = dest_info->k.port;
3584     if(PREDICT_TRUE(db->dst_ipv4 || db->dst_port)) {
3585         /* for static fwding, let the nsessions remain zero */
3586         db->nsessions++;
3587     }
3588
3589     /*
3590      * don't forget logging
3591      * logging API is unconditional, 
3592      * logging configuration check is done inside the inline function
3593      */
3594     if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) {
3595         if(PREDICT_FALSE( dslite_entry_ptr->nf_logging_policy == 
3596             SESSION_LOG_ENABLE)) {
3597             if(PREDICT_TRUE(db->dst_ipv4 || db->dst_port)) {
3598                 cnat_nfv9_ds_lite_log_session_create(db, 
3599                         dslite_entry_ptr,NULL);
3600             }
3601         } else {
3602                 cnat_nfv9_ds_lite_mapping_create(db,dslite_entry_ptr
3603 #ifndef NO_BULK_LOGGING
3604                 ,nfv9_log_req
3605 #endif
3606                 );
3607         }
3608         if(PREDICT_TRUE((dslite_entry_ptr->syslog_logging_policy != SESSION_LOG_ENABLE) ||
3609                         (db->dst_ipv4 || db->dst_port))) {
3610             cnat_syslog_ds_lite_mapping_create(db,dslite_entry_ptr,NULL
3611 #ifndef NO_BULK_LOGGING
3612             ,nfv9_log_req
3613 #endif
3614             );
3615         }
3616     }
3617
3618 #if 0
3619     if (PREDICT_FALSE(port_pair_type == PORT_PAIR)) {
3620        cnat_main_db_entry_t *db2 = 0;
3621        dslite_db_key_bucket_t new_ki = *ki;
3622        u64 a, b, c;
3623
3624        new_ki.k.k.port += 1;
3625        ko.k.k.port += 1;
3626
3627        CNAT_V4_GET_HASH(new_ki.k.key64, new_ki.bucket, 
3628                         CNAT_MAIN_HASH_MASK);
3629
3630        db2 = cnat_create_main_db_entry_and_hash(&new_ki, &ko, udb);
3631
3632        translation_create_count ++;
3633        db2->dslite_nat44_inst_id = dslite_id;
3634        db2->entry_expires = cnat_current_time;
3635        db2->flags |= CNAT_DB_FLAG_ALG_ENTRY;
3636        udb->ntranslations += 1;
3637 #ifndef NO_BULK_LOGGING
3638        if(PREDICT_FALSE(nfv9_log_req == BULK_ALLOC_NOT_ATTEMPTED))
3639            cnat_nfv9_log_mapping_create(db2, my_vrfmap, nfv9_log_req);
3640 #else 
3641         cnat_nfv9_log_mapping_create(db2, my_vrfmap);
3642 #endif
3643     }
3644 #endif
3645     return db;
3646 }
3647 #endif /* TOBE_PORTED */
3648
3649 #if 0
3650 /* TOBE_PORTED */
3651 uword
3652 cnat_db_v2_node_fn (vlib_main_t * vm,
3653                   vlib_node_runtime_t * node,
3654                   vlib_frame_t * frame)
3655 {
3656     return 0;
3657 }
3658 VLIB_REGISTER_NODE (cnat_db_v2_node) = {
3659     .function = cnat_db_v2_node_fn,
3660     .name = "vcgn-db-v2",
3661     .vector_size = sizeof (u32),
3662     .type = VLIB_NODE_TYPE_INTERNAL,
3663   
3664     .n_errors = ARRAY_LEN(cnat_db_v2_error_strings),
3665     .error_strings = cnat_db_v2_error_strings,
3666   
3667     .n_next_nodes = CNAT_DB_V2_DROP,
3668   
3669     /* edit / add dispositions here */
3670     .next_nodes = {
3671         [CNAT_DB_V2_DROP] = "error-drop",
3672     },
3673 };
3674 #endif
3675 void cnat_db_v2_init (void)
3676 {
3677
3678     u32 i, n;
3679     cnat_timeout_db_entry_t * tdb __attribute__((unused));
3680
3681     cgse_nat_db_entry_t *comb_db __attribute__((unused));
3682     cgse_nat_user_db_entry_t *comb_user __attribute__((unused));
3683     cgse_nat_session_db_entry_t *comb_session __attribute__((unused));
3684
3685     n = CNAT_DB_SIZE*1.15;    /* add 15% LB margin */
3686
3687     /*
3688      * We also make it multiple of NUM_BITS_IN_UWORD for better
3689      * DB scanning algorithm
3690      */
3691     if (n % NUM_BITS_IN_UWORD)
3692         n += (NUM_BITS_IN_UWORD - (n % NUM_BITS_IN_UWORD));
3693
3694     pool_alloc(cgse_nat_db,n);
3695     for(i=0; i< n; i++) {
3696          pool_get(cgse_nat_db, comb_db);
3697     }
3698
3699     for(i=0; i< n; i++) {
3700         pool_put(cgse_nat_db, cgse_nat_db + i);
3701     }
3702
3703     cnat_main_db = &cgse_nat_db->nat44_main_db; 
3704
3705     /* For Sessions */
3706     if(PLATFORM_DBL_SUPPORT) {
3707         /* create session table for NAT44 and NAT64 itself */
3708         printf("DBL Support exist %d\n", PLATFORM_DBL_SUPPORT);
3709         n = CNAT_SESSION_DB_SIZE * 1.15;    /* add 15% LB margin */
3710     } else {
3711         /* Create session table for NAT64 only */
3712         printf("DBL Support Not exist\n");
3713         n = NAT64_MAIN_DB_SIZE * 1.15;    /* add 15% LB margin */
3714     }
3715
3716     /*
3717      * We also make it multiple of NUM_BITS_IN_UWORD for better
3718      * DB scanning algorithm
3719      */
3720     if (n % NUM_BITS_IN_UWORD)
3721         n += (NUM_BITS_IN_UWORD - (n % NUM_BITS_IN_UWORD));
3722
3723     pool_alloc(cgse_session_db,n);
3724     for(i=0; i< n; i++) {
3725          pool_get(cgse_session_db, comb_session);
3726     }
3727
3728     for(i=0; i< n; i++) {
3729         pool_put(cgse_session_db, cgse_session_db + i);
3730     }
3731
3732     cnat_session_db = &cgse_session_db->nat44_session_db;
3733
3734     vec_validate(cnat_out2in_hash, CNAT_MAIN_HASH_MASK);
3735     memset(cnat_out2in_hash, 0xff, CNAT_MAIN_HASH_SIZE*sizeof(index_slist_t));
3736
3737     vec_validate(cnat_in2out_hash, CNAT_MAIN_HASH_MASK);
3738     memset(cnat_in2out_hash, 0xff, CNAT_MAIN_HASH_SIZE*sizeof(index_slist_t));
3739
3740     vec_validate(cnat_session_hash, CNAT_SESSION_HASH_MASK);
3741     memset(cnat_session_hash, 0xff, CNAT_SESSION_HASH_SIZE*sizeof(index_slist_t));
3742
3743     n = CNAT_USER_DB_SIZE * 1.15;  /* use hash size as db size for LB margin */
3744     if (n % NUM_BITS_IN_UWORD)
3745         n += (NUM_BITS_IN_UWORD - (n % NUM_BITS_IN_UWORD));
3746
3747     pool_alloc(cgse_user_db,n);
3748     for(i=0; i< n; i++) {
3749         pool_get(cgse_user_db, comb_user);
3750     }
3751
3752     for(i=0; i< n; i++) {
3753         pool_put(cgse_user_db, cgse_user_db + i);
3754     }
3755
3756     cnat_user_db = &cgse_user_db->nat44_user_db;
3757
3758     vec_validate(cnat_user_hash, CNAT_USER_HASH_MASK);
3759     memset(cnat_user_hash, 0xff, CNAT_USER_HASH_SIZE*sizeof(index_slist_t));
3760
3761     n = CNAT_TIMEOUT_HASH_SIZE;  /* use hash size as db size for LB margin */
3762     for(i=0; i< n; i++) {
3763         pool_get(cnat_timeout_db, tdb);
3764     }
3765
3766     for(i=0; i< n; i++) {
3767         pool_put(cnat_timeout_db, cnat_timeout_db + i);
3768     }
3769
3770     vec_validate(cnat_timeout_hash, CNAT_TIMEOUT_HASH_MASK);
3771     memset(cnat_timeout_hash, 0xff, CNAT_TIMEOUT_HASH_SIZE*sizeof(index_slist_t));
3772
3773 #ifdef TOBE_PORTED
3774     for (i=0;i<CNAT_MAX_VRFMAP_ENTRIES; i++) {
3775         svi_params_array[i].svi_type = CGSE_SVI_TYPE_INFRA;
3776     }
3777 #endif
3778
3779     cnat_db_v2_main.main_db_lockp =
3780         clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
3781             CLIB_CACHE_LINE_BYTES);
3782
3783     cnat_db_v2_main.user_db_lockp =
3784         clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
3785             CLIB_CACHE_LINE_BYTES);
3786
3787     cnat_db_v2_main.session_db_lockp =
3788         clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
3789             CLIB_CACHE_LINE_BYTES);
3790
3791     ASSERT (pthread_spin_init(cnat_db_v2_main.main_db_lockp,
3792         PTHREAD_PROCESS_PRIVATE) == 0);
3793     ASSERT (pthread_spin_init(cnat_db_v2_main.user_db_lockp,
3794         PTHREAD_PROCESS_PRIVATE) == 0);
3795     ASSERT (pthread_spin_init(cnat_db_v2_main.session_db_lockp,
3796         PTHREAD_PROCESS_PRIVATE) == 0);
3797
3798     cnat_db_init_done = 1;
3799     printf("CNAT DB init is successful\n");
3800     return;
3801     //return 0;
3802 }