[dpdk-dev] [PATCH v2 1/5] kni: add API to set link status on kernel interface

Dan Gora dg at adax.com
Wed Sep 19 21:55:45 CEST 2018


Add a new API function to KNI, rte_kni_update_link() to allow DPDK
applications to update the link status for KNI network interfaces in
the linux kernel.

Signed-off-by: Dan Gora <dg at adax.com>
---
 lib/librte_kni/rte_kni.c           |  57 ++++++++++++++++
 lib/librte_kni/rte_kni.h           |  18 ++++++
 lib/librte_kni/rte_kni_version.map |   6 ++
 test/test/test_kni.c               | 100 ++++++++++++++++++++++++++++-
 4 files changed, 180 insertions(+), 1 deletion(-)

diff --git a/lib/librte_kni/rte_kni.c b/lib/librte_kni/rte_kni.c
index 65f6a2b03..0c3e17dbb 100644
--- a/lib/librte_kni/rte_kni.c
+++ b/lib/librte_kni/rte_kni.c
@@ -790,6 +790,63 @@ rte_kni_unregister_handlers(struct rte_kni *kni)
 
 	return 0;
 }
+
+int __rte_experimental
+rte_kni_update_link(struct rte_kni *kni, struct rte_eth_link *link)
+{
+	char path[64];
+	char carrier[2];
+	const char *new_carrier;
+	int fd, ret;
+
+	if (kni == NULL || link == NULL)
+		return -1;
+
+	snprintf(path, sizeof(path), "/sys/devices/virtual/net/%s/carrier",
+		kni->name);
+
+	fd = open(path, O_RDWR);
+	if (fd == -1) {
+		RTE_LOG(ERR, KNI, "Failed to open file: %s.\n", path);
+		return -1;
+	}
+
+	ret = read(fd, carrier, 2);
+	if (ret < 1) {
+		/* Cannot read carrier until interface is marked
+		 * 'up', so don't log an error.
+		 */
+		close(fd);
+		return -1;
+	}
+
+	new_carrier = (link->link_status == ETH_LINK_UP) ? "1" : "0";
+	ret = write(fd, new_carrier, 1);
+	if (ret < 1) {
+		RTE_LOG(ERR, KNI, "Failed to write file: %s.\n", path);
+		close(fd);
+		return -1;
+	}
+
+	if (strncmp(carrier, new_carrier, 1)) {
+		if (link->link_status == ETH_LINK_UP) {
+			RTE_LOG(INFO, KNI, "%s NIC Link is Up %d Mbps %s %s.\n",
+				kni->name,
+				link->link_speed,
+				link->link_autoneg ? "(AutoNeg)" : "(Fixed)",
+				link->link_duplex ?
+					"Full Duplex" : "Half Duplex");
+		} else {
+			RTE_LOG(INFO, KNI, "%s NIC Link is Down.\n",
+				kni->name);
+		}
+	}
+
+	close(fd);
+
+	return 0;
+}
+
 void
 rte_kni_close(void)
 {
diff --git a/lib/librte_kni/rte_kni.h b/lib/librte_kni/rte_kni.h
index 99055e2c2..4118ae97a 100644
--- a/lib/librte_kni/rte_kni.h
+++ b/lib/librte_kni/rte_kni.h
@@ -21,6 +21,7 @@
 #include <rte_memory.h>
 #include <rte_mempool.h>
 #include <rte_ether.h>
+#include <rte_ethdev.h>
 
 #include <exec-env/rte_kni_common.h>
 
@@ -228,6 +229,23 @@ int rte_kni_register_handlers(struct rte_kni *kni, struct rte_kni_ops *ops);
  */
 int rte_kni_unregister_handlers(struct rte_kni *kni);
 
+/**
+ * Update link status info for KNI port.
+ *
+ * Update the linkup/linkdown status of a KNI interface in the kernel.
+ *
+ * @param kni
+ *  pointer to struct rte_kni.
+ * @param link
+ *  pointer to struct rte_eth_link containing new interface status.
+ *
+ * @return
+ *  On success: 0
+ *  On failure: -1
+ */
+int __rte_experimental
+rte_kni_update_link(struct rte_kni *kni, struct rte_eth_link *link);
+
 /**
  *  Close KNI device.
  */
diff --git a/lib/librte_kni/rte_kni_version.map b/lib/librte_kni/rte_kni_version.map
index acd515eb0..c877dc6aa 100644
--- a/lib/librte_kni/rte_kni_version.map
+++ b/lib/librte_kni/rte_kni_version.map
@@ -15,3 +15,9 @@ DPDK_2.0 {
 
 	local: *;
 };
+
+EXPERIMENTAL {
+	global:
+
+	rte_kni_update_link;
+};
diff --git a/test/test/test_kni.c b/test/test/test_kni.c
index 3dcadcebd..d450cc342 100644
--- a/test/test/test_kni.c
+++ b/test/test/test_kni.c
@@ -118,6 +118,97 @@ kni_change_mtu(uint16_t port_id, unsigned int new_mtu)
 					 port_id, kni_pkt_mtu);
 	return 0;
 }
+
+static int
+kni_change_link(void)
+{
+	struct rte_eth_link link;
+	int ret;
+
+	link.link_speed = 10;
+	link.link_status = ETH_LINK_UP;
+	link.link_autoneg = ETH_LINK_AUTONEG;
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+	ret = rte_kni_update_link(test_kni_ctx, &link);
+	if (ret != 0) {
+		printf("Failed to change link state to "
+				"Up/10Mbps/AutoNeg/Full ret=%d.\n", ret);
+		return -1;
+	}
+	rte_delay_ms(1000);
+
+	link.link_speed = 0;
+	link.link_status = ETH_LINK_DOWN;
+	link.link_autoneg = ETH_LINK_FIXED;
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+	ret = rte_kni_update_link(test_kni_ctx, &link);
+	if (ret != 0) {
+		printf("Failed to change link state to Down ret=%d.\n", ret);
+		return -1;
+	}
+	rte_delay_ms(1000);
+
+	link.link_speed = 1000;
+	link.link_status = ETH_LINK_UP;
+	link.link_autoneg = ETH_LINK_AUTONEG;
+	link.link_duplex = ETH_LINK_HALF_DUPLEX;
+	ret = rte_kni_update_link(test_kni_ctx, &link);
+	if (ret != 0) {
+		printf("Failed to change link state to "
+				"Up/1Gbps/AutoNeg/Half ret=%d.\n", ret);
+		return -1;
+	}
+	rte_delay_ms(1000);
+
+	link.link_speed = 0;
+	link.link_status = ETH_LINK_DOWN;
+	link.link_autoneg = ETH_LINK_FIXED;
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+	ret = rte_kni_update_link(test_kni_ctx, &link);
+	if (ret != 0) {
+		printf("Failed to change link state to Down ret=%d.\n", ret);
+		return -1;
+	}
+	rte_delay_ms(1000);
+
+	link.link_speed = 40000;
+	link.link_status = ETH_LINK_UP;
+	link.link_autoneg = ETH_LINK_FIXED;
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+	ret = rte_kni_update_link(test_kni_ctx, &link);
+	if (ret != 0) {
+		printf("Failed to change link state to "
+				"Up/40Gbps/Fixed/Full ret=%d.\n", ret);
+		return -1;
+	}
+	rte_delay_ms(1000);
+
+	link.link_speed = 0;
+	link.link_status = ETH_LINK_DOWN;
+	link.link_autoneg = ETH_LINK_FIXED;
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+	ret = rte_kni_update_link(test_kni_ctx, &link);
+	if (ret != 0) {
+		printf("Failed to change link state to Down ret=%d.\n", ret);
+		return -1;
+	}
+	rte_delay_ms(1000);
+
+	link.link_speed = 100000;
+	link.link_status = ETH_LINK_UP;
+	link.link_autoneg = ETH_LINK_FIXED;
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+	ret = rte_kni_update_link(test_kni_ctx, &link);
+	if (ret != 0) {
+		printf("Failed to change link state to "
+				"Up/100Gbps/Fixed/Full ret=%d.\n", ret);
+		return -1;
+	}
+	rte_delay_ms(1000);
+
+	return 0;
+}
+
 /**
  * This loop fully tests the basic functions of KNI. e.g. transmitting,
  * receiving to, from kernel space, and kernel requests.
@@ -148,9 +239,16 @@ test_kni_loop(__rte_unused void *arg)
 			ret = -1;
 		if (system(IFCONFIG TEST_KNI_PORT" mtu 1400") == -1)
 			ret = -1;
+
+		ret = kni_change_link();
+		if (ret != 0) {
+			test_kni_processing_flag = 1;
+			return ret;
+		}
+		rte_delay_ms(KNI_TIMEOUT_MS);
 		if (system(IFCONFIG TEST_KNI_PORT" down") == -1)
 			ret = -1;
-		rte_delay_ms(KNI_TIMEOUT_MS);
+		rte_delay_ms(1000);
 		test_kni_processing_flag = 1;
 	} else if (lcore_id == lcore_ingress) {
 		struct rte_mempool *mp = test_kni_lookup_mempool();
-- 
2.19.0



More information about the dev mailing list