FD.io VPP  v16.06
Vector Packet Processing
cnat_ports.c
Go to the documentation of this file.
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  */
52 
53 typedef struct {
55  /* $$$$ add data here */
56 
57  /* convenience variables */
61 
63 
64 static u32 rseed_port; /* random number generator seed */
65 
66 void
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
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
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 */
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  */
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)) &&
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)) &&
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)) {
251  my_pm->bm,i_port) == 1)
252 #ifndef NO_BULK_LOGGING
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)) {
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  */
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  */
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;
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 
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) || FIXME u16 cannot be >= 65536 */
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 
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) ||
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 
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;
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)) {
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
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  */
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)) {
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 
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))) {
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 
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  */
1097 {
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 
1113 
static int check_if_stat_alloc_ok_for_bulk(cnat_portmap_v2_t *pm, u16 i_port, bulk_alloc_size_t bulk_size, u16 static_port_range)
Definition: cnat_ports.c:108
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
static u16 bit2port(u32 bit)
Definition: cnat_ports.h:43
u32 private_ip_users_count
Definition: cnat_ports.h:77
#define PREDICT_TRUE(x)
Definition: clib.h:98
static u32 randq1(u32 prev)
Definition: cnat_ports.h:111
#define NULL
Definition: clib.h:55
clib_error_t * cnat_ports_init(vlib_main_t *vm)
Definition: cnat_ports.c:1096
cnat_errno_t
Definition: cnat_cli.h:26
cnat_portmap_v2_t * portmap_list
Definition: cnat_db.h:430
vnet_main_t * vnet_get_main(void)
Definition: misc.c:45
void cnat_portmap_dump_v2(cnat_portmap_v2_t *pm, u16 print_limit)
Definition: cnat_ports.c:1072
#define PLATFORM_DEBUG_PRINT(...)
cnat_errno_t cnat_static_port_alloc_v2(cnat_portmap_v2_t *pm, port_alloc_t atype, port_pair_t pair_type, u32 i_ipv4_address, u16 i_port, u32 *index, u32 *o_ipv4_address, u16 *o_port, u16 static_port_range, bulk_alloc_size_t bulk_size, int *nfv9_log_req, u16 ip_n_to_1)
Definition: cnat_ports.c:135
void cnat_port_free_v2(cnat_portmap_v2_t *pm, int index, port_pair_t pair_type, u16 base_port, u16 static_port_range)
Definition: cnat_ports.c:1037
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:109
void spp_printf(u16 error_code, u16 num_args, u32 *arg)
vnet_main_t * vnet_main
Definition: cnat_ports.c:59
#define PORTS_PER_ADDR
Definition: cnat_ports.h:26
static u32 rseed_port
Definition: cnat_ports.c:64
#define CNAT_MAX_VRFMAP_ENTRIES
Definition: cnat_db.h:103
void cnat_db_dump_portmaps()
Definition: cnat_ports.c:91
#define PREDICT_FALSE(x)
Definition: clib.h:97
u16 vrf_map_array[CNAT_MAX_VRFMAP_ENTRIES]
Definition: cnat_db_v2.c:219
#define PORT_PROBE_LIMIT
Definition: cnat_ports.h:101
cnat_errno_t cnat_dynamic_port_alloc_v2(cnat_portmap_v2_t *pm, port_alloc_t atype, port_pair_t pair_type, u32 *index, u32 *o_ipv4_address, u16 *o_port, u16 static_port_range, bulk_alloc_size_t bulk_size, int *nfv9_log_req, u16 ip_n_to_1, u32 *rseed_ip)
Definition: cnat_ports.c:554
#define BITS_PER_INST
Definition: cnat_ports.h:30
static uword cgn_clib_bitmap_clear_no_check(uword *a, uword i)
Definition: cgn_bitmap.h:81
static uword port2bit(u16 port)
Definition: cnat_ports.h:48
void cnat_db_dump_portmap_for_vrf(u32 vrfmap_index)
Definition: cnat_ports.c:67
#define BULK_ALLOC_NOT_ATTEMPTED
#define CNAT_DEBUG_GLOBAL_ALL
Definition: cnat_cli.h:94
u8 my_instance_number
Definition: cnat_ports.c:51
cnat_ports_main_t cnat_ports_main
Definition: cnat_ports.c:62
u32 spp_trace_log_get_unix_time_in_seconds(void)
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
port_alloc_t
Definition: cnat_ports.h:96
u32 global_debug_flag
port_pair_t
Definition: cnat_ports.h:82
#define VRF_MAP_ENTRY_EMPTY
Definition: cnat_db.h:506
u64 uword
Definition: types.h:112
always_inline uword clib_bitmap_get_no_check(uword *ai, uword i)
Definition: bitmap.h:170
unsigned short u16
Definition: types.h:57
cnat_vrfmap_t * cnat_map_by_vrf
Definition: cnat_db_v2.c:212
uword bm[(BITS_PER_INST+BITS(uword)-1)/BITS(uword)]
Definition: cnat_ports.h:75
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
vlib_main_t * vlib_main
Definition: cnat_ports.c:58
bulk_alloc_size_t
#define msg_spp_err(s)
Definition: cnat_ports.c:39
cnat_errno_t cnat_mapped_static_port_alloc_v2(cnat_portmap_v2_t *pm, port_alloc_t atype, u32 *index, u32 ipv4_address, u16 port, int *nfv9_log_req, bulk_alloc_size_t bulk_size, u16 ip_n_to_1)
Definition: cnat_ports.c:932
cnat_portmap_v2_t * cnat_dynamic_addr_alloc_from_pm(cnat_portmap_v2_t *pm, port_alloc_t atype, u32 *index, cnat_errno_t *err, u16 ip_n_to_1, u32 *rseed_ip)
Definition: cnat_ports.c:415
static uword cgn_clib_bitmap_check_if_all(uword *ai, u16 start, i16 num_bits)
Definition: cgn_bitmap.h:110
static uword cgn_clib_bitmap_set_no_check(uword *a, uword i)
Definition: cgn_bitmap.h:66
cnat_errno_t cnat_dynamic_port_alloc_rtsp(cnat_portmap_v2_t *pm, port_alloc_t atype, port_pair_t pair_type, u16 start_range, u16 end_range, u32 *index, u32 *o_ipv4_address, u16 *o_port, bulk_alloc_size_t bulk_size, int *nfv9_log_req, u32 *rseed_ip)
Definition: cnat_ports.c:906
CLIB vectors are ubiquitous dynamically resized arrays with by user defined "headers".