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