Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/kronosnetd/Makefile.am b/kronosnetd/Makefile.am
index a298f50b..fa18c6ec 100644
--- a/kronosnetd/Makefile.am
+++ b/kronosnetd/Makefile.am
@@ -1,74 +1,76 @@
#
# Copyright (C) 2010-2012 Red Hat, Inc. All rights reserved.
#
# Author: Fabio M. Di Nitto <fabbione@kronosnet.org>
#
# This software licensed under GPL-2.0+, LGPL-2.0+
#
MAINTAINERCLEANFILES = Makefile.in kronostnetd.logrotate
EXTRA_DIST = kronosnetd.logrotate.in vty_test.c
noinst_HEADERS = \
cfg.h \
+ etherfilter.h \
logging.h \
netutils.h \
vty.h \
vty_auth.h \
vty_cli.h \
vty_cli_cmds.h \
vty_utils.h
sbin_PROGRAMS = kronosnetd \
knet-keygen
kronosnetd_SOURCES = \
cfg.c \
+ etherfilter.c \
main.c \
logging.c \
netutils.c \
vty.c \
vty_auth.c \
vty_cli.c \
vty_cli_cmds.c \
vty_utils.c
kronosnetd_CPPFLAGS = \
-I$(top_srcdir)/libtap \
-I$(top_srcdir)/libknet
kronosnetd_CFLAGS = $(libqb_CFLAGS)
kronosnetd_LDADD = \
$(top_builddir)/libknet/libknet.la \
$(top_builddir)/libtap/libtap.la \
$(libqb_LIBS)
knet_keygen_SOURCES = keygen.c
knet_keygen_CPPFLAGS = -I$(top_srcdir)/libknet
dist_man_MANS = kronosnetd.8 knet-keygen.8
install-exec-local:
$(INSTALL) -d $(DESTDIR)/$(DEFAULT_CONFIG_DIR)
$(INSTALL) -d $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/down.d
$(INSTALL) -d $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/post-down.d
$(INSTALL) -d $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/pre-up.d
$(INSTALL) -d $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/up.d
$(INSTALL) -d $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/cryptokeys.d
$(INSTALL) -d -m 0755 $(DESTDIR)/$(sysconfdir)/logrotate.d
$(INSTALL) -m 644 kronosnetd.logrotate $(DESTDIR)/$(sysconfdir)/logrotate.d/kronosnetd
uninstall-local:
rmdir $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/cryptokeys.d || :;
rmdir $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/down.d || :;
rmdir $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/post-down.d || :;
rmdir $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/pre-up.d || :;
rmdir $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/up.d || :;
rmdir $(DESTDIR)/$(DEFAULT_CONFIG_DIR) || :;
rm -f $(DESTDIR)/$(sysconfdir)/logrotate.d/kronosnetd
rmdir $(DESTDIR)/$(sysconfdir)/logrotate.d || :;
diff --git a/libknet/etherfilter.c b/kronosnetd/etherfilter.c
similarity index 96%
rename from libknet/etherfilter.c
rename to kronosnetd/etherfilter.c
index 6ed78cda..abfa795c 100644
--- a/libknet/etherfilter.c
+++ b/kronosnetd/etherfilter.c
@@ -1,59 +1,60 @@
/*
* Copyright (C) 2010-2012 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 "libknet.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 (const unsigned char *outdata,
ssize_t outdata_len,
uint16_t src_node_id,
uint16_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;
}
memcpy(&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
new file mode 100644
index 00000000..4c01ff12
--- /dev/null
+++ b/kronosnetd/etherfilter.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2010-2012 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 (const unsigned char *outdata,
+ ssize_t outdata_len,
+ uint16_t src_node_id,
+ uint16_t *dst_host_ids,
+ size_t *dst_host_ids_entries);
+
+#endif
diff --git a/kronosnetd/vty_cli_cmds.c b/kronosnetd/vty_cli_cmds.c
index 1cd5ef7c..bb6670b1 100644
--- a/kronosnetd/vty_cli_cmds.c
+++ b/kronosnetd/vty_cli_cmds.c
@@ -1,2029 +1,2030 @@
/*
* Copyright (C) 2010-2012 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_DYN 18
#define CMDS_PARAM_VTY_TIMEOUT 19
/*
* CLI helper functions - menu/node stuff starts below
*/
/*
* return 0 if we find a command in vty->line and cmd/len/no are set
* return -1 if we cannot find a command. no can be trusted. cmd/len would be empty
*/
static int get_command(struct knet_vty *vty, char **cmd, int *cmdlen, int *cmdoffset, int *no)
{
int start = 0, idx;
for (idx = 0; idx < vty->line_idx; idx++) {
if (vty->line[idx] != ' ')
break;
}
if (!strncmp(&vty->line[idx], "no ", 3)) {
*no = 1;
idx = idx + 3;
for (idx = idx; idx < vty->line_idx; idx++) {
if (vty->line[idx] != ' ')
break;
}
} else {
*no = 0;
}
start = idx;
if (start == vty->line_idx)
return -1;
*cmd = &vty->line[start];
*cmdoffset = start;
for (idx = start; idx < vty->line_idx; idx++) {
if (vty->line[idx] == ' ')
break;
}
*cmdlen = idx - start;
return 0;
}
/*
* still not sure why I need to count backwards...
*/
static void get_n_word_from_end(struct knet_vty *vty, int n,
char **word, int *wlen, int *woffset)
{
int widx;
int idx, end, start;
start = end = vty->line_idx;
for (widx = 0; widx < n; widx++) {
for (idx = start - 1; idx > 0; idx--) {
if (vty->line[idx] != ' ')
break;
}
end = idx;
for (idx = end; idx > 0; idx--) {
if (vty->line[idx-1] == ' ')
break;
}
start = idx;
}
*wlen = (end - start) + 1;
*word = &vty->line[start];
*woffset = start;
}
static int expected_params(const vty_param_t *params)
{
int idx = 0;
while(params[idx].param != CMDS_PARAM_NOMORE)
idx++;
return idx;
}
static int count_words(struct knet_vty *vty,
int offset)
{
int idx, widx = 0;
int status = 0;
for (idx = offset; idx < vty->line_idx; idx++) {
if (vty->line[idx] == ' ') {
status = 0;
continue;
}
if ((vty->line[idx] != ' ') && (!status)) {
widx++;
status = 1;
continue;
}
}
return widx;
}
static int param_to_int(const char *param, int paramlen)
{
char buf[KNET_VTY_MAX_LINE];
memset(buf, 0, sizeof(buf));
memcpy(buf, param, paramlen);
return atoi(buf);
}
static int param_to_str(char *buf, int bufsize, const char *param, int paramlen)
{
if (bufsize < paramlen)
return -1;
memset(buf, 0, bufsize);
memcpy(buf, param, paramlen);
return paramlen;
}
static const vty_node_cmds_t *get_cmds(struct knet_vty *vty, char **cmd, int *cmdlen, int *cmdoffset)
{
int no;
const vty_node_cmds_t *cmds = knet_vty_nodes[vty->node].cmds;
get_command(vty, cmd, cmdlen, cmdoffset, &no);
if (no)
cmds = knet_vty_nodes[vty->node].no_cmds;
return cmds;
}
static int check_param(struct knet_vty *vty, const int paramtype, char *param, int paramlen)
{
int err = 0;
char buf[KNET_VTY_MAX_LINE];
int tmp;
memset(buf, 0, sizeof(buf));
switch(paramtype) {
case CMDS_PARAM_NOMORE:
break;
case CMDS_PARAM_KNET:
if (paramlen >= IFNAMSIZ) {
knet_vty_write(vty, "interface name too long%s", telnet_newline);
err = -1;
}
break;
case CMDS_PARAM_IP:
break;
case CMDS_PARAM_IP_PREFIX:
break;
case CMDS_PARAM_IP_PORT:
tmp = param_to_int(param, paramlen);
if ((tmp < 0) || (tmp > 65279)) {
knet_vty_write(vty, "port number must be a value between 0 and 65279%s", telnet_newline);
err = -1;
}
break;
case CMDS_PARAM_BOOL:
break;
case CMDS_PARAM_INT:
break;
case CMDS_PARAM_NODEID:
tmp = param_to_int(param, paramlen);
if ((tmp < 0) || (tmp > 255)) {
knet_vty_write(vty, "node id must be a value between 0 and 255%s", telnet_newline);
err = -1;
}
break;
case CMDS_PARAM_NAME:
if (paramlen >= KNET_MAX_HOST_LEN) {
knet_vty_write(vty, "name cannot exceed %d char in len%s", KNET_MAX_HOST_LEN - 1, telnet_newline);
}
break;
case CMDS_PARAM_MTU:
tmp = param_to_int(param, paramlen);
if ((tmp < 576) || (tmp > 65536)) {
knet_vty_write(vty, "mtu should be a value between 576 and 65536 (note: max value depends on the media)%s", telnet_newline);
err = -1;
}
break;
case CMDS_PARAM_CRYPTO_MODEL:
param_to_str(buf, KNET_VTY_MAX_LINE, param, paramlen);
if (!strncmp("none", buf, 4))
break;
if (!strncmp("nss", buf, 3))
break;
knet_vty_write(vty, "unknown encryption model: %s. Supported: none/nss%s", param, telnet_newline);
err = -1;
break;
case CMDS_PARAM_CRYPTO_TYPE:
param_to_str(buf, KNET_VTY_MAX_LINE, param, paramlen);
if (!strncmp("none", buf, 4))
break;
if (!strncmp("aes256", buf, 6))
break;
if (!strncmp("aes192", buf, 6))
break;
if (!strncmp("aes128", buf, 6))
break;
if (!strncmp("3des", buf, 4))
break;
knet_vty_write(vty, "unknown encryption method: %s. Supported: none/aes256/aes192/aes128/3des%s", param, telnet_newline);
err = -1;
break;
case CMDS_PARAM_HASH_TYPE:
param_to_str(buf, KNET_VTY_MAX_LINE, param, paramlen);
if (!strncmp("none", buf, 4))
break;
if (!strncmp("md5", buf, 3))
break;
if (!strncmp("sha1", buf, 4))
break;
if (!strncmp("sha256", buf, 6))
break;
if (!strncmp("sha384", buf, 6))
break;
if (!strncmp("sha512", buf, 6))
break;
knet_vty_write(vty, "unknown hash method: %s. Supported none/md5/sha1/sha256/sha384/sha512%s", param, telnet_newline);
err = -1;
break;
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_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_DYN:
tmp = param_to_int(param, paramlen);
if ((tmp < 0) || (tmp > 1)) {
knet_vty_write(vty, "link dynamic should be either 0 or 1. Default: 0%s", telnet_newline);
}
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_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_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_LINK_DYN:
knet_vty_write(vty, "DYNAMIC - specify if this link will traverse NAT or Dynamic IP connections.%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);
memcpy(vty->line + cmdoffset, cmds[matches[0]].cmd, cmdreallen);
vty->line[cmdreallen + cmdoffset] = ' ';
vty->line_idx = cmdreallen + cmdoffset + 1;
vty->cursor_pos = cmdreallen + cmdoffset + 1;
}
if (found > 0) { /* add completion to string base root */
int count = 0;
idx = 0;
while (matches[idx] >= 0) {
knet_vty_write(vty, "%s\t\t", cmds[matches[idx]].cmd);
idx++;
count++;
if (count == 4) {
knet_vty_write(vty, "%s",telnet_newline);
count = 0;
}
}
knet_vty_write(vty, "%s",telnet_newline);
}
break;
default: /* this should never really happen */
log_info("Unknown match mode");
break;
}
return found;
}
/* forward declarations */
/* common to almost all nodes */
static int knet_cmd_logout(struct knet_vty *vty);
static int knet_cmd_who(struct knet_vty *vty);
static int knet_cmd_exit_node(struct knet_vty *vty);
static int knet_cmd_help(struct knet_vty *vty);
/* root node */
static int knet_cmd_config(struct knet_vty *vty);
/* config node */
static int knet_cmd_interface(struct knet_vty *vty);
static int knet_cmd_no_interface(struct knet_vty *vty);
static int knet_cmd_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);
/* 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_timer(struct knet_vty *vty);
static int knet_cmd_link_dyn(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 },
{ "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 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", mtu_params, knet_cmd_mtu },
{ "no", "revert command", NULL, NULL },
{ "peer", "add peer endpoint", peer_params, knet_cmd_peer },
{ "show", "show running config", NULL, knet_cmd_show_conf },
{ "start", "start forwarding engine", NULL, knet_cmd_start },
{ "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_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 link_dyn_params[] = {
{ CMDS_PARAM_LINK_DYN },
{ CMDS_PARAM_NOMORE },
};
vty_node_cmds_t link_cmds[] = {
{ "dynamic", "set link NAT/dynamic ip traversal code", link_dyn_params, knet_cmd_link_dyn },
{ "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 },
{ "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_dyn(struct knet_vty *vty)
{
struct knet_link *klink = (struct knet_link *)vty->link;
int paramlen = 0, paramoffset = 0, dyn;
char *param = NULL;
if (klink->dynamic == KNET_LINK_DYN_DST)
return 0;
get_param(vty, 1, &param, &paramlen, &paramoffset);
dyn = param_to_int(param, paramlen);
if (dyn) {
klink->dynamic = KNET_LINK_DYN_SRC;
} else {
klink->dynamic = KNET_LINK_STATIC;
}
return 0;
}
static int knet_cmd_link_timer(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
struct knet_host *host = (struct knet_host *)vty->host;
struct knet_link *klink = (struct knet_link *)vty->link;
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_timeout(knet_iface->cfg_ring.knet_h, host->node_id, klink, 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;
struct knet_host *host = (struct knet_host *)vty->host;
struct knet_link *klink = (struct knet_link *)vty->link;
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_priority(knet_iface->cfg_ring.knet_h, host->node_id, klink, 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_host *host = (struct knet_host *)vty->host;
struct knet_link *klink = NULL;
int paramlen = 0, paramoffset = 0;
char *param = NULL;
int link_id;
get_param(vty, 1, &param, &paramlen, &paramoffset);
link_id = param_to_int(param, paramlen);
klink = &host->link[link_id];
if (klink->configured) {
if (knet_link_enable(knet_iface->cfg_ring.knet_h, host->node_id, klink, 0)) {
knet_vty_write(vty, "Error: unable to update switching cache%s", telnet_newline);
return -1;
}
}
return 0;
}
static int knet_cmd_link(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
struct knet_host *host = (struct knet_host *)vty->host;
struct knet_link *klink = NULL;
int paramlen = 0, paramoffset = 0, err = 0;
char *param = NULL;
int link_id;
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];
get_param(vty, 1, &param, &paramlen, &paramoffset);
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 + host->node_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);
klink = &host->link[link_id];
if (!klink->configured) {
memset(klink, 0, sizeof(struct knet_link));
klink->link_id = link_id;
memcpy(klink->src_ipaddr, src_ipaddr, strlen(src_ipaddr));
memcpy(klink->src_port, src_port, strlen(src_port));
memcpy(klink->dst_ipaddr, dst_ipaddr, strlen(dst_ipaddr));
memcpy(klink->dst_port, dst_port, strlen(dst_port));
if (strtoaddr(klink->src_ipaddr, klink->src_port, (struct sockaddr *)&klink->src_addr, sizeof(klink->src_addr)) != 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)) {
klink->dynamic = KNET_LINK_DYN_DST;
} else {
if (strtoaddr(klink->dst_ipaddr, klink->dst_port, (struct sockaddr *)&klink->dst_addr, sizeof(klink->dst_addr)) != 0) {
knet_vty_write(vty, "Error: unable to convert destination ip addr to sockaddr!%s", telnet_newline);
err = -1;
goto out_clean;
}
}
knet_link_timeout(knet_iface->cfg_ring.knet_h, host->node_id, klink, 1000, 5000, 2048);
knet_link_enable(knet_iface->cfg_ring.knet_h, host->node_id, klink, 1);
}
vty->link = (void *)klink;
vty->node = NODE_LINK;
out_clean:
return err;
}
static int knet_cmd_switch_policy(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
struct knet_host *host = (struct knet_host *)vty->host;
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, host->node_id, policy);
if (err)
knet_vty_write(vty, "Error: unable to set switching policy to %s%s", policystr, telnet_newline);
return err;
}
static int knet_find_host(struct knet_vty *vty, struct knet_host **host,
const char *nodename, const uint16_t requested_node_id)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
struct knet_host *head = NULL;
int err = 0;
*host = NULL;
if (knet_host_acquire(knet_iface->cfg_ring.knet_h, &head)) {
knet_vty_write(vty, "Error: unable to acquire lock on peer list!%s", telnet_newline);
return -1;
}
while (head != NULL) {
if (!strcmp(head->name, nodename)) {
if (head->node_id == requested_node_id) {
*host = head;
err = 1;
goto out_clean;
} else {
knet_vty_write(vty, "Error: requested peer exists with another nodeid%s", telnet_newline);
err = -1;
goto out_clean;
}
} else {
if (head->node_id == requested_node_id) {
knet_vty_write(vty, "Error: requested peer nodeid already exists%s", telnet_newline);
err = -1;
goto out_clean;
}
}
head = head->next;
}
out_clean:
while (knet_host_release(knet_iface->cfg_ring.knet_h, &head) != 0) {
knet_vty_write(vty, "Error: unable to release lock on peer list!%s", telnet_newline);
sleep(1);
}
return err;
}
static int knet_cmd_no_peer(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
int paramlen = 0, paramoffset = 0, requested_node_id = 0, err = 0;
char *param = NULL;
struct knet_host *host = NULL;
char nodename[KNET_MAX_HOST_LEN];
get_param(vty, 1, &param, &paramlen, &paramoffset);
param_to_str(nodename, sizeof(nodename), param, paramlen);
get_param(vty, 2, &param, &paramlen, &paramoffset);
requested_node_id = param_to_int(param, paramlen);
if (requested_node_id == knet_iface->cfg_eth.node_id) {
knet_vty_write(vty, "Error: remote peer id cannot be the same as local id%s", telnet_newline);
return -1;
}
err = knet_find_host(vty, &host, nodename, requested_node_id);
if (err < 0)
goto out_clean;
if (err == 0) {
knet_vty_write(vty, "Error: peer not found in list%s", telnet_newline);
goto out_clean;
}
if (knet_host_remove(knet_iface->cfg_ring.knet_h, requested_node_id) < 0) {
knet_vty_write(vty, "Error: unable to remove peer from current config%s", telnet_newline);
err = -1;
goto out_clean;
}
out_clean:
return err;
}
static int knet_cmd_peer(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
int paramlen = 0, paramoffset = 0, requested_node_id = 0, err = 0;
char *param = NULL;
struct knet_host *host, *temp = NULL;
char nodename[KNET_MAX_HOST_LEN];
get_param(vty, 1, &param, &paramlen, &paramoffset);
param_to_str(nodename, sizeof(nodename), param, paramlen);
get_param(vty, 2, &param, &paramlen, &paramoffset);
requested_node_id = param_to_int(param, paramlen);
if (requested_node_id == knet_iface->cfg_eth.node_id) {
knet_vty_write(vty, "Error: remote peer id cannot be the same as local id%s", telnet_newline);
return -1;
}
err = knet_find_host(vty, &host, nodename, requested_node_id);
if (err < 0)
goto out_clean;
if (err == 0) {
if (knet_host_add(knet_iface->cfg_ring.knet_h, requested_node_id) < 0) {
knet_vty_write(vty, "Error: unable to allocate memory for host struct!%s", telnet_newline);
err = -1;
goto out_clean;
}
knet_host_get(knet_iface->cfg_ring.knet_h, requested_node_id, &temp);
host = temp;
knet_host_release(knet_iface->cfg_ring.knet_h, &temp);
memcpy(host->name, nodename, strlen(nodename));
knet_host_set_policy(knet_iface->cfg_ring.knet_h, requested_node_id, KNET_LINK_POLICY_PASSIVE);
}
vty->host = (void *)host;
vty->node = NODE_PEER;
out_clean:
if (err < 0) {
if (host)
knet_host_remove(knet_iface->cfg_ring.knet_h, host->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 int knet_cmd_no_mtu(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
if (tap_reset_mtu(knet_iface->cfg_eth.tap) < 0) {
knet_vty_write(vty, "Error: Unable to set default mtu on device %s%s",
tap_get_name(knet_iface->cfg_eth.tap), telnet_newline);
return -1;
}
return 0;
}
static int knet_cmd_mtu(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
int paramlen = 0, paramoffset = 0, expected_mtu = 0;
char *param = NULL;
get_param(vty, 1, &param, &paramlen, &paramoffset);
expected_mtu = param_to_int(param, paramlen);
if (tap_set_mtu(knet_iface->cfg_eth.tap, expected_mtu) < 0) {
knet_vty_write(vty, "Error: Unable to set requested mtu %d on device %s%s",
expected_mtu, tap_get_name(knet_iface->cfg_eth.tap), telnet_newline);
return -1;
}
return 0;
}
static int knet_cmd_stop(struct knet_vty *vty)
{
struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface;
char *error_down = NULL, *error_postdown = NULL;
int err = 0;
err = tap_set_down(knet_iface->cfg_eth.tap, &error_down, &error_postdown);
if (err < 0) {
knet_vty_write(vty, "Error: Unable to set interface %s down!%s", tap_get_name(knet_iface->cfg_eth.tap), telnet_newline);
} else {
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) {
memcpy(&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;
struct knet_host *host;
char *ip_list = NULL;
int ip_list_entries = 0, i, offset = 0;
char *error_string = NULL;
get_param(vty, 1, &param, &paramlen, &paramoffset);
param_to_str(device, IFNAMSIZ, param, paramlen);
knet_iface = knet_get_iface(device, 0);
if (!knet_iface) {
knet_vty_write(vty, "Error: Unable to find requested interface%s", telnet_newline);
return -1;
}
vty->iface = (void *)knet_iface;
tap_get_ips(knet_iface->cfg_eth.tap, &ip_list, &ip_list_entries);
if ((ip_list) && (ip_list_entries > 0)) {
for (i = 1; i <= ip_list_entries; i++) {
tap_del_ip(knet_iface->cfg_eth.tap,
ip_list + offset,
ip_list + offset + strlen(ip_list + offset) + 1, &error_string);
if (error_string) {
free(error_string);
error_string = NULL;
}
offset = offset + strlen(ip_list) + 1;
offset = offset + strlen(ip_list + offset) + 1;
}
free(ip_list);
ip_list = NULL;
ip_list_entries = 0;
}
while (1) {
struct knet_host *head;
while (knet_host_acquire(knet_iface->cfg_ring.knet_h, &head) != 0) {
log_error("CLI ERROR: unable to acquire peer lock.. will retry in 1 sec");
sleep (1);
}
host = head;
while (knet_host_release(knet_iface->cfg_ring.knet_h, &head) != 0) {
log_error("CLI ERROR: unable to release peer lock.. will retry in 1 sec");
sleep (1);
}
if (host == NULL)
break;
for (i = 0; i < KNET_MAX_LINK; i++)
knet_link_enable(knet_iface->cfg_ring.knet_h, host->node_id, &host->link[i], 0);
while (knet_host_remove(knet_iface->cfg_ring.knet_h, host->node_id) != 0) {
log_error("CLI ERROR: unable to release peer.. will retry in 1 sec");
sleep (1);
}
}
knet_cmd_stop(vty);
if (knet_iface->cfg_ring.knet_h) {
knet_handle_free(knet_iface->cfg_ring.knet_h);
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 int knet_cmd_interface(struct knet_vty *vty)
{
int err = 0, paramlen = 0, paramoffset = 0, found = 0, requested_id;
uint16_t baseport;
uint8_t *bport = (uint8_t *)&baseport;
char *param = NULL;
char device[IFNAMSIZ];
char mac[18];
struct knet_cfg *knet_iface = NULL;
struct knet_handle_cfg knet_handle_cfg;
get_param(vty, 1, &param, &paramlen, &paramoffset);
param_to_str(device, IFNAMSIZ, param, paramlen);
get_param(vty, 2, &param, &paramlen, &paramoffset);
requested_id = param_to_int(param, paramlen);
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;
memset(&knet_handle_cfg, 0, sizeof(struct knet_handle_cfg));
knet_handle_cfg.to_net_fd = tap_get_fd(knet_iface->cfg_eth.tap);
knet_handle_cfg.node_id = requested_id;
knet_handle_cfg.log_fd = vty->logfd;
knet_handle_cfg.default_log_level = vty->loglevel;
knet_handle_cfg.dst_host_filter = KNET_DST_FILTER_ENABLE;
knet_handle_cfg.dst_host_filter_fn = ether_host_filter_fn;
knet_iface->cfg_ring.knet_h = knet_handle_new(&knet_handle_cfg);
if (!knet_iface->cfg_ring.knet_h) {
knet_vty_write(vty, "Error: Unable to create ring handle for device %s%s",
device, telnet_newline);
err = -1;
goto out_clean;
}
knet_found:
if (found) {
if (requested_id == knet_iface->cfg_eth.node_id)
goto out_found;
knet_vty_write(vty, "Error: no interface %s with nodeid %d found%s",
device, requested_id, telnet_newline);
goto out_clean;
} else {
knet_iface->cfg_eth.node_id = requested_id;
}
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;
struct knet_cfg *knet_iface = knet_cfg_head.knet_cfg;
struct knet_host *host = NULL;
const char *nl = telnet_newline;
struct timespec now;
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);
while (knet_host_acquire(knet_iface->cfg_ring.knet_h, &host)) {
log_error("CLI ERROR: waiting for peer lock");
sleep(1);
}
while (host != NULL) {
knet_vty_write(vty, " peer %s ", host->name);
switch (host->link_handler_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;
}
for (i = 0; i < KNET_MAX_LINK; i++) {
if (host->link[i].configured == 1) {
knet_vty_write(vty, " link %s %s (connected: %d)%s", host->link[i].src_ipaddr, host->link[i].dst_ipaddr, host->link[i].connected, nl);
if (host->link[i].connected) {
knet_vty_write(vty, " average latency: %llu us%s", host->link[i].latency, nl);
if ((host->link[i].dynamic == KNET_LINK_DYN_DST) &&
(host->link[i].dynconnected)) {
char *src_ip[2];
src_ip[0] = NULL;
if (addrtostr((struct sockaddr *)&host->link[i].dst_addr,
sizeof(struct sockaddr_storage), src_ip)) {
knet_vty_write(vty, " source ip: unknown%s", nl);
} else {
knet_vty_write(vty, " source ip: %s%s", src_ip[0], nl);
addrtostr_free(src_ip);
}
}
} else {
knet_vty_write(vty, " last heard: ");
if (host->link[i].pong_last.tv_sec) {
knet_vty_write(vty, "%lu s ago%s",
(long unsigned int)now.tv_sec - host->link[i].pong_last.tv_sec, nl);
} else {
knet_vty_write(vty, "never%s", nl);
}
}
}
}
host = host->next;
}
while (knet_host_release(knet_iface->cfg_ring.knet_h, &host) != 0) {
log_error("CLI ERROR: unable to release peer lock.. will retry in 1 sec");
sleep(1);
}
knet_iface = knet_iface->next;
}
return 0;
}
static int knet_cmd_print_conf(struct knet_vty *vty)
{
int i;
struct knet_cfg *knet_iface = knet_cfg_head.knet_cfg;
struct knet_host *host = NULL;
const char *nl = telnet_newline;
char *ip_list = NULL;
int ip_list_entries = 0;
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);
knet_vty_write(vty, " mtu %d%s", tap_get_mtu(knet_iface->cfg_eth.tap), nl);
tap_get_ips(knet_iface->cfg_eth.tap, &ip_list, &ip_list_entries);
if ((ip_list) && (ip_list_entries > 0)) {
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);
while (knet_host_acquire(knet_iface->cfg_ring.knet_h, &host)) {
log_error("CLI ERROR: waiting for peer lock");
sleep(1);
}
while (host != NULL) {
knet_vty_write(vty, " peer %s %u%s", host->name, host->node_id, nl);
switch (host->link_handler_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;
}
for (i = 0; i < KNET_MAX_LINK; i++) {
if (host->link[i].configured == 1) {
knet_vty_write(vty, " link %d %s %s%s", i, host->link[i].src_ipaddr , host->link[i].dst_ipaddr, nl);
if (host->link[i].dynamic != KNET_LINK_DYN_DST)
knet_vty_write(vty, " dynamic %u%s", host->link[i].dynamic, nl);
knet_vty_write(vty, " timers %llu %llu%s", host->link[i].ping_interval / 1000, host->link[i].pong_timeout / 1000, nl);
knet_vty_write(vty, " priority %u%s", host->link[i].priority, nl);
/* print link properties */
knet_vty_write(vty, " exit%s", nl);
}
}
knet_vty_write(vty, " exit%s", nl);
host = host->next;
}
while (knet_host_release(knet_iface->cfg_ring.knet_h, &host) != 0) {
log_error("CLI ERROR: unable to release peer lock.. will retry in 1 sec");
sleep(1);
}
if (knet_iface->active)
knet_vty_write(vty, " start%s", nl);
knet_vty_write(vty, " exit%s", nl);
knet_iface = knet_iface->next;
}
knet_vty_write(vty, " exit%sexit%s", nl, nl);
return 0;
}
static int knet_cmd_show_conf(struct knet_vty *vty)
{
return knet_cmd_print_conf(vty);
}
static int knet_cmd_write_conf(struct knet_vty *vty)
{
int fd = 1, vty_sock, err = 0, backup = 1;
char tempfile[PATH_MAX];
memset(tempfile, 0, sizeof(tempfile));
snprintf(tempfile, sizeof(tempfile), "%s.sav", knet_cfg_head.conffile);
err = rename(knet_cfg_head.conffile, tempfile);
if ((err < 0) && (errno != ENOENT)) {
knet_vty_write(vty, "Unable to create backup config file %s %s", tempfile, telnet_newline);
return -1;
}
if ((err < 0) && (errno == ENOENT))
backup = 0;
fd = open(knet_cfg_head.conffile,
O_RDWR | O_CREAT | O_EXCL | O_TRUNC,
S_IRUSR | S_IWUSR);
if (fd < 0) {
knet_vty_write(vty, "Error unable to open file%s", telnet_newline);
return -1;
}
vty_sock = vty->vty_sock;
vty->vty_sock = fd;
vty->filemode = 1;
knet_cmd_print_conf(vty);
vty->vty_sock = vty_sock;
vty->filemode = 0;
close(fd);
knet_vty_write(vty, "Configuration saved to %s%s", knet_cfg_head.conffile, telnet_newline);
if (backup)
knet_vty_write(vty, "Old configuration file has been stored in %s%s",
tempfile, telnet_newline);
return err;
}
static int knet_cmd_config(struct knet_vty *vty)
{
int err = 0;
if (!vty->user_can_enable) {
knet_vty_write(vty, "Error: user %s does not have enough privileges to perform config operations%s", vty->username, telnet_newline);
return -1;
}
pthread_mutex_lock(&knet_vty_mutex);
if (knet_vty_config >= 0) {
knet_vty_write(vty, "Error: configuration is currently locked by user %s on vty(%d). Try again later%s", vty->username, knet_vty_config, telnet_newline);
err = -1;
goto out_clean;
}
vty->node = NODE_CONFIG;
knet_vty_config = vty->conn_num;
out_clean:
pthread_mutex_unlock(&knet_vty_mutex);
return err;
}
static int knet_cmd_logout(struct knet_vty *vty)
{
vty->got_epipe = 1;
return 0;
}
static int knet_cmd_who(struct knet_vty *vty)
{
int conn_index;
pthread_mutex_lock(&knet_vty_mutex);
for(conn_index = 0; conn_index < KNET_VTY_TOTAL_MAX_CONN; conn_index++) {
if (knet_vtys[conn_index].active) {
knet_vty_write(vty, "User %s connected on vty(%d) from %s%s",
knet_vtys[conn_index].username,
knet_vtys[conn_index].conn_num,
knet_vtys[conn_index].ip,
telnet_newline);
}
}
pthread_mutex_unlock(&knet_vty_mutex);
return 0;
}
static int knet_cmd_help(struct knet_vty *vty)
{
knet_vty_write(vty, PACKAGE "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/Makefile.am b/libknet/Makefile.am
index e33499d7..91895f67 100644
--- a/libknet/Makefile.am
+++ b/libknet/Makefile.am
@@ -1,41 +1,40 @@
#
# Copyright (C) 2010-2012 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+
#
MAINTAINERCLEANFILES = Makefile.in
LIBS = -lpthread \
-version-info $(libversion)
libversion = 0:0:0
sources = \
common.c \
handle.c \
host.c \
listener.c \
crypto.c \
- nsscrypto.c \
- etherfilter.c
+ nsscrypto.c
include_HEADERS = libknet.h
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libknet.pc
noinst_HEADERS = libknet-private.h \
crypto.h \
nsscrypto.h
lib_LTLIBRARIES = libknet.la
libknet_la_SOURCES = $(sources)
libknet_la_CFLAGS = $(nss_CFLAGS)
libknet_la_LIBADD = $(nss_LIBS) -lrt
diff --git a/libknet/libknet.h b/libknet/libknet.h
index df03f91e..fe00b23f 100644
--- a/libknet/libknet.h
+++ b/libknet/libknet.h
@@ -1,261 +1,255 @@
/*
* Copyright (C) 2010-2012 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>
typedef struct knet_handle *knet_handle_t;
#define KNET_RING_DEFPORT 50000
#define KNET_RING_RCVBUFF 8388608
#define KNET_MAX_HOST 65536
#define KNET_MAX_LINK 8
#define KNET_MAX_HOST_LEN 64
#define KNET_MAX_PORT_LEN 6
#define KNET_CBUFFER_SIZE 4096
/*
typedef uint64_t seq_num_t;
#define SEQ_MAX UINT64_MAX
*/
typedef uint16_t seq_num_t;
#define SEQ_MAX UINT16_MAX
#define KNET_LINK_STATIC 0 /* link com is static ip (default) */
#define KNET_LINK_DYN_SRC 1 /* link com has src dynamic ip */
#define KNET_LINK_DYN_DST 2 /* link com is dst from dyn src */
struct knet_link {
uint8_t link_id;
int listener_sock;
char src_ipaddr[KNET_MAX_HOST_LEN];
char src_port[KNET_MAX_PORT_LEN];
struct sockaddr_storage src_addr;
char dst_ipaddr[KNET_MAX_HOST_LEN];
char dst_port[KNET_MAX_PORT_LEN];
struct sockaddr_storage dst_addr;
unsigned int configured:1; /* link is configured and ready to be used */
unsigned int connected:1; /* link is enabled for data (local view) */
unsigned int remoteconnected:1; /* link is enabled for data (peer view) */
unsigned int donnotremoteupdate:1; /* define source of the update */
unsigned int dynamic; /* see KNET_LINK_DYN_ define above */
unsigned int dynconnected:1; /* link has been activated by remote dynip */
uint8_t priority; /* higher priority == preferred for A/P */
unsigned int host_info_up_sent:1; /* 0 if we need to notify remote that link is up */
unsigned long long latency; /* average latency computed by fix/exp */
unsigned int latency_exp;
unsigned int latency_fix;
unsigned long long ping_interval;
unsigned long long pong_timeout;
struct timespec ping_last;
struct timespec pong_last;
};
#define KNET_LINK_POLICY_PASSIVE 0
#define KNET_LINK_POLICY_ACTIVE 1
#define KNET_LINK_POLICY_RR 2
struct knet_host {
uint16_t node_id;
char name[KNET_MAX_HOST_LEN];
char bcast_circular_buffer[KNET_CBUFFER_SIZE];
seq_num_t bcast_seq_num_rx;
char ucast_circular_buffer[KNET_CBUFFER_SIZE];
seq_num_t ucast_seq_num_tx;
seq_num_t ucast_seq_num_rx;
struct knet_link link[KNET_MAX_LINK];
uint8_t active_link_entries;
uint8_t active_links[KNET_MAX_LINK];
uint8_t link_handler_policy;
struct knet_host *next;
};
#define KNET_HOST_INFO_LINK_UP_DOWN 0
#define KNET_HOST_INFO_LINK_TABLE 1
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_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));
union knet_hinfo_dtype {
struct {
uint8_t khdt_link_id;
uint8_t khdt_link_status;
} link_up_down;
struct {
uint16_t khdt_host_entries;
uint8_t khdt_host_maps[0]; /* array of knet_hinfo_link_table[khdt_host_entries] */
} link_table __attribute__((packed));
} __attribute__((packed));
struct knet_hinfo_data { /* this is sent in kf_data */
uint8_t khd_type; /* link_up_down / link_table */
uint8_t khd_bcast; /* bcast/ucast */
uint16_t khd_dst_node_id;/* used only if in ucast mode */
union knet_hinfo_dtype khd_dype;
} __attribute__((packed));
union knet_frame_data {
struct {
seq_num_t kfd_seq_num;
uint8_t kfd_data[0];
} data __attribute__((packed));
struct {
uint8_t kfd_link;
uint8_t kfd_dyn;
uint32_t kfd_time[4];
} ping __attribute__((packed));
} __attribute__((packed));
struct knet_frame {
uint8_t kf_version;
uint8_t kf_type;
uint16_t kf_node;
union knet_frame_data kf_payload;
} __attribute__((packed));
#define kf_seq_num kf_payload.data.kfd_seq_num
#define kf_data kf_payload.data.kfd_data
#define kf_link kf_payload.ping.kfd_link
#define kf_time kf_payload.ping.kfd_time
#define kf_dyn kf_payload.ping.kfd_dyn
#define KNET_FRAME_SIZE (sizeof(struct knet_frame) - sizeof(union knet_frame_data))
#define KNET_FRAME_VERSION 0x01
#define KNET_FRAME_DATA 0x00
#define KNET_FRAME_HOST_INFO 0x01
#define KNET_FRAME_PING 0x81
#define KNET_FRAME_PONG 0x82
#define KNET_FRAME_PMSK 0x80 /* ping/pong packet mask */
#define KNET_MIN_KEY_LEN 1024
#define KNET_MAX_KEY_LEN 4096
#define KNET_DST_FILTER_DISABLE 0 /* pckt goes everywhere */
#define KNET_DST_FILTER_ENABLE 1 /* pckt goes via dst_host_filter,
see knet_ether_filter for example */
/*
* dst_host_filter_fn should return
* -1 on error, pkt is discarded
* 0 all good, send pkt to dst_host_ids and there are dst_host_ids_entries in buffer ready
* 1 send it to all hosts. contents of dst_host_ids and dst_host_ids_entries is ignored.
*/
#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_TAP_T 5 /* tap thread */
#define KNET_SUB_LINK_T 6 /* link thread */
#define KNET_SUB_SWITCH_T 7 /* switching thread */
#define KNET_SUB_HB_T 8 /* heartbeat thread */
#define KNET_SUB_FILTER 9 /* (ether)filter errors */
#define KNET_SUB_CRYPTO 10 /* crypto.c generic layer */
#define KNET_SUB_NSSCRYPTO 11 /* nsscrypto.c */
#define KNET_SUB_LAST KNET_SUB_NSSCRYPTO
#define KNET_MAX_SUBSYSTEMS KNET_SUB_LAST + 1
#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
#define KNET_MAX_LOG_MSG_SIZE 1024
struct knet_log_msg {
uint8_t subsystem; /* KNET_SUB_* */
uint8_t msglevel; /* KNET_LOG_* */
char msg[KNET_MAX_LOG_MSG_SIZE - (sizeof(uint8_t)*2)];
};
struct knet_handle_cfg {
int to_net_fd;
int log_fd;
uint8_t default_log_level;
uint16_t node_id;
uint8_t dst_host_filter;
int (*dst_host_filter_fn) (
const unsigned char *outdata,
ssize_t outdata_len,
uint16_t src_node_id,
uint16_t *dst_host_ids,
size_t *dst_host_ids_entries);
};
-int ether_host_filter_fn (const unsigned char *outdata,
- ssize_t outdata_len,
- uint16_t src_node_id,
- uint16_t *dst_host_ids,
- size_t *dst_host_ids_entries);
-
knet_handle_t knet_handle_new(const struct knet_handle_cfg *knet_handle_cfg);
void knet_handle_setfwd(knet_handle_t knet_h, int enabled);
int knet_handle_free(knet_handle_t knet_h);
struct knet_handle_crypto_cfg {
char crypto_model[16];
char crypto_cipher_type[16];
char crypto_hash_type[16];
unsigned char private_key[KNET_MAX_KEY_LEN];
unsigned int private_key_len;
};
int knet_handle_crypto(knet_handle_t knet_h, struct knet_handle_crypto_cfg *knet_handle_crypto_cfg);
int knet_host_add(knet_handle_t knet_h, uint16_t node_id);
int knet_host_acquire(knet_handle_t knet_h, struct knet_host **host);
int knet_host_get(knet_handle_t knet_h, uint16_t node_id, struct knet_host **host);
int knet_host_release(knet_handle_t knet_h, struct knet_host **host);
int knet_host_remove(knet_handle_t knet_h, uint16_t node_id);
int knet_host_set_policy(knet_handle_t knet_h, uint16_t node_id, int policy);
int knet_link_enable(knet_handle_t knet_h, uint16_t node_id, struct knet_link *lnk, int configured);
void knet_link_timeout(knet_handle_t knet_h, uint16_t node_id, struct knet_link *lnk, time_t interval, time_t timeout, int precision);
int knet_link_priority(knet_handle_t knet_h, uint16_t node_id, struct knet_link *lnk, uint8_t priority);
#define KNET_HOST_FOREACH_NEXT 0 /* next host */
#define KNET_HOST_FOREACH_FOUND 1 /* host found, exit loop */
struct knet_host_search {
int param1; /* user parameter 1 */
void *data1; /* user data pointer 1 */
void *data2; /* user data pointer 2 */
int retval; /* search return value */
};
typedef int (*knet_link_fn_t)(knet_handle_t knet_h, struct knet_host *host, struct knet_host_search *data);
int knet_host_foreach(knet_handle_t knet_h, knet_link_fn_t linkfun, struct knet_host_search *data);
/* logging */
void knet_set_log_level(knet_handle_t knet_h, uint8_t subsystem, uint8_t level);
const char *knet_get_subsystem_name(uint8_t subsystem);
const char *knet_get_loglevel_name(uint8_t level);
uint8_t knet_get_subsystem_id(const char *name);
uint8_t knet_get_loglevel_id(const char *name);
#endif

File Metadata

Mime Type
text/x-diff
Expires
Wed, Feb 26, 9:28 AM (1 d, 18 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1465236
Default Alt Text
(74 KB)

Event Timeline