2 *------------------------------------------------------------------
3 * cnat_va_db.c - virtual assembly database
5 * Copyright (c) 2009, 2013 Cisco and/or its affiliates.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at:
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *------------------------------------------------------------------
23 #include <cnat_va_db.h>
26 #include <spp_alloc.h>
27 #include <spp_byteorder.h>
29 #include <spp_cache.h>
30 #include <spp_interface.h>
32 #include <spp_client_api.h>
33 #include <spp_timers.h>
35 #include <spp_plugin.h>
36 #include <cnat_v4_functions.h>
39 va_bucket_t va_bucket[VA_BUCKETS];
41 void va_bucket_init () {
46 * set the pointer in each bucket
49 for (i=0; i<VA_BUCKETS; i++) {
50 va_bucket[i].next_available_entry = ~0;
55 inline void va_db_add_new_entry (u32 bucket_index,
62 entry_p = va_db_lookup(bucket_index, key);
64 if (PREDICT_FALSE(entry_p)) {
66 "\nVA_ADD_NEW: Bucket %d fnd Existng entry [%d, %d] -> [%d, %d]\n",
67 bucket_index, entry_p->src_port,
68 entry_p->dst_port, key->e.src_port, key->e.dst_port)
70 /* found match entry, update it */
71 entry_p->src_port = key->e.src_port;
72 entry_p->dst_port = key->e.dst_port;
74 FRAG_DEBUG_PRINTF3("VA_ADD_NEW: Existing bucket %d, counter %d\n",
76 va_bucket[bucket_index].new_entry_counter)
80 /* no match, add a new one */
81 head = va_bucket[bucket_index].head_entry;
82 next = va_bucket[bucket_index].next_available_entry;
85 "\nVA_ADD_NEW: Filling bucket %d, index %d with key 0x%llx %x\n",
86 bucket_index, next, key->k.key64, key->k.key32)
88 va_bucket[bucket_index].va_entry[next] = key->e;
90 /* increase next pointer */
91 va_bucket[bucket_index].next_available_entry = (next+1) & VA_BUCKET_MASK;
93 if (PREDICT_FALSE(head == va_bucket[bucket_index].next_available_entry)) {
94 /* adjust head circular pointer */
95 va_bucket[bucket_index].head_entry = (head+1) & VA_BUCKET_MASK;
98 va_bucket[bucket_index].new_entry_counter++;
101 "VA_ADD_NEW: NEW bucket %d, entry %d counter %d\n",
102 bucket_index, next, va_bucket[bucket_index].new_entry_counter)
109 * return pointer to the entry if found,
114 va_entry_t * va_db_lookup (u32 bucket_index, va_lookup_key * key)
118 va_entry_t * entry_p;
119 va_bucket_t * bucket;
121 bucket = &va_bucket[bucket_index];
122 index = bucket->head_entry;
123 next = bucket->next_available_entry;
127 "\nVA_DB_LOOKUP: bucket index %d head %d next %d\n",
128 bucket_index, index, next)
130 /* loop through the entries in the bucket */
131 while( index != next) {
133 if(PREDICT_TRUE(memcmp(&bucket->va_entry[index], key, VA_KEY_SIZE)==0)) {
135 entry_p = &bucket->va_entry[index];
136 /*In add frag entry function we are again assigning key's src
137 port to entry_p's src port. So when a main DB entry is deleted/
138 timed out, and again another entry is created for the same
139 src ip and src port pair, the frag's entry_p will have the
140 previous port info stored and not updated. Hence the below
141 line is not required*/
143 /* *(u32*)&key->e.src_port = *(u32*)&entry_p->src_port; */
144 /* do two ports as u32 :) */
149 index = (index +1) & VA_BUCKET_MASK;
154 if (PREDICT_TRUE(entry_p)) {
155 FRAG_DEBUG_PRINTF3("VA_DB_LOOKUP: bucket index %d entry index %d\n",
157 FRAG_DEBUG_PRINTF5("VA_DB_LOOKUP: SRC-->DST [0x%x, %d] [0x%x, %d]\n",
158 entry_p->src_ip, entry_p->src_port,
159 entry_p->dst_ip, entry_p->dst_port)
160 FRAG_DEBUG_PRINTF3("[vrf 0x%x, id 0x%x]\n",
161 entry_p->vrf, entry_p->ip_id)
163 FRAG_DEBUG_PRINTF1("\nNULL ENTRY\n")
172 int va_db_delete_entry (u32 bucket_index, va_lookup_key * key)
177 va_bucket_t * bucket;
179 bucket = &va_bucket[bucket_index];
180 index = bucket->head_entry;
181 next = bucket->next_available_entry;
184 "\nVA_DB_DELETE_ENTRY: bucket index %d head %d next %d\n",
185 bucket_index, index, next);
187 /* loop through the entries in the bucket */
188 while( index != next) {
189 if(PREDICT_TRUE(memcmp(&bucket->va_entry[index], key,
191 /* Clear the entry */
192 FRAG_DEBUG_PRINTF1("Entry found in delete API");
193 memset(&bucket->va_entry[index], 0, sizeof(va_entry_t));
197 index = (index +1) & VA_BUCKET_MASK;
204 void cnat_va_bucket_used (int argc, unsigned long * argv)
209 for(i=0;i<VA_BUCKETS;i++) {
211 if(PREDICT_TRUE(va_bucket[i].new_entry_counter)) sum++;
215 if (PREDICT_FALSE(!sum)) {
216 printf("no bucket in use\n");
220 printf("index head next counter (%d bucket in use)\n", sum);
222 for(i=0;i<VA_BUCKETS;i++) {
224 if (PREDICT_FALSE(!va_bucket[i].new_entry_counter)) continue;
226 printf(" %04d %04d %04d %d\n", i,
227 va_bucket[i].head_entry,
228 va_bucket[i].next_available_entry,
229 va_bucket[i].new_entry_counter);
234 void cnat_va_dump (int argc, unsigned long * argv)
239 PLATFORM_DEBUG_PRINT("====== SUMMARY ======\n");
240 PLATFORM_DEBUG_PRINT("Total buckets: %d\n", VA_BUCKETS);
241 PLATFORM_DEBUG_PRINT("Entries per bucket: %d\n", VA_ENTRY_PER_BUCKET);
245 for(i=0; i<VA_BUCKETS; i++) {
246 if (PREDICT_TRUE(va_bucket[i].new_entry_counter > 0)) sum ++;
249 PLATFORM_DEBUG_PRINT("buckets in use: %d\n", sum);
252 for(i=0; i<VA_BUCKETS; i++) {
254 if ( PREDICT_FALSE(((va_bucket[i].next_available_entry+1) & VA_BUCKET_MASK)
255 == va_bucket[i].head_entry)) {
261 PLATFORM_DEBUG_PRINT("bucket full: %d\n", sum);
263 /* dump per bucket info */
265 if (argc == 0 ) return;
267 index = (u32) argv[0];
269 if (PREDICT_FALSE(index >= VA_BUCKETS)) {
270 PLATFORM_DEBUG_PRINT("invalid bucket index %d\n", index);
274 PLATFORM_DEBUG_PRINT("\n====== Bucket %d ======\n", index);
276 PLATFORM_DEBUG_PRINT("bucket head index %d\n", va_bucket[index].head_entry);
278 PLATFORM_DEBUG_PRINT("bucket next index %d\n", va_bucket[index].next_available_entry);
280 PLATFORM_DEBUG_PRINT(" source IP dest IP VRF ip-id srcP dstP\n");
282 for(i=0;i<VA_ENTRY_PER_BUCKET;i++) {
283 hex_dump((u8*)&va_bucket[index].va_entry[i], sizeof(va_entry_t));