Skip to contentSkip to conversation

net/tap: remote netdevice traffic capture

PATCH Superseded Pascal Mazon 3 participants 24 messages Mar 3, 2017 – Mar 24, 2017 Network drivers

lore
Share & tools
lore
#0 lore raw

cover net/tap: remote netdevice traffic capture

This patchset adds the special "remote" feature to the tap PMD, that actually enables capturing traffic from another netdevice. This is especially useful to get packets into the DPDK app, when the remote netdevice has no DPDK support.

The "remote" feature requires flow API support as flow rules will be configured on the remote netdevice for redirection, using the same mechanism.

This series applies on top of:

[PATCH 0/4] net/tap: support flow API

Pascal Mazon (4):
net/tap: add remote netdevice traffic capture net/tap: reflect tap flags on the remote net/tap: use the remote MAC address if available net/tap: set MTU on the remote

 doc/guides/nics/tap.rst       |  17 ++
 drivers/net/tap/rte_eth_tap.c | 212 ++++++++++++++++++---
 drivers/net/tap/tap.h         |   4 +
 drivers/net/tap/tap_flow.c    | 414 ++++++++++++++++++++++++++++++++++++++++--
 drivers/net/tap/tap_flow.h    |  24 +++
 5 files changed, 631 insertions(+), 40 deletions(-)
Signature · 1 line
2.8.0.rc0
#1 lore raw

PATCH 1/4 net/tap: add remote netdevice traffic capture

By default, a tap netdevice is of no use when not fed by a separate process. The ability to automatically feed it from another netdevice allows applications to capture any kind of traffic normally destined to the kernel stack.

This patch implements this ability through a new optional "remote" parameter.

Packets matching filtering rules created with the flow API are matched on the remote device and redirected to the tap PMD, where the relevant action will be performed.

---
 doc/guides/nics/tap.rst       |  17 ++
 drivers/net/tap/rte_eth_tap.c |  78 +++++++-
 drivers/net/tap/tap.h         |   3 +
 drivers/net/tap/tap_flow.c    | 414 ++++++++++++++++++++++++++++++++++++++++--
 drivers/net/tap/tap_flow.h    |  24 +++
 5 files changed, 523 insertions(+), 13 deletions(-)
doc/guides/nics/tap.rst +17 -0
index c4f207be3b47..a937f018f7b5 100644
@@ -58,6 +58,23 @@ needed, but the interface does not enforce that speed, for example::
 
    --vdev=net_tap0,iface=foo0,speed=25000
 
+It is possible to specify a remote netdevice to capture packets from by adding
+``remote=foo1``, for example::
+
+   --vdev=net_tap,iface=tap0,remote=foo1
+
+If a ``remote`` is set, then all packets with the tap PMD's local MAC coming
+in on the remote netdevice will be redirected to the tap.
+If the tap is in promiscuous mode, then all packets will be redirected.
+In allmulti mode, all multicast packets will be redirected.
+It is possible to add explicit rte_flow rules on the tap PMD to capture specific
+traffic. For instance, in testpmd, the following rte_flow rule would capture
+packets with the given MAC address from the remote, and send it to the tap RX
+QUEUE 3::
+
+   testpmd> flow create 0 ingress pattern eth src is 02:03:04:05:06:07 / \
+            end actions queue index 3 / end
+
 After the DPDK application is started you can send and receive packets on the
 interface using the standard rx_burst/tx_burst APIs in DPDK. From the host
 point of view you can use any host tool like tcpdump, Wireshark, ping, Pktgen
drivers/net/tap/rte_eth_tap.c +76 -2

165 lines not on this page · raw message

drivers/net/tap/tap.h +3 -0
index 96d9025412b3..a5f83d4feea3 100644
@@ -68,7 +68,10 @@ struct pmd_internals {
 	uint16_t nb_queues; /* Number of queues supported */
 	struct ether_addr eth_addr; /* Mac address of the device port */
 	int if_index; /* IF_INDEX for the port */
+	int remote_if_index; /* remote netdevice IF_INDEX */
 	LIST_HEAD(tap_flows, rte_flow) flows; /* rte_flow rules */
+	/* implicit rte_flow rules set when a remote device is active */
+	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
 	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 */
 };
drivers/net/tap/tap_flow.c +403 -11

520 lines not on this page · raw message

drivers/net/tap/tap_flow.h +24 -0
index a05e945df523..0134cdbaeb90 100644
@@ -36,6 +36,7 @@
 
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
+#include <tap.h>
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -49,10 +50,33 @@
 #define GROUP_SHIFT 12
 #define MAX_GROUP GROUP_MASK
 
+/**
+ * These index are actually in reversed order: their priority is processed
+ * by subtracting their value to the lowest priority (PRIORITY_MASK).
+ * Thus the first one will have the lowest priority in the end
+ * (but biggest value).
+ */
+enum implicit_rule_index {
+	TAP_REMOTE_TX,
+	TAP_REMOTE_BROADCASTV6,
+	TAP_REMOTE_BROADCAST,
+	TAP_REMOTE_ALLMULTI,
+	TAP_REMOTE_PROMISC,
+	TAP_REMOTE_LOCAL_MAC,
+	TAP_REMOTE_MAX_IDX,
+};
+
 int tap_dev_filter_ctrl(struct rte_eth_dev *dev,
 			enum rte_filter_type filter_type,
 			enum rte_filter_op filter_op,
 			void *arg);
 int tap_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error);
 
+int tap_flow_implicit_create(struct pmd_internals *pmd,
+			     enum implicit_rule_index idx);
+int tap_flow_implicit_destroy(struct rte_eth_dev *dev,
+			      enum implicit_rule_index idx);
+int tap_flow_implicit_flush(struct rte_eth_dev *dev,
+			    struct rte_flow_error *error);
+
 #endif /* _TAP_FLOW_H_ */
Signature · 1 line
2.8.0.rc0
#2 lore raw

PATCH 2/4 net/tap: reflect tap flags on the remote

In reply to Pascal Mazon

Synchronize PROMISC and ALLMULTI flags to the remote netdevice if possible.

Leave the IFF_UP flag as it is, however.

---
 drivers/net/tap/rte_eth_tap.c | 36 +++++++++++++++++++++++-------------
 drivers/net/tap/tap.h         |  1 +
 2 files changed, 24 insertions(+), 13 deletions(-)
drivers/net/tap/rte_eth_tap.c +23 -13
index 327fefd0d3a1..c77f206b4f60 100644
@@ -249,7 +249,7 @@ pmd_tx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 }
 
 static int
-tap_link_set_flags(struct pmd_internals *pmd, short flags, int add)
+tap_netdev_set_flags(const char *iface, short flags, int add)
 {
 	struct ifreq ifr;
 	int err, s;
@@ -266,11 +266,11 @@ tap_link_set_flags(struct pmd_internals *pmd, short flags, int add)
 		return -1;
 	}
 	memset(&ifr, 0, sizeof(ifr));
-	snprintf(ifr.ifr_name, IFNAMSIZ, "%s", pmd->name);
+	snprintf(ifr.ifr_name, IFNAMSIZ, "%s", iface);
 	err = ioctl(s, SIOCGIFFLAGS, &ifr);
 	if (err < 0) {
 		RTE_LOG(WARNING, PMD, "Unable to get %s device flags: %s\n",
-			pmd->name, strerror(errno));
+			iface, strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -288,6 +288,7 @@ tap_link_set_flags(struct pmd_internals *pmd, short flags, int add)
 	close(s);
 
 	return 0;
+
 }
 
 static int
@@ -296,7 +297,7 @@ tap_link_set_down(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->dev_link.link_status = ETH_LINK_DOWN;
-	return tap_link_set_flags(pmd, IFF_UP | IFF_NOARP, 0);
+	return tap_netdev_set_flags(pmd->name, IFF_UP | IFF_NOARP, 0);
 }
 
 static int
@@ -305,7 +306,7 @@ tap_link_set_up(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->dev_link.link_status = ETH_LINK_UP;
-	return tap_link_set_flags(pmd, IFF_UP | IFF_NOARP, 1);
+	return tap_netdev_set_flags(pmd->name, IFF_UP | IFF_NOARP, 1);
 }
 
 static int
@@ -476,9 +477,11 @@ tap_promisc_enable(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->promiscuous = 1;
-	tap_link_set_flags(pmd, IFF_PROMISC, 1);
-	if (pmd->remote_if_index)
+	tap_netdev_set_flags(pmd->name, IFF_PROMISC, 1);
+	if (pmd->remote_if_index) {
 		tap_flow_implicit_create(pmd, TAP_REMOTE_PROMISC);
+		tap_netdev_set_flags(pmd->remote_iface, IFF_PROMISC, 1);
+	}
 }
 
 static void
@@ -487,9 +490,11 @@ tap_promisc_disable(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->promiscuous = 0;
-	tap_link_set_flags(pmd, IFF_PROMISC, 0);
-	if (pmd->remote_if_index)
+	tap_netdev_set_flags(pmd->name, IFF_PROMISC, 0);
+	if (pmd->remote_if_index) {
 		tap_flow_implicit_destroy(dev, TAP_REMOTE_PROMISC);
+		tap_netdev_set_flags(pmd->remote_iface, IFF_PROMISC, 0);
+	}
 }
 
 static void
@@ -498,9 +503,11 @@ tap_allmulti_enable(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->all_multicast = 1;
-	tap_link_set_flags(pmd, IFF_ALLMULTI, 1);
-	if (pmd->remote_if_index)
+	tap_netdev_set_flags(pmd->name, IFF_ALLMULTI, 1);
+	if (pmd->remote_if_index) {
 		tap_flow_implicit_create(pmd, TAP_REMOTE_ALLMULTI);
+		tap_netdev_set_flags(pmd->remote_iface, IFF_ALLMULTI, 1);
+	}
 }
 
 static void
@@ -509,9 +516,11 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->all_multicast = 0;
-	tap_link_set_flags(pmd, IFF_ALLMULTI, 0);
-	if (pmd->remote_if_index)
+	tap_netdev_set_flags(pmd->name, IFF_ALLMULTI, 0);
+	if (pmd->remote_if_index) {
 		tap_flow_implicit_destroy(dev, TAP_REMOTE_ALLMULTI);
+		tap_netdev_set_flags(pmd->remote_iface, IFF_ALLMULTI, 0);
+	}
 }
 
 static void
@@ -924,6 +933,7 @@ eth_dev_tap_create(const char *name, char *tap_name, char *remote_iface)
 	 */
 	pmd->nlsk_fd = nl_init();
 	if (strlen(remote_iface)) {
+		strncpy(pmd->remote_iface, remote_iface, RTE_ETH_NAME_MAX_LEN);
 		pmd->remote_if_index = if_nametoindex(remote_iface);
 		if (!pmd->remote_if_index)
 			RTE_LOG(ERR, PMD, "Could not find %s ifindex: "
drivers/net/tap/tap.h +1 -0
index a5f83d4feea3..2afd0f9a4a58 100644
@@ -64,6 +64,7 @@ struct tx_queue {
 
 struct pmd_internals {
 	char name[RTE_ETH_NAME_MAX_LEN]; /* Internal Tap device name */
+	char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */
 	int nlsk_fd; /* Netlink socket fd */
 	uint16_t nb_queues; /* Number of queues supported */
 	struct ether_addr eth_addr; /* Mac address of the device port */
Signature · 1 line
2.8.0.rc0
#3 lore raw

PATCH 3/4 net/tap: use the remote MAC address if available

In reply to Pascal Mazon

The remote on a tap is most likely used with netdevices that are not under DPDK control. Outgoing traffic is supposed to use the source MAC address of the remote netdevice.

This commit synchronizes the MAC address of the local tap netdevice with the remote one.

Of course, it is still possible to change the tap MAC address, using standard DPDK APIs. It sets that MAC address on the tap PMD and redirect any packets matching that destination MAC to the tap PMD. It also tries setting the MAC address directly on the remote, if supported, through ioctl() calls.

---
 drivers/net/tap/rte_eth_tap.c | 77 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 65 insertions(+), 12 deletions(-)
drivers/net/tap/rte_eth_tap.c +65 -12
index c77f206b4f60..98b466aba223 100644
@@ -523,6 +523,65 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 	}
 }
 
+static int
+tap_netdev_set_mac(const char *iface, struct ether_addr *mac_addr)
+{
+	struct ifreq ifr;
+	int err, s;
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s < 0) {
+		RTE_LOG(ERR, PMD,
+			"Unable to get a socket to get MAC: %s\n",
+			strerror(errno));
+		return -1;
+	}
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, iface, IFNAMSIZ);
+	err = ioctl(s, SIOCGIFHWADDR, &ifr);
+	if (err < 0) {
+		RTE_LOG(ERR, PMD, "%s: couldn't get current MAC address (%s)\n",
+			iface, strerror(errno));
+		close(s);
+		return -1;
+	}
+	rte_memcpy(ifr.ifr_hwaddr.sa_data, mac_addr, ETHER_ADDR_LEN);
+	err = ioctl(s, SIOCSIFHWADDR, &ifr) == -1;
+	close(s);
+	if (err < 0) {
+		RTE_LOG(ERR, PMD, "%s: couldn't set current MAC address (%s)\n",
+			iface, strerror(errno));
+		return -1;
+	}
+	return 0;
+}
+
+static int
+tap_netdev_get_mac(const char *iface, struct ether_addr *mac_addr)
+{
+	struct ifreq ifr;
+	int err, s;
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s < 0) {
+		RTE_LOG(ERR, PMD,
+			"Unable to get a socket to get MAC: %s\n",
+			strerror(errno));
+		return -1;
+	}
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, iface, IFNAMSIZ);
+	err = ioctl(s, SIOCGIFHWADDR, &ifr);
+	close(s);
+	if (err < 0) {
+		RTE_LOG(ERR, PMD, "%s: couldn't get MAC address (%s)\n",
+			iface, strerror(errno));
+		return -1;
+	}
+	rte_memcpy(mac_addr, ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
+	return 0;
+}
+
 static void
 tap_mac_remove(struct rte_eth_dev *dev __rte_unused,
 	       uint32_t index __rte_unused)
@@ -539,7 +598,6 @@ tap_mac_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 {
 	struct pmd_internals *internals = dev->data->dev_private;
 	int fd = internals->rxq[0].fd;
-	struct ifreq ifr;
 
 	if (index > RTE_PMD_TAP_MAX_MAC_ADDRS - 1) {
 		RTE_LOG(ERR, PMD,
@@ -559,19 +617,11 @@ tap_mac_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 			dev->data->name);
 		return;
 	}
-	memset(&ifr, 0, sizeof(struct ifreq));
-	if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) {
-		RTE_LOG(ERR, PMD, "%s: couldn't get current MAC address (%s)\n",
-			dev->data->name, strerror(errno));
+	if (tap_netdev_set_mac(internals->name, mac_addr) < 0)
 		return;
-	}
-	rte_memcpy(ifr.ifr_hwaddr.sa_data, mac_addr, ETHER_ADDR_LEN);
-	if (ioctl(fd, SIOCSIFHWADDR, &ifr) == -1) {
-		RTE_LOG(ERR, PMD, "%s: couldn't set current MAC address (%s)\n",
-			dev->data->name, strerror(errno));
-		return;
-	}
 	rte_memcpy(&dev->data->mac_addrs[index], mac_addr, ETHER_ADDR_LEN);
+	if (internals->remote_if_index)
+		tap_netdev_set_mac(internals->remote_iface, mac_addr);
 }
 
 static void
@@ -939,6 +989,9 @@ eth_dev_tap_create(const char *name, char *tap_name, char *remote_iface)
 			RTE_LOG(ERR, PMD, "Could not find %s ifindex: "
 				"remote interface will remain unconfigured\n",
 				remote_iface);
+		else
+			/* Set the local mac address to the remote mac */
+			tap_netdev_get_mac(remote_iface, &pmd->eth_addr);
 	}
 
 	return 0;
Signature · 1 line
2.8.0.rc0
#4 lore raw

PATCH 4/4 net/tap: set MTU on the remote

In reply to Pascal Mazon
---
 drivers/net/tap/rte_eth_tap.c | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)
drivers/net/tap/rte_eth_tap.c +23 -6
index 98b466aba223..141fc7944a5f 100644
@@ -823,9 +823,8 @@ tap_set_mc_addr_list(struct rte_eth_dev *dev __rte_unused,
 }
 
 static int
-tap_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+tap_netdev_mtu_set(const char *iface, uint16_t mtu)
 {
-	struct pmd_internals *pmd = dev->data->dev_private;
 	struct ifreq ifr;
 	int err, s;
 
@@ -833,15 +832,15 @@ tap_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 	if (s < 0) {
 		RTE_LOG(ERR, PMD,
 			"Unable to get a socket for %s to set flags: %s\n",
-			pmd->name, strerror(errno));
+			iface, strerror(errno));
 		return -1;
 	}
 	memset(&ifr, 0, sizeof(ifr));
-	strncpy(ifr.ifr_name, pmd->name, IFNAMSIZ);
+	strncpy(ifr.ifr_name, iface, IFNAMSIZ);
 	err = ioctl(s, SIOCGIFMTU, &ifr);
 	if (err < 0) {
 		RTE_LOG(WARNING, PMD, "Unable to get %s device MTU: %s\n",
-			pmd->name, strerror(errno));
+			iface, strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -849,11 +848,29 @@ tap_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 	err = ioctl(s, SIOCSIFMTU, &ifr);
 	if (err < 0) {
 		RTE_LOG(WARNING, PMD, "Unable to set %s mtu %d: %s\n",
-			pmd->name, mtu, strerror(errno));
+			iface, mtu, strerror(errno));
 		close(s);
 		return -1;
 	}
 	close(s);
+	return 0;
+}
+
+static int
+tap_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+{
+	struct pmd_internals *pmd = dev->data->dev_private;
+	int err;
+
+	/* First try to set mtu on the remote */
+	if (pmd->remote_if_index) {
+		err = tap_netdev_mtu_set(pmd->remote_iface, mtu);
+		if (err < 0)
+			return err;
+	}
+	err = tap_netdev_mtu_set(pmd->name, mtu);
+	if (err < 0)
+		return err;
 	dev->data->mtu = mtu;
 	return 0;
 }
Signature · 1 line
2.8.0.rc0
#5 lore raw
In reply to Pascal Mazon
Quoted 22 lines · Pascal Mazon

This patchset adds the special "remote" feature to the tap PMD, that actually enables capturing traffic from another netdevice. This is especially useful to get packets into the DPDK app, when the remote netdevice has no DPDK support.

The "remote" feature requires flow API support as flow rules will be configured on the remote netdevice for redirection, using the same mechanism.

This series applies on top of:

[PATCH 0/4] net/tap: support flow API

Pascal Mazon (4):
net/tap: add remote netdevice traffic capture
net/tap: reflect tap flags on the remote
net/tap: use the remote MAC address if available
net/tap: set MTU on the remote

Quoted 6 lines
doc/guides/nics/tap.rst       |  17 ++
drivers/net/tap/rte_eth_tap.c | 212 ++++++++++++++++++---
drivers/net/tap/tap.h         |   4 +
drivers/net/tap/tap_flow.c    | 414 ++++++++++++++++++++++++++++++++++++++++--
drivers/net/tap/tap_flow.h    |  24 +++
5 files changed, 631 insertions(+), 40 deletions(-)

Ah here is the tap.rst change, thanks.

Quoted 4 lines
Signature · 2 lines
-- 
2.8.0.rc0

Regards,
Keith

#6 lore raw

v2 cover remote netdevice traffic capture

In reply to Pascal Mazon

This patchset adds the special "remote" feature to the tap PMD, that actually enables capturing traffic from another netdevice. This is especially useful to get packets into the DPDK app, when the remote netdevice has no DPDK support.

The "remote" feature requires flow API support as flow rules will be configured on the remote netdevice for redirection, using the same mechanism.

This series applies on top of:

[PATCH 0/4] net/tap: support flow API

v2 changes:
- rebase on top of updated "net/tap: support flow API"
- fix implicit flow flush when closing the netdevices

Pascal Mazon (4):
net/tap: add remote netdevice traffic capture net/tap: reflect tap flags on the remote net/tap: use the remote MAC address if available net/tap: set MTU on the remote

 doc/guides/nics/tap.rst       |  17 ++
 drivers/net/tap/rte_eth_tap.c | 213 ++++++++++++++++++---
 drivers/net/tap/tap.h         |   4 +
 drivers/net/tap/tap_flow.c    | 418 ++++++++++++++++++++++++++++++++++++++++--
 drivers/net/tap/tap_flow.h    |  24 +++
 5 files changed, 635 insertions(+), 41 deletions(-)
Signature · 1 line
2.8.0.rc0
#7 lore raw

PATCH v2 1/4 net/tap: add remote netdevice traffic capture

By default, a tap netdevice is of no use when not fed by a separate process. The ability to automatically feed it from another netdevice allows applications to capture any kind of traffic normally destined to the kernel stack.

This patch implements this ability through a new optional "remote" parameter.

Packets matching filtering rules created with the flow API are matched on the remote device and redirected to the tap PMD, where the relevant action will be performed.

---
 doc/guides/nics/tap.rst       |  17 ++
 drivers/net/tap/rte_eth_tap.c |  79 +++++++-
 drivers/net/tap/tap.h         |   2 +
 drivers/net/tap/tap_flow.c    | 418 ++++++++++++++++++++++++++++++++++++++++--
 drivers/net/tap/tap_flow.h    |  24 +++
 5 files changed, 526 insertions(+), 14 deletions(-)
doc/guides/nics/tap.rst +17 -0
index cdb528b5eae4..676a569b00ca 100644
@@ -58,6 +58,23 @@ needed, but the interface does not enforce that speed, for example::
 
    --vdev=net_tap0,iface=foo0,speed=25000
 
+It is possible to specify a remote netdevice to capture packets from by adding
+``remote=foo1``, for example::
+
+   --vdev=net_tap,iface=tap0,remote=foo1
+
+If a ``remote`` is set, then all packets with the tap PMD's local MAC coming
+in on the remote netdevice will be redirected to the tap.
+If the tap is in promiscuous mode, then all packets will be redirected.
+In allmulti mode, all multicast packets will be redirected.
+It is possible to add explicit rte_flow rules on the tap PMD to capture specific
+traffic. For instance, in testpmd, the following rte_flow rule would capture
+packets with the given MAC address from the remote, and send it to the tap RX
+QUEUE 3::
+
+   testpmd> flow create 0 ingress pattern eth src is 02:03:04:05:06:07 / \
+            end actions queue index 3 / end
+
 After the DPDK application is started you can send and receive packets on the
 interface using the standard rx_burst/tx_burst APIs in DPDK. From the host
 point of view you can use any host tool like tcpdump, Wireshark, ping, Pktgen
drivers/net/tap/rte_eth_tap.c +77 -2

172 lines not on this page · raw message

drivers/net/tap/tap.h +2 -0
index 2c8cc7d5b485..4c4de939f1cc 100644
@@ -71,6 +71,8 @@ struct pmd_internals {
 	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 */
+	/* implicit rte_flow rules set when a remote device is active */
+	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
 	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 */
 };
drivers/net/tap/tap_flow.c +406 -12

527 lines not on this page · raw message

drivers/net/tap/tap_flow.h +24 -0
index a05e945df523..0134cdbaeb90 100644
@@ -36,6 +36,7 @@
 
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
+#include <tap.h>
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -49,10 +50,33 @@
 #define GROUP_SHIFT 12
 #define MAX_GROUP GROUP_MASK
 
+/**
+ * These index are actually in reversed order: their priority is processed
+ * by subtracting their value to the lowest priority (PRIORITY_MASK).
+ * Thus the first one will have the lowest priority in the end
+ * (but biggest value).
+ */
+enum implicit_rule_index {
+	TAP_REMOTE_TX,
+	TAP_REMOTE_BROADCASTV6,
+	TAP_REMOTE_BROADCAST,
+	TAP_REMOTE_ALLMULTI,
+	TAP_REMOTE_PROMISC,
+	TAP_REMOTE_LOCAL_MAC,
+	TAP_REMOTE_MAX_IDX,
+};
+
 int tap_dev_filter_ctrl(struct rte_eth_dev *dev,
 			enum rte_filter_type filter_type,
 			enum rte_filter_op filter_op,
 			void *arg);
 int tap_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error);
 
+int tap_flow_implicit_create(struct pmd_internals *pmd,
+			     enum implicit_rule_index idx);
+int tap_flow_implicit_destroy(struct rte_eth_dev *dev,
+			      enum implicit_rule_index idx);
+int tap_flow_implicit_flush(struct rte_eth_dev *dev,
+			    struct rte_flow_error *error);
+
 #endif /* _TAP_FLOW_H_ */
Signature · 1 line
2.8.0.rc0
#8 lore raw

PATCH v2 2/4 net/tap: reflect tap flags on the remote

In reply to Pascal Mazon

Synchronize PROMISC and ALLMULTI flags to the remote netdevice if possible.

Leave the IFF_UP flag as it is, however.

---
 drivers/net/tap/rte_eth_tap.c | 36 +++++++++++++++++++++++-------------
 drivers/net/tap/tap.h         |  2 ++
 2 files changed, 25 insertions(+), 13 deletions(-)
drivers/net/tap/rte_eth_tap.c +23 -13
index b29cfbfb41f3..ded8bb0f18d9 100644
@@ -254,7 +254,7 @@ pmd_tx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 }
 
 static int
-tap_link_set_flags(struct pmd_internals *pmd, short flags, int add)
+tap_netdev_set_flags(const char *iface, short flags, int add)
 {
 	struct ifreq ifr;
 	int err, s;
@@ -271,11 +271,11 @@ tap_link_set_flags(struct pmd_internals *pmd, short flags, int add)
 		return -1;
 	}
 	memset(&ifr, 0, sizeof(ifr));
-	snprintf(ifr.ifr_name, IFNAMSIZ, "%s", pmd->name);
+	snprintf(ifr.ifr_name, IFNAMSIZ, "%s", iface);
 	err = ioctl(s, SIOCGIFFLAGS, &ifr);
 	if (err < 0) {
 		RTE_LOG(WARNING, PMD, "Unable to get %s device flags: %s\n",
-			pmd->name, strerror(errno));
+			iface, strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -293,6 +293,7 @@ tap_link_set_flags(struct pmd_internals *pmd, short flags, int add)
 	close(s);
 
 	return 0;
+
 }
 
 static int
@@ -301,7 +302,7 @@ tap_link_set_down(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->dev_link.link_status = ETH_LINK_DOWN;
-	return tap_link_set_flags(pmd, IFF_UP | IFF_NOARP, 0);
+	return tap_netdev_set_flags(pmd->name, IFF_UP | IFF_NOARP, 0);
 }
 
 static int
@@ -310,7 +311,7 @@ tap_link_set_up(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->dev_link.link_status = ETH_LINK_UP;
-	return tap_link_set_flags(pmd, IFF_UP | IFF_NOARP, 1);
+	return tap_netdev_set_flags(pmd->name, IFF_UP | IFF_NOARP, 1);
 }
 
 static int
@@ -482,9 +483,11 @@ tap_promisc_enable(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->promiscuous = 1;
-	tap_link_set_flags(pmd, IFF_PROMISC, 1);
-	if (pmd->remote_if_index)
+	tap_netdev_set_flags(pmd->name, IFF_PROMISC, 1);
+	if (pmd->remote_if_index) {
 		tap_flow_implicit_create(pmd, TAP_REMOTE_PROMISC);
+		tap_netdev_set_flags(pmd->remote_iface, IFF_PROMISC, 1);
+	}
 }
 
 static void
@@ -493,9 +496,11 @@ tap_promisc_disable(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->promiscuous = 0;
-	tap_link_set_flags(pmd, IFF_PROMISC, 0);
-	if (pmd->remote_if_index)
+	tap_netdev_set_flags(pmd->name, IFF_PROMISC, 0);
+	if (pmd->remote_if_index) {
 		tap_flow_implicit_destroy(dev, TAP_REMOTE_PROMISC);
+		tap_netdev_set_flags(pmd->remote_iface, IFF_PROMISC, 0);
+	}
 }
 
 static void
@@ -504,9 +509,11 @@ tap_allmulti_enable(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->all_multicast = 1;
-	tap_link_set_flags(pmd, IFF_ALLMULTI, 1);
-	if (pmd->remote_if_index)
+	tap_netdev_set_flags(pmd->name, IFF_ALLMULTI, 1);
+	if (pmd->remote_if_index) {
 		tap_flow_implicit_create(pmd, TAP_REMOTE_ALLMULTI);
+		tap_netdev_set_flags(pmd->remote_iface, IFF_ALLMULTI, 1);
+	}
 }
 
 static void
@@ -515,9 +522,11 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->all_multicast = 0;
-	tap_link_set_flags(pmd, IFF_ALLMULTI, 0);
-	if (pmd->remote_if_index)
+	tap_netdev_set_flags(pmd->name, IFF_ALLMULTI, 0);
+	if (pmd->remote_if_index) {
 		tap_flow_implicit_destroy(dev, TAP_REMOTE_ALLMULTI);
+		tap_netdev_set_flags(pmd->remote_iface, IFF_ALLMULTI, 0);
+	}
 }
 
 static void
@@ -962,6 +971,7 @@ eth_dev_tap_create(const char *name, char *tap_name, char *remote_iface)
 	 */
 	pmd->nlsk_fd = nl_init();
 	if (strlen(remote_iface)) {
+		strncpy(pmd->remote_iface, remote_iface, RTE_ETH_NAME_MAX_LEN);
 		pmd->remote_if_index = if_nametoindex(remote_iface);
 		if (!pmd->remote_if_index)
 			RTE_LOG(ERR, PMD, "Could not find %s ifindex: "
drivers/net/tap/tap.h +2 -0
index 4c4de939f1cc..9811d0b0f085 100644
@@ -63,9 +63,11 @@ struct tx_queue {
 };
 
 struct pmd_internals {
+	char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */
 	char name[RTE_ETH_NAME_MAX_LEN];  /* Internal Tap device name */
 	uint16_t nb_queues;               /* Number of queues supported */
 	struct ether_addr eth_addr;       /* Mac address of the device port */
+	int remote_if_index;              /* remote netdevice IF_INDEX */
 	int if_index;                     /* IF_INDEX for the port */
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flower_support;               /* 1 if kernel supports, else 0 */
Signature · 1 line
2.8.0.rc0
#9 lore raw

PATCH v2 3/4 net/tap: use the remote MAC address if available

In reply to Pascal Mazon

The remote on a tap is most likely used with netdevices that are not under DPDK control. Outgoing traffic is supposed to use the source MAC address of the remote netdevice.

This commit synchronizes the MAC address of the local tap netdevice with the remote one.

Of course, it is still possible to change the tap MAC address, using standard DPDK APIs. It sets that MAC address on the tap PMD and redirect any packets matching that destination MAC to the tap PMD. It also tries setting the MAC address directly on the remote, if supported, through ioctl() calls.

---
 drivers/net/tap/rte_eth_tap.c | 77 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 65 insertions(+), 12 deletions(-)
drivers/net/tap/rte_eth_tap.c +65 -12
index ded8bb0f18d9..ed71cddfe0b3 100644
@@ -529,6 +529,65 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 	}
 }
 
+static int
+tap_netdev_set_mac(const char *iface, struct ether_addr *mac_addr)
+{
+	struct ifreq ifr;
+	int err, s;
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s < 0) {
+		RTE_LOG(ERR, PMD,
+			"Unable to get a socket to get MAC: %s\n",
+			strerror(errno));
+		return -1;
+	}
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, iface, IFNAMSIZ);
+	err = ioctl(s, SIOCGIFHWADDR, &ifr);
+	if (err < 0) {
+		RTE_LOG(ERR, PMD, "%s: couldn't get current MAC address (%s)\n",
+			iface, strerror(errno));
+		close(s);
+		return -1;
+	}
+	rte_memcpy(ifr.ifr_hwaddr.sa_data, mac_addr, ETHER_ADDR_LEN);
+	err = ioctl(s, SIOCSIFHWADDR, &ifr) == -1;
+	close(s);
+	if (err < 0) {
+		RTE_LOG(ERR, PMD, "%s: couldn't set current MAC address (%s)\n",
+			iface, strerror(errno));
+		return -1;
+	}
+	return 0;
+}
+
+static int
+tap_netdev_get_mac(const char *iface, struct ether_addr *mac_addr)
+{
+	struct ifreq ifr;
+	int err, s;
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s < 0) {
+		RTE_LOG(ERR, PMD,
+			"Unable to get a socket to get MAC: %s\n",
+			strerror(errno));
+		return -1;
+	}
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, iface, IFNAMSIZ);
+	err = ioctl(s, SIOCGIFHWADDR, &ifr);
+	close(s);
+	if (err < 0) {
+		RTE_LOG(ERR, PMD, "%s: couldn't get MAC address (%s)\n",
+			iface, strerror(errno));
+		return -1;
+	}
+	rte_memcpy(mac_addr, ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
+	return 0;
+}
+
 static void
 tap_mac_remove(struct rte_eth_dev *dev __rte_unused,
 	       uint32_t index __rte_unused)
@@ -545,7 +604,6 @@ tap_mac_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 {
 	struct pmd_internals *internals = dev->data->dev_private;
 	int fd = internals->rxq[0].fd;
-	struct ifreq ifr;
 
 	if (index > RTE_PMD_TAP_MAX_MAC_ADDRS - 1) {
 		RTE_LOG(ERR, PMD,
@@ -565,19 +623,11 @@ tap_mac_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 			dev->data->name);
 		return;
 	}
-	memset(&ifr, 0, sizeof(struct ifreq));
-	if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) {
-		RTE_LOG(ERR, PMD, "%s: couldn't get current MAC address (%s)\n",
-			dev->data->name, strerror(errno));
+	if (tap_netdev_set_mac(internals->name, mac_addr) < 0)
 		return;
-	}
-	rte_memcpy(ifr.ifr_hwaddr.sa_data, mac_addr, ETHER_ADDR_LEN);
-	if (ioctl(fd, SIOCSIFHWADDR, &ifr) == -1) {
-		RTE_LOG(ERR, PMD, "%s: couldn't set current MAC address (%s)\n",
-			dev->data->name, strerror(errno));
-		return;
-	}
 	rte_memcpy(&dev->data->mac_addrs[index], mac_addr, ETHER_ADDR_LEN);
+	if (internals->remote_if_index)
+		tap_netdev_set_mac(internals->remote_iface, mac_addr);
 }
 
 static void
@@ -977,6 +1027,9 @@ eth_dev_tap_create(const char *name, char *tap_name, char *remote_iface)
 			RTE_LOG(ERR, PMD, "Could not find %s ifindex: "
 				"remote interface will remain unconfigured\n",
 				remote_iface);
+		else
+			/* Set the local mac address to the remote mac */
+			tap_netdev_get_mac(remote_iface, &pmd->eth_addr);
 	}
 
 	return 0;
Signature · 1 line
2.8.0.rc0
#10 lore raw

PATCH v2 4/4 net/tap: set MTU on the remote

In reply to Pascal Mazon
---
 drivers/net/tap/rte_eth_tap.c | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)
drivers/net/tap/rte_eth_tap.c +23 -6
index ed71cddfe0b3..34e56813cedb 100644
@@ -839,9 +839,8 @@ tap_set_mc_addr_list(struct rte_eth_dev *dev __rte_unused,
 }
 
 static int
-tap_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+tap_netdev_mtu_set(const char *iface, uint16_t mtu)
 {
-	struct pmd_internals *pmd = dev->data->dev_private;
 	struct ifreq ifr;
 	int err, s;
 
@@ -849,15 +848,15 @@ tap_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 	if (s < 0) {
 		RTE_LOG(ERR, PMD,
 			"Unable to get a socket for %s to set flags: %s\n",
-			pmd->name, strerror(errno));
+			iface, strerror(errno));
 		return -1;
 	}
 	memset(&ifr, 0, sizeof(ifr));
-	snprintf(ifr.ifr_name, IFNAMSIZ, "%s", pmd->name);
+	snprintf(ifr.ifr_name, IFNAMSIZ, "%s", iface);
 	err = ioctl(s, SIOCGIFMTU, &ifr);
 	if (err < 0) {
 		RTE_LOG(WARNING, PMD, "Unable to get %s device MTU: %s\n",
-			pmd->name, strerror(errno));
+			iface, strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -865,11 +864,29 @@ tap_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 	err = ioctl(s, SIOCSIFMTU, &ifr);
 	if (err < 0) {
 		RTE_LOG(WARNING, PMD, "Unable to set %s mtu %d: %s\n",
-			pmd->name, mtu, strerror(errno));
+			iface, mtu, strerror(errno));
 		close(s);
 		return -1;
 	}
 	close(s);
+	return 0;
+}
+
+static int
+tap_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+{
+	struct pmd_internals *pmd = dev->data->dev_private;
+	int err;
+
+	/* First try to set mtu on the remote */
+	if (pmd->remote_if_index) {
+		err = tap_netdev_mtu_set(pmd->remote_iface, mtu);
+		if (err < 0)
+			return err;
+	}
+	err = tap_netdev_mtu_set(pmd->name, mtu);
+	if (err < 0)
+		return err;
 	dev->data->mtu = mtu;
 	return 0;
 }
Signature · 1 line
2.8.0.rc0
#11 lore raw

v3 cover net/tap: remote netdevice traffic capture

In reply to Pascal Mazon

This patchset adds the special "remote" feature to the tap PMD, that actually enables capturing traffic from another netdevice. This is especially useful to get packets into the DPDK app, when the remote netdevice has no DPDK support.

The "remote" feature requires flow API support as flow rules will be configured on the remote netdevice for redirection, using the same mechanism.

This series applies on top of:

[PATCH 0/4] net/tap: support flow API

v2 changes:
- rebase on top of updated "net/tap: support flow API"
- fix implicit flow flush when closing the netdevices

v3 changes:
- memset(0) for remote_iface in rte_pmd_tap_probe()
- use snprintf instead of strncpy to correctly handle terminating \0

Pascal Mazon (4):
net/tap: add remote netdevice traffic capture net/tap: reflect tap flags on the remote net/tap: use the remote MAC address if available net/tap: set MTU on the remote

 doc/guides/nics/tap.rst       |  17 ++
 drivers/net/tap/rte_eth_tap.c | 215 +++++++++++++++++++---
 drivers/net/tap/tap.h         |   4 +
 drivers/net/tap/tap_flow.c    | 418 ++++++++++++++++++++++++++++++++++++++++--
 drivers/net/tap/tap_flow.h    |  24 +++
 5 files changed, 637 insertions(+), 41 deletions(-)
Signature · 1 line
2.8.0.rc0
#12 lore raw

PATCH v3 1/4 net/tap: add remote netdevice traffic capture

By default, a tap netdevice is of no use when not fed by a separate process. The ability to automatically feed it from another netdevice allows applications to capture any kind of traffic normally destined to the kernel stack.

This patch implements this ability through a new optional "remote" parameter.

Packets matching filtering rules created with the flow API are matched on the remote device and redirected to the tap PMD, where the relevant action will be performed.

---
 doc/guides/nics/tap.rst       |  17 ++
 drivers/net/tap/rte_eth_tap.c |  80 +++++++-
 drivers/net/tap/tap.h         |   2 +
 drivers/net/tap/tap_flow.c    | 418 ++++++++++++++++++++++++++++++++++++++++--
 drivers/net/tap/tap_flow.h    |  24 +++
 5 files changed, 527 insertions(+), 14 deletions(-)
doc/guides/nics/tap.rst +17 -0
index cdb528b5eae4..676a569b00ca 100644
@@ -58,6 +58,23 @@ needed, but the interface does not enforce that speed, for example::
 
    --vdev=net_tap0,iface=foo0,speed=25000
 
+It is possible to specify a remote netdevice to capture packets from by adding
+``remote=foo1``, for example::
+
+   --vdev=net_tap,iface=tap0,remote=foo1
+
+If a ``remote`` is set, then all packets with the tap PMD's local MAC coming
+in on the remote netdevice will be redirected to the tap.
+If the tap is in promiscuous mode, then all packets will be redirected.
+In allmulti mode, all multicast packets will be redirected.
+It is possible to add explicit rte_flow rules on the tap PMD to capture specific
+traffic. For instance, in testpmd, the following rte_flow rule would capture
+packets with the given MAC address from the remote, and send it to the tap RX
+QUEUE 3::
+
+   testpmd> flow create 0 ingress pattern eth src is 02:03:04:05:06:07 / \
+            end actions queue index 3 / end
+
 After the DPDK application is started you can send and receive packets on the
 interface using the standard rx_burst/tx_burst APIs in DPDK. From the host
 point of view you can use any host tool like tcpdump, Wireshark, ping, Pktgen
drivers/net/tap/rte_eth_tap.c +78 -2

177 lines not on this page · raw message

drivers/net/tap/tap.h +2 -0
index 2c8cc7d5b485..4c4de939f1cc 100644
@@ -71,6 +71,8 @@ struct pmd_internals {
 	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 */
+	/* implicit rte_flow rules set when a remote device is active */
+	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
 	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 */
 };
drivers/net/tap/tap_flow.c +406 -12

527 lines not on this page · raw message

drivers/net/tap/tap_flow.h +24 -0
index a05e945df523..0134cdbaeb90 100644
@@ -36,6 +36,7 @@
 
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
+#include <tap.h>
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -49,10 +50,33 @@
 #define GROUP_SHIFT 12
 #define MAX_GROUP GROUP_MASK
 
+/**
+ * These index are actually in reversed order: their priority is processed
+ * by subtracting their value to the lowest priority (PRIORITY_MASK).
+ * Thus the first one will have the lowest priority in the end
+ * (but biggest value).
+ */
+enum implicit_rule_index {
+	TAP_REMOTE_TX,
+	TAP_REMOTE_BROADCASTV6,
+	TAP_REMOTE_BROADCAST,
+	TAP_REMOTE_ALLMULTI,
+	TAP_REMOTE_PROMISC,
+	TAP_REMOTE_LOCAL_MAC,
+	TAP_REMOTE_MAX_IDX,
+};
+
 int tap_dev_filter_ctrl(struct rte_eth_dev *dev,
 			enum rte_filter_type filter_type,
 			enum rte_filter_op filter_op,
 			void *arg);
 int tap_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error);
 
+int tap_flow_implicit_create(struct pmd_internals *pmd,
+			     enum implicit_rule_index idx);
+int tap_flow_implicit_destroy(struct rte_eth_dev *dev,
+			      enum implicit_rule_index idx);
+int tap_flow_implicit_flush(struct rte_eth_dev *dev,
+			    struct rte_flow_error *error);
+
 #endif /* _TAP_FLOW_H_ */
Signature · 1 line
2.8.0.rc0
#13 lore raw

PATCH v3 2/4 net/tap: reflect tap flags on the remote

In reply to Pascal Mazon

Synchronize PROMISC and ALLMULTI flags to the remote netdevice if possible.

Leave the IFF_UP flag as it is, however.

---
 drivers/net/tap/rte_eth_tap.c | 37 ++++++++++++++++++++++++-------------
 drivers/net/tap/tap.h         |  2 ++
 2 files changed, 26 insertions(+), 13 deletions(-)
drivers/net/tap/rte_eth_tap.c +24 -13
index f3d9d8fe96aa..b0f5ffbb8ace 100644
@@ -254,7 +254,7 @@ pmd_tx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 }
 
 static int
-tap_link_set_flags(struct pmd_internals *pmd, short flags, int add)
+tap_netdev_set_flags(const char *iface, short flags, int add)
 {
 	struct ifreq ifr;
 	int err, s;
@@ -271,11 +271,11 @@ tap_link_set_flags(struct pmd_internals *pmd, short flags, int add)
 		return -1;
 	}
 	memset(&ifr, 0, sizeof(ifr));
-	snprintf(ifr.ifr_name, IFNAMSIZ, "%s", pmd->name);
+	snprintf(ifr.ifr_name, IFNAMSIZ, "%s", iface);
 	err = ioctl(s, SIOCGIFFLAGS, &ifr);
 	if (err < 0) {
 		RTE_LOG(WARNING, PMD, "Unable to get %s device flags: %s\n",
-			pmd->name, strerror(errno));
+			iface, strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -293,6 +293,7 @@ tap_link_set_flags(struct pmd_internals *pmd, short flags, int add)
 	close(s);
 
 	return 0;
+
 }
 
 static int
@@ -301,7 +302,7 @@ tap_link_set_down(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->dev_link.link_status = ETH_LINK_DOWN;
-	return tap_link_set_flags(pmd, IFF_UP | IFF_NOARP, 0);
+	return tap_netdev_set_flags(pmd->name, IFF_UP | IFF_NOARP, 0);
 }
 
 static int
@@ -310,7 +311,7 @@ tap_link_set_up(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->dev_link.link_status = ETH_LINK_UP;
-	return tap_link_set_flags(pmd, IFF_UP | IFF_NOARP, 1);
+	return tap_netdev_set_flags(pmd->name, IFF_UP | IFF_NOARP, 1);
 }
 
 static int
@@ -482,9 +483,11 @@ tap_promisc_enable(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->promiscuous = 1;
-	tap_link_set_flags(pmd, IFF_PROMISC, 1);
-	if (pmd->remote_if_index)
+	tap_netdev_set_flags(pmd->name, IFF_PROMISC, 1);
+	if (pmd->remote_if_index) {
 		tap_flow_implicit_create(pmd, TAP_REMOTE_PROMISC);
+		tap_netdev_set_flags(pmd->remote_iface, IFF_PROMISC, 1);
+	}
 }
 
 static void
@@ -493,9 +496,11 @@ tap_promisc_disable(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->promiscuous = 0;
-	tap_link_set_flags(pmd, IFF_PROMISC, 0);
-	if (pmd->remote_if_index)
+	tap_netdev_set_flags(pmd->name, IFF_PROMISC, 0);
+	if (pmd->remote_if_index) {
 		tap_flow_implicit_destroy(dev, TAP_REMOTE_PROMISC);
+		tap_netdev_set_flags(pmd->remote_iface, IFF_PROMISC, 0);
+	}
 }
 
 static void
@@ -504,9 +509,11 @@ tap_allmulti_enable(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->all_multicast = 1;
-	tap_link_set_flags(pmd, IFF_ALLMULTI, 1);
-	if (pmd->remote_if_index)
+	tap_netdev_set_flags(pmd->name, IFF_ALLMULTI, 1);
+	if (pmd->remote_if_index) {
 		tap_flow_implicit_create(pmd, TAP_REMOTE_ALLMULTI);
+		tap_netdev_set_flags(pmd->remote_iface, IFF_ALLMULTI, 1);
+	}
 }
 
 static void
@@ -515,9 +522,11 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 	struct pmd_internals *pmd = dev->data->dev_private;
 
 	dev->data->all_multicast = 0;
-	tap_link_set_flags(pmd, IFF_ALLMULTI, 0);
-	if (pmd->remote_if_index)
+	tap_netdev_set_flags(pmd->name, IFF_ALLMULTI, 0);
+	if (pmd->remote_if_index) {
 		tap_flow_implicit_destroy(dev, TAP_REMOTE_ALLMULTI);
+		tap_netdev_set_flags(pmd->remote_iface, IFF_ALLMULTI, 0);
+	}
 }
 
 static void
@@ -962,6 +971,8 @@ eth_dev_tap_create(const char *name, char *tap_name, char *remote_iface)
 	 */
 	pmd->nlsk_fd = nl_init();
 	if (strlen(remote_iface)) {
+		snprintf(pmd->remote_iface, RTE_ETH_NAME_MAX_LEN,
+			 "%s", remote_iface);
 		pmd->remote_if_index = if_nametoindex(remote_iface);
 		if (!pmd->remote_if_index)
 			RTE_LOG(ERR, PMD, "Could not find %s ifindex: "
drivers/net/tap/tap.h +2 -0
index 4c4de939f1cc..9811d0b0f085 100644
@@ -63,9 +63,11 @@ struct tx_queue {
 };
 
 struct pmd_internals {
+	char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */
 	char name[RTE_ETH_NAME_MAX_LEN];  /* Internal Tap device name */
 	uint16_t nb_queues;               /* Number of queues supported */
 	struct ether_addr eth_addr;       /* Mac address of the device port */
+	int remote_if_index;              /* remote netdevice IF_INDEX */
 	int if_index;                     /* IF_INDEX for the port */
 	int nlsk_fd;                      /* Netlink socket fd */
 	int flower_support;               /* 1 if kernel supports, else 0 */
Signature · 1 line
2.8.0.rc0
#14 lore raw

PATCH v3 3/4 net/tap: use the remote MAC address if available

In reply to Pascal Mazon

The remote on a tap is most likely used with netdevices that are not under DPDK control. Outgoing traffic is supposed to use the source MAC address of the remote netdevice.

This commit synchronizes the MAC address of the local tap netdevice with the remote one.

Of course, it is still possible to change the tap MAC address, using standard DPDK APIs. It sets that MAC address on the tap PMD and redirect any packets matching that destination MAC to the tap PMD. It also tries setting the MAC address directly on the remote, if supported, through ioctl() calls.

---
 drivers/net/tap/rte_eth_tap.c | 77 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 65 insertions(+), 12 deletions(-)
drivers/net/tap/rte_eth_tap.c +65 -12
index b0f5ffbb8ace..05ed0a131d63 100644
@@ -529,6 +529,65 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 	}
 }
 
+static int
+tap_netdev_set_mac(const char *iface, struct ether_addr *mac_addr)
+{
+	struct ifreq ifr;
+	int err, s;
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s < 0) {
+		RTE_LOG(ERR, PMD,
+			"Unable to get a socket to get MAC: %s\n",
+			strerror(errno));
+		return -1;
+	}
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, iface, IFNAMSIZ);
+	err = ioctl(s, SIOCGIFHWADDR, &ifr);
+	if (err < 0) {
+		RTE_LOG(ERR, PMD, "%s: couldn't get current MAC address (%s)\n",
+			iface, strerror(errno));
+		close(s);
+		return -1;
+	}
+	rte_memcpy(ifr.ifr_hwaddr.sa_data, mac_addr, ETHER_ADDR_LEN);
+	err = ioctl(s, SIOCSIFHWADDR, &ifr) == -1;
+	close(s);
+	if (err < 0) {
+		RTE_LOG(ERR, PMD, "%s: couldn't set current MAC address (%s)\n",
+			iface, strerror(errno));
+		return -1;
+	}
+	return 0;
+}
+
+static int
+tap_netdev_get_mac(const char *iface, struct ether_addr *mac_addr)
+{
+	struct ifreq ifr;
+	int err, s;
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s < 0) {
+		RTE_LOG(ERR, PMD,
+			"Unable to get a socket to get MAC: %s\n",
+			strerror(errno));
+		return -1;
+	}
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, iface, IFNAMSIZ);
+	err = ioctl(s, SIOCGIFHWADDR, &ifr);
+	close(s);
+	if (err < 0) {
+		RTE_LOG(ERR, PMD, "%s: couldn't get MAC address (%s)\n",
+			iface, strerror(errno));
+		return -1;
+	}
+	rte_memcpy(mac_addr, ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
+	return 0;
+}
+
 static void
 tap_mac_remove(struct rte_eth_dev *dev __rte_unused,
 	       uint32_t index __rte_unused)
@@ -545,7 +604,6 @@ tap_mac_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 {
 	struct pmd_internals *internals = dev->data->dev_private;
 	int fd = internals->rxq[0].fd;
-	struct ifreq ifr;
 
 	if (index > RTE_PMD_TAP_MAX_MAC_ADDRS - 1) {
 		RTE_LOG(ERR, PMD,
@@ -565,19 +623,11 @@ tap_mac_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
 			dev->data->name);
 		return;
 	}
-	memset(&ifr, 0, sizeof(struct ifreq));
-	if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) {
-		RTE_LOG(ERR, PMD, "%s: couldn't get current MAC address (%s)\n",
-			dev->data->name, strerror(errno));
+	if (tap_netdev_set_mac(internals->name, mac_addr) < 0)
 		return;
-	}
-	rte_memcpy(ifr.ifr_hwaddr.sa_data, mac_addr, ETHER_ADDR_LEN);
-	if (ioctl(fd, SIOCSIFHWADDR, &ifr) == -1) {
-		RTE_LOG(ERR, PMD, "%s: couldn't set current MAC address (%s)\n",
-			dev->data->name, strerror(errno));
-		return;
-	}
 	rte_memcpy(&dev->data->mac_addrs[index], mac_addr, ETHER_ADDR_LEN);
+	if (internals->remote_if_index)
+		tap_netdev_set_mac(internals->remote_iface, mac_addr);
 }
 
 static void
@@ -978,6 +1028,9 @@ eth_dev_tap_create(const char *name, char *tap_name, char *remote_iface)
 			RTE_LOG(ERR, PMD, "Could not find %s ifindex: "
 				"remote interface will remain unconfigured\n",
 				remote_iface);
+		else
+			/* Set the local mac address to the remote mac */
+			tap_netdev_get_mac(remote_iface, &pmd->eth_addr);
 	}
 
 	return 0;
Signature · 1 line
2.8.0.rc0
#15 lore raw

PATCH v3 4/4 net/tap: set MTU on the remote

In reply to Pascal Mazon
---
 drivers/net/tap/rte_eth_tap.c | 29 +++++++++++++++++++++++------
 1 file changed, 23 insertions(+), 6 deletions(-)
drivers/net/tap/rte_eth_tap.c +23 -6
index 05ed0a131d63..9edf6b355a47 100644
@@ -839,9 +839,8 @@ tap_set_mc_addr_list(struct rte_eth_dev *dev __rte_unused,
 }
 
 static int
-tap_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+tap_netdev_mtu_set(const char *iface, uint16_t mtu)
 {
-	struct pmd_internals *pmd = dev->data->dev_private;
 	struct ifreq ifr;
 	int err, s;
 
@@ -849,15 +848,15 @@ tap_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 	if (s < 0) {
 		RTE_LOG(ERR, PMD,
 			"Unable to get a socket for %s to set flags: %s\n",
-			pmd->name, strerror(errno));
+			iface, strerror(errno));
 		return -1;
 	}
 	memset(&ifr, 0, sizeof(ifr));
-	snprintf(ifr.ifr_name, IFNAMSIZ, "%s", pmd->name);
+	snprintf(ifr.ifr_name, IFNAMSIZ, "%s", iface);
 	err = ioctl(s, SIOCGIFMTU, &ifr);
 	if (err < 0) {
 		RTE_LOG(WARNING, PMD, "Unable to get %s device MTU: %s\n",
-			pmd->name, strerror(errno));
+			iface, strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -865,11 +864,29 @@ tap_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 	err = ioctl(s, SIOCSIFMTU, &ifr);
 	if (err < 0) {
 		RTE_LOG(WARNING, PMD, "Unable to set %s mtu %d: %s\n",
-			pmd->name, mtu, strerror(errno));
+			iface, mtu, strerror(errno));
 		close(s);
 		return -1;
 	}
 	close(s);
+	return 0;
+}
+
+static int
+tap_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+{
+	struct pmd_internals *pmd = dev->data->dev_private;
+	int err;
+
+	/* First try to set mtu on the remote */
+	if (pmd->remote_if_index) {
+		err = tap_netdev_mtu_set(pmd->remote_iface, mtu);
+		if (err < 0)
+			return err;
+	}
+	err = tap_netdev_mtu_set(pmd->name, mtu);
+	if (err < 0)
+		return err;
 	dev->data->mtu = mtu;
 	return 0;
 }
Signature · 1 line
2.8.0.rc0
#16 lore raw

PATCH v4 1/1 net/tap: remote netdevice traffic capture

In reply to Pascal Mazon

This patchset adds the special "remote" feature to the tap PMD, that actually enables capturing traffic from another netdevice. This is especially useful to get packets into the DPDK app, when the remote netdevice has no DPDK support.

The "remote" feature requires flow API support as flow rules will be configured on the remote netdevice for redirection, using the same mechanism.

This series applies on top of:

[PATCH 0/4] net/tap: support flow API

v2 changes:
- rebase on top of updated "net/tap: support flow API"
- fix implicit flow flush when closing the netdevices

v3 changes:
- memset(0) for remote_iface in rte_pmd_tap_probe()
- use snprintf instead of strncpy to correctly handle terminating \0

v4 changes:
- rebase on top of updated "net/tap: support flow API"
- use only a single patch now as MTU, MAC and flags can be easily managed with tap_ioctl()

Pascal Mazon (1):
net/tap: add remote netdevice traffic capture

 doc/guides/nics/tap.rst       |  17 ++
 drivers/net/tap/rte_eth_tap.c | 101 +++++++++-
 drivers/net/tap/rte_eth_tap.h |   4 +
 drivers/net/tap/tap_flow.c    | 451 ++++++++++++++++++++++++++++++++++++++++--
 drivers/net/tap/tap_flow.h    |  24 +++
 5 files changed, 575 insertions(+), 22 deletions(-)
Signature · 1 line
2.8.0.rc0
#17 lore raw

PATCH v4 1/1 net/tap: add remote netdevice traffic capture

By default, a tap netdevice is of no use when not fed by a separate process. The ability to automatically feed it from another netdevice allows applications to capture any kind of traffic normally destined to the kernel stack.

This patch implements this ability through a new optional "remote" parameter.

Packets matching filtering rules created with the flow API are matched on the remote device and redirected to the tap PMD, where the relevant action will be performed.

---
 doc/guides/nics/tap.rst       |  17 ++
 drivers/net/tap/rte_eth_tap.c | 101 +++++++++-
 drivers/net/tap/rte_eth_tap.h |   4 +
 drivers/net/tap/tap_flow.c    | 451 ++++++++++++++++++++++++++++++++++++++++--
 drivers/net/tap/tap_flow.h    |  24 +++
 5 files changed, 575 insertions(+), 22 deletions(-)
doc/guides/nics/tap.rst +17 -0
index cdb528b5eae4..676a569b00ca 100644
@@ -58,6 +58,23 @@ needed, but the interface does not enforce that speed, for example::
 
    --vdev=net_tap0,iface=foo0,speed=25000
 
+It is possible to specify a remote netdevice to capture packets from by adding
+``remote=foo1``, for example::
+
+   --vdev=net_tap,iface=tap0,remote=foo1
+
+If a ``remote`` is set, then all packets with the tap PMD's local MAC coming
+in on the remote netdevice will be redirected to the tap.
+If the tap is in promiscuous mode, then all packets will be redirected.
+In allmulti mode, all multicast packets will be redirected.
+It is possible to add explicit rte_flow rules on the tap PMD to capture specific
+traffic. For instance, in testpmd, the following rte_flow rule would capture
+packets with the given MAC address from the remote, and send it to the tap RX
+QUEUE 3::
+
+   testpmd> flow create 0 ingress pattern eth src is 02:03:04:05:06:07 / \
+            end actions queue index 3 / end
+
 After the DPDK application is started you can send and receive packets on the
 interface using the standard rx_burst/tx_burst APIs in DPDK. From the host
 point of view you can use any host tool like tcpdump, Wireshark, ping, Pktgen
drivers/net/tap/rte_eth_tap.c +98 -3

218 lines not on this page · raw message

drivers/net/tap/rte_eth_tap.h +4 -0
index 15ae0b980ace..bd32e93aa59c 100644
@@ -63,15 +63,19 @@ struct tx_queue {
 };
 
 struct pmd_internals {
+	char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */
 	char name[RTE_ETH_NAME_MAX_LEN];  /* Internal Tap device name */
 	uint16_t nb_queues;               /* Number of queues supported */
 	struct ether_addr eth_addr;       /* Mac address of the device port */
+	int remote_if_index;              /* remote netdevice IF_INDEX */
 	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 */
+	/* implicit rte_flow rules set when a remote device is active */
+	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
 	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 */
 };
drivers/net/tap/tap_flow.c +432 -19

569 lines not on this page · raw message

drivers/net/tap/tap_flow.h +24 -0
index a05e945df523..94414f18f4ff 100644
@@ -36,6 +36,7 @@
 
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
+#include <rte_eth_tap.h>
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -49,10 +50,33 @@
 #define GROUP_SHIFT 12
 #define MAX_GROUP GROUP_MASK
 
+/**
+ * These index are actually in reversed order: their priority is processed
+ * by subtracting their value to the lowest priority (PRIORITY_MASK).
+ * Thus the first one will have the lowest priority in the end
+ * (but biggest value).
+ */
+enum implicit_rule_index {
+	TAP_REMOTE_TX,
+	TAP_REMOTE_BROADCASTV6,
+	TAP_REMOTE_BROADCAST,
+	TAP_REMOTE_ALLMULTI,
+	TAP_REMOTE_PROMISC,
+	TAP_REMOTE_LOCAL_MAC,
+	TAP_REMOTE_MAX_IDX,
+};
+
 int tap_dev_filter_ctrl(struct rte_eth_dev *dev,
 			enum rte_filter_type filter_type,
 			enum rte_filter_op filter_op,
 			void *arg);
 int tap_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error);
 
+int tap_flow_implicit_create(struct pmd_internals *pmd,
+			     enum implicit_rule_index idx);
+int tap_flow_implicit_destroy(struct pmd_internals *pmd,
+			      enum implicit_rule_index idx);
+int tap_flow_implicit_flush(struct pmd_internals *pmd,
+			    struct rte_flow_error *error);
+
 #endif /* _TAP_FLOW_H_ */
Signature · 1 line
2.8.0.rc0
Acked-by on v4 1/1
#18 lore raw

Re: [PATCH v4] net/tap: add remote netdevice traffic capture

Quoted 11 lines · Pascal Mazon

By default, a tap netdevice is of no use when not fed by a separate process. The ability to automatically feed it from another netdevice allows applications to capture any kind of traffic normally destined to the kernel stack.

This patch implements this ability through a new optional "remote" parameter.

Quoted 6 lines

Packets matching filtering rules created with the flow API are matched on the remote device and redirected to the tap PMD, where the relevant action will be performed.

Quoted 7 lines

---

doc/guides/nics/tap.rst       |  17 ++
drivers/net/tap/rte_eth_tap.c | 101 +++++++++-
drivers/net/tap/rte_eth_tap.h |   4 +
drivers/net/tap/tap_flow.c    | 451 ++++++++++++++++++++++++++++++++++++++++--
drivers/net/tap/tap_flow.h    |  24 +++
5 files changed, 575 insertions(+), 22 deletions(-)

Regards,
Keith

#19 lore raw

PATCH v5 1/1 net/tap: remote netdevice traffic capture

In reply to Pascal Mazon

This patchset adds the special "remote" feature to the tap PMD, that actually enables capturing traffic from another netdevice. This is especially useful to get packets into the DPDK app, when the remote netdevice has no DPDK support.

The "remote" feature requires flow API support as flow rules will be configured on the remote netdevice for redirection, using the same mechanism.

This series applies on top of:

[PATCH 0/4] net/tap: support flow API

v2 changes:
- rebase on top of updated "net/tap: support flow API"
- fix implicit flow flush when closing the netdevices

v3 changes:
- memset(0) for remote_iface in rte_pmd_tap_probe()
- use snprintf instead of strncpy to correctly handle terminating \0

v4 changes:
- rebase on top of updated "net/tap: support flow API"
- use only a single patch now as MTU, MAC and flags can be easily managed with tap_ioctl()

v5 changes:
- rebase after adrien's patches on Tx poll and Rx signaling

Pascal Mazon (1):
net/tap: add remote netdevice traffic capture

 doc/guides/nics/tap.rst       |  17 ++
 drivers/net/tap/rte_eth_tap.c | 101 +++++++++-
 drivers/net/tap/rte_eth_tap.h |   4 +
 drivers/net/tap/tap_flow.c    | 451 ++++++++++++++++++++++++++++++++++++++++--
 drivers/net/tap/tap_flow.h    |  24 +++
 5 files changed, 575 insertions(+), 22 deletions(-)
Signature · 1 line
2.8.0.rc0
#20 lore raw

PATCH v5 1/1 net/tap: add remote netdevice traffic capture

By default, a tap netdevice is of no use when not fed by a separate process. The ability to automatically feed it from another netdevice allows applications to capture any kind of traffic normally destined to the kernel stack.

This patch implements this ability through a new optional "remote" parameter.

Packets matching filtering rules created with the flow API are matched on the remote device and redirected to the tap PMD, where the relevant action will be performed.

---
 doc/guides/nics/tap.rst       |  17 ++
 drivers/net/tap/rte_eth_tap.c | 101 +++++++++-
 drivers/net/tap/rte_eth_tap.h |   4 +
 drivers/net/tap/tap_flow.c    | 451 ++++++++++++++++++++++++++++++++++++++++--
 drivers/net/tap/tap_flow.h    |  24 +++
 5 files changed, 575 insertions(+), 22 deletions(-)
doc/guides/nics/tap.rst +17 -0
index cdb528b5eae4..676a569b00ca 100644
@@ -58,6 +58,23 @@ needed, but the interface does not enforce that speed, for example::
 
    --vdev=net_tap0,iface=foo0,speed=25000
 
+It is possible to specify a remote netdevice to capture packets from by adding
+``remote=foo1``, for example::
+
+   --vdev=net_tap,iface=tap0,remote=foo1
+
+If a ``remote`` is set, then all packets with the tap PMD's local MAC coming
+in on the remote netdevice will be redirected to the tap.
+If the tap is in promiscuous mode, then all packets will be redirected.
+In allmulti mode, all multicast packets will be redirected.
+It is possible to add explicit rte_flow rules on the tap PMD to capture specific
+traffic. For instance, in testpmd, the following rte_flow rule would capture
+packets with the given MAC address from the remote, and send it to the tap RX
+QUEUE 3::
+
+   testpmd> flow create 0 ingress pattern eth src is 02:03:04:05:06:07 / \
+            end actions queue index 3 / end
+
 After the DPDK application is started you can send and receive packets on the
 interface using the standard rx_burst/tx_burst APIs in DPDK. From the host
 point of view you can use any host tool like tcpdump, Wireshark, ping, Pktgen
drivers/net/tap/rte_eth_tap.c +98 -3

218 lines not on this page · raw message

drivers/net/tap/rte_eth_tap.h +4 -0
index 741ec5350886..1ad6ad88796a 100644
@@ -64,15 +64,19 @@ struct tx_queue {
 };
 
 struct pmd_internals {
+	char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */
 	char name[RTE_ETH_NAME_MAX_LEN];  /* Internal Tap device name */
 	uint16_t nb_queues;               /* Number of queues supported */
 	struct ether_addr eth_addr;       /* Mac address of the device port */
+	int remote_if_index;              /* remote netdevice IF_INDEX */
 	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 */
+	/* implicit rte_flow rules set when a remote device is active */
+	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
 	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 */
 };
drivers/net/tap/tap_flow.c +432 -19

569 lines not on this page · raw message

drivers/net/tap/tap_flow.h +24 -0
index a05e945df523..94414f18f4ff 100644
@@ -36,6 +36,7 @@
 
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
+#include <rte_eth_tap.h>
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -49,10 +50,33 @@
 #define GROUP_SHIFT 12
 #define MAX_GROUP GROUP_MASK
 
+/**
+ * These index are actually in reversed order: their priority is processed
+ * by subtracting their value to the lowest priority (PRIORITY_MASK).
+ * Thus the first one will have the lowest priority in the end
+ * (but biggest value).
+ */
+enum implicit_rule_index {
+	TAP_REMOTE_TX,
+	TAP_REMOTE_BROADCASTV6,
+	TAP_REMOTE_BROADCAST,
+	TAP_REMOTE_ALLMULTI,
+	TAP_REMOTE_PROMISC,
+	TAP_REMOTE_LOCAL_MAC,
+	TAP_REMOTE_MAX_IDX,
+};
+
 int tap_dev_filter_ctrl(struct rte_eth_dev *dev,
 			enum rte_filter_type filter_type,
 			enum rte_filter_op filter_op,
 			void *arg);
 int tap_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error);
 
+int tap_flow_implicit_create(struct pmd_internals *pmd,
+			     enum implicit_rule_index idx);
+int tap_flow_implicit_destroy(struct pmd_internals *pmd,
+			      enum implicit_rule_index idx);
+int tap_flow_implicit_flush(struct pmd_internals *pmd,
+			    struct rte_flow_error *error);
+
 #endif /* _TAP_FLOW_H_ */
Signature · 1 line
2.8.0.rc0
#21 lore raw

v6 cover net/tap: remote netdevice traffic capture

In reply to Pascal Mazon

This patchset adds the special "remote" feature to the tap PMD, that actually enables capturing traffic from another netdevice. This is especially useful to get packets into the DPDK app, when the remote netdevice has no DPDK support.

The "remote" feature requires flow API support as flow rules will be configured on the remote netdevice for redirection, using the same mechanism.

This series applies on top of:

[PATCH 0/4] net/tap: support flow API

v6 changes:
- update documentation with use case

v5 changes:
- rebase after adrien's patches on Tx poll and Rx signaling

v4 changes:
- rebase on top of updated "net/tap: support flow API"
- use only a single patch now as MTU, MAC and flags can be easily managed with tap_ioctl()

v3 changes:
- memset(0) for remote_iface in rte_pmd_tap_probe()
- use snprintf instead of strncpy to correctly handle terminating \0

v2 changes:
- rebase on top of updated "net/tap: support flow API"
- fix implicit flow flush when closing the netdevices

Pascal Mazon (1):
net/tap: add remote netdevice traffic capture

 doc/guides/nics/tap.rst       |  16 ++
 drivers/net/tap/rte_eth_tap.c | 101 +++++++++-
 drivers/net/tap/rte_eth_tap.h |   4 +
 drivers/net/tap/tap_flow.c    | 451 ++++++++++++++++++++++++++++++++++++++++--
 drivers/net/tap/tap_flow.h    |  24 +++
 5 files changed, 574 insertions(+), 22 deletions(-)
Signature · 1 line
2.12.0.306.g4a9b9b3
#22 lore raw

PATCH v6 1/1 net/tap: add remote netdevice traffic capture

By default, a tap netdevice is of no use when not fed by a separate process. The ability to automatically feed it from another netdevice allows applications to capture any kind of traffic normally destined to the kernel stack.

This patch implements this ability through a new optional "remote" parameter.

Packets matching filtering rules created with the flow API are matched on the remote device and redirected to the tap PMD, where the relevant action will be performed.

---
 doc/guides/nics/tap.rst       |  16 ++
 drivers/net/tap/rte_eth_tap.c | 101 +++++++++-
 drivers/net/tap/rte_eth_tap.h |   4 +
 drivers/net/tap/tap_flow.c    | 451 ++++++++++++++++++++++++++++++++++++++++--
 drivers/net/tap/tap_flow.h    |  24 +++
 5 files changed, 574 insertions(+), 22 deletions(-)
doc/guides/nics/tap.rst +16 -0
index 4986e47e9f57..5c5ba5357bba 100644
@@ -58,6 +58,22 @@ needed, but the interface does not enforce that speed, for example::
 
    --vdev=net_tap0,iface=foo0,speed=25000
 
+It is possible to specify a remote netdevice to capture packets from by adding
+``remote=foo1``, for example::
+
+   --vdev=net_tap,iface=tap0,remote=foo1
+
+If a ``remote`` is set, the tap MAC address will be set to match the remote one
+just after netdevice creation. Using TC rules, traffic from the remote netdevice
+will be redirected to the tap. If the tap is in promiscuous mode, then all
+packets will be redirected. In allmulti mode, all multicast packets will be
+redirected.
+
+Using the remote feature is especially useful for capturing traffic from a
+netdevice that has no support in the DPDK. It is possible to add explicit
+rte_flow rules on the tap PMD to capture specific traffic (see next section for
+examples).
+
 After the DPDK application is started you can send and receive packets on the
 interface using the standard rx_burst/tx_burst APIs in DPDK. From the host
 point of view you can use any host tool like tcpdump, Wireshark, ping, Pktgen
drivers/net/tap/rte_eth_tap.c +98 -3

218 lines not on this page · raw message

drivers/net/tap/rte_eth_tap.h +4 -0
index 741ec5350886..1ad6ad88796a 100644
@@ -64,15 +64,19 @@ struct tx_queue {
 };
 
 struct pmd_internals {
+	char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */
 	char name[RTE_ETH_NAME_MAX_LEN];  /* Internal Tap device name */
 	uint16_t nb_queues;               /* Number of queues supported */
 	struct ether_addr eth_addr;       /* Mac address of the device port */
+	int remote_if_index;              /* remote netdevice IF_INDEX */
 	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 */
+	/* implicit rte_flow rules set when a remote device is active */
+	LIST_HEAD(tap_implicit_flows, rte_flow) implicit_flows;
 	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 */
 };
drivers/net/tap/tap_flow.c +432 -19

569 lines not on this page · raw message

drivers/net/tap/tap_flow.h +24 -0
index a05e945df523..94414f18f4ff 100644
@@ -36,6 +36,7 @@
 
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
+#include <rte_eth_tap.h>
 
 /**
  * In TC, priority 0 means we require the kernel to allocate one for us.
@@ -49,10 +50,33 @@
 #define GROUP_SHIFT 12
 #define MAX_GROUP GROUP_MASK
 
+/**
+ * These index are actually in reversed order: their priority is processed
+ * by subtracting their value to the lowest priority (PRIORITY_MASK).
+ * Thus the first one will have the lowest priority in the end
+ * (but biggest value).
+ */
+enum implicit_rule_index {
+	TAP_REMOTE_TX,
+	TAP_REMOTE_BROADCASTV6,
+	TAP_REMOTE_BROADCAST,
+	TAP_REMOTE_ALLMULTI,
+	TAP_REMOTE_PROMISC,
+	TAP_REMOTE_LOCAL_MAC,
+	TAP_REMOTE_MAX_IDX,
+};
+
 int tap_dev_filter_ctrl(struct rte_eth_dev *dev,
 			enum rte_filter_type filter_type,
 			enum rte_filter_op filter_op,
 			void *arg);
 int tap_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error);
 
+int tap_flow_implicit_create(struct pmd_internals *pmd,
+			     enum implicit_rule_index idx);
+int tap_flow_implicit_destroy(struct pmd_internals *pmd,
+			      enum implicit_rule_index idx);
+int tap_flow_implicit_flush(struct pmd_internals *pmd,
+			    struct rte_flow_error *error);
+
 #endif /* _TAP_FLOW_H_ */
Signature · 1 line
2.12.0.306.g4a9b9b3
Applied
#23 lore raw

Re: [PATCH v6 1/1] net/tap: add remote netdevice traffic capture

Quoted 8 lines · Pascal Mazon

By default, a tap netdevice is of no use when not fed by a separate process. The ability to automatically feed it from another netdevice allows applications to capture any kind of traffic normally destined to the kernel stack.

This patch implements this ability through a new optional "remote" parameter.

Quoted 7 lines

Packets matching filtering rules created with the flow API are matched on the remote device and redirected to the tap PMD, where the relevant action will be performed.

Applied to dpdk-next-net/master, thanks.