Skip to content

Commit

Permalink
[libknet] add knet_link_enable_status_change_notify API
Browse files Browse the repository at this point in the history
this API enables callbacks on link status change

Signed-off-by: Fabio M. Di Nitto <fdinitto@redhat.com>
  • Loading branch information
fabbione committed Jan 4, 2019
1 parent b695487 commit 847fa3e
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 3 deletions.
8 changes: 8 additions & 0 deletions libknet/internals.h
Expand Up @@ -236,6 +236,14 @@ struct knet_handle {
uint8_t reachable,
uint8_t remote,
uint8_t external);
void *link_status_change_notify_fn_private_data;
void (*link_status_change_notify_fn) (
void *private_data,
knet_node_id_t host_id,
uint8_t link_id,
uint8_t connected,
uint8_t remote,
uint8_t external);
void *sock_notify_fn_private_data;
void (*sock_notify_fn) (
void *private_data,
Expand Down
45 changes: 45 additions & 0 deletions libknet/libknet.h
Expand Up @@ -1796,6 +1796,51 @@ struct knet_link_status {
int knet_link_get_status(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
struct knet_link_status *status, size_t struct_size);

/**
* knet_link_enable_status_change_notify
*
* @brief Install a callback to get a link status change events
*
* knet_h - pointer to knet_handle_t
*
* host_status_change_notify_fn_private_data -
* void pointer to data that can be used to identify
* the callback
*
* host_status_change_notify_fn -
* is a callback function that is invoked every time
* there is a change in a link status.
* host status is identified by:
* - connected, 0 if the link has been disconnected, 1 if the link
* is connected.
* - remote, 0 if the host_id is connected locally or 1 if
* the there is one or more knet host(s) in between.
* NOTE: re-switching is NOT currently implemented,
* but this is ready for future and can avoid
* an API/ABI breakage later on.
* - external, 0 if the host_id is configured locally or 1 if
* it has been added from remote nodes config.
* NOTE: dynamic topology is NOT currently implemented,
* but this is ready for future and can avoid
* an API/ABI breakage later on.
* This function MUST NEVER block or add substantial delays.
*
* @return
* knet_host_status_change_notify returns
* 0 on success
* -1 on error and errno is set.
*/

int knet_link_enable_status_change_notify(knet_handle_t knet_h,
void *link_status_change_notify_fn_private_data,
void (*link_status_change_notify_fn) (
void *private_data,
knet_node_id_t host_id,
uint8_t link_id,
uint8_t connected,
uint8_t remote,
uint8_t external));

/*
* logging structs/API calls
*/
Expand Down
62 changes: 60 additions & 2 deletions libknet/links.c
Expand Up @@ -24,16 +24,35 @@
int _link_updown(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
unsigned int enabled, unsigned int connected)
{
struct knet_link *link = &knet_h->host_index[host_id]->link[link_id];
struct knet_host *host = knet_h->host_index[host_id];
struct knet_link *link = &host->link[link_id];
int notify_status = link->status.connected;

if ((link->status.enabled == enabled) &&
(link->status.connected == connected))
return 0;

if ((link->status.enabled) &&
(knet_h->link_status_change_notify_fn)) {
if (link->status.connected != connected) {
notify_status = connected; /* connection state */
}
if (!enabled) {
notify_status = 0; /* disable == disconnected */
}
knet_h->link_status_change_notify_fn(
knet_h->link_status_change_notify_fn_private_data,
host_id,
link_id,
notify_status,
host->status.remote,
host->status.external);
}

link->status.enabled = enabled;
link->status.connected = connected;

_host_dstcache_update_async(knet_h, knet_h->host_index[host_id]);
_host_dstcache_update_async(knet_h, host);

if ((link->status.dynconnected) &&
(!link->status.connected))
Expand Down Expand Up @@ -1084,3 +1103,42 @@ int knet_link_get_status(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t l
errno = err ? savederrno : 0;
return err;
}

int knet_link_enable_status_change_notify(knet_handle_t knet_h,
void *link_status_change_notify_fn_private_data,
void (*link_status_change_notify_fn) (
void *private_data,
knet_node_id_t host_id,
uint8_t link_id,
uint8_t connected,
uint8_t remote,
uint8_t external))
{
int savederrno = 0;

if (!knet_h) {
errno = EINVAL;
return -1;
}

savederrno = get_global_wrlock(knet_h);
if (savederrno) {
log_err(knet_h, KNET_SUB_HOST, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}

knet_h->link_status_change_notify_fn_private_data = link_status_change_notify_fn_private_data;
knet_h->link_status_change_notify_fn = link_status_change_notify_fn;
if (knet_h->link_status_change_notify_fn) {
log_debug(knet_h, KNET_SUB_HOST, "link_status_change_notify_fn enabled");
} else {
log_debug(knet_h, KNET_SUB_HOST, "link_status_change_notify_fn disabled");
}

pthread_rwlock_unlock(&knet_h->global_rwlock);

errno = 0;
return 0;
}
6 changes: 5 additions & 1 deletion libknet/tests/api-check.mk
Expand Up @@ -67,7 +67,8 @@ api_checks = \
api_knet_link_set_enable_test \
api_knet_link_get_enable_test \
api_knet_link_get_link_list_test \
api_knet_link_get_status_test
api_knet_link_get_status_test \
api_knet_link_enable_status_change_notify_test

api_knet_handle_new_test_SOURCES = api_knet_handle_new.c \
test-common.c
Expand Down Expand Up @@ -252,3 +253,6 @@ api_knet_link_get_link_list_test_SOURCES = api_knet_link_get_link_list.c \

api_knet_link_get_status_test_SOURCES = api_knet_link_get_status.c \
test-common.c

api_knet_link_enable_status_change_notify_test_SOURCES = api_knet_link_enable_status_change_notify.c \
test-common.c
144 changes: 144 additions & 0 deletions libknet/tests/api_knet_link_enable_status_change_notify.c
@@ -0,0 +1,144 @@
/*
* Copyright (C) 2016-2018 Red Hat, Inc. All rights reserved.
*
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/

#include "config.h"

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "libknet.h"

#include "internals.h"
#include "test-common.h"

static int private_data;

static void link_notify(void *priv_data,
knet_node_id_t host_id,
uint8_t link_id,
uint8_t connected,
uint8_t remote,
uint8_t external)
{
return;
}

static void test(void)
{
knet_handle_t knet_h;
int logfds[2];

printf("Test knet_link_enable_status_change_notify incorrect knet_h\n");

if ((!knet_link_enable_status_change_notify(NULL, NULL, link_notify)) || (errno != EINVAL)) {
printf("knet_link_enable_status_change_notify accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno));
exit(FAIL);
}

setup_logpipes(logfds);

knet_h = knet_handle_start(logfds, KNET_LOG_DEBUG);

printf("Test knet_link_enable_status_change_notify with no private_data\n");

if (knet_link_enable_status_change_notify(knet_h, NULL, link_notify) < 0) {
printf("knet_link_enable_status_change_notify failed: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}

if (knet_h->link_status_change_notify_fn_private_data != NULL) {
printf("knet_link_enable_status_change_notify failed to unset private_data");
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);

}

flush_logs(logfds[0], stdout);

printf("Test knet_link_enable_status_change_notify with private_data\n");

if (knet_link_enable_status_change_notify(knet_h, &private_data, NULL) < 0) {
printf("knet_link_enable_status_change_notify failed: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}

if (knet_h->link_status_change_notify_fn_private_data != &private_data) {
printf("knet_link_enable_status_change_notify failed to set private_data");
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);

}

flush_logs(logfds[0], stdout);

printf("Test knet_link_enable_status_change_notify with no link_notify fn\n");

if (knet_link_enable_status_change_notify(knet_h, NULL, NULL) < 0) {
printf("knet_link_enable_status_change_notify failed: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}

if (knet_h->link_status_change_notify_fn != NULL) {
printf("knet_link_enable_status_change_notify failed to unset link_notify fn");
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);

}

flush_logs(logfds[0], stdout);

printf("Test knet_link_enable_status_change_notify with link_notify fn\n");

if (knet_link_enable_status_change_notify(knet_h, NULL, link_notify) < 0) {
printf("knet_link_enable_status_change_notify failed: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}

if (knet_h->link_status_change_notify_fn != &link_notify) {
printf("knet_link_enable_status_change_notify failed to set link_notify fn");
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);

}

flush_logs(logfds[0], stdout);

knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
}

int main(int argc, char *argv[])
{
test();

return PASS;
}

0 comments on commit 847fa3e

Please sign in to comment.