Initial commit of vpp code.
[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   dpdk_set_next_node (DPDK_RX_NEXT_IP4_INPUT, "vcgn-classify");
401
402   {
403     pg_node_t * pn;
404     pn = pg_get_node (vcgn_classify_node.index);
405     pn->unformat_edit = unformat_pg_ip4_header;
406   }
407   return 0;
408 }
409
410 VLIB_INIT_FUNCTION (vcgn_classify_init);
411
412 /* Show command handlers */
413 static clib_error_t *
414 show_vcgn_stats_command_fn (vlib_main_t * vm,
415                          unformat_input_t * input,
416                          vlib_cli_command_t * cmd)
417 {
418     if (cnat_db_init_done) {
419         cnat_nat44_handle_show_stats(vm);
420     } else {
421         vlib_cli_output(vm, "vCGN is not configured !!\n");
422     }
423     return 0;
424 }
425
426
427 static clib_error_t *
428 show_vcgn_config_command_fn (vlib_main_t * vm,
429                          unformat_input_t * input,
430                          vlib_cli_command_t * cmd)
431 {
432   cnat_nat44_handle_show_config(vm);
433   return 0;
434 }
435
436 static clib_error_t *
437 show_vcgn_inside_translation_command_fn (vlib_main_t * vm,
438                          unformat_input_t * input,
439                          vlib_cli_command_t * cmd)
440 {
441     /*
442     vnet_main_t * vnm = vnet_get_main();
443     */
444     vcgn_classify_main_t * vcm = &vcgn_classify_main;
445     spp_api_cnat_v4_show_inside_entry_req_t inside_req;
446     u8 *proto; 
447     ip4_address_t inside_addr;
448     u32 start_port = 1;
449     u32 end_port = 65535;
450     
451     inside_req.start_port = start_port;
452     inside_req.end_port = end_port;
453     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
454         if (unformat(input, "protocol %s", &proto)) { 
455             if (!strncmp((char *) proto, "udp", 3)) {
456                 inside_req.protocol = 1;
457             } else if (!strncmp((char *) proto, "tcp", 3)) {
458                 inside_req.protocol = 2;
459             } else {
460                 inside_req.protocol = 3;
461             } 
462         } else if (unformat (input, "inside-addr %U", 
463                        unformat_ip4_address, &inside_addr)) {
464             inside_req.ipv4_addr = clib_net_to_host_u32(inside_addr.as_u32); 
465         } else if (unformat(input, "start-port %u", &start_port)) {
466             inside_req.start_port = start_port;
467         } else if (unformat(input, "end-port %u", &end_port)) {
468             inside_req.end_port = end_port;
469         } else { break;}
470     }
471     inside_req.vrf_id = vcm->inside_sw_if_index;
472     inside_req.flags |= CNAT_TRANSLATION_ENTRY_DYNAMIC; /* as of now only dynamic */  
473     inside_req.all_entries = 0; /* we can see it later */
474 #if DEBUG
475     vlib_cli_output(vm, "proto %d, inside-addr 0x%x, start_port %u, "
476                 "end_port %u, vrf 0x%x\n",
477                 inside_req.protocol, 
478                 inside_req.ipv4_addr,
479                 inside_req.start_port,
480                 inside_req.end_port,
481                 vcm->inside_sw_if_index);
482 #endif
483     if (cnat_db_init_done) {
484         cnat_v4_show_inside_entry_req_t_handler(&inside_req, vm);
485     } else {
486         vlib_cli_output(vm, "vCGN is not configured !!\n");
487     }
488     return 0;
489 }
490
491
492 static clib_error_t *
493 show_vcgn_outside_translation_command_fn (vlib_main_t * vm,
494                          unformat_input_t * input,
495                          vlib_cli_command_t * cmd)
496 {
497     void cnat_v4_show_outside_entry_req_t_handler
498         (spp_api_cnat_v4_show_outside_entry_req_t *mp, vlib_main_t *vm);
499     vcgn_classify_main_t * vcm = &vcgn_classify_main;
500     spp_api_cnat_v4_show_outside_entry_req_t outside_req;
501     u8 *proto; 
502     ip4_address_t outside_addr;
503     u32 start_port = 1;
504     u32 end_port = 65535;
505     
506     outside_req.start_port = start_port;
507     outside_req.end_port = end_port;
508     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
509         if (unformat(input, "protocol %s", &proto)) { 
510             if (!strncmp((char *) proto, "udp", 3)) {
511                 outside_req.protocol = 1;
512             } else if (!strncmp((char *) proto, "tcp", 3)) {
513                 outside_req.protocol = 2;
514             } else {
515                 outside_req.protocol = 3;
516             } 
517         } else if (unformat (input, "outside-addr %U", 
518                        unformat_ip4_address, &outside_addr)) {
519             outside_req.ipv4_addr = clib_net_to_host_u32(outside_addr.as_u32); 
520         } else if (unformat(input, "start-port %u", &start_port)) {
521             outside_req.start_port = start_port;
522         } else if (unformat(input, "end-port %u", &end_port)) {
523             outside_req.end_port = end_port;
524         } else { break;}
525     }
526     outside_req.vrf_id = vcm->outside_sw_if_index;
527     outside_req.flags |= CNAT_TRANSLATION_ENTRY_DYNAMIC; /* as of now only dynamic */  
528 #if DEBUG
529     vlib_cli_output(vm, "proto %d, outside-addr 0x%x, start_port %u, "
530                 "end_port %u, vrf 0x%x\n",
531                 outside_req.protocol, 
532                 outside_req.ipv4_addr,
533                 outside_req.start_port,
534                 outside_req.end_port,
535                 vcm->outside_sw_if_index);
536 #endif
537     if (cnat_db_init_done) {
538         cnat_v4_show_outside_entry_req_t_handler(&outside_req, vm);
539     } else {
540         vlib_cli_output(vm, "vCGN is not configured !!\n");
541     }
542     return 0;
543 }
544
545
546 /* Config command handlers */
547 static clib_error_t *
548 set_vcgn_inside_command_fn (vlib_main_t * vm,
549                             unformat_input_t * input,
550                             vlib_cli_command_t * cmd)
551 {
552   vnet_main_t * vnm = vnet_get_main();
553   vcgn_classify_main_t * vcm = &vcgn_classify_main;
554   u32 inside_sw_if_index = 1;
555   u32 outside_sw_if_index = ~0;
556   void cnat_db_v2_init (void );
557
558     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
559       if (unformat(input, "%U", 
560                    unformat_vnet_sw_interface, vnm, &inside_sw_if_index))
561     ;
562       else if (unformat(input, "outside %U", 
563                    unformat_vnet_sw_interface, vnm, &outside_sw_if_index))
564         ; 
565       else break;
566     }
567     if (inside_sw_if_index == ~0 ||
568         outside_sw_if_index == ~0)
569       return clib_error_return (0, "unknown input `%U'",
570                                 format_unformat_error, input);
571
572     if (inside_sw_if_index == outside_sw_if_index)
573       return clib_error_return (0, "inside and outside interfaces can't be the same...");
574
575     vcm->inside_sw_if_index = inside_sw_if_index;
576     vcm->outside_sw_if_index = outside_sw_if_index;
577
578     cnat_db_v2_init();
579     
580     /* Turn on the db scanner process */
581     cnat_scanner_db_process_turn_on(vm);
582     return 0;
583 }
584
585 static clib_error_t *
586 set_vcgn_map_command_fn (vlib_main_t * vm,
587                          unformat_input_t * input,
588                          vlib_cli_command_t * cmd)
589 {
590   vcgn_classify_main_t * vcm = &vcgn_classify_main;
591   ip4_address_t lo, hi;
592   spp_api_cnat_v4_add_vrf_map_t map;
593   int i;
594
595   vnet_hw_interface_t *inside_hw_if_index = NULL;
596   vnet_hw_interface_t *outside_hw_if_index = NULL;
597
598   if (!unformat (input, "%U", unformat_ip4_address, &lo))
599     return clib_error_return (0, "unknown input `%U'",
600                               format_unformat_error, input);
601
602   if (unformat (input, "- %U", unformat_ip4_address, &hi))
603     ;
604
605   /* $$$$ remember to set i_vrf, i_vrf_id as needed */
606
607   /* Fill the structure spp_api_cnat_v4_add_vrf_map_t & let this API handle it */
608   /* i_vrf_id & o_vrf_id are 32-bit & i_vrf, o_vrf are 16 bit */
609   map.i_vrf_id = vcm->inside_sw_if_index; 
610   map.o_vrf_id = vcm->outside_sw_if_index; 
611   map.i_vrf    = vcm->inside_sw_if_index;
612   map.o_vrf    = vcm->outside_sw_if_index;
613
614   map.start_addr[0] = clib_net_to_host_u32(lo.as_u32); 
615   map.end_addr[0]   = clib_net_to_host_u32(hi.as_u32); 
616
617   for (i = 0; i < CNAT_MAX_VRFMAP_ENTRIES; i++) {
618         vrf_map_array[i] = VRF_MAP_ENTRY_EMPTY;
619   }
620   cnat_nat44_add_vrf_map_t_handler(&map, vm);
621
622 #if 1
623   inside_hw_if_index = vnet_get_sup_hw_interface(vcm->vnet_main, vcm->inside_sw_if_index);
624   if (inside_hw_if_index) {
625     vnet_hw_interface_rx_redirect_to_node(vcm->vnet_main, 
626             inside_hw_if_index->hw_if_index, vcgn_classify_node.index);
627   }
628   outside_hw_if_index = vnet_get_sup_hw_interface(vcm->vnet_main, vcm->outside_sw_if_index);
629   if (outside_hw_if_index) {
630     vnet_hw_interface_rx_redirect_to_node(vcm->vnet_main, 
631             outside_hw_if_index->hw_if_index, vcgn_classify_node.index);
632   }
633 #endif
634   return 0;
635 }
636
637 static clib_error_t *
638 set_vcgn_tcp_timeout_command_fn (vlib_main_t * vm,
639                             unformat_input_t * input,
640                             vlib_cli_command_t * cmd)
641 {
642   /*
643   vnet_main_t * vnm = vnet_get_main();
644   vcgn_classify_main_t * vcm = &vcgn_classify_main;
645   */
646   u32 act_timeout = 0;
647   u32 init_timeout = 0;
648
649     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
650         if (unformat(input, "active %u", &act_timeout)) 
651             tcp_active_timeout = act_timeout;
652         else if (unformat(input, "init %u", &init_timeout)) 
653             tcp_initial_setup_timeout = init_timeout; 
654         else break;
655     }
656     return 0;
657 }
658
659 static clib_error_t *
660 set_vcgn_udp_timeout_command_fn (vlib_main_t * vm,
661                             unformat_input_t * input,
662                             vlib_cli_command_t * cmd)
663 {
664   /*
665   vnet_main_t * vnm = vnet_get_main();
666   vcgn_classify_main_t * vcm = &vcgn_classify_main;
667   */
668   u32 act_timeout = 0;
669   u32 init_timeout = 0;
670
671     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
672         if (unformat(input, "active %u", &act_timeout)) 
673             udp_act_session_timeout = act_timeout;
674         else if (unformat(input, "init %u", &init_timeout)) 
675             udp_init_session_timeout = init_timeout; 
676         else break;
677     }
678     return 0;
679 }
680
681
682 static clib_error_t *
683 set_vcgn_icmp_timeout_command_fn (vlib_main_t * vm,
684                             unformat_input_t * input,
685                             vlib_cli_command_t * cmd)
686 {
687   /* 
688    * vnet_main_t * vnm = vnet_get_main(); 
689    * vcgn_classify_main_t * vcm = &vcgn_classify_main;
690    */
691   u32 timeout = 0;
692
693     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
694         if (unformat(input, "%u", &timeout)) 
695             ; 
696         else break;
697     }
698     icmp_session_timeout = timeout;
699     return 0;
700 }
701
702
703 static clib_error_t *
704 set_vcgn_protocol_default_timeout_command_fn (vlib_main_t * vm,
705                             unformat_input_t * input,
706                             vlib_cli_command_t * cmd)
707 {
708     /*
709     vnet_main_t * vnm = vnet_get_main();
710     vcgn_classify_main_t * vcm = &vcgn_classify_main;
711     */
712     u8 *protocol;
713     u8 reset = 1; 
714
715     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
716       if (unformat(input, "%s", &protocol)) 
717         ;
718       else break;
719     }
720     cnat_nat44_set_protocol_timeout_value(0, 0, protocol, reset, vm);
721     return 0;
722 }
723
724 static clib_error_t *
725 set_vcgn_dynamic_port_start_range_command_fn (vlib_main_t * vm,
726                             unformat_input_t * input,
727                             vlib_cli_command_t * cmd)
728 {
729     /*
730     vnet_main_t * vnm = vnet_get_main();
731     vcgn_classify_main_t * vcm = &vcgn_classify_main;
732     */
733     u32 port = 0;
734
735     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
736       if (unformat(input, "%u", &port)) 
737         ;
738       else break;
739     }
740     if (port != 0 && port > 65535) {
741         vlib_cli_output(vm, "Error !! Invalid port\n");
742     } else {
743         cnat_static_port_range = port;
744         vlib_cli_output(vm, "Dynamic Port Range Config Successful !!\n");
745     }
746     return 0;
747 }
748
749 static clib_error_t *
750 set_vcgn_port_limit_command_fn (vlib_main_t * vm,
751                             unformat_input_t * input,
752                             vlib_cli_command_t * cmd)
753 {
754     /*
755     vnet_main_t * vnm = vnet_get_main();
756     vcgn_classify_main_t * vcm = &vcgn_classify_main;
757     */
758     u32 port = 0;
759
760     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
761       if (unformat(input, "%u", &port)) 
762         ;
763       else break;
764     }
765     if (port != 0 && port > 65535) {
766         vlib_cli_output(vm, "Error !! Invalid port\n");
767     } else {
768         cnat_main_db_max_ports_per_user = port;
769         vlib_cli_output(vm, "Port Limit Config Successful !!\n");
770     }
771     return 0;
772 }
773
774 static inline void nfv9_init_pkt_sent_data(cnat_nfv9_logging_info_t *nfv9_info)
775 {
776     nfv9_server_info_t *server = nfv9_server_info_pool +
777         nfv9_info->server_index;
778
779         /*
780          * Reset the pkts_since_last_template and sent_time
781          * so that template will be sent next time
782          */
783         server->last_template_sent_time  = 0;
784         server->pkts_since_last_template = 0xffffffff;
785 }
786
787 static inline u16 nfv9_get_max_length_minus_max_record_size(u16 path_mtu)
788 {
789     u16 max_length_minus_max_record_size;
790     if(!path_mtu) /* Use default */
791         path_mtu = NFV9_DEF_PATH_MTU;
792
793     max_length_minus_max_record_size = path_mtu -
794         CNAT_NFV9_DATAFLOW_RECORD_HEADER_LENGTH -
795         NFV9_PAD_VALUE -
796         CNAT_NFV9_MAX_SINGLE_RECORD_LENGTH; /* Note.. as of now this record
797             * requires max number of bytes. If you add more records,
798             * this needs to be re-checked */
799         if (max_length_minus_max_record_size < CNAT_NFV9_MIN_RECORD_SIZE) {
800             printf(
801                "Resetting max_length_minus_max_record_size from %d to %ld\n",
802                max_length_minus_max_record_size,
803                CNAT_NFV9_MIN_RECORD_SIZE);
804
805             max_length_minus_max_record_size = CNAT_NFV9_MIN_RECORD_SIZE;
806         }
807    return max_length_minus_max_record_size;
808 }
809
810 /* This function finds if the netflow server indicated by
811  * new_server_info is already configured for some other instance
812  * if yes, it returns the same pointer so that, info sent to the
813  * server is consistent. If the server is not found, a new instance
814  * is created and returned. If an existing server is used, its refernce
815  * count is incrimented (indicating the number of instances using the
816  * same server
817  */
818  /* #define DEBUG_NF_SERVER_CONFIG 1 */
819 static u16 nfv9_get_server_instance(
820     cnat_nfv9_logging_info_t *nfv9_info, nfv9_server_info_t *new_server_info)
821 {
822
823     /* Check if the instance has a server already and if yes, does it match */
824     nfv9_server_info_t *server;
825     if(nfv9_info->server_index != EMPTY) {
826         server =  nfv9_server_info_pool + nfv9_info->server_index;
827
828         if((server->ipv4_address == new_server_info->ipv4_address) &&
829             (server->port == new_server_info->port)) {
830             /* Same server.. just check if refresh rate/timeouts are reduced */
831 #ifdef DEBUG_NF_SERVER_CONFIG
832             if(my_instance_number == 1) {
833             printf("\n Server match for %x and port %d\n",
834                 new_server_info->ipv4_address, new_server_info->port);
835             }
836 #endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
837             goto adjust_refresh_rate;
838         } else { /* The server is being changed */
839             server->ref_count--;
840 #ifdef DEBUG_NF_SERVER_CONFIG
841             if(my_instance_number == 1) {
842             printf("\n Server change from %x, %d to %x, %d"
843                 "Ref count %d\n",
844                 server->ipv4_address,
845                 server->port,
846                 new_server_info->ipv4_address, new_server_info->port,
847                 server->ref_count);
848             }
849 #endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
850             if(!server->ref_count) {
851                 /* Return this server to pool */
852 #ifdef DEBUG_NF_SERVER_CONFIG
853                 if(my_instance_number == 1) {
854                     PLATFORM_DEBUG_PRINT("Deleting Server %x, %d at %d\n",
855                     server->ipv4_address,
856                     server->port,
857                     nfv9_info->server_index);
858                 }
859 #endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
860                 pool_put(nfv9_server_info_pool, server);
861             }
862         }
863     }
864
865     /* Now check if the server is already present in the pool */
866     u8 found = 0;
867     server = 0;
868     pool_foreach (server, nfv9_server_info_pool, ({
869         if ((server->ipv4_address == new_server_info->ipv4_address) &&
870             (server->port == new_server_info->port)) {
871             server->ref_count++;
872             nfv9_info->server_index = server - nfv9_server_info_pool;
873             found = 1;
874 #ifdef DEBUG_NF_SERVER_CONFIG
875             if(my_instance_number == 1) {
876             printf("Re-using server %x, %d Ref count %d\n",
877             server->ipv4_address, server->port, server->ref_count);
878             }
879 #endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
880             break;
881         }
882     }));
883
884     if(!found) {
885         /* Create a new one, initialize and return */
886         server = 0;
887         pool_get(nfv9_server_info_pool, server);
888         memcpy(server, new_server_info, sizeof(nfv9_server_info_t));
889         server->ref_count = 1;
890         nfv9_info->server_index = server - nfv9_server_info_pool;
891 #ifdef DEBUG_NF_SERVER_CONFIG
892         if(my_instance_number == 1) {
893         printf("Create new server for at %d %x and port %d\n",
894                 nfv9_info->server_index,
895                 new_server_info->ipv4_address, new_server_info->port);
896         }
897 #endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
898         return CNAT_SUCCESS;
899     }
900
901 adjust_refresh_rate:
902     if(server->refresh_rate >
903         new_server_info->refresh_rate) {
904         server->refresh_rate =
905             new_server_info->refresh_rate;
906 #ifdef DEBUG_NF_SERVER_CONFIG
907         if(my_instance_number == 1) {
908         printf("Reset refresh rate to %d\n",
909             server->refresh_rate);
910         }
911 #endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
912     }
913
914     if(server->timeout_rate >
915         new_server_info->timeout_rate) {
916         server->timeout_rate =
917         new_server_info->timeout_rate;
918 #ifdef DEBUG_NF_SERVER_CONFIG
919         if(my_instance_number == 1) {
920             printf("Reset timeout rate to %d\n",
921             server->timeout_rate);
922         }
923 #endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
924     }
925
926     return CNAT_SUCCESS;
927 }
928 static clib_error_t *
929 set_vcgn_nfv9_logging_cofig_command_fn (vlib_main_t * vm,
930                             unformat_input_t * input,
931                             vlib_cli_command_t * cmd)
932 {
933     vcgn_classify_main_t * vcm = &vcgn_classify_main;
934     spp_api_cnat_v4_config_nfv9_logging_t nfv9_conf;
935     ip4_address_t server_addr;
936     u32 ip_addr = 0;
937     u32 port;
938     u32 refresh_rate = 0;
939     u32 timeout = 0;
940     u32 pmtu = 0;
941     u8 enable = 1;
942 /* vcgn changes start*/
943     cnat_nfv9_logging_info_t *my_nfv9_logging_info = NULL;
944     cnat_nfv9_logging_info_t *my_nfv9_logging_info_tmp = NULL;
945     cnat_vrfmap_t *my_vrfmap = 0, *my_vrfmap_temp; 
946     u16           i_vrf;
947     u32           i_vrf_id;
948     u8            found;
949     u8            found_vrf;
950     /*
951      * Init NFv9 logging info as needed, this will be done only once
952      */
953     cnat_nfv9_logging_init();
954
955     i_vrf    = vcm->inside_sw_if_index;
956     i_vrf_id = vcm->inside_sw_if_index; 
957
958     found = 0;
959   
960 /* vcgn changes end*/
961     while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
962         if (unformat (input, "server %U", unformat_ip4_address, &server_addr))
963             ip_addr = clib_net_to_host_u32(server_addr.as_u32);
964         else if (unformat(input, "port %u", &port)) 
965         ;
966         else if (unformat(input, "refresh-rate %u", &refresh_rate)) 
967         ;
968         else if (unformat(input, "timeout %u", &timeout)) 
969         ;
970         else if (unformat(input, "pmtu %u", &pmtu)) 
971         ;
972         else if (unformat(input, "del")) 
973             enable = 0;
974         else break;
975     }
976
977
978     #if 0
979     vlib_cli_output(vm, "ip 0x%x, port %u, refresh %u, "
980                     "timeout %u, pmtu %u enable %u\n",
981                     ip_addr, port, refresh_rate, 
982                     timeout, pmtu, enable);
983     #endif
984     nfv9_conf.enable = enable;
985     nfv9_conf.ipv4_address = ip_addr;
986     nfv9_conf.i_vrf_id = vcm->inside_sw_if_index;
987     nfv9_conf.i_vrf = vcm->inside_sw_if_index;
988     nfv9_conf.port = port;
989     nfv9_conf.refresh_rate = refresh_rate;
990     nfv9_conf.timeout_rate = timeout;
991     nfv9_conf.path_mtu = pmtu;
992     nfv9_conf.nfv9_global_collector = 0;
993     nfv9_conf.session_logging = 0;
994
995     /*
996      * At this point the NFv9 global information should already be
997      * inited as we have called cnat_nfv9_logging_init()
998      */
999
1000     if (nfv9_conf.nfv9_global_collector) {
1001         if (cnat_nfv9_global_info.cnat_nfv9_global_collector_index != EMPTY) {
1002             found = 1;
1003             my_nfv9_logging_info = cnat_nfv9_logging_info_pool +
1004                     cnat_nfv9_global_info.cnat_nfv9_global_collector_index;
1005         }
1006     } else {
1007         /* Do we already have a map for this VRF? */
1008         pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info_pool, ({
1009               if (my_nfv9_logging_info->i_vrf_id == i_vrf_id) {
1010                   found_vrf = 1;
1011                   printf("found_vrf %d\n", found_vrf);
1012                   nfv9_server_info_t *server =  nfv9_server_info_pool +
1013                       my_nfv9_logging_info->server_index;
1014                   printf("server ip4 0x%x port %d\n", server->ipv4_address, server->port);
1015                   printf("nfv9_conf v4 0x%x port %d\n", nfv9_conf.ipv4_address, nfv9_conf.port);
1016                   if((server->ipv4_address ==  (nfv9_conf.ipv4_address)) && (server->port == (nfv9_conf.port))) {
1017                       found = 1;
1018                       my_nfv9_logging_info_tmp = my_nfv9_logging_info;
1019                       printf("found %d\n", found);
1020                       break;
1021                   }
1022               }
1023           }));
1024     }
1025
1026     if ((nfv9_conf.ipv4_address == 0) ||
1027         (nfv9_conf.port == 0)) {
1028         vlib_cli_output(vm,
1029             "Add NFv9 ivrf %d Logging Invalid values [IPv4 0x%x, PORT %d]\n",
1030                 i_vrf,
1031                 (nfv9_conf.ipv4_address),
1032                 (nfv9_conf.port));
1033          goto done;    
1034     }
1035
1036     if (nfv9_conf.enable) {
1037         if ((nfv9_conf.ipv4_address == 0) ||
1038               (nfv9_conf.port == 0)) {
1039               nfv9_conf.rc = CNAT_ERR_PARSER;
1040               vlib_cli_output(vm,
1041                   "NFV9_logging i_vrf %d, Invalid [v4_addr 0x%x port %d]\n",
1042                   i_vrf,
1043                   (nfv9_conf.ipv4_address),
1044                   (nfv9_conf.port));
1045               goto done;    
1046         }
1047
1048         nfv9_server_info_t new_server_info;
1049         memset(&new_server_info, 0, sizeof(nfv9_server_info_t));
1050         new_server_info.ipv4_address =
1051                 nfv9_conf.ipv4_address;
1052         new_server_info.port =
1053                 (nfv9_conf.port);
1054         new_server_info.refresh_rate =
1055             (nfv9_conf.refresh_rate);
1056         /*
1057          * Store the timeout in seconds.  User configures it in minutes
1058          */
1059         new_server_info.timeout_rate =
1060             60*(nfv9_conf.timeout_rate);
1061         if (found && my_nfv9_logging_info) {
1062             /*
1063              * Entry already present, change it
1064              */
1065             my_nfv9_logging_info->max_length_minus_max_record_size =
1066                 nfv9_get_max_length_minus_max_record_size(
1067                     ((nfv9_conf.path_mtu)));
1068         } else {
1069             pool_get(cnat_nfv9_logging_info_pool, my_nfv9_logging_info);
1070             memset(my_nfv9_logging_info, 0, sizeof(*my_nfv9_logging_info));
1071             my_nfv9_logging_info->server_index = EMPTY;
1072             my_nfv9_logging_info->nfv9_logging_next_index = EMPTY;
1073             /*
1074              * Make the current and head logging context indeices as EMPTY.
1075              * When first logging happens, these get set correctly
1076              */
1077             my_nfv9_logging_info->current_logging_context = NULL;
1078             my_nfv9_logging_info->queued_logging_context  = NULL;
1079 #if 0
1080             my_nfv9_logging_info->f  = NULL;
1081             my_nfv9_logging_info->to_next  = NULL;
1082             output_node =  vlib_get_node_by_name (vm, (u8 *) "ip4-input");
1083             my_nfv9_logging_info->ip4_input_node_index = output_node->index;
1084             printf("ip4_input_node_index %d\n", my_nfv9_logging_info->ip4_input_node_index);
1085 #endif
1086             my_nfv9_logging_info->i_vrf    = i_vrf;
1087             my_nfv9_logging_info->i_vrf_id = i_vrf_id;
1088             my_nfv9_logging_info->max_length_minus_max_record_size =
1089             nfv9_get_max_length_minus_max_record_size(
1090                     nfv9_conf.path_mtu);
1091
1092          /* my_nfv9_logging_info will have a copy of logging_policy
1093           * because, it is quite possible that nfv9 config arrives before
1094           * the corresponding vrfmap is initialized. In such cases
1095           * this copy will be used to update the vrfmap entry
1096           */
1097             my_nfv9_logging_info->logging_policy = nfv9_conf.session_logging;
1098
1099             if (nfv9_conf.nfv9_global_collector) {
1100                 cnat_nfv9_global_info.cnat_nfv9_global_collector_index =
1101                     my_nfv9_logging_info - cnat_nfv9_logging_info_pool;
1102
1103                 pool_foreach (my_vrfmap, cnat_map_by_vrf, ({
1104                             if (my_vrfmap->nfv9_logging_index == EMPTY) {
1105                                 my_vrfmap->nfv9_logging_index =
1106                                     cnat_nfv9_global_info.cnat_nfv9_global_collector_index;
1107                             }
1108                         }));
1109             } else {
1110                 u32 my_vrfmap_found = 0;
1111
1112                 FIND_MY_VRF_USING_I_VRF_ID
1113                 my_vrfmap = my_vrfmap_temp;
1114                     if (my_vrfmap_found) {
1115                         if(my_vrfmap->nfv9_logging_index == EMPTY) {
1116                             my_vrfmap->nfv9_logging_index =
1117                                 my_nfv9_logging_info - cnat_nfv9_logging_info_pool;
1118                             // my_vrfmap->nf_logging_policy = mp->session_logging;
1119                         } else {
1120                             cnat_nfv9_logging_info_t *my_nfv9_logging_info_temp = cnat_nfv9_logging_info_pool + my_vrfmap->nfv9_logging_index;
1121                             while(my_nfv9_logging_info_temp->nfv9_logging_next_index != EMPTY){
1122                                 my_nfv9_logging_info_temp = cnat_nfv9_logging_info_pool + my_nfv9_logging_info_temp->nfv9_logging_next_index;
1123                             }
1124                             my_nfv9_logging_info_temp->nfv9_logging_next_index = my_nfv9_logging_info - cnat_nfv9_logging_info_pool;
1125                         }
1126                     }
1127             }
1128         }
1129
1130         /* Update logging policy */
1131         my_nfv9_logging_info->logging_policy = nfv9_conf.session_logging;
1132         if (nfv9_conf.nfv9_global_collector) {
1133                 if(PLATFORM_DBL_SUPPORT) {
1134                     pool_foreach (my_vrfmap, cnat_map_by_vrf, ({
1135                         if (my_vrfmap->nfv9_logging_index ==
1136                     cnat_nfv9_global_info.cnat_nfv9_global_collector_index) {
1137                     my_vrfmap->nf_logging_policy = nfv9_conf.session_logging;
1138                 }
1139                     }));
1140                 } else {
1141                         nfv9_conf.rc = CNAT_ERR_NO_SESSION_DB;
1142                 }
1143         } else {
1144                 if(PLATFORM_DBL_SUPPORT) {
1145                         u32 my_vrfmap_found = 0;
1146                         my_vrfmap_temp = NULL;
1147                         FIND_MY_VRF_USING_I_VRF_ID
1148                         my_vrfmap = my_vrfmap_temp;
1149                         if (my_vrfmap_found) {
1150                           //    my_vrfmap->nf_logging_policy = mp->session_logging;
1151                         }
1152                 } else {
1153                         nfv9_conf.rc = CNAT_ERR_NO_SESSION_DB;
1154                 }
1155         }
1156         u8  nfv9_logging_policy = 0;
1157         u32 my_vrfmap_found = 0;
1158         my_vrfmap_temp = NULL;
1159         FIND_MY_VRF_USING_I_VRF_ID
1160         my_vrfmap = my_vrfmap_temp;
1161             if (my_vrfmap_found) {
1162                 u32 index_curr = my_vrfmap->nfv9_logging_index;
1163                 cnat_nfv9_logging_info_t *my_nfv9_logging_info_temp;
1164                 while(index_curr != EMPTY) {
1165                     my_nfv9_logging_info_temp = cnat_nfv9_logging_info_pool + index_curr;
1166                     nfv9_logging_policy = nfv9_logging_policy || my_nfv9_logging_info_temp->logging_policy;
1167                     index_curr = (cnat_nfv9_logging_info_pool + index_curr)->nfv9_logging_next_index;
1168                 }
1169                 my_vrfmap->nf_logging_policy = nfv9_logging_policy;
1170             }
1171             //vlib_cli_output(vm,"Netflow logging policy = %d\n", my_vrfmap->nf_logging_policy);
1172             if(nfv9_get_server_instance(my_nfv9_logging_info, &new_server_info)
1173                != CNAT_SUCCESS) {
1174                 vlib_cli_output(vm, "Error to get server instance");
1175                 nfv9_conf.rc = CNAT_ERR_PARSER;
1176                 goto done;
1177             }
1178         nfv9_init_pkt_sent_data(my_nfv9_logging_info);
1179
1180         vlib_cli_output(vm,"Adding NFv9 Logging Succeeded\n");
1181         nfv9_configured = 1;
1182
1183     } else {
1184     /*Delete path*/
1185         if (found) {
1186             /* if found entry then we need to overwrite the my_nfv9_logging_info_tmp
1187              * to my_nfv9_logging_info
1188              */
1189             my_nfv9_logging_info = my_nfv9_logging_info_tmp;
1190             if (i_vrf == INVALID_UIDX) {
1191                 /*
1192                  * We are deleting a global collector.  Mark the collectors
1193                  * in those VRFs using the global collector
1194                  */
1195                 pool_foreach (my_vrfmap, cnat_map_by_vrf, ({
1196                             if (my_vrfmap->nfv9_logging_index ==
1197                                 cnat_nfv9_global_info.cnat_nfv9_global_collector_index) {
1198                                 my_vrfmap->nfv9_logging_index = EMPTY;
1199                             }
1200                         }));
1201
1202                 cnat_nfv9_global_info.cnat_nfv9_global_collector_index = EMPTY;
1203             } else {
1204                 u32 my_vrfmap_found = 0;
1205                 my_vrfmap_temp = NULL;
1206                 FIND_MY_VRF_USING_I_VRF_ID
1207                 my_vrfmap = my_vrfmap_temp;
1208                     if (my_vrfmap_found) {
1209                         // my_vrfmap->nfv9_logging_index = cnat_nfv9_global_info.cnat_nfv9_global_collector_index;
1210                     }
1211             }
1212             if (my_nfv9_logging_info->queued_logging_context ||
1213                 my_nfv9_logging_info->current_logging_context) {
1214                 /*
1215                  * If there is a pending context:
1216                  * Set the deleted flag to 1.  This will ensure
1217                  * that the logging info structure gets freed after any
1218                  * pending packet get sent
1219                  */
1220                 my_nfv9_logging_info->deleted = 1;
1221             } else {
1222                 /*
1223                  * No pending context, just free the logging info structure
1224                  */
1225                 u32  index = my_nfv9_logging_info - cnat_nfv9_logging_info_pool;
1226                 if(index == my_vrfmap->nfv9_logging_index) {
1227                     /* Deleting the first sever */
1228                     my_vrfmap->nfv9_logging_index = my_nfv9_logging_info->nfv9_logging_next_index;
1229                     /* if(my_nfv9_logging_info->nfv9_logging_next_index != EMPTY){
1230                         my_vrfmap->nf_logging_policy = (cnat_nfv9_logging_info_pool + my_nfv9_logging_info->nfv9_logging_next_index)->logging_policy;
1231                     } else {
1232                         my_vrfmap->nf_logging_policy = EMPTY;
1233                     }*/
1234                 } else {
1235                     u32 index_curr = my_vrfmap->nfv9_logging_index;
1236                     u32 index_prev = EMPTY;
1237                     while(index_curr != EMPTY) {
1238                         index_prev = index_curr;
1239                         index_curr = (cnat_nfv9_logging_info_pool + index_curr)->nfv9_logging_next_index;
1240                         if(index == index_curr)
1241                         {
1242                             (cnat_nfv9_logging_info_pool + index_prev)->nfv9_logging_next_index = (cnat_nfv9_logging_info_pool + index_curr)->nfv9_logging_next_index;
1243                             break;
1244                         }
1245                     }
1246                 }
1247                 nfv9_delete_server_info(my_nfv9_logging_info);
1248                 pool_put(cnat_nfv9_logging_info_pool, my_nfv9_logging_info);
1249             }
1250
1251             vlib_cli_output(vm, "Deleting NFv9 Logging Succeeded\n");
1252             /* 
1253              * Search across all vrf and check if nfv9 logging is configured.
1254              */ 
1255             nfv9_configured = 0;
1256             pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info_pool, ({
1257                  nfv9_configured = 1;
1258                  break;
1259             }));
1260         } else {
1261             nfv9_conf.rc = CNAT_NO_CONFIG;
1262             vlib_cli_output(vm, "Add NFv9 Logging Failed (2) Non Existent vrf %d\n",
1263                                      i_vrf);
1264
1265         }
1266         u8  nfv9_logging_policy = 0;
1267         u32 my_vrfmap_found = 0;
1268         my_vrfmap_temp = NULL;
1269         FIND_MY_VRF_USING_I_VRF_ID
1270         my_vrfmap = my_vrfmap_temp; 
1271             if (my_vrfmap_found) {
1272                 u32 index_curr = my_vrfmap->nfv9_logging_index;
1273                 cnat_nfv9_logging_info_t *my_nfv9_logging_info_temp;
1274                 while(index_curr != EMPTY) {
1275                     my_nfv9_logging_info_temp = cnat_nfv9_logging_info_pool + index_curr;
1276                     nfv9_logging_policy = nfv9_logging_policy || my_nfv9_logging_info_temp->logging_policy;
1277                     index_curr = (cnat_nfv9_logging_info_pool + index_curr)->nfv9_logging_next_index;
1278                 }
1279                 my_vrfmap->nf_logging_policy = nfv9_logging_policy;
1280             }
1281         printf("After deleting the netflow server,Netflow logging policy = %d\n", my_vrfmap->nf_logging_policy);
1282     }
1283
1284 done:
1285     return 0;
1286 }
1287
1288 /* config CLIs */
1289 VLIB_CLI_COMMAND (set_vcgn_map_command) = {
1290     .path = "set vcgn map",
1291     .short_help = "set vcgn map <lo-address> [- <hi-address>]",
1292     .function = set_vcgn_map_command_fn,
1293 };
1294
1295 VLIB_CLI_COMMAND (set_vcgn_inside_command) = {
1296     .path = "set vcgn inside",
1297     .short_help = "set vcgn inside <inside intfc> outside <outside intfc>",
1298     .function = set_vcgn_inside_command_fn,
1299 };
1300
1301 VLIB_CLI_COMMAND (set_vcgn_tcp_timeout_command) = {
1302     .path = "set vcgn tcp timeout",
1303     .short_help = "set vcgn tcp timeout active <1-65535> init <1-65535>",
1304     .function = set_vcgn_tcp_timeout_command_fn,
1305 };
1306
1307 VLIB_CLI_COMMAND (set_vcgn_udp_timeout_command) = {
1308     .path = "set vcgn udp timeout",
1309     .short_help = "set vcgn udp timeout active <1-65535> init <1-65535>",
1310     .function = set_vcgn_udp_timeout_command_fn,
1311 };
1312
1313 VLIB_CLI_COMMAND (set_vcgn_icmp_timeout_command) = {
1314     .path = "set vcgn icmp timeout",
1315     .short_help = "set vcgn icmp timeout <1-65535>",
1316     .function = set_vcgn_icmp_timeout_command_fn,
1317 };
1318
1319 VLIB_CLI_COMMAND (set_vcgn_protocol_default_timeout_command) = {
1320     .path = "set vcgn default timeout",
1321     .short_help = "set vcgn default timeout protocol <tcp/udp/icmp>",
1322     .function = set_vcgn_protocol_default_timeout_command_fn,
1323 };
1324
1325 VLIB_CLI_COMMAND (set_vcgn_dynamic_port_start_range_command) = {
1326     .path = "set vcgn dynamic port start",
1327     .short_help = "set vcgn dynamic port start <1-65535>",
1328     .function = set_vcgn_dynamic_port_start_range_command_fn,
1329 };
1330
1331 VLIB_CLI_COMMAND (set_vcgn_port_limit_command) = {
1332     .path = "set vcgn port limit",
1333     .short_help = "set vcgn port limit <1-65535>",
1334     .function = set_vcgn_port_limit_command_fn,
1335 };
1336
1337 VLIB_CLI_COMMAND (set_vcgn_nfv9_logging_cofig_command) = {
1338     .path = "set vcgn nfv9",
1339     .short_help = "set vcgn nfv9 [del] server <ip-addr> port <port> [refresh-rate <n>] [timeout <n>] [pmtu <n>]",
1340     .function = set_vcgn_nfv9_logging_cofig_command_fn,
1341 };
1342
1343
1344 /* show CLIs */
1345 VLIB_CLI_COMMAND (show_vcgn_config_command) = {
1346     .path = "show vcgn config",
1347     .short_help = "show vcgn config",
1348     .function = show_vcgn_config_command_fn,
1349 };
1350
1351 VLIB_CLI_COMMAND (show_vcgn_stat_command) = {
1352     .path = "show vcgn statistics",
1353     .short_help = "show vcgn statistics",
1354     .function = show_vcgn_stats_command_fn,
1355 };
1356
1357 VLIB_CLI_COMMAND (show_vcgn_inside_translation_command) = {
1358     .path = "show vcgn inside-translation",
1359     .short_help = "show vcgn inside-translation protocol <tcp/udp/icmp> "
1360                   "inside-addr <ip-addr> [start-port <n>] [end-port <n>]",
1361     .function = show_vcgn_inside_translation_command_fn,
1362 };
1363
1364 VLIB_CLI_COMMAND (show_vcgn_outside_translation_command) = {
1365     .path = "show vcgn outside-translation",
1366     .short_help = "show vcgn outside-translation protocol <tcp/udp/icmp> "
1367                   "outside-addr <ip-addr> [start-port <n>] [end-port <n>]",
1368     .function = show_vcgn_outside_translation_command_fn,
1369 };
1370
1371 static clib_error_t *
1372 vcgn_init (vlib_main_t * vm)
1373 {
1374   clib_error_t * error = 0;
1375
1376   if ((error = vlib_call_init_function 
1377        (vm, vcgn_classify_init)))
1378     return error;
1379   if ((error = vlib_call_init_function 
1380        (vm, cnat_ipv4_udp_inside_input_init)))
1381     return error;
1382   if ((error = vlib_call_init_function 
1383        (vm, cnat_ipv4_udp_outside_input_init)))
1384     return error;
1385   if ((error = vlib_call_init_function 
1386        (vm, cnat_ipv4_udp_inside_input_exc_init)))
1387     return error;
1388   if ((error = vlib_call_init_function 
1389        (vm, cnat_db_scanner_init)))
1390     return error;
1391   if ((error = vlib_call_init_function 
1392        (vm, cnat_ipv4_tcp_inside_input_init)))
1393     return error;
1394   if ((error = vlib_call_init_function 
1395        (vm, cnat_ipv4_tcp_inside_input_exc_init)))
1396     return error;
1397   if ((error = vlib_call_init_function 
1398        (vm, cnat_ipv4_tcp_outside_input_init)))
1399     return error;
1400   if ((error = vlib_call_init_function 
1401        (vm, cnat_ipv4_icmp_q_inside_input_init)))
1402     return error;
1403   if ((error = vlib_call_init_function 
1404        (vm, cnat_ipv4_icmp_q_inside_input_exc_init)))
1405     return error;
1406   if ((error = vlib_call_init_function 
1407        (vm, cnat_ipv4_icmp_q_outside_input_init)))
1408     return error;
1409   if ((error = vlib_call_init_function 
1410        (vm, cnat_ipv4_icmp_e_inside_input_init)))
1411     return error;
1412   if ((error = vlib_call_init_function 
1413        (vm, cnat_ipv4_icmp_e_outside_input_init)))
1414     return error;
1415
1416   return error;
1417 }
1418
1419 VLIB_INIT_FUNCTION (vcgn_init);