net: add rte prefix to IP defines
[dpdk.git] / app / test / test_table_acl.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4
5 #include <rte_string_fns.h>
6 #include <rte_hexdump.h>
7 #include "test_table.h"
8 #include "test_table_acl.h"
9
10 #define RTE_IPv4(a, b, c, d) ((uint32_t)(((a) & 0xff) << 24) |          \
11         (((b) & 0xff) << 16) |                                          \
12         (((c) & 0xff) << 8) |                                           \
13         ((d) & 0xff))
14
15 /*
16  * Rule and trace formats definitions.
17  **/
18
19 struct ipv4_5tuple {
20         uint8_t  proto;
21         uint32_t ip_src;
22         uint32_t ip_dst;
23         uint16_t port_src;
24         uint16_t port_dst;
25 };
26
27 enum {
28         PROTO_FIELD_IPV4,
29         SRC_FIELD_IPV4,
30         DST_FIELD_IPV4,
31         SRCP_FIELD_IPV4,
32         DSTP_FIELD_IPV4,
33         NUM_FIELDS_IPV4
34 };
35
36 struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
37         {
38                 .type = RTE_ACL_FIELD_TYPE_BITMASK,
39                 .size = sizeof(uint8_t),
40                 .field_index = PROTO_FIELD_IPV4,
41                 .input_index = PROTO_FIELD_IPV4,
42                 .offset = offsetof(struct ipv4_5tuple, proto),
43         },
44         {
45                 .type = RTE_ACL_FIELD_TYPE_MASK,
46                 .size = sizeof(uint32_t),
47                 .field_index = SRC_FIELD_IPV4,
48                 .input_index = SRC_FIELD_IPV4,
49                 .offset = offsetof(struct ipv4_5tuple, ip_src),
50         },
51         {
52                 .type = RTE_ACL_FIELD_TYPE_MASK,
53                 .size = sizeof(uint32_t),
54                 .field_index = DST_FIELD_IPV4,
55                 .input_index = DST_FIELD_IPV4,
56                 .offset = offsetof(struct ipv4_5tuple, ip_dst),
57         },
58         {
59                 .type = RTE_ACL_FIELD_TYPE_RANGE,
60                 .size = sizeof(uint16_t),
61                 .field_index = SRCP_FIELD_IPV4,
62                 .input_index = SRCP_FIELD_IPV4,
63                 .offset = offsetof(struct ipv4_5tuple, port_src),
64         },
65         {
66                 .type = RTE_ACL_FIELD_TYPE_RANGE,
67                 .size = sizeof(uint16_t),
68                 .field_index = DSTP_FIELD_IPV4,
69                 .input_index = SRCP_FIELD_IPV4,
70                 .offset = offsetof(struct ipv4_5tuple, port_dst),
71         },
72 };
73
74 struct rte_table_acl_rule_add_params table_acl_IPv4_rule;
75
76 typedef int (*parse_5tuple)(char *text,
77         struct rte_table_acl_rule_add_params *rule);
78
79 /*
80 * The order of the fields in the rule string after the initial '@'
81 */
82 enum {
83         CB_FLD_SRC_ADDR,
84         CB_FLD_DST_ADDR,
85         CB_FLD_SRC_PORT_RANGE,
86         CB_FLD_DST_PORT_RANGE,
87         CB_FLD_PROTO,
88         CB_FLD_NUM,
89 };
90
91
92 #define GET_CB_FIELD(in, fd, base, lim, dlm)                            \
93 do {                                                                    \
94         unsigned long val;                                              \
95         char *end;                                                      \
96                                                                         \
97         errno = 0;                                                      \
98         val = strtoul((in), &end, (base));                              \
99         if (errno != 0 || end[0] != (dlm) || val > (lim))               \
100                 return -EINVAL;                                         \
101         (fd) = (typeof(fd)) val;                                        \
102         (in) = end + 1;                                                 \
103 } while (0)
104
105
106
107
108 static int
109 parse_ipv4_net(const char *in, uint32_t *addr, uint32_t *mask_len)
110 {
111         uint8_t a, b, c, d, m;
112
113         GET_CB_FIELD(in, a, 0, UINT8_MAX, '.');
114         GET_CB_FIELD(in, b, 0, UINT8_MAX, '.');
115         GET_CB_FIELD(in, c, 0, UINT8_MAX, '.');
116         GET_CB_FIELD(in, d, 0, UINT8_MAX, '/');
117         GET_CB_FIELD(in, m, 0, sizeof(uint32_t) * CHAR_BIT, 0);
118
119         addr[0] = RTE_IPv4(a, b, c, d);
120         mask_len[0] = m;
121
122         return 0;
123 }
124
125 static int
126 parse_port_range(const char *in, uint16_t *port_low, uint16_t *port_high)
127 {
128         uint16_t a, b;
129
130         GET_CB_FIELD(in, a, 0, UINT16_MAX, ':');
131         GET_CB_FIELD(in, b, 0, UINT16_MAX, 0);
132
133         port_low[0] = a;
134         port_high[0] = b;
135
136         return 0;
137 }
138
139 static int
140 parse_cb_ipv4_rule(char *str, struct rte_table_acl_rule_add_params *v)
141 {
142         int i, rc;
143         char *s, *sp, *in[CB_FLD_NUM];
144         static const char *dlm = " \t\n";
145
146         /*
147         ** Skip leading '@'
148         */
149         if (strchr(str, '@') != str)
150                 return -EINVAL;
151
152         s = str + 1;
153
154         /*
155         * Populate the 'in' array with the location of each
156         * field in the string we're parsing
157         */
158         for (i = 0; i != DIM(in); i++) {
159                 in[i] = strtok_r(s, dlm, &sp);
160                 if (in[i] == NULL)
161                         return -EINVAL;
162                 s = NULL;
163         }
164
165         /* Parse x.x.x.x/x */
166         rc = parse_ipv4_net(in[CB_FLD_SRC_ADDR],
167                 &v->field_value[SRC_FIELD_IPV4].value.u32,
168                 &v->field_value[SRC_FIELD_IPV4].mask_range.u32);
169         if (rc != 0) {
170                 RTE_LOG(ERR, PIPELINE, "failed to read src address/mask: %s\n",
171                         in[CB_FLD_SRC_ADDR]);
172                 return rc;
173         }
174
175         printf("V=%u, mask=%u\n", v->field_value[SRC_FIELD_IPV4].value.u32,
176                 v->field_value[SRC_FIELD_IPV4].mask_range.u32);
177
178         /* Parse x.x.x.x/x */
179         rc = parse_ipv4_net(in[CB_FLD_DST_ADDR],
180                 &v->field_value[DST_FIELD_IPV4].value.u32,
181                 &v->field_value[DST_FIELD_IPV4].mask_range.u32);
182         if (rc != 0) {
183                 RTE_LOG(ERR, PIPELINE, "failed to read dest address/mask: %s\n",
184                         in[CB_FLD_DST_ADDR]);
185                 return rc;
186         }
187
188         printf("V=%u, mask=%u\n", v->field_value[DST_FIELD_IPV4].value.u32,
189         v->field_value[DST_FIELD_IPV4].mask_range.u32);
190         /* Parse n:n */
191         rc = parse_port_range(in[CB_FLD_SRC_PORT_RANGE],
192                 &v->field_value[SRCP_FIELD_IPV4].value.u16,
193                 &v->field_value[SRCP_FIELD_IPV4].mask_range.u16);
194         if (rc != 0) {
195                 RTE_LOG(ERR, PIPELINE, "failed to read source port range: %s\n",
196                         in[CB_FLD_SRC_PORT_RANGE]);
197                 return rc;
198         }
199
200         printf("V=%u, mask=%u\n", v->field_value[SRCP_FIELD_IPV4].value.u16,
201                 v->field_value[SRCP_FIELD_IPV4].mask_range.u16);
202         /* Parse n:n */
203         rc = parse_port_range(in[CB_FLD_DST_PORT_RANGE],
204                 &v->field_value[DSTP_FIELD_IPV4].value.u16,
205                 &v->field_value[DSTP_FIELD_IPV4].mask_range.u16);
206         if (rc != 0) {
207                 RTE_LOG(ERR, PIPELINE, "failed to read dest port range: %s\n",
208                         in[CB_FLD_DST_PORT_RANGE]);
209                 return rc;
210         }
211
212         printf("V=%u, mask=%u\n", v->field_value[DSTP_FIELD_IPV4].value.u16,
213                 v->field_value[DSTP_FIELD_IPV4].mask_range.u16);
214         /* parse 0/0xnn */
215         GET_CB_FIELD(in[CB_FLD_PROTO],
216                 v->field_value[PROTO_FIELD_IPV4].value.u8,
217                 0, UINT8_MAX, '/');
218         GET_CB_FIELD(in[CB_FLD_PROTO],
219                 v->field_value[PROTO_FIELD_IPV4].mask_range.u8,
220                 0, UINT8_MAX, 0);
221
222         printf("V=%u, mask=%u\n",
223                 (unsigned int)v->field_value[PROTO_FIELD_IPV4].value.u8,
224                 v->field_value[PROTO_FIELD_IPV4].mask_range.u8);
225         return 0;
226 }
227
228 static int
229 parse_cb_ipv4_rule_del(char *str, struct rte_table_acl_rule_delete_params *v)
230 {
231         int i, rc;
232         char *s, *sp, *in[CB_FLD_NUM];
233         static const char *dlm = " \t\n";
234
235         /*
236         ** Skip leading '@'
237         */
238         if (strchr(str, '@') != str)
239                 return -EINVAL;
240
241         s = str + 1;
242
243         /*
244         * Populate the 'in' array with the location of each
245         * field in the string we're parsing
246         */
247         for (i = 0; i != DIM(in); i++) {
248                 in[i] = strtok_r(s, dlm, &sp);
249                 if (in[i] == NULL)
250                         return -EINVAL;
251                 s = NULL;
252         }
253
254         /* Parse x.x.x.x/x */
255         rc = parse_ipv4_net(in[CB_FLD_SRC_ADDR],
256                 &v->field_value[SRC_FIELD_IPV4].value.u32,
257                 &v->field_value[SRC_FIELD_IPV4].mask_range.u32);
258         if (rc != 0) {
259                 RTE_LOG(ERR, PIPELINE, "failed to read src address/mask: %s\n",
260                         in[CB_FLD_SRC_ADDR]);
261                 return rc;
262         }
263
264         printf("V=%u, mask=%u\n", v->field_value[SRC_FIELD_IPV4].value.u32,
265                 v->field_value[SRC_FIELD_IPV4].mask_range.u32);
266
267         /* Parse x.x.x.x/x */
268         rc = parse_ipv4_net(in[CB_FLD_DST_ADDR],
269                 &v->field_value[DST_FIELD_IPV4].value.u32,
270                 &v->field_value[DST_FIELD_IPV4].mask_range.u32);
271         if (rc != 0) {
272                 RTE_LOG(ERR, PIPELINE, "failed to read dest address/mask: %s\n",
273                         in[CB_FLD_DST_ADDR]);
274                 return rc;
275         }
276
277         printf("V=%u, mask=%u\n", v->field_value[DST_FIELD_IPV4].value.u32,
278         v->field_value[DST_FIELD_IPV4].mask_range.u32);
279         /* Parse n:n */
280         rc = parse_port_range(in[CB_FLD_SRC_PORT_RANGE],
281                 &v->field_value[SRCP_FIELD_IPV4].value.u16,
282                 &v->field_value[SRCP_FIELD_IPV4].mask_range.u16);
283         if (rc != 0) {
284                 RTE_LOG(ERR, PIPELINE, "failed to read source port range: %s\n",
285                         in[CB_FLD_SRC_PORT_RANGE]);
286                 return rc;
287         }
288
289         printf("V=%u, mask=%u\n", v->field_value[SRCP_FIELD_IPV4].value.u16,
290                 v->field_value[SRCP_FIELD_IPV4].mask_range.u16);
291         /* Parse n:n */
292         rc = parse_port_range(in[CB_FLD_DST_PORT_RANGE],
293                 &v->field_value[DSTP_FIELD_IPV4].value.u16,
294                 &v->field_value[DSTP_FIELD_IPV4].mask_range.u16);
295         if (rc != 0) {
296                 RTE_LOG(ERR, PIPELINE, "failed to read dest port range: %s\n",
297                         in[CB_FLD_DST_PORT_RANGE]);
298                 return rc;
299         }
300
301         printf("V=%u, mask=%u\n", v->field_value[DSTP_FIELD_IPV4].value.u16,
302                 v->field_value[DSTP_FIELD_IPV4].mask_range.u16);
303         /* parse 0/0xnn */
304         GET_CB_FIELD(in[CB_FLD_PROTO],
305                 v->field_value[PROTO_FIELD_IPV4].value.u8,
306                 0, UINT8_MAX, '/');
307         GET_CB_FIELD(in[CB_FLD_PROTO],
308                 v->field_value[PROTO_FIELD_IPV4].mask_range.u8,
309                 0, UINT8_MAX, 0);
310
311         printf("V=%u, mask=%u\n",
312                 (unsigned int)v->field_value[PROTO_FIELD_IPV4].value.u8,
313                 v->field_value[PROTO_FIELD_IPV4].mask_range.u8);
314         return 0;
315 }
316
317 /*
318  * The format for these rules DO NOT need the port ranges to be
319  * separated by ' : ', just ':'. It's a lot more readable and
320  * cleaner, IMO.
321  */
322 char lines[][128] = {
323         "@0.0.0.0/0 0.0.0.0/0 0:65535 0:65535 2/0xff", /* Protocol check */
324         "@192.168.3.1/32 0.0.0.0/0 0:65535 0:65535 0/0", /* Src IP checl */
325         "@0.0.0.0/0 10.4.4.1/32 0:65535 0:65535 0/0", /* dst IP check */
326         "@0.0.0.0/0 0.0.0.0/0 105:105 0:65535 0/0", /* src port check */
327         "@0.0.0.0/0 0.0.0.0/0 0:65535 206:206 0/0", /* dst port check */
328 };
329
330 char line[128];
331
332
333 static int
334 setup_acl_pipeline(void)
335 {
336         int ret;
337         int i;
338         struct rte_pipeline_params pipeline_params = {
339                 .name = "PIPELINE",
340                 .socket_id = 0,
341         };
342         uint32_t n;
343         struct rte_table_acl_rule_add_params rule_params;
344         struct rte_pipeline_table_acl_rule_delete_params *delete_params;
345         parse_5tuple parser;
346         char acl_name[64];
347
348         /* Pipeline configuration */
349         p = rte_pipeline_create(&pipeline_params);
350         if (p == NULL) {
351                 RTE_LOG(INFO, PIPELINE, "%s: Failed to configure pipeline\n",
352                         __func__);
353                 goto fail;
354         }
355
356         /* Input port configuration */
357         for (i = 0; i < N_PORTS; i++) {
358                 struct rte_port_ring_reader_params port_ring_params = {
359                         .ring = rings_rx[i],
360                 };
361
362                 struct rte_pipeline_port_in_params port_params = {
363                         .ops = &rte_port_ring_reader_ops,
364                         .arg_create = (void *) &port_ring_params,
365                         .f_action = NULL,
366                         .burst_size = BURST_SIZE,
367                 };
368
369                 /* Put in action for some ports */
370                 if (i)
371                         port_params.f_action = port_in_action;
372
373                 ret = rte_pipeline_port_in_create(p, &port_params,
374                         &port_in_id[i]);
375                 if (ret) {
376                         rte_panic("Unable to configure input port %d, ret:%d\n",
377                                 i, ret);
378                         goto fail;
379                 }
380         }
381
382         /* output Port configuration */
383         for (i = 0; i < N_PORTS; i++) {
384                 struct rte_port_ring_writer_params port_ring_params = {
385                         .ring = rings_tx[i],
386                         .tx_burst_sz = BURST_SIZE,
387                 };
388
389                 struct rte_pipeline_port_out_params port_params = {
390                         .ops = &rte_port_ring_writer_ops,
391                         .arg_create = (void *) &port_ring_params,
392                         .f_action = NULL,
393                         .arg_ah = NULL,
394                 };
395
396
397                 if (rte_pipeline_port_out_create(p, &port_params,
398                         &port_out_id[i])) {
399                         rte_panic("Unable to configure output port %d\n", i);
400                         goto fail;
401                 }
402         }
403
404         /* Table configuration  */
405         for (i = 0; i < N_PORTS; i++) {
406                 struct rte_pipeline_table_params table_params;
407
408                 /* Set up defaults for stub */
409                 table_params.ops = &rte_table_stub_ops;
410                 table_params.arg_create = NULL;
411                 table_params.f_action_hit = action_handler_hit;
412                 table_params.f_action_miss = NULL;
413                 table_params.action_data_size = 0;
414
415                 RTE_LOG(INFO, PIPELINE, "miss_action=%x\n",
416                         table_entry_miss_action);
417
418                 printf("RTE_ACL_RULE_SZ(%zu) = %zu\n", DIM(ipv4_defs),
419                         RTE_ACL_RULE_SZ(DIM(ipv4_defs)));
420
421                 struct rte_table_acl_params acl_params;
422
423                 acl_params.n_rules = 1 << 5;
424                 acl_params.n_rule_fields = DIM(ipv4_defs);
425                 snprintf(acl_name, sizeof(acl_name), "ACL%d", i);
426                 acl_params.name = acl_name;
427                 memcpy(acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
428
429                 table_params.ops = &rte_table_acl_ops;
430                 table_params.arg_create = &acl_params;
431
432                 if (rte_pipeline_table_create(p, &table_params, &table_id[i])) {
433                         rte_panic("Unable to configure table %u\n", i);
434                         goto fail;
435                 }
436
437                 if (connect_miss_action_to_table) {
438                         if (rte_pipeline_table_create(p, &table_params,
439                                 &table_id[i+2])) {
440                                 rte_panic("Unable to configure table %u\n", i);
441                                 goto fail;
442                         }
443                 }
444         }
445
446         for (i = 0; i < N_PORTS; i++) {
447                 if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
448                         table_id[i])) {
449                         rte_panic("Unable to connect input port %u to "
450                                 "table %u\n",
451                                 port_in_id[i],  table_id[i]);
452                         goto fail;
453                 }
454         }
455
456         /* Add bulk entries to tables */
457         for (i = 0; i < N_PORTS; i++) {
458                 struct rte_table_acl_rule_add_params keys[5];
459                 struct rte_pipeline_table_entry entries[5];
460                 struct rte_table_acl_rule_add_params *key_array[5];
461                 struct rte_pipeline_table_entry *table_entries[5];
462                 int key_found[5];
463                 struct rte_pipeline_table_entry *table_entries_ptr[5];
464                 struct rte_pipeline_table_entry entries_ptr[5];
465
466                 parser = parse_cb_ipv4_rule;
467                 for (n = 0; n < 5; n++) {
468                         memset(&keys[n], 0, sizeof(struct rte_table_acl_rule_add_params));
469                         key_array[n] = &keys[n];
470
471                         strlcpy(line, lines[n], sizeof(line));
472                         printf("PARSING [%s]\n", line);
473
474                         ret = parser(line, &keys[n]);
475                         if (ret != 0) {
476                                 RTE_LOG(ERR, PIPELINE,
477                                         "line %u: parse_cb_ipv4vlan_rule"
478                                         " failed, error code: %d (%s)\n",
479                                         n, ret, strerror(-ret));
480                                 return ret;
481                         }
482
483                         keys[n].priority = RTE_ACL_MAX_PRIORITY - n - 1;
484
485                         entries[n].action = RTE_PIPELINE_ACTION_PORT;
486                         entries[n].port_id = port_out_id[i^1];
487                         table_entries[n] = &entries[n];
488                         table_entries_ptr[n] = &entries_ptr[n];
489                 }
490
491                 ret = rte_pipeline_table_entry_add_bulk(p, table_id[i],
492                                 (void **)key_array, table_entries, 5, key_found, table_entries_ptr);
493                 if (ret < 0) {
494                         rte_panic("Add entry bulk to table %u failed (%d)\n",
495                                 table_id[i], ret);
496                         goto fail;
497                 }
498         }
499
500         /* Delete bulk entries from tables */
501         for (i = 0; i < N_PORTS; i++) {
502                 struct rte_table_acl_rule_delete_params keys[5];
503                 struct rte_table_acl_rule_delete_params *key_array[5];
504                 struct rte_pipeline_table_entry *table_entries[5];
505                 int key_found[5];
506
507                 memset(table_entries, 0, sizeof(table_entries));
508
509                 for (n = 0; n < 5; n++) {
510                         memset(&keys[n], 0, sizeof(struct rte_table_acl_rule_delete_params));
511                         key_array[n] = &keys[n];
512
513                         strlcpy(line, lines[n], sizeof(line));
514                         printf("PARSING [%s]\n", line);
515
516                         ret = parse_cb_ipv4_rule_del(line, &keys[n]);
517                         if (ret != 0) {
518                                 RTE_LOG(ERR, PIPELINE,
519                                         "line %u: parse_cb_ipv4vlan_rule"
520                                         " failed, error code: %d (%s)\n",
521                                         n, ret, strerror(-ret));
522                                 return ret;
523                         }
524                 }
525
526                 ret = rte_pipeline_table_entry_delete_bulk(p, table_id[i],
527                         (void **)key_array, 5, key_found, table_entries);
528                 if (ret < 0) {
529                         rte_panic("Delete bulk entries from table %u failed (%d)\n",
530                                 table_id[i], ret);
531                         goto fail;
532                 } else
533                         printf("Bulk deleted rules.\n");
534         }
535
536         /* Add entries to tables */
537         for (i = 0; i < N_PORTS; i++) {
538                 struct rte_pipeline_table_entry table_entry = {
539                         .action = RTE_PIPELINE_ACTION_PORT,
540                         {.port_id = port_out_id[i^1]},
541                 };
542                 int key_found;
543                 struct rte_pipeline_table_entry *entry_ptr;
544
545                 memset(&rule_params, 0, sizeof(rule_params));
546                 parser = parse_cb_ipv4_rule;
547
548                 for (n = 1; n <= 5; n++) {
549                         strlcpy(line, lines[n - 1], sizeof(line));
550                         printf("PARSING [%s]\n", line);
551
552                         ret = parser(line, &rule_params);
553                         if (ret != 0) {
554                                 RTE_LOG(ERR, PIPELINE,
555                                         "line %u: parse_cb_ipv4vlan_rule"
556                                         " failed, error code: %d (%s)\n",
557                                         n, ret, strerror(-ret));
558                                 return ret;
559                         }
560
561                         rule_params.priority = RTE_ACL_MAX_PRIORITY - n;
562
563                         ret = rte_pipeline_table_entry_add(p, table_id[i],
564                                 &rule_params,
565                                 &table_entry, &key_found, &entry_ptr);
566                         if (ret < 0) {
567                                 rte_panic("Add entry to table %u failed (%d)\n",
568                                         table_id[i], ret);
569                                 goto fail;
570                         }
571                 }
572
573                 /* delete a few rules */
574                 for (n = 2; n <= 3; n++) {
575                         strlcpy(line, lines[n - 1], sizeof(line));
576                         printf("PARSING [%s]\n", line);
577
578                         ret = parser(line, &rule_params);
579                         if (ret != 0) {
580                                 RTE_LOG(ERR, PIPELINE, "line %u: parse rule "
581                                         " failed, error code: %d (%s)\n",
582                                         n, ret, strerror(-ret));
583                                 return ret;
584                         }
585
586                         delete_params = (struct
587                                 rte_pipeline_table_acl_rule_delete_params *)
588                                 &(rule_params.field_value[0]);
589                         ret = rte_pipeline_table_entry_delete(p, table_id[i],
590                                 delete_params, &key_found, NULL);
591                         if (ret < 0) {
592                                 rte_panic("Add entry to table %u failed (%d)\n",
593                                         table_id[i], ret);
594                                 goto fail;
595                         } else
596                                 printf("Deleted Rule.\n");
597                 }
598
599
600                 /* Try to add duplicates */
601                 for (n = 1; n <= 5; n++) {
602                         strlcpy(line, lines[n - 1], sizeof(line));
603                         printf("PARSING [%s]\n", line);
604
605                         ret = parser(line, &rule_params);
606                         if (ret != 0) {
607                                 RTE_LOG(ERR, PIPELINE, "line %u: parse rule"
608                                         " failed, error code: %d (%s)\n",
609                                         n, ret, strerror(-ret));
610                                 return ret;
611                         }
612
613                         rule_params.priority = RTE_ACL_MAX_PRIORITY - n;
614
615                         ret = rte_pipeline_table_entry_add(p, table_id[i],
616                                 &rule_params,
617                                 &table_entry, &key_found, &entry_ptr);
618                         if (ret < 0) {
619                                 rte_panic("Add entry to table %u failed (%d)\n",
620                                         table_id[i], ret);
621                                 goto fail;
622                         }
623                 }
624         }
625
626         /* Enable input ports */
627         for (i = 0; i < N_PORTS ; i++)
628                 if (rte_pipeline_port_in_enable(p, port_in_id[i]))
629                         rte_panic("Unable to enable input port %u\n",
630                                 port_in_id[i]);
631
632         /* Check pipeline consistency */
633         if (rte_pipeline_check(p) < 0) {
634                 rte_panic("Pipeline consistency check failed\n");
635                 goto fail;
636         }
637
638         return  0;
639 fail:
640
641         return -1;
642 }
643
644 static int
645 test_pipeline_single_filter(int expected_count)
646 {
647         int i, j, ret, tx_count;
648         struct ipv4_5tuple five_tuple;
649
650         /* Allocate a few mbufs and manually insert into the rings. */
651         for (i = 0; i < N_PORTS; i++) {
652                 for (j = 0; j < 8; j++) {
653                         struct rte_mbuf *mbuf;
654
655                         mbuf = rte_pktmbuf_alloc(pool);
656                         if (mbuf == NULL)
657                                 /* this will cause test failure after cleanup
658                                  * of already enqueued mbufs, as the mbuf
659                                  * counts won't match */
660                                 break;
661                         memset(rte_pktmbuf_mtod(mbuf, char *), 0x00,
662                                 sizeof(struct ipv4_5tuple));
663
664                         five_tuple.proto = j;
665                         five_tuple.ip_src = rte_bswap32(RTE_IPv4(192, 168, j, 1));
666                         five_tuple.ip_dst = rte_bswap32(RTE_IPv4(10, 4, j, 1));
667                         five_tuple.port_src = rte_bswap16(100 + j);
668                         five_tuple.port_dst = rte_bswap16(200 + j);
669
670                         memcpy(rte_pktmbuf_mtod(mbuf, char *), &five_tuple,
671                                 sizeof(struct ipv4_5tuple));
672                         RTE_LOG(INFO, PIPELINE, "%s: Enqueue onto ring %d\n",
673                                 __func__, i);
674                         rte_ring_enqueue(rings_rx[i], mbuf);
675                 }
676         }
677
678         /* Run pipeline once */
679         for (i = 0; i< N_PORTS; i++)
680                 rte_pipeline_run(p);
681
682         rte_pipeline_flush(p);
683
684         tx_count = 0;
685
686         for (i = 0; i < N_PORTS; i++) {
687                 void *objs[RING_TX_SIZE];
688                 struct rte_mbuf *mbuf;
689
690                 ret = rte_ring_sc_dequeue_burst(rings_tx[i], objs, 10, NULL);
691                 if (ret <= 0) {
692                         printf("Got no objects from ring %d - error code %d\n",
693                                 i, ret);
694                 } else {
695                         printf("Got %d object(s) from ring %d!\n", ret, i);
696                         for (j = 0; j < ret; j++) {
697                                 mbuf = objs[j];
698                                 rte_hexdump(stdout, "mbuf",
699                                         rte_pktmbuf_mtod(mbuf, char *), 64);
700                                 rte_pktmbuf_free(mbuf);
701                         }
702                         tx_count += ret;
703                 }
704         }
705
706         if (tx_count != expected_count) {
707                 RTE_LOG(INFO, PIPELINE,
708                         "%s: Unexpected packets for ACL test, "
709                         "expected %d, got %d\n",
710                         __func__, expected_count, tx_count);
711                 goto fail;
712         }
713
714         rte_pipeline_free(p);
715
716         return  0;
717 fail:
718         return -1;
719
720 }
721
722 int
723 test_table_acl(void)
724 {
725
726
727         override_hit_mask = 0xFF; /* All packets are a hit */
728
729         setup_acl_pipeline();
730         if (test_pipeline_single_filter(10) < 0)
731                 return -1;
732
733         return 0;
734 }