kni: add function to set link state on kernel interface

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>
This commit is contained in:
Dan Gora 2018-10-24 19:26:27 -03:00 committed by Thomas Monjalon
parent fd5f33323e
commit c6fd54f28c
4 changed files with 144 additions and 0 deletions

View 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)
{

View 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.
*/

View File

@ -15,3 +15,9 @@ DPDK_2.0 {
local: *;
};
EXPERIMENTAL {
global:
rte_kni_update_link;
};

View 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) {