2 Copyright(c) 2017 Intel Corporation. All rights reserved.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in
13 the documentation and/or other materials provided with the
15 * Neither the name of Intel Corporation nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 Flow Classify Sample Application
32 ================================
34 The Flow Classify sample application is based on the simple *skeleton* example
35 of a forwarding application.
37 It is intended as a demonstration of the basic components of a DPDK forwarding
38 application which uses the Flow Classify library API's.
41 :doc:`../prog_guide/flow_classify_lib`
44 Compiling the Application
45 -------------------------
47 To compile the sample application see :doc:`compiling`.
49 The application is located in the ``flow_classify`` sub-directory.
51 Running the Application
52 -----------------------
54 To run the example in a ``linuxapp`` environment:
56 .. code-block:: console
58 cd ~/dpdk/examples/flow_classify
59 ./build/flow_classify -c 4 -n 4 -- --rule_ipv4="../ipv4_rules_file.txt"
61 Please refer to the *DPDK Getting Started Guide*, section
62 :doc:`../linux_gsg/build_sample_apps`
63 for general information on running applications and the Environment Abstraction
67 Sample ipv4_rules_file.txt
68 --------------------------
70 .. code-block:: console
73 #src_ip/masklen dst_ip/masklen src_port : mask dst_port : mask proto/mask priority
75 2.2.2.3/24 2.2.2.7/24 32 : 0xffff 33 : 0xffff 17/0xff 0
76 9.9.9.3/24 9.9.9.7/24 32 : 0xffff 33 : 0xffff 17/0xff 1
77 9.9.9.3/24 9.9.9.7/24 32 : 0xffff 33 : 0xffff 6/0xff 2
78 9.9.8.3/24 9.9.8.7/24 32 : 0xffff 33 : 0xffff 6/0xff 3
79 6.7.8.9/24 2.3.4.5/24 32 : 0x0000 33 : 0x0000 132/0xff 4
84 The following sections provide an explanation of the main components of the
87 All DPDK library functions used in the sample code are prefixed with ``rte_``
88 and are explained in detail in the *DPDK API Documentation*.
90 ACL field definitions for the IPv4 5 tuple rule
91 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
93 The following field definitions are used when creating the ACL table during
94 initialisation of the ``Flow Classify`` application..
111 SRCP_DESTP_INPUT_IPV4
114 static struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
115 /* first input field - always one byte long. */
117 .type = RTE_ACL_FIELD_TYPE_BITMASK,
118 .size = sizeof(uint8_t),
119 .field_index = PROTO_FIELD_IPV4,
120 .input_index = PROTO_INPUT_IPV4,
121 .offset = sizeof(struct ether_hdr) +
122 offsetof(struct ipv4_hdr, next_proto_id),
124 /* next input field (IPv4 source address) - 4 consecutive bytes. */
126 /* rte_flow uses a bit mask for IPv4 addresses */
127 .type = RTE_ACL_FIELD_TYPE_BITMASK,
128 .size = sizeof(uint32_t),
129 .field_index = SRC_FIELD_IPV4,
130 .input_index = SRC_INPUT_IPV4,
131 .offset = sizeof(struct ether_hdr) +
132 offsetof(struct ipv4_hdr, src_addr),
134 /* next input field (IPv4 destination address) - 4 consecutive bytes. */
136 /* rte_flow uses a bit mask for IPv4 addresses */
137 .type = RTE_ACL_FIELD_TYPE_BITMASK,
138 .size = sizeof(uint32_t),
139 .field_index = DST_FIELD_IPV4,
140 .input_index = DST_INPUT_IPV4,
141 .offset = sizeof(struct ether_hdr) +
142 offsetof(struct ipv4_hdr, dst_addr),
145 * Next 2 fields (src & dst ports) form 4 consecutive bytes.
146 * They share the same input index.
149 /* rte_flow uses a bit mask for protocol ports */
150 .type = RTE_ACL_FIELD_TYPE_BITMASK,
151 .size = sizeof(uint16_t),
152 .field_index = SRCP_FIELD_IPV4,
153 .input_index = SRCP_DESTP_INPUT_IPV4,
154 .offset = sizeof(struct ether_hdr) +
155 sizeof(struct ipv4_hdr) +
156 offsetof(struct tcp_hdr, src_port),
159 /* rte_flow uses a bit mask for protocol ports */
160 .type = RTE_ACL_FIELD_TYPE_BITMASK,
161 .size = sizeof(uint16_t),
162 .field_index = DSTP_FIELD_IPV4,
163 .input_index = SRCP_DESTP_INPUT_IPV4,
164 .offset = sizeof(struct ether_hdr) +
165 sizeof(struct ipv4_hdr) +
166 offsetof(struct tcp_hdr, dst_port),
173 The ``main()`` function performs the initialization and calls the execution
174 threads for each lcore.
176 The first task is to initialize the Environment Abstraction Layer (EAL).
177 The ``argc`` and ``argv`` arguments are provided to the ``rte_eal_init()``
178 function. The value returned is the number of parsed arguments:
182 int ret = rte_eal_init(argc, argv);
184 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
186 It then parses the flow_classify application arguments
190 ret = parse_args(argc, argv);
192 rte_exit(EXIT_FAILURE, "Invalid flow_classify parameters\n");
194 The ``main()`` function also allocates a mempool to hold the mbufs
195 (Message Buffers) used by the application:
199 mbuf_pool = rte_mempool_create("MBUF_POOL",
200 NUM_MBUFS * nb_ports,
203 sizeof(struct rte_pktmbuf_pool_private),
204 rte_pktmbuf_pool_init, NULL,
205 rte_pktmbuf_init, NULL,
209 mbufs are the packet buffer structure used by DPDK. They are explained in
210 detail in the "Mbuf Library" section of the *DPDK Programmer's Guide*.
212 The ``main()`` function also initializes all the ports using the user defined
213 ``port_init()`` function which is explained in the next section:
217 for (portid = 0; portid < nb_ports; portid++) {
218 if (port_init(portid, mbuf_pool) != 0) {
219 rte_exit(EXIT_FAILURE,
220 "Cannot init port %" PRIu8 "\n", portid);
224 The ``main()`` function creates the ``flow classifier object`` and adds an ``ACL
225 table`` to the flow classifier.
229 struct flow_classifier {
230 struct rte_flow_classifier *cls;
233 struct flow_classifier_acl {
234 struct flow_classifier cls;
235 } __rte_cache_aligned;
237 /* Memory allocation */
238 size = RTE_CACHE_LINE_ROUNDUP(sizeof(struct flow_classifier_acl));
239 cls_app = rte_zmalloc(NULL, size, RTE_CACHE_LINE_SIZE);
241 rte_exit(EXIT_FAILURE, "Cannot allocate classifier memory\n");
243 cls_params.name = "flow_classifier";
244 cls_params.socket_id = socket_id;
246 cls_app->cls = rte_flow_classifier_create(&cls_params);
247 if (cls_app->cls == NULL) {
249 rte_exit(EXIT_FAILURE, "Cannot create classifier\n");
252 /* initialise ACL table params */
253 table_acl_params.name = "table_acl_ipv4_5tuple";
254 table_acl_params.n_rule_fields = RTE_DIM(ipv4_defs);
255 table_acl_params.n_rules = FLOW_CLASSIFY_MAX_RULE_NUM;
256 memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
258 /* initialise table create params */
259 cls_table_params.ops = &rte_table_acl_ops,
260 cls_table_params.arg_create = &table_acl_params,
261 cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
263 ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params);
265 rte_flow_classifier_free(cls_app->cls);
267 rte_exit(EXIT_FAILURE, "Failed to create classifier table\n");
270 It then reads the ipv4_rules_file.txt file and initialises the parameters for
271 the ``rte_flow_classify_table_entry_add`` API.
272 This API adds a rule to the ACL table.
276 if (add_rules(parm_config.rule_ipv4_name)) {
277 rte_flow_classifier_free(cls_app->cls);
279 rte_exit(EXIT_FAILURE, "Failed to add rules\n");
282 Once the initialization is complete, the application is ready to launch a
283 function on an lcore. In this example ``lcore_main()`` is called on a single
290 The ``lcore_main()`` function is explained below.
292 The Port Initialization Function
293 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
295 The main functional part of the port initialization used in the Basic
296 Forwarding application is shown below:
301 port_init(uint8_t port, struct rte_mempool *mbuf_pool)
303 struct rte_eth_conf port_conf = port_conf_default;
304 const uint16_t rx_rings = 1, tx_rings = 1;
305 struct ether_addr addr;
309 if (port >= rte_eth_dev_count())
312 /* Configure the Ethernet device. */
313 retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
317 /* Allocate and set up 1 RX queue per Ethernet port. */
318 for (q = 0; q < rx_rings; q++) {
319 retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE,
320 rte_eth_dev_socket_id(port), NULL, mbuf_pool);
325 /* Allocate and set up 1 TX queue per Ethernet port. */
326 for (q = 0; q < tx_rings; q++) {
327 retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE,
328 rte_eth_dev_socket_id(port), NULL);
333 /* Start the Ethernet port. */
334 retval = rte_eth_dev_start(port);
338 /* Display the port MAC address. */
339 rte_eth_macaddr_get(port, &addr);
340 printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8
341 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n",
343 addr.addr_bytes[0], addr.addr_bytes[1],
344 addr.addr_bytes[2], addr.addr_bytes[3],
345 addr.addr_bytes[4], addr.addr_bytes[5]);
347 /* Enable RX in promiscuous mode for the Ethernet device. */
348 rte_eth_promiscuous_enable(port);
353 The Ethernet ports are configured with default settings using the
354 ``rte_eth_dev_configure()`` function and the ``port_conf_default`` struct.
358 static const struct rte_eth_conf port_conf_default = {
359 .rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN }
362 For this example the ports are set up with 1 RX and 1 TX queue using the
363 ``rte_eth_rx_queue_setup()`` and ``rte_eth_tx_queue_setup()`` functions.
365 The Ethernet port is then started:
369 retval = rte_eth_dev_start(port);
372 Finally the RX port is set in promiscuous mode:
376 rte_eth_promiscuous_enable(port);
378 The Add Rules function
379 ~~~~~~~~~~~~~~~~~~~~~~
381 The ``add_rules`` function reads the ``ipv4_rules_file.txt`` file and calls the
382 ``add_classify_rule`` function which calls the
383 ``rte_flow_classify_table_entry_add`` API.
388 add_rules(const char *rule_path)
393 unsigned int total_num = 0;
394 struct rte_eth_ntuple_filter ntuple_filter;
396 fh = fopen(rule_path, "rb");
398 rte_exit(EXIT_FAILURE, "%s: Open %s failed\n", __func__,
401 fseek(fh, 0, SEEK_SET);
404 while (fgets(buff, LINE_MAX, fh) != NULL) {
407 if (is_bypass_line(buff))
410 if (total_num >= FLOW_CLASSIFY_MAX_RULE_NUM - 1) {
411 printf("\nINFO: classify rule capacity %d reached\n",
416 if (parse_ipv4_5tuple_rule(buff, &ntuple_filter) != 0)
417 rte_exit(EXIT_FAILURE,
418 "%s Line %u: parse rules error\n",
421 if (add_classify_rule(&ntuple_filter) != 0)
422 rte_exit(EXIT_FAILURE, "add rule error\n");
432 The Lcore Main function
433 ~~~~~~~~~~~~~~~~~~~~~~~
435 As we saw above the ``main()`` function calls an application function on the
437 The ``lcore_main`` function calls the ``rte_flow_classifier_query`` API.
438 For the Basic Forwarding application the ``lcore_main`` function looks like the
443 /* flow classify data */
444 static int num_classify_rules;
445 static struct rte_flow_classify_rule *rules[MAX_NUM_CLASSIFY];
446 static struct rte_flow_classify_ipv4_5tuple_stats ntuple_stats;
447 static struct rte_flow_classify_stats classify_stats = {
448 .stats = (void *)&ntuple_stats
451 static __attribute__((noreturn)) void
454 const uint8_t nb_ports = rte_eth_dev_count();
458 * Check that the port is on the same NUMA node as the polling thread
459 * for best performance.
461 for (port = 0; port < nb_ports; port++)
462 if (rte_eth_dev_socket_id(port) > 0 &&
463 rte_eth_dev_socket_id(port) != (int)rte_socket_id()) {
465 printf("WARNING: port %u is on remote NUMA node\n",
467 printf("to polling thread.\n");
468 printf("Performance will not be optimal.\n");
470 printf("\nCore %u forwarding packets. \n",
472 printf("[Ctrl+C to quit]\n
475 /* Run until the application is quit or killed. */
478 * Receive packets on a port and forward them on the paired
479 * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
481 for (port = 0; port < nb_ports; port++) {
483 /* Get burst of RX packets, from first port of pair. */
484 struct rte_mbuf *bufs[BURST_SIZE];
485 const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
488 if (unlikely(nb_rx == 0))
491 for (i = 0; i < MAX_NUM_CLASSIFY; i++) {
493 ret = rte_flow_classifier_query(
495 bufs, nb_rx, rules[i],
499 "rule [%d] query failed ret [%d]\n\n",
503 "rule[%d] count=%"PRIu64"\n",
504 i, ntuple_stats.counter1);
506 printf("proto = %d\n",
507 ntuple_stats.ipv4_5tuple.proto);
512 /* Send burst of TX packets, to second port of pair. */
513 const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
516 /* Free any unsent packets. */
517 if (unlikely(nb_tx < nb_rx)) {
519 for (buf = nb_tx; buf < nb_rx; buf++)
520 rte_pktmbuf_free(bufs[buf]);
526 The main work of the application is done within the loop:
531 for (port = 0; port < nb_ports; port++) {
533 /* Get burst of RX packets, from first port of pair. */
534 struct rte_mbuf *bufs[BURST_SIZE];
535 const uint16_t nb_rx = rte_eth_rx_burst(port, 0,
538 if (unlikely(nb_rx == 0))
541 /* Send burst of TX packets, to second port of pair. */
542 const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0,
545 /* Free any unsent packets. */
546 if (unlikely(nb_tx < nb_rx)) {
548 for (buf = nb_tx; buf < nb_rx; buf++)
549 rte_pktmbuf_free(bufs[buf]);
554 Packets are received in bursts on the RX ports and transmitted in bursts on
555 the TX ports. The ports are grouped in pairs with a simple mapping scheme
556 using the an XOR on the port number::
566 The ``rte_eth_tx_burst()`` function frees the memory buffers of packets that
567 are transmitted. If packets fail to transmit, ``(nb_tx < nb_rx)``, then they
568 must be freed explicitly using ``rte_pktmbuf_free()``.
570 The forwarding loop can be interrupted and the application closed using