13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
23998e2a0SBruce Richardson * Copyright(c) 2017 Intel Corporation
3bab16ddaSBernard Iremonger */
4bab16ddaSBernard Iremonger
5bab16ddaSBernard Iremonger #include <stdint.h>
6bab16ddaSBernard Iremonger #include <inttypes.h>
7bab16ddaSBernard Iremonger #include <getopt.h>
8bab16ddaSBernard Iremonger
9bab16ddaSBernard Iremonger #include <rte_eal.h>
10bab16ddaSBernard Iremonger #include <rte_ethdev.h>
11bab16ddaSBernard Iremonger #include <rte_cycles.h>
12bab16ddaSBernard Iremonger #include <rte_lcore.h>
13bab16ddaSBernard Iremonger #include <rte_mbuf.h>
14bab16ddaSBernard Iremonger #include <rte_flow.h>
15bab16ddaSBernard Iremonger #include <rte_flow_classify.h>
16bab16ddaSBernard Iremonger #include <rte_table_acl.h>
17bab16ddaSBernard Iremonger
18867a6c66SKevin Laatz #define RX_RING_SIZE 1024
19867a6c66SKevin Laatz #define TX_RING_SIZE 1024
20bab16ddaSBernard Iremonger
21bab16ddaSBernard Iremonger #define NUM_MBUFS 8191
22bab16ddaSBernard Iremonger #define MBUF_CACHE_SIZE 250
23bab16ddaSBernard Iremonger #define BURST_SIZE 32
24bab16ddaSBernard Iremonger
25bab16ddaSBernard Iremonger #define MAX_NUM_CLASSIFY 30
26bab16ddaSBernard Iremonger #define FLOW_CLASSIFY_MAX_RULE_NUM 91
27bab16ddaSBernard Iremonger #define FLOW_CLASSIFY_MAX_PRIORITY 8
28bab16ddaSBernard Iremonger #define FLOW_CLASSIFIER_NAME_SIZE 64
29bab16ddaSBernard Iremonger
30bab16ddaSBernard Iremonger #define COMMENT_LEAD_CHAR ('#')
31bab16ddaSBernard Iremonger #define OPTION_RULE_IPV4 "rule_ipv4"
32bab16ddaSBernard Iremonger #define RTE_LOGTYPE_FLOW_CLASSIFY RTE_LOGTYPE_USER3
33bab16ddaSBernard Iremonger #define flow_classify_log(format, ...) \
34bab16ddaSBernard Iremonger RTE_LOG(ERR, FLOW_CLASSIFY, format, ##__VA_ARGS__)
35bab16ddaSBernard Iremonger
36bab16ddaSBernard Iremonger #define uint32_t_to_char(ip, a, b, c, d) do {\
37bab16ddaSBernard Iremonger *a = (unsigned char)(ip >> 24 & 0xff);\
38bab16ddaSBernard Iremonger *b = (unsigned char)(ip >> 16 & 0xff);\
39bab16ddaSBernard Iremonger *c = (unsigned char)(ip >> 8 & 0xff);\
40bab16ddaSBernard Iremonger *d = (unsigned char)(ip & 0xff);\
41bab16ddaSBernard Iremonger } while (0)
42bab16ddaSBernard Iremonger
43bab16ddaSBernard Iremonger enum {
44bab16ddaSBernard Iremonger CB_FLD_SRC_ADDR,
45bab16ddaSBernard Iremonger CB_FLD_DST_ADDR,
46bab16ddaSBernard Iremonger CB_FLD_SRC_PORT,
47bab16ddaSBernard Iremonger CB_FLD_SRC_PORT_DLM,
48bab16ddaSBernard Iremonger CB_FLD_SRC_PORT_MASK,
49bab16ddaSBernard Iremonger CB_FLD_DST_PORT,
50bab16ddaSBernard Iremonger CB_FLD_DST_PORT_DLM,
51bab16ddaSBernard Iremonger CB_FLD_DST_PORT_MASK,
52bab16ddaSBernard Iremonger CB_FLD_PROTO,
53bab16ddaSBernard Iremonger CB_FLD_PRIORITY,
54bab16ddaSBernard Iremonger CB_FLD_NUM,
55bab16ddaSBernard Iremonger };
56bab16ddaSBernard Iremonger
57bab16ddaSBernard Iremonger static struct{
58bab16ddaSBernard Iremonger const char *rule_ipv4_name;
59bab16ddaSBernard Iremonger } parm_config;
60bab16ddaSBernard Iremonger const char cb_port_delim[] = ":";
61bab16ddaSBernard Iremonger
629a212dc0SConor Fogarty /* Creation of flow classifier object. 8< */
63bab16ddaSBernard Iremonger struct flow_classifier {
64bab16ddaSBernard Iremonger struct rte_flow_classifier *cls;
65bab16ddaSBernard Iremonger };
66bab16ddaSBernard Iremonger
67bab16ddaSBernard Iremonger struct flow_classifier_acl {
68bab16ddaSBernard Iremonger struct flow_classifier cls;
69bab16ddaSBernard Iremonger } __rte_cache_aligned;
709a212dc0SConor Fogarty /* >8 End of creation of flow classifier object. */
719a212dc0SConor Fogarty
729a212dc0SConor Fogarty /* Creation of ACL table during initialization of application. 8< */
73bab16ddaSBernard Iremonger
74bab16ddaSBernard Iremonger /* ACL field definitions for IPv4 5 tuple rule */
75bab16ddaSBernard Iremonger enum {
76bab16ddaSBernard Iremonger PROTO_FIELD_IPV4,
77bab16ddaSBernard Iremonger SRC_FIELD_IPV4,
78bab16ddaSBernard Iremonger DST_FIELD_IPV4,
79bab16ddaSBernard Iremonger SRCP_FIELD_IPV4,
80bab16ddaSBernard Iremonger DSTP_FIELD_IPV4,
81bab16ddaSBernard Iremonger NUM_FIELDS_IPV4
82bab16ddaSBernard Iremonger };
83bab16ddaSBernard Iremonger
84bab16ddaSBernard Iremonger enum {
85bab16ddaSBernard Iremonger PROTO_INPUT_IPV4,
86bab16ddaSBernard Iremonger SRC_INPUT_IPV4,
87bab16ddaSBernard Iremonger DST_INPUT_IPV4,
88bab16ddaSBernard Iremonger SRCP_DESTP_INPUT_IPV4
89bab16ddaSBernard Iremonger };
90bab16ddaSBernard Iremonger
91bab16ddaSBernard Iremonger static struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
92bab16ddaSBernard Iremonger /* first input field - always one byte long. */
93bab16ddaSBernard Iremonger {
94bab16ddaSBernard Iremonger .type = RTE_ACL_FIELD_TYPE_BITMASK,
95bab16ddaSBernard Iremonger .size = sizeof(uint8_t),
96bab16ddaSBernard Iremonger .field_index = PROTO_FIELD_IPV4,
97bab16ddaSBernard Iremonger .input_index = PROTO_INPUT_IPV4,
986d13ea8eSOlivier Matz .offset = sizeof(struct rte_ether_hdr) +
99a7c528e5SOlivier Matz offsetof(struct rte_ipv4_hdr, next_proto_id),
100bab16ddaSBernard Iremonger },
101bab16ddaSBernard Iremonger /* next input field (IPv4 source address) - 4 consecutive bytes. */
102bab16ddaSBernard Iremonger {
103bab16ddaSBernard Iremonger /* rte_flow uses a bit mask for IPv4 addresses */
104bab16ddaSBernard Iremonger .type = RTE_ACL_FIELD_TYPE_BITMASK,
105bab16ddaSBernard Iremonger .size = sizeof(uint32_t),
106bab16ddaSBernard Iremonger .field_index = SRC_FIELD_IPV4,
107bab16ddaSBernard Iremonger .input_index = SRC_INPUT_IPV4,
1086d13ea8eSOlivier Matz .offset = sizeof(struct rte_ether_hdr) +
109a7c528e5SOlivier Matz offsetof(struct rte_ipv4_hdr, src_addr),
110bab16ddaSBernard Iremonger },
111bab16ddaSBernard Iremonger /* next input field (IPv4 destination address) - 4 consecutive bytes. */
112bab16ddaSBernard Iremonger {
113bab16ddaSBernard Iremonger /* rte_flow uses a bit mask for IPv4 addresses */
114bab16ddaSBernard Iremonger .type = RTE_ACL_FIELD_TYPE_BITMASK,
115bab16ddaSBernard Iremonger .size = sizeof(uint32_t),
116bab16ddaSBernard Iremonger .field_index = DST_FIELD_IPV4,
117bab16ddaSBernard Iremonger .input_index = DST_INPUT_IPV4,
1186d13ea8eSOlivier Matz .offset = sizeof(struct rte_ether_hdr) +
119a7c528e5SOlivier Matz offsetof(struct rte_ipv4_hdr, dst_addr),
120bab16ddaSBernard Iremonger },
121bab16ddaSBernard Iremonger /*
122bab16ddaSBernard Iremonger * Next 2 fields (src & dst ports) form 4 consecutive bytes.
123bab16ddaSBernard Iremonger * They share the same input index.
124bab16ddaSBernard Iremonger */
125bab16ddaSBernard Iremonger {
126bab16ddaSBernard Iremonger /* rte_flow uses a bit mask for protocol ports */
127bab16ddaSBernard Iremonger .type = RTE_ACL_FIELD_TYPE_BITMASK,
128bab16ddaSBernard Iremonger .size = sizeof(uint16_t),
129bab16ddaSBernard Iremonger .field_index = SRCP_FIELD_IPV4,
130bab16ddaSBernard Iremonger .input_index = SRCP_DESTP_INPUT_IPV4,
1316d13ea8eSOlivier Matz .offset = sizeof(struct rte_ether_hdr) +
132a7c528e5SOlivier Matz sizeof(struct rte_ipv4_hdr) +
133f41b5156SOlivier Matz offsetof(struct rte_tcp_hdr, src_port),
134bab16ddaSBernard Iremonger },
135bab16ddaSBernard Iremonger {
136bab16ddaSBernard Iremonger /* rte_flow uses a bit mask for protocol ports */
137bab16ddaSBernard Iremonger .type = RTE_ACL_FIELD_TYPE_BITMASK,
138bab16ddaSBernard Iremonger .size = sizeof(uint16_t),
139bab16ddaSBernard Iremonger .field_index = DSTP_FIELD_IPV4,
140bab16ddaSBernard Iremonger .input_index = SRCP_DESTP_INPUT_IPV4,
1416d13ea8eSOlivier Matz .offset = sizeof(struct rte_ether_hdr) +
142a7c528e5SOlivier Matz sizeof(struct rte_ipv4_hdr) +
143f41b5156SOlivier Matz offsetof(struct rte_tcp_hdr, dst_port),
144bab16ddaSBernard Iremonger },
145bab16ddaSBernard Iremonger };
1469a212dc0SConor Fogarty /* >8 End of creation of ACL table. */
147bab16ddaSBernard Iremonger
1489a212dc0SConor Fogarty /* Flow classify data. 8< */
149bab16ddaSBernard Iremonger static int num_classify_rules;
150bab16ddaSBernard Iremonger static struct rte_flow_classify_rule *rules[MAX_NUM_CLASSIFY];
151bab16ddaSBernard Iremonger static struct rte_flow_classify_ipv4_5tuple_stats ntuple_stats;
152bab16ddaSBernard Iremonger static struct rte_flow_classify_stats classify_stats = {
153bab16ddaSBernard Iremonger .stats = (void **)&ntuple_stats
154bab16ddaSBernard Iremonger };
1559a212dc0SConor Fogarty /* >8 End of flow classify data. */
156bab16ddaSBernard Iremonger
157bab16ddaSBernard Iremonger /* parameters for rte_flow_classify_validate and
158bab16ddaSBernard Iremonger * rte_flow_classify_table_entry_add functions
159bab16ddaSBernard Iremonger */
160bab16ddaSBernard Iremonger
161bab16ddaSBernard Iremonger static struct rte_flow_item eth_item = { RTE_FLOW_ITEM_TYPE_ETH,
162bab16ddaSBernard Iremonger 0, 0, 0 };
163bab16ddaSBernard Iremonger static struct rte_flow_item end_item = { RTE_FLOW_ITEM_TYPE_END,
164bab16ddaSBernard Iremonger 0, 0, 0 };
165bab16ddaSBernard Iremonger
166bab16ddaSBernard Iremonger /* sample actions:
167bab16ddaSBernard Iremonger * "actions count / end"
168bab16ddaSBernard Iremonger */
16950bdac59SJasvinder Singh struct rte_flow_query_count count = {
17050bdac59SJasvinder Singh .reset = 1,
17150bdac59SJasvinder Singh .hits_set = 1,
17250bdac59SJasvinder Singh .bytes_set = 1,
17350bdac59SJasvinder Singh .hits = 0,
17450bdac59SJasvinder Singh .bytes = 0,
17550bdac59SJasvinder Singh };
17650bdac59SJasvinder Singh static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT,
17750bdac59SJasvinder Singh &count};
178bab16ddaSBernard Iremonger static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END, 0};
179bab16ddaSBernard Iremonger static struct rte_flow_action actions[2];
180bab16ddaSBernard Iremonger
181bab16ddaSBernard Iremonger /* sample attributes */
182bab16ddaSBernard Iremonger static struct rte_flow_attr attr;
183bab16ddaSBernard Iremonger
184bab16ddaSBernard Iremonger /* flow_classify.c: * Based on DPDK skeleton forwarding example. */
185bab16ddaSBernard Iremonger
186bab16ddaSBernard Iremonger /*
187bab16ddaSBernard Iremonger * Initializes a given port using global settings and with the RX buffers
188bab16ddaSBernard Iremonger * coming from the mbuf_pool passed as a parameter.
189bab16ddaSBernard Iremonger */
1909a212dc0SConor Fogarty
1919a212dc0SConor Fogarty /* Initializing port using global settings. 8< */
192bab16ddaSBernard Iremonger static inline int
port_init(uint8_t port,struct rte_mempool * mbuf_pool)193bab16ddaSBernard Iremonger port_init(uint8_t port, struct rte_mempool *mbuf_pool)
194bab16ddaSBernard Iremonger {
1951bb4a528SFerruh Yigit struct rte_eth_conf port_conf;
1966d13ea8eSOlivier Matz struct rte_ether_addr addr;
197bab16ddaSBernard Iremonger const uint16_t rx_rings = 1, tx_rings = 1;
198bab16ddaSBernard Iremonger int retval;
199bab16ddaSBernard Iremonger uint16_t q;
200e5242400SShahaf Shuler struct rte_eth_dev_info dev_info;
201e5242400SShahaf Shuler struct rte_eth_txconf txconf;
202bab16ddaSBernard Iremonger
203211992f3SBernard Iremonger if (!rte_eth_dev_is_valid_port(port))
204bab16ddaSBernard Iremonger return -1;
205bab16ddaSBernard Iremonger
2061bb4a528SFerruh Yigit memset(&port_conf, 0, sizeof(struct rte_eth_conf));
2071bb4a528SFerruh Yigit
20828f90c35SIvan Ilchenko retval = rte_eth_dev_info_get(port, &dev_info);
20928f90c35SIvan Ilchenko if (retval != 0) {
21028f90c35SIvan Ilchenko printf("Error during getting device (port %u) info: %s\n",
21128f90c35SIvan Ilchenko port, strerror(-retval));
21228f90c35SIvan Ilchenko return retval;
21328f90c35SIvan Ilchenko }
21428f90c35SIvan Ilchenko
215295968d1SFerruh Yigit if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
216e5242400SShahaf Shuler port_conf.txmode.offloads |=
217295968d1SFerruh Yigit RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
218e5242400SShahaf Shuler
219bab16ddaSBernard Iremonger /* Configure the Ethernet device. */
220bab16ddaSBernard Iremonger retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
221bab16ddaSBernard Iremonger if (retval != 0)
222bab16ddaSBernard Iremonger return retval;
223bab16ddaSBernard Iremonger
224bab16ddaSBernard Iremonger /* Allocate and set up 1 RX queue per Ethernet port. */
225bab16ddaSBernard Iremonger for (q = 0; q < rx_rings; q++) {
226bab16ddaSBernard Iremonger retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE,
227bab16ddaSBernard Iremonger rte_eth_dev_socket_id(port), NULL, mbuf_pool);
228bab16ddaSBernard Iremonger if (retval < 0)
229bab16ddaSBernard Iremonger return retval;
230bab16ddaSBernard Iremonger }
231bab16ddaSBernard Iremonger
232e5242400SShahaf Shuler txconf = dev_info.default_txconf;
233e5242400SShahaf Shuler txconf.offloads = port_conf.txmode.offloads;
234bab16ddaSBernard Iremonger /* Allocate and set up 1 TX queue per Ethernet port. */
235bab16ddaSBernard Iremonger for (q = 0; q < tx_rings; q++) {
236bab16ddaSBernard Iremonger retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE,
237e5242400SShahaf Shuler rte_eth_dev_socket_id(port), &txconf);
238bab16ddaSBernard Iremonger if (retval < 0)
239bab16ddaSBernard Iremonger return retval;
240bab16ddaSBernard Iremonger }
241bab16ddaSBernard Iremonger
2429a212dc0SConor Fogarty /* Start the Ethernet port. 8< */
243bab16ddaSBernard Iremonger retval = rte_eth_dev_start(port);
2449a212dc0SConor Fogarty /* >8 End of starting the Ethernet port. */
245bab16ddaSBernard Iremonger if (retval < 0)
246bab16ddaSBernard Iremonger return retval;
247bab16ddaSBernard Iremonger
248bab16ddaSBernard Iremonger /* Display the port MAC address. */
24970febdcfSIgor Romanov retval = rte_eth_macaddr_get(port, &addr);
25070febdcfSIgor Romanov if (retval != 0)
25170febdcfSIgor Romanov return retval;
25270febdcfSIgor Romanov
253bab16ddaSBernard Iremonger printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8
254bab16ddaSBernard Iremonger " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n",
255a7db3afcSAman Deep Singh port, RTE_ETHER_ADDR_BYTES(&addr));
256bab16ddaSBernard Iremonger
257bab16ddaSBernard Iremonger /* Enable RX in promiscuous mode for the Ethernet device. */
258f430bbceSIvan Ilchenko retval = rte_eth_promiscuous_enable(port);
259f430bbceSIvan Ilchenko if (retval != 0)
260f430bbceSIvan Ilchenko return retval;
261bab16ddaSBernard Iremonger
262bab16ddaSBernard Iremonger return 0;
263bab16ddaSBernard Iremonger }
2649a212dc0SConor Fogarty /* >8 End of initializing a given port. */
265bab16ddaSBernard Iremonger
266bab16ddaSBernard Iremonger /*
267bab16ddaSBernard Iremonger * The lcore main. This is the main thread that does the work, reading from
268bab16ddaSBernard Iremonger * an input port classifying the packets and writing to an output port.
269bab16ddaSBernard Iremonger */
2709a212dc0SConor Fogarty
2719a212dc0SConor Fogarty /* Classifying the packets. 8< */
272ddcd7640SThomas Monjalon static __rte_noreturn void
lcore_main(struct flow_classifier * cls_app)273bab16ddaSBernard Iremonger lcore_main(struct flow_classifier *cls_app)
274bab16ddaSBernard Iremonger {
2758728ccf3SThomas Monjalon uint16_t port;
276bab16ddaSBernard Iremonger int ret;
277bab16ddaSBernard Iremonger int i = 0;
278bab16ddaSBernard Iremonger
279bab16ddaSBernard Iremonger ret = rte_flow_classify_table_entry_delete(cls_app->cls,
28050bdac59SJasvinder Singh rules[7]);
281bab16ddaSBernard Iremonger if (ret)
282bab16ddaSBernard Iremonger printf("table_entry_delete failed [7] %d\n\n", ret);
283bab16ddaSBernard Iremonger else
284bab16ddaSBernard Iremonger printf("table_entry_delete succeeded [7]\n\n");
285bab16ddaSBernard Iremonger
286bab16ddaSBernard Iremonger /*
287bab16ddaSBernard Iremonger * Check that the port is on the same NUMA node as the polling thread
288bab16ddaSBernard Iremonger * for best performance.
289bab16ddaSBernard Iremonger */
2908728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(port)
29178a5545eSMin Hu (Connor) if (rte_eth_dev_socket_id(port) >= 0 &&
292bab16ddaSBernard Iremonger rte_eth_dev_socket_id(port) != (int)rte_socket_id()) {
293bab16ddaSBernard Iremonger printf("\n\n");
294bab16ddaSBernard Iremonger printf("WARNING: port %u is on remote NUMA node\n",
295bab16ddaSBernard Iremonger port);
296bab16ddaSBernard Iremonger printf("to polling thread.\n");
297bab16ddaSBernard Iremonger printf("Performance will not be optimal.\n");
298bab16ddaSBernard Iremonger }
29950bdac59SJasvinder Singh printf("\nCore %u forwarding packets. ", rte_lcore_id());
30050bdac59SJasvinder Singh printf("[Ctrl+C to quit]\n");
30150bdac59SJasvinder Singh
3029a212dc0SConor Fogarty /* Run until the application is quit or killed. 8< */
303bab16ddaSBernard Iremonger for (;;) {
304bab16ddaSBernard Iremonger /*
305bab16ddaSBernard Iremonger * Receive packets on a port, classify them and forward them
306bab16ddaSBernard Iremonger * on the paired port.
307bab16ddaSBernard Iremonger * The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
308bab16ddaSBernard Iremonger */
3098728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(port) {
310bab16ddaSBernard Iremonger /* Get burst of RX packets, from first port of pair. */
311bab16ddaSBernard Iremonger struct rte_mbuf *bufs[BURST_SIZE];
312bab16ddaSBernard Iremonger const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
313bab16ddaSBernard Iremonger bufs, BURST_SIZE);
314bab16ddaSBernard Iremonger
315bab16ddaSBernard Iremonger if (unlikely(nb_rx == 0))
316bab16ddaSBernard Iremonger continue;
317bab16ddaSBernard Iremonger
318bab16ddaSBernard Iremonger for (i = 0; i < MAX_NUM_CLASSIFY; i++) {
319bab16ddaSBernard Iremonger if (rules[i]) {
320bab16ddaSBernard Iremonger ret = rte_flow_classifier_query(
321bab16ddaSBernard Iremonger cls_app->cls,
322bab16ddaSBernard Iremonger bufs, nb_rx, rules[i],
323bab16ddaSBernard Iremonger &classify_stats);
324bab16ddaSBernard Iremonger if (ret)
325bab16ddaSBernard Iremonger printf(
326bab16ddaSBernard Iremonger "rule [%d] query failed ret [%d]\n\n",
327bab16ddaSBernard Iremonger i, ret);
328bab16ddaSBernard Iremonger else {
329bab16ddaSBernard Iremonger printf(
330bab16ddaSBernard Iremonger "rule[%d] count=%"PRIu64"\n",
331bab16ddaSBernard Iremonger i, ntuple_stats.counter1);
332bab16ddaSBernard Iremonger
333bab16ddaSBernard Iremonger printf("proto = %d\n",
334bab16ddaSBernard Iremonger ntuple_stats.ipv4_5tuple.proto);
335bab16ddaSBernard Iremonger }
336bab16ddaSBernard Iremonger }
337bab16ddaSBernard Iremonger }
338bab16ddaSBernard Iremonger
339bab16ddaSBernard Iremonger /* Send burst of TX packets, to second port of pair. */
340bab16ddaSBernard Iremonger const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
341bab16ddaSBernard Iremonger bufs, nb_rx);
342bab16ddaSBernard Iremonger
343bab16ddaSBernard Iremonger /* Free any unsent packets. */
344bab16ddaSBernard Iremonger if (unlikely(nb_tx < nb_rx)) {
345bab16ddaSBernard Iremonger uint16_t buf;
346bab16ddaSBernard Iremonger
347bab16ddaSBernard Iremonger for (buf = nb_tx; buf < nb_rx; buf++)
348bab16ddaSBernard Iremonger rte_pktmbuf_free(bufs[buf]);
349bab16ddaSBernard Iremonger }
350bab16ddaSBernard Iremonger }
351bab16ddaSBernard Iremonger }
3529a212dc0SConor Fogarty /* >8 End of main loop. */
353bab16ddaSBernard Iremonger }
3549a212dc0SConor Fogarty /* >8 End of lcore main. */
355bab16ddaSBernard Iremonger
356bab16ddaSBernard Iremonger /*
357bab16ddaSBernard Iremonger * Parse IPv4 5 tuple rules file, ipv4_rules_file.txt.
358bab16ddaSBernard Iremonger * Expected format:
359bab16ddaSBernard Iremonger * <src_ipv4_addr>'/'<masklen> <space> \
360bab16ddaSBernard Iremonger * <dst_ipv4_addr>'/'<masklen> <space> \
361bab16ddaSBernard Iremonger * <src_port> <space> ":" <src_port_mask> <space> \
362bab16ddaSBernard Iremonger * <dst_port> <space> ":" <dst_port_mask> <space> \
363bab16ddaSBernard Iremonger * <proto>'/'<proto_mask> <space> \
364bab16ddaSBernard Iremonger * <priority>
365bab16ddaSBernard Iremonger */
366bab16ddaSBernard Iremonger
367bab16ddaSBernard Iremonger static int
get_cb_field(char ** in,uint32_t * fd,int base,unsigned long lim,char dlm)368bab16ddaSBernard Iremonger get_cb_field(char **in, uint32_t *fd, int base, unsigned long lim,
369bab16ddaSBernard Iremonger char dlm)
370bab16ddaSBernard Iremonger {
371bab16ddaSBernard Iremonger unsigned long val;
372bab16ddaSBernard Iremonger char *end;
373bab16ddaSBernard Iremonger
374bab16ddaSBernard Iremonger errno = 0;
375bab16ddaSBernard Iremonger val = strtoul(*in, &end, base);
376bab16ddaSBernard Iremonger if (errno != 0 || end[0] != dlm || val > lim)
377bab16ddaSBernard Iremonger return -EINVAL;
378bab16ddaSBernard Iremonger *fd = (uint32_t)val;
379bab16ddaSBernard Iremonger *in = end + 1;
380bab16ddaSBernard Iremonger return 0;
381bab16ddaSBernard Iremonger }
382bab16ddaSBernard Iremonger
383bab16ddaSBernard Iremonger static int
parse_ipv4_net(char * in,uint32_t * addr,uint32_t * mask_len)384bab16ddaSBernard Iremonger parse_ipv4_net(char *in, uint32_t *addr, uint32_t *mask_len)
385bab16ddaSBernard Iremonger {
386bab16ddaSBernard Iremonger uint32_t a, b, c, d, m;
387bab16ddaSBernard Iremonger
388bab16ddaSBernard Iremonger if (get_cb_field(&in, &a, 0, UINT8_MAX, '.'))
389bab16ddaSBernard Iremonger return -EINVAL;
390bab16ddaSBernard Iremonger if (get_cb_field(&in, &b, 0, UINT8_MAX, '.'))
391bab16ddaSBernard Iremonger return -EINVAL;
392bab16ddaSBernard Iremonger if (get_cb_field(&in, &c, 0, UINT8_MAX, '.'))
393bab16ddaSBernard Iremonger return -EINVAL;
394bab16ddaSBernard Iremonger if (get_cb_field(&in, &d, 0, UINT8_MAX, '/'))
395bab16ddaSBernard Iremonger return -EINVAL;
396bab16ddaSBernard Iremonger if (get_cb_field(&in, &m, 0, sizeof(uint32_t) * CHAR_BIT, 0))
397bab16ddaSBernard Iremonger return -EINVAL;
398bab16ddaSBernard Iremonger
3990c9da755SDavid Marchand addr[0] = RTE_IPV4(a, b, c, d);
400bab16ddaSBernard Iremonger mask_len[0] = m;
401bab16ddaSBernard Iremonger return 0;
402bab16ddaSBernard Iremonger }
403bab16ddaSBernard Iremonger
404bab16ddaSBernard Iremonger static int
parse_ipv4_5tuple_rule(char * str,struct rte_eth_ntuple_filter * ntuple_filter)405bab16ddaSBernard Iremonger parse_ipv4_5tuple_rule(char *str, struct rte_eth_ntuple_filter *ntuple_filter)
406bab16ddaSBernard Iremonger {
407bab16ddaSBernard Iremonger int i, ret;
408bab16ddaSBernard Iremonger char *s, *sp, *in[CB_FLD_NUM];
409bab16ddaSBernard Iremonger static const char *dlm = " \t\n";
410bab16ddaSBernard Iremonger int dim = CB_FLD_NUM;
411bab16ddaSBernard Iremonger uint32_t temp;
412bab16ddaSBernard Iremonger
413bab16ddaSBernard Iremonger s = str;
414bab16ddaSBernard Iremonger for (i = 0; i != dim; i++, s = NULL) {
415bab16ddaSBernard Iremonger in[i] = strtok_r(s, dlm, &sp);
416bab16ddaSBernard Iremonger if (in[i] == NULL)
417bab16ddaSBernard Iremonger return -EINVAL;
418bab16ddaSBernard Iremonger }
419bab16ddaSBernard Iremonger
420bab16ddaSBernard Iremonger ret = parse_ipv4_net(in[CB_FLD_SRC_ADDR],
421bab16ddaSBernard Iremonger &ntuple_filter->src_ip,
422bab16ddaSBernard Iremonger &ntuple_filter->src_ip_mask);
423bab16ddaSBernard Iremonger if (ret != 0) {
424bab16ddaSBernard Iremonger flow_classify_log("failed to read source address/mask: %s\n",
425bab16ddaSBernard Iremonger in[CB_FLD_SRC_ADDR]);
426bab16ddaSBernard Iremonger return ret;
427bab16ddaSBernard Iremonger }
428bab16ddaSBernard Iremonger
429bab16ddaSBernard Iremonger ret = parse_ipv4_net(in[CB_FLD_DST_ADDR],
430bab16ddaSBernard Iremonger &ntuple_filter->dst_ip,
431bab16ddaSBernard Iremonger &ntuple_filter->dst_ip_mask);
432bab16ddaSBernard Iremonger if (ret != 0) {
433*750c1779SChuanshe Zhang flow_classify_log("failed to read destination address/mask: %s\n",
434bab16ddaSBernard Iremonger in[CB_FLD_DST_ADDR]);
435bab16ddaSBernard Iremonger return ret;
436bab16ddaSBernard Iremonger }
437bab16ddaSBernard Iremonger
438bab16ddaSBernard Iremonger if (get_cb_field(&in[CB_FLD_SRC_PORT], &temp, 0, UINT16_MAX, 0))
439bab16ddaSBernard Iremonger return -EINVAL;
440bab16ddaSBernard Iremonger ntuple_filter->src_port = (uint16_t)temp;
441bab16ddaSBernard Iremonger
442bab16ddaSBernard Iremonger if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim,
443bab16ddaSBernard Iremonger sizeof(cb_port_delim)) != 0)
444bab16ddaSBernard Iremonger return -EINVAL;
445bab16ddaSBernard Iremonger
446bab16ddaSBernard Iremonger if (get_cb_field(&in[CB_FLD_SRC_PORT_MASK], &temp, 0, UINT16_MAX, 0))
447bab16ddaSBernard Iremonger return -EINVAL;
448bab16ddaSBernard Iremonger ntuple_filter->src_port_mask = (uint16_t)temp;
449bab16ddaSBernard Iremonger
450bab16ddaSBernard Iremonger if (get_cb_field(&in[CB_FLD_DST_PORT], &temp, 0, UINT16_MAX, 0))
451bab16ddaSBernard Iremonger return -EINVAL;
452bab16ddaSBernard Iremonger ntuple_filter->dst_port = (uint16_t)temp;
453bab16ddaSBernard Iremonger
454bab16ddaSBernard Iremonger if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim,
455bab16ddaSBernard Iremonger sizeof(cb_port_delim)) != 0)
456bab16ddaSBernard Iremonger return -EINVAL;
457bab16ddaSBernard Iremonger
458bab16ddaSBernard Iremonger if (get_cb_field(&in[CB_FLD_DST_PORT_MASK], &temp, 0, UINT16_MAX, 0))
459bab16ddaSBernard Iremonger return -EINVAL;
460bab16ddaSBernard Iremonger ntuple_filter->dst_port_mask = (uint16_t)temp;
461bab16ddaSBernard Iremonger
462bab16ddaSBernard Iremonger if (get_cb_field(&in[CB_FLD_PROTO], &temp, 0, UINT8_MAX, '/'))
463bab16ddaSBernard Iremonger return -EINVAL;
464bab16ddaSBernard Iremonger ntuple_filter->proto = (uint8_t)temp;
465bab16ddaSBernard Iremonger
466bab16ddaSBernard Iremonger if (get_cb_field(&in[CB_FLD_PROTO], &temp, 0, UINT8_MAX, 0))
467bab16ddaSBernard Iremonger return -EINVAL;
468bab16ddaSBernard Iremonger ntuple_filter->proto_mask = (uint8_t)temp;
469bab16ddaSBernard Iremonger
470bab16ddaSBernard Iremonger if (get_cb_field(&in[CB_FLD_PRIORITY], &temp, 0, UINT16_MAX, 0))
471bab16ddaSBernard Iremonger return -EINVAL;
472bab16ddaSBernard Iremonger ntuple_filter->priority = (uint16_t)temp;
473bab16ddaSBernard Iremonger if (ntuple_filter->priority > FLOW_CLASSIFY_MAX_PRIORITY)
474bab16ddaSBernard Iremonger ret = -EINVAL;
475bab16ddaSBernard Iremonger
476bab16ddaSBernard Iremonger return ret;
477bab16ddaSBernard Iremonger }
478bab16ddaSBernard Iremonger
479bab16ddaSBernard Iremonger /* Bypass comment and empty lines */
480bab16ddaSBernard Iremonger static inline int
is_bypass_line(char * buff)481bab16ddaSBernard Iremonger is_bypass_line(char *buff)
482bab16ddaSBernard Iremonger {
483bab16ddaSBernard Iremonger int i = 0;
484bab16ddaSBernard Iremonger
485bab16ddaSBernard Iremonger /* comment line */
486bab16ddaSBernard Iremonger if (buff[0] == COMMENT_LEAD_CHAR)
487bab16ddaSBernard Iremonger return 1;
488bab16ddaSBernard Iremonger /* empty line */
489bab16ddaSBernard Iremonger while (buff[i] != '\0') {
490bab16ddaSBernard Iremonger if (!isspace(buff[i]))
491bab16ddaSBernard Iremonger return 0;
492bab16ddaSBernard Iremonger i++;
493bab16ddaSBernard Iremonger }
494bab16ddaSBernard Iremonger return 1;
495bab16ddaSBernard Iremonger }
496bab16ddaSBernard Iremonger
497bab16ddaSBernard Iremonger static uint32_t
convert_depth_to_bitmask(uint32_t depth_val)498bab16ddaSBernard Iremonger convert_depth_to_bitmask(uint32_t depth_val)
499bab16ddaSBernard Iremonger {
500bab16ddaSBernard Iremonger uint32_t bitmask = 0;
501bab16ddaSBernard Iremonger int i, j;
502bab16ddaSBernard Iremonger
503bab16ddaSBernard Iremonger for (i = depth_val, j = 0; i > 0; i--, j++)
504bab16ddaSBernard Iremonger bitmask |= (1 << (31 - j));
505bab16ddaSBernard Iremonger return bitmask;
506bab16ddaSBernard Iremonger }
507bab16ddaSBernard Iremonger
508bab16ddaSBernard Iremonger static int
add_classify_rule(struct rte_eth_ntuple_filter * ntuple_filter,struct flow_classifier * cls_app)509bab16ddaSBernard Iremonger add_classify_rule(struct rte_eth_ntuple_filter *ntuple_filter,
510bab16ddaSBernard Iremonger struct flow_classifier *cls_app)
511bab16ddaSBernard Iremonger {
512bab16ddaSBernard Iremonger int ret = -1;
513bab16ddaSBernard Iremonger int key_found;
514bab16ddaSBernard Iremonger struct rte_flow_error error;
515bab16ddaSBernard Iremonger struct rte_flow_item_ipv4 ipv4_spec;
516bab16ddaSBernard Iremonger struct rte_flow_item_ipv4 ipv4_mask;
517bab16ddaSBernard Iremonger struct rte_flow_item ipv4_udp_item;
518bab16ddaSBernard Iremonger struct rte_flow_item ipv4_tcp_item;
519bab16ddaSBernard Iremonger struct rte_flow_item ipv4_sctp_item;
520bab16ddaSBernard Iremonger struct rte_flow_item_udp udp_spec;
521bab16ddaSBernard Iremonger struct rte_flow_item_udp udp_mask;
522bab16ddaSBernard Iremonger struct rte_flow_item udp_item;
523bab16ddaSBernard Iremonger struct rte_flow_item_tcp tcp_spec;
524bab16ddaSBernard Iremonger struct rte_flow_item_tcp tcp_mask;
525bab16ddaSBernard Iremonger struct rte_flow_item tcp_item;
526bab16ddaSBernard Iremonger struct rte_flow_item_sctp sctp_spec;
527bab16ddaSBernard Iremonger struct rte_flow_item_sctp sctp_mask;
528bab16ddaSBernard Iremonger struct rte_flow_item sctp_item;
529bab16ddaSBernard Iremonger struct rte_flow_item pattern_ipv4_5tuple[4];
530bab16ddaSBernard Iremonger struct rte_flow_classify_rule *rule;
531bab16ddaSBernard Iremonger uint8_t ipv4_proto;
532bab16ddaSBernard Iremonger
533bab16ddaSBernard Iremonger if (num_classify_rules >= MAX_NUM_CLASSIFY) {
534bab16ddaSBernard Iremonger printf(
535bab16ddaSBernard Iremonger "\nINFO: classify rule capacity %d reached\n",
536bab16ddaSBernard Iremonger num_classify_rules);
537bab16ddaSBernard Iremonger return ret;
538bab16ddaSBernard Iremonger }
539bab16ddaSBernard Iremonger
540bab16ddaSBernard Iremonger /* set up parameters for validate and add */
541bab16ddaSBernard Iremonger memset(&ipv4_spec, 0, sizeof(ipv4_spec));
542bab16ddaSBernard Iremonger ipv4_spec.hdr.next_proto_id = ntuple_filter->proto;
543bab16ddaSBernard Iremonger ipv4_spec.hdr.src_addr = ntuple_filter->src_ip;
544bab16ddaSBernard Iremonger ipv4_spec.hdr.dst_addr = ntuple_filter->dst_ip;
545bab16ddaSBernard Iremonger ipv4_proto = ipv4_spec.hdr.next_proto_id;
546bab16ddaSBernard Iremonger
547bab16ddaSBernard Iremonger memset(&ipv4_mask, 0, sizeof(ipv4_mask));
548bab16ddaSBernard Iremonger ipv4_mask.hdr.next_proto_id = ntuple_filter->proto_mask;
549bab16ddaSBernard Iremonger ipv4_mask.hdr.src_addr = ntuple_filter->src_ip_mask;
550bab16ddaSBernard Iremonger ipv4_mask.hdr.src_addr =
551bab16ddaSBernard Iremonger convert_depth_to_bitmask(ipv4_mask.hdr.src_addr);
552bab16ddaSBernard Iremonger ipv4_mask.hdr.dst_addr = ntuple_filter->dst_ip_mask;
553bab16ddaSBernard Iremonger ipv4_mask.hdr.dst_addr =
554bab16ddaSBernard Iremonger convert_depth_to_bitmask(ipv4_mask.hdr.dst_addr);
555bab16ddaSBernard Iremonger
556bab16ddaSBernard Iremonger switch (ipv4_proto) {
557bab16ddaSBernard Iremonger case IPPROTO_UDP:
558bab16ddaSBernard Iremonger ipv4_udp_item.type = RTE_FLOW_ITEM_TYPE_IPV4;
559bab16ddaSBernard Iremonger ipv4_udp_item.spec = &ipv4_spec;
560bab16ddaSBernard Iremonger ipv4_udp_item.mask = &ipv4_mask;
561bab16ddaSBernard Iremonger ipv4_udp_item.last = NULL;
562bab16ddaSBernard Iremonger
563bab16ddaSBernard Iremonger udp_spec.hdr.src_port = ntuple_filter->src_port;
564bab16ddaSBernard Iremonger udp_spec.hdr.dst_port = ntuple_filter->dst_port;
565bab16ddaSBernard Iremonger udp_spec.hdr.dgram_len = 0;
566bab16ddaSBernard Iremonger udp_spec.hdr.dgram_cksum = 0;
567bab16ddaSBernard Iremonger
568bab16ddaSBernard Iremonger udp_mask.hdr.src_port = ntuple_filter->src_port_mask;
569bab16ddaSBernard Iremonger udp_mask.hdr.dst_port = ntuple_filter->dst_port_mask;
570bab16ddaSBernard Iremonger udp_mask.hdr.dgram_len = 0;
571bab16ddaSBernard Iremonger udp_mask.hdr.dgram_cksum = 0;
572bab16ddaSBernard Iremonger
573bab16ddaSBernard Iremonger udp_item.type = RTE_FLOW_ITEM_TYPE_UDP;
574bab16ddaSBernard Iremonger udp_item.spec = &udp_spec;
575bab16ddaSBernard Iremonger udp_item.mask = &udp_mask;
576bab16ddaSBernard Iremonger udp_item.last = NULL;
577bab16ddaSBernard Iremonger
578bab16ddaSBernard Iremonger attr.priority = ntuple_filter->priority;
579bab16ddaSBernard Iremonger pattern_ipv4_5tuple[1] = ipv4_udp_item;
580bab16ddaSBernard Iremonger pattern_ipv4_5tuple[2] = udp_item;
581bab16ddaSBernard Iremonger break;
582bab16ddaSBernard Iremonger case IPPROTO_TCP:
583bab16ddaSBernard Iremonger ipv4_tcp_item.type = RTE_FLOW_ITEM_TYPE_IPV4;
584bab16ddaSBernard Iremonger ipv4_tcp_item.spec = &ipv4_spec;
585bab16ddaSBernard Iremonger ipv4_tcp_item.mask = &ipv4_mask;
586bab16ddaSBernard Iremonger ipv4_tcp_item.last = NULL;
587bab16ddaSBernard Iremonger
588bab16ddaSBernard Iremonger memset(&tcp_spec, 0, sizeof(tcp_spec));
589bab16ddaSBernard Iremonger tcp_spec.hdr.src_port = ntuple_filter->src_port;
590bab16ddaSBernard Iremonger tcp_spec.hdr.dst_port = ntuple_filter->dst_port;
591bab16ddaSBernard Iremonger
592bab16ddaSBernard Iremonger memset(&tcp_mask, 0, sizeof(tcp_mask));
593bab16ddaSBernard Iremonger tcp_mask.hdr.src_port = ntuple_filter->src_port_mask;
594bab16ddaSBernard Iremonger tcp_mask.hdr.dst_port = ntuple_filter->dst_port_mask;
595bab16ddaSBernard Iremonger
596bab16ddaSBernard Iremonger tcp_item.type = RTE_FLOW_ITEM_TYPE_TCP;
597bab16ddaSBernard Iremonger tcp_item.spec = &tcp_spec;
598bab16ddaSBernard Iremonger tcp_item.mask = &tcp_mask;
599bab16ddaSBernard Iremonger tcp_item.last = NULL;
600bab16ddaSBernard Iremonger
601bab16ddaSBernard Iremonger attr.priority = ntuple_filter->priority;
602bab16ddaSBernard Iremonger pattern_ipv4_5tuple[1] = ipv4_tcp_item;
603bab16ddaSBernard Iremonger pattern_ipv4_5tuple[2] = tcp_item;
604bab16ddaSBernard Iremonger break;
605bab16ddaSBernard Iremonger case IPPROTO_SCTP:
606bab16ddaSBernard Iremonger ipv4_sctp_item.type = RTE_FLOW_ITEM_TYPE_IPV4;
607bab16ddaSBernard Iremonger ipv4_sctp_item.spec = &ipv4_spec;
608bab16ddaSBernard Iremonger ipv4_sctp_item.mask = &ipv4_mask;
609bab16ddaSBernard Iremonger ipv4_sctp_item.last = NULL;
610bab16ddaSBernard Iremonger
611bab16ddaSBernard Iremonger sctp_spec.hdr.src_port = ntuple_filter->src_port;
612bab16ddaSBernard Iremonger sctp_spec.hdr.dst_port = ntuple_filter->dst_port;
613bab16ddaSBernard Iremonger sctp_spec.hdr.cksum = 0;
614bab16ddaSBernard Iremonger sctp_spec.hdr.tag = 0;
615bab16ddaSBernard Iremonger
616bab16ddaSBernard Iremonger sctp_mask.hdr.src_port = ntuple_filter->src_port_mask;
617bab16ddaSBernard Iremonger sctp_mask.hdr.dst_port = ntuple_filter->dst_port_mask;
618bab16ddaSBernard Iremonger sctp_mask.hdr.cksum = 0;
619bab16ddaSBernard Iremonger sctp_mask.hdr.tag = 0;
620bab16ddaSBernard Iremonger
621bab16ddaSBernard Iremonger sctp_item.type = RTE_FLOW_ITEM_TYPE_SCTP;
622bab16ddaSBernard Iremonger sctp_item.spec = &sctp_spec;
623bab16ddaSBernard Iremonger sctp_item.mask = &sctp_mask;
624bab16ddaSBernard Iremonger sctp_item.last = NULL;
625bab16ddaSBernard Iremonger
626bab16ddaSBernard Iremonger attr.priority = ntuple_filter->priority;
627bab16ddaSBernard Iremonger pattern_ipv4_5tuple[1] = ipv4_sctp_item;
628bab16ddaSBernard Iremonger pattern_ipv4_5tuple[2] = sctp_item;
629bab16ddaSBernard Iremonger break;
630bab16ddaSBernard Iremonger default:
631bab16ddaSBernard Iremonger return ret;
632bab16ddaSBernard Iremonger }
633bab16ddaSBernard Iremonger
634bab16ddaSBernard Iremonger attr.ingress = 1;
635bab16ddaSBernard Iremonger pattern_ipv4_5tuple[0] = eth_item;
636bab16ddaSBernard Iremonger pattern_ipv4_5tuple[3] = end_item;
637bab16ddaSBernard Iremonger actions[0] = count_action;
638bab16ddaSBernard Iremonger actions[1] = end_action;
639bab16ddaSBernard Iremonger
64050bdac59SJasvinder Singh /* Validate and add rule */
64150bdac59SJasvinder Singh ret = rte_flow_classify_validate(cls_app->cls, &attr,
64250bdac59SJasvinder Singh pattern_ipv4_5tuple, actions, &error);
64350bdac59SJasvinder Singh if (ret) {
64450bdac59SJasvinder Singh printf("table entry validate failed ipv4_proto = %u\n",
64550bdac59SJasvinder Singh ipv4_proto);
64650bdac59SJasvinder Singh return ret;
64750bdac59SJasvinder Singh }
64850bdac59SJasvinder Singh
649bab16ddaSBernard Iremonger rule = rte_flow_classify_table_entry_add(
65050bdac59SJasvinder Singh cls_app->cls, &attr, pattern_ipv4_5tuple,
65150bdac59SJasvinder Singh actions, &key_found, &error);
652bab16ddaSBernard Iremonger if (rule == NULL) {
653bab16ddaSBernard Iremonger printf("table entry add failed ipv4_proto = %u\n",
654bab16ddaSBernard Iremonger ipv4_proto);
655bab16ddaSBernard Iremonger ret = -1;
656bab16ddaSBernard Iremonger return ret;
657bab16ddaSBernard Iremonger }
658bab16ddaSBernard Iremonger
659bab16ddaSBernard Iremonger rules[num_classify_rules] = rule;
660bab16ddaSBernard Iremonger num_classify_rules++;
661bab16ddaSBernard Iremonger return 0;
662bab16ddaSBernard Iremonger }
663bab16ddaSBernard Iremonger
6649a212dc0SConor Fogarty /* Reads file and calls the add_classify_rule function. 8< */
665bab16ddaSBernard Iremonger static int
add_rules(const char * rule_path,struct flow_classifier * cls_app)666bab16ddaSBernard Iremonger add_rules(const char *rule_path, struct flow_classifier *cls_app)
667bab16ddaSBernard Iremonger {
668bab16ddaSBernard Iremonger FILE *fh;
669bab16ddaSBernard Iremonger char buff[LINE_MAX];
670bab16ddaSBernard Iremonger unsigned int i = 0;
671bab16ddaSBernard Iremonger unsigned int total_num = 0;
672bab16ddaSBernard Iremonger struct rte_eth_ntuple_filter ntuple_filter;
673c044ffaaSBernard Iremonger int ret;
674bab16ddaSBernard Iremonger
675bab16ddaSBernard Iremonger fh = fopen(rule_path, "rb");
676bab16ddaSBernard Iremonger if (fh == NULL)
677c044ffaaSBernard Iremonger rte_exit(EXIT_FAILURE, "%s: fopen %s failed\n", __func__,
678bab16ddaSBernard Iremonger rule_path);
679bab16ddaSBernard Iremonger
680c044ffaaSBernard Iremonger ret = fseek(fh, 0, SEEK_SET);
681c044ffaaSBernard Iremonger if (ret)
682c044ffaaSBernard Iremonger rte_exit(EXIT_FAILURE, "%s: fseek %d failed\n", __func__,
683c044ffaaSBernard Iremonger ret);
684bab16ddaSBernard Iremonger
685bab16ddaSBernard Iremonger i = 0;
686bab16ddaSBernard Iremonger while (fgets(buff, LINE_MAX, fh) != NULL) {
687bab16ddaSBernard Iremonger i++;
688bab16ddaSBernard Iremonger
689bab16ddaSBernard Iremonger if (is_bypass_line(buff))
690bab16ddaSBernard Iremonger continue;
691bab16ddaSBernard Iremonger
692bab16ddaSBernard Iremonger if (total_num >= FLOW_CLASSIFY_MAX_RULE_NUM - 1) {
693bab16ddaSBernard Iremonger printf("\nINFO: classify rule capacity %d reached\n",
694bab16ddaSBernard Iremonger total_num);
695bab16ddaSBernard Iremonger break;
696bab16ddaSBernard Iremonger }
697bab16ddaSBernard Iremonger
698bab16ddaSBernard Iremonger if (parse_ipv4_5tuple_rule(buff, &ntuple_filter) != 0)
699bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE,
700bab16ddaSBernard Iremonger "%s Line %u: parse rules error\n",
701bab16ddaSBernard Iremonger rule_path, i);
702bab16ddaSBernard Iremonger
703bab16ddaSBernard Iremonger if (add_classify_rule(&ntuple_filter, cls_app) != 0)
704bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "add rule error\n");
705bab16ddaSBernard Iremonger
706bab16ddaSBernard Iremonger total_num++;
707bab16ddaSBernard Iremonger }
708bab16ddaSBernard Iremonger
709bab16ddaSBernard Iremonger fclose(fh);
710bab16ddaSBernard Iremonger return 0;
711bab16ddaSBernard Iremonger }
7129a212dc0SConor Fogarty /* >8 End of add_rules. */
713bab16ddaSBernard Iremonger
714bab16ddaSBernard Iremonger /* display usage */
715bab16ddaSBernard Iremonger static void
print_usage(const char * prgname)716bab16ddaSBernard Iremonger print_usage(const char *prgname)
717bab16ddaSBernard Iremonger {
718bab16ddaSBernard Iremonger printf("%s usage:\n", prgname);
719bab16ddaSBernard Iremonger printf("[EAL options] -- --"OPTION_RULE_IPV4"=FILE: ");
720bab16ddaSBernard Iremonger printf("specify the ipv4 rules file.\n");
721bab16ddaSBernard Iremonger printf("Each rule occupies one line in the file.\n");
722bab16ddaSBernard Iremonger }
723bab16ddaSBernard Iremonger
724bab16ddaSBernard Iremonger /* Parse the argument given in the command line of the application */
725bab16ddaSBernard Iremonger static int
parse_args(int argc,char ** argv)726bab16ddaSBernard Iremonger parse_args(int argc, char **argv)
727bab16ddaSBernard Iremonger {
728bab16ddaSBernard Iremonger int opt, ret;
729bab16ddaSBernard Iremonger char **argvopt;
730bab16ddaSBernard Iremonger int option_index;
731bab16ddaSBernard Iremonger char *prgname = argv[0];
732bab16ddaSBernard Iremonger static struct option lgopts[] = {
733bab16ddaSBernard Iremonger {OPTION_RULE_IPV4, 1, 0, 0},
734bab16ddaSBernard Iremonger {NULL, 0, 0, 0}
735bab16ddaSBernard Iremonger };
736bab16ddaSBernard Iremonger
737bab16ddaSBernard Iremonger argvopt = argv;
738bab16ddaSBernard Iremonger
739bab16ddaSBernard Iremonger while ((opt = getopt_long(argc, argvopt, "",
740bab16ddaSBernard Iremonger lgopts, &option_index)) != EOF) {
741bab16ddaSBernard Iremonger
742bab16ddaSBernard Iremonger switch (opt) {
743bab16ddaSBernard Iremonger /* long options */
744bab16ddaSBernard Iremonger case 0:
745bab16ddaSBernard Iremonger if (!strncmp(lgopts[option_index].name,
746bab16ddaSBernard Iremonger OPTION_RULE_IPV4,
747bab16ddaSBernard Iremonger sizeof(OPTION_RULE_IPV4)))
748bab16ddaSBernard Iremonger parm_config.rule_ipv4_name = optarg;
749bab16ddaSBernard Iremonger break;
750bab16ddaSBernard Iremonger default:
751bab16ddaSBernard Iremonger print_usage(prgname);
752bab16ddaSBernard Iremonger return -1;
753bab16ddaSBernard Iremonger }
754bab16ddaSBernard Iremonger }
755bab16ddaSBernard Iremonger
756bab16ddaSBernard Iremonger if (optind >= 0)
757bab16ddaSBernard Iremonger argv[optind-1] = prgname;
758bab16ddaSBernard Iremonger
759bab16ddaSBernard Iremonger ret = optind-1;
760bab16ddaSBernard Iremonger optind = 1; /* reset getopt lib */
761bab16ddaSBernard Iremonger return ret;
762bab16ddaSBernard Iremonger }
763bab16ddaSBernard Iremonger
764bab16ddaSBernard Iremonger /*
765bab16ddaSBernard Iremonger * The main function, which does initialization and calls the lcore_main
766bab16ddaSBernard Iremonger * function.
767bab16ddaSBernard Iremonger */
768bab16ddaSBernard Iremonger int
main(int argc,char * argv[])769bab16ddaSBernard Iremonger main(int argc, char *argv[])
770bab16ddaSBernard Iremonger {
771bab16ddaSBernard Iremonger struct rte_mempool *mbuf_pool;
772d9a42a69SThomas Monjalon uint16_t nb_ports;
7738728ccf3SThomas Monjalon uint16_t portid;
774bab16ddaSBernard Iremonger int ret;
775bab16ddaSBernard Iremonger int socket_id;
776bab16ddaSBernard Iremonger struct rte_table_acl_params table_acl_params;
777bab16ddaSBernard Iremonger struct rte_flow_classify_table_params cls_table_params;
778bab16ddaSBernard Iremonger struct flow_classifier *cls_app;
779bab16ddaSBernard Iremonger struct rte_flow_classifier_params cls_params;
780bab16ddaSBernard Iremonger uint32_t size;
781bab16ddaSBernard Iremonger
7829a212dc0SConor Fogarty /* Initialize the Environment Abstraction Layer (EAL). 8< */
783bab16ddaSBernard Iremonger ret = rte_eal_init(argc, argv);
784bab16ddaSBernard Iremonger if (ret < 0)
785bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
7869a212dc0SConor Fogarty /* >8 End of initialization of EAL. */
787bab16ddaSBernard Iremonger
788bab16ddaSBernard Iremonger argc -= ret;
789bab16ddaSBernard Iremonger argv += ret;
790bab16ddaSBernard Iremonger
7919a212dc0SConor Fogarty /* Parse application arguments (after the EAL ones). 8< */
792bab16ddaSBernard Iremonger ret = parse_args(argc, argv);
793bab16ddaSBernard Iremonger if (ret < 0)
794bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Invalid flow_classify parameters\n");
7959a212dc0SConor Fogarty /* >8 End of parse application arguments. */
796bab16ddaSBernard Iremonger
797bab16ddaSBernard Iremonger /* Check that there is an even number of ports to send/receive on. */
798d9a42a69SThomas Monjalon nb_ports = rte_eth_dev_count_avail();
799bab16ddaSBernard Iremonger if (nb_ports < 2 || (nb_ports & 1))
800bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n");
801bab16ddaSBernard Iremonger
8029a212dc0SConor Fogarty /* Creates a new mempool in memory to hold the mbufs. 8< */
803bab16ddaSBernard Iremonger mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
804bab16ddaSBernard Iremonger MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
8059a212dc0SConor Fogarty /* >8 End of creation of new mempool in memory. */
806bab16ddaSBernard Iremonger
807bab16ddaSBernard Iremonger if (mbuf_pool == NULL)
808bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
809bab16ddaSBernard Iremonger
8109a212dc0SConor Fogarty /* Initialize all ports. 8< */
8118728ccf3SThomas Monjalon RTE_ETH_FOREACH_DEV(portid)
812bab16ddaSBernard Iremonger if (port_init(portid, mbuf_pool) != 0)
813bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu8 "\n",
814bab16ddaSBernard Iremonger portid);
8159a212dc0SConor Fogarty /* >8 End of initialization of all ports. */
816bab16ddaSBernard Iremonger
817bab16ddaSBernard Iremonger if (rte_lcore_count() > 1)
818bab16ddaSBernard Iremonger printf("\nWARNING: Too many lcores enabled. Only 1 used.\n");
819bab16ddaSBernard Iremonger
820bab16ddaSBernard Iremonger socket_id = rte_eth_dev_socket_id(0);
821bab16ddaSBernard Iremonger
8229a212dc0SConor Fogarty /* Memory allocation. 8< */
823bab16ddaSBernard Iremonger size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct flow_classifier_acl));
824bab16ddaSBernard Iremonger cls_app = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
825bab16ddaSBernard Iremonger if (cls_app == NULL)
826bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Cannot allocate classifier memory\n");
827bab16ddaSBernard Iremonger
828bab16ddaSBernard Iremonger cls_params.name = "flow_classifier";
829bab16ddaSBernard Iremonger cls_params.socket_id = socket_id;
830bab16ddaSBernard Iremonger
831bab16ddaSBernard Iremonger cls_app->cls = rte_flow_classifier_create(&cls_params);
832bab16ddaSBernard Iremonger if (cls_app->cls == NULL) {
833bab16ddaSBernard Iremonger rte_free(cls_app);
834bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Cannot create classifier\n");
835bab16ddaSBernard Iremonger }
836bab16ddaSBernard Iremonger
837bab16ddaSBernard Iremonger /* initialise ACL table params */
838bab16ddaSBernard Iremonger table_acl_params.name = "table_acl_ipv4_5tuple";
839bab16ddaSBernard Iremonger table_acl_params.n_rules = FLOW_CLASSIFY_MAX_RULE_NUM;
840bab16ddaSBernard Iremonger table_acl_params.n_rule_fields = RTE_DIM(ipv4_defs);
841bab16ddaSBernard Iremonger memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
842bab16ddaSBernard Iremonger
843bab16ddaSBernard Iremonger /* initialise table create params */
84450bdac59SJasvinder Singh cls_table_params.ops = &rte_table_acl_ops;
84550bdac59SJasvinder Singh cls_table_params.arg_create = &table_acl_params;
84650bdac59SJasvinder Singh cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
847bab16ddaSBernard Iremonger
84850bdac59SJasvinder Singh ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params);
849bab16ddaSBernard Iremonger if (ret) {
850bab16ddaSBernard Iremonger rte_flow_classifier_free(cls_app->cls);
851bab16ddaSBernard Iremonger rte_free(cls_app);
852bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Failed to create classifier table\n");
853bab16ddaSBernard Iremonger }
8549a212dc0SConor Fogarty /* >8 End of initialization of table create params. */
855bab16ddaSBernard Iremonger
856bab16ddaSBernard Iremonger /* read file of IPv4 5 tuple rules and initialize parameters
857bab16ddaSBernard Iremonger * for rte_flow_classify_validate and rte_flow_classify_table_entry_add
858bab16ddaSBernard Iremonger * API's.
859bab16ddaSBernard Iremonger */
8609a212dc0SConor Fogarty
8619a212dc0SConor Fogarty /* Read file of IPv4 tuple rules. 8< */
862bab16ddaSBernard Iremonger if (add_rules(parm_config.rule_ipv4_name, cls_app)) {
863bab16ddaSBernard Iremonger rte_flow_classifier_free(cls_app->cls);
864bab16ddaSBernard Iremonger rte_free(cls_app);
865bab16ddaSBernard Iremonger rte_exit(EXIT_FAILURE, "Failed to add rules\n");
866bab16ddaSBernard Iremonger }
8679a212dc0SConor Fogarty /* >8 End of reading file of IPv4 5 tuple rules. */
868bab16ddaSBernard Iremonger
869cb056611SStephen Hemminger /* Call lcore_main on the main core only. */
870bab16ddaSBernard Iremonger lcore_main(cls_app);
871bab16ddaSBernard Iremonger
87210aa3757SChengchang Tang /* clean up the EAL */
87310aa3757SChengchang Tang rte_eal_cleanup();
87410aa3757SChengchang Tang
875bab16ddaSBernard Iremonger return 0;
876bab16ddaSBernard Iremonger }
877