[dpdk-dev] [RFC v1] examples/flow_filtering: demo of simple rte flow

Ori Kam orika at mellanox.com
Thu Aug 24 13:52:28 CEST 2017


This application shows a simple usage of the
rte_flow API for hardware filtering offloading.

In this demo we are filtering specific IP to
specific target queue, while sending all the
rest of the packets to other queue.

Included in this commit is a simple python
script file for sending custom packets.

Signed-off-by: Ori Kam <orika at mellanox.com>
---
 examples/flow_filtering/Makefile            |  17 ++
 examples/flow_filtering/flow_blocks.c       | 122 +++++++++++++++
 examples/flow_filtering/main.c              | 233 ++++++++++++++++++++++++++++
 examples/flow_filtering/test-flowy.scapy.py |  28 ++++
 4 files changed, 400 insertions(+)
 create mode 100644 examples/flow_filtering/Makefile
 create mode 100644 examples/flow_filtering/flow_blocks.c
 create mode 100644 examples/flow_filtering/main.c
 create mode 100755 examples/flow_filtering/test-flowy.scapy.py

diff --git a/examples/flow_filtering/Makefile b/examples/flow_filtering/Makefile
new file mode 100644
index 0000000..6e5295d
--- /dev/null
+++ b/examples/flow_filtering/Makefile
@@ -0,0 +1,17 @@
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overridden by command line or environment
+RTE_TARGET ?= x86_64-native-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+APP = flow
+
+SRCS-y := main.c
+
+CFLAGS += -g3
+CFLAGS += $(WERROR_FLAGS)
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/flow_filtering/flow_blocks.c b/examples/flow_filtering/flow_blocks.c
new file mode 100644
index 0000000..cb8b06d
--- /dev/null
+++ b/examples/flow_filtering/flow_blocks.c
@@ -0,0 +1,122 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2017 Mellanox.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of 6WIND S.A. nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define MAX_PATTERN_NUM		4
+
+
+static struct rte_flow *
+generate_ipv4_rule(uint8_t port_id, uint16_t rx_q,
+		uint32_t src_ip, uint32_t src_mask,
+		uint32_t dest_ip, uint32_t dest_mask)
+{
+	struct rte_flow_attr attr;
+	struct rte_flow_item pattern[MAX_PATTERN_NUM];
+	struct rte_flow_action action[MAX_PATTERN_NUM];
+	struct rte_flow *flow;
+	struct rte_flow_error error;
+
+	memset(pattern, 0, sizeof(pattern));
+	memset(action, 0, sizeof(action));
+
+	/*
+	 * create the action sequence.
+	 * one action only,  move packet to queue
+	 */
+	struct rte_flow_action_queue queue = { .index = rx_q };
+
+	action[0].type = RTE_FLOW_ACTION_TYPE_QUEUE;
+	action[0].conf = &queue;
+
+	action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+	/*
+	 * set the rule attribute.
+	 * in this case only ingress packets will be checked.
+	 */
+	memset(&attr, 0, sizeof(struct rte_flow_attr));
+	attr.ingress = 1;
+
+	/*
+	 * set the first level of the pattern (eth).
+	 * since in this example we just want to get the
+	 * ipv4 we set this level to allow all.
+	 */
+	struct rte_flow_item_eth eth_spec;
+	struct rte_flow_item_eth eth_mask;
+	memset(&eth_spec, 0, sizeof(struct rte_flow_item_eth));
+	memset(&eth_mask, 0, sizeof(struct rte_flow_item_eth));
+	eth_spec.type = 0;
+	eth_mask.type = 0;
+	pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+	pattern[0].spec = &eth_spec;
+	pattern[0].mask = &eth_mask;
+
+	/*
+	 * setting the second level of the pattern (vlan).
+	 * since in this example we just want to get the
+	 * ipv4 we also set this level to allow all.
+	 */
+	struct rte_flow_item_vlan vlan_spec;
+	struct rte_flow_item_vlan vlan_mask;
+	memset(&vlan_spec, 0, sizeof(struct rte_flow_item_vlan));
+	memset(&vlan_mask, 0, sizeof(struct rte_flow_item_vlan));
+	pattern[1].type = RTE_FLOW_ITEM_TYPE_VLAN;
+	pattern[1].spec = &vlan_spec;
+	pattern[1].mask = &vlan_mask;
+
+	/*
+	 * setting the third level of the pattern (ip).
+	 * in this example this is the level we care about
+	 * so we set it according to the parameters.
+	 */
+	struct rte_flow_item_ipv4 ip_spec;
+	struct rte_flow_item_ipv4 ip_mask;
+	memset(&ip_spec, 0, sizeof(struct rte_flow_item_ipv4));
+	memset(&ip_mask, 0, sizeof(struct rte_flow_item_ipv4));
+	ip_spec.hdr.dst_addr = htonl(dest_ip);
+	ip_mask.hdr.dst_addr = dest_mask;
+	ip_spec.hdr.src_addr = htonl(src_ip);
+	ip_mask.hdr.src_addr = src_mask;
+	pattern[2].type = RTE_FLOW_ITEM_TYPE_IPV4;
+	pattern[2].spec = &ip_spec;
+	pattern[2].mask = &ip_mask;
+
+	/* the final level must be always type end */
+	pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+
+	int res = rte_flow_validate(port_id, &attr, pattern, action, &error);
+	printf("\nrule validation result = %d\n", res);
+	flow = rte_flow_create(port_id, &attr, pattern, action, &error);
+
+	return flow;
+}
+
diff --git a/examples/flow_filtering/main.c b/examples/flow_filtering/main.c
new file mode 100644
index 0000000..733d008
--- /dev/null
+++ b/examples/flow_filtering/main.c
@@ -0,0 +1,233 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2017 Mellanox.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of 6WIND S.A. nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdbool.h>
+
+#include <rte_eal.h>
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_mempool.h>
+#include <rte_mbuf.h>
+#include <rte_net.h>
+#include <rte_flow.h>
+
+static volatile bool force_quit;
+
+static uint8_t port_id;
+static uint16_t nr_queues = 5;
+static uint8_t selected_queue = 1;
+struct rte_mempool *mbuf_pool;
+
+#include "flow_blocks.c"
+
+static inline void
+print_ether_addr(const char *what, struct ether_addr *eth_addr)
+{
+	char buf[ETHER_ADDR_FMT_SIZE];
+	ether_format_addr(buf, ETHER_ADDR_FMT_SIZE, eth_addr);
+	printf("%s%s", what, buf);
+}
+
+static void
+main_loop(void)
+{
+	struct rte_mbuf *mbufs[32];
+	struct ether_hdr *eth_hdr;
+	uint16_t nb_rx;
+	uint16_t i;
+	uint16_t j;
+
+	while (!force_quit) {
+		for (i = 0; i < nr_queues; i++) {
+			nb_rx = rte_eth_rx_burst(port_id,
+						i, mbufs, 32);
+			if (nb_rx) {
+				for (j = 0; j < nb_rx; j++) {
+					struct rte_mbuf *m = mbufs[j];
+
+					eth_hdr = rte_pktmbuf_mtod(m,
+							struct ether_hdr *);
+					print_ether_addr("src=",
+							&eth_hdr->s_addr);
+					print_ether_addr(" - dst=",
+							&eth_hdr->d_addr);
+					printf(" - queue=0x%x",
+							(unsigned int)i);
+					printf("\n");
+
+					rte_pktmbuf_free(m);
+				}
+			}
+		}
+	}
+
+	/* closing and releasing resources */
+	rte_eth_dev_stop(port_id);
+	rte_eth_dev_close(port_id);
+}
+
+static void
+assert_link_status(void)
+{
+	struct rte_eth_link link;
+
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get(port_id, &link);
+	if (link.link_status == ETH_LINK_DOWN)
+		rte_exit(EXIT_FAILURE, ":: error: link is still down\n");
+}
+
+static void
+init_port(void)
+{
+	int ret;
+	uint16_t i;
+	struct rte_eth_conf port_conf = {
+		.rxmode = {
+			.split_hdr_size = 0,
+			/**< Header Split disabled */
+			.header_split   = 0,
+			/**< IP checksum offload disabled */
+			.hw_ip_checksum = 0,
+			/**< VLAN filtering disabled */
+			.hw_vlan_filter = 0,
+			/**< Jumbo Frame Support disabled */
+			.jumbo_frame    = 0,
+			/**< CRC stripped by hardware */
+			.hw_strip_crc   = 1,
+		},
+	};
+
+	printf(":: initializing port: %d\n", port_id);
+	ret = rte_eth_dev_configure(port_id,
+				nr_queues, nr_queues, &port_conf);
+	if (ret < 0) {
+		rte_exit(EXIT_FAILURE,
+			":: cannot configure device: err=%d, port=%u\n",
+			ret, port_id);
+	}
+
+	/* only set Rx queues: something we care only so far */
+	for (i = 0; i < nr_queues; i++) {
+		ret = rte_eth_rx_queue_setup(port_id, i, 512,
+				     rte_eth_dev_socket_id(port_id),
+				     NULL,
+				     mbuf_pool);
+		if (ret < 0) {
+			rte_exit(EXIT_FAILURE,
+				":: Rx queue setup failed: err=%d, port=%u\n",
+				ret, port_id);
+		}
+	}
+
+	/*
+	 * create rule for send packet with
+	 * destination ip  = 192.168.1.1  to queue number 1
+	 */
+	generate_ipv4_rule(port_id, selected_queue,
+				0x0, 0x0,
+				0xc0a80101, 0xffffffff);
+
+	rte_eth_promiscuous_enable(port_id);
+
+	ret = rte_eth_dev_start(port_id);
+	if (ret < 0) {
+		rte_exit(EXIT_FAILURE,
+			"rte_eth_dev_start:err=%d, port=%u\n",
+			ret, port_id);
+	}
+
+	assert_link_status();
+
+	printf(":: initializing port: %d done\n", port_id);
+}
+
+static void
+signal_handler(int signum)
+{
+	if (signum == SIGINT || signum == SIGTERM) {
+		printf("\n\nSignal %d received, preparing to exit...\n",
+				signum);
+		force_quit = true;
+	}
+}
+
+int
+main(int argc, char **argv)
+{
+	int ret;
+	uint8_t nr_ports;
+
+	ret = rte_eal_init(argc, argv);
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, ":: invalid EAL arguments\n");
+
+	force_quit = false;
+	signal(SIGINT, signal_handler);
+	signal(SIGTERM, signal_handler);
+
+	nr_ports = rte_eth_dev_count();
+	if (nr_ports == 0)
+		rte_exit(EXIT_FAILURE, ":: no Ethernet ports found\n");
+	port_id = 0;
+	if (nr_ports != 1) {
+		printf(":: warn: %d ports detected, but we use only one: port %u\n",
+			nr_ports, port_id);
+	}
+	mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", 4096, 128, 0,
+					    RTE_MBUF_DEFAULT_BUF_SIZE,
+					    rte_socket_id());
+	if (mbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n");
+
+	init_port();
+
+	main_loop();
+
+	return 0;
+}
diff --git a/examples/flow_filtering/test-flowy.scapy.py b/examples/flow_filtering/test-flowy.scapy.py
new file mode 100755
index 0000000..46758ed
--- /dev/null
+++ b/examples/flow_filtering/test-flowy.scapy.py
@@ -0,0 +1,28 @@
+#!/usr/bin/python
+
+import sys
+import getopt
+from scapy.all import *
+
+def main(argv):
+	interface_id = None
+
+	try:
+		opts, args = getopt.getopt(argv,"hi:",["interface="])
+	except getopt.GetoptError:
+		print('test-flowy.scapy.py -i <interface>')
+		sys.exit(2)
+	for opt, arg in opts:
+		if opt == '-i':
+			interface_id = arg
+	if interface_id == None:
+		print('test-flowy.scapy.py -i <interface>')
+		sys.exit(2)
+
+	for i in range (1, 7):
+		ip = "192.168.1." + str(i)
+		p = Ether(src="02:00:00:01:02:3" + str(i), dst="24:8a:07:8d:ae:ae")/Dot1Q(vlan = 0x123)/IP(dst = ip)
+		sendp(p, iface = interface_id, count=1)
+
+if __name__ == "__main__":
+	main(sys.argv[1:])
-- 
1.8.3.1



More information about the dev mailing list