xref: /dpdk/app/test-pipeline/pipeline_acl.c (revision 25d11a86c56d50947af33d0b79ede622809bd8b9)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2016 Intel Corporation
3  */
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stdint.h>
8 
9 #include <rte_log.h>
10 #include <rte_ethdev.h>
11 #include <rte_ether.h>
12 #include <rte_ip.h>
13 #include <rte_byteorder.h>
14 
15 #include <rte_port_ring.h>
16 #include <rte_table_acl.h>
17 #include <rte_pipeline.h>
18 
19 #include "main.h"
20 
21 enum {
22 	PROTO_FIELD_IPV4,
23 	SRC_FIELD_IPV4,
24 	DST_FIELD_IPV4,
25 	SRCP_FIELD_IPV4,
26 	DSTP_FIELD_IPV4,
27 	NUM_FIELDS_IPV4
28 };
29 
30 /*
31  * Here we define the 'shape' of the data we're searching for,
32  * by defining the meta-data of the ACL rules.
33  * in this case, we're defining 5 tuples. IP addresses, ports,
34  * and protocol.
35  */
36 struct rte_acl_field_def ipv4_field_formats[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 = sizeof(struct ether_hdr) +
43 			offsetof(struct ipv4_hdr, next_proto_id),
44 	},
45 	{
46 		.type = RTE_ACL_FIELD_TYPE_MASK,
47 		.size = sizeof(uint32_t),
48 		.field_index = SRC_FIELD_IPV4,
49 		.input_index = SRC_FIELD_IPV4,
50 		.offset = sizeof(struct ether_hdr) +
51 			offsetof(struct ipv4_hdr, src_addr),
52 	},
53 	{
54 		.type = RTE_ACL_FIELD_TYPE_MASK,
55 		.size = sizeof(uint32_t),
56 		.field_index = DST_FIELD_IPV4,
57 		.input_index = DST_FIELD_IPV4,
58 		.offset = sizeof(struct ether_hdr) +
59 			offsetof(struct ipv4_hdr, dst_addr),
60 	},
61 	{
62 		.type = RTE_ACL_FIELD_TYPE_RANGE,
63 		.size = sizeof(uint16_t),
64 		.field_index = SRCP_FIELD_IPV4,
65 		.input_index = SRCP_FIELD_IPV4,
66 		.offset = sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr),
67 	},
68 	{
69 		.type = RTE_ACL_FIELD_TYPE_RANGE,
70 		.size = sizeof(uint16_t),
71 		.field_index = DSTP_FIELD_IPV4,
72 		.input_index = SRCP_FIELD_IPV4,
73 		.offset = sizeof(struct ether_hdr) + sizeof(struct ipv4_hdr) +
74 			sizeof(uint16_t),
75 	},
76 };
77 
78 
79 
80 void
81 app_main_loop_worker_pipeline_acl(void) {
82 	struct rte_pipeline_params pipeline_params = {
83 		.name = "pipeline",
84 		.socket_id = rte_socket_id(),
85 	};
86 
87 	struct rte_pipeline *p;
88 	uint32_t port_in_id[APP_MAX_PORTS];
89 	uint32_t port_out_id[APP_MAX_PORTS];
90 	uint32_t table_id;
91 	uint32_t i;
92 
93 	RTE_LOG(INFO, USER1,
94 		"Core %u is doing work (pipeline with ACL table)\n",
95 		rte_lcore_id());
96 
97 	/* Pipeline configuration */
98 	p = rte_pipeline_create(&pipeline_params);
99 	if (p == NULL)
100 		rte_panic("Unable to configure the pipeline\n");
101 
102 	/* Input port configuration */
103 	for (i = 0; i < app.n_ports; i++) {
104 		struct rte_port_ring_reader_params port_ring_params = {
105 			.ring = app.rings_rx[i],
106 		};
107 
108 		struct rte_pipeline_port_in_params port_params = {
109 			.ops = &rte_port_ring_reader_ops,
110 			.arg_create = (void *) &port_ring_params,
111 			.f_action = NULL,
112 			.arg_ah = NULL,
113 			.burst_size = app.burst_size_worker_read,
114 		};
115 
116 		if (rte_pipeline_port_in_create(p, &port_params,
117 			&port_in_id[i]))
118 			rte_panic("Unable to configure input port for "
119 				"ring %d\n", i);
120 	}
121 
122 	/* Output port configuration */
123 	for (i = 0; i < app.n_ports; i++) {
124 		struct rte_port_ring_writer_params port_ring_params = {
125 			.ring = app.rings_tx[i],
126 			.tx_burst_sz = app.burst_size_worker_write,
127 		};
128 
129 		struct rte_pipeline_port_out_params port_params = {
130 			.ops = &rte_port_ring_writer_ops,
131 			.arg_create = (void *) &port_ring_params,
132 			.f_action = NULL,
133 			.arg_ah = NULL,
134 		};
135 
136 		if (rte_pipeline_port_out_create(p, &port_params,
137 			&port_out_id[i]))
138 			rte_panic("Unable to configure output port for "
139 				"ring %d\n", i);
140 	}
141 
142 	/* Table configuration */
143 	{
144 		struct rte_table_acl_params table_acl_params = {
145 			.name = "test", /* unique identifier for acl contexts */
146 			.n_rules = 1 << 5,
147 			.n_rule_fields = DIM(ipv4_field_formats),
148 		};
149 
150 		/* Copy in the rule meta-data defined above into the params */
151 		memcpy(table_acl_params.field_format, ipv4_field_formats,
152 			sizeof(ipv4_field_formats));
153 
154 		struct rte_pipeline_table_params table_params = {
155 			.ops = &rte_table_acl_ops,
156 			.arg_create = &table_acl_params,
157 			.f_action_hit = NULL,
158 			.f_action_miss = NULL,
159 			.arg_ah = NULL,
160 			.action_data_size = 0,
161 		};
162 
163 		if (rte_pipeline_table_create(p, &table_params, &table_id))
164 			rte_panic("Unable to configure the ACL table\n");
165 	}
166 
167 	/* Interconnecting ports and tables */
168 	for (i = 0; i < app.n_ports; i++)
169 		if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
170 			table_id))
171 			rte_panic("Unable to connect input port %u to "
172 				"table %u\n", port_in_id[i],  table_id);
173 
174 	/* Add entries to tables */
175 	for (i = 0; i < app.n_ports; i++) {
176 		struct rte_pipeline_table_entry table_entry = {
177 			.action = RTE_PIPELINE_ACTION_PORT,
178 			{.port_id = port_out_id[i & (app.n_ports - 1)]},
179 		};
180 		struct rte_table_acl_rule_add_params rule_params;
181 		struct rte_pipeline_table_entry *entry_ptr;
182 		int key_found, ret;
183 
184 		memset(&rule_params, 0, sizeof(rule_params));
185 
186 		/* Set the rule values */
187 		rule_params.field_value[SRC_FIELD_IPV4].value.u32 = 0;
188 		rule_params.field_value[SRC_FIELD_IPV4].mask_range.u32 = 0;
189 		rule_params.field_value[DST_FIELD_IPV4].value.u32 =
190 			i << (24 - __builtin_popcount(app.n_ports - 1));
191 		rule_params.field_value[DST_FIELD_IPV4].mask_range.u32 =
192 			8 + __builtin_popcount(app.n_ports - 1);
193 		rule_params.field_value[SRCP_FIELD_IPV4].value.u16 = 0;
194 		rule_params.field_value[SRCP_FIELD_IPV4].mask_range.u16 =
195 			UINT16_MAX;
196 		rule_params.field_value[DSTP_FIELD_IPV4].value.u16 = 0;
197 		rule_params.field_value[DSTP_FIELD_IPV4].mask_range.u16 =
198 			UINT16_MAX;
199 		rule_params.field_value[PROTO_FIELD_IPV4].value.u8 = 0;
200 		rule_params.field_value[PROTO_FIELD_IPV4].mask_range.u8 = 0;
201 
202 		rule_params.priority = 0;
203 
204 		uint32_t dst_addr = rule_params.field_value[DST_FIELD_IPV4].
205 			value.u32;
206 		uint32_t dst_mask =
207 			rule_params.field_value[DST_FIELD_IPV4].mask_range.u32;
208 
209 		printf("Adding rule to ACL table (IPv4 destination = "
210 			"%u.%u.%u.%u/%u => port out = %u)\n",
211 			(dst_addr & 0xFF000000) >> 24,
212 			(dst_addr & 0x00FF0000) >> 16,
213 			(dst_addr & 0x0000FF00) >> 8,
214 			dst_addr & 0x000000FF,
215 			dst_mask,
216 			table_entry.port_id);
217 
218 		/* For ACL, add needs an rte_table_acl_rule_add_params struct */
219 		ret = rte_pipeline_table_entry_add(p, table_id, &rule_params,
220 			&table_entry, &key_found, &entry_ptr);
221 		if (ret < 0)
222 			rte_panic("Unable to add entry to table %u (%d)\n",
223 				table_id, ret);
224 	}
225 
226 	/* Enable input ports */
227 	for (i = 0; i < app.n_ports; i++)
228 		if (rte_pipeline_port_in_enable(p, port_in_id[i]))
229 			rte_panic("Unable to enable input port %u\n",
230 				port_in_id[i]);
231 
232 	/* Check pipeline consistency */
233 	if (rte_pipeline_check(p) < 0)
234 		rte_panic("Pipeline consistency check failed\n");
235 
236 	/* Run-time */
237 #if APP_FLUSH == 0
238 	for ( ; ; )
239 		rte_pipeline_run(p);
240 #else
241 	for (i = 0; ; i++) {
242 		rte_pipeline_run(p);
243 
244 		if ((i & APP_FLUSH) == 0)
245 			rte_pipeline_flush(p);
246 	}
247 #endif
248 }
249