Added support for mis-ordered packets in rapid
[samplevnf.git] / VNFs / vCGNAPT / pipeline / pipeline_timer_be.c
1 /*
2 // Copyright (c) 2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include <fcntl.h>
18 #include <unistd.h>
19
20 #include <rte_common.h>
21 #include <rte_malloc.h>
22 #include <rte_ring.h>
23 #include <rte_hexdump.h>
24 #include <rte_timer.h>
25 #include <rte_lcore.h>
26 #include <rte_cycles.h>
27 #include <rte_jhash.h>
28 #include "app.h"
29 #include "pipeline_timer_be.h"
30 #include "pipeline_cgnapt_be.h"
31
32 #define BLURT printf("This is line %d of file %s (function %s)\n",\
33                                                  __LINE__, __FILE__, __func__)
34 /**
35  * @file
36  * Pipeline Timer Implementation.
37  *
38  * Implementation of Pipeline TIMER Back End (BE).
39  * Runs on separate timer core.
40  *
41  */
42
43
44 /**
45  * @struct
46  * Main Pipeline structure for Timer.
47  *
48  *
49  */
50
51
52 struct pipeline_timer {
53
54         uint32_t dequeue_loop_cnt;
55
56 } __rte_cache_aligned;
57
58 struct rte_mempool *timer_mempool;
59 struct rte_mempool *timer_key_mempool;
60 static int timer_objs_mempool_count;
61 static int timer_ring_alloc_cnt;
62 static uint32_t timer_dyn_timeout = 30;
63 uint64_t cgnapt_timeout;
64 uint32_t timer_lcore;
65
66 uint8_t TIMER_DEBUG;
67
68 /**
69 * Function to enqueue timer objects from CGNAPT
70 *
71 * @param egress_key
72 *  CGNAPT egress key
73 * @param ingress_key
74 *  CGNAPT inress key
75 * @param egress_entry
76 *  CGNAPT egress entry
77 * @param ingress_entry
78 *  CGNAPT ingress entry
79 * @param p_nat
80 *  CGNAPT thread main pipeline structure
81 */
82
83 void timer_thread_enqueue(struct pipeline_cgnapt_entry_key *egress_key,
84                                 struct pipeline_cgnapt_entry_key *ingress_key,
85                                 struct cgnapt_table_entry *egress_entry,
86                                 struct cgnapt_table_entry *ingress_entry,
87                                 struct pipeline *p_nat)
88 {
89
90         struct timer_key *tk_ptr;
91
92         if (rte_mempool_get(timer_key_mempool, (void **)&tk_ptr) < 0) {
93                 printf("TIMER - Error in getting timer_key alloc buffer\n");
94                 return;
95         }
96
97         rte_memcpy(&tk_ptr->egress_key, egress_key,
98                          sizeof(struct pipeline_cgnapt_entry_key));
99         rte_memcpy(&tk_ptr->ingress_key, ingress_key,
100                          sizeof(struct pipeline_cgnapt_entry_key));
101         tk_ptr->egress_entry = egress_entry;
102         tk_ptr->ingress_entry = ingress_entry;
103         tk_ptr->p_nat = (struct pipeline *) p_nat;
104
105         if (TIMER_DEBUG == 1) {
106                 rte_hexdump(stdout, "Egress Key", &tk_ptr->egress_key,
107                                         sizeof(struct pipeline_cgnapt_entry_key));
108                 rte_hexdump(stdout, "Ingress Key", &tk_ptr->ingress_key,
109                                         sizeof(struct pipeline_cgnapt_entry_key));
110                 rte_hexdump(stdout, "Egress Entry", &tk_ptr->egress_entry,
111                                         sizeof(struct cgnapt_table_entry));
112                 rte_hexdump(stdout, "Ingress Entry", &tk_ptr->ingress_entry,
113                                         sizeof(struct cgnapt_table_entry));
114         }
115
116         if (rte_ring_enqueue(timer_ring, (void *)tk_ptr) == -ENOBUFS)
117                 printf("Ring enqueue failed: trying to enqueue\n");
118 }
119
120 /**
121 * Function to dequeue timer objects coming from CGNAPT
122 *
123 */
124 void timer_thread_dequeue(void)
125 {
126         struct timer_key *tk_ptr;
127         int ret;
128
129         ret = rte_ring_dequeue(timer_ring, (void *)&tk_ptr);
130         if (ret == -ENOENT)
131                 return;
132
133         if (TIMER_DEBUG == 1) {
134                 BLURT;
135                 rte_hexdump(stdout, "Egress Key", &tk_ptr->egress_key,
136                                         sizeof(struct pipeline_cgnapt_entry_key));
137                 rte_hexdump(stdout, "Ingress Key", &tk_ptr->ingress_key,
138                                         sizeof(struct pipeline_cgnapt_entry_key));
139                 rte_hexdump(stdout, "Egress Entry", &tk_ptr->egress_entry,
140                                         sizeof(struct cgnapt_table_entry));
141                 rte_hexdump(stdout, "Ingress Entry", &tk_ptr->ingress_entry,
142                                         sizeof(struct cgnapt_table_entry));
143         }
144
145         #ifdef PCP_ENABLE
146         /* To differentiate between PCP req entry and dynamic entry we
147         * are using "timeout" value in the table entry
148         * timeout is - 1 : static entry
149         * timeout is 0  : dynamic entry
150         * timeout > 0  : pcp entry
151         * timeout is 0 then default cgnapt_timeout value is used
152         */
153
154         //If PCP entry already exits
155
156         if (tk_ptr->egress_entry->data.timer != NULL) {
157
158                 if (rte_timer_reset(tk_ptr->egress_entry->data.timer,
159                         tk_ptr->egress_entry->data.timeout * rte_get_timer_hz(),
160                         SINGLE, timer_lcore,
161                         cgnapt_entry_delete,
162                         tk_ptr) < 0)
163                 printf("PCP Entry Err : Timer already running\n");
164
165
166         } else{
167         #endif
168
169         struct rte_timer *timer;
170
171         if (rte_mempool_get(timer_mempool, (void **)&timer) < 0) {
172                 printf("TIMER - Error in getting timer alloc buffer\n");
173                 return;
174         }
175         rte_timer_init(timer);
176
177         #ifdef PCP_ENABLE
178                 if (tk_ptr->egress_entry->data.timeout > 0)
179                         tk_ptr->egress_entry->data.timer = timer;
180         #endif
181
182         if (rte_timer_reset(
183                 timer,
184                 #ifdef PCP_ENABLE
185                 tk_ptr->egress_entry->data.timeout > 0 ?
186                 tk_ptr->egress_entry->data.timeout * rte_get_timer_hz() :
187                 #endif
188                 cgnapt_timeout,
189                 SINGLE,
190                 timer_lcore,
191                 cgnapt_entry_delete,
192                 tk_ptr) < 0)
193                 printf("Err : Timer already running\n");
194
195         #ifdef PCP_ENABLE
196         }
197         #endif
198 }
199
200 /**
201  * Function to delete a NAT entry due to timer expiry
202  *
203  * @param timer
204  *  A pointer to struct rte_timer
205  * @param arg
206  *  void pointer to timer arguments
207  */
208 void cgnapt_entry_delete(struct rte_timer *timer, void *arg)
209 {
210         int ret = 0;
211
212         struct timer_key *tk_ptr = (struct timer_key *)arg;
213         struct pipeline_cgnapt *p_nat = (struct pipeline_cgnapt *)
214                                         tk_ptr->p_nat;
215
216         if (
217                 #ifdef PCP_ENABLE
218                 (tk_ptr->egress_entry->data.timeout > 0) ||
219                 #endif
220                 ((tk_ptr->egress_entry->data.ttl == 1) &&
221                 (tk_ptr->ingress_entry->data.ttl == 1))) {
222
223                 /* call pipeline hash table egress entry delete */
224                 #ifdef CGNAPT_DEBUGGING
225                 #ifdef CGNAPT_DBG_PRNT
226                 printf("\nTimer egr:");
227                 print_key(&tk_ptr->egress_key);
228                 #endif
229                 #endif
230
231                 rte_hash_del_key(napt_common_table,
232                                         &tk_ptr->egress_key);
233
234                 /* call pipeline hash table ingress entry delete */
235                 #ifdef CGNAPT_DEBUGGING
236                 #ifdef CGNAPT_DBG_PRNT
237                 printf("\nTimer ing:");
238                 print_key(&tk_ptr->ingress_key);
239                 #endif
240                 #endif
241
242                 rte_hash_del_key(napt_common_table,
243                                         &tk_ptr->ingress_key);
244
245                 p_nat->dynCgnaptCount -= 2;
246                 p_nat->n_cgnapt_entry_deleted += 2;
247
248                 if (is_phy_port_privte(tk_ptr->egress_key.pid)) {
249                 #ifdef CGNAPT_DBG_PRNT
250                         if (CGNAPT_DEBUG > 2)
251                                 printf("Deleting port:%d\n",
252                                                          tk_ptr->ingress_key.port);
253                 #endif
254
255                 uint32_t public_ip = tk_ptr->egress_entry->data.pub_ip;
256
257                 release_iport(tk_ptr->ingress_key.port, public_ip, p_nat);
258
259                 ret = decrement_max_port_counter(tk_ptr->egress_key.ip,
260                                                 tk_ptr->egress_key.pid,
261                                                 p_nat);
262
263                 if (ret == MAX_PORT_DEC_REACHED)
264                         rte_atomic16_dec(&all_public_ip
265                                  [rte_jhash(&public_ip, 4, 0) %
266                                         CGNAPT_MAX_PUB_IP].count);
267
268                 #ifdef CGNAPT_DBG_PRNT
269                         if (CGNAPT_DEBUG >= 2) {
270                                 if (ret < 0)
271                                         printf("Max Port hash entry does not "
272                                         "exist: %d\n", ret);
273                                 if (!ret)
274                                         printf("Max Port Deletion entry for "
275                                         "the IP address: 0x%x\n",
276                                         tk_ptr->egress_key.ip);
277                         }
278                 #endif
279                 }
280
281                 rte_timer_stop(timer);
282                 rte_mempool_put(timer_mempool, timer);
283                 rte_mempool_put(timer_key_mempool, tk_ptr);
284                 return;
285         }
286
287         if (!tk_ptr->egress_entry->data.ttl)
288                 tk_ptr->egress_entry->data.ttl = 1;
289
290         if (!tk_ptr->ingress_entry->data.ttl)
291                 tk_ptr->ingress_entry->data.ttl = 1;
292
293         /*cgnapt_timeout*/
294         rte_timer_reset(timer, cgnapt_timeout, SINGLE,
295                         timer_lcore, cgnapt_entry_delete, tk_ptr);
296
297 }
298
299 /*
300  * Function to parse the timer pipeline parameters
301  *
302  * @params p
303  *  Timer pipeline structure
304  * @params params
305  *  Timer pipeline params read from config file
306  *
307  * @return
308  * 0 on success, value on failure
309  */
310 static int
311 pipeline_cgnapt_parse_args(struct pipeline_timer *p,
312                                  struct pipeline_params *params)
313 {
314         uint32_t dequeue_loop_cnt_present = 0;
315         uint32_t n_flows_present = 0;
316         uint32_t timer_dyn_timeout_present = 0;
317         struct pipeline_timer *p_timer = (struct pipeline_timer *)p;
318         uint32_t i;
319
320         if (TIMER_DEBUG > 2) {
321                 printf("TIMER pipeline_cgnapt_parse_args params->n_args: %d\n",
322                                          params->n_args);
323         }
324
325         for (i = 0; i < params->n_args; i++) {
326                 char *arg_name = params->args_name[i];
327                 char *arg_value = params->args_value[i];
328
329                 if (TIMER_DEBUG > 2) {
330                         printf("TIMER args[%d]: %s %d, %s\n", i, arg_name,
331                                                  atoi(arg_value), arg_value);
332                 }
333
334                 if (strcmp(arg_name, "dequeue_loop_cnt") == 0) {
335                         if (dequeue_loop_cnt_present)
336                                 return -1;
337                         dequeue_loop_cnt_present = 1;
338
339                         p_timer->dequeue_loop_cnt = atoi(arg_value);
340                         printf("dequeue_loop_cnt : %d\n",
341                                                  p_timer->dequeue_loop_cnt);
342                         continue;
343                 }
344
345                 if (strcmp(arg_name, "timer_dyn_timeout") == 0) {
346                         if (timer_dyn_timeout_present)
347                                 return -1;
348                         timer_dyn_timeout_present = 1;
349
350                         timer_dyn_timeout = atoi(arg_value);
351                         printf("cgnapt dyn timeout: %d\n", timer_dyn_timeout);
352                         continue;
353                 }
354
355                 if (strcmp(arg_name, "n_flows") == 0) {
356                         if(n_flows_present)
357                                 return -1;
358                         n_flows_present = 1;
359
360                         printf("Timer : n_flows = %d\n", atoi(arg_value));
361                         timer_objs_mempool_count =
362                                         nextPowerOf2(atoi(arg_value));
363                         timer_ring_alloc_cnt =
364                                         nextPowerOf2(atoi(arg_value));
365                         printf("Timer : next power of 2 of n_flows = %d\n",
366                                 timer_ring_alloc_cnt);
367                 }
368         }
369
370         if(!n_flows_present){
371                 printf("Timer : n_flows is not present\n");
372                 return -1;
373         }
374
375
376         return 0;
377 }
378
379 uint32_t get_timer_core_id(void)
380 {
381         return timer_lcore;
382 }
383
384 /*
385  * Function to initialize main Timer pipeline
386  *
387  * Init Timer pipeline parameters
388  * Parse Timer pipline parameters
389  *
390  * @params params
391  *  Timer pipeline parameters read from config file
392  * @params arg
393  *  Pointer to the app_params structure
394  *
395  * @return
396  * Timer pipeline struct pointer on success , NULL on failue
397  */
398 static void *pipeline_timer_init(struct pipeline_params *params, void *arg)
399 {
400         struct app_params *app = (struct app_params *)arg;
401         struct pipeline_timer *p_timer;
402         uint32_t size;
403
404         printf("Entering pipeline_timer_init\n");
405
406         /* Check input arguments */
407         if (app == NULL)
408                 return NULL;
409
410         /* Memory allocation */
411         size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_timer));
412         p_timer = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
413
414         if (p_timer == NULL)
415                 return NULL;
416
417         p_timer->dequeue_loop_cnt = 100;
418
419         timer_lcore = rte_lcore_id();
420
421         if (pipeline_cgnapt_parse_args(p_timer, params))
422                 return NULL;
423
424         cgnapt_timeout = rte_get_tsc_hz() * timer_dyn_timeout;
425         printf("cgnapt_timerout%" PRIu64 "\n", cgnapt_timeout);
426
427         /* Create port alloc buffer */
428
429         timer_mempool = rte_mempool_create("timer_mempool",
430                                                  timer_objs_mempool_count,
431                                                  sizeof(struct rte_timer),
432                                                  0, 0,
433                                                  NULL, NULL,
434                                                  NULL, NULL, rte_socket_id(), 0);
435         if (timer_mempool == NULL)
436                 rte_panic("timer_mempool create error\n");
437
438         timer_key_mempool = rte_mempool_create("timer_key_mempool",
439                                                                  timer_objs_mempool_count,
440                                                                  sizeof(struct timer_key),
441                                                                  0, 0,
442                                                                  NULL, NULL,
443                                                                  NULL, NULL, rte_socket_id(), 0);
444         if (timer_key_mempool == NULL)
445                 rte_panic("timer_key_mempool create error\n");
446
447         timer_ring = rte_ring_create("TIMER_RING", timer_ring_alloc_cnt,
448                         rte_socket_id(), RING_F_SC_DEQ);
449
450         if (timer_ring == NULL)
451                 rte_panic("timer_ring creation failed");
452
453         return (void *)p_timer;
454 }
455
456 /*
457  * Function to free the Timer pipeline
458  *
459  * @params pipeline
460  *  Timer pipeline structure pointer
461  *
462  * @return
463  * 0 on success, Negitive value on failure
464  */
465 static int pipeline_timer_free(void *pipeline)
466 {
467         struct pipeline_master *p = (struct pipeline_master *)pipeline;
468
469         if (p == NULL)
470                 return -EINVAL;
471
472         rte_free(p);
473
474         return 0;
475 }
476
477 /*
478  * Function to run custom code continiously
479  *
480  * @params pipeline
481  *  Timer pipeline structure pointer
482  *
483  * @return
484  * 0 on success, Negitive value on failure
485  */
486 static int pipeline_timer_run(void *pipeline)
487 {
488         struct pipeline_timer *p = (struct pipeline_timer *)pipeline;
489         uint32_t i;
490
491         if (p == NULL)
492                 return -EINVAL;
493         for (i = 0; i < p->dequeue_loop_cnt; i++)
494                 timer_thread_dequeue();
495
496         return 0;
497 }
498
499 /*
500  * Function to run custom code on pipeline timer expiry
501  *
502  * @params pipeline
503  *  Timer pipeline structure pointer
504  *
505  * @return
506  * 0 on success, Negitive value on failure
507  */
508 static int pipeline_timer_timer(__rte_unused void *pipeline)
509 {
510         rte_timer_manage();
511         return 0;
512 }
513
514 struct pipeline_be_ops pipeline_timer_be_ops = {
515         .f_init = pipeline_timer_init,
516         .f_free = pipeline_timer_free,
517         .f_run = pipeline_timer_run,
518         .f_timer = pipeline_timer_timer,
519         .f_track = NULL,
520 };