examples/ip_pipeline: fix resource leak
[dpdk.git] / examples / ip_pipeline / pipeline / pipeline_flow_classification_be.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <string.h>
35
36 #include <rte_common.h>
37 #include <rte_malloc.h>
38 #include <rte_table_hash.h>
39 #include <rte_byteorder.h>
40 #include <pipeline.h>
41
42 #include "pipeline_flow_classification_be.h"
43 #include "hash_func.h"
44
45 struct pipeline_flow_classification {
46         struct pipeline p;
47         pipeline_msg_req_handler custom_handlers[PIPELINE_FC_MSG_REQS];
48
49         uint32_t n_flows;
50         uint32_t key_offset;
51         uint32_t key_size;
52         uint32_t hash_offset;
53         uint8_t *key_mask;
54 } __rte_cache_aligned;
55
56 static void *
57 pipeline_fc_msg_req_custom_handler(struct pipeline *p, void *msg);
58
59 static pipeline_msg_req_handler handlers[] = {
60         [PIPELINE_MSG_REQ_PING] =
61                 pipeline_msg_req_ping_handler,
62         [PIPELINE_MSG_REQ_STATS_PORT_IN] =
63                 pipeline_msg_req_stats_port_in_handler,
64         [PIPELINE_MSG_REQ_STATS_PORT_OUT] =
65                 pipeline_msg_req_stats_port_out_handler,
66         [PIPELINE_MSG_REQ_STATS_TABLE] =
67                 pipeline_msg_req_stats_table_handler,
68         [PIPELINE_MSG_REQ_PORT_IN_ENABLE] =
69                 pipeline_msg_req_port_in_enable_handler,
70         [PIPELINE_MSG_REQ_PORT_IN_DISABLE] =
71                 pipeline_msg_req_port_in_disable_handler,
72         [PIPELINE_MSG_REQ_CUSTOM] =
73                 pipeline_fc_msg_req_custom_handler,
74 };
75
76 static void *
77 pipeline_fc_msg_req_add_handler(struct pipeline *p, void *msg);
78
79 static void *
80 pipeline_fc_msg_req_add_bulk_handler(struct pipeline *p, void *msg);
81
82 static void *
83 pipeline_fc_msg_req_del_handler(struct pipeline *p, void *msg);
84
85 static void *
86 pipeline_fc_msg_req_add_default_handler(struct pipeline *p, void *msg);
87
88 static void *
89 pipeline_fc_msg_req_del_default_handler(struct pipeline *p, void *msg);
90
91 static pipeline_msg_req_handler custom_handlers[] = {
92         [PIPELINE_FC_MSG_REQ_FLOW_ADD] =
93                 pipeline_fc_msg_req_add_handler,
94         [PIPELINE_FC_MSG_REQ_FLOW_ADD_BULK] =
95                 pipeline_fc_msg_req_add_bulk_handler,
96         [PIPELINE_FC_MSG_REQ_FLOW_DEL] =
97                 pipeline_fc_msg_req_del_handler,
98         [PIPELINE_FC_MSG_REQ_FLOW_ADD_DEFAULT] =
99                 pipeline_fc_msg_req_add_default_handler,
100         [PIPELINE_FC_MSG_REQ_FLOW_DEL_DEFAULT] =
101                 pipeline_fc_msg_req_del_default_handler,
102 };
103
104 /*
105  * Flow table
106  */
107 struct flow_table_entry {
108         struct rte_pipeline_table_entry head;
109 };
110
111 rte_table_hash_op_hash hash_func[] = {
112         hash_default_key8,
113         hash_default_key16,
114         hash_default_key24,
115         hash_default_key32,
116         hash_default_key40,
117         hash_default_key48,
118         hash_default_key56,
119         hash_default_key64
120 };
121
122 static int
123 pipeline_fc_parse_args(struct pipeline_flow_classification *p,
124         struct pipeline_params *params)
125 {
126         uint32_t n_flows_present = 0;
127         uint32_t key_offset_present = 0;
128         uint32_t key_size_present = 0;
129         uint32_t hash_offset_present = 0;
130         uint32_t key_mask_present = 0;
131
132         uint32_t i;
133         char *key_mask_str = NULL;
134
135         p->hash_offset = 0;
136
137         for (i = 0; i < params->n_args; i++) {
138                 char *arg_name = params->args_name[i];
139                 char *arg_value = params->args_value[i];
140
141                 /* n_flows */
142                 if (strcmp(arg_name, "n_flows") == 0) {
143                         if (n_flows_present)
144                                 goto error_parse;
145                         n_flows_present = 1;
146
147                         p->n_flows = atoi(arg_value);
148                         if (p->n_flows == 0)
149                                 goto error_parse;
150
151                         continue;
152                 }
153
154                 /* key_offset */
155                 if (strcmp(arg_name, "key_offset") == 0) {
156                         if (key_offset_present)
157                                 goto error_parse;
158
159                         key_offset_present = 1;
160
161                         p->key_offset = atoi(arg_value);
162
163                         continue;
164                 }
165
166                 /* key_size */
167                 if (strcmp(arg_name, "key_size") == 0) {
168                         if (key_size_present)
169                                 goto error_parse;
170                         key_size_present = 1;
171
172                         p->key_size = atoi(arg_value);
173                         if ((p->key_size == 0) ||
174                                 (p->key_size > PIPELINE_FC_FLOW_KEY_MAX_SIZE) ||
175                                 (p->key_size % 8))
176                                 goto error_parse;
177
178                         continue;
179                 }
180
181                 /* key_mask */
182                 if (strcmp(arg_name, "key_mask") == 0) {
183                         if (key_mask_present)
184                                 goto error_parse;
185
186                         key_mask_str = strdup(arg_value);
187                         if (key_mask_str == NULL)
188                                 goto error_parse;
189
190                         key_mask_present = 1;
191
192                         continue;
193                 }
194
195                 /* hash_offset */
196                 if (strcmp(arg_name, "hash_offset") == 0) {
197                         if (hash_offset_present)
198                                 goto error_parse;
199                         hash_offset_present = 1;
200
201                         p->hash_offset = atoi(arg_value);
202
203                         continue;
204                 }
205
206                 /* Unknown argument */
207                 return -1;
208         }
209
210         /* Check that mandatory arguments are present */
211         if ((n_flows_present == 0) ||
212                 (key_offset_present == 0) ||
213                 (key_size_present == 0))
214                 goto error_parse;
215
216         if (key_mask_present) {
217                 p->key_mask = rte_malloc(NULL, p->key_size, 0);
218                 if (p->key_mask == NULL)
219                         goto error_parse;
220
221                 if (parse_hex_string(key_mask_str, p->key_mask, &p->key_size)
222                         != 0) {
223                         goto error_parse;
224                 }
225
226                 free(key_mask_str);
227         }
228
229         return 0;
230
231 error_parse:
232         if (key_mask_str != NULL)
233                 free(key_mask_str);
234         if (p->key_mask != NULL)
235                 free(p->key_mask);
236         return -1;
237 }
238
239 static void *pipeline_fc_init(struct pipeline_params *params,
240         __rte_unused void *arg)
241 {
242         struct pipeline *p;
243         struct pipeline_flow_classification *p_fc;
244         uint32_t size, i;
245
246         /* Check input arguments */
247         if (params == NULL)
248                 return NULL;
249
250         /* Memory allocation */
251         size = RTE_CACHE_LINE_ROUNDUP(
252                 sizeof(struct pipeline_flow_classification));
253         p = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
254         if (p == NULL)
255                 return NULL;
256         p_fc = (struct pipeline_flow_classification *) p;
257
258         strcpy(p->name, params->name);
259         p->log_level = params->log_level;
260
261         PLOG(p, HIGH, "Flow classification");
262
263         /* Parse arguments */
264         if (pipeline_fc_parse_args(p_fc, params))
265                 return NULL;
266
267         /* Pipeline */
268         {
269                 struct rte_pipeline_params pipeline_params = {
270                         .name = params->name,
271                         .socket_id = params->socket_id,
272                         .offset_port_id = 0,
273                 };
274
275                 p->p = rte_pipeline_create(&pipeline_params);
276                 if (p->p == NULL) {
277                         rte_free(p);
278                         return NULL;
279                 }
280         }
281
282         /* Input ports */
283         p->n_ports_in = params->n_ports_in;
284         for (i = 0; i < p->n_ports_in; i++) {
285                 struct rte_pipeline_port_in_params port_params = {
286                         .ops = pipeline_port_in_params_get_ops(
287                                 &params->port_in[i]),
288                         .arg_create = pipeline_port_in_params_convert(
289                                 &params->port_in[i]),
290                         .f_action = NULL,
291                         .arg_ah = NULL,
292                         .burst_size = params->port_in[i].burst_size,
293                 };
294
295                 int status = rte_pipeline_port_in_create(p->p,
296                         &port_params,
297                         &p->port_in_id[i]);
298
299                 if (status) {
300                         rte_pipeline_free(p->p);
301                         rte_free(p);
302                         return NULL;
303                 }
304         }
305
306         /* Output ports */
307         p->n_ports_out = params->n_ports_out;
308         for (i = 0; i < p->n_ports_out; i++) {
309                 struct rte_pipeline_port_out_params port_params = {
310                         .ops = pipeline_port_out_params_get_ops(
311                                 &params->port_out[i]),
312                         .arg_create = pipeline_port_out_params_convert(
313                                 &params->port_out[i]),
314                         .f_action = NULL,
315                         .f_action_bulk = NULL,
316                         .arg_ah = NULL,
317                 };
318
319                 int status = rte_pipeline_port_out_create(p->p,
320                         &port_params,
321                         &p->port_out_id[i]);
322
323                 if (status) {
324                         rte_pipeline_free(p->p);
325                         rte_free(p);
326                         return NULL;
327                 }
328         }
329
330         /* Tables */
331         p->n_tables = 1;
332         {
333                 struct rte_table_hash_key8_ext_params
334                         table_hash_key8_params = {
335                         .n_entries = p_fc->n_flows,
336                         .n_entries_ext = p_fc->n_flows,
337                         .signature_offset = p_fc->hash_offset,
338                         .key_offset = p_fc->key_offset,
339                         .f_hash = hash_func[(p_fc->key_size / 8) - 1],
340                         .key_mask = p_fc->key_mask,
341                         .seed = 0,
342                 };
343
344                 struct rte_table_hash_key16_ext_params
345                         table_hash_key16_params = {
346                         .n_entries = p_fc->n_flows,
347                         .n_entries_ext = p_fc->n_flows,
348                         .signature_offset = p_fc->hash_offset,
349                         .key_offset = p_fc->key_offset,
350                         .f_hash = hash_func[(p_fc->key_size / 8) - 1],
351                         .key_mask = p_fc->key_mask,
352                         .seed = 0,
353                 };
354
355                 struct rte_table_hash_ext_params
356                         table_hash_params = {
357                         .key_size = p_fc->key_size,
358                         .n_keys = p_fc->n_flows,
359                         .n_buckets = p_fc->n_flows / 4,
360                         .n_buckets_ext = p_fc->n_flows / 4,
361                         .f_hash = hash_func[(p_fc->key_size / 8) - 1],
362                         .seed = 0,
363                         .signature_offset = p_fc->hash_offset,
364                         .key_offset = p_fc->key_offset,
365                 };
366
367                 struct rte_pipeline_table_params table_params = {
368                         .ops = NULL, /* set below */
369                         .arg_create = NULL, /* set below */
370                         .f_action_hit = NULL,
371                         .f_action_miss = NULL,
372                         .arg_ah = NULL,
373                         .action_data_size = sizeof(struct flow_table_entry) -
374                                 sizeof(struct rte_pipeline_table_entry),
375                 };
376
377                 int status;
378
379                 switch (p_fc->key_size) {
380                 case 8:
381                         if (p_fc->hash_offset != 0) {
382                                 table_params.ops =
383                                         &rte_table_hash_key8_ext_ops;
384                         } else {
385                                 table_params.ops =
386                                         &rte_table_hash_key8_ext_dosig_ops;
387                         }
388                         table_params.arg_create = &table_hash_key8_params;
389                         break;
390                         break;
391
392                 case 16:
393                         if (p_fc->hash_offset != 0) {
394                                 table_params.ops =
395                                         &rte_table_hash_key16_ext_ops;
396                         } else {
397                                 table_params.ops =
398                                         &rte_table_hash_key16_ext_dosig_ops;
399                         }
400                         table_params.arg_create = &table_hash_key16_params;
401                         break;
402
403                 default:
404                         table_params.ops = &rte_table_hash_ext_ops;
405                         table_params.arg_create = &table_hash_params;
406                 }
407
408                 status = rte_pipeline_table_create(p->p,
409                         &table_params,
410                         &p->table_id[0]);
411
412                 if (status) {
413                         rte_pipeline_free(p->p);
414                         rte_free(p);
415                         return NULL;
416                 }
417         }
418
419         /* Connecting input ports to tables */
420         for (i = 0; i < p->n_ports_in; i++) {
421                 int status = rte_pipeline_port_in_connect_to_table(p->p,
422                         p->port_in_id[i],
423                         p->table_id[0]);
424
425                 if (status) {
426                         rte_pipeline_free(p->p);
427                         rte_free(p);
428                         return NULL;
429                 }
430         }
431
432         /* Enable input ports */
433         for (i = 0; i < p->n_ports_in; i++) {
434                 int status = rte_pipeline_port_in_enable(p->p,
435                         p->port_in_id[i]);
436
437                 if (status) {
438                         rte_pipeline_free(p->p);
439                         rte_free(p);
440                         return NULL;
441                 }
442         }
443
444         /* Check pipeline consistency */
445         if (rte_pipeline_check(p->p) < 0) {
446                 rte_pipeline_free(p->p);
447                 rte_free(p);
448                 return NULL;
449         }
450
451         /* Message queues */
452         p->n_msgq = params->n_msgq;
453         for (i = 0; i < p->n_msgq; i++)
454                 p->msgq_in[i] = params->msgq_in[i];
455         for (i = 0; i < p->n_msgq; i++)
456                 p->msgq_out[i] = params->msgq_out[i];
457
458         /* Message handlers */
459         memcpy(p->handlers, handlers, sizeof(p->handlers));
460         memcpy(p_fc->custom_handlers,
461                 custom_handlers,
462                 sizeof(p_fc->custom_handlers));
463
464         return p;
465 }
466
467 static int
468 pipeline_fc_free(void *pipeline)
469 {
470         struct pipeline *p = (struct pipeline *) pipeline;
471
472         /* Check input arguments */
473         if (p == NULL)
474                 return -1;
475
476         /* Free resources */
477         rte_pipeline_free(p->p);
478         rte_free(p);
479         return 0;
480 }
481
482 static int
483 pipeline_fc_track(void *pipeline,
484         __rte_unused uint32_t port_in,
485         uint32_t *port_out)
486 {
487         struct pipeline *p = (struct pipeline *) pipeline;
488
489         /* Check input arguments */
490         if ((p == NULL) ||
491                 (port_in >= p->n_ports_in) ||
492                 (port_out == NULL))
493                 return -1;
494
495         if (p->n_ports_in == 1) {
496                 *port_out = 0;
497                 return 0;
498         }
499
500         return -1;
501 }
502
503 static int
504 pipeline_fc_timer(void *pipeline)
505 {
506         struct pipeline *p = (struct pipeline *) pipeline;
507
508         pipeline_msg_req_handle(p);
509         rte_pipeline_flush(p->p);
510
511         return 0;
512 }
513
514 static void *
515 pipeline_fc_msg_req_custom_handler(struct pipeline *p, void *msg)
516 {
517         struct pipeline_flow_classification *p_fc =
518                         (struct pipeline_flow_classification *) p;
519         struct pipeline_custom_msg_req *req = msg;
520         pipeline_msg_req_handler f_handle;
521
522         f_handle = (req->subtype < PIPELINE_FC_MSG_REQS) ?
523                 p_fc->custom_handlers[req->subtype] :
524                 pipeline_msg_req_invalid_handler;
525
526         if (f_handle == NULL)
527                 f_handle = pipeline_msg_req_invalid_handler;
528
529         return f_handle(p, req);
530 }
531
532 static void *
533 pipeline_fc_msg_req_add_handler(struct pipeline *p, void *msg)
534 {
535         struct pipeline_fc_add_msg_req *req = msg;
536         struct pipeline_fc_add_msg_rsp *rsp = msg;
537
538         struct flow_table_entry entry = {
539                 .head = {
540                         .action = RTE_PIPELINE_ACTION_PORT,
541                         {.port_id = p->port_out_id[req->port_id]},
542                 },
543         };
544
545         rsp->status = rte_pipeline_table_entry_add(p->p,
546                 p->table_id[0],
547                 &req->key,
548                 (struct rte_pipeline_table_entry *) &entry,
549                 &rsp->key_found,
550                 (struct rte_pipeline_table_entry **) &rsp->entry_ptr);
551
552         return rsp;
553 }
554
555 static void *
556 pipeline_fc_msg_req_add_bulk_handler(struct pipeline *p, void *msg)
557 {
558         struct pipeline_fc_add_bulk_msg_req *req = msg;
559         struct pipeline_fc_add_bulk_msg_rsp *rsp = msg;
560         uint32_t i;
561
562         for (i = 0; i < req->n_keys; i++) {
563                 struct pipeline_fc_add_bulk_flow_req *flow_req = &req->req[i];
564                 struct pipeline_fc_add_bulk_flow_rsp *flow_rsp = &req->rsp[i];
565
566                 struct flow_table_entry entry = {
567                         .head = {
568                                 .action = RTE_PIPELINE_ACTION_PORT,
569                                 {.port_id = p->port_out_id[flow_req->port_id]},
570                         },
571                 };
572
573                 int status = rte_pipeline_table_entry_add(p->p,
574                         p->table_id[0],
575                         &flow_req->key,
576                         (struct rte_pipeline_table_entry *) &entry,
577                         &flow_rsp->key_found,
578                         (struct rte_pipeline_table_entry **)
579                                 &flow_rsp->entry_ptr);
580
581                 if (status)
582                         break;
583         }
584
585         rsp->n_keys = i;
586
587         return rsp;
588 }
589
590 static void *
591 pipeline_fc_msg_req_del_handler(struct pipeline *p, void *msg)
592 {
593         struct pipeline_fc_del_msg_req *req = msg;
594         struct pipeline_fc_del_msg_rsp *rsp = msg;
595
596         rsp->status = rte_pipeline_table_entry_delete(p->p,
597                 p->table_id[0],
598                 &req->key,
599                 &rsp->key_found,
600                 NULL);
601
602         return rsp;
603 }
604
605 static void *
606 pipeline_fc_msg_req_add_default_handler(struct pipeline *p, void *msg)
607 {
608         struct pipeline_fc_add_default_msg_req *req = msg;
609         struct pipeline_fc_add_default_msg_rsp *rsp = msg;
610
611         struct flow_table_entry default_entry = {
612                 .head = {
613                         .action = RTE_PIPELINE_ACTION_PORT,
614                         {.port_id = p->port_out_id[req->port_id]},
615                 },
616         };
617
618         rsp->status = rte_pipeline_table_default_entry_add(p->p,
619                 p->table_id[0],
620                 (struct rte_pipeline_table_entry *) &default_entry,
621                 (struct rte_pipeline_table_entry **) &rsp->entry_ptr);
622
623         return rsp;
624 }
625
626 static void *
627 pipeline_fc_msg_req_del_default_handler(struct pipeline *p, void *msg)
628 {
629         struct pipeline_fc_del_default_msg_rsp *rsp = msg;
630
631         rsp->status = rte_pipeline_table_default_entry_delete(p->p,
632                 p->table_id[0],
633                 NULL);
634
635         return rsp;
636 }
637
638 struct pipeline_be_ops pipeline_flow_classification_be_ops = {
639         .f_init = pipeline_fc_init,
640         .f_free = pipeline_fc_free,
641         .f_run = NULL,
642         .f_timer = pipeline_fc_timer,
643         .f_track = pipeline_fc_track,
644 };