Initial commit of vpp code.
[vpp.git] / vnet / vnet / vcgn / cnat_ports.c
1 /* 
2  *------------------------------------------------------------------
3  * cnat_ports.c - port allocator
4  *
5  * Copyright (c) 2008-2014 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
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/hash.h>
23 #include <vppinfra/pool.h>
24 #include <vppinfra/clib.h>
25 #include <vppinfra/bitmap.h>
26
27 #include "cnat_db.h"
28 #include "cnat_config.h"
29 #include "cnat_global.h"
30 #include "cnat_logging.h"
31 #include "spp_timers.h"
32 #include "platform_common.h"
33 #include "cgn_bitmap.h"
34 #include "spp_platform_trace_log.h"
35 #include "cnat_ports.h"
36
37 #if 1 /* TOBE_PORTED */
38 /* Following is defined elsewhere. */
39 #define msg_spp_err(s)                          \
40 do {                                            \
41     fprintf(stderr,(i8 *)s);                    \
42     fputs("\n", stderr);                        \
43 } while(0);
44 #endif
45
46
47 #define PM_90_PERCENT_USE 58980
48 /*
49  * instance number provisioned from HW
50  */
51 u8 my_instance_number = 0;
52
53 typedef struct {
54   u32 cached_next_index;
55   /* $$$$ add data here */
56
57   /* convenience variables */
58   vlib_main_t * vlib_main;
59   vnet_main_t * vnet_main;
60 } cnat_ports_main_t;
61
62 cnat_ports_main_t cnat_ports_main;
63
64 static u32 rseed_port;          /* random number generator seed */
65
66 void
67 cnat_db_dump_portmap_for_vrf (u32 vrfmap_index)
68 {
69     u32 i, pm_len;
70     cnat_vrfmap_t *my_vrfmap = cnat_map_by_vrf + vrfmap_index;
71     cnat_portmap_v2_t *pm, *my_pm __attribute__((unused));
72
73     pm = my_vrfmap->portmap_list; 
74     pm_len = vec_len(pm);
75
76     for (i = 0; i < pm_len; i++) {
77         my_pm = pm + i;
78
79         PLATFORM_DEBUG_PRINT("pm %d: IPv4 Addr 0x%x - in use %d private_ip_users_count %d\n",
80                i, my_pm->ipv4_address, my_pm->inuse, 
81                my_pm->private_ip_users_count);
82
83         PLATFORM_DEBUG_PRINT("pm %d: IPv4 Addr 0x%x - in use %d "
84                              "private_ip_users_count %d\n",
85                              i, my_pm->ipv4_address, my_pm->inuse, 
86                              my_pm->private_ip_users_count);
87     }
88 }
89
90 void
91 cnat_db_dump_portmaps ()
92 {
93     u32 i, vrfmap_index;
94
95     for (i = 0; i < CNAT_MAX_VRFMAP_ENTRIES; i++) {
96         vrfmap_index = vrf_map_array[i];
97
98         if (vrfmap_index == VRF_MAP_ENTRY_EMPTY) {
99             continue;
100         }
101
102         PLATFORM_DEBUG_PRINT("\n\nDumping the port map for uidb_index %d\n", i);
103         cnat_db_dump_portmap_for_vrf(vrfmap_index);
104     }
105 }
106
107 #ifndef NO_BULK_LOGGING
108 static int check_if_stat_alloc_ok_for_bulk(cnat_portmap_v2_t *pm,
109             u16 i_port, bulk_alloc_size_t bulk_size,
110             u16 static_port_range)
111 {
112     uword bit_test_result;
113     if(BULK_ALLOC_SIZE_NONE == bulk_size) return 1; /* No issues */
114
115     if(i_port < static_port_range) return 1; /* we don't want bulk */
116
117     i_port = (i_port/bulk_size) * bulk_size;
118     bit_test_result = cgn_clib_bitmap_check_if_all(pm->bm, i_port, bulk_size);
119     return(bit_test_result);
120 }
121 #else /* dummy */
122 inline static int check_if_stat_alloc_ok_for_bulk(cnat_portmap_v2_t *pm,
123             u16 i_port, bulk_alloc_size_t bulk_size, 
124             u16 static_port_range)
125 {   
126     return 1;
127 }
128 #endif /* NO_BULK_LOGGING */
129 /*
130  * cnat_port_alloc_static_v2
131  * public ipv4 address/port allocator for Static Port commands
132  * tries to allocate same outside port as inside port
133  */
134 cnat_errno_t
135 cnat_static_port_alloc_v2 (
136                  cnat_portmap_v2_t    *pm,
137                  port_alloc_t          atype,
138                  port_pair_t           pair_type,
139                  u32                   i_ipv4_address,
140                  u16                   i_port,
141                  u32                  *index,
142                  u32                  *o_ipv4_address,
143                  u16                  *o_port,
144                  u16                   static_port_range
145 #ifndef NO_BULK_LOGGING
146                  , bulk_alloc_size_t    bulk_size,
147                  int *nfv9_log_req
148 #endif 
149                  , u16                   ip_n_to_1
150                  )
151 {
152     u32 i, hash_value, my_index, found, max_attempts;
153     u16 start_bit, new_port;
154     cnat_portmap_v2_t *my_pm = 0;
155     u32 pm_len = vec_len(pm);
156     uword bit_test_result;
157
158 #ifndef NO_BULK_LOGGING
159     *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
160 #endif 
161
162     if (PREDICT_FALSE(pm_len == 0)) {
163         return (CNAT_NO_POOL_ANY);
164     }
165
166     switch (atype) {
167
168     case PORT_ALLOC_ANY:
169
170         found = 0;
171
172         /*
173          * Try to hash the IPv4 address to get an index value to select the pm
174          */
175         hash_value = (i_ipv4_address & 0xffff) ^
176                         ((i_ipv4_address > 16) & 0xffff);
177
178         /*
179          * If pm_len <= 256, compact the hash to 8 bits
180          */
181         if (PREDICT_TRUE(pm_len <= 256)) {
182             hash_value = (hash_value & 0xff) ^ ((hash_value > 8) & 0xff);
183         }
184
185         /*
186          * Ensure that the hash value is in the range 0 .. (pm_len-1)
187          */
188         my_index = hash_value % pm_len;
189
190         for (i = 0; i < PORT_PROBE_LIMIT; i++) {
191             my_pm = pm + my_index;
192             if(PREDICT_TRUE(ip_n_to_1)) {
193                 if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1)) {
194                     /*
195                      * Try to find a PM with atlest 33% free and my_port free
196                      */
197                     if (PREDICT_TRUE((my_pm->inuse < ((BITS_PER_INST*2)/3)) &&
198                                      clib_bitmap_get_no_check(my_pm->bm, 
199                                                               i_port) == 1) 
200 #ifndef NO_BULK_LOGGING
201                         && check_if_stat_alloc_ok_for_bulk(my_pm, i_port,
202                                                            bulk_size, 
203                                                            static_port_range)
204 #endif 
205                         ) {
206                         found = 1;
207                         break;
208                     }
209                 }
210                 
211             } else {
212                 /*
213                  * Try to find a PM with atlest 33% free and my_port free
214                  */
215                 if (PREDICT_TRUE((my_pm->inuse < ((BITS_PER_INST*2)/3)) &&
216                                  clib_bitmap_get_no_check(my_pm->bm, 
217                                                           i_port) == 1) 
218 #ifndef NO_BULK_LOGGING
219                     && check_if_stat_alloc_ok_for_bulk(my_pm, i_port,
220                                                        bulk_size, 
221                                                        static_port_range)
222 #endif 
223                     ) {
224                     found = 1;
225                     break;
226                 }
227             }
228             my_index = (my_index + 1) % pm_len;
229         }
230
231         /*
232          * If not found do it the hard way .
233          * "hard" way, best-fit.
234          */
235         if (!found) {
236             u32 min_inuse_any, min_inuse_myport;
237             u32 min_index_any, min_index_myport;
238
239             min_inuse_any = min_inuse_myport = PORTS_PER_ADDR + 1;
240             min_index_any = min_index_myport = ~0;
241             for (i = 0; i < pm_len; i++) {
242                 my_pm = pm + i;
243                 if(PREDICT_TRUE(ip_n_to_1)) {
244                     if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1))                     {
245                         if (PREDICT_FALSE(my_pm->inuse < min_inuse_any)) {
246                             min_inuse_any = my_pm->inuse;
247                             min_index_any = my_pm - pm;
248                         }
249                         if (PREDICT_FALSE(my_pm->inuse < min_inuse_myport)) {
250                             if (PREDICT_TRUE(clib_bitmap_get_no_check(
251                                              my_pm->bm,i_port) == 1) 
252 #ifndef NO_BULK_LOGGING
253                                 && check_if_stat_alloc_ok_for_bulk(my_pm, 
254                                             i_port,bulk_size,static_port_range)
255 #endif 
256                                 ) {
257                                 min_inuse_myport = my_pm->inuse;
258                                 min_index_myport = my_pm - pm;
259                             }
260                         }
261                         
262                     } 
263                     
264                 } else {
265                     if (PREDICT_FALSE(my_pm->inuse < min_inuse_any)) {
266                         min_inuse_any = my_pm->inuse;
267                         min_index_any = my_pm - pm;
268                     }
269                     if (PREDICT_FALSE(my_pm->inuse < min_inuse_myport)) {
270                         if (PREDICT_TRUE(clib_bitmap_get_no_check(
271                                          my_pm->bm, i_port) == 1) 
272 #ifndef NO_BULK_LOGGING
273                             && check_if_stat_alloc_ok_for_bulk(my_pm, i_port,
274                                                  bulk_size, static_port_range)
275 #endif 
276                             ) {
277                             min_inuse_myport = my_pm->inuse;
278                             min_index_myport = my_pm - pm;
279                         }
280                     }
281                 }
282             }
283
284             /*
285              * Check if we have an exactly matching PM that has
286              * myport free.  If so use it.  If no such PM is
287              * available, use any PM
288              */
289             if (PREDICT_TRUE(min_inuse_myport < PORTS_PER_ADDR)) {
290                 my_pm = pm + min_index_myport;
291                 my_index = min_index_myport;
292                 found = 1;
293             } else if (PREDICT_TRUE(min_inuse_any < PORTS_PER_ADDR)) {
294                 my_pm = pm + min_index_any;
295                 my_index = min_index_any;
296                 found = 1;
297             }
298         }
299
300         if (!found) {
301             return (CNAT_NO_PORT_ANY);
302         }
303         break;
304
305     case PORT_ALLOC_DIRECTED:
306         my_index = *index;
307         if (PREDICT_FALSE(my_index > pm_len)) {
308             return (CNAT_INV_PORT_DIRECT);
309         }
310         my_pm = pm + my_index;
311         break;
312
313     default:
314         return (CNAT_ERR_PARSER);
315     }
316
317     /* Allocate a matching port if possible */
318     start_bit = i_port;
319     found = 0;
320     max_attempts = BITS_PER_INST;
321 #ifndef NO_BULK_LOGGING
322     if((BULK_ALLOC_SIZE_NONE != bulk_size) && 
323         (i_port >= static_port_range)) {
324         start_bit =  (start_bit/bulk_size) * bulk_size;
325         max_attempts = BITS_PER_INST/bulk_size;
326     }
327 #endif /* NO_BULK_LOGGING */
328
329     for (i = 0; i < max_attempts; i++) {
330 #ifndef NO_BULK_LOGGING
331         if((BULK_ALLOC_SIZE_NONE != bulk_size) &&
332             (i_port >= static_port_range)) {
333             bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm, 
334                         start_bit, bulk_size);
335         }
336         else
337 #endif /* #ifndef NO_BULK_LOGGING */
338         bit_test_result = clib_bitmap_get_no_check(my_pm->bm, start_bit);
339
340         if (PREDICT_TRUE(bit_test_result)) {
341 #ifndef NO_BULK_LOGGING
342         if((BULK_ALLOC_SIZE_NONE != bulk_size) && 
343             (i_port >= static_port_range)) {
344             *nfv9_log_req = start_bit;
345             if(i==0) new_port = i_port; /* First go */
346             else {
347                 new_port = bit2port(start_bit);
348                 if (pair_type == PORT_S_ODD &&  (new_port & 0x1) == 0)
349                     new_port++;                    
350             }
351             found = 1;
352             break;
353         }
354         else {
355 #endif  /* NO_BULK_LOGGING */
356             new_port = bit2port(start_bit);
357             if (pair_type == PORT_S_ODD) {
358                 if ((new_port & 0x1) == 1) {
359                     found = 1;
360                     break;
361                 }
362             } else if (pair_type == PORT_S_EVEN) {
363                 if ((new_port & 0x1) == 0) {
364                     found = 1;
365                     break;
366                 }
367             } else {
368                 found = 1;
369                 break;
370             }
371 #ifndef NO_BULK_LOGGING
372         }
373 #endif 
374         }
375 #ifndef NO_BULK_LOGGING
376         if((BULK_ALLOC_SIZE_NONE != bulk_size) &&
377                 (i_port >= static_port_range))
378             start_bit = (start_bit + bulk_size) % BITS_PER_INST;
379         else {
380 #endif /* NO_BULK_LOGGING */
381             start_bit = (start_bit + 1) % BITS_PER_INST;
382             if(PREDICT_FALSE(start_bit == 0)) {
383                 start_bit = 1; /* Port 0 is invalid, so start from 1 */
384             }
385 #ifndef NO_BULK_LOGGING
386         }
387 #endif 
388     } /* End of for loop */
389
390     if (!found) {
391         /* Port allocation failure */
392         if (atype == PORT_ALLOC_DIRECTED) {
393             return (CNAT_NOT_FOUND_DIRECT);
394         } else {
395             return (CNAT_NOT_FOUND_ANY);
396         }
397     }
398
399     /* Accounting */
400     cgn_clib_bitmap_clear_no_check(my_pm->bm, new_port);
401     (my_pm->inuse)++;
402
403     *index = my_pm - pm;
404     *o_ipv4_address = my_pm->ipv4_address;
405
406     *o_port = new_port;
407
408     return (CNAT_SUCCESS);
409 }
410
411 /*
412  * Try to allocate a portmap structure based on atype field
413  */
414 cnat_portmap_v2_t *
415 cnat_dynamic_addr_alloc_from_pm (
416                  cnat_portmap_v2_t    *pm,
417                  port_alloc_t          atype,
418                  u32                  *index,
419                  cnat_errno_t         *err,
420                  u16                   ip_n_to_1,
421                  u32                  *rseed_ip)
422 {
423     u32 i, pm_len;
424     int my_index;
425     int min_inuse, min_index;
426
427     cnat_portmap_v2_t *my_pm = 0;
428     *err = CNAT_NO_POOL_ANY;
429
430     pm_len = vec_len(pm);
431
432     switch(atype) {
433     case PORT_ALLOC_ANY:
434         if (PREDICT_FALSE(pm_len == 0)) {
435             my_pm = 0;
436             *err = CNAT_NO_POOL_ANY;
437             goto done;
438         }
439
440         /* "Easy" way, first address with at least 200 free ports */
441         for (i = 0; i < PORT_PROBE_LIMIT; i++) {
442             *rseed_ip = randq1(*rseed_ip);
443             my_index = (*rseed_ip) % pm_len;
444             my_pm = pm + my_index;
445             if (PREDICT_FALSE(ip_n_to_1)) {
446                 if(PREDICT_TRUE(ip_n_to_1 == 1)) {
447                     if (PREDICT_FALSE(0 == my_pm->inuse)) {     
448                         goto done;              
449                     }                                       
450                 } else {
451                     if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1))                     {
452                         if (PREDICT_FALSE(my_pm->inuse < ((BITS_PER_INST*2)/3)))                        {
453                             goto done;
454                         }
455                     } 
456                 }
457             } else {
458                 if (PREDICT_FALSE(my_pm->inuse < ((BITS_PER_INST*2)/3))) {
459                     goto done;
460                 }
461             }
462         }  
463
464         /* "hard" way, best-fit. $$$$ Throttle complaint */
465         min_inuse = PORTS_PER_ADDR + 1;
466         min_index = ~0;
467         for (i = 0; i < pm_len; i++) {
468             my_pm = pm + i;
469             if (PREDICT_FALSE(ip_n_to_1)) {
470                if(PREDICT_TRUE(ip_n_to_1 == 1)) {
471                    if (PREDICT_FALSE(!my_pm->inuse)) {
472                        min_inuse = my_pm->inuse;
473                        min_index = my_pm - pm;
474                    } 
475                } else {
476                    if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1)) {
477                        if (PREDICT_TRUE(my_pm->inuse < min_inuse)) {
478                            min_inuse = my_pm->inuse;
479                            min_index = my_pm - pm;
480                        }
481
482                    } 
483                }
484
485             } else {
486                 if (PREDICT_TRUE(my_pm->inuse < min_inuse)) {
487                     min_inuse = my_pm->inuse;
488                     min_index = my_pm - pm;
489                 }
490             }
491         }
492
493         if (PREDICT_TRUE(min_inuse < PORTS_PER_ADDR)) {
494             my_pm = pm + min_index;
495             my_index = min_index;
496             goto done;
497         }
498
499         /* Completely out of ports */
500 #ifdef DEBUG_PRINTF_ENABLED
501         PLATFORM_DEBUG_PRINT("%s out of ports\n", __FUNCTION__);
502 #endif
503
504         my_pm = 0;
505         *err = CNAT_NO_PORT_ANY;
506         break;
507
508
509     case PORT_ALLOC_DIRECTED:
510         //ASSERT(*index < pm_len);
511         if (PREDICT_FALSE(*index > pm_len)) {
512             my_pm = 0;
513             *err = CNAT_INV_PORT_DIRECT;
514             goto done;
515         }
516         my_pm = pm + *index;
517         my_index = *index;
518         break;
519
520     default:
521         msg_spp_err("bad allocation type in cnat_port_alloc");
522         my_pm = 0;
523         *err = CNAT_ERR_PARSER;
524         break;
525     }
526
527  done:
528     if (PREDICT_FALSE(my_pm == NULL)) {
529         return (my_pm);
530     }
531
532     if (PREDICT_FALSE(my_pm->inuse >= BITS_PER_INST)) {
533         my_pm = 0;
534         if (atype == PORT_ALLOC_DIRECTED) {
535             *err = CNAT_BAD_INUSE_DIRECT;
536         } else {
537             *err = CNAT_BAD_INUSE_ANY;
538         }
539     }
540
541     return (my_pm);
542 }
543
544
545 /*
546  * cnat_port_alloc_v2
547  * public ipv4 address/port allocator for dynamic ports
548  *
549  * 200K users / 20M translations means vec_len(cnat_portmap) will be
550  * around 300.
551  *
552  */
553 cnat_errno_t
554 cnat_dynamic_port_alloc_v2 (
555                  cnat_portmap_v2_t    *pm,
556                  port_alloc_t          atype,
557                  port_pair_t           pair_type,
558                  u32                  *index,
559                  u32                  *o_ipv4_address,
560                  u16                  *o_port,
561                  u16                  static_port_range
562 #ifndef NO_BULK_LOGGING
563                  , bulk_alloc_size_t    bulk_size,
564                   int *nfv9_log_req
565 #endif
566                  , u16                   ip_n_to_1,
567                   u32                  *rseed_ip
568                  )
569 {
570     int i;
571     cnat_errno_t       my_err = CNAT_NO_POOL_ANY;
572     cnat_portmap_v2_t *my_pm = 0;
573     u16 start_bit;
574     u16 new_port;
575     uword bit_test_result;
576     uword max_trys_to_find_port;
577
578     ASSERT(index);
579     ASSERT(o_ipv4_address);
580     ASSERT(o_port);
581
582     my_pm = cnat_dynamic_addr_alloc_from_pm(pm, atype, index, &my_err, ip_n_to_1, 
583             rseed_ip);
584
585     if (PREDICT_FALSE(my_pm == NULL)) {
586         return (my_err);
587     }
588     if(PREDICT_FALSE(my_pm->dyn_full == 1)) {
589         if (atype == PORT_ALLOC_DIRECTED) {
590             return (CNAT_NOT_FOUND_DIRECT);
591         } else {
592             return (CNAT_NOT_FOUND_ANY);
593         }
594     }
595
596 #if DEBUG > 1
597     PLATFORM_DEBUG_PRINT("ALLOC_PORT_V2: My_Instance_Number %d: IP addr 0x%x, Inuse %d\n",
598            my_instance_number, my_pm->ipv4_address, my_pm->inuse);
599 #endif
600
601     rseed_port = randq1(rseed_port);
602
603     /*
604      * Exclude the static port range for allocating dynamic ports
605      */
606     start_bit = (rseed_port) % (BITS_PER_INST - static_port_range);
607     start_bit = start_bit + static_port_range;
608
609 #ifndef NO_BULK_LOGGING
610     *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
611     if(BULK_ALLOC_SIZE_NONE != bulk_size)
612     {
613         /* We need the start port of the range to be alined on integer multiple
614          * of bulk_size */
615         max_trys_to_find_port = BITS_PER_INST/bulk_size;
616         start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size;
617     }
618     else
619 #endif /* #ifndef NO_BULK_LOGGING */
620     max_trys_to_find_port = BITS_PER_INST;
621
622     /* Allocate a random port / port-pair */
623     for (i = 0; i < max_trys_to_find_port;  i++) {
624
625     /* start_bit is only a u16.. so it can rollover and become zero */
626     if (PREDICT_FALSE((start_bit >= BITS_PER_INST) ||
627                     (start_bit < static_port_range))) {
628                     start_bit = static_port_range;
629 #ifndef NO_BULK_LOGGING
630         if(BULK_ALLOC_SIZE_NONE != bulk_size) {
631             start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size;
632         }
633 #endif /* #ifndef NO_BULK_LOGGING */
634     }
635         /* Scan forward from random position */
636 #ifndef NO_BULK_LOGGING
637         if(BULK_ALLOC_SIZE_NONE != bulk_size) {
638             bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm,
639             start_bit, bulk_size);
640         }
641         else
642 #endif /* #ifndef NO_BULK_LOGGING */
643         bit_test_result = clib_bitmap_get_no_check(my_pm->bm, start_bit);
644         
645         if (PREDICT_TRUE(bit_test_result)) {
646             new_port = bit2port(start_bit);
647 #ifndef NO_BULK_LOGGING
648             if(BULK_ALLOC_SIZE_NONE != bulk_size)
649                 *nfv9_log_req = new_port;
650 #endif
651             if ((pair_type == PORT_S_ODD) &&
652                        (!(new_port & 0x1))) {
653 #ifndef NO_BULK_LOGGING
654                 if(BULK_ALLOC_SIZE_NONE != bulk_size) {
655                     start_bit++; /* Just use the next one in the bulk range */
656                     new_port++;
657                     goto found2;
658                 }
659 #endif /* #ifndef NO_BULK_LOGGING */
660                         goto notfound;
661             } else if ((pair_type == PORT_S_EVEN) &&
662                        (new_port & 0x1)) {
663                         goto notfound;
664             }
665
666             /* OK we got one or two suitable ports */
667             goto found2;
668         }
669
670     notfound:
671 #ifndef NO_BULK_LOGGING
672     if(BULK_ALLOC_SIZE_NONE != bulk_size)
673         start_bit += bulk_size;
674     else
675 #endif /* #ifndef NO_BULK_LOGGING */
676     start_bit++;
677
678     } /* end of for loop */
679
680     /* Completely out of ports */
681
682     /* Port allocation failure */
683     /* set dyn_full flag. This would be used to verify
684      * for further dyn session before searching for port
685      */
686     if (atype == PORT_ALLOC_DIRECTED) {
687         my_pm->dyn_full = 1;
688         return (CNAT_NOT_FOUND_DIRECT);
689     } else {
690         my_pm->dyn_full = 1;
691         return (CNAT_NOT_FOUND_ANY);
692     }
693   
694
695  found2:
696
697     /* Accounting */
698     cgn_clib_bitmap_clear_no_check (my_pm->bm, start_bit);
699     (my_pm->inuse)++;
700
701     *index = my_pm - pm;
702     *o_ipv4_address = my_pm->ipv4_address;
703
704     *o_port = new_port;
705     return (CNAT_SUCCESS);
706 }
707
708 #ifdef TOBE_PORTED
709 /*
710  * cnat_alloc_port_from_pm
711  * Given a portmap structure find port/port_pair that are free
712  *
713  * The assumption in this function is that bit in bm corresponds
714  * to a port number.   This is TRUE and hence there is no call
715  * to the function bit2port here, though it is done in other 
716  * places in this file.
717  *
718  */
719 static u32
720 cnat_alloc_port_from_pm (
721     u32 start_port,
722     u32 end_port,
723     cnat_portmap_v2_t *my_pm,
724     port_pair_t       pair_type
725 #ifndef NO_BULK_LOGGING
726     , bulk_alloc_size_t    bulk_size,
727     int                  *nfv9_log_req
728 #endif /* #ifnded NO_BULK_ALLOCATION */
729     )
730 {
731     u32 i;
732     u32 start_bit;
733     u32 total_ports = end_port - start_port + 1;
734     uword bit_test_result;
735     uword max_trys_to_find_port;
736
737     rseed_port = randq1(rseed_port);
738
739     start_bit = rseed_port % total_ports;
740     start_bit = start_bit + start_port;
741 #ifndef NO_BULK_LOGGING
742     *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
743     if(BULK_ALLOC_SIZE_NONE != bulk_size)
744     {
745         /* We need the start port of the range to be alined on integer multiple
746          * of bulk_size */
747         max_trys_to_find_port = total_ports/bulk_size;
748         start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size;
749     }
750     else
751 #endif /* #ifndef NO_BULK_LOGGING */
752     max_trys_to_find_port = total_ports;
753
754     /* Allocate a random port / port-pair */
755     for (i = 0; i < max_trys_to_find_port; i++) {
756         /* start_bit is only a u16.. so it can rollover and become zero */
757         if (PREDICT_FALSE((start_bit >= end_port) ||
758                     (start_bit < start_port))) {
759                     start_bit = start_port;
760 #ifndef NO_BULK_LOGGING
761             if(BULK_ALLOC_SIZE_NONE != bulk_size) {
762                 start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size;
763             }
764 #endif /* #ifndef NO_BULK_LOGGING */
765         }
766
767         /* Scan forward from random position */
768 #ifndef NO_BULK_LOGGING
769         if(BULK_ALLOC_SIZE_NONE != bulk_size) {
770             bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm,
771             start_bit, bulk_size);
772         }
773         else
774 #endif /* #ifndef NO_BULK_LOGGING */
775             bit_test_result = clib_bitmap_get_no_check(my_pm->bm, start_bit);
776         
777             if (PREDICT_TRUE(bit_test_result)) {
778 #ifndef NO_BULK_LOGGING
779                 if(BULK_ALLOC_SIZE_NONE != bulk_size) {
780                     /* Got the entire bulk range */
781                     *nfv9_log_req = bit2port(start_bit);
782                     return start_bit;
783                 } else { 
784 #endif /* #ifndef NO_BULK_LOGGING */
785                         /*
786                          * For PORT_PAIR, first port has to be Even
787                          * subsequent port <= end_port
788                          * subsequent port should be unallocated
789                          */
790                 if ((start_bit & 0x1) ||
791                     ((start_bit + 1) > end_port) ||
792                             (clib_bitmap_get_no_check(my_pm->bm,
793                                     (start_bit + 1)) == 0)) {
794                         goto notfound;
795                 }
796                 return (start_bit);
797 #ifndef NO_BULK_LOGGING
798             }
799 #endif /* #ifndef NO_BULK_LOGGING */
800         } /* if( free port found ) */
801
802 notfound:
803 #ifndef NO_BULK_LOGGING
804         if(BULK_ALLOC_SIZE_NONE != bulk_size) {
805             start_bit += bulk_size;
806         } else
807 #endif /* #ifndef NO_BULK_LOGGING */
808             start_bit++;
809
810     }
811     return (BITS_PER_INST);
812 }
813
814 /*
815  * cnat_dynamic_port_alloc_rtsp
816  * public ipv4 address/port allocator for dynamic ports
817  *
818  * 200K users / 20M translations means vec_len(cnat_portmap) will be
819  * around 300.
820  *
821  */
822
823 cnat_errno_t
824 cnat_dynamic_port_alloc_rtsp (
825                             cnat_portmap_v2_t *pm,
826                             port_alloc_t       atype,
827                             port_pair_t        pair_type,
828                             u16                start_range,
829                             u16                end_range,
830                             u32               *index,
831                             u32               *o_ipv4_address,
832                             u16               *o_port
833 #ifndef NO_BULK_LOGGING
834                             , bulk_alloc_size_t bulk_size,
835                             int *nfv9_log_req
836 #endif
837                             , u32               *rseed_ip
838             )
839 {
840
841     u32 current_timestamp;
842     cnat_errno_t       my_err = CNAT_NO_POOL_ANY;
843     cnat_portmap_v2_t *my_pm = 0;
844     u32 alloc_bit;
845
846     ASSERT(index);
847     ASSERT(o_ipv4_address);
848     ASSERT(o_port);
849
850     my_pm = cnat_dynamic_addr_alloc_from_pm(pm, atype, index, &my_err, 0,rseed_ip);
851
852     if (PREDICT_FALSE(my_pm == NULL)) {
853         return (my_err);
854     }
855
856 #if DEBUG > 1
857     PLATFORM_DEBUG_PRINT("ALLOC_PORT_V2: My_Instance_Number %d: IP addr 0x%x, Inuse %d\n",
858            my_instance_number, my_pm->ipv4_address, my_pm->inuse);
859 #endif
860
861     alloc_bit = 
862         cnat_alloc_port_from_pm(start_range, end_range, my_pm, pair_type
863 #ifndef NO_BULK_LOGGING
864          , bulk_size, nfv9_log_req
865 #endif /* #ifndef NO_BULK_LOGGING */
866         );
867
868     if (alloc_bit < BITS_PER_INST) {
869         if (pair_type == PORT_PAIR) {
870             /* Accounting */
871             cgn_clib_bitmap_clear_no_check (my_pm->bm, alloc_bit);
872             cgn_clib_bitmap_clear_no_check (my_pm->bm, alloc_bit+1);
873             (my_pm->inuse) += 2;
874         } else {
875             /* Accounting */
876             cgn_clib_bitmap_clear_no_check (my_pm->bm, alloc_bit);
877             (my_pm->inuse)++;
878         }
879
880         *index = my_pm - pm;
881         *o_ipv4_address = my_pm->ipv4_address;
882
883         *o_port = bit2port(alloc_bit);;
884
885         return (CNAT_SUCCESS);
886     }
887
888     /* Completely out of ports */
889     current_timestamp = spp_trace_log_get_unix_time_in_seconds();
890     if (PREDICT_FALSE((current_timestamp - my_pm->last_sent_timestamp) >
891                 1000)) {
892         spp_printf(CNAT_NO_EXT_PORT_AVAILABLE, 0, NULL);
893         my_pm->last_sent_timestamp = current_timestamp;
894     }
895
896
897     /* Port allocation failure */
898     if (atype == PORT_ALLOC_DIRECTED) {
899         return (CNAT_NOT_FOUND_DIRECT);
900     } else {
901         return (CNAT_NOT_FOUND_ANY);
902     }
903 }
904 #else
905 cnat_errno_t
906 cnat_dynamic_port_alloc_rtsp (
907                             cnat_portmap_v2_t *pm,
908                             port_alloc_t       atype,
909                             port_pair_t        pair_type,
910                             u16                start_range,
911                             u16                end_range,
912                             u32               *index,
913                             u32               *o_ipv4_address,
914                             u16               *o_port
915 #ifndef NO_BULK_LOGGING
916                             , bulk_alloc_size_t bulk_size,
917                             int *nfv9_log_req
918 #endif
919                             , u32               *rseed_ip
920             )
921 {
922     return (CNAT_NOT_FOUND_ANY);
923 }
924 #endif
925
926
927 /*
928  * cnat_mapped_static_port_alloc_v2
929  * /
930  */
931 cnat_errno_t
932 cnat_mapped_static_port_alloc_v2 (
933              cnat_portmap_v2_t    *pm, 
934                      port_alloc_t         atype, 
935                      u32                  *index,
936                      u32                   ipv4_address,
937                      u16                   port
938 #ifndef NO_BULK_LOGGING
939             , int *nfv9_log_req,
940             bulk_alloc_size_t bulk_size
941 #endif
942             , u16                   ip_n_to_1
943                 )
944 {
945     int i;
946     u32 pm_len;
947     u16 bm_bit;
948     cnat_portmap_v2_t *my_pm = 0;
949     u32 my_index;
950
951     ASSERT(index);
952
953     /*
954      * Map the port to the bit in the pm bitmap structure.
955      * Note that we use ports from 1024..65535, so 
956      * port number x corresponds to (x-1024) position in bitmap
957      */
958     bm_bit = port2bit(port);
959
960     pm_len = vec_len(pm);
961
962     switch(atype) {
963     case PORT_ALLOC_ANY:
964         if (PREDICT_FALSE(pm_len == 0)) {
965             return (CNAT_NO_POOL_ANY);
966         }
967
968             /*
969              * Find the pm that is allocated for this translated IP address
970              */
971             my_index = pm_len;
972
973         for (i = 0; i < pm_len; i++) {
974                 my_pm = pm + i;
975                 if (PREDICT_FALSE(my_pm->ipv4_address == ipv4_address)) {
976                         my_index = i;
977                         break;
978                 }
979             }
980
981             if ((PREDICT_FALSE(my_index >= pm_len)) || 
982                 ((PREDICT_FALSE(ip_n_to_1)) && (PREDICT_TRUE(my_pm->private_ip_users_count >= ip_n_to_1)))) {
983                 return (CNAT_NO_POOL_ANY);
984             }
985
986             break;
987
988     case PORT_ALLOC_DIRECTED:
989         if (PREDICT_FALSE(*index > pm_len)) {
990             return (CNAT_INV_PORT_DIRECT);
991         }
992
993         my_index = *index;
994         my_pm = pm + my_index;
995         if (PREDICT_FALSE(my_pm->ipv4_address != ipv4_address)) {
996             if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) { 
997                 PLATFORM_DEBUG_PRINT("Delete all main db entry for that particular in ipv4 address\n");
998             }
999             return (CNAT_INV_PORT_DIRECT);
1000         }
1001         
1002         break;
1003
1004     default:
1005         msg_spp_err("bad allocation type in cnat_port_alloc");
1006         return (CNAT_ERR_PARSER);
1007     }
1008
1009
1010     if (PREDICT_FALSE(my_pm == NULL)) {
1011             return (CNAT_NO_POOL_ANY);
1012     }
1013
1014     /*
1015      * Check if the port is already allocated to some other mapping
1016      */
1017     if (PREDICT_FALSE(clib_bitmap_get_no_check (my_pm->bm, bm_bit) == 0)) {
1018             return (CNAT_NO_POOL_ANY);
1019     }
1020
1021 #if DEBUG > 1
1022     PLATFORM_DEBUG_PRINT("ALLOC_PORT_V2: My_Instance_Number %d: IP addr 0x%x, Inuse %d\n",
1023            my_instance_number, my_pm->ipv4_address, my_pm->inuse);
1024 #endif
1025
1026     /*
1027      * Indicate that the port is already allocated
1028      */
1029     cgn_clib_bitmap_clear_no_check (my_pm->bm, bm_bit);
1030     (my_pm->inuse)++;
1031
1032     *index = my_index;
1033
1034     return (CNAT_SUCCESS);
1035 }
1036
1037 void cnat_port_free_v2 (
1038          cnat_portmap_v2_t *pm,
1039          int                index,
1040          port_pair_t        pair_type,
1041          u16                base_port,
1042          u16                static_port_range)
1043 {
1044     cnat_portmap_v2_t *my_pm;
1045     uword bit;
1046
1047     /* check for valid portmap */   
1048     if (PREDICT_FALSE(index > vec_len(pm))) {
1049         spp_printf(CNAT_INVALID_INDEX_TO_FREE_PORT, 0, 0);
1050         return;
1051     }
1052
1053     my_pm = pm + index;
1054     bit = port2bit(base_port);
1055
1056 #if DEBUG > 0
1057     if(clib_bitmap_get_no_check(my_pm->bm, bit))
1058         ASSERT(clib_bitmap_get_no_check(my_pm->bm, bit) == 0); 
1059 #endif
1060
1061     cgn_clib_bitmap_set_no_check(my_pm->bm, bit);
1062
1063     my_pm->inuse -= 1;
1064     if(base_port >= static_port_range) {
1065         /* Clear the full flag. we can have a new dynamic session now */
1066         my_pm->dyn_full = 0;
1067     }
1068
1069     return;
1070 }
1071
1072 void cnat_portmap_dump_v2 (cnat_portmap_v2_t *pm, u16 print_limit)
1073 {
1074     int i;
1075     u32 inuse =0;
1076
1077     ASSERT(pm);
1078
1079     for (i = 0; i < BITS_PER_INST; i++) {
1080         if (PREDICT_FALSE(clib_bitmap_get_no_check (pm->bm, i) == 0)) {
1081             if (PREDICT_TRUE(inuse++ < print_limit))
1082                 PLATFORM_DEBUG_PRINT(" %d", bit2port(i));
1083         }
1084     }
1085     if (PREDICT_FALSE(inuse >= print_limit)) {
1086         PLATFORM_DEBUG_PRINT("%d printed, print limit is %d\n",
1087                 inuse, print_limit);
1088     }
1089     PLATFORM_DEBUG_PRINT("\n");
1090 }
1091
1092
1093 /*
1094  * cnat_ports_init
1095  */
1096 clib_error_t *cnat_ports_init(vlib_main_t *vm)
1097 {
1098     cnat_ports_main_t *mp = &cnat_ports_main;
1099
1100     mp->vlib_main = vm;
1101     mp->vnet_main = vnet_get_main();
1102
1103     /* suppress crypto-random port numbering */
1104 #ifdef SOON
1105     if (spp_get_int_prop("no_crypto_random_ports") == 0)
1106         crypto_random32(&seed);
1107 #endif
1108
1109     return 0;
1110 }
1111
1112 VLIB_INIT_FUNCTION(cnat_ports_init);
1113