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