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 <d...@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

Reply via email to