2 // Copyright (c) 2017 Intel Corporation
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include <rte_common.h>
21 #include <rte_malloc.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>
29 #include "pipeline_timer_be.h"
30 #include "pipeline_cgnapt_be.h"
32 #define BLURT printf("This is line %d of file %s (function %s)\n",\
33 __LINE__, __FILE__, __func__)
36 * Pipeline Timer Implementation.
38 * Implementation of Pipeline TIMER Back End (BE).
39 * Runs on separate timer core.
46 * Main Pipeline structure for Timer.
52 struct pipeline_timer {
54 uint32_t dequeue_loop_cnt;
56 } __rte_cache_aligned;
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;
69 * Function to enqueue timer objects from CGNAPT
77 * @param ingress_entry
78 * CGNAPT ingress entry
80 * CGNAPT thread main pipeline structure
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)
90 struct timer_key *tk_ptr;
92 if (rte_mempool_get(timer_key_mempool, (void **)&tk_ptr) < 0) {
93 printf("TIMER - Error in getting timer_key alloc buffer\n");
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;
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));
116 if (rte_ring_enqueue(timer_ring, (void *)tk_ptr) == -ENOBUFS)
117 printf("Ring enqueue failed: trying to enqueue\n");
121 * Function to dequeue timer objects coming from CGNAPT
124 void timer_thread_dequeue(void)
126 struct timer_key *tk_ptr;
129 ret = rte_ring_dequeue(timer_ring, (void *)&tk_ptr);
133 if (TIMER_DEBUG == 1) {
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));
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
154 //If PCP entry already exits
156 if (tk_ptr->egress_entry->data.timer != NULL) {
158 if (rte_timer_reset(tk_ptr->egress_entry->data.timer,
159 tk_ptr->egress_entry->data.timeout * rte_get_timer_hz(),
163 printf("PCP Entry Err : Timer already running\n");
169 struct rte_timer *timer;
171 if (rte_mempool_get(timer_mempool, (void **)&timer) < 0) {
172 printf("TIMER - Error in getting timer alloc buffer\n");
175 rte_timer_init(timer);
178 if (tk_ptr->egress_entry->data.timeout > 0)
179 tk_ptr->egress_entry->data.timer = timer;
185 tk_ptr->egress_entry->data.timeout > 0 ?
186 tk_ptr->egress_entry->data.timeout * rte_get_timer_hz() :
193 printf("Err : Timer already running\n");
201 * Function to delete a NAT entry due to timer expiry
204 * A pointer to struct rte_timer
206 * void pointer to timer arguments
208 void cgnapt_entry_delete(struct rte_timer *timer, void *arg)
212 struct timer_key *tk_ptr = (struct timer_key *)arg;
213 struct pipeline_cgnapt *p_nat = (struct pipeline_cgnapt *)
218 (tk_ptr->egress_entry->data.timeout > 0) ||
220 ((tk_ptr->egress_entry->data.ttl == 1) &&
221 (tk_ptr->ingress_entry->data.ttl == 1))) {
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);
231 rte_hash_del_key(napt_common_table,
232 &tk_ptr->egress_key);
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);
242 rte_hash_del_key(napt_common_table,
243 &tk_ptr->ingress_key);
245 p_nat->dynCgnaptCount -= 2;
246 p_nat->n_cgnapt_entry_deleted += 2;
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);
255 uint32_t public_ip = tk_ptr->egress_entry->data.pub_ip;
257 release_iport(tk_ptr->ingress_key.port, public_ip, p_nat);
259 ret = decrement_max_port_counter(tk_ptr->egress_key.ip,
260 tk_ptr->egress_key.pid,
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);
268 #ifdef CGNAPT_DBG_PRNT
269 if (CGNAPT_DEBUG >= 2) {
271 printf("Max Port hash entry does not "
274 printf("Max Port Deletion entry for "
275 "the IP address: 0x%x\n",
276 tk_ptr->egress_key.ip);
281 rte_timer_stop(timer);
282 rte_mempool_put(timer_mempool, timer);
283 rte_mempool_put(timer_key_mempool, tk_ptr);
287 if (!tk_ptr->egress_entry->data.ttl)
288 tk_ptr->egress_entry->data.ttl = 1;
290 if (!tk_ptr->ingress_entry->data.ttl)
291 tk_ptr->ingress_entry->data.ttl = 1;
294 rte_timer_reset(timer, cgnapt_timeout, SINGLE,
295 timer_lcore, cgnapt_entry_delete, tk_ptr);
300 * Function to parse the timer pipeline parameters
303 * Timer pipeline structure
305 * Timer pipeline params read from config file
308 * 0 on success, value on failure
311 pipeline_cgnapt_parse_args(struct pipeline_timer *p,
312 struct pipeline_params *params)
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;
320 if (TIMER_DEBUG > 2) {
321 printf("TIMER pipeline_cgnapt_parse_args params->n_args: %d\n",
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];
329 if (TIMER_DEBUG > 2) {
330 printf("TIMER args[%d]: %s %d, %s\n", i, arg_name,
331 atoi(arg_value), arg_value);
334 if (strcmp(arg_name, "dequeue_loop_cnt") == 0) {
335 if (dequeue_loop_cnt_present)
337 dequeue_loop_cnt_present = 1;
339 p_timer->dequeue_loop_cnt = atoi(arg_value);
340 printf("dequeue_loop_cnt : %d\n",
341 p_timer->dequeue_loop_cnt);
345 if (strcmp(arg_name, "timer_dyn_timeout") == 0) {
346 if (timer_dyn_timeout_present)
348 timer_dyn_timeout_present = 1;
350 timer_dyn_timeout = atoi(arg_value);
351 printf("cgnapt dyn timeout: %d\n", timer_dyn_timeout);
355 if (strcmp(arg_name, "n_flows") == 0) {
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);
370 if(!n_flows_present){
371 printf("Timer : n_flows is not present\n");
379 uint32_t get_timer_core_id(void)
385 * Function to initialize main Timer pipeline
387 * Init Timer pipeline parameters
388 * Parse Timer pipline parameters
391 * Timer pipeline parameters read from config file
393 * Pointer to the app_params structure
396 * Timer pipeline struct pointer on success , NULL on failue
398 static void *pipeline_timer_init(struct pipeline_params *params, void *arg)
400 struct app_params *app = (struct app_params *)arg;
401 struct pipeline_timer *p_timer;
404 printf("Entering pipeline_timer_init\n");
406 /* Check input arguments */
410 /* Memory allocation */
411 size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct pipeline_timer));
412 p_timer = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
417 p_timer->dequeue_loop_cnt = 100;
419 timer_lcore = rte_lcore_id();
421 if (pipeline_cgnapt_parse_args(p_timer, params))
424 cgnapt_timeout = rte_get_tsc_hz() * timer_dyn_timeout;
425 printf("cgnapt_timerout%" PRIu64 "\n", cgnapt_timeout);
427 /* Create port alloc buffer */
429 timer_mempool = rte_mempool_create("timer_mempool",
430 timer_objs_mempool_count,
431 sizeof(struct rte_timer),
434 NULL, NULL, rte_socket_id(), 0);
435 if (timer_mempool == NULL)
436 rte_panic("timer_mempool create error\n");
438 timer_key_mempool = rte_mempool_create("timer_key_mempool",
439 timer_objs_mempool_count,
440 sizeof(struct timer_key),
443 NULL, NULL, rte_socket_id(), 0);
444 if (timer_key_mempool == NULL)
445 rte_panic("timer_key_mempool create error\n");
447 timer_ring = rte_ring_create("TIMER_RING", timer_ring_alloc_cnt,
448 rte_socket_id(), RING_F_SC_DEQ);
450 if (timer_ring == NULL)
451 rte_panic("timer_ring creation failed");
453 return (void *)p_timer;
457 * Function to free the Timer pipeline
460 * Timer pipeline structure pointer
463 * 0 on success, Negitive value on failure
465 static int pipeline_timer_free(void *pipeline)
467 struct pipeline_master *p = (struct pipeline_master *)pipeline;
478 * Function to run custom code continiously
481 * Timer pipeline structure pointer
484 * 0 on success, Negitive value on failure
486 static int pipeline_timer_run(void *pipeline)
488 struct pipeline_timer *p = (struct pipeline_timer *)pipeline;
493 for (i = 0; i < p->dequeue_loop_cnt; i++)
494 timer_thread_dequeue();
500 * Function to run custom code on pipeline timer expiry
503 * Timer pipeline structure pointer
506 * 0 on success, Negitive value on failure
508 static int pipeline_timer_timer(__rte_unused void *pipeline)
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,