aboutsummaryrefslogtreecommitdiffstats
path: root/vpp/plugins/vcgn-plugin/vcgn
diff options
context:
space:
mode:
Diffstat (limited to 'vpp/plugins/vcgn-plugin/vcgn')
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/README100
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cgn_bitmap.h133
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cgse_defs.h88
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_bulk_port.c964
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_bulk_port.h157
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_bulk_port_defs.h57
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_cli.h206
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_cli_handler.c961
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_common_api.h22
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_config.c77
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_config.h582
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_config_api.h46
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_db.h701
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_db_scanner.c493
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_db_v2.c3806
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_debug_msg_handler.c1780
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_global.c79
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_global.h87
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp.h60
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_error_inside_input.c476
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_error_outside_input.c452
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_inside_input.c404
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_inside_input_exception.c235
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_outside_input.c381
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_inside_input.c424
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_inside_input_exceptions.c314
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_outside_input.c382
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp.h41
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_inside_input.c508
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_inside_input_exceptions.c283
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_outside_input.c605
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_log_api.h114
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_log_common.h79
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_logging.c3500
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_logging.h1091
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_pcp_server.h398
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_ports.c1113
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_ports.h208
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_show.c810
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_show_api.h40
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_show_response.h580
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_syslog.c1787
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_syslog.h190
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_util.c2256
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_v4_ftp_alg.h133
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_v4_functions.c364
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_v4_functions.h342
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_v4_pptp_alg.h150
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_v4_tcp_in2out_stages.c679
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_va_db.c286
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/cnat_va_db.h121
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/dslite_db.h170
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/dslite_defs.h336
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/index_list.c336
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/index_list.h118
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/nat64_db.h480
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/nat64_defs.h576
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/nat64_tcp_sm.h91
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/platform_common.h136
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/platform_common_override.h304
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/spp_ctx.h76
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/spp_platform_trace_log.c989
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/spp_platform_trace_log.h358
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/spp_timers.h139
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/tcp_header_definitions.h1582
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/vcgn_classify.c1508
-rw-r--r--vpp/plugins/vcgn-plugin/vcgn/vcgn_db.h117
67 files changed, 36461 insertions, 0 deletions
diff --git a/vpp/plugins/vcgn-plugin/vcgn/README b/vpp/plugins/vcgn-plugin/vcgn/README
new file mode 100644
index 00000000..9b903967
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/README
@@ -0,0 +1,100 @@
+ =================================
+ CARRIER GRADE NAT - NAT44 README
+ =================================
+
+What is implemented:
+====================
+* NAT44 UDP, TCP, ICMP protocols
+* Show and config commands for various parameters for the same
+* NF9 logging is implemented but is not tested
+
+What is not implemented:
+=========================
+* TCP MSS
+* TCP refresh direction
+* Static port forwarding
+* Syslog support
+* Destination based logging or session logging
+* None of the ALGs
+* Performance optimization
+* Binary APIs, suitable for configuring the feature from netconf/restconf/yang
+* Support for VLANs
+
+Setup
+=====
+
+ +--------------+
++------------+ GEb/0/0 | |
+| Tester +-------------->+ vCGN/vPE-f |
+| +<--------------+ VM in UCS |
++------------+ GE13/0/0 | |
+ +--------------+
+
+Configure Interfaces and add routes in vPE-f
+=============================================
+set int ip address GigabitEthernetb/0/0 10.4.5.2/24
+set int state GigabitEthernetb/0/0 up
+set int ip address GigabitEthernet13/0/0 20.4.5.2/24
+set int state GigabitEthernet13/0/0 up
+ip route add 4.4.4.0/24 via GigabitEthernet13/0/0
+ip route add 1.2.3.0/24 via GigabitEthernetb/0/0 show ip fib
+
+Configure vCGN NAT44 for UDP/TCP/ICMP
+=======================================
+set vcgn inside GigabitEthernetb/0/0 outside GigabitEthernet13/0/0
+set vcgn port limit 65535 set vcgn dynamic port start 5641
+set vcgn map 10.1.1.0 - 10.1.1.31 set vcgn tcp timeout active 65535 init 65535
+set vcgn udp timeout active 65535 init 65535 set vcgn icmp timeout 65535
+
+Set ARP entries for CGN to Tester
+==================================
+set ip arp GigabitEthernet13/0/0 4.4.4.4 11:22:33:44:55:00
+set ip arp GigabitEthernetb/0/0 1.2.3.0 11:22:33:44:55:10
+set ip arp GigabitEthernetb/0/0 1.2.3.1 11:22:33:44:55:12
+set ip arp GigabitEthernetb/0/0 1.2.3.2 11:22:33:44:55:13
+set ip arp GigabitEthernetb/0/0 1.2.3.3 11:22:33:44:55:14
+set ip arp GigabitEthernetb/0/0 1.2.3.4 11:22:33:4e:55:11
+set ip arp GigabitEthernetb/0/0 1.2.3.5 11:22:33:44:55:15
+set ip arp GigabitEthernetb/0/0 1.2.3.6 11:22:33:44:55:16
+set ip arp GigabitEthernetb/0/0 1.2.3.7 11:22:33:44:55:17
+set ip arp GigabitEthernetb/0/0 1.2.3.8 11:22:33:44:55:18
+set ip arp GigabitEthernetb/0/0 1.2.3.9 11:22:33:44:55:19
+set ip arp GigabitEthernetb/0/0 1.2.3.10 11:22:33:44:55:1a
+set ip arp GigabitEthernetb/0/0 1.2.3.11 11:22:33:44:55:1b
+set ip arp GigabitEthernetb/0/0 1.2.3.12 11:22:33:44:55:1c
+set ip arp GigabitEthernetb/0/0 1.2.3.13 11:22:33:44:55:1d
+set ip arp GigabitEthernetb/0/0 1.2.3.14 11:22:33:44:55:1e
+set ip arp GigabitEthernetb/0/0 1.2.3.15 11:22:33:44:55:1f
+set ip arp GigabitEthernetb/0/0 1.2.3.16 11:22:33:44:50:01
+set ip arp GigabitEthernetb/0/0 1.2.3.17 11:22:33:44:51:01
+set ip arp GigabitEthernetb/0/0 1.2.3.18 11:22:33:44:52:01
+set ip arp GigabitEthernetb/0/0 1.2.3.19 11:22:33:44:53:01
+set ip arp GigabitEthernetb/0/0 1.2.3.20 11:22:33:44:54:02
+set ip arp GigabitEthernetb/0/0 1.2.3.21 11:22:33:44:55:01
+set ip arp GigabitEthernetb/0/0 1.2.3.22 11:22:33:44:56:02
+set ip arp GigabitEthernetb/0/0 1.2.3.23 11:22:33:44:57:00
+set ip arp GigabitEthernetb/0/0 1.2.3.24 11:22:33:44:58:02
+set ip arp GigabitEthernetb/0/0 1.2.3.25 11:22:33:44:59:03
+set ip arp GigabitEthernetb/0/0 1.2.3.26 11:22:33:44:5a:01
+set ip arp GigabitEthernetb/0/0 1.2.3.27 11:22:33:44:5b:02
+set ip arp GigabitEthernetb/0/0 1.2.3.28 11:22:33:44:5c:03
+set ip arp GigabitEthernetb/0/0 1.2.3.29 11:22:33:44:5d:04
+set ip arp GigabitEthernetb/0/0 1.2.3.30 11:22:33:44:5e:05
+set ip arp GigabitEthernetb/0/0 1.2.3.31 11:22:33:44:5f:06
+
+
+Show commands
+=============
+show vcgn config
+show vcgn statistics
+show node counters
+show interface
+
+Show commands to show translations
+==================================
+show vcgn inside-translation protocol tcp inside-addr 1.2.3.4 start-port 5641 end-port 5645
+show vcgn outside-translation protocol tcp outside-addr 10.1.1.31 start-port 7000 end-port 8000
+show vcgn inside-translation protocol icmp inside-addr 1.2.3.4 start-port 7000 end-port 8000
+show vcgn outside-translation protocol icmp outside-addr 10.1.1.31 start-port 7000 end-port 8000
+
+
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cgn_bitmap.h b/vpp/plugins/vcgn-plugin/vcgn/cgn_bitmap.h
new file mode 100644
index 00000000..6c46b75a
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cgn_bitmap.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Modifications to this file
+ * Copyright (c) 2006-2009 by cisco Systems, Inc.
+ * All rights reserved.
+ */
+
+/*
+ Copyright (c) 2001, 2002, 2003, 2005 Eliot Dresselhaus
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef __CGN_BITMAP_H__
+#define __CGN_BITMAP_H__
+
+/* Bitmaps built as vectors of machine words. */
+
+#include <string.h>
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/vec.h>
+#include <vppinfra/random.h>
+
+#define clib_bitmap_dup(v) vec_dup(v)
+#define clib_bitmap_free(v) vec_free(v)
+#define clib_bitmap_bytes(v) vec_bytes(v)
+#define clib_bitmap_zero(v) vec_zero(v)
+
+/* Allocate bitmap with given number of bits. */
+#define clib_bitmap_alloc(v,n_bits) \
+ v = vec_new (uword, ((n_bits) + BITS (uword) - 1) / BITS (uword))
+
+/* Sets given bit. Returns old value. */
+static inline uword
+cgn_clib_bitmap_set_no_check (uword * a, uword i)
+{
+ uword i0 = i / BITS (a[0]);
+ uword bit = (uword) 1 << (i % BITS (a[0]));
+ uword ai;
+
+/* ASSERT (i0 < vec_len (a)); */
+ ai = a[i0];
+ a[i0] = ai | bit;
+
+ return (ai & bit) != 0;
+}
+
+/* Clears given bit. Returns old value. */
+static inline
+uword cgn_clib_bitmap_clear_no_check (uword * a, uword i)
+{
+ uword i0 = i / BITS (a[0]);
+ uword bit = (uword) 1 << (i % BITS (a[0]));
+ uword ai;
+
+/* ASSERT (i0 < vec_len (a)); */
+ ai = a[i0];
+ a[i0] = ai & ~bit;
+
+ return (ai & bit) != 0;
+}
+
+/* Gets num_bits from ai start at start. assume that all bits are
+ * in the same uword.
+ */
+static inline uword cgn_clib_bitmap_get_bits (uword *ai, u16 start,
+ unsigned char num_bits)
+{
+ uword i0 = start / BITS (ai[0]);
+ uword i1 = start % BITS (ai[0]);
+ uword result = ai[i0] >> i1;
+ if(num_bits >= BITS(ai[0])) return result;
+ /* Else, we have to trim the bits */
+ result = result & (((uword)1 << num_bits) - 1);
+ return result;
+}
+
+/* Check if all of the bits from start to numb_bits are avaiable */
+static inline uword cgn_clib_bitmap_check_if_all (uword *ai, u16 start,
+ i16 num_bits)
+{
+ /* Now check if any bits are zero.. if yes, return false */
+ uword bitmask;
+ if(num_bits >= BITS(ai[0])) {
+ /* assume that its going to be multiples of BUTS(ai[0]) */
+ uword i0 = start / BITS (ai[0]);
+ bitmask = ~0; /* set all bits to 1 */
+ do {
+ if(ai[i0] ^ bitmask) return 0;
+ num_bits = num_bits - BITS (ai[0]);
+ i0++;
+ } while (num_bits > 0);
+ return 1;
+ }
+ else {
+ uword result = cgn_clib_bitmap_get_bits (ai, start, num_bits);
+ bitmask = ((uword)1 << num_bits) -1; /* set only num_bits */
+ return (!(result ^ bitmask));
+ }
+}
+
+#endif
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cgse_defs.h b/vpp/plugins/vcgn-plugin/vcgn/cgse_defs.h
new file mode 100644
index 00000000..08255875
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cgse_defs.h
@@ -0,0 +1,88 @@
+/*
+ *------------------------------------------------------------------
+ * cgse_defs.h - CGSE specific definiitions
+ *
+ * Copyright (c) 2007-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CGSE_DEFS_H__
+#define __CGSE_DEFS_H__
+
+#include "spp_platform_common.h"
+#include <cnat_cli.h>
+
+
+#define CGSE_SVI_TYPE_CNAT 1
+#define CGSE_SVI_TYPE_XLAT 2
+#define CGSE_SVI_TYPE_NAT64_STATEFUL 3
+#define CGSE_SVI_TYPE_V6RD 4
+#define CGSE_SVI_TYPE_INFRA 5
+#define CGSE_SVI_TYPE_DS_LITE 7
+#define CGSE_SVI_TYPE_MAPE 9
+
+#define CGSE_SET_TX_PKT_TYPE(type) PLATFORM_SET_CTX_RU_TX_PKT_TYPE(ctx, type)
+
+#define CGSE_INVALID_UIDX 0xffff /*invalid svi app uidb index */
+#define CGSE_INVALID_VRFID 0xffffffff /*invalid vrf id */
+
+#define CGSE_VRF_MASK 0x3fff
+#define CGSE_MAX_VRFMAP_ENTRIES (CGSE_VRF_MASK + 1)
+
+#define CGSE_VRFMAP_ENTRY_INVALID 0xffff
+
+
+#define CGSE_INVALID_CGSE_ID (0)
+
+#define CGSE_TABLE_ENTRY_DELETED 0
+#define CGSE_TABLE_ENTRY_ACTIVE 1
+#define CGSE_TABLE_ENTRY_DORMANT 2
+#define CGSE_TABLE_ENTRY_INVALID_UIDB 3
+
+
+#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF1(level, a) \
+ if (cgse_config_debug_level > level) printf(a);
+
+#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF2(level, a, b) \
+ if (cgse_config_debug_level > level) printf(a, b);
+
+#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF3(level, a, b, c) \
+ if (cgse_config_debug_level > level) printf(a, b, c);
+
+#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF4(level, a, b, c, d) \
+ if (cgse_config_debug_level > level) printf(a, b, c, d);
+
+#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF5(level, a, b, c, d, e) \
+ if (cgse_config_debug_level > level) printf(a, b, c, d, e);
+
+#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF6(level, a, b, c, d, e, f) \
+ if (cgse_config_debug_level > level) printf(a, b, c, d, e, f);
+
+#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF7(level, a, b, c, d, e, f, g) \
+ if (cgse_config_debug_level > level) printf(a, b, c, d, e, f, g);
+
+#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF8(level, a, b, c, d, e, f, g, h) \
+ if (cgse_config_debug_level > level) printf(a, b, c, d, e, f, g, h);
+
+#define CGSE_CONFIG_HANDLER_DEBUG_PRINTF9(level, a, b, c, d, e, f, g, h, i) \
+ if (cgse_config_debug_level > level) printf(a, b, c, d, e, f, g, h, i);
+
+extern u16 *cgse_uidb_index_cgse_id_mapping_ptr;
+
+#define CGSE_ADD_UIDB_INDEX_CGSE_ID_MAPPING(uidb_index, cgse_id) \
+ *(cgse_uidb_index_cgse_id_mapping_ptr + uidb_index) = cgse_id;
+
+extern u8 my_instance_number;
+
+#endif
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_bulk_port.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_bulk_port.c
new file mode 100644
index 00000000..d8894eb8
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_bulk_port.c
@@ -0,0 +1,964 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_bulk_ports.c - wrappers for bulk port allocation
+ *
+ * Copyright (c) 2011-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/error.h>
+#include <vnet/buffer.h>
+#include <vppinfra/vec.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/pool.h>
+#include <vppinfra/bitmap.h>
+
+#include "cnat_db.h"
+#include "cnat_config.h"
+#include "cnat_global.h"
+#include "cnat_logging.h"
+#include "spp_timers.h"
+#include "platform_common.h"
+#include "cgn_bitmap.h"
+#include "spp_platform_trace_log.h"
+#include "cnat_ports.h"
+
+#ifndef NO_BULK_LOGGING
+
+#define PORT_TO_CACHE(y, z) ((y)/(z))
+/* The last bit (MSB) is used to indicate whether the cache entry is full */
+#define CACHE_TO_PORT(x, z) (((x)& 0x7FFF) * (z))
+#define IS_CACHE_ENTRY_FULL(x) ((x) & 0x8000)
+#define MARK_CACHE_ENTRY_AS_FULL(x) ((x) = ((x) | 0x8000))
+#define UNMARK_CACHE_ENTRY_AS_FULL(x) ((x) = ((x) & 0x7FFF))
+#define CACHE_ENTRY_WITHOUT_FULL_STAT(x) ((x) & 0x7FFF)
+
+
+#define NUM_BULK_CHECK 128 /* max number of previous chache to check.
+ * somewhat orbirtrary.. assume 64 as bulk size.. can handle up
+ * to 128*64 ports allocated by a single subscriber */
+
+/* #define DEBUG_BULK_PORT 1 */
+/* #define DEBUG_BULK_PORT_DETAIL 1 */
+#define HAVE_BULK_PORT_STATS 1
+
+#ifdef HAVE_BULK_PORT_STATS
+static uword bulk_cache_hit_count;
+static uword bulk_port_use_count;
+static uword bulk_port_alloc_count;
+static uword mapped_port_alloc_count;
+#endif /* HAVE_BULK_PORT_STATS */
+
+static u32 bulk_port_rand_across;
+
+void show_bulk_port_allocation(u16 in_vrfid, u32 inside_ip)
+{
+ cnat_db_key_bucket_t u_ki;
+ cnat_user_db_entry_t *udb;
+ int i;
+ u32 head;
+ cnat_main_db_entry_t *db = NULL;
+ i16 printed_so_far = 0; /* entries printed so far */
+ u16 prev_bulks[NUM_BULK_CHECK];
+ cnat_vrfmap_t *my_vrfmap = 0;
+ cnat_vrfmap_t *vrfmap = 0;
+ bulk_alloc_size_t bulk_size;
+
+ u_ki.k.k.vrf = in_vrfid;
+ u_ki.k.k.ipv4 = inside_ip;
+ u_ki.k.k.port = 0;
+
+ PLATFORM_DEBUG_PRINT("Searching for user %x in invrf %d\n",
+ inside_ip, in_vrfid);
+ udb = cnat_user_db_lookup_entry(&u_ki);
+ if(!udb) {
+ PLATFORM_DEBUG_PRINT("No such user\n"); return;
+ }
+
+ pool_foreach (vrfmap, cnat_map_by_vrf, ({
+ if(vrfmap->i_vrf == in_vrfid) {
+ my_vrfmap = vrfmap;
+ break;
+ }}));
+
+ if(!my_vrfmap) {
+ PLATFORM_DEBUG_PRINT("Vrf map not found\n");
+ return;
+ }
+ bulk_size = BULKSIZE_FROM_VRFMAP(my_vrfmap);
+
+ if(bulk_size == BULK_ALLOC_SIZE_NONE) {
+ PLATFORM_DEBUG_PRINT("Bulk allocation not enabled\n");
+ return;
+ }
+
+ PLATFORM_DEBUG_PRINT("\nBulk cache for subscriber 0x%x: ", inside_ip);
+ for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
+ PLATFORM_DEBUG_PRINT("%d , ",
+ CACHE_TO_PORT(udb->bulk_port_range_cache[i], bulk_size));
+ }
+ PLATFORM_DEBUG_PRINT("\nNon cached bulk allocation for subscriber 0x%x:\n",
+ inside_ip);
+ ASSERT(udb);
+ memset(prev_bulks, 0,sizeof(prev_bulks));
+
+ head = udb->translation_list_head_index;
+ if(PREDICT_FALSE(head == EMPTY)) {
+ return;
+ }
+ db = cnat_main_db + head;
+ while (1) {
+ /* skip static ports - static ports may not belong to bulk pool*/
+ if(db->out2in_key.k.port < cnat_static_port_range) goto next_entry;
+
+ u16 bm_index = PORT_TO_CACHE(db->out2in_key.k.port, bulk_size);
+
+ /*Check if we have already tested this bulk */
+ for(i=0; i < printed_so_far; i++) {
+ if(prev_bulks[i] == bm_index) goto next_entry;
+ }
+
+ /*Check if this base port is already part of cache */
+ for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
+ if(CACHE_ENTRY_WITHOUT_FULL_STAT(udb->bulk_port_range_cache[i])
+ == bm_index) {
+ goto next_entry;
+ }
+ }
+ /* this is not in chache already */
+ PLATFORM_DEBUG_PRINT("%d ", CACHE_TO_PORT(bm_index, bulk_size));
+ if(printed_so_far < NUM_BULK_CHECK) {
+ prev_bulks[printed_so_far] = bm_index;
+ printed_so_far++;
+ }
+
+next_entry:
+ db = cnat_main_db + db->user_ports.next;
+ /*
+ * its a circular list, so if we have reached the head again
+ * all the entries for that user have been read
+ */
+ if (db == (cnat_main_db + head)) {
+ break;
+ }
+ } /* while loop for db entries */
+
+ PLATFORM_DEBUG_PRINT("\n");
+ return;
+}
+
+void show_bulk_port_stats()
+{
+
+ cnat_vrfmap_t *my_vrfmap = 0;
+ PLATFORM_DEBUG_PRINT("Bulk size settings of each inside vrf ...\n");
+ pool_foreach (my_vrfmap, cnat_map_by_vrf, ({
+ PLATFORM_DEBUG_PRINT("vrf id %d, bulk size %d\n", my_vrfmap->i_vrf,
+ BULKSIZE_FROM_VRFMAP(my_vrfmap));
+ }));
+
+#ifdef HAVE_BULK_PORT_STATS
+ PLATFORM_DEBUG_PRINT("\nBulk port allocation, use and cache hit statistics\n");
+ PLATFORM_DEBUG_PRINT("Number of times bulk ports allocated %lld\n",
+ bulk_port_alloc_count);
+ PLATFORM_DEBUG_PRINT("Number of times pre-allocated ports used %lld\n",
+ bulk_port_use_count);
+ PLATFORM_DEBUG_PRINT(
+ "Number of times pre-allocated bulk port found from cache %lld\n",
+ bulk_cache_hit_count);
+ PLATFORM_DEBUG_PRINT(
+ "Number of times mapped port (static) allocations made %lld\n",
+ mapped_port_alloc_count);
+#else
+ PLATFORM_DEBUG_PRINT("\nNat44 bulk port statistics not turned on\n");
+#endif /* HAVE_BULK_PORT_STATS */
+}
+
+void clear_bulk_port_stats()
+{
+#ifdef HAVE_BULK_PORT_STATS
+ bulk_port_alloc_count = 0;
+ bulk_port_use_count = 0;
+ bulk_cache_hit_count = 0;
+ mapped_port_alloc_count = 0;
+#endif /* HAVE_BULK_PORT_STATS */
+ return;
+}
+
+void cnat_update_bulk_range_cache(cnat_user_db_entry_t *udb, u16 o_port,
+ bulk_alloc_size_t bulk_size)
+{
+ i16 i;
+ if(!udb) {
+#ifdef DEBUG_BULK_PORT
+ PLATFORM_DEBUG_PRINT("%s, null udb!\n", __func__);
+#endif
+ return;
+ }
+ if(BULK_ALLOC_SIZE_NONE == bulk_size) { /* no bulk logging */
+ return;
+ }
+
+ /* Take care of caching */
+ if(o_port & 0x1) {
+ o_port--;
+ }
+ if(PREDICT_FALSE(o_port <= 0)) {
+#ifdef DEBUG_BULK_PORT
+ PLATFORM_DEBUG_PRINT("%s invalid port: %d\n", __func__, o_port);
+#endif
+ return;
+ }
+
+ /* First preference is for the cache entry's that are not used yet */
+ for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
+ if(PREDICT_FALSE(
+ udb->bulk_port_range_cache[i] == (i16)BULK_RANGE_INVALID)) {
+ udb->bulk_port_range_cache[i] = PORT_TO_CACHE(o_port, bulk_size);
+ return;
+ }
+ }
+
+ /* Now check if any cache entry is full and if it can be replaced */
+ for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
+ if(PREDICT_FALSE(IS_CACHE_ENTRY_FULL(udb->bulk_port_range_cache[i]))) {
+ udb->bulk_port_range_cache[i] = PORT_TO_CACHE(o_port, bulk_size);
+ return;
+ }
+ }
+
+ return;
+}
+
+
+void cnat_port_free_v2_bulk (
+ cnat_portmap_v2_t *pm,
+ int index,
+ port_pair_t ptype,
+ u16 base_port,
+ cnat_user_db_entry_t *udb,
+ u16 static_port_range,
+ bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req)
+{
+ cnat_portmap_v2_t *my_pm;
+ i16 bm_index;
+ i16 i;
+ int unmark_full_status = 0;
+
+ *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
+
+ /* First free up the port */
+ cnat_port_free_v2(pm, index, ptype, base_port, static_port_range);
+ if(BULK_ALLOC_SIZE_NONE == bulk_size) /* no bulk logging */
+ return;
+ if(PREDICT_FALSE(!udb)) {
+#ifdef DEBUG_BULK_PORT
+ PLATFORM_DEBUG_PRINT("%s udb is null\n", __func__);
+#endif
+ }
+
+ if(PREDICT_FALSE(base_port < static_port_range)) {
+ return;
+ }
+ /* Now check if cache needs to be removed */
+ my_pm = pm + index;
+ base_port = base_port/bulk_size;
+ base_port = base_port * bulk_size; /*Align it to multiples of bulk_size */
+ if(PREDICT_TRUE(!cgn_clib_bitmap_check_if_all(
+ my_pm->bm, base_port, bulk_size))) {
+ *nfv9_log_req = CACHE_ALLOC_NO_LOG_REQUIRED;
+ unmark_full_status = 1;
+ /* One or more ports are still in use */
+ } else {
+ *nfv9_log_req = base_port; /* logging required now. indicate base port*/
+ }
+ bm_index = PORT_TO_CACHE(base_port, bulk_size);
+ /* Now check if this is in the cache */
+ for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
+ if(PREDICT_FALSE(
+ CACHE_ENTRY_WITHOUT_FULL_STAT(udb->bulk_port_range_cache[i]))
+ == bm_index) {
+ if(unmark_full_status) {
+ /* Unmark full stat.. if it was marked so..*/
+ UNMARK_CACHE_ENTRY_AS_FULL(udb->bulk_port_range_cache[i]);
+ } else {
+ udb->bulk_port_range_cache[i] = (i16)BULK_RANGE_INVALID;
+#ifdef DEBUG_BULK_PORT
+ PLATFORM_DEBUG_PRINT(
+ "Clearing cache for client 0x%x, bulk port %d\n",
+ my_pm->ipv4_address, base_port);
+#endif
+ }
+ break;
+ }
+ }
+ return;
+}
+
+
+/* Get suitable port from range */
+static i16 get_suiting_port_pos_from_range(cnat_portmap_v2_t *my_pm,
+ u16 bulk_start, i16 bulk_size, port_pair_t pair_type)
+{
+ i16 num_pos = 0, num_bits, iterations;
+ uword bulk_ports;
+ i16 inc = 0;
+ i16 num_uwords = bulk_size/BITS(my_pm->bm[0]);
+
+ if(PREDICT_FALSE(!num_uwords)) {
+ iterations = 0;
+ num_bits = bulk_size;
+ bulk_size = 0;
+ } else {
+ bulk_port_rand_across = randq1(bulk_port_rand_across);
+ iterations = bulk_port_rand_across % num_uwords;
+ num_bits = BITS(my_pm->bm[0]);
+ }
+
+ do {
+ bulk_ports = cgn_clib_bitmap_get_bits(my_pm->bm,
+ (bulk_start + iterations * BITS(my_pm->bm[0])), num_bits);
+#ifdef DEBUG_BULK_PORT_DETAIL
+ PLATFORM_DEBUG_PRINT("%s %d, bulk start %d, num_bits %d, ports %lld \n",
+ __func__, __LINE__, bulk_start, num_bits, bulk_ports);
+#endif /* DEBUG_BULK_PORT_DETAIL */
+ if(PREDICT_FALSE(!bulk_ports)) goto next_uword;
+ if(PREDICT_TRUE((pair_type == PORT_SINGLE)
+ || (pair_type == PORT_PAIR))) {
+ num_pos =0;
+ inc = 1;
+ } else if(pair_type == PORT_S_ODD) {
+ num_pos = 1;
+ inc = 2;
+ } else if(pair_type == PORT_S_EVEN) {
+ num_pos =0;
+ inc = 2;
+ }
+
+ for(; num_pos < num_bits; num_pos = num_pos + inc) {
+ if(!((bulk_ports >> num_pos) & 1))
+ continue; /* In use */
+ /* Check if the available port meets our
+ * criteria such as add, even, pair etc */
+ else if(PREDICT_FALSE(
+ (pair_type == PORT_PAIR) && ((num_pos & 0x1) ||
+ (!((bulk_ports >> (num_pos + 1)) & 1)))))
+ continue;
+ else break; /* Found one that meets the criteria */
+ }
+ if(num_pos < num_bits)
+ return (num_pos + iterations * BITS(my_pm->bm[0]));
+next_uword:
+ num_bits = BITS(my_pm->bm[0]);
+ bulk_size -= BITS(my_pm->bm[0]);
+ iterations++;
+ if(iterations >= num_uwords) iterations = 0;
+ } while (bulk_size > 0);
+
+ return -2; /* nothing found */
+}
+
+static cnat_errno_t try_bulk_port_from_non_cache(
+ cnat_user_db_entry_t *udb,
+ cnat_portmap_v2_t *my_pm,
+ port_pair_t pair_type,
+ bulk_alloc_size_t bulk_size,
+ u16 *port_available,
+ u16 static_port_range
+ )
+{
+ /****
+ 1. user should have existing translations.. otherwise, we wouldn't get here.
+ 2. For each, get the outside port. get the base port.
+ check if it is already in cache
+ 3. if not, we stand chance.
+ 4. Check for availability from this non cached pool.
+ 5. if found, repalce this with one of the cache that is invalid or full??
+ 6. if we are replacing the cache.. it has to be governed by user
+ preference on prefer oldest pool or prefer newest pool
+ ********/
+ u32 head;
+ cnat_main_db_entry_t *db = NULL;
+ u16 bulk_start; /* start point in 64 bitmap array to search for port */
+ i16 port_pos; /* indicates the position of available port in bulk */
+ i16 i; /* just a counter */
+ i16 attempts_so_far = 0; /* (futile-;) attemps so far..*/
+ u16 prev_bulks[NUM_BULK_CHECK];
+ ASSERT(udb);
+ memset(prev_bulks, 0,sizeof(prev_bulks));
+
+ head = udb->translation_list_head_index;
+ if(PREDICT_FALSE(head == EMPTY)) return CNAT_NO_PRE_ALLOCATED_BULK_PORTS;
+
+ db = cnat_main_db + head;
+ while (1) { //what should be the limit??
+
+ /* skip static ports - static ports may not belong to bulk pool*/
+ if(db->out2in_key.k.port < static_port_range) goto next_entry;
+
+ u16 bm_index = PORT_TO_CACHE(db->out2in_key.k.port, bulk_size);
+
+ /*Check if we have already tested this bulk */
+ for(i=0; i < attempts_so_far; i++) {
+ if(prev_bulks[i] == bm_index) {
+ goto next_entry;
+ }
+ }
+
+ /*Check if this base port is already part of cache */
+ for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
+ if(CACHE_ENTRY_WITHOUT_FULL_STAT(udb->bulk_port_range_cache[i])
+ == bm_index)
+ goto next_entry;
+ }
+
+ /* this is not in chache already */
+ bulk_start = CACHE_TO_PORT(bm_index, bulk_size);
+ port_pos = get_suiting_port_pos_from_range(my_pm,
+ bulk_start, bulk_size, pair_type);
+
+ if(port_pos < 0) { /* no port available in this range */
+ /* Mark this bulk so that we don't have to try this again */
+ if(attempts_so_far < NUM_BULK_CHECK) {
+ prev_bulks[attempts_so_far] = bm_index;
+ attempts_so_far++;
+ }
+ goto next_entry;
+ }
+
+ /* Got one...Get the port number */
+ *port_available = bulk_start + port_pos;
+
+ /* Check to see if we shoud replace one of the cache */
+ for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
+ if(PREDICT_FALSE((udb->bulk_port_range_cache[i]
+ == (i16)BULK_RANGE_INVALID) || (
+ IS_CACHE_ENTRY_FULL(udb->bulk_port_range_cache[i])))) {
+ udb->bulk_port_range_cache[i] = bm_index;
+ return CNAT_SUCCESS;
+ }
+ }
+ /* Check to replace an existing (in use) entry */
+ /* TODO: enforce policy */
+ /* order of looping should depend on policy */
+
+ return CNAT_SUCCESS;
+
+next_entry:
+ db = cnat_main_db + db->user_ports.next;
+ /*
+ * its a circular list, so if we have reached the head again
+ * all the entries for that user have been read
+ */
+ if (db == (cnat_main_db + head)) {
+ break;
+ }
+ } /* while loop for db entries */
+ /* no ports available from pre allocated bulk pool */
+ return CNAT_NO_PORT_FROM_BULK;
+}
+
+cnat_errno_t
+cnat_dynamic_port_alloc_v2_bulk (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ port_pair_t pair_type,
+ u32 *index,
+ u32 *o_ipv4_address,
+ u16 *o_port,
+ u16 static_port_range,
+ cnat_user_db_entry_t *udb,
+ bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req,
+ u16 ip_n_to_1,
+ u32 *rseed_ip
+ )
+{
+
+ cnat_errno_t rv;
+ u16 port_available = 0;
+ i16 i;
+ cnat_portmap_v2_t *my_pm;
+
+ if((BULK_ALLOC_SIZE_NONE != bulk_size) /* bulk logging enabled */
+ && (udb)) { /* This user does have translations already */
+ u16 bulk_start;
+ i16 port_pos;
+
+ my_pm = pm + *index;
+ /* We have a case to check if bulk allocated ports can be used */
+ /* TODO: order of looping to be based on policy
+ * like prefer older or prefer newer ??
+ * For now, start with most recent cache entry
+ * so that we stand a better chance of
+ * finding a port
+ */
+ for(i= 0; i < BULK_RANGE_CACHE_SIZE; i++) {
+ if(PREDICT_TRUE((udb->bulk_port_range_cache[i] ==
+ (i16)BULK_RANGE_INVALID) ||
+ IS_CACHE_ENTRY_FULL(udb->bulk_port_range_cache[i]))) {
+ continue; /* This range is not initialized yet or it is full */
+ }
+ bulk_start = CACHE_TO_PORT(udb->bulk_port_range_cache[i],
+ bulk_size);
+ port_pos = get_suiting_port_pos_from_range(my_pm,
+ bulk_start, bulk_size, pair_type);
+ if(PREDICT_FALSE(port_pos < 0)) {
+ /* Mark this cache entry as full so that we do not
+ * waste time on this entry again */
+ MARK_CACHE_ENTRY_AS_FULL(udb->bulk_port_range_cache[i]);
+#ifdef DEBUG_BULK_PORT
+ PLATFORM_DEBUG_PRINT("Marked bulk cache entry %d as full for %x \n",
+ i, my_pm->ipv4_address);
+#endif /* #ifdef DEBUG_BULK_PORT */
+ continue;
+ }
+ /* Get the port number */
+ port_available = bulk_start+ port_pos;
+#ifdef DEBUG_BULK_PORT
+ PLATFORM_DEBUG_PRINT(
+ "Found port from cache : IP 0x%x, port %d %d iterations\n",
+ my_pm->ipv4_address, port_available, i)
+#endif
+#ifdef HAVE_BULK_PORT_STATS
+ bulk_cache_hit_count++;
+#endif /* HAVE_BULK_PORT_STATS */
+ break;
+ } /* end of for loop for cache check */
+ /* If we have not found a port yet, check if we can have
+ * pre allocated bulk port from non-cache */
+ if(PREDICT_FALSE(i == BULK_RANGE_CACHE_SIZE)) {
+ if( try_bulk_port_from_non_cache(udb, my_pm, pair_type,
+ bulk_size, &port_available,
+ static_port_range) != CNAT_SUCCESS ) {
+ goto ALLCOATE_NEW_BULK;
+ }
+#ifdef DEBUG_BULK_PORT
+ PLATFORM_DEBUG_PRINT("Found port from non-cache : IP 0x%x, port %d\n",
+ my_pm->ipv4_address, port_available);
+#endif
+ }
+ /* Assign the port, mark it as in use */
+ cgn_clib_bitmap_clear_no_check(my_pm->bm, port_available);
+ (my_pm->inuse)++;
+ if(PREDICT_FALSE(pair_type == PORT_PAIR)) {/* Mark the next one too */
+ cgn_clib_bitmap_clear_no_check(my_pm->bm, port_available + 1);
+ (my_pm->inuse)++;
+ }
+ *o_ipv4_address = my_pm->ipv4_address;
+ *o_port = port_available;
+ *nfv9_log_req = CACHE_ALLOC_NO_LOG_REQUIRED;
+#ifdef HAVE_BULK_PORT_STATS
+ bulk_port_use_count++;
+#endif /* HAVE_BULK_PORT_STATS */
+ return (CNAT_SUCCESS);
+ }
+ALLCOATE_NEW_BULK:
+#ifdef DEBUG_BULK_PORT
+ if(BULK_ALLOC_SIZE_NONE != bulk_size) {
+ PLATFORM_DEBUG_PRINT(
+ "No port available from bulk cache, bulk size %d\n", bulk_size);
+ }
+#endif
+ /* For whatever reason, we have not got a port yet */
+ rv = cnat_dynamic_port_alloc_v2(pm, atype, pair_type, index,
+ o_ipv4_address, o_port, static_port_range, bulk_size, nfv9_log_req,
+ ip_n_to_1, rseed_ip);
+ if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
+ return rv;
+ }
+ /* Take care of caching */
+ if(PREDICT_FALSE(udb != NULL)) {
+ /* Predict false because, we usually allocate for new users */
+ cnat_update_bulk_range_cache(udb, *o_port, bulk_size);
+ }
+#ifdef HAVE_BULK_PORT_STATS
+ bulk_port_alloc_count++;
+#endif /* HAVE_BULK_PORT_STATS */
+ return (CNAT_SUCCESS);
+}
+
+
+cnat_errno_t
+cnat_static_port_alloc_v2_bulk (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ port_pair_t pair_type,
+ u32 i_ipv4_address,
+ u16 i_port,
+ u32 *index,
+ u32 *o_ipv4_address,
+ u16 *o_port,
+ u16 static_port_range,
+ cnat_user_db_entry_t *udb,
+ bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req,
+ u16 ip_n_to_1
+ )
+{
+
+ /***
+ * Requirements -
+ * 1. If the port allocated is below dyn start, it should be individual
+ * port (not bulk)
+ * 2. If NOT, it should be bulk allocated
+ * 3. Try and keep the inside port same as outside port in both the
+ * cases (best effort)
+
+ * Algorithm
+ * 1. Check if it is below stat port start or user is new or bulk is
+ * disabled. If yes, call existing function
+ * 2. If not, see if we can pick from bulk and yet try to keep the port
+ * same - difficult thing - check if the port is free - then check if the
+ * entire bulk is free - if not check if bulk is owned by the user already.
+ * If all of these fail, call existing function to allocate a new bulk
+ * 3. Update cache, etc return log requirements
+ *****/
+
+ cnat_errno_t rv;
+ i16 i;
+ u32 head;
+ cnat_portmap_v2_t *my_pm;
+ uword bit_test_result, start_bit;
+ cnat_main_db_entry_t *db = NULL;
+
+ if((BULK_ALLOC_SIZE_NONE != bulk_size) /* bulk logging enabled */
+ && (udb) && /* This user does have translations already */
+ i_port >= static_port_range ) { /* It is outside stat port range*/
+
+ my_pm = pm + *index;
+ /* We have a case to check if bulk allocated ports can be used */
+
+ /* First check if the required port is available. */
+ if(PREDICT_FALSE(clib_bitmap_get_no_check(my_pm->bm, i_port) == 0)) {
+ goto ALLOCATE_NEW_BULK_STATIC;
+ }
+
+ /* Port is free.. check if the bulk is also free */
+ start_bit= ((i_port/bulk_size) * bulk_size);
+ bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm,
+ start_bit, bulk_size);
+ if(PREDICT_TRUE(bit_test_result)) { /* bulk is available, grab it */
+ goto ALLOCATE_NEW_BULK_STATIC;
+ }
+
+ /* else, bulk is taken by someone. check if it is me */
+ /* Check if we own the bulk by any chance */
+ for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
+ if(udb->bulk_port_range_cache[i] == start_bit) break;
+ }
+ if(i == BULK_RANGE_CACHE_SIZE) { /* no luck with cache */
+ head = udb->translation_list_head_index;
+ if(PREDICT_FALSE(head == EMPTY))
+ goto ALLOCATE_NEW_BULK_STATIC;
+ db = cnat_main_db + head;
+ i = 0;
+ while(1) {
+ if((db->out2in_key.k.port/bulk_size) * bulk_size == start_bit) {
+ i = 1; /* Just to indicate it is found */
+ break;
+ }
+ db = cnat_main_db + db->user_ports.next;
+ /*
+ * its a circular list, so if we have reached the head again
+ * all the entries for that user have been read
+ */
+ if (db == (cnat_main_db + head)) break;
+ } /* while loop for db entries */
+ if(!i) {
+ goto ALLOCATE_NEW_BULK_STATIC;
+ }
+ }
+ /* Assign the port, mark it as in use */
+ cgn_clib_bitmap_clear_no_check(my_pm->bm, i_port);
+ (my_pm->inuse)++;
+ *o_ipv4_address = my_pm->ipv4_address;
+ *o_port = i_port;
+ *nfv9_log_req = CACHE_ALLOC_NO_LOG_REQUIRED;
+#ifdef HAVE_BULK_PORT_STATS
+ bulk_port_use_count++;
+#endif /* HAVE_BULK_PORT_STATS */
+
+#ifdef DEBUG_BULK_PORT
+ PLATFORM_DEBUG_PRINT("%s, %d, found stat port from bulk: %x, %d\n",
+ __func__,
+ __LINE__, *o_ipv4_address, *o_port);
+#endif /* DEBUG_BULK_PORT */
+ return (CNAT_SUCCESS);
+ }
+
+ALLOCATE_NEW_BULK_STATIC:
+#ifdef DEBUG_BULK_PORT
+ PLATFORM_DEBUG_PRINT("%s No port available from bulk cache, bulk size %d\n",
+ __func__,bulk_size);
+#endif
+ /* For whatever reason, we have not got a port yet */
+ rv = cnat_static_port_alloc_v2(pm, atype, pair_type, i_ipv4_address,
+ i_port, index, o_ipv4_address, o_port, static_port_range,
+ bulk_size, nfv9_log_req,ip_n_to_1);
+ if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
+ return rv;
+ }
+ /* Take care of caching only if it was a bulk alloc */
+ if(PREDICT_FALSE(udb && (BULK_ALLOC_NOT_ATTEMPTED != *nfv9_log_req))) {
+ cnat_update_bulk_range_cache(udb, *o_port, bulk_size);
+ }
+#ifdef HAVE_BULK_PORT_STATS
+ bulk_port_alloc_count++;
+#endif /* HAVE_BULK_PORT_STATS */
+ return (CNAT_SUCCESS);
+
+}
+
+cnat_errno_t
+cnat_mapped_static_port_alloc_v2_bulk (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ u32 *index,
+ u32 ipv4_address,
+ u16 port,
+ cnat_user_db_entry_t *udb,
+ bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req,
+ u16 ip_n_to_1
+ )
+{
+ /* Requirements :
+ * 1. Check if bulk allocation is required.
+ * 2. Call cnat_mapped_static_port_alloc_v2 to allocate
+ * 3. Decide if alloc has to be cached
+ * 4. Update nfv9_log_req
+ */
+ cnat_errno_t rv;
+ rv = cnat_mapped_static_port_alloc_v2 (pm,
+ atype, index, ipv4_address, port, nfv9_log_req, bulk_size, ip_n_to_1);
+ if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
+ return rv;
+ }
+ /* Take care of caching only if it was a bulk alloc */
+ if(PREDICT_FALSE(udb && (BULK_ALLOC_NOT_ATTEMPTED != *nfv9_log_req))) {
+ int i;
+ port = port*bulk_size;
+ port = port/bulk_size; /* align it to bulk size boundary */
+ for(i=0; i < BULK_RANGE_CACHE_SIZE; i++) {
+ if(CACHE_ENTRY_WITHOUT_FULL_STAT(udb->bulk_port_range_cache[i])
+ == PORT_TO_CACHE(port, bulk_size))
+ break;
+ }
+ if( i == BULK_RANGE_CACHE_SIZE) { /* else, it is alredy in cache */
+ cnat_update_bulk_range_cache(udb, port, bulk_size);
+ }
+ }
+#ifdef HAVE_BULK_PORT_STATS
+ mapped_port_alloc_count++;
+#endif /* HAVE_BULK_PORT_STATS */
+ return (CNAT_SUCCESS);
+}
+
+
+cnat_errno_t
+cnat_dynamic_port_alloc_rtsp_bulk (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ port_pair_t pair_type,
+ u16 i_port,
+ u32 *index,
+ u32 *o_ipv4_address,
+ u16 *o_port,
+ u16 static_port_range,
+ cnat_user_db_entry_t *udb,
+ bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req,
+ u32 *rseed_ip)
+{
+
+ /***
+ * Algorithm
+ * 1. Compute the range of ports required based on the number of digits
+ * in the port request made by the client.
+ * 2. Check if bulk logging is enabled. If not, use the existing method.
+ * 3. Check if there are 2 adjacent ports available that meet the above
+ * criteria in any of the bulk allocations made already.
+ * 4. If yes, mark them in use and return.
+ * 5. If not allocate a new bulk and pick 2 ports in it
+ ***/
+
+ i16 i;
+ cnat_portmap_v2_t *my_pm = 0;
+ u32 start_port1, end_port1, start_port2, end_port2;
+ int range_loop;
+ u16 bulk_start;
+ i16 port_pos;
+ u16 port_available = 0;
+
+ ASSERT(index);
+ ASSERT(o_ipv4_address);
+ ASSERT(o_port);
+
+ /*
+ * Check if the port is 4 digit or 5 digit. I am assuming we are
+ * not getting 3 (or 2 or 1) digit ports, which we cannot anyway
+ * allocate same sized outside ports - as outside ports start from 1024
+ *
+ * Static Port has its own reserved range. Ensure that the range is
+ * such that atleast few 4 digit ports are available for RTSP. If
+ * not it does not make sense to do special allocation for RTSP.
+ */
+ if (PREDICT_TRUE(static_port_range < MIN_STATIC_PORT_RANGE_FOR_RTSP)) {
+ /*
+ * 4 digit port or less
+ */
+ if (i_port <= 9999) {
+ start_port1 = static_port_range;
+ end_port1 = 9999;
+
+ start_port2 = 10000;
+ end_port2 = PORTS_PER_ADDR - 1;
+ } else { /* 5 digit port */
+ start_port1 = 10000;
+ end_port1 = PORTS_PER_ADDR - 1;
+
+ start_port2 = static_port_range;
+ end_port2 = 9999;
+ }
+ } else { /* Static port range is too big */
+ start_port1 = static_port_range;
+ end_port1 = PORTS_PER_ADDR - 1;
+
+ /*
+ * PORTS_PER_ADDR is just a placeholder for
+ * INVALID_PORT, valid ports are b/w 1 and PORTS_PER_ADDR
+ */
+ start_port2 = PORTS_PER_ADDR;
+ end_port2 = PORTS_PER_ADDR;
+ }
+
+
+ if(PREDICT_TRUE(udb != NULL)) {
+ my_pm = pm + *index;
+ }
+
+ /* Now check if this user already owns a bulk range that is
+ * within start range 1
+ */
+
+ u32 start_range = start_port1;
+ u32 end_range = end_port1;
+ for(range_loop = 0; range_loop < 2; range_loop++) {
+ if((BULK_ALLOC_SIZE_NONE == bulk_size) || (!udb)) {
+ goto ALLOCATE_NEW_RTSP_PORTS;
+ }
+ for(i= 0; i < BULK_RANGE_CACHE_SIZE; i++) {
+ if(PREDICT_TRUE((udb->bulk_port_range_cache[i] ==
+ (i16)BULK_RANGE_INVALID) ||
+ IS_CACHE_ENTRY_FULL(udb->bulk_port_range_cache[i]))) {
+ continue; /* This range is not initialized yet or it is full */
+ }
+
+ bulk_start = CACHE_TO_PORT(udb->bulk_port_range_cache[i],
+ bulk_size);
+ if(bulk_start < start_port1 || bulk_start >= end_port1) {
+ continue; /* Not in the range */
+ }
+
+ port_pos = get_suiting_port_pos_from_range(my_pm,
+ bulk_start, bulk_size, pair_type);
+ if(PREDICT_FALSE(port_pos < 0)) {
+ /* Not Marking this cache entry as full as it failed
+ * for pair type. It might have individual entries
+ */
+ continue;
+ }
+ /* Get the port number */
+ port_available = bulk_start+ port_pos;
+#ifdef DEBUG_BULK_PORT
+ PLATFORM_DEBUG_PRINT(
+ "Found port from cache : IP 0x%x, port %d %d iterations\n",
+ my_pm->ipv4_address, port_available, i)
+#endif
+#ifdef HAVE_BULK_PORT_STATS
+ bulk_cache_hit_count += 2;
+#endif /* HAVE_BULK_PORT_STATS */
+ break;
+ } /* end of for loop for cache check */
+
+ if(PREDICT_FALSE(i == BULK_RANGE_CACHE_SIZE)) {
+ /* we have not found a port yet, but to do not want to try
+ * non-cache bulks.. because, it is a very low probability and
+ * do not want to tweak that code for this special case
+ * The impact of non checking the non-cache is, we give this
+ * user few extra ports .. which is OK
+ */
+ goto ALLOCATE_NEW_RTSP_PORTS;
+ }
+#ifdef DEBUG_BULK_PORT
+ PLATFORM_DEBUG_PRINT("RTSP: Found port from non-cache : IP 0x%x, port %d\n",
+ my_pm->ipv4_address, port_available);
+#endif
+
+ /* Assign the port, mark it as in use */
+ cgn_clib_bitmap_clear_no_check(my_pm->bm, port_available);
+ (my_pm->inuse)++;
+ cgn_clib_bitmap_clear_no_check(my_pm->bm, port_available + 1);
+ (my_pm->inuse)++;
+
+ *o_ipv4_address = my_pm->ipv4_address;
+ *o_port = port_available;
+ *nfv9_log_req = CACHE_ALLOC_NO_LOG_REQUIRED;
+#ifdef HAVE_BULK_PORT_STATS
+ bulk_port_use_count += 2;
+#endif /* HAVE_BULK_PORT_STATS */
+ return (CNAT_SUCCESS);
+
+ALLOCATE_NEW_RTSP_PORTS:
+ /* No luck. Let's try allocating new bulk.. */
+ if(PREDICT_TRUE(CNAT_SUCCESS == cnat_dynamic_port_alloc_rtsp
+ (pm, atype, pair_type,
+ start_range, end_range,index, o_ipv4_address,
+ o_port, bulk_size, nfv9_log_req,rseed_ip))) {
+ if(PREDICT_FALSE(udb &&
+ (BULK_ALLOC_NOT_ATTEMPTED != *nfv9_log_req))) {
+ cnat_update_bulk_range_cache(udb, *o_port, bulk_size);
+ }
+#ifdef HAVE_BULK_PORT_STATS
+ bulk_port_alloc_count++;
+#endif /* HAVE_BULK_PORT_STATS */
+ return CNAT_SUCCESS;
+ }
+
+ /* Could not allocate in range 1.. so move to range 2. */
+ start_range = start_port2;
+ end_range = end_port2;
+
+ }
+
+ return (CNAT_NOT_FOUND_DIRECT); /* if we are here, we could not get any ports */
+
+}
+
+#else /* Dummy definitions */
+void show_bulk_port_stats()
+{
+ PLATFORM_DEBUG_PRINT("\nBulk logging feature not included\n");
+}
+
+ void clear_bulk_port_stats()
+{
+ PLATFORM_DEBUG_PRINT("\nBulk logging feature not included\n");
+}
+#endif /* NO_BULK_LOGGING */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_bulk_port.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_bulk_port.h
new file mode 100644
index 00000000..3e48b9a7
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_bulk_port.h
@@ -0,0 +1,157 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_bulk_port_defs.h bulk port alloc definitions
+ *
+ * Copyright (c) 2011-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_BULK_PORT_H__
+#define __CNAT_BULK_PORT_H__
+
+#ifndef NO_BULK_LOGGING
+#include "cnat_bulk_port_defs.h"
+
+cnat_errno_t
+cnat_dynamic_port_alloc_v2_bulk (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ port_pair_t pair_type,
+ u32 *index,
+ u32 *o_ipv4_address,
+ u16 *o_port,
+ u16 static_port_range,
+ cnat_user_db_entry_t *udb,
+ bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req,
+ u16 ip_n_to_1,
+ u32 *rseed_ip);
+
+void cnat_update_bulk_range_cache(cnat_user_db_entry_t *udb, u16 o_port,
+ bulk_alloc_size_t bulk_size);
+
+void cnat_port_free_v2_bulk (
+ cnat_portmap_v2_t *pm,
+ int index,
+ port_pair_t ptype,
+ u16 base_port,
+ cnat_user_db_entry_t *udb,
+ u16 static_port_range,
+ bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req);
+
+cnat_errno_t cnat_static_port_alloc_v2_bulk (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ port_pair_t pair_type,
+ u32 i_ipv4_address,
+ u16 i_port,
+ u32 *index,
+ u32 *o_ipv4_address,
+ u16 *o_port,
+ u16 static_port_range,
+ cnat_user_db_entry_t *udb,
+ bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req,
+ u16 ip_n_to_1
+ );
+
+cnat_errno_t cnat_dynamic_port_alloc_rtsp_bulk (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ port_pair_t pair_type,
+ u16 i_port,
+ u32 *index,
+ u32 *o_ipv4_address,
+ u16 *o_port,
+ u16 static_port_range,
+ cnat_user_db_entry_t *udb,
+ bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req,
+ u32 *rseed_ip);
+
+cnat_errno_t
+cnat_mapped_static_port_alloc_v2_bulk (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ u32 *index,
+ u32 ipv4_address,
+ u16 port,
+ cnat_user_db_entry_t *udb,
+ bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req,
+ u16 ip_n_to_1
+ );
+
+#else /* NO_BULK_LOGGING */
+/* use older code */
+inline cnat_errno_t
+cnat_dynamic_port_alloc_v2_bulk (
+ cnat_vrfmap_t *vrf_map,
+ port_alloc_t atype,
+ port_pair_t pair_type,
+ u32 *index,
+ u32 *o_ipv4_address,
+ u16 *o_port,
+ u16 static_port_range,
+ u16 ip_n_to_1,
+ u32 *rseed_ip
+ )
+{
+ return cnat_dynamic_port_alloc_v2(vrf_map->portmap_list, atype,
+ pair_type, index, o_ipv4_address, o_port, static_port_range,
+ ip_n_to_1, rseed_ip);
+}
+
+inline void cnat_port_free_v2_bulk (
+ cnat_portmap_v2_t *pm,
+ int index,
+ port_pair_t ptype,
+ u16 base_port,
+ cnat_user_db_entry_t *udb,
+ u16 static_port_range);
+{
+ return cnat_port_free_v2(pm, index, ptype, base_port,
+ static_port_range);
+}
+
+inline cnat_errno_t cnat_static_port_alloc_v2_bulk (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ port_pair_t pair_type,
+ u32 i_ipv4_address,
+ u16 i_port,
+ u32 *index,
+ u32 *o_ipv4_address,
+ u16 *o_port,
+ u16 static_port_range)
+{
+ return cnat_static_port_alloc_v2 (pm, atype, pair_type,
+ i_ipv4_address, i_port, index, o_ipv4_address, o_port);
+}
+
+inline cnat_errno_t
+cnat_mapped_static_port_alloc_v2_bulk (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ u32 *index,
+ u32 ipv4_address,
+ u16 port)
+{
+ return cnat_mapped_static_port_alloc_v2(pm, atype, index
+ ipv4_address, port);
+}
+
+#endif /* NO_BULK_LOGGING */
+#endif /* __CNAT_BULK_PORT_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_bulk_port_defs.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_bulk_port_defs.h
new file mode 100644
index 00000000..edb47b0a
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_bulk_port_defs.h
@@ -0,0 +1,57 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_bulk_port_defs.h bulk port alloc definitions
+ *
+ * Copyright (c) 2011 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_BULK_PORT_DEFS_H__
+#define __CNAT_BULK_PORT_DEFS_H__
+
+
+#ifndef NO_BULK_LOGGING
+
+typedef enum {
+ BULK_ALLOC_SIZE_NONE = 1,
+ BULK_ALLOC_SIZE_16 = 16,
+ BULK_ALLOC_SIZE_32 = 32,
+ BULK_ALLOC_SIZE_64 = 64,
+ BULK_ALLOC_SIZE_128 = 128,
+ BULK_ALLOC_SIZE_256 = 256,
+ BULK_ALLOC_SIZE_512 = 512,
+ BULK_ALLOC_SIZE_1024 = 1024,
+ BULK_ALLOC_SIZE_2048 = 2048,
+ BULK_ALLOC_SIZE_4096 = 4096
+} bulk_alloc_size_t;
+
+/* #define DEBUG_BULK_PORT 1 TODO: remove this later */
+
+#define CACHE_ALLOC_NO_LOG_REQUIRED -1
+#define BULK_ALLOC_NOT_ATTEMPTED -2
+
+#define BULK_RANGE_INVALID 0xFFFF
+#define BULK_RANGE_CACHE_SIZE 4
+
+#define BULKSIZE_FROM_VRFMAP(vrfmap) ((vrfmap)->bulk_size)
+
+#define INIT_BULK_CACHE(udb) \
+ { \
+ int i; \
+ for(i =0; i < BULK_RANGE_CACHE_SIZE; i++) \
+ (udb)->bulk_port_range_cache[i] = (i16)BULK_RANGE_INVALID; \
+ }
+
+#endif /* NO_BULK_LOGGING */
+#endif /* __CNAT_BULK_PORT_DEFS_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_cli.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_cli.h
new file mode 100644
index 00000000..e9d190a5
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_cli.h
@@ -0,0 +1,206 @@
+/* *------------------------------------------------------------------
+ * cnat_cli.h - CLI definitions
+ *
+ * Copyright (c) 2007-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_CLI_H__
+#define __CNAT_CLI_H__
+
+#include "cnat_config_api.h"
+#include "cnat_show_api.h"
+
+/* from iox cli error */
+typedef enum {
+ CNAT_SUCCESS = 0,
+ CNAT_NO_CONFIG,
+ CNAT_NO_VRF_RUN,
+ CNAT_NO_POOL_ANY,
+ CNAT_NO_PORT_ANY,
+#ifndef NO_BULK_LOGGING
+ CNAT_NO_PORT_FROM_BULK,
+ CNAT_NO_PRE_ALLOCATED_BULK_PORTS,
+#endif /* NO_BULK_LOGGING */
+ CNAT_BAD_INUSE_ANY,
+ CNAT_NOT_FOUND_ANY,
+ CNAT_INV_PORT_DIRECT,
+ CNAT_DEL_PORT_DIRECT,
+ CNAT_BAD_INUSE_DIRECT,
+ CNAT_NOT_FOUND_DIRECT,
+ CNAT_OUT_LIMIT,
+ CNAT_MAIN_DB_LIMIT,
+ CNAT_USER_DB_LIMIT,
+ CNAT_NOT_STATIC_PORT,
+ CNAT_BAD_STATIC_PORT_REQ,
+ CNAT_NOT_THIS_CORE,
+ CNAT_ERR_PARSER,
+ CNAT_ERR_INVALID_MSG_ID,
+ CNAT_ERR_INVALID_MSG_SIZE,
+ CNAT_ERR_INVALID_PAYLOAD_SIZE,
+ CNAT_ERR_BAD_TCP_UDP_PORT,
+ CNAT_ERR_BULK_SINGLE_FAILURE,
+ CNAT_ERR_XLAT_ID_INVALID,
+ CNAT_ERR_XLAT_V6_PREFIX_INVALID,
+ CNAT_ERR_XLAT_V4_PREFIX_INVALID,
+ CNAT_ERR_XLAT_TCP_MSS_INVALID,
+ CNAT_ERR_6RD_ID_INVALID,
+ CNAT_ERR_6RD_V4_TUNNEL_SRC_INVALID,
+ CNAT_ERR_6RD_V6_PREFIX_INVALID,
+ CNAT_ERR_6RD_V6_BR_UNICAST_INVALID,
+ CNAT_ERR_6RD_V4_PREFIX_MASK_LEN_INVALID,
+ CNAT_ERR_6RD_V4_SUFFIX_MASK_LEN_INVALID,
+ CNAT_ERR_6RD_V4_COMBO_MASK_LEN_INVALID,
+ CNAT_ERR_6RD_TUNNEL_MTU_INVALID,
+ CNAT_ERR_6RD_TUNNEL_TTL_INVALID,
+ CNAT_ERR_6RD_TUNNEL_TOS_INVALID,
+ CNAT_ERR_NAT64_NO_VRF_RUN,
+ CNAT_ERR_NAT64_ID_INVALID,
+ CNAT_ERR_NAT64_V6_PREFIX_INVALID,
+ CNAT_ERR_NAT64_V4_PREFIX_INVALID,
+ CNAT_ERR_NAT64_TCP_MSS_INVALID,
+#ifdef CGSE_DS_LITE
+ CNAT_ERR_DS_LITE_ID_INVALID,
+#endif /* CGSE_DS_LITE */
+ CNAT_ERR_NO_SESSION_DB,
+ CNAT_ERR_MAPE_ID_INVALID,
+ CNAT_ERR_MAX
+} cnat_errno_t;
+
+#define CNAT_TRUE 1
+#define CNAT_FALSE 0
+
+
+#define CNAT_DEBUG_NONE (0)
+#define CNAT_DEBUG_GLOBAL_ERR (1 << 0)
+#define CNAT_DEBUG_DROP_TCP (1 << 0)
+#define CNAT_DEBUG_DROP_UDP (1 << 1)
+#define CNAT_DEBUG_DROP_ICMP (1 << 2)
+#define CNAT_DEBUG_ERR_TCP (1 << 3)
+#define CNAT_DEBUG_ERR_UDP (1 << 4)
+#define CNAT_DEBUG_ERR_ICMP (1 << 5)
+#define CNAT_DEBUG_ERR_ALG (1 << 6)
+#define CNAT_DEBUG_GLOBAL_ALL (1 << 7)
+#define CNAT_DEBUG_FTP_ALG (1 << 8)
+
+
+
+#define CNAT_DEBUG_ALL 0x1FF /*all of above*/
+#define CNAT_DEBUG_ERR_ALL 0x38
+
+#define CNAT_DB_CLEAR_SPECIFIC (0)
+#define CNAT_DB_CLEAR_ALL (1 << 0)
+#define CNAT_DB_CLEAR_VRF (1 << 1)
+#define CNAT_DB_CLEAR_ADDR (1 << 2)
+#define CNAT_DB_CLEAR_PROTO (1 << 3)
+#define CNAT_DB_CLEAR_PORT (1 << 4)
+
+
+#define MAX_UIDX 0x3fff /*the max svi app uidb index */
+/* address mask per core */
+#define ADDR_MASK_PER_CORE PLATFORM_ADDR_MASK_PER_CORE
+#define ADDR_MASK_PER_CORE_PER_PARTITION \
+ PLATFORM_ADDR_MASK_PER_CORE_PER_PARTITION
+
+#define MAX_CORES PLATFORM_MAX_CORES
+#define MAX_CORES_PER_PARTITION PLATFORM_MAX_CORES_PER_PARTITION
+
+/*
+ * Maximum pool size that is supported by platform
+ */
+#define CNAT_MAX_ADDR_POOL_SIZE PLATFORM_CNAT_MAX_ADDR_POOL_SIZE
+#define CNAT_MAX_ADDR_POOL_SIZE_PER_CORE \
+ (CNAT_MAX_ADDR_POOL_SIZE / MAX_CORES_PER_PARTITION)
+
+#define BOUNDARY_VALUE 256
+
+#define BOUNDARY_VALUE_MASK 0xff
+
+#define NUM_ADDR_IN_RANGE(range, value, instance) \
+ ((range / value) + ((instance % MAX_CORES_PER_PARTITION) < (range%value) ? 1 : 0))
+
+typedef enum {
+ CNAT_DEBUG_FLAGS_DUMP = 0,
+ CNAT_DEBUG_FLAG_UDP_INSIDE_CHECKSUM_DISABLE,
+ CNAT_DEBUG_FLAG_UDP_OUTSIDE_CHECKSUM_DISABLE,
+ CNAT_DEBUG_FLAG_UDP_OUTSIDE_PKT_DUMP_ENABLE,
+ CNAT_DEBUG_FLAG_UDP_INSIDE_PKT_DUMP_ENABLE,
+ CNAT_DEBUG_FLAG_ICMP_PKT_DUMP_ENABLE,
+ CNAT_DEBUG_FLAG_FRAG_PKT_DUMP_ENABLE,
+ CNAT_DEBUG_FLAG_CONFIG_DEBUG_ENABLE,
+ CNAT_DEBUG_FLAG_GLOBAL_DEBUG_ALL_ENABLE,
+ CNAT_DEBUG_FLAG_SUMMARY_STATS_DEBUG_ENABLE,
+ CNAT_DEBUG_FLAG_SHOW_DEBUG_ENABLE,
+ CNAT_DEBUG_FLAG_XLAT_CONFIG_DEBUG_ENABLE,
+ CNAT_DEBUG_FLAG_XLAT_DATA_PATH_DEBUG_ENABLE,
+ CNAT_DEBUG_FLAG_TCP_LOGGING_ENABLE,
+ CNAT_DEBUG_FLAG_NFV9_LOGGING_DUMP_ENABLE,
+ CNAT_DEBUG_FLAG_SYSLOG_LOGGING_DUMP_ENABLE,
+ CNAT_DEBUG_SET_STATIC_PORT_RANGE,
+ CNAT_DEBUG_FLAG_V6RD_DATA_PATH_DEBUG_ENABLE,
+ CNAT_DEBUG_FLAG_V6RD_CONFIG_DEBUG_ENABLE,
+ CNAT_DEBUG_FLAG_V6RD_DEFRAG_DEBUG_ENABLE,
+ CNAT_DEBUG_FLAG_NAT64_CONFIG_DEBUG_ENABLE,
+ CNAT_DEBUG_FLAG_NAT64_DATA_PATH_DEBUG_ENABLE,
+ CNAT_DEBUG_FLAG_DSLITE_DP_ENABLE,
+ CNAT_DEBUG_FLAG_DSLITE_CONFIG_DEBUG_ENABLE,
+ CNAT_DEBUG_FLAG_CONFIG_PPTP_ENABLE = 24,
+ CNAT_DEBUG_FLAG_CONFIG_PCP_ENABLE = 25,
+ CNAT_DEBUG_FLAG_MAPE_CONFIG_DEBUG_ENABLE,
+ CNAT_DEBUG_FLAG_MAPE_DATA_PATH_DEBUG_ENABLE,
+ CNAT_DEBUG_FLAG_MAX,
+} cnat_debug_variable_value;
+
+/*
+ * Don't use too small values for PATH MTU
+ */
+#define MIN_NFV9_PATH_MTU 100
+
+extern u32 global_debug_flag;
+extern u16 debug_i_vrf;
+extern u32 debug_i_flag;
+extern u32 debug_i_addr_start;
+extern u32 debug_i_addr_end;
+extern u16 debug_o_vrf;
+extern u32 debug_o_flag;
+extern u32 debug_o_addr_start;
+extern u32 debug_o_addr_end;
+extern u32 tcp_logging_enable_flag;
+extern u32 nfv9_logging_debug_flag;
+
+extern u32 udp_inside_checksum_disable;
+extern u32 udp_outside_checksum_disable;
+extern u32 udp_inside_packet_dump_enable;
+extern u32 udp_outside_packet_dump_enable;
+
+extern u32 icmp_debug_flag;
+extern u32 frag_debug_flag;
+
+extern u32 summary_stats_debug_flag;
+
+extern u32 config_debug_level;
+extern u32 show_debug_level;
+
+
+/* CLI API prototypes called from vcgn_classify.c */
+extern void cnat_nat44_add_vrf_map_t_handler(spp_api_cnat_v4_add_vrf_map_t *mp,
+ vlib_main_t *vm);
+extern void cnat_nat44_handle_show_stats(vlib_main_t *vm);
+extern void cnat_nat44_handle_show_config(vlib_main_t *vm);
+extern void cnat_nat44_set_protocol_timeout_value(u16 active,
+ u16 init, u8 *proto, u8 reset, vlib_main_t *vm);
+extern void cnat_v4_show_inside_entry_req_t_handler
+(spp_api_cnat_v4_show_inside_entry_req_t *mp, vlib_main_t *vm);
+
+#endif /* __CNAT_CLI_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_cli_handler.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_cli_handler.c
new file mode 100644
index 00000000..a4010349
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_cli_handler.c
@@ -0,0 +1,961 @@
+/* *------------------------------------------------------------------
+ * cnat_cli_handler.c - CLI handler definitions
+ *
+ * Copyright (c) 2007-2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/vec.h>
+#include <vppinfra/bitmap.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/pool.h>
+#include <vppinfra/clib.h>
+#include <vppinfra/error.h>
+
+#include "cnat_db.h"
+#include "cnat_config.h"
+#include "cnat_global.h"
+#include "cnat_cli.h"
+#include "cnat_logging.h"
+#include "cnat_syslog.h"
+#include "cnat_config_api.h"
+#include "cnat_show_api.h"
+#include "cnat_show_response.h"
+
+#include <arpa/inet.h>
+
+#if DPDK
+#include <vnet/devices/dpdk/dpdk.h>
+#endif
+
+u32 show_debug_level = 0;
+
+u32
+cnat_get_vrfmap_nfv9_logging_index (u32 i_vrf_id)
+{
+ cnat_nfv9_logging_info_t *my_nfv9_logging_info = 0;
+ u32 logging_index = EMPTY;
+
+ /*
+ * Start with global logging index if available
+ */
+ if (cnat_nfv9_global_info.cnat_nfv9_init_done) {
+ logging_index = cnat_nfv9_global_info.cnat_nfv9_global_collector_index;
+
+ pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info_pool, ({
+ if (my_nfv9_logging_info->i_vrf_id == i_vrf_id) {
+ logging_index = my_nfv9_logging_info -
+ cnat_nfv9_logging_info_pool;
+ break;
+ }
+ }));
+ }
+ return (logging_index);
+}
+
+u32
+cnat_get_vrfmap_syslog_logging_index (u32 i_vrf_id)
+{
+ cnat_syslog_logging_info_t *my_syslog_info = NULL;
+ u32 logging_index = EMPTY;
+
+ /*
+ * Start with global logging index if available
+ */
+ if(PREDICT_TRUE(cnat_syslog_global_info.cnat_syslog_init_done)) {
+
+ pool_foreach (my_syslog_info, cnat_syslog_logging_info_pool, ({
+ if (my_syslog_info->i_vrf_id == i_vrf_id) {
+ logging_index = my_syslog_info -
+ cnat_syslog_logging_info_pool;
+ break;
+ }
+ }));
+ }
+ return (logging_index);
+}
+
+void
+cnat_set_vrf_params_with_default(cnat_vrfmap_t *my_vrfmap, u32 i_vrf, u32 i_vrf_id)
+{
+
+ my_vrfmap->status = S_WAO;
+
+ my_vrfmap->i_vrf = i_vrf;
+ my_vrfmap->i_vrf_id = i_vrf_id;
+
+ my_vrfmap->o_vrf = INVALID_UIDX;
+ my_vrfmap->o_vrf_id = INVALID_VRFID;
+
+#ifndef NO_BULK_LOGGING
+ BULKSIZE_FROM_VRFMAP(my_vrfmap) = BULK_ALLOC_SIZE_NONE;
+#endif /* #ifndef NO_BULK_LOGGING */
+ my_vrfmap->tcp_mss = V4_TCP_MSS_NOT_CONFIGURED_VALUE;
+ my_vrfmap->frag_tout = CNAT_IPV4_FRAG_TIMEOUT_DEF;
+ my_vrfmap->port_limit = V4_DEF_VRF_MAX_PORTS;
+ my_vrfmap->nfv9_logging_index =
+ cnat_get_vrfmap_nfv9_logging_index(i_vrf_id);
+ my_vrfmap->syslog_logging_index =
+ cnat_get_vrfmap_syslog_logging_index(i_vrf_id);
+
+ /* Copy logging policy from nfv9 info. */
+ if(my_vrfmap->nfv9_logging_index != EMPTY) {
+ cnat_nfv9_logging_info_t *nfv9_logging_info =
+ cnat_nfv9_logging_info_pool + my_vrfmap->nfv9_logging_index;
+ my_vrfmap->nf_logging_policy = nfv9_logging_info->logging_policy;
+ }
+ if(my_vrfmap->syslog_logging_index != EMPTY) {
+ cnat_syslog_logging_info_t *syslog_logging_info =
+ cnat_syslog_logging_info_pool + my_vrfmap->syslog_logging_index;
+ my_vrfmap->syslog_logging_policy = syslog_logging_info->logging_policy;
+ }
+ #if 0
+ printf("Initializing params in cnat_set_vrf_params_with_default\n"
+ "my_vrfmap->status = %u\n"
+ "my_vrfmap->tcp_mss = %u\n"
+ "my_vrfmap->i_vrf = %u\n"
+ "my_vrfmap->i_vrf_id = %u\n"
+ "my_vrfmap->o_vrf = %u\n"
+ "my_vrfmap->o_vrf_id = %u\n"
+ "my_vrfmap->bulk_size = %u\n"
+ "my_vrfmap->nfv9_logging_index = %u\n"
+ "my_vrfmap->syslog_logging_index = %u\n"
+ "my_vrfmap->frag_tout = %u\n"
+ "my_vrfmap->port_limit = %u\n"
+ "my_vrfmap->nf_logging_policy = %u\n"
+ "my_vrfmap->syslog_logging_policy = %u\n",
+ my_vrfmap->status,
+ my_vrfmap->tcp_mss,
+ my_vrfmap->i_vrf,
+ my_vrfmap->i_vrf_id,
+ my_vrfmap->o_vrf,
+ my_vrfmap->o_vrf_id,
+ my_vrfmap->bulk_size,
+ my_vrfmap->nfv9_logging_index,
+ my_vrfmap->syslog_logging_index,
+ my_vrfmap->frag_tout,
+ my_vrfmap->port_limit,
+ my_vrfmap->nf_logging_policy,
+ my_vrfmap->syslog_logging_policy);
+ #endif /* if 0 */
+}
+
+/* config command handlers */
+void cnat_nat44_add_vrf_map_t_handler(spp_api_cnat_v4_add_vrf_map_t *mp,
+ vlib_main_t *vm)
+{
+ void cnat_table_entry_fill_map(u32 start_addr, u32 end_addr,
+ cnat_portmap_v2_t **port_map_holder);
+ u32 start_addr, end_addr;
+ u32 pm_len __attribute__((unused));
+ cnat_vrfmap_t *my_vrfmap = 0;
+ cnat_portmap_v2_t *pm = 0;
+ u16 i_vrf, o_vrf;
+ u32 ivrf_id, ovrf_id;
+ u16 my_vrfmap_index;
+ u8 i = 0;
+
+ start_addr = mp->start_addr[0];
+ end_addr = mp->end_addr[0];
+ i_vrf = mp->i_vrf;
+ o_vrf = mp->o_vrf;
+ ovrf_id = mp->o_vrf_id;
+ ivrf_id = mp->i_vrf_id;
+
+#if DEBUG_NOT_COMMENTED
+ vlib_cli_output(vm, "%s: saddr[0x%x], eaddr[0x%x], i_vrf[0x%x], o_vrf[0x%x], "
+ "ovrf_id[0x%x], ivrf_id[0x%x]\n", __func__, start_addr, end_addr,
+ i_vrf, o_vrf, ovrf_id, ivrf_id);
+#endif
+ if (start_addr > end_addr) {
+ vlib_cli_output(vm, "Add VRF Map failed start addr 0x%x > end addr 0x%x\n",
+ start_addr, end_addr);
+ return;
+ }
+ if ((end_addr - start_addr) > CNAT_MAX_ADDR_POOL_SIZE) {
+ vlib_cli_output(vm, "Add VRF Map failed start addr 0x%x - end addr "
+ "0x%x range > 65536\n", start_addr, end_addr);
+ return;
+ }
+ my_vrfmap_index = vrf_map_array[i_vrf];
+
+ if (my_vrfmap_index != VRF_MAP_ENTRY_EMPTY) {
+
+ my_vrfmap = cnat_map_by_vrf + my_vrfmap_index;
+
+ my_vrfmap->o_vrf = o_vrf;
+ my_vrfmap->i_vrf_id = ivrf_id;
+ my_vrfmap->o_vrf_id = ovrf_id;
+ } else {
+ /*
+ * first time add
+ */
+ pool_get(cnat_map_by_vrf, my_vrfmap);
+ memset(my_vrfmap, 0, sizeof(*my_vrfmap));
+ /* waiting for outside vrf */
+ cnat_set_vrf_params_with_default(my_vrfmap, i_vrf, ivrf_id);
+ my_vrfmap->i_vrf = i_vrf;
+ my_vrfmap->o_vrf = o_vrf;
+ my_vrfmap->i_vrf_id = ivrf_id;
+ my_vrfmap->o_vrf_id = ovrf_id;
+#ifndef NO_BULK_LOGGING
+ BULKSIZE_FROM_VRFMAP(my_vrfmap) = BULK_ALLOC_SIZE_NONE;
+#endif /* #ifndef NO_BULK_LOGGING */
+
+ my_vrfmap->tcp_mss = V4_TCP_MSS_NOT_CONFIGURED_VALUE;
+ my_vrfmap->status = S_WA;
+ my_vrfmap->frag_tout = 0; /* currently setting it to 0 */
+ my_vrfmap->port_limit = V4_DEF_VRF_MAX_PORTS;
+ vrf_map_array[i_vrf] = (my_vrfmap - cnat_map_by_vrf);
+ }
+ pm = my_vrfmap->portmap_list;
+ pm_len = vec_len(pm);
+ for(i=0; i < 1 ; i++) {
+ start_addr = mp->start_addr[i];
+ end_addr = mp->end_addr[i];
+ if((start_addr == 0) || (end_addr == 0))
+ break;
+
+ cnat_table_entry_fill_map(start_addr, end_addr,
+ &(my_vrfmap->portmap_list));
+ }
+ my_vrfmap->status = S_RUN;
+ vlib_cli_output(vm, "Address Pool Config Successful !!\n");
+ return;
+}
+
+void cnat_nat44_set_protocol_timeout_value(u16 active,
+ u16 init, u8 *proto, u8 reset, vlib_main_t *vm)
+{
+ if (!strncmp((char *) proto, "tcp", 3)) {
+ tcp_initial_setup_timeout = (reset) ? V4_DEF_TCP_IS_TO : init;
+ tcp_active_timeout = (reset) ? V4_DEF_TCP_AS_TO : active;
+
+ } else if (!strncmp((char *) proto, "udp", 3)) {
+ udp_init_session_timeout = (reset) ? V4_DEF_UDP_IS_TO : init;
+ udp_act_session_timeout = (reset) ? V4_DEF_UDP_AS_TO : active;
+
+ } else if (!strncmp((char *) proto, "icmp", 4)) {
+ icmp_session_timeout = (reset) ? V4_DEF_ICMP_S_TO : active;
+
+ } else {
+ vlib_cli_output(vm, "Error !! Unsupported protocol %s\n", proto);
+ }
+ return;
+}
+
+
+
+
+/* Show command handlers */
+void cnat_nat44_handle_show_stats(vlib_main_t *vm)
+{
+ pool_header_t *h;
+ u32 used, free;
+ cnat_vrfmap_t *my_vrfmap =0;
+ cnat_portmap_v2_t *pm =0, *my_pm = 0;
+ u32 i, pm_len;
+ struct in_addr ip;
+ void cnat_nfv9_show_collector
+ (vlib_main_t *vm, cnat_nfv9_logging_info_t *my_nfv9_logging_info);
+
+ /* active translations */
+ h = pool_header(cnat_main_db);
+ free = vec_len(h->free_indices);
+ used = vec_len(cnat_main_db) - free;
+
+ vlib_cli_output(vm, "vCGN NAT44 Statistics :\n");
+ vlib_cli_output(vm, "\tActive Translations : %u\n",
+ NAT44_COMMON_STATS.active_translations);
+ vlib_cli_output(vm, "\tTotal free translation entries : %u\n", free);
+ vlib_cli_output(vm, "\tTotal used translation entries : %u\n", used);
+ vlib_cli_output(vm, "\ti2o drops due to port limit exceeded : %lu\n",
+ in2out_drops_port_limit_exceeded);
+ vlib_cli_output(vm, "\ti2o drops due to system limit reached : %lu\n",
+ in2out_drops_system_limit_reached);
+ vlib_cli_output(vm, "\ti2o drops due to resource depletion : %lu\n",
+ in2out_drops_resource_depletion);
+ vlib_cli_output(vm, "\to2i drops due to no translations : %lu\n",
+ NAT44_COMMON_STATS.no_translation_entry_drops);
+
+ vlib_cli_output(vm, "\tPool address usage:\n");
+ vlib_cli_output(vm, "\t-------------------------------------------------\n");
+ vlib_cli_output(vm, "\tExternal Address \tPorts Used\n");
+ vlib_cli_output(vm, "\t-------------------------------------------------\n");
+
+ used = 0;
+ pool_foreach (my_vrfmap, cnat_map_by_vrf, ({
+ pm = my_vrfmap->portmap_list;
+ pm_len = vec_len(pm);
+ for (i = 0; i < pm_len; i++) {
+ my_pm = pm + i;
+ if (my_pm->inuse) {
+ used++;
+ /* maximum of 200 addresses to be returned */
+ if (used <= 200) {
+ ip.s_addr = ntohl(my_pm->ipv4_address);
+ vlib_cli_output(vm, "\t%s \t\t%u\n", inet_ntoa(ip), my_pm->inuse);
+ }
+ }
+ }
+ }));
+ return;
+}
+
+void cnat_nat44_handle_show_config(vlib_main_t *vm)
+{
+ cnat_vrfmap_t * my_vrfmap;
+ cnat_portmap_v2_t *pm = 0;
+ cnat_portmap_v2_t *my_pm = 0;
+ u32 pm_len;
+ struct in_addr ip_addr;
+ u8 status_str[20];
+ cnat_nfv9_logging_info_t *my_nfv9_logging_info,
+ *global_nfv9_logging_info = 0;
+
+ vnet_hw_interface_t * hw;
+ vnet_main_t * vnm = vnet_get_main();
+
+ void cnat_nfv9_show_collector
+ (vlib_main_t *vm, cnat_nfv9_logging_info_t *my_nfv9_logging_info);
+
+ vlib_cli_output(vm, "vCGN NAT44 Config:\n");
+ vlib_cli_output(vm, "\tPort Limit : %u\n", cnat_main_db_max_ports_per_user);
+ vlib_cli_output(vm, "\ttotal address pool : %u\n", total_address_pool_allocated);
+ vlib_cli_output(vm, "\tdynamic port start range : %u\n", cnat_static_port_range);
+
+ pool_foreach(my_vrfmap, cnat_map_by_vrf, ({
+ hw = vnet_get_hw_interface (vnm, my_vrfmap->i_vrf);
+ vlib_cli_output(vm, "\tInside Interface : %v\n", hw->name);
+ hw = vnet_get_hw_interface (vnm, my_vrfmap->o_vrf);
+ vlib_cli_output(vm, "\tOutside Interface : %v\n", hw->name);
+
+ memset(status_str, 0x00, sizeof(status_str));
+ switch(my_vrfmap->status) {
+ case S_WAO: clib_memcpy(status_str, "S_WAO", 5); break;
+ case S_WA: clib_memcpy(status_str, "S_WA", 4); break;
+ case S_WO: clib_memcpy(status_str, "S_WO", 4); break;
+ case S_RUN: clib_memcpy(status_str, "ONLINE", 6); break;
+ case S_DEL: clib_memcpy(status_str, "S_DEL", 5); break;
+ default: clib_memcpy(status_str, "Invalid state", 13);
+
+ }
+ vlib_cli_output(vm,
+ "\tAddress pool map table status : %s\n", status_str);
+
+ pm = my_vrfmap->portmap_list;
+ pm_len = vec_len(pm);
+ my_pm = pm;
+ ip_addr.s_addr = clib_net_to_host_u32(my_pm->ipv4_address);
+ vlib_cli_output(vm,
+ "\tStart Address : %s\n", inet_ntoa(ip_addr));
+ my_pm = pm + (pm_len - 1);
+ ip_addr.s_addr = clib_net_to_host_u32(my_pm->ipv4_address);
+ vlib_cli_output(vm,
+ "\tEnd Address : %s\n", inet_ntoa(ip_addr));
+
+ }));
+ vlib_cli_output(vm,
+ "\ttcp init timeout : %u sec\n", tcp_initial_setup_timeout);
+ vlib_cli_output(vm,
+ "\ttcp active timeout : %u sec\n", tcp_active_timeout);
+ vlib_cli_output(vm,
+ "\tudp init timeout : %u sec\n", udp_init_session_timeout);
+ vlib_cli_output(vm,
+ "\tudp active timeout : %u sec\n", udp_act_session_timeout);
+ vlib_cli_output(vm,
+ "\ticmp session timeout: %u sec\n", icmp_session_timeout);
+
+#if 0
+ if (cnat_nfv9_global_info.cnat_nfv9_global_collector_index != EMPTY) {
+ vlib_cli_output(vm,"\nGloabal NFV9 Collector :");
+ global_nfv9_logging_info = cnat_nfv9_logging_info_pool +
+ cnat_nfv9_global_info.cnat_nfv9_global_collector_index;
+ cnat_nfv9_show_collector(vm, global_nfv9_logging_info);
+ }
+#endif
+
+ vlib_cli_output(vm, "\nNFV9 Collector :");
+ if (cnat_nfv9_logging_info_pool !=NULL) {
+ pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info_pool, ({
+ if (my_nfv9_logging_info != global_nfv9_logging_info) {
+ cnat_nfv9_show_collector(vm, my_nfv9_logging_info);
+ vlib_cli_output(vm, "\n");
+ }
+ }));
+ } else {
+ vlib_cli_output(vm, "\n");
+ }
+
+ return;
+}
+
+/*
+ * Check if the request flag matches the entry flags and
+ * if so return "1"
+ *
+ * entry_flag_ptr is an output parameter - it returns the flags
+ * corresponding to the translation entry
+ */
+static u8 cnat_v4_show_verify_display_entry (
+ u16 request_flag,
+ cnat_main_db_entry_t *db,
+ u16 *entry_flag_ptr)
+{
+ u8 display_entry = 0;
+
+ /*
+ * This should never happen
+ */
+ if (!entry_flag_ptr) {
+ return (display_entry);
+ }
+
+ *entry_flag_ptr = 0;
+
+ if ((db->flags & CNAT_DB_FLAG_STATIC_PORT)
+ &&(db->flags & CNAT_DB_FLAG_ALG_ENTRY)) {
+ *entry_flag_ptr |= CNAT_TRANSLATION_ENTRY_STATIC;
+ *entry_flag_ptr |= CNAT_TRANSLATION_ENTRY_ALG;
+ } else if (db->flags & CNAT_DB_FLAG_STATIC_PORT) {
+ *entry_flag_ptr |= CNAT_TRANSLATION_ENTRY_STATIC;
+ } else if ((db->flags & CNAT_DB_FLAG_ALG_ENTRY) ||
+ (db->flags & CNAT_DB_FLAG_PPTP_GRE_ENTRY)) {
+ *entry_flag_ptr |= CNAT_TRANSLATION_ENTRY_ALG;
+ } else if (db->flags & CNAT_DB_FLAG_PCPI) {
+ *entry_flag_ptr |= CNAT_TRANSLATION_ENTRY_PCPI_DYNAMIC;
+ } else if (db->flags & CNAT_DB_FLAG_PCPE) {
+ *entry_flag_ptr |= CNAT_TRANSLATION_ENTRY_PCPE_DYNAMIC;
+ } else {
+ *entry_flag_ptr |= CNAT_TRANSLATION_ENTRY_DYNAMIC;
+ }
+
+ if (request_flag == CNAT_TRANSLATION_ENTRY_ALL) {
+ display_entry = 1;
+ } else {
+ /*
+ * Check if the request_flag is STATIC or ALG
+ * and the entry is STATIC or ALG as well
+ */
+ if ((request_flag & CNAT_TRANSLATION_ENTRY_STATIC) &&
+ (*entry_flag_ptr & CNAT_TRANSLATION_ENTRY_STATIC)) {
+ display_entry = 1;
+ }
+
+ if ((request_flag & CNAT_TRANSLATION_ENTRY_ALG) &&
+ (*entry_flag_ptr & CNAT_TRANSLATION_ENTRY_ALG)) {
+ display_entry = 1;
+ }
+
+ if ((request_flag & CNAT_TRANSLATION_ENTRY_PCPI_DYNAMIC) &&
+ (*entry_flag_ptr & CNAT_TRANSLATION_ENTRY_PCPI_DYNAMIC)) {
+ display_entry = 1;
+ }
+
+ if ((request_flag & CNAT_TRANSLATION_ENTRY_PCPE_DYNAMIC) &&
+ (*entry_flag_ptr & CNAT_TRANSLATION_ENTRY_PCPE_DYNAMIC)) {
+ display_entry = 1;
+ }
+
+ /*
+ * For dynamic entry case, check if flags field is 0
+ */
+ if ((request_flag & CNAT_TRANSLATION_ENTRY_DYNAMIC) &&
+ (*entry_flag_ptr & CNAT_TRANSLATION_ENTRY_DYNAMIC)) {
+ display_entry = 1;
+ }
+ }
+
+ if (PREDICT_FALSE(show_debug_level > 2)) {
+ PLATFORM_DEBUG_PRINT("Entry (0x%x, %d) -> (0x%x, %d) request_flag 0x%x, entry_flag 0x%x, display_entry %d\n", db->in2out_key.k.ipv4, db->in2out_key.k.port, db->out2in_key.k.ipv4, db->out2in_key.k.port, request_flag, *entry_flag_ptr, display_entry);
+ }
+
+ return (display_entry);
+}
+void cnat_v4_show_inside_entry_req_t_handler
+(spp_api_cnat_v4_show_inside_entry_req_t *mp, vlib_main_t * vm)
+{
+ cnat_user_db_entry_t *udb = NULL;
+ cnat_main_db_entry_t *db = NULL;
+ cnat_db_key_bucket_t u_ki, ki;
+ u64 a, b, c;
+ u32 index;
+ u16 start_port, end_port, port;
+ u16 request_flag = 0;
+ u16 entry_flag = 0;
+ u8 num_entries = 0;
+ u8 proto, all;
+ u8 done = 0;
+ cnat_v4_show_translation_entry *entry_list;
+ cnat_v4_show_translation_entry entry[PLATFORM_MAX_TRANSLATION_ENTRIES];
+ u8 display_entry;
+ u8 flag_str[11];
+ vnet_hw_interface_t * hw;
+ vnet_main_t * vnm = vnet_get_main();
+
+ ki.k.k.ipv4 = mp->ipv4_addr;
+ ki.k.k.vrf = mp->vrf_id;
+ start_port = mp->start_port;
+ end_port = mp->end_port;
+#if DEBUG
+ vlib_cli_output(vm, "## proto %d, inside-addr 0x%x, start_port %u, "
+ "end_port %u, vrf 0x%x, flag 0x%x\n",
+ mp->protocol,
+ mp->ipv4_addr,
+ mp->start_port,
+ mp->end_port,
+ mp->vrf_id,
+ mp->flags);
+#endif
+
+ proto = mp->protocol;
+ ki.k.k.vrf |= ((u16)proto << CNAT_PRO_SHIFT);
+
+ all = mp->all_entries; /* for no port range case */
+ request_flag = mp->flags; /* for all, alg, static entries case */
+ entry_list = entry;
+
+ /*
+ * check if the address is belonging to this core
+ */
+
+
+ /*
+ * first we check if the user exists in the udb, if he is not then
+ * it does not make sense to check the main db for translations
+ */
+ u_ki.k.k.vrf = ki.k.k.vrf & CNAT_VRF_MASK;
+ u_ki.k.k.ipv4 = ki.k.k.ipv4;
+ u_ki.k.k.port = 0;
+
+ if (PREDICT_FALSE(show_debug_level > 0)) {
+ vlib_cli_output(vm, "\nI_TRANS_CORE %d: IPv4 0x%x, VRF 0x%x, "
+ "start_port %d, end_port %d",
+ my_instance_number, ki.k.k.ipv4,
+ ki.k.k.vrf, start_port, end_port);
+ }
+
+ udb = cnat_user_db_lookup_entry(&u_ki);
+ if (!udb) {
+ if (PREDICT_FALSE(show_debug_level > 0)) {
+ vlib_cli_output(vm, "\nReturning %d entries",
+ num_entries);
+ }
+ return;
+ }
+
+ if (all) {
+ #if 0
+ if (PREDICT_FALSE(show_debug_level > 0)) {
+ PLATFORM_DEBUG_PRINT("\nI_TRANS: Printing ALL\n");
+ }
+
+ /*
+ * get the head of list of translation entries for that user
+ * from the user db
+ */
+ head = udb->translation_list_head_index;
+ db = cnat_main_db + head;
+
+ while (num_entries < PLATFORM_MAX_TRANSLATION_ENTRIES) {
+
+ if (((db->in2out_key.k.vrf & CNAT_PRO_MASK) >> CNAT_PRO_SHIFT)
+ != proto) {
+ goto next_entry;
+ }
+
+ display_entry =
+ spp_api_cnat_v4_show_verify_display_entry(request_flag, db,
+ &entry_flag);
+
+ if (display_entry) {
+ entry_list->ipv4_addr =
+ spp_host_to_net_byte_order_32(db->out2in_key.k.ipv4);
+ entry_list->cnat_port =
+ spp_host_to_net_byte_order_16(db->out2in_key.k.port);
+ entry_list->src_port =
+ spp_host_to_net_byte_order_16(db->in2out_key.k.port);
+
+ entry_list->protocol = proto;
+
+ /* incase of gre - in2out is not accounted */
+ if(proto != CNAT_PPTP) {
+
+ entry_list->in2out_packets =
+ spp_host_to_net_byte_order_32(db->in2out_pkts);
+ } else {
+ entry_list->in2out_packets = 0;
+ }
+ entry_list->out2in_packets =
+ spp_host_to_net_byte_order_32(db->out2in_pkts);
+
+ entry_list->flags =
+ spp_host_to_net_byte_order_16(entry_flag);
+
+ num_entries++;
+ entry_list = entry_list + 1;
+ }
+next_entry:
+ db = cnat_main_db + db->user_ports.next;
+ /*
+ * its a circular list, so if we have reached the head again
+ * all the entries for that user have been read
+ */
+ if (db == (cnat_main_db + head)) {
+ break;
+ }
+ }
+ resp->num_entries = num_entries;
+ #endif /* if 0 */
+ } else {
+ if (PREDICT_FALSE(show_debug_level > 0)) {
+ vlib_cli_output(vm, "\nI_TRANS: Printing range %d .. %d\n",
+ start_port, end_port);
+ }
+ /*
+ * port range is specified so for each port calculate the hash and
+ * check if the entry is present in main db
+ */
+ port = start_port;
+ done = 0;
+ while ((!done) && (num_entries < PLATFORM_MAX_TRANSLATION_ENTRIES)) {
+
+ ki.k.k.port = port;
+ if (port >= end_port) {
+ done = 1;
+ } else {
+ port++;
+ }
+ CNAT_V4_GET_HASH(ki.k.key64,
+ ki.bucket,
+ CNAT_MAIN_HASH_MASK);
+ index = cnat_in2out_hash[ki.bucket].next;
+ if (PREDICT_TRUE(index == EMPTY)) {
+ continue;
+ }
+
+ do {
+ db = cnat_main_db + index;
+ if (db->in2out_key.key64 == ki.k.key64) {
+ break;
+ }
+ index = db->in2out_hash.next;
+ } while (index != EMPTY);
+
+ if (index == EMPTY) {
+ continue;
+ } else {
+
+ display_entry =
+ cnat_v4_show_verify_display_entry(request_flag, db,
+ &entry_flag);
+ if (display_entry) {
+
+ entry_list->ipv4_addr =
+ clib_host_to_net_u32(db->out2in_key.k.ipv4);
+ entry_list->cnat_port =
+ clib_host_to_net_u16(db->out2in_key.k.port);
+ entry_list->src_port =
+ clib_host_to_net_u16(db->in2out_key.k.port);
+
+ entry_list->protocol = proto;
+ entry_list->nsessions = db->nsessions;
+ entry_list->flags = ((db->flags & CNAT_DB_FLAG_TCP_ACTIVE) ||
+ (db->flags & CNAT_DB_FLAG_UDP_ACTIVE)) ? 1:0;
+ /* incase of gre - in2out is not accounted */
+ if(proto != CNAT_PPTP) {
+ entry_list->in2out_packets =
+ clib_host_to_net_u32(db->in2out_pkts);
+ } else {
+ entry_list->in2out_packets = 0;
+ }
+
+ entry_list->out2in_packets =
+ clib_host_to_net_u32(db->out2in_pkts);
+
+ if (PREDICT_FALSE(show_debug_level > 3)) {
+ vlib_cli_output(vm, "\n1. Entry: Addr 0x%x, port %d, num_entries %d",
+ clib_net_to_host_u32(entry_list->ipv4_addr),
+ clib_net_to_host_u16(entry_list->cnat_port),
+ num_entries);
+ }
+
+ entry_list = entry_list + 1;
+ num_entries++;
+ }
+ } /* if (index == EMPTY) */
+ } /* while() */
+ }
+
+ if (PREDICT_FALSE(show_debug_level > 0)) {
+ if (num_entries) {
+ vlib_cli_output(vm, "\nReturning %d entries\n",
+ num_entries);
+ }
+ }
+
+ entry_list = entry;
+ u8 i = 0;
+ struct in_addr ip;
+ u8 proto_str[10];
+ u8 transl_str[10];
+ memset(proto_str, 0x00, 10);
+ memset(transl_str, 0x00, 10);
+
+ if (proto == 1) strncpy((char *)proto_str, "udp", 3);
+ else if (proto == 2) strncpy((char *)proto_str, "tcp", 3);
+ else if (proto == 3) strncpy((char *)proto_str, "icmp", 4);
+ else strncpy((char *)proto_str, "unknown", 7);
+
+ if (request_flag == 0x04) strncpy((char *)transl_str, "Dynamic", 7);
+ else strncpy((char *)transl_str, "Unknown", 7); /* currently we are not supporting static/alg entries */
+
+ ip.s_addr = clib_net_to_host_u32(u_ki.k.k.ipv4);
+ hw = vnet_get_hw_interface (vnm, u_ki.k.k.vrf);
+
+ vlib_cli_output (vm, "Inside-translation details\n");
+ vlib_cli_output (vm, "--------------------------\n");
+
+ vlib_cli_output (vm, "Inside interface : %s\n", hw->name);
+ vlib_cli_output (vm, "Inside address : %s\n", inet_ntoa(ip));
+ vlib_cli_output (vm, "Start port : %u\n", start_port);
+ vlib_cli_output (vm, "End port : %u\n", end_port);
+
+ vlib_cli_output (vm, "--------------------------------------------------------------------------------------"
+ "-----------------------\n");
+ vlib_cli_output (vm, "Outside Protocol Inside Outside Translation"
+ " I2O O2I Flag Num\n");
+ vlib_cli_output (vm, "Address Src Port Src Port Type "
+ " Pkts Pkts Sessions\n");
+ vlib_cli_output (vm, "--------------------------------------------------------------------------------------"
+ "-----------------------\n");
+
+ while ((num_entries) && (entry_list) && (i < 50)) {
+
+ ip.s_addr = entry_list->ipv4_addr;
+ memset(flag_str,0x00,11);
+ if((proto == 1) || (proto == 2)) {
+ if(entry_list->flags == 1) {
+ strncpy((char *)flag_str,"Active",6);
+ }
+ else {
+ strncpy((char *) flag_str,"Non Active",10);
+ }
+ } else {
+ strncpy((char *) flag_str, "NA", 2);
+ }
+ vlib_cli_output(vm, "%s %10s %11u %12u %13s %10u %10u %14s %6u\n",
+ inet_ntoa(ip), proto_str,
+ clib_net_to_host_u16(entry_list->src_port),
+ clib_net_to_host_u16(entry_list->cnat_port),
+ transl_str,
+ clib_net_to_host_u32(entry_list->in2out_packets),
+ clib_net_to_host_u32(entry_list->out2in_packets),
+ flag_str,
+ entry_list->nsessions);
+ entry_list++;
+ num_entries--; i++;
+ }
+
+ return;
+}
+
+void cnat_v4_show_outside_entry_req_t_handler
+(spp_api_cnat_v4_show_outside_entry_req_t *mp, vlib_main_t *vm)
+{
+ cnat_main_db_entry_t *db = NULL;
+ cnat_db_key_bucket_t ko;
+ u64 a, b, c;
+ u32 index;
+ u16 start_port, end_port, port;
+ u16 request_flag = 0;
+ u16 entry_flag = 0;
+ u8 num_entries = 0;
+ u8 proto;
+ cnat_v4_show_translation_entry *entry_list;
+ cnat_v4_show_translation_entry entry[PLATFORM_MAX_TRANSLATION_ENTRIES];
+ u8 done = 0;
+ u8 display_entry;
+ u8 flag_str[11];
+ vnet_hw_interface_t * hw;
+ vnet_main_t * vnm = vnet_get_main();
+
+ ko.k.k.ipv4 = mp->ipv4_addr;
+ ko.k.k.vrf = mp->vrf_id;
+ start_port = mp->start_port;
+ end_port = mp->end_port;
+
+ proto = mp->protocol;
+ request_flag = mp->flags;
+
+ ko.k.k.vrf |= ((u16)proto << CNAT_PRO_SHIFT);
+
+ entry_list = entry;
+
+ if (PREDICT_FALSE(show_debug_level > 0)) {
+ vlib_cli_output(vm, "\nO_TRANS_CORE %d: IPv4 0x%x, VRF 0x%x, "
+ "start_port %d, end_port %d", my_instance_number,
+ ko.k.k.ipv4, ko.k.k.vrf, start_port, end_port);
+ }
+
+ /*
+ * for each ip and port combination we need to scan the main db
+ * and check if the entry is present in main db
+ */
+ port = start_port;
+ done = 0;
+ while ((!done) && (num_entries < PLATFORM_MAX_TRANSLATION_ENTRIES)) {
+ ko.k.k.port = port;
+
+ /*
+ * If we have reached the end_port, we are DONE
+ */
+ if (port >= end_port) {
+ done = 1;
+ } else {
+ port++;
+ }
+
+ CNAT_V4_GET_HASH(ko.k.key64,
+ ko.bucket,
+ CNAT_MAIN_HASH_MASK);
+
+ index = cnat_out2in_hash[ko.bucket].next;
+ if (PREDICT_TRUE(index == EMPTY)) {
+ continue;
+ }
+
+ do {
+ db = cnat_main_db + index;
+ if (db->out2in_key.key64 == ko.k.key64) {
+ break;
+ }
+ index = db->out2in_hash.next;
+ } while (index != EMPTY);
+
+ if (index == EMPTY) {
+ continue;
+ } else {
+ display_entry =
+ cnat_v4_show_verify_display_entry(request_flag, db,
+ &entry_flag);
+
+ if (display_entry) {
+ entry_list->ipv4_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+ entry_list->cnat_port =
+ clib_host_to_net_u16(db->out2in_key.k.port);
+ entry_list->src_port =
+ clib_host_to_net_u16(db->in2out_key.k.port);
+ entry_list->protocol = proto;
+ entry_list->nsessions = db->nsessions;
+ entry_list->flags = ((db->flags & CNAT_DB_FLAG_TCP_ACTIVE) ||
+ (db->flags & CNAT_DB_FLAG_UDP_ACTIVE)) ? 1:0;
+ /* incase of gre - in2out is not accounted */
+ if(proto != CNAT_PPTP) {
+ entry_list->in2out_packets =
+ clib_host_to_net_u32(db->in2out_pkts);
+ } else {
+ entry_list->in2out_packets = 0 ;
+ }
+ entry_list->out2in_packets =
+ clib_host_to_net_u32(db->out2in_pkts);
+ #if 0
+ entry_list->flags =
+ clib_host_to_net_u16(entry_flag);
+ #endif
+ entry_list = entry_list + 1;
+ num_entries++;
+ }
+ }
+ }
+
+ if (num_entries == 0) {
+ /* No point proceeding further */
+ return;
+ }
+
+ if (PREDICT_FALSE(show_debug_level > 0)) {
+ if (num_entries) {
+ vlib_cli_output(vm, "\nO_TRANS: Core %d returning %d entries",
+ num_entries);
+ }
+ }
+
+ entry_list = entry;
+ u8 i = 0;
+ struct in_addr ip;
+ u8 proto_str[10];
+ u8 transl_str[10];
+ memset(proto_str, 0x00, 10);
+ memset(transl_str, 0x00, 10);
+
+ if (proto == 1) strncpy((char *) proto_str, "udp", 3);
+ else if (proto == 2) strncpy((char *) proto_str, "tcp", 3);
+ else if (proto == 3) strncpy((char *) proto_str, "icmp", 4);
+ else strncpy((char *) proto_str, "unknown", 7);
+
+ if (request_flag == 0x04) strncpy((char *) transl_str, "Dynamic", 7);
+ else strncpy((char *)transl_str, "Unknown", 7); /* currently we are not supporting static/alg entries */
+
+ ip.s_addr = clib_net_to_host_u32(ko.k.k.ipv4);
+ hw = vnet_get_hw_interface (vnm, (ko.k.k.vrf & CNAT_VRF_MASK));
+
+ vlib_cli_output (vm, "Outside-translation details\n");
+ vlib_cli_output (vm, "--------------------------\n");
+
+ vlib_cli_output (vm, "Outside interface : %s\n", hw->name);
+ vlib_cli_output (vm, "Outside address : %s\n", inet_ntoa(ip));
+ vlib_cli_output (vm, "Start port : %u\n", start_port);
+ vlib_cli_output (vm, "End port : %u\n", end_port);
+
+ vlib_cli_output (vm, "--------------------------------------------------------------------------------------"
+ "-----------------------\n");
+ vlib_cli_output (vm, "Inside Protocol Outside Inside Translation"
+ " I2O O2I Flag Num\n");
+ vlib_cli_output (vm, "Address Dst Port Dst Port Type "
+ " Pkts Pkts Sessions\n");
+ vlib_cli_output (vm, "--------------------------------------------------------------------------------------"
+ "-----------------------\n");
+
+ while ((num_entries) && (entry_list) && (i < 50)) {
+ ip.s_addr = entry_list->ipv4_addr;
+ memset(flag_str,0x00,11);
+ if((proto == 1) || (proto == 2)) {
+ if(entry_list->flags == 1) {
+ strncpy((char *) flag_str,"Active",6);
+ }
+ else {
+ strncpy((char *) flag_str,"Non Active",10);
+ }
+ } else {
+ strncpy((char *) flag_str, "NA", 2);
+ }
+ vlib_cli_output(vm, "%s %10s %11u %12u %13s %10u %10u %14s %6u\n",
+ inet_ntoa(ip), proto_str,
+ clib_net_to_host_u16(entry_list->cnat_port),
+ clib_net_to_host_u16(entry_list->src_port),
+ transl_str,
+ clib_net_to_host_u32(entry_list->in2out_packets),
+ clib_net_to_host_u32(entry_list->out2in_packets),
+ flag_str,
+ entry_list->nsessions);
+ entry_list++;
+ num_entries--; i++;
+
+ }
+ return;
+}
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_common_api.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_common_api.h
new file mode 100644
index 00000000..a4eb7443
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_common_api.h
@@ -0,0 +1,22 @@
+/*---------------------------------------------------------------------------
+ * Copyright (c) 2009-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+#ifndef __CNAT_COMMON_API_H__
+#define __CNAT_COMMON_API_H__
+
+/* All common API prototypes */
+void cnat_scanner_db_process_turn_on(vlib_main_t *vm);
+
+#endif
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_config.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_config.c
new file mode 100644
index 00000000..87183dfa
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_config.c
@@ -0,0 +1,77 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_config.c - configuration definitions
+ *
+ * Copyright (c) 2007-2012 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+#include "cnat_config.h"
+#include "cnat_cli.h"
+#include "cnat_v4_pptp_alg.h"
+#include "platform_common.h"
+
+/* session timeout */
+
+u16 tcp_initial_setup_timeout = V4_DEF_TCP_IS_TO; /* sec */
+u16 tcp_active_timeout = V4_DEF_TCP_AS_TO; /* sec */
+u16 udp_init_session_timeout = V4_DEF_UDP_IS_TO; /* 30 sec */
+u16 udp_act_session_timeout = V4_DEF_UDP_AS_TO; /* 2 min */
+u16 icmp_session_timeout = V4_DEF_ICMP_S_TO; /* 60 sec */
+
+cnat_pptp_config_t pptp_cfg =
+ {
+ .enable = PPTP_DISABLED,
+ .timeout = PPTP_GRE_TIMEOUT
+ } ;
+
+/* This flag is used as indication of timeout related config
+ * changes and hence db needs to be updated
+ */
+u8 timeout_dirty_flag = 0;
+
+/* mapping refresh direction,
+ * 1 inbound and outbound refresh
+ */
+u8 mapping_refresh_both_direction = V4_DEF_ENABLE;
+
+u16 cnat_main_db_max_ports_per_user = V4_DEF_MAX_PORTS;
+
+u32 cnat_main_db_icmp_rate_limit = DEF_RATE_LIMIT;
+u32 cnat_main_db_icmp_rate_limit_core = DEF_RATE_LIMIT_CORE;
+u32 crc_zero_udp_rate_limit_core = RATE_LIMIT_UDP_CORE;
+u16 cnat_static_port_range = CNAT_DEF_STATIC_PORT_RANGE;
+
+
+/*
+ * ftp alg enable
+ */
+u8 ftp_alg_enabled = V4_DEF_DISABLE;
+u16 rtsp_alg_port_num = 0;
+
+/*
+ * load balancing debug mode
+ */
+u8 lb_debug_enable = V4_DEF_DISABLE;
+
+
+/* good or evil mode
+ * 0 endpoint-independnet filter, good mode
+ * 1 address depedent filter, evil mode
+ */
+u8 address_dependent_filtering = V4_DEF_DISABLE;
+
+u16 per_user_icmp_msg_limit = ICMP_MSG_RATE_LIMIT;
+
+u16 config_delete_timeout = V4_CONFIG_DELETE_TO;
+
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_config.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_config.h
new file mode 100644
index 00000000..f1042737
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_config.h
@@ -0,0 +1,582 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_config.h - configuration database definitions
+ *
+ * Copyright (c) 2007-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_CONFIG_H__
+#define __CNAT_CONFIG_H__
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+#include "cnat_bulk_port_defs.h"
+
+/* default policy value */
+#define V4_DEF_ICMP_S_TO 60 /*icmp session timeout */
+#define V4_DEF_UDP_IS_TO 30 /*udp init session timeout */
+#define V4_DEF_UDP_AS_TO 120 /*udp active session timeout */
+#define V4_DEF_TCP_IS_TO 120 /*tcp init session timeout */
+#define V4_DEF_TCP_AS_TO 1800 /*tcp active session timeout, 30 min */
+#define V4_DEF_TCP_MSS 1460 /*tcp mss */
+#define V4_DEF_MAX_PORTS 100 /*max port limit per user */
+#define DEF_RATE_LIMIT PLATFORM_MAX_CORES /* No of packets/sec icmp generated */
+#define DEF_RATE_LIMIT_CORE 1 /* No of packets/sec icmp generated (per core) */
+#define RATE_LIMIT_UDP_CORE 1000 /* Max allowed udp crc zero packets/sec/core */
+
+#define NAT44_RESERVED_INST_ID 1
+#define DSLITE_START_ID (NAT44_RESERVED_INST_ID + 1)
+#define V4_DEF_VRF_MAX_PORTS 0 /*max port limit per vrf user;
+ 0 means use the global port limit for user*/
+/*Hardcoded . TBD - can be made configurable */
+
+#define V4_DEF_ENABLE 1 /* feature enable */
+#define V4_DEF_DISABLE 0 /* feature disable */
+
+#define CNAT_DEF_STATIC_PORT_RANGE 1024 /* Default range for static ports */
+/*
+ * If TCP MSS is not configured, store the maximum possible value
+ */
+#define V4_TCP_MSS_NOT_CONFIGURED_VALUE 0xffff
+
+/* default timeout for fragments in seconds set to 2
+ * in case its not configured
+ */
+#define CNAT_IPV4_FRAG_TIMEOUT_DEF 2
+/* other */
+/* max db entries to be scaned */
+#define MAX_DB_ENTRY_PER_SCAN PLATFORM_MAX_DB_ENTRY_PER_SCAN
+/* max db entries selected per scan */
+#define MAX_DB_ENTRY_SELECTED_PER_SCAN PLATFORM_MAX_DB_ENTRY_SELECTED_PER_SCAN
+
+#define ICMP_MSG_RATE_LIMIT 3 /* rate limit for icmp message */
+#define V4_CONFIG_DELETE_TO 600 /* timeout for entry to be deleted */
+
+/* session timeout */
+
+extern u16 tcp_initial_setup_timeout;
+extern u16 tcp_active_timeout;
+extern u16 udp_init_session_timeout;
+extern u16 udp_act_session_timeout;
+extern u16 icmp_session_timeout;
+
+extern u8 timeout_dirty_flag;
+
+/* mapping refresh direction,
+ * 0 outbound only refresh,
+ * 1 inbound and outbound refresh
+ */
+extern u8 mapping_refresh_both_direction;
+
+
+extern u16 cnat_main_db_max_ports_per_user;
+extern u32 cnat_main_db_icmp_rate_limit;
+extern u32 cnat_main_db_icmp_rate_limit_core;
+extern u32 crc_zero_udp_rate_limit_core;
+
+extern u16 cnat_static_port_range;
+
+typedef enum {
+ LOG_FORMAT_UNDEFINED =0,
+ LOG_FORMAT_COMPACT,
+ LOG_FORMAT_NF9,
+ LOG_FORMAT_MAX, /* keep this as last */
+} log_format_t;
+
+typedef enum {
+ CNAT_CONFIG_DEL_OP = 0,
+ CNAT_CONFIG_ADD_OP,
+} cnat_op_flag_t;
+
+extern u8 ftp_alg_enabled;
+extern u16 rtsp_alg_port_num;
+
+/*
+ * load balancing debug mode
+ */
+extern u8 lb_debug_enable;
+
+/* good or evil mode
+ * 0 endpoint-independnet filter, good mode
+ * 1 address depedent filter, evil mode
+ */
+extern u8 address_dependent_filtering;
+
+extern u16 per_user_icmp_msg_limit;
+
+/* vrfmap or portmap holding time
+ * after delete
+ */
+extern u16 config_delete_timeout;
+
+/*
+ * Bit map for various configuration in the POLICY KNOB case
+ */
+#define BIDIR_REFRESH_ENABLE 0x01
+#define BIDIR_REFRESH_DISABLE 0x02
+#define FTP_ALG_ENABLE 0x04
+#define FTP_ALG_DISABLE 0x08
+#define DEFAULT_NFV9_LOGGING_SERVER_ENABLE 0x10
+#define DEFAULT_NFV9_LOGGING_SERVER_DISABLE 0x20
+
+
+/*
+ * This structure contains a single VRF map configuration
+ * from a bulk message. This structure is in conformanace
+ * with the following structures defined in cnat_config_api.h
+ * - spp_api_cnat_v4_bulk_vrf_map_t
+ *
+ * Any change in the above structures should be propagated here
+ */
+typedef struct _spp_api_cnat_v4_single_vrf_map_req {
+ u32 i_vrf_id;
+ u32 o_vrf_id;
+
+ u16 i_vrf;
+ u16 o_vrf;
+
+ u32 start_addr;
+ u32 end_addr;
+
+ u16 vrf_policy_enable;
+#define TCP_MSS_ENABLE 0x0001
+#define TCP_MSS_DISABLE 0x0002
+#define NFV9_LOGGING_ENABLE 0x0004
+#define NFV9_LOGGING_DISABLE 0x0008
+#define VRF_MAP_DELETE 0x0010
+#define VRF_MAP_ADD 0x0020
+#define BULK_ALLOC_CHANGE 0x0040
+
+ u16 tcp_mss_value;
+ u32 vrf_nfv9_logging_ipv4_address;
+ u16 vrf_nfv9_logging_udp_port;
+ u16 vrf_nfv9_refresh_rate;
+ u16 vrf_nfv9_timeout_rate;
+ u16 vrf_nfv9_path_mtu;
+#ifndef NO_BULK_LOGGING
+ bulk_alloc_size_t bulk_size;
+#endif /* NO_BULK_LOGGING */
+} spp_api_cnat_v4_single_vrf_map_req;
+
+typedef struct _spp_api_cnat_v4_single_vrf_map_rc {
+ u8 vrf_map_rc;
+ u8 tcp_mss_rc;
+ u8 nfv9_logging_rc;
+ u8 pad;
+} spp_api_cnat_v4_single_vrf_map_rc;
+
+/*
+ * Bulk Response for the VRF map request
+ */
+typedef struct _spp_api_cnat_v4_bulk_vrf_map_resp {
+ u16 _spp_msg_id;
+ u8 bulk_rc;
+ u8 pad;
+
+ u32 num_vrfmap_entries;
+
+ spp_api_cnat_v4_single_vrf_map_rc vrf_map_rc;
+
+} spp_api_cnat_v4_bulk_vrf_map_resp;
+
+/*
+ * Bulk Response for the Policy Knob request
+ */
+typedef struct _spp_api_cnat_v4_bulk_policy_knob_resp {
+ u16 _spp_msg_id;
+ u8 bulk_rc; /* Global rc code */
+ u8 pad;
+
+ u8 port_limit_rc;
+ u8 icmp_timeout_rc;
+ u8 udp_init_timeout_rc;
+ u8 udp_act_timeout_rc;
+
+ u8 tcp_init_timeout_rc;
+ u8 tcp_act_timeout_rc;
+ u8 nfv9_logging_rc;
+ u8 pad2;
+} spp_api_cnat_v4_bulk_policy_knob_resp;
+
+
+/* PPTP ALG defs and structures */
+
+/* dont change the order..
+ maintened at offset mapped to msg ids */
+
+typedef struct pptp_ctrl_msg_ctrs_t {
+ u64 dummy;
+ u64 sccr;
+ u64 sccrp;
+ u64 stccrq;
+ u64 stccrp;
+ u64 erq;
+ u64 erp;
+ u64 ocrq;
+ u64 ocrp;
+ u64 icrq;
+ u64 icrp;
+ u64 iccn;
+ u64 cclr;
+ u64 cdn;
+ u64 wen;
+ u64 sli;
+}pptp_ctrl_msg_ctrs_t;
+
+#define PPTP_INCR(ctr) pptp_cfg.counters.pptp_##ctr++
+#define PPTP_DECR(ctr) pptp_cfg.counters.pptp_##ctr--
+
+typedef struct pptp_counters_t {
+
+ u64 pptp_ctrl_msg_drops;
+ u64 pptp_active_tunnels;
+ u64 pptp_active_channels;
+ u64 pptp_in2out_gre_drops;
+ u64 pptp_out2in_gre_drops;
+ u64 pptp_in2out_gre_fwds;
+ u64 pptp_out2in_gre_fwds;
+ pptp_ctrl_msg_ctrs_t ctrl_ctrs;
+
+} pptp_counters_t;
+
+#define CNAT_PPTP_ENABLE 1
+#define CNAT_PPTP_DEF_TIMEOUT 60 /* secs */
+
+typedef struct cnat_pptp_config_t {
+ u8 enable;
+ u16 timeout;
+ pptp_counters_t counters;
+
+} cnat_pptp_config_t;
+
+
+#define CNAT_PPTP_ENABLE_FLAG 0x01
+#define CNAT_PPTP_TIMEOUT_FLAG 0x02
+
+/* pptp config msg resp */
+typedef struct _spp_api_cnat_v4_config_pptp_alg_resp {
+ u16 _spp_msg_id;
+ u8 bulk_rc;
+ u8 pad;
+
+} spp_api_cnat_v4_config_pptp_alg_resp_t;
+
+typedef struct {
+ u16 msg_id;
+ u8 rc;
+ u8 pad[5];
+
+ /* better to have a group structures rather than individual
+ variables, any change in counters is will automatically
+ reflect here */
+ pptp_counters_t counters;
+} pptp_show_counters_resp_t ;
+
+
+extern cnat_pptp_config_t pptp_cfg;
+
+
+/* ========= 6RD declarations =============================== */
+
+#define V6RD_ENTRY_DELETE 0x00
+#define IPV4_TUNNEL_SRC_CONFIG 0x04
+#define TUNNEL_MTU_CONFIG 0x08
+#define IPV4_PREFIXMASK_LEN_CONFIG 0x10
+#define IPV4_SUFFIXMASK_LEN_CONFIG 0x20
+#define TTL_CONFIG 0x40
+#define TOS_CONFIG 0x80
+#define V6RD_IPV6_PREFIX_CONFIG 0x100
+#define V6RD_RESET_DF_BIT_CONFIG 0x200
+#define V6RD_UNICAST_ADDR_CONFIG 0x400
+#define V6RD_REASSEMB_CONFIG 0x800
+
+#define TTL_ENABLE 0x1
+#define TOS_ENABLE 0x2
+#define RESET_DF_BIT 0x4
+#define REASSEMBLY_ENABLE 0x8
+
+/* ========= 6RD declarations =============================== */
+
+/*
+ * Single Request for XLAT config
+ */
+typedef struct _spp_api_cnat_v4_single_xlat_config_req {
+
+ /*
+ * Indicates the xlat instance id - How big will this value be
+ * Can we restrict it between 0..255, that way the APP code
+ * can use an array to store the xlat instances.
+ */
+ u32 xlat_id;
+
+#define XLAT_ENTRY_DELETE 0x0000
+#define IPV6_SVI_IF_NUM_CONFIG 0x0001
+#define IPV4_SVI_IF_NUM_CONFIG 0x0002
+#define IPV4_TO_IPV6_TCP_MSS_CONFIG 0x0004
+#define IPV6_TO_IPV4_TCP_MSS_CONFIG 0x0008
+#define IPV6_PREFIX_CONFIG 0x0010
+#define IPV6_UBIT_ON_CONFIG 0x0020
+#define IPV6_NON_TRANSLATABLE_PREFIX_MAP_CONFIG 0x0040
+#define IPV4_TOS_SETTING_CONFIG 0x0080
+#define IPV6_TOS_SETTING_CONFIG 0x0100
+#define IPV4_DFBIT_CLEAR_CONFIG 0x0200
+#define ICMPV6_PTB_MTU_SET_CONFIG 0x0400
+#define IPV6_NON_TRANSLATABLE_PREFIX_MAP_ALG_CONFIG 0x0800
+#define CPE_V4_PREFIX_CONFIG 0x1000 /* for map-t */
+#define CPE_V6_PREFIX_CONFIG 0x2000 /* for map-t */
+#define EXTERNAL_V6_PREFIX_CONFIG 0x4000 /* for map-t */
+#define PORT_SHARING_RATIO_CONFIG 0x8000 /* for map-t */
+#define CONSECUTIVE_PORTS_CONFIG 0x10000 /* for map-t */
+
+ u32 xlat_config_fields_enable;
+
+ /*
+ * If numbers of the IPv6 and IPv4 SVI interfaces
+ */
+ u32 ipv6_svi_if_num;
+ u32 ipv4_svi_if_num;
+
+ /*
+ * TCP MSS values for the 2 XLAT directions
+ */
+ u16 v4_to_v6_tcp_mss;
+ u16 v6_to_v4_tcp_mss;
+
+ /*
+ * XLAT IPv6 prefix
+ */
+ u32 v6_prefix[4];
+
+ /*
+ * XLAT IPv6 prefix mask
+ */
+ u8 v6_prefix_mask_len;
+
+ /*
+ * Set to non-zero if UBITs are reserved
+ */
+#define UBITS_ON 0x01
+#define IPV4_DF_BIT_CLEAR 0x02
+#define ICMPV6_MTU_SET 0x04
+#define IPV4_TOS_SET_ENABLED 0x08
+#define IPV6_TC_SET_ENABLED 0x10
+
+ u8 feature_enable_bits;
+
+ u8 v4_prefix_mask_len;
+
+#define IPV6_NON_TRANSLATABLE_PREFIX_MAP_ALG_HASH 0x1
+#define IPV6_NON_TRANSLATABLE_PREFIX_MAP_ALG_TTL 0x2
+#define IPV6_NON_TRANSLATABLE_PREFIX_MAP_ALG_RANDOM 0x3
+ u8 non_translatable_v6_prefix_v4_map_prefix_alg;
+
+ u8 ipv6_tos_value;
+
+ u8 ipv4_tos_value;
+
+ u8 pad2;
+
+ u8 pad3;
+
+ u32 v4_prefix;
+
+ /*
+ * MAP-T/MAP-E specific parameters
+ */
+ u8 xlat_type;
+
+ u32 cpe_domain_v6_prefix[4];
+ u8 cpe_domain_v6_prefix_len;
+
+ u32 cpe_domain_v4_prefix;
+ u8 cpe_domain_v4_prefix_len;
+
+ u32 external_domain_v6_prefix[4];
+ u8 external_domain_v6_prefix_len;
+
+ u8 port_sharing_ratio_bits;
+ u8 consecutive_ports_bits;
+
+} spp_api_cnat_v4_single_xlat_config_req;
+
+/*
+ * Single Response for the xlat config request
+ */
+typedef struct _spp_api_cnat_v4_single_xlat_config_resp {
+ u8 v4_if_num_rc;
+ u8 v6_if_num_rc;
+ u8 v4_to_v6_tcp_mss_rc;
+ u8 v6_to_v4_tcp_mss_rc;
+
+ u8 v6_prefix_rc;
+ u8 ubit_on_rc;
+ u8 v4_prefix_rc;
+ u8 xlat_id_rc;
+
+ u8 non_translatable_v6_prefix_v4_map_alg_rc;
+ u8 ipv4_dfbit_clear_rc;
+ u8 icmpv6_ptb_mtu_set_rc;
+ u8 ipv4_tos_set_rc;
+
+ u8 ipv6_tos_set_rc;
+ u8 pad1;
+ u8 pad2;
+ u8 pad3;
+} spp_api_cnat_v4_single_xlat_config_resp;
+
+/*
+ * Bulk Response for the xlat config request
+ */
+typedef struct _spp_api_cnat_v4_bulk_xlat_config_resp {
+ u16 _spp_msg_id;
+ u16 pad;
+
+ u32 bulk_rc;
+
+ u32 num_xlat_entries;
+
+ spp_api_cnat_v4_single_xlat_config_resp xlat_config_resp;
+
+} spp_api_cnat_v4_bulk_xlat_config_resp;
+
+typedef struct _spp_api_v6rd_v4_single_v6rd_config_resp {
+ u8 v6rd_id_rc;
+ u8 v4_if_num_rc;
+ u8 v6_if_num_rc;
+ u8 tunnel_source_rc;
+ u8 tunnel_mtu_rc;
+ u8 ipv4masklen_prefix_rc;
+ u8 ipv4masklen_suffix_rc;
+ u8 ttl_rc;
+ u8 tos_rc;
+ u8 anycast_rc;
+ u8 v6_prefix_rc;
+ u8 v6_br_unicast_rc;
+ u8 reassembly_rc;
+ u8 pad1;
+ u8 pad2;
+ u8 pad3;
+} spp_api_v6rd_v4_single_v6rd_config_resp_t;
+
+typedef struct _spp_api_v6rd_v4_bulk_v6rd_config_resp {
+ u16 _spp_msg_id;
+ u16 pad;
+ u32 bulk_rc;
+ u32 num_v6rd_entries;
+ spp_api_v6rd_v4_single_v6rd_config_resp_t v6rd_config_resp[0];
+} spp_api_v6rd_v4_bulk_v6rd_config_resp_t;
+
+/*
+ * Single Request for MAPE config
+ */
+typedef struct _spp_api_mape_single_config_req {
+
+ /*
+ * Indicates the mape instance id - How big will this value be
+ * Can we restrict it between 0..255, that way the APP code
+ * can use an array to store the xlat instances.
+ */
+ u32 mape_id;
+
+#define MAPE_ENTRY_DELETE 0x0000
+#define MAPE_IPV4_SVI_IF_NUM_CONFIG 0x0001
+#define MAPE_IPV6_SVI_IF_NUM_CONFIG 0x0002
+#define MAPE_IPV4_TO_IPV6_TCP_MSS_CONFIG 0x0004
+#define MAPE_IPV6_TO_IPV4_TCP_MSS_CONFIG 0x0008
+#define MAPE_CPE_V4_PREFIX_CONFIG 0x0010
+#define MAPE_CPE_V6_PREFIX_CONFIG 0x0020
+#define MAPE_PORT_SHARING_RATIO_CONFIG 0x0040
+#define MAPE_CONSECUTIVE_PORTS_CONFIG 0x0080
+#define MAPE_PATH_MTU 0x0100
+#define MAPE_TUNNEL_ENDPOINT_V6_CONFIG 0x0200
+
+ u32 mape_config_fields_enable;
+
+ /*
+ * If numbers of the IPv6 and IPv4 SVI interfaces
+ */
+ u32 ipv6_svi_if_num;
+ u32 ipv4_svi_if_num;
+
+ /*
+ * TCP MSS values for the 2 XLAT directions
+ */
+ u16 v4_to_v6_tcp_mss;
+ u16 v6_to_v4_tcp_mss;
+
+ /*
+ * Path v6 MTU.
+ */
+ u32 path_mtu;
+
+ /*
+ * CPE IPv6 prefix and mask len.
+ */
+ u32 cpe_domain_v6_prefix[4];
+ u8 cpe_domain_v6_prefix_len;
+
+ /*
+ * CPE IPv4 prefix and mask len.
+ */
+ u32 cpe_domain_v4_prefix;
+ u8 cpe_domain_v4_prefix_len;
+
+ /*
+ * BR IPv6 tunnel end point V6 prefix and mask len.
+ */
+ u32 aftr_tunnel_endpoint_address_v6[4];
+ u8 aftr_tunnel_endpoint_address_v6_len;
+
+ /*
+ * BR IPv6 tunnel end point V6 prefix and mask len.
+ */
+ u8 port_sharing_ratio_bits;
+ u8 consecutive_ports_bits;
+
+} spp_api_mape_single_config_req;
+
+
+/*
+ * Single Response for the mape config response
+ */
+typedef struct _spp_api_mape_single_config_resp {
+ u8 v4_if_num_rc;
+ u8 v6_if_num_rc;
+ u8 v4_to_v6_tcp_mss_rc;
+ u8 v6_to_v4_tcp_mss_rc;
+ u8 mape_id_rc;
+ u8 path_mtu_rc;
+ u8 cpe_v6_prefix_rc;
+ u8 cpe_v4_prefix_rc;
+ u8 tunnel_endpoint_prefix_rc;
+ u8 port_sharing_ratio_rc;
+ u8 port_contiguous_rc;
+ u8 pad1;
+} spp_api_mape_single_config_resp;
+
+/*
+ * Bulk Response for the mape config request
+ */
+typedef struct _spp_api_mape_bulk_config_resp {
+ u16 _spp_msg_id;
+ u16 pad;
+ u32 bulk_rc;
+ u32 num_mape_entries;
+ spp_api_mape_single_config_resp mape_config_resp;
+} spp_api_mape_bulk_config_resp;
+
+
+#endif /* __CNAT_CONFIG_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_config_api.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_config_api.h
new file mode 100644
index 00000000..0789d6a9
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_config_api.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __CNAT_CONFIG_API_H__
+#define __CNAT_CONFIG_API_H__
+
+typedef struct _spp_api_cnat_v4_add_vrf_map {
+ u16 _spp_msg_id;
+ u8 rc;
+ u8 pad;
+ u32 i_vrf_id;
+ u32 o_vrf_id;
+ u16 i_vrf;
+ u16 o_vrf;
+ u32 start_addr[8];
+ u32 end_addr[8];
+} spp_api_cnat_v4_add_vrf_map_t;
+
+typedef struct _spp_api_cnat_v4_config_nfv9_logging {
+ u16 _spp_msg_id;
+ u8 rc;
+ u8 enable;
+ u32 ipv4_address;
+ u32 i_vrf_id;
+ u16 i_vrf;
+ u16 port;
+ u16 refresh_rate;
+ u16 timeout_rate;
+ u16 path_mtu;
+ u8 nfv9_global_collector;
+ u8 session_logging;
+} spp_api_cnat_v4_config_nfv9_logging_t;
+
+
+#endif
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_db.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_db.h
new file mode 100644
index 00000000..3596e238
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_db.h
@@ -0,0 +1,701 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_db.h - translation database definitions
+ *
+ * Copyright (c) 2007-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_DB_H__
+#define __CNAT_DB_H__
+
+#include "cnat_cli.h"
+#include "cnat_ports.h"
+#include "index_list.h"
+
+#define VRF_NAME_LEN_STORED 12
+#define MAX_VRFID 400
+typedef struct _cnat_svi_params_entry {
+ u16 svi_type;
+ u16 pad;
+
+ u32 vrf_id;
+ u16 if_num;
+
+ u32 ipv6_addr[4];
+ u32 ipv4_addr;
+
+ u8 direction;
+ u32 tbl_id; /* vrf */
+ u32 vrf_override_id; /* tbl_id for override vrf */
+ u8 vrf_override_flag;
+ u8 partition_id;
+} cnat_svi_params_entry;
+
+typedef struct _cnat_ingress_vrfid_name_entry {
+ u32 vrf_id;
+ u16 ref_count; /*no# of serviceApps under a single vrf*/
+ u8 vrf_name[VRF_NAME_LEN_STORED];
+ u16 pad1;
+} cnat_ingress_vrfid_name_entry;
+#define HASH_ENHANCE 4
+
+#define CNAT_DB_SIZE (PLATFORM_MAX_NAT_ENTRIES / PLATFORM_CNAT_INSTS)
+#define CNAT_MAIN_HASH_SIZE (HASH_ENHANCE * PLATFORM_CNAT_MAIN_PRELIM_HASH_SIZE)
+#define CNAT_MAIN_HASH_MASK (CNAT_MAIN_HASH_SIZE-1)
+
+#define CNAT_USER_DB_SIZE (PLATFORM_MAX_USER_ENTRIES / PLATFORM_CNAT_INSTS)
+#define CNAT_USER_HASH_SIZE (HASH_ENHANCE * PLATFORM_CNAT_USER_PRELIM_HASH_SIZE)
+#define CNAT_USER_HASH_MASK (CNAT_USER_HASH_SIZE-1)
+
+#define CNAT_SESSION_DB_SIZE (PLATFORM_MAX_NAT_ENTRIES / PLATFORM_CNAT_INSTS)
+#define CNAT_SESSION_HASH_SIZE (HASH_ENHANCE * PLATFORM_CNAT_MAIN_PRELIM_HASH_SIZE)
+#define CNAT_SESSION_HASH_MASK (CNAT_SESSION_HASH_SIZE-1)
+
+
+#define CNAT_MAX_SESSIONS_PER_BIB 0xFFFF
+
+#define NUM_BITS_IN_UWORD (8*sizeof(uword))
+
+/* No. of per ip/port config will be limited to 1024 */
+#define CNAT_TIMEOUT_HASH_SIZE 1024
+#define CNAT_TIMEOUT_HASH_MASK (CNAT_TIMEOUT_HASH_SIZE - 1)
+#define CNAT_TIMEOUT_FULL_MASK 0xFFFFFFFFFFFFFFFF
+#define CNAT_TIMEOUT_IPPROT_MASK PLATFORM_CNAT_TIMEOUT_IPPROT_MASK
+#define CNAT_TIMEOUT_PORTPROT_MASK PLATFORM_CNAT_TIMEOUT_PORTPROT_MASK
+
+#define TRUE 1
+#define FALSE 0
+
+/*
+ * The key structure. All fields are in NETWORK byte order!
+ */
+typedef struct {
+ u32 ipv4;
+ u16 port;
+ u16 vrf; //bit0-12:vrf, bit13:unused, bit14-15:protocol
+} cnat_db_key_t;
+
+/* bit14-15:protocol in cnat_db_key_t */
+#define CNAT_INVALID_PROTO 0x0000
+#define CNAT_PPTP 0x0000
+#define CNAT_UDP 0x4000
+#define CNAT_TCP 0x8000
+#define CNAT_ICMP 0xc000
+#define CNAT_VRF_MASK 0x3fff
+#define CNAT_PRO_MASK 0xc000
+#define CNAT_PRO_SHIFT 14
+
+/*
+ * Maximum number of VRF entries supported
+ */
+#define CNAT_MAX_VRFMAP_ENTRIES (CNAT_VRF_MASK + 1)
+/*
+ * for hashing purposes, fetch the key in one instr.
+ */
+typedef union {
+ cnat_db_key_t k;
+ u64 key64;
+} cnat_key_t;
+
+typedef struct {
+ cnat_key_t k;
+ u32 bucket;
+} cnat_db_key_bucket_t;
+
+typedef struct {
+ u32 ipv6[4];
+ cnat_key_t ipv4_key;
+} dslite_key_t;
+
+typedef struct {
+/*
+ cnat_db_key_bucket_t ck;
+ u32 ipv6[4];
+*/
+ dslite_key_t dk;
+ u32 bucket;
+} dslite_db_key_bucket_t;
+
+
+/* Per port/ip timeout related strucutres */
+extern index_slist_t *cnat_timeout_hash;
+
+typedef struct {
+ cnat_key_t timeout_key;
+ u16 timeout_value;
+} cnat_timeout_t;
+
+typedef struct {
+ cnat_timeout_t t_key;
+ index_slist_t t_hash;
+} cnat_timeout_db_entry_t;
+
+extern cnat_timeout_db_entry_t *cnat_timeout_db;
+
+/*
+ * Main translation database entries. Currently 0x5A = 90 bytes in length.
+ * Given 20,000,000 entries, it saves nearly 1gb of SDRAM to pack the entries
+ * and pay the extra prefetch. So, that's what we do.
+ */
+
+typedef struct {
+ /* 0x00 */
+ index_slist_t out2in_hash; /* hash-and-chain, x2 */
+ index_slist_t in2out_hash;
+
+ /* 0x08 */
+ u16 flags; /* Always need flags... */
+#define CNAT_DB_FLAG_PORT_PAIR (1<<0)
+#define CNAT_DB_FLAG_TCP_ACTIVE (1<<1)
+#define CNAT_DB_FLAG_ENTRY_FREE (1<<2)
+#define CNAT_DB_FLAG_UDP_ACTIVE (1<<3)
+#define CNAT_DB_FLAG_STATIC_PORT (1<<4)
+/* This alg entry is set for FTP data connection */
+#define CNAT_DB_FLAG_ALG_ENTRY (1<<5)
+
+/* Will be set for TCP connection with destination port - 1723
+ * note - here CNAT_DB_FLAG_TCP_ACTIVE is also set */
+#define CNAT_DB_FLAG_PPTP_TUNNEL_INIT (1<<6)
+#define CNAT_DB_FLAG_PPTP_TUNNEL_ACTIVE (1<<7)
+
+/* for PPTP GRE packtes */
+#define CNAT_DB_FLAG_PPTP_GRE_ENTRY (1<<8)
+
+/* for PCP support */
+#define CNAT_DB_FLAG_PCPI (1<<9)
+#define CNAT_DB_FLAG_PCPE (1<<10)
+#define CNAT_PCP_FLAG (CNAT_DB_FLAG_PCPI | CNAT_DB_FLAG_PCPE)
+
+#define CNAT_TAC_SEQ_MISMATCH (1<<11)
+/* This alg entry is set for ftp control connection */
+#define CNAT_DB_FLAG_ALG_CTRL_FLOW (1<<12)
+
+/* This is for marking the state where connection is closing */
+#define CNAT_DB_FLAG_TCP_CLOSING (1<<13)
+
+#define CNAT_DB_DSLITE_FLAG (1<<14)
+#define CNAT_DB_NAT64_FLAG (1<<15)
+
+ /* 0x0A */
+ u16 vrfmap_index; /* index of vrfmap */
+
+ /* 0x0C */
+ u32 user_index; /* index of user that owns this entry */
+
+ /* 0x10 */
+ cnat_key_t out2in_key; /* network-to-user, outside-to-inside key */
+
+ /* 0x18 */
+ cnat_key_t in2out_key; /* user-to-network, inside-to-outside key */
+
+ /* 0x20 */
+ index_dlist_t user_ports; /* per-user translation list */
+
+ /* 0x28 */
+ u32 out2in_pkts; /* pkt counters */
+
+ /* 0x2C */
+ u32 in2out_pkts;
+
+ /* 0x30 */
+ u32 entry_expires; /* timestamp used to expire translations */
+
+ /* 0x34 */
+ union { /* used by FTP ALG, pkt len delta due to FTP PORT cmd */
+ u16 delta;
+ i8 alg_dlt[2]; /* two delta values, 0 for previous, 1 for current */
+ u16 il; /* Used to indicate if interleaved mode is used
+ in case of RTSP ALG */
+ } alg;
+
+ /* 0x36 */
+ u16 timeout;
+
+ /* 0x38 */
+ union {
+ struct seq_pcp_t {
+ u32 tcp_seq_num; /* last tcp (FTP) seq # that has pkt len change due to PORT */
+ u32 pcp_lifetime; /* peer and map life time value sent in reply*/
+ } seq_pcp;
+
+ /* This is for TCP seq check */
+ struct tcp_seq_chk_t {
+ u32 seq_no;
+ u32 ack_no;
+ } tcp_seq_chk;
+
+ /* used for pptp alg entries
+ 1. only tunnel : prev and next = 0xFFFFFFFF
+ 2. first gre entry : prev = tunnel db, next = next gre db
+ 3. last gre entry : prev = previous gre/tunnel db, next= 0xFFFFFFFF;
+
+ *while adding gre entry- updated at the begining of head
+ *while deleting gre entry - hash look up will be done and prev and next are adjusted
+ * while deleting need not traverse throufgh the list, as done in index_dlist_remelem
+
+ */
+ index_dlist_t pptp_list;
+
+ } proto_data;
+
+ /* 0x40 */
+ u32 dst_ipv4; /* pointer to ipv4 dst list, used in evil mode */
+
+ /* 0x44 */
+ u16 dst_port;
+
+ /* 0x46 */
+ u16 dslite_nat44_inst_id;
+
+ /* 0x48 */
+ u32 session_head_index;
+
+ /* 0x4C */
+ u16 nsessions;
+
+ /* 0x4E */
+ u8 unused;
+
+ /* 0x4F */
+ u8 scale;
+
+ /* 0x50 */
+ u32 diff_window;
+
+ /* Sizeof cnat_main_db_entry_t = 0x54 */
+} cnat_main_db_entry_t;
+
+/* Caution ...
+ * 1. The size of this structure should be same as that of
+ * nat64_bib_user_entry_t
+ * 2. Do not alter the position of first four fields
+ */
+typedef struct {
+ /* 0x00 */
+ index_slist_t user_hash; /* hash 'n chain bucket chain */
+
+ /* 0x04 */
+ u16 ntranslations; /* translations hold by this user */
+
+ /* 0x06 */
+ u8 icmp_msg_count; /* use to rate limit imcp send to this user */
+
+ /* 0x07 */
+ u8 flags; /* To identfiy whether it is NAT64 or NAT44 etc */
+#define CNAT_USER_DB_NAT44_FLAG 0
+#define CNAT_USER_DB_NAT64_FLAG 1
+#define CNAT_USER_DB_DSLITE_FLAG 2
+#define CNAT_USER_DB_PORT_LIMIT_EXCEEDED 0X80
+
+ /* 0x08 */
+ u32 translation_list_head_index;
+
+ /* 0x0C */
+ u32 portmap_index; /* index of bound port-map */
+
+ /* 0x10 */
+ cnat_key_t key; /* For dslite this should store IPv6 address */
+ u32 ipv6[4]; // B4 ipv6 address
+ /* 0x18 */
+#if 0
+ u32 temp1;
+ u32 temp2;
+ u32 temp3;
+#endif
+ /* 0x28 same as nat64_user_db */
+#ifndef NO_BULK_LOGGING
+ /* Now adding 8 more bytes for bulk allocation.. This makes it
+ * 0x30 (48). Added the same to nat64_bib_user_entry_t make the
+ * the sizes equal. For nat64 stful, we may support bulk allocation
+ * later.
+ */
+ /* Indicates the currently used bulk port range */
+ i16 bulk_port_range_cache[BULK_RANGE_CACHE_SIZE];
+#endif /* #ifndef NO_BULK_LOGGING */
+} cnat_user_db_entry_t;
+
+/*
+ * cnat_session_entry_t
+ * This structure represents the cnat session table. It maintains the
+ * information about the destination of a given translation (main db)
+ * There would be entry here only if packets are send to more than 1 destn
+ * from the same source.
+ */
+typedef struct {
+
+ /* 0x00 */
+ index_slist_t cnat_session_hash;
+
+ /* 0x04 */
+ u32 main_db_index; /* would point to v4 src transport address */
+
+ /* 0x08 */
+ cnat_key_t v4_dest_key;
+
+ /* 0x10 */
+ u16 flags; /* Same as cnat_main_db_t */
+
+ /* 0x12 */
+ u16 timeout;
+
+ /* 0x14 */
+ u32 entry_expires;
+ /* 0x18 */
+ index_dlist_t main_list;
+ /* 0x20 = 32 B */
+
+ union { /* alg same as cnat_main_db_t */
+ u16 delta;
+ i8 alg_dlt[2];
+ u16 il;
+ } alg;
+
+ /* 0x22 */
+ u16 tcp_flags;
+
+ /* 0x24 */
+ u32 tcp_seq_num;
+
+ /* 0x28 */
+ u32 ack_no;
+
+ /* 0x2C */
+ u32 window;
+
+ /* 0x30 */
+ u8 scale;
+
+ /* 0x31 */
+ u8 pad;
+
+ /* 0x32 */
+} cnat_session_entry_t;
+
+
+
+/*
+ * out2in and in2out hash bucket arrays are simply arrays of index_slist_t's
+ */
+
+typedef enum {
+ CNAT_DB_CREATE_DEFAULT=0, /* honor cnat_main_db_max_ports_per_user */
+ CNAT_DB_CREATE_OVERRIDE, /* just do it. */
+} cnat_db_create_policy_t;
+
+typedef struct {
+ cnat_key_t in2out_key;
+ cnat_key_t out2in_key;
+ u32 dst_ipv4; /* evil for mode only */
+ u16 cnat_instance;
+ cnat_portmap_t *portmap;
+ u16 *portmap_inuse;
+ cnat_main_db_entry_t *db;
+ cnat_db_create_policy_t policy;
+ port_pair_t pair_of_ports;
+} cnat_db_create_args_t;
+
+extern cnat_main_db_entry_t *cnat_main_db;
+extern cnat_user_db_entry_t *cnat_user_db;
+extern cnat_session_entry_t *cnat_session_db;
+
+#define S_WAO 0
+#define S_WA 1 /* waiting for address pool */
+#define S_WO 2 /* waiting for outside vrf */
+#define S_RUN 3 /* got everything */
+#define S_DEL 4 /* just delete */
+
+#define INVALID_UIDX 0xffff /*invalid svi app uidb index */
+#define INVALID_VRFID 0xffffffff /*invalid vrf id */
+
+typedef struct {
+ u16 status;
+ u16 tcp_mss; //tcp max segment size for this inside vrf */
+ u32 delete_time;
+ u16 i_vrf; //inside SVI uidx
+ u16 o_vrf; //outside SVI uidx
+ u32 i_vrf_id; //inside vrf id
+ u32 o_vrf_id; //outside vrf id
+ cnat_portmap_v2_t *portmap_list;
+ u32 nfv9_logging_index;
+ u32 syslog_logging_index;
+ u16 ip_n_to_1;
+#ifndef NO_BULK_LOGGING
+ bulk_alloc_size_t bulk_size;
+#endif /* #ifndef NO_BULK_LOGGING */
+ u32 pcp_server_addr;
+ u32 pcp_server_port;
+
+ u8 nf_logging_policy;
+ u8 syslog_logging_policy;
+ u8 frag_tout;
+ u32 rseed_ip;
+ u16 port_limit;
+ u8 tcp_seq_check_enable;
+ u8 pad;
+ u32 tcp_seq_user_window;
+ u8 filter_policy;
+ u8 ignore_port;
+} cnat_vrfmap_t;
+
+/*
+ * When creating cnat_vrfmap entry, ensure that any already
+ * configured logging info is taken into account
+ */
+#define CNAT_SET_VRFMAP_NFV9_LOGGING_INDEX(logging_index, i_vrf) \
+do { \
+ cnat_nfv9_logging_info_t *my_nfv9_logging_info = 0; \
+ pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info, ({ \
+ if (my_nfv9_logging_info->i_vrf == i_vrf) { \
+ logging_index = my_nfv9_logging_info - cnat_nfv9_logging_info; \
+ break; \
+ } \
+ })); \
+while (0)
+
+
+typedef struct {
+ /*
+ * spp_ctx_alloc() call failed
+ */
+ u64 nfv9_logging_context_creation_fail_count;
+
+ /*
+ * Cannot send the existing logging pkt, so cannot create
+ * any additional packets for logging purposes
+ */
+ u64 nfv9_logging_context_creation_deferred_count;
+
+ /*
+ * Cannot send the existing logging pkt due to cnat_rewrite_output
+ * superframe being full.
+ */
+ u64 nfv9_downstream_constipation_count;
+
+ /*
+ * buffer for spp_ctx_alloc() call failed
+ */
+ u64 nfv9_logging_context_buffer_allocation_fail_count;
+
+} cnat_global_counters_t;
+
+
+extern cnat_global_counters_t cnat_global_counters;
+
+extern u16 *cnat_portmap_indices_by_vrf;
+extern cnat_vrfmap_t *cnat_portmap_by_vrf;
+extern cnat_portmap_t **cnat_portmaps;
+extern u16 **cnat_portmaps_inuse;
+
+extern cnat_vrfmap_t *cnat_map_by_vrf;
+
+/*
+ * Special define to indicate that the VRF map index entry is empty
+ */
+#define VRF_MAP_ENTRY_EMPTY 0xffff
+extern u16 vrf_map_array[CNAT_MAX_VRFMAP_ENTRIES];
+
+extern cnat_svi_params_entry svi_params_array[CNAT_MAX_VRFMAP_ENTRIES];
+extern cnat_ingress_vrfid_name_entry vrfid_name_map[MAX_VRFID];
+
+extern index_slist_t *cnat_out2in_hash;
+extern index_slist_t *cnat_in2out_hash;
+extern index_slist_t *cnat_user_hash;
+extern index_slist_t *cnat_session_hash;
+
+typedef enum {
+ CNAT_DB_IN2OUT = 0,
+ CNAT_DB_OUT2IN,
+} cnat_db_which_t;
+
+typedef enum {
+ CNAT_NO_ICMP_MSG =0,
+ CNAT_ICMP_MSG,
+} cnat_icmp_msg_t;
+
+typedef struct {
+ cnat_errno_t error;
+ cnat_icmp_msg_t gen_icmp_msg;
+ u32 svi_addr;
+} cnat_gen_icmp_info;
+
+typedef cnat_vrfmap_t nat64_vrfmap_t;
+typedef cnat_portmap_v2_t nat64_portmap_v2_t;
+
+#define CNAT_V4_GET_HASH(key64, hash, mask) \
+ a = key64; \
+ b = c = 0x9e3779b97f4a7c13LL; \
+ /* Jenkins hash, arbitrarily use c as the "answer" */ \
+ hash_mix64(a, b, c); \
+ hash = c & mask;
+
+#define CNAT_V4_GET_SESSION_HASH(main_index, in_addr, port, vrf, hash, mask) \
+ a = main_index ^ in_addr ^ port ^ vrf; \
+ b = c = 0x9e3779b9; \
+ /* Jenkins hash, arbitrarily use c as the "answer" */ \
+ hash_mix32(a, b, c); \
+ hash = c & mask;
+
+#define CNAT_V4_GET_FRAG_HASH(key64, key32, hash, mask) \
+ a = key64; \
+ b = key32; \
+ c = 0x9e3779b97f4a7c13LL; \
+ hash_mix64(a, b, c); \
+ hash = c % mask;
+
+#define CNAT_DB_UPDATE_IN2OUT_TIMER \
+ db->entry_expires = cnat_current_time; \
+ db->in2out_pkts++;
+
+#define CNAT_DB_TIMEOUT_RST(db) \
+ if(PREDICT_TRUE(db->entry_expires != 0 )) \
+ db->entry_expires = cnat_current_time;
+
+#define DEBUG_I2O_DROP(debug_flag) \
+if (debug_i_flag & debug_flag) { \
+ cnat_db_debug_i2o_drop(&ki); \
+}
+
+
+cnat_main_db_entry_t *cnat_main_db_create (cnat_db_create_args_t *a);
+void cnat_main_db_entry_delete(cnat_main_db_entry_t *ep);
+
+void cnat_delete_main_db_entry(cnat_main_db_entry_t *ep);
+void cnat_delete_main_db_entry_v2(cnat_main_db_entry_t *ep);
+
+
+cnat_main_db_entry_t*
+cnat_get_main_db_entry(cnat_db_key_bucket_t *ki,
+ port_pair_t port_type,
+ cnat_errno_t *error,
+ cnat_user_db_entry_t ** user_db_entry);
+
+cnat_main_db_entry_t*
+cnat_get_main_db_entry_v2(cnat_db_key_bucket_t *ki,
+ port_pair_t port_pair_type,
+ port_type_t port_type,
+ cnat_gen_icmp_info *info,
+ cnat_key_t *dest_info);
+
+cnat_main_db_entry_t*
+cnat_create_static_main_db_entry_v2(cnat_db_key_bucket_t *ki,
+ cnat_db_key_bucket_t *ko,
+ cnat_vrfmap_t *my_vrfmap,
+ cnat_gen_icmp_info *info);
+
+cnat_main_db_entry_t*
+cnat_create_main_db_entry_and_hash(cnat_db_key_bucket_t *ki,
+ cnat_db_key_bucket_t *ko,
+ cnat_user_db_entry_t *udb);
+
+cnat_user_db_entry_t*
+cnat_user_db_create_entry(cnat_db_key_bucket_t *uki,
+ u32 portmap_index);
+
+cnat_user_db_entry_t*
+cnat_user_db_lookup_entry(cnat_db_key_bucket_t *uki);
+
+cnat_main_db_entry_t*
+cnat_main_db_lookup_entry(cnat_db_key_bucket_t *ki);
+
+cnat_main_db_entry_t*
+cnat_main_db_lookup_entry_out2in (cnat_db_key_bucket_t *ko);
+
+void cnat_main_db_entry_dump (cnat_main_db_entry_t *db);
+void cnat_db_in2out_hash_delete (cnat_main_db_entry_t *ep, cnat_user_db_entry_t *up);
+void cnat_db_out2in_hash_delete (cnat_main_db_entry_t *ep);
+void cnat_user_db_delete (cnat_user_db_entry_t *up);
+void cnat_db_debug_i2o_drop(cnat_db_key_bucket_t *ki);
+
+/*
+ * Function to dump the Hash Table that maps if_num to uidb_index
+ */
+extern void cnat_if_num_hash_table_dump(void);
+
+#define MAIN_DB_TYPE 0
+#define SESSION_DB_TYPE 1
+u16 query_and_update_db_timeout(void *db, u8 db_type);
+
+u16 cnat_timeout_db_create (cnat_timeout_t t_entry);
+void cnat_timeout_db_delete(cnat_key_t t_key);
+
+cnat_session_entry_t *
+cnat_create_session_db_entry(cnat_key_t *ko,
+ cnat_main_db_entry_t *bdb, u8 log);
+
+void cnat_dest_update_main2session(cnat_main_db_entry_t *mdb,
+ cnat_session_entry_t *sdb);
+
+cnat_session_entry_t *cnat_handle_1to2_session(
+ cnat_main_db_entry_t *mdb,
+ cnat_key_t *dest_info);
+
+void cnat_add_dest_n_log(
+ cnat_main_db_entry_t *mdb,
+ cnat_key_t *dest_info);
+
+cnat_session_entry_t *
+ cnat_session_db_lookup_entry(cnat_key_t *ko,u32 main_db_index);
+
+cnat_session_entry_t *
+ cnat_session_db_edm_lookup_entry(cnat_key_t *ko,
+ u32 session_head_index,
+ u32 main_db_index);
+
+
+typedef struct{
+ u32 sessions;
+ u32 active_translations;
+ u32 num_dynamic_translations;
+ u32 num_static_translations;
+ u64 in2out_drops_port_limit_exceeded;
+ u64 in2out_drops_system_limit_reached;
+ u64 in2out_drops_resource_depletion;
+ u64 no_translation_entry_drops;
+ u32 num_subscribers;
+ u32 dummy;
+ u64 drops_sessiondb_limit_exceeded;
+} nat44_dslite_common_stats_t;
+
+typedef struct {
+ u32 translation_delete_count;
+ u32 translation_create_count;
+ u32 out2in_forwarding_count;
+} nat44_dslite_global_stats_t;
+
+typedef struct {
+ u64 v4_to_v6_tcp_seq_mismatch_drop_count;
+ u64 v4_to_v6_tcp_seq_mismatch_count;
+ u64 v4_to_v6_out2in_session_create_count;
+ u64 v4_to_v6_end_point_filter_drop_count;
+} nat44_counters_stats_t;
+
+#define NAT44_STATS 0
+#define DSLITE_STATS 1
+extern nat44_dslite_common_stats_t nat44_dslite_common_stats[255]; /* 0 is for nat44 */
+extern nat44_dslite_global_stats_t nat44_dslite_global_stats[2]; /* 0 for nat44 and 1 for dslite */
+extern nat44_counters_stats_t nat44_counters_stats[CNAT_MAX_VRFMAP_ENTRIES];/*For displaying show cgn <cgn-name> inside-vrf <vrf-name> counters */
+
+#define NAT44_COMMON_STATS nat44_dslite_common_stats[NAT44_RESERVED_INST_ID]
+#define NAT44_GLOBAL_STATS nat44_dslite_global_stats[NAT44_STATS]
+#define DSLITE_GLOBAL_STATS nat44_dslite_global_stats[DSLITE_STATS]
+#define SESSION_LOG_ENABLE 1
+#define ALG_ENABLED_DB(db) \
+ ((db->flags & CNAT_PCP_FLAG) || \
+ (db->flags & CNAT_DB_FLAG_ALG_CTRL_FLOW) || \
+ (db->flags & (CNAT_DB_FLAG_PPTP_TUNNEL_INIT | \
+ CNAT_DB_FLAG_PPTP_TUNNEL_ACTIVE)))
+
+
+#endif /* __CNAT_DB_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_db_scanner.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_db_scanner.c
new file mode 100644
index 00000000..6e536d84
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_db_scanner.c
@@ -0,0 +1,493 @@
+/*
+ *---------------------------------------------------------------------------
+ * cnat_db_scanner.c - cnat_db_scanner dispatch function and initialization
+ *
+ * Copyright (c) 2009-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/error.h>
+#include <vnet/buffer.h>
+#include <vppinfra/string.h>
+#include <vppinfra/random.h>
+#include <vppinfra/fifo.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/format.h>
+
+
+#include "cnat_db.h"
+#include "cnat_logging.h"
+#include "cnat_global.h"
+#include "cnat_ipv4_udp.h"
+#include "cnat_common_api.h"
+
+u32 translation_create_count, translation_delete_count;
+u32 translation_create_rate, translation_delete_rate;
+
+u32 in2out_forwarding_count, out2in_forwarding_count;
+u32 in2out_forwarding_rate, out2in_forwarding_rate;
+
+u32 nat44_active_translations;
+u32 num_entries;
+uword check_these_pool_indices[2*MAX_DB_ENTRY_SELECTED_PER_SCAN];
+
+#define CNAT_DB_SCANNER_TURN_ON 5 /* just an arbitary number for easier debugging */
+
+//extern u32 pcp_throttle_count;
+
+typedef struct {
+ u32 cached_next_index;
+ /* $$$$ add data here */
+
+ /* convenience variables */
+ vlib_main_t * vlib_main;
+ vnet_main_t * vnet_main;
+} cnat_db_scanner_main_t;
+
+cnat_db_scanner_main_t cnat_db_scanner_main;
+
+
+static inline void check_session_for_expiry(
+ cnat_session_entry_t * sdb, u8 timeout_dirty
+ /*,dslite_table_entry_t *dslite_entry_ptr*/)
+{
+ void cnat_delete_session_db_entry (cnat_session_entry_t *ep, u8 log);
+ /* Tasks -
+ * 1. Check for expiry for this entry
+ * 2. Delete if expired
+ */
+ u32 timeout = 0;
+
+ switch(sdb->v4_dest_key.k.vrf & CNAT_PRO_MASK) {
+ case CNAT_TCP:
+ if (sdb->flags & CNAT_DB_FLAG_TCP_ACTIVE) {
+ timeout = sdb->timeout;
+ if(PREDICT_FALSE(timeout_dirty)) {
+ timeout = query_and_update_db_timeout(
+ (void *)sdb, SESSION_DB_TYPE);
+ }
+ if(PREDICT_TRUE(timeout == 0)) {
+ timeout = tcp_active_timeout;
+ //dslite_entry_ptr->timeout_info.tcp_active_timeout;
+ }
+ } else {
+ timeout = tcp_initial_setup_timeout;
+ //dslite_entry_ptr->timeout_info.tcp_initial_setup_timeout;
+ }
+ break;
+ case CNAT_UDP:
+ if (sdb->flags & CNAT_DB_FLAG_UDP_ACTIVE) {
+ timeout = sdb->timeout;
+ if(PREDICT_FALSE(timeout_dirty)) {
+ timeout = query_and_update_db_timeout(
+ (void *)sdb, SESSION_DB_TYPE);
+ }
+
+ if(PREDICT_TRUE(timeout == 0)) {
+ timeout = udp_act_session_timeout;
+ //dslite_entry_ptr->timeout_info.udp_act_session_timeout;
+ }
+ } else {
+ timeout = udp_init_session_timeout;
+ //dslite_entry_ptr->timeout_info.udp_init_session_timeout;
+ }
+ break;
+ case CNAT_ICMP:
+ timeout = icmp_session_timeout;
+ //dslite_entry_ptr->timeout_info.icmp_session_timeout;
+ break;
+ case CNAT_PPTP:
+ timeout = pptp_cfg.timeout;
+ break;
+ default:
+ return;
+ }
+ /* Changes required for clearing sessions */
+ if (PREDICT_FALSE((sdb->entry_expires == 0) ||
+ (sdb->entry_expires + timeout < cnat_current_time))) {
+ cnat_delete_session_db_entry(sdb, TRUE);
+ }
+}
+
+static u8 handle_db_scan_for_sessions(
+ cnat_main_db_entry_t *db, int *dirty_index, uword db_index
+ /* ,dslite_table_entry_t *dslite_entry_ptr */)
+{
+ /* Tasks -
+ * 1. Traverse through the sessions and check for timeouts
+ * 2. Delete sessions that have exipred
+ * 3. Check if the db has only one session remaining.. if so,
+ * the details of the session has to be moved to main db
+ * and session db entry needs to be freed
+ * 4. If db does not have any sessions left, the db itself
+ * needs to be deleted.
+ */
+ u32 nsessions, session_index_head, session_index;
+ cnat_session_entry_t *sdb;
+ u8 timeout_dirty = FALSE;
+
+ if(PREDICT_FALSE(*dirty_index == db_index)) {
+ *dirty_index = -1;
+ }
+ if(PREDICT_FALSE(timeout_dirty_flag == 1)) {
+ timeout_dirty_flag = 0;
+ *dirty_index = db_index;
+ timeout_dirty = TRUE;
+ }
+
+ session_index_head = session_index = db->session_head_index;
+ nsessions = db->nsessions;
+
+ do {
+ sdb = cnat_session_db + session_index;
+ if(PREDICT_FALSE(!sdb)) {
+ //TO DO: Debug msg?
+ return FALSE;
+ }
+ session_index = sdb->main_list.next;
+ check_session_for_expiry(sdb, timeout_dirty /*,dslite_entry_ptr*/);
+ nsessions--; /* To ensure that we do not get in to an infinite loop */
+ } while(session_index != session_index_head
+ && db->session_head_index != EMPTY &&
+ nsessions);
+
+ /* Note.. the code below assumes that while deleting the
+ * sessions, we do not delete the main db entry if it does
+ * not have any sessions anymore
+ */
+ if(PREDICT_FALSE((!db->nsessions) &&
+ (!(db->flags & CNAT_DB_FLAG_STATIC_PORT)))) {
+ cnat_delete_main_db_entry_v2(db);
+ return TRUE; /* to indicate that main db was deleted */
+ }
+ return FALSE;
+}
+
+static void cnat_db_scanner(void)
+{
+ cnat_main_db_entry_t * db;
+ u32 timeout;
+ cnat_vrfmap_t *my_vrfmap __attribute__((unused)) = 0;
+ static int dirty_index = -1;
+ u16 instance __attribute__((unused));
+ //dslite_table_entry_t *dslite_entry_ptr;
+ u32 i;
+ uword db_index;
+ //pcp_throttle_count = 0;
+
+ for (i = 0; i < num_entries; i++) {
+ db_index = check_these_pool_indices[i];
+ db = cnat_main_db + db_index;
+ timeout=0;
+ my_vrfmap = 0;
+
+#if 0
+ if(PREDICT_FALSE(db->flags & CNAT_PCP_FLAG)) {
+
+ if(db->proto_data.seq_pcp.pcp_lifetime < cnat_current_time) {
+ /* mark as implicit */
+ db->flags &= ~CNAT_PCP_FLAG;
+ }
+ continue;
+ }
+
+#endif
+ if(PREDICT_FALSE(db->nsessions > 1)) {
+ if(PREDICT_FALSE(
+ handle_db_scan_for_sessions(db, &dirty_index, db_index /*,dslite_entry_ptr */))) {
+ continue;
+ } else if(PREDICT_TRUE(db->nsessions > 1)) {
+ continue;
+ }
+ /* if there is exactly one dest left.. let it fall through
+ * and check if that needs to be deleted as well
+ */
+ }
+
+#if 0
+ if (PREDICT_FALSE(db->flags & CNAT_DB_FLAG_STATIC_PORT)) {
+ if (PREDICT_FALSE(db->flags & CNAT_DB_DSLITE_FLAG)) {
+ if(PREDICT_FALSE(
+ ((dslite_entry_ptr->nf_logging_policy != SESSION_LOG_ENABLE) &&
+ (dslite_entry_ptr->syslog_logging_policy != SESSION_LOG_ENABLE))
+ || (db->nsessions !=1))) {
+ continue;
+ }
+ } else {
+ my_vrfmap = cnat_map_by_vrf + db->vrfmap_index;
+ if(PREDICT_FALSE(
+ ((my_vrfmap->nf_logging_policy != SESSION_LOG_ENABLE) &&
+ (my_vrfmap->syslog_logging_policy != SESSION_LOG_ENABLE)) ||
+ (db->nsessions !=1))) {
+ continue;
+ }
+ }
+ }
+#endif
+
+ switch(db->in2out_key.k.vrf & CNAT_PRO_MASK) {
+ case CNAT_TCP:
+ if (db->flags & CNAT_DB_FLAG_TCP_ACTIVE) {
+ timeout = db->timeout;
+ if(PREDICT_FALSE(dirty_index == db_index)) {
+ dirty_index = -1;
+ }
+ if(PREDICT_FALSE(timeout_dirty_flag == 1)) {
+ timeout_dirty_flag = 0;
+ dirty_index = db_index;
+ }
+ if(PREDICT_FALSE(dirty_index != -1)) {
+ timeout = query_and_update_db_timeout(
+ (void *)db, MAIN_DB_TYPE);
+ }
+ if(PREDICT_TRUE(timeout == 0)) {
+ timeout = tcp_active_timeout;
+ }
+ } else {
+ timeout = tcp_initial_setup_timeout;
+ }
+ break;
+ case CNAT_UDP:
+ if (db->flags & CNAT_DB_FLAG_UDP_ACTIVE) {
+ timeout = db->timeout;
+ if(PREDICT_FALSE(dirty_index == db_index)) {
+ dirty_index = -1;
+ }
+ if(PREDICT_FALSE(timeout_dirty_flag == 1)) {
+ timeout_dirty_flag = 0;
+ dirty_index = db_index;
+ }
+ if(PREDICT_FALSE(dirty_index != -1)) {
+ timeout = query_and_update_db_timeout(
+ (void *)db, MAIN_DB_TYPE);
+ }
+ if(PREDICT_TRUE(timeout == 0)) {
+ timeout = udp_act_session_timeout;
+ }
+ } else {
+ timeout = udp_init_session_timeout;
+ }
+ break;
+ case CNAT_ICMP:
+ timeout = icmp_session_timeout;
+ break;
+ case CNAT_PPTP:
+ timeout = pptp_cfg.timeout;
+ break;
+ default:
+ continue;
+ }
+
+
+ /* Ref: CSCtu97536 */
+ if (PREDICT_FALSE((db->entry_expires == 0) ||
+ (db->entry_expires + timeout < cnat_current_time))) {
+#if 0
+ if (PREDICT_FALSE(db->flags & CNAT_DB_FLAG_STATIC_PORT)) {
+ if (PREDICT_FALSE(db->flags & CNAT_DB_DSLITE_FLAG)) {
+ instance = db->dslite_nat44_inst_id;
+ } else {
+ instance = NAT44_RESERVED_INST_ID;
+ cnat_session_log_nat44_mapping_delete(db, 0, my_vrfmap);
+ }
+
+ /* Reset the session details */
+ db->nsessions = 0;
+ db->dst_ipv4 = 0;
+ db->dst_port = 0;
+ db->flags &= ~(CNAT_DB_FLAG_TCP_ACTIVE | CNAT_DB_FLAG_UDP_ACTIVE
+ | CNAT_DB_FLAG_ALG_ENTRY);
+ db->timeout = 0;
+ db->entry_expires = 0;
+ db->alg.delta = 0;
+ db->proto_data.seq_pcp.tcp_seq_num = 0;
+ continue;
+ }
+#endif
+ //printf("DELETING DB ENTRY FOR 0x%x\n", db->in2out_key.k.ipv4);
+ cnat_delete_main_db_entry_v2(db);
+ }
+ //free(check_these_pool_indices[i]);
+ }
+}
+
+static void walk_the_db (void)
+{
+ pool_header_t *h = pool_header(cnat_main_db);
+ u32 db_uword_len;
+ static u32 base_index = 0, free_bitmap_index = 0;
+ int bits_scanned = 0, i;
+ uword inuse_bitmap;
+
+ num_entries=0;
+
+ /* Across all db entries... */
+ db_uword_len = vec_len(cnat_main_db) / NUM_BITS_IN_UWORD;
+ if (PREDICT_FALSE(vec_len(cnat_main_db) % NUM_BITS_IN_UWORD)) {
+ /*
+ * It should not come here as in cnat_db_init_v2()
+ * it is made multiple of NUM_BITS_IN_UWORD
+ */
+ ASSERT(0);
+ return ;
+ }
+
+ if (PREDICT_FALSE(! db_uword_len))
+ return ;
+
+ while (bits_scanned < MAX_DB_ENTRY_PER_SCAN) {
+
+ if (PREDICT_FALSE(free_bitmap_index < vec_len(h->free_bitmap))) {
+
+ /* free_bitmap exists and it is not all 0 */
+
+ inuse_bitmap = ~(h->free_bitmap[free_bitmap_index]);
+ i = 0;
+ while (inuse_bitmap) {
+
+ /* Check to see if the index is in use */
+ if (PREDICT_FALSE((inuse_bitmap >> i) & 1)) {
+ check_these_pool_indices[num_entries] = base_index + i;
+ inuse_bitmap &= ~((uword) 1 << i);
+ num_entries++;
+ }
+ i++;
+ } // while (inuse_bitmap)
+ } else {
+
+ /*
+ * 64-bit entry is 0, means all 64 entries are allocated.
+ * So, simply add all 64 entries here.
+ * No need to form inuse_bitmap, check and reset bits
+ */
+ for (i=0; i<NUM_BITS_IN_UWORD; i++) {
+
+ check_these_pool_indices[num_entries] = base_index + i;
+ num_entries++;
+ }
+ } // if (free_bitmap_index < vec_len(h->free_bitmap))
+
+ /* Update free_bitmap_index and base_index for next run */
+ if (PREDICT_FALSE(free_bitmap_index == db_uword_len - 1)) {
+ /* wrap-around for next run */
+ free_bitmap_index = 0;
+ base_index = 0;
+ } else {
+ free_bitmap_index ++;
+ base_index += NUM_BITS_IN_UWORD;
+ }
+
+ /* increment # of bits scanned */
+ bits_scanned += NUM_BITS_IN_UWORD;
+
+ /* Found enough entries to check ? */
+ if (PREDICT_FALSE(num_entries >= MAX_DB_ENTRY_SELECTED_PER_SCAN))
+ {
+ /* This check is introduced to keep fixed MAX scan entry value */
+ /* This is very much required when we do scanning for NAT64 */
+ /* please check comments in cnat_db_scanner() &
+ * handler_nat64_db_scanner() */
+ if (num_entries >= MAX_COMBINED_DB_ENTRIES_PER_SCAN) {
+ num_entries = MAX_COMBINED_DB_ENTRIES_PER_SCAN;
+ }
+ break;
+ }
+
+ } // while (bits_scanned < MAX_DB_ENTRY_PER_SCAN)
+
+ if (PREDICT_FALSE(num_entries > 0)) {
+ //printf("%s: num_entries [%d]\n", __func__, num_entries);
+ cnat_db_scanner();
+ }
+ return ;
+}
+
+static uword cnat_db_scanner_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ f64 timeout = 0.01; /* timeout value in sec (10 ms) */
+ static u8 timeout_count = 0;
+
+ uword event_type;
+ uword * event_data = 0;
+ /* Wait until vCGN is configured */
+ while (1) {
+ /* Assigning a huge timeout value, vCGN may or
+ * may not get configured within this timeout */
+ vlib_process_wait_for_event_or_clock (vm, 1e9);
+ event_type = vlib_process_get_events (vm, &event_data);
+
+ /* check whether the process is waken up by correct guy,
+ * otherwise continue waiting for the vCGN config */
+ if (event_type == CNAT_DB_SCANNER_TURN_ON) {
+ break;
+ }
+ }
+
+ while(1) {
+ vlib_process_suspend(vm, timeout);
+
+ /* Above suspend API should serve the purpose, no need to invoke wait API */
+ /* vlib_process_wait_for_event_or_clock (vm, timeout); */
+
+ /* Lets make use of this timeout for netflow packet sent */
+ if (timeout_count < 100) { /* 100*10 ms = 1 sec */
+ timeout_count++;
+ } else {
+ if (nfv9_configured) {
+ handle_pending_nfv9_pkts();
+ }
+ timeout_count = 0;
+ }
+ /* Do we need this ? */
+ //event_type = vlib_process_get_events (vm, &event_data);
+ cnat_current_time = (u32)vlib_time_now (vm);
+ if (cnat_db_init_done) {
+ walk_the_db();
+ }
+ }
+
+ return 0;
+}
+
+
+VLIB_REGISTER_NODE (cnat_db_scanner_node) = {
+ .function = cnat_db_scanner_fn,
+ .type = VLIB_NODE_TYPE_PROCESS,
+ .name = "cnat-db-scanner",
+ .process_log2_n_stack_bytes = 18,
+};
+
+clib_error_t *cnat_db_scanner_init (vlib_main_t *vm)
+{
+ cnat_db_scanner_main_t *mp = &cnat_db_scanner_main;
+
+ mp->vlib_main = vm;
+ mp->vnet_main = vnet_get_main();
+
+ return 0;
+}
+
+void cnat_scanner_db_process_turn_on(vlib_main_t *vm)
+{
+ vlib_process_signal_event (vm, cnat_db_scanner_node.index,
+ CNAT_DB_SCANNER_TURN_ON, 0);
+ return;
+}
+
+VLIB_INIT_FUNCTION (cnat_db_scanner_init);
+
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_db_v2.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_db_v2.c
new file mode 100644
index 00000000..46af9f31
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_db_v2.c
@@ -0,0 +1,3806 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_db_v2.c - translation database definitions
+ *
+ * Copyright (c) 2007-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/vec.h>
+#include <vppinfra/bitmap.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/pool.h>
+#include <vppinfra/clib.h>
+#include <vppinfra/error.h>
+
+#include "cnat_db.h"
+#include "cnat_config.h"
+#include "cnat_global.h"
+#include "cnat_v4_functions.h"
+#include "cnat_log_api.h"
+#include "cnat_cli.h"
+#include "spp_platform_trace_log.h"
+#include "cnat_bulk_port.h"
+#include "nat64_db.h"
+#include "dslite_db.h"
+#include "cnat_config_api.h"
+
+#define HASH_TABLE_SIZE 8192 // hash table size
+#define THROTTLE_TIME 180 // throttle time value for out of port msg/user
+
+u8 cnat_db_init_done = 0;
+
+typedef struct {
+ /* Locks for multi thread support */
+ CLIB_CACHE_LINE_ALIGN_MARK(cacheline0);
+ pthread_spinlock_t *main_db_lockp;
+ pthread_spinlock_t *user_db_lockp;
+ pthread_spinlock_t *session_db_lockp;
+
+ u32 cached_next_index;
+ /* $$$$ add data here */
+
+ /* convenience variables */
+ vlib_main_t * vlib_main;
+ vnet_main_t * vnet_main;
+} cnat_db_v2_main_t;
+
+cnat_db_v2_main_t cnat_db_v2_main;
+
+#if 1
+/* TOBE_PORTED : Remove the following once fixed */
+#undef PREDICT_TRUE
+#undef PREDICT_FALSE
+#define PREDICT_TRUE(x) (x)
+#define PREDICT_FALSE(x) (x)
+#endif
+
+#define foreach_cnat_db_v2_error \
+_(DROP, "error-drop packets")
+
+typedef enum {
+#define _(sym,str) CNAT_DB_V2_##sym,
+ foreach_cnat_db_v2_error
+#undef _
+ CNAT_DB_V2_N_ERROR,
+} cnat_db_v2_error_t;
+
+static char * cnat_db_v2_error_strings[] __attribute__((unused)) = {
+#define _(sym,string) string,
+ foreach_cnat_db_v2_error
+#undef _
+};
+
+
+void cnat_table_entry_fill_map(u32 start_addr, u32 end_addr,
+ cnat_portmap_v2_t **port_map_holder)
+{
+ u32 this_start_addr, this_end_addr, this_addr, new;
+ u32 loop_count;
+ u32 pm_len, i;
+ cnat_portmap_v2_t *my_pm =0;
+ cnat_portmap_v2_t *pm = 0;
+
+ my_instance_number = 0;
+
+ this_start_addr = start_addr;
+ this_end_addr = end_addr;
+
+ /*
+ * How many new addresses are getting added ??
+ */
+ /* commenting this. Right now end - start will be for this vCGN instance */
+ //new = ((this_end_addr - this_start_addr) / MAX_CORES_PER_PARTITION) + 1;
+ new = (this_end_addr - this_start_addr) + 1;
+
+ pm = *port_map_holder;
+ pm_len = vec_len(pm);
+#if DEBUG_NOT_COMMENTED
+ printf("this_start_addr = 0x%08X, this_end_addr = 0x%08X, Num Addr = %d\n",
+ this_start_addr, this_end_addr, new);
+ printf("pm_len = %d\n", pm_len);
+#endif
+ /* Check whether the address pool add requested already exists */
+ my_pm = pm;
+ for(i = 0; i< pm_len; i++) {
+ if(my_pm->ipv4_address == this_start_addr) {
+ printf("address pool with addr 0x%08X exists\n", this_start_addr);
+ return;
+ }
+ my_pm++;
+ }
+
+ /*
+ * For now give a warning message only....
+ */
+#if 0
+ if ((total_address_pool_allocated + new) >
+ CNAT_MAX_ADDR_POOL_SIZE_PER_CORE) {
+ printf("address pool size (%d) would cross permissible limit (%u) \n",
+ (total_address_pool_allocated + new),
+ CNAT_MAX_ADDR_POOL_SIZE_PER_CORE);
+ }
+#endif
+
+ total_address_pool_allocated += new;
+ vec_add2(pm, my_pm, new);
+
+#if DEBUG_NOT_COMMENTED
+ printf("total_address_pool_allocated changed from %d to %d (added %d)",
+ (total_address_pool_allocated - new),
+ total_address_pool_allocated, new);
+ printf("vec add is ok\n");
+#endif
+
+ memset(my_pm, 0, new*sizeof(*my_pm));
+ this_addr = this_start_addr;
+ loop_count = 0; /* Sanity counter */
+
+ while (this_addr <= this_end_addr) {
+#if DEBUG_NOT_COMMENTED
+ printf("loop %d: this addr = 0x%08X\n", loop_count+1, this_addr);
+#endif
+ my_pm->ipv4_address = this_addr;
+ /*
+ * Set all bits to "1" indicating all ports are free
+ */
+ memset(my_pm->bm, 0xff,
+ (((BITS_PER_INST + BITS(uword)-1)/BITS(uword))*(sizeof(uword))));
+ //this_addr += MAX_CORES_PER_PARTITION;
+ this_addr += 1;
+ my_pm++;
+ loop_count++;
+ }
+ /*
+ * We should have loop_count same as the new value
+ */
+ if (loop_count != new) {
+ printf("Mismatch in loop_count (%d) != new (%d)\n",
+ loop_count, new);
+ }
+
+ *port_map_holder = pm;
+
+#if DEBUG_NOT_COMMENTED
+ printf("revised pm len %d\n", vec_len(*port_map_holder));
+#endif
+
+ return;
+}
+
+
+void cnat_delete_session_db_entry (cnat_session_entry_t *ep, u8 log);
+void handle_cnat_port_exceeded_logging(
+ cnat_user_db_entry_t *udb,
+ cnat_key_t * key,
+ cnat_vrfmap_t *vrfmap);
+
+cnat_global_counters_t cnat_global_counters;
+u32 last_log_timestamp = 0;
+u32 last_user_dyn_port_exc_timestamp = 0;
+u32 last_user_stat_port_exc_timestamp = 0;
+
+index_slist_t *cnat_out2in_hash;
+index_slist_t *cnat_in2out_hash;
+index_slist_t *cnat_user_hash;
+index_slist_t *cnat_timeout_hash;
+index_slist_t *cnat_session_hash;
+
+cnat_main_db_entry_t *cnat_main_db;
+cnat_user_db_entry_t *cnat_user_db;
+cnat_session_entry_t *cnat_session_db;
+cnat_timeout_db_entry_t *cnat_timeout_db;
+
+cgse_nat_db_entry_t *cgse_nat_db;
+cgse_nat_user_db_entry_t *cgse_user_db;
+cgse_nat_session_db_entry_t *cgse_session_db;
+
+nat44_dslite_common_stats_t nat44_dslite_common_stats[255]; /* 0 is for nat44 */
+nat44_dslite_global_stats_t nat44_dslite_global_stats[2]; /* 0 for nat44 and 1 for dslite */
+nat44_counters_stats_t nat44_counters_stats[CNAT_MAX_VRFMAP_ENTRIES];
+/*For displaying show cgn <cgn-name> inside-vrf <vrf-name> counters */
+
+/*
+ * This is the pool of vrf map structures used by latest main-db functions
+ */
+cnat_vrfmap_t *cnat_map_by_vrf;
+
+/*
+ * Have a mapping table of vrf_id-->vrf_map_index
+ * This helps in easily getting the vrf_map structure during
+ * main-db create paths
+ */
+u16 vrf_map_array[CNAT_MAX_VRFMAP_ENTRIES];
+cnat_svi_params_entry svi_params_array[CNAT_MAX_VRFMAP_ENTRIES];
+cnat_ingress_vrfid_name_entry vrfid_name_map[MAX_VRFID] = {{0}};
+u64 in2out_drops_port_limit_exceeded;
+u64 in2out_drops_system_limit_reached;
+u64 in2out_drops_resource_depletion;
+u64 no_translation_entry_drops;
+u32 no_sessions;
+
+#define CNAT_SET_ICMP_MSG_INFO \
+if (PREDICT_TRUE((my_vrfmap->i_vrf < CNAT_MAX_VRFMAP_ENTRIES) && \
+ (svi_params_array[my_vrfmap->i_vrf].ipv4_addr))) { \
+ info->gen_icmp_msg = icmp_msg_gen_allowed(); \
+ info->svi_addr = svi_params_array[my_vrfmap->i_vrf].ipv4_addr; \
+}
+
+#define CNAT_DEBUG_INSIDE_ERR(err) \
+if (((protocol == CNAT_UDP) && \
+ (debug_i_flag & CNAT_DEBUG_ERR_UDP)) || \
+ ((protocol == CNAT_TCP) && \
+ (debug_i_flag & CNAT_DEBUG_ERR_TCP)) || \
+ ((protocol == CNAT_ICMP) && \
+ (debug_i_flag & CNAT_DEBUG_ERR_ICMP))) { \
+ cnat_db_debug_error(&u_ki, err); \
+}
+
+#define DSLITE_DEBUG_INSIDE_ERR(err) \
+if (((protocol == CNAT_UDP) && \
+ (debug_i_flag & CNAT_DEBUG_ERR_UDP)) || \
+ ((protocol == CNAT_TCP) && \
+ (debug_i_flag & CNAT_DEBUG_ERR_TCP)) || \
+ ((protocol == CNAT_ICMP) && \
+ (debug_i_flag & CNAT_DEBUG_ERR_ICMP))) { \
+ dslite_db_debug_error(&u_ki, err); \
+}
+
+#define PORT_LIMIT_LOW_THRESHOLD_FOR_SYSLOG 7
+/* If the max_limit is less than 10, no meaningful throttling can be
+ * done.. so, log only once per user and never clear the flag
+ * once the user exceeds limit
+ */
+#define CHECK_CLEAR_PORT_LIMIT_EXCEED_FLAG(udb, max_limit) \
+ if(PREDICT_FALSE(udb->flags & CNAT_USER_DB_PORT_LIMIT_EXCEEDED)) { \
+ if(udb->ntranslations < \
+ ((max_limit/10)*PORT_LIMIT_LOW_THRESHOLD_FOR_SYSLOG) && \
+ max_limit >= 10) { \
+ udb->flags = udb->flags & (~CNAT_USER_DB_PORT_LIMIT_EXCEEDED); \
+ } \
+ }
+
+#ifdef TOBE_PORTED
+/* Commented to remove unused variable warning */
+static char *debug_db_error[] = {
+ "no error", /* CNAT_SUCCESS */
+ "no config", /*CNAT_NO_CONFIG*/
+ "not in run state", /*CNAT_NO_VRF_RUN*/
+ "no pool for any", /*CNAT_NO_POOL_ANY*/
+ "no port for any", /*CNAT_NO_PORT_ANY*/
+ "bad in use for any", /*CNAT_BAD_INUSE_ANY*/
+ "not found for any", /*CNAT_NOT_FOUND_ANY*/
+ "invalid index for direct", /*CNAT_INV_PORT_DIRECT*/
+ "deleted addr for direct", /*CNAT_DEL_PORT_DIRECT*/
+ "bad in use for direct",/*CNAT_BAD_INUSE_DIRECT*/
+ "not found for direct",/*CNAT_NOT_FOUND_DIRECT*/
+ "out of port limit", /*CNAT_OUT_LIMIT*/
+ "main db limit", /*CNAT_MAIN_DB_LIMIT*/
+ "user db limit", /*CNAT_USER_DB_LIMIT*/
+ "not static port", /*CNAT_NOT_STATIC_PORT*/
+ "bad static port request", /*CNAT_BAD_STATIC_PORT_REQ*/
+ "not this core", /*CNAT_NOT_THIS_CORE*/
+ "parser error", /*CNAT_ERR_PARSER*/
+ "invalid msg id", /*CNAT_ERR_INVALID_MSG_ID*/
+ "invalid msg size", /*CNAT_ERR_INVALID_MSG_SIZE*/
+ "invalid payload size", /*CNAT_ERR_INVALID_PAYLOAD_SIZE*/
+ "bad tcp udp port", /*CNAT_ERR_BAD_TCP_UDP_PORT*/
+ "bulk single failure", /*CNAT_ERR_BULK_SINGLE_FAILURE*/
+ "xlat id invalid", /*CNAT_ERR_XLAT_ID_INVALID*/
+ "xlat v6 prefix invalid", /*CNAT_ERR_XLAT_V6_PREFIX_INVALID*/
+ "xlat v4 prefix invalid", /*CNAT_ERR_XLAT_V4_PREFIX_INVALID*/
+ "xlat tcp mss invalid", /*CNAT_ERR_XLAT_TCP_MSS_INVALID*/
+ "6rd id invalid", /*CNAT_ERR_6RD_ID_INVALID*/
+ "6rd v4 tunnel src invalid", /*CNAT_ERR_6RD_V4_TUNNEL_SRC_INVALID*/
+ "6rd v6 prefix invalid", /*CNAT_ERR_6RD_V6_PREFIX_INVALID*/
+ "6rd v6 BR unicast invalid", /*CNAT_ERR_6RD_V6_BR_UNICAST_INVALID*/
+ "6rd v4 prefix masklen invalid", /*CNAT_ERR_6RD_V4_PREFIX_MASK_LEN_INVALID*/
+ "6rd v4 suffix masklen invalid", /*CNAT_ERR_6RD_V4_SUFFIX_MASK_LEN_INVALID*/
+ "6rd v4 combo masklen invalid", /*CNAT_ERR_6RD_V4_COMBO_MASK_LEN_INVALID*/
+ "6rd tunnel mtu invalid", /*CNAT_ERR_6RD_TUNNEL_MTU_INVALID*/
+ "6rd tunnel ttl invalid", /*CNAT_ERR_6RD_TUNNEL_TTL_INVALID*/
+ "6rd tunnel tos invalid", /*CNAT_ERR_6RD_TUNNEL_TOS_INVALID*/
+};
+#endif
+
+f64 port_log_timestamps[HASH_TABLE_SIZE]; /* 32 KB array per core */
+
+void port_exceeded_msg_log (u32 src_addr, u16 i_vrf)
+{
+ u32 hash_value;
+ f64 current_timestamp;
+ vlib_main_t *vlib_main;
+
+ vlib_main = vlib_get_main();
+ current_timestamp = vlib_time_now((vlib_main_t *) vlib_main);
+
+ hash_value = ((src_addr >> 16) ^ ((src_addr & 0xffff) ^ i_vrf)) % (1024*8);
+
+ if (PREDICT_FALSE((current_timestamp - port_log_timestamps[hash_value]) > THROTTLE_TIME)) {
+ u32 arg[2] = {i_vrf, src_addr};
+ /* update timestamp */
+ port_log_timestamps[hash_value] = current_timestamp;
+ spp_printf(CNAT_USER_OUT_OF_PORTS, 2, arg);
+ }
+
+ return ;
+}
+
+static void log_port_alloc_error(cnat_errno_t error, cnat_key_t *k)
+{
+ u32 error_code;
+ u32 arr[] = {k->k.vrf, k->k.ipv4, k->k.port};
+ switch (error)
+ {
+ case CNAT_NO_POOL_ANY:
+ error_code = CNAT_NO_POOL_FOR_ANY_ERROR;
+ break;
+ case CNAT_NO_PORT_ANY:
+ error_code = CNAT_NO_PORT_FOR_ANY_ERROR;
+ break;
+ case CNAT_ERR_PARSER:
+ error_code = CNAT_WRONG_PORT_ALLOC_TYPE;
+ break;
+ case CNAT_BAD_INUSE_ANY:
+ error_code = CNAT_BAD_INUSE_ANY_ERROR;
+ break;
+ case CNAT_BAD_INUSE_DIRECT:
+ error_code = CNAT_BAD_INUSE_DIRECT_ERROR;
+ break;
+ case CNAT_NOT_FOUND_ANY:
+ error_code = CNAT_NOT_FOUND_ANY_ERROR;
+ break;
+ case CNAT_NOT_FOUND_DIRECT:
+ error_code = CNAT_NOT_FOUND_DIRECT_ERROR;
+ break;
+ case CNAT_INV_PORT_DIRECT:
+ error_code = CNAT_INV_PORT_FOR_DIRECT_ERROR;
+ break;
+ default:
+ error_code = CNAT_NEW_PORT_ALLOC_ERROR; /* If this code is seen in the log,
+ it means, new error codes are to be added here */
+ break;
+ }
+ spp_printf(error_code, 3, arr);
+}
+
+void cnat_db_debug_error(cnat_db_key_bucket_t *u_ki,
+ cnat_errno_t error)
+{
+ if (PREDICT_FALSE((u_ki->k.k.vrf == debug_i_vrf) &&
+ ((u_ki->k.k.ipv4 >= debug_i_addr_start) &&
+ (u_ki->k.k.ipv4 <= debug_i_addr_end)))) {
+#ifdef DEBUG_PRINTF_ENABLED
+ PLATFORM_DEBUG_PRINT("failed to allocate port due to %s "
+ "for i-vrf 0x%x addr 0x%x port 0x%x\n",
+ debug_db_error[error], u_ki->k.k.vrf,
+ u_ki->k.k.ipv4, u_ki->k.k.port);
+#endif
+ {
+ u32 arg[] = {u_ki->k.k.vrf, u_ki->k.k.ipv4, u_ki->k.k.port};
+ spp_printf(error, 3, arg);
+ }
+ }
+}
+
+void dslite_db_debug_error(dslite_db_key_bucket_t *u_ki,
+ cnat_errno_t error)
+{
+ if (PREDICT_FALSE((u_ki->dk.ipv4_key.k.vrf == debug_i_vrf) &&
+ ((u_ki->dk.ipv4_key.k.ipv4 >= debug_i_addr_start) &&
+ (u_ki->dk.ipv4_key.k.ipv4 <= debug_i_addr_end)))) {
+#ifdef DEBUG_PRINTF_ENABLED
+ PLATFORM_DEBUG_PRINT("failed to allocate port due to %s "
+ "for i-vrf 0x%x addr 0x%x port 0x%x\n",
+ debug_db_error[error], u_ki->dk.ipv4_key.k.vrf,
+ u_ki->dk.ipv4_key.k.ipv4, u_ki->dk.ipv4_key.k.port);
+#endif
+ {
+ u32 arg[] = {u_ki->dk.ipv4_key.k.vrf, u_ki->dk.ipv4_key.k.ipv4, u_ki->dk.ipv4_key.k.port};
+ spp_printf(error, 3, arg);
+ }
+ }
+}
+
+void cnat_db_debug_i2o_drop(cnat_db_key_bucket_t *ki)
+{
+ if (PREDICT_FALSE(((ki->k.k.vrf & CNAT_VRF_MASK) == debug_i_vrf) &&
+ ((ki->k.k.ipv4 >= debug_i_addr_start) &&
+ (ki->k.k.ipv4 <= debug_i_addr_end)))) {
+#ifdef DEBUG_PRINTF_ENABLED
+ PLATFORM_DEBUG_PRINT("pakcet[i-vrf 0x%x addr 0x%x port 0x%x] dropped\n",
+ ki->k.k.vrf, ki->k.k.ipv4, ki->k.k.port);
+#endif
+ {
+ u32 arg[] = {ki->k.k.vrf, ki->k.k.ipv4, ki->k.k.port};
+ spp_printf(CNAT_PACKET_DROP_ERROR, 3, arg);
+ }
+ }
+}
+
+void cnat_db_in2out_hash_delete (cnat_main_db_entry_t *ep, cnat_user_db_entry_t *up)
+{
+ u64 a, b, c;
+ u32 index, bucket;
+ cnat_main_db_entry_t *this, *prev;
+
+#ifdef DSLITE_DEF
+ if (PREDICT_FALSE(ep->flags & CNAT_DB_DSLITE_FLAG)) {
+ dslite_key_t dk = {
+ {up->ipv6[0], up->ipv6[1], up->ipv6[2], up->ipv6[3]} ,
+ {ep->in2out_key.k.ipv4, ep->in2out_key.k.port, ep->in2out_key.k.vrf}
+ };
+ DSLITE_V6_GET_HASH((&dk),
+ bucket,
+ CNAT_MAIN_HASH_MASK);
+ DSLITE_PRINTF(1, "Delete1 DSL main hash bucket ..%u\n", bucket);
+ } else {
+ CNAT_V4_GET_HASH(ep->in2out_key.key64,
+ bucket, CNAT_MAIN_HASH_MASK)
+ DSLITE_PRINTF(1, "Delete1 NAT44 main hash bucket ..%u\n", bucket);
+ }
+#else
+ CNAT_V4_GET_HASH(ep->in2out_key.key64,
+ bucket, CNAT_MAIN_HASH_MASK)
+#endif
+
+ index = cnat_in2out_hash[bucket].next;
+
+ ASSERT(index != EMPTY);
+
+ prev = 0;
+ do {
+ this = cnat_main_db + index;
+ if (PREDICT_TRUE(this == ep)) {
+ if (prev == 0) {
+ cnat_in2out_hash[bucket].next = ep->in2out_hash.next;
+ return;
+ } else {
+ prev->in2out_hash.next = ep->in2out_hash.next;
+ return;
+ }
+ }
+ prev = this;
+ index = this->in2out_hash.next;
+ } while (index != EMPTY);
+
+ ASSERT(0);
+}
+
+void cnat_db_out2in_hash_delete (cnat_main_db_entry_t *ep)
+{
+ u64 a, b, c;
+ u32 index, bucket;
+ cnat_main_db_entry_t *this, *prev;
+
+ CNAT_V4_GET_HASH(ep->out2in_key.key64,
+ bucket, CNAT_MAIN_HASH_MASK)
+
+ index = cnat_out2in_hash[bucket].next;
+
+ ASSERT(index != EMPTY);
+
+ prev = 0;
+ do {
+ this = cnat_main_db + index;
+ if (PREDICT_TRUE(this == ep)) {
+ if (prev == 0) {
+ cnat_out2in_hash[bucket].next = ep->out2in_hash.next;
+ return;
+ } else {
+ prev->out2in_hash.next = ep->out2in_hash.next;
+ return;
+ }
+ }
+ prev = this;
+ index = this->out2in_hash.next;
+ } while (index != EMPTY);
+
+ ASSERT(0);
+}
+
+cnat_main_db_entry_t*
+cnat_main_db_lookup_entry(cnat_db_key_bucket_t *ki)
+{
+ u64 a, b, c;
+ u32 index;
+ cnat_main_db_entry_t *db;
+
+ CNAT_V4_GET_HASH(ki->k.key64,
+ ki->bucket,
+ CNAT_MAIN_HASH_MASK);
+
+ index = cnat_in2out_hash[ki->bucket].next;
+ if (PREDICT_TRUE(index == EMPTY)) {
+ return (NULL);
+ }
+
+ do {
+ db = cnat_main_db + index;
+ if (PREDICT_TRUE(db->in2out_key.key64 == ki->k.key64)) {
+ return db;
+ }
+ index = db->in2out_hash.next;
+ } while (index != EMPTY);
+
+ return (NULL);
+}
+
+void cnat_user_db_delete (cnat_user_db_entry_t *up)
+{
+ u64 a, b, c;
+ u32 index, bucket;
+ cnat_user_db_entry_t *this, *prev;
+
+ if (PREDICT_FALSE(up->flags & CNAT_USER_DB_NAT64_FLAG) != 0) {
+ /* Preventive check - Not a NAT44 entry */
+ return;
+ }
+
+ pthread_spin_lock(cnat_db_v2_main.user_db_lockp);
+#if 1
+ if(PREDICT_FALSE(up->flags & CNAT_USER_DB_DSLITE_FLAG)) {
+ dslite_key_t dk = {
+ {up->ipv6[0], up->ipv6[1], up->ipv6[2], up->ipv6[3]} ,
+ {{up->key.k.ipv4, up->key.k.port, up->key.k.vrf}}
+ };
+
+ DSLITE_V6_GET_HASH((&dk),
+ bucket,
+ CNAT_USER_HASH_MASK);
+ DSLITE_PRINTF(1, "Delete1 DSL user hash bucket ..%u\n", bucket);
+ } else {
+ CNAT_V4_GET_HASH(up->key.key64,
+ bucket, CNAT_USER_HASH_MASK)
+ DSLITE_PRINTF(1, "Delete1 NAT44 user hash bucket ..%u\n", bucket);
+ }
+#else
+ CNAT_V4_GET_HASH(up->key.key64,
+ bucket, CNAT_USER_HASH_MASK)
+ DSLITE_PRINTF(1, "Delete2 NAT44 user hash bucket ..%u\n", bucket);
+#endif
+
+ index = cnat_user_hash[bucket].next;
+
+ ASSERT(index != EMPTY);
+
+ prev = 0;
+ do {
+ this = cnat_user_db + index;
+ if (PREDICT_TRUE(this == up)) {
+ if (prev == 0) {
+ cnat_user_hash[bucket].next = up->user_hash.next;
+ goto found;
+ } else {
+ prev->user_hash.next = up->user_hash.next;
+ goto found;
+ }
+ }
+ prev = this;
+ index = this->user_hash.next;
+ } while (index != EMPTY);
+
+ ASSERT(0);
+
+ found:
+ pool_put(cnat_user_db, up);
+ pthread_spin_unlock(cnat_db_v2_main.user_db_lockp);
+}
+
+cnat_user_db_entry_t*
+cnat_user_db_lookup_entry(cnat_db_key_bucket_t *uki)
+{
+ u64 a, b, c;
+ u32 index;
+ cnat_user_db_entry_t *udb=NULL;
+
+ CNAT_V4_GET_HASH(uki->k.key64,
+ uki->bucket,
+ CNAT_USER_HASH_MASK)
+
+ /* now: index in user vector */
+ index = cnat_user_hash[uki->bucket].next;
+ if (PREDICT_TRUE(index != EMPTY)) {
+ do {
+ udb = cnat_user_db + index;
+ if (PREDICT_FALSE(udb->key.key64 == uki->k.key64)) {
+ return udb;
+ }
+ index = udb->user_hash.next;
+ } while (index != EMPTY);
+ }
+ return (NULL);
+}
+
+cnat_user_db_entry_t*
+cnat_user_db_create_entry(cnat_db_key_bucket_t *uki,
+ u32 portmap_index)
+{
+ cnat_user_db_entry_t *udb = NULL;
+
+ pthread_spin_lock(cnat_db_v2_main.user_db_lockp);
+ pool_get(cnat_user_db, udb);
+ memset(udb, 0, sizeof(*udb));
+
+ udb->ntranslations = 1;
+ udb->portmap_index = portmap_index;
+ udb->key.key64 = uki->k.key64;
+ /* Add this user to the head of the bucket chain */
+ udb->user_hash.next =
+ cnat_user_hash[uki->bucket].next;
+ cnat_user_hash[uki->bucket].next = udb - cnat_user_db;
+
+#ifndef NO_BULK_LOGGING
+ INIT_BULK_CACHE(udb)
+#endif /* NO_BULK_LOGGING */
+ pthread_spin_unlock(cnat_db_v2_main.user_db_lockp);
+ return udb;
+}
+
+cnat_main_db_entry_t*
+cnat_create_main_db_entry_and_hash(cnat_db_key_bucket_t *ki,
+ cnat_db_key_bucket_t *ko,
+ cnat_user_db_entry_t *udb)
+{
+ u64 a, b, c;
+ u32 db_index;
+ cnat_main_db_entry_t *db = NULL;
+
+ pool_get(cnat_main_db, db);
+ memset(db, 0, sizeof(*db));
+
+ db_index = db - cnat_main_db;
+ db->in2out_key.k.ipv4 = ki->k.k.ipv4;
+ db->in2out_key.k.port = ki->k.k.port;
+ db->in2out_key.k.vrf = ki->k.k.vrf;
+ db->out2in_key.k.ipv4 = ko->k.k.ipv4;
+ db->out2in_key.k.port = ko->k.k.port;
+ db->out2in_key.k.vrf = ko->k.k.vrf;
+
+ db->user_ports.next = db_index;
+ db->user_ports.prev = db_index;
+ db->user_index = udb - cnat_user_db;
+ //db->portmap_index = udb->portmap_index;
+ db->flags &= ~(CNAT_DB_DSLITE_FLAG); // Mark that it is not dslite
+ if (PREDICT_FALSE(udb->ntranslations == 1)) {
+ /*
+ * first port for this src vrf/src ip addr
+ */
+ udb->translation_list_head_index = db_index;
+ } else {
+ index_dlist_addtail(udb->translation_list_head_index,
+ (u8 *)cnat_main_db, sizeof(cnat_main_db[0]),
+ STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports),
+ db_index);
+ }
+
+ /*
+ * setup o2i hash key
+ */
+ CNAT_V4_GET_HASH(ko->k.key64,
+ ko->bucket,
+ CNAT_MAIN_HASH_MASK)
+ db->out2in_hash.next = cnat_out2in_hash[ko->bucket].next;
+ cnat_out2in_hash[ko->bucket].next = db_index;
+ /*
+ * setup i2o hash key, bucket is already calculate
+ */
+ db->in2out_hash.next = cnat_in2out_hash[ki->bucket].next;
+ cnat_in2out_hash[ki->bucket].next = db_index;
+
+#if DEBUG > 1
+ printf("\nMy_Instance_Number %d: Bucket %d, Db_Index %d",
+ my_instance_number, ki->bucket, db_index);
+ printf("\nInside (VRF 0x%x, IP 0x%x, PORT 0x%x)",
+ db->in2out_key.k.vrf, db->in2out_key.k.ipv4, db->in2out_key.k.port);
+ printf("\nOutside (VRF 0x%x, IP 0x%x, PORT 0x%x)",
+ db->out2in_key.k.vrf, db->out2in_key.k.ipv4, db->out2in_key.k.port);
+ printf("\nUser Index %d, IP 0x%x",
+ db->user_index, udb->key.k.ipv4);
+#endif
+
+ NAT44_COMMON_STATS.active_translations++;
+
+ return db;
+}
+
+static inline void pptp_clear_all_channels(
+ cnat_main_db_entry_t *db)
+{
+ u32 db_index, current_db_index;
+ cnat_main_db_entry_t *temp_db;
+
+ /* clear all channels */
+
+ db_index = db->proto_data.pptp_list.next;
+ current_db_index = db - cnat_main_db;
+
+ while( db_index != EMPTY) {
+ temp_db = cnat_main_db + db_index;
+ db_index = temp_db->proto_data.pptp_list.next;
+ temp_db->entry_expires = 0;
+ if(PREDICT_FALSE(temp_db->proto_data.pptp_list.prev
+ == current_db_index)) { // Decouple child GREs from parent
+ temp_db->proto_data.pptp_list.prev = EMPTY;
+ }
+ }
+
+ db->proto_data.pptp_list.next = EMPTY;
+}
+
+void pptp_remove_channel_from_tunnel(cnat_main_db_entry_t *db) {
+
+ cnat_main_db_entry_t *prev_db, *next_db;
+
+ prev_db = cnat_main_db + db->proto_data.pptp_list.prev;
+ next_db = cnat_main_db + db->proto_data.pptp_list.next;
+
+ /* remove entry from the tunnel list */
+ if(PREDICT_TRUE(db->proto_data.pptp_list.prev != EMPTY)) {
+ prev_db->proto_data.pptp_list.next =
+ db->proto_data.pptp_list.next ;
+ }
+
+ if(db->proto_data.pptp_list.next != EMPTY) {
+ next_db->proto_data.pptp_list.prev
+ = db->proto_data.pptp_list.prev;
+ }
+
+}
+
+void cnat_delete_main_db_entry_v2 (cnat_main_db_entry_t *ep)
+{
+ u32 main_db_index;
+ u32 vrfmap_len, udb_len;
+ cnat_user_db_entry_t *up =0;
+ cnat_portmap_v2_t *pm =0;
+ cnat_portmap_v2_t *my_pm =0;
+ cnat_vrfmap_t *my_vrfmap =0;
+ u16 static_port_range;
+#ifndef NO_BULK_LOGGING
+ bulk_alloc_size_t bulk_size;
+ int nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
+#endif
+ pool_header_t *h = pool_header(cnat_user_db);
+ u16 instance = 0;
+ u32 my_index;
+
+
+ if (PREDICT_FALSE(ep->flags & CNAT_DB_NAT64_FLAG) != 0) {
+ /* Preventive check - Not a NAT44 entry */
+ return;
+ }
+
+ pthread_spin_lock(cnat_db_v2_main.main_db_lockp);
+ if(PREDICT_FALSE(ep->flags &
+ CNAT_DB_FLAG_PPTP_TUNNEL_ACTIVE)) {
+ pptp_clear_all_channels(ep);
+ PPTP_DECR(active_tunnels);
+ }
+
+ if(PREDICT_FALSE(ep->flags &
+ CNAT_DB_FLAG_PPTP_GRE_ENTRY)) {
+ pptp_remove_channel_from_tunnel(ep);
+ PPTP_DECR(active_channels);
+ }
+
+ /* This function gets called from various locations..
+ * many times from config handler.. so we
+ * to ensure that multiple sessions if any are
+ * released
+ */
+
+ if(PREDICT_FALSE(ep->nsessions > 1)) {
+ cnat_session_entry_t *sdb;
+ while(ep->nsessions > 1 &&
+ ep->session_head_index != EMPTY) {
+ sdb = cnat_session_db + ep->session_head_index;
+ cnat_delete_session_db_entry(sdb, TRUE);
+ }
+ }
+
+ /* Find the set of portmaps for the outside vrf */
+ vrfmap_len = vec_len(cnat_map_by_vrf);
+ udb_len = vec_len(cnat_user_db);
+
+ /* In case of invalid user just return, deleting only main db
+ * is not a good idea, since some valid user db entry might be pointing
+ * to that main db and hence leave the dbs in a inconsistent state
+ */
+ if (PREDICT_FALSE((ep->user_index >= udb_len) ||
+ (clib_bitmap_get(h->free_bitmap, ep->user_index)))) {
+#ifdef DEBUG_PRINTF_ENABLED
+ printf("invalid/unused user index in db %d\n", ep->user_index);
+#endif
+ spp_printf(CNAT_INV_UNUSED_USR_INDEX, 1, (u32 *) &(ep->user_index));
+ cnat_main_db_entry_dump(ep);
+ goto unlock;
+ }
+
+ up = cnat_user_db + ep->user_index;
+
+/* Point to the right portmap list */
+if (PREDICT_FALSE(ep->flags & CNAT_DB_DSLITE_FLAG)) {
+ instance = ep->dslite_nat44_inst_id;
+ pm = dslite_table_db_ptr[instance].portmap_list;
+ if(PREDICT_FALSE((pm == NULL))) {
+ DSLITE_PRINTF(3, "NULL portmap list for dslite_id %u, state %u\n",
+ instance, dslite_table_db_ptr[instance].state);
+ cnat_main_db_entry_dump(ep);
+ goto delete_entry;
+ }
+ static_port_range =
+ STAT_PORT_RANGE_FROM_INST_PTR(&(dslite_table_db_ptr[instance]));
+ /*
+ * Netflow logging API for delete event
+ */
+ bulk_size =
+ BULKSIZE_FROM_VRFMAP(&(dslite_table_db_ptr[instance]));
+} else {
+ if (PREDICT_FALSE(ep->vrfmap_index >= vrfmap_len)) {
+#ifdef DEBUG_PRINTF_ENABLED
+ printf("invalid vrfmap index in db\n");
+#endif
+ spp_printf(CNAT_INVALID_VRFMAP_INDEX, 0, NULL);
+ cnat_main_db_entry_dump(ep);
+ goto delete_entry;
+ }
+ instance = NAT44_RESERVED_INST_ID;
+ my_vrfmap = cnat_map_by_vrf + ep->vrfmap_index;
+ pm = my_vrfmap->portmap_list;
+ static_port_range = cnat_static_port_range;
+ bulk_size = BULKSIZE_FROM_VRFMAP(my_vrfmap);
+}
+
+ if (PREDICT_FALSE(ep->flags & CNAT_DB_FLAG_PORT_PAIR)) {
+ /* Give back the port(s) */
+ cnat_port_free_v2_bulk(pm, up->portmap_index,
+ PORT_PAIR, ep->out2in_key.k.port, up, static_port_range
+#ifndef NO_BULK_LOGGING
+ , bulk_size, &nfv9_log_req
+#endif
+ );
+ } else {
+ /* Give back the port(s) */
+ cnat_port_free_v2_bulk (pm, up->portmap_index,
+ PORT_SINGLE, ep->out2in_key.k.port, up, static_port_range
+#ifndef NO_BULK_LOGGING
+ , bulk_size, &nfv9_log_req
+#endif
+ );
+ }
+
+ if (PREDICT_TRUE(!(ep->flags & CNAT_DB_DSLITE_FLAG))) {
+ if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) {
+ if(PREDICT_FALSE(my_vrfmap->nf_logging_policy == SESSION_LOG_ENABLE)) {
+ if(ep->nsessions != 0) {
+ cnat_nfv9_nat44_log_session_delete(ep, NULL, my_vrfmap);
+ }
+ } else {
+ cnat_nfv9_log_mapping_delete(ep, my_vrfmap
+#ifndef NO_BULK_LOGGING
+ , nfv9_log_req
+#endif
+ );
+ }
+ if(PREDICT_TRUE((my_vrfmap->syslog_logging_policy != SESSION_LOG_ENABLE) ||
+ (ep->nsessions != 0))) {
+ cnat_syslog_nat44_mapping_delete(ep, my_vrfmap, NULL
+#ifndef NO_BULK_LOGGING
+ , nfv9_log_req
+#endif
+ );
+ }
+ }
+ } else {
+ if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) {
+ if(PREDICT_FALSE( dslite_table_db_ptr[instance].nf_logging_policy ==
+ SESSION_LOG_ENABLE)) {
+ cnat_nfv9_ds_lite_log_session_delete(ep,
+ (dslite_table_db_ptr + instance),NULL);
+ } else {
+ cnat_nfv9_ds_lite_mapping_delete(ep,
+ (dslite_table_db_ptr + instance)
+#ifndef NO_BULK_LOGGING
+ , nfv9_log_req
+#endif
+ );
+ }
+#ifdef TOBE_PORTED
+ cnat_syslog_ds_lite_mapping_delete(ep,
+ (dslite_table_db_ptr + instance), NULL
+#ifndef NO_BULK_LOGGING
+ , nfv9_log_req
+#endif
+ );
+#endif /* TOBE_PORTED */
+ }
+ }
+
+delete_entry:
+
+ main_db_index = ep - cnat_main_db;
+
+ pthread_spin_lock(cnat_db_v2_main.user_db_lockp);
+ up->ntranslations--;
+ pthread_spin_unlock(cnat_db_v2_main.user_db_lockp);
+
+ /*
+ * when user reaches max allowed port limit
+ * we generate icmp msg and inc the counter
+ * when counter reach the icmp msg rate limit
+ * we stop icmp msg gen
+ * when a user port is freed
+ * that means we need to clear the msg gen counter
+ * so that next time
+ * reach max port limit, we can generate new icmp msg again
+ */
+ up->icmp_msg_count = 0;
+
+ up->translation_list_head_index = index_dlist_remelem (
+ up->translation_list_head_index, (u8 *)cnat_main_db,
+ sizeof (cnat_main_db[0]),
+ STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports),
+ main_db_index);
+
+ cnat_db_in2out_hash_delete(ep, up);
+
+ if (PREDICT_FALSE(up->ntranslations == 0)) {
+ ASSERT(up->translation_list_head_index == EMPTY);
+ nat44_dslite_common_stats[instance].num_subscribers--;
+ my_index = up->portmap_index;
+ my_pm = pm + my_index;
+ if(PREDICT_TRUE(my_pm->private_ip_users_count)) {
+ my_pm->private_ip_users_count--;
+#ifdef DEBUG_PRINTF_IP_N_TO_1_ENABLED
+ PLATFORM_DEBUG_PRINT("\n cnat_delete_main_db_entry_v2 "
+ "private_ip_users_count = %d",
+ my_pm->private_ip_users_count);
+#endif
+
+ }
+ cnat_user_db_delete(up);
+
+ }
+
+ /* Remove from main DB hashes */
+ //cnat_db_in2out_hash_delete(ep);
+ cnat_db_out2in_hash_delete(ep);
+
+ pool_put(cnat_main_db, ep);
+
+ if(PREDICT_FALSE(ep->flags & CNAT_DB_FLAG_STATIC_PORT)) {
+ nat44_dslite_common_stats[instance].num_static_translations--;
+ } else {
+ nat44_dslite_common_stats[instance].num_dynamic_translations--;
+ }
+ nat44_dslite_common_stats[instance].active_translations--;
+ nat44_dslite_global_stats[!!(instance - 1)].translation_delete_count ++;
+unlock:
+ pthread_spin_unlock(cnat_db_v2_main.main_db_lockp);
+}
+
+cnat_main_db_entry_t*
+cnat_main_db_lookup_entry_out2in (cnat_db_key_bucket_t *ko)
+{
+ u64 a, b, c;
+ u32 index;
+ cnat_main_db_entry_t *db;
+
+ CNAT_V4_GET_HASH(ko->k.key64,
+ ko->bucket,
+ CNAT_MAIN_HASH_MASK);
+
+ index = cnat_out2in_hash[ko->bucket].next;
+ if (PREDICT_TRUE(index == EMPTY)) {
+ return (NULL);
+ }
+
+ do {
+ db = cnat_main_db + index;
+ if (PREDICT_TRUE(db->out2in_key.key64 == ko->k.key64)) {
+ return db;
+ }
+ index = db->out2in_hash.next;
+ } while (index != EMPTY);
+
+ return (NULL);
+}
+
+/* Creates 2 sessions.
+ * Moves the default dest info from mdb to first session
+ * Fills the dest_info details in to second session and
+ * returns the pointer to second session
+ */
+cnat_session_entry_t *cnat_handle_1to2_session(
+ cnat_main_db_entry_t *mdb,
+ cnat_key_t *dest_info)
+{
+ cnat_key_t old_dest_info;
+ pool_header_t *h;
+ u32 free_session = 0;
+ u16 instance;
+ cnat_session_entry_t *session_db1 = NULL, *session_db2 = NULL;
+
+ h = pool_header(cnat_session_db);
+ free_session = vec_len(h->free_indices) - 1;
+
+ if (PREDICT_FALSE(free_session < 2)) {
+ if (mdb->flags & CNAT_DB_DSLITE_FLAG) {
+ instance = mdb->dslite_nat44_inst_id;
+ } else {
+ instance = NAT44_RESERVED_INST_ID;
+ }
+
+ /* we need 2 sessions here, return NULL */
+ nat44_dslite_common_stats[instance].drops_sessiondb_limit_exceeded++;
+ return NULL;
+ }
+
+ old_dest_info.k.ipv4 = mdb->dst_ipv4;
+ old_dest_info.k.port = mdb->dst_port;
+ old_dest_info.k.vrf = mdb->in2out_key.k.vrf;
+
+ /* create 2 new sessions */
+ session_db1 = cnat_create_session_db_entry(&old_dest_info,
+ mdb, FALSE);
+
+ if(PREDICT_FALSE(session_db1 == NULL)) {
+ return NULL;
+ }
+
+ /* update pkt info to session 2 */
+ session_db2 = cnat_create_session_db_entry(dest_info,
+ mdb, TRUE);
+
+ if(PREDICT_FALSE(session_db2 == NULL)) {
+ cnat_delete_session_db_entry(session_db1, FALSE);
+ return NULL;
+ }
+ /* update main db info to session 1 */
+ cnat_dest_update_main2session(mdb, session_db1);
+
+ return session_db2;
+}
+
+/* The below function shold be called only
+ * when a NAT44 STATIC entry received traffic
+ * for the first time. This is to ensure
+ * the destination is noted and logged
+ */
+void cnat_add_dest_n_log(
+ cnat_main_db_entry_t *mdb,
+ cnat_key_t *dest_info)
+{
+
+ if(PREDICT_FALSE(mdb->nsessions != 0)) {
+ return; /* Should not have been called */
+ }
+
+ mdb->dst_ipv4 = dest_info->k.ipv4;
+ mdb->dst_port = dest_info->k.port;
+ mdb->nsessions = 1;
+ mdb->entry_expires = cnat_current_time;
+ u16 instance;
+
+ if (mdb->flags & CNAT_DB_DSLITE_FLAG) {
+ instance = mdb->dslite_nat44_inst_id;
+ cnat_session_log_ds_lite_mapping_create(mdb,
+ (dslite_table_db_ptr + instance),NULL);
+ } else {
+ instance = NAT44_RESERVED_INST_ID;
+ cnat_vrfmap_t *my_vrfmap = cnat_map_by_vrf + mdb->vrfmap_index;
+ cnat_session_log_nat44_mapping_create(mdb, 0, my_vrfmap);
+ }
+}
+
+/*
+ * this function is called by exception node
+ * when lookup is fialed in i2o node
+ *
+ * if reash per user port limit,
+ * set user_db_entry pointer, and error == CNAT_OUT_LIMIT
+ */
+static cnat_main_db_entry_t*
+_cnat_get_main_db_entry_v2(cnat_db_key_bucket_t *ki,
+ port_pair_t port_pair_type,
+ port_type_t port_type,
+ cnat_gen_icmp_info *info,
+ cnat_key_t *dest_info)
+{
+ u16 protocol;
+ cnat_errno_t rv;
+ cnat_db_key_bucket_t u_ki, ko;
+ u32 my_index, free_main, free_user;
+ u32 current_timestamp;
+ u16 my_vrfmap_index;
+ u16 my_vrfmap_entry_found = 0;
+ cnat_vrfmap_t *my_vrfmap =0;
+ cnat_portmap_v2_t *pm =0;
+ cnat_user_db_entry_t *udb = 0;
+ cnat_main_db_entry_t *db = 0;
+ pool_header_t *h;
+ u16 port_limit;
+ cnat_portmap_v2_t *my_pm = 0;
+
+#ifndef NO_BULK_LOGGING
+ int nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
+#endif
+
+
+ /*
+ * need to try lookup again because
+ * second pkt may come here before the entry is created
+ * by receiving first pkt due to high line rate.
+ */
+ info->gen_icmp_msg = CNAT_NO_ICMP_MSG;
+ info->error = CNAT_SUCCESS;
+ db = cnat_main_db_lookup_entry(ki);
+ if (PREDICT_TRUE(db)) {
+ /* what if the source is talking to a
+ * new dest now? We will have to handle this case and
+ * take care of - creating session db and logging
+ */
+ if(PREDICT_FALSE((!dest_info->k.ipv4) && (!dest_info->k.port))) {
+ return db; /* if dest_info is null don't create session */
+ }
+ if(PREDICT_TRUE((db->dst_ipv4 == dest_info->k.ipv4) &&
+ (db->dst_port == dest_info->k.port))) {
+ return db;
+ }
+ dest_info->k.vrf = db->in2out_key.k.vrf;
+ /* Src is indeed talking to a different dest */
+ cnat_session_entry_t *session_db2 = NULL;
+ if(PREDICT_TRUE(db->nsessions == 1)) {
+ session_db2 = cnat_handle_1to2_session(db, dest_info);
+ if(PREDICT_TRUE(session_db2 != NULL)) {
+ CNAT_DB_TIMEOUT_RST(session_db2);
+ return db;
+ } else {
+ info->error = CNAT_ERR_NO_SESSION_DB;
+ return NULL;
+ }
+ } else if(PREDICT_FALSE(db->nsessions == 0)) {
+ /* Should be static entry.. should never happen
+ */
+ if(PREDICT_TRUE(dest_info->k.ipv4 != 0)) {
+ cnat_add_dest_n_log(db, dest_info);
+ }
+ return db;
+ } else {
+ /* The src has already created multiple sessions.. very rare
+ */
+ session_db2 = cnat_create_session_db_entry(dest_info,
+ db, TRUE);
+ if(PREDICT_TRUE(session_db2 != NULL)) {
+ CNAT_DB_TIMEOUT_RST(session_db2);
+ return db;
+ } else {
+ info->error = CNAT_ERR_NO_SESSION_DB;
+ return NULL;
+ }
+ }
+
+ }
+
+ /*
+ * step 1. check if outside vrf is configured or not
+ * and Find the set of portmaps for the outside vrf
+ * insider vrf is one to one mappted to outside vrf
+ * key is vrf and ip only
+ * ki.k.k.vrf has protocol bits, mask out
+ */
+ protocol = ki->k.k.vrf & CNAT_PRO_MASK;
+ u_ki.k.k.vrf = ki->k.k.vrf & CNAT_VRF_MASK;
+ u_ki.k.k.ipv4 = ki->k.k.ipv4;
+ u_ki.k.k.port = 0;
+
+ my_vrfmap_index = vrf_map_array[u_ki.k.k.vrf];
+ my_vrfmap = cnat_map_by_vrf + my_vrfmap_index;
+
+ my_vrfmap_entry_found = ((my_vrfmap_index != VRF_MAP_ENTRY_EMPTY) &&
+ (my_vrfmap->status == S_RUN) &&
+ (my_vrfmap->i_vrf == u_ki.k.k.vrf));
+
+ if (PREDICT_FALSE(!my_vrfmap_entry_found)) {
+ u32 arr[] = {ki->k.k.vrf, ki->k.k.ipv4, ki->k.k.port};
+ if ((my_vrfmap_index == VRF_MAP_ENTRY_EMPTY) ||
+ (my_vrfmap->i_vrf == u_ki.k.k.vrf)) {
+ info->error = CNAT_NO_CONFIG;
+ CNAT_DEBUG_INSIDE_ERR(CNAT_NO_CONFIG)
+ spp_printf(CNAT_NO_CONFIG_ERROR, 3, arr);
+ } else {
+ info->error = CNAT_NO_VRF_RUN;
+ CNAT_DEBUG_INSIDE_ERR(CNAT_NO_VRF_RUN)
+ spp_printf(CNAT_NO_VRF_RUN_ERROR, 3, arr);
+ }
+
+ return (NULL);
+ }
+
+ pm = my_vrfmap->portmap_list;
+
+ port_limit = my_vrfmap->port_limit;
+ if(PREDICT_FALSE(!port_limit)) {
+ port_limit = cnat_main_db_max_ports_per_user;
+ }
+ /*
+ * set o2i key with protocl bits
+ */
+ ko.k.k.vrf = my_vrfmap->o_vrf | protocol;
+
+ /*
+ * step 2. check if src vrf, src ip addr is alreay
+ * in the user db
+ * if yes, use PORT_ALLOC_DIRECTED
+ * if no, use PORT_ALLOC_ANY since it is first time
+ */
+ udb = cnat_user_db_lookup_entry(&u_ki);
+ if (PREDICT_TRUE(udb)) {
+ /*
+ * not first time allocate port for this user
+ * check limit
+ */
+ if (PREDICT_FALSE(udb->ntranslations >=
+ port_limit)) {
+ /* Check for the port type here. If we are getting
+ * a STATIC PORT, allow the config.
+ */
+ if (PREDICT_TRUE(port_type != PORT_TYPE_STATIC)) {
+ info->error = CNAT_OUT_LIMIT;
+ CNAT_SET_ICMP_MSG_INFO
+ CNAT_DEBUG_INSIDE_ERR(CNAT_OUT_LIMIT)
+ port_exceeded_msg_log(u_ki.k.k.ipv4, u_ki.k.k.vrf);
+ in2out_drops_port_limit_exceeded ++;
+ u_ki.k.k.port = ki->k.k.port;
+ u_ki.k.k.vrf = ki->k.k.vrf;
+ handle_cnat_port_exceeded_logging(udb, &u_ki.k, my_vrfmap);
+ return (NULL);
+ }
+ }
+ CHECK_CLEAR_PORT_LIMIT_EXCEED_FLAG(udb,
+ port_limit)
+
+ /*
+ * check if main db has space to accomodate new entry
+ */
+ h = pool_header(cnat_main_db);
+
+ free_main = vec_len(h->free_indices) - 1;
+ if (PREDICT_FALSE(!free_main)) {
+ info->error = CNAT_MAIN_DB_LIMIT;
+ CNAT_SET_ICMP_MSG_INFO
+ in2out_drops_system_limit_reached ++;
+ CNAT_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT)
+
+ current_timestamp = spp_trace_log_get_unix_time_in_seconds();
+ if (PREDICT_FALSE((current_timestamp - last_log_timestamp) >
+ 1800)) {
+ spp_printf(CNAT_SESSION_THRESH_EXCEEDED, 0, NULL);
+ last_log_timestamp = current_timestamp;
+ }
+
+#ifdef UT_TEST_CODE
+ printf("Limit reached : OLD USER");
+#endif
+ return NULL;
+ }
+
+ /*
+ * allocate port, from existing mapping
+ */
+ my_index = udb->portmap_index;
+
+ if (PREDICT_FALSE(port_type == PORT_TYPE_STATIC)) {
+ rv = cnat_static_port_alloc_v2_bulk(pm,
+ PORT_ALLOC_DIRECTED,
+ port_pair_type,
+ ki->k.k.ipv4,
+ ki->k.k.port,
+ &my_index,
+ &(ko.k.k.ipv4),
+ &(ko.k.k.port),
+ cnat_static_port_range
+#ifndef NO_BULK_LOGGING
+ ,
+ udb, BULKSIZE_FROM_VRFMAP(my_vrfmap),
+ &nfv9_log_req
+#endif
+ , my_vrfmap->ip_n_to_1
+ );
+
+ } else if (PREDICT_TRUE(port_type != PORT_TYPE_RTSP) ) {
+
+ rv = cnat_dynamic_port_alloc_v2_bulk(pm,
+ PORT_ALLOC_DIRECTED,
+ port_pair_type,
+ &my_index,
+ &(ko.k.k.ipv4),
+ &(ko.k.k.port),
+ cnat_static_port_range
+#ifndef NO_BULK_LOGGING
+ ,
+ udb, BULKSIZE_FROM_VRFMAP(my_vrfmap),
+ &nfv9_log_req
+#endif
+ , my_vrfmap->ip_n_to_1,
+ &(my_vrfmap->rseed_ip)
+ );
+
+ } else {
+ /*
+ * For RTSP, two translation entries are created,
+ * check if main db has space to accomodate two new entry
+ */
+ free_main = free_main - 1;
+ if (PREDICT_FALSE(!free_main)) {
+ info->error = CNAT_MAIN_DB_LIMIT;
+ CNAT_SET_ICMP_MSG_INFO
+ in2out_drops_system_limit_reached ++;
+ CNAT_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT)
+
+ return NULL;
+ } else {
+ rv = cnat_dynamic_port_alloc_rtsp_bulk(pm,
+ PORT_ALLOC_DIRECTED,
+ port_pair_type,
+ ki->k.k.port,
+ &my_index,
+ &(ko.k.k.ipv4),
+ &(ko.k.k.port),
+ cnat_static_port_range
+#ifndef NO_BULK_LOGGING
+ ,
+ udb, BULKSIZE_FROM_VRFMAP(my_vrfmap),
+ &nfv9_log_req
+#endif
+ , &(my_vrfmap->rseed_ip)
+ );
+ }
+ }
+
+
+ if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
+ info->error = rv;
+ CNAT_SET_ICMP_MSG_INFO
+ CNAT_DEBUG_INSIDE_ERR(rv)
+ in2out_drops_resource_depletion++;
+ log_port_alloc_error(rv, &(ki->k));
+ return (NULL);
+ }
+ /*
+ * increment port in use for this user
+ */
+ pthread_spin_lock(cnat_db_v2_main.user_db_lockp);
+ udb->ntranslations += 1;
+ pthread_spin_unlock(cnat_db_v2_main.user_db_lockp);
+
+ } else {
+ /*
+ * first time allocate port for this user
+ */
+
+ /*
+ * Do not create entry if port limit is invalid
+ */
+
+ if (PREDICT_FALSE(!port_limit)) {
+ if (PREDICT_TRUE(port_type != PORT_TYPE_STATIC)) {
+ info->error = CNAT_OUT_LIMIT;
+ in2out_drops_port_limit_exceeded ++;
+ port_exceeded_msg_log(u_ki.k.k.ipv4, u_ki.k.k.vrf);
+ CNAT_SET_ICMP_MSG_INFO
+ CNAT_DEBUG_INSIDE_ERR(CNAT_OUT_LIMIT)
+ return (NULL);
+ }
+ }
+
+ /*
+ * Check if main db has space for new entry
+ * Allowing a user db entry to be created if main db is not free
+ * will cause a port to be allocated to that user, which results in
+ * wastage of that port, hence the check is done here.
+ */
+ h = pool_header(cnat_main_db);
+ free_main = vec_len(h->free_indices) - 1;
+ h = pool_header(cnat_user_db);
+ free_user = vec_len(h->free_indices) - 1;
+
+ /*
+ * If either main_db or user_db does not have entries
+ * bail out, with appropriate error
+ */
+ if (PREDICT_FALSE(!(free_main && free_user))) {
+ u32 log_error;
+ if(free_main) {
+ info->error = CNAT_USER_DB_LIMIT;
+ log_error = CNAT_USER_DB_LIMIT_ERROR;
+ } else {
+ info->error = CNAT_MAIN_DB_LIMIT;
+ log_error = CNAT_MAIN_DB_LIMIT_ERROR;
+ }
+ in2out_drops_system_limit_reached ++;
+ CNAT_SET_ICMP_MSG_INFO
+ CNAT_DEBUG_INSIDE_ERR(info->error)
+ spp_printf(log_error, 0, 0);
+ return NULL;
+ }
+
+ if (PREDICT_FALSE(port_type == PORT_TYPE_STATIC)) {
+ rv = cnat_static_port_alloc_v2_bulk(pm,
+ PORT_ALLOC_ANY,
+ port_pair_type,
+ ki->k.k.ipv4,
+ ki->k.k.port,
+ &my_index,
+ &(ko.k.k.ipv4),
+ &(ko.k.k.port),
+ cnat_static_port_range
+#ifndef NO_BULK_LOGGING
+ ,
+ udb, BULKSIZE_FROM_VRFMAP(my_vrfmap),
+ &nfv9_log_req
+#endif
+ , my_vrfmap->ip_n_to_1
+ );
+
+ } else if (PREDICT_TRUE(port_type != PORT_TYPE_RTSP)) {
+ rv = cnat_dynamic_port_alloc_v2_bulk(pm,
+ PORT_ALLOC_ANY,
+ port_pair_type,
+ &my_index,
+ &(ko.k.k.ipv4),
+ &(ko.k.k.port),
+ cnat_static_port_range
+#ifndef NO_BULK_LOGGING
+ , NULL, BULKSIZE_FROM_VRFMAP(my_vrfmap),
+ &nfv9_log_req
+#endif
+ , my_vrfmap->ip_n_to_1,
+ &(my_vrfmap->rseed_ip)
+ );
+ } else {
+ /*
+ * For RTSP, two translation entries are created,
+ * check if main db has space to accomodate two new entry
+ */
+ free_main = free_main - 1;
+ if (PREDICT_FALSE(!free_main)) {
+ info->error = CNAT_MAIN_DB_LIMIT;
+ CNAT_SET_ICMP_MSG_INFO
+ in2out_drops_system_limit_reached ++;
+ CNAT_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT)
+
+ return NULL;
+ } else {
+
+ rv = cnat_dynamic_port_alloc_rtsp_bulk(pm,
+ PORT_ALLOC_ANY,
+ port_pair_type,
+ ki->k.k.port,
+ &my_index,
+ &(ko.k.k.ipv4),
+ &(ko.k.k.port),
+ cnat_static_port_range
+#ifndef NO_BULK_LOGGING
+ , NULL, BULKSIZE_FROM_VRFMAP(my_vrfmap),
+ &nfv9_log_req
+#endif
+ , &(my_vrfmap->rseed_ip)
+ );
+ /* TODO: Add the port pair flag here */
+ }
+ }
+
+
+
+ if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
+ info->error = rv;
+ in2out_drops_resource_depletion ++;
+ CNAT_SET_ICMP_MSG_INFO
+ CNAT_DEBUG_INSIDE_ERR(rv)
+ log_port_alloc_error(rv, &(ki->k));
+ return (NULL);
+ }
+ /*
+ * create entry in user db
+ */
+ udb = cnat_user_db_create_entry(&u_ki, my_index);
+ NAT44_COMMON_STATS.num_subscribers++;
+ my_pm = pm + my_index;
+ if(PREDICT_TRUE(my_pm->private_ip_users_count < PORTS_PER_ADDR)) {
+ my_pm->private_ip_users_count++;
+#ifdef DEBUG_PRINTF_IP_N_TO_1_ENABLED
+ PLATFORM_DEBUG_PRINT("\n cnat_get_main_db_entry_v2 "
+ "dynamic alloc private_ip_users_count = %d",
+ my_pm->private_ip_users_count);
+#endif
+ } else {
+ PLATFORM_DEBUG_PRINT("\n ERROR: private_ip_users_count has "
+ "reached MAX PORTS_PER_ADDR");
+ }
+#ifndef NO_BULK_LOGGING
+ if(PREDICT_TRUE(udb && (BULK_ALLOC_NOT_ATTEMPTED != nfv9_log_req))) {
+ cnat_update_bulk_range_cache(udb, ko.k.k.port,
+ BULKSIZE_FROM_VRFMAP(my_vrfmap));
+ }
+#endif /* #ifndef NO_BULK_LOGGING */
+
+ }
+
+ /*
+ * step 3:
+ * outside port is allocated for this src vrf/src ip addr
+ * 1)create a new entry in main db
+ * 2)setup cnat_out2in_hash key
+ * 3)setup cnat_in2out_hash key
+ */
+ db = cnat_create_main_db_entry_and_hash(ki, &ko, udb);
+
+ translation_create_count ++;
+#ifdef DSLITE_DEF
+ db->dslite_nat44_inst_id = NAT44_RESERVED_INST_ID;
+#endif
+ db->vrfmap_index = my_vrfmap - cnat_map_by_vrf;
+
+ /*
+ * don't forget logging
+ * logging API is unconditional,
+ * logging configuration check is done inside the inline function
+ */
+
+ db->dst_ipv4 = dest_info->k.ipv4;
+ db->dst_port = dest_info->k.port;
+ if(PREDICT_TRUE(db->dst_ipv4 || db->dst_port)) {
+ db->nsessions++;
+ }
+
+ if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) {
+ if(PREDICT_FALSE(my_vrfmap->nf_logging_policy == SESSION_LOG_ENABLE)) {
+ /* do not log for static entries.. we will log when traffic flows */
+ if(PREDICT_TRUE(db->dst_ipv4 || db->dst_port)) {
+ cnat_nfv9_nat44_log_session_create(db, 0, my_vrfmap);
+ }
+ } else {
+ cnat_nfv9_log_mapping_create(db, my_vrfmap
+#ifndef NO_BULK_LOGGING
+ , nfv9_log_req
+#endif
+ );
+ }
+ if(PREDICT_TRUE((my_vrfmap->syslog_logging_policy != SESSION_LOG_ENABLE) ||
+ (db->dst_ipv4 || db->dst_port))) {
+ cnat_syslog_nat44_mapping_create(db, my_vrfmap, 0
+#ifndef NO_BULK_LOGGING
+ , nfv9_log_req
+#endif
+ );
+ }
+ }
+ if (PREDICT_FALSE(port_pair_type == PORT_PAIR)) {
+ cnat_main_db_entry_t *db2 = 0;
+ cnat_db_key_bucket_t new_ki = *ki;
+ u64 a, b, c;
+
+ new_ki.k.k.port += 1;
+ ko.k.k.port += 1;
+
+ CNAT_V4_GET_HASH(new_ki.k.key64, new_ki.bucket,
+ CNAT_MAIN_HASH_MASK);
+
+ db2 = cnat_create_main_db_entry_and_hash(&new_ki, &ko, udb);
+
+ translation_create_count ++;
+#ifdef DSLITE_DEF
+ db2->dslite_nat44_inst_id = NAT44_RESERVED_INST_ID;
+#endif
+ db2->vrfmap_index = my_vrfmap - cnat_map_by_vrf;
+ db2->entry_expires = cnat_current_time;
+ db2->flags |= CNAT_DB_FLAG_ALG_ENTRY;
+ pthread_spin_lock(cnat_db_v2_main.user_db_lockp);
+ udb->ntranslations += 1;
+ pthread_spin_unlock(cnat_db_v2_main.user_db_lockp);
+ db2->dst_ipv4 = dest_info->k.ipv4;
+ db2->dst_port = dest_info->k.port;
+ db2->nsessions = 0; /* For ALG db, set sessions to 0 - CSCuf78420 */
+
+ if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) {
+ if(PREDICT_FALSE(my_vrfmap->nf_logging_policy == SESSION_LOG_ENABLE)) {
+ /* do not log for static entries.. we will log when traffic flows */
+ if(PREDICT_TRUE(db2->dst_ipv4 || db2->dst_port)) {
+ cnat_nfv9_nat44_log_session_create(db2, 0, my_vrfmap);
+ }
+ } else {
+ cnat_nfv9_log_mapping_create(db2, my_vrfmap
+#ifndef NO_BULK_LOGGING
+ , nfv9_log_req
+#endif
+ );
+ }
+ if(PREDICT_TRUE((my_vrfmap->syslog_logging_policy != SESSION_LOG_ENABLE) ||
+ (db2->dst_ipv4 || db2->dst_port))) {
+ cnat_syslog_nat44_mapping_create(db2, my_vrfmap, 0
+#ifndef NO_BULK_LOGGING
+ , nfv9_log_req
+#endif
+ );
+ }
+ }
+ }
+
+ return db;
+}
+
+cnat_main_db_entry_t*
+cnat_get_main_db_entry_v2(cnat_db_key_bucket_t *ki,
+ port_pair_t port_pair_type,
+ port_type_t port_type,
+ cnat_gen_icmp_info *info,
+ cnat_key_t *dest_info)
+{
+
+ cnat_main_db_entry_t *db;
+ pthread_spin_lock(cnat_db_v2_main.main_db_lockp);
+ db = _cnat_get_main_db_entry_v2(ki, port_pair_type,
+ port_type, info, dest_info);
+ pthread_spin_unlock(cnat_db_v2_main.main_db_lockp);
+ return db;
+}
+
+/*
+ * this function is called from config handler only
+ * to allocate a static port based db entry
+ *
+ * the actual mapped address and port are already specified
+ */
+cnat_main_db_entry_t*
+cnat_create_static_main_db_entry_v2 (cnat_db_key_bucket_t *ki,
+ cnat_db_key_bucket_t *ko,
+ cnat_vrfmap_t *my_vrfmap,
+ cnat_gen_icmp_info *info)
+{
+ u16 protocol;
+ u32 head;
+ cnat_errno_t rv;
+ cnat_db_key_bucket_t u_ki;
+ u32 my_index, free_main, free_user;
+ cnat_portmap_v2_t *pm =0;
+ cnat_portmap_v2_t *my_pm =0;
+ cnat_user_db_entry_t *udb = 0;
+ cnat_main_db_entry_t *db = 0;
+ pool_header_t *h;
+#ifndef NO_BULK_LOGGING
+ int nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
+#endif
+
+ /* UNUSED. Therefore not ported to be multi-thread friendly */
+ ASSERT(0);
+
+ /*
+ * need to try lookup again because
+ * second pkt may come here before the entry is created
+ * by receiving first pkt due to high line rate.
+ */
+ info->gen_icmp_msg = CNAT_NO_ICMP_MSG;
+ info->error = CNAT_SUCCESS;
+ db = cnat_main_db_lookup_entry(ki);
+
+ /*
+ * If we already have an entry with this inside address, port
+ * check delete the entry and proceed further. This should
+ * If yes, something is terribly wrong. Bail out
+ */
+ if (PREDICT_FALSE(db)) {
+
+ if (db->flags & CNAT_DB_FLAG_STATIC_PORT) {
+
+ if ((db->out2in_key.k.ipv4 == ko->k.k.ipv4) &&
+ (db->out2in_key.k.port == ko->k.k.port) &&
+ (db->out2in_key.k.vrf == ko->k.k.vrf)) {
+
+#ifdef DEBUG_PRINTF_ENABLED
+ printf("Same Static Port Exists ki 0x%16llx ko 0x%16llx",
+ ki->k, ko->k);
+#endif
+ /*
+ * We have already programmed this, return
+ */
+ return (db);
+ }
+
+ /*
+ * We already have a static port with different mapping
+ * Return an error for this case.
+ */
+ info->error = CNAT_ERR_PARSER;
+
+#ifdef DEBUG_PRINTF_ENABLED
+ printf("Static Port Existing and Diff ki 0x%16llx ko 0x%16llx",
+ ki, db->out2in_key);
+#endif
+ {
+ u32 arr[] = {STAT_PORT_CONFIG_IN_USE, (ki->k.k.vrf & CNAT_VRF_MASK),
+ ki->k.k.ipv4, ki->k.k.port, (ki->k.k.vrf & CNAT_PRO_MASK) };
+ spp_printf(CNAT_CONFIG_ERROR, 5, arr);
+ }
+ return (db);
+ }
+
+#ifdef DEBUG_PRINTF_ENABLED
+ printf("Deleting Dynamic entry ki 0x%16llx ko 0x%16llx",
+ ki, db->out2in_key);
+#endif
+
+ /*
+ * If for some reason we have dynamic entries, just delete them
+ * and proceed.
+ */
+ cnat_delete_main_db_entry_v2(db);
+
+ db = NULL;
+ }
+
+ protocol = ki->k.k.vrf & CNAT_PRO_MASK;
+ u_ki.k.k.vrf = ki->k.k.vrf & CNAT_VRF_MASK;
+ u_ki.k.k.ipv4 = ki->k.k.ipv4;
+ u_ki.k.k.port = 0;
+
+ pm = my_vrfmap->portmap_list;
+
+ /*
+ * check if src vrf, src ip addr is already
+ * in the user db
+ * if yes, use PORT_ALLOC_DIRECTED
+ * if no, use PORT_ALLOC_ANY since it is first time
+ */
+ udb = cnat_user_db_lookup_entry(&u_ki);
+ if (PREDICT_TRUE(udb)) {
+ /*
+ * check if main db has space to accomodate new entry
+ */
+ h = pool_header(cnat_main_db);
+
+ free_main = vec_len(h->free_indices) - 1;
+ if (PREDICT_FALSE(!free_main)) {
+ info->error = CNAT_MAIN_DB_LIMIT;
+ CNAT_SET_ICMP_MSG_INFO
+ in2out_drops_system_limit_reached ++;
+ CNAT_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT)
+#ifdef UT_TEST_CODE
+ printf("Limit reached : OLD USER");
+#endif
+ spp_printf(CNAT_MAIN_DB_LIMIT_ERROR, 0, 0);
+ return NULL;
+ }
+
+ /*
+ * allocate port, from existing mapping
+ */
+ my_index = udb->portmap_index;
+ my_pm = pm + my_index;
+ /* It is quite possible that we hit the scenario of CSCtj17774.
+ * Delete all the main db entries and add the ipv4 address sent by
+ * CGN-MA as Static port alloc any
+ */
+
+ if (PREDICT_FALSE(my_pm->ipv4_address != ko->k.k.ipv4)) {
+ if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) {
+ printf("Delete Main db entry and check for"
+ " ipv4 address sanity pm add = 0x%x ip add = 0x%x\n",
+ my_pm->ipv4_address, ko->k.k.ipv4);
+ }
+ do {
+ /* udb is not NULL when we begin with for sure */
+ head = udb->translation_list_head_index;
+ db = cnat_main_db + head;
+ cnat_delete_main_db_entry_v2(db);
+ } while (!pool_is_free(cnat_user_db, udb));
+
+ rv = cnat_mapped_static_port_alloc_v2_bulk (pm,
+ PORT_ALLOC_ANY, &my_index, ko->k.k.ipv4, ko->k.k.port,
+ udb, BULKSIZE_FROM_VRFMAP(my_vrfmap), &nfv9_log_req,
+ my_vrfmap->ip_n_to_1);
+
+ if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
+ info->error = rv;
+ in2out_drops_resource_depletion ++;
+ CNAT_SET_ICMP_MSG_INFO
+ CNAT_DEBUG_INSIDE_ERR(rv)
+ return (NULL);
+ }
+ /*
+ * create entry in user db
+ */
+ udb = cnat_user_db_create_entry(&u_ki, my_index);
+ my_pm = pm + my_index;
+ if(PREDICT_TRUE(my_pm->private_ip_users_count < PORTS_PER_ADDR)) {
+ my_pm->private_ip_users_count++;
+#ifdef DEBUG_PRINTF_IP_N_TO_1_ENABLED
+ PLATFORM_DEBUG_PRINT("\n cnat_create_static_main_db_entry_v2 "
+ "static del n alloc private_ip_users_count = "
+ "%d",my_pm->private_ip_users_count);
+#endif
+ } else {
+ PLATFORM_DEBUG_PRINT("\n ERROR: private_ip_users_count has "
+ "reached MAX PORTS_PER_ADDR");
+ }
+ NAT44_COMMON_STATS.num_subscribers++;
+#ifndef NO_BULK_LOGGING
+ cnat_update_bulk_range_cache(udb, ko->k.k.port,
+ BULKSIZE_FROM_VRFMAP(my_vrfmap));
+#endif /* #ifndef NO_BULK_LOGGING */
+ } else {
+
+ rv = cnat_mapped_static_port_alloc_v2_bulk (pm,
+ PORT_ALLOC_DIRECTED, &my_index, ko->k.k.ipv4, ko->k.k.port,
+ udb, BULKSIZE_FROM_VRFMAP(my_vrfmap), &nfv9_log_req,
+ my_vrfmap->ip_n_to_1);
+
+ if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
+ info->error = rv;
+ CNAT_SET_ICMP_MSG_INFO
+ CNAT_DEBUG_INSIDE_ERR(rv)
+ log_port_alloc_error(rv, &(ki->k));
+ return (NULL);
+ }
+
+ /*
+ * increment port in use for this user
+ */
+ udb->ntranslations += 1;
+ }
+ } else {
+ if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) {
+ printf ("Static port alloc any\n");
+ }
+ /*
+ * first time allocate port for this user
+ */
+
+ /*
+ * Check if main db has space for new entry
+ * Allowing a user db entry to be created if main db is not free
+ * will cause a port to be allocated to that user, which results in
+ * wastage of that port, hence the check is done here.
+ */
+ h = pool_header(cnat_main_db);
+ free_main = vec_len(h->free_indices) - 1;
+ h = pool_header(cnat_user_db);
+ free_user = vec_len(h->free_indices) - 1;
+
+ /*
+ * If either main_db or user_db does not have entries
+ * bail out, with appropriate error
+ */
+ if (PREDICT_FALSE(!(free_main && free_user))) {
+ u32 log_error;
+ if(free_main) {
+ info->error = CNAT_USER_DB_LIMIT;
+ log_error = CNAT_USER_DB_LIMIT_ERROR;
+ } else {
+ info->error = CNAT_MAIN_DB_LIMIT;
+ log_error = CNAT_MAIN_DB_LIMIT_ERROR;
+ }
+ in2out_drops_system_limit_reached ++;
+ CNAT_SET_ICMP_MSG_INFO
+ CNAT_DEBUG_INSIDE_ERR(info->error)
+ spp_printf(log_error, 0, 0);
+ return NULL;
+ }
+
+ rv = cnat_mapped_static_port_alloc_v2_bulk (pm,
+ PORT_ALLOC_ANY, &my_index, ko->k.k.ipv4, ko->k.k.port,
+ udb, BULKSIZE_FROM_VRFMAP(my_vrfmap), &nfv9_log_req,
+ my_vrfmap->ip_n_to_1);
+
+ if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
+ info->error = rv;
+ in2out_drops_resource_depletion ++;
+ CNAT_SET_ICMP_MSG_INFO
+ CNAT_DEBUG_INSIDE_ERR(rv)
+ log_port_alloc_error(rv, &(ki->k));
+ return (NULL);
+ }
+ /*
+ * create entry in user db
+ */
+ udb = cnat_user_db_create_entry(&u_ki, my_index);
+ my_pm = pm + my_index;
+ if(PREDICT_TRUE(my_pm->private_ip_users_count < PORTS_PER_ADDR)) {
+ my_pm->private_ip_users_count++;
+#ifdef DEBUG_PRINTF_IP_N_TO_1_ENABLED
+ PLATFORM_DEBUG_PRINT("\n cnat_create_static_main_db_entry_v2 "
+ "static alloc private_ip_users_count = %d",
+ my_pm->private_ip_users_count);
+#endif
+ } else {
+ PLATFORM_DEBUG_PRINT("\n ERROR: private_ip_users_count has "
+ "reached MAX PORTS_PER_ADDR");
+ }
+ NAT44_COMMON_STATS.num_subscribers++;
+#ifndef NO_BULK_LOGGING
+ cnat_update_bulk_range_cache(udb, ko->k.k.port,
+ BULKSIZE_FROM_VRFMAP(my_vrfmap));
+#endif /* #ifndef NO_BULK_LOGGING */
+ }
+
+ /*
+ * step 3:
+ * outside port is allocated for this src vrf/src ip addr
+ * 1)create a new entry in main db
+ * 2)setup cnat_out2in_hash key
+ * 3)setup cnat_in2out_hash key
+ */
+ db = cnat_create_main_db_entry_and_hash(ki, ko, udb);
+
+ translation_create_count ++;
+ db->vrfmap_index = my_vrfmap - cnat_map_by_vrf;
+
+ /*
+ * don't forget logging
+ * logging API is unconditional,
+ * logging configuration check is done inside the inline function
+ */
+
+ if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) {
+ /* if session logging is enabled .. do not log as there is no
+ * traffic yet
+ */
+ if(PREDICT_FALSE(my_vrfmap->nf_logging_policy != SESSION_LOG_ENABLE)) {
+ cnat_nfv9_log_mapping_create(db, my_vrfmap
+#ifndef NO_BULK_LOGGING
+ , nfv9_log_req
+#endif
+ );
+ }
+ if(PREDICT_FALSE(my_vrfmap->syslog_logging_policy != SESSION_LOG_ENABLE)) {
+ cnat_syslog_nat44_mapping_create(db, my_vrfmap, 0
+#ifndef NO_BULK_LOGGING
+ , nfv9_log_req
+#endif
+ );
+ }
+ }
+
+ return db;
+}
+
+
+cnat_main_db_entry_t*
+dslite_main_db_lookup_entry(dslite_db_key_bucket_t *ki);
+
+cnat_user_db_entry_t*
+dslite_user_db_lookup_entry(dslite_db_key_bucket_t *uki);
+
+cnat_user_db_entry_t*
+dslite_user_db_create_entry(dslite_db_key_bucket_t *uki, u32 portmap_index);
+
+cnat_main_db_entry_t*
+dslite_create_main_db_entry_and_hash(dslite_db_key_bucket_t *ki,
+ cnat_db_key_bucket_t *ko,
+ cnat_user_db_entry_t *udb);
+
+#ifdef TOBE_PORTED
+/*
+ * this function is called from config handler only
+ * to allocate a static port based db entry
+ *
+ * the actual mapped address and port are already specified
+ */
+cnat_main_db_entry_t*
+dslite_create_static_main_db_entry_v2 (dslite_db_key_bucket_t *ki,
+ cnat_db_key_bucket_t *ko,
+ dslite_table_entry_t *dslite_entry_ptr,
+ cnat_gen_icmp_info *info)
+{
+ u16 protocol;
+ u32 head;
+ cnat_errno_t rv;
+ dslite_db_key_bucket_t u_ki;
+ u32 my_index, free_main, free_user;
+ cnat_portmap_v2_t *pm =0;
+ cnat_portmap_v2_t *my_pm =0;
+ cnat_user_db_entry_t *udb = 0;
+ cnat_main_db_entry_t *db = 0;
+ pool_header_t *h;
+ u16 dslite_id = dslite_entry_ptr->dslite_id;
+#ifndef NO_BULK_LOGGING
+ int nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
+#endif
+ cnat_vrfmap_t *my_vrfmap =0;
+ u16 my_vrfmap_index;
+
+ /* UNUSED. Therefore not ported to be multi-thread friendly */
+ ASSERT(0);
+ /*
+ * need to try lookup again because
+ * second pkt may come here before the entry is created
+ * by receiving first pkt due to high line rate.
+ */
+ info->gen_icmp_msg = CNAT_NO_ICMP_MSG;
+ info->error = CNAT_SUCCESS;
+ db = dslite_main_db_lookup_entry(ki);
+
+ /*
+ * If we already have an entry with this inside address, port
+ * check delete the entry and proceed further. This should
+ * If yes, something is terribly wrong. Bail out
+ */
+ if (PREDICT_FALSE(db)) {
+
+ if (db->flags & CNAT_DB_FLAG_STATIC_PORT) {
+
+ if ((db->out2in_key.k.ipv4 == ko->k.k.ipv4) &&
+ (db->out2in_key.k.port == ko->k.k.port) &&
+ (db->out2in_key.k.vrf == ko->k.k.vrf)) {
+
+#ifdef DEBUG_PRINTF_ENABLED
+ printf("Same Static Port Exists ki 0x%16llx ko 0x%16llx",
+ ki->k, ko->k);
+#endif
+ /*
+ * We have already programmed this, return
+ */
+ return (db);
+ }
+
+ /*
+ * We already have a static port with different mapping
+ * Return an error for this case.
+ */
+ info->error = CNAT_ERR_PARSER;
+
+#ifdef DEBUG_PRINTF_ENABLED
+ printf("Static Port Existing and Diff ki 0x%16llx ko 0x%16llx",
+ ki, db->out2in_key);
+#endif
+ {
+ u32 arr[] = {STAT_PORT_CONFIG_IN_USE, (ki->dk.ipv4_key.k.vrf & CNAT_VRF_MASK),
+ ki->dk.ipv4_key.k.ipv4, ki->dk.ipv4_key.k.port, (ki->dk.ipv4_key.k.vrf & CNAT_PRO_MASK) };
+ spp_printf(CNAT_CONFIG_ERROR, 5, arr);
+ }
+ return (db);
+ }
+
+#ifdef DEBUG_PRINTF_ENABLED
+ printf("Deleting Dynamic entry ki 0x%16llx ko 0x%16llx",
+ ki, db->out2in_key);
+#endif
+
+ /*
+ * If for some reason we have dynamic entries, just delete them
+ * and proceed.
+ */
+ cnat_delete_main_db_entry_v2(db);
+
+ db = NULL;
+ }
+
+
+ protocol = ki->dk.ipv4_key.k.vrf & CNAT_PRO_MASK;
+ u_ki.dk.ipv4_key.k.vrf = ki->dk.ipv4_key.k.vrf & CNAT_VRF_MASK;
+ u_ki.dk.ipv4_key.k.ipv4 = ki->dk.ipv4_key.k.ipv4;
+ u_ki.dk.ipv4_key.k.port = 0;
+ u_ki.dk.ipv6[0] = ki->dk.ipv6[0];
+ u_ki.dk.ipv6[1] = ki->dk.ipv6[1];
+ u_ki.dk.ipv6[2] = ki->dk.ipv6[2];
+ u_ki.dk.ipv6[3] = ki->dk.ipv6[3];
+
+ my_vrfmap_index = vrf_map_array[u_ki.dk.ipv4_key.k.vrf];
+ my_vrfmap = cnat_map_by_vrf + my_vrfmap_index;
+
+ pm = dslite_entry_ptr->portmap_list;
+
+ /*
+ * check if src vrf, src ip addr is already
+ * in the user db
+ * if yes, use PORT_ALLOC_DIRECTED
+ * if no, use PORT_ALLOC_ANY since it is first time
+ */
+ udb = dslite_user_db_lookup_entry(&u_ki);
+ if (PREDICT_TRUE(udb)) {
+ /*
+ * check if main db has space to accomodate new entry
+ */
+ h = pool_header(cnat_main_db);
+
+ free_main = vec_len(h->free_indices) - 1;
+ if (PREDICT_FALSE(!free_main)) {
+ info->error = CNAT_MAIN_DB_LIMIT;
+ nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++;
+ DSLITE_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT)
+#ifdef UT_TEST_CODE
+ printf("Limit reached : OLD USER");
+#endif
+ spp_printf(CNAT_MAIN_DB_LIMIT_ERROR, 0, 0);
+ return NULL;
+ }
+
+ /*
+ * allocate port, from existing mapping
+ */
+ my_index = udb->portmap_index;
+ my_pm = pm + my_index;
+ /* It is quite possible that we hit the scenario of CSCtj17774.
+ * Delete all the main db entries and add the ipv4 address sent by
+ * CGN-MA as Static port alloc any
+ */
+
+ if (PREDICT_FALSE(my_pm->ipv4_address != ko->k.k.ipv4)) {
+ if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) {
+ printf("Delete Main db entry and check for"
+ " ipv4 address sanity pm add = 0x%x ip add = 0x%x\n",
+ my_pm->ipv4_address, ko->k.k.ipv4);
+ }
+ do {
+ /* udb is not NULL when we begin with for sure */
+ head = udb->translation_list_head_index;
+ db = cnat_main_db + head;
+ cnat_delete_main_db_entry_v2(db);
+ } while (!pool_is_free(cnat_user_db, udb));
+
+ rv = cnat_mapped_static_port_alloc_v2_bulk (pm,
+ PORT_ALLOC_ANY, &my_index, ko->k.k.ipv4, ko->k.k.port,
+ udb, BULKSIZE_FROM_VRFMAP(dslite_entry_ptr), &nfv9_log_req,
+ my_vrfmap->ip_n_to_1);
+
+ if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
+ info->error = rv;
+ nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++;
+ DSLITE_DEBUG_INSIDE_ERR(rv)
+ return (NULL);
+ }
+ /*
+ * create entry in user db
+ */
+ udb = dslite_user_db_create_entry(&u_ki, my_index);
+ nat44_dslite_common_stats[dslite_id].num_subscribers++;
+#ifndef NO_BULK_LOGGING
+ if(PREDICT_FALSE(udb && (BULK_ALLOC_NOT_ATTEMPTED != nfv9_log_req))) {
+ cnat_update_bulk_range_cache(udb, ko->k.k.port,
+ BULKSIZE_FROM_VRFMAP(dslite_entry_ptr));
+ }
+#endif /* #ifndef NO_BULK_LOGGING */
+ } else {
+
+ rv = cnat_mapped_static_port_alloc_v2_bulk (pm,
+ PORT_ALLOC_DIRECTED, &my_index, ko->k.k.ipv4, ko->k.k.port,
+ udb, BULKSIZE_FROM_VRFMAP(dslite_entry_ptr), &nfv9_log_req,
+ my_vrfmap->ip_n_to_1);
+
+ if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
+ info->error = rv;
+ DSLITE_DEBUG_INSIDE_ERR(rv)
+ log_port_alloc_error(rv, &(ki->dk.ipv4_key));
+ return (NULL);
+ }
+
+ /*
+ * increment port in use for this user
+ */
+ udb->ntranslations += 1;
+ }
+ } else {
+ if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) {
+ printf ("Static port alloc any\n");
+ }
+ /*
+ * first time allocate port for this user
+ */
+
+ /*
+ * Check if main db has space for new entry
+ * Allowing a user db entry to be created if main db is not free
+ * will cause a port to be allocated to that user, which results in
+ * wastage of that port, hence the check is done here.
+ */
+ h = pool_header(cnat_main_db);
+ free_main = vec_len(h->free_indices) - 1;
+ h = pool_header(cnat_user_db);
+ free_user = vec_len(h->free_indices) - 1;
+
+ /*
+ * If either main_db or user_db does not have entries
+ * bail out, with appropriate error
+ */
+ if (PREDICT_FALSE(!(free_main && free_user))) {
+ u32 log_error;
+ if(free_main) {
+ info->error = CNAT_USER_DB_LIMIT;
+ log_error = CNAT_USER_DB_LIMIT_ERROR;
+ } else {
+ info->error = CNAT_MAIN_DB_LIMIT;
+ log_error = CNAT_MAIN_DB_LIMIT_ERROR;
+ }
+ nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++;
+ DSLITE_DEBUG_INSIDE_ERR(info->error)
+ spp_printf(log_error, 0, 0);
+ return NULL;
+ }
+
+ rv = cnat_mapped_static_port_alloc_v2_bulk (pm,
+ PORT_ALLOC_ANY, &my_index, ko->k.k.ipv4, ko->k.k.port,
+ udb, BULKSIZE_FROM_VRFMAP(dslite_entry_ptr), &nfv9_log_req,
+ my_vrfmap->ip_n_to_1);
+
+ if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
+ info->error = rv;
+ nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++;
+ DSLITE_DEBUG_INSIDE_ERR(rv)
+ log_port_alloc_error(rv, &(ki->dk.ipv4_key));
+ return (NULL);
+ }
+ /*
+ * create entry in user db
+ */
+ udb = dslite_user_db_create_entry(&u_ki, my_index);
+ nat44_dslite_common_stats[dslite_id].num_subscribers++;
+#ifndef NO_BULK_LOGGING
+ if(PREDICT_FALSE(udb && (BULK_ALLOC_NOT_ATTEMPTED != nfv9_log_req))) {
+ cnat_update_bulk_range_cache(udb, ko->k.k.port,
+ BULKSIZE_FROM_VRFMAP(dslite_entry_ptr));
+ }
+#endif /* #ifndef NO_BULK_LOGGING */
+ }
+
+ /*
+ * step 3:
+ * outside port is allocated for this src vrf/src ip addr
+ * 1)create a new entry in main db
+ * 2)setup cnat_out2in_hash key
+ * 3)setup cnat_in2out_hash key
+ */
+ db = dslite_create_main_db_entry_and_hash(ki, ko, udb);
+ db->dslite_nat44_inst_id = dslite_id;
+ nat44_dslite_common_stats[dslite_id].active_translations++;
+ dslite_translation_create_count++;
+
+ /*
+ * don't forget logging
+ * logging API is unconditional,
+ * logging configuration check is done inside the inline function
+ */
+#if 0 /* TBD - NEED TO DECIDE ON LOGGING */
+ if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) {
+ /* if session logging is enabled .. do not log as there is no
+ * traffic yet
+ */
+#endif /* #if 0 - this has to be removed later */
+
+ return db;
+}
+#endif /* TOBE_PORTED */
+
+
+/* Per port/ip timeout related routines */
+static
+u32 cnat_timeout_db_hash_lookup (cnat_key_t t_key)
+{
+ cnat_key_t key;
+ u64 a, b, c;
+ u32 index;
+ cnat_timeout_db_entry_t *db;
+
+ key.k.ipv4 = t_key.k.ipv4;
+ key.k.port = t_key.k.port;
+ key.k.vrf = t_key.k.vrf;
+
+ CNAT_V4_GET_HASH(key.key64,
+ index, CNAT_TIMEOUT_HASH_MASK)
+
+
+ index = cnat_timeout_hash[index].next;
+
+ if (PREDICT_FALSE(index == EMPTY))
+ return EMPTY;
+
+ do {
+ db = cnat_timeout_db + index;
+ if (PREDICT_TRUE((db->t_key.timeout_key.key64 & CNAT_TIMEOUT_FULL_MASK)
+ == (key.key64 & CNAT_TIMEOUT_FULL_MASK)))
+ break;
+ index = db->t_hash.next;
+ } while (index != EMPTY);
+
+ return index;
+}
+
+/* Pass db_type as MAIN_DB_TYPE if you are passing
+ * cnat_main_db_entry_t * casted as void * for db
+ * else pass db_type as SESSION_DB_TYPE
+ */
+u16
+query_and_update_db_timeout(void *db, u8 db_type)
+{
+ cnat_key_t t_search_key;
+ u32 index;
+ cnat_timeout_db_entry_t *timeout_db_entry;
+ pool_header_t *h;
+ u32 free;
+
+ cnat_main_db_entry_t *mdb = NULL;
+ cnat_session_entry_t *sdb = NULL;
+
+ if(PREDICT_TRUE(db_type == MAIN_DB_TYPE)) {
+ mdb = (cnat_main_db_entry_t *)db;
+ } else if(db_type == SESSION_DB_TYPE) {
+ sdb = (cnat_session_entry_t *)db;
+ } else {
+ return 0;
+ }
+
+ h = pool_header(cnat_timeout_db);
+ free = vec_len(h->free_indices) - 1;
+
+ if(free == CNAT_TIMEOUT_HASH_SIZE) {
+ /* No timeout db configured */
+ return 0;
+ }
+
+ /* First search for ip/port pair */
+ if(PREDICT_TRUE(db_type == MAIN_DB_TYPE)) {
+ t_search_key.k.ipv4 = mdb->dst_ipv4;
+ t_search_key.k.port = mdb->dst_port;
+ t_search_key.k.vrf = mdb->in2out_key.k.vrf;
+ } else {
+ t_search_key.k.ipv4 = sdb->v4_dest_key.k.ipv4;
+ t_search_key.k.port = sdb->v4_dest_key.k.port;
+ t_search_key.k.vrf = sdb->v4_dest_key.k.vrf;
+ }
+
+ index = cnat_timeout_db_hash_lookup(t_search_key);
+
+ if(index == EMPTY) {
+ /* Search for port map */
+ t_search_key.k.ipv4 = 0;
+
+ index = cnat_timeout_db_hash_lookup(t_search_key);
+
+ if(index == EMPTY) {
+ /* Search for ip only map */
+ if(PREDICT_TRUE(db_type == MAIN_DB_TYPE)) {
+ t_search_key.k.ipv4 = mdb->dst_ipv4;
+ } else {
+ t_search_key.k.ipv4 = sdb->v4_dest_key.k.ipv4;
+ }
+ t_search_key.k.port = 0;
+
+ index = cnat_timeout_db_hash_lookup(t_search_key);
+ if(index != EMPTY) {
+#ifdef DEBUG_PRINTF_ENABLED
+ printf("%s: ip only map sucess\n","query_and_update_db_timeout");
+#endif
+ }
+ } else {
+#ifdef DEBUG_PRINTF_ENABLED
+ printf("%s: port only map sucess\n", "query_and_update_db_timeout");
+#endif
+ }
+
+ } else {
+#ifdef DEBUG_PRINTF_ENABLED
+ printf("%s: ip port map sucess\n","query_and_update_db_timeout");
+#endif
+
+ }
+
+ if(index == EMPTY) {
+ /* No match found, clear timeout */
+ if(PREDICT_TRUE(db_type == MAIN_DB_TYPE)) {
+ mdb->timeout = 0;
+ } else {
+ sdb->timeout = 0;
+ }
+#ifdef DEBUG_PRINTF_ENABLED
+ printf("%s: No match\n","query_and_update_db_timeout");
+#endif
+ } else {
+ /* Match found, update timeout */
+ timeout_db_entry = cnat_timeout_db + index;
+ if(PREDICT_TRUE(db_type == MAIN_DB_TYPE)) {
+ mdb->timeout = timeout_db_entry->t_key.timeout_value;
+ } else {
+ sdb->timeout = timeout_db_entry->t_key.timeout_value;
+ }
+ return timeout_db_entry->t_key.timeout_value;
+ }
+ return 0;
+}
+
+
+
+static
+void cnat_timeout_db_hash_add (cnat_timeout_db_entry_t *t_entry)
+{
+ cnat_key_t key;
+ u64 a, b, c;
+ u32 index, bucket;
+ cnat_key_t t_key = t_entry->t_key.timeout_key;
+
+ key.k.ipv4 = t_key.k.ipv4;
+ key.k.port = t_key.k.port;
+ key.k.vrf = t_key.k.vrf;
+
+ CNAT_V4_GET_HASH(key.key64,
+ bucket, CNAT_TIMEOUT_HASH_MASK)
+
+
+ index = cnat_timeout_hash[bucket].next;
+
+ /* Add this db entry to the head of the bucket chain */
+ t_entry->t_hash.next = index;
+ cnat_timeout_hash[bucket].next = t_entry - cnat_timeout_db;
+}
+
+
+
+u16
+cnat_timeout_db_create (cnat_timeout_t t_entry)
+{
+ cnat_timeout_db_entry_t *db;
+ cnat_key_t t_key = t_entry.timeout_key;
+ u32 db_index;
+
+ pool_header_t *h;
+ u32 free;
+
+ /* UNUSED. Therefore not ported to be multi-thread friendly */
+ ASSERT(0);
+
+ db_index = cnat_timeout_db_hash_lookup(t_key);
+
+ if(db_index != EMPTY) {
+ /* Entry already exists. Check if it is replay or update */
+ db = cnat_timeout_db + db_index;
+ db->t_key.timeout_value = t_entry.timeout_value;
+ return CNAT_SUCCESS;
+ }
+
+ h = pool_header(cnat_timeout_db);
+ free = vec_len(h->free_indices) - 1;
+
+ if(free == 0) {
+ return CNAT_OUT_LIMIT;
+ }
+
+
+ pool_get(cnat_timeout_db, db);
+ ASSERT(db);
+
+ memset(db, 0, sizeof(*db));
+
+ db_index = db - cnat_timeout_db;
+
+ db->t_key.timeout_key.k.ipv4 = t_key.k.ipv4;
+ db->t_key.timeout_key.k.port = t_key.k.port;
+ db->t_key.timeout_key.k.vrf = t_key.k.vrf;
+ db->t_key.timeout_value = t_entry.timeout_value;
+
+
+ cnat_timeout_db_hash_add(db);
+ return CNAT_SUCCESS;
+}
+
+void cnat_timeout_db_delete(cnat_key_t t_key)
+{
+ cnat_key_t key;
+ u64 a, b, c;
+ u32 index, bucket;
+ cnat_timeout_db_entry_t *this, *prev;
+
+ /* UNUSED. Therefore not ported to be multi-thread friendly */
+ ASSERT(0);
+
+ key.k.ipv4 = t_key.k.ipv4;
+ key.k.port = t_key.k.port;
+ key.k.vrf = t_key.k.vrf;
+
+
+ CNAT_V4_GET_HASH(key.key64,
+ bucket, CNAT_TIMEOUT_HASH_MASK)
+
+
+ index = cnat_timeout_hash[bucket].next;
+
+ if(index == EMPTY) return;
+
+ prev = 0;
+ do {
+ this = cnat_timeout_db + index;
+ if (PREDICT_TRUE(
+ (this->t_key.timeout_key.key64 & CNAT_TIMEOUT_FULL_MASK) ==
+ (key.key64 & CNAT_TIMEOUT_FULL_MASK))) {
+ if (prev == 0) {
+ cnat_timeout_hash[bucket].next = this->t_hash.next;
+ goto found;
+ } else {
+ prev->t_hash.next = this->t_hash.next;
+ goto found;
+ }
+ }
+
+ prev = this;
+ index = this->t_hash.next;
+ } while (index != EMPTY);
+
+ if(index == EMPTY) return;
+
+ found:
+ pool_put(cnat_timeout_db, this);
+
+}
+
+void cnat_session_db_hash_delete (cnat_session_entry_t *ep)
+{
+ u32 a, b, c;
+ u32 index, bucket;
+ cnat_session_entry_t *this, *prev;
+
+ CNAT_V4_GET_SESSION_HASH(ep->main_db_index, ep->v4_dest_key.k.ipv4,
+ ep->v4_dest_key.k.port, ep->v4_dest_key.k.vrf, bucket,
+ CNAT_SESSION_HASH_MASK)
+
+
+ index = cnat_session_hash[bucket].next;
+
+ ASSERT(index != EMPTY);
+
+ prev = 0;
+ do {
+ this = cnat_session_db + index;
+ if (PREDICT_TRUE(this == ep)) {
+ if (prev == 0) {
+ cnat_session_hash[bucket].next =
+ ep->cnat_session_hash.next;
+ return;
+ } else {
+ prev->cnat_session_hash.next =
+ ep->cnat_session_hash.next;
+ return;
+ }
+ }
+ prev = this;
+ index = this->cnat_session_hash.next;
+ } while (index != EMPTY);
+
+ ASSERT(0);
+
+}
+
+cnat_session_entry_t *
+cnat_session_db_edm_lookup_entry(cnat_key_t *ko,u32 session_head_index,
+ u32 main_db_index)
+{
+ u32 index;
+ cnat_session_entry_t *db;
+
+
+ index = session_head_index;
+ if (PREDICT_TRUE(index == EMPTY)) {
+ return (NULL);
+ }
+
+ do {
+ db = cnat_session_db + index;
+ if(PREDICT_TRUE((db->main_db_index == main_db_index) &&
+ (db->v4_dest_key.k.vrf == ko->k.vrf) &&
+ (db->v4_dest_key.k.ipv4 == ko->k.ipv4))) {
+
+ return db;
+ }
+ index = db->cnat_session_hash.next;
+ } while (index != EMPTY);
+
+ return (NULL);
+}
+
+
+
+cnat_session_entry_t *
+cnat_session_db_lookup_entry(cnat_key_t *ko,u32 main_db_index)
+{
+ u32 a, b, c;
+ u32 index, bucket;
+ cnat_session_entry_t *db;
+
+ CNAT_V4_GET_SESSION_HASH(main_db_index, ko->k.ipv4, ko->k.port,
+ ko->k.vrf, bucket, CNAT_SESSION_HASH_MASK)
+
+
+ index = cnat_session_hash[bucket].next;
+ if (PREDICT_TRUE(index == EMPTY)) {
+ return (NULL);
+ }
+
+ do {
+ db = cnat_session_db + index;
+ if(PREDICT_TRUE((db->main_db_index == main_db_index) &&
+ (db->v4_dest_key.k.vrf == ko->k.vrf) &&
+ (db->v4_dest_key.k.port == ko->k.port) &&
+ (db->v4_dest_key.k.ipv4 == ko->k.ipv4))) {
+
+ return db;
+ }
+ index = db->cnat_session_hash.next;
+ } while (index != EMPTY);
+
+ return (NULL);
+}
+
+cnat_session_entry_t *
+cnat_create_session_db_entry(cnat_key_t *ko,
+ cnat_main_db_entry_t *bdb, u8 log)
+{
+ u32 a, b, c;
+ u32 db_index, bucket_out;
+ cnat_session_entry_t *db = NULL;
+ pool_header_t *h;
+ u32 free_session;
+ u16 instance;
+
+ db = cnat_session_db_lookup_entry(ko, bdb - cnat_main_db);
+ if (PREDICT_FALSE(db != NULL)) {
+ /*printf("Create Session - Entry already Exists\n");*/
+ return db;
+ }
+
+ h = pool_header(cnat_session_db);
+ free_session = vec_len(h->free_indices) - 1;
+
+ if (bdb->flags & CNAT_DB_DSLITE_FLAG) {
+ instance = bdb->dslite_nat44_inst_id;
+ } else {
+ instance = NAT44_RESERVED_INST_ID;
+ }
+
+ if (PREDICT_FALSE(!free_session)) {
+ nat44_dslite_common_stats[instance].drops_sessiondb_limit_exceeded++;
+ return NULL;
+ }
+
+ if( PREDICT_FALSE(bdb->nsessions == CNAT_MAX_SESSIONS_PER_BIB)) {
+ /* printf("Create Session - Max sessions per BIB reached\n"); */
+ return NULL;
+ }
+
+ pthread_spin_lock(cnat_db_v2_main.session_db_lockp);
+ pool_get(cnat_session_db, db);
+ memset(db, 0, sizeof(*db));
+
+ db_index = db - cnat_session_db;
+ db->v4_dest_key.k.port = ko->k.port;
+ db->v4_dest_key.k.ipv4 = ko->k.ipv4;
+ db->v4_dest_key.k.vrf = ko->k.vrf;
+
+ db->main_list.next = db_index;
+ db->main_list.prev = db_index;
+ db->main_db_index = bdb - cnat_main_db;
+
+ db->tcp_seq_num = 0;
+ db->ack_no = 0;
+ db->window = 0;
+
+ if(PREDICT_FALSE(log)) {
+ bdb->nsessions++;
+ query_and_update_db_timeout(db, SESSION_DB_TYPE);
+ }
+
+ if (PREDICT_FALSE(bdb->nsessions == 1)) {
+ /*
+ * first port for this src vrf/src ip addr
+ */
+ bdb->session_head_index = db_index;
+ } else {
+ index_dlist_addtail(bdb->session_head_index,
+ (u8 *)cnat_session_db, sizeof(cnat_session_db[0]),
+ STRUCT_OFFSET_OF(cnat_session_entry_t, main_list),
+ db_index);
+ }
+
+ /*
+ * setup o2i hash key
+ */
+ CNAT_V4_GET_SESSION_HASH(db->main_db_index, ko->k.ipv4, ko->k.port,
+ ko->k.vrf, bucket_out, CNAT_SESSION_HASH_MASK)
+
+
+ db->cnat_session_hash.next =
+ cnat_session_hash[bucket_out].next;
+ cnat_session_hash[bucket_out].next = db_index;
+
+
+ if(PREDICT_FALSE(log)) {
+ if (bdb->flags & CNAT_DB_DSLITE_FLAG) {
+ cnat_session_log_ds_lite_mapping_create(bdb,
+ (dslite_table_db_ptr + instance),db);
+ } else {
+ cnat_vrfmap_t *my_vrfmap = cnat_map_by_vrf + bdb->vrfmap_index;
+ cnat_session_log_nat44_mapping_create(bdb, db, my_vrfmap);
+ }
+ }
+
+ /* Need to set entry_expires here, as we need to override 0 check for
+ newly established sessions */
+ db->entry_expires = cnat_current_time;
+ nat44_dslite_common_stats[instance].sessions++;
+ pthread_spin_unlock(cnat_db_v2_main.session_db_lockp);
+ return db;
+}
+
+void
+cnat_dest_update_main2session(cnat_main_db_entry_t *mdb,
+ cnat_session_entry_t *sdb)
+{
+
+ sdb->flags = mdb->flags;
+ sdb->timeout = mdb->timeout;
+ sdb->entry_expires = mdb->entry_expires;
+ sdb->alg.delta = mdb->alg.delta;
+ sdb->tcp_seq_num = mdb->proto_data.seq_pcp.tcp_seq_num;
+
+ /* Reset Main db values to 0 */
+ /* Reset only session specific flags */
+ mdb->flags &= ~(CNAT_DB_FLAG_TCP_ACTIVE | CNAT_DB_FLAG_UDP_ACTIVE
+ | CNAT_DB_FLAG_ALG_ENTRY | CNAT_DB_FLAG_ALG_CTRL_FLOW);
+ mdb->timeout = 0;
+ mdb->entry_expires = 0;
+ mdb->alg.delta = 0;
+ if(PREDICT_FALSE(!((mdb->flags & CNAT_DB_FLAG_PPTP_TUNNEL_ACTIVE) ||
+ (mdb->flags & CNAT_DB_FLAG_PPTP_TUNNEL_INIT)))) {
+ mdb->proto_data.seq_pcp.tcp_seq_num = 0;
+ }
+
+ mdb->dst_ipv4 = 0;
+ mdb->dst_port = 0;
+}
+
+
+void
+cnat_dest_update_session2main(cnat_main_db_entry_t *mdb,
+ cnat_session_entry_t *sdb)
+{
+
+ u16 flags = sdb->flags & (CNAT_DB_FLAG_TCP_ACTIVE |
+ CNAT_DB_FLAG_UDP_ACTIVE | CNAT_DB_FLAG_ALG_ENTRY |
+ CNAT_DB_FLAG_ALG_CTRL_FLOW);
+ mdb->flags |= flags;
+ mdb->timeout = sdb->timeout;
+ mdb->entry_expires = sdb->entry_expires;
+ mdb->alg.delta = sdb->alg.delta;
+ if(PREDICT_FALSE(!((mdb->flags & CNAT_DB_FLAG_PPTP_TUNNEL_ACTIVE) ||
+ (mdb->flags & CNAT_DB_FLAG_PPTP_TUNNEL_INIT)))) {
+ mdb->proto_data.seq_pcp.tcp_seq_num = sdb->tcp_seq_num;
+ }
+ mdb->dst_ipv4 = sdb->v4_dest_key.k.ipv4;
+ mdb->dst_port = sdb->v4_dest_key.k.port;
+}
+
+static void
+_cnat_delete_session_db_entry (cnat_session_entry_t *ep, u8 log)
+{
+ u32 session_db_index;
+ u32 bdb_len;
+ cnat_main_db_entry_t *be =0;
+ cnat_session_entry_t *sdb_last = NULL;
+ u16 instance;
+
+ if (PREDICT_FALSE(ep->flags & CNAT_DB_NAT64_FLAG) != 0) {
+ /* Preventive check - Not a NAT44 entry */
+ return;
+ }
+
+ pool_header_t *h = pool_header(cnat_main_db);
+
+ /* Validate .. just in case we are trying to delete a non existing one */
+ bdb_len = vec_len(cnat_main_db);
+
+ /* In case of invalid user just return, deleting only main db
+ * is not a good idea, since some valid user db entry might be pointing
+ * to that main db and hence leave the dbs in a inconsistent state
+ */
+ if (PREDICT_FALSE((ep->main_db_index >= bdb_len) ||
+ (clib_bitmap_get(h->free_bitmap, ep->main_db_index)))) {
+#ifdef DEBUG_PRINTF_ENABLED
+ printf("invalid/unused user index in db %d\n", ep->main_db_index);
+#endif
+ spp_printf(CNAT_INV_UNUSED_USR_INDEX, 1, (u32 *) &(ep->main_db_index));
+ return;
+ }
+
+ be = cnat_main_db + ep->main_db_index;
+
+ session_db_index = ep - cnat_session_db;
+
+ be->session_head_index = index_dlist_remelem (
+ be->session_head_index, (u8 *)cnat_session_db,
+ sizeof (cnat_session_db[0]),
+ STRUCT_OFFSET_OF(cnat_session_entry_t, main_list),
+ session_db_index);
+
+ if (be->flags & CNAT_DB_DSLITE_FLAG) {
+ instance = be->dslite_nat44_inst_id;
+ } else {
+ instance = NAT44_RESERVED_INST_ID;
+ }
+
+ if(PREDICT_TRUE(log)) {
+ if (be->flags & CNAT_DB_DSLITE_FLAG) {
+ cnat_session_log_ds_lite_mapping_delete(be,
+ (dslite_table_db_ptr + instance),ep);
+ } else {
+ cnat_vrfmap_t *my_vrfmap = cnat_map_by_vrf + be->vrfmap_index;
+ cnat_session_log_nat44_mapping_delete(be, ep, my_vrfmap);
+ }
+ be->nsessions--;
+ }
+
+ if (PREDICT_FALSE(be->nsessions == 1 && log)) {
+ /* There is only 1 session left
+ * Copy the info back to main db and release the last
+ * existing session
+ */
+
+ sdb_last = cnat_session_db + be->session_head_index;
+ ASSERT(sdb_last != NULL);
+
+ cnat_dest_update_session2main(be, sdb_last);
+ _cnat_delete_session_db_entry(sdb_last, FALSE);
+ }
+
+ /* Remove from session DB hashes */
+ cnat_session_db_hash_delete(ep);
+ nat44_dslite_common_stats[instance].sessions--;
+
+ pool_put(cnat_session_db, ep);
+}
+
+void cnat_delete_session_db_entry (cnat_session_entry_t *ep, u8 log)
+{
+ pthread_spin_lock(cnat_db_v2_main.session_db_lockp);
+ _cnat_delete_session_db_entry (ep, log);
+ pthread_spin_unlock(cnat_db_v2_main.session_db_lockp);
+}
+
+cnat_main_db_entry_t*
+dslite_main_db_lookup_entry(dslite_db_key_bucket_t *ki)
+{
+ u64 a, b, c;
+ u32 index;
+ cnat_main_db_entry_t *db;
+ cnat_user_db_entry_t *userdb;
+
+ DSLITE_V6_GET_HASH((&(ki->dk)),
+ ki->bucket,
+ CNAT_MAIN_HASH_MASK);
+
+ DSLITE_PRINTF(1,"MDBLU hash..%u\n", ki->bucket);
+
+ index = cnat_in2out_hash[ki->bucket].next;
+ if (PREDICT_TRUE(index == EMPTY)) {
+ DSLITE_PRINTF(1,"MDBLU index MT..\n");
+ return (NULL);
+ }
+
+ do {
+/* We can add a flag here to indicate if the db entry is for nat44 or
+ * dslite. If the db entry is for nat44 then we can simply move to the
+ * one.
+ */
+ db = cnat_main_db + index;
+ userdb = cnat_user_db + db->user_index;
+ if (PREDICT_TRUE(db->in2out_key.key64 == ki->dk.ipv4_key.key64)
+ && userdb->ipv6[0] == ki->dk.ipv6[0]
+ && userdb->ipv6[1] == ki->dk.ipv6[1]
+ && userdb->ipv6[2] == ki->dk.ipv6[2]
+ && userdb->ipv6[3] == ki->dk.ipv6[3]) {
+ DSLITE_PRINTF(1,"MDBLU success..%u\n", index);
+ return db;
+ }
+ index = db->in2out_hash.next;
+ } while (index != EMPTY);
+
+ DSLITE_PRINTF(1,"MDBLU Entry does not exist..\n");
+ return (NULL);
+}
+
+cnat_user_db_entry_t*
+dslite_user_db_lookup_entry(dslite_db_key_bucket_t *uki)
+{
+ u64 a, b, c;
+ u32 index;
+ cnat_user_db_entry_t *udb=NULL;
+
+ DSLITE_V6_GET_HASH((&(uki->dk)),
+ uki->bucket,
+ CNAT_USER_HASH_MASK)
+
+ DSLITE_PRINTF(1,"UDBLU hash..%u\n", uki->bucket);
+
+ /* now: index in user vector */
+ index = cnat_user_hash[uki->bucket].next;
+ if (PREDICT_TRUE(index != EMPTY)) {
+ DSLITE_PRINTF(1,"UDBLU hash table entry not MT..\n");
+ do {
+ udb = cnat_user_db + index;
+ if (PREDICT_FALSE(udb->key.key64 == uki->dk.ipv4_key.key64)
+ && udb->ipv6[0] == uki->dk.ipv6[0]
+ && udb->ipv6[1] == uki->dk.ipv6[1]
+ && udb->ipv6[2] == uki->dk.ipv6[2]
+ && udb->ipv6[3] == uki->dk.ipv6[3]) {
+ DSLITE_PRINTF(1,"UDBLU success..%u\n", index);
+ return udb;
+ }
+ index = udb->user_hash.next;
+ } while (index != EMPTY);
+ }
+ DSLITE_PRINTF(1,"UDBLU Entry doesnt exist..\n");
+ return (NULL);
+}
+
+cnat_user_db_entry_t*
+dslite_user_db_create_entry(dslite_db_key_bucket_t *uki,
+ u32 portmap_index)
+{
+ cnat_user_db_entry_t *udb = NULL;
+
+ /* UNUSED. Therefore not ported to be multi-thread friendly */
+ ASSERT(0);
+
+ pool_get(cnat_user_db, udb);
+ memset(udb, 0, sizeof(*udb));
+
+ udb->ntranslations = 1;
+ udb->portmap_index = portmap_index;
+// udb->key.key64 = uki->k.key64;
+
+ udb->key.key64 = uki->dk.ipv4_key.key64;
+ udb->ipv6[0] = uki->dk.ipv6[0];
+ udb->ipv6[1] = uki->dk.ipv6[1];
+ udb->ipv6[2] = uki->dk.ipv6[2];
+ udb->ipv6[3] = uki->dk.ipv6[3];
+
+ udb->flags |= CNAT_USER_DB_DSLITE_FLAG;
+ /* Add this user to the head of the bucket chain */
+ udb->user_hash.next =
+ cnat_user_hash[uki->bucket].next;
+ cnat_user_hash[uki->bucket].next = udb - cnat_user_db;
+
+#ifndef NO_BULK_LOGGING
+ INIT_BULK_CACHE(udb)
+#endif /* NO_BULK_LOGGING */
+
+ return udb;
+}
+
+#ifndef TOBE_PORTED
+cnat_main_db_entry_t*
+dslite_create_main_db_entry_and_hash(dslite_db_key_bucket_t *ki,
+ cnat_db_key_bucket_t *ko,
+ cnat_user_db_entry_t *udb)
+{
+ return 0;
+}
+#else
+cnat_main_db_entry_t*
+dslite_create_main_db_entry_and_hash(dslite_db_key_bucket_t *ki,
+ cnat_db_key_bucket_t *ko,
+ cnat_user_db_entry_t *udb)
+{
+ u64 a, b, c;
+ u32 db_index;
+ cnat_main_db_entry_t *db = NULL;
+
+ /* UNUSED. Therefore not ported to be multi-thread friendly */
+ ASSERT(0);
+
+ pool_get(cnat_main_db, db);
+ memset(db, 0, sizeof(*db));
+
+ db_index = db - cnat_main_db;
+ db->in2out_key.k.ipv4 = ki->dk.ipv4_key.k.ipv4;
+ db->in2out_key.k.port = ki->dk.ipv4_key.k.port;
+ db->in2out_key.k.vrf = ki->dk.ipv4_key.k.vrf;
+ db->out2in_key.k.ipv4 = ko->k.k.ipv4;
+ db->out2in_key.k.port = ko->k.k.port;
+ db->out2in_key.k.vrf = ko->k.k.vrf;
+
+ db->user_ports.next = db_index;
+ db->user_ports.prev = db_index;
+ db->user_index = udb - cnat_user_db;
+ //db->portmap_index = udb->portmap_index;
+ db->flags |= CNAT_DB_DSLITE_FLAG;
+
+ if (PREDICT_FALSE(udb->ntranslations == 1)) {
+ /*
+ * first port for this src vrf/src ip addr
+ */
+ udb->translation_list_head_index = db_index;
+ DSLITE_PRINTF(1,"First translation of this user..\n");
+ } else {
+ index_dlist_addtail(udb->translation_list_head_index,
+ (u8 *)cnat_main_db, sizeof(cnat_main_db[0]),
+ STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports),
+ db_index);
+ }
+
+ /*
+ * setup o2i hash key
+ */
+ CNAT_V4_GET_HASH(ko->k.key64,
+ ko->bucket,
+ CNAT_MAIN_HASH_MASK)
+ db->out2in_hash.next = cnat_out2in_hash[ko->bucket].next;
+ cnat_out2in_hash[ko->bucket].next = db_index;
+ /*
+ * setup i2o hash key, bucket is already calculate
+ */
+ db->in2out_hash.next = cnat_in2out_hash[ki->bucket].next;
+ cnat_in2out_hash[ki->bucket].next = db_index;
+
+ DSLITE_PRINTF(1,"Create main db and hash..%u %u %u %u %x\n",
+ ki->bucket, ko->bucket,
+ db_index, db->user_index, ko->k.key64);
+
+#if DEBUG > 1
+ printf("\nMy_Instance_Number %d: Bucket %d, Db_Index %d",
+ my_instance_number, ki->bucket, db_index);
+ printf("\nInside (VRF 0x%x, IP 0x%x, PORT 0x%x)",
+ db->in2out_key.k.vrf, db->in2out_key.k.ipv4, db->in2out_key.k.port);
+ printf("\nOutside (VRF 0x%x, IP 0x%x, PORT 0x%x)",
+ db->out2in_key.k.vrf, db->out2in_key.k.ipv4, db->out2in_key.k.port);
+ printf("\nUser Index %d, IP 0x%x",
+ db->user_index, udb->key.k.ipv4);
+#endif
+
+ //nat44_dslite_common_stats[DSLITE_COMMON_STATS].active_translations++;
+
+ return db;
+}
+
+static inline void handle_dslite_port_exceeded_logging(
+ cnat_user_db_entry_t *udb,
+ dslite_key_t * key,
+ dslite_table_entry_t *dslite_entry_ptr)
+{
+
+ if(PREDICT_TRUE(udb->flags & CNAT_USER_DB_PORT_LIMIT_EXCEEDED)) {
+ /* Already logged ..*/
+ return;
+ }
+
+ /* else, set the flag and call the log API */
+ udb->flags = udb->flags | CNAT_USER_DB_PORT_LIMIT_EXCEEDED;
+ cnat_log_ds_lite_port_limit_exceeded(key, dslite_entry_ptr);
+ return;
+}
+#endif
+
+void handle_cnat_port_exceeded_logging(
+ cnat_user_db_entry_t *udb,
+ cnat_key_t * key,
+ cnat_vrfmap_t *vrfmap)
+{
+
+ if(PREDICT_TRUE(udb->flags & CNAT_USER_DB_PORT_LIMIT_EXCEEDED)) {
+ /* Already logged ..*/
+ return;
+ }
+
+ /* else, set the flag and call the log API */
+ udb->flags = udb->flags | CNAT_USER_DB_PORT_LIMIT_EXCEEDED;
+ cnat_log_nat44_port_limit_exceeded(key,vrfmap);
+ return;
+}
+
+#ifndef TOBE_PORTED
+cnat_main_db_entry_t*
+dslite_get_main_db_entry_v2(dslite_db_key_bucket_t *ki,
+ port_pair_t port_pair_type,
+ port_type_t port_type,
+ cnat_gen_icmp_info *info,
+ dslite_table_entry_t *dslite_entry_ptr,
+ cnat_key_t *dest_info)
+{
+ return 0;
+}
+#else
+/*
+ * this function is called by exception node
+ * when lookup is fialed in i2o node
+ *
+ * if reash per user port limit,
+ * set user_db_entry pointer, and error == CNAT_OUT_LIMIT
+ */
+cnat_main_db_entry_t*
+dslite_get_main_db_entry_v2(dslite_db_key_bucket_t *ki,
+ port_pair_t port_pair_type,
+ port_type_t port_type,
+ cnat_gen_icmp_info *info,
+ dslite_table_entry_t *dslite_entry_ptr,
+ cnat_key_t *dest_info)
+{
+ u16 protocol;
+ cnat_errno_t rv;
+ dslite_db_key_bucket_t u_ki;
+ cnat_db_key_bucket_t ko;
+ u32 my_index, free_main, free_user;
+ u32 current_timestamp;
+ cnat_vrfmap_t *my_vrfmap =0;
+ u16 my_vrfmap_index;
+ cnat_portmap_v2_t *pm =0;
+ cnat_user_db_entry_t *udb = 0;
+ cnat_main_db_entry_t *db = 0;
+ pool_header_t *h;
+ u16 dslite_id = dslite_entry_ptr->dslite_id;
+
+#ifndef NO_BULK_LOGGING
+ int nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
+#endif
+
+ /* UNUSED. Therefore not ported to be multi-thread friendly */
+ ASSERT(0);
+
+ /*
+ * need to try lookup again because
+ * second pkt may come here before the entry is created
+ * by receiving first pkt due to high line rate.
+ */
+ info->gen_icmp_msg = CNAT_NO_ICMP_MSG;
+ info->error = CNAT_SUCCESS;
+ db = dslite_main_db_lookup_entry(ki);
+ if (PREDICT_TRUE(db)) {
+ /* what if the source is talking to a
+ * new dest now? We will have to handle this case and
+ * take care of - creating session db and logging
+ */
+ if(PREDICT_FALSE((!dest_info->k.ipv4) && (!dest_info->k.port))) {
+ return db; /* if dest_info is null don't create session */
+ }
+
+ if(PREDICT_TRUE((db->dst_ipv4 == dest_info->k.ipv4) &&
+ (db->dst_port == dest_info->k.port))) {
+ return db;
+ }
+ dest_info->k.vrf = db->in2out_key.k.vrf;
+ /* Src is indeed talking to a different dest */
+ cnat_session_entry_t *session_db2 = NULL;
+ if(PREDICT_TRUE(db->nsessions == 1)) {
+ session_db2 = cnat_handle_1to2_session(db, dest_info);
+ if(PREDICT_TRUE(session_db2 != NULL)) {
+ CNAT_DB_TIMEOUT_RST(session_db2);
+ return db;
+ } else {
+ info->error = CNAT_ERR_NO_SESSION_DB;
+ return NULL;
+ }
+ } else if(PREDICT_FALSE(db->nsessions == 0)) {
+ /* Should be static entry.. should never happen
+ */
+ if(PREDICT_TRUE(dest_info->k.ipv4 != 0)) {
+ cnat_add_dest_n_log(db, dest_info);
+ }
+ return db;
+ } else {
+ /* The src has already created multiple sessions.. very rare
+ */
+ session_db2 = cnat_create_session_db_entry(dest_info,
+ db, TRUE);
+ if(PREDICT_TRUE(session_db2 != NULL)) {
+ CNAT_DB_TIMEOUT_RST(session_db2);
+ return db;
+ } else {
+ info->error = CNAT_ERR_NO_SESSION_DB;
+ return NULL;
+ }
+ }
+
+ }
+
+ /*
+ * step 1. check if outside vrf is configured or not
+ * and Find the set of portmaps for the outside vrf
+ * insider vrf is one to one mappted to outside vrf
+ * key is vrf and ip only
+ * ki.k.k.vrf has protocol bits, mask out
+ */
+ protocol = ki->dk.ipv4_key.k.vrf & CNAT_PRO_MASK;
+ u_ki.dk.ipv4_key.k.vrf = ki->dk.ipv4_key.k.vrf & CNAT_VRF_MASK;
+#ifdef DSLITE_USER_IPV4
+ u_ki.dk.ipv4_key.k.ipv4 = ki->dk.ipv4_key.k.ipv4;
+#else
+ /*
+ * Inside ipv4 address should be masked, if port limit
+ * need to be done at B4 element level.
+ */
+ u_ki.dk.ipv4_key.k.ipv4 = 0;
+#endif
+ u_ki.dk.ipv4_key.k.port = 0;
+
+ u_ki.dk.ipv6[0] = ki->dk.ipv6[0];
+ u_ki.dk.ipv6[1] = ki->dk.ipv6[1];
+ u_ki.dk.ipv6[2] = ki->dk.ipv6[2];
+ u_ki.dk.ipv6[3] = ki->dk.ipv6[3];
+
+ my_vrfmap_index = vrf_map_array[u_ki.dk.ipv4_key.k.vrf];
+ my_vrfmap = cnat_map_by_vrf + my_vrfmap_index;
+/* Checking if the inst entry is active or not is done much earlier
+ */
+#if 0
+ my_vrfmap_index = vrf_map_array[u_ki.k.k.vrf];
+ my_vrfmap = cnat_map_by_vrf + my_vrfmap_index;
+ my_vrfmap_entry_found = ((my_vrfmap_index != VRF_MAP_ENTRY_EMPTY) &&
+ (my_vrfmap->status == S_RUN) &&
+ (my_vrfmap->i_vrf == u_ki.k.k.vrf));
+
+ if (PREDICT_FALSE(!my_vrfmap_entry_found)) {
+ u32 arr[] = {ki->k.k.vrf, ki->k.k.ipv4, ki->k.k.port};
+ if ((my_vrfmap_index == VRF_MAP_ENTRY_EMPTY) ||
+ (my_vrfmap->i_vrf == u_ki.k.k.vrf)) {
+ info->error = CNAT_NO_CONFIG;
+ CNAT_DEBUG_INSIDE_ERR(CNAT_NO_CONFIG)
+ spp_printf(CNAT_NO_CONFIG_ERROR, 3, arr);
+ } else {
+ info->error = CNAT_NO_VRF_RUN;
+ CNAT_DEBUG_INSIDE_ERR(CNAT_NO_VRF_RUN)
+ spp_printf(CNAT_NO_VRF_RUN_ERROR, 3, arr);
+ }
+
+ return (NULL);
+ }
+#endif
+/*
+ dslite_inst_ptr = dslite_nat44_config_table[dslite_inst_id];
+*/
+ pm = dslite_entry_ptr->portmap_list;
+ //pm = my_vrfmap->portmap_list;
+
+ /*
+ * set o2i key with protocl bits
+ */
+ ko.k.k.vrf = dslite_entry_ptr->o_vrf | protocol;
+ //ko.k.k.vrf = my_vrfmap->o_vrf | protocol;
+
+ /*
+ * step 2. check if src vrf, src ip addr is alreay
+ * in the user db
+ * if yes, use PORT_ALLOC_DIRECTED
+ * if no, use PORT_ALLOC_ANY since it is first time
+ */
+ udb = dslite_user_db_lookup_entry(&u_ki);
+ if (PREDICT_TRUE(udb)) {
+ /*
+ * not first time allocate port for this user
+ * check limit
+ */
+ if (PREDICT_FALSE(udb->ntranslations >=
+ dslite_entry_ptr->cnat_main_db_max_ports_per_user)) {
+ //cnat_main_db_max_ports_per_user))
+
+ /* Check for the port type here. If we are getting
+ * a STATIC PORT, allow the config.
+ */
+ if (PREDICT_TRUE(port_type != PORT_TYPE_STATIC)) {
+ info->error = CNAT_OUT_LIMIT;
+ DSLITE_DEBUG_INSIDE_ERR(CNAT_OUT_LIMIT)
+ port_exceeded_msg_log(u_ki.dk.ipv4_key.k.ipv4, u_ki.dk.ipv4_key.k.vrf);
+ nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++;
+ u_ki.dk.ipv4_key.k.vrf = ki->dk.ipv4_key.k.vrf;
+ u_ki.dk.ipv4_key.k.port = ki->dk.ipv4_key.k.port;
+ handle_dslite_port_exceeded_logging(udb, &u_ki.dk, dslite_entry_ptr);
+ return (NULL);
+ }
+ }
+
+ CHECK_CLEAR_PORT_LIMIT_EXCEED_FLAG(udb,
+ dslite_entry_ptr->cnat_main_db_max_ports_per_user)
+
+ /*
+ * check if main db has space to accomodate new entry
+ */
+ h = pool_header(cnat_main_db);
+
+ free_main = vec_len(h->free_indices) - 1;
+ if (PREDICT_FALSE(!free_main)) {
+ info->error = CNAT_MAIN_DB_LIMIT;
+ nat44_dslite_common_stats[dslite_id].in2out_drops_system_limit_reached ++;
+ DSLITE_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT)
+
+ current_timestamp = spp_trace_log_get_unix_time_in_seconds();
+ if (PREDICT_FALSE((current_timestamp - last_log_timestamp) >
+ 1800)) {
+ spp_printf(CNAT_SESSION_THRESH_EXCEEDED, 0, NULL);
+ last_log_timestamp = current_timestamp;
+ }
+
+#ifdef UT_TEST_CODE
+ printf("Limit reached : OLD USER");
+#endif
+ return NULL;
+ }
+
+ /*
+ * allocate port, from existing mapping
+ */
+ my_index = udb->portmap_index;
+
+ if (PREDICT_FALSE(port_type == PORT_TYPE_STATIC)) {
+ rv = cnat_static_port_alloc_v2_bulk(pm,
+ PORT_ALLOC_DIRECTED,
+ port_pair_type,
+ ki->dk.ipv4_key.k.ipv4,
+ ki->dk.ipv4_key.k.port,
+ &my_index,
+ &(ko.k.k.ipv4),
+ &(ko.k.k.port),
+ STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr)
+#ifndef NO_BULK_LOGGING
+ , udb,
+ BULKSIZE_FROM_VRFMAP(dslite_entry_ptr),
+ &nfv9_log_req
+#endif
+ , my_vrfmap->ip_n_to_1
+ );
+ } else if (PREDICT_TRUE(port_type != PORT_TYPE_RTSP) ) {
+
+ rv = cnat_dynamic_port_alloc_v2_bulk(pm,
+ PORT_ALLOC_DIRECTED,
+ port_pair_type,
+ &my_index,
+ &(ko.k.k.ipv4),
+ &(ko.k.k.port),
+ STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr)
+#ifndef NO_BULK_LOGGING
+ , udb,
+ BULKSIZE_FROM_VRFMAP(dslite_entry_ptr),
+ &nfv9_log_req
+#endif
+ , 0,
+ &(dslite_entry_ptr->rseed_ip)
+ );
+ DSLITE_PRINTF(1,"D_PORT_ALLOC %x %u\n", ko.k.k.ipv4, ko.k.k.port);
+ } else {
+ /*
+ * For RTSP, two translation entries are created,
+ * check if main db has space to accomodate two new entry
+ */
+ free_main = free_main - 1;
+
+ if (PREDICT_FALSE(!free_main)) {
+ info->error = CNAT_MAIN_DB_LIMIT;
+ nat44_dslite_common_stats[dslite_id].in2out_drops_system_limit_reached ++;
+ DSLITE_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT)
+
+ return NULL;
+ } else {
+
+ rv = cnat_dynamic_port_alloc_rtsp_bulk(pm,
+ PORT_ALLOC_DIRECTED,
+ port_pair_type,
+ ki->dk.ipv4_key.k.port,
+ &my_index,
+ &(ko.k.k.ipv4),
+ &(ko.k.k.port),
+ STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr)
+#ifndef NO_BULK_LOGGING
+ , udb,
+ BULKSIZE_FROM_VRFMAP(dslite_entry_ptr),
+ &nfv9_log_req
+#endif
+ , &(dslite_entry_ptr->rseed_ip)
+ );
+ }
+ }
+
+ if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
+ DSLITE_PRINTF(1,"D_PORT_ALLOC port alloc error\n");
+ info->error = rv;
+ DSLITE_DEBUG_INSIDE_ERR(rv)
+ nat44_dslite_common_stats[dslite_id].in2out_drops_resource_depletion ++;
+ log_port_alloc_error(rv, &(ki->dk.ipv4_key));
+ return (NULL);
+ }
+ /*
+ * increment port in use for this user
+ */
+ udb->ntranslations += 1;
+ } else {
+ /*
+ * first time allocate port for this user
+ */
+
+ /*
+ * Do not create entry if port limit is invalid
+ */
+ if (PREDICT_FALSE(!(dslite_entry_ptr->cnat_main_db_max_ports_per_user))) {
+ if (PREDICT_TRUE(port_type != PORT_TYPE_STATIC)) {
+ info->error = CNAT_OUT_LIMIT;
+ nat44_dslite_common_stats[dslite_id].in2out_drops_port_limit_exceeded ++;
+ port_exceeded_msg_log(u_ki.dk.ipv4_key.k.ipv4, u_ki.dk.ipv4_key.k.vrf);
+ DSLITE_DEBUG_INSIDE_ERR(CNAT_OUT_LIMIT)
+ return (NULL);
+ }
+ }
+
+ /*
+ * Check if main db has space for new entry
+ * Allowing a user db entry to be created if main db is not free
+ * will cause a port to be allocated to that user, which results in
+ * wastage of that port, hence the check is done here.
+ */
+ h = pool_header(cnat_main_db);
+ free_main = vec_len(h->free_indices) - 1;
+
+ h = pool_header(cnat_user_db);
+ free_user = vec_len(h->free_indices) - 1;
+
+ /*
+ * If either main_db or user_db does not have entries
+ * bail out, with appropriate error
+ */
+ if (PREDICT_FALSE(!(free_main && free_user))) {
+ u32 log_error;
+ if(free_main) {
+ info->error = CNAT_USER_DB_LIMIT;
+ log_error = CNAT_USER_DB_LIMIT_ERROR;
+ } else {
+ info->error = CNAT_MAIN_DB_LIMIT;
+ log_error = CNAT_MAIN_DB_LIMIT_ERROR;
+ }
+ nat44_dslite_common_stats[dslite_id].in2out_drops_system_limit_reached ++;
+ DSLITE_DEBUG_INSIDE_ERR(info->error)
+ spp_printf(log_error, 0, 0);
+ return NULL;
+ }
+
+ if (PREDICT_FALSE(port_type == PORT_TYPE_STATIC)) {
+ rv = cnat_static_port_alloc_v2_bulk(pm,
+ PORT_ALLOC_ANY,
+ port_pair_type,
+ ki->dk.ipv4_key.k.ipv4,
+ ki->dk.ipv4_key.k.port,
+ &my_index,
+ &(ko.k.k.ipv4),
+ &(ko.k.k.port),
+ STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr)
+#ifndef NO_BULK_LOGGING
+ , NULL,
+ BULKSIZE_FROM_VRFMAP(dslite_entry_ptr),
+ &nfv9_log_req
+#endif
+ , my_vrfmap->ip_n_to_1
+
+ );
+ } else if (PREDICT_TRUE(port_type != PORT_TYPE_RTSP)) {
+ rv = cnat_dynamic_port_alloc_v2_bulk(pm,
+ PORT_ALLOC_ANY,
+ port_pair_type,
+ &my_index,
+ &(ko.k.k.ipv4),
+ &(ko.k.k.port),
+ STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr)
+#ifndef NO_BULK_LOGGING
+ , NULL,
+ BULKSIZE_FROM_VRFMAP(dslite_entry_ptr),
+ &nfv9_log_req
+#endif
+ , 0,
+ &(dslite_entry_ptr->rseed_ip)
+ );
+ DSLITE_PRINTF(1,"NU:D PORT ALLOC..%x %u\n", ko.k.k.ipv4,
+ ko.k.k.port);
+
+ } else {
+ /*
+ * For RTSP, two translation entries are created,
+ * check if main db has space to accomodate two new entry
+ */
+ free_main = free_main - 1;
+
+ if (PREDICT_FALSE(!free_main)) {
+ info->error = CNAT_MAIN_DB_LIMIT;
+ nat44_dslite_common_stats[dslite_id].in2out_drops_system_limit_reached ++;
+ DSLITE_DEBUG_INSIDE_ERR(CNAT_MAIN_DB_LIMIT)
+
+ return NULL;
+ } else {
+
+ rv = cnat_dynamic_port_alloc_rtsp_bulk(pm,
+ PORT_ALLOC_DIRECTED,
+ port_pair_type,
+ ki->dk.ipv4_key.k.port,
+ &my_index,
+ &(ko.k.k.ipv4),
+ &(ko.k.k.port),
+ STAT_PORT_RANGE_FROM_INST_PTR(dslite_entry_ptr)
+#ifndef NO_BULK_LOGGING
+ , NULL,
+ BULKSIZE_FROM_VRFMAP(dslite_entry_ptr),
+ &nfv9_log_req
+#endif
+ , &(dslite_entry_ptr->rseed_ip)
+ );
+ /* TODO: Add the port pair flag here */
+ }
+ }
+
+
+
+ if (PREDICT_FALSE(rv != CNAT_SUCCESS)) {
+ DSLITE_PRINTF(1,"NU:D_PORT_ALLOC port alloc error\n");
+ info->error = rv;
+ nat44_dslite_common_stats[dslite_id].in2out_drops_resource_depletion ++;
+ DSLITE_DEBUG_INSIDE_ERR(rv)
+ log_port_alloc_error(rv, &(ki->dk.ipv4_key));
+ return (NULL);
+ }
+ /*
+ * create entry in user db
+ */
+ udb = dslite_user_db_create_entry(&u_ki, my_index);
+ nat44_dslite_common_stats[dslite_id].num_subscribers++;
+ DSLITE_PRINTF(1,"UDB crete entry done..\n");
+#ifndef NO_BULK_LOGGING
+ if(PREDICT_TRUE(udb && (BULK_ALLOC_NOT_ATTEMPTED != nfv9_log_req))) {
+ cnat_update_bulk_range_cache(udb, ko.k.k.port,
+ BULKSIZE_FROM_VRFMAP(dslite_entry_ptr));
+ }
+#endif /* #ifndef NO_BULK_LOGGING */
+ }
+
+ /*
+ * step 3:
+ * outside port is allocated for this src vrf/src ip addr
+ * 1)create a new entry in main db
+ * 2)setup cnat_out2in_hash key
+ * 3)setup cnat_in2out_hash key
+ */
+ db = dslite_create_main_db_entry_and_hash(ki, &ko, udb);
+ DSLITE_PRINTF(1,"dslite_create_main_db_entry_and_hash done..\n");
+ //db->vrfmap_index = my_vrfmap - cnat_map_by_vrf;
+ db->dslite_nat44_inst_id = dslite_id;
+ nat44_dslite_common_stats[dslite_id].active_translations++;
+ if (PREDICT_FALSE(port_type == PORT_TYPE_STATIC)) {
+ nat44_dslite_common_stats[dslite_id].num_static_translations++;
+ } else {
+ nat44_dslite_common_stats[dslite_id].num_dynamic_translations++;
+ }
+
+ dslite_translation_create_count++;
+
+ db->dst_ipv4 = dest_info->k.ipv4;
+ db->dst_port = dest_info->k.port;
+ if(PREDICT_TRUE(db->dst_ipv4 || db->dst_port)) {
+ /* for static fwding, let the nsessions remain zero */
+ db->nsessions++;
+ }
+
+ /*
+ * don't forget logging
+ * logging API is unconditional,
+ * logging configuration check is done inside the inline function
+ */
+ if(PREDICT_FALSE(nfv9_log_req != CACHE_ALLOC_NO_LOG_REQUIRED)) {
+ if(PREDICT_FALSE( dslite_entry_ptr->nf_logging_policy ==
+ SESSION_LOG_ENABLE)) {
+ if(PREDICT_TRUE(db->dst_ipv4 || db->dst_port)) {
+ cnat_nfv9_ds_lite_log_session_create(db,
+ dslite_entry_ptr,NULL);
+ }
+ } else {
+ cnat_nfv9_ds_lite_mapping_create(db,dslite_entry_ptr
+#ifndef NO_BULK_LOGGING
+ ,nfv9_log_req
+#endif
+ );
+ }
+ if(PREDICT_TRUE((dslite_entry_ptr->syslog_logging_policy != SESSION_LOG_ENABLE) ||
+ (db->dst_ipv4 || db->dst_port))) {
+ cnat_syslog_ds_lite_mapping_create(db,dslite_entry_ptr,NULL
+#ifndef NO_BULK_LOGGING
+ ,nfv9_log_req
+#endif
+ );
+ }
+ }
+
+#if 0
+ if (PREDICT_FALSE(port_pair_type == PORT_PAIR)) {
+ cnat_main_db_entry_t *db2 = 0;
+ dslite_db_key_bucket_t new_ki = *ki;
+ u64 a, b, c;
+
+ new_ki.k.k.port += 1;
+ ko.k.k.port += 1;
+
+ CNAT_V4_GET_HASH(new_ki.k.key64, new_ki.bucket,
+ CNAT_MAIN_HASH_MASK);
+
+ db2 = cnat_create_main_db_entry_and_hash(&new_ki, &ko, udb);
+
+ translation_create_count ++;
+ db2->dslite_nat44_inst_id = dslite_id;
+ db2->entry_expires = cnat_current_time;
+ db2->flags |= CNAT_DB_FLAG_ALG_ENTRY;
+ udb->ntranslations += 1;
+#ifndef NO_BULK_LOGGING
+ if(PREDICT_FALSE(nfv9_log_req == BULK_ALLOC_NOT_ATTEMPTED))
+ cnat_nfv9_log_mapping_create(db2, my_vrfmap, nfv9_log_req);
+#else
+ cnat_nfv9_log_mapping_create(db2, my_vrfmap);
+#endif
+ }
+#endif
+ return db;
+}
+#endif /* TOBE_PORTED */
+
+#if 0
+/* TOBE_PORTED */
+uword
+cnat_db_v2_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return 0;
+}
+VLIB_REGISTER_NODE (cnat_db_v2_node) = {
+ .function = cnat_db_v2_node_fn,
+ .name = "vcgn-db-v2",
+ .vector_size = sizeof (u32),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(cnat_db_v2_error_strings),
+ .error_strings = cnat_db_v2_error_strings,
+
+ .n_next_nodes = CNAT_DB_V2_DROP,
+
+ /* edit / add dispositions here */
+ .next_nodes = {
+ [CNAT_DB_V2_DROP] = "error-drop",
+ },
+};
+#endif
+void cnat_db_v2_init (void)
+{
+
+ u32 i, n, lockinit;
+ cnat_timeout_db_entry_t * tdb __attribute__((unused));
+
+ cgse_nat_db_entry_t *comb_db __attribute__((unused));
+ cgse_nat_user_db_entry_t *comb_user __attribute__((unused));
+ cgse_nat_session_db_entry_t *comb_session __attribute__((unused));
+
+ n = CNAT_DB_SIZE*1.15; /* add 15% LB margin */
+
+ /*
+ * We also make it multiple of NUM_BITS_IN_UWORD for better
+ * DB scanning algorithm
+ */
+ if (n % NUM_BITS_IN_UWORD)
+ n += (NUM_BITS_IN_UWORD - (n % NUM_BITS_IN_UWORD));
+
+ pool_alloc(cgse_nat_db,n);
+ for(i=0; i< n; i++) {
+ pool_get(cgse_nat_db, comb_db);
+ }
+
+ for(i=0; i< n; i++) {
+ pool_put(cgse_nat_db, cgse_nat_db + i);
+ }
+
+ cnat_main_db = &cgse_nat_db->nat44_main_db;
+
+ /* For Sessions */
+ if(PLATFORM_DBL_SUPPORT) {
+ /* create session table for NAT44 and NAT64 itself */
+ printf("DBL Support exist %d\n", PLATFORM_DBL_SUPPORT);
+ n = CNAT_SESSION_DB_SIZE * 1.15; /* add 15% LB margin */
+ } else {
+ /* Create session table for NAT64 only */
+ printf("DBL Support Not exist\n");
+ n = NAT64_MAIN_DB_SIZE * 1.15; /* add 15% LB margin */
+ }
+
+ /*
+ * We also make it multiple of NUM_BITS_IN_UWORD for better
+ * DB scanning algorithm
+ */
+ if (n % NUM_BITS_IN_UWORD)
+ n += (NUM_BITS_IN_UWORD - (n % NUM_BITS_IN_UWORD));
+
+ pool_alloc(cgse_session_db,n);
+ for(i=0; i< n; i++) {
+ pool_get(cgse_session_db, comb_session);
+ }
+
+ for(i=0; i< n; i++) {
+ pool_put(cgse_session_db, cgse_session_db + i);
+ }
+
+ cnat_session_db = &cgse_session_db->nat44_session_db;
+
+ vec_validate(cnat_out2in_hash, CNAT_MAIN_HASH_MASK);
+ memset(cnat_out2in_hash, 0xff, CNAT_MAIN_HASH_SIZE*sizeof(index_slist_t));
+
+ vec_validate(cnat_in2out_hash, CNAT_MAIN_HASH_MASK);
+ memset(cnat_in2out_hash, 0xff, CNAT_MAIN_HASH_SIZE*sizeof(index_slist_t));
+
+ vec_validate(cnat_session_hash, CNAT_SESSION_HASH_MASK);
+ memset(cnat_session_hash, 0xff, CNAT_SESSION_HASH_SIZE*sizeof(index_slist_t));
+
+ n = CNAT_USER_DB_SIZE * 1.15; /* use hash size as db size for LB margin */
+ if (n % NUM_BITS_IN_UWORD)
+ n += (NUM_BITS_IN_UWORD - (n % NUM_BITS_IN_UWORD));
+
+ pool_alloc(cgse_user_db,n);
+ for(i=0; i< n; i++) {
+ pool_get(cgse_user_db, comb_user);
+ }
+
+ for(i=0; i< n; i++) {
+ pool_put(cgse_user_db, cgse_user_db + i);
+ }
+
+ cnat_user_db = &cgse_user_db->nat44_user_db;
+
+ vec_validate(cnat_user_hash, CNAT_USER_HASH_MASK);
+ memset(cnat_user_hash, 0xff, CNAT_USER_HASH_SIZE*sizeof(index_slist_t));
+
+ n = CNAT_TIMEOUT_HASH_SIZE; /* use hash size as db size for LB margin */
+ for(i=0; i< n; i++) {
+ pool_get(cnat_timeout_db, tdb);
+ }
+
+ for(i=0; i< n; i++) {
+ pool_put(cnat_timeout_db, cnat_timeout_db + i);
+ }
+
+ vec_validate(cnat_timeout_hash, CNAT_TIMEOUT_HASH_MASK);
+ memset(cnat_timeout_hash, 0xff, CNAT_TIMEOUT_HASH_SIZE*sizeof(index_slist_t));
+
+#ifdef TOBE_PORTED
+ for (i=0;i<CNAT_MAX_VRFMAP_ENTRIES; i++) {
+ svi_params_array[i].svi_type = CGSE_SVI_TYPE_INFRA;
+ }
+#endif
+
+ cnat_db_v2_main.main_db_lockp =
+ clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
+ CLIB_CACHE_LINE_BYTES);
+
+ cnat_db_v2_main.user_db_lockp =
+ clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
+ CLIB_CACHE_LINE_BYTES);
+
+ cnat_db_v2_main.session_db_lockp =
+ clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
+ CLIB_CACHE_LINE_BYTES);
+
+ lockinit = pthread_spin_init(cnat_db_v2_main.main_db_lockp,
+ PTHREAD_PROCESS_PRIVATE);
+ ASSERT (lockinit == 0);
+
+ lockinit = pthread_spin_init(cnat_db_v2_main.user_db_lockp,
+ PTHREAD_PROCESS_PRIVATE);
+ ASSERT (lockinit == 0);
+
+ lockinit = pthread_spin_init(cnat_db_v2_main.session_db_lockp,
+ PTHREAD_PROCESS_PRIVATE);
+ ASSERT (lockinit == 0);
+
+ cnat_db_init_done = 1;
+ printf("CNAT DB init is successful\n");
+ return;
+}
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_debug_msg_handler.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_debug_msg_handler.c
new file mode 100644
index 00000000..519f4b64
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_debug_msg_handler.c
@@ -0,0 +1,1780 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_debug_msg_handler.c - debug command
+ *
+ * Copyright (c) 2007-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+#include "cnat_cli.h"
+
+u32 global_debug_flag = CNAT_DEBUG_NONE;
+u16 debug_i_vrf = CNAT_DEBUG_NONE;
+u32 debug_i_flag = CNAT_DEBUG_NONE;
+u32 debug_i_addr_start = CNAT_DEBUG_NONE;
+u32 debug_i_addr_end = CNAT_DEBUG_NONE;
+
+u16 debug_o_vrf = CNAT_DEBUG_NONE;
+u32 debug_o_flag = CNAT_DEBUG_NONE;
+u32 debug_o_addr_start = CNAT_DEBUG_NONE;
+u32 debug_o_addr_end = CNAT_DEBUG_NONE;
+
+u32 udp_inside_checksum_disable = 0;
+u32 udp_outside_checksum_disable = 0;
+u32 udp_inside_packet_dump_enable = 0;
+u32 udp_outside_packet_dump_enable = 0;
+
+u32 tcp_logging_enable_flag = 0;
+
+u32 icmp_debug_flag = 0;
+u32 frag_debug_flag = 0;
+
+u32 nfv9_logging_debug_flag = 0;
+u32 syslog_debug_flag = 0;
+
+u32 summary_stats_debug_flag = 0;
+
+/*
+ * By defaut we set the config debug level to 1
+ */
+u32 config_debug_level = 1;
+
+#ifdef TOBE_PORTED
+extern void show_bulk_port_stats();
+extern void clear_bulk_port_stats();
+extern void show_bulk_port_allocation(u16 in_vrfid, u32 inside_ip);
+extern void set_bulk_size_to_all_vrfs(int bulk_size);
+
+u32 *cnat_debug_addr_list;
+
+extern int global_pd_dbg_lvl;
+extern int global_pi_dbg_lvl;
+extern int global_l2_dbg_lvl;
+extern u32 cnat_pptp_debug_flag;
+extern u32 cnat_pcp_debug_flag;
+
+void spp_api_cnat_get_cgn_db_summary
+(spp_api_cnat_generic_command_request_t *);
+
+void spp_api_cnat_v4_debug_dummy_t_handler
+(spp_api_cnat_v4_debug_dummy_t *mp)
+{
+ u32 arr[] = { DEBUG_DUMMY };
+ spp_printf(CNAT_DUMMY_HANDLER_HIT, 1, arr);
+ if(global_pd_dbg_lvl) {
+ PLATFORM_DEBUG_PRINT("\n invalid debug command received: message id is 0\n");
+ }
+ mp->rc = CNAT_ERR_INVALID_MSG_ID;
+
+}
+
+void spp_api_cnat_v4_debug_dummy_max_t_handler
+(spp_api_cnat_v4_debug_dummy_max_t *mp)
+{
+ u32 arr[] = { DEBUG_DUMMY_MAX };
+ spp_printf(CNAT_DUMMY_HANDLER_HIT, 1, arr);
+ if(global_pd_dbg_lvl) {
+ PLATFORM_DEBUG_PRINT("\n invalid debug command received: message id is out of range\n");
+ }
+ mp->rc = CNAT_ERR_INVALID_MSG_ID;
+
+}
+
+
+void spp_api_cnat_v4_debug_global_t_handler
+(spp_api_cnat_v4_debug_global_t *mp)
+{
+ if ((mp->debug_flag == CNAT_DEBUG_GLOBAL_ERR) ||
+ (mp->debug_flag == CNAT_DEBUG_GLOBAL_ALL) ||
+ (mp->debug_flag == CNAT_DEBUG_NONE)) {
+ mp->rc = CNAT_SUCCESS;
+ global_debug_flag = mp->debug_flag;
+ return;
+ }
+
+ mp->rc = CNAT_ERR_PARSER;
+ if(global_pd_dbg_lvl) {
+ PLATFORM_DEBUG_PRINT("invalid global debug flag %x\n",
+ mp->debug_flag);
+ }
+ return;
+}
+
+void spp_node_print_cnat_counters()
+{
+ if (cnat_global_counters.nfv9_downstream_constipation_count) {
+ PLATFORM_DEBUG_PRINT("\nNF downstream constipation count: %llu\n",
+ cnat_global_counters.nfv9_downstream_constipation_count);
+ }
+
+ if (xlat_global_counters.v4_to_v6_frag_invalid_uidb_drop_count ||
+ xlat_global_counters.v6_to_v4_frag_invalid_uidb_drop_count ||
+ xlat_global_counters.v4_to_v6_icmp_invalid_uidb_drop_count ||
+ xlat_global_counters.v6_to_v4_icmp_invalid_uidb_drop_count ||
+ xlat_global_counters.v4_to_v6_tcp_invalid_uidb_drop_count ||
+ xlat_global_counters.v6_to_v4_tcp_invalid_uidb_drop_count ||
+ xlat_global_counters.v4_to_v6_udp_invalid_uidb_drop_count ||
+ xlat_global_counters.v6_to_v4_udp_invalid_uidb_drop_count ||
+ xlat_global_counters.v4_to_v6_udp_crc_zero_invalid_uidb_drop_count) {
+
+ PLATFORM_DEBUG_PRINT("\nMy_instance %d: v4_to_v6 frag invalid uidb drop count %lld",
+ my_instance_number,
+ xlat_global_counters.v4_to_v6_frag_invalid_uidb_drop_count);
+
+ PLATFORM_DEBUG_PRINT("\nMy_instance %d: v6_to_v4 frag invalid uidb drop count %lld",
+ my_instance_number,
+ xlat_global_counters.v6_to_v4_frag_invalid_uidb_drop_count);
+
+ PLATFORM_DEBUG_PRINT("\nMy_instance %d: v4_to_v6 icmp invalid uidb drop count %lld",
+ my_instance_number,
+ xlat_global_counters.v4_to_v6_icmp_invalid_uidb_drop_count);
+
+ PLATFORM_DEBUG_PRINT("\nMy_instance %d: v6_to_v4 icmp invalid uidb drop count %lld",
+ my_instance_number,
+ xlat_global_counters.v6_to_v4_icmp_invalid_uidb_drop_count);
+
+ PLATFORM_DEBUG_PRINT("\nMy_instance %d: v4_to_v6 tcp invalid uidb drop count %lld",
+ my_instance_number,
+ xlat_global_counters.v4_to_v6_tcp_invalid_uidb_drop_count);
+
+ PLATFORM_DEBUG_PRINT("\nMy_instance %d: v6_to_v4 tcp invalid uidb drop count %lld",
+ my_instance_number,
+ xlat_global_counters.v6_to_v4_tcp_invalid_uidb_drop_count);
+
+ PLATFORM_DEBUG_PRINT("\nMy_instance %d: v4_to_v6 udp invalid uidb drop count %lld",
+ my_instance_number,
+ xlat_global_counters.v4_to_v6_udp_invalid_uidb_drop_count);
+
+ PLATFORM_DEBUG_PRINT("\nMy_instance %d: v6_to_v4 udp invalid uidb drop count %lld",
+ my_instance_number,
+ xlat_global_counters.v6_to_v4_udp_invalid_uidb_drop_count);
+
+ PLATFORM_DEBUG_PRINT("\nMy_instance %d: v4_to_v6 udp crc0 invld uidb drop count %lld",
+ my_instance_number,
+ xlat_global_counters.v4_to_v6_udp_crc_zero_invalid_uidb_drop_count);
+
+ PLATFORM_DEBUG_PRINT("\n");
+ }
+
+
+}
+
+void spp_log_p2mp_req(spp_api_cnat_p2mp_debug_request_t *mp)
+{
+ u8 i = 0;
+ u32 num_rec = spp_net_to_host_byte_order_32(&mp->param[i++]);
+ u32 err_c_num_args;
+
+ while (num_rec--) {
+ u8 j = 0;
+ u16 err_c;
+ u16 num_args;
+ u32 argv[32];
+
+ err_c_num_args = spp_net_to_host_byte_order_32(&mp->param[i++]);
+ err_c = (err_c_num_args >> 16) & 0xFFFF;
+ num_args = err_c_num_args & 0xFFFF;
+
+ num_args = (num_args <= 32) ? num_args : 32;
+ while (j < num_args) {
+ argv[j++] = spp_net_to_host_byte_order_32(&mp->param[i++]);
+ }
+
+ i += ((num_args - 32) > 0) ? (num_args - 32) : 0;
+ spp_printf(err_c, num_args, argv);
+ }
+}
+
+void nat64_debug_addr_pool_add_del()
+{
+ cnat_portmap_v2_t *my_pm = NULL;
+ cnat_portmap_v2_t *pm = NULL;
+ u32 len, i, pm_len;
+
+ PLATFORM_DEBUG_PRINT("\n sizeof port_map =%d\n", sizeof( cnat_portmap_v2_t));
+ len = 10;
+ PLATFORM_DEBUG_PRINT("\n adding 10 entries in vector 1-10\n ");
+ vec_add2(pm, my_pm, len);
+ pm = my_pm;
+
+ PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm);
+ for(i=0;i<len;i++){
+ my_pm->ipv4_address = i+1;
+ my_pm++;
+ }
+ PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm);
+
+ pm_len = vec_len(pm);
+ PLATFORM_DEBUG_PRINT("\n printing vector contents : vec_len = %d \n", pm_len);
+ my_pm = pm;
+ for(i=0;i<pm_len ; i++)
+ {
+ PLATFORM_DEBUG_PRINT(" %d ,",my_pm->ipv4_address);
+ my_pm++;
+ }
+ PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm);
+
+ PLATFORM_DEBUG_PRINT("\n adding 5 entries in vector 11-15\n ");
+ len = 5;
+ vec_add2(pm, my_pm, len);
+
+ PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm);
+ for(i=0;i<len;i++) {
+ my_pm->ipv4_address = 11+i;
+ my_pm++;
+ }
+
+ PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm);
+ pm_len = vec_len(pm);
+ PLATFORM_DEBUG_PRINT("\n printing vector contents : vec_len = %d \n", pm_len);
+ my_pm = pm;
+ for(i=0;i<pm_len ; i++)
+ {
+ PLATFORM_DEBUG_PRINT(" %d ,",my_pm->ipv4_address);
+ my_pm++;
+ }
+ PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm);
+
+ PLATFORM_DEBUG_PRINT("\n adding 6 entries in vector 16-21\n ");
+ len = 6;
+ vec_add2(pm, my_pm, len);
+ PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm);
+ for(i=0;i<len;i++) {
+ my_pm->ipv4_address = 16+i;
+ my_pm++;
+ }
+
+ PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm);
+ pm_len = vec_len(pm);
+ PLATFORM_DEBUG_PRINT("\n printing vector contents : vec_len = %d \n", pm_len);
+ my_pm = pm;
+ for(i=0;i<pm_len ; i++)
+ {
+ PLATFORM_DEBUG_PRINT(" %d ,",my_pm->ipv4_address);
+ my_pm++;
+ }
+
+ PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm);
+ PLATFORM_DEBUG_PRINT("\nDeleting 7 entries starting from entry value=8\n");
+ pm_len = vec_len(pm);
+ my_pm = pm;
+ PLATFORM_DEBUG_PRINT(" pm_len =%d\n", pm_len);
+ for(i=0;i<pm_len;i++)
+ {
+ if(my_pm->ipv4_address == 8){
+ PLATFORM_DEBUG_PRINT("\n match found brraeaking..\n");
+ break;
+ }
+ my_pm++;
+ }
+
+ PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p i= %d\n", pm, my_pm, i);
+// vec_delete(pm, 7, my_pm);
+ vec_delete(pm, 7, i);
+ PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm);
+
+ PLATFORM_DEBUG_PRINT(" printing entries aftr deletion from 8-14\n");
+ pm_len = vec_len(pm);
+ PLATFORM_DEBUG_PRINT("\n printing vector contents : vec_len = %d \n", pm_len);
+ my_pm = pm;
+ for(i=0;i<pm_len ; i++)
+ {
+ PLATFORM_DEBUG_PRINT(" %d ,",my_pm->ipv4_address);
+ my_pm++;
+ }
+
+
+ PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm);
+
+ PLATFORM_DEBUG_PRINT("\nadding deleted items again 8-14\n");
+ len =7;
+ vec_add2(pm, my_pm, len);
+
+ PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm);
+ for(i=0;i<len;i++) {
+ my_pm->ipv4_address = 8+i;
+ my_pm++;
+ }
+
+ PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm);
+ pm_len = vec_len(pm);
+ PLATFORM_DEBUG_PRINT("\n printing vector contents : vec_len = %d \n", pm_len);
+ my_pm = pm;
+ for(i=0;i<pm_len ; i++)
+ {
+ PLATFORM_DEBUG_PRINT(" %d ,",my_pm->ipv4_address);
+ my_pm++;
+ }
+ PLATFORM_DEBUG_PRINT(" pm =%p , my_pm = %p\n", pm, my_pm);
+ PLATFORM_DEBUG_PRINT("\n");
+}
+
+
+void uidb_mapping_dump_timeout() {
+
+ u32 i;
+
+ PLATFORM_DEBUG_PRINT("\nCGSE uidb mapping table \n");
+ for(i = 0;i < 30;i++) {
+ PLATFORM_DEBUG_PRINT("%d ",*(cgse_uidb_index_cgse_id_mapping_ptr + i));
+ }
+
+}
+
+void nat64_debug_dump_info(u32 debug_value)
+{
+
+ switch(debug_value) {
+
+ case 1 :
+ bib_add_v6_entry1();
+ break;
+
+ case 2 :
+ bib_add_v6_entry2();
+ break;
+
+ case 3 :
+ bib_add_v6_entry1_new();
+ break;
+
+ case 4 :
+ bib_add_v6_entry1_new_static();
+ break;
+
+ case 5 :
+ bib_add_v6_entry3();
+ break;
+
+ case 6 :
+ bib_add_v6_entry_new2();
+ break;
+
+ case 7 :
+ nat64_fill_table_entry();
+ break;
+
+ case 10 :
+ nat64_db_dump_main();
+ break;
+
+ case 11 :
+ nat64_db_dump_user();
+ break;
+
+ case 12 :
+ nat64_db_dump_session();
+ break;
+
+ case 13 :
+ nat64_dump_table();
+ break;
+
+ case 14 :
+ bib_del_v6_entry1_static();
+ break;
+
+ case 15 :
+ nat64_debug_addr_pool_add_del();
+ break;
+
+ case 16 :
+ nat64_db_dump_timeout(0);
+ break;
+
+ case 17 :
+ uidb_mapping_dump_timeout();
+ break;
+
+ default : break;
+ }
+}
+
+
+void cnat_debug_flags_set (spp_api_cnat_p2mp_debug_request_t *mp)
+{
+ u32 debug_variable = spp_net_to_host_byte_order_32(&mp->param[0]);
+ u32 debug_value = spp_net_to_host_byte_order_32(&mp->param[1]);
+
+ cnat_key_t t_key;
+
+ switch (debug_variable) {
+
+ case CNAT_DEBUG_FLAG_UDP_INSIDE_CHECKSUM_DISABLE:
+ udp_inside_checksum_disable = debug_value;
+ PLATFORM_DEBUG_PRINT("\nudp_inside_checksum_disable set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_UDP_OUTSIDE_CHECKSUM_DISABLE:
+ udp_outside_checksum_disable = debug_value;
+ PLATFORM_DEBUG_PRINT("\nudp_outside_checksum_disable set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_UDP_OUTSIDE_PKT_DUMP_ENABLE:
+ udp_outside_packet_dump_enable = debug_value;
+ PLATFORM_DEBUG_PRINT("\nudp_outside_packet_dump_enable set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_UDP_INSIDE_PKT_DUMP_ENABLE:
+ udp_inside_packet_dump_enable = debug_value;
+ PLATFORM_DEBUG_PRINT("\nudp_inside_packet_dump_enable set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_ICMP_PKT_DUMP_ENABLE:
+ icmp_debug_flag = debug_value;
+ PLATFORM_DEBUG_PRINT("\nicmp_debug_flag set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_FRAG_PKT_DUMP_ENABLE:
+ frag_debug_flag = debug_value;
+ PLATFORM_DEBUG_PRINT("\nfrag_debug_flag set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_XLAT_CONFIG_DEBUG_ENABLE:
+ xlat_config_debug_level = debug_value;
+ PLATFORM_DEBUG_PRINT("\nxlat_config_debug_level set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_NAT64_CONFIG_DEBUG_ENABLE:
+ nat64_config_debug_level = debug_value;
+ PLATFORM_DEBUG_PRINT("\nnat64_config_debug_level set to %d\n", debug_value);
+ nat64_debug_dump_info(debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_NAT64_DATA_PATH_DEBUG_ENABLE:
+ nat64_data_path_debug_level = debug_value;
+ PLATFORM_DEBUG_PRINT("\nnat64_data_path_debug_level set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_DSLITE_CONFIG_DEBUG_ENABLE:
+ ds_lite_config_debug_level = debug_value;
+ PLATFORM_DEBUG_PRINT("\nds_lite_config_debug_level set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_XLAT_DATA_PATH_DEBUG_ENABLE:
+ xlat_data_path_debug_level = debug_value;
+ PLATFORM_DEBUG_PRINT("\nxlat_data_path_debug_level set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_CONFIG_DEBUG_ENABLE:
+ config_debug_level = debug_value;
+
+ PLATFORM_DEBUG_PRINT("\nconfig_debug_level set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_CONFIG_PPTP_ENABLE:
+ cnat_pptp_debug_flag = debug_value;
+
+ if(debug_value == 0) {
+ pptp_dump_counters();
+ }
+
+ PLATFORM_DEBUG_PRINT("\ncnat_pptp_debug_level set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_CONFIG_PCP_ENABLE:
+ cnat_pcp_debug_flag = debug_value;
+
+ if(debug_value == 0) {
+ pcp_dump_counters();
+ }
+ PLATFORM_DEBUG_PRINT("\ncnat_pcp_debug_level set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_GLOBAL_DEBUG_ALL_ENABLE:
+ global_debug_flag = debug_value;
+ PLATFORM_DEBUG_PRINT("\nglobal_debug_flag set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_SUMMARY_STATS_DEBUG_ENABLE:
+ summary_stats_debug_flag = debug_value;
+ PLATFORM_DEBUG_PRINT("\nsummary_stats_debug_flag set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_SHOW_DEBUG_ENABLE:
+ show_debug_level = debug_value;
+ PLATFORM_DEBUG_PRINT("\nshow_debug_level set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_TCP_LOGGING_ENABLE:
+ tcp_debug_logging_enable_disable(debug_value);
+ break;
+ case CNAT_DEBUG_FLAG_V6RD_DATA_PATH_DEBUG_ENABLE:
+ v6rd_data_path_debug_level = debug_value;
+ PLATFORM_DEBUG_PRINT("\nv6rd_data_path_debug_level set to %d\n", debug_value);
+ break;
+ case CNAT_DEBUG_FLAG_V6RD_CONFIG_DEBUG_ENABLE:
+ v6rd_config_debug_level = debug_value;
+ PLATFORM_DEBUG_PRINT("\nv6rd_config_debug_level set to %d\n", debug_value);
+ break;
+ case CNAT_DEBUG_FLAG_V6RD_DEFRAG_DEBUG_ENABLE:
+ /* set debug atleast to 1, so that critical errors are always
+ * enabled
+ */
+ v6rd_defrag_debug_level = debug_value ? debug_value : 1;
+ PLATFORM_DEBUG_PRINT("\nv6rd_config_debug_level set to %d\n", debug_value);
+ break;
+
+
+ case CNAT_DEBUG_SET_STATIC_PORT_RANGE:
+ PLATFORM_DEBUG_PRINT("\nChange Static Port Range from %d --> %d\n",
+ cnat_static_port_range, debug_value);
+ cnat_static_port_range = debug_value;
+ break;
+
+ case CNAT_DEBUG_FLAG_DSLITE_DP_ENABLE:
+ PLATFORM_DEBUG_PRINT("\n Changing dslite debug flag from %d --> %d\n",
+ dslite_debug_level, debug_value);
+ dslite_debug_level = debug_value;
+ break;
+
+ case CNAT_DEBUG_FLAG_NFV9_LOGGING_DUMP_ENABLE:
+ nfv9_logging_debug_flag = debug_value;
+ PLATFORM_DEBUG_PRINT("\nnfv9_logging_debug_flag set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_SYSLOG_LOGGING_DUMP_ENABLE:
+ syslog_debug_flag = debug_value;
+ PLATFORM_DEBUG_PRINT("\nsyslog_debug_flag set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_MAPE_CONFIG_DEBUG_ENABLE:
+ mape_config_debug_level = debug_value;
+ PLATFORM_DEBUG_PRINT("\nmape_config_debug_level set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAG_MAPE_DATA_PATH_DEBUG_ENABLE:
+ mape_data_path_debug_level = debug_value;
+ PLATFORM_DEBUG_PRINT("\nmape_data_path_debug_level set to %d\n", debug_value);
+ break;
+
+ case CNAT_DEBUG_FLAGS_DUMP:
+ default:
+ {
+ PLATFORM_DEBUG_PRINT("\nCurrent values of Debug Variables\n");
+ PLATFORM_DEBUG_PRINT("\nTo modify an item chose its index and provide the value\n");
+ PLATFORM_DEBUG_PRINT("\n%d: udp_inside_checksum_disable %d\n",
+ CNAT_DEBUG_FLAG_UDP_INSIDE_CHECKSUM_DISABLE,
+ udp_inside_checksum_disable);
+ PLATFORM_DEBUG_PRINT("%d: udp_outside_checksum_disable %d\n",
+ CNAT_DEBUG_FLAG_UDP_OUTSIDE_CHECKSUM_DISABLE,
+ udp_outside_checksum_disable);
+ PLATFORM_DEBUG_PRINT("%d: udp_inside_packet_dump_enable %d\n",
+ CNAT_DEBUG_FLAG_UDP_OUTSIDE_PKT_DUMP_ENABLE,
+ udp_inside_packet_dump_enable);
+ PLATFORM_DEBUG_PRINT("%d: udp_outside_packet_dump_enable %d\n",
+ CNAT_DEBUG_FLAG_UDP_INSIDE_PKT_DUMP_ENABLE,
+ udp_outside_packet_dump_enable);
+ PLATFORM_DEBUG_PRINT("%d: icmp_debug_flag %d\n",
+ CNAT_DEBUG_FLAG_ICMP_PKT_DUMP_ENABLE,
+ icmp_debug_flag);
+ PLATFORM_DEBUG_PRINT("%d: frag_debug_flag %d\n",
+ CNAT_DEBUG_FLAG_FRAG_PKT_DUMP_ENABLE,
+ frag_debug_flag);
+ PLATFORM_DEBUG_PRINT("%d: config_debug_level %d\n",
+ CNAT_DEBUG_FLAG_CONFIG_DEBUG_ENABLE,
+ config_debug_level);
+ PLATFORM_DEBUG_PRINT("%d: global_debug_flag %d\n",
+ CNAT_DEBUG_FLAG_GLOBAL_DEBUG_ALL_ENABLE,
+ global_debug_flag);
+ PLATFORM_DEBUG_PRINT("%d: summary_stats_debug_flag %d\n",
+ CNAT_DEBUG_FLAG_SUMMARY_STATS_DEBUG_ENABLE,
+ summary_stats_debug_flag);
+ PLATFORM_DEBUG_PRINT("%d: show_debug_level %d\n",
+ CNAT_DEBUG_FLAG_SHOW_DEBUG_ENABLE,
+ show_debug_level);
+ PLATFORM_DEBUG_PRINT("%d: xlat_config_debug_level %d\n",
+ CNAT_DEBUG_FLAG_XLAT_CONFIG_DEBUG_ENABLE,
+ xlat_config_debug_level);
+ PLATFORM_DEBUG_PRINT("%d: xlat_data_path_debug_level %d\n",
+ CNAT_DEBUG_FLAG_XLAT_DATA_PATH_DEBUG_ENABLE,
+ xlat_data_path_debug_level);
+ PLATFORM_DEBUG_PRINT("%d: tcp_logging_enable_flag %d\n",
+ CNAT_DEBUG_FLAG_TCP_LOGGING_ENABLE,
+ tcp_logging_enable_flag);
+ PLATFORM_DEBUG_PRINT(" tcp_logging_enable_options DISABLE %d, ENABLE %d, PKT_DUMP %d, SUMMARY_DUMP %d\n",
+ TCP_LOGGING_DISABLE, TCP_LOGGING_ENABLE,
+ TCP_LOGGING_PACKET_DUMP, TCP_LOGGING_SUMMARY_DUMP);
+ PLATFORM_DEBUG_PRINT("%d: nfv9_logging_debug_flag %d\n",
+ CNAT_DEBUG_FLAG_NFV9_LOGGING_DUMP_ENABLE,
+ nfv9_logging_debug_flag);
+ PLATFORM_DEBUG_PRINT("%d: syslog_debug_flag %d\n",
+ CNAT_DEBUG_FLAG_SYSLOG_LOGGING_DUMP_ENABLE,
+ syslog_debug_flag);
+ PLATFORM_DEBUG_PRINT("%d: cnat_static_port_range %d\n",
+ CNAT_DEBUG_SET_STATIC_PORT_RANGE,
+ cnat_static_port_range);
+ PLATFORM_DEBUG_PRINT("%d: v6rd_data_path_debug_level %d\n",
+ CNAT_DEBUG_FLAG_V6RD_DATA_PATH_DEBUG_ENABLE,
+ v6rd_data_path_debug_level);
+ PLATFORM_DEBUG_PRINT("%d: v6rd_config_debug_level %d\n",
+ CNAT_DEBUG_FLAG_V6RD_CONFIG_DEBUG_ENABLE,
+ v6rd_config_debug_level);
+ PLATFORM_DEBUG_PRINT("%d: v6rd_defrag_debug_level %d\n",
+ CNAT_DEBUG_FLAG_V6RD_DEFRAG_DEBUG_ENABLE,
+ v6rd_defrag_debug_level);
+ PLATFORM_DEBUG_PRINT("%d: nat64_stful_debug %d\n",
+ CNAT_DEBUG_FLAG_NAT64_CONFIG_DEBUG_ENABLE,
+ nat64_config_debug_level);
+ PLATFORM_DEBUG_PRINT("%d: nat64_data_path_debug_level %d\n",
+ CNAT_DEBUG_FLAG_NAT64_DATA_PATH_DEBUG_ENABLE,
+ nat64_data_path_debug_level);
+ PLATFORM_DEBUG_PRINT("%d: dslite_debug_level %d\n",
+ CNAT_DEBUG_FLAG_DSLITE_DP_ENABLE,
+ dslite_debug_level);
+ PLATFORM_DEBUG_PRINT("%d: ds_lite_config_debug_level %d\n",
+ CNAT_DEBUG_FLAG_DSLITE_CONFIG_DEBUG_ENABLE,
+ ds_lite_config_debug_level);
+ PLATFORM_DEBUG_PRINT("%d: mape_config_debug_level %d\n",
+ CNAT_DEBUG_FLAG_MAPE_CONFIG_DEBUG_ENABLE,
+ mape_config_debug_level);
+ PLATFORM_DEBUG_PRINT("%d: mape_data_path_debug_level %d\n",
+ CNAT_DEBUG_FLAG_MAPE_DATA_PATH_DEBUG_ENABLE,
+ mape_data_path_debug_level);
+ }
+ break;
+ }
+}
+
+extern void dump_cnat_frag_stats(void);
+
+void spp_api_cnat_p2mp_debug_request_t_handler
+(spp_api_cnat_p2mp_debug_request_t *mp)
+{
+ u16 command_type;
+
+/*
+ if (mp->core_num != my_instance_number) {
+ mp->rc = CNAT_NOT_THIS_CORE;
+ return;
+ }
+*/
+
+ command_type = spp_net_to_host_byte_order_16(&mp->dump_type);
+ PLATFORM_DEBUG_PRINT("-->> Core%d: Received debug msg ... cmd type: %d\n",
+ my_instance_number, command_type);
+
+ switch (command_type) {
+
+ case CNAT_DEBUG_GENERIC_COMMAND_DUMP_POLICY:
+ PLATFORM_DEBUG_PRINT("Core%d: policy\n", my_instance_number);
+ cnat_db_dump_policy();
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_DUMP_MAIN_DB:
+ PLATFORM_DEBUG_PRINT("Core%d: Main db\n", my_instance_number);
+ cnat_db_dump_main();
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_DUMP_MAIN_DB_SUMMARY:
+ PLATFORM_DEBUG_PRINT("Core%d: Main db Summary\n", my_instance_number);
+ cnat_db_dump_main_summary();
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_DUMP_USER_DB:
+ PLATFORM_DEBUG_PRINT("Core%d: User db\n", my_instance_number);
+ cnat_db_dump_user();
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_DUMP_USER_DB_SUMMARY:
+ PLATFORM_DEBUG_PRINT("Core%d: User db Summary\n", my_instance_number);
+ cnat_db_dump_user_summary();
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_DUMP_HASHES_DB:
+ PLATFORM_DEBUG_PRINT("Core%d: Hashes db\n", my_instance_number);
+ cnat_db_dump_hashes();
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_DUMP_VRF_MAP:
+ PLATFORM_DEBUG_PRINT("Core%d: Vrf map \n", my_instance_number);
+ cnat_db_dump_portmaps();
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_DUMP_SUMMARY_DB:
+ PLATFORM_DEBUG_PRINT("Core%d: dump summary DB \n", my_instance_number);
+ cnat_db_summary();
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_DUMP_STATS:
+ PLATFORM_DEBUG_PRINT("Core%d: dump stats \n", my_instance_number);
+ spp_node_print_stats(1, NULL);
+ break;
+
+ /* Currently does same as clear node ctr, may change */
+ case CNAT_DEBUG_GENERIC_COMMAND_CLEAR_STATS:
+ PLATFORM_DEBUG_PRINT("Core%d: clear stats \n", my_instance_number);
+ spp_node_clear_stats();
+ break;
+
+ case CNAT_DEBUG_SPP_LOG:
+ PLATFORM_DEBUG_PRINT("Core%d: SPP LOG \n", my_instance_number);
+ spp_log_p2mp_req(mp);
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_DUMP_NODE_COUNTER:
+ PLATFORM_DEBUG_PRINT("Core%d: NODE Counter dump \n", my_instance_number);
+ spp_node_print_counters();
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_CLEAR_NODE_COUNTER:
+ PLATFORM_DEBUG_PRINT("Core%d: clear node counter \n", my_instance_number);
+ spp_node_clear_stats();
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_DUMP_CNAT_COUNTER:
+ PLATFORM_DEBUG_PRINT("Core%d: CNAT Counter dump \n", my_instance_number);
+ spp_node_print_cnat_counters();
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_DUMP_VA:
+ PLATFORM_DEBUG_PRINT("Core%d: VA dump \n", my_instance_number);
+ {
+ int argc = 1;
+ u32 arg[2] = {spp_net_to_host_byte_order_32(&mp->param[0]), 0};
+
+ cnat_va_dump(argc, arg);
+ }
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_SHOW_CONFIG:
+ PLATFORM_DEBUG_PRINT("Core%d: Show config dump \n", my_instance_number);
+ {
+ int argc = 0;
+ unsigned long arg[3];
+
+ if (arg[argc++] = spp_net_to_host_byte_order_32(&mp->param[0])) {
+ if (arg[argc++] = spp_net_to_host_byte_order_32(&mp->param[1])) {
+ ;
+ } else {
+ argc--;
+ }
+ }
+
+ cnat_show_cdb_command_v2(argc, arg);
+/*
+ xlat_show_config();
+ cnat_alg_show();
+*/
+ v6rd_show_config();
+ dslite_show_config();
+ nat64_dump_table();
+ mape_show_config();
+ }
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_SHOW_NFV9:
+ PLATFORM_DEBUG_PRINT("Core%d: NFv9 dump \n", my_instance_number);
+ #if 0 /* Currently not calling this */
+ cnat_nfv9_show_cmd();
+ #endif
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_SHOW_IVRF:
+ PLATFORM_DEBUG_PRINT("Core%d: IVRF dump \n", my_instance_number);
+ {
+ int argc = 0;
+ unsigned long arg[3];
+
+ if (arg[argc++] = spp_net_to_host_byte_order_32(&mp->param[0])) {
+ if (arg[argc++] = spp_net_to_host_byte_order_32(&mp->param[1])) {
+ if (arg[argc++] = spp_net_to_host_byte_order_32(&mp->param[2])) {
+ ;
+ } else {
+ argc--;
+ }
+ } else {
+ argc--;
+ }
+ }
+
+
+ PLATFORM_DEBUG_PRINT("VRF: %d \n", spp_net_to_host_byte_order_32(&mp->param[0]));
+ PLATFORM_DEBUG_PRINT("2nd arg: %d \n",
+ spp_net_to_host_byte_order_32(&mp->param[1]));
+
+ cnat_show_ivrf_command_v2(argc, arg);
+ }
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_SHOW_OVRF:
+ PLATFORM_DEBUG_PRINT("Core%d: OVRF dump \n", my_instance_number);
+ {
+ int argc = 0;
+ unsigned long arg[3];
+ if (arg[argc++] = spp_net_to_host_byte_order_32(&mp->param[0])) {
+ if (arg[argc++] = spp_net_to_host_byte_order_32(&mp->param[1])) {
+ if (arg[argc++] = spp_net_to_host_byte_order_32(&mp->param[2])) {
+ ;
+ } else {
+ argc--;
+ }
+ } else {
+ argc--;
+ }
+ }
+
+ PLATFORM_DEBUG_PRINT("VRF: %d \n", spp_net_to_host_byte_order_32(&mp->param[0]));
+ PLATFORM_DEBUG_PRINT("2nd arg: %d \n",
+ spp_net_to_host_byte_order_32(&mp->param[1]));
+
+ cnat_show_ovrf_command_v2(argc, arg);
+ }
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_DEBUG_OPTIONS:
+ PLATFORM_DEBUG_PRINT("Core%d: Debug option dump \n", my_instance_number);
+ {
+ global_pd_dbg_lvl = 0;
+ global_pi_dbg_lvl = 0;
+ global_l2_dbg_lvl = 0;
+
+ global_pd_dbg_lvl =
+ spp_net_to_host_byte_order_32(&mp->param[0]);
+ global_pi_dbg_lvl =
+ spp_net_to_host_byte_order_32(&mp->param[1]);
+ global_l2_dbg_lvl =
+ spp_net_to_host_byte_order_32(&mp->param[2]);
+
+ PLATFORM_DEBUG_PRINT("global_pd_dbg_lvl: %d, global_pi_dbg_lvl: %d, global_l2_dbg_lvl: %d\n",
+ global_pd_dbg_lvl, global_pi_dbg_lvl, global_l2_dbg_lvl);
+ }
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_DUMP_DEBUG_LEVELS:
+ PLATFORM_DEBUG_PRINT("Core%d: PD Debug level: %d \n", my_instance_number, global_pd_dbg_lvl);
+ PLATFORM_DEBUG_PRINT("Core%d: PI Debug level: %d \n", my_instance_number, global_pi_dbg_lvl);
+ PLATFORM_DEBUG_PRINT("Core%d: L2 Debug level: %d \n", my_instance_number, global_l2_dbg_lvl);
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_DEBUG_FLAGS:
+ PLATFORM_DEBUG_PRINT("Core%d: Debug flags \n", my_instance_number);
+ cnat_debug_flags_set(mp);
+ break;
+
+ case CNAT_READ_TEMP_SENSORS:
+ PLATFORM_INIT_TEMP_SENSORS();
+ PLATFORM_READ_CPU_SENSORS(TEMPERATURE_SENSOR_TEST_MODE);
+ break;
+
+ case CNAT_BLOCK_OCTEON_SENSOR_READ:
+
+ PLATFORM_SET_TEMP_READ_BLOCK(temperature_read_blocked , mp);
+#ifdef TARGET_RODDICK
+ temperature_read_blocked =
+ spp_net_to_host_byte_order_32(&mp->param[0]);
+#endif
+ break;
+
+ case CNAT_DEBUG_TIMEOUT_DB_SUMMARY:
+ cnat_db_dump_timeout();
+ break;
+
+ /* This option has to be removed later */
+ case CNAT_DEBUG_SET_BULK_SIZE:
+ PLATFORM_DEBUG_PRINT("\nSetting bulk size to %d\n",
+ spp_net_to_host_byte_order_32(&mp->param[0]));
+ set_bulk_size_to_all_vrfs(
+ spp_net_to_host_byte_order_32(&mp->param[0]));
+ break;
+
+ case CNAT_DEBUG_SHOW_BULK_STAT:
+ show_bulk_port_stats();
+ break;
+
+ case CNAT_DEBUG_CLEAR_BULK_STAT:
+ clear_bulk_port_stats();
+ break;
+
+ case CNAT_DEBUG_SHOW_BULK_ALLOC:
+ {
+ u16 in_vrfid = spp_net_to_host_byte_order_32(&mp->param[0]);
+ u32 inside_ip = spp_net_to_host_byte_order_32(&mp->param[1]);
+ show_bulk_port_allocation(in_vrfid, inside_ip);
+ }
+ break;
+
+ case CNAT_DEBUG_NAT44_IN2OUT_FRAG_STATS:
+ dump_cnat_frag_stats();
+ break;
+
+ default:
+ mp->rc = CNAT_ERR_INVALID_MSG_ID;
+ break;
+ }
+
+ mp->rc = CNAT_SUCCESS;
+ return;
+}
+
+
+void spp_api_cnat_v4_debug_in2out_private_addr_t_handler
+(spp_api_cnat_v4_debug_in2out_private_addr_t *mp)
+{
+ u16 i_vrf;
+ u32 debug_flag;
+ u32 start_addr, end_addr;
+
+
+ start_addr =
+ spp_net_to_host_byte_order_32(&mp->start_addr);
+ end_addr =
+ spp_net_to_host_byte_order_32(&mp->end_addr);
+ i_vrf =
+ spp_net_to_host_byte_order_16(&mp->i_vrf);
+ debug_flag =
+ spp_net_to_host_byte_order_32(&mp->debug_flag);
+
+ if ((i_vrf > MAX_UIDX) || (start_addr > end_addr) ||
+ ((debug_flag != CNAT_DEBUG_NONE) &&
+ ((debug_flag & CNAT_DEBUG_ALL) == CNAT_DEBUG_NONE))) {
+ mp->rc = CNAT_ERR_PARSER;
+ PLATFORM_DEBUG_PRINT("invalid debug ivrf 0x%x flag 0x%x "
+ "start addr 0x%x end addr 0x%x\n",
+ i_vrf, debug_flag,
+ start_addr, end_addr);
+ return;
+ }
+
+ PLATFORM_DEBUG_PRINT("debug ivrf 0x%x flag 0x%x "
+ "start addr 0x%x end addr 0x%x\n",
+ i_vrf, debug_flag,
+ start_addr, end_addr);
+
+ mp->rc = CNAT_SUCCESS;
+ debug_i_vrf = i_vrf;
+ debug_i_flag = debug_flag;
+ debug_i_addr_start = start_addr;
+ debug_i_addr_end = end_addr;
+
+}
+
+void spp_api_cnat_v4_debug_out2in_public_addr_t_handler
+(spp_api_cnat_v4_debug_out2in_public_addr_t *mp)
+{
+ u16 o_vrf;
+ u32 debug_flag;
+ u32 start_addr, end_addr;
+
+ start_addr =
+ spp_net_to_host_byte_order_32(&mp->start_addr);
+ end_addr =
+ spp_net_to_host_byte_order_32(&mp->end_addr);
+ o_vrf =
+ spp_net_to_host_byte_order_16(&mp->o_vrf);
+ debug_flag =
+ spp_net_to_host_byte_order_32(&mp->debug_flag);
+
+ if ((o_vrf > MAX_UIDX) || (start_addr > end_addr) ||
+ ((debug_flag != CNAT_DEBUG_NONE) &&
+ ((debug_flag & CNAT_DEBUG_ALL) == CNAT_DEBUG_NONE))) {
+ mp->rc = CNAT_ERR_PARSER;
+ PLATFORM_DEBUG_PRINT("invalid debug ovrf 0x%x flag 0x%x "
+ "start addr 0x%x end addr 0x%x\n",
+ o_vrf, debug_flag,
+ start_addr, end_addr);
+ return;
+ }
+
+ mp->rc = CNAT_SUCCESS;
+ debug_o_vrf = o_vrf;
+ debug_o_flag = debug_flag;
+ debug_o_addr_start = start_addr;
+ debug_o_addr_end = end_addr;
+
+ PLATFORM_DEBUG_PRINT(" o2i debug currently is not supported\n");
+}
+
+void nat64_reset_session_expiry(nat64_bib_entry_t *db)
+{
+ NAT64_STFUL_DEBUG_PRINT(3, " invoking nat64_clean_bib_db_entry\n " );
+ nat64_clean_bib_db_entry(db);
+ NAT64_STFUL_DEBUG_PRINT(3, "done with clean_bib_db_entry\n " );
+}
+
+void spp_api_nat64_clear_db_request_t_handler
+(spp_api_nat64_clear_db_request_t *mp)
+{
+ u16 port, proto, flag;
+ u32 index;
+ u32 i;
+ nat64_bib_entry_t* db;
+ nat64_v6_key_t ki;
+ nat64_table_entry_t *my_nat64_table_db_ptr;
+ u16 nat64_id;
+
+ NAT64_STFUL_FUNC_ENTER;
+ NAT64_STFUL_DEBUG_DUMP_MSG(mp);
+
+ nat64_id = spp_net_to_host_byte_order_16(&mp->nat64_id);
+ my_nat64_table_db_ptr = nat64_table_ptr + nat64_id;
+
+ port = spp_net_to_host_byte_order_16(&mp->port_num);
+ proto = mp->protocol;
+
+ ki.vrf = nat64_id;
+ ki.vrf |= ((u16)proto << CNAT_PRO_SHIFT);
+
+ for(i =0 ; i< 4 ; i++)
+ ki.ipv6[i] = spp_net_to_host_byte_order_32(&mp->ip_addr[i]);
+
+ ki.port = port;
+
+ flag = mp->flags;
+
+ mp->rc = CNAT_SUCCESS;
+
+ NAT64_STFUL_DEBUG_PRINT(3, "\n Nat64_id = %d, port =%d, \
+ proto =%d, flags=0x%08X",\
+ nat64_id, port, proto, flag);
+
+ NAT64_STFUL_DEBUG_PRINT(3, "\n IPv6 Addr = %08X : %08X: %08X: %08X",\
+ ki.ipv6[0], ki.ipv6[1], ki.ipv6[2], ki.ipv6[3]);
+
+ if (flag == CNAT_DB_CLEAR_SPECIFIC) {
+ NAT64_STFUL_DEBUG_PRINT(3, "\n clear specific \n");
+
+ db = nat64_bib_db_lookup_entry(&ki);
+ if (db == NULL) {
+ NAT64_STFUL_DEBUG_PRINT(3, "\n clear specific - not present\n");
+ mp->rc = CNAT_NOT_FOUND_ANY;
+ return;
+ }
+
+ if( !(db->flags & CNAT_DB_NAT64_FLAG) ||
+ (db->nat64_inst_id != nat64_id))
+ return;
+
+
+ nat64_reset_session_expiry(db);
+ return;
+ }
+
+ pool_header_t *p = pool_header(nat64_bib_db);
+
+ for(index = 0; index < vec_len(nat64_bib_db); index++) {
+
+ /* check is it nat44, if yes skip , do it n nat44 as well */
+
+ if (PREDICT_FALSE(!clib_bitmap_get(p->free_bitmap, index))) {
+ db = nat64_bib_db + index;
+
+ if( !(db->flags & CNAT_DB_NAT64_FLAG) ||
+ (db->nat64_inst_id != nat64_id))
+ continue;
+
+ if (flag == CNAT_DB_CLEAR_ALL) {
+ nat64_reset_session_expiry(db);
+ continue;
+ }
+
+ if (flag & CNAT_DB_CLEAR_ADDR) {
+ if ((db->v6_in_key.ipv6[0] != ki.ipv6[0]) ||
+ (db->v6_in_key.ipv6[1] != ki.ipv6[1]) ||
+ (db->v6_in_key.ipv6[2] != ki.ipv6[2]) ||
+ (db->v6_in_key.ipv6[3] != ki.ipv6[3])){
+ NAT64_STFUL_DEBUG_PRINT(3, "\n%s:%d\n", __FUNCTION__, \
+ __LINE__ );
+ continue;
+ }
+ }
+
+ if (flag & CNAT_DB_CLEAR_PROTO) {
+ if (((db->v6_in_key.vrf & CNAT_PRO_MASK) >> CNAT_PRO_SHIFT)
+ != proto) {
+ NAT64_STFUL_DEBUG_PRINT(3, "\n%s:%d\n", __FUNCTION__, \
+ __LINE__ );
+ continue;
+ }
+ }
+
+ if (flag & CNAT_DB_CLEAR_PORT) {
+ if (db->v6_in_key.port != port) {
+ NAT64_STFUL_DEBUG_PRINT(3, "\n%s:%d\n", __FUNCTION__, \
+ __LINE__ );
+ continue;
+ }
+ }
+
+ NAT64_STFUL_DEBUG_PRINT(3, "\n%s:%d\n", __FUNCTION__, \
+ __LINE__ );
+ /*
+ * Delete if the db entry matches and it is not a
+ */
+ nat64_reset_session_expiry(db);
+ }
+ }
+}
+
+void inline cnat_clear_session_db(cnat_main_db_entry_t *db)
+{
+ if(PREDICT_FALSE(db->nsessions > 1)) {
+ u32 session_index = db->session_head_index;
+ cnat_session_entry_t *sdb;
+ do {
+ sdb = cnat_session_db + session_index;
+ if(PREDICT_FALSE(!sdb)) {
+ //TO DO: Debug msg?
+ break;
+ }
+ sdb->entry_expires = 0;
+ session_index = sdb->main_list.next;
+ } while(session_index != db->session_head_index
+ && db->session_head_index != EMPTY);
+ }
+ return;
+}
+
+#ifdef CGSE_DS_LITE
+extern dslite_table_entry_t dslite_table_array[];
+
+void spp_api_ds_lite_clear_db_request_t_handler
+(spp_api_ds_lite_clear_db_request_t *mp)
+{
+ u16 port, proto, flag;
+ u32 index;
+ u32 i;
+ cnat_main_db_entry_t *db;
+ cnat_user_db_entry_t *udb;
+ dslite_key_t ki;
+ dslite_table_entry_t *my_table_db_ptr;
+ u16 id;
+ u16 i_vrf;
+
+
+ id = spp_net_to_host_byte_order_16(&mp->ds_lite_id);
+ id = DS_LITE_CONFIG_TO_ARRAY_ID(id);
+
+ my_table_db_ptr = &dslite_table_array[id];
+ i_vrf = my_table_db_ptr->i_vrf;
+
+ port = spp_net_to_host_byte_order_16(&mp->port_num);
+ proto = mp->protocol;
+
+ ki.ipv4_key.k.vrf = i_vrf;
+ ki.ipv4_key.k.vrf |= ((u16)proto << CNAT_PRO_SHIFT);
+
+ for(i =0 ; i< 4 ; i++)
+ ki.ipv6[i] = spp_net_to_host_byte_order_32(&mp->ip_addr[i]);
+
+ ki.ipv4_key.k.port = port;
+
+ flag = mp->flags;
+
+ mp->rc = CNAT_SUCCESS;
+
+ DSLITE_PRINTF(3, "\n dslite id = %d, port =%d"
+ "proto =%d, flags=0x%08X",\
+ id, port, proto, flag);
+
+ DSLITE_PRINTF(3, "\n IPv6 Addr = %08X : %08X: %08X: %08X",\
+ ki.ipv6[0], ki.ipv6[1], ki.ipv6[2], ki.ipv6[3]);
+
+ if (flag == CNAT_DB_CLEAR_SPECIFIC) {
+ DSLITE_PRINTF(3, "\n Clear specific NOT supported for DS Lite \n");
+ return;
+ }
+
+ pool_header_t *p = pool_header(cnat_main_db);
+
+ for(index = 0; index < vec_len(cnat_main_db); index++) {
+
+ /* check is it dslite entry, if not skip */
+
+ if (PREDICT_FALSE(!clib_bitmap_get(p->free_bitmap, index))) {
+ db = cnat_main_db + index;
+
+ if( !(db->flags & CNAT_DB_DSLITE_FLAG) ||
+ ((db->in2out_key.k.vrf & CNAT_VRF_MASK) != i_vrf) ||
+ (db->flags & CNAT_DB_FLAG_STATIC_PORT)) {
+ continue;
+ }
+
+ if (flag == CNAT_DB_CLEAR_ALL) {
+
+ /*
+ * Make the entry time as very old (0), and wait
+ * for a timeout to auto-expire the entry.
+ */
+ db->entry_expires = 0;
+ /* Handle sessions as well.. */
+ cnat_clear_session_db(db);
+ continue;
+ }
+
+ if (flag & CNAT_DB_CLEAR_ADDR) {
+ udb = cnat_user_db + db->user_index;
+ if(PREDICT_FALSE(!udb)) {
+ continue;
+ }
+ if ((udb->ipv6[0] != ki.ipv6[0]) ||
+ (udb->ipv6[1] != ki.ipv6[1]) ||
+ (udb->ipv6[2] != ki.ipv6[2]) ||
+ (udb->ipv6[3] != ki.ipv6[3])) {
+ continue;
+ }
+ }
+
+ if (flag & CNAT_DB_CLEAR_PROTO) {
+ if (((db->in2out_key.k.vrf & CNAT_PRO_MASK) >> CNAT_PRO_SHIFT)
+ != proto) {
+ continue;
+ }
+ }
+
+ if (flag & CNAT_DB_CLEAR_PORT) {
+ if (db->in2out_key.k.port != port) {
+ continue;
+ }
+ }
+
+ /*
+ * Mark for expiry in the next round of DB scan
+ */
+ db->entry_expires = 0;
+ /* Handle sessions as well.. */
+ cnat_clear_session_db(db);
+ }
+ }
+}
+#endif /* #ifdef CGSE_DS_LITE */
+
+void spp_api_cnat_clear_db_request_t_handler
+(spp_api_cnat_clear_db_request_t *mp)
+{
+ u16 i_vrf, port, proto, flag;
+ u32 ip_addr, index;
+ u64 a,b,c;
+ cnat_main_db_entry_t * db;
+ cnat_db_key_bucket_t ki;
+
+#if defined(TARGET_LINUX_UDVR) || defined(CNAT_PG)
+ i_vrf = mp->inside_vrf;
+ ip_addr = mp->ip_addr;
+ port = mp->port_num;
+ proto = mp->protocol;
+#else
+ i_vrf = spp_net_to_host_byte_order_16(&mp->inside_vrf);
+ ip_addr = spp_net_to_host_byte_order_32(&mp->ip_addr);
+ port = spp_net_to_host_byte_order_16(&mp->port_num);
+ proto = spp_net_to_host_byte_order_16(&mp->protocol);
+#endif
+
+
+
+ ki.k.k.vrf = i_vrf;
+ ki.k.k.vrf |= ((u16)proto << CNAT_PRO_SHIFT);
+ ki.k.k.ipv4 = ip_addr;
+ ki.k.k.port = port;
+
+ flag = mp->wildcard;
+
+ mp->rc = CNAT_SUCCESS;
+
+ if (flag == CNAT_DB_CLEAR_SPECIFIC) {
+ CNAT_V4_GET_HASH(ki.k.key64,
+ ki.bucket,
+ CNAT_MAIN_HASH_MASK);
+ index = cnat_in2out_hash[ki.bucket].next;
+ if (PREDICT_TRUE(index == EMPTY)) {
+ mp->rc = CNAT_NOT_FOUND_ANY;
+ return;
+ }
+
+ do {
+ db = cnat_main_db + index;
+
+ /*
+ * Delete if the db entry matches and it is not a
+ * STATIC port entry
+ */
+ if ((db->in2out_key.key64 == ki.k.key64) &&
+ !(db->flags & CNAT_DB_FLAG_STATIC_PORT) &&
+ !(db->flags & CNAT_DB_NAT64_FLAG) &&
+ !(db->flags & CNAT_DB_DSLITE_FLAG)) {
+
+ /*
+ * Make the entry time as very old (0), and wait
+ * for a timeout to auto-expire the entry.
+ */
+ db->entry_expires = 0;
+ /* Handle sessions as well.. */
+ cnat_clear_session_db(db);
+ return;
+ }
+ index = db->in2out_hash.next;
+ } while (index != EMPTY);
+
+ mp->rc = CNAT_NOT_FOUND_ANY;
+ return;
+ }
+
+ pool_header_t *p = vec_header(cnat_main_db, sizeof(pool_header_t));
+
+ for(index = 0; index < vec_len(cnat_main_db); index++) {
+
+ if (PREDICT_TRUE(!clib_bitmap_get(p->free_bitmap, index))) {
+ db = cnat_main_db + index;
+
+ if(PREDICT_FALSE(db->flags & CNAT_DB_NAT64_FLAG)) {
+ continue;
+ }
+
+ if(PREDICT_FALSE(db->flags & CNAT_DB_DSLITE_FLAG)) {
+ continue;
+ }
+
+ if (flag == CNAT_DB_CLEAR_ALL) {
+ if (!(db->flags & CNAT_DB_FLAG_STATIC_PORT)) {
+ db->entry_expires = 0;
+ /* Handle sessions as well.. */
+ cnat_clear_session_db(db);
+ }
+ continue;
+ }
+
+ if (flag & CNAT_DB_CLEAR_VRF) {
+ if (((db->in2out_key.k.vrf & CNAT_VRF_MASK) != i_vrf)) {
+ continue;
+ }
+ }
+
+ if (flag & CNAT_DB_CLEAR_ADDR) {
+ if ((db->in2out_key.k.ipv4 != ip_addr)) {
+ continue;
+ }
+ }
+
+ if (flag & CNAT_DB_CLEAR_PROTO) {
+ if (((db->in2out_key.k.vrf & CNAT_PRO_MASK) >> CNAT_PRO_SHIFT)
+ != proto) {
+ continue;
+ }
+ }
+
+ if (flag & CNAT_DB_CLEAR_PORT) {
+ if (db->in2out_key.k.port != port) {
+ continue;
+ }
+ }
+
+ /*
+ * Delete if the db entry matches and it is not a
+ * STATIC port entry
+ */
+ if (!(db->flags & CNAT_DB_FLAG_STATIC_PORT)) {
+ db->entry_expires = 0;
+ /* Handle sessions as well.. */
+ cnat_clear_session_db(db);
+ }
+ }
+ }
+}
+
+void
+spp_api_cnat_generic_command_debug (cnat_generic_command_resp *mp_resp)
+{
+#ifdef SHOW_DEBUG
+ u32 i, j;
+
+ i = spp_net_to_host_byte_order_32(&(mp_resp->num_bytes));
+
+ PLATFORM_DEBUG_PRINT("\nNum_Bytes %d\n", i);
+
+ for (j = 0; j < i; j++) {
+ PLATFORM_DEBUG_PRINT("0x%02X ", mp_resp->raw_data[j]);
+ if ((j % 16) == 15) {
+ PLATFORM_DEBUG_PRINT("\n");
+ }
+ }
+#endif
+}
+
+/*
+ * The following commands implements command to dump the
+ * user-db information
+ * port-map information
+ * for a give user source IP address
+ *
+ * The format of the output is:
+ * Word 0: Address of udb
+ * Word 1: udb->translation_list_head_index
+ * Word 2:
+ * Bytes 0..1: udb->ntranslations
+ * Bytes 2..2: udb->icmp_msg_coung
+ * Bytes 3..3: udb->unused
+ * Word 3: udb->portmap_index
+ * Word 4: udb->key.k.ipv4
+ * Word 5:
+ * Bytes 0..1: udb->key.k.port = 0
+ * Bytes 2..3: udb->key.k.vrf
+ * Word 6: udb->user_hash
+ * Word 7: Address of my_pm
+ * Word 8: my_pm->status
+ * Word 9: my_pm->inuse
+ * Word A: my_pm->delete_time
+ * Word B: my_pm->ipv4_address
+ */
+void spp_api_cnat_generic_command_user_db_pm
+(spp_api_cnat_generic_command_request_t *mp)
+{
+ u32 i;
+ cnat_db_key_bucket_t u_ki;
+ u16 my_vrfmap_index;
+ u32 *result_array;
+ cnat_generic_command_resp *mp_resp;
+ cnat_user_db_entry_t *udb;
+ cnat_user_db_entry_t *mp_udb;
+ cnat_vrfmap_t *my_vrfmap;
+ cnat_portmap_v2_t *pm;
+ cnat_portmap_v2_t *my_pm;
+
+ /*
+ * Request structure is used to send the response
+ */
+ mp_resp = (cnat_generic_command_resp *) mp;
+
+ u_ki.k.k.vrf = spp_net_to_host_byte_order_32(&mp->params[1]);
+ u_ki.k.k.ipv4 = spp_net_to_host_byte_order_32(&mp->params[2]);
+ u_ki.k.k.port = 0;
+
+ udb = cnat_user_db_lookup_entry(&u_ki);
+
+ if (!udb) {
+ mp_resp->num_bytes = spp_host_to_net_byte_order_32(0);
+ goto no_udb_found;
+ }
+
+ result_array = (u32 *) (&(mp_resp->raw_data[0]));
+
+ i = 0;
+ result_array[i++] = spp_host_to_net_byte_order_32((u32) udb);
+
+ mp_udb = (cnat_user_db_entry_t *) &(result_array[i]);
+
+ /*
+ * Align the entry to the next 4 byte boundary
+ */
+ i = i + ((sizeof(cnat_user_db_entry_t)+3)/4);
+
+ /*
+ * Fill in the UDB information
+ */
+ mp_udb->translation_list_head_index =
+ spp_host_to_net_byte_order_32(udb->translation_list_head_index);
+ mp_udb->ntranslations =
+ spp_host_to_net_byte_order_16(udb->ntranslations);
+ mp_udb->icmp_msg_count = udb->icmp_msg_count;
+ mp_udb->flags = udb->flags;
+ mp_udb->portmap_index =
+ spp_host_to_net_byte_order_32(udb->portmap_index);
+ mp_udb->key.k.ipv4 =
+ spp_host_to_net_byte_order_32(udb->key.k.ipv4);
+ mp_udb->key.k.port =
+ spp_host_to_net_byte_order_16(udb->key.k.port);
+ mp_udb->key.k.vrf =
+ spp_host_to_net_byte_order_16(udb->key.k.vrf);
+ mp_udb->user_hash.next =
+ spp_host_to_net_byte_order_32(udb->user_hash.next);
+
+ my_vrfmap_index = vrf_map_array[u_ki.k.k.vrf];
+ my_vrfmap = cnat_map_by_vrf + my_vrfmap_index;
+ pm = my_vrfmap->portmap_list;
+ my_pm = pm + udb->portmap_index;
+
+ /*
+ * Fill in the port_map information
+ */
+ result_array[i++] = spp_host_to_net_byte_order_32((u32) my_pm);
+ result_array[i++] = spp_host_to_net_byte_order_32(my_pm->inuse);
+ result_array[i++] = spp_host_to_net_byte_order_32(my_pm->delete_time);
+ result_array[i++] = spp_host_to_net_byte_order_32(my_pm->ipv4_address);
+
+ mp_resp->num_bytes = spp_host_to_net_byte_order_32(i*4);
+
+no_udb_found:
+ spp_api_cnat_generic_command_debug(mp_resp);
+}
+
+/*
+ * The following commands implements command to dump the
+ * DB usage stats for
+ * main-db
+ * user-db
+ * in2out hash
+ * out2in hash
+ *
+ * The format of the output is:
+ * Word 0: Main-DB - Total
+ * Word 1: Main-DB - Active
+ * Word 2: Main-DB - Free
+ * Word 3: User-DB - Total
+ * Word 4: User-DB - Active
+ * Word 5: User-DB - Free
+ * Word 6: Hash In2Out - Size
+ * Word 7: Hash In2Out - Used
+ * Word 8: Hash In2Out - Used Percentage
+ * Word 9: Hash Out2In - Size
+ * Word A: Hash Out2In - Used
+ * Word B: Hash Out2In - Used Percentage
+ */
+void spp_api_cnat_generic_command_db_summary
+(spp_api_cnat_generic_command_request_t *mp)
+{
+ u32 count1, count2, count3;
+ u32 i = 0;
+ u32 k = 0;
+ cnat_generic_command_resp *mp_resp;
+ u32 *result_array;
+
+ /*
+ * Request structure is used to send the response
+ */
+ mp_resp = (cnat_generic_command_resp *) mp;
+ result_array = (u32 *) (&(mp_resp->raw_data[0]));
+
+ /*
+ * Find entries free and used in main-db
+ */
+ count1 = vec_len(cnat_main_db);
+ count2 = db_free_entry(cnat_main_db);
+ count3 = count1 - count2;
+
+ *(result_array + i++) = spp_host_to_net_byte_order_32(count1);
+ *(result_array + i++) = spp_host_to_net_byte_order_32(count3);
+ *(result_array + i++) = spp_host_to_net_byte_order_32(count2);
+
+ /*
+ * Find entries free and used in user-db
+ */
+ count1 = vec_len(cnat_user_db);
+ count2 = db_free_entry(cnat_user_db);
+ count3 = count1 - count2;
+
+ *(result_array + i++) = spp_host_to_net_byte_order_32(count1);
+ *(result_array + i++) = spp_host_to_net_byte_order_32(count3);
+ *(result_array + i++) = spp_host_to_net_byte_order_32(count2);
+
+ /*
+ * Find entries used in in2out and out2in hash tables
+ * and percentage utilization.
+ */
+ count1 = count2 = 0;
+ for (k = 0; k < CNAT_MAIN_HASH_SIZE; k++) {
+ if(cnat_in2out_hash[k].next != ~0) count1++;
+ if(cnat_out2in_hash[k].next != ~0) count2++;
+
+ }
+
+ count3 = count1*100/CNAT_MAIN_HASH_SIZE;
+
+ *(result_array + i++) = spp_host_to_net_byte_order_32(CNAT_MAIN_HASH_SIZE);
+ *(result_array + i++) = spp_host_to_net_byte_order_32(count1);
+ *(result_array + i++) = spp_host_to_net_byte_order_32(count3);
+
+ count3 = count2*100/CNAT_MAIN_HASH_SIZE;
+
+ *(result_array + i++) = spp_host_to_net_byte_order_32(CNAT_MAIN_HASH_SIZE);
+ *(result_array + i++) = spp_host_to_net_byte_order_32(count2);
+ *(result_array + i++) = spp_host_to_net_byte_order_32(count3);
+
+ mp_resp->num_bytes = spp_host_to_net_byte_order_32(i*4);
+
+ spp_api_cnat_generic_command_debug(mp_resp);
+}
+
+/*
+ * The following commands implements generic commands such as:
+ *
+ * Command 1:
+ * Reads num_bytes octets from a start_locn
+ * generic command <core_num> <cmd_type=1> <start_locn> <num_bytes> 0 0 0 0 0
+ *
+ * Command 2:
+ * Writes upto 8 octets from a start_locn
+ * generic command <core_num> <cmd_type=2> <start_locn> <num_bytes> 0 0 0 0 0
+ *
+ * Command 3:
+ * Dump the db summary stats
+ * generic command <core_num> <cmd_type=3>
+ *
+ * Command 4:
+ * Dump the user db entry
+ * generic command <core_num> <cmd_type=4> <vrf_id> <src_ip_addr>
+ *
+ * The following structures are referenced by this command:
+ * typedef struct _spp_api_cnat_generic_command_request {
+ * u16 _spp_msg_id;
+ * u8 rc;
+ * u8 core_num;
+ * u32 params[8];
+ * } spp_api_cnat_generic_command_request_t;
+ *
+ * typedef struct {
+ * u16 spp_msg_id;
+ * u8 rc;
+ * u8 core;
+ * u32 num_bytes;
+ * u8 raw_data[0];
+ * } cnat_generic_command_resp;
+ *
+ */
+void spp_api_cnat_generic_command_request_t_handler
+(spp_api_cnat_generic_command_request_t *mp)
+{
+ cnat_generic_command_resp *resp_ptr;
+ u32 command_type, start_locn, num_bytes;
+
+ command_type = spp_net_to_host_byte_order_32(&mp->params[0]);
+ resp_ptr = (cnat_generic_command_resp *) mp;
+
+ switch (command_type) {
+ case CNAT_DEBUG_GENERIC_COMMAND_READ_MEM:
+ start_locn = spp_net_to_host_byte_order_32(&mp->params[1]);
+ num_bytes = spp_net_to_host_byte_order_32(&mp->params[2]);
+ clib_memcpy(&(resp_ptr->raw_data[0]), (u8 *) start_locn, num_bytes);
+ resp_ptr->num_bytes = spp_host_to_net_byte_order_32(num_bytes);
+
+#ifdef SHOW_DEBUG
+ {
+ u32 i;
+
+ for (i = 0; i < num_bytes; i++) {
+ PLATFORM_DEBUG_PRINT("0x%02X ", resp_ptr->raw_data[i]);
+ if ((i % 16) == 15) {
+ PLATFORM_DEBUG_PRINT("\n");
+ }
+ }
+ }
+#endif
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_WRITE_MEM:
+ start_locn = spp_net_to_host_byte_order_32(&mp->params[1]);
+ num_bytes = spp_net_to_host_byte_order_32(&mp->params[2]);
+
+ if (num_bytes > sizeof(u64)) {
+ mp->rc = CNAT_ERR_INVALID_MSG_SIZE;
+ return;
+ }
+
+ clib_memcpy((u8 *) start_locn, &(mp->params[3]), num_bytes);
+ resp_ptr->num_bytes = 0;
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_DB_SUMMARY:
+ spp_api_cnat_generic_command_db_summary(mp);
+ break;
+
+ case CNAT_DEBUG_GENERIC_COMMAND_USER_DB_PM:
+ spp_api_cnat_generic_command_user_db_pm(mp);
+ break;
+
+ case CNAT_DEBUG_GET_CGN_DB_SUMMARY:
+ spp_api_cnat_get_cgn_db_summary(mp);
+ break;
+
+ default:
+ mp->rc = CNAT_ERR_INVALID_MSG_ID;
+ break;
+ }
+}
+
+
+static int cnat_debug_init (void *notused)
+{
+ spp_msg_api_set_handler(SPP_API_CNAT_V4_DEBUG_DUMMY,
+ spp_api_cnat_v4_debug_dummy_t_handler);
+
+ spp_msg_api_set_handler(SPP_API_CNAT_V4_DEBUG_DUMMY_MAX,
+ spp_api_cnat_v4_debug_dummy_max_t_handler);
+
+ spp_msg_api_set_handler(SPP_API_CNAT_V4_DEBUG_GLOBAL,
+ spp_api_cnat_v4_debug_global_t_handler);
+
+ spp_msg_api_set_handler(SPP_API_CNAT_V4_DEBUG_IN2OUT_PRIVATE_ADDR,
+ spp_api_cnat_v4_debug_in2out_private_addr_t_handler);
+
+ spp_msg_api_set_handler(SPP_API_CNAT_V4_DEBUG_OUT2IN_PUBLIC_ADDR,
+ spp_api_cnat_v4_debug_out2in_public_addr_t_handler);
+
+ spp_msg_api_set_handler(SPP_API_CNAT_CLEAR_DB_REQUEST,
+ spp_api_cnat_clear_db_request_t_handler);
+
+ spp_msg_api_set_handler(SPP_API_CNAT_GENERIC_COMMAND_REQUEST,
+ spp_api_cnat_generic_command_request_t_handler);
+
+ spp_msg_api_set_handler(SPP_API_CNAT_P2MP_DEBUG_REQUEST,
+ spp_api_cnat_p2mp_debug_request_t_handler);
+
+ spp_msg_api_set_handler(SPP_API_NAT64_CLEAR_DB_REQUEST,
+ spp_api_nat64_clear_db_request_t_handler);
+
+ spp_msg_api_set_handler(SPP_API_DS_LITE_CLEAR_DB_REQUEST,
+ spp_api_ds_lite_clear_db_request_t_handler);
+
+ return 0;
+}
+
+/*
+************************
+* spp_api_cnat_get_cgn_db_summary
+* This is for finding out the per core CPU users and utilization
+************************
+*/
+
+void spp_api_cnat_get_cgn_db_summary
+(spp_api_cnat_generic_command_request_t *mp)
+{
+ u32 total_db_entries, total_free_entries, used_entries;
+ u32 i = 0;
+ cnat_generic_command_resp *mp_resp;
+ u32 *result_array;
+
+ /*
+ * Request structure is used to send the response
+ */
+ mp_resp = (cnat_generic_command_resp *) mp;
+ result_array = (u32 *) (&(mp_resp->raw_data[0]));
+
+ /*
+ * Find entries free and used in main-db
+ */
+ total_db_entries = vec_len(cnat_main_db);
+ total_free_entries = db_free_entry(cnat_main_db);
+ used_entries = total_db_entries - total_free_entries;
+
+ *(result_array + i++) = spp_host_to_net_byte_order_32(total_db_entries);
+ *(result_array + i++) = spp_host_to_net_byte_order_32(used_entries);
+ *(result_array + i++) = spp_host_to_net_byte_order_32(total_free_entries);
+
+ /*
+ * Find entries free and used in user-db
+ */
+ total_db_entries = vec_len(cnat_user_db);
+ total_free_entries = db_free_entry(cnat_user_db);
+ used_entries = total_db_entries - total_free_entries;
+
+ *(result_array + i++) = spp_host_to_net_byte_order_32(total_db_entries);
+ *(result_array + i++) = spp_host_to_net_byte_order_32(used_entries);
+ *(result_array + i++) = spp_host_to_net_byte_order_32(total_free_entries);
+
+ mp_resp->num_bytes = spp_host_to_net_byte_order_32(i*sizeof(u32));
+}
+
+SPP_INIT_FUNCTION(cnat_debug_init);
+#endif /* TOBE_PORTED */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_global.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_global.c
new file mode 100644
index 00000000..71770834
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_global.c
@@ -0,0 +1,79 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_global.c - global variables
+ *
+ * Copyright (c) 2008-2009, 2012 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+/* gloable variables */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/error.h>
+#include <vnet/buffer.h>
+
+#include "dslite_defs.h"
+#include "tcp_header_definitions.h"
+u32 cnat_current_time;
+u8 nfv9_configured = 0;
+/* ctx/sf alloc error counters */
+u32 null_enq_pkt;
+u32 null_deq_pkt;
+
+u32 null_enq_ctx;
+u32 null_deq_ctx;
+
+u32 null_enq_wqe;
+u32 null_deq_wqe;
+
+u32 ctx_alloc_errs;
+u32 sf_alloc_errs;
+
+u32 rcv_pkt_errs;
+
+/* TOBE_PORTED : Remove following once we bring DSLite */
+u32 dslite_config_debug_level = 1;
+u32 dslite_data_path_debug_level = 1;
+u32 dslite_defrag_debug_level = 1;
+u32 dslite_debug_level = 1;
+
+dslite_table_entry_t *dslite_table_db_ptr;
+
+/*
+ * ipv4_decr_ttl_n_calc_csum()
+ * - It decrements the TTL and calculates the incremental IPv4 checksum
+ */
+
+/* TOBE_PORTED: Following is in cnat_util.c */
+always_inline __attribute__((unused))
+void ipv4_decr_ttl_n_calc_csum(ipv4_header *ipv4)
+{
+ u32 checksum;
+ u16 old;
+ u16 ttl;
+
+ ttl = ipv4->ttl;
+ old = clib_net_to_host_u16(ttl);
+
+ /* Decrement TTL */
+ ipv4->ttl--;
+
+ /* Calculate incremental checksum */
+ checksum = old + (~clib_net_to_host_u16(ttl) & 0xFFFF);
+ checksum += clib_net_to_host_u16(ipv4->checksum);
+ checksum = (checksum & 0xFFFF) + (checksum >> 16);
+ ipv4->checksum = clib_host_to_net_u32(checksum + (checksum >> 16));
+}
+
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_global.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_global.h
new file mode 100644
index 00000000..823a4797
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_global.h
@@ -0,0 +1,87 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_global.h - global definition and variables
+ * to be used by non cnat files
+ *
+ * Copyright (c) 2007-2012 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_GLOBAL_H__
+#define __CNAT_GLOBAL_H__
+
+/* gloable variables */
+
+extern u8 cnat_db_init_done;
+extern u32 cnat_current_time;
+extern u64 in2out_drops_port_limit_exceeded;
+extern u64 in2out_drops_system_limit_reached;
+extern u64 in2out_drops_resource_depletion;
+extern u64 no_translation_entry_drops;
+extern u8 nfv9_configured;
+extern u32 translation_create_count;
+extern u32 translation_create_rate;
+
+extern u32 translation_delete_count;
+extern u32 translation_delete_rate;
+
+extern u32 in2out_forwarding_count;
+extern u32 in2out_forwarding_rate;
+
+extern u32 out2in_forwarding_count;
+extern u32 out2in_forwarding_rate;
+
+extern u32 total_address_pool_allocated;
+
+extern u32 nat44_active_translations;
+
+#if 1 //DSLITE_DEF
+extern u32 dslite_translation_create_rate;
+extern u32 dslite_translation_delete_rate;
+extern u32 dslite_translation_create_count;
+extern u32 dslite_in2out_forwarding_count;
+extern u32 dslite_in2out_forwarding_count;
+extern u32 dslite_out2in_forwarding_rate;
+#endif
+/* sf/ctx allocation error collection declarations */
+#define COLLECT_FREQ_FACTOR 100
+#define NUM_SECONDS_TO_WAIT 10
+#define COUNTER_BUFFER_SIZE 25
+
+extern u32 null_enq_pkt;
+extern u32 null_deq_pkt;
+
+extern u32 null_enq_ctx;
+extern u32 null_deq_ctx;
+
+extern u32 null_enq_wqe;
+extern u32 null_deq_wqe;
+
+extern u32 ctx_alloc_errs;
+extern u32 sf_alloc_errs;
+
+extern u32 rcv_pkt_errs;
+
+struct counter_array_t {
+ u32 sf_error_counter;
+ u32 ctx_error_counter;
+ u32 timestamp;
+} counter_array_t;
+
+#define COUNTER_BUFFER_SIZE 25
+struct counter_array_t err_cnt_arr[COUNTER_BUFFER_SIZE];
+
+//#define DISABLE_ICMP_THROTTLE_FOR_DEBUG_PURPOSE
+
+#endif /*__CNAT_GLOBAL_H__*/
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp.h
new file mode 100644
index 00000000..664b62ac
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp.h
@@ -0,0 +1,60 @@
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Filename: cnat_ipv4_icmp.h
+ *
+ * Description: common functions for icmp node
+ *
+ * Assumptions and Constraints:
+ *
+ * Copyright (c) 2000-2009, 2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-----------------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_IPV4_ICMP_H__
+#define __CNAT_IPV4_ICMP_H__
+
+#include "tcp_header_definitions.h"
+#include "cnat_db.h"
+#include "cnat_v4_functions.h"
+#include "cnat_global.h"
+#include "cnat_config.h"
+
+typedef struct {
+ icmp_v4_t *icmp;
+ ipv4_header *em_ip;
+ u16 *em_port;
+ u16 *em_l4_checksum;
+} icmp_em_ip_info;
+
+extern void swap_ip_src_icmp_id(ipv4_header *ip,
+ icmp_v4_t *icmp,
+ cnat_main_db_entry_t *db,
+ u16 vrf);
+
+extern void swap_ip_dst_icmp_id(ipv4_header *ip,
+ icmp_v4_t *icmp,
+ cnat_main_db_entry_t *db,
+ u16 vrf);
+
+extern void swap_ip_src_emip_dst(ipv4_header *ip,
+ icmp_em_ip_info *icmp_info,
+ cnat_main_db_entry_t *db, u16 vrf);
+
+extern void swap_ip_dst_emip_src(ipv4_header *ip,
+ icmp_em_ip_info *icmp_info,
+ cnat_main_db_entry_t *db, u16 vrf);
+
+
+#endif /* __CNAT_IPV4_ICMP_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_error_inside_input.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_error_inside_input.c
new file mode 100644
index 00000000..218d7e53
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_error_inside_input.c
@@ -0,0 +1,476 @@
+/*
+ *---------------------------------------------------------------------------
+ * cnat_ipv4_icmp_error_inside_input.c - cnat_ipv4_icmp_error_inside_input node pipeline stage functions
+ *
+ * Copyright (c) 2008-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/error.h>
+#include <vnet/buffer.h>
+
+#include "cnat_ipv4_icmp.h"
+
+#define foreach_cnat_ipv4_icmp_e_inside_input_error \
+_(CNAT_V4_ICMP_E_I2O_T_PKT, "cnat v4 icmp_e i2o packet transmit") \
+_(CNAT_V4_ICMP_E_I2O_D_PKT, "cnat v4 icmp_e i2o packet drop") \
+_(CNAT_V4_ICMP_E_I2O_TTL_DROP, "cnat v4 icmp_e i2o ttl drop")
+
+typedef enum {
+#define _(sym,str) sym,
+ foreach_cnat_ipv4_icmp_e_inside_input_error
+#undef _
+ CNAT_IPV4_ICMP_E_INSIDE_INPUT_N_ERROR,
+} cnat_ipv4_icmp_e_inside_input_t;
+
+static char * cnat_ipv4_icmp_e_inside_input_error_strings[] = {
+#define _(sym,string) string,
+ foreach_cnat_ipv4_icmp_e_inside_input_error
+#undef _
+};
+
+typedef struct {
+ u32 cached_next_index;
+ /* $$$$ add data here */
+
+ /* convenience variables */
+ vlib_main_t * vlib_main;
+ vnet_main_t * vnet_main;
+} cnat_ipv4_icmp_e_inside_input_main_t;
+
+typedef enum {
+ CNAT_V4_ICMP_E_I2O_T,
+ CNAT_V4_ICMP_E_I2O_D,
+ CNAT_V4_ICMP_E_I2O_NEXT,
+} cnat_ipv4_icmp_e_inside_input_next_t;
+
+cnat_ipv4_icmp_e_inside_input_main_t cnat_ipv4_icmp_e_inside_input_main;
+vlib_node_registration_t cnat_ipv4_icmp_e_inside_input_node;
+
+#define NSTAGES 5
+
+inline void swap_ip_src_emip_dst(ipv4_header *ip,
+ icmp_em_ip_info *icmp_info,
+ cnat_main_db_entry_t *db, u16 vrf)
+{
+ icmp_v4_t *icmp;
+ ipv4_header *em_ip;
+ u16 *em_port;
+ u32 old_ip;
+ u16 old_port;
+ u16 old_ip_checksum;
+
+ /*
+ * declear variable
+ */
+ CNAT_UPDATE_L3_CHECKSUM_DECLARE
+ CNAT_UPDATE_ICMP_ERR_CHECKSUM_DECLARE
+
+ /*
+ * fix inner layer ip & l4 checksum
+ */
+ em_ip = icmp_info->em_ip;
+ em_port = icmp_info->em_port;
+
+ CNAT_UPDATE_L3_CHECKSUM(((u16)(db->in2out_key.k.ipv4)),
+ ((u16)(db->in2out_key.k.ipv4 >> 16)),
+ (clib_net_to_host_u16(em_ip->checksum)),
+ ((u16)(db->out2in_key.k.ipv4)),
+ ((u16)(db->out2in_key.k.ipv4 >> 16)))
+
+ old_ip = clib_net_to_host_u32(em_ip->dest_addr);
+ old_port = clib_net_to_host_u16(*em_port);
+ old_ip_checksum = clib_net_to_host_u16(em_ip->checksum);
+
+ em_ip->dest_addr =
+ clib_host_to_net_u32(db->out2in_key.k.ipv4);
+ em_ip->checksum =
+ clib_host_to_net_u16(new_l3_c);
+ *em_port =
+ clib_host_to_net_u16(db->out2in_key.k.port);
+
+ /*
+ * fix outter layer ip & icmp checksum
+ */
+ icmp = icmp_info->icmp;
+ CNAT_UPDATE_ICMP_ERR_CHECKSUM(((u16)(old_ip & 0xFFFF)),
+ ((u16)(old_ip >> 16)),
+ (old_port),
+ (old_ip_checksum),
+ (clib_net_to_host_u16(icmp->checksum)),
+ ((u16)(db->out2in_key.k.ipv4 & 0xffff)),
+ ((u16)(db->out2in_key.k.ipv4 >> 16)),
+ ((u16)(db->out2in_key.k.port)),
+ ((u16)(new_l3_c)))
+
+ icmp->checksum =
+ clib_host_to_net_u16(new_icmp_c);
+
+ old_ip = clib_net_to_host_u32(ip->src_addr);
+
+ ip->src_addr =
+ clib_host_to_net_u32(db->out2in_key.k.ipv4);
+
+ CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip & 0xFFFF)),
+ ((u16)(old_ip >> 16)),
+ (clib_net_to_host_u16(ip->checksum)),
+ ((u16)(db->out2in_key.k.ipv4)),
+ ((u16)(db->out2in_key.k.ipv4 >> 16)))
+ ip->checksum =
+ clib_host_to_net_u16(new_l3_c);
+
+#if 0
+ if(is_static_dest_nat_enabled(vrf) == CNAT_SUCCESS) {
+ /*
+ * fix inner layer ip & l4 checksum
+ */
+ em_snat_ip = icmp_info->em_ip;
+ em_snat_port = icmp_info->em_port;
+
+ old_ip = spp_net_to_host_byte_order_32(&(em_snat_ip->src_addr));
+ old_port = spp_net_to_host_byte_order_16(em_snat_port);
+ old_ip_checksum = spp_net_to_host_byte_order_16(&(em_snat_ip->checksum));
+ direction = 0;
+ if(cnat_static_dest_db_get_translation(em_snat_ip->src_addr, &postmap_ip, vrf, direction) == CNAT_SUCCESS) {
+ old_postmap_ip = spp_net_to_host_byte_order_32(&postmap_ip);
+
+ CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip)),
+ ((u16)(old_ip >> 16)),
+ (spp_net_to_host_byte_order_16(&(em_snat_ip->checksum))),
+ ((u16)(old_postmap_ip)),
+ ((u16)(old_postmap_ip >> 16)))
+ em_snat_ip->src_addr = postmap_ip;
+ em_snat_ip->checksum =
+ spp_host_to_net_byte_order_16(new_l3_c);
+
+ /*
+ * fix outter layer ip & icmp checksum
+ */
+ icmp = icmp_info->icmp;
+ CNAT_UPDATE_ICMP_ERR_CHECKSUM(((u16)(old_ip & 0xFFFF)),
+ ((u16)(old_ip >> 16)),
+ (old_port),
+ (old_ip_checksum),
+ (spp_net_to_host_byte_order_16(&(icmp->checksum))),
+ ((u16)(old_postmap_ip & 0xffff)),
+ ((u16)(old_postmap_ip >> 16)),
+ ((u16)(old_port)),
+ ((u16)(new_l3_c)))
+
+ icmp->checksum =
+ spp_host_to_net_byte_order_16(new_icmp_c);
+
+ }
+ }
+
+ if(is_static_dest_nat_enabled(vrf) == CNAT_SUCCESS) {
+ direction = 0;
+ if(cnat_static_dest_db_get_translation(ip->dest_addr, &postmap_ip, vrf, direction) == CNAT_SUCCESS) {
+
+ old_ip = spp_net_to_host_byte_order_32(&(ip->dest_addr));
+ old_postmap_ip = spp_net_to_host_byte_order_32(&postmap_ip);
+
+ CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip & 0xFFFF)),
+ ((u16)(old_ip >> 16)),
+ (spp_net_to_host_byte_order_16(&(ip->checksum))),
+ ((u16)(old_postmap_ip & 0xFFFF)),
+ ((u16)(old_postmap_ip >> 16)))
+ ip->dest_addr = postmap_ip;
+
+ ip->checksum =
+ clib_host_to_net_u16(new_l3_c);
+ }
+ }
+#endif /* if 0 */
+
+}
+
+/*
+ * Use the generic buffer metadata + first line of packet data prefetch
+ * stage function from <api/pipeline.h>. This is usually a Good Idea.
+ */
+#define stage0 generic_stage0
+
+
+static inline void
+stage1(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ u64 a, b, c;
+ u32 bucket;
+ u8 *prefetch_target;
+
+ vlib_buffer_t * b0 = vlib_get_buffer (vm, buffer_index);
+ ipv4_header *ip = vlib_buffer_get_current (b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len);
+ ipv4_header *em_ip = (ipv4_header*)((u8*)icmp + 8); /* embedded pkt's v4 hdr */
+ u8 em_ip_hdr_len = (em_ip->version_hdr_len_words & 0xf) << 2;
+
+ u64 tmp = 0;
+ u32 protocol = CNAT_ICMP;
+
+ /* Check L4 header for embedded packet */
+ if (em_ip->protocol == TCP_PROT) {
+ tcp_hdr_type *tcp = (tcp_hdr_type*)((u8 *)em_ip + em_ip_hdr_len);
+ vnet_buffer(b0)->vcgn_uii.key.k.port =
+ clib_net_to_host_u16(tcp->dest_port);
+ protocol = CNAT_TCP;
+
+ } else if (em_ip->protocol == UDP_PROT) {
+ udp_hdr_type_t *udp = (udp_hdr_type_t *)((u8 *)em_ip + em_ip_hdr_len);
+ vnet_buffer(b0)->vcgn_uii.key.k.port =
+ clib_net_to_host_u16(udp->dest_port);
+ protocol = CNAT_UDP;
+
+ } else {
+ icmp_v4_t *icmp = (icmp_v4_t*)((u8 *)em_ip + em_ip_hdr_len);
+ vnet_buffer(b0)->vcgn_uii.key.k.port =
+ clib_net_to_host_u16(icmp->identifier);
+
+ if (PREDICT_FALSE((icmp->type != ICMPV4_ECHOREPLY) &&
+ (icmp->type != ICMPV4_ECHO))) {
+ /*
+ * Try to set invalid protocol for these cases, so that
+ * hash lookup does not return valid main_db. This approach
+ * may optimize the regular cases with valid protocols
+ * as it avoids one more check for regular cases in stage3
+ */
+ protocol = CNAT_INVALID_PROTO;
+ }
+ }
+
+ tmp = vnet_buffer(b0)->vcgn_uii.key.k.ipv4 =
+ clib_net_to_host_u32(em_ip->dest_addr);
+
+ tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.port) << 32;
+
+ PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX],
+ vnet_buffer(b0)->vcgn_uii.key.k.vrf,
+ protocol)
+ tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.vrf) << 48;
+
+ CNAT_V4_GET_HASH(tmp, bucket, CNAT_MAIN_HASH_MASK)
+
+ prefetch_target = (u8 *)(&cnat_in2out_hash[bucket]);
+ vnet_buffer(b0)->vcgn_uii.bucket = bucket;
+
+ /* Prefetch the hash bucket */
+ CLIB_PREFETCH(prefetch_target, CLIB_CACHE_LINE_BYTES, LOAD);
+}
+
+#define SPP_LOG2_CACHE_LINE_BYTES 6
+#define SPP_CACHE_LINE_BYTES (1 << SPP_LOG2_CACHE_LINE_BYTES)
+
+static inline void
+stage2(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index);
+ uword prefetch_target0, prefetch_target1;
+ u32 bucket = vnet_buffer(b0)->vcgn_uii.bucket;
+
+ /* read the hash bucket */
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket
+ = cnat_in2out_hash[bucket].next;
+
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+ /*
+ * Prefetch database keys. We save space by not cache-line
+ * aligning the DB entries. We don't want to waste LSU
+ * bandwidth prefetching stuff we won't need.
+ */
+ prefetch_target0 = (uword)(cnat_main_db + db_index);
+ CLIB_PREFETCH((void*)prefetch_target0, CLIB_CACHE_LINE_BYTES, LOAD);
+ /* Just beyond DB key #2 */
+ prefetch_target1 = prefetch_target0 +
+ STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports);
+ /* If the targets are in different lines, do the second prefetch */
+ if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) !=
+ (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) {
+ CLIB_PREFETCH((void *)prefetch_target1, CLIB_CACHE_LINE_BYTES, LOAD);
+ }
+ }
+}
+
+static inline void
+stage3(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ cnat_main_db_entry_t *db;
+ vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index);
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket;
+
+ /*
+ * Note: if the search already failed (empty bucket),
+ * the answer is already in the pipeline context structure
+ */
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+
+ /*
+ * Note: hash collisions suck. We can't easily prefetch around them.
+ * The first trip around the track will be fast. After that, maybe
+ * not so much...
+ */
+ do {
+ db = cnat_main_db + db_index;
+ if (PREDICT_TRUE(db->in2out_key.key64 ==
+ vnet_buffer(b0)->vcgn_uii.key.key64)) {
+ break;
+ }
+ db_index = db->in2out_hash.next;
+ } while (db_index != EMPTY);
+
+ /* Stick the answer back into the pipeline context structure */
+ vnet_buffer(b0)->vcgn_uii.bucket = db_index;
+ }
+}
+
+
+
+static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
+ u32 bi)
+{
+ vlib_buffer_t *b0 = vlib_get_buffer (vm, bi);
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket;
+ int disposition = CNAT_V4_ICMP_E_I2O_T;
+ int counter = CNAT_V4_ICMP_E_I2O_T_PKT;
+
+ ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len);
+ ipv4_header *em_ip = (ipv4_header*)((u8*)icmp + 8); /* embedded pkt's v4 hdr */
+ u8 em_ip_hdr_len = (em_ip->version_hdr_len_words & 0xf) << 2;
+ vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_icmp_e_inside_input_node.index);
+ u32 node_counter_base_index = n->error_heap_index;
+ vlib_error_main_t * em = &vm->error_main;
+ cnat_main_db_entry_t *db = NULL;
+ icmp_em_ip_info icmp_info;
+
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ if (PREDICT_FALSE(ip->ttl <= 1)) {
+ /*
+ * As it is ICMP error packet with TTL <= 1,
+ * let's drop the packet (no need to genereate
+ * another ICMP error).
+ */
+
+ disposition = CNAT_V4_ICMP_E_I2O_D;
+ counter = CNAT_V4_ICMP_E_I2O_TTL_DROP;
+
+ goto drop_pkt;
+ }
+ }
+
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+ icmp_info.em_ip = em_ip;
+ icmp_info.icmp = icmp;
+ //icmp_info.em_port = vnet_buffer(b0)->vcgn_uii.key.k.port;
+
+ /* Note: This could have been done in stage1 itself,
+ * but we need to introduce one u16 * in vnet_buffer_opaque_t
+ * Since this flow is expected to be very rare in actual
+ * deployment scenario, we may afford to do these steps here
+ * as well. Lets confirm during core review. */
+ if (em_ip->protocol == TCP_PROT) {
+ tcp_hdr_type *tcp = (tcp_hdr_type*)((u8 *)em_ip + em_ip_hdr_len);
+ icmp_info.em_port = &(tcp->dest_port);
+ } else if (em_ip->protocol == UDP_PROT) {
+ udp_hdr_type_t *udp = (udp_hdr_type_t *)
+ ((u8 *)em_ip + em_ip_hdr_len);
+ icmp_info.em_port = &(udp->dest_port);
+ } else {
+ icmp_v4_t *icmp_inner = (icmp_v4_t*)((u8 *)em_ip + em_ip_hdr_len);
+ icmp_info.em_port = &(icmp_inner->identifier);
+ }
+
+ db = cnat_main_db + db_index;
+ /*
+ * 1. update dst addr:dst port of embedded ip pkt
+ * update src addr of icmp pkt
+ * 2. fix udp/tcp/ip checksum of embedded pkt
+ * fix icmp, ip check of icmp pkt
+ * don need to update the timer
+ */
+
+ if (PREDICT_FALSE(icmp_debug_flag)) {
+ printf("\nDUMPING ICMP PKT BEFORE\n");
+ print_icmp_pkt(ip);
+ }
+
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ /*
+ * Decrement TTL and update IPv4 checksum
+ */
+ ipv4_decr_ttl_n_calc_csum(ip);
+ }
+
+ swap_ip_src_emip_dst(ip, &icmp_info,
+ db, db->in2out_key.k.vrf);
+
+ if (PREDICT_FALSE(icmp_debug_flag)) {
+ printf("\nDUMPING ICMP PKT AFTER\n");
+ print_icmp_pkt(ip);
+ }
+ in2out_forwarding_count++;
+
+ } else {
+ disposition = CNAT_V4_ICMP_E_I2O_D;
+ counter = CNAT_V4_ICMP_E_I2O_D_PKT;
+ }
+
+drop_pkt:
+
+ em->counters[node_counter_base_index + counter] += 1;
+ return disposition;
+}
+
+#include <vnet/pipeline.h>
+
+static uword cnat_ipv4_icmp_e_inside_input_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return dispatch_pipeline (vm, node, frame);
+}
+
+
+VLIB_REGISTER_NODE (cnat_ipv4_icmp_e_inside_input_node) = {
+ .function = cnat_ipv4_icmp_e_inside_input_node_fn,
+ .name = "vcgn-v4-icmp-e-i2o",
+ .vector_size = sizeof (u32),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(cnat_ipv4_icmp_e_inside_input_error_strings),
+ .error_strings = cnat_ipv4_icmp_e_inside_input_error_strings,
+
+ .n_next_nodes = CNAT_V4_ICMP_E_I2O_NEXT,
+
+ /* edit / add dispositions here */
+ .next_nodes = {
+ [CNAT_V4_ICMP_E_I2O_T] = "ip4-input",
+ [CNAT_V4_ICMP_E_I2O_D] = "error-drop",
+ },
+};
+
+clib_error_t *cnat_ipv4_icmp_e_inside_input_init (vlib_main_t *vm)
+{
+ cnat_ipv4_icmp_e_inside_input_main_t * mp = &cnat_ipv4_icmp_e_inside_input_main;
+
+ mp->vlib_main = vm;
+ mp->vnet_main = vnet_get_main();
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (cnat_ipv4_icmp_e_inside_input_init);
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_error_outside_input.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_error_outside_input.c
new file mode 100644
index 00000000..f25f4d02
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_error_outside_input.c
@@ -0,0 +1,452 @@
+/*
+ *---------------------------------------------------------------------------
+ * cnat_ipv4_icmp_error_outside_input.c - cnat_ipv4_icmp_error_outside_input node pipeline stage functions
+ *
+ * Copyright (c) 2008-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/error.h>
+#include <vnet/buffer.h>
+
+#include "cnat_ipv4_icmp.h"
+
+#define foreach_cnat_ipv4_icmp_e_outside_input_error \
+_(CNAT_V4_ICMP_E_O2I_T_PKT, "cnat v4 icmp_e o2i packet transmit") \
+_(CNAT_V4_ICMP_E_O2I_D_PKT, "cnat v4 icmp_e o2i packet drop") \
+_(CNAT_V4_ICMP_E_O2I_TTL_DROP, "cnat v4 icmp_e o2i ttl drop")
+
+typedef enum {
+#define _(sym,str) sym,
+ foreach_cnat_ipv4_icmp_e_outside_input_error
+#undef _
+ CNAT_IPV4_ICMP_E_OUTSIDE_INPUT_N_ERROR,
+} cnat_ipv4_icmp_e_outside_input_t;
+
+static char * cnat_ipv4_icmp_e_outside_input_error_strings[] = {
+#define _(sym,string) string,
+ foreach_cnat_ipv4_icmp_e_outside_input_error
+#undef _
+};
+
+typedef struct {
+ u32 cached_next_index;
+ /* $$$$ add data here */
+
+ /* convenience variables */
+ vlib_main_t * vlib_main;
+ vnet_main_t * vnet_main;
+} cnat_ipv4_icmp_e_outside_input_main_t;
+
+typedef enum {
+ CNAT_V4_ICMP_E_O2I_T,
+ CNAT_V4_ICMP_E_O2I_D,
+ CNAT_V4_ICMP_E_O2I_NEXT,
+} cnat_ipv4_icmp_e_outside_input_next_t;
+
+cnat_ipv4_icmp_e_outside_input_main_t cnat_ipv4_icmp_e_outside_input_main;
+vlib_node_registration_t cnat_ipv4_icmp_e_outside_input_node;
+
+#define NSTAGES 5
+
+inline void swap_ip_dst_emip_src(ipv4_header *ip,
+ icmp_em_ip_info *icmp_info,
+ cnat_main_db_entry_t *db, u16 vrf)
+{
+ icmp_v4_t *icmp;
+ ipv4_header *em_ip;
+ u16 *em_port;
+ u32 old_ip;
+ u16 old_port;
+ u16 old_ip_checksum;
+
+ /*
+ * declear variable
+ */
+ CNAT_UPDATE_L3_CHECKSUM_DECLARE
+ CNAT_UPDATE_ICMP_ERR_CHECKSUM_DECLARE
+
+ /*
+ * fix inner layer ip & l4 checksum
+ */
+ em_ip = icmp_info->em_ip;
+ em_port = icmp_info->em_port;
+
+ CNAT_UPDATE_L3_CHECKSUM(((u16)(db->out2in_key.k.ipv4)),
+ ((u16)(db->out2in_key.k.ipv4 >> 16)),
+ (clib_net_to_host_u16(em_ip->checksum)),
+ ((u16)(db->in2out_key.k.ipv4)),
+ ((u16)(db->in2out_key.k.ipv4 >> 16)))
+
+ old_ip = clib_net_to_host_u32(em_ip->src_addr);
+ old_port = clib_net_to_host_u16(*em_port);
+ old_ip_checksum = clib_net_to_host_u16(em_ip->checksum);
+
+ em_ip->src_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+ em_ip->checksum =
+ clib_host_to_net_u16(new_l3_c);
+ *em_port =
+ clib_host_to_net_u16(db->in2out_key.k.port);
+
+ /*
+ * fix outter layer ip & icmp checksum
+ */
+ icmp = icmp_info->icmp;
+ CNAT_UPDATE_ICMP_ERR_CHECKSUM(((u16)(old_ip & 0xFFFF)),
+ ((u16)(old_ip >> 16)),
+ (old_port),
+ (old_ip_checksum),
+ (clib_net_to_host_u16(icmp->checksum)),
+ ((u16)(db->in2out_key.k.ipv4 & 0xffff)),
+ ((u16)(db->in2out_key.k.ipv4 >> 16)),
+ ((u16)(db->in2out_key.k.port)),
+ ((u16)(new_l3_c)))
+
+ icmp->checksum =
+ clib_host_to_net_u16(new_icmp_c);
+
+ old_ip = clib_net_to_host_u32(ip->dest_addr);
+
+ ip->dest_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+
+ CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip & 0xFFFF)),
+ ((u16)(old_ip >> 16)),
+ (clib_net_to_host_u16(ip->checksum)),
+ ((u16)(db->in2out_key.k.ipv4)),
+ ((u16)(db->in2out_key.k.ipv4 >> 16)))
+ ip->checksum =
+ clib_host_to_net_u16(new_l3_c);
+
+#if 0
+ if(is_static_dest_nat_enabled(vrf) == CNAT_SUCCESS) {
+ /*
+ * fix inner layer ip & l4 checksum
+ */
+ em_snat_ip = icmp_info->em_ip;
+ em_snat_port = icmp_info->em_port;
+
+ old_ip = spp_net_to_host_byte_order_32(&(em_snat_ip->dest_addr));
+ old_port = spp_net_to_host_byte_order_16(em_snat_port);
+ old_ip_checksum = spp_net_to_host_byte_order_16(&(em_snat_ip->checksum));
+ direction = 1;
+ if(cnat_static_dest_db_get_translation(em_snat_ip->dest_addr, &postmap_ip, vrf, direction) == CNAT_SUCCESS) {
+ old_postmap_ip = spp_net_to_host_byte_order_32(&postmap_ip);
+
+ CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip)),
+ ((u16)(old_ip >> 16)),
+ (spp_net_to_host_byte_order_16(&(em_snat_ip->checksum))),
+ ((u16)(old_postmap_ip)),
+ ((u16)(old_postmap_ip >> 16)))
+ em_snat_ip->dest_addr = postmap_ip;
+ em_snat_ip->checksum =
+ spp_host_to_net_byte_order_16(new_l3_c);
+
+ /*
+ * fix outter layer ip & icmp checksum
+ */
+ icmp = icmp_info->icmp;
+ CNAT_UPDATE_ICMP_ERR_CHECKSUM(((u16)(old_ip & 0xFFFF)),
+ ((u16)(old_ip >> 16)),
+ (old_port),
+ (old_ip_checksum),
+ (spp_net_to_host_byte_order_16(&(icmp->checksum))),
+ ((u16)(old_postmap_ip & 0xffff)),
+ ((u16)(old_postmap_ip >> 16)),
+ ((u16)(old_port)),
+ ((u16)(new_l3_c)))
+
+ icmp->checksum =
+ spp_host_to_net_byte_order_16(new_icmp_c);
+
+ }
+ }
+
+ if(is_static_dest_nat_enabled(vrf) == CNAT_SUCCESS) {
+ direction = 1;
+ if(cnat_static_dest_db_get_translation(ip->src_addr, &postmap_ip, vrf, direction) == CNAT_SUCCESS) {
+ CNAT_UPDATE_L3_CHECKSUM_DECLARE
+
+ old_ip = spp_net_to_host_byte_order_32(&(ip->src_addr));
+ old_postmap_ip = spp_net_to_host_byte_order_32(&postmap_ip);
+
+ CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip & 0xFFFF)),
+ ((u16)(old_ip >> 16)),
+ (spp_net_to_host_byte_order_16(&(ip->checksum))),
+ ((u16)(old_postmap_ip & 0xFFFF)),
+ ((u16)(old_postmap_ip >> 16)))
+ ip->checksum =
+ spp_host_to_net_byte_order_16(new_l3_c);
+ ip->src_addr = postmap_ip;
+ }
+ }
+#endif /* if 0 */
+}
+
+/*
+ * Use the generic buffer metadata + first line of packet data prefetch
+ * stage function from <api/pipeline.h>. This is usually a Good Idea.
+ */
+#define stage0 generic_stage0
+
+
+static inline void
+stage1(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ u64 a, b, c;
+ u32 bucket;
+ u8 *prefetch_target;
+
+ vlib_buffer_t * b0 = vlib_get_buffer (vm, buffer_index);
+ ipv4_header *ip = vlib_buffer_get_current (b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len);
+ ipv4_header *em_ip = (ipv4_header*)((u8*)icmp + 8); /* embedded pkt's v4 hdr */
+ u8 em_ip_hdr_len = (em_ip->version_hdr_len_words & 0xf) << 2;
+
+ u64 tmp = 0;
+ u32 protocol = CNAT_ICMP;
+
+ /* Check L4 header for embedded packet */
+ if (em_ip->protocol == TCP_PROT) {
+ tcp_hdr_type *tcp = (tcp_hdr_type*)((u8 *)em_ip + em_ip_hdr_len);
+ vnet_buffer(b0)->vcgn_uii.key.k.port =
+ clib_net_to_host_u16(tcp->src_port);
+ protocol = CNAT_TCP;
+
+ } else if (em_ip->protocol == UDP_PROT) {
+ udp_hdr_type_t *udp = (udp_hdr_type_t *)((u8 *)em_ip + em_ip_hdr_len);
+ vnet_buffer(b0)->vcgn_uii.key.k.port =
+ clib_net_to_host_u16(udp->src_port);
+ protocol = CNAT_UDP;
+
+ } else {
+ icmp_v4_t *icmp = (icmp_v4_t*)((u8 *)em_ip + em_ip_hdr_len);
+ vnet_buffer(b0)->vcgn_uii.key.k.port =
+ clib_net_to_host_u16(icmp->identifier);
+
+ if (PREDICT_FALSE((icmp->type != ICMPV4_ECHOREPLY) &&
+ (icmp->type != ICMPV4_ECHO))) {
+ /*
+ * Try to set invalid protocol for these cases, so that
+ * hash lookup does not return valid main_db. This approach
+ * may optimize the regular cases with valid protocols
+ * as it avoids one more check for regular cases in stage3
+ */
+ protocol = CNAT_INVALID_PROTO;
+ }
+ }
+
+ tmp = vnet_buffer(b0)->vcgn_uii.key.k.ipv4 =
+ clib_net_to_host_u32(em_ip->src_addr);
+
+ tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.port) << 32;
+
+ PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX],
+ vnet_buffer(b0)->vcgn_uii.key.k.vrf,
+ protocol)
+ tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.vrf) << 48;
+
+ CNAT_V4_GET_HASH(tmp, bucket, CNAT_MAIN_HASH_MASK)
+
+ prefetch_target = (u8 *)(&cnat_out2in_hash[bucket]);
+ vnet_buffer(b0)->vcgn_uii.bucket = bucket;
+
+ /* Prefetch the hash bucket */
+ CLIB_PREFETCH(prefetch_target, CLIB_CACHE_LINE_BYTES, LOAD);
+}
+
+
+#define SPP_LOG2_CACHE_LINE_BYTES 6
+#define SPP_CACHE_LINE_BYTES (1 << SPP_LOG2_CACHE_LINE_BYTES)
+
+static inline void
+stage2(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index);
+ uword prefetch_target0, prefetch_target1;
+ u32 bucket = vnet_buffer(b0)->vcgn_uii.bucket;
+
+ /* read the hash bucket */
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket
+ = cnat_out2in_hash[bucket].next;
+
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+ /*
+ * Prefetch database keys. We save space by not cache-line
+ * aligning the DB entries. We don't want to waste LSU
+ * bandwidth prefetching stuff we won't need.
+ */
+ prefetch_target0 = (uword)(cnat_main_db + db_index);
+ CLIB_PREFETCH((void*)prefetch_target0, CLIB_CACHE_LINE_BYTES, LOAD);
+ /* Just beyond DB key #2 */
+ prefetch_target1 = prefetch_target0 +
+ STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports);
+ /* If the targets are in different lines, do the second prefetch */
+ if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) !=
+ (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) {
+ CLIB_PREFETCH((void *)prefetch_target1, CLIB_CACHE_LINE_BYTES, LOAD);
+ }
+ }
+}
+
+
+static inline void
+stage3(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ cnat_main_db_entry_t *db;
+ vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index);
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket;
+
+ /*
+ * Note: if the search already failed (empty bucket),
+ * the answer is already in the pipeline context structure
+ */
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+
+ /*
+ * Note: hash collisions suck. We can't easily prefetch around them.
+ * The first trip around the track will be fast. After that, maybe
+ * not so much...
+ */
+ do {
+ db = cnat_main_db + db_index;
+ if (PREDICT_TRUE(db->out2in_key.key64 ==
+ vnet_buffer(b0)->vcgn_uii.key.key64)) {
+ break;
+ }
+ db_index = db->out2in_hash.next;
+ } while (db_index != EMPTY);
+
+ /* Stick the answer back into the pipeline context structure */
+ vnet_buffer(b0)->vcgn_uii.bucket = db_index;
+ }
+}
+
+static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
+ u32 bi)
+{
+ vlib_buffer_t *b0 = vlib_get_buffer (vm, bi);
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket;
+ int disposition = CNAT_V4_ICMP_E_O2I_T;
+ int counter = CNAT_V4_ICMP_E_O2I_T_PKT;
+
+ ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len);
+ ipv4_header *em_ip = (ipv4_header*)((u8*)icmp + 8); /* embedded pkt's v4 hdr */
+ u8 em_ip_hdr_len = (em_ip->version_hdr_len_words & 0xf) << 2;
+ vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_icmp_e_outside_input_node.index);
+ u32 node_counter_base_index = n->error_heap_index;
+ vlib_error_main_t * em = &vm->error_main;
+ cnat_main_db_entry_t *db = NULL;
+ icmp_em_ip_info icmp_info;
+
+
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+
+ icmp_info.em_ip = em_ip;
+ icmp_info.icmp = icmp;
+
+ /* Note: This could have been done in stage1 itself,
+ * but we need to introduce one u16 * in vnet_buffer_opaque_t
+ * Since this flow is expected to be very rare in actual
+ * deployment scenario, we may afford to do these steps here
+ * as well. Lets confirm during core review. */
+
+ if (em_ip->protocol == TCP_PROT) {
+ tcp_hdr_type *tcp = (tcp_hdr_type*)((u8 *)em_ip + em_ip_hdr_len);
+ icmp_info.em_port = &(tcp->src_port);
+ } else if (em_ip->protocol == UDP_PROT) {
+ udp_hdr_type_t *udp = (udp_hdr_type_t *)
+ ((u8 *)em_ip + em_ip_hdr_len);
+ icmp_info.em_port = &(udp->src_port);
+ } else {
+ icmp_v4_t *icmp_inner = (icmp_v4_t*)((u8 *)em_ip + em_ip_hdr_len);
+ icmp_info.em_port = &(icmp_inner->identifier);
+ }
+
+ db = cnat_main_db + db_index;
+
+ if (PREDICT_FALSE(icmp_debug_flag)) {
+ printf("\nDUMPING ICMP PKT BEFORE\n");
+ print_icmp_pkt(ip);
+ }
+
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ /*
+ * Decrement TTL and update IPv4 checksum
+ */
+ ipv4_decr_ttl_n_calc_csum(ip);
+ }
+
+ swap_ip_dst_emip_src(ip, &icmp_info,
+ db, db->in2out_key.k.vrf);
+
+ if (PREDICT_FALSE(icmp_debug_flag)) {
+ printf("\nDUMPING ICMP PKT AFTER\n");
+ print_icmp_pkt(ip);
+ }
+
+ } else {
+ disposition = CNAT_V4_ICMP_E_O2I_D;
+ counter = CNAT_V4_ICMP_E_O2I_D_PKT;
+ }
+
+ em->counters[node_counter_base_index + counter] += 1;
+ return disposition;
+}
+
+#include <vnet/pipeline.h>
+
+static uword cnat_ipv4_icmp_e_outside_input_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return dispatch_pipeline (vm, node, frame);
+}
+
+
+VLIB_REGISTER_NODE (cnat_ipv4_icmp_e_outside_input_node) = {
+ .function = cnat_ipv4_icmp_e_outside_input_node_fn,
+ .name = "vcgn-v4-icmp-e-o2i",
+ .vector_size = sizeof (u32),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(cnat_ipv4_icmp_e_outside_input_error_strings),
+ .error_strings = cnat_ipv4_icmp_e_outside_input_error_strings,
+
+ .n_next_nodes = CNAT_V4_ICMP_E_O2I_NEXT,
+
+ /* edit / add dispositions here */
+ .next_nodes = {
+ [CNAT_V4_ICMP_E_O2I_T] = "ip4-input",
+ [CNAT_V4_ICMP_E_O2I_D] = "error-drop",
+ },
+};
+
+clib_error_t *cnat_ipv4_icmp_e_outside_input_init (vlib_main_t *vm)
+{
+ cnat_ipv4_icmp_e_outside_input_main_t * mp = &cnat_ipv4_icmp_e_outside_input_main;
+
+ mp->vlib_main = vm;
+ mp->vnet_main = vnet_get_main();
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (cnat_ipv4_icmp_e_outside_input_init);
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_inside_input.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_inside_input.c
new file mode 100644
index 00000000..1b9f0266
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_inside_input.c
@@ -0,0 +1,404 @@
+/*
+ *---------------------------------------------------------------------------
+ * cnat_ipv4_icmp_query_inside_input.c - cnat_ipv4_icmp_query_inside_input node pipeline stage functions
+ *
+ *
+ * Copyright (c) 2008-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/error.h>
+#include <vnet/buffer.h>
+
+#include "cnat_ipv4_icmp.h"
+
+#define foreach_cnat_ipv4_icmp_q_inside_input_error \
+_(CNAT_V4_ICMP_Q_I2O_T_PKT, "cnat v4 icmp_q i2o packet transmit") \
+_(CNAT_V4_ICMP_Q_I2O_MISS_PKT, "cnat v4 icmp_q i2o db miss") \
+_(CNAT_V4_ICMP_Q_I2O_TTL_GEN, "cnat v4 icmp_q i2o ttl generate") \
+_(CNAT_V4_ICMP_Q_I2O_TTL_DROP, "cnat v4 icmp_q i2o ttl drop") \
+_(CNAT_V4_ICMP_Q_I2O_NO_SESSION_DROP, "cnat v4 icmp_q i2o no session drop")
+
+typedef enum {
+#define _(sym,str) sym,
+ foreach_cnat_ipv4_icmp_q_inside_input_error
+#undef _
+ CNAT_IPV4_ICMP_Q_INSIDE_INPUT_N_ERROR,
+} cnat_ipv4_icmp_q_inside_input_t;
+
+static char * cnat_ipv4_icmp_q_inside_input_error_strings[] = {
+#define _(sym,string) string,
+ foreach_cnat_ipv4_icmp_q_inside_input_error
+#undef _
+};
+
+typedef struct {
+ u32 cached_next_index;
+ /* $$$$ add data here */
+
+ /* convenience variables */
+ vlib_main_t * vlib_main;
+ vnet_main_t * vnet_main;
+} cnat_ipv4_icmp_q_inside_input_main_t;
+
+typedef enum {
+ CNAT_V4_ICMP_Q_I2O_T,
+ CNAT_V4_ICMP_Q_I2O_E,
+ CNAT_V4_ICMP_Q_I2O_D,
+ CNAT_V4_ICMP_Q_I2O_NEXT,
+} cnat_ipv4_icmp_q_inside_input_next_t;
+
+cnat_ipv4_icmp_q_inside_input_main_t cnat_ipv4_icmp_q_inside_input_main;
+vlib_node_registration_t cnat_ipv4_icmp_q_inside_input_node;
+
+#define NSTAGES 5
+
+inline void swap_ip_src_icmp_id(ipv4_header *ip,
+ icmp_v4_t *icmp,
+ cnat_main_db_entry_t *db, u16 vrf)
+{
+#if 0
+ u32 postmap_ip;
+ u8 direction;
+ u32 old_ip;
+ u32 old_postmap_ip;
+
+
+ if(is_static_dest_nat_enabled(vrf) == CNAT_SUCCESS) {
+ direction = 0;
+ if(cnat_static_dest_db_get_translation(ip->dest_addr, &postmap_ip, vrf, direction) == CNAT_SUCCESS) {
+ CNAT_UPDATE_L3_CHECKSUM_DECLARE
+
+ old_ip = spp_net_to_host_byte_order_32(&(ip->dest_addr));
+ old_postmap_ip = spp_net_to_host_byte_order_32(&postmap_ip);
+
+ CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip & 0xFFFF)),
+ ((u16)(old_ip >> 16)),
+ (spp_net_to_host_byte_order_16(&(ip->checksum))),
+ ((u16)(old_postmap_ip & 0xFFFF)),
+ ((u16)(old_postmap_ip >> 16)))
+ ip->dest_addr = postmap_ip;
+
+ ip->checksum =
+ spp_host_to_net_byte_order_16(new_l3_c);
+ }
+ }
+#endif /* if 0 */
+ /*
+ * declare variable
+ */
+ CNAT_UPDATE_L3_L4_CHECKSUM_DECLARE
+ /*
+ * calculate checksum
+ */
+ CNAT_UPDATE_L3_ICMP_CHECKSUM(((u16)(db->in2out_key.k.ipv4)),
+ ((u16)(db->in2out_key.k.ipv4 >> 16)),
+ (db->in2out_key.k.port),
+ (clib_net_to_host_u16(ip->checksum)),
+ (clib_net_to_host_u16(icmp->checksum)),
+ ((u16)(db->out2in_key.k.ipv4)),
+ ((u16)(db->out2in_key.k.ipv4 >> 16)),
+ (db->out2in_key.k.port))
+ //set ip header
+ ip->src_addr =
+ clib_host_to_net_u32(db->out2in_key.k.ipv4);
+ ip->checksum =
+ clib_host_to_net_u16(new_l3_c);
+
+ //set icmp header
+ icmp->identifier =
+ clib_host_to_net_u16(db->out2in_key.k.port);
+ icmp->checksum =
+ clib_host_to_net_u16(new_l4_c);
+}
+
+/*
+ * Use the generic buffer metadata + first line of packet data prefetch
+ * stage function from <api/pipeline.h>. This is usually a Good Idea.
+ */
+#define stage0 generic_stage0
+
+static inline void
+stage1(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ u64 a, b, c;
+ u32 bucket;
+ u8 *prefetch_target;
+
+ vlib_buffer_t * b0 = vlib_get_buffer (vm, buffer_index);
+ ipv4_header *ip = vlib_buffer_get_current (b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len);
+
+ u64 tmp = 0;
+ tmp = vnet_buffer(b0)->vcgn_uii.key.k.ipv4 =
+ clib_net_to_host_u32(ip->src_addr);
+ vnet_buffer(b0)->vcgn_uii.key.k.port =
+ clib_net_to_host_u16 (icmp->identifier);
+
+ tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.port) << 32;
+
+ PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX],
+ vnet_buffer(b0)->vcgn_uii.key.k.vrf,
+ CNAT_ICMP)
+ tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.vrf) << 48;
+
+ CNAT_V4_GET_HASH(tmp, bucket, CNAT_MAIN_HASH_MASK)
+
+ prefetch_target = (u8 *)(&cnat_in2out_hash[bucket]);
+ vnet_buffer(b0)->vcgn_uii.bucket = bucket;
+
+ /* Prefetch the hash bucket */
+ CLIB_PREFETCH(prefetch_target, CLIB_CACHE_LINE_BYTES, LOAD);
+}
+
+#define SPP_LOG2_CACHE_LINE_BYTES 6
+#define SPP_CACHE_LINE_BYTES (1 << SPP_LOG2_CACHE_LINE_BYTES)
+
+static inline void
+stage2(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index);
+ uword prefetch_target0, prefetch_target1;
+ u32 bucket = vnet_buffer(b0)->vcgn_uii.bucket;
+
+ /* read the hash bucket */
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket
+ = cnat_in2out_hash[bucket].next;
+
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+ /*
+ * Prefetch database keys. We save space by not cache-line
+ * aligning the DB entries. We don't want to waste LSU
+ * bandwidth prefetching stuff we won't need.
+ */
+ prefetch_target0 = (uword)(cnat_main_db + db_index);
+ CLIB_PREFETCH((void*)prefetch_target0, CLIB_CACHE_LINE_BYTES, LOAD);
+ /* Just beyond DB key #2 */
+ prefetch_target1 = prefetch_target0 +
+ STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports);
+ /* If the targets are in different lines, do the second prefetch */
+ if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) !=
+ (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) {
+ CLIB_PREFETCH((void *)prefetch_target1, CLIB_CACHE_LINE_BYTES, LOAD);
+ }
+ }
+}
+
+static inline void
+stage3(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ cnat_main_db_entry_t *db;
+ vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index);
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket;
+
+ /*
+ * Note: if the search already failed (empty bucket),
+ * the answer is already in the pipeline context structure
+ */
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+
+ /*
+ * Note: hash collisions suck. We can't easily prefetch around them.
+ * The first trip around the track will be fast. After that, maybe
+ * not so much...
+ */
+ do {
+ db = cnat_main_db + db_index;
+ if (PREDICT_TRUE(db->in2out_key.key64 ==
+ vnet_buffer(b0)->vcgn_uii.key.key64)) {
+ break;
+ }
+ db_index = db->in2out_hash.next;
+ } while (db_index != EMPTY);
+
+ /* Stick the answer back into the pipeline context structure */
+ vnet_buffer(b0)->vcgn_uii.bucket = db_index;
+ }
+}
+
+static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
+ u32 bi)
+{
+ vlib_buffer_t *b0 = vlib_get_buffer (vm, bi);
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket;
+ spp_ctx_t *ctx = (spp_ctx_t *) &vnet_buffer(b0)->vcgn_uii;
+ int disposition = CNAT_V4_ICMP_Q_I2O_T;
+ int counter = CNAT_V4_ICMP_Q_I2O_T_PKT;
+
+ ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len);
+ vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_icmp_q_inside_input_node.index);
+ u32 node_counter_base_index = n->error_heap_index;
+ vlib_error_main_t * em = &vm->error_main;
+ cnat_session_entry_t *session_db = NULL;
+ cnat_main_db_entry_t *db = NULL;
+ cnat_key_t dest_info;
+
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ if (PREDICT_FALSE(ip->ttl <= 1)) {
+ /* Try to generate ICMP error msg, as TTL is <= 1 */
+
+ if (icmpv4_generate_with_throttling
+ (ctx, ip, ctx->ru.rx.uidb_index)) {
+
+ /* Generated ICMP */
+ disposition = CNAT_V4_ICMP_Q_I2O_T;
+ counter = CNAT_V4_ICMP_Q_I2O_TTL_GEN;
+ } else {
+ /* Could not generated ICMP - drop the packet */
+ disposition = CNAT_V4_ICMP_Q_I2O_D;
+ counter = CNAT_V4_ICMP_Q_I2O_TTL_DROP;
+ }
+ goto drop_pkt;
+ }
+ }
+
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+ db = cnat_main_db + db_index;
+ dest_info.k.port = 0;
+ dest_info.k.ipv4 = clib_net_to_host_u32(ip->dest_addr);
+
+ if(PREDICT_TRUE(!PLATFORM_DBL_SUPPORT)) {
+
+ /* No DBL support, so just update the destn and proceed */
+ db->dst_ipv4 = dest_info.k.ipv4;
+ db->dst_port = dest_info.k.port;
+ goto update_pkt;
+ }
+
+ if(PREDICT_FALSE(db->dst_ipv4 != dest_info.k.ipv4)) {
+ if(PREDICT_TRUE(db->nsessions == 1)) {
+ /* Handle one to 2 dest scenarion */
+ dest_info.k.vrf = db->in2out_key.k.vrf;
+ session_db = cnat_handle_1to2_session(db, &dest_info);
+
+ if(PREDICT_FALSE(session_db == NULL)) {
+ disposition = CNAT_V4_ICMP_Q_I2O_D;
+ counter = CNAT_V4_ICMP_Q_I2O_NO_SESSION_DROP;
+ goto drop_pkt;
+ }
+ } else if (PREDICT_FALSE(db->nsessions == 0)) {
+ /* Should be a static entry
+ * Note this session as the first session and log
+ */
+ cnat_add_dest_n_log(db, &dest_info);
+ } else { /* Many translations exist already */
+ dest_info.k.vrf = db->in2out_key.k.vrf;
+ /* If session already exists,
+ * cnat_create_session_db_entry will return the existing db
+ * else create a new db
+ * If could not create, return NULL
+ */
+ session_db = cnat_create_session_db_entry(&dest_info,
+ db, TRUE);
+
+ if(PREDICT_FALSE(session_db == NULL)) {
+ disposition = CNAT_V4_ICMP_Q_I2O_D;
+ counter = CNAT_V4_ICMP_Q_I2O_NO_SESSION_DROP;
+ goto drop_pkt;
+ }
+ }
+ }
+
+update_pkt:
+
+ if (PREDICT_FALSE(icmp_debug_flag)) {
+ printf("\nDUMPING ICMP PKT BEFORE\n");
+ print_icmp_pkt(ip);
+ }
+
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ /*
+ * Decrement TTL and update IPv4 checksum
+ */
+ ipv4_decr_ttl_n_calc_csum(ip);
+ }
+
+ /*
+ * 1. update src ipv4 addr and src icmp identifier
+ * 2. update ipv4 checksum and icmp checksum
+ */
+ swap_ip_src_icmp_id(ip, icmp, db, db->in2out_key.k.vrf);
+
+ if (PREDICT_FALSE(icmp_debug_flag)) {
+ printf("\nDUMPING ICMP PKT AFTER\n");
+ print_icmp_pkt(ip);
+ }
+
+ /*
+ * update db counter, timer
+ */
+
+ if(PREDICT_FALSE(session_db != 0)) {
+ CNAT_DB_TIMEOUT_RST(session_db);
+ } else {
+ CNAT_DB_TIMEOUT_RST(db);
+ }
+ db->in2out_pkts++;
+ in2out_forwarding_count++;
+
+ } else {
+ disposition = CNAT_V4_ICMP_Q_I2O_E;
+ counter = CNAT_V4_ICMP_Q_I2O_MISS_PKT;
+ }
+
+drop_pkt:
+
+ em->counters[node_counter_base_index + counter] += 1;
+ return disposition;
+}
+
+#include <vnet/pipeline.h>
+
+static uword cnat_ipv4_icmp_q_inside_input_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return dispatch_pipeline (vm, node, frame);
+}
+
+
+VLIB_REGISTER_NODE (cnat_ipv4_icmp_q_inside_input_node) = {
+ .function = cnat_ipv4_icmp_q_inside_input_node_fn,
+ .name = "vcgn-v4-icmp-q-i2o",
+ .vector_size = sizeof (u32),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(cnat_ipv4_icmp_q_inside_input_error_strings),
+ .error_strings = cnat_ipv4_icmp_q_inside_input_error_strings,
+
+ .n_next_nodes = CNAT_V4_ICMP_Q_I2O_NEXT,
+
+ /* edit / add dispositions here */
+ .next_nodes = {
+ [CNAT_V4_ICMP_Q_I2O_E] = "vcgn-v4-icmp-q-i2o-e",
+ [CNAT_V4_ICMP_Q_I2O_T] = "ip4-input",
+ [CNAT_V4_ICMP_Q_I2O_D] = "error-drop",
+ },
+};
+
+clib_error_t *cnat_ipv4_icmp_q_inside_input_init (vlib_main_t *vm)
+{
+ cnat_ipv4_icmp_q_inside_input_main_t * mp = &cnat_ipv4_icmp_q_inside_input_main;
+
+ mp->vlib_main = vm;
+ mp->vnet_main = vnet_get_main();
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (cnat_ipv4_icmp_q_inside_input_init);
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_inside_input_exception.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_inside_input_exception.c
new file mode 100644
index 00000000..9b5e280e
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_inside_input_exception.c
@@ -0,0 +1,235 @@
+/*
+ *---------------------------------------------------------------------------
+ * cnat_ipv4_icmp_query_inside_input_exception.c - cnat_ipv4_icmp_query_inside_input_exception node pipeline stage functions
+ *
+ * Copyright (c) 2008-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/error.h>
+#include <vnet/buffer.h>
+
+#include "cnat_ipv4_icmp.h"
+
+#define foreach_cnat_ipv4_icmp_q_inside_input_exc_error \
+_(CNAT_V4_ICMP_Q_I2O_E_T_PKT, "v4 icmp query i2o-e transmit") \
+_(CNAT_V4_ICMP_Q_I2O_E_G_PKT, "v4 icmp query i2o-e gen icmp msg") \
+_(CNAT_V4_ICMP_Q_I2O_E_D_PKT, "v4 icmp query i2o-e pkt drop") \
+_(CNAT_V4_ICMP_Q_I2O_E_DC_PKT, "v4 icmp query i2o-e drop (no config)") \
+_(CNAT_V4_ICMP_Q_I2O_E_DR_PKT, "v4 icmp query i2o-e drop (not in run state)") \
+_(CNAT_V4_ICMP_Q_I2O_E_DD_PKT, "v4 icmp query i2o-e drop (no direct port)") \
+_(CNAT_V4_ICMP_Q_I2O_E_DA_PKT, "v4 icmp query i2o-e drop (no any port)") \
+_(CNAT_V4_ICMP_Q_I2O_E_DO_PKT, "v4 icmp query i2o-e drop (out of port limit)") \
+_(CNAT_V4_ICMP_Q_I2O_E_DS_PKT, "v4 icmp query i2o_e drop (out of session db)")
+
+typedef enum {
+#define _(sym,str) sym,
+ foreach_cnat_ipv4_icmp_q_inside_input_exc_error
+#undef _
+ CNAT_IPV4_ICMP_Q_INSIDE_INPUT_EXCEPTIONS_N_ERROR,
+} cnat_ipv4_icmp_q_inside_input_exc_error_t;
+
+
+static char * cnat_ipv4_icmp_q_inside_input_exc_error_strings[] = {
+#define _(sym,string) string,
+ foreach_cnat_ipv4_icmp_q_inside_input_exc_error
+#undef _
+};
+
+typedef struct {
+ u32 cached_next_index;
+ /* $$$$ add data here */
+
+ /* convenience variables */
+ vlib_main_t * vlib_main;
+ vnet_main_t * vnet_main;
+} cnat_ipv4_icmp_q_inside_input_exc_main_t;
+
+typedef enum {
+ CNAT_V4_ICMP_Q_E_I2O_T,
+ //CNAT_V4_ICMP_Q_E_I2O_GEN,
+ CNAT_V4_ICMP_Q_E_I2O_D,
+ CNAT_V4_ICMP_Q_E_I2O_NEXT,
+} cnat_ipv4_icmp_q_inside_input_exc_next_t;
+
+#define CNAT_V4_ICMP_Q_E_I2O_GEN CNAT_V4_ICMP_Q_E_I2O_T
+
+cnat_ipv4_icmp_q_inside_input_exc_main_t cnat_ipv4_icmp_q_inside_input_exc_main;
+vlib_node_registration_t cnat_ipv4_icmp_q_inside_input_exc_node;
+
+#define NSTAGES 2
+
+/*
+ * Use the generic buffer metadata + first line of packet data prefetch
+ * stage function from <api/pipeline.h>. This is usually a Good Idea.
+ */
+#define stage0 generic_stage0
+
+static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
+ u32 bi)
+{
+ vlib_buffer_t *b0 = vlib_get_buffer (vm, bi);
+ int disposition = CNAT_V4_ICMP_Q_E_I2O_T;
+ int counter = CNAT_V4_ICMP_Q_I2O_E_T_PKT;
+
+ ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len);
+ vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_icmp_q_inside_input_exc_node.index);
+ u32 node_counter_base_index = n->error_heap_index;
+ vlib_error_main_t * em = &vm->error_main;
+
+ cnat_key_t dest_info;
+ cnat_gen_icmp_info info;
+ cnat_db_key_bucket_t ki;
+ cnat_main_db_entry_t *db = NULL;
+
+ PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX],
+ ki.k.k.vrf, CNAT_ICMP)
+
+ ki.k.k.ipv4 =
+ clib_net_to_host_u32(ip->src_addr);
+ ki.k.k.port =
+ clib_net_to_host_u16(icmp->identifier);
+
+ dest_info.k.port = 0;
+ dest_info.k.ipv4 = clib_net_to_host_u32(ip->dest_addr);
+ PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX],
+ dest_info.k.vrf, CNAT_ICMP)
+
+ db = cnat_get_main_db_entry_v2(&ki, PORT_SINGLE, PORT_TYPE_DYNAMIC,
+ &info, &dest_info);
+ if (PREDICT_TRUE(db != 0)) {
+
+ if (PREDICT_FALSE(icmp_debug_flag)) {
+ printf("\nDUMPING ICMP PKT BEFORE\n");
+ print_icmp_pkt(ip);
+ }
+
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ /*
+ * Decrement TTL and update IPv4 checksum
+ */
+ ipv4_decr_ttl_n_calc_csum(ip);
+ }
+
+ /*
+ * step 6 do nat before fwd pkt
+ */
+ swap_ip_src_icmp_id(ip, icmp, db, db->in2out_key.k.vrf);
+
+ if (PREDICT_FALSE(icmp_debug_flag)) {
+ printf("\nDUMPING ICMP PKT AFTER\n");
+ print_icmp_pkt(ip);
+ }
+
+ /*
+ * update db for this pkt
+ */
+ CNAT_DB_UPDATE_IN2OUT_TIMER
+ in2out_forwarding_count++;
+
+ } else {
+ switch (info.error) {
+ case (CNAT_NO_VRF_RUN):
+ counter = CNAT_V4_ICMP_Q_I2O_E_DR_PKT;
+ break;
+ case (CNAT_OUT_LIMIT):
+ counter = CNAT_V4_ICMP_Q_I2O_E_DO_PKT;
+ break;
+ case (CNAT_NO_PORT_ANY):
+ case (CNAT_NO_POOL_ANY):
+ case (CNAT_BAD_INUSE_ANY):
+ case (CNAT_NOT_FOUND_ANY):
+ counter = CNAT_V4_ICMP_Q_I2O_E_DA_PKT;
+ break;
+ case (CNAT_INV_PORT_DIRECT):
+ case (CNAT_DEL_PORT_DIRECT):
+ case (CNAT_BAD_INUSE_DIRECT):
+ case (CNAT_NOT_FOUND_DIRECT):
+ counter = CNAT_V4_ICMP_Q_I2O_E_DD_PKT;
+ break;
+ case (CNAT_ERR_NO_SESSION_DB):
+ counter = CNAT_V4_ICMP_Q_I2O_E_DS_PKT;
+ break;
+ default:
+ counter = CNAT_V4_ICMP_Q_I2O_E_DC_PKT;
+ break;
+ }
+ /*
+ * send to icmp msg generate node
+ */
+ if (info.gen_icmp_msg == CNAT_ICMP_MSG) {
+ #if 0
+ u32 *fd = (u32*)ctx->feature_data;
+ fd[0] = info.svi_addr;
+ fd[1] = CNAT_ICMP_DEST_UNREACHABLE;
+ #endif
+ disposition = CNAT_V4_ICMP_Q_E_I2O_GEN;
+ counter = CNAT_V4_ICMP_Q_I2O_E_G_PKT;
+ } else {
+ disposition = CNAT_V4_ICMP_Q_E_I2O_D;
+ counter = CNAT_V4_ICMP_Q_I2O_E_D_PKT;
+ }
+ DEBUG_I2O_DROP(CNAT_DEBUG_DROP_ICMP)
+ }
+
+ em->counters[node_counter_base_index + counter] += 1;
+
+ return disposition;
+}
+
+#include <vnet/pipeline.h>
+
+static uword cnat_ipv4_icmp_q_inside_input_exc_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return dispatch_pipeline (vm, node, frame);
+}
+
+VLIB_REGISTER_NODE (cnat_ipv4_icmp_q_inside_input_exc_node) = {
+ .function = cnat_ipv4_icmp_q_inside_input_exc_node_fn,
+ .name = "vcgn-v4-icmp-q-i2o-e",
+ .vector_size = sizeof (u32),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(cnat_ipv4_icmp_q_inside_input_exc_error_strings),
+ .error_strings = cnat_ipv4_icmp_q_inside_input_exc_error_strings,
+
+ .n_next_nodes = CNAT_V4_ICMP_Q_E_I2O_NEXT,
+
+ /* edit / add dispositions here */
+ .next_nodes = {
+ //[CNAT_V4_ICMP_Q_E_I2O_GEN] = "icmp_msg_gen", /* Currently it will go
+ //to ip4-input node. We have to port icmp msg generator node */
+ [CNAT_V4_ICMP_Q_E_I2O_T] = "ip4-input",
+ [CNAT_V4_ICMP_Q_E_I2O_D] = "error-drop",
+ },
+};
+
+
+clib_error_t *cnat_ipv4_icmp_q_inside_input_exc_init (vlib_main_t *vm)
+{
+ cnat_ipv4_icmp_q_inside_input_exc_main_t * mp = &cnat_ipv4_icmp_q_inside_input_exc_main;
+
+ mp->vlib_main = vm;
+ mp->vnet_main = vnet_get_main();
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (cnat_ipv4_icmp_q_inside_input_exc_init);
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_outside_input.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_outside_input.c
new file mode 100644
index 00000000..2c05e0b4
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_icmp_query_outside_input.c
@@ -0,0 +1,381 @@
+/*
+ *---------------------------------------------------------------------------
+ * cnat_ipv4_icmp_query_outside_input.c - cnat_ipv4_icmp_query_outside_input node pipeline stage functions
+ *
+ *
+ * Copyright (c) 2008-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/error.h>
+#include <vnet/buffer.h>
+
+#include "cnat_ipv4_icmp.h"
+
+#define foreach_cnat_ipv4_icmp_q_outside_input_error \
+_(CNAT_V4_ICMP_Q_O2I_T_PKT, "cnat v4 icmp_q o2i packet transmit") \
+_(CNAT_V4_ICMP_Q_O2I_MISS_PKT, "cnat v4 icmp_q o2i drop") \
+_(CNAT_V4_ICMP_Q_O2I_TTL_GEN, "cnat v4 icmp_q o2i ttl generate") \
+_(CNAT_V4_ICMP_Q_O2I_TTL_DROP, "cnat v4 icmp_q o2i ttl drop") \
+_(CNAT_V4_ICMP_Q_O2I_NO_SESSION_DROP, "cnat v4 icmp_q o2i no session drop")
+
+typedef enum {
+#define _(sym,str) sym,
+ foreach_cnat_ipv4_icmp_q_outside_input_error
+#undef _
+ CNAT_IPV4_ICMP_Q_OUTSIDE_INPUT_N_ERROR,
+} cnat_ipv4_icmp_q_outside_input_t;
+
+static char * cnat_ipv4_icmp_q_outside_input_error_strings[] = {
+#define _(sym,string) string,
+ foreach_cnat_ipv4_icmp_q_outside_input_error
+#undef _
+};
+
+typedef struct {
+ u32 cached_next_index;
+ /* $$$$ add data here */
+
+ /* convenience variables */
+ vlib_main_t * vlib_main;
+ vnet_main_t * vnet_main;
+} cnat_ipv4_icmp_q_outside_input_main_t;
+
+typedef enum {
+ CNAT_V4_ICMP_Q_O2I_T,
+ CNAT_V4_ICMP_Q_O2I_D,
+ CNAT_V4_ICMP_Q_O2I_NEXT,
+} cnat_ipv4_icmp_q_outside_input_next_t;
+
+cnat_ipv4_icmp_q_outside_input_main_t cnat_ipv4_icmp_q_outside_input_main;
+vlib_node_registration_t cnat_ipv4_icmp_q_outside_input_node;
+
+#define NSTAGES 5
+
+inline void swap_ip_dst_icmp_id(ipv4_header *ip,
+ icmp_v4_t *icmp,
+ cnat_main_db_entry_t *db, u16 vrf)
+{
+#if 0
+ u32 postmap_ip;
+ u8 direction;
+ u32 old_ip;
+ u32 old_postmap_ip;
+
+ if(is_static_dest_nat_enabled(vrf) == CNAT_SUCCESS) {
+ direction = 1;
+ if(cnat_static_dest_db_get_translation(ip->src_addr, &postmap_ip, vrf, direction) == CNAT_SUCCESS) {
+ CNAT_UPDATE_L3_CHECKSUM_DECLARE
+
+ old_ip = spp_net_to_host_byte_order_32(&(ip->src_addr));
+ old_postmap_ip = spp_net_to_host_byte_order_32(&postmap_ip);
+
+ CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip & 0xFFFF)),
+ ((u16)(old_ip >> 16)),
+ (spp_net_to_host_byte_order_16(&(ip->checksum))),
+ ((u16)(old_postmap_ip & 0xFFFF)),
+ ((u16)(old_postmap_ip >> 16)))
+ ip->checksum =
+ spp_host_to_net_byte_order_16(new_l3_c);
+ ip->src_addr = postmap_ip;
+ }
+ }
+#endif /* if 0 */
+ /*
+ * declare variable
+ */
+ CNAT_UPDATE_L3_L4_CHECKSUM_DECLARE
+ /*
+ * calculate checksum
+ */
+ CNAT_UPDATE_L3_ICMP_CHECKSUM(((u16)(db->out2in_key.k.ipv4)),
+ ((u16)(db->out2in_key.k.ipv4 >> 16)),
+ (db->out2in_key.k.port),
+ (clib_net_to_host_u16(ip->checksum)),
+ (clib_net_to_host_u16(icmp->checksum)),
+ ((u16)(db->in2out_key.k.ipv4)),
+ ((u16)(db->in2out_key.k.ipv4 >> 16)),
+ (db->in2out_key.k.port))
+ //set ip header
+ ip->dest_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+ ip->checksum =
+ clib_host_to_net_u16(new_l3_c);
+
+ //set icmp header
+ icmp->identifier =
+ clib_host_to_net_u16(db->in2out_key.k.port);
+ icmp->checksum =
+ clib_host_to_net_u16(new_l4_c);
+}
+
+/*
+ * Use the generic buffer metadata + first line of packet data prefetch
+ * stage function from <api/pipeline.h>. This is usually a Good Idea.
+ */
+#define stage0 generic_stage0
+
+static inline void
+stage1(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ u64 a, b, c;
+ u32 bucket;
+ u8 *prefetch_target;
+
+ vlib_buffer_t * b0 = vlib_get_buffer (vm, buffer_index);
+ ipv4_header *ip = vlib_buffer_get_current (b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len);
+
+ u64 tmp = 0;
+ tmp = vnet_buffer(b0)->vcgn_uii.key.k.ipv4 =
+ clib_net_to_host_u32(ip->dest_addr);
+ vnet_buffer(b0)->vcgn_uii.key.k.port =
+ clib_net_to_host_u16 (icmp->identifier);
+
+ tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.port) << 32;
+
+ PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX],
+ vnet_buffer(b0)->vcgn_uii.key.k.vrf,
+ CNAT_ICMP)
+ tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.vrf) << 48;
+
+ CNAT_V4_GET_HASH(tmp, bucket, CNAT_MAIN_HASH_MASK)
+
+ prefetch_target = (u8 *)(&cnat_out2in_hash[bucket]);
+ vnet_buffer(b0)->vcgn_uii.bucket = bucket;
+
+ /* Prefetch the hash bucket */
+ CLIB_PREFETCH(prefetch_target, CLIB_CACHE_LINE_BYTES, LOAD);
+}
+
+#define SPP_LOG2_CACHE_LINE_BYTES 6
+#define SPP_CACHE_LINE_BYTES (1 << SPP_LOG2_CACHE_LINE_BYTES)
+
+static inline void
+stage2(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index);
+ uword prefetch_target0, prefetch_target1;
+ u32 bucket = vnet_buffer(b0)->vcgn_uii.bucket;
+
+ /* read the hash bucket */
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket
+ = cnat_out2in_hash[bucket].next;
+
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+ /*
+ * Prefetch database keys. We save space by not cache-line
+ * aligning the DB entries. We don't want to waste LSU
+ * bandwidth prefetching stuff we won't need.
+ */
+ prefetch_target0 = (uword)(cnat_main_db + db_index);
+ CLIB_PREFETCH((void*)prefetch_target0, CLIB_CACHE_LINE_BYTES, LOAD);
+ /* Just beyond DB key #2 */
+ prefetch_target1 = prefetch_target0 +
+ STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports);
+ /* If the targets are in different lines, do the second prefetch */
+ if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) !=
+ (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) {
+ CLIB_PREFETCH((void *)prefetch_target1, CLIB_CACHE_LINE_BYTES, LOAD);
+ }
+ }
+}
+
+static inline void
+stage3(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ cnat_main_db_entry_t *db;
+ vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index);
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket;
+
+ /*
+ * Note: if the search already failed (empty bucket),
+ * the answer is already in the pipeline context structure
+ */
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+
+ /*
+ * Note: hash collisions suck. We can't easily prefetch around them.
+ * The first trip around the track will be fast. After that, maybe
+ * not so much...
+ */
+ do {
+ db = cnat_main_db + db_index;
+ if (PREDICT_TRUE(db->out2in_key.key64 ==
+ vnet_buffer(b0)->vcgn_uii.key.key64)) {
+ break;
+ }
+ db_index = db->out2in_hash.next;
+ } while (db_index != EMPTY);
+
+ /* Stick the answer back into the pipeline context structure */
+ vnet_buffer(b0)->vcgn_uii.bucket = db_index;
+ }
+}
+
+
+static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
+ u32 bi)
+{
+
+ vlib_buffer_t *b0 = vlib_get_buffer (vm, bi);
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket;
+ int disposition = CNAT_V4_ICMP_Q_O2I_T;
+ int counter = CNAT_V4_ICMP_Q_O2I_T_PKT;
+
+ ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ icmp_v4_t *icmp = (icmp_v4_t *)((u8*)ip + ipv4_hdr_len);
+ vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_icmp_q_outside_input_node.index);
+ u32 node_counter_base_index = n->error_heap_index;
+ vlib_error_main_t * em = &vm->error_main;
+ cnat_session_entry_t *session_db = NULL;
+ cnat_main_db_entry_t *db = NULL;
+ cnat_key_t dest_info;
+ cnat_vrfmap_t * vrf_map_p __attribute__((unused)) = NULL;
+ u32 vrf_index __attribute__((unused)) = 0;
+
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+
+ db = cnat_main_db + db_index;
+ dest_info.k.port = 0;
+ dest_info.k.ipv4 = clib_net_to_host_u32(ip->src_addr);
+
+ if (PREDICT_FALSE(icmp_debug_flag)) {
+ printf("\nDUMPING ICMP PKT BEFORE\n");
+ print_icmp_pkt(ip);
+ }
+
+ vrf_map_p = cnat_map_by_vrf + db->vrfmap_index;
+ vrf_index = (db->in2out_key.k.vrf & CNAT_VRF_MASK);
+
+ if(PREDICT_TRUE(!PLATFORM_DBL_SUPPORT)) {
+
+ /* No DBL support, so just update the destn and proceed */
+ db->dst_ipv4 = dest_info.k.ipv4;
+ db->dst_port = dest_info.k.port;
+ goto update_pkt;
+ }
+
+ if(PREDICT_FALSE(db->dst_ipv4 != dest_info.k.ipv4)) {
+
+ if(PREDICT_TRUE(db->nsessions == 1)) {
+ /* Handle one to 2 dest scenarion */
+ dest_info.k.vrf = db->in2out_key.k.vrf;
+ session_db = cnat_handle_1to2_session(db, &dest_info);
+
+ if(PREDICT_FALSE(session_db == NULL)) {
+ disposition = CNAT_V4_ICMP_Q_O2I_D;
+ counter = CNAT_V4_ICMP_Q_O2I_NO_SESSION_DROP;
+ goto drop_pkt;
+ }
+ } else if (PREDICT_FALSE(db->nsessions == 0)) {
+ /* Should be a static entry
+ * Note this session as the first session and log
+ */
+ cnat_add_dest_n_log(db, &dest_info);
+ } else { /* Many translations exist already */
+ dest_info.k.vrf = db->in2out_key.k.vrf;
+ /* If session already exists,
+ * cnat_create_session_db_entry will return the existing db
+ * else create a new db
+ * If could not create, return NULL
+ */
+ session_db = cnat_create_session_db_entry(&dest_info,
+ db, TRUE);
+
+ if(PREDICT_FALSE(session_db == NULL)) {
+ disposition = CNAT_V4_ICMP_Q_O2I_D;
+ counter = CNAT_V4_ICMP_Q_O2I_NO_SESSION_DROP;
+ goto drop_pkt;
+ }
+ }
+ }
+
+update_pkt:
+
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ /*
+ * Decrement TTL and update IPv4 checksum
+ */
+ ipv4_decr_ttl_n_calc_csum(ip);
+ }
+
+ /*
+ * 1. update dest ipv4 addr and icmp id
+ * 2. update ipv4 checksum and icmp checksum
+ */
+ swap_ip_dst_icmp_id(ip, icmp, db, db->in2out_key.k.vrf);
+
+ if (PREDICT_FALSE(icmp_debug_flag)) {
+ printf("\nDUMPING ICMP PKT AFTER\n");
+ print_icmp_pkt(ip);
+ }
+
+ db->out2in_pkts++;
+
+ //nat44_dslite_global_stats[dslite_flag].out2in_forwarding_count++;
+
+ } else {
+ disposition = CNAT_V4_ICMP_Q_O2I_D;
+ counter = CNAT_V4_ICMP_Q_O2I_MISS_PKT;
+ }
+
+drop_pkt:
+ em->counters[node_counter_base_index + counter] += 1;
+ return disposition;
+
+}
+
+#include <vnet/pipeline.h>
+
+static uword cnat_ipv4_icmp_q_outside_input_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return dispatch_pipeline (vm, node, frame);
+}
+
+
+VLIB_REGISTER_NODE (cnat_ipv4_icmp_q_outside_input_node) = {
+ .function = cnat_ipv4_icmp_q_outside_input_node_fn,
+ .name = "vcgn-v4-icmp-q-o2i",
+ .vector_size = sizeof (u32),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(cnat_ipv4_icmp_q_outside_input_error_strings),
+ .error_strings = cnat_ipv4_icmp_q_outside_input_error_strings,
+
+ .n_next_nodes = CNAT_V4_ICMP_Q_O2I_NEXT,
+
+ /* edit / add dispositions here */
+ .next_nodes = {
+ [CNAT_V4_ICMP_Q_O2I_T] = "ip4-input",
+ [CNAT_V4_ICMP_Q_O2I_D] = "error-drop",
+ },
+};
+
+clib_error_t *cnat_ipv4_icmp_q_outside_input_init (vlib_main_t *vm)
+{
+ cnat_ipv4_icmp_q_outside_input_main_t * mp = &cnat_ipv4_icmp_q_outside_input_main;
+
+ mp->vlib_main = vm;
+ mp->vnet_main = vnet_get_main();
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (cnat_ipv4_icmp_q_outside_input_init);
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_inside_input.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_inside_input.c
new file mode 100644
index 00000000..5bea7073
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_inside_input.c
@@ -0,0 +1,424 @@
+/*
+ *---------------------------------------------------------------------------
+ * cnat_ipv4_tcp_inside_input.c - cnat_ipv4_tcp_inside_input node pipeline
+ * stage functions
+ *
+ *
+ * Copyright (c) 2008-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/error.h>
+#include <vnet/buffer.h>
+
+#include "cnat_db.h"
+#include "tcp_header_definitions.h"
+#include "cnat_config.h"
+#include "cnat_global.h"
+#include "cnat_v4_functions.h"
+
+#define foreach_cnat_ipv4_tcp_inside_input_error \
+_(CNAT_V4_TCP_I2O_PKT_IN, "tcp i2o packets received") \
+_(CNAT_V4_TCP_I2O_PKT_T, "tcp i2o packets natted") \
+_(CNAT_V4_TCP_I2O_EXCEPTION, "packets to tcp i2o exception") \
+_(CNAT_V4_TCP_I2O_TTL_GEN, "generated TTL expiry ICMP packets") \
+_(CNAT_V4_TCP_I2O_TTL_GEN_DROP, "could not generate TTL expiry ICMP packets") \
+_(CNAT_V4_TCP_I2O_SESSION_DROP, "could not generate session") \
+_(CNAT_V4_UDP_I2O_FRAG_DROP, "non-first fragment drop")
+
+typedef enum {
+#define _(sym,str) sym,
+ foreach_cnat_ipv4_tcp_inside_input_error
+#undef _
+ CNAT_IPV4_TCP_INSIDE_INPUT_N_ERROR,
+} cnat_ipv4_tcp_inside_input_t;
+
+static char * cnat_ipv4_tcp_inside_input_error_strings[] = {
+#define _(sym,string) string,
+ foreach_cnat_ipv4_tcp_inside_input_error
+#undef _
+};
+
+typedef struct {
+ u32 cached_next_index;
+ /* $$$$ add data here */
+
+ /* convenience variables */
+ vlib_main_t * vlib_main;
+ vnet_main_t * vnet_main;
+} cnat_ipv4_tcp_inside_input_main_t;
+
+typedef enum {
+ CNAT_V4_TCP_I2O_E,
+ CNAT_V4_TCP_I2O_T,
+ CNAT_V4_TCP_I2O_D,
+ CNAT_V4_TCP_I2O_NEXT,
+} cnat_ipv4_tcp_inside_input_next_t;
+
+#define CNAT_REWRITE_OUTPUT CNAT_V4_TCP_I2O_T
+#define CNAT_V4_ICMP_GEN CNAT_V4_TCP_I2O_D
+
+//#define CNAT_V4_TCP_I2O_E CNAT_V4_TCP_I2O_D //remove it once exception node is created
+cnat_ipv4_tcp_inside_input_main_t cnat_ipv4_tcp_inside_input_main;
+vlib_node_registration_t cnat_ipv4_tcp_inside_input_node;
+
+#define NSTAGES 6
+
+/*
+ * Use the generic buffer metadata + first line of packet data prefetch
+ * stage function from <api/pipeline.h>. This is usually a Good Idea.
+ */
+#define stage0 generic_stage0
+
+
+static inline void
+stage1(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ u64 a, b, c;
+ u32 bucket;
+ u8 *prefetch_target;
+ //cnat_feature_data_t *fd = (cnat_feature_data_t *)ctx->feature_data;
+
+
+ vlib_buffer_t * b0 = vlib_get_buffer (vm, buffer_index);
+ ipv4_header *ip = vlib_buffer_get_current (b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ tcp_hdr_type *tcp = (tcp_hdr_type *)((u8*)ip + ipv4_hdr_len);
+
+ u64 tmp = 0;
+ tmp = vnet_buffer(b0)->vcgn_uii.key.k.ipv4 =
+ clib_net_to_host_u32(ip->src_addr);
+ vnet_buffer(b0)->vcgn_uii.key.k.port =
+ clib_net_to_host_u16 (tcp->src_port);
+
+ tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.port) << 32;
+
+ PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX],
+ vnet_buffer(b0)->vcgn_uii.key.k.vrf,
+ CNAT_TCP)
+ tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.vrf) << 48;
+
+ CNAT_V4_GET_HASH(tmp, bucket, CNAT_MAIN_HASH_MASK)
+
+ prefetch_target = (u8 *)(&cnat_in2out_hash[bucket]);
+ vnet_buffer(b0)->vcgn_uii.bucket = bucket;
+
+ /* Prefetch the hash bucket */
+ CLIB_PREFETCH(prefetch_target, CLIB_CACHE_LINE_BYTES, LOAD);
+}
+
+static inline void
+stage2(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{ /* nothing */ }
+
+
+#define SPP_LOG2_CACHE_LINE_BYTES 6
+#define SPP_CACHE_LINE_BYTES (1 << SPP_LOG2_CACHE_LINE_BYTES)
+
+static inline void
+stage3(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index);
+ uword prefetch_target0, prefetch_target1;
+ u32 bucket = vnet_buffer(b0)->vcgn_uii.bucket;
+
+ /* read the hash bucket */
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket
+ = cnat_in2out_hash[bucket].next;
+
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+ /*
+ * Prefetch database keys. We save space by not cache-line
+ * aligning the DB entries. We don't want to waste LSU
+ * bandwidth prefetching stuff we won't need.
+ */
+ prefetch_target0 = (uword)(cnat_main_db + db_index);
+ CLIB_PREFETCH((void*)prefetch_target0, CLIB_CACHE_LINE_BYTES, LOAD);
+ /* Just beyond DB key #2 */
+ prefetch_target1 = prefetch_target0 +
+ STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports);
+ /* If the targets are in different lines, do the second prefetch */
+ if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) !=
+ (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) {
+ CLIB_PREFETCH((void *)prefetch_target1, CLIB_CACHE_LINE_BYTES, LOAD);
+ }
+ }
+}
+
+static inline void
+stage4(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ cnat_main_db_entry_t *db;
+ vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index);
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket;
+
+ /*
+ * Note: if the search already failed (empty bucket),
+ * the answer is already in the pipeline context structure
+ */
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+
+ /*
+ * Note: hash collisions suck. We can't easily prefetch around them.
+ * The first trip around the track will be fast. After that, maybe
+ * not so much...
+ */
+ do {
+ db = cnat_main_db + db_index;
+ if (PREDICT_TRUE(db->in2out_key.key64 ==
+ vnet_buffer(b0)->vcgn_uii.key.key64)) {
+ break;
+ }
+ db_index = db->in2out_hash.next;
+ } while (db_index != EMPTY);
+
+ /* Stick the answer back into the pipeline context structure */
+ vnet_buffer(b0)->vcgn_uii.bucket = db_index;
+ }
+}
+
+
+static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
+ u32 bi)
+{
+ vlib_buffer_t *b0 = vlib_get_buffer (vm, bi);
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket;
+ spp_ctx_t *ctx = (spp_ctx_t *) &vnet_buffer(b0)->vcgn_uii;
+ int disposition = CNAT_V4_TCP_I2O_T;
+ int counter = CNAT_V4_TCP_I2O_PKT_T;
+
+ ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ tcp_hdr_type *tcp = (tcp_hdr_type *)((u8*)ip + ipv4_hdr_len);
+ vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_tcp_inside_input_node.index);
+ u32 node_counter_base_index = n->error_heap_index;
+ vlib_error_main_t * em = &vm->error_main;
+ cnat_session_entry_t *session_db = NULL;
+ cnat_main_db_entry_t *db = NULL;
+ cnat_key_t dest_info;
+ u32 window;
+ u8 scale;
+
+
+ INCREMENT_NODE_COUNTER(CNAT_V4_TCP_I2O_PKT_IN);
+
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ if (PREDICT_FALSE(ip->ttl <= 1)) {
+ /* Try to generate ICMP error msg, as TTL is <= 1 */
+
+ if (icmpv4_generate_with_throttling
+ (ctx, ip, ctx->ru.rx.uidb_index)) {
+
+ /* Generated ICMP */
+ disposition = CNAT_REWRITE_OUTPUT;
+ counter = CNAT_V4_TCP_I2O_TTL_GEN;
+ } else {
+ /* Could not generated ICMP - drop the packet */
+ disposition = CNAT_V4_TCP_I2O_D;
+ counter = CNAT_V4_TCP_I2O_TTL_GEN_DROP;
+ }
+ goto drop_pkt;
+ }
+ }
+
+ if (PREDICT_FALSE(db_index == EMPTY)) {
+ /* Deleted fragment code from here */
+ disposition = CNAT_V4_TCP_I2O_E;
+ counter = CNAT_V4_TCP_I2O_EXCEPTION;
+ } else {
+ db = cnat_main_db + db_index;
+
+ /* Handle destination sessions */
+ dest_info.k.port = clib_net_to_host_u16(tcp->dest_port);
+ dest_info.k.ipv4 = clib_net_to_host_u32(ip->dest_addr);
+
+ if(PREDICT_TRUE(!PLATFORM_DBL_SUPPORT)) {
+
+ /* No DBL support, so just update the destn and proceed */
+ db->dst_ipv4 = dest_info.k.ipv4;
+ db->dst_port = dest_info.k.port;
+ goto update_pkt;
+ }
+
+ if(PREDICT_FALSE(db->dst_ipv4 != dest_info.k.ipv4 ||
+ db->dst_port != dest_info.k.port)) {
+ if(PREDICT_TRUE(db->nsessions == 0)) {
+ /* Should be a static entry
+ * Note this session as the first session and log
+ */
+ cnat_add_dest_n_log(db, &dest_info);
+ } else if(PREDICT_FALSE(db->nsessions == 1)) {
+ /* Destn is not same as in main db. Multiple session
+ * scenario
+ */
+ dest_info.k.vrf = db->in2out_key.k.vrf;
+ session_db = cnat_handle_1to2_session(db, &dest_info);
+ if(PREDICT_FALSE(session_db == NULL)) {
+ disposition = CNAT_V4_TCP_I2O_D;
+ counter = CNAT_V4_TCP_I2O_SESSION_DROP;
+ goto drop_pkt;
+ }
+ } else { /* There are already multiple destinations */
+ dest_info.k.vrf = db->in2out_key.k.vrf;
+ /* If session already exists,
+ * cnat_create_session_db_entry will return the existing db
+ * else create a new db
+ * If could not create, return NULL
+ */
+ session_db = cnat_create_session_db_entry(&dest_info,
+ db, TRUE);
+ if(PREDICT_FALSE(session_db == NULL)) {
+ disposition = CNAT_V4_TCP_I2O_D;
+ counter = CNAT_V4_TCP_I2O_SESSION_DROP;
+ goto drop_pkt;
+ }
+ }
+ if(PREDICT_TRUE(session_db != 0)) {
+ /* Have to repeat the window size check for new destinations */
+ window = (u32)clib_net_to_host_u16(tcp->window_size);
+ window = window << session_db->scale;
+ if(PREDICT_TRUE(!session_db->window)) {
+ calculate_window_scale(tcp, &scale);
+ session_db->scale = scale;
+ session_db->window = window;
+ } else if (PREDICT_FALSE(session_db->window <
+ window)) {
+ /* Update the db entry with window option from packet */
+ session_db->window = window;
+ } else {
+ /* Do nothing */
+ }
+ session_db->tcp_seq_num = clib_net_to_host_u32(tcp->seq_num);
+ session_db->ack_no = clib_net_to_host_u32(tcp->ack_num);
+#if DEBUG > 1
+ printf("\n In2out SDB stages seq no = %u,"
+ " ack no = %u, window = %u\n",
+ session_db->tcp_seq_num,
+ session_db->ack_no,
+ session_db->window);
+#endif
+
+ }
+ } else {
+ //Update the seq no and ack no for subsequent communication
+ //after connection establishment
+ //No need to update window here. Window is already updated
+ //during connection establishment
+ window = (u32)clib_net_to_host_u16(tcp->window_size);
+ window = window << db->scale;
+ if(PREDICT_FALSE(!ALG_ENABLED_DB(db))) {
+ //This check is done since proto_data is part of union in main
+ //db entry
+ db->proto_data.tcp_seq_chk.seq_no =
+ clib_net_to_host_u32(tcp->seq_num);
+ db->proto_data.tcp_seq_chk.ack_no =
+ clib_net_to_host_u32(tcp->ack_num);
+ }
+ if (PREDICT_FALSE(db->diff_window < window)) {
+ /* Update the db entry with window option from packet */
+ db->diff_window = window;
+ }
+#if DEBUG > 1
+ printf("\n In2out MainDB seq no = %u,"
+ "\n ack no = %u\n",
+ db->proto_data.tcp_seq_chk.seq_no,
+ db->proto_data.tcp_seq_chk.ack_no);
+ printf("\n In2out MAINDB window = %u\n",
+ db->diff_window);
+#endif
+ }
+update_pkt:
+
+ counter = CNAT_V4_TCP_I2O_PKT_T;
+ disposition = CNAT_V4_TCP_I2O_T;
+
+ /* NO FRAGMENT & ALG HANDLING. DELETING THE CODE */
+
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ /*
+ * Decrement TTL and update IPv4 checksum
+ */
+ ipv4_decr_ttl_n_calc_csum(ip);
+ }
+
+ tcp_in2out_nat_mss_n_checksum(ip,
+ tcp,
+ db->out2in_key.k.ipv4,
+ db->out2in_key.k.port,
+ db
+ /*, db->in2out_key.k.vrf */);
+
+ /* update transaltion counters */
+ db->in2out_pkts++;
+ in2out_forwarding_count++;
+
+ /* update the timer for good mode, or evil mode dst_ip match */
+
+ if(PREDICT_FALSE(session_db != NULL)) {
+ V4_TCP_UPDATE_SESSION_DB_FLAG(session_db, tcp);
+ CNAT_DB_TIMEOUT_RST(session_db);
+ } else {
+ V4_TCP_UPDATE_SESSION_FLAG(db, tcp);
+ CNAT_DB_TIMEOUT_RST(db);
+ }
+ }
+
+drop_pkt:
+
+ em->counters[node_counter_base_index + counter] += 1;
+ return disposition;
+}
+
+#include <vnet/pipeline.h>
+
+static uword cnat_ipv4_tcp_inside_input_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return dispatch_pipeline (vm, node, frame);
+}
+
+
+VLIB_REGISTER_NODE (cnat_ipv4_tcp_inside_input_node) = {
+ .function = cnat_ipv4_tcp_inside_input_node_fn,
+ .name = "vcgn-v4-tcp-i2o",
+ .vector_size = sizeof (u32),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(cnat_ipv4_tcp_inside_input_error_strings),
+ .error_strings = cnat_ipv4_tcp_inside_input_error_strings,
+
+ .n_next_nodes = CNAT_V4_TCP_I2O_NEXT,
+
+ /* edit / add dispositions here */
+ .next_nodes = {
+ [CNAT_V4_TCP_I2O_E] = "vcgn-v4-tcp-i2o-e",
+ [CNAT_V4_TCP_I2O_T] = "ip4-input",
+ [CNAT_V4_TCP_I2O_D] = "error-drop",
+ },
+};
+
+clib_error_t *cnat_ipv4_tcp_inside_input_init (vlib_main_t *vm)
+{
+ cnat_ipv4_tcp_inside_input_main_t * mp = &cnat_ipv4_tcp_inside_input_main;
+
+ mp->vlib_main = vm;
+ mp->vnet_main = vnet_get_main();
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (cnat_ipv4_tcp_inside_input_init);
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_inside_input_exceptions.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_inside_input_exceptions.c
new file mode 100644
index 00000000..bc1bebb0
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_inside_input_exceptions.c
@@ -0,0 +1,314 @@
+/*
+ *---------------------------------------------------------------------------
+ * cnat_ipv4_tcp_inside_input_exceptions.c -
+ * cnat_ipv4_tcp_inside_input_exceptions node pipeline stage functions
+ *
+ *
+ * Copyright (c) 2008-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/error.h>
+#include <vnet/buffer.h>
+
+#include "cnat_db.h"
+#include "tcp_header_definitions.h"
+#include "cnat_config.h"
+#include "cnat_global.h"
+#include "cnat_v4_functions.h"
+
+
+#define foreach_cnat_ipv4_tcp_inside_input_exc_error \
+_(CNAT_V4_TCP_I2O_E_T_PKT, "v4 tcp i2o-e transmit natted pkt") \
+_(CNAT_V4_TCP_I2O_E_D_NON_SYN_PKT, "v4 tcp i2o-e non syn drop") \
+_(CNAT_V4_TCP_I2O_E_D_INVALID_PKT, "v4 tcp i2o-e invalid pkt drop") \
+_(CNAT_V4_TCP_I2O_E_DROP, "v4 tcp i2o-e drop") \
+_(CNAT_V4_TCP_I2O_E_GEN_ICMP, "v4 tcp i2o-e gen icmp msg") \
+_(CNAT_V4_TCP_I2O_E_D_NO_SESSION, "v4 tcp i2o-e no session db entry drop")
+
+typedef enum {
+#define _(sym,str) sym,
+ foreach_cnat_ipv4_tcp_inside_input_exc_error
+#undef _
+ CNAT_IPV4_TCP_INSIDE_INPUT_EXCEPTIONS_N_ERROR,
+} cnat_ipv4_tcp_inside_input_exc_error_t;
+
+
+static char * cnat_ipv4_tcp_inside_input_exc_error_strings[] = {
+#define _(sym,string) string,
+ foreach_cnat_ipv4_tcp_inside_input_exc_error
+#undef _
+};
+
+typedef struct {
+ u32 cached_next_index;
+ /* $$$$ add data here */
+
+ /* convenience variables */
+ vlib_main_t * vlib_main;
+ vnet_main_t * vnet_main;
+} cnat_ipv4_tcp_inside_input_exc_main_t;
+
+typedef enum {
+ CNAT_V4_TCP_I2O_E_T,
+ //CNAT_V4_TCP_I2O_E_ICMP,
+ CNAT_V4_TCP_I2O_E_D,
+ CNAT_V4_TCP_I2O_E_NEXT,
+} cnat_ipv4_udp_inside_input_exc_next_t;
+
+#define CNAT_V4_TCP_I2O_E_ICMP CNAT_V4_TCP_I2O_E_D
+
+cnat_ipv4_tcp_inside_input_exc_main_t cnat_ipv4_tcp_inside_input_exc_main;
+vlib_node_registration_t cnat_ipv4_tcp_inside_input_exc_node;
+
+#define NSTAGES 2
+
+/*
+ * Use the generic buffer metadata + first line of packet data prefetch
+ * stage function from <api/pipeline.h>. This is usually a Good Idea.
+ */
+#define stage0 generic_stage0
+
+
+static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
+ u32 bi)
+{
+ vlib_buffer_t *b0 = vlib_get_buffer (vm, bi);
+ vlib_node_t *n =
+ vlib_get_node (vm, cnat_ipv4_tcp_inside_input_exc_node.index);
+ u32 node_counter_base_index = n->error_heap_index;
+ vlib_error_main_t * em = &vm->error_main;
+
+ cnat_gen_icmp_info info;
+ cnat_db_key_bucket_t ki;
+ cnat_main_db_entry_t *db = NULL;
+ ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ tcp_hdr_type *tcp = (tcp_hdr_type *)((u8*)ip + ipv4_hdr_len);
+ int disposition = CNAT_V4_TCP_I2O_E_T;
+ int counter = CNAT_V4_TCP_I2O_E_T_PKT;
+ cnat_key_t dest_info;
+ u32 window;
+ u8 scale;
+
+ window = (u32)clib_net_to_host_u16(tcp->window_size);
+ calculate_window_scale(tcp, &scale);
+
+ dest_info.k.port = clib_net_to_host_u16(tcp->dest_port);
+ dest_info.k.ipv4 = clib_net_to_host_u32(ip->dest_addr);
+
+ PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX],
+ dest_info.k.vrf, CNAT_TCP)
+
+ /* for TCP if not SYN or if src_port is 0, silently drop the packet */
+ if (PREDICT_FALSE(!((tcp->flags & TCP_FLAG_SYN) && (tcp->src_port)))) {
+
+ /*
+ * If the packet is dropped due to both reasons,
+ * count it as invalid packet drop
+ */
+ if (!tcp->src_port) {
+ counter = CNAT_V4_TCP_I2O_E_D_INVALID_PKT;
+ } else {
+ counter = CNAT_V4_TCP_I2O_E_D_NON_SYN_PKT;
+ }
+ disposition = CNAT_V4_TCP_I2O_E_D;
+ goto in2out_e;
+ }
+
+ PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX],
+ ki.k.k.vrf, CNAT_TCP)
+
+ ki.k.k.ipv4 = clib_net_to_host_u32(ip->src_addr);
+ ki.k.k.port = clib_net_to_host_u16(tcp->src_port);
+
+ db = cnat_get_main_db_entry_v2(&ki, PORT_SINGLE, PORT_TYPE_DYNAMIC, &info,
+ &dest_info);
+
+
+#if DEBUG > 1
+ if(PREDICT_TRUE(db)) {
+ printf("create db %x ip %x->%x port %x->%x dst_ip %x\n", db,
+ db->in2out_key.k.ipv4, db->out2in_key.k.ipv4,
+ db->in2out_key.k.port, db->out2in_key.k.port, db->dst_ipv4);
+ }
+#endif
+
+
+ if (PREDICT_FALSE(db == 0)) {
+ /* failed to create new db entry due to either no more port, or user limit reached,
+ * need to generate ICMP type=3,code=13 msg here,
+ */
+
+ /*
+ * we rate limit the icmp msg per private user,
+ * so we don't flood a user with icmp msg
+ * in case the per user port limit reached
+ */
+ if (PREDICT_TRUE(info.gen_icmp_msg == CNAT_ICMP_MSG)) {
+ /* KEEPING THINGS COMMENTED HERE..MAY NEED TO REVISIT AGAIN */
+ #if 0
+ u32 *fd = (u32*)ctx->feature_data;
+ fd[0] = info.svi_addr;
+ fd[1] = CNAT_ICMP_DEST_UNREACHABLE;
+
+ /*
+ * Let's reverse the direction from i2o to o2i.
+ * This will help using the correct VRF in the fib lookup (AVSM)
+ * especially for the o2i_vrf_override case
+ */
+ ctx->ru.rx.direction = 0; // 0 - o2i, 1 - i2o
+ #endif
+ disposition = CNAT_V4_TCP_I2O_E_ICMP;
+ counter = CNAT_V4_TCP_I2O_E_GEN_ICMP;
+
+ } else {
+ disposition = CNAT_V4_TCP_I2O_E_D;
+ counter = CNAT_V4_TCP_I2O_E_DROP;
+ }
+ //DEBUG_I2O_DROP(CNAT_DEBUG_DROP_TCP)
+ } else {
+
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ /*
+ * Decrement TTL and update IPv4 checksum
+ */
+ ipv4_decr_ttl_n_calc_csum(ip);
+ }
+
+ /* NAT the packet and fix checksum */
+
+ tcp_in2out_nat_mss_n_checksum(ip,
+ tcp,
+ db->out2in_key.k.ipv4,
+ db->out2in_key.k.port,
+ db
+ /*, db->in2out_key.k.vrf */);
+
+ /* this must be inside to outside SYN, do mss here */
+
+ /* update translation counters */
+ db->in2out_pkts++;
+
+ /* set keepalive timer */
+
+ if(PREDICT_TRUE((dest_info.k.ipv4 == db->dst_ipv4) &&
+ (dest_info.k.port == db->dst_port))) {
+ if(PREDICT_FALSE(!ALG_ENABLED_DB(db))) {
+ //This check is done since proto_data is part of union in main
+ //db entry
+
+ db->proto_data.tcp_seq_chk.seq_no =
+ clib_net_to_host_u32(tcp->seq_num);
+ db->proto_data.tcp_seq_chk.ack_no =
+ clib_net_to_host_u32(tcp->ack_num);
+ db->scale = scale;
+ db->diff_window = window;
+ }
+#if DEBUG > 1
+ PLATFORM_DEBUG_PRINT("\nMain DB seq no = %u,"
+ "ack no = %u, window = %u,"
+ "scale = %u",
+ db->proto_data.tcp_seq_chk.seq_no,
+ db->proto_data.tcp_seq_chk.ack_no,
+ db->diff_window
+ db->scale);
+#endif
+ V4_TCP_UPDATE_SESSION_FLAG(db, tcp);
+ /* Check timeout db if there is config for this */
+ (void) query_and_update_db_timeout((void *)db, MAIN_DB_TYPE);
+ db->entry_expires = cnat_current_time;
+ } else {
+ /* Got to find out the session entry corresponding to this..*/
+ cnat_session_entry_t *sdb;
+ sdb = cnat_session_db_lookup_entry(
+ &dest_info, db - cnat_main_db);
+ if(PREDICT_FALSE(sdb == NULL)) {
+ disposition = CNAT_V4_TCP_I2O_E_D;
+ counter = CNAT_V4_TCP_I2O_E_D_NO_SESSION;
+ goto in2out_e;
+ }
+ sdb->tcp_seq_num = clib_net_to_host_u32(tcp->seq_num);
+ sdb->ack_no = clib_net_to_host_u32(tcp->ack_num);
+ sdb->scale = scale;
+ sdb->window = window;
+
+#if DEBUG > 1
+ PLATFORM_DEBUG_PRINT("\nSDB seq no = %u, ack no = %u, window = %u"
+ "\nSDB scale = %u" ,
+ sdb->tcp_seq_num,
+ sdb->ack_no,
+ sdb->window,
+ sdb->scale);
+#endif
+ V4_TCP_UPDATE_SESSION_DB_FLAG(sdb, tcp);
+ /* Check timeout db if there is config for this */
+ (void) query_and_update_db_timeout((void *)sdb, SESSION_DB_TYPE);
+ sdb->entry_expires = cnat_current_time;
+ }
+
+ //PLATFORM_CNAT_SET_TX_VRF(ctx,db->out2in_key.k.vrf)
+
+ counter = CNAT_V4_TCP_I2O_E_T_PKT;
+ in2out_forwarding_count++;
+ }
+
+in2out_e:
+
+ em->counters[node_counter_base_index + counter] += 1;
+
+ return disposition;
+}
+
+#include <vnet/pipeline.h>
+
+static uword cnat_ipv4_tcp_inside_input_exc_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return dispatch_pipeline (vm, node, frame);
+}
+
+VLIB_REGISTER_NODE (cnat_ipv4_tcp_inside_input_exc_node) = {
+ .function = cnat_ipv4_tcp_inside_input_exc_node_fn,
+ .name = "vcgn-v4-tcp-i2o-e",
+ .vector_size = sizeof (u32),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(cnat_ipv4_tcp_inside_input_exc_error_strings),
+ .error_strings = cnat_ipv4_tcp_inside_input_exc_error_strings,
+
+ .n_next_nodes = CNAT_V4_TCP_I2O_E_NEXT,
+
+ /* edit / add dispositions here */
+ .next_nodes = {
+ [CNAT_V4_TCP_I2O_E_T] = "ip4-input",
+ [CNAT_V4_TCP_I2O_E_D] = "error-drop",
+ },
+};
+
+
+clib_error_t *cnat_ipv4_tcp_inside_input_exc_init (vlib_main_t *vm)
+{
+ cnat_ipv4_tcp_inside_input_exc_main_t * mp = &cnat_ipv4_tcp_inside_input_exc_main;
+
+ mp->vlib_main = vm;
+ mp->vnet_main = vnet_get_main();
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (cnat_ipv4_tcp_inside_input_exc_init);
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_outside_input.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_outside_input.c
new file mode 100644
index 00000000..bcf132b1
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_tcp_outside_input.c
@@ -0,0 +1,382 @@
+/*
+ *---------------------------------------------------------------------------
+ * cnat_ipv4_tcp_outside_input.c - cnat_v4_tcp_out2in node pipeline stage functions
+ *
+ *
+ * Copyright (c) 2008-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/error.h>
+#include <vnet/buffer.h>
+
+#include "cnat_db.h"
+#include "tcp_header_definitions.h"
+#include "cnat_config.h"
+#include "cnat_global.h"
+#include "cnat_ipv4_udp.h"
+#include "cnat_v4_functions.h"
+
+
+#define foreach_cnat_ipv4_tcp_outside_input_error \
+_(CNAT_V4_TCP_O2I_R_PKT, "v4 tcp o2i pkt received") \
+_(CNAT_V4_TCP_O2I_T_PKT, "v4 tcp o2i pkt natted & transmitted") \
+_(CNAT_V4_TCP_O2I_LOOKUP_FAILED, "v4 tcp o2i lookup failed") \
+_(CNAT_V4_TCP_O2I_TTL_GEN, "v4 tcp o2i generated TTL Expiry ICMP packet") \
+_(CNAT_V4_TCP_O2I_TTL_DROP, "v4 tcp o2i drop due to failure in creating TTL expiry ICMP msg") \
+_(CNAT_V4_TCP_O2I_PTB_GEN, "v4 tcp o2i PTB ICMP pkt generation") \
+_(CNAT_V4_UDP_O2I_PTB_DROP, "v4 tcp o2i drop due to failure in creating PTB ICMP pkt") \
+_(CNAT_V4_TCP_O2I_SESSION_DROP, "v4 tcp o2i drop due to failure in creating session db") \
+_(CNAT_V4_TCP_O2I_SEQ_MISMATCH_DROP, "v4 tcp o2i drop due to TCP sequence mismatch") \
+_(CNAT_V4_TCP_O2I_FILTER_DROP, "v4 tcp o2i drop due to endpoint filtering") \
+_(CNAT_V4_TCP_O2I_NON_SYN_RST_DROP, "v4 tcp o2i drop due no syn/rst flag") \
+_(CNAT_V4_TCP_O2I_FIRST_FRAG_DROP, "v4 tcp o2i first fragment drop") \
+_(CNAT_V4_TCP_O2I_SUB_FRAG_NO_DB_DROP, "v4 tcp o2i subsequest frag no DB drop")
+
+typedef enum {
+#define _(sym,str) sym,
+ foreach_cnat_ipv4_tcp_outside_input_error
+#undef _
+ CNAT_IPV4_TCP_OUTSIDE_INPUT_N_ERROR,
+} cnat_ipv4_tcp_outside_input_t;
+
+static char * cnat_ipv4_tcp_outside_input_error_strings[] = {
+#define _(sym,string) string,
+ foreach_cnat_ipv4_tcp_outside_input_error
+#undef _
+};
+
+typedef struct {
+ u32 cached_next_index;
+ /* $$$$ add data here */
+
+ /* convenience variables */
+ vlib_main_t * vlib_main;
+ vnet_main_t * vnet_main;
+} cnat_ipv4_tcp_outside_input_main_t;
+
+typedef enum {
+ //CNAT_V4_TCP_O2I_E,
+ CNAT_V4_TCP_O2I_T,
+ CNAT_V4_TCP_O2I_D,
+ CNAT_V4_TCP_O2I_NEXT,
+} cnat_ipv4_tcp_outside_input_next_t;
+
+cnat_ipv4_tcp_outside_input_main_t cnat_ipv4_tcp_outside_input_main;
+vlib_node_registration_t cnat_ipv4_tcp_outside_input_node;
+
+#define NSTAGES 6
+
+/*
+ * Use the generic buffer metadata + first line of packet data prefetch
+ * stage function from <api/pipeline.h>. This is usually a Good Idea.
+ */
+#define stage0 generic_stage0
+
+
+static inline void
+stage1(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ u64 a, b, c;
+ u32 bucket;
+ u8 *prefetch_target;
+
+
+ vlib_buffer_t * b0 = vlib_get_buffer (vm, buffer_index);
+ ipv4_header *ip = vlib_buffer_get_current (b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ tcp_hdr_type *tcp = (tcp_hdr_type *)((u8*)ip + ipv4_hdr_len);
+
+ u64 tmp = 0;
+ tmp = vnet_buffer(b0)->vcgn_uii.key.k.ipv4 =
+ clib_net_to_host_u32(ip->dest_addr);
+ vnet_buffer(b0)->vcgn_uii.key.k.port =
+ clib_net_to_host_u16 (tcp->dest_port);
+
+ tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.port) << 32;
+
+ PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX],
+ vnet_buffer(b0)->vcgn_uii.key.k.vrf,
+ CNAT_TCP)
+ tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.vrf) << 48;
+
+ CNAT_V4_GET_HASH(tmp, bucket, CNAT_MAIN_HASH_MASK)
+
+ prefetch_target = (u8 *)(&cnat_out2in_hash[bucket]);
+ vnet_buffer(b0)->vcgn_uii.bucket = bucket;
+
+ /* Prefetch the hash bucket */
+ CLIB_PREFETCH(prefetch_target, CLIB_CACHE_LINE_BYTES, LOAD);
+}
+
+static inline void
+stage2(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{ /* nothing */ }
+
+#define SPP_LOG2_CACHE_LINE_BYTES 6
+#define SPP_CACHE_LINE_BYTES (1 << SPP_LOG2_CACHE_LINE_BYTES)
+
+static inline void
+stage3(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index);
+ uword prefetch_target0, prefetch_target1;
+ u32 bucket = vnet_buffer(b0)->vcgn_uii.bucket;
+
+ /* read the hash bucket */
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket
+ = cnat_out2in_hash[bucket].next;
+
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+ /*
+ * Prefetch database keys. We save space by not cache-line
+ * aligning the DB entries. We don't want to waste LSU
+ * bandwidth prefetching stuff we won't need.
+ */
+ prefetch_target0 = (uword)(cnat_main_db + db_index);
+ CLIB_PREFETCH((void*)prefetch_target0, CLIB_CACHE_LINE_BYTES, STORE);
+ /* Just beyond DB key #2 */
+ prefetch_target1 = prefetch_target0 +
+ STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports);
+ /* If the targets are in different lines, do the second prefetch */
+ if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) !=
+ (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) {
+ CLIB_PREFETCH((void *)prefetch_target1, CLIB_CACHE_LINE_BYTES, STORE);
+ }
+ }
+}
+
+static inline void
+stage4(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ cnat_main_db_entry_t *db;
+ vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index);
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket;
+
+ /*
+ * Note: if the search already failed (empty bucket),
+ * the answer is already in the pipeline context structure
+ */
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+
+ /*
+ * Note: hash collisions suck. We can't easily prefetch around them.
+ * The first trip around the track will be fast. After that, maybe
+ * not so much...
+ */
+ do {
+ db = cnat_main_db + db_index;
+ if (PREDICT_TRUE(db->out2in_key.key64 ==
+ vnet_buffer(b0)->vcgn_uii.key.key64)) {
+ break;
+ }
+ db_index = db->out2in_hash.next;
+ } while (db_index != EMPTY);
+
+ /* Stick the answer back into the pipeline context structure */
+ vnet_buffer(b0)->vcgn_uii.bucket = db_index;
+ }
+}
+
+static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
+ u32 bi)
+{
+ vlib_buffer_t *b0 = vlib_get_buffer (vm, bi);
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket;
+ spp_ctx_t *ctx = (spp_ctx_t *) &vnet_buffer(b0)->vcgn_uii;
+ int disposition = CNAT_V4_TCP_O2I_T;
+ int counter = CNAT_V4_TCP_O2I_T_PKT;
+
+ ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ tcp_hdr_type *tcp = (tcp_hdr_type *)((u8*)ip + ipv4_hdr_len);
+ vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_tcp_outside_input_node.index);
+ u32 node_counter_base_index = n->error_heap_index;
+ vlib_error_main_t * em = &vm->error_main;
+ cnat_session_entry_t *session_db = NULL;
+ cnat_main_db_entry_t *db = NULL;
+ cnat_key_t dest_info;
+
+ INCREMENT_NODE_COUNTER(CNAT_V4_TCP_O2I_R_PKT);
+
+ if (PREDICT_FALSE(db_index == EMPTY)) {
+ nat44_dslite_common_stats[0].no_translation_entry_drops ++;
+ counter = CNAT_V4_TCP_O2I_LOOKUP_FAILED;
+ disposition = CNAT_V4_TCP_O2I_D;
+ } else {
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ if (PREDICT_FALSE(ip->ttl <= 1)) {
+ /* Try to generate ICMP error msg, as TTL is <= 1 */
+ if (icmpv4_generate_with_throttling(ctx,
+ ip, ctx->ru.rx.uidb_index)) {
+ /* Generated ICMP */
+ disposition = CNAT_V4_TCP_O2I_T_PKT; //CNAT_REWRITE_OUTPUT;
+ counter = CNAT_V4_TCP_O2I_TTL_GEN;
+ } else {
+ /* Could not generated ICMP - drop the packet */
+ disposition = CNAT_V4_TCP_O2I_D;
+ counter = CNAT_V4_TCP_O2I_TTL_DROP;
+ }
+ goto drop_pkt;
+ }
+ }
+ db = cnat_main_db + db_index;
+#if 0
+ window = db->diff_window;
+ stored_seq_no = db->proto_data.tcp_seq_chk.seq_no;
+ stored_ack_no = db->proto_data.tcp_seq_chk.ack_no;
+ vrf_map_p = cnat_map_by_vrf + db->vrfmap_index;
+ vrf_index = (db->in2out_key.k.vrf & CNAT_VRF_MASK);
+#endif
+ /* For Out2In packet, the dest info is src address and port */
+ dest_info.k.port = clib_net_to_host_u16(tcp->src_port);
+ dest_info.k.ipv4 = clib_net_to_host_u32(ip->src_addr);
+
+ if(PREDICT_TRUE(!PLATFORM_DBL_SUPPORT)) {
+
+ /* No DBL support, so just update the destn and proceed */
+ db->dst_ipv4 = dest_info.k.ipv4;
+ db->dst_port = dest_info.k.port;
+ goto update_pkt;
+ }
+
+
+ if(PREDICT_FALSE(db->dst_ipv4 != dest_info.k.ipv4 ||
+ db->dst_port != dest_info.k.port)) {
+
+ if(PREDICT_TRUE(db->nsessions == 0)) {
+ /* Should be a static entry
+ * Note this session as the first session and log
+ */
+ cnat_add_dest_n_log(db, &dest_info);
+ //goto packet_upd;
+ } else if(PREDICT_FALSE(db->nsessions == 1)) {
+ /* Destn is not same as in main db. Multiple session
+ * scenario
+ */
+ dest_info.k.vrf = db->in2out_key.k.vrf;
+ session_db = cnat_handle_1to2_session(db, &dest_info);
+ if(PREDICT_FALSE(session_db == NULL)) {
+ disposition = CNAT_V4_TCP_O2I_D;
+ counter = CNAT_V4_TCP_O2I_SESSION_DROP;
+ goto drop_pkt;
+ }
+ } else { /* There are already multiple destinations */
+ dest_info.k.vrf = db->in2out_key.k.vrf;
+ /* If session already exists,
+ * cnat_create_session_db_entry will return the existing db
+ * else create a new db
+ * If could not create, return NULL
+ */
+ session_db = cnat_create_session_db_entry(&dest_info, db, TRUE);
+ if(PREDICT_FALSE(session_db == NULL)) {
+ disposition = CNAT_V4_TCP_O2I_D;
+ counter = CNAT_V4_TCP_O2I_SESSION_DROP;
+ goto drop_pkt;
+ }
+ }
+ /* useful for ALG only */
+ #if 0
+ if(PREDICT_TRUE(session_db)) {
+ stored_seq_no = session_db->tcp_seq_num;
+ stored_ack_no = session_db->ack_no;
+ window = session_db->window;
+ }
+ #endif
+ }
+
+
+update_pkt:
+
+ counter = CNAT_V4_TCP_O2I_T_PKT;
+
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ /*
+ * Decrement TTL and update IPv4 checksum
+ */
+ ipv4_decr_ttl_n_calc_csum(ip);
+ }
+
+ /* update ip checksum, newchecksum = ~(~oldchecksum + ~old + new) */
+ cnat_v4_recalculate_tcp_checksum(ip, tcp,
+ &(ip->dest_addr),
+ &(tcp->dest_port),
+ db->in2out_key.k.ipv4,
+ db->in2out_key.k.port);
+
+ /* CNAT_PPTP_ALG_SUPPORT */
+ db->out2in_pkts++;
+
+ nat44_dslite_global_stats[0].out2in_forwarding_count++;;
+
+ V4_TCP_UPDATE_SESSION_FLAG(db, tcp);
+
+
+ if(PREDICT_FALSE(session_db != NULL)) {
+ V4_TCP_UPDATE_SESSION_DB_FLAG(session_db, tcp);
+ CNAT_DB_TIMEOUT_RST(session_db);
+ } else {
+ V4_TCP_UPDATE_SESSION_FLAG(db, tcp);
+ CNAT_DB_TIMEOUT_RST(db);
+ }
+
+ }
+
+drop_pkt:
+ em->counters[node_counter_base_index + counter] += 1;
+ return disposition;
+}
+
+#include <vnet/pipeline.h>
+
+static uword cnat_ipv4_tcp_outside_input_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return dispatch_pipeline (vm, node, frame);
+}
+
+
+VLIB_REGISTER_NODE (cnat_ipv4_tcp_outside_input_node) = {
+ .function = cnat_ipv4_tcp_outside_input_node_fn,
+ .name = "vcgn-v4-tcp-o2i",
+ .vector_size = sizeof (u32),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(cnat_ipv4_tcp_outside_input_error_strings),
+ .error_strings = cnat_ipv4_tcp_outside_input_error_strings,
+
+ .n_next_nodes = CNAT_V4_TCP_O2I_NEXT,
+
+ /* edit / add dispositions here */
+ .next_nodes = {
+ //[CNAT_V4_TCP_O2I_E] = "vcgn-v4-tcp-o2i-e",
+ [CNAT_V4_TCP_O2I_T] = "ip4-input",
+ [CNAT_V4_TCP_O2I_D] = "error-drop",
+ },
+};
+
+clib_error_t *cnat_ipv4_tcp_outside_input_init (vlib_main_t *vm)
+{
+ cnat_ipv4_tcp_outside_input_main_t * mp = &cnat_ipv4_tcp_outside_input_main;
+
+ mp->vlib_main = vm;
+ mp->vnet_main = vnet_get_main();
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (cnat_ipv4_tcp_outside_input_init);
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp.h
new file mode 100644
index 00000000..1ccf74a0
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp.h
@@ -0,0 +1,41 @@
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Filename: cnat_ipv4_udp.h
+ *
+ * Description: common functions for udp node
+ *
+ * Assumptions and Constraints:
+ *
+ * Copyright (c) 2000-2009 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-----------------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_IPV4_UDP_H__
+#define __CNAT_IPV4_UDP_H__
+
+#include "tcp_header_definitions.h"
+#include "cnat_db.h"
+#include "cnat_v4_functions.h"
+#include "cnat_global.h"
+#include "cnat_config.h"
+
+extern void swap_ip_src_udp_port(ipv4_header *ip,
+ udp_hdr_type_t *udp,
+ cnat_main_db_entry_t *db);
+extern void swap_ip_dst_udp_port(ipv4_header *ip,
+ udp_hdr_type_t *udp,
+ cnat_main_db_entry_t *db,
+ u16 vrf);
+#endif /* __CNAT_IPV4_UDP_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_inside_input.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_inside_input.c
new file mode 100644
index 00000000..657c5f1e
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_inside_input.c
@@ -0,0 +1,508 @@
+/*
+ *---------------------------------------------------------------------------
+ * cnat_ipv4_udp_inside_input.c - cnat_ipv4_udp_inside_input node functions
+ *
+ *
+ * Copyright (c) 2008-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/error.h>
+#include <vnet/buffer.h>
+
+#include "cnat_global.h"
+#include "cnat_db.h"
+#include "cnat_ipv4_udp.h"
+#include "cnat_pcp_server.h"
+
+
+#define foreach_cnat_ipv4_udp_inside_input_error \
+_(CNAT_V4_UDP_I2O_T_PKT, "v4 udp i2o transmit") \
+_(CNAT_V4_UDP_I2O_MISS_PKT, "v4 udp i2o db miss") \
+_(CNAT_V4_UDP_I2O_TTL_GEN, "v4 udp i2o TTL gen") \
+_(CNAT_V4_UDP_I2O_TTL_DROP, "v4 udp i2o TTL drop") \
+_(CNAT_V4_PCP_PKT, "v4 pcp pkt") \
+_(CNAT_V4_UDP_I2O_SESSION_DROP, "v4 udp i2o session drop")
+
+typedef enum {
+#define _(sym,str) sym,
+ foreach_cnat_ipv4_udp_inside_input_error
+#undef _
+ CNAT_IPV4_UDP_INSIDE_INPUT_N_ERROR,
+} cnat_ipv4_udp_inside_input_t;
+
+static char * cnat_ipv4_udp_inside_input_error_strings[] = {
+#define _(sym,string) string,
+ foreach_cnat_ipv4_udp_inside_input_error
+#undef _
+};
+
+typedef struct {
+ u32 cached_next_index;
+ /* $$$$ add data here */
+
+ /* convenience variables */
+ vlib_main_t * vlib_main;
+ vnet_main_t * vnet_main;
+} cnat_ipv4_udp_inside_input_main_t;
+
+typedef enum {
+ CNAT_V4_I2O_FIXME,
+ CNAT_V4_UDP_I2O_E,
+ CNAT_REWRITE_OUTPUT,
+ CNAT_V4_UDP_I2O_T = CNAT_REWRITE_OUTPUT,
+ CNAT_N_NEXT,
+} cnat_ipv4_udp_inside_input_next_t;
+
+#define CNAT_V4_UDP_I2O_D CNAT_V4_I2O_FIXME
+#define CNAT_V4_PCP_T CNAT_V4_I2O_FIXME
+
+cnat_ipv4_udp_inside_input_main_t cnat_ipv4_udp_inside_input_main;
+vlib_node_registration_t cnat_ipv4_udp_inside_input_node;
+
+#define NSTAGES 6
+
+/*
+ * Use the generic buffer metadata + first line of packet data prefetch
+ * stage function from <api/pipeline.h>. This is usually a Good Idea.
+ */
+#define stage0 generic_stage0
+
+#ifndef TOBE_PORTED
+static inline u32
+is_pcp_pkt(u32 addr, u16 port)
+{
+ return CNAT_NO_CONFIG;
+}
+#else
+static inline u32
+is_pcp_pkt(spp_ctx_t *ctx, u32 addr, u16 port)
+{
+ cnat_vrfmap_t *my_vrfmap = NULL;
+ u16 my_vrfmap_index;
+
+ my_vrfmap_index = vrf_map_array[ctx->ru.rx.uidb_index];
+
+ if (PREDICT_TRUE(my_vrfmap_index != VRF_MAP_ENTRY_EMPTY)) {
+
+ my_vrfmap = cnat_map_by_vrf + my_vrfmap_index;
+
+ if (PREDICT_FALSE( port == my_vrfmap->pcp_server_port)) {
+ if(PREDICT_TRUE(addr == my_vrfmap->pcp_server_addr)) {
+ return CNAT_SUCCESS;
+ }
+ }
+ }
+
+ return CNAT_NO_CONFIG;
+}
+#endif
+
+inline void swap_ip_src_udp_port(ipv4_header *ip,
+ udp_hdr_type_t *udp,
+ cnat_main_db_entry_t *db)
+{
+ /*
+ * declare varibale
+ */
+ CNAT_UPDATE_L3_L4_CHECKSUM_DECLARE
+ /*
+ * calculate checksum
+ */
+ CNAT_UPDATE_L3_L4_CHECKSUM(((u16)(db->in2out_key.k.ipv4)),
+ ((u16)(db->in2out_key.k.ipv4 >> 16)),
+ (db->in2out_key.k.port),
+ (clib_net_to_host_u16(ip->checksum)),
+ (clib_net_to_host_u16(udp->udp_checksum)),
+ ((u16)(db->out2in_key.k.ipv4)),
+ ((u16)(db->out2in_key.k.ipv4 >> 16)),
+ (db->out2in_key.k.port))
+
+/* #define UDP_PACKET_DEBUG 1 */
+
+// Temporary debugs which will be suppressed later
+#ifdef UDP_PACKET_DEBUG
+ if (PREDICT_FALSE(udp_inside_packet_dump_enable)) {
+ printf("\nIn2Out UDP packet before translation");
+ print_udp_pkt(ip);
+ }
+#endif
+
+ //set ip header
+ ip->src_addr =
+ clib_host_to_net_u32(db->out2in_key.k.ipv4);
+ ip->checksum =
+ clib_host_to_net_u16(new_l3_c);
+
+ u16 frag_offset =
+ clib_net_to_host_u16(ip->frag_flags_offset);
+
+ if(PREDICT_FALSE(frag_offset & IP_FRAG_OFFSET_MASK)) {
+ return; /* No need to update UDP fields */
+ }
+ //set udp header
+ udp->src_port =
+ clib_host_to_net_u16(db->out2in_key.k.port);
+
+ /*
+ * No easy way to avoid this if check except by using
+ * complex logic - may not be worth it.
+ */
+ if (PREDICT_TRUE(udp->udp_checksum)) {
+ udp->udp_checksum =
+ clib_host_to_net_u16(new_l4_c);
+ }
+
+// Temporary debugs which will be suppressed later
+#ifdef UDP_PACKET_DEBUG
+ if (PREDICT_FALSE(udp_inside_checksum_disable)) {
+ printf("\nIn2Out UDP checksum 0x%x disabled by force", new_l4_c);
+ udp->udp_checksum = 0;
+ }
+ if (PREDICT_FALSE(udp_inside_packet_dump_enable)) {
+ printf("\nIn2Out UDP packet after translation");
+ print_udp_pkt(ip);
+ }
+#endif
+}
+
+static inline void
+stage1(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ u64 a, b, c;
+ u32 bucket;
+ u8 *prefetch_target;
+
+ vlib_buffer_t * b0 = vlib_get_buffer (vm, buffer_index);
+ ipv4_header *ip = vlib_buffer_get_current (b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ udp_hdr_type_t *udp = (udp_hdr_type_t *)((u8*)ip + ipv4_hdr_len);
+
+ u64 tmp = 0;
+ tmp = vnet_buffer(b0)->vcgn_uii.key.k.ipv4 =
+ clib_net_to_host_u32(ip->src_addr);
+ vnet_buffer(b0)->vcgn_uii.key.k.port =
+ clib_net_to_host_u16 (udp->src_port);
+
+ tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.port) << 32;
+
+ PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX],
+ vnet_buffer(b0)->vcgn_uii.key.k.vrf,
+ CNAT_UDP)
+ tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.vrf) << 48;
+
+ CNAT_V4_GET_HASH(tmp, bucket, CNAT_MAIN_HASH_MASK)
+
+ prefetch_target = (u8 *)(&cnat_in2out_hash[bucket]);
+ vnet_buffer(b0)->vcgn_uii.bucket = bucket;
+
+ /* Prefetch the hash bucket */
+ CLIB_PREFETCH(prefetch_target, CLIB_CACHE_LINE_BYTES, LOAD);
+}
+
+static inline void
+stage2(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{ /* nothing */ }
+
+#define SPP_LOG2_CACHE_LINE_BYTES 6
+#define SPP_CACHE_LINE_BYTES (1 << SPP_LOG2_CACHE_LINE_BYTES)
+
+static inline void
+stage3(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index);
+ uword prefetch_target0, prefetch_target1;
+ u32 bucket = vnet_buffer(b0)->vcgn_uii.bucket;
+
+ /* read the hash bucket */
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket
+ = cnat_in2out_hash[bucket].next;
+
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+ /*
+ * Prefetch database keys. We save space by not cache-line
+ * aligning the DB entries. We don't want to waste LSU
+ * bandwidth prefetching stuff we won't need.
+ */
+ prefetch_target0 = (uword)(cnat_main_db + db_index);
+ CLIB_PREFETCH((void*)prefetch_target0, CLIB_CACHE_LINE_BYTES, LOAD);
+ /* Just beyond DB key #2 */
+ prefetch_target1 = prefetch_target0 +
+ STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports);
+ /* If the targets are in different lines, do the second prefetch */
+ if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) !=
+ (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) {
+ CLIB_PREFETCH((void *)prefetch_target1, CLIB_CACHE_LINE_BYTES, LOAD);
+ }
+ }
+}
+
+static inline void
+stage4(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ cnat_main_db_entry_t *db;
+ vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index);
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket;
+
+ /*
+ * Note: if the search already failed (empty bucket),
+ * the answer is already in the pipeline context structure
+ */
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+
+ /*
+ * Note: hash collisions suck. We can't easily prefetch around them.
+ * The first trip around the track will be fast. After that, maybe
+ * not so much...
+ */
+ do {
+ db = cnat_main_db + db_index;
+ if (PREDICT_TRUE(db->in2out_key.key64 ==
+ vnet_buffer(b0)->vcgn_uii.key.key64)) {
+ break;
+ }
+ db_index = db->in2out_hash.next;
+ } while (db_index != EMPTY);
+
+ /* Stick the answer back into the pipeline context structure */
+ vnet_buffer(b0)->vcgn_uii.bucket = db_index;
+ }
+}
+
+static u64 pkt_num = 0;
+static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
+ u32 bi)
+{
+ vlib_buffer_t *b0 = vlib_get_buffer (vm, bi);
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket;
+ spp_ctx_t *ctx = (spp_ctx_t *) &vnet_buffer(b0)->vcgn_uii;
+ int disposition = CNAT_V4_UDP_I2O_T;
+ int counter = CNAT_V4_UDP_I2O_T_PKT;
+ ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ udp_hdr_type_t *udp = (udp_hdr_type_t *)((u8*)ip + ipv4_hdr_len);
+ vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_udp_inside_input_node.index);
+ u32 node_counter_base_index = n->error_heap_index;
+ vlib_error_main_t * em = &vm->error_main;
+ cnat_session_entry_t *session_db = NULL;
+ cnat_key_t dest_info;
+
+ pkt_num++;
+
+ if(PREDICT_FALSE(is_pcp_pkt(ip->dest_addr, udp->dest_port) ==
+ CNAT_SUCCESS))
+ {
+ PCP_INCR(input);
+ disposition = CNAT_V4_PCP_T;
+ counter = CNAT_V4_PCP_PKT;
+
+ goto pcp_pkt;
+ }
+
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ if (PREDICT_FALSE(ip->ttl <= 1)) {
+ /* Try to generate ICMP error msg, as TTL is <= 1 */
+
+ if (icmpv4_generate_with_throttling
+ (ctx, ip, ctx->ru.rx.uidb_index)) {
+ /* Generated ICMP */
+ disposition = CNAT_REWRITE_OUTPUT;
+ counter = CNAT_V4_UDP_I2O_TTL_GEN;
+ } else {
+ /* Could not generated ICMP - drop the packet */
+ disposition = CNAT_V4_UDP_I2O_D;
+ counter = CNAT_V4_UDP_I2O_TTL_DROP;
+ }
+ goto drop_pkt;
+ }
+ }
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+ cnat_main_db_entry_t *db = cnat_main_db + db_index;
+
+ dest_info.k.ipv4 = clib_net_to_host_u32(ip->dest_addr);
+
+ /* MUST revisit: it seems farg is set to 1 for few packets & because of
+ * this the port is not updated & it becomes 0. Commenting teporarily
+ * this fargment check & setting dst port with udp dst port value */
+ dest_info.k.port = clib_net_to_host_u16(udp->dest_port);
+ #if 0 // DONOT REMOVE THIS if 0
+ if(PREDICT_FALSE(ctx->ru.rx.frag)) {
+#ifdef TOBE_PORTED
+ /* Must have routed through cnat_v4_frag_in2out node */
+ u16 *feature_data_ports = (u16 *)&ctx->feature_data[4];
+ dest_info.k.port = *feature_data_ports;
+#endif
+ } else {
+ dest_info.k.port = clib_net_to_host_u16(udp->dest_port);
+ }
+ #endif
+
+
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ /*
+ * Decrement TTL and update IPv4 checksum
+ */
+ ipv4_decr_ttl_n_calc_csum(ip);
+ }
+
+ if(PREDICT_TRUE(!PLATFORM_DBL_SUPPORT)) {
+
+ /* No DBL support, so just update the destn and proceed */
+ db->dst_ipv4 = dest_info.k.ipv4;
+ db->dst_port = dest_info.k.port;
+ CNAT_DB_TIMEOUT_RST(db);
+ goto update_pkt;
+ }
+
+ if(PREDICT_TRUE((db->dst_ipv4 == dest_info.k.ipv4) &&
+ (db->dst_port == dest_info.k.port))) {
+
+ CNAT_DB_TIMEOUT_RST(db);
+ goto update_pkt;
+ } else {
+ if (PREDICT_FALSE(db->nsessions == 0)) {
+ /* Should be a static entry
+ * Note this session as the first session and log
+ */
+ cnat_add_dest_n_log(db, &dest_info);
+ /*
+ * update db counter, timer
+ */
+
+ CNAT_DB_TIMEOUT_RST(db);
+
+ } else if(PREDICT_TRUE(db->nsessions == 1)) {
+ /* Destn is not same as in main db. Multiple session
+ * scenario
+ */
+ //printf(">>> [pkt# %lu] src_ip: 0x%x, db ip: 0x%x, db port: %u; dest ip: 0x%x, dest port: %u\n",
+ // pkt_num, ntohl(ip->src_addr), db->dst_ipv4, db->dst_port, dest_info.k.ipv4, dest_info.k.port);
+
+ dest_info.k.vrf = db->in2out_key.k.vrf;
+ session_db = cnat_handle_1to2_session(db, &dest_info);
+
+ if(PREDICT_TRUE(session_db != NULL)) {
+ /* session exists */
+ CNAT_DB_TIMEOUT_RST(session_db);
+ } else {
+ /* could not create session db - drop packet */
+ disposition = CNAT_V4_UDP_I2O_D;
+ counter = CNAT_V4_UDP_I2O_SESSION_DROP;
+ goto drop_pkt;
+ }
+
+ } else {
+ /* More than 2 sessions exists */
+
+ dest_info.k.vrf = db->in2out_key.k.vrf;
+
+ /* If session already exists,
+ * cnat_create_session_db_entry will return the existing db
+ * else create a new db
+ * If could not create, return NULL
+ */
+ session_db = cnat_create_session_db_entry(&dest_info,
+ db, TRUE);
+
+ if(PREDICT_FALSE(session_db != NULL)) {
+ /* session exists */
+ CNAT_DB_TIMEOUT_RST(session_db);
+ } else {
+ /* could not create session db - drop packet */
+ disposition = CNAT_V4_UDP_I2O_D;
+ counter = CNAT_V4_UDP_I2O_SESSION_DROP;
+ goto drop_pkt;
+ }
+ }
+ }
+
+update_pkt:
+ /*
+ * 1. update src ipv4 addr and src udp port
+ * 2. update ipv4 checksum and udp checksum
+ */
+ swap_ip_src_udp_port(ip, udp, db);
+ /*
+ * update db counter, timer
+ */
+
+ db->in2out_pkts++;
+
+ /*
+ * need to set outside vrf
+ * from db->out2in_key.k.vrf
+ */
+
+ /* Temporarily keeping this commented */
+ //PLATFORM_CNAT_SET_TX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_TX],
+ // db->out2in_key.k.vrf)
+
+ in2out_forwarding_count++;
+
+ } else {
+ disposition = CNAT_V4_UDP_I2O_E;
+ counter = CNAT_V4_UDP_I2O_MISS_PKT;
+ }
+
+drop_pkt:
+pcp_pkt:
+
+ em->counters[node_counter_base_index + counter] += 1;
+
+ return disposition;
+}
+
+#include <vnet/pipeline.h>
+
+static uword cnat_ipv4_udp_inside_input_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return dispatch_pipeline (vm, node, frame);
+}
+
+
+VLIB_REGISTER_NODE (cnat_ipv4_udp_inside_input_node) = {
+ .function = cnat_ipv4_udp_inside_input_node_fn,
+ .name = "vcgn-v4-udp-i2o",
+ .vector_size = sizeof (u32),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(cnat_ipv4_udp_inside_input_error_strings),
+ .error_strings = cnat_ipv4_udp_inside_input_error_strings,
+
+ .n_next_nodes = CNAT_N_NEXT,
+
+ /* edit / add dispositions here */
+ .next_nodes = {
+ [CNAT_V4_I2O_FIXME] = "error-drop",
+ // [CNAT_V4_UDP_I2O_T] = "ip4-input",
+ [CNAT_V4_UDP_I2O_E] = "vcgn-v4-udp-i2o-e",
+ [CNAT_REWRITE_OUTPUT] = "ip4-input",
+ },
+};
+
+clib_error_t *cnat_ipv4_udp_inside_input_init (vlib_main_t *vm)
+{
+ cnat_ipv4_udp_inside_input_main_t * mp = &cnat_ipv4_udp_inside_input_main;
+
+ mp->vlib_main = vm;
+ mp->vnet_main = vnet_get_main();
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (cnat_ipv4_udp_inside_input_init);
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_inside_input_exceptions.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_inside_input_exceptions.c
new file mode 100644
index 00000000..f078c8d4
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_inside_input_exceptions.c
@@ -0,0 +1,283 @@
+/*
+ *---------------------------------------------------------------------------
+ * cnat_ipv4_udp_inside_input_exception_stages.c - cnat_ipv4_udp_inside_input_exception node pipeline stage functions
+ *
+ *
+ * Copyright (c) 2008-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/error.h>
+#include <vnet/buffer.h>
+
+#include "cnat_global.h"
+#include "cnat_db.h"
+#include "cnat_ipv4_udp.h"
+
+/*
+ * Dump these counters via the "show error" CLI command
+ */
+
+#define foreach_cnat_ipv4_udp_inside_input_exc_error \
+_(CNAT_V4_UDP_I2O_T_PKT, "v4 udp i2o transmit") \
+_(CNAT_V4_UDP_I2O_D_PKT, "v4 udp i2o drop") \
+_(CNAT_V4_ICMP_G_I2O_T_PKT, "v4 udp i2o icmp msg gen") \
+_(CNAT_V4_UDP_I2O_DC_PKT, "v4 udp i2o (no config) drop") \
+_(CNAT_V4_UDP_I2O_DR_PKT, "v4 udp i2o (not in run state) drop") \
+_(CNAT_V4_UDP_I2O_DD_PKT, "v4 udp i2o (no direct port) drop") \
+_(CNAT_V4_UDP_I2O_DA_PKT, "v4 udp i2o (no any port) drop") \
+_(CNAT_V4_UDP_I2O_DO_PKT, "v4 udp i2o (out of port limit) drop") \
+_(CNAT_V4_UDP_I2O_DI_PKT, "v4 udp i2o (invalid packet) drop") \
+_(CNAT_V4_UDP_I2O_DS_PKT, "v4 udp i2o (no sessoon db) drop")
+
+typedef enum {
+#define _(sym,str) sym,
+ foreach_cnat_ipv4_udp_inside_input_exc_error
+#undef _
+ CNAT_IPV4_UDP_INSIDE_INPUT_EXCEPTIONS_N_ERROR,
+} cnat_ipv4_udp_inside_input_exc_error_t;
+
+
+static char * cnat_ipv4_udp_inside_input_exc_error_strings[] = {
+#define _(sym,string) string,
+ foreach_cnat_ipv4_udp_inside_input_exc_error
+#undef _
+};
+
+typedef struct {
+ u32 cached_next_index;
+ /* $$$$ add data here */
+
+ /* convenience variables */
+ vlib_main_t * vlib_main;
+ vnet_main_t * vnet_main;
+} cnat_ipv4_udp_inside_input_exc_main_t;
+
+typedef enum {
+ CNAT_V4_UDP_I2O_T,
+ CNAT_V4_UDP_I2O_D,
+ CNAT_V4_ICMP_G_I2O_T = CNAT_V4_UDP_I2O_D, /* TOBE_PORTED */
+ CNAT_V4_UDP_INSIDE_INPUT_EXC_N_NEXT,
+} cnat_ipv4_udp_inside_input_exc_next_t;
+
+cnat_ipv4_udp_inside_input_exc_main_t cnat_ipv4_udp_inside_input_exc_main;
+vlib_node_registration_t cnat_ipv4_udp_inside_input_exc_node;
+
+#define NSTAGES 2
+
+/*
+ * Use the generic buffer metadata + first line of packet data prefetch
+ * stage function from <api/pipeline.h>. This is usually a Good Idea.
+ */
+#define stage0 generic_stage0
+
+static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
+ u32 bi)
+{
+ vlib_buffer_t *b0 = vlib_get_buffer (vm, bi);
+ vlib_node_t *n =
+ vlib_get_node (vm, cnat_ipv4_udp_inside_input_exc_node.index);
+ u32 node_counter_base_index = n->error_heap_index;
+ vlib_error_main_t * em = &vm->error_main;
+
+ cnat_gen_icmp_info info;
+ cnat_db_key_bucket_t ki;
+ spp_ctx_t *ctx __attribute__((unused))
+ = (spp_ctx_t *) &vnet_buffer(b0)->vcgn_uii;
+ cnat_main_db_entry_t *db = NULL;
+ ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ udp_hdr_type_t *udp = (udp_hdr_type_t *)((u8*)ip + ipv4_hdr_len);
+ int disposition = CNAT_V4_UDP_I2O_T;
+ int counter = CNAT_V4_UDP_I2O_T_PKT;
+
+ cnat_key_t dest_info;
+
+ PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX],
+ vnet_buffer(b0)->vcgn_uii.key.k.vrf,
+ CNAT_UDP)
+
+ vnet_buffer(b0)->vcgn_uii.key.k.ipv4 = clib_net_to_host_u32(ip->src_addr);
+
+ PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX],
+ ki.k.k.vrf, CNAT_UDP)
+
+ ki.k.k.ipv4 = clib_net_to_host_u32(ip->src_addr);
+
+
+ /* MUST REVISIT: commentting frag check. Unconditional destination port
+ * update. DONOT remove this #if 0 */
+ ki.k.k.port =
+ clib_net_to_host_u16(udp->src_port);
+ dest_info.k.port =
+ clib_net_to_host_u16(udp->dest_port);
+#if 0
+ if(PREDICT_FALSE(ctx->ru.rx.frag)) {
+#ifdef TOBE_PORTED
+ /* Must have routed through cnat_v4_frag_in2out node */
+ u16 *feature_data_ports = (u16 *)&ctx->feature_data[2];
+ ki.k.k.port = *feature_data_ports;
+ feature_data_ports++;
+ dest_info.k.port = *feature_data_ports;
+#endif
+ } else {
+ ki.k.k.port =
+ clib_net_to_host_u16(udp->src_port);
+ dest_info.k.port =
+ clib_net_to_host_u16(udp->dest_port);
+ }
+#endif /* if 0 */
+
+ dest_info.k.ipv4 = clib_net_to_host_u32(ip->dest_addr);
+ PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX],
+ dest_info.k.vrf, CNAT_UDP)
+
+ if (PREDICT_TRUE(ki.k.k.port)) {
+ if (ki.k.k.port & 0x1) {
+ db = cnat_get_main_db_entry_v2(&ki, PORT_S_ODD, PORT_TYPE_DYNAMIC,
+ &info, &dest_info);
+ } else {
+ db = cnat_get_main_db_entry_v2(&ki, PORT_S_EVEN, PORT_TYPE_DYNAMIC,
+ &info, &dest_info);
+ }
+ } else {
+ /*
+ * No UDP port value of 0 - drop it
+ */
+ db = NULL;
+ info.error = CNAT_ERR_BAD_TCP_UDP_PORT;
+ }
+
+ if (PREDICT_TRUE((u64)db)) {
+
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ /*
+ * Decrement TTL and update IPv4 checksum
+ */
+ ipv4_decr_ttl_n_calc_csum(ip);
+ }
+
+ /*
+ * step 6 do nat before fwd pkt
+ */
+ swap_ip_src_udp_port(ip, udp, db);
+ /*
+ * update db for this pkt
+ */
+ CNAT_DB_UPDATE_IN2OUT_TIMER
+
+ /* Check timeout db if there is config for this */
+ (void) query_and_update_db_timeout((void *)db, MAIN_DB_TYPE);
+
+/* Temporarily keeping it commented */
+ //PLATFORM_CNAT_SET_TX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_TX],
+ // db->out2in_key.k.vrf)
+ in2out_forwarding_count++;
+
+ } else {
+ switch (info.error) {
+ case (CNAT_NO_VRF_RUN):
+ em->counters[node_counter_base_index + CNAT_V4_UDP_I2O_DR_PKT] += 1;
+ break;
+ case (CNAT_OUT_LIMIT):
+ em->counters[node_counter_base_index + CNAT_V4_UDP_I2O_DO_PKT] += 1;
+ break;
+ case (CNAT_NO_PORT_ANY):
+ case (CNAT_NO_POOL_ANY):
+ case (CNAT_BAD_INUSE_ANY):
+ case (CNAT_NOT_FOUND_ANY):
+ em->counters[node_counter_base_index + CNAT_V4_UDP_I2O_DA_PKT] += 1;
+ break;
+ case (CNAT_INV_PORT_DIRECT):
+ case (CNAT_DEL_PORT_DIRECT):
+ case (CNAT_BAD_INUSE_DIRECT):
+ case (CNAT_NOT_FOUND_DIRECT):
+ em->counters[node_counter_base_index + CNAT_V4_UDP_I2O_DD_PKT] += 1;
+ break;
+ case (CNAT_ERR_BAD_TCP_UDP_PORT):
+ em->counters[node_counter_base_index + CNAT_V4_UDP_I2O_DI_PKT] += 1;
+ break;
+ case (CNAT_ERR_NO_SESSION_DB):
+ em->counters[node_counter_base_index + CNAT_V4_UDP_I2O_DS_PKT] += 1;
+ break;
+ default:
+ em->counters[node_counter_base_index + CNAT_V4_UDP_I2O_DC_PKT] += 1;
+ break;
+ }
+ /*
+ * send to icmp msg generate node
+ */
+ if (info.gen_icmp_msg == CNAT_ICMP_MSG) {
+#ifdef TOBE_PORTED
+ u32 *fd = (u32*)ctx->feature_data;
+ fd[0] = info.svi_addr;
+ fd[1] = CNAT_ICMP_DEST_UNREACHABLE;
+#endif
+ disposition = CNAT_V4_ICMP_G_I2O_T;
+ counter = CNAT_V4_ICMP_G_I2O_T_PKT;
+ } else {
+ disposition = CNAT_V4_UDP_I2O_D;
+ counter = CNAT_V4_UDP_I2O_D_PKT;
+ }
+ DEBUG_I2O_DROP(CNAT_DEBUG_DROP_UDP)
+ }
+
+ em->counters[node_counter_base_index + counter] += 1;
+
+ return disposition;
+}
+
+
+#include <vnet/pipeline.h>
+
+static uword cnat_ipv4_udp_inside_input_exc_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return dispatch_pipeline (vm, node, frame);
+}
+
+VLIB_REGISTER_NODE (cnat_ipv4_udp_inside_input_exc_node) = {
+ .function = cnat_ipv4_udp_inside_input_exc_node_fn,
+ .name = "vcgn-v4-udp-i2o-e",
+ .vector_size = sizeof (u32),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(cnat_ipv4_udp_inside_input_exc_error_strings),
+ .error_strings = cnat_ipv4_udp_inside_input_exc_error_strings,
+
+ .n_next_nodes = CNAT_V4_UDP_INSIDE_INPUT_EXC_N_NEXT,
+
+ /* edit / add dispositions here */
+ .next_nodes = {
+ [CNAT_V4_UDP_I2O_T] = "ip4-input",
+ [CNAT_V4_UDP_I2O_D] = "error-drop",
+ },
+};
+
+
+clib_error_t *cnat_ipv4_udp_inside_input_exc_init (vlib_main_t *vm)
+{
+ cnat_ipv4_udp_inside_input_exc_main_t * mp = &cnat_ipv4_udp_inside_input_exc_main;
+
+ mp->vlib_main = vm;
+ mp->vnet_main = vnet_get_main();
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (cnat_ipv4_udp_inside_input_exc_init);
+
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_outside_input.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_outside_input.c
new file mode 100644
index 00000000..5a24a111
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_ipv4_udp_outside_input.c
@@ -0,0 +1,605 @@
+
+/*
+ *---------------------------------------------------------------------------
+ * cnat_ipv4_udp_outside_input_stages.c - cnat_ipv4_udp_outside_input node pipeline stage functions
+ *
+ *
+ * Copyright (c) 2008-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/error.h>
+#include <vnet/buffer.h>
+
+#include "cnat_ipv4_udp.h"
+#include "dslite_db.h"
+#include "cnat_db.h"
+#include "cnat_v4_functions.h"
+
+//#include <dslite_v6_functions.h>
+//#include <pool.h>
+//#include "cnat_va_db.h"
+
+#define foreach_cnat_ipv4_udp_outside_input_error \
+_(CNAT_V4_UDP_O2I_T_PKT, "v4 udp o2i transmit") \
+_(CNAT_V4_DSLITE_ENCAP_CTR, "to dslite encap") \
+_(CNAT_V4_UDP_O2I_MISS_PKT, "v4 udp o2i db miss drop") \
+_(CNAT_V4_UDP_O2I_TTL_GEN, "v4 udp o2i TTL gen") \
+_(CNAT_V4_UDP_O2I_TTL_DROP, "v4 udp o2i TTL drop") \
+_(CNAT_V4_UDP_O2I_PTB_GEN, "v4 ptb gen") \
+_(CNAT_V4_UDP_O2I_PTB_DROP, "v4 ptb throttle drop") \
+_(CNAT_V4_UDP_O2I_SESSION_DROP, "v4 udp o2i session drop") \
+_(CNAT_V4_UDP_O2I_FILTER_DROP, "v4 udp o2i drop: end point filtering") \
+_(CNAT_V4_UDP_O2I_SUB_FRAG_NO_DB_DROP, "v4 udp o2i subsequent frag no DB drop") \
+_(CNAT_V4_UDP_O2I_1ST_FRAG_FILTER_DROP, "v4 udp i2o 1st frag filter drop")
+
+typedef enum {
+#define _(sym,str) sym,
+ foreach_cnat_ipv4_udp_outside_input_error
+#undef _
+ CNAT_IPV4_UDP_OUTSIDE_INPUT_N_ERROR,
+} cnat_ipv4_udp_outside_input_t;
+
+static char * cnat_ipv4_udp_outside_input_error_strings[] = {
+#define _(sym,string) string,
+ foreach_cnat_ipv4_udp_outside_input_error
+#undef _
+};
+
+typedef struct {
+ u32 cached_next_index;
+ /* $$$$ add data here */
+
+ /* convenience variables */
+ vlib_main_t * vlib_main;
+ vnet_main_t * vnet_main;
+} cnat_ipv4_udp_outside_input_main_t;
+
+typedef enum {
+ //CNAT_V4_O2I_FIXME,
+ CNAT_V4_UDP_O2I_E,
+ CNAT_V4_UDP_O2I_T,
+ CNAT_V4_UDP_O2I_NEXT,
+} cnat_ipv4_udp_outside_input_next_t;
+
+//#define CNAT_V4_DSLITE_ENCAP CNAT_V4_O2I_FIXME
+//#define CNAT_V4_UDP_O2I_E CNAT_V4_O2I_FIXME
+
+cnat_ipv4_udp_outside_input_main_t cnat_ipv4_udp_outside_input_main;
+vlib_node_registration_t cnat_ipv4_udp_outside_input_node;
+
+#define NSTAGES 6
+
+/*
+ * Use the generic buffer metadata + first line of packet data prefetch
+ * stage function from <api/pipeline.h>. This is usually a Good Idea.
+ */
+#define stage0 generic_stage0
+
+
+#if 0
+typedef struct cnat_ipv4_udp_outside_input_pipeline_data_ {
+ //spp_node_main_vector_t *nmv;
+ dslite_common_pipeline_data_t common_data;
+ /* Add additional pipeline stage data here... */
+ u32 bucket;
+#ifdef DSLITE_DEF
+ u32 user_bucket;
+ dslite_v4_to_v6_udp_counter_t *udp_counter;
+ dslite_icmp_gen_counter_t *icmp_gen_counter;
+
+#endif
+ cnat_key_t ki;
+ udp_hdr_type_t *udp;
+ u8 frag_pkt;
+} cnat_ipv4_udp_outside_input_pipeline_data_t;
+
+#endif
+
+#define CNAT_UDP_OUTSIDE_UPDATE_FLAG_TIMER(db,dslite_nat44_inst_id) \
+ if (PREDICT_FALSE(!(db->flags & CNAT_DB_FLAG_UDP_ACTIVE))) { \
+ db->flags |= CNAT_DB_FLAG_UDP_ACTIVE; \
+ CNAT_DB_TIMEOUT_RST(db); \
+ } else if (PREDICT_FALSE(db->flags & CNAT_DB_DSLITE_FLAG)) { \
+ if (PREDICT_TRUE(dslite_table_db_ptr[dslite_nat44_inst_id].mapping_refresh_both_direction)) { \
+ CNAT_DB_TIMEOUT_RST(db); \
+ } \
+ } else if (PREDICT_TRUE(mapping_refresh_both_direction)) { \
+ CNAT_DB_TIMEOUT_RST(db); \
+ } \
+
+#if 0
+static cnat_ipv4_udp_outside_input_pipeline_data_t pctx_data[SPP_MAXDISPATCH];
+#define EXTRA_PIPELINE_ARGS_PROTO , cnat_ipv4_udp_outside_input_pipeline_data_t *pctx
+#define EXTRA_PIPELINE_ARGS , pctx
+
+#endif
+
+/*inline u32
+is_static_dest_nat_enabled(u16 vrf)
+{
+ if(static_dest_vrf_map_array[vrf] == 1) {
+ return CNAT_SUCCESS;
+ }
+ return CNAT_NO_CONFIG;
+}*/
+
+static inline void __attribute__((unused))
+swap_ip_dst(ipv4_header *ip, cnat_main_db_entry_t *db, u16 vrf)
+{
+
+ CNAT_UPDATE_L3_CHECKSUM_DECLARE
+ /*
+ * calculate checksum
+ */
+ CNAT_UPDATE_L3_CHECKSUM(((u16)(db->out2in_key.k.ipv4)),
+ ((u16)(db->out2in_key.k.ipv4 >> 16)),
+ (clib_host_to_net_u16(ip->checksum)),
+ ((u16)(db->in2out_key.k.ipv4)),
+ ((u16)(db->in2out_key.k.ipv4 >> 16)))
+ //set ip header
+ ip->dest_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+ ip->checksum =
+ clib_host_to_net_u16(new_l3_c);
+
+#if 0
+
+ if(is_static_dest_nat_enabled(vrf) == CNAT_SUCCESS) {
+ direction = 1;
+ if(cnat_static_dest_db_get_translation(ip->src_addr, &postmap_ip, vrf, direction) == CNAT_SUCCESS) {
+ old_ip = spp_net_to_host_byte_order_32(&(ip->src_addr));
+ old_postmap_ip = spp_net_to_host_byte_order_32(&postmap_ip);
+
+ CNAT_UPDATE_L3_CHECKSUM(((u16)(old_ip & 0xFFFF)),
+ ((u16)(old_ip >> 16)),
+ (spp_net_to_host_byte_order_16(&(ip->checksum))),
+ ((u16)(old_postmap_ip & 0xFFFF)),
+ ((u16)(old_postmap_ip >> 16)))
+ ip->checksum =
+ clib_host_to_net_u16(new_l3_c);
+ ip->src_addr = postmap_ip;
+ }
+ }
+#endif
+}
+
+inline void swap_ip_dst_udp_port(ipv4_header *ip,
+ udp_hdr_type_t *udp,
+ cnat_main_db_entry_t *db, u16 vrf)
+{
+
+#define UDP_PACKET_DEBUG 1
+
+// Temporary debugs which will be suppressed later
+#ifdef UDP_PACKET_DEBUG
+ if (PREDICT_FALSE(udp_outside_packet_dump_enable)) {
+ printf("\nOut2In UDP packet before translation");
+ print_udp_pkt(ip);
+ }
+#endif
+
+#if 0
+ if(is_static_dest_nat_enabled(vrf) == CNAT_SUCCESS) {
+ direction = 1;
+ if(cnat_static_dest_db_get_translation(ip->src_addr, &postmap_ip, vrf, direction) == CNAT_SUCCESS) {
+
+ CNAT_UPDATE_L3_L4_CHECKSUM_DECLARE
+
+ old_ip = spp_net_to_host_byte_order_32(&(ip->src_addr));
+ old_postmap_ip = spp_net_to_host_byte_order_32(&postmap_ip);
+
+ CNAT_UPDATE_L3_L4_CHECKSUM(((u16)(old_ip & 0xFFFF)),
+ ((u16)(old_ip >> 16)),
+ (spp_net_to_host_byte_order_16(&(udp->src_port))),
+ (spp_net_to_host_byte_order_16(&(ip->checksum))),
+ (spp_net_to_host_byte_order_16(&(udp->udp_checksum))),
+ ((u16)(old_postmap_ip & 0xFFFF)),
+ ((u16)(old_postmap_ip >> 16)),
+ (spp_net_to_host_byte_order_16(&(udp->src_port))))
+
+ ip->checksum =
+ clib_host_to_net_u16(new_l3_c);
+ ip->src_addr = postmap_ip;
+ if (PREDICT_TRUE(udp->udp_checksum)) {
+ udp->udp_checksum = clib_host_to_net_u16(new_l4_c);
+ }
+ }
+ }
+#endif
+ /*
+ * declare variable
+ */
+ CNAT_UPDATE_L3_L4_CHECKSUM_DECLARE
+ /*
+ * calculate checksum
+ */
+ CNAT_UPDATE_L3_L4_CHECKSUM(((u16)(db->out2in_key.k.ipv4)),
+ ((u16)(db->out2in_key.k.ipv4 >> 16)),
+ (db->out2in_key.k.port),
+ (clib_net_to_host_u16(ip->checksum)),
+ (clib_net_to_host_u16(udp->udp_checksum)),
+ ((u16)(db->in2out_key.k.ipv4)),
+ ((u16)(db->in2out_key.k.ipv4 >> 16)),
+ (db->in2out_key.k.port))
+
+
+
+
+ //set ip header
+ ip->dest_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+ ip->checksum =
+ clib_host_to_net_u16(new_l3_c);
+
+ //set udp header
+ udp->dest_port =
+ clib_host_to_net_u16(db->in2out_key.k.port);
+
+ /*
+ * No easy way to avoid this if check except by using
+ * complex logic - may not be worth it.
+ */
+ if (PREDICT_TRUE(udp->udp_checksum)) {
+ udp->udp_checksum = clib_host_to_net_u16(new_l4_c);
+ }
+
+
+
+// Temporary debugs which will be suppressed later
+#ifdef UDP_PACKET_DEBUG
+ if (PREDICT_FALSE(udp_outside_checksum_disable)) {
+ printf("\nOut2In UDP checksum 0x%x disabled by force", new_l4_c);
+ udp->udp_checksum = 0;
+ }
+ if (PREDICT_FALSE(udp_outside_packet_dump_enable)) {
+ printf("\nOut2In UDP packet after translation");
+ print_udp_pkt(ip);
+ }
+#endif
+}
+
+static inline void
+stage1(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ u64 a, b, c;
+ u32 bucket;
+ u8 *prefetch_target;
+
+ vlib_buffer_t * b0 = vlib_get_buffer (vm, buffer_index);
+ ipv4_header *ip = vlib_buffer_get_current (b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ udp_hdr_type_t *udp = (udp_hdr_type_t *)((u8*)ip + ipv4_hdr_len);
+
+ u64 tmp = 0;
+ tmp = vnet_buffer(b0)->vcgn_uii.key.k.ipv4 =
+ clib_net_to_host_u32(ip->dest_addr);
+ vnet_buffer(b0)->vcgn_uii.key.k.port =
+ clib_net_to_host_u16 (udp->dest_port);
+
+ tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.port) << 32;
+
+ PLATFORM_CNAT_SET_RX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_RX],
+ vnet_buffer(b0)->vcgn_uii.key.k.vrf,
+ CNAT_UDP)
+ tmp |= ((u64)vnet_buffer(b0)->vcgn_uii.key.k.vrf) << 48;
+
+ CNAT_V4_GET_HASH(tmp, bucket, CNAT_MAIN_HASH_MASK)
+
+ prefetch_target = (u8 *)(&cnat_out2in_hash[bucket]);
+ vnet_buffer(b0)->vcgn_uii.bucket = bucket;
+
+ /* Prefetch the hash bucket */
+ CLIB_PREFETCH(prefetch_target, CLIB_CACHE_LINE_BYTES, LOAD);
+}
+
+static inline void
+stage2(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{ /* nothing */ }
+
+#define SPP_LOG2_CACHE_LINE_BYTES 6
+#define SPP_CACHE_LINE_BYTES (1 << SPP_LOG2_CACHE_LINE_BYTES)
+
+static inline void
+stage3(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index);
+ uword prefetch_target0, prefetch_target1;
+ u32 bucket = vnet_buffer(b0)->vcgn_uii.bucket;
+
+ /* read the hash bucket */
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket
+ = cnat_out2in_hash[bucket].next;
+
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+ /*
+ * Prefetch database keys. We save space by not cache-line
+ * aligning the DB entries. We don't want to waste LSU
+ * bandwidth prefetching stuff we won't need.
+ */
+ prefetch_target0 = (uword)(cnat_main_db + db_index);
+ CLIB_PREFETCH((void*)prefetch_target0, CLIB_CACHE_LINE_BYTES, STORE);
+ /* Just beyond DB key #2 */
+ prefetch_target1 = prefetch_target0 +
+ STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports);
+ /* If the targets are in different lines, do the second prefetch */
+ if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) !=
+ (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) {
+ CLIB_PREFETCH((void *)prefetch_target1, CLIB_CACHE_LINE_BYTES, STORE);
+ }
+ }
+}
+
+static inline void
+stage4(vlib_main_t * vm, vlib_node_runtime_t * node, u32 buffer_index)
+{
+ cnat_main_db_entry_t *db;
+ vlib_buffer_t * b0 = vlib_get_buffer(vm, buffer_index);
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket;
+
+ /*
+ * Note: if the search already failed (empty bucket),
+ * the answer is already in the pipeline context structure
+ */
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+
+ /*
+ * Note: hash collisions suck. We can't easily prefetch around them.
+ * The first trip around the track will be fast. After that, maybe
+ * not so much...
+ */
+ do {
+ db = cnat_main_db + db_index;
+ if (PREDICT_TRUE(db->out2in_key.key64 ==
+ vnet_buffer(b0)->vcgn_uii.key.key64)) {
+ break;
+ }
+ db_index = db->out2in_hash.next;
+ } while (db_index != EMPTY);
+
+ /* Stick the answer back into the pipeline context structure */
+ vnet_buffer(b0)->vcgn_uii.bucket = db_index;
+ }
+}
+
+#if 0
+
+ALWAYS_INLINE(
+static inline void
+stage5(spp_ctx_t **ctxs, int index, spp_node_t *np,
+ u8 *disp_used EXTRA_PIPELINE_ARGS_PROTO))
+{
+ spp_ctx_t *ctx = ctxs[index];
+ u32 db_index = pctx[index].bucket;
+ /* for nat44, dslite_id will be 1 */
+ u16 dslite_id = *(pctx[index].common_data.dslite_id_ptr);
+
+ DSLITE_PREFETCH_COUNTER(pctx[index].udp_counter,
+ &dslite_all_counters[dslite_id].v46_udp_counters,
+ dslite_v4_to_v6_udp_counter_t,
+ v4_to_v6_udp_output_count,
+ "V4_TO_V6_UDP")
+
+ DSLITE_PREFETCH_COUNTER(pctx[index].icmp_gen_counter,
+ &dslite_all_counters[dslite_id].dslite_icmp_gen_counters,
+ dslite_icmp_gen_counter_t,
+ v6_icmp_gen_count,
+ "V4_TO_V6_icmp")
+
+if (PREDICT_TRUE(db_index != EMPTY)) {
+ cnat_main_db_entry_t *db = cnat_main_db + db_index;
+
+ u32 user_db_index = db->user_index;
+ DSLITE_PRINTF(1, "UDP o2i, db entry found %u %u %u\n",
+ db_index, user_db_index,
+ db->dslite_nat44_inst_id);
+ uword prefetch_target0 = (uword)(cnat_user_db + user_db_index);
+ SPP_PREFETCH(prefetch_target0, 0, LOAD);
+ pctx[index].user_bucket = user_db_index;
+ DSLITE_PRINTF(1, "UDP: Done with prefetch..\n");
+} else {
+ DSLITE_PRINTF(1, "UDP: Stage 5, db_index empty...\n");
+}
+}
+
+#endif
+
+
+static inline u32 last_stage (vlib_main_t *vm, vlib_node_runtime_t *node,
+ u32 bi)
+{
+
+ vlib_buffer_t *b0 = vlib_get_buffer (vm, bi);
+ u32 db_index = vnet_buffer(b0)->vcgn_uii.bucket;
+ //spp_ctx_t *ctx = (spp_ctx_t *) &vnet_buffer(b0)->vcgn_uii;
+ int disposition = CNAT_V4_UDP_O2I_T;
+ int counter = CNAT_V4_UDP_O2I_T_PKT;
+ ipv4_header *ip = (ipv4_header *)vlib_buffer_get_current(b0);
+ u8 ipv4_hdr_len = (ip->version_hdr_len_words & 0xf) << 2;
+ udp_hdr_type_t *udp = (udp_hdr_type_t *)((u8*)ip + ipv4_hdr_len);
+ vlib_node_t *n = vlib_get_node (vm, cnat_ipv4_udp_outside_input_node.index);
+ u32 node_counter_base_index = n->error_heap_index;
+ vlib_error_main_t * em = &vm->error_main;
+ cnat_session_entry_t *session_db = NULL;
+ cnat_main_db_entry_t *db = NULL;
+ cnat_key_t dest_info;
+ u16 dslite_nat44_inst_id __attribute__((unused)) = 0;
+
+ dest_info.k.port = clib_net_to_host_u16(udp->src_port);
+ dest_info.k.ipv4 = clib_net_to_host_u32(ip->src_addr);
+
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+ /* TTL gen was disabled for nat44 earlier
+ * But since dslite has got integrated in this
+ * TTL gen is enabled
+ */
+
+ db = cnat_main_db + db_index;
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ /*
+ * Decrement TTL and update IPv4 checksum
+ */
+ ipv4_decr_ttl_n_calc_csum(ip);
+ }
+ if(PREDICT_TRUE(!PLATFORM_DBL_SUPPORT)) {
+
+ /* No DBL support, so just update the destn and proceed */
+ db->dst_ipv4 = dest_info.k.ipv4;
+ db->dst_port = dest_info.k.port;
+ CNAT_UDP_OUTSIDE_UPDATE_FLAG_TIMER(db, 0)
+ goto update_pkt;
+ }
+
+
+ if(PREDICT_TRUE((db->dst_ipv4 == dest_info.k.ipv4) &&
+ (db->dst_port == dest_info.k.port))) {
+
+ CNAT_UDP_OUTSIDE_UPDATE_FLAG_TIMER(db, 0)
+ goto update_pkt;
+ } else {
+ /* The session entries belonging to this entry are checked to find
+ * if an entry exist whose destination IP and port match with the
+ * source IP and port of the packet being processed
+ */
+ dest_info.k.vrf = db->in2out_key.k.vrf;
+
+ if (PREDICT_FALSE(db->nsessions == 0)) {
+ /* Should be a static entry
+ * Note this session as the first session and log
+ */
+ cnat_add_dest_n_log(db, &dest_info);
+ CNAT_UDP_OUTSIDE_UPDATE_FLAG_TIMER(db, 0)
+
+ } else if(PREDICT_TRUE(db->nsessions == 1)) {
+
+ /* Destn is not same as in main db. Multiple session
+ * scenario
+ */
+ dest_info.k.vrf = db->in2out_key.k.vrf;
+ session_db = cnat_handle_1to2_session(db, &dest_info);
+
+ if(PREDICT_FALSE(session_db == NULL)) {
+ disposition = CNAT_V4_UDP_O2I_E;
+ counter = CNAT_V4_UDP_O2I_SESSION_DROP;
+ goto drop_pkt;
+ }
+
+ /* update session_db(cur packet) timer */
+ CNAT_UDP_OUTSIDE_UPDATE_FLAG_TIMER(session_db, 0)
+ } else {
+ /* More 2 sessions exists */
+
+ dest_info.k.vrf = db->in2out_key.k.vrf;
+
+ /* If session already exists,
+ * cnat_create_session_db_entry will return the existing db
+ * else create a new db
+ * If could not create, return NULL
+ */
+ session_db = cnat_create_session_db_entry(&dest_info,
+ db, TRUE);
+
+ if(PREDICT_FALSE(session_db != NULL)) {
+ /* session exists */
+ CNAT_UDP_OUTSIDE_UPDATE_FLAG_TIMER(session_db, 0)
+ } else {
+ /* could not create session db - drop packet */
+ disposition = CNAT_V4_UDP_O2I_E;
+ counter = CNAT_V4_UDP_O2I_SESSION_DROP;
+ goto drop_pkt;
+ }
+ }
+ }
+
+update_pkt:
+
+ /*
+ * 1. update dest ipv4 addr and dest udp port
+ * 2. update ipv4 checksum and udp checksum
+ */
+ //swap_ip_dst(ip, db, db->in2out_key.k.vrf);
+ swap_ip_dst_udp_port(ip, udp, db, db->in2out_key.k.vrf);
+ //DSLITE_PRINTF(1, "Done with swap_ip_dst_udp_port..\n");
+
+ db->out2in_pkts++;
+
+ nat44_dslite_global_stats[0].out2in_forwarding_count++;
+
+ /* #### Temporarily COMMENTED FOR IP ROUTE LOOKUP ISSUE #### */
+
+ //PLATFORM_CNAT_SET_TX_VRF(vnet_buffer(b0)->sw_if_index[VLIB_TX],
+ // db->in2out_key.k.vrf)
+ } else {
+ disposition = CNAT_V4_UDP_O2I_E;
+ counter = CNAT_V4_UDP_O2I_MISS_PKT;
+ /* for NAT44 dslite_id would be 1 */
+ nat44_dslite_common_stats[0].no_translation_entry_drops ++;
+ }
+
+drop_pkt:
+
+ em->counters[node_counter_base_index + counter] += 1;
+ return disposition;
+}
+
+#include <vnet/pipeline.h>
+
+static uword cnat_ipv4_udp_outside_input_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return dispatch_pipeline (vm, node, frame);
+}
+
+
+VLIB_REGISTER_NODE (cnat_ipv4_udp_outside_input_node) = {
+ .function = cnat_ipv4_udp_outside_input_node_fn,
+ .name = "vcgn-v4-udp-o2i",
+ .vector_size = sizeof (u32),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(cnat_ipv4_udp_outside_input_error_strings),
+ .error_strings = cnat_ipv4_udp_outside_input_error_strings,
+
+ .n_next_nodes = CNAT_V4_UDP_O2I_NEXT,
+
+ /* edit / add dispositions here */
+#if 0
+ .next_nodes = {
+ //[CNAT_V4_O2I_FIXME] = "error-drop",
+ //[CNAT_V4_UDP_O2I_E] = "vcgn-v4-udp-o2i-e",
+ [CNAT_V4_UDP_O2I_E] = "vcgn-v4-udp-o2i-e",
+ [CNAT_V4_UDP_O2I_T] = "ip4-input",
+ },
+#endif
+ .next_nodes = {
+ [CNAT_V4_UDP_O2I_E] = "error-drop",
+ [CNAT_V4_UDP_O2I_T] = "ip4-input",
+ },
+
+};
+
+clib_error_t *cnat_ipv4_udp_outside_input_init (vlib_main_t *vm)
+{
+ cnat_ipv4_udp_outside_input_main_t * mp = &cnat_ipv4_udp_outside_input_main;
+
+ mp->vlib_main = vm;
+ mp->vnet_main = vnet_get_main();
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (cnat_ipv4_udp_outside_input_init);
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_log_api.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_log_api.h
new file mode 100644
index 00000000..60cf6836
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_log_api.h
@@ -0,0 +1,114 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_log_api.h
+ * Declraes the common APIs for logging (both syslog and NFV9)
+ * Copyright (c) 2013, 20122 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_LOG_API_H__
+#define __CNAT_LOG_API_H__
+
+#include "cnat_logging.h"
+
+static inline void cnat_log_ds_lite_mapping_delete(cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ )
+{
+ return;
+}
+
+static inline void cnat_log_ds_lite_mapping_create(cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ )
+{
+ return;
+}
+
+static inline void cnat_log_ds_lite_port_limit_exceeded(
+ dslite_key_t * key,
+ dslite_table_entry_t *dslite_entry_ptr)
+{
+ return;
+
+}
+
+static inline void cnat_log_nat44_port_limit_exceeded(
+ cnat_key_t * key,
+ cnat_vrfmap_t *vrfmap)
+{
+ return;
+}
+static inline void cnat_log_nat44_mapping_create(cnat_main_db_entry_t *db,
+ cnat_vrfmap_t *vrfmap
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ )
+{
+ return;
+}
+
+static inline void cnat_log_nat44_mapping_delete(cnat_main_db_entry_t *db,
+ cnat_vrfmap_t *vrfmap
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ )
+{
+ return;
+}
+
+/* Session Logging API for nat44 */
+static inline void cnat_session_log_nat44_mapping_create (
+ cnat_main_db_entry_t *db,
+ cnat_session_entry_t *sdb,
+ cnat_vrfmap_t *vrfmap )
+{
+ return;
+}
+
+static inline void cnat_session_log_nat44_mapping_delete (
+ cnat_main_db_entry_t *db,
+ cnat_session_entry_t *sdb,
+ cnat_vrfmap_t *vrfmap )
+{
+ return;
+}
+
+/* Session Logging API for dslite */
+static inline void cnat_session_log_ds_lite_mapping_create (
+ cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry,
+ cnat_session_entry_t *sdb )
+{
+ return;
+}
+
+static inline void cnat_session_log_ds_lite_mapping_delete (
+ cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry,
+ cnat_session_entry_t *sdb )
+{
+ return;
+}
+
+#endif /* #ifndef __CNAT_LOG_API_H__ */
+
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_log_common.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_log_common.h
new file mode 100644
index 00000000..52731bc0
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_log_common.h
@@ -0,0 +1,79 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_log_common.h
+ * Contains macros and definitions that are common to both syslog and nfv9
+ * Copyright (c) 2011-2012 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_LOG_COMMON_H__
+#define __CNAT_LOG_COMMON_H__
+
+#include <stdio.h>
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+#include "cnat_db.h"
+#include "nat64_db.h"
+#include "spp_timers.h"
+#include "spp_ctx.h"
+
+/*
+ * This corresponds to the length of the IMETRO SHIM Header for RODDICK
+ * For non-roddick cases, introduce an Ethernet header as well
+ */
+#if 0
+ #if defined(TARGET_RODDICK)
+ #define CNAT_NFV9_SHIM_HDR_OFFSET 8
+ #define CNAT_NFV9_L2_ENCAPS_OFFSET 0
+ #else
+ #define CNAT_NFV9_SHIM_HDR_OFFSET 0
+ #define CNAT_NFV9_L2_ENCAPS_OFFSET 16
+ #endif
+#endif
+
+ #define CNAT_NFV9_IP_HDR_OFFSET 0
+
+ #define CNAT_NFV9_UDP_HDR_OFFSET \
+ (CNAT_NFV9_IP_HDR_OFFSET + sizeof(ipv4_header))
+
+ #define CNAT_NFV9_HDR_OFFSET \
+ (CNAT_NFV9_UDP_HDR_OFFSET + sizeof(udp_hdr_type_t))
+
+u32 cnat_get_sys_up_time_in_ms(void);
+u32 cnat_get_unix_time_in_seconds(void);
+void cnat_dump_time_change_logs(void);
+void cnat_handle_sys_time_change (time_t current_unix_time);
+/*
+ * Maximum number of time log changes we maintain
+ */
+
+#define MAX_TIME_CHANGE_LOGS (8)
+
+typedef struct {
+ /*
+ * A timer structure to periodically send NFv9 & syslog logging packets
+ * that have been waiting to be full for a long time. This will
+ * ensure add/delete events don't get delayed too much before they
+ * are sent to the collector.
+ */
+ spp_timer_t log_timer;
+
+ /*
+ * Whether we have initialized the NFv9 information
+ */
+ u8 cnat_log_init_done;
+} cnat_log_global_info_t;
+
+#endif /* __CNAT_LOG_COMMON_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_logging.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_logging.c
new file mode 100644
index 00000000..71f156a9
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_logging.c
@@ -0,0 +1,3500 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_logging.c
+ *
+ * Copyright (c) 2009-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/error.h>
+#include <vnet/buffer.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ip/ip4.h>
+#include <vnet/ip/ip4_packet.h>
+#include <vnet/ip/format.h>
+#include <vnet/ip/udp.h>
+
+
+#include "cnat_config.h"
+#include "cnat_global.h"
+#include "cnat_v4_functions.h"
+#include "tcp_header_definitions.h"
+#include "cnat_v4_ftp_alg.h"
+#include "cnat_logging.h"
+#include "platform_common.h"
+
+#define CNAT_NFV9_DEBUG_CODE 2
+#if CNAT_NFV9_DEBUG_CODE > 3
+
+#define NFV9_COND if ((my_instance_number != 0) && (my_instance_number != 15))
+
+#define NFV9_DEBUG_PRINTF1(a) NFV9_COND printf(a);
+#define NFV9_DEBUG_PRINTF2(a, b) NFV9_COND printf(a, b);
+#define NFV9_DEBUG_PRINTF3(a, b, c) NFV9_COND printf(a, b, c);
+#define NFV9_DEBUG_PRINTF4(a, b, c, d) NFV9_COND printf(a, b, c, d);
+
+#else
+
+#define NFV9_DEBUG_PRINTF1(a)
+#define NFV9_DEBUG_PRINTF2(a, b)
+#define NFV9_DEBUG_PRINTF3(a, b, c)
+#define NFV9_DEBUG_PRINTF4(a, b, c, d)
+
+#endif
+
+static void cnat_nfv9_insert_ingress_vrfid_name_record(cnat_nfv9_logging_info_t *nfv9_logging_info, u16 index);
+void cnat_nfv9_ingress_vrfid_name_mapping_create(
+ cnat_nfv9_logging_info_t *nfv9_logging_info);
+
+
+cnat_nfv9_global_info_t cnat_nfv9_global_info;
+
+cnat_nfv9_template_t cnat_nfv9_template_info;
+
+#define CNAT_NFV9_OPTION_TEMPLATE cnat_nfv9_template_info.cnat_nfv9_option_template
+
+u16 cnat_template_id[MAX_RECORDS] =
+ {0, CNAT_NFV9_ADD_TEMPLATE_ID, CNAT_NFV9_DEL_TEMPLATE_ID,
+ CNAT_NFV9_NAT64_ADD_BIB_TEMPLATE_ID,CNAT_NFV9_NAT64_DEL_BIB_TEMPLATE_ID,
+ CNAT_NFV9_NAT64_ADD_SESSION_TEMPLATE_ID,
+ CNAT_NFV9_NAT64_DEL_SESSION_TEMPLATE_ID,
+ CNAT_NFV9_DS_LITE_ADD_TEMPLATE_ID,
+ CNAT_NFV9_DS_LITE_DEL_TEMPLATE_ID
+#ifndef NO_BULK_LOGGING
+ , CNAT_NFV9_NAT44_BULK_ADD_TEMPLATE_ID,
+ CNAT_NFV9_NAT44_BULK_DEL_TEMPLATE_ID,
+ CNAT_NFV9_DS_LITE_BULK_ADD_TEMPLATE_ID,
+ CNAT_NFV9_DS_LITE_BULK_DEL_TEMPLATE_ID
+#endif /* #ifndef NO_BULK_LOGGING */
+ , CNAT_NFV9_INGRESS_VRF_ID_NAME_TEMPLATE_ID,
+ CNAT_NFV9_NAT44_ADD_SESSION_TEMPLATE_ID,
+ CNAT_NFV9_NAT44_DEL_SESSION_TEMPLATE_ID,
+ CNAT_NFV9_DS_LITE_ADD_SESSION_TEMPLATE_ID,
+ CNAT_NFV9_DS_LITE_DEL_SESSION_TEMPLATE_ID
+ };
+
+/*
+ * Logging information structures
+ */
+cnat_nfv9_logging_info_t cnat_default_nfv9_logging_info;
+cnat_nfv9_logging_info_t *cnat_nfv9_logging_info_pool;
+#define NFV9_SERVER_POOL_SIZE 16
+nfv9_server_info_t *nfv9_server_info_pool;
+
+u32 nfv9_src_id = 0;
+
+u32
+cnat_get_sys_up_time_in_ms (void)
+{
+ vlib_main_t * vm = vlib_get_main();
+ u32 cnat_curr_time;
+
+ cnat_curr_time = (u32)vlib_time_now (vm);
+ return cnat_curr_time;
+}
+
+void
+cnat_dump_time_change_logs (void)
+{
+ return;
+}
+
+inline void cnat_nfv9_handle_sys_time_change(time_t current_unix_time)
+{
+ return;
+ #if 0
+ cnat_handle_sys_time_change(current_unix_time);
+ #endif
+}
+
+void cnat_nfv9_update_sys_time_change()
+{
+ cnat_nfv9_logging_info_t *my_nfv9_logging_info = NULL;
+ pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info_pool, ({
+ nfv9_server_info_t *server = nfv9_server_info_pool +
+ my_nfv9_logging_info->server_index;
+ server->last_template_sent_time = 0;
+ }));
+}
+
+void nfv9_params_show(u32 logging_index)
+{
+ cnat_nfv9_logging_info_t *log_info;
+ if(logging_index == EMPTY) {
+ PLATFORM_DEBUG_PRINT("\nNetflow logging not configured\n");
+ return;
+ }
+
+ log_info = cnat_nfv9_logging_info_pool + logging_index;
+ nfv9_server_info_t *server __attribute__((unused))
+ = nfv9_server_info_pool + log_info->server_index;
+
+
+ PLATFORM_DEBUG_PRINT("\nNetflow parameters --\n");
+ PLATFORM_DEBUG_PRINT("Server index %d IPV4 address: %x, port %d, max log size %d\n",
+ log_info->server_index, server->ipv4_address,
+ server->port, log_info->max_length_minus_max_record_size);
+
+ PLATFORM_DEBUG_PRINT("Server ref count %d Refresh rate %d timeout rate %d\n",
+ server->ref_count, server->refresh_rate,
+ server->timeout_rate);
+
+}
+
+/*
+ * Code to dump NFV9 packets before they are sent
+ */
+void
+cnat_nfv9_dump_logging_context (u32 value1,
+ cnat_nfv9_logging_info_t *nfv9_logging_info,
+ u32 value2)
+{
+ u8 *pkt_ptr;
+ u32 i;
+ u32 next_nfv9_template_data_index = 0xffff;
+ u32 next_data_flow_index = 0xffff;
+ u32 next_data_record = 0xffff;
+ u32 data_record_size = 0;
+ vlib_main_t *vm = vlib_get_main();
+
+ nfv9_server_info_t *server = nfv9_server_info_pool +
+ nfv9_logging_info->server_index;
+
+ vlib_cli_output(vm,"\nDumping %s packet at locn %d: time 0x%x",
+ (value2 == 1) ? "CURRENT" : "QUEUED",
+ value1,
+ cnat_nfv9_get_unix_time_in_seconds());
+
+ vlib_cli_output(vm, "\ni_vrf 0x%x, ip_address 0x%x, port %d",
+ nfv9_logging_info->i_vrf,
+ server->ipv4_address,
+ server->port);
+
+ vlib_cli_output(vm,"\nseq_num %d",
+ server->sequence_num);
+
+ vlib_cli_output(vm,"\nlast_template_sent time 0x%x, pkts_since_last_template %d",
+ server->last_template_sent_time,
+ server->pkts_since_last_template);
+
+ vlib_cli_output(vm, "\npkt_len %d, add_rec_len %d, del_rec_len %d, total_rec_count %d",
+ nfv9_logging_info->pkt_length,
+ nfv9_logging_info->record_length[NAT44_ADD_RECORD],
+ nfv9_logging_info->record_length[NAT44_DEL_RECORD],
+ nfv9_logging_info->total_record_count);
+
+ vlib_cli_output(vm,"\nbulk_add_rec_len %d, bulk_del_rec_len %d",
+ nfv9_logging_info->record_length[NAT44_BULK_ADD_RECORD],
+ nfv9_logging_info->record_length[NAT44_BULK_DEL_RECORD]);
+
+ vlib_cli_output(vm,"\ncurr_logging_ctx 0x%p, timestamp 0x%x, queued_logging_ctx 0x%p",
+ nfv9_logging_info->current_logging_context,
+ nfv9_logging_info->current_logging_context_timestamp,
+ nfv9_logging_info->queued_logging_context);
+
+ vlib_cli_output(vm,"\nnfv9_hdr 0x%p, tmpl_hdr 0x%p, dataflow_hdr 0x%p",
+ nfv9_logging_info->nfv9_header,
+ nfv9_logging_info->nfv9_template_header,
+ nfv9_logging_info->dataflow_header);
+
+ vlib_cli_output(vm,"\nadd_rec 0x%p, del_rec 0x%p, next_data_ptr 0x%p",
+ nfv9_logging_info->record[NAT44_ADD_RECORD],
+ nfv9_logging_info->record[NAT44_DEL_RECORD],
+ nfv9_logging_info->next_data_ptr);
+
+ vlib_cli_output(vm,"\n");
+
+ pkt_ptr = vlib_buffer_get_current(nfv9_logging_info->current_logging_context);
+ /*
+ * Dump along with 8 bytes of SHIM header
+ */
+ for (i = 0; i < (nfv9_logging_info->pkt_length + CNAT_NFV9_IP_HDR_OFFSET);
+ i = i + 1) {
+ u8 c1, c2, c3;
+ if (i == CNAT_NFV9_IP_HDR_OFFSET) {
+ vlib_cli_output(vm,"\nIP_HEADER: \n");
+ } else if (i == CNAT_NFV9_UDP_HDR_OFFSET) {
+ vlib_cli_output(vm,"\nUDP_HEADER: \n");
+ } else if (i == CNAT_NFV9_HDR_OFFSET) {
+ vlib_cli_output(vm,"\nNFV9 Header: Version:Count: \n");
+ } else if (i == (CNAT_NFV9_HDR_OFFSET+4)) {
+ vlib_cli_output(vm,"\nBoot_Up_Time_In_ms: \n");
+ } else if (i == (CNAT_NFV9_HDR_OFFSET+8)) {
+ vlib_cli_output(vm, "\nUNIX_Time: \n");
+ } else if (i == (CNAT_NFV9_HDR_OFFSET+12)) {
+ vlib_cli_output(vm,"\nSeq_Num: \n");
+ } else if (i == (CNAT_NFV9_HDR_OFFSET+16)) {
+ vlib_cli_output(vm,"\nSource ID: \n");
+ } else if (i == (CNAT_NFV9_HDR_OFFSET+20)) {
+ if (nfv9_logging_info->nfv9_template_header) {
+ vlib_cli_output(vm,"\nNFV9 TEMPLATE HDR: \n");
+ next_nfv9_template_data_index = i + 4;
+ } else {
+ next_data_flow_index = i;
+ }
+ } else if (i == (CNAT_NFV9_TEMPLATE_OFFSET+CNAT_NFV9_TEMPLATE_LENGTH)) {
+ if (nfv9_logging_info->nfv9_template_header) {
+ next_data_flow_index = i;
+ }
+ }
+
+ if (i == next_nfv9_template_data_index) {
+ vlib_cli_output(vm,"\nNFV9 TEMPLATE DATA: \n");
+ } else if (i == next_data_flow_index) {
+ if (*(pkt_ptr + i) == 0x01) {
+ if (*(pkt_ptr + i + 1) == 0x00) {
+ data_record_size = 21;
+ next_data_record = i + 4;
+ next_data_flow_index = i + *(pkt_ptr + i + 3) +
+ *(pkt_ptr + i + 2)*0x100;
+ vlib_cli_output(vm,"\nADD_RECORD (total %d): next_data_flow_index (%d->%d)\n", (next_data_flow_index - i), i, next_data_flow_index);
+ } else if (*(pkt_ptr + i + 1) == 0x01) {
+ data_record_size = 11;
+ next_data_record = i + 4;
+ next_data_flow_index = i + *(pkt_ptr + i + 3) +
+ *(pkt_ptr + i + 2)*0x100;
+ vlib_cli_output(vm,"\nDEL_RECORD (total %d) : next_data_flow_index (%d->%d)\n", (next_data_flow_index - i), i, next_data_flow_index);
+ } else if (*(pkt_ptr + i + 1) == 0x09) {
+ data_record_size = 20;
+ next_data_record = i + 4;
+ next_data_flow_index = i + *(pkt_ptr + i + 3) +
+ *(pkt_ptr + i + 2)*0x100;
+ vlib_cli_output(vm,"\nBULK_ADD_RECORD (total %d) : next_data_flow_index (%d->%d)\n", (next_data_flow_index - i), i, next_data_flow_index);
+ } else if (*(pkt_ptr + i + 1) == 0x0a) {
+ data_record_size = 10;
+ next_data_record = i + 4;
+ next_data_flow_index = i + *(pkt_ptr + i + 3) +
+ *(pkt_ptr + i + 2)*0x100;
+ vlib_cli_output(vm,"\nBULK_DEL_RECORD (total %d) : next_data_flow_index (%d->%d)\n", (next_data_flow_index - i), i, next_data_flow_index);
+ }
+
+ }
+ } else if (i == next_data_record) {
+ vlib_cli_output(vm,"\n");
+ next_data_record += data_record_size;
+ }
+
+ c3 = *(pkt_ptr + i);
+
+ c2 = c3 & 0xf;
+ c1 = (c3 >> 4) & 0xf;
+
+
+ vlib_cli_output(vm,"%c%c ",
+ ((c1 <= 9) ? (c1 + '0') : (c1 - 10 + 'a')),
+ ((c2 <= 9) ? (c2 + '0') : (c2 - 10 + 'a')));
+
+ }
+ vlib_cli_output(vm,"\n");
+}
+
+/*
+ * edt: * * cnat_nfv9_pad_added_to_an_addr
+ *
+ * Returns the difference (no# of bytes) between new_addr
+ * & org_addr
+ *
+ * Argument: u8 *new_addr, u8 *org_addr
+ * returns the difference
+ */
+
+static inline
+int cnat_nfv9_pad_added_to_an_addr(u8 *new_addr, u8 *org_addr)
+{
+ uword addr1 = (uword) new_addr;
+ uword addr2 = (uword) org_addr;
+ return (addr1 - addr2);
+}
+
+/*
+ * edt: * * cnat_nfv9_add_end_of_record_padding
+ *
+ * Tries to add padding to data_ptr to ensure it is word aligned
+ *
+ * Argument: u8 * data_ptr
+ * pointer to the data pointer
+ */
+
+static inline
+u8 *cnat_nfv9_add_end_of_record_padding (u8 *data_ptr)
+{
+ uword tmp = (uword) data_ptr;
+ uword pad_value = (uword) NFV9_PAD_VALUE;
+
+ tmp = (tmp + pad_value) & (~pad_value);
+
+ return ((u8 *) tmp);
+}
+
+/*
+ * edt: * * cnat_nfv9_pad_end_of_record_length
+ *
+ * Tries to add padding to data_ptr to ensure it is word aligned
+ *
+ * Argument: u8 * data_ptr
+ * pointer to the data pointer
+ */
+
+static inline
+u16 cnat_nfv9_pad_end_of_record_length (u16 record_length)
+{
+ u16 pad_value = NFV9_PAD_VALUE;
+
+ return ((record_length + pad_value) & (~pad_value));
+}
+
+void fill_ip_n_udp_hdr (u32 ipv4_addr, u16 port,
+ cnat_nfv9_logging_info_t *nfv9_logging_info)
+{
+ vlib_buffer_t * b0 = nfv9_logging_info->current_logging_context;
+ ipv4_header *ip_header = vlib_buffer_get_current(b0);
+ udp_hdr_type_t *udp_header = (udp_hdr_type_t *)((u8*)ip_header + sizeof(ipv4_header));
+ vlib_main_t *vm = vlib_get_main();
+ u16 ip_length __attribute__((unused));
+ u16 pkt_len = nfv9_logging_info->pkt_length;
+ ip4_address_t *ia0 = 0;
+ u16 src_port = 0x0a0a;
+
+ /*
+ * Clear the SHIM header fields. The PD nodes will set it
+ * appropriately.
+ */
+ PLATFORM_MEMSET_CNAT_LOG_PKT_DATA
+
+ /*
+ * Don't need a special define for 0x45 - IP version and hdr len
+ */
+ ip_header->version_hdr_len_words = 0x45;
+ ip_header->tos = 0;
+ ip_header->frag_flags_offset = 0;
+ ip_header->ttl = 0xff;
+ ip_header->protocol = UDP_PROT;
+ ip_header->dest_addr = clib_host_to_net_u32(ipv4_addr);
+ ip_length = vlib_buffer_length_in_chain (vm, b0);
+ ip_header->total_len_bytes = clib_host_to_net_u16(pkt_len);
+ ia0 = ip4_interface_first_address(&ip4_main, nfv9_logging_info->i_vrf_id, 0);
+ ip_header->src_addr = ia0->as_u32;
+ udp_header->src_port = clib_host_to_net_u16(src_port);
+ udp_header->dest_port = clib_host_to_net_u16(port);
+ udp_header->udp_checksum = 0;
+ udp_header->udp_length =
+ clib_host_to_net_u16(pkt_len - sizeof(ipv4_header));
+ ip_header->checksum = ip4_header_checksum((ip4_header_t *)ip_header);
+}
+
+/*
+ * edt: * * cnat_nfv9_fill_nfv9_ip_header
+ *
+ * Tries to fill the fields of the IP header before it
+ * is sent to the L3 infra node.
+ *
+ * Argument: cnat_nfv9_logging_info_t *nfv9_logging_info
+ * structure that contains the packet context
+ */
+
+static inline
+void cnat_nfv9_fill_nfv9_ip_header (cnat_nfv9_logging_info_t *nfv9_logging_info)
+{
+ u16 new_record_length = 0;
+ u16 orig_record_length = 0;
+ vlib_buffer_t * b0 = nfv9_logging_info->current_logging_context;
+
+ /*
+ * Fill in the IP header and port number of the Netflow collector
+ * The L3 Infra node will fill in the rest of the fields
+ */
+
+ nfv9_logging_info->nfv9_header->count =
+ clib_host_to_net_u16(nfv9_logging_info->total_record_count);
+
+ /*
+ * Pad the last add/del record to ensure multiple of 4 bytes
+ */
+
+ if(nfv9_logging_info->last_record != RECORD_INVALID) {
+
+ orig_record_length =
+ nfv9_logging_info->record_length[nfv9_logging_info->last_record];
+
+ new_record_length = cnat_nfv9_pad_end_of_record_length(
+ orig_record_length);
+
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u16(new_record_length);
+ }
+
+ /*
+ * If the record is padded, ensure the padded bytes are ZERO
+ */
+ if (PREDICT_TRUE(new_record_length - orig_record_length)) {
+ u8 *pkt_ptr = (u8 *) (b0 + nfv9_logging_info->pkt_length);
+
+ /*
+ * Blindly copy 3 bytes of data to Zero to avoid for loops
+ * We have sufficient padding bytes for safety and we won't
+ * go over buffer limits
+ */
+ *pkt_ptr++ = 0;
+ *pkt_ptr++ = 0;
+ *pkt_ptr++ = 0;
+
+ nfv9_logging_info->pkt_length +=
+ (new_record_length - orig_record_length);
+ }
+ nfv9_server_info_t *server = nfv9_server_info_pool +
+ nfv9_logging_info->server_index;
+ fill_ip_n_udp_hdr(server->ipv4_address,
+ server->port, nfv9_logging_info);
+ /*
+ * It is important to set the sw_if_index for the new buffer create
+ */
+ vnet_buffer(b0)->sw_if_index[VLIB_TX] = (u32)~0;
+
+}
+
+/*
+ * edt: * * cnat_nfv9_send_queued_pkt
+ *
+ * Tries to send a logging pkt that has been queued earlier
+ * because it could not be sent due to downstream constipation
+ *
+ * Argument: cnat_nfv9_logging_info_t *nfv9_logging_info
+ * structure that contains the packet context
+ */
+
+static inline
+void cnat_nfv9_send_queued_pkt (cnat_nfv9_logging_info_t *nfv9_logging_info)
+{
+ return;
+}
+
+/*
+ * edt: * * cnat_nfv9_send_pkt
+ *
+ * Tries to send a logging pkt. If the packet cannot be sent
+ * because of rewrite_output node cannot process it, queue
+ * it temporarily and try to send it later.
+ *
+ * Argument: cnat_nfv9_logging_info_t *nfv9_logging_info
+ * structure that contains the packet context
+ */
+
+static inline
+void cnat_nfv9_send_pkt (cnat_nfv9_logging_info_t *nfv9_logging_info)
+{
+ cnat_nfv9_fill_nfv9_ip_header(nfv9_logging_info);
+
+ nfv9_server_info_t *server = nfv9_server_info_pool +
+ nfv9_logging_info->server_index;
+
+ /* Update sequence number just before sending.
+ * So that, multiple NAT44/NAT64/DSLite instances sharing a
+ * a single server instance can stamp the sequence number
+ * in the right sequence (as seen by the server).
+ */
+ server->sequence_num += 1;
+ nfv9_logging_info->nfv9_header->sequence_num =
+ clib_host_to_net_u32(server->sequence_num);
+
+#if DEBUG
+ cnat_nfv9_dump_logging_context (2, nfv9_logging_info, 1);
+#endif
+#if 0 /* commented out below */
+ send_vpp3_nfv9_pkt(nfv9_logging_info);
+#endif
+ nfv9_logging_info->current_logging_context = NULL;
+ /*
+ * Increase last packet sent count
+ */
+ server->pkts_since_last_template++;
+
+ /*
+ * If we are sending an nfv9 tempate with this packet
+ * log this timestamp
+ */
+ if (nfv9_logging_info->nfv9_template_header) {
+ server->last_template_sent_time =
+ cnat_nfv9_get_unix_time_in_seconds();
+ server->pkts_since_last_template = 0;
+ }
+
+ return;
+}
+
+/*
+ * send_vpp3_nfv9_pkt: to send multiple b0 in a frame
+ */
+
+static inline
+void send_vpp3_nfv9_pkt (cnat_nfv9_logging_info_t *nfv9_logging_info)
+{
+ vlib_node_t *output_node;
+ vlib_main_t *vm = vlib_get_main();
+ vlib_frame_t *f;
+ vlib_buffer_t *b0;
+ u32 *to_next;
+ u32 bi=0;
+ ipv4_header *ip;
+
+ //Lets check and send it to ip4-lookup node
+ output_node = vlib_get_node_by_name (vm, (u8 *) "ip4-lookup");
+ f = vlib_get_frame_to_node (vm, output_node->index);
+
+ if ( nfv9_logging_info->current_logging_context != NULL) {
+ /* Build a pkt from whole cloth */
+ b0 = nfv9_logging_info->current_logging_context;
+ ip = vlib_buffer_get_current(b0);
+ to_next = vlib_frame_vector_args (f);
+ bi = vlib_get_buffer_index (vm, b0);
+ to_next[0] = bi;
+
+ f->n_vectors = 1;
+ b0->current_length = clib_net_to_host_u16(ip->total_len_bytes);
+ vlib_put_frame_to_node (vm, output_node->index, f);
+ }
+ return;
+}
+/*
+ * edt: * * cnat_nfv9_send_pkt_always_success
+ *
+ * Tries to send a logging pkt. This cannot fail due to downstream
+ * constipation because we have already checked if the rewrite_output
+ * node can accept it.
+ *
+ * Argument: cnat_nfv9_logging_info_t *nfv9_logging_info
+ * structure that contains the packet context
+ *
+ * Argument: vlib_node_t *output_node
+ * vlib_node_t structure for rewrite_output node
+ */
+
+static inline
+void cnat_nfv9_send_pkt_always_success (
+ cnat_nfv9_logging_info_t *nfv9_logging_info,
+ vlib_node_t *output_node)
+{
+ nfv9_server_info_t *server = nfv9_server_info_pool +
+ nfv9_logging_info->server_index;
+ vlib_main_t * vm = vlib_get_main();
+
+ /*
+ * At this point we either have a current or queued logging context
+ */
+ if (PREDICT_TRUE(nfv9_logging_info->current_logging_context != NULL)) {
+ server->sequence_num += 1;
+ nfv9_logging_info->nfv9_header->sequence_num =
+ clib_host_to_net_u32(server->sequence_num);
+ cnat_nfv9_fill_nfv9_ip_header(nfv9_logging_info);
+
+ nfv9_logging_info->current_logging_context->current_length =
+ nfv9_logging_info->pkt_length;
+ vlib_cli_output(vm, "\nNFV9: 3. Sending Current packet\n");
+#if DEBUG
+ cnat_nfv9_dump_logging_context (3, nfv9_logging_info, 1);
+#endif
+ send_vpp3_nfv9_pkt(nfv9_logging_info);
+ nfv9_logging_info->current_logging_context = NULL;
+ } else {
+ /*
+ * For queued logging context, nfv9_header-> count is already set
+ */
+ nfv9_logging_info->queued_logging_context->current_length =
+ nfv9_logging_info->pkt_length;
+ vlib_cli_output(vm,"\nNFV9: 4. Sending Queued packet\n");
+#if DEBUG
+ cnat_nfv9_dump_logging_context (4, nfv9_logging_info, 2);
+#endif
+ send_vpp3_nfv9_pkt(nfv9_logging_info);
+
+ nfv9_logging_info->queued_logging_context = NULL;
+ }
+
+ /*
+ * NF Logging info already deleted, just free it and return
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->deleted)) {
+ pool_put(cnat_nfv9_logging_info_pool, nfv9_logging_info);
+ return;
+ }
+
+ /*
+ * Increase last packet sent count and timestamp
+ */
+ server->pkts_since_last_template++;
+
+ /*
+ * If we are sending an nfv9 tempate with this packet
+ * log this timestamp
+ */
+ if (nfv9_logging_info->nfv9_template_header) {
+ server->last_template_sent_time =
+ cnat_nfv9_get_unix_time_in_seconds();
+ server->pkts_since_last_template = 0;
+ }
+}
+
+/*
+ * edt: * * cnat_nfv9_create_logging_context
+ *
+ * Tries to create a logging context with packet buffer
+ * to send a new logging packet
+ *
+ * Argument: cnat_nfv9_logging_info_t *nfv9_logging_info
+ * structure that contains the nfv9 logging info and will store
+ * the packet context as well.
+ */
+
+static inline
+void cnat_nfv9_create_logging_context (
+ cnat_nfv9_logging_info_t *nfv9_logging_info,
+ cnat_nfv9_template_add_flag_t template_flag)
+{
+ vlib_main_t *vm = vlib_get_main();
+ vlib_buffer_t *b0;
+ static u32 bi;
+ u8 i;
+
+ /*
+ * If queued_logging_context_index is non-EMPTY, we already have a logging
+ * packet queued to be sent. First try sending this before allocating
+ * a new context. We can have only one active packet context per
+ * nfv9_logging_info structure
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->queued_logging_context != NULL)) {
+ cnat_nfv9_send_queued_pkt(nfv9_logging_info);
+ /*
+ * If we cannot still send the queued pkt, just return
+ * Downstream Constipation count would have increased anyway
+ */
+ if (nfv9_logging_info->queued_logging_context != NULL) {
+ cnat_global_counters.nfv9_logging_context_creation_deferred_count++;
+ return;
+ }
+ }
+
+
+ /*
+ * No context can be allocated, return silently
+ * calling routine will handle updating the error counters
+ */
+ if (vlib_buffer_alloc (vm, &bi, 1) != 1) {
+ vlib_cli_output(vm, "buffer allocation failure");
+ return;
+ }
+ /* Build a pkt from whole cloth */
+ b0 = vlib_get_buffer (vm, bi);
+ b0->current_data = 0;
+
+ nfv9_server_info_t *server = nfv9_server_info_pool +
+ nfv9_logging_info->server_index;
+
+ nfv9_logging_info->current_logging_context = b0;
+ nfv9_logging_info->current_logging_context_timestamp =
+ cnat_nfv9_get_sys_up_time_in_ms();
+
+
+ nfv9_logging_info->nfv9_header =
+ (nfv9_header_t *) (vlib_buffer_get_current(b0) +
+ (sizeof(ipv4_header)) +
+ (sizeof(udp_hdr_type_t)));
+
+ nfv9_logging_info->nfv9_header->version =
+ clib_host_to_net_u16(CNAT_NFV9_VERSION_NUMBER);
+
+ nfv9_logging_info->nfv9_header->sys_up_time =
+ clib_host_to_net_u32(cnat_nfv9_get_sys_up_time_in_ms());
+
+ nfv9_logging_info->nfv9_header->timestamp =
+ clib_host_to_net_u32(cnat_nfv9_get_unix_time_in_seconds());
+
+
+ nfv9_logging_info->nfv9_header->source_id =
+ clib_host_to_net_u32(nfv9_src_id);
+
+ nfv9_logging_info->dataflow_header = 0;
+
+ for(i = 0; i < MAX_RECORDS;i++) {
+ nfv9_logging_info->record[i] = NULL;
+ nfv9_logging_info->record_length[i] = 0;
+ }
+ nfv9_logging_info->last_record = 0;
+
+
+ nfv9_logging_info->nfv9_template_header = 0;
+ nfv9_logging_info->next_data_ptr =
+ (u8 *) (vlib_buffer_get_current(b0) +
+ sizeof(ipv4_header) + sizeof(udp_hdr_type_t) +
+ sizeof(nfv9_header_t));
+
+ nfv9_logging_info->pkt_length = (CNAT_NFV9_TEMPLATE_OFFSET -
+ CNAT_NFV9_IP_HDR_OFFSET);
+
+
+ /*
+ * Now we have 0 records to start with
+ */
+
+ nfv9_logging_info->total_record_count = 0;
+
+ if ((template_flag == cnat_nfv9_template_add_always) ||
+ (server->pkts_since_last_template >
+ server->refresh_rate) ||
+ ((cnat_nfv9_get_unix_time_in_seconds() -
+ server->last_template_sent_time) >
+ server->timeout_rate)) {
+
+ /*
+ * Send a new template
+ */
+ nfv9_logging_info->nfv9_template_header =
+ (cnat_nfv9_template_t *) nfv9_logging_info->next_data_ptr;
+
+ clib_memcpy(nfv9_logging_info->nfv9_template_header,
+ &cnat_nfv9_template_info,
+ sizeof(cnat_nfv9_template_info));
+
+ /*
+ * Templates are sent irrespective of particular service-type config
+ */
+ nfv9_logging_info->total_record_count = MAX_RECORDS - 1;
+
+ nfv9_logging_info->pkt_length += CNAT_NFV9_TEMPLATE_LENGTH;
+
+ /*
+ * Set the data pointer beyond the template field
+ */
+ nfv9_logging_info->next_data_ptr =
+ (u8 *) (nfv9_logging_info->nfv9_template_header + 1);
+ /*
+ * Setting template_sent flag as TRUE. this will be checked in
+ * handle_vrfid_name_mapping()
+ */
+ server->template_sent = TEMPLATE_SENT_TRUE;
+ }
+}
+
+void cnat_nfv9_record_create (
+ cnat_nfv9_logging_info_t *nfv9_logging_info, u16 cur_record)
+{
+ int byte_diff = 0;
+ u16 last_record = nfv9_logging_info->last_record;
+
+ if(last_record != 0 && last_record != cur_record) {
+ u16 orig_length, new_length;
+
+ orig_length = nfv9_logging_info->record_length[last_record];
+ new_length = cnat_nfv9_pad_end_of_record_length(orig_length);
+
+ /*
+ * The padding bytes are required after the last record
+ * Ensure length of last record accounts for padding bytes
+ */
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u16(new_length);
+
+ /*
+ * Since we are working on the del record, set add record to 0
+ */
+ nfv9_logging_info->record[last_record] = 0;
+
+ nfv9_logging_info->record_length[last_record] = 0;
+
+ nfv9_logging_info->last_record = 0;
+ }
+
+ nfv9_logging_info->last_record = cur_record;
+
+ /*
+ * The padding bytes are required after the last record
+ * Ensure that we skip over the padding bytes
+ */
+ nfv9_logging_info->dataflow_header = (nfv9_dataflow_record_header_t *)
+ cnat_nfv9_add_end_of_record_padding(nfv9_logging_info->next_data_ptr);
+ /*
+ * Get the difference
+ */
+ byte_diff = cnat_nfv9_pad_added_to_an_addr(
+ (u8 *)nfv9_logging_info->dataflow_header,
+ nfv9_logging_info->next_data_ptr);
+ if(byte_diff > 0) {
+ /*
+ * Update the packet length to account for the pad bytes
+ */
+ nfv9_logging_info->pkt_length += byte_diff;
+ u8 *pkt_ptr = nfv9_logging_info->next_data_ptr;
+
+ /*
+ * Blindly copy 3 bytes of data to Zero to avoid for loops
+ * We have sufficient padding bytes for safety and we won't
+ * go over buffer limits
+ */
+ *pkt_ptr++ = 0;
+ *pkt_ptr++ = 0;
+ *pkt_ptr++ = 0;
+ }
+ /*
+ * Initialize the template_id and the length of the add record
+ */
+ nfv9_logging_info->dataflow_header->dataflow_template_id =
+ clib_host_to_net_u16(cnat_template_id[cur_record]);
+
+ nfv9_logging_info->record[cur_record] =
+ (u8 *) (nfv9_logging_info->dataflow_header + 1);
+
+ nfv9_logging_info->record_length[cur_record] =
+ CNAT_NFV9_DATAFLOW_RECORD_HEADER_LENGTH;
+
+ /*
+ * Update the length of the total NFV9 record
+ */
+ nfv9_logging_info->pkt_length +=
+ CNAT_NFV9_DATAFLOW_RECORD_HEADER_LENGTH;
+
+ /*
+ * Set the data pointer beyond the dataflow header field
+ */
+ nfv9_logging_info->next_data_ptr =
+ (u8 *) (nfv9_logging_info->dataflow_header + 1);
+
+}
+
+static void cnat_nfv9_insert_add_record(
+ cnat_nfv9_logging_info_t *nfv9_logging_info,
+ cnat_main_db_entry_t *db,
+ cnat_vrfmap_t *vrfmap)
+{
+ u16 my_proto_mask;
+ u8 my_protocol;
+ nfv9_add_record_t nfv9_logging_add_record;
+ if (PREDICT_FALSE(nfv9_logging_info->record[NAT44_ADD_RECORD] == NULL)) {
+ cnat_nfv9_record_create(nfv9_logging_info, NAT44_ADD_RECORD);
+ }
+
+ /*
+ * We should definitely have add_record now, no need to sanitize
+ */
+
+ nfv9_logging_add_record.inside_vrf_id =
+ clib_host_to_net_u32(vrfmap->i_vrf_id);
+
+ nfv9_logging_add_record.outside_vrf_id =
+ clib_host_to_net_u32(vrfmap->o_vrf_id);
+
+ nfv9_logging_add_record.inside_ip_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+ nfv9_logging_add_record.outside_ip_addr =
+ clib_host_to_net_u32(db->out2in_key.k.ipv4);
+
+ nfv9_logging_add_record.inside_ip_port =
+ clib_host_to_net_u16(db->in2out_key.k.port);
+ nfv9_logging_add_record.outside_ip_port =
+ clib_host_to_net_u16(db->out2in_key.k.port);
+
+ my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK;
+ my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT :
+ ((my_proto_mask == CNAT_TCP) ? TCP_PROT :
+ ((my_proto_mask == CNAT_ICMP) ? ICMP_PROT : GRE_PROT)));
+
+ nfv9_logging_add_record.protocol = my_protocol;
+
+ clib_memcpy(nfv9_logging_info->record[NAT44_ADD_RECORD],
+ &nfv9_logging_add_record, CNAT_NFV9_ADD_RECORD_LENGTH);
+
+ nfv9_logging_info->record_length[NAT44_ADD_RECORD]
+ += CNAT_NFV9_ADD_RECORD_LENGTH;
+
+ nfv9_logging_info->pkt_length += CNAT_NFV9_ADD_RECORD_LENGTH;
+
+ nfv9_logging_info->record[NAT44_ADD_RECORD]
+ += CNAT_NFV9_ADD_RECORD_LENGTH;
+ nfv9_logging_info->next_data_ptr =
+ nfv9_logging_info->record[NAT44_ADD_RECORD];
+
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u32(
+ nfv9_logging_info->record_length[NAT44_ADD_RECORD]);
+
+}
+
+
+static void cnat_nfv9_ds_lite_insert_add_record(
+ cnat_nfv9_logging_info_t *nfv9_logging_info,
+ cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry)
+{
+
+ nfv9_ds_lite_add_record_t nfv9_logging_add_record = {0};
+ cnat_user_db_entry_t *udb = NULL;
+ u16 my_proto_mask;
+ u8 my_protocol;
+
+ udb = cnat_user_db + db->user_index;
+ if (PREDICT_FALSE(!udb)) {
+ return;
+ }
+ if (PREDICT_FALSE(nfv9_logging_info->record[DS_LITE_ADD_RECORD] == NULL)) {
+ cnat_nfv9_record_create(nfv9_logging_info, DS_LITE_ADD_RECORD);
+ }
+ /*
+ * We should definitely have add_record now, no need to sanitize
+ */
+ nfv9_logging_add_record.inside_vrf_id =
+ clib_host_to_net_u32(dslite_entry->i_vrf_id);
+ nfv9_logging_add_record.outside_vrf_id =
+ clib_host_to_net_u32(dslite_entry->o_vrf_id);
+
+#ifdef DSLITE_USER_IPV4
+ nfv9_logging_add_record.inside_ip_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+#else
+ /*
+ * Inside ipv4 address is sent as 0.0.0.0 for ds-lite case as
+ * ipv6 is user here.
+ */
+ nfv9_logging_add_record.inside_ip_addr = 0;
+#endif
+
+ nfv9_logging_add_record.inside_v6_src_addr[0] =
+ clib_host_to_net_u32(udb->ipv6[0]);
+ nfv9_logging_add_record.inside_v6_src_addr[1] =
+ clib_host_to_net_u32(udb->ipv6[1]);
+ nfv9_logging_add_record.inside_v6_src_addr[2] =
+ clib_host_to_net_u32(udb->ipv6[2]);
+ nfv9_logging_add_record.inside_v6_src_addr[3] =
+ clib_host_to_net_u32(udb->ipv6[3]);
+
+ nfv9_logging_add_record.outside_ip_addr =
+ clib_host_to_net_u32(db->out2in_key.k.ipv4);
+
+ nfv9_logging_add_record.inside_ip_port =
+ clib_host_to_net_u16(db->in2out_key.k.port);
+ nfv9_logging_add_record.outside_ip_port =
+ clib_host_to_net_u16(db->out2in_key.k.port);
+
+ my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK;
+
+ my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT :
+ ((my_proto_mask == CNAT_TCP) ? TCP_PROT :
+ ((my_proto_mask == CNAT_ICMP) ? ICMP_PROT : 0)));
+ nfv9_logging_add_record.protocol = my_protocol;
+
+ clib_memcpy(nfv9_logging_info->record[DS_LITE_ADD_RECORD],
+ &nfv9_logging_add_record, CNAT_NFV9_DS_LITE_ADD_RECORD_LENGTH);
+
+ nfv9_logging_info->record_length[DS_LITE_ADD_RECORD]
+ += CNAT_NFV9_DS_LITE_ADD_RECORD_LENGTH;
+
+ nfv9_logging_info->pkt_length += CNAT_NFV9_DS_LITE_ADD_RECORD_LENGTH;
+ nfv9_logging_info->total_record_count += 1;
+
+ nfv9_logging_info->record[DS_LITE_ADD_RECORD]
+ += CNAT_NFV9_DS_LITE_ADD_RECORD_LENGTH;
+ nfv9_logging_info->next_data_ptr =
+ nfv9_logging_info->record[DS_LITE_ADD_RECORD];
+
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u32(
+ nfv9_logging_info->record_length[DS_LITE_ADD_RECORD]);
+}
+
+
+static void cnat_nfv9_ds_lite_insert_del_record(
+ cnat_nfv9_logging_info_t *nfv9_logging_info,
+ cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry)
+{
+
+ nfv9_ds_lite_del_record_t nfv9_logging_del_record = {0};
+ cnat_user_db_entry_t *udb = NULL;
+ u16 my_proto_mask;
+ u8 my_protocol;
+
+ udb = cnat_user_db + db->user_index;
+ if (PREDICT_FALSE(!udb)) {
+ return;
+ }
+ if (PREDICT_FALSE(nfv9_logging_info->record[DS_LITE_DEL_RECORD] == NULL)) {
+ cnat_nfv9_record_create(nfv9_logging_info, DS_LITE_DEL_RECORD);
+ }
+ /*
+ * We should definitely have a del record now.
+ * No need to sanitize
+ */
+ nfv9_logging_del_record.inside_vrf_id =
+ clib_host_to_net_u32(dslite_entry->i_vrf_id);
+
+#ifdef DSLITE_USER_IPV4
+ nfv9_logging_del_record.inside_ip_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+#else
+ /*
+ * Inside ipv4 address is sent as 0.0.0.0 for ds-lite case as
+ * ipv6 is user here.
+ */
+ nfv9_logging_del_record.inside_ip_addr = 0;
+#endif
+
+ nfv9_logging_del_record.inside_v6_src_addr[0] =
+ clib_host_to_net_u32(udb->ipv6[0]);
+ nfv9_logging_del_record.inside_v6_src_addr[1] =
+ clib_host_to_net_u32(udb->ipv6[1]);
+ nfv9_logging_del_record.inside_v6_src_addr[2] =
+ clib_host_to_net_u32(udb->ipv6[2]);
+ nfv9_logging_del_record.inside_v6_src_addr[3] =
+ clib_host_to_net_u32(udb->ipv6[3]);
+
+ nfv9_logging_del_record.inside_ip_port =
+ clib_host_to_net_u16(db->in2out_key.k.port);
+
+ my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK;
+
+ my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT :
+ ((my_proto_mask == CNAT_TCP) ? TCP_PROT :
+ ((my_proto_mask == CNAT_ICMP) ? ICMP_PROT : 0)));
+ nfv9_logging_del_record.protocol = my_protocol;
+
+ clib_memcpy(nfv9_logging_info->record[DS_LITE_DEL_RECORD],
+ &nfv9_logging_del_record, CNAT_NFV9_DS_LITE_DEL_RECORD_LENGTH);
+
+ nfv9_logging_info->record_length[DS_LITE_DEL_RECORD] +=
+ CNAT_NFV9_DS_LITE_DEL_RECORD_LENGTH;
+
+ nfv9_logging_info->pkt_length += CNAT_NFV9_DS_LITE_DEL_RECORD_LENGTH;
+ nfv9_logging_info->total_record_count += 1;
+
+ nfv9_logging_info->record[DS_LITE_DEL_RECORD]
+ += CNAT_NFV9_DS_LITE_DEL_RECORD_LENGTH;
+ nfv9_logging_info->next_data_ptr =
+ nfv9_logging_info->record[DS_LITE_DEL_RECORD];
+
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u32(
+ nfv9_logging_info->record_length[DS_LITE_DEL_RECORD]);
+}
+
+#ifndef NO_BULK_LOGGING
+static void cnat_nfv9_insert_bulk_add_record(
+ cnat_nfv9_logging_info_t *nfv9_logging_info,
+ cnat_main_db_entry_t *db,
+ cnat_vrfmap_t *vrfmap,
+ int bulk_alloc_start_port)
+{
+ nfv9_bulk_add_record_t nfv9_logging_bulk_add_record;
+ bulk_alloc_size_t bulk_size = BULKSIZE_FROM_VRFMAP(vrfmap);
+ if (PREDICT_FALSE(nfv9_logging_info->record[NAT44_BULK_ADD_RECORD] == NULL)) {
+ cnat_nfv9_record_create(nfv9_logging_info, NAT44_BULK_ADD_RECORD);
+ }
+
+ /*
+ * We should definitely have add_record now, no need to sanitize
+ */
+
+ nfv9_logging_bulk_add_record.inside_vrf_id =
+ clib_host_to_net_u32(vrfmap->i_vrf_id);
+ nfv9_logging_bulk_add_record.outside_vrf_id =
+ clib_host_to_net_u32(vrfmap->o_vrf_id);
+
+ nfv9_logging_bulk_add_record.inside_ip_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+ nfv9_logging_bulk_add_record.outside_ip_addr =
+ clib_host_to_net_u32(db->out2in_key.k.ipv4);
+
+ nfv9_logging_bulk_add_record.outside_ip_port_start =
+ clib_host_to_net_u16(bulk_alloc_start_port);
+ nfv9_logging_bulk_add_record.outside_ip_port_end =
+ clib_host_to_net_u16(bulk_alloc_start_port + bulk_size -1);
+
+ clib_memcpy(nfv9_logging_info->record[NAT44_BULK_ADD_RECORD],
+ &nfv9_logging_bulk_add_record, CNAT_NFV9_BULK_ADD_RECORD_LENGTH);
+
+ nfv9_logging_info->record_length[NAT44_BULK_ADD_RECORD]
+ += CNAT_NFV9_BULK_ADD_RECORD_LENGTH;
+
+ nfv9_logging_info->pkt_length += CNAT_NFV9_BULK_ADD_RECORD_LENGTH;
+
+ nfv9_logging_info->record[NAT44_BULK_ADD_RECORD]
+ += CNAT_NFV9_BULK_ADD_RECORD_LENGTH;
+ nfv9_logging_info->next_data_ptr =
+ nfv9_logging_info->record[NAT44_BULK_ADD_RECORD];
+
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u32(
+ nfv9_logging_info->record_length[NAT44_BULK_ADD_RECORD]);
+
+}
+
+
+static void cnat_nfv9_ds_lite_insert_bulk_add_record(
+ cnat_nfv9_logging_info_t *nfv9_logging_info,
+ cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry,
+ int bulk_alloc_start_port)
+{
+
+ nfv9_ds_lite_bulk_add_record_t nfv9_logging_bulk_add_record = {0};
+ cnat_user_db_entry_t *udb = NULL;
+ bulk_alloc_size_t bulk_size = BULKSIZE_FROM_VRFMAP(dslite_entry);
+
+ if (PREDICT_FALSE(nfv9_logging_info->record[DS_LITE_BULK_ADD_RECORD] == NULL)) {
+ cnat_nfv9_record_create(nfv9_logging_info, DS_LITE_BULK_ADD_RECORD);
+ }
+ udb = cnat_user_db + db->user_index;
+ if (PREDICT_FALSE(!udb)) {
+ return;
+ }
+ /*
+ * We should definitely have add_record now, no need to sanitize
+ */
+
+ nfv9_logging_bulk_add_record.inside_vrf_id =
+ clib_host_to_net_u32(dslite_entry->i_vrf_id);
+ nfv9_logging_bulk_add_record.outside_vrf_id =
+ clib_host_to_net_u32(dslite_entry->o_vrf_id);
+
+#ifdef DSLITE_USER_IPV4
+ nfv9_logging_bulk_add_record.inside_ip_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+#else
+ /*
+ * Inside ipv4 address is sent as 0.0.0.0 for ds-lite case as
+ * ipv6 is user here.
+ */
+ nfv9_logging_bulk_add_record.inside_ip_addr = 0;
+#endif
+
+ nfv9_logging_bulk_add_record.inside_v6_src_addr[0] =
+ clib_host_to_net_u32(udb->ipv6[0]);
+ nfv9_logging_bulk_add_record.inside_v6_src_addr[1] =
+ clib_host_to_net_u32(udb->ipv6[1]);
+ nfv9_logging_bulk_add_record.inside_v6_src_addr[2] =
+ clib_host_to_net_u32(udb->ipv6[2]);
+ nfv9_logging_bulk_add_record.inside_v6_src_addr[3] =
+ clib_host_to_net_u32(udb->ipv6[3]);
+
+ nfv9_logging_bulk_add_record.outside_ip_addr =
+ clib_host_to_net_u32(db->out2in_key.k.ipv4);
+
+ nfv9_logging_bulk_add_record.outside_ip_port_start =
+ clib_host_to_net_u16(bulk_alloc_start_port);
+ nfv9_logging_bulk_add_record.outside_ip_port_end =
+ clib_host_to_net_u16(bulk_alloc_start_port + bulk_size -1);
+
+ clib_memcpy(nfv9_logging_info->record[DS_LITE_BULK_ADD_RECORD],
+ &nfv9_logging_bulk_add_record, CNAT_NFV9_DS_LITE_BULK_ADD_RECORD_LENGTH);
+
+ nfv9_logging_info->record_length[DS_LITE_BULK_ADD_RECORD]
+ += CNAT_NFV9_DS_LITE_BULK_ADD_RECORD_LENGTH;
+
+ nfv9_logging_info->pkt_length += CNAT_NFV9_DS_LITE_BULK_ADD_RECORD_LENGTH;
+ nfv9_logging_info->total_record_count += 1;
+ nfv9_logging_info->record[DS_LITE_BULK_ADD_RECORD]
+ += CNAT_NFV9_DS_LITE_BULK_ADD_RECORD_LENGTH;
+ nfv9_logging_info->next_data_ptr =
+ nfv9_logging_info->record[DS_LITE_BULK_ADD_RECORD];
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u32(
+ nfv9_logging_info->record_length[DS_LITE_BULK_ADD_RECORD]);
+}
+
+
+static void cnat_nfv9_ds_lite_insert_bulk_del_record(
+ cnat_nfv9_logging_info_t *nfv9_logging_info,
+ cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry,
+ int bulk_alloc_start_port)
+{
+
+ nfv9_ds_lite_bulk_del_record_t nfv9_logging_bulk_del_record = {0};
+ cnat_user_db_entry_t *udb = NULL;
+
+ if (PREDICT_FALSE(nfv9_logging_info->record[DS_LITE_BULK_DEL_RECORD] == NULL)) {
+ cnat_nfv9_record_create(nfv9_logging_info, DS_LITE_BULK_DEL_RECORD);
+ }
+ udb = cnat_user_db + db->user_index;
+ if (PREDICT_FALSE(!udb)) {
+ return;
+ }
+ /*
+ * We should definitely have add_record now, no need to sanitize
+ */
+
+ nfv9_logging_bulk_del_record.inside_vrf_id =
+ clib_host_to_net_u32(dslite_entry->i_vrf_id);
+
+#ifdef DSLITE_USER_IPV4
+ nfv9_logging_bulk_del_record.inside_ip_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+#else
+ nfv9_logging_bulk_del_record.inside_ip_addr =
+ clib_host_to_net_u32(0);
+#endif
+
+ nfv9_logging_bulk_del_record.inside_v6_src_addr[0] =
+ clib_host_to_net_u32(udb->ipv6[0]);
+ nfv9_logging_bulk_del_record.inside_v6_src_addr[1] =
+ clib_host_to_net_u32(udb->ipv6[1]);
+ nfv9_logging_bulk_del_record.inside_v6_src_addr[2] =
+ clib_host_to_net_u32(udb->ipv6[2]);
+ nfv9_logging_bulk_del_record.inside_v6_src_addr[3] =
+ clib_host_to_net_u32(udb->ipv6[3]);
+
+ nfv9_logging_bulk_del_record.outside_ip_port_start =
+ clib_host_to_net_u16(bulk_alloc_start_port);
+
+ clib_memcpy(nfv9_logging_info->record[DS_LITE_BULK_DEL_RECORD],
+ &nfv9_logging_bulk_del_record,
+ CNAT_NFV9_DS_LITE_BULK_DEL_RECORD_LENGTH);
+ nfv9_logging_info->record_length[DS_LITE_BULK_DEL_RECORD] +=
+ CNAT_NFV9_DS_LITE_BULK_DEL_RECORD_LENGTH;
+ nfv9_logging_info->pkt_length +=
+ CNAT_NFV9_DS_LITE_BULK_DEL_RECORD_LENGTH;
+ nfv9_logging_info->total_record_count += 1;
+ nfv9_logging_info->record[DS_LITE_BULK_DEL_RECORD] +=
+ CNAT_NFV9_DS_LITE_BULK_DEL_RECORD_LENGTH;
+ nfv9_logging_info->next_data_ptr =
+ nfv9_logging_info->record[DS_LITE_BULK_DEL_RECORD];
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u32(
+ nfv9_logging_info->record_length[DS_LITE_BULK_DEL_RECORD]);
+}
+#endif /* #ifndef NO_BULK_LOGGING */
+
+static void cnat_nfv9_insert_del_record(
+ cnat_nfv9_logging_info_t *nfv9_logging_info,
+ cnat_main_db_entry_t *db,
+ cnat_vrfmap_t *vrfmap)
+{
+ u16 my_proto_mask;
+ u8 my_protocol;
+ nfv9_del_record_t nfv9_logging_del_record;
+
+ if (PREDICT_FALSE(nfv9_logging_info->record[NAT44_DEL_RECORD] == NULL)) {
+ cnat_nfv9_record_create(nfv9_logging_info, NAT44_DEL_RECORD);
+ }
+
+ /*
+ * We should definitely have add_record now, no need to sanitize
+ */
+
+ nfv9_logging_del_record.inside_vrf_id =
+ clib_host_to_net_u32(vrfmap->i_vrf_id);
+
+ nfv9_logging_del_record.inside_ip_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+
+ nfv9_logging_del_record.inside_ip_port =
+ clib_host_to_net_u16(db->in2out_key.k.port);
+
+ my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK;
+ my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT :
+ ((my_proto_mask == CNAT_TCP) ? TCP_PROT :
+ ((my_proto_mask == CNAT_ICMP) ? ICMP_PROT : GRE_PROT)));
+
+ nfv9_logging_del_record.protocol = my_protocol;
+
+ clib_memcpy(nfv9_logging_info->record[NAT44_DEL_RECORD],
+ &nfv9_logging_del_record, CNAT_NFV9_DEL_RECORD_LENGTH);
+
+ nfv9_logging_info->record_length[NAT44_DEL_RECORD]
+ += CNAT_NFV9_DEL_RECORD_LENGTH;
+
+ nfv9_logging_info->pkt_length += CNAT_NFV9_DEL_RECORD_LENGTH;
+
+ nfv9_logging_info->record[NAT44_DEL_RECORD]
+ += CNAT_NFV9_DEL_RECORD_LENGTH;
+ nfv9_logging_info->next_data_ptr =
+ nfv9_logging_info->record[NAT44_DEL_RECORD];
+
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u32(
+ nfv9_logging_info->record_length[NAT44_DEL_RECORD]);
+
+}
+
+#ifndef NO_BULK_LOGGING
+static void cnat_nfv9_insert_bulk_del_record(
+ cnat_nfv9_logging_info_t *nfv9_logging_info,
+ cnat_main_db_entry_t *db,
+ cnat_vrfmap_t *vrfmap,
+ int bulk_alloc_start_port)
+{
+ nfv9_bulk_del_record_t nfv9_logging_bulk_del_record;
+ if (PREDICT_FALSE(nfv9_logging_info->record[NAT44_BULK_DEL_RECORD] == NULL)) {
+ cnat_nfv9_record_create(nfv9_logging_info, NAT44_BULK_DEL_RECORD);
+ }
+
+ /*
+ * We should definitely have add_record now, no need to sanitize
+ */
+
+ nfv9_logging_bulk_del_record.inside_vrf_id =
+ clib_host_to_net_u32(vrfmap->i_vrf_id);
+
+ nfv9_logging_bulk_del_record.inside_ip_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+
+ nfv9_logging_bulk_del_record.outside_ip_port_start =
+ clib_host_to_net_u16(bulk_alloc_start_port);
+
+ clib_memcpy(nfv9_logging_info->record[NAT44_BULK_DEL_RECORD],
+ &nfv9_logging_bulk_del_record, CNAT_NFV9_BULK_DEL_RECORD_LENGTH);
+
+ nfv9_logging_info->record_length[NAT44_BULK_DEL_RECORD]
+ += CNAT_NFV9_BULK_DEL_RECORD_LENGTH;
+
+ nfv9_logging_info->pkt_length += CNAT_NFV9_BULK_DEL_RECORD_LENGTH;
+
+ nfv9_logging_info->record[NAT44_BULK_DEL_RECORD]
+ += CNAT_NFV9_BULK_DEL_RECORD_LENGTH;
+ nfv9_logging_info->next_data_ptr =
+ nfv9_logging_info->record[NAT44_BULK_DEL_RECORD];
+
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u32(
+ nfv9_logging_info->record_length[NAT44_BULK_DEL_RECORD]);
+
+}
+
+#endif /* #ifndef NO_BULK_LOGGING */
+/*
+ * edt: * * cnat_nfv9_log_mapping_create
+ *
+ * Tries to log a creation of mapping record
+ *
+ * Argument: cnat_main_db_entry_t *db
+ * Main DB entry being created
+ *
+ * Argument: cnat_vrfmap_t *vrfmap
+ * VRF Map for the Main DB entry being created
+ */
+void cnat_nfv9_log_mapping_create (cnat_main_db_entry_t *db,
+ cnat_vrfmap_t *vrfmap
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ )
+{
+ cnat_nfv9_logging_info_t *nfv9_logging_info = 0;
+ vlib_main_t * vm = vlib_get_main();
+
+ if (PREDICT_FALSE(vrfmap->nfv9_logging_index == EMPTY)) {
+
+ //vlib_cli_output(vm, "\n1. Log Mapping failed");
+ /*
+ * No logging configured, silently return
+ */
+ return;
+ }
+
+ if (cnat_nfv9_logging_info_pool == NULL) {
+ vlib_cli_output(vm, "%s: info_pool pointer is NULL !!!!\n", __func__);
+ return;
+ }
+ nfv9_logging_info =
+ cnat_nfv9_logging_info_pool + vrfmap->nfv9_logging_index;
+
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ cnat_nfv9_create_logging_context(nfv9_logging_info,
+ cnat_nfv9_template_add_default);
+
+ /*
+ * If still empty, return after increasing the count
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ //vlib_cli_output(vm, "\n2. Log Mapping failed");
+ return;
+ }
+
+ }
+
+#ifndef NO_BULK_LOGGING
+ if(bulk_alloc > 0) { /* new bulk alloc - use bulk add template */
+ cnat_nfv9_insert_bulk_add_record(nfv9_logging_info, db, vrfmap,
+ bulk_alloc);
+ } else if(bulk_alloc == CACHE_ALLOC_NO_LOG_REQUIRED)
+ return; /* No logging required.. bulk port usage */
+ else /* Individual logging .. fall back to old method */
+#endif
+ cnat_nfv9_insert_add_record(nfv9_logging_info, db, vrfmap);
+
+ nfv9_logging_info->total_record_count += 1;
+
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->pkt_length >
+ nfv9_logging_info->max_length_minus_max_record_size)) {
+ cnat_nfv9_send_pkt(nfv9_logging_info);
+ }
+}
+
+/*
+ * edt: * * cnat_nfv9_log_mapping_delete
+ *
+ * Tries to log a deletion of mapping record
+ *
+ * Argument: cnat_main_db_entry_t *db
+ * Main DB entry being deleted
+ *
+ * Argument: cnat_vrfmap_t *vrfmap
+ * VRF Map for the Main DB entry being deleted
+ */
+void cnat_nfv9_log_mapping_delete (cnat_main_db_entry_t * db,
+ cnat_vrfmap_t *vrfmap
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ )
+{
+ cnat_nfv9_logging_info_t *nfv9_logging_info = 0;
+
+ if (PREDICT_FALSE(vrfmap->nfv9_logging_index == EMPTY)) {
+ //vlib_cli_output(vm, "\n3. Log Mapping failed");
+ /*
+ * No logging configured, silently return
+ */
+ return;
+ }
+
+ nfv9_logging_info =
+ cnat_nfv9_logging_info_pool + vrfmap->nfv9_logging_index;
+
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ cnat_nfv9_create_logging_context(nfv9_logging_info,
+ cnat_nfv9_template_add_default);
+
+ /*
+ * If still empty, return after increasing the count
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ //vlib_cli_output(vm, "\n4. Log Mapping failed");
+ return;
+ }
+ }
+#ifndef NO_BULK_LOGGING
+ if(bulk_alloc > 0) { /* new bulk alloc - use bulk add template */
+ cnat_nfv9_insert_bulk_del_record(nfv9_logging_info, db, vrfmap,
+ bulk_alloc);
+ } else if(bulk_alloc == CACHE_ALLOC_NO_LOG_REQUIRED)
+ return; /* No logging required.. bulk port usage */
+ else /* Individual logging .. fall back to old method */
+#endif
+ cnat_nfv9_insert_del_record(nfv9_logging_info, db, vrfmap);
+
+ nfv9_logging_info->total_record_count += 1;
+
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->pkt_length >
+ nfv9_logging_info->max_length_minus_max_record_size)) {
+ cnat_nfv9_send_pkt(nfv9_logging_info);
+ }
+}
+
+
+/* NAT64 Related routines */
+
+/*
+ * edt: * * cnat_nfv9_bib_mapping_create
+ *
+ * Tries to log a creation of Bib mapping record
+ *
+ * Argument: nat64_bib_entry_t *db
+ * BIB DB entry being created
+ *
+ * Argument: nat64_table_entry_t *nat64_entry
+ * NAT64 Instance where this BIB belongs
+ */
+void cnat_nfv9_bib_mapping_create (nat64_bib_entry_t *db,
+ nat64_table_entry_t *nat64_entry)
+{
+ cnat_nfv9_logging_info_t *nfv9_logging_info = 0;
+ u16 my_proto_mask;
+ u8 my_protocol;
+ nfv9_nat64_add_bib_record_t nfv9_logging_add_record;
+
+ if (PREDICT_FALSE(nat64_entry->logging_index == EMPTY)) {
+ /*
+ * No logging configured, silently return
+ */
+ return;
+ }
+
+ nfv9_logging_info =
+ cnat_nfv9_logging_info_pool + nat64_entry->logging_index;
+
+
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ cnat_nfv9_create_logging_context(nfv9_logging_info,
+ cnat_nfv9_template_add_default);
+
+ /*
+ * If still empty, return after increasing the count
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ return;
+ }
+ }
+
+ if (PREDICT_FALSE(nfv9_logging_info->record[NAT64_ADD_BIB_RECORD] == NULL)){
+ cnat_nfv9_record_create(nfv9_logging_info,NAT64_ADD_BIB_RECORD);
+ }
+
+
+ nfv9_logging_add_record.inside_v6_src_addr[0] =
+ clib_host_to_net_u32(db->v6_in_key.ipv6[0]);
+ nfv9_logging_add_record.inside_v6_src_addr[1] =
+ clib_host_to_net_u32(db->v6_in_key.ipv6[1]);
+ nfv9_logging_add_record.inside_v6_src_addr[2] =
+ clib_host_to_net_u32(db->v6_in_key.ipv6[2]);
+ nfv9_logging_add_record.inside_v6_src_addr[3] =
+ clib_host_to_net_u32(db->v6_in_key.ipv6[3]);
+
+
+ nfv9_logging_add_record.outside_v4_src_addr =
+ clib_host_to_net_u32(db->v4_out_key.k.ipv4);
+
+ nfv9_logging_add_record.inside_src_port =
+ clib_host_to_net_u16(db->v6_in_key.port);
+ nfv9_logging_add_record.outside_src_port =
+ clib_host_to_net_u16(db->v4_out_key.k.port);
+
+ my_proto_mask = db->v6_in_key.vrf & CNAT_PRO_MASK;
+
+ my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT :
+ ((my_proto_mask == CNAT_TCP) ? TCP_PROT :
+ ((my_proto_mask == CNAT_ICMP) ? IPV6_PROTO_ICMPV6 : 0)));
+ nfv9_logging_add_record.protocol = my_protocol;
+
+
+ clib_memcpy(nfv9_logging_info->record[NAT64_ADD_BIB_RECORD],
+ &nfv9_logging_add_record, CNAT_NFV9_NAT64_ADD_BIB_RECORD_LENGTH);
+
+ nfv9_logging_info->record_length[NAT64_ADD_BIB_RECORD] +=
+ CNAT_NFV9_NAT64_ADD_BIB_RECORD_LENGTH;
+ nfv9_logging_info->pkt_length += CNAT_NFV9_NAT64_ADD_BIB_RECORD_LENGTH;
+ nfv9_logging_info->total_record_count += 1;
+
+ nfv9_logging_info->record[NAT64_ADD_BIB_RECORD]
+ += CNAT_NFV9_NAT64_ADD_BIB_RECORD_LENGTH;
+
+ nfv9_logging_info->next_data_ptr =
+ nfv9_logging_info->record[NAT64_ADD_BIB_RECORD];
+
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u32(
+ nfv9_logging_info->record_length[NAT64_ADD_BIB_RECORD]);
+
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->pkt_length >
+ nfv9_logging_info->max_length_minus_max_record_size)) {
+ cnat_nfv9_send_pkt(nfv9_logging_info);
+ }
+}
+
+
+/*
+ * edt: * * cnat_nfv9_session_mapping_create
+ *
+ * Tries to log a creation of Bib mapping record
+ *
+ * Argument: nat64_bib_entry_t *bdb
+ * BIB DB entry for the session that is created
+ *
+ * Argument: nat64_session_entry_t *sdb
+ * Session DB entry being created
+ *
+ * Argument: nat64_table_entry_t *nat64_entry
+ * NAT64 Instance where this BIB and Session belongs
+ */
+void cnat_nfv9_session_mapping_create (nat64_bib_entry_t *bdb,
+ nat64_session_entry_t *sdb,
+ nat64_table_entry_t *nat64_entry_ptr)
+{
+ cnat_nfv9_logging_info_t *nfv9_logging_info = 0;
+ u16 my_proto_mask;
+ u8 my_protocol;
+ u32 dest_v6[4];
+ nfv9_nat64_add_session_record_t nfv9_logging_add_record;
+ u8 *ipv6_addr_ptr;
+ u8 *ipv4_addr_ptr;
+
+
+ if (PREDICT_FALSE(nat64_entry_ptr->logging_index == EMPTY)) {
+ /*
+ * No logging configured, silently return
+ */
+ return;
+ }
+
+ nfv9_logging_info =
+ cnat_nfv9_logging_info_pool + nat64_entry_ptr->logging_index;
+
+
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ cnat_nfv9_create_logging_context(nfv9_logging_info,
+ cnat_nfv9_template_add_default);
+
+ /*
+ * If still empty, return after increasing the count
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)){
+ return;
+ }
+ }
+
+ if (PREDICT_FALSE(nfv9_logging_info->record[NAT64_ADD_SESSION_RECORD]
+ == NULL)){
+ cnat_nfv9_record_create(nfv9_logging_info, NAT64_ADD_SESSION_RECORD);
+ }
+
+
+ nfv9_logging_add_record.inside_v6_src_addr[0] =
+ clib_host_to_net_u32(bdb->v6_in_key.ipv6[0]);
+ nfv9_logging_add_record.inside_v6_src_addr[1] =
+ clib_host_to_net_u32(bdb->v6_in_key.ipv6[1]);
+ nfv9_logging_add_record.inside_v6_src_addr[2] =
+ clib_host_to_net_u32(bdb->v6_in_key.ipv6[2]);
+ nfv9_logging_add_record.inside_v6_src_addr[3] =
+ clib_host_to_net_u32(bdb->v6_in_key.ipv6[3]);
+
+
+ nfv9_logging_add_record.outside_v4_src_addr =
+ clib_host_to_net_u32(bdb->v4_out_key.k.ipv4);
+
+
+ nfv9_logging_add_record.outside_v4_dest_addr =
+ clib_host_to_net_u32(sdb->v4_dest_key.k.ipv4);
+
+ /* Need to create the V6 address using prefix */
+ dest_v6[0] = nat64_entry_ptr->v6_prefix[0];
+ dest_v6[1] = nat64_entry_ptr->v6_prefix[1];
+ dest_v6[2] = nat64_entry_ptr->v6_prefix[2];
+ dest_v6[3] = nat64_entry_ptr->v6_prefix[3];
+
+ ipv6_addr_ptr = (u8 *) (&(dest_v6[0]));
+ ipv4_addr_ptr = (u8 *) (&(sdb->v4_dest_key.k.ipv4));
+
+ *(ipv6_addr_ptr + nat64_entry_ptr->octet0_position) = *(ipv4_addr_ptr);
+ *(ipv6_addr_ptr + nat64_entry_ptr->octet1_position) = *(ipv4_addr_ptr + 1);
+ *(ipv6_addr_ptr + nat64_entry_ptr->octet2_position) = *(ipv4_addr_ptr + 2);
+ *(ipv6_addr_ptr + nat64_entry_ptr->octet3_position) = *(ipv4_addr_ptr + 3);
+
+ nfv9_logging_add_record.inside_v6_dest_addr[0] =
+ clib_host_to_net_u32(dest_v6[0]);
+ nfv9_logging_add_record.inside_v6_dest_addr[1] =
+ clib_host_to_net_u32(dest_v6[1]);
+ nfv9_logging_add_record.inside_v6_dest_addr[2] =
+ clib_host_to_net_u32(dest_v6[2]);
+ nfv9_logging_add_record.inside_v6_dest_addr[3] =
+ clib_host_to_net_u32(dest_v6[3]);
+
+ nfv9_logging_add_record.outside_v4_dest_addr =
+ clib_host_to_net_u32(sdb->v4_dest_key.k.ipv4);
+
+ nfv9_logging_add_record.inside_src_port =
+ clib_host_to_net_u16(bdb->v6_in_key.port);
+ nfv9_logging_add_record.outside_src_port =
+ clib_host_to_net_u16(bdb->v4_out_key.k.port);
+
+ nfv9_logging_add_record.dest_port =
+ clib_host_to_net_u16(sdb->v4_dest_key.k.port);
+
+
+ my_proto_mask = bdb->v6_in_key.vrf & CNAT_PRO_MASK;
+
+ my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT :
+ ((my_proto_mask == CNAT_TCP) ? TCP_PROT :
+ ((my_proto_mask == CNAT_ICMP) ? IPV6_PROTO_ICMPV6 : 0)));
+ nfv9_logging_add_record.protocol = my_protocol;
+
+
+ clib_memcpy(nfv9_logging_info->record[NAT64_ADD_SESSION_RECORD],
+ &nfv9_logging_add_record, CNAT_NFV9_NAT64_ADD_SESSION_RECORD_LENGTH);
+
+ nfv9_logging_info->record_length[NAT64_ADD_SESSION_RECORD] +=
+ CNAT_NFV9_NAT64_ADD_SESSION_RECORD_LENGTH;
+ nfv9_logging_info->pkt_length += CNAT_NFV9_NAT64_ADD_SESSION_RECORD_LENGTH;
+ nfv9_logging_info->total_record_count += 1;
+
+ nfv9_logging_info->record[NAT64_ADD_SESSION_RECORD]
+ += CNAT_NFV9_NAT64_ADD_SESSION_RECORD_LENGTH;
+
+ nfv9_logging_info->next_data_ptr =
+ nfv9_logging_info->record[NAT64_ADD_SESSION_RECORD];
+
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u32(
+ nfv9_logging_info->record_length[NAT64_ADD_SESSION_RECORD]);
+
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->pkt_length >
+ nfv9_logging_info->max_length_minus_max_record_size)) {
+ cnat_nfv9_send_pkt(nfv9_logging_info);
+ }
+}
+
+
+/*
+ * edt: * * cnat_nfv9_bib_mapping_delete
+ *
+ * Tries to log a deletion of Bib mapping record
+ *
+ * Argument: nat64_bib_entry_t *db
+ * BIB DB entry being created
+ *
+ * Argument: nat64_table_entry_t *nat64_entry
+ * NAT64 Instance where this BIB belongs
+ */
+void cnat_nfv9_bib_mapping_delete (nat64_bib_entry_t *db,
+ nat64_table_entry_t *nat64_entry)
+{
+ cnat_nfv9_logging_info_t *nfv9_logging_info = 0;
+ u16 my_proto_mask;
+ u8 my_protocol;
+ nfv9_nat64_del_bib_record_t nfv9_logging_del_record;
+ if (PREDICT_FALSE(nat64_entry->logging_index == EMPTY)) {
+ /*
+ * No logging configured, silently return
+ */
+ return;
+ }
+
+ nfv9_logging_info =
+ cnat_nfv9_logging_info_pool + nat64_entry->logging_index;
+
+
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ cnat_nfv9_create_logging_context(nfv9_logging_info,
+ cnat_nfv9_template_add_default);
+
+ /*
+ * If still empty, return after increasing the count
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)){
+ return;
+ }
+ }
+
+ if (PREDICT_FALSE(nfv9_logging_info->record[NAT64_DEL_BIB_RECORD] == NULL)){
+ cnat_nfv9_record_create(nfv9_logging_info,NAT64_DEL_BIB_RECORD);
+ }
+
+
+ nfv9_logging_del_record.inside_v6_src_addr[0] =
+ clib_host_to_net_u32(db->v6_in_key.ipv6[0]);
+ nfv9_logging_del_record.inside_v6_src_addr[1] =
+ clib_host_to_net_u32(db->v6_in_key.ipv6[1]);
+ nfv9_logging_del_record.inside_v6_src_addr[2] =
+ clib_host_to_net_u32(db->v6_in_key.ipv6[2]);
+ nfv9_logging_del_record.inside_v6_src_addr[3] =
+ clib_host_to_net_u32(db->v6_in_key.ipv6[3]);
+
+
+ nfv9_logging_del_record.inside_src_port =
+ clib_host_to_net_u16(db->v6_in_key.port);
+
+ my_proto_mask = db->v6_in_key.vrf & CNAT_PRO_MASK;
+
+ my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT :
+ ((my_proto_mask == CNAT_TCP) ? TCP_PROT :
+ ((my_proto_mask == CNAT_ICMP) ? IPV6_PROTO_ICMPV6 : 0)));
+ nfv9_logging_del_record.protocol = my_protocol;
+
+
+ clib_memcpy(nfv9_logging_info->record[NAT64_DEL_BIB_RECORD],
+ &nfv9_logging_del_record, CNAT_NFV9_NAT64_DEL_BIB_RECORD_LENGTH);
+
+ nfv9_logging_info->record_length[NAT64_DEL_BIB_RECORD] +=
+ CNAT_NFV9_NAT64_DEL_BIB_RECORD_LENGTH;
+ nfv9_logging_info->pkt_length += CNAT_NFV9_NAT64_DEL_BIB_RECORD_LENGTH;
+ nfv9_logging_info->total_record_count += 1;
+
+ nfv9_logging_info->record[NAT64_DEL_BIB_RECORD]
+ += CNAT_NFV9_NAT64_DEL_BIB_RECORD_LENGTH;
+
+ nfv9_logging_info->next_data_ptr =
+ nfv9_logging_info->record[NAT64_DEL_BIB_RECORD];
+
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u32(
+ nfv9_logging_info->record_length[NAT64_DEL_BIB_RECORD]);
+
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->pkt_length >
+ nfv9_logging_info->max_length_minus_max_record_size)) {
+ cnat_nfv9_send_pkt(nfv9_logging_info);
+ }
+}
+
+
+/*
+ * edt: * * cnat_nfv9_session_mapping_delete
+ *
+ * Tries to log a deletion of Bib mapping record
+ *
+ * Argument: nat64_bib_entry_t *bdb
+ * BIB DB entry for the session that is created
+ *
+ * Argument: nat64_session_entry_t *sdb
+ * Session DB entry being created
+ *
+ * Argument: nat64_table_entry_t *nat64_entry
+ * NAT64 Instance where this BIB and Session belongs
+ */
+void cnat_nfv9_session_mapping_delete (nat64_bib_entry_t *bdb,
+ nat64_session_entry_t *sdb,
+ nat64_table_entry_t *nat64_entry_ptr)
+{
+ cnat_nfv9_logging_info_t *nfv9_logging_info = 0;
+ u16 my_proto_mask;
+ u8 my_protocol;
+ u32 dest_v6[4];
+ nfv9_nat64_del_session_record_t nfv9_logging_del_record;
+ u8 *ipv6_addr_ptr;
+ u8 *ipv4_addr_ptr;
+
+ if (PREDICT_FALSE(nat64_entry_ptr->logging_index == EMPTY)) {
+ /*
+ * No logging configured, silently return
+ */
+ return;
+ }
+
+ nfv9_logging_info =
+ cnat_nfv9_logging_info_pool + nat64_entry_ptr->logging_index;
+
+
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ cnat_nfv9_create_logging_context(nfv9_logging_info,
+ cnat_nfv9_template_add_default);
+
+ /*
+ * If still empty, return after increasing the count
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)){
+ return;
+ }
+ }
+
+ if (PREDICT_FALSE(nfv9_logging_info->record[NAT64_DEL_SESSION_RECORD]
+ == NULL)){
+ cnat_nfv9_record_create(nfv9_logging_info, NAT64_DEL_SESSION_RECORD);
+ }
+
+
+ nfv9_logging_del_record.inside_v6_src_addr[0] =
+ clib_host_to_net_u32(bdb->v6_in_key.ipv6[0]);
+ nfv9_logging_del_record.inside_v6_src_addr[1] =
+ clib_host_to_net_u32(bdb->v6_in_key.ipv6[1]);
+ nfv9_logging_del_record.inside_v6_src_addr[2] =
+ clib_host_to_net_u32(bdb->v6_in_key.ipv6[2]);
+ nfv9_logging_del_record.inside_v6_src_addr[3] =
+ clib_host_to_net_u32(bdb->v6_in_key.ipv6[3]);
+
+ /* Need to create the V6 address using prefix */
+ dest_v6[0] = nat64_entry_ptr->v6_prefix[0];
+ dest_v6[1] = nat64_entry_ptr->v6_prefix[1];
+ dest_v6[2] = nat64_entry_ptr->v6_prefix[2];
+ dest_v6[3] = nat64_entry_ptr->v6_prefix[3];
+
+ ipv6_addr_ptr = (u8 *) (&(dest_v6[0]));
+ ipv4_addr_ptr = (u8 *) (&(sdb->v4_dest_key.k.ipv4));
+
+ *(ipv6_addr_ptr + nat64_entry_ptr->octet0_position) = *(ipv4_addr_ptr);
+ *(ipv6_addr_ptr + nat64_entry_ptr->octet1_position) = *(ipv4_addr_ptr + 1);
+ *(ipv6_addr_ptr + nat64_entry_ptr->octet2_position) = *(ipv4_addr_ptr + 2);
+ *(ipv6_addr_ptr + nat64_entry_ptr->octet3_position) = *(ipv4_addr_ptr + 3);
+
+ nfv9_logging_del_record.inside_v6_dest_addr[0] =
+ clib_host_to_net_u32(dest_v6[0]);
+ nfv9_logging_del_record.inside_v6_dest_addr[1] =
+ clib_host_to_net_u32(dest_v6[1]);
+ nfv9_logging_del_record.inside_v6_dest_addr[2] =
+ clib_host_to_net_u32(dest_v6[2]);
+ nfv9_logging_del_record.inside_v6_dest_addr[3] =
+ clib_host_to_net_u32(dest_v6[3]);
+
+ nfv9_logging_del_record.inside_src_port =
+ clib_host_to_net_u16(bdb->v6_in_key.port);
+
+ nfv9_logging_del_record.dest_port =
+ clib_host_to_net_u16(sdb->v4_dest_key.k.port);
+
+
+ my_proto_mask = bdb->v6_in_key.vrf & CNAT_PRO_MASK;
+
+ my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT :
+ ((my_proto_mask == CNAT_TCP) ? TCP_PROT :
+ ((my_proto_mask == CNAT_ICMP) ? IPV6_PROTO_ICMPV6 : 0)));
+ nfv9_logging_del_record.protocol = my_protocol;
+
+ clib_memcpy(nfv9_logging_info->record[NAT64_DEL_SESSION_RECORD],
+ &nfv9_logging_del_record, CNAT_NFV9_NAT64_DEL_SESSION_RECORD_LENGTH);
+
+ nfv9_logging_info->record_length[NAT64_DEL_SESSION_RECORD] +=
+ CNAT_NFV9_NAT64_DEL_SESSION_RECORD_LENGTH;
+ nfv9_logging_info->pkt_length += CNAT_NFV9_NAT64_DEL_SESSION_RECORD_LENGTH;
+ nfv9_logging_info->total_record_count += 1;
+
+ nfv9_logging_info->record[NAT64_DEL_SESSION_RECORD]
+ += CNAT_NFV9_NAT64_DEL_SESSION_RECORD_LENGTH;
+
+ nfv9_logging_info->next_data_ptr =
+ nfv9_logging_info->record[NAT64_DEL_SESSION_RECORD];
+
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u32(
+ nfv9_logging_info->record_length[NAT64_DEL_SESSION_RECORD]);
+
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->pkt_length >
+ nfv9_logging_info->max_length_minus_max_record_size)) {
+ cnat_nfv9_send_pkt(nfv9_logging_info);
+ }
+}
+
+/*
+ * edt: * * cnat_nfv9_nat44_log_session_create
+ *
+ * Tries to log a creation of mapping record (session based)
+ *
+ * Argument: cnat_main_db_entry_t *db
+ * Main DB entry being created
+ * Arugment: cnat_session_entry_t *sdb
+ * Session DB entry if the destination is not the first dest
+ * Argument: cnat_vrfmap_t *vrfmap
+ * VRF Map for the Main DB entry being created
+ */
+
+void cnat_nfv9_nat44_log_session_create(cnat_main_db_entry_t *db,
+ cnat_session_entry_t *sdb,
+ cnat_vrfmap_t *vrfmap)
+{
+ cnat_nfv9_logging_info_t *nfv9_logging_info = 0;
+ u16 my_proto_mask;
+ u8 my_protocol;
+ nfv9_add_session_record_t nfv9_logging_add_session_record;
+
+ if (PREDICT_FALSE(vrfmap->nfv9_logging_index == EMPTY)) {
+ //vlib_cli_output(vm,"\n1. Log Mapping failed");
+ /*
+ * No logging configured, silently return
+ */
+ return;
+ }
+
+ nfv9_logging_info =
+ cnat_nfv9_logging_info_pool + vrfmap->nfv9_logging_index;
+
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ cnat_nfv9_create_logging_context(nfv9_logging_info,
+ cnat_nfv9_template_add_default);
+
+ /*
+ * If still empty, return after increasing the count
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ //vlib_cli_output(vm,"\n2. Log Mapping failed");
+ return;
+ }
+ }
+
+ if(PREDICT_FALSE(nfv9_logging_info->record[
+ NAT44_ADD_SESSION_RECORD] == NULL)) {
+ cnat_nfv9_record_create(nfv9_logging_info, NAT44_ADD_SESSION_RECORD);
+ }
+
+ /*
+ * We should definitely have add_record now, no need to sanitize
+ */
+ nfv9_logging_add_session_record.inside_vrf_id =
+ clib_host_to_net_u32(vrfmap->i_vrf_id);
+ nfv9_logging_add_session_record.outside_vrf_id =
+ clib_host_to_net_u32(vrfmap->o_vrf_id);
+
+ nfv9_logging_add_session_record.inside_ip_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+ nfv9_logging_add_session_record.outside_ip_addr =
+ clib_host_to_net_u32(db->out2in_key.k.ipv4);
+
+ /* If sdb is null, it is assumed that logging is being done
+ * for the first destination which is held in the main db
+
+ * itself
+ */
+ if(PREDICT_TRUE(sdb == NULL)) {
+ nfv9_logging_add_session_record.dest_ip_addr =
+ clib_host_to_net_u32(db->dst_ipv4);
+ nfv9_logging_add_session_record.dest_port =
+ clib_host_to_net_u16(db->dst_port);
+ } else {
+ nfv9_logging_add_session_record.dest_ip_addr =
+ clib_host_to_net_u32(sdb->v4_dest_key.k.ipv4);
+ nfv9_logging_add_session_record.dest_port =
+ clib_host_to_net_u16(sdb->v4_dest_key.k.port);
+ }
+
+ nfv9_logging_add_session_record.inside_ip_port =
+ clib_host_to_net_u16(db->in2out_key.k.port);
+ nfv9_logging_add_session_record.outside_ip_port =
+ clib_host_to_net_u16(db->out2in_key.k.port);
+
+
+ my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK;
+
+ my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT :
+ ((my_proto_mask == CNAT_TCP) ? TCP_PROT :
+ ((my_proto_mask == CNAT_ICMP) ? ICMP_PROT : GRE_PROT)));
+ nfv9_logging_add_session_record.protocol = my_protocol;
+
+ clib_memcpy(nfv9_logging_info->record[NAT44_ADD_SESSION_RECORD],
+ &nfv9_logging_add_session_record,
+ CNAT_NFV9_NAT44_ADD_SESSION_RECORD_LENGTH);
+
+ nfv9_logging_info->record_length[NAT44_ADD_SESSION_RECORD]
+ += CNAT_NFV9_NAT44_ADD_SESSION_RECORD_LENGTH;
+ nfv9_logging_info->pkt_length += CNAT_NFV9_NAT44_ADD_SESSION_RECORD_LENGTH;
+ nfv9_logging_info->total_record_count += 1;
+
+
+ nfv9_logging_info->record[NAT44_ADD_SESSION_RECORD]
+ += CNAT_NFV9_NAT44_ADD_SESSION_RECORD_LENGTH;
+
+ nfv9_logging_info->next_data_ptr =
+ nfv9_logging_info->record[NAT44_ADD_SESSION_RECORD];
+
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u32(
+ nfv9_logging_info->record_length[NAT44_ADD_SESSION_RECORD]);
+
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->pkt_length >
+ nfv9_logging_info->max_length_minus_max_record_size)) {
+ cnat_nfv9_send_pkt(nfv9_logging_info);
+ }
+}
+
+/*
+ * edt: * * cnat_nfv9_nat44_log_session_delete
+ *
+ * Tries to log a deletion of mapping record (session based)
+ *
+ * Argument: cnat_main_db_entry_t *db
+ * Main DB entry being created
+ * Arugment: cnat_session_entry_t *sdb
+ * Session DB entry if the destination is not the first dest
+ * Argument: cnat_vrfmap_t *vrfmap
+ * VRF Map for the Main DB entry being deleted
+ */
+
+void cnat_nfv9_nat44_log_session_delete(cnat_main_db_entry_t *db,
+ cnat_session_entry_t *sdb,
+ cnat_vrfmap_t *vrfmap)
+{
+ cnat_nfv9_logging_info_t *nfv9_logging_info = 0;
+ u16 my_proto_mask;
+ u8 my_protocol;
+ nfv9_del_session_record_t nfv9_logging_del_session_record;
+
+ if (PREDICT_FALSE(vrfmap->nfv9_logging_index == EMPTY)) {
+ //vlib_cli_output(vm, "\n1. Log Mapping failed");
+ /*
+ * No logging configured, silently return
+ */
+ return;
+ }
+
+ nfv9_logging_info =
+ cnat_nfv9_logging_info_pool + vrfmap->nfv9_logging_index;
+
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ cnat_nfv9_create_logging_context(nfv9_logging_info,
+ cnat_nfv9_template_add_default);
+
+ /*
+ * If still empty, return after increasing the count
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ //vlib_cli_output(vm, "\n2. Log Mapping failed");
+ return;
+ }
+ }
+
+ if(PREDICT_FALSE(nfv9_logging_info->record[
+ NAT44_DEL_SESSION_RECORD] == NULL)) {
+ cnat_nfv9_record_create(nfv9_logging_info, NAT44_DEL_SESSION_RECORD);
+ }
+
+ /*
+ * We should definitely have add_record now, no need to sanitize
+ */
+ nfv9_logging_del_session_record.inside_vrf_id =
+ clib_host_to_net_u32(vrfmap->i_vrf_id);
+
+ nfv9_logging_del_session_record.inside_ip_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+
+ /* If sdb is null, it is assumed that logging is being done
+ * for the first destination which is held in the main db
+ * itself
+ */
+ if(PREDICT_TRUE(sdb == NULL)) {
+ nfv9_logging_del_session_record.dest_ip_addr =
+ clib_host_to_net_u32(db->dst_ipv4);
+ nfv9_logging_del_session_record.dest_port =
+ clib_host_to_net_u16(db->dst_port);
+ } else {
+ nfv9_logging_del_session_record.dest_ip_addr =
+ clib_host_to_net_u32(sdb->v4_dest_key.k.ipv4);
+ nfv9_logging_del_session_record.dest_port =
+ clib_host_to_net_u16(sdb->v4_dest_key.k.port);
+ }
+
+ nfv9_logging_del_session_record.inside_ip_port =
+ clib_host_to_net_u16(db->in2out_key.k.port);
+
+ my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK;
+ my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT :
+ ((my_proto_mask == CNAT_TCP) ? TCP_PROT :
+ ((my_proto_mask == CNAT_ICMP) ? ICMP_PROT : GRE_PROT)));
+
+ nfv9_logging_del_session_record.protocol = my_protocol;
+
+ clib_memcpy(nfv9_logging_info->record[NAT44_DEL_SESSION_RECORD],
+ &nfv9_logging_del_session_record,
+ CNAT_NFV9_NAT44_DEL_SESSION_RECORD_LENGTH);
+
+ nfv9_logging_info->record_length[NAT44_DEL_SESSION_RECORD]
+ += CNAT_NFV9_NAT44_DEL_SESSION_RECORD_LENGTH;
+ nfv9_logging_info->pkt_length += CNAT_NFV9_NAT44_DEL_SESSION_RECORD_LENGTH;
+ nfv9_logging_info->total_record_count += 1;
+
+ nfv9_logging_info->record[NAT44_DEL_SESSION_RECORD]
+ += CNAT_NFV9_NAT44_DEL_SESSION_RECORD_LENGTH;
+
+ nfv9_logging_info->next_data_ptr =
+ nfv9_logging_info->record[NAT44_DEL_SESSION_RECORD];
+
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u32(
+ nfv9_logging_info->record_length[NAT44_DEL_SESSION_RECORD]);
+
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->pkt_length >
+ nfv9_logging_info->max_length_minus_max_record_size)) {
+ cnat_nfv9_send_pkt(nfv9_logging_info);
+ }
+}
+
+/*
+ * DS-Lite APIs for netflow logging
+ */
+
+/*
+ * edt: * * cnat_nfv9_ds_lite_mapping_create
+ *
+ * Tries to log a creation of mapping record
+ *
+ * Argument: cnat_main_db_entry_t *db
+ * Main DB entry being created
+ *
+ * Argument: dslite_table_entry_t *dslite_entry
+ * ds-lite instance for the Main DB entry being created
+ */
+void cnat_nfv9_ds_lite_mapping_create(cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ )
+{
+
+ cnat_nfv9_logging_info_t *nfv9_logging_info = NULL;
+
+ if (PREDICT_FALSE(!(db && dslite_entry))) {
+ return;
+ }
+ if (PREDICT_FALSE(dslite_entry->nfv9_logging_index == EMPTY)) {
+ /*
+ * no logging configured, silently return
+ */
+ return;
+ }
+
+ nfv9_logging_info =
+ cnat_nfv9_logging_info_pool + dslite_entry->nfv9_logging_index;
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ cnat_nfv9_create_logging_context(nfv9_logging_info,
+ cnat_nfv9_template_add_default);
+ /*
+ * If still empty, return after increasing the count
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ return;
+ }
+ }
+#ifndef NO_BULK_LOGGING
+ if(bulk_alloc > 0) { /* new bulk alloc - use bulk add template */
+ cnat_nfv9_ds_lite_insert_bulk_add_record(nfv9_logging_info,
+ db, dslite_entry, bulk_alloc);
+ } else if(bulk_alloc == CACHE_ALLOC_NO_LOG_REQUIRED)
+ return; /* No logging required.. bulk port usage */
+ else /* Individual logging .. fall back to old method */
+#endif /*NO_BULK_LOGGING*/
+ cnat_nfv9_ds_lite_insert_add_record(nfv9_logging_info, db, dslite_entry);
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->pkt_length >
+ nfv9_logging_info->max_length_minus_max_record_size)) {
+ cnat_nfv9_send_pkt(nfv9_logging_info);
+ }
+}
+
+/*
+ * edt: * * cnat_nfv9_ds_lite_mapping_delete
+ *
+ * Tries to log a deletion of mapping record
+ *
+ * Argument: cnat_main_db_entry_t *db
+ * Main DB entry being deleted
+ *
+ * Argument: dslite_table_entry_t *dslite_entry
+ * ds-lite instance for the Main DB entry being deleted
+ */
+void cnat_nfv9_ds_lite_mapping_delete(cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ )
+{
+
+ cnat_nfv9_logging_info_t *nfv9_logging_info = NULL;
+ if (PREDICT_FALSE(!(db && dslite_entry))) {
+ return;
+ }
+ if (PREDICT_FALSE(dslite_entry->nfv9_logging_index == EMPTY)) {
+ /*
+ * No logging configured, silently return
+ */
+ return;
+ }
+ nfv9_logging_info =
+ cnat_nfv9_logging_info_pool + dslite_entry->nfv9_logging_index;
+
+
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ cnat_nfv9_create_logging_context(nfv9_logging_info,
+ cnat_nfv9_template_add_default);
+ /*
+ * If still empty, return after increasing the count
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ return;
+ }
+ }
+#ifndef NO_BULK_LOGGING
+ if(bulk_alloc > 0) { /* new bulk alloc - use bulk add template */
+ cnat_nfv9_ds_lite_insert_bulk_del_record(nfv9_logging_info,
+ db, dslite_entry, bulk_alloc);
+ } else if(bulk_alloc == CACHE_ALLOC_NO_LOG_REQUIRED)
+ return; /* No logging required.. bulk port usage */
+ else /* Individual logging .. fall back to old method */
+#endif /*NO_BULK_LOGGING*/
+ cnat_nfv9_ds_lite_insert_del_record(nfv9_logging_info, db, dslite_entry);
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->pkt_length >
+ nfv9_logging_info->max_length_minus_max_record_size)) {
+ cnat_nfv9_send_pkt(nfv9_logging_info);
+ }
+}
+
+/*
+ * edt: * * cnat_nfv9_dslite_log_session_create
+ *
+ * Tries to log a creation of mapping record (session based)
+ * Argument: cnat_main_db_entry_t *db
+ * Main DB entry being created
+ * Arugment: cnat_session_entry_t *sdb
+ * Session DB entry if the destination is not the first dest
+ * Argument: dslite_table_entry_t *dslite_entry,
+ * dslite table entry for dslite instance
+ */
+
+void cnat_nfv9_ds_lite_log_session_create(
+ cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry,
+ cnat_session_entry_t *sdb)
+{
+
+ nfv9_ds_lite_add_session_record_t nfv9_logging_add_record ;
+ cnat_user_db_entry_t *udb = NULL;
+ u16 my_proto_mask;
+ u8 my_protocol;
+ cnat_nfv9_logging_info_t *nfv9_logging_info = 0;
+
+ if (PREDICT_FALSE(dslite_entry->nfv9_logging_index == EMPTY)) {
+ /*
+ * no logging configured, silently return
+ */
+ return;
+ }
+
+ nfv9_logging_info =
+ cnat_nfv9_logging_info_pool + dslite_entry->nfv9_logging_index;
+ udb = cnat_user_db + db->user_index;
+
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ cnat_nfv9_create_logging_context(nfv9_logging_info,
+ cnat_nfv9_template_add_default);
+
+ /*
+ * If still empty, return after increasing the count
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ return;
+ }
+ }
+
+ udb = cnat_user_db + db->user_index;
+ if (PREDICT_FALSE(!udb)) {
+ return;
+ }
+ if (PREDICT_FALSE(nfv9_logging_info->record[DS_LITE_ADD_SESSION_RECORD] == NULL)) {
+ cnat_nfv9_record_create(nfv9_logging_info, DS_LITE_ADD_SESSION_RECORD);
+ }
+ /*
+ * We should definitely have add_record now, no need to sanitize
+ */
+ nfv9_logging_add_record.inside_vrf_id =
+ clib_host_to_net_u32(dslite_entry->i_vrf_id);
+ nfv9_logging_add_record.outside_vrf_id =
+ clib_host_to_net_u32(dslite_entry->o_vrf_id);
+
+ nfv9_logging_add_record.inside_ip_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+
+ nfv9_logging_add_record.inside_v6_src_addr[0] =
+ clib_host_to_net_u32(udb->ipv6[0]);
+ nfv9_logging_add_record.inside_v6_src_addr[1] =
+ clib_host_to_net_u32(udb->ipv6[1]);
+ nfv9_logging_add_record.inside_v6_src_addr[2] =
+ clib_host_to_net_u32(udb->ipv6[2]);
+ nfv9_logging_add_record.inside_v6_src_addr[3] =
+ clib_host_to_net_u32(udb->ipv6[3]);
+
+ nfv9_logging_add_record.outside_ip_addr =
+ clib_host_to_net_u32(db->out2in_key.k.ipv4);
+
+ nfv9_logging_add_record.inside_ip_port =
+ clib_host_to_net_u16(db->in2out_key.k.port);
+ nfv9_logging_add_record.outside_ip_port =
+ clib_host_to_net_u16(db->out2in_key.k.port);
+
+ /* If sdb is null, it is assumed that logging is being done
+ * for the first destination which is held in the main db
+
+ * itself
+ */
+ if(PREDICT_TRUE(sdb == NULL)) {
+ nfv9_logging_add_record.dest_ip_addr =
+ clib_host_to_net_u32(db->dst_ipv4);
+ nfv9_logging_add_record.dest_port =
+ clib_host_to_net_u16(db->dst_port);
+ } else {
+ nfv9_logging_add_record.dest_ip_addr =
+ clib_host_to_net_u32(sdb->v4_dest_key.k.ipv4);
+ nfv9_logging_add_record.dest_port =
+ clib_host_to_net_u16(sdb->v4_dest_key.k.port);
+ }
+
+
+ my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK;
+
+ my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT :
+ ((my_proto_mask == CNAT_TCP) ? TCP_PROT :
+ ((my_proto_mask == CNAT_ICMP) ? ICMP_PROT : 0)));
+ nfv9_logging_add_record.protocol = my_protocol;
+
+ clib_memcpy(nfv9_logging_info->record[DS_LITE_ADD_SESSION_RECORD],
+ &nfv9_logging_add_record, CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_LENGTH);
+
+ nfv9_logging_info->record_length[DS_LITE_ADD_SESSION_RECORD]
+ += CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_LENGTH;
+
+ nfv9_logging_info->pkt_length += CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_LENGTH;
+ nfv9_logging_info->total_record_count += 1;
+
+ nfv9_logging_info->record[DS_LITE_ADD_SESSION_RECORD]
+ += CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_LENGTH;
+ nfv9_logging_info->next_data_ptr =
+ nfv9_logging_info->record[DS_LITE_ADD_SESSION_RECORD];
+
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u32(
+ nfv9_logging_info->record_length[DS_LITE_ADD_SESSION_RECORD]);
+
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->pkt_length >
+ nfv9_logging_info->max_length_minus_max_record_size)) {
+ cnat_nfv9_send_pkt(nfv9_logging_info);
+ }
+
+}
+
+/*
+ * edt: * * cnat_nfv9_dslite_log_session_delete
+ *
+ * Tries to log a creation of mapping record (session based)
+ * Argument: cnat_main_db_entry_t *db
+ * Main DB entry being created
+ * Arugment: cnat_session_entry_t *sdb
+ * Session DB entry if the destination is not the first dest
+ * Argument: dslite_table_entry_t *dslite_entry,
+ * dslite table entry for dslite instance
+ */
+
+void cnat_nfv9_ds_lite_log_session_delete(
+ cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry,
+ cnat_session_entry_t *sdb)
+{
+
+ nfv9_ds_lite_del_session_record_t nfv9_logging_add_record = {0};
+ cnat_user_db_entry_t *udb = NULL;
+ u16 my_proto_mask;
+ u8 my_protocol;
+ cnat_nfv9_logging_info_t *nfv9_logging_info = NULL;
+
+ if (PREDICT_FALSE(dslite_entry->nfv9_logging_index == EMPTY)) {
+ /*
+ * no logging configured, silently return
+ */
+ return;
+ }
+
+ nfv9_logging_info =
+ cnat_nfv9_logging_info_pool + dslite_entry->nfv9_logging_index;
+ udb = cnat_user_db + db->user_index;
+
+ if (PREDICT_FALSE(!udb)) {
+ return;
+ }
+
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ cnat_nfv9_create_logging_context(nfv9_logging_info,
+ cnat_nfv9_template_add_default);
+
+ /*
+ * If still empty, return after increasing the count
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->current_logging_context == NULL)) {
+ return;
+ }
+ }
+
+ if (PREDICT_FALSE(nfv9_logging_info->record[DS_LITE_DEL_SESSION_RECORD] == NULL)) {
+ cnat_nfv9_record_create(nfv9_logging_info, DS_LITE_DEL_SESSION_RECORD);
+ }
+ /*
+ * We should definitely have add_record now, no need to sanitize
+ */
+ nfv9_logging_add_record.inside_vrf_id =
+ clib_host_to_net_u32(dslite_entry->i_vrf_id);
+
+ nfv9_logging_add_record.inside_ip_addr =
+ clib_host_to_net_u32(db->in2out_key.k.ipv4);
+
+ nfv9_logging_add_record.inside_v6_src_addr[0] =
+ clib_host_to_net_u32(udb->ipv6[0]);
+ nfv9_logging_add_record.inside_v6_src_addr[1] =
+ clib_host_to_net_u32(udb->ipv6[1]);
+ nfv9_logging_add_record.inside_v6_src_addr[2] =
+ clib_host_to_net_u32(udb->ipv6[2]);
+ nfv9_logging_add_record.inside_v6_src_addr[3] =
+ clib_host_to_net_u32(udb->ipv6[3]);
+
+ nfv9_logging_add_record.inside_ip_port =
+ clib_host_to_net_u16(db->in2out_key.k.port);
+
+ /* If sdb is null, it is assumed that logging is being done
+ * for the first destination which is held in the main db
+ * itself
+ */
+ if(PREDICT_TRUE(sdb == NULL)) {
+ nfv9_logging_add_record.dest_ip_addr =
+ clib_host_to_net_u32(db->dst_ipv4);
+ nfv9_logging_add_record.dest_port =
+ clib_host_to_net_u16(db->dst_port);
+ } else {
+ nfv9_logging_add_record.dest_ip_addr =
+ clib_host_to_net_u32(sdb->v4_dest_key.k.ipv4);
+ nfv9_logging_add_record.dest_port =
+ clib_host_to_net_u16(sdb->v4_dest_key.k.port);
+ }
+
+
+ my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK;
+
+ my_protocol = ((my_proto_mask == CNAT_UDP) ? UDP_PROT :
+ ((my_proto_mask == CNAT_TCP) ? TCP_PROT :
+ ((my_proto_mask == CNAT_ICMP) ? ICMP_PROT : 0)));
+ nfv9_logging_add_record.protocol = my_protocol;
+
+ clib_memcpy(nfv9_logging_info->record[DS_LITE_DEL_SESSION_RECORD],
+ &nfv9_logging_add_record, CNAT_NFV9_DS_LITE_DEL_SESSION_RECORD_LENGTH);
+
+ nfv9_logging_info->record_length[DS_LITE_DEL_SESSION_RECORD]
+ += CNAT_NFV9_DS_LITE_DEL_SESSION_RECORD_LENGTH;
+
+ nfv9_logging_info->pkt_length += CNAT_NFV9_DS_LITE_DEL_SESSION_RECORD_LENGTH;
+ nfv9_logging_info->total_record_count += 1;
+
+ nfv9_logging_info->record[DS_LITE_DEL_SESSION_RECORD]
+ += CNAT_NFV9_DS_LITE_DEL_SESSION_RECORD_LENGTH;
+ nfv9_logging_info->next_data_ptr =
+ nfv9_logging_info->record[DS_LITE_DEL_SESSION_RECORD];
+
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u32(
+ nfv9_logging_info->record_length[DS_LITE_DEL_SESSION_RECORD]);
+
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+ if (PREDICT_FALSE(nfv9_logging_info->pkt_length >
+ nfv9_logging_info->max_length_minus_max_record_size)) {
+ cnat_nfv9_send_pkt(nfv9_logging_info);
+ }
+
+}
+
+
+/*
+ * netflow logging API for ingress vrf_id to name mapping
+ */
+
+/*
+ * edt: * * handle_vrfid_name_mapping
+ * It will search for valid natflow entry in netflow pool,
+ * once found one, will send all vrfid name mapping info
+ * using that entry
+ */
+
+
+static inline __attribute__((unused))
+void handle_vrfid_name_mapping(void)
+{
+ cnat_nfv9_logging_info_t *nfv9_logging_info = NULL;
+
+ pool_foreach (nfv9_logging_info, cnat_nfv9_logging_info_pool, ({
+ if(PREDICT_FALSE(nfv9_logging_info == NULL)) {
+ continue;
+ }
+ nfv9_server_info_t *server = nfv9_server_info_pool +
+ nfv9_logging_info->server_index;
+ if(server->template_sent == TEMPLATE_SENT_TRUE) {
+ cnat_nfv9_ingress_vrfid_name_mapping_create(nfv9_logging_info);
+ server->template_sent = TEMPLATE_SENT_FALSE;
+ }
+ }));
+}
+
+/*
+ * edt: * * cnat_nfv9_ingress_vrfid_name_mapping_create
+ *
+ * Tries to log vrfid-name mapping record
+ * Argument: netflow pointer
+ */
+
+
+void cnat_nfv9_ingress_vrfid_name_mapping_create(
+ cnat_nfv9_logging_info_t *nfv9_logging_info)
+{
+ u16 index = 0;
+
+ for (index = 0; index < MAX_VRFID; index++) {
+ if(vrfid_name_map[index].ref_count == 0) {
+ continue;
+ }
+ if (PREDICT_FALSE(
+ nfv9_logging_info->current_logging_context == NULL)) {
+ cnat_nfv9_create_logging_context(nfv9_logging_info,
+ cnat_nfv9_template_add_default);
+ }
+ cnat_nfv9_insert_ingress_vrfid_name_record(
+ nfv9_logging_info,index);
+ if (PREDICT_FALSE(nfv9_logging_info->pkt_length >
+ nfv9_logging_info->max_length_minus_max_record_size) ||
+ PREDICT_FALSE(index == MAX_VRFID - 1)) {
+ if (PREDICT_TRUE(nfv9_logging_info->current_logging_context
+ != NULL)) {
+ cnat_nfv9_send_pkt(nfv9_logging_info);
+ }
+ }
+ }/*for()*/
+ return;
+}
+
+static void cnat_nfv9_insert_ingress_vrfid_name_record(
+ cnat_nfv9_logging_info_t *nfv9_logging_info, u16 index)
+{
+ nfv9_ingress_vrfid_name_record_t nfv9_ingress_vrfid_name_record = {0};
+
+ if (PREDICT_FALSE(
+ nfv9_logging_info->record[INGRESS_VRF_ID_NAME_RECORD] == NULL)) {
+ cnat_nfv9_record_create(nfv9_logging_info, INGRESS_VRF_ID_NAME_RECORD);
+ }
+ nfv9_ingress_vrfid_name_record.ingress_vrf_id =
+ clib_host_to_net_u32(vrfid_name_map[index].vrf_id);
+
+ clib_memcpy(nfv9_ingress_vrfid_name_record.ingress_vrf_name,
+ vrfid_name_map[index].vrf_name, NFV9_VRF_NAME_LEN);
+
+ clib_memcpy(nfv9_logging_info->record[INGRESS_VRF_ID_NAME_RECORD],
+ &nfv9_ingress_vrfid_name_record,
+ CNAT_NFV9_INGRESS_VRFID_NAME_RECORD_LENGTH);
+
+ nfv9_logging_info->record_length[INGRESS_VRF_ID_NAME_RECORD]
+ += CNAT_NFV9_INGRESS_VRFID_NAME_RECORD_LENGTH;
+
+ nfv9_logging_info->pkt_length +=
+ CNAT_NFV9_INGRESS_VRFID_NAME_RECORD_LENGTH;
+
+ nfv9_logging_info->total_record_count += 1;
+
+ nfv9_logging_info->record[INGRESS_VRF_ID_NAME_RECORD]
+ += CNAT_NFV9_INGRESS_VRFID_NAME_RECORD_LENGTH;
+
+ nfv9_logging_info->next_data_ptr =
+ nfv9_logging_info->record[INGRESS_VRF_ID_NAME_RECORD];
+
+ nfv9_logging_info->dataflow_header->dataflow_length =
+ clib_host_to_net_u32(
+ nfv9_logging_info->record_length[INGRESS_VRF_ID_NAME_RECORD]);
+ return;
+}
+/*
+ * edt: * * cnat_log_timer_handler
+ *
+ * Timer handler for sending any pending NFV9 record
+ *
+ * Argument: spp_timer_t * timer_p
+ * Timer handler structure
+ */
+void handle_pending_nfv9_pkts()
+{
+ vlib_node_t *output_node;
+ vlib_main_t * vm = vlib_get_main();
+ cnat_nfv9_logging_info_t *my_nfv9_logging_info = 0;
+ u32 current_timestamp = cnat_nfv9_get_sys_up_time_in_ms();
+ u32 current_unix_time_in_seconds = cnat_nfv9_get_unix_time_in_seconds();
+
+ output_node = vlib_get_node_by_name (vm, (u8 *) "ip4-lookup");
+
+ pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info_pool, ({
+ nfv9_server_info_t *server = nfv9_server_info_pool +
+ my_nfv9_logging_info->server_index;
+ if (my_nfv9_logging_info->queued_logging_context ||
+ (my_nfv9_logging_info->current_logging_context &&
+ (current_timestamp -
+ my_nfv9_logging_info->current_logging_context_timestamp)
+ > 1000)) {
+ /*
+ * If there is a current logging context and timestamp
+ * indicates it is pending for long, send it out
+ * Also if there is a queued context send it out as well
+ */
+ vlib_cli_output(vm, "\nNFV9_TIMER: queued %p, curr %p",
+ my_nfv9_logging_info->queued_logging_context,
+ my_nfv9_logging_info->current_logging_context);
+
+
+ cnat_nfv9_send_pkt_always_success(my_nfv9_logging_info,
+ output_node);
+ } else {
+ /*
+ * If the last_template_sent_time is too far back in time
+ * send the template even if there is no NFv9 records to send
+ */
+ if ((my_nfv9_logging_info->queued_logging_context == NULL) &&
+ (my_nfv9_logging_info->current_logging_context == NULL) &&
+ ((current_unix_time_in_seconds -
+ server->last_template_sent_time) >
+ server->timeout_rate)) {
+ cnat_nfv9_create_logging_context(my_nfv9_logging_info,
+ cnat_nfv9_template_add_always);
+ if (PREDICT_TRUE(my_nfv9_logging_info->current_logging_context
+ != NULL)) {
+ cnat_nfv9_send_pkt(my_nfv9_logging_info);
+ }
+ }
+ }
+ }));
+}
+
+/*
+ * Code to initialize NFV9 Template. This is done when a NFV9 is enabled
+ * It is done only once and later used when sending NFV9 template records.
+ */
+static void
+cnat_nfv9_template_init (void)
+{
+ cnat_nfv9_template_info.flowset_id =
+ clib_host_to_net_u16(CNAT_NFV9_TEMPLATE_FLOWSET_ID);
+ cnat_nfv9_template_info.length =
+ clib_host_to_net_u16(CNAT_NFV9_TEMPLATE_LENGTH -
+ CNAT_NFV9_OPTION_TEMPLATE_LENGTH);
+ /*
+ * Create the add Template
+ */
+ cnat_nfv9_template_info.add_template_id =
+ clib_host_to_net_u16(CNAT_NFV9_ADD_TEMPLATE_ID);
+ cnat_nfv9_template_info.add_field_count =
+ clib_host_to_net_u16(CNAT_NFV9_ADD_FIELD_COUNT);
+
+ cnat_nfv9_template_info.add_inside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.add_inside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_outside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.add_outside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_inside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.add_inside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_outside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.add_outside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_inside_ip_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.add_inside_ip_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_outside_ip_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.add_outside_ip_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_protocol_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE);
+ cnat_nfv9_template_info.add_protocol_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE);
+
+ /*
+ * Create the delete Template
+ */
+ cnat_nfv9_template_info.del_template_id =
+ clib_host_to_net_u16(CNAT_NFV9_DEL_TEMPLATE_ID);
+ cnat_nfv9_template_info.del_field_count =
+ clib_host_to_net_u16(CNAT_NFV9_DEL_FIELD_COUNT);
+
+ cnat_nfv9_template_info.del_inside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.del_inside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.del_inside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.del_inside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.del_inside_ip_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.del_inside_ip_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.del_protocol_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE);
+ cnat_nfv9_template_info.del_protocol_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE);
+
+
+ /* Create NAT64 BIB Add template */
+#if 0
+ cnat_nfv9_template_info.nat64_add_bib_template_id =
+ clib_host_to_net_u16(CNAT_NFV9_NAT64_ADD_BIB_TEMPLATE_ID);
+ cnat_nfv9_template_info.nat64_add_bib_field_count =
+ clib_host_to_net_u16(CNAT_NFV9_NAT64_ADD_BIB_FIELD_COUNT);
+
+
+ cnat_nfv9_template_info.nat64_add_bib_inside_ipv6_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_add_bib_inside_ipv6_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat64_add_bib_outside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_add_bib_outside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat64_add_bib_inside_ip_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_add_bib_inside_ip_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat64_add_bib_outside_ip_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_add_bib_outside_ip_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat64_add_bib_protocol_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_add_bib_protocol_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE);
+
+
+ /* NAT64 BIB Delete */
+ cnat_nfv9_template_info.nat64_del_bib_template_id =
+ clib_host_to_net_u16(CNAT_NFV9_NAT64_DEL_BIB_TEMPLATE_ID);
+ cnat_nfv9_template_info.nat64_del_bib_field_count =
+ clib_host_to_net_u16(CNAT_NFV9_NAT64_DEL_BIB_FIELD_COUNT);
+
+ cnat_nfv9_template_info.nat64_del_bib_inside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_del_bib_inside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat64_del_bib_inside_ip_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_del_bib_inside_ip_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat64_del_bib_protocol_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_del_bib_protocol_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE);
+
+
+ /* NAt64 SESSION ADD */
+
+ cnat_nfv9_template_info.nat64_add_session_template_id =
+ clib_host_to_net_u16(CNAT_NFV9_NAT64_ADD_SESSION_TEMPLATE_ID);
+ cnat_nfv9_template_info.nat64_add_session_field_count =
+ clib_host_to_net_u16(CNAT_NFV9_NAT64_ADD_SESSION_FIELD_COUNT);
+
+
+ cnat_nfv9_template_info.nat64_add_session_inside_ipv6_src_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_add_session_inside_ipv6_src_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat64_add_session_outside_ip_src_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_add_session_outside_ip_src_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE);
+
+
+ cnat_nfv9_template_info.nat64_add_session_inside_ipv6_dst_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_DST_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_add_session_inside_ipv6_dst_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_DST_ADDR_FIELD_SIZE);
+
+
+ cnat_nfv9_template_info.nat64_add_session_outside_ip_dst_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_DST_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_add_session_outside_ip_dst_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_DST_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat64_add_session_inside_ip_src_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_add_session_inside_ip_src_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE);
+
+
+ cnat_nfv9_template_info.nat64_add_session_outside_ip_src_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_add_session_outside_ip_src_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_SIZE);
+
+
+ cnat_nfv9_template_info.nat64_add_session_ip_dest_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_add_session_ip_dest_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat64_add_session_protocol_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_add_session_protocol_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE);
+
+
+
+ /* Session Delete */
+ cnat_nfv9_template_info.nat64_del_session_template_id =
+ clib_host_to_net_u16(CNAT_NFV9_NAT64_DEL_SESSION_TEMPLATE_ID);
+ cnat_nfv9_template_info.nat64_del_session_field_count =
+ clib_host_to_net_u16(CNAT_NFV9_NAT64_DEL_SESSION_FIELD_COUNT);
+
+ cnat_nfv9_template_info.nat64_del_session_inside_ip_src_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_del_session_inside_ip_src_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat64_del_session_inside_ip_dst_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_DST_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_del_session_inside_ip_dst_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_DST_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat64_del_session_inside_ip_src_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_del_session_inside_ip_src_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat64_del_session_inside_ip_dst_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_del_session_inside_ip_dst_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat64_del_session_protocol_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE);
+ cnat_nfv9_template_info.nat64_del_session_protocol_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE);
+#endif
+ /*
+ * Create the nat44 session add Template
+ */
+ cnat_nfv9_template_info.nat44_session_add_template_id =
+ clib_host_to_net_u16(CNAT_NFV9_NAT44_ADD_SESSION_TEMPLATE_ID);
+ cnat_nfv9_template_info.nat44_session_add_field_count =
+ clib_host_to_net_u16(CNAT_NFV9_NAT44_ADD_SESSION_FIELD_COUNT);
+
+ cnat_nfv9_template_info.nat44_session_add_inside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.nat44_session_add_inside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat44_session_add_outside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.nat44_session_add_outside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat44_session_add_inside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.nat44_session_add_inside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat44_session_add_outside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.nat44_session_add_outside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat44_session_add_inside_ip_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.nat44_session_add_inside_ip_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat44_session_add_outside_ip_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.nat44_session_add_outside_ip_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat44_session_add_dest_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.nat44_session_add_dest_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat44_session_add_dest_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.nat44_session_add_dest_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat44_session_add_protocol_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE);
+ cnat_nfv9_template_info.nat44_session_add_protocol_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE);
+
+ /*
+ * Create the nat44 session del Template
+ */
+ cnat_nfv9_template_info.nat44_session_del_template_id =
+ clib_host_to_net_u16(CNAT_NFV9_NAT44_DEL_SESSION_TEMPLATE_ID);
+ cnat_nfv9_template_info.nat44_session_del_field_count =
+ clib_host_to_net_u16(CNAT_NFV9_NAT44_DEL_SESSION_FIELD_COUNT);
+
+ cnat_nfv9_template_info.nat44_session_del_inside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.nat44_session_del_inside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat44_session_del_inside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.nat44_session_del_inside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat44_session_del_dest_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.nat44_session_del_dest_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat44_session_del_inside_ip_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.nat44_session_del_inside_ip_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat44_session_del_dest_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.nat44_session_del_dest_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.nat44_session_del_protocol_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE);
+ cnat_nfv9_template_info.nat44_session_del_protocol_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE);
+ /*
+ * Ds-lite add template
+ */
+#if 0
+ cnat_nfv9_template_info.add_dslite_template_id =
+ clib_host_to_net_u16(CNAT_NFV9_DS_LITE_ADD_TEMPLATE_ID);
+ cnat_nfv9_template_info.add_dslite_field_count =
+ clib_host_to_net_u16(CNAT_NFV9_DS_LITE_ADD_FIELD_COUNT);
+
+ cnat_nfv9_template_info.add_dslite_inside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_inside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_dslite_outside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_outside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_dslite_inside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_inside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_dslite_inside_ipv6_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_inside_ipv6_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_dslite_outside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_outside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_dslite_inside_ip_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_inside_ip_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_dslite_outside_ip_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_outside_ip_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_dslite_protocol_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_protocol_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE);
+
+ /*
+ * Ds-lite delete template
+ */
+ cnat_nfv9_template_info.del_dslite_template_id =
+ clib_host_to_net_u16(CNAT_NFV9_DS_LITE_DEL_TEMPLATE_ID);
+ cnat_nfv9_template_info.del_dslite_field_count =
+ clib_host_to_net_u16(CNAT_NFV9_DS_LITE_DEL_FIELD_COUNT);
+
+ cnat_nfv9_template_info.del_dslite_inside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.del_dslite_inside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.del_dslite_inside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.del_dslite_inside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.del_dslite_inside_ipv6_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.del_dslite_inside_ipv6_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.del_dslite_inside_ip_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.del_dslite_inside_ip_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.del_dslite_protocol_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE);
+ cnat_nfv9_template_info.del_dslite_protocol_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE);
+
+ /*
+ * Ds-lite session add template
+ */
+
+ cnat_nfv9_template_info.add_dslite_session_template_id =
+ clib_host_to_net_u16(CNAT_NFV9_DS_LITE_ADD_SESSION_TEMPLATE_ID);
+ cnat_nfv9_template_info.add_dslite_session_field_count =
+ clib_host_to_net_u16(CNAT_NFV9_DS_LITE_ADD_SESSION_FIELD_COUNT);
+
+ cnat_nfv9_template_info.add_dslite_session_inside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_session_inside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_dslite_session_outside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_session_outside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_dslite_session_inside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_session_inside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_dslite_session_inside_ipv6_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_session_inside_ipv6_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_dslite_session_outside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_session_outside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_dslite_session_inside_ip_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_session_inside_ip_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_dslite_session_outside_ip_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_session_outside_ip_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_dslite_session_dest_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_session_dest_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_dslite_session_dest_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_session_dest_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.add_dslite_session_protocol_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE);
+ cnat_nfv9_template_info.add_dslite_session_protocol_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE);
+
+ /*
+ * Ds-lite session delete template
+ */
+ cnat_nfv9_template_info.del_dslite_session_template_id =
+ clib_host_to_net_u16(CNAT_NFV9_DS_LITE_DEL_SESSION_TEMPLATE_ID);
+ cnat_nfv9_template_info.del_dslite_session_field_count =
+ clib_host_to_net_u16(CNAT_NFV9_DS_LITE_DEL_SESSION_FIELD_COUNT);
+
+ cnat_nfv9_template_info.del_dslite_session_inside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.del_dslite_session_inside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.del_dslite_session_inside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.del_dslite_session_inside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.del_dslite_session_inside_ipv6_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.del_dslite_session_inside_ipv6_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.del_dslite_session_inside_ip_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.del_dslite_session_inside_ip_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.del_dslite_session_dest_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.del_dslite_session_dest_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.del_dslite_session_dest_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_TYPE);
+ cnat_nfv9_template_info.del_dslite_session_dest_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_DST_PORT_FIELD_SIZE);
+
+ cnat_nfv9_template_info.del_dslite_session_protocol_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_TYPE);
+ cnat_nfv9_template_info.del_dslite_session_protocol_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_PROTOCOL_FIELD_SIZE);
+
+ /* Create add bulk template */
+ cnat_nfv9_template_info.bulk_add_template_id =
+ clib_host_to_net_u16(CNAT_NFV9_NAT44_BULK_ADD_TEMPLATE_ID);
+ cnat_nfv9_template_info.bulk_add_field_count =
+ clib_host_to_net_u16(CNAT_NFV9_NAT44_BULK_ADD_FIELD_COUNT);
+
+ cnat_nfv9_template_info.bulk_add_inside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_add_inside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.bulk_add_outside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_add_outside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.bulk_add_inside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_add_inside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.bulk_add_outside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_add_outside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.bulk_add_outside_start_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_add_outside_start_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_SIZE);
+
+ cnat_nfv9_template_info.bulk_add_outside_end_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_END_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_add_outside_end_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_END_FIELD_SIZE);
+
+ /*
+ * Create the bulk delete Template
+ */
+ cnat_nfv9_template_info.bulk_del_template_id =
+ clib_host_to_net_u16(CNAT_NFV9_NAT44_BULK_DEL_TEMPLATE_ID);
+ cnat_nfv9_template_info.bulk_del_field_count =
+ clib_host_to_net_u16(CNAT_NFV9_NAT44_BULK_DEL_FIELD_COUNT);
+
+ cnat_nfv9_template_info.bulk_del_inside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_del_inside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.bulk_del_inside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_del_inside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.bulk_del_outside_start_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_del_outside_start_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_SIZE);
+
+ /*
+ * Ds-lite bulk add template
+ */
+ cnat_nfv9_template_info.bulk_dslite_add_template_id =
+ clib_host_to_net_u16(CNAT_NFV9_DS_LITE_BULK_ADD_TEMPLATE_ID);
+ cnat_nfv9_template_info.bulk_dslite_add_field_count =
+ clib_host_to_net_u16(CNAT_NFV9_DS_LITE_BULK_ADD_FIELD_COUNT);
+
+ cnat_nfv9_template_info.bulk_dslite_add_inside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_dslite_add_inside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.bulk_dslite_add_outside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_dslite_add_outside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.bulk_dslite_add_inside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_dslite_add_inside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.bulk_dslite_add_inside_ipv6_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_dslite_add_inside_ipv6_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.bulk_dslite_add_outside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_dslite_add_outside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.bulk_dslite_add_outside_start_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_dslite_add_outside_start_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_SIZE);
+
+ cnat_nfv9_template_info.bulk_dslite_add_outside_end_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_END_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_dslite_add_outside_end_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_END_FIELD_SIZE);
+
+ /*
+ * Ds-lite bulk delete template
+ */
+
+ cnat_nfv9_template_info.bulk_dslite_del_template_id =
+ clib_host_to_net_u16(CNAT_NFV9_DS_LITE_BULK_DEL_TEMPLATE_ID);
+ cnat_nfv9_template_info.bulk_dslite_del_field_count =
+ clib_host_to_net_u16(CNAT_NFV9_DS_LITE_BULK_DEL_FIELD_COUNT);
+
+ cnat_nfv9_template_info.bulk_dslite_del_inside_vrf_id_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_dslite_del_inside_vrf_id_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE);
+
+ cnat_nfv9_template_info.bulk_dslite_del_inside_ip_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_dslite_del_inside_ip_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.bulk_dslite_del_inside_ipv6_addr_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_dslite_del_inside_ipv6_addr_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE);
+
+ cnat_nfv9_template_info.bulk_dslite_del_outside_start_port_field_type =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_TYPE);
+ cnat_nfv9_template_info.bulk_dslite_del_outside_start_port_field_size =
+ clib_host_to_net_u16(CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_SIZE);
+
+#endif /* NO_BULK_LOGGING */
+
+ /*
+ * Ingress vrfid - name mapping
+ */
+ CNAT_NFV9_OPTION_TEMPLATE.flowset_id =
+ clib_host_to_net_u16(CNAT_NFV9_OPTION_TEMPLATE_FLOWSET_ID);
+ CNAT_NFV9_OPTION_TEMPLATE.length =
+ clib_host_to_net_u16(CNAT_NFV9_OPTION_TEMPLATE_LENGTH);
+
+ CNAT_NFV9_OPTION_TEMPLATE.ingress_vrfid_name_map_template_id =
+ clib_host_to_net_u16(CNAT_NFV9_INGRESS_VRF_ID_NAME_TEMPLATE_ID);
+ /* currently no scope field supported */
+ CNAT_NFV9_OPTION_TEMPLATE.ingress_vrfid_name_map_scope_len = 0;
+ CNAT_NFV9_OPTION_TEMPLATE.ingress_vrfid_name_map_option_len =
+ clib_host_to_net_u16(CNAT_NFV9_INGRESS_VRF_ID_NAME_OPTION_LEN);
+ CNAT_NFV9_OPTION_TEMPLATE.ingress_vrfid_name_map_vrfid_option_type =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE);
+ CNAT_NFV9_OPTION_TEMPLATE.ingress_vrfid_name_map_vrfid_option_len =
+ clib_host_to_net_u16(CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE);
+ CNAT_NFV9_OPTION_TEMPLATE.ingress_vrfid_name_map_vrfname_option_type =
+ clib_host_to_net_u16(CNAT_NFV9_INGRESS_VRF_NAME_FIELD_TYPE);
+ CNAT_NFV9_OPTION_TEMPLATE.ingress_vrfid_name_map_vrfname_option_len =
+ clib_host_to_net_u16(CNAT_NFV9_INGRESS_VRF_NAME_FIELD_SIZE);
+
+ /*
+ * Set the padding (which was added to make the size of template
+ * multiple of 4) to zero
+ */
+ CNAT_NFV9_OPTION_TEMPLATE.padding1 = 0;
+}
+
+/*
+ * one time function
+ * has to be called at the init time
+ */
+void cnat_nfv9_logging_init()
+{
+ if (!cnat_nfv9_global_info.cnat_nfv9_init_done) {
+ cnat_nfv9_template_init();
+
+ /* Pre allocate for NFV9_SERVER_POOL_SIZE. Will be good
+ * enough for most deployments
+ */
+ pool_alloc(nfv9_server_info_pool, NFV9_SERVER_POOL_SIZE);
+ int i;
+ nfv9_server_info_t *server __attribute__((unused));
+ for(i = 0; i < NFV9_SERVER_POOL_SIZE; i++) {
+ pool_get(nfv9_server_info_pool, server);
+ }
+
+ for(i = 0; i < NFV9_SERVER_POOL_SIZE; i++) {
+ pool_put(nfv9_server_info_pool, nfv9_server_info_pool + i);
+ }
+
+ memset(&cnat_nfv9_global_info, 0 , sizeof(cnat_nfv9_global_info_t));
+ ASSERT(cnat_nfv9_global_info.cnat_nfv9_disp_node_index != (u16)~0);
+
+ cnat_nfv9_global_info.cnat_nfv9_global_collector_index = EMPTY;
+ cnat_nfv9_global_info.cnat_nfv9_init_done = 1;
+
+ /*
+ * src id is set to infra IPv4 address + octeon core number
+ */
+ nfv9_src_id = my_instance_number;
+ }
+}
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_logging.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_logging.h
new file mode 100644
index 00000000..7bd43ecf
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_logging.h
@@ -0,0 +1,1091 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_logging.h
+ *
+ * Copyright (c) 2009, 2012 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_LOGGING_H__
+#define __CNAT_LOGGING_H__
+
+#include <stdio.h>
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/vec.h>
+#include <vppinfra/bitmap.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/pool.h>
+#include <vppinfra/clib.h>
+
+#include "nat64_db.h"
+#include "cnat_log_common.h"
+#include "dslite_defs.h"
+
+#define NFV9_DEF_PATH_MTU 1500
+#define NFV9_VRF_NAME_LEN 12
+
+/* one time call at the beginning */
+void cnat_nfv9_logging_init();
+
+/*
+ * unconditional call
+ * will check logging config inside
+ */
+void cnat_nfv9_log_mapping_create(cnat_main_db_entry_t * db,
+ cnat_vrfmap_t *vrfmap
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ );
+
+void cnat_nfv9_nat44_log_session_create(cnat_main_db_entry_t * db,
+ cnat_session_entry_t * sdb,
+ cnat_vrfmap_t *vrfmap);
+
+void cnat_nfv9_nat44_log_session_delete(cnat_main_db_entry_t * db,
+ cnat_session_entry_t * sdb,
+ cnat_vrfmap_t *vrfmap);
+
+
+/*
+ * unconditional call
+ * will check logging config inside
+ */
+void cnat_nfv9_log_mapping_delete(cnat_main_db_entry_t * db,
+ cnat_vrfmap_t *vrfmap
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ );
+
+/* nat44 syslog APIs */
+void cnat_syslog_nat44_mapping_create(cnat_main_db_entry_t *db,
+ cnat_vrfmap_t *vrfmap, cnat_session_entry_t * sdb
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ );
+
+void cnat_syslog_nat44_mapping_delete(cnat_main_db_entry_t *db,
+ cnat_vrfmap_t *vrfmap, cnat_session_entry_t *sdb
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ );
+
+/*
+ * dslite
+ */
+void cnat_nfv9_ds_lite_mapping_create(cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ );
+
+void cnat_nfv9_ds_lite_mapping_delete(cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ );
+void cnat_nfv9_ds_lite_log_session_create(cnat_main_db_entry_t * db,
+ dslite_table_entry_t *dslite_entry,
+ cnat_session_entry_t * sdb);
+
+void cnat_nfv9_ds_lite_log_session_delete(cnat_main_db_entry_t * db,
+ dslite_table_entry_t *dslite_entry,
+ cnat_session_entry_t * sdb);
+
+/*
+ * nat64
+ */
+
+void cnat_nfv9_bib_mapping_create (nat64_bib_entry_t *db,
+ nat64_table_entry_t *nat64_entry);
+
+void cnat_nfv9_session_mapping_create (nat64_bib_entry_t *bdb,
+ nat64_session_entry_t *sdb,
+ nat64_table_entry_t *nat64_entry_ptr);
+
+void cnat_nfv9_bib_mapping_delete (nat64_bib_entry_t *db,
+ nat64_table_entry_t *nat64_entry);
+
+void cnat_nfv9_session_mapping_delete (nat64_bib_entry_t *bdb,
+ nat64_session_entry_t *sdb,
+ nat64_table_entry_t *nat64_entry_ptr);
+
+typedef enum {
+ RECORD_INVALID = 0,
+ NAT44_ADD_RECORD,
+ NAT44_DEL_RECORD,
+ NAT64_ADD_BIB_RECORD,
+ NAT64_DEL_BIB_RECORD,
+ NAT64_ADD_SESSION_RECORD,
+ NAT64_DEL_SESSION_RECORD,
+ DS_LITE_ADD_RECORD,
+ DS_LITE_DEL_RECORD,
+ NAT44_BULK_ADD_RECORD,
+ NAT44_BULK_DEL_RECORD,
+ DS_LITE_BULK_ADD_RECORD,
+ DS_LITE_BULK_DEL_RECORD,
+ INGRESS_VRF_ID_NAME_RECORD,
+ NAT44_ADD_SESSION_RECORD,
+ NAT44_DEL_SESSION_RECORD,
+ DS_LITE_ADD_SESSION_RECORD,
+ DS_LITE_DEL_SESSION_RECORD,
+ MAX_RECORDS
+} netflow_record;
+
+typedef enum {
+ TEMPLATE_SENT_FALSE = 0,
+ TEMPLATE_SENT_TRUE = 1
+} netflow_template_sent;
+
+#define cnat_nfv9_get_sys_up_time_in_ms cnat_get_sys_up_time_in_ms
+
+#define cnat_nfv9_get_unix_time_in_seconds cnat_get_unix_time_in_seconds
+
+#define cnat_nfv9_dump_time_change_logs cnat_dump_time_change_logs
+
+
+/*
+ * Netflow V9 Specific Defines and structures
+ */
+
+#define CNAT_NFV9_VERSION_NUMBER 9
+
+#define CNAT_NFV9_TEMPLATE_FLOWSET_ID 0
+#define CNAT_NFV9_OPTION_TEMPLATE_FLOWSET_ID 1
+
+#define CNAT_NFV9_ADD_FIELD_COUNT 7
+#define CNAT_NFV9_DEL_FIELD_COUNT 4
+#define CNAT_NFV9_DS_LITE_ADD_FIELD_COUNT 8
+#define CNAT_NFV9_DS_LITE_DEL_FIELD_COUNT 5
+#define CNAT_NFV9_NAT64_ADD_BIB_FIELD_COUNT 5
+#define CNAT_NFV9_NAT64_DEL_BIB_FIELD_COUNT 3
+#define CNAT_NFV9_NAT64_ADD_SESSION_FIELD_COUNT 8
+#define CNAT_NFV9_NAT64_DEL_SESSION_FIELD_COUNT 5
+#define CNAT_NFV9_NAT44_ADD_SESSION_FIELD_COUNT 9
+#define CNAT_NFV9_NAT44_DEL_SESSION_FIELD_COUNT 6
+#define CNAT_NFV9_DS_LITE_ADD_SESSION_FIELD_COUNT 10
+#define CNAT_NFV9_DS_LITE_DEL_SESSION_FIELD_COUNT 7
+
+#define CNAT_NFV9_ADD_TEMPLATE_ID 256
+#define CNAT_NFV9_DEL_TEMPLATE_ID 257
+#define CNAT_NFV9_NAT64_ADD_BIB_TEMPLATE_ID 258
+#define CNAT_NFV9_NAT64_DEL_BIB_TEMPLATE_ID 259
+#define CNAT_NFV9_NAT64_ADD_SESSION_TEMPLATE_ID 260
+#define CNAT_NFV9_NAT64_DEL_SESSION_TEMPLATE_ID 261
+#define CNAT_NFV9_INGRESS_VRF_ID_NAME_TEMPLATE_ID 262
+#define CNAT_NFV9_DS_LITE_ADD_TEMPLATE_ID 267
+#define CNAT_NFV9_DS_LITE_DEL_TEMPLATE_ID 268
+#define CNAT_NFV9_NAT44_ADD_SESSION_TEMPLATE_ID 271
+#define CNAT_NFV9_NAT44_DEL_SESSION_TEMPLATE_ID 272
+#define CNAT_NFV9_DS_LITE_ADD_SESSION_TEMPLATE_ID 273
+#define CNAT_NFV9_DS_LITE_DEL_SESSION_TEMPLATE_ID 274
+
+#ifndef NO_BULK_LOGGING
+#define CNAT_NFV9_NAT44_BULK_ADD_TEMPLATE_ID 265
+#define CNAT_NFV9_NAT44_BULK_DEL_TEMPLATE_ID 266
+#define CNAT_NFV9_DS_LITE_BULK_ADD_TEMPLATE_ID 269
+#define CNAT_NFV9_DS_LITE_BULK_DEL_TEMPLATE_ID 270
+
+#define CNAT_NFV9_NAT44_BULK_ADD_FIELD_COUNT 6
+#define CNAT_NFV9_NAT44_BULK_DEL_FIELD_COUNT 3
+#define CNAT_NFV9_DS_LITE_BULK_ADD_FIELD_COUNT 7
+#define CNAT_NFV9_DS_LITE_BULK_DEL_FIELD_COUNT 4
+
+#define CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_TYPE 361
+#define CNAT_NFV9_OUTSIDE_IP_PORT_START_FIELD_SIZE 2
+
+#define CNAT_NFV9_OUTSIDE_IP_PORT_END_FIELD_TYPE 362
+#define CNAT_NFV9_OUTSIDE_IP_PORT_END_FIELD_SIZE 2
+
+#endif /* #ifndef NO_BULK_LOGGING */
+
+#define CNAT_NFV9_INGRESS_VRF_NAME_FIELD_TYPE 236
+#define CNAT_NFV9_INGRESS_VRF_NAME_FIELD_SIZE 12
+/* 4 byte for vrf_id + 4 byte for vrf_name (option fields) */
+#define CNAT_NFV9_INGRESS_VRF_ID_NAME_OPTION_LEN 8
+extern u16 cnat_template_id[MAX_RECORDS];
+
+#define CNAT_NFV9_INSIDE_VRFID_FIELD_TYPE 234
+#define CNAT_NFV9_INSIDE_VRFID_FIELD_SIZE 4
+
+#define CNAT_NFV9_OUTSIDE_VRFID_FIELD_TYPE 235
+#define CNAT_NFV9_OUTSIDE_VRFID_FIELD_SIZE 4
+
+#define CNAT_NFV9_INSIDE_IP_ADDR_FIELD_TYPE 8
+#define CNAT_NFV9_INSIDE_IP_ADDR_FIELD_SIZE 4
+
+#define CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_TYPE 225
+#define CNAT_NFV9_OUTSIDE_IP_ADDR_FIELD_SIZE 4
+
+#define CNAT_NFV9_INSIDE_IP_PORT_FIELD_TYPE 7
+#define CNAT_NFV9_INSIDE_IP_PORT_FIELD_SIZE 2
+
+#define CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_TYPE 227
+#define CNAT_NFV9_OUTSIDE_IP_PORT_FIELD_SIZE 2
+
+#define CNAT_NFV9_PROTOCOL_FIELD_TYPE 4
+#define CNAT_NFV9_PROTOCOL_FIELD_SIZE 1
+
+/* IPv6 related info */
+
+#define CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_TYPE 27
+#define CNAT_NFV9_INSIDE_IPV6_SRC_ADDR_FIELD_SIZE 16
+
+#define CNAT_NFV9_INSIDE_IPV6_DST_ADDR_FIELD_TYPE 28
+#define CNAT_NFV9_INSIDE_IPV6_DST_ADDR_FIELD_SIZE 16
+
+#define CNAT_NFV9_OUTSIDE_IP_DST_ADDR_FIELD_TYPE 226
+#define CNAT_NFV9_OUTSIDE_IP_DST_ADDR_FIELD_SIZE 4
+
+#define CNAT_NFV9_INSIDE_DST_PORT_FIELD_TYPE 11
+#define CNAT_NFV9_INSIDE_DST_PORT_FIELD_SIZE 2
+
+#define CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_TYPE 12
+#define CNAT_NFV9_DESTINATION_IP_ADDR_FIELD_SIZE 4
+
+
+typedef struct {
+ u16 version;
+ u16 count;
+ u32 sys_up_time; /* time in ms since system was booted */
+ u32 timestamp; /* UNIX time in seconds since 1970 */
+ u32 sequence_num;
+ u32 source_id;
+} nfv9_header_t;
+
+/*
+ * Hardcoded - need to be fixed
+ */
+#define CNAT_NFV9_SOURCE_ID_VALUE 0x1234
+
+typedef struct {
+ u16 flowset_id;
+ u16 length;
+
+ u16 ingress_vrfid_name_map_template_id;
+ u16 ingress_vrfid_name_map_scope_len;
+ u16 ingress_vrfid_name_map_option_len;
+ u16 ingress_vrfid_name_map_vrfid_option_type;
+ u16 ingress_vrfid_name_map_vrfid_option_len;
+ u16 ingress_vrfid_name_map_vrfname_option_type;
+ u16 ingress_vrfid_name_map_vrfname_option_len;
+ /*
+ * Adding the padding so as to make the tempalate
+ * structure end on a 4 byte boundary
+ */
+ u16 padding1;
+
+} cnat_nfv9_option_template_t;
+
+/*
+ * The following structure defines the Netflow Template that
+ * will be exported to the Netflow Collector
+ */
+
+typedef struct {
+ u16 flowset_id;
+ u16 length;
+
+ u16 add_template_id;
+ u16 add_field_count;
+ u16 add_inside_vrf_id_field_type;
+ u16 add_inside_vrf_id_field_size;
+ u16 add_outside_vrf_id_field_type;
+ u16 add_outside_vrf_id_field_size;
+ u16 add_inside_ip_addr_field_type;
+ u16 add_inside_ip_addr_field_size;
+ u16 add_outside_ip_addr_field_type;
+ u16 add_outside_ip_addr_field_size;
+ u16 add_inside_ip_port_field_type;
+ u16 add_inside_ip_port_field_size;
+ u16 add_outside_ip_port_field_type;
+ u16 add_outside_ip_port_field_size;
+ u16 add_protocol_field_type;
+ u16 add_protocol_field_size;
+
+ u16 del_template_id;
+ u16 del_field_count;
+ u16 del_inside_vrf_id_field_type;
+ u16 del_inside_vrf_id_field_size;
+ u16 del_inside_ip_addr_field_type;
+ u16 del_inside_ip_addr_field_size;
+ u16 del_inside_ip_port_field_type;
+ u16 del_inside_ip_port_field_size;
+ u16 del_protocol_field_type;
+ u16 del_protocol_field_size;
+#if 0
+ /* NAT64 related info */
+ u16 nat64_add_bib_template_id;
+ u16 nat64_add_bib_field_count;
+ u16 nat64_add_bib_inside_ipv6_addr_field_type;
+ u16 nat64_add_bib_inside_ipv6_addr_field_size;
+ u16 nat64_add_bib_outside_ip_addr_field_type;
+ u16 nat64_add_bib_outside_ip_addr_field_size;
+ u16 nat64_add_bib_inside_ip_port_field_type;
+ u16 nat64_add_bib_inside_ip_port_field_size;
+ u16 nat64_add_bib_outside_ip_port_field_type;
+ u16 nat64_add_bib_outside_ip_port_field_size;
+ u16 nat64_add_bib_protocol_field_type;
+ u16 nat64_add_bib_protocol_field_size;
+
+ u16 nat64_del_bib_template_id;
+ u16 nat64_del_bib_field_count;
+ u16 nat64_del_bib_inside_ip_addr_field_type;
+ u16 nat64_del_bib_inside_ip_addr_field_size;
+ u16 nat64_del_bib_inside_ip_port_field_type;
+ u16 nat64_del_bib_inside_ip_port_field_size;
+ u16 nat64_del_bib_protocol_field_type;
+ u16 nat64_del_bib_protocol_field_size;
+
+
+ u16 nat64_add_session_template_id;
+ u16 nat64_add_session_field_count;
+ u16 nat64_add_session_inside_ipv6_src_addr_field_type;
+ u16 nat64_add_session_inside_ipv6_src_addr_field_size;
+ u16 nat64_add_session_outside_ip_src_addr_field_type;
+ u16 nat64_add_session_outside_ip_src_addr_field_size;
+ u16 nat64_add_session_inside_ipv6_dst_addr_field_type;
+ u16 nat64_add_session_inside_ipv6_dst_addr_field_size;
+ u16 nat64_add_session_outside_ip_dst_addr_field_type;
+ u16 nat64_add_session_outside_ip_dst_addr_field_size;
+ u16 nat64_add_session_inside_ip_src_port_field_type;
+ u16 nat64_add_session_inside_ip_src_port_field_size;
+ u16 nat64_add_session_outside_ip_src_port_field_type;
+ u16 nat64_add_session_outside_ip_src_port_field_size;
+ u16 nat64_add_session_ip_dest_port_field_type;
+ u16 nat64_add_session_ip_dest_port_field_size;
+ u16 nat64_add_session_protocol_field_type;
+ u16 nat64_add_session_protocol_field_size;
+
+ u16 nat64_del_session_template_id;
+ u16 nat64_del_session_field_count;
+ u16 nat64_del_session_inside_ip_src_addr_field_type;
+ u16 nat64_del_session_inside_ip_src_addr_field_size;
+ u16 nat64_del_session_inside_ip_dst_addr_field_type;
+ u16 nat64_del_session_inside_ip_dst_addr_field_size;
+ u16 nat64_del_session_inside_ip_src_port_field_type;
+ u16 nat64_del_session_inside_ip_src_port_field_size;
+ u16 nat64_del_session_inside_ip_dst_port_field_type;
+ u16 nat64_del_session_inside_ip_dst_port_field_size;
+ u16 nat64_del_session_protocol_field_type;
+ u16 nat64_del_session_protocol_field_size;
+
+ /*
+ * Ds-Lite specific info
+ */
+ u16 add_dslite_template_id;
+ u16 add_dslite_field_count;
+ u16 add_dslite_inside_vrf_id_field_type;
+ u16 add_dslite_inside_vrf_id_field_size;
+ u16 add_dslite_outside_vrf_id_field_type;
+ u16 add_dslite_outside_vrf_id_field_size;
+ u16 add_dslite_inside_ip_addr_field_type;
+ u16 add_dslite_inside_ip_addr_field_size;
+ u16 add_dslite_inside_ipv6_addr_field_type;
+ u16 add_dslite_inside_ipv6_addr_field_size;
+ u16 add_dslite_outside_ip_addr_field_type;
+ u16 add_dslite_outside_ip_addr_field_size;
+ u16 add_dslite_inside_ip_port_field_type;
+ u16 add_dslite_inside_ip_port_field_size;
+ u16 add_dslite_outside_ip_port_field_type;
+ u16 add_dslite_outside_ip_port_field_size;
+ u16 add_dslite_protocol_field_type;
+ u16 add_dslite_protocol_field_size;
+
+ u16 del_dslite_template_id;
+ u16 del_dslite_field_count;
+ u16 del_dslite_inside_vrf_id_field_type;
+ u16 del_dslite_inside_vrf_id_field_size;
+ u16 del_dslite_inside_ip_addr_field_type;
+ u16 del_dslite_inside_ip_addr_field_size;
+ u16 del_dslite_inside_ipv6_addr_field_type;
+ u16 del_dslite_inside_ipv6_addr_field_size;
+ u16 del_dslite_inside_ip_port_field_type;
+ u16 del_dslite_inside_ip_port_field_size;
+ u16 del_dslite_protocol_field_type;
+ u16 del_dslite_protocol_field_size;
+#endif
+
+//#ifndef NO_BULK_LOGGING /* commenting for time being */
+#if 0
+ u16 bulk_add_template_id;
+ u16 bulk_add_field_count;
+ u16 bulk_add_inside_vrf_id_field_type;
+ u16 bulk_add_inside_vrf_id_field_size;
+ u16 bulk_add_outside_vrf_id_field_type;
+ u16 bulk_add_outside_vrf_id_field_size;
+ u16 bulk_add_inside_ip_addr_field_type;
+ u16 bulk_add_inside_ip_addr_field_size;
+ u16 bulk_add_outside_ip_addr_field_type;
+ u16 bulk_add_outside_ip_addr_field_size;
+ u16 bulk_add_outside_start_port_field_type;
+ u16 bulk_add_outside_start_port_field_size;
+ u16 bulk_add_outside_end_port_field_type;
+ u16 bulk_add_outside_end_port_field_size;
+
+ u16 bulk_del_template_id;
+ u16 bulk_del_field_count;
+ u16 bulk_del_inside_vrf_id_field_type;
+ u16 bulk_del_inside_vrf_id_field_size;
+ u16 bulk_del_inside_ip_addr_field_type;
+ u16 bulk_del_inside_ip_addr_field_size;
+ u16 bulk_del_outside_start_port_field_type;
+ u16 bulk_del_outside_start_port_field_size;
+
+ /* ds-lite bulk logging create delete event */
+
+ u16 bulk_dslite_add_template_id;
+ u16 bulk_dslite_add_field_count;
+ u16 bulk_dslite_add_inside_vrf_id_field_type;
+ u16 bulk_dslite_add_inside_vrf_id_field_size;
+ u16 bulk_dslite_add_outside_vrf_id_field_type;
+ u16 bulk_dslite_add_outside_vrf_id_field_size;
+ u16 bulk_dslite_add_inside_ip_addr_field_type;
+ u16 bulk_dslite_add_inside_ip_addr_field_size;
+ u16 bulk_dslite_add_inside_ipv6_addr_field_type;
+ u16 bulk_dslite_add_inside_ipv6_addr_field_size;
+ u16 bulk_dslite_add_outside_ip_addr_field_type;
+ u16 bulk_dslite_add_outside_ip_addr_field_size;
+ u16 bulk_dslite_add_outside_start_port_field_type;
+ u16 bulk_dslite_add_outside_start_port_field_size;
+ u16 bulk_dslite_add_outside_end_port_field_type;
+ u16 bulk_dslite_add_outside_end_port_field_size;
+
+ u16 bulk_dslite_del_template_id;
+ u16 bulk_dslite_del_field_count;
+ u16 bulk_dslite_del_inside_vrf_id_field_type;
+ u16 bulk_dslite_del_inside_vrf_id_field_size;
+ u16 bulk_dslite_del_inside_ip_addr_field_type;
+ u16 bulk_dslite_del_inside_ip_addr_field_size;
+ u16 bulk_dslite_del_inside_ipv6_addr_field_type;
+ u16 bulk_dslite_del_inside_ipv6_addr_field_size;
+ u16 bulk_dslite_del_outside_start_port_field_type;
+ u16 bulk_dslite_del_outside_start_port_field_size;
+
+#endif /* NO_BULK_LOGGING */
+
+ u16 nat44_session_add_template_id;
+ u16 nat44_session_add_field_count;
+ u16 nat44_session_add_inside_vrf_id_field_type;
+ u16 nat44_session_add_inside_vrf_id_field_size;
+ u16 nat44_session_add_outside_vrf_id_field_type;
+ u16 nat44_session_add_outside_vrf_id_field_size;
+ u16 nat44_session_add_inside_ip_addr_field_type;
+ u16 nat44_session_add_inside_ip_addr_field_size;
+ u16 nat44_session_add_outside_ip_addr_field_type;
+ u16 nat44_session_add_outside_ip_addr_field_size;
+ u16 nat44_session_add_inside_ip_port_field_type;
+ u16 nat44_session_add_inside_ip_port_field_size;
+ u16 nat44_session_add_outside_ip_port_field_type;
+ u16 nat44_session_add_outside_ip_port_field_size;
+ u16 nat44_session_add_dest_ip_addr_field_type;
+ u16 nat44_session_add_dest_ip_addr_field_size;
+ u16 nat44_session_add_dest_port_field_type;
+ u16 nat44_session_add_dest_port_field_size;
+ u16 nat44_session_add_protocol_field_type;
+ u16 nat44_session_add_protocol_field_size;
+
+ u16 nat44_session_del_template_id;
+ u16 nat44_session_del_field_count;
+ u16 nat44_session_del_inside_vrf_id_field_type;
+ u16 nat44_session_del_inside_vrf_id_field_size;
+ u16 nat44_session_del_inside_ip_addr_field_type;
+ u16 nat44_session_del_inside_ip_addr_field_size;
+ u16 nat44_session_del_dest_ip_addr_field_type;
+ u16 nat44_session_del_dest_ip_addr_field_size;
+ u16 nat44_session_del_inside_ip_port_field_type;
+ u16 nat44_session_del_inside_ip_port_field_size;
+ u16 nat44_session_del_dest_port_field_type;
+ u16 nat44_session_del_dest_port_field_size;
+ u16 nat44_session_del_protocol_field_type;
+ u16 nat44_session_del_protocol_field_size;
+
+#if 0
+ u16 add_dslite_session_template_id;
+ u16 add_dslite_session_field_count;
+ u16 add_dslite_session_inside_vrf_id_field_type;
+ u16 add_dslite_session_inside_vrf_id_field_size;
+ u16 add_dslite_session_outside_vrf_id_field_type;
+ u16 add_dslite_session_outside_vrf_id_field_size;
+ u16 add_dslite_session_inside_ip_addr_field_type;
+ u16 add_dslite_session_inside_ip_addr_field_size;
+ u16 add_dslite_session_inside_ipv6_addr_field_type;
+ u16 add_dslite_session_inside_ipv6_addr_field_size;
+ u16 add_dslite_session_outside_ip_addr_field_type;
+ u16 add_dslite_session_outside_ip_addr_field_size;
+ u16 add_dslite_session_inside_ip_port_field_type;
+ u16 add_dslite_session_inside_ip_port_field_size;
+ u16 add_dslite_session_outside_ip_port_field_type;
+ u16 add_dslite_session_outside_ip_port_field_size;
+ u16 add_dslite_session_dest_ip_addr_field_type;
+ u16 add_dslite_session_dest_ip_addr_field_size;
+ u16 add_dslite_session_dest_port_field_type;
+ u16 add_dslite_session_dest_port_field_size;
+ u16 add_dslite_session_protocol_field_type;
+ u16 add_dslite_session_protocol_field_size;
+
+ u16 del_dslite_session_template_id;
+ u16 del_dslite_session_field_count;
+ u16 del_dslite_session_inside_vrf_id_field_type;
+ u16 del_dslite_session_inside_vrf_id_field_size;
+ u16 del_dslite_session_inside_ip_addr_field_type;
+ u16 del_dslite_session_inside_ip_addr_field_size;
+ u16 del_dslite_session_inside_ipv6_addr_field_type;
+ u16 del_dslite_session_inside_ipv6_addr_field_size;
+ u16 del_dslite_session_dest_ip_addr_field_type;
+ u16 del_dslite_session_dest_ip_addr_field_size;
+ u16 del_dslite_session_inside_ip_port_field_type;
+ u16 del_dslite_session_inside_ip_port_field_size;
+ u16 del_dslite_session_dest_port_field_type;
+ u16 del_dslite_session_dest_port_field_size;
+ u16 del_dslite_session_protocol_field_type;
+ u16 del_dslite_session_protocol_field_size;
+#endif
+
+ /*
+ * Netflow option template
+ * Ingress VRF ID - Name mapping
+ * This template will be sent under flowset id 1
+ */
+ cnat_nfv9_option_template_t cnat_nfv9_option_template;
+} cnat_nfv9_template_t;
+
+/*
+ * The Dataflow header for each add/delete record group
+ */
+typedef struct {
+ u16 dataflow_template_id;
+ u16 dataflow_length;
+} nfv9_dataflow_record_header_t;
+
+/*
+ * NFv9 Add record definition
+ */
+
+/*
+ * pad bytes needed to make the structure a multiple of 4 bytes
+ */
+#define CNAT_NFV9_ADD_RECORD_PAD_BYTES (3)
+#define CNAT_NFV9_DEL_RECORD_PAD_BYTES (1)
+
+#define CNAT_NFV9_NAT64_ADD_BIB_RECORD_PAD_BYTES (3)
+#define CNAT_NFV9_NAT64_DEL_BIB_RECORD_PAD_BYTES (1)
+#define CNAT_NFV9_NAT64_ADD_SESSION_RECORD_PAD_BYTES (1)
+#define CNAT_NFV9_NAT64_DEL_SESSION_RECORD_PAD_BYTES (3)
+#define CNAT_NFV9_NAT44_ADD_SESSION_RECORD_PAD_BYTES (1)
+#define CNAT_NFV9_NAT44_DEL_SESSION_RECORD_PAD_BYTES (3)
+
+#define CNAT_NFV9_DS_LITE_ADD_RECORD_PAD_BYTES (3)
+#define CNAT_NFV9_DS_LITE_DEL_RECORD_PAD_BYTES (1)
+#define CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_PAD_BYTES (1)
+#define CNAT_NFV9_DS_LITE_DEL_SESSION_RECORD_PAD_BYTES (3)
+
+#define CNAT_NFV9_INGRESS_VRFID_NAME_RECORD_PAD_BYTES (0)
+
+typedef struct {
+ u32 inside_vrf_id;
+ u32 outside_vrf_id;
+ u32 inside_ip_addr;
+ u32 outside_ip_addr;
+ u16 inside_ip_port;
+ u16 outside_ip_port;
+ u8 protocol;
+ u8 pad[CNAT_NFV9_ADD_RECORD_PAD_BYTES];
+} nfv9_add_record_t;
+
+/*
+ * NFv9 Delete record definition
+ */
+typedef struct {
+ u32 inside_vrf_id;
+ u32 inside_ip_addr;
+ u16 inside_ip_port;
+ u8 protocol;
+ u8 pad[CNAT_NFV9_DEL_RECORD_PAD_BYTES];
+} nfv9_del_record_t;
+
+#ifndef NO_BULK_LOGGING
+
+#define CNAT_NFV9_BULK_ADD_RECORD_PAD_BYTES (0)
+#define CNAT_NFV9_BULK_DEL_RECORD_PAD_BYTES (2)
+
+typedef struct {
+ u32 inside_vrf_id;
+ u32 outside_vrf_id;
+ u32 inside_ip_addr;
+ u32 outside_ip_addr;
+ u16 outside_ip_port_start;
+ u16 outside_ip_port_end;
+ u8 pad[CNAT_NFV9_BULK_ADD_RECORD_PAD_BYTES];
+} nfv9_bulk_add_record_t;
+
+/*
+ * NFv9 Delete record definition
+ */
+typedef struct {
+ u32 inside_vrf_id;
+ u32 inside_ip_addr;
+ u16 outside_ip_port_start;
+ u8 pad[CNAT_NFV9_BULK_DEL_RECORD_PAD_BYTES];
+} nfv9_bulk_del_record_t;
+
+/*
+ * DS-lite bulk port (user based) add record definition
+ */
+
+#define CNAT_NFV9_DS_LITE_BULK_ADD_RECORD_PAD_BYTES (0)
+#define CNAT_NFV9_DS_LITE_BULK_DEL_RECORD_PAD_BYTES (2)
+
+typedef struct {
+ u32 inside_vrf_id;
+ u32 outside_vrf_id;
+ u32 inside_ip_addr;
+ u32 inside_v6_src_addr[4];
+ u32 outside_ip_addr;
+ u16 outside_ip_port_start;
+ u16 outside_ip_port_end;
+ u8 pad[CNAT_NFV9_DS_LITE_BULK_ADD_RECORD_PAD_BYTES];
+} nfv9_ds_lite_bulk_add_record_t;
+
+
+/*
+ * DS-lite bulk port (user based) delete record definition
+ */
+
+typedef struct {
+ u32 inside_vrf_id;
+ u32 inside_ip_addr;
+ u32 inside_v6_src_addr[4];
+ u16 outside_ip_port_start;
+ u8 pad[CNAT_NFV9_DS_LITE_BULK_DEL_RECORD_PAD_BYTES];
+} nfv9_ds_lite_bulk_del_record_t;
+
+#endif /* NO_BULK_LOGGING */
+
+/* NAT64 related structures */
+
+typedef struct {
+ u32 inside_v6_src_addr[4];
+ u32 outside_v4_src_addr;
+ u16 inside_src_port;
+ u16 outside_src_port;
+ u8 protocol;
+ u8 pad[CNAT_NFV9_NAT64_ADD_BIB_RECORD_PAD_BYTES];
+} nfv9_nat64_add_bib_record_t;
+
+
+typedef struct {
+ u32 inside_v6_src_addr[4];
+ u32 outside_v4_src_addr;
+ u32 inside_v6_dest_addr[4];
+ u32 outside_v4_dest_addr;
+ u16 inside_src_port;
+ u16 outside_src_port;
+ u16 dest_port;
+ u8 protocol;
+ u8 pad[CNAT_NFV9_NAT64_ADD_SESSION_RECORD_PAD_BYTES];
+} nfv9_nat64_add_session_record_t;
+
+
+typedef struct {
+ u32 inside_v6_src_addr[4];
+ u16 inside_src_port;
+ u8 protocol;
+ u8 pad[CNAT_NFV9_NAT64_DEL_BIB_RECORD_PAD_BYTES];
+} nfv9_nat64_del_bib_record_t;
+
+
+typedef struct {
+ u32 inside_v6_src_addr[4];
+ u32 inside_v6_dest_addr[4];
+ u16 inside_src_port;
+ u16 dest_port;
+ u8 protocol;
+ u8 pad[CNAT_NFV9_NAT64_DEL_SESSION_RECORD_PAD_BYTES];
+} nfv9_nat64_del_session_record_t;
+
+/*
+ * NFv9 Session based Add record definition
+ */
+typedef struct {
+ u32 inside_vrf_id;
+ u32 outside_vrf_id;
+ u32 inside_ip_addr;
+ u32 outside_ip_addr;
+ u16 inside_ip_port;
+ u16 outside_ip_port;
+ u32 dest_ip_addr;
+ u16 dest_port;
+ u8 protocol;
+ u8 pad[CNAT_NFV9_NAT44_ADD_SESSION_RECORD_PAD_BYTES];
+} nfv9_add_session_record_t;
+
+/*
+ * NFv9 Session based del record definition
+ */
+typedef struct {
+ u32 inside_vrf_id;
+ u32 inside_ip_addr;
+ u32 dest_ip_addr;
+ u16 inside_ip_port;
+ u16 dest_port;
+ u8 protocol;
+ u8 pad[CNAT_NFV9_NAT44_DEL_SESSION_RECORD_PAD_BYTES];
+} nfv9_del_session_record_t;
+
+/*
+ * DS-lite NFv9 create record structure
+ */
+typedef struct {
+ u32 inside_vrf_id;
+ u32 outside_vrf_id;
+ u32 inside_ip_addr;
+ u32 inside_v6_src_addr[4];
+ u32 outside_ip_addr;
+ u16 inside_ip_port;
+ u16 outside_ip_port;
+ u8 protocol;
+ u8 pad[CNAT_NFV9_DS_LITE_ADD_RECORD_PAD_BYTES];
+} nfv9_ds_lite_add_record_t;
+
+typedef struct {
+ u32 inside_vrf_id;
+ u32 inside_ip_addr;
+ u32 inside_v6_src_addr[4];
+ u16 inside_ip_port;
+ u8 protocol;
+ u8 pad[CNAT_NFV9_DS_LITE_DEL_RECORD_PAD_BYTES];
+} nfv9_ds_lite_del_record_t;
+
+/*
+ * NFv9 Session based Add record definition
+ */
+typedef struct {
+ u32 inside_vrf_id;
+ u32 outside_vrf_id;
+ u32 inside_ip_addr;
+ u32 inside_v6_src_addr[4];
+ u32 outside_ip_addr;
+ u16 inside_ip_port;
+ u16 outside_ip_port;
+ u32 dest_ip_addr;
+ u16 dest_port;
+ u8 protocol;
+ u8 pad[CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_PAD_BYTES];
+} nfv9_ds_lite_add_session_record_t;
+
+/*
+ * NFv9 Session based del record definition
+ */
+typedef struct {
+ u32 inside_vrf_id;
+ u32 inside_ip_addr;
+ u32 inside_v6_src_addr[4];
+ u32 dest_ip_addr;
+ u16 inside_ip_port;
+ u16 dest_port;
+ u8 protocol;
+ u8 pad[CNAT_NFV9_DS_LITE_DEL_SESSION_RECORD_PAD_BYTES];
+} nfv9_ds_lite_del_session_record_t;
+
+
+typedef struct {
+ u32 ingress_vrf_id;
+ u8 ingress_vrf_name[NFV9_VRF_NAME_LEN];
+ u8 pad[CNAT_NFV9_INGRESS_VRFID_NAME_RECORD_PAD_BYTES];
+} nfv9_ingress_vrfid_name_record_t;
+
+#define CNAT_NFV9_TEMPLATE_OFFSET \
+ (CNAT_NFV9_HDR_OFFSET + sizeof(nfv9_header_t))
+
+#define CNAT_NFV9_TEMPLATE_LENGTH (sizeof(cnat_nfv9_template_t))
+#define CNAT_NFV9_OPTION_TEMPLATE_LENGTH (sizeof(cnat_nfv9_option_template_t))
+
+#define CNAT_NFV9_DATAFLOW_RECORD_HEADER_LENGTH \
+ (sizeof(nfv9_dataflow_record_header_t))
+
+/*
+ * No padding is needed for the add/delete records - reduce padding bytes
+ */
+
+#define CNAT_NFV9_ADD_RECORD_LENGTH (sizeof(nfv9_add_record_t) - \
+ CNAT_NFV9_ADD_RECORD_PAD_BYTES)
+
+#define CNAT_NFV9_DEL_RECORD_LENGTH (sizeof(nfv9_del_record_t) - \
+ CNAT_NFV9_DEL_RECORD_PAD_BYTES)
+
+#define CNAT_NFV9_DS_LITE_ADD_RECORD_LENGTH (sizeof(nfv9_ds_lite_add_record_t) - \
+ CNAT_NFV9_DS_LITE_ADD_RECORD_PAD_BYTES)
+#define CNAT_NFV9_DS_LITE_DEL_RECORD_LENGTH (sizeof(nfv9_ds_lite_del_record_t) - \
+ CNAT_NFV9_DS_LITE_DEL_RECORD_PAD_BYTES)
+#ifndef NO_BULK_LOGGING
+#define CNAT_NFV9_BULK_ADD_RECORD_LENGTH (sizeof(nfv9_bulk_add_record_t) - \
+ CNAT_NFV9_BULK_ADD_RECORD_PAD_BYTES)
+#define CNAT_NFV9_BULK_DEL_RECORD_LENGTH (sizeof(nfv9_bulk_del_record_t) - \
+ CNAT_NFV9_BULK_DEL_RECORD_PAD_BYTES)
+
+#define CNAT_NFV9_DS_LITE_BULK_ADD_RECORD_LENGTH (sizeof(nfv9_ds_lite_bulk_add_record_t) - \
+ CNAT_NFV9_DS_LITE_BULK_ADD_RECORD_PAD_BYTES)
+#define CNAT_NFV9_DS_LITE_BULK_DEL_RECORD_LENGTH (sizeof(nfv9_ds_lite_bulk_del_record_t) - \
+ CNAT_NFV9_DS_LITE_BULK_DEL_RECORD_PAD_BYTES)
+
+
+#endif /* NO_BULK_LOGGING */
+
+#define CNAT_NFV9_INGRESS_VRFID_NAME_RECORD_LENGTH (sizeof(nfv9_ingress_vrfid_name_record_t) - \
+ CNAT_NFV9_INGRESS_VRFID_NAME_RECORD_PAD_BYTES)
+
+#define CNAT_NFV9_NAT64_ADD_BIB_RECORD_LENGTH \
+ (sizeof(nfv9_nat64_add_bib_record_t) - \
+ CNAT_NFV9_NAT64_ADD_BIB_RECORD_PAD_BYTES)
+
+#define CNAT_NFV9_NAT64_DEL_BIB_RECORD_LENGTH \
+ (sizeof(nfv9_nat64_del_bib_record_t) - \
+ CNAT_NFV9_NAT64_DEL_BIB_RECORD_PAD_BYTES)
+
+#define CNAT_NFV9_NAT64_ADD_SESSION_RECORD_LENGTH \
+ (sizeof(nfv9_nat64_add_session_record_t) - \
+ CNAT_NFV9_NAT64_ADD_SESSION_RECORD_PAD_BYTES)
+
+#define CNAT_NFV9_NAT64_DEL_SESSION_RECORD_LENGTH \
+ (sizeof(nfv9_nat64_del_session_record_t) - \
+ CNAT_NFV9_NAT64_DEL_SESSION_RECORD_PAD_BYTES)
+
+#define CNAT_NFV9_MAX_SINGLE_RECORD_LENGTH \
+ (sizeof(nfv9_ds_lite_add_session_record_t) - \
+ CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_PAD_BYTES)
+
+#define CNAT_NFV9_NAT44_ADD_SESSION_RECORD_LENGTH \
+ (sizeof(nfv9_add_session_record_t) -\
+ CNAT_NFV9_NAT44_ADD_SESSION_RECORD_PAD_BYTES)
+
+#define CNAT_NFV9_NAT44_DEL_SESSION_RECORD_LENGTH \
+ (sizeof(nfv9_del_session_record_t) -\
+ CNAT_NFV9_NAT44_DEL_SESSION_RECORD_PAD_BYTES)
+
+#define CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_LENGTH \
+ (sizeof(nfv9_ds_lite_add_session_record_t) -\
+ CNAT_NFV9_DS_LITE_ADD_SESSION_RECORD_PAD_BYTES)
+
+#define CNAT_NFV9_DS_LITE_DEL_SESSION_RECORD_LENGTH \
+ (sizeof(nfv9_ds_lite_del_session_record_t) -\
+ CNAT_NFV9_DS_LITE_DEL_SESSION_RECORD_PAD_BYTES)
+
+/*
+ * Minimum value of the path MTU value
+ */
+#define CNAT_NFV9_MIN_RECORD_SIZE (60 + \
+ CNAT_NFV9_DATAFLOW_RECORD_HEADER_LENGTH + \
+ CNAT_NFV9_TEMPLATE_LENGTH + \
+ CNAT_NFV9_MAX_SINGLE_RECORD_LENGTH)
+
+/*
+ * Let us put the maximum length of the netflow data to be 1400
+ */
+#define CNAT_NFV9_MAX_PKT_LENGTH 1400
+
+/*
+ * Data structures and defines to store NFV9 specific info
+ */
+#define CNAT_NFV9_INVALID_LOGGING_INDEX 0xffffffff
+
+/*
+ * Padding value between ADD and DELETE records. This can be atmost 3 bytes
+ */
+#define NFV9_PAD_VALUE (3)
+
+typedef struct {
+ /* NFV9 server specific info
+ * For now, it will maintain only package sequence count.
+ * Later it will maintain server address, port, etc.
+ * Though it currently has server address and port, it is only for
+ * cross refernce
+ */
+ u32 ipv4_address; /* Destination IP address of the collector */
+ u16 port; /* Destination port number of the collector */
+ u16 refresh_rate; /* Refresh rate in packets after which template is sent */
+ u16 timeout_rate; /* Timeout rate in seconds after which template is sent */
+ u16 ref_count; /* Num of instances using this data */
+ u32 sequence_num; /* Sequence number of the logging packet */
+ /*
+ * Keep track of the time and packets since last template send
+ */
+ u32 last_template_sent_time;
+ u32 pkts_since_last_template;
+ u8 template_sent; /* used while sending vrfid-name mapping */
+
+} nfv9_server_info_t;
+
+/*
+ * This structure store the Netflow Logging information on per NFv9
+ * collector basis. This structure is allocated from a pool and index
+ * to this structure is stored VRF MAP structures
+ */
+typedef struct {
+ /*
+ * nat64_id will be 0 for nat44 config and i_vrf_id, i_vrf will be 0
+ * for nat64 config. Nat64_id will be used while nat64 collector is
+ * search and i_vrf* for nat44 collector
+ */
+ /* Similarly for ds_lite, ds_lite_id will be used and nat64_id,
+ * ivrf_id shall be set to 0
+ */
+ u32 i_vrf_id; /* Inside VRF ID corresponding to this collector */
+ u16 i_vrf; /* Inside VRF (uidb_index) corresponding to this collector */
+ u16 nat64_id; /* NAT64 instance for to this collector */
+ u16 ds_lite_id; /* DS Lite instance for this collector */
+
+ /*
+ * This field determines the maximum size of the Netflow V9 information
+ * that can be stored in a logging packet
+ */
+ u16 max_length_minus_max_record_size;
+
+ /*
+ * Indicates if the entry is already deleted
+ */
+ u16 deleted;
+
+ u16 pkt_length; /* Length of the currently NFv9 information */
+ u16 record_length[MAX_RECORDS]; /* Length of delete record */
+ u16 total_record_count; /* Total number of records including templates */
+
+ u8 logging_policy;
+
+ /*
+ * Keep track of the time and packets since last template send
+ */
+ u32 last_template_sent_time;
+ u32 pkts_since_last_template;
+
+ /* Server info */
+ u32 server_index;
+
+ /*
+ * current logging context
+ */
+ vlib_buffer_t *current_logging_context;
+
+ /*
+ * Timestamp in UNIX seconds corresponding to when the current
+ * logging packet was created
+ */
+ u32 current_logging_context_timestamp;
+
+ /*
+ * Queued logging context waiting to be sent to the l3 infra node
+ */
+ vlib_buffer_t *queued_logging_context;
+
+ /*
+ * Headers corresponding to various records in this
+ * current nfv9 logging context
+ */
+ nfv9_header_t *nfv9_header;
+ cnat_nfv9_template_t *nfv9_template_header;
+ nfv9_dataflow_record_header_t *dataflow_header;
+ u8 *record[MAX_RECORDS];
+ u8 *next_data_ptr;
+ u8 last_record;
+ u32 nfv9_logging_next_index;
+ u32 ip4_input_node_index;
+ vlib_frame_t *f;
+ u32 *to_next;
+} cnat_nfv9_logging_info_t;
+
+
+/*
+ * Global structure for CGN APP configuration
+ */
+typedef struct {
+ /*
+ * Global NFv9 Logging Collector Index
+ */
+ u32 cnat_nfv9_global_collector_index;
+
+ /*
+ * Node index corresponding to the infra L3 output node
+ * to which the nfv9 logging node will send the packet
+ */
+ u16 cnat_nfv9_disp_node_index;
+
+ /*
+ * Whether we have initialized the NFv9 information
+ */
+ u8 cnat_nfv9_init_done;
+} cnat_nfv9_global_info_t;
+
+typedef enum {
+ cnat_nfv9_template_add_default,
+ cnat_nfv9_template_add_always
+} cnat_nfv9_template_add_flag_t;
+
+extern cnat_nfv9_template_t cnat_nfv9_template_info;
+
+extern cnat_nfv9_logging_info_t cnat_default_nfv9_logging_info;
+extern cnat_nfv9_logging_info_t *cnat_nfv9_logging_info_pool;
+
+extern cnat_nfv9_global_info_t cnat_nfv9_global_info;
+extern nfv9_server_info_t *nfv9_server_info_pool;
+
+/* #define DEBUG_NF_SERVER_CONFIG 1 */
+static inline void nfv9_delete_server_info(cnat_nfv9_logging_info_t *nfv9_info)
+{
+ nfv9_server_info_t *server = nfv9_server_info_pool +
+ nfv9_info->server_index;
+ if(nfv9_info->server_index == EMPTY) {
+#ifdef DEBUG_NF_SERVER_CONFIG
+ if(my_instance_number == 1) {
+ PLATFORM_DEBUG_PRINT("Deleting empty server info\n");
+ }
+#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
+ return;
+ }
+
+ /* Check if this server is not used by anyone.. if not delete */
+ /* Caller of this function does not need it..so decrement ref count */
+ server->ref_count--;
+ if(!(server->ref_count)) {
+#ifdef DEBUG_NF_SERVER_CONFIG
+ if(my_instance_number == 1) {
+ PLATFORM_DEBUG_PRINT("Deleting nfv9 server %x, %d at %d\n",
+ server->ipv4_address,
+ server->port,
+ nfv9_info->server_index);
+ }
+#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
+ pool_put(nfv9_server_info_pool, server);
+ nfv9_info->server_index = EMPTY;
+ }
+#ifdef DEBUG_NF_SERVER_CONFIG
+ else {
+ if(my_instance_number == 1) {
+ PLATFORM_DEBUG_PRINT("Not Deleting nfv9 server %x, %d rc %d\n",
+ server->ipv4_address,
+ server->port,
+ server->ref_count);
+ }
+ }
+#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
+ return;
+}
+
+void handle_pending_nfv9_pkts();
+#endif /* __CNAT_LOGGING_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_pcp_server.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_pcp_server.h
new file mode 100644
index 00000000..c77c6a87
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_pcp_server.h
@@ -0,0 +1,398 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_pcp_server.h
+ *
+ * Copyright (c) 2009-2012 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_PCP_SERVER_H__
+#define __CNAT_PCP_SERVER_H__
+
+#include "dslite_defs.h"
+
+/* Debug utils of PCP */
+#define PCP_DBG(debug, ...) \
+ if(PREDICT_FALSE(cnat_pcp_debug_flag >= debug)) { \
+ printf("%s:%s:%d - ", \
+ __FILE__, __FUNCTION__, __LINE__);\
+ printf(__VA_ARGS__);\
+ printf("\n"); \
+ }
+
+#define PCP_DUMP_PDATA \
+ if(PREDICT_FALSE(cnat_pcp_debug_flag >= 100)) { \
+ printf("%s:%s:%d - \n", \
+ __FILE__, __FUNCTION__, __LINE__);\
+ printf("src - ip = %X, proto = %d, port = %d i_vrf = %d, o_vrf = %d\n", \
+ pcp_data.src_ip[3], pcp_data.proto, pcp_data.src_port, pcp_data.i_vrf, pcp_data.o_vrf); \
+ printf(" third party ip = %X\n", pcp_data.third_party_ip[3]); \
+ printf("map - ip = %X, port = %d \n", \
+ pcp_data.ext_ip[3], pcp_data.ext_port);\
+ printf("remote - ip = %X, port = %d \n", \
+ pcp_data.peer_ip[3], pcp_data.peer_port); \
+ printf("req life time = %d \n", pcp_data.req_lifetime); \
+ printf("drop = %d \n", pcp_data.drop);\
+ printf("udp_len = %d \n", pcp_data.udp_len); \
+ printf("pm = %p \n", pcp_data.pm); \
+ printf("cnat_proto = %X \n", pcp_data.cnat_proto); \
+ printf("inst_id = %X \n", pcp_data.inst_id); \
+ printf("======================================================\n"); \
+ }
+
+#define PCP_DUMP_PACKET(ip, len) pcp_hex_dump(ip, len)
+
+#ifdef TOBE_PORTED
+#define PCP_INCR(counter) pcp_counters.pcp_##counter++ ;
+#else
+#define PCP_INCR(counter)
+#endif
+
+typedef struct pcp_debug_counters {
+ u64 pcp_input;
+ u64 pcp_output;
+ u64 pcp_service_nat44;
+ u64 pcp_service_dslite;
+ /* below all are drops */
+ u64 pcp_drops;
+ u64 pcp_i2o_key_inuse;
+ u64 pcp_throttle_drops;
+ u64 pcp_udp_len;
+ u64 pcp_nrequest;
+ u64 pcp_min_udp_len;
+ u64 pcp_max_udp_len;
+ u64 pcp_mod4_len;
+ u64 pcp_invalid_3rd_len;
+ u64 pcp_invalid_option;
+ u64 pcp_version;
+ u64 pcp_invalid_opcode;
+ u64 pcp_invalid_client_ip;
+ u64 pcp_invalid_proto;
+ u64 pcp_invalid_port;
+ u64 pcp_invalid_vrfmap;
+ u64 pcp_invalid_ext_addr;
+ u64 pcp_out_addr_inuse;
+ u64 pcp_exact_match;
+ u64 pcp_exact_entry_created;
+ u64 pcp_exact_db_alloc_failed;
+ u64 pcp_udb_mismatch;
+ u64 pcp_noexact_db_allocated;
+ u64 pcp_static_entry_present;
+ u64 pcp_entry_deleted;
+ u64 pcp_3rd_party_option;
+
+ /* map counters */
+ u64 pcp_map_input;
+ u64 pcp_map_min_len;
+ u64 pcp_map_max_len;
+ u64 pcp_map_invalid_option;
+ u64 pcp_map_invalid_option_len;
+ u64 pcp_map_pref_fail_option;
+ u64 pcp_map_invalid_delete_req;
+ u64 pcp_map_delete_req;
+ u64 pcp_map_create_req;
+ u64 pcp_map_refresh;
+
+ /* peer counters */
+ u64 pcp_peer_input;
+ u64 pcp_peer_invalid_len;
+ u64 pcp_peer_delete_req;
+ u64 pcp_peer_create_req;
+ u64 pcp_peer_addr_mistmatch;
+ u64 pcp_peer_refresh;
+
+} pcp_debug_counters_t;
+
+typedef struct {
+ u16 msg_id;
+ u8 rc;
+ u8 pad[5];
+
+ /* better to have a group structures rather than individual
+ variables, any change in counters is will automatically
+ reflect here */
+ pcp_debug_counters_t counters;
+} pcp_show_counters_resp_t ;
+
+
+
+/* PCP opcodes */
+typedef enum pcp_opcode {
+ PCP_OPCODE_MAP = 1,
+ PCP_OPCODE_PEER = 2
+}pcp_opcode_t;
+
+
+/* PCP opcodes */
+typedef enum pcp_options {
+ PCP_OPTION_3RD_PARTY = 1,
+ PCP_OPTION_PREF_FAIL = 2,
+ PCP_OPTION_FILTER = 3
+} pcp_options_t;
+
+/* PCP Result codes */
+typedef enum pcp_result_codes {
+ PCP_SUCCESS = 0,
+ PCP_ERR_UNSUPP_VERSION = 1,
+ PCP_ERR_NOT_AUTHORIZED = 2,
+ PCP_ERR_MALFORMED_REQUEST = 3,
+ PCP_ERR_UNSUPP_OPCODE = 4,
+ PCP_ERR_UNSUPP_OPTION = 5,
+ PCP_ERR_MALFORMED_OPTION = 6,
+ PCP_ERR_NETWORK_FAILURE = 7,
+ PCP_ERR_NO_RESOURCES = 8,
+ PCP_ERR_UNSUPP_PROTOCOL = 9,
+ PCP_ERR_USER_EX_QUOTA = 10,
+ PCP_ERR_CANNOT_PROVIDE_EXTERNAL = 11,
+ PCP_ERR_ADDRESS_MISMATCH = 12,
+ PCP_ERR_EXCESSIVE_REMOTE_PEERS = 13
+} pcp_result_codes_t;
+
+#define PCP_DISABLED 0
+#define PCP_ENABLED 1
+
+#define PCP_DROP 1
+
+#define PCP_STATIC_LIFETIME 0xFFFFFFFF
+#define PCP_MAX_LIFETIME 0x00015180 /* 24 hours = 86400 seconds*/
+
+#define PCP_VERSION_SUPPORTED 1
+
+#define PCP_NO_PREF_FAIL_OPTION 0
+#define PCP_PREF_FAIL_OPTION 1
+
+#define CNAT_DEF_PCP_PORT 5351
+
+#define PCP_REQ_RESP_BIT 0x80
+#define PCP_RESPONSE(r_opcode) (r_opcode & PCP_REQ_RESP_BIT)
+#define PCP_REQUEST(r_opcode) !(PCP_RESPONSE(r_opcode))
+
+#define PCP_REQ_OPCODE(r_opcode) (r_opcode & 0x7F)
+
+/* 24 bytes */
+#define PCP_COMMON_HDR_LEN sizeof(pcp_request_t)
+
+/* 8 bytes */
+#define UDP_HDR_LEN sizeof(udp_hdr_type_t)
+
+#define PCP_PREF_FAIL_OPTION_SIZE \
+ sizeof(pcp_prefer_fail_option_t)
+
+#define PCP_3RD_PARTY_OPTION_SIZE \
+ sizeof(pcp_3rd_party_option_t)
+
+#define PCP_MIN_LEN PCP_COMMON_HDR_LEN
+
+/* 24+8=32 bytes */
+#define PCP_MIN_UDP_LEN (PCP_MIN_LEN + UDP_HDR_LEN)
+
+#define PCP_MAX_LEN 1024
+
+/* 1024+8 = 1032 bytes */
+#define PCP_MAX_UDP_LEN (PCP_MAX_LEN + UDP_HDR_LEN)
+
+/* 24+ 24 = 48 bytes */
+#define PCP_MAP_OPCODE_MIN_LEN (PCP_COMMON_HDR_LEN + \
+ sizeof( pcp_map_option_specific_data_t))
+
+/* 24 + 44 = 68 bytes */
+#define PCP_PEER_OPCODE_MIN_LEN (PCP_COMMON_HDR_LEN + \
+ sizeof( pcp_peer_option_specific_data_t))
+
+/* 48 + 8 = 56 bytes */
+#define PCP_MAP_OPCODE_MIN_UDP_LEN (PCP_MAP_OPCODE_MIN_LEN + \
+ UDP_HDR_LEN )
+
+#define PCP_GET_MAP_OPTION_OFFSET(req) \
+ ((u8*)req + PCP_MAP_OPCODE_MIN_LEN)
+
+#define PCP_GET_PEER_OPTION_OFFSET(req) \
+ ((u8*)req + PCP_PEER_OPCODE_MIN_LEN)
+
+
+#define PCP_REQ_TOTAL_LEN(udp) (udp->udp_length - \
+ UDP_HDR_LEN)
+/* 56 + 4 = 60 bytes */
+#define PCP_MAP_OPCODE_PREF_FAIL_OPTION_LEN \
+ (PCP_MAP_OPCODE_MIN_UDP_LEN + \
+ sizeof(pcp_prefer_fail_option_t))
+
+
+/* 68 + 8 = 76 bytes */
+#define PCP_PEER_OPCODE_MIN_UDP_LEN (PCP_PEER_OPCODE_MIN_LEN + \
+ UDP_HDR_LEN)
+
+#define PCP_MUST_OPTION(option_code) (option_code & 0x80)
+
+
+
+/* 56 + 20 = 76*/
+#define PCP_DSLITE_MAP_OPCODE_MIN_UDP_LEN \
+ ( PCP_MAP_OPCODE_MIN_UDP_LEN + \
+ PCP_3RD_PARTY_OPTION_SIZE)
+
+/* 60 + 20 = 80 */
+#define PCP_DSLITE_MAP_OPCODE_MAX_UDP_LEN \
+ ( PCP_MAP_OPCODE_PREF_FAIL_OPTION_LEN + \
+ PCP_3RD_PARTY_OPTION_SIZE)
+
+/* 76 + 20 = 96 */
+#define PCP_DSLITE_PEER_OPCODE_MIN_UDP_LEN \
+ ( PCP_PEER_OPCODE_MIN_UDP_LEN + \
+ PCP_3RD_PARTY_OPTION_SIZE)
+
+
+#define PCP_SET_CNAT_PROTO(proto) \
+ pcp_data.cnat_proto = (proto == TCP_PROT) ? CNAT_TCP: \
+ (proto == UDP_PROT)? CNAT_UDP : CNAT_ICMP;
+
+#define PCP_SET_REQ_LIFETIME() \
+ if(pcp_data.db->flags & CNAT_DB_FLAG_STATIC_PORT) { \
+ pcp_data.db->proto_data.seq_pcp.pcp_lifetime = \
+ PCP_STATIC_LIFETIME; \
+ pcp_data.req_lifetime = PCP_STATIC_LIFETIME; \
+ } else { \
+ pcp_data.db->proto_data.seq_pcp.pcp_lifetime = \
+ pcp_data.req_lifetime + cnat_current_time ; \
+ }
+
+
+/* per second not more than PCP_THROTTLE_LIMIT
+ * delete requests will be handled.
+ * this excludes , specific entries, in which
+ * only one entry needs to be deleted
+ */
+#define PCP_THROTTLE_LIMIT 2
+
+typedef struct pcp_request {
+ u8 ver;
+ u8 r_opcode;
+ u16 reserved;
+ u32 req_lifetime;
+ u32 ip[4]; /* ipv4 will be represented
+ by the ipv4 mapped ipv6 */
+} pcp_request_t;
+
+typedef struct pcp_response {
+ u8 ver;
+ u8 r_opcode;
+ u8 reserved;
+ u8 result_code;
+ u32 lifetime;
+ u32 epochtime;
+ u32 reserved1[3];
+} pcp_response_t;
+
+
+typedef struct pcp_options_hdr {
+ u8 code;
+ u8 reserved;
+ u16 len;
+ u8 data[0];
+} pcp_options_hdr_t;
+
+
+/* same for both request and response */
+typedef struct pcp_map_option_specific_data {
+ u8 protocol;
+ u8 reserved[3];
+ u16 int_port;
+ u16 ext_port;
+ u32 ext_ip[4]; /* ipv4 will be represnted
+ by the ipv4 mapped ipv6 */
+} pcp_map_option_specific_data_t;
+
+/* same for both request and response */
+typedef struct pcp_peer_option_specific_data {
+ u8 protocol;
+ u8 reserved[3];
+ u16 int_port;
+ u16 ext_port;
+ u32 ext_ip[4]; /* ipv4 will be represented
+ by the ipv4 mapped ipv6 */
+ u16 peer_port;
+ u16 reserved1;
+ u32 peer_ip[4];
+} pcp_peer_option_specific_data_t;
+
+typedef struct pcp_prefer_fail_option {
+ u8 option;
+ u8 reserved;
+ u16 len;
+} pcp_prefer_fail_option_t;
+
+
+typedef struct pcp_3rd_party_option{
+ u8 option;
+ u8 reserved;
+ u16 len;
+ u32 ip[4];
+} pcp_3rd_party_option_t;
+
+/* structure used as pipeline data */
+
+typedef struct pcp_pipeline_data {
+
+ union {
+
+ u8 *p;
+ ipv4_header *ip ;
+ ipv6_header_t *ipv6 ;
+
+ } l3addr;
+
+ udp_hdr_type_t *udp;
+ pcp_request_t *req;
+ pcp_response_t *resp;
+ pcp_opcode_t opcode;
+ u32 src_ip[4];
+ u16 src_port;
+ u8 proto;
+ u16 i_vrf;
+ u16 o_vrf;
+ u32 ext_ip[4];
+ u16 ext_port;
+ u32 third_party_ip[4];
+
+ /* valid for peer opcode */
+ u32 peer_ip[4];
+ u32 peer_port;
+ u32 req_lifetime;
+ u32 udp_len;
+ pcp_options_t pref_fail;
+ pcp_options_t third_party;
+ u8 *option_spec;
+ pcp_result_codes_t ret_code;
+ cnat_portmap_v2_t *pm;
+ cnat_main_db_entry_t *db;
+ cnat_vrfmap_t *vrfmap;
+ dslite_table_entry_t *inst_ptr;
+ u16 inst_id;
+ u32 flags;
+ u16 cnat_proto;
+
+ /* is packet needs to be dropped ? */
+ u8 drop;
+ /* nat44, dslite, nat64 */
+#define PCP_SERVICE_NAT44 1
+#define PCP_SERVICE_DSLITE 2
+#define PCP_SERVICE_NAT64 3
+ u8 service_type;
+
+#define PCP_REQ_ENTRY_PRESENT 1
+#define PCP_REQ_EXT_MAP_PRESENT 1
+ u8 state;
+} pcp_pipeline_data_t;
+
+#endif /* __CNAT_PCP_sERVER_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_ports.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_ports.c
new file mode 100644
index 00000000..943fb3ed
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_ports.c
@@ -0,0 +1,1113 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_ports.c - port allocator
+ *
+ * Copyright (c) 2008-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/vec.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/pool.h>
+#include <vppinfra/clib.h>
+#include <vppinfra/bitmap.h>
+
+#include "cnat_db.h"
+#include "cnat_config.h"
+#include "cnat_global.h"
+#include "cnat_logging.h"
+#include "spp_timers.h"
+#include "platform_common.h"
+#include "cgn_bitmap.h"
+#include "spp_platform_trace_log.h"
+#include "cnat_ports.h"
+
+#if 1 /* TOBE_PORTED */
+/* Following is defined elsewhere. */
+#define msg_spp_err(s) \
+do { \
+ fprintf(stderr,(i8 *)s); \
+ fputs("\n", stderr); \
+} while(0);
+#endif
+
+
+#define PM_90_PERCENT_USE 58980
+/*
+ * instance number provisioned from HW
+ */
+u8 my_instance_number = 0;
+
+typedef struct {
+ u32 cached_next_index;
+ /* $$$$ add data here */
+
+ /* convenience variables */
+ vlib_main_t * vlib_main;
+ vnet_main_t * vnet_main;
+} cnat_ports_main_t;
+
+cnat_ports_main_t cnat_ports_main;
+
+static u32 rseed_port; /* random number generator seed */
+
+void
+cnat_db_dump_portmap_for_vrf (u32 vrfmap_index)
+{
+ u32 i, pm_len;
+ cnat_vrfmap_t *my_vrfmap = cnat_map_by_vrf + vrfmap_index;
+ cnat_portmap_v2_t *pm, *my_pm __attribute__((unused));
+
+ pm = my_vrfmap->portmap_list;
+ pm_len = vec_len(pm);
+
+ for (i = 0; i < pm_len; i++) {
+ my_pm = pm + i;
+
+ PLATFORM_DEBUG_PRINT("pm %d: IPv4 Addr 0x%x - in use %d private_ip_users_count %d\n",
+ i, my_pm->ipv4_address, my_pm->inuse,
+ my_pm->private_ip_users_count);
+
+ PLATFORM_DEBUG_PRINT("pm %d: IPv4 Addr 0x%x - in use %d "
+ "private_ip_users_count %d\n",
+ i, my_pm->ipv4_address, my_pm->inuse,
+ my_pm->private_ip_users_count);
+ }
+}
+
+void
+cnat_db_dump_portmaps ()
+{
+ u32 i, vrfmap_index;
+
+ for (i = 0; i < CNAT_MAX_VRFMAP_ENTRIES; i++) {
+ vrfmap_index = vrf_map_array[i];
+
+ if (vrfmap_index == VRF_MAP_ENTRY_EMPTY) {
+ continue;
+ }
+
+ PLATFORM_DEBUG_PRINT("\n\nDumping the port map for uidb_index %d\n", i);
+ cnat_db_dump_portmap_for_vrf(vrfmap_index);
+ }
+}
+
+#ifndef NO_BULK_LOGGING
+static int check_if_stat_alloc_ok_for_bulk(cnat_portmap_v2_t *pm,
+ u16 i_port, bulk_alloc_size_t bulk_size,
+ u16 static_port_range)
+{
+ uword bit_test_result;
+ if(BULK_ALLOC_SIZE_NONE == bulk_size) return 1; /* No issues */
+
+ if(i_port < static_port_range) return 1; /* we don't want bulk */
+
+ i_port = (i_port/bulk_size) * bulk_size;
+ bit_test_result = cgn_clib_bitmap_check_if_all(pm->bm, i_port, bulk_size);
+ return(bit_test_result);
+}
+#else /* dummy */
+inline static int check_if_stat_alloc_ok_for_bulk(cnat_portmap_v2_t *pm,
+ u16 i_port, bulk_alloc_size_t bulk_size,
+ u16 static_port_range)
+{
+ return 1;
+}
+#endif /* NO_BULK_LOGGING */
+/*
+ * cnat_port_alloc_static_v2
+ * public ipv4 address/port allocator for Static Port commands
+ * tries to allocate same outside port as inside port
+ */
+cnat_errno_t
+cnat_static_port_alloc_v2 (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ port_pair_t pair_type,
+ u32 i_ipv4_address,
+ u16 i_port,
+ u32 *index,
+ u32 *o_ipv4_address,
+ u16 *o_port,
+ u16 static_port_range
+#ifndef NO_BULK_LOGGING
+ , bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req
+#endif
+ , u16 ip_n_to_1
+ )
+{
+ u32 i, hash_value, my_index, found, max_attempts;
+ u16 start_bit, new_port;
+ cnat_portmap_v2_t *my_pm = 0;
+ u32 pm_len = vec_len(pm);
+ uword bit_test_result;
+
+#ifndef NO_BULK_LOGGING
+ *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
+#endif
+
+ if (PREDICT_FALSE(pm_len == 0)) {
+ return (CNAT_NO_POOL_ANY);
+ }
+
+ switch (atype) {
+
+ case PORT_ALLOC_ANY:
+
+ found = 0;
+
+ /*
+ * Try to hash the IPv4 address to get an index value to select the pm
+ */
+ hash_value = (i_ipv4_address & 0xffff) ^
+ ((i_ipv4_address > 16) & 0xffff);
+
+ /*
+ * If pm_len <= 256, compact the hash to 8 bits
+ */
+ if (PREDICT_TRUE(pm_len <= 256)) {
+ hash_value = (hash_value & 0xff) ^ ((hash_value > 8) & 0xff);
+ }
+
+ /*
+ * Ensure that the hash value is in the range 0 .. (pm_len-1)
+ */
+ my_index = hash_value % pm_len;
+
+ for (i = 0; i < PORT_PROBE_LIMIT; i++) {
+ my_pm = pm + my_index;
+ if(PREDICT_TRUE(ip_n_to_1)) {
+ if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1)) {
+ /*
+ * Try to find a PM with atlest 33% free and my_port free
+ */
+ if (PREDICT_TRUE((my_pm->inuse < ((BITS_PER_INST*2)/3)) &&
+ clib_bitmap_get_no_check(my_pm->bm,
+ i_port) == 1)
+#ifndef NO_BULK_LOGGING
+ && check_if_stat_alloc_ok_for_bulk(my_pm, i_port,
+ bulk_size,
+ static_port_range)
+#endif
+ ) {
+ found = 1;
+ break;
+ }
+ }
+
+ } else {
+ /*
+ * Try to find a PM with atlest 33% free and my_port free
+ */
+ if (PREDICT_TRUE((my_pm->inuse < ((BITS_PER_INST*2)/3)) &&
+ clib_bitmap_get_no_check(my_pm->bm,
+ i_port) == 1)
+#ifndef NO_BULK_LOGGING
+ && check_if_stat_alloc_ok_for_bulk(my_pm, i_port,
+ bulk_size,
+ static_port_range)
+#endif
+ ) {
+ found = 1;
+ break;
+ }
+ }
+ my_index = (my_index + 1) % pm_len;
+ }
+
+ /*
+ * If not found do it the hard way .
+ * "hard" way, best-fit.
+ */
+ if (!found) {
+ u32 min_inuse_any, min_inuse_myport;
+ u32 min_index_any, min_index_myport;
+
+ min_inuse_any = min_inuse_myport = PORTS_PER_ADDR + 1;
+ min_index_any = min_index_myport = ~0;
+ for (i = 0; i < pm_len; i++) {
+ my_pm = pm + i;
+ if(PREDICT_TRUE(ip_n_to_1)) {
+ if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1)) {
+ if (PREDICT_FALSE(my_pm->inuse < min_inuse_any)) {
+ min_inuse_any = my_pm->inuse;
+ min_index_any = my_pm - pm;
+ }
+ if (PREDICT_FALSE(my_pm->inuse < min_inuse_myport)) {
+ if (PREDICT_TRUE(clib_bitmap_get_no_check(
+ my_pm->bm,i_port) == 1)
+#ifndef NO_BULK_LOGGING
+ && check_if_stat_alloc_ok_for_bulk(my_pm,
+ i_port,bulk_size,static_port_range)
+#endif
+ ) {
+ min_inuse_myport = my_pm->inuse;
+ min_index_myport = my_pm - pm;
+ }
+ }
+
+ }
+
+ } else {
+ if (PREDICT_FALSE(my_pm->inuse < min_inuse_any)) {
+ min_inuse_any = my_pm->inuse;
+ min_index_any = my_pm - pm;
+ }
+ if (PREDICT_FALSE(my_pm->inuse < min_inuse_myport)) {
+ if (PREDICT_TRUE(clib_bitmap_get_no_check(
+ my_pm->bm, i_port) == 1)
+#ifndef NO_BULK_LOGGING
+ && check_if_stat_alloc_ok_for_bulk(my_pm, i_port,
+ bulk_size, static_port_range)
+#endif
+ ) {
+ min_inuse_myport = my_pm->inuse;
+ min_index_myport = my_pm - pm;
+ }
+ }
+ }
+ }
+
+ /*
+ * Check if we have an exactly matching PM that has
+ * myport free. If so use it. If no such PM is
+ * available, use any PM
+ */
+ if (PREDICT_TRUE(min_inuse_myport < PORTS_PER_ADDR)) {
+ my_pm = pm + min_index_myport;
+ my_index = min_index_myport;
+ found = 1;
+ } else if (PREDICT_TRUE(min_inuse_any < PORTS_PER_ADDR)) {
+ my_pm = pm + min_index_any;
+ my_index = min_index_any;
+ found = 1;
+ }
+ }
+
+ if (!found) {
+ return (CNAT_NO_PORT_ANY);
+ }
+ break;
+
+ case PORT_ALLOC_DIRECTED:
+ my_index = *index;
+ if (PREDICT_FALSE(my_index > pm_len)) {
+ return (CNAT_INV_PORT_DIRECT);
+ }
+ my_pm = pm + my_index;
+ break;
+
+ default:
+ return (CNAT_ERR_PARSER);
+ }
+
+ /* Allocate a matching port if possible */
+ start_bit = i_port;
+ found = 0;
+ max_attempts = BITS_PER_INST;
+#ifndef NO_BULK_LOGGING
+ if((BULK_ALLOC_SIZE_NONE != bulk_size) &&
+ (i_port >= static_port_range)) {
+ start_bit = (start_bit/bulk_size) * bulk_size;
+ max_attempts = BITS_PER_INST/bulk_size;
+ }
+#endif /* NO_BULK_LOGGING */
+
+ for (i = 0; i < max_attempts; i++) {
+#ifndef NO_BULK_LOGGING
+ if((BULK_ALLOC_SIZE_NONE != bulk_size) &&
+ (i_port >= static_port_range)) {
+ bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm,
+ start_bit, bulk_size);
+ }
+ else
+#endif /* #ifndef NO_BULK_LOGGING */
+ bit_test_result = clib_bitmap_get_no_check(my_pm->bm, start_bit);
+
+ if (PREDICT_TRUE(bit_test_result)) {
+#ifndef NO_BULK_LOGGING
+ if((BULK_ALLOC_SIZE_NONE != bulk_size) &&
+ (i_port >= static_port_range)) {
+ *nfv9_log_req = start_bit;
+ if(i==0) new_port = i_port; /* First go */
+ else {
+ new_port = bit2port(start_bit);
+ if (pair_type == PORT_S_ODD && (new_port & 0x1) == 0)
+ new_port++;
+ }
+ found = 1;
+ break;
+ }
+ else {
+#endif /* NO_BULK_LOGGING */
+ new_port = bit2port(start_bit);
+ if (pair_type == PORT_S_ODD) {
+ if ((new_port & 0x1) == 1) {
+ found = 1;
+ break;
+ }
+ } else if (pair_type == PORT_S_EVEN) {
+ if ((new_port & 0x1) == 0) {
+ found = 1;
+ break;
+ }
+ } else {
+ found = 1;
+ break;
+ }
+#ifndef NO_BULK_LOGGING
+ }
+#endif
+ }
+#ifndef NO_BULK_LOGGING
+ if((BULK_ALLOC_SIZE_NONE != bulk_size) &&
+ (i_port >= static_port_range))
+ start_bit = (start_bit + bulk_size) % BITS_PER_INST;
+ else {
+#endif /* NO_BULK_LOGGING */
+ start_bit = (start_bit + 1) % BITS_PER_INST;
+ if(PREDICT_FALSE(start_bit == 0)) {
+ start_bit = 1; /* Port 0 is invalid, so start from 1 */
+ }
+#ifndef NO_BULK_LOGGING
+ }
+#endif
+ } /* End of for loop */
+
+ if (!found) {
+ /* Port allocation failure */
+ if (atype == PORT_ALLOC_DIRECTED) {
+ return (CNAT_NOT_FOUND_DIRECT);
+ } else {
+ return (CNAT_NOT_FOUND_ANY);
+ }
+ }
+
+ /* Accounting */
+ cgn_clib_bitmap_clear_no_check(my_pm->bm, new_port);
+ (my_pm->inuse)++;
+
+ *index = my_pm - pm;
+ *o_ipv4_address = my_pm->ipv4_address;
+
+ *o_port = new_port;
+
+ return (CNAT_SUCCESS);
+}
+
+/*
+ * Try to allocate a portmap structure based on atype field
+ */
+cnat_portmap_v2_t *
+cnat_dynamic_addr_alloc_from_pm (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ u32 *index,
+ cnat_errno_t *err,
+ u16 ip_n_to_1,
+ u32 *rseed_ip)
+{
+ u32 i, pm_len;
+ int my_index;
+ int min_inuse, min_index;
+
+ cnat_portmap_v2_t *my_pm = 0;
+ *err = CNAT_NO_POOL_ANY;
+
+ pm_len = vec_len(pm);
+
+ switch(atype) {
+ case PORT_ALLOC_ANY:
+ if (PREDICT_FALSE(pm_len == 0)) {
+ my_pm = 0;
+ *err = CNAT_NO_POOL_ANY;
+ goto done;
+ }
+
+ /* "Easy" way, first address with at least 200 free ports */
+ for (i = 0; i < PORT_PROBE_LIMIT; i++) {
+ *rseed_ip = randq1(*rseed_ip);
+ my_index = (*rseed_ip) % pm_len;
+ my_pm = pm + my_index;
+ if (PREDICT_FALSE(ip_n_to_1)) {
+ if(PREDICT_TRUE(ip_n_to_1 == 1)) {
+ if (PREDICT_FALSE(0 == my_pm->inuse)) {
+ goto done;
+ }
+ } else {
+ if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1)) {
+ if (PREDICT_FALSE(my_pm->inuse < ((BITS_PER_INST*2)/3))) {
+ goto done;
+ }
+ }
+ }
+ } else {
+ if (PREDICT_FALSE(my_pm->inuse < ((BITS_PER_INST*2)/3))) {
+ goto done;
+ }
+ }
+ }
+
+ /* "hard" way, best-fit. $$$$ Throttle complaint */
+ min_inuse = PORTS_PER_ADDR + 1;
+ min_index = ~0;
+ for (i = 0; i < pm_len; i++) {
+ my_pm = pm + i;
+ if (PREDICT_FALSE(ip_n_to_1)) {
+ if(PREDICT_TRUE(ip_n_to_1 == 1)) {
+ if (PREDICT_FALSE(!my_pm->inuse)) {
+ min_inuse = my_pm->inuse;
+ min_index = my_pm - pm;
+ }
+ } else {
+ if(PREDICT_TRUE(my_pm->private_ip_users_count < ip_n_to_1)) {
+ if (PREDICT_TRUE(my_pm->inuse < min_inuse)) {
+ min_inuse = my_pm->inuse;
+ min_index = my_pm - pm;
+ }
+
+ }
+ }
+
+ } else {
+ if (PREDICT_TRUE(my_pm->inuse < min_inuse)) {
+ min_inuse = my_pm->inuse;
+ min_index = my_pm - pm;
+ }
+ }
+ }
+
+ if (PREDICT_TRUE(min_inuse < PORTS_PER_ADDR)) {
+ my_pm = pm + min_index;
+ my_index = min_index;
+ goto done;
+ }
+
+ /* Completely out of ports */
+#ifdef DEBUG_PRINTF_ENABLED
+ PLATFORM_DEBUG_PRINT("%s out of ports\n", __FUNCTION__);
+#endif
+
+ my_pm = 0;
+ *err = CNAT_NO_PORT_ANY;
+ break;
+
+
+ case PORT_ALLOC_DIRECTED:
+ //ASSERT(*index < pm_len);
+ if (PREDICT_FALSE(*index > pm_len)) {
+ my_pm = 0;
+ *err = CNAT_INV_PORT_DIRECT;
+ goto done;
+ }
+ my_pm = pm + *index;
+ my_index = *index;
+ break;
+
+ default:
+ msg_spp_err("bad allocation type in cnat_port_alloc");
+ my_pm = 0;
+ *err = CNAT_ERR_PARSER;
+ break;
+ }
+
+ done:
+ if (PREDICT_FALSE(my_pm == NULL)) {
+ return (my_pm);
+ }
+
+ if (PREDICT_FALSE(my_pm->inuse >= BITS_PER_INST)) {
+ my_pm = 0;
+ if (atype == PORT_ALLOC_DIRECTED) {
+ *err = CNAT_BAD_INUSE_DIRECT;
+ } else {
+ *err = CNAT_BAD_INUSE_ANY;
+ }
+ }
+
+ return (my_pm);
+}
+
+
+/*
+ * cnat_port_alloc_v2
+ * public ipv4 address/port allocator for dynamic ports
+ *
+ * 200K users / 20M translations means vec_len(cnat_portmap) will be
+ * around 300.
+ *
+ */
+cnat_errno_t
+cnat_dynamic_port_alloc_v2 (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ port_pair_t pair_type,
+ u32 *index,
+ u32 *o_ipv4_address,
+ u16 *o_port,
+ u16 static_port_range
+#ifndef NO_BULK_LOGGING
+ , bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req
+#endif
+ , u16 ip_n_to_1,
+ u32 *rseed_ip
+ )
+{
+ int i;
+ cnat_errno_t my_err = CNAT_NO_POOL_ANY;
+ cnat_portmap_v2_t *my_pm = 0;
+ u16 start_bit;
+ u16 new_port;
+ uword bit_test_result;
+ uword max_trys_to_find_port;
+
+ ASSERT(index);
+ ASSERT(o_ipv4_address);
+ ASSERT(o_port);
+
+ my_pm = cnat_dynamic_addr_alloc_from_pm(pm, atype, index, &my_err, ip_n_to_1,
+ rseed_ip);
+
+ if (PREDICT_FALSE(my_pm == NULL)) {
+ return (my_err);
+ }
+ if(PREDICT_FALSE(my_pm->dyn_full == 1)) {
+ if (atype == PORT_ALLOC_DIRECTED) {
+ return (CNAT_NOT_FOUND_DIRECT);
+ } else {
+ return (CNAT_NOT_FOUND_ANY);
+ }
+ }
+
+#if DEBUG > 1
+ PLATFORM_DEBUG_PRINT("ALLOC_PORT_V2: My_Instance_Number %d: IP addr 0x%x, Inuse %d\n",
+ my_instance_number, my_pm->ipv4_address, my_pm->inuse);
+#endif
+
+ rseed_port = randq1(rseed_port);
+
+ /*
+ * Exclude the static port range for allocating dynamic ports
+ */
+ start_bit = (rseed_port) % (BITS_PER_INST - static_port_range);
+ start_bit = start_bit + static_port_range;
+
+#ifndef NO_BULK_LOGGING
+ *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
+ if(BULK_ALLOC_SIZE_NONE != bulk_size)
+ {
+ /* We need the start port of the range to be alined on integer multiple
+ * of bulk_size */
+ max_trys_to_find_port = BITS_PER_INST/bulk_size;
+ start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size;
+ }
+ else
+#endif /* #ifndef NO_BULK_LOGGING */
+ max_trys_to_find_port = BITS_PER_INST;
+
+ /* Allocate a random port / port-pair */
+ for (i = 0; i < max_trys_to_find_port; i++) {
+
+ /* start_bit is only a u16.. so it can rollover and become zero */
+ if (PREDICT_FALSE( /* (start_bit >= BITS_PER_INST) || FIXME u16 cannot be >= 65536 */
+ (start_bit < static_port_range))) {
+ start_bit = static_port_range;
+#ifndef NO_BULK_LOGGING
+ if(BULK_ALLOC_SIZE_NONE != bulk_size) {
+ start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size;
+ }
+#endif /* #ifndef NO_BULK_LOGGING */
+ }
+ /* Scan forward from random position */
+#ifndef NO_BULK_LOGGING
+ if(BULK_ALLOC_SIZE_NONE != bulk_size) {
+ bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm,
+ start_bit, bulk_size);
+ }
+ else
+#endif /* #ifndef NO_BULK_LOGGING */
+ bit_test_result = clib_bitmap_get_no_check(my_pm->bm, start_bit);
+
+ if (PREDICT_TRUE(bit_test_result)) {
+ new_port = bit2port(start_bit);
+#ifndef NO_BULK_LOGGING
+ if(BULK_ALLOC_SIZE_NONE != bulk_size)
+ *nfv9_log_req = new_port;
+#endif
+ if ((pair_type == PORT_S_ODD) &&
+ (!(new_port & 0x1))) {
+#ifndef NO_BULK_LOGGING
+ if(BULK_ALLOC_SIZE_NONE != bulk_size) {
+ start_bit++; /* Just use the next one in the bulk range */
+ new_port++;
+ goto found2;
+ }
+#endif /* #ifndef NO_BULK_LOGGING */
+ goto notfound;
+ } else if ((pair_type == PORT_S_EVEN) &&
+ (new_port & 0x1)) {
+ goto notfound;
+ }
+
+ /* OK we got one or two suitable ports */
+ goto found2;
+ }
+
+ notfound:
+#ifndef NO_BULK_LOGGING
+ if(BULK_ALLOC_SIZE_NONE != bulk_size)
+ start_bit += bulk_size;
+ else
+#endif /* #ifndef NO_BULK_LOGGING */
+ start_bit++;
+
+ } /* end of for loop */
+
+ /* Completely out of ports */
+
+ /* Port allocation failure */
+ /* set dyn_full flag. This would be used to verify
+ * for further dyn session before searching for port
+ */
+ if (atype == PORT_ALLOC_DIRECTED) {
+ my_pm->dyn_full = 1;
+ return (CNAT_NOT_FOUND_DIRECT);
+ } else {
+ my_pm->dyn_full = 1;
+ return (CNAT_NOT_FOUND_ANY);
+ }
+
+
+ found2:
+
+ /* Accounting */
+ cgn_clib_bitmap_clear_no_check (my_pm->bm, start_bit);
+ (my_pm->inuse)++;
+
+ *index = my_pm - pm;
+ *o_ipv4_address = my_pm->ipv4_address;
+
+ *o_port = new_port;
+ return (CNAT_SUCCESS);
+}
+
+#ifdef TOBE_PORTED
+/*
+ * cnat_alloc_port_from_pm
+ * Given a portmap structure find port/port_pair that are free
+ *
+ * The assumption in this function is that bit in bm corresponds
+ * to a port number. This is TRUE and hence there is no call
+ * to the function bit2port here, though it is done in other
+ * places in this file.
+ *
+ */
+static u32
+cnat_alloc_port_from_pm (
+ u32 start_port,
+ u32 end_port,
+ cnat_portmap_v2_t *my_pm,
+ port_pair_t pair_type
+#ifndef NO_BULK_LOGGING
+ , bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req
+#endif /* #ifnded NO_BULK_ALLOCATION */
+ )
+{
+ u32 i;
+ u32 start_bit;
+ u32 total_ports = end_port - start_port + 1;
+ uword bit_test_result;
+ uword max_trys_to_find_port;
+
+ rseed_port = randq1(rseed_port);
+
+ start_bit = rseed_port % total_ports;
+ start_bit = start_bit + start_port;
+#ifndef NO_BULK_LOGGING
+ *nfv9_log_req = BULK_ALLOC_NOT_ATTEMPTED;
+ if(BULK_ALLOC_SIZE_NONE != bulk_size)
+ {
+ /* We need the start port of the range to be alined on integer multiple
+ * of bulk_size */
+ max_trys_to_find_port = total_ports/bulk_size;
+ start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size;
+ }
+ else
+#endif /* #ifndef NO_BULK_LOGGING */
+ max_trys_to_find_port = total_ports;
+
+ /* Allocate a random port / port-pair */
+ for (i = 0; i < max_trys_to_find_port; i++) {
+ /* start_bit is only a u16.. so it can rollover and become zero */
+ if (PREDICT_FALSE((start_bit >= end_port) ||
+ (start_bit < start_port))) {
+ start_bit = start_port;
+#ifndef NO_BULK_LOGGING
+ if(BULK_ALLOC_SIZE_NONE != bulk_size) {
+ start_bit= ((start_bit + bulk_size -1)/bulk_size) * bulk_size;
+ }
+#endif /* #ifndef NO_BULK_LOGGING */
+ }
+
+ /* Scan forward from random position */
+#ifndef NO_BULK_LOGGING
+ if(BULK_ALLOC_SIZE_NONE != bulk_size) {
+ bit_test_result = cgn_clib_bitmap_check_if_all(my_pm->bm,
+ start_bit, bulk_size);
+ }
+ else
+#endif /* #ifndef NO_BULK_LOGGING */
+ bit_test_result = clib_bitmap_get_no_check(my_pm->bm, start_bit);
+
+ if (PREDICT_TRUE(bit_test_result)) {
+#ifndef NO_BULK_LOGGING
+ if(BULK_ALLOC_SIZE_NONE != bulk_size) {
+ /* Got the entire bulk range */
+ *nfv9_log_req = bit2port(start_bit);
+ return start_bit;
+ } else {
+#endif /* #ifndef NO_BULK_LOGGING */
+ /*
+ * For PORT_PAIR, first port has to be Even
+ * subsequent port <= end_port
+ * subsequent port should be unallocated
+ */
+ if ((start_bit & 0x1) ||
+ ((start_bit + 1) > end_port) ||
+ (clib_bitmap_get_no_check(my_pm->bm,
+ (start_bit + 1)) == 0)) {
+ goto notfound;
+ }
+ return (start_bit);
+#ifndef NO_BULK_LOGGING
+ }
+#endif /* #ifndef NO_BULK_LOGGING */
+ } /* if( free port found ) */
+
+notfound:
+#ifndef NO_BULK_LOGGING
+ if(BULK_ALLOC_SIZE_NONE != bulk_size) {
+ start_bit += bulk_size;
+ } else
+#endif /* #ifndef NO_BULK_LOGGING */
+ start_bit++;
+
+ }
+ return (BITS_PER_INST);
+}
+
+/*
+ * cnat_dynamic_port_alloc_rtsp
+ * public ipv4 address/port allocator for dynamic ports
+ *
+ * 200K users / 20M translations means vec_len(cnat_portmap) will be
+ * around 300.
+ *
+ */
+
+cnat_errno_t
+cnat_dynamic_port_alloc_rtsp (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ port_pair_t pair_type,
+ u16 start_range,
+ u16 end_range,
+ u32 *index,
+ u32 *o_ipv4_address,
+ u16 *o_port
+#ifndef NO_BULK_LOGGING
+ , bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req
+#endif
+ , u32 *rseed_ip
+ )
+{
+
+ u32 current_timestamp;
+ cnat_errno_t my_err = CNAT_NO_POOL_ANY;
+ cnat_portmap_v2_t *my_pm = 0;
+ u32 alloc_bit;
+
+ ASSERT(index);
+ ASSERT(o_ipv4_address);
+ ASSERT(o_port);
+
+ my_pm = cnat_dynamic_addr_alloc_from_pm(pm, atype, index, &my_err, 0,rseed_ip);
+
+ if (PREDICT_FALSE(my_pm == NULL)) {
+ return (my_err);
+ }
+
+#if DEBUG > 1
+ PLATFORM_DEBUG_PRINT("ALLOC_PORT_V2: My_Instance_Number %d: IP addr 0x%x, Inuse %d\n",
+ my_instance_number, my_pm->ipv4_address, my_pm->inuse);
+#endif
+
+ alloc_bit =
+ cnat_alloc_port_from_pm(start_range, end_range, my_pm, pair_type
+#ifndef NO_BULK_LOGGING
+ , bulk_size, nfv9_log_req
+#endif /* #ifndef NO_BULK_LOGGING */
+ );
+
+ if (alloc_bit < BITS_PER_INST) {
+ if (pair_type == PORT_PAIR) {
+ /* Accounting */
+ cgn_clib_bitmap_clear_no_check (my_pm->bm, alloc_bit);
+ cgn_clib_bitmap_clear_no_check (my_pm->bm, alloc_bit+1);
+ (my_pm->inuse) += 2;
+ } else {
+ /* Accounting */
+ cgn_clib_bitmap_clear_no_check (my_pm->bm, alloc_bit);
+ (my_pm->inuse)++;
+ }
+
+ *index = my_pm - pm;
+ *o_ipv4_address = my_pm->ipv4_address;
+
+ *o_port = bit2port(alloc_bit);;
+
+ return (CNAT_SUCCESS);
+ }
+
+ /* Completely out of ports */
+ current_timestamp = spp_trace_log_get_unix_time_in_seconds();
+ if (PREDICT_FALSE((current_timestamp - my_pm->last_sent_timestamp) >
+ 1000)) {
+ spp_printf(CNAT_NO_EXT_PORT_AVAILABLE, 0, NULL);
+ my_pm->last_sent_timestamp = current_timestamp;
+ }
+
+
+ /* Port allocation failure */
+ if (atype == PORT_ALLOC_DIRECTED) {
+ return (CNAT_NOT_FOUND_DIRECT);
+ } else {
+ return (CNAT_NOT_FOUND_ANY);
+ }
+}
+#else
+cnat_errno_t
+cnat_dynamic_port_alloc_rtsp (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ port_pair_t pair_type,
+ u16 start_range,
+ u16 end_range,
+ u32 *index,
+ u32 *o_ipv4_address,
+ u16 *o_port
+#ifndef NO_BULK_LOGGING
+ , bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req
+#endif
+ , u32 *rseed_ip
+ )
+{
+ return (CNAT_NOT_FOUND_ANY);
+}
+#endif
+
+
+/*
+ * cnat_mapped_static_port_alloc_v2
+ * /
+ */
+cnat_errno_t
+cnat_mapped_static_port_alloc_v2 (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ u32 *index,
+ u32 ipv4_address,
+ u16 port
+#ifndef NO_BULK_LOGGING
+ , int *nfv9_log_req,
+ bulk_alloc_size_t bulk_size
+#endif
+ , u16 ip_n_to_1
+ )
+{
+ int i;
+ u32 pm_len;
+ u16 bm_bit;
+ cnat_portmap_v2_t *my_pm = 0;
+ u32 my_index;
+
+ ASSERT(index);
+
+ /*
+ * Map the port to the bit in the pm bitmap structure.
+ * Note that we use ports from 1024..65535, so
+ * port number x corresponds to (x-1024) position in bitmap
+ */
+ bm_bit = port2bit(port);
+
+ pm_len = vec_len(pm);
+
+ switch(atype) {
+ case PORT_ALLOC_ANY:
+ if (PREDICT_FALSE(pm_len == 0)) {
+ return (CNAT_NO_POOL_ANY);
+ }
+
+ /*
+ * Find the pm that is allocated for this translated IP address
+ */
+ my_index = pm_len;
+
+ for (i = 0; i < pm_len; i++) {
+ my_pm = pm + i;
+ if (PREDICT_FALSE(my_pm->ipv4_address == ipv4_address)) {
+ my_index = i;
+ break;
+ }
+ }
+
+ if ((PREDICT_FALSE(my_index >= pm_len)) ||
+ ((PREDICT_FALSE(ip_n_to_1)) && (PREDICT_TRUE(my_pm->private_ip_users_count >= ip_n_to_1)))) {
+ return (CNAT_NO_POOL_ANY);
+ }
+
+ break;
+
+ case PORT_ALLOC_DIRECTED:
+ if (PREDICT_FALSE(*index > pm_len)) {
+ return (CNAT_INV_PORT_DIRECT);
+ }
+
+ my_index = *index;
+ my_pm = pm + my_index;
+ if (PREDICT_FALSE(my_pm->ipv4_address != ipv4_address)) {
+ if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) {
+ PLATFORM_DEBUG_PRINT("Delete all main db entry for that particular in ipv4 address\n");
+ }
+ return (CNAT_INV_PORT_DIRECT);
+ }
+
+ break;
+
+ default:
+ msg_spp_err("bad allocation type in cnat_port_alloc");
+ return (CNAT_ERR_PARSER);
+ }
+
+
+ if (PREDICT_FALSE(my_pm == NULL)) {
+ return (CNAT_NO_POOL_ANY);
+ }
+
+ /*
+ * Check if the port is already allocated to some other mapping
+ */
+ if (PREDICT_FALSE(clib_bitmap_get_no_check (my_pm->bm, bm_bit) == 0)) {
+ return (CNAT_NO_POOL_ANY);
+ }
+
+#if DEBUG > 1
+ PLATFORM_DEBUG_PRINT("ALLOC_PORT_V2: My_Instance_Number %d: IP addr 0x%x, Inuse %d\n",
+ my_instance_number, my_pm->ipv4_address, my_pm->inuse);
+#endif
+
+ /*
+ * Indicate that the port is already allocated
+ */
+ cgn_clib_bitmap_clear_no_check (my_pm->bm, bm_bit);
+ (my_pm->inuse)++;
+
+ *index = my_index;
+
+ return (CNAT_SUCCESS);
+}
+
+void cnat_port_free_v2 (
+ cnat_portmap_v2_t *pm,
+ int index,
+ port_pair_t pair_type,
+ u16 base_port,
+ u16 static_port_range)
+{
+ cnat_portmap_v2_t *my_pm;
+ uword bit;
+
+ /* check for valid portmap */
+ if (PREDICT_FALSE(index > vec_len(pm))) {
+ spp_printf(CNAT_INVALID_INDEX_TO_FREE_PORT, 0, 0);
+ return;
+ }
+
+ my_pm = pm + index;
+ bit = port2bit(base_port);
+
+#if DEBUG > 0
+ if(clib_bitmap_get_no_check(my_pm->bm, bit))
+ ASSERT(clib_bitmap_get_no_check(my_pm->bm, bit) == 0);
+#endif
+
+ cgn_clib_bitmap_set_no_check(my_pm->bm, bit);
+
+ my_pm->inuse -= 1;
+ if(base_port >= static_port_range) {
+ /* Clear the full flag. we can have a new dynamic session now */
+ my_pm->dyn_full = 0;
+ }
+
+ return;
+}
+
+void cnat_portmap_dump_v2 (cnat_portmap_v2_t *pm, u16 print_limit)
+{
+ int i;
+ u32 inuse =0;
+
+ ASSERT(pm);
+
+ for (i = 0; i < BITS_PER_INST; i++) {
+ if (PREDICT_FALSE(clib_bitmap_get_no_check (pm->bm, i) == 0)) {
+ if (PREDICT_TRUE(inuse++ < print_limit))
+ PLATFORM_DEBUG_PRINT(" %d", bit2port(i));
+ }
+ }
+ if (PREDICT_FALSE(inuse >= print_limit)) {
+ PLATFORM_DEBUG_PRINT("%d printed, print limit is %d\n",
+ inuse, print_limit);
+ }
+ PLATFORM_DEBUG_PRINT("\n");
+}
+
+
+/*
+ * cnat_ports_init
+ */
+clib_error_t *cnat_ports_init(vlib_main_t *vm)
+{
+ cnat_ports_main_t *mp = &cnat_ports_main;
+
+ mp->vlib_main = vm;
+ mp->vnet_main = vnet_get_main();
+
+ /* suppress crypto-random port numbering */
+#ifdef SOON
+ if (spp_get_int_prop("no_crypto_random_ports") == 0)
+ crypto_random32(&seed);
+#endif
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION(cnat_ports_init);
+
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_ports.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_ports.h
new file mode 100644
index 00000000..bc1fb0d2
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_ports.h
@@ -0,0 +1,208 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_ports.h - port database definitions
+ *
+ * Copyright (c) 2007-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_PORTS_H__
+#define __CNAT_PORTS_H__
+
+#include "platform_common.h"
+#include "cnat_bulk_port_defs.h"
+
+#define PORTS_PER_ADDR 65536
+
+#define CNAT_INSTS PLATFORM_CNAT_INSTS
+
+#define BITS_PER_INST (PORTS_PER_ADDR)
+
+/*
+ * Ensure that atleast few 4 bit ports are available for RTSP
+ * in case we want to map 4 digit inside ports to 4 digit outside ports
+ */
+#define MIN_STATIC_PORT_RANGE_FOR_RTSP (9900)
+
+extern u8 my_instance_number;
+
+/*
+ * Now it is a 1-to-1 mapping between bit and port values
+ */
+static inline u16 bit2port (u32 bit)
+{
+ return bit;
+}
+
+static inline uword port2bit (u16 port)
+{
+ return port;
+}
+
+/*
+ * Port bitmap structure
+ * THIS structure is not used to be REMOVED....
+ */
+
+
+typedef struct {
+ u32 ipv4_address; /* native bit order */
+ u16 vrf;
+ u16 pad;
+ u32 threshold_crossed;
+ uword bm[(BITS_PER_INST + BITS(uword)-1)/BITS(uword)];
+} cnat_portmap_t;
+
+//cnat_portmap_t *cnat_portmap;
+
+
+typedef struct {
+ u32 inuse;
+ u32 delete_time;
+ u32 ipv4_address; /* native bit order */
+ u32 last_sent_timestamp;
+ uword bm[(BITS_PER_INST + BITS(uword)-1)/BITS(uword)];
+ u32 dyn_full;
+ u32 private_ip_users_count; /* number of private ip's(subscribers) to this
+ public ip */
+} cnat_portmap_v2_t;
+
+
+typedef enum {
+ PORT_SINGLE=0,
+ PORT_PAIR=1,
+ PORT_S_EVEN=2,
+ PORT_S_ODD=3,
+} port_pair_t;
+
+typedef enum {
+ PORT_TYPE_DYNAMIC=0,
+ PORT_TYPE_STATIC=1,
+ PORT_TYPE_RTSP=2,
+} port_type_t;
+
+
+typedef enum {
+ PORT_ALLOC_ANY=1,
+ PORT_ALLOC_DIRECTED=2,
+} port_alloc_t;
+
+#define PORT_PROBE_LIMIT 20
+
+
+/*
+ * randq1
+ * Linear congruential random number generator with
+ * extensively studied properties. See Numerical Recipes in C
+ * 2nd Ed. page 284. Known to behave according to the test vector
+ * supplied in the text, on X86 and Octeon.
+ */
+static inline u32 randq1 (u32 prev)
+{
+ return (1664525L*prev + 1013904223L);
+}
+
+cnat_errno_t
+cnat_static_port_alloc_v2(
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ port_pair_t pair_type,
+ u32 i_ipv4_address,
+ u16 i_port,
+ u32 *index,
+ u32 *o_ipv4_address,
+ u16 *o_port,
+ u16 static_port_range
+#ifndef NO_BULK_LOGGING
+ , bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req
+#endif /* NO_BULK_LOGGING */
+ , u16 ip_n_to_1
+ );
+
+cnat_errno_t
+cnat_mapped_static_port_alloc_v2 (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ u32 *index,
+ u32 ipv4_address,
+ u16 port
+#ifndef NO_BULK_LOGGING
+ , int *nfv9_log_req,
+ bulk_alloc_size_t bulk_size
+#endif
+ , u16 ip_n_to_1
+ );
+
+cnat_errno_t
+cnat_dynamic_port_alloc_v2(
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ port_pair_t pair_type,
+ u32 *index,
+ u32 *o_ipv4_address,
+ u16 *o_port,
+ u16 static_port_range
+#ifndef NO_BULK_LOGGING
+ , bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req
+#endif
+ , u16 ip_n_to_1,
+ u32 *rseed_ip
+ );
+
+
+cnat_errno_t
+cnat_dynamic_port_alloc_rtsp (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ port_pair_t pair_type,
+ u16 start_range,
+ u16 end_range,
+ u32 *index,
+ u32 *o_ipv4_address,
+ u16 *o_port
+#ifndef NO_BULK_LOGGING
+ , bulk_alloc_size_t bulk_size,
+ int *nfv9_log_req
+#endif
+ , u32 *rseed_ip
+ );
+
+void cnat_port_free_v2(
+ cnat_portmap_v2_t *pm,
+ int index,
+ port_pair_t ptype,
+ u16 base_port,
+ u16 static_port_range);
+
+void cnat_portmap_dump_v2(cnat_portmap_v2_t *pm,
+ u16 print_limit);
+
+
+
+cnat_errno_t
+nat64_static_port_alloc (
+ cnat_portmap_v2_t *pm,
+ port_alloc_t atype,
+ port_pair_t pair_type,
+ u32 *i_ipv6_address,
+ u16 i_port,
+ u32 *index,
+ u32 *o_ipv4_address,
+ u16 *o_port);
+
+
+
+#endif /* __CNAT_PORTS_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_show.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_show.c
new file mode 100644
index 00000000..68c52756
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_show.c
@@ -0,0 +1,810 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_show.c - translation database definitions
+ *
+ * Copyright (c) 2007-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/vec.h>
+#include <vppinfra/bitmap.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/pool.h>
+#include <vppinfra/clib.h>
+
+#include "cnat_db.h"
+#include "cnat_config.h"
+#include "cnat_global.h"
+#include "cnat_logging.h"
+#include "spp_ctx.h"
+#include "spp_timers.h"
+#include "platform_common.h"
+#include "cnat_syslog.h"
+#include "cnat_v4_pptp_alg.h"
+#include "platform_common.h"
+
+#ifndef TOBE_PORTED
+/* The following variable is in cnat_config_msg_handler.c which
+ * is to be ported later.. if required
+ */
+u32 total_address_pool_allocated = 0;
+#endif
+
+#ifndef NO_BULK_LOGGING
+#define CNAT_MY_VRFMAP_PRINT \
+PLATFORM_DEBUG_PRINT("i-uidx 0x%x o-uidx 0x%x i-vrfid 0x%x o-vrfid 0x%x\n" \
+ "status %d del time 0x%x tcp mss 0x%x pm list 0x%x\n" \
+ "bulk size %d\n" \
+ "ip n:1 %d\n" \
+ "NFV9 template index 0x%x\n" \
+ "SYSLOG template index 0x%x\n" \
+ "Netflow Session Logging %d \n" \
+ "Syslog Session Logging %d \n" \
+ "PCP Server 0x%x, Port %u \n", \
+ my_vrfmap->i_vrf, my_vrfmap->o_vrf, my_vrfmap->i_vrf_id, \
+ my_vrfmap->o_vrf_id, my_vrfmap->status, my_vrfmap->delete_time, \
+ my_vrfmap->tcp_mss, my_vrfmap->portmap_list, \
+ BULKSIZE_FROM_VRFMAP(my_vrfmap), \
+ my_vrfmap->ip_n_to_1, \
+ my_vrfmap->nfv9_logging_index, \
+ my_vrfmap->syslog_logging_index,\
+ my_vrfmap->nf_logging_policy, \
+ my_vrfmap->syslog_logging_policy, \
+ my_vrfmap->pcp_server_addr, \
+ my_vrfmap->pcp_server_port);
+#else
+#define CNAT_MY_VRFMAP_PRINT \
+PLATFORM_DEBUG_PRINT("i-uidx 0x%x o-uidx 0x%x i-vrfid 0x%x o-vrfid 0x%x\n" \
+ "status %d del time 0x%x tcp mss 0x%x pm list 0x%x\n" \
+ "NFV9 template index 0x%x\n ip n:1 %d\n", \
+ my_vrfmap->i_vrf, my_vrfmap->o_vrf, my_vrfmap->i_vrf_id, \
+ my_vrfmap->o_vrf_id, my_vrfmap->status, my_vrfmap->delete_time, \
+ my_vrfmap->tcp_mss, my_vrfmap->portmap_list, \
+ my_vrfmap->nfv9_logging_index, my_vrfmap->ip_n_to_1);
+#endif /* NO_BULK_LOGGING */
+
+#define CNAT_MY_LOGGING_INFO_PRINT \
+do { \
+ cnat_syslog_logging_info_t *my_syslog_info = 0; \
+ PLATFORM_DEBUG_PRINT("SYSLOG config: \n"); \
+ pool_foreach (my_syslog_info, cnat_syslog_logging_info_pool, ({ \
+ if (my_syslog_info->i_vrf == my_vrfmap->i_vrf) { \
+ PLATFORM_DEBUG_PRINT(" \
+ ipv4[0x%x], port[%u], hostname[%s]\n", \
+ my_syslog_info->ipv4_address, my_syslog_info->port, \
+ my_syslog_info->header_hostname); \
+ break; \
+ } \
+ })); \
+}while (0) \
+;
+
+
+void printf_ipv4(u32 ad)
+{
+ u8 a __attribute__((unused)), b __attribute__((unused)),
+ c __attribute__((unused)), d __attribute__((unused));
+
+ a = ad>>24;
+ b = (ad>>16) & 0xFF;
+ c = (ad>>8) & 0xFF;
+ d = (ad>>0) & 0xFF;
+
+ PLATFORM_DEBUG_PRINT("%d.%d.%d.%d", a, b, c, d);
+}
+void cnat_main_db_entry_dump (cnat_main_db_entry_t *db)
+{
+ PLATFORM_DEBUG_PRINT("Main DB entry at %p, index %ld dst_ip %x\n",
+ db, db - cnat_main_db, db->dst_ipv4);
+ /* only dump hash next index if it's non EMPTY */
+ if (db->out2in_hash.next != EMPTY || db->in2out_hash.next != EMPTY)
+ PLATFORM_DEBUG_PRINT("out2in hash %u, in2out hash %u\n",
+ db->out2in_hash.next,
+ db->in2out_hash.next);
+ PLATFORM_DEBUG_PRINT("out2in key ipv4 0x%08X, port 0x%04X (%5d), vrf %d, protocol %s\n",
+ db->out2in_key.k.ipv4,
+ db->out2in_key.k.port,
+ db->out2in_key.k.port,
+ db->out2in_key.k.vrf & CNAT_VRF_MASK,
+ (db->out2in_key.k.vrf & CNAT_PRO_MASK) == CNAT_UDP ? "UDP" :
+ ((db->in2out_key.k.vrf & CNAT_PRO_MASK) == CNAT_TCP ? "TCP" :
+ ((db->in2out_key.k.vrf & CNAT_PRO_MASK) == CNAT_ICMP ? "ICMP" : "PPTP ALG")));
+
+ PLATFORM_DEBUG_PRINT("in2out key ipv4 0x%08X, port 0x%04X (%5d), vrf %d, protocol %s\n",
+ db->in2out_key.k.ipv4,
+ db->in2out_key.k.port,
+ db->in2out_key.k.port,
+ db->in2out_key.k.vrf & CNAT_VRF_MASK,
+ (db->in2out_key.k.vrf & CNAT_PRO_MASK) == CNAT_UDP ? "UDP" :
+ ((db->in2out_key.k.vrf & CNAT_PRO_MASK) == CNAT_TCP ? "TCP" :
+ ((db->in2out_key.k.vrf & CNAT_PRO_MASK) == CNAT_ICMP ? "ICMP" : "UNKNOWN")));
+
+ PLATFORM_DEBUG_PRINT("user %d, user ports (nxt) %d (prev) %d, vrfmap_index 0x%x\n",
+ db->user_index, db->user_ports.next, db->user_ports.prev,
+ db->vrfmap_index);
+ PLATFORM_DEBUG_PRINT("timeout %d \n", db->timeout);
+ PLATFORM_DEBUG_PRINT("flags 0x%x ", db->flags);
+
+ if (db->flags & CNAT_DB_FLAG_TCP_ACTIVE) {
+ PLATFORM_DEBUG_PRINT(" TCP_ACTIVE ");
+ } else if (db->flags & CNAT_DB_FLAG_UDP_ACTIVE) {
+ PLATFORM_DEBUG_PRINT(" UDP_ACTIVE ");
+ } else if (db->flags & CNAT_DB_FLAG_STATIC_PORT) {
+ PLATFORM_DEBUG_PRINT(" STATIC_PORT ");
+ }
+
+ PLATFORM_DEBUG_PRINT(" ALG dlt0 0x%02X dlt1 0x%02X\n", db->alg.alg_dlt[0], db->alg.alg_dlt[1]);
+ PLATFORM_DEBUG_PRINT("\n");
+
+ PLATFORM_DEBUG_PRINT("out2in_pkts: %u\n", db->out2in_pkts);
+ PLATFORM_DEBUG_PRINT("in2out_pkts: %u\n", db->in2out_pkts);
+ PLATFORM_DEBUG_PRINT("entry_expires: %u current time: %u\n", db->entry_expires, cnat_current_time);
+ PLATFORM_DEBUG_PRINT("-------------------------\n");
+}
+
+void cnat_user_db_entry_dump (cnat_user_db_entry_t *up)
+{
+ u32 db_entry_index, first_db_entry_index;
+ cnat_main_db_entry_t *ep;
+
+ PLATFORM_DEBUG_PRINT("User DB entry at %p, index %ld\n",
+ up, up - cnat_user_db);
+ PLATFORM_DEBUG_PRINT("translation list head index %u, %u translations portmapindex 0x%x\n",
+ up->translation_list_head_index,
+ up->ntranslations, up->portmap_index);
+ PLATFORM_DEBUG_PRINT("source ipv4 0x%x, source port 0x%x, vrf %d\n",
+ up->key.k.ipv4,
+ up->key.k.port,
+ up->key.k.vrf);
+ first_db_entry_index = db_entry_index = up->translation_list_head_index;
+ if (first_db_entry_index != EMPTY) {
+ PLATFORM_DEBUG_PRINT("Port translation list:\n");
+ do {
+ PLATFORM_DEBUG_PRINT(" [%d]\n", db_entry_index);
+ ep = cnat_main_db + db_entry_index;
+ db_entry_index = ep->user_ports.next;
+ } while (first_db_entry_index != db_entry_index);
+ } else {
+ PLATFORM_DEBUG_PRINT("WARNING: empty translation list!\n");
+ }
+ PLATFORM_DEBUG_PRINT("-------------------------\n");
+}
+
+void cnat_user_db_entry_dump_summary (cnat_user_db_entry_t *up)
+{
+ u32 db_entry_index, first_db_entry_index;
+ u32 total_entries = 0;
+
+ PLATFORM_DEBUG_PRINT("User DB entry at %p, index %ld\n",
+ up, up - cnat_user_db);
+ PLATFORM_DEBUG_PRINT("translation list head index %u, %u translations portmapindex 0x%x\n",
+ up->translation_list_head_index,
+ up->ntranslations, up->portmap_index);
+ PLATFORM_DEBUG_PRINT("source ipv4 0x%x, source port 0x%x, vrf %d\n",
+ up->key.k.ipv4,
+ up->key.k.port,
+ up->key.k.vrf);
+ first_db_entry_index = db_entry_index = up->translation_list_head_index;
+ if (first_db_entry_index != EMPTY) {
+ PLATFORM_DEBUG_PRINT("Port translation list:\n");
+ do {
+ total_entries++;
+ } while (first_db_entry_index != db_entry_index);
+ PLATFORM_DEBUG_PRINT("TOTAL_ENTRIES: %d\n", total_entries);
+ } else {
+ PLATFORM_DEBUG_PRINT("WARNING: empty translation list!\n");
+ }
+ PLATFORM_DEBUG_PRINT("-------------------------\n");
+}
+
+/* for internal development and UT only */
+void cnat_db_dump_main_by_index (int argc, unsigned long *argv)
+{
+ u32 index, i, len;
+ u32 active_count, scan_count;
+
+ if (argc != 1) {
+ PLATFORM_DEBUG_PRINT("invalid input %d\n", argc);
+ return;
+ }
+
+ index = argv[0];
+
+ len = vec_len(cnat_main_db);
+
+ active_count = pool_elts(cnat_main_db);
+
+ if (index >= active_count) {
+ PLATFORM_DEBUG_PRINT("Index %u >= total active entries %u\n", index, active_count);
+ return;
+ }
+
+ scan_count = 0;
+ for (i=0; i< len; i++) {
+ if(pool_is_free_index(cnat_main_db, i)) continue;
+
+ if (index == scan_count) {
+ cnat_main_db_entry_dump(cnat_main_db + i);
+ break;
+ }
+ scan_count++;
+ }
+}
+
+void cnat_db_dump_main (int argc, unsigned long *argv)
+{
+ cnat_main_db_entry_t *db;
+
+ pool_foreach(db, cnat_main_db, ({
+ cnat_main_db_entry_dump(db);
+ }));
+}
+
+void cnat_db_dump_main_summary (int argc, unsigned long *argv)
+{
+ cnat_main_db_entry_t *db;
+ u32 num_entries = 0;
+
+ pool_foreach(db, cnat_main_db, ({
+ num_entries++;
+ }));
+
+ PLATFORM_DEBUG_PRINT("\nNum main entries %d\n", num_entries);
+}
+
+void cnat_db_dump_user (int argc, unsigned long *argv)
+{
+ cnat_user_db_entry_t *up;
+
+ pool_foreach(up, cnat_user_db, ({
+ cnat_user_db_entry_dump(up);
+ }));
+}
+
+void cnat_db_dump_user_summary (int argc, unsigned long *argv)
+{
+ cnat_user_db_entry_t *up;
+
+ pool_foreach(up, cnat_user_db, ({
+ cnat_user_db_entry_dump_summary(up);
+ }));
+}
+
+void cnat_db_dump_hashes (int argc, unsigned long *argv)
+{
+ int i;
+
+ PLATFORM_DEBUG_PRINT("Main DB out2in hash:\n");
+ for (i = 0; i < vec_len(cnat_out2in_hash); i++) {
+ if (cnat_out2in_hash[i].next != EMPTY) {
+ PLATFORM_DEBUG_PRINT("[%d]: %u\n", i, cnat_out2in_hash[i].next);
+ }
+ }
+ PLATFORM_DEBUG_PRINT("Main DB in2out hash:\n");
+ for (i = 0; i < vec_len(cnat_in2out_hash); i++) {
+ if (cnat_in2out_hash[i].next != EMPTY) {
+ PLATFORM_DEBUG_PRINT("[%d]: %u\n", i, cnat_in2out_hash[i].next);
+ }
+ }
+
+ PLATFORM_DEBUG_PRINT("User hash:\n");
+ for (i = 0; i < vec_len(cnat_user_hash); i++) {
+ if (cnat_user_hash[i].next != EMPTY) {
+ PLATFORM_DEBUG_PRINT("[%d]: %u\n", i, cnat_user_hash[i].next);
+ }
+ }
+ PLATFORM_DEBUG_PRINT("-------------------------\n");
+}
+
+
+#ifdef OLD_VRFMAP
+
+void cnat_db_dump_cdb (int argc, unsigned long *argv)
+{
+ int k;
+ int verbose=0;
+ int all = 0;
+
+ if (argc > 0) {
+ verbose = 1;
+ }
+
+ if (argc > 1) {
+ all = 1;
+ }
+
+ PLATFORM_DEBUG_PRINT ("%d vrfmap vectors \n", vec_len(cnat_portmap_by_vrf));
+
+ for (k = 0; k < vec_len(cnat_portmap_by_vrf); k++) {
+ PLATFORM_DEBUG_PRINT("index%d: status %d i_vrf 0x%x o_vrf 0x%x\n", k,
+ cnat_portmap_by_vrf[k].status,
+ cnat_portmap_by_vrf[k].i_vrf,
+ cnat_portmap_by_vrf[k].o_vrf);
+ cnat_db_dump_address_portmap(verbose, all,
+ cnat_portmaps[k],
+ cnat_portmaps_inuse[k]);
+ }
+}
+
+void cnat_db_dump_i_vrf (int argc, unsigned long *argv)
+{
+ u32 k;
+ u32 vrf =0;
+ int verbose=0;
+ int all = 0;
+
+ if (!argc) {
+ PLATFORM_DEBUG_PRINT("need vrf input ,return\n");
+ return;
+ }
+
+ if (argc > 0) {
+ vrf = argv[0];
+ }
+
+ if (argc > 1) {
+ verbose = 1;
+ }
+
+ if (argc > 2) {
+ all = 1;
+ }
+
+ PLATFORM_DEBUG_PRINT ("%d vrfmap vectors \n", vec_len(cnat_portmap_by_vrf));
+
+ for (k = 0; k < vec_len(cnat_portmap_by_vrf); k++) {
+ if (cnat_portmap_by_vrf[k].i_vrf == vrf) {
+ PLATFORM_DEBUG_PRINT("%d: i_vrf 0x%x o_vrf 0x%x\n", k,
+ cnat_portmap_by_vrf[k].i_vrf,
+ cnat_portmap_by_vrf[k].o_vrf);
+ cnat_db_dump_address_portmap(verbose, all,
+ cnat_portmaps[k],
+ cnat_portmaps_inuse[k]);
+ return;
+ }
+ }
+ PLATFORM_DEBUG_PRINT("not found\n");
+}
+
+void cnat_db_dump_o_vrf (int argc, unsigned long *argv)
+{
+ u32 k;
+ int verbose=0;
+ int all = 0;
+ u32 vrf =0;
+
+ if (!argc) {
+ PLATFORM_DEBUG_PRINT("need vrf input ,return\n");
+ return;
+ }
+
+ if (argc > 0) {
+ vrf = argv[0];
+ }
+
+ if (argc > 1) {
+ verbose = 1;
+ }
+
+ if (argc > 2) {
+ all = 1;
+ }
+
+ PLATFORM_DEBUG_PRINT ("%d vrfmap vectors \n", vec_len(cnat_portmap_by_vrf));
+
+ for (k = 0; k < vec_len(cnat_portmap_by_vrf); k++) {
+ if (cnat_portmap_by_vrf[k].o_vrf == vrf) {
+ PLATFORM_DEBUG_PRINT("index%d: status %d i_vrf 0x%x o_vrf 0x%x\n", k,
+ cnat_portmap_by_vrf[k].status,
+ cnat_portmap_by_vrf[k].i_vrf,
+ cnat_portmap_by_vrf[k].o_vrf);
+ cnat_db_dump_address_portmap(verbose, all,
+ cnat_portmaps[k],
+ cnat_portmaps_inuse[k]);
+ return;
+ }
+ }
+ PLATFORM_DEBUG_PRINT("not found\n");
+}
+#endif
+
+#ifdef TOBE_PORTED
+/* This does not seem to be used */
+void cnat_db_mem_usage_cmd (int argc, unsigned long *argv)
+{
+ pool_header_t * p;
+ _VEC *_v;
+ u32 bitmap_bytes=0, free_indices_bytes=0, vec_bytes=0, total_bytes=0;
+
+ if (cnat_main_db) {
+ p = pool_header(cnat_main_db);
+ if (p->free_bitmap) {
+ _v = _vec_find(p->free_bitmap);
+ bitmap_bytes = _v->alen;
+ } else {
+ bitmap_bytes = 0;
+ }
+ if (p->free_indices) {
+ _v = _vec_find(p->free_indices);
+ free_indices_bytes = _v->alen;
+ } else {
+ free_indices_bytes = 0;
+ }
+ _v = _vec_find(cnat_main_db);
+ vec_bytes = _v->alen;
+ } else {
+ vec_bytes = 0;
+ }
+
+ total_bytes = bitmap_bytes + free_indices_bytes + vec_bytes;
+
+ PLATFORM_DEBUG_PRINT ("Main DB: %d total bytes, %d bitmap, %d indices, %d vec\n",
+ total_bytes, bitmap_bytes, free_indices_bytes, vec_bytes);
+ PLATFORM_DEBUG_PRINT (" vector length %d\n", vec_len(cnat_main_db));
+
+ if (cnat_user_db) {
+ p = pool_header(cnat_user_db);
+ if (p->free_bitmap) {
+ _v = _vec_find(p->free_bitmap);
+ bitmap_bytes = _v->alen;
+ } else {
+ bitmap_bytes = 0;
+ }
+ if (p->free_indices) {
+ _v = _vec_find(p->free_indices);
+ free_indices_bytes = _v->alen;
+ } else {
+ free_indices_bytes = 0;
+ }
+ _v = _vec_find(cnat_user_db);
+ vec_bytes = _v->alen;
+ } else {
+ vec_bytes = 0;
+ }
+
+ total_bytes = bitmap_bytes + free_indices_bytes + vec_bytes;
+
+ PLATFORM_DEBUG_PRINT ("User DB: %d total bytes, %d bitmap, %d indices, %d vec\n",
+ total_bytes, bitmap_bytes, free_indices_bytes, vec_bytes);
+ PLATFORM_DEBUG_PRINT (" vector length %d\n", vec_len(cnat_user_db));
+
+ _v = _vec_find(cnat_out2in_hash);
+ PLATFORM_DEBUG_PRINT("out2in hash: %d total bytes\n", _v->alen);
+
+ _v = _vec_find(cnat_in2out_hash);
+ PLATFORM_DEBUG_PRINT("in2out hash: %d total bytes\n", _v->alen);
+}
+#endif
+
+static void print_server_ip_address (vlib_main_t *vm, u32 ip)
+{
+ unsigned char bytes[4];
+ bytes[0] = ip & 0xFF;
+ bytes[1] = (ip >> 8) & 0xFF;
+ bytes[2] = (ip >> 16) & 0xFF;
+ bytes[3] = (ip >> 24) & 0xFF;
+ vlib_cli_output(vm, "\tIP Address : %d.%d.%d.%d\n", bytes[0], bytes[1], bytes[2], bytes[3]);
+}
+
+void cnat_nfv9_show_collector (vlib_main_t *vm, cnat_nfv9_logging_info_t *my_nfv9_logging_info)
+{
+ nfv9_server_info_t *server = nfv9_server_info_pool +
+ my_nfv9_logging_info->server_index;
+#if 0
+ vlib_cli_output(vm,"\tVRF - 0x%x - %s\n", my_nfv9_logging_info->i_vrf,
+ my_nfv9_logging_info->deleted?"DELETED":"ACTIVE");
+#endif
+ print_server_ip_address(vm, clib_net_to_host_u32(server->ipv4_address));
+ vlib_cli_output(vm,"\tPort : %d\n", server->port);
+ vlib_cli_output(vm,"\tTimeout : %d\n", server->timeout_rate);
+ vlib_cli_output(vm,"\tRefresh Rate : %d\n", server->refresh_rate);
+ vlib_cli_output(vm,"\tMax Pkt Size : %d\n", my_nfv9_logging_info->max_length_minus_max_record_size);
+
+ return;
+}
+
+void cnat_db_dump_policy (int argc, unsigned long *argv)
+{
+
+ PLATFORM_CNAT_DB_DUMP_POLICY_PRINT();
+
+ if (cnat_nfv9_global_info.cnat_nfv9_init_done) {
+ if (cnat_nfv9_global_info.cnat_nfv9_global_collector_index != EMPTY) {
+ cnat_nfv9_logging_info_t *my_nfv9_logging_info;
+ nfv9_server_info_t *server __attribute__((unused));
+
+ my_nfv9_logging_info = cnat_nfv9_logging_info_pool +
+ cnat_nfv9_global_info.cnat_nfv9_global_collector_index;
+ server = nfv9_server_info_pool +
+ my_nfv9_logging_info->server_index;
+
+ PLATFORM_DEBUG_PRINT("NFv9 logging ip 0x%x port 0x%x refresh-rate %d timeout %d\n",
+ server->ipv4_address,
+ server->port,
+ server->refresh_rate,
+ server->timeout_rate);
+ PLATFORM_DEBUG_PRINT("NFv9 path_mtu = %d\n",
+ my_nfv9_logging_info->max_length_minus_max_record_size);
+ } else {
+ PLATFORM_DEBUG_PRINT("NFv9 global logging is not configured\n");
+ }
+ } else {
+ PLATFORM_DEBUG_PRINT("NFv9 LOGGING is not configured\n");
+ }
+
+}
+
+#ifdef OLD_VRFMAP
+void cnat_show_cdb (int verbose)
+{
+ int k, l, i;
+ for (i = 0; i < vec_len(cnat_portmap_by_vrf); i++) {
+ PLATFORM_DEBUG_PRINT("i_vrf %d : o_vrf %d\n",
+ cnat_portmap_by_vrf[i].i_vrf,
+ cnat_portmap_by_vrf[i].o_vrf);
+ }
+
+ PLATFORM_DEBUG_PRINT("port limit %d\n", cnat_main_db_max_ports_per_user);
+
+ PLATFORM_DEBUG_PRINT ("%d portmap vectors\n", vec_len(cnat_portmaps));
+
+ for (k = 0; k < vec_len(cnat_portmaps); k++) {
+ cnat_portmap_t *pm;
+ u16 *inuse;
+ pm = cnat_portmaps[k];
+ inuse = cnat_portmaps_inuse[k];
+ for (l = 0; l < vec_len(pm); l++) {
+ if (inuse[l] || verbose ) {
+ u32 net_address;
+ net_address =
+ spp_host_to_net_byte_order_32((pm+l)->ipv4_address);
+ printf_ipv4(net_address);
+ PLATFORM_DEBUG_PRINT (": %d inuse\n", inuse[l]);
+ if (verbose && inuse[l]) {
+ cnat_portmap_dump (pm+l, inuse+l);
+ }
+ }
+ }
+ }
+}
+#endif
+
+
+
+/* v2 show command */
+void cnat_show_address_portmap_sumary (cnat_portmap_v2_t *pm)
+{
+ cnat_portmap_v2_t *my_pm =0;
+ u32 first_address = 0;
+ u32 second_address = 0;
+ u32 last_address = 0;
+ u32 i, pm_len;
+
+ if ((pm_len = vec_len(pm))) {
+ PLATFORM_DEBUG_PRINT("%d portmap in this list 0x%lx\n",
+ pm_len, (u32)pm);
+ for (i = 0; i < pm_len; i++) {
+ my_pm = pm + i;
+ if (!first_address) {
+ first_address = my_pm->ipv4_address;
+ } else if (!second_address) {
+ second_address = my_pm->ipv4_address;
+ }
+ last_address = my_pm->ipv4_address;
+ }
+
+ if (first_address) {
+ PLATFORM_DEBUG_PRINT("1. 0x%08x", first_address);
+ }
+ if (second_address) {
+ PLATFORM_DEBUG_PRINT(", 2. 0x%08x", second_address);
+ }
+
+ if ((last_address != first_address) &&
+ (last_address != second_address)) {
+ PLATFORM_DEBUG_PRINT(", ....., %d. 0x%08x", pm_len, last_address);
+ }
+ PLATFORM_DEBUG_PRINT("\n");
+ } else {
+ PLATFORM_DEBUG_PRINT("ZERO POOL ADDRESSES in this list 0x%x \n", (u32)pm);
+ }
+}
+
+
+void cnat_show_address_portmap (int verbose, int all,
+ cnat_portmap_v2_t *pm, u16 port_limit)
+{
+ cnat_portmap_v2_t *my_pm =0;
+ u32 i, pm_len;
+
+ pm_len = vec_len(pm);
+ if (!all) {
+ cnat_show_address_portmap_sumary(pm);
+ } else {
+ PLATFORM_DEBUG_PRINT("%d portmap in this list 0x%x \n", pm_len, (u32)pm);
+ }
+
+ for (i = 0; i < pm_len; i++) {
+
+ my_pm = pm + i;
+ if (all) {
+ PLATFORM_DEBUG_PRINT("pm:0x%x ip address:0x%x del_time 0x%x inuse:%d\n",
+ (u32)my_pm, my_pm->ipv4_address, my_pm->delete_time, my_pm->inuse);
+ } else if (my_pm->inuse) {
+ PLATFORM_DEBUG_PRINT("pm:0x%x ip address:0x%x inuse:%d\n",
+ (u32)my_pm, my_pm->ipv4_address, my_pm->inuse);
+ }
+
+ if (verbose && (my_pm->inuse)) {
+ if(PREDICT_FALSE(!port_limit)) {
+ cnat_portmap_dump_v2 (my_pm, cnat_main_db_max_ports_per_user);
+ }
+ else {
+ cnat_portmap_dump_v2 (my_pm, port_limit);
+ }
+ }
+ }
+
+ PLATFORM_DEBUG_PRINT("\n");
+}
+
+
+void cnat_show_cdb_v2 (int verbose, int all)
+{
+ cnat_vrfmap_t *my_vrfmap = 0;
+ cnat_portmap_v2_t *pm =0;
+ PLATFORM_DEBUG_PRINT("port limit %d\n", cnat_main_db_max_ports_per_user);
+ PLATFORM_DEBUG_PRINT("total address pool allocated %d\n", total_address_pool_allocated);
+ PLATFORM_DEBUG_PRINT("icmp rate limit %d (per core %d)\n",
+ cnat_main_db_icmp_rate_limit, cnat_main_db_icmp_rate_limit_core);
+ PLATFORM_DEBUG_PRINT("dynamic port range start %d\n", cnat_static_port_range);
+ if (pptp_cfg.enable == PPTP_DISABLED) {
+ PLATFORM_DEBUG_PRINT("PPTP alg disabled \n");
+ } else {
+ PLATFORM_DEBUG_PRINT("PPTP alg enabled \n");
+ }
+
+ if (ftp_alg_enabled) {
+ PLATFORM_DEBUG_PRINT("FTP alg enabled\n");
+ } else {
+ PLATFORM_DEBUG_PRINT("FTP alg disabled\n");
+ }
+
+ pool_foreach (my_vrfmap, cnat_map_by_vrf, ({
+ CNAT_MY_VRFMAP_PRINT
+ CNAT_MY_LOGGING_INFO_PRINT
+ PLATFORM_DEBUG_PRINT("per vrf port limit %d\n", my_vrfmap->port_limit);
+ pm = my_vrfmap->portmap_list;
+ cnat_show_address_portmap(verbose, all, pm, my_vrfmap->port_limit);
+
+ }));
+}
+
+
+void cnat_show_cdb_command_v2(int argc, unsigned long *argv)
+{
+ int verbose=0;
+ int all = 0;
+
+ if (argc > 0) {
+ verbose = 1;
+ }
+
+ if (argc > 1) {
+ all = 1;
+ }
+
+ cnat_show_cdb_v2(verbose, all);
+}
+
+void cnat_show_ivrf_command_v2 (int argc, unsigned long *argv)
+{
+ u32 vrf =0;
+ int verbose=0;
+ int all = 0;
+ cnat_vrfmap_t *my_vrfmap = 0;
+ cnat_portmap_v2_t *pm =0;
+
+ if (!argc) {
+ PLATFORM_DEBUG_PRINT("need vrf input ,return\n");
+ return;
+ }
+ if (argc > 0) {
+ vrf = argv[0];
+ }
+ if (argc > 1) {
+ verbose = 1;
+ }
+ if (argc > 2) {
+ all = 1;
+ }
+ PLATFORM_DEBUG_PRINT ("%lld vrfmap vectors \n", pool_elts(cnat_map_by_vrf));
+ pool_foreach (my_vrfmap, cnat_map_by_vrf, ({
+ if (my_vrfmap->i_vrf == vrf) {
+ CNAT_MY_VRFMAP_PRINT
+ pm = my_vrfmap->portmap_list;
+ cnat_show_address_portmap(verbose, all, pm,my_vrfmap->port_limit);
+ return;
+ }
+ }));
+ PLATFORM_DEBUG_PRINT("not found\n");
+}
+
+void cnat_show_ovrf_command_v2 (int argc, unsigned long *argv)
+{
+ u32 not_found =1;
+ u32 vrf =0;
+ int verbose=0;
+ int all = 0;
+ cnat_vrfmap_t *my_vrfmap = 0;
+ cnat_portmap_v2_t *pm =0;
+
+ if (!argc) {
+ PLATFORM_DEBUG_PRINT("need vrf input ,return\n");
+ return;
+ }
+ if (argc > 0) {
+ vrf = argv[0];
+ }
+ if (argc > 1) {
+ verbose = 1;
+ }
+ if (argc > 2) {
+ all = 1;
+ }
+ PLATFORM_DEBUG_PRINT("%d vrfmap vectors \n", pool_elts(cnat_map_by_vrf));
+ pool_foreach (my_vrfmap, cnat_map_by_vrf, ({
+ if (my_vrfmap->o_vrf == vrf) {
+ CNAT_MY_VRFMAP_PRINT
+ pm = my_vrfmap->portmap_list;
+ cnat_show_address_portmap(verbose, all, pm,my_vrfmap->port_limit);
+ not_found = 0;
+ }
+ }));
+ if (not_found) {
+ PLATFORM_DEBUG_PRINT("not found\n");
+ }
+}
+
+void cnat_timeout_db_entry_dump (cnat_timeout_db_entry_t *up)
+{
+ u32 db_entry_index __attribute__((unused)),
+ first_db_entry_index __attribute__((unused));
+
+ PLATFORM_DEBUG_PRINT("Timeout DB entry at index %ld\n", up - cnat_timeout_db);
+ PLATFORM_DEBUG_PRINT("Desnt key 0x%16llx\n", up->t_key.timeout_key.key64);
+ PLATFORM_DEBUG_PRINT("Timeout value %d\n", up->t_key.timeout_value);
+ PLATFORM_DEBUG_PRINT("Hash Next 0x%x\n", up->t_hash.next);
+
+}
+
+void cnat_db_dump_timeout ()
+{
+ cnat_timeout_db_entry_t *up;
+ pool_header_t *h;
+ u32 used __attribute__((unused)), free __attribute__((unused));
+
+ h = pool_header(cnat_timeout_db);
+ free = vec_len(h->free_indices);
+ used = (vec_len(cnat_timeout_db) - free);
+
+ PLATFORM_DEBUG_PRINT("Timeout DB Free %d, Used %d\n",free, used);
+
+ pool_foreach(up, cnat_timeout_db, ({
+ cnat_timeout_db_entry_dump(up);
+ }));
+}
+
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_show_api.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_show_api.h
new file mode 100644
index 00000000..5904c7e2
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_show_api.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef __CNAT_SHOW_API_H__
+#define __CNAT_SHOW_API_H__
+
+typedef struct _spp_api_cnat_v4_show_inside_entry_req {
+ u16 _spp_msg_id;
+ u16 vrf_id;
+ u32 ipv4_addr;
+ u16 start_port;
+ u16 end_port;
+ u8 flags;
+ u8 all_entries;
+ u8 protocol;
+} spp_api_cnat_v4_show_inside_entry_req_t;
+
+typedef struct _spp_api_cnat_v4_show_outside_entry_req {
+ u16 _spp_msg_id;
+ u16 vrf_id;
+ u32 ipv4_addr;
+ u16 start_port;
+ u16 end_port;
+ u8 flags;
+ u8 protocol;
+} spp_api_cnat_v4_show_outside_entry_req_t;
+
+
+#endif
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_show_response.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_show_response.h
new file mode 100644
index 00000000..bec1bd97
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_show_response.h
@@ -0,0 +1,580 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_show_response.h show command response structs
+ *
+ * Copyright (c) 2007-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_SHOW_RESPONSE_H__
+#define __CNAT_SHOW_RESPONSE_H__
+
+/*
+ * Flags indicating the type of translation entry
+ */
+#define CNAT_TRANSLATION_ENTRY_ALL 0x0
+#define CNAT_TRANSLATION_ENTRY_STATIC 0x1
+#define CNAT_TRANSLATION_ENTRY_ALG 0x2
+#define CNAT_TRANSLATION_ENTRY_DYNAMIC 0x4
+
+/* for PCP support */
+#define CNAT_TRANSLATION_ENTRY_PCPI_DYNAMIC 0x08
+#define CNAT_TRANSLATION_ENTRY_PCPE_DYNAMIC 0x10
+
+#define MAX_NODE_NAME_LEN 18
+#define MAX_CTR_NAME_LEN 10
+
+/*
+ * show translation entry response structures
+ */
+typedef struct {
+ u16 call_id;
+ u16 cnat_call_id; /* mapped call Id */
+ u16 dst_call_id; /* dest call id */
+} cnat_v4_show_gre_entry;
+
+typedef struct {
+ u16 msg_id;
+ u16 rc; /* o/p parameter. */
+ u16 num_entries; /* Number of entries sent as output */
+ u16 vrf_id; /* vrf id */
+ u32 pns_ip;
+ cnat_v4_show_gre_entry entries[0];
+} cnat_v4_show_gre_entry_resp;
+
+/*
+ * show translation entry response structures
+ */
+typedef struct {
+ u32 ipv4_addr;
+ u16 src_port;
+ u16 cnat_port; /* port which replaced the src port */
+ u8 protocol;
+ u8 pad;
+ u16 flags;
+ u16 nsessions;
+ u32 in2out_packets;
+ u32 out2in_packets;
+} cnat_v4_show_translation_entry;
+
+typedef struct {
+ u16 msg_id;
+ u8 rc; /* o/p parameter. */
+ u8 num_entries; /* Number of entries sent as output */
+ u16 vrf_id; /* vrf id */
+ u16 pad;
+ cnat_v4_show_translation_entry entries[0];
+} cnat_v4_show_entry_resp;
+
+/*
+ * show free/used ipv4 address/port response structure
+ */
+typedef struct {
+ u32 ip_addr;
+ u32 free_used_ports;
+} cnat_v4_show_free_used_entry;
+
+typedef struct {
+ u16 msg_id;
+ u8 rc;
+ u8 count;
+ u32 max_ports;
+ cnat_v4_show_free_used_entry entry_list[0];
+} cnat_v4_show_free_used_entry_resp;
+
+/*
+ * Node name to id mapping
+ */
+typedef struct {
+ u8 node_id;
+ u8 pad;
+ char node_name[MAX_NODE_NAME_LEN];
+} cnat_statistics_node_name;
+
+typedef struct {
+ u16 msg_id;
+ u8 rc;
+ u8 num_nodes;
+ cnat_statistics_node_name node_name_array[0];
+} cnat_statistics_node_name_mapping_resp;
+
+/*
+ * Counter name to id mapping
+ */
+typedef struct {
+ u8 node_id;
+ u8 counter_id;
+ char counter_name[MAX_CTR_NAME_LEN];
+} cnat_statistics_counter_name;
+
+typedef struct {
+ u16 msg_id;
+ u8 rc;
+ u8 num_counters;
+ cnat_statistics_counter_name counter_name_array[0];
+} cnat_statistics_counter_name_mapping_resp;
+
+
+/*
+ * Node name to id mapping
+ */
+typedef struct {
+ u16 msg_id;
+ u8 rc;
+ u8 num_nodes;
+ u32 pad;
+ u64 counters [0];
+} cnat_statistics_counter_values;
+
+/*
+ * Summary Stats
+ */
+typedef struct {
+ u32 eaddr;
+ u32 ports_used;
+} pool_address_usage_t;
+
+typedef struct {
+ u16 msg_id;
+ u8 rc;
+ u8 pad;
+ u16 max_pkt_size;
+ u16 pool_address_copied;
+ u32 active_translations;
+ u32 translation_create_rate;
+ u32 translation_delete_rate;
+ u32 in2out_forwarding_rate;
+ u32 out2in_forwarding_rate;
+ u32 dummy;
+ u64 in2out_drops_port_limit_exceeded;
+ u64 in2out_drops_system_limit_reached;
+ u64 in2out_drops_resource_depletion;
+ u64 no_translation_entry_drops;
+ u64 pptp_active_tunnels;
+ u64 pptp_active_channels;
+ u64 pptp_ctrlmsg_drops;
+ u32 no_sessions;
+
+ u32 pool_address_totally_free;
+ u32 pool_address_used; /* The following array size will be lesser of
+ (pool_address_used, 200) */
+ u32 num_subscribers;
+ u64 drops_sessiondb_limit_exceeded;
+ u64 in2out_drops_src_ip_no_config; // for deterministic nat on brahmos
+ pool_address_usage_t pool_address_usage[0];
+} cnat_show_statistics_summary_resp;
+
+
+typedef struct {
+ u16 msg_id;
+ u8 rc;
+ u8 pad;
+ u64 o2i_tcp_seq_mismatch_drop;
+ u64 o2i_tcp_seq_mismatch;
+ u64 o2i_sessions_created;
+ u64 o2i_end_point_filter_drop;
+} cnat_show_counters_summary_resp;
+
+
+typedef struct {
+ u16 msg_id;
+ u8 rc;
+ u8 pad;
+
+ /*
+ * XLAT statistics
+ */
+ u64 v6_to_v4_tcp_input_count;
+ u64 v6_to_v4_tcp_non_translatable_drop_count;
+ u64 v6_to_v4_tcp_invalid_next_hdr_drop_count;
+ u64 v6_to_v4_tcp_no_db_drop_count;
+ u64 v6_to_v4_tcp_output_count;
+
+ u64 v4_to_v6_tcp_input_count;
+ u64 v4_to_v6_tcp_no_db_drop_count;
+ u64 v4_to_v6_tcp_output_count;
+
+ u64 v6_to_v4_udp_input_count;
+ u64 v6_to_v4_udp_non_translatable_drop_count;
+ u64 v6_to_v4_udp_invalid_next_hdr_drop_count;
+ u64 v6_to_v4_udp_no_db_drop_count;
+ u64 v6_to_v4_udp_output_count;
+
+ u64 v4_to_v6_udp_input_count;
+ u64 v4_to_v6_udp_no_db_drop_count;
+ u64 v4_to_v6_udp_output_count;
+ u64 v4_to_v6_udp_frag_crc_zero_drop_count;
+ u64 v4_to_v6_udp_crc_zero_recycle_sent_count;
+ u64 v4_to_v6_udp_crc_zero_recycle_drop_count;
+
+ u64 v6_to_v4_icmp_qry_input_count;
+ u64 v6_to_v4_icmp_no_db_drop_count;
+ u64 v6_to_v4_icmp_frag_drop_count;
+ u64 v6_to_v4_icmp_invalid_next_hdr_drop_count;
+ u64 v6_to_v4_icmp_non_translatable_drop_count;
+ u64 v6_to_v4_icmp_non_translatable_fwd_count;
+ u64 v6_to_v4_icmp_unsupported_type_drop_count;
+ u64 v6_to_v4_icmp_err_output_count;
+ u64 v6_to_v4_icmp_qry_output_count;
+
+ u64 v4_to_v6_icmp_qry_input_count;
+ u64 v4_to_v6_icmp_no_db_drop_count;
+ u64 v4_to_v6_icmp_frag_drop_count;
+ u64 v4_to_v6_icmp_unsupported_type_drop_count;
+ u64 v4_to_v6_icmp_err_output_count;
+ u64 v4_to_v6_icmp_qry_output_count;
+
+ u64 v6_to_v4_subsequent_frag_input_count;
+ u64 v6_to_v4_subsequent_frag_non_translatable_drop_count;
+ u64 v6_to_v4_subsequent_frag_invalid_next_hdr_drop_count;
+ u64 v6_to_v4_subsequent_frag_no_db_drop_count;
+ u64 v6_to_v4_subsequent_frag_output_count;
+
+ u64 v4_to_v6_subsequent_frag_input_count;
+ u64 v4_to_v6_subsequent_frag_no_db_drop_count;
+ u64 v4_to_v6_subsequent_frag_output_count;
+
+ u64 v4_to_v6_subsequent_frag_drop_count;
+ u64 v4_to_v6_subsequent_frag_throttled_count;
+ u64 v4_to_v6_subsequent_frag_timeout_drop_count;
+ u64 v4_to_v6_subsequent_frag_tcp_input_count;
+ u64 v4_to_v6_subsequent_frag_udp_input_count;
+ u64 v4_to_v6_subsequent_frag_icmp_input_count;
+
+ u64 v6_to_v4_options_input_count;
+ u64 v6_to_v4_options_drop_count;
+ u64 v6_to_v4_options_forward_count;
+ u64 v6_to_v4_options_no_db_drop_count;
+ u64 v6_to_v4_unsupp_proto_count;
+
+ u64 v4_to_v6_options_input_count;
+ u64 v4_to_v6_options_drop_count;
+ u64 v4_to_v6_options_forward_count;
+ u64 v4_to_v6_options_no_db_drop_count;
+ u64 v4_to_v6_unsupp_proto_count;
+
+ u64 v4_icmp_gen_count;
+ u64 v6_icmp_gen_count;
+} xlat_show_statistics_summary_resp;
+
+typedef struct {
+ u16 msg_id;
+ u8 rc;
+ u8 pad;
+ /* Total v4 packets to BR */
+ u64 v4_to_v6_input_total_count;
+ /* Total v4 tunneled packets to BR */
+ u64 v4_to_v6_41_input_total_count;
+ /* proto 41 packets without minimum, of 40, v6 payload */
+ u64 v4_to_v6_41_insuff_v6payld_count;
+ /* total proto 41 packets being considered for decap */
+ u64 v4_to_v6_41_valid_count;
+ /* proto 41 packets that failed security check*/
+ u64 v4_to_v6_41_sec_check_fail_count;
+ /* packets with no active db entry */
+ u64 v4_to_v6_no_db_drop_count;
+ /* proto 41 packets actually getting decapped */
+ u64 v4_to_v6_41_decap_count;
+ /* total v4 packets which are neither icmp nor 41 */
+ u64 v4_to_v6_unsupported_protocol_count;
+ /* v4 tunneled packets with invalid v6 source address */
+ u64 v4_to_v6_41_invalid_v6_source;
+ /* total icmpv4 packets destined to BR */
+ u64 v4_forus_icmp_input_count;
+ /* total icmpv4 echo replies by BR */
+ u64 v4_icmp_reply_count;
+ /* total icmpv4 error messages translated to icmpv6 by BR */
+ u64 v4_to_v6_icmp_translation_count;
+ /* total packets with icmpv4 type/code which are not supported by BR */
+ u64 v4_icmp_unsupported_count;
+ /* total icmpv4 packets which are rate-limited by BR */
+ u64 v4_icmp_throttled_count;
+ /* total ICMPv4 error messages which could not be translated */
+ u64 v4_icmp_non_translatable_drop_count;
+
+ /* ipv4 defrag stats */
+ u64 v4_to_v6_frag_input_count;
+ u64 v4_to_v6_frag_sec_check_fail_count;
+ u64 v4_to_v6_frag_reassem_count;
+ u64 v4_to_v6_frag_timeout_drop_count;
+ u64 v4_to_v6_frag_icmp_input_count;
+ u64 v4_to_v6_frag_41_insuff_v6payld_count;
+ u64 v4_to_v6_frag_no_db_drop_count;
+ u64 v4_to_v6_frag_unsupported_protocol_count;
+ u64 v4_to_v6_frag_41_invalid_v6_source;
+ u64 v4_to_v6_frag_throttled_count;
+ u64 v4_to_v6_frag_dup_count;
+ u64 v4_to_v6_frag_reassem_frag_count;
+ u64 v4_to_v6_frag_disable_count;
+ u64 v4_to_v6_frag_drop_count;
+
+ /* total v6 packets input to BR */
+ u64 v6_to_v4_total_input_count;
+ /* v6 packets with no active db entry */
+ u64 v6_to_v4_no_db_drop_count;
+ /* forus v6 packets with next header other than icmpv6 */
+ u64 v6_to_v4_forus_unsupp_proto_count;
+ /* total v6 packets that got tunneled */
+ u64 v6_to_v4_encap_count;
+ /* total icmpv6 packets destined to BR */
+ u64 v6_forus_icmp_input_count;
+ /* total icmpv6 echo replies by BR */
+ u64 v6_icmp_reply_count;
+ /* total icmpv6 PTB messages generated by BR */
+ u64 v6_ptb_generated_count;
+ /* total ipv6 packets for which PTBv6 was NOT generated by BR */
+ u64 v6_ptb_not_generated_drop_count;
+ /* total icmpv6 Neighbor Advertisements generated by BR */
+ u64 v6_na_generated_count;
+ /* total icmpv6 TTL expiry messages generated by BR */
+ u64 v6_ttl_expiry_generated_count;
+ /* total ICMPv6 fragments, which are dropped by BR */
+ u64 v6_to_v4_frag_icmp_input_count;
+ /* total packets with icmpv6 type/code which are not supported by BR */
+ u64 v6_icmp_unsupported_count;
+ /* total icmpv6 packets which are rate-limited by BR */
+ u64 v6_icmp_throttled_count;
+} v6rd_show_statistics_summary_resp;
+
+typedef struct {
+ u16 msg_id;
+ u8 rc;
+ u8 pad;
+
+ /* Total Incoming Count */
+ u64 v4_input_count;
+ /* Total Drop Count */
+ u64 v4_drop_count;
+ /* Total Output Count */
+ u64 v4_to_v6_output_count;
+ /* TCP Incoming Count */
+ u64 v4_tcp_input_count;
+ /* TCP Output Count */
+ u64 v4_tcp_output_count;
+ /* UDP Incoming Count */
+ u64 v4_udp_input_count;
+ /* UDP Output Count */
+ u64 v4_udp_output_count;
+ /* ICMPv4 Incoming Count */
+ u64 v4_icmp_input_count;
+ /* ICMPv4 Output Count */
+ u64 v4_to_v6_icmp_output_count;
+ /* Invalid UIDB Drop Count */
+ u64 v4_invalid_uidb_drop_count;
+ /* NoDb Drop Count */
+ u64 v4_no_db_drop_count;
+ /* TTL Expire Drop Count */
+ u64 v4_ttl_expire_drop_count;
+ /* Invalid IP Destination Drop Count */
+ u64 v4_invalid_destination_prefix_drop_count;
+ /* Packet Execeeding Path MTU Drop Count */
+ u64 v4_path_mtu_exceed_count;
+ /* Unsupported Protocol Drop Count */
+ u64 v4_invalid_proto_type_drop_count;
+ /* ICMPv4 Generated for TTL Expire Count */
+ u64 v4_ttl_expiry_generated_count;
+ /* ICMPv4 Generated for Error Count */
+ u64 v4_icmp_error_gen_count;
+ /* ICMPv4 Packets Rate-Limited Count */
+ u64 v4_icmp_throttled_drop_count;
+ /* TCP MSS Changed Count */
+ u64 v4_tcp_mss_changed_count;
+
+ /* Total Incoming Count */
+ u64 v6_input_count;
+ /* Total Drop Count */
+ u64 v6_drop_count;
+ /* Total Output Count */
+ u64 v6_to_v4_output_count;
+ /* TCP Incoming Count */
+ u64 v6_tcp_input_count;
+ /* TCP Output Count */
+ u64 v6_tcp_output_count;
+ /* UDP Incoming Count */
+ u64 v6_udp_input_count;
+ /* UDP Output Count */
+ u64 v6_udp_output_count;
+ /* ICMPv4 Incoming Count */
+ u64 v6_icmpv4_input_count;
+ /* ICMPv4 Output Count */
+ u64 v6_icmpv4_output_count;
+ /* Invalid UIDB Drop Count */
+ u64 v6_invalid_uidb_drop_count;
+ /* NoDb Drop Count */
+ u64 v6_no_db_drop_count;
+ /* TTL Expire Drop Count */
+ u64 v6_ttl_expire_drop_count;
+ /* Invalid IPv6 Destination Drop Count */
+ u64 v6_invalid_destination_drop_count;
+ /* Invalid Source Prefix Drop Count */
+ u64 v6_invalid_source_prefix_drop_count;
+ /* Unsupported Protocol Drop Count */
+ u64 v6_invalid_proto_type_drop_count;
+ /* ICMPv6 Input Count */
+ u64 v6_icmp_input_count;
+ /* ICMPv6 Invalid UIDB Drop Count */
+ u64 v6_icmp_invalid_uidb_drop_count;
+ /* ICMPv6 NoDb Drop Count */
+ u64 v6_icmp_no_db_drop_count;
+ /* ICMPv6 TTL Expire Drop Count */
+ u64 v6_icmp_ttl_expire_drop_count;
+ /* ICMPv6 Invalid IPv6 Destination Drop Count */
+ u64 v6_icmp_invalid_destination_drop_count;
+ /* ICMPv6 Unsupported Type Drop Count */
+ u64 v6_icmp_unsupported_type_drop_count;
+ /* ICMPv6 Invalid NxtHdr Drop Count*/
+ u64 v6_icmp_unsupported_nxthdr_drop_count;
+ /* ICMPv6 Frag Drop Count */
+ u64 v6_icmp_frag_drop_count;
+ /* ICMPv6 Forus Count */
+ u64 v6_forus_icmp_input_count;
+ /* ICMPv6 Echo Response Received Count */
+ u64 v6_received_echo_response_count;
+ /* ICMPv6 Echo Replies Count */
+ u64 v6_echo_reply_count;
+ /* ICMPv6 Translated to ICMPV4 Output Count*/
+ u64 v6_to_v4_icmp_output_count;
+ /* ICMPv6 Generated for TTL Expire Count */
+ u64 v6_ttl_expiry_generated_count;
+ /* ICMPv6 Generated for Error Count */
+ u64 v6_icmp_error_gen_count;
+ /* ICMPv6 Packets Rate-Limited Count */
+ u64 v6_icmp_throttled_drop_count;
+ /* TCP MSS Changed Count */
+ u64 v6_tcp_mss_changed_count;
+
+ /*Total Input Count*/
+ u64 v4_to_v6_frag_input_count;
+ /*Total Drop Count*/
+ u64 v4_to_v6_frag_drop_count;
+ /*Reassembled Output Count*/
+ u64 v4_to_v6_frag_reassem_count;
+
+ /*TCP Input Count*/
+ u64 v4_to_v6_frag_tcp_input_count;
+ /*UDP Input Count*/
+ u64 v4_to_v6_frag_udp_input_count;
+ /*ICMPv4 Input Count*/
+ u64 v4_to_v6_frag_icmp_input_count;
+
+ /*Invalid UIDB Drop Count */
+ u64 v4_to_v6_frag_invalid_uidb_drop_count;
+ /*NoDb Drop Count*/
+ u64 v4_to_v6_frag_no_db_drop_count;
+ /*Unsupported Protocol Drop Count*/
+ u64 v4_to_v6_frag_invalid_proto_type_drop_count;
+ /*Throttled Count*/
+ u64 v4_to_v6_frag_throttled_count;
+ /*Timeout Drop Count*/
+ u64 v4_to_v6_frag_timeout_drop_count;
+ /*Duplicates Drop Count*/
+ u64 v4_to_v6_frag_dup_count;
+
+ /*Total Input Count*/
+ u64 v6_to_v4_inner_frag_input_count;
+ /*Total Drop Count*/
+ u64 v6_to_v4_inner_frag_drop_count;
+ /*Total Output Count*/
+ u64 v6_to_v4_inner_frag_output_count;
+
+ /*TCP Input Count*/
+ u64 v6_to_v4_inner_frag_tcp_input_count;
+ /*UDP Input Count*/
+ u64 v6_to_v4_inner_frag_udp_input_count;
+ /*ICMPv4 Input Count*/
+ u64 v6_to_v4_inner_frag_icmp_input_count;
+
+ /*Invalid Source Prefix Drop Count*/
+ u64 v6_to_v4_inner_frag_invalid_source_prefix_drop_count;
+ /*Unsupported Protocol Drop Count*/
+ u64 v6_to_v4_inner_frag_invalid_proto_type_drop_count;
+ /*Throttled Count*/
+ u64 v6_to_v4_inner_frag_throttled_count;
+ /*Timeout Drop Count*/
+ u64 v6_to_v4_inner_frag_timeout_drop_count;
+ /*Duplicates Drop Count*/
+ u64 v6_to_v4_inner_frag_dup_count;
+
+ /*ICMPv6 Generated for Error Count */
+ u64 v6_to_v4_inner_frag_icmp_error_gen_count;
+ /*ICMPv6 Packets Rate-Limited Count */
+ u64 v6_to_v4_inner_frag_icmp_throttled_drop_count;
+
+ /*TCP MSS Changed Count */
+ u64 v6_to_v4_inner_frag_tcp_mss_changed_count;
+
+} mape_show_statistics_summary_resp;
+
+/*
+ * The following are the command types for Generic Command cases
+ */
+#define CNAT_DEBUG_GENERIC_COMMAND_READ_MEM 1
+#define CNAT_DEBUG_GENERIC_COMMAND_WRITE_MEM 2
+#define CNAT_DEBUG_GENERIC_COMMAND_DB_SUMMARY 3
+#define CNAT_DEBUG_GENERIC_COMMAND_USER_DB_PM 4
+#define CNAT_DEBUG_GET_CGN_DB_SUMMARY 5
+
+typedef enum {
+ CNAT_DEBUG_GENERIC_COMMAND_DUMP_POLICY,
+ CNAT_DEBUG_GENERIC_COMMAND_DUMP_MAIN_DB,
+ CNAT_DEBUG_GENERIC_COMMAND_DUMP_USER_DB,
+ CNAT_DEBUG_GENERIC_COMMAND_DUMP_HASHES_DB,
+ CNAT_DEBUG_GENERIC_COMMAND_DUMP_VRF_MAP,
+ CNAT_DEBUG_GENERIC_COMMAND_DUMP_SUMMARY_DB,
+ CNAT_DEBUG_GENERIC_COMMAND_DUMP_STATS,
+ CNAT_DEBUG_GENERIC_COMMAND_CLEAR_STATS,
+ CNAT_DEBUG_GENERIC_COMMAND_DUMP_NODE_COUNTER,
+ CNAT_DEBUG_GENERIC_COMMAND_CLEAR_NODE_COUNTER,
+ CNAT_DEBUG_GENERIC_COMMAND_DUMP_CNAT_COUNTER,
+ CNAT_DEBUG_GENERIC_COMMAND_DUMP_VA,
+ CNAT_DEBUG_GENERIC_COMMAND_SHOW_CONFIG,
+ CNAT_DEBUG_GENERIC_COMMAND_SHOW_NFV9,
+ CNAT_DEBUG_GENERIC_COMMAND_SHOW_IVRF,
+ CNAT_DEBUG_GENERIC_COMMAND_SHOW_OVRF,
+ CNAT_DEBUG_SPP_LOG,
+ CNAT_DEBUG_GENERIC_COMMAND_DEBUG_OPTIONS,
+ CNAT_DEBUG_GENERIC_COMMAND_DUMP_DEBUG_LEVELS,
+ CNAT_DEBUG_GENERIC_COMMAND_DEBUG_FLAGS,
+ CNAT_READ_TEMP_SENSORS,
+ CNAT_BLOCK_OCTEON_SENSOR_READ,
+ CNAT_DEBUG_GENERIC_COMMAND_DUMP_MAIN_DB_SUMMARY,
+ CNAT_DEBUG_GENERIC_COMMAND_DUMP_USER_DB_SUMMARY,
+ CNAT_DEBUG_DUMP_6RD_STATS,
+ CNAT_DEBUG_TIMEOUT_DB_SUMMARY,
+ CNAT_NAT64_STFUL_DEBUG_COMMAND,
+ CNAT_DEBUG_SET_BULK_SIZE,
+ CNAT_DEBUG_SHOW_BULK_STAT,
+ CNAT_DEBUG_CLEAR_BULK_STAT,
+ CNAT_DEBUG_SHOW_BULK_ALLOC,
+ CNAT_DEBUG_NAT64,
+ CNAT_DEBUG_NAT44_IN2OUT_FRAG_STATS,
+} cnat_debug_dump_type_t;
+
+typedef enum {
+ CNAT_DEBUG_FLAG_UDP_INSIDE_CHECKSUM_MODIFY,
+ CNAT_DEBUG_FLAG_UDP_OUTSIDE_CHECKSUM_MODIFY,
+ CNAT_DEBUG_FLAG_UDP_INSIDE_PACKET_DUMP,
+ CNAT_DEBUG_FLAG_UDP_OUTSIDE_PACKET_DUMP,
+} cnat_debug_flag_type_t;
+
+typedef struct {
+ u16 spp_msg_id;
+ u8 rc;
+ u8 core;
+ u32 num_bytes;
+ u8 raw_data[0];
+} cnat_generic_command_resp;
+
+extern u32 db_free_entry (void * p);
+#endif /*__CNAT_SHOW_RESPONSE_H__*/
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_syslog.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_syslog.c
new file mode 100644
index 00000000..91758f14
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_syslog.c
@@ -0,0 +1,1787 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_syslog.c
+ *
+ * Copyright (c) 2011-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <arpa/inet.h>
+#include "cnat_syslog.h"
+#include "platform_common.h"
+#include "cnat_db.h"
+#include "cnat_log_common.h"
+#include <vppinfra/pool.h>
+
+#define SYSLOG_DELIMITER ' '
+#define SYSLOG_FIELD_ABSENT '-'
+/* #define SHOW_SYSLOG_TIMESTAMP 1 TO DO. Remove this later */
+/*
+ * Defining the below macro here for now. Assumption is, syslog packets
+ * are sent out via same channel as that of NFV9.
+ * Has to be overridden if this assumption is false.
+ */
+#define PLATFORM_SYSLOG_DISP_NODE_IDX PLATFORM_NFV9_DISP_NODE_IDX
+
+cnat_syslog_global_info_t cnat_syslog_global_info;
+cnat_syslog_logging_info_t *cnat_syslog_logging_info_pool;
+cnat_syslog_global_counters_t cnat_syslog_global_counter;
+extern u32 syslog_debug_flag;
+
+#define CNAT_SYSLOG_DEBUG_CODE 2
+
+#if CNAT_SYSLOG_DEBUG_CODE > 3
+#define SYSLOG_COND if(my_instance_number == 0)
+
+#define SYSLOG_DEBUG_PRINTF1(a) SYSLOG_COND printf(a);
+#define SYSLOG_DEBUG_PRINTF2(a, b) SYSLOG_COND printf(a, b);
+#define SYSLOG_DEBUG_PRINTF3(a, b, c) SYSLOG_COND printf(a, b, c);
+#define SYSLOG_DEBUG_PRINTF4(a, b, c, d) SYSLOG_COND printf(a, b, c, d);
+
+#else
+
+#define SYSLOG_DEBUG_PRINTF1(a)
+#define SYSLOG_DEBUG_PRINTF2(a, b)
+#define SYSLOG_DEBUG_PRINTF3(a, b, c)
+#define SYSLOG_DEBUG_PRINTF4(a, b, c, d)
+
+#endif
+
+
+void syslog_params_show(u32 logging_index)
+{
+ cnat_syslog_logging_info_t *log_info __attribute__((unused));
+ if(logging_index == EMPTY) {
+ PLATFORM_DEBUG_PRINT("\nSyslog logging not configured\n");
+ return;
+ }
+
+ log_info = cnat_syslog_logging_info_pool + logging_index;
+
+ PLATFORM_DEBUG_PRINT("\nSyslog parameters --\n");
+ PLATFORM_DEBUG_PRINT("IPV4 address: %x, port %d, max log size %d\n",
+ log_info->ipv4_address,
+ log_info->port, log_info->max_length_minus_max_record_size);
+ PLATFORM_DEBUG_PRINT("Host name: %s, priority %d",
+ log_info->header_hostname, log_info->header_priority);
+
+}
+
+/* Util function to copy a number as ASCII in to a buf in a
+ * faster way (should be faster than sprintf)
+ */
+
+const unsigned char ascii_numbers[][3] =
+ { {'0', '0', '0'},
+ {'1', '0', '0'},
+ {'2', '0', '0'},
+ {'3', '0', '0'},
+ {'4', '0', '0'},
+ {'5', '0', '0'},
+ {'6', '0', '0'},
+ {'7', '0', '0'},
+ {'8', '0', '0'},
+ {'9', '0', '0'},
+ {'1', '0', '0'},
+ {'1', '1', '0'},
+ {'1', '2', '0'},
+ {'1', '3', '0'},
+ {'1', '4', '0'},
+ {'1', '5', '0'},
+ {'1', '6', '0'},
+ {'1', '7', '0'},
+ {'1', '8', '0'},
+ {'1', '9', '0'},
+ {'2', '0', '0'},
+ {'2', '1', '0'},
+ {'2', '2', '0'},
+ {'2', '3', '0'},
+ {'2', '4', '0'},
+ {'2', '5', '0'},
+ {'2', '6', '0'},
+ {'2', '7', '0'},
+ {'2', '8', '0'},
+ {'2', '9', '0'},
+ {'3', '0', '0'},
+ {'3', '1', '0'},
+ {'3', '2', '0'},
+ {'3', '3', '0'},
+ {'3', '4', '0'},
+ {'3', '5', '0'},
+ {'3', '6', '0'},
+ {'3', '7', '0'},
+ {'3', '8', '0'},
+ {'3', '9', '0'},
+ {'4', '0', '0'},
+ {'4', '1', '0'},
+ {'4', '2', '0'},
+ {'4', '3', '0'},
+ {'4', '4', '0'},
+ {'4', '5', '0'},
+ {'4', '6', '0'},
+ {'4', '7', '0'},
+ {'4', '8', '0'},
+ {'4', '9', '0'},
+ {'5', '0', '0'},
+ {'5', '1', '0'},
+ {'5', '2', '0'},
+ {'5', '3', '0'},
+ {'5', '4', '0'},
+ {'5', '5', '0'},
+ {'5', '6', '0'},
+ {'5', '7', '0'},
+ {'5', '8', '0'},
+ {'5', '9', '0'},
+ {'6', '0', '0'},
+ {'6', '1', '0'},
+ {'6', '2', '0'},
+ {'6', '3', '0'},
+ {'6', '4', '0'},
+ {'6', '5', '0'},
+ {'6', '6', '0'},
+ {'6', '7', '0'},
+ {'6', '8', '0'},
+ {'6', '9', '0'},
+ {'7', '0', '0'},
+ {'7', '1', '0'},
+ {'7', '2', '0'},
+ {'7', '3', '0'},
+ {'7', '4', '0'},
+ {'7', '5', '0'},
+ {'7', '6', '0'},
+ {'7', '7', '0'},
+ {'7', '8', '0'},
+ {'7', '9', '0'},
+ {'8', '0', '0'},
+ {'8', '1', '0'},
+ {'8', '2', '0'},
+ {'8', '3', '0'},
+ {'8', '4', '0'},
+ {'8', '5', '0'},
+ {'8', '6', '0'},
+ {'8', '7', '0'},
+ {'8', '8', '0'},
+ {'8', '9', '0'},
+ {'9', '0', '0'},
+ {'9', '1', '0'},
+ {'9', '2', '0'},
+ {'9', '3', '0'},
+ {'9', '4', '0'},
+ {'9', '5', '0'},
+ {'9', '6', '0'},
+ {'9', '7', '0'},
+ {'9', '8', '0'},
+ {'9', '9', '0'},
+ {'1', '0', '0'},
+ {'1', '0', '1'},
+ {'1', '0', '2'},
+ {'1', '0', '3'},
+ {'1', '0', '4'},
+ {'1', '0', '5'},
+ {'1', '0', '6'},
+ {'1', '0', '7'},
+ {'1', '0', '8'},
+ {'1', '0', '9'},
+ {'1', '1', '0'},
+ {'1', '1', '1'},
+ {'1', '1', '2'},
+ {'1', '1', '3'},
+ {'1', '1', '4'},
+ {'1', '1', '5'},
+ {'1', '1', '6'},
+ {'1', '1', '7'},
+ {'1', '1', '8'},
+ {'1', '1', '9'},
+ {'1', '2', '0'},
+ {'1', '2', '1'},
+ {'1', '2', '2'},
+ {'1', '2', '3'},
+ {'1', '2', '4'},
+ {'1', '2', '5'},
+ {'1', '2', '6'},
+ {'1', '2', '7'},
+ {'1', '2', '8'},
+ {'1', '2', '9'},
+ {'1', '3', '0'},
+ {'1', '3', '1'},
+ {'1', '3', '2'},
+ {'1', '3', '3'},
+ {'1', '3', '4'},
+ {'1', '3', '5'},
+ {'1', '3', '6'},
+ {'1', '3', '7'},
+ {'1', '3', '8'},
+ {'1', '3', '9'},
+ {'1', '4', '0'},
+ {'1', '4', '1'},
+ {'1', '4', '2'},
+ {'1', '4', '3'},
+ {'1', '4', '4'},
+ {'1', '4', '5'},
+ {'1', '4', '6'},
+ {'1', '4', '7'},
+ {'1', '4', '8'},
+ {'1', '4', '9'},
+ {'1', '5', '0'},
+ {'1', '5', '1'},
+ {'1', '5', '2'},
+ {'1', '5', '3'},
+ {'1', '5', '4'},
+ {'1', '5', '5'},
+ {'1', '5', '6'},
+ {'1', '5', '7'},
+ {'1', '5', '8'},
+ {'1', '5', '9'},
+ {'1', '6', '0'},
+ {'1', '6', '1'},
+ {'1', '6', '2'},
+ {'1', '6', '3'},
+ {'1', '6', '4'},
+ {'1', '6', '5'},
+ {'1', '6', '6'},
+ {'1', '6', '7'},
+ {'1', '6', '8'},
+ {'1', '6', '9'},
+ {'1', '7', '0'},
+ {'1', '7', '1'},
+ {'1', '7', '2'},
+ {'1', '7', '3'},
+ {'1', '7', '4'},
+ {'1', '7', '5'},
+ {'1', '7', '6'},
+ {'1', '7', '7'},
+ {'1', '7', '8'},
+ {'1', '7', '9'},
+ {'1', '8', '0'},
+ {'1', '8', '1'},
+ {'1', '8', '2'},
+ {'1', '8', '3'},
+ {'1', '8', '4'},
+ {'1', '8', '5'},
+ {'1', '8', '6'},
+ {'1', '8', '7'},
+ {'1', '8', '8'},
+ {'1', '8', '9'},
+ {'1', '9', '0'},
+ {'1', '9', '1'},
+ {'1', '9', '2'},
+ {'1', '9', '3'},
+ {'1', '9', '4'},
+ {'1', '9', '5'},
+ {'1', '9', '6'},
+ {'1', '9', '7'},
+ {'1', '9', '8'},
+ {'1', '9', '9'},
+ {'2', '0', '0'},
+ {'2', '0', '1'},
+ {'2', '0', '2'},
+ {'2', '0', '3'},
+ {'2', '0', '4'},
+ {'2', '0', '5'},
+ {'2', '0', '6'},
+ {'2', '0', '7'},
+ {'2', '0', '8'},
+ {'2', '0', '9'},
+ {'2', '1', '0'},
+ {'2', '1', '1'},
+ {'2', '1', '2'},
+ {'2', '1', '3'},
+ {'2', '1', '4'},
+ {'2', '1', '5'},
+ {'2', '1', '6'},
+ {'2', '1', '7'},
+ {'2', '1', '8'},
+ {'2', '1', '9'},
+ {'2', '2', '0'},
+ {'2', '2', '1'},
+ {'2', '2', '2'},
+ {'2', '2', '3'},
+ {'2', '2', '4'},
+ {'2', '2', '5'},
+ {'2', '2', '6'},
+ {'2', '2', '7'},
+ {'2', '2', '8'},
+ {'2', '2', '9'},
+ {'2', '3', '0'},
+ {'2', '3', '1'},
+ {'2', '3', '2'},
+ {'2', '3', '3'},
+ {'2', '3', '4'},
+ {'2', '3', '5'},
+ {'2', '3', '6'},
+ {'2', '3', '7'},
+ {'2', '3', '8'},
+ {'2', '3', '9'},
+ {'2', '4', '0'},
+ {'2', '4', '1'},
+ {'2', '4', '2'},
+ {'2', '4', '3'},
+ {'2', '4', '4'},
+ {'2', '4', '5'},
+ {'2', '4', '6'},
+ {'2', '4', '7'},
+ {'2', '4', '8'},
+ {'2', '4', '9'},
+ {'2', '5', '0'},
+ {'2', '5', '1'},
+ {'2', '5', '2'},
+ {'2', '5', '3'},
+ {'2', '5', '4'},
+ {'2', '5', '5'}
+ };
+
+inline static int
+byte_to_ascii_decimal_unaligned(
+ unsigned char *ptr, unsigned char num)
+{
+ *ptr++ = ascii_numbers[num][0];
+ if(PREDICT_FALSE(num < 10)) {
+ return 1;
+ }
+ *ptr++ = ascii_numbers[num][1];
+ if(PREDICT_FALSE(num < 100)) {
+ return 2;
+ }
+ *ptr++ = ascii_numbers[num][2];
+ return 3;
+}
+
+/* Copies the dotted decimal format of ipv4
+ * in to the space provided and
+ * returns the number of bytes copied
+ */
+inline static int __attribute__((unused))
+copy_ipv4_addr(unsigned char *ptr, u32 ipv4)
+{
+ unsigned char *temp = ptr;
+ temp += byte_to_ascii_decimal_unaligned(temp, (ipv4 >> 24));
+ *temp++ = '.';
+ temp += byte_to_ascii_decimal_unaligned(temp, ((ipv4 >> 16) & 0xFF));
+ *temp++ = '.';
+ temp += byte_to_ascii_decimal_unaligned(temp, ((ipv4 >> 8) & 0xFF));
+ *temp++ = '.';
+ temp += byte_to_ascii_decimal_unaligned(temp, (ipv4 & 0xFF));
+
+ return (temp - ptr);
+}
+
+#ifdef TOBE_PORTED
+/*
+ * edt: * * cnat_syslog_fill_ip_header
+ *
+ * Tries to fill the fields of the IP header before it
+ * is sent to the L3 infra node.
+ *
+ * Argument: cnat_syslog_logging_info_t *logging_info
+ * structure that contains the packet context
+ */
+inline
+void cnat_syslog_fill_ip_header (cnat_syslog_logging_info_t *logging_info)
+{
+ spp_ctx_t *ctx;
+
+ /*
+ * Fill in the IP header and port number of the Netflow collector
+ * The L3 Infra node will fill in the rest of the fields
+ */
+ ctx = logging_info->current_logging_context;
+ fill_ip_n_udp_hdr(ctx, logging_info->ipv4_address,
+ logging_info->port, logging_info->pkt_length);
+
+}
+#else
+inline
+void cnat_syslog_fill_ip_header (cnat_syslog_logging_info_t *logging_info)
+{
+ return;
+}
+#endif
+
+#ifndef TOBE_PORTED
+void cnat_syslog_logging_init()
+{
+ return;
+}
+
+void cnat_syslog_log_mapping_create(cnat_main_db_entry_t * db,
+ cnat_vrfmap_t *vrfmap)
+{
+ return;
+}
+
+void cnat_syslog_log_mapping_delete(cnat_main_db_entry_t * db,
+ cnat_vrfmap_t *vrfmap)
+{
+ return;
+}
+
+void cnat_syslog_ds_lite_port_limit_exceeded(
+ dslite_key_t * key,
+ dslite_table_entry_t *dslite_entry)
+{
+ return;
+}
+
+void cnat_syslog_nat44_mapping_create(cnat_main_db_entry_t *db,
+ cnat_vrfmap_t *vrfmap, cnat_session_entry_t * sdb
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ )
+{
+ return;
+}
+
+/* Following are in cnat_util.c which are not ported */
+/* This function is defined in cnat_util.c which need to be ported */
+cnat_icmp_msg_t icmp_msg_gen_allowed ()
+{
+ return 1;
+}
+
+void cnat_syslog_nat44_mapping_delete(cnat_main_db_entry_t *db,
+ cnat_vrfmap_t *vrfmap, cnat_session_entry_t *sdb
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ )
+{
+ return;
+}
+
+u32
+cnat_get_unix_time_in_seconds (void)
+{
+ return 0;
+}
+#else /* TOBE_PORTED */
+void
+cnat_syslog_dump_logging_context (u32 value1,
+ cnat_syslog_logging_info_t *logging_info,
+ u32 value2)
+{
+ u8 *pkt_ptr;
+ u32 i;
+
+ if (PREDICT_TRUE(syslog_debug_flag == 0)) {
+ return;
+ }
+ /*
+ * Reduce the logging to few cores, to enable easier debugging
+ */
+ if ((my_instance_number & 0x7) != 0) {
+ return;
+ }
+ printf("\nDumping %s packet at locn %d: time 0x%x",
+ (value2 == 1) ? "CURRENT" : "QUEUED",
+ value1,
+ cnat_get_unix_time_in_seconds());
+
+ printf("\ni_vrf 0x%x, ip_address 0x%x, port %d, pkt len %d",
+ 0 /* TO DP Add vrf like nfv9_logging_info->i_vrf */,
+ logging_info->ipv4_address,
+ logging_info->port,
+ logging_info->pkt_length);
+ printf("\n");
+
+ if (value2 == 1) {
+ pkt_ptr = logging_info->current_logging_context->packet_data;
+ } else {
+ pkt_ptr = logging_info->queued_logging_context->packet_data;
+ }
+
+ /*
+ * Dump along with 8 bytes of SHIM header
+ */
+ for (i = 0; i <
+ (logging_info->pkt_length + CNAT_NFV9_IP_HDR_OFFSET);
+ i = i + 1) {
+ u8 c1, c2, c3;
+
+ if (i == 0) {
+ printf("\nL2_HEADER + SHIM_HEADER: \n");
+ } else if (i == CNAT_NFV9_IP_HDR_OFFSET) {
+ printf("\nIP_HEADER: \n");
+ } else if (i == CNAT_NFV9_UDP_HDR_OFFSET) {
+ printf("\nUDP_HEADER: \n");
+ } else if (i == CNAT_NFV9_HDR_OFFSET) {
+ printf("\nSyslog content..\n");
+ while(i <
+ (logging_info->pkt_length + CNAT_NFV9_HDR_OFFSET)) {
+ printf("%c", (u8)(*(pkt_ptr + i)));
+ i++;
+ if((u8)(*(pkt_ptr + i)) == '[') /* new record begins */
+ printf("\n");
+ }
+ return;
+ }
+
+ c3 = *(pkt_ptr + i);
+ c2 = c3 & 0xf;
+ c1 = (c3 >> 4) & 0xf;
+
+ printf("%c%c ",
+ ((c1 <= 9) ? (c1 + '0') : (c1 - 10 + 'a')),
+ ((c2 <= 9) ? (c2 + '0') : (c2 - 10 + 'a')));
+
+ }
+
+ printf("\n");
+}
+
+
+/*
+ * edt: * * cnat_syslog_send_pkt
+ *
+ * Tries to send a logging pkt. If the packet cannot be sent
+ * because of rewrite_output node cannot process it, queue
+ * it temporarily and try to send it later.
+ *
+ * Argument: cnat_syslog_logging_info_t *logging_info
+ * structure that contains the packet context
+ */
+inline
+void cnat_syslog_send_pkt (cnat_syslog_logging_info_t *logging_info)
+{
+ spp_node_t *output_node;
+
+ cnat_syslog_fill_ip_header(logging_info);
+
+ output_node = spp_get_nodes() +
+ cnat_syslog_global_info.cnat_syslog_disp_node_index;
+
+ cnat_syslog_dump_logging_context (2, logging_info, 1);
+
+ if (PREDICT_TRUE(output_node->sf.nused < SPP_MAXDISPATCH)) {
+ /*
+ * Move the logging context to output node
+ */
+ logging_info->current_logging_context->current_length =
+ logging_info->pkt_length;
+ PLATFORM_SET_CTX_RU_TX_FROM_NODE(logging_info->current_logging_context, \
+ NODE_LOGGING);
+ spp_dispatch_make_node_runnable(output_node);
+ output_node->sf.ctxs[output_node->sf.nused++] =
+ logging_info->current_logging_context;
+
+ if(PREDICT_FALSE(syslog_debug_flag > 10))
+ printf("\nSyslog: 2. Sending Current packet\n");
+ } else {
+ /*
+ * Queue the context into the logging_info structure,
+ * We will try to send it later. Currently, we will
+ * restrict to only one context queued.
+ */
+ cnat_syslog_global_counter.downstream_constipation_count++;
+ if(PREDICT_FALSE(syslog_debug_flag > 10))
+ printf("\nSyslog: 2. Downstream congestion \n");
+
+ /*
+ * Attach the current logging context which is full to the
+ * queued context list in logging_info structure
+ */
+ logging_info->queued_logging_context =
+ logging_info->current_logging_context;
+ }
+
+ /*
+ * Whether the context is queued or not, set the current context index
+ * to EMPTY, as the earlier context can no more be used to send
+ * more logging records.
+ */
+ logging_info->current_logging_context = NULL;
+}
+
+
+/*
+ * edt: * * cnat_syslog_send_queued_pkt
+ *
+ * Tries to send a logging pkt that has been queued earlier
+ * because it could not be sent due to downstream constipation
+ *
+ * Argument: cnat_syslog_logging_info_t *logging_info
+ * structure that contains the packet context
+ */
+inline
+void cnat_syslog_send_queued_pkt (cnat_syslog_logging_info_t *logging_info)
+{
+ spp_node_t *output_node;
+
+ output_node = spp_get_nodes() +
+ cnat_syslog_global_info.cnat_syslog_disp_node_index;
+
+ cnat_syslog_dump_logging_context(1, logging_info, 2);
+
+ if(PREDICT_TRUE(output_node->sf.nused < SPP_MAXDISPATCH)) {
+ /*
+ * Move the logging context to output node
+ */
+ /** This looks like a bug to me .. need to confirm *****
+ logging_info->queued_logging_context->current_length =
+ nfv9_logging_info->pkt_length; ***/
+ PLATFORM_SET_CTX_RU_TX_FROM_NODE(logging_info->queued_logging_context,
+ NODE_LOGGING)
+ spp_dispatch_make_node_runnable(output_node);
+ output_node->sf.ctxs[output_node->sf.nused++] =
+ logging_info->queued_logging_context;
+
+ SYSLOG_DEBUG_PRINTF1("\nSYSLOG: 1. Sending Queued packet\n")
+
+ /*
+ * Context has been queued, it will be freed after the pkt
+ * is sent. Clear this from the logging_context_info structure
+ */
+ logging_info->queued_logging_context = NULL;
+
+ } else {
+ cnat_syslog_global_counter.downstream_constipation_count++;
+ }
+}
+
+/*
+ * edt: * * handle_pending_syslog_pkts
+ *
+ * Timer handler for sending any pending syslog record
+ *
+ */
+inline
+void handle_pending_syslog_pkts()
+{
+ spp_node_t *output_node;
+ cnat_syslog_logging_info_t *my_logging_info = 0;
+ u32 current_timestamp = cnat_get_sys_up_time_in_ms();
+ i16 sf_nused;
+
+ output_node = spp_get_nodes() +
+ cnat_syslog_global_info.cnat_syslog_disp_node_index;
+
+ sf_nused = output_node->sf.nused;
+
+ pool_foreach (my_logging_info, cnat_syslog_logging_info_pool, ({
+ /*
+ * Check if no more logging contexts can be queued
+ */
+ if (PREDICT_FALSE(sf_nused >= SPP_MAXDISPATCH)) {
+ break;
+ }
+ if (my_logging_info->queued_logging_context)
+ cnat_syslog_send_queued_pkt (my_logging_info);
+
+ if(my_logging_info->current_logging_context &&
+ ((current_timestamp -
+ my_logging_info->current_logging_context_timestamp)
+ > 1000)) {
+ /*
+ * If there is a current logging context and timestamp
+ * indicates it is pending for long, send it out
+ * Also if there is a queued context send it out as well
+ */
+ SYSLOG_DEBUG_PRINTF4("\nLOG_TIMER: queued %p, curr %p, sf_nused %d",
+ my_logging_info->queued_logging_context,
+ my_logging_info->current_logging_context,
+ sf_nused);
+ cnat_syslog_send_pkt(my_logging_info);
+ }
+ }));
+}
+
+const unsigned char hex_numbers_single_digit[] =
+ { '0', '1', '2', '3', '4', '5', '6', '7', '8',
+ '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+inline static int u16_to_ascii_decimal_aligned(
+ unsigned char *ptr, u16 num, u16 min_digits)
+{
+ /* The logic below is replicated in
+ * function u16_to_ascii_decimal_unaligned
+ * except the use of min_digits
+ * Replication is done to optimize run time
+ * if you fix a bug here, check u16_to_ascii_decimal_unaligned
+ * as well (and vice versa)
+ */
+ unsigned char *temp = ptr;
+ int no_leading_zeros = 0;
+
+ if(num > 9999 || min_digits == 5) {
+ *temp++ = hex_numbers_single_digit[num/10000];
+ num = num%10000;
+ no_leading_zeros = 1;
+ }
+
+ if(no_leading_zeros || num > 999 || min_digits == 4) {
+ *temp++ = hex_numbers_single_digit[num/1000];
+ num = num%1000;
+ no_leading_zeros = 1;
+ }
+
+ if(no_leading_zeros || num > 99 || min_digits == 3) {
+ *temp++ = hex_numbers_single_digit[num/100];
+ num = num%100;
+ no_leading_zeros = 1;
+ }
+
+ if(no_leading_zeros || num > 9 || min_digits == 2) {
+ *temp++ = hex_numbers_single_digit[num/10];
+ num = num%10;
+ }
+
+ *temp++ = hex_numbers_single_digit[num];
+
+ return temp-ptr;
+}
+
+inline static int u16_to_ascii_decimal_unaligned(
+ unsigned char *ptr, u16 num)
+{
+ /*
+ * return u16_to_ascii_decimal_aligned(ptr, num, 0);
+ * should do the job.. however, to opimize the run time
+ * the code of u16_to_ascii_decimal_aligned is being
+ * repeated here without the use of min_digits
+ * if you fix a bug here, please check
+ * u16_to_ascii_decimal_aligned as well (and vice versa)
+ */
+ unsigned char *temp = ptr;
+ int no_leading_zeros = 0;
+
+ if(num > 9999) {
+ *temp++ = hex_numbers_single_digit[num/10000];
+ num = num%10000;
+ no_leading_zeros = 1;
+ }
+
+ if(no_leading_zeros || num > 999) {
+ *temp++ = hex_numbers_single_digit[num/1000];
+ num = num%1000;
+ no_leading_zeros = 1;
+ }
+
+ if(no_leading_zeros || num > 99) {
+ *temp++ = hex_numbers_single_digit[num/100];
+ num = num%100;
+ no_leading_zeros = 1;
+ }
+
+ if(no_leading_zeros || num > 9) {
+ *temp++ = hex_numbers_single_digit[num/10];
+ num = num%10;
+ }
+
+ *temp++ = hex_numbers_single_digit[num];
+
+ return temp-ptr;
+}
+
+static int syslog_get_timestamp(unsigned char *ts)
+{
+ static const char *months[] = {"Jan ", "Feb ", "Mar ", "Apr ", "May ",
+ "Jun ", "Jul ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec " };
+
+ unsigned char *temp = ts;
+ /* Inserts time stamp in the syslog format and returns lenght
+ * assumes that ts has sufficient space
+ */
+ /* China Telecom has demanded that the time stamp has to be
+ * in the format '2011 Jun 7 12:34:08'
+ */
+ time_t time = (time_t)cnat_get_unix_time_in_seconds();
+ struct tm tm1;
+
+ gmtime_r(&time, &tm1);
+ /* Now put the pieces together */
+ /* Year */
+ ts += u16_to_ascii_decimal_unaligned(ts, (tm1.tm_year + 1900));
+ *ts++ = SYSLOG_DELIMITER;
+ /* Month */
+ clib_memcpy(ts, months[tm1.tm_mon], 4);
+ ts += 4; /* DELIMITER taken care */
+ /* day */
+ ts += u16_to_ascii_decimal_unaligned(ts, tm1.tm_mday);
+ *ts++ = SYSLOG_DELIMITER;
+ /* hours */
+ ts += u16_to_ascii_decimal_aligned(ts, tm1.tm_hour, 2);
+ *ts++ = ':';
+ /* minutes */
+ ts += u16_to_ascii_decimal_aligned(ts, tm1.tm_min, 2);
+ *ts++ = ':';
+ /* seconds */
+ ts += u16_to_ascii_decimal_aligned(ts, tm1.tm_sec, 2);
+ return ts - temp;
+}
+
+/* Ensure that the order of the below array matches with
+ * syslog_service_type enum
+ */
+static char *syslog_service_string[] = { "NAT44", "DSLITE" };
+
+/* Ensure that the order of below array matches with
+ * syslog_event_type_t enum
+ */
+typedef struct {
+ char *event_name;
+ int name_length;
+} syslog_event_description_type;
+
+const static syslog_event_description_type sys_log_event[] = {
+ { "UserbasedA", 10 }, /* yes, 10 is strlen of "UserbasedA" */
+ { "UserbasedW", 10 },
+ { "SessionbasedA", 13 },
+ { "SessionbasedW", 13 },
+ { "SessionbasedAD", 14 },
+ { "SessionbasedWD", 14 },
+ { "Portblockrunout", 15 },
+ { "TCPseqmismatch", 14},
+ { "Invalid", 7 }
+};
+
+inline static int syslog_fill_header(const cnat_syslog_logging_info_t *log_info,
+ syslog_service_type_t s_type)
+{
+ /* Forms the syslog header and returns the lenght
+ * Assumes that header has sufficient space
+ */
+
+ /* Sample header (as agreed for China Telecom requirements --
+ * <134> 1 2011 May 31 10:30:45 192.168.2.3 - - NAT44 -
+ */
+
+ unsigned char *temp, *header;
+ int count;
+ temp = header = (unsigned char *)
+ &(log_info->current_logging_context->packet_data[CNAT_NFV9_HDR_OFFSET]);
+ *temp++ = '<';
+ temp += byte_to_ascii_decimal_unaligned(temp,
+ log_info->header_priority);
+ *temp++ = '>';
+ *temp++ = SYSLOG_DELIMITER;
+ *temp++ = '1'; /* Syslog version -- always set to 1 */
+ *temp++ = SYSLOG_DELIMITER;
+ temp += syslog_get_timestamp(temp);
+ *temp++ = SYSLOG_DELIMITER;
+ count = strlen(log_info->header_hostname);
+ clib_memcpy(temp, log_info->header_hostname, count);
+ temp += count;
+ *temp++ = SYSLOG_DELIMITER;
+ *temp++ = SYSLOG_FIELD_ABSENT; /* App name - nil value */
+ *temp++ = SYSLOG_DELIMITER;
+ *temp++ = SYSLOG_FIELD_ABSENT; /* Proc ID - nil value for now */
+ *temp++ = SYSLOG_DELIMITER;
+ /* Now the msg id */
+ count = strlen(syslog_service_string[s_type]);
+ clib_memcpy(temp, syslog_service_string[s_type], count);
+ temp += count;
+ *temp++ = SYSLOG_DELIMITER;
+ *temp++ = SYSLOG_FIELD_ABSENT; /* No structured elements */
+ *temp++ = SYSLOG_DELIMITER;
+#ifdef SHOW_SYSLOG_TIMESTAMP
+ printf("\nSysLog TS: %s : Length %d", header, temp - header);
+#endif /* SHOW_SYSLOG_TIMESTAMP */
+ return temp-header;
+}
+
+extern void cnat_logging_init();
+
+/* one time call at the beginning */
+void cnat_syslog_logging_init()
+{
+ if(PREDICT_TRUE(cnat_syslog_global_info.cnat_syslog_init_done))
+ return; /* Already done */
+
+ cnat_logging_init();
+ cnat_syslog_global_info.cnat_syslog_disp_node_index =
+ spp_lookup_node_index(PLATFORM_SYSLOG_DISP_NODE_IDX);
+ ASSERT(cnat_syslog_global_info.cnat_syslog_disp_node_index != (u16)~0);
+
+ cnat_syslog_global_info.cnat_syslog_init_done = 1;
+}
+
+/*
+ * edt: * * cnat_syslog_create_logging_context
+ *
+ * Tries to create a logging context with packet buffer
+ * to send a new logging packet
+ *
+ * Argument: cnat_syslog_logging_info_t *logging_info
+ * structure that contains the logging info and will store
+ * the packet context as well.
+ */
+inline
+void cnat_syslog_create_logging_context (
+ cnat_syslog_logging_info_t *logging_info,
+ syslog_service_type_t s_type)
+{
+ spp_ctx_t *ctx;
+
+ /*
+ * If queued_logging_context_index is non-EMPTY, we already have a logging
+ * packet queued to be sent. First try sending this before allocating
+ * a new context. We can have only one active packet context per
+ * logging_info structure
+ */
+
+ if (PREDICT_FALSE(logging_info->queued_logging_context != NULL)) {
+ cnat_syslog_send_queued_pkt(logging_info);
+ /*
+ * If we cannot still send the queued pkt, just return
+ * Downstream Constipation count would have increased anyway
+ */
+ if (logging_info->queued_logging_context != NULL) {
+ cnat_syslog_global_counter.logging_context_creation_deferred_count++;
+ return;
+ }
+ }
+
+ /*
+ * If no context can be allocated, return silently
+ * calling routine will handle updating the error counters
+ */
+ if (spp_ctx_alloc(&ctx, 1) < 1) {
+ cnat_syslog_global_counter.logging_context_creation_fail_count++;
+ SYSLOG_DEBUG_PRINTF1("\nCould not allocate ctx for syslog");
+ return;
+ }
+
+ // Allocate packet buffer (used for AVSM currently)
+ PLATFORM_ALLOC_NFV9_PKT_BUFFER(ctx, 0);
+
+ logging_info->current_logging_context = ctx;
+
+ PLATFORM_SET_CTX_RU_TX_FROM_NODE(ctx, NODE_LOGGING);
+
+ ctx->flags = SPP_CTX_END_OF_PACKET;
+ ctx->next_ctx_this_packet = (spp_ctx_t*) SPP_CTX_NO_NEXT_CTX;
+ ctx->current_header = &ctx->packet_data[CNAT_NFV9_HDR_OFFSET];
+
+ logging_info->pkt_length = syslog_fill_header(logging_info, s_type);
+ logging_info->pkt_length += (CNAT_NFV9_HDR_OFFSET -
+ CNAT_NFV9_IP_HDR_OFFSET);
+ logging_info->current_logging_context_timestamp =
+ cnat_get_sys_up_time_in_ms();
+
+}
+
+inline static int u16_to_ascii_hex_unaligned(
+ unsigned char *ptr, u16 num)
+{
+ unsigned char nibble, *temp;
+ int no_leading_zeros = 0;
+ temp = ptr;
+ nibble = (num >> 12);
+ if(nibble) {
+ *temp++ = hex_numbers_single_digit[nibble];
+ no_leading_zeros = 1;
+ }
+
+ nibble = (num >> 8) & 0xF;
+ if(nibble || no_leading_zeros) {
+ *temp++ = hex_numbers_single_digit[nibble];
+ no_leading_zeros = 1;
+ }
+
+ nibble = (num >> 4) & 0xF;
+ if(nibble || no_leading_zeros) {
+ *temp++ = hex_numbers_single_digit[nibble];
+ }
+
+ *temp++ = hex_numbers_single_digit[num & 0xF];
+
+ return temp-ptr;
+}
+
+inline static int ipv6_int_2_str(u32 ipv6[], unsigned char *ipv6_str)
+{
+/* DC stands for Double Colon.
+ * Refer http://tools.ietf.org/html/rfc5952 for
+ * more details on text representations of
+ * IPV6 address
+ */
+#define DC_NOT_USED_YET 0
+#define DC_IN_USE 1 /* Zeros are skipped */
+#define DC_ALREADY_USED 2 /* Cannot skip zeros anymore */
+ int i;
+ u16 *ipv6_temp = (u16 *)ipv6;
+ unsigned char *temp = ipv6_str;
+ int double_colon = DC_NOT_USED_YET;
+ for(i = 0; i < 7; i++) {
+ if(ipv6_temp[i]) {
+ ipv6_str += u16_to_ascii_hex_unaligned(ipv6_str, ipv6_temp[i]);
+ *ipv6_str++ = ':';
+ if(double_colon == DC_IN_USE) { /* Cannot use DC anymore */
+ double_colon = DC_ALREADY_USED;
+ }
+ } else {
+ if(double_colon == DC_IN_USE) {
+ /* Skip this zero as well */
+ continue;
+ } else if((ipv6_temp[i+1])
+ /* DC makes sense if there is more than one contiguous zero */
+ || (double_colon != DC_NOT_USED_YET)) {
+ ipv6_str += u16_to_ascii_hex_unaligned(ipv6_str,
+ ipv6_temp[i]);
+ *ipv6_str++ = ':';
+ } else { /* Start using DC */
+ *ipv6_str++ = ':'; /* The 2nd colon */
+ double_colon = DC_IN_USE;
+ }
+ }
+ }
+ if(ipv6_temp[7]) {
+ ipv6_str += u16_to_ascii_hex_unaligned(ipv6_str, ipv6_temp[7]);
+ } else if(double_colon != DC_IN_USE) {
+ *ipv6_str++ = '0';
+ }
+ *ipv6_str = 0;
+
+ return ipv6_str - temp;
+}
+
+/* insert syslog record for nat44 */
+
+void cnat_syslog_insert_nat44_record(
+ cnat_syslog_logging_info_t *log_info,
+ cnat_main_db_entry_t *db, cnat_vrfmap_t *vrfmap,
+ cnat_session_entry_t *sdb, int bulk_alloc, syslog_event_type_t e_type)
+{
+ /* This record should like this -
+ * [EventName <L4> <Original Source IP> <Inside VRF Name>
+ * <Original Source IPv6> < Translated Source IP> <Original Port>
+ * <Translated First Source Port> <Translated Last Source Port>
+ * <Destination ip address> <destination port>]
+ */
+ u32 original_source = db->in2out_key.k.ipv4;
+ u32 translated_ip = db->out2in_key.k.ipv4;
+ cnat_user_db_entry_t *udb = cnat_user_db + db->user_index;
+ unsigned char *temp, *record;
+ u32 network_order_ipv6[4];
+
+ SYSLOG_CONFIG_DEBUG_PRINTF(4,"In Function %s\n", __func__);
+ temp = record = &(log_info->current_logging_context->packet_data[
+ CNAT_NFV9_IP_HDR_OFFSET + log_info->pkt_length]);
+
+ if (PREDICT_FALSE(!udb)) {
+ SYSLOG_DEBUG_PRINTF1("\nnull udb!");
+ return;
+ }
+
+ /* Now we point to the location where record needs to be inserted */
+ *record++ = '['; /* Open the record */
+
+ /* Copy the record type */
+ clib_memcpy(record, sys_log_event[e_type].event_name,
+ sys_log_event[e_type].name_length);
+ record += sys_log_event[e_type].name_length;
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy the Protocol type */
+ if(PREDICT_FALSE(
+ e_type == sessionbased_assign || e_type == sessionbased_withdraw ||
+ e_type == sessionbased_assignD || e_type == sessionbased_withdrawD)) {
+ u16 my_proto_mask;
+ my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK;
+ if(PREDICT_TRUE(my_proto_mask == CNAT_TCP)) {
+ *record++ = '6';
+ } else if(PREDICT_TRUE(my_proto_mask == CNAT_UDP)) {
+ *record++ = '1';
+ *record++ = '7';
+ } else if(PREDICT_TRUE(my_proto_mask == CNAT_ICMP)) {
+ *record++ = '1';
+ } else { /* Default, assume GRE (for PPTP) */
+ *record++ = '4';
+ *record++ = '7';
+ }
+ } else {
+ *record++ = SYSLOG_FIELD_ABSENT;
+ }
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy the Original Source IP */
+ record += copy_ipv4_addr(record, original_source);
+ *record++ = SYSLOG_DELIMITER;
+
+ /* copy configured VRF NAME */
+ clib_memcpy(record, log_info->vrf_name, log_info->vrf_name_len);
+ record += log_info->vrf_name_len;
+ *record++ = SYSLOG_DELIMITER;
+
+ /* No IPV6 source address for nat44 */
+ *record++ = SYSLOG_FIELD_ABSENT;
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy the translated IP address */
+ record += copy_ipv4_addr(record, translated_ip);
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy the Original port */
+ if(e_type == sessionbased_assign || e_type == sessionbased_withdraw ||
+ e_type == sessionbased_assignD || e_type == sessionbased_withdrawD) {
+ record += u16_to_ascii_decimal_unaligned(
+ record, db->in2out_key.k.port);
+ } else {
+ *record++ = SYSLOG_FIELD_ABSENT;
+ }
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy the start outside port */
+ record += u16_to_ascii_decimal_unaligned(record, bulk_alloc);
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy the last outside port */
+ if(e_type == userbased_assign || e_type == userbased_withdraw) {
+ record += u16_to_ascii_decimal_unaligned(record,
+ (bulk_alloc + BULKSIZE_FROM_VRFMAP(vrfmap) - 1));
+ } else {
+ *record++ = SYSLOG_FIELD_ABSENT;
+ }
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy destination ip and port in case for DBL*/
+ if(PREDICT_FALSE(e_type == sessionbased_assignD || e_type == sessionbased_withdrawD)) {
+ if(PREDICT_TRUE(sdb == NULL)) {
+ record += copy_ipv4_addr(record,db->dst_ipv4);
+ *record++ = SYSLOG_DELIMITER;
+ record += u16_to_ascii_decimal_unaligned(record, db->dst_port);
+ } else {
+ record += copy_ipv4_addr(record, sdb->v4_dest_key.k.ipv4);
+ *record++ = SYSLOG_DELIMITER;
+ record += u16_to_ascii_decimal_unaligned(record, sdb->v4_dest_key.k.port);
+ }
+ } else {
+ *record++ = '-';
+ *record++ = SYSLOG_DELIMITER;
+ *record++ = '-';
+ }
+ *record++ = SYSLOG_DELIMITER;
+
+ *record++ = ']'; /* End of the reocrd */
+
+ log_info->pkt_length += record - temp;
+}
+
+void cnat_syslog_insert_record(
+ cnat_syslog_logging_info_t *log_info,
+ cnat_main_db_entry_t *db, dslite_table_entry_t *dslite_entry,
+ cnat_session_entry_t *sdb, int bulk_alloc, syslog_event_type_t e_type)
+{
+ /* This record should like this -
+ * [EventName <L4> <Original Source IP> <Inside VRF Name>
+ * <Original Source IPv6> < Translated Source IP> <Original Port>
+ * <Translated First Source Port> <Translated Last Source Port>
+ * <Destination ip address> <destination port>]
+ */
+ u32 original_source = db->in2out_key.k.ipv4;
+ u32 translated_ip = db->out2in_key.k.ipv4;
+ cnat_user_db_entry_t *udb = cnat_user_db + db->user_index;
+ unsigned char *temp, *record;
+ u32 network_order_ipv6[4];
+
+ temp = record = &(log_info->current_logging_context->packet_data[
+ CNAT_NFV9_IP_HDR_OFFSET + log_info->pkt_length]);
+
+ if (PREDICT_FALSE(!udb)) {
+ SYSLOG_DEBUG_PRINTF1("\nnull udb!");
+ return;
+ }
+
+ /* Now we point to the location where record needs to be inserted */
+ *record++ = '['; /* Open the record */
+
+ /* Copy the record type */
+ clib_memcpy(record, sys_log_event[e_type].event_name,
+ sys_log_event[e_type].name_length);
+ record += sys_log_event[e_type].name_length;
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy the Protocol type */
+ if(PREDICT_FALSE(
+ e_type == sessionbased_assign || e_type == sessionbased_withdraw ||
+ e_type == sessionbased_assignD || e_type == sessionbased_withdrawD)) {
+ u16 my_proto_mask;
+ my_proto_mask = db->in2out_key.k.vrf & CNAT_PRO_MASK;
+ if(PREDICT_TRUE(my_proto_mask == CNAT_TCP)) {
+ *record++ = '6';
+ } else if(PREDICT_TRUE(my_proto_mask == CNAT_UDP)) {
+ *record++ = '1';
+ *record++ = '7';
+ } else {
+ *record++ = '1';
+ }
+ } else {
+ *record++ = SYSLOG_FIELD_ABSENT;
+ }
+
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy the Original Source IP */
+#ifdef DSLITE_USER_IPV4
+ record += copy_ipv4_addr(record, original_source);
+#else
+ /*
+ * Do not include inside ipv4 address for B4 element level port limiting
+ */
+ *record++ = SYSLOG_FIELD_ABSENT;
+#endif
+ *record++ = SYSLOG_DELIMITER;
+
+ /* copy configured VRF NAME */
+ clib_memcpy(record, log_info->vrf_name, log_info->vrf_name_len);
+ record += log_info->vrf_name_len;
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy the IPV6 source address */
+ /* CSCtt16960 Fix. */
+ network_order_ipv6[0] = htonl(udb->ipv6[0]);
+ network_order_ipv6[1] = htonl(udb->ipv6[1]);
+ network_order_ipv6[2] = htonl(udb->ipv6[2]);
+ network_order_ipv6[3] = htonl(udb->ipv6[3]);
+
+ inet_ntop(AF_INET6,network_order_ipv6,record,INET6_ADDRSTRLEN);
+ record += strlen(record);
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy the translated IP address */
+ record += copy_ipv4_addr(record, translated_ip);
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy the Original port */
+ if(e_type == sessionbased_assign || e_type == sessionbased_withdraw ||
+ e_type == sessionbased_assignD || e_type == sessionbased_withdrawD) {
+ record += u16_to_ascii_decimal_unaligned(
+ record, db->in2out_key.k.port);
+ } else {
+ *record++ = SYSLOG_FIELD_ABSENT;
+ }
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy the start outside port */
+ record += u16_to_ascii_decimal_unaligned(record, bulk_alloc);
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy the last outside port */
+ if(e_type == userbased_assign || e_type == userbased_withdraw) {
+ record += u16_to_ascii_decimal_unaligned(record,
+ (bulk_alloc + BULKSIZE_FROM_VRFMAP(dslite_entry) - 1));
+ } else {
+ *record++ = SYSLOG_FIELD_ABSENT;
+ }
+ *record++ = SYSLOG_DELIMITER;
+
+ if(PREDICT_FALSE(e_type == sessionbased_assignD || e_type == sessionbased_withdrawD)) {
+ if(sdb == NULL) {
+ record += copy_ipv4_addr(record, db->dst_ipv4);
+ *record++ = SYSLOG_DELIMITER;
+ record += u16_to_ascii_decimal_unaligned(record, db->dst_port);
+ } else {
+ record += copy_ipv4_addr(record, sdb->v4_dest_key.k.ipv4);
+ *record++ = SYSLOG_DELIMITER;
+ record += u16_to_ascii_decimal_unaligned(record, sdb->v4_dest_key.k.port);
+ }
+ } else {
+ *record++ = '-';
+ *record++ = SYSLOG_DELIMITER;
+ *record++ = '-';
+ }
+ *record++ = SYSLOG_DELIMITER;
+
+ *record++ = ']'; /* End of the reocrd */
+
+ log_info->pkt_length += record - temp;
+}
+
+#define SYSLOG_PRECHECK(entry, s_type) \
+ if(PREDICT_FALSE((entry)->syslog_logging_index == EMPTY)) { \
+ SYSLOG_DEBUG_PRINTF1("\n1. Log Mapping failed") \
+ return; \
+ } \
+ logging_info = \
+ cnat_syslog_logging_info_pool + (entry)->syslog_logging_index; \
+ if(PREDICT_FALSE(logging_info->current_logging_context == NULL)) { \
+ cnat_syslog_create_logging_context(logging_info, s_type); \
+ if(PREDICT_FALSE(logging_info->current_logging_context == NULL)) { \
+ SYSLOG_DEBUG_PRINTF1("\n2. Log Mapping failed") \
+ return; \
+ } \
+ }
+
+void cnat_syslog_nat44_mapping_create(cnat_main_db_entry_t *db,
+ cnat_vrfmap_t *vrfmap, cnat_session_entry_t * sdb
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ )
+{
+ cnat_syslog_logging_info_t *logging_info = 0;
+ syslog_event_type_t e_type;
+ int start_port;
+
+ SYSLOG_CONFIG_DEBUG_PRINTF(4,"In Function %s\n", __func__);
+ SYSLOG_PRECHECK(vrfmap, NAT44)
+
+#ifndef NO_BULK_LOGGING
+ if(bulk_alloc > 0) { /* new bulk alloc - use bulk add template */
+ e_type = userbased_assign;
+ start_port = bulk_alloc;
+ } else if(bulk_alloc == CACHE_ALLOC_NO_LOG_REQUIRED) {
+ return; /* No logging required.. bulk port usage */
+ }
+ else { /* Individual logging .. fall back to old method */
+#endif
+ if(vrfmap->syslog_logging_policy == SESSION_LOG_ENABLE) {
+ e_type = sessionbased_assignD;
+ } else {
+ e_type = sessionbased_assign;
+ }
+ start_port = db->out2in_key.k.port;
+#ifndef NO_BULK_LOGGING
+ }
+#endif
+
+ cnat_syslog_insert_nat44_record(logging_info, db, vrfmap, sdb,
+ start_port, e_type);
+
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+
+ if (PREDICT_FALSE(logging_info->pkt_length >
+ logging_info->max_length_minus_max_record_size)) {
+ cnat_syslog_send_pkt(logging_info);
+ }
+}
+
+void cnat_syslog_ds_lite_mapping_create(cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry, cnat_session_entry_t *sdb
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ )
+{
+ cnat_syslog_logging_info_t *logging_info = 0;
+ syslog_event_type_t e_type;
+ int start_port;
+
+ SYSLOG_PRECHECK(dslite_entry, DSLite)
+
+#ifndef NO_BULK_LOGGING
+ if(bulk_alloc > 0) { /* new bulk alloc - use bulk add template */
+ e_type = userbased_assign;
+ start_port = bulk_alloc;
+ } else if(bulk_alloc == CACHE_ALLOC_NO_LOG_REQUIRED) {
+ return; /* No logging required.. bulk port usage */
+ }
+ else { /* Individual logging .. fall back to old method */
+#endif
+ if(PREDICT_FALSE(dslite_entry->syslog_logging_policy == SESSION_LOG_ENABLE)) {
+ e_type = sessionbased_assignD;
+ } else {
+ e_type = sessionbased_assign;
+ }
+ start_port = db->out2in_key.k.port;
+#ifndef NO_BULK_LOGGING
+ }
+#endif
+
+ cnat_syslog_insert_record(logging_info, db, dslite_entry, sdb,
+ start_port, e_type);
+
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+
+ if (PREDICT_FALSE(logging_info->pkt_length >
+ logging_info->max_length_minus_max_record_size)) {
+ cnat_syslog_send_pkt(logging_info);
+ }
+}
+
+void cnat_syslog_nat44_mapping_delete(cnat_main_db_entry_t *db,
+ cnat_vrfmap_t *vrfmap, cnat_session_entry_t *sdb
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ )
+{
+ cnat_syslog_logging_info_t *logging_info = 0;
+ syslog_event_type_t e_type;
+ int start_port;
+
+ SYSLOG_CONFIG_DEBUG_PRINTF(4,"In Function %s\n", __func__);
+ SYSLOG_PRECHECK(vrfmap, NAT44)
+
+#ifndef NO_BULK_LOGGING
+ if(bulk_alloc > 0) { /* new bulk alloc - use bulk add template */
+ e_type = userbased_withdraw;
+ start_port = bulk_alloc;
+ } else if(bulk_alloc == CACHE_ALLOC_NO_LOG_REQUIRED) {
+ return; /* No logging required.. bulk port usage */
+ }
+ else { /* Individual logging .. fall back to old method */
+#endif
+ if(vrfmap->syslog_logging_policy == SESSION_LOG_ENABLE) {
+ e_type = sessionbased_withdrawD;
+ } else {
+ e_type = sessionbased_withdraw;
+ }
+ start_port = db->out2in_key.k.port;
+#ifndef NO_BULK_LOGGING
+ }
+#endif
+ cnat_syslog_insert_nat44_record(logging_info, db, vrfmap, sdb,
+ start_port, e_type);
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+ if (PREDICT_FALSE(logging_info->pkt_length >
+ logging_info->max_length_minus_max_record_size)) {
+ cnat_syslog_send_pkt(logging_info);
+ }
+}
+
+void cnat_syslog_ds_lite_mapping_delete(cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry, cnat_session_entry_t *sdb
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ )
+{
+ cnat_syslog_logging_info_t *logging_info = 0;
+ syslog_event_type_t e_type;
+ int start_port;
+
+ SYSLOG_PRECHECK(dslite_entry, DSLite)
+
+#ifndef NO_BULK_LOGGING
+ if(bulk_alloc > 0) { /* new bulk alloc - use bulk add template */
+ e_type = userbased_withdraw;
+ start_port = bulk_alloc;
+ } else if(bulk_alloc == CACHE_ALLOC_NO_LOG_REQUIRED) {
+ return; /* No logging required.. bulk port usage */
+ }
+ else { /* Individual logging .. fall back to old method */
+#endif
+ if(PREDICT_FALSE(dslite_entry->syslog_logging_policy == SESSION_LOG_ENABLE)) {
+ e_type = sessionbased_withdrawD;
+ } else {
+ e_type = sessionbased_withdraw;
+ }
+ start_port = db->out2in_key.k.port;
+#ifndef NO_BULK_LOGGING
+ }
+#endif
+ cnat_syslog_insert_record(logging_info, db, dslite_entry, sdb,
+ start_port, e_type);
+
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+
+ if (PREDICT_FALSE(logging_info->pkt_length >
+ logging_info->max_length_minus_max_record_size)) {
+ cnat_syslog_send_pkt(logging_info);
+ }
+}
+
+void cnat_syslog_dslite_insert_port_exceeded(
+ cnat_syslog_logging_info_t *log_info,
+ dslite_key_t * key)
+{
+ /* This record should like this -
+ * [Portblockrunout <L4> <Original Source IP> <Inside VRF Name>
+ * <Original Source IPv6> - <Original Port> - - - -]
+ */
+ u32 network_order_ipv6[4];
+ unsigned char *temp, *record;
+
+ temp = record = &(log_info->current_logging_context->packet_data[
+ CNAT_NFV9_IP_HDR_OFFSET + log_info->pkt_length]);
+
+ /* Now we point to the location where record needs to be inserted */
+ *record++ = '['; /* Open the record */
+
+ /* Copy the record type */
+ clib_memcpy(record, sys_log_event[port_block_runout].event_name,
+ sys_log_event[port_block_runout].name_length);
+ record += sys_log_event[port_block_runout].name_length;
+ *record++ = SYSLOG_DELIMITER;
+
+ u16 my_proto_mask;
+ my_proto_mask = key->ipv4_key.k.vrf & CNAT_PRO_MASK;
+ if(PREDICT_TRUE(my_proto_mask == CNAT_TCP)) {
+ *record++ = '6';
+ } else if(PREDICT_TRUE(my_proto_mask == CNAT_UDP)) {
+ *record++ = '1';
+ *record++ = '7';
+ } else {
+ *record++ = '1';
+ }
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy the Original Source IP */
+ record += copy_ipv4_addr(record, key->ipv4_key.k.ipv4);
+ *record++ = SYSLOG_DELIMITER;
+
+ /* copy configured VRF NAME */
+ clib_memcpy(record, log_info->vrf_name, log_info->vrf_name_len);
+ record += log_info->vrf_name_len;
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy the IPV6 source address */
+ network_order_ipv6[0] = htonl(key->ipv6[0]);
+ network_order_ipv6[1] = htonl(key->ipv6[1]);
+ network_order_ipv6[2] = htonl(key->ipv6[2]);
+ network_order_ipv6[3] = htonl(key->ipv6[3]);
+
+ inet_ntop(AF_INET6,network_order_ipv6,record,INET6_ADDRSTRLEN);
+ record += strlen(record);
+ *record++ = SYSLOG_DELIMITER;
+
+ *record++ = SYSLOG_FIELD_ABSENT; /* No translated source ip */
+ *record++ = SYSLOG_DELIMITER;
+
+ record += u16_to_ascii_decimal_unaligned(
+ record, key->ipv4_key.k.port);
+ *record++ = SYSLOG_DELIMITER;
+
+ *record++ = SYSLOG_FIELD_ABSENT; /* No translated start port */
+ *record++ = SYSLOG_DELIMITER;
+
+ *record++ = SYSLOG_FIELD_ABSENT; /* No translated end port */
+ *record++ = SYSLOG_DELIMITER;
+
+ /*No Destination Info*/
+ *record++ = '-';
+ *record++ = SYSLOG_DELIMITER;
+ *record++ = '-';
+ *record++ = SYSLOG_DELIMITER;
+
+ *record++ = ']'; /* End of the reocrd */
+
+ log_info->pkt_length += record - temp;
+}
+
+void cnat_syslog_ds_lite_port_limit_exceeded(
+ dslite_key_t * key,
+ dslite_table_entry_t *dslite_entry)
+{
+ cnat_syslog_logging_info_t *logging_info = 0;
+
+ SYSLOG_PRECHECK(dslite_entry, DSLite)
+
+ cnat_syslog_dslite_insert_port_exceeded(logging_info, key);
+
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+
+ if (PREDICT_FALSE(logging_info->pkt_length >
+ logging_info->max_length_minus_max_record_size)) {
+ cnat_syslog_send_pkt(logging_info);
+ }
+}
+
+void cnat_syslog_nat44_insert_port_exceeded(
+ cnat_syslog_logging_info_t *log_info,
+ cnat_key_t * key)
+{
+ /* This record should like this -
+ * [Portblockrunout <L4> <Original Source IP> <Inside VRF Name>
+ * - - <Original Port> - - - -]
+ */
+ unsigned char *temp, *record;
+
+ temp = record = &(log_info->current_logging_context->packet_data[
+ CNAT_NFV9_IP_HDR_OFFSET + log_info->pkt_length]);
+
+ /* Now we point to the location where record needs to be inserted */
+ *record++ = '['; /* Open the record */
+
+ /* Copy the record type */
+ clib_memcpy(record, sys_log_event[port_block_runout].event_name,
+ sys_log_event[port_block_runout].name_length);
+ record += sys_log_event[port_block_runout].name_length;
+ *record++ = SYSLOG_DELIMITER;
+
+ u16 my_proto_mask;
+ my_proto_mask = key->k.vrf & CNAT_PRO_MASK;
+ if(PREDICT_TRUE(my_proto_mask == CNAT_TCP)) {
+ *record++ = '6';
+ } else if(PREDICT_TRUE(my_proto_mask == CNAT_UDP)) {
+ *record++ = '1';
+ *record++ = '7';
+ } else {
+ *record++ = '1';
+ }
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy the Original Source IP */
+ record += copy_ipv4_addr(record, key->k.ipv4);
+ *record++ = SYSLOG_DELIMITER;
+
+ /* copy configured VRF NAME */
+ clib_memcpy(record, log_info->vrf_name, log_info->vrf_name_len);
+ record += log_info->vrf_name_len;
+ *record++ = SYSLOG_DELIMITER;
+
+ /* No IPV6 source address for nat44 */
+ *record++ = '-';
+ *record++ = SYSLOG_DELIMITER;
+
+ *record++ = '-'; /* No translated source ip */
+ *record++ = SYSLOG_DELIMITER;
+
+ record += u16_to_ascii_decimal_unaligned(
+ record, key->k.port);
+ *record++ = SYSLOG_DELIMITER;
+
+ *record++ = '-'; /* No translated start port */
+ *record++ = SYSLOG_DELIMITER;
+
+ *record++ = '-'; /* No translated end port */
+ *record++ = SYSLOG_DELIMITER;
+
+ /*No Destination Info*/
+ *record++ = '-';
+ *record++ = SYSLOG_DELIMITER;
+ *record++ = '-';
+ *record++ = SYSLOG_DELIMITER;
+
+ *record++ = ']'; /* End of the reocrd */
+
+ log_info->pkt_length += record - temp;
+}
+
+void cnat_syslog_nat44_port_limit_exceeded(
+ cnat_key_t * key,
+ cnat_vrfmap_t *vrfmap)
+{
+ cnat_syslog_logging_info_t *logging_info = 0;
+
+ SYSLOG_PRECHECK(vrfmap, NAT44)
+
+ cnat_syslog_nat44_insert_port_exceeded(logging_info, key);
+
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+
+ if (PREDICT_FALSE(logging_info->pkt_length >
+ logging_info->max_length_minus_max_record_size)) {
+ cnat_syslog_send_pkt(logging_info);
+ }
+}
+
+void cnat_syslog_nat44_insert_tcp_seq_mismatch(
+ cnat_syslog_logging_info_t *log_info,
+ cnat_main_db_entry_t *db)
+{
+ /* This record should like this -
+ * [TCPseqmismatch <L4> <Original Source IP> <Inside VRF Name>
+ * - <Translated Source IP> <Original Port> <Translated Source Port> - - -]
+ */
+ unsigned char *temp, *record;
+
+ temp = record = &(log_info->current_logging_context->packet_data[
+ CNAT_NFV9_IP_HDR_OFFSET + log_info->pkt_length]);
+
+ /* Now we point to the location where record needs to be inserted */
+ *record++ = '['; /* Open the record */
+
+ /* Copy the record type */
+ clib_memcpy(record, sys_log_event[tcp_seq_mismatch].event_name,
+ sys_log_event[tcp_seq_mismatch].name_length);
+ record += sys_log_event[tcp_seq_mismatch].name_length;
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Next field is TCP */
+ *record++ = '6';
+ *record++ = SYSLOG_DELIMITER;
+
+ /* Copy the Original Source IP */
+ record += copy_ipv4_addr(record, db->in2out_key.k.ipv4);
+ *record++ = SYSLOG_DELIMITER;
+
+ /* copy configured VRF NAME */
+ clib_memcpy(record, log_info->vrf_name, log_info->vrf_name_len);
+ record += log_info->vrf_name_len;
+ *record++ = SYSLOG_DELIMITER;
+
+ /* No IPV6 source address for nat44 */
+ *record++ = '-';
+ *record++ = SYSLOG_DELIMITER;
+
+ record += copy_ipv4_addr(record, db->out2in_key.k.ipv4);
+ *record++ = SYSLOG_DELIMITER;
+
+ record += u16_to_ascii_decimal_unaligned(
+ record, db->in2out_key.k.port);
+ *record++ = SYSLOG_DELIMITER;
+
+ record += u16_to_ascii_decimal_unaligned(
+ record, db->out2in_key.k.port);
+ *record++ = SYSLOG_DELIMITER;
+
+ *record++ = '-'; /* No translated end port */
+ *record++ = SYSLOG_DELIMITER;
+
+ /*No Destination Info*/
+ *record++ = '-';
+ *record++ = SYSLOG_DELIMITER;
+ *record++ = '-';
+ *record++ = SYSLOG_DELIMITER;
+
+ *record++ = ']'; /* End of the reocrd */
+
+ log_info->pkt_length += record - temp;
+}
+
+void cnat_syslog_nat44_tcp_seq_mismatch(
+ cnat_main_db_entry_t *db,
+ cnat_vrfmap_t *vrfmap)
+{
+ cnat_syslog_logging_info_t *logging_info = 0;
+
+ SYSLOG_PRECHECK(vrfmap, NAT44)
+
+ cnat_syslog_nat44_insert_tcp_seq_mismatch(logging_info, db);
+
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+
+ if (PREDICT_FALSE(logging_info->pkt_length >
+ logging_info->max_length_minus_max_record_size)) {
+ cnat_syslog_send_pkt(logging_info);
+ }
+}
+#endif
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_syslog.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_syslog.h
new file mode 100644
index 00000000..931f4b9c
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_syslog.h
@@ -0,0 +1,190 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_syslog.h
+ *
+ * Copyright (c) 2011-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_SYSLOG_H__
+#define __CNAT_SYSLOG_H__
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vnet/pg/pg.h>
+#include <vppinfra/error.h>
+
+#include "cnat_db.h"
+#include "nat64_db.h"
+#include "cnat_log_common.h"
+#include "dslite_defs.h"
+
+#define SYSLOG_CONFIG_DEBUG_PRINTF(level, ...) \
+ if (config_debug_level > level) PLATFORM_DEBUG_PRINT(__VA_ARGS__);
+
+
+/* one time call at the beginning */
+void cnat_syslog_logging_init();
+
+/*
+ * unconditional call
+ * will check logging config inside
+ */
+void cnat_syslog_log_mapping_create(cnat_main_db_entry_t * db,
+ cnat_vrfmap_t *vrfmap);
+
+/*
+ * unconditional call
+ * will check logging config inside
+ */
+void cnat_syslog_log_mapping_delete(cnat_main_db_entry_t * db,
+ cnat_vrfmap_t *vrfmap);
+
+void cnat_syslog_ds_lite_mapping_create(cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry, cnat_session_entry_t *sdb
+#ifndef NO_BULK_LOGGING
+ , int bulk_alloc
+#endif
+ );
+
+void cnat_syslog_ds_lite_port_limit_exceeded(
+ dslite_key_t * key,
+ dslite_table_entry_t *dslite_entry);
+
+#define SYSLOG_TIMESTAMP_LENGTH 20
+
+#define CNAT_SYSLOG_VERSION_NUMBER 1
+#define CNAT_SYSLOG_PRIORITY 16*8+6
+/* facility = local0 + severity = info */
+
+#define MAX_SYSLOG_HOSTNAME_LEN 32
+
+/* 6 for priority + space
+ * 2 for version + space
+ * 21 YYYY MMM DD HH:MM:SS + space
+ * 33 for hostname + space
+ * 4 for App Name (-) + space + Proc ID (-) + space
+ * 7 for Msg ID (DSLite is the longest Msg ID so far + space
+ * 2 for Structured data (-) + space
+ */
+#define MAX_SYSLOG_HEADER_LEN 75
+
+/* 18 for Event Name (Portblockrunout is the longest as of now)
+ * 3 for L4 (including space)
+ * 16 for original souce IP + space
+ * 33 for inside vrf name + space
+ * 40 for original source IPV6 + space
+ * 16 for translated source IP + space
+ * 6 for original port + space
+ * 6 for translated first source port + space
+ * 5 for translated last source port
+ * 2 for [] enclosure
+ */
+#define MAX_SYSLOG_RECORD_LEN 145
+
+typedef enum {
+ NAT44,
+ DSLite
+} syslog_service_type_t;
+
+typedef enum {
+ userbased_assign,
+ userbased_withdraw,
+ sessionbased_assign,
+ sessionbased_withdraw,
+ sessionbased_assignD,
+ sessionbased_withdrawD,
+ port_block_runout,
+ tcp_seq_mismatch,
+ max_syslog_event_type
+} syslog_event_type_t;
+
+/*
+ * This structure store the Syslog Logging information on per
+ * collector basis. This structure is allocated from a pool and index
+ * to this structure is stored VRF MAP structures
+ */
+typedef struct {
+ /*
+ * nat64_id will be 0 for nat44 config and i_vrf_id, i_vrf will be 0
+ * for nat64 config. Nat64_id will be used while nat64 collector is
+ * search and i_vrf* for nat44 collector
+ */
+ /* Similarly for ds_lite, ds_lite_id will be used and nat64_id,
+ * ivrf_id shall be set to 0
+ */
+ u32 i_vrf_id; /* Inside VRF ID corresponding to this collector */
+ u16 i_vrf; /* Inside VRF (uidb_index) corresponding to this collector */
+ u16 ds_lite_id; /* DS Lite instance for this collector */
+ u16 port; /* Destination port number of the collector */
+
+ /*
+ * This field determines the maximum size of the Syslog information
+ * that can be stored in a logging packet
+ */
+ u16 max_length_minus_max_record_size;
+ u32 ipv4_address; /* Destination IP address of the collector */
+ /*
+ * Timestamp in UNIX seconds corresponding to when the current
+ * logging packet was created
+ */
+ u32 current_logging_context_timestamp;
+
+ /*
+ * Indicates if the entry is already deleted
+ */
+ u8 deleted;
+
+ u8 header_priority;
+ u16 pkt_length;
+
+ char header_hostname[MAX_SYSLOG_HOSTNAME_LEN];
+ char vrf_name[VRF_NAME_LEN_STORED];
+ u16 vrf_name_len;
+ u8 logging_policy;
+ /*
+ * current logging context
+ */
+ spp_ctx_t *current_logging_context;
+ spp_ctx_t *queued_logging_context;
+
+} cnat_syslog_logging_info_t;
+
+
+/*
+ * Global structure for CGN APP configuration
+ */
+typedef struct {
+
+ u16 cnat_syslog_disp_node_index;
+
+ /*
+ * Whether we have initialized the Syslog information
+ */
+ u8 cnat_syslog_init_done;
+
+} cnat_syslog_global_info_t;
+
+typedef struct {
+ u64 logging_context_creation_fail_count;
+ u64 downstream_constipation_count;
+ u64 logging_context_creation_deferred_count;
+} cnat_syslog_global_counters_t;
+
+extern cnat_syslog_logging_info_t *cnat_syslog_logging_info_pool;
+extern cnat_syslog_global_info_t cnat_syslog_global_info;
+
+#define SYSLOG_DEF_PATH_MTU 1500
+
+#endif /* __CNAT_SYSLOG_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_util.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_util.c
new file mode 100644
index 00000000..c3697b6b
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_util.c
@@ -0,0 +1,2256 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_util.c - cnat helpers
+ *
+ * Copyright (c) 2009-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/vec.h>
+#include <vppinfra/bitmap.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/pool.h>
+#include <vppinfra/clib.h>
+#include <vppinfra/error.h>
+
+#include "tcp_header_definitions.h"
+
+#if 0
+void spp_api_cnat_v4_config_dummy_t_handler
+(spp_api_cnat_v4_config_dummy_t *mp);
+
+void spp_api_cnat_v4_config_dummy_max_t_handler
+(spp_api_cnat_v4_config_dummy_max_t *mp);
+
+void spp_api_cnat_v4_config_icmp_timeout_t_handler
+(spp_api_cnat_v4_config_icmp_timeout_t *mp);
+
+void spp_api_cnat_clear_db_request_t_handler
+(spp_api_cnat_clear_db_request_t *mp);
+
+void spp_api_cnat_v4_debug_global_t_handler
+(spp_api_cnat_v4_debug_global_t *mp);
+
+void spp_api_cnat_v4_show_outside_entry_req_t_handler
+(spp_api_cnat_v4_show_outside_entry_req_t *mp);
+
+void spp_api_cnat_v4_show_inside_entry_req_t_handler
+(spp_api_cnat_v4_show_inside_entry_req_t *mp);
+
+void spp_api_cnat_show_statistics_summary_req_t_handler
+(spp_api_cnat_show_statistics_summary_req_t *mp);
+
+void cnat_db_create_db_entries_cmd (int argc, unsigned long *argv)
+{
+ int i, j ;
+ int nusers = 3000;
+
+ cnat_db_key_bucket_t key_info;
+ cnat_main_db_entry_t *db;
+ cnat_gen_icmp_info info;
+ cnat_key_t dest_info_dummy;
+
+ memset(&dest_info_dummy, 0, sizeof(cnat_key_t));
+ printf ("Create %d users, 100 translations each...\n", nusers);
+
+ for (i = 0; i < nusers; i++) {
+ for (j = 0; j < 100; j++) {
+
+ key_info.k.k.vrf = CNAT_TCP | (1 & CNAT_VRF_MASK);
+ key_info.k.k.ipv4 = 0x0c000001+i;
+ key_info.k.k.port = 1024+j;
+
+ db = cnat_get_main_db_entry_v2(&key_info, PORT_SINGLE,
+ PORT_TYPE_DYNAMIC, &info, &dest_info_dummy);
+
+ if (db == 0) {
+ printf ("OOPS: cnat_main_db_create failed users %d trans %d\n", i, j);
+ return; /*jli*/
+ }
+
+ db->entry_expires = cnat_current_time;
+
+ }
+ }
+}
+
+void db_test_clear (int argc, unsigned long *argv)
+{
+ spp_api_cnat_clear_db_request_t mp;
+
+ mp.wildcard = argv[0];
+ mp.protocol = argv[1];
+ mp.port_num = argv[2];
+ mp.inside_vrf = argv[3];
+ mp.ip_addr = argv[4];
+ spp_api_cnat_clear_db_request_t_handler(&mp);
+}
+
+/* test code*/
+void cnat_db_test_show (int argc, unsigned long *argv)
+{
+
+ spp_api_cnat_v4_show_inside_entry_req_t mp1[2000];
+ spp_api_cnat_v4_show_outside_entry_req_t mp2[30000];
+
+ if (argc > 1) {
+ if (argc != 7) {
+ printf("Usage: db test show dec((which)) dec((vrf)) dec((proto)) dec((ip)) dec((start_port)) dec((end_port)) dec((flags))\n");
+ return;
+ }
+
+ mp1[0].vrf_id = argv[1];
+ mp1[0].protocol = argv[2];;
+ mp1[0].ipv4_addr = argv[3];
+ mp1[0].start_port = argv[4];
+ mp1[0].end_port = argv[5];
+ mp1[0].flags = argv[6];
+ mp1[0].all_entries = 0;
+
+ if (argv[0] == 1) {
+ spp_api_cnat_v4_show_inside_entry_req_t_handler (&(mp1[0]));
+ } else {
+ spp_api_cnat_v4_show_outside_entry_req_t_handler (&(mp2[0]));
+ }
+
+ return;
+ } else {
+ printf("inside entries \n");
+ mp1[0].ipv4_addr = 0x016994CA;
+ mp1[0].vrf_id = 1;
+ mp1[0].all_entries = 0;
+ mp1[0].start_port = 32765;
+ mp1[0].end_port = 65535;
+ mp1[0].protocol = 2;
+ mp1[0].flags = 3;
+
+ spp_api_cnat_v4_show_inside_entry_req_t_handler (&(mp1[0]));
+
+ mp2[0].ipv4_addr = 0x640200c1;
+ mp2[0].vrf_id = 0;
+ mp2[0].start_port = 1025;
+ mp2[0].end_port = 62235;
+ mp2[0].protocol = 2;
+ mp2[0].flags = 3;
+
+ spp_api_cnat_v4_show_outside_entry_req_t_handler (&(mp2[0]));
+ }
+
+#if 1
+ {
+ spp_api_cnat_stats_node_mapping_t mp3[20000];
+ spp_api_cnat_stats_counter_mapping_t mp4[20000];
+ spp_api_cnat_stats_counter_values_t mp5[23000];
+
+ mp3[0].rc = 0;
+ spp_api_cnat_stats_node_mapping_t_handler (&mp3);
+ mp4[0].rc = 0;
+ spp_api_cnat_stats_counter_mapping_t_handler (&mp4);
+
+ mp5[0].flag = 1;
+ spp_api_cnat_stats_counter_values_t_handler(&mp5);
+ }
+#endif
+
+#if 0
+ mp1.ipv4_addr = 0x0A010102;
+ mp1.vrf_id = 1;
+ mp1.all_entries = 1;
+ mp1.protocol = 1;
+
+ spp_api_cnat_v4_show_inside_entry_req_t_handler (&mp1);
+
+
+ mp1.ipv4_addr = 0x0A010103;
+ mp1.vrf_id = 1;
+ mp1.all_entries = 1;
+ mp1.protocol = 2;
+
+ spp_api_cnat_v4_show_inside_entry_req_t_handler (&mp1);
+
+ mp6[0].inside_vrf_id = 1;
+ mp6[0].start_ipv4_address = 0x64020001;
+ mp6[0].end_ipv4_address = 0x64020101;
+ mp6[0].free_addr = 0;
+ mp6[0].flags = CNAT_TRANSLATION_ENTRY_STATIC;
+
+ spp_api_cnat_v4_show_freeUsed_entry_req_t_handler(&mp6);
+
+#endif
+ printf("returned here");
+
+ return;
+}
+
+
+
+void cnat_db_clear_all_entries (int argc, unsigned long *argv)
+{
+ cnat_main_db_entry_t * db;
+ u32 index;
+
+ pool_header_t * p = vec_header(cnat_main_db, sizeof(pool_header_t) );
+
+ for(index = 0; index < vec_len(cnat_main_db); index++) {
+
+ if ( !clib_bitmap_get(p->free_bitmap, index)) {
+
+ db = cnat_main_db + index;
+ cnat_delete_main_db_entry_v2(db);
+
+ }
+ }
+
+}
+
+
+void spp_log_cmd (int argc, unsigned long *argv)
+{
+ u16 num_traces;
+ u16 error_code;
+ u16 num_args;
+ u32 arg[7];
+ u8 i;
+
+ num_traces = argv[0];
+
+ for (i = 0; i < num_traces; i++) {
+ error_code = argv[1 + 4*i];
+ num_args = argv[2 + 4*i];
+ arg[0] = argv[3 + 4*i];
+ arg[1] = argv[4 + 4*i];
+
+ spp_printf(error_code, num_args, arg);
+ }
+}
+
+
+void cnat_db_create_random_entries (int argc, unsigned long *argv)
+{
+
+ platform_cnat_db_create_random_entries();
+}
+
+#define MAX_DEPTH 10
+
+void show_user_db_hash_chain_len() {
+
+ u32 max_len, len, n, i, max_idx, index, used;
+ cnat_user_db_entry_t * udb;
+ u32 hash_depth[MAX_DEPTH];
+
+ memset(hash_depth, 0, sizeof(u32)*MAX_DEPTH);
+
+ n = vec_len(cnat_user_hash);
+
+ used = 0;
+ max_len = 0;
+ for(i=0;i<n;i++) {
+
+ index = cnat_user_hash[i].next;
+
+ len = 0;
+ if (index != EMPTY) used++;
+
+ while (index != EMPTY) {
+ len++ ;
+ udb = cnat_user_db + index;
+ index = udb->user_hash.next;
+ }
+
+ if(len < (MAX_DEPTH-1) ) {
+ hash_depth[len]++;
+ } else {
+ hash_depth[MAX_DEPTH-1]++;
+ }
+
+ if (max_len < len) {
+ max_len = len;
+ max_idx = cnat_user_hash[i].next;
+ }
+ }
+
+ printf("Max user db hash length %u, total buckets %u used %u\n",
+ max_len, n, used);
+
+ for( i=1; i<(MAX_DEPTH - 1); i++) {
+ printf("Hash chain len %02d, entries count %d\n", i, hash_depth[i]);
+ }
+
+ printf("Hash chain len >%02d, entries count %d\n",
+ MAX_DEPTH-1, hash_depth[MAX_DEPTH-1]);
+
+}
+
+void show_main_db_hash_chain_len() {
+
+ u32 max_len, len, n, i, max_idx, index, used;
+ cnat_main_db_entry_t * db;
+ u32 hash_depth[MAX_DEPTH];
+
+ memset(hash_depth, 0, sizeof(u32)*MAX_DEPTH);
+
+ n = vec_len(cnat_in2out_hash);
+
+ used = 0;
+ max_len = 0;
+ for(i=0;i<n;i++) {
+
+ index = cnat_in2out_hash[i].next;
+
+ len = 0;
+ if (index != EMPTY) used++;
+
+ while (index != EMPTY) {
+ len++ ;
+ db = cnat_main_db + index;
+ index = db->in2out_hash.next;
+ }
+
+ if(len < (MAX_DEPTH-1) ) {
+ hash_depth[len]++;
+ } else {
+ hash_depth[MAX_DEPTH-1]++;
+ }
+
+ if (max_len < len) {
+ max_len = len;
+ max_idx = cnat_in2out_hash[i].next;
+ }
+ }
+
+ printf("Max main db I2O hash length %u, total buckets %u used %u\n",
+ max_len, n, used);
+
+ for( i=1; i<(MAX_DEPTH - 1); i++) {
+ printf("Hash chain len %02d, entries count %d\n", i, hash_depth[i]);
+ }
+
+ printf("Hash chain len >%02d, entries count %d\n",
+ MAX_DEPTH-1, hash_depth[MAX_DEPTH-1]);
+
+
+ memset(hash_depth, 0, sizeof(u32)*MAX_DEPTH);
+
+ n = vec_len(cnat_out2in_hash);
+ used = 0;
+ max_len = 0;
+
+ for(i=0;i<n;i++) {
+
+ index = cnat_out2in_hash[i].next;
+ len = 0;
+
+ if (index != EMPTY) used++;
+
+ while (index != EMPTY) {
+ len++ ;
+ db = cnat_main_db + index;
+ index = db->out2in_hash.next;
+ }
+
+ if(len < (MAX_DEPTH-1) ) {
+ hash_depth[len]++;
+ } else {
+ hash_depth[MAX_DEPTH-1]++;
+ }
+
+ if (max_len < len) {
+ max_len = len;
+ max_idx = cnat_in2out_hash[i].next;
+ }
+ }
+
+ printf("Max main db O2I hash length %u, total buckets %u used %u\n",
+ max_len, n, used);
+
+ for( i=1; i<(MAX_DEPTH - 1); i++) {
+ printf("Hash chain len %02d, entries count %d\n", i, hash_depth[i]);
+ }
+
+ printf("Hash chain len >%02d, entries count %d\n",
+ MAX_DEPTH-1, hash_depth[MAX_DEPTH-1]);
+
+
+}
+
+u32 db_free_entry (void * p) {
+
+ pool_header_t * h;
+ u32 free;
+
+ h = pool_header(p);
+
+ free = p == 0 ? 0: vec_len(h->free_indices);
+
+ return free;
+}
+
+void cnat_db_summary (int argc, unsigned long *argv) {
+
+ PLATFORM_DEBUG_PRINT("\n-----------------------------------------");
+ PLATFORM_DEBUG_PRINT("\nSummary DB");
+ PLATFORM_DEBUG_PRINT("\n-----------------------------------------\n");
+ u32 count1, count2, i;
+#ifndef NO_NAT64_DEF
+ extern void nat64_session_db_summary();
+#endif
+ /* main db active entry count*/
+ count1 = vec_len(cnat_main_db);
+ count2 = db_free_entry(cnat_main_db);
+
+ PLATFORM_DEBUG_PRINT("main db entries: total %u, active %u, free %u\n", count1, count1 - count2, count2);
+
+ /* user db active entry count */
+ count1 = vec_len(cnat_user_db);
+ count2 = db_free_entry(cnat_user_db);
+
+ PLATFORM_DEBUG_PRINT("user db entries: total %u, active %u, free %u\n", count1, count1 - count2, count2);
+
+
+ /* user db active entry count */
+#ifndef NO_NAT64_DEF
+ nat64_session_db_summary();
+#endif
+
+ /* main db hash i2o o2i usage count */
+ count1 = 0;
+ count2 = 0;
+
+ for (i=0; i< CNAT_MAIN_HASH_SIZE; i++) {
+
+ if(cnat_in2out_hash[i].next != ~0) count1++;
+ if(cnat_out2in_hash[i].next != ~0) count2++;
+
+ }
+
+ PLATFORM_DEBUG_PRINT("main hash in2out: total %6u, used %u (%.2f%%)\n",
+ CNAT_MAIN_HASH_SIZE, count1,
+ (100.0*count1)/CNAT_MAIN_HASH_SIZE);
+
+ PLATFORM_DEBUG_PRINT("main hash out2in: total %6u, used %u (%.2f%%)\n",
+ CNAT_MAIN_HASH_SIZE, count2,
+ (100.0 * count1)/CNAT_MAIN_HASH_SIZE);
+
+ /* use db hashing usage count */
+
+ count1 = 0;
+
+ for (i=0; i< CNAT_USER_HASH_SIZE; i++) {
+ if(cnat_user_hash[i].next != ~0) count1++;
+ }
+
+ PLATFORM_DEBUG_PRINT("user db hash: total %6u, used %u (%.2f%%)\n",
+ CNAT_USER_HASH_SIZE, count1,
+ (100.0*count1)/CNAT_USER_HASH_SIZE);
+
+ PLATFORM_DEBUG_PRINT("\nNull pointer exceptions:\n");
+ PLATFORM_DEBUG_PRINT("packet_pool: null enq : %10u, null deq : %10u\n",null_enq_pkt, null_deq_pkt);
+ PLATFORM_DEBUG_PRINT("ctx_pool : null enq : %10u, null deq : %10u\n",null_enq_ctx, null_deq_ctx);
+ PLATFORM_DEBUG_PRINT("wqe_pool : null enq : %10u, null deq : %10u\n",null_enq_wqe, null_deq_wqe);
+
+ PLATFORM_DEBUG_PRINT("\nReceived Packet Errors on SPI:\n");
+ PLATFORM_DEBUG_PRINT("rcv_pkt_errs: %10u\n",rcv_pkt_errs);
+
+ PLATFORM_DEBUG_PRINT("\nctx/sf allocation failure errors: \n");
+#ifndef CGN_PERF_SCALE_DEBUG
+ PLATFORM_DEBUG_PRINT("Warning: collection of error counts <with timestamp> is disabled.\n");
+ PLATFORM_DEBUG_PRINT("sf alloc errors: %10u, ctx alloc errors: %10u\n",sf_alloc_errs,ctx_alloc_errs);
+#else
+ for(i=0;i<COUNTER_BUFFER_SIZE;i++)
+ PLATFORM_DEBUG_PRINT("<%2d>Timestamp <sec>: %10u, sf errors: %10u, ctx errors: %10u\n",\
+ i,err_cnt_arr[i].timestamp,\
+ err_cnt_arr[i].sf_error_counter, \
+ err_cnt_arr[i].ctx_error_counter);
+#endif
+}
+
+void cnat_db_hash_summary (int argc, unsigned long *argv) {
+
+ show_main_db_hash_chain_len();
+
+ show_user_db_hash_chain_len();
+}
+
+/*
+ * cnat_port_alloc
+ * This function is now deprecated...
+ *
+ */
+#ifdef LB_PORT
+int cnat_port_alloc (cnat_portmap_t *cnat_portmap, u16 *portmap_inuse,
+ int cnat_instance,
+ port_alloc_t atype, port_pair_t ptype,
+ int *index, u32 *ipv4_address, u16 *base_port)
+#else
+int cnat_port_alloc (cnat_portmap_t *cnat_portmap, u16 *portmap_inuse,
+ port_alloc_t atype, port_pair_t ptype,
+ int *index, u32 *ipv4_address, u16 *base_port)
+#endif
+{
+
+ return (0);
+}
+
+/*
+ * cnat_port_free
+ * This function is now deprecated...
+ *
+ */
+#ifdef LB_PORT
+void cnat_port_free (cnat_portmap_t *cnat_portmap, u16 *portmap_inuse,
+ int instance, int index, port_pair_t ptype, u16 base_port)
+#else
+void cnat_port_free (cnat_portmap_t *cnat_portmap, u16 *portmap_inuse,
+ int index, port_pair_t ptype, u16 base_port)
+#endif
+{
+}
+
+void spp_api_cnat_port_allocate_t_handler(spp_api_cnat_port_allocate_t *mp)
+{
+ int i, j, k1, k2;
+ int pm_index;
+ u32 ipv4_address;
+ u16 aport;
+ int rv;
+ char *out1, *out2, *out_f;
+ port_alloc_t pt1, pt2;
+ cnat_portmap_t *pm = 0;
+ u16 *pm_inuse = 0;
+ u32 *firstp =0;
+ u32 nr_ports =0;
+ u32 nodd_ports = 0;
+ u32 neven_ports = 0;
+#ifdef LB_PORT
+ u32 my_instance = 1;
+#endif
+ char out_r[12] = "allocated-r";
+ char out_o[12] = "allocated-o";
+ char out_e[12] = "allocated-e";
+
+
+ /*
+ * this command is run after db create portmap
+ * vrf is hardcode to 1
+ */
+
+ /* Already have a portmap vector for this VRF? */
+ for (i = 0; i < vec_len(cnat_portmap_indices_by_vrf); i++) {
+ if (cnat_portmap_indices_by_vrf[i] == mp->vrf) {
+ pm = cnat_portmaps[i];
+ pm_inuse = cnat_portmaps_inuse[i];
+ goto found_portmaps;
+ }
+ }
+
+ printf("need to run db create portmaps first 0x%d\n",
+ vec_len(cnat_portmap_indices_by_vrf));
+ return;
+
+found_portmaps:
+ nr_ports = mp->nr_ports;
+ nodd_ports = mp->nodd_ports;
+ neven_ports = mp->neven_ports;
+
+ if ((nr_ports + nodd_ports + neven_ports ) > (PORTS_PER_ADDR)) {
+ printf("invalid port# nr_ports %d + odd %d + even %d "
+ "should be less than 200 \n", nr_ports, nodd_ports, neven_ports);
+ return;
+ }
+
+ /*
+ * first port
+ */
+ firstp = nr_ports ? (&nr_ports) : (nodd_ports ? (&nodd_ports) : (&neven_ports));
+ if (!(*firstp)) {
+ printf("invalid port# nr_ports %d odd %d even %d ",
+ nr_ports, nodd_ports, neven_ports);
+ }
+ out_f = nr_ports ? out_r : (nodd_ports ? out_o : out_e);
+
+#ifdef LB_PORT
+ rv = cnat_port_alloc (pm, pm_inuse, my_instance,
+ PORT_ALLOC_ANY, PORT_S_ODD,
+ &pm_index, &ipv4_address, &aport);
+#else
+ rv = cnat_port_alloc (pm, pm_inuse,
+ PORT_ALLOC_ANY, PORT_S_ODD,
+ &pm_index, &ipv4_address, &aport);
+#endif
+
+ if (!rv) {
+ printf("failed-o\n");
+ return;
+ }
+ printf("%s %8d %10x %8d\n", out_f,
+ pm_index, ipv4_address, aport);
+
+ (*firstp)--;
+
+ for (i=0; i < nr_ports; i++) {
+#ifdef LB_PORT
+ rv = cnat_port_alloc (pm, pm_inuse, my_instance,
+ PORT_ALLOC_DIRECTED, PORT_SINGLE,
+ &pm_index, &ipv4_address, &aport);
+#else
+ rv = cnat_port_alloc (pm, pm_inuse,
+ PORT_ALLOC_DIRECTED, PORT_SINGLE,
+ &pm_index, &ipv4_address, &aport);
+#endif
+ if (rv) {
+ printf("%s %8d %10x %8d\n", out_r,
+ pm_index, ipv4_address, aport);
+ } else {
+ printf("%s failed\n", out_r);
+ return;
+ }
+ }
+
+ if (nodd_ports > neven_ports) {
+ k1 = nodd_ports;
+ k2 = neven_ports;
+ pt1 = PORT_S_ODD;
+ pt2 = PORT_S_EVEN;
+ out1 = out_o;
+ out2 = out_e;
+ } else {
+ k1= neven_ports;
+ pt1 = PORT_S_EVEN;
+ k2 = nodd_ports;
+ pt2 = PORT_S_ODD;
+ out1 = out_e;
+ out2 = out_o;
+ }
+
+ j = 0;
+ for (i=0; i < k1; i++) {
+#ifdef LB_PORT
+ rv = cnat_port_alloc (pm, pm_inuse, my_instance,
+ PORT_ALLOC_DIRECTED, pt1,
+ &pm_index, &ipv4_address, &aport);
+#else
+ rv = cnat_port_alloc (pm, pm_inuse,
+ PORT_ALLOC_DIRECTED, pt1,
+ &pm_index, &ipv4_address, &aport);
+#endif
+ if (rv) {
+ printf("%s %8d %10x %8d\n", out1,
+ pm_index, ipv4_address, aport);
+ } else {
+ printf("%s failed\n", out1);
+ return;
+ }
+
+ if (j < k2) {
+#ifdef LB_PORT
+ rv = cnat_port_alloc (pm, pm_inuse, my_instance,
+ PORT_ALLOC_DIRECTED, pt2,
+ &pm_index, &ipv4_address, &aport);
+#else
+ rv = cnat_port_alloc (pm, pm_inuse,
+ PORT_ALLOC_DIRECTED, pt2,
+ &pm_index, &ipv4_address, &aport);
+#endif
+
+ if (rv) {
+ printf("%s %8d %10x %8d\n", out2,
+ pm_index, ipv4_address, aport);
+ j++;
+ } else {
+ printf("%s failed\n", __FUNCTION__);
+ return;
+ }
+ }
+ }
+}
+
+void cnat_db_summary_stats (int argc, unsigned long *argv)
+{
+ spp_api_cnat_show_statistics_summary_req_t mp[50000];
+
+ spp_api_cnat_show_statistics_summary_req_t_handler(&(mp[0]));
+}
+
+void cnat_debug_global_test (int argc, unsigned long *argv)
+{
+ spp_api_cnat_v4_debug_global_t *mp;
+ spp_api_cnat_v4_config_dummy_t mp1;
+ spp_api_cnat_v4_config_icmp_timeout_t mp2[10];
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+
+
+ mp->_spp_msg_id = SPP_API_CNAT_V4_DEBUG_GLOBAL;
+ mp->debug_flag = argv[0];
+
+ platform_send_msg(mp);
+
+ mp2[0].default_value = 3;
+
+ spp_api_cnat_v4_config_dummy_t_handler(&mp1);
+ spp_api_cnat_v4_config_icmp_timeout_t_handler(&(mp2[0]));
+}
+
+void cnat_debug_inside_test (int argc, unsigned long *argv)
+{
+
+ spp_api_cnat_v4_debug_in2out_private_addr_t *mp;
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+
+
+ mp->_spp_msg_id = SPP_API_CNAT_V4_DEBUG_IN2OUT_PRIVATE_ADDR;
+
+ mp->start_addr = spp_host_to_net_byte_order_32(argv[0]);
+ mp->end_addr = spp_host_to_net_byte_order_32(argv[1]);
+ mp->i_vrf = spp_host_to_net_byte_order_16(argv[2]);
+ mp->debug_flag = spp_host_to_net_byte_order_32(argv[3]);
+
+ platform_send_msg(mp);
+}
+
+void cnat_config_ports_user (int argc, unsigned long *argv)
+{
+ spp_api_cnat_v4_config_port_limit_t *mp;
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+
+
+ mp->_spp_msg_id = SPP_API_CNAT_V4_CONFIG_PORT_LIMIT;
+
+ mp->port_limit = spp_host_to_net_byte_order_16(argv[0]);
+
+ platform_send_msg(mp);
+
+}
+
+void cnat_debug_outside_test (int argc, unsigned long *argv)
+{
+
+ spp_api_cnat_v4_debug_out2in_public_addr_t *mp;
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+
+
+ mp->_spp_msg_id = SPP_API_CNAT_V4_DEBUG_OUT2IN_PUBLIC_ADDR;
+
+ mp->start_addr = spp_host_to_net_byte_order_32(argv[0]);
+ mp->end_addr = spp_host_to_net_byte_order_32(argv[1]);
+ mp->o_vrf = spp_host_to_net_byte_order_16(argv[2]);
+ mp->debug_flag = spp_host_to_net_byte_order_32(argv[3]);
+
+ platform_send_msg(mp);
+}
+
+void cnat_debug_udp_dump (int argc, unsigned long *argv)
+{
+
+ spp_api_cnat_p2mp_debug_request_t *mp;
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+
+
+ mp->_spp_msg_id = SPP_API_CNAT_P2MP_DEBUG_REQUEST;
+ mp->dump_type =
+ spp_host_to_net_byte_order_16(CNAT_DEBUG_GENERIC_COMMAND_DEBUG_FLAGS);
+
+ if (spp_host_to_net_byte_order_32(argv[0]) == 1) {
+ mp->param[0] = spp_host_to_net_byte_order_32(
+ CNAT_DEBUG_FLAG_UDP_INSIDE_PACKET_DUMP);
+ } else {
+ mp->param[0] = spp_host_to_net_byte_order_32(
+ CNAT_DEBUG_FLAG_UDP_OUTSIDE_PACKET_DUMP);
+ }
+ mp->param[1] = spp_host_to_net_byte_order_32(argv[1]);
+
+ platform_send_msg(mp);
+
+
+
+}
+
+void cnat_debug_udp_crc (int argc, unsigned long *argv)
+{
+ spp_api_cnat_p2mp_debug_request_t *mp;
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+
+
+ mp->_spp_msg_id = SPP_API_CNAT_P2MP_DEBUG_REQUEST;
+ mp->dump_type =
+ spp_host_to_net_byte_order_16(CNAT_DEBUG_GENERIC_COMMAND_DEBUG_FLAGS);
+
+ if (spp_host_to_net_byte_order_32(argv[0]) == 1) {
+ mp->param[0] = spp_host_to_net_byte_order_32(
+ CNAT_DEBUG_FLAG_UDP_INSIDE_CHECKSUM_MODIFY);
+ } else {
+ mp->param[0] = spp_host_to_net_byte_order_32(
+ CNAT_DEBUG_FLAG_UDP_OUTSIDE_CHECKSUM_MODIFY);
+ }
+ mp->param[1] = spp_host_to_net_byte_order_32(argv[1]);
+
+ platform_send_msg(mp);
+
+}
+
+void cnat_db_allocate_port_cmd (int argc, unsigned long *argv)
+{
+ spp_api_cnat_port_allocate_t *mp;
+
+
+ if (!argc) {
+ printf("no port# defined\n");
+ return;
+ }
+
+ if ( argc < 3) {
+ printf("no port# defined\n");
+ return;
+ }
+
+ if ((argc == 3) && (argv[0] == 0) && (argv[1] == 0) && (argv[2] == 0)) {
+ printf("no port# defined\n");
+ return;
+ }
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+
+
+ mp->_spp_msg_id = SPP_API_CNAT_PORT_ALLOCATE;
+ mp->nr_ports = argv[0];
+ mp->nodd_ports = argv[1];
+ mp->neven_ports = argv[2];
+ mp->vrf = 1;
+
+ platform_send_msg(mp);
+}
+
+
+void spp_api_cnat_port_clear_t_handler(spp_api_cnat_port_clear_t *mp)
+{
+ u32 i;
+ cnat_portmap_t *pm = 0;
+ u16 *pm_inuse = 0;
+#ifdef LB_PORT
+ u32 my_instance = 1;
+#endif
+
+
+ /*
+ * this command is run after db create port
+ * vrf is hardcode to 1
+ */
+
+ /* Already have a portmap vector for this VRF? */
+ for (i = 0; i < vec_len(cnat_portmap_indices_by_vrf); i++) {
+ if (cnat_portmap_indices_by_vrf[i] == mp->vrf) {
+ pm = cnat_portmaps[i];
+ pm_inuse = cnat_portmaps_inuse[i];
+ goto found_portmaps;
+ }
+ }
+
+ printf("portmap is not created 0x%d\n",
+ vec_len(cnat_portmap_indices_by_vrf));
+ return;
+
+found_portmaps:
+ if (mp->pm_index >= vec_len(pm)) {
+ printf("invalid port_index 0x%d >= 0x%d\n",
+ mp->pm_index, vec_len(pm));
+ return;
+ }
+
+#ifdef LB_PORT
+ cnat_port_free(pm, pm_inuse, my_instance,
+ mp->pm_index, PORT_SINGLE, mp->port);
+#else
+ cnat_port_free(pm, pm_inuse,
+ mp->pm_index, PORT_SINGLE, mp->port);
+#endif
+ printf("\n pm_index %d port %d is deleted\n", mp->pm_index, mp->port);
+}
+
+
+
+void cnat_db_clear_port_cmd (int argc, unsigned long *argv)
+{
+ spp_api_cnat_port_clear_t *mp;
+
+ if (!argc) {
+ printf("no port# defined\n");
+ return;
+ }
+
+ if ( argc < 2 ) {
+ printf("no port# defined\n");
+ return;
+ }
+
+ if (argc > 2) {
+ printf("too many port# defined\n");
+ return;
+ }
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+
+
+ mp->_spp_msg_id = SPP_API_CNAT_PORT_CLEAR;
+ mp->pm_index = argv[0];
+ mp->port = argv[1];
+ mp->vrf = 1;
+
+ platform_send_msg(mp);
+}
+
+
+void spp_api_cnat_v4_add_vrf_map_t_handler
+(spp_api_cnat_v4_add_vrf_map_t *mp);
+
+void spp_api_cnat_v4_del_vrf_map_t_handler
+(spp_api_cnat_v4_del_vrf_map_t *mp);
+
+void spp_api_cnat_v4_add_static_port_t_handler
+(spp_api_cnat_v4_add_static_port_t *mp);
+
+void spp_api_cnat_v4_del_static_port_t_handler
+(spp_api_cnat_v4_del_static_port_t *mp);
+
+
+void cnat_db_create_vrfmap_cmd (int argc, unsigned long *argv)
+{
+ spp_api_cnat_v4_add_vrf_map_t *mp;
+
+ if ((argc != 4)) {
+ printf("need right input\n");
+ return;
+ }
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+ mp->_spp_msg_id = SPP_API_CNAT_V4_ADD_VRF_MAP;
+ mp->i_vrf = spp_host_to_net_byte_order_16(argv[0]);
+ mp->o_vrf = spp_host_to_net_byte_order_16(argv[1]);
+ mp->start_addr[0] = spp_host_to_net_byte_order_32(argv[2]);
+ mp->end_addr[0] = spp_host_to_net_byte_order_32(argv[3]);
+
+ /*
+ * Some hardcoded values for the vrf ids
+ */
+ mp->i_vrf_id = spp_host_to_net_byte_order_32(0x00000100 | mp->i_vrf);
+ mp->o_vrf_id = spp_host_to_net_byte_order_32(0x00000200 | mp->o_vrf);
+
+ platform_send_msg(mp);
+}
+
+
+void cnat_db_delete_vrfmap_cmd (int argc, unsigned long *argv)
+{
+ spp_api_cnat_v4_del_vrf_map_t *mp;
+
+ if (argc != 4) {
+ printf("need right input\n");
+ return;
+ }
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+ mp->_spp_msg_id = SPP_API_CNAT_V4_DEL_VRF_MAP;
+ mp->i_vrf = spp_host_to_net_byte_order_16(argv[0]);
+ mp->start_addr[0] = spp_host_to_net_byte_order_32(argv[2]);
+ mp->end_addr[0] = spp_host_to_net_byte_order_32(argv[3]);
+
+ platform_send_msg(mp);
+}
+
+void cnat_db_add_svi_cmd (int argc, unsigned long *argv)
+{
+ spp_api_cnat_config_svi_params_t *mp;
+
+ if (argc != 3) {
+ printf("need right input\n");
+ return;
+ }
+
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+ mp->_spp_msg_id = SPP_API_CNAT_CONFIG_SVI_PARAMS;
+ mp->uidb_index = spp_host_to_net_byte_order_16(argv[1]);
+ mp->svi_ipv4_addr = spp_host_to_net_byte_order_32(argv[2]);
+ platform_send_msg(mp);
+ return;
+}
+
+
+
+void spp_api_cnat_port_create_t_handler(spp_api_cnat_port_create_t *mp)
+{
+ int i, j, k1, k2;
+ int my_index;
+ u32 ipv4_address;
+ u16 aport;
+ u32 pm_len =0;
+ cnat_errno_t rv;
+ u16 i_vrf;
+ char *out1, *out2, *out_f;
+ port_alloc_t pt1, pt2;
+ cnat_vrfmap_t *my_vrfmap;
+ cnat_portmap_v2_t *pm = 0;
+ u32 *firstp =0;
+ u32 nr_ports =0;
+ u32 nodd_ports = 0;
+ u32 neven_ports = 0;
+#ifdef LB_PORT
+ u32 my_instance = 1;
+#endif
+ char out_r[12] = "allocated-r";
+ char out_o[12] = "allocated-o";
+ char out_e[12] = "allocated-e";
+#ifndef NO_BULK_LOGGING
+ int nfv9_log_req;
+#endif
+
+ nr_ports = mp->nr_ports;
+ nodd_ports = mp->nodd_ports;
+ neven_ports = mp->neven_ports;
+ i_vrf = mp->vrf;
+
+ /*
+ * this command is run after db create vrfmap
+ * or using vrf id in init function
+ */
+ /* Already have a portmap vector for this VRF? */
+ pool_foreach (my_vrfmap, cnat_map_by_vrf, ({
+ if ((my_vrfmap->status == S_RUN) &&
+ (my_vrfmap->i_vrf == i_vrf)) {
+ pm = my_vrfmap->portmap_list;
+ pm_len = vec_len(pm);
+ if (pm_len) {
+ goto found_portmaps;
+ }
+ }
+ }));
+
+ printf("need to run db create vrfmaps first for this vrf0x%d\n", pm_len);
+ return;
+
+found_portmaps:
+
+ if ((nr_ports + nodd_ports + neven_ports ) > (PORTS_PER_ADDR)) {
+ printf("invalid port# nr_ports %d + odd %d + even %d "
+ "should be less than 200 \n", nr_ports, nodd_ports, neven_ports);
+ return;
+ }
+
+ /*
+ * first port
+ */
+ firstp = nr_ports ? (&nr_ports) : (nodd_ports ? (&nodd_ports) : (&neven_ports));
+ if (!(*firstp)) {
+ printf("invalid port# nr_ports %d odd %d even %d ",
+ nr_ports, nodd_ports, neven_ports);
+ }
+ out_f = nr_ports ? out_r : (nodd_ports ? out_o : out_e);
+
+ rv = cnat_dynamic_port_alloc_v2 (pm, PORT_ALLOC_ANY, PORT_S_ODD,
+ &my_index, &ipv4_address, &aport,
+ cnat_static_port_range
+#ifndef NO_BULK_LOGGING
+ , BULKSIZE_FROM_VRFMAP(my_vrfmap),
+ &nfv9_log_req
+#endif
+ , 0,
+ &(my_vrfmap->rseed_ip)
+ );
+
+ if (rv != CNAT_SUCCESS) {
+ printf("failed-o\n");
+ return;
+ }
+ printf("%s %8d %10x %8d\n", out_f,
+ my_index, ipv4_address, aport);
+
+ (*firstp)--;
+
+ for (i=0; i < nr_ports; i++) {
+ rv = cnat_dynamic_port_alloc_v2 (pm, PORT_ALLOC_DIRECTED, PORT_SINGLE,
+ &my_index, &ipv4_address, &aport,
+ cnat_static_port_range
+#ifndef NO_BULK_LOGGING
+ , BULKSIZE_FROM_VRFMAP(my_vrfmap),
+ &nfv9_log_req
+#endif
+ , 0,
+ &(my_vrfmap->rseed_ip)
+ );
+
+ if (rv == CNAT_SUCCESS) {
+ printf("%s %8d %10x %8d\n", out_r,
+ my_index, ipv4_address, aport);
+ } else {
+ printf("%s failed\n", __FUNCTION__);
+ return;
+ }
+ }
+
+ if (nodd_ports > neven_ports) {
+ k1 = nodd_ports;
+ k2 = neven_ports;
+ pt1 = PORT_S_ODD;
+ pt2 = PORT_S_EVEN;
+ out1 = out_o;
+ out2 = out_e;
+ } else {
+ k1= neven_ports;
+ pt1 = PORT_S_EVEN;
+ k2 = nodd_ports;
+ pt2 = PORT_S_ODD;
+ out1 = out_e;
+ out2 = out_o;
+ }
+
+ j = 0;
+ for (i=0; i < k1; i++) {
+ rv = cnat_dynamic_port_alloc_v2 (pm, PORT_ALLOC_DIRECTED, pt1,
+ &my_index, &ipv4_address, &aport,
+ cnat_static_port_range
+#ifndef NO_BULK_LOGGING
+ , BULKSIZE_FROM_VRFMAP(my_vrfmap),
+ &nfv9_log_req
+#endif
+ , 0,
+ &(my_vrfmap->rseed_ip)
+ );
+
+ if (rv == CNAT_SUCCESS) {
+ printf("%s %8d %10x %8d\n", out1,
+ my_index, ipv4_address, aport);
+ } else {
+ printf("%s failed\n", __FUNCTION__);
+ return;
+ }
+
+ if (j < k2) {
+ rv = cnat_dynamic_port_alloc_v2 (pm, PORT_ALLOC_DIRECTED, pt2,
+ &my_index, &ipv4_address, &aport,
+ cnat_static_port_range
+#ifndef NO_BULK_LOGGING
+ , BULKSIZE_FROM_VRFMAP(my_vrfmap),
+ &nfv9_log_req
+#endif
+ , 0,
+ &(my_vrfmap->rseed_ip)
+ );
+
+ if (rv == CNAT_SUCCESS) {
+ printf("%s %8d %10x %8d\n", out2,
+ my_index, ipv4_address, aport);
+ j++;
+ } else {
+ printf("%s failed\n", __FUNCTION__);
+ return;
+ return;
+ }
+ }
+ }
+}
+
+
+void cnat_db_create_port_cmd (int argc, unsigned long *argv)
+{
+ spp_api_cnat_port_create_t *mp;
+
+ if (argc != 4) {
+ printf("no proper input defined\n");
+ return;
+ }
+
+ if ((argv[0] == 0) && (argv[1] == 0) && (argv[2] == 0)) {
+ printf("no port# defined\n");
+ return;
+ }
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+
+
+ mp->_spp_msg_id = SPP_API_CNAT_PORT_CREATE;
+ mp->nr_ports = argv[0];
+ mp->nodd_ports = argv[1];
+ mp->neven_ports = argv[2];
+ mp->vrf = argv[3];
+
+ platform_send_msg(mp);
+}
+
+void spp_api_cnat_port_delete_t_handler(spp_api_cnat_port_delete_t *mp)
+{
+ u32 pm_len;
+ cnat_vrfmap_t *my_vrfmap;
+ cnat_portmap_v2_t *pm = 0;
+
+ u32 my_index, my_port;
+ u16 i_vrf;
+#ifdef LB_PORT
+ u32 my_instance = 1;
+#endif
+
+ my_index = mp->pm_index;
+ my_port = mp->port;
+ i_vrf = mp->vrf;
+
+ /*
+ * this command is run after db create port
+ */
+ pool_foreach (my_vrfmap, cnat_map_by_vrf, ({
+ if (my_vrfmap->i_vrf == i_vrf) {
+ pm = my_vrfmap->portmap_list;
+ pm_len = vec_len(pm);
+ if (pm_len) {
+ goto found_portmaps;
+ }
+ }
+ }));
+
+ printf("portmap is not created 0x%d\n",
+ vec_len(cnat_portmap_indices_by_vrf));
+ return;
+
+found_portmaps:
+ if (my_index >= pm_len) {
+ printf("invalid port_index 0x%d >= 0x%d\n",
+ my_index, pm_len);
+ return;
+ }
+
+#ifdef LB_PORT
+ cnat_port_free_v2(pm, my_instance,
+ my_index, PORT_SINGLE, mp->port,cnat_static_port_range);
+#else
+ cnat_port_free_v2(pm, my_index, PORT_SINGLE, mp->port,cnat_static_port_range);
+#endif
+ printf("\n pm_index %d port %d is deleted\n", mp->pm_index, mp->port);
+}
+
+void cnat_db_delete_port_cmd (int argc, unsigned long *argv)
+{
+ spp_api_cnat_port_clear_t *mp;
+
+ if (argc != 3) {
+ printf("no proper input defined\n");
+ return;
+ }
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+
+
+ mp->_spp_msg_id = SPP_API_CNAT_PORT_DELETE;
+ mp->pm_index = argv[0];
+ mp->port = argv[1];
+ mp->vrf = argv[2];
+ platform_send_msg(mp);
+}
+
+void cnat_db_create_static_fwd_cmd (int argc, unsigned long *argv)
+{
+ spp_api_cnat_v4_add_static_port_t *mp;
+
+ if (argc != 4) {
+ printf("need right input\n");
+ return;
+ }
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+ mp->_spp_msg_id = SPP_API_CNAT_V4_ADD_STATIC_PORT;
+ mp->i_vrf = spp_host_to_net_byte_order_16(argv[0]);
+ mp->i_ip = spp_host_to_net_byte_order_32(argv[1]);
+ mp->i_port = spp_host_to_net_byte_order_16(argv[2]);
+ mp->proto = argv[3];
+
+ platform_send_msg(mp);
+ return;
+}
+
+void cnat_db_create_static_fwd_stby_cmd (int argc, unsigned long *argv)
+{
+ spp_api_cnat_v4_add_static_port_t *mp;
+
+ if (argc != 7) {
+ printf("need right input\n");
+ return;
+ }
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+ mp->_spp_msg_id = SPP_API_CNAT_V4_ADD_STATIC_PORT;
+ mp->i_vrf = spp_host_to_net_byte_order_16(argv[0]);
+ mp->i_ip = spp_host_to_net_byte_order_32(argv[1]);
+ mp->i_port = spp_host_to_net_byte_order_16(argv[2]);
+ mp->proto = argv[3];
+ mp->o_vrf_id = spp_host_to_net_byte_order_32(argv[4]);
+ mp->o_ip = spp_host_to_net_byte_order_32(argv[5]);
+ mp->o_port = spp_host_to_net_byte_order_16(argv[6]);
+
+printf("\ni_vrf %d, ip 0x%x, port %d, o_ip, port %d", mp->i_vrf, mp->i_ip, mp->i_port, mp->o_ip, mp->o_port);
+
+ platform_send_msg(mp);
+ return;
+}
+
+void cnat_db_delete_static_fwd_cmd (int argc, unsigned long *argv)
+{
+ spp_api_cnat_v4_del_static_port_t *mp;
+
+ if (argc != 3) {
+ printf("need right input\n");
+ return;
+ }
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+ mp->_spp_msg_id = SPP_API_CNAT_V4_DEL_STATIC_PORT;
+ mp->i_vrf = spp_host_to_net_byte_order_16(argv[0]);
+ mp->i_ip = spp_host_to_net_byte_order_32(argv[1]);
+ mp->i_port = spp_host_to_net_byte_order_16(argv[2]);
+
+ platform_send_msg(mp);
+ return;
+}
+
+void cnat_nfv9_create_cmd (int argc, unsigned long *argv)
+{
+ spp_api_cnat_v4_config_nfv9_logging_t *mp;
+
+ if (argc < 3) {
+ printf("nfv9 create i_vrf ip_addr port [refresh_rate] [timeout] [mtu]");
+ return;
+ }
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+ mp->_spp_msg_id = SPP_API_CNAT_V4_CONFIG_NFV9_LOGGING;
+ mp->enable = 1;
+ mp->i_vrf = spp_host_to_net_byte_order_16(argv[0]);
+
+ mp->ipv4_address = spp_host_to_net_byte_order_32(argv[1]);
+ mp->port = spp_host_to_net_byte_order_16(argv[2]);
+
+ if (argc > 3) {
+ mp->refresh_rate = spp_host_to_net_byte_order_16(argv[3]);
+ mp->timeout_rate = spp_host_to_net_byte_order_16(argv[4]);
+ mp->path_mtu = spp_host_to_net_byte_order_16(argv[5]);
+ } else {
+ mp->refresh_rate = spp_host_to_net_byte_order_16(1000);
+ mp->timeout_rate = spp_host_to_net_byte_order_16(30);
+ mp->path_mtu = spp_host_to_net_byte_order_16(1500);
+ }
+ platform_send_msg(mp);
+}
+
+void cnat_delete_cgn (int argc, unsigned long *argv)
+{
+ void *mp_send;
+ spp_api_cnat_del_cgn_t *mp;
+ u32 mp_size;
+
+ mp_size = sizeof(spp_api_cnat_del_cgn_t);
+
+ mp = spp_msg_api_alloc(mp_size);
+ memset(mp, 0, mp_size);
+
+ mp->_spp_msg_id = SPP_API_CNAT_DEL_CGN;
+
+ mp_send = mp;
+
+ platform_send_msg(mp);
+}
+
+void cnat_debug_global_all (int argc, unsigned long *argv)
+{
+ spp_api_cnat_v4_debug_global_t *mp;
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+
+ mp->_spp_msg_id = SPP_API_CNAT_V4_DEBUG_GLOBAL;
+ mp->debug_flag = CNAT_DEBUG_GLOBAL_ALL;
+
+ platform_send_msg(mp);
+}
+
+void cnat_debug_global_none (int argc, unsigned long *argv)
+{
+ spp_api_cnat_v4_debug_global_t *mp;
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+
+ mp->_spp_msg_id = SPP_API_CNAT_V4_DEBUG_GLOBAL;
+ mp->debug_flag = CNAT_DEBUG_NONE;
+
+ platform_send_msg(mp);
+}
+
+
+void cnat_bulk_cmd (int argc, unsigned long *argv)
+{
+ void *mp_send;
+
+ if (argc < 1) {
+ printf("\nargc = %d", argc);
+ printf("\n1. bulk cmd [0=static-port, 1=bulk_vrf, 2=policy_knob]");
+ return;
+ }
+
+
+ switch (argv[0]) {
+ case 0:
+ {
+ spp_api_cnat_v4_bulk_add_delete_static_port_t *mp;
+ spp_api_cnat_v4_add_static_port_t *mp_sp;
+ u32 mp_size =
+ sizeof(spp_api_cnat_v4_bulk_add_delete_static_port_t) +
+ (sizeof(spp_api_cnat_v4_add_static_port_t))*2;
+
+ mp = spp_msg_api_alloc(mp_size);
+ memset(mp, 0, mp_size);
+
+ mp->_spp_msg_id = SPP_API_CNAT_V4_BULK_ADD_DELETE_STATIC_PORT;
+
+ mp->num_static_port_entries = spp_host_to_net_byte_order_32(3);
+
+ mp_sp = (spp_api_cnat_v4_add_static_port_t *) &(mp->pad2);
+
+ mp_sp->_spp_msg_id = spp_host_to_net_byte_order_16(
+ SPP_API_CNAT_V4_ADD_STATIC_PORT);
+ mp_sp->proto = 2;
+ mp_sp->i_vrf = spp_host_to_net_byte_order_16(0x1);
+ mp_sp->i_ip = spp_host_to_net_byte_order_32(0x11111111);
+ mp_sp->i_port = spp_host_to_net_byte_order_16(0x7777);
+
+ mp_sp++;
+
+
+ mp_sp->_spp_msg_id = spp_host_to_net_byte_order_16(
+ SPP_API_CNAT_V4_ADD_STATIC_PORT);
+ mp_sp->proto = 1;
+ mp_sp->i_vrf = spp_host_to_net_byte_order_16(0x1);
+ mp_sp->i_ip = spp_host_to_net_byte_order_32(0x22222222);
+ mp_sp->i_port = spp_host_to_net_byte_order_16(0x6666);
+
+ mp_sp++;
+
+
+ mp_sp->_spp_msg_id = spp_host_to_net_byte_order_16(
+ SPP_API_CNAT_V4_ADD_STATIC_PORT);
+ mp_sp->proto = 1;
+ mp_sp->i_vrf = spp_host_to_net_byte_order_16(0x1);
+ mp_sp->i_ip = spp_host_to_net_byte_order_32(0x33333333);
+ mp_sp->i_port = spp_host_to_net_byte_order_16(0x5555);
+
+ mp_send = mp;
+
+ }
+ break;
+
+ case 1:
+ {
+ spp_api_cnat_v4_bulk_vrf_map_t *mp;
+ spp_api_cnat_v4_single_vrf_map_req *mp_sp;
+
+ u32 mp_size = sizeof(spp_api_cnat_v4_bulk_vrf_map_t) +
+ (sizeof(spp_api_cnat_v4_single_vrf_map_req))*2;
+
+ mp = spp_msg_api_alloc(mp_size);
+ memset(mp, 0, mp_size);
+
+ mp->_spp_msg_id = SPP_API_CNAT_V4_BULK_VRF_MAP;
+
+ mp->num_vrfmap_entries = spp_host_to_net_byte_order_32(3);
+
+ mp_sp = (spp_api_cnat_v4_single_vrf_map_req *)
+ &(mp->vrf_policy_enable);
+
+ mp_sp->i_vrf_id = spp_host_to_net_byte_order_32(0xe0000001);
+ mp_sp->o_vrf_id = spp_host_to_net_byte_order_32(0xe0000000);
+ mp_sp->i_vrf = spp_host_to_net_byte_order_16(0x1);
+ mp_sp->o_vrf = spp_host_to_net_byte_order_16(0x0);
+ mp_sp->start_addr = spp_host_to_net_byte_order_32(0x11111100);
+ mp_sp->end_addr = spp_host_to_net_byte_order_32(0x111111ff);
+ mp_sp->vrf_policy_enable = spp_host_to_net_byte_order_16(0x3);
+ mp_sp->tcp_mss_value = spp_host_to_net_byte_order_16(0x111);
+ mp_sp->vrf_nfv9_logging_ipv4_address = spp_host_to_net_byte_order_32(0x11000001);
+ mp_sp->vrf_nfv9_logging_udp_port = spp_host_to_net_byte_order_16(0x1001);
+ mp_sp->vrf_nfv9_refresh_rate = spp_host_to_net_byte_order_16(0x100);
+ mp_sp->vrf_nfv9_timeout_rate = spp_host_to_net_byte_order_16(0x10);
+ mp_sp->vrf_nfv9_path_mtu = spp_host_to_net_byte_order_16(0x100);
+
+ mp_sp++;
+
+ mp_sp->i_vrf_id = spp_host_to_net_byte_order_32(0xe0000002);
+ mp_sp->o_vrf_id = spp_host_to_net_byte_order_32(0xe0000000);
+ mp_sp->i_vrf = spp_host_to_net_byte_order_16(0x2);
+ mp_sp->o_vrf = spp_host_to_net_byte_order_16(0x0);
+ mp_sp->start_addr = spp_host_to_net_byte_order_32(0x22220000);
+ mp_sp->end_addr = spp_host_to_net_byte_order_32(0x2222ffff);
+ mp_sp->vrf_policy_enable = spp_host_to_net_byte_order_16(0x1);
+ mp_sp->tcp_mss_value = spp_host_to_net_byte_order_16(0x222);
+ mp_sp->vrf_nfv9_logging_ipv4_address = spp_host_to_net_byte_order_32(0x22000002);
+ mp_sp->vrf_nfv9_logging_udp_port = spp_host_to_net_byte_order_16(0x2002);
+ mp_sp->vrf_nfv9_refresh_rate = spp_host_to_net_byte_order_16(0x200);
+ mp_sp->vrf_nfv9_timeout_rate = spp_host_to_net_byte_order_16(0x20);
+ mp_sp->vrf_nfv9_path_mtu = spp_host_to_net_byte_order_16(0x200);
+
+ mp_sp++;
+
+ mp_sp->i_vrf_id = spp_host_to_net_byte_order_32(0xe0000003);
+ mp_sp->o_vrf_id = spp_host_to_net_byte_order_32(0xe0000007);
+ mp_sp->i_vrf = spp_host_to_net_byte_order_16(0x3);
+ mp_sp->o_vrf = spp_host_to_net_byte_order_16(0x7);
+ mp_sp->start_addr = spp_host_to_net_byte_order_32(0x33333000);
+ mp_sp->end_addr = spp_host_to_net_byte_order_32(0x33333fff);
+ mp_sp->vrf_policy_enable = spp_host_to_net_byte_order_16(0x1);
+ mp_sp->tcp_mss_value = spp_host_to_net_byte_order_16(0x333);
+ mp_sp->vrf_nfv9_logging_ipv4_address = spp_host_to_net_byte_order_32(0x33000003);
+ mp_sp->vrf_nfv9_logging_udp_port = spp_host_to_net_byte_order_16(0x3003);
+ mp_sp->vrf_nfv9_refresh_rate = spp_host_to_net_byte_order_16(0x300);
+ mp_sp->vrf_nfv9_timeout_rate = spp_host_to_net_byte_order_16(0x30);
+ mp_sp->vrf_nfv9_path_mtu = spp_host_to_net_byte_order_16(0x300);
+
+ mp_send = mp;
+ }
+ break;
+
+ case 2:
+ {
+ spp_api_cnat_v4_bulk_policy_knob_t *mp;
+
+ u32 mp_size =
+ sizeof(spp_api_cnat_v4_bulk_policy_knob_t) +
+ (sizeof(spp_api_cnat_v4_single_vrf_map_req))*2;
+
+ mp = spp_msg_api_alloc(mp_size);
+ memset(mp, 0, mp_size);
+
+ mp->_spp_msg_id = SPP_API_CNAT_V4_BULK_POLICY_KNOB;
+
+ mp->port_limit = spp_host_to_net_byte_order_16(345);
+ mp->icmp_timeout = spp_host_to_net_byte_order_16(300);
+ mp->udp_init_timeout = spp_host_to_net_byte_order_16(175);
+ mp->udp_act_timeout = spp_host_to_net_byte_order_16(133);
+ mp->tcp_init_timeout = spp_host_to_net_byte_order_16(222);
+ mp->tcp_act_timeout = spp_host_to_net_byte_order_16(2345);
+
+ mp->nat_policy_enable = spp_host_to_net_byte_order_32(0x7);
+
+ mp->global_nfv9_logging_ipv4_address = spp_host_to_net_byte_order_32(0x77777777);
+ mp->global_nfv9_logging_udp_port = spp_host_to_net_byte_order_16(0x7007);
+ mp->global_nfv9_refresh_rate = spp_host_to_net_byte_order_16(0x700);
+ mp->global_nfv9_timeout_rate = spp_host_to_net_byte_order_16(0x70);
+ mp->global_nfv9_path_mtu = spp_host_to_net_byte_order_16(0x700);
+
+ mp_send = mp;
+ }
+ break;
+
+
+ default:
+ printf("\nargv[2] = %d", argv[2]);
+ printf("\n2. bulk cmd [0=static-port, 1=bulk_vrf, 2=policy_knob+bulk_vrf]");
+ return;
+
+ }
+ platform_send_msg(mp_send);
+}
+
+void cnat_nfv9_delete_cmd (int argc, unsigned long *argv)
+{
+ spp_api_cnat_v4_config_nfv9_logging_t *mp;
+
+ if (argc != 1) {
+ printf("nfv9 delete i_vrf ");
+ return;
+ }
+
+ mp = spp_msg_api_alloc (sizeof (*mp));
+ memset(mp, 0, sizeof (*mp));
+ mp->_spp_msg_id = SPP_API_CNAT_V4_CONFIG_NFV9_LOGGING;
+ mp->enable = 0;
+ mp->i_vrf = spp_host_to_net_byte_order_16(argv[0]);
+ platform_send_msg(mp);
+}
+
+void cnat_generic_cmd (int argc, unsigned long *argv)
+{
+ spp_api_cnat_generic_command_request_t *mp;
+
+ if (argc != 9) {
+ printf("generic command core type p1 p2 p3 p4 p5 p6 p7 ");
+ return;
+ }
+
+ /*
+ * Allocate a large buffer for message req and resp structure
+ */
+ mp = spp_msg_api_alloc (MAX_DEBUG_BUFFER_SIZE);
+ memset(mp, 0, MAX_DEBUG_BUFFER_SIZE);
+ mp->_spp_msg_id = SPP_API_CNAT_GENERIC_COMMAND_REQUEST;
+ mp->core_num = argv[0];
+ mp->params[0] = spp_host_to_net_byte_order_32(argv[1]);
+ mp->params[1] = spp_host_to_net_byte_order_32(argv[2]);
+ mp->params[2] = spp_host_to_net_byte_order_32(argv[3]);
+ mp->params[3] = spp_host_to_net_byte_order_32(argv[4]);
+ mp->params[4] = spp_host_to_net_byte_order_32(argv[5]);
+ mp->params[5] = spp_host_to_net_byte_order_32(argv[6]);
+ mp->params[6] = spp_host_to_net_byte_order_32(argv[7]);
+ mp->params[7] = spp_host_to_net_byte_order_32(argv[8]);
+ platform_send_msg(mp);
+}
+
+u32 icmp_sent_timestamps; /* 32 KB array per core */
+u8 v4_pkt_count = 0;
+
+cnat_icmp_msg_t icmp_msg_gen_allowed ()
+{
+#ifdef DISABLE_ICMP_THROTTLE_FOR_DEBUG_PURPOSE
+ return CNAT_ICMP_MSG;
+#else
+ u32 current_timestamp;
+ spp_node_main_vector_t *nmv;
+ u32 updated_timestamp;
+
+ v4_pkt_count ++;
+
+ nmv = spp_get_node_main_vectorized_inline();
+
+ current_timestamp = nmv->ticks / nmv->ticks_per_second;
+
+ PLATFORM_UPDATE_TIMESTAMP
+ if (PREDICT_FALSE(icmp_sent_timestamps != updated_timestamp)) {
+ v4_pkt_count = 1;
+ /* update timestamp */
+ icmp_sent_timestamps = updated_timestamp;
+ }
+ if (PREDICT_TRUE(v4_pkt_count <= cnat_main_db_icmp_rate_limit_core)) {
+ return CNAT_ICMP_MSG;
+ } else {
+ return CNAT_NO_ICMP_MSG;
+ }
+#endif
+}
+
+u32 v6_icmp_sent_timestamps; /* 32 KB array per core */
+u8 v6_pkt_count = 0;
+
+cnat_icmp_msg_t v6_icmp_msg_gen_allowed ()
+{
+#ifdef DISABLE_ICMP_THROTTLE_FOR_DEBUG_PURPOSE
+ return CNAT_ICMP_MSG;
+#else
+ u32 current_timestamp;
+ spp_node_main_vector_t *nmv;
+ u32 updated_timestamp;
+
+ nmv = spp_get_node_main_vectorized_inline();
+
+ current_timestamp = nmv->ticks / nmv->ticks_per_second;
+ PLATFORM_UPDATE_TIMESTAMP
+ v6_pkt_count ++;
+
+ if (PREDICT_FALSE(v6_icmp_sent_timestamps != updated_timestamp)) {
+ v6_pkt_count = 1;
+ /* update timestamp */
+ v6_icmp_sent_timestamps = updated_timestamp;
+ }
+ if (PREDICT_TRUE(v6_pkt_count <= cnat_main_db_icmp_rate_limit_core)) {
+ return CNAT_ICMP_MSG;
+ } else {
+ return CNAT_NO_ICMP_MSG;
+ }
+#endif
+}
+
+u32 v4_udp_crc_zero_timestamps;
+u32 v4_udp_crc_zero_pkt_count = 0;
+int v4_crc_zero_udp_allowed ()
+{
+ PLATFORM_V4_CRC_ZERO_UDP_ALLOWED
+ /* Currently not supported for Brahmos. we need to take care of this */
+ spp_node_main_vector_t *nmv;
+ u32 hash_value, current_timestamp;
+
+ nmv = spp_get_node_main_vectorized_inline();
+
+ current_timestamp = nmv->ticks / nmv->ticks_per_second;
+ v4_udp_crc_zero_pkt_count++;
+ if (PREDICT_FALSE(v4_udp_crc_zero_timestamps != current_timestamp)) {
+ v4_udp_crc_zero_pkt_count = 1;
+ v4_udp_crc_zero_timestamps = current_timestamp;
+ }
+ if (PREDICT_TRUE(v4_udp_crc_zero_pkt_count <=
+ crc_zero_udp_rate_limit_core)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/*
+ * ipv4_decr_ttl_n_calc_csum()
+ * - It decrements the TTL and calculates the incremental IPv4 checksum
+ */
+
+ALWAYS_INLINE(
+void ipv4_decr_ttl_n_calc_csum(ipv4_header *ipv4))
+{
+ u32 checksum;
+ u16 old;
+
+ old = ntohs(*(u16 *)&ipv4->ttl);
+
+ /* Decrement TTL */
+ ipv4->ttl--;
+
+ /* Calculate incremental checksum */
+ checksum = old + (~ntohs(*(u16 *)&ipv4->ttl) & 0xFFFF);
+ checksum += ntohs(ipv4->checksum);
+ checksum = (checksum & 0xFFFF) + (checksum >> 16);
+ ipv4->checksum = htons(checksum + (checksum >> 16));
+}
+
+ALWAYS_INLINE(
+void calc_ipv4_checksum (ipv4_header *ipv4))
+{
+ u16 *data = (u16 *) ipv4;
+ u32 checksum = 0;
+
+ checksum = crc_calc(ipv4);
+
+ /* Now produce the 1's complement */
+ ipv4->checksum = spp_host_to_net_byte_order_16(((u16) (~(u16)checksum)));
+}
+
+ALWAYS_INLINE(
+void calc_v4_icmp_checksum (icmp_v4_t *icmp, int ipv4_payload_size))
+{
+ u16 *data = (u16 *) icmp;
+ int num_hwords = (ipv4_payload_size)/2;
+ u32 checksum = 0;
+
+ icmp->checksum = 0;
+ if (PREDICT_FALSE((ipv4_payload_size%2) != 0)) {
+ num_hwords += 1;
+ /* Append 0's in the last octet */
+ *((u8 *)data + ipv4_payload_size) = 0;
+ }
+ while (num_hwords) {
+ checksum += (u32)spp_net_to_host_byte_order_16(data++);
+ num_hwords--;
+ }
+
+ /* Add in the carry of the original sum */
+ checksum = (checksum & 0xFFFF) + (checksum >> 16);
+ /* Add in the carry of the final sum */
+ checksum = (checksum & 0xFFFF) + (checksum >> 16);
+ /* Now produce the 1's complement */
+ icmp->checksum = spp_host_to_net_byte_order_16(((u16) (~(u16)checksum)));
+}
+
+ALWAYS_INLINE(
+void calc_v6_icmp_checksum (ipv6_header_t *ipv6, u16 ip_payload_size))
+{
+ u16 *data;
+ u16 *data1;
+ int i;
+ icmp_v6_t *icmp;
+ int num_hwords = (ip_payload_size)/2;
+ u32 checksum = 0;
+ pseudo_v6_header_t pseudo_header;
+
+ icmp = (icmp_v6_t *) ((u8 *)ipv6 + IPV6_HDR_LEN);
+ data = (u16 *) icmp;
+ icmp->checksum = 0;
+
+#if 1
+ if (PREDICT_FALSE((ip_payload_size%2) != 0)) {
+ num_hwords += 1;
+ /* Append 0's in the last octet */
+ *((u8 *)data + ip_payload_size) = 0;
+ }
+#endif
+
+ /* construct the pseudo header */
+
+ pseudo_header.src_addr[0] = ipv6->src_addr[0];
+ pseudo_header.src_addr[1] = ipv6->src_addr[1];
+ pseudo_header.src_addr[2] = ipv6->src_addr[2];
+ pseudo_header.src_addr[3] = ipv6->src_addr[3];
+ pseudo_header.dst_addr[0] = ipv6->dst_addr[0];
+ pseudo_header.dst_addr[1] = ipv6->dst_addr[1];
+ pseudo_header.dst_addr[2] = ipv6->dst_addr[2];
+ pseudo_header.dst_addr[3] = ipv6->dst_addr[3];
+ pseudo_header.payload_length = spp_host_to_net_byte_order_16(ip_payload_size);
+ pseudo_header.next_header = spp_host_to_net_byte_order_16(ipv6->next_header);
+
+ data1 = (u16 *) &pseudo_header;
+
+ /* sizeof(pseudo_v6_header_t) = 36 */
+ for (i = 0; i < 18; i++) {
+ checksum += (u32)spp_net_to_host_byte_order_16(data1++);
+ }
+
+checksum_calc:
+
+ if (PREDICT_TRUE(num_hwords)) {
+ checksum += (u32)spp_net_to_host_byte_order_16(data);
+ num_hwords--;
+ data++;
+ goto checksum_calc;
+ }
+
+ /* Add in the carry of the original sum */
+ checksum = (checksum & 0xFFFF) + (checksum >> 16);
+ /* Add in the carry of the final sum */
+ checksum = (checksum & 0xFFFF) + (checksum >> 16);
+ /* Now produce the 1's complement */
+ icmp->checksum = spp_host_to_net_byte_order_16(((u16) (~(u16)checksum)));
+}
+
+void icmp_error_generate_v6 (spp_ctx_t *ctx, u8 icmp_type,
+ u8 icmp_code, u16 uidb_index) {
+
+ u16 ip_hdr_len, ip_payload_size;
+ u32 *src_p, * dst_p;
+ icmp_v6_t *icmp;
+ int i;
+ ipv6_header_t *ip_old, *ip_new;
+ u16 icmp_payload_len;
+
+ /*
+ * As per RFC 2463, we limit the maximum size of generated ICMPv6 message to * 1280. And hence if the packet is bigger than 1280, then it needs to be
+ * truncated. Also, if the packet had multiple chained buffers, we need to
+ * free all chained buffers, except the first one.
+ */
+ free_all_but_first_chained_buffers(ctx);
+
+ ip_hdr_len = IPV6_HDR_LEN;
+ /* offset to ip payload */
+
+ ip_old = (ipv6_header_t *)PLATFORM_CTX_CURRENT_HDR;
+ ip_new = (ipv6_header_t *) ((u8 *) PLATFORM_CTX_CURRENT_HDR - ICMPV6_ERR_SIZE);
+ icmp = (icmp_v6_t*) ( (u8*)ip_new + ip_hdr_len);
+
+ icmp_payload_len = ip_hdr_len +
+ spp_net_to_host_byte_order_16(&(ip_old->payload_length)) ;
+
+ ip_payload_size = ICMPV6_HDR_SIZE + icmp_payload_len;
+ /*
+ * There is no easy way to predict this case as the probablity that the IPv6
+ * pkt is big depends on the type of traffic. Let us optimize the big
+ * pkt case as it involves more processing
+ *
+ * If the pkt size exceeds IPV6_MIN_PATH_MTU truncate it to IPV6_MIN_PATH_MTU
+ */
+ if (PREDICT_TRUE((ip_payload_size + ip_hdr_len) > IPV6_MIN_PATH_MTU)) {
+ ip_payload_size = IPV6_MIN_PATH_MTU - ip_hdr_len;
+ }
+
+ /* Following ICMP op has to be after ip header being copied */
+ icmp->type = icmp_type;
+ icmp->code = icmp_code;
+
+ ip_new->version_trafficclass_flowlabel = spp_host_to_net_byte_order_32(
+ VERSION_TRAFFICCLASS_FLOWLABEL);
+ ip_new->payload_length = spp_host_to_net_byte_order_16(ip_payload_size);
+ ip_new->next_header = IPV6_PROTO_ICMPV6;
+ ip_new->hop_limit = 64;
+ ip_new->dst_addr[0] = ip_old->src_addr[0];
+ ip_new->dst_addr[1] = ip_old->src_addr[1];
+ ip_new->dst_addr[2] = ip_old->src_addr[2];
+ ip_new->dst_addr[3] = ip_old->src_addr[3];
+
+ ip_new->src_addr[0] =
+ spp_host_to_net_byte_order_32(svi_params_array[uidb_index].ipv6_addr[0]);
+ ip_new->src_addr[1] =
+ spp_host_to_net_byte_order_32(svi_params_array[uidb_index].ipv6_addr[1]);
+ ip_new->src_addr[2] =
+ spp_host_to_net_byte_order_32(svi_params_array[uidb_index].ipv6_addr[2]);
+ ip_new->src_addr[3] =
+ spp_host_to_net_byte_order_32(svi_params_array[uidb_index].ipv6_addr[3]);
+ /* calc checksum for icmp */
+
+ calc_v6_icmp_checksum(ip_new, ip_payload_size);
+#if 0
+ printf("Flow = 0x%x\n", ip_new->version_trafficclass_flowlabel);
+ printf("Hoplimit = 0x%x\n", ip_new->hop_limit);
+ printf("Length= 0x%x\n", ip_new->payload_length);
+ printf("Next header = 0x%x\n", ip_new->next_header);
+ printf("Src add0 = 0x%x\n", ip_new->src_addr[0]);
+ printf("Src add1 = 0x%x\n", ip_new->src_addr[1]);
+ printf("Src add2 = 0x%x\n", ip_new->src_addr[2]);
+ printf("Src add3 = 0x%x\n", ip_new->src_addr[3]);
+ printf("Dst add0 = 0x%x\n", ip_new->dst_addr[0]);
+ printf("Dst add1 = 0x%x\n", ip_new->dst_addr[1]);
+ printf("Dst add2 = 0x%x\n", ip_new->dst_addr[2]);
+ printf("Dst add3 = 0x%x\n", ip_new->dst_addr[3]);
+ printf("Icmp type = 0x%x\n", icmp->type);
+ printf("Icmp code = 0x%x\n", icmp->code);
+
+ printf("\n\nICMP packet:\n");
+ for (i = 0; i < 10; i ++) {
+ printf("0x%x " , *((u8 *)icmp + i));
+ if ((i%16) == 15) {
+ printf("\n");
+ }
+ }
+#endif
+
+ ctx->current_header -= ICMPV6_ERR_SIZE;
+ ctx->current_length = ip_payload_size + ip_hdr_len;
+ PLATFORM_CNAT_SET_TX_VRF(ctx,uidb_index);
+}
+
+void icmp_error_generate_v2 (ipv4_header *ip, u8 icmp_type,
+ u8 icmp_code, u16 mtu, u32 src_ip)
+{
+
+ u16 ip_hdr_len, ip_payload_size;
+ u32 *src_p, * dst_p;
+ icmp_v4_t *icmp;
+
+ ip_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; /* offset to ip payload */
+ icmp = (icmp_v4_t*) ( (u8*)ip + ip_hdr_len);
+ ip_payload_size = sizeof(icmp_v4_t) + ip_hdr_len +
+ ICMP_UNREACHABLE_IP_PAYLOAD_SIZE;
+
+ src_p = (u32*)
+ ((u8*)ip + ip_hdr_len + ICMP_UNREACHABLE_IP_PAYLOAD_SIZE - 4);
+ dst_p = (u32*) ((u8*)src_p + sizeof(ipv4_header) +
+ sizeof(icmp_v4_t));
+
+ while(src_p >= (u32*)ip) *dst_p-- = *src_p--;
+
+ /* Following ICMP op has to be after ip header being copied */
+ icmp->type = icmp_type;
+ icmp->code = icmp_code;
+ icmp->identifier = 0;
+ icmp->sequence = 0;
+ if(PREDICT_FALSE(mtu != 0)) {
+ icmp->sequence = spp_host_to_net_byte_order_16(mtu);
+ }
+
+
+ /* build icmp header, keep original tos, identification values */
+ ip->version_hdr_len_words = 0x45;
+ ip->total_len_bytes = sizeof(ipv4_header) + ip_payload_size;
+ ip->total_len_bytes = spp_host_to_net_byte_order_16(ip->total_len_bytes);
+ ip->frag_flags_offset = 0;
+ ip->ttl = 64;
+ ip->protocol = ICMP_PROT;
+ ip->checksum = 0;
+ ip->dest_addr = ip->src_addr;
+ ip->src_addr = spp_host_to_net_byte_order_32(src_ip);
+
+ /* calc checksum for ip and icmp */
+
+ calc_ipv4_checksum(ip);
+ calc_v4_icmp_checksum( (icmp_v4_t *) ((u8*) ip + sizeof(ipv4_header)),
+ ip_payload_size);
+}
+
+void icmp_error_generate (ipv4_header *ip, u8 icmp_type,
+ u8 icmp_code, u16 uidb_index) {
+
+ u16 ip_hdr_len, ip_payload_size;
+ u32 *src_p, * dst_p;
+ icmp_v4_t *icmp;
+
+ ip_hdr_len = (ip->version_hdr_len_words & 0xf) << 2; /* offset to ip payload */
+ icmp = (icmp_v4_t*) ( (u8*)ip + ip_hdr_len);
+ ip_payload_size = sizeof(icmp_v4_t) + ip_hdr_len +
+ ICMP_UNREACHABLE_IP_PAYLOAD_SIZE;
+
+ src_p = (u32*)
+ ((u8*)ip + ip_hdr_len + ICMP_UNREACHABLE_IP_PAYLOAD_SIZE - 4);
+ dst_p = (u32*) ((u8*)src_p + sizeof(ipv4_header) +
+ sizeof(icmp_v4_t));
+
+ while(src_p >= (u32*)ip) *dst_p-- = *src_p--;
+
+ /* Following ICMP op has to be after ip header being copied */
+ icmp->type = icmp_type;
+ icmp->code = icmp_code;
+ icmp->identifier = 0;
+ icmp->sequence = 0;
+
+
+ /* build icmp header, keep original tos, identification values */
+ ip->version_hdr_len_words = 0x45;
+ ip->total_len_bytes = sizeof(ipv4_header) + ip_payload_size;
+ ip->total_len_bytes = spp_host_to_net_byte_order_16(ip->total_len_bytes);
+ ip->frag_flags_offset = 0;
+ ip->ttl = 64;
+ ip->protocol = ICMP_PROT;
+ ip->checksum = 0;
+ ip->dest_addr = ip->src_addr;
+
+ ip->src_addr = spp_host_to_net_byte_order_32(svi_params_array[uidb_index].ipv4_addr);
+
+ /* calc checksum for ip and icmp */
+
+ calc_ipv4_checksum(ip);
+ calc_v4_icmp_checksum( (icmp_v4_t *) ((u8*) ip + sizeof(ipv4_header)),
+ ip_payload_size);
+#if 0
+ printf("version_hdr_len_words = 0x%x\n", ip->version_hdr_len_words);
+ printf("total_len_bytes = 0x%x\n", ip->total_len_bytes);
+ printf("Frag = 0x%x\n", ip->frag_flags_offset);
+ printf("ttl = 0x%x\n", ip->ttl);
+ printf("Protocol = 0x%x\n", ip->protocol);
+ printf("checksum = 0x%x\n", ip->checksum);
+ printf("Dest addr = 0x%x\n", ip->dest_addr);
+ printf("Src addr = 0x%x\n", ip->src_addr);
+ printf("Icmp type = 0x%x\n", icmp->type);
+ printf("Icmp code = 0x%x\n", icmp->code);
+#endif
+
+}
+
+int icmpv4_generate_with_throttling_v2 (spp_ctx_t *ctx, ipv4_header *ipv4,
+ int icmp_type, int icmp_code,
+ u16 mtu, u32 src_ip)
+{
+ u16 ip_hdr_len;
+ icmp_v4_t *icmp;
+ u16 rx_uidb_index = ctx->ru.rx.uidb_index;
+ if (icmp_msg_gen_allowed()) {
+ free_all_but_first_chained_buffers(ctx);
+ icmp_error_generate_v2(ipv4, icmp_type, icmp_code, mtu, src_ip);
+ ctx->current_length = (u16)
+ ((u8*)ctx->current_header - ctx->packet_data) +
+ spp_net_to_host_byte_order_16(&ipv4->total_len_bytes);
+ PLATFORM_CNAT_SET_TX_VRF(ctx,rx_uidb_index);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int icmpv4_generate_with_throttling (spp_ctx_t *ctx, ipv4_header *ipv4,
+ u16 rx_uidb_index)
+{
+ int icmp_type;
+ int icmp_code;
+
+ if (icmp_msg_gen_allowed()) {
+ /* ICMP error would be small, so one buffer is enough. Clear the other */
+ free_all_but_first_chained_buffers(ctx);
+
+ icmp_type = ICMPV4_TIMEEXCEEDED;
+ icmp_code = ICMPV4_TIMTTL;
+ icmp_error_generate(ipv4, icmp_type, icmp_code, rx_uidb_index);
+ ctx->current_length = (u16)
+ ((u8*)ctx->current_header - ctx->packet_data) +
+ spp_net_to_host_byte_order_16(&ipv4->total_len_bytes);
+ PLATFORM_CNAT_SET_TX_VRF(ctx,rx_uidb_index);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int icmpv4_generate_with_throttling_v1 (spp_ctx_t *ctx, ipv4_header *ipv4,
+ u16 rx_uidb_index, u32 type, u32 code)
+{
+ if (icmp_msg_gen_allowed()) {
+ /* ICMP error would be small, so one buffer is enough. Clear the other */
+ free_all_but_first_chained_buffers(ctx);
+
+ icmp_error_generate(ipv4, type, code, rx_uidb_index);
+ ctx->current_length = (u16)
+ ((u8*)ctx->current_header - ctx->packet_data) +
+ spp_net_to_host_byte_order_16(&ipv4->total_len_bytes);
+ PLATFORM_CNAT_SET_TX_VRF(ctx,rx_uidb_index);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+int icmpv6_generate_with_throttling (spp_ctx_t *ctx, ipv6_header_t *ipv6,
+ u16 rx_uidb_index)
+{
+ int icmp_type;
+ int icmp_code;
+
+ if (v6_icmp_msg_gen_allowed()) {
+ icmp_type = ICMPV6_TIMEEXCEEDED;
+ icmp_code = ICMPV6_TIMTTL;
+ icmp_error_generate_v6(ctx, icmp_type, icmp_code, rx_uidb_index);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int icmpv6_generate_with_throttling_v1 (spp_ctx_t *ctx, ipv6_header_t *ipv6,
+ u16 rx_uidb_index, u32 type, u32 code)
+{
+
+ if (v6_icmp_msg_gen_allowed()) {
+ icmp_error_generate_v6(ctx, type, code, rx_uidb_index);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+#endif
+
+void calculate_window_scale(tcp_hdr_type *tcp_header, u8 *scale) {
+
+ u8 check_options = 0;
+
+ *scale = 0;
+ check_options = ((tcp_header->flags & TCP_FLAG_SYN) &&
+ (((tcp_header->hdr_len>>4) << 2) > sizeof(tcp_hdr_type)));
+
+ if (PREDICT_FALSE(check_options)) {
+ u8 *options_ptr = tcp_findoption(tcp_header, TCP_OPTION_WINDOW_SCALE);
+
+ /*
+ * TCP option field: | kind 1B | len 1B | value 2B|
+ * where kind != [0, 1]
+ */
+ if (PREDICT_TRUE(options_ptr &&
+ (options_ptr[1] == TCP_OPTION_WINDOW_SCALE))) {
+ u8 *ptr = (u8*)(options_ptr + 2);
+ *scale = *ptr;
+
+ if(PREDICT_FALSE(*scale >= 14)) {
+ *scale = 14;
+ }
+
+ return;
+ }
+ }
+}
+
+#if 0
+ALWAYS_INLINE(
+void cnat_log_nat44_tcp_seq_mismatch(
+ cnat_main_db_entry_t *db,
+ cnat_vrfmap_t *vrfmap))
+{
+ /* As of now, Netflow does not require this to be logged
+ * So only syslog
+ */
+ if(PREDICT_TRUE(db->flags & CNAT_TAC_SEQ_MISMATCH)) {
+ /* Already logged ..*/
+ return;
+ }
+ /* else, set the flag and call the log API */
+
+ db->flags = db->flags | CNAT_TAC_SEQ_MISMATCH;
+
+ cnat_syslog_nat44_tcp_seq_mismatch(db, vrfmap);
+}
+
+
+static int cnat_util_init (void *notused)
+{
+ /* run SPP_API_CNAT_PORTMAP_CREATE first*/
+ spp_msg_api_set_handler(SPP_API_CNAT_PORT_ALLOCATE,
+ spp_api_cnat_port_allocate_t_handler);
+
+
+ spp_msg_api_set_handler(SPP_API_CNAT_PORT_CLEAR,
+ spp_api_cnat_port_clear_t_handler);
+
+ /* run vrfmap config first */
+ spp_msg_api_set_handler(SPP_API_CNAT_PORT_CREATE,
+ spp_api_cnat_port_create_t_handler);
+
+ spp_msg_api_set_handler(SPP_API_CNAT_PORT_DELETE,
+ spp_api_cnat_port_delete_t_handler);
+ return 0;
+}
+
+void
+print_ipv6_pkt (ipv6_header_t *ip)
+{
+ u32 i, total_len, l4_len=0;
+
+ u8 *pkt = (u8 *) ip;
+
+ total_len = spp_net_to_host_byte_order_16(&ip->payload_length);
+
+ /* we rarely need to debug > 200 bytes of packet */
+ if(total_len > 200) {
+ total_len = 200;
+ }
+
+ printf("\n======== PRINTING PKT START======\n");
+ printf("======== IPv6 PAYLOAD LEN %d ===========\n", total_len);
+ for (i=0; i < 40; i++) {
+ printf(" %02X ", *(pkt + i));
+ if(i%16==15)
+ printf("\n");
+ }
+
+ if (ip->next_header == IPV6_PROTO_TCP) {
+ printf("\n======== TCP HEADER =================\n");
+ l4_len = 20;
+ }
+ else if (ip->next_header == IPV6_PROTO_UDP) {
+ printf("\n======== UDP HEADER =================\n");
+ l4_len = 8;
+ }
+ else if (ip->next_header == IPV6_PROTO_ICMPV6) {
+ printf("\n======== ICMP HEADER =================\n");
+ l4_len = 8;
+ }
+
+ for (i=40; i < (l4_len + 40); i++) {
+ printf(" %02X ", *(pkt + i));
+ }
+
+ printf("\n======== LAYER4 PAYLOAD ===================\n");
+ for (i=(l4_len + 40); i < total_len; i++) {
+ printf(" %02X ", *(pkt + i));
+ if(i%16==15)
+ printf("\n");
+ }
+
+ printf("\n======== PRINTING PKT END =======\n");
+}
+
+
+
+PLATFORM_SPP_INIT_FUNCTION(cnat_util_init);
+#endif
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_v4_ftp_alg.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_v4_ftp_alg.h
new file mode 100644
index 00000000..df3dfcb0
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_v4_ftp_alg.h
@@ -0,0 +1,133 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_v4_ftp_alg.h
+ *
+ * Copyright (c) 2012-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_V4_FTP_ALG_H__
+#define __CNAT_V4_FTP_ALG_H__
+
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+
+#include "tcp_header_definitions.h"
+#include "dslite_defs.h"
+#include "dslite_db.h"
+
+/* shorter form of byte order functions */
+
+#define net2host16(x) clib_net_to_host_u16( x)
+#define net2host32(x) clib_net_to_host_u32( x)
+#define net2host64(x) clib_net_to_host_u64( x)
+#define host2net16(x) clib_host_to_net_u16(x)
+#define host2net32(x) clib_host_to_net_u32(x)
+#define host2net64(x) clib_host_to_net_u64(x)
+
+//#define BIGENDIAN
+
+typedef struct iphdrtype_ {
+ u8 v_ihl; /* version and IP header length */
+ u8 tos; /* type of service */
+ u16 tl; /* total length */
+ u16 id; /* identifier */
+ u16 ipreserved: 1;
+ u16 dontfragment: 1;
+ u16 morefragments: 1;
+ u16 fo: 13; /* fragment offset */
+ u8 ttl; /* time to live */
+ u8 prot; /* protocol type */
+ u16 checksum; /* checksum */
+ u32 srcadr; /* IP source address */
+ u32 dstadr; /* IP destination address */
+} iphdrtype;
+
+
+typedef struct tcptype_ {
+ u16 sourceport;
+ u16 destinationport;
+ u32 sequencenumber;
+ u32 acknowledgementnumber;
+ u8 dataoffset;
+ u8 flags;
+#if 0
+/* bypass the ENDIAN part */
+#ifdef BIGENDIAN
+ u8 reserved: 2;
+ u8 urg: 1;
+ u8 ack: 1;
+ u8 psh: 1;
+ u8 rst: 1;
+ u8 syn: 1;
+ u8 fin: 1;
+#else
+ u8 fin: 1;
+ u8 syn: 1;
+ u8 rst: 1;
+ u8 psh: 1;
+ u8 ack: 1;
+ u8 urg: 1;
+ u8 reserved2: 2;
+#endif
+#endif
+
+ u16 window;
+ u16 checksum;
+ u16 urgentpointer;
+ u8 data[0];
+} tcptype ;
+
+
+int watch_ftp_port_cmd (iphdrtype *ip,
+ tcptype *tcp,
+ u32 * ip_addr,
+ u16 * port);
+
+
+u8 * ftp_test_pkt_gen (u32 ip_addr, u16 port);
+
+int update_ftp_port(u8 * pkt, u32 new_ip, u16 new_port, i8 * delta,
+ cnat_main_db_entry_t *db_tcp_control,
+ dslite_table_entry_t *dslite_entry_ptr,
+ ipv6_header_t *ipv6_hdr);
+/*
+ * caller needs to check if it's a ftp packet
+ * this function returns 1
+ * if packet being updated for PORT
+ * otherwise return 0.
+ * Assume IP header DOES NOT have option fields
+ */
+
+int cnat_ftp_alg ( u8* pkt, i8 * delta, cnat_main_db_entry_t *db,
+ dslite_table_entry_t *dslite_entry_ptr,
+ ipv6_header_t *ipv6_hdr);
+
+#define FTP_ALG_DEBUG_PRINTF_ENABLED 1
+
+#ifdef FTP_ALG_DEBUG_PRINTF_ENABLED
+
+#define FTP_ALG_DEBUG_PRINTF(...) { \
+ if (global_debug_flag & CNAT_DEBUG_FTP_ALG) { \
+ printf(__VA_ARGS__); \
+ } }
+
+#else
+
+#define FTP_ALG_DEBUG_PRINTF(...)
+
+#endif
+
+#endif /* __CNAT_V4_FTP_ALG_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_v4_functions.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_v4_functions.c
new file mode 100644
index 00000000..d3051fba
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_v4_functions.c
@@ -0,0 +1,364 @@
+/*
+ *---------------------------------------------------------------------------
+ * cnat_v4_funtions.c
+ *
+ * Copyright (c) 2008-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vnet/pg/pg.h>
+#include <vppinfra/error.h>
+
+
+#include "tcp_header_definitions.h"
+#include "cnat_db.h"
+#include "cnat_config.h"
+#include "cnat_v4_functions.h"
+#include "dslite_defs.h"
+#include "dslite_db.h"
+
+static u32 tcp_logging_count;
+static u32 tcp_logging_overflow;
+
+static tcp_logging_struct_t tcp_logging_array[MAX_TCP_LOGGING_COUNT];
+
+/*
+ * Function to log TCP pkts checksum changes..
+ */
+void
+tcp_debug_logging (
+ u32 seq_num,
+ u32 ack_num,
+ u32 old_ip,
+ u32 new_ip,
+ u16 old_port,
+ u16 new_port,
+ u16 old_ip_crc,
+ u16 new_ip_crc,
+ u16 old_tcp_crc,
+ u16 new_tcp_crc)
+{
+ tcp_logging_array[tcp_logging_count].seq_num = seq_num;
+ tcp_logging_array[tcp_logging_count].ack_num = ack_num;
+ tcp_logging_array[tcp_logging_count].old_ip = old_ip;
+ tcp_logging_array[tcp_logging_count].new_ip = new_ip;
+ tcp_logging_array[tcp_logging_count].old_port = old_port;
+ tcp_logging_array[tcp_logging_count].new_port = new_port;
+ tcp_logging_array[tcp_logging_count].old_ip_crc = old_ip_crc;
+ tcp_logging_array[tcp_logging_count].new_ip_crc = new_ip_crc;
+ tcp_logging_array[tcp_logging_count].old_tcp_crc = old_tcp_crc;
+ tcp_logging_array[tcp_logging_count].new_tcp_crc = new_tcp_crc;
+
+ tcp_logging_count++;
+
+ if (tcp_logging_count >= MAX_TCP_LOGGING_COUNT) {
+ tcp_logging_overflow = 1;
+ tcp_logging_count = 0;
+ }
+}
+
+/*
+ * Function to dmp TCP pkts logged..
+ */
+void
+tcp_debug_logging_dump (void)
+{
+ u32 i, total_count, start_entry;
+
+ if (tcp_logging_overflow) {
+ total_count = MAX_TCP_LOGGING_COUNT;
+ start_entry = tcp_logging_count;
+ printf("Logging Entries Wrapped Around, displaying %d entries\n",
+ total_count);
+ } else {
+ total_count = tcp_logging_count;
+ start_entry = 0;
+ printf("Displaying %d entries\n", total_count);
+ }
+
+ printf("SEQ ACK IP_O IP_N PORT_O PORT_N L3_CRC_O L3_CRC_N L4_CRC_O L4_CRC_N\n");
+
+ for (i = 0; i < total_count; i++) {
+ u32 entry = (i + start_entry) % MAX_TCP_LOGGING_COUNT;
+
+ printf("%04d: 0x%08x 0x%08x 0x%08x 0x%08x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n",
+ entry,
+ tcp_logging_array[entry].seq_num,
+ tcp_logging_array[entry].ack_num,
+ tcp_logging_array[entry].old_ip,
+ tcp_logging_array[entry].new_ip,
+ tcp_logging_array[entry].old_port,
+ tcp_logging_array[entry].new_port,
+ tcp_logging_array[entry].old_ip_crc,
+ tcp_logging_array[entry].new_ip_crc,
+ tcp_logging_array[entry].old_tcp_crc,
+ tcp_logging_array[entry].new_tcp_crc);
+ }
+}
+
+/*
+ * Function to enable TCP logging
+ */
+void
+tcp_debug_logging_enable_disable (u32 enable_flag)
+{
+ switch (enable_flag) {
+
+ case TCP_LOGGING_DISABLE:
+ if (tcp_logging_enable_flag == TCP_LOGGING_DISABLE) {
+ printf("\nTCP Logging ALREADY DISABLED\n");
+ } else {
+ printf("\nTCP Logging DISABLED\n");
+ }
+ tcp_logging_enable_flag = 0;
+ break;
+
+ case TCP_LOGGING_ENABLE:
+ if (tcp_logging_enable_flag == TCP_LOGGING_ENABLE) {
+ printf("\nTCP Logging ALREADY ENABLED\n");
+ } else {
+ tcp_logging_enable_flag = 1;
+ tcp_logging_count = 0;
+ tcp_logging_overflow = 0;
+
+ printf("\nTCP Logging ENABLED\n");
+ }
+ break;
+
+ case TCP_LOGGING_PACKET_DUMP:
+ tcp_debug_logging_dump();
+ break;
+
+ case TCP_LOGGING_SUMMARY_DUMP:
+ default:
+ printf("\ntcp_logging_enable_flag %d, tcp_log_count %d\n",
+ tcp_logging_enable_flag, tcp_logging_count);
+ printf("To Enable TCP LOGGING provide a flag value of %d\n",
+ TCP_LOGGING_ENABLE);
+ break;
+ }
+}
+
+void hex_dump (u8 * p, int len) {
+ int i;
+ for (i=0;i<len;i++) {
+ if(i && (i & 0x3 ) == 0) printf(" ");
+ if(i && (i & 0xf ) == 0) printf("\n");
+ PLATFORM_DEBUG_PRINT("%02X ", p[i]);
+ }
+ PLATFORM_DEBUG_PRINT("\n");
+}
+
+void
+print_icmp_pkt (ipv4_header *ip)
+{
+ u32 i, total_len;
+
+ u8 *pkt = (u8 *) ip;
+
+ total_len = clib_net_to_host_u16(ip->total_len_bytes);
+
+ printf("\n======== PRINTING PKT START======\n");
+ printf("======== IP PACKET LEN %d ===========\n", total_len);
+ for (i=0; i < 20; i++) {
+ printf(" %02X ", *(pkt + i));
+ }
+
+ printf("\n======== ICMP HEADER =================\n");
+ for (i=20; i < 28; i++) {
+ printf(" %02X ", *(pkt + i));
+ }
+
+ printf("\n======== ICMP BODY ===================\n");
+ for (i=28; i < total_len; i++) {
+ printf(" %02X ", *(pkt + i));
+ }
+
+ printf("\n======== PRINTING PKT END =======\n");
+}
+
+void
+print_udp_pkt (ipv4_header *ip)
+{
+ u32 i, total_len, udp_len;
+
+ u8 *pkt = (u8 *) ip;
+
+ total_len = clib_net_to_host_u16(ip->total_len_bytes);
+ udp_len = total_len - 20;
+
+ printf("\n======== PRINTING PKT START======\n");
+ printf("======== IP PACKET LEN %d ===========\n", total_len);
+ for (i=0; i < 20; i++) {
+ printf(" %02X ", *(pkt + i));
+ }
+ printf("\n======== UDP PSEUDO HEADER ==========\n");
+ for (i=12; i < 20; i++) {
+ printf(" %02X ", *(pkt + i));
+ }
+ printf(" 00 11 %02X %02X ", udp_len >> 8, udp_len & 0xff);
+
+ printf("\n======== UDP HEADER =================\n");
+ for (i=20; i < 28; i++) {
+ printf(" %02X ", *(pkt + i));
+ }
+ printf("\n======== UDP BODY ===================\n");
+ for (i=28; i < total_len; i++) {
+ printf(" %02X ", *(pkt + i));
+ }
+
+ printf("\n======== PRINTING PKT END =======\n");
+}
+
+void
+print_tcp_pkt (ipv4_header *ip)
+{
+ u32 i, total_len, tcp_len;
+
+ u8 *pkt = (u8 *) ip;
+
+ total_len = clib_net_to_host_u16(ip->total_len_bytes);
+ tcp_len = total_len - 20;
+
+ printf("\n======== PRINTING PKT START======\n");
+ printf("======== IP PACKET LEN %d ===========\n", total_len);
+ for (i=0; i < 20; i++) {
+ printf(" %02X ", *(pkt + i));
+ }
+ printf("\n======== TCP PSEUDO HEADER ==========\n");
+ for (i=12; i < 20; i++) {
+ printf(" %02X ", *(pkt + i));
+ }
+ printf(" 00 06 %02X %02X ", tcp_len >> 8, tcp_len & 0xff);
+
+ printf("\n======== TCP HEADER =================\n");
+ for (i=20; i < 40; i++) {
+ printf(" %02X ", *(pkt + i));
+ }
+ printf("\n======== TCP BODY ===================\n");
+ for (i=40; i < total_len; i++) {
+ printf(" %02X ", *(pkt + i));
+ }
+
+ printf("\n======== PRINTING PKT END =======\n");
+}
+
+/* IN: ipv4 and tcp header pointer,
+ * new ipv4 addr and port value
+ * main db index for accessing per vrf mss value
+ * DO:
+ * NAT
+ * mss adjust if needed
+ * ip & tcp checksum update (incremental)
+ */
+
+inline void tcp_in2out_nat_mss_n_checksum (ipv4_header * ip,
+ tcp_hdr_type * tcp,
+ u32 ipv4_addr,
+ u16 port,
+ cnat_main_db_entry_t * db)
+{
+ u8 *mss_ptr;
+ u8 check_mss = 0;
+ u16 mss_old, mss_new;
+ cnat_vrfmap_t * vrf_map_p;
+
+ cnat_v4_recalculate_tcp_checksum(ip,
+ tcp,
+ &(ip->src_addr),
+ &(tcp->src_port),
+ ipv4_addr,
+ port);
+ u16 frag_offset =
+ clib_net_to_host_u16(ip->frag_flags_offset);
+
+ if(PREDICT_FALSE(frag_offset & IP_FRAG_OFFSET_MASK)) {
+ return; /* No TCP Header at all */
+ }
+
+ /*
+ * check SYN bit and if options field is present
+ * If yes, proceed to extract the options and get TCP MSS value
+ */
+ check_mss = ((tcp->flags & TCP_FLAG_SYN) &&
+ (((tcp->hdr_len>>4) << 2) > sizeof(tcp_hdr_type)));
+
+ if (PREDICT_FALSE(check_mss)) {
+
+ /* get per VRF mss config */
+ if(PREDICT_FALSE(db->flags & (CNAT_DB_DSLITE_FLAG))) {
+ mss_new = dslite_table_db_ptr[db->dslite_nat44_inst_id].tcp_mss;
+ } else {
+ vrf_map_p = cnat_map_by_vrf + db->vrfmap_index;
+ mss_new = vrf_map_p->tcp_mss;
+ }
+ DSLITE_PRINTF(1, "Check MSS true..%u\n", mss_new);
+ /*
+ * If TCP MSS is not configured, skip the MSS checks
+ */
+ if (PREDICT_FALSE(mss_new != V4_TCP_MSS_NOT_CONFIGURED_VALUE)) {
+
+ /* if mss_ptr != NULL, then it points to MSS option */
+ mss_ptr = tcp_findoption(tcp, TCP_OPTION_MSS);
+
+ /*
+ * TCP option field: | kind 1B | len 1B | value 2B|
+ * where kind != [0,1]
+ */
+ if (PREDICT_TRUE(mss_ptr && (mss_ptr[1] == 4))) {
+
+ u16 *ptr = (u16*)(mss_ptr + 2);
+
+ mss_old = clib_net_to_host_u16(*ptr);
+
+ if (PREDICT_FALSE(mss_old > mss_new)) {
+ u32 sum32;
+ u16 mss_old_r, old_tcp_checksum_r;
+
+ *ptr = clib_host_to_net_u16(mss_new);
+
+ mss_old_r = ~mss_old;
+
+ old_tcp_checksum_r =
+ ~clib_net_to_host_u16(tcp->tcp_checksum);
+
+ /*
+ * Revise the TCP checksum
+ */
+ sum32 = old_tcp_checksum_r + mss_old_r + mss_new;
+ FILL_CHECKSUM(tcp->tcp_checksum, sum32)
+
+ if (PREDICT_FALSE(tcp_logging_enable_flag)) {
+ tcp_debug_logging(
+ clib_net_to_host_u32(tcp->seq_num),
+ clib_net_to_host_u32(tcp->ack_num),
+ 0,
+ 0,
+ mss_old,
+ mss_new,
+ 0,
+ 0,
+ ~old_tcp_checksum_r,
+ clib_net_to_host_u16(tcp->tcp_checksum));
+ }
+ }
+ }
+ }
+ }
+}
+
+u32 get_my_svi_intf_ip_addr() {
+ return 0x01010101;
+}
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_v4_functions.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_v4_functions.h
new file mode 100644
index 00000000..2429e5e1
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_v4_functions.h
@@ -0,0 +1,342 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_v4_functions.h
+ *
+ * Copyright (c) 2007-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_V4_FUNCTOINS__
+#define __CNAT_V4_FUNCTOINS__
+
+#include "tcp_header_definitions.h"
+#include "cnat_db.h"
+#include "spp_ctx.h"
+
+#include "platform_common.h"
+
+/*
+ * Defines and structures to enable TCP packet logging
+ */
+#define TCP_LOGGING_DISABLE 0
+#define TCP_LOGGING_ENABLE 1
+#define TCP_LOGGING_PACKET_DUMP 2
+#define TCP_LOGGING_SUMMARY_DUMP 3
+
+#define MAX_TCP_LOGGING_COUNT 1024
+
+typedef struct tcp_logging_struct {
+ u32 seq_num;
+ u32 ack_num;
+ u32 old_ip;
+ u32 new_ip;
+ u16 old_port;
+ u16 new_port;
+ u16 old_ip_crc;
+ u16 new_ip_crc;
+ u16 old_tcp_crc;
+ u16 new_tcp_crc;
+} tcp_logging_struct_t;
+
+void tcp_debug_logging_dump (void);
+void tcp_debug_logging_enable_disable (u32 enable_flag);
+
+void
+tcp_debug_logging (
+ u32 seq_num,
+ u32 ack_num,
+ u32 old_ip,
+ u32 new_ip,
+ u16 old_port,
+ u16 new_port,
+ u16 old_ip_crc,
+ u16 new_ip_crc,
+ u16 old_tcp_crc,
+ u16 new_tcp_crc);
+
+#define JLI printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); fflush(stdout);
+
+#define CNAT_ICMP_DEST_UNREACHABLE 100
+#define INCREMENT_NODE_COUNTER(c) \
+ em->counters[node_counter_base_index + c] += 1;
+
+#define V4_TCP_UPDATE_SESSION_FLAG(db, tcp) \
+if ((tcp->flags & TCP_FLAG_ACK) && (tcp->flags & TCP_FLAG_SYN)) { \
+ db->flags |= CNAT_DB_FLAG_TCP_ACTIVE; \
+} \
+if ((tcp->flags & TCP_FLAG_RST) || (tcp->flags & TCP_FLAG_FIN)) { \
+ db->flags &= ~CNAT_DB_FLAG_TCP_ACTIVE; \
+ db->flags |= CNAT_DB_FLAG_TCP_CLOSING; \
+}
+
+#define V4_TCP_UPDATE_SESSION_DB_FLAG(sdb, tcp) \
+if ((tcp->flags & TCP_FLAG_ACK) && (tcp->flags & TCP_FLAG_SYN)) { \
+ sdb->flags |= CNAT_DB_FLAG_TCP_ACTIVE; \
+} \
+if ((tcp->flags & TCP_FLAG_RST) || (tcp->flags & TCP_FLAG_FIN)) { \
+ sdb->flags &= ~CNAT_DB_FLAG_TCP_ACTIVE; \
+ sdb->flags |= CNAT_DB_FLAG_TCP_CLOSING; \
+}
+
+/*
+ * Code to recalculate checksum after ACK/SEQ number changes
+ * This macro assumes, we have pointer to tcp structure
+ * referenced by the name "tcp"
+ */
+#define CNAT_UPDATE_TCP_SEQ_ACK_CHECKSUM(old_val32, new_val32) \
+{ \
+ u16 old_val_lower, old_val_upper, old_tcp_cr; \
+ u16 new_val_lower, new_val_upper, new_tcp_cr; \
+ u32 sum32; \
+ \
+ old_val_lower = ~((u16) old_val32); \
+ old_val_upper = ~((u16) (old_val32 >> 16)); \
+ old_tcp_cr = ~net2host16(&tcp->tcp_checksum); \
+ new_val_lower = (u16) new_val32; \
+ new_val_upper = (u16) (new_val32 >> 16); \
+ \
+ sum32 = old_val_lower + old_val_upper + old_tcp_cr + \
+ new_val_lower + new_val_upper; \
+ \
+ sum32 = (sum32 & 0xffff) + ((sum32 >> 16) & 0xffff); \
+ sum32 = (sum32 & 0xffff) + ((sum32 >> 16) & 0xffff); \
+ new_tcp_cr = ~((u16)sum32); \
+ \
+ tcp->tcp_checksum = host2net16(new_tcp_cr); \
+}
+
+/*
+ * newchecksum = ~(~oldchecksum + ~old + new)
+ * old/new for l3 checksum: ip address
+ */
+#define CNAT_UPDATE_L3_CHECKSUM_DECLARE \
+u16 old_l3_1r, old_l3_2r; \
+u16 old_l3_cr, new_l3_c; \
+u32 new32;
+
+#define CNAT_UPDATE_L3_CHECKSUM(old_l3_1, old_l3_2, old_l3_c, \
+ new_l3_1, new_l3_2) \
+old_l3_1r = ~(old_l3_1); \
+old_l3_2r = ~(old_l3_2); \
+old_l3_cr = ~(old_l3_c); \
+new32 = old_l3_cr + old_l3_1r + old_l3_2r + new_l3_1 + new_l3_2; \
+new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
+new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
+new_l3_c = ~((u16)new32);
+
+
+/*
+ * newchecksum = ~(~oldchecksum + ~old + new)
+ * old/new for l3 checksum: ip address
+ * old/new for l4 checksum: ip address and port
+ */
+#define CNAT_UPDATE_L3_L4_CHECKSUM_DECLARE \
+u16 old_l3_1r, old_l3_2r, old_l4r; \
+u16 old_l3_cr, old_l4_cr; \
+u16 new_l3_c, new_l4_c; \
+u32 sum32, new32;
+
+#define CNAT_UPDATE_L3_L4_CHECKSUM(old_l3_1, old_l3_2, old_l4, \
+ old_l3_c, old_l4_c, \
+ new_l3_1, new_l3_2, new_l4) \
+old_l3_1r = ~(old_l3_1); \
+old_l3_2r = ~(old_l3_2); \
+old_l3_cr = ~(old_l3_c); \
+sum32 = old_l3_1r + old_l3_2r + new_l3_1 + new_l3_2; \
+new32 = old_l3_cr + sum32; \
+new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
+new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
+new_l3_c = ~((u16)new32); \
+old_l4r = ~(old_l4); \
+old_l4_cr = ~(old_l4_c); \
+sum32 += old_l4r + new_l4; \
+new32 = old_l4_cr + sum32; \
+new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
+new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
+new_l4_c = ~((u16)new32);
+
+/*
+ * For ICMP checksums, we don't use the top IP header for checksum calculation
+ */
+#define CNAT_UPDATE_L3_ICMP_CHECKSUM(old_l3_1, old_l3_2, old_l4, \
+ old_l3_c, old_l4_c, \
+ new_l3_1, new_l3_2, new_l4) \
+old_l3_1r = ~(old_l3_1); \
+old_l3_2r = ~(old_l3_2); \
+old_l3_cr = ~(old_l3_c); \
+sum32 = old_l3_1r + old_l3_2r + new_l3_1 + new_l3_2; \
+new32 = old_l3_cr + sum32; \
+new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
+new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
+new_l3_c = ~((u16)new32); \
+old_l4r = ~(old_l4); \
+old_l4_cr = ~(old_l4_c); \
+sum32 = old_l4r + new_l4; \
+new32 = old_l4_cr + sum32; \
+new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
+new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
+new_l4_c = ~((u16)new32);
+
+
+/*
+ * icmp error type message:
+ * newchecksum = ~(~oldchecksum + ~old + new)
+ * old/new for outlayer ip checksum: ip address
+ * old/new for outlayer icmp checksum:
+ * out-layer: ip address
+ * inner-layer: ip addr, port, l3 checksum, l4 checksum
+ */
+#define CNAT_UPDATE_ICMP_ERR_CHECKSUM_DECLARE \
+u16 old_ip_1r, old_ip_2r, old_ip_port_r, old_ip_cr, old_icmp_cr; \
+u16 new_icmp_c; \
+u32 sum32;
+
+
+#define CNAT_UPDATE_ICMP_ERR_CHECKSUM(old_ip_1, old_ip_2, old_ip_port, old_ip_c, old_icmp_c, \
+ new_ip_1, new_ip_2, new_ip_port, new_ip_c) \
+old_ip_1r = ~(old_ip_1); \
+old_ip_2r = ~(old_ip_2); \
+old_ip_port_r = ~(old_ip_port); \
+old_ip_cr = ~(old_ip_c); \
+old_icmp_cr = ~(old_icmp_c); \
+sum32 = old_ip_1r + old_ip_2r + new_ip_1 + new_ip_2 + \
+ old_ip_port_r + new_ip_port + old_ip_cr + new_ip_c; \
+new32 = old_icmp_cr + sum32; \
+new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
+new32 = (new32 & 0xffff) + ((new32 >> 16) & 0xffff); \
+new_icmp_c = ~((u16)new32); \
+
+/*
+ * Add the two 16 bit parts of the 32 bit field
+ * Repeat it one more time to take care of any overflow
+ * Complement the u16 value and store it in network format
+ */
+#define FILL_CHECKSUM(checksum_field, sum32) { \
+ sum32 = (sum32 & 0xffff) + ((sum32>>16) & 0xffff); \
+ sum32 = (sum32 & 0xffff) + ((sum32>>16) & 0xffff); \
+ checksum_field = clib_host_to_net_u16(~((u16) sum32)); \
+}
+
+static inline void
+cnat_v4_recalculate_tcp_checksum (ipv4_header *ip,
+ tcp_hdr_type *tcp,
+ u32 *ip_addr_ptr,
+ u16 *tcp_port_addr_ptr,
+ u32 new_ip,
+ u16 new_port)
+{
+ u32 old_ip_addr, old_ip32_r, new_ip32, sum32;
+ u16 old_port_r, old_ip_checksum_r, old_tcp_checksum_r;
+
+ u16 *p16;
+
+ p16 = (u16*) ip_addr_ptr;
+
+ old_ip_addr = *ip_addr_ptr;
+ old_ip32_r = (((u16) ~clib_net_to_host_u16(*p16)) +
+ ((u16) ~clib_net_to_host_u16(*(p16+1))));
+
+ old_port_r = ~clib_net_to_host_u16(*tcp_port_addr_ptr);
+
+ *ip_addr_ptr = clib_host_to_net_u32(new_ip);
+
+ new_ip32 = (new_ip & 0xffff) + ((new_ip >> 16) & 0xffff);
+
+ old_ip_checksum_r = ~clib_net_to_host_u16(ip->checksum);
+
+ /*
+ * Recalculate the new IP checksum
+ */
+ sum32 = old_ip32_r + new_ip32 + old_ip_checksum_r;
+
+ FILL_CHECKSUM(ip->checksum, sum32);
+
+ u16 frag_offset =
+ clib_net_to_host_u16((ip->frag_flags_offset));
+
+ if(PREDICT_FALSE(frag_offset & IP_FRAG_OFFSET_MASK)) {
+ return; /* No need to update TCP fields */
+ }
+
+ *tcp_port_addr_ptr = clib_host_to_net_u16(new_port);
+ old_tcp_checksum_r = ~clib_net_to_host_u16(tcp->tcp_checksum);
+
+ /*
+ * Recalculate the new TCP checksum
+ */
+ sum32 = old_ip32_r + new_ip32 +
+ old_port_r + new_port + old_tcp_checksum_r;
+
+ FILL_CHECKSUM(tcp->tcp_checksum, sum32);
+
+ if (PREDICT_FALSE(tcp_logging_enable_flag)) {
+ tcp_debug_logging(
+ clib_net_to_host_u32(tcp->seq_num),
+ clib_net_to_host_u32(tcp->ack_num),
+ clib_net_to_host_u32(old_ip_addr),
+ clib_net_to_host_u32(*ip_addr_ptr),
+ ~old_port_r,
+ clib_net_to_host_u16(*tcp_port_addr_ptr),
+ ~old_ip_checksum_r,
+ clib_net_to_host_u16(ip->checksum),
+ ~old_tcp_checksum_r,
+ clib_net_to_host_u16(tcp->tcp_checksum));
+ }
+}
+
+
+extern void tcp_in2out_nat_mss_n_checksum (ipv4_header *ip,
+ tcp_hdr_type *tcp,
+ u32 ipv4_addr,
+ u16 port,
+ cnat_main_db_entry_t * db);
+
+void hex_dump(u8 * p, int len);
+
+u32 get_my_svi_intf_ip_addr();
+
+/*
+ * in cnat_v4_icmp_gen.c,
+ * return 1 if icmp msg allow to generate
+ * for this user
+ */
+
+u32 icmp_msg_gen_allowed ();
+
+cnat_icmp_msg_t v6_icmp_msg_gen_allowed();
+
+int v4_crc_zero_udp_allowed();
+void ipv4_decr_ttl_n_calc_csum(ipv4_header *ipv4);
+int icmpv4_generate_with_throttling (spp_ctx_t *ctx, ipv4_header *ipv4,
+ u16 rx_uidb_index);
+
+int icmpv6_generate_with_throttling (spp_ctx_t *ctx, ipv6_header_t *ipv4,
+ u16 rx_uidb_index);
+
+void icmp_error_generate_v6(spp_ctx_t *ctx, u8 icmp_type,
+ u8 icmp_code, u16 uidb_index);
+
+void calculate_window_scale(tcp_hdr_type *tcp_header, u8 *scale);
+
+void cnat_log_nat44_tcp_seq_mismatch(
+ cnat_main_db_entry_t *db,
+ cnat_vrfmap_t *vrfmap);
+void print_icmp_pkt (ipv4_header *ip);
+void print_udp_pkt (ipv4_header *ip);
+void print_tcp_pkt (ipv4_header *ip);
+void print_ipv6_pkt (ipv6_header_t *ip);
+
+
+#endif
+
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_v4_pptp_alg.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_v4_pptp_alg.h
new file mode 100644
index 00000000..5a6d4243
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_v4_pptp_alg.h
@@ -0,0 +1,150 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_v4_pptp_alg.h
+ *
+ * Copyright (c) 2009-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_V4_PPTP_ALG_H__
+#define __CNAT_V4_PPTP_ALG_H__
+
+/* Debug utils of PPTP */
+#define PPTP_DBG(debug, ...) \
+ if(PREDICT_FALSE(cnat_pptp_debug_flag >= debug)) { \
+ PLATFORM_DEBUG_PRINT("%s:%s:%d - ", \
+ __FILE__, __FUNCTION__, __LINE__);\
+ PLATFORM_DEBUG_PRINT(__VA_ARGS__);\
+ PLATFORM_DEBUG_PRINT("\n"); \
+ }
+
+#define PPTP_DUMP_PACKET(ip, len) pptp_hex_dump(ip, len)
+
+
+#define PPTP_DISABLED 0
+#define PPTP_ENABLED 1
+
+#define PPTP_GRE_TIMEOUT 60 /*sec */
+
+#define TCP_PPTP_PORT 1723
+
+#define PPTP_PAC 0
+#define PPTP_PNS 1
+
+/* PPTP MSG TYPE */
+
+#define PPTP_MSG_TYPE_CONTROL 1
+#define PPTP_MSG_TYPE_MGMT 2
+
+/* PPTP control messages */
+
+/* control connection mgmt */
+#define PPTP_START_CC_RQ 1
+#define PPTP_START_CC_RP 2
+#define PPTP_STOP_CC_RQ 3
+#define PPTP_STOP_CC_RP 4
+#define PPTP_ECHO_RQ 5
+#define PPTP_ECHO_RP 6
+
+/* call mgmt */
+#define PPTP_OBOUND_CALL_RQ 7
+#define PPTP_OBOUND_CALL_RP 8
+#define PPTP_IBOUND_CALL_RQ 9
+#define PPTP_IBOUND_CALL_RP 10
+#define PPTP_IBOUND_CALL_CN 11
+#define PPTP_CALL_CLEAR_RQ 12
+#define PPTP_CALL_DISCON_NT 13
+
+/* other */
+
+#define PPTP_WAN_ERR_NT 14
+#define PPTP_SET_LINK_INF 15
+
+#define PPTP_MIN_HDR_LEN 8
+
+/* Byte offsets from start of TCP Data(PPTP header) */
+
+#define PPTP_CTRL_MGMT_TYPE_OFFSET 0x02
+#define PPTP_CC_TYPE_OFFSET 0x08
+#define PPTP_HDR_CALL_ID_OFFSET 0x0c
+#define PPTP_HDR_PEER_CALL_ID_OFFSET 0x0e
+
+#define PPTP_HDR_RESULT_CODE_OFFSET_STCCRP 0x0e
+#define PPTP_HDR_RESULT_CODE_OFFSET 0x10
+
+
+/* Offset of control/mgmt msg types
+ from start of TCP header */
+
+#define TCP_HEADER_SIZE(tcp) \
+ ((tcp->hdr_len>>4) << 2)
+
+
+#define PPTP_MSG_START_OFFSET(tcp) \
+ ((u8*)tcp + TCP_HEADER_SIZE(tcp))
+
+
+#define PPTP_CC_MSG_TYPE_OFFSET(tcp) \
+ (PPTP_MSG_START_OFFSET(tcp) + \
+ PPTP_CC_TYPE_OFFSET )
+
+#define PPTP_MGMT_MSG_TYPE_OFFSET(tcp) \
+ ( PPTP_MSG_START_OFFSET(tcp) + \
+ PPTP_CTRL_MGMT_TYPE_OFFSET )
+
+#define PPTP_CALL_ID_OFFSET(tcp) \
+ ( PPTP_MSG_START_OFFSET(tcp) + \
+ PPTP_HDR_CALL_ID_OFFSET )
+
+#define PPTP_PEER_CALL_ID_OFFSET(tcp) \
+ ( PPTP_MSG_START_OFFSET(tcp) + \
+ PPTP_HDR_PEER_CALL_ID_OFFSET )
+
+#define PPTP_RESULT_CODE_OFFSET(tcp) \
+ ( PPTP_MSG_START_OFFSET(tcp) + \
+ PPTP_HDR_RESULT_CODE_OFFSET )
+
+#define PPTP_RESULT_CODE_OFFSET_STCCRP(tcp) \
+ ( PPTP_MSG_START_OFFSET(tcp) + \
+ PPTP_HDR_RESULT_CODE_OFFSET_STCCRP)
+
+/* values */
+#define PPTP_CC_MSG_TYPE(tcp) \
+ (u16*)PPTP_CC_MSG_TYPE_OFFSET(tcp)
+
+#define PPTP_MGMT_MSG_TYPE(tcp) \
+ (u16*)PPTP_MGMT_MSG_TYPE_OFFSET(tcp)
+
+#define PPTP_CALL_ID(tcp) \
+ (u16*)PPTP_CALL_ID_OFFSET(tcp)
+
+#define PPTP_PEER_CALL_ID(tcp) \
+ (u16*)PPTP_PEER_CALL_ID_OFFSET(tcp)
+
+#define PPTP_RESULT_CODE(tcp) \
+ *(u8*)PPTP_RESULT_CODE_OFFSET(tcp);
+
+#define PPTP_RESULT_CODE_STCCRP(tcp) \
+ *(u8*)PPTP_RESULT_CODE_OFFSET_STCCRP(tcp);
+
+
+/* other code */
+#define PPTP_CHAN_SUCCESS 1
+
+
+/* Data structures */
+
+extern u32 cnat_pptp_debug_flag;
+
+#endif /* __CNAT_V4_PPTP_ALG_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_v4_tcp_in2out_stages.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_v4_tcp_in2out_stages.c
new file mode 100644
index 00000000..220ced46
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_v4_tcp_in2out_stages.c
@@ -0,0 +1,679 @@
+/*
+ *---------------------------------------------------------------------------
+ * cnat_v4_tcp_in2out_stages.c - cnat_v4_tcp_in2out node pipeline stage functions
+ *
+ *
+ * Copyright (c) 2008-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vppinfra/error.h>
+#include <vnet/buffer.h>
+
+#include "cnat_db.h"
+/* #include <cnat_feature_data.h> */
+#include "ipv4_packet.h"
+#include "tcp_header_definitions.h"
+#include "cnat_config.h"
+#include "cnat_global.h"
+#include "cnat_v4_functions.h"
+#include "cnat_v4_ftp_alg.h"
+#include "cnat_v4_pptp_alg.h"
+
+#define foreach_cnat_ipv4_tcp_inside_input_error \
+_(TCP_NAT_IN, "packets received") \
+_(TCP_NAT, "packets NATed") \
+_(TCP_EXCEPTION, "packets to exception") \
+_(TCP_TTL_GEN, "Generated TTL Expiry ICMP packet") \
+_(TCP_TTL_DROP, "Could not generate TTL Expiry ICMP packet") \
+_(TCP_SESSION_DROP, "Could not generate session") \
+_(TCP_FRAG_DROP, "Non-first Fragment received")
+
+typedef enum {
+#define _(sym,str) sym,
+ foreach_cnat_ipv4_tcp_inside_input_error
+#undef _
+ CNAT_IPV4_TCP_INSIDE_INPUT_N_ERROR,
+} cnat_ipv4_tcp_inside_input_t;
+
+static char * cnat_ipv4_tcp_inside_input_error_strings[] = {
+#define _(sym,string) string,
+ foreach_cnat_ipv4_tcp_inside_input_error
+#undef _
+
+
+
+typedef struct cnat_v4_tcp_in2out_pipeline_data_ {
+ spp_node_main_vector_t *nmv;
+ /* Add additional pipeline stage data here... */
+ u32 bucket;
+ u16 src_port; /* Added for handling fragments */
+ u16 dst_port; /* Added for handling fragments */
+} cnat_v4_tcp_in2out_pipeline_data_t;
+
+static cnat_v4_tcp_in2out_pipeline_data_t pctx_data[SPP_MAXDISPATCH];
+
+#define EXTRA_PIPELINE_ARGS_PROTO , cnat_v4_tcp_in2out_pipeline_data_t *pctx
+#define EXTRA_PIPELINE_ARGS , pctx
+
+ALWAYS_INLINE(
+static inline void
+stage0(spp_ctx_t **ctxs, int index, spp_node_t *np,
+ u8 *disp_used EXTRA_PIPELINE_ARGS_PROTO))
+{
+ spp_ctx_t *ctx = ctxs[index];
+ /*
+ * Prefetch the context header. This is almost always
+ * the right thing to do
+ */
+ SPP_PREFETCH_CTX(ctx);
+}
+
+ALWAYS_INLINE(
+static inline void
+stage1(spp_ctx_t **ctxs, int index, spp_node_t *np,
+ u8 *disp_used EXTRA_PIPELINE_ARGS_PROTO))
+{
+ spp_ctx_t *ctx = ctxs[index];
+ /* got ctx, prefetch packet data separately */
+ SPP_PREFETCH_CTX_DATA(ctx, 1*CACHE_DATA_QUANTUM);
+}
+
+ALWAYS_INLINE(
+static inline void
+stage2(spp_ctx_t **ctxs, int index, spp_node_t *np,
+ u8 *disp_used EXTRA_PIPELINE_ARGS_PROTO))
+{
+ spp_ctx_t *ctx = ctxs[index];
+ u64 a, b, c;
+ u32 bucket;
+ cnat_feature_data_t *fd = (cnat_feature_data_t *)ctx->feature_data;
+ ipv4_header *ip;
+ tcp_hdr_type * tcp;
+ u8 *prefetch_target;
+
+ INCREMENT_NODE_COUNTER(np, TCP_NAT_IN);
+
+ /* extract the key from ctx and save it to feature_data */
+
+ ip = (ipv4_header *)(ctx->current_header);
+ ctx->application_start = (ip->version_hdr_len_words & 0xf) << 2;
+ tcp = (tcp_hdr_type*) ((u8 *)ip + ctx->application_start);
+
+ PLATFORM_CNAT_SET_RX_VRF(ctx,fd->dbl.k.k.vrf, CNAT_TCP, 1);
+ fd->dbl.k.k.ipv4 = spp_net_to_host_byte_order_32(&ip->src_addr);
+
+ if(PREDICT_FALSE(ctx->ru.rx.frag)) {
+ /* Must have routed through cnat_v4_frag_in2out node
+ * Since feature data of the ctx is being used for other
+ * purposes here, copy them to extra stage argument
+ */
+ u16 *feature_data_ports = (u16 *)&ctx->feature_data[2];
+ pctx[index].src_port = fd->dbl.k.k.port = *feature_data_ports;
+ feature_data_ports++;
+ pctx[index].dst_port = *feature_data_ports;
+ } else {
+ fd->dbl.k.k.port = spp_net_to_host_byte_order_16(&tcp->src_port);
+ pctx[index].dst_port =
+ spp_net_to_host_byte_order_16(&tcp->dest_port);
+ }
+
+#if 0
+ /* extra info for evil mode, or default value for dst_ipv4 field in good mode */
+ fd->dbl.dst_ipv4 = address_dependent_filtering ?
+ spp_net_to_host_byte_order_32(&ip->dest_addr) : 0;
+#endif
+
+ CNAT_V4_GET_HASH(fd->dbl.k.key64,
+ bucket, CNAT_MAIN_HASH_MASK)
+
+ prefetch_target = (u8 *)(&cnat_in2out_hash[bucket]);
+ pctx[index].bucket = bucket;
+
+ /* Prefetch the hash bucket */
+ SPP_PREFETCH(prefetch_target, 0, LOAD);
+
+}
+
+ALWAYS_INLINE(
+static inline void
+stage3(spp_ctx_t **ctxs, int index, spp_node_t *np,
+ u8 *disp_used EXTRA_PIPELINE_ARGS_PROTO))
+{
+ u32 db_index;
+ u32 bucket;
+ uword prefetch_target0, prefetch_target1;
+
+ bucket = pctx[index].bucket;
+
+ /* read the hash bucket */
+ db_index = pctx[index].bucket = cnat_in2out_hash[bucket].next;
+ if (PREDICT_TRUE(db_index != EMPTY)) {
+
+ /*
+ * Prefetch database keys. We save space by not cache-line
+ * aligning the DB entries. We don't want to waste LSU
+ * bandwidth prefetching stuff we won't need.
+ */
+
+ prefetch_target0 = (uword)(cnat_main_db + db_index);
+
+ SPP_PREFETCH(prefetch_target0, 0, LOAD);
+
+ /* Just beyond DB key #2 */
+
+ prefetch_target1 = prefetch_target0 +
+ STRUCT_OFFSET_OF(cnat_main_db_entry_t, user_ports);
+
+ /* If the targets are in different lines, do the second prefetch */
+
+ if (PREDICT_FALSE((prefetch_target0 & ~(SPP_CACHE_LINE_BYTES-1)) !=
+ (prefetch_target1 & ~(SPP_CACHE_LINE_BYTES-1)))) {
+
+ SPP_PREFETCH(prefetch_target1, 0, LOAD);
+
+ }
+ }
+}
+
+static inline void
+stage4(spp_ctx_t **ctxs, int index, spp_node_t *np,
+ u8 *disp_used EXTRA_PIPELINE_ARGS_PROTO)
+{
+ spp_ctx_t *ctx = ctxs[index];
+ u32 db_index = pctx[index].bucket;
+ cnat_main_db_entry_t *db;
+ cnat_feature_data_t *fd;
+
+ /*
+ * Note: if the search already failed (empty bucket),
+ * the answer is already in the pipeline context structure
+ */
+ if (PREDICT_FALSE(db_index == EMPTY)) {
+ return;
+ }
+
+ fd = (cnat_feature_data_t *)ctx->feature_data;
+
+ /*
+ * Note: hash collisions suck. We can't easily prefetch around them.
+ * The first trip around the track will be fast. After that, maybe
+ * not so much...
+ */
+ do {
+
+ db = cnat_main_db + db_index;
+ if (PREDICT_TRUE(db->in2out_key.key64 == fd->dbl.k.key64))
+ break;
+ db_index = db->in2out_hash.next;
+
+ } while (db_index != EMPTY);
+
+ /* even in evil mode, for in2out, we nat all packets regardless mode and dst_ip */
+
+ /* Stick the answer back into the pipeline context structure */
+ pctx[index].bucket = db_index;
+}
+
+ALWAYS_INLINE(
+static inline void
+stage5(spp_ctx_t **ctxs, int index, spp_node_t *np,
+ u8 *disp_used EXTRA_PIPELINE_ARGS_PROTO))
+{
+ spp_ctx_t *ctx = ctxs[index];
+ u32 db_index = pctx[index].bucket;
+ cnat_feature_data_t *fd = (cnat_feature_data_t *)ctx->feature_data;
+ int disposition;
+ cnat_main_db_entry_t *db;
+ /* Below two pointers are just to keep the cnat_ftp_alg call happy*/
+ dslite_table_entry_t *dslite_entry_ptr = NULL;
+ ipv6_header_t *ipv6_hdr = NULL;
+ tcp_hdr_type *tcp;
+ ipv4_header *ip;
+ i8 delta;
+ u32 seq, seq1;
+ u32 window;
+ u8 scale;
+ int rc;
+
+ ip = (ipv4_header *) ctx->current_header;
+
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ if (PREDICT_FALSE(ip->ttl <= 1)) {
+ /* Try to generate ICMP error msg, as TTL is <= 1 */
+
+ if (icmpv4_generate_with_throttling
+ (ctx, ip, ctx->ru.rx.uidb_index)) {
+ /* Generated ICMP */
+ disposition = CNAT_REWRITE_OUTPUT;
+ INCREMENT_NODE_COUNTER(np, TCP_TTL_GEN);
+ } else {
+ /* Could not generated ICMP - drop the packet */
+ disposition = CNAT_DROP;
+ INCREMENT_NODE_COUNTER(np, TCP_TTL_DROP);
+ }
+ goto drop_pkt;
+ }
+ }
+
+ if (PREDICT_FALSE(db_index == EMPTY)) {
+ if(PREDICT_FALSE(ctx->ru.rx.frag)) {
+ /* Must have routed through cnat_v4_frag_in2out node */
+ u16 frag_offset =
+ spp_net_to_host_byte_order_16(&(ip->frag_flags_offset));
+ if(PREDICT_FALSE(frag_offset & IP_FRAG_OFFSET_MASK)) {
+ INCREMENT_NODE_COUNTER(np, TCP_FRAG_DROP);
+ disposition = CNAT_DROP;
+ goto drop_pkt;
+ } else {
+ INCREMENT_NODE_COUNTER(np, TCP_EXCEPTION);
+ disposition = CNAT_V4_TCP_IE;
+ }
+ } else {
+ INCREMENT_NODE_COUNTER(np, TCP_EXCEPTION);
+ disposition = CNAT_V4_TCP_IE;
+ }
+ } else {
+ cnat_key_t dest_info;
+ cnat_session_entry_t *session_db = NULL;
+ db = cnat_main_db + db_index;
+ /* Handle destination sessions */
+ tcp = (tcp_hdr_type*) ((u8*)ip + ctx->application_start);
+ dest_info.k.port = pctx[index].dst_port;
+ dest_info.k.ipv4 = spp_net_to_host_byte_order_32(&(ip->dest_addr));
+
+ if(PREDICT_TRUE(!PLATFORM_DBL_SUPPORT)) {
+
+ /* No DBL support, so just update the destn and proceed */
+ db->dst_ipv4 = dest_info.k.ipv4;
+ db->dst_port = dest_info.k.port;
+ goto update_pkt;
+ }
+
+ if(PREDICT_FALSE(db->dst_ipv4 != dest_info.k.ipv4 ||
+ db->dst_port != dest_info.k.port)) {
+ if(PREDICT_TRUE(db->nsessions == 0)) {
+ /* Should be a static entry
+ * Note this session as the first session and log
+ */
+ cnat_add_dest_n_log(db, &dest_info);
+ } else if(PREDICT_FALSE(db->nsessions == 1)) {
+ /* Destn is not same as in main db. Multiple session
+ * scenario
+ */
+ dest_info.k.vrf = db->in2out_key.k.vrf;
+ session_db = cnat_handle_1to2_session(db, &dest_info);
+ if(PREDICT_FALSE(session_db == NULL)) {
+ disposition = CNAT_DROP;
+ INCREMENT_NODE_COUNTER(np, TCP_SESSION_DROP);
+ goto drop_pkt;
+ }
+ } else { /* There are already multiple destinations */
+ dest_info.k.vrf = db->in2out_key.k.vrf;
+ /* If session already exists,
+ * cnat_create_session_db_entry will return the existing db
+ * else create a new db
+ * If could not create, return NULL
+ */
+ session_db = cnat_create_session_db_entry(&dest_info,
+ db, TRUE);
+ if(PREDICT_FALSE(session_db == NULL)) {
+ disposition = CNAT_DROP;
+ INCREMENT_NODE_COUNTER(np, TCP_SESSION_DROP);
+ goto drop_pkt;
+ }
+ }
+ if(PREDICT_TRUE(session_db)) {
+ /* Have to repeat the window size check for new destinations */
+ window = (u32)spp_net_to_host_byte_order_16(
+ &tcp->window_size);
+ window = window << session_db->scale;
+ if(PREDICT_TRUE(!session_db->window)) {
+ calculate_window_scale(tcp, &scale);
+ session_db->scale = scale;
+ session_db->window = window;
+ } else if (PREDICT_FALSE(session_db->window <
+ window)) {
+ /* Update the db entry with window option from packet */
+ session_db->window = window;
+ } else {
+ /* Do nothing */
+ }
+ session_db->tcp_seq_num = spp_net_to_host_byte_order_32(
+ &tcp->seq_num);
+ session_db->ack_no = spp_net_to_host_byte_order_32(
+ &tcp->ack_num);
+ if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) {
+ PLATFORM_DEBUG_PRINT("\n In2out SDB stages seq no = %u,"
+ " ack no = %u, window = %u\n",
+ session_db->tcp_seq_num,
+ session_db->ack_no,
+ session_db->window);
+ }
+ }
+ } else {
+ //Update the seq no and ack no for subsequent communication
+ //after connection establishment
+ //No need to update window here. Window is already updated
+ //during connection establishment
+ window = (u32)spp_net_to_host_byte_order_16(
+ &tcp->window_size);
+ window = window << db->scale;
+ if(PREDICT_FALSE(!ALG_ENABLED_DB(db))) {
+ //This check is done since proto_data is part of union in main
+ //db entry
+ db->proto_data.tcp_seq_chk.seq_no =
+ spp_net_to_host_byte_order_32(
+ &tcp->seq_num);
+ db->proto_data.tcp_seq_chk.ack_no =
+ spp_net_to_host_byte_order_32(
+ &tcp->ack_num);
+ }
+ if (PREDICT_FALSE(db->diff_window < window)) {
+ /* Update the db entry with window option from packet */
+ db->diff_window = window;
+ }
+ if (PREDICT_FALSE(global_debug_flag && CNAT_DEBUG_GLOBAL_ALL)) {
+ PLATFORM_DEBUG_PRINT("\n In2out MainDB seq no = %u,"
+ "\n ack no = %u\n",
+ db->proto_data.tcp_seq_chk.seq_no,
+ db->proto_data.tcp_seq_chk.ack_no);
+ PLATFORM_DEBUG_PRINT("\n In2out MAINDB window = %u\n",
+ db->diff_window);
+ }
+ }
+update_pkt:
+
+ INCREMENT_NODE_COUNTER(np, TCP_NAT);
+
+ disposition = CNAT_REWRITE_OUTPUT;
+
+ /* NAT the packet and update checksum (increamental) */
+
+ /* If it is a non-first fragment, we need not worry about
+ * ALGs as the packet does not have TCP header..
+ * However, under a very race scenario when this non-first
+ * fragment is containing an FTP PORT command OR RTSP command
+ * we cannot handle that case.. in that case the ALG will fail
+ * Do not want to add a lot of complexity to handle one in million
+ * of such ALG case
+ */
+ u16 frag_offset =
+ spp_net_to_host_byte_order_16(&(ip->frag_flags_offset));
+
+ if(PREDICT_FALSE(frag_offset & IP_FRAG_OFFSET_MASK)) {
+ /* Non first fragment.. no TCP header */
+ FTP_ALG_DEBUG_PRINTF("Non first frag.. cannot handle ALG");
+ goto handle_ttl_n_checksum;
+ }
+
+ FTP_ALG_DEBUG_PRINTF("src port 0x%x, dst_port 0x%x",
+ spp_net_to_host_byte_order_16(&tcp->src_port),
+ spp_net_to_host_byte_order_16(&tcp->dest_port))
+
+ /* handle FTP ALG */
+ if (PREDICT_FALSE(ftp_alg_enabled &&
+ (spp_net_to_host_byte_order_16(&tcp->src_port) == 21 ||
+ spp_net_to_host_byte_order_16(&tcp->dest_port) == 21))) {
+
+ if(PREDICT_FALSE((db->flags & CNAT_DB_FLAG_PPTP_TUNNEL_ACTIVE) ||
+ (db->flags & CNAT_DB_FLAG_PPTP_TUNNEL_INIT)))
+ {
+ /* FTP on a PPTP Control session? Ignore FTP */
+ goto handle_ttl_n_checksum;
+ }
+
+ if (PREDICT_FALSE(tcp->flags & (TCP_FLAG_SYN | TCP_FLAG_RST |
+ TCP_FLAG_FIN))) {
+
+ FTP_ALG_DEBUG_PRINTF("SYN Case setting delta = 0")
+
+ /* reset the delta */
+ if(PREDICT_FALSE(session_db != NULL)) {
+ session_db->alg.delta = 0;
+ } else {
+ db->alg.delta = 0;
+ }
+
+ } else {
+
+ /* need to adjust seq # for in2out pkt if delta is not 0 */
+ if (PREDICT_TRUE((session_db && (session_db->alg.delta != 0))
+ || ((!session_db) && (db->alg.delta != 0)))) {
+ seq = net2host32(&tcp->seq_num);
+
+ FTP_ALG_DEBUG_PRINTF("Orig Seq Num 0x%x", seq)
+ /*
+ * for ftp packets, due to PORT command translation,
+ * we may have cases that a packet/payload len gets
+ * changed for tcp, we need to adjust the packet's
+ * sequence numbers to match the changes. The delta
+ * of orig pkt len and new len is in alg_dlt[1] together
+ * with the sequence number that cuased the delta. When
+ * there are multiple len changes, we keep theprevious
+ * delta in alg_dlt[0] for case like pkt retransmission.
+ * So depends on packet seq number, we decide to use
+ * either latest delta or previous delta ([0])
+ * We won't be here if both delta values are 0
+ */
+ if(PREDICT_FALSE(session_db != NULL)) {
+ seq1 = seq > session_db->tcp_seq_num ?
+ (seq + session_db->alg.alg_dlt[1]):
+ (seq + session_db->alg.alg_dlt[0]);
+ } else {
+ seq1 = seq > db->proto_data.seq_pcp.tcp_seq_num ?
+ (seq + db->alg.alg_dlt[1]):
+ (seq + db->alg.alg_dlt[0]);
+ }
+
+ FTP_ALG_DEBUG_PRINTF("Old_seq_num 0x%x New Seq Num 0x%x",
+ seq, seq1)
+
+ if (PREDICT_TRUE(seq1 != seq)) {
+
+ tcp->seq_num = host2net32(seq1);
+
+ FTP_ALG_DEBUG_PRINTF("Old TCP Checksum 0x%x",
+ net2host16(&tcp->tcp_checksum))
+
+ /*
+ * fix checksum incremental for seq # changes
+ * newchecksum = ~(~oldchecksum + ~old + new)
+ */
+ CNAT_UPDATE_TCP_SEQ_ACK_CHECKSUM(seq, seq1)
+ } /* There is a diff in seq */
+
+ } /* ALG Delta is non zero */
+
+ rc = cnat_ftp_alg((u8*) ip, &delta, db, dslite_entry_ptr, ipv6_hdr);
+
+ FTP_ALG_DEBUG_PRINTF("cnat_ftp_alg rc 0x%x", rc)
+
+ /*if located PORT cmd, packet being updated, take the delta and seq # */
+ if (PREDICT_FALSE(rc)) {
+
+ /* set alg flag for this ftp control connection */
+ if(PREDICT_FALSE(session_db != NULL)) {
+ session_db->flags |= CNAT_DB_FLAG_ALG_CTRL_FLOW;
+ } else {
+ db->flags |= CNAT_DB_FLAG_ALG_CTRL_FLOW;
+ }
+
+ /*
+ * rc != 0 indicates this packet has triggered a new pkt len delta
+ * we need to update db entry's seq# with seq# of this packet.
+ *
+ * Move alg_dlt[1] to [0], (current delta -> previous delta)
+ * then apply latest delta to alg_dlt[1] (keep [1] as latest delta)
+ */
+ if(PREDICT_FALSE(session_db != NULL)) {
+ session_db->tcp_seq_num = net2host32(&tcp->seq_num);
+ session_db->alg.alg_dlt[0] = session_db->alg.alg_dlt[1];
+
+ /* accumulate the delta ! */
+ session_db->alg.alg_dlt[1] += delta;
+ FTP_ALG_DEBUG_PRINTF(
+ "cnat_ftp_alg seq_num 0x%x, dlt0 0x%x, dlt1 0x%x",
+ session_db->tcp_seq_num,
+ session_db->alg.alg_dlt[0],
+ session_db->alg.alg_dlt[1])
+
+ } else {
+ db->proto_data.seq_pcp.tcp_seq_num = net2host32(&tcp->seq_num);
+ db->alg.alg_dlt[0] = db->alg.alg_dlt[1];
+
+ /* accumulate the delta ! */
+ db->alg.alg_dlt[1] += delta;
+
+ FTP_ALG_DEBUG_PRINTF(
+ "cnat_ftp_alg seq_num 0x%x, dlt0 0x%x, dlt1 0x%x",
+ db->proto_data.seq_pcp.tcp_seq_num,
+ db->alg.alg_dlt[0],
+ db->alg.alg_dlt[1])
+ }
+ ctx->current_length += delta;
+ }/* cnat_ftp_alg returned non zero */
+ } /* It is not a SYN, RST or FIN */
+ } else if (PREDICT_FALSE(rtsp_alg_port_num &&
+ ((spp_net_to_host_byte_order_16(&tcp->dest_port) == rtsp_alg_port_num) ||
+ (spp_net_to_host_byte_order_16(&tcp->src_port) == rtsp_alg_port_num))) ) {
+
+ if (PREDICT_FALSE(tcp->flags & (TCP_FLAG_SYN | TCP_FLAG_RST |
+ TCP_FLAG_FIN))) {
+
+ FTP_ALG_DEBUG_PRINTF("SYN Case setting delta = 0")
+
+ /* reset the delta */
+ if(PREDICT_FALSE(session_db != NULL)) {
+ session_db->alg.delta = 0;
+ } else {
+ db->alg.delta = 0;
+ }
+
+ } else {
+#define RTSP_ALG_DELTA_MASK 0xFF
+ /* need to adjust seq # for in2out pkt if delta is not 0 */
+ if (PREDICT_FALSE((session_db &&
+ (session_db->alg.delta & RTSP_ALG_DELTA_MASK) != 0) ||
+ ((!session_db) &&
+ (db->alg.delta & RTSP_ALG_DELTA_MASK) != 0))) {
+ seq = net2host32(&tcp->seq_num);
+
+ if(PREDICT_FALSE(session_db != NULL)) {
+ seq1 = seq > session_db->tcp_seq_num ?
+ (seq + db->alg.alg_dlt[1]):
+ (seq + db->alg.alg_dlt[0]);
+ } else {
+ seq1 = seq > db->proto_data.seq_pcp.tcp_seq_num ?
+ (seq + db->alg.alg_dlt[1]):
+ (seq + db->alg.alg_dlt[0]);
+ }
+
+ FTP_ALG_DEBUG_PRINTF("Old_seq_num 0x%x New Seq Num 0x%x",
+ seq, seq1)
+
+ if (PREDICT_TRUE(seq1 != seq)) {
+
+ tcp->seq_num = host2net32(seq1);
+
+ FTP_ALG_DEBUG_PRINTF("Old TCP Checksum 0x%x",
+ net2host16(&tcp->tcp_checksum))
+
+ /*
+ * fix checksum incremental for seq # changes
+ * newchecksum = ~(~oldchecksum + ~old + new)
+ */
+ CNAT_UPDATE_TCP_SEQ_ACK_CHECKSUM(seq, seq1)
+ }
+
+ }
+ }
+ if ((session_db && (!session_db->alg.il)) ||
+ ((!session_db) && (!db->alg.il))) {
+ cnat_rtsp_alg((u8*) ip,
+ &delta,
+ db,
+ ctx->current_length,
+ NULL,
+ NULL);
+ }
+ }
+handle_ttl_n_checksum:
+ if (PLATFORM_HANDLE_TTL_DECREMENT) {
+ /*
+ * Decrement TTL and update IPv4 checksum
+ */
+ ipv4_decr_ttl_n_calc_csum(ip);
+ }
+
+ tcp_in2out_nat_mss_n_checksum(ip,
+ tcp,
+ db->out2in_key.k.ipv4,
+ db->out2in_key.k.port,
+ db);
+/* CNAT_PPTP_ALG_SUPPORT */
+ /* code to handle pptp control msgs */
+ if(PREDICT_FALSE(
+ (spp_net_to_host_byte_order_16(&tcp->dest_port) ==
+ TCP_PPTP_PORT))) {
+
+ u32 ret;
+
+ PPTP_DBG(3, "PPTP mgmt/ctrl msg recieved");
+
+ ret = cnat_handle_pptp_msg(ctx, db , tcp, PPTP_PNS );
+
+ if( PREDICT_FALSE( ret != CNAT_SUCCESS) ) {
+ PPTP_DBG(3, "PPTP mgmt/ctrl msg drop");
+ disposition = CNAT_DROP;
+ PPTP_INCR(ctrl_msg_drops);
+ goto drop_pkt;
+ }
+ }
+
+/* CNAT_PPTP_ALG_SUPPORT */
+
+ /* update transaltion counters */
+ db->in2out_pkts++;
+
+ in2out_forwarding_count++;
+
+ PLATFORM_CNAT_SET_TX_VRF(ctx,db->out2in_key.k.vrf);
+
+ /* update the timer for good mode, or evil mode dst_ip match */
+
+// if (!address_dependent_filtering || fd->dbl.dst_ipv4 == db->dst_ipv4) {
+ if(PREDICT_FALSE(session_db != NULL)) {
+ V4_TCP_UPDATE_SESSION_DB_FLAG(session_db, tcp);
+ CNAT_DB_TIMEOUT_RST(session_db);
+ } else {
+ V4_TCP_UPDATE_SESSION_FLAG(db, tcp);
+ CNAT_DB_TIMEOUT_RST(db);
+ }
+
+// }
+
+ }
+
+ /* Pick up the answer and put it into the context */
+ fd->dbl.db_index = db_index;
+
+drop_pkt:
+
+ DISP_PUSH_CTX(np, ctx, disposition, disp_used, last_disposition, last_contexts_ptr, last_nused_ptr);
+
+}
+
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_va_db.c b/vpp/plugins/vcgn-plugin/vcgn/cnat_va_db.c
new file mode 100644
index 00000000..7423bdf2
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_va_db.c
@@ -0,0 +1,286 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_va_db.c - virtual assembly database
+ *
+ * Copyright (c) 2009, 2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <cnat_va_db.h>
+#include <format.h>
+#include <spp_node.h>
+#include <spp_alloc.h>
+#include <spp_byteorder.h>
+#include <spp_main.h>
+#include <spp_cache.h>
+#include <spp_interface.h>
+#include <spp_api.h>
+#include <spp_client_api.h>
+#include <spp_timers.h>
+#include <cnat_db.h>
+#include <spp_plugin.h>
+#include <cnat_v4_functions.h>
+
+
+va_bucket_t va_bucket[VA_BUCKETS];
+
+void va_bucket_init () {
+
+ u32 i;
+
+ /*
+ * set the pointer in each bucket
+ * points to nowhere
+ */
+ for (i=0; i<VA_BUCKETS; i++) {
+ va_bucket[i].next_available_entry = ~0;
+ }
+
+}
+
+inline void va_db_add_new_entry (u32 bucket_index,
+ va_lookup_key * key )
+{
+
+ va_entry_t * entry_p;
+ u32 head, next;
+
+ entry_p = va_db_lookup(bucket_index, key);
+
+ if (PREDICT_FALSE(entry_p)) {
+ FRAG_DEBUG_PRINTF6(
+ "\nVA_ADD_NEW: Bucket %d fnd Existng entry [%d, %d] -> [%d, %d]\n",
+ bucket_index, entry_p->src_port,
+ entry_p->dst_port, key->e.src_port, key->e.dst_port)
+
+ /* found match entry, update it */
+ entry_p->src_port = key->e.src_port;
+ entry_p->dst_port = key->e.dst_port;
+
+ FRAG_DEBUG_PRINTF3("VA_ADD_NEW: Existing bucket %d, counter %d\n",
+ bucket_index,
+ va_bucket[bucket_index].new_entry_counter)
+
+ } else {
+
+ /* no match, add a new one */
+ head = va_bucket[bucket_index].head_entry;
+ next = va_bucket[bucket_index].next_available_entry;
+
+ FRAG_DEBUG_PRINTF5(
+ "\nVA_ADD_NEW: Filling bucket %d, index %d with key 0x%llx %x\n",
+ bucket_index, next, key->k.key64, key->k.key32)
+
+ va_bucket[bucket_index].va_entry[next] = key->e;
+
+ /* increase next pointer */
+ va_bucket[bucket_index].next_available_entry = (next+1) & VA_BUCKET_MASK;
+
+ if (PREDICT_FALSE(head == va_bucket[bucket_index].next_available_entry)) {
+ /* adjust head circular pointer */
+ va_bucket[bucket_index].head_entry = (head+1) & VA_BUCKET_MASK;
+ }
+
+ va_bucket[bucket_index].new_entry_counter++;
+
+ FRAG_DEBUG_PRINTF4(
+ "VA_ADD_NEW: NEW bucket %d, entry %d counter %d\n",
+ bucket_index, next, va_bucket[bucket_index].new_entry_counter)
+ }
+}
+
+
+/*
+ * use the key,
+ * return pointer to the entry if found,
+ * NULL if not
+ */
+
+inline
+va_entry_t * va_db_lookup (u32 bucket_index, va_lookup_key * key)
+{
+
+ u32 index, next;
+ va_entry_t * entry_p;
+ va_bucket_t * bucket;
+
+ bucket = &va_bucket[bucket_index];
+ index = bucket->head_entry;
+ next = bucket->next_available_entry;
+ entry_p = NULL;
+
+ FRAG_DEBUG_PRINTF4(
+ "\nVA_DB_LOOKUP: bucket index %d head %d next %d\n",
+ bucket_index, index, next)
+
+ /* loop through the entries in the bucket */
+ while( index != next) {
+
+ if(PREDICT_TRUE(memcmp(&bucket->va_entry[index], key, VA_KEY_SIZE)==0)) {
+
+ entry_p = &bucket->va_entry[index];
+ /*In add frag entry function we are again assigning key's src
+ port to entry_p's src port. So when a main DB entry is deleted/
+ timed out, and again another entry is created for the same
+ src ip and src port pair, the frag's entry_p will have the
+ previous port info stored and not updated. Hence the below
+ line is not required*/
+
+ /* *(u32*)&key->e.src_port = *(u32*)&entry_p->src_port; */
+ /* do two ports as u32 :) */
+
+ break;
+ }
+
+ index = (index +1) & VA_BUCKET_MASK;
+
+ }
+
+#ifdef FRAG_DEBUG
+ if (PREDICT_TRUE(entry_p)) {
+ FRAG_DEBUG_PRINTF3("VA_DB_LOOKUP: bucket index %d entry index %d\n",
+ bucket_index, index)
+ FRAG_DEBUG_PRINTF5("VA_DB_LOOKUP: SRC-->DST [0x%x, %d] [0x%x, %d]\n",
+ entry_p->src_ip, entry_p->src_port,
+ entry_p->dst_ip, entry_p->dst_port)
+ FRAG_DEBUG_PRINTF3("[vrf 0x%x, id 0x%x]\n",
+ entry_p->vrf, entry_p->ip_id)
+ } else {
+ FRAG_DEBUG_PRINTF1("\nNULL ENTRY\n")
+ }
+#endif
+
+ return entry_p;
+
+}
+
+inline
+int va_db_delete_entry (u32 bucket_index, va_lookup_key * key)
+{
+
+ u32 index, next;
+ int entry_found = 0;
+ va_bucket_t * bucket;
+
+ bucket = &va_bucket[bucket_index];
+ index = bucket->head_entry;
+ next = bucket->next_available_entry;
+
+ FRAG_DEBUG_PRINTF4(
+ "\nVA_DB_DELETE_ENTRY: bucket index %d head %d next %d\n",
+ bucket_index, index, next);
+
+ /* loop through the entries in the bucket */
+ while( index != next) {
+ if(PREDICT_TRUE(memcmp(&bucket->va_entry[index], key,
+ VA_KEY_SIZE)==0)) {
+ /* Clear the entry */
+ FRAG_DEBUG_PRINTF1("Entry found in delete API");
+ memset(&bucket->va_entry[index], 0, sizeof(va_entry_t));
+ entry_found = 1;
+ break;
+ }
+ index = (index +1) & VA_BUCKET_MASK;
+ }
+ return entry_found;
+}
+
+
+
+void cnat_va_bucket_used (int argc, unsigned long * argv)
+{
+
+ u32 i, sum = 0;;
+
+ for(i=0;i<VA_BUCKETS;i++) {
+
+ if(PREDICT_TRUE(va_bucket[i].new_entry_counter)) sum++;
+
+ }
+
+ if (PREDICT_FALSE(!sum)) {
+ printf("no bucket in use\n");
+ return;
+ }
+
+ printf("index head next counter (%d bucket in use)\n", sum);
+
+ for(i=0;i<VA_BUCKETS;i++) {
+
+ if (PREDICT_FALSE(!va_bucket[i].new_entry_counter)) continue;
+
+ printf(" %04d %04d %04d %d\n", i,
+ va_bucket[i].head_entry,
+ va_bucket[i].next_available_entry,
+ va_bucket[i].new_entry_counter);
+
+ }
+}
+
+void cnat_va_dump (int argc, unsigned long * argv)
+{
+
+ u32 i, sum, index ;
+
+ PLATFORM_DEBUG_PRINT("====== SUMMARY ======\n");
+ PLATFORM_DEBUG_PRINT("Total buckets: %d\n", VA_BUCKETS);
+ PLATFORM_DEBUG_PRINT("Entries per bucket: %d\n", VA_ENTRY_PER_BUCKET);
+
+ sum = 0;
+
+ for(i=0; i<VA_BUCKETS; i++) {
+ if (PREDICT_TRUE(va_bucket[i].new_entry_counter > 0)) sum ++;
+ }
+
+ PLATFORM_DEBUG_PRINT("buckets in use: %d\n", sum);
+
+ sum = 0;
+ for(i=0; i<VA_BUCKETS; i++) {
+
+ if ( PREDICT_FALSE(((va_bucket[i].next_available_entry+1) & VA_BUCKET_MASK)
+ == va_bucket[i].head_entry)) {
+
+ sum ++;
+ }
+ }
+
+ PLATFORM_DEBUG_PRINT("bucket full: %d\n", sum);
+
+ /* dump per bucket info */
+
+ if (argc == 0 ) return;
+
+ index = (u32) argv[0];
+
+ if (PREDICT_FALSE(index >= VA_BUCKETS)) {
+ PLATFORM_DEBUG_PRINT("invalid bucket index %d\n", index);
+ return;
+ }
+
+ PLATFORM_DEBUG_PRINT("\n====== Bucket %d ======\n", index);
+
+ PLATFORM_DEBUG_PRINT("bucket head index %d\n", va_bucket[index].head_entry);
+
+ PLATFORM_DEBUG_PRINT("bucket next index %d\n", va_bucket[index].next_available_entry);
+
+ PLATFORM_DEBUG_PRINT(" source IP dest IP VRF ip-id srcP dstP\n");
+
+ for(i=0;i<VA_ENTRY_PER_BUCKET;i++) {
+ hex_dump((u8*)&va_bucket[index].va_entry[i], sizeof(va_entry_t));
+ }
+
+}
diff --git a/vpp/plugins/vcgn-plugin/vcgn/cnat_va_db.h b/vpp/plugins/vcgn-plugin/vcgn/cnat_va_db.h
new file mode 100644
index 00000000..6e0051b4
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/cnat_va_db.h
@@ -0,0 +1,121 @@
+/*
+ *------------------------------------------------------------------
+ * cnat_va_db.h - definition for virtual assembly database
+ *
+ * Copyright (c) 2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __CNAT_VA_DB_H__
+#define __CNAT_VA_DB_H__
+
+#include <clib_lite.h>
+
+#define FRAG_DEBUG 1
+
+/* virtual assemble hash database size ~ 16B x 64K = 1MB */
+
+#define VA_TOTAL_ENTRIES (64*1024)
+#define VA_ENTRY_PER_BUCKET (8) /* make sure size is power of 2 for circular FIFO */
+#define VA_BUCKET_MASK (VA_ENTRY_PER_BUCKET -1)
+#define VA_BUCKETS (VA_TOTAL_ENTRIES / VA_ENTRY_PER_BUCKET)
+#define VA_KEY_SIZE 12
+
+typedef struct _va_entry {
+ /* key: top 12 bytes */
+ u32 src_ip;
+ u32 dst_ip;
+ u16 vrf; /* overloaded with protocol info with top two bits */
+ u16 ip_id;
+
+ /* values */
+ u16 src_port;
+ u16 dst_port;
+} va_entry_t;
+
+typedef struct _va_keys {
+ u64 key64; /* src & dst IP */
+ u32 key32; /* vrf, protocol and ip_id */
+} va_keys;
+
+typedef union {
+ va_entry_t e;
+ va_keys k;
+} va_lookup_key;
+
+typedef struct _va_bucket_t {
+ u32 head_entry;
+ u32 next_available_entry; /* ~0 for empty bucket */
+ u32 new_entry_counter; /* for debug purpose */
+ va_entry_t va_entry[VA_ENTRY_PER_BUCKET];
+} va_bucket_t;
+
+extern va_bucket_t va_bucket[]; /* hash table in cnat_va_db.c */
+
+void va_bucket_init ();
+
+inline void va_db_add_new_entry (u32 bucket_index, va_lookup_key * );
+inline int va_db_delete_entry (u32 bucket_index, va_lookup_key * );
+inline va_entry_t * va_db_lookup (u32 bucket_index, va_lookup_key * key);
+
+#ifdef FRAG_DEBUG
+
+#define FRAG_DEBUG_PRINTF1(a) \
+ if (frag_debug_flag) { \
+ PLATFORM_DEBUG_PRINT(a); \
+ }
+
+#define FRAG_DEBUG_PRINTF2(a, b) \
+ if (frag_debug_flag) { \
+ PLATFORM_DEBUG_PRINT(a, b); \
+ }
+
+#define FRAG_DEBUG_PRINTF3(a, b, c) \
+ if (frag_debug_flag) { \
+ PLATFORM_DEBUG_PRINT(a, b, c); \
+ }
+
+#define FRAG_DEBUG_PRINTF4(a, b, c, d) \
+ if (frag_debug_flag) { \
+ PLATFORM_DEBUG_PRINT(a, b, c, d); \
+ }
+
+#define FRAG_DEBUG_PRINTF5(a, b, c, d, e) \
+ if (frag_debug_flag) { \
+ PLATFORM_DEBUG_PRINT(a, b, c, d, e); \
+ }
+
+#define FRAG_DEBUG_PRINTF6(a, b, c, d, e, f) \
+ if (frag_debug_flag) { \
+ PLATFORM_DEBUG_PRINT(a, b, c, d, e, f); \
+ }
+#else
+
+#define FRAG_DEBUG_PRINTF1(a)
+
+#define FRAG_DEBUG_PRINTF2(a, b)
+
+#define FRAG_DEBUG_PRINTF3(a, b, c)
+
+#define FRAG_DEBUG_PRINTF4(a, b, c, d)
+
+#define FRAG_DEBUG_PRINTF5(a, b, c, d, e)
+
+#define FRAG_DEBUG_PRINTF6(a, b, c, d, e, f)
+
+#endif
+
+#endif /* __CNAT_VA_DB_H__ */
+
+
diff --git a/vpp/plugins/vcgn-plugin/vcgn/dslite_db.h b/vpp/plugins/vcgn-plugin/vcgn/dslite_db.h
new file mode 100644
index 00000000..2269b98c
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/dslite_db.h
@@ -0,0 +1,170 @@
+/*
+ *------------------------------------------------------------------
+ * dslite_db.h - Stateful DSLITE translation database definitions
+ *
+ * Copyright (c) 2010-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+#ifndef __DSLITE_DB_H__
+#define __DSLITE_DB_H__
+
+#include "cnat_cli.h"
+#include "index_list.h"
+#include "cnat_ports.h"
+#include "cnat_db.h"
+#include "dslite_defs.h"
+
+#define DSLITE_PRINTF(level, ...) \
+ if (dslite_debug_level > level) PLATFORM_DEBUG_PRINT(__VA_ARGS__);
+/*
+#define DSLITE_PRINTF(lvl, ...) \
+{ \
+ avsm_dispatlib_debug (__VA_ARGS__); \
+}
+*/
+
+#define HASH_ENHANCE 4
+//#define DSLITE_DEF
+#define DSLITE_MAIN_DB_SIZE (20000000 / PLATFORM_CNAT_INSTS)
+#define DSLITE_MAIN_HASH_SIZE \
+ (HASH_ENHANCE * PLATFORM_CNAT_MAIN_PRELIM_HASH_SIZE)
+
+#define DSLITE_MAIN_HASH_MASK (DSLITE_MAIN_HASH_SIZE-1)
+
+
+/* nb: 200000 users / 64 CNAT = 3125, 76% occupancy */
+#define DSLITE_USER_HASH_SIZE CNAT_USER_HASH_SIZE
+#define DSLITE_USER_HASH_MASK (DSLITE_USER_HASH_SIZE-1)
+
+/* No. of per ip/port config will be limited to 1000 */
+#define DSLITE_TIMEOUT_HASH_SIZE 1000
+#define DSLITE_TIMEOUT_HASH_MASK (DSLITE_TIMEOUT_HASH_SIZE - 1)
+#define DSLITE_TIMEOUT_FULL_MASK 0xFFFFFFFFFFFFFFFF
+
+#define CNAT_MAX_SESSIONS_PER_BIB 0xFFFF
+
+#define FORCE_DEL 1 /* Delete static BIB entries as well */
+
+/* default timeout values */
+#define DSLITE_UDP_DEFAULT 300 /* 5 min */
+#define DSLITE_UDP_MIN 120 /* 2 min */
+#define DSLITE_TCP_TRANS 240 /* 4 min */
+#define DSLITE_TCP_EST 7200 /* 2 hrs */
+#define DSLITE_TCP_V4_SYN 6 /* 6 sec */
+#define DSLITE_FRAG_MIN 2 /* 2 sec */
+#define DSLITE_ICMP_DEFAULT 60 /* 1 min */
+
+extern u32 dslite_translation_create_count;
+extern u32 dslite_translation_delete_count;
+extern u32 dslite_translation_create_rate;
+extern u32 dslite_translation_delete_rate;
+extern u32 dslite_in2out_forwarding_count;
+extern u32 dslite_in2out_forwarding_rate;
+extern u32 dslite_out2in_forwarding_count;
+extern u32 dslite_out2in_forwarding_rate;
+
+#define DSLITE_V6_GET_HASH(in_key, hash, mask) \
+ a = in_key->ipv6[0] ^ in_key->ipv6[1] ^ in_key->ipv6[2] ^ in_key->ipv6[3] \
+ ^ in_key->ipv4_key.k.ipv4 ^ ((in_key->ipv4_key.k.port << 16) | in_key->ipv4_key.k.vrf); \
+ DSLITE_PRINTF(1, "%x:%x:%x:%x:%x:%x:%x\n", in_key->ipv6[0], in_key->ipv6[1], in_key->ipv6[2], in_key->ipv6[3], \
+ in_key->ipv4_key.k.ipv4, in_key->ipv4_key.k.port, in_key->ipv4_key.k.vrf); \
+ b = c = 0x9e3779b9;\
+ /* Jenkins hash, arbitrarily use c as the "answer" */ \
+ hash_mix32(a, b, c); \
+ hash = c & mask; \
+
+
+#define DSLITE_V6_GET_USER_HASH(ipv6, hash, mask) \
+ a = ipv6[0] ^ ipv6[1] ^ ipv6[2] ^ ipv6[3]; \
+ b = c = 0x9e3779b9;\
+ /* Jenkins hash, arbitrarily use c as the "answer" */ \
+ hash_mix32(a, b, c); \
+ hash = c & mask; \
+
+#define DSLITE_V4_GET_HASH(in_key, hash, mask) \
+ a = in_key.ipv4 ^ ((in_key.port << 16) | in_key.vrf); \
+ b = c = 0x9e3779b9; \
+ /* Jenkins hash, arbitrarily use c as the "answer" */ \
+ hash_mix32(a, b, c); \
+ hash = c & mask;
+
+#define PRIVATE_V4_ADDR_CHECK(addr, invalid) \
+ invalid = 0; \
+ int range1 = ((addr & 0xFF000000) >> 24); \
+ int range2 = ((addr & 0xFFF00000) >> 20); \
+ int range3 = ((addr & 0xFFFF0000) >> 16); \
+ int range4 = ((addr & 0xFFFFFFF8) >> 3); \
+ if(range1 != 0xa && range2 != 0xac1 && range3 != 0xc0a8 && range4 != 0x18000000) \
+ invalid = 1;
+
+#define V4_MAPPED_V6_CHECK(v6_addr, invalid) \
+ invalid = 0; \
+ int word1 = v6_addr[0]; \
+ int word2 = v6_addr[1]; \
+ int word3 = v6_addr[2]; \
+ if(!((word1 == 0) && (word2 == 0) && (word3 == 0x0000FFFF))) \
+ invalid = 1;
+
+
+extern dslite_table_entry_t dslite_table_array[DSLITE_MAX_DSLITE_ENTRIES];
+extern dslite_table_entry_t *dslite_table_ptr;
+
+#define DSLITE_CMP_V6_KEY(key1, key2) \
+ memcmp(key1, key2, sizeof(dslite_v6_key_t))
+
+#define DSLITE_CMP_V4_KEY(key1, key2) \
+ memcmp(key1, key2, sizeof(dslite_v4_key_t))
+
+
+#define DSLITE_CMP_V6_IP(ip1, ip2) \
+ memcmp(ip1, ip2, (sizeof(u32) * 4))
+
+
+#define DSLITE_CMP_V6_KEY1(key1, key2) \
+ (key1.ipv6[0] == key2.ipv6[0]) && (key1.ipv6[1] == key2.ipv6[1]) && \
+ (key1.ipv6[2] == key2.ipv6[2]) && (key1.ipv6[3] == key2.ipv6[3]) && \
+ (key1.port == key2.port) && (key1.vrf == key2.vrf)
+
+
+#define DSLITE_CMP_V6_IP1(ip1, ip2) \
+ ((ip1[0] == ip2[0]) && (ip1[1] == ip2[1]) && \
+ (ip1[2] == ip2[2]) && (ip1[3] == ip2[3]))
+
+#define DSLITE_CMP_V4_KEY1(key1, key2) \
+ (key1.key64 == key2.key64)
+
+cnat_main_db_entry_t*
+dslite_get_main_db_entry_v2(dslite_db_key_bucket_t *ki,
+ port_pair_t port_pair_type,
+ port_type_t port_type,
+ cnat_gen_icmp_info *info,
+ dslite_table_entry_t *dslite_entry_ptr,
+ cnat_key_t *dest_info);
+
+cnat_main_db_entry_t*
+dslite_main_db_lookup_entry(dslite_db_key_bucket_t *ki);
+
+
+cnat_user_db_entry_t*
+dslite_user_db_lookup_entry(dslite_db_key_bucket_t *uki);
+
+cnat_user_db_entry_t*
+dslite_user_db_create_entry(dslite_db_key_bucket_t *uki, u32 portmap_index);
+
+cnat_main_db_entry_t*
+dslite_create_main_db_entry_and_hash(dslite_db_key_bucket_t *ki,
+ cnat_db_key_bucket_t *ko,
+ cnat_user_db_entry_t *udb);
+
+#endif
diff --git a/vpp/plugins/vcgn-plugin/vcgn/dslite_defs.h b/vpp/plugins/vcgn-plugin/vcgn/dslite_defs.h
new file mode 100644
index 00000000..4860adcb
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/dslite_defs.h
@@ -0,0 +1,336 @@
+/*
+ *------------------------------------------------------------------
+ * dslite_defs.h - DSLITE structure definiitions
+ *
+ * Copyright (c) 2011-2012 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __DSLITE_DEFS_H__
+#define __DSLITE_DEFS_H__
+
+#ifdef TOBE_PORTED
+#include "spp_platform_common.h"
+#include "cgse_defs.h"
+#endif
+#include "cnat_cli.h"
+#include "cnat_config.h"
+#include "cnat_ports.h"
+#include "cnat_bulk_port_defs.h"
+
+extern u32 ds_lite_config_debug_level;
+
+#define SWAP_IPV6_ADDR(ipv6_hdr, dslite_entry_ptr) \
+ ipv6_hdr->dst_addr[0] = ipv6_hdr->src_addr[0]; \
+ ipv6_hdr->dst_addr[1] = ipv6_hdr->src_addr[1]; \
+ ipv6_hdr->dst_addr[2] = ipv6_hdr->src_addr[2]; \
+ ipv6_hdr->dst_addr[3] = ipv6_hdr->src_addr[3]; \
+ ipv6_hdr->src_addr[0] = spp_host_to_net_byte_order_32(dslite_entry_ptr->AFTR_v6_address[0]); \
+ ipv6_hdr->src_addr[1] = spp_host_to_net_byte_order_32(dslite_entry_ptr->AFTR_v6_address[1]); \
+ ipv6_hdr->src_addr[2] = spp_host_to_net_byte_order_32(dslite_entry_ptr->AFTR_v6_address[2]); \
+ ipv6_hdr->src_addr[3] = spp_host_to_net_byte_order_32(dslite_entry_ptr->AFTR_v6_address[3]);
+
+#define DSLITE_SET_TX_PKT_TYPE(type) { \
+ ctx->ru.tx.packet_type = type; \
+}
+
+#define DSLITE_INC_STATS_V4(PTR, COUNTER, IPV4_SRC_ADDR) { \
+ PTR->COUNTER++; \
+}
+
+#define DSLITE_INC_STATS_V6(PTR, COUNTER, IPV6_DEST_ADDR) { \
+ PTR->COUNTER++; \
+}
+
+
+#define DSLITE_INVALID_UIDX 0xffff /*invalid svi app uidb index */
+#define DSLITE_INVALID_VRFID 0xffffffff /*invalid vrf id */
+
+#define DSLITE_VRF_MASK 0x3fff
+#define DSLITE_MAX_VRFMAP_ENTRIES (DSLITE_VRF_MASK + 1)
+
+#define DSLITE_VRFMAP_ENTRY_INVALID 0xffff
+
+#define DSLITE_V6_PREFIX_MASK_MIN 16
+#define DSLITE_V6_PREFIX_MASK_MAX 96
+#define DSLITE_V6_PREFIX_MASK_MULTIPLE 8
+
+#define DSLITE_TUNNEL_MTU_MIN 1280
+#define DSLITE_TUNNEL_MTU_MAX 9216
+
+#define DSLITE_TUNNEL_TTL_MIN 0
+#define DSLITE_TUNNEL_TTL_MAX 255
+
+#define DSLITE_TUNNEL_TOS_MIN 0
+#define DSLITE_TUNNEL_TOS_MAX 255
+
+#define DSLITE_V4_MASK_MAX 32
+
+//#define XLAT_MAX_FRAG_ID_COUNTERS (256)
+#define DSLITE_AFTR_IPV4_ADDR 0xC0000001
+
+#define DSLITE_MAX_TAP_RG_ENTRIES 2
+#define DSLITE_MAX_DSLITE_ENTRIES (256)
+#define DSLITE_MAX_DSLITE_ID (DSLITE_MAX_DSLITE_ENTRIES-1)
+/* Define the below value as 64 if first 64 entries are for NAT44 */
+#define DSLITE_INDEX_OFFSET 1
+
+#define DSLITE_INVALID_DSLITE_ID (0)
+
+#define DSLITE_TABLE_ENTRY_DELETED 0
+#define DSLITE_TABLE_ENTRY_ACTIVE 1
+#define DSLITE_TABLE_ENTRY_DORMANT 2
+#define DSLITE_TABLE_ENTRY_INVALID_UIDB 3
+
+typedef struct {
+ u16 tcp_initial_setup_timeout;
+ u16 tcp_active_timeout;
+ u16 udp_init_session_timeout;
+ u16 udp_act_session_timeout;
+ u16 icmp_session_timeout;
+ u16 temp;
+} dslite_timeout_info_t;
+
+
+typedef struct {
+
+ u16 state; /* To use nat44 enums ?? TBD */
+ u16 dslite_id; /* DSLITE_ID value for this table entry - for easy access */
+
+ u16 i_vrf; /* V6 uidb index */
+ u16 o_vrf; /* V4 uidb index */
+
+ u16 cnat_main_db_max_ports_per_user; /* port limit */
+ u16 tcp_mss; /*tcp max segment size for this inside vrf */
+
+ u32 delete_time;
+
+ cnat_portmap_v2_t *portmap_list;
+
+ u32 nfv9_logging_index;
+ u32 syslog_logging_index;
+ u32 AFTR_v6_address[4];
+
+#define DSLITE_IPV4_TOS_OVERRIDE_FLAG 0x00000001
+#define DSLITE_IPV6_TOS_OVERRIDE_FLAG 0x00000002
+#define DSLITE_IPV4_TTL_OVERRIDE_FLAG 0x00000004
+#define DSLITE_IPV6_TTL_OVERRIDE_FLAG 0x00000008
+#define DSLITE_IPV6_FRAG_REASSEMB_ENG 0x00000010
+#define DSLITE_FTP_ALG_ENABLE 0x00000020
+#define DSLITE_RTSP_ALG_ENABLE 0x00000040
+#define DSLITE_NETFLOW_ENABLE 0x00000080
+#define DSLITE_SYSLOG_ENABLE 0x00000100
+
+ u16 feature_flags;
+ u16 tunnel_mtu;
+
+ u8 ipv4_ttl_value;
+ u8 ipv6_ttl_value;
+ u8 ipv4_tos_value;
+ u8 ipv6_tos_value;
+
+ u32 v4_if_num; /* V4 SVI ifnum */
+ u32 v6_if_num; /* V6 SVI ifnum */
+ u32 i_vrf_id; //inside vrf id
+ u32 o_vrf_id; //outside vrf id
+
+ dslite_timeout_info_t timeout_info;
+ u16 cnat_static_port_range;
+ u16 dyn_start_port;
+
+ u32 AFTR_v4_addr;
+ bulk_alloc_size_t bulk_size; /* should be equivalent to u16 - 2 bytes */
+ u32 pcp_server_addr;
+ u16 pcp_server_port;
+ u8 mapping_refresh_both_direction;
+ u8 pad;
+ u16 rtsp_port;
+#define DSLITE_BIDIR_REFRESH 1
+ u8 dslite_enable; /* DS-Lite enable check flag */
+ u8 syslog_logging_policy; /* DS-Lite Session Logging check flag */
+ u8 nf_logging_policy;
+
+ u8 temp1;
+ u16 temp2;
+ u32 temp3;
+ u32 rseed_ip;
+} dslite_table_entry_t;
+
+typedef struct {
+ u64 v4_to_v6_invalid_uidb_drop_count;
+ u64 v6_to_v4_invalid_uidb_drop_count;
+ u64 v4_to_v6_frag_invalid_uidb_drop_count;
+} dslite_global_counters_t;
+
+typedef struct {
+ u32 tap_enable;
+ u32 ipv4_addr;
+ u32 ipv6_addr[4];
+} dslite_tap_rg_t;
+
+extern dslite_table_entry_t *dslite_table_db_ptr;
+
+
+#define DSLITE_ADD_UIDB_INDEX_DSLITE_ID_MAPPING(uidb_index, dslite_id) \
+ *(cgse_uidb_index_cgse_id_mapping_ptr + uidb_index) = dslite_id;
+
+extern u8 my_instance_number;
+
+extern void dslite_clear_counters(u16 dslite_id);
+extern void dslite_clear_per_RG_counters();
+extern dslite_global_counters_t dslite_global_counters;
+extern u32 dslite_config_debug_level;
+extern u32 dslite_data_path_debug_level;
+extern u32 dslite_defrag_debug_level;
+extern u32 dslite_debug_level;
+
+typedef struct {
+ u64 v6_to_v4_tcp_input_count;
+ u64 v6_to_v4_tcp_nat_error;
+ u64 v6_to_v4_tcp_output_count;
+} dslite_v6_to_v4_tcp_counter_t;
+
+typedef struct {
+ u64 v4_to_v6_tcp_input_count;
+ u64 v4_to_v6_tcp_no_entry;
+ u64 v4_to_v6_tcp_output_count;
+} dslite_v4_to_v6_tcp_counter_t;
+
+typedef struct {
+ u64 v6_to_v4_udp_input_count;
+ u64 v6_to_v4_udp_nat_error;
+ u64 v6_to_v4_udp_output_count;
+} dslite_v6_to_v4_udp_counter_t;
+
+typedef struct {
+ u64 v4_to_v6_udp_input_count;
+ u64 v4_to_v6_udp_no_entry;
+ u64 v4_to_v6_udp_output_count;
+} dslite_v4_to_v6_udp_counter_t;
+
+typedef struct {
+ u64 v6_to_v4_icmp_qry_input_count;
+ u64 v6_to_v4_icmp_qry_nat_error;
+ u64 v6_to_v4_icmp_qry_output_count;
+} dslite_v6_to_v4_icmp_qry_counter_t;
+
+typedef struct {
+ u64 v4_to_v6_icmp_qry_input_count;
+ u64 v4_to_v6_icmp_qry_no_nat_entry;
+ u64 v4_to_v6_icmp_qry_output_count;
+} dslite_v4_to_v6_icmp_qry_counter_t;
+
+typedef struct {
+ u64 v6_to_v4_icmp_error_input_count;
+ u64 v6_to_v4_icmp_error_nat_error;
+ u64 v6_to_v4_icmp_error_output_count;
+} dslite_v6_to_v4_icmp_error_counter_t;
+
+typedef struct {
+ u64 v4_to_v6_icmp_error_input_count;
+ u64 v4_to_v6_icmp_error_no_nat_entry;
+ u64 v4_to_v6_icmp_error_output_count;
+} dslite_v4_to_v6_icmp_error_counter_t;
+
+typedef struct {
+ u64 v6_icmp_error_input_count;
+ u64 v6_AFTR_echo_reply_count;
+ u64 v6_to_v4_icmp_error_unsupported_type_drop_count;
+ u64 v6_to_v4_icmp_error_no_db_entry_count;
+ u64 v6_to_v4_icmp_err_throttled_count;
+ u64 v6_to_v4_icmp_error_xlated_count;
+} dslite_v6_icmp_error_counter_t;
+
+typedef struct {
+ u64 v4_to_v6_ttl_gen_count;
+ u64 v4_to_v6_icmp_throttle_count;
+ u64 v4_to_v6_ptb_gen_count;
+ u64 v4_to_v6_aftr_v4_echo_reply_count;
+ u64 v6_to_v4_ttl_gen_count;
+ u64 v6_to_v4_icmp_throttle_count;
+ u64 v6_to_v4_admin_prohib_icmp_count;
+ u64 v6_to_v4_aftr_v4_echo_reply_count;
+ u64 v6_icmp_gen_count;
+} dslite_icmp_gen_counter_t;
+
+typedef struct {
+ u64 dslite_input_tunnel_pkt;
+ u64 dslite_encap_count;
+ u64 dslite_decap_count;
+ u64 dslite_sec_check_failed;
+ u64 dslite_unsupp_packet;
+} dslite_common_counter_t;
+
+typedef struct {
+
+ dslite_v6_to_v4_tcp_counter_t v64_tcp_counters;
+ dslite_v4_to_v6_tcp_counter_t v46_tcp_counters;
+ dslite_v6_to_v4_udp_counter_t v64_udp_counters;
+ dslite_v4_to_v6_udp_counter_t v46_udp_counters;
+ dslite_v6_to_v4_icmp_qry_counter_t v64_icmp_counters;
+ dslite_v4_to_v6_icmp_qry_counter_t v46_icmp_counters;
+ dslite_v6_to_v4_icmp_error_counter_t v64_icmp_error_counters;
+ dslite_v4_to_v6_icmp_error_counter_t v46_icmp_error_counters;
+ dslite_v6_icmp_error_counter_t dslite_v6_icmp_err_counters;
+ dslite_icmp_gen_counter_t dslite_icmp_gen_counters;
+ dslite_common_counter_t dslite_common_counters;
+} dslite_counters_t;
+
+typedef struct {
+ u32 active_translations;
+ u32 translation_create_rate;
+ u32 translation_delete_rate;
+ u32 in2out_forwarding_rate;
+ u32 out2in_forwarding_rate;
+ u32 in2out_drops_port_limit_exceeded;
+ u32 in2out_drops_system_limit_reached;
+ u32 in2out_drops_resource_depletion;
+ u32 no_translation_entry_drops;
+ u32 pool_address_totally_free;
+ u32 num_subscribers;
+ u32 dummy;
+ u64 drops_sessiondb_limit_exceeded;
+} dslite_common_stats_t;
+
+typedef struct {
+ u16 msg_id;
+ u8 rc;
+ u8 pad[5];
+ dslite_counters_t counters;
+} dslite_show_statistics_summary_resp;
+
+
+#define CMD_GENERATE_PTB 0x1
+#define CMD_GENERATE_TTL 0x2
+
+/*
+ * This structure is to provide abstraction for data exchanged from one
+ * VPP node to its disposition or further in the dslite node graph.
+ */
+typedef struct {
+ u32 icmp_gen_type; // ctx->feature_data[0]
+ u32 reserved1; // ctx->feature_data[1]
+ u32 reserved2; // ctx->feature_data[2]
+ u32 reserved3; // ctx->feature_data[3]
+} dslite_feature_data_t;
+
+extern dslite_counters_t dslite_all_counters[DSLITE_MAX_DSLITE_ENTRIES];
+//extern dslite_inst_gen_counter_t dslite_inst_gen_counters[DSLITE_MAX_DSLITE_ENTRIES];
+
+
+ extern void dslite_show_config(void);
+#define STAT_PORT_RANGE_FROM_INST_PTR(inst) ((inst)->cnat_static_port_range)
+
+#endif /* __DSLITE_DEFS_H__ */
+
diff --git a/vpp/plugins/vcgn-plugin/vcgn/index_list.c b/vpp/plugins/vcgn-plugin/vcgn/index_list.c
new file mode 100644
index 00000000..ec1b83b0
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/index_list.c
@@ -0,0 +1,336 @@
+/*
+ *------------------------------------------------------------------
+ * index_list.c - vector-index-based lists. 64-bit pointers suck.
+ *
+ * Copyright (c) 2008-2009, 2011 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <string.h>
+//#include <clib_lite.h>
+#include <vppinfra/vec.h>
+#include "index_list.h"
+
+/*
+ * index_slist_addhead
+ *
+ * args: headp -- pointer to e.g. a hash bucket
+ * vector -- vector containing the list
+ * elsize -- size of an element in this vector
+ * offset -- offset in each vector element of this list thread
+ * index_to_add -- index in the vector to add to the list
+ *
+ * Adds new items to the head of the list. Try not to screw up the args!
+ */
+void index_slist_addhead (index_slist_t *headp,
+ u8 *vector, u32 elsize, u32 offset, u32 index_to_add)
+{
+ return (index_slist_addhead_inline(headp, vector, elsize, offset,
+ index_to_add));
+}
+
+/*
+ * index_slist_remelem
+ *
+ * args: headp -- pointer to e.g. a hash bucket
+ * vector -- vector containing the list
+ * elsize -- size of an element in this vector
+ * offset -- offset in each vector element of this list thread
+ * index_to_del -- index in the vector to delete from the list
+ *
+ * Try not to screw up the args!
+ */
+
+int index_slist_remelem (index_slist_t *headp,
+ u8 *vector, u32 elsize, u32 offset,
+ u32 index_to_delete)
+{
+ return (index_slist_remelem_inline(headp, vector, elsize, offset,
+ index_to_delete));
+}
+
+
+/*
+ * index_dlist_addtail
+ *
+ * Append the indicated vector element to the doubly-linked list
+ * whose first element is pointed to by headp.
+ *
+ * args: head_index -- listhead vector element index.
+ * vector -- vector containing the list
+ * elsize -- size of an element in this vector
+ * offset -- offset in each vector element of this list thread
+ * index_to_add -- index in the vector to add to the list
+ *
+ * Do not call this routine to create the listhead. Simply set
+ * index_dlist->next = index_dlist->prev = index of item.
+ *
+ * Try not to screw up the args.
+ */
+
+void index_dlist_addtail (u32 head_index, u8 *vector, u32 elsize,
+ u32 offset, u32 index_to_add)
+{
+ index_dlist_t *elp;
+ index_dlist_t *elp_next;
+ index_dlist_t *headp;
+
+ headp = (index_dlist_t *)(vector + offset + elsize*head_index);
+ elp = (index_dlist_t *)(vector + offset + elsize*index_to_add);
+ elp->next = index_to_add;
+ elp->prev = index_to_add;
+
+ elp->next = headp->next;
+ headp->next = index_to_add;
+
+ elp_next = (index_dlist_t *)(vector + offset + elsize*elp->next);
+ elp->prev = elp_next->prev;
+ elp_next->prev = index_to_add;
+}
+
+u32 index_dlist_remelem (u32 head_index,
+ u8 *vector, u32 elsize, u32 offset,
+ u32 index_to_delete)
+{
+ u32 rv = head_index;
+ index_dlist_t *headp, *elp, *elp_next;
+
+ elp = (index_dlist_t *)(vector + offset + elsize*index_to_delete);
+
+ /* Deleting the head index? */
+ if (PREDICT_FALSE(head_index == index_to_delete)) {
+ rv = elp->next;
+ /* The only element on the list? */
+ if (PREDICT_FALSE(rv == head_index))
+ rv = EMPTY;
+ }
+
+ headp = (index_dlist_t *)(vector + offset + elsize*elp->prev);
+ headp->next = elp->next;
+ elp_next = (index_dlist_t *)(vector + offset + elsize*elp->next);
+ elp_next->prev = elp->prev;
+
+ elp->next = elp->prev = EMPTY;
+
+ return rv;
+}
+
+
+#ifdef TEST_CODE2
+
+typedef struct tv_ {
+ char junk[43];
+ index_dlist_t l;
+} tv_t;
+
+
+void index_list_test_cmd(int argc, unsigned long *argv)
+{
+ int i, j;
+ u32 head_index;
+ index_dlist_t *headp;
+ tv_t *tp=0;
+
+ vec_validate(tp, 3);
+ head_index = 3;
+
+ memset(tp, 0xa, sizeof(tp[0])*vec_len(tp));
+
+ /* Here's how to set up the head element... */
+ headp = &((tp + head_index)->l);
+ headp->next = headp->prev = head_index;
+
+ for (i = 0; i < 3; i++) {
+ index_dlist_addtail(head_index, (u8 *)tp, sizeof(tp[0]),
+ STRUCT_OFFSET_OF(tv_t, l), i);
+ printf("headp next %d prev %d\n",
+ headp->next, headp->prev);
+ for (j = 0; j <= 3; j++) {
+ printf ("[%d]: next %d prev %d\n", j,
+ tp[j].l.next, tp[j].l.prev);
+ }
+ printf("---------------\n");
+
+ }
+
+ printf("After all adds:\n");
+
+ printf("headp next %d prev %d\n",
+ headp->next, headp->prev);
+
+ for (j = 0; j <= 3; j++) {
+ printf ("[%d]: next %d prev %d\n", j,
+ tp[j].l.next, tp[j].l.prev);
+ }
+ printf("---------------\n");
+
+ head_index = index_dlist_remelem (head_index, (u8 *)tp, sizeof(tp[0]),
+ STRUCT_OFFSET_OF(tv_t, l), 1);
+
+ printf("after delete 1, head index %d\n", head_index);
+ headp = &((tp + head_index)->l);
+ printf("headp next %d prev %d\n",
+ headp->next, headp->prev);
+ for (j = 0; j <= 3; j++) {
+ printf ("[%d]: next %d prev %d\n", j,
+ tp[j].l.next, tp[j].l.prev);
+ }
+ printf("---------------\n");
+
+ index_dlist_addtail(head_index, (u8 *)tp, sizeof(tp[0]),
+ STRUCT_OFFSET_OF(tv_t, l), 1);
+
+ printf("after re-add 1, head index %d\n", head_index);
+ headp = &((tp + head_index)->l);
+ printf("headp next %d prev %d\n",
+ headp->next, headp->prev);
+ for (j = 0; j <= 3; j++) {
+ printf ("[%d]: next %d prev %d\n", j,
+ tp[j].l.next, tp[j].l.prev);
+ }
+ printf("---------------\n");
+
+ for (i = 3; i >= 0; i--) {
+ head_index = index_dlist_remelem (head_index, (u8 *)tp, sizeof(tp[0]),
+ STRUCT_OFFSET_OF(tv_t, l), i);
+ printf("after delete, head index %d\n", head_index);
+ if (head_index != EMPTY) {
+ headp = &((tp + head_index)->l);
+ printf("headp next %d prev %d\n",
+ headp->next, headp->prev);
+ for (j = 0; j <= 3; j++) {
+ printf ("[%d]: next %d prev %d\n", j,
+ tp[j].l.next, tp[j].l.prev);
+ }
+ } else {
+ printf("empty list\n");
+ }
+ printf("---------------\n");
+ }
+}
+#endif /* test code 2 */
+
+#ifdef TEST_CODE
+
+typedef struct tv_ {
+ char junk[43];
+ index_slist_t l;
+} tv_t;
+
+
+void index_list_test_cmd(int argc, unsigned long *argv)
+{
+ int i, j;
+ tv_t *tp = 0;
+ index_slist_t *buckets = 0;
+
+ vec_add1((u32 *)buckets, EMPTY);
+ vec_validate(tp, 9);
+
+ for (i = 0; i < 10; i++) {
+ index_slist_addhead(buckets, (u8 *)tp, sizeof(*tp),
+ STRUCT_OFFSET_OF(tv_t, l), i);
+ }
+
+ printf ("after adds, buckets[0] = %u\n", buckets[0]);
+
+ for (j = 0; j < 10; j++) {
+ printf("tp[%d] next %u\n", j, tp[j].l);
+
+ }
+
+ for (i = 0; i < 10; i++) {
+ if (PREDICT_FALSE(index_slist_remelem(buckets, (u8 *) tp, sizeof(*tp),
+ STRUCT_OFFSET_OF(tv_t, l), i))) {
+ printf("OUCH: remelem failure at index %d\n", i);
+ }
+ if (PREDICT_FALSE(tp[i].l.next != EMPTY)) {
+ printf("OUCH: post-remelem next not EMPTY, index %d\n", i);
+ }
+ }
+
+ printf ("after deletes, buckets[0] = %x\n", buckets[0]);
+
+ for (i = 0; i < 10; i++) {
+ index_slist_addhead(buckets, (u8 *)tp, sizeof(*tp),
+ STRUCT_OFFSET_OF(tv_t, l), i);
+ }
+
+ printf ("after adds, buckets[0] = %u\n", buckets[0]);
+
+ for (j = 0; j < 10; j++) {
+ printf("tp[%d] next %u\n", j, tp[j].l);
+
+ }
+
+ for (i = 9; i >= 0; i--) {
+ if (PREDICT_FALSE(index_slist_remelem(buckets, (u8 *) tp, sizeof(*tp),
+ STRUCT_OFFSET_OF(tv_t, l), i))) {
+ printf("OUCH: remelem failure at index %d\n", i);
+ }
+ if ((tp[i].l.next != EMPTY)) {
+ printf("OUCH: post-remelem next not EMPTY, index %d\n", i);
+ }
+ }
+
+ printf ("after deletes, buckets[0] = %x\n", buckets[0]);
+
+ printf("add evens, then odds...\n");
+
+ for (i = 0; i < 10; i += 2) {
+ index_slist_addhead(buckets, (u8 *)tp, sizeof(*tp),
+ STRUCT_OFFSET_OF(tv_t, l), i);
+
+ printf ("head = buckets[0].next = %d\n", buckets[0].next);
+ for (j = 0; j < 10; j++) {
+ printf("tp[%d] next %u\n", j, tp[j].l);
+ }
+ printf("-------------\n");
+ }
+
+ for (i = 1; i < 10; i += 2) {
+ index_slist_addhead(buckets, (u8 *)tp, sizeof(*tp),
+ STRUCT_OFFSET_OF(tv_t, l), i);
+
+ printf ("head = buckets[0].next = %d\n", buckets[0].next);
+ for (j = 0; j < 10; j++) {
+ printf("tp[%d] next %u\n", j, tp[j].l);
+ }
+ printf("-------------\n");
+ }
+
+ printf ("after adds, buckets[0] = %u\n", buckets[0]);
+
+ for (j = 0; j < 10; j++) {
+ printf("tp[%d] next %u\n", j, tp[j].l);
+
+ }
+
+ for (i = 9; i >= 0; i--) {
+ if (PREDICT_FALSE(index_slist_remelem(buckets, (u8 *) tp, sizeof(*tp),
+ STRUCT_OFFSET_OF(tv_t, l), i))) {
+ printf("OUCH: remelem failure at index %d\n", i);
+ }
+ if (PREDICT_FALSE(tp[i].l.next != EMPTY)) {
+ printf("OUCH: post-remelem next not EMPTY, index %d\n", i);
+ }
+ }
+
+ printf ("after deletes, buckets[0] = %x\n", buckets[0]);
+
+ vec_free(buckets);
+ vec_free(tp);
+}
+#endif /* test code */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/index_list.h b/vpp/plugins/vcgn-plugin/vcgn/index_list.h
new file mode 100644
index 00000000..498cd7eb
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/index_list.h
@@ -0,0 +1,118 @@
+/*
+ *------------------------------------------------------------------
+ * index_list.h - vector-index-based doubly-linked lists
+ *
+ * Copyright (c) 2008-2009 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef _INDEX_LIST_H_
+#define _INDEX_LIST_H_ 1
+
+/* An index we can't possibly see in practice... */
+#define EMPTY ((u32)~0)
+
+typedef struct index_slist_ {
+ u32 next;
+} index_slist_t;
+
+/*
+ * index_slist_addhead
+ *
+ * args: headp -- pointer to e.g. a hash bucket
+ * vector -- vector containing the list
+ * elsize -- size of an element in this vector
+ * offset -- offset in each vector element of this list thread
+ * index_to_add -- index in the vector to add to the list
+ *
+ * Adds new items to the head of the list. Try not to screw up the args!
+ */
+static inline void
+ index_slist_addhead_inline (index_slist_t *headp,
+ u8 *vector, u32 elsize,
+ u32 offset, u32 index_to_add)
+{
+ index_slist_t *addme;
+
+ addme = (index_slist_t *)(vector + offset + elsize*index_to_add);
+ addme->next = EMPTY;
+
+ if (headp->next == EMPTY) {
+ headp->next = index_to_add;
+ return;
+ } else {
+ addme->next = headp->next;
+ headp->next = index_to_add;
+ }
+}
+
+/*
+ * index_slist_remelem
+ *
+ * args: headp -- pointer to e.g. a hash bucket
+ * vector -- vector containing the list
+ * elsize -- size of an element in this vector
+ * offset -- offset in each vector element of this list thread
+ * index_to_del -- index in the vector to delete from the list
+ *
+ * Try not to screw up the args!
+ */
+
+static inline int
+ index_slist_remelem_inline (index_slist_t *headp,
+ u8 *vector, u32 elsize,
+ u32 offset, u32 index_to_delete)
+{
+ index_slist_t *findme;
+ index_slist_t *prev;
+ index_slist_t *cur;
+
+ findme = (index_slist_t *)(vector + offset + elsize*index_to_delete);
+
+ if (headp->next == index_to_delete) {
+ headp->next = findme->next;
+ findme->next = EMPTY;
+ return 0;
+ }
+
+ prev = (index_slist_t *)(vector + offset + elsize*headp->next);
+ cur = (index_slist_t *)(vector + offset + elsize*prev->next);
+ while (cur != findme) {
+ if (cur->next == EMPTY)
+ return (1);
+ prev = cur;
+ cur = (index_slist_t *)(vector + offset + elsize*cur->next);
+ }
+ prev->next = findme->next;
+ findme->next = EMPTY;
+ return 0;
+}
+
+void index_slist_addhead (index_slist_t *headp,
+ u8 *vector, u32 elsize, u32 offset, u32 index);
+int index_slist_remelem (index_slist_t *headp,
+ u8 *vector, u32 elsize, u32 offset, u32 index);
+
+typedef struct index_dlist_ {
+ u32 next;
+ u32 prev;
+} index_dlist_t;
+
+void index_dlist_addtail (u32 head_index, u8 *vector, u32 elsize,
+ u32 offset, u32 index_to_add);
+
+u32 index_dlist_remelem (u32 head_index,
+ u8 *vector, u32 elsize, u32 offset,
+ u32 index_to_delete);
+#endif /* _INDEX_LIST_H_ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/nat64_db.h b/vpp/plugins/vcgn-plugin/vcgn/nat64_db.h
new file mode 100644
index 00000000..837464f6
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/nat64_db.h
@@ -0,0 +1,480 @@
+/*
+ *------------------------------------------------------------------
+ * nat64_db.h - Stateful NAT64 translation database definitions
+ *
+ * Copyright (c) 2010-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+#ifndef __NAT64_DB_H__
+#define __NAT64_DB_H__
+
+#include "cnat_cli.h"
+#include "index_list.h"
+#include "cnat_ports.h"
+#include "cnat_db.h"
+#include "nat64_defs.h"
+#include "cnat_bulk_port_defs.h"
+
+nat64_vrfmap_t *nat64_map_by_vrf;
+
+#define SESSION_OPT
+
+#define HASH_ENHANCE 4
+
+
+#define NAT64_MAIN_DB_SIZE \
+ (PLATFORM_NAT64_MAX_SESSIONS / PLATFORM_CNAT_INSTS)
+#define NAT64_MAIN_HASH_SIZE \
+ (HASH_ENHANCE * PLATFORM_CNAT_MAIN_PRELIM_HASH_SIZE)
+
+#define NAT64_MAIN_HASH_MASK (NAT64_MAIN_HASH_SIZE-1)
+
+
+/* nb: 200000 users / 64 CNAT = 3125, 76% occupancy */
+#define NAT64_USER_HASH_SIZE CNAT_USER_HASH_SIZE
+#define NAT64_USER_HASH_MASK (NAT64_USER_HASH_SIZE-1)
+
+/* Number of sessions per BIB entry/NAT64 translation
+ - nsessions is u16 type. So selected 0xFFFF
+ - Ideally Sessions per transltion will not reach the limit
+ - Only DoS can possible. It can take care of it */
+#define NAT64_MAX_SESSIONS_PER_BIB 0xFFFF
+
+/* No. of per ip/port config will be limited to 1000 */
+/* totally 25K across all instances) */
+#define NAT64_TIMEOUT_HASH_SIZE \
+ PLATFORM_NAT64_TIMEOUT_HASH_SIZE
+
+#define NAT64_TIMEOUT_HASH_MASK (NAT64_TIMEOUT_HASH_SIZE - 1)
+#define NAT64_TIMEOUT_FULL_MASK 0xFFFFFFFFFFFFFFFF
+
+
+#define FORCE_DEL 1 /* Delete static BIB entries as well */
+
+/* default timeout values */
+#define NAT64_UDP_DEFAULT 300 /* 5 min */
+#define NAT64_UDP_MIN 120 /* 2 min */
+#define NAT64_TCP_TRANS 240 /* 4 min */
+#define NAT64_TCP_EST 7200 /* 2 hrs */
+#define NAT64_TCP_V4_SYN 6 /* 6 sec */
+#define NAT64_FRAG_MIN 2 /* 2 sec */
+#define NAT64_ICMP_DEFAULT 60 /* 1 min */
+
+
+#define NAT64_V6_GET_HASH(in_key, hash, mask) \
+ a = in_key->ipv6[0] ^ in_key->ipv6[1] ^ in_key->ipv6[2] ^ in_key->ipv6[3] \
+ ^ ((in_key->port << 16) | in_key->vrf); \
+ b = c = 0x9e3779b9;\
+ /* Jenkins hash, arbitrarily use c as the "answer" */ \
+ hash_mix32(a, b, c); \
+ hash = c & mask; \
+
+
+#define NAT64_V4_GET_HASH(in_key, hash, mask) \
+ a = in_key.ipv4 ^ ((in_key.port << 16) | in_key.vrf); \
+ b = c = 0x9e3779b9; \
+ /* Jenkins hash, arbitrarily use c as the "answer" */ \
+ hash_mix32(a, b, c); \
+ hash = c & mask;
+
+
+
+#define NAT64_V6_GET_SESSION_HASH(bib_index, in_addr, port, vrf, hash, mask) \
+ a = bib_index ^ in_addr[0] ^ in_addr[1] ^ in_addr[2] ^ in_addr[3] \
+ ^ port ^ vrf; \
+ b = c = 0x9e3779b9; \
+ /* Jenkins hash, arbitrarily use c as the "answer" */ \
+ hash_mix32(a, b, c); \
+ hash = c & mask;
+
+#define NAT64_V4_GET_SESSION_HASH(bib_index, in_addr, port, vrf, hash, mask) \
+ a = bib_index ^ in_addr ^ port ^ vrf; \
+ b = c = 0x9e3779b9; \
+ /* Jenkins hash, arbitrarily use c as the "answer" */ \
+ hash_mix32(a, b, c); \
+ hash = c & mask;
+
+
+extern index_slist_t *nat64_bib_out2in_hash;
+extern index_slist_t *nat64_bib_in2out_hash;
+extern index_slist_t *nat64_bib_user_hash;
+extern index_slist_t *nat64_session_out2in_hash;
+#ifndef SESSION_OPT
+extern index_slist_t *nat64_session_in2out_hash;
+#endif
+extern index_slist_t *nat64_frag_out2in_hash;
+extern index_slist_t *nat64_frag_in2out_hash;
+extern index_slist_t *nat64_timeout_hash;
+
+
+/*
+ * nat64_ bib_entry_t
+ * This structure depicts Binding Information Base of NAT64 sessions.
+ * It stores information about the inside v6 source transport address and
+ * corresponding outside v4 source transport address for each protocol.
+ */
+
+typedef struct {
+
+ index_slist_t nat64_bib_out2in_hash;
+ index_slist_t nat64_bib_in2out_hash;
+
+ /* 0x08 */
+ u16 flags; /* flags in cnat_db.h (cnat_main_db_entry_t) */
+#define NAT64_DB_FLAG_STATIC_PORT CNAT_DB_FLAG_STATIC_PORT
+#define NAT64_DB_NAT64_FLAG CNAT_DB_NAT64_FLAG
+#define NAT64_DB_FLAG_ALG_ENTRY CNAT_DB_FLAG_ALG_ENTRY
+#define NAT64_DB_FLAG_PCPI CNAT_DB_FLAG_PCPI
+#define NAT64_DB_FLAG_PCPE CNAT_DB_FLAG_PCPE
+
+ /* 0x0A */
+ u16 nat64_inst_id;
+ /* 0x0C */
+ u32 user_index;
+
+ /* 0x10 */
+ nat64_v4_key_t v4_out_key;
+
+ /* 0x18 */
+ nat64_v6_key_t v6_in_key;
+
+ /* 0x2C */
+ index_dlist_t user_ports;
+ /* 0x34 */
+ u32 session_head_index;
+ /* 0x38 - 56B*/
+ u16 nsessions;
+ u16 pad2;
+
+ /* 0x3C - 60B */
+ u32 in2outpkts;
+ u32 out2inpkts;
+ /* 0x44 - 68B */
+
+ /* 0x42 - 70B */
+ union { /* used by FTP ALG, pkt len delta due to FTP PORT cmd */
+ u16 delta;
+ i8 alg_dlt[2]; /* two delta values, 0 for previous, 1 for current */
+ u16 il; /* Used to indicate if interleaved mode is used
+ in case of RTSP ALG */
+ } alg;
+
+ u16 temp1;
+
+ u32 entry_expires;
+
+ u32 temp3;
+ /* unused, temp1 ,temp2 and temp3 put to make it in sync with nat44 main db entry size */
+ /* size of = 0x54 = 84 B */
+ u32 unused;
+
+} nat64_bib_entry_t ;
+
+/*
+ * nat64_bib_user_entry_t
+ * This structure stores information about translations of a particular user
+ * (User here refers to a same inside source address)
+ */
+typedef struct {
+ /* 0x00 */
+ index_slist_t user_hash;
+ /* 0x04 */
+ u16 ntranslations;
+ /* 0x06 */
+ u8 icmp_msg_count;
+ /* 0x07 */
+ u8 flags;
+#define NAT64_USER_DB_NAT64_FLAG CNAT_USER_DB_NAT64_FLAG
+
+ /* 0x08 */
+ u32 translation_list_head_index;
+ /* 0x0C */
+ u32 portmap_index;
+ /* 0x10 */
+ nat64_v6_key_t v6_in_key;
+ /* 0x24 = 36 B */
+
+ u32 align1; /* Make it 8B boundary and in sync with nat44 user db entry size */
+#ifndef NO_BULK_LOGGING
+ /* size of = 0x28 = 40 B */
+ /* Now adding 8 more bytes for bulk allocation.. This makes it
+ * 0x30 (48). For nat64 stful, we may support bulk allocation
+ * later */
+ /* Indicates the currently used bulk port range */
+ i16 bulk_port_range_cache[BULK_RANGE_CACHE_SIZE];
+#endif /* NO_BULK_LOGGING */
+} nat64_bib_user_entry_t;
+
+/*
+ * nat64_session_entry_t
+ * This structure represents the session table. It maintains the information
+ * about the flow of the packets. It would consist of source and destination
+ * (inside and outside) ipv4 and ipv4 transport addresses.
+ */
+typedef struct {
+
+ /* 0x00 */
+ index_slist_t nat64_session_out2in_hash;
+
+ /* 0x04 */
+ u32 bib_index; /* would point to v4/v6 src transport address */
+
+ /* 0x08 */
+ nat64_v4_key_t v4_dest_key;
+
+#ifndef SESSION_OPT
+ index_slist_t nat64_session_in2out_hash;
+ nat64_v6_key_t v6_dest_key;
+#endif
+
+ /* 0x10 */
+ u16 flags;/* Will be used for flags same as nat44 session */
+
+ /* 0x12 */
+ u16 timeout;
+
+ /* 0x14 */
+ u32 entry_expires;
+ /* 0x18 */
+ index_dlist_t bib_list;
+ /* 0x20 = 32 B */
+
+ union { /* alg same as cnat_main_db_t */
+ u16 delta;
+ i8 alg_dlt[2];
+ u16 il;
+ } alg;
+
+ /* 0x22 */
+ u16 tcp_flags; /* Mainly TCP events - check nat64_tcp_sm.h */
+
+ /* 0x24 */
+ u32 tcp_seq_num;
+
+ /* 0x28 */ /* unused1, unused2 and unused3 are put to make it in sync with
+ * cnat_session_db */
+ u32 unused1;
+
+ /* 0x2C */
+ u32 unused2;
+
+ /* 0x30 */
+ u16 unused3;
+
+ /* 0x32 - 50B */
+
+} nat64_session_entry_t;
+
+/*
+ * nat64_session_tcp_init_entry_t
+ * This structure will be used to store information about v4 initiation
+ * tcp entries.
+ */
+typedef struct {
+ nat64_v6_key_t v6_in_key;
+ nat64_v4_key_t v4_out_key;
+} nat64_session_tcp_init_entry_t;
+
+/*
+ * nat64_in_v6_frag_entry_t
+ * This structure will be used to store information about fragment flows
+ * that are coming from inside v6 hosts.
+ */
+typedef struct {
+ index_slist_t nat64_frag_in2out_hash;
+
+ u32 v6_src_addr[4];
+ u32 v6_destn_addr[4];
+ u32 frag_iden;
+ u16 vrf;
+ u16 pad1;
+} nat64_in_v6_frag_entry_t ;
+
+/*
+ * nat64_out_v4_frag_entry_t
+ * This structure will be used to store information about fragment flows
+ * that are coming from outside v4 machines.
+ */
+typedef struct {
+ index_slist_t nat64_frag_out2in_hash;
+
+ u32 v4_src_addr;
+ u32 v4_destn_addr;
+ u16 frag_iden;
+ u16 vrf;
+} nat64_out_v4_frag_entry_t ;
+
+/*
+ * nat64_timeout _t
+ * These following structures will be used to store information destination
+ * timeouts configured.
+ */
+typedef struct {
+ nat64_v4_key_t timeout_key;
+ u16 timeout_value;
+} nat64_timeout_t;
+
+/*
+ * nat64_timeout_db_entry_t
+ */
+typedef struct {
+ nat64_timeout_t t_key;
+ index_slist_t t_hash;
+} nat64_timeout_db_entry_t;
+
+
+typedef union {
+ cnat_main_db_entry_t nat44_main_db;
+ nat64_bib_entry_t nat64_bib_db;
+} cgse_nat_db_entry_t;
+
+typedef union {
+ cnat_session_entry_t nat44_session_db;
+ nat64_session_entry_t nat64_session_db;
+} cgse_nat_session_db_entry_t;
+
+typedef union {
+ cnat_user_db_entry_t nat44_user_db;
+ nat64_bib_user_entry_t nat64_user_db;
+} cgse_nat_user_db_entry_t;
+
+extern index_slist_t *nat64_bib_out2in_hash;
+extern index_slist_t *nat64_bib_in2out_hash;
+extern index_slist_t *nat64_bib_user_hash;
+extern index_slist_t *nat64_session_out2in_hash;
+extern index_slist_t *nat64_session_in2out_hash;
+extern index_slist_t *nat64_frag_out2in_hash;
+extern index_slist_t *nat64_frag_in2out_hash;
+extern index_slist_t *nat64_timeout_hash;
+
+extern nat64_bib_entry_t *nat64_bib_db;
+extern nat64_bib_user_entry_t *nat64_bib_user_db;
+extern nat64_session_entry_t *nat64_session_db;
+extern nat64_in_v6_frag_entry_t *nat64_in_frag_db;
+extern nat64_out_v4_frag_entry_t *nat64_out_frag_db;
+extern nat64_session_tcp_init_entry_t *nat64_tcp_init_db ;
+extern nat64_timeout_db_entry_t *nat64_timeout_db;
+
+extern nat64_table_entry_t nat64_table_array[NAT64_MAX_NAT64_ENTRIES];
+extern nat64_table_entry_t *nat64_table_ptr;
+
+extern cgse_nat_db_entry_t *cgse_nat_db;
+extern cgse_nat_user_db_entry_t *cgse_user_db;
+extern cgse_nat_session_db_entry_t *cgse_session_db;
+
+void nat64_bib_user_db_delete (nat64_bib_user_entry_t *up);
+
+nat64_bib_user_entry_t*
+nat64_bib_user_db_create_entry(nat64_v6_key_t *uki, u32 bucket,
+ u32 portmap_index);
+
+nat64_bib_user_entry_t*
+nat64_bib_user_db_lookup_entry(nat64_v6_key_t *uki, u32 *bucket);
+
+
+nat64_bib_entry_t*
+nat64_bib_db_lookup_entry(nat64_v6_key_t *ki);
+
+void nat64_bib_db_in2out_hash_delete (nat64_bib_entry_t *ep);
+
+void nat64_bib_db_out2in_hash_delete (nat64_bib_entry_t *ep);
+
+nat64_bib_entry_t *
+nat64_create_bib_db_entry_and_hash(nat64_v6_key_t *ki,
+ nat64_v4_key_t *ko,
+ nat64_bib_user_entry_t *udb);
+
+
+void nat64_delete_bib_db_entry (nat64_bib_entry_t *ep, u8 force);
+
+nat64_bib_entry_t *
+nat64_bib_db_lookup_entry_out2in (nat64_v4_key_t *ko);
+
+nat64_bib_entry_t *
+nat64_get_bib_db_entry (nat64_v6_key_t *ki,
+ port_pair_t port_pair_type,
+ port_type_t port_type,
+ cnat_gen_icmp_info *info);
+
+
+nat64_bib_entry_t*
+nat64_create_static_bib_db_entry (nat64_v6_key_t *ki,
+ nat64_v4_key_t *ko,
+ nat64_table_entry_t *my_table,
+ cnat_gen_icmp_info *info);
+
+
+
+//void nat64_session_db_in2out_hash_delete (nat64_session_entry_t *ep);
+void nat64_session_db_out2in_hash_delete (nat64_session_entry_t *ep);
+
+/*nat64_session_entry_t *
+nat64_session_db_lookup_entry(nat64_v6_key_t *ki, u32 bib_index); */
+
+
+nat64_session_entry_t *
+nat64_session_db_lookup_entry_out2in (nat64_v4_key_t *ko,u32 bib_index);
+
+/*
+nat64_session_entry_t *
+nat64_create_session_db_entry(nat64_v6_key_t *ki,
+ nat64_v4_key_t *ko,
+ nat64_bib_entry_t *bdb);
+*/
+nat64_session_entry_t *
+nat64_create_session_db_entry_v2( nat64_v4_key_t *ko,
+ nat64_bib_entry_t *bdb);
+
+
+//void nat64_delete_session_db_entry (nat64_session_entry_t *ep);
+void nat64_delete_session_db_entry_v2 (nat64_session_entry_t *ep, u8 force);
+
+u32 nat64_timeout_db_hash_lookup (nat64_v4_key_t t_key);
+
+u16 query_and_update_db_timeout_nat64(nat64_session_entry_t *db);
+
+void nat64_timeout_db_hash_add (nat64_timeout_db_entry_t *t_entry);
+
+u16 nat64_timeout_db_create (nat64_timeout_t t_entry);
+
+void nat64_timeout_db_delete(nat64_v4_key_t t_key);
+
+#define NAT64_CMP_V6_KEY(key1, key2) \
+ memcmp(key1, key2, sizeof(nat64_v6_key_t))
+
+#define NAT64_CMP_V4_KEY(key1, key2) \
+ memcmp(key1, key2, sizeof(nat64_v4_key_t))
+
+
+#define NAT64_CMP_V6_IP(ip1, ip2) \
+ memcmp(ip1, ip2, (sizeof(u32) * 4))
+
+
+#define NAT64_CMP_V6_KEY1(key1, key2) \
+ (key1.ipv6[0] == key2.ipv6[0]) && (key1.ipv6[1] == key2.ipv6[1]) && \
+ (key1.ipv6[2] == key2.ipv6[2]) && (key1.ipv6[3] == key2.ipv6[3]) && \
+ (key1.port == key2.port) && (key1.vrf == key2.vrf)
+
+
+#define NAT64_CMP_V6_IP1(ip1, ip2) \
+ ((ip1[0] == ip2[0]) && (ip1[1] == ip2[1]) && \
+ (ip1[2] == ip2[2]) && (ip1[3] == ip2[3]))
+
+#define NAT64_CMP_V4_KEY1(key1, key2) \
+ (key1.key64 == key2.key64)
+
+
+extern u8 nat64_timeout_dirty_flag[NAT64_MAX_NAT64_ENTRIES];
+
+#endif
diff --git a/vpp/plugins/vcgn-plugin/vcgn/nat64_defs.h b/vpp/plugins/vcgn-plugin/vcgn/nat64_defs.h
new file mode 100644
index 00000000..47e431a7
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/nat64_defs.h
@@ -0,0 +1,576 @@
+/*
+ *------------------------------------------------------------------
+ * nat64_defs.h - NAT64 structure definiitions
+ *
+ * Copyright (c) 2007-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __NAT64_DEFS_H__
+#define __NAT64_DEFS_H__
+
+#ifdef TOBE_PORTED
+#include "spp_platform_common.h"
+#include "cgse_defs.h"
+#include "xlat_defs.h"
+#endif
+#include "cnat_cli.h"
+#include "cnat_ports.h"
+#include "tcp_header_definitions.h"
+#include "nat64_tcp_sm.h"
+#include "cnat_db.h"
+
+#define NAT64_MAX_FRAG_ID_COUNTERS (256)
+
+#define NAT64_MAX_NAT64_ENTRIES 500
+
+#define NAT64_MAX_ID (NAT64_MAX_NAT64_ENTRIES-1)
+
+#define NAT64_INVALID_ID (0)
+
+#define NAT64_MAX_CFG_INSTANCES 64
+
+#define NAT64_TABLE_ENTRY_DELETED 0
+#define NAT64_TABLE_ENTRY_ACTIVE 1
+#define NAT64_TABLE_ENTRY_DORMANT 2
+#define NAT64_TABLE_ENTRY_INVALID_UIDB 3
+
+#define NAT64_MAX_TRANSLATION_ENTRIES PLATFORM_MAX_TRANSLATION_ENTRIES
+
+#define NAT64_WKP_PREFIX_LEN 96
+#define NAT64_WKP_PREFIX_0 0x0064FF9B
+#define NAT64_WKP_PREFIX_1 0x00000000
+#define NAT64_WKP_PREFIX_2 0x00000000
+#define NAT64_WKP_PREFIX_3 0x00000000
+
+
+/* Reset the expiry time only if it is not 0
+** if it is 0 - then queue for delete by clear command
+**/
+
+#define NAT64_TIMEOUT_RST(db) \
+ if(PREDICT_TRUE(db->entry_expires !=0 )) \
+ db->entry_expires = cnat_current_time;
+
+extern u32 nat64_config_debug_level;
+extern u32 nat64_data_path_debug_level;
+
+extern u32 nat64_translation_create_count[NAT64_MAX_NAT64_ENTRIES];
+extern u32 nat64_translation_delete_count[NAT64_MAX_NAT64_ENTRIES];
+extern u32 nat64_translation_create_rate[NAT64_MAX_NAT64_ENTRIES];
+extern u32 nat64_translation_delete_rate[NAT64_MAX_NAT64_ENTRIES];
+extern u32 nat64_in2out_forwarding_count[NAT64_MAX_NAT64_ENTRIES];
+extern u32 nat64_in2out_forwarding_rate[NAT64_MAX_NAT64_ENTRIES];
+extern u32 nat64_out2in_forwarding_count[NAT64_MAX_NAT64_ENTRIES];
+extern u32 nat64_out2in_forwarding_rate[NAT64_MAX_NAT64_ENTRIES];
+
+extern u32 nat64_translation_create_count_old[NAT64_MAX_NAT64_ENTRIES];
+extern u32 nat64_translation_delete_count_old[NAT64_MAX_NAT64_ENTRIES];
+extern u32 nat64_in2out_forwarding_count_old[NAT64_MAX_NAT64_ENTRIES];
+extern u32 nat64_out2in_forwarding_count_old[NAT64_MAX_NAT64_ENTRIES];
+
+extern u16 *nat64_frag_id_counter_ptr;
+
+typedef struct {
+ u64 v6_to_v4_tcp_input_count;
+ u64 v6_to_v4_tcp_non_translatable_drop_count;
+ u64 v6_to_v4_tcp_state_drop_count;
+ u64 v6_to_v4_tcp_no_db_drop_count;
+ u64 v6_to_v4_tcp_output_count;
+} nat64_v6_to_v4_tcp_counter_t;
+
+typedef struct {
+ u64 v4_to_v6_tcp_input_count;
+ u64 v4_to_v6_tcp_no_db_drop_count;
+ u64 v4_to_v6_tcp_v4_init_policy_drop_count;
+ u64 v4_to_v6_tcp_state_drop_count;
+ u64 v4_to_v6_tcp_output_count;
+ u64 v4_to_v6_tcp_filter_drop_count;
+} nat64_v4_to_v6_tcp_counter_t;
+
+typedef struct {
+ u64 v6_to_v4_udp_input_count;
+ u64 v6_to_v4_udp_non_translatable_drop_count;
+ u64 v6_to_v4_udp_no_db_drop_count;
+ u64 v6_to_v4_udp_output_count;
+ u64 v6_to_v4_udp_checksum_zero_count;
+} nat64_v6_to_v4_udp_counter_t;
+
+typedef struct {
+ u64 v4_to_v6_udp_input_count;
+ u64 v4_to_v6_udp_no_db_drop_count;
+ u64 v4_to_v6_udp_filter_drop_count;
+ u64 v4_to_v6_udp_output_count;
+ u64 v4_to_v6_udp_crc_zero_drop_count;
+ u64 v4_to_v6_udp_frag_crc_zero_drop_count;
+ u64 v4_to_v6_udp_crc_zero_recycle_sent_count;
+ u64 v4_to_v6_udp_crc_zero_recycle_drop_count;
+} nat64_v4_to_v6_udp_counter_t;
+
+typedef struct {
+ u64 v6_to_v4_icmp_input_count;
+ u64 v6_to_v4_icmp_no_db_drop_count;
+ u64 v6_to_v4_icmp_non_translatable_drop_count;
+ u64 v6_to_v4_icmp_qry_output_count;
+} nat64_v6_to_v4_icmp_counter_t;
+
+typedef struct {
+ u64 v4_to_v6_icmp_input_count;
+ u64 v4_to_v6_icmp_no_db_drop_count;
+ u64 v4_to_v6_icmp_filter_drop;
+ u64 v4_to_v6_icmp_qry_output_count;
+} nat64_v4_to_v6_icmp_counter_t;
+
+typedef struct {
+ u64 v6_to_v4_icmp_error_input_count;
+ u64 v6_to_v4_icmp_error_no_db_drop_count;
+ u64 v6_to_v4_icmp_error_invalid_next_hdr_drop_count;
+ u64 v6_to_v4_icmp_error_non_translatable_drop_count;
+ u64 v6_to_v4_icmp_error_unsupported_type_drop_count;
+ u64 v6_to_v4_icmp_error_output_count;
+} nat64_v6_to_v4_icmp_error_counter_t;
+
+typedef struct {
+ u64 v4_to_v6_icmp_error_input_count;
+ u64 v4_to_v6_icmp_error_no_db_drop_count;
+ u64 v4_to_v6_icmp_error_unsupported_type_drop_count;
+ u64 v4_to_v6_icmp_error_unsupported_protocol_drop_count;
+ u64 v4_to_v6_icmp_error_output_count;
+} nat64_v4_to_v6_icmp_error_counter_t;
+
+
+
+typedef struct {
+ u64 nat64_v4_frag_input_count;
+ u64 nat64_v4_frag_forward_count;
+ u64 nat64_v4_frag_drop_count;
+ u64 nat64_v4_frag_throttled_count;
+ u64 nat64_v4_frag_timeout_drop_count;
+ u64 nat64_v4_frag_tcp_input_count;
+ u64 nat64_v4_frag_udp_input_count;
+ u64 nat64_v4_frag_icmp_input_count;
+
+ u64 nat64_v6_frag_input_count;
+ u64 nat64_v6_frag_forward_count;
+ u64 nat64_v6_frag_drop_count;
+ u64 nat64_v6_frag_throttled_count;
+ u64 nat64_v6_frag_timeout_drop_count;
+ u64 nat64_v6_frag_tcp_input_count;
+ u64 nat64_v6_frag_udp_input_count;
+ u64 nat64_v6_frag_icmp_input_count;
+ u64 nat64_v6_frag_invalid_input_count;
+} nat64_frag_counter_t;
+
+typedef struct {
+ u64 v6_to_v4_options_input_count;
+ u64 v6_to_v4_options_drop_count;
+ u64 v6_to_v4_options_forward_count;
+ u64 v6_to_v4_options_no_db_drop_count;
+ u64 v6_to_v4_unsupp_proto_count;
+
+ u64 v4_to_v6_options_input_count;
+ u64 v4_to_v6_options_drop_count;
+ u64 v4_to_v6_options_forward_count;
+ u64 v4_to_v6_options_no_db_drop_count;
+ u64 v4_to_v6_unsupp_proto_count;
+} nat64_options_counter_t;
+
+typedef struct {
+ u64 v4_icmp_gen_count;
+ u64 v6_icmp_gen_count;
+} nat64_icmp_gen_counter_t;
+
+typedef struct{
+ u32 nat64_num_translations;
+ u32 nat64_num_dynamic_translations;
+ u32 nat64_num_static_translations;
+ u32 nat64_sessions;
+ u64 nat64_port_limit_exceeded;
+ u64 nat64_system_limit_reached;
+ u64 nat64_resource_depletion_drops;
+ u64 nat64_no_translation_entry_drops;
+ u64 nat64_filtering_drops ;
+ u64 nat64_invalid_ipv6_prefix_drops;
+ u32 num_subscribers;
+ u32 dummy;
+ u64 drops_sessiondb_limit_exceeded;
+} nat64_inst_gen_counter_t;
+
+typedef struct {
+
+ nat64_v6_to_v4_tcp_counter_t v64_tcp_counters;
+ nat64_v4_to_v6_tcp_counter_t v46_tcp_counters;
+ nat64_v6_to_v4_udp_counter_t v64_udp_counters;
+ nat64_v4_to_v6_udp_counter_t v46_udp_counters;
+ nat64_v6_to_v4_icmp_counter_t v64_icmp_counters;
+ nat64_v4_to_v6_icmp_counter_t v46_icmp_counters;
+ nat64_v6_to_v4_icmp_error_counter_t v64_icmp_error_counters;
+ nat64_v4_to_v6_icmp_error_counter_t v46_icmp_error_counters;
+ nat64_frag_counter_t nat64_frag_counters;
+ nat64_options_counter_t nat64_options_counters;
+ nat64_icmp_gen_counter_t nat64_icmp_gen_counters;
+
+} nat64_counters_t;
+
+/*
+ * nat64_portmap_v2_t
+ * This structure stores information about the IP address and ports
+ * available for NAT for this nat64 instance.
+ */
+
+typedef struct {
+ u32 delete_time;
+ u32 last_sent_timestamp;
+ u32 inuse;
+ u32 ipv4_address; /* native bit order */
+ uword bm[(BITS_PER_INST + BITS(uword)-1)/BITS(uword)];
+} nat64_portmap_t;
+
+/*
+ * nat64_v4_db_key_t
+ * This structure gives information about the v4 transport address
+ * (ipv4, port, protocol)
+ */
+typedef struct {
+ u32 ipv4;
+ u16 port;
+ u16 vrf; //bit0-12:inst_id, bit13:unused, bit14-15:protocol
+} nat64_v4_db_key_t;
+
+/* Union will be easier while compare/hash */
+typedef union {
+ nat64_v4_db_key_t k;
+ u64 key64;
+} nat64_v4_key_t;
+/*
+ * nat64_v6_db_key_t
+ * This structure gives information about the v6 transport address
+ * (ipv6, port, protocol)
+ */
+typedef struct {
+ u32 ipv6[4];
+ u16 port;
+ u16 vrf; //bit0-12:inst_id, bit13:unused, bit14-15:protocol
+} nat64_v6_key_t;
+
+
+typedef struct {
+ u16 udp_timeout;
+ u16 tcp_trans_timeout;
+ u16 tcp_est_timeout;
+ u16 tcp_v4_init_timeout;
+ u16 frag_timeout;
+ u16 icmp_timeout;
+} nat64_timeout_info_t;
+
+#define NAT64_UDP_DEF 300 /* 5min */
+#define NAT64_TCP_TRANS_DEF 240 /* 4min */
+#define NAT64_TCP_EST_DEF 7200 /* 2Hrs */
+#define NAT64_TCP_V4_DEF 6 /* 6 sec */
+#define NAT64_FRAG_DEF 2 /* 2 sec */
+#define NAT64_ICMP_DEF 60 /* 60 sec */
+
+/*
+ * nat64_table_entry_t
+ * This structure is used to store information regarding every nat64 instance.
+ */
+
+/* structure will hold the L4 information, of a particular frag stream set
+ * src_port - holds the original src port
+ * dst_port - holds the original dst port
+ * total_len - useful only in ICMP nodes
+ * cnat_port - vlaue used for looksups
+ * next_prot - Protocol after translation */
+
+typedef struct l4_frag_info {
+ u16 next_node_idx;
+ u16 src_port;
+ u16 dst_port;
+ u16 total_length;
+ u8 protocol;
+ u16 cnat_prot;
+ u16 next_prot;
+} l4_frag_info_t;
+
+typedef struct {
+ u16 state;
+ u16 nat64_id; /* nat64_id value for this table entry - for easy access */
+
+ u16 v4_uidb_index; /* V4 uidb index */
+ u16 v6_uidb_index; /* V6 uidb index */
+
+ u8 octet0_position;
+ u8 octet1_position;
+ u8 octet2_position;
+ u8 octet3_position;
+
+ u16 v4_to_v6_tcp_mss; /* TCP MSS */
+ u16 v6_to_v4_tcp_mss; /* TCP MSS */
+
+ /*
+ * V6 NAT64 prefix value and mask size
+ */
+ u32 v6_prefix[4];
+ u32 v6_prefix_mask[4];
+
+ u8 v6_prefix_mask_len;
+ u8 ubits_reserved_on;
+#define IPV4_TOS_OVERRIDE_FLAG 0x1
+#define IPV6_TOS_OVERRIDE_FLAG 0x2
+#define NAT64_STFUL_RTSP_ALG_ENABLE 0x4
+ u8 feature_flags;
+
+ u8 ipv4_tos_value;
+ u8 ipv6_tos_value;
+ u8 df_bit_clear;
+ u8 ipv6_mtu_set;
+
+ u8 filtering_policy;
+#define NAT64_ADDRESS_DEPENDENT_ENABLE 1
+ u8 tcp_policy;
+#define NAT64_TCP_SECURITY_FLAG_DISABLE 1
+ u8 ftp_flags;
+
+ u8 tcp_v4_init_enable;
+#define NAT64_TCP_V4_INIT_ENABLE 1
+
+ u8 logging_policy;
+#define NAT64_BIB_LOG_ENABLE 0 /* Default */
+#define NAT64_SESSION_LOG_ENABLE 1
+
+#define NAT64_BIDIR_REFRESH 1 /* 1 - timer refresh in both direction */
+#define NAT64_UNIDIR_REFRESH 0 /* 0 - default (only v6 side refresh timer)*/
+
+ u8 nat64_refresh_both_direction; /* 0 - default (only v6 side refresh timer) */
+#define NAT64_BIDIR_REFRESH 1 /* 1 - timer refresh in both direction */
+
+ u8 udp_zero_checksum; /* 0 - default (calc checksum) */
+#define NAT64_UDP_ZERO_CHECKSUM_DROP 1 /* 1 -drop */
+
+ u16 port_limit;
+
+ cnat_portmap_v2_t *port_map;
+
+ u32 logging_index;
+
+ nat64_timeout_info_t timeout_info;
+ /*
+ * These fields are not used much, let us keep it in the end
+ */
+ u32 v4_vrf_id; /* V4 vrf id */
+ u32 v6_vrf_id; /* V6 vrf id */
+
+ u32 v4_if_num; /* V4 SVI ifnum */
+ u32 v6_if_num; /* V6 SVI ifnum */
+
+ u16 dyn_start_port;
+
+ u16 pcp_server_port;
+ u32 pcp_server_addr[4];
+ u32 rseed_ip;
+#define NAT64_FRAG_ENABLE 1
+#define NAT64_FRAG_DISABLE 0
+ u8 frag_state;
+ u8 nat64_enable; /* Enable/Disable this instance. */
+
+ u16 rtsp_port;
+
+} nat64_table_entry_t;
+
+
+
+extern nat64_table_entry_t nat64_table_array[NAT64_MAX_NAT64_ENTRIES];
+extern nat64_table_entry_t *nat64_table_ptr;
+extern nat64_counters_t nat64_all_counters[NAT64_MAX_NAT64_ENTRIES];
+extern nat64_inst_gen_counter_t nat64_inst_gen_counters[NAT64_MAX_NAT64_ENTRIES];
+
+typedef struct nat64_common_pipeline_data_ {
+#ifdef TOBE_PORTED
+ spp_node_main_vector_t *nmv;
+#endif
+
+ u16 *nat64_id_ptr;
+
+ nat64_table_entry_t *nat64_entry_ptr;
+
+} nat64_common_pipeline_data_t;
+
+typedef struct nat64_v6_to_v4_pipeline_data_ {
+ nat64_common_pipeline_data_t common_data;
+
+ u32 bib_bucket;
+ u32 session_bucket;
+
+ nat64_v6_key_t v6_in_key;
+ nat64_v6_key_t v6_dest_key;
+
+ /*
+ * IPv6 Data, everthing in host order except for the addr fields
+ */
+ u32 version_trafficclass_flowlabel;
+
+ u16 payload_length;
+ u8 next_header;
+ u8 hop_limit;
+
+ /*
+ * These Address fields are in Network Order, so that
+ * it is easy to extract the IPv4 address from them
+ */
+ u32 ipv6_src[4];
+
+ u32 ipv6_dst[4];
+
+ u8 frag_next_header;
+ u8 frag_reserved;
+ u16 frag_offset_res_m;
+ u32 frag_identification;
+
+ ipv4_header *ipv4_header;
+ union {
+ struct _v4_l4_info {
+ u8 *ipv4_l4_header;
+ u8 pad0;
+ u8 pad1;
+ u8 pad2;
+ u8 pad3;
+ } v4_l4_info;
+ struct _v4_icmp_info {
+ icmp_v4_t *ipv4_icmp_header;
+ u8 old_icmp_type;
+ u8 new_icmp_type;
+ u8 old_icmp_code;
+ u8 new_icmp_code;
+ u16 checksum;
+ u16 old_iden; // length (ICMP extn), ptr (param)
+ u16 new_iden; // ----- do -------------
+ u16 old_seq; // MTU for PTB case
+ u16 new_seq; // ----- do -------------
+ } v4_icmp_info;
+ struct _v4_udp_info {
+ udp_hdr_type_t *ipv4_udp_header;
+ u8 pad0;
+ u8 pad1;
+ u8 pad2;
+ u8 pad3;
+ } v4_udp_info;
+ struct _v4_tcp_info {
+ tcp_hdr_type *ipv4_tcp_header;
+ u16 old_src_port;
+ u16 new_src_port;
+ u16 dest_port;
+ nat64_tcp_events tcp_event;
+ } v4_tcp_info;
+ } l4_u;
+
+
+ l4_frag_info_t *frag_info; /* port for tcp/udp, ident - icmp */
+
+
+ /* Counters will be added here */
+ union {
+ nat64_v6_to_v4_tcp_counter_t *tcp_counter;
+ nat64_v6_to_v4_udp_counter_t *udp_counter;
+ nat64_v6_to_v4_icmp_counter_t *icmp_counter;
+ nat64_v6_to_v4_icmp_error_counter_t *icmp_error_counter;
+ nat64_frag_counter_t *frag_counter;
+ nat64_options_counter_t *options_counter;
+ } nat64_ctr_u;
+ nat64_icmp_gen_counter_t *icmp_gen_counter;
+} nat64_v6_to_v4_pipeline_data_t;
+
+
+typedef struct nat64_v4_to_v6_pipeline_data_ {
+ nat64_common_pipeline_data_t common_data;
+
+ u32 bib_bucket;
+ u32 session_bucket;
+
+ nat64_v4_key_t v4_src_key; /* Will be translated using Prefix */
+ nat64_v4_key_t v4_dest_key; /* will be the out key for NAT64 */
+
+ /*
+ * IPv4 data
+ */
+ u8 version_hdr_len_words;
+ u8 tos;
+ u16 total_len_bytes;
+
+ u16 identification;
+ u16 frag_flags_offset;
+
+ u8 ttl;
+ u8 protocol;
+ u16 l4_checksum;
+
+ u32 ipv4_src_addr;
+ u32 ipv4_dst_addr;
+
+ /*
+ * Pointers to IPv6 headers
+ */
+ ipv6_header_t *ipv6_header;
+ ipv6_frag_header_t *ipv6_frag_header;
+
+ union {
+ struct _v6_l4_info {
+ u8 *ipv6_l4_header;
+ u8 pad0;
+ u8 pad1;
+ u8 pad2;
+ u8 pad3;
+ } v6_l4_info;
+ struct _v6_icmp_info {
+ icmp_v6_t *ipv6_icmp_header;
+ u8 old_icmp_type;
+ u8 new_icmp_type;
+ u8 old_icmp_code;
+ u8 new_icmp_code;
+ u16 old_iden; // length (ICMP extn), ptr (param)
+ u16 new_iden; // ----- do -------------
+ u16 old_seq; // MTU for PTB case
+ u16 new_seq; // ----- do -------------
+ } v6_icmp_info;
+ struct _v6_udp_info {
+ udp_hdr_type_t *ipv6_udp_header;
+ u8 pad0;
+ u8 pad1;
+ u8 pad2;
+ u8 pad3;
+ } v6_udp_info;
+ struct _v6_tcp_info {
+ tcp_hdr_type *ipv6_tcp_header;
+ u16 old_dest_port;
+ u16 new_dest_port;
+ u16 src_port;
+ nat64_tcp_events tcp_event;
+ } v6_tcp_info;
+ } l4_u;
+
+ l4_frag_info_t *frag_info; /* port for tcp/udp, ident - icmp */
+
+ /* Need to add counters here */
+ union {
+ nat64_v4_to_v6_tcp_counter_t *tcp_counter;
+ nat64_v4_to_v6_udp_counter_t *udp_counter;
+ nat64_v4_to_v6_icmp_counter_t *icmp_counter;
+ nat64_v4_to_v6_icmp_error_counter_t *icmp_error_counter;
+ nat64_frag_counter_t *frag_counter;
+ nat64_options_counter_t *options_counter;
+ } nat64_ctr_u;
+ nat64_icmp_gen_counter_t *icmp_gen_counter;
+
+} nat64_v4_to_v6_pipeline_data_t;
+
+#endif
diff --git a/vpp/plugins/vcgn-plugin/vcgn/nat64_tcp_sm.h b/vpp/plugins/vcgn-plugin/vcgn/nat64_tcp_sm.h
new file mode 100644
index 00000000..3a505bc1
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/nat64_tcp_sm.h
@@ -0,0 +1,91 @@
+/*
+ *------------------------------------------------------------------
+ * nat64_tcp_sm.h - Stateful NAT64 translation TCP State machine
+ *
+ * Copyright (c) 2011 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+#ifndef __NAT64_TCP_SM_H__
+#define __NAT64_TCP_SM_H__
+
+
+/* TCP States */
+typedef enum {
+ TCP_CLOSED,
+ TCP_V4_INIT,
+ TCP_V6_INIT,
+ TCP_ESTABLISHED,
+ TCP_V4_FIN_RCV,
+ TCP_V6_FIN_RCV,
+ TCP_V4V6_FIN_RCV,
+ TCP_TRANS,
+ TCP_NONE
+} nat64_tcp_states;
+
+/* TCP Events */
+typedef enum {
+ TCP_TIMEOUT_EV,
+ TCP_V6_SYN_EV,
+ TCP_V4_SYN_EV,
+ TCP_V6_FIN_EV,
+ TCP_V4_FIN_EV,
+ TCP_V6_RST_EV,
+ TCP_V4_RST_EV,
+ TCP_DEFAULT_EV,
+ TCP_EV_COUNT
+} nat64_tcp_events;
+
+/* TCP Actions */
+typedef enum {
+ TCP_FORWARD,
+ TCP_COND_FORWARD, /* Conditional forward, based on presence of
+ * session and bib entries */
+ TCP_STORE,
+ TCP_PROBE,
+ TCP_CREATE_SESSION,
+ TCP_DELETE_SESSION,
+ TCP_DROP,
+ TCP_ACTION_NONE,
+ TCP_ACTION_COUNT
+} nat64_tcp_actions;
+
+typedef struct {
+ nat64_tcp_states next_state;
+ nat64_tcp_actions action;
+} nat64_tcp_trans_t;
+
+typedef struct {
+ nat64_tcp_trans_t event[TCP_EV_COUNT];
+} nat64_tcp_state_trans_t;
+
+extern nat64_tcp_state_trans_t nat64_tcp_sm_lookup[TCP_NONE];
+
+/*
+inline void
+nat64_update_v6_to_v4_tcp (nat64_v6_to_v4_pipeline_data_t *pctx_ptr,
+ nat64_bib_entry_t *bib_ptr);
+
+inline u8 nat64_v6_to_v4_tcp_perform_action (
+ spp_ctx_t *ctx,
+ nat64_v6_to_v4_pipeline_data_t *pctx_ptr,
+ nat64_bib_entry_t *bib_db,
+ nat64_session_entry_t *session_db);
+
+inline void
+nat64_copy_tcp_into_pctx (nat64_v6_to_v4_pipeline_data_t *pctx_ptr);
+*/
+
+
+
+#endif
diff --git a/vpp/plugins/vcgn-plugin/vcgn/platform_common.h b/vpp/plugins/vcgn-plugin/vcgn/platform_common.h
new file mode 100644
index 00000000..2805b607
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/platform_common.h
@@ -0,0 +1,136 @@
+/*
+ *---------------------------------------------------------------------------
+ * platform_common.h -- file has all platform related macros defined as NULL
+ * included "platform_common_override.h will have actual
+ * platform specific defines
+ *
+ * Copyright (c) 2011-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+#ifndef __PLATFORM_COMMON_H__
+#define __PLATFORM_COMMON_H__
+
+/* $$$ FIXME causes printf format warnings */
+#define PLATFORM_DEBUG_PRINT(...) /* printf(__VA_ARGS__) */
+#define PLATFORM_FILL_DST_ADDR_PORT_TABLE
+#define PLATFORM_SET_CTX_RU_TX_FROM_NODE(ctx, value)
+#define PLATFORM_SET_CTX_RU_TX_DST_IPPORT_IDX(ctx, value)
+#define PLATFORM_SET_CTX_RU_TX_PKT_TYPE(ctx, type)
+#define PLATFORM_SET_RX_VRF(ctx, rx_vrf, hardcode, mask)
+#define PLATFORM_SET_TX_VRF(ctx, tx_vrf)
+/* PLATFORM_CNAT_SET_RX_VRF definition is not same as PLATFORM_SET_RX_VRF,
+ * So, maintaining two different definitions
+ */
+#define PLATFORM_CNAT_SET_RX_VRF(ctx, rx_vrf, proto)
+#define PLATFORM_CNAT_SET_TX_VRF(ctx, tx_vrf)
+
+#define PLATFORM_PRINT_TESTING_PG()
+#define PLATFORM_INIT_TEMP_SENSORS()
+#define PLATFORM_READ_CPU_SENSORS(value)
+#define PLATFORM_SET_TEMP_READ_BLOCK(var, val)
+#define PLATFORM_NFV9_DISP_NODE_IDX
+
+
+/* Assumption is, syslog packets
+ * are sent out via same channel as that of NFV9.
+ * Has to be overridden if this assumption is false.
+ */
+#define PLATFORM_SYSLOG_DISP_NODE_IDX PLATFORM_NFV9_DISP_NODE_IDX
+
+#define PLATFORM_CNAT_DB_DUMP_POLICY_PRINT()
+#define PLATFORM_PRINT_CTX_VALUES(ctx)
+#define PLATFORM_ADD_VRF_MAP_HANDLE_PARTITION(uidb_index, partition_id)
+#define PLATFORM_DEL_VRF_MAP_HANDLE_PARTITION(uidb_index, partition_id)
+#define PLATFORM_ALLOC_NFV9_PKT_BUFFER(ctx, to_lc_cpu)
+#define PLATFORM_SET_DSLITE_ENABLE_FLAG(uidb_index, dslite_id)
+#define PLATFORM_CHECK_DSLITE_ENABLE_FLAG
+
+#define PLATFORM_CNAT_INSTS 1
+#define PLATFORM_HANDLE_TTL_DECREMENT 0 // Don't handle TTL in NAT44 Application (default).
+
+// For ISM, we need to copy the ipv6->hop_limit to ipv4 ttl.
+#define PLATFORM_6RD_COPY_TTL_IPV6_TO_IPV4 0
+
+//For ISM case, need to allow as the TTL decrement happens at ingress LC
+#define PLATFORM_6RD_ALLOW_TTL_1 0
+
+#define PLATFORM_HANDLE_ICMP_TTL_EXPIRED 0 // Don't handle ICMP_ERROR msg for TTL <=1 in NAT44 App (default).
+
+#define PLATFORM_IPV4_FRAG_FRAG_HOLD_LIMIT 1
+#define PLATFORM_MAX_IPV4_CTX_ENTRIES 1
+#define PLATFORM_MAPE_FRAG 0
+
+#define PLATFORM_ADDR_MASK_PER_CORE 0
+#define PLATFORM_ADDR_MASK_PER_CORE_PER_PARTITION 0
+#define PLATFORM_MAX_CORES 1
+#define PLATFORM_MAX_CORES_PER_PARTITION 1
+#define PLATFORM_MAX_NAT_ENTRIES 1
+#define PLATFORM_MAX_USER_ENTRIES 1
+#define PLATFORM_CNAT_MAX_ADDR_POOL_SIZE 0x1
+#define PLATFORM_DBL_SUPPORT 0 /* Default no DBL support, no NAT44 session table */
+
+#define PLATFORM_MAX_DB_ENTRY_PER_SCAN 1
+#define PLATFORM_MAX_DB_ENTRY_SELECTED_PER_SCAN 1
+#define MAX_COMBINED_DB_ENTRIES_PER_SCAN 0
+
+#define PLATFORM_CNAT_TIMEOUT_IPPROT_MASK 0
+#define PLATFORM_CNAT_TIMEOUT_PORTPROT_MASK 0
+
+#define PLATFORM_MAX_SHOW_BUFFER_SIZE 1700
+#define PLATFORM_MAX_TRANSLATION_ENTRIES (50)
+#define PLATFORM_MAX_UTIL_ENTRIES (100)
+#define PLATFORM_MAX_NAT44_UTIL_ENTRIES ((64)/PLATFORM_MAX_CORES)
+
+#define PLATFORM_CNAT_NFV9_SHIM_HDR_OFFSET 0
+#define PLATFORM_CNAT_NFV9_L2_ENCAPS_OFFSET 0
+
+
+/* Below are nat64 statful related define */
+#define PLATFORM_NAT64_SET_RX_VRF(rx_vrf, proto, inst_id) \
+ rx_vrf = proto | (inst_id & CNAT_VRF_MASK);
+
+#define PLATFORM_NAT64_MAX_TRANSLATION_ENTRIES (30)
+#define PLATFORM_DS_LITE_MAX_TRANSLATION_ENTRIES (30)
+
+#define PLATFORM_SET_NAT64_ENABLE_FLAG(uidb_index, nat64_id) \
+ { \
+ nat64_set_enable_flag(nat64_id, ENABLE); \
+ }
+
+#define PLATFORM_CHECK_NAT64_ENABLE_FLAG 1
+#define PLATFORM_SET_MAPE_ENABLE_FLAG(uidb_index, mape_id)
+#define PLATFORM_CHECK_MAPE_ENABLE_FLAG 1
+
+/* very small number , PD has correct value.
+ this is bcoz, if platform doesnt support nat64..shudnt take too much..*/
+#define PLATFORM_NAT64_MAX_SESSIONS 10
+#define PLATFORM_NAT64_TIMEOUT_HASH_SIZE 10
+#define PLATFORM_MAP_ADDR_PER_CORE 1024
+
+#define ENABLE 1
+#define DISABLE 0
+
+/* Platform Xlat inline learn function */
+#define PLATFORM_INLINE_LEARN_FUNC(a,b,c)
+
+
+/* Checksum calculation to be done in software */
+#define PLATFORM_XLAT_SW_CHECKSUM_CALC 0
+
+
+/* Below include overrides all the above null defs and defines platform specific
+ define */
+#include "platform_common_override.h"
+
+#endif /* __PLATFORM_COMMON_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/platform_common_override.h b/vpp/plugins/vcgn-plugin/vcgn/platform_common_override.h
new file mode 100644
index 00000000..d6d3b078
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/platform_common_override.h
@@ -0,0 +1,304 @@
+/*
+ *---------------------------------------------------------------------------
+ * platform_common_override.h -- Files has actual platform specific defines.
+ * Will only included by platform_common.h
+ *
+ * Copyright (c) 2011-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+
+#ifndef __PLATFORM_COMMON_OVERRIDE_H__
+#define __PLATFORM_COMMON_OVERRIDE_H__
+
+extern unsigned char my_octeon_id;
+
+#undef PLATFORM_DBL_SUPPORT
+#define PLATFORM_DBL_SUPPORT 1 // Destination Based logging support
+ // NAT44 session table required.
+
+#undef PLATFORM_ADDR_MASK_PER_CORE
+/* commenting this. Currently we are considering only single core */
+//#define PLATFORM_ADDR_MASK_PER_CORE 0x3f // Using 64 cores
+#define PLATFORM_ADDR_MASK_PER_CORE 0x01
+
+#undef MAX_COMBINED_DB_ENTRIES_PER_SCAN
+#define MAX_COMBINED_DB_ENTRIES_PER_SCAN 128
+
+#undef PLATFORM_MAX_CORES
+#define PLATFORM_MAX_CORES (PLATFORM_ADDR_MASK_PER_CORE + 1)
+
+// Roddick does not have any partition of cores
+#undef PLATFORM_ADDR_MASK_PER_CORE_PER_PARTITION
+#define PLATFORM_ADDR_MASK_PER_CORE_PER_PARTITION \
+ PLATFORM_ADDR_MASK_PER_CORE
+
+#undef PLATFORM_MAX_CORES_PER_PARTITION
+#define PLATFORM_MAX_CORES_PER_PARTITION PLATFORM_MAX_CORES
+
+#undef PLATFORM_CNAT_INSTS
+//#define PLATFORM_CNAT_INSTS 64
+#define PLATFORM_CNAT_INSTS 1 /* currently its only single instance */
+
+#undef PLATFORM_MAX_NAT_ENTRIES
+//#define PLATFORM_MAX_NAT_ENTRIES 20000000 // 20M
+#define PLATFORM_MAX_NAT_ENTRIES 1666660 // ~80M/48 (79999680/48)
+
+#undef PLATFORM_MAX_USER_ENTRIES
+#define PLATFORM_MAX_USER_ENTRIES 20800 // ~1M/48 (998400/48)
+
+
+/* 524288:
+ (20000000 translations) / (64 CNAT INSTANCES) = 312500
+ nearest higher number which is power of 2 next to 312500
+*/
+#undef PLATFORM_CNAT_MAIN_PRELIM_HASH_SIZE
+//#define PLATFORM_CNAT_MAIN_PRELIM_HASH_SIZE 524288
+#define PLATFORM_CNAT_MAIN_PRELIM_HASH_SIZE (5<<20)
+/* 4096:
+ (200000 users) / (64 CNAT INSTANCES) = 3125
+ nearest higher number which is power of 2 next to 3125
+*/
+#undef PLATFORM_CNAT_USER_PRELIM_HASH_SIZE
+#define PLATFORM_CNAT_USER_PRELIM_HASH_SIZE 4096
+
+#undef PLATFORM_CNAT_MAX_ADDR_POOL_SIZE
+#define PLATFORM_CNAT_MAX_ADDR_POOL_SIZE 0x10000 // max /16
+
+#undef PLATFORM_MAX_DB_ENTRY_PER_SCAN
+#define PLATFORM_MAX_DB_ENTRY_PER_SCAN 400
+
+#undef PLATFORM_MAX_DB_ENTRY_SELECTED_PER_SCAN
+#define PLATFORM_MAX_DB_ENTRY_SELECTED_PER_SCAN 100 // 1/4th of above
+
+#undef PLATFORM_CNAT_TIMEOUT_IPPROT_MASK
+#define PLATFORM_CNAT_TIMEOUT_IPPROT_MASK 0xFFFFFFFF0000FFFF
+
+#undef PLATFORM_CNAT_TIMEOUT_PORTPROT_MASK
+#define PLATFORM_CNAT_TIMEOUT_PORTPROT_MASK 0x00000000FFFFFFFF
+
+#ifdef TARGET_RODDICK /* EVB doesnt need it */
+#undef PLATFORM_FILL_DST_ADDR_PORT_TABLE
+#define PLATFORM_FILL_DST_ADDR_PORT_TABLE fill_dst_addr_port_table();
+#endif
+
+
+#ifndef RODDICK_ON_LINUX_OR_EVB
+#undef PLATFORM_SET_CTX_RU_TX_FROM_NODE
+#undef PLATFORM_SET_CTX_RU_TX_DST_IPPORT_IDX
+#undef PLATFORM_SET_CTX_RU_TX_PKT_TYPE
+
+#define PLATFORM_SET_CTX_RU_TX_FROM_NODE(ctx, value) \
+ (vnet_buffer(ctx))->vcgn_uii.ru.tx.from_node = value;
+#define PLATFORM_SET_CTX_RU_TX_DST_IPPORT_IDX(ctx, value) \
+ (vnet_buffer(ctx))->vcgn_uii.ru.tx.dst_ip_port_idx = value;
+#define PLATFORM_SET_CTX_RU_TX_PKT_TYPE(ctx, type) \
+ (vnet_buffer(ctx))->vcgn_uii.ru.tx.packet_type = type;
+#endif
+
+#undef PLATFORM_SET_RX_VRF
+#undef PLATFORM_SET_TX_VRF
+#ifdef TARGET_RODDICK
+#define PLATFORM_SET_RX_VRF(ctx, rx_vrf, hardcode, mask) \
+ rx_vrf = (ctx->ru.rx.uidb_index & CNAT_VRF_MASK);
+#define PLATFORM_SET_TX_VRF(ctx, tx_vrf) \
+ ctx->ru.tx.uidb_index = tx_vrf;
+#else /*EVB */
+#define PLATFORM_SET_RX_VRF(ctx, rx_vrf, hardcode, mask) \
+ rx_vrf = hardcode;
+#define PLATFORM_SET_TX_VRF(ctx, tx_vrf)
+#endif
+
+#undef PLATFORM_CNAT_SET_RX_VRF
+#undef PLATFORM_CNAT_SET_TX_VRF
+
+#define PLATFORM_CNAT_SET_RX_VRF(if_index, rx_vrf, proto) \
+ rx_vrf = proto | ((if_index) & CNAT_VRF_MASK);
+
+#define PLATFORM_CNAT_SET_TX_VRF(if_index, tx_vrf) \
+ (if_index) = ((tx_vrf) & CNAT_VRF_MASK);
+
+
+
+#undef PLATFORM_NAT64_SET_RX_VRF
+
+#ifdef TARGET_RODDICK
+
+#define PLATFORM_NAT64_SET_RX_VRF(rx_vrf, proto, inst_id) \
+ rx_vrf = proto | (inst_id & CNAT_VRF_MASK);
+
+#else /* EVB */
+
+#define PLATFORM_NAT64_SET_RX_VRF(rx_vrf, proto, inst_id) \
+ rx_vrf = proto | inst_id;
+
+#endif
+
+#ifdef TARGET_EVB
+#define VRF_MAP_CONFIG
+#endif
+
+#undef PLATFORM_PRINT_TESTING_PG
+#if defined(TARGET_LINUX_UDVR) || defined(CNAT_PG)
+#define PLATFORM_PRINT_TESTING_PG() printf("testing pg\n");
+#else
+#define PLATFORM_PRINT_TESTING_PG()
+#endif
+
+#ifdef TARGET_RODDICK
+#undef PLATFORM_INIT_TEMP_SENSORS
+#undef PLATFORM_READ_CPU_SENSORS
+#undef PLATFORM_SET_TEMP_READ_BLOCK
+
+#define PLATFORM_INIT_TEMP_SENSORS() Init_temperature_sensors();
+#define PLATFORM_READ_CPU_SENSORS(value) read_octeon_sensors(value);
+#define PLATFORM_SET_TEMP_READ_BLOCK(var, val) var = &val->param[0];
+#endif
+
+#undef PLATFORM_HANDLE_ICMP_TTL_EXPIRED
+#define PLATFORM_HANDLE_ICMP_TTL_EXPIRED 1 // handle TTL in NAT44 Application (for AVSM)
+
+#undef PLATFORM_NFV9_DISP_NODE_IDX
+#ifdef TARGET_RODDICK
+#define PLATFORM_NFV9_DISP_NODE_IDX "roddick_infra_l3_tx"
+#else /* EVB */
+#define PLATFORM_NFV9_DISP_NODE_IDX "cnat_rewrite_output"
+#endif
+
+#undef PLATFORM_CNAT_DB_DUMP_POLICY_PRINT
+#define PLATFORM_CNAT_DB_DUMP_POLICY_PRINT() \
+ printf("my instance:%d\n" \
+ "icmp timeout %d udp init timeout %d act timeout %d\n" \
+ "tcp init timeout %d act timeout %d mapping refresh %d\n" \
+ "port limit per user %d ftp alg %d lb debug %d\n" \
+ "icmp rate limit 0x%x config delete timer 0x%x\n" \
+ "global debug flag 0x%x\n" \
+ "icmp rate limit (pkts/per sec) %d\n" \
+ "dynamic port range start %d\n" \
+ "debug ivrf 0x%x flag 0x%x start_addr 0x%x end_addr 0x%x\n" \
+ "debug ovrf 0x%x flag 0x%x start_addr 0x%x end_addr 0x%x\n", \
+ my_instance_number, \
+ icmp_session_timeout, udp_init_session_timeout, udp_act_session_timeout, \
+ tcp_initial_setup_timeout, tcp_active_timeout, \
+ mapping_refresh_both_direction, cnat_main_db_max_ports_per_user, \
+ ftp_alg_enabled, lb_debug_enable, per_user_icmp_msg_limit, \
+ config_delete_timeout, \
+ global_debug_flag, \
+ cnat_main_db_icmp_rate_limit, \
+ cnat_static_port_range, \
+ debug_i_vrf, debug_i_flag, debug_i_addr_start, debug_i_addr_end, \
+ debug_o_vrf, debug_o_flag, debug_o_addr_start, debug_o_addr_end);
+
+
+#undef PLATFORM_PRINT_CTX_VALUES
+#ifdef TARGET_RODDICK
+#define PLATFORM_PRINT_CTX_VALUES(ctx) \
+ printf("\nAFTER: %s cur_hdr %p, uidb %d, pkt_type %d, cur_len %d\n", \
+ type_str, \
+ ctx->current_header, \
+ ctx->ru.tx.uidb_index, \
+ ctx->ru.tx.packet_type, \
+ ctx->current_length);
+#else /* EVB */
+#define PLATFORM_PRINT_CTX_VALUES(ctx) \
+ printf("\nAFTER: %s cur_hdr %p, cur_len %d\n", \
+ type_str,\
+ ctx->current_header, \
+ ctx->current_length);
+#endif
+
+#undef PLATFORM_ADD_VRF_MAP_HANDLE_PARTITION
+#define PLATFORM_ADD_VRF_MAP_HANDLE_PARTITION(uidb_index, partition_id)
+
+#undef PLATFORM_DEL_VRF_MAP_HANDLE_PARTITION
+#define PLATFORM_DEL_VRF_MAP_HANDLE_PARTITION(uidb_index, partition_id)
+
+#undef PLATFORM_ALLOC_NFV9_PKT_BUFFER
+#define PLATFORM_ALLOC_NFV9_PKT_BUFFER(ctx, to_lc_cpu)
+
+#undef PLATFORM_CNAT_NFV9_SHIM_HDR_OFFSET
+#ifdef TARGET_RODDICK
+// This corresponds to the length of the IMETRO SHIM Header for RODDICK
+#define PLATFORM_CNAT_NFV9_SHIM_HDR_OFFSET 8
+#else
+#define PLATFORM_CNAT_NFV9_SHIM_HDR_OFFSET 0
+#endif
+
+#undef PLATFORM_CNAT_NFV9_L2_ENCAPS_OFFSET
+#ifdef TARGET_RODDICK
+#define PLATFORM_CNAT_NFV9_L2_ENCAPS_OFFSET 0
+#else
+#define PLATFORM_CNAT_NFV9_L2_ENCAPS_OFFSET 16
+#endif
+
+#undef PLATFORM_MAX_SHOW_BUFFER_SIZE
+#undef PLATFORM_MAX_TRANSLATION_ENTRIES
+#undef PLATFORM_MAX_UTIL_ENTRIES
+
+#define PLATFORM_MAX_SHOW_BUFFER_SIZE 1700
+#define PLATFORM_MAX_TRANSLATION_ENTRIES (50)
+#define PLATFORM_NAT64_MAX_TRANSLATION_ENTRIES (30)
+#define PLATFORM_MAX_UTIL_ENTRIES (100)
+
+
+#undef PLATFORM_NAT64_MAX_SESSIONS
+#undef PLATFORM_NAT64_TIMEOUT_HASH_SIZE
+#define PLATFORM_NAT64_MAX_SESSIONS 20000000
+#define PLATFORM_NAT64_TIMEOUT_HASH_SIZE 24001 /* Ref: CSCtr36242 */
+
+#undef PLATFORM_CHECK_DSLITE_ENABLE_FLAG
+#define PLATFORM_CHECK_DSLITE_ENABLE_FLAG 1
+
+/* Fragment hold limit is Platform specific */
+/* For Roddick, it is 63 due to hardware limitation */
+#undef PLATFORM_IPV4_FRAG_FRAG_HOLD_LIMIT
+#define PLATFORM_IPV4_FRAG_FRAG_HOLD_LIMIT 63
+
+#undef PLATFORM_MAX_IPV4_CTX_ENTRIES
+#define PLATFORM_MAX_IPV4_CTX_ENTRIES 80
+
+#undef PLATFORM_DIRN_IN_TO_OUT
+#undef PLATFORM_DIRN_OUT_TO_IN
+#undef PLATFORM_SET_SVI_PARAMS_FIELD
+
+#define PLATFORM_DIRN_IN_TO_OUT
+#define PLATFORM_DIRN_OUT_TO_IN
+#define PLATFORM_SET_SVI_PARAMS_FIELD(var, value)
+
+#undef PLATFORM_GET_NFV9_L3_HDR_OFFSET
+#define PLATFORM_GET_NFV9_L3_HDR_OFFSET \
+ ((u8 *)ctx + ctx->data + CNAT_NFV9_IP_HDR_OFFSET);
+
+#undef PLATFORM_GET_NFV9_L4_HDR_OFFSET
+#define PLATFORM_GET_NFV9_L4_HDR_OFFSET \
+ ((u8 *) ctx + ctx->data + CNAT_NFV9_UDP_HDR_OFFSET);
+
+#undef PLATFORM_MEMSET_CNAT_LOG_PKT_DATA
+#define PLATFORM_MEMSET_CNAT_LOG_PKT_DATA
+
+/*
+ Index 0 -- SE_P2MP
+ Index 1 -- HA Destination 1
+ Index 2 -- HA Destination 2
+ Index 3 -- EXT_LOG_SRVR
+*/
+enum {
+ NODE_CGNCFG,
+ NODE_HA,
+ NODE_PD_CONFIG,
+ NODE_LOGGING,
+ NODE_TRACE_BACKUP,
+ NODE_MAX,
+};
+
+#endif /* __PLATFORM_COMMON_OVERRIDE_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/spp_ctx.h b/vpp/plugins/vcgn-plugin/vcgn/spp_ctx.h
new file mode 100644
index 00000000..2d3c95c8
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/spp_ctx.h
@@ -0,0 +1,76 @@
+/*
+ *------------------------------------------------------------------
+ * spp_ctx.h - packet / context definitions
+ *
+ * Copyright (c) 2007-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __SPP_CTX_H__
+#define __SPP_CTX_H__
+
+/* Packet header / data */
+
+/* Any change to spp_ctx_t structure should be updated in vnet/buffer.h
+ * as well.
+ */
+typedef struct _spp_ctx {
+#ifdef TOBE_PORTED
+ /* Following fields are required to handle multibuffer */
+ u32 num_buffers; /* Number of buffers part of packet */
+ vlib_buffer_t *next_ctx_this_packet;
+
+ /* Following is used by non-UDP protocols */
+#define SPP_CTX_FEATURE_DATA_SIZE 16
+
+ u8 feature_data[SPP_CTX_FEATURE_DATA_SIZE];
+#endif
+
+ union { /* Roddick specific */
+ u32 roddick_info;
+ struct __tx_pkt_info { /* Used by PI to PI communication for TX */
+ u32 uidb_index:16; /* uidb_index to transmit */
+ u32 packet_type:2; /* 1-IPv4, 2-Ipv6, - 0,3 - Unused */
+ u32 ipv4_defrag:1; /* 0 - Normal, 1 - update first
+ * segment size
+ * (set by 6rd defrag node)
+ */
+
+ u32 dst_ip_port_idx:4;/* Index to dst_ip_port_table */
+ u32 from_node:4;
+ u32 calc_chksum:1;
+ u32 reserved:4;
+ } tx;
+ struct __rx_pkt_info { /* Used by PD / PI communication */
+ u32 uidb_index:16; /* uidb_index received in packet */
+ u32 packet_type:2; /* 1-IPv4, 2-Ipv6, - 0,3 - Unused */
+ u32 icmp_type:1; /* 0-ICMP query type, 1-ICMP error type */
+ u32 protocol_type:2; /* 1-TCP, 2-UDP, 3-ICMP, 0 - Unused */
+ u32 ipv4_defrag:1; /* 0 - Normal, 1 - update first
+ * segment size
+ * (set by 6rd defrag node)
+ */
+
+ u32 direction:1; /* 0-Outside, 1-Inside */
+ u32 frag:1; /*IP fragment-1, Otherwise-0*/
+ u32 option:1; /* 0-No IP option (v4) present, non-fragHdr
+ * option hdr present (v6)
+ */
+ u32 df_bit:1; /* IPv4 DF bit copied here */
+ u32 reserved1:6;
+ } rx;
+ } ru;
+} spp_ctx_t;
+
+#endif
diff --git a/vpp/plugins/vcgn-plugin/vcgn/spp_platform_trace_log.c b/vpp/plugins/vcgn-plugin/vcgn/spp_platform_trace_log.c
new file mode 100644
index 00000000..a96894f9
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/spp_platform_trace_log.c
@@ -0,0 +1,989 @@
+/*
+ *------------------------------------------------------------------
+ * spp_platform_trace_log.c
+ *
+ * Copyright (c) 2008-2011, 2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *---------------------------------------------------------------------------
+ */
+
+#include <vlib/vlib.h>
+#include <stdio.h>
+#include <vppinfra/vec.h>
+#include <vppinfra/bitmap.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/pool.h>
+#include <vppinfra/clib.h>
+#include <vlib/main.h>
+
+#include "tcp_header_definitions.h"
+#include "platform_common.h"
+#include "spp_platform_trace_log.h"
+
+#define WORD_SIZE sizeof(u32)
+
+int temperature_read_blocked = 1;
+
+spp_cnat_logger_tbl_t spp_cnat_logger_table[] =
+{
+ { CNAT_ERROR_SUCCESS,
+ 3,
+ 0,
+ {"i-vrf",
+ "ipv4 addr",
+ "port"}
+ },
+ { CNAT_NO_CONFIG_ERROR,
+ 3,
+ 180,
+ {"i-vrf",
+ "ipv4 addr",
+ "port"}
+ },
+ { CNAT_NO_VRF_RUN_ERROR,
+ 3,
+ 180,
+ {"i-vrf",
+ "ipv4 addr",
+ "port"}
+ },
+ { CNAT_NO_POOL_FOR_ANY_ERROR,
+ 3,
+ 180,
+ {"i-vrf",
+ "ipv4 addr",
+ "port"}
+ },
+ { CNAT_NO_PORT_FOR_ANY_ERROR,
+ 3,
+ 60,
+ {"i-vrf",
+ "ipv4 addr",
+ "port"}
+ },
+ { CNAT_BAD_INUSE_ANY_ERROR,
+ 3,
+ 60,
+ {"i-vrf",
+ "ipv4 addr",
+ "port"}
+ },
+ { CNAT_NOT_FOUND_ANY_ERROR,
+ 3,
+ 60,
+ {"i-vrf",
+ "ipv4 addr",
+ "port"}
+ },
+ { CNAT_INV_PORT_FOR_DIRECT_ERROR,
+ 3,
+ 60,
+ {"i-vrf",
+ "ipv4 addr",
+ "port"}
+ },
+ { CNAT_BAD_INUSE_DIRECT_ERROR,
+ 3,
+ 1,
+ {"i-vrf",
+ "ipv4 addr",
+ "port"}
+ },
+ { CNAT_NOT_FOUND_DIRECT_ERROR,
+ 3,
+ 1,
+ {"i-vrf",
+ "ipv4 addr",
+ "port"}
+ },
+ { CNAT_OUT_OF_PORT_LIMIT_ERROR,
+ 3,
+ 60,
+ {"i-vrf",
+ "ipv4 addr",
+ "port"}
+ },
+ { CNAT_MAIN_DB_CREATE_ERROR,
+ 0,
+ 30,
+ {""}
+ },
+ { CNAT_LOOKUP_ERROR,
+ 1,
+ 30,
+ {"Type"}
+ },
+ { CNAT_INDEX_MISMATCH_ERROR,
+ 2,
+ 30,
+ {"in2out_index",
+ "out2in_index"}
+ },
+ { CNAT_PACKET_DROP_ERROR,
+ 3,
+ 15,
+ {"i-vrf",
+ "ipv4 addr",
+ "port"}
+ },
+ { CNAT_INV_UNUSED_USR_INDEX,
+ 1,
+ 10,
+ {"invalid/unused user index"}
+ },
+ { CNAT_INVALID_VRFMAP_INDEX,
+ 0,
+ 60,
+ {""}
+ },
+ { CNAT_USER_OUT_OF_PORTS,
+ 2,
+ 1800,
+ {"i-vrf",
+ "ipv4 addr"}
+ },
+ { CNAT_EXT_PORT_THRESH_EXCEEDED,
+ 2,
+ 180,
+ {"i-vrf",
+ "ipv4 address"}
+ },
+ { CNAT_EXT_PORT_THRESH_NORMAL,
+ 2,
+ 180,
+ {"vrf",
+ "ipv4 address"}
+ },
+ { CNAT_NO_EXT_PORT_AVAILABLE,
+ 0,
+ 1,
+ {"",}
+ },
+ { CNAT_SESSION_THRESH_EXCEEDED,
+ 2,
+ 1800,
+ {"vrf",
+ "ipv4 address"}
+ },
+ { CNAT_SESSION_THRESH_NORMAL,
+ 2,
+ 30, /* changed to 30 */
+ {"vrf",
+ "ipv4 address"}
+ },
+ { WQE_ALLOCATION_ERROR,
+ 0,
+ 180, /* changed to 180 */
+ {""}
+ },
+ { ERROR_PKT_DROPPED,
+ 2,
+ 60, /* changed to 60 */
+ {"spi-port",
+ "error-code"}
+ },
+ { SYSMGR_PD_KEY_CREATION_ERROR,
+ 0,
+ 30,
+ {""}
+ },
+ { SYSMGR_PD_SHMEM_ID_ERROR,
+ 0,
+ 1,
+ {""}
+ },
+ { SYSMGR_PD_SHMEM_ATTACH_ERROR,
+ 0,
+ 1,
+ {""}
+ },
+ { OCTEON_CKHUM_SKIPPED,
+ 2,
+ 60, /* changed to 60 */
+ {"version",
+ "protocol"}
+ },
+ { PK0_SEND_STATUS,
+ 1,
+ 15,
+ {"status"}
+ },
+ { CMD_BUF_ALLOC_ERR,
+ 0,
+ 60,
+ {""}
+ },
+ { SPP_CTX_ALLOC_FAILED,
+ 1,
+ 300, /* every 5 min */
+ {"node"}
+ },
+ { SPP_MAX_DISPATCH_REACHED,
+ 1,
+ 60,
+ {"node"}
+ },
+ { HA_SIGCHILD_RECV,
+ 3,
+ 1,
+ {"pid",
+ "uid",
+ "signal",}
+ },
+ { SIGACTION_ERR,
+ 0,
+ 1,
+ {""}
+ },
+ { HA_INVALID_SEQ_OR_CONFIG_OR_TYPE,
+ 2,
+ 10,
+ {"seq-id or config option",
+ "Type"}
+ },
+ { NODE_CREATION_ERROR,
+ 1,
+ 1,
+ {"node"}
+ },
+
+ { CNAT_CLI_INVALID_INPUT,
+ 4,
+ 0,
+ {"Error Type",
+ "Passed",
+ "Expected",
+ "Type"}
+ },
+ { CNAT_DUMMY_HANDLER_HIT,
+ 1,
+ 0,
+ {"Handler"}
+ },
+ { CNAT_CONFIG_ERROR,
+ 5,
+ 0,
+ {"Sub code",
+ "Param 1",
+ "Param 2",
+ "Param 3",
+ "Param 4"}
+ },
+ { CNAT_NFV9_ERROR,
+ 1,
+ 180, /* changed to 180 */
+ {"Sub code"}
+ },
+ { CNAT_CMVX_TWSI_READ_WRITE_FAIL,
+ 3,
+ 180,
+ {"Operation",
+ "Location",
+ "Data"}
+ },
+ { CNAT_TEMP_SENSOR_TIMEOUT,
+ 0,
+ 180,
+ {""}
+ },
+ { CNAT_TEMP_SENSOR_DATA_MISMATCH,
+ 2,
+ 180,
+ {"Actual",
+ "Expected"}
+ },
+ { CNAT_TEMP_SENSOR_CONFIG_FAILED,
+ 1,
+ 180,
+ {"Glik"}
+ },
+ { HA_APP_NOT_RESPONDING,
+ 2,
+ 180,
+ {"CPU",
+ "Core"}
+ },
+ { HA_DATA_PATH_TEST_FAILED,
+ 0,
+ 30,
+ {""}
+ },
+ { CNAT_WRONG_PORT_ALLOC_TYPE,
+ 3,
+ 60,
+ {"i-vrf",
+ "ipv4 addr",
+ "port"}
+ },
+ { CNAT_NEW_PORT_ALLOC_ERROR,
+ 3,
+ 60,
+ {"i-vrf",
+ "ipv4 addr",
+ "port"}
+ },
+ { CNAT_INVALID_INDEX_TO_FREE_PORT,
+ 0,
+ 60,
+ {""}
+ },
+ { CNAT_DELETE_DB_ENTRY_NO_PORTMAP,
+ 0,
+ 60,
+ {""}
+ },
+ { CNAT_MAIN_DB_LIMIT_ERROR,
+ 0,
+ 180,
+ {""}
+ },
+ { CNAT_USER_DB_LIMIT_ERROR,
+ 0,
+ 180,
+ {""}
+ },
+ { CNAT_FRAG_DB_ERROR,
+ 1,
+ 180,
+ {"Type"}
+ },
+
+ { DROP_PKT_DUMP,
+ 0,
+ 20,
+ {""}
+ }
+};
+
+#define LOG_TABLE_MAX_ENTRIES \
+ (sizeof(spp_cnat_logger_table)/sizeof(spp_cnat_logger_table[0]))
+
+u32 error_code_timestamps[LOG_TABLE_MAX_ENTRIES];
+spp_timer_t sensor_timer;
+spp_trace_log_global_info_t spp_trace_log_global_info;
+spp_global_counters_t spp_global_counters;
+
+/*
+ * Logging information structures
+ */
+spp_trace_log_info_t spp_default_trace_log_info;
+spp_trace_log_info_t *spp_trace_log_info_pool;
+
+#ifdef TOBE_PORTED
+/*
+ * The following 2 functions are temporary hacks until
+ * we have RTC support from the PD nodes
+ */
+inline
+u32 spp_trace_log_get_sys_up_time_in_ms (void)
+{
+ spp_node_main_vector_t *nmv;
+ u32 sys_up_time;
+
+ nmv = spp_get_node_main_vectorized_inline();
+
+ sys_up_time = (u32) (nmv->ticks / nmv->ticks_per_ms);
+
+ return (sys_up_time);
+}
+
+u32 spp_trace_log_get_unix_time_in_seconds (void)
+{
+ spp_node_main_vector_t *nmv;
+ u32 unix_time;
+
+ nmv = spp_get_node_main_vectorized_inline();
+
+ unix_time = (u32) (nmv->ticks / nmv->ticks_per_second);
+
+ return (unix_time);
+}
+
+/*
+ * edt: * * spp_trace_log_send_queued_pkt
+ *
+ * Tries to send a logging pkt that has been queued earlier
+ * because it could not be sent due to downstream constipation
+ *
+ * Argument: spp_trace_log_info_t *trace_logging_info
+ * structure that contains the packet context
+ */
+inline
+void spp_trace_log_send_queued_pkt (spp_trace_log_info_t *trace_logging_info)
+{
+ spp_node_t *output_node;
+
+ output_node = spp_get_nodes() +
+ spp_trace_log_global_info.spp_trace_log_disp_node_index;
+
+ if (PREDICT_TRUE(output_node->sf.nused < SPP_MAXDISPATCH)) {
+ /*
+ * Move the logging context to output node
+ */
+ spp_dispatch_make_node_runnable(output_node);
+ output_node->sf.ctxs[output_node->sf.nused++] =
+ trace_logging_info->queued_logging_context;
+
+ /*
+ * Context has been queued, it will be freed after the pkt
+ * is sent. Clear this from the logging_context_info structure
+ */
+ trace_logging_info->queued_logging_context = NULL;
+
+ } else {
+ /*
+ * Can't do much, just return, may be we can send it later
+ */
+ spp_global_counters.spp_trace_log_downstream_constipation_count++;
+ }
+}
+
+/*
+ * edt: * * spp_trace_log_send_pkt
+ *
+ * Tries to send a logging pkt. If the packet cannot be sent
+ * because of rewrite_output node cannot process it, queue
+ * it temporarily and try to send it later.
+ *
+ * Argument: spp_trace_log_info_t *trace_logging_info
+ * structure that contains the packet context
+ */
+inline
+void spp_trace_log_send_pkt (spp_trace_log_info_t *trace_logging_info)
+{
+ spp_node_t *output_node;
+
+
+ output_node = spp_get_nodes() +
+ spp_trace_log_global_info.spp_trace_log_disp_node_index;
+
+ if (PREDICT_TRUE(output_node->sf.nused < SPP_MAXDISPATCH)) {
+ /*
+ * Move the logging context to output node
+ */
+ spp_dispatch_make_node_runnable(output_node);
+ output_node->sf.ctxs[output_node->sf.nused++] =
+ trace_logging_info->current_logging_context;
+
+ } else {
+ /*
+ * Queue the context into the logging_info structure,
+ * We will try to send it later. Currently, we will
+ * restrict to only one context queued.
+ */
+ spp_global_counters.spp_trace_log_downstream_constipation_count++;
+
+ /*
+ * Attach the current logging context which is full to the
+ * queued context list in trace_logging_info structure
+ */
+ trace_logging_info->queued_logging_context =
+ trace_logging_info->current_logging_context;
+
+ /*
+ * Whether the context is queued or not, set the current context index
+ * to EMPTY, as the earlier context can no more be used to send
+ * more logging records.
+ */
+ }
+
+ trace_logging_info->current_logging_context = NULL;
+}
+
+/*
+ * edt: * * spp_trace_log_send_pkt_always_success
+ *
+ * Tries to send a logging pkt. This cannot fail due to downstream
+ * constipation because we have already checked if the rewrite_output
+ * node can accept it.
+ *
+ * Argument: spp_trace_log_info_t *trace_logging_info
+ * structure that contains the packet context
+ *
+ * Argument: spp_node_t *output_node
+ * spp_node_t structure for rewrite_output node
+ */
+inline
+void spp_trace_log_send_pkt_always_success (
+ spp_trace_log_info_t *trace_logging_info,
+ spp_node_t *output_node)
+{
+ /*
+ * At this point we either have a current or queued logging context
+ */
+ if (PREDICT_TRUE(trace_logging_info->current_logging_context != NULL)) {
+
+ output_node->sf.ctxs[output_node->sf.nused++] =
+ trace_logging_info->current_logging_context;
+
+ trace_logging_info->current_logging_context = NULL;
+ } else {
+ /*
+ * For queued logging context
+ */
+ output_node->sf.ctxs[output_node->sf.nused++] =
+ trace_logging_info->queued_logging_context;
+
+ trace_logging_info->queued_logging_context = NULL;
+ }
+
+ /*
+ * Move the logging context to output node
+ */
+ spp_dispatch_make_node_runnable(output_node);
+
+}
+
+/*
+ * edt: * * spp_create_trace_log_context
+ *
+ * Tries to create a logging context with packet buffer
+ * to send a new logging packet
+ *
+ * Argument: spp_trace_log_info_t *trace_logging_info
+ * structure that contains the nfv9 logging info and will store
+ * the packet context as well.
+ */
+inline
+void spp_create_trace_log_context (
+ spp_trace_log_info_t *trace_logging_info)
+{
+ spp_ctx_t *ctx;
+
+ /*
+ * If queued_logging_context_index is non-EMPTY, we already have a logging
+ * packet queued to be sent. First try sending this before allocating
+ * a new context. We can have only one active packet context per
+ * trace_logging_info structure
+ */
+ if (PREDICT_FALSE(trace_logging_info->queued_logging_context != NULL)) {
+ spp_trace_log_send_queued_pkt(trace_logging_info);
+ /*
+ * If we cannot still send the queued pkt, just return
+ * Downstream Constipation count would have increased anyway
+ */
+ if (trace_logging_info->queued_logging_context != NULL) {
+ spp_global_counters.spp_trace_log_context_creation_deferred_count++;
+ return;
+ }
+ }
+
+
+ /*
+ * No context can be allocated, return silently
+ * calling routine will handle updating the error counters
+ */
+ if (spp_ctx_alloc(&ctx, 1) < 1) {
+ spp_global_counters.spp_trace_log_context_creation_fail_count++;
+ return;
+ }
+
+ trace_logging_info->current_logging_context = ctx;
+ trace_logging_info->pkt_length = 0;
+
+ trace_logging_info->current_logging_context_timestamp =
+ spp_trace_log_get_sys_up_time_in_ms();
+
+ ctx->flags = SPP_CTX_END_OF_PACKET;
+ ctx->ru.tx.from_node = NODE_TRACE_BACKUP;
+ ctx->ru.tx.dst_ip_port_idx = EXT_TRACE_BACKUP_INDEX;
+ ctx->next_ctx_this_packet = (spp_ctx_t*) SPP_CTX_NO_NEXT_CTX;
+ ctx->current_header = &ctx->packet_data[SPP_TRACE_LOG_HDR_OFFSET];
+ ctx->current_length = 0;
+
+ trace_logging_info->log_record = 0;
+ trace_logging_info->total_record_count = 0;
+ trace_logging_info->next_data_ptr =
+ (u8 *) &ctx->packet_data[SPP_TRACE_LOG_HDR_OFFSET];
+
+}
+
+/*
+ * edt: * * spp_trace_log_add_record_create
+ *
+ * Tries to create an add record to the NFV9 packet
+ *
+ * Argument: spp_trace_log_info_t *trace_logging_info
+ * structure that contains the nfv9 logging info and will store
+ * the packet context as well.
+ */
+inline
+void spp_trace_log_add_record_create (spp_trace_log_info_t *trace_logging_info)
+{
+
+ trace_logging_info->log_header =
+ (spp_trace_log_hdr_t *) (trace_logging_info->next_data_ptr);
+
+ /*
+ * Initialize the number of traces recorded
+ */
+ trace_logging_info->log_header->num_traces =
+ spp_host_to_net_byte_order_32(0);
+
+
+ trace_logging_info->log_record =
+ (spp_trace_log_t *) (trace_logging_info->log_header + 1);
+
+ /*
+ * Update the length of the total pkt
+ */
+ trace_logging_info->pkt_length +=
+ SPP_LOG_TRACE_HEADER_LENGTH;
+
+ /*
+ * Set the data pointer beyond the trace header field
+ */
+ trace_logging_info->next_data_ptr =
+ (u8 *) (trace_logging_info->log_header + 1);
+
+}
+
+/*
+ * edt: * * spp_trace_logger
+ *
+ * Tries to log spp/cnat event/errors
+ *
+ * Argument: u8 *error_code
+ * Error code passed
+ *
+ * Argument: optional arguments
+ */
+void spp_trace_logger (u16 error_code, u16 num_args, u32 *arg)
+{
+ spp_trace_log_info_t *trace_logging_info = 0;
+ u8 i;
+
+ trace_logging_info =
+ spp_trace_log_info_pool +
+ spp_trace_log_global_info.spp_log_pool_index[SPP_LOG_LTRACE];
+
+ if (PREDICT_FALSE(trace_logging_info->current_logging_context == NULL)) {
+ spp_create_trace_log_context(trace_logging_info);
+
+ /*
+ * If still empty, return after increasing the count
+ */
+ if (PREDICT_FALSE(trace_logging_info->current_logging_context == NULL)) {
+ return;
+ }
+ }
+
+ if (PREDICT_FALSE(trace_logging_info->log_record == NULL)) {
+ spp_trace_log_add_record_create(trace_logging_info);
+ }
+
+ /*
+ * We should definitely have add_record now, no need to sanitize
+ */
+ trace_logging_info->log_record->error_code =
+ spp_host_to_net_byte_order_16(error_code);
+ trace_logging_info->log_record->num_args =
+ spp_host_to_net_byte_order_16(num_args);
+
+ for (i = 0; i < num_args; i++) {
+ trace_logging_info->log_record->arg[i] =
+ spp_host_to_net_byte_order_32(*(arg + i));
+ }
+
+ trace_logging_info->pkt_length += SPP_TRACE_LOG_RECORD_LENGTH + WORD_SIZE*num_args;
+ trace_logging_info->current_logging_context->current_length =
+ trace_logging_info->pkt_length;
+ trace_logging_info->total_record_count += 1;
+
+ trace_logging_info->next_data_ptr =
+ (u8 *) (trace_logging_info->next_data_ptr + WORD_SIZE + WORD_SIZE*num_args);
+
+ trace_logging_info->log_record =
+ (spp_trace_log_t *) (trace_logging_info->next_data_ptr);
+
+ /*
+ * Initialize the number of traces recorded
+ */
+ trace_logging_info->log_header->num_traces =
+ spp_host_to_net_byte_order_32(trace_logging_info->total_record_count);
+
+
+
+ /*
+ * If we have exceeded the packet length, let us send the
+ * packet now. There is buffer of additional bytes beyond
+ * max_pkt_length to ensure that the last add/delete record
+ * can be stored safely.
+ */
+ if (trace_logging_info->pkt_length >
+ trace_logging_info->max_length_minus_max_record_size) {
+ spp_trace_log_send_pkt(trace_logging_info);
+ }
+}
+
+
+/*
+ * edt: * * spp_trace_log_timer_handler
+ *
+ * Timer handler for sending any pending NFV9 record
+ *
+ * Argument: spp_timer_t * timer_p
+ * Timer handler structure
+ */
+inline
+void spp_trace_log_timer_handler (spp_timer_t * timer_p)
+{
+ spp_node_t *output_node;
+ spp_trace_log_info_t *trace_logging_info = 0;
+ u32 current_timestamp = spp_trace_log_get_sys_up_time_in_ms();
+ i16 sf_nused;
+
+ output_node = spp_get_nodes() +
+ spp_trace_log_global_info.spp_trace_log_disp_node_index;
+
+ sf_nused = output_node->sf.nused;
+
+ pool_foreach (trace_logging_info, spp_trace_log_info_pool, ({
+ /*
+ * Check if no more logging contexts can be queued
+ */
+ if (PREDICT_FALSE(sf_nused >= SPP_MAXDISPATCH)) {
+ break;
+ }
+
+ /*
+ * If there is a current logging context and timestamp
+ * indicates it is pending for long, send it out
+ * Also if there is a queued context send it out as well
+ */
+ if (trace_logging_info->queued_logging_context ||
+ (trace_logging_info->current_logging_context &&
+ (current_timestamp -
+ trace_logging_info->current_logging_context_timestamp)
+ > 1000)) {
+ spp_trace_log_send_pkt_always_success(trace_logging_info,
+ output_node);
+ sf_nused++;
+ }
+ }));
+
+ timer_p->expires =
+ spp_timer_in_n_ms_inline(1000); /* every 1 sec */
+ spp_timer_start(timer_p);
+
+}
+inline
+void spp_sensor_timer_handler (spp_timer_t * timer_p)
+{
+#ifdef TARGET_RODDICK
+ if (!temperature_read_blocked) {
+ Init_temperature_sensors();
+ read_octeon_sensors(TEMPERATURE_SENSOR_QUIET_MODE);
+ }
+
+ timer_p->expires =
+ spp_timer_in_n_ms_inline(60000); /* every 1 sec */
+ spp_timer_start(timer_p);
+
+#endif
+}
+void init_trace_log_buf_pool (void)
+{
+ spp_trace_log_info_t *my_spp_log_info;
+ u8 found;
+ spp_log_type_t log_type;
+
+ /*
+ * Init SPP logging info as needed, this will be done only once
+ */
+ spp_trace_log_init();
+
+ found = 0;
+
+ for (log_type = SPP_LOG_LTRACE; log_type < SPP_LOG_MAX; log_type++ ) {
+ /* Do we already have a map for this log type? */
+ pool_foreach (my_spp_log_info, spp_trace_log_info_pool, ({
+ if (my_spp_log_info->log_type == log_type) {
+ found = 1;
+ break;
+ }
+ }));
+
+ /*
+ * Entry not present
+ */
+ if (!found) {
+ pool_get(spp_trace_log_info_pool, my_spp_log_info);
+ memset(my_spp_log_info, 0, sizeof(*my_spp_log_info));
+
+ /*
+ * Make the current and head logging context indeices as EMPTY.
+ * When first logging happens, these get set correctly
+ */
+ my_spp_log_info->current_logging_context = NULL;
+ my_spp_log_info->queued_logging_context = NULL;
+
+ my_spp_log_info->log_type = log_type;
+ my_spp_log_info->max_length_minus_max_record_size =
+ SPP_TRACE_LOG_MAX_PKT_LENGTH;
+
+ spp_trace_log_global_info.spp_log_pool_index[log_type] =
+ my_spp_log_info - spp_trace_log_info_pool;
+ }
+
+ }
+
+ return;
+}
+
+
+/*
+ * one time function
+ * has to be called at the init time
+ */
+void spp_trace_log_init (void)
+{
+ if (!spp_trace_log_global_info.spp_trace_log_init_done) {
+
+#ifdef TARGET_RODDICK
+ spp_trace_log_global_info.spp_trace_log_disp_node_index =
+ spp_lookup_node_index("roddick_infra_l3_tx");
+#elif defined(TARGET_BOOSTER)
+ spp_trace_log_global_info.spp_trace_log_disp_node_index =
+ spp_lookup_node_index("booster_infra_l3_tx");
+#endif
+ ASSERT(spp_trace_log_global_info.spp_trace_log_disp_node_index != (u16)~0);
+
+ spp_trace_log_global_info.log_timer.cb_index =
+ spp_timer_register_callback(spp_trace_log_timer_handler);
+ spp_trace_log_global_info.log_timer.expires =
+ spp_timer_in_n_ms_inline(1000); /* every 1 sec */
+ spp_timer_start(&spp_trace_log_global_info.log_timer);
+
+ if (!my_core_id) {
+ sensor_timer.cb_index =
+ spp_timer_register_callback(spp_sensor_timer_handler);
+ sensor_timer.expires =
+ spp_timer_in_n_ms_inline(60000); /* every 1 sec */
+ spp_timer_start(&sensor_timer);
+ }
+
+ spp_trace_log_global_info.spp_trace_log_init_done = 1;
+
+ /*
+ * Set MSC ip_addr, port values
+ */
+#ifdef TARGET_RODDICK
+ dst_ipv4_port_table[EXT_TRACE_BACKUP_INDEX].ipv4_address =
+ vpp_boot_params.msc_ip_address;
+ switch(vpp_boot_params.octeon_number) {
+ case 0:
+ dst_ipv4_port_table[EXT_TRACE_BACKUP_INDEX].port = 0x15BF;
+ break;
+ case 1:
+ dst_ipv4_port_table[EXT_TRACE_BACKUP_INDEX].port = 0x15BF;
+ break;
+ case 2:
+ dst_ipv4_port_table[EXT_TRACE_BACKUP_INDEX].port = 0x15BF;
+ break;
+ case 3:
+ dst_ipv4_port_table[EXT_TRACE_BACKUP_INDEX].port = 0x15BF;
+ break;
+ }
+#else
+ dst_ipv4_port_table[EXT_TRACE_BACKUP_INDEX].ipv4_address = 0x01020304;
+ dst_ipv4_port_table[EXT_TRACE_BACKUP_INDEX].port = 0x15BF;
+#endif
+
+ }
+}
+
+void spp_printf (u16 error_code, u16 num_args, u32 *arg)
+{
+ u32 current_timestamp;
+ spp_node_main_vector_t *nmv;
+
+ if (PREDICT_FALSE(error_code >= LOG_TABLE_MAX_ENTRIES))
+ {
+ /* printf("Error code invalid %d, %d, %d, %d\n",
+ error_code, LOG_TABLE_MAX_ENTRIES,
+ sizeof(spp_cnat_logger_table), sizeof(spp_cnat_logger_table[0]));
+ */
+ return; /* Should not happen */
+ }
+
+ nmv = spp_get_node_main_vectorized_inline();
+ current_timestamp = nmv->ticks / nmv->ticks_per_second;
+
+ /* Check if any further hashing is required */
+
+ if (PREDICT_FALSE(error_code == DUMP_PKT_IDX)) {
+#ifdef TARGET_RODDICK || defined(TARGET_BOOSTER)
+ spp_trace_logger(error_code, num_args, arg);
+#else
+ u8 j ;
+
+ printf("PKT DUMP :: ");
+ for (j = 0 ; j < num_args; j++) {
+ printf("0x%x ", arg[j]);
+ if (j == (num_args - 1)) {
+ printf("\n");
+ }
+ }
+#endif
+ } else if (PREDICT_TRUE((current_timestamp - error_code_timestamps[error_code]) >=
+ spp_cnat_logger_table[error_code].rate_limit_time)) {
+ /* update timestamp */
+ error_code_timestamps[error_code] = current_timestamp;
+
+#ifdef TARGET_RODDICK || defined(TARGET_BOOSTER)
+ spp_trace_logger(error_code, num_args, arg);
+#else
+ u8 j ;
+
+ for (j = 0 ; j < num_args; j++) {
+ printf("%s: %d ", spp_cnat_logger_table[error_code].param_name[j], arg[j]);
+ if (j == (num_args - 1)) {
+ printf("\n");
+ }
+ }
+#endif
+ }
+}
+
+#else /* TOBE_PORTEED */
+void spp_trace_logger(u16 error_code, u16 num_args, u32 *arg)
+{
+ /* To be filled */
+}
+
+void spp_trace_log_init(void)
+{
+ /* To be filled */
+}
+
+void init_trace_log_buf_pool(void)
+{
+ /* To be filled */
+}
+
+void spp_printf(u16 error_code, u16 num_args, u32 *arg)
+{
+ /* To be filled */
+}
+
+inline u32 spp_trace_log_get_unix_time_in_seconds (void)
+{
+ vlib_main_t *vlib_main;
+
+ vlib_main = vlib_get_main();
+ return(vlib_time_now((vlib_main_t *) vlib_main));
+}
+
+#endif /* TOBE_PORTED */
+
diff --git a/vpp/plugins/vcgn-plugin/vcgn/spp_platform_trace_log.h b/vpp/plugins/vcgn-plugin/vcgn/spp_platform_trace_log.h
new file mode 100644
index 00000000..36da710f
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/spp_platform_trace_log.h
@@ -0,0 +1,358 @@
+/*
+ *------------------------------------------------------------------
+ * spp_platform_trace_log.h
+ *
+ * Copyright (c) 2009-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __SPP_PLATFORM_TRACE_LOG_H__
+#define __SPP_PLATFORM_TRACE_LOG_H__
+
+#include <stdio.h>
+#include <vppinfra/vec.h>
+#include <vppinfra/bitmap.h>
+#include <vppinfra/hash.h>
+#include <vppinfra/pool.h>
+#include <vppinfra/clib.h>
+
+#include "spp_ctx.h"
+#include "spp_timers.h"
+
+
+typedef enum {
+ SPP_LOG_LTRACE,
+ SPP_LOG_MAX
+} spp_log_type_t;
+
+typedef struct {
+ u32 num_traces;
+} spp_trace_log_hdr_t;
+
+typedef struct {
+ u16 error_code;
+ u16 num_args;
+ u32 arg[0];
+} spp_trace_log_t;
+
+#define DUMP_PKT_IDX 61
+#define OCTEON_SENSOR_READ 62
+
+typedef enum {
+ CNAT_ERROR_SUCCESS,
+ CNAT_NO_CONFIG_ERROR,
+ CNAT_NO_VRF_RUN_ERROR,
+ CNAT_NO_POOL_FOR_ANY_ERROR,
+ CNAT_NO_PORT_FOR_ANY_ERROR,
+ CNAT_BAD_INUSE_ANY_ERROR,
+ CNAT_NOT_FOUND_ANY_ERROR,
+ CNAT_INV_PORT_FOR_DIRECT_ERROR,
+ CNAT_BAD_INUSE_DIRECT_ERROR,
+ CNAT_NOT_FOUND_DIRECT_ERROR,
+ CNAT_OUT_OF_PORT_LIMIT_ERROR,
+ CNAT_MAIN_DB_CREATE_ERROR,
+ CNAT_LOOKUP_ERROR,
+ CNAT_INDEX_MISMATCH_ERROR,
+ CNAT_PACKET_DROP_ERROR,
+ CNAT_INV_UNUSED_USR_INDEX,
+ CNAT_INVALID_VRFMAP_INDEX,
+ CNAT_USER_OUT_OF_PORTS,
+ CNAT_EXT_PORT_THRESH_EXCEEDED,
+ CNAT_EXT_PORT_THRESH_NORMAL,
+ CNAT_NO_EXT_PORT_AVAILABLE,
+ CNAT_SESSION_THRESH_EXCEEDED,
+ CNAT_SESSION_THRESH_NORMAL,
+ WQE_ALLOCATION_ERROR,
+ ERROR_PKT_DROPPED,
+ SYSMGR_PD_KEY_CREATION_ERROR,
+ SYSMGR_PD_SHMEM_ID_ERROR,
+ SYSMGR_PD_SHMEM_ATTACH_ERROR,
+ OCTEON_CKHUM_SKIPPED,
+ PK0_SEND_STATUS,
+ CMD_BUF_ALLOC_ERR,
+ SPP_CTX_ALLOC_FAILED,
+ SPP_MAX_DISPATCH_REACHED,
+ HA_SIGCHILD_RECV,
+ SIGACTION_ERR,
+ HA_INVALID_SEQ_OR_CONFIG_OR_TYPE,
+ NODE_CREATION_ERROR,
+ CNAT_CLI_INVALID_INPUT, /* new adds as part of CSCto04510, see sub codes below */
+ CNAT_DUMMY_HANDLER_HIT, /* Has sub codes , see spp_dummy_handler_sub_cdes_t */
+ CNAT_CONFIG_ERROR, /* has subcodes-see spp_config_error_sub_codes_t below */
+ CNAT_NFV9_ERROR, /* Has sub codes see spp_nfv9_error_sub_codes_t below */
+ CNAT_CMVX_TWSI_READ_WRITE_FAIL, /* Hassub codes see spp_cmvx_error_sub_codes_t */
+ CNAT_TEMP_SENSOR_TIMEOUT,
+ CNAT_TEMP_SENSOR_DATA_MISMATCH,
+ CNAT_TEMP_SENSOR_CONFIG_FAILED,
+ HA_APP_NOT_RESPONDING,
+ HA_DATA_PATH_TEST_FAILED,
+ CNAT_WRONG_PORT_ALLOC_TYPE,
+ CNAT_NEW_PORT_ALLOC_ERROR,
+ CNAT_INVALID_INDEX_TO_FREE_PORT,
+ CNAT_DELETE_DB_ENTRY_NO_PORTMAP,
+ CNAT_MAIN_DB_LIMIT_ERROR,
+ CNAT_USER_DB_LIMIT_ERROR,
+ CNAT_FRAG_DB_ERROR, /* see spp_frag_db_error_sub_codes_t below */
+
+ DROP_PKT_DUMP,
+ CNAT_NAT64_SYSTEM_LIMIT_ERROR,
+ CNAT_ERROR_MAX
+} spp_error_codes_t;
+
+typedef enum {
+
+ TCP_MSS_INVALID_IVRF = 10, /* 1 param - vrf id */
+ NFV9_LOG_INVALID_IP_OR_PORT = 20, /* 2 params - nfv9 server ip and port */
+ NFV9_LOG_INVALID_PARAMS_OTHERS, /* 3 params, ref rate, time out, path mtu */
+ NFV9_LOG_PATH_MTU_TOO_SMALL, /* 1 param, path mtu passed */
+ NFV9_LOG_CANNOT_ADD_VRF_NOT_FOUND, /* 1 param, in vrf id */
+
+ VRF_MAP_ADDR_POOL_START_ADDR_GT_END_ADDR = 30, /* 2 params, start and end addr */
+ VRF_MAP_ADDR_POOL_ADDR_POOL_TOO_LARGE, /* 2 params, start and end addr */
+ VRF_MAP_ADDR_POOL_INVALID_IN_OR_OUT_VRF, /* 2 params, in vrf and out vrf */
+ VRF_MAP_ADDR_POOL_TOO_LARGE_FOR_CORE, /* 2 params, pool size, core instance */
+ VRF_MAP_DEL_POOL_START_ADDR_GT_END_ADDR, /* 2 params, start and end addr */
+ VRF_MAP_DEL_POOL_ADDR_POOL_NOT_FOUND, /* 2 params, start and end addr */
+ VRF_MAP_DEL_POOL_VRF_MAP_EMPTY, /* 2 params, start and end addr */
+
+ ADD_SVI_ADDR_INVALID_VRF = 40, /* 2 params, vrf passed and ipv4 addr */
+ ADD_SVI_INDEX_INVALID_VRF, /* 2 params, vrf, uidb_index */
+
+ MAPPED_STAT_PORT_INVALID_OUTPUT_PARAMS = 50,
+ /* 3 params, out vrf, out ip, out port */
+ MAPPED_STAT_PORT_UDP_PORT_POLARITY_MISMATCH, /* 2 params, in port and out port */
+ MAPPED_STAT_PORT_IN_VRF_MAP_EMPTY, /* 1 param, in vrf id passed */
+ MAPPED_STAT_PORT_VRF_MAP_NOT_IN_S_RUN, /* 1 param, vrf map status */
+ MAPPED_STAT_PORT_INVALID_OUT_VRF_ID, /* 1 param, out vrf id passed */
+ MAPPED_STAT_PORT_FAILED_TO_ADD_STAT_PORT, /* 4 params, in vrf, in ip, in port, error code */
+
+ STAT_PORT_INVALID_IN_PARAMS = 60, /* 4 params, in vrf, in ip, in port, proto */
+ STAT_PORT_FAILED_TO_ADD_STAT_PORT, /* 4 params, in vrf, in ip, in port, error code */
+ STAT_PORT_CONFIG_IN_USE, /* 4 params, in vrf, in ip, in port, proto */
+
+ DEL_STAT_PORT_IN_VRF_MAP_EMPTY = 70, /* 1 param, in vrf id passed */
+ DEL_STAT_PORT_INVALID_IN_PARAMS, /* 4 params, in vrf, in ip, in port, proto */
+ DEL_STAT_PORT_CANNOT_DELETE_NO_ENTRY, /* 4 params, in vrf, in ip, in port, proto */
+ DEL_STAT_PORT_CANNOT_DELETE_NOT_STATIC_PORT, /* 4 params, in vrf, in ip, in port, proto*/
+
+ XLAT_SVI_CFG_INVALID_INDEX = 80, /* 1 param - uidb_index */
+ XLAT_WRONG_V6_PREFIX_MASK, /* 1 param - v6 prefix mask */
+ XLAT_INVALID_XLAT_ID_ERROR, /* 1 param - id */
+
+ V6RD_INVALID_6RD_ID_ERROR = 90, /*1 param - id */
+ MAPE_INVALID_MAPE_ID_ERROR = 100 /* param - id */
+} spp_config_error_sub_codes_t;
+
+typedef enum {
+ CONFIG_DUMMY,
+ CONFIG_DUMMY_MAX,
+ SHOW_DUMMY,
+ SHOW_DUMMY_MAX,
+ DEBUG_DUMMY,
+ DEBUG_DUMMY_MAX
+} spp_dummy_handler_sub_cdes_t;
+
+typedef enum {
+ CMVX_READ,
+ CMVX_WRITE
+} spp_cmvx_error_sub_codes_t;
+
+typedef enum {
+ FRAG_DB_INVALID_BUCKET,
+ FRAG_DB_NO_ENTRY
+} spp_frag_db_error_sub_codes_t;
+
+typedef enum {
+ CLI_INVALID_PAYLOAD_SIZE,
+ CLI_INVALID_MSG_ID
+} spp_cli_error_sub_codes_t;
+
+typedef enum {
+ NFV9_DOWNSTREAM_CONGESTION,
+ NFV9_FAILED_TO_CREATE_CONTEXT
+} spp_nfv9_error_sub_codes_t;
+
+typedef struct spp_cnat_logger_tbl_t_ {
+ u16 error_code; // The thread id stored by software
+ u16 num_args;
+ u16 rate_limit_time; // If we need to rate_limit logging
+ u8 param_name[7][32];// Parameter name for debug purposes
+} spp_cnat_logger_tbl_t;
+
+extern spp_cnat_logger_tbl_t spp_cnat_logger_table[];
+
+/*
+ * This corresponds to the length of the IMETRO SHIM Header for RODDICK
+ * For non-roddick cases, introduce an Ethernet header as well
+ */
+#if defined(RODDICK)
+#define SPP_TRACE_LOG_SHIM_HDR_OFFSET 8
+#define SPP_TRACE_LOG_ENCAPS_OFFSET 0
+#else
+#define SPP_TRACE_LOG_SHIM_HDR_OFFSET 0
+#define SPP_TRACE_LOG_ENCAPS_OFFSET 16
+#endif
+
+#define SPP_LOG_TRACE_HEADER_LENGTH \
+ (sizeof(spp_trace_log_hdr_t))
+
+
+#define SPP_TRACE_LOG_IP_HDR_OFFSET \
+ (SPP_TRACE_LOG_ENCAPS_OFFSET + \
+ SPP_TRACE_LOG_SHIM_HDR_OFFSET)
+
+
+#define SPP_TRACE_LOG_UDP_HDR_OFFSET \
+ (SPP_TRACE_LOG_IP_HDR_OFFSET + sizeof(ipv4_header))
+
+#define SPP_TRACE_LOG_HDR_OFFSET \
+ (SPP_TRACE_LOG_UDP_HDR_OFFSET + sizeof(udp_hdr_type_t))
+
+#define SPP_TRACE_LOG_RECORD_LENGTH 4
+
+/*
+ * Let us put the maximum length of the log data to be 1400
+ */
+#define SPP_TRACE_LOG_MAX_PKT_LENGTH 800
+
+/* Structures and defines to store log info for MSC */
+#define SPP_TRACE_LOG_INVALID_LOGGING_INDEX 0xffffffff
+
+/*
+ * This structure stores the Logging information on per LOG TYPE
+ * basis. This structure is allocated from a pool and index
+ * to this structure based on log type
+ */
+typedef struct {
+ /*
+ * This field determines the maximum size of the Netflow V9 information
+ * that can be stored in a logging packet
+ */
+ u16 max_length_minus_max_record_size;
+
+ u32 sequence_num; /* Sequence number of the logging packet */
+ u32 last_pkt_sent_count;
+ u16 pkt_length; /* Length of the currently NFv9 information */
+ u16 log_record_length; /* Length of add record */
+ u16 total_record_length; /* number of trace records */
+ u16 total_record_count;
+ spp_log_type_t log_type;
+ /*
+ * current logging context
+ */
+ spp_ctx_t *current_logging_context;
+
+ /*
+ * Timestamp in UNIX seconds corresponding to when the current
+ * logging packet was created
+ */
+ u32 current_logging_context_timestamp;
+
+ /*
+ * Queued logging context waiting to be sent to the l3 infra node
+ */
+ spp_ctx_t *queued_logging_context;
+
+ /*
+ * Headers corresponding to various records in this
+ * current nfv9 logging context
+ */
+ spp_trace_log_t *log_record;
+ spp_trace_log_hdr_t *log_header;
+ u8 *next_data_ptr;
+
+} spp_trace_log_info_t;
+
+typedef struct {
+ /*
+ * spp_ctx_alloc() call failed
+ */
+ u64 spp_trace_log_context_creation_fail_count;
+
+ /*
+ * Cannot send the existing logging pkt, so cannot create
+ * any additional packets for logging purposes
+ */
+ u64 spp_trace_log_context_creation_deferred_count;
+
+ /*
+ * Cannot send the existing logging pkt due to cnat_rewrite_output
+ * superframe being full.
+ */
+ u64 spp_trace_log_downstream_constipation_count;
+} spp_global_counters_t;
+
+
+/*
+ * Global structure for SPP LOGS
+ */
+typedef struct {
+ /* A timer structure to periodically send log packets
+ * that have been waiting to be full for a long time. This will
+ * ensure event/error logs don't get delayed too much before they
+ * are sent to the MSC.
+ */
+ spp_timer_t log_timer;
+
+ /*
+ * Node index corresponding to the infra L3 output node
+ * to which the nfv9 logging node will send the packet
+ */
+ u16 spp_trace_log_disp_node_index;
+
+ /*
+ * Whether we have initialized the NFv9 information
+ */
+ u8 spp_trace_log_init_done;
+
+ /*
+ * pool index in global pool based on log type
+ */
+ u32 spp_log_pool_index[SPP_LOG_MAX];
+
+} spp_trace_log_global_info_t;
+
+
+extern spp_timer_t sensor_timer;
+extern spp_trace_log_info_t spp_default_trace_log_info;
+extern spp_trace_log_info_t *spp_trace_log_info_pool;
+
+extern spp_trace_log_global_info_t spp_trace_log_global_info;
+
+void spp_trace_logger(u16 error_code, u16 num_args, u32 *arg);
+void spp_trace_log_init(void);
+void init_trace_log_buf_pool(void);
+void spp_printf(u16 error_code, u16 num_args, u32 *arg);
+
+/*
+ * The following 2 functions are temporary hacks until
+ * we have RTC support from the PD nodes
+ */
+#if 0
+inline
+u32 spp_trace_log_get_sys_up_time_in_ms (void);
+#endif
+extern
+u32 spp_trace_log_get_unix_time_in_seconds (void);
+
+enum {
+ TEMPERATURE_SENSOR_TEST_MODE,
+ TEMPERATURE_SENSOR_QUIET_MODE,
+};
+
+extern int temperature_read_blocked;
+
+void read_octeon_sensors(u8 mode);
+void Init_temperature_sensors();
+#endif /* __SPP_PLATFORM_TRACE_LOG_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/spp_timers.h b/vpp/plugins/vcgn-plugin/vcgn/spp_timers.h
new file mode 100644
index 00000000..afb0147b
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/spp_timers.h
@@ -0,0 +1,139 @@
+/*
+ *------------------------------------------------------------------
+ * spp_timers.h
+ *
+ * Copyright (c) 2008-2009 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+#ifndef __SPP_TIMERS_H__
+#define __SPP_TIMERS_H__
+
+
+typedef struct d_list_el_ {
+ struct d_list_el_ *next;
+ struct d_list_el_ *prev;
+} d_list_el_t;
+
+/*
+ * d_list_init
+ */
+
+static inline void d_list_init (d_list_el_t *headp)
+{
+ headp->prev = headp->next = headp;
+}
+
+/*
+ * d_list_init - add at head of list
+ */
+
+static inline void d_list_add_head (d_list_el_t *headp,
+ d_list_el_t *elp)
+{
+ ASSERT(elp->prev == elp); /* multiple enqueue, BAD! */
+ ASSERT(elp->next == elp);
+
+ elp->next = headp->next;
+ headp->next = elp;
+ elp->prev = elp->next->prev;
+ elp->next->prev = elp;
+}
+
+/*
+ * d_list_add_tail - add element at tail of list
+ */
+static inline void d_list_add_tail (d_list_el_t *headp,
+ d_list_el_t *elp)
+{
+ ASSERT(elp->prev == elp); /* multiple enqueue, BAD! */
+ ASSERT(elp->next == elp);
+
+ headp = headp->prev;
+
+ elp->next = headp->next;
+ headp->next = elp;
+ elp->prev = elp->next->prev;
+ elp->next->prev = elp;
+}
+
+/*
+ * d_list_rem_head - removes first element from list
+ */
+static inline d_list_el_t *d_list_rem_head (d_list_el_t *headp)
+{
+ d_list_el_t *elp;
+
+ elp = headp->next;
+ if (elp == headp)
+ return (NULL);
+ headp->next = elp->next;
+ elp->next->prev = elp->prev;
+
+ elp->next = elp->prev = elp;
+ return (elp);
+}
+
+/*
+ * d_list_rem_elem - removes specific element from list.
+ */
+static inline void d_list_rem_elem (d_list_el_t *elp)
+{
+ d_list_el_t *headp;
+
+ headp = elp->prev;
+
+ headp->next = elp->next;
+ elp->next->prev = elp->prev;
+ elp->next = elp->prev = elp;
+}
+
+#define TIMER_BKTS_PER_WHEEL 128 /* power of 2, please */
+#define TIMER_NWHEELS 4
+
+typedef struct {
+ i32 curindex; /* current index for this wheel */
+ d_list_el_t *bkts; /* vector of bucket listheads */
+} spp_timer_wheel_t;
+
+
+typedef struct {
+ u64 next_run_ticks; /* Next time we expire timers */
+ spp_timer_wheel_t **wheels; /* pointers to wheels */
+} spp_timer_axle_t;
+
+
+typedef struct {
+ d_list_el_t el;
+ u16 cb_index;
+ u16 flags;
+ u64 expires;
+} spp_timer_t;
+
+#define SPP_TIMER_RUNNING 0x0001
+
+
+/*
+ * prototypes
+ */
+void spp_timer_set_ticks_per_ms(u64);
+void spp_timer_axle_init (spp_timer_axle_t *ta);
+void spp_timer_expire(spp_timer_axle_t *ta, u64 now);
+void spp_timer_final_init(void);
+
+void spp_timer_start(spp_timer_t *tp);
+void spp_timer_start_axle(spp_timer_axle_t *ta, spp_timer_t *tp);
+void spp_timer_stop(spp_timer_t *tp);
+u16 spp_timer_register_callback (void (*fp)(spp_timer_t *));
+
+#endif /* __SPP_TIMERS_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/tcp_header_definitions.h b/vpp/plugins/vcgn-plugin/vcgn/tcp_header_definitions.h
new file mode 100644
index 00000000..02920bcc
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/tcp_header_definitions.h
@@ -0,0 +1,1582 @@
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Filename: tcp_header_definitions.h
+ *
+ * Description: Layer 2, 3, 4 definitions and header types
+ *
+ * Assumptions and Constraints:
+ *
+ * Copyright (c) 2012-2013 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *-----------------------------------------------------------------------------
+ */
+
+#ifndef __TCP_HEADER_DEFINITIONS_H__
+#define __TCP_HEADER_DEFINITIONS_H__
+
+/*
+ * A general list of Layer 3 protocols, used by many Layer 2 encaps.
+ *
+ * formerly:
+ * TYPE_IP TYPE_IP10MB
+ * TYPE_ARP TYPE_RFC826_ARP
+ * TYPE_RARP TYPE_REVERSE_ARP
+ * TYPE_MPLS TYPE_TAGSWITCH
+ */
+#define TYPE_IP 0x0800
+#define TYPE_IP_V6 0x86DD
+#define TYPE_ARP 0x0806
+#define TYPE_RARP 0x8035
+#define TYPE_MPLS 0x8847
+#define TYPE_CDP 0x2000
+#define TYPE_CGMP 0x2001
+#define TYPE_LACP 0x8808 /* 802.3ad */
+#define TYPE_CLNS 0xFEFE
+
+#define TYPE_PPPOE_SESSION 0x8864 /* PTA plus */
+#define TYPE_PPPOE_DISCOVERY 0x8863 /* PTA plus */
+
+/*
+ * for atm arp handling
+ */
+#define IN_ATM_ARP_BIT 0x0008
+
+/*
+ * The Layer 2 header structures.
+ */
+
+
+/*
+** HDLC
+*/
+
+typedef struct hdlc_hdr_type {
+ u16 addr;
+ u16 type;
+ u8 data[0];
+} hdlc_hdr_type;
+
+#define HDLC_ADDR_CMD 0x0F00
+#define HDLC_HDR_LEN 4
+#define HDLC_BROADCAST_BIT 31
+#define TYPE_KEEP 0x8035
+
+#define HDLC_CLNS (HDLC_ADDR_CMD<<16|TYPE_CLNS)
+#define HDLC_CDP (HDLC_ADDR_CMD<<16|TYPE_CDP)
+#define HDLC_MPLS (HDLC_ADDR_CMD<<16|TYPE_MPLS)
+#define HDLC_IP (HDLC_ADDR_CMD<<16|TYPE_IP)
+#define HDLC_IP_V6 (HDLC_ADDR_CMD<<16|TYPE_IP_V6)
+#define HDLC_KEEPALIVE_CMD (HDLC_ADDR_CMD<<16|TYPE_KEEP)
+
+/*
+** PPP
+*/
+
+typedef struct ppp_comp_hdr_type {
+ union {
+ u8 ppp_u8[4];
+ u16 ppp_u16[2];
+ u32 ppp_u32;
+ } ppp_comp_u;
+} ppp_comp_hdr_type;
+
+#define PPP_STATION 0xFF03
+#define PPP_STATION_LEN 0x2
+#define PPP_ENDPROTO 0x01
+#define PPP_NOT_ENDPROTO 0xfffffffe
+#define PPP_CONTROL_PROTOCOL_MASK 0x8000
+#define PPP_CONTROL_PROTOCOL_BIT 15
+#define PPP_CSCO_LEN 4
+#define PPP_RFC1661_LEN 2
+#define PPP_RFC1661_COMP_LEN 1
+
+#define TYPE_PPP_IP 0x0021
+#define TYPE_PPP_IP_V6 0x0057
+#define TYPE_PPP_MPLS_UNICAST 0x0281
+#define TYPE_PPP_MPLS_CONTROL 0x8281
+#define TYPE_PPP_CLNS 0x0023
+#define TYPE_PPP_CDP 0x0207
+
+#define TYPE_PPP_IPCP 0x8021
+#define TYPE_PPP_LCP 0xC021
+#define TYPE_PPP_PAP 0xC023
+#define TYPE_PPP_LQR 0xC025
+#define TYPE_PPP_CHAP 0xC223
+
+
+#define TYPE_PPP_LCP_ECHO_REQUEST 0x09
+/*
+** MultiLink PPP
+*/
+
+#define MLPPP_FLAGS_FIELD_LEN 4
+#define MLPPP_BEGIN_MASK 0x80000000
+#define MLPPP_END_MASK 0x40000000
+#define MLPPP_BEGIN_END_MASK (MLPPP_BEGIN_MASK|MLPPP_END_MASK)
+#define MLPPP_BEGIN_END_SHIFT 30
+#define MLPPP_SEQUENCE_NUM_MASK 0x00FFFFFF
+#define MLPPP_MC_CLASS_ID_MASK 0x3C000000
+#define MLPPP_MC_CLASS_SHIFT 26
+
+#define TYPE_PPP_MULTILINK 0x003D
+
+/* these are needed in the micro-code, for optimizations */
+#define TYPE_PPP_FULL_IP_4 0xff030021
+#define TYPE_PPP_FULL_IP_3 0xff0321
+#define TYPE_PPP_FULL_IP_2 0x0021
+#define TYPE_PPP_FULL_IP_1 0x21
+
+#define MLPPP_BEGIN_END_MASK_BYTE 0xC0
+#define MLPPP_BEGIN_BIT 7
+#define MLPPP_END_BIT 6
+#define MLPPP_MC_CLASS_ID_MASK_BYTE 0x3C
+#define MLPPP_MC_CLASS_ID_SHIFT_BYTE 2
+
+#define MLPOA_BEGIN_END_SHIFT 24
+
+/*
+** Ethernet ARPA
+*/
+
+
+typedef struct ethernet_arpa_hdr_type {
+ u8 daddr[6];
+ u8 saddr[6];
+ u16 type;
+ u8 data[0];
+} ethernet_arpa_hdr_type;
+
+typedef struct extension_802p3_type {
+ u16 type;
+ u8 ctl;
+ u8 data[0];
+} extension_802p3_type;
+
+typedef struct ethernet_802p3_hdr_type {
+ u8 daddr[6];
+ u8 saddr[6];
+ u16 length;
+ extension_802p3_type extension;
+} ethernet_802p3_hdr_type;
+
+
+typedef struct ethernet_vlan_802p3_hdr_type {
+ u8 daddr[6];
+ u8 saddr[6];
+ u16 type1;
+ u16 vlan_id;
+ u16 length;
+ extension_802p3_type extension;
+} ethernet_vlan_802p3_hdr_type;
+
+#define MIN_ETHERNET_PKT_LEN 60
+#define MAX_ETHERNET_PKT_LEN 1500
+#define ETHERNET_ARPA_HDR_LEN 14
+#define ETHERNET_TYPE_FIELD_SIZE 2
+
+
+/*
+** Ethernet 802.1q (VLAN)
+*/
+
+typedef struct ethernet_vlan_hdr_type {
+ u8 dest_addr[6];
+ u8 src_addr[6];
+ u16 type1;
+ u16 vlan_hdr;
+ u16 type2;
+ u8 data[0];
+} ethernet_vlan_hdr_type;
+
+
+/*
+** Ethernet 802.1.q-in-q (QinQ)
+*/
+
+typedef struct ethernet_qinq_hdr_type {
+ u8 dest_addr[6];
+ u8 src_addr[6];
+ u16 type1;
+ u16 vlan_hdr1;
+ u16 type2;
+ u16 vlan_hdr2;
+ u16 type3;
+ u8 data[0];
+} ethernet_qinq_hdr_type;
+
+
+/*
+** Ethernet 802.3ad EtherChannel control
+*/
+
+typedef struct ethernet_lacp_hdr_type {
+ u8 daddr[6];
+ u8 saddr[6];
+ u16 type;
+ u16 LAcmd;
+ u8 data[0];
+} ethernet_lacp_hdr_type;
+
+
+/*
+** Ethernet 802.1 Bridge (spanning tree) PDU
+*/
+
+typedef struct ethernet_bpdu_hdr_type {
+ u8 daddr[6];
+ u8 saddr[6];
+ u8 dsap;
+ u8 ssap;
+ u8 control;
+ u8 more[0];
+} ethernet_bpdu_hdr_type;
+
+#define ETH_BPDU_DSAP 0x42
+#define ETH_BPDU_SSAP 0x42
+#define ETH_BPDU_CONTROL 0x03
+#define ETH_BPDU_MATCH 0x424203
+
+
+/************************************************************/
+/* PTA PLUS ETHERNET ENCAPSULATIONS */
+/*
+ * PPPoEoARPA 20 bytes
+ */
+typedef struct ethernet_pppoe_arpa_hdr_type {
+ u8 daddr[6];
+ u8 saddr[6];
+ u16 type;
+ /* pppoe hdr at begining of enet payload */
+ u16 vtc; /* version(4b), type(4b) and code(8b) fields */
+ u16 sid;
+ u16 len;
+ u8 ppp_header[0]; /* PPP header start, no ff03 field present */
+} ethernet_pppoe_arpa_hdr_type;
+
+typedef struct pppoe_hdr_type {
+ /* pppoe hdr at begining of enet payload */
+ u16 vtc; /* version(4b), type(4b) and code(8b) fields */
+ u16 sid;
+ u16 len;
+ u8 ppp_header[0]; /* PPP header start, no ff03 field present */
+} pppoe_hdr_type;
+
+/*
+** PPPoEoVLAN (802.1p or 802.1q) 24 bytes
+*/
+typedef struct ethernet_pppoe_vlan_hdr_type {
+ u8 dest_addr[6];
+ u8 src_addr[6];
+ u16 type1;
+ u16 vlan_hdr;
+ u16 type2;
+ /* pppoe hdr at begining of enet payload */
+ u16 vtc; /* version(4b), type(4b) and code(8b) fields */
+ u16 sid;
+ u16 len;
+ u8 ppp_header[0]; /* PPP header start, no ff03 field present */
+} ethernet_pppoe_vlan_hdr_type;
+
+/*
+** PPPoEoQinQ 28 bytes
+*/
+typedef struct ethernet_pppoe_qinq_hdr_type {
+ u8 dest_addr[6];
+ u8 src_addr[6];
+ u16 type1;
+ u16 vlan_hdr1;
+ u16 type2;
+ u16 vlan_hdr2;
+ u16 type3;
+ /* pppoe hdr at begining of enet payload */
+ u16 vtc; /* version(4b), type(4b) and code(8b) fields */
+ u16 sid;
+ u16 len;
+ u8 ppp_header[0]; /* PPP header start, no ff03 field present */
+} ethernet_pppoe_qinq_hdr_type;
+
+#define ETH_PPPOE_ARPA_HDR_LEN sizeof(ethernet_pppoe_arpa_hdr_type)
+#define ETH_PPPOE_VLAN_HDR_LEN sizeof(ethernet_pppoe_vlan_hdr_type)
+#define ETH_PPPOE_QINQ_HDR_LEN sizeof(ethernet_pppoe_qinq_hdr_type)
+#define PPPOE_HDR_LEN 6
+/* End PTA PLUS ETHERNET ENCAPSULATIONS */
+/****************************************************************/
+
+
+
+#define TYPE_DOT1Q 0x8100
+#define DOT1Q_HDR_LEN 18
+#define DOT1Q_VLAN_ID_MASK 0x0FFF
+#define DOT1Q_VLAN_ID_RES_0 0x0000
+#define DOT1Q_VLAN_ID_RES_4095 0x0FFF
+#define DOT1Q_ARPA_INDEX DOT1Q_VLAN_ID_RES_0
+
+#define TYPE_QINQ_91 0x9100
+#define TYPE_QINQ_92 0x9200
+#define TYPE_QINQ_88A8 0x88A8
+#define QINQ_HDR_LEN 22
+
+/*
+ * 802.1p support
+ */
+#define DOT1P_VLAN_COS_MASK 0xE000
+#define DOT1P_VLAN_COS_SHIFT 13
+#define DOT1P_MAX_COS_VALUE 7
+
+/*
+** Frame Relay
+*/
+
+/*
+ * formerly:
+ * TYPE_FR_IETF_IPV4 ENCAPS_FR_IETF
+ * TYPE_FR_CISCO_IPV4 ENCAPS_FR_CISCO
+ * TYPE_FR_ISIS ENCAPS_FR_ISIS
+ *
+ * FR_LMI_DLCI_CISCO LMI_DLCI_CISCO
+ * FR_LMI_DLCI_IETF LMI_DLCI_ITUANSI
+ */
+
+typedef struct frame_relay_hdr_type {
+ u16 address;
+ u16 control_nlpid;
+ u8 data[0];
+} frame_relay_hdr_type;
+
+typedef struct fr_snap_hdr_type {
+ u16 address;
+ u8 control;
+ u8 pad;
+ u8 nlpid;
+ u8 oui[3];
+ u16 protocol_id;
+} fr_snap_hdr_type;
+
+#define FR_ADDR_LEN 2
+#define FR_CTL_NLPID_LEN 2
+#define FR_HDR_LEN (FR_ADDR_LEN+FR_CTL_NLPID_LEN)
+
+/*
+ * These defines are for the FR-SNAP header.
+ * The SNAP header is set up solely so that we can
+ * identify ARP packets, which look like this:
+ *
+ * control pad nlpid oui protocol_id
+ * 03 00 80 00 00 00 0806
+ */
+#define FR_ARP_CONTROL 0x03
+#define FR_ARP_PAD 0x00
+#define FR_ARP_NLPID 0x80
+#define FR_ARP_OUI_0 0x00
+#define FR_ARP_OUI_1 0x00
+#define FR_ARP_OUI_2 0x00
+/*
+ * these are used only in the tmc code
+ */
+#define FR_NLPID_OUI_LEN 4
+#define FR_ARP_CONTROL_PAD 0x0300
+#define FR_ARP_NLPID_OUI 0x80000000
+
+
+#define FR_DLCI_UPPER_MASK 0xFC00
+#define FR_DLCI_UPPER_SHIFT 6
+#define FR_DLCI_LOWER_MASK 0x00F0
+#define FR_DLCI_LOWER_SHIFT 4
+
+/*
+ * Defines for converting a DLCI for insertion into a synthesized FR address
+ * field for FRoMPLS disposition.
+
+ * bit 8 7 6 5 4 3 2 1
+ * +-------------------------------+
+ * | Flag |
+ * | 0 1 1 1 1 1 1 0 |
+ * +-------------------------------+
+ * | Upper DLCI |C/R| 0 |
+ * +-------------------------------+
+ * | Lower DLCI | F | B | DE| 1 |
+ * +-------------------------------+
+ * | |
+ * :Frame relay information field :
+ * : (i.e.payload) :
+ * | |
+ * +-------------------------------+
+ * | FCS (2 or 4 octets) |
+ * | |
+ * +-------------------------------+
+ * | Flag |
+ * | 0 1 1 1 1 1 1 0 |
+ * +-------------------------------+
+ *
+ * a-With 10 bits for the DLCI
+ */
+#define FR_DLCI_TO_HDR_UPPER_MASK 0x3f0
+#define FR_DLCI_TO_HDR_UPPER_SHIFT (10-4)
+#define FR_DLCI_TO_HDR_LOWER_MASK 0xf
+#define FR_DLCI_TO_HDR_LOWER_SHIFT 4
+
+#define TYPE_FR_IETF_IP 0x03CC
+#define TYPE_FR_IETF_IP_V6 0x038E
+#define TYPE_FR_CISCO_IP 0x0800
+#define TYPE_FR_CISCO_IP_V6 0x86DD
+#define TYPE_FR_ISIS 0x0383
+#define TYPE_FR_SNAP0PAD 0x0380
+#define TYPE_FR_SNAP1PAD 0x0300
+#define TYPE_FR_FRF12 0x03B1
+#define TYPE_FR_MLP 0x03CF
+#define TYPE_FR_EEK 0x8037
+
+#define FR_LMI_DLCI_CISCO 1023
+#define FR_LMI_DLCI_IETF 0
+
+#define FR_NOT_NOT_NOT 0
+#define FR_NOT_NOT_DE 1
+#define FR_NOT_BECN_NOT 2
+#define FR_NOT_BECN_DE 3
+#define FR_FECN_NOT_NOT 4
+#define FR_FECN_NOT_DE 5
+#define FR_FECN_BECN_NOT 6
+#define FR_FECN_BECN_DE 7
+
+#define FR_FECN_BECN_DE_MASK 0x000E
+#define FR_FECN_BECN_DE_SHIFT 1
+
+/* Address field extension bit for standard 2-byte FR address field */
+#define FR_EA1_MASK 0x0001
+#define FR_EA1_MASK_BIT 0
+
+/*
+ * these are needed in the micro-code, for optimizations
+ */
+
+/* the bit position (in the address field) of the LSB of the DLCI */
+#define FR_DLCI_LS_BIT 4
+
+
+/*
+**
+** MultiLink Frame Relay
+**
+*/
+
+typedef struct mlfr_hdr_type {
+ u16 frag_hdr;
+ u16 address;
+ u16 control_nlpid;
+ u8 data[0];
+} mlfr_hdr_type;
+
+/*
+ * LIP frames have B, E and C set--the other
+ * bits in the frag_hdr field are irrelevant.
+ *
+ * NOTE: Injected LIP packets have a frag_hdr of 0xE100.
+ *
+ */
+#define MLFR_LIP_FRAME 0xE100
+#define MLFR_LIP_MASK 0xE000
+#define MLFR_FRAG_HDR_LEN 2
+
+#define MLFR_BEGIN_MASK 0x8000
+#define MLFR_END_MASK 0x4000
+#define MLFR_BEGIN_END_MASK (MLFR_BEGIN_MASK|MLFR_END_MASK)
+#define MLFR_BEGIN_END_SHIFT 14
+
+#define MLFR_SEQ_NUM_HI_MASK 0x1E00
+#define MLFR_SEQ_NUM_HI_SHIFT 1
+#define MLFR_SEQ_NUM_LO_MASK 0x00FF
+
+/*
+ * these are needed in the micro-code, for optimizations
+ */
+#define MLFR_BEGIN_END_MASK_BYTE 0xC0
+
+
+/*
+ * FRF.12 definitions
+ */
+typedef struct frf12_hdr_type_ {
+ u16 address;
+ u16 control_nlpid;
+ u16 frag_hdr;
+ u8 data[0];
+} frf12_hdr_type;
+
+#define FRF12_FRAG_HDR_LEN sizeof(frf12_hdr_type)
+
+#define FRF12_BEGIN_MASK 0x8000
+#define FRF12_END_MASK 0x4000
+#define FRF12_BEGIN_END_MASK (FRF12_BEGIN_MASK|FRF12_END_MASK)
+#define FRF12_BEGIN_END_SHIFT 8
+
+#define FRF12_SEQ_NUM_HI_MASK 0x1E00
+#define FRF12_SEQ_NUM_HI_SHIFT 1
+#define FRF12_SEQ_NUM_LO_MASK 0x00FF
+#define FRF12_BEGIN_END_MASK_BYTE 0xC0
+
+
+
+/*
+**
+** MLP over Frame Relay
+** The ppp hdr can be either a
+** an MLP hdr or a PPP hdr
+**
+** MLP can be compressed or not:
+** a) 0xff03003d
+** b) 0x003d
+** c) 0x3d
+** followed by:
+** 1 byte with begin/end bits
+** 3 bytes of a sequence #
+**
+** PPP can be also be compressed or not.
+** Only these will be fwded:
+** a) 0xff030021
+** b) 0xff0321
+** c) 0x0021
+** d) 0x21
+**
+**
+*/
+typedef struct mlpofr_hdr_type {
+ u16 address;
+ u16 control_nlpid;
+ u8 ppp_header[0];
+} mlpofr_hdr_type;
+
+/*
+** ATM -
+*/
+
+/*
+ * channel_handle is defined as follows:
+ *
+ * bits 15 = reserved (must be 0)
+ * bits 14 - 0 = channel handle
+ *
+ *
+ * flags is a bitfield defined as follows:
+ *
+ * bits 15 - 13 = proto (PPPoA RFC1661 = 0,
+ * PPPoE = 1,
+ * RBE = 2,
+ * PPPoA Cisco = 3,
+ * MLPoATM RFC1661 = 4,
+ * MLPoATM Cisco = 5,
+ * Reserved = 6-7)
+ * bit 12 = encap (MUX=0,
+ * SNAP=1)
+ * bits 11 - 6 = reserved (must be 0)
+ * bits 5 - 3 = pkt_type (AAL5 pkt = 0,
+ * Raw cell (includes F4 OAM) = 1,
+ * F5 segment OAM cell = 2
+ * F5 end-to-end OAM cell = 3
+ * Reserved = 4-7)
+ * bit 2 = EFCI (congestion indication)
+ * bit 1 = reserved (must be 0)
+ * bit 0 = CLP (cell loss priority)
+ */
+
+typedef struct apollo_atm_generic_hdr_type {
+ u16 channel_handle;
+ u16 flags;
+} apollo_atm_generic_hdr_type;
+
+typedef struct apollo_atm_aal5_snap_hdr_type {
+ u16 channel_handle;
+ u16 flags;
+ u8 dsap;
+ u8 ssap;
+ u8 control;
+ u8 oui[3];
+ u16 type;
+ u8 data[0];
+} apollo_atm_aal5_snap_hdr_type;
+
+typedef struct atm_aal5_snap_hdr_type {
+ u8 dsap;
+ u8 ssap;
+ u8 control;
+ u8 oui[3];
+ u16 pid;
+ u16 pad;
+ u8 data[0];
+} atm_aal5_snap_hdr_type;
+
+
+typedef struct apollo_atm_aal5_snap_hdr1_type {
+ u16 channel_handle;
+ u16 flags;
+ u8 dsap;
+ u8 ssap;
+ u8 control;
+ u8 oui0;
+ u8 oui1;
+ u8 oui2;
+ u16 type;
+ u8 data[0];
+} apollo_atm_aal5_snap_hdr1_type;
+
+typedef struct apollo_atm_aal5_clns_hdr_type {
+ u16 channel_handle;
+ u16 flags;
+ u16 type;
+ u16 data;
+} apollo_atm_aal5_clns_hdr_type;
+
+typedef struct apollo_atm_aal5_ilmi_hdr_type {
+ u16 channel_handle;
+ u16 flags;
+ u8 data[0];
+} apollo_atm_aal5_ilmi_hdr_type;
+
+typedef struct apollo_atm_aal5_mux_hdr_type {
+ u16 channel_handle;
+ u16 flags;
+ u8 data[0];
+} apollo_atm_aal5_mux_hdr_type;
+
+typedef struct apollo_atm_oam_f4_hdr_type {
+ u16 channel_handle;
+ u16 flags;
+ /*
+ * gcf_vpi_vci_pt_clp is a bitfield defined as follows:
+ *
+ * bits 31 - 28 = GCF
+ * bits 27 - 20 = VPI
+ * bits 19 - 4 = VCI
+ * bits 3 - 1 = PT
+ * bit 0 = CLP
+ */
+ u32 gcf_vpi_vci_pt_clp;
+ u8 data[0];
+} apollo_atm_oam_f4_hdr_type;
+
+#define APOLLO_ATM_OAM_F4_HDR_PT_MASK 0xE
+#define APOLLO_ATM_OAM_F4_HDR_PT_SHIFT 1
+
+typedef struct apollo_atm_oam_f5_hdr_type {
+ u16 channel_handle;
+ u16 flags;
+ u8 data[0];
+} apollo_atm_oam_f5_hdr_type;
+
+#define APOLLO_IRONBUS_EXT_LESS_PROTO 0xFFFF0FFF
+#define APOLLO_CHANNEL_HANDLE_MASK 0xFFFF
+#define APOLLO_PKT_TYPE_MASK 0x0038
+#define APOLLO_PKT_TYPE_SHIFT 3
+#define APOLLO_FLAG_CLP_MASK 0x0001
+#define APOLLO_FLAG_CLP_BIT 0
+
+#define APOLLO_CHANNEL_HANDLE_RES_0 0x0000
+/*
+ * The 1 byte HEC field is removed by the line card.
+ */
+#define APOLLO_F4_RX_CELL_SIZE 52
+#define APOLLO_F5_RX_CELL_SIZE 52
+
+#define APOLLO_ATM_PACKET_TYPE_AAL5 0
+#define APOLLO_ATM_PACKET_TYPE_F4 1
+#define APOLLO_ATM_PACKET_TYPE_F5_SEG 2
+#define APOLLO_ATM_PACKET_TYPE_F5_E_TO_E 3
+#define APOLLO_ATM_PACKET_TYPE_4 4
+#define APOLLO_ATM_PACKET_TYPE_5 5
+#define APOLLO_ATM_PACKET_TYPE_6 6
+#define APOLLO_ATM_PACKET_RESERVED 7
+
+#define APOLLO_AAL5_MUX_IP_HDR_LEN 4
+#define APOLLO_AAL5_SNAP_HDR_LEN 12
+
+#define APOLLO_RCV_IRON_BUS_EXT_LEN 4
+#define APOLLO_TX_IRON_BUS_EXT_LEN 8
+
+/*
+ * MLPoA type definitions
+ */
+#define MLPOA_CISCO_HDR 0xFF03
+#define MLPOA_SNAP_HDR_LEN 4
+#define MLPOA_CISCO_HDR_LEN 2
+
+/************************************************************/
+/* PTA PLUS ATM ENCAPSULATIONS */
+
+/* RBE header 28 bytes*/
+typedef struct apollo_atm_aal5_llcsnap_rbe_hdr_type {
+ u16 channel_handle;
+ u16 flags;
+ u8 dsap;
+ u8 ssap;
+ u8 control;
+ u8 oui[3];
+ u16 pid;
+ u16 pad;
+ /* enet header within */
+ u8 daddr[6];
+ u8 saddr[6];
+ u16 type;
+ u8 data[0]; /* start of IP */
+} apollo_atm_aal5_llcsnap_rbe_hdr_type;
+
+/* PPPoEoA header 34 bytes*/
+typedef struct apollo_atm_aal5_llcsnap_pppoe_hdr_type {
+ u16 channel_handle;
+ u16 flags;
+ u8 dsap;
+ u8 ssap;
+ u8 control;
+ u8 oui[3];
+ u16 pid;
+ u16 pad;
+ /* enet header within */
+ u8 daddr[6];
+ u8 saddr[6];
+ u16 type;
+ /* pppoe hdr at begining of enet payload */
+ u16 vtc; /* version(4b), type(4b) and code(8b) fields */
+ u16 sid;
+ u16 len;
+ u8 ppp_header[0]; /* PPP header start, no ff03 field present */
+} apollo_atm_aal5_llcsnap_pppoe_hdr_type;
+
+
+/* PPPoA MUX 4 bytes*/
+typedef struct apollo_atm_aal5_mux_pppoa_hdr_type {
+ u16 channel_handle;
+ u16 flags;
+ u8 ppp_header[0];
+} apollo_atm_aal5_mux_pppoa_hdr_type;
+
+
+/* PPPoA SNAP LLC 8 bytes */
+typedef struct apollo_atm_aal5_llcsnap_pppoa_hdr_type {
+ u16 channel_handle;
+ u16 flags;
+ u8 dsap;
+ u8 ssap;
+ u8 control;
+ u8 nlpid;
+ u8 ppp_header[0];
+} apollo_atm_aal5_llcsnap_pppoa_hdr_type;
+
+/* MLPoA MUX (generic) */
+typedef struct apollo_atm_aal5_mux_mlpoa_hdr_type {
+ u16 channel_handle;
+ u16 flags;
+ u8 ppp_header[0];
+} apollo_atm_aal5_mux_mlpoa_hdr_type;
+
+/* MLPoA SNAP LLC */
+typedef struct apollo_atm_aal5_llcsnap_mlpoa_hdr_type {
+ u16 channel_handle;
+ u16 flags;
+ u8 dsap;
+ u8 ssap;
+ u8 control;
+ u8 nlpid;
+ u8 ppp_header[0];
+} apollo_atm_aal5_llcsnap_mlpoa_hdr_type;
+
+
+#define PPPOA_SNAPLLC_HDR_LEN sizeof(apollo_atm_aal5_llcsnap_pppoa_hdr_type)
+#define PPPOA_MUX_HDR_LEN sizeof(apollo_atm_aal5_mux_pppoa_hdr_type)
+#define PPPOE_SNAPLLC_HDR_LEN sizeof(apollo_atm_aal5_llcsnap_pppoe_hdr_type)
+#define RBE_SNAPLLC_HDR_LEN sizeof(apollo_atm_aal5_llcsnap_rbe_hdr_type)
+
+/* End PTA PLUS ATM ENCAPSULATIONS */
+/****************************************************************/
+
+#define LLCSNAP_PID_DOT3_NOFCS 0x0007
+
+/*
+** the SNAP header
+*/
+
+/*
+ * Note that some of these definitions are split
+ * up along certain word or half word boundaries
+ * to help expediate the TMC code.
+ */
+#define LLC_SNAP_HDR_DSAP 0xAA
+#define LLC_SNAP_HDR_SSAP 0xAA
+#define LLC_SNAP_HDR_CONTROL 0x03
+#define LLC_SNAP_HDR_OUI_0 0x00
+#define LLC_SNAP_HDR_OUI_1 0x00
+#define LLC_SNAP_HDR_OUI_2 0x00
+#define LLC_SNAP_HDR_OUI_2_CDP 0x0C
+
+#define LLC_SNAP_HDR_DSAP_SSAP 0xAAAA
+#define LLC_SNAP_HDR_DSAP_SSAP_CTRL_OUI0 0xAAAA0300
+#define LLC_SNAP_HDR_CONTROL_OUI 0x03000000
+#define LLC_SNAP_HDR_OUI1_OUI2_CDP 0x000C2000
+
+
+
+/*
+** SRP
+*/
+
+/*
+ * The v2_gen_hdr is a 2-byte field that contains the following:
+ *
+ * [ ttl | ring_id | mode | priority | parity ]
+ * bits 8 1 3 3 1
+ */
+typedef struct srp_hdr_type {
+ u16 v2_gen_hdr;
+ u8 dest_addr[6];
+ u8 src_addr[6];
+ u16 protocol;
+ u8 data[0];
+} srp_hdr_type;
+
+#define SRP_HDR_LEN 16
+
+#define SRP_IB_CHANNEL_CONTROL 0x0000
+#define SRP_IB_CHANNEL_DATA_HI 0x0001
+#define SRP_IB_CHANNEL_DATA_LO 0x0002
+
+#define SRP_RING_ID_MASK 0x0080
+#define SRP_RING_ID_BIT 7
+
+#define SRP_MODE_BITS_MASK 0x0070
+#define SRP_MODE_BITS_SHIFT 4
+#define SRP_MODE_CONTROL_TOPOLOGY 4
+#define SRP_MODE_CONTROL_IPS 5
+#define SRP_MODE_DATA 7
+
+#define SRP_PRIORITY_BITS_MASK 0x000E
+#define SRP_PRIORITY_BITS_SHIFT 1
+#define SRP_PRIORITY_HIGH 7
+#define SRP_PRIORITY_PAK_PRIORITY 6
+
+/* this is for the tmc code */
+#define SRP_INV_PRIORITY_BITS_MASK 0xFFF1
+
+#define SRP_PROT_CONTROL_TOPOLOGY 0x2007
+#define SRP_PROT_CONTROL_IPS 0x2007
+
+/* this is for the tmc code */
+#define SRP_TRUE 1
+#define SRP_FALSE 0
+
+/*
+** MPLS
+*/
+#define MPLS_EOS_BIT 0x00000100
+#define MPLS_EOS_SHIFT 8
+#define MPLS_LABEL_SIZE 4
+#define MAX_MPLS_LABEL_STACK 6
+#define MPLS_LABEL_MASK 0xfffff000
+#define MPLS_LABEL_SHIFT 12
+#define MPLS_TTL_MASK 0x000000ff
+#define MPLS_EXP_MASK 0x00000e00
+#define MPLS_EXP_SHIFT 9
+#define MPLS_EXP_TTL_MASK 0x00000eff
+
+
+
+typedef union _layer2 {
+ hdlc_hdr_type hdlc;
+ ppp_comp_hdr_type ppp;
+ ethernet_arpa_hdr_type eth_arpa;
+ ethernet_vlan_hdr_type eth_vlan;
+ ethernet_qinq_hdr_type eth_qinq;
+ ethernet_lacp_hdr_type eth_lacp;
+ ethernet_bpdu_hdr_type eth_bpdu;
+ ethernet_802p3_hdr_type eth_802p3;
+ ethernet_vlan_802p3_hdr_type eth_vlan_802p3;
+ ethernet_pppoe_arpa_hdr_type eth_pppoe_arpa; /* PTA plus */
+ ethernet_pppoe_vlan_hdr_type eth_pppoe_vlan; /* PTA plus */
+ ethernet_pppoe_qinq_hdr_type eth_pppoe_qinq; /* PTA plus */
+ frame_relay_hdr_type frame_relay;
+ fr_snap_hdr_type fr_snap;
+ mlfr_hdr_type mlfr;
+ mlpofr_hdr_type mlpofr;
+ frf12_hdr_type frf12;
+ apollo_atm_generic_hdr_type atm_generic;
+ apollo_atm_aal5_snap_hdr_type atm_aal5_snap;
+ apollo_atm_aal5_snap_hdr1_type atm_aal5_snap1;
+ apollo_atm_aal5_clns_hdr_type atm_aal5_clns;
+ apollo_atm_aal5_ilmi_hdr_type atm_aal5_ilmi;
+ apollo_atm_aal5_mux_hdr_type atm_aal5_mux;
+ apollo_atm_oam_f4_hdr_type atm_oam_f4;
+ apollo_atm_oam_f5_hdr_type atm_oam_f5;
+ apollo_atm_aal5_llcsnap_rbe_hdr_type atm_aal5_rbe_snapllc; /* PTA plus */
+ apollo_atm_aal5_llcsnap_pppoe_hdr_type atm_aal5_pppoe_snapllc; /* PTA plus */
+ apollo_atm_aal5_mux_pppoa_hdr_type atm_aal5_pppoa_mux; /* PTA plus */
+ apollo_atm_aal5_llcsnap_pppoa_hdr_type atm_aal5_pppoa_snapllc; /* PTA plus */
+ apollo_atm_aal5_mux_mlpoa_hdr_type mlpoa_generic;
+ apollo_atm_aal5_llcsnap_mlpoa_hdr_type mlpoa_snapllc;
+ srp_hdr_type srp;
+} layer2_t;
+
+/*
+ * Define the Common OAM cell format - F4 & F5 cells
+ * For F4 cells:
+ * VPI == User VPI
+ * VCI == (3 == Segment), (4 == End-to-End)
+ *
+ * For F5 cells:
+ * VPI == User VPI
+ * VCI == User VCI
+ * PT == (100 == Segment, 101 == End-to-End)
+ *
+ * OAM Cell Type & Function Type:
+ *
+ * OAM_TYPE = (0001 == Fault management)
+ * OAM_FUNC == (0000 == AIS, 0001 == RDI, 0100 == CC,
+ * 1000 == loopback)
+ *
+ * OAM_TYPE = (0010 == Performance management)
+ * OAM_FUNC == (0000 == Forward Monitoring(FM),
+ * 0001 == Backward monitoring(BR),
+ * 0010 == Monitoring & reporting (FM+BR))
+ *
+ * OAM_TYPE = (1000 == Activation/Deactivation)
+ * OAM_FUNC == (0000 == Performance Monitoring,
+ * 0001 == Continuity Check)
+ *
+ * OAM_TYPE = (1111 == Sytem Management)
+ * OAM_FUNC == (0001 == Security - non-real-time,
+ * 0010 == Security - real-time)
+ *
+ */
+#define ATM_OAM_FAULT_MGMT 0x1 /* OAM Fault mgmt. code */
+#define ATM_OAM_PRFRM_MGMT 0x2 /* performance mgmt code */
+#define ATM_OAM_ACT_DEACT 0x8 /* OAM Activation/Deactivation
+ code */
+#define ATM_OAM_SYSTEM_MGMT 0xF /* System Management code */
+
+#define ATM_OAM_AIS_FUNC 0x0 /* AIS function type */
+#define ATM_OAM_RDI_FUNC 0x1 /* RDI function type */
+#define ATM_OAM_CC_FUNC 0x4 /* OAM CC FM function code */
+#define ATM_OAM_LOOP_FUNC 0x8 /* Loopback function type */
+
+#define ATM_OAM_F5_SEGMENT 0x4 /* Segment function */
+#define ATM_OAM_F5_ENDTOEND 0x5 /* End-to-End function */
+#define ATM_OAM_F4_SEGMENT 0x3 /* Segment function */
+#define ATM_OAM_F4_ENDTOEND 0x4 /* End-to-End function */
+#define ATM_OAM_F4_PTI_ZERO 0x0 /* PTI=0 for F4 OAM */
+
+typedef struct atm_oam_hdr_t_ {
+ unsigned oam_gfc:4; /* GFC */
+ unsigned oam_vpi:8; /* VPI */
+ unsigned oam_vci_ms:4; /* VCI (Most Significant Bits) */
+
+ unsigned oam_vci_ls:12; /* VCI (Least Significant Bits) */
+ unsigned oam_pt:3; /* Payload Type */
+ unsigned oam_clp:1; /* Cell Loss Priority */
+ u8 data[0];
+} atm_oam_hdr_t;
+
+typedef struct atm_oam_type_func_t_ {
+ u8 oam_type:4;
+ u8 oam_func:4;
+ u8 data[0];
+} atm_oam_type_func_t;
+
+/*
+** IP Version 4 header
+*/
+
+/*
+ * version_hdr_len_words [7-4] IP Header Version
+ * [3-0] IP Header Length in 32-bit words
+ * tos Type of Service
+ * total_len_bytes Total IP datagram length in bytes
+ * (including IP header)
+ * identification Unique fragmentation identifier
+ * frag_flags_offset [15-13] Fragmentation flags
+ * [12-0] Fragmentation Offset
+ * ttl Time To Live
+ * protocol_id Protocol Identifier
+ * checksum 16-bit 1's complement IP Header checksum
+ * src_addr IP Source Address
+ * dest_addr IP Destination Address
+ */
+typedef struct ipv4_header {
+ u8 version_hdr_len_words;
+ u8 tos;
+ u16 total_len_bytes;
+ u16 identification;
+ u16 frag_flags_offset;
+ u8 ttl;
+ u8 protocol;
+ u16 checksum;
+ u32 src_addr;
+ u32 dest_addr;
+ u8 data[0];
+} ipv4_header;
+
+/*OPTIONS PACKET TYPE
+ * +-+-+-+-+-+-+-+-+
+ * |C| CL| OP |
+ * +-+-+-+-+-+-+-+-+
+ */
+typedef struct ipv4_options {
+ u8 copy :1 ;
+ u8 op_class :2 ;
+ u8 option :5 ;
+ u8 pad ;
+}ipv4_options;
+
+#define LOOSE_SOURCE_ROUTE 131
+#define STRICT_SOURCE_ROUTE 137
+#define IPV4_NO_OPTIONS_HDR_LEN (sizeof(ipv4_header))
+#define IPV4_VERSION 4
+#define IPV4_HEADER_LENGTH_WORDS 5
+#define IPV4_VERSION_HDR_LEN_FIELD ((u8) 0x45)
+#define IPV4_HEADER_LENGTH_WORDS 5
+#define IPV4_MIN_HEADER_LENGTH_BYTES 20
+#define IP_HDR_LEN sizeof(ipv4_header)
+#define IPV4_VERSION_VALUE_SHIFT 4
+
+#define IPV4_FRAG_OFFSET_MASK (0x1fff)
+#define IPV4_FRAG_MF_MASK (0x2000)
+#define IPV4_FRAG_MF_SHIFT (13)
+
+/* 0.0.0.0 */
+#define IP_BOOTP_SOURCE_ADDRESS 0
+/* 255.255.255.255 */
+#define IP_LIMITED_BROADCAST_ADDRESS 0xFFFFFFFF
+
+/*
+ * IPv4 header - version & length fields
+ */
+#define IP_VER_LEN 0x45
+#define IP_VER 0x4
+#define IP_MIN_LEN 0x5
+#define IP_VER_MASK 0xf0
+#define IP_LEN_MASK 0x0f
+
+/*
+ * IPv4 header - TOS field
+ */
+#define PS_IP_TOS_MASK 0xff
+#define IP_PRECEDENCE_SHIFT 5 /* shift value up to precedence bits */
+#define IP_DSCP_SHIFT 2 /* shift value up to dscp bits */
+
+#define IP_TOS_PRECEDENCE 0xe0 /* mask of precedence in tos byte */
+#define IP_TOS_NO_PRECEDENCE 0x1f
+#define IP_TOS_LOW_DELAY 8 /* values must be shifted 1 bit */
+#define IP_TOS_HIGH_TPUT 4 /* before using */
+#define IP_TOS_HIGH_RELY 2
+#define IP_TOS_LOW_COST 1
+#define IP_TOS_NORMAL 0
+#define IP_TOS_MASK 0x1e /* mask of tos in tos byte */
+#define IP_TOS_MBZ_MASK 0x01 /* mask for MZB bit in tos byte */
+#define IP_TOS_DSCP 0xfc /* mask for dscp in tos byte */
+#define IP_TOS_NO_DSCP 0x03
+
+#define IP_TOS_METRIC_TYPES 8
+#define IP_TOS_SHIFT 1
+
+#define IP_TOS_PRECEDENCE_MASK (IP_TOS_PRECEDENCE | IP_TOS_MASK)
+
+/*
+ * IP TOS Precedence values (High order 3 bits)
+ */
+#define TOS_PREC_NET_CONTROL 0xe0
+#define TOS_PREC_INET_CONTROL 0xc0
+#define TOS_PREC_CRIT_ECP 0xa0
+#define TOS_PREC_FLASH_OVER 0x80
+#define TOS_PREC_FLASH 0x60
+#define TOS_PREC_IMMEDIATE 0x40
+#define TOS_PREC_PRIORITY 0x20
+#define TOS_PREC_ROUTINE 0x00
+#define TOS_PREC_ILLEGAL 0xff /* invalid precedence value */
+
+#define TOS_PREC_NET_CONTROL_NUM 7
+#define TOS_PREC_INET_CONTROL_NUM 6
+#define TOS_PREC_CRIT_ECP_NUM 5
+#define TOS_PREC_FLASH_OVER_NUM 4
+#define TOS_PREC_FLASH_NUM 3
+#define TOS_PREC_IMMEDIATE_NUM 2
+#define TOS_PREC_PRIORITY_NUM 1
+#define TOS_PREC_ROUTINE_NUM 0
+
+
+
+/*
+ * IPv4 header - flags and fragment offset fields
+ */
+#define IP_FRAG_OFFSET_MASK 0x1fff
+
+
+#define IP_FRAG_MORE_MASK 0x2000
+#define IP_FRAG_DF_MASK 0x4000
+#define IP_FRAG_UNDEF_MASK 0x8000
+#define IP_FRAG_NO_DF_SET 0x0000
+
+/* bit definitions for fragment flags */
+#define IP_FRAG_MORE_BIT 13
+#define IP_FRAG_DF_BIT 14
+#define IP_FRAG_UNDEF_BIT 15
+
+/*
+ * IPv4 header - TTL field
+ */
+#define TTL_DEFAULT 255
+#define TTL_1 1
+#define TTL_2 2
+#define TTL_255 255
+
+
+/*
+ * IPv4 header - protocol field
+ *
+ * ICMP_PROT 1 ICMP
+ * IGMP_PROT 2 group management
+ * GGP_PROT 3 GGP
+ * IPINIP_PROT 4 IPv4 in IPv4 encapsulation
+ * TCP_PROT 6 TCP
+ * EGP_PROT 8 EGP
+ * IGRP_PROT 9 IGRP
+ * UDP_PROT 17 UDP
+ * HMP_PROT 20 HMP
+ * RDP_PROT 27 RDP
+ * IPV6_INIP_PROT 41 IPV6 in IPv4 encapsulation
+ * RSVP_PROT 46 RSVP
+ * GRE_PROT 47 GRE
+ * ESP_PROT 50 ESP
+ * AHP_PROT 51 AHP
+ * SDNS0_PROT 53 SNDS
+ * NHRP_PROT 54 NHRP
+ * SDNS1_PROT 55 SDNS1
+ * HELLO_PROT 63 HELLO
+ * ND_PROT 77 ND
+ * EONIP_PROT 80 CLNS over IP
+ * VINES_PROT 83 Banyan Vines
+ * NEWIGRP_PROT 88 IGRP
+ * OSPF_PROT 89 OSPF
+ * FST_RSRB_PROT 90 RSRB
+ * FST_DLSW_PROT 91 DLSW
+ * NOSIP_PROT 94 KA9Q/NOS compatible IP over IP
+ * PIM_PROT 103 PIMv2
+ * PCP_PROT 108 PCP
+ * PGM_PROT 113 PGM
+ * MAX_PROT 113 maximum protocol number in the above list,
+ * used in creating case registry
+ */
+#define ICMP_PROT 1
+#define IGMP_PROT 2
+#define GGP_PROT 3
+#define IPINIP_PROT 4
+#define TCP_PROT 6
+#define EGP_PROT 8
+#define IGRP_PROT 9
+#define UDP_PROT 17
+#define HMP_PROT 20
+#define RDP_PROT 27
+#define IPV6_INIP_PROT 41
+#define RSVP_PROT 46
+#define GRE_PROT 47
+#define ESP_PROT 50
+#define AHP_PROT 51
+#define SDNS0_PROT 53
+#define NHRP_PROT 54
+#define SDNS1_PROT 55
+#define HELLO_PROT 63
+#define ND_PROT 77
+#define EONIP_PROT 80
+#define VINES_PROT 83
+#define NEWIGRP_PROT 88
+#define OSPF_PROT 89
+#define FST_RSRB_PROT 90
+#define FST_DLSW_PROT 91
+#define NOSIP_PROT 94
+#define PIM_PROT 103
+#define PCP_PROT 108
+#define PGM_PROT 113
+#define MAX_PROT 113
+
+/*Well Known Application ports */
+#define FTP_PORT 21 /* For control connection */
+/*
+ * TCP header
+ */
+typedef struct tcp_hdr_type {
+ u16 src_port;
+ u16 dest_port;
+ u32 seq_num;
+ u32 ack_num;
+ u8 hdr_len;
+ u8 flags;
+ u16 window_size;
+ u16 tcp_checksum;
+ u16 urgent_pointer;
+ u8 option_data[0];
+} tcp_hdr_type;
+
+#define TCP_FLAG_FIN 0x01
+#define TCP_FLAG_SYN 0x02
+#define TCP_FLAG_RST 0x04
+#define TCP_FLAG_PUSH 0x08
+#define TCP_FLAG_ACK 0x10
+#define TCP_FLAG_URG 0x20
+#define TCP_FLAG_ECE 0x40
+#define TCP_FLAG_CWR 0x80
+
+/*
+ * TCP Option
+ */
+typedef struct tcp_option_s {
+ u8 kind;
+ u8 length;
+ u8 data[0];
+} tcp_option_t;
+
+#define TCP_END_OPTIONS_LIST 0
+#define TCP_OPTION_NOP 1
+#define TCP_OPTION_MSS 2
+#define TCP_OPTION_WINDOW_SCALE 3
+#define TCP_OPTION_SACK_PERMITTED 4
+#define TCP_OPTION_SACK_DATA 5
+#define TCP_OPTION_ECHO 6
+#define TCP_OPTION_ECHO_REPLY 7
+#define TCP_OPTION_TSOPT 8
+/*
+ 9 2 Partial Order Connection Permitted. RFC 1693
+ 10 3 Partial Order Service Profile. RFC 1693
+ 11 6 CC, Connection Count. RFC 1644
+ 12 6 CC.NEW RFC 1644
+ 13 6 CC.ECHO RFC 1644
+ 14 3 TCP Alternate Checksum Request. RFC 1146
+ 15 Variable. TCP Alternate Checksum Data. RFC 1146
+ 16 Skeeter.
+ 17 Bubba.
+ 18 3 Trailer Checksum Option.
+*/
+#define TCP_OPTION_MD5_SIGNATURE 19
+/*
+ 20 SCPS Capabilities.
+ 21 Selective Negative Acknowledgements.
+ 22 Record Boundaries.
+ 23 Corruption experienced.
+ 24 SNAP.
+ 25
+ 26 TCP Compression Filter.
+*/
+#define TCP_OPTION_QUICK_START 27
+
+#define TCP_OPTION_NUM_MAX 27
+
+#ifdef TARGET_CISCO
+#define tcp_printf(format_str, params...) //printf(format_str, ## params)
+#else
+#define tcp_printf(format_str, params...) printf(format_str, ## params)
+#endif
+
+typedef struct udp_hdr_type {
+ u16 src_port;
+ u16 dest_port;
+ u16 udp_length;
+ u16 udp_checksum;
+} udp_hdr_type_t;
+
+#define TYPE_IPV6 0x86dd
+#define TYPE_IPV4 0x0800
+
+/*
+ * version_trafficclass_flowlabel [31:28] IP Header Version,
+ [27:20] traffic_class,
+ [19:0] flow_label[20]
+ * payload_length Length of packet in bytes excluding header size(s)
+ * next_header Identifies the type of header following the IPv6 header
+ * hop_limit Decremented by 1 by each forwarding node, packet discarded when zero
+ * src_addr IPv6 Source Address
+ * dst_addr IPv6 Destination Address
+ */
+typedef struct ipv6_header {
+ u32 version_trafficclass_flowlabel;
+ u16 payload_length;
+ u8 next_header;
+ u8 hop_limit;
+ u32 src_addr[4];
+ u32 dst_addr[4];
+ u8 data[0];
+} ipv6_header_t;
+
+#define IPV6_HDR_LEN 40
+#define IPV6_HDR_LEN_WORDS 10
+#define IPV6_FLABLE_MASK 0x000FFFFF
+#define IPV6_MIN_PATH_MTU (1280)
+
+#define IPV6_GET_IP_VER(ih) ((clib_net_to_host_u32((ih) \
+ ->version_trafficclass_flowlabel) >> 28) & 0xf)
+#define IPV6_GET_TOS(ih) ((clib_net_to_host_u32((ih) \
+ ->version_trafficclass_flowlabel) >> 20) & 0xff)
+#define IPV6_GET_FLOW_LABEL(ih) ((clib_net_to_host_u32((ih) \
+ ->version_trafficclass_flowlabel)) & 0xfffff)
+
+#define IPV6_VERSION_VALUE (6)
+#define IPV6_VERSION_VALUE_SHIFT (28)
+#define IPV6_TRAFFIC_CLASS_VALUE_SHIFT (20)
+#define IPV6_TRAFFIC_CLASS_VALUE_MASK (0xff)
+
+#define IPV6_PROTO_HOPOPTS 0
+#define IPV6_PROTO_TCP 6
+#define IPV6_PROTO_UDP 17
+#define IPV6_PROTO_IPV6 41
+#define IPV6_PROTO_ROUTING 43
+#define IPV6_PROTO_FRAGMENT 44
+#define IPV6_PROTO_DESTOPTS 60
+#define IPV6_PROTO_ESP 50
+#define IPV6_PROTO_AH 51
+#define IPV6_PROTO_ICMPV6 58
+#define IPV6_PROTO_NONE 59
+
+/* standard v6 extension header are 2 tytes
+ * one byte next header
+ * one byte header length
+ */
+
+typedef struct ipv6_frag_header {
+ u8 next_header;
+ u8 reserved;
+ u16 frag_offset_res_m;
+ u32 identification;
+} ipv6_frag_header_t;
+
+#define IPV6_FRAG_HDR_LEN (sizeof(ipv6_frag_header_t))
+
+#define IPV6_FRAG_OFFSET_MASK (0xFFF8)
+#define IPV6_FRAG_OFFSET_SHIFT (3)
+#define IPV6_FRAG_MORE_FRAG_MASK (0x0001)
+
+#define IPV6_TOS_SHIFT 20
+#define IPV6_TOS_SHIFT_HLF_WD 4
+#define IPV6_NEXT_HDR_SHIFT 8
+
+typedef struct ipv6_routing_header {
+ u8 next_header;
+ u8 hdr_ext_len;
+ u8 routing_type;
+ u8 segments_left;
+ u8 data[0];
+} ipv6_routing_header_t;
+#define IPV6_ROUTING_HDR_LEN (sizeof(ipv6_routing_header_t))
+
+typedef struct ipv6_hop_header {
+ u8 next_header;
+ u8 hdr_ext_len;
+ u8 options[0];
+} ipv6_hop_header_t;
+#define IPV6_HOP_LEN (sizeof(ipv6_hop_header_t))
+
+typedef struct ipv6_dest_opt_header {
+ u8 next_header;
+ u8 hdr_ext_len;
+ u8 options[0];
+} ipv6_dest_opt_header_t;
+#define IPV6_DESTOPT_LEN (sizeof(ipv6_dest_opt_header_t))
+
+
+/* Definition of ICMP header */
+typedef struct icmp_v4_s {
+ u8 type;
+ u8 code;
+ u16 checksum;
+ u16 identifier;
+ u16 sequence;
+} icmp_v4_t;
+
+#define ICMPV4_HDR_SIZE (sizeof(icmp_v4_t))
+#define ICMPV4_ECHOREPLY 0 /* Type: echo reply */
+#define ICMPV4_ECHO 8 /* Type: echo request */
+
+#define ICMPV4_UNREACHABLE 3 /* Type: destination unreachable */
+#define ICMPV4_UNRNET 0 /* Code: Net unreachable */
+#define ICMPV4_UNRHOST 1 /* Code: host unreachable */
+#define ICMPV4_UNRPROT 2 /* Code: protocol unreachable */
+#define ICMPV4_UNRPORT 3 /* Code: port unreachable */
+#define ICMPV4_UNRFRAG 4 /* Code: frag req DF set */
+#define ICMPV4_UNRADMIN 13 /* Code: administratively prohib. */
+#define ICMPV4_SOURCEROUTE_FAILED 5 /* Code: administratively prohib. */
+
+#define ICMPV4_SRC_ROUTE_FAIL 5 /* Code: Source Route Failed */
+#define ICMPV4_NO_ROUTE_DESTN_8 8 /* Code: No Route to Destn */
+#define ICMPV4_NO_ROUTE_DESTN_11 11 /* Code: No Route to Destn */
+#define ICMPV4_NO_ROUTE_DESTN_12 12 /* Code: No Route to Destn */
+
+#define ICMPV4_ADMIN_PROH_9 9 /* Code: Administratively Prohibited */
+#define ICMPV4_ADMIN_PROH_10 10 /* Code: Administratively Prohibited */
+#define ICMPV4_PREC_CUTOFF 15 /* Code: Precedence Cutoff */
+
+
+#define ICMPV4_TIMEEXCEEDED 11 /* Type: time exceeded */
+#define ICMPV4_TIMTTL 0 /* Code: ttl in transit code */
+
+#define ICMPV4_PARAMETER_PROBLEM 12 /* Type: Parameter Problem */
+#define ICMPV4_PARAM_ERROR 0 /* Code: Pointer to Error */
+#define ICMPV4_MISSING_OPTION_CODE 1 /* Code: Mission option */
+#define ICMPV4_PARAM_BAD_LEN 2 /* Code: Bad Length */
+
+#define ICMPV4_CONVERSION_ERROR 31
+#define ICMPV4_SOURCE_QUENCH 4
+#define ICMPV4_REDIRECT 5
+#define ICMPV4_TIMESTAMP 13
+#define ICMPV4_TIMESTAMP_REPLY 14
+#define ICMPV4_INFO_REQUEST 15
+#define ICMPV4_INFO_REPLY 16
+#define ICMPV4_ADDR_MASK_REQUEST 17
+#define ICMPV4_ADDR_MASK_REPLY 18
+
+typedef struct icmp_v6_s {
+
+ u8 type;
+ u8 code;
+ u16 checksum;
+
+ u32 data[0];
+} icmp_v6_t;
+
+typedef struct pseudo_v6_header {
+ u32 src_addr[4];
+ u32 dst_addr[4];
+ u16 payload_length;
+ u16 next_header;
+} pseudo_v6_header_t;
+
+
+#define ICMPV6_ECHO 128
+#define ICMPV6_ECHO_REPLY 129
+#define ICMPV6_PKT_TOO_BIG 2
+#define ICMPV6_TIMEEXCEEDED 3
+#define ICMPV6_TIMTTL 0
+#define ICMPV6_PARAMETER_PROBLEM 4
+#define ICMPV6_UNREACHABLE 1
+#define ICMPV6_NEIGHBOR_SOLICITAION 135
+#define ICMPV6_NEIGHBOR_ADVT 136
+/* ICMP V6 generated packet size */
+#define ICMPV6_ERR_SIZE 48
+#define ICMPV6_HDR_SIZE (sizeof(icmp_v6_t) +sizeof(u32))
+
+/* Code for Type 1 */
+#define ICMPV6_UNRDESTN 0 /* Code: No route to Desnt */
+#define ICMPV6_ADM_PROH 1 /* Code: Adminitrative Prohibited */
+#define ICMPV6_SRC_ADD_SCOPE 2 /* Code: Source Address beyond scope */
+#define ICMPV6_UNRHOST 3 /* Code: Host Unreachable */
+#define ICMPV6_UNRPORT 4 /* Code: Port UnReachable */
+
+#define ICMPV6_UNRPROT 1 /* type 4 - Code: No route to Desnt */
+
+#define ICMPV6_PTB_CODE 0 /* Code: For PTB */
+#define ICMPV6_PARAM_CODE 0 /* Code: For Parameter Problem */
+#define ICMPV6_UNREC_HDR 1 /* Code: For Parameter Problem */
+#define ICMPV6_SRC_ADD_FAIL 5 /* Code: For Source address failed */
+#define ICMP_ECHO_REPLY_CODE 0
+#define DEFAULT_TTL_HOPLIMIT_VAL 64
+
+typedef struct pptp_hdr_type {
+
+ u16 flags_ver;
+ u16 proto_type; /* PPP = 0x880B */
+ u16 payload_len;
+ u16 call_id;
+ u32 seq_no;
+ u32 ack_no;
+
+} pptp_hdr_type_t;
+
+/*
+ * NAME
+ *
+ * tcp_findoption
+ *
+ * SYNOPSIS
+ * u8* tcp_findoption (tcp_hdr_t *tcp, uchar option)
+ *
+ * PARAMETERS
+ * tcp - pointer to TCP header
+ * option - TCP option
+ *
+ * RETURNS
+ * This function returns a pointer to the option found,
+ * otherwise returns null.
+ *
+ *
+ * DESCRIPTION
+ * This function searches the option and returns a pointer to the
+ * matched option field containing option kind/length/data sub-fields.
+ *
+ */
+static inline u8* tcp_findoption (tcp_hdr_type *tcp, u8 option)
+{
+ u8*data;
+ u8 len, optlen;
+
+ data = tcp->option_data;
+ len = ((tcp->hdr_len>>4) << 2) - sizeof(tcp_hdr_type);
+
+#define MAXTCPOPTIONBYTES 40
+#define MINTCPOPTIONLENGTH 2
+
+ while (len) {
+ if (PREDICT_TRUE(option == data[0])) {
+ return (data);
+ } else {
+ switch (data[0]) {
+ case TCP_END_OPTIONS_LIST:
+ return (NULL);
+ case TCP_OPTION_NOP:
+ len -= 1;
+ data += 1;
+ break;
+ default:
+ /* Sanity check the length. */
+ optlen = data[1];
+ if ((optlen < MINTCPOPTIONLENGTH) ||
+ (optlen > MAXTCPOPTIONBYTES) ||
+ (optlen > len)) {
+ return (NULL);
+ }
+ len -= optlen;
+ data += optlen;
+ break;
+ }
+ }
+ }
+
+ return (NULL);
+}
+
+
+static inline u32 crc_calc (ipv4_header *ipv4)
+{
+ u16 *ipv4_word_ptr = (u16 *) ipv4;
+ u32 crc32;
+ /*
+ * Add all fields except the checksum field
+ */
+ crc32 = (u32)clib_net_to_host_u16(*ipv4_word_ptr) +
+ (u32)clib_net_to_host_u16(*(ipv4_word_ptr + 1)) +
+ (u32)clib_net_to_host_u16(*(ipv4_word_ptr + 2)) +
+ (u32)clib_net_to_host_u16(*(ipv4_word_ptr + 3)) +
+ (u32)clib_net_to_host_u16(*(ipv4_word_ptr + 4)) +
+ (u32)clib_net_to_host_u16(*(ipv4_word_ptr + 6)) +
+ (u32)clib_net_to_host_u16(*(ipv4_word_ptr + 7)) +
+ (u32)clib_net_to_host_u16(*(ipv4_word_ptr + 8)) +
+ (u32)clib_net_to_host_u16(*(ipv4_word_ptr + 9));
+
+ /* Add in the carry of the original sum */
+ crc32 = (crc32 & 0xFFFF) + (crc32 >> 16);
+ /* Add in the carry of the final sum */
+ crc32 = (crc32 & 0xFFFF) + (crc32 >> 16);
+
+ return crc32;
+}
+
+#endif /* __TCP_HEADER_DEFINITIONS_H__ */
diff --git a/vpp/plugins/vcgn-plugin/vcgn/vcgn_classify.c b/vpp/plugins/vcgn-plugin/vcgn/vcgn_classify.c
new file mode 100644
index 00000000..b9917df6
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/vcgn_classify.c
@@ -0,0 +1,1508 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/plugin/plugin.h>
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <vnet/pg/pg.h>
+#include <vppinfra/error.h>
+#include <vppinfra/pool.h>
+
+#include <vnet/ip/ip.h>
+#include <vnet/ethernet/ethernet.h>
+
+#include "cnat_db.h"
+#include "cnat_global.h"
+#include "cnat_cli.h"
+#include "cnat_config.h"
+#include "cnat_logging.h"
+#include "cnat_config_api.h"
+#include "cnat_show_api.h"
+#include "cnat_show_response.h"
+#include "cnat_ipv4_udp.h"
+#include "cnat_common_api.h"
+
+#include <arpa/inet.h>
+
+typedef struct {
+ u32 cached_next_index;
+
+ /* inside, outside interface handles */
+ u32 * inside_sw_if_index_table;
+ u32 * outside_sw_if_index_table;
+
+ /* convenience variables */
+ vlib_main_t * vlib_main;
+ vnet_main_t * vnet_main;
+ u8 cnat_db_initalized;
+} vcgn_classify_main_t;
+
+typedef struct {
+ /* $$$$ fill in with per-pkt trace data */
+ u32 next_index;
+ u32 sw_if_index;
+ u32 orig_dst_address;
+ u16 orig_dst_port;
+} vcgn_classify_trace_t;
+
+#define FIND_MY_VRF_USING_I_VRF_ID \
+ my_vrfmap_found = 0; \
+ pool_foreach (my_vrfmap, cnat_map_by_vrf, ({ \
+ if (my_vrfmap->i_vrf_id == i_vrf_id) { \
+ my_vrfmap_found = 1; \
+ my_vrfmap_temp = my_vrfmap; \
+ break; \
+ } \
+ }));
+
+
+/* packet trace format function */
+static u8 * format_swap_trace (u8 * s, va_list * args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+ vcgn_classify_trace_t * t = va_arg (*args, vcgn_classify_trace_t *);
+
+ s = format (s, "VCGN_CLASSIFY: dst %U dst_port %d sw_if_index %d next %d",
+ format_ip4_address, (ip4_header_t *) &t->orig_dst_address,
+ clib_net_to_host_u16(t->orig_dst_port),
+ t->sw_if_index, t->next_index);
+ return s;
+}
+
+vcgn_classify_main_t vcgn_classify_main;
+
+vlib_node_registration_t vcgn_classify_node;
+
+#define foreach_vcgn_classify_error \
+_(PACKETS_RECEIVED, "total packets received") \
+_(V4_PACKETS_PROCESSED, "ipv4 packets processed for vCGN") \
+_(V4_PACKETS_PUNTED, "ipv4 packets punted") \
+_(V6_PACKETS_PUNTED, "ipv6 packets punted") \
+_(MPLS_PACKETS_PUNTED, "mpls unicast packets punted") \
+_(ETH_PACKETS_PUNTED, "ethernet packets punted")
+
+
+typedef enum {
+#define _(sym,str) VCGN_CLASSIFY_ERROR_##sym,
+ foreach_vcgn_classify_error
+#undef _
+ VCGN_CLASSIFY_N_ERROR,
+} vcgn_classify_error_t;
+
+static char * vcgn_classify_error_strings[] = {
+#define _(sym,string) string,
+ foreach_vcgn_classify_error
+#undef _
+};
+
+/*
+ * To drop a pkt and increment one of the previous counters:
+ *
+ * set b0->error = error_node->errors[VCGN_CLASSIFY_ERROR_EXAMPLE];
+ * set next0 to a disposition index bound to "error-drop".
+ *
+ * To manually increment the specific counter VCGN_CLASSIFY_ERROR_EXAMPLE:
+ *
+ * vlib_node_t *n = vlib_get_node (vm, vcgn_classify.index);
+ * u32 node_counter_base_index = n->error_heap_index;
+ * vlib_error_main_t * em = &vm->error_main;
+ * em->counters[node_counter_base_index + VCGN_CLASSIFY_ERROR_EXAMPLE] += 1;
+ *
+ */
+
+typedef enum {
+ VCGN_CLASSIFY_NEXT_IP4_INPUT,
+ VCGN_CLASSIFY_NEXT_IP6_INPUT,
+ VCGN_CLASSIFY_NEXT_MPLS_INPUT,
+ VCGN_CLASSIFY_NEXT_ETHERNET_INPUT,
+ VCGN_CLASSIFY_NEXT_UDP_INSIDE,
+ VCGN_CLASSIFY_NEXT_UDP_OUTSIDE,
+ VCGN_CLASSIFY_NEXT_TCP_INSIDE,
+ VCGN_CLASSIFY_NEXT_TCP_OUTSIDE,
+ VCGN_CLASSIFY_NEXT_ICMP_Q_INSIDE,
+ VCGN_CLASSIFY_NEXT_ICMP_Q_OUTSIDE,
+ VCGN_CLASSIFY_NEXT_ICMP_E_INSIDE,
+ VCGN_CLASSIFY_NEXT_ICMP_E_OUTSIDE,
+ VCGN_CLASSIFY_N_NEXT,
+} vcgn_classify_next_t;
+
+static uword
+vcgn_classify_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ u32 n_left_from, * from, * to_next;
+ vcgn_classify_next_t next_index;
+ vcgn_classify_main_t * vcm = &vcgn_classify_main;
+ vlib_node_t *n = vlib_get_node (vm, vcgn_classify_node.index);
+ u32 node_counter_base_index = n->error_heap_index;
+ vlib_error_main_t * em = &vm->error_main;
+ u16 *l3_type;
+ int counter;
+
+ from = vlib_frame_vector_args (frame);
+ n_left_from = frame->n_vectors;
+ next_index = node->cached_next_index;
+
+ while (n_left_from > 0)
+ {
+ u32 n_left_to_next;
+
+ vlib_get_next_frame (vm, node, next_index,
+ to_next, n_left_to_next);
+
+ #if 0
+ while (n_left_from >= 4 && n_left_to_next >= 2)
+ {
+ u32 bi0, bi1;
+ vlib_buffer_t * b0, * b1;
+ u32 next0, next1;
+ u32 sw_if_index0, sw_if_index1;
+
+ /* Prefetch next iteration. */
+ {
+ vlib_buffer_t * p2, * p3;
+
+ p2 = vlib_get_buffer (vm, from[2]);
+ p3 = vlib_get_buffer (vm, from[3]);
+
+ vlib_prefetch_buffer_header (p2, LOAD);
+ vlib_prefetch_buffer_header (p3, LOAD);
+
+ CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
+ CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
+ }
+
+ /* speculatively enqueue b0 and b1 to the current next frame */
+ to_next[0] = bi0 = from[0];
+ to_next[1] = bi1 = from[1];
+ from += 2;
+ to_next += 2;
+ n_left_from -= 2;
+ n_left_to_next -= 2;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ b1 = vlib_get_buffer (vm, bi1);
+
+ sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
+ next0 = vcm->cached_next_index;
+ sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_RX];
+ next1 = vcm->cached_next_index;
+
+ /* $$$$ your message in this space. Process 2 x pkts */
+ em->counters[node_counter_base_index + VCGN_CLASSIFY_ERROR_PACKETS_RECEIVED] += 2;
+
+ if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)))
+ {
+ if (b0->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ vcgn_classify_trace_t *t =
+ vlib_add_trace (vm, node, b0, sizeof (*t));
+ t->sw_if_index = sw_if_index0;
+ t->next_index = next0;
+ }
+ if (b1->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ vcgn_classify_trace_t *t =
+ vlib_add_trace (vm, node, b1, sizeof (*t));
+ t->sw_if_index = sw_if_index1;
+ t->next_index = next1;
+ }
+ }
+
+ /* verify speculative enqueues, maybe switch current next frame */
+ vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
+ to_next, n_left_to_next,
+ bi0, bi1, next0, next1);
+ }
+ #endif /* if 0 */
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ u32 bi0;
+ vlib_buffer_t * b0;
+ u32 next0;
+ u32 sw_if_index0;
+ ip4_header_t * h0;
+ //ipv4_header *h0;
+ ethernet_header_t *eth0;
+ icmp_v4_t *icmp;
+ u8 icmp_type;
+ u8 ipv4_hdr_len;
+
+ /* speculatively enqueue b0 to the current next frame */
+ bi0 = from[0];
+ to_next[0] = bi0;
+ from += 1;
+ to_next += 1;
+ n_left_from -= 1;
+ n_left_to_next -= 1;
+
+ b0 = vlib_get_buffer (vm, bi0);
+
+ eth0 = (ethernet_header_t *) vlib_buffer_get_current(b0);
+ u16 *etype = &eth0->type;
+
+ /* vlan tag 0x8100 */
+ if (*etype == clib_host_to_net_u16(ETHERNET_TYPE_VLAN)) {
+ l3_type = (etype + 1); /* Skip 2 bytes of vlan id */
+ vlib_buffer_advance(b0, 18);
+ } else {
+ l3_type = etype;
+ vlib_buffer_advance(b0, 14);
+ }
+ /* Handling v4 pkts 0x800 */
+ if (*l3_type == clib_host_to_net_u16(ETHERNET_TYPE_IP4)) {
+
+ h0 = vlib_buffer_get_current (b0);
+
+ u8 protocol_type = h0->protocol;
+
+ sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX];
+ next0 = VCGN_CLASSIFY_NEXT_IP4_INPUT;
+ counter = VCGN_CLASSIFY_ERROR_V4_PACKETS_PROCESSED;
+
+ if (protocol_type == 0x11) { /* UDP# 17 */
+ next0 = (sw_if_index0 < vec_len(vcm->inside_sw_if_index_table) &&
+ vcm->inside_sw_if_index_table[sw_if_index0] != EMPTY) ?
+ VCGN_CLASSIFY_NEXT_UDP_INSIDE : next0;
+
+ next0 = (sw_if_index0 < vec_len(vcm->outside_sw_if_index_table) &&
+ vcm->outside_sw_if_index_table[sw_if_index0] != EMPTY) ?
+ VCGN_CLASSIFY_NEXT_UDP_OUTSIDE : next0;
+
+ } else if (protocol_type == 0x06) { /* TCP# 6 */
+ next0 = (sw_if_index0 < vec_len(vcm->inside_sw_if_index_table) &&
+ vcm->inside_sw_if_index_table[sw_if_index0] != EMPTY) ?
+ VCGN_CLASSIFY_NEXT_TCP_INSIDE : next0;
+
+ next0 = (sw_if_index0 < vec_len(vcm->outside_sw_if_index_table) &&
+ vcm->outside_sw_if_index_table[sw_if_index0] != EMPTY) ?
+ VCGN_CLASSIFY_NEXT_TCP_OUTSIDE : next0;
+
+ } else if (protocol_type == 0x01) { /* ICMP # 1 */
+
+ ipv4_hdr_len = (h0->ip_version_and_header_length & 0xf) << 2;
+ icmp = (icmp_v4_t *)((u8*)h0 + ipv4_hdr_len);
+ icmp_type = icmp->type;
+
+ if ((icmp_type == ICMPV4_ECHO) ||
+ (icmp_type == ICMPV4_ECHOREPLY)) {
+ next0 = (sw_if_index0 < vec_len(vcm->inside_sw_if_index_table) &&
+ vcm->inside_sw_if_index_table[sw_if_index0] != EMPTY) ?
+ VCGN_CLASSIFY_NEXT_ICMP_Q_INSIDE : next0;
+
+ next0 = (sw_if_index0 < vec_len(vcm->outside_sw_if_index_table) &&
+ vcm->outside_sw_if_index_table[sw_if_index0] != EMPTY) ?
+ VCGN_CLASSIFY_NEXT_ICMP_Q_OUTSIDE : next0;
+
+ } else {
+ next0 = (sw_if_index0 < vec_len(vcm->inside_sw_if_index_table) &&
+ vcm->inside_sw_if_index_table[sw_if_index0] != EMPTY) ?
+ VCGN_CLASSIFY_NEXT_ICMP_E_INSIDE : next0;
+
+ next0 = (sw_if_index0 < vec_len(vcm->outside_sw_if_index_table) &&
+ vcm->outside_sw_if_index_table[sw_if_index0] != EMPTY) ?
+ VCGN_CLASSIFY_NEXT_ICMP_E_OUTSIDE : next0;
+ }
+ } else {
+ /* cannot do NATting with this L4 protocol */
+ counter = VCGN_CLASSIFY_ERROR_V4_PACKETS_PUNTED;
+ }
+
+ if (PREDICT_FALSE((node->flags & VLIB_NODE_FLAG_TRACE)
+ && (b0->flags & VLIB_BUFFER_IS_TRACED))) {
+ udp_header_t * u0 = (udp_header_t *)(h0+1);
+ vcgn_classify_trace_t *t =
+ vlib_add_trace (vm, node, b0, sizeof (*t));
+ t->sw_if_index = sw_if_index0;
+ t->next_index = next0;
+ t->orig_dst_address = h0->dst_address.as_u32;
+ t->orig_dst_port = u0->dst_port;
+ }
+
+ } else if (*l3_type == clib_host_to_net_u16(ETHERNET_TYPE_IP6)) {
+
+ /* IPv6 0x86DD */
+ next0 = VCGN_CLASSIFY_NEXT_IP6_INPUT;
+ counter = VCGN_CLASSIFY_ERROR_V6_PACKETS_PUNTED;
+
+ } else if (*l3_type ==
+ clib_host_to_net_u16(ETHERNET_TYPE_MPLS_UNICAST)) {
+
+ /* MPLS unicast 0x8847 */
+ next0 = VCGN_CLASSIFY_NEXT_MPLS_INPUT;
+ counter = VCGN_CLASSIFY_ERROR_MPLS_PACKETS_PUNTED;
+ } else { /* Remaining all should be pushed to "ethernet-input" */
+
+ next0 = VCGN_CLASSIFY_NEXT_ETHERNET_INPUT;
+ counter = VCGN_CLASSIFY_ERROR_ETH_PACKETS_PUNTED;
+ }
+
+ em->counters[node_counter_base_index + counter] += 1;
+ em->counters[node_counter_base_index +
+ VCGN_CLASSIFY_ERROR_PACKETS_RECEIVED] += 1;
+
+ /* verify speculative enqueue, maybe switch current next frame */
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+ to_next, n_left_to_next,
+ bi0, next0);
+ }
+
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+ }
+
+ return frame->n_vectors;
+}
+
+VLIB_REGISTER_NODE (vcgn_classify_node) = {
+ .function = vcgn_classify_node_fn,
+ .name = "vcgn-classify",
+ .vector_size = sizeof (u32),
+ .format_trace = format_swap_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(vcgn_classify_error_strings),
+ .error_strings = vcgn_classify_error_strings,
+
+ .n_next_nodes = VCGN_CLASSIFY_N_NEXT,
+
+ /* edit / add dispositions here */
+ .next_nodes = {
+ [VCGN_CLASSIFY_NEXT_IP4_INPUT] = "ip4-input",
+ [VCGN_CLASSIFY_NEXT_IP6_INPUT] = "ip6-input",
+ [VCGN_CLASSIFY_NEXT_MPLS_INPUT] = "mpls-input",
+ [VCGN_CLASSIFY_NEXT_ETHERNET_INPUT] = "ethernet-input",
+ [VCGN_CLASSIFY_NEXT_UDP_INSIDE] = "vcgn-v4-udp-i2o",
+ [VCGN_CLASSIFY_NEXT_UDP_OUTSIDE] = "vcgn-v4-udp-o2i",
+ [VCGN_CLASSIFY_NEXT_TCP_INSIDE] = "vcgn-v4-tcp-i2o",
+ [VCGN_CLASSIFY_NEXT_TCP_OUTSIDE] = "vcgn-v4-tcp-o2i",
+ [VCGN_CLASSIFY_NEXT_ICMP_Q_INSIDE] = "vcgn-v4-icmp-q-i2o",
+ [VCGN_CLASSIFY_NEXT_ICMP_Q_OUTSIDE] = "vcgn-v4-icmp-q-o2i",
+ [VCGN_CLASSIFY_NEXT_ICMP_E_INSIDE] = "vcgn-v4-icmp-e-i2o",
+ [VCGN_CLASSIFY_NEXT_ICMP_E_OUTSIDE] = "vcgn-v4-icmp-e-o2i"
+ },
+};
+
+
+/* A test function to init the vrf map */
+
+clib_error_t *vcgn_classify_init (vlib_main_t *vm)
+{
+ vcgn_classify_main_t * mp = &vcgn_classify_main;
+
+ mp->vlib_main = vm;
+ mp->vnet_main = vnet_get_main();
+ u32 inside_sw_if_index = 1;
+ u32 outside_sw_if_index = 0;
+
+ vec_validate_init_empty (mp->inside_sw_if_index_table,
+ inside_sw_if_index + 1, EMPTY);
+ vec_validate_init_empty (mp->outside_sw_if_index_table,
+ outside_sw_if_index + 1, EMPTY);
+
+ /*
+ * inside_sw_if_index cell of the table stores outside_sw_if_index
+ * and vice versa. This is ensurs pair of indices being remembered
+ * using one mem-location.
+ */
+ mp->inside_sw_if_index_table[inside_sw_if_index] = outside_sw_if_index;
+ mp->outside_sw_if_index_table[outside_sw_if_index] = inside_sw_if_index;
+
+#if DPDK==1
+ dpdk_set_next_node (DPDK_RX_NEXT_IP4_INPUT, "vcgn-classify");
+#endif
+
+ {
+ pg_node_t * pn;
+ pn = pg_get_node (vcgn_classify_node.index);
+ pn->unformat_edit = unformat_pg_ip4_header;
+ }
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (vcgn_classify_init);
+
+/* Show command handlers */
+static clib_error_t *
+show_vcgn_stats_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ if (cnat_db_init_done) {
+ cnat_nat44_handle_show_stats(vm);
+ } else {
+ vlib_cli_output(vm, "vCGN is not configured !!\n");
+ }
+ return 0;
+}
+
+
+static clib_error_t *
+show_vcgn_config_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ cnat_nat44_handle_show_config(vm);
+ return 0;
+}
+
+static clib_error_t *
+show_vcgn_inside_translation_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ vnet_main_t * vnm = vnet_get_main();
+ vcgn_classify_main_t * vcm = &vcgn_classify_main;
+ spp_api_cnat_v4_show_inside_entry_req_t inside_req;
+ u8 *proto;
+ ip4_address_t inside_addr;
+ u32 start_port = 1;
+ u32 end_port = 65535;
+ u32 inside_sw_if_index = EMPTY;
+
+ inside_req.start_port = start_port;
+ inside_req.end_port = end_port;
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
+ if (unformat(input, "protocol %s", &proto)) {
+ if (!strncmp((char *) proto, "udp", 3)) {
+ inside_req.protocol = 1;
+ } else if (!strncmp((char *) proto, "tcp", 3)) {
+ inside_req.protocol = 2;
+ } else {
+ inside_req.protocol = 3;
+ }
+ } else if (unformat (input, "interface %U",
+ unformat_vnet_sw_interface, vnm, &inside_sw_if_index)) {
+ if (inside_sw_if_index > vec_len(vcm->inside_sw_if_index_table) ||
+ vcm->inside_sw_if_index_table[inside_sw_if_index] == EMPTY) {
+ return clib_error_return (0, "Could not find the inside interface");
+ }
+ } else if (unformat (input, "inside-addr %U",
+ unformat_ip4_address, &inside_addr)) {
+ inside_req.ipv4_addr = clib_net_to_host_u32(inside_addr.as_u32);
+ } else if (unformat(input, "start-port %u", &start_port)) {
+ inside_req.start_port = start_port;
+ } else if (unformat(input, "end-port %u", &end_port)) {
+ inside_req.end_port = end_port;
+ } else { break;}
+ }
+ inside_req.vrf_id = inside_sw_if_index;
+ inside_req.flags |= CNAT_TRANSLATION_ENTRY_DYNAMIC; /* as of now only dynamic */
+ inside_req.all_entries = 0; /* we can see it later */
+#if DEBUG
+ vlib_cli_output(vm, "proto %d, inside-addr 0x%x, start_port %u, "
+ "end_port %u, vrf 0x%x\n",
+ inside_req.protocol,
+ inside_req.ipv4_addr,
+ inside_req.start_port,
+ inside_req.end_port,
+ inside_sw_if_index);
+#endif
+ if (cnat_db_init_done) {
+ cnat_v4_show_inside_entry_req_t_handler(&inside_req, vm);
+ } else {
+ vlib_cli_output(vm, "vCGN is not configured !!\n");
+ }
+ return 0;
+}
+
+
+static clib_error_t *
+show_vcgn_outside_translation_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ void cnat_v4_show_outside_entry_req_t_handler
+ (spp_api_cnat_v4_show_outside_entry_req_t *mp, vlib_main_t *vm);
+ vnet_main_t * vnm = vnet_get_main();
+ vcgn_classify_main_t * vcm = &vcgn_classify_main;
+ spp_api_cnat_v4_show_outside_entry_req_t outside_req;
+ u8 *proto;
+ ip4_address_t outside_addr;
+ u32 start_port = 1;
+ u32 end_port = 65535;
+ u32 outside_sw_if_index = EMPTY;
+
+
+ outside_req.start_port = start_port;
+ outside_req.end_port = end_port;
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
+ if (unformat(input, "protocol %s", &proto)) {
+ if (!strncmp((char *) proto, "udp", 3)) {
+ outside_req.protocol = 1;
+ } else if (!strncmp((char *) proto, "tcp", 3)) {
+ outside_req.protocol = 2;
+ } else {
+ outside_req.protocol = 3;
+ }
+ } else if (unformat (input, "interface %U",
+ unformat_vnet_sw_interface, vnm, &outside_sw_if_index)) {
+ if (outside_sw_if_index > vec_len(vcm->outside_sw_if_index_table) ||
+ vcm->outside_sw_if_index_table[outside_sw_if_index] == EMPTY) {
+ return clib_error_return (0, "Could not find the outside interface");
+ }
+ } else if (unformat (input, "outside-addr %U",
+ unformat_ip4_address, &outside_addr)) {
+ outside_req.ipv4_addr = clib_net_to_host_u32(outside_addr.as_u32);
+ } else if (unformat(input, "start-port %u", &start_port)) {
+ outside_req.start_port = start_port;
+ } else if (unformat(input, "end-port %u", &end_port)) {
+ outside_req.end_port = end_port;
+ } else { break;}
+ }
+ outside_req.vrf_id = outside_sw_if_index;
+ outside_req.flags |= CNAT_TRANSLATION_ENTRY_DYNAMIC; /* as of now only dynamic */
+#if DEBUG
+ vlib_cli_output(vm, "proto %d, outside-addr 0x%x, start_port %u, "
+ "end_port %u, vrf 0x%x\n",
+ outside_req.protocol,
+ outside_req.ipv4_addr,
+ outside_req.start_port,
+ outside_req.end_port,
+ outside_sw_if_index);
+#endif
+ if (cnat_db_init_done) {
+ cnat_v4_show_outside_entry_req_t_handler(&outside_req, vm);
+ } else {
+ vlib_cli_output(vm, "vCGN is not configured !!\n");
+ }
+ return 0;
+}
+
+
+/* Config command handlers */
+static clib_error_t *
+set_vcgn_inside_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ vnet_main_t * vnm = vnet_get_main();
+ vcgn_classify_main_t * vcm = &vcgn_classify_main;
+ u32 inside_sw_if_index = 1;
+ u32 outside_sw_if_index = ~0;
+ void cnat_db_v2_init (void );
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
+ if (unformat(input, "%U",
+ unformat_vnet_sw_interface, vnm, &inside_sw_if_index))
+ ;
+ else if (unformat(input, "outside %U",
+ unformat_vnet_sw_interface, vnm, &outside_sw_if_index))
+ ;
+ else break;
+ }
+ if (inside_sw_if_index == ~0 ||
+ outside_sw_if_index == ~0)
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+
+ if (inside_sw_if_index == outside_sw_if_index)
+ return clib_error_return (0, "inside and outside interfaces can't be the same...");
+
+ /*
+ * Initialize in/out sw_if_index table. Could use
+ * non-indexed table to reduce memory. However, this
+ * is consulted in vcgn_classify for every packet.
+ * Therefore, table is indexed by sw_if_index.
+ */
+ vec_validate_init_empty (vcm->inside_sw_if_index_table,
+ inside_sw_if_index + 1, EMPTY);
+ vec_validate_init_empty (vcm->outside_sw_if_index_table,
+ outside_sw_if_index + 1, EMPTY);
+
+ /*
+ * inside_sw_if_index cell of the table stores outside_sw_if_index
+ * and vice versa. This is ensurs pair of indices being remembered
+ * using one mem-location.
+ */
+ vcm->inside_sw_if_index_table[inside_sw_if_index] = outside_sw_if_index;
+ vcm->outside_sw_if_index_table[outside_sw_if_index] = inside_sw_if_index;
+
+ if (! vcm->cnat_db_initalized) {
+ int i;
+ cnat_db_v2_init();
+
+ for (i = 0; i < CNAT_MAX_VRFMAP_ENTRIES; i++) {
+ vrf_map_array[i] = VRF_MAP_ENTRY_EMPTY;
+ }
+ /* Turn on the db scanner process */
+ cnat_scanner_db_process_turn_on(vm);
+ vcm->cnat_db_initalized = 1;
+ }
+ return 0;
+}
+
+static clib_error_t *
+set_vcgn_map_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ vnet_main_t * vnm = vnet_get_main();
+ vcgn_classify_main_t * vcm = &vcgn_classify_main;
+ ip4_address_t lo, hi;
+ spp_api_cnat_v4_add_vrf_map_t map;
+ u32 inside_sw_if_index = EMPTY;
+ u32 outside_sw_if_index;
+
+ vnet_hw_interface_t *inside_hw_if_index = NULL;
+ vnet_hw_interface_t *outside_hw_if_index = NULL;
+
+ if (! unformat(input, "inside %U",
+ unformat_vnet_sw_interface, vnm, &inside_sw_if_index))
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+
+ if (!unformat (input, "%U", unformat_ip4_address, &lo))
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+
+ if (unformat (input, "- %U", unformat_ip4_address, &hi))
+ ;
+
+ /* $$$$ remember to set i_vrf, i_vrf_id as needed */
+
+ /* Fill the structure spp_api_cnat_v4_add_vrf_map_t & let this API handle it */
+ /* i_vrf_id & o_vrf_id are 32-bit & i_vrf, o_vrf are 16 bit */
+
+ if (inside_sw_if_index > vec_len(vcm->inside_sw_if_index_table) ||
+ vcm->inside_sw_if_index_table[inside_sw_if_index] == EMPTY) {
+ return clib_error_return (0, "Could not find the inside interface");
+ }
+ outside_sw_if_index = vcm->inside_sw_if_index_table[inside_sw_if_index];
+
+ map.i_vrf_id = inside_sw_if_index;
+ map.o_vrf_id = outside_sw_if_index;
+ map.i_vrf = inside_sw_if_index;
+ map.o_vrf = outside_sw_if_index;
+
+ map.start_addr[0] = clib_net_to_host_u32(lo.as_u32);
+ map.end_addr[0] = clib_net_to_host_u32(hi.as_u32);
+
+ cnat_nat44_add_vrf_map_t_handler(&map, vm);
+
+#if 1
+ inside_hw_if_index = vnet_get_sup_hw_interface(vcm->vnet_main, inside_sw_if_index);
+ if (inside_hw_if_index) {
+ vnet_hw_interface_rx_redirect_to_node(vcm->vnet_main,
+ inside_hw_if_index->hw_if_index, vcgn_classify_node.index);
+ }
+ outside_hw_if_index = vnet_get_sup_hw_interface(vcm->vnet_main, outside_sw_if_index);
+ if (outside_hw_if_index) {
+ vnet_hw_interface_rx_redirect_to_node(vcm->vnet_main,
+ outside_hw_if_index->hw_if_index, vcgn_classify_node.index);
+ }
+#endif
+ return 0;
+}
+
+static clib_error_t *
+set_vcgn_tcp_timeout_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ /*
+ vnet_main_t * vnm = vnet_get_main();
+ vcgn_classify_main_t * vcm = &vcgn_classify_main;
+ */
+ u32 act_timeout = 0;
+ u32 init_timeout = 0;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
+ if (unformat(input, "active %u", &act_timeout))
+ tcp_active_timeout = act_timeout;
+ else if (unformat(input, "init %u", &init_timeout))
+ tcp_initial_setup_timeout = init_timeout;
+ else break;
+ }
+ return 0;
+}
+
+static clib_error_t *
+set_vcgn_udp_timeout_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ /*
+ vnet_main_t * vnm = vnet_get_main();
+ vcgn_classify_main_t * vcm = &vcgn_classify_main;
+ */
+ u32 act_timeout = 0;
+ u32 init_timeout = 0;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
+ if (unformat(input, "active %u", &act_timeout))
+ udp_act_session_timeout = act_timeout;
+ else if (unformat(input, "init %u", &init_timeout))
+ udp_init_session_timeout = init_timeout;
+ else break;
+ }
+ return 0;
+}
+
+
+static clib_error_t *
+set_vcgn_icmp_timeout_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ /*
+ * vnet_main_t * vnm = vnet_get_main();
+ * vcgn_classify_main_t * vcm = &vcgn_classify_main;
+ */
+ u32 timeout = 0;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
+ if (unformat(input, "%u", &timeout))
+ ;
+ else break;
+ }
+ icmp_session_timeout = timeout;
+ return 0;
+}
+
+
+static clib_error_t *
+set_vcgn_protocol_default_timeout_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ /*
+ vnet_main_t * vnm = vnet_get_main();
+ vcgn_classify_main_t * vcm = &vcgn_classify_main;
+ */
+ u8 *protocol;
+ u8 reset = 1;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
+ if (unformat(input, "%s", &protocol))
+ ;
+ else break;
+ }
+ cnat_nat44_set_protocol_timeout_value(0, 0, protocol, reset, vm);
+ return 0;
+}
+
+static clib_error_t *
+set_vcgn_dynamic_port_start_range_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ /*
+ vnet_main_t * vnm = vnet_get_main();
+ vcgn_classify_main_t * vcm = &vcgn_classify_main;
+ */
+ u32 port = 0;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
+ if (unformat(input, "%u", &port))
+ ;
+ else break;
+ }
+ if (port != 0 && port > 65535) {
+ vlib_cli_output(vm, "Error !! Invalid port\n");
+ } else {
+ cnat_static_port_range = port;
+ vlib_cli_output(vm, "Dynamic Port Range Config Successful !!\n");
+ }
+ return 0;
+}
+
+static clib_error_t *
+set_vcgn_port_limit_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ /*
+ vnet_main_t * vnm = vnet_get_main();
+ vcgn_classify_main_t * vcm = &vcgn_classify_main;
+ */
+ u32 port = 0;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
+ if (unformat(input, "%u", &port))
+ ;
+ else break;
+ }
+ if (port != 0 && port > 65535) {
+ vlib_cli_output(vm, "Error !! Invalid port\n");
+ } else {
+ cnat_main_db_max_ports_per_user = port;
+ vlib_cli_output(vm, "Port Limit Config Successful !!\n");
+ }
+ return 0;
+}
+
+static inline void nfv9_init_pkt_sent_data(cnat_nfv9_logging_info_t *nfv9_info)
+{
+ nfv9_server_info_t *server = nfv9_server_info_pool +
+ nfv9_info->server_index;
+
+ /*
+ * Reset the pkts_since_last_template and sent_time
+ * so that template will be sent next time
+ */
+ server->last_template_sent_time = 0;
+ server->pkts_since_last_template = 0xffffffff;
+}
+
+static inline u16 nfv9_get_max_length_minus_max_record_size(u16 path_mtu)
+{
+ u16 max_length_minus_max_record_size;
+ if(!path_mtu) /* Use default */
+ path_mtu = NFV9_DEF_PATH_MTU;
+
+ max_length_minus_max_record_size = path_mtu -
+ CNAT_NFV9_DATAFLOW_RECORD_HEADER_LENGTH -
+ NFV9_PAD_VALUE -
+ CNAT_NFV9_MAX_SINGLE_RECORD_LENGTH; /* Note.. as of now this record
+ * requires max number of bytes. If you add more records,
+ * this needs to be re-checked */
+ if (max_length_minus_max_record_size < CNAT_NFV9_MIN_RECORD_SIZE) {
+ max_length_minus_max_record_size = CNAT_NFV9_MIN_RECORD_SIZE;
+ }
+ return max_length_minus_max_record_size;
+}
+
+/* This function finds if the netflow server indicated by
+ * new_server_info is already configured for some other instance
+ * if yes, it returns the same pointer so that, info sent to the
+ * server is consistent. If the server is not found, a new instance
+ * is created and returned. If an existing server is used, its refernce
+ * count is incrimented (indicating the number of instances using the
+ * same server
+ */
+ /* #define DEBUG_NF_SERVER_CONFIG 1 */
+static u16 nfv9_get_server_instance(
+ cnat_nfv9_logging_info_t *nfv9_info, nfv9_server_info_t *new_server_info)
+{
+
+ /* Check if the instance has a server already and if yes, does it match */
+ nfv9_server_info_t *server;
+ if(nfv9_info->server_index != EMPTY) {
+ server = nfv9_server_info_pool + nfv9_info->server_index;
+
+ if((server->ipv4_address == new_server_info->ipv4_address) &&
+ (server->port == new_server_info->port)) {
+ /* Same server.. just check if refresh rate/timeouts are reduced */
+#ifdef DEBUG_NF_SERVER_CONFIG
+ if(my_instance_number == 1) {
+ printf("\n Server match for %x and port %d\n",
+ new_server_info->ipv4_address, new_server_info->port);
+ }
+#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
+ goto adjust_refresh_rate;
+ } else { /* The server is being changed */
+ server->ref_count--;
+#ifdef DEBUG_NF_SERVER_CONFIG
+ if(my_instance_number == 1) {
+ printf("\n Server change from %x, %d to %x, %d"
+ "Ref count %d\n",
+ server->ipv4_address,
+ server->port,
+ new_server_info->ipv4_address, new_server_info->port,
+ server->ref_count);
+ }
+#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
+ if(!server->ref_count) {
+ /* Return this server to pool */
+#ifdef DEBUG_NF_SERVER_CONFIG
+ if(my_instance_number == 1) {
+ PLATFORM_DEBUG_PRINT("Deleting Server %x, %d at %d\n",
+ server->ipv4_address,
+ server->port,
+ nfv9_info->server_index);
+ }
+#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
+ pool_put(nfv9_server_info_pool, server);
+ }
+ }
+ }
+
+ /* Now check if the server is already present in the pool */
+ u8 found = 0;
+ server = 0;
+ pool_foreach (server, nfv9_server_info_pool, ({
+ if ((server->ipv4_address == new_server_info->ipv4_address) &&
+ (server->port == new_server_info->port)) {
+ server->ref_count++;
+ nfv9_info->server_index = server - nfv9_server_info_pool;
+ found = 1;
+#ifdef DEBUG_NF_SERVER_CONFIG
+ if(my_instance_number == 1) {
+ printf("Re-using server %x, %d Ref count %d\n",
+ server->ipv4_address, server->port, server->ref_count);
+ }
+#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
+ break;
+ }
+ }));
+
+ if(!found) {
+ /* Create a new one, initialize and return */
+ server = 0;
+ pool_get(nfv9_server_info_pool, server);
+ clib_memcpy(server, new_server_info, sizeof(nfv9_server_info_t));
+ server->ref_count = 1;
+ nfv9_info->server_index = server - nfv9_server_info_pool;
+#ifdef DEBUG_NF_SERVER_CONFIG
+ if(my_instance_number == 1) {
+ printf("Create new server for at %d %x and port %d\n",
+ nfv9_info->server_index,
+ new_server_info->ipv4_address, new_server_info->port);
+ }
+#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
+ return CNAT_SUCCESS;
+ }
+
+adjust_refresh_rate:
+ if(server->refresh_rate >
+ new_server_info->refresh_rate) {
+ server->refresh_rate =
+ new_server_info->refresh_rate;
+#ifdef DEBUG_NF_SERVER_CONFIG
+ if(my_instance_number == 1) {
+ printf("Reset refresh rate to %d\n",
+ server->refresh_rate);
+ }
+#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
+ }
+
+ if(server->timeout_rate >
+ new_server_info->timeout_rate) {
+ server->timeout_rate =
+ new_server_info->timeout_rate;
+#ifdef DEBUG_NF_SERVER_CONFIG
+ if(my_instance_number == 1) {
+ printf("Reset timeout rate to %d\n",
+ server->timeout_rate);
+ }
+#endif /* #ifdef DEBUG_NF_SERVER_CONFIG */
+ }
+
+ return CNAT_SUCCESS;
+}
+static clib_error_t *
+set_vcgn_nfv9_logging_cofig_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ vcgn_classify_main_t * vcm = &vcgn_classify_main;
+ spp_api_cnat_v4_config_nfv9_logging_t nfv9_conf;
+ ip4_address_t server_addr;
+ u32 ip_addr = 0;
+ u32 port;
+ u32 refresh_rate = 0;
+ u32 timeout = 0;
+ u32 pmtu = 0;
+ u8 enable = 1;
+/* vcgn changes start*/
+ cnat_nfv9_logging_info_t *my_nfv9_logging_info = NULL;
+ cnat_nfv9_logging_info_t *my_nfv9_logging_info_tmp = NULL;
+ cnat_vrfmap_t *my_vrfmap = 0, *my_vrfmap_temp = 0;
+ u16 i_vrf = ~0;
+ u32 i_vrf_id = ~0;
+ u8 found;
+ u32 inside_sw_if_index = EMPTY;
+ /*
+ * Init NFv9 logging info as needed, this will be done only once
+ */
+ cnat_nfv9_logging_init();
+
+ found = 0;
+
+/* vcgn changes end*/
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) {
+ if (unformat (input, "inside %U",
+ unformat_vnet_sw_interface, &inside_sw_if_index)) {
+ /* Do nothing */
+ } else if (unformat (input, "server %U", unformat_ip4_address, &server_addr))
+ ip_addr = clib_net_to_host_u32(server_addr.as_u32);
+ else if (unformat(input, "port %u", &port))
+ ;
+ else if (unformat(input, "refresh-rate %u", &refresh_rate))
+ ;
+ else if (unformat(input, "timeout %u", &timeout))
+ ;
+ else if (unformat(input, "pmtu %u", &pmtu))
+ ;
+ else if (unformat(input, "del"))
+ enable = 0;
+ else break;
+ }
+
+ if (inside_sw_if_index > vec_len(vcm->inside_sw_if_index_table) ||
+ vcm->inside_sw_if_index_table[inside_sw_if_index] == EMPTY) {
+ return clib_error_return (0, "Could not find the inside interface");
+ }
+ i_vrf = inside_sw_if_index;
+ i_vrf_id = inside_sw_if_index;
+
+ #if 0
+ vlib_cli_output(vm, "ip 0x%x, port %u, refresh %u, "
+ "timeout %u, pmtu %u enable %u\n",
+ ip_addr, port, refresh_rate,
+ timeout, pmtu, enable);
+ #endif
+ if (refresh_rate == 0) refresh_rate = 500; /* num of pkts */
+ if (timeout == 0) timeout = 30; /* in mins */
+
+ nfv9_conf.enable = enable;
+ nfv9_conf.ipv4_address = ip_addr;
+ nfv9_conf.i_vrf_id = inside_sw_if_index;
+ nfv9_conf.i_vrf = inside_sw_if_index;
+ nfv9_conf.port = port;
+ nfv9_conf.refresh_rate = refresh_rate;
+ nfv9_conf.timeout_rate = timeout;
+ nfv9_conf.path_mtu = pmtu;
+ nfv9_conf.nfv9_global_collector = 0;
+ nfv9_conf.session_logging = 0;
+
+ /*
+ * At this point the NFv9 global information should already be
+ * inited as we have called cnat_nfv9_logging_init()
+ */
+
+ if (nfv9_conf.nfv9_global_collector) {
+ if (cnat_nfv9_global_info.cnat_nfv9_global_collector_index != EMPTY) {
+ found = 1;
+ my_nfv9_logging_info = cnat_nfv9_logging_info_pool +
+ cnat_nfv9_global_info.cnat_nfv9_global_collector_index;
+ }
+ } else {
+ /* Do we already have a map for this VRF? */
+ pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info_pool, ({
+ if (my_nfv9_logging_info->i_vrf_id == i_vrf_id) {
+ nfv9_server_info_t *server = nfv9_server_info_pool +
+ my_nfv9_logging_info->server_index;
+ if((server->ipv4_address == (nfv9_conf.ipv4_address)) && (server->port == (nfv9_conf.port))) {
+ found = 1;
+ my_nfv9_logging_info_tmp = my_nfv9_logging_info;
+ break;
+ }
+ }
+ }));
+ }
+
+ if ((nfv9_conf.ipv4_address == 0) ||
+ (nfv9_conf.port == 0)) {
+ vlib_cli_output(vm,
+ "Add NFv9 ivrf %d Logging Invalid values [IPv4 0x%x, PORT %d]\n",
+ i_vrf,
+ (nfv9_conf.ipv4_address),
+ (nfv9_conf.port));
+ goto done;
+ }
+
+ if (nfv9_conf.enable) {
+ if ((nfv9_conf.ipv4_address == 0) ||
+ (nfv9_conf.port == 0)) {
+ nfv9_conf.rc = CNAT_ERR_PARSER;
+ vlib_cli_output(vm,
+ "NFV9_logging i_vrf %d, Invalid [v4_addr 0x%x port %d]\n",
+ i_vrf,
+ (nfv9_conf.ipv4_address),
+ (nfv9_conf.port));
+ goto done;
+ }
+
+ nfv9_server_info_t new_server_info;
+ memset(&new_server_info, 0, sizeof(nfv9_server_info_t));
+ new_server_info.ipv4_address =
+ nfv9_conf.ipv4_address;
+ new_server_info.port =
+ (nfv9_conf.port);
+ new_server_info.refresh_rate =
+ (nfv9_conf.refresh_rate);
+ /*
+ * Store the timeout in seconds. User configures it in minutes
+ */
+ new_server_info.timeout_rate =
+ 60*(nfv9_conf.timeout_rate);
+ if (found && my_nfv9_logging_info) {
+ /*
+ * Entry already present, change it
+ */
+ my_nfv9_logging_info->max_length_minus_max_record_size =
+ nfv9_get_max_length_minus_max_record_size(
+ ((nfv9_conf.path_mtu)));
+ } else {
+ pool_get(cnat_nfv9_logging_info_pool, my_nfv9_logging_info);
+ memset(my_nfv9_logging_info, 0, sizeof(*my_nfv9_logging_info));
+ my_nfv9_logging_info->server_index = EMPTY;
+ my_nfv9_logging_info->nfv9_logging_next_index = EMPTY;
+ /*
+ * Make the current and head logging context indeices as EMPTY.
+ * When first logging happens, these get set correctly
+ */
+ my_nfv9_logging_info->current_logging_context = NULL;
+ my_nfv9_logging_info->queued_logging_context = NULL;
+#if 0
+ my_nfv9_logging_info->f = NULL;
+ my_nfv9_logging_info->to_next = NULL;
+ output_node = vlib_get_node_by_name (vm, (u8 *) "ip4-input");
+ my_nfv9_logging_info->ip4_input_node_index = output_node->index;
+ printf("ip4_input_node_index %d\n", my_nfv9_logging_info->ip4_input_node_index);
+#endif
+ my_nfv9_logging_info->i_vrf = i_vrf;
+ my_nfv9_logging_info->i_vrf_id = i_vrf_id;
+ my_nfv9_logging_info->max_length_minus_max_record_size =
+ nfv9_get_max_length_minus_max_record_size(
+ nfv9_conf.path_mtu);
+
+ /* my_nfv9_logging_info will have a copy of logging_policy
+ * because, it is quite possible that nfv9 config arrives before
+ * the corresponding vrfmap is initialized. In such cases
+ * this copy will be used to update the vrfmap entry
+ */
+ my_nfv9_logging_info->logging_policy = nfv9_conf.session_logging;
+
+ if (nfv9_conf.nfv9_global_collector) {
+ cnat_nfv9_global_info.cnat_nfv9_global_collector_index =
+ my_nfv9_logging_info - cnat_nfv9_logging_info_pool;
+
+ pool_foreach (my_vrfmap, cnat_map_by_vrf, ({
+ if (my_vrfmap->nfv9_logging_index == EMPTY) {
+ my_vrfmap->nfv9_logging_index =
+ cnat_nfv9_global_info.cnat_nfv9_global_collector_index;
+ }
+ }));
+ } else {
+ u32 my_vrfmap_found = 0;
+
+ FIND_MY_VRF_USING_I_VRF_ID
+ my_vrfmap = my_vrfmap_temp;
+ if (my_vrfmap_found) {
+ if(my_vrfmap->nfv9_logging_index == EMPTY) {
+ my_vrfmap->nfv9_logging_index =
+ my_nfv9_logging_info - cnat_nfv9_logging_info_pool;
+ // my_vrfmap->nf_logging_policy = mp->session_logging;
+ } else {
+ cnat_nfv9_logging_info_t *my_nfv9_logging_info_temp = cnat_nfv9_logging_info_pool + my_vrfmap->nfv9_logging_index;
+ while(my_nfv9_logging_info_temp->nfv9_logging_next_index != EMPTY){
+ my_nfv9_logging_info_temp = cnat_nfv9_logging_info_pool + my_nfv9_logging_info_temp->nfv9_logging_next_index;
+ }
+ my_nfv9_logging_info_temp->nfv9_logging_next_index = my_nfv9_logging_info - cnat_nfv9_logging_info_pool;
+ }
+ }
+ }
+ }
+
+ /* Update logging policy */
+ my_nfv9_logging_info->logging_policy = nfv9_conf.session_logging;
+ if (nfv9_conf.nfv9_global_collector) {
+ if(PLATFORM_DBL_SUPPORT) {
+ pool_foreach (my_vrfmap, cnat_map_by_vrf, ({
+ if (my_vrfmap->nfv9_logging_index ==
+ cnat_nfv9_global_info.cnat_nfv9_global_collector_index) {
+ my_vrfmap->nf_logging_policy = nfv9_conf.session_logging;
+ }
+ }));
+ } else {
+ nfv9_conf.rc = CNAT_ERR_NO_SESSION_DB;
+ }
+ } else {
+ if(PLATFORM_DBL_SUPPORT) {
+ u32 my_vrfmap_found = 0;
+ my_vrfmap_temp = NULL;
+ FIND_MY_VRF_USING_I_VRF_ID
+ my_vrfmap = my_vrfmap_temp;
+ if (my_vrfmap_found) {
+ // my_vrfmap->nf_logging_policy = mp->session_logging;
+ }
+ } else {
+ nfv9_conf.rc = CNAT_ERR_NO_SESSION_DB;
+ }
+ }
+ u8 nfv9_logging_policy = 0;
+ u32 my_vrfmap_found = 0;
+ my_vrfmap_temp = NULL;
+ FIND_MY_VRF_USING_I_VRF_ID
+ my_vrfmap = my_vrfmap_temp;
+ if (my_vrfmap_found) {
+ u32 index_curr = my_vrfmap->nfv9_logging_index;
+ cnat_nfv9_logging_info_t *my_nfv9_logging_info_temp;
+ while(index_curr != EMPTY) {
+ my_nfv9_logging_info_temp = cnat_nfv9_logging_info_pool + index_curr;
+ nfv9_logging_policy = nfv9_logging_policy || my_nfv9_logging_info_temp->logging_policy;
+ index_curr = (cnat_nfv9_logging_info_pool + index_curr)->nfv9_logging_next_index;
+ }
+ my_vrfmap->nf_logging_policy = nfv9_logging_policy;
+ }
+ //vlib_cli_output(vm,"Netflow logging policy = %d\n", my_vrfmap->nf_logging_policy);
+ if(nfv9_get_server_instance(my_nfv9_logging_info, &new_server_info)
+ != CNAT_SUCCESS) {
+ vlib_cli_output(vm, "Error to get server instance");
+ nfv9_conf.rc = CNAT_ERR_PARSER;
+ goto done;
+ }
+ nfv9_init_pkt_sent_data(my_nfv9_logging_info);
+
+ vlib_cli_output(vm,"Adding NFv9 Logging Succeeded\n");
+ nfv9_configured = 1;
+
+ } else {
+ /*Delete path*/
+ if (found) {
+ /* if found entry then we need to overwrite the my_nfv9_logging_info_tmp
+ * to my_nfv9_logging_info
+ */
+ my_nfv9_logging_info = my_nfv9_logging_info_tmp;
+ if (i_vrf == INVALID_UIDX) {
+ /*
+ * We are deleting a global collector. Mark the collectors
+ * in those VRFs using the global collector
+ */
+ pool_foreach (my_vrfmap, cnat_map_by_vrf, ({
+ if (my_vrfmap->nfv9_logging_index ==
+ cnat_nfv9_global_info.cnat_nfv9_global_collector_index) {
+ my_vrfmap->nfv9_logging_index = EMPTY;
+ }
+ }));
+
+ cnat_nfv9_global_info.cnat_nfv9_global_collector_index = EMPTY;
+ } else {
+ u32 my_vrfmap_found = 0;
+ my_vrfmap_temp = NULL;
+ FIND_MY_VRF_USING_I_VRF_ID
+ my_vrfmap = my_vrfmap_temp;
+ if (my_vrfmap_found) {
+ // my_vrfmap->nfv9_logging_index = cnat_nfv9_global_info.cnat_nfv9_global_collector_index;
+ }
+ }
+ if (my_nfv9_logging_info->queued_logging_context ||
+ my_nfv9_logging_info->current_logging_context) {
+ /*
+ * If there is a pending context:
+ * Set the deleted flag to 1. This will ensure
+ * that the logging info structure gets freed after any
+ * pending packet get sent
+ */
+ my_nfv9_logging_info->deleted = 1;
+ } else {
+ /*
+ * No pending context, just free the logging info structure
+ */
+ u32 index = my_nfv9_logging_info - cnat_nfv9_logging_info_pool;
+ if(index == my_vrfmap->nfv9_logging_index) {
+ /* Deleting the first sever */
+ my_vrfmap->nfv9_logging_index = my_nfv9_logging_info->nfv9_logging_next_index;
+ /* if(my_nfv9_logging_info->nfv9_logging_next_index != EMPTY){
+ my_vrfmap->nf_logging_policy = (cnat_nfv9_logging_info_pool + my_nfv9_logging_info->nfv9_logging_next_index)->logging_policy;
+ } else {
+ my_vrfmap->nf_logging_policy = EMPTY;
+ }*/
+ } else {
+ u32 index_curr = my_vrfmap->nfv9_logging_index;
+ u32 index_prev = EMPTY;
+ while(index_curr != EMPTY) {
+ index_prev = index_curr;
+ index_curr = (cnat_nfv9_logging_info_pool + index_curr)->nfv9_logging_next_index;
+ if(index == index_curr)
+ {
+ (cnat_nfv9_logging_info_pool + index_prev)->nfv9_logging_next_index = (cnat_nfv9_logging_info_pool + index_curr)->nfv9_logging_next_index;
+ break;
+ }
+ }
+ }
+ nfv9_delete_server_info(my_nfv9_logging_info);
+ pool_put(cnat_nfv9_logging_info_pool, my_nfv9_logging_info);
+ }
+
+ vlib_cli_output(vm, "Deleting NFv9 Logging Succeeded\n");
+ /*
+ * Search across all vrf and check if nfv9 logging is configured.
+ */
+ nfv9_configured = 0;
+ pool_foreach (my_nfv9_logging_info, cnat_nfv9_logging_info_pool, ({
+ nfv9_configured = 1;
+ break;
+ }));
+ } else {
+ nfv9_conf.rc = CNAT_NO_CONFIG;
+ vlib_cli_output(vm, "Add NFv9 Logging Failed (2) Non Existent vrf %d\n",
+ i_vrf);
+
+ }
+ u8 nfv9_logging_policy = 0;
+ u32 my_vrfmap_found = 0;
+ my_vrfmap_temp = NULL;
+ FIND_MY_VRF_USING_I_VRF_ID
+ my_vrfmap = my_vrfmap_temp;
+ if (my_vrfmap_found) {
+ u32 index_curr = my_vrfmap->nfv9_logging_index;
+ cnat_nfv9_logging_info_t *my_nfv9_logging_info_temp;
+ while(index_curr != EMPTY) {
+ my_nfv9_logging_info_temp = cnat_nfv9_logging_info_pool + index_curr;
+ nfv9_logging_policy = nfv9_logging_policy || my_nfv9_logging_info_temp->logging_policy;
+ index_curr = (cnat_nfv9_logging_info_pool + index_curr)->nfv9_logging_next_index;
+ }
+ my_vrfmap->nf_logging_policy = nfv9_logging_policy;
+ }
+ }
+
+done:
+ return 0;
+}
+
+/* config CLIs */
+VLIB_CLI_COMMAND (set_vcgn_map_command) = {
+ .path = "set vcgn map",
+ .short_help = "set vcgn map <lo-address> [- <hi-address>]",
+ .function = set_vcgn_map_command_fn,
+};
+
+VLIB_CLI_COMMAND (set_vcgn_inside_command) = {
+ .path = "set vcgn inside",
+ .short_help = "set vcgn inside <inside intfc> outside <outside intfc>",
+ .function = set_vcgn_inside_command_fn,
+};
+
+VLIB_CLI_COMMAND (set_vcgn_tcp_timeout_command) = {
+ .path = "set vcgn tcp timeout",
+ .short_help = "set vcgn tcp timeout active <1-65535> init <1-65535>",
+ .function = set_vcgn_tcp_timeout_command_fn,
+};
+
+VLIB_CLI_COMMAND (set_vcgn_udp_timeout_command) = {
+ .path = "set vcgn udp timeout",
+ .short_help = "set vcgn udp timeout active <1-65535> init <1-65535>",
+ .function = set_vcgn_udp_timeout_command_fn,
+};
+
+VLIB_CLI_COMMAND (set_vcgn_icmp_timeout_command) = {
+ .path = "set vcgn icmp timeout",
+ .short_help = "set vcgn icmp timeout <1-65535>",
+ .function = set_vcgn_icmp_timeout_command_fn,
+};
+
+VLIB_CLI_COMMAND (set_vcgn_protocol_default_timeout_command) = {
+ .path = "set vcgn default timeout",
+ .short_help = "set vcgn default timeout protocol <tcp/udp/icmp>",
+ .function = set_vcgn_protocol_default_timeout_command_fn,
+};
+
+VLIB_CLI_COMMAND (set_vcgn_dynamic_port_start_range_command) = {
+ .path = "set vcgn dynamic port start",
+ .short_help = "set vcgn dynamic port start <1-65535>",
+ .function = set_vcgn_dynamic_port_start_range_command_fn,
+};
+
+VLIB_CLI_COMMAND (set_vcgn_port_limit_command) = {
+ .path = "set vcgn port limit",
+ .short_help = "set vcgn port limit <1-65535>",
+ .function = set_vcgn_port_limit_command_fn,
+};
+
+VLIB_CLI_COMMAND (set_vcgn_nfv9_logging_cofig_command) = {
+ .path = "set vcgn nfv9",
+ .short_help = "set vcgn nfv9 [del] inside <interface> "
+ "server <ip-addr> port <port> [refresh-rate <n>] "
+ "[timeout <n>] [pmtu <n>]",
+ .function = set_vcgn_nfv9_logging_cofig_command_fn,
+};
+
+
+/* show CLIs */
+VLIB_CLI_COMMAND (show_vcgn_config_command) = {
+ .path = "show vcgn config",
+ .short_help = "show vcgn config",
+ .function = show_vcgn_config_command_fn,
+};
+
+VLIB_CLI_COMMAND (show_vcgn_stat_command) = {
+ .path = "show vcgn statistics",
+ .short_help = "show vcgn statistics",
+ .function = show_vcgn_stats_command_fn,
+};
+
+VLIB_CLI_COMMAND (show_vcgn_inside_translation_command) = {
+ .path = "show vcgn inside-translation",
+ .short_help = "show vcgn inside-translation protocol <tcp/udp/icmp> "
+ "interface <inside-if> inside-addr <ip-addr> "
+ "[start-port <n>] [end-port <n>]",
+ .function = show_vcgn_inside_translation_command_fn,
+};
+
+VLIB_CLI_COMMAND (show_vcgn_outside_translation_command) = {
+ .path = "show vcgn outside-translation",
+ .short_help = "show vcgn outside-translation protocol <tcp/udp/icmp> "
+ "interface <outside-if> outside-addr <ip-addr> "
+ "[start-port <n>] [end-port <n>]",
+ .function = show_vcgn_outside_translation_command_fn,
+};
+
+static clib_error_t *
+vcgn_init (vlib_main_t * vm)
+{
+ clib_error_t * error = 0;
+
+ if ((error = vlib_call_init_function
+ (vm, vcgn_classify_init)))
+ return error;
+ if ((error = vlib_call_init_function
+ (vm, cnat_ipv4_udp_inside_input_init)))
+ return error;
+ if ((error = vlib_call_init_function
+ (vm, cnat_ipv4_udp_outside_input_init)))
+ return error;
+ if ((error = vlib_call_init_function
+ (vm, cnat_ipv4_udp_inside_input_exc_init)))
+ return error;
+ if ((error = vlib_call_init_function
+ (vm, cnat_db_scanner_init)))
+ return error;
+ if ((error = vlib_call_init_function
+ (vm, cnat_ipv4_tcp_inside_input_init)))
+ return error;
+ if ((error = vlib_call_init_function
+ (vm, cnat_ipv4_tcp_inside_input_exc_init)))
+ return error;
+ if ((error = vlib_call_init_function
+ (vm, cnat_ipv4_tcp_outside_input_init)))
+ return error;
+ if ((error = vlib_call_init_function
+ (vm, cnat_ipv4_icmp_q_inside_input_init)))
+ return error;
+ if ((error = vlib_call_init_function
+ (vm, cnat_ipv4_icmp_q_inside_input_exc_init)))
+ return error;
+ if ((error = vlib_call_init_function
+ (vm, cnat_ipv4_icmp_q_outside_input_init)))
+ return error;
+ if ((error = vlib_call_init_function
+ (vm, cnat_ipv4_icmp_e_inside_input_init)))
+ return error;
+ if ((error = vlib_call_init_function
+ (vm, cnat_ipv4_icmp_e_outside_input_init)))
+ return error;
+
+ return error;
+}
+
+/*
+ * This routine exists to convince the vlib plugin framework that
+ * we haven't accidentally copied a random .dll into the plugin
+ * directory. This is used in lieu of VLIB_INIT_FUNCTION(vcgn_init).
+ *
+ * Also collects global variable pointers passed from the vpp engine
+ */
+clib_error_t *
+vlib_plugin_register (vlib_main_t * vm, vnet_plugin_handoff_t * h,
+ int from_early_init)
+{
+ return vcgn_init(vm);
+}
diff --git a/vpp/plugins/vcgn-plugin/vcgn/vcgn_db.h b/vpp/plugins/vcgn-plugin/vcgn/vcgn_db.h
new file mode 100644
index 00000000..cd7d835c
--- /dev/null
+++ b/vpp/plugins/vcgn-plugin/vcgn/vcgn_db.h
@@ -0,0 +1,117 @@
+/*
+ *------------------------------------------------------------------
+ * vcgn_db.h - translation database definitions
+ *
+ * Copyright (c) 2007-2014 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *------------------------------------------------------------------
+ */
+
+#ifndef __VCGN_DB_H__
+#define __VCGN_DB_H__
+
+#include "index_list.h"
+
+/*
+ * The key structure. All fields are in NETWORK byte order!
+ */
+typedef struct {
+ u32 ipv4;
+ u16 port;
+ u16 vrf; //bit0-12:vrf, bit13:unused, bit14-15:protocol
+} cnat_db_key_t;
+
+/* bit14-15:protocol in cnat_db_key_t */
+#define CNAT_INVALID_PROTO 0x0000
+#define CNAT_UDP 0x4000
+#define CNAT_TCP 0x8000
+#define CNAT_ICMP 0xc000
+#define CNAT_VRF_MASK 0x3fff
+#define CNAT_PRO_MASK 0xc000
+#define CNAT_PRO_SHIFT 14
+
+/*
+ * Maximum number of VRF entries supported
+ */
+#define CNAT_MAX_VRFMAP_ENTRIES (CNAT_VRF_MASK + 1)
+/*
+ * for hashing purposes, fetch the key in one instr.
+ */
+typedef union {
+ cnat_db_key_t k;
+ u64 key64;
+} cnat_key_t;
+
+/*
+ * Main translation database entries. Currently 0x50 = 80 bytes in length.
+ * Given 20,000,000 entries, it saves nearly 1gb of SDRAM to pack the entries
+ * and pay the extra prefetch. So, that's what we do.
+ */
+
+typedef struct {
+ /* 0x00 */
+ index_slist_t out2in_hash; /* hash-and-chain, x2 */
+ index_slist_t in2out_hash;
+
+ /* 0x08 */
+ cnat_key_t out2in_key; /* network-to-user, outside-to-inside key */
+
+ /* 0x10 */
+ cnat_key_t in2out_key; /* user-to-network, inside-to-outside key */
+
+ /* 0x18 */
+ index_dlist_t user_ports; /* per-user translation list */
+
+ /* 0x20 */
+ u32 user_index; /* index of user that owns this entry */
+
+ /* 0x24 */
+ u16 vrfmap_index; /* index of vrfmap */
+
+ /* 0x26 */
+ u16 flags; /* Always need flags... */
+#define CNAT_DB_FLAG_PORT_PAIR (1<<0)
+#define CNAT_DB_FLAG_TCP_ACTIVE (1<<1)
+#define CNAT_DB_FLAG_ENTRY_FREE (1<<2)
+#define CNAT_DB_FLAG_UDP_ACTIVE (1<<3)
+#define CNAT_DB_FLAG_STATIC_PORT (1<<4)
+#define CNAT_DB_FLAG_ALG_ENTRY (1<<5)
+
+ /* 0x28 */
+ u32 dst_ipv4; /* pointer to ipv4 dst list, used in evil mode */
+
+ /* 0x2C */
+ u32 out2in_pkts; /* pkt counters */
+
+ /* 0x30 */
+ u32 in2out_pkts;
+
+ /* 0x34 */
+ u32 entry_expires; /* timestamp used to expire translations */
+
+ /* 0x38 */
+ union { /* used by FTP ALG, pkt len delta due to FTP PORT cmd */
+ u16 delta;
+ i8 alg_dlt[2]; /* two delta values, 0 for previous, 1 for current */
+ u16 il; /* Used to indicate if interleaved mode is used
+ in case of RTSP ALG */
+ } alg;
+
+ /* 0x 48 */
+ u32 tcp_seq_num; /* last tcp (FTP) seq # that has pkt len change due to PORT */
+
+ cnat_timeout_t destn_key;
+
+ /* 0x4C... last byte -- 72 total */
+} cnat_main_db_entry_t;
+#endif