Initial commit of vpp code.
[vpp.git] / vnet / vnet / vcgn / cnat_va_db.c
1 /*
2  *------------------------------------------------------------------
3  * cnat_va_db.c - virtual assembly database
4  *
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:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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  *------------------------------------------------------------------
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <cnat_va_db.h>
24 #include <format.h>
25 #include <spp_node.h>
26 #include <spp_alloc.h>
27 #include <spp_byteorder.h>
28 #include <spp_main.h>
29 #include <spp_cache.h>
30 #include <spp_interface.h>
31 #include <spp_api.h>
32 #include <spp_client_api.h>
33 #include <spp_timers.h>
34 #include <cnat_db.h>
35 #include <spp_plugin.h>
36 #include <cnat_v4_functions.h>
37
38
39 va_bucket_t va_bucket[VA_BUCKETS];
40
41 void va_bucket_init () {
42
43     u32 i;
44
45     /* 
46      * set the pointer in each bucket
47      * points to nowhere
48      */
49     for (i=0; i<VA_BUCKETS; i++) {
50         va_bucket[i].next_available_entry = ~0;
51     }
52
53 }
54
55 inline void va_db_add_new_entry (u32 bucket_index, 
56                                  va_lookup_key * key ) 
57 {
58
59     va_entry_t * entry_p;
60     u32 head, next;
61
62     entry_p = va_db_lookup(bucket_index, key);
63
64     if (PREDICT_FALSE(entry_p)) { 
65         FRAG_DEBUG_PRINTF6(
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)
69
70         /* found match entry, update it */
71         entry_p->src_port = key->e.src_port; 
72         entry_p->dst_port = key->e.dst_port; 
73
74         FRAG_DEBUG_PRINTF3("VA_ADD_NEW: Existing bucket %d, counter %d\n", 
75                             bucket_index, 
76                             va_bucket[bucket_index].new_entry_counter)
77
78     } else { 
79  
80         /* no match, add a new one */
81         head = va_bucket[bucket_index].head_entry;
82         next = va_bucket[bucket_index].next_available_entry;
83
84         FRAG_DEBUG_PRINTF5(
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)
87
88         va_bucket[bucket_index].va_entry[next] = key->e;
89
90         /* increase next pointer */
91         va_bucket[bucket_index].next_available_entry = (next+1) & VA_BUCKET_MASK;
92
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;
96         }
97
98         va_bucket[bucket_index].new_entry_counter++;
99
100         FRAG_DEBUG_PRINTF4(
101             "VA_ADD_NEW: NEW bucket %d, entry %d counter %d\n", 
102             bucket_index, next, va_bucket[bucket_index].new_entry_counter)
103     }
104
105
106
107 /* 
108  * use the key, 
109  * return pointer to the entry if found, 
110  * NULL if not 
111  */
112
113 inline 
114 va_entry_t * va_db_lookup (u32 bucket_index, va_lookup_key * key) 
115 {
116
117     u32 index, next;
118     va_entry_t * entry_p;
119     va_bucket_t * bucket;
120  
121     bucket  = &va_bucket[bucket_index];
122     index   = bucket->head_entry;
123     next    = bucket->next_available_entry;
124     entry_p = NULL;
125
126     FRAG_DEBUG_PRINTF4(
127         "\nVA_DB_LOOKUP: bucket index %d head %d next %d\n",
128         bucket_index, index, next)
129
130     /* loop through the entries in the bucket */
131     while( index != next) {
132
133         if(PREDICT_TRUE(memcmp(&bucket->va_entry[index], key, VA_KEY_SIZE)==0)) {
134
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*/
142               
143             /* *(u32*)&key->e.src_port = *(u32*)&entry_p->src_port; */
144             /* do two ports as u32 :) */
145             
146             break;
147         }
148
149         index = (index +1) & VA_BUCKET_MASK;
150
151     }
152
153 #ifdef FRAG_DEBUG
154     if (PREDICT_TRUE(entry_p)) {
155         FRAG_DEBUG_PRINTF3("VA_DB_LOOKUP: bucket index %d entry index %d\n",
156                            bucket_index, index)
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)
162     } else {
163         FRAG_DEBUG_PRINTF1("\nNULL ENTRY\n")
164     }
165 #endif
166
167     return entry_p;
168
169 }
170
171 inline 
172 int va_db_delete_entry (u32 bucket_index, va_lookup_key * key) 
173 {
174
175     u32 index, next;
176     int entry_found = 0;
177     va_bucket_t * bucket;
178  
179     bucket  = &va_bucket[bucket_index];
180     index   = bucket->head_entry;
181     next    = bucket->next_available_entry;
182
183     FRAG_DEBUG_PRINTF4(
184         "\nVA_DB_DELETE_ENTRY: bucket index %d head %d next %d\n",
185         bucket_index, index, next);
186
187     /* loop through the entries in the bucket */
188     while( index != next) {
189         if(PREDICT_TRUE(memcmp(&bucket->va_entry[index], key,
190                                VA_KEY_SIZE)==0)) {
191             /* Clear the entry */
192             FRAG_DEBUG_PRINTF1("Entry found in delete API");
193             memset(&bucket->va_entry[index], 0, sizeof(va_entry_t));
194             entry_found = 1;
195             break;
196         }
197         index = (index +1) & VA_BUCKET_MASK;
198     }
199     return entry_found;
200 }    
201   
202
203
204 void cnat_va_bucket_used (int argc, unsigned long * argv) 
205 {
206
207     u32 i, sum = 0;;
208
209     for(i=0;i<VA_BUCKETS;i++)  {
210
211         if(PREDICT_TRUE(va_bucket[i].new_entry_counter)) sum++;
212
213     }
214
215     if (PREDICT_FALSE(!sum)) {
216         printf("no bucket in use\n");
217         return;
218     }
219
220     printf("index head next counter (%d bucket in use)\n", sum);
221
222     for(i=0;i<VA_BUCKETS;i++) {
223
224         if (PREDICT_FALSE(!va_bucket[i].new_entry_counter)) continue; 
225
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);
230
231     }
232 }
233
234 void cnat_va_dump (int argc, unsigned long * argv) 
235 {
236
237     u32 i, sum, index ;
238
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);
242
243     sum = 0;
244
245     for(i=0; i<VA_BUCKETS; i++) {
246         if (PREDICT_TRUE(va_bucket[i].new_entry_counter > 0)) sum ++;
247     }
248
249     PLATFORM_DEBUG_PRINT("buckets in use:     %d\n", sum); 
250
251     sum = 0;
252     for(i=0; i<VA_BUCKETS; i++) {
253
254         if ( PREDICT_FALSE(((va_bucket[i].next_available_entry+1) & VA_BUCKET_MASK)  
255                == va_bucket[i].head_entry)) {
256
257             sum ++;
258         }
259     }
260
261     PLATFORM_DEBUG_PRINT("bucket full:        %d\n", sum); 
262
263     /* dump per bucket info */
264
265     if (argc == 0 ) return;
266
267     index = (u32) argv[0];
268
269     if (PREDICT_FALSE(index >= VA_BUCKETS)) {
270         PLATFORM_DEBUG_PRINT("invalid bucket index %d\n", index);
271         return;
272     }
273
274     PLATFORM_DEBUG_PRINT("\n====== Bucket %d ======\n", index);
275
276     PLATFORM_DEBUG_PRINT("bucket head index %d\n", va_bucket[index].head_entry);
277
278     PLATFORM_DEBUG_PRINT("bucket next index %d\n", va_bucket[index].next_available_entry);
279
280     PLATFORM_DEBUG_PRINT(" source IP     dest IP     VRF  ip-id   srcP  dstP\n");
281
282     for(i=0;i<VA_ENTRY_PER_BUCKET;i++) {
283         hex_dump((u8*)&va_bucket[index].va_entry[i], sizeof(va_entry_t));
284     }
285
286 }