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