net/tap: add persist option

Message ID 20220809193411.182392-1-stephen@networkplumber.org (mailing list archive)
State Accepted, archived
Delegated to: Andrew Rybchenko
Headers
Series net/tap: add persist option |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation success Compilation OK
ci/intel-Testing success Testing PASS
ci/github-robot: build success github build: passed
ci/iol-mellanox-Performance success Performance Testing PASS
ci/iol-aarch64-unit-testing success Testing PASS
ci/iol-x86_64-unit-testing success Testing PASS
ci/iol-aarch64-compile-testing success Testing PASS
ci/iol-x86_64-compile-testing success Testing PASS
ci/iol-intel-Performance success Performance Testing PASS
ci/iol-intel-Functional success Functional Testing PASS

Commit Message

Stephen Hemminger Aug. 9, 2022, 7:34 p.m. UTC
  The TAP device only lasts as long as the DPDK application that opened
it is running. This behavior is basd if the DPDK application needs
to be updated transparently without disturbing other services
using the tap device.

This patch adds a persist feature to the TAP device. If this flag
is set, the kernel network device remains even if after the application
has exited.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 doc/guides/nics/tap.rst       |  6 ++++++
 drivers/net/tap/rte_eth_tap.c | 39 ++++++++++++++++++++++++++++-------
 drivers/net/tap/rte_eth_tap.h |  1 +
 3 files changed, 38 insertions(+), 8 deletions(-)
  

Comments

Andrew Rybchenko Oct. 4, 2022, 2:44 p.m. UTC | #1
On 8/9/22 22:34, Stephen Hemminger wrote:
> The TAP device only lasts as long as the DPDK application that opened
> it is running. This behavior is basd if the DPDK application needs
> to be updated transparently without disturbing other services
> using the tap device.
> 
> This patch adds a persist feature to the TAP device. If this flag
> is set, the kernel network device remains even if after the application
> has exited.
> 
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>

Reviewed-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>

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

Patch

diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
index 3d4564b04612..c5a8c69a7274 100644
--- a/doc/guides/nics/tap.rst
+++ b/doc/guides/nics/tap.rst
@@ -83,6 +83,12 @@  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.
 
+Normally, when the DPDK application exits the TAP device is marked down and
+is removed. But this behaviour can be overridden by the use of the persist
+flag, example::
+
+  --vdev=net_tap0,iface=tap0,persist ...
+
 The TUN PMD allows user to create a TUN device on host. The PMD allows user
 to transmit and receive packets via DPDK API calls with L3 header and payload.
 The devices in host can be accessed via ``ifconfig`` or ``ip`` command. TUN
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 9e1032fe7269..07b6bd7365ef 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -54,6 +54,7 @@ 
 #define ETH_TAP_REMOTE_ARG      "remote"
 #define ETH_TAP_MAC_ARG         "mac"
 #define ETH_TAP_MAC_FIXED       "fixed"
+#define ETH_TAP_PERSIST_ARG     "persist"
 
 #define ETH_TAP_USR_MAC_FMT     "xx:xx:xx:xx:xx:xx"
 #define ETH_TAP_CMP_MAC_FMT     "0123456789ABCDEFabcdef"
@@ -92,6 +93,7 @@  static const char *valid_arguments[] = {
 	ETH_TAP_IFACE_ARG,
 	ETH_TAP_REMOTE_ARG,
 	ETH_TAP_MAC_ARG,
+	ETH_TAP_PERSIST_ARG,
 	NULL
 };
 
@@ -140,11 +142,14 @@  static int tap_intr_handle_set(struct rte_eth_dev *dev, int set);
  * @param[in] is_keepalive
  *   Keepalive flag
  *
+ * @param[in] persistent
+ *   Mark device as persistent
+ *
  * @return
  *   -1 on failure, fd on success
  */
 static int
-tun_alloc(struct pmd_internals *pmd, int is_keepalive)
+tun_alloc(struct pmd_internals *pmd, int is_keepalive, int persistent)
 {
 	struct ifreq ifr;
 #ifdef IFF_MULTI_QUEUE
@@ -194,6 +199,14 @@  tun_alloc(struct pmd_internals *pmd, int is_keepalive)
 		goto error;
 	}
 
+	/* Keep the device after application exit */
+	if (persistent && ioctl(fd, TUNSETPERSIST, 1) < 0) {
+		TAP_LOG(WARNING,
+			"Unable to set persist %s: %s",
+			ifr.ifr_name, strerror(errno));
+		goto error;
+	}
+
 	/*
 	 * Name passed to kernel might be wildcard like dtun%d
 	 * and need to find the resulting device.
@@ -973,6 +986,7 @@  tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void
 static int
 tap_dev_stop(struct rte_eth_dev *dev)
 {
+	struct pmd_internals *pmd = dev->data->dev_private;
 	int i;
 
 	for (i = 0; i < dev->data->nb_tx_queues; i++)
@@ -981,7 +995,8 @@  tap_dev_stop(struct rte_eth_dev *dev)
 		dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
 
 	tap_intr_handle_set(dev, 0);
-	tap_link_set_down(dev);
+	if (!pmd->persist)
+		tap_link_set_down(dev);
 
 	return 0;
 }
@@ -1165,7 +1180,8 @@  tap_dev_close(struct rte_eth_dev *dev)
 		return 0;
 	}
 
-	tap_link_set_down(dev);
+	if (!internals->persist)
+		tap_link_set_down(dev);
 	if (internals->nlsk_fd != -1) {
 		tap_flow_flush(dev, NULL);
 		tap_flow_implicit_flush(internals, NULL);
@@ -1553,7 +1569,7 @@  tap_setup_queue(struct rte_eth_dev *dev,
 			pmd->name, *other_fd, dir, qid, *fd);
 	} else {
 		/* Both RX and TX fds do not exist (equal -1). Create fd */
-		*fd = tun_alloc(pmd, 0);
+		*fd = tun_alloc(pmd, 0, 0);
 		if (*fd < 0) {
 			*fd = -1; /* restore original value */
 			TAP_LOG(ERR, "%s: tun_alloc() failed.", pmd->name);
@@ -1958,7 +1974,7 @@  static const struct eth_dev_ops ops = {
 static int
 eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 		   char *remote_iface, struct rte_ether_addr *mac_addr,
-		   enum rte_tuntap_type type)
+		   enum rte_tuntap_type type, int persist)
 {
 	int numa_node = rte_socket_id();
 	struct rte_eth_dev *dev;
@@ -2050,7 +2066,7 @@  eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 	 * This keep-alive file descriptor will guarantee that the TUN device
 	 * exists even when all of its queues are closed
 	 */
-	pmd->ka_fd = tun_alloc(pmd, 1);
+	pmd->ka_fd = tun_alloc(pmd, 1, persist);
 	if (pmd->ka_fd == -1) {
 		TAP_LOG(ERR, "Unable to create %s interface", tuntap_name);
 		goto error_exit;
@@ -2070,6 +2086,9 @@  eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 			goto error_exit;
 	}
 
+	/* Make network device persist after application exit */
+	pmd->persist = persist;
+
 	/*
 	 * Set up everything related to rte_flow:
 	 * - netlink socket
@@ -2360,7 +2379,7 @@  rte_pmd_tun_probe(struct rte_vdev_device *dev)
 	TAP_LOG(DEBUG, "Initializing pmd_tun for %s", name);
 
 	ret = eth_dev_tap_create(dev, tun_name, remote_iface, 0,
-				 ETH_TUNTAP_TYPE_TUN);
+				 ETH_TUNTAP_TYPE_TUN, 0);
 
 leave:
 	if (ret == -1) {
@@ -2490,6 +2509,7 @@  rte_pmd_tap_probe(struct rte_vdev_device *dev)
 	struct rte_ether_addr user_mac = { .addr_bytes = {0} };
 	struct rte_eth_dev *eth_dev;
 	int tap_devices_count_increased = 0;
+	int persist = 0;
 
 	name = rte_vdev_device_name(dev);
 	params = rte_vdev_device_args(dev);
@@ -2573,6 +2593,9 @@  rte_pmd_tap_probe(struct rte_vdev_device *dev)
 				if (ret == -1)
 					goto leave;
 			}
+
+			if (rte_kvargs_count(kvlist, ETH_TAP_PERSIST_ARG) == 1)
+				persist = 1;
 		}
 	}
 	pmd_link.link_speed = speed;
@@ -2591,7 +2614,7 @@  rte_pmd_tap_probe(struct rte_vdev_device *dev)
 	tap_devices_count++;
 	tap_devices_count_increased = 1;
 	ret = eth_dev_tap_create(dev, tap_name, remote_iface, &user_mac,
-		ETH_TUNTAP_TYPE_TAP);
+				 ETH_TUNTAP_TYPE_TAP, persist);
 
 leave:
 	if (ret == -1) {
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index 996021e424fd..5ac93f93e961 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -80,6 +80,7 @@  struct pmd_internals {
 	int flower_support;               /* 1 if kernel supports, else 0 */
 	int flower_vlan_support;          /* 1 if kernel supports, else 0 */
 	int rss_enabled;                  /* 1 if RSS is enabled, else 0 */
+	int persist;			  /* 1 if keep link up, else 0 */
 	/* implicit rules set when RSS is enabled */
 	int map_fd;                       /* BPF RSS map fd */
 	int bpf_fd[RTE_PMD_TAP_MAX_QUEUES];/* List of bpf fds per queue */