Skip to content

Commit

Permalink
net/tap: add basic flow API patterns and actions
Browse files Browse the repository at this point in the history
Supported flow rules are now mapped to TC rules on the tap netdevice.
The netlink message used for creating the TC rule is stored in struct
rte_flow. That way, by simply changing a metadata in it, we can require
for the rule deletion without further parsing.

Supported items:
- eth: src and dst (with variable masks), and eth_type (0xffff mask).
- vlan: vid, pcp, tpid, but not eid.
- ipv4/6: src and dst (with variable masks), and ip_proto (0xffff mask).
- udp/tcp: src and dst port (0xffff) mask.

Supported actions:
- DROP
- QUEUE
- PASSTHRU

It is generally not possible to provide a "last" item. However, if the
"last" item, once masked, is identical to the masked spec, then it is
supported.

Only IPv4/6 and MAC addresses can use a variable mask. All other
items need a full mask (exact match).

Support for VLAN requires kernel headers >= 4.9, checked using
auto-config.sh.

Signed-off-by: Pascal Mazon <pascal.mazon@6wind.com>
Acked-by: Olga Shern <olgas@mellanox.com>
Acked-by: Keith Wiles <keith.wiles@intel.com>
  • Loading branch information
Pascal Mazon authored and Ferruh Yigit committed Apr 4, 2017
1 parent 7c25284 commit de96fe6
Show file tree
Hide file tree
Showing 6 changed files with 1,057 additions and 15 deletions.
45 changes: 45 additions & 0 deletions doc/guides/nics/tap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,51 @@ can utilize that stack to handle the network protocols. Plus you would be able
to address the interface using an IP address assigned to the internal
interface.

Flow API support
----------------

The tap PMD supports major flow API pattern items and actions, when running on
linux kernels above 4.2 ("Flower" classifier required). Supported items:

- eth: src and dst (with variable masks), and eth_type (0xffff mask).
- vlan: vid, pcp, tpid, but not eid. (requires kernel 4.9)
- ipv4/6: src and dst (with variable masks), and ip_proto (0xffff mask).
- udp/tcp: src and dst port (0xffff) mask.

Supported actions:

- DROP
- QUEUE
- PASSTHRU

It is generally not possible to provide a "last" item. However, if the "last"
item, once masked, is identical to the masked spec, then it is supported.

Only IPv4/6 and MAC addresses can use a variable mask. All other items need a
full mask (exact match).

As rules are translated to TC, it is possible to show them with something like::

tc -s filter show dev tap1 parent 1:

Examples of testpmd flow rules
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Drop packets for destination IP 192.168.0.1::

testpmd> flow create 0 priority 1 ingress pattern eth / ipv4 dst is 1.1.1.1 \
/ end actions drop / end

Ensure packets from a given MAC address are received on a queue 2::

testpmd> flow create 0 priority 2 ingress pattern eth src is 06:05:04:03:02:01 \
/ end actions queue index 2 / end

Drop UDP packets in vlan 3::

testpmd> flow create 0 priority 3 ingress pattern eth / vlan vid is 3 / \
ipv4 proto is 17 / end actions drop / end

Example
-------

Expand Down
40 changes: 40 additions & 0 deletions drivers/net/tap/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ LIBABIVER := 1

CFLAGS += -O3
CFLAGS += -I$(SRCDIR)
CFLAGS += -I.
CFLAGS += $(WERROR_FLAGS)

#
Expand All @@ -58,5 +59,44 @@ DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_mempool
DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_ether
DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_kvargs
DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_net
DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_TAP) += lib/librte_hash

include $(RTE_SDK)/mk/rte.lib.mk

# Generate and clean-up tap_autoconf.h.

export CC CFLAGS CPPFLAGS EXTRA_CFLAGS EXTRA_CPPFLAGS
export AUTO_CONFIG_CFLAGS = -Wno-error

ifndef V
AUTOCONF_OUTPUT := >/dev/null
endif

tap_autoconf.h.new: FORCE

tap_autoconf.h.new: $(RTE_SDK)/buildtools/auto-config-h.sh
$Q $(RM) -f -- '$@'
$Q sh -- '$<' '$@' \
HAVE_TC_FLOWER \
linux/pkt_cls.h \
enum TCA_FLOWER_UNSPEC \
$(AUTOCONF_OUTPUT)
$Q sh -- '$<' '$@' \
HAVE_TC_VLAN_ID \
linux/pkt_cls.h \
enum TCA_FLOWER_KEY_VLAN_PRIO \
$(AUTOCONF_OUTPUT)

# Create tap_autoconf.h or update it in case it differs from the new one.

tap_autoconf.h: tap_autoconf.h.new
$Q [ -f '$@' ] && \
cmp '$<' '$@' $(AUTOCONF_OUTPUT) || \
mv '$<' '$@'

$(SRCS-$(CONFIG_RTE_LIBRTE_PMD_TAP):.c=.o): tap_autoconf.h

clean_tap: FORCE
$Q rm -f -- tap_autoconf.h tap_autoconf.h.new

clean: clean_tap
61 changes: 59 additions & 2 deletions drivers/net/tap/rte_eth_tap.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,22 @@
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <sys/mman.h>
#include <errno.h>
#include <signal.h>
#include <stdint.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <linux/if.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <linux/if_ether.h>
#include <linux/version.h>
#include <fcntl.h>

#include <rte_eth_tap.h>
#include <tap_flow.h>
#include <tap_tcmsgs.h>

/* Linux based path to the TUN device */
#define TUN_TAP_DEV_PATH "/dev/net/tun"
Expand All @@ -71,6 +74,9 @@
#define RTE_PMD_TAP_MAX_QUEUES 1
#endif

#define FLOWER_KERNEL_VERSION KERNEL_VERSION(4, 2, 0)
#define FLOWER_VLAN_KERNEL_VERSION KERNEL_VERSION(4, 9, 0)

static struct rte_vdev_driver pmd_tap_drv;

static const char *valid_arguments[] = {
Expand Down Expand Up @@ -209,6 +215,28 @@ tun_alloc(struct pmd_internals *pmd, uint16_t qid)
goto error;
rte_memcpy(&pmd->eth_addr, ifr.ifr_hwaddr.sa_data,
ETHER_ADDR_LEN);

pmd->if_index = if_nametoindex(pmd->name);
if (!pmd->if_index) {
RTE_LOG(ERR, PMD,
"Could not find ifindex for %s: rte_flow won't be usable.\n",
pmd->name);
return fd;
}
if (!pmd->flower_support)
return fd;
if (qdisc_create_multiq(pmd->nlsk_fd, pmd->if_index) < 0) {
RTE_LOG(ERR, PMD,
"Could not create multiq qdisc for %s: rte_flow won't be usable.\n",
pmd->name);
return fd;
}
if (qdisc_create_ingress(pmd->nlsk_fd, pmd->if_index) < 0) {
RTE_LOG(ERR, PMD,
"Could not create multiq qdisc for %s: rte_flow won't be usable.\n",
pmd->name);
return fd;
}
}

return fd;
Expand Down Expand Up @@ -811,6 +839,24 @@ static const struct eth_dev_ops ops = {
.filter_ctrl = tap_dev_filter_ctrl,
};

static int
tap_kernel_support(struct pmd_internals *pmd)
{
struct utsname utsname;
int ver[3];

if (uname(&utsname) == -1 ||
sscanf(utsname.release, "%d.%d.%d",
&ver[0], &ver[1], &ver[2]) != 3)
return 0;
if (KERNEL_VERSION(ver[0], ver[1], ver[2]) >= FLOWER_KERNEL_VERSION)
pmd->flower_support = 1;
if (KERNEL_VERSION(ver[0], ver[1], ver[2]) >=
FLOWER_VLAN_KERNEL_VERSION)
pmd->flower_vlan_support = 1;
return 1;
}

static int
eth_dev_tap_create(const char *name, char *tap_name)
{
Expand Down Expand Up @@ -880,7 +926,15 @@ eth_dev_tap_create(const char *name, char *tap_name)
pmd->txq[i].fd = -1;
}

tap_kernel_support(pmd);
if (!pmd->flower_support)
return 0;
LIST_INIT(&pmd->flows);
/*
* If no netlink socket can be created, then it will fail when
* creating/destroying flow rules.
*/
pmd->nlsk_fd = nl_init();

return 0;

Expand Down Expand Up @@ -995,7 +1049,10 @@ rte_pmd_tap_remove(const char *name)
return 0;

internals = eth_dev->data->dev_private;
tap_flow_flush(eth_dev, NULL);
if (internals->flower_support && internals->nlsk_fd) {
tap_flow_flush(eth_dev, NULL);
nl_final(internals->nlsk_fd);
}
for (i = 0; i < internals->nb_queues; i++)
if (internals->rxq[i].fd != -1)
close(internals->rxq[i].fd);
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/tap/rte_eth_tap.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ struct pmd_internals {
struct ether_addr eth_addr; /* Mac address of the device port */
int if_index; /* IF_INDEX for the port */
int ioctl_sock; /* socket for ioctl calls */
int nlsk_fd; /* Netlink socket fd */
int flower_support; /* 1 if kernel supports, else 0 */
int flower_vlan_support; /* 1 if kernel supports, else 0 */
LIST_HEAD(tap_flows, rte_flow) flows; /* rte_flow rules */
struct rx_queue rxq[RTE_PMD_TAP_MAX_QUEUES]; /* List of RX queues */
struct tx_queue txq[RTE_PMD_TAP_MAX_QUEUES]; /* List of TX queues */
Expand Down
Loading

0 comments on commit de96fe6

Please sign in to comment.