
directory and GNU autotools setup. Change-Id: I6c59d1297389c9413db0c0b9bdf3b759080bf1b8 Signed-off-by: Ole Troan <ot@cisco.com>
2257 lines
64 KiB
C
2257 lines
64 KiB
C
/*
|
|
*------------------------------------------------------------------
|
|
* 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
|