Page MenuHomeClusterLabs Projects

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/kronosnetd/cfg.h b/kronosnetd/cfg.h
index d39f7da0..e57ddc20 100644
--- a/kronosnetd/cfg.h
+++ b/kronosnetd/cfg.h
@@ -1,55 +1,55 @@
/*
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
*
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
* Federico Simoncelli <fsimon@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#ifndef __CFG_H__
#define __CFG_H__
#include <stdint.h>
#include <net/if.h>
#include "libtap.h"
#include "libknet.h"
#define KNET_RING_DEFPORT 50000
struct knet_cfg_eth {
tap_t tap;
int auto_mtu;
- uint16_t node_id;
+ uint8_t node_id;
};
struct knet_cfg_ring {
knet_handle_t knet_h;
int data_mtu;
int base_port;
};
struct knet_cfg {
struct knet_cfg_eth cfg_eth;
struct knet_cfg_ring cfg_ring;
int active;
struct knet_handle_crypto_cfg knet_handle_crypto_cfg;
struct knet_cfg *next;
};
struct knet_cfg_top {
char *conffile;
char *logfile;
char *vty_ipv4;
char *vty_ipv6;
char *vty_port;
struct knet_cfg *knet_cfg;
};
struct knet_cfg *knet_get_iface(const char *name, const int create);
void knet_destroy_iface(struct knet_cfg *knet_iface);
extern struct knet_cfg_top knet_cfg_head;
#endif
diff --git a/kronosnetd/etherfilter.c b/kronosnetd/etherfilter.c
index de6353c1..d31b8e23 100644
--- a/kronosnetd/etherfilter.c
+++ b/kronosnetd/etherfilter.c
@@ -1,64 +1,64 @@
/*
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
*
* Author: Fabio M. Di Nitto <fabbione@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#include "config.h"
#include <arpa/inet.h>
#include <netinet/ether.h>
#include <string.h>
#include "etherfilter.h"
/*
* stole from linux kernel/include/linux/etherdevice.h
*/
static inline int is_zero_ether_addr(const uint8_t *addr)
{
return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]);
}
static inline int is_multicast_ether_addr(const uint8_t *addr)
{
return 0x01 & addr[0];
}
static inline int is_broadcast_ether_addr(const uint8_t *addr)
{
return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == 0xff;
}
int ether_host_filter_fn (void *private_data,
const unsigned char *outdata,
ssize_t outdata_len,
uint8_t tx_rx,
- uint16_t this_host_id,
- uint16_t src_host_id,
+ uint8_t this_host_id,
+ uint8_t src_host_id,
int8_t *channel,
- uint16_t *dst_host_ids,
+ uint8_t *dst_host_ids,
size_t *dst_host_ids_entries)
{
struct ether_header *eth_h = (struct ether_header *)outdata;
uint8_t *dst_mac = (uint8_t *)eth_h->ether_dhost;
uint16_t dst_host_id;
if (is_zero_ether_addr(dst_mac))
return -1;
if (is_multicast_ether_addr(dst_mac) ||
is_broadcast_ether_addr(dst_mac)) {
return 1;
}
memmove(&dst_host_id, &dst_mac[4], 2);
dst_host_ids[0] = ntohs(dst_host_id);
*dst_host_ids_entries = 1;
return 0;
}
diff --git a/kronosnetd/etherfilter.h b/kronosnetd/etherfilter.h
index e12f20e7..1bb5b0b0 100644
--- a/kronosnetd/etherfilter.h
+++ b/kronosnetd/etherfilter.h
@@ -1,24 +1,24 @@
/*
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
*
* Author: Fabio M. Di Nitto <fabbione@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#ifndef __ETHERFILTER_H__
#define __ETHERFILTER_H__
#include <stdint.h>
int ether_host_filter_fn (void *private_data,
const unsigned char *outdata,
ssize_t outdata_len,
uint8_t tx_rx,
- uint16_t this_host_id,
- uint16_t src_host_id,
+ uint8_t this_host_id,
+ uint8_t src_host_id,
int8_t *channel,
- uint16_t *dst_host_ids,
+ uint8_t *dst_host_ids,
size_t *dst_host_ids_entries);
#endif
diff --git a/kronosnetd/vty.h b/kronosnetd/vty.h
index 25390c9d..9fb7ad6d 100644
--- a/kronosnetd/vty.h
+++ b/kronosnetd/vty.h
@@ -1,73 +1,73 @@
/*
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
*
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
* Federico Simoncelli <fsimon@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#ifndef __VTY_H__
#define __VTY_H__
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#define KNET_VTY_DEFAULT_PORT 50000
#define KNET_VTY_DEFAULT_MAX_CONN 4
#define KNET_VTY_TOTAL_MAX_CONN 16
#define KNET_VTY_CLI_TIMEOUT 300
#define KNET_VTY_MAX_LINE 512
#define KNET_VTY_MAX_HIST 50
struct knet_vty_global_conf {
int idle_timeout;
};
struct knet_vty {
pthread_t vty_thread; /* thread struct for this vty */
struct sockaddr_storage src_sa; /* source IP */
socklen_t src_sa_len; /* sa len */
char ip[128]; /* ip addr of source */
char username[64]; /* username */
char line[KNET_VTY_MAX_LINE]; /* input line */
char *history[KNET_VTY_MAX_HIST]; /* history */
int history_idx; /* index to history */
int history_pos; /* position in the history */
int insert_mode; /* add or insert */
int line_idx; /* index on the input line */
int cursor_pos; /* position of the cursor in the line */
int escape; /* escape status */
int escape_code; /* escape code buffer */
int user_can_enable;/* user is in group kronosnetadm */
int vty_sock; /* tcp socket for this vty */
int conn_num; /* vty number */
int active; /* vty is active */
int got_epipe; /* vty_sock has been closed */
int idle; /* idle time */
int idle_timeout; /* in seconds or 0 to disable automatic logout */
int node; /* node number of the menus */
int prevnode; /* node number of the menus (used by VTY node) */
void *param; /* pointer to cmd param */
int paramoffset; /* required if param is set */
int logfd; /* fd to pass to iface create */
int loglevel; /* loglevel (debug, etc) */
void *iface; /* pointer to iface we are working on */
- uint16_t host_id; /* peer/host we are working on */
+ uint8_t host_id; /* peer/host we are working on */
uint8_t link_id; /* link id we are working on */
int filemode; /* tell print_conf to add or not carriage return */
struct knet_vty_global_conf *vty_global_conf; /* pointer to vty global config */
};
extern pthread_mutex_t knet_vty_mutex;
extern int knet_vty_config;
extern struct knet_vty knet_vtys[KNET_VTY_TOTAL_MAX_CONN];
int knet_vty_main_loop(int debug);
#endif
diff --git a/kronosnetd/vty_cli_cmds.c b/kronosnetd/vty_cli_cmds.c
index 7e873c6f..ec037331 100644
--- a/kronosnetd/vty_cli_cmds.c
+++ b/kronosnetd/vty_cli_cmds.c
@@ -1,2185 +1,2185 @@
/*
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
*
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
* Federico Simoncelli <fsimon@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#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 "etherfilter.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
#define CMDS_PARAM_POLICY 13
#define CMDS_PARAM_LINK_ID 14
#define CMDS_PARAM_LINK_PRI 15
#define CMDS_PARAM_LINK_KEEPAL 16
#define CMDS_PARAM_LINK_HOLDTI 17
#define CMDS_PARAM_LINK_PONG 18
#define CMDS_PARAM_VTY_TIMEOUT 19
#define CMDS_PARAM_PMTU_FREQ 20
#define CMDS_PARAM_LINK_TRANSP 21
/*
* 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 < 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));
memmove(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);
memmove(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;
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
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_PMTU_FREQ:
tmp = param_to_int(param, paramlen);
if ((tmp < 5) || (tmp > 600)) {
knet_vty_write(vty, "PMTUd frequency should be a value between 5 and 600%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;
case CMDS_PARAM_POLICY:
param_to_str(buf, KNET_VTY_MAX_LINE, param, paramlen);
if (!strncmp("passive", buf, 7))
break;
if (!strncmp("active", buf, 6))
break;
if (!strncmp("round-robin", buf, 11))
break;
knet_vty_write(vty, "unknown switching policy: %s. Supported passive/active/round-robin%s", param, telnet_newline);
err = -1;
break;
case CMDS_PARAM_LINK_ID:
tmp = param_to_int(param, paramlen);
if ((tmp < 0) || (tmp > 7)) {
knet_vty_write(vty, "link id should be a value between 0 and 7%s", telnet_newline);
err = -1;
}
break;
case CMDS_PARAM_LINK_TRANSP:
param_to_str(buf, KNET_VTY_MAX_LINE, param, paramlen);
if (knet_handle_get_transport_id_by_name(knet_iface->cfg_ring.knet_h, buf) == KNET_MAX_TRANSPORTS) {
knet_vty_write(vty, "link transport is invalid%s", telnet_newline);
err = -1;
}
break;
case CMDS_PARAM_LINK_PRI:
tmp = param_to_int(param, paramlen);
if ((tmp < 0) || (tmp > 255)) {
knet_vty_write(vty, "link priority should be a value between 0 and 256%s", telnet_newline);
err = -1;
}
break;
case CMDS_PARAM_LINK_KEEPAL:
tmp = param_to_int(param, paramlen);
if ((tmp <= 0) || (tmp > 60000)) {
knet_vty_write(vty, "link keepalive should be a value between 0 and 60000 (milliseconds). Default: 1000%s", telnet_newline);
err = -1;
}
break;
case CMDS_PARAM_LINK_HOLDTI:
tmp = param_to_int(param, paramlen);
if ((tmp <= 0) || (tmp > 60000)) {
knet_vty_write(vty, "link holdtimer should be a value between 0 and 60000 (milliseconds). Default: 5000%s", telnet_newline);
err = -1;
}
break;
case CMDS_PARAM_LINK_PONG:
tmp = param_to_int(param, paramlen);
if (tmp < 1) {
knet_vty_write(vty, "pong_count must be a value between 0 and 255%s", telnet_newline);
err = -1;
}
break;
case CMDS_PARAM_VTY_TIMEOUT:
tmp = param_to_int(param, paramlen);
if ((tmp < 0) || (tmp > 3600)) {
knet_vty_write(vty, "vty logout timeout should be a value between 0 (disabled) and 3600 seconds. Default: %d%s", KNET_VTY_CLI_TIMEOUT, telnet_newline);
}
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_PMTU_FREQ:
knet_vty_write(vty, "PMTUd frequency - a value in seconds between 5 and 600 (default: 5)%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;
case CMDS_PARAM_POLICY:
knet_vty_write(vty, "POLICY - define packets switching policy: passive/active/round-robin%s", telnet_newline);
break;
case CMDS_PARAM_LINK_ID:
knet_vty_write(vty, "LINKID - specify the link identification number (0-7)%s", telnet_newline);
break;
case CMDS_PARAM_LINK_TRANSP:
knet_vty_write(vty, "TRANSPORT - specify the link transport protocol (UDP/SCTP/..)%s", telnet_newline);
break;
case CMDS_PARAM_LINK_PRI:
knet_vty_write(vty, "PRIORITY - specify the link priority for passive switching (0 to 255, default is 0). The higher value is preferred over lower value%s", telnet_newline);
break;
case CMDS_PARAM_LINK_KEEPAL:
knet_vty_write(vty, "KEEPALIVE - specify the keepalive interval for this link (0 to 60000 milliseconds, default is 1000).%s", telnet_newline);
break;
case CMDS_PARAM_LINK_HOLDTI:
knet_vty_write(vty, "HOLDTIME - specify how much time has to pass without connection before a link is considered dead (0 to 60000 milliseconds, default is 5000).%s", telnet_newline);
break;
case CMDS_PARAM_VTY_TIMEOUT:
knet_vty_write(vty, "VTY_TIMEOUT - specify the number of seconds before a session is automatically closed.%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);
memmove(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_status(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_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);
static int knet_cmd_pmtufreq(struct knet_vty *vty);
static int knet_cmd_no_pmtufreq(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);
static int knet_cmd_switch_policy(struct knet_vty *vty);
/* link node */
static int knet_cmd_link_pri(struct knet_vty *vty);
static int knet_cmd_link_pong(struct knet_vty *vty);
static int knet_cmd_link_timer(struct knet_vty *vty);
/* vty node */
static int knet_cmd_vty(struct knet_vty *vty);
static int knet_cmd_vty_timeout(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 },
{ "status", "display current network status", NULL, knet_cmd_status },
{ "vty", "enter vty configuration mode", NULL, knet_cmd_vty },
{ "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_IP_PORT },
{ 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 },
{ "status", "display current network status", NULL, knet_cmd_status },
{ "vty", "enter vty configuration mode", NULL, knet_cmd_vty },
{ "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 },
{ "pmtudfreq", "revert to default PMTUd frequency (default: 5)", NULL, knet_cmd_no_pmtufreq },
{ "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 pmtu_params[] = {
{ CMDS_PARAM_PMTU_FREQ },
{ 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[] = {
{ "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 (default: auto)", mtu_params, knet_cmd_mtu },
{ "pmtudfreq", "PMTUd frequency (default: 5)", pmtu_params, knet_cmd_pmtufreq },
{ "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 },
{ "status", "display current network status", NULL, knet_cmd_status },
{ "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 nolink_params[] = {
{ CMDS_PARAM_LINK_ID },
{ CMDS_PARAM_NOMORE },
};
vty_param_t link_params[] = {
{ CMDS_PARAM_LINK_ID },
{ CMDS_PARAM_IP },
{ CMDS_PARAM_IP },
{ CMDS_PARAM_LINK_TRANSP },
{ CMDS_PARAM_NOMORE },
};
vty_param_t switch_params[] = {
{ CMDS_PARAM_POLICY },
{ CMDS_PARAM_NOMORE },
};
vty_node_cmds_t no_peer_cmds[] = {
{ "link", "remove peer endpoint", nolink_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 },
{ "status", "display current network status", NULL, knet_cmd_status },
{ "switch-policy", "configure switching policy engine", switch_params, knet_cmd_switch_policy },
{ "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_param_t link_pri_params[] = {
{ CMDS_PARAM_LINK_PRI },
{ CMDS_PARAM_NOMORE },
};
vty_param_t link_timer_params[] = {
{ CMDS_PARAM_LINK_KEEPAL },
{ CMDS_PARAM_LINK_HOLDTI },
{ CMDS_PARAM_NOMORE },
};
vty_param_t pong_count_params[] = {
{ CMDS_PARAM_LINK_PONG },
{ CMDS_PARAM_NOMORE },
};
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 },
{ "pong_count", "set number of pongs to be received before a link is considered alive", pong_count_params, knet_cmd_link_pong },
{ "priority", "set priority of this link for passive switching", link_pri_params, knet_cmd_link_pri },
{ "show", "show running config", NULL, knet_cmd_show_conf },
{ "status", "display current network status", NULL, knet_cmd_status },
{ "timers", "set link keepalive and holdtime", link_timer_params, knet_cmd_link_timer },
{ "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 },
};
vty_param_t vty_timeout_params[] = {
{ CMDS_PARAM_VTY_TIMEOUT },
{ CMDS_PARAM_NOMORE },
};
vty_node_cmds_t vty_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 },
{ "show", "show running config", NULL, knet_cmd_show_conf },
{ "status", "display current network status", NULL, knet_cmd_status },
{ "timeout", "set number of seconds before session is automatically closed", vty_timeout_params, knet_cmd_vty_timeout },
{ "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 },
{ NODE_VTY, "vty", vty_cmds, NULL },
{ -1, NULL, NULL },
};
/* command execution */
/* vty */
static int knet_cmd_vty_timeout(struct knet_vty *vty)
{
int paramlen = 0, paramoffset = 0, timeout;
char *param = NULL;
get_param(vty, 1, &param, &paramlen, &paramoffset);
timeout = param_to_int(param, paramlen);
if ((vty->filemode) || (vty->prevnode == NODE_CONFIG)) {
vty->vty_global_conf->idle_timeout = timeout;
}
vty->idle_timeout = timeout;
return 0;
}
static int knet_cmd_vty(struct knet_vty *vty)
{
vty->prevnode = vty->node;
vty->node = NODE_VTY;
return 0;
}
/* links */
static int knet_cmd_link_pong(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
int paramlen = 0, paramoffset = 0;
char *param = NULL;
uint8_t pong_count;
get_param(vty, 1, &param, &paramlen, &paramoffset);
pong_count = param_to_int(param, paramlen);
knet_link_set_pong_count(knet_iface->cfg_ring.knet_h, vty->host_id, vty->link_id, pong_count);
return 0;
}
static int knet_cmd_link_timer(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
int paramlen = 0, paramoffset = 0;
char *param = NULL;
time_t keepalive, holdtime;
get_param(vty, 1, &param, &paramlen, &paramoffset);
keepalive = param_to_int(param, paramlen);
get_param(vty, 2, &param, &paramlen, &paramoffset);
holdtime = param_to_int(param, paramlen);
knet_link_set_ping_timers(knet_iface->cfg_ring.knet_h, vty->host_id, vty->link_id, keepalive, holdtime, 2048);
return 0;
}
static int knet_cmd_link_pri(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
int paramlen = 0, paramoffset = 0;
char *param = NULL;
uint8_t priority;
get_param(vty, 1, &param, &paramlen, &paramoffset);
priority = param_to_int(param, paramlen);
if (knet_link_set_priority(knet_iface->cfg_ring.knet_h, vty->host_id, vty->link_id, priority)) {
knet_vty_write(vty, "Error: unable to update link priority%s", telnet_newline);
return -1;
}
return 0;
}
static int knet_cmd_no_link(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
struct knet_link_status status;
int paramlen = 0, paramoffset = 0;
char *param = NULL;
get_param(vty, 1, &param, &paramlen, &paramoffset);
vty->link_id = param_to_int(param, paramlen);
knet_link_get_status(knet_iface->cfg_ring.knet_h, vty->host_id, vty->link_id, &status);
if (status.enabled) {
if (knet_link_set_enable(knet_iface->cfg_ring.knet_h, vty->host_id, vty->link_id, 0)) {
knet_vty_write(vty, "Error: unable to update switching cache%s", telnet_newline);
return -1;
}
knet_link_clear_config(knet_iface->cfg_ring.knet_h, vty->host_id, vty->link_id);
}
return 0;
}
static int knet_cmd_link(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
struct knet_link_status status;
int paramlen = 0, paramoffset = 0, err = 0;
char *param = NULL;
char src_ipaddr[KNET_MAX_HOST_LEN], src_port[KNET_MAX_PORT_LEN], dst_ipaddr[KNET_MAX_HOST_LEN], dst_port[KNET_MAX_PORT_LEN];
struct sockaddr_storage src_addr;
struct sockaddr_storage dst_addr;
struct sockaddr_storage *dst = NULL;
char transport[10];
uint8_t transport_id;
get_param(vty, 1, &param, &paramlen, &paramoffset);
vty->link_id = param_to_int(param, paramlen);
get_param(vty, 2, &param, &paramlen, &paramoffset);
param_to_str(src_ipaddr, KNET_MAX_HOST_LEN, param, paramlen);
memset(src_port, 0, sizeof(src_port));
snprintf(src_port, KNET_MAX_PORT_LEN, "%d", knet_iface->cfg_ring.base_port + vty->host_id);
get_param(vty, 3, &param, &paramlen, &paramoffset);
param_to_str(dst_ipaddr, KNET_MAX_HOST_LEN, param, paramlen);
memset(dst_port, 0, sizeof(dst_port));
snprintf(dst_port, KNET_MAX_PORT_LEN, "%d", knet_iface->cfg_ring.base_port + knet_iface->cfg_eth.node_id);
get_param(vty, 4, &param, &paramlen, &paramoffset);
param_to_str(transport, sizeof(transport), param, paramlen);
transport_id = knet_handle_get_transport_id_by_name(knet_iface->cfg_ring.knet_h, transport);
knet_link_get_status(knet_iface->cfg_ring.knet_h, vty->host_id, vty->link_id, &status);
if (!status.enabled) {
if (knet_strtoaddr(src_ipaddr, src_port, &src_addr, sizeof(struct sockaddr_storage)) != 0) {
knet_vty_write(vty, "Error: unable to convert source ip addr to sockaddr!%s", telnet_newline);
err = -1;
goto out_clean;
}
if (!strncmp(dst_ipaddr, "dynamic", 7)) {
dst = NULL;
} else {
if (knet_strtoaddr(dst_ipaddr, dst_port, &dst_addr, sizeof(struct sockaddr_storage)) != 0) {
knet_vty_write(vty, "Error: unable to convert destination ip addr to sockaddr!%s", telnet_newline);
err = -1;
goto out_clean;
}
dst = &dst_addr;
}
knet_link_set_config(knet_iface->cfg_ring.knet_h, vty->host_id, vty->link_id, transport_id, &src_addr, dst);
knet_link_set_ping_timers(knet_iface->cfg_ring.knet_h, vty->host_id, vty->link_id, 1000, 5000, 2048);
knet_link_set_enable(knet_iface->cfg_ring.knet_h, vty->host_id, vty->link_id, 1);
}
vty->node = NODE_LINK;
out_clean:
return err;
}
static int knet_cmd_switch_policy(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
int paramlen = 0, paramoffset = 0, err = 0;
char *param = NULL;
char policystr[16];
int policy = -1;
get_param(vty, 1, &param, &paramlen, &paramoffset);
param_to_str(policystr, sizeof(policystr), param, paramlen);
if (!strncmp("passive", policystr, 7))
policy = KNET_LINK_POLICY_PASSIVE;
if (!strncmp("active", policystr, 6))
policy = KNET_LINK_POLICY_ACTIVE;
if (!strncmp("round-robin", policystr, 11))
policy = KNET_LINK_POLICY_RR;
if (policy < 0) {
knet_vty_write(vty, "Error: unknown switching policy method%s", telnet_newline);
return -1;
}
err = knet_host_set_policy(knet_iface->cfg_ring.knet_h, vty->host_id, policy);
if (err)
knet_vty_write(vty, "Error: unable to set switching policy to %s%s", policystr, telnet_newline);
return err;
}
/*
* -1 on internal error
* 0 host does not exist
* 1 host exists
*/
-static int knet_find_host(struct knet_vty *vty, const char *nodename, const uint16_t requested_node_id)
+static int knet_find_host(struct knet_vty *vty, const char *nodename, const uint8_t requested_node_id)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
int have_nodeid, have_name;
- uint16_t node_id;
+ uint8_t node_id;
char name[KNET_MAX_HOST_LEN];
have_nodeid = knet_host_get_id_by_host_name(knet_iface->cfg_ring.knet_h, nodename, &node_id);
have_name = knet_host_get_name_by_host_id(knet_iface->cfg_ring.knet_h, requested_node_id, name);
/*
* host does not exist without a name
*/
if (have_name < 0) {
return 0;
}
/*
* internal error.. get out
*/
if ((have_nodeid < 0) || (have_name < 0)) {
knet_vty_write(vty, "Error: unable to query libknet for name/nodeid info%s", telnet_newline);
return -1;
}
if ((!have_name) && (!have_nodeid)) {
if (!strcmp(name, nodename) && (node_id == requested_node_id))
return 1;
}
knet_vty_write(vty, "Error: requested nodename or id already exists in libknet%s", telnet_newline);
return -1;
}
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;
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, nodename, requested_node_id);
if (err < 0)
goto out_clean;
if (err != 1) {
knet_vty_write(vty, "Error: peer not found in list%s", telnet_newline);
goto out_clean;
}
err = knet_host_remove(knet_iface->cfg_ring.knet_h, requested_node_id);
if (err < 0) {
knet_vty_write(vty, "Error: unable to remove peer from current config%s", telnet_newline);
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, host = 0;
char *param = 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, nodename, requested_node_id);
if (err < 0)
goto out_clean;
if (err == 0) {
err = knet_host_add(knet_iface->cfg_ring.knet_h, requested_node_id);
if (err < 0) {
knet_vty_write(vty, "Error: unable to allocate memory for host struct!%s", telnet_newline);
goto out_clean;
}
host = 1;
knet_host_set_name(knet_iface->cfg_ring.knet_h, requested_node_id, nodename);
knet_host_set_policy(knet_iface->cfg_ring.knet_h, requested_node_id, KNET_LINK_POLICY_PASSIVE);
}
vty->host_id = requested_node_id;
vty->node = NODE_PEER;
out_clean:
if (err < 0) {
if (host)
knet_host_remove(knet_iface->cfg_ring.knet_h, requested_node_id);
}
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 void knet_cmd_auto_mtu_notify(void *private_data,
unsigned int data_mtu)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)private_data;
/*
* 48 is the magic number! yes it is.. it's the magic number...
*/
knet_iface->cfg_ring.data_mtu = data_mtu - 48;
if (!knet_iface->cfg_eth.auto_mtu) {
int mtu = 0;
mtu = tap_get_mtu(knet_iface->cfg_eth.tap);
if (mtu < 0) {
log_debug("Unable to get current MTU?");
} else {
if (data_mtu < mtu) {
log_debug("Manually configured MTU (%d) is higher than automatically detected MTU (%d)",
mtu, data_mtu);
}
}
return;
}
if (tap_set_mtu(knet_iface->cfg_eth.tap, knet_iface->cfg_ring.data_mtu) < 0) {
log_warn("Error: Unable to set requested mtu %d on device %s via mtu notify",
knet_iface->cfg_ring.data_mtu, tap_get_name(knet_iface->cfg_eth.tap));
} else {
log_info("Device %s new mtu: %d (via mtu notify)",
tap_get_name(knet_iface->cfg_eth.tap), knet_iface->cfg_ring.data_mtu);
}
}
static int knet_cmd_no_pmtufreq(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
if (knet_handle_pmtud_setfreq(knet_iface->cfg_ring.knet_h, 5) < 0) {
knet_vty_write(vty, "Error: Unable to reset PMTUd frequency to 5 seconds on device %s%s",
tap_get_name(knet_iface->cfg_eth.tap), telnet_newline);
return -1;
}
return 0;
}
static int knet_cmd_pmtufreq(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
int paramlen = 0, paramoffset = 0, pmtufreq = 5;
char *param = NULL;
get_param(vty, 1, &param, &paramlen, &paramoffset);
pmtufreq = param_to_int(param, paramlen);
if (knet_handle_pmtud_setfreq(knet_iface->cfg_ring.knet_h, pmtufreq) < 0) {
knet_vty_write(vty, "Error: Unable to set PMTUd frequency to %d seconds on device %s%s",
pmtufreq, tap_get_name(knet_iface->cfg_eth.tap), telnet_newline);
return -1;
}
return 0;
}
static int knet_cmd_no_mtu(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
/* allow automatic updates of mtu */
knet_iface->cfg_eth.auto_mtu = 1;
if (knet_iface->cfg_ring.data_mtu > 0) {
if (tap_set_mtu(knet_iface->cfg_eth.tap, knet_iface->cfg_ring.data_mtu) < 0) {
knet_iface->cfg_eth.auto_mtu = 0;
knet_vty_write(vty, "Error: Unable to set auto detected mtu on device %s%s",
tap_get_name(knet_iface->cfg_eth.tap), telnet_newline);
return -1;
}
} else {
if (tap_reset_mtu(knet_iface->cfg_eth.tap) < 0) {
knet_iface->cfg_eth.auto_mtu = 0;
knet_vty_write(vty, "Error: Unable to reset 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);
/* disable mtu auto updates */
knet_iface->cfg_eth.auto_mtu = 0;
if ((knet_iface->cfg_ring.data_mtu) &&
(expected_mtu > knet_iface->cfg_ring.data_mtu)) {
knet_vty_write(vty, "WARNING: Manually configured MTU (%d) is higher than automatically detected MTU (%d)%s",
expected_mtu, knet_iface->cfg_ring.data_mtu, telnet_newline);
}
if (tap_set_mtu(knet_iface->cfg_eth.tap, expected_mtu) < 0) {
knet_iface->cfg_eth.auto_mtu = 1;
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 {
if (knet_iface->cfg_ring.knet_h)
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;
struct knet_handle_crypto_cfg knet_handle_crypto_cfg_new;
int fd = -1;
char keyfile[PATH_MAX];
struct stat sb;
if (knet_iface->active) {
knet_vty_write(vty, "Error: Unable to activate encryption while interface is active%s", telnet_newline);
return -1;
}
memset(&knet_handle_crypto_cfg_new, 0, sizeof(struct knet_handle_crypto_cfg));
get_param(vty, 1, &param, &paramlen, &paramoffset);
param_to_str(knet_handle_crypto_cfg_new.crypto_model,
sizeof(knet_handle_crypto_cfg_new.crypto_model), param, paramlen);
get_param(vty, 2, &param, &paramlen, &paramoffset);
param_to_str(knet_handle_crypto_cfg_new.crypto_cipher_type,
sizeof(knet_handle_crypto_cfg_new.crypto_cipher_type), param, paramlen);
get_param(vty, 3, &param, &paramlen, &paramoffset);
param_to_str(knet_handle_crypto_cfg_new.crypto_hash_type,
sizeof(knet_handle_crypto_cfg_new.crypto_hash_type), param, paramlen);
if ((!strncmp("none", knet_handle_crypto_cfg_new.crypto_model, 4)) ||
((!strncmp("none", knet_handle_crypto_cfg_new.crypto_cipher_type, 4)) &&
((!strncmp("none", knet_handle_crypto_cfg_new.crypto_hash_type, 4)))))
goto no_key;
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_handle_crypto_cfg_new.private_key_len = (unsigned int)sb.st_size;
if ((knet_handle_crypto_cfg_new.private_key_len < KNET_MIN_KEY_LEN) ||
(knet_handle_crypto_cfg_new.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_handle_crypto_cfg_new.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_handle_crypto_cfg_new.private_key,
knet_handle_crypto_cfg_new.private_key_len) != knet_handle_crypto_cfg_new.private_key_len) {
knet_vty_write(vty, "Error: Unable to read key %s%s", keyfile, telnet_newline);
goto key_error;
}
close(fd);
no_key:
err = knet_handle_crypto(knet_iface->cfg_ring.knet_h,
&knet_handle_crypto_cfg_new);
if (!err) {
memmove(&knet_iface->knet_handle_crypto_cfg, &knet_handle_crypto_cfg_new, sizeof(struct knet_handle_crypto_cfg));
} else {
knet_vty_write(vty, "Error: Unable to initialize crypto module%s", telnet_newline);
}
return err;
key_error:
close(fd);
return -1;
}
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;
char *ip_list = NULL;
int ip_list_entries = 0, j, i, offset = 0;
char *error_string = NULL;
- uint16_t host_ids[KNET_MAX_HOST];
+ uint8_t host_ids[KNET_MAX_HOST];
uint8_t link_ids[KNET_MAX_LINK];
size_t host_ids_entries = 0, link_ids_entries = 0;
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;
/*
* disable PTMUd notification before shutting down the tap device
*/
knet_handle_enable_pmtud_notify(knet_iface->cfg_ring.knet_h, NULL, NULL);
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;
}
knet_host_get_host_list(knet_iface->cfg_ring.knet_h, host_ids, &host_ids_entries);
for (j = 0; j < host_ids_entries; j++) {
knet_link_get_link_list(knet_iface->cfg_ring.knet_h, host_ids[j], link_ids, &link_ids_entries);
for (i = 0; i < link_ids_entries; i++) {
knet_link_set_enable(knet_iface->cfg_ring.knet_h, host_ids[j], link_ids[i], 0);
knet_link_clear_config(knet_iface->cfg_ring.knet_h, host_ids[j], link_ids[i]);
}
knet_host_remove(knet_iface->cfg_ring.knet_h, host_ids[j]);
}
knet_cmd_stop(vty);
if (knet_iface->cfg_ring.knet_h) {
knet_handle_free(knet_iface->cfg_ring.knet_h);
knet_iface->cfg_ring.knet_h = NULL;
}
if (knet_iface->cfg_eth.tap)
tap_close(knet_iface->cfg_eth.tap);
if (knet_iface)
knet_destroy_iface(knet_iface);
return err;
}
static void sock_notify_fn(void *private_data, int datafd, int8_t chan, uint8_t tx_rx, int error, int errorno)
{
struct knet_vty *vty = (struct knet_vty *)private_data;
knet_vty_write(vty, "Error: received sock notify, datafd: %d channel: %d direction: %u error: %d errno: %d (%s)%s",
datafd, chan, tx_rx, error, errorno, strerror(errorno), telnet_newline);
}
static int knet_cmd_interface(struct knet_vty *vty)
{
int err = 0, paramlen = 0, paramoffset = 0, found = 0, requested_id, tapfd;
uint16_t baseport;
uint8_t *bport = (uint8_t *)&baseport;
char *param = NULL;
char device[IFNAMSIZ];
char mac[18];
struct knet_cfg *knet_iface = NULL;
int8_t channel = 0;
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);
get_param(vty, 3, &param, &paramlen, &paramoffset);
baseport = 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;
knet_iface->cfg_ring.base_port = baseport;
tapfd = tap_get_fd(knet_iface->cfg_eth.tap);
knet_iface->cfg_ring.knet_h = knet_handle_new(requested_id, vty->logfd, vty->loglevel);
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;
}
if (knet_handle_enable_sock_notify(knet_iface->cfg_ring.knet_h, &vty, sock_notify_fn)) {
knet_vty_write(vty, "Error: Unable to add sock notify callback to to knet_handle %s%s",
strerror(errno), telnet_newline);
err = -1;
goto out_clean;
}
if (knet_handle_add_datafd(knet_iface->cfg_ring.knet_h, &tapfd, &channel) < 0) {
knet_vty_write(vty, "Error: Unable to add tapfd to knet_handle %s%s",
strerror(errno), telnet_newline);
err = -1;
goto out_clean;
}
knet_handle_enable_filter(knet_iface->cfg_ring.knet_h, NULL, ether_host_filter_fn);
if (knet_handle_enable_pmtud_notify(knet_iface->cfg_ring.knet_h,
knet_iface,
knet_cmd_auto_mtu_notify) < 0) {
knet_vty_write(vty, "Error: Unable to configure auto mtu notification for device %s%s",
device, telnet_newline);
err = -1;
goto out_clean;
}
knet_iface->cfg_eth.auto_mtu = 1;
/*
* make this configurable
*/
knet_handle_pmtud_setfreq(knet_iface->cfg_ring.knet_h, 5);
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;
}
baseport = htons(baseport);
memset(&mac, 0, sizeof(mac));
snprintf(mac, sizeof(mac) - 1, "54:54:%x:%x:0:%x", bport[0], bport[1], 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_status(struct knet_vty *vty)
{
int i, j;
struct knet_cfg *knet_iface = knet_cfg_head.knet_cfg;
struct knet_link_status status;
const char *nl = telnet_newline;
struct timespec now;
char nodename[KNET_MAX_HOST_LEN];
- uint16_t host_ids[KNET_MAX_HOST];
+ uint8_t host_ids[KNET_MAX_HOST];
uint8_t link_ids[KNET_MAX_LINK];
size_t host_ids_entries = 0, link_ids_entries = 0;
uint8_t policy;
clock_gettime(CLOCK_MONOTONIC, &now);
knet_vty_write(vty, "Current knet status%s", nl);
knet_vty_write(vty, "-------------------%s", nl);
while (knet_iface != NULL) {
knet_vty_write(vty, "interface %s (active: %d)%s", tap_get_name(knet_iface->cfg_eth.tap), knet_iface->active, nl);
knet_host_get_host_list(knet_iface->cfg_ring.knet_h, host_ids, &host_ids_entries);
for (j = 0; j < host_ids_entries; j++) {
knet_host_get_name_by_host_id(knet_iface->cfg_ring.knet_h, host_ids[j], nodename);
knet_vty_write(vty, " peer %s ", nodename);
knet_host_get_policy(knet_iface->cfg_ring.knet_h, host_ids[j], &policy);
switch (policy) {
case KNET_LINK_POLICY_PASSIVE:
knet_vty_write(vty, "(passive)%s", nl);
break;
case KNET_LINK_POLICY_ACTIVE:
knet_vty_write(vty, "(active)%s", nl);
break;
case KNET_LINK_POLICY_RR:
knet_vty_write(vty, "(round-robin)%s", nl);
break;
}
knet_link_get_link_list(knet_iface->cfg_ring.knet_h, host_ids[j], link_ids, &link_ids_entries);
for (i = 0; i < link_ids_entries; i++) {
uint8_t dynamic, transport;
const char *transport_name;
struct sockaddr_storage src_addr;
struct sockaddr_storage dst_addr;
if (!knet_link_get_config(knet_iface->cfg_ring.knet_h, host_ids[j], link_ids[i], &transport, &src_addr, &dst_addr, &dynamic)) {
transport_name = knet_handle_get_transport_name_by_id(knet_iface->cfg_ring.knet_h, transport);
knet_link_get_status(knet_iface->cfg_ring.knet_h, host_ids[j], link_ids[i], &status);
if (status.enabled == 1) {
if (dynamic) {
knet_vty_write(vty, " link %s dynamic (%s/connected: %d)%s", status.src_ipaddr, transport_name, status.connected, nl);
} else {
knet_vty_write(vty, " link %s %s (%s/connected: %d)%s", status.src_ipaddr, status.dst_ipaddr, transport_name, status.connected, nl);
}
if (status.connected) {
knet_vty_write(vty, " average latency: %llu us%s", status.latency, nl);
if ((dynamic) && (status.dynconnected)) {
knet_vty_write(vty, " source ip: %s%s", status.dst_ipaddr, nl);
}
} else {
knet_vty_write(vty, " last heard: ");
if (status.pong_last.tv_sec) {
knet_vty_write(vty, "%lu s ago%s",
(long unsigned int)now.tv_sec - status.pong_last.tv_sec, nl);
} else {
knet_vty_write(vty, "never%s", nl);
}
}
}
}
}
}
knet_iface = knet_iface->next;
}
return 0;
}
static int knet_cmd_print_conf(struct knet_vty *vty)
{
int i, j;
struct knet_cfg *knet_iface = knet_cfg_head.knet_cfg;
struct knet_link_status status;
const char *nl = telnet_newline;
char *ip_list = NULL;
int ip_list_entries = 0;
- uint16_t host_ids[KNET_MAX_HOST];
+ uint8_t host_ids[KNET_MAX_HOST];
uint8_t link_ids[KNET_MAX_LINK];
size_t host_ids_entries = 0, link_ids_entries = 0;
char nodename[KNET_MAX_HOST_LEN];
uint8_t policy;
unsigned int pmtudfreq = 0;
if (vty->filemode)
nl = file_newline;
knet_vty_write(vty, "configure%s", nl);
knet_vty_write(vty, " vty%s", nl);
knet_vty_write(vty, " timeout %d%s", vty->idle_timeout, nl);
knet_vty_write(vty, " exit%s", nl);
while (knet_iface != NULL) {
knet_vty_write(vty, " interface %s %u %u%s", tap_get_name(knet_iface->cfg_eth.tap),
knet_iface->cfg_eth.node_id,
knet_iface->cfg_ring.base_port, nl);
if (!knet_iface->cfg_eth.auto_mtu)
knet_vty_write(vty, " mtu %d%s", tap_get_mtu(knet_iface->cfg_eth.tap), nl);
knet_handle_pmtud_getfreq(knet_iface->cfg_ring.knet_h, &pmtudfreq);
if ((pmtudfreq > 0) && (pmtudfreq != 5))
knet_vty_write(vty, " pmtudfreq %d%s", pmtudfreq, nl);
tap_get_ips(knet_iface->cfg_eth.tap, &ip_list, &ip_list_entries);
if ((ip_list) && (ip_list_entries > 0)) {
char *ipaddr = NULL, *prefix = NULL, *next = ip_list;
for (i = 1; i <= ip_list_entries; i++) {
ipaddr = next;
prefix = ipaddr + strlen(ipaddr) + 1;
next = prefix + strlen(prefix) + 1;
knet_vty_write(vty, " ip %s %s%s", ipaddr, prefix, nl);
}
free(ip_list);
ip_list = NULL;
ip_list_entries = 0;
}
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);
knet_host_get_host_list(knet_iface->cfg_ring.knet_h, host_ids, &host_ids_entries);
for (j = 0; j < host_ids_entries; j++) {
knet_host_get_name_by_host_id(knet_iface->cfg_ring.knet_h, host_ids[j], nodename);
knet_vty_write(vty, " peer %s %u%s", nodename, host_ids[j], nl);
knet_host_get_policy(knet_iface->cfg_ring.knet_h, host_ids[j], &policy);
switch (policy) {
case KNET_LINK_POLICY_PASSIVE:
knet_vty_write(vty, " switch-policy passive%s", nl);
break;
case KNET_LINK_POLICY_ACTIVE:
knet_vty_write(vty, " switch-policy active%s", nl);
break;
case KNET_LINK_POLICY_RR:
knet_vty_write(vty, " switch-policy round-robin%s", nl);
break;
}
knet_link_get_link_list(knet_iface->cfg_ring.knet_h, host_ids[j], link_ids, &link_ids_entries);
for (i = 0; i < link_ids_entries; i++) {
uint8_t dynamic, transport;
const char *transport_name;
struct sockaddr_storage src_addr;
struct sockaddr_storage dst_addr;
if (!knet_link_get_config(knet_iface->cfg_ring.knet_h, host_ids[j], link_ids[i], &transport, &src_addr, &dst_addr, &dynamic)) {
transport_name = knet_handle_get_transport_name_by_id(knet_iface->cfg_ring.knet_h, transport);
knet_link_get_status(knet_iface->cfg_ring.knet_h, host_ids[j], link_ids[i], &status);
if (status.enabled == 1) {
uint8_t priority, pong_count;
unsigned int precision;
time_t interval, timeout;
if (dynamic) {
knet_vty_write(vty, " link %d %s dynamic %s%s", link_ids[i], status.src_ipaddr, transport_name, nl);
} else {
knet_vty_write(vty, " link %d %s %s %s%s", link_ids[i], status.src_ipaddr, status.dst_ipaddr, transport_name, nl);
}
knet_link_get_pong_count(knet_iface->cfg_ring.knet_h, host_ids[j], link_ids[i], &pong_count);
knet_vty_write(vty, " pong_count %u%s", pong_count, nl);
knet_link_get_ping_timers(knet_iface->cfg_ring.knet_h, host_ids[j], link_ids[i], &interval, &timeout, &precision);
knet_vty_write(vty, " timers %llu %llu%s", (unsigned long long)interval, (unsigned long long)timeout, nl);
knet_link_get_priority(knet_iface->cfg_ring.knet_h, host_ids[j], link_ids[i], &priority);
knet_vty_write(vty, " priority %u%s", priority, nl);
/* print link properties */
knet_vty_write(vty, " exit%s", nl);
}
}
}
knet_vty_write(vty, " exit%s", nl);
}
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 "d 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);
}
void knet_close_down(void)
{
struct knet_vty *vty = &knet_vtys[0];
int err, loop = 0;
vty->node = NODE_CONFIG;
vty->vty_sock = 1;
vty->user_can_enable = 1;
vty->filemode = 1;
vty->got_epipe = 0;
while ((knet_cfg_head.knet_cfg) && (loop < 10)) {
memset(vty->line, 0, sizeof(vty->line));
snprintf(vty->line, sizeof(vty->line) - 1, "no interface %s", tap_get_name(knet_cfg_head.knet_cfg->cfg_eth.tap));
vty->line_idx = strlen(vty->line);
err = knet_vty_execute_cmd(vty);
if (err != 0) {
log_error("error shutting down: %s", vty->line);
break;
}
loop++;
}
}
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 d50c1f84..3783268e 100644
--- a/libknet/handle.c
+++ b/libknet/handle.c
@@ -1,1414 +1,1414 @@
/*
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
*
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
* Federico Simoncelli <fsimon@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sys/uio.h>
#include <math.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "internals.h"
#include "crypto.h"
#include "compat.h"
#include "common.h"
#include "threads_common.h"
#include "threads_heartbeat.h"
#include "threads_pmtud.h"
#include "threads_dsthandler.h"
#include "threads_rx.h"
#include "threads_tx.h"
#include "transports.h"
#include "logging.h"
static pthread_mutex_t handle_config_mutex = PTHREAD_MUTEX_INITIALIZER;
static int _init_locks(knet_handle_t knet_h)
{
int savederrno = 0;
savederrno = pthread_rwlock_init(&knet_h->global_rwlock, NULL);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to initialize list rwlock: %s",
strerror(savederrno));
goto exit_fail;
}
knet_h->lock_init_done = 1;
savederrno = pthread_mutex_init(&knet_h->pmtud_mutex, NULL);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to initialize pmtud mutex: %s",
strerror(savederrno));
goto exit_fail;
}
savederrno = pthread_cond_init(&knet_h->pmtud_cond, NULL);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to initialize pmtud conditional mutex: %s",
strerror(savederrno));
goto exit_fail;
}
savederrno = pthread_mutex_init(&knet_h->hb_mutex, NULL);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to initialize hb_thread mutex: %s",
strerror(savederrno));
goto exit_fail;
}
savederrno = pthread_mutex_init(&knet_h->tx_mutex, NULL);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to initialize tx_thread mutex: %s",
strerror(savederrno));
goto exit_fail;
}
savederrno = pthread_mutex_init(&knet_h->tx_seq_num_mutex, NULL);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to initialize tx_seq_num_mutex mutex: %s",
strerror(savederrno));
goto exit_fail;
}
return 0;
exit_fail:
errno = savederrno;
return -1;
}
static void _destroy_locks(knet_handle_t knet_h)
{
knet_h->lock_init_done = 0;
pthread_rwlock_destroy(&knet_h->global_rwlock);
pthread_mutex_destroy(&knet_h->pmtud_mutex);
pthread_cond_destroy(&knet_h->pmtud_cond);
pthread_mutex_destroy(&knet_h->hb_mutex);
pthread_mutex_destroy(&knet_h->tx_mutex);
pthread_mutex_destroy(&knet_h->tx_seq_num_mutex);
}
static int _init_socks(knet_handle_t knet_h)
{
int savederrno = 0;
if (_init_socketpair(knet_h, knet_h->hostsockfd)) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to initialize internal hostsockpair: %s",
strerror(savederrno));
goto exit_fail;
}
if (_init_socketpair(knet_h, knet_h->dstsockfd)) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to initialize internal dstsockpair: %s",
strerror(savederrno));
goto exit_fail;
}
return 0;
exit_fail:
errno = savederrno;
return -1;
}
static void _close_socks(knet_handle_t knet_h)
{
_close_socketpair(knet_h, knet_h->dstsockfd);
_close_socketpair(knet_h, knet_h->hostsockfd);
}
static int _init_buffers(knet_handle_t knet_h)
{
int savederrno = 0;
int i;
size_t bufsize;
for (i = 0; i < PCKT_FRAG_MAX; i++) {
bufsize = ceil((float)KNET_MAX_PACKET_SIZE / (i + 1)) + KNET_HEADER_ALL_SIZE;
knet_h->send_to_links_buf[i] = malloc(bufsize);
if (!knet_h->send_to_links_buf[i]) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to allocate memory datafd to link buffer: %s",
strerror(savederrno));
goto exit_fail;
}
memset(knet_h->send_to_links_buf[i], 0, bufsize);
knet_h->recv_from_sock_buf[i] = malloc(KNET_DATABUFSIZE);
if (!knet_h->recv_from_sock_buf[i]) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to allocate memory for app to datafd buffer: %s",
strerror(savederrno));
goto exit_fail;
}
memset(knet_h->recv_from_sock_buf[i], 0, KNET_DATABUFSIZE);
knet_h->recv_from_links_buf[i] = malloc(KNET_DATABUFSIZE);
if (!knet_h->recv_from_links_buf[i]) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to allocate memory for link to datafd buffer: %s",
strerror(savederrno));
goto exit_fail;
}
memset(knet_h->recv_from_links_buf[i], 0, KNET_DATABUFSIZE);
}
knet_h->pingbuf = malloc(KNET_HEADER_PING_SIZE);
if (!knet_h->pingbuf) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to allocate memory for hearbeat buffer: %s",
strerror(savederrno));
goto exit_fail;
}
memset(knet_h->pingbuf, 0, KNET_HEADER_PING_SIZE);
knet_h->pmtudbuf = malloc(KNET_PMTUD_SIZE_V6);
if (!knet_h->pmtudbuf) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to allocate memory for pmtud buffer: %s",
strerror(savederrno));
goto exit_fail;
}
memset(knet_h->pmtudbuf, 0, KNET_PMTUD_SIZE_V6);
for (i = 0; i < PCKT_FRAG_MAX; i++) {
bufsize = ceil((float)KNET_MAX_PACKET_SIZE / (i + 1)) + KNET_HEADER_ALL_SIZE + KNET_DATABUFSIZE_CRYPT_PAD;
knet_h->send_to_links_buf_crypt[i] = malloc(bufsize);
if (!knet_h->send_to_links_buf_crypt[i]) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to allocate memory for crypto datafd to link buffer: %s",
strerror(savederrno));
goto exit_fail;
}
memset(knet_h->send_to_links_buf_crypt[i], 0, bufsize);
}
knet_h->recv_from_links_buf_decrypt = malloc(KNET_DATABUFSIZE_CRYPT);
if (!knet_h->recv_from_links_buf_decrypt) {
savederrno = errno;
log_err(knet_h, KNET_SUB_CRYPTO, "Unable to allocate memory for crypto link to datafd buffer: %s",
strerror(savederrno));
goto exit_fail;
}
memset(knet_h->recv_from_links_buf_decrypt, 0, KNET_DATABUFSIZE_CRYPT);
knet_h->recv_from_links_buf_crypt = malloc(KNET_DATABUFSIZE_CRYPT);
if (!knet_h->recv_from_links_buf_crypt) {
savederrno = errno;
log_err(knet_h, KNET_SUB_CRYPTO, "Unable to allocate memory for crypto link to datafd buffer: %s",
strerror(savederrno));
goto exit_fail;
}
memset(knet_h->recv_from_links_buf_crypt, 0, KNET_DATABUFSIZE_CRYPT);
knet_h->pingbuf_crypt = malloc(KNET_DATABUFSIZE_CRYPT);
if (!knet_h->pingbuf_crypt) {
savederrno = errno;
log_err(knet_h, KNET_SUB_CRYPTO, "Unable to allocate memory for crypto hearbeat buffer: %s",
strerror(savederrno));
goto exit_fail;
}
memset(knet_h->pingbuf_crypt, 0, KNET_DATABUFSIZE_CRYPT);
knet_h->pmtudbuf_crypt = malloc(KNET_DATABUFSIZE_CRYPT);
if (!knet_h->pmtudbuf_crypt) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to allocate memory for crypto pmtud buffer: %s",
strerror(savederrno));
goto exit_fail;
}
memset(knet_h->pmtudbuf_crypt, 0, KNET_DATABUFSIZE_CRYPT);
memset(knet_h->knet_transport_fd_tracker, KNET_MAX_TRANSPORTS, sizeof(knet_h->knet_transport_fd_tracker));
return 0;
exit_fail:
errno = savederrno;
return -1;
}
static void _destroy_buffers(knet_handle_t knet_h)
{
int i;
for (i = 0; i < PCKT_FRAG_MAX; i++) {
free(knet_h->send_to_links_buf[i]);
free(knet_h->recv_from_sock_buf[i]);
free(knet_h->send_to_links_buf_crypt[i]);
free(knet_h->recv_from_links_buf[i]);
}
free(knet_h->recv_from_links_buf_decrypt);
free(knet_h->recv_from_links_buf_crypt);
free(knet_h->pingbuf);
free(knet_h->pingbuf_crypt);
free(knet_h->pmtudbuf);
free(knet_h->pmtudbuf_crypt);
}
static int _init_epolls(knet_handle_t knet_h)
{
struct epoll_event ev;
int savederrno = 0;
/*
* even if the kernel does dynamic allocation with epoll_ctl
* we need to reserve one extra for host to host communication
*/
knet_h->send_to_links_epollfd = epoll_create(KNET_EPOLL_MAX_EVENTS + 1);
if (knet_h->send_to_links_epollfd < 0) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to create epoll datafd to link fd: %s",
strerror(savederrno));
goto exit_fail;
}
knet_h->recv_from_links_epollfd = epoll_create(KNET_EPOLL_MAX_EVENTS);
if (knet_h->recv_from_links_epollfd < 0) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to create epoll link to datafd fd: %s",
strerror(savederrno));
goto exit_fail;
}
knet_h->dst_link_handler_epollfd = epoll_create(KNET_EPOLL_MAX_EVENTS);
if (knet_h->dst_link_handler_epollfd < 0) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to create epoll dst cache fd: %s",
strerror(savederrno));
goto exit_fail;
}
if (_fdset_cloexec(knet_h->send_to_links_epollfd)) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to set CLOEXEC on datafd to link epoll fd: %s",
strerror(savederrno));
goto exit_fail;
}
if (_fdset_cloexec(knet_h->recv_from_links_epollfd)) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to set CLOEXEC on link to datafd epoll fd: %s",
strerror(savederrno));
goto exit_fail;
}
if (_fdset_cloexec(knet_h->dst_link_handler_epollfd)) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to set CLOEXEC on dst cache epoll fd: %s",
strerror(savederrno));
goto exit_fail;
}
memset(&ev, 0, sizeof(struct epoll_event));
ev.events = EPOLLIN;
ev.data.fd = knet_h->hostsockfd[0];
if (epoll_ctl(knet_h->send_to_links_epollfd,
EPOLL_CTL_ADD, knet_h->hostsockfd[0], &ev)) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to add hostsockfd[0] to epoll pool: %s",
strerror(savederrno));
goto exit_fail;
}
memset(&ev, 0, sizeof(struct epoll_event));
ev.events = EPOLLIN;
ev.data.fd = knet_h->dstsockfd[0];
if (epoll_ctl(knet_h->dst_link_handler_epollfd,
EPOLL_CTL_ADD, knet_h->dstsockfd[0], &ev)) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to add dstsockfd[0] to epoll pool: %s",
strerror(savederrno));
goto exit_fail;
}
return 0;
exit_fail:
errno = savederrno;
return -1;
}
static void _close_epolls(knet_handle_t knet_h)
{
struct epoll_event ev;
int i;
memset(&ev, 0, sizeof(struct epoll_event));
for (i = 0; i < KNET_DATAFD_MAX; i++) {
if (knet_h->sockfd[i].in_use) {
epoll_ctl(knet_h->send_to_links_epollfd, EPOLL_CTL_DEL, knet_h->sockfd[i].sockfd[knet_h->sockfd[i].is_created], &ev);
if (knet_h->sockfd[i].sockfd[knet_h->sockfd[i].is_created]) {
_close_socketpair(knet_h, knet_h->sockfd[i].sockfd);
}
}
}
epoll_ctl(knet_h->send_to_links_epollfd, EPOLL_CTL_DEL, knet_h->hostsockfd[0], &ev);
epoll_ctl(knet_h->dst_link_handler_epollfd, EPOLL_CTL_DEL, knet_h->dstsockfd[0], &ev);
close(knet_h->send_to_links_epollfd);
close(knet_h->recv_from_links_epollfd);
close(knet_h->dst_link_handler_epollfd);
}
static int _start_transports(knet_handle_t knet_h)
{
int i, savederrno = 0, err = 0;
for (i=0; i<KNET_MAX_TRANSPORTS; i++) {
switch (i) {
case KNET_TRANSPORT_UDP:
knet_h->transport_ops[i] = get_udp_transport();
break;
case KNET_TRANSPORT_SCTP:
knet_h->transport_ops[i] = get_sctp_transport();
break;
}
if (knet_h->transport_ops[i]) {
if (knet_h->transport_ops[i]->transport_init(knet_h) < 0) {
savederrno = errno;
log_err(knet_h, KNET_SUB_HANDLE, "Failed to allocate transport handle for %s: %s",
knet_h->transport_ops[i]->transport_name,
strerror(savederrno));
err = -1;
goto out;
}
}
}
out:
errno = savederrno;
return err;
}
static void _stop_transports(knet_handle_t knet_h)
{
int i;
for (i=0; i<KNET_MAX_TRANSPORTS; i++) {
if (knet_h->transport_ops[i]) {
knet_h->transport_ops[i]->transport_free(knet_h);
}
}
}
static int _start_threads(knet_handle_t knet_h)
{
int savederrno = 0;
savederrno = pthread_create(&knet_h->pmtud_link_handler_thread, 0,
_handle_pmtud_link_thread, (void *) knet_h);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to start pmtud link thread: %s",
strerror(savederrno));
goto exit_fail;
}
savederrno = pthread_create(&knet_h->dst_link_handler_thread, 0,
_handle_dst_link_handler_thread, (void *) knet_h);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to start dst cache thread: %s",
strerror(savederrno));
goto exit_fail;
}
savederrno = pthread_create(&knet_h->send_to_links_thread, 0,
_handle_send_to_links_thread, (void *) knet_h);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to start datafd to link thread: %s",
strerror(savederrno));
goto exit_fail;
}
savederrno = pthread_create(&knet_h->recv_from_links_thread, 0,
_handle_recv_from_links_thread, (void *) knet_h);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to start link to datafd thread: %s",
strerror(savederrno));
goto exit_fail;
}
savederrno = pthread_create(&knet_h->heartbt_thread, 0,
_handle_heartbt_thread, (void *) knet_h);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to start heartbeat thread: %s",
strerror(savederrno));
goto exit_fail;
}
return 0;
exit_fail:
errno = savederrno;
return -1;
}
static void _stop_threads(knet_handle_t knet_h)
{
void *retval;
/*
* allow threads to catch on shutdown request
* and release locks before we stop them.
* this isn't the most efficent way to handle it
* but it works good enough for now
*/
sleep(1);
if (knet_h->heartbt_thread) {
pthread_cancel(knet_h->heartbt_thread);
pthread_join(knet_h->heartbt_thread, &retval);
}
if (knet_h->send_to_links_thread) {
pthread_cancel(knet_h->send_to_links_thread);
pthread_join(knet_h->send_to_links_thread, &retval);
}
if (knet_h->recv_from_links_thread) {
pthread_cancel(knet_h->recv_from_links_thread);
pthread_join(knet_h->recv_from_links_thread, &retval);
}
if (knet_h->dst_link_handler_thread) {
pthread_cancel(knet_h->dst_link_handler_thread);
pthread_join(knet_h->dst_link_handler_thread, &retval);
}
pthread_mutex_lock(&knet_h->pmtud_mutex);
pthread_cond_signal(&knet_h->pmtud_cond);
pthread_mutex_unlock(&knet_h->pmtud_mutex);
sleep(1);
if (knet_h->pmtud_link_handler_thread) {
pthread_cancel(knet_h->pmtud_link_handler_thread);
pthread_join(knet_h->pmtud_link_handler_thread, &retval);
}
}
-knet_handle_t knet_handle_new(uint16_t host_id,
- int log_fd,
- uint8_t default_log_level)
+knet_handle_t knet_handle_new(uint8_t host_id,
+ int log_fd,
+ uint8_t default_log_level)
{
knet_handle_t knet_h;
int savederrno = 0;
struct rlimit cur;
if (getrlimit(RLIMIT_NOFILE, &cur) < 0) {
return NULL;
}
if ((log_fd < 0) || (log_fd >= cur.rlim_max)) {
errno = EINVAL;
return NULL;
}
/*
* validate incoming request
*/
if ((log_fd) && (default_log_level > KNET_LOG_DEBUG)) {
errno = EINVAL;
return NULL;
}
/*
* allocate handle
*/
knet_h = malloc(sizeof(struct knet_handle));
if (!knet_h) {
errno = ENOMEM;
return NULL;
}
memset(knet_h, 0, sizeof(struct knet_handle));
savederrno = pthread_mutex_lock(&handle_config_mutex);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get handle mutex lock: %s",
strerror(savederrno));
errno = savederrno;
goto exit_fail;
}
/*
* copy config in place
*/
knet_h->host_id = host_id;
knet_h->logfd = log_fd;
if (knet_h->logfd > 0) {
memset(&knet_h->log_levels, default_log_level, KNET_MAX_SUBSYSTEMS);
}
/*
* set pmtud default timers
*/
knet_h->pmtud_interval = KNET_PMTUD_DEFAULT_INTERVAL;
/*
* init main locking structures
*/
if (_init_locks(knet_h)) {
savederrno = errno;
goto exit_fail;
}
/*
* init sockets
*/
if (_init_socks(knet_h)) {
savederrno = errno;
goto exit_fail;
}
/*
* allocate packet buffers
*/
if (_init_buffers(knet_h)) {
savederrno = errno;
goto exit_fail;
}
/*
* create epoll fds
*/
if (_init_epolls(knet_h)) {
savederrno = errno;
goto exit_fail;
}
/*
* start transports
*/
if (_start_transports(knet_h)) {
savederrno = errno;
goto exit_fail;
}
/*
* start internal threads
*/
if (_start_threads(knet_h)) {
savederrno = errno;
goto exit_fail;
}
pthread_mutex_unlock(&handle_config_mutex);
return knet_h;
exit_fail:
pthread_mutex_unlock(&handle_config_mutex);
knet_handle_free(knet_h);
errno = savederrno;
return NULL;
}
int knet_handle_free(knet_handle_t knet_h)
{
int savederrno = 0;
savederrno = pthread_mutex_lock(&handle_config_mutex);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get handle mutex lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
if (!knet_h) {
pthread_mutex_unlock(&handle_config_mutex);
errno = EINVAL;
return -1;
}
if (!knet_h->lock_init_done) {
goto exit_nolock;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s",
strerror(savederrno));
pthread_mutex_unlock(&handle_config_mutex);
errno = savederrno;
return -1;
}
if (knet_h->host_head != NULL) {
savederrno = EBUSY;
log_err(knet_h, KNET_SUB_HANDLE,
"Unable to free handle: host(s) or listener(s) are still active: %s",
strerror(savederrno));
pthread_rwlock_unlock(&knet_h->global_rwlock);
pthread_mutex_unlock(&handle_config_mutex);
errno = savederrno;
return -1;
}
knet_h->fini_in_progress = 1;
pthread_rwlock_unlock(&knet_h->global_rwlock);
_stop_threads(knet_h);
_stop_transports(knet_h);
_close_epolls(knet_h);
_destroy_buffers(knet_h);
_close_socks(knet_h);
crypto_fini(knet_h);
_destroy_locks(knet_h);
exit_nolock:
free(knet_h);
knet_h = NULL;
pthread_mutex_unlock(&handle_config_mutex);
return 0;
}
int knet_handle_enable_sock_notify(knet_handle_t knet_h,
void *sock_notify_fn_private_data,
void (*sock_notify_fn) (
void *private_data,
int datafd,
int8_t channel,
uint8_t tx_rx,
int error,
int errorno))
{
int savederrno = 0, err = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (!sock_notify_fn) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
knet_h->sock_notify_fn_private_data = sock_notify_fn_private_data;
knet_h->sock_notify_fn = sock_notify_fn;
log_debug(knet_h, KNET_SUB_HANDLE, "sock_notify_fn enabled");
pthread_rwlock_unlock(&knet_h->global_rwlock);
return err;
}
int knet_handle_add_datafd(knet_handle_t knet_h, int *datafd, int8_t *channel)
{
int err = 0, savederrno = 0;
int i;
struct epoll_event ev;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (datafd == NULL) {
errno = EINVAL;
return -1;
}
if (channel == NULL) {
errno = EINVAL;
return -1;
}
if (*channel >= KNET_DATAFD_MAX) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
if (!knet_h->sock_notify_fn) {
log_err(knet_h, KNET_SUB_HANDLE, "Adding datafd requires sock notify callback enabled!");
savederrno = EINVAL;
err = -1;
goto out_unlock;
}
if (*datafd > 0) {
for (i = 0; i < KNET_DATAFD_MAX; i++) {
if ((knet_h->sockfd[i].in_use) && (knet_h->sockfd[i].sockfd[0] == *datafd)) {
log_err(knet_h, KNET_SUB_HANDLE, "requested datafd: %d already exist in index: %d", *datafd, i);
savederrno = EEXIST;
err = -1;
goto out_unlock;
}
}
}
/*
* auto allocate a channel
*/
if (*channel < 0) {
for (i = 0; i < KNET_DATAFD_MAX; i++) {
if (!knet_h->sockfd[i].in_use) {
*channel = i;
break;
}
}
if (*channel < 0) {
savederrno = EBUSY;
err = -1;
goto out_unlock;
}
} else {
if (knet_h->sockfd[*channel].in_use) {
savederrno = EBUSY;
err = -1;
goto out_unlock;
}
}
knet_h->sockfd[*channel].is_created = 0;
knet_h->sockfd[*channel].is_socket = 0;
knet_h->sockfd[*channel].has_error = 0;
if (*datafd > 0) {
int sockopt;
socklen_t sockoptlen = sizeof(sockopt);
if (_fdset_cloexec(*datafd)) {
savederrno = errno;
err = -1;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to set CLOEXEC on datafd: %s",
strerror(savederrno));
goto out_unlock;
}
if (_fdset_nonblock(*datafd)) {
savederrno = errno;
err = -1;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to set NONBLOCK on datafd: %s",
strerror(savederrno));
goto out_unlock;
}
knet_h->sockfd[*channel].sockfd[0] = *datafd;
knet_h->sockfd[*channel].sockfd[1] = 0;
if (!getsockopt(knet_h->sockfd[*channel].sockfd[0], SOL_SOCKET, SO_TYPE, &sockopt, &sockoptlen)) {
knet_h->sockfd[*channel].is_socket = 1;
}
} else {
if (_init_socketpair(knet_h, knet_h->sockfd[*channel].sockfd)) {
savederrno = errno;
err = -1;
goto out_unlock;
}
knet_h->sockfd[*channel].is_created = 1;
knet_h->sockfd[*channel].is_socket = 1;
*datafd = knet_h->sockfd[*channel].sockfd[0];
}
memset(&ev, 0, sizeof(struct epoll_event));
ev.events = EPOLLIN;
ev.data.fd = knet_h->sockfd[*channel].sockfd[knet_h->sockfd[*channel].is_created];
if (epoll_ctl(knet_h->send_to_links_epollfd,
EPOLL_CTL_ADD, knet_h->sockfd[*channel].sockfd[knet_h->sockfd[*channel].is_created], &ev)) {
savederrno = errno;
err = -1;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to add datafd %d to linkfd epoll pool: %s",
knet_h->sockfd[*channel].sockfd[knet_h->sockfd[*channel].is_created], strerror(savederrno));
if (knet_h->sockfd[*channel].is_created) {
_close_socketpair(knet_h, knet_h->sockfd[*channel].sockfd);
}
goto out_unlock;
}
knet_h->sockfd[*channel].in_use = 1;
out_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
int knet_handle_remove_datafd(knet_handle_t knet_h, int datafd)
{
int err = 0, savederrno = 0;
int8_t channel = -1;
int i;
struct epoll_event ev;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (datafd <= 0) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
for (i = 0; i < KNET_DATAFD_MAX; i++) {
if ((knet_h->sockfd[i].in_use) &&
(knet_h->sockfd[i].sockfd[0] == datafd)) {
channel = i;
break;
}
}
if (channel < 0) {
savederrno = EINVAL;
err = -1;
goto out_unlock;
}
if (!knet_h->sockfd[channel].has_error) {
memset(&ev, 0, sizeof(struct epoll_event));
if (epoll_ctl(knet_h->send_to_links_epollfd,
EPOLL_CTL_DEL, knet_h->sockfd[channel].sockfd[knet_h->sockfd[channel].is_created], &ev)) {
savederrno = errno;
err = -1;
log_err(knet_h, KNET_SUB_HANDLE, "Unable to del datafd %d from linkfd epoll pool: %s",
knet_h->sockfd[channel].sockfd[0], strerror(savederrno));
goto out_unlock;
}
}
if (knet_h->sockfd[channel].is_created) {
_close_socketpair(knet_h, knet_h->sockfd[channel].sockfd);
}
memset(&knet_h->sockfd[channel], 0, sizeof(struct knet_sock));
out_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
int knet_handle_get_datafd(knet_handle_t knet_h, const int8_t channel, int *datafd)
{
int err = 0, savederrno = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if ((channel < 0) || (channel >= KNET_DATAFD_MAX)) {
errno = EINVAL;
return -1;
}
if (datafd == NULL) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
if (!knet_h->sockfd[channel].in_use) {
savederrno = EINVAL;
err = -1;
goto out_unlock;
}
*datafd = knet_h->sockfd[channel].sockfd[0];
out_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
int knet_handle_get_channel(knet_handle_t knet_h, const int datafd, int8_t *channel)
{
int err = 0, savederrno = 0;
int i;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (datafd <= 0) {
errno = EINVAL;
return -1;
}
if (channel == NULL) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
*channel = -1;
for (i = 0; i < KNET_DATAFD_MAX; i++) {
if ((knet_h->sockfd[i].in_use) &&
(knet_h->sockfd[i].sockfd[0] == datafd)) {
*channel = i;
break;
}
}
if (*channel < 0) {
savederrno = EINVAL;
err = -1;
goto out_unlock;
}
out_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
int knet_handle_enable_filter(knet_handle_t knet_h,
void *dst_host_filter_fn_private_data,
int (*dst_host_filter_fn) (
void *private_data,
const unsigned char *outdata,
ssize_t outdata_len,
uint8_t tx_rx,
- uint16_t this_host_id,
- uint16_t src_node_id,
+ uint8_t this_host_id,
+ uint8_t src_node_id,
int8_t *channel,
- uint16_t *dst_host_ids,
+ uint8_t *dst_host_ids,
size_t *dst_host_ids_entries))
{
int savederrno = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
knet_h->dst_host_filter_fn_private_data = dst_host_filter_fn_private_data;
knet_h->dst_host_filter_fn = dst_host_filter_fn;
if (knet_h->dst_host_filter_fn) {
log_debug(knet_h, KNET_SUB_HANDLE, "dst_host_filter_fn enabled");
} else {
log_debug(knet_h, KNET_SUB_HANDLE, "dst_host_filter_fn disabled");
}
pthread_rwlock_unlock(&knet_h->global_rwlock);
return 0;
}
int knet_handle_setfwd(knet_handle_t knet_h, unsigned int enabled)
{
int savederrno = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if ((enabled < 0) || (enabled > 1)) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
knet_h->enabled = enabled;
if (enabled) {
log_debug(knet_h, KNET_SUB_HANDLE, "Data forwarding is enabled");
} else {
log_debug(knet_h, KNET_SUB_HANDLE, "Data forwarding is disabled");
}
pthread_rwlock_unlock(&knet_h->global_rwlock);
return 0;
}
int knet_handle_pmtud_getfreq(knet_handle_t knet_h, unsigned int *interval)
{
int savederrno = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (!interval) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
*interval = knet_h->pmtud_interval;
pthread_rwlock_unlock(&knet_h->global_rwlock);
return 0;
}
int knet_handle_pmtud_setfreq(knet_handle_t knet_h, unsigned int interval)
{
int savederrno = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if ((!interval) || (interval > 86400)) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
knet_h->pmtud_interval = interval;
log_debug(knet_h, KNET_SUB_HANDLE, "PMTUd interval set to: %u seconds", interval);
pthread_rwlock_unlock(&knet_h->global_rwlock);
return 0;
}
int knet_handle_enable_pmtud_notify(knet_handle_t knet_h,
void *pmtud_notify_fn_private_data,
void (*pmtud_notify_fn) (
void *private_data,
unsigned int data_mtu))
{
int savederrno = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
knet_h->pmtud_notify_fn_private_data = pmtud_notify_fn_private_data;
knet_h->pmtud_notify_fn = pmtud_notify_fn;
if (knet_h->pmtud_notify_fn) {
log_debug(knet_h, KNET_SUB_HANDLE, "pmtud_notify_fn enabled");
} else {
log_debug(knet_h, KNET_SUB_HANDLE, "pmtud_notify_fn disabled");
}
pthread_rwlock_unlock(&knet_h->global_rwlock);
return 0;
}
int knet_handle_pmtud_get(knet_handle_t knet_h,
unsigned int *data_mtu)
{
int savederrno = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (!data_mtu) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
*data_mtu = knet_h->data_mtu;
pthread_rwlock_unlock(&knet_h->global_rwlock);
return 0;
}
int knet_handle_crypto(knet_handle_t knet_h, struct knet_handle_crypto_cfg *knet_handle_crypto_cfg)
{
int savederrno = 0;
int err = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (!knet_handle_crypto_cfg) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
crypto_fini(knet_h);
if ((!strncmp("none", knet_handle_crypto_cfg->crypto_model, 4)) ||
((!strncmp("none", knet_handle_crypto_cfg->crypto_cipher_type, 4)) &&
(!strncmp("none", knet_handle_crypto_cfg->crypto_hash_type, 4)))) {
log_debug(knet_h, KNET_SUB_CRYPTO, "crypto is not enabled");
err = 0;
goto exit_unlock;
}
if (knet_handle_crypto_cfg->private_key_len < KNET_MIN_KEY_LEN) {
log_debug(knet_h, KNET_SUB_CRYPTO, "private key len too short (min %u): %u",
KNET_MIN_KEY_LEN, knet_handle_crypto_cfg->private_key_len);
savederrno = EINVAL;
err = -1;
goto exit_unlock;
}
if (knet_handle_crypto_cfg->private_key_len > KNET_MAX_KEY_LEN) {
log_debug(knet_h, KNET_SUB_CRYPTO, "private key len too long (max %u): %u",
KNET_MAX_KEY_LEN, knet_handle_crypto_cfg->private_key_len);
savederrno = EINVAL;
err = -1;
goto exit_unlock;
}
err = crypto_init(knet_h, knet_handle_crypto_cfg);
if (err) {
err = -2;
}
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
ssize_t knet_recv(knet_handle_t knet_h, char *buff, const size_t buff_len, const int8_t channel)
{
int savederrno = 0;
ssize_t err = 0;
struct iovec iov_in;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (buff == NULL) {
errno = EINVAL;
return -1;
}
if (buff_len <= 0) {
errno = EINVAL;
return -1;
}
if (buff_len > KNET_MAX_PACKET_SIZE) {
errno = EINVAL;
return -1;
}
if (channel < 0) {
errno = EINVAL;
return -1;
}
if (channel >= KNET_DATAFD_MAX) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
if (!knet_h->sockfd[channel].in_use) {
savederrno = EINVAL;
err = -1;
goto out_unlock;
}
memset(&iov_in, 0, sizeof(iov_in));
iov_in.iov_base = (void *)buff;
iov_in.iov_len = buff_len;
err = readv(knet_h->sockfd[channel].sockfd[0], &iov_in, 1);
savederrno = errno;
out_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
ssize_t knet_send(knet_handle_t knet_h, const char *buff, const size_t buff_len, const int8_t channel)
{
int savederrno = 0;
ssize_t err = 0;
struct iovec iov_out[1];
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (buff == NULL) {
errno = EINVAL;
return -1;
}
if (buff_len <= 0) {
errno = EINVAL;
return -1;
}
if (buff_len > KNET_MAX_PACKET_SIZE) {
errno = EINVAL;
return -1;
}
if (channel < 0) {
errno = EINVAL;
return -1;
}
if (channel >= KNET_DATAFD_MAX) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
if (!knet_h->sockfd[channel].in_use) {
savederrno = EINVAL;
err = -1;
goto out_unlock;
}
memset(iov_out, 0, sizeof(iov_out));
iov_out[0].iov_base = (void *)buff;
iov_out[0].iov_len = buff_len;
err = writev(knet_h->sockfd[channel].sockfd[0], iov_out, 1);
savederrno = errno;
out_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
diff --git a/libknet/host.c b/libknet/host.c
index 0370b467..968c4324 100644
--- a/libknet/host.c
+++ b/libknet/host.c
@@ -1,698 +1,698 @@
/*
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
*
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
* Federico Simoncelli <fsimon@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include "host.h"
#include "internals.h"
#include "logging.h"
static void _host_list_update(knet_handle_t knet_h)
{
struct knet_host *host;
knet_h->host_ids_entries = 0;
for (host = knet_h->host_head; host != NULL; host = host->next) {
knet_h->host_ids[knet_h->host_ids_entries] = host->host_id;
knet_h->host_ids_entries++;
}
}
-int knet_host_add(knet_handle_t knet_h, uint16_t host_id)
+int knet_host_add(knet_handle_t knet_h, uint8_t host_id)
{
int savederrno = 0, err = 0;
struct knet_host *host = NULL;
uint8_t link_idx;
if (!knet_h) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HOST, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
if (knet_h->host_index[host_id]) {
err = -1;
savederrno = EEXIST;
log_err(knet_h, KNET_SUB_HOST, "Unable to add host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
host = malloc(sizeof(struct knet_host));
if (!host) {
err = -1;
savederrno = errno;
log_err(knet_h, KNET_SUB_HOST, "Unable to allocate memory for host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
memset(host, 0, sizeof(struct knet_host));
/*
* set host_id
*/
host->host_id = host_id;
/*
* set default host->name to host_id for logging
*/
snprintf(host->name, KNET_MAX_HOST_LEN - 1, "%u", host_id);
/*
* initialize links internal data
*/
for (link_idx = 0; link_idx < KNET_MAX_LINK; link_idx++) {
host->link[link_idx].link_id = link_idx;
}
/*
* add new host to the index
*/
knet_h->host_index[host_id] = host;
/*
* add new host to host list
*/
if (knet_h->host_head) {
host->next = knet_h->host_head;
}
knet_h->host_head = host;
_host_list_update(knet_h);
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
if (err < 0) {
free(host);
}
errno = savederrno;
return err;
}
-int knet_host_remove(knet_handle_t knet_h, uint16_t host_id)
+int knet_host_remove(knet_handle_t knet_h, uint8_t host_id)
{
int savederrno = 0, err = 0;
struct knet_host *host, *removed;
uint8_t link_idx;
if (!knet_h) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HOST, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
host = knet_h->host_index[host_id];
if (!host) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_HOST, "Unable to remove host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
/*
* if links are configured we cannot release the host
*/
for (link_idx = 0; link_idx < KNET_MAX_LINK; link_idx++) {
if (host->link[link_idx].configured) {
err = -1;
savederrno = EBUSY;
log_err(knet_h, KNET_SUB_HOST, "Unable to remove host %u, links are still configured: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
}
removed = NULL;
/*
* removing host from list
*/
if (knet_h->host_head->host_id == host_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->host_id == host_id) {
removed = host->next;
host->next = removed->next;
break;
}
}
}
knet_h->host_index[host_id] = NULL;
free(removed);
_host_list_update(knet_h);
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
-int knet_host_set_name(knet_handle_t knet_h, uint16_t host_id, const char *name)
+int knet_host_set_name(knet_handle_t knet_h, uint8_t host_id, const char *name)
{
int savederrno = 0, err = 0;
struct knet_host *host;
if (!knet_h) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HOST, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
if (!knet_h->host_index[host_id]) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_HOST, "Unable to find host %u to set name: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
if (!name) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_HOST, "Unable to set name for host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
if (strlen(name) >= KNET_MAX_HOST_LEN) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_HOST, "Requested name for host %u is too long: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
for (host = knet_h->host_head; host != NULL; host = host->next) {
if (!strncmp(host->name, name, KNET_MAX_HOST_LEN - 1)) {
err = -1;
savederrno = EEXIST;
log_err(knet_h, KNET_SUB_HOST, "Duplicated name found on host_id %u",
host->host_id);
goto exit_unlock;
}
}
snprintf(knet_h->host_index[host_id]->name, KNET_MAX_HOST_LEN - 1, "%s", name);
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
-int knet_host_get_name_by_host_id(knet_handle_t knet_h, uint16_t host_id,
+int knet_host_get_name_by_host_id(knet_handle_t knet_h, uint8_t host_id,
char *name)
{
int savederrno = 0, err = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (!name) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HOST, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
if (!knet_h->host_index[host_id]) {
savederrno = EINVAL;
err = -1;
log_debug(knet_h, KNET_SUB_HOST, "Host %u not found", host_id);
goto exit_unlock;
}
snprintf(name, KNET_MAX_HOST_LEN - 1, "%s", knet_h->host_index[host_id]->name);
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
int knet_host_get_id_by_host_name(knet_handle_t knet_h, const char *name,
- uint16_t *host_id)
+ uint8_t *host_id)
{
int savederrno = 0, err = 0, found = 0;
struct knet_host *host;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (!name) {
errno = EINVAL;
return -1;
}
if (!host_id) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HOST, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
for (host = knet_h->host_head; host != NULL; host = host->next) {
if (!strncmp(name, host->name, KNET_MAX_HOST_LEN)) {
found = 1;
*host_id = host->host_id;
break;
}
}
if (!found) {
savederrno = ENOENT;
err = -1;
}
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
int knet_host_get_host_list(knet_handle_t knet_h,
- uint16_t *host_ids, size_t *host_ids_entries)
+ uint8_t *host_ids, size_t *host_ids_entries)
{
int savederrno = 0, err = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if ((!host_ids) || (!host_ids_entries)) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HOST, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
memmove(host_ids, knet_h->host_ids, sizeof(knet_h->host_ids));
*host_ids_entries = knet_h->host_ids_entries;
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
-int knet_host_set_policy(knet_handle_t knet_h, uint16_t host_id,
+int knet_host_set_policy(knet_handle_t knet_h, uint8_t host_id,
uint8_t policy)
{
int savederrno = 0, err = 0;
uint8_t old_policy;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (policy > KNET_LINK_POLICY_RR) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HOST, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
if (!knet_h->host_index[host_id]) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_HOST, "Unable to set name for host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
old_policy = knet_h->host_index[host_id]->link_handler_policy;
knet_h->host_index[host_id]->link_handler_policy = policy;
if (_host_dstcache_update_async(knet_h, knet_h->host_index[host_id])) {
savederrno = errno;
err = -1;
knet_h->host_index[host_id]->link_handler_policy = old_policy;
log_debug(knet_h, KNET_SUB_HOST, "Unable to update switch cache for host %u: %s",
host_id, strerror(savederrno));
}
log_debug(knet_h, KNET_SUB_HOST, "Host %u has new switching policy: %u", host_id, policy);
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
-int knet_host_get_policy(knet_handle_t knet_h, uint16_t host_id,
+int knet_host_get_policy(knet_handle_t knet_h, uint8_t host_id,
uint8_t *policy)
{
int savederrno = 0, err = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (!policy) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HOST, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
if (!knet_h->host_index[host_id]) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_HOST, "Unable to get name for host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
*policy = knet_h->host_index[host_id]->link_handler_policy;
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
-int knet_host_get_status(knet_handle_t knet_h, uint16_t host_id,
+int knet_host_get_status(knet_handle_t knet_h, uint8_t host_id,
struct knet_host_status *status)
{
int savederrno = 0, err = 0;
struct knet_host *host;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (!status) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HOST, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
host = knet_h->host_index[host_id];
if (!host) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_HOST, "Unable to find host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
memmove(status, &host->status, sizeof(struct knet_host_status));
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
int knet_host_enable_status_change_notify(knet_handle_t knet_h,
void *host_status_change_notify_fn_private_data,
void (*host_status_change_notify_fn) (
void *private_data,
- uint16_t host_id,
+ uint8_t host_id,
uint8_t reachable,
uint8_t remote,
uint8_t external))
{
int savederrno = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_HOST, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
knet_h->host_status_change_notify_fn_private_data = host_status_change_notify_fn_private_data;
knet_h->host_status_change_notify_fn = host_status_change_notify_fn;
if (knet_h->host_status_change_notify_fn) {
log_debug(knet_h, KNET_SUB_HOST, "host_status_change_notify_fn enabled");
} else {
log_debug(knet_h, KNET_SUB_HOST, "host_status_change_notify_fn disabled");
}
pthread_rwlock_unlock(&knet_h->global_rwlock);
return 0;
}
int _send_host_info(knet_handle_t knet_h, const void *data, const size_t datalen)
{
if (knet_h->fini_in_progress) {
return 0;
}
if (sendto(knet_h->hostsockfd[1], data, datalen, MSG_DONTWAIT | MSG_NOSIGNAL, NULL, 0) != datalen) {
log_debug(knet_h, KNET_SUB_HOST, "Unable to write data to hostpipe");
return -1;
}
return 0;
}
static void _clear_cbuffers(struct knet_host *host, seq_num_t rx_seq_num)
{
int i;
memset(host->circular_buffer, 0, KNET_CBUFFER_SIZE);
host->rx_seq_num = rx_seq_num;
memset(host->circular_buffer_defrag, 0, KNET_CBUFFER_SIZE);
for (i = 0; i < KNET_MAX_LINK; i++) {
memset(&host->defrag_buf[i], 0, sizeof(struct knet_host_defrag_buf));
}
}
/*
* check if a given packet seq num is in the circular buffers
* defrag_buf = 0 -> use normal cbuf 1 -> use the defrag buffer lookup
*/
int _seq_num_lookup(struct knet_host *host, seq_num_t seq_num, int defrag_buf, int clear_buf)
{
size_t i, j; /* circular buffer indexes */
seq_num_t seq_dist;
char *dst_cbuf = host->circular_buffer;
char *dst_cbuf_defrag = host->circular_buffer_defrag;
seq_num_t *dst_seq_num = &host->rx_seq_num;
if (clear_buf) {
_clear_cbuffers(host, seq_num);
}
if (seq_num < *dst_seq_num) {
seq_dist = (SEQ_MAX - seq_num) + *dst_seq_num;
} else {
seq_dist = *dst_seq_num - seq_num;
}
j = seq_num % KNET_CBUFFER_SIZE;
if (seq_dist < KNET_CBUFFER_SIZE) { /* seq num is in ring buffer */
if (!defrag_buf) {
return (dst_cbuf[j] == 0) ? 1 : 0;
} else {
return (dst_cbuf_defrag[j] == 0) ? 1 : 0;
}
} else if (seq_dist <= SEQ_MAX - KNET_CBUFFER_SIZE) {
memset(dst_cbuf, 0, KNET_CBUFFER_SIZE);
memset(dst_cbuf_defrag, 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);
memset(dst_cbuf_defrag + i, 0, KNET_CBUFFER_SIZE - i);
memset(dst_cbuf_defrag, 0, j + 1);
} else {
memset(dst_cbuf + i, 0, j - i + 1);
memset(dst_cbuf_defrag + i, 0, j - i + 1);
}
*dst_seq_num = seq_num;
return 1;
}
void _seq_num_set(struct knet_host *host, seq_num_t seq_num, int defrag_buf)
{
if (!defrag_buf) {
host->circular_buffer[seq_num % KNET_CBUFFER_SIZE] = 1;
} else {
host->circular_buffer_defrag[seq_num % KNET_CBUFFER_SIZE] = 1;
}
return;
}
int _host_dstcache_update_async(knet_handle_t knet_h, struct knet_host *host)
{
int savederrno = 0;
- uint16_t host_id = host->host_id;
+ uint8_t host_id = host->host_id;
if (sendto(knet_h->dstsockfd[1], &host_id, sizeof(host_id), MSG_DONTWAIT | MSG_NOSIGNAL, NULL, 0) != sizeof(host_id)) {
savederrno = errno;
log_debug(knet_h, KNET_SUB_HOST, "Unable to write to dstpipefd[1]: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
return 0;
}
int _host_dstcache_update_sync(knet_handle_t knet_h, struct knet_host *host)
{
int link_idx;
int best_priority = -1;
int reachable = 0;
host->active_link_entries = 0;
for (link_idx = 0; link_idx < KNET_MAX_LINK; link_idx++) {
if (host->link[link_idx].status.enabled != 1) /* link is not enabled */
continue;
if (host->link[link_idx].status.connected != 1) /* link is not enabled */
continue;
if (host->link[link_idx].has_valid_mtu != 1) /* link does not have valid MTU */
continue;
if (host->link_handler_policy == KNET_LINK_POLICY_PASSIVE) {
/* for passive we look for the only active link with higher priority */
if (host->link[link_idx].priority > best_priority) {
host->active_links[0] = link_idx;
best_priority = host->link[link_idx].priority;
}
host->active_link_entries = 1;
} else {
/* for RR and ACTIVE we need to copy all available links */
host->active_links[host->active_link_entries] = link_idx;
host->active_link_entries++;
}
}
if (host->link_handler_policy == KNET_LINK_POLICY_PASSIVE) {
log_debug(knet_h, KNET_SUB_HOST, "host: %u (passive) best link: %u (pri: %u)",
host->host_id, host->link[host->active_links[0]].link_id,
host->link[host->active_links[0]].priority);
} else {
log_debug(knet_h, KNET_SUB_HOST, "host: %u has %u active links",
host->host_id, host->active_link_entries);
}
/* no active links, we can clean the circular buffers and indexes */
if (!host->active_link_entries) {
log_warn(knet_h, KNET_SUB_HOST, "host: %u has no active links", host->host_id);
_clear_cbuffers(host, 0);
} else {
reachable = 1;
}
if (host->status.reachable != reachable) {
host->status.reachable = reachable;
if (knet_h->host_status_change_notify_fn) {
knet_h->host_status_change_notify_fn(
knet_h->host_status_change_notify_fn_private_data,
host->host_id,
host->status.reachable,
host->status.remote,
host->status.external);
}
}
return 0;
}
diff --git a/libknet/internals.h b/libknet/internals.h
index 60cb0512..2bd917e8 100644
--- a/libknet/internals.h
+++ b/libknet/internals.h
@@ -1,462 +1,462 @@
/*
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
*
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
* Federico Simoncelli <fsimon@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#ifndef __INTERNALS_H__
#define __INTERNALS_H__
/*
* NOTE: you shouldn't need to include this header normally
*/
#include "libknet.h"
#include "onwire.h"
#include "compat.h"
#define KNET_DATABUFSIZE KNET_MAX_PACKET_SIZE + KNET_HEADER_ALL_SIZE
#define KNET_DATABUFSIZE_CRYPT_PAD 1024
#define KNET_DATABUFSIZE_CRYPT KNET_DATABUFSIZE + KNET_DATABUFSIZE_CRYPT_PAD
#define KNET_RING_RCVBUFF 8388608
#define PCKT_FRAG_MAX UINT8_MAX
#define KNET_EPOLL_MAX_EVENTS KNET_DATAFD_MAX
typedef void *knet_transport_link_t; /* per link transport handle */
typedef void *knet_transport_t; /* per knet_h transport handle */
struct knet_transport_ops; /* Forward because of circular dependancy */
struct knet_link {
/* required */
struct sockaddr_storage src_addr;
struct sockaddr_storage dst_addr;
/* configurable */
unsigned int dynamic; /* see KNET_LINK_DYN_ define above */
uint8_t priority; /* higher priority == preferred for A/P */
unsigned long long ping_interval; /* interval */
unsigned long long pong_timeout; /* timeout */
unsigned int latency_fix; /* precision */
uint8_t pong_count; /* how many ping/pong to send/receive before link is up */
/* status */
struct knet_link_status status;
/* internals */
uint8_t link_id;
uint8_t transport_type; /* #defined constant from API */
knet_transport_link_t transport_link; /* link_info_t from transport */
int outsock;
unsigned int configured:1; /* set to 1 if src/dst have been configured transport initialized on this link*/
unsigned int transport_connected:1; /* set to 1 if lower level transport is connected */
unsigned int latency_exp;
uint8_t received_pong;
struct timespec ping_last;
/* used by PMTUD thread as temp per-link variables and should always contain the onwire_len value! */
uint32_t proto_overhead;
struct timespec pmtud_last;
uint32_t last_ping_size;
uint32_t last_good_mtu;
uint32_t last_bad_mtu;
uint32_t last_sent_mtu;
uint32_t last_recv_mtu;
uint8_t has_valid_mtu;
};
#define KNET_CBUFFER_SIZE 4096
struct knet_host_defrag_buf {
char buf[KNET_DATABUFSIZE];
uint8_t in_use; /* 0 buffer is free, 1 is in use */
seq_num_t pckt_seq; /* identify the pckt we are receiving */
uint8_t frag_recv; /* how many frags did we receive */
uint8_t frag_map[PCKT_FRAG_MAX];/* bitmap of what we received? */
uint8_t last_first; /* special case if we receive the last fragment first */
uint16_t frag_size; /* normal frag size (not the last one) */
uint16_t last_frag_size; /* the last fragment might not be aligned with MTU size */
struct timespec last_update; /* keep time of the last pckt */
};
struct knet_host {
/* required */
- uint16_t host_id;
+ uint8_t host_id;
/* configurable */
uint8_t link_handler_policy;
char name[KNET_MAX_HOST_LEN];
/* status */
struct knet_host_status status;
/* internals */
char circular_buffer[KNET_CBUFFER_SIZE];
seq_num_t rx_seq_num;
seq_num_t untimed_rx_seq_num;
seq_num_t timed_rx_seq_num;
uint8_t got_data;
/* defrag/reassembly buffers */
struct knet_host_defrag_buf defrag_buf[KNET_MAX_LINK];
char circular_buffer_defrag[KNET_CBUFFER_SIZE];
/* link stuff */
struct knet_link link[KNET_MAX_LINK];
uint8_t active_link_entries;
uint8_t active_links[KNET_MAX_LINK];
struct knet_host *next;
};
struct knet_sock {
int sockfd[2]; /* sockfd[0] will always be application facing
* and sockfd[1] internal if sockpair has been created by knet */
int is_socket; /* check if it's a socket for recvmmsg usage */
int is_created; /* knet created this socket and has to clean up on exit/del */
int in_use; /* set to 1 if it's use, 0 if free */
int has_error; /* set to 1 if there were errors reading from the sock
* and socket has been removed from epoll */
};
struct knet_fd_trackers {
uint8_t transport; /* transport type (UDP/SCTP...) */
uint8_t data_type; /* internal use for transport to define what data are associated
* to this fd */
void *data; /* pointer to the data */
};
#define KNET_MAX_FDS KNET_MAX_HOST * KNET_MAX_LINK * 4
struct knet_handle {
- uint16_t host_id;
+ uint8_t host_id;
unsigned int enabled:1;
struct knet_sock sockfd[KNET_DATAFD_MAX];
int logfd;
uint8_t log_levels[KNET_MAX_SUBSYSTEMS];
int hostsockfd[2];
int dstsockfd[2];
int send_to_links_epollfd;
int recv_from_links_epollfd;
int dst_link_handler_epollfd;
unsigned int pmtud_interval;
unsigned int data_mtu; /* contains the max data size that we can send onwire
* without frags */
struct knet_host *host_head;
struct knet_host *host_index[KNET_MAX_HOST];
knet_transport_t transports[KNET_MAX_TRANSPORTS+1];
struct knet_transport_ops *transport_ops[KNET_MAX_TRANSPORTS+1];
struct knet_fd_trackers knet_transport_fd_tracker[KNET_MAX_FDS]; /* track status for each fd handled by transports */
- uint16_t host_ids[KNET_MAX_HOST];
- size_t host_ids_entries;
+ uint8_t host_ids[KNET_MAX_HOST];
+ size_t host_ids_entries;
struct knet_header *recv_from_sock_buf[PCKT_FRAG_MAX];
struct knet_header *send_to_links_buf[PCKT_FRAG_MAX];
struct knet_header *recv_from_links_buf[PCKT_FRAG_MAX];
struct knet_header *pingbuf;
struct knet_header *pmtudbuf;
pthread_t send_to_links_thread;
pthread_t recv_from_links_thread;
pthread_t heartbt_thread;
pthread_t dst_link_handler_thread;
pthread_t pmtud_link_handler_thread;
int lock_init_done;
pthread_rwlock_t global_rwlock; /* global config lock */
pthread_mutex_t pmtud_mutex; /* pmtud mutex to handle conditional send/recv + timeout */
pthread_cond_t pmtud_cond; /* conditional for above */
pthread_mutex_t tx_mutex; /* used to protect knet_send_sync and TX thread */
pthread_mutex_t hb_mutex; /* used to protect heartbeat thread and seq_num broadcasting */
struct crypto_instance *crypto_instance;
uint16_t sec_header_size;
uint16_t sec_block_size;
uint16_t sec_hash_size;
uint16_t sec_salt_size;
unsigned char *send_to_links_buf_crypt[PCKT_FRAG_MAX];
unsigned char *recv_from_links_buf_crypt;
unsigned char *recv_from_links_buf_decrypt;
unsigned char *pingbuf_crypt;
unsigned char *pmtudbuf_crypt;
seq_num_t tx_seq_num;
pthread_mutex_t tx_seq_num_mutex;
void *dst_host_filter_fn_private_data;
int (*dst_host_filter_fn) (
void *private_data,
const unsigned char *outdata,
ssize_t outdata_len,
uint8_t tx_rx,
- uint16_t this_host_id,
- uint16_t src_node_id,
+ uint8_t this_host_id,
+ uint8_t src_node_id,
int8_t *channel,
- uint16_t *dst_host_ids,
+ uint8_t *dst_host_ids,
size_t *dst_host_ids_entries);
void *pmtud_notify_fn_private_data;
void (*pmtud_notify_fn) (
void *private_data,
unsigned int data_mtu);
void *host_status_change_notify_fn_private_data;
void (*host_status_change_notify_fn) (
void *private_data,
- uint16_t host_id,
+ uint8_t host_id,
uint8_t reachable,
uint8_t remote,
uint8_t external);
void *sock_notify_fn_private_data;
void (*sock_notify_fn) (
void *private_data,
int datafd,
int8_t channel,
uint8_t tx_rx,
int error,
int errorno);
int fini_in_progress;
};
/*
* NOTE: every single operation must be implementend
* for every protocol.
*/
typedef struct knet_transport_ops {
/*
* transport generic information
*/
const char *transport_name;
const uint8_t transport_id;
uint32_t transport_mtu_overhead;
/*
* transport init must allocate the new transport
* and perform all internal initializations
* (threads, lists, etc).
*/
int (*transport_init)(knet_handle_t knet_h);
/*
* transport free must releases _all_ resources
* allocated by tranport_init
*/
int (*transport_free)(knet_handle_t knet_h);
/*
* link operations should take care of all the
* sockets and epoll management for a given link/transport set
* transport_link_disable should return err = -1 and errno = EBUSY
* if listener is still in use, and any other errno in case
* the link cannot be disabled.
*
* set_config/clear_config are invoked in global write lock context
*/
int (*transport_link_set_config)(knet_handle_t knet_h, struct knet_link *link);
int (*transport_link_clear_config)(knet_handle_t knet_h, struct knet_link *link);
/*
* transport callback for incoming dynamic connections
* this is called in global read lock context
*/
int (*transport_link_dyn_connect)(knet_handle_t knet_h, int sockfd, struct knet_link *link);
/*
* per transport error handling of recvmmsg
* (see _handle_recv_from_links comments for details)
*/
/*
* transport_rx_sock_error is invoked when recvmmsg returns <= 0
*
* transport_rx_sock_error is invoked with both global_rdlock
*/
int (*transport_rx_sock_error)(knet_handle_t knet_h, int sockfd, int recv_err, int recv_errno);
/*
* transport_tx_sock_error is invoked with global_rwlock and
* it's invoked when sendto or sendmmsg returns =< 0
*
* it should return:
* -1 on internal error
* 0 ignore error and continue
* 1 retry
* any sleep or wait action should happen inside the transport code
*/
int (*transport_tx_sock_error)(knet_handle_t knet_h, int sockfd, int recv_err, int recv_errno);
/*
* this function is called on _every_ received packet
* to verify if the packet is data or internal protocol error handling
*
* it should return:
* -1 on error
* 0 packet is not data and we should continue the packet process loop
* 1 packet is not data and we should STOP the packet process loop
* 2 packet is data and should be parsed as such
*
* transport_rx_is_data is invoked with both global_rwlock
* and fd_tracker read lock (from RX thread)
*/
int (*transport_rx_is_data)(knet_handle_t knet_h, int sockfd, struct mmsghdr *msg);
} knet_transport_ops_t;
socklen_t sockaddr_len(const struct sockaddr_storage *ss);
/**
* This is a kernel style list implementation.
*
* @author Steven Dake <sdake@redhat.com>
*/
struct knet_list_head {
struct knet_list_head *next;
struct knet_list_head *prev;
};
/**
* @def KNET_LIST_DECLARE()
* Declare and initialize a list head.
*/
#define KNET_LIST_DECLARE(name) \
struct knet_list_head name = { &(name), &(name) }
#define KNET_INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/**
* Initialize the list entry.
*
* Points next and prev pointers to head.
* @param head pointer to the list head
*/
static inline void knet_list_init(struct knet_list_head *head)
{
head->next = head;
head->prev = head;
}
/**
* Add this element to the list.
*
* @param element the new element to insert.
* @param head pointer to the list head
*/
static inline void knet_list_add(struct knet_list_head *element,
struct knet_list_head *head)
{
head->next->prev = element;
element->next = head->next;
element->prev = head;
head->next = element;
}
/**
* Add to the list (but at the end of the list).
*
* @param element pointer to the element to add
* @param head pointer to the list head
* @see knet_list_add()
*/
static inline void knet_list_add_tail(struct knet_list_head *element,
struct knet_list_head *head)
{
head->prev->next = element;
element->next = head;
element->prev = head->prev;
head->prev = element;
}
/**
* Delete an entry from the list.
*
* @param _remove the list item to remove
*/
static inline void knet_list_del(struct knet_list_head *_remove)
{
_remove->next->prev = _remove->prev;
_remove->prev->next = _remove->next;
}
/**
* Replace old entry by new one
* @param old: the element to be replaced
* @param new: the new element to insert
*/
static inline void knet_list_replace(struct knet_list_head *old,
struct knet_list_head *new)
{
new->next = old->next;
new->next->prev = new;
new->prev = old->prev;
new->prev->next = new;
}
/**
* Tests whether list is the last entry in list head
* @param list: the entry to test
* @param head: the head of the list
* @return boolean true/false
*/
static inline int knet_list_is_last(const struct knet_list_head *list,
const struct knet_list_head *head)
{
return list->next == head;
}
/**
* A quick test to see if the list is empty (pointing to it's self).
* @param head pointer to the list head
* @return boolean true/false
*/
static inline int32_t knet_list_empty(const struct knet_list_head *head)
{
return head->next == head;
}
/**
* Get the struct for this entry
* @param ptr: the &struct list_head pointer.
* @param type: the type of the struct this is embedded in.
* @param member: the name of the list_struct within the struct.
*/
#define knet_list_entry(ptr,type,member)\
((type *)((char *)(ptr)-(char*)(&((type *)0)->member)))
/**
* Get the first element from a list
* @param ptr: the &struct list_head pointer.
* @param type: the type of the struct this is embedded in.
* @param member: the name of the list_struct within the struct.
*/
#define knet_list_first_entry(ptr, type, member) \
knet_list_entry((ptr)->next, type, member)
/**
* Iterate over a list
* @param pos: the &struct list_head to use as a loop counter.
* @param head: the head for your list.
*/
#define knet_list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/**
* Iterate over a list backwards
* @param pos: the &struct list_head to use as a loop counter.
* @param head: the head for your list.
*/
#define knet_list_for_each_reverse(pos, head) \
for (pos = (head)->prev; pos != (head); pos = pos->prev)
/**
* Iterate over a list safe against removal of list entry
* @param pos: the &struct list_head to use as a loop counter.
* @param n: another &struct list_head to use as temporary storage
* @param head: the head for your list.
*/
#define knet_list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/**
* Iterate over list of given type
* @param pos: the type * to use as a loop counter.
* @param head: the head for your list.
* @param member: the name of the list_struct within the struct.
*/
#define knet_list_for_each_entry(pos, head, member) \
for (pos = knet_list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = knet_list_entry(pos->member.next, typeof(*pos), member))
#endif
diff --git a/libknet/libknet.h b/libknet/libknet.h
index ed4810a6..4ddfa48e 100644
--- a/libknet/libknet.h
+++ b/libknet/libknet.h
@@ -1,1462 +1,1462 @@
/*
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
*
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
* Federico Simoncelli <fsimon@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#ifndef __LIBKNET_H__
#define __LIBKNET_H__
#include <stdint.h>
#include <netinet/in.h>
/*
* libknet limits
*/
/*
* Maximum number of hosts
*/
-#define KNET_MAX_HOST 65536
+#define KNET_MAX_HOST 256
/*
* Maximum number of links between 2 hosts
*/
#define KNET_MAX_LINK 8
/*
* Maximum packet size that should be written to datafd
* see knet_handle_new for details
*/
#define KNET_MAX_PACKET_SIZE 65536
/*
* Buffers used for pretty logging
* host is used to store both ip addresses and hostnames
*/
#define KNET_MAX_HOST_LEN 256
#define KNET_MAX_PORT_LEN 6
/*
* Some notifications can be generated either on TX or RX
*/
#define KNET_NOTIFY_TX 0
#define KNET_NOTIFY_RX 1
typedef struct knet_handle *knet_handle_t;
/*
* Handle structs/API calls
*/
/*
* knet_handle_new
*
* host_id - Each host in a knet is identified with a unique
* ID. when creating a new handle local host_id
* must be specified (0 to UINT16T_MAX are all valid).
* It is the user's responsibility to check that the value
* is unique, or bad things might happen.
*
* log_fd - Write file descriptor. If set to a value > 0, it will be used
* to write log packets (see below) from libknet to the application.
* Setting to 0 will disable logging from libknet.
* It is possible to enable logging at any given time (see logging API
* below).
* Make sure to either read from this filedescriptor properly and/or
* mark it O_NONBLOCK, otherwise if the fd becomes full, libknet could
* block.
*
* default_log_level -
* If logfd is specified, it will initialize all subsystems to log
* at default_log_level value. (see logging API below)
*
* on success, a new knet_handle_t is returned.
* on failure, NULL is returned and errno is set.
*/
-knet_handle_t knet_handle_new(uint16_t host_id,
+knet_handle_t knet_handle_new(uint8_t host_id,
int log_fd,
uint8_t default_log_level);
/*
* knet_handle_free
*
* knet_h - pointer to knet_handle_t
*
* Destroy a knet handle, free all resources
*
* knet_handle_free returns:
*
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_free(knet_handle_t knet_h);
/*
* knet_handle_enable_sock_notify
*
* knet_h - pointer to knet_handle_t
*
* sock_notify_fn_private_data
* void pointer to data that can be used to identify
* the callback.
*
* sock_notify_fn
* A callback function that is invoked every time
* a socket in the datafd pool will report an error (-1)
* or an end of read (0) (see socket.7).
* This function MUST NEVER block or add substantial delays.
* The callback is invoked in an internal unlocked area
* to allow calls to knet_handle_add_datafd/knet_handle_remove_datafd
* to swap/replace the bad fd.
* if both err and errno are 0, it means that the socket
* has received a 0 byte packet (EOF?).
* The callback function must either remove the fd from knet
* (by calling knet_handle_remove_fd()) or dup a new fd in its place.
* Failure to do this can cause problems.
*
* knet_handle_enable_sock_notify returns:
*
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_enable_sock_notify(knet_handle_t knet_h,
void *sock_notify_fn_private_data,
void (*sock_notify_fn) (
void *private_data,
int datafd,
int8_t channel,
uint8_t tx_rx,
int error,
int errorno)); /* sorry! can't call it errno ;) */
/*
* knet_handle_add_datafd
*
* IMPORTANT: In order to add datafd to knet, knet_handle_enable_sock_notify
* _MUST_ be set and be able to handle both errors (-1) and
* 0 bytes read / write from the provided datafd.
* On read error (< 0) from datafd, the socket is automatically
* removed from polling to avoid spinning on dead sockets.
* It is safe to call knet_handle_remove_datafd even on sockets
* that have been removed.
*
* knet_h - pointer to knet_handle_t
*
* *datafd - read/write file descriptor.
* knet will read data here to send to the other hosts
* and will write data received from the network.
* Each data packet can be of max size KNET_MAX_PACKET_SIZE!
* Applications using knet_send/knet_recv will receive a
* proper error if the packet size is not within boundaries.
* Applications using their own functions to write to the
* datafd should NOT write more than KNET_MAX_PACKET_SIZE.
*
* Please refer to handle.c on how to set up a socketpair.
*
* datafd can be 0, and knet_handle_add_datafd will create a properly
* populated socket pair the same way as ping_test, or a value
* higher than 0. A negative number will return an error.
* On exit knet_handle_free will take care to cleanup the
* socketpair only if they have been created by knet_handle_add_datafd.
*
* It is possible to pass either sockets or normal fds.
* User provided datafd will be marked as non-blocking and close-on-exit.
*
* *channel - This value has the same effect of VLAN tagging.
* A negative value will auto-allocate a channel.
* Setting a value between 0 and 31 will try to allocate that
* specific channel (unless already in use).
*
* It is possible to add up to 32 datafds but be aware that each
* one of them must have a receiving end on the other host.
*
* Example:
* hostA channel 0 will be delivered to datafd on hostB channel 0
* hostA channel 1 to hostB channel 1.
*
* Each channel must have a unique file descriptor.
*
* If your application could have 2 channels on one host and one
* channel on another host, then you can use dst_host_filter
* to manipulate channel values on TX and RX.
*
* knet_handle_add_datafd returns:
*
* 0 on success
* *datafd will be populated with a socket if the original value was 0
* or if a specific fd was set, the value is untouched.
* *channel will be populated with a channel number if the original value
* was negative or the value is untouched if a specific channel
* was requested.
*
* -1 on error and errno is set.
* *datafd and *channel are untouched or empty.
*/
#define KNET_DATAFD_MAX 32
int knet_handle_add_datafd(knet_handle_t knet_h, int *datafd, int8_t *channel);
/*
* knet_handle_remove_datafd
*
* knet_h - pointer to knet_handle_t
*
* datafd - file descriptor to remove.
* NOTE that if the socket/fd was created by knet_handle_add_datafd,
* the socket will be closed by libknet.
*
* knet_handle_remove_datafd returns:
*
* 0 on success
*
* -1 on error and errno is set.
*/
int knet_handle_remove_datafd(knet_handle_t knet_h, int datafd);
/*
* knet_handle_enable_sock_notify
*
* knet_h - pointer to knet_handle_t
*
* sock_notify_fn_private_data
* void pointer to data that can be used to identify
* the callback.
*
* sock_notify_fn
* A callback function that is invoked every time
* a socket in the datafd pool will report an error (-1)
* or an end of read (0) (see socket.7).
* This function MUST NEVER block or add substantial delays.
* The callback is invoked in an internal unlocked area
* to allow calls to knet_handle_add_datafd/knet_handle_remove_datafd
* to swap/replace the bad fd.
* if both err and errno are 0, it means that the socket
* has received a 0 byte packet (EOF?).
* The callback function must either remove the fd from knet
* (by calling knet_handle_remove_fd()) or dup a new fd in its place.
* Failure to do this can cause problems.
*
* knet_handle_enable_sock_notify returns:
*
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_get_channel(knet_handle_t knet_h, const int datafd, int8_t *channel);
/*
* knet_handle_get_datafd
*
* knet_h - pointer to knet_handle_t
*
* channel - get the datafd associated to this channel
*
* *datafd - will contain the result
*
* knet_handle_get_datafd returns:
*
* 0 on success
* and *datafd will contain the results
*
* -1 on error and errno is set.
* and *datafd content is meaningless
*/
int knet_handle_get_datafd(knet_handle_t knet_h, const int8_t channel, int *datafd);
/*
* knet_recv
*
* knet_h - pointer to knet_handle_t
*
* buff - pointer to buffer to store the received data
*
* buff_len - buffer lenght
*
* knet_recv is a commodity function to wrap iovec operations
* around a socket. It returns a call to readv(2).
*/
ssize_t knet_recv(knet_handle_t knet_h,
char *buff,
const size_t buff_len,
const int8_t channel);
/*
* knet_send
*
* knet_h - pointer to knet_handle_t
*
* buff - pointer to the buffer of data to send
*
* buff_len - length of data to send
*
* knet_send is a commodity function to wrap iovec operations
* around a socket. It returns a call to writev(2).
*/
ssize_t knet_send(knet_handle_t knet_h,
const char *buff,
const size_t buff_len,
const int8_t channel);
/*
* knet_send_sync
*
* knet_h - pointer to knet_handle_t
*
* buff - pointer to the buffer of data to send
*
* buff_len - length of data to send
*
* channel - data channel to use (see knet_handle_add_datafd)
*
* All knet RX/TX operations are async for performance reasons.
* There are applications that might need a sync version of data
* transmission and receive errors in case of failure to deliver
* to another host.
* knet_send_sync bypasses the whole TX async layer and delivers
* data directly to the link layer, and returns errors accordingly.
* knet_send_sync allows to send only one packet to one host at
* a time. It does NOT support multiple destinations or multicast
* packets. Decision is still based on dst_host_filter_fn.
*
* knet_send_sync returns 0 on success and -1 on error.
*
* In addition to normal sendmmsg errors, knet_send_sync can fail
* due to:
*
* ECANCELED - data forward is disabled
* EFAULT - dst_host_filter fatal error
* EINVAL - dst_host_filter did not provide
* dst_host_ids_entries on unicast pckts
* E2BIG - dst_host_filter did return more than one
* dst_host_ids_entries on unicast pckts
* ENOMSG - received unknown message type
* EHOSTDOWN - unicast pckt cannot be delivered because
* dest host is not connected yet
* ECHILD - crypto failed
* EAGAIN - sendmmsg was unable to send all messages and
* there was no progress during retry
*/
int knet_send_sync(knet_handle_t knet_h,
const char *buff,
const size_t buff_len,
const int8_t channel);
/*
* knet_handle_enable_filter
*
* knet_h - pointer to knet_handle_t
*
* dst_host_filter_fn_private_data
* void pointer to data that can be used to identify
* the callback.
*
* dst_host_filter_fn -
* is a callback function that is invoked every time
* a packet hits datafd (see knet_handle_new).
* the function allows users to tell libknet where the
* packet has to be delivered.
*
* const unsigned char *outdata - is a pointer to the
* current packet
* ssize_t outdata_len - lenght of the above data
* uint8_t tx_rx - filter is called on tx or rx
* (see defines below)
- * uint16_t this_host_id - host_id processing the packet
- * uint16_t src_host_id - host_id that generated the
+ * uint8_t this_host_id - host_id processing the packet
+ * uint8_t src_host_id - host_id that generated the
* packet
- * uint16_t *dst_host_ids - array of KNET_MAX_HOST uint16_t
+ * uint8_t *dst_host_ids - array of KNET_MAX_HOST uint8_t
* where to store the destinations
* size_t *dst_host_ids_entries - number of hosts to send the message
*
* dst_host_filter_fn should return
* -1 on error, packet is discarded.
* 0 packet is unicast and should be sent to dst_host_ids and there are
* dst_host_ids_entries in the buffer.
* 1 packet is broadcast/multicast and is sent all hosts.
* contents of dst_host_ids and dst_host_ids_entries are ignored.
* (see also kronosnetd/etherfilter.* for an example that filters based
* on ether protocol)
*
* knet_handle_enable_filter returns:
*
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_enable_filter(knet_handle_t knet_h,
void *dst_host_filter_fn_private_data,
int (*dst_host_filter_fn) (
void *private_data,
const unsigned char *outdata,
ssize_t outdata_len,
uint8_t tx_rx,
- uint16_t this_host_id,
- uint16_t src_host_id,
+ uint8_t this_host_id,
+ uint8_t src_host_id,
int8_t *channel,
- uint16_t *dst_host_ids,
+ uint8_t *dst_host_ids,
size_t *dst_host_ids_entries));
/*
* knet_handle_setfwd
*
* knet_h - pointer to knet_handle_t
*
* enable - set to 1 to allow data forwarding, 0 to disable data forwarding.
*
* knet_handle_setfwd returns:
*
* 0 on success
* -1 on error and errno is set.
*
* By default data forwarding is off and no traffic will pass through knet until
* it is set on.
*/
int knet_handle_setfwd(knet_handle_t knet_h, unsigned int enabled);
/*
* knet_handle_pmtud_setfreq
*
* knet_h - pointer to knet_handle_t
*
* interval - define the interval in seconds between PMTUd scans
* range from 1 to 86400 (24h)
*
* knet_handle_pmtud_setfreq returns:
*
* 0 on success
* -1 on error and errno is set.
*
* default interval is 60.
*/
#define KNET_PMTUD_DEFAULT_INTERVAL 60
int knet_handle_pmtud_setfreq(knet_handle_t knet_h, unsigned int interval);
/*
* knet_handle_pmtud_getfreq
*
* knet_h - pointer to knet_handle_t
*
* interval - pointer where to store the current interval value
*
* knet_handle_pmtud_setfreq returns:
*
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_pmtud_getfreq(knet_handle_t knet_h, unsigned int *interval);
/*
* knet_handle_enable_pmtud_notify
*
* knet_h - pointer to knet_handle_t
*
* pmtud_notify_fn_private_data
* void pointer to data that can be used to identify
* the callback.
*
* pmtud_notify_fn
* is a callback function that is invoked every time
* a path MTU size change is detected.
* The function allows libknet to notify the user
* of data MTU, that's the max value that can be send
* onwire without fragmentation. The data MTU will always
* be lower than real link MTU because it accounts for
* protocol overhead, knet packet header and (if configured)
* crypto overhead,
* This function MUST NEVER block or add substantial delays.
*
* knet_handle_enable_pmtud_notify returns:
*
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_enable_pmtud_notify(knet_handle_t knet_h,
void *pmtud_notify_fn_private_data,
void (*pmtud_notify_fn) (
void *private_data,
unsigned int data_mtu));
/*
* knet_handle_pmtud_get
*
* knet_h - pointer to knet_handle_t
*
* data_mtu - pointer where to store data_mtu (see above)
*
* knet_handle_pmtud_get returns:
*
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_pmtud_get(knet_handle_t knet_h,
unsigned int *data_mtu);
/*
* knet_handle_crypto
*
* knet_h - pointer to knet_handle_t
*
* knet_handle_crypto_cfg -
* pointer to a knet_handle_crypto_cfg structure
*
* crypto_model should contain the model name.
* Currently only "nss" is supported.
* Setting to "none" will disable crypto.
*
* crypto_cipher_type
* should contain the cipher algo name.
* It can be set to "none" to disable
* encryption.
* Currently supported by "nss" model:
* "3des", "aes128", "aes192" and "aes256".
*
* crypto_hash_type
* should contain the hashing algo name.
* It can be set to "none" to disable
* hashing.
* Currently supported by "nss" model:
* "md5", "sha1", "sha256", "sha384" and "sha512".
*
* private_key will contain the private shared key.
* It has to be at least KNET_MIN_KEY_LEN long.
*
* private_key_len
* length of the provided private_key.
*
* Implementation notes/current limitations:
* - enabling crypto, will increase latency as packets have
* to processed.
* - enabling crypto might reduce the overall throughtput
* due to crypto data overhead.
* - re-keying is not implemented yet.
* - private/public key encryption/hashing is not currently
* planned.
* - crypto key must be the same for all hosts in the same
* knet instance.
* - it is safe to call knet_handle_crypto multiple times at runtime.
* The last config will be used.
* IMPORTANT: a call to knet_handle_crypto can fail due to:
* 1) failure to obtain locking
* 2) errors to initializing the crypto level.
* This can happen even in subsequent calls to knet_handle_crypto.
* A failure in crypto init, might leave your traffic unencrypted!
* It's best to stop data forwarding (see above), change crypto config,
* start forward again.
*
* knet_handle_crypto returns:
*
* 0 on success
* -1 on error and errno is set.
* -2 on crypto subsystem initialization error. No errno is provided at the moment (yet).
*/
#define KNET_MIN_KEY_LEN 1024
#define KNET_MAX_KEY_LEN 4096
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);
/*
* host structs/API calls
*/
/*
* knet_host_add
*
* knet_h - pointer to knet_handle_t
*
* host_id - each host in a knet is identified with a unique ID
* (see also knet_handle_new documentation above)
*
* knet_host_add returns:
*
* 0 on success
* -1 on error and errno is set.
*/
-int knet_host_add(knet_handle_t knet_h, uint16_t host_id);
+int knet_host_add(knet_handle_t knet_h, uint8_t host_id);
/*
* knet_host_remove
*
* knet_h - pointer to knet_handle_t
*
* host_id - each host in a knet is identified with a unique ID
* (see also knet_handle_new documentation above)
*
* knet_host_remove returns:
*
* 0 on success
* -1 on error and errno is set.
*/
-int knet_host_remove(knet_handle_t knet_h, uint16_t host_id);
+int knet_host_remove(knet_handle_t knet_h, uint8_t host_id);
/*
* knet_host_set_name
*
* knet_h - pointer to knet_handle_t
*
* host_id - see above
*
* name - this name will be used for pretty logging and eventually
* search for hosts (see also get_name and get_id below).
* Only up to KNET_MAX_HOST_LEN - 1 bytes will be accepted and
* name has to be unique for each host.
*
* knet_host_set_name returns:
*
* 0 on success
* -1 on error and errno is set.
*/
-int knet_host_set_name(knet_handle_t knet_h, uint16_t host_id,
+int knet_host_set_name(knet_handle_t knet_h, uint8_t host_id,
const char *name);
/*
* knet_host_get_name_by_host_id
*
* knet_h - pointer to knet_handle_t
*
* host_id - see above
*
* name - pointer to a preallocated buffer of at least size KNET_MAX_HOST_LEN
* where the current host name will be stored
* (as set by knet_host_set_name or default by knet_host_add)
*
* knet_host_get_name_by_host_id returns:
*
* 0 on success
* -1 on error and errno is set (name is left untouched)
*/
-int knet_host_get_name_by_host_id(knet_handle_t knet_h, uint16_t host_id,
+int knet_host_get_name_by_host_id(knet_handle_t knet_h, uint8_t host_id,
char *name);
/*
* knet_host_get_id_by_host_name
*
* knet_h - pointer to knet_handle_t
*
* name - name to lookup, max len KNET_MAX_HOST_LEN
*
* host_id - where to store the result
*
* knet_host_get_id_by_host_name returns:
*
* 0 on success
* -1 on error and errno is set.
*/
int knet_host_get_id_by_host_name(knet_handle_t knet_h, const char *name,
- uint16_t *host_id);
+ uint8_t *host_id);
/*
* knet_host_get_host_list
*
* knet_h - pointer to knet_handle_t
*
* host_ids - array of at lest KNET_MAX_HOST size
*
* host_ids_entries -
* number of entries writted in host_ids
*
* knet_host_get_host_list returns:
*
* 0 on success
* -1 on error and errno is set.
*/
int knet_host_get_host_list(knet_handle_t knet_h,
- uint16_t *host_ids, size_t *host_ids_entries);
+ uint8_t *host_ids, size_t *host_ids_entries);
/*
* define switching policies
*/
#define KNET_LINK_POLICY_PASSIVE 0
#define KNET_LINK_POLICY_ACTIVE 1
#define KNET_LINK_POLICY_RR 2
/*
* knet_host_set_policy
*
* knet_h - pointer to knet_handle_t
*
* host_id - see above
*
* policy - there are currently 3 kind of simple switching policies
* as defined above, based on link configuration.
* KNET_LINK_POLICY_PASSIVE - the active link with the lowest
* priority will be used.
* if one or more active links share
* the same priority, the one with
* lowest link_id will be used.
*
* KNET_LINK_POLICY_ACTIVE - all active links will be used
* simultaneously to send traffic.
* link priority is ignored.
*
* KNET_LINK_POLICY_RR - round-robin policy, every packet
* will be send on a different active
* link.
*
* knet_host_set_policy returns:
*
* 0 on success
* -1 on error and errno is set.
*/
-int knet_host_set_policy(knet_handle_t knet_h, uint16_t host_id,
+int knet_host_set_policy(knet_handle_t knet_h, uint8_t host_id,
uint8_t policy);
/*
* knet_host_get_policy
*
* knet_h - pointer to knet_handle_t
*
* host_id - see above
*
* policy - will contain the current configured switching policy.
* Default is passive when creating a new host.
*
* knet_host_get_policy returns:
*
* 0 on success
* -1 on error and errno is set.
*/
-int knet_host_get_policy(knet_handle_t knet_h, uint16_t host_id,
+int knet_host_get_policy(knet_handle_t knet_h, uint8_t host_id,
uint8_t *policy);
/*
* knet_host_enable_status_change_notify
*
* 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 the host status.
* host status is identified by:
* - reachable, this host can send/receive data to/from host_id
* - 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.
*
* knet_host_status_change_notify returns:
*
* 0 on success
* -1 on error and errno is set.
*/
int knet_host_enable_status_change_notify(knet_handle_t knet_h,
void *host_status_change_notify_fn_private_data,
void (*host_status_change_notify_fn) (
void *private_data,
- uint16_t host_id,
+ uint8_t host_id,
uint8_t reachable,
uint8_t remote,
uint8_t external));
/*
* define host status structure for quick lookup
* struct is in flux as more stats will be added soon
*
* reachable host_id can be seen either directly connected
* or via another host_id
*
* remote 0 = node is connected locally, 1 is visible via
* via another host_id
*
* external 0 = node is configured/known locally,
* 1 host_id has been received via another host_id
*/
struct knet_host_status {
uint8_t reachable;
uint8_t remote;
uint8_t external;
/* add host statistics */
};
/*
* knet_host_status_get
*
* knet_h - pointer to knet_handle_t
*
* status - pointer to knet_host_status struct (see above)
*
* knet_handle_pmtud_get returns:
*
* 0 on success
* -1 on error and errno is set.
*/
-int knet_host_get_status(knet_handle_t knet_h, uint16_t host_id,
+int knet_host_get_status(knet_handle_t knet_h, uint8_t host_id,
struct knet_host_status *status);
/*
* link structs/API calls
*
* every host allocated/managed by knet_host_* has
* KNET_MAX_LINK structures to define the network
* paths that connect 2 hosts.
*
* Each link is identified by a link_id that has a
* values between 0 and KNET_MAX_LINK - 1.
*
* KNOWN LIMITATIONS:
*
* - let's assume the scenario where two hosts are connected
* with any number of links. link_id must match on both sides.
* If host_id 0 link_id 0 is configured to connect IP1 to IP2 and
* host_id 0 link_id 1 is configured to connect IP3 to IP4,
* host_id 1 link_id 0 _must_ connect IP2 to IP1 and likewise
* host_id 1 link_id 1 _must_ connect IP4 to IP3.
* We might be able to lift this restriction in future, by using
* other data to determine src/dst link_id, but for now, deal with it.
*
* -
*/
/*
* commodity functions to convert strings to sockaddr and viceversa
*/
/*
* knet_strtoaddr
*
* host - IPaddr/hostname to convert
* be aware only the first IP address will be returned
* in case a hostname resolves to multiple IP
*
* port - port to connect to
*
* ss - sockaddr_storage where to store the converted data
*
* sslen - len of the sockaddr_storage
*
* knet_strtoaddr returns same error codes as getaddrinfo
*
*/
int knet_strtoaddr(const char *host, const char *port,
struct sockaddr_storage *ss, socklen_t sslen);
/*
* knet_addrtostr
*
* ss - sockaddr_storage to convert
*
* sslen - len of the sockaddr_storage
*
* host - IPaddr/hostname where to store data
* (recommended size: KNET_MAX_HOST_LEN)
*
* port - port buffer where to store data
* (recommended size: KNET_MAX_PORT_LEN)
*
* knet_strtoaddr returns same error codes as getnameinfo
*
*/
int knet_addrtostr(const struct sockaddr_storage *ss, socklen_t sslen,
char *addr_buf, size_t addr_buf_size,
char *port_buf, size_t port_buf_size);
/*
* knet_handle_get_transport_list
*
* knet_h - pointer to knet_handle_t
*
* transport_list - an array of struct transport_info that must be
* at least of size struct transport_info * KNET_MAX_TRANSPORTS
*
* transport_list_entries - pointer to a size_t where to store how many transports
* are available in this build of libknet.
*
* knet_handle_get_transport_list returns:
*
* 0 on success
* -1 on error and errno is set.
*/
#define KNET_TRANSPORT_UDP 0
#define KNET_TRANSPORT_SCTP 1
#define KNET_MAX_TRANSPORTS 2
struct transport_info {
const char *name; /* UDP/SCTP/etc... */
uint8_t id; /* value that can be used for link_set_config */
uint8_t properties; /* currently unused */
};
int knet_handle_get_transport_list(knet_handle_t knet_h,
struct transport_info *transport_list, size_t *transport_list_entries);
/*
* knet_handle_get_transport_name_by_id
*
* knet_h - pointer to knet_handle_t
*
* transport - one of the above KNET_TRANSPORT_xxx constants
*
* knet_handle_get_transport_name_by_id returns:
*
* pointer to the name on success or
* NULL on error and errno is set.
*/
const char *knet_handle_get_transport_name_by_id(knet_handle_t knet_h, uint8_t transport);
/*
* knet_handle_get_transport_id_by_name
*
* knet_h - pointer to knet_handle_t
*
* name - transport name (UDP/SCTP/etc)
*
* knet_handle_get_transport_name_by_id returns:
*
* KNET_MAX_TRANSPORTS on error and errno is set accordingly
* KNET_TRANSPORT_xxx on success.
*/
uint8_t knet_handle_get_transport_id_by_name(knet_handle_t knet_h, const char *name);
/*
* knet_link_set_config
*
* knet_h - pointer to knet_handle_t
*
* host_id - see above
*
* link_id - see above
*
* transport - one of the above KNET_TRANSPORT_xxx constants
*
* src_addr - sockaddr_storage that can be either IPv4 or IPv6
*
* dst_addr - sockaddr_storage that can be either IPv4 or IPv6
* this can be null if we don't know the incoming
* IP address/port and the link will remain quiet
* till the node on the other end will initiate a
* connection
*
* knet_link_set_config returns:
*
* 0 on success
* -1 on error and errno is set.
*/
-int knet_link_set_config(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_set_config(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
uint8_t transport,
struct sockaddr_storage *src_addr,
struct sockaddr_storage *dst_addr);
/*
* knet_link_get_config
*
* knet_h - pointer to knet_handle_t
*
* host_id - see above
*
* link_id - see above
*
* transport - see above
*
* src_addr - sockaddr_storage that can be either IPv4 or IPv6
*
* dst_addr - sockaddr_storage that can be either IPv4 or IPv6
*
* dynamic - 0 if dst_addr is static or 1 if dst_addr is dynamic.
* In case of 1, dst_addr can be NULL and it will be left
* untouched.
*
* knet_link_get_config returns:
*
* 0 on success.
* -1 on error and errno is set.
*/
-int knet_link_get_config(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_get_config(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
uint8_t *transport,
struct sockaddr_storage *src_addr,
struct sockaddr_storage *dst_addr,
uint8_t *dynamic);
/*
* knet_link_clear_config
*
* knet_h - pointer to knet_handle_t
*
* host_id - see above
*
* link_id - see above
*
* knet_link_clear_config returns:
*
* 0 on success.
* -1 on error and errno is set.
*/
-int knet_link_clear_config(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id);
+int knet_link_clear_config(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id);
/*
* knet_link_set_enable
*
* knet_h - pointer to knet_handle_t
*
* host_id - see above
*
* link_id - see above
*
* enabled - 0 disable the link, 1 enable the link
*
* knet_link_set_enable returns:
*
* 0 on success
* -1 on error and errno is set.
*/
-int knet_link_set_enable(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_set_enable(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
unsigned int enabled);
/*
* knet_link_get_enable
*
* knet_h - pointer to knet_handle_t
*
* host_id - see above
*
* link_id - see above
*
* enabled - 0 disable the link, 1 enable the link
*
* knet_link_get_enable returns:
*
* 0 on success
* -1 on error and errno is set.
*/
-int knet_link_get_enable(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_get_enable(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
unsigned int *enabled);
/*
* knet_link_set_ping_timers
*
* knet_h - pointer to knet_handle_t
*
* host_id - see above
*
* link_id - see above
*
* interval - specify the ping interval
*
* timeout - if no pong is received within this time,
* the link is declared dead
*
* precision - how many values of latency are used to calculate
* the average link latency (see also get_status below)
*
* knet_link_set_ping_timers returns:
*
* 0 on success
* -1 on error and errno is set.
*/
#define KNET_LINK_DEFAULT_PING_INTERVAL 1000 /* 1 second */
#define KNET_LINK_DEFAULT_PING_TIMEOUT 2000 /* 2 seconds */
#define KNET_LINK_DEFAULT_PING_PRECISION 2048 /* samples */
-int knet_link_set_ping_timers(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_set_ping_timers(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
time_t interval, time_t timeout, unsigned int precision);
/*
* knet_link_get_ping_timers
*
* knet_h - pointer to knet_handle_t
*
* host_id - see above
*
* link_id - see above
*
* interval - ping intervall
*
* timeout - if no pong is received within this time,
* the link is declared dead
*
* precision - how many values of latency are used to calculate
* the average link latency (see also get_status below)
*
* knet_link_get_ping_timers returns:
*
* 0 on success
* -1 on error and errno is set.
*/
-int knet_link_get_ping_timers(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_get_ping_timers(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
time_t *interval, time_t *timeout, unsigned int *precision);
/*
* knet_link_set_pong_count
*
* knet_h - pointer to knet_handle_t
*
* host_id - see above
*
* link_id - see above
*
* pong_count - how many valid ping/pongs before a link is marked UP.
* default: 5, value should be > 0
*
* knet_link_set_pong_count returns:
*
* 0 on success
* -1 on error and errno is set.
*/
#define KNET_LINK_DEFAULT_PONG_COUNT 5
-int knet_link_set_pong_count(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_set_pong_count(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
uint8_t pong_count);
/*
* knet_link_get_pong_count
*
* knet_h - pointer to knet_handle_t
*
* host_id - see above
*
* link_id - see above
*
* pong_count - see above
*
* knet_link_get_pong_count returns:
*
* 0 on success
* -1 on error and errno is set.
*/
-int knet_link_get_pong_count(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_get_pong_count(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
uint8_t *pong_count);
/*
* knet_link_set_priority
*
* knet_h - pointer to knet_handle_t
*
* host_id - see above
*
* link_id - see above
*
* priority - specify the switching priority for this link
* see also knet_host_set_policy
*
* knet_link_set_priority returns:
*
* 0 on success
* -1 on error and errno is set.
*/
-int knet_link_set_priority(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_set_priority(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
uint8_t priority);
/*
* knet_link_get_priority
*
* knet_h - pointer to knet_handle_t
*
* host_id - see above
*
* link_id - see above
*
* priority - gather the switching priority for this link
* see also knet_host_set_policy
*
* knet_link_get_priority returns:
*
* 0 on success
* -1 on error and errno is set.
*/
-int knet_link_get_priority(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_get_priority(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
uint8_t *priority);
/*
* knet_link_get_link_list
*
* knet_h - pointer to knet_handle_t
*
* link_ids - array of at lest KNET_MAX_LINK size
* with the list of configured links for a certain host.
*
* link_ids_entries -
* number of entries contained in link_ids
*
* knet_link_get_link_list returns:
*
* 0 on success
* -1 on error and errno is set.
*/
-int knet_link_get_link_list(knet_handle_t knet_h, uint16_t host_id,
+int knet_link_get_link_list(knet_handle_t knet_h, uint8_t host_id,
uint8_t *link_ids, size_t *link_ids_entries);
/*
* define link status structure for quick lookup
* struct is in flux as more stats will be added soon
*
* src/dst_{ipaddr,port} strings are filled by
* getnameinfo(3) when configuring the link.
* if the link is dynamic (see knet_link_set_config)
* dst_ipaddr/port will contain ipaddr/port of the currently
* connected peer or "Unknown" if it was not possible
* to determine the ipaddr/port at runtime.
*
* enabled see also knet_link_set/get_enable.
*
* connected the link is connected to a peer and ping/pong traffic
* is flowing.
*
* dynconnected the link has dynamic ip on the other end, and
* we can see the other host is sending pings to us.
*
* latency average latency of this link
* see also knet_link_set/get_timeout.
*
* pong_last if the link is down, this value tells us how long
* ago this link was active. A value of 0 means that the link
* has never been active.
*/
struct knet_link_status {
char src_ipaddr[KNET_MAX_HOST_LEN];
char src_port[KNET_MAX_PORT_LEN];
char dst_ipaddr[KNET_MAX_HOST_LEN];
char dst_port[KNET_MAX_PORT_LEN];
unsigned int enabled:1; /* link is configured and admin enabled for traffic */
unsigned int connected:1; /* link is connected for data (local view) */
unsigned int dynconnected:1; /* link has been activated by remote dynip */
unsigned long long latency; /* average latency computed by fix/exp */
struct timespec pong_last;
unsigned int mtu; /* current detected MTU on this link */
unsigned int proto_overhead; /* contains the size of the IP protocol, knet headers and
* crypto headers (if configured). This value is filled in
* ONLY after the first PMTUd run on that given link,
* and can change if link configuration or crypto configuration
* changes at runtime.
* WARNING: in general mtu + proto_overhead might or might
* not match the output of ifconfig mtu due to crypto
* requirements to pad packets to some specific boundaries. */
/* add link statistics */
};
/*
* knet_link_get_status
*
* knet_h - pointer to knet_handle_t
*
* host_id - see above
*
* link_id - see above
*
* status - pointer to knet_link_status struct (see above)
*
* knet_link_get_status returns:
*
* 0 on success
* -1 on error and errno is set.
*/
-int knet_link_get_status(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_get_status(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
struct knet_link_status *status);
/*
* logging structs/API calls
*/
/*
* libknet is composed of several subsystems. In order
* to easily distinguish log messages coming from different
* places, each subsystem has its own ID.
*
* 0-19 config/management
* 20-39 internal threads
* 40-59 transports
* 60-69 crypto implementations
*/
#define KNET_SUB_COMMON 0 /* common.c */
#define KNET_SUB_HANDLE 1 /* handle.c alloc/dealloc config changes */
#define KNET_SUB_HOST 2 /* host add/del/modify */
#define KNET_SUB_LISTENER 3 /* listeners add/del/modify... */
#define KNET_SUB_LINK 4 /* link add/del/modify */
#define KNET_SUB_TRANSPORT 5 /* Transport common */
#define KNET_SUB_CRYPTO 6 /* crypto.c config generic layer */
#define KNET_SUB_FILTER 19 /* allocated for users to log from dst_filter */
#define KNET_SUB_DSTCACHE 20 /* switching thread (destination cache handling) */
#define KNET_SUB_HEARTBEAT 21 /* heartbeat thread */
#define KNET_SUB_PMTUD 22 /* Path MTU Discovery thread */
#define KNET_SUB_TX 23 /* send to link thread */
#define KNET_SUB_RX 24 /* recv from link thread */
#define KNET_SUB_TRANSP_UDP 40 /* UDP Transport */
#define KNET_SUB_TRANSP_SCTP 41 /* SCTP Transport */
#define KNET_SUB_NSSCRYPTO 60 /* nsscrypto.c */
#define KNET_SUB_UNKNOWN 254
#define KNET_MAX_SUBSYSTEMS KNET_SUB_UNKNOWN + 1
/*
* Convert between subsystem IDs and names
*/
/*
* knet_log_get_subsystem_name
*
* return internal name of the subsystem or "common"
*/
const char *knet_log_get_subsystem_name(uint8_t subsystem);
/*
* knet_log_get_subsystem_id
*
* return internal ID of the subsystem or KNET_SUB_COMMON
*/
uint8_t knet_log_get_subsystem_id(const char *name);
/*
* 4 log levels are enough for everybody
*/
#define KNET_LOG_ERR 0 /* unrecoverable errors/conditions */
#define KNET_LOG_WARN 1 /* recoverable errors/conditions */
#define KNET_LOG_INFO 2 /* info, link up/down, config changes.. */
#define KNET_LOG_DEBUG 3
/*
* Convert between log level values and names
*/
/*
* knet_log_get_loglevel_name
*
* return internal name of the log level or "ERROR" for unknown values
*/
const char *knet_log_get_loglevel_name(uint8_t level);
/*
* knet_log_get_loglevel_id
*
* return internal log level ID or KNET_LOG_ERR for invalid names
*/
uint8_t knet_log_get_loglevel_id(const char *name);
/*
* every log message is composed by a text message (including a trailing \n)
* and message level/subsystem IDs.
* In order to make debugging easier it is possible to send those packets
* straight to stdout/stderr (see knet_bench.c stdout option).
*/
#define KNET_MAX_LOG_MSG_SIZE 256
struct knet_log_msg {
char msg[KNET_MAX_LOG_MSG_SIZE - (sizeof(uint8_t)*2)];
uint8_t subsystem; /* KNET_SUB_* */
uint8_t msglevel; /* KNET_LOG_* */
};
/*
* knet_log_set_log_level
*
* knet_h - same as above
*
* subsystem - same as above
*
* level - same as above
*
* knet_log_set_loglevel allows fine control of log levels by subsystem.
* See also knet_handle_new for defaults.
*
* knet_log_set_loglevel returns:
*
* 0 on success
* -1 on error and errno is set.
*/
int knet_log_set_loglevel(knet_handle_t knet_h, uint8_t subsystem,
uint8_t level);
/*
* knet_log_get_log_level
*
* knet_h - same as above
*
* subsystem - same as above
*
* level - same as above
*
* knet_log_get_loglevel returns:
*
* 0 on success
* -1 on error and errno is set.
*/
int knet_log_get_loglevel(knet_handle_t knet_h, uint8_t subsystem,
uint8_t *level);
#endif
diff --git a/libknet/link.c b/libknet/link.c
index a0ae60d9..d221a1a7 100644
--- a/libknet/link.c
+++ b/libknet/link.c
@@ -1,973 +1,973 @@
/*
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
*
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
* Federico Simoncelli <fsimon@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#include "config.h"
#include <errno.h>
#include <netdb.h>
#include <string.h>
#include <pthread.h>
#include "internals.h"
#include "logging.h"
#include "link.h"
#include "transports.h"
#include "host.h"
-int _link_updown(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int _link_updown(knet_handle_t knet_h, uint8_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];
if ((link->status.enabled == enabled) &&
(link->status.connected == connected))
return 0;
link->status.enabled = enabled;
link->status.connected = connected;
_host_dstcache_update_async(knet_h, knet_h->host_index[host_id]);
if ((link->status.dynconnected) &&
(!link->status.connected))
link->status.dynconnected = 0;
return 0;
}
-int knet_link_set_config(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_set_config(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
uint8_t transport,
struct sockaddr_storage *src_addr,
struct sockaddr_storage *dst_addr)
{
int savederrno = 0, err = 0;
struct knet_host *host;
struct knet_link *link;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (link_id >= KNET_MAX_LINK) {
errno = EINVAL;
return -1;
}
if (!src_addr) {
errno = EINVAL;
return -1;
}
if (transport >= KNET_MAX_TRANSPORTS) {
errno = EINVAL;
return -1;
}
if (!knet_h->transport_ops[transport]) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
host = knet_h->host_index[host_id];
if (!host) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
link = &host->link[link_id];
if (link->configured != 0) {
err =-1;
savederrno = EBUSY;
log_err(knet_h, KNET_SUB_LINK, "Host %u link %u is currently configured: %s",
host_id, link_id, strerror(savederrno));
goto exit_unlock;
}
if (link->status.enabled != 0) {
err =-1;
savederrno = EBUSY;
log_err(knet_h, KNET_SUB_LINK, "Host %u link %u is currently in use: %s",
host_id, link_id, strerror(savederrno));
goto exit_unlock;
}
memmove(&link->src_addr, src_addr, sizeof(struct sockaddr_storage));
err = knet_addrtostr(src_addr, sizeof(struct sockaddr_storage),
link->status.src_ipaddr, KNET_MAX_HOST_LEN,
link->status.src_port, KNET_MAX_PORT_LEN);
if (err) {
if (err == EAI_SYSTEM) {
savederrno = errno;
log_warn(knet_h, KNET_SUB_LINK,
"Unable to resolve host: %u link: %u source addr/port: %s",
host_id, link_id, strerror(savederrno));
} else {
savederrno = EINVAL;
log_warn(knet_h, KNET_SUB_LINK,
"Unable to resolve host: %u link: %u source addr/port: %s",
host_id, link_id, gai_strerror(err));
}
err = -1;
goto exit_unlock;
}
if (!dst_addr) {
link->dynamic = KNET_LINK_DYNIP;
} else {
link->dynamic = KNET_LINK_STATIC;
memmove(&link->dst_addr, dst_addr, sizeof(struct sockaddr_storage));
err = knet_addrtostr(dst_addr, sizeof(struct sockaddr_storage),
link->status.dst_ipaddr, KNET_MAX_HOST_LEN,
link->status.dst_port, KNET_MAX_PORT_LEN);
if (err) {
if (err == EAI_SYSTEM) {
savederrno = errno;
log_warn(knet_h, KNET_SUB_LINK,
"Unable to resolve host: %u link: %u destination addr/port: %s",
host_id, link_id, strerror(savederrno));
} else {
savederrno = EINVAL;
log_warn(knet_h, KNET_SUB_LINK,
"Unable to resolve host: %u link: %u destination addr/port: %s",
host_id, link_id, gai_strerror(err));
}
err = -1;
goto exit_unlock;
}
}
link->transport_type = transport;
link->transport_connected = 0;
link->proto_overhead = knet_h->transport_ops[link->transport_type]->transport_mtu_overhead;
link->configured = 1;
link->pong_count = KNET_LINK_DEFAULT_PONG_COUNT;
link->has_valid_mtu = 0;
link->ping_interval = KNET_LINK_DEFAULT_PING_INTERVAL * 1000; /* microseconds */
link->pong_timeout = KNET_LINK_DEFAULT_PING_TIMEOUT * 1000; /* microseconds */
link->latency_fix = KNET_LINK_DEFAULT_PING_PRECISION;
link->latency_exp = KNET_LINK_DEFAULT_PING_PRECISION - \
((link->ping_interval * KNET_LINK_DEFAULT_PING_PRECISION) / 8000000);
if (knet_h->transport_ops[link->transport_type]->transport_link_set_config(knet_h, link) < 0) {
savederrno = errno;
err = -1;
goto exit_unlock;
}
log_debug(knet_h, KNET_SUB_LINK, "host: %u link: %u is configured",
host_id, link_id);
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
-int knet_link_get_config(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_get_config(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
uint8_t *transport,
struct sockaddr_storage *src_addr,
struct sockaddr_storage *dst_addr,
uint8_t *dynamic)
{
int savederrno = 0, err = 0;
struct knet_host *host;
struct knet_link *link;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (link_id >= KNET_MAX_LINK) {
errno = EINVAL;
return -1;
}
if (!src_addr) {
errno = EINVAL;
return -1;
}
if (!dynamic) {
errno = EINVAL;
return -1;
}
if (!transport) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
host = knet_h->host_index[host_id];
if (!host) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
link = &host->link[link_id];
if (!link->configured) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
host_id, link_id, strerror(savederrno));
goto exit_unlock;
}
if ((link->dynamic == KNET_LINK_STATIC) && (!dst_addr)) {
savederrno = EINVAL;
err = -1;
goto exit_unlock;
}
memmove(src_addr, &link->src_addr, sizeof(struct sockaddr_storage));
*transport = link->transport_type;
if (link->dynamic == KNET_LINK_STATIC) {
*dynamic = 0;
memmove(dst_addr, &link->dst_addr, sizeof(struct sockaddr_storage));
} else {
*dynamic = 1;
}
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
-int knet_link_clear_config(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id)
+int knet_link_clear_config(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id)
{
int savederrno = 0, err = 0;
struct knet_host *host;
struct knet_link *link;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (link_id >= KNET_MAX_LINK) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
host = knet_h->host_index[host_id];
if (!host) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
link = &host->link[link_id];
if (link->configured != 1) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "Host %u link %u is not configured: %s",
host_id, link_id, strerror(savederrno));
goto exit_unlock;
}
if (link->status.enabled != 0) {
err = -1;
savederrno = EBUSY;
log_err(knet_h, KNET_SUB_LINK, "Host %u link %u is currently in use: %s",
host_id, link_id, strerror(savederrno));
goto exit_unlock;
}
if ((knet_h->transport_ops[link->transport_type]->transport_link_clear_config(knet_h, link) < 0) &&
(errno != EBUSY)) {
savederrno = errno;
err = -1;
goto exit_unlock;
}
memset(link, 0, sizeof(struct knet_link));
link->link_id = link_id;
log_debug(knet_h, KNET_SUB_LINK, "host: %u link: %u config has been wiped",
host_id, link_id);
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
-int knet_link_set_enable(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_set_enable(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
unsigned int enabled)
{
int savederrno = 0, err = 0;
struct knet_host *host;
struct knet_link *link;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (link_id >= KNET_MAX_LINK) {
errno = EINVAL;
return -1;
}
if (enabled > 1) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
host = knet_h->host_index[host_id];
if (!host) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
link = &host->link[link_id];
if (!link->configured) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
host_id, link_id, strerror(savederrno));
goto exit_unlock;
}
if (link->status.enabled == enabled) {
err = 0;
goto exit_unlock;
}
err = _link_updown(knet_h, host_id, link_id, enabled, link->status.connected);
savederrno = errno;
if (enabled) {
goto exit_unlock;
}
log_debug(knet_h, KNET_SUB_LINK, "host: %u link: %u is disabled",
host_id, link_id);
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
-int knet_link_get_enable(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_get_enable(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
unsigned int *enabled)
{
int savederrno = 0, err = 0;
struct knet_host *host;
struct knet_link *link;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (link_id >= KNET_MAX_LINK) {
errno = EINVAL;
return -1;
}
if (!enabled) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
host = knet_h->host_index[host_id];
if (!host) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
link = &host->link[link_id];
if (!link->configured) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
host_id, link_id, strerror(savederrno));
goto exit_unlock;
}
*enabled = link->status.enabled;
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
-int knet_link_set_pong_count(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_set_pong_count(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
uint8_t pong_count)
{
int savederrno = 0, err = 0;
struct knet_host *host;
struct knet_link *link;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (link_id >= KNET_MAX_LINK) {
errno = EINVAL;
return -1;
}
if (pong_count < 1) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
host = knet_h->host_index[host_id];
if (!host) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
link = &host->link[link_id];
if (!link->configured) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
host_id, link_id, strerror(savederrno));
goto exit_unlock;
}
link->pong_count = pong_count;
log_debug(knet_h, KNET_SUB_LINK,
"host: %u link: %u pong count update: %u",
host_id, link_id, link->pong_count);
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
-int knet_link_get_pong_count(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_get_pong_count(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
uint8_t *pong_count)
{
int savederrno = 0, err = 0;
struct knet_host *host;
struct knet_link *link;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (link_id >= KNET_MAX_LINK) {
errno = EINVAL;
return -1;
}
if (!pong_count) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
host = knet_h->host_index[host_id];
if (!host) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
link = &host->link[link_id];
if (!link->configured) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
host_id, link_id, strerror(savederrno));
goto exit_unlock;
}
*pong_count = link->pong_count;
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
-int knet_link_set_ping_timers(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_set_ping_timers(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
time_t interval, time_t timeout, unsigned int precision)
{
int savederrno = 0, err = 0;
struct knet_host *host;
struct knet_link *link;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (link_id >= KNET_MAX_LINK) {
errno = EINVAL;
return -1;
}
if (!interval) {
errno = EINVAL;
return -1;
}
if (!timeout) {
errno = EINVAL;
return -1;
}
if (!precision) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
host = knet_h->host_index[host_id];
if (!host) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
link = &host->link[link_id];
if (!link->configured) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
host_id, link_id, strerror(savederrno));
goto exit_unlock;
}
link->ping_interval = interval * 1000; /* microseconds */
link->pong_timeout = timeout * 1000; /* microseconds */
link->latency_fix = precision;
link->latency_exp = precision - \
((link->ping_interval * precision) / 8000000);
log_debug(knet_h, KNET_SUB_LINK,
"host: %u link: %u timeout update - interval: %llu timeout: %llu precision: %d",
host_id, link_id, link->ping_interval, link->pong_timeout, precision);
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
-int knet_link_get_ping_timers(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_get_ping_timers(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
time_t *interval, time_t *timeout, unsigned int *precision)
{
int savederrno = 0, err = 0;
struct knet_host *host;
struct knet_link *link;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (link_id >= KNET_MAX_LINK) {
errno = EINVAL;
return -1;
}
if (!interval) {
errno = EINVAL;
return -1;
}
if (!timeout) {
errno = EINVAL;
return -1;
}
if (!precision) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
host = knet_h->host_index[host_id];
if (!host) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
link = &host->link[link_id];
if (!link->configured) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
host_id, link_id, strerror(savederrno));
goto exit_unlock;
}
*interval = link->ping_interval / 1000; /* microseconds */
*timeout = link->pong_timeout / 1000;
*precision = link->latency_fix;
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
-int knet_link_set_priority(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_set_priority(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
uint8_t priority)
{
int savederrno = 0, err = 0;
struct knet_host *host;
struct knet_link *link;
uint8_t old_priority;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (link_id >= KNET_MAX_LINK) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
host = knet_h->host_index[host_id];
if (!host) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
link = &host->link[link_id];
if (!link->configured) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
host_id, link_id, strerror(savederrno));
goto exit_unlock;
}
old_priority = link->priority;
if (link->priority == priority) {
err = 0;
goto exit_unlock;
}
link->priority = priority;
if (_host_dstcache_update_sync(knet_h, host)) {
savederrno = errno;
log_debug(knet_h, KNET_SUB_LINK,
"Unable to update link priority (host: %u link: %u priority: %u): %s",
host_id, link_id, link->priority, strerror(savederrno));
link->priority = old_priority;
err = -1;
goto exit_unlock;
}
log_debug(knet_h, KNET_SUB_LINK,
"host: %u link: %u priority set to: %u",
host_id, link_id, link->priority);
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
-int knet_link_get_priority(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_get_priority(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
uint8_t *priority)
{
int savederrno = 0, err = 0;
struct knet_host *host;
struct knet_link *link;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (link_id >= KNET_MAX_LINK) {
errno = EINVAL;
return -1;
}
if (!priority) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
host = knet_h->host_index[host_id];
if (!host) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
link = &host->link[link_id];
if (!link->configured) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
host_id, link_id, strerror(savederrno));
goto exit_unlock;
}
*priority = link->priority;
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
-int knet_link_get_link_list(knet_handle_t knet_h, uint16_t host_id,
+int knet_link_get_link_list(knet_handle_t knet_h, uint8_t host_id,
uint8_t *link_ids, size_t *link_ids_entries)
{
int savederrno = 0, err = 0, i, count = 0;
struct knet_host *host;
struct knet_link *link;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (!link_ids) {
errno = EINVAL;
return -1;
}
if (!link_ids_entries) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
host = knet_h->host_index[host_id];
if (!host) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
for (i = 0; i < KNET_MAX_LINK; i++) {
link = &host->link[i];
if (!link->configured) {
continue;
}
link_ids[count] = i;
count++;
}
*link_ids_entries = count;
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
-int knet_link_get_status(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id,
+int knet_link_get_status(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
struct knet_link_status *status)
{
int savederrno = 0, err = 0;
struct knet_host *host;
struct knet_link *link;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (link_id >= KNET_MAX_LINK) {
errno = EINVAL;
return -1;
}
if (!status) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
host = knet_h->host_index[host_id];
if (!host) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s",
host_id, strerror(savederrno));
goto exit_unlock;
}
link = &host->link[link_id];
if (!link->configured) {
err = -1;
savederrno = EINVAL;
log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s",
host_id, link_id, strerror(savederrno));
goto exit_unlock;
}
memmove(status, &link->status, sizeof(struct knet_link_status));
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
diff --git a/libknet/link.h b/libknet/link.h
index eb70ef8d..9b4cc798 100644
--- a/libknet/link.h
+++ b/libknet/link.h
@@ -1,21 +1,21 @@
/*
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
*
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
* Federico Simoncelli <fsimon@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#ifndef __LINK_H__
#define __LINK_H__
#include "internals.h"
#define KNET_LINK_STATIC 0 /* link has static ip on both ends */
#define KNET_LINK_DYNIP 1 /* link has dynamic destination ip */
-int _link_updown(knet_handle_t knet_h, uint16_t node_id, uint8_t link_id,
+int _link_updown(knet_handle_t knet_h, uint8_t host_id, uint8_t link_id,
unsigned int enabled, unsigned int connected);
#endif
diff --git a/libknet/onwire.h b/libknet/onwire.h
index f0c07f08..3fc1f6ca 100644
--- a/libknet/onwire.h
+++ b/libknet/onwire.h
@@ -1,199 +1,199 @@
/*
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
*
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
* Federico Simoncelli <fsimon@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#ifndef __ONWIRE_H__
#define __ONWIRE_H__
/*
* data structures to define network packets.
* Start from knet_header at the bottom
*/
#include <stdint.h>
#if 0
/*
* for future protocol extension (re-switching table calculation)
*/
struct knet_hinfo_link {
uint8_t khl_link_id;
uint8_t khl_link_dynamic;
uint8_t khl_link_priority;
uint64_t khl_link_latency;
char khl_link_dst_ipaddr[KNET_MAX_HOST_LEN];
char khl_link_dst_port[KNET_MAX_PORT_LEN];
} __attribute__((packed));
struct knet_hinfo_link_table {
- uint16_t khlt_node_id;
+ uint8_t khlt_node_id;
uint8_t khlt_local; /* we have this node connected locally */
struct knet_hinfo_link khlt_link[KNET_MAX_LINK]; /* info we send about each link in the node */
} __attribute__((packed));
struct link_table {
- uint16_t khdt_host_entries;
- uint8_t khdt_host_maps[0]; /* array of knet_hinfo_link_table[khdt_host_entries] */
+ uint8_t khdt_host_entries;
+ uint8_t khdt_host_maps[0]; /* array of knet_hinfo_link_table[khdt_host_entries] */
} __attribute__((packed));
#endif
#define KNET_HOSTINFO_LINK_STATUS_DOWN 0
#define KNET_HOSTINFO_LINK_STATUS_UP 1
struct knet_hostinfo_payload_link_status {
uint8_t khip_link_status_link_id; /* link id */
uint8_t khip_link_status_status; /* up/down status */
} __attribute__((packed));
/*
* union to reference possible individual payloads
*/
union knet_hostinfo_payload {
struct knet_hostinfo_payload_link_status knet_hostinfo_payload_link_status;
} __attribute__((packed));
/*
* due to the nature of knet_hostinfo, we are currently
* sending those data as part of knet_header_payload_data.khp_data_userdata
* and avoid a union that increses knet_header_payload_data size
* unnecessarely.
* This might change later on depending on how we implement
* host info exchange
*/
#define KNET_HOSTINFO_TYPE_LINK_UP_DOWN 0 // UNUSED
#define KNET_HOSTINFO_TYPE_LINK_TABLE 1 // NOT IMPLEMENTED
#define KNET_HOSTINFO_UCAST 0 /* send info to a specific host */
#define KNET_HOSTINFO_BCAST 1 /* send info to all known / connected hosts */
struct knet_hostinfo {
uint8_t khi_type; /* type of hostinfo we are sending */
uint8_t khi_bcast; /* hostinfo destination bcast/ucast */
- uint16_t khi_dst_node_id;/* used only if in ucast mode */
+ uint8_t khi_dst_node_id;/* used only if in ucast mode */
union knet_hostinfo_payload khi_payload;
} __attribute__((packed));
#define KNET_HOSTINFO_ALL_SIZE sizeof(struct knet_hostinfo)
#define KNET_HOSTINFO_SIZE (KNET_HOSTINFO_ALL_SIZE - sizeof(union knet_hostinfo_payload))
#define KNET_HOSTINFO_LINK_STATUS_SIZE (KNET_HOSTINFO_SIZE + sizeof(struct knet_hostinfo_payload_link_status))
#define khip_link_status_status khi_payload.knet_hostinfo_payload_link_status.khip_link_status_status
#define khip_link_status_link_id khi_payload.knet_hostinfo_payload_link_status.khip_link_status_link_id
/*
* typedef uint64_t seq_num_t;
* #define SEQ_MAX UINT64_MAX
*/
typedef uint16_t seq_num_t;
#define SEQ_MAX UINT16_MAX
struct knet_header_payload_data {
seq_num_t khp_data_seq_num; /* pckt seq number used to deduplicate pkcts */
uint8_t khp_data_pad1; /* make sure to have space in the header to grow features */
uint8_t khp_data_pad2;
uint8_t khp_data_bcast; /* data destination bcast/ucast */
uint8_t khp_data_frag_num; /* number of fragments of this pckt. 1 is not fragmented */
uint8_t khp_data_frag_seq; /* as above, indicates the frag sequence number */
int8_t khp_data_channel; /* transport channel data for localsock <-> knet <-> localsock mapping */
uint8_t khp_data_userdata[0]; /* pointer to the real user data */
} __attribute__((packed));
struct knet_header_payload_ping {
uint8_t khp_ping_link; /* source link id */
uint32_t khp_ping_time[4]; /* ping timestamp */
seq_num_t khp_ping_seq_num; /* transport host seq_num */
uint8_t khp_ping_timed; /* timed pinged (1) or forced by seq_num (0) */
} __attribute__((packed));
/* taken from tracepath6 */
#define KNET_PMTUD_SIZE_V4 65535
#define KNET_PMTUD_SIZE_V6 KNET_PMTUD_SIZE_V4
/* These two get the protocol-specific overheads added to them */
#define KNET_PMTUD_OVERHEAD_V4 20
#define KNET_PMTUD_OVERHEAD_V6 40
#define KNET_PMTUD_MIN_MTU_V4 576
#define KNET_PMTUD_MIN_MTU_V6 1280
struct knet_header_payload_pmtud {
uint8_t khp_pmtud_link; /* source link id */
uint16_t khp_pmtud_size; /* size of the current packet */
uint8_t khp_pmtud_data[0]; /* pointer to empty/random data/fill buffer */
} __attribute__((packed));
/*
* union to reference possible individual payloads
*/
union knet_header_payload {
struct knet_header_payload_data khp_data; /* pure data packet struct */
struct knet_header_payload_ping khp_ping; /* heartbeat packet struct */
struct knet_header_payload_pmtud khp_pmtud; /* Path MTU discovery packet struct */
} __attribute__((packed));
/*
* starting point
*/
#define KNET_HEADER_VERSION 0x01 /* we currently support only one version */
#define KNET_HEADER_TYPE_DATA 0x00 /* pure data packet */
#define KNET_HEADER_TYPE_HOST_INFO 0x01 /* host status information pckt */
#define KNET_HEADER_TYPE_PMSK 0x80 /* packet mask */
#define KNET_HEADER_TYPE_PING 0x81 /* heartbeat */
#define KNET_HEADER_TYPE_PONG 0x82 /* reply to heartbeat */
#define KNET_HEADER_TYPE_PMTUD 0x83 /* Used to determine Path MTU */
#define KNET_HEADER_TYPE_PMTUD_REPLY 0x84 /* reply from remote host */
struct knet_header {
uint8_t kh_version; /* pckt format/version */
uint8_t kh_type; /* from above defines. Tells what kind of pckt it is */
- uint16_t kh_node; /* host id of the source host for this pckt */
+ uint8_t kh_node; /* host id of the source host for this pckt */
uint8_t kh_pad1; /* make sure to have space in the header to grow features */
uint8_t kh_pad2;
union knet_header_payload kh_payload; /* union of potential data struct based on kh_type */
} __attribute__((packed));
/*
* commodoty defines to hide structure nesting
* (needs review and cleanup)
*/
#define khp_data_seq_num kh_payload.khp_data.khp_data_seq_num
#define khp_data_frag_num kh_payload.khp_data.khp_data_frag_num
#define khp_data_frag_seq kh_payload.khp_data.khp_data_frag_seq
#define khp_data_userdata kh_payload.khp_data.khp_data_userdata
#define khp_data_bcast kh_payload.khp_data.khp_data_bcast
#define khp_data_channel kh_payload.khp_data.khp_data_channel
#define khp_ping_link kh_payload.khp_ping.khp_ping_link
#define khp_ping_time kh_payload.khp_ping.khp_ping_time
#define khp_ping_seq_num kh_payload.khp_ping.khp_ping_seq_num
#define khp_ping_timed kh_payload.khp_ping.khp_ping_timed
#define khp_pmtud_link kh_payload.khp_pmtud.khp_pmtud_link
#define khp_pmtud_size kh_payload.khp_pmtud.khp_pmtud_size
#define khp_pmtud_data kh_payload.khp_pmtud.khp_pmtud_data
/*
* extra defines to avoid mingling with sizeof() too much
*/
#define KNET_HEADER_ALL_SIZE sizeof(struct knet_header)
#define KNET_HEADER_SIZE (KNET_HEADER_ALL_SIZE - sizeof(union knet_header_payload))
#define KNET_HEADER_PING_SIZE (KNET_HEADER_SIZE + sizeof(struct knet_header_payload_ping))
#define KNET_HEADER_PMTUD_SIZE (KNET_HEADER_SIZE + sizeof(struct knet_header_payload_pmtud))
#define KNET_HEADER_DATA_SIZE (KNET_HEADER_SIZE + sizeof(struct knet_header_payload_data))
#endif
diff --git a/libknet/tests/api_knet_handle_enable_filter.c b/libknet/tests/api_knet_handle_enable_filter.c
index a6cd7d87..1db85d40 100644
--- a/libknet/tests/api_knet_handle_enable_filter.c
+++ b/libknet/tests/api_knet_handle_enable_filter.c
@@ -1,158 +1,158 @@
/*
* Copyright (C) 2016 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 int dhost_filter(void *pvt_data,
const unsigned char *outdata,
ssize_t outdata_len,
uint8_t tx_rx,
- uint16_t this_host_id,
- uint16_t src_host_id,
+ uint8_t this_host_id,
+ uint8_t src_host_id,
int8_t *dst_channel,
- uint16_t *dst_host_ids,
+ uint8_t *dst_host_ids,
size_t *dst_host_ids_entries)
{
return 0;
}
static void test(void)
{
knet_handle_t knet_h;
int logfds[2];
printf("Test knet_handle_enable_filter incorrect knet_h\n");
if ((!knet_handle_enable_filter(NULL, NULL, dhost_filter)) || (errno != EINVAL)) {
printf("knet_handle_enable_filter accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno));
exit(FAIL);
}
setup_logpipes(logfds);
knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG);
if (!knet_h) {
printf("knet_handle_new failed: %s\n", strerror(errno));
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
printf("Test knet_handle_enable_filter with no private_data\n");
if (knet_handle_enable_filter(knet_h, NULL, dhost_filter) < 0) {
printf("knet_handle_enable_filter failed: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (knet_h->dst_host_filter_fn_private_data != NULL) {
printf("knet_handle_enable_filter 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_handle_enable_filter with private_data\n");
if (knet_handle_enable_filter(knet_h, &private_data, NULL) < 0) {
printf("knet_handle_enable_filter failed: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (knet_h->dst_host_filter_fn_private_data != &private_data) {
printf("knet_handle_enable_filter 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_handle_enable_filter with no dhost_filter fn\n");
if (knet_handle_enable_filter(knet_h, NULL, NULL) < 0) {
printf("knet_handle_enable_filter failed: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (knet_h->dst_host_filter_fn != NULL) {
printf("knet_handle_enable_filter failed to unset dhost_filter fn");
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_handle_enable_filter with dhost_filter fn\n");
if (knet_handle_enable_filter(knet_h, NULL, dhost_filter) < 0) {
printf("knet_handle_enable_filter failed: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (knet_h->dst_host_filter_fn != &dhost_filter) {
printf("knet_handle_enable_filter failed to set dhost_filter fn");
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
knet_host_remove(knet_h, 1);
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
}
int main(int argc, char *argv[])
{
need_root();
test();
return PASS;
}
diff --git a/libknet/tests/api_knet_handle_new.c b/libknet/tests/api_knet_handle_new.c
index e862b37a..70252c7d 100644
--- a/libknet/tests/api_knet_handle_new.c
+++ b/libknet/tests/api_knet_handle_new.c
@@ -1,139 +1,139 @@
/*
* Copyright (C) 2016 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 <sys/time.h>
#include <sys/resource.h>
#include "libknet.h"
#include "internals.h"
#include "test-common.h"
static void test(void)
{
knet_handle_t knet_h;
struct rlimit cur;
int logfds[2];
printf("Test knet_handle_new hostid 1, no logging\n");
knet_h = knet_handle_new(1, 0, 0);
if (!knet_h) {
printf("Unable to init knet_handle! err: %s\n", strerror(errno));
exit(FAIL);
}
if (knet_handle_free(knet_h) != 0) {
printf("Unable to free knet_handle\n");
exit(FAIL);
}
printf("Test knet_handle_new hostid -1, no logging\n");
knet_h = knet_handle_new(-1, 0, 0);
if (!knet_h) {
printf("Unable to init knet_handle! err: %s\n", strerror(errno));
exit(FAIL);
}
/*
- * -1 == uint16_t 65535
+ * -1 == uint8_t 255
*/
- if (knet_h->host_id != 65535) {
+ if (knet_h->host_id != 255) {
printf("host_id size might have changed!\n");
knet_handle_free(knet_h);
exit(FAIL);
}
if (knet_handle_free(knet_h) != 0) {
printf("Unable to free knet_handle\n");
exit(FAIL);
}
if (getrlimit(RLIMIT_NOFILE, &cur) < 0) {
printf("Unable to get current fd limit: %s\n", strerror(errno));
exit(SKIP);
}
/*
* passing a bad fd and it should fail
*/
printf("Test knet_handle_new hostid 1, incorrect log_fd (-1)\n");
knet_h = knet_handle_new(1, -1, 0);
if ((!knet_h) && (errno != EINVAL)) {
printf("knet_handle_new returned incorrect errno on incorrect log_fd\n");
exit(FAIL);
}
if (knet_h) {
printf("knet_handle_new accepted an incorrect (-1) log_fd\n");
knet_handle_free(knet_h);
exit(FAIL);
}
/*
* passing a bad fd and it should fail
*/
printf("Test knet_handle_new hostid 1, incorrect log_fd (max_fd + 1)\n");
knet_h = knet_handle_new(1, (int) cur.rlim_max, 0);
if ((knet_h) || (errno != EINVAL)) {
printf("knet_handle_new accepted an incorrect (max_fd + 1) log_fd or returned incorrect errno on incorrect log_fd: %s\n", strerror(errno));
knet_handle_free(knet_h);
exit(FAIL);
}
setup_logpipes(logfds);
printf("Test knet_handle_new hostid 1, proper log_fd, invalid log level (DEBUG + 1)\n");
knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG + 1);
if ((knet_h) || (errno != EINVAL)) {
printf("knet_handle_new accepted an incorrect log level or returned incorrect errno on incorrect log level: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
printf("Test knet_handle_new hostid 1, proper log_fd, proper log level (DEBUG)\n");
knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG);
if (!knet_h) {
printf("knet_handle_new failed: %s\n", strerror(errno));
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
}
int main(int argc, char *argv[])
{
need_root();
test();
return PASS;
}
diff --git a/libknet/tests/api_knet_host_add.c b/libknet/tests/api_knet_host_add.c
index c08408af..b7d62ceb 100644
--- a/libknet/tests/api_knet_host_add.c
+++ b/libknet/tests/api_knet_host_add.c
@@ -1,114 +1,114 @@
/*
* Copyright (C) 2016 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 "test-common.h"
static void test(void)
{
knet_handle_t knet_h;
int logfds[2];
- uint16_t host_ids[KNET_MAX_HOST];
+ uint8_t host_ids[KNET_MAX_HOST];
size_t host_ids_entries;
printf("Test knet_host_add incorrect knet_h\n");
if ((!knet_host_add(NULL, 1)) || (errno != EINVAL)) {
printf("knet_host_add accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno));
exit(FAIL);
}
setup_logpipes(logfds);
knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG);
if (!knet_h) {
printf("knet_handle_new failed: %s\n", strerror(errno));
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_host_add with hostid 1\n");
if (knet_host_add(knet_h, 1) < 0) {
printf("knet_host_add failed error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test verify host_id 1 is in the host list\n");
if (knet_host_get_host_list(knet_h, host_ids, &host_ids_entries) < 0) {
printf("Unable to get host list: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (host_ids_entries != 1) {
printf("Too many hosts?\n");
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (host_ids[0] != 1) {
printf("Unable to find host id 1 in host list\n");
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_host_add adding host 1 again\n");
if ((!knet_host_add(knet_h, 1)) || (errno != EEXIST)) {
printf("knet_host_add accepted duplicated host_id or returned incorrect error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
knet_host_remove(knet_h, 1);
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
}
int main(int argc, char *argv[])
{
need_root();
test();
return PASS;
}
diff --git a/libknet/tests/api_knet_host_enable_status_change_notify.c b/libknet/tests/api_knet_host_enable_status_change_notify.c
index 95138fb1..4d809809 100644
--- a/libknet/tests/api_knet_host_enable_status_change_notify.c
+++ b/libknet/tests/api_knet_host_enable_status_change_notify.c
@@ -1,152 +1,152 @@
/*
* Copyright (C) 2016 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 host_notify(void *priv_data,
- uint16_t host_id,
+ uint8_t host_id,
uint8_t reachable,
uint8_t remote,
uint8_t external)
{
return;
}
static void test(void)
{
knet_handle_t knet_h;
int logfds[2];
printf("Test knet_host_enable_status_change_notify incorrect knet_h\n");
if ((!knet_host_enable_status_change_notify(NULL, NULL, host_notify)) || (errno != EINVAL)) {
printf("knet_host_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_new(1, logfds[1], KNET_LOG_DEBUG);
if (!knet_h) {
printf("knet_handle_new failed: %s\n", strerror(errno));
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
printf("Test knet_host_enable_status_change_notify with no private_data\n");
if (knet_host_enable_status_change_notify(knet_h, NULL, host_notify) < 0) {
printf("knet_host_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->host_status_change_notify_fn_private_data != NULL) {
printf("knet_host_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_host_enable_status_change_notify with private_data\n");
if (knet_host_enable_status_change_notify(knet_h, &private_data, NULL) < 0) {
printf("knet_host_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->host_status_change_notify_fn_private_data != &private_data) {
printf("knet_host_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_host_enable_status_change_notify with no host_notify fn\n");
if (knet_host_enable_status_change_notify(knet_h, NULL, NULL) < 0) {
printf("knet_host_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->host_status_change_notify_fn != NULL) {
printf("knet_host_enable_status_change_notify failed to unset host_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_host_enable_status_change_notify with host_notify fn\n");
if (knet_host_enable_status_change_notify(knet_h, NULL, host_notify) < 0) {
printf("knet_host_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->host_status_change_notify_fn != &host_notify) {
printf("knet_host_enable_status_change_notify failed to set host_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[])
{
need_root();
test();
return PASS;
}
diff --git a/libknet/tests/api_knet_host_get_host_list.c b/libknet/tests/api_knet_host_get_host_list.c
index ff8b75f1..2cb6a78d 100644
--- a/libknet/tests/api_knet_host_get_host_list.c
+++ b/libknet/tests/api_knet_host_get_host_list.c
@@ -1,148 +1,148 @@
/*
* Copyright (C) 2016 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 "test-common.h"
static void test(void)
{
knet_handle_t knet_h;
int logfds[2];
- uint16_t host_ids[KNET_MAX_HOST];
+ uint8_t host_ids[KNET_MAX_HOST];
size_t host_ids_entries;
printf("Test knet_host_get_host_list incorrect knet_h\n");
if ((!knet_host_get_host_list(NULL, host_ids, &host_ids_entries)) || (errno != EINVAL)) {
printf("knet_host_get_host_list accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno));
exit(FAIL);
}
setup_logpipes(logfds);
knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG);
if (!knet_h) {
printf("knet_handle_new failed: %s\n", strerror(errno));
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_host_get_host_list incorrect host_ids\n");
if ((!knet_host_get_host_list(knet_h, NULL, &host_ids_entries)) || (errno != EINVAL)) {
printf("knet_host_get_host_list accepted invalid host_ids or returned incorrect error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_host_get_host_list incorrect host_ids_entries\n");
if ((!knet_host_get_host_list(knet_h, host_ids, NULL)) || (errno != EINVAL)) {
printf("knet_host_get_host_list accepted invalid host_ids or returned incorrect error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_host_get_host_list with one host\n");
if (knet_host_add(knet_h, 1) < 0) {
printf("knet_host_add failed error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (knet_host_get_host_list(knet_h, host_ids, &host_ids_entries) < 0) {
printf("Unable to get host list: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (host_ids_entries != 1) {
printf("Too many hosts?\n");
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (host_ids[0] != 1) {
printf("Unable to find host id 1 in host list\n");
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_host_get_host_list with zero hosts\n");
if (knet_host_remove(knet_h, 1) < 0) {
printf("knet_host_remove failed error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (knet_host_get_host_list(knet_h, host_ids, &host_ids_entries) < 0) {
printf("Unable to get host list: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (host_ids_entries != 0) {
printf("Too many hosts?\n");
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[])
{
need_root();
test();
return PASS;
}
diff --git a/libknet/tests/api_knet_host_get_id_by_host_name.c b/libknet/tests/api_knet_host_get_id_by_host_name.c
index 232d1a7c..071dc938 100644
--- a/libknet/tests/api_knet_host_get_id_by_host_name.c
+++ b/libknet/tests/api_knet_host_get_id_by_host_name.c
@@ -1,120 +1,120 @@
/*
* Copyright (C) 2016 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 void test(void)
{
knet_handle_t knet_h;
int logfds[2];
- uint16_t host_id;
+ uint8_t host_id;
printf("Test knet_host_get_id_by_host_name incorrect knet_h\n");
if ((!knet_host_get_id_by_host_name(NULL, "1", &host_id)) || (errno != EINVAL)) {
printf("knet_host_get_id_by_host_name accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno));
exit(FAIL);
}
setup_logpipes(logfds);
knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG);
if (!knet_h) {
printf("knet_handle_new failed: %s\n", strerror(errno));
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_host_get_id_by_host_name with incorrect name 1\n");
if ((!knet_host_get_id_by_host_name(knet_h, NULL, &host_id)) || (errno != EINVAL)) {
printf("knet_host_get_id_by_host_name accepted invalid name or returned incorrect error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_host_get_id_by_host_name with incorrect host_id\n");
if ((!knet_host_get_id_by_host_name(knet_h, "1", NULL)) || (errno != EINVAL)) {
printf("knet_host_get_id_by_host_name accepted invalid host_id or returned incorrect error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_host_get_id_by_host_name with incorrect values for name\n");
if (knet_host_add(knet_h, 1) < 0) {
printf("knet_host_add failed error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if ((!knet_host_get_id_by_host_name(knet_h, "test", &host_id)) || (errno != ENOENT)) {
printf("knet_host_get_id_by_host_name returned invalid host_id or returned incorrect error: %s\n", strerror(errno));
knet_host_remove(knet_h, 1);
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_host_get_id_by_host_name with correct values\n");
if (knet_host_get_id_by_host_name(knet_h, "1", &host_id) < 0) {
printf("knet_host_get_id_by_host_name could not get id for known name: %s\n", strerror(errno));
knet_host_remove(knet_h, 1);
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
knet_host_remove(knet_h, 1);
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
}
int main(int argc, char *argv[])
{
need_root();
test();
return PASS;
}
diff --git a/libknet/tests/api_knet_host_remove.c b/libknet/tests/api_knet_host_remove.c
index b1ba78ae..55e0d89b 100644
--- a/libknet/tests/api_knet_host_remove.c
+++ b/libknet/tests/api_knet_host_remove.c
@@ -1,169 +1,169 @@
/*
* Copyright (C) 2016 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 "netutils.h"
#include "test-common.h"
static void test(void)
{
knet_handle_t knet_h;
int logfds[2];
- uint16_t host_ids[KNET_MAX_HOST];
+ uint8_t host_ids[KNET_MAX_HOST];
size_t host_ids_entries;
struct sockaddr_storage ss;
printf("Test knet_host_add incorrect knet_h\n");
if ((!knet_host_remove(NULL, 1)) || (errno != EINVAL)) {
printf("knet_host_remove accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno));
exit(FAIL);
}
setup_logpipes(logfds);
knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG);
if (!knet_h) {
printf("knet_handle_new failed: %s\n", strerror(errno));
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_host_remove with unconfigured host_id\n");
if ((!knet_host_remove(knet_h, 1)) || (errno != EINVAL)) {
printf("knet_host_remove accepted invalid host_id or returned incorrect error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
if (knet_host_add(knet_h, 1) < 0) {
printf("Unable to add host_id 1: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_host_remove with configured host_id and links\n");
memset(&ss, 0, sizeof(struct sockaddr_storage));
if (knet_strtoaddr("127.0.0.0", "50000", &ss, sizeof(struct sockaddr_storage)) < 0) {
printf("Unable to convert str to sockaddr: %s\n", strerror(errno));
knet_host_remove(knet_h, 1);
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (knet_link_set_config(knet_h, 1, 0, KNET_TRANSPORT_UDP, &ss, NULL) < 0) {
printf("Unable to configure link: %s\n", strerror(errno));
knet_host_remove(knet_h, 1);
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (knet_link_set_enable(knet_h, 1, 0, 1) < 0) {
printf("Unable to enable link: %s\n", strerror(errno));
knet_host_remove(knet_h, 1);
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if ((!knet_host_remove(knet_h, 1)) || (errno != EBUSY)) {
printf("knet_host_remove accepted invalid request to remove host with link enabled or returned incorrect error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (knet_link_set_enable(knet_h, 1, 0, 0) < 0) {
printf("Unable to disable link: %s\n", strerror(errno));
knet_host_remove(knet_h, 1);
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (knet_link_clear_config(knet_h, 1, 0) < 0) {
printf("Unable to clear link config: %s\n", strerror(errno));
knet_host_remove(knet_h, 1);
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_host_remove with configured host_id (no links)\n");
if (knet_host_remove(knet_h, 1) < 0) {
printf("knet_host_remove didn't remove host_id 1: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (knet_host_get_host_list(knet_h, host_ids, &host_ids_entries) < 0) {
printf("Unable to get host list: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (host_ids_entries) {
printf("Too many hosts?\n");
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
}
int main(int argc, char *argv[])
{
need_root();
test();
return PASS;
}
diff --git a/libknet/tests/api_knet_send_sync.c b/libknet/tests/api_knet_send_sync.c
index d50f793e..fe8654e6 100644
--- a/libknet/tests/api_knet_send_sync.c
+++ b/libknet/tests/api_knet_send_sync.c
@@ -1,396 +1,396 @@
/*
* Copyright (C) 2016 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 "netutils.h"
#include "test-common.h"
static int private_data;
static void sock_notify(void *pvt_data,
int datafd,
int8_t channel,
uint8_t tx_rx,
int error,
int errorno)
{
return;
}
static int dhost_filter_ret = 0;
static int dhost_filter(void *pvt_data,
const unsigned char *outdata,
ssize_t outdata_len,
uint8_t tx_rx,
- uint16_t this_host_id,
- uint16_t src_host_id,
+ uint8_t this_host_id,
+ uint8_t src_host_id,
int8_t *dst_channel,
- uint16_t *dst_host_ids,
+ uint8_t *dst_host_ids,
size_t *dst_host_ids_entries)
{
dst_host_ids[0] = 0;
/*
* fatal fault
*/
if (dhost_filter_ret < 0) {
return -1;
}
/*
* trigger EINVAL
* no ids found
*/
if (dhost_filter_ret == 0) {
*dst_host_ids_entries = 0;
return 0;
}
/*
* send correct info back
*/
if (dhost_filter_ret == 1) {
dst_host_ids[0] = 1;
*dst_host_ids_entries = 1;
return 0;
}
/*
* trigger E2BIG
* mcast destinations
*/
if (dhost_filter_ret == 2) {
dst_host_ids[0] = 1;
*dst_host_ids_entries = 2;
return 0;
}
/*
* return mcast
*/
if (dhost_filter_ret == 3) {
return 1;
}
return dhost_filter_ret;
}
static void test(void)
{
knet_handle_t knet_h;
int logfds[2];
int datafd = 0;
int8_t channel = 0;
char send_buff[KNET_MAX_PACKET_SIZE];
struct sockaddr_storage lo;
memset(&lo, 0, sizeof(struct sockaddr_storage));
if (knet_strtoaddr("127.0.0.1", "50000", &lo, sizeof(struct sockaddr_storage)) < 0) {
printf("Unable to convert loopback to sockaddr: %s\n", strerror(errno));
exit(FAIL);
}
memset(send_buff, 0, sizeof(send_buff));
printf("Test knet_send_sync incorrect knet_h\n");
if ((!knet_send_sync(NULL, send_buff, KNET_MAX_PACKET_SIZE, channel)) || (errno != EINVAL)) {
printf("knet_send_sync accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno));
exit(FAIL);
}
setup_logpipes(logfds);
knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG);
if (!knet_h) {
printf("knet_handle_new failed: %s\n", strerror(errno));
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
printf("Test knet_send_sync with no send_buff\n");
if ((!knet_send_sync(knet_h, NULL, KNET_MAX_PACKET_SIZE, channel)) || (errno != EINVAL)) {
printf("knet_send_sync accepted invalid send_buff or returned incorrect error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_send_sync with invalid send_buff len (0)\n");
if ((!knet_send_sync(knet_h, send_buff, 0, channel)) || (errno != EINVAL)) {
printf("knet_send_sync accepted invalid send_buff len (0) or returned incorrect error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_send_sync with invalid send_buff len (> KNET_MAX_PACKET_SIZE)\n");
if ((!knet_send_sync(knet_h, send_buff, KNET_MAX_PACKET_SIZE + 1, channel)) || (errno != EINVAL)) {
printf("knet_send_sync accepted invalid send_buff len (> KNET_MAX_PACKET_SIZE) or returned incorrect error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_send_sync with invalid channel (-1)\n");
channel = -1;
if ((!knet_send_sync(knet_h, send_buff, KNET_MAX_PACKET_SIZE, channel)) || (errno != EINVAL)) {
printf("knet_send_sync accepted invalid channel (-1) or returned incorrect error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_send_sync with invalid channel (KNET_DATAFD_MAX)\n");
channel = KNET_DATAFD_MAX;
if ((!knet_send_sync(knet_h, send_buff, KNET_MAX_PACKET_SIZE, channel)) || (errno != EINVAL)) {
printf("knet_send_sync accepted invalid channel (KNET_DATAFD_MAX) or returned incorrect error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_send_sync with unconfigured channel\n");
channel = 0;
if ((!knet_send_sync(knet_h, send_buff, KNET_MAX_PACKET_SIZE, channel)) || (errno != EINVAL)) {
printf("knet_send_sync accepted invalid unconfigured channel or returned incorrect error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_send_sync with data forwarding disabled\n");
if (knet_handle_enable_sock_notify(knet_h, &private_data, sock_notify) < 0) {
printf("knet_handle_enable_sock_notify failed: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
datafd = 0;
channel = -1;
if (knet_handle_add_datafd(knet_h, &datafd, &channel) < 0) {
printf("knet_handle_add_datafd failed: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if ((knet_send_sync(knet_h, send_buff, KNET_MAX_PACKET_SIZE, channel) == sizeof(send_buff)) || (errno != ECANCELED)) {
printf("knet_send_sync didn't detect datafwd disabled or returned incorrect error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_send_sync with broken dst_host_filter\n");
if (knet_handle_setfwd(knet_h, 1) < 0) {
printf("knet_handle_setfwd failed: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (knet_handle_enable_filter(knet_h, NULL, dhost_filter) < 0) {
printf("knet_handle_enable_filter failed: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
dhost_filter_ret = -1;
if ((knet_send_sync(knet_h, send_buff, KNET_MAX_PACKET_SIZE, channel) == sizeof(send_buff)) || (errno != EFAULT)) {
printf("knet_send_sync didn't detect fatal error from dst_host_filter or returned incorrect error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_send_sync with dst_host_filter returning no host_ids_entries\n");
dhost_filter_ret = 0;
if ((knet_send_sync(knet_h, send_buff, KNET_MAX_PACKET_SIZE, channel) == sizeof(send_buff)) || (errno != EINVAL)) {
printf("knet_send_sync didn't detect 0 host_ids from dst_host_filter or returned incorrect error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_send_sync with host down\n");
dhost_filter_ret = 1;
if ((knet_send_sync(knet_h, send_buff, KNET_MAX_PACKET_SIZE, channel) == sizeof(send_buff)) || (errno != EHOSTDOWN)) {
printf("knet_send_sync didn't detect hostdown or returned incorrect error: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_send_sync with dst_host_filter returning too many host_ids_entries\n");
if (knet_host_add(knet_h, 1) < 0) {
printf("knet_host_add failed: %s\n", strerror(errno));
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (knet_link_set_config(knet_h, 1, 0, KNET_TRANSPORT_UDP, &lo, &lo) < 0) {
printf("Unable to configure link: %s\n", strerror(errno));
knet_host_remove(knet_h, 1);
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
if (knet_link_set_enable(knet_h, 1, 0, 1) < 0) {
printf("knet_link_set_enable failed: %s\n", strerror(errno));
knet_link_clear_config(knet_h, 1, 0);
knet_host_remove(knet_h, 1);
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
while(knet_h->host_index[1]->status.reachable != 1) {
printf("waiting host to be reachable\n");
sleep(1);
}
dhost_filter_ret = 2;
if ((knet_send_sync(knet_h, send_buff, KNET_MAX_PACKET_SIZE, channel) == sizeof(send_buff)) || (errno != E2BIG)) {
printf("knet_send_sync didn't detect 2+ host_ids from dst_host_filter or returned incorrect error: %s\n", strerror(errno));
knet_link_set_enable(knet_h, 1, 0, 0);
knet_link_clear_config(knet_h, 1, 0);
knet_host_remove(knet_h, 1);
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_send_sync with dst_host_filter returning mcast packets\n");
dhost_filter_ret = 3;
if ((knet_send_sync(knet_h, send_buff, KNET_MAX_PACKET_SIZE, channel) == sizeof(send_buff)) || (errno != E2BIG)) {
printf("knet_send_sync didn't detect mcast packet from dst_host_filter or returned incorrect error: %s\n", strerror(errno));
knet_link_set_enable(knet_h, 1, 0, 0);
knet_link_clear_config(knet_h, 1, 0);
knet_host_remove(knet_h, 1);
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
printf("Test knet_send_sync with valid data\n");
dhost_filter_ret = 1;
if (knet_send_sync(knet_h, send_buff, KNET_MAX_PACKET_SIZE, channel) < 0) {
printf("knet_send_sync failed: %d %s\n", errno, strerror(errno));
knet_link_set_enable(knet_h, 1, 0, 0);
knet_link_clear_config(knet_h, 1, 0);
knet_host_remove(knet_h, 1);
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
exit(FAIL);
}
flush_logs(logfds[0], stdout);
knet_link_set_enable(knet_h, 1, 0, 0);
knet_link_clear_config(knet_h, 1, 0);
knet_host_remove(knet_h, 1);
knet_handle_free(knet_h);
flush_logs(logfds[0], stdout);
close_logpipes(logfds);
}
int main(int argc, char *argv[])
{
need_root();
test();
return PASS;
}
diff --git a/libknet/tests/knet_bench.c b/libknet/tests/knet_bench.c
index ad9008d2..2d862e92 100644
--- a/libknet/tests/knet_bench.c
+++ b/libknet/tests/knet_bench.c
@@ -1,663 +1,663 @@
/*
* Copyright (C) 2016 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 <signal.h>
#include <pthread.h>
#include "libknet.h"
#include "internals.h"
#include "netutils.h"
#include "test-common.h"
#define MAX_NODES 128
static int senderid = -1;
static knet_handle_t knet_h;
static int datafd = 0;
static int8_t channel = 0;
static int globallistener = 0;
static int continous = 0;
static struct sockaddr_storage allv4;
static struct sockaddr_storage allv6;
static int broadcast_test = 1;
static pthread_t rx_thread = (pthread_t)NULL;
static char *rx_buf[PCKT_FRAG_MAX];
static int shutdown_in_progress = 0;
static pthread_mutex_t shutdown_mutex = PTHREAD_MUTEX_INITIALIZER;
#define TEST_PING 0
#define TEST_PING_AND_DATA 1
#define TEST_PERF 2
static int test_type = TEST_PING;
struct node {
int nodeid;
int links;
struct sockaddr_storage address[KNET_MAX_LINK];
};
static void print_help(void)
{
printf("knet_bench usage:\n");
printf(" -h print this help (no really)\n");
printf(" -d enable debug logs (default INFO)\n");
printf(" -c [implementation]:[crypto]:[hashing] crypto configuration. (default disabled)\n");
printf(" Example: -c nss:aes128:sha1\n");
printf(" -p [active|passive|rr] (default: passive)\n");
printf(" -P [udp|sctp] (default: udp) protocol (transport) to use\n");
printf(" -t [nodeid] This nodeid (required)\n");
printf(" -n [nodeid],[link1_ip_addr],[link2_..] Other nodes information (at least one required)\n");
printf(" Example: -t 1,192.168.8.1,3ffe::8:1,..\n");
printf(" can be repeated up to %d and should contain also the localnode info\n", MAX_NODES);
printf(" -b [port] baseport (default: 50000)\n");
printf(" -l enable global listener on 0.0.0.0/:: (default: off, incompatible with -o)\n");
printf(" -o enable baseport offset per nodeid\n");
printf(" -w dont wait for all nodes to be up before starting the test (default: wait)\n");
printf(" -T [ping|ping_data|perf] test type (default: ping)\n");
printf(" ping: will wait for all hosts to join the knet network, sleep 5 seconds and quit\n");
printf(" ping_data: will wait for all hosts to join the knet network, sends some data to all nodes and quit\n");
printf(" perf: will wait for all hosts to join the knet network, perform a series of benchmarks and quit\n");
printf(" -s nodeid that will generate traffic for benchmarks\n");
printf(" -C repeat the test continously (default: off)\n");
}
static void parse_nodes(char *nodesinfo[MAX_NODES], int onidx, int port, struct node nodes[MAX_NODES], int thisnodeid, int *thisidx)
{
int i;
char *temp = NULL;
char port_str[10];
memset(port_str, 0, sizeof(port_str));
sprintf(port_str, "%d", port);
for (i = 0; i < onidx; i++) {
nodes[i].nodeid = atoi(strtok(nodesinfo[i], ","));
if ((nodes[i].nodeid < 0) || (nodes[i].nodeid > KNET_MAX_HOST)) {
printf("Invalid nodeid: %d (0 - %d)\n", nodes[i].nodeid, KNET_MAX_HOST);
exit(FAIL);
}
if (thisnodeid == nodes[i].nodeid) {
*thisidx = i;
}
while((temp = strtok(NULL, ","))) {
if (nodes[i].links == KNET_MAX_LINK) {
printf("Too many links configured. Max %d\n", KNET_MAX_LINK);
exit(FAIL);
}
if (knet_strtoaddr(temp, port_str,
&nodes[i].address[nodes[i].links],
sizeof(struct sockaddr_storage)) < 0) {
printf("Unable to convert %s to sockaddress\n", temp);
exit(FAIL);
}
nodes[i].links++;
}
}
if (knet_strtoaddr("0.0.0.0", port_str, &allv4, sizeof(struct sockaddr_storage)) < 0) {
printf("Unable to convert 0.0.0.0 to sockaddress\n");
exit(FAIL);
}
if (knet_strtoaddr("::", port_str, &allv6, sizeof(struct sockaddr_storage)) < 0) {
printf("Unable to convert :: to sockaddress\n");
exit(FAIL);
}
for (i = 1; i < onidx; i++) {
if (nodes[0].links != nodes[i].links) {
printf("knet_bench does not support unbalanced link configuration\n");
exit(FAIL);
}
}
return;
}
static int private_data;
static void sock_notify(void *pvt_data,
int local_datafd,
int8_t local_channel,
uint8_t tx_rx,
int error,
int errorno)
{
printf("Error (%d - %d - %s) from socket: %d\n", error, errorno, strerror(errno), local_datafd);
return;
}
static void setup_knet(int argc, char *argv[])
{
int logfd;
int rv;
char *cryptocfg = NULL, *policystr = NULL, *protostr = NULL;
char *othernodeinfo[MAX_NODES];
struct node nodes[MAX_NODES];
int thisnodeid = -1;
int thisidx = -1;
int onidx = 0;
int debug = KNET_LOG_INFO;
int port = 50000, portoffset = 0;
int thisport = 0, otherport = 0;
int thisnewport = 0, othernewport = 0;
struct sockaddr_in *so_in;
struct sockaddr_in6 *so_in6;
struct sockaddr_storage *src;
int i, link_idx, allnodesup = 0;
int policy = KNET_LINK_POLICY_PASSIVE, policyfound = 0;
int protocol = KNET_TRANSPORT_UDP, protofound = 0;
int wait = 1;
struct knet_handle_crypto_cfg knet_handle_crypto_cfg;
char *cryptomodel = NULL, *cryptotype = NULL, *cryptohash = NULL;
memset(nodes, 0, sizeof(nodes));
while ((rv = getopt(argc, argv, "CT:s:ldowb:t:n:c:p:P:h")) != EOF) {
switch(rv) {
case 'h':
print_help();
exit(PASS);
break;
case 'd':
debug = KNET_LOG_DEBUG;
break;
case 'c':
if (cryptocfg) {
printf("Error: -c can only be specified once\n");
exit(FAIL);
}
cryptocfg = optarg;
break;
case 'p':
if (policystr) {
printf("Error: -p can only be specified once\n");
exit(FAIL);
}
policystr = optarg;
if (!strcmp(policystr, "active")) {
policy = KNET_LINK_POLICY_ACTIVE;
policyfound = 1;
}
if (!strcmp(policystr, "rr")) {
policy = KNET_LINK_POLICY_RR;
policyfound = 1;
}
if (!strcmp(policystr, "passive")) {
policy = KNET_LINK_POLICY_PASSIVE;
policyfound = 1;
}
if (!policyfound) {
printf("Error: invalid policy %s specified. -p accepts active|passive|rr\n", policystr);
exit(FAIL);
}
break;
case 'P':
if (protostr) {
printf("Error: -P can only be specified once\n");
exit(FAIL);
}
protostr = optarg;
if (!strcmp(protostr, "udp")) {
protocol = KNET_TRANSPORT_UDP;
protofound = 1;
}
if (!strcmp(protostr, "sctp")) {
protocol = KNET_TRANSPORT_SCTP;
protofound = 1;
}
if (!protofound) {
printf("Error: invalid protocol %s specified. -P accepts udp|sctp\n", policystr);
exit(FAIL);
}
break;
case 't':
if (thisnodeid >= 0) {
printf("Error: -t can only be specified once\n");
exit(FAIL);
}
thisnodeid = atoi(optarg);
if ((thisnodeid < 0) || (thisnodeid > 65536)) {
printf("Error: -t nodeid out of range %d (1 - 65536)\n", thisnodeid);
exit(FAIL);
}
break;
case 'n':
if (onidx == MAX_NODES) {
printf("Error: too many other nodes. Max %d\n", MAX_NODES);
exit(FAIL);
}
othernodeinfo[onidx] = optarg;
onidx++;
break;
case 'b':
port = atoi(optarg);
if ((port < 1) || (port > 65536)) {
printf("Error: port %d out of range (1 - 65536)\n", port);
exit(FAIL);
}
case 'o':
if (globallistener) {
printf("Error: -l cannot be used with -o\n");
exit(FAIL);
}
portoffset = 1;
break;
case 'l':
if (portoffset) {
printf("Error: -o cannot be used with -l\n");
exit(FAIL);
}
globallistener = 1;
break;
case 'w':
wait = 0;
break;
case 's':
if (senderid >= 0) {
printf("Error: -s can only be specified once\n");
exit(FAIL);
}
senderid = atoi(optarg);
if ((senderid < 0) || (senderid > 65536)) {
printf("Error: -s nodeid out of range %d (1 - 65536)\n", senderid);
exit(FAIL);
}
break;
case 'T':
if (!strcmp("ping", optarg)) {
test_type = TEST_PING;
}
if (!strcmp("ping_data", optarg)) {
test_type = TEST_PING_AND_DATA;
}
if (!strcmp("perf", optarg)) {
test_type = TEST_PERF;
}
break;
case 'C':
continous = 1;
break;
default:
break;
}
}
if (thisnodeid < 0) {
printf("Who am I?!? missing -t from command line?\n");
exit(FAIL);
}
if (onidx < 1) {
printf("no other nodes configured?!? missing -n from command line\n");
exit(FAIL);
}
parse_nodes(othernodeinfo, onidx, port, nodes, thisnodeid, &thisidx);
if (thisidx < 0) {
printf("no config for this node found\n");
exit(FAIL);
}
if (senderid >= 0) {
for (i=0; i < onidx; i++) {
if (senderid == nodes[i].nodeid) {
break;
}
}
if (i == onidx) {
printf("Unable to find senderid in nodelist\n");
exit(FAIL);
}
}
if ((test_type == TEST_PERF) && (senderid < 0)) {
printf("Error: performance test requires -s to be set (for now)\n");
exit(FAIL);
}
logfd = start_logging(stdout);
knet_h = knet_handle_new(thisnodeid, logfd, debug);
if (!knet_h) {
printf("Unable to knet_handle_new: %s\n", strerror(errno));
exit(FAIL);
}
if (cryptocfg) {
memset(&knet_handle_crypto_cfg, 0, sizeof(knet_handle_crypto_cfg));
cryptomodel = strtok(cryptocfg, ":");
cryptotype = strtok(NULL, ":");
cryptohash = strtok(NULL, ":");
if (cryptomodel) {
strncpy(knet_handle_crypto_cfg.crypto_model, cryptomodel, sizeof(knet_handle_crypto_cfg.crypto_model) - 1);
}
if (cryptotype) {
strncpy(knet_handle_crypto_cfg.crypto_cipher_type, cryptotype, sizeof(knet_handle_crypto_cfg.crypto_cipher_type) - 1);
}
if (cryptohash) {
strncpy(knet_handle_crypto_cfg.crypto_hash_type, cryptohash, sizeof(knet_handle_crypto_cfg.crypto_hash_type) - 1);
}
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(FAIL);
}
}
if (knet_handle_enable_sock_notify(knet_h, &private_data, sock_notify) < 0) {
printf("knet_handle_enable_sock_notify failed: %s\n", strerror(errno));
knet_handle_free(knet_h);
exit(FAIL);
}
datafd = 0;
channel = -1;
if (knet_handle_add_datafd(knet_h, &datafd, &channel) < 0) {
printf("knet_handle_add_datafd failed: %s\n", strerror(errno));
knet_handle_free(knet_h);
exit(FAIL);
}
for (i=0; i < onidx; i++) {
if (i == thisidx) {
continue;
}
if (knet_host_add(knet_h, nodes[i].nodeid) < 0) {
printf("knet_host_add failed: %s\n", strerror(errno));
exit(FAIL);
}
if (knet_host_set_policy(knet_h, nodes[i].nodeid, policy) < 0) {
printf("knet_host_set_policy failed: %s\n", strerror(errno));
exit(FAIL);
}
for (link_idx = 0; link_idx < nodes[i].links; link_idx++) {
if (portoffset) {
if (nodes[thisidx].address[link_idx].ss_family == AF_INET) {
so_in = (struct sockaddr_in *)&nodes[thisidx].address[link_idx];
thisport = ntohs(so_in->sin_port);
thisnewport = thisport + nodes[i].nodeid;
so_in->sin_port = (htons(thisnewport));
so_in = (struct sockaddr_in *)&nodes[i].address[link_idx];
otherport = ntohs(so_in->sin_port);
othernewport = otherport + nodes[thisidx].nodeid;
so_in->sin_port = (htons(othernewport));
} else {
so_in6 = (struct sockaddr_in6 *)&nodes[thisidx].address[link_idx];
thisport = ntohs(so_in6->sin6_port);
thisnewport = thisport + nodes[i].nodeid;
so_in6->sin6_port = (htons(thisnewport));
so_in6 = (struct sockaddr_in6 *)&nodes[i].address[link_idx];
otherport = ntohs(so_in6->sin6_port);
othernewport = otherport + nodes[thisidx].nodeid;
so_in6->sin6_port = (htons(othernewport));
}
}
if (!globallistener) {
src = &nodes[thisidx].address[link_idx];
} else {
if (nodes[thisidx].address[link_idx].ss_family == AF_INET) {
src = &allv4;
} else {
src = &allv6;
}
}
if (knet_link_set_config(knet_h, nodes[i].nodeid, link_idx,
protocol, src,
&nodes[i].address[link_idx]) < 0) {
printf("Unable to configure link: %s\n", strerror(errno));
exit(FAIL);
}
if (portoffset) {
if (nodes[thisidx].address[link_idx].ss_family == AF_INET) {
so_in = (struct sockaddr_in *)&nodes[thisidx].address[link_idx];
so_in->sin_port = (htons(thisport));
so_in = (struct sockaddr_in *)&nodes[i].address[link_idx];
so_in->sin_port = (htons(otherport));
} else {
so_in6 = (struct sockaddr_in6 *)&nodes[thisidx].address[link_idx];
so_in6->sin6_port = (htons(thisport));
so_in6 = (struct sockaddr_in6 *)&nodes[i].address[link_idx];
so_in6->sin6_port = (htons(otherport));
}
}
if (knet_link_set_enable(knet_h, nodes[i].nodeid, link_idx, 1) < 0) {
printf("knet_link_set_enable failed: %s\n", strerror(errno));
exit(FAIL);
}
}
}
if (knet_handle_setfwd(knet_h, 1) < 0) {
printf("knet_handle_setfwd failed: %s\n", strerror(errno));
exit(FAIL);
}
if (wait) {
while(!allnodesup) {
allnodesup = 1;
for (i=0; i < onidx; i++) {
if (i == thisidx) {
continue;
}
if(knet_h->host_index[nodes[i].nodeid]->status.reachable != 1) {
printf("waiting host %d to be reachable\n", nodes[i].nodeid);
allnodesup = 0;
}
}
if (!allnodesup) {
sleep(1);
}
}
sleep(1);
}
}
static int ping_dst_host_filter(void *pvt_data,
const unsigned char *outdata,
ssize_t outdata_len,
uint8_t tx_rx,
- uint16_t this_host_id,
- uint16_t src_host_id,
+ uint8_t this_host_id,
+ uint8_t src_host_id,
int8_t *dst_channel,
- uint16_t *dst_host_ids,
+ uint8_t *dst_host_ids,
size_t *dst_host_ids_entries)
{
if (broadcast_test) {
return 1;
}
if (tx_rx == KNET_NOTIFY_TX) {
- memmove(&dst_host_ids[0], outdata, 2);
+ memmove(&dst_host_ids[0], outdata, 1);
} else {
dst_host_ids[0] = this_host_id;
}
*dst_host_ids_entries = 1;
return 0;
}
static void *_rx_thread(void *args)
{
fd_set rfds;
ssize_t len;
struct timeval tv;
struct sockaddr_storage address[PCKT_FRAG_MAX];
struct mmsghdr msg[PCKT_FRAG_MAX];
struct iovec iov_in[PCKT_FRAG_MAX];
int i, msg_recv;
for (i = 0; i < PCKT_FRAG_MAX; i++) {
rx_buf[i] = malloc(KNET_MAX_PACKET_SIZE);
if (!rx_buf[i]) {
printf("RXT: Unable to malloc!\n");
return NULL;
}
memset(rx_buf[i], 0, KNET_MAX_PACKET_SIZE);
iov_in[i].iov_base = (void *)rx_buf[i];
iov_in[i].iov_len = KNET_MAX_PACKET_SIZE;
memset(&msg[i].msg_hdr, 0, sizeof(struct msghdr));
msg[i].msg_hdr.msg_name = &address[i];
msg[i].msg_hdr.msg_namelen = sizeof(struct sockaddr_storage);
msg[i].msg_hdr.msg_iov = &iov_in[i];
msg[i].msg_hdr.msg_iovlen = 1;
}
select_loop:
tv.tv_sec = 5;
tv.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(datafd, &rfds);
len = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
if (len < 0) {
printf("RXT: Unable select over datafd\nHALTING RX THREAD!\n");
return NULL;
}
if (!len) {
printf("RXT: No data for the past 5 seconds\n");
}
if (FD_ISSET(datafd, &rfds)) {
msg_recv = recvmmsg(datafd, msg, PCKT_FRAG_MAX, MSG_DONTWAIT | MSG_NOSIGNAL, NULL);
if (msg_recv < 0) {
printf("RXT: error from recvmmsg: %s\n", strerror(errno));
}
for (i = 0; i < msg_recv; i++) {
if (msg[i].msg_len == 0) {
printf("RXT: received 0 bytes message?\n");
}
if (test_type == TEST_PING_AND_DATA) {
printf("received %lu bytes message: %s\n", (long)msg[i].msg_len, (char *)msg[i].msg_hdr.msg_iov->iov_base);
}
/*
* do stats here
*/
}
}
goto select_loop;
return NULL;
}
static void setup_data_txrx_common(void)
{
if (!rx_thread) {
if (knet_handle_enable_filter(knet_h, NULL, ping_dst_host_filter)) {
printf("Unable to enable dst_host_filter: %s\n", strerror(errno));
exit(FAIL);
}
printf("Setting up rx thread\n");
if (pthread_create(&rx_thread, 0, _rx_thread, NULL)) {
printf("Unable to start rx thread\n");
exit(FAIL);
}
}
}
static void stop_rx_thread(void)
{
void *retval;
int i;
if (rx_thread) {
printf("Shutting down rx thread\n");
pthread_cancel(rx_thread);
pthread_join(rx_thread, &retval);
for (i = 0; i < PCKT_FRAG_MAX; i ++) {
free(rx_buf[i]);
}
}
}
static void send_ping_data(void)
{
const char *buf = "Hello world!\x0";
ssize_t len = strlen(buf);
if (knet_send(knet_h, buf, len, channel) != len) {
printf("Error sending hello world: %s\n", strerror(errno));
}
sleep(1);
}
static void cleanup_all(void)
{
if (pthread_mutex_lock(&shutdown_mutex)) {
return;
}
if (shutdown_in_progress) {
pthread_mutex_unlock(&shutdown_mutex);
return;
}
shutdown_in_progress = 1;
pthread_mutex_unlock(&shutdown_mutex);
if (rx_thread) {
stop_rx_thread();
}
knet_handle_stop(knet_h);
}
static void sigint_handler(int signum)
{
printf("Cleaning up... got signal: %d\n", signum);
cleanup_all();
exit(PASS);
}
int main(int argc, char *argv[])
{
if (signal(SIGINT, sigint_handler) == SIG_ERR) {
printf("Unable to configure SIGINT handler\n");
exit(FAIL);
}
need_root();
setup_knet(argc, argv);
restart:
switch(test_type) {
default:
case TEST_PING: /* basic ping, no data */
sleep(5);
break;
case TEST_PING_AND_DATA:
setup_data_txrx_common();
send_ping_data();
break;
case TEST_PERF:
setup_data_txrx_common();
break;
}
if (continous) {
goto restart;
}
cleanup_all();
return PASS;
}
diff --git a/libknet/tests/test-common.c b/libknet/tests/test-common.c
index 6eb68de4..94cf25be 100644
--- a/libknet/tests/test-common.c
+++ b/libknet/tests/test-common.c
@@ -1,434 +1,434 @@
/*
* Copyright (C) 2016 Red Hat, Inc. All rights reserved.
*
* Author: 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 <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <pthread.h>
#include "libknet.h"
#include "test-common.h"
static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
static int log_init = 0;
static pthread_mutex_t log_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_t log_thread;
static int log_thread_init = 0;
static int log_fds[2];
struct log_thread_data {
int logfd;
FILE *std;
};
static struct log_thread_data data;
static pthread_mutex_t shutdown_mutex = PTHREAD_MUTEX_INITIALIZER;
static int shutdown_in_progress = 0;
static int _read_pipe(int fd, char **file, size_t *length)
{
char buf[4096];
int n;
int done = 0;
*file = NULL;
*length = 0;
memset(buf, 0, sizeof(buf));
while (!done) {
n = read(fd, buf, sizeof(buf));
if (n < 0) {
if (errno == EINTR)
continue;
if (*file)
free(*file);
return n;
}
if (n == 0 && (!*length))
return 0;
if (n == 0)
done = 1;
if (*file)
*file = realloc(*file, (*length) + n + done);
else
*file = malloc(n + done);
if (!*file)
return -1;
memcpy((*file) + (*length), buf, n);
*length += (done + n);
}
/* Null terminator */
(*file)[(*length) - 1] = 0;
return 0;
}
int execute_shell(const char *command, char **error_string)
{
pid_t pid;
int status, err = 0;
int fd[2];
size_t size = 0;
if ((command == NULL) || (!error_string)) {
errno = EINVAL;
return FAIL;
}
*error_string = NULL;
err = pipe(fd);
if (err)
goto out_clean;
pid = fork();
if (pid < 0) {
err = pid;
goto out_clean;
}
if (pid) { /* parent */
close(fd[1]);
err = _read_pipe(fd[0], error_string, &size);
if (err)
goto out_clean0;
waitpid(pid, &status, 0);
if (!WIFEXITED(status)) {
err = -1;
goto out_clean0;
}
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
err = WEXITSTATUS(status);
goto out_clean0;
}
goto out_clean0;
} else { /* child */
close(0);
close(1);
close(2);
close(fd[0]);
dup2(fd[1], 1);
dup2(fd[1], 2);
close(fd[1]);
execlp("/bin/sh", "/bin/sh", "-c", command, NULL);
exit(FAIL);
}
out_clean:
close(fd[1]);
out_clean0:
close(fd[0]);
return err;
}
int is_memcheck(void)
{
char *val;
val = getenv("KNETMEMCHECK");
if (val) {
if (!strncmp(val, "yes", 3)) {
return 1;
}
}
return 0;
}
int is_helgrind(void)
{
char *val;
val = getenv("KNETHELGRIND");
if (val) {
if (!strncmp(val, "yes", 3)) {
return 1;
}
}
return 0;
}
int need_root(void)
{
if (geteuid() != 0) {
printf("This test requires root privileges\n");
exit(SKIP);
}
return PASS;
}
void set_scheduler(int policy)
{
struct sched_param sched_param;
int err;
err = sched_get_priority_max(policy);
if (err < 0) {
printf("Could not get maximum scheduler priority\n");
exit(FAIL);
}
sched_param.sched_priority = err;
err = sched_setscheduler(0, policy, &sched_param);
if (err < 0) {
printf("Could not set priority\n");
exit(FAIL);
}
return;
}
int setup_logpipes(int *logfds)
{
if (pipe2(logfds, O_CLOEXEC | O_NONBLOCK) < 0) {
printf("Unable to setup logging pipe\n");
exit(FAIL);
}
return PASS;
}
void close_logpipes(int *logfds)
{
close(logfds[0]);
logfds[0] = 0;
close(logfds[1]);
logfds[1] = 0;
}
void flush_logs(int logfd, FILE *std)
{
struct knet_log_msg msg;
size_t bytes_read;
int len;
next:
len = 0;
bytes_read = 0;
memset(&msg, 0, sizeof(struct knet_log_msg));
while (bytes_read < sizeof(struct knet_log_msg)) {
len = read(logfd, &msg + bytes_read,
sizeof(struct knet_log_msg) - bytes_read);
if (len <= 0) {
return;
}
bytes_read += len;
}
if (len > 0) {
fprintf(std, "knet logs: [%s] %s: %s\n",
knet_log_get_loglevel_name(msg.msglevel),
knet_log_get_subsystem_name(msg.subsystem),
msg.msg);
goto next;
}
}
static void *_logthread(void *args)
{
fd_set rfds;
ssize_t len;
struct timeval tv;
select_loop:
tv.tv_sec = 5;
tv.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(data.logfd, &rfds);
len = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
if (len < 0) {
fprintf(data.std, "Unable select over logfd!\nHALTING LOGTHREAD!\n");
return NULL;
}
if (!len) {
fprintf(data.std, "knet logs: No logs in the last 5 seconds\n");
}
if (FD_ISSET(data.logfd, &rfds)) {
flush_logs(data.logfd, data.std);
}
goto select_loop;
return NULL;
}
int start_logthread(int logfd, FILE *std)
{
int savederrno = 0;
savederrno = pthread_mutex_lock(&log_thread_mutex);
if (savederrno) {
printf("Unable to get log_thread mutex lock\n");
return -1;
}
if (!log_thread_init) {
data.logfd = logfd;
data.std = std;
savederrno = pthread_create(&log_thread, 0, _logthread, NULL);
if (savederrno) {
printf("Unable to start logging thread: %s\n", strerror(savederrno));
pthread_mutex_unlock(&log_thread_mutex);
return -1;
}
log_thread_init = 1;
}
pthread_mutex_unlock(&log_thread_mutex);
return 0;
}
int stop_logthread(void)
{
int savederrno = 0;
void *retval;
savederrno = pthread_mutex_lock(&log_thread_mutex);
if (savederrno) {
printf("Unable to get log_thread mutex lock\n");
return -1;
}
if (log_thread_init) {
pthread_cancel(log_thread);
pthread_join(log_thread, &retval);
log_thread_init = 0;
}
pthread_mutex_unlock(&log_thread_mutex);
return 0;
}
static void stop_logging(void)
{
stop_logthread();
flush_logs(log_fds[0], stdout);
close_logpipes(log_fds);
}
int start_logging(FILE *std)
{
int savederrno = 0;
savederrno = pthread_mutex_lock(&log_mutex);
if (savederrno) {
printf("Unable to get log_mutex lock\n");
return -1;
}
if (!log_init) {
setup_logpipes(log_fds);
if (atexit(&stop_logging) != 0) {
printf("Unable to register atexit handler to stop logging: %s\n",
strerror(errno));
exit(FAIL);
}
if (start_logthread(log_fds[0], std) < 0) {
exit(FAIL);
}
log_init = 1;
}
pthread_mutex_unlock(&log_mutex);
return log_fds[1];
}
int knet_handle_stop(knet_handle_t knet_h)
{
int i, j, savederrno;
- uint16_t host_ids[KNET_MAX_HOST];
+ uint8_t host_ids[KNET_MAX_HOST];
uint8_t link_ids[KNET_MAX_LINK];
size_t host_ids_entries = 0, link_ids_entries = 0;
struct knet_link_status status;
savederrno = pthread_mutex_lock(&shutdown_mutex);
if (savederrno) {
printf("Unable to get shutdown mutex lock\n");
return -1;
}
if (shutdown_in_progress) {
pthread_mutex_unlock(&shutdown_mutex);
errno = EINVAL;
return -1;
}
shutdown_in_progress = 1;
pthread_mutex_unlock(&shutdown_mutex);
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (knet_host_get_host_list(knet_h, host_ids, &host_ids_entries) < 0) {
printf("knet_host_get_host_list failed: %s\n", strerror(errno));
return -1;
}
for (i = 0; i < host_ids_entries; i++) {
if (knet_link_get_link_list(knet_h, host_ids[i], link_ids, &link_ids_entries)) {
printf("knet_link_get_link_list failed: %s\n", strerror(errno));
return -1;
}
for (j = 0; j < link_ids_entries; j++) {
if (knet_link_get_status(knet_h, host_ids[i], link_ids[j], &status)) {
printf("knet_link_get_status failed: %s\n", strerror(errno));
return -1;
}
if (status.enabled) {
if (knet_link_set_enable(knet_h, host_ids[i], j, 0)) {
printf("knet_link_set_enable failed: %s\n", strerror(errno));
return -1;
}
}
knet_link_clear_config(knet_h, host_ids[i], j);
}
if (knet_host_remove(knet_h, host_ids[i]) < 0) {
printf("knet_host_remove failed: %s\n", strerror(errno));
return -1;
}
}
if (knet_handle_free(knet_h)) {
printf("knet_handle_free failed: %s\n", strerror(errno));
return -1;
}
return 0;
}
diff --git a/libknet/threads_dsthandler.c b/libknet/threads_dsthandler.c
index c01b3847..c855cc5c 100644
--- a/libknet/threads_dsthandler.c
+++ b/libknet/threads_dsthandler.c
@@ -1,61 +1,61 @@
/*
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
*
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
* Federico Simoncelli <fsimon@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#include "config.h"
#include <unistd.h>
#include <pthread.h>
#include "host.h"
#include "compat.h"
#include "logging.h"
#include "threads_common.h"
#include "threads_dsthandler.h"
static void _handle_dst_link_updates(knet_handle_t knet_h)
{
- uint16_t host_id;
+ uint8_t host_id;
struct knet_host *host;
if (recv(knet_h->dstsockfd[0], &host_id, sizeof(host_id), MSG_DONTWAIT | MSG_NOSIGNAL) != sizeof(host_id)) {
log_debug(knet_h, KNET_SUB_DSTCACHE, "Short read on dstsockfd");
return;
}
if (pthread_rwlock_wrlock(&knet_h->global_rwlock) != 0) {
log_debug(knet_h, KNET_SUB_DSTCACHE, "Unable to get read lock");
return;
}
host = knet_h->host_index[host_id];
if (!host) {
log_debug(knet_h, KNET_SUB_DSTCACHE, "Unable to find host: %u", host_id);
goto out_unlock;
}
_host_dstcache_update_sync(knet_h, host);
out_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
return;
}
void *_handle_dst_link_handler_thread(void *data)
{
knet_handle_t knet_h = (knet_handle_t) data;
struct epoll_event events[KNET_EPOLL_MAX_EVENTS];
while (!shutdown_in_progress(knet_h)) {
if (epoll_wait(knet_h->dst_link_handler_epollfd, events, KNET_EPOLL_MAX_EVENTS, -1) >= 1)
_handle_dst_link_updates(knet_h);
}
return NULL;
}
diff --git a/libknet/threads_heartbeat.c b/libknet/threads_heartbeat.c
index 77727245..c4f48405 100644
--- a/libknet/threads_heartbeat.c
+++ b/libknet/threads_heartbeat.c
@@ -1,167 +1,167 @@
/*
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
*
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
* Federico Simoncelli <fsimon@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#include "config.h"
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#include "crypto.h"
#include "link.h"
#include "logging.h"
#include "threads_common.h"
#include "threads_heartbeat.h"
static void _link_down(knet_handle_t knet_h, struct knet_host *dst_host, struct knet_link *dst_link)
{
memset(&dst_link->pmtud_last, 0, sizeof(struct timespec));
dst_link->received_pong = 0;
dst_link->status.pong_last.tv_nsec = 0;
if (dst_link->status.connected == 1) {
log_info(knet_h, KNET_SUB_LINK, "host: %u link: %u is down",
dst_host->host_id, dst_link->link_id);
_link_updown(knet_h, dst_host->host_id, dst_link->link_id, dst_link->status.enabled, 0);
}
}
static void _handle_check_each(knet_handle_t knet_h, struct knet_host *dst_host, struct knet_link *dst_link, int timed)
{
int err = 0, savederrno = 0;
int len;
ssize_t outlen = KNET_HEADER_PING_SIZE;
struct timespec clock_now, pong_last;
unsigned long long diff_ping;
unsigned char *outbuf = (unsigned char *)knet_h->pingbuf;
if (dst_link->transport_connected == 0) {
_link_down(knet_h, dst_host, dst_link);
return;
}
/* caching last pong to avoid race conditions */
pong_last = dst_link->status.pong_last;
if (clock_gettime(CLOCK_MONOTONIC, &clock_now) != 0) {
log_debug(knet_h, KNET_SUB_HEARTBEAT, "Unable to get monotonic clock");
return;
}
timespec_diff(dst_link->ping_last, clock_now, &diff_ping);
if ((diff_ping >= (dst_link->ping_interval * 1000llu)) || (!timed)) {
memmove(&knet_h->pingbuf->khp_ping_time[0], &clock_now, sizeof(struct timespec));
knet_h->pingbuf->khp_ping_link = dst_link->link_id;
if (pthread_mutex_lock(&knet_h->tx_seq_num_mutex)) {
log_debug(knet_h, KNET_SUB_HEARTBEAT, "Unable to get seq mutex lock");
return;
}
knet_h->pingbuf->khp_ping_seq_num = htons(knet_h->tx_seq_num);
pthread_mutex_unlock(&knet_h->tx_seq_num_mutex);
knet_h->pingbuf->khp_ping_timed = timed;
if (knet_h->crypto_instance) {
if (crypto_encrypt_and_sign(knet_h,
(const unsigned char *)knet_h->pingbuf,
outlen,
knet_h->pingbuf_crypt,
&outlen) < 0) {
log_debug(knet_h, KNET_SUB_HEARTBEAT, "Unable to crypto ping packet");
return;
}
outbuf = knet_h->pingbuf_crypt;
}
retry:
len = sendto(dst_link->outsock, outbuf, outlen,
MSG_DONTWAIT | MSG_NOSIGNAL, (struct sockaddr *) &dst_link->dst_addr,
sizeof(struct sockaddr_storage));
dst_link->ping_last = clock_now;
if (len != outlen) {
err = knet_h->transport_ops[dst_link->transport_type]->transport_tx_sock_error(knet_h, dst_link->outsock, len, savederrno);
switch(err) {
case -1: /* unrecoverable error */
log_debug(knet_h, KNET_SUB_HEARTBEAT,
"Unable to send ping (sock: %d) packet (sendto): %d %s. recorded src ip: %s src port: %s dst ip: %s dst port: %s",
dst_link->outsock, errno, strerror(errno),
dst_link->status.src_ipaddr, dst_link->status.src_port,
dst_link->status.dst_ipaddr, dst_link->status.dst_port);
break;
case 0:
break;
case 1:
goto retry;
break;
}
} else {
dst_link->last_ping_size = outlen;
}
}
timespec_diff(pong_last, clock_now, &diff_ping);
if ((pong_last.tv_nsec) &&
(diff_ping >= (dst_link->pong_timeout * 1000llu))) {
_link_down(knet_h, dst_host, dst_link);
}
}
void _send_pings(knet_handle_t knet_h, int timed)
{
struct knet_host *dst_host;
int link_idx;
if (pthread_mutex_lock(&knet_h->hb_mutex)) {
log_debug(knet_h, KNET_SUB_HEARTBEAT, "Unable to get hb mutex lock");
return;
}
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].status.enabled != 1) ||
((dst_host->link[link_idx].dynamic == KNET_LINK_DYNIP) &&
(dst_host->link[link_idx].status.dynconnected != 1)))
continue;
_handle_check_each(knet_h, dst_host, &dst_host->link[link_idx], timed);
}
}
pthread_mutex_unlock(&knet_h->hb_mutex);
}
void *_handle_heartbt_thread(void *data)
{
knet_handle_t knet_h = (knet_handle_t) data;
/* preparing ping buffer */
knet_h->pingbuf->kh_version = KNET_HEADER_VERSION;
knet_h->pingbuf->kh_type = KNET_HEADER_TYPE_PING;
- knet_h->pingbuf->kh_node = htons(knet_h->host_id);
+ knet_h->pingbuf->kh_node = knet_h->host_id;
while (!shutdown_in_progress(knet_h)) {
usleep(KNET_THREADS_TIMERES);
if (pthread_rwlock_rdlock(&knet_h->global_rwlock) != 0) {
log_debug(knet_h, KNET_SUB_HEARTBEAT, "Unable to get read lock");
continue;
}
_send_pings(knet_h, 1);
pthread_rwlock_unlock(&knet_h->global_rwlock);
}
return NULL;
}
diff --git a/libknet/threads_pmtud.c b/libknet/threads_pmtud.c
index 0df8b4fe..3f375a52 100644
--- a/libknet/threads_pmtud.c
+++ b/libknet/threads_pmtud.c
@@ -1,404 +1,404 @@
/*
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
*
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
* Federico Simoncelli <fsimon@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#include "config.h"
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include "crypto.h"
#include "link.h"
#include "host.h"
#include "logging.h"
#include "threads_common.h"
#include "threads_pmtud.h"
static int _handle_check_link_pmtud(knet_handle_t knet_h, struct knet_host *dst_host, struct knet_link *dst_link)
{
int err, ret, savederrno, mutex_retry_limit, failsafe;
ssize_t onwire_len; /* current packet onwire size */
ssize_t overhead_len; /* onwire packet overhead (protocol based) */
ssize_t max_mtu_len; /* max mtu for protocol */
ssize_t data_len; /* how much data we can send in the packet
* generally would be onwire_len - overhead_len
* needs to be adjusted for crypto
*/
ssize_t pad_len; /* crypto packet pad size, needs to move into crypto.c callbacks */
int len; /* len of what we were able to sendto onwire */
struct timespec ts;
unsigned char *outbuf = (unsigned char *)knet_h->pmtudbuf;
mutex_retry_limit = 0;
failsafe = 0;
pad_len = 0;
dst_link->last_bad_mtu = 0;
knet_h->pmtudbuf->khp_pmtud_link = dst_link->link_id;
switch (dst_link->dst_addr.ss_family) {
case AF_INET6:
max_mtu_len = KNET_PMTUD_SIZE_V6;
overhead_len = KNET_PMTUD_OVERHEAD_V6 + dst_link->proto_overhead;
dst_link->last_good_mtu = dst_link->last_ping_size + overhead_len;
break;
case AF_INET:
max_mtu_len = KNET_PMTUD_SIZE_V4;
overhead_len = KNET_PMTUD_OVERHEAD_V4 + dst_link->proto_overhead;
dst_link->last_good_mtu = dst_link->last_ping_size + overhead_len;
break;
default:
log_debug(knet_h, KNET_SUB_PMTUD, "PMTUD aborted, unknown protocol");
return -1;
break;
}
/*
* discovery starts from the top because kernel will
* refuse to send packets > current iface mtu.
* this saves us some time and network bw.
*/
onwire_len = max_mtu_len;
restart:
/*
* prevent a race when interface mtu is changed _exactly_ during
* the discovery process and it's complex to detect. Easier
* to wait the next loop.
* 30 is not an arbitrary value. To bisect from 576 to 128000 doesn't
* take more than 18/19 steps.
*/
if (failsafe == 30) {
log_err(knet_h, KNET_SUB_PMTUD,
"Aborting PMTUD process: Too many attempts. MTU might have changed during discovery.");
return -1;
} else {
failsafe++;
}
data_len = onwire_len - overhead_len;
if (knet_h->crypto_instance) {
if (knet_h->sec_block_size) {
pad_len = knet_h->sec_block_size - (data_len % knet_h->sec_block_size);
if (pad_len == knet_h->sec_block_size) {
pad_len = 0;
}
data_len = data_len + pad_len;
}
data_len = data_len + (knet_h->sec_hash_size + knet_h->sec_salt_size + knet_h->sec_block_size);
if (knet_h->sec_block_size) {
while (data_len + overhead_len >= max_mtu_len) {
data_len = data_len - knet_h->sec_block_size;
}
}
if (dst_link->last_bad_mtu) {
while (data_len + overhead_len >= dst_link->last_bad_mtu) {
data_len = data_len - (knet_h->sec_hash_size + knet_h->sec_salt_size + knet_h->sec_block_size);
}
}
if (data_len < (knet_h->sec_hash_size + knet_h->sec_salt_size + knet_h->sec_block_size) + 1) {
log_debug(knet_h, KNET_SUB_PMTUD, "Aborting PMTUD process: link mtu smaller than crypto header detected (link might have been disconnected)");
return -1;
}
onwire_len = data_len + overhead_len;
knet_h->pmtudbuf->khp_pmtud_size = onwire_len;
if (crypto_encrypt_and_sign(knet_h,
(const unsigned char *)knet_h->pmtudbuf,
data_len - (knet_h->sec_hash_size + knet_h->sec_salt_size + knet_h->sec_block_size),
knet_h->pmtudbuf_crypt,
&data_len) < 0) {
log_debug(knet_h, KNET_SUB_PMTUD, "Unable to crypto pmtud packet");
return -1;
}
outbuf = knet_h->pmtudbuf_crypt;
} else {
knet_h->pmtudbuf->khp_pmtud_size = onwire_len;
}
/* link has gone down, aborting pmtud */
if (dst_link->status.connected != 1) {
log_debug(knet_h, KNET_SUB_PMTUD, "PMTUD detected host (%u) link (%u) has been disconnected", dst_host->host_id, dst_link->link_id);
return -1;
}
if (dst_link->transport_connected != 1) {
log_debug(knet_h, KNET_SUB_PMTUD, "PMTUD detected host (%u) link (%u) has been disconnected", dst_host->host_id, dst_link->link_id);
return -1;
}
if (pthread_mutex_lock(&knet_h->pmtud_mutex) != 0) {
log_debug(knet_h, KNET_SUB_PMTUD, "Unable to get mutex lock");
return -1;
}
retry:
len = sendto(dst_link->outsock, outbuf, data_len,
MSG_DONTWAIT | MSG_NOSIGNAL, (struct sockaddr *) &dst_link->dst_addr,
sizeof(struct sockaddr_storage));
savederrno = errno;
err = knet_h->transport_ops[dst_link->transport_type]->transport_tx_sock_error(knet_h, dst_link->outsock, len, savederrno);
switch(err) {
case -1: /* unrecoverable error */
log_debug(knet_h, KNET_SUB_PMTUD, "Unable to send pmtu packet (sendto): %d %s", savederrno, strerror(savederrno));
pthread_mutex_unlock(&knet_h->pmtud_mutex);
return -1;
case 0: /* ignore error and continue */
break;
case 1: /* retry to send those same data */
goto retry;
break;
}
if (len != data_len) {
if (savederrno == EMSGSIZE) {
dst_link->last_bad_mtu = onwire_len;
} else {
log_debug(knet_h, KNET_SUB_PMTUD, "Unable to send pmtu packet len: %zu err: %s", onwire_len, strerror(savederrno));
}
} else {
dst_link->last_sent_mtu = onwire_len;
dst_link->last_recv_mtu = 0;
if (clock_gettime(CLOCK_REALTIME, &ts) < 0) {
log_debug(knet_h, KNET_SUB_PMTUD, "Unable to get current time: %s", strerror(errno));
pthread_mutex_unlock(&knet_h->pmtud_mutex);
return -1;
}
/*
* Set an artibrary 2 seconds timeout to receive a PMTUd reply
* perhaps this should be configurable but:
* 1) too short timeout can cause instability since MTU value
* influeces link status
* 2) too high timeout slows down the MTU detection process for
* small MTU
*
* Another option is to make the PMTUd process less influent
* in link status detection but that could cause data packet loss
* without link up/down changes
*/
ts.tv_sec += 2;
ret = pthread_cond_timedwait(&knet_h->pmtud_cond, &knet_h->pmtud_mutex, &ts);
if (shutdown_in_progress(knet_h)) {
pthread_mutex_unlock(&knet_h->pmtud_mutex);
log_debug(knet_h, KNET_SUB_PMTUD, "PMTUD aborted. shutdown in progress");
return -1;
}
if ((ret != 0) && (ret != ETIMEDOUT)) {
pthread_mutex_unlock(&knet_h->pmtud_mutex);
if (mutex_retry_limit == 3) {
log_debug(knet_h, KNET_SUB_PMTUD, "PMTUD aborted, unable to get mutex lock");
return -1;
}
mutex_retry_limit++;
goto restart;
}
if ((dst_link->last_recv_mtu != onwire_len) || (ret)) {
dst_link->last_bad_mtu = onwire_len;
} else {
int found_mtu = 0;
if (knet_h->sec_block_size) {
if ((onwire_len + knet_h->sec_block_size >= max_mtu_len) ||
((dst_link->last_bad_mtu) && (dst_link->last_bad_mtu <= (onwire_len + knet_h->sec_block_size)))) {
found_mtu = 1;
}
} else {
if ((onwire_len == max_mtu_len) ||
((dst_link->last_bad_mtu) && (dst_link->last_bad_mtu == (onwire_len + 1)))) {
found_mtu = 1;
}
}
if (found_mtu) {
/*
* account for IP overhead, knet headers and crypto in PMTU calculation
*/
dst_link->status.mtu = onwire_len - dst_link->status.proto_overhead;
pthread_mutex_unlock(&knet_h->pmtud_mutex);
return 0;
}
dst_link->last_good_mtu = onwire_len;
}
}
onwire_len = (dst_link->last_good_mtu + dst_link->last_bad_mtu) / 2;
pthread_mutex_unlock(&knet_h->pmtud_mutex);
goto restart;
}
static int _handle_check_pmtud(knet_handle_t knet_h, struct knet_host *dst_host, struct knet_link *dst_link, unsigned int *min_mtu)
{
uint8_t saved_valid_pmtud;
unsigned int saved_pmtud;
struct timespec clock_now;
unsigned long long diff_pmtud, interval;
interval = knet_h->pmtud_interval * 1000000000llu; /* nanoseconds */
if (clock_gettime(CLOCK_MONOTONIC, &clock_now) != 0) {
log_debug(knet_h, KNET_SUB_PMTUD, "Unable to get monotonic clock");
return 0;
}
timespec_diff(dst_link->pmtud_last, clock_now, &diff_pmtud);
if (diff_pmtud < interval) {
*min_mtu = dst_link->status.mtu;
return dst_link->has_valid_mtu;
}
switch (dst_link->dst_addr.ss_family) {
case AF_INET6:
dst_link->status.proto_overhead = KNET_PMTUD_OVERHEAD_V6 + dst_link->proto_overhead + KNET_HEADER_ALL_SIZE + knet_h->sec_header_size;
break;
case AF_INET:
dst_link->status.proto_overhead = KNET_PMTUD_OVERHEAD_V4 + dst_link->proto_overhead + KNET_HEADER_ALL_SIZE + knet_h->sec_header_size;
break;
}
saved_pmtud = dst_link->status.mtu;
saved_valid_pmtud = dst_link->has_valid_mtu;
log_debug(knet_h, KNET_SUB_PMTUD, "Starting PMTUD for host: %u link: %u", dst_host->host_id, dst_link->link_id);
if (_handle_check_link_pmtud(knet_h, dst_host, dst_link) < 0) {
dst_link->has_valid_mtu = 0;
} else {
dst_link->has_valid_mtu = 1;
switch (dst_link->dst_addr.ss_family) {
case AF_INET6:
if (((dst_link->status.mtu + dst_link->status.proto_overhead) < KNET_PMTUD_MIN_MTU_V6) ||
((dst_link->status.mtu + dst_link->status.proto_overhead) > KNET_PMTUD_SIZE_V6)) {
log_debug(knet_h, KNET_SUB_PMTUD,
"PMTUD detected an IPv6 MTU out of bound value (%u) for host: %u link: %u.",
dst_link->status.mtu + dst_link->status.proto_overhead, dst_host->host_id, dst_link->link_id);
dst_link->has_valid_mtu = 0;
}
break;
case AF_INET:
if (((dst_link->status.mtu + dst_link->status.proto_overhead) < KNET_PMTUD_MIN_MTU_V4) ||
((dst_link->status.mtu + dst_link->status.proto_overhead) > KNET_PMTUD_SIZE_V4)) {
log_debug(knet_h, KNET_SUB_PMTUD,
"PMTUD detected an IPv4 MTU out of bound value (%u) for host: %u link: %u.",
dst_link->status.mtu + dst_link->status.proto_overhead, dst_host->host_id, dst_link->link_id);
dst_link->has_valid_mtu = 0;
}
break;
}
if (dst_link->has_valid_mtu) {
if ((saved_pmtud) && (saved_pmtud != dst_link->status.mtu)) {
log_info(knet_h, KNET_SUB_PMTUD, "PMTUD link change for host: %u link: %u from %u to %u",
dst_host->host_id, dst_link->link_id, saved_pmtud, dst_link->status.mtu);
}
log_debug(knet_h, KNET_SUB_PMTUD, "PMTUD completed for host: %u link: %u current link mtu: %u",
dst_host->host_id, dst_link->link_id, dst_link->status.mtu);
if (dst_link->status.mtu < *min_mtu) {
*min_mtu = dst_link->status.mtu;
}
dst_link->pmtud_last = clock_now;
}
}
if (saved_valid_pmtud != dst_link->has_valid_mtu) {
_host_dstcache_update_sync(knet_h, dst_host);
}
return dst_link->has_valid_mtu;
}
void *_handle_pmtud_link_thread(void *data)
{
knet_handle_t knet_h = (knet_handle_t) data;
struct knet_host *dst_host;
struct knet_link *dst_link;
int link_idx;
unsigned int min_mtu, have_mtu;
unsigned int lower_mtu;
knet_h->data_mtu = KNET_PMTUD_MIN_MTU_V4 - KNET_HEADER_ALL_SIZE - knet_h->sec_header_size;
/* preparing pmtu buffer */
knet_h->pmtudbuf->kh_version = KNET_HEADER_VERSION;
knet_h->pmtudbuf->kh_type = KNET_HEADER_TYPE_PMTUD;
- knet_h->pmtudbuf->kh_node = htons(knet_h->host_id);
+ knet_h->pmtudbuf->kh_node = knet_h->host_id;
while (!shutdown_in_progress(knet_h)) {
usleep(KNET_THREADS_TIMERES);
if (pthread_rwlock_rdlock(&knet_h->global_rwlock) != 0) {
log_debug(knet_h, KNET_SUB_PMTUD, "Unable to get read lock");
continue;
}
lower_mtu = KNET_PMTUD_SIZE_V4;
min_mtu = KNET_PMTUD_SIZE_V4 - KNET_HEADER_ALL_SIZE - knet_h->sec_header_size;
have_mtu = 0;
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++) {
dst_link = &dst_host->link[link_idx];
if ((dst_link->status.enabled != 1) ||
(dst_link->status.connected != 1) ||
(!dst_link->last_ping_size) ||
((dst_link->dynamic == KNET_LINK_DYNIP) &&
(dst_link->status.dynconnected != 1)))
continue;
if (_handle_check_pmtud(knet_h, dst_host, dst_link, &min_mtu)) {
have_mtu = 1;
if (min_mtu < lower_mtu) {
lower_mtu = min_mtu;
}
}
}
}
if (have_mtu) {
if (knet_h->data_mtu != lower_mtu) {
knet_h->data_mtu = lower_mtu;
log_info(knet_h, KNET_SUB_PMTUD, "Global data MTU changed to: %u", knet_h->data_mtu);
if (knet_h->pmtud_notify_fn) {
knet_h->pmtud_notify_fn(knet_h->pmtud_notify_fn_private_data,
knet_h->data_mtu);
}
}
}
pthread_rwlock_unlock(&knet_h->global_rwlock);
}
return NULL;
}
diff --git a/libknet/threads_rx.c b/libknet/threads_rx.c
index b3e177aa..65feab4d 100644
--- a/libknet/threads_rx.c
+++ b/libknet/threads_rx.c
@@ -1,727 +1,725 @@
/*
* Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved.
*
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
* Federico Simoncelli <fsimon@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include "compat.h"
#include "crypto.h"
#include "host.h"
#include "link.h"
#include "logging.h"
#include "transports.h"
#include "threads_common.h"
#include "threads_heartbeat.h"
#include "threads_rx.h"
#include "netutils.h"
/*
* RECV
*/
/*
* return 1 if a > b
* return -1 if b > a
* return 0 if they are equal
*/
static inline int timecmp(struct timespec a, struct timespec b)
{
if (a.tv_sec != b.tv_sec) {
if (a.tv_sec > b.tv_sec) {
return 1;
} else {
return -1;
}
} else {
if (a.tv_nsec > b.tv_nsec) {
return 1;
} else if (a.tv_nsec < b.tv_nsec) {
return -1;
} else {
return 0;
}
}
}
/*
* this functions needs to return an index (0 to 7)
* to a knet_host_defrag_buf. (-1 on errors)
*/
static int find_pckt_defrag_buf(knet_handle_t knet_h, struct knet_header *inbuf)
{
struct knet_host *src_host = knet_h->host_index[inbuf->kh_node];
int i, oldest;
/*
* check if there is a buffer already in use handling the same seq_num
*/
for (i = 0; i < KNET_MAX_LINK; i++) {
if (src_host->defrag_buf[i].in_use) {
if (src_host->defrag_buf[i].pckt_seq == inbuf->khp_data_seq_num) {
return i;
}
}
}
/*
* If there is no buffer that's handling the current seq_num
* either it's new or it's been reclaimed already.
* check if it's been reclaimed/seen before using the defrag circular
* buffer. If the pckt has been seen before, the buffer expired (ETIME)
* and there is no point to try to defrag it again.
*/
if (!_seq_num_lookup(src_host, inbuf->khp_data_seq_num, 1, 0)) {
errno = ETIME;
return -1;
}
/*
* register the pckt as seen
*/
_seq_num_set(src_host, inbuf->khp_data_seq_num, 1);
/*
* see if there is a free buffer
*/
for (i = 0; i < KNET_MAX_LINK; i++) {
if (!src_host->defrag_buf[i].in_use) {
return i;
}
}
/*
* at this point, there are no free buffers, the pckt is new
* and we need to reclaim a buffer, and we will take the one
* with the oldest timestamp. It's as good as any.
*/
oldest = 0;
for (i = 0; i < KNET_MAX_LINK; i++) {
if (timecmp(src_host->defrag_buf[i].last_update, src_host->defrag_buf[oldest].last_update) < 0) {
oldest = i;
}
}
src_host->defrag_buf[oldest].in_use = 0;
return oldest;
}
static int pckt_defrag(knet_handle_t knet_h, struct knet_header *inbuf, ssize_t *len)
{
struct knet_host_defrag_buf *defrag_buf;
int defrag_buf_idx;
defrag_buf_idx = find_pckt_defrag_buf(knet_h, inbuf);
if (defrag_buf_idx < 0) {
if (errno == ETIME) {
log_debug(knet_h, KNET_SUB_RX, "Defrag buffer expired");
}
return 1;
}
defrag_buf = &knet_h->host_index[inbuf->kh_node]->defrag_buf[defrag_buf_idx];
/*
* if the buf is not is use, then make sure it's clean
*/
if (!defrag_buf->in_use) {
memset(defrag_buf, 0, sizeof(struct knet_host_defrag_buf));
defrag_buf->in_use = 1;
defrag_buf->pckt_seq = inbuf->khp_data_seq_num;
}
/*
* update timestamp on the buffer
*/
clock_gettime(CLOCK_MONOTONIC, &defrag_buf->last_update);
/*
* check if we already received this fragment
*/
if (defrag_buf->frag_map[inbuf->khp_data_frag_seq]) {
/*
* if we have received this fragment and we didn't clear the buffer
* it means that we don't have all fragments yet
*/
return 1;
}
/*
* we need to handle the last packet with gloves due to its different size
*/
if (inbuf->khp_data_frag_seq == inbuf->khp_data_frag_num) {
defrag_buf->last_frag_size = *len;
/*
* in the event when the last packet arrives first,
* we still don't know the offset vs the other fragments (based on MTU),
* so we store the fragment at the end of the buffer where it's safe
* and take a copy of the len so that we can restore its offset later.
* remember we can't use the local MTU for this calculation because pMTU
* can be asymettric between the same hosts.
*/
if (!defrag_buf->frag_size) {
defrag_buf->last_first = 1;
memmove(defrag_buf->buf + (KNET_MAX_PACKET_SIZE - *len),
inbuf->khp_data_userdata,
*len);
}
} else {
defrag_buf->frag_size = *len;
}
memmove(defrag_buf->buf + ((inbuf->khp_data_frag_seq - 1) * defrag_buf->frag_size),
inbuf->khp_data_userdata, *len);
defrag_buf->frag_recv++;
defrag_buf->frag_map[inbuf->khp_data_frag_seq] = 1;
/*
* check if we received all the fragments
*/
if (defrag_buf->frag_recv == inbuf->khp_data_frag_num) {
/*
* special case the last pckt
*/
if (defrag_buf->last_first) {
memmove(defrag_buf->buf + ((inbuf->khp_data_frag_num - 1) * defrag_buf->frag_size),
defrag_buf->buf + (KNET_MAX_PACKET_SIZE - defrag_buf->last_frag_size),
defrag_buf->last_frag_size);
}
/*
* recalculate packet lenght
*/
*len = ((inbuf->khp_data_frag_num - 1) * defrag_buf->frag_size) + defrag_buf->last_frag_size;
/*
* copy the pckt back in the user data
*/
memmove(inbuf->khp_data_userdata, defrag_buf->buf, *len);
/*
* free this buffer
*/
defrag_buf->in_use = 0;
return 0;
}
return 1;
}
static void _parse_recv_from_links(knet_handle_t knet_h, int sockfd, const struct mmsghdr *msg)
{
int err = 0, savederrno = 0;
ssize_t outlen;
struct knet_host *src_host;
struct knet_link *src_link;
unsigned long long latency_last;
- uint16_t dst_host_ids[KNET_MAX_HOST];
+ uint8_t dst_host_ids[KNET_MAX_HOST];
size_t dst_host_ids_entries = 0;
int bcast = 1;
struct timespec recvtime;
struct knet_header *inbuf = msg->msg_hdr.msg_iov->iov_base;
unsigned char *outbuf = (unsigned char *)msg->msg_hdr.msg_iov->iov_base;
ssize_t len = msg->msg_len;
struct knet_hostinfo *knet_hostinfo;
struct iovec iov_out[1];
int8_t channel;
struct sockaddr_storage pckt_src;
seq_num_t recv_seq_num;
int wipe_bufs = 0;
if (knet_h->crypto_instance) {
if (crypto_authenticate_and_decrypt(knet_h,
(unsigned char *)inbuf,
len,
knet_h->recv_from_links_buf_decrypt,
&outlen) < 0) {
log_debug(knet_h, KNET_SUB_RX, "Unable to decrypt/auth packet");
return;
}
len = outlen;
inbuf = (struct knet_header *)knet_h->recv_from_links_buf_decrypt;
}
if (len < (KNET_HEADER_SIZE + 1)) {
log_debug(knet_h, KNET_SUB_RX, "Packet is too short: %ld", len);
return;
}
if (inbuf->kh_version != KNET_HEADER_VERSION) {
log_debug(knet_h, KNET_SUB_RX, "Packet version does not match");
return;
}
- inbuf->kh_node = ntohs(inbuf->kh_node);
src_host = knet_h->host_index[inbuf->kh_node];
if (src_host == NULL) { /* host not found */
log_debug(knet_h, KNET_SUB_RX, "Unable to find source host for this packet");
return;
}
src_link = NULL;
if ((inbuf->kh_type & KNET_HEADER_TYPE_PMSK) != 0) {
src_link = src_host->link +
(inbuf->khp_ping_link % KNET_MAX_LINK);
if (src_link->dynamic == KNET_LINK_DYNIP) {
/*
* cpyaddrport will only copy address and port of the incoming
* packet and strip extra bits such as flow and scopeid
*/
cpyaddrport(&pckt_src, msg->msg_hdr.msg_name);
if (cmpaddr(&src_link->dst_addr, sockaddr_len(&src_link->dst_addr),
&pckt_src, sockaddr_len(&pckt_src)) != 0) {
log_debug(knet_h, KNET_SUB_RX, "host: %u link: %u appears to have changed ip address",
src_host->host_id, src_link->link_id);
memmove(&src_link->dst_addr, &pckt_src, sizeof(struct sockaddr_storage));
if (knet_addrtostr(&src_link->dst_addr, sockaddr_len(msg->msg_hdr.msg_name),
src_link->status.dst_ipaddr, KNET_MAX_HOST_LEN,
src_link->status.dst_port, KNET_MAX_PORT_LEN) != 0) {
log_debug(knet_h, KNET_SUB_RX, "Unable to resolve ???");
snprintf(src_link->status.dst_ipaddr, KNET_MAX_HOST_LEN - 1, "Unknown!!!");
snprintf(src_link->status.dst_port, KNET_MAX_PORT_LEN - 1, "??");
} else {
log_info(knet_h, KNET_SUB_RX,
"host: %u link: %u new connection established from: %s %s",
src_host->host_id, src_link->link_id,
src_link->status.dst_ipaddr, src_link->status.dst_port);
}
}
/*
* transport has already accepted the connection here
* otherwise we would not be receiving packets
*/
knet_h->transport_ops[src_link->transport_type]->transport_link_dyn_connect(knet_h, sockfd, src_link);
}
}
switch (inbuf->kh_type) {
case KNET_HEADER_TYPE_HOST_INFO:
case KNET_HEADER_TYPE_DATA:
/*
* TODO: should we accept data even if we can't reply to the other node?
* how would that work with SCTP and guaranteed delivery?
*/
if (!src_host->status.reachable) {
log_debug(knet_h, KNET_SUB_RX, "Source host %u not reachable yet", src_host->host_id);
//return;
}
inbuf->khp_data_seq_num = ntohs(inbuf->khp_data_seq_num);
channel = inbuf->khp_data_channel;
src_host->got_data = 1;
if (!_seq_num_lookup(src_host, inbuf->khp_data_seq_num, 0, 0)) {
if (src_host->link_handler_policy != KNET_LINK_POLICY_ACTIVE) {
log_debug(knet_h, KNET_SUB_RX, "Packet has already been delivered");
}
return;
}
if (inbuf->khp_data_frag_num > 1) {
/*
* len as received from the socket also includes extra stuff
* that the defrag code doesn't care about. So strip it
* here and readd only for repadding once we are done
* defragging
*/
len = len - KNET_HEADER_DATA_SIZE;
if (pckt_defrag(knet_h, inbuf, &len)) {
return;
}
len = len + KNET_HEADER_DATA_SIZE;
}
if (inbuf->kh_type == KNET_HEADER_TYPE_DATA) {
if (knet_h->enabled != 1) /* data forward is disabled */
break;
if (knet_h->dst_host_filter_fn) {
int host_idx;
int found = 0;
bcast = knet_h->dst_host_filter_fn(
knet_h->dst_host_filter_fn_private_data,
(const unsigned char *)inbuf->khp_data_userdata,
len - KNET_HEADER_DATA_SIZE,
KNET_NOTIFY_RX,
knet_h->host_id,
inbuf->kh_node,
&channel,
dst_host_ids,
&dst_host_ids_entries);
if (bcast < 0) {
log_debug(knet_h, KNET_SUB_RX, "Error from dst_host_filter_fn: %d", bcast);
return;
}
if ((!bcast) && (!dst_host_ids_entries)) {
log_debug(knet_h, KNET_SUB_RX, "Message is unicast but no dst_host_ids_entries");
return;
}
/* 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->host_id) {
found = 1;
break;
}
}
if (!found) {
log_debug(knet_h, KNET_SUB_RX, "Packet is not for us");
return;
}
}
}
}
if (inbuf->kh_type == KNET_HEADER_TYPE_DATA) {
if (!knet_h->sockfd[channel].in_use) {
log_debug(knet_h, KNET_SUB_RX,
"received packet for channel %d but there is no local sock connected",
channel);
return;
}
memset(iov_out, 0, sizeof(iov_out));
iov_out[0].iov_base = (void *) inbuf->khp_data_userdata;
iov_out[0].iov_len = len - KNET_HEADER_DATA_SIZE;
outlen = writev(knet_h->sockfd[channel].sockfd[knet_h->sockfd[channel].is_created], iov_out, 1);
if (outlen <= 0) {
knet_h->sock_notify_fn(knet_h->sock_notify_fn_private_data,
knet_h->sockfd[channel].sockfd[0],
channel,
KNET_NOTIFY_RX,
outlen,
errno);
return;
}
if (outlen == iov_out[0].iov_len) {
_seq_num_set(src_host, inbuf->khp_data_seq_num, 0);
}
} else { /* HOSTINFO */
knet_hostinfo = (struct knet_hostinfo *)inbuf->khp_data_userdata;
if (knet_hostinfo->khi_bcast == KNET_HOSTINFO_UCAST) {
bcast = 0;
- knet_hostinfo->khi_dst_node_id = ntohs(knet_hostinfo->khi_dst_node_id);
}
if (!_seq_num_lookup(src_host, inbuf->khp_data_seq_num, 0, 0)) {
return;
}
_seq_num_set(src_host, inbuf->khp_data_seq_num, 0);
switch(knet_hostinfo->khi_type) {
case KNET_HOSTINFO_TYPE_LINK_UP_DOWN:
break;
case KNET_HOSTINFO_TYPE_LINK_TABLE:
break;
default:
log_warn(knet_h, KNET_SUB_RX, "Receiving unknown host info message from host %u", src_host->host_id);
break;
}
}
break;
case KNET_HEADER_TYPE_PING:
outlen = KNET_HEADER_PING_SIZE;
inbuf->kh_type = KNET_HEADER_TYPE_PONG;
- inbuf->kh_node = htons(knet_h->host_id);
+ inbuf->kh_node = knet_h->host_id;
recv_seq_num = ntohs(inbuf->khp_ping_seq_num);
wipe_bufs = 0;
if (!inbuf->khp_ping_timed) {
/*
* we might be receiving this message from all links, but we want
* to process it only the first time
*/
if (recv_seq_num != src_host->untimed_rx_seq_num) {
/*
* cache the untimed seq num
*/
src_host->untimed_rx_seq_num = recv_seq_num;
/*
* if the host has received data in between
* untimed ping, then we don't need to wipe the bufs
*/
if (src_host->got_data) {
src_host->got_data = 0;
wipe_bufs = 0;
} else {
wipe_bufs = 1;
}
}
_seq_num_lookup(src_host, recv_seq_num, 0, wipe_bufs);
} else {
/*
* pings always arrives in bursts over all the link
* catch the first of them to cache the seq num and
* avoid duplicate processing
*/
if (recv_seq_num != src_host->timed_rx_seq_num) {
src_host->timed_rx_seq_num = recv_seq_num;
if (recv_seq_num == 0) {
_seq_num_lookup(src_host, recv_seq_num, 0, 1);
}
}
}
if (knet_h->crypto_instance) {
if (crypto_encrypt_and_sign(knet_h,
(const unsigned char *)inbuf,
len,
knet_h->recv_from_links_buf_crypt,
&outlen) < 0) {
log_debug(knet_h, KNET_SUB_RX, "Unable to encrypt pong packet");
break;
}
outbuf = knet_h->recv_from_links_buf_crypt;
}
retry_pong:
len = sendto(src_link->outsock, outbuf, outlen, MSG_DONTWAIT | MSG_NOSIGNAL,
(struct sockaddr *) &src_link->dst_addr,
sizeof(struct sockaddr_storage));
savederrno = errno;
if (len != outlen) {
err = knet_h->transport_ops[src_link->transport_type]->transport_tx_sock_error(knet_h, src_link->outsock, len, savederrno);
switch(err) {
case -1: /* unrecoverable error */
log_debug(knet_h, KNET_SUB_RX,
"Unable to send pong reply (sock: %d) packet (sendto): %d %s. recorded src ip: %s src port: %s dst ip: %s dst port: %s",
src_link->outsock, errno, strerror(errno),
src_link->status.src_ipaddr, src_link->status.src_port,
src_link->status.dst_ipaddr, src_link->status.dst_port);
break;
case 0: /* ignore error and continue */
break;
case 1: /* retry to send those same data */
goto retry_pong;
break;
}
}
break;
case KNET_HEADER_TYPE_PONG:
clock_gettime(CLOCK_MONOTONIC, &src_link->status.pong_last);
memmove(&recvtime, &inbuf->khp_ping_time[0], sizeof(struct timespec));
timespec_diff(recvtime,
src_link->status.pong_last, &latency_last);
src_link->status.latency =
((src_link->status.latency * src_link->latency_exp) +
((latency_last / 1000llu) *
(src_link->latency_fix - src_link->latency_exp))) /
src_link->latency_fix;
if (src_link->status.latency < src_link->pong_timeout) {
if (!src_link->status.connected) {
if (src_link->received_pong >= src_link->pong_count) {
log_info(knet_h, KNET_SUB_RX, "host: %u link: %u is up",
src_host->host_id, src_link->link_id);
_link_updown(knet_h, src_host->host_id, src_link->link_id, src_link->status.enabled, 1);
} else {
src_link->received_pong++;
log_debug(knet_h, KNET_SUB_RX, "host: %u link: %u received pong: %u",
src_host->host_id, src_link->link_id, src_link->received_pong);
}
}
}
break;
case KNET_HEADER_TYPE_PMTUD:
outlen = KNET_HEADER_PMTUD_SIZE;
inbuf->kh_type = KNET_HEADER_TYPE_PMTUD_REPLY;
- inbuf->kh_node = htons(knet_h->host_id);
+ inbuf->kh_node = knet_h->host_id;
if (knet_h->crypto_instance) {
if (crypto_encrypt_and_sign(knet_h,
(const unsigned char *)inbuf,
len,
knet_h->recv_from_links_buf_crypt,
&outlen) < 0) {
log_debug(knet_h, KNET_SUB_RX, "Unable to encrypt PMTUd reply packet");
break;
}
outbuf = knet_h->recv_from_links_buf_crypt;
}
retry_pmtud:
len = sendto(src_link->outsock, outbuf, outlen, MSG_DONTWAIT | MSG_NOSIGNAL,
(struct sockaddr *) &src_link->dst_addr,
sizeof(struct sockaddr_storage));
if (len != outlen) {
err = knet_h->transport_ops[src_link->transport_type]->transport_tx_sock_error(knet_h, src_link->outsock, len, savederrno);
switch(err) {
case -1: /* unrecoverable error */
log_debug(knet_h, KNET_SUB_RX,
"Unable to send PMTUd reply (sock: %d) packet (sendto): %d %s. recorded src ip: %s src port: %s dst ip: %s dst port: %s",
src_link->outsock, errno, strerror(errno),
src_link->status.src_ipaddr, src_link->status.src_port,
src_link->status.dst_ipaddr, src_link->status.dst_port);
break;
case 0: /* ignore error and continue */
break;
case 1: /* retry to send those same data */
goto retry_pmtud;
break;
}
}
break;
case KNET_HEADER_TYPE_PMTUD_REPLY:
if (pthread_mutex_lock(&knet_h->pmtud_mutex) != 0) {
log_debug(knet_h, KNET_SUB_RX, "Unable to get mutex lock");
break;
}
src_link->last_recv_mtu = inbuf->khp_pmtud_size;
pthread_cond_signal(&knet_h->pmtud_cond);
pthread_mutex_unlock(&knet_h->pmtud_mutex);
break;
default:
return;
}
}
static void _handle_recv_from_links(knet_handle_t knet_h, int sockfd, struct mmsghdr *msg)
{
int err, savederrno;
int i, msg_recv, transport;
if (pthread_rwlock_rdlock(&knet_h->global_rwlock) != 0) {
log_debug(knet_h, KNET_SUB_RX, "Unable to get global read lock");
return;
}
if (_is_valid_fd(knet_h, sockfd) < 1) {
/*
* this is normal if a fd got an event and before we grab the read lock
* and the link is removed by another thread
*/
goto exit_unlock;
}
transport = knet_h->knet_transport_fd_tracker[sockfd].transport;
/*
* reset msg_namelen to buffer size because after recvmmsg
* each msg_namelen will contain sizeof sockaddr_in or sockaddr_in6
*/
for (i = 0; i < PCKT_FRAG_MAX; i++) {
msg[i].msg_hdr.msg_namelen = sizeof(struct sockaddr_storage);
}
msg_recv = recvmmsg(sockfd, msg, PCKT_FRAG_MAX, MSG_DONTWAIT | MSG_NOSIGNAL, NULL);
savederrno = errno;
/*
* WARNING: man page for recvmmsg is wrong. Kernel implementation here:
* recvmmsg can return:
* -1 on error
* 0 if the previous run of recvmmsg recorded an error on the socket
* N number of messages (see exception below).
*
* If there is an error from recvmsg after receiving a frame or more, the recvmmsg
* loop is interrupted, error recorded in the socket (getsockopt(SO_ERROR) and
* it will be visibile in the next run.
*
* Need to be careful how we handle errors at this stage.
*
* error messages need to be handled on a per transport/protocol base
* at this point we have different layers of error handling
* - msg_recv < 0 -> error from this run
* msg_recv = 0 -> error from previous run and error on socket needs to be cleared
* - per-transport message data
* example: msg[i].msg_hdr.msg_flags & MSG_NOTIFICATION or msg_len for SCTP == EOF,
* but for UDP it is perfectly legal to receive a 0 bytes message.. go figure
* - NOTE: on SCTP MSG_NOTIFICATION we get msg_recv == PCKT_FRAG_MAX messages and no
* errno set. That means the error api needs to be able to abort the loop below.
*/
if (msg_recv <= 0) {
knet_h->transport_ops[transport]->transport_rx_sock_error(knet_h, sockfd, msg_recv, savederrno);
goto exit_unlock;
}
for (i = 0; i < msg_recv; i++) {
err = knet_h->transport_ops[transport]->transport_rx_is_data(knet_h, sockfd, &msg[i]);
/*
* TODO: make this section silent once we are confident
* all protocols packet handlers are good
*/
switch(err) {
case -1: /* on error */
log_debug(knet_h, KNET_SUB_RX, "Transport reported error parsing packet");
goto exit_unlock;
break;
case 0: /* packet is not data and we should continue the packet process loop */
log_debug(knet_h, KNET_SUB_RX, "Transport reported no data, continue");
break;
case 1: /* packet is not data and we should STOP the packet process loop */
log_debug(knet_h, KNET_SUB_RX, "Transport reported no data, stop");
goto exit_unlock;
break;
case 2: /* packet is data and should be parsed as such */
_parse_recv_from_links(knet_h, sockfd, &msg[i]);
break;
}
}
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
}
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_EPOLL_MAX_EVENTS];
struct sockaddr_storage address[PCKT_FRAG_MAX];
struct mmsghdr msg[PCKT_FRAG_MAX];
struct iovec iov_in[PCKT_FRAG_MAX];
memset(&msg, 0, sizeof(msg));
for (i = 0; i < PCKT_FRAG_MAX; i++) {
iov_in[i].iov_base = (void *)knet_h->recv_from_links_buf[i];
iov_in[i].iov_len = KNET_DATABUFSIZE;
memset(&msg[i].msg_hdr, 0, sizeof(struct msghdr));
msg[i].msg_hdr.msg_name = &address[i];
msg[i].msg_hdr.msg_namelen = sizeof(struct sockaddr_storage);
msg[i].msg_hdr.msg_iov = &iov_in[i];
msg[i].msg_hdr.msg_iovlen = 1;
}
while (!shutdown_in_progress(knet_h)) {
nev = epoll_wait(knet_h->recv_from_links_epollfd, events, KNET_EPOLL_MAX_EVENTS, -1);
for (i = 0; i < nev; i++) {
_handle_recv_from_links(knet_h, events[i].data.fd, msg);
}
}
return NULL;
}
diff --git a/libknet/threads_tx.c b/libknet/threads_tx.c
index efafd9d8..1786aba8 100644
--- a/libknet/threads_tx.c
+++ b/libknet/threads_tx.c
@@ -1,595 +1,594 @@
/*
* Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved.
*
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
* Federico Simoncelli <fsimon@kronosnet.org>
*
* This software licensed under GPL-2.0+, LGPL-2.0+
*/
#include "config.h"
#include <math.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include "compat.h"
#include "crypto.h"
#include "host.h"
#include "link.h"
#include "logging.h"
#include "transports.h"
#include "threads_common.h"
#include "threads_heartbeat.h"
#include "threads_tx.h"
#include "netutils.h"
/*
* SEND
*/
static int _dispatch_to_links(knet_handle_t knet_h, struct knet_host *dst_host, struct iovec *iov_out)
{
int link_idx, msg_idx, sent_msgs, msgs_to_send, prev_sent, progress;
struct mmsghdr msg[PCKT_FRAG_MAX];
int err = 0, savederrno = 0;
memset(&msg, 0, sizeof(struct mmsghdr));
for (link_idx = 0; link_idx < dst_host->active_link_entries; link_idx++) {
msgs_to_send = knet_h->send_to_links_buf[0]->khp_data_frag_num;
sent_msgs = 0;
prev_sent = 0;
progress = 1;
retry:
msg_idx = 0;
while (msg_idx < msgs_to_send) {
memset(&msg[msg_idx].msg_hdr, 0, sizeof(struct msghdr));
msg[msg_idx].msg_hdr.msg_name = &dst_host->link[dst_host->active_links[link_idx]].dst_addr;
msg[msg_idx].msg_hdr.msg_namelen = sizeof(struct sockaddr_storage);
msg[msg_idx].msg_hdr.msg_iov = &iov_out[msg_idx + prev_sent];
msg[msg_idx].msg_hdr.msg_iovlen = 1;
msg_idx++;
}
sent_msgs = sendmmsg(dst_host->link[dst_host->active_links[link_idx]].outsock,
msg, msg_idx, MSG_DONTWAIT | MSG_NOSIGNAL);
savederrno = errno;
err = knet_h->transport_ops[dst_host->link[dst_host->active_links[link_idx]].transport_type]->transport_tx_sock_error(knet_h, dst_host->link[dst_host->active_links[link_idx]].outsock, sent_msgs, savederrno);
switch(err) {
case -1: /* unrecoverable error */
goto out_unlock;
break;
case 0: /* ignore error and continue */
break;
case 1: /* retry to send those same data */
goto retry;
break;
}
if ((sent_msgs >= 0) && (sent_msgs < msg_idx)) {
if ((sent_msgs) || (progress)) {
msgs_to_send = msg_idx - sent_msgs;
prev_sent = prev_sent + sent_msgs;
if (sent_msgs) {
progress = 1;
} else {
progress = 0;
}
log_debug(knet_h, KNET_SUB_TX, "Unable to send all (%d/%d) data packets to host %s (%u) link %s:%s (%u)",
sent_msgs, msg_idx,
dst_host->name, dst_host->host_id,
dst_host->link[dst_host->active_links[link_idx]].status.dst_ipaddr,
dst_host->link[dst_host->active_links[link_idx]].status.dst_port,
dst_host->link[dst_host->active_links[link_idx]].link_id);
goto retry;
}
if (!progress) {
savederrno = EAGAIN;
err = -1;
goto out_unlock;
}
}
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;
}
}
out_unlock:
errno = savederrno;
return err;
}
static int _parse_recv_from_sock(knet_handle_t knet_h, int buf_idx, ssize_t inlen, int8_t channel, int is_sync)
{
ssize_t outlen, frag_len;
struct knet_host *dst_host;
- uint16_t dst_host_ids_temp[KNET_MAX_HOST];
+ uint8_t dst_host_ids_temp[KNET_MAX_HOST];
size_t dst_host_ids_entries_temp = 0;
- uint16_t dst_host_ids[KNET_MAX_HOST];
+ uint8_t dst_host_ids[KNET_MAX_HOST];
size_t dst_host_ids_entries = 0;
int bcast = 1;
struct knet_hostinfo *knet_hostinfo;
struct iovec iov_out[PCKT_FRAG_MAX];
uint8_t frag_idx;
unsigned int temp_data_mtu;
int host_idx;
int send_mcast = 0;
struct knet_header *inbuf;
int savederrno = 0;
int err = 0;
seq_num_t tx_seq_num;
inbuf = knet_h->recv_from_sock_buf[buf_idx];
if ((knet_h->enabled != 1) &&
(inbuf->kh_type != KNET_HEADER_TYPE_HOST_INFO)) { /* data forward is disabled */
log_debug(knet_h, KNET_SUB_TX, "Received data packet but forwarding is disabled");
savederrno = ECANCELED;
err = -1;
goto out_unlock;
}
/*
* move this into a separate function to expand on
* extra switching rules
*/
switch(inbuf->kh_type) {
case KNET_HEADER_TYPE_DATA:
if (knet_h->dst_host_filter_fn) {
bcast = knet_h->dst_host_filter_fn(
knet_h->dst_host_filter_fn_private_data,
(const unsigned char *)inbuf->khp_data_userdata,
inlen,
KNET_NOTIFY_TX,
knet_h->host_id,
knet_h->host_id,
&channel,
dst_host_ids_temp,
&dst_host_ids_entries_temp);
if (bcast < 0) {
log_debug(knet_h, KNET_SUB_TX, "Error from dst_host_filter_fn: %d", bcast);
savederrno = EFAULT;
err = -1;
goto out_unlock;
}
if ((!bcast) && (!dst_host_ids_entries_temp)) {
log_debug(knet_h, KNET_SUB_TX, "Message is unicast but no dst_host_ids_entries");
savederrno = EINVAL;
err = -1;
goto out_unlock;
}
}
break;
case KNET_HEADER_TYPE_HOST_INFO:
knet_hostinfo = (struct knet_hostinfo *)inbuf->khp_data_userdata;
if (knet_hostinfo->khi_bcast == KNET_HOSTINFO_UCAST) {
bcast = 0;
dst_host_ids_temp[0] = knet_hostinfo->khi_dst_node_id;
dst_host_ids_entries_temp = 1;
- knet_hostinfo->khi_dst_node_id = htons(knet_hostinfo->khi_dst_node_id);
}
break;
default:
log_warn(knet_h, KNET_SUB_TX, "Receiving unknown messages from socket");
savederrno = ENOMSG;
err = -1;
goto out_unlock;
break;
}
if (is_sync) {
if ((bcast) ||
((!bcast) && (dst_host_ids_entries_temp > 1))) {
log_debug(knet_h, KNET_SUB_TX, "knet_send_sync is only supported with unicast packets for one destination");
savederrno = E2BIG;
err = -1;
goto out_unlock;
}
}
/*
* check destinations hosts before spending time
* in fragmenting/encrypting packets to save
* time processing data for unrechable hosts.
* for unicast, also remap the destination data
* to skip unreachable hosts.
*/
if (!bcast) {
dst_host_ids_entries = 0;
for (host_idx = 0; host_idx < dst_host_ids_entries_temp; host_idx++) {
dst_host = knet_h->host_index[dst_host_ids_temp[host_idx]];
if (!dst_host) {
continue;
}
if (dst_host->status.reachable) {
dst_host_ids[dst_host_ids_entries] = dst_host_ids_temp[host_idx];
dst_host_ids_entries++;
}
}
if (!dst_host_ids_entries) {
savederrno = EHOSTDOWN;
err = -1;
goto out_unlock;
}
} else {
send_mcast = 0;
for (dst_host = knet_h->host_head; dst_host != NULL; dst_host = dst_host->next) {
if (dst_host->status.reachable) {
send_mcast = 1;
break;
}
}
if (!send_mcast) {
savederrno = EHOSTDOWN;
err = -1;
goto out_unlock;
}
}
if (!knet_h->data_mtu) {
/*
* using MIN_MTU_V4 for data mtu is not completely accurate but safe enough
*/
log_debug(knet_h, KNET_SUB_TX,
"Received data packet but data MTU is still unknown."
" Packet might not be delivered."
" Assuming mininum IPv4 mtu (%d)",
KNET_PMTUD_MIN_MTU_V4);
temp_data_mtu = KNET_PMTUD_MIN_MTU_V4;
} else {
/*
* take a copy of the mtu to avoid value changing under
* our feet while we are sending a fragmented pckt
*/
temp_data_mtu = knet_h->data_mtu;
}
/*
* prepare the outgoing buffers
*/
frag_len = inlen;
frag_idx = 0;
inbuf->khp_data_bcast = bcast;
inbuf->khp_data_frag_num = ceil((float)inlen / temp_data_mtu);
inbuf->khp_data_channel = channel;
if (pthread_mutex_lock(&knet_h->tx_seq_num_mutex)) {
log_debug(knet_h, KNET_SUB_TX, "Unable to get seq mutex lock");
goto out_unlock;
}
knet_h->tx_seq_num++;
/*
* force seq_num 0 to detect a node that has crashed and rejoining
* the knet instance. seq_num 0 will clear the buffers in the RX
* thread
*/
if (knet_h->tx_seq_num == 0) {
knet_h->tx_seq_num++;
}
/*
* cache the value in locked context
*/
tx_seq_num = knet_h->tx_seq_num;
knet_h->send_to_links_buf[0]->khp_data_seq_num = htons(knet_h->tx_seq_num);
pthread_mutex_unlock(&knet_h->tx_seq_num_mutex);
/*
* forcefully broadcast a ping to all nodes every SEQ_MAX / 8
* pckts.
* this solves 2 problems:
* 1) on TX socket overloads we generate extra pings to keep links alive
* 2) in 3+ nodes setup, where all the traffic is flowing between node 1 and 2,
* node 3+ will be able to keep in sync on the TX seq_num even without
* receiving traffic or pings in betweens. This avoids issues with
* rollover of the circular buffer
*/
if (tx_seq_num % (SEQ_MAX / 8) == 0) {
_send_pings(knet_h, 0);
}
while (frag_idx < inbuf->khp_data_frag_num) {
/*
* set the iov_base
*/
iov_out[frag_idx].iov_base = (void *)knet_h->send_to_links_buf[frag_idx];
/*
* set the len
*/
if (frag_len > temp_data_mtu) {
iov_out[frag_idx].iov_len = temp_data_mtu + KNET_HEADER_DATA_SIZE;
} else {
iov_out[frag_idx].iov_len = frag_len + KNET_HEADER_DATA_SIZE;
}
/*
* copy the frag info on all buffers
*/
knet_h->send_to_links_buf[frag_idx]->kh_type = inbuf->kh_type;
knet_h->send_to_links_buf[frag_idx]->khp_data_seq_num = knet_h->send_to_links_buf[0]->khp_data_seq_num;
knet_h->send_to_links_buf[frag_idx]->khp_data_frag_num = inbuf->khp_data_frag_num;
knet_h->send_to_links_buf[frag_idx]->khp_data_bcast = inbuf->khp_data_bcast;
knet_h->send_to_links_buf[frag_idx]->khp_data_channel = inbuf->khp_data_channel;
memmove(knet_h->send_to_links_buf[frag_idx]->khp_data_userdata,
inbuf->khp_data_userdata + (temp_data_mtu * frag_idx),
iov_out[frag_idx].iov_len - KNET_HEADER_DATA_SIZE);
frag_len = frag_len - temp_data_mtu;
frag_idx++;
}
if (knet_h->crypto_instance) {
frag_idx = 0;
while (frag_idx < knet_h->send_to_links_buf[0]->khp_data_frag_num) {
if (crypto_encrypt_and_sign(
knet_h,
(const unsigned char *)knet_h->send_to_links_buf[frag_idx],
iov_out[frag_idx].iov_len,
knet_h->send_to_links_buf_crypt[frag_idx],
&outlen) < 0) {
log_debug(knet_h, KNET_SUB_TX, "Unable to encrypt unicast packet");
savederrno = ECHILD;
err = -1;
goto out_unlock;
}
iov_out[frag_idx].iov_base = knet_h->send_to_links_buf_crypt[frag_idx];
iov_out[frag_idx].iov_len = outlen;
frag_idx++;
}
}
if (!bcast) {
for (host_idx = 0; host_idx < dst_host_ids_entries; host_idx++) {
dst_host = knet_h->host_index[dst_host_ids[host_idx]];
err = _dispatch_to_links(knet_h, dst_host, iov_out);
savederrno = errno;
if (err) {
goto out_unlock;
}
}
} else {
for (dst_host = knet_h->host_head; dst_host != NULL; dst_host = dst_host->next) {
if (dst_host->status.reachable) {
err = _dispatch_to_links(knet_h, dst_host, iov_out);
savederrno = errno;
if (err) {
goto out_unlock;
}
}
}
}
out_unlock:
errno = savederrno;
return err;
}
int knet_send_sync(knet_handle_t knet_h, const char *buff, const size_t buff_len, const int8_t channel)
{
int savederrno = 0, err = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (buff == NULL) {
errno = EINVAL;
return -1;
}
if (buff_len <= 0) {
errno = EINVAL;
return -1;
}
if (buff_len > KNET_MAX_PACKET_SIZE) {
errno = EINVAL;
return -1;
}
if (channel < 0) {
errno = EINVAL;
return -1;
}
if (channel >= KNET_DATAFD_MAX) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_TX, "Unable to get read lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
if (!knet_h->sockfd[channel].in_use) {
savederrno = EINVAL;
err = -1;
goto out;
}
savederrno = pthread_mutex_lock(&knet_h->tx_mutex);
if (savederrno) {
log_err(knet_h, KNET_SUB_TX, "Unable to get TX mutex lock: %s",
strerror(savederrno));
err = -1;
goto out;
}
knet_h->recv_from_sock_buf[0]->kh_type = KNET_HEADER_TYPE_DATA;
memmove(knet_h->recv_from_sock_buf[0]->khp_data_userdata, buff, buff_len);
err = _parse_recv_from_sock(knet_h, 0, buff_len, channel, 1);
savederrno = errno;
pthread_mutex_unlock(&knet_h->tx_mutex);
out:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = savederrno;
return err;
}
static void _handle_send_to_links(knet_handle_t knet_h, int sockfd, int8_t channel, struct mmsghdr *msg, int type)
{
ssize_t inlen = 0;
struct iovec iov_in;
int msg_recv, i;
int savederrno = 0, docallback = 0;
if ((channel >= 0) &&
(channel < KNET_DATAFD_MAX) &&
(!knet_h->sockfd[channel].is_socket)) {
memset(&iov_in, 0, sizeof(iov_in));
iov_in.iov_base = (void *)knet_h->recv_from_sock_buf[0]->khp_data_userdata;
iov_in.iov_len = KNET_MAX_PACKET_SIZE;
inlen = readv(sockfd, &iov_in, 1);
if (inlen <= 0) {
savederrno = errno;
docallback = 1;
goto out;
}
msg_recv = 1;
knet_h->recv_from_sock_buf[0]->kh_type = type;
_parse_recv_from_sock(knet_h, 0, inlen, channel, 0);
} else {
msg_recv = recvmmsg(sockfd, msg, PCKT_FRAG_MAX, MSG_DONTWAIT | MSG_NOSIGNAL, NULL);
if (msg_recv < 0) {
inlen = msg_recv;
savederrno = errno;
docallback = 1;
goto out;
}
for (i = 0; i < msg_recv; i++) {
inlen = msg[i].msg_len;
if (inlen == 0) {
savederrno = 0;
docallback = 1;
goto out;
break;
}
knet_h->recv_from_sock_buf[i]->kh_type = type;
_parse_recv_from_sock(knet_h, i, inlen, channel, 0);
}
}
out:
if (inlen < 0) {
struct epoll_event ev;
memset(&ev, 0, sizeof(struct epoll_event));
if (epoll_ctl(knet_h->send_to_links_epollfd,
EPOLL_CTL_DEL, knet_h->sockfd[channel].sockfd[knet_h->sockfd[channel].is_created], &ev)) {
log_err(knet_h, KNET_SUB_TX, "Unable to del datafd %d from linkfd epoll pool: %s",
knet_h->sockfd[channel].sockfd[0], strerror(savederrno));
} else {
knet_h->sockfd[channel].has_error = 1;
}
}
if (docallback) {
knet_h->sock_notify_fn(knet_h->sock_notify_fn_private_data,
knet_h->sockfd[channel].sockfd[0],
channel,
KNET_NOTIFY_TX,
inlen,
savederrno);
}
}
void *_handle_send_to_links_thread(void *data)
{
knet_handle_t knet_h = (knet_handle_t) data;
struct epoll_event events[KNET_EPOLL_MAX_EVENTS];
struct sockaddr_storage address[PCKT_FRAG_MAX];
struct mmsghdr msg[PCKT_FRAG_MAX];
struct iovec iov_in[PCKT_FRAG_MAX];
int i, nev, type;
int8_t channel;
memset(&msg, 0, sizeof(struct mmsghdr));
/* preparing data buffer */
for (i = 0; i < PCKT_FRAG_MAX; i++) {
iov_in[i].iov_base = (void *)knet_h->recv_from_sock_buf[i]->khp_data_userdata;
iov_in[i].iov_len = KNET_MAX_PACKET_SIZE;
memset(&msg[i].msg_hdr, 0, sizeof(struct msghdr));
msg[i].msg_hdr.msg_name = &address[i];
msg[i].msg_hdr.msg_namelen = sizeof(struct sockaddr_storage);
msg[i].msg_hdr.msg_iov = &iov_in[i];
msg[i].msg_hdr.msg_iovlen = 1;
knet_h->recv_from_sock_buf[i]->kh_version = KNET_HEADER_VERSION;
knet_h->recv_from_sock_buf[i]->khp_data_frag_seq = 0;
- knet_h->recv_from_sock_buf[i]->kh_node = htons(knet_h->host_id);
+ knet_h->recv_from_sock_buf[i]->kh_node = knet_h->host_id;
knet_h->send_to_links_buf[i]->kh_version = KNET_HEADER_VERSION;
knet_h->send_to_links_buf[i]->khp_data_frag_seq = i + 1;
- knet_h->send_to_links_buf[i]->kh_node = htons(knet_h->host_id);
+ knet_h->send_to_links_buf[i]->kh_node = knet_h->host_id;
}
while (!shutdown_in_progress(knet_h)) {
nev = epoll_wait(knet_h->send_to_links_epollfd, events, KNET_EPOLL_MAX_EVENTS + 1, -1);
if (pthread_rwlock_rdlock(&knet_h->global_rwlock) != 0) {
log_debug(knet_h, KNET_SUB_TX, "Unable to get read lock");
continue;
}
for (i = 0; i < nev; i++) {
if (events[i].data.fd == knet_h->hostsockfd[0]) {
type = KNET_HEADER_TYPE_HOST_INFO;
channel = -1;
} else {
type = KNET_HEADER_TYPE_DATA;
for (channel = 0; channel < KNET_DATAFD_MAX; channel++) {
if ((knet_h->sockfd[channel].in_use) &&
(knet_h->sockfd[channel].sockfd[knet_h->sockfd[channel].is_created] == events[i].data.fd)) {
break;
}
}
}
if (pthread_mutex_lock(&knet_h->tx_mutex) != 0) {
log_debug(knet_h, KNET_SUB_TX, "Unable to get mutex lock");
continue;
}
_handle_send_to_links(knet_h, events[i].data.fd, channel, msg, type);
pthread_mutex_unlock(&knet_h->tx_mutex);
}
pthread_rwlock_unlock(&knet_h->global_rwlock);
}
return NULL;
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 10, 2:47 AM (1 d, 15 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1991324
Default Alt Text
(337 KB)

Event Timeline