Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/kronosnetd/vty_cli_cmds.c b/kronosnetd/vty_cli_cmds.c
index 944729c4..12d65b20 100644
--- a/kronosnetd/vty_cli_cmds.c
+++ b/kronosnetd/vty_cli_cmds.c
@@ -1,1703 +1,1702 @@
#include "config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include "cfg.h"
#include "logging.h"
#include "libtap.h"
#include "netutils.h"
#include "vty.h"
#include "vty_cli.h"
#include "vty_cli_cmds.h"
#include "vty_utils.h"
#define KNET_VTY_MAX_MATCHES 64
#define KNET_VTY_MATCH_HELP 0
#define KNET_VTY_MATCH_EXEC 1
#define KNET_VTY_MATCH_EXPAND 2
#define CMDS_PARAM_NOMORE 0
#define CMDS_PARAM_KNET 1
#define CMDS_PARAM_IP 2
#define CMDS_PARAM_IP_PREFIX 3
#define CMDS_PARAM_IP_PORT 4
#define CMDS_PARAM_BOOL 5
#define CMDS_PARAM_INT 6
#define CMDS_PARAM_NODEID 7
#define CMDS_PARAM_NAME 8
#define CMDS_PARAM_MTU 9
#define CMDS_PARAM_CRYPTO_MODEL 10
#define CMDS_PARAM_CRYPTO_TYPE 11
#define CMDS_PARAM_HASH_TYPE 12
/*
* CLI helper functions - menu/node stuff starts below
*/
/*
* return 0 if we find a command in vty->line and cmd/len/no are set
* return -1 if we cannot find a command. no can be trusted. cmd/len would be empty
*/
static int get_command(struct knet_vty *vty, char **cmd, int *cmdlen, int *cmdoffset, int *no)
{
int start = 0, idx;
for (idx = 0; idx < vty->line_idx; idx++) {
if (vty->line[idx] != ' ')
break;
}
if (!strncmp(&vty->line[idx], "no ", 3)) {
*no = 1;
idx = idx + 3;
for (idx = idx; idx < vty->line_idx; idx++) {
if (vty->line[idx] != ' ')
break;
}
} else {
*no = 0;
}
start = idx;
if (start == vty->line_idx)
return -1;
*cmd = &vty->line[start];
*cmdoffset = start;
for (idx = start; idx < vty->line_idx; idx++) {
if (vty->line[idx] == ' ')
break;
}
*cmdlen = idx - start;
return 0;
}
/*
* still not sure why I need to count backwards...
*/
static void get_n_word_from_end(struct knet_vty *vty, int n,
char **word, int *wlen, int *woffset)
{
int widx;
int idx, end, start;
start = end = vty->line_idx;
for (widx = 0; widx < n; widx++) {
for (idx = start - 1; idx > 0; idx--) {
if (vty->line[idx] != ' ')
break;
}
end = idx;
for (idx = end; idx > 0; idx--) {
if (vty->line[idx-1] == ' ')
break;
}
start = idx;
}
*wlen = (end - start) + 1;
*word = &vty->line[start];
*woffset = start;
}
static int expected_params(const vty_param_t *params)
{
int idx = 0;
while(params[idx].param != CMDS_PARAM_NOMORE)
idx++;
return idx;
}
static int count_words(struct knet_vty *vty,
int offset)
{
int idx, widx = 0;
int status = 0;
for (idx = offset; idx < vty->line_idx; idx++) {
if (vty->line[idx] == ' ') {
status = 0;
continue;
}
if ((vty->line[idx] != ' ') && (!status)) {
widx++;
status = 1;
continue;
}
}
return widx;
}
static int param_to_int(const char *param, int paramlen)
{
char buf[KNET_VTY_MAX_LINE];
memset(buf, 0, sizeof(buf));
memcpy(buf, param, paramlen);
return atoi(buf);
}
static int param_to_str(char *buf, int bufsize, const char *param, int paramlen)
{
if (bufsize < paramlen)
return -1;
memset(buf, 0, bufsize);
memcpy(buf, param, paramlen);
return paramlen;
}
static const vty_node_cmds_t *get_cmds(struct knet_vty *vty, char **cmd, int *cmdlen, int *cmdoffset)
{
int no;
const vty_node_cmds_t *cmds = knet_vty_nodes[vty->node].cmds;
get_command(vty, cmd, cmdlen, cmdoffset, &no);
if (no)
cmds = knet_vty_nodes[vty->node].no_cmds;
return cmds;
}
static int check_param(struct knet_vty *vty, const int paramtype, char *param, int paramlen)
{
int err = 0;
char buf[KNET_VTY_MAX_LINE];
int tmp;
memset(buf, 0, sizeof(buf));
switch(paramtype) {
case CMDS_PARAM_NOMORE:
break;
case CMDS_PARAM_KNET:
if (paramlen >= IFNAMSIZ) {
knet_vty_write(vty, "interface name too long%s", telnet_newline);
err = -1;
}
break;
case CMDS_PARAM_IP:
break;
case CMDS_PARAM_IP_PREFIX:
break;
case CMDS_PARAM_IP_PORT:
tmp = param_to_int(param, paramlen);
if ((tmp < 0) || (tmp > 65279)) {
knet_vty_write(vty, "port number must be a value between 0 and 65279%s", telnet_newline);
err = -1;
}
break;
case CMDS_PARAM_BOOL:
break;
case CMDS_PARAM_INT:
break;
case CMDS_PARAM_NODEID:
tmp = param_to_int(param, paramlen);
if ((tmp < 0) || (tmp > 255)) {
knet_vty_write(vty, "node id must be a value between 0 and 255%s", telnet_newline);
err = -1;
}
break;
case CMDS_PARAM_NAME:
if (paramlen >= KNET_MAX_HOST_LEN) {
knet_vty_write(vty, "name cannot exceed %d char in len%s", KNET_MAX_HOST_LEN - 1, telnet_newline);
}
break;
case CMDS_PARAM_MTU:
tmp = param_to_int(param, paramlen);
if ((tmp < 576) || (tmp > 65536)) {
knet_vty_write(vty, "mtu should be a value between 576 and 65536 (note: max value depends on the media)%s", telnet_newline);
err = -1;
}
break;
case CMDS_PARAM_CRYPTO_MODEL:
param_to_str(buf, KNET_VTY_MAX_LINE, param, paramlen);
if (!strncmp("none", buf, 4))
break;
if (!strncmp("nss", buf, 3))
break;
knet_vty_write(vty, "unknown encryption model: %s. Supported: none/nss%s", param, telnet_newline);
err = -1;
break;
case CMDS_PARAM_CRYPTO_TYPE:
param_to_str(buf, KNET_VTY_MAX_LINE, param, paramlen);
if (!strncmp("none", buf, 4))
break;
if (!strncmp("aes256", buf, 6))
break;
if (!strncmp("aes192", buf, 6))
break;
if (!strncmp("aes128", buf, 6))
break;
if (!strncmp("3des", buf, 4))
break;
knet_vty_write(vty, "unknown encryption method: %s. Supported: none/aes256/aes192/aes128/3des%s", param, telnet_newline);
err = -1;
break;
case CMDS_PARAM_HASH_TYPE:
param_to_str(buf, KNET_VTY_MAX_LINE, param, paramlen);
if (!strncmp("none", buf, 4))
break;
if (!strncmp("md5", buf, 3))
break;
if (!strncmp("sha1", buf, 4))
break;
if (!strncmp("sha256", buf, 6))
break;
if (!strncmp("sha384", buf, 6))
break;
if (!strncmp("sha512", buf, 6))
break;
knet_vty_write(vty, "unknown hash method: %s. Supported none/md5/sha1/sha256/sha384/sha512%s", param, telnet_newline);
err = -1;
break;
default:
knet_vty_write(vty, "CLI ERROR: unknown parameter type%s", telnet_newline);
err = -1;
break;
}
return err;
}
static void describe_param(struct knet_vty *vty, const int paramtype)
{
switch(paramtype) {
case CMDS_PARAM_NOMORE:
knet_vty_write(vty, "no more parameters%s", telnet_newline);
break;
case CMDS_PARAM_KNET:
knet_vty_write(vty, "KNET_IFACE_NAME - interface name (max %d chars) eg: kronosnet0%s", IFNAMSIZ, telnet_newline);
break;
case CMDS_PARAM_IP:
knet_vty_write(vty, "IP address - ipv4 or ipv6 address to add/remove%s", telnet_newline);
break;
case CMDS_PARAM_IP_PREFIX:
knet_vty_write(vty, "IP prefix len (eg. 24, 64)%s", telnet_newline);
break;
case CMDS_PARAM_IP_PORT:
knet_vty_write(vty, "base port (eg: %d) %s", KNET_RING_DEFPORT, telnet_newline);
case CMDS_PARAM_BOOL:
break;
case CMDS_PARAM_INT:
break;
case CMDS_PARAM_NODEID:
knet_vty_write(vty, "NODEID - unique identifier for this interface in this kronos network (value between 0 and 255)%s", telnet_newline);
break;
case CMDS_PARAM_NAME:
knet_vty_write(vty, "NAME - unique name identifier for this entity (max %d chars)%s", KNET_MAX_HOST_LEN - 1, telnet_newline);
break;
case CMDS_PARAM_MTU:
knet_vty_write(vty, "MTU - a value between 576 and 65536 (note: max value depends on the media)%s", telnet_newline);
break;
case CMDS_PARAM_CRYPTO_MODEL:
knet_vty_write(vty, "MODEL - define encryption backend: none or nss%s", telnet_newline);
break;
case CMDS_PARAM_CRYPTO_TYPE:
knet_vty_write(vty, "CRYPTO - define packets encryption method: none or aes256%s", telnet_newline);
break;
case CMDS_PARAM_HASH_TYPE:
knet_vty_write(vty, "HASH - define packets hashing method: none/md5/sha1/sha256/sha384/sha512%s", telnet_newline);
break;
default: /* this should never happen */
knet_vty_write(vty, "CLI ERROR: unknown parameter type%s", telnet_newline);
break;
}
}
static void print_help(struct knet_vty *vty, const vty_node_cmds_t *cmds, int idx)
{
if ((idx < 0) || (cmds == NULL) || (cmds[idx].cmd == NULL))
return;
if (cmds[idx].help != NULL) {
knet_vty_write(vty, "%s\t%s%s",
cmds[idx].cmd,
cmds[idx].help,
telnet_newline);
} else {
knet_vty_write(vty, "%s\tNo help available for this command%s",
cmds[idx].cmd,
telnet_newline);
}
}
static int get_param(struct knet_vty *vty, int wanted_paranum,
char **param, int *paramlen, int *paramoffset)
{
int eparams, tparams;
const vty_param_t *params = (const vty_param_t *)vty->param;
int paramstart = vty->paramoffset;
eparams = expected_params(params);
tparams = count_words(vty, paramstart);
if (tparams > eparams)
return -1;
if (wanted_paranum == -1) {
get_n_word_from_end(vty, 1, param, paramlen, paramoffset);
return tparams;
}
if (tparams < wanted_paranum)
return -1;
get_n_word_from_end(vty, (tparams - wanted_paranum) + 1, param, paramlen, paramoffset);
return tparams - wanted_paranum;
}
static int match_command(struct knet_vty *vty, const vty_node_cmds_t *cmds,
char *cmd, int cmdlen, int cmdoffset, int mode)
{
int idx = 0, found = -1, paramoffset = 0, paramlen = 0, last_param = 0;
char *param = NULL;
int paramstart = cmdlen + cmdoffset;
int matches[KNET_VTY_MAX_MATCHES];
memset(&matches, -1, sizeof(matches));
while ((cmds[idx].cmd != NULL) && (idx < KNET_VTY_MAX_MATCHES)) {
if (!strncmp(cmds[idx].cmd, cmd, cmdlen)) {
found++;
matches[found] = idx;
}
idx++;
}
if (idx >= KNET_VTY_MAX_MATCHES) {
knet_vty_write(vty, "Too many matches for this command%s", telnet_newline);
return -1;
}
if (found < 0) {
knet_vty_write(vty, "There is no such command%s", telnet_newline);
return -1;
}
switch(mode) {
case KNET_VTY_MATCH_HELP:
if (found == 0) {
if ((cmdoffset <= vty->cursor_pos) && (vty->cursor_pos <= paramstart)) {
print_help(vty, cmds, matches[0]);
break;
}
if (cmds[matches[0]].params != NULL) {
vty->param = (void *)cmds[matches[0]].params;
vty->paramoffset = paramstart;
last_param = get_param(vty, -1, &param, &paramlen, &paramoffset);
if ((paramoffset <= vty->cursor_pos) && (vty->cursor_pos <= (paramoffset + paramlen)))
last_param--;
if (last_param >= CMDS_PARAM_NOMORE) {
describe_param(vty, cmds[matches[0]].params[last_param].param);
if (paramoffset > 0)
check_param(vty, cmds[matches[0]].params[last_param].param, param, paramlen);
}
break;
}
}
if (found >= 0) {
idx = 0;
while (matches[idx] >= 0) {
print_help(vty, cmds, matches[idx]);
idx++;
}
}
break;
case KNET_VTY_MATCH_EXEC:
if (found == 0) {
int exec = 0;
if (cmds[matches[0]].params != NULL) {
int eparams, tparams;
eparams = expected_params(cmds[matches[0]].params);
tparams = count_words(vty, paramstart);
if (eparams != tparams) {
exec = -1;
idx = 0;
knet_vty_write(vty, "Parameter required for this command:%s", telnet_newline);
while(cmds[matches[0]].params[idx].param != CMDS_PARAM_NOMORE) {
describe_param(vty, cmds[matches[0]].params[idx].param);
idx++;
}
break;
}
idx = 0;
vty->param = (void *)cmds[matches[0]].params;
vty->paramoffset = paramstart;
while(cmds[matches[0]].params[idx].param != CMDS_PARAM_NOMORE) {
get_param(vty, idx + 1, &param, &paramlen, &paramoffset);
if (check_param(vty, cmds[matches[0]].params[idx].param,
param, paramlen) < 0) {
exec = -1;
if (vty->filemode)
return -1;
}
idx++;
}
}
if (!exec) {
if (cmds[matches[0]].params != NULL) {
vty->param = (void *)cmds[matches[0]].params;
vty->paramoffset = paramstart;
}
if (cmds[matches[0]].func != NULL) {
return cmds[matches[0]].func(vty);
} else { /* this will eventually disappear */
knet_vty_write(vty, "no fn associated to this command%s", telnet_newline);
}
}
}
if (found > 0) {
knet_vty_write(vty, "Ambiguous command.%s", telnet_newline);
}
break;
case KNET_VTY_MATCH_EXPAND:
if (found == 0) {
int cmdreallen;
if (vty->cursor_pos > cmdoffset+cmdlen) /* complete param? */
break;
cmdreallen = strlen(cmds[matches[0]].cmd);
memset(vty->line + cmdoffset, 0, cmdlen);
memcpy(vty->line + cmdoffset, cmds[matches[0]].cmd, cmdreallen);
vty->line[cmdreallen + cmdoffset] = ' ';
vty->line_idx = cmdreallen + cmdoffset + 1;
vty->cursor_pos = cmdreallen + cmdoffset + 1;
}
if (found > 0) { /* add completion to string base root */
int count = 0;
idx = 0;
while (matches[idx] >= 0) {
knet_vty_write(vty, "%s\t\t", cmds[matches[idx]].cmd);
idx++;
count++;
if (count == 4) {
knet_vty_write(vty, "%s",telnet_newline);
count = 0;
}
}
knet_vty_write(vty, "%s",telnet_newline);
}
break;
default: /* this should never really happen */
log_info("Unknown match mode");
break;
}
return found;
}
/* forward declarations */
/* common to almost all nodes */
static int knet_cmd_logout(struct knet_vty *vty);
static int knet_cmd_who(struct knet_vty *vty);
static int knet_cmd_exit_node(struct knet_vty *vty);
static int knet_cmd_help(struct knet_vty *vty);
/* root node */
static int knet_cmd_config(struct knet_vty *vty);
/* config node */
static int knet_cmd_interface(struct knet_vty *vty);
static int knet_cmd_no_interface(struct knet_vty *vty);
static int knet_cmd_show_conf(struct knet_vty *vty);
static int knet_cmd_write_conf(struct knet_vty *vty);
/* interface node */
static int knet_cmd_mtu(struct knet_vty *vty);
static int knet_cmd_no_mtu(struct knet_vty *vty);
static int knet_cmd_ip(struct knet_vty *vty);
static int knet_cmd_no_ip(struct knet_vty *vty);
static int knet_cmd_baseport(struct knet_vty *vty);
static int knet_cmd_peer(struct knet_vty *vty);
static int knet_cmd_no_peer(struct knet_vty *vty);
static int knet_cmd_start(struct knet_vty *vty);
static int knet_cmd_stop(struct knet_vty *vty);
static int knet_cmd_crypto(struct knet_vty *vty);
/* peer node */
static int knet_cmd_link(struct knet_vty *vty);
static int knet_cmd_no_link(struct knet_vty *vty);
/* root node description */
vty_node_cmds_t root_cmds[] = {
{ "configure", "enter configuration mode", NULL, knet_cmd_config },
{ "exit", "exit from CLI", NULL, knet_cmd_logout },
{ "help", "display basic help", NULL, knet_cmd_help },
{ "logout", "exit from CLI", NULL, knet_cmd_logout },
{ "who", "display users connected to CLI", NULL, knet_cmd_who },
{ NULL, NULL, NULL, NULL },
};
/* config node description */
vty_param_t no_int_params[] = {
{ CMDS_PARAM_KNET },
{ CMDS_PARAM_NOMORE },
};
vty_node_cmds_t no_config_cmds[] = {
{ "interface", "destroy kronosnet interface", no_int_params, knet_cmd_no_interface },
{ NULL, NULL, NULL, NULL },
};
vty_param_t int_params[] = {
{ CMDS_PARAM_KNET },
{ CMDS_PARAM_NODEID },
{ CMDS_PARAM_NOMORE },
};
vty_node_cmds_t config_cmds[] = {
{ "exit", "exit configuration mode", NULL, knet_cmd_exit_node },
{ "interface", "configure kronosnet interface", int_params, knet_cmd_interface },
{ "show", "show running config", NULL, knet_cmd_show_conf },
{ "help", "display basic help", NULL, knet_cmd_help },
{ "logout", "exit from CLI", NULL, knet_cmd_logout },
{ "no", "revert command", NULL, NULL },
{ "who", "display users connected to CLI", NULL, knet_cmd_who },
{ "write", "write current config to file", NULL, knet_cmd_write_conf },
{ NULL, NULL, NULL, NULL },
};
/* interface node description */
vty_param_t ip_params[] = {
{ CMDS_PARAM_IP },
{ CMDS_PARAM_IP_PREFIX },
{ CMDS_PARAM_NOMORE },
};
vty_param_t peer_params[] = {
{ CMDS_PARAM_NAME },
{ CMDS_PARAM_NODEID },
{ CMDS_PARAM_NOMORE },
};
vty_node_cmds_t no_interface_cmds[] = {
{ "ip", "remove ip address", ip_params, knet_cmd_no_ip },
{ "mtu", "revert to default MTU", NULL, knet_cmd_no_mtu },
{ "peer", "remove peer from this interface", peer_params, knet_cmd_no_peer },
{ NULL, NULL, NULL, NULL },
};
vty_param_t mtu_params[] = {
{ CMDS_PARAM_MTU },
{ CMDS_PARAM_NOMORE },
};
vty_param_t baseport_params[] = {
{ CMDS_PARAM_IP_PORT },
{ CMDS_PARAM_NOMORE },
};
vty_param_t crypto_params[] = {
{ CMDS_PARAM_CRYPTO_MODEL },
{ CMDS_PARAM_CRYPTO_TYPE },
{ CMDS_PARAM_HASH_TYPE },
{ CMDS_PARAM_NOMORE },
};
vty_node_cmds_t interface_cmds[] = {
{ "baseport", "set base listening port for this interface", baseport_params, knet_cmd_baseport },
{ "crypto", "enable crypto/hmac", crypto_params, knet_cmd_crypto },
{ "exit", "exit configuration mode", NULL, knet_cmd_exit_node },
{ "help", "display basic help", NULL, knet_cmd_help },
{ "ip", "add ip address", ip_params, knet_cmd_ip },
{ "logout", "exit from CLI", NULL, knet_cmd_logout },
{ "mtu", "set mtu", mtu_params, knet_cmd_mtu },
{ "no", "revert command", NULL, NULL },
{ "peer", "add peer endpoint", peer_params, knet_cmd_peer },
{ "show", "show running config", NULL, knet_cmd_show_conf },
{ "start", "start forwarding engine", NULL, knet_cmd_start },
{ "stop", "stop forwarding engine", NULL, knet_cmd_stop },
{ "who", "display users connected to CLI", NULL, knet_cmd_who },
{ "write", "write current config to file", NULL, knet_cmd_write_conf },
{ NULL, NULL, NULL, NULL },
};
/* peer node description */
vty_param_t link_params[] = {
{ CMDS_PARAM_IP },
{ CMDS_PARAM_NOMORE },
};
vty_node_cmds_t no_peer_cmds[] = {
{ "link", "remove peer endpoint", link_params, knet_cmd_no_link},
{ NULL, NULL, NULL, NULL },
};
vty_node_cmds_t peer_cmds[] = {
{ "exit", "exit configuration mode", NULL, knet_cmd_exit_node },
{ "help", "display basic help", NULL, knet_cmd_help },
{ "link", "add peer endpoint", link_params, knet_cmd_link },
{ "logout", "exit from CLI", NULL, knet_cmd_logout },
{ "no", "revert command", NULL, NULL },
{ "show", "show running config", NULL, knet_cmd_show_conf },
{ "who", "display users connected to CLI", NULL, knet_cmd_who },
{ "write", "write current config to file", NULL, knet_cmd_write_conf },
{ NULL, NULL, NULL, NULL },
};
/* link node description */
vty_node_cmds_t link_cmds[] = {
{ "exit", "exit configuration mode", NULL, knet_cmd_exit_node },
{ "help", "display basic help", NULL, knet_cmd_help },
{ "logout", "exit from CLI", NULL, knet_cmd_logout },
{ "no", "revert command", NULL, NULL },
{ "show", "show running config", NULL, knet_cmd_show_conf },
{ "who", "display users connected to CLI", NULL, knet_cmd_who },
{ "write", "write current config to file", NULL, knet_cmd_write_conf },
{ NULL, NULL, NULL, NULL },
};
/* nodes */
vty_nodes_t knet_vty_nodes[] = {
{ NODE_ROOT, "knet", root_cmds, NULL },
{ NODE_CONFIG, "config", config_cmds, no_config_cmds },
{ NODE_INTERFACE, "iface", interface_cmds, no_interface_cmds },
{ NODE_PEER, "peer", peer_cmds, no_peer_cmds },
{ NODE_LINK, "link", link_cmds, NULL },
{ -1, NULL, NULL },
};
/* command execution */
/* links */
static int knet_cmd_no_link(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
struct knet_host *host = (struct knet_host *)vty->host;
int j, paramlen = 0, paramoffset = 0, found = 0;
char *param = NULL;
char ipaddr[KNET_MAX_HOST_LEN], port[6];
get_param(vty, 1, &param, &paramlen, &paramoffset);
param_to_str(ipaddr, KNET_MAX_HOST_LEN, param, paramlen);
memset(port, 0, sizeof(port));
snprintf(port, 6, "%d", knet_iface->cfg_ring.base_port + knet_iface->cfg_eth.node_id);
for (j = 0; j < KNET_MAX_LINK; j++) {
if (!strcmp(host->link[j].ipaddr, ipaddr)
&& !strcmp(host->link[j].port, port)) {
found = 1;
break;
}
}
if (!found) {
knet_vty_write(vty, "Error: unable to find link%s", telnet_newline);
return -1;
}
- host->link[j].configured = 0;
- if (knet_host_dst_cache_update(knet_iface->cfg_ring.knet_h, host->node_id))
+ if (knet_link_enable(knet_iface->cfg_ring.knet_h, host->node_id, &host->link[j], 0))
knet_vty_write(vty, "Error: unable to update switching cache%s", telnet_newline);
return 0;
}
static int knet_cmd_link(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
struct knet_host *host = (struct knet_host *)vty->host;
struct knet_link *klink = NULL;
int j, paramlen = 0, paramoffset = 0, err = 0, found = 0;
char *param = NULL;
char ipaddr[KNET_MAX_HOST_LEN], port[6];
get_param(vty, 1, &param, &paramlen, &paramoffset);
param_to_str(ipaddr, KNET_MAX_HOST_LEN, param, paramlen);
memset(port, 0, sizeof(port));
snprintf(port, 6, "%d", knet_iface->cfg_ring.base_port + knet_iface->cfg_eth.node_id);
for (j = 0; j < KNET_MAX_LINK; j++) {
if ((klink == NULL) && (host->link[j].configured == 0)) {
klink = &host->link[j];
}
if (!strcmp(host->link[j].ipaddr, ipaddr)
&& !strcmp(host->link[j].port, port)) {
found = 1;
break;
}
}
if (!found) {
if (!klink) {
knet_vty_write(vty, "Error: all links are in use!%s", telnet_newline);
return -1;
}
memcpy(klink->ipaddr, ipaddr, strlen(ipaddr));
memcpy(klink->port, port, strlen(port));
if (strtoaddr(klink->ipaddr, klink->port, (struct sockaddr *)&klink->address, sizeof(klink->address)) != 0) {
knet_vty_write(vty, "Error: unable to convert ip addr to sockaddr!%s", telnet_newline);
err = -1;
goto out_clean;
}
klink->sock = host->listener->sock;
knet_link_timeout(klink, 1000, 5000, 2048);
- klink->configured = 1;
+ knet_link_enable(knet_iface->cfg_ring.knet_h, host->node_id, klink, 1);
}
vty->link = (void *)klink;
vty->node = NODE_LINK;
out_clean:
return err;
}
static int knet_find_host(struct knet_vty *vty, struct knet_host **host,
const char *nodename, const uint16_t requested_node_id)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
struct knet_host *head = NULL;
int err = 0;
*host = NULL;
if (knet_host_acquire(knet_iface->cfg_ring.knet_h, &head)) {
knet_vty_write(vty, "Error: unable to acquire lock on peer list!%s", telnet_newline);
return -1;
}
while (head != NULL) {
if (!strcmp(head->name, nodename)) {
if (head->node_id == requested_node_id) {
*host = head;
err = 1;
goto out_clean;
} else {
knet_vty_write(vty, "Error: requested peer exists with another nodeid%s", telnet_newline);
err = -1;
goto out_clean;
}
} else {
if (head->node_id == requested_node_id) {
knet_vty_write(vty, "Error: requested peer nodeid already exists%s", telnet_newline);
err = -1;
goto out_clean;
}
}
head = head->next;
}
out_clean:
while (knet_host_release(knet_iface->cfg_ring.knet_h, &head) != 0) {
knet_vty_write(vty, "Error: unable to release lock on peer list!%s", telnet_newline);
sleep(1);
}
return err;
}
static int knet_cmd_no_peer(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
int paramlen = 0, paramoffset = 0, requested_node_id = 0, err = 0;
char *param = NULL;
struct knet_host *host = NULL;
char nodename[KNET_MAX_HOST_LEN];
get_param(vty, 1, &param, &paramlen, &paramoffset);
param_to_str(nodename, sizeof(nodename), param, paramlen);
get_param(vty, 2, &param, &paramlen, &paramoffset);
requested_node_id = param_to_int(param, paramlen);
if (requested_node_id == knet_iface->cfg_eth.node_id) {
knet_vty_write(vty, "Error: remote peer id cannot be the same as local id%s", telnet_newline);
return -1;
}
err = knet_find_host(vty, &host, nodename, requested_node_id);
if (err < 0)
goto out_clean;
if (err == 0) {
knet_vty_write(vty, "Error: peer not found in list%s", telnet_newline);
goto out_clean;
}
if (host->listener) {
if (knet_listener_remove(knet_iface->cfg_ring.knet_h, host->listener) == -EBUSY) {
knet_vty_write(vty, "Error: unable to remove listener from current peer%s", telnet_newline);
err = -1;
goto out_clean;
}
}
if (knet_host_remove(knet_iface->cfg_ring.knet_h, requested_node_id) < 0) {
knet_vty_write(vty, "Error: unable to remove peer from current config%s", telnet_newline);
err = -1;
goto out_clean;
}
out_clean:
return err;
}
static int knet_cmd_peer(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
int paramlen = 0, paramoffset = 0, requested_node_id = 0, err = 0;
char *param = NULL;
struct knet_host *host, *temp = NULL;
struct knet_listener *listener = NULL;
char nodename[KNET_MAX_HOST_LEN];
get_param(vty, 1, &param, &paramlen, &paramoffset);
param_to_str(nodename, sizeof(nodename), param, paramlen);
get_param(vty, 2, &param, &paramlen, &paramoffset);
requested_node_id = param_to_int(param, paramlen);
if (requested_node_id == knet_iface->cfg_eth.node_id) {
knet_vty_write(vty, "Error: remote peer id cannot be the same as local id%s", telnet_newline);
return -1;
}
err = knet_find_host(vty, &host, nodename, requested_node_id);
if (err < 0)
goto out_clean;
if (err == 0) {
if (knet_host_add(knet_iface->cfg_ring.knet_h, requested_node_id) < 0) {
knet_vty_write(vty, "Error: unable to allocate memory for host struct!%s", telnet_newline);
err = -1;
goto out_clean;
}
knet_host_get(knet_iface->cfg_ring.knet_h, requested_node_id, &temp);
host = temp;
knet_host_release(knet_iface->cfg_ring.knet_h, &temp);
memcpy(host->name, nodename, strlen(nodename));
host->link_handler_policy = KNET_LINK_POLICY_PASSIVE;
listener = malloc(sizeof(struct knet_listener));
if (!listener) {
knet_vty_write(vty, "Error: unable to allocate memory for listener struct!%s", telnet_newline);
err = -1;
goto out_clean;
}
memset(listener, 0, sizeof(struct knet_listener));
snprintf(listener->ipaddr, KNET_MAX_HOST_LEN, "::");
snprintf(listener->port, 6, "%d", knet_iface->cfg_ring.base_port + requested_node_id);
if (strtoaddr(listener->ipaddr, listener->port, (struct sockaddr *)&listener->address, sizeof(listener->address)) != 0) {
knet_vty_write(vty, "Error: unable to convert ip addr to sockaddr!%s", telnet_newline);
err = -1;
goto out_clean;
}
if (knet_listener_add(knet_iface->cfg_ring.knet_h, listener) != 0) {
knet_vty_write(vty, "Error: unable to start listener!%s", telnet_newline);
err = -1;
goto out_clean;
}
host->listener = listener;
}
vty->host = (void *)host;
vty->node = NODE_PEER;
out_clean:
if (err < 0) {
if (listener)
free(listener);
if (host)
knet_host_remove(knet_iface->cfg_ring.knet_h, host->node_id);
}
return err;
}
static int active_listeners(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
struct knet_host *head = NULL;
int listeners = 0;
if (knet_host_acquire(knet_iface->cfg_ring.knet_h, &head)) {
knet_vty_write(vty, "Error: unable to acquire lock on peer list!%s", telnet_newline);
return -1;
}
while (head != NULL) {
if (head->listener)
listeners++;
head = head->next;
}
while (knet_host_release(knet_iface->cfg_ring.knet_h, &head) != 0) {
knet_vty_write(vty, "Error: unable to release lock on peer list!%s", telnet_newline);
sleep(1);
}
return listeners;
}
static int knet_cmd_baseport(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
int paramlen = 0, paramoffset = 0, err = 0;
char *param = NULL;
get_param(vty, 1, &param, &paramlen, &paramoffset);
/* need to check if baseport is in use by other interfaces */
err = active_listeners(vty);
if (!err) {
knet_iface->cfg_ring.base_port = param_to_int(param, paramlen);
}
if (err > 0) {
knet_vty_write(vty, "Error: cannot switch baseport when listeners are active%s", telnet_newline);
err = -1;
}
return err;
}
static int knet_cmd_no_ip(struct knet_vty *vty)
{
int paramlen = 0, paramoffset = 0;
char *param = NULL;
char ipaddr[KNET_MAX_HOST_LEN], prefix[4];
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
char *error_string = NULL;
get_param(vty, 1, &param, &paramlen, &paramoffset);
param_to_str(ipaddr, sizeof(ipaddr), param, paramlen);
get_param(vty, 2, &param, &paramlen, &paramoffset);
param_to_str(prefix, sizeof(prefix), param, paramlen);
if (tap_del_ip(knet_iface->cfg_eth.tap, ipaddr, prefix, &error_string) < 0) {
knet_vty_write(vty, "Error: Unable to del ip addr %s/%s on device %s%s",
ipaddr, prefix, tap_get_name(knet_iface->cfg_eth.tap), telnet_newline);
if (error_string) {
knet_vty_write(vty, "(%s)%s", error_string, telnet_newline);
free(error_string);
}
return -1;
}
return 0;
}
static int knet_cmd_ip(struct knet_vty *vty)
{
int paramlen = 0, paramoffset = 0;
char *param = NULL;
char ipaddr[512], prefix[4];
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
char *error_string = NULL;
get_param(vty, 1, &param, &paramlen, &paramoffset);
param_to_str(ipaddr, sizeof(ipaddr), param, paramlen);
get_param(vty, 2, &param, &paramlen, &paramoffset);
param_to_str(prefix, sizeof(prefix), param, paramlen);
if (tap_add_ip(knet_iface->cfg_eth.tap, ipaddr, prefix, &error_string) < 0) {
knet_vty_write(vty, "Error: Unable to set ip addr %s/%s on device %s%s",
ipaddr, prefix, tap_get_name(knet_iface->cfg_eth.tap), telnet_newline);
if (error_string) {
knet_vty_write(vty, "(%s)%s", error_string, telnet_newline);
free(error_string);
}
return -1;
}
return 0;
}
static int knet_cmd_no_mtu(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
if (tap_reset_mtu(knet_iface->cfg_eth.tap) < 0) {
knet_vty_write(vty, "Error: Unable to set default mtu on device %s%s",
tap_get_name(knet_iface->cfg_eth.tap), telnet_newline);
return -1;
}
return 0;
}
static int knet_cmd_mtu(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
int paramlen = 0, paramoffset = 0, expected_mtu = 0;
char *param = NULL;
get_param(vty, 1, &param, &paramlen, &paramoffset);
expected_mtu = param_to_int(param, paramlen);
if (tap_set_mtu(knet_iface->cfg_eth.tap, expected_mtu) < 0) {
knet_vty_write(vty, "Error: Unable to set requested mtu %d on device %s%s",
expected_mtu, tap_get_name(knet_iface->cfg_eth.tap), telnet_newline);
return -1;
}
return 0;
}
static int knet_cmd_stop(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
char *error_down = NULL, *error_postdown = NULL;
int err = 0;
err = tap_set_down(knet_iface->cfg_eth.tap, &error_down, &error_postdown);
if (err < 0) {
knet_vty_write(vty, "Error: Unable to set interface %s down!%s", tap_get_name(knet_iface->cfg_eth.tap), telnet_newline);
} else {
knet_handle_setfwd(knet_iface->cfg_ring.knet_h, 0);
knet_iface->active = 0;
}
if (error_down) {
knet_vty_write(vty, "down script output:%s(%s)%s", telnet_newline, error_down, telnet_newline);
free(error_down);
}
if (error_postdown) {
knet_vty_write(vty, "post-down script output:%s(%s)%s", telnet_newline, error_postdown, telnet_newline);
free(error_postdown);
}
return err;
}
static int knet_cmd_crypto(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
int paramlen = 0, paramoffset = 0;
char *param = NULL;
int err = 0;
if (knet_iface->active) {
knet_vty_write(vty, "Error: Unable to activate encryption while interface is active%s", telnet_newline);
return -1;
}
get_param(vty, 1, &param, &paramlen, &paramoffset);
param_to_str(knet_iface->knet_handle_crypto_cfg.crypto_model,
sizeof(knet_iface->knet_handle_crypto_cfg.crypto_model), param, paramlen);
get_param(vty, 2, &param, &paramlen, &paramoffset);
param_to_str(knet_iface->knet_handle_crypto_cfg.crypto_cipher_type,
sizeof(knet_iface->knet_handle_crypto_cfg.crypto_cipher_type), param, paramlen);
get_param(vty, 3, &param, &paramlen, &paramoffset);
param_to_str(knet_iface->knet_handle_crypto_cfg.crypto_hash_type,
sizeof(knet_iface->knet_handle_crypto_cfg.crypto_hash_type), param, paramlen);
if ((strncmp("none", knet_iface->knet_handle_crypto_cfg.crypto_cipher_type, 4)) ||
(strncmp("none", knet_iface->knet_handle_crypto_cfg.crypto_hash_type, 4))) {
int fd = -1;
char keyfile[PATH_MAX];
struct stat sb;
memset(keyfile, 0, PATH_MAX);
snprintf(keyfile, PATH_MAX - 1, DEFAULT_CONFIG_DIR "/cryptokeys.d/%s", tap_get_name(knet_iface->cfg_eth.tap));
fd = open(keyfile, O_RDONLY);
if (fd < 0) {
knet_vty_write(vty, "Error: Unable to open security key: %s%s", keyfile, telnet_newline);
err = -1;
return -1;
}
if (fstat(fd, &sb)) {
knet_vty_write(vty, "Error: Unable to verify security key: %s%s", keyfile, telnet_newline);
goto key_error;
}
if (!S_ISREG(sb.st_mode)) {
knet_vty_write(vty, "Error: Key %s does not appear to be a regular file%s",
keyfile, telnet_newline);
goto key_error;
}
knet_iface->knet_handle_crypto_cfg.private_key_len = (unsigned int)sb.st_size;
if ((knet_iface->knet_handle_crypto_cfg.private_key_len < KNET_MIN_KEY_LEN) ||
(knet_iface->knet_handle_crypto_cfg.private_key_len > KNET_MAX_KEY_LEN)) {
knet_vty_write(vty, "Error: Key %s is %u long. Must be %u <= key_len <= %u%s",
keyfile, knet_iface->knet_handle_crypto_cfg.private_key_len,
KNET_MIN_KEY_LEN, KNET_MAX_KEY_LEN, telnet_newline);
goto key_error;
}
if (((sb.st_mode & S_IRWXU) != S_IRUSR) ||
(sb.st_mode & S_IRWXG) ||
(sb.st_mode & S_IRWXO)) {
knet_vty_write(vty, "Error: Key %s does not have the correct permission (must be user read-only)%s",
keyfile, telnet_newline);
goto key_error;
}
if (read(fd,
&knet_iface->knet_handle_crypto_cfg.private_key,
knet_iface->knet_handle_crypto_cfg.private_key_len) != knet_iface->knet_handle_crypto_cfg.private_key_len) {
knet_vty_write(vty, "Error: Unable to read key %s%s", keyfile, telnet_newline);
goto key_error;
}
close(fd);
goto key_clean;
key_error:
close(fd);
err = -1;
}
key_clean:
if (!err) {
err = knet_handle_crypto(knet_iface->cfg_ring.knet_h,
&knet_iface->knet_handle_crypto_cfg);
}
return err;
}
static int knet_cmd_start(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
char *error_preup = NULL, *error_up = NULL;
int err = 0;
err = tap_set_up(knet_iface->cfg_eth.tap, &error_preup, &error_up);
if (err < 0) {
knet_vty_write(vty, "Error: Unable to set interface %s up!%s", tap_get_name(knet_iface->cfg_eth.tap), telnet_newline);
knet_handle_setfwd(knet_iface->cfg_ring.knet_h, 0);
} else {
knet_handle_setfwd(knet_iface->cfg_ring.knet_h, 1);
knet_iface->active = 1;
}
if (error_preup) {
knet_vty_write(vty, "pre-up script output:%s(%s)%s", telnet_newline, error_preup, telnet_newline);
free(error_preup);
}
if (error_up) {
knet_vty_write(vty, "up script output:%s(%s)%s", telnet_newline, error_up, telnet_newline);
free(error_up);
}
return err;
}
static int knet_cmd_no_interface(struct knet_vty *vty)
{
int err = 0, paramlen = 0, paramoffset = 0;
char *param = NULL;
char device[IFNAMSIZ];
struct knet_cfg *knet_iface = NULL;
struct knet_host *host;
char *ip_list = NULL;
int ip_list_entries = 0, i, offset = 0;
char *error_string = NULL;
get_param(vty, 1, &param, &paramlen, &paramoffset);
param_to_str(device, IFNAMSIZ, param, paramlen);
knet_iface = knet_get_iface(device, 0);
if (!knet_iface) {
knet_vty_write(vty, "Error: Unable to find requested interface%s", telnet_newline);
return -1;
}
vty->iface = (void *)knet_iface;
tap_get_ips(knet_iface->cfg_eth.tap, &ip_list, &ip_list_entries);
if ((ip_list) && (ip_list_entries > 0)) {
for (i = 1; i <= ip_list_entries; i++) {
tap_del_ip(knet_iface->cfg_eth.tap,
ip_list + offset,
ip_list + offset + strlen(ip_list + offset) + 1, &error_string);
if (error_string) {
free(error_string);
error_string = NULL;
}
offset = offset + strlen(ip_list) + 1;
offset = offset + strlen(ip_list + offset) + 1;
}
free(ip_list);
ip_list = NULL;
ip_list_entries = 0;
}
while (1) {
struct knet_host *head;
while (knet_host_acquire(knet_iface->cfg_ring.knet_h, &head) != 0) {
log_error("CLI ERROR: unable to acquire peer lock.. will retry in 1 sec");
sleep (1);
}
if (head == NULL)
break;
host = head;
while (knet_host_release(knet_iface->cfg_ring.knet_h, &head) != 0) {
log_error("CLI ERROR: unable to release peer lock.. will retry in 1 sec");
sleep (1);
}
for (i = 0; i < KNET_MAX_LINK; i++)
- host->link[i].configured = 0;
+ knet_link_enable(knet_iface->cfg_ring.knet_h, host->node_id, &host->link[i], 0);
knet_listener_remove(knet_iface->cfg_ring.knet_h, host->listener);
while (knet_host_remove(knet_iface->cfg_ring.knet_h, host->node_id) != 0) {
log_error("CLI ERROR: unable to release peer.. will retry in 1 sec");
sleep (1);
}
}
knet_cmd_stop(vty);
if (knet_iface->cfg_ring.knet_h)
knet_handle_free(knet_iface->cfg_ring.knet_h);
if (knet_iface->cfg_eth.tap)
tap_close(knet_iface->cfg_eth.tap);
if (knet_iface)
knet_destroy_iface(knet_iface);
return err;
}
static int knet_cmd_interface(struct knet_vty *vty)
{
int err = 0, paramlen = 0, paramoffset = 0, found = 0, requested_id;
char *param = NULL;
char device[IFNAMSIZ];
char mac[18];
struct knet_cfg *knet_iface = NULL;
struct knet_handle_cfg knet_handle_cfg;
get_param(vty, 1, &param, &paramlen, &paramoffset);
param_to_str(device, IFNAMSIZ, param, paramlen);
get_param(vty, 2, &param, &paramlen, &paramoffset);
requested_id = param_to_int(param, paramlen);
knet_iface = knet_get_iface(device, 1);
if (!knet_iface) {
knet_vty_write(vty, "Error: Unable to allocate memory for config structures%s",
telnet_newline);
return -1;
}
if (knet_iface->cfg_eth.tap) {
found = 1;
goto tap_found;
}
if (!knet_iface->cfg_eth.tap)
knet_iface->cfg_eth.tap = tap_open(device, IFNAMSIZ, DEFAULT_CONFIG_DIR);
if ((!knet_iface->cfg_eth.tap) && (errno = EBUSY)) {
knet_vty_write(vty, "Error: interface %s seems to exist in the system%s",
device, telnet_newline);
err = -1;
goto out_clean;
}
if (!knet_iface->cfg_eth.tap) {
knet_vty_write(vty, "Error: Unable to create %s system tap device%s",
device, telnet_newline);
err = -1;
goto out_clean;
}
tap_found:
if (knet_iface->cfg_ring.knet_h)
goto knet_found;
memset(&knet_handle_cfg, 0, sizeof(struct knet_handle_cfg));
knet_handle_cfg.fd = tap_get_fd(knet_iface->cfg_eth.tap);
knet_handle_cfg.node_id = requested_id;
knet_handle_cfg.dst_host_filter = KNET_DST_FILTER_ENABLE;
knet_handle_cfg.dst_host_filter_fn = ether_host_filter_fn;
knet_iface->cfg_ring.knet_h = knet_handle_new(&knet_handle_cfg);
if (!knet_iface->cfg_ring.knet_h) {
knet_vty_write(vty, "Error: Unable to create ring handle for device %s%s",
device, telnet_newline);
err = -1;
goto out_clean;
}
knet_found:
if (found) {
if (requested_id == knet_iface->cfg_eth.node_id)
goto out_found;
knet_vty_write(vty, "Error: no interface %s with nodeid %d found%s",
device, requested_id, telnet_newline);
goto out_clean;
} else {
knet_iface->cfg_eth.node_id = requested_id;
}
memset(&mac, 0, sizeof(mac));
snprintf(mac, sizeof(mac) - 1, "54:54:0:0:0:%x", knet_iface->cfg_eth.node_id);
if (tap_set_mac(knet_iface->cfg_eth.tap, mac) < 0) {
knet_vty_write(vty, "Error: Unable to set mac address %s on device %s%s",
mac, device, telnet_newline);
err = -1;
goto out_clean;
}
out_found:
vty->node = NODE_INTERFACE;
vty->iface = (void *)knet_iface;
out_clean:
if (err) {
if (knet_iface->cfg_ring.knet_h)
knet_handle_free(knet_iface->cfg_ring.knet_h);
if (knet_iface->cfg_eth.tap)
tap_close(knet_iface->cfg_eth.tap);
knet_destroy_iface(knet_iface);
}
return err;
}
static int knet_cmd_exit_node(struct knet_vty *vty)
{
knet_vty_exit_node(vty);
return 0;
}
static int knet_cmd_print_conf(struct knet_vty *vty)
{
int i;
struct knet_cfg *knet_iface = knet_cfg_head.knet_cfg;
struct knet_host *host = NULL;
const char *nl = telnet_newline;
char *ip_list = NULL;
int ip_list_entries = 0, offset = 0;
if (vty->filemode)
nl = file_newline;
knet_vty_write(vty, "configure%s", nl);
while (knet_iface != NULL) {
knet_vty_write(vty, " interface %s %u%s", tap_get_name(knet_iface->cfg_eth.tap),
knet_iface->cfg_eth.node_id, nl);
knet_vty_write(vty, " mtu %d%s", tap_get_mtu(knet_iface->cfg_eth.tap), nl);
tap_get_ips(knet_iface->cfg_eth.tap, &ip_list, &ip_list_entries);
if ((ip_list) && (ip_list_entries > 0)) {
for (i = 1; i <= ip_list_entries; i++) {
knet_vty_write(vty, " ip %s %s%s", ip_list + offset, ip_list + offset + strlen(ip_list + offset) + 1, nl);
offset = offset + strlen(ip_list) + 1;
offset = offset + strlen(ip_list + offset) + 1;
}
free(ip_list);
ip_list = NULL;
ip_list_entries = 0;
}
knet_vty_write(vty, " baseport %d%s", knet_iface->cfg_ring.base_port, nl);
knet_vty_write(vty, " crypto %s %s %s%s",
knet_iface->knet_handle_crypto_cfg.crypto_model,
knet_iface->knet_handle_crypto_cfg.crypto_cipher_type,
knet_iface->knet_handle_crypto_cfg.crypto_hash_type, nl);
while (knet_host_acquire(knet_iface->cfg_ring.knet_h, &host)) {
log_error("CLI ERROR: waiting for peer lock");
sleep(1);
}
while (host != NULL) {
knet_vty_write(vty, " peer %s %u%s", host->name, host->node_id, nl);
for (i = 0; i < KNET_MAX_LINK; i++) {
if (host->link[i].configured == 1) {
knet_vty_write(vty, " link %s%s", host->link[i].ipaddr, nl);
/* print link properties */
knet_vty_write(vty, " exit%s", nl);
}
}
knet_vty_write(vty, " exit%s", nl);
host = host->next;
}
while (knet_host_release(knet_iface->cfg_ring.knet_h, &host) != 0) {
log_error("CLI ERROR: unable to release peer lock.. will retry in 1 sec");
sleep(1);
}
if (knet_iface->active)
knet_vty_write(vty, " start%s", nl);
knet_vty_write(vty, " exit%s", nl);
knet_iface = knet_iface->next;
}
knet_vty_write(vty, " exit%sexit%s", nl, nl);
return 0;
}
static int knet_cmd_show_conf(struct knet_vty *vty)
{
return knet_cmd_print_conf(vty);
}
static int knet_cmd_write_conf(struct knet_vty *vty)
{
int fd = 1, vty_sock, err = 0, backup = 1;
char tempfile[PATH_MAX];
memset(tempfile, 0, sizeof(tempfile));
snprintf(tempfile, sizeof(tempfile), "%s.sav", knet_cfg_head.conffile);
err = rename(knet_cfg_head.conffile, tempfile);
if ((err < 0) && (errno != ENOENT)) {
knet_vty_write(vty, "Unable to create backup config file %s %s", tempfile, telnet_newline);
return -1;
}
if ((err < 0) && (errno == ENOENT))
backup = 0;
fd = open(knet_cfg_head.conffile,
O_RDWR | O_CREAT | O_EXCL | O_TRUNC,
S_IRUSR | S_IWUSR);
if (fd < 0) {
knet_vty_write(vty, "Error unable to open file%s", telnet_newline);
return -1;
}
vty_sock = vty->vty_sock;
vty->vty_sock = fd;
vty->filemode = 1;
knet_cmd_print_conf(vty);
vty->vty_sock = vty_sock;
vty->filemode = 0;
close(fd);
knet_vty_write(vty, "Configuration saved to %s%s", knet_cfg_head.conffile, telnet_newline);
if (backup)
knet_vty_write(vty, "Old configuration file has been stored in %s%s",
tempfile, telnet_newline);
return err;
}
static int knet_cmd_config(struct knet_vty *vty)
{
int err = 0;
if (!vty->user_can_enable) {
knet_vty_write(vty, "Error: user %s does not have enough privileges to perform config operations%s", vty->username, telnet_newline);
return -1;
}
pthread_mutex_lock(&knet_vty_mutex);
if (knet_vty_config >= 0) {
knet_vty_write(vty, "Error: configuration is currently locked by user %s on vty(%d). Try again later%s", vty->username, knet_vty_config, telnet_newline);
err = -1;
goto out_clean;
}
vty->node = NODE_CONFIG;
knet_vty_config = vty->conn_num;
out_clean:
pthread_mutex_unlock(&knet_vty_mutex);
return err;
}
static int knet_cmd_logout(struct knet_vty *vty)
{
vty->got_epipe = 1;
return 0;
}
static int knet_cmd_who(struct knet_vty *vty)
{
int conn_index;
pthread_mutex_lock(&knet_vty_mutex);
for(conn_index = 0; conn_index < KNET_VTY_TOTAL_MAX_CONN; conn_index++) {
if (knet_vtys[conn_index].active) {
knet_vty_write(vty, "User %s connected on vty(%d) from %s%s",
knet_vtys[conn_index].username,
knet_vtys[conn_index].conn_num,
knet_vtys[conn_index].ip,
telnet_newline);
}
}
pthread_mutex_unlock(&knet_vty_mutex);
return 0;
}
static int knet_cmd_help(struct knet_vty *vty)
{
knet_vty_write(vty, PACKAGE " VTY provides advanced help feature.%s%s"
"When you need help, anytime at the command line please press '?'.%s%s"
"If nothing matches, the help list will be empty and you must backup%s"
" until entering a '?' shows the available options.%s",
telnet_newline, telnet_newline, telnet_newline, telnet_newline,
telnet_newline, telnet_newline);
return 0;
}
/* exported API to vty_cli.c */
int knet_vty_execute_cmd(struct knet_vty *vty)
{
const vty_node_cmds_t *cmds = NULL;
char *cmd = NULL;
int cmdlen = 0;
int cmdoffset = 0;
if (knet_vty_is_line_empty(vty))
return 0;
cmds = get_cmds(vty, &cmd, &cmdlen, &cmdoffset);
/* this will eventually disappear. keep it as safeguard for now */
if (cmds == NULL) {
knet_vty_write(vty, "No commands associated to this node%s", telnet_newline);
return 0;
}
return match_command(vty, cmds, cmd, cmdlen, cmdoffset, KNET_VTY_MATCH_EXEC);
}
int knet_read_conf(void)
{
int err = 0, len = 0, line = 0;
struct knet_vty *vty = &knet_vtys[0];
FILE *file = NULL;
file = fopen(knet_cfg_head.conffile, "r");
if ((file == NULL) && (errno != ENOENT)) {
log_error("Unable to open config file for reading %s", knet_cfg_head.conffile);
return -1;
}
if ((file == NULL) && (errno == ENOENT)) {
log_info("Configuration file %s not found, starting with default empty config", knet_cfg_head.conffile);
return 0;
}
vty->vty_sock = 1;
vty->user_can_enable = 1;
vty->filemode = 1;
while(fgets(vty->line, sizeof(vty->line), file) != NULL) {
line++;
len = strlen(vty->line) - 1;
memset(&vty->line[len], 0, 1);
vty->line_idx = len;
err = knet_vty_execute_cmd(vty);
if (err != 0) {
log_error("line[%d]: %s", line, vty->line);
break;
}
}
fclose(file);
memset(vty, 0, sizeof(vty));
return err;
}
void knet_vty_help(struct knet_vty *vty)
{
int idx = 0;
const vty_node_cmds_t *cmds = NULL;
char *cmd = NULL;
int cmdlen = 0;
int cmdoffset = 0;
cmds = get_cmds(vty, &cmd, &cmdlen, &cmdoffset);
/* this will eventually disappear. keep it as safeguard for now */
if (cmds == NULL) {
knet_vty_write(vty, "No commands associated to this node%s", telnet_newline);
return;
}
if (knet_vty_is_line_empty(vty) || cmd == NULL) {
while (cmds[idx].cmd != NULL) {
print_help(vty, cmds, idx);
idx++;
}
return;
}
match_command(vty, cmds, cmd, cmdlen, cmdoffset, KNET_VTY_MATCH_HELP);
}
void knet_vty_tab_completion(struct knet_vty *vty)
{
const vty_node_cmds_t *cmds = NULL;
char *cmd = NULL;
int cmdlen = 0;
int cmdoffset = 0;
if (knet_vty_is_line_empty(vty))
return;
knet_vty_write(vty, "%s", telnet_newline);
cmds = get_cmds(vty, &cmd, &cmdlen, &cmdoffset);
/* this will eventually disappear. keep it as safeguard for now */
if (cmds == NULL) {
knet_vty_write(vty, "No commands associated to this node%s", telnet_newline);
return;
}
match_command(vty, cmds, cmd, cmdlen, cmdoffset, KNET_VTY_MATCH_EXPAND);
knet_vty_prompt(vty);
knet_vty_write(vty, "%s", vty->line);
}
diff --git a/libknet/handle.c b/libknet/handle.c
index 28e385c6..4d4839e4 100644
--- a/libknet/handle.c
+++ b/libknet/handle.c
@@ -1,705 +1,729 @@
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sys/epoll.h>
#include "libknet-private.h"
#include "crypto.h"
#define KNET_MAX_EVENTS 8
#define KNET_PING_TIMERES 200000
static void *_handle_tap_to_links_thread(void *data);
static void *_handle_recv_from_links_thread(void *data);
static void *_handle_heartbt_thread(void *data);
static void *_handle_dst_link_handler_thread(void *data);
knet_handle_t knet_handle_new(const struct knet_handle_cfg *knet_handle_cfg)
{
knet_handle_t knet_h;
struct epoll_event ev;
/*
* validate incoming config request
*/
if (knet_handle_cfg == NULL) {
errno = EINVAL;
return NULL;
}
if (knet_handle_cfg->fd <= 0) {
errno = EINVAL;
return NULL;
}
if ((knet_h = malloc(sizeof(struct knet_handle))) == NULL)
return NULL;
memset(knet_h, 0, sizeof(struct knet_handle));
knet_h->node_id = knet_handle_cfg->node_id;
knet_h->sockfd = knet_handle_cfg->fd;
if (pipe(knet_h->pipefd))
goto exit_fail1;
if ((_fdset_cloexec(knet_h->pipefd[0])) ||
(_fdset_cloexec(knet_h->pipefd[1])) ||
(_fdset_nonblock(knet_h->pipefd[0])) ||
(_fdset_nonblock(knet_h->pipefd[1])))
goto exit_fail2;
knet_h->dst_host_filter = knet_handle_cfg->dst_host_filter;
knet_h->dst_host_filter_fn = knet_handle_cfg->dst_host_filter_fn;
if ((knet_h->dst_host_filter) && (!knet_h->dst_host_filter_fn))
goto exit_fail2;
if ((knet_h->tap_to_links_buf = malloc(KNET_DATABUFSIZE))== NULL)
goto exit_fail2;
memset(knet_h->tap_to_links_buf, 0, KNET_DATABUFSIZE);
if ((knet_h->recv_from_links_buf = malloc(KNET_DATABUFSIZE))== NULL)
goto exit_fail3;
memset(knet_h->recv_from_links_buf, 0, KNET_DATABUFSIZE);
if ((knet_h->pingbuf = malloc(KNET_PINGBUFSIZE))== NULL)
goto exit_fail4;
memset(knet_h->pingbuf, 0, KNET_PINGBUFSIZE);
if (pthread_rwlock_init(&knet_h->list_rwlock, NULL) != 0)
goto exit_fail5;
knet_h->tap_to_links_epollfd = epoll_create(KNET_MAX_EVENTS);
knet_h->recv_from_links_epollfd = epoll_create(KNET_MAX_EVENTS);
knet_h->dst_link_handler_epollfd = epoll_create(KNET_MAX_EVENTS);
if ((knet_h->tap_to_links_epollfd < 0) ||
(knet_h->recv_from_links_epollfd < 0) ||
(knet_h->dst_link_handler_epollfd < 0))
goto exit_fail6;
if ((_fdset_cloexec(knet_h->tap_to_links_epollfd) != 0) ||
(_fdset_cloexec(knet_h->recv_from_links_epollfd) != 0) ||
(_fdset_cloexec(knet_h->dst_link_handler_epollfd) != 0))
goto exit_fail6;
memset(&ev, 0, sizeof(struct epoll_event));
ev.events = EPOLLIN;
ev.data.fd = knet_h->sockfd;
if (epoll_ctl(knet_h->tap_to_links_epollfd,
EPOLL_CTL_ADD, knet_h->sockfd, &ev) != 0)
goto exit_fail6;
memset(&ev, 0, sizeof(struct epoll_event));
ev.events = EPOLLIN;
ev.data.fd = knet_h->pipefd[0];
if (epoll_ctl(knet_h->dst_link_handler_epollfd,
EPOLL_CTL_ADD, knet_h->pipefd[0], &ev) != 0)
goto exit_fail6;
if (pthread_create(&knet_h->dst_link_handler_thread, 0,
_handle_dst_link_handler_thread, (void *) knet_h) != 0)
goto exit_fail6;
if (pthread_create(&knet_h->tap_to_links_thread, 0,
_handle_tap_to_links_thread, (void *) knet_h) != 0)
goto exit_fail7;
if (pthread_create(&knet_h->recv_from_links_thread, 0,
_handle_recv_from_links_thread, (void *) knet_h) != 0)
goto exit_fail8;
if (pthread_create(&knet_h->heartbt_thread, 0,
_handle_heartbt_thread, (void *) knet_h) != 0)
goto exit_fail9;
return knet_h;
exit_fail9:
pthread_cancel(knet_h->recv_from_links_thread);
exit_fail8:
pthread_cancel(knet_h->tap_to_links_thread);
exit_fail7:
pthread_cancel(knet_h->dst_link_handler_thread);
exit_fail6:
if (knet_h->tap_to_links_epollfd >= 0)
close(knet_h->tap_to_links_epollfd);
if (knet_h->recv_from_links_epollfd >= 0)
close(knet_h->recv_from_links_epollfd);
if (knet_h->dst_link_handler_epollfd >= 0)
close(knet_h->dst_link_handler_epollfd);
pthread_rwlock_destroy(&knet_h->list_rwlock);
exit_fail5:
free(knet_h->pingbuf);
exit_fail4:
free(knet_h->recv_from_links_buf);
exit_fail3:
free(knet_h->tap_to_links_buf);
exit_fail2:
close(knet_h->pipefd[0]);
close(knet_h->pipefd[1]);
exit_fail1:
free(knet_h);
return NULL;
}
int knet_handle_free(knet_handle_t knet_h)
{
void *retval;
if ((knet_h->host_head != NULL) || (knet_h->listener_head != NULL))
goto exit_busy;
pthread_cancel(knet_h->heartbt_thread);
pthread_join(knet_h->heartbt_thread, &retval);
if (retval != PTHREAD_CANCELED)
goto exit_busy;
pthread_cancel(knet_h->tap_to_links_thread);
pthread_join(knet_h->tap_to_links_thread, &retval);
if (retval != PTHREAD_CANCELED)
goto exit_busy;
pthread_cancel(knet_h->recv_from_links_thread);
pthread_join(knet_h->recv_from_links_thread, &retval);
if (retval != PTHREAD_CANCELED)
goto exit_busy;
pthread_cancel(knet_h->dst_link_handler_thread);
pthread_join(knet_h->dst_link_handler_thread, &retval);
if (retval != PTHREAD_CANCELED)
goto exit_busy;
close(knet_h->tap_to_links_epollfd);
close(knet_h->recv_from_links_epollfd);
close(knet_h->dst_link_handler_epollfd);
close(knet_h->pipefd[0]);
close(knet_h->pipefd[1]);
pthread_rwlock_destroy(&knet_h->list_rwlock);
free(knet_h->tap_to_links_buf);
free(knet_h->recv_from_links_buf);
free(knet_h->pingbuf);
crypto_fini(knet_h);
free(knet_h);
return 0;
exit_busy:
errno = EBUSY;
return -EBUSY;
}
void knet_handle_setfwd(knet_handle_t knet_h, int enabled)
{
knet_h->enabled = (enabled == 1) ? 1 : 0;
}
int knet_handle_crypto(knet_handle_t knet_h, struct knet_handle_crypto_cfg *knet_handle_crypto_cfg)
{
if (knet_h->enabled)
return -1;
return crypto_init(knet_h, knet_handle_crypto_cfg);
}
+int knet_link_enable(knet_handle_t knet_h, uint16_t node_id, struct knet_link *lnk, int configured)
+{
+ int write_retry = 0;
+
+ if (lnk->configured == configured)
+ return 0;
+
+ lnk->configured = configured;
+
+ if (configured)
+ return 0;
+
+try_again:
+ if (write(knet_h->pipefd[1], &node_id, sizeof(node_id)) != sizeof(node_id)) {
+ if ((write_retry < 10) && ((errno = EAGAIN) || (errno = EWOULDBLOCK))) {
+ write_retry++;
+ goto try_again;
+ } else {
+ return -1;
+ }
+ }
+ return 0;
+}
+
void knet_link_timeout(struct knet_link *lnk,
time_t interval, time_t timeout, int precision)
{
lnk->ping_interval = interval * 1000; /* microseconds */
lnk->pong_timeout = timeout * 1000; /* microseconds */
lnk->latency_fix = precision;
lnk->latency_exp = precision - \
((lnk->ping_interval * precision) / 8000000);
}
static void _handle_tap_to_links(knet_handle_t knet_h)
{
ssize_t inlen, len, outlen;
struct knet_host *dst_host;
int link_idx;
uint16_t dst_host_ids[KNET_MAX_HOST];
size_t dst_host_ids_entries = 0;
int bcast = 1;
unsigned char *outbuf = (unsigned char *)knet_h->tap_to_links_buf;
inlen = read(knet_h->sockfd, knet_h->tap_to_links_buf->kf_data,
KNET_DATABUFSIZE - (KNET_FRAME_SIZE + sizeof(seq_num_t)));
if (inlen == 0) {
/* TODO: disconnection, should never happen! */
return;
}
outlen = len = inlen + KNET_FRAME_SIZE + sizeof(seq_num_t);
if (knet_h->enabled != 1) /* data forward is disabled */
return;
if (knet_h->dst_host_filter) {
bcast = knet_h->dst_host_filter_fn(
(const unsigned char *)knet_h->tap_to_links_buf->kf_data,
inlen,
knet_h->tap_to_links_buf->kf_node,
dst_host_ids,
&dst_host_ids_entries);
if (bcast < 0)
return;
if ((!bcast) && (!dst_host_ids_entries))
return;
}
if (pthread_rwlock_rdlock(&knet_h->list_rwlock) != 0)
return;
if (!bcast) {
int host_idx;
for (host_idx = 0; host_idx < dst_host_ids_entries; host_idx++) {
dst_host = knet_h->host_index[dst_host_ids[host_idx]];
if (!dst_host)
continue;
knet_h->tap_to_links_buf->kf_seq_num = htons(++dst_host->ucast_seq_num_tx);
if (knet_h->crypto_instance) {
if (crypto_encrypt_and_sign(knet_h->crypto_instance,
(const unsigned char *)knet_h->tap_to_links_buf,
len,
knet_h->tap_to_links_buf_crypt,
&outlen) < 0) {
pthread_rwlock_unlock(&knet_h->list_rwlock);
return;
}
outbuf = knet_h->tap_to_links_buf_crypt;
}
for (link_idx = 0; link_idx < dst_host->active_link_entries; link_idx++) {
sendto(dst_host->link[dst_host->active_links[link_idx]].sock,
outbuf, outlen, MSG_DONTWAIT,
(struct sockaddr *) &dst_host->link[dst_host->active_links[link_idx]].address,
sizeof(struct sockaddr_storage));
if ((dst_host->link_handler_policy == KNET_LINK_POLICY_RR) &&
(dst_host->active_link_entries > 1)) {
uint8_t cur_link_id = dst_host->active_links[0];
memmove(&dst_host->active_links[0], &dst_host->active_links[1], KNET_MAX_LINK - 1);
dst_host->active_links[dst_host->active_link_entries - 1] = cur_link_id;
break;
}
}
}
} else {
knet_h->tap_to_links_buf->kf_seq_num = htons(++knet_h->bcast_seq_num_tx);
if (knet_h->crypto_instance) {
if (crypto_encrypt_and_sign(knet_h->crypto_instance,
(const unsigned char *)knet_h->tap_to_links_buf,
len,
knet_h->tap_to_links_buf_crypt,
&outlen) < 0) {
pthread_rwlock_unlock(&knet_h->list_rwlock);
return;
}
outbuf = knet_h->tap_to_links_buf_crypt;
}
for (dst_host = knet_h->host_head; dst_host != NULL; dst_host = dst_host->next) {
for (link_idx = 0; link_idx < dst_host->active_link_entries; link_idx++) {
sendto(dst_host->link[dst_host->active_links[link_idx]].sock,
outbuf, outlen, MSG_DONTWAIT,
(struct sockaddr *) &dst_host->link[dst_host->active_links[link_idx]].address,
sizeof(struct sockaddr_storage));
if ((dst_host->link_handler_policy == KNET_LINK_POLICY_RR) &&
(dst_host->active_link_entries > 1)) {
uint8_t cur_link_id = dst_host->active_links[0];
memmove(&dst_host->active_links[0], &dst_host->active_links[1], KNET_MAX_LINK - 1);
dst_host->active_links[dst_host->active_link_entries - 1] = cur_link_id;
break;
}
}
}
}
pthread_rwlock_unlock(&knet_h->list_rwlock);
}
static void _handle_recv_from_links(knet_handle_t knet_h, int sockfd)
{
ssize_t len, outlen;
struct sockaddr_storage address;
socklen_t addrlen;
struct knet_host *src_host;
struct knet_link *src_link;
unsigned long long latency_last;
uint16_t dst_host_ids[KNET_MAX_HOST];
size_t dst_host_ids_entries = 0;
int bcast = 1;
unsigned char *outbuf = (unsigned char *)knet_h->recv_from_links_buf;
if (pthread_rwlock_rdlock(&knet_h->list_rwlock) != 0)
return;
addrlen = sizeof(struct sockaddr_storage);
len = recvfrom(sockfd, knet_h->recv_from_links_buf, KNET_DATABUFSIZE,
MSG_DONTWAIT, (struct sockaddr *) &address, &addrlen);
if (knet_h->crypto_instance) {
if (crypto_authenticate_and_decrypt(knet_h->crypto_instance,
(unsigned char *)knet_h->recv_from_links_buf,
&len) < 0)
goto exit_unlock;
}
if (len < (KNET_FRAME_SIZE + 1))
goto exit_unlock;
if (ntohl(knet_h->recv_from_links_buf->kf_magic) != KNET_FRAME_MAGIC)
goto exit_unlock;
if (knet_h->recv_from_links_buf->kf_version != KNET_FRAME_VERSION)
goto exit_unlock;
knet_h->recv_from_links_buf->kf_node = ntohs(knet_h->recv_from_links_buf->kf_node);
src_host = knet_h->host_index[knet_h->recv_from_links_buf->kf_node];
if (src_host == NULL) { /* host not found */
goto exit_unlock;
}
src_link = NULL;
if ((knet_h->recv_from_links_buf->kf_type & KNET_FRAME_PMSK) != 0) {
src_link = src_host->link +
(knet_h->recv_from_links_buf->kf_link % KNET_MAX_LINK);
}
switch (knet_h->recv_from_links_buf->kf_type) {
case KNET_FRAME_DATA:
if (knet_h->enabled != 1) /* data forward is disabled */
break;
knet_h->recv_from_links_buf->kf_seq_num = ntohs(knet_h->recv_from_links_buf->kf_seq_num);
if (knet_h->dst_host_filter) {
int host_idx;
int found = 0;
bcast = knet_h->dst_host_filter_fn(
(const unsigned char *)knet_h->recv_from_links_buf->kf_data,
len,
knet_h->recv_from_links_buf->kf_node,
dst_host_ids,
&dst_host_ids_entries);
if (bcast < 0)
goto exit_unlock;
if ((!bcast) && (!dst_host_ids_entries))
goto exit_unlock;
/* check if we are dst for this packet */
if (!bcast) {
for (host_idx = 0; host_idx < dst_host_ids_entries; host_idx++) {
if (dst_host_ids[host_idx] == knet_h->node_id) {
found = 1;
break;
}
}
if (!found)
goto exit_unlock;
}
}
if (!knet_should_deliver(src_host, bcast, knet_h->recv_from_links_buf->kf_seq_num))
goto exit_unlock;
if (write(knet_h->sockfd,
knet_h->recv_from_links_buf->kf_data,
len - (KNET_FRAME_SIZE + sizeof(seq_num_t))) == len - (KNET_FRAME_SIZE + sizeof(seq_num_t)))
knet_has_been_delivered(src_host, bcast, knet_h->recv_from_links_buf->kf_seq_num);
break;
case KNET_FRAME_PING:
outlen = KNET_PINGBUFSIZE;
knet_h->recv_from_links_buf->kf_type = KNET_FRAME_PONG;
knet_h->recv_from_links_buf->kf_node = htons(knet_h->node_id);
if (knet_h->crypto_instance) {
if (crypto_encrypt_and_sign(knet_h->crypto_instance,
(const unsigned char *)knet_h->recv_from_links_buf,
len,
knet_h->recv_from_links_buf_crypt,
&outlen) < 0)
break;
outbuf = knet_h->recv_from_links_buf_crypt;
}
sendto(src_link->sock, outbuf, outlen, MSG_DONTWAIT,
(struct sockaddr *) &src_link->address,
sizeof(struct sockaddr_storage));
break;
case KNET_FRAME_PONG:
clock_gettime(CLOCK_MONOTONIC, &src_link->pong_last);
timespec_diff(knet_h->recv_from_links_buf->kf_time,
src_link->pong_last, &latency_last);
src_link->latency =
((src_link->latency * src_link->latency_exp) +
((latency_last / 1000llu) *
(src_link->latency_fix - src_link->latency_exp))) /
src_link->latency_fix;
if (src_link->latency < src_link->pong_timeout) {
if (!src_link->connected) {
int write_retry = 0;
src_link->connected = 1;
try_again:
if (write(knet_h->pipefd[1], &src_host->node_id,
sizeof(src_host->node_id)) != sizeof(src_host->node_id)) {
if ((write_retry < 10) && ((errno = EAGAIN) || (errno = EWOULDBLOCK))) {
write_retry++;
goto try_again;
} /* define what to do if we can't add a link */
}
}
}
break;
default:
goto exit_unlock;
}
exit_unlock:
pthread_rwlock_unlock(&knet_h->list_rwlock);
}
static void _handle_dst_link_updates(knet_handle_t knet_h)
{
uint16_t dst_host_id;
struct knet_host *dst_host;
int link_idx;
int best_priority = -1;
if (read(knet_h->pipefd[0], &dst_host_id, sizeof(dst_host_id)) != sizeof(dst_host_id))
return;
if (pthread_rwlock_wrlock(&knet_h->list_rwlock) != 0)
return;
dst_host = knet_h->host_index[dst_host_id];
if (!dst_host)
goto out_unlock;
dst_host->active_link_entries = 0;
for (link_idx = 0; link_idx < KNET_MAX_LINK; link_idx++) {
if (dst_host->link[link_idx].configured != 1) /* link is not configured */
continue;
if (dst_host->link[link_idx].connected != 1) /* link is not enabled */
continue;
if (dst_host->link_handler_policy == KNET_LINK_POLICY_PASSIVE) {
/* for passive we look for the only active link with higher priority */
if (dst_host->link[link_idx].priority > best_priority) {
dst_host->active_links[0] = link_idx;
best_priority = dst_host->link[link_idx].priority;
}
dst_host->active_link_entries = 1;
} else {
/* for RR and ACTIVE we need to copy all available links */
dst_host->active_links[dst_host->active_link_entries] = link_idx;
dst_host->active_link_entries++;
}
}
/* no active links, we can clean the circular buffers and indexes */
if (!dst_host->active_link_entries) {
memset(dst_host->bcast_circular_buffer, 0, KNET_CBUFFER_SIZE);
memset(dst_host->ucast_circular_buffer, 0, KNET_CBUFFER_SIZE);
dst_host->bcast_seq_num_rx = 0;
dst_host->ucast_seq_num_rx = 0;
}
out_unlock:
pthread_rwlock_unlock(&knet_h->list_rwlock);
return;
}
static void _handle_check_each(knet_handle_t knet_h, struct knet_host *dst_host, struct knet_link *dst_link)
{
int len;
ssize_t outlen = KNET_PINGBUFSIZE;
struct timespec clock_now, pong_last;
unsigned long long diff_ping;
unsigned char *outbuf = (unsigned char *)knet_h->pingbuf;
/* caching last pong to avoid race conditions */
pong_last = dst_link->pong_last;
if (clock_gettime(CLOCK_MONOTONIC, &clock_now) != 0)
return;
timespec_diff(dst_link->ping_last, clock_now, &diff_ping);
if (diff_ping >= (dst_link->ping_interval * 1000llu)) {
knet_h->pingbuf->kf_time = clock_now;
knet_h->pingbuf->kf_link = dst_link->link_id;
if (knet_h->crypto_instance) {
if (crypto_encrypt_and_sign(knet_h->crypto_instance,
(const unsigned char *)knet_h->pingbuf,
KNET_PINGBUFSIZE,
knet_h->pingbuf_crypt,
&outlen) < 0)
return;
outbuf = knet_h->pingbuf_crypt;
}
len = sendto(dst_link->sock, outbuf, outlen,
MSG_DONTWAIT, (struct sockaddr *) &dst_link->address,
sizeof(struct sockaddr_storage));
if (len == outlen)
dst_link->ping_last = clock_now;
}
if (dst_link->connected == 1) {
timespec_diff(pong_last, clock_now, &diff_ping);
if (diff_ping >= (dst_link->pong_timeout * 1000llu)) {
int write_retry = 0;
dst_link->connected = 0;
try_again:
if (write(knet_h->pipefd[1], &dst_host->node_id, sizeof(dst_host->node_id)) != sizeof(dst_host->node_id)) {
if ((write_retry < 10) && ((errno = EAGAIN) || (errno = EWOULDBLOCK))) {
write_retry++;
goto try_again;
} /* define what to do if we can't deactivate a link */
}
}
}
}
static void *_handle_heartbt_thread(void *data)
{
knet_handle_t knet_h;
struct knet_host *dst_host;
int link_idx;
knet_h = (knet_handle_t) data;
/* preparing ping buffer */
knet_h->pingbuf->kf_magic = htonl(KNET_FRAME_MAGIC);
knet_h->pingbuf->kf_version = KNET_FRAME_VERSION;
knet_h->pingbuf->kf_type = KNET_FRAME_PING;
knet_h->pingbuf->kf_node = htons(knet_h->node_id);
while (1) {
usleep(KNET_PING_TIMERES);
if (pthread_rwlock_rdlock(&knet_h->list_rwlock) != 0)
continue;
for (dst_host = knet_h->host_head; dst_host != NULL; dst_host = dst_host->next) {
for (link_idx = 0; link_idx < KNET_MAX_LINK; link_idx++) {
if (dst_host->link[link_idx].configured != 1)
continue;
_handle_check_each(knet_h, dst_host, &dst_host->link[link_idx]);
}
}
pthread_rwlock_unlock(&knet_h->list_rwlock);
}
return NULL;
}
static void *_handle_tap_to_links_thread(void *data)
{
knet_handle_t knet_h;
struct epoll_event events[KNET_MAX_EVENTS];
knet_h = (knet_handle_t) data;
/* preparing data buffer */
knet_h->tap_to_links_buf->kf_magic = htonl(KNET_FRAME_MAGIC);
knet_h->tap_to_links_buf->kf_version = KNET_FRAME_VERSION;
knet_h->tap_to_links_buf->kf_type = KNET_FRAME_DATA;
knet_h->tap_to_links_buf->kf_node = htons(knet_h->node_id);
while (1) {
if (epoll_wait(knet_h->tap_to_links_epollfd, events, KNET_MAX_EVENTS, -1) >= 1)
_handle_tap_to_links(knet_h);
}
return NULL;
}
static void *_handle_recv_from_links_thread(void *data)
{
int i, nev;
knet_handle_t knet_h = (knet_handle_t) data;
struct epoll_event events[KNET_MAX_EVENTS];
while (1) {
nev = epoll_wait(knet_h->recv_from_links_epollfd, events, KNET_MAX_EVENTS, -1);
for (i = 0; i < nev; i++) {
_handle_recv_from_links(knet_h, events[i].data.fd);
}
}
return NULL;
}
static void *_handle_dst_link_handler_thread(void *data)
{
knet_handle_t knet_h = (knet_handle_t) data;
struct epoll_event events[KNET_MAX_EVENTS];
while (1) {
if (epoll_wait(knet_h->dst_link_handler_epollfd, events, KNET_MAX_EVENTS, -1) >= 1)
_handle_dst_link_updates(knet_h);
}
return NULL;
}
diff --git a/libknet/host.c b/libknet/host.c
index ab6800eb..4d313bac 100644
--- a/libknet/host.c
+++ b/libknet/host.c
@@ -1,227 +1,211 @@
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#include "libknet-private.h"
int knet_host_get(knet_handle_t knet_h, uint16_t node_id, struct knet_host **host)
{
int ret;
if ((ret = pthread_rwlock_rdlock(&knet_h->list_rwlock)) != 0)
return ret;
*host = knet_h->host_index[node_id];
if (*host == NULL) {
pthread_rwlock_unlock(&knet_h->list_rwlock);
errno = ENOENT;
return ENOENT;
}
return 0;
}
int knet_host_acquire(knet_handle_t knet_h, struct knet_host **host)
{
int ret;
if ((ret = pthread_rwlock_rdlock(&knet_h->list_rwlock)) != 0)
return ret;
*host = knet_h->host_head;
return 0;
}
int knet_host_release(knet_handle_t knet_h, struct knet_host **host)
{
int ret;
*host = NULL;
if ((ret = pthread_rwlock_unlock(&knet_h->list_rwlock)) != 0)
return ret;
return 0;
}
int knet_host_foreach(knet_handle_t knet_h, knet_link_fn_t linkfun, struct knet_host_search *data)
{
int lockstatus;
struct knet_host *host;
lockstatus = pthread_rwlock_rdlock(&knet_h->list_rwlock);
if ((lockstatus != 0) && (lockstatus != EDEADLK))
return lockstatus;
for (host = knet_h->host_head; host != NULL; host = host->next) {
if ((linkfun(knet_h, host, data)) != KNET_HOST_FOREACH_NEXT)
break;
}
if (lockstatus == 0)
pthread_rwlock_unlock(&knet_h->list_rwlock);
return 0;
}
int knet_host_add(knet_handle_t knet_h, uint16_t node_id)
{
int link_idx, ret = 0; /* success */
struct knet_host *host;
if ((ret = pthread_rwlock_wrlock(&knet_h->list_rwlock)) != 0)
goto exit_clean;
if (knet_h->host_index[node_id] != NULL) {
errno = ret = EEXIST;
goto exit_unlock;
}
if ((host = malloc(sizeof(struct knet_host))) == NULL)
goto exit_unlock;
memset(host, 0, sizeof(struct knet_host));
host->node_id = node_id;
for (link_idx = 0; link_idx < KNET_MAX_LINK; link_idx++)
host->link[link_idx].link_id = link_idx;
/* adding new host to the index */
knet_h->host_index[node_id] = host;
if (!knet_h->host_head) {
knet_h->host_head = host;
knet_h->host_tail = host;
} else {
knet_h->host_tail->next = host;
knet_h->host_tail = host;
}
exit_unlock:
pthread_rwlock_unlock(&knet_h->list_rwlock);
exit_clean:
return ret;
}
int knet_host_remove(knet_handle_t knet_h, uint16_t node_id)
{
int ret = 0; /* success */
struct knet_host *host, *removed;
if ((ret = pthread_rwlock_wrlock(&knet_h->list_rwlock)) != 0)
goto exit_clean;
if (knet_h->host_index[node_id] == NULL) {
errno = ret = EINVAL;
goto exit_unlock;
}
removed = NULL;
/* removing host from list */
if (knet_h->host_head->node_id == node_id) {
removed = knet_h->host_head;
knet_h->host_head = removed->next;
} else {
for (host = knet_h->host_head; host->next != NULL; host = host->next) {
if (host->next->node_id == node_id) {
removed = host->next;
host->next = removed->next;
break;
}
}
}
if (removed != NULL) {
knet_h->host_index[node_id] = NULL;
free(removed);
}
exit_unlock:
pthread_rwlock_unlock(&knet_h->list_rwlock);
exit_clean:
return ret;
}
-int knet_host_dst_cache_update(knet_handle_t knet_h, uint16_t node_id)
-{
- int write_retry = 0;
-
-try_again:
- if (write(knet_h->pipefd[1], &node_id, sizeof(node_id)) != sizeof(node_id)) {
- if ((write_retry < 10) && ((errno = EAGAIN) || (errno = EWOULDBLOCK))) {
- write_retry++;
- goto try_again;
- } else {
- return -1;
- }
- }
- return 0;
-}
-
/* bcast = 0 -> unicast packet | 1 -> broadcast|mcast */
/* make this bcast/ucast aware */
int knet_should_deliver(struct knet_host *host, int bcast, seq_num_t seq_num)
{
size_t i, j; /* circular buffer indexes */
seq_num_t seq_dist;
char *dst_cbuf = NULL;
seq_num_t *dst_seq_num;
if (bcast) {
dst_cbuf = host->bcast_circular_buffer;
dst_seq_num = &host->bcast_seq_num_rx;
} else {
dst_cbuf = host->ucast_circular_buffer;
dst_seq_num = &host->ucast_seq_num_rx;
}
seq_dist = (seq_num < *dst_seq_num) ?
(SEQ_MAX - seq_num) + *dst_seq_num : *dst_seq_num - seq_num;
j = seq_num % KNET_CBUFFER_SIZE;
if (seq_dist < KNET_CBUFFER_SIZE) { /* seq num is in ring buffer */
return (dst_cbuf[j] == 0) ? 1 : 0;
} else if (seq_dist <= SEQ_MAX - KNET_CBUFFER_SIZE) {
memset(dst_cbuf, 0, KNET_CBUFFER_SIZE);
*dst_seq_num = seq_num;
}
/* cleaning up circular buffer */
i = (*dst_seq_num + 1) % KNET_CBUFFER_SIZE;
if (i > j) {
memset(dst_cbuf + i, 0, KNET_CBUFFER_SIZE - i);
memset(dst_cbuf, 0, j + 1);
} else {
memset(dst_cbuf + i, 0, j - i + 1);
}
*dst_seq_num = seq_num;
return 1;
}
void knet_has_been_delivered(struct knet_host *host, int bcast, seq_num_t seq_num)
{
if (bcast) {
host->bcast_circular_buffer[seq_num % KNET_CBUFFER_SIZE] = 1;
} else {
host->ucast_circular_buffer[seq_num % KNET_CBUFFER_SIZE] = 1;
}
return;
}
diff --git a/libknet/libknet.h b/libknet/libknet.h
index 7c2edade..9e399f6f 100644
--- a/libknet/libknet.h
+++ b/libknet/libknet.h
@@ -1,177 +1,177 @@
#ifndef __LIBKNET_H__
#define __LIBKNET_H__
#include <stdint.h>
#include <netinet/in.h>
typedef struct knet_handle *knet_handle_t;
#define KNET_RING_DEFPORT 50000
#define KNET_RING_RCVBUFF 8388608
#define KNET_MAX_HOST 65536
#define KNET_MAX_LINK 8
#define KNET_MAX_HOST_LEN 64
#define KNET_CBUFFER_SIZE 4096
/*
typedef uint64_t seq_num_t;
#define SEQ_MAX UINT64_MAX
*/
typedef uint16_t seq_num_t;
#define SEQ_MAX UINT16_MAX
struct knet_link {
uint8_t link_id;
int sock;
char ipaddr[KNET_MAX_HOST_LEN];
char port[6];
struct sockaddr_storage address;
unsigned int configured:1; /* link is configured and ready to be used */
unsigned int connected:1; /* link is enabled for data */
uint8_t priority; /* higher priority == preferred for A/P */
unsigned long long latency; /* average latency computed by fix/exp */
unsigned int latency_exp;
unsigned int latency_fix;
unsigned long long ping_interval;
unsigned long long pong_timeout;
struct timespec ping_last;
struct timespec pong_last;
};
#define KNET_LINK_POLICY_PASSIVE 0
#define KNET_LINK_POLICY_ACTIVE 1
#define KNET_LINK_POLICY_RR 2
struct knet_host {
uint16_t node_id;
char name[KNET_MAX_HOST_LEN];
char bcast_circular_buffer[KNET_CBUFFER_SIZE];
seq_num_t bcast_seq_num_rx;
char ucast_circular_buffer[KNET_CBUFFER_SIZE];
seq_num_t ucast_seq_num_tx;
seq_num_t ucast_seq_num_rx;
struct knet_listener *listener;
struct knet_link link[KNET_MAX_LINK];
uint8_t active_link_entries;
uint8_t active_links[KNET_MAX_LINK];
uint8_t link_handler_policy;
struct knet_host *next;
};
struct knet_listener {
int sock;
char ipaddr[KNET_MAX_HOST_LEN];
char port[6];
struct sockaddr_storage address;
struct knet_listener *next;
};
union knet_frame_data {
struct {
seq_num_t kfd_seq_num;
uint8_t kfd_data[0];
} data;
struct {
uint8_t kfd_link;
struct timespec kfd_time;
} ping;
} __attribute__((packed));
struct knet_frame {
uint32_t kf_magic;
uint8_t kf_version;
uint8_t kf_type;
uint16_t kf_node;
union knet_frame_data kf_payload;
} __attribute__((packed));
#define kf_seq_num kf_payload.data.kfd_seq_num
#define kf_data kf_payload.data.kfd_data
#define kf_link kf_payload.ping.kfd_link
#define kf_time kf_payload.ping.kfd_time
#define KNET_FRAME_SIZE (sizeof(struct knet_frame) - sizeof(union knet_frame_data))
#define KNET_FRAME_MAGIC 0x12344321
#define KNET_FRAME_VERSION 0x01
#define KNET_FRAME_DATA 0x00
#define KNET_FRAME_PING 0x81
#define KNET_FRAME_PONG 0x82
#define KNET_FRAME_PMSK 0x80 /* ping/pong packet mask */
#define KNET_MIN_KEY_LEN 1024
#define KNET_MAX_KEY_LEN 4096
#define KNET_DST_FILTER_DISABLE 0 /* pckt goes everywhere */
#define KNET_DST_FILTER_ENABLE 1 /* pckt goes via dst_host_filter,
see knet_ether_filter for example */
/*
* dst_host_filter_fn should return
* -1 on error, pkt is discarded
* 0 all good, send pkt to dst_host_ids and there are dst_host_ids_entries in buffer ready
* 1 send it to all hosts. contents of dst_host_ids and dst_host_ids_entries is ignored.
*/
struct knet_handle_cfg {
int fd;
uint16_t node_id;
uint8_t dst_host_filter;
int (*dst_host_filter_fn) (
const unsigned char *outdata,
ssize_t outdata_len,
uint16_t src_node_id,
uint16_t *dst_host_ids,
size_t *dst_host_ids_entries);
};
int ether_host_filter_fn (const unsigned char *outdata,
ssize_t outdata_len,
uint16_t src_node_id,
uint16_t *dst_host_ids,
size_t *dst_host_ids_entries);
knet_handle_t knet_handle_new(const struct knet_handle_cfg *knet_handle_cfg);
void knet_handle_setfwd(knet_handle_t knet_h, int enabled);
int knet_handle_free(knet_handle_t knet_h);
struct knet_handle_crypto_cfg {
char crypto_model[16];
char crypto_cipher_type[16];
char crypto_hash_type[16];
unsigned char private_key[KNET_MAX_KEY_LEN];
unsigned int private_key_len;
};
int knet_handle_crypto(knet_handle_t knet_h, struct knet_handle_crypto_cfg *knet_handle_crypto_cfg);
int knet_host_add(knet_handle_t knet_h, uint16_t node_id);
int knet_host_acquire(knet_handle_t knet_h, struct knet_host **host);
int knet_host_get(knet_handle_t knet_h, uint16_t node_id, struct knet_host **host);
int knet_host_release(knet_handle_t knet_h, struct knet_host **host);
int knet_host_remove(knet_handle_t knet_h, uint16_t node_id);
-int knet_host_dst_cache_update(knet_handle_t knet_h, uint16_t node_id);
+int knet_link_enable(knet_handle_t knet_h, uint16_t node_id, struct knet_link *lnk, int configured);
void knet_link_timeout(struct knet_link *lnk, time_t interval, time_t timeout, int precision);
#define KNET_HOST_FOREACH_NEXT 0 /* next host */
#define KNET_HOST_FOREACH_FOUND 1 /* host found, exit loop */
struct knet_host_search {
int param1; /* user parameter 1 */
void *data1; /* user data pointer 1 */
void *data2; /* user data pointer 2 */
int retval; /* search return value */
};
typedef int (*knet_link_fn_t)(knet_handle_t knet_h, struct knet_host *host, struct knet_host_search *data);
int knet_host_foreach(knet_handle_t knet_h, knet_link_fn_t linkfun, struct knet_host_search *data);
int knet_listener_acquire(knet_handle_t knet_h, struct knet_listener **head, int writelock);
int knet_listener_release(knet_handle_t knet_h);
int knet_listener_add(knet_handle_t knet_h, struct knet_listener *listener);
int knet_listener_remove(knet_handle_t knet_h, struct knet_listener *listener);
#endif
diff --git a/tests/listener_test.c b/tests/listener_test.c
index 7abc576c..74fbaab1 100644
--- a/tests/listener_test.c
+++ b/tests/listener_test.c
@@ -1,139 +1,139 @@
#include "config.h"
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include "libknet-private.h"
#define KNET_TEST_PORT 50000
static knet_handle_t knet_h;
struct knet_listener *listener;
static void test_add_listener(void)
{
struct sockaddr_in *address;
listener = malloc(sizeof(struct knet_listener));
if (listener == NULL) {
printf("Unable to create listener\n");
exit(EXIT_FAILURE);
}
memset(listener, 0, sizeof(struct knet_listener));
address = (struct sockaddr_in *) &listener->address;
address->sin_family = AF_INET;
address->sin_port = htons(KNET_TEST_PORT);
address->sin_addr.s_addr = INADDR_ANY;
if (knet_listener_add(knet_h, listener) != 0) {
printf("Unable to add listener\n");
exit(EXIT_FAILURE);
}
}
static void test_add_host(void)
{
struct knet_host *host;
if (knet_host_add(knet_h, 1) != 0) {
printf("Unable to add host to knet_handle\n");
exit(EXIT_FAILURE);
}
knet_host_get(knet_h, 1, &host);
host->link[0].sock = listener->sock;
- host->link[0].configured = 1;
+ knet_link_enable(knet_h, host->node_id, &host->link[0], 1);
knet_host_release(knet_h, &host);
}
int main(int argc, char *argv[])
{
int err, sock;
struct epoll_event ev;
struct knet_handle_cfg knet_handle_cfg;
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
printf("Unable to create new socket\n");
exit(EXIT_FAILURE);
}
memset(&knet_handle_cfg, 0, sizeof(struct knet_handle_cfg));
knet_handle_cfg.fd = sock;
knet_handle_cfg.node_id = 1;
if ((knet_h = knet_handle_new(&knet_handle_cfg)) == NULL) {
printf("Unable to create new knet_handle_t\n");
exit(EXIT_FAILURE);
}
printf("Adding listener to handle\n");
test_add_listener();
memset(&ev, 0, sizeof(struct epoll_event));
/* don't try this at home :) */
err = epoll_ctl(knet_h->recv_from_links_epollfd, EPOLL_CTL_ADD, listener->sock, &ev);
if (err != -1) {
printf("Listener file descriptor not found in epollfd\n");
exit(EXIT_FAILURE);
}
printf("Listener file descriptor was added to epollfd\n");
printf("Adding host to handle\n");
test_add_host();
err = knet_listener_remove(knet_h, listener);
if (err != -EBUSY) {
printf("Listener socket should be in use\n");
exit(EXIT_FAILURE);
}
printf("Unable to remove listener with active links\n");
printf("Removing host from handle\n");
err = knet_host_remove(knet_h, 1);
if (err != 0) {
printf("Unable to remove host from knet_handle\n");
exit(EXIT_FAILURE);
}
printf("Removing listener\n");
err = knet_listener_remove(knet_h, listener);
if (err != 0) {
printf("Unable to remove listener from knet_handle\n");
exit(EXIT_FAILURE);
}
/* don't try this at home :) */
err = epoll_ctl(knet_h->recv_from_links_epollfd, EPOLL_CTL_DEL, listener->sock, &ev);
if (err != -1) {
printf("Listener file was present in epollfd\n");
exit(EXIT_FAILURE);
}
printf("Listener file descriptor was removed from epollfd\n");
if (knet_handle_free(knet_h) != 0) {
printf("Unable to free knet_handle\n");
exit(EXIT_FAILURE);
}
return 0;
}
diff --git a/tests/ping_test.c b/tests/ping_test.c
index bb957cd3..cce54361 100644
--- a/tests/ping_test.c
+++ b/tests/ping_test.c
@@ -1,268 +1,268 @@
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <alloca.h>
#include <signal.h>
#include <arpa/inet.h>
#include "libknet.h"
static int knet_sock[2];
static knet_handle_t knet_h;
static struct knet_handle_cfg knet_handle_cfg;
static struct knet_handle_crypto_cfg knet_handle_crypto_cfg;
static in_port_t tok_inport(char *str)
{
int value = atoi(str);
if ((value < 0) || (value > UINT16_MAX))
return 0;
return (in_port_t) value;
}
static int tok_inaddrport(char *str, struct sockaddr_in *addr)
{
char *strhost, *strport, *tmp = NULL;
strhost = strtok_r(str, ":", &tmp);
strport = strtok_r(NULL, ":", &tmp);
if (strport == NULL)
addr->sin_port = htons(KNET_RING_DEFPORT);
else
addr->sin_port = htons(tok_inport(strport));
return inet_aton(strhost, &addr->sin_addr);
}
static void print_usage(char *name)
{
printf("usage: %s <localip>[:<port>] <remoteip>[:port] [...]\n", name);
printf("example: %s 0.0.0.0 192.168.0.2\n", name);
printf("example: %s 127.0.0.1:50000 127.0.0.1:50000 crypto:aes256,sha1\n", name);
}
static int set_crypto(int argc, char *argv[])
{
int i, found = 0;
for (i = 0; i < argc; i++) {
if (!strncmp(argv[i], "crypto", 6)) {
found = 1;
break;
}
}
if (found) {
char *tmp = NULL;
strtok_r(argv[i], ":", &tmp);
strncpy(knet_handle_crypto_cfg.crypto_model,
strtok_r(NULL, ",", &tmp),
sizeof(knet_handle_crypto_cfg.crypto_model) - 1);
strncpy(knet_handle_crypto_cfg.crypto_cipher_type,
strtok_r(NULL, ",", &tmp),
sizeof(knet_handle_crypto_cfg.crypto_cipher_type) - 1);
strncpy(knet_handle_crypto_cfg.crypto_hash_type,
strtok_r(NULL, ",", &tmp),
sizeof(knet_handle_crypto_cfg.crypto_hash_type) - 1);
printf("Setting up encryption: model: %s crypto: %s hmac: %s\n",
knet_handle_crypto_cfg.crypto_model,
knet_handle_crypto_cfg.crypto_cipher_type,
knet_handle_crypto_cfg.crypto_hash_type);
return 1;
}
return 0;
}
static void argv_to_hosts(int argc, char *argv[])
{
int err, i;
struct sockaddr_in *address;
struct knet_host *host;
struct knet_listener *listener;
listener = malloc(sizeof(struct knet_listener));
if (listener == NULL) {
printf("Unable to create listener\n");
exit(EXIT_FAILURE);
}
memset(listener, 0, sizeof(struct knet_listener));
address = (struct sockaddr_in *) &listener->address;
address->sin_family = AF_INET;
err = tok_inaddrport(argv[1], address);
if (err < 0) {
printf("Unable to convert ip address: %s\n", argv[1]);
exit(EXIT_FAILURE);
}
err = knet_listener_add(knet_h, listener);
if (err != 0) {
printf("Unable to start knet listener\n");
exit(EXIT_FAILURE);
}
for (i = 2; i < argc; i++) {
if (!strncmp(argv[i], "crypto", 6))
continue;
if (knet_host_add(knet_h, i - 1) != 0) {
printf("Unable to add new knet_host\n");
exit(EXIT_FAILURE);
}
knet_host_get(knet_h, i - 1, &host);
host->link[0].sock = listener->sock;
host->link[0].address.ss_family = AF_INET;
knet_link_timeout(&host->link[0], 1000, 5000, 2048);
- host->link[0].configured = 1;
+ knet_link_enable(knet_h, host->node_id, &host->link[0], 1);
err = tok_inaddrport(argv[i],
(struct sockaddr_in *) &host->link[0].address);
if (err < 0) {
printf("Unable to convert ip address: %s", argv[i]);
exit(EXIT_FAILURE);
}
knet_host_release(knet_h, &host);
}
}
/* Testing the latency/timeout:
* # tc qdisc add dev lo root handle 1:0 netem delay 1s limit 1000
* # tc -d qdisc show dev lo
* # tc qdisc del dev lo root
*/
static int print_link(knet_handle_t khandle, struct knet_host *host, struct knet_host_search *data)
{
int i;
for (i = 0; i < KNET_MAX_LINK; i++) {
if (host->link[i].configured != 1) continue;
printf("host %p, link %p latency is %llu microsecs, status: %s\n",
host, &host->link[i], host->link[i].latency,
(host->link[i].connected == 0) ? "disconnected" : "connected");
}
return KNET_HOST_FOREACH_NEXT;
}
static void sigint_handler(int signum)
{
int err;
printf("Cleaning up...\n");
if (knet_h != NULL) {
err = knet_handle_free(knet_h);
if (err != 0) {
printf("Unable to cleanup before exit\n");
exit(EXIT_FAILURE);
}
}
exit(EXIT_SUCCESS);
}
int main(int argc, char *argv[])
{
char buff[1024];
size_t len;
fd_set rfds;
struct timeval tv;
struct knet_host_search print_search;
if (argc < 3) {
print_usage(argv[0]);
exit(EXIT_FAILURE);
}
if (socketpair(AF_UNIX, SOCK_STREAM, IPPROTO_IP, knet_sock) != 0) {
printf("Unable to create socket\n");
exit(EXIT_FAILURE);
}
knet_h = NULL;
if (signal(SIGINT, sigint_handler) == SIG_ERR) {
printf("Unable to configure SIGINT handler\n");
exit(EXIT_FAILURE);
}
memset(&knet_handle_cfg, 0, sizeof(struct knet_handle_cfg));
knet_handle_cfg.fd = knet_sock[0];
knet_handle_cfg.node_id = 1;
if ((knet_h = knet_handle_new(&knet_handle_cfg)) == NULL) {
printf("Unable to create new knet_handle_t\n");
exit(EXIT_FAILURE);
}
if (set_crypto(argc, argv)) {
memset(knet_handle_crypto_cfg.private_key, 0, KNET_MAX_KEY_LEN);
knet_handle_crypto_cfg.private_key_len = KNET_MAX_KEY_LEN;
if (knet_handle_crypto(knet_h, &knet_handle_crypto_cfg)) {
printf("Unable to init crypto\n");
exit(EXIT_FAILURE);
}
} else {
printf("Crypto not activated\n");
}
argv_to_hosts(argc, argv);
knet_handle_setfwd(knet_h, 1);
while (1) {
ssize_t wlen;
knet_host_foreach(knet_h, print_link, &print_search);
printf("Sending 'Hello World!' frame\n");
wlen = write(knet_sock[1], "Hello World!", 13);
if (wlen != 13)
printf("Unable to send Hello World! to socket!\n");
tv.tv_sec = 5;
tv.tv_usec = 0;
select_loop:
FD_ZERO(&rfds);
FD_SET(knet_sock[1], &rfds);
len = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
/* uncomment this to replicate the one-message problem */
/* usleep(500000); */
if (len < 0) {
printf("Unable select over knet_handle_t\n");
exit(EXIT_FAILURE);
} else if (FD_ISSET(knet_sock[1], &rfds)) {
len = read(knet_sock[1], buff, sizeof(buff));
printf("Received data (%zu bytes): '%s'\n", len, buff);
}
if ((tv.tv_sec > 0) || (tv.tv_usec > 0))
goto select_loop;
}
/* FIXME: allocated hosts should be free'd */
return 0;
}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Feb 26, 11:23 AM (22 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1465291
Default Alt Text
(88 KB)

Event Timeline