diff --git a/kronosnetd/cfg.c b/kronosnetd/cfg.c index d2663926..c88d6f03 100644 --- a/kronosnetd/cfg.c +++ b/kronosnetd/cfg.c @@ -1,88 +1,88 @@ /* * Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. * * Author: Fabio M. Di Nitto * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include #include #include #include #include "cfg.h" #include "libnozzle.h" struct knet_cfg *knet_get_iface(const char *name, int create) { struct knet_cfg *knet_iface = knet_cfg_head.knet_cfg; int found = 0; while (knet_iface != NULL) { - if (!strcmp(tap_get_name(knet_iface->cfg_eth.tap), name)) { + if (!strcmp(nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle), name)) { found = 1; break; } knet_iface = knet_iface->next; } if ((!found) && (create)) { knet_iface = malloc(sizeof(struct knet_cfg)); if (!knet_iface) goto out_clean; memset(knet_iface, 0, sizeof(struct knet_cfg)); knet_iface->cfg_ring.base_port = KNET_RING_DEFPORT; strncpy(knet_iface->knet_handle_crypto_cfg.crypto_model, "none", sizeof(knet_iface->knet_handle_crypto_cfg.crypto_model) - 1); strncpy(knet_iface->knet_handle_crypto_cfg.crypto_cipher_type, "none", sizeof(knet_iface->knet_handle_crypto_cfg.crypto_cipher_type) - 1); strncpy(knet_iface->knet_handle_crypto_cfg.crypto_hash_type, "none", sizeof(knet_iface->knet_handle_crypto_cfg.crypto_hash_type) - 1); if (knet_cfg_head.knet_cfg) { struct knet_cfg *knet_iface_last = knet_cfg_head.knet_cfg; while (knet_iface_last->next != NULL) { knet_iface_last = knet_iface_last->next; } knet_iface_last->next = knet_iface; } else { knet_cfg_head.knet_cfg = knet_iface; } } out_clean: return knet_iface; } void knet_destroy_iface(struct knet_cfg *knet_iface) { struct knet_cfg *knet_iface_tmp = knet_cfg_head.knet_cfg; struct knet_cfg *knet_iface_prev = knet_cfg_head.knet_cfg; while (knet_iface_tmp != knet_iface) { knet_iface_prev = knet_iface_tmp; knet_iface_tmp = knet_iface_tmp->next; } if (knet_iface_tmp == knet_iface) { if (knet_iface_tmp == knet_iface_prev) { knet_cfg_head.knet_cfg = knet_iface_tmp->next; } else { knet_iface_prev->next = knet_iface_tmp->next; } free(knet_iface); } } diff --git a/kronosnetd/cfg.h b/kronosnetd/cfg.h index b884ffb4..e62980ff 100644 --- a/kronosnetd/cfg.h +++ b/kronosnetd/cfg.h @@ -1,55 +1,55 @@ /* * Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto * Federico Simoncelli * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNETD_CFG_H__ #define __KNETD_CFG_H__ #include #include #include "libnozzle.h" #include "libknet.h" #define KNET_RING_DEFPORT 50000 struct knet_cfg_eth { - tap_t tap; + nozzle_t nozzle; int auto_mtu; knet_node_id_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 5a16c311..7ee3c274 100644 --- a/kronosnetd/etherfilter.c +++ b/kronosnetd/etherfilter.c @@ -1,64 +1,65 @@ /* * Copyright (C) 2012-2018 Red Hat, Inc. All rights reserved. * * Author: Fabio M. Di Nitto * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include -#include +#include +#include #include #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, knet_node_id_t this_host_id, knet_node_id_t src_host_id, int8_t *channel, knet_node_id_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 16ce615a..e3c57e88 100644 --- a/kronosnetd/etherfilter.h +++ b/kronosnetd/etherfilter.h @@ -1,25 +1,26 @@ /* * Copyright (C) 2012-2018 Red Hat, Inc. All rights reserved. * * Author: Fabio M. Di Nitto * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNETD_ETHERFILTER_H__ #define __KNETD_ETHERFILTER_H__ #include +#include #include "libknet.h" int ether_host_filter_fn (void *private_data, const unsigned char *outdata, ssize_t outdata_len, uint8_t tx_rx, knet_node_id_t this_host_id, knet_node_id_t src_host_id, int8_t *channel, knet_node_id_t *dst_host_ids, size_t *dst_host_ids_entries); #endif diff --git a/kronosnetd/vty.h b/kronosnetd/vty.h index 7778f76b..c0a665c6 100644 --- a/kronosnetd/vty.h +++ b/kronosnetd/vty.h @@ -1,74 +1,74 @@ /* * Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto * Federico Simoncelli * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNETD_VTY_H__ #define __KNETD_VTY_H__ #include #include #include #include "libknet.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 ip[KNET_MAX_HOST_LEN]; /* 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 */ knet_node_id_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.c b/kronosnetd/vty_cli.c index b1a40d59..aaa9db4f 100644 --- a/kronosnetd/vty_cli.c +++ b/kronosnetd/vty_cli.c @@ -1,531 +1,533 @@ /* * Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto * Federico Simoncelli * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include #include #include #include #include "logging.h" #include "vty.h" #include "vty_cli.h" #include "vty_cli_cmds.h" #include "vty_utils.h" +static const char telnet_backward_char[] = { 0x08, 0x0 }; + /* if this code looks like quagga lib/vty.c it is because we stole it in good part */ #define CONTROL(X) ((X) - '@') #define VTY_NORMAL 0 #define VTY_PRE_ESCAPE 1 #define VTY_ESCAPE 2 #define VTY_EXT_ESCAPE 3 static void knet_vty_reset_buf(struct knet_vty *vty) { memset(vty->line, 0, sizeof(vty->line)); vty->line_idx = 0; vty->cursor_pos = 0; vty->history_pos = vty->history_idx; } static void knet_vty_add_to_buf(struct knet_vty *vty, unsigned char *buf, int pos) { char outbuf[2]; int i; if (vty->cursor_pos == vty->line_idx) { vty->line[vty->line_idx] = buf[pos]; vty->line_idx++; vty->cursor_pos++; } else { if (!vty->insert_mode) { memmove(&vty->line[vty->cursor_pos+1], &vty->line[vty->cursor_pos], vty->line_idx - vty->cursor_pos); vty->line_idx++; } vty->line[vty->cursor_pos] = buf[pos]; vty->cursor_pos++; } outbuf[0] = buf[pos]; outbuf[1] = 0; knet_vty_write(vty, "%s%s", outbuf, &vty->line[vty->cursor_pos]); for (i = 0; i < (vty->line_idx - vty->cursor_pos); i++) knet_vty_write(vty, "%s", telnet_backward_char); } static void knet_vty_forward_char(struct knet_vty *vty) { char buf[2]; if (vty->cursor_pos < vty->line_idx) { buf[0] = vty->line[vty->cursor_pos]; buf[1] = 0; knet_vty_write(vty, "%s", buf); vty->cursor_pos++; } } static void knet_vty_backward_char(struct knet_vty *vty) { if (vty->cursor_pos > 0) { knet_vty_write(vty, "%s", telnet_backward_char); vty->cursor_pos--; } } static void knet_vty_kill_line(struct knet_vty *vty) { int size, i; size = vty->line_idx - vty->cursor_pos; if (size == 0) return; for (i = 0; i < size; i++) knet_vty_write(vty, " "); for (i = 0; i < size; i++) knet_vty_write(vty, "%s", telnet_backward_char); memset(&vty->line[vty->cursor_pos], 0, size); vty->line_idx = vty->cursor_pos; } static void knet_vty_newline(struct knet_vty *vty) { knet_vty_write(vty, "%s", telnet_newline); knet_vty_reset_buf(vty); knet_vty_prompt(vty); } static void knet_vty_delete_char(struct knet_vty *vty) { int size, i; if (vty->line_idx == 0) { knet_vty_exit_node(vty); if (!vty->got_epipe) { knet_vty_newline(vty); } return; } if (vty->line_idx == vty->cursor_pos) return; size = vty->line_idx - vty->cursor_pos; vty->line_idx--; memmove(&vty->line[vty->cursor_pos], &vty->line[vty->cursor_pos+1], size - 1); vty->line[vty->line_idx] = '\0'; knet_vty_write(vty, "%s ", &vty->line[vty->cursor_pos]); for (i = 0; i < size; i++) knet_vty_write(vty, "%s", telnet_backward_char); } static void knet_vty_delete_backward_char(struct knet_vty *vty) { if (vty->cursor_pos == 0) return; knet_vty_backward_char(vty); knet_vty_delete_char(vty); } static void knet_vty_beginning_of_line(struct knet_vty *vty) { while (vty->cursor_pos != 0) knet_vty_backward_char(vty); } static void knet_vty_end_of_line(struct knet_vty *vty) { while (vty->cursor_pos != vty->line_idx) knet_vty_forward_char(vty); } static void knet_vty_kill_line_from_beginning(struct knet_vty *vty) { knet_vty_beginning_of_line(vty); knet_vty_kill_line(vty); } static void knet_vty_backward_word(struct knet_vty *vty) { while(vty->cursor_pos > 0 && vty->line[vty->cursor_pos - 1] == ' ') knet_vty_backward_char(vty); while(vty->cursor_pos > 0 && vty->line[vty->cursor_pos - 1] != ' ') knet_vty_backward_char(vty); } static void knet_vty_forward_word(struct knet_vty *vty) { while(vty->cursor_pos != vty->line_idx && vty->line[vty->cursor_pos] == ' ') knet_vty_forward_char(vty); while(vty->cursor_pos != vty->line_idx && vty->line[vty->cursor_pos] != ' ') knet_vty_forward_char(vty); } static void knet_vty_backward_kill_word(struct knet_vty *vty) { while(vty->cursor_pos > 0 && vty->line[vty->cursor_pos - 1] == ' ') knet_vty_delete_backward_char(vty); while(vty->cursor_pos > 0 && vty->line[vty->cursor_pos - 1] != ' ') knet_vty_delete_backward_char(vty); } static void knet_vty_forward_kill_word(struct knet_vty *vty) { while(vty->cursor_pos != vty->line_idx && vty->line[vty->cursor_pos] == ' ') knet_vty_delete_char(vty); while(vty->cursor_pos != vty->line_idx && vty->line[vty->cursor_pos] != ' ') knet_vty_delete_backward_char(vty); } static void knet_vty_transpose_chars(struct knet_vty *vty) { unsigned char swap[2]; if (vty->line_idx < 2 || vty->cursor_pos < 2) return; swap[0] = vty->line[vty->cursor_pos - 1]; swap[1] = vty->line[vty->cursor_pos - 2]; knet_vty_delete_backward_char(vty); knet_vty_delete_backward_char(vty); knet_vty_add_to_buf(vty, swap, 0); knet_vty_add_to_buf(vty, swap, 1); } static void knet_vty_history_add(struct knet_vty *vty) { int idx; if (knet_vty_is_line_empty(vty)) return; idx = vty->history_idx % KNET_VTY_MAX_HIST; if (vty->history[idx]) { free(vty->history[idx]); vty->history[idx] = NULL; } vty->history[idx] = strdup(vty->line); if (vty->history[idx] == NULL) { log_error("Not enough memory to add history lines!"); knet_vty_write(vty, "Not enough memory to add history lines!"); } vty->history_idx++; if (vty->history_idx == KNET_VTY_MAX_HIST) vty->history_idx = 0; vty->history_pos = vty->history_idx; } static void knet_vty_history_print(struct knet_vty *vty) { int len; knet_vty_kill_line_from_beginning(vty); len = strlen(vty->history[vty->history_pos]); memmove(vty->line, vty->history[vty->history_pos], len); vty->cursor_pos = vty->line_idx = len; knet_vty_write(vty, "%s", vty->line); } static void knet_vty_history_prev(struct knet_vty *vty) { int idx; idx = vty->history_pos; if (idx == 0) { idx = KNET_VTY_MAX_HIST - 1; } else { idx--; } if (vty->history[idx] == NULL) return; vty->history_pos = idx; knet_vty_history_print(vty); } static void knet_vty_history_next(struct knet_vty *vty) { int idx; if (vty->history_pos == vty->history_idx) return; idx = vty->history_pos; if (idx == (KNET_VTY_MAX_HIST - 1)) { idx = 0; } else { idx++; } if (vty->history[idx] == NULL) { knet_vty_kill_line_from_beginning(vty); vty->history_pos = vty->history_idx; return; } vty->history_pos = idx; knet_vty_history_print(vty); } static int knet_vty_process_buf(struct knet_vty *vty, unsigned char *buf, int buflen) { int i; if (vty->line_idx >= KNET_VTY_MAX_LINE) return -1; for (i = 0; i < buflen; i++) { if (vty->escape == VTY_EXT_ESCAPE) { if (buf[i] != '~') goto vty_ext_escape_out; switch (vty->escape_code) { case ('1'): knet_vty_beginning_of_line(vty); break; case ('2'): if (!vty->insert_mode) { vty->insert_mode = 1; } else { vty->insert_mode = 0; } break; case ('3'): knet_vty_delete_char(vty); break; case ('4'): knet_vty_end_of_line(vty); break; case ('5'): knet_vty_history_prev(vty); break; case ('6'): knet_vty_history_next(vty); break; } vty_ext_escape_out: vty->escape = VTY_NORMAL; continue; } if (vty->escape == VTY_ESCAPE) { switch (buf[i]) { case ('A'): knet_vty_history_prev(vty); break; case ('B'): knet_vty_history_next(vty); break; case ('C'): knet_vty_forward_char(vty); break; case ('D'): knet_vty_backward_char(vty); break; case ('H'): knet_vty_beginning_of_line(vty); break; case ('F'): knet_vty_end_of_line(vty); break; case ('1'): case ('2'): case ('3'): case ('4'): case ('5'): case ('6'): vty->escape = VTY_EXT_ESCAPE; vty->escape_code = buf[i]; break; default: break; } if (vty->escape == VTY_ESCAPE) vty->escape = VTY_NORMAL; continue; } if (vty->escape == VTY_PRE_ESCAPE) { switch (buf[i]) { case 'O': case '[': vty->escape = VTY_ESCAPE; break; case 'b': vty->escape = VTY_NORMAL; knet_vty_backward_word(vty); break; case 'f': vty->escape = VTY_NORMAL; knet_vty_forward_word(vty); break; case 'd': vty->escape = VTY_NORMAL; knet_vty_forward_kill_word(vty); break; case CONTROL('H'): case 0x7f: vty->escape = VTY_NORMAL; knet_vty_backward_kill_word(vty); break; default: break; } continue; } switch (buf[i]) { case CONTROL('A'): knet_vty_beginning_of_line(vty); break; case CONTROL('B'): knet_vty_backward_char(vty); break; case CONTROL('C'): knet_vty_newline(vty); break; case CONTROL('D'): knet_vty_delete_char(vty); break; case CONTROL('E'): knet_vty_end_of_line(vty); break; case CONTROL('F'): knet_vty_forward_char(vty); break; case CONTROL('H'): case 0x7f: knet_vty_delete_backward_char(vty); break; case CONTROL('K'): knet_vty_kill_line(vty); break; case CONTROL('N'): knet_vty_history_next(vty); break; case CONTROL('P'): knet_vty_history_prev(vty); break; case CONTROL('T'): knet_vty_transpose_chars(vty); break; case CONTROL('U'): knet_vty_kill_line_from_beginning(vty); break; case CONTROL('W'): knet_vty_backward_kill_word(vty); break; case CONTROL('Z'): vty->node = NODE_CONFIG; knet_vty_exit_node(vty); knet_vty_newline(vty); break; case '\n': case '\r': knet_vty_end_of_line(vty); knet_vty_write(vty, "%s", telnet_newline); knet_vty_history_add(vty); knet_vty_execute_cmd(vty); knet_vty_reset_buf(vty); knet_vty_prompt(vty); break; case '\t': knet_vty_end_of_line(vty); knet_vty_tab_completion(vty); break; case '?': knet_vty_end_of_line(vty); knet_vty_write(vty, "%s", telnet_newline); knet_vty_help(vty); knet_vty_prompt(vty); knet_vty_write(vty, "%s", vty->line); break; case '\033': vty->escape = VTY_PRE_ESCAPE; break; default: if (buf[i] > 31 && buf[i] < 127) knet_vty_add_to_buf(vty, buf, i); break; } } return 0; } void knet_vty_cli_bind(struct knet_vty *vty) { int se_result = 0; fd_set rfds; struct timeval tv; unsigned char buf[VTY_MAX_BUFFER_SIZE]; int readlen; knet_vty_prompt(vty); while (se_result >= 0 && !vty->got_epipe) { FD_ZERO (&rfds); FD_SET (vty->vty_sock, &rfds); tv.tv_sec = 1; tv.tv_usec = 0; se_result = select((vty->vty_sock + 1), &rfds, 0, 0, &tv); if ((se_result == -1) || (vty->got_epipe)) goto out_clean; if ((se_result == 0) || (!FD_ISSET(vty->vty_sock, &rfds))) continue; memset(buf, 0 , sizeof(buf)); readlen = knet_vty_read(vty, buf, sizeof(buf)); if (readlen <= 0) goto out_clean; if (knet_vty_process_buf(vty, buf, readlen) < 0) { knet_vty_write(vty, "\nError processing command: command too long\n"); knet_vty_reset_buf(vty); } } out_clean: return; } diff --git a/kronosnetd/vty_cli.h b/kronosnetd/vty_cli.h index 81110a11..d3c0df74 100644 --- a/kronosnetd/vty_cli.h +++ b/kronosnetd/vty_cli.h @@ -1,20 +1,18 @@ /* * Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. * * Author: Fabio M. Di Nitto * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNETD_VTY_CLI_H__ #define __KNETD_VTY_CLI_H__ #include "vty.h" -static const char telnet_backward_char[] = { 0x08, 0x0 }; static const char telnet_newline[] = { '\n', '\r', 0x0 }; -static const char file_newline[] = { '\n', 0x0 }; void knet_vty_cli_bind(struct knet_vty *vty); #endif diff --git a/kronosnetd/vty_cli_cmds.c b/kronosnetd/vty_cli_cmds.c index bf795e6e..07331bb7 100644 --- a/kronosnetd/vty_cli_cmds.c +++ b/kronosnetd/vty_cli_cmds.c @@ -1,2188 +1,2169 @@ /* * Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto * Federico Simoncelli * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include #include #include #include #include #include #include #include "cfg.h" #include "etherfilter.h" #include "logging.h" #include "libnozzle.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 +static const char file_newline[] = { '\n', 0x0 }; + /* * 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) { + if (knet_get_transport_id_by_name(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, ¶m, ¶mlen, ¶moffset); 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, ¶m, ¶mlen, ¶moffset); 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, 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, ¶m, ¶mlen, ¶moffset); 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, ¶m, ¶mlen, ¶moffset); 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, ¶m, ¶mlen, ¶moffset); keepalive = param_to_int(param, paramlen); get_param(vty, 2, ¶m, ¶mlen, ¶moffset); 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, ¶m, ¶mlen, ¶moffset); 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, ¶m, ¶mlen, ¶moffset); 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, sizeof(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, ¶m, ¶mlen, ¶moffset); vty->link_id = param_to_int(param, paramlen); get_param(vty, 2, ¶m, ¶mlen, ¶moffset); 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, ¶m, ¶mlen, ¶moffset); 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, ¶m, ¶mlen, ¶moffset); param_to_str(transport, sizeof(transport), param, paramlen); - transport_id = knet_handle_get_transport_id_by_name(knet_iface->cfg_ring.knet_h, transport); + transport_id = knet_get_transport_id_by_name(transport); knet_link_get_status(knet_iface->cfg_ring.knet_h, vty->host_id, vty->link_id, &status, sizeof(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_FLAG_TRAFFICHIPRIO); 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, ¶m, ¶mlen, ¶moffset); 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 knet_node_id_t requested_node_id) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; int have_nodeid, have_name; knet_node_id_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) { knet_vty_write(vty, "Error: unable to query libknet for 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, ¶m, ¶mlen, ¶moffset); param_to_str(nodename, sizeof(nodename), param, paramlen); get_param(vty, 2, ¶m, ¶mlen, ¶moffset); 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, ¶m, ¶mlen, ¶moffset); param_to_str(nodename, sizeof(nodename), param, paramlen); get_param(vty, 2, ¶m, ¶mlen, ¶moffset); 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, ¶m, ¶mlen, ¶moffset); param_to_str(ipaddr, sizeof(ipaddr), param, paramlen); get_param(vty, 2, ¶m, ¶mlen, ¶moffset); param_to_str(prefix, sizeof(prefix), param, paramlen); - if (tap_del_ip(knet_iface->cfg_eth.tap, ipaddr, prefix, &error_string) < 0) { + if (nozzle_del_ip(knet_iface->cfg_eth.nozzle, ipaddr, prefix) < 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); - } + ipaddr, prefix, nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle), telnet_newline); 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, ¶m, ¶mlen, ¶moffset); param_to_str(ipaddr, sizeof(ipaddr), param, paramlen); get_param(vty, 2, ¶m, ¶mlen, ¶moffset); param_to_str(prefix, sizeof(prefix), param, paramlen); - if (tap_add_ip(knet_iface->cfg_eth.tap, ipaddr, prefix, &error_string) < 0) { + if (nozzle_add_ip(knet_iface->cfg_eth.nozzle, ipaddr, prefix) < 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); - } + ipaddr, prefix, nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle), telnet_newline); 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); + mtu = nozzle_get_mtu(knet_iface->cfg_eth.nozzle); if (mtu < 0) { log_debug("Unable to get current MTU?"); } else { if (data_mtu < (unsigned int)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) { + if (nozzle_set_mtu(knet_iface->cfg_eth.nozzle, 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)); + knet_iface->cfg_ring.data_mtu, nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle)); } 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); + nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle), 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); + nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle), 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, ¶m, ¶mlen, ¶moffset); 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); + pmtufreq, nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle), 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) { + if (nozzle_set_mtu(knet_iface->cfg_eth.nozzle, 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); + nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle), telnet_newline); return -1; } } else { - if (tap_reset_mtu(knet_iface->cfg_eth.tap) < 0) { + if (nozzle_reset_mtu(knet_iface->cfg_eth.nozzle) < 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); + nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle), 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, ¶m, ¶mlen, ¶moffset); 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) { + if (nozzle_set_mtu(knet_iface->cfg_eth.nozzle, 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); + expected_mtu, nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle), 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; + char *exec_str = NULL; int err = 0; - err = tap_set_down(knet_iface->cfg_eth.tap, &error_down, &error_postdown); + err = nozzle_run_updown(knet_iface->cfg_eth.nozzle, NOZZLE_DOWN, &exec_str); + if (err) { + knet_vty_write(vty, "Non-fatal Error: Unable to execute down.d script for interface %s: %s!%s", nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle), exec_str, telnet_newline); + if (exec_str) { + free(exec_str); + exec_str = NULL; + } + } + + err = nozzle_set_down(knet_iface->cfg_eth.nozzle); 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); + knet_vty_write(vty, "Error: Unable to set interface %s down!%s", nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle), 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); + + err = nozzle_run_updown(knet_iface->cfg_eth.nozzle, NOZZLE_POSTDOWN, &exec_str); + if (err) { + knet_vty_write(vty, "Non-fatal Error: Unable to execute post-down.d script for interface %s: %s!%s", nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle), exec_str, telnet_newline); + if (exec_str) { + free(exec_str); + exec_str = NULL; + } } 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, ¶m, ¶mlen, ¶moffset); param_to_str(knet_handle_crypto_cfg_new.crypto_model, sizeof(knet_handle_crypto_cfg_new.crypto_model), param, paramlen); get_param(vty, 2, ¶m, ¶mlen, ¶moffset); 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, ¶m, ¶mlen, ¶moffset); 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)); + snprintf(keyfile, PATH_MAX - 1, DEFAULT_CONFIG_DIR "/cryptokeys.d/%s", nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle)); 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 %d <= key_len <= %d%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_handle_crypto_cfg_new.private_key_len) != (ssize_t)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; + char *exec_str = NULL; int err = 0; - err = tap_set_up(knet_iface->cfg_eth.tap, &error_preup, &error_up); + err = nozzle_run_updown(knet_iface->cfg_eth.nozzle, NOZZLE_PREUP, &exec_str); + if (err) { + knet_vty_write(vty, "Non-fatal Error: Unable to execute pre-up.d script for interface %s: %s!%s", nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle), exec_str, telnet_newline); + if (exec_str) { + free(exec_str); + exec_str = NULL; + } + } + + err = nozzle_set_up(knet_iface->cfg_eth.nozzle); 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_vty_write(vty, "Error: Unable to set interface %s up!%s", nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle), 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); + + err = nozzle_run_updown(knet_iface->cfg_eth.nozzle, NOZZLE_UP, &exec_str); + if (err) { + knet_vty_write(vty, "Non-fatal Error: Unable to execute up.d script for interface %s: %s!%s", nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle), exec_str, telnet_newline); + if (exec_str) { + free(exec_str); + exec_str = NULL; + } } 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, offset = 0; size_t j, i; - char *error_string = NULL; knet_node_id_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, ¶m, ¶mlen, ¶moffset); 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 <= (size_t)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->cfg_eth.nozzle) + nozzle_close(knet_iface->cfg_eth.nozzle); 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]; + char mac[30]; struct knet_cfg *knet_iface = NULL; int8_t channel = 0; get_param(vty, 1, ¶m, ¶mlen, ¶moffset); param_to_str(device, IFNAMSIZ, param, paramlen); get_param(vty, 2, ¶m, ¶mlen, ¶moffset); requested_id = param_to_int(param, paramlen); get_param(vty, 3, ¶m, ¶mlen, ¶moffset); 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) { + if (knet_iface->cfg_eth.nozzle) { 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.nozzle) + knet_iface->cfg_eth.nozzle = nozzle_open(device, IFNAMSIZ, DEFAULT_CONFIG_DIR); - if ((!knet_iface->cfg_eth.tap) && (errno == EBUSY)) { + if ((!knet_iface->cfg_eth.nozzle) && (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) { + if (!knet_iface->cfg_eth.nozzle) { 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); + tapfd = nozzle_get_fd(knet_iface->cfg_eth.nozzle); 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) { + if (nozzle_set_mac(knet_iface->cfg_eth.nozzle, 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); + if (knet_iface->cfg_eth.nozzle) + nozzle_close(knet_iface->cfg_eth.nozzle); 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) { size_t 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]; knet_node_id_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_vty_write(vty, "interface %s (active: %d)%s", nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle), 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; uint64_t flags; if (!knet_link_get_config(knet_iface->cfg_ring.knet_h, host_ids[j], link_ids[i], &transport, &src_addr, &dst_addr, &dynamic, &flags)) { - transport_name = knet_handle_get_transport_name_by_id(knet_iface->cfg_ring.knet_h, transport); + transport_name = knet_get_transport_name_by_id(transport); knet_link_get_status(knet_iface->cfg_ring.knet_h, host_ids[j], link_ids[i], &status, sizeof(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) { size_t 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; + struct nozzle_ip *ip_list = NULL; knet_node_id_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 %d %d%s", tap_get_name(knet_iface->cfg_eth.tap), + knet_vty_write(vty, " interface %s %d %d%s", nozzle_get_name_by_handle(knet_iface->cfg_eth.nozzle), 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_vty_write(vty, " mtu %d%s", nozzle_get_mtu(knet_iface->cfg_eth.nozzle), nl); knet_handle_pmtud_getfreq(knet_iface->cfg_ring.knet_h, &pmtudfreq); if ((pmtudfreq > 0) && (pmtudfreq != 5)) knet_vty_write(vty, " pmtudfreq %u%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 <= (size_t)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; + nozzle_get_ips(knet_iface->cfg_eth.nozzle, &ip_list); + while (ip_list) { + knet_vty_write(vty, " ip %s %s%s", ip_list->ipaddr, ip_list->prefix, nl); + ip_list = ip_list->next; } 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; uint64_t flags; if (!knet_link_get_config(knet_iface->cfg_ring.knet_h, host_ids[j], link_ids[i], &transport, &src_addr, &dst_addr, &dynamic, &flags)) { - transport_name = knet_handle_get_transport_name_by_id(knet_iface->cfg_ring.knet_h, transport); + transport_name = knet_get_transport_name_by_id(transport); knet_link_get_status(knet_iface->cfg_ring.knet_h, host_ids[j], link_ids[i], &status, sizeof(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)); + snprintf(vty->line, sizeof(vty->line) - 1, "no interface %s", nozzle_get_name_by_handle(knet_cfg_head.knet_cfg->cfg_eth.nozzle)); 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); }