gateway: Created common code for routing in gateway
[samplevnf.git] / common / vnf_common / thread_fe.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 <rte_common.h>
18 #include <rte_ring.h>
19 #include <rte_malloc.h>
20 #include <cmdline_rdline.h>
21 #include <cmdline_parse.h>
22 #include <cmdline_parse_num.h>
23 #include <cmdline_parse_string.h>
24 #include <cmdline_parse_ipaddr.h>
25 #include <cmdline_parse_etheraddr.h>
26 #include <cmdline_socket.h>
27 #include <cmdline.h>
28
29 #include "thread.h"
30 #include "thread_fe.h"
31 #include "pipeline.h"
32 #include "pipeline_common_fe.h"
33 #include "app.h"
34
35 static inline void *
36 thread_msg_send_recv(struct app_params *app,
37         uint32_t socket_id, uint32_t core_id, uint32_t ht_id,
38         void *msg,
39         uint32_t timeout_ms)
40 {
41         struct rte_ring *r_req = app_thread_msgq_in_get(app,
42                 socket_id, core_id, ht_id);
43         if(r_req == NULL)
44                 return NULL;
45         struct rte_ring *r_rsp = app_thread_msgq_out_get(app,
46                 socket_id, core_id, ht_id);
47         if(r_rsp == NULL)
48                 return NULL;
49         uint64_t hz = rte_get_tsc_hz();
50         void *msg_recv;
51         uint64_t deadline;
52         int status;
53
54         /* send */
55         do {
56                 status = rte_ring_sp_enqueue(r_req, (void *) msg);
57         } while (status == -ENOBUFS);
58
59         /* recv */
60         deadline = (timeout_ms) ?
61                 (rte_rdtsc() + ((hz * timeout_ms) / 1000)) :
62                 UINT64_MAX;
63
64         do {
65                 if (rte_rdtsc() > deadline)
66                         return NULL;
67
68                 status = rte_ring_sc_dequeue(r_rsp, &msg_recv);
69         } while (status != 0);
70
71         return msg_recv;
72 }
73
74 int
75 app_pipeline_enable(struct app_params *app,
76                 uint32_t socket_id,
77                 uint32_t core_id,
78                 uint32_t hyper_th_id,
79                 uint32_t pipeline_id)
80 {
81         struct thread_pipeline_enable_msg_req *req;
82         struct thread_pipeline_enable_msg_rsp *rsp;
83         int thread_id;
84         struct app_pipeline_data *p;
85         struct app_pipeline_params *p_params;
86         struct pipeline_type *p_type;
87         int status;
88
89         if (app == NULL)
90                 return -1;
91
92         thread_id = cpu_core_map_get_lcore_id(app->core_map,
93                         socket_id,
94                         core_id,
95                         hyper_th_id);
96
97         if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
98                 return -1;
99
100         if (app_pipeline_data(app, pipeline_id) == NULL)
101                 return -1;
102
103         p = &app->pipeline_data[pipeline_id];
104         p_params = &app->pipeline_params[pipeline_id];
105         p_type = app_pipeline_type_find(app, p_params->type);
106         if (p_type == NULL)
107                 return -1;
108
109         if (p->enabled == 1)
110                 return -1;
111
112         req = app_msg_alloc(app);
113         if (req == NULL)
114                 return -1;
115
116         req->type = THREAD_MSG_REQ_PIPELINE_ENABLE;
117         req->pipeline_id = pipeline_id;
118         req->be = p->be;
119         req->f_run = p_type->be_ops->f_run;
120         req->f_timer = p_type->be_ops->f_timer;
121         req->timer_period = p->timer_period;
122
123         rsp = thread_msg_send_recv(app,
124                 socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
125         if (rsp == NULL)
126                 return -1;
127
128         status = rsp->status;
129         app_msg_free(app, rsp);
130
131         if (status != 0)
132                 return -1;
133
134         p->enabled = 1;
135         return 0;
136 }
137
138 int
139 app_pipeline_disable(struct app_params *app,
140                 uint32_t socket_id,
141                 uint32_t core_id,
142                 uint32_t hyper_th_id,
143                 uint32_t pipeline_id)
144 {
145         struct thread_pipeline_disable_msg_req *req;
146         struct thread_pipeline_disable_msg_rsp *rsp;
147         int thread_id;
148         struct app_pipeline_data *p;
149         int status;
150
151         if (app == NULL)
152                 return -1;
153
154         thread_id = cpu_core_map_get_lcore_id(app->core_map,
155                         socket_id,
156                         core_id,
157                         hyper_th_id);
158
159         if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
160                 return -1;
161
162         if (app_pipeline_data(app, pipeline_id) == NULL)
163                 return -1;
164
165         p = &app->pipeline_data[pipeline_id];
166
167         if (p->enabled == 0)
168                 return -1;
169
170         req = app_msg_alloc(app);
171         if (req == NULL)
172                 return -1;
173
174         req->type = THREAD_MSG_REQ_PIPELINE_DISABLE;
175         req->pipeline_id = pipeline_id;
176
177         rsp = thread_msg_send_recv(app,
178                 socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
179
180         if (rsp == NULL)
181                 return -1;
182
183         status = rsp->status;
184         app_msg_free(app, rsp);
185
186         if (status != 0)
187                 return -1;
188
189         p->enabled = 0;
190         return 0;
191 }
192
193 int
194 app_thread_headroom(struct app_params *app,
195                 uint32_t socket_id,
196                 uint32_t core_id,
197                 uint32_t hyper_th_id)
198 {
199         struct thread_headroom_read_msg_req *req;
200         struct thread_headroom_read_msg_rsp *rsp;
201         int thread_id;
202         int status;
203
204         if (app == NULL)
205                 return -1;
206
207         thread_id = cpu_core_map_get_lcore_id(app->core_map,
208                         socket_id,
209                         core_id,
210                         hyper_th_id);
211
212         if ((thread_id < 0) || !app_core_is_enabled(app, thread_id))
213                 return -1;
214
215         req = app_msg_alloc(app);
216         if (req == NULL)
217                 return -1;
218
219         req->type = THREAD_MSG_REQ_HEADROOM_READ;
220
221         rsp = thread_msg_send_recv(app,
222                 socket_id, core_id, hyper_th_id, req, MSG_TIMEOUT_DEFAULT);
223
224         if (rsp == NULL)
225                 return -1;
226
227         status = rsp->status;
228
229         if (status != 0)
230                 return -1;
231
232         printf("%.3f%%\n", rsp->headroom_ratio * 100);
233
234
235         app_msg_free(app, rsp);
236
237         return 0;
238 }
239
240 /*
241  * pipeline enable
242  */
243
244 struct cmd_pipeline_enable_result {
245         cmdline_fixed_string_t t_string;
246         cmdline_fixed_string_t t_id_string;
247         cmdline_fixed_string_t pipeline_string;
248         uint32_t pipeline_id;
249         cmdline_fixed_string_t enable_string;
250 };
251
252 static void
253 cmd_pipeline_enable_parsed(
254         void *parsed_result,
255         __rte_unused struct cmdline *cl,
256          void *data)
257 {
258         struct cmd_pipeline_enable_result *params = parsed_result;
259         struct app_params *app = data;
260         int status;
261         uint32_t core_id, socket_id, hyper_th_id;
262
263         if (parse_pipeline_core(&socket_id,
264                         &core_id,
265                         &hyper_th_id,
266                         params->t_id_string) != 0) {
267                 printf("Command failed\n");
268                 return;
269         }
270
271         status = app_pipeline_enable(app,
272                         socket_id,
273                         core_id,
274                         hyper_th_id,
275                         params->pipeline_id);
276
277         if (status != 0)
278                 printf("Command failed\n");
279 }
280
281 cmdline_parse_token_string_t cmd_pipeline_enable_t_string =
282         TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, t_string, "t");
283
284 cmdline_parse_token_string_t cmd_pipeline_enable_t_id_string =
285         TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, t_id_string,
286                 NULL);
287
288 cmdline_parse_token_string_t cmd_pipeline_enable_pipeline_string =
289         TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, pipeline_string,
290                 "pipeline");
291
292 cmdline_parse_token_num_t cmd_pipeline_enable_pipeline_id =
293         TOKEN_NUM_INITIALIZER(struct cmd_pipeline_enable_result, pipeline_id,
294                 UINT32);
295
296 cmdline_parse_token_string_t cmd_pipeline_enable_enable_string =
297         TOKEN_STRING_INITIALIZER(struct cmd_pipeline_enable_result, enable_string,
298                 "enable");
299
300 cmdline_parse_inst_t cmd_pipeline_enable = {
301         .f = cmd_pipeline_enable_parsed,
302         .data = NULL,
303         .help_str = "Enable pipeline on specified core",
304         .tokens = {
305                 (void *)&cmd_pipeline_enable_t_string,
306                 (void *)&cmd_pipeline_enable_t_id_string,
307                 (void *)&cmd_pipeline_enable_pipeline_string,
308                 (void *)&cmd_pipeline_enable_pipeline_id,
309                 (void *)&cmd_pipeline_enable_enable_string,
310                 NULL,
311         },
312 };
313
314 /*
315  * pipeline disable
316  */
317
318 struct cmd_pipeline_disable_result {
319         cmdline_fixed_string_t t_string;
320         cmdline_fixed_string_t t_id_string;
321         cmdline_fixed_string_t pipeline_string;
322         uint32_t pipeline_id;
323         cmdline_fixed_string_t disable_string;
324 };
325
326 static void
327 cmd_pipeline_disable_parsed(
328         void *parsed_result,
329         __rte_unused struct cmdline *cl,
330          void *data)
331 {
332         struct cmd_pipeline_disable_result *params = parsed_result;
333         struct app_params *app = data;
334         int status;
335         uint32_t core_id, socket_id, hyper_th_id;
336
337         if (parse_pipeline_core(&socket_id,
338                         &core_id,
339                         &hyper_th_id,
340                         params->t_id_string) != 0) {
341                 printf("Command failed\n");
342                 return;
343         }
344
345         status = app_pipeline_disable(app,
346                         socket_id,
347                         core_id,
348                         hyper_th_id,
349                         params->pipeline_id);
350
351         if (status != 0)
352                 printf("Command failed\n");
353 }
354
355 cmdline_parse_token_string_t cmd_pipeline_disable_t_string =
356         TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, t_string, "t");
357
358 cmdline_parse_token_string_t cmd_pipeline_disable_t_id_string =
359         TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, t_id_string,
360                 NULL);
361
362 cmdline_parse_token_string_t cmd_pipeline_disable_pipeline_string =
363         TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result,
364                 pipeline_string, "pipeline");
365
366 cmdline_parse_token_num_t cmd_pipeline_disable_pipeline_id =
367         TOKEN_NUM_INITIALIZER(struct cmd_pipeline_disable_result, pipeline_id,
368                 UINT32);
369
370 cmdline_parse_token_string_t cmd_pipeline_disable_disable_string =
371         TOKEN_STRING_INITIALIZER(struct cmd_pipeline_disable_result, disable_string,
372                 "disable");
373
374 cmdline_parse_inst_t cmd_pipeline_disable = {
375         .f = cmd_pipeline_disable_parsed,
376         .data = NULL,
377         .help_str = "Disable pipeline on specified core",
378         .tokens = {
379                 (void *)&cmd_pipeline_disable_t_string,
380                 (void *)&cmd_pipeline_disable_t_id_string,
381                 (void *)&cmd_pipeline_disable_pipeline_string,
382                 (void *)&cmd_pipeline_disable_pipeline_id,
383                 (void *)&cmd_pipeline_disable_disable_string,
384                 NULL,
385         },
386 };
387
388
389 /*
390  * thread headroom
391  */
392
393 struct cmd_thread_headroom_result {
394         cmdline_fixed_string_t t_string;
395         cmdline_fixed_string_t t_id_string;
396         cmdline_fixed_string_t headroom_string;
397 };
398
399 static void
400 cmd_thread_headroom_parsed(
401         void *parsed_result,
402         __rte_unused struct cmdline *cl,
403          void *data)
404 {
405         struct cmd_thread_headroom_result *params = parsed_result;
406         struct app_params *app = data;
407         int status;
408         uint32_t core_id, socket_id, hyper_th_id;
409
410         if (parse_pipeline_core(&socket_id,
411                         &core_id,
412                         &hyper_th_id,
413                         params->t_id_string) != 0) {
414                 printf("Command failed\n");
415                 return;
416         }
417
418         status = app_thread_headroom(app,
419                         socket_id,
420                         core_id,
421                         hyper_th_id);
422
423         if (status != 0)
424                 printf("Command failed\n");
425 }
426
427 cmdline_parse_token_string_t cmd_thread_headroom_t_string =
428         TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
429         t_string, "t");
430
431 cmdline_parse_token_string_t cmd_thread_headroom_t_id_string =
432         TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
433         t_id_string, NULL);
434
435 cmdline_parse_token_string_t cmd_thread_headroom_headroom_string =
436         TOKEN_STRING_INITIALIZER(struct cmd_thread_headroom_result,
437                 headroom_string, "headroom");
438
439 cmdline_parse_inst_t cmd_thread_headroom = {
440         .f = cmd_thread_headroom_parsed,
441         .data = NULL,
442         .help_str = "Display thread headroom",
443         .tokens = {
444                 (void *)&cmd_thread_headroom_t_string,
445                 (void *)&cmd_thread_headroom_t_id_string,
446                 (void *)&cmd_thread_headroom_headroom_string,
447                 NULL,
448         },
449 };
450
451
452 static cmdline_parse_ctx_t thread_cmds[] = {
453         (cmdline_parse_inst_t *) &cmd_pipeline_enable,
454         (cmdline_parse_inst_t *) &cmd_pipeline_disable,
455         (cmdline_parse_inst_t *) &cmd_thread_headroom,
456         NULL,
457 };
458
459 int
460 app_pipeline_thread_cmd_push(struct app_params *app)
461 {
462         uint32_t n_cmds, i;
463
464         /* Check for available slots in the application commands array */
465         n_cmds = RTE_DIM(thread_cmds) - 1;
466         if (n_cmds > APP_MAX_CMDS - app->n_cmds)
467                 return -ENOMEM;
468
469         /* Push thread commands into the application */
470         memcpy(&app->cmds[app->n_cmds], thread_cmds,
471                 n_cmds * sizeof(cmdline_parse_ctx_t));
472
473         for (i = 0; i < n_cmds; i++)
474                 app->cmds[app->n_cmds + i]->data = app;
475
476         app->n_cmds += n_cmds;
477         app->cmds[app->n_cmds] = NULL;
478
479         return 0;
480 }