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

Dan Gora dg at adax.com
Wed Oct 24 22:27:15 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           | 41 ++++++++++++++++
 lib/librte_kni/rte_kni.h           | 20 ++++++++
 lib/librte_kni/rte_kni_version.map |  6 +++
 test/test/test_kni.c               | 77 ++++++++++++++++++++++++++++++
 4 files changed, 144 insertions(+)

diff --git a/lib/librte_kni/rte_kni.c b/lib/librte_kni/rte_kni.c
index b8edd40f4..c9726d4f8 100644
--- a/lib/librte_kni/rte_kni.c
+++ b/lib/librte_kni/rte_kni.c
@@ -717,6 +717,47 @@ rte_kni_unregister_handlers(struct rte_kni *kni)
 
 	return 0;
 }
+
+int __rte_experimental
+rte_kni_update_link(struct rte_kni *kni, unsigned int linkup)
+{
+	char path[64];
+	char old_carrier[2];
+	const char *new_carrier;
+	int old_linkup;
+	int fd, ret;
+
+	if (kni == 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, old_carrier, 2);
+	if (ret < 1) {
+		close(fd);
+		return -1;
+	}
+	old_linkup = (old_carrier[0] == '1');
+
+	new_carrier = linkup ? "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;
+	}
+
+	close(fd);
+	return old_linkup;
+}
+
 void
 rte_kni_close(void)
 {
diff --git a/lib/librte_kni/rte_kni.h b/lib/librte_kni/rte_kni.h
index 601abdfc6..02ca43b4b 100644
--- a/lib/librte_kni/rte_kni.h
+++ b/lib/librte_kni/rte_kni.h
@@ -232,6 +232,26 @@ 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 carrier state for KNI port.
+ *
+ * Update the linkup/linkdown state of a KNI interface in the kernel.
+ *
+ * @param kni
+ *  pointer to struct rte_kni.
+ * @param linkup
+ *  New link state:
+ *  0 for linkdown.
+ *  > 0 for linkup.
+ *
+ * @return
+ *  On failure: -1
+ *  Previous link state == linkdown: 0
+ *  Previous link state == linkup: 1
+ */
+int __rte_experimental
+rte_kni_update_link(struct rte_kni *kni, unsigned int linkup);
+
 /**
  *  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 cf64c0b27..e38206905 100644
--- a/test/test/test_kni.c
+++ b/test/test/test_kni.c
@@ -118,6 +118,79 @@ kni_change_mtu(uint16_t port_id, unsigned int new_mtu)
 					 port_id, kni_pkt_mtu);
 	return 0;
 }
+
+static int
+test_kni_link_change(void)
+{
+	int ret;
+	int pid;
+
+	pid = fork();
+	if (pid < 0) {
+		printf("Error: Failed to fork a process\n");
+		return -1;
+	}
+
+	if (pid == 0) {
+		printf("Starting KNI Link status change tests.\n");
+		if (system(IFCONFIG TEST_KNI_PORT" up") == -1) {
+			ret = -1;
+			goto error;
+		}
+
+		ret = rte_kni_update_link(test_kni_ctx, 1);
+		if (ret < 0) {
+			printf("Failed to change link state to Up ret=%d.\n",
+				ret);
+			goto error;
+		}
+		rte_delay_ms(1000);
+		printf("KNI: Set LINKUP, previous state=%d\n", ret);
+
+		ret = rte_kni_update_link(test_kni_ctx, 0);
+		if (ret != 1) {
+			printf(
+		"Failed! Previous link state should be 1, returned %d.\n",
+				ret);
+			goto error;
+		}
+		rte_delay_ms(1000);
+		printf("KNI: Set LINKDOWN, previous state=%d\n", ret);
+
+		ret = rte_kni_update_link(test_kni_ctx, 1);
+		if (ret != 0) {
+			printf(
+		"Failed! Previous link state should be 0, returned %d.\n",
+				ret);
+			goto error;
+		}
+		printf("KNI: Set LINKUP, previous state=%d\n", ret);
+
+		ret = 0;
+		rte_delay_ms(1000);
+
+error:
+		if (system(IFCONFIG TEST_KNI_PORT" down") == -1)
+			ret = -1;
+
+		printf("KNI: Link status change tests: %s.\n",
+			(ret == 0) ? "Passed" : "Failed");
+		exit(ret);
+	} else {
+		int p_ret, status;
+
+		while (1) {
+			p_ret = waitpid(pid, &status, WNOHANG);
+			if (p_ret != 0) {
+				if (WIFEXITED(status))
+					return WEXITSTATUS(status);
+				return -1;
+			}
+			rte_delay_ms(10);
+			rte_kni_handle_request(test_kni_ctx);
+		}
+	}
+}
 /**
  * This loop fully tests the basic functions of KNI. e.g. transmitting,
  * receiving to, from kernel space, and kernel requests.
@@ -401,6 +474,10 @@ test_kni_processing(uint16_t port_id, struct rte_mempool *mp)
 		goto fail_kni;
 	}
 
+	ret = test_kni_link_change();
+	if (ret != 0)
+		goto fail_kni;
+
 	rte_eal_mp_remote_launch(test_kni_loop, NULL, CALL_MASTER);
 	RTE_LCORE_FOREACH_SLAVE(i) {
 		if (rte_eal_wait_lcore(i) < 0) {
-- 
2.19.0



More information about the dev mailing list