All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] net/tap: update netlink error code management
@ 2017-03-29  9:44 Pascal Mazon
  2017-03-29  9:44 ` [PATCH 2/2] net/tap: update redirection rule after MAC change Pascal Mazon
  0 siblings, 1 reply; 9+ messages in thread
From: Pascal Mazon @ 2017-03-29  9:44 UTC (permalink / raw)
  To: keith.wiles; +Cc: dev, Pascal Mazon

Some errors received from the kernel are acceptable, such as a -ENOENT
for a rule deletion (the rule was already no longer existing in the
kernel). Make sure we consider return codes properly. For that,
nl_recv() has been simplified.

qdisc_exists() function is no longer needed as we can check whether the
kernel returned -EEXIST when requiring the qdisc creation. It's simpler
and faster.

Add a few messages for clarity when a netlink error occurs.

Signed-off-by: Pascal Mazon <pascal.mazon@6wind.com>
---
 drivers/net/tap/tap_flow.c    |  22 ++++++++-
 drivers/net/tap/tap_netlink.c |  73 +++++++++++++---------------
 drivers/net/tap/tap_tcmsgs.c  | 107 ++++++++++--------------------------------
 drivers/net/tap/tap_tcmsgs.h  |   2 -
 4 files changed, 80 insertions(+), 124 deletions(-)

diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 7f1693d40468..514e3fae5c38 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -31,6 +31,8 @@
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <errno.h>
+#include <string.h>
 #include <sys/queue.h>
 
 #include <rte_byteorder.h>
@@ -1165,6 +1167,9 @@ tap_flow_create(struct rte_eth_dev *dev,
 	}
 	err = nl_recv_ack(pmd->nlsk_fd);
 	if (err < 0) {
+		RTE_LOG(ERR, PMD,
+			"Kernel refused TC filter rule creation (%d): %s\n",
+			errno, strerror(errno));
 		rte_flow_error_set(error, EEXIST, RTE_FLOW_ERROR_TYPE_HANDLE,
 				   NULL, "overlapping rules");
 		goto fail;
@@ -1206,6 +1211,9 @@ tap_flow_create(struct rte_eth_dev *dev,
 		}
 		err = nl_recv_ack(pmd->nlsk_fd);
 		if (err < 0) {
+			RTE_LOG(ERR, PMD,
+				"Kernel refused TC filter rule creation (%d): %s\n",
+				errno, strerror(errno));
 			rte_flow_error_set(
 				error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
 				NULL, "overlapping rules");
@@ -1253,7 +1261,13 @@ tap_flow_destroy_pmd(struct pmd_internals *pmd,
 		goto end;
 	}
 	ret = nl_recv_ack(pmd->nlsk_fd);
+	/* If errno is ENOENT, the rule is already no longer in the kernel. */
+	if (ret < 0 && errno == ENOENT)
+		ret = 0;
 	if (ret < 0) {
+		RTE_LOG(ERR, PMD,
+			"Kernel refused TC filter rule deletion (%d): %s\n",
+			errno, strerror(errno));
 		rte_flow_error_set(
 			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 			"couldn't receive kernel ack to our request");
@@ -1271,7 +1285,12 @@ tap_flow_destroy_pmd(struct pmd_internals *pmd,
 			goto end;
 		}
 		ret = nl_recv_ack(pmd->nlsk_fd);
+		if (ret < 0 && errno == ENOENT)
+			ret = 0;
 		if (ret < 0) {
+			RTE_LOG(ERR, PMD,
+				"Kernel refused TC filter rule deletion (%d): %s\n",
+				errno, strerror(errno));
 			rte_flow_error_set(
 				error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
 				NULL, "Failure trying to receive nl ack");
@@ -1386,7 +1405,8 @@ int tap_flow_implicit_create(struct pmd_internals *pmd,
 	err = nl_recv_ack(pmd->nlsk_fd);
 	if (err < 0) {
 		RTE_LOG(ERR, PMD,
-			"Kernel refused TC filter rule creation");
+			"Kernel refused TC filter rule creation (%d): %s\n",
+			errno, strerror(errno));
 		goto fail;
 	}
 	LIST_INSERT_HEAD(&pmd->implicit_flows, remote_flow, next);
diff --git a/drivers/net/tap/tap_netlink.c b/drivers/net/tap/tap_netlink.c
index 6de896ab17b6..ee92e2e7ed13 100644
--- a/drivers/net/tap/tap_netlink.c
+++ b/drivers/net/tap/tap_netlink.c
@@ -159,7 +159,7 @@ nl_send(int nlsk_fd, struct nlmsghdr *nh)
  *   The netlink socket file descriptor used for communication.
  *
  * @return
- *   0 on success, -1 otherwise.
+ *   0 on success, -1 otherwise with errno set.
  */
 int
 nl_recv_ack(int nlsk_fd)
@@ -179,14 +179,13 @@ nl_recv_ack(int nlsk_fd)
  *   Custom arguments for the callback.
  *
  * @return
- *   0 on success, -1 otherwise.
+ *   0 on success, -1 otherwise with errno set.
  */
 int
 nl_recv(int nlsk_fd, int (*cb)(struct nlmsghdr *, void *arg), void *arg)
 {
 	/* man 7 netlink EXAMPLE */
 	struct sockaddr_nl sa;
-	struct nlmsghdr *nh;
 	char buf[BUF_SIZE];
 	struct iovec iov = {
 		.iov_base = buf,
@@ -196,49 +195,43 @@ nl_recv(int nlsk_fd, int (*cb)(struct nlmsghdr *, void *arg), void *arg)
 		.msg_name = &sa,
 		.msg_namelen = sizeof(sa),
 		.msg_iov = &iov,
+		/* One message at a time */
 		.msg_iovlen = 1,
 	};
-	int recv_bytes = 0, done = 0, multipart = 0, error = 0;
+	int multipart = 0;
+	int ret = 0;
 
-read:
-	recv_bytes = recvmsg(nlsk_fd, &msg, 0);
-	if (recv_bytes < 0)
-		return -1;
-	for (nh = (struct nlmsghdr *)buf;
-	     NLMSG_OK(nh, (unsigned int)recv_bytes);
-	     nh = NLMSG_NEXT(nh, recv_bytes)) {
-		/*
-		 * Multi-part messages and their following DONE message have the
-		 * NLM_F_MULTI flag set. Make note, in order to read the DONE
-		 * message afterwards.
-		 */
-		if (nh->nlmsg_flags & NLM_F_MULTI)
-			multipart = 1;
-		if (nh->nlmsg_type == NLMSG_ERROR) {
-			struct nlmsgerr *err_data = NLMSG_DATA(nh);
+	do {
+		struct nlmsghdr *nh;
+		int recv_bytes = 0;
+
+		recv_bytes = recvmsg(nlsk_fd, &msg, 0);
+		if (recv_bytes < 0)
+			return -1;
+		for (nh = (struct nlmsghdr *)buf;
+		     NLMSG_OK(nh, (unsigned int)recv_bytes);
+		     nh = NLMSG_NEXT(nh, recv_bytes)) {
+			if (nh->nlmsg_type == NLMSG_ERROR) {
+				struct nlmsgerr *err_data = NLMSG_DATA(nh);
 
-			if (err_data->error == 0)
-				RTE_LOG(DEBUG, PMD, "%s() ack message recvd\n",
-					__func__);
-			else {
-				RTE_LOG(DEBUG, PMD,
-					"%s() error message recvd\n", __func__);
-				error = 1;
+				if (err_data->error < 0) {
+					errno = -err_data->error;
+					return -1;
+				}
+				/* Ack message. */
+				return 0;
 			}
+			/* Multi-part msgs and their trailing DONE message. */
+			if (nh->nlmsg_flags & NLM_F_MULTI) {
+				if (nh->nlmsg_type == NLMSG_DONE)
+					return 0;
+				multipart = 1;
+			}
+			if (cb)
+				ret = cb(nh, arg);
 		}
-		/* The end of multipart message. */
-		if (nh->nlmsg_type == NLMSG_DONE)
-			/* No need to call the callback for a DONE message. */
-			done = 1;
-		else if (cb)
-			if (cb(nh, arg) < 0)
-				error = 1;
-	}
-	if (multipart && !done)
-		goto read;
-	if (error)
-		return -1;
-	return 0;
+	} while (multipart);
+	return ret;
 }
 
 /**
diff --git a/drivers/net/tap/tap_tcmsgs.c b/drivers/net/tap/tap_tcmsgs.c
index af1c9aec0d22..d74ac805b184 100644
--- a/drivers/net/tap/tap_tcmsgs.c
+++ b/drivers/net/tap/tap_tcmsgs.c
@@ -94,7 +94,7 @@ tc_init_msg(struct nlmsg *msg, uint16_t ifindex, uint16_t type, uint16_t flags)
  *   Additional info to identify the QDISC (handle and parent).
  *
  * @return
- *   0 on success, -1 otherwise.
+ *   0 on success, -1 otherwise with errno set.
  */
 static int
 qdisc_del(int nlsk_fd, uint16_t ifindex, struct qdisc *qinfo)
@@ -117,12 +117,16 @@ qdisc_del(int nlsk_fd, uint16_t ifindex, struct qdisc *qinfo)
 		fd = nlsk_fd;
 	}
 	if (nl_send(fd, &msg.nh) < 0)
-		return -1;
+		goto error;
 	if (nl_recv_ack(fd) < 0)
-		return -1;
+		goto error;
 	if (!nlsk_fd)
 		return nl_final(fd);
 	return 0;
+error:
+	if (!nlsk_fd)
+		nl_final(fd);
+	return -1;
 }
 
 /**
@@ -134,7 +138,7 @@ qdisc_del(int nlsk_fd, uint16_t ifindex, struct qdisc *qinfo)
  *   The netdevice ifindex where to add the multiqueue QDISC.
  *
  * @return
- *   -1 if the qdisc cannot be added, and 0 otherwise.
+ *   0 on success, -1 otherwise with errno set.
  */
 int
 qdisc_add_multiq(int nlsk_fd, uint16_t ifindex)
@@ -164,7 +168,7 @@ qdisc_add_multiq(int nlsk_fd, uint16_t ifindex)
  *   The netdevice ifindex where the QDISC will be added.
  *
  * @return
- *   -1 if the qdisc cannot be added, and 0 otherwise.
+ *   0 on success, -1 otherwise with errno set.
  */
 int
 qdisc_add_ingress(int nlsk_fd, uint16_t ifindex)
@@ -184,34 +188,6 @@ qdisc_add_ingress(int nlsk_fd, uint16_t ifindex)
 }
 
 /**
- * Callback function to check for QDISC existence.
- * If the QDISC is found to exist, increment "exists" in the custom arg.
- *
- * @param[in] nh
- *   The netlink message to parse, received from the kernel.
- * @param[in, out] arg
- *   Custom arguments for the callback.
- *
- * @return
- *   0.
- */
-static int
-qdisc_exist_cb(struct nlmsghdr *nh, void *arg)
-{
-	struct list_args *args = (struct list_args *)arg;
-	struct qdisc_custom_arg *custom = args->custom_arg;
-	struct tcmsg *t = NLMSG_DATA(nh);
-
-	/* filter by request iface */
-	if (args->ifindex != (unsigned int)t->tcm_ifindex)
-		return 0;
-	if (t->tcm_handle != custom->handle || t->tcm_parent != custom->parent)
-		return 0;
-	custom->exists++;
-	return 0;
-}
-
-/**
  * Callback function to delete a QDISC.
  *
  * @param[in] nh
@@ -220,7 +196,7 @@ qdisc_exist_cb(struct nlmsghdr *nh, void *arg)
  *   Custom arguments for the callback.
  *
  * @return
- *   0.
+ *   0 on success, -1 otherwise with errno set.
  */
 static int
 qdisc_del_cb(struct nlmsghdr *nh, void *arg)
@@ -256,10 +232,7 @@ qdisc_del_cb(struct nlmsghdr *nh, void *arg)
  *   The arguments to provide the callback function with.
  *
  * @return
- *   -1 if either sending the netlink message failed, or if receiving the answer
- *   failed, or finally if the callback returned a negative value for that
- *   answer.
- *   0 is returned otherwise.
+ *   0 on success, -1 otherwise with errno set.
  */
 static int
 qdisc_iterate(int nlsk_fd, uint16_t ifindex,
@@ -281,36 +254,6 @@ qdisc_iterate(int nlsk_fd, uint16_t ifindex,
 }
 
 /**
- * Check whether a given QDISC already exists for the netdevice.
- *
- * @param[in] nlsk_fd
- *   The netlink socket file descriptor used for communication.
- * @param[in] ifindex
- *   The netdevice ifindex to check QDISC existence for.
- * @param[in] callback
- *   The function to call for each QDISC.
- * @param[in, out] arg
- *   The arguments to provide the callback function with.
- *
- * @return
- *   1 if the qdisc exists, 0 otherwise.
- */
-int
-qdisc_exists(int nlsk_fd, uint16_t ifindex, uint32_t handle, uint32_t parent)
-{
-	struct qdisc_custom_arg arg = {
-		.handle = handle,
-		.parent = parent,
-		.exists = 0,
-	};
-
-	qdisc_iterate(nlsk_fd, ifindex, qdisc_exist_cb, &arg);
-	if (arg.exists)
-		return 1;
-	return 0;
-}
-
-/**
  * Delete all QDISCs for a given netdevice.
  *
  * @param[in] nlsk_fd
@@ -319,7 +262,7 @@ qdisc_exists(int nlsk_fd, uint16_t ifindex, uint32_t handle, uint32_t parent)
  *   The netdevice ifindex where to find QDISCs.
  *
  * @return
- *   -1 if the lookup failed, 0 otherwise.
+ *   0 on success, -1 otherwise with errno set.
  */
 int
 qdisc_flush(int nlsk_fd, uint16_t ifindex)
@@ -342,12 +285,13 @@ qdisc_flush(int nlsk_fd, uint16_t ifindex)
 int
 qdisc_create_multiq(int nlsk_fd, uint16_t ifindex)
 {
-	if (!qdisc_exists(nlsk_fd, ifindex,
-			  TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0), TC_H_ROOT)) {
-		if (qdisc_add_multiq(nlsk_fd, ifindex) < 0) {
-			RTE_LOG(ERR, PMD, "Could not add multiq qdisc\n");
-			return -1;
-		}
+	int err = 0;
+
+	err = qdisc_add_multiq(nlsk_fd, ifindex);
+	if (err < 0 && errno != -EEXIST) {
+		RTE_LOG(ERR, PMD, "Could not add multiq qdisc (%d): %s\n",
+			errno, strerror(errno));
+		return -1;
 	}
 	return 0;
 }
@@ -367,12 +311,13 @@ qdisc_create_multiq(int nlsk_fd, uint16_t ifindex)
 int
 qdisc_create_ingress(int nlsk_fd, uint16_t ifindex)
 {
-	if (!qdisc_exists(nlsk_fd, ifindex,
-			  TC_H_MAKE(TC_H_INGRESS, 0), TC_H_INGRESS)) {
-		if (qdisc_add_ingress(nlsk_fd, ifindex) < 0) {
-			RTE_LOG(ERR, PMD, "Could not add ingress qdisc\n");
-			return -1;
-		}
+	int err = 0;
+
+	err = qdisc_add_ingress(nlsk_fd, ifindex);
+	if (err < 0 && errno != -EEXIST) {
+		RTE_LOG(ERR, PMD, "Could not add ingress qdisc (%d): %s\n",
+			errno, strerror(errno));
+		return -1;
 	}
 	return 0;
 }
diff --git a/drivers/net/tap/tap_tcmsgs.h b/drivers/net/tap/tap_tcmsgs.h
index a571a56d6964..789595771d63 100644
--- a/drivers/net/tap/tap_tcmsgs.h
+++ b/drivers/net/tap/tap_tcmsgs.h
@@ -50,8 +50,6 @@
 
 void tc_init_msg(struct nlmsg *msg, uint16_t ifindex, uint16_t type,
 		 uint16_t flags);
-int qdisc_exists(int nlsk_fd, uint16_t ifindex, uint32_t handle,
-		 uint32_t parent);
 int qdisc_list(int nlsk_fd, uint16_t ifindex);
 int qdisc_flush(int nlsk_fd, uint16_t ifindex);
 int qdisc_create_ingress(int nlsk_fd, uint16_t ifindex);
-- 
2.12.0.306.g4a9b9b3

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/2] net/tap: update redirection rule after MAC change
  2017-03-29  9:44 [PATCH 1/2] net/tap: update netlink error code management Pascal Mazon
@ 2017-03-29  9:44 ` Pascal Mazon
  2017-03-31 13:02   ` [PATCH v2 1/2] net/tap: fix null MAC address at init Pascal Mazon
  2017-03-31 13:02   ` [PATCH v2 2/2] net/tap: fix redirection rule after MAC change Pascal Mazon
  0 siblings, 2 replies; 9+ messages in thread
From: Pascal Mazon @ 2017-03-29  9:44 UTC (permalink / raw)
  To: keith.wiles; +Cc: dev, Pascal Mazon

This is necessary to ensure packets with the new MAC address as
destination get redirected to the tap device.

Also make the change only if the requested MAC address is different from
the current one.

Fixes: 75b6a1f7f004 ("net/tap: add remote netdevice traffic capture")
Signed-off-by: Pascal Mazon <pascal.mazon@6wind.com>
---
 drivers/net/tap/rte_eth_tap.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 6567bba75b47..069200199573 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -772,6 +772,8 @@ tap_mac_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
 	struct pmd_internals *pmd = dev->data->dev_private;
 	struct ifreq ifr;
 
+	if (is_same_ether_addr(mac_addr, &pmd->eth_addr))
+		return;
 	if (is_zero_ether_addr(mac_addr)) {
 		RTE_LOG(ERR, PMD, "%s: can't set an empty MAC address\n",
 			dev->data->name);
@@ -783,6 +785,19 @@ tap_mac_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
 	if (tap_ioctl(pmd, SIOCSIFHWADDR, &ifr, 1) < 0)
 		return;
 	rte_memcpy(&pmd->eth_addr, mac_addr, ETHER_ADDR_LEN);
+	if (pmd->remote_if_index) {
+		/* Replace MAC redirection rule after a MAC change */
+		if (tap_flow_implicit_destroy(pmd, TAP_REMOTE_LOCAL_MAC) < 0) {
+			RTE_LOG(ERR, PMD,
+				"%s: Couldn't delete MAC redirection rule\n",
+				pmd->remote_iface);
+			return;
+		}
+		if (tap_flow_implicit_create(pmd, TAP_REMOTE_LOCAL_MAC) < 0)
+			RTE_LOG(ERR, PMD,
+				"%s: Couldn't add MAC redirection rule\n",
+				pmd->remote_iface);
+	}
 }
 
 static int
-- 
2.12.0.306.g4a9b9b3

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 1/2] net/tap: fix null MAC address at init
  2017-03-29  9:44 ` [PATCH 2/2] net/tap: update redirection rule after MAC change Pascal Mazon
@ 2017-03-31 13:02   ` Pascal Mazon
  2017-03-31 13:54     ` [PATCH v3 0/3] net/tap: netlink and MAC address fixes Pascal Mazon
  2017-03-31 13:02   ` [PATCH v2 2/2] net/tap: fix redirection rule after MAC change Pascal Mazon
  1 sibling, 1 reply; 9+ messages in thread
From: Pascal Mazon @ 2017-03-31 13:02 UTC (permalink / raw)
  To: keith.wiles; +Cc: dev, Pascal Mazon

Immediately after init (probing), the device MAC address is all zeroes.
It should be possible to get a correct MAC address as soon as that,
without need for a dev_configure().

With this patch, a MAC address is set in eth_dev_tap_create()
explicitly. It either comes from the remote if any was configured, or is
randomly generated. In any case, the device MAC address is guaranteed to
be the correct one when the tap netdevice actually gets created in
tun_alloc().

Fixes: 77a92d9f33a8 ("net/tap: add MAC address management")
Fixes: 7d1aa96ee105 ("net/tap: add remote netdevice traffic capture")

Signed-off-by: Pascal Mazon <pascal.mazon@6wind.com>
---
 drivers/net/tap/rte_eth_tap.c | 85 ++++++++++++++++++++++++-------------------
 1 file changed, 48 insertions(+), 37 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 6567bba75b47..72897adcce3b 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -108,9 +108,16 @@ tap_trigger_cb(int sig __rte_unused)
 	tap_trigger = (tap_trigger + 1) | 0x80000000;
 }
 
+/* Specifies on what netdevices the ioctl should be applied */
+enum ioctl_mode {
+	LOCAL_AND_REMOTE,
+	LOCAL_ONLY,
+	REMOTE_ONLY,
+};
+
 static int
 tap_ioctl(struct pmd_internals *pmd, unsigned long request,
-	  struct ifreq *ifr, int set);
+	  struct ifreq *ifr, int set, enum ioctl_mode mode);
 
 static int tap_intr_handle_set(struct rte_eth_dev *dev, int set);
 
@@ -222,10 +229,15 @@ tun_alloc(struct pmd_internals *pmd, uint16_t qid)
 	if (qid == 0) {
 		struct ifreq ifr;
 
-		if (tap_ioctl(pmd, SIOCGIFHWADDR, &ifr, 0) < 0)
-			goto error;
-		rte_memcpy(&pmd->eth_addr, ifr.ifr_hwaddr.sa_data,
+		/*
+		 * pmd->eth_addr contains the desired MAC, either from remote
+		 * or from a random assignment. Sync it with the tap netdevice.
+		 */
+		ifr.ifr_hwaddr.sa_family = AF_LOCAL;
+		rte_memcpy(ifr.ifr_hwaddr.sa_data, &pmd->eth_addr,
 			   ETHER_ADDR_LEN);
+		if (tap_ioctl(pmd, SIOCSIFHWADDR, &ifr, 0, LOCAL_ONLY) < 0)
+			goto error;
 
 		pmd->if_index = if_nametoindex(pmd->name);
 		if (!pmd->if_index) {
@@ -437,27 +449,22 @@ pmd_tx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 
 static int
 tap_ioctl(struct pmd_internals *pmd, unsigned long request,
-	  struct ifreq *ifr, int set)
+	  struct ifreq *ifr, int set, enum ioctl_mode mode)
 {
 	short req_flags = ifr->ifr_flags;
-	int remote = !!pmd->remote_if_index;
+	int remote = pmd->remote_if_index &&
+		(mode == REMOTE_ONLY || mode == LOCAL_AND_REMOTE);
 
+	if (!pmd->remote_if_index && mode == REMOTE_ONLY)
+		return 0;
 	/*
 	 * If there is a remote netdevice, apply ioctl on it, then apply it on
 	 * the tap netdevice.
 	 */
-	if (request == SIOCGIFFLAGS && !set) {
-		/*
-		 * Special case for getting flags. If set is given,
-		 * then return the flags from the remote netdevice only.
-		 * Otherwise return the flags from the tap netdevice.
-		 */
-		remote = 0;
-	}
 apply:
 	if (remote)
 		snprintf(ifr->ifr_name, IFNAMSIZ, "%s", pmd->remote_iface);
-	else
+	else if (mode == LOCAL_ONLY || mode == LOCAL_AND_REMOTE)
 		snprintf(ifr->ifr_name, IFNAMSIZ, "%s", pmd->name);
 	switch (request) {
 	case SIOCSIFFLAGS:
@@ -470,16 +477,7 @@ tap_ioctl(struct pmd_internals *pmd, unsigned long request,
 			ifr->ifr_flags &= ~req_flags;
 		break;
 	case SIOCGIFFLAGS:
-		if (remote && set)
-			remote = 0; /* don't loop */
-		break;
 	case SIOCGIFHWADDR:
-		/* Set remote MAC on the tap netdevice */
-		if (!remote && pmd->remote_if_index) {
-			request = SIOCSIFHWADDR;
-			goto apply;
-		}
-		break;
 	case SIOCSIFHWADDR:
 	case SIOCSIFMTU:
 		break;
@@ -490,7 +488,7 @@ tap_ioctl(struct pmd_internals *pmd, unsigned long request,
 	}
 	if (ioctl(pmd->ioctl_sock, request, ifr) < 0)
 		goto error;
-	if (remote--)
+	if (remote-- && mode == LOCAL_AND_REMOTE)
 		goto apply;
 	return 0;
 
@@ -507,7 +505,7 @@ tap_link_set_down(struct rte_eth_dev *dev)
 	struct ifreq ifr = { .ifr_flags = IFF_UP };
 
 	dev->data->dev_link.link_status = ETH_LINK_DOWN;
-	return tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 0);
+	return tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 0, LOCAL_AND_REMOTE);
 }
 
 static int
@@ -517,7 +515,7 @@ tap_link_set_up(struct rte_eth_dev *dev)
 	struct ifreq ifr = { .ifr_flags = IFF_UP };
 
 	dev->data->dev_link.link_status = ETH_LINK_UP;
-	return tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 1);
+	return tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 1, LOCAL_AND_REMOTE);
 }
 
 static int
@@ -702,14 +700,14 @@ tap_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused)
 	struct ifreq ifr = { .ifr_flags = 0 };
 
 	if (pmd->remote_if_index) {
-		tap_ioctl(pmd, SIOCGIFFLAGS, &ifr, 1);
+		tap_ioctl(pmd, SIOCGIFFLAGS, &ifr, 0, REMOTE_ONLY);
 		if (!(ifr.ifr_flags & IFF_UP) ||
 		    !(ifr.ifr_flags & IFF_RUNNING)) {
 			dev_link->link_status = ETH_LINK_DOWN;
 			return 0;
 		}
 	}
-	tap_ioctl(pmd, SIOCGIFFLAGS, &ifr, 0);
+	tap_ioctl(pmd, SIOCGIFFLAGS, &ifr, 0, LOCAL_ONLY);
 	dev_link->link_status =
 		((ifr.ifr_flags & IFF_UP) && (ifr.ifr_flags & IFF_RUNNING) ?
 		 ETH_LINK_UP :
@@ -724,7 +722,7 @@ tap_promisc_enable(struct rte_eth_dev *dev)
 	struct ifreq ifr = { .ifr_flags = IFF_PROMISC };
 
 	dev->data->promiscuous = 1;
-	tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 1);
+	tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 1, LOCAL_AND_REMOTE);
 	if (pmd->remote_if_index)
 		tap_flow_implicit_create(pmd, TAP_REMOTE_PROMISC);
 }
@@ -736,7 +734,7 @@ tap_promisc_disable(struct rte_eth_dev *dev)
 	struct ifreq ifr = { .ifr_flags = IFF_PROMISC };
 
 	dev->data->promiscuous = 0;
-	tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 0);
+	tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 0, LOCAL_AND_REMOTE);
 	if (pmd->remote_if_index)
 		tap_flow_implicit_destroy(pmd, TAP_REMOTE_PROMISC);
 }
@@ -748,7 +746,7 @@ tap_allmulti_enable(struct rte_eth_dev *dev)
 	struct ifreq ifr = { .ifr_flags = IFF_ALLMULTI };
 
 	dev->data->all_multicast = 1;
-	tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 1);
+	tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 1, LOCAL_AND_REMOTE);
 	if (pmd->remote_if_index)
 		tap_flow_implicit_create(pmd, TAP_REMOTE_ALLMULTI);
 }
@@ -760,7 +758,7 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 	struct ifreq ifr = { .ifr_flags = IFF_ALLMULTI };
 
 	dev->data->all_multicast = 0;
-	tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 0);
+	tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 0, LOCAL_AND_REMOTE);
 	if (pmd->remote_if_index)
 		tap_flow_implicit_destroy(pmd, TAP_REMOTE_ALLMULTI);
 }
@@ -780,7 +778,7 @@ tap_mac_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
 
 	ifr.ifr_hwaddr.sa_family = AF_LOCAL;
 	rte_memcpy(ifr.ifr_hwaddr.sa_data, mac_addr, ETHER_ADDR_LEN);
-	if (tap_ioctl(pmd, SIOCSIFHWADDR, &ifr, 1) < 0)
+	if (tap_ioctl(pmd, SIOCSIFHWADDR, &ifr, 1, LOCAL_AND_REMOTE) < 0)
 		return;
 	rte_memcpy(&pmd->eth_addr, mac_addr, ETHER_ADDR_LEN);
 }
@@ -811,7 +809,8 @@ tap_setup_queue(struct rte_eth_dev *dev,
 				struct ifreq ifr;
 
 				ifr.ifr_mtu = dev->data->mtu;
-				if (tap_ioctl(pmd, SIOCSIFMTU, &ifr, 1) < 0) {
+				if (tap_ioctl(pmd, SIOCSIFMTU, &ifr, 1,
+					      LOCAL_AND_REMOTE) < 0) {
 					close(fd);
 					return -1;
 				}
@@ -966,7 +965,7 @@ tap_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 	struct ifreq ifr = { .ifr_mtu = mtu };
 	int err = 0;
 
-	err = tap_ioctl(pmd, SIOCSIFMTU, &ifr, 1);
+	err = tap_ioctl(pmd, SIOCSIFMTU, &ifr, 1, LOCAL_AND_REMOTE);
 	if (!err)
 		dev->data->mtu = mtu;
 
@@ -1210,13 +1209,25 @@ eth_dev_tap_create(const char *name, char *tap_name, char *remote_iface)
 	 */
 	pmd->nlsk_fd = nl_init(0);
 	if (strlen(remote_iface)) {
+		struct ifreq ifr;
+
 		pmd->remote_if_index = if_nametoindex(remote_iface);
 		snprintf(pmd->remote_iface, RTE_ETH_NAME_MAX_LEN,
 			 "%s", remote_iface);
-		if (!pmd->remote_if_index)
+		if (!pmd->remote_if_index) {
 			RTE_LOG(ERR, PMD, "Could not find %s ifindex: "
 				"remote interface will remain unconfigured\n",
 				remote_iface);
+			return 0;
+		}
+		if (tap_ioctl(pmd, SIOCGIFHWADDR, &ifr, 0, REMOTE_ONLY) < 0) {
+			RTE_LOG(ERR, PMD, "Could not get remote MAC address\n");
+			goto error_exit;
+		}
+		rte_memcpy(&pmd->eth_addr, ifr.ifr_hwaddr.sa_data,
+			   ETHER_ADDR_LEN);
+	} else {
+		eth_random_addr((uint8_t *)&pmd->eth_addr);
 	}
 
 	return 0;
-- 
2.12.0.306.g4a9b9b3

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 2/2] net/tap: fix redirection rule after MAC change
  2017-03-29  9:44 ` [PATCH 2/2] net/tap: update redirection rule after MAC change Pascal Mazon
  2017-03-31 13:02   ` [PATCH v2 1/2] net/tap: fix null MAC address at init Pascal Mazon
@ 2017-03-31 13:02   ` Pascal Mazon
  1 sibling, 0 replies; 9+ messages in thread
From: Pascal Mazon @ 2017-03-31 13:02 UTC (permalink / raw)
  To: keith.wiles; +Cc: dev, Pascal Mazon

This is necessary to ensure packets with the new MAC address as
destination get redirected to the tap device.

Also change the MAC address only if the current one is different from
the requested one.

Fixes: 75b6a1f7f004 ("net/tap: add remote netdevice traffic capture")
Signed-off-by: Pascal Mazon <pascal.mazon@6wind.com>
---
 drivers/net/tap/rte_eth_tap.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 72897adcce3b..618fd02800d5 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -775,12 +775,35 @@ tap_mac_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
 			dev->data->name);
 		return;
 	}
+	/* Check the actual current MAC address on the tap netdevice */
+	if (tap_ioctl(pmd, SIOCGIFHWADDR, &ifr, 0, LOCAL_ONLY) != 0) {
+		RTE_LOG(ERR, PMD,
+			"%s: couldn't check current tap MAC address\n",
+			dev->data->name);
+		return;
+	}
+	if (is_same_ether_addr((struct ether_addr *)&ifr.ifr_hwaddr.sa_data,
+			       mac_addr))
+		return;
 
 	ifr.ifr_hwaddr.sa_family = AF_LOCAL;
 	rte_memcpy(ifr.ifr_hwaddr.sa_data, mac_addr, ETHER_ADDR_LEN);
 	if (tap_ioctl(pmd, SIOCSIFHWADDR, &ifr, 1, LOCAL_AND_REMOTE) < 0)
 		return;
 	rte_memcpy(&pmd->eth_addr, mac_addr, ETHER_ADDR_LEN);
+	if (pmd->remote_if_index) {
+		/* Replace MAC redirection rule after a MAC change */
+		if (tap_flow_implicit_destroy(pmd, TAP_REMOTE_LOCAL_MAC) < 0) {
+			RTE_LOG(ERR, PMD,
+				"%s: Couldn't delete MAC redirection rule\n",
+				dev->data->name);
+			return;
+		}
+		if (tap_flow_implicit_create(pmd, TAP_REMOTE_LOCAL_MAC) < 0)
+			RTE_LOG(ERR, PMD,
+				"%s: Couldn't add MAC redirection rule\n",
+				dev->data->name);
+	}
 }
 
 static int
-- 
2.12.0.306.g4a9b9b3

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 0/3] net/tap: netlink and MAC address fixes
  2017-03-31 13:02   ` [PATCH v2 1/2] net/tap: fix null MAC address at init Pascal Mazon
@ 2017-03-31 13:54     ` Pascal Mazon
  2017-03-31 13:54       ` [PATCH v3 1/3] net/tap: update netlink error code management Pascal Mazon
                         ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Pascal Mazon @ 2017-03-31 13:54 UTC (permalink / raw)
  To: keith.wiles; +Cc: dev, Pascal Mazon

I'm adding a cover letter to clarify this series history, as I've mixed my
versions a little...

This series fixes some errors in the tap PMD.

v3 changes:
  - Re-sending the complete patch series:
      [PATCH v3 1/3] net/tap: update netlink error code management
      [PATCH v3 2/3] net/tap: fix null MAC address at init
      [PATCH v3 3/3] net/tap: fix redirection rule after MAC change


v2 changes:
  I separated patch for MAC address in two:
  - 1 for ensuring the device MAC address is set immediately after init:
      [PATCH v2 1/2] net/tap: fix null MAC address at init

  - 1 for ensuring the MAC address redirection rule is changed when
    needed:
      [PATCH v2 2/2] net/tap: fix redirection rule after MAC change

  But I forgot to re-send the netlink patch, which is now missing from
  DPDK patchwork...

v1:
  - 1 patch for netlink: correctly interpret the kernel's error message:
      [PATCH 1/2] net/tap: update netlink error code management

  - 1 patch for MAC address: update remote MAC address redirection:
      [PATCH 2/2] net/tap: update redirection rule after MAC change

Pascal Mazon (3):
  net/tap: update netlink error code management
  net/tap: fix null MAC address at init
  net/tap: fix redirection rule after MAC change

 drivers/net/tap/rte_eth_tap.c | 108 +++++++++++++++++++++++++++---------------
 drivers/net/tap/tap_flow.c    |  22 ++++++++-
 drivers/net/tap/tap_netlink.c |  73 +++++++++++++---------------
 drivers/net/tap/tap_tcmsgs.c  | 107 ++++++++++-------------------------------
 drivers/net/tap/tap_tcmsgs.h  |   2 -
 5 files changed, 151 insertions(+), 161 deletions(-)

--
2.12.0.306.g4a9b9b3

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 1/3] net/tap: update netlink error code management
  2017-03-31 13:54     ` [PATCH v3 0/3] net/tap: netlink and MAC address fixes Pascal Mazon
@ 2017-03-31 13:54       ` Pascal Mazon
  2017-03-31 13:54       ` [PATCH v3 2/3] net/tap: fix null MAC address at init Pascal Mazon
                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 9+ messages in thread
From: Pascal Mazon @ 2017-03-31 13:54 UTC (permalink / raw)
  To: keith.wiles; +Cc: dev, Pascal Mazon

Some errors received from the kernel are acceptable, such as a -ENOENT
for a rule deletion (the rule was already no longer existing in the
kernel). Make sure we consider return codes properly. For that,
nl_recv() has been simplified.

qdisc_exists() function is no longer needed as we can check whether the
kernel returned -EEXIST when requiring the qdisc creation. It's simpler
and faster.

Add a few messages for clarity when a netlink error occurs.

Signed-off-by: Pascal Mazon <pascal.mazon@6wind.com>
---
 drivers/net/tap/tap_flow.c    |  22 ++++++++-
 drivers/net/tap/tap_netlink.c |  73 +++++++++++++---------------
 drivers/net/tap/tap_tcmsgs.c  | 107 ++++++++++--------------------------------
 drivers/net/tap/tap_tcmsgs.h  |   2 -
 4 files changed, 80 insertions(+), 124 deletions(-)

diff --git a/drivers/net/tap/tap_flow.c b/drivers/net/tap/tap_flow.c
index 7f1693d40468..514e3fae5c38 100644
--- a/drivers/net/tap/tap_flow.c
+++ b/drivers/net/tap/tap_flow.c
@@ -31,6 +31,8 @@
  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <errno.h>
+#include <string.h>
 #include <sys/queue.h>
 
 #include <rte_byteorder.h>
@@ -1165,6 +1167,9 @@ tap_flow_create(struct rte_eth_dev *dev,
 	}
 	err = nl_recv_ack(pmd->nlsk_fd);
 	if (err < 0) {
+		RTE_LOG(ERR, PMD,
+			"Kernel refused TC filter rule creation (%d): %s\n",
+			errno, strerror(errno));
 		rte_flow_error_set(error, EEXIST, RTE_FLOW_ERROR_TYPE_HANDLE,
 				   NULL, "overlapping rules");
 		goto fail;
@@ -1206,6 +1211,9 @@ tap_flow_create(struct rte_eth_dev *dev,
 		}
 		err = nl_recv_ack(pmd->nlsk_fd);
 		if (err < 0) {
+			RTE_LOG(ERR, PMD,
+				"Kernel refused TC filter rule creation (%d): %s\n",
+				errno, strerror(errno));
 			rte_flow_error_set(
 				error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
 				NULL, "overlapping rules");
@@ -1253,7 +1261,13 @@ tap_flow_destroy_pmd(struct pmd_internals *pmd,
 		goto end;
 	}
 	ret = nl_recv_ack(pmd->nlsk_fd);
+	/* If errno is ENOENT, the rule is already no longer in the kernel. */
+	if (ret < 0 && errno == ENOENT)
+		ret = 0;
 	if (ret < 0) {
+		RTE_LOG(ERR, PMD,
+			"Kernel refused TC filter rule deletion (%d): %s\n",
+			errno, strerror(errno));
 		rte_flow_error_set(
 			error, ENOTSUP, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 			"couldn't receive kernel ack to our request");
@@ -1271,7 +1285,12 @@ tap_flow_destroy_pmd(struct pmd_internals *pmd,
 			goto end;
 		}
 		ret = nl_recv_ack(pmd->nlsk_fd);
+		if (ret < 0 && errno == ENOENT)
+			ret = 0;
 		if (ret < 0) {
+			RTE_LOG(ERR, PMD,
+				"Kernel refused TC filter rule deletion (%d): %s\n",
+				errno, strerror(errno));
 			rte_flow_error_set(
 				error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE,
 				NULL, "Failure trying to receive nl ack");
@@ -1386,7 +1405,8 @@ int tap_flow_implicit_create(struct pmd_internals *pmd,
 	err = nl_recv_ack(pmd->nlsk_fd);
 	if (err < 0) {
 		RTE_LOG(ERR, PMD,
-			"Kernel refused TC filter rule creation");
+			"Kernel refused TC filter rule creation (%d): %s\n",
+			errno, strerror(errno));
 		goto fail;
 	}
 	LIST_INSERT_HEAD(&pmd->implicit_flows, remote_flow, next);
diff --git a/drivers/net/tap/tap_netlink.c b/drivers/net/tap/tap_netlink.c
index 6de896ab17b6..ee92e2e7ed13 100644
--- a/drivers/net/tap/tap_netlink.c
+++ b/drivers/net/tap/tap_netlink.c
@@ -159,7 +159,7 @@ nl_send(int nlsk_fd, struct nlmsghdr *nh)
  *   The netlink socket file descriptor used for communication.
  *
  * @return
- *   0 on success, -1 otherwise.
+ *   0 on success, -1 otherwise with errno set.
  */
 int
 nl_recv_ack(int nlsk_fd)
@@ -179,14 +179,13 @@ nl_recv_ack(int nlsk_fd)
  *   Custom arguments for the callback.
  *
  * @return
- *   0 on success, -1 otherwise.
+ *   0 on success, -1 otherwise with errno set.
  */
 int
 nl_recv(int nlsk_fd, int (*cb)(struct nlmsghdr *, void *arg), void *arg)
 {
 	/* man 7 netlink EXAMPLE */
 	struct sockaddr_nl sa;
-	struct nlmsghdr *nh;
 	char buf[BUF_SIZE];
 	struct iovec iov = {
 		.iov_base = buf,
@@ -196,49 +195,43 @@ nl_recv(int nlsk_fd, int (*cb)(struct nlmsghdr *, void *arg), void *arg)
 		.msg_name = &sa,
 		.msg_namelen = sizeof(sa),
 		.msg_iov = &iov,
+		/* One message at a time */
 		.msg_iovlen = 1,
 	};
-	int recv_bytes = 0, done = 0, multipart = 0, error = 0;
+	int multipart = 0;
+	int ret = 0;
 
-read:
-	recv_bytes = recvmsg(nlsk_fd, &msg, 0);
-	if (recv_bytes < 0)
-		return -1;
-	for (nh = (struct nlmsghdr *)buf;
-	     NLMSG_OK(nh, (unsigned int)recv_bytes);
-	     nh = NLMSG_NEXT(nh, recv_bytes)) {
-		/*
-		 * Multi-part messages and their following DONE message have the
-		 * NLM_F_MULTI flag set. Make note, in order to read the DONE
-		 * message afterwards.
-		 */
-		if (nh->nlmsg_flags & NLM_F_MULTI)
-			multipart = 1;
-		if (nh->nlmsg_type == NLMSG_ERROR) {
-			struct nlmsgerr *err_data = NLMSG_DATA(nh);
+	do {
+		struct nlmsghdr *nh;
+		int recv_bytes = 0;
+
+		recv_bytes = recvmsg(nlsk_fd, &msg, 0);
+		if (recv_bytes < 0)
+			return -1;
+		for (nh = (struct nlmsghdr *)buf;
+		     NLMSG_OK(nh, (unsigned int)recv_bytes);
+		     nh = NLMSG_NEXT(nh, recv_bytes)) {
+			if (nh->nlmsg_type == NLMSG_ERROR) {
+				struct nlmsgerr *err_data = NLMSG_DATA(nh);
 
-			if (err_data->error == 0)
-				RTE_LOG(DEBUG, PMD, "%s() ack message recvd\n",
-					__func__);
-			else {
-				RTE_LOG(DEBUG, PMD,
-					"%s() error message recvd\n", __func__);
-				error = 1;
+				if (err_data->error < 0) {
+					errno = -err_data->error;
+					return -1;
+				}
+				/* Ack message. */
+				return 0;
 			}
+			/* Multi-part msgs and their trailing DONE message. */
+			if (nh->nlmsg_flags & NLM_F_MULTI) {
+				if (nh->nlmsg_type == NLMSG_DONE)
+					return 0;
+				multipart = 1;
+			}
+			if (cb)
+				ret = cb(nh, arg);
 		}
-		/* The end of multipart message. */
-		if (nh->nlmsg_type == NLMSG_DONE)
-			/* No need to call the callback for a DONE message. */
-			done = 1;
-		else if (cb)
-			if (cb(nh, arg) < 0)
-				error = 1;
-	}
-	if (multipart && !done)
-		goto read;
-	if (error)
-		return -1;
-	return 0;
+	} while (multipart);
+	return ret;
 }
 
 /**
diff --git a/drivers/net/tap/tap_tcmsgs.c b/drivers/net/tap/tap_tcmsgs.c
index af1c9aec0d22..d74ac805b184 100644
--- a/drivers/net/tap/tap_tcmsgs.c
+++ b/drivers/net/tap/tap_tcmsgs.c
@@ -94,7 +94,7 @@ tc_init_msg(struct nlmsg *msg, uint16_t ifindex, uint16_t type, uint16_t flags)
  *   Additional info to identify the QDISC (handle and parent).
  *
  * @return
- *   0 on success, -1 otherwise.
+ *   0 on success, -1 otherwise with errno set.
  */
 static int
 qdisc_del(int nlsk_fd, uint16_t ifindex, struct qdisc *qinfo)
@@ -117,12 +117,16 @@ qdisc_del(int nlsk_fd, uint16_t ifindex, struct qdisc *qinfo)
 		fd = nlsk_fd;
 	}
 	if (nl_send(fd, &msg.nh) < 0)
-		return -1;
+		goto error;
 	if (nl_recv_ack(fd) < 0)
-		return -1;
+		goto error;
 	if (!nlsk_fd)
 		return nl_final(fd);
 	return 0;
+error:
+	if (!nlsk_fd)
+		nl_final(fd);
+	return -1;
 }
 
 /**
@@ -134,7 +138,7 @@ qdisc_del(int nlsk_fd, uint16_t ifindex, struct qdisc *qinfo)
  *   The netdevice ifindex where to add the multiqueue QDISC.
  *
  * @return
- *   -1 if the qdisc cannot be added, and 0 otherwise.
+ *   0 on success, -1 otherwise with errno set.
  */
 int
 qdisc_add_multiq(int nlsk_fd, uint16_t ifindex)
@@ -164,7 +168,7 @@ qdisc_add_multiq(int nlsk_fd, uint16_t ifindex)
  *   The netdevice ifindex where the QDISC will be added.
  *
  * @return
- *   -1 if the qdisc cannot be added, and 0 otherwise.
+ *   0 on success, -1 otherwise with errno set.
  */
 int
 qdisc_add_ingress(int nlsk_fd, uint16_t ifindex)
@@ -184,34 +188,6 @@ qdisc_add_ingress(int nlsk_fd, uint16_t ifindex)
 }
 
 /**
- * Callback function to check for QDISC existence.
- * If the QDISC is found to exist, increment "exists" in the custom arg.
- *
- * @param[in] nh
- *   The netlink message to parse, received from the kernel.
- * @param[in, out] arg
- *   Custom arguments for the callback.
- *
- * @return
- *   0.
- */
-static int
-qdisc_exist_cb(struct nlmsghdr *nh, void *arg)
-{
-	struct list_args *args = (struct list_args *)arg;
-	struct qdisc_custom_arg *custom = args->custom_arg;
-	struct tcmsg *t = NLMSG_DATA(nh);
-
-	/* filter by request iface */
-	if (args->ifindex != (unsigned int)t->tcm_ifindex)
-		return 0;
-	if (t->tcm_handle != custom->handle || t->tcm_parent != custom->parent)
-		return 0;
-	custom->exists++;
-	return 0;
-}
-
-/**
  * Callback function to delete a QDISC.
  *
  * @param[in] nh
@@ -220,7 +196,7 @@ qdisc_exist_cb(struct nlmsghdr *nh, void *arg)
  *   Custom arguments for the callback.
  *
  * @return
- *   0.
+ *   0 on success, -1 otherwise with errno set.
  */
 static int
 qdisc_del_cb(struct nlmsghdr *nh, void *arg)
@@ -256,10 +232,7 @@ qdisc_del_cb(struct nlmsghdr *nh, void *arg)
  *   The arguments to provide the callback function with.
  *
  * @return
- *   -1 if either sending the netlink message failed, or if receiving the answer
- *   failed, or finally if the callback returned a negative value for that
- *   answer.
- *   0 is returned otherwise.
+ *   0 on success, -1 otherwise with errno set.
  */
 static int
 qdisc_iterate(int nlsk_fd, uint16_t ifindex,
@@ -281,36 +254,6 @@ qdisc_iterate(int nlsk_fd, uint16_t ifindex,
 }
 
 /**
- * Check whether a given QDISC already exists for the netdevice.
- *
- * @param[in] nlsk_fd
- *   The netlink socket file descriptor used for communication.
- * @param[in] ifindex
- *   The netdevice ifindex to check QDISC existence for.
- * @param[in] callback
- *   The function to call for each QDISC.
- * @param[in, out] arg
- *   The arguments to provide the callback function with.
- *
- * @return
- *   1 if the qdisc exists, 0 otherwise.
- */
-int
-qdisc_exists(int nlsk_fd, uint16_t ifindex, uint32_t handle, uint32_t parent)
-{
-	struct qdisc_custom_arg arg = {
-		.handle = handle,
-		.parent = parent,
-		.exists = 0,
-	};
-
-	qdisc_iterate(nlsk_fd, ifindex, qdisc_exist_cb, &arg);
-	if (arg.exists)
-		return 1;
-	return 0;
-}
-
-/**
  * Delete all QDISCs for a given netdevice.
  *
  * @param[in] nlsk_fd
@@ -319,7 +262,7 @@ qdisc_exists(int nlsk_fd, uint16_t ifindex, uint32_t handle, uint32_t parent)
  *   The netdevice ifindex where to find QDISCs.
  *
  * @return
- *   -1 if the lookup failed, 0 otherwise.
+ *   0 on success, -1 otherwise with errno set.
  */
 int
 qdisc_flush(int nlsk_fd, uint16_t ifindex)
@@ -342,12 +285,13 @@ qdisc_flush(int nlsk_fd, uint16_t ifindex)
 int
 qdisc_create_multiq(int nlsk_fd, uint16_t ifindex)
 {
-	if (!qdisc_exists(nlsk_fd, ifindex,
-			  TC_H_MAKE(MULTIQ_MAJOR_HANDLE, 0), TC_H_ROOT)) {
-		if (qdisc_add_multiq(nlsk_fd, ifindex) < 0) {
-			RTE_LOG(ERR, PMD, "Could not add multiq qdisc\n");
-			return -1;
-		}
+	int err = 0;
+
+	err = qdisc_add_multiq(nlsk_fd, ifindex);
+	if (err < 0 && errno != -EEXIST) {
+		RTE_LOG(ERR, PMD, "Could not add multiq qdisc (%d): %s\n",
+			errno, strerror(errno));
+		return -1;
 	}
 	return 0;
 }
@@ -367,12 +311,13 @@ qdisc_create_multiq(int nlsk_fd, uint16_t ifindex)
 int
 qdisc_create_ingress(int nlsk_fd, uint16_t ifindex)
 {
-	if (!qdisc_exists(nlsk_fd, ifindex,
-			  TC_H_MAKE(TC_H_INGRESS, 0), TC_H_INGRESS)) {
-		if (qdisc_add_ingress(nlsk_fd, ifindex) < 0) {
-			RTE_LOG(ERR, PMD, "Could not add ingress qdisc\n");
-			return -1;
-		}
+	int err = 0;
+
+	err = qdisc_add_ingress(nlsk_fd, ifindex);
+	if (err < 0 && errno != -EEXIST) {
+		RTE_LOG(ERR, PMD, "Could not add ingress qdisc (%d): %s\n",
+			errno, strerror(errno));
+		return -1;
 	}
 	return 0;
 }
diff --git a/drivers/net/tap/tap_tcmsgs.h b/drivers/net/tap/tap_tcmsgs.h
index a571a56d6964..789595771d63 100644
--- a/drivers/net/tap/tap_tcmsgs.h
+++ b/drivers/net/tap/tap_tcmsgs.h
@@ -50,8 +50,6 @@
 
 void tc_init_msg(struct nlmsg *msg, uint16_t ifindex, uint16_t type,
 		 uint16_t flags);
-int qdisc_exists(int nlsk_fd, uint16_t ifindex, uint32_t handle,
-		 uint32_t parent);
 int qdisc_list(int nlsk_fd, uint16_t ifindex);
 int qdisc_flush(int nlsk_fd, uint16_t ifindex);
 int qdisc_create_ingress(int nlsk_fd, uint16_t ifindex);
-- 
2.12.0.306.g4a9b9b3

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 2/3] net/tap: fix null MAC address at init
  2017-03-31 13:54     ` [PATCH v3 0/3] net/tap: netlink and MAC address fixes Pascal Mazon
  2017-03-31 13:54       ` [PATCH v3 1/3] net/tap: update netlink error code management Pascal Mazon
@ 2017-03-31 13:54       ` Pascal Mazon
  2017-03-31 13:54       ` [PATCH v3 3/3] net/tap: fix redirection rule after MAC change Pascal Mazon
  2017-04-03 13:11       ` [PATCH v3 0/3] net/tap: netlink and MAC address fixes Ferruh Yigit
  3 siblings, 0 replies; 9+ messages in thread
From: Pascal Mazon @ 2017-03-31 13:54 UTC (permalink / raw)
  To: keith.wiles; +Cc: dev, Pascal Mazon

Immediately after init (probing), the device MAC address is all zeroes.
It should be possible to get a correct MAC address as soon as that,
without need for a dev_configure().

With this patch, a MAC address is set in eth_dev_tap_create()
explicitly. It either comes from the remote if any was configured, or is
randomly generated. In any case, the device MAC address is guaranteed to
be the correct one when the tap netdevice actually gets created in
tun_alloc().

Fixes: 77a92d9f33a8 ("net/tap: add MAC address management")
Fixes: 7d1aa96ee105 ("net/tap: add remote netdevice traffic capture")

Signed-off-by: Pascal Mazon <pascal.mazon@6wind.com>
---
 drivers/net/tap/rte_eth_tap.c | 85 ++++++++++++++++++++++++-------------------
 1 file changed, 48 insertions(+), 37 deletions(-)

diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 6567bba75b47..72897adcce3b 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -108,9 +108,16 @@ tap_trigger_cb(int sig __rte_unused)
 	tap_trigger = (tap_trigger + 1) | 0x80000000;
 }
 
+/* Specifies on what netdevices the ioctl should be applied */
+enum ioctl_mode {
+	LOCAL_AND_REMOTE,
+	LOCAL_ONLY,
+	REMOTE_ONLY,
+};
+
 static int
 tap_ioctl(struct pmd_internals *pmd, unsigned long request,
-	  struct ifreq *ifr, int set);
+	  struct ifreq *ifr, int set, enum ioctl_mode mode);
 
 static int tap_intr_handle_set(struct rte_eth_dev *dev, int set);
 
@@ -222,10 +229,15 @@ tun_alloc(struct pmd_internals *pmd, uint16_t qid)
 	if (qid == 0) {
 		struct ifreq ifr;
 
-		if (tap_ioctl(pmd, SIOCGIFHWADDR, &ifr, 0) < 0)
-			goto error;
-		rte_memcpy(&pmd->eth_addr, ifr.ifr_hwaddr.sa_data,
+		/*
+		 * pmd->eth_addr contains the desired MAC, either from remote
+		 * or from a random assignment. Sync it with the tap netdevice.
+		 */
+		ifr.ifr_hwaddr.sa_family = AF_LOCAL;
+		rte_memcpy(ifr.ifr_hwaddr.sa_data, &pmd->eth_addr,
 			   ETHER_ADDR_LEN);
+		if (tap_ioctl(pmd, SIOCSIFHWADDR, &ifr, 0, LOCAL_ONLY) < 0)
+			goto error;
 
 		pmd->if_index = if_nametoindex(pmd->name);
 		if (!pmd->if_index) {
@@ -437,27 +449,22 @@ pmd_tx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 
 static int
 tap_ioctl(struct pmd_internals *pmd, unsigned long request,
-	  struct ifreq *ifr, int set)
+	  struct ifreq *ifr, int set, enum ioctl_mode mode)
 {
 	short req_flags = ifr->ifr_flags;
-	int remote = !!pmd->remote_if_index;
+	int remote = pmd->remote_if_index &&
+		(mode == REMOTE_ONLY || mode == LOCAL_AND_REMOTE);
 
+	if (!pmd->remote_if_index && mode == REMOTE_ONLY)
+		return 0;
 	/*
 	 * If there is a remote netdevice, apply ioctl on it, then apply it on
 	 * the tap netdevice.
 	 */
-	if (request == SIOCGIFFLAGS && !set) {
-		/*
-		 * Special case for getting flags. If set is given,
-		 * then return the flags from the remote netdevice only.
-		 * Otherwise return the flags from the tap netdevice.
-		 */
-		remote = 0;
-	}
 apply:
 	if (remote)
 		snprintf(ifr->ifr_name, IFNAMSIZ, "%s", pmd->remote_iface);
-	else
+	else if (mode == LOCAL_ONLY || mode == LOCAL_AND_REMOTE)
 		snprintf(ifr->ifr_name, IFNAMSIZ, "%s", pmd->name);
 	switch (request) {
 	case SIOCSIFFLAGS:
@@ -470,16 +477,7 @@ tap_ioctl(struct pmd_internals *pmd, unsigned long request,
 			ifr->ifr_flags &= ~req_flags;
 		break;
 	case SIOCGIFFLAGS:
-		if (remote && set)
-			remote = 0; /* don't loop */
-		break;
 	case SIOCGIFHWADDR:
-		/* Set remote MAC on the tap netdevice */
-		if (!remote && pmd->remote_if_index) {
-			request = SIOCSIFHWADDR;
-			goto apply;
-		}
-		break;
 	case SIOCSIFHWADDR:
 	case SIOCSIFMTU:
 		break;
@@ -490,7 +488,7 @@ tap_ioctl(struct pmd_internals *pmd, unsigned long request,
 	}
 	if (ioctl(pmd->ioctl_sock, request, ifr) < 0)
 		goto error;
-	if (remote--)
+	if (remote-- && mode == LOCAL_AND_REMOTE)
 		goto apply;
 	return 0;
 
@@ -507,7 +505,7 @@ tap_link_set_down(struct rte_eth_dev *dev)
 	struct ifreq ifr = { .ifr_flags = IFF_UP };
 
 	dev->data->dev_link.link_status = ETH_LINK_DOWN;
-	return tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 0);
+	return tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 0, LOCAL_AND_REMOTE);
 }
 
 static int
@@ -517,7 +515,7 @@ tap_link_set_up(struct rte_eth_dev *dev)
 	struct ifreq ifr = { .ifr_flags = IFF_UP };
 
 	dev->data->dev_link.link_status = ETH_LINK_UP;
-	return tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 1);
+	return tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 1, LOCAL_AND_REMOTE);
 }
 
 static int
@@ -702,14 +700,14 @@ tap_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused)
 	struct ifreq ifr = { .ifr_flags = 0 };
 
 	if (pmd->remote_if_index) {
-		tap_ioctl(pmd, SIOCGIFFLAGS, &ifr, 1);
+		tap_ioctl(pmd, SIOCGIFFLAGS, &ifr, 0, REMOTE_ONLY);
 		if (!(ifr.ifr_flags & IFF_UP) ||
 		    !(ifr.ifr_flags & IFF_RUNNING)) {
 			dev_link->link_status = ETH_LINK_DOWN;
 			return 0;
 		}
 	}
-	tap_ioctl(pmd, SIOCGIFFLAGS, &ifr, 0);
+	tap_ioctl(pmd, SIOCGIFFLAGS, &ifr, 0, LOCAL_ONLY);
 	dev_link->link_status =
 		((ifr.ifr_flags & IFF_UP) && (ifr.ifr_flags & IFF_RUNNING) ?
 		 ETH_LINK_UP :
@@ -724,7 +722,7 @@ tap_promisc_enable(struct rte_eth_dev *dev)
 	struct ifreq ifr = { .ifr_flags = IFF_PROMISC };
 
 	dev->data->promiscuous = 1;
-	tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 1);
+	tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 1, LOCAL_AND_REMOTE);
 	if (pmd->remote_if_index)
 		tap_flow_implicit_create(pmd, TAP_REMOTE_PROMISC);
 }
@@ -736,7 +734,7 @@ tap_promisc_disable(struct rte_eth_dev *dev)
 	struct ifreq ifr = { .ifr_flags = IFF_PROMISC };
 
 	dev->data->promiscuous = 0;
-	tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 0);
+	tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 0, LOCAL_AND_REMOTE);
 	if (pmd->remote_if_index)
 		tap_flow_implicit_destroy(pmd, TAP_REMOTE_PROMISC);
 }
@@ -748,7 +746,7 @@ tap_allmulti_enable(struct rte_eth_dev *dev)
 	struct ifreq ifr = { .ifr_flags = IFF_ALLMULTI };
 
 	dev->data->all_multicast = 1;
-	tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 1);
+	tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 1, LOCAL_AND_REMOTE);
 	if (pmd->remote_if_index)
 		tap_flow_implicit_create(pmd, TAP_REMOTE_ALLMULTI);
 }
@@ -760,7 +758,7 @@ tap_allmulti_disable(struct rte_eth_dev *dev)
 	struct ifreq ifr = { .ifr_flags = IFF_ALLMULTI };
 
 	dev->data->all_multicast = 0;
-	tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 0);
+	tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 0, LOCAL_AND_REMOTE);
 	if (pmd->remote_if_index)
 		tap_flow_implicit_destroy(pmd, TAP_REMOTE_ALLMULTI);
 }
@@ -780,7 +778,7 @@ tap_mac_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
 
 	ifr.ifr_hwaddr.sa_family = AF_LOCAL;
 	rte_memcpy(ifr.ifr_hwaddr.sa_data, mac_addr, ETHER_ADDR_LEN);
-	if (tap_ioctl(pmd, SIOCSIFHWADDR, &ifr, 1) < 0)
+	if (tap_ioctl(pmd, SIOCSIFHWADDR, &ifr, 1, LOCAL_AND_REMOTE) < 0)
 		return;
 	rte_memcpy(&pmd->eth_addr, mac_addr, ETHER_ADDR_LEN);
 }
@@ -811,7 +809,8 @@ tap_setup_queue(struct rte_eth_dev *dev,
 				struct ifreq ifr;
 
 				ifr.ifr_mtu = dev->data->mtu;
-				if (tap_ioctl(pmd, SIOCSIFMTU, &ifr, 1) < 0) {
+				if (tap_ioctl(pmd, SIOCSIFMTU, &ifr, 1,
+					      LOCAL_AND_REMOTE) < 0) {
 					close(fd);
 					return -1;
 				}
@@ -966,7 +965,7 @@ tap_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 	struct ifreq ifr = { .ifr_mtu = mtu };
 	int err = 0;
 
-	err = tap_ioctl(pmd, SIOCSIFMTU, &ifr, 1);
+	err = tap_ioctl(pmd, SIOCSIFMTU, &ifr, 1, LOCAL_AND_REMOTE);
 	if (!err)
 		dev->data->mtu = mtu;
 
@@ -1210,13 +1209,25 @@ eth_dev_tap_create(const char *name, char *tap_name, char *remote_iface)
 	 */
 	pmd->nlsk_fd = nl_init(0);
 	if (strlen(remote_iface)) {
+		struct ifreq ifr;
+
 		pmd->remote_if_index = if_nametoindex(remote_iface);
 		snprintf(pmd->remote_iface, RTE_ETH_NAME_MAX_LEN,
 			 "%s", remote_iface);
-		if (!pmd->remote_if_index)
+		if (!pmd->remote_if_index) {
 			RTE_LOG(ERR, PMD, "Could not find %s ifindex: "
 				"remote interface will remain unconfigured\n",
 				remote_iface);
+			return 0;
+		}
+		if (tap_ioctl(pmd, SIOCGIFHWADDR, &ifr, 0, REMOTE_ONLY) < 0) {
+			RTE_LOG(ERR, PMD, "Could not get remote MAC address\n");
+			goto error_exit;
+		}
+		rte_memcpy(&pmd->eth_addr, ifr.ifr_hwaddr.sa_data,
+			   ETHER_ADDR_LEN);
+	} else {
+		eth_random_addr((uint8_t *)&pmd->eth_addr);
 	}
 
 	return 0;
-- 
2.12.0.306.g4a9b9b3

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v3 3/3] net/tap: fix redirection rule after MAC change
  2017-03-31 13:54     ` [PATCH v3 0/3] net/tap: netlink and MAC address fixes Pascal Mazon
  2017-03-31 13:54       ` [PATCH v3 1/3] net/tap: update netlink error code management Pascal Mazon
  2017-03-31 13:54       ` [PATCH v3 2/3] net/tap: fix null MAC address at init Pascal Mazon
@ 2017-03-31 13:54       ` Pascal Mazon
  2017-04-03 13:11       ` [PATCH v3 0/3] net/tap: netlink and MAC address fixes Ferruh Yigit
  3 siblings, 0 replies; 9+ messages in thread
From: Pascal Mazon @ 2017-03-31 13:54 UTC (permalink / raw)
  To: keith.wiles; +Cc: dev, Pascal Mazon

This is necessary to ensure packets with the new MAC address as
destination get redirected to the tap device.

Also change the MAC address only if the current one is different from
the requested one.

Fixes: 75b6a1f7f004 ("net/tap: add remote netdevice traffic capture")
Signed-off-by: Pascal Mazon <pascal.mazon@6wind.com>
---
 drivers/net/tap/rte_eth_tap.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index 72897adcce3b..618fd02800d5 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -775,12 +775,35 @@ tap_mac_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
 			dev->data->name);
 		return;
 	}
+	/* Check the actual current MAC address on the tap netdevice */
+	if (tap_ioctl(pmd, SIOCGIFHWADDR, &ifr, 0, LOCAL_ONLY) != 0) {
+		RTE_LOG(ERR, PMD,
+			"%s: couldn't check current tap MAC address\n",
+			dev->data->name);
+		return;
+	}
+	if (is_same_ether_addr((struct ether_addr *)&ifr.ifr_hwaddr.sa_data,
+			       mac_addr))
+		return;
 
 	ifr.ifr_hwaddr.sa_family = AF_LOCAL;
 	rte_memcpy(ifr.ifr_hwaddr.sa_data, mac_addr, ETHER_ADDR_LEN);
 	if (tap_ioctl(pmd, SIOCSIFHWADDR, &ifr, 1, LOCAL_AND_REMOTE) < 0)
 		return;
 	rte_memcpy(&pmd->eth_addr, mac_addr, ETHER_ADDR_LEN);
+	if (pmd->remote_if_index) {
+		/* Replace MAC redirection rule after a MAC change */
+		if (tap_flow_implicit_destroy(pmd, TAP_REMOTE_LOCAL_MAC) < 0) {
+			RTE_LOG(ERR, PMD,
+				"%s: Couldn't delete MAC redirection rule\n",
+				dev->data->name);
+			return;
+		}
+		if (tap_flow_implicit_create(pmd, TAP_REMOTE_LOCAL_MAC) < 0)
+			RTE_LOG(ERR, PMD,
+				"%s: Couldn't add MAC redirection rule\n",
+				dev->data->name);
+	}
 }
 
 static int
-- 
2.12.0.306.g4a9b9b3

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 0/3] net/tap: netlink and MAC address fixes
  2017-03-31 13:54     ` [PATCH v3 0/3] net/tap: netlink and MAC address fixes Pascal Mazon
                         ` (2 preceding siblings ...)
  2017-03-31 13:54       ` [PATCH v3 3/3] net/tap: fix redirection rule after MAC change Pascal Mazon
@ 2017-04-03 13:11       ` Ferruh Yigit
  3 siblings, 0 replies; 9+ messages in thread
From: Ferruh Yigit @ 2017-04-03 13:11 UTC (permalink / raw)
  To: Pascal Mazon, keith.wiles; +Cc: dev

On 3/31/2017 2:54 PM, Pascal Mazon wrote:
> I'm adding a cover letter to clarify this series history, as I've mixed my
> versions a little...
> 
> This series fixes some errors in the tap PMD.
> 
<...>
> 
> Pascal Mazon (3):
>   net/tap: update netlink error code management
>   net/tap: fix null MAC address at init
>   net/tap: fix redirection rule after MAC change

Series applied to dpdk-next-net/master, thanks.

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2017-04-03 13:12 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-29  9:44 [PATCH 1/2] net/tap: update netlink error code management Pascal Mazon
2017-03-29  9:44 ` [PATCH 2/2] net/tap: update redirection rule after MAC change Pascal Mazon
2017-03-31 13:02   ` [PATCH v2 1/2] net/tap: fix null MAC address at init Pascal Mazon
2017-03-31 13:54     ` [PATCH v3 0/3] net/tap: netlink and MAC address fixes Pascal Mazon
2017-03-31 13:54       ` [PATCH v3 1/3] net/tap: update netlink error code management Pascal Mazon
2017-03-31 13:54       ` [PATCH v3 2/3] net/tap: fix null MAC address at init Pascal Mazon
2017-03-31 13:54       ` [PATCH v3 3/3] net/tap: fix redirection rule after MAC change Pascal Mazon
2017-04-03 13:11       ` [PATCH v3 0/3] net/tap: netlink and MAC address fixes Ferruh Yigit
2017-03-31 13:02   ` [PATCH v2 2/2] net/tap: fix redirection rule after MAC change Pascal Mazon

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.