@@ -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
@@ -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) {
@@ -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 */