kni: add function to set link state on kernel interface
authorDan Gora <dg@adax.com>
Wed, 24 Oct 2018 22:26:27 +0000 (19:26 -0300)
committerThomas Monjalon <thomas@monjalon.net>
Fri, 26 Oct 2018 17:46:15 +0000 (19:46 +0200)
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@adax.com>
Acked-by: Ferruh Yigit <ferruh.yigit@intel.com>
lib/librte_kni/rte_kni.c
lib/librte_kni/rte_kni.h
lib/librte_kni/rte_kni_version.map
test/test/test_kni.c

index b8edd40..c9726d4 100644 (file)
@@ -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)
 {
index 601abdf..02ca43b 100644 (file)
@@ -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.
  */
index acd515e..c877dc6 100644 (file)
@@ -15,3 +15,9 @@ DPDK_2.0 {
 
        local: *;
 };
+
+EXPERIMENTAL {
+       global:
+
+       rte_kni_update_link;
+};
index cf64c0b..e382069 100644 (file)
@@ -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) {