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