DPDK patches and discussions
 help / color / mirror / Atom feed
From: Isaac Boukris <iboukris@gmail.com>
To: stephen@networkplumber.org
Cc: dev@dpdk.org, Isaac Boukris <iboukris@gmail.com>
Subject: [PATCH] net/tap: add new macpair option for split MAC address
Date: Mon, 16 Sep 2024 20:38:51 +0300	[thread overview]
Message-ID: <20240916173851.369395-1-iboukris@gmail.com> (raw)

Normally, the MAC address of the kernel interface is the same as in the
interface in dpdk, as they represent the same interface. It is useful
to allow viewing them as separate connected interfaces (like ip's veth).

This solves a problem I have running a freebsd-based IPv6 stack on top
of dpdk and using the tap interface, as both the kernel and freebsd
stacks configure the MAC derived IPv6 address on the interface (as can
be seen with ifconfig for the kernel), and they both complain about
duplicate IPv6 address and the freebsd disables IPv6 as a result.

Signed-off-by: Isaac Boukris <iboukris@gmail.com>
---
 doc/guides/nics/tap.rst       | 19 +++++++++++++++++++
 drivers/net/tap/rte_eth_tap.c | 34 +++++++++++++++++++++++++++++++---
 drivers/net/tap/rte_eth_tap.h |  1 +
 3 files changed, 51 insertions(+), 3 deletions(-)

diff --git a/doc/guides/nics/tap.rst b/doc/guides/nics/tap.rst
index f01663c700..c5b08f2470 100644
--- a/doc/guides/nics/tap.rst
+++ b/doc/guides/nics/tap.rst
@@ -71,6 +71,25 @@ But this behavior can be overridden by the use of the persist flag, example::
 
   --vdev=net_tap0,iface=tap0,persist ...
 
+Normally, the MAC address of the kernel interface is the same as in the
+interface in dpdk, as they represent the same interface. If a MAC address is set
+by the dpdk application using ``rte_eth_dev_default_mac_addr_set()`` then the
+kernel interface changes accordingly (but not vice versa).
+
+If the ``macpair`` option is given, then the MAC address of the kernel is
+initially set to a different MAC address than the dpdk one (the fourth octet is
+increamented by 1) and calling ``rte_eth_dev_default_mac_addr_set()`` no longer
+changes the MAC of the kernel interface. This allows to view the two interfaces
+as separate connected interfaces, similar to linux's veth pair interfaces. For
+instance, you can configure an IP address on the kernel interface with the ``ip``
+command in the same subnet as the one used in dpdk and use it as next gateway.
+
+The ``macpair`` options is incompatible with the ``remote`` option (see above).
+
+Example::
+
+    --vdev=net_tap0,iface=tap0,macpair
+
 
 TUN devices
 -----------
diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c
index c5af5751f6..1a70832baa 100644
--- a/drivers/net/tap/rte_eth_tap.c
+++ b/drivers/net/tap/rte_eth_tap.c
@@ -56,6 +56,7 @@
 #define ETH_TAP_MAC_ARG         "mac"
 #define ETH_TAP_MAC_FIXED       "fixed"
 #define ETH_TAP_PERSIST_ARG     "persist"
+#define ETH_TAP_MACPAIR_ARG     "macpair"
 
 #define ETH_TAP_USR_MAC_FMT     "xx:xx:xx:xx:xx:xx"
 #define ETH_TAP_CMP_MAC_FMT     "0123456789ABCDEFabcdef"
@@ -95,6 +96,7 @@ static const char *valid_arguments[] = {
 	ETH_TAP_REMOTE_ARG,
 	ETH_TAP_MAC_ARG,
 	ETH_TAP_PERSIST_ARG,
+	ETH_TAP_MACPAIR_ARG,
 	NULL
 };
 
@@ -1391,6 +1393,12 @@ tap_mac_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr)
 			dev->device->name);
 		return -EINVAL;
 	}
+
+	if (pmd->mac_pair) {
+		rte_memcpy(&pmd->eth_addr, mac_addr, RTE_ETHER_ADDR_LEN);
+		return 0;
+	}
+
 	/* Check the actual current MAC address on the tap netdevice */
 	ret = tap_ioctl(pmd, SIOCGIFHWADDR, &ifr, 0, LOCAL_ONLY);
 	if (ret < 0)
@@ -1915,7 +1923,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, int persist)
+		   enum rte_tuntap_type type, int persist, int mac_pair)
 {
 	int numa_node = rte_socket_id();
 	struct rte_eth_dev *dev;
@@ -2025,10 +2033,19 @@ eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name,
 		ifr.ifr_hwaddr.sa_family = AF_LOCAL;
 		rte_memcpy(ifr.ifr_hwaddr.sa_data, &pmd->eth_addr,
 				RTE_ETHER_ADDR_LEN);
+
+		if (mac_pair) {
+			struct rte_ether_addr *mac;
+			mac = (struct rte_ether_addr*)ifr.ifr_hwaddr.sa_data;
+			mac->addr_bytes[3]++;
+		}
+
 		if (tap_ioctl(pmd, SIOCSIFHWADDR, &ifr, 0, LOCAL_ONLY) < 0)
 			goto error_exit;
 	}
 
+	pmd->mac_pair = mac_pair;
+
 	/* Make network device persist after application exit */
 	pmd->persist = persist;
 
@@ -2306,7 +2323,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, 0);
+				 ETH_TUNTAP_TYPE_TUN, 0, 0);
 
 leave:
 	if (ret == -1) {
@@ -2429,6 +2446,7 @@ rte_pmd_tap_probe(struct rte_vdev_device *dev)
 	struct rte_eth_dev *eth_dev;
 	int tap_devices_count_increased = 0;
 	int persist = 0;
+	int mac_pair = 0;
 
 	name = rte_vdev_device_name(dev);
 	params = rte_vdev_device_args(dev);
@@ -2504,6 +2522,16 @@ rte_pmd_tap_probe(struct rte_vdev_device *dev)
 					goto leave;
 			}
 
+			if (rte_kvargs_count(kvlist, ETH_TAP_MACPAIR_ARG) == 1) {
+				if (strlen(remote_iface)) {
+					TAP_LOG(ERR, "mac pair not supported "
+						     "with remote interface.");
+					ret = -1;
+					goto leave;
+				}
+				mac_pair = 1;
+			}
+
 			if (rte_kvargs_count(kvlist, ETH_TAP_MAC_ARG) == 1) {
 				ret = rte_kvargs_process(kvlist,
 							 ETH_TAP_MAC_ARG,
@@ -2533,7 +2561,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, persist);
+				 ETH_TUNTAP_TYPE_TAP, persist, mac_pair);
 
 leave:
 	if (ret == -1) {
diff --git a/drivers/net/tap/rte_eth_tap.h b/drivers/net/tap/rte_eth_tap.h
index ce4322ad04..5a33698f76 100644
--- a/drivers/net/tap/rte_eth_tap.h
+++ b/drivers/net/tap/rte_eth_tap.h
@@ -72,6 +72,7 @@ struct pmd_internals {
 	char name[RTE_ETH_NAME_MAX_LEN];  /* Internal Tap device name */
 	int type;                         /* Type field - TUN|TAP */
 	int persist;			  /* 1 if keep link up, else 0 */
+	int mac_pair;                     /* 1 if mac pair enabled, else 0 */
 	struct rte_ether_addr eth_addr;   /* Mac address of the device port */
 	struct ifreq remote_initial_flags;/* Remote netdevice flags on init */
 	int remote_if_index;              /* remote netdevice IF_INDEX */
-- 
2.45.0


             reply	other threads:[~2024-09-16 17:39 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-09-16 17:38 Isaac Boukris [this message]
2024-09-17  3:34 ` Stephen Hemminger
2024-09-17  3:36 ` Stephen Hemminger
2024-09-17  6:48   ` Isaac Boukris
2024-09-17  7:38     ` Morten Brørup
2024-09-17 11:51 Isaac Boukris
2024-09-17 12:14 ` Isaac Boukris

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240916173851.369395-1-iboukris@gmail.com \
    --to=iboukris@gmail.com \
    --cc=dev@dpdk.org \
    --cc=stephen@networkplumber.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).