18cc4ba0d1e45a87c18831716a20fbc7de3acb91
[vpp.git] / plugins / vcgn-plugin / vcgn / vcgn_classify.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vnet/plugin/plugin.h>
17 #include <vlib/vlib.h>
18 #include <vnet/vnet.h>
19 #include <vnet/pg/pg.h>
20 #include <vppinfra/error.h>
21 #include <vppinfra/pool.h>
22
23 #include <vnet/ip/ip.h>
24 #include <vnet/ethernet/ethernet.h>
25
26 #include "cnat_db.h"
27 #include "cnat_global.h"
28 #include "cnat_cli.h"
29 #include "cnat_config.h"
30 #include "cnat_logging.h"
31 #include "cnat_config_api.h"
32 #include "cnat_show_api.h"
33 #include "cnat_show_response.h"
34 #include "cnat_ipv4_udp.h"
35 #include "cnat_common_api.h"
36
37 #include <arpa/inet.h>
38
39 typedef struct {
40   u32 cached_next_index;
41
42   /* inside, outside interface handles */
43   u32 * inside_sw_if_index_table;
44   u32 * outside_sw_if_index_table;
45
46   /* convenience variables */
47   vlib_main_t * vlib_main;
48   vnet_main_t * vnet_main;
49   u8 cnat_db_initalized;
50 } vcgn_classify_main_t;
51
52 typedef struct {
53   /* $$$$ fill in with per-pkt trace data */ 
54   u32 next_index;
55   u32 sw_if_index;
56   u32 orig_dst_address;
57   u16 orig_dst_port;
58 } vcgn_classify_trace_t;
59
60 #define FIND_MY_VRF_USING_I_VRF_ID                                       \
61     my_vrfmap_found = 0;                                                 \
62     pool_foreach (my_vrfmap, cnat_map_by_vrf, ({                         \
63         if (my_vrfmap->i_vrf_id == i_vrf_id) {                           \
64             my_vrfmap_found = 1;                                         \
65             my_vrfmap_temp = my_vrfmap;                                  \
66             break;                                                       \
67         }                                                                \
68     }));
69
70
71 /* packet trace format function */
72 static u8 * format_swap_trace (u8 * s, va_list * args)
73 {
74   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
75   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
76   vcgn_classify_trace_t * t = va_arg (*args, vcgn_classify_trace_t *);
77   
78   s = format (s, "VCGN_CLASSIFY: dst %U dst_port %d sw_if_index %d next %d",
79               format_ip4_address, (ip4_header_t *) &t->orig_dst_address,
80               clib_net_to_host_u16(t->orig_dst_port), 
81               t->sw_if_index, t->next_index);
82   return s;
83 }
84
85 vcgn_classify_main_t vcgn_classify_main;
86
87 vlib_node_registration_t vcgn_classify_node;
88
89 #define foreach_vcgn_classify_error \
90 _(PACKETS_RECEIVED,     "total packets received")   \
91 _(V4_PACKETS_PROCESSED, "ipv4 packets processed for vCGN")   \
92 _(V4_PACKETS_PUNTED,    "ipv4 packets punted")   \
93 _(V6_PACKETS_PUNTED,    "ipv6 packets punted")   \
94 _(MPLS_PACKETS_PUNTED,  "mpls unicast packets punted")   \
95 _(ETH_PACKETS_PUNTED,   "ethernet packets punted")
96
97
98 typedef enum {
99 #define _(sym,str) VCGN_CLASSIFY_ERROR_##sym,
100   foreach_vcgn_classify_error
101 #undef _
102   VCGN_CLASSIFY_N_ERROR,
103 } vcgn_classify_error_t;
104
105 static char * vcgn_classify_error_strings[] = {
106 #define _(sym,string) string,
107   foreach_vcgn_classify_error
108 #undef _
109 };
110
111 /* 
112  * To drop a pkt and increment one of the previous counters:
113  * 
114  * set b0->error = error_node->errors[VCGN_CLASSIFY_ERROR_EXAMPLE];
115  * set next0 to a disposition index bound to "error-drop".
116  *
117  * To manually increment the specific counter VCGN_CLASSIFY_ERROR_EXAMPLE:
118  *
119  *  vlib_node_t *n = vlib_get_node (vm, vcgn_classify.index);
120  *  u32 node_counter_base_index = n->error_heap_index;
121  *  vlib_error_main_t * em = &vm->error_main;
122  *  em->counters[node_counter_base_index + VCGN_CLASSIFY_ERROR_EXAMPLE] += 1;
123  * 
124  */
125
126 typedef enum {
127   VCGN_CLASSIFY_NEXT_IP4_INPUT,
128   VCGN_CLASSIFY_NEXT_IP6_INPUT,
129   VCGN_CLASSIFY_NEXT_MPLS_INPUT,
130   VCGN_CLASSIFY_NEXT_ETHERNET_INPUT,
131   VCGN_CLASSIFY_NEXT_UDP_INSIDE,
132   VCGN_CLASSIFY_NEXT_UDP_OUTSIDE,
133   VCGN_CLASSIFY_NEXT_TCP_INSIDE,
134   VCGN_CLASSIFY_NEXT_TCP_OUTSIDE,
135   VCGN_CLASSIFY_NEXT_ICMP_Q_INSIDE,
136   VCGN_CLASSIFY_NEXT_ICMP_Q_OUTSIDE,
137   VCGN_CLASSIFY_NEXT_ICMP_E_INSIDE,
138   VCGN_CLASSIFY_NEXT_ICMP_E_OUTSIDE,
139   VCGN_CLASSIFY_N_NEXT,
140 } vcgn_classify_next_t;
141
142 static uword
143 vcgn_classify_node_fn (vlib_main_t * vm,
144                   vlib_node_runtime_t * node,
145                   vlib_frame_t * frame)
146 {
147   u32 n_left_from, * from, * to_next;
148   vcgn_classify_next_t next_index;
149   vcgn_classify_main_t * vcm = &vcgn_classify_main;
150   vlib_node_t *n = vlib_get_node (vm, vcgn_classify_node.index);
151   u32 node_counter_base_index = n->error_heap_index;
152   vlib_error_main_t * em = &vm->error_main;
153   u16 *l3_type;
154   int counter;
155
156   from = vlib_frame_vector_args (frame);
157   n_left_from = frame->n_vectors;
158   next_index = node->cached_next_index;
159
160   while (n_left_from > 0)
161     {
162       u32 n_left_to_next;
163
164       vlib_get_next_frame (vm, node, next_index,
165                            to_next, n_left_to_next);
166
167       #if 0
168       while (n_left_from >= 4 && n_left_to_next >= 2)
169       {
170           u32 bi0, bi1;
171           vlib_buffer_t * b0, * b1;
172           u32 next0, next1;
173           u32 sw_if_index0, sw_if_index1;
174           
175           /* Prefetch next iteration. */
176           {
177             vlib_buffer_t * p2, * p3;
178             
179             p2 = vlib_get_buffer (vm, from[2]);
180             p3 = vlib_get_buffer (vm, from[3]);
181             
182             vlib_prefetch_buffer_header (p2, LOAD);
183             vlib_prefetch_buffer_header (p3, LOAD);
184
185             CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
186             CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
187           }
188
189           /* speculatively enqueue b0 and b1 to the current next frame */
190           to_next[0] = bi0 = from[0];
191           to_next[1] = bi1 = from[1];
192           from += 2;
193           to_next += 2;
194           n_left_from -= 2;
195           n_left_to_next -= 2;
196
197           b0 = vlib_get_buffer (vm, bi0);
198           b1 = vlib_get_buffer (vm, bi1);
199
200           sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
201           next0 = vcm->cached_next_index;
202           sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
203           next1 = vcm->cached_next_index;
204
205           /* $$$$ your message in this space. Process 2 x pkts */
206           em->counters[node_counter_base_index + VCGN_CLASSIFY_ERROR_PACKETS_RECEIVED] += 2;
207
208           if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)))
209             {
210               if (b0->flags & VLIB_BUFFER_IS_TRACED) 
211                 {
212                     vcgn_classify_trace_t *t = 
213                       vlib_add_trace (vm, node, b0, sizeof (*t));
214                     t->sw_if_index = sw_if_index0;
215                     t->next_index = next0;
216                   }
217                 if (b1->flags & VLIB_BUFFER_IS_TRACED) 
218                   {
219                     vcgn_classify_trace_t *t = 
220                       vlib_add_trace (vm, node, b1, sizeof (*t));
221                     t->sw_if_index = sw_if_index1;
222                     t->next_index = next1;
223                   }
224               }
225             
226             /* verify speculative enqueues, maybe switch current next frame */
227             vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
228                                              to_next, n_left_to_next,
229                                              bi0, bi1, next0, next1);
230         }
231         #endif /* if 0 */
232       
233       while (n_left_from > 0 && n_left_to_next > 0)
234       {
235           u32 bi0;
236           vlib_buffer_t * b0;
237           u32 next0;
238           u32 sw_if_index0;
239           ip4_header_t * h0;
240           //ipv4_header *h0;
241           ethernet_header_t *eth0;
242           icmp_v4_t *icmp;
243           u8 icmp_type;
244           u8 ipv4_hdr_len;
245
246           /* speculatively enqueue b0 to the current next frame */
247           bi0 = from[0];
248           to_next[0] = bi0;
249           from += 1;
250           to_next += 1;
251           n_left_from -= 1;
252           n_left_to_next -= 1;
253
254           b0 = vlib_get_buffer (vm, bi0);
255           
256           eth0 = (ethernet_header_t *) vlib_buffer_get_current(b0);
257           u16 *etype = &eth0->type;
258     
259           /* vlan tag 0x8100 */      
260           if (*etype == clib_host_to_net_u16(ETHERNET_TYPE_VLAN)) { 
261             l3_type = (etype + 1); /* Skip 2 bytes of vlan id */  
262             vlib_buffer_advance(b0, 18);
263           } else {
264             l3_type = etype;
265             vlib_buffer_advance(b0, 14);
266           }
267           /* Handling v4 pkts 0x800 */
268           if (*l3_type == clib_host_to_net_u16(ETHERNET_TYPE_IP4)) {  
269           
270               h0 = vlib_buffer_get_current (b0);
271
272               u8 protocol_type = h0->protocol;
273
274               sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
275               next0 = VCGN_CLASSIFY_NEXT_IP4_INPUT;
276               counter = VCGN_CLASSIFY_ERROR_V4_PACKETS_PROCESSED;
277
278               if (protocol_type == 0x11) { /* UDP# 17 */
279                   next0 = (sw_if_index0 < vec_len(vcm->inside_sw_if_index_table) &&
280                     vcm->inside_sw_if_index_table[sw_if_index0] != EMPTY) ?
281                         VCGN_CLASSIFY_NEXT_UDP_INSIDE : next0;
282
283                   next0 = (sw_if_index0 < vec_len(vcm->outside_sw_if_index_table) &&
284                     vcm->outside_sw_if_index_table[sw_if_index0] != EMPTY) ?
285                         VCGN_CLASSIFY_NEXT_UDP_OUTSIDE : next0;
286
287               } else if (protocol_type == 0x06) { /* TCP# 6 */
288                   next0 = (sw_if_index0 < vec_len(vcm->inside_sw_if_index_table) &&
289                     vcm->inside_sw_if_index_table[sw_if_index0] != EMPTY) ?
290                         VCGN_CLASSIFY_NEXT_TCP_INSIDE : next0;
291
292                   next0 = (sw_if_index0 < vec_len(vcm->outside_sw_if_index_table) &&
293                     vcm->outside_sw_if_index_table[sw_if_index0] != EMPTY) ?
294                         VCGN_CLASSIFY_NEXT_TCP_OUTSIDE : next0;
295
296               } else if (protocol_type == 0x01) { /* ICMP # 1 */
297
298                   ipv4_hdr_len = (h0->ip_version_and_header_length & 0xf) << 2;
299                   icmp = (icmp_v4_t *)((u8*)h0 + ipv4_hdr_len);
300                   icmp_type = icmp->type;
301
302                   if ((icmp_type == ICMPV4_ECHO) || 
303                           (icmp_type == ICMPV4_ECHOREPLY)) {
304                       next0 = (sw_if_index0 < vec_len(vcm->inside_sw_if_index_table) &&
305                         vcm->inside_sw_if_index_table[sw_if_index0] != EMPTY) ?
306                             VCGN_CLASSIFY_NEXT_ICMP_Q_INSIDE : next0;
307
308                       next0 = (sw_if_index0 < vec_len(vcm->outside_sw_if_index_table) &&
309                         vcm->outside_sw_if_index_table[sw_if_index0] != EMPTY) ?
310                             VCGN_CLASSIFY_NEXT_ICMP_Q_OUTSIDE : next0;
311
312                   } else {
313                       next0 = (sw_if_index0 < vec_len(vcm->inside_sw_if_index_table) &&
314                         vcm->inside_sw_if_index_table[sw_if_index0] != EMPTY) ?
315                             VCGN_CLASSIFY_NEXT_ICMP_E_INSIDE : next0;
316
317                       next0 = (sw_if_index0 < vec_len(vcm->outside_sw_if_index_table) &&
318                         vcm->outside_sw_if_index_table[sw_if_index0] != EMPTY) ?
319                             VCGN_CLASSIFY_NEXT_ICMP_E_OUTSIDE : next0;
320                   }
321               } else {
322                  /* cannot do NATting with this L4 protocol */
323                   counter = VCGN_CLASSIFY_ERROR_V4_PACKETS_PUNTED;
324               }
325
326               if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE) 
327                           && (b0->flags & VLIB_BUFFER_IS_TRACED))) {
328                   udp_header_t * u0 = (udp_header_t *)(h0+1);
329                   vcgn_classify_trace_t *t = 
330                       vlib_add_trace (vm, node, b0, sizeof (*t));
331                   t->sw_if_index = sw_if_index0;
332                   t->next_index = next0;
333                   t->orig_dst_address = h0->dst_address.as_u32;
334                   t->orig_dst_port = u0->dst_port;
335               }
336
337           } else if (*l3_type == clib_host_to_net_u16(ETHERNET_TYPE_IP6)) { 
338
339                 /* IPv6 0x86DD */
340                 next0 = VCGN_CLASSIFY_NEXT_IP6_INPUT;
341                 counter = VCGN_CLASSIFY_ERROR_V6_PACKETS_PUNTED;
342
343             } else if (*l3_type == 
344                 clib_host_to_net_u16(ETHERNET_TYPE_MPLS_UNICAST)) { 
345
346                 /* MPLS unicast 0x8847 */
347                 next0 = VCGN_CLASSIFY_NEXT_MPLS_INPUT;
348                 counter = VCGN_CLASSIFY_ERROR_MPLS_PACKETS_PUNTED;
349           } else { /* Remaining all should be pushed to "ethernet-input" */
350
351                 next0 = VCGN_CLASSIFY_NEXT_ETHERNET_INPUT;
352                 counter = VCGN_CLASSIFY_ERROR_ETH_PACKETS_PUNTED;
353           }
354
355           em->counters[node_counter_base_index + counter] += 1;
356           em->counters[node_counter_base_index + 
357                     VCGN_CLASSIFY_ERROR_PACKETS_RECEIVED] += 1;
358
359           /* verify speculative enqueue, maybe switch current next frame */
360           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
361                                            to_next, n_left_to_next,
362                                            bi0, next0);
363         }
364
365       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
366     }
367
368   return frame->n_vectors;
369 }
370
371 VLIB_REGISTER_NODE (vcgn_classify_node) = {
372   .function = vcgn_classify_node_fn,
373   .name = "vcgn-classify",
374   .vector_size = sizeof (u32),
375   .format_trace = format_swap_trace,
376   .type = VLIB_NODE_TYPE_INTERNAL,
377   
378   .n_errors = ARRAY_LEN(vcgn_classify_error_strings),
379   .error_strings = vcgn_classify_error_strings,
380
381   .n_next_nodes = VCGN_CLASSIFY_N_NEXT,
382
383   /* edit / add dispositions here */
384   .next_nodes = {
385     [VCGN_CLASSIFY_NEXT_IP4_INPUT]      = "ip4-input",
386     [VCGN_CLASSIFY_NEXT_IP6_INPUT]      = "ip6-input",
387     [VCGN_CLASSIFY_NEXT_MPLS_INPUT]     = "mpls-gre-input",
388     [VCGN_CLASSIFY_NEXT_ETHERNET_INPUT] = "ethernet-input",
389         [VCGN_CLASSIFY_NEXT_UDP_INSIDE]     = "vcgn-v4-udp-i2o",
390         [VCGN_CLASSIFY_NEXT_UDP_OUTSIDE]    = "vcgn-v4-udp-o2i",
391         [VCGN_CLASSIFY_NEXT_TCP_INSIDE]     = "vcgn-v4-tcp-i2o",
392         [VCGN_CLASSIFY_NEXT_TCP_OUTSIDE]    = "vcgn-v4-tcp-o2i",
393         [VCGN_CLASSIFY_NEXT_ICMP_Q_INSIDE]  = "vcgn-v4-icmp-q-i2o",
394         [VCGN_CLASSIFY_NEXT_ICMP_Q_OUTSIDE] = "vcgn-v4-icmp-q-o2i",
395         [VCGN_CLASSIFY_NEXT_ICMP_E_INSIDE]  = "vcgn-v4-icmp-e-i2o",
396         [VCGN_CLASSIFY_NEXT_ICMP_E_OUTSIDE] = "vcgn-v4-icmp-e-o2i"
397   },
398 };
399
400
401 /* A test function to init the vrf map */
402
403 clib_error_t *vcgn_classify_init (vlib_main_t *vm)
404 {
405   vcgn_classify_main_t * mp = &vcgn_classify_main;
406     
407   mp->vlib_main = vm;
408   mp->vnet_main = vnet_get_main();
409   u32 inside_sw_if_index = 1;
410   u32 outside_sw_if_index = 0;
411
412   vec_validate_init_empty (mp->inside_sw_if_index_table,
413     inside_sw_if_index + 1, EMPTY);
414   vec_validate_init_empty (mp->outside_sw_if_index_table,
415     outside_sw_if_index + 1, EMPTY);
416
417   /*
418    * inside_sw_if_index cell of the table stores outside_sw_if_index
419    * and vice versa. This is ensurs pair of indices being remembered
420    * using one mem-location.
421    */
422   mp->inside_sw_if_index_table[inside_sw_if_index] = outside_sw_if_index;
423   mp->outside_sw_if_index_table[outside_sw_if_index] = inside_sw_if_index;
424
425 #if DPDK==1
426   dpdk_set_next_node (DPDK_RX_NEXT_IP4_INPUT, "vcgn-classify");
427 #endif
428
429   {
430     pg_node_t * pn;
431     pn = pg_get_node (vcgn_classify_node.index);
432     pn->unformat_edit = unformat_pg_ip4_header;
433   }
434   return 0;
435 }
436
437 VLIB_INIT_FUNCTION (vcgn_classify_init);
438
439 /* Show command handlers */
440 static clib_error_t *
441 show_vcgn_stats_command_fn (vlib_main_t * vm,
442                          unformat_input_t * input,
443                          vlib_cli_command_t * cmd)
444 {
445     if (cnat_db_init_done) {
446         cnat_nat44_handle_show_stats(vm);
447     } else {
448         vlib_cli_output(vm, "vCGN is not configured !!\n");
449     }
450     return 0;
451 }
452
453
454 static clib_error_t *
455 show_vcgn_config_command_fn (vlib_main_t * vm,
456                          unformat_input_t * input,
457                          vlib_cli_command_t * cmd)
458 {
459   cnat_nat44_handle_show_config(vm);
460   return 0;
461 }
462
463 static clib_error_t *
464 show_vcgn_inside_translation_command_fn (vlib_main_t * vm,
465                          unformat_input_t * input,
466                          vlib_cli_command_t * cmd)
467 {
468     vnet_main_t * vnm = vnet_get_main();
469     vcgn_classify_main_t * vcm = &vcgn_classify_main;
470     spp_api_cnat_v4_show_inside_entry_req_t inside_req;
471     u8 *proto; 
472     ip4_address_t inside_addr;
473     u32 start_port = 1;
474     u32 end_port = 65535;
475     u32 inside_sw_if_index = EMPTY;
476     
477     inside_req.start_port = start_port;
478     inside_req.end_port = end_port;
479     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
480         if (unformat(input, "protocol %s", &proto)) { 
481             if (!strncmp((char *) proto, "udp", 3)) {
482                 inside_req.protocol = 1;
483             } else if (!strncmp((char *) proto, "tcp", 3)) {
484                 inside_req.protocol = 2;
485             } else {
486                 inside_req.protocol = 3;
487             } 
488         } else if (unformat (input, "interface %U", 
489                     unformat_vnet_sw_interface, vnm, &inside_sw_if_index)) {
490             if (inside_sw_if_index > vec_len(vcm->inside_sw_if_index_table) ||
491                 vcm->inside_sw_if_index_table[inside_sw_if_index] == EMPTY) {
492                     return clib_error_return (0, "Could not find the inside interface");
493             }
494         } else if (unformat (input, "inside-addr %U", 
495                        unformat_ip4_address, &inside_addr)) {
496             inside_req.ipv4_addr = clib_net_to_host_u32(inside_addr.as_u32); 
497         } else if (unformat(input, "start-port %u", &start_port)) {
498             inside_req.start_port = start_port;
499         } else if (unformat(input, "end-port %u", &end_port)) {
500             inside_req.end_port = end_port;
501         } else { break;}
502     }
503     inside_req.vrf_id = inside_sw_if_index;
504     inside_req.flags |= CNAT_TRANSLATION_ENTRY_DYNAMIC; /* as of now only dynamic */  
505     inside_req.all_entries = 0; /* we can see it later */
506 #if DEBUG
507     vlib_cli_output(vm, "proto %d, inside-addr 0x%x, start_port %u, "
508                 "end_port %u, vrf 0x%x\n",
509                 inside_req.protocol, 
510                 inside_req.ipv4_addr,
511                 inside_req.start_port,
512                 inside_req.end_port,
513                 inside_sw_if_index);
514 #endif
515     if (cnat_db_init_done) {
516         cnat_v4_show_inside_entry_req_t_handler(&inside_req, vm);
517     } else {
518         vlib_cli_output(vm, "vCGN is not configured !!\n");
519     }
520     return 0;
521 }
522
523
524 static clib_error_t *
525 show_vcgn_outside_translation_command_fn (vlib_main_t * vm,
526                          unformat_input_t * input,
527                          vlib_cli_command_t * cmd)
528 {
529     void cnat_v4_show_outside_entry_req_t_handler
530         (spp_api_cnat_v4_show_outside_entry_req_t *mp, vlib_main_t *vm);
531     vnet_main_t * vnm = vnet_get_main();
532     vcgn_classify_main_t * vcm = &vcgn_classify_main;
533     spp_api_cnat_v4_show_outside_entry_req_t outside_req;
534     u8 *proto; 
535     ip4_address_t outside_addr;
536     u32 start_port = 1;
537     u32 end_port = 65535;
538     u32 outside_sw_if_index = EMPTY;
539     
540     
541     outside_req.start_port = start_port;
542     outside_req.end_port = end_port;
543     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
544         if (unformat(input, "protocol %s", &proto)) { 
545             if (!strncmp((char *) proto, "udp", 3)) {
546                 outside_req.protocol = 1;
547             } else if (!strncmp((char *) proto, "tcp", 3)) {
548                 outside_req.protocol = 2;
549             } else {
550                 outside_req.protocol = 3;
551             } 
552         } else if (unformat (input, "interface %U", 
553             unformat_vnet_sw_interface, vnm, &outside_sw_if_index)) {
554             if (outside_sw_if_index > vec_len(vcm->outside_sw_if_index_table) ||
555                 vcm->outside_sw_if_index_table[outside_sw_if_index] == EMPTY) {
556                     return clib_error_return (0, "Could not find the outside interface");
557             }
558         } else if (unformat (input, "outside-addr %U", 
559                        unformat_ip4_address, &outside_addr)) {
560             outside_req.ipv4_addr = clib_net_to_host_u32(outside_addr.as_u32); 
561         } else if (unformat(input, "start-port %u", &start_port)) {
562             outside_req.start_port = start_port;
563         } else if (unformat(input, "end-port %u", &end_port)) {
564             outside_req.end_port = end_port;
565         } else { break;}
566     }
567     outside_req.vrf_id = outside_sw_if_index;
568     outside_req.flags |= CNAT_TRANSLATION_ENTRY_DYNAMIC; /* as of now only dynamic */  
569 #if DEBUG
570     vlib_cli_output(vm, "proto %d, outside-addr 0x%x, start_port %u, "
571                 "end_port %u, vrf 0x%x\n",
572                 outside_req.protocol, 
573                 outside_req.ipv4_addr,
574                 outside_req.start_port,
575                 outside_req.end_port,
576                 outside_sw_if_index);
577 #endif
578     if (cnat_db_init_done) {
579         cnat_v4_show_outside_entry_req_t_handler(&outside_req, vm);
580     } else {
581         vlib_cli_output(vm, "vCGN is not configured !!\n");
582     }
583     return 0;
584 }
585
586
587 /* Config command handlers */
588 static clib_error_t *
589 set_vcgn_inside_command_fn (vlib_main_t * vm,
590                             unformat_input_t * input,
591                             vlib_cli_command_t * cmd)
592 {
593   vnet_main_t * vnm = vnet_get_main();
594   vcgn_classify_main_t * vcm = &vcgn_classify_main;
595   u32 inside_sw_if_index = 1;
596   u32 outside_sw_if_index = ~0;
597   void cnat_db_v2_init (void );
598
599     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
600       if (unformat(input, "%U", 
601                    unformat_vnet_sw_interface, vnm, &inside_sw_if_index))
602     ;
603       else if (unformat(input, "outside %U", 
604                    unformat_vnet_sw_interface, vnm, &outside_sw_if_index))
605         ; 
606       else break;
607     }
608     if (inside_sw_if_index == ~0 ||
609         outside_sw_if_index == ~0)
610       return clib_error_return (0, "unknown input `%U'",
611                                 format_unformat_error, input);
612
613     if (inside_sw_if_index == outside_sw_if_index)
614       return clib_error_return (0, "inside and outside interfaces can't be the same...");
615
616     /*
617      * Initialize in/out sw_if_index table. Could use
618      * non-indexed table to reduce memory. However, this
619      * is consulted in vcgn_classify for every packet.
620      * Therefore, table is indexed by sw_if_index.
621      */
622     vec_validate_init_empty (vcm->inside_sw_if_index_table,
623         inside_sw_if_index + 1, EMPTY);
624     vec_validate_init_empty (vcm->outside_sw_if_index_table,
625         outside_sw_if_index + 1, EMPTY);
626
627     /*
628      * inside_sw_if_index cell of the table stores outside_sw_if_index
629      * and vice versa. This is ensurs pair of indices being remembered
630      * using one mem-location.
631      */
632     vcm->inside_sw_if_index_table[inside_sw_if_index] = outside_sw_if_index;
633     vcm->outside_sw_if_index_table[outside_sw_if_index] = inside_sw_if_index;
634
635     if (! vcm->cnat_db_initalized) {
636         int i;
637         cnat_db_v2_init();
638         
639         for (i = 0; i < CNAT_MAX_VRFMAP_ENTRIES; i++) {
640             vrf_map_array[i] = VRF_MAP_ENTRY_EMPTY;
641         }
642         /* Turn on the db scanner process */
643         cnat_scanner_db_process_turn_on(vm);
644         vcm->cnat_db_initalized = 1;
645     }
646     return 0;
647 }
648
649 static clib_error_t *
650 set_vcgn_map_command_fn (vlib_main_t * vm,
651                          unformat_input_t * input,
652                          vlib_cli_command_t * cmd)
653 {
654   vnet_main_t * vnm = vnet_get_main();
655   vcgn_classify_main_t * vcm = &vcgn_classify_main;
656   ip4_address_t lo, hi;
657   spp_api_cnat_v4_add_vrf_map_t map;
658   u32 inside_sw_if_index = EMPTY;
659   u32 outside_sw_if_index;
660
661   vnet_hw_interface_t *inside_hw_if_index = NULL;
662   vnet_hw_interface_t *outside_hw_if_index = NULL;
663
664   if (! unformat(input, "inside %U", 
665        unformat_vnet_sw_interface, vnm, &inside_sw_if_index))
666     return clib_error_return (0, "unknown input `%U'",
667                   format_unformat_error, input);
668
669   if (!unformat (input, "%U", unformat_ip4_address, &lo))
670     return clib_error_return (0, "unknown input `%U'",
671                               format_unformat_error, input);
672
673   if (unformat (input, "- %U", unformat_ip4_address, &hi))
674     ;
675
676   /* $$$$ remember to set i_vrf, i_vrf_id as needed */
677
678   /* Fill the structure spp_api_cnat_v4_add_vrf_map_t & let this API handle it */
679   /* i_vrf_id & o_vrf_id are 32-bit & i_vrf, o_vrf are 16 bit */
680
681   if (inside_sw_if_index > vec_len(vcm->inside_sw_if_index_table) ||
682     vcm->inside_sw_if_index_table[inside_sw_if_index] == EMPTY) {
683       return clib_error_return (0, "Could not find the inside interface");
684   }
685   outside_sw_if_index = vcm->inside_sw_if_index_table[inside_sw_if_index];
686
687   map.i_vrf_id = inside_sw_if_index; 
688   map.o_vrf_id = outside_sw_if_index; 
689   map.i_vrf    = inside_sw_if_index;
690   map.o_vrf    = outside_sw_if_index;
691
692   map.start_addr[0] = clib_net_to_host_u32(lo.as_u32); 
693   map.end_addr[0]   = clib_net_to_host_u32(hi.as_u32); 
694
695   cnat_nat44_add_vrf_map_t_handler(&map, vm);
696
697 #if 1
698   inside_hw_if_index = vnet_get_sup_hw_interface(vcm->vnet_main, inside_sw_if_index);
699   if (inside_hw_if_index) {
700     vnet_hw_interface_rx_redirect_to_node(vcm->vnet_main, 
701             inside_hw_if_index->hw_if_index, vcgn_classify_node.index);
702   }
703   outside_hw_if_index = vnet_get_sup_hw_interface(vcm->vnet_main, outside_sw_if_index);
704   if (outside_hw_if_index) {
705     vnet_hw_interface_rx_redirect_to_node(vcm->vnet_main, 
706             outside_hw_if_index->hw_if_index, vcgn_classify_node.index);
707   }
708 #endif
709   return 0;
710 }
711
712 static clib_error_t *
713 set_vcgn_tcp_timeout_command_fn (vlib_main_t * vm,
714                             unformat_input_t * input,
715                             vlib_cli_command_t * cmd)
716 {
717   /*
718   vnet_main_t * vnm = vnet_get_main();
719   vcgn_classify_main_t * vcm = &vcgn_classify_main;
720   */
721   u32 act_timeout = 0;
722   u32 init_timeout = 0;
723
724     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
725         if (unformat(input, "active %u", &act_timeout)) 
726             tcp_active_timeout = act_timeout;
727         else if (unformat(input, "init %u", &init_timeout)) 
728             tcp_initial_setup_timeout = init_timeout; 
729         else break;
730     }
731     return 0;
732 }
733
734 static clib_error_t *
735 set_vcgn_udp_timeout_command_fn (vlib_main_t * vm,
736                             unformat_input_t * input,
737                             vlib_cli_command_t * cmd)
738 {
739   /*
740   vnet_main_t * vnm = vnet_get_main();
741   vcgn_classify_main_t * vcm = &vcgn_classify_main;
742   */
743   u32 act_timeout = 0;
744   u32 init_timeout = 0;
745
746     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
747         if (unformat(input, "active %u", &act_timeout)) 
748             udp_act_session_timeout = act_timeout;
749         else if (unformat(input, "init %u", &init_timeout)) 
750             udp_init_session_timeout = init_timeout; 
751         else break;
752     }
753     return 0;
754 }
755
756
757 static clib_error_t *
758 set_vcgn_icmp_timeout_command_fn (vlib_main_t * vm,
759                             unformat_input_t * input,
760                             vlib_cli_command_t * cmd)
761 {
762   /* 
763    * vnet_main_t * vnm = vnet_get_main(); 
764    * vcgn_classify_main_t * vcm = &vcgn_classify_main;
765    */
766   u32 timeout = 0;
767
768     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
769         if (unformat(input, "%u", &timeout)) 
770             ; 
771         else break;
772     }
773     icmp_session_timeout = timeout;
774     return 0;
775 }
776
777
778 static clib_error_t *
779 set_vcgn_protocol_default_timeout_command_fn (vlib_main_t * vm,
780                             unformat_input_t * input,
781                             vlib_cli_command_t * cmd)
782 {
783     /*
784     vnet_main_t * vnm = vnet_get_main();
785     vcgn_classify_main_t * vcm = &vcgn_classify_main;
786     */
787     u8 *protocol;
788     u8 reset = 1; 
789
790     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
791       if (unformat(input, "%s", &protocol)) 
792         ;
793       else break;
794     }
795     cnat_nat44_set_protocol_timeout_value(0, 0, protocol, reset, vm);
796     return 0;
797 }
798
799 static clib_error_t *
800 set_vcgn_dynamic_port_start_range_command_fn (vlib_main_t * vm,
801                             unformat_input_t * input,
802                             vlib_cli_command_t * cmd)
803 {
804     /*
805     vnet_main_t * vnm = vnet_get_main();
806     vcgn_classify_main_t * vcm = &vcgn_classify_main;
807     */
808     u32 port = 0;
809
810     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
811       if (unformat(input, "%u", &port)) 
812         ;
813       else break;
814     }
815     if (port != 0 && port > 65535) {
816         vlib_cli_output(vm, "Error !! Invalid port\n");
817     } else {
818         cnat_static_port_range = port;
819         vlib_cli_output(vm, "Dynamic Port Range Config Successful !!\n");
820     }
821     return 0;
822 }
823
824 static clib_error_t *
825 set_vcgn_port_limit_command_fn (vlib_main_t * vm,
826                             unformat_input_t * input,
827                             vlib_cli_command_t * cmd)
828 {
829     /*
830     vnet_main_t * vnm = vnet_get_main();
831     vcgn_classify_main_t * vcm = &vcgn_classify_main;
832     */
833     u32 port = 0;
834
835     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
836       if (unformat(input, "%u", &port)) 
837         ;
838       else break;
839     }
840     if (port != 0 && port > 65535) {
841         vlib_cli_output(vm, "Error !! Invalid port\n");
842     } else {
843         cnat_main_db_max_ports_per_user = port;
844         vlib_cli_output(vm, "Port Limit Config Successful !!\n");
845     }
846     return 0;
847 }
848
849 static inline void nfv9_init_pkt_sent_data(cnat_nfv9_logging_info_t *nfv9_info)
850 {
851     nfv9_server_info_t *server = nfv9_server_info_pool +
852         nfv9_info->server_index;
853
854         /*
855          * Reset the pkts_since_last_template and sent_time
856          * so that template will be sent next time
857          */
858         server->last_template_sent_time  = 0;
859         server->pkts_since_last_template = 0xffffffff;
860 }
861
862 static inline u16 nfv9_get_max_length_minus_max_record_size(u16 path_mtu)
863 {
864     u16 max_length_minus_max_record_size;
865     if(!path_mtu) /* Use default */
866         path_mtu = NFV9_DEF_PATH_MTU;
867
868     max_length_minus_max_record_size = path_mtu -
869         CNAT_NFV9_DATAFLOW_RECORD_HEADER_LENGTH -
870         NFV9_PAD_VALUE -
871         CNAT_NFV9_MAX_SINGLE_RECORD_LENGTH; /* Note.. as of now this record
872             * requires max number of bytes. If you add more records,
873             * this needs to be re-checked */
874         if (max_length_minus_max_record_size < CNAT_NFV9_MIN_RECORD_SIZE) {
875             max_length_minus_max_record_size = CNAT_NFV9_MIN_RECORD_SIZE;
876         }
877    return max_length_minus_max_record_size;
878 }
879
880 /* This function finds if the netflow server indicated by
881  * new_server_info is already configured for some other instance
882  * if yes, it returns the same pointer so that, info sent to the
883  * server is consistent. If the server is not found, a new instance
884  * is created and returned. If an existing server is used, its refernce
885  * count is incrimented (indicating the number of instances using the
886  * same server
887  */
888  /* #define DEBUG_NF_SERVER_CONFIG 1 */
889 static u16 nfv9_get_server_instance(
890     cnat_nfv9_logging_info_t *nfv9_info, nfv9_server_info_t *new_server_info)
891 {
892
893     /* Check if the instance has a server already and if yes, does it match */
894     nfv9_server_info_t *server;
895     if(nfv9_info->server_index != EMPTY) {
896         server =  nfv9_server_info_pool + nfv9_info->server_index;
897
898         if((server->ipv4_address == new_server_info->ipv4_address) &&
899             (server->port == new_server_info->port)) {
900             /* Same server.. just check if refresh rate/timeouts are reduced */
901 #ifdef DEBUG_NF_SERVER_CONFIG
902             if(my_instance_number == 1) {
903             printf("\n Server match for %x and port %d\n",
904                 new_server_info->ipv4_address, new_server_info->port);
905             }
906 #endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
907             goto adjust_refresh_rate;
908         } else { /* The server is being changed */
909             server->ref_count--;
910 #ifdef DEBUG_NF_SERVER_CONFIG
911             if(my_instance_number == 1) {
912             printf("\n Server change from %x, %d to %x, %d"
913                 "Ref count %d\n",
914                 server->ipv4_address,
915                 server->port,
916                 new_server_info->ipv4_address, new_server_info->port,
917                 server->ref_count);
918             }
919 #endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
920             if(!server->ref_count) {
921                 /* Return this server to pool */
922 #ifdef DEBUG_NF_SERVER_CONFIG
923                 if(my_instance_number == 1) {
924                     PLATFORM_DEBUG_PRINT("Deleting Server %x, %d at %d\n",
925                     server->ipv4_address,
926                     server->port,
927                     nfv9_info->server_index);
928                 }
929 #endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
930                 pool_put(nfv9_server_info_pool, server);
931             }
932         }
933     }
934
935     /* Now check if the server is already present in the pool */
936     u8 found = 0;
937     server = 0;
938     pool_foreach (server, nfv9_server_info_pool, ({
939         if ((server->ipv4_address == new_server_info->ipv4_address) &&
940             (server->port == new_server_info->port)) {
941             server->ref_count++;
942             nfv9_info->server_index = server - nfv9_server_info_pool;
943             found = 1;
944 #ifdef DEBUG_NF_SERVER_CONFIG
945             if(my_instance_number == 1) {
946             printf("Re-using server %x, %d Ref count %d\n",
947             server->ipv4_address, server->port, server->ref_count);
948             }
949 #endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
950             break;
951         }
952     }));
953
954     if(!found) {
955         /* Create a new one, initialize and return */
956         server = 0;
957         pool_get(nfv9_server_info_pool, server);
958         clib_memcpy(server, new_server_info, sizeof(nfv9_server_info_t));
959         server->ref_count = 1;
960         nfv9_info->server_index = server - nfv9_server_info_pool;
961 #ifdef DEBUG_NF_SERVER_CONFIG
962         if(my_instance_number == 1) {
963         printf("Create new server for at %d %x and port %d\n",
964                 nfv9_info->server_index,
965                 new_server_info->ipv4_address, new_server_info->port);
966         }
967 #endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
968         return CNAT_SUCCESS;
969     }
970
971 adjust_refresh_rate:
972     if(server->refresh_rate >
973         new_server_info->refresh_rate) {
974         server->refresh_rate =
975             new_server_info->refresh_rate;
976 #ifdef DEBUG_NF_SERVER_CONFIG
977         if(my_instance_number == 1) {
978         printf("Reset refresh rate to %d\n",
979             server->refresh_rate);
980         }
981 #endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
982     }
983
984     if(server->timeout_rate >
985         new_server_info->timeout_rate) {
986         server->timeout_rate =
987         new_server_info->timeout_rate;
988 #ifdef DEBUG_NF_SERVER_CONFIG
989         if(my_instance_number == 1) {
990             printf("Reset timeout rate to %d\n",
991             server->timeout_rate);
992         }
993 #endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
994     }
995
996     return CNAT_SUCCESS;
997 }
998 static clib_error_t *
999 set_vcgn_nfv9_logging_cofig_command_fn (vlib_main_t * vm,
1000                             unformat_input_t * input,
1001                             vlib_cli_command_t * cmd)
1002 {
1003     vcgn_classify_main_t * vcm = &vcgn_classify_main;
1004     spp_api_cnat_v4_config_nfv9_logging_t nfv9_conf;
1005     ip4_address_t server_addr;
1006     u32 ip_addr = 0;
1007     u32 port;
1008     u32 refresh_rate = 0;
1009     u32 timeout = 0;
1010     u32 pmtu = 0;
1011     u8 enable = 1;
1012 /* vcgn changes start*/
1013     cnat_nfv9_logging_info_t *my_nfv9_logging_info = NULL;
1014     cnat_nfv9_logging_info_t *my_nfv9_logging_info_tmp = NULL;
1015     cnat_vrfmap_t *my_vrfmap = 0, *my_vrfmap_temp = 0; 
1016     u16           i_vrf = ~0;
1017     u32           i_vrf_id = ~0;
1018     u8            found;
1019     u32 inside_sw_if_index = EMPTY;
1020     /*
1021      * Init NFv9 logging info as needed, this will be done only once
1022      */
1023     cnat_nfv9_logging_init();
1024
1025     found = 0;
1026   
1027 /* vcgn changes end*/
1028     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
1029         if (unformat (input, "inside %U", 
1030                unformat_vnet_sw_interface, &inside_sw_if_index)) {
1031             /* Do nothing */
1032         } else if (unformat (input, "server %U", unformat_ip4_address, &server_addr))
1033             ip_addr = clib_net_to_host_u32(server_addr.as_u32);
1034         else if (unformat(input, "port %u", &port)) 
1035         ;
1036         else if (unformat(input, "refresh-rate %u", &refresh_rate)) 
1037         ;
1038         else if (unformat(input, "timeout %u", &timeout)) 
1039         ;
1040         else if (unformat(input, "pmtu %u", &pmtu)) 
1041         ;
1042         else if (unformat(input, "del")) 
1043             enable = 0;
1044         else break;
1045     }
1046
1047     if (inside_sw_if_index > vec_len(vcm->inside_sw_if_index_table) ||
1048         vcm->inside_sw_if_index_table[inside_sw_if_index] == EMPTY) {
1049             return clib_error_return (0, "Could not find the inside interface");
1050     }
1051     i_vrf    = inside_sw_if_index;
1052     i_vrf_id = inside_sw_if_index; 
1053
1054     #if 0
1055     vlib_cli_output(vm, "ip 0x%x, port %u, refresh %u, "
1056                     "timeout %u, pmtu %u enable %u\n",
1057                     ip_addr, port, refresh_rate, 
1058                     timeout, pmtu, enable);
1059     #endif
1060     if (refresh_rate == 0) refresh_rate = 500; /* num of pkts */
1061     if (timeout == 0) timeout = 30;  /* in mins */
1062
1063     nfv9_conf.enable = enable;
1064     nfv9_conf.ipv4_address = ip_addr;
1065     nfv9_conf.i_vrf_id = inside_sw_if_index;
1066     nfv9_conf.i_vrf = inside_sw_if_index;
1067     nfv9_conf.port = port;
1068     nfv9_conf.refresh_rate = refresh_rate;
1069     nfv9_conf.timeout_rate = timeout;
1070     nfv9_conf.path_mtu = pmtu;
1071     nfv9_conf.nfv9_global_collector = 0;
1072     nfv9_conf.session_logging = 0;
1073
1074     /*
1075      * At this point the NFv9 global information should already be
1076      * inited as we have called cnat_nfv9_logging_init()
1077      */
1078
1079     if (nfv9_conf.nfv9_global_collector) {
1080         if (cnat_nfv9_global_info.cnat_nfv9_global_collector_index != EMPTY) {
1081             found = 1;
1082             my_nfv9_logging_info = cnat_nfv9_logging_info_pool +
1083                     cnat_nfv9_global_info.cnat_nfv9_global_collector_index;
1084         }
1085     } else {
1086         /* Do we already have a map for this VRF? */
1087         pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info_pool, ({
1088               if (my_nfv9_logging_info->i_vrf_id == i_vrf_id) {
1089                   nfv9_server_info_t *server =  nfv9_server_info_pool +
1090                       my_nfv9_logging_info->server_index;
1091                   if((server->ipv4_address ==  (nfv9_conf.ipv4_address)) && (server->port == (nfv9_conf.port))) {
1092                       found = 1;
1093                       my_nfv9_logging_info_tmp = my_nfv9_logging_info;
1094                       break;
1095                   }
1096               }
1097           }));
1098     }
1099
1100     if ((nfv9_conf.ipv4_address == 0) ||
1101         (nfv9_conf.port == 0)) {
1102         vlib_cli_output(vm,
1103             "Add NFv9 ivrf %d Logging Invalid values [IPv4 0x%x, PORT %d]\n",
1104                 i_vrf,
1105                 (nfv9_conf.ipv4_address),
1106                 (nfv9_conf.port));
1107          goto done;    
1108     }
1109
1110     if (nfv9_conf.enable) {
1111         if ((nfv9_conf.ipv4_address == 0) ||
1112               (nfv9_conf.port == 0)) {
1113               nfv9_conf.rc = CNAT_ERR_PARSER;
1114               vlib_cli_output(vm,
1115                   "NFV9_logging i_vrf %d, Invalid [v4_addr 0x%x port %d]\n",
1116                   i_vrf,
1117                   (nfv9_conf.ipv4_address),
1118                   (nfv9_conf.port));
1119               goto done;    
1120         }
1121
1122         nfv9_server_info_t new_server_info;
1123         memset(&new_server_info, 0, sizeof(nfv9_server_info_t));
1124         new_server_info.ipv4_address =
1125                 nfv9_conf.ipv4_address;
1126         new_server_info.port =
1127                 (nfv9_conf.port);
1128         new_server_info.refresh_rate =
1129             (nfv9_conf.refresh_rate);
1130         /*
1131          * Store the timeout in seconds.  User configures it in minutes
1132          */
1133         new_server_info.timeout_rate =
1134             60*(nfv9_conf.timeout_rate);
1135         if (found && my_nfv9_logging_info) {
1136             /*
1137              * Entry already present, change it
1138              */
1139             my_nfv9_logging_info->max_length_minus_max_record_size =
1140                 nfv9_get_max_length_minus_max_record_size(
1141                     ((nfv9_conf.path_mtu)));
1142         } else {
1143             pool_get(cnat_nfv9_logging_info_pool, my_nfv9_logging_info);
1144             memset(my_nfv9_logging_info, 0, sizeof(*my_nfv9_logging_info));
1145             my_nfv9_logging_info->server_index = EMPTY;
1146             my_nfv9_logging_info->nfv9_logging_next_index = EMPTY;
1147             /*
1148              * Make the current and head logging context indeices as EMPTY.
1149              * When first logging happens, these get set correctly
1150              */
1151             my_nfv9_logging_info->current_logging_context = NULL;
1152             my_nfv9_logging_info->queued_logging_context  = NULL;
1153 #if 0
1154             my_nfv9_logging_info->f  = NULL;
1155             my_nfv9_logging_info->to_next  = NULL;
1156             output_node =  vlib_get_node_by_name (vm, (u8 *) "ip4-input");
1157             my_nfv9_logging_info->ip4_input_node_index = output_node->index;
1158             printf("ip4_input_node_index %d\n", my_nfv9_logging_info->ip4_input_node_index);
1159 #endif
1160             my_nfv9_logging_info->i_vrf    = i_vrf;
1161             my_nfv9_logging_info->i_vrf_id = i_vrf_id;
1162             my_nfv9_logging_info->max_length_minus_max_record_size =
1163             nfv9_get_max_length_minus_max_record_size(
1164                     nfv9_conf.path_mtu);
1165
1166          /* my_nfv9_logging_info will have a copy of logging_policy
1167           * because, it is quite possible that nfv9 config arrives before
1168           * the corresponding vrfmap is initialized. In such cases
1169           * this copy will be used to update the vrfmap entry
1170           */
1171             my_nfv9_logging_info->logging_policy = nfv9_conf.session_logging;
1172
1173             if (nfv9_conf.nfv9_global_collector) {
1174                 cnat_nfv9_global_info.cnat_nfv9_global_collector_index =
1175                     my_nfv9_logging_info - cnat_nfv9_logging_info_pool;
1176
1177                 pool_foreach (my_vrfmap, cnat_map_by_vrf, ({
1178                             if (my_vrfmap->nfv9_logging_index == EMPTY) {
1179                                 my_vrfmap->nfv9_logging_index =
1180                                     cnat_nfv9_global_info.cnat_nfv9_global_collector_index;
1181                             }
1182                         }));
1183             } else {
1184                 u32 my_vrfmap_found = 0;
1185
1186                 FIND_MY_VRF_USING_I_VRF_ID
1187                 my_vrfmap = my_vrfmap_temp;
1188                     if (my_vrfmap_found) {
1189                         if(my_vrfmap->nfv9_logging_index == EMPTY) {
1190                             my_vrfmap->nfv9_logging_index =
1191                                 my_nfv9_logging_info - cnat_nfv9_logging_info_pool;
1192                             // my_vrfmap->nf_logging_policy = mp->session_logging;
1193                         } else {
1194                             cnat_nfv9_logging_info_t *my_nfv9_logging_info_temp = cnat_nfv9_logging_info_pool + my_vrfmap->nfv9_logging_index;
1195                             while(my_nfv9_logging_info_temp->nfv9_logging_next_index != EMPTY){
1196                                 my_nfv9_logging_info_temp = cnat_nfv9_logging_info_pool + my_nfv9_logging_info_temp->nfv9_logging_next_index;
1197                             }
1198                             my_nfv9_logging_info_temp->nfv9_logging_next_index = my_nfv9_logging_info - cnat_nfv9_logging_info_pool;
1199                         }
1200                     }
1201             }
1202         }
1203
1204         /* Update logging policy */
1205         my_nfv9_logging_info->logging_policy = nfv9_conf.session_logging;
1206         if (nfv9_conf.nfv9_global_collector) {
1207                 if(PLATFORM_DBL_SUPPORT) {
1208                     pool_foreach (my_vrfmap, cnat_map_by_vrf, ({
1209                         if (my_vrfmap->nfv9_logging_index ==
1210                     cnat_nfv9_global_info.cnat_nfv9_global_collector_index) {
1211                     my_vrfmap->nf_logging_policy = nfv9_conf.session_logging;
1212                 }
1213                     }));
1214                 } else {
1215                         nfv9_conf.rc = CNAT_ERR_NO_SESSION_DB;
1216                 }
1217         } else {
1218                 if(PLATFORM_DBL_SUPPORT) {
1219                         u32 my_vrfmap_found = 0;
1220                         my_vrfmap_temp = NULL;
1221                         FIND_MY_VRF_USING_I_VRF_ID
1222                         my_vrfmap = my_vrfmap_temp;
1223                         if (my_vrfmap_found) {
1224                           //    my_vrfmap->nf_logging_policy = mp->session_logging;
1225                         }
1226                 } else {
1227                         nfv9_conf.rc = CNAT_ERR_NO_SESSION_DB;
1228                 }
1229         }
1230         u8  nfv9_logging_policy = 0;
1231         u32 my_vrfmap_found = 0;
1232         my_vrfmap_temp = NULL;
1233         FIND_MY_VRF_USING_I_VRF_ID
1234         my_vrfmap = my_vrfmap_temp;
1235             if (my_vrfmap_found) {
1236                 u32 index_curr = my_vrfmap->nfv9_logging_index;
1237                 cnat_nfv9_logging_info_t *my_nfv9_logging_info_temp;
1238                 while(index_curr != EMPTY) {
1239                     my_nfv9_logging_info_temp = cnat_nfv9_logging_info_pool + index_curr;
1240                     nfv9_logging_policy = nfv9_logging_policy || my_nfv9_logging_info_temp->logging_policy;
1241                     index_curr = (cnat_nfv9_logging_info_pool + index_curr)->nfv9_logging_next_index;
1242                 }
1243                 my_vrfmap->nf_logging_policy = nfv9_logging_policy;
1244             }
1245             //vlib_cli_output(vm,"Netflow logging policy = %d\n", my_vrfmap->nf_logging_policy);
1246             if(nfv9_get_server_instance(my_nfv9_logging_info, &new_server_info)
1247                != CNAT_SUCCESS) {
1248                 vlib_cli_output(vm, "Error to get server instance");
1249                 nfv9_conf.rc = CNAT_ERR_PARSER;
1250                 goto done;
1251             }
1252         nfv9_init_pkt_sent_data(my_nfv9_logging_info);
1253
1254         vlib_cli_output(vm,"Adding NFv9 Logging Succeeded\n");
1255         nfv9_configured = 1;
1256
1257     } else {
1258     /*Delete path*/
1259         if (found) {
1260             /* if found entry then we need to overwrite the my_nfv9_logging_info_tmp
1261              * to my_nfv9_logging_info
1262              */
1263             my_nfv9_logging_info = my_nfv9_logging_info_tmp;
1264             if (i_vrf == INVALID_UIDX) {
1265                 /*
1266                  * We are deleting a global collector.  Mark the collectors
1267                  * in those VRFs using the global collector
1268                  */
1269                 pool_foreach (my_vrfmap, cnat_map_by_vrf, ({
1270                             if (my_vrfmap->nfv9_logging_index ==
1271                                 cnat_nfv9_global_info.cnat_nfv9_global_collector_index) {
1272                                 my_vrfmap->nfv9_logging_index = EMPTY;
1273                             }
1274                         }));
1275
1276                 cnat_nfv9_global_info.cnat_nfv9_global_collector_index = EMPTY;
1277             } else {
1278                 u32 my_vrfmap_found = 0;
1279                 my_vrfmap_temp = NULL;
1280                 FIND_MY_VRF_USING_I_VRF_ID
1281                 my_vrfmap = my_vrfmap_temp;
1282                     if (my_vrfmap_found) {
1283                         // my_vrfmap->nfv9_logging_index = cnat_nfv9_global_info.cnat_nfv9_global_collector_index;
1284                     }
1285             }
1286             if (my_nfv9_logging_info->queued_logging_context ||
1287                 my_nfv9_logging_info->current_logging_context) {
1288                 /*
1289                  * If there is a pending context:
1290                  * Set the deleted flag to 1.  This will ensure
1291                  * that the logging info structure gets freed after any
1292                  * pending packet get sent
1293                  */
1294                 my_nfv9_logging_info->deleted = 1;
1295             } else {
1296                 /*
1297                  * No pending context, just free the logging info structure
1298                  */
1299                 u32  index = my_nfv9_logging_info - cnat_nfv9_logging_info_pool;
1300                 if(index == my_vrfmap->nfv9_logging_index) {
1301                     /* Deleting the first sever */
1302                     my_vrfmap->nfv9_logging_index = my_nfv9_logging_info->nfv9_logging_next_index;
1303                     /* if(my_nfv9_logging_info->nfv9_logging_next_index != EMPTY){
1304                         my_vrfmap->nf_logging_policy = (cnat_nfv9_logging_info_pool + my_nfv9_logging_info->nfv9_logging_next_index)->logging_policy;
1305                     } else {
1306                         my_vrfmap->nf_logging_policy = EMPTY;
1307                     }*/
1308                 } else {
1309                     u32 index_curr = my_vrfmap->nfv9_logging_index;
1310                     u32 index_prev = EMPTY;
1311                     while(index_curr != EMPTY) {
1312                         index_prev = index_curr;
1313                         index_curr = (cnat_nfv9_logging_info_pool + index_curr)->nfv9_logging_next_index;
1314                         if(index == index_curr)
1315                         {
1316                             (cnat_nfv9_logging_info_pool + index_prev)->nfv9_logging_next_index = (cnat_nfv9_logging_info_pool + index_curr)->nfv9_logging_next_index;
1317                             break;
1318                         }
1319                     }
1320                 }
1321                 nfv9_delete_server_info(my_nfv9_logging_info);
1322                 pool_put(cnat_nfv9_logging_info_pool, my_nfv9_logging_info);
1323             }
1324
1325             vlib_cli_output(vm, "Deleting NFv9 Logging Succeeded\n");
1326             /* 
1327              * Search across all vrf and check if nfv9 logging is configured.
1328              */ 
1329             nfv9_configured = 0;
1330             pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info_pool, ({
1331                  nfv9_configured = 1;
1332                  break;
1333             }));
1334         } else {
1335             nfv9_conf.rc = CNAT_NO_CONFIG;
1336             vlib_cli_output(vm, "Add NFv9 Logging Failed (2) Non Existent vrf %d\n",
1337                                      i_vrf);
1338
1339         }
1340         u8  nfv9_logging_policy = 0;
1341         u32 my_vrfmap_found = 0;
1342         my_vrfmap_temp = NULL;
1343         FIND_MY_VRF_USING_I_VRF_ID
1344         my_vrfmap = my_vrfmap_temp; 
1345             if (my_vrfmap_found) {
1346                 u32 index_curr = my_vrfmap->nfv9_logging_index;
1347                 cnat_nfv9_logging_info_t *my_nfv9_logging_info_temp;
1348                 while(index_curr != EMPTY) {
1349                     my_nfv9_logging_info_temp = cnat_nfv9_logging_info_pool + index_curr;
1350                     nfv9_logging_policy = nfv9_logging_policy || my_nfv9_logging_info_temp->logging_policy;
1351                     index_curr = (cnat_nfv9_logging_info_pool + index_curr)->nfv9_logging_next_index;
1352                 }
1353                 my_vrfmap->nf_logging_policy = nfv9_logging_policy;
1354             }
1355     }
1356
1357 done:
1358     return 0;
1359 }
1360
1361 /* config CLIs */
1362 VLIB_CLI_COMMAND (set_vcgn_map_command) = {
1363     .path = "set vcgn map",
1364     .short_help = "set vcgn map <lo-address> [- <hi-address>]",
1365     .function = set_vcgn_map_command_fn,
1366 };
1367
1368 VLIB_CLI_COMMAND (set_vcgn_inside_command) = {
1369     .path = "set vcgn inside",
1370     .short_help = "set vcgn inside <inside intfc> outside <outside intfc>",
1371     .function = set_vcgn_inside_command_fn,
1372 };
1373
1374 VLIB_CLI_COMMAND (set_vcgn_tcp_timeout_command) = {
1375     .path = "set vcgn tcp timeout",
1376     .short_help = "set vcgn tcp timeout active <1-65535> init <1-65535>",
1377     .function = set_vcgn_tcp_timeout_command_fn,
1378 };
1379
1380 VLIB_CLI_COMMAND (set_vcgn_udp_timeout_command) = {
1381     .path = "set vcgn udp timeout",
1382     .short_help = "set vcgn udp timeout active <1-65535> init <1-65535>",
1383     .function = set_vcgn_udp_timeout_command_fn,
1384 };
1385
1386 VLIB_CLI_COMMAND (set_vcgn_icmp_timeout_command) = {
1387     .path = "set vcgn icmp timeout",
1388     .short_help = "set vcgn icmp timeout <1-65535>",
1389     .function = set_vcgn_icmp_timeout_command_fn,
1390 };
1391
1392 VLIB_CLI_COMMAND (set_vcgn_protocol_default_timeout_command) = {
1393     .path = "set vcgn default timeout",
1394     .short_help = "set vcgn default timeout protocol <tcp/udp/icmp>",
1395     .function = set_vcgn_protocol_default_timeout_command_fn,
1396 };
1397
1398 VLIB_CLI_COMMAND (set_vcgn_dynamic_port_start_range_command) = {
1399     .path = "set vcgn dynamic port start",
1400     .short_help = "set vcgn dynamic port start <1-65535>",
1401     .function = set_vcgn_dynamic_port_start_range_command_fn,
1402 };
1403
1404 VLIB_CLI_COMMAND (set_vcgn_port_limit_command) = {
1405     .path = "set vcgn port limit",
1406     .short_help = "set vcgn port limit <1-65535>",
1407     .function = set_vcgn_port_limit_command_fn,
1408 };
1409
1410 VLIB_CLI_COMMAND (set_vcgn_nfv9_logging_cofig_command) = {
1411     .path = "set vcgn nfv9",
1412     .short_help = "set vcgn nfv9 [del] inside <interface> "
1413                   "server <ip-addr> port <port> [refresh-rate <n>] "
1414                   "[timeout <n>] [pmtu <n>]",
1415     .function = set_vcgn_nfv9_logging_cofig_command_fn,
1416 };
1417
1418
1419 /* show CLIs */
1420 VLIB_CLI_COMMAND (show_vcgn_config_command) = {
1421     .path = "show vcgn config",
1422     .short_help = "show vcgn config",
1423     .function = show_vcgn_config_command_fn,
1424 };
1425
1426 VLIB_CLI_COMMAND (show_vcgn_stat_command) = {
1427     .path = "show vcgn statistics",
1428     .short_help = "show vcgn statistics",
1429     .function = show_vcgn_stats_command_fn,
1430 };
1431
1432 VLIB_CLI_COMMAND (show_vcgn_inside_translation_command) = {
1433     .path = "show vcgn inside-translation",
1434     .short_help = "show vcgn inside-translation protocol <tcp/udp/icmp> "
1435                   "interface <inside-if> inside-addr <ip-addr> "
1436                   "[start-port <n>] [end-port <n>]",
1437     .function = show_vcgn_inside_translation_command_fn,
1438 };
1439
1440 VLIB_CLI_COMMAND (show_vcgn_outside_translation_command) = {
1441     .path = "show vcgn outside-translation",
1442     .short_help = "show vcgn outside-translation protocol <tcp/udp/icmp> "
1443                   "interface <outside-if> outside-addr <ip-addr> "
1444                   "[start-port <n>] [end-port <n>]",
1445     .function = show_vcgn_outside_translation_command_fn,
1446 };
1447
1448 static clib_error_t *
1449 vcgn_init (vlib_main_t * vm)
1450 {
1451   clib_error_t * error = 0;
1452
1453   if ((error = vlib_call_init_function 
1454        (vm, vcgn_classify_init)))
1455     return error;
1456   if ((error = vlib_call_init_function 
1457        (vm, cnat_ipv4_udp_inside_input_init)))
1458     return error;
1459   if ((error = vlib_call_init_function 
1460        (vm, cnat_ipv4_udp_outside_input_init)))
1461     return error;
1462   if ((error = vlib_call_init_function 
1463        (vm, cnat_ipv4_udp_inside_input_exc_init)))
1464     return error;
1465   if ((error = vlib_call_init_function 
1466        (vm, cnat_db_scanner_init)))
1467     return error;
1468   if ((error = vlib_call_init_function 
1469        (vm, cnat_ipv4_tcp_inside_input_init)))
1470     return error;
1471   if ((error = vlib_call_init_function 
1472        (vm, cnat_ipv4_tcp_inside_input_exc_init)))
1473     return error;
1474   if ((error = vlib_call_init_function 
1475        (vm, cnat_ipv4_tcp_outside_input_init)))
1476     return error;
1477   if ((error = vlib_call_init_function 
1478        (vm, cnat_ipv4_icmp_q_inside_input_init)))
1479     return error;
1480   if ((error = vlib_call_init_function 
1481        (vm, cnat_ipv4_icmp_q_inside_input_exc_init)))
1482     return error;
1483   if ((error = vlib_call_init_function 
1484        (vm, cnat_ipv4_icmp_q_outside_input_init)))
1485     return error;
1486   if ((error = vlib_call_init_function 
1487        (vm, cnat_ipv4_icmp_e_inside_input_init)))
1488     return error;
1489   if ((error = vlib_call_init_function 
1490        (vm, cnat_ipv4_icmp_e_outside_input_init)))
1491     return error;
1492
1493   return error;
1494 }
1495
1496 /* 
1497  * This routine exists to convince the vlib plugin framework that
1498  * we haven't accidentally copied a random .dll into the plugin
1499  * directory. This is used in lieu of VLIB_INIT_FUNCTION(vcgn_init).
1500  *
1501  * Also collects global variable pointers passed from the vpp engine
1502  */
1503 clib_error_t *
1504 vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h,
1505                       int from_early_init)
1506 {
1507     return vcgn_init(vm);
1508 }