diff --git a/build-aux/update-copyright.sh b/build-aux/update-copyright.sh index d5c256ae..82f9c4d4 100755 --- a/build-aux/update-copyright.sh +++ b/build-aux/update-copyright.sh @@ -1,28 +1,29 @@ #!/bin/bash # # Copyright (C) 2017 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto <fabbione@kronosnet.org> # # This software licensed under GPL-2.0+, LGPL-2.0+ # # script to update copyright dates across the tree -input=$(grep -ril -e "Copyright.*Red Hat" |grep -v .swp) +enddate=$(date +%Y) + +input=$(grep -ril -e "Copyright.*Red Hat" |grep -v .swp |grep -v update-copyright) for i in $input; do - startdate=$(git log "$i" | grep ^Date: | tail -n 1 | awk '{print $6}') - enddate=$(git log "$i" | grep ^Date: | head -n 1 | awk '{print $6}') + startdate=$(git log --follow "$i" | grep ^Date: | tail -n 1 | awk '{print $6}') if [ "$startdate" != "$enddate" ]; then sed -i -e 's#Copyright (C).*Red Hat#Copyright (C) '$startdate'-'$enddate' Red Hat#g' $i else sed -i -e 's#Copyright (C).*Red Hat#Copyright (C) '$startdate' Red Hat#g' $i fi done input=$(find . -type f |grep -v ".git") for i in $input; do if [ -z "$(grep -i "Copyright" $i)" ]; then echo "WARNING: $i appears to be missing Copyright information" fi done diff --git a/init/Makefile.am b/init/Makefile.am index 23c71e04..ed74d2ea 100644 --- a/init/Makefile.am +++ b/init/Makefile.am @@ -1,47 +1,47 @@ # -# Copyright (C) 2012-2016 Red Hat, Inc. All rights reserved. +# Copyright (C) 2012-2017 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 include $(top_srcdir)/build-aux/check.mk EXTRA_DIST = kronosnetd.in kronosnetd.service.in \ kronosnetd.default if BUILD_KRONOSNETD systemdconfdir = $(SYSTEMDDIR) systemdconf_DATA = kronosnetd.service initscriptdir = $(INITDDIR) initscript_SCRIPTS = kronosnetd %: %.in Makefile rm -f $@-t $@ cat $< | sed \ -e 's#@''SBINDIR@#$(sbindir)#g' \ -e 's#@''SYSCONFDIR@#$(sysconfdir)#g' \ -e 's#@''INITDDIR@#$(INITDDIR)#g' \ -e 's#@''LOCALSTATEDIR@#$(localstatedir)#g' \ > $@-t mv $@-t $@ install-exec-local: $(INSTALL) -d $(DESTDIR)/$(INITDEFAULTDIR) $(INSTALL) -m 644 $(srcdir)/kronosnetd.default $(DESTDIR)/$(INITDEFAULTDIR)/kronosnetd uninstall-local: rm -f $(DESTDIR)/$(INITDEFAULTDIR)/kronosnetd rmdir $(DESTDIR)/$(INITDEFAULTDIR) || :; all-local: $(initscript_SCRIPTS) $(systemdconf_DATA) clean-local: rm -rf $(initscript_SCRIPTS) $(systemdconf_DATA) endif diff --git a/init/kronosnetd.in b/init/kronosnetd.in index d879d89e..0edeb987 100644 --- a/init/kronosnetd.in +++ b/init/kronosnetd.in @@ -1,152 +1,152 @@ #!/bin/bash # -# Copyright (C) 2012-2015 Red Hat, Inc. All rights reserved. +# Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto <fabbione@kronosnet.org> # # This software licensed under GPL-2.0+, LGPL-2.0+ # # chkconfig: - 20 80 # description: kronosnetd vpn daemon # processname: kronosnetd # ### BEGIN INIT INFO # Provides: kronosnetd # Required-Start: $network $remote_fs $syslog # Required-Stop: $network $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: # Short-Description: Starts and stops kronosnetd vpn daemon. # Description: Starts and stops kronosnetd vpn daemon. ### END INIT INFO desc="kronosnetd" prog="kronosnetd" # set secure PATH PATH="/sbin:/bin:/usr/sbin:/usr/bin:@SBINDIR@" success() { echo -ne "[ OK ]\r" } failure() { echo -ne "[FAILED]\r" } status() { pid=$(pidof $1 2>/dev/null) rtrn=$? if [ $rtrn -ne 0 ]; then echo "$1 is stopped" else echo "$1 (pid $pid) is running..." fi return $rtrn } # rpm based distros if [ -d @SYSCONFDIR@/sysconfig ]; then [ -f @INITDDIR@/functions ] && . @INITDDIR@/functions [ -f @SYSCONFDIR@/sysconfig/$prog ] && . @SYSCONFDIR@/sysconfig/$prog [ -z "$LOCK_FILE" ] && LOCK_FILE="@LOCALSTATEDIR@/lock/subsys/$prog" fi # deb based distros if [ -d @SYSCONFDIR@/default ]; then [ -f @SYSCONFDIR@/default/$prog ] && . @SYSCONFDIR@/default/$prog [ -z "$LOCK_FILE" ] && LOCK_FILE="@LOCALSTATEDIR@/lock/$prog" fi # The version of __pids_pidof in /etc/init.d/functions calls pidof with -x # This means it matches scripts, including this one. # Redefine it here so that status (from the same file) works. # Otherwise simultaneous calls to stop() will loop forever __pids_pidof() { pidof -c -o $$ -o $PPID -o %PPID "$1" || \ pidof -c -o $$ -o $PPID -o %PPID "${1##*/}" } start() { echo -n "Starting $desc ($prog): " # most recent distributions use tmpfs for @LOCALSTATEDIR@/run # to avoid to clean it up on every boot. # they also assume that init scripts will create # required subdirectories for proper operations mkdir -p @LOCALSTATEDIR@/run if status $prog > /dev/null 2>&1; then success else $prog $KNETD_OPTS > /dev/null 2>&1 touch $LOCK_FILE success fi echo } stop() { ! status $prog > /dev/null 2>&1 && return echo -n "Signaling $desc ($prog) to terminate: " kill -TERM $(pidof $prog) > /dev/null 2>&1 success echo echo -n "Waiting for $prog to unload:" while status $prog > /dev/null 2>&1; do sleep 1 echo -n "." done rm -f $LOCK_FILE success echo } restart() { stop start } rtrn=0 case "$1" in start) start rtrn=$? ;; restart|reload|force-reload) restart rtrn=$? ;; condrestart|try-restart) if status $prog > /dev/null 2>&1; then restart rtrn=$? fi ;; status) status $prog rtrn=$? ;; stop) stop rtrn=$? ;; *) echo "usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}" rtrn=2 ;; esac exit $rtrn diff --git a/kronosnetd/cfg.c b/kronosnetd/cfg.c index 02d200ed..1d9074c1 100644 --- a/kronosnetd/cfg.c +++ b/kronosnetd/cfg.c @@ -1,88 +1,88 @@ /* - * Copyright (C) 2012-2015 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 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 <pthread.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include "cfg.h" #include "libtap.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)) { 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 99a9d217..f046e96a 100644 --- a/kronosnetd/cfg.h +++ b/kronosnetd/cfg.h @@ -1,55 +1,55 @@ /* - * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNETD_CFG_H__ #define __KNETD_CFG_H__ #include <stdint.h> #include <net/if.h> #include "libtap.h" #include "libknet.h" #define KNET_RING_DEFPORT 50000 struct knet_cfg_eth { tap_t tap; int auto_mtu; 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/knet-keygen.8 b/kronosnetd/knet-keygen.8 index 4e30ba20..d272b0c7 100644 --- a/kronosnetd/knet-keygen.8 +++ b/kronosnetd/knet-keygen.8 @@ -1,28 +1,28 @@ .\"/* -.\" * Copyright (C) 2012-2015 Red Hat, Inc. +.\" * Copyright (C) 2012-2017 Red Hat, Inc. .\" * .\" * All rights reserved. .\" * .\" * Author: Fabio M. Di Nitto <fabbione@kronosnet.org> .\" * .\" * This software licensed under GPL-2.0+, LGPL-2.0+ .\" */ .TH "KRONOSNETD" "8" "November 2012" "kronosnetd key generator." "System Administration Utilities" .SH "NAME" knet\-keygen \- Tool to generate keys for kronosnetd. .SH "SYNOPSIS" .B knet\-keygen \fB\-o\fR <output_file> [\-s <size>] .SH "OPTIONS" .TP \fB\-o\fR Output file .TP \fB\-s\fR Key size (value between 1024 and 4096 included) .SH "SEE ALSO" kronosnetd(8) diff --git a/kronosnetd/kronosnetd.8 b/kronosnetd/kronosnetd.8 index b34de276..110d8c37 100644 --- a/kronosnetd/kronosnetd.8 +++ b/kronosnetd/kronosnetd.8 @@ -1,51 +1,51 @@ .\"/* -.\" * Copyright (C) 2012-2015 Red Hat, Inc. +.\" * Copyright (C) 2012-2017 Red Hat, Inc. .\" * .\" * All rights reserved. .\" * .\" * Author: Fabio M. Di Nitto <fabbione@kronosnet.org> .\" * .\" * This software licensed under GPL-2.0+, LGPL-2.0+ .\" */ .TH "KRONOSNETD" "8" "November 2012" "kronosnetd Usage:" "System Administration Utilities" .SH "NAME" kronosnetd \- libknet management daemon .SH "DESCRIPTION" Usage: .PP kronosnetd [options] .SH "OPTIONS" .TP \fB\-a\fR <ipv6_addr> Bind management VTY to ipv6_addr (default: localhost) .TP \fB\-b\fR <ipv4_addr> Bind management VTY to ipv4_addr (default: localhost) .TP \fB\-p\fR <port> Bind management VTY to port (default 50000) .TP \fB\-c\fR <file> Use config file (default /etc/kronosnet/kronosnetd.conf) .TP \fB\-l\fR <file> Use log file (default /var/log//kronosnetd.log) .TP \fB\-f\fR Do not fork in background .TP \fB\-d\fR Enable debugging output .TP \fB\-h\fR This help .TP \fB\-V\fR Print program version information .SH "SEE ALSO" knet-keygen(8) diff --git a/kronosnetd/kronosnetd.logrotate.in b/kronosnetd/kronosnetd.logrotate.in index acfd331d..af4a113e 100644 --- a/kronosnetd/kronosnetd.logrotate.in +++ b/kronosnetd/kronosnetd.logrotate.in @@ -1,17 +1,17 @@ # -# Copyright (C) 2012-2015 Red Hat, Inc. All rights reserved. +# Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto <fabbione@kronosnet.org> # # This software licensed under GPL-2.0+, LGPL-2.0+ # @LOGDIR@kronosnetd.log { missingok compress copytruncate daily rotate 31 minsize 2048 notifempty } diff --git a/kronosnetd/logging.c b/kronosnetd/logging.c index d041a2ad..a1006a6a 100644 --- a/kronosnetd/logging.c +++ b/kronosnetd/logging.c @@ -1,55 +1,55 @@ /* - * Copyright (C) 2012-2015 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include "logging.h" void logging_init_defaults(int debug, int daemonize, const char *logfile) { int level = SYSLOGLEVEL; int32_t filetarget; if (debug) { level = LOG_DEBUG; } qb_log_init(PACKAGE "d", SYSLOGFACILITY, level); qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_TRUE); if (debug) { qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_PRIORITY_BUMP, LOG_INFO - LOG_DEBUG); } /* * initialize stderr output only if we are not forking in background */ if (!daemonize) { qb_log_format_set(QB_LOG_STDERR, "%t %N [%p]: %b"); qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE); qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FUNCTION, "*", level); } filetarget = qb_log_file_open(logfile); qb_log_ctl(filetarget, QB_LOG_CONF_ENABLED, QB_TRUE); qb_log_format_set(filetarget, "%t %N [%p]: %b"); qb_log_filter_ctl(filetarget, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FUNCTION, "*", level); qb_log_thread_start(); qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_THREADED, QB_TRUE); qb_log_ctl(filetarget, QB_LOG_CONF_THREADED, QB_TRUE); } void logging_fini(void) { qb_log_fini(); } diff --git a/kronosnetd/logging.h b/kronosnetd/logging.h index 6ab6acbc..61cc96c0 100644 --- a/kronosnetd/logging.h +++ b/kronosnetd/logging.h @@ -1,29 +1,29 @@ /* - * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNETD_LOGGING_H__ #define __KNETD_LOGGING_H__ #include <qb/qblog.h> #define log_debug(fmt, args...) qb_log(LOG_DEBUG, "(%s:%i|%s): " fmt, __FILE__, __LINE__, __FUNCTION__, ##args); #define log_kdebug(fmt, args...) qb_log(LOG_DEBUG, fmt, ##args); #define log_info(fmt, args...) qb_log(LOG_INFO, fmt, ##args); #define log_warn(fmt, args...) qb_log(LOG_WARNING, fmt, ##args); #define log_error(fmt, args...) qb_log(LOG_ERR, fmt, ##args); void logging_init_defaults(int debug, int daemonize, const char *logfile); void logging_fini(void); #endif diff --git a/kronosnetd/main.c b/kronosnetd/main.c index 39cc2d58..34403a2f 100644 --- a/kronosnetd/main.c +++ b/kronosnetd/main.c @@ -1,347 +1,347 @@ /* - * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sched.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <string.h> #include "cfg.h" #include "vty.h" #include "logging.h" #define LOCKFILE_NAME RUNDIR PACKAGE "d.pid" #define OPTION_STRING "hdfVc:l:a:b:p:" static int debug = 0; static int daemonize = 1; struct knet_cfg_top knet_cfg_head; static void print_usage(void) { printf("Usage:\n\n"); printf(PACKAGE "d [options]\n\n"); printf("Options:\n\n"); printf(" -a <ipv6_addr> Bind management VTY to ipv6_addr (default: localhost)\n"); printf(" -b <ipv4_addr> Bind management VTY to ipv4_addr (default: localhost)\n"); printf(" -p <port> Bind management VTY to port (default %d)\n", KNET_VTY_DEFAULT_PORT); printf(" -c <file> Use config file (default "DEFAULT_CONFIG_FILE")\n"); printf(" -l <file> Use log file (default "DEFAULT_LOG_FILE")\n"); printf(" -f Do not fork in background\n"); printf(" -d Enable debugging output\n"); printf(" -h This help\n"); printf(" -V Print program version information\n"); return; } static int read_arguments(int argc, char **argv) { int cont = 1; int optchar; int int_port; while (cont) { optchar = getopt(argc, argv, OPTION_STRING); switch (optchar) { case 'a': knet_cfg_head.vty_ipv6 = strdup(optarg); if (!knet_cfg_head.vty_ipv6) return -1; break; case 'b': knet_cfg_head.vty_ipv4 = strdup(optarg); if (!knet_cfg_head.vty_ipv4) return -1; break; case 'p': int_port = atoi(optarg); if ((int_port < 0) || (int_port > 65535)) { errno = EINVAL; return -1; } knet_cfg_head.vty_port = strdup(optarg); if (!knet_cfg_head.vty_port) return -1; break; case 'c': knet_cfg_head.conffile = strdup(optarg); if (!knet_cfg_head.conffile) return -1; break; case 'l': knet_cfg_head.logfile = strdup(optarg); if (!knet_cfg_head.logfile) return -1; break; case 'd': debug = 1; break; case 'f': daemonize = 0; break; case 'h': print_usage(); exit(EXIT_SUCCESS); break; case 'V': printf(PACKAGE "d " PACKAGE_VERSION " (built " __DATE__ " " __TIME__ ")\n"); exit(EXIT_SUCCESS); break; case EOF: cont = 0; break; default: fprintf(stderr, "unknown option: %c\n", optchar); print_usage(); exit(EXIT_FAILURE); break; } } return 0; } static int set_scheduler(void) { struct sched_param sched_param; int err; err = sched_get_priority_max(SCHED_RR); if (err < 0) { log_warn("Could not get maximum scheduler priority"); return err; } sched_param.sched_priority = err; err = sched_setscheduler(0, SCHED_RR, &sched_param); if (err < 0) log_warn("could not set SCHED_RR priority %d", sched_param.sched_priority); return err; } static void remove_lockfile(void) { unlink(LOCKFILE_NAME); } static int create_lockfile(const char *lockfile) { int fd, value; size_t bufferlen; ssize_t write_out; struct flock lock; char buffer[50]; if ((fd = open(lockfile, O_CREAT | O_WRONLY, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) { fprintf(stderr, "Cannot open lockfile [%s], error was [%s]\n", lockfile, strerror(errno)); return -1; } lock.l_type = F_WRLCK; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len = 0; retry_fcntl: if (fcntl(fd, F_SETLK, &lock) < 0) { switch (errno) { case EINTR: goto retry_fcntl; break; case EACCES: case EAGAIN: fprintf(stderr, "Cannot lock lockfile [%s], error was [%s]\n", lockfile, strerror(errno)); break; default: fprintf(stderr, "process is already running\n"); } goto fail_close; } if (ftruncate(fd, 0) < 0) { fprintf(stderr, "Cannot truncate pidfile [%s], error was [%s]\n", lockfile, strerror(errno)); goto fail_close_unlink; } memset(buffer, 0, sizeof(buffer)); snprintf(buffer, sizeof(buffer)-1, "%d\n", getpid()); bufferlen = strlen(buffer); write_out = write(fd, buffer, bufferlen); if ((write_out < 0) || (write_out == 0 && errno)) { fprintf(stderr, "Cannot write pid to pidfile [%s], error was [%s]\n", lockfile, strerror(errno)); goto fail_close_unlink; } if ((write_out == 0) || ((size_t)write_out < bufferlen)) { fprintf(stderr, "Cannot write pid to pidfile [%s], shortwrite of" "[%zd] bytes, expected [%zu]\n", lockfile, write_out, bufferlen); goto fail_close_unlink; } if ((value = fcntl(fd, F_GETFD, 0)) < 0) { fprintf(stderr, "Cannot get close-on-exec flag from pidfile [%s], " "error was [%s]\n", lockfile, strerror(errno)); goto fail_close_unlink; } value |= FD_CLOEXEC; if (fcntl(fd, F_SETFD, value) < 0) { fprintf(stderr, "Cannot set close-on-exec flag from pidfile [%s], " "error was [%s]\n", lockfile, strerror(errno)); goto fail_close_unlink; } atexit(remove_lockfile); return 0; fail_close_unlink: if (unlink(lockfile)) fprintf(stderr, "Unable to unlink %s\n", lockfile); fail_close: if (close(fd)) fprintf(stderr, "Unable to close %s file descriptor\n", lockfile); return -1; } static void set_cfg_defaults(void) { if (!knet_cfg_head.conffile) knet_cfg_head.conffile = strdup(DEFAULT_CONFIG_FILE); if (!knet_cfg_head.conffile) { fprintf(stderr, "Unable to allocate memory for config file\n"); exit(EXIT_FAILURE); } if (!knet_cfg_head.logfile) knet_cfg_head.logfile = strdup(DEFAULT_LOG_FILE); if (!knet_cfg_head.conffile) { fprintf(stderr, "Unable to allocate memory for log file\n"); exit(EXIT_FAILURE); } if (!knet_cfg_head.vty_ipv6) knet_cfg_head.vty_ipv6 = strdup("::1"); if (!knet_cfg_head.vty_ipv6) { fprintf(stderr, "Unable to allocate memory for default ip address\n"); exit(EXIT_FAILURE); } if (!knet_cfg_head.vty_ipv4) knet_cfg_head.vty_ipv4 = strdup("127.0.0.1"); if (!knet_cfg_head.vty_ipv4) { fprintf(stderr, "Unable to allocate memory for default ip address\n"); exit(EXIT_FAILURE); } if (!knet_cfg_head.vty_port) { char portbuf[8]; memset(&portbuf, 0, sizeof(portbuf)); snprintf(portbuf, sizeof(portbuf), "%d", KNET_VTY_DEFAULT_PORT); knet_cfg_head.vty_port = strdup(portbuf); } if (!knet_cfg_head.vty_port) { fprintf(stderr, "Unable to allocate memory for default port address\n"); exit(EXIT_FAILURE); } } int main(int argc, char **argv) { int err; memset(&knet_cfg_head, 0, sizeof(struct knet_cfg_top)); if (read_arguments(argc, argv) < 0) { fprintf(stderr, "Unable to parse options\n"); exit(EXIT_FAILURE); } set_cfg_defaults(); if (create_lockfile(LOCKFILE_NAME) < 0) { fprintf(stderr, "Unable to create lockfile\n"); exit(EXIT_FAILURE); } if (daemonize) { if (daemon(0, 0) < 0) { perror("Unable to daemonize"); exit(EXIT_FAILURE); } } logging_init_defaults(debug, daemonize, knet_cfg_head.logfile); log_info(PACKAGE "d version " VERSION); /* * don't fail if scheduler is not RR because systemd is * an utter piece of shit that refuses us to set RR via init script */ set_scheduler(); err = knet_vty_main_loop(debug); if (err < 0) log_error("Detected fatal error in main loop"); if (knet_cfg_head.logfile) free(knet_cfg_head.logfile); if (knet_cfg_head.conffile) free(knet_cfg_head.conffile); if (knet_cfg_head.vty_ipv6) free(knet_cfg_head.vty_ipv6); if (knet_cfg_head.vty_ipv4) free(knet_cfg_head.vty_ipv4); if (knet_cfg_head.vty_port) free(knet_cfg_head.vty_port); logging_fini(); return err; } diff --git a/kronosnetd/vty.c b/kronosnetd/vty.c index c25993fe..067b93e8 100644 --- a/kronosnetd/vty.c +++ b/kronosnetd/vty.c @@ -1,504 +1,504 @@ /* - * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #include <fcntl.h> #include <arpa/inet.h> #include <string.h> #include <errno.h> #include <pthread.h> #include <signal.h> #include <stdlib.h> #include "cfg.h" #include "logging.h" #include "netutils.h" #include "vty.h" #include "vty_auth.h" #include "vty_cli.h" #include "vty_cli_cmds.h" #include "vty_utils.h" static int vty_max_connections = KNET_VTY_DEFAULT_MAX_CONN; static int vty_current_connections = 0; static int daemon_quit = 0; pthread_mutex_t knet_vty_mutex = PTHREAD_MUTEX_INITIALIZER; int knet_vty_config = -1; struct knet_vty knet_vtys[KNET_VTY_TOTAL_MAX_CONN]; struct knet_vty_global_conf vty_global_conf; pthread_t logging_thread; static int _fdset_cloexec(int fd) { int fdflags; fdflags = fcntl(fd, F_GETFD, 0); if (fdflags < 0) return -1; fdflags |= FD_CLOEXEC; if (fcntl(fd, F_SETFD, fdflags) < 0) return -1; return 0; } static int _fdset_nonblock(int fd) { int fdflags; fdflags = fcntl(fd, F_GETFL, 0); if (fdflags < 0) return -1; fdflags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, fdflags) < 0) return -1; return 0; } static void *_handle_logging_thread(void *data) { int logfd; int se_result = 0; fd_set rfds; struct timeval tv; memmove(&logfd, data, sizeof(int)); while (se_result >= 0 && !daemon_quit){ FD_ZERO (&rfds); FD_SET (logfd, &rfds); tv.tv_sec = 1; tv.tv_usec = 0; se_result = select(FD_SETSIZE, &rfds, 0, 0, &tv); if (se_result == -1) goto out; if (se_result == 0) continue; if (FD_ISSET(logfd, &rfds)) { struct knet_log_msg msg; size_t bytes_read = 0; size_t len; while (bytes_read < sizeof(struct knet_log_msg)) { len = read(logfd, &msg + bytes_read, sizeof(struct knet_log_msg) - bytes_read); if (len <= 0) { break; } bytes_read += len; } if (bytes_read != sizeof(struct knet_log_msg)) continue; switch(msg.msglevel) { case KNET_LOG_WARN: log_warn("(%s) %s", knet_log_get_subsystem_name(msg.subsystem), msg.msg); break; case KNET_LOG_INFO: log_info("(%s) %s", knet_log_get_subsystem_name(msg.subsystem), msg.msg); break; case KNET_LOG_DEBUG: log_kdebug("(%s) %s", knet_log_get_subsystem_name(msg.subsystem), msg.msg); break; case KNET_LOG_ERR: default: log_error("(%s) %s", knet_log_get_subsystem_name(msg.subsystem), msg.msg); } } } out: return NULL; } static int knet_vty_init_listener(const char *ip_addr, const char *port) { int sockfd = -1, sockopt = 1; int socktype = SOCK_STREAM; int err = 0; struct sockaddr_storage ss; memset(&ss, 0, sizeof(struct sockaddr_storage)); if (knet_strtoaddr(ip_addr, port, &ss, sizeof(struct sockaddr_storage)) != 0) return -1; pthread_mutex_lock(&knet_vty_mutex); /* handle sigpipe if we decide to use KEEPALIVE */ sockfd = socket(ss.ss_family, socktype, 0); if (sockfd < 0) { err = sockfd; goto out_clean; } if (ss.ss_family == AF_INET6) { err = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&sockopt, sizeof(sockopt)); if (err) goto out_clean; } err = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&sockopt, sizeof(sockopt)); if (err) goto out_clean; if (_fdset_cloexec(sockfd)) { err = -1; goto out_clean; } err = bind(sockfd, (struct sockaddr *)&ss, sizeof(struct sockaddr_storage)); if (err) goto out_clean; err = listen(sockfd, 0); if (err) goto out_clean; pthread_mutex_unlock(&knet_vty_mutex); return sockfd; out_clean: if (sockfd >= 0) close(sockfd); pthread_mutex_unlock(&knet_vty_mutex); return err; } static void knet_vty_close_listener(int listener_fd) { pthread_mutex_lock(&knet_vty_mutex); if (listener_fd <= 0) goto out_clean; close(listener_fd); listener_fd = 0; out_clean: pthread_mutex_unlock(&knet_vty_mutex); return; } static void sigterm_handler(int sig) { daemon_quit = 1; } static void sigpipe_handler(int sig) { return; } static void knet_vty_close(struct knet_vty *vty) { if (knet_vty_config == vty->conn_num) knet_vty_config = -1; knet_vty_free_history(vty); vty->active = 0; close(vty->vty_sock); vty_current_connections--; } static void *vty_accept_thread(void *arg) { struct knet_vty *vty = (struct knet_vty *)&knet_vtys[*(int *)arg]; char addr_str[KNET_MAX_HOST_LEN]; char port_str[KNET_MAX_PORT_LEN]; int err; knet_vty_print_banner(vty); if (vty->got_epipe) goto out_clean; err = knet_addrtostr(&vty->src_sa, vty->src_sa_len, addr_str, KNET_MAX_HOST_LEN, port_str, KNET_MAX_PORT_LEN); if (!err) { strncpy(vty->ip, addr_str, sizeof(vty->ip)); } else { strcpy(vty->ip, "unknown"); } if ((knet_vty_auth_user(vty, NULL) < 0) && (!vty->got_epipe)) { log_info("User failed to authenticate (ip: %s)", vty->ip); goto out_clean; } if (vty->got_epipe) goto out_clean; log_info("User %s connected from %s", vty->username, vty->ip); knet_vty_write(vty, "Welcome %s (%s) on vty(%d)\n\n", vty->username, vty->ip, vty->conn_num); if (vty->got_epipe) goto out_clean; if (knet_vty_set_iacs(vty) < 0) { knet_vty_write(vty, "Unable to set telnet session preferences"); goto out_clean; } if (vty->got_epipe) goto out_clean; knet_vty_cli_bind(vty); out_clean: pthread_mutex_lock(&knet_vty_mutex); knet_vty_close(vty); pthread_mutex_unlock(&knet_vty_mutex); return NULL; } /* * mainloop is not thread safe as there should only be one */ int knet_vty_main_loop(int debug) { int logfd[2]; int vty_listener6_fd; int vty_listener4_fd; int vty_listener_fd; int vty_accept_fd; struct sockaddr_storage incoming_sa; socklen_t salen; fd_set rfds; int se_result = 0; struct timeval tv; int err = 0; int conn_index, found; signal(SIGTERM, sigterm_handler); signal(SIGINT, sigterm_handler); signal(SIGPIPE, sigpipe_handler); if (pipe(logfd)) { log_error("Unable to create logging pipe"); return -1; } if ((_fdset_cloexec(logfd[0])) || (_fdset_nonblock(logfd[0])) || (_fdset_cloexec(logfd[1])) || (_fdset_nonblock(logfd[1]))) { log_error("Unable to set FD_CLOEXEX / O_NONBLOCK on logfd pipe"); return -1; } err = pthread_create(&logging_thread, NULL, _handle_logging_thread, (void *)&logfd[0]); if (err) { log_error("Unable to create logging thread"); return -1; } memset(&knet_vtys, 0, sizeof(knet_vtys)); memset(&vty_global_conf, 0, sizeof(struct knet_vty_global_conf)); vty_global_conf.idle_timeout = KNET_VTY_CLI_TIMEOUT; for(conn_index = 0; conn_index < KNET_VTY_TOTAL_MAX_CONN; conn_index++) { knet_vtys[conn_index].logfd = logfd[1]; knet_vtys[conn_index].vty_global_conf = &vty_global_conf; if (debug) { knet_vtys[conn_index].loglevel = KNET_LOG_DEBUG; } else { knet_vtys[conn_index].loglevel = KNET_LOG_INFO; } } if (knet_read_conf() < 0) { log_error("Unable to read config file %s", knet_cfg_head.conffile); return -1; } vty_listener6_fd = knet_vty_init_listener(knet_cfg_head.vty_ipv6, knet_cfg_head.vty_port); if (vty_listener6_fd < 0) { log_error("Unable to setup vty listener for ipv6"); return -1; } vty_listener4_fd = knet_vty_init_listener(knet_cfg_head.vty_ipv4, knet_cfg_head.vty_port); if (vty_listener4_fd < 0) { log_error("Unable to setup vty listener for ipv4"); goto out; } while (se_result >= 0 && !daemon_quit) { FD_ZERO (&rfds); FD_SET (vty_listener6_fd, &rfds); FD_SET (vty_listener4_fd, &rfds); tv.tv_sec = 1; tv.tv_usec = 0; se_result = select(FD_SETSIZE, &rfds, 0, 0, &tv); if ((se_result == -1) && (daemon_quit)) { log_info("Got a SIGTERM, requesting CLI threads to exit"); for(conn_index = 0; conn_index < KNET_VTY_TOTAL_MAX_CONN; conn_index++) { if (knet_vtys[conn_index].active) { knet_vty_write(&knet_vtys[conn_index], "%s%sServer is going down..%s%s", telnet_newline, telnet_newline, telnet_newline, telnet_newline); knet_vty_close(&knet_vtys[conn_index]); knet_vtys[conn_index].got_epipe = 1; } } sleep(2); /* give time to all vty to exit */ knet_close_down(); log_info("Have a nice day! Goodbye"); goto out; } if (se_result == -1) { err = se_result; log_error("Unable to select on vty listener socket!"); goto out; } if (se_result == 0) { 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_vtys[conn_index].idle_timeout)) { knet_vtys[conn_index].idle++; if (knet_vtys[conn_index].idle > knet_vtys[conn_index].idle_timeout) { knet_vty_close(&knet_vtys[conn_index]); knet_vtys[conn_index].got_epipe = 1; } } } pthread_mutex_unlock(&knet_vty_mutex); continue; } if (FD_ISSET(vty_listener6_fd, &rfds)) { vty_listener_fd = vty_listener6_fd; } else if (FD_ISSET(vty_listener4_fd, &rfds)) { vty_listener_fd = vty_listener4_fd; } else { continue; } memset(&incoming_sa, 0, sizeof(struct sockaddr_storage)); salen = sizeof(struct sockaddr_storage); vty_accept_fd = accept(vty_listener_fd, (struct sockaddr *)&incoming_sa, &salen); if (vty_accept_fd < 0) { log_error("Unable to accept connection to vty"); continue; } // check for ip address access list here against incoming_sa pthread_mutex_lock(&knet_vty_mutex); found = 0; for(conn_index = 0; conn_index <= vty_max_connections; conn_index++) { if (knet_vtys[conn_index].active == 0) { found = 1; break; } } if ((vty_current_connections == vty_max_connections) || (!found)) { errno = ECONNREFUSED; log_error("Too many connections to VTY or no available slots"); close(vty_accept_fd); pthread_mutex_unlock(&knet_vty_mutex); continue; } vty_current_connections++; memset(&knet_vtys[conn_index], 0, sizeof(struct knet_vty)); knet_vtys[conn_index].vty_sock = vty_accept_fd; knet_vtys[conn_index].conn_num = conn_index; memmove(&knet_vtys[conn_index].src_sa, &incoming_sa, salen); knet_vtys[conn_index].src_sa_len = salen; knet_vtys[conn_index].active = 1; knet_vtys[conn_index].logfd = logfd[1]; knet_vtys[conn_index].vty_global_conf = &vty_global_conf; knet_vtys[conn_index].idle_timeout = vty_global_conf.idle_timeout; if (debug) { knet_vtys[conn_index].loglevel = KNET_LOG_DEBUG; } else { knet_vtys[conn_index].loglevel = KNET_LOG_INFO; } err = pthread_create(&knet_vtys[conn_index].vty_thread, NULL, vty_accept_thread, (void *)&conn_index); if (err < 0) { log_error("Unable to spawn vty thread"); memset(&knet_vtys[conn_index], 0, sizeof(struct knet_vty)); vty_current_connections--; } pthread_mutex_unlock(&knet_vty_mutex); } out: pthread_cancel(logging_thread); knet_vty_close_listener(vty_listener6_fd); knet_vty_close_listener(vty_listener4_fd); close(logfd[0]); close(logfd[1]); return err; } /* int knet_vty_set_max_connections(const int max_connections) { int err = 0; pthread_mutex_lock(&knet_vty_mutex); if ((max_connections > KNET_VTY_TOTAL_MAX_CONN) || (max_connections < 1)) { errno = EINVAL; err = -1; } else { vty_max_connections = max_connections; } pthread_mutex_unlock(&knet_vty_mutex); return err; } */ diff --git a/kronosnetd/vty.h b/kronosnetd/vty.h index 73608897..f91be4d0 100644 --- a/kronosnetd/vty.h +++ b/kronosnetd/vty.h @@ -1,74 +1,74 @@ /* - * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNETD_VTY_H__ #define __KNETD_VTY_H__ #include <pthread.h> #include <sys/types.h> #include <sys/socket.h> #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 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_auth.c b/kronosnetd/vty_auth.c index 250ffb22..4ee793fb 100644 --- a/kronosnetd/vty_auth.c +++ b/kronosnetd/vty_auth.c @@ -1,305 +1,305 @@ /* - * Copyright (C) 2012-2015 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 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 <stdio.h> #include <stdarg.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <grp.h> #include <security/pam_appl.h> #include <security/pam_misc.h> #include "logging.h" #include "vty_auth.h" #include "vty_utils.h" static int knet_pam_misc_conv(int num_msg, const struct pam_message **msgm, struct pam_response **response, void *appdata_ptr) { int count = 0; struct pam_response *reply; struct knet_vty *vty = (struct knet_vty *)appdata_ptr; if (num_msg <= 0) return PAM_CONV_ERR; reply = (struct pam_response *) calloc(num_msg, sizeof(struct pam_response)); if (reply == NULL) return PAM_CONV_ERR; for (count=0; count < num_msg; ++count) { unsigned char readbuf[VTY_MAX_BUFFER_SIZE]; char *string=NULL; int nc; memset(readbuf, 0, sizeof(readbuf)); switch (msgm[count]->msg_style) { case PAM_PROMPT_ECHO_OFF: if (knet_vty_set_echo(vty, 0) < 0) { knet_vty_write(vty, "Unable to turn off terminal/telnet echo"); goto failed_conversation; } knet_vty_write(vty, "%s", msgm[count]->msg); nc = knet_vty_read(vty, readbuf, sizeof(readbuf)); if (nc < 0) goto failed_conversation; if (knet_vty_set_echo(vty, 1) < 0) { /* doesn't really make a lot of sense tho.... */ knet_vty_write(vty, "Unable to turn on terminal/telnet echo"); goto failed_conversation; } knet_vty_write(vty, "\n"); readbuf[nc-2] = 0; string = strdup((const char*)readbuf); if (!string) goto failed_conversation; break; case PAM_PROMPT_ECHO_ON: knet_vty_write(vty, "\n%s", msgm[count]->msg); nc = knet_vty_read(vty, readbuf, sizeof(readbuf)); if (nc < 0) goto failed_conversation; readbuf[nc-2] = 0; string = strdup((const char*)readbuf); if (!string) goto failed_conversation; break; case PAM_ERROR_MSG: log_error("Received PAM error message %s", msgm[count]->msg); knet_vty_write(vty, "%s", msgm[count]->msg); break; case PAM_TEXT_INFO: log_error("Received PAM text info: %s", msgm[count]->msg); knet_vty_write(vty, "%s", msgm[count]->msg); break; default: if (!vty->got_epipe) { log_error("Unknown PAM conversation message"); knet_vty_write(vty, "Unknown PAM conversation message"); } goto failed_conversation; } if (string) { reply[count].resp_retcode = 0; reply[count].resp = string; string = NULL; } } *response = reply; reply = NULL; return PAM_SUCCESS; failed_conversation: if (!vty->got_epipe) { log_error("PAM conversation error"); knet_vty_write(vty, "PAM conversation error"); } if (reply) { for (count=0; count < num_msg; ++count) { if (reply[count].resp == NULL) continue; switch (msgm[count]->msg_style) { case PAM_PROMPT_ECHO_ON: case PAM_PROMPT_ECHO_OFF: _pam_overwrite(reply[count].resp); free(reply[count].resp); break; case PAM_BINARY_PROMPT: { void *bt_ptr = reply[count].resp; pam_binary_handler_free(appdata_ptr, bt_ptr); break; } case PAM_ERROR_MSG: case PAM_TEXT_INFO: free(reply[count].resp); } } free(reply); reply = NULL; } return PAM_CONV_ERR; } static int knet_vty_get_pam_user(struct knet_vty *vty, pam_handle_t *pamh) { const void *value; int err; memset(vty->username, 0, sizeof(vty->username)); err = pam_get_item(pamh, PAM_USER, &value); if (err != PAM_SUCCESS) return err; strncpy(vty->username, (const char*)value, 32); return 0; } static int knet_vty_pam_auth_user(struct knet_vty *vty, const char *user) { pam_handle_t *pamh=NULL; struct pam_conv conv; int err; int retry = 1; conv.conv = knet_pam_misc_conv; conv.appdata_ptr = (void *)vty; retry_auth: err = pam_start("kronosnetd", user, &conv, &pamh); if (err != PAM_SUCCESS) { errno = EINVAL; log_error("PAM fatal error: %s", pam_strerror(pamh, err)); knet_vty_write(vty, "PAM fatal error: %s", pam_strerror(pamh, err)); goto out_fatal; } if (pam_set_item(pamh, PAM_USER_PROMPT, (const void *)"login: ") != PAM_SUCCESS) { log_error("PAM fatal error: %s", pam_strerror(pamh, err)); knet_vty_write(vty, "PAM fatal error: %s", pam_strerror(pamh, err)); goto out_fatal; } err = pam_authenticate(pamh, 0); if (err != PAM_SUCCESS) { if (vty->got_epipe) { errno = EPIPE; goto out_fatal; } else { errno = EINVAL; goto out_clean; } } if (knet_vty_get_pam_user(vty, pamh) != PAM_SUCCESS) { log_error("PAM: unable to get PAM_USER: %s", pam_strerror(pamh, err)); knet_vty_write(vty, "PAM: unable to get PAM_USER: %s", pam_strerror(pamh, err)); goto out_clean; } err = pam_acct_mgmt(pamh, 0); if (err != PAM_SUCCESS) { log_info("User: %s failed to authenticate on vty(%d) attempt %d", vty->username, vty->conn_num, retry); goto out_clean; } out_clean: if (pamh) { pam_end(pamh, err); pamh = NULL; } if ((err != PAM_SUCCESS) && (retry < AUTH_MAX_RETRY)) { retry++; goto retry_auth; } out_fatal: if (pamh) { pam_end(pamh, err); pamh = NULL; } knet_vty_write(vty, "\n"); return err; } static int knet_vty_group_check(struct knet_vty *vty) { struct group grp; char *buf; size_t buflen; long int initlen; struct group *result; char *gr_mem; int err, i; errno = 0; initlen = sysconf(_SC_GETGR_R_SIZE_MAX); if ((initlen < 0) && (errno == EINVAL)) return -1; if (initlen < 0) initlen = 1024; buflen = (size_t) initlen; buf = malloc(buflen); if (!buf) return -1; while ((err = getgrnam_r(DEFAULTADMGROUP, &grp, buf, buflen, &result)) == ERANGE) { size_t newlen = 2 * buflen; char *newbuf; newbuf = realloc(buf, newlen); if (!newbuf) { err = -1; goto out_clean; } buf = newbuf; } if (err) goto out_clean; if (result == NULL) { errno = EACCES; log_error("No " DEFAULTADMGROUP " group found on the system"); knet_vty_write(vty, "No " DEFAULTADMGROUP " group found on the system\n"); err = -1; goto out_clean; } gr_mem = *grp.gr_mem; i = 0; while(gr_mem != NULL) { if (!strcmp(vty->username, gr_mem)) { vty->user_can_enable = 1; break; } gr_mem = *(grp.gr_mem + i); i++; } out_clean: free(buf); return err; } int knet_vty_auth_user(struct knet_vty *vty, const char *user) { int err; err = knet_vty_pam_auth_user(vty, user); if (err != PAM_SUCCESS) return -1; return knet_vty_group_check(vty); } diff --git a/kronosnetd/vty_auth.h b/kronosnetd/vty_auth.h index ef787224..2274f76d 100644 --- a/kronosnetd/vty_auth.h +++ b/kronosnetd/vty_auth.h @@ -1,18 +1,18 @@ /* - * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 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 __KNETD_VTY_AUTH_H__ #define __KNETD_VTY_AUTH_H__ #include "vty.h" #define AUTH_MAX_RETRY 3 int knet_vty_auth_user(struct knet_vty *vty, const char *user); #endif diff --git a/kronosnetd/vty_cli.c b/kronosnetd/vty_cli.c index 8bac0667..09e4a2d7 100644 --- a/kronosnetd/vty_cli.c +++ b/kronosnetd/vty_cli.c @@ -1,531 +1,531 @@ /* - * Copyright (C) 2012-2015 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <sys/select.h> #include <unistd.h> #include <stdlib.h> #include "logging.h" #include "vty.h" #include "vty_cli.h" #include "vty_cli_cmds.h" #include "vty_utils.h" /* 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 0895b28d..73bcd50c 100644 --- a/kronosnetd/vty_cli.h +++ b/kronosnetd/vty_cli.h @@ -1,20 +1,20 @@ /* - * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 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 __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 7dcdc689..6f6a9279 100644 --- a/kronosnetd/vty_cli_cmds.c +++ b/kronosnetd/vty_cli_cmds.c @@ -1,2188 +1,2188 @@ /* - * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include "cfg.h" #include "etherfilter.h" #include "logging.h" #include "libtap.h" #include "netutils.h" #include "vty.h" #include "vty_cli.h" #include "vty_cli_cmds.h" #include "vty_utils.h" #define KNET_VTY_MAX_MATCHES 64 #define KNET_VTY_MATCH_HELP 0 #define KNET_VTY_MATCH_EXEC 1 #define KNET_VTY_MATCH_EXPAND 2 #define CMDS_PARAM_NOMORE 0 #define CMDS_PARAM_KNET 1 #define CMDS_PARAM_IP 2 #define CMDS_PARAM_IP_PREFIX 3 #define CMDS_PARAM_IP_PORT 4 #define CMDS_PARAM_BOOL 5 #define CMDS_PARAM_INT 6 #define CMDS_PARAM_NODEID 7 #define CMDS_PARAM_NAME 8 #define CMDS_PARAM_MTU 9 #define CMDS_PARAM_CRYPTO_MODEL 10 #define CMDS_PARAM_CRYPTO_TYPE 11 #define CMDS_PARAM_HASH_TYPE 12 #define CMDS_PARAM_POLICY 13 #define CMDS_PARAM_LINK_ID 14 #define CMDS_PARAM_LINK_PRI 15 #define CMDS_PARAM_LINK_KEEPAL 16 #define CMDS_PARAM_LINK_HOLDTI 17 #define CMDS_PARAM_LINK_PONG 18 #define CMDS_PARAM_VTY_TIMEOUT 19 #define CMDS_PARAM_PMTU_FREQ 20 #define CMDS_PARAM_LINK_TRANSP 21 /* * CLI helper functions - menu/node stuff starts below */ /* * return 0 if we find a command in vty->line and cmd/len/no are set * return -1 if we cannot find a command. no can be trusted. cmd/len would be empty */ static int get_command(struct knet_vty *vty, char **cmd, int *cmdlen, int *cmdoffset, int *no) { int start = 0, idx; for (idx = 0; idx < vty->line_idx; idx++) { if (vty->line[idx] != ' ') break; } if (!strncmp(&vty->line[idx], "no ", 3)) { *no = 1; idx = idx + 3; for (; idx < vty->line_idx; idx++) { if (vty->line[idx] != ' ') break; } } else { *no = 0; } start = idx; if (start == vty->line_idx) return -1; *cmd = &vty->line[start]; *cmdoffset = start; for (idx = start; idx < vty->line_idx; idx++) { if (vty->line[idx] == ' ') break; } *cmdlen = idx - start; return 0; } /* * still not sure why I need to count backwards... */ static void get_n_word_from_end(struct knet_vty *vty, int n, char **word, int *wlen, int *woffset) { int widx; int idx, end, start; start = end = vty->line_idx; for (widx = 0; widx < n; widx++) { for (idx = start - 1; idx > 0; idx--) { if (vty->line[idx] != ' ') break; } end = idx; for (idx = end; idx > 0; idx--) { if (vty->line[idx-1] == ' ') break; } start = idx; } *wlen = (end - start) + 1; *word = &vty->line[start]; *woffset = start; } static int expected_params(const vty_param_t *params) { int idx = 0; while(params[idx].param != CMDS_PARAM_NOMORE) idx++; return idx; } static int count_words(struct knet_vty *vty, int offset) { int idx, widx = 0; int status = 0; for (idx = offset; idx < vty->line_idx; idx++) { if (vty->line[idx] == ' ') { status = 0; continue; } if ((vty->line[idx] != ' ') && (!status)) { widx++; status = 1; continue; } } return widx; } static int param_to_int(const char *param, int paramlen) { char buf[KNET_VTY_MAX_LINE]; memset(buf, 0, sizeof(buf)); memmove(buf, param, paramlen); return atoi(buf); } static int param_to_str(char *buf, int bufsize, const char *param, int paramlen) { if (bufsize < paramlen) return -1; memset(buf, 0, bufsize); memmove(buf, param, paramlen); return paramlen; } static const vty_node_cmds_t *get_cmds(struct knet_vty *vty, char **cmd, int *cmdlen, int *cmdoffset) { int no; const vty_node_cmds_t *cmds = knet_vty_nodes[vty->node].cmds; get_command(vty, cmd, cmdlen, cmdoffset, &no); if (no) cmds = knet_vty_nodes[vty->node].no_cmds; return cmds; } static int check_param(struct knet_vty *vty, const int paramtype, char *param, int paramlen) { int err = 0; char buf[KNET_VTY_MAX_LINE]; int tmp; struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; memset(buf, 0, sizeof(buf)); switch(paramtype) { case CMDS_PARAM_NOMORE: break; case CMDS_PARAM_KNET: if (paramlen >= IFNAMSIZ) { knet_vty_write(vty, "interface name too long%s", telnet_newline); err = -1; } break; case CMDS_PARAM_IP: break; case CMDS_PARAM_IP_PREFIX: break; case CMDS_PARAM_IP_PORT: tmp = param_to_int(param, paramlen); if ((tmp < 0) || (tmp > 65279)) { knet_vty_write(vty, "port number must be a value between 0 and 65279%s", telnet_newline); err = -1; } break; case CMDS_PARAM_BOOL: break; case CMDS_PARAM_INT: break; case CMDS_PARAM_NODEID: tmp = param_to_int(param, paramlen); if ((tmp < 0) || (tmp > 255)) { knet_vty_write(vty, "node id must be a value between 0 and 255%s", telnet_newline); err = -1; } break; case CMDS_PARAM_NAME: if (paramlen >= KNET_MAX_HOST_LEN) { knet_vty_write(vty, "name cannot exceed %d char in len%s", KNET_MAX_HOST_LEN - 1, telnet_newline); } break; case CMDS_PARAM_MTU: tmp = param_to_int(param, paramlen); if ((tmp < 576) || (tmp > 65536)) { knet_vty_write(vty, "mtu should be a value between 576 and 65536 (note: max value depends on the media)%s", telnet_newline); err = -1; } break; case CMDS_PARAM_PMTU_FREQ: tmp = param_to_int(param, paramlen); if ((tmp < 5) || (tmp > 600)) { knet_vty_write(vty, "PMTUd frequency should be a value between 5 and 600%s", telnet_newline); err = -1; } break; case CMDS_PARAM_CRYPTO_MODEL: param_to_str(buf, KNET_VTY_MAX_LINE, param, paramlen); if (!strncmp("none", buf, 4)) break; if (!strncmp("nss", buf, 3)) break; knet_vty_write(vty, "unknown encryption model: %s. Supported: none/nss%s", param, telnet_newline); err = -1; break; case CMDS_PARAM_CRYPTO_TYPE: param_to_str(buf, KNET_VTY_MAX_LINE, param, paramlen); if (!strncmp("none", buf, 4)) break; if (!strncmp("aes256", buf, 6)) break; if (!strncmp("aes192", buf, 6)) break; if (!strncmp("aes128", buf, 6)) break; if (!strncmp("3des", buf, 4)) break; knet_vty_write(vty, "unknown encryption method: %s. Supported: none/aes256/aes192/aes128/3des%s", param, telnet_newline); err = -1; break; case CMDS_PARAM_HASH_TYPE: param_to_str(buf, KNET_VTY_MAX_LINE, param, paramlen); if (!strncmp("none", buf, 4)) break; if (!strncmp("md5", buf, 3)) break; if (!strncmp("sha1", buf, 4)) break; if (!strncmp("sha256", buf, 6)) break; if (!strncmp("sha384", buf, 6)) break; if (!strncmp("sha512", buf, 6)) break; knet_vty_write(vty, "unknown hash method: %s. Supported none/md5/sha1/sha256/sha384/sha512%s", param, telnet_newline); err = -1; break; case CMDS_PARAM_POLICY: param_to_str(buf, KNET_VTY_MAX_LINE, param, paramlen); if (!strncmp("passive", buf, 7)) break; if (!strncmp("active", buf, 6)) break; if (!strncmp("round-robin", buf, 11)) break; knet_vty_write(vty, "unknown switching policy: %s. Supported passive/active/round-robin%s", param, telnet_newline); err = -1; break; case CMDS_PARAM_LINK_ID: tmp = param_to_int(param, paramlen); if ((tmp < 0) || (tmp > 7)) { knet_vty_write(vty, "link id should be a value between 0 and 7%s", telnet_newline); err = -1; } break; case CMDS_PARAM_LINK_TRANSP: param_to_str(buf, KNET_VTY_MAX_LINE, param, paramlen); if (knet_handle_get_transport_id_by_name(knet_iface->cfg_ring.knet_h, buf) == KNET_MAX_TRANSPORTS) { knet_vty_write(vty, "link transport is invalid%s", telnet_newline); err = -1; } break; case CMDS_PARAM_LINK_PRI: tmp = param_to_int(param, paramlen); if ((tmp < 0) || (tmp > 255)) { knet_vty_write(vty, "link priority should be a value between 0 and 256%s", telnet_newline); err = -1; } break; case CMDS_PARAM_LINK_KEEPAL: tmp = param_to_int(param, paramlen); if ((tmp <= 0) || (tmp > 60000)) { knet_vty_write(vty, "link keepalive should be a value between 0 and 60000 (milliseconds). Default: 1000%s", telnet_newline); err = -1; } break; case CMDS_PARAM_LINK_HOLDTI: tmp = param_to_int(param, paramlen); if ((tmp <= 0) || (tmp > 60000)) { knet_vty_write(vty, "link holdtimer should be a value between 0 and 60000 (milliseconds). Default: 5000%s", telnet_newline); err = -1; } break; case CMDS_PARAM_LINK_PONG: tmp = param_to_int(param, paramlen); if (tmp < 1) { knet_vty_write(vty, "pong_count must be a value between 0 and 255%s", telnet_newline); err = -1; } break; case CMDS_PARAM_VTY_TIMEOUT: tmp = param_to_int(param, paramlen); if ((tmp < 0) || (tmp > 3600)) { knet_vty_write(vty, "vty logout timeout should be a value between 0 (disabled) and 3600 seconds. Default: %d%s", KNET_VTY_CLI_TIMEOUT, telnet_newline); } break; default: knet_vty_write(vty, "CLI ERROR: unknown parameter type%s", telnet_newline); err = -1; break; } return err; } static void describe_param(struct knet_vty *vty, const int paramtype) { switch(paramtype) { case CMDS_PARAM_NOMORE: knet_vty_write(vty, "no more parameters%s", telnet_newline); break; case CMDS_PARAM_KNET: knet_vty_write(vty, "KNET_IFACE_NAME - interface name (max %d chars) eg: kronosnet0%s", IFNAMSIZ, telnet_newline); break; case CMDS_PARAM_IP: knet_vty_write(vty, "IP address - ipv4 or ipv6 address to add/remove%s", telnet_newline); break; case CMDS_PARAM_IP_PREFIX: knet_vty_write(vty, "IP prefix len (eg. 24, 64)%s", telnet_newline); break; case CMDS_PARAM_IP_PORT: knet_vty_write(vty, "base port (eg: %d) %s", KNET_RING_DEFPORT, telnet_newline); case CMDS_PARAM_BOOL: break; case CMDS_PARAM_INT: break; case CMDS_PARAM_NODEID: knet_vty_write(vty, "NODEID - unique identifier for this interface in this kronos network (value between 0 and 255)%s", telnet_newline); break; case CMDS_PARAM_NAME: knet_vty_write(vty, "NAME - unique name identifier for this entity (max %d chars)%s", KNET_MAX_HOST_LEN - 1, telnet_newline); break; case CMDS_PARAM_MTU: knet_vty_write(vty, "MTU - a value between 576 and 65536 (note: max value depends on the media)%s", telnet_newline); break; case CMDS_PARAM_PMTU_FREQ: knet_vty_write(vty, "PMTUd frequency - a value in seconds between 5 and 600 (default: 5)%s", telnet_newline); break; case CMDS_PARAM_CRYPTO_MODEL: knet_vty_write(vty, "MODEL - define encryption backend: none or nss%s", telnet_newline); break; case CMDS_PARAM_CRYPTO_TYPE: knet_vty_write(vty, "CRYPTO - define packets encryption method: none or aes256%s", telnet_newline); break; case CMDS_PARAM_HASH_TYPE: knet_vty_write(vty, "HASH - define packets hashing method: none/md5/sha1/sha256/sha384/sha512%s", telnet_newline); break; case CMDS_PARAM_POLICY: knet_vty_write(vty, "POLICY - define packets switching policy: passive/active/round-robin%s", telnet_newline); break; case CMDS_PARAM_LINK_ID: knet_vty_write(vty, "LINKID - specify the link identification number (0-7)%s", telnet_newline); break; case CMDS_PARAM_LINK_TRANSP: knet_vty_write(vty, "TRANSPORT - specify the link transport protocol (UDP/SCTP/..)%s", telnet_newline); break; case CMDS_PARAM_LINK_PRI: knet_vty_write(vty, "PRIORITY - specify the link priority for passive switching (0 to 255, default is 0). The higher value is preferred over lower value%s", telnet_newline); break; case CMDS_PARAM_LINK_KEEPAL: knet_vty_write(vty, "KEEPALIVE - specify the keepalive interval for this link (0 to 60000 milliseconds, default is 1000).%s", telnet_newline); break; case CMDS_PARAM_LINK_HOLDTI: knet_vty_write(vty, "HOLDTIME - specify how much time has to pass without connection before a link is considered dead (0 to 60000 milliseconds, default is 5000).%s", telnet_newline); break; case CMDS_PARAM_VTY_TIMEOUT: knet_vty_write(vty, "VTY_TIMEOUT - specify the number of seconds before a session is automatically closed.%s", telnet_newline); break; default: /* this should never happen */ knet_vty_write(vty, "CLI ERROR: unknown parameter type%s", telnet_newline); break; } } static void print_help(struct knet_vty *vty, const vty_node_cmds_t *cmds, int idx) { if ((idx < 0) || (cmds == NULL) || (cmds[idx].cmd == NULL)) return; if (cmds[idx].help != NULL) { knet_vty_write(vty, "%s\t%s%s", cmds[idx].cmd, cmds[idx].help, telnet_newline); } else { knet_vty_write(vty, "%s\tNo help available for this command%s", cmds[idx].cmd, telnet_newline); } } static int get_param(struct knet_vty *vty, int wanted_paranum, char **param, int *paramlen, int *paramoffset) { int eparams, tparams; const vty_param_t *params = (const vty_param_t *)vty->param; int paramstart = vty->paramoffset; eparams = expected_params(params); tparams = count_words(vty, paramstart); if (tparams > eparams) return -1; if (wanted_paranum == -1) { get_n_word_from_end(vty, 1, param, paramlen, paramoffset); return tparams; } if (tparams < wanted_paranum) return -1; get_n_word_from_end(vty, (tparams - wanted_paranum) + 1, param, paramlen, paramoffset); return tparams - wanted_paranum; } static int match_command(struct knet_vty *vty, const vty_node_cmds_t *cmds, char *cmd, int cmdlen, int cmdoffset, int mode) { int idx = 0, found = -1, paramoffset = 0, paramlen = 0, last_param = 0; char *param = NULL; int paramstart = cmdlen + cmdoffset; int matches[KNET_VTY_MAX_MATCHES]; memset(&matches, -1, sizeof(matches)); while ((cmds[idx].cmd != NULL) && (idx < KNET_VTY_MAX_MATCHES)) { if (!strncmp(cmds[idx].cmd, cmd, cmdlen)) { found++; matches[found] = idx; } idx++; } if (idx >= KNET_VTY_MAX_MATCHES) { knet_vty_write(vty, "Too many matches for this command%s", telnet_newline); return -1; } if (found < 0) { knet_vty_write(vty, "There is no such command%s", telnet_newline); return -1; } switch(mode) { case KNET_VTY_MATCH_HELP: if (found == 0) { if ((cmdoffset <= vty->cursor_pos) && (vty->cursor_pos <= paramstart)) { print_help(vty, cmds, matches[0]); break; } if (cmds[matches[0]].params != NULL) { vty->param = (void *)cmds[matches[0]].params; vty->paramoffset = paramstart; last_param = get_param(vty, -1, ¶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); 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) { 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, ¶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) { knet_vty_write(vty, "Error: Unable to set ip addr %s/%s on device %s%s", ipaddr, prefix, tap_get_name(knet_iface->cfg_eth.tap), telnet_newline); if (error_string) { knet_vty_write(vty, "(%s)%s", error_string, telnet_newline); free(error_string); } return -1; } return 0; } static void knet_cmd_auto_mtu_notify(void *private_data, unsigned int data_mtu) { struct knet_cfg *knet_iface = (struct knet_cfg *)private_data; /* * 48 is the magic number! yes it is.. it's the magic number... */ knet_iface->cfg_ring.data_mtu = data_mtu - 48; if (!knet_iface->cfg_eth.auto_mtu) { int mtu = 0; mtu = tap_get_mtu(knet_iface->cfg_eth.tap); if (mtu < 0) { log_debug("Unable to get current MTU?"); } else { if (data_mtu < (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) { log_warn("Error: Unable to set requested mtu %d on device %s via mtu notify", knet_iface->cfg_ring.data_mtu, tap_get_name(knet_iface->cfg_eth.tap)); } else { log_info("Device %s new mtu: %d (via mtu notify)", tap_get_name(knet_iface->cfg_eth.tap), knet_iface->cfg_ring.data_mtu); } } static int knet_cmd_no_pmtufreq(struct knet_vty *vty) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; if (knet_handle_pmtud_setfreq(knet_iface->cfg_ring.knet_h, 5) < 0) { knet_vty_write(vty, "Error: Unable to reset PMTUd frequency to 5 seconds on device %s%s", tap_get_name(knet_iface->cfg_eth.tap), telnet_newline); return -1; } return 0; } static int knet_cmd_pmtufreq(struct knet_vty *vty) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; int paramlen = 0, paramoffset = 0, pmtufreq = 5; char *param = NULL; get_param(vty, 1, ¶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); return -1; } return 0; } static int knet_cmd_no_mtu(struct knet_vty *vty) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; /* allow automatic updates of mtu */ knet_iface->cfg_eth.auto_mtu = 1; if (knet_iface->cfg_ring.data_mtu > 0) { if (tap_set_mtu(knet_iface->cfg_eth.tap, knet_iface->cfg_ring.data_mtu) < 0) { knet_iface->cfg_eth.auto_mtu = 0; knet_vty_write(vty, "Error: Unable to set auto detected mtu on device %s%s", tap_get_name(knet_iface->cfg_eth.tap), telnet_newline); return -1; } } else { if (tap_reset_mtu(knet_iface->cfg_eth.tap) < 0) { knet_iface->cfg_eth.auto_mtu = 0; knet_vty_write(vty, "Error: Unable to reset mtu on device %s%s", tap_get_name(knet_iface->cfg_eth.tap), telnet_newline); return -1; } } return 0; } static int knet_cmd_mtu(struct knet_vty *vty) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; int paramlen = 0, paramoffset = 0, expected_mtu = 0; char *param = NULL; get_param(vty, 1, ¶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) { knet_iface->cfg_eth.auto_mtu = 1; knet_vty_write(vty, "Error: Unable to set requested mtu %d on device %s%s", expected_mtu, tap_get_name(knet_iface->cfg_eth.tap), telnet_newline); return -1; } return 0; } static int knet_cmd_stop(struct knet_vty *vty) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; char *error_down = NULL, *error_postdown = NULL; int err = 0; err = tap_set_down(knet_iface->cfg_eth.tap, &error_down, &error_postdown); if (err < 0) { knet_vty_write(vty, "Error: Unable to set interface %s down!%s", tap_get_name(knet_iface->cfg_eth.tap), telnet_newline); } else { if (knet_iface->cfg_ring.knet_h) knet_handle_setfwd(knet_iface->cfg_ring.knet_h, 0); knet_iface->active = 0; } if (error_down) { knet_vty_write(vty, "down script output:%s(%s)%s", telnet_newline, error_down, telnet_newline); free(error_down); } if (error_postdown) { knet_vty_write(vty, "post-down script output:%s(%s)%s", telnet_newline, error_postdown, telnet_newline); free(error_postdown); } return err; } static int knet_cmd_crypto(struct knet_vty *vty) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; int paramlen = 0, paramoffset = 0; char *param = NULL; int err = 0; struct knet_handle_crypto_cfg knet_handle_crypto_cfg_new; int fd = -1; char keyfile[PATH_MAX]; struct stat sb; if (knet_iface->active) { knet_vty_write(vty, "Error: Unable to activate encryption while interface is active%s", telnet_newline); return -1; } memset(&knet_handle_crypto_cfg_new, 0, sizeof(struct knet_handle_crypto_cfg)); get_param(vty, 1, ¶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)); 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_vty_write(vty, "Error: Unable to read key %s%s", keyfile, telnet_newline); goto key_error; } close(fd); no_key: err = knet_handle_crypto(knet_iface->cfg_ring.knet_h, &knet_handle_crypto_cfg_new); if (!err) { memmove(&knet_iface->knet_handle_crypto_cfg, &knet_handle_crypto_cfg_new, sizeof(struct knet_handle_crypto_cfg)); } else { knet_vty_write(vty, "Error: Unable to initialize crypto module%s", telnet_newline); } return err; key_error: close(fd); return -1; } static int knet_cmd_start(struct knet_vty *vty) { struct knet_cfg *knet_iface = (struct knet_cfg *)vty->iface; char *error_preup = NULL, *error_up = NULL; int err = 0; err = tap_set_up(knet_iface->cfg_eth.tap, &error_preup, &error_up); if (err < 0) { knet_vty_write(vty, "Error: Unable to set interface %s up!%s", tap_get_name(knet_iface->cfg_eth.tap), telnet_newline); knet_handle_setfwd(knet_iface->cfg_ring.knet_h, 0); } else { knet_handle_setfwd(knet_iface->cfg_ring.knet_h, 1); knet_iface->active = 1; } if (error_preup) { knet_vty_write(vty, "pre-up script output:%s(%s)%s", telnet_newline, error_preup, telnet_newline); free(error_preup); } if (error_up) { knet_vty_write(vty, "up script output:%s(%s)%s", telnet_newline, error_up, telnet_newline); free(error_up); } return err; } static int knet_cmd_no_interface(struct knet_vty *vty) { int err = 0, paramlen = 0, paramoffset = 0; char *param = NULL; char device[IFNAMSIZ]; struct knet_cfg *knet_iface = NULL; char *ip_list = NULL; int ip_list_entries = 0, 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) knet_destroy_iface(knet_iface); return err; } static void sock_notify_fn(void *private_data, int datafd, int8_t chan, uint8_t tx_rx, int error, int errorno) { struct knet_vty *vty = (struct knet_vty *)private_data; knet_vty_write(vty, "Error: received sock notify, datafd: %d channel: %d direction: %u error: %d errno: %d (%s)%s", datafd, chan, tx_rx, error, errorno, strerror(errorno), telnet_newline); } static int knet_cmd_interface(struct knet_vty *vty) { int err = 0, paramlen = 0, paramoffset = 0, found = 0, requested_id, tapfd; uint16_t baseport; uint8_t *bport = (uint8_t *)&baseport; char *param = NULL; char device[IFNAMSIZ]; char mac[18]; struct knet_cfg *knet_iface = NULL; int8_t channel = 0; get_param(vty, 1, ¶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) { found = 1; goto tap_found; } if (!knet_iface->cfg_eth.tap) knet_iface->cfg_eth.tap = tap_open(device, IFNAMSIZ, DEFAULT_CONFIG_DIR); if ((!knet_iface->cfg_eth.tap) && (errno == EBUSY)) { knet_vty_write(vty, "Error: interface %s seems to exist in the system%s", device, telnet_newline); err = -1; goto out_clean; } if (!knet_iface->cfg_eth.tap) { knet_vty_write(vty, "Error: Unable to create %s system tap device%s", device, telnet_newline); err = -1; goto out_clean; } tap_found: if (knet_iface->cfg_ring.knet_h) goto knet_found; knet_iface->cfg_ring.base_port = baseport; tapfd = tap_get_fd(knet_iface->cfg_eth.tap); knet_iface->cfg_ring.knet_h = knet_handle_new(requested_id, vty->logfd, vty->loglevel); if (!knet_iface->cfg_ring.knet_h) { knet_vty_write(vty, "Error: Unable to create ring handle for device %s%s", device, telnet_newline); err = -1; goto out_clean; } if (knet_handle_enable_sock_notify(knet_iface->cfg_ring.knet_h, &vty, sock_notify_fn)) { knet_vty_write(vty, "Error: Unable to add sock notify callback to to knet_handle %s%s", strerror(errno), telnet_newline); err = -1; goto out_clean; } if (knet_handle_add_datafd(knet_iface->cfg_ring.knet_h, &tapfd, &channel) < 0) { knet_vty_write(vty, "Error: Unable to add tapfd to knet_handle %s%s", strerror(errno), telnet_newline); err = -1; goto out_clean; } knet_handle_enable_filter(knet_iface->cfg_ring.knet_h, NULL, ether_host_filter_fn); if (knet_handle_enable_pmtud_notify(knet_iface->cfg_ring.knet_h, knet_iface, knet_cmd_auto_mtu_notify) < 0) { knet_vty_write(vty, "Error: Unable to configure auto mtu notification for device %s%s", device, telnet_newline); err = -1; goto out_clean; } knet_iface->cfg_eth.auto_mtu = 1; /* * make this configurable */ knet_handle_pmtud_setfreq(knet_iface->cfg_ring.knet_h, 5); knet_found: if (found) { if (requested_id == knet_iface->cfg_eth.node_id) goto out_found; knet_vty_write(vty, "Error: no interface %s with nodeid %d found%s", device, requested_id, telnet_newline); goto out_clean; } else { knet_iface->cfg_eth.node_id = requested_id; } baseport = htons(baseport); memset(&mac, 0, sizeof(mac)); snprintf(mac, sizeof(mac) - 1, "54:54:%x:%x:0:%x", bport[0], bport[1], knet_iface->cfg_eth.node_id); if (tap_set_mac(knet_iface->cfg_eth.tap, mac) < 0) { knet_vty_write(vty, "Error: Unable to set mac address %s on device %s%s", mac, device, telnet_newline); err = -1; goto out_clean; } out_found: vty->node = NODE_INTERFACE; vty->iface = (void *)knet_iface; out_clean: if (err) { if (knet_iface->cfg_ring.knet_h) knet_handle_free(knet_iface->cfg_ring.knet_h); if (knet_iface->cfg_eth.tap) tap_close(knet_iface->cfg_eth.tap); knet_destroy_iface(knet_iface); } return err; } static int knet_cmd_exit_node(struct knet_vty *vty) { knet_vty_exit_node(vty); return 0; } static int knet_cmd_status(struct knet_vty *vty) { 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_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); 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; 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_iface->cfg_eth.node_id, knet_iface->cfg_ring.base_port, nl); if (!knet_iface->cfg_eth.auto_mtu) knet_vty_write(vty, " mtu %d%s", tap_get_mtu(knet_iface->cfg_eth.tap), nl); knet_handle_pmtud_getfreq(knet_iface->cfg_ring.knet_h, &pmtudfreq); if ((pmtudfreq > 0) && (pmtudfreq != 5)) knet_vty_write(vty, " pmtudfreq %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; } 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); 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)); 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/kronosnetd/vty_cli_cmds.h b/kronosnetd/vty_cli_cmds.h index 79615f5d..c03f7411 100644 --- a/kronosnetd/vty_cli_cmds.h +++ b/kronosnetd/vty_cli_cmds.h @@ -1,50 +1,50 @@ /* - * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 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 __KNETD_VTY_CLI_CMDS_H__ #define __KNETD_VTY_CLI_CMDS_H__ #include "vty.h" typedef struct { const int param; } vty_param_t; typedef struct { const char *cmd; const char *help; const vty_param_t *params; int (*func) (struct knet_vty *vty); } vty_node_cmds_t; typedef struct { const int node_num; const char *prompt; const vty_node_cmds_t *cmds; const vty_node_cmds_t *no_cmds; } vty_nodes_t; enum vty_nodes { NODE_ROOT = 0, NODE_CONFIG, NODE_INTERFACE, NODE_PEER, NODE_LINK, NODE_VTY }; int knet_vty_execute_cmd(struct knet_vty *vty); void knet_vty_help(struct knet_vty *vty); void knet_vty_tab_completion(struct knet_vty *vty); int knet_read_conf(void); void knet_close_down(void); extern vty_nodes_t knet_vty_nodes[]; #endif diff --git a/kronosnetd/vty_utils.c b/kronosnetd/vty_utils.c index 77f3dc48..fb7d2454 100644 --- a/kronosnetd/vty_utils.c +++ b/kronosnetd/vty_utils.c @@ -1,269 +1,269 @@ /* - * Copyright (C) 2012-2015 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 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 <stdarg.h> #include <arpa/telnet.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include "logging.h" #include "vty_cli.h" #include "vty_cli_cmds.h" #include "vty_utils.h" static int check_vty(struct knet_vty *vty) { if (!vty) { errno = EINVAL; return -1; } if (vty->got_epipe) { errno = EPIPE; return -1; } return 0; } /* * TODO: implement loopy_write here * should sock be non-blocking? */ static int knet_vty_loopy_write(struct knet_vty *vty, const char *buf, size_t bufsize) { ssize_t writelen; writelen = write(vty->vty_sock, buf, bufsize); if (writelen < 0) vty->got_epipe = 1; return writelen; } int knet_vty_write(struct knet_vty *vty, const char *format, ...) { va_list args; int len = 0; char buf[VTY_MAX_BUFFER_SIZE]; if (check_vty(vty)) return -1; va_start (args, format); len = vsnprintf (buf, VTY_MAX_BUFFER_SIZE, format, args); va_end (args); if ((len < 0) || (len > VTY_MAX_BUFFER_SIZE)) return -1; return knet_vty_loopy_write(vty, buf, len); } static int knet_vty_read_real(struct knet_vty *vty, unsigned char *buf, size_t bufsize, int ignore_iac) { ssize_t readlen; iac_retry: readlen = recv(vty->vty_sock, buf, bufsize, 0); if (readlen == 0) { vty->got_epipe = 1; goto out_clean; } if (readlen < 0) goto out_clean; vty->idle = 0; /* at somepoint we have to add IAC parsing */ if ((buf[0] == IAC) && (ignore_iac)) goto iac_retry; out_clean: return readlen; } int knet_vty_read(struct knet_vty *vty, unsigned char *buf, size_t bufsize) { if (check_vty(vty)) return -1; if ((!buf) || (bufsize == 0)) { errno = EINVAL; return -1; } return knet_vty_read_real(vty, buf, bufsize, 1); } static int knet_vty_set_echooff(struct knet_vty *vty) { unsigned char cmdreply[VTY_MAX_BUFFER_SIZE]; unsigned char cmdechooff[] = { IAC, WILL, TELOPT_ECHO, '\0' }; unsigned char cmdechooffreply[] = { IAC, DO, TELOPT_ECHO, '\0' }; ssize_t readlen; if (knet_vty_write(vty, "%s", cmdechooff) < 0) return -1; readlen = knet_vty_read_real(vty, cmdreply, VTY_MAX_BUFFER_SIZE, 0); if (readlen < 0) return readlen; if (memcmp(&cmdreply, &cmdechooffreply, readlen)) return -1; return 0; } static int knet_vty_set_echoon(struct knet_vty *vty) { unsigned char cmdreply[VTY_MAX_BUFFER_SIZE]; unsigned char cmdechoon[] = { IAC, WONT, TELOPT_ECHO, '\0' }; unsigned char cmdechoonreply[] = { IAC, DONT, TELOPT_ECHO, '\0' }; ssize_t readlen; if (knet_vty_write(vty, "%s", cmdechoon) < 0) return -1; readlen = knet_vty_read_real(vty, cmdreply, VTY_MAX_BUFFER_SIZE, 0); if (readlen < 0) return readlen; if (memcmp(&cmdreply, &cmdechoonreply, readlen)) return -1; return 0; } int knet_vty_set_echo(struct knet_vty *vty, int on) { if (check_vty(vty)) return -1; if (on) return knet_vty_set_echoon(vty); return knet_vty_set_echooff(vty); } void knet_vty_print_banner(struct knet_vty *vty) { if (check_vty(vty)) return; knet_vty_write(vty, "Welcome to " PACKAGE "d " PACKAGE_VERSION " (built " __DATE__ " " __TIME__ ")\n"); } int knet_vty_set_iacs(struct knet_vty *vty) { unsigned char cmdreply[VTY_MAX_BUFFER_SIZE]; unsigned char cmdsga[] = { IAC, WILL, TELOPT_SGA, '\0' }; unsigned char cmdsgareply[] = { IAC, DO, TELOPT_SGA, '\0' }; unsigned char cmdlm[] = { IAC, DONT, TELOPT_LINEMODE, '\0' }; ssize_t readlen; if (check_vty(vty)) return -1; if (knet_vty_set_echo(vty, 0) < 0) return -1; if (knet_vty_write(vty, "%s", cmdsga) < 0) return -1; readlen = knet_vty_read_real(vty, cmdreply, VTY_MAX_BUFFER_SIZE, 0); if (readlen < 0) return readlen; if (memcmp(&cmdreply, &cmdsgareply, readlen)) return -1; if (knet_vty_write(vty, "%s", cmdlm) < 0) return -1; return 0; } void knet_vty_free_history(struct knet_vty *vty) { int i; if (check_vty(vty)) return; for (i = 0; i < KNET_VTY_MAX_HIST; i++) { if (vty->history[i]) { free(vty->history[i]); vty->history[i] = NULL; } } } void knet_vty_exit_node(struct knet_vty *vty) { switch(vty->node) { case NODE_VTY: vty->node = vty->prevnode; break; case NODE_LINK: vty->node = NODE_PEER; break; case NODE_PEER: vty->node = NODE_INTERFACE; break; case NODE_INTERFACE: vty->node = NODE_CONFIG; break; case NODE_CONFIG: pthread_mutex_lock(&knet_vty_mutex); knet_vty_config = -1; pthread_mutex_unlock(&knet_vty_mutex); vty->node = NODE_ROOT; break; case NODE_ROOT: vty->got_epipe = 1; break; default: knet_vty_write(vty, "No idea where to go..%s", telnet_newline); break; } } int knet_vty_is_line_empty(struct knet_vty *vty) { int idx; for (idx = 0; idx < vty->line_idx; idx++) { if (vty->line[idx] != ' ') return 0; } return 1; } void knet_vty_prompt(struct knet_vty *vty) { char buf[3]; if (vty->user_can_enable) { buf[0] = '#'; } else { buf[0] = '>'; } buf[1] = ' '; buf[2] = 0; knet_vty_write(vty, "%s%s", knet_vty_nodes[vty->node].prompt, buf); } diff --git a/kronosnetd/vty_utils.h b/kronosnetd/vty_utils.h index c6ff101d..326bcbc0 100644 --- a/kronosnetd/vty_utils.h +++ b/kronosnetd/vty_utils.h @@ -1,35 +1,35 @@ /* - * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 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 __KNETD_VTY_UTILS_H__ #define __KNETD_VTY_UTILS_H__ #include "vty.h" #define VTY_MAX_BUFFER_SIZE 4096 int knet_vty_write(struct knet_vty *vty, const char *format, ...) __attribute__ ((__format__ (__printf__, 2, 3))); int knet_vty_read(struct knet_vty *vty, unsigned char *buf, size_t bufsize); int knet_vty_set_echo(struct knet_vty *vty, int on); void knet_vty_print_banner(struct knet_vty *vty); int knet_vty_set_iacs(struct knet_vty *vty); void knet_vty_free_history(struct knet_vty *vty); void knet_vty_exit_node(struct knet_vty *vty); int knet_vty_is_line_empty(struct knet_vty *vty); void knet_vty_prompt(struct knet_vty *vty); #endif diff --git a/libknet/common.c b/libknet/common.c index 69e3d3f0..eefa100c 100644 --- a/libknet/common.c +++ b/libknet/common.c @@ -1,120 +1,120 @@ /* - * Copyright (C) 2011-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 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 <unistd.h> #include <fcntl.h> #include <dlfcn.h> #include <errno.h> #include <string.h> #include <sys/param.h> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> #include "logging.h" #include "common.h" int _fdset_cloexec(int fd) { int fdflags; fdflags = fcntl(fd, F_GETFD, 0); if (fdflags < 0) return -1; fdflags |= FD_CLOEXEC; if (fcntl(fd, F_SETFD, fdflags) < 0) return -1; return 0; } int _fdset_nonblock(int fd) { int fdflags; fdflags = fcntl(fd, F_GETFL, 0); if (fdflags < 0) return -1; fdflags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, fdflags) < 0) return -1; return 0; } void *open_lib(knet_handle_t knet_h, const char *libname, int extra_flags) { void *ret = NULL; char *error = NULL; char dir[MAXPATHLEN], path[MAXPATHLEN], link[MAXPATHLEN]; struct stat sb; /* * clear any pending error */ dlerror(); ret = dlopen(libname, RTLD_NOW | RTLD_GLOBAL | extra_flags); error = dlerror(); if (error != NULL) { log_err(knet_h, KNET_SUB_COMMON, "unable to dlopen %s: %s", libname, error); errno = EAGAIN; return NULL; } memset(dir, 0, sizeof(dir)); memset(link, 0, sizeof(link)); memset(path, 0, sizeof(path)); if (dlinfo(ret, RTLD_DI_ORIGIN, &dir) < 0) { /* * should we dlclose and return error? */ log_warn(knet_h, KNET_SUB_COMMON, "unable to dlinfo %s: %s", libname, error); } else { snprintf(path, sizeof(path), "%s/%s", dir, libname); log_info(knet_h, KNET_SUB_COMMON, "%s has been loaded from %s", libname, path); /* * try to resolve the library and check if it is a symlink and to where. * we can't prevent symlink attacks but at least we can log where the library * has been loaded from */ if (lstat(path, &sb) < 0) { log_debug(knet_h, KNET_SUB_COMMON, "Unable to stat %s: %s", path, strerror(errno)); goto out; } if (S_ISLNK(sb.st_mode)) { if (readlink(path, link, sizeof(link)) < 0) { log_debug(knet_h, KNET_SUB_COMMON, "Unable to readlink %s: %s", path, strerror(errno)); goto out; } /* * symlink is relative to the directory */ if (link[0] != '/') { snprintf(path, sizeof(path), "%s/%s", dir, link); log_info(knet_h, KNET_SUB_COMMON, "%s/%s is a symlink to %s", dir, libname, path); } else { log_info(knet_h, KNET_SUB_COMMON, "%s/%s is a symlink to %s", dir, libname, link); } } } out: return ret; } diff --git a/libknet/crypto_nss.c b/libknet/crypto_nss.c index 7169da01..c6a12e67 100644 --- a/libknet/crypto_nss.c +++ b/libknet/crypto_nss.c @@ -1,1147 +1,1147 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. * * Author: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <dlfcn.h> #include <stdlib.h> #ifdef BUILDCRYPTONSS #include <nss.h> #include <nspr.h> #include <pk11pub.h> #include <pkcs11.h> #include <prerror.h> #include <blapit.h> #include <hasht.h> #include <pthread.h> #include <secerr.h> #include <prinit.h> #include "common.h" #include "crypto.h" #include "crypto_nss.h" #include "logging.h" #define LIBNSS3 "libnss3.so" /* * global vars for dlopen */ static void *nss_lib; /* * symbols remapping */ /* * nss3 */ CK_MECHANISM_TYPE (*_int_PK11_GetBestWrapMechanism)(PK11SlotInfo *slot); PK11SlotInfo *(*_int_PK11_GetBestSlot)(CK_MECHANISM_TYPE type, void *wincx); int (*_int_PK11_GetBestKeyLength)(PK11SlotInfo *slot, CK_MECHANISM_TYPE type); SECStatus (*_int_PK11_DigestFinal)(PK11Context *context, unsigned char *data, unsigned int *outLen, unsigned int length); void (*_int_SECITEM_FreeItem)(SECItem *zap, PRBool freeit); SECStatus (*_int_NSS_NoDB_Init)(const char *configdir); SECStatus (*_int_NSS_Shutdown)(void); SECStatus (*_int_PK11_DigestBegin)(PK11Context *cx); SECStatus (*_int_PK11_DigestOp)(PK11Context *context, const unsigned char *in, unsigned len); void (*_int_PK11_DestroyContext)(PK11Context *context, PRBool freeit); SECStatus (*_int_PK11_Finalize)(PK11Context *context); SECStatus (*_int_PK11_CipherOp)(PK11Context *context, unsigned char *out, int *outlen, int maxout, const unsigned char *in, int inlen); PK11SymKey *(*_int_PK11_UnwrapSymKey)(PK11SymKey *key, CK_MECHANISM_TYPE wraptype, SECItem *param, SECItem *wrapppedKey, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize); void (*_int_PK11_FreeSymKey)(PK11SymKey *key); PK11Context *(*_int_PK11_CreateContextBySymKey)(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey, SECItem *param); SECStatus (*_int_PK11_GenerateRandom)(unsigned char *data, int len); SECItem *(*_int_PK11_ParamFromIV)(CK_MECHANISM_TYPE type, SECItem *iv); void (*_int_PK11_FreeSlot)(PK11SlotInfo *slot); int (*_int_PK11_GetBlockSize)(CK_MECHANISM_TYPE type, SECItem *params); PK11SymKey *(*_int_PK11_KeyGen)(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param, int keySize, void *wincx); /* * nspr4 */ PRStatus (*_int_PR_Cleanup)(void); const char * (*_int_PR_ErrorToString)(PRErrorCode code, PRLanguageCode language); PRErrorCode (*_int_PR_GetError)(void); PRBool (*_int_PR_Initialized)(void); /* * plds4 */ void (*_int_PL_ArenaFinish)(void); static void clean_nss_syms(void) { _int_PK11_GetBestWrapMechanism = NULL; _int_PK11_GetBestSlot = NULL; _int_PK11_GetBestKeyLength = NULL; _int_PK11_DigestFinal = NULL; _int_SECITEM_FreeItem = NULL; _int_NSS_NoDB_Init = NULL; _int_NSS_Shutdown = NULL; _int_PK11_DigestBegin = NULL; _int_PK11_DigestOp = NULL; _int_PK11_DestroyContext = NULL; _int_PK11_Finalize = NULL; _int_PK11_CipherOp = NULL; _int_PK11_UnwrapSymKey = NULL; _int_PK11_FreeSymKey = NULL; _int_PK11_CreateContextBySymKey = NULL; _int_PK11_GenerateRandom = NULL; _int_PK11_ParamFromIV = NULL; _int_PK11_FreeSlot = NULL; _int_PK11_GetBlockSize = NULL; _int_PK11_KeyGen = NULL; _int_PR_Cleanup = NULL; _int_PR_ErrorToString = NULL; _int_PR_Initialized = NULL; _int_PR_GetError = NULL; _int_PL_ArenaFinish = NULL; return; } static int nsscrypto_remap_symbols(knet_handle_t knet_h) { int err = 0; char *error = NULL; /* * nss3 */ _int_PK11_GetBestWrapMechanism = dlsym(nss_lib, "PK11_GetBestWrapMechanism"); if (!_int_PK11_GetBestWrapMechanism) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PK11_GetBestWrapMechanism: %s", error); err = -1; goto out; } _int_PK11_GetBestSlot = dlsym(nss_lib, "PK11_GetBestSlot"); if (!_int_PK11_GetBestSlot) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PK11_GetBestSlot: %s", error); err = -1; goto out; } _int_PK11_GetBestKeyLength = dlsym(nss_lib, "PK11_GetBestKeyLength"); if (!_int_PK11_GetBestKeyLength) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PK11_GetBestKeyLength: %s", error); err = -1; goto out; } _int_PK11_DigestFinal = dlsym(nss_lib, "PK11_DigestFinal"); if (!_int_PK11_DigestFinal) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PK11_DigestFinal: %s", error); err = -1; goto out; } _int_SECITEM_FreeItem = dlsym(nss_lib, "SECITEM_FreeItem"); if (!_int_SECITEM_FreeItem) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map SECITEM_FreeItem: %s", error); err = -1; goto out; } _int_NSS_NoDB_Init = dlsym(nss_lib, "NSS_NoDB_Init"); if (!_int_NSS_NoDB_Init) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map NSS_NoDB_Init: %s", error); err = -1; goto out; } _int_NSS_Shutdown = dlsym(nss_lib, "NSS_Shutdown"); if (!_int_NSS_Shutdown) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map NSS_Shutdown: %s", error); err = -1; goto out; } _int_PK11_DigestBegin = dlsym(nss_lib, "PK11_DigestBegin"); if (!_int_PK11_DigestBegin) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PK11_DigestBegin: %s", error); err = -1; goto out; } _int_PK11_DigestOp = dlsym(nss_lib, "PK11_DigestOp"); if (!_int_PK11_DigestOp) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PK11_DigestOp: %s", error); err = -1; goto out; } _int_PK11_DestroyContext = dlsym(nss_lib, "PK11_DestroyContext"); if (!_int_PK11_DestroyContext) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PK11_DestroyContext: %s", error); err = -1; goto out; } _int_PK11_Finalize = dlsym(nss_lib, "PK11_Finalize"); if (!_int_PK11_Finalize) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PK11_Finalize: %s", error); err = -1; goto out; } _int_PK11_CipherOp = dlsym(nss_lib, "PK11_CipherOp"); if (!_int_PK11_CipherOp) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PK11_CipherOp: %s", error); err = -1; goto out; } _int_PK11_UnwrapSymKey = dlsym(nss_lib, "PK11_UnwrapSymKey"); if (!_int_PK11_UnwrapSymKey) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PK11_UnwrapSymKey: %s", error); err = -1; goto out; } _int_PK11_FreeSymKey = dlsym(nss_lib, "PK11_FreeSymKey"); if (!_int_PK11_FreeSymKey) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PK11_FreeSymKey: %s", error); err = -1; goto out; } _int_PK11_CreateContextBySymKey = dlsym(nss_lib, "PK11_CreateContextBySymKey"); if (!_int_PK11_CreateContextBySymKey) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PK11_CreateContextBySymKey: %s", error); err = -1; goto out; } _int_PK11_GenerateRandom = dlsym(nss_lib, "PK11_GenerateRandom"); if (!_int_PK11_GenerateRandom) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PK11_GenerateRandom: %s", error); err = -1; goto out; } _int_PK11_ParamFromIV = dlsym(nss_lib, "PK11_ParamFromIV"); if (!_int_PK11_ParamFromIV) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PK11_ParamFromIV: %s", error); err = -1; goto out; } _int_PK11_FreeSlot = dlsym(nss_lib, "PK11_FreeSlot"); if (!_int_PK11_FreeSlot) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PK11_FreeSlot: %s", error); err = -1; goto out; } _int_PK11_GetBlockSize = dlsym(nss_lib, "PK11_GetBlockSize"); if (!_int_PK11_GetBlockSize) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PK11_GetBlockSize: %s", error); err = -1; goto out; } _int_PK11_KeyGen = dlsym(nss_lib, "PK11_KeyGen"); if (!_int_PK11_KeyGen) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PK11_KeyGen: %s", error); err = -1; goto out; } /* * nspr4 */ _int_PR_Cleanup = dlsym(nss_lib, "PR_Cleanup"); if (!_int_PR_Cleanup) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PR_Cleanup: %s", error); err = -1; goto out; } _int_PR_ErrorToString = dlsym(nss_lib, "PR_ErrorToString"); if (!_int_PR_ErrorToString) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PR_ErrorToString: %s", error); err = -1; goto out; } _int_PR_Initialized = dlsym(nss_lib, "PR_Initialized"); if (!_int_PR_Initialized) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map Initialized: %s", error); err = -1; goto out; } _int_PR_GetError = dlsym(nss_lib, "PR_GetError"); if (!_int_PR_GetError) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PR_GetError: %s", error); err = -1; goto out; } /* * plds4 */ _int_PL_ArenaFinish = dlsym(nss_lib, "PL_ArenaFinish"); if (!_int_PL_ArenaFinish) { error = dlerror(); log_err(knet_h, KNET_SUB_NSSCRYPTO, "unable to map PL_ArenaFinish: %s", error); err = -1; goto out; } out: if (err) { clean_nss_syms(); } return err; } static int nss_db_is_init = 0; static int at_exit_registered = 0; static void nss_atexit_handler(void) { if (nss_db_is_init) { if (_int_NSS_Shutdown) { (*_int_NSS_Shutdown)(); } if ((_int_PR_Initialized) && ((*_int_PR_Initialized)())) { if (_int_PL_ArenaFinish) { (*_int_PL_ArenaFinish)(); } if (_int_PR_Cleanup) { (*_int_PR_Cleanup)(); } } } return; } int nsscrypto_load_lib( knet_handle_t knet_h) { int err = 0, savederrno = 0; if (!nss_lib) { nss_lib = open_lib(knet_h, LIBNSS3, 0); if (!nss_lib) { savederrno = errno; err = -1; goto out; } } if (nsscrypto_remap_symbols(knet_h) < 0) { savederrno = errno; err = -1; goto out; } if (!at_exit_registered) { if (atexit(nss_atexit_handler)) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "Unable to register NSS atexit handler"); savederrno = EAGAIN; err = -1; goto out; } at_exit_registered = 1; } if ((nss_lib) && (_int_NSS_NoDB_Init) && (!nss_db_is_init)) { if ((*_int_NSS_NoDB_Init)(".") != SECSuccess) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "NSS DB initialization failed (err %d): %s", (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); savederrno = EAGAIN; err = -1; goto out; } nss_db_is_init = 1; } out: errno = savederrno; return err; } /* * crypto definitions and conversion tables */ #define SALT_SIZE 16 /* * This are defined in new NSS. For older one, we will define our own */ #ifndef AES_256_KEY_LENGTH #define AES_256_KEY_LENGTH 32 #endif #ifndef AES_192_KEY_LENGTH #define AES_192_KEY_LENGTH 24 #endif #ifndef AES_128_KEY_LENGTH #define AES_128_KEY_LENGTH 16 #endif enum nsscrypto_crypt_t { CRYPTO_CIPHER_TYPE_NONE = 0, CRYPTO_CIPHER_TYPE_AES256 = 1, CRYPTO_CIPHER_TYPE_AES192 = 2, CRYPTO_CIPHER_TYPE_AES128 = 3, CRYPTO_CIPHER_TYPE_3DES = 4 }; CK_MECHANISM_TYPE cipher_to_nss[] = { 0, /* CRYPTO_CIPHER_TYPE_NONE */ CKM_AES_CBC_PAD, /* CRYPTO_CIPHER_TYPE_AES256 */ CKM_AES_CBC_PAD, /* CRYPTO_CIPHER_TYPE_AES192 */ CKM_AES_CBC_PAD, /* CRYPTO_CIPHER_TYPE_AES128 */ CKM_DES3_CBC_PAD /* CRYPTO_CIPHER_TYPE_3DES */ }; size_t nsscipher_key_len[] = { 0, /* CRYPTO_CIPHER_TYPE_NONE */ AES_256_KEY_LENGTH, /* CRYPTO_CIPHER_TYPE_AES256 */ AES_192_KEY_LENGTH, /* CRYPTO_CIPHER_TYPE_AES192 */ AES_128_KEY_LENGTH, /* CRYPTO_CIPHER_TYPE_AES128 */ 24 /* CRYPTO_CIPHER_TYPE_3DES */ }; size_t nsscypher_block_len[] = { 0, /* CRYPTO_CIPHER_TYPE_NONE */ AES_BLOCK_SIZE, /* CRYPTO_CIPHER_TYPE_AES256 */ AES_BLOCK_SIZE, /* CRYPTO_CIPHER_TYPE_AES192 */ AES_BLOCK_SIZE, /* CRYPTO_CIPHER_TYPE_AES128 */ 0 /* CRYPTO_CIPHER_TYPE_3DES */ }; /* * hash definitions and conversion tables */ enum nsscrypto_hash_t { CRYPTO_HASH_TYPE_NONE = 0, CRYPTO_HASH_TYPE_MD5 = 1, CRYPTO_HASH_TYPE_SHA1 = 2, CRYPTO_HASH_TYPE_SHA256 = 3, CRYPTO_HASH_TYPE_SHA384 = 4, CRYPTO_HASH_TYPE_SHA512 = 5 }; CK_MECHANISM_TYPE hash_to_nss[] = { 0, /* CRYPTO_HASH_TYPE_NONE */ CKM_MD5_HMAC, /* CRYPTO_HASH_TYPE_MD5 */ CKM_SHA_1_HMAC, /* CRYPTO_HASH_TYPE_SHA1 */ CKM_SHA256_HMAC, /* CRYPTO_HASH_TYPE_SHA256 */ CKM_SHA384_HMAC, /* CRYPTO_HASH_TYPE_SHA384 */ CKM_SHA512_HMAC /* CRYPTO_HASH_TYPE_SHA512 */ }; size_t nsshash_len[] = { 0, /* CRYPTO_HASH_TYPE_NONE */ MD5_LENGTH, /* CRYPTO_HASH_TYPE_MD5 */ SHA1_LENGTH, /* CRYPTO_HASH_TYPE_SHA1 */ SHA256_LENGTH, /* CRYPTO_HASH_TYPE_SHA256 */ SHA384_LENGTH, /* CRYPTO_HASH_TYPE_SHA384 */ SHA512_LENGTH /* CRYPTO_HASH_TYPE_SHA512 */ }; enum sym_key_type { SYM_KEY_TYPE_CRYPT, SYM_KEY_TYPE_HASH }; struct nsscrypto_instance { PK11SymKey *nss_sym_key; PK11SymKey *nss_sym_key_sign; unsigned char *private_key; unsigned int private_key_len; int crypto_cipher_type; int crypto_hash_type; }; /* * crypt/decrypt functions */ static int nssstring_to_crypto_cipher_type(const char* crypto_cipher_type) { if (strcmp(crypto_cipher_type, "none") == 0) { return CRYPTO_CIPHER_TYPE_NONE; } else if (strcmp(crypto_cipher_type, "aes256") == 0) { return CRYPTO_CIPHER_TYPE_AES256; } else if (strcmp(crypto_cipher_type, "aes192") == 0) { return CRYPTO_CIPHER_TYPE_AES192; } else if (strcmp(crypto_cipher_type, "aes128") == 0) { return CRYPTO_CIPHER_TYPE_AES128; } else if (strcmp(crypto_cipher_type, "3des") == 0) { return CRYPTO_CIPHER_TYPE_3DES; } return -1; } static PK11SymKey *nssimport_symmetric_key(knet_handle_t knet_h, enum sym_key_type key_type) { struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance; SECItem key_item; PK11SlotInfo *slot; PK11SymKey *res_key; CK_MECHANISM_TYPE cipher; CK_ATTRIBUTE_TYPE operation; CK_MECHANISM_TYPE wrap_mechanism; int wrap_key_len; PK11SymKey *wrap_key; PK11Context *wrap_key_crypt_context; SECItem tmp_sec_item; SECItem wrapped_key; int wrapped_key_len; unsigned char wrapped_key_data[KNET_MAX_KEY_LEN]; memset(&key_item, 0, sizeof(key_item)); slot = NULL; wrap_key = NULL; res_key = NULL; wrap_key_crypt_context = NULL; key_item.type = siBuffer; key_item.data = instance->private_key; switch (key_type) { case SYM_KEY_TYPE_CRYPT: key_item.len = nsscipher_key_len[instance->crypto_cipher_type]; cipher = cipher_to_nss[instance->crypto_cipher_type]; operation = CKA_ENCRYPT|CKA_DECRYPT; break; case SYM_KEY_TYPE_HASH: key_item.len = instance->private_key_len; cipher = hash_to_nss[instance->crypto_hash_type]; operation = CKA_SIGN; break; default: log_err(knet_h, KNET_SUB_NSSCRYPTO, "Import symmetric key failed. Unknown keyimport request"); goto exit_res_key; break; } slot = (*_int_PK11_GetBestSlot)(cipher, NULL); if (slot == NULL) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "Unable to find security slot (%d): %s", (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); goto exit_res_key; } /* * Without FIPS it would be possible to just use * res_key = PK11_ImportSymKey(slot, cipher, PK11_OriginUnwrap, operation, &key_item, NULL); * with FIPS NSS Level 2 certification has to be "workarounded" (so it becomes Level 1) by using * following method: * 1. Generate wrap key * 2. Encrypt authkey with wrap key * 3. Unwrap encrypted authkey using wrap key */ /* * Generate wrapping key */ wrap_mechanism = (*_int_PK11_GetBestWrapMechanism)(slot); wrap_key_len = (*_int_PK11_GetBestKeyLength)(slot, wrap_mechanism); wrap_key = (*_int_PK11_KeyGen)(slot, wrap_mechanism, NULL, wrap_key_len, NULL); if (wrap_key == NULL) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "Unable to generate wrapping key (%d): %s", (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); goto exit_res_key; } /* * Encrypt authkey with wrapping key */ /* * Initialization of IV is not needed because PK11_GetBestWrapMechanism should return ECB mode */ memset(&tmp_sec_item, 0, sizeof(tmp_sec_item)); wrap_key_crypt_context = (*_int_PK11_CreateContextBySymKey)(wrap_mechanism, CKA_ENCRYPT, wrap_key, &tmp_sec_item); if (wrap_key_crypt_context == NULL) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "Unable to create encrypt context (%d): %s", (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); goto exit_res_key; } wrapped_key_len = (int)sizeof(wrapped_key_data); if ((*_int_PK11_CipherOp)(wrap_key_crypt_context, wrapped_key_data, &wrapped_key_len, sizeof(wrapped_key_data), key_item.data, key_item.len) != SECSuccess) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "Unable to encrypt authkey (%d): %s", (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); goto exit_res_key; } if ((*_int_PK11_Finalize)(wrap_key_crypt_context) != SECSuccess) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "Unable to finalize encryption of authkey (%d): %s", (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); goto exit_res_key; } /* * Finally unwrap sym key */ memset(&tmp_sec_item, 0, sizeof(tmp_sec_item)); wrapped_key.data = wrapped_key_data; wrapped_key.len = wrapped_key_len; res_key = (*_int_PK11_UnwrapSymKey)(wrap_key, wrap_mechanism, &tmp_sec_item, &wrapped_key, cipher, operation, key_item.len); if (res_key == NULL) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "Failure to import key into NSS (%d): %s", (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); if ((*_int_PR_GetError)() == SEC_ERROR_BAD_DATA) { /* * Maximum key length for FIPS enabled softtoken is limited to * MAX_KEY_LEN (pkcs11i.h - 256) and checked in NSC_UnwrapKey. Returned * error is CKR_TEMPLATE_INCONSISTENT which is mapped to SEC_ERROR_BAD_DATA. */ log_err(knet_h, KNET_SUB_NSSCRYPTO, "Secret key is probably too long. " "Try reduce it to 256 bytes"); } goto exit_res_key; } exit_res_key: if (wrap_key_crypt_context != NULL) { (*_int_PK11_DestroyContext)(wrap_key_crypt_context, PR_TRUE); } if (wrap_key != NULL) { (*_int_PK11_FreeSymKey)(wrap_key); } if (slot != NULL) { (*_int_PK11_FreeSlot)(slot); } return (res_key); } static int init_nss_crypto(knet_handle_t knet_h) { struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance; if (!cipher_to_nss[instance->crypto_cipher_type]) { return 0; } instance->nss_sym_key = nssimport_symmetric_key(knet_h, SYM_KEY_TYPE_CRYPT); if (instance->nss_sym_key == NULL) { return -1; } return 0; } static int encrypt_nss( knet_handle_t knet_h, const struct iovec *iov, int iovcnt, unsigned char *buf_out, ssize_t *buf_out_len) { struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance; PK11Context* crypt_context = NULL; SECItem crypt_param; SECItem *nss_sec_param = NULL; int tmp_outlen = 0, tmp1_outlen = 0; unsigned int tmp2_outlen = 0; unsigned char *salt = buf_out; unsigned char *data = buf_out + SALT_SIZE; int err = -1; int i; if ((*_int_PK11_GenerateRandom)(salt, SALT_SIZE) != SECSuccess) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "Failure to generate a random number (err %d): %s", (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); goto out; } crypt_param.type = siBuffer; crypt_param.data = salt; crypt_param.len = SALT_SIZE; nss_sec_param = (*_int_PK11_ParamFromIV)(cipher_to_nss[instance->crypto_cipher_type], &crypt_param); if (nss_sec_param == NULL) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "Failure to set up PKCS11 param (err %d): %s", (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); goto out; } /* * Create cipher context for encryption */ crypt_context = (*_int_PK11_CreateContextBySymKey)(cipher_to_nss[instance->crypto_cipher_type], CKA_ENCRYPT, instance->nss_sym_key, nss_sec_param); if (!crypt_context) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_CreateContext failed (encrypt) crypt_type=%d (err %d): %s", (int)cipher_to_nss[instance->crypto_cipher_type], (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); goto out; } for (i=0; i<iovcnt; i++) { if ((*_int_PK11_CipherOp)(crypt_context, data, &tmp_outlen, KNET_DATABUFSIZE_CRYPT, (unsigned char *)iov[i].iov_base, iov[i].iov_len) != SECSuccess) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_CipherOp failed (encrypt) crypt_type=%d (err %d): %s", (int)cipher_to_nss[instance->crypto_cipher_type], (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); goto out; } tmp1_outlen = tmp1_outlen + tmp_outlen; } if ((*_int_PK11_DigestFinal)(crypt_context, data + tmp1_outlen, &tmp2_outlen, KNET_DATABUFSIZE_CRYPT - tmp1_outlen) != SECSuccess) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_DigestFinal failed (encrypt) crypt_type=%d (err %d): %s", (int)cipher_to_nss[instance->crypto_cipher_type], (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); goto out; } *buf_out_len = tmp1_outlen + tmp2_outlen + SALT_SIZE; err = 0; out: if (crypt_context) { (*_int_PK11_DestroyContext)(crypt_context, PR_TRUE); } if (nss_sec_param) { (*_int_SECITEM_FreeItem)(nss_sec_param, PR_TRUE); } return err; } static int decrypt_nss ( knet_handle_t knet_h, const unsigned char *buf_in, const ssize_t buf_in_len, unsigned char *buf_out, ssize_t *buf_out_len) { struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance; PK11Context* decrypt_context = NULL; SECItem decrypt_param; int tmp1_outlen = 0; unsigned int tmp2_outlen = 0; unsigned char *salt = (unsigned char *)buf_in; unsigned char *data = salt + SALT_SIZE; int datalen = buf_in_len - SALT_SIZE; int err = -1; /* Create cipher context for decryption */ decrypt_param.type = siBuffer; decrypt_param.data = salt; decrypt_param.len = SALT_SIZE; decrypt_context = (*_int_PK11_CreateContextBySymKey)(cipher_to_nss[instance->crypto_cipher_type], CKA_DECRYPT, instance->nss_sym_key, &decrypt_param); if (!decrypt_context) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_CreateContext (decrypt) failed (err %d): %s", (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); goto out; } if ((*_int_PK11_CipherOp)(decrypt_context, buf_out, &tmp1_outlen, KNET_DATABUFSIZE_CRYPT, data, datalen) != SECSuccess) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_CipherOp (decrypt) failed (err %d): %s", (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); goto out; } if ((*_int_PK11_DigestFinal)(decrypt_context, buf_out + tmp1_outlen, &tmp2_outlen, KNET_DATABUFSIZE_CRYPT - tmp1_outlen) != SECSuccess) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_DigestFinal (decrypt) failed (err %d): %s", (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); goto out; } *buf_out_len = tmp1_outlen + tmp2_outlen; err = 0; out: if (decrypt_context) { (*_int_PK11_DestroyContext)(decrypt_context, PR_TRUE); } return err; } /* * hash/hmac/digest functions */ static int nssstring_to_crypto_hash_type(const char* crypto_hash_type) { if (strcmp(crypto_hash_type, "none") == 0) { return CRYPTO_HASH_TYPE_NONE; } else if (strcmp(crypto_hash_type, "md5") == 0) { return CRYPTO_HASH_TYPE_MD5; } else if (strcmp(crypto_hash_type, "sha1") == 0) { return CRYPTO_HASH_TYPE_SHA1; } else if (strcmp(crypto_hash_type, "sha256") == 0) { return CRYPTO_HASH_TYPE_SHA256; } else if (strcmp(crypto_hash_type, "sha384") == 0) { return CRYPTO_HASH_TYPE_SHA384; } else if (strcmp(crypto_hash_type, "sha512") == 0) { return CRYPTO_HASH_TYPE_SHA512; } return -1; } static int init_nss_hash(knet_handle_t knet_h) { struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance; if (!hash_to_nss[instance->crypto_hash_type]) { return 0; } instance->nss_sym_key_sign = nssimport_symmetric_key(knet_h, SYM_KEY_TYPE_HASH); if (instance->nss_sym_key_sign == NULL) { return -1; } return 0; } static int calculate_nss_hash( knet_handle_t knet_h, const unsigned char *buf, const size_t buf_len, unsigned char *hash) { struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance; PK11Context* hash_context = NULL; SECItem hash_param; unsigned int hash_tmp_outlen = 0; int err = -1; /* Now do the digest */ hash_param.type = siBuffer; hash_param.data = 0; hash_param.len = 0; hash_context = (*_int_PK11_CreateContextBySymKey)(hash_to_nss[instance->crypto_hash_type], CKA_SIGN, instance->nss_sym_key_sign, &hash_param); if (!hash_context) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_CreateContext failed (hash) hash_type=%d (err %d): %s", (int)hash_to_nss[instance->crypto_hash_type], (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); goto out; } if ((*_int_PK11_DigestBegin)(hash_context) != SECSuccess) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_DigestBegin failed (hash) hash_type=%d (err %d): %s", (int)hash_to_nss[instance->crypto_hash_type], (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); goto out; } if ((*_int_PK11_DigestOp)(hash_context, buf, buf_len) != SECSuccess) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_DigestOp failed (hash) hash_type=%d (err %d): %s", (int)hash_to_nss[instance->crypto_hash_type], (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); goto out; } if ((*_int_PK11_DigestFinal)(hash_context, hash, &hash_tmp_outlen, nsshash_len[instance->crypto_hash_type]) != SECSuccess) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "PK11_DigestFinale failed (hash) hash_type=%d (err %d): %s", (int)hash_to_nss[instance->crypto_hash_type], (*_int_PR_GetError)(), (*_int_PR_ErrorToString)((*_int_PR_GetError)(), PR_LANGUAGE_I_DEFAULT)); goto out; } err = 0; out: if (hash_context) { (*_int_PK11_DestroyContext)(hash_context, PR_TRUE); } return err; } /* * global/glue nss functions */ static int init_nss(knet_handle_t knet_h) { if (init_nss_crypto(knet_h) < 0) { return -1; } if (init_nss_hash(knet_h) < 0) { return -1; } return 0; } /* * exported API */ int nsscrypto_encrypt_and_sign ( knet_handle_t knet_h, const unsigned char *buf_in, const ssize_t buf_in_len, unsigned char *buf_out, ssize_t *buf_out_len) { struct iovec iov_in; memset(&iov_in, 0, sizeof(iov_in)); iov_in.iov_base = (unsigned char *)buf_in; iov_in.iov_len = buf_in_len; return nsscrypto_encrypt_and_signv(knet_h, &iov_in, 1, buf_out, buf_out_len); } int nsscrypto_encrypt_and_signv ( knet_handle_t knet_h, const struct iovec *iov_in, int iovcnt_in, unsigned char *buf_out, ssize_t *buf_out_len) { struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance; int i; if (cipher_to_nss[instance->crypto_cipher_type]) { if (encrypt_nss(knet_h, iov_in, iovcnt_in, buf_out, buf_out_len) < 0) { return -1; } } else { *buf_out_len = 0; for (i=0; i<iovcnt_in; i++) { memmove(buf_out + *buf_out_len, iov_in[i].iov_base, iov_in[i].iov_len); *buf_out_len = *buf_out_len + iov_in[i].iov_len; } } if (hash_to_nss[instance->crypto_hash_type]) { if (calculate_nss_hash(knet_h, buf_out, *buf_out_len, buf_out + *buf_out_len) < 0) { return -1; } *buf_out_len = *buf_out_len + nsshash_len[instance->crypto_hash_type]; } return 0; } int nsscrypto_authenticate_and_decrypt ( knet_handle_t knet_h, const unsigned char *buf_in, const ssize_t buf_in_len, unsigned char *buf_out, ssize_t *buf_out_len) { struct nsscrypto_instance *instance = knet_h->crypto_instance->model_instance; ssize_t temp_len = buf_in_len; if (hash_to_nss[instance->crypto_hash_type]) { unsigned char tmp_hash[nsshash_len[instance->crypto_hash_type]]; ssize_t temp_buf_len = buf_in_len - nsshash_len[instance->crypto_hash_type]; if ((temp_buf_len < 0) || (temp_buf_len > KNET_MAX_PACKET_SIZE)) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "Incorrect packet size."); return -1; } if (calculate_nss_hash(knet_h, buf_in, temp_buf_len, tmp_hash) < 0) { return -1; } if (memcmp(tmp_hash, buf_in + temp_buf_len, nsshash_len[instance->crypto_hash_type]) != 0) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "Digest does not match"); return -1; } temp_len = temp_len - nsshash_len[instance->crypto_hash_type]; *buf_out_len = temp_len; } if (cipher_to_nss[instance->crypto_cipher_type]) { if (decrypt_nss(knet_h, buf_in, temp_len, buf_out, buf_out_len) < 0) { return -1; } } else { memmove(buf_out, buf_in, temp_len); *buf_out_len = temp_len; } return 0; } int nsscrypto_init( knet_handle_t knet_h, struct knet_handle_crypto_cfg *knet_handle_crypto_cfg) { struct nsscrypto_instance *nsscrypto_instance = NULL; log_debug(knet_h, KNET_SUB_NSSCRYPTO, "Initizializing nss crypto module [%s/%s]", knet_handle_crypto_cfg->crypto_cipher_type, knet_handle_crypto_cfg->crypto_hash_type); knet_h->crypto_instance->model_instance = malloc(sizeof(struct nsscrypto_instance)); if (!knet_h->crypto_instance->model_instance) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "Unable to allocate memory for nss model instance"); return -1; } nsscrypto_instance = knet_h->crypto_instance->model_instance; memset(nsscrypto_instance, 0, sizeof(struct nsscrypto_instance)); nsscrypto_instance->crypto_cipher_type = nssstring_to_crypto_cipher_type(knet_handle_crypto_cfg->crypto_cipher_type); if (nsscrypto_instance->crypto_cipher_type < 0) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "unknown crypto cipher type requested"); goto out_err; } nsscrypto_instance->crypto_hash_type = nssstring_to_crypto_hash_type(knet_handle_crypto_cfg->crypto_hash_type); if (nsscrypto_instance->crypto_hash_type < 0) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "unknown crypto hash type requested"); goto out_err; } if ((nsscrypto_instance->crypto_cipher_type > 0) && (nsscrypto_instance->crypto_hash_type == 0)) { log_err(knet_h, KNET_SUB_NSSCRYPTO, "crypto communication requires hash specified"); goto out_err; } nsscrypto_instance->private_key = knet_handle_crypto_cfg->private_key; nsscrypto_instance->private_key_len = knet_handle_crypto_cfg->private_key_len; if (init_nss(knet_h) < 0) { goto out_err; } knet_h->sec_header_size = 0; if (nsscrypto_instance->crypto_hash_type > 0) { knet_h->sec_header_size += nsshash_len[nsscrypto_instance->crypto_hash_type]; knet_h->sec_hash_size = nsshash_len[nsscrypto_instance->crypto_hash_type]; } if (nsscrypto_instance->crypto_cipher_type > 0) { int block_size; if (nsscypher_block_len[nsscrypto_instance->crypto_cipher_type]) { block_size = nsscypher_block_len[nsscrypto_instance->crypto_cipher_type]; } else { block_size = (*_int_PK11_GetBlockSize)(nsscrypto_instance->crypto_cipher_type, NULL); if (block_size < 0) { goto out_err; } } knet_h->sec_header_size += (block_size * 2); knet_h->sec_header_size += SALT_SIZE; knet_h->sec_salt_size = SALT_SIZE; knet_h->sec_block_size = block_size; } return 0; out_err: nsscrypto_fini(knet_h); return -1; } void nsscrypto_fini( knet_handle_t knet_h) { struct nsscrypto_instance *nsscrypto_instance = knet_h->crypto_instance->model_instance; if (nsscrypto_instance) { if (nsscrypto_instance->nss_sym_key) { (*_int_PK11_FreeSymKey)(nsscrypto_instance->nss_sym_key); nsscrypto_instance->nss_sym_key = NULL; } if (nsscrypto_instance->nss_sym_key_sign) { (*_int_PK11_FreeSymKey)(nsscrypto_instance->nss_sym_key_sign); nsscrypto_instance->nss_sym_key_sign = NULL; } free(nsscrypto_instance); knet_h->crypto_instance->model_instance = NULL; knet_h->sec_header_size = 0; } return; } #endif diff --git a/libknet/crypto_nss.h b/libknet/crypto_nss.h index 9443fb50..d77a8d8b 100644 --- a/libknet/crypto_nss.h +++ b/libknet/crypto_nss.h @@ -1,47 +1,47 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2012-2017 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 __KNET_NSSCRYPTO_H__ #define __KNET_NSSCRYPTO_H__ #include "internals.h" struct nsscrypto_instance; int nsscrypto_load_lib( knet_handle_t knet_h); int nsscrypto_init( knet_handle_t knet_h, struct knet_handle_crypto_cfg *knet_handle_crypto_cfg); void nsscrypto_fini( knet_handle_t knet_h); int nsscrypto_authenticate_and_decrypt ( knet_handle_t knet_h, const unsigned char *buf_in, const ssize_t buf_in_len, unsigned char *buf_out, ssize_t *buf_out_len); int nsscrypto_encrypt_and_sign ( knet_handle_t knet_h, const unsigned char *buf_in, const ssize_t buf_in_len, unsigned char *buf_out, ssize_t *buf_out_len); int nsscrypto_encrypt_and_signv ( knet_handle_t knet_h, const struct iovec *iov_in, int iovcnt_in, unsigned char *buf_out, ssize_t *buf_out_len); #endif diff --git a/libknet/crypto_openssl.h b/libknet/crypto_openssl.h index f314b9d8..cdb2fd44 100644 --- a/libknet/crypto_openssl.h +++ b/libknet/crypto_openssl.h @@ -1,47 +1,47 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2012-2017 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 __KNET_OPENSSLCRYPTO_H__ #define __KNET_OPENSSLCRYPTO_H__ #include "internals.h" struct opensslcrypto_instance; int opensslcrypto_load_lib( knet_handle_t knet_h); int opensslcrypto_init( knet_handle_t knet_h, struct knet_handle_crypto_cfg *knet_handle_crypto_cfg); void opensslcrypto_fini( knet_handle_t knet_h); int opensslcrypto_authenticate_and_decrypt ( knet_handle_t knet_h, const unsigned char *buf_in, const ssize_t buf_in_len, unsigned char *buf_out, ssize_t *buf_out_len); int opensslcrypto_encrypt_and_sign ( knet_handle_t knet_h, const unsigned char *buf_in, const ssize_t buf_in_len, unsigned char *buf_out, ssize_t *buf_out_len); int opensslcrypto_encrypt_and_signv ( knet_handle_t knet_h, const struct iovec *iov_in, int iovcnt_in, unsigned char *buf_out, ssize_t *buf_out_len); #endif diff --git a/libknet/internals.h b/libknet/internals.h index 0a4d5cf1..048590aa 100644 --- a/libknet/internals.h +++ b/libknet/internals.h @@ -1,488 +1,488 @@ /* - * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNET_INTERNALS_H__ #define __KNET_INTERNALS_H__ /* * NOTE: you shouldn't need to include this header normally */ #include <pthread.h> #include "libknet.h" #include "onwire.h" #include "compat.h" #define KNET_DATABUFSIZE KNET_MAX_PACKET_SIZE + KNET_HEADER_ALL_SIZE #define KNET_DATABUFSIZE_CRYPT_PAD 1024 #define KNET_DATABUFSIZE_CRYPT KNET_DATABUFSIZE + KNET_DATABUFSIZE_CRYPT_PAD #define KNET_DATABUFSIZE_COMPRESS_PAD 1024 #define KNET_DATABUFSIZE_COMPRESS KNET_DATABUFSIZE + KNET_DATABUFSIZE_COMPRESS_PAD #define KNET_RING_RCVBUFF 8388608 #define PCKT_FRAG_MAX UINT8_MAX #define PCKT_RX_BUFS 512 #define KNET_EPOLL_MAX_EVENTS KNET_DATAFD_MAX typedef void *knet_transport_link_t; /* per link transport handle */ typedef void *knet_transport_t; /* per knet_h transport handle */ struct knet_transport_ops; /* Forward because of circular dependancy */ struct knet_mmsghdr { struct msghdr msg_hdr; /* Message header */ unsigned int msg_len; /* Number of bytes transmitted */ }; struct knet_link { /* required */ struct sockaddr_storage src_addr; struct sockaddr_storage dst_addr; /* configurable */ unsigned int dynamic; /* see KNET_LINK_DYN_ define above */ uint8_t priority; /* higher priority == preferred for A/P */ unsigned long long ping_interval; /* interval */ unsigned long long pong_timeout; /* timeout */ unsigned int latency_fix; /* precision */ uint8_t pong_count; /* how many ping/pong to send/receive before link is up */ uint64_t flags; /* status */ struct knet_link_status status; /* internals */ uint8_t link_id; uint8_t transport_type; /* #defined constant from API */ knet_transport_link_t transport_link; /* link_info_t from transport */ int outsock; unsigned int configured:1; /* set to 1 if src/dst have been configured transport initialized on this link*/ unsigned int transport_connected:1; /* set to 1 if lower level transport is connected */ unsigned int latency_exp; uint8_t received_pong; struct timespec ping_last; /* used by PMTUD thread as temp per-link variables and should always contain the onwire_len value! */ uint32_t proto_overhead; struct timespec pmtud_last; uint32_t last_ping_size; uint32_t last_good_mtu; uint32_t last_bad_mtu; uint32_t last_sent_mtu; uint32_t last_recv_mtu; uint8_t has_valid_mtu; }; #define KNET_CBUFFER_SIZE 4096 struct knet_host_defrag_buf { char buf[KNET_DATABUFSIZE]; uint8_t in_use; /* 0 buffer is free, 1 is in use */ seq_num_t pckt_seq; /* identify the pckt we are receiving */ uint8_t frag_recv; /* how many frags did we receive */ uint8_t frag_map[PCKT_FRAG_MAX];/* bitmap of what we received? */ uint8_t last_first; /* special case if we receive the last fragment first */ uint16_t frag_size; /* normal frag size (not the last one) */ uint16_t last_frag_size; /* the last fragment might not be aligned with MTU size */ struct timespec last_update; /* keep time of the last pckt */ }; struct knet_host { /* required */ knet_node_id_t host_id; /* configurable */ uint8_t link_handler_policy; char name[KNET_MAX_HOST_LEN]; /* status */ struct knet_host_status status; /* internals */ char circular_buffer[KNET_CBUFFER_SIZE]; seq_num_t rx_seq_num; seq_num_t untimed_rx_seq_num; seq_num_t timed_rx_seq_num; uint8_t got_data; /* defrag/reassembly buffers */ struct knet_host_defrag_buf defrag_buf[KNET_MAX_LINK]; char circular_buffer_defrag[KNET_CBUFFER_SIZE]; /* link stuff */ struct knet_link link[KNET_MAX_LINK]; uint8_t active_link_entries; uint8_t active_links[KNET_MAX_LINK]; struct knet_host *next; }; struct knet_sock { int sockfd[2]; /* sockfd[0] will always be application facing * and sockfd[1] internal if sockpair has been created by knet */ int is_socket; /* check if it's a socket for recvmmsg usage */ int is_created; /* knet created this socket and has to clean up on exit/del */ int in_use; /* set to 1 if it's use, 0 if free */ int has_error; /* set to 1 if there were errors reading from the sock * and socket has been removed from epoll */ }; struct knet_fd_trackers { uint8_t transport; /* transport type (UDP/SCTP...) */ uint8_t data_type; /* internal use for transport to define what data are associated * to this fd */ void *data; /* pointer to the data */ }; #define KNET_MAX_FDS KNET_MAX_HOST * KNET_MAX_LINK * 4 #define KNET_MAX_COMPRESS_METHODS UINT8_MAX struct knet_handle { knet_node_id_t host_id; unsigned int enabled:1; struct knet_sock sockfd[KNET_DATAFD_MAX]; int logfd; uint8_t log_levels[KNET_MAX_SUBSYSTEMS]; int hostsockfd[2]; int dstsockfd[2]; int send_to_links_epollfd; int recv_from_links_epollfd; int dst_link_handler_epollfd; unsigned int pmtud_interval; unsigned int data_mtu; /* contains the max data size that we can send onwire * without frags */ struct knet_host *host_head; struct knet_host *host_index[KNET_MAX_HOST]; knet_transport_t transports[KNET_MAX_TRANSPORTS+1]; struct knet_transport_ops *transport_ops[KNET_MAX_TRANSPORTS+1]; struct knet_fd_trackers knet_transport_fd_tracker[KNET_MAX_FDS]; /* track status for each fd handled by transports */ struct knet_handle_stats stats; uint32_t reconnect_int; knet_node_id_t host_ids[KNET_MAX_HOST]; size_t host_ids_entries; struct knet_header *recv_from_sock_buf; struct knet_header *send_to_links_buf[PCKT_FRAG_MAX]; struct knet_header *recv_from_links_buf[PCKT_RX_BUFS]; struct knet_header *pingbuf; struct knet_header *pmtudbuf; pthread_t send_to_links_thread; pthread_t recv_from_links_thread; pthread_t heartbt_thread; pthread_t dst_link_handler_thread; pthread_t pmtud_link_handler_thread; int lock_init_done; pthread_rwlock_t global_rwlock; /* global config lock */ pthread_mutex_t pmtud_mutex; /* pmtud mutex to handle conditional send/recv + timeout */ pthread_cond_t pmtud_cond; /* conditional for above */ pthread_mutex_t tx_mutex; /* used to protect knet_send_sync and TX thread */ pthread_mutex_t hb_mutex; /* used to protect heartbeat thread and seq_num broadcasting */ struct crypto_instance *crypto_instance; size_t sec_header_size; size_t sec_block_size; size_t sec_hash_size; size_t sec_salt_size; unsigned char *send_to_links_buf_crypt[PCKT_FRAG_MAX]; unsigned char *recv_from_links_buf_crypt; unsigned char *recv_from_links_buf_decrypt; unsigned char *pingbuf_crypt; unsigned char *pmtudbuf_crypt; int compress_model; int compress_level; size_t compress_threshold; void *compress_int_data[KNET_MAX_COMPRESS_METHODS]; /* for compress method private data */ unsigned char *recv_from_links_buf_decompress; unsigned char *send_to_links_buf_compress; seq_num_t tx_seq_num; pthread_mutex_t tx_seq_num_mutex; uint8_t has_loop_link; uint8_t loop_link; void *dst_host_filter_fn_private_data; int (*dst_host_filter_fn) ( void *private_data, const unsigned char *outdata, ssize_t outdata_len, uint8_t tx_rx, knet_node_id_t this_host_id, knet_node_id_t src_node_id, int8_t *channel, knet_node_id_t *dst_host_ids, size_t *dst_host_ids_entries); void *pmtud_notify_fn_private_data; void (*pmtud_notify_fn) ( void *private_data, unsigned int data_mtu); void *host_status_change_notify_fn_private_data; void (*host_status_change_notify_fn) ( void *private_data, knet_node_id_t host_id, uint8_t reachable, uint8_t remote, uint8_t external); void *sock_notify_fn_private_data; void (*sock_notify_fn) ( void *private_data, int datafd, int8_t channel, uint8_t tx_rx, int error, int errorno); int fini_in_progress; }; extern pthread_rwlock_t shlib_rwlock; /* global shared lib load lock */ /* * NOTE: every single operation must be implementend * for every protocol. */ typedef struct knet_transport_ops { /* * transport generic information */ const char *transport_name; const uint8_t transport_id; uint32_t transport_mtu_overhead; /* * transport init must allocate the new transport * and perform all internal initializations * (threads, lists, etc). */ int (*transport_init)(knet_handle_t knet_h); /* * transport free must releases _all_ resources * allocated by tranport_init */ int (*transport_free)(knet_handle_t knet_h); /* * link operations should take care of all the * sockets and epoll management for a given link/transport set * transport_link_disable should return err = -1 and errno = EBUSY * if listener is still in use, and any other errno in case * the link cannot be disabled. * * set_config/clear_config are invoked in global write lock context */ int (*transport_link_set_config)(knet_handle_t knet_h, struct knet_link *link); int (*transport_link_clear_config)(knet_handle_t knet_h, struct knet_link *link); /* * transport callback for incoming dynamic connections * this is called in global read lock context */ int (*transport_link_dyn_connect)(knet_handle_t knet_h, int sockfd, struct knet_link *link); /* * per transport error handling of recvmmsg * (see _handle_recv_from_links comments for details) */ /* * transport_rx_sock_error is invoked when recvmmsg returns <= 0 * * transport_rx_sock_error is invoked with both global_rdlock */ int (*transport_rx_sock_error)(knet_handle_t knet_h, int sockfd, int recv_err, int recv_errno); /* * transport_tx_sock_error is invoked with global_rwlock and * it's invoked when sendto or sendmmsg returns =< 0 * * it should return: * -1 on internal error * 0 ignore error and continue * 1 retry * any sleep or wait action should happen inside the transport code */ int (*transport_tx_sock_error)(knet_handle_t knet_h, int sockfd, int recv_err, int recv_errno); /* * this function is called on _every_ received packet * to verify if the packet is data or internal protocol error handling * * it should return: * -1 on error * 0 packet is not data and we should continue the packet process loop * 1 packet is not data and we should STOP the packet process loop * 2 packet is data and should be parsed as such * * transport_rx_is_data is invoked with both global_rwlock * and fd_tracker read lock (from RX thread) */ int (*transport_rx_is_data)(knet_handle_t knet_h, int sockfd, struct knet_mmsghdr *msg); } knet_transport_ops_t; socklen_t sockaddr_len(const struct sockaddr_storage *ss); /** * This is a kernel style list implementation. * * @author Steven Dake <sdake@redhat.com> */ struct knet_list_head { struct knet_list_head *next; struct knet_list_head *prev; }; /** * @def KNET_LIST_DECLARE() * Declare and initialize a list head. */ #define KNET_LIST_DECLARE(name) \ struct knet_list_head name = { &(name), &(name) } #define KNET_INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0) /** * Initialize the list entry. * * Points next and prev pointers to head. * @param head pointer to the list head */ static inline void knet_list_init(struct knet_list_head *head) { head->next = head; head->prev = head; } /** * Add this element to the list. * * @param element the new element to insert. * @param head pointer to the list head */ static inline void knet_list_add(struct knet_list_head *element, struct knet_list_head *head) { head->next->prev = element; element->next = head->next; element->prev = head; head->next = element; } /** * Add to the list (but at the end of the list). * * @param element pointer to the element to add * @param head pointer to the list head * @see knet_list_add() */ static inline void knet_list_add_tail(struct knet_list_head *element, struct knet_list_head *head) { head->prev->next = element; element->next = head; element->prev = head->prev; head->prev = element; } /** * Delete an entry from the list. * * @param _remove the list item to remove */ static inline void knet_list_del(struct knet_list_head *_remove) { _remove->next->prev = _remove->prev; _remove->prev->next = _remove->next; } /** * Replace old entry by new one * @param old: the element to be replaced * @param new: the new element to insert */ static inline void knet_list_replace(struct knet_list_head *old, struct knet_list_head *new) { new->next = old->next; new->next->prev = new; new->prev = old->prev; new->prev->next = new; } /** * Tests whether list is the last entry in list head * @param list: the entry to test * @param head: the head of the list * @return boolean true/false */ static inline int knet_list_is_last(const struct knet_list_head *list, const struct knet_list_head *head) { return list->next == head; } /** * A quick test to see if the list is empty (pointing to it's self). * @param head pointer to the list head * @return boolean true/false */ static inline int32_t knet_list_empty(const struct knet_list_head *head) { return head->next == head; } /** * Get the struct for this entry * @param ptr: the &struct list_head pointer. * @param type: the type of the struct this is embedded in. * @param member: the name of the list_struct within the struct. */ #define knet_list_entry(ptr,type,member)\ ((type *)((char *)(ptr)-(char*)(&((type *)0)->member))) /** * Get the first element from a list * @param ptr: the &struct list_head pointer. * @param type: the type of the struct this is embedded in. * @param member: the name of the list_struct within the struct. */ #define knet_list_first_entry(ptr, type, member) \ knet_list_entry((ptr)->next, type, member) /** * Iterate over a list * @param pos: the &struct list_head to use as a loop counter. * @param head: the head for your list. */ #define knet_list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) /** * Iterate over a list backwards * @param pos: the &struct list_head to use as a loop counter. * @param head: the head for your list. */ #define knet_list_for_each_reverse(pos, head) \ for (pos = (head)->prev; pos != (head); pos = pos->prev) /** * Iterate over a list safe against removal of list entry * @param pos: the &struct list_head to use as a loop counter. * @param n: another &struct list_head to use as temporary storage * @param head: the head for your list. */ #define knet_list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) /** * Iterate over list of given type * @param pos: the type * to use as a loop counter. * @param head: the head for your list. * @param member: the name of the list_struct within the struct. */ #define knet_list_for_each_entry(pos, head, member) \ for (pos = knet_list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = knet_list_entry(pos->member.next, typeof(*pos), member)) #endif diff --git a/libknet/links.c b/libknet/links.c index 7ccbeabc..8d7bfe77 100644 --- a/libknet/links.c +++ b/libknet/links.c @@ -1,1087 +1,1087 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <netdb.h> #include <string.h> #include <pthread.h> #include "internals.h" #include "logging.h" #include "links.h" #include "transports.h" #include "host.h" int _link_updown(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, unsigned int enabled, unsigned int connected) { struct knet_link *link = &knet_h->host_index[host_id]->link[link_id]; if ((link->status.enabled == enabled) && (link->status.connected == connected)) return 0; link->status.enabled = enabled; link->status.connected = connected; _host_dstcache_update_async(knet_h, knet_h->host_index[host_id]); if ((link->status.dynconnected) && (!link->status.connected)) link->status.dynconnected = 0; if (connected) { time(&link->status.stats.last_up_times[link->status.stats.last_up_time_index]); link->status.stats.up_count++; if (++link->status.stats.last_up_time_index > MAX_LINK_EVENTS) { link->status.stats.last_up_time_index = 0; } } else { time(&link->status.stats.last_down_times[link->status.stats.last_down_time_index]); link->status.stats.down_count++; if (++link->status.stats.last_down_time_index > MAX_LINK_EVENTS) { link->status.stats.last_down_time_index = 0; } } return 0; } void _link_clear_stats(knet_handle_t knet_h) { struct knet_host *host; struct knet_link *link; uint32_t host_id; uint8_t link_id; for (host_id = 0; host_id < KNET_MAX_HOST; host_id++) { host = knet_h->host_index[host_id]; if (!host) { continue; } for (link_id = 0; link_id < KNET_MAX_LINK; link_id++) { link = &host->link[link_id]; memset(&link->status.stats, 0, sizeof(struct knet_link_stats)); } } } int knet_link_set_config(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, uint8_t transport, struct sockaddr_storage *src_addr, struct sockaddr_storage *dst_addr, uint64_t flags) { int savederrno = 0, err = 0, i; struct knet_host *host; struct knet_link *link; if (!knet_h) { errno = EINVAL; return -1; } if (link_id >= KNET_MAX_LINK) { errno = EINVAL; return -1; } if (!src_addr) { errno = EINVAL; return -1; } if (transport >= KNET_MAX_TRANSPORTS) { errno = EINVAL; return -1; } if (!knet_h->transport_ops[transport]) { errno = EINVAL; return -1; } savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s", strerror(savederrno)); errno = savederrno; return -1; } if (transport == KNET_TRANSPORT_LOOPBACK && knet_h->host_id != host_id) { log_err(knet_h, KNET_SUB_LINK, "Cannot create loopback link to remote node"); err = -1; savederrno = EINVAL; goto exit_unlock; } if (knet_h->host_id == host_id && knet_h->has_loop_link) { log_err(knet_h, KNET_SUB_LINK, "Cannot create more than 1 link when loopback is active"); err = -1; savederrno = EINVAL; goto exit_unlock; } host = knet_h->host_index[host_id]; if (!host) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s", host_id, strerror(savederrno)); goto exit_unlock; } if (transport == KNET_TRANSPORT_LOOPBACK && knet_h->host_id == host_id) { for (i=0; i<KNET_MAX_LINK; i++) { if (host->link[i].configured) { log_err(knet_h, KNET_SUB_LINK, "Cannot add loopback link when other links are already configured."); err = -1; savederrno = EINVAL; goto exit_unlock; } } } link = &host->link[link_id]; if (link->configured != 0) { err =-1; savederrno = EBUSY; log_err(knet_h, KNET_SUB_LINK, "Host %u link %u is currently configured: %s", host_id, link_id, strerror(savederrno)); goto exit_unlock; } if (link->status.enabled != 0) { err =-1; savederrno = EBUSY; log_err(knet_h, KNET_SUB_LINK, "Host %u link %u is currently in use: %s", host_id, link_id, strerror(savederrno)); goto exit_unlock; } memmove(&link->src_addr, src_addr, sizeof(struct sockaddr_storage)); err = knet_addrtostr(src_addr, sizeof(struct sockaddr_storage), link->status.src_ipaddr, KNET_MAX_HOST_LEN, link->status.src_port, KNET_MAX_PORT_LEN); if (err) { if (err == EAI_SYSTEM) { savederrno = errno; log_warn(knet_h, KNET_SUB_LINK, "Unable to resolve host: %u link: %u source addr/port: %s", host_id, link_id, strerror(savederrno)); } else { savederrno = EINVAL; log_warn(knet_h, KNET_SUB_LINK, "Unable to resolve host: %u link: %u source addr/port: %s", host_id, link_id, gai_strerror(err)); } err = -1; goto exit_unlock; } if (!dst_addr) { link->dynamic = KNET_LINK_DYNIP; } else { link->dynamic = KNET_LINK_STATIC; memmove(&link->dst_addr, dst_addr, sizeof(struct sockaddr_storage)); err = knet_addrtostr(dst_addr, sizeof(struct sockaddr_storage), link->status.dst_ipaddr, KNET_MAX_HOST_LEN, link->status.dst_port, KNET_MAX_PORT_LEN); if (err) { if (err == EAI_SYSTEM) { savederrno = errno; log_warn(knet_h, KNET_SUB_LINK, "Unable to resolve host: %u link: %u destination addr/port: %s", host_id, link_id, strerror(savederrno)); } else { savederrno = EINVAL; log_warn(knet_h, KNET_SUB_LINK, "Unable to resolve host: %u link: %u destination addr/port: %s", host_id, link_id, gai_strerror(err)); } err = -1; goto exit_unlock; } } link->transport_type = transport; link->transport_connected = 0; link->proto_overhead = knet_h->transport_ops[link->transport_type]->transport_mtu_overhead; link->pong_count = KNET_LINK_DEFAULT_PONG_COUNT; link->has_valid_mtu = 0; link->ping_interval = KNET_LINK_DEFAULT_PING_INTERVAL * 1000; /* microseconds */ link->pong_timeout = KNET_LINK_DEFAULT_PING_TIMEOUT * 1000; /* microseconds */ link->latency_fix = KNET_LINK_DEFAULT_PING_PRECISION; link->latency_exp = KNET_LINK_DEFAULT_PING_PRECISION - \ ((link->ping_interval * KNET_LINK_DEFAULT_PING_PRECISION) / 8000000); link->flags = flags; if (knet_h->transport_ops[link->transport_type]->transport_link_set_config(knet_h, link) < 0) { savederrno = errno; err = -1; goto exit_unlock; } link->configured = 1; log_debug(knet_h, KNET_SUB_LINK, "host: %u link: %u is configured", host_id, link_id); if (transport == KNET_TRANSPORT_LOOPBACK) { knet_h->has_loop_link = 1; knet_h->loop_link = link_id; host->status.reachable = 1; } exit_unlock: pthread_rwlock_unlock(&knet_h->global_rwlock); errno = savederrno; return err; } int knet_link_get_config(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, uint8_t *transport, struct sockaddr_storage *src_addr, struct sockaddr_storage *dst_addr, uint8_t *dynamic, uint64_t *flags) { int savederrno = 0, err = 0; struct knet_host *host; struct knet_link *link; if (!knet_h) { errno = EINVAL; return -1; } if (link_id >= KNET_MAX_LINK) { errno = EINVAL; return -1; } if (!src_addr) { errno = EINVAL; return -1; } if (!dynamic) { errno = EINVAL; return -1; } if (!transport) { errno = EINVAL; return -1; } if (!flags) { errno = EINVAL; return -1; } savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s", strerror(savederrno)); errno = savederrno; return -1; } host = knet_h->host_index[host_id]; if (!host) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s", host_id, strerror(savederrno)); goto exit_unlock; } link = &host->link[link_id]; if (!link->configured) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s", host_id, link_id, strerror(savederrno)); goto exit_unlock; } if ((link->dynamic == KNET_LINK_STATIC) && (!dst_addr)) { savederrno = EINVAL; err = -1; goto exit_unlock; } memmove(src_addr, &link->src_addr, sizeof(struct sockaddr_storage)); *transport = link->transport_type; *flags = link->flags; if (link->dynamic == KNET_LINK_STATIC) { *dynamic = 0; memmove(dst_addr, &link->dst_addr, sizeof(struct sockaddr_storage)); } else { *dynamic = 1; } exit_unlock: pthread_rwlock_unlock(&knet_h->global_rwlock); errno = savederrno; return err; } int knet_link_clear_config(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id) { int savederrno = 0, err = 0; struct knet_host *host; struct knet_link *link; if (!knet_h) { errno = EINVAL; return -1; } if (link_id >= KNET_MAX_LINK) { errno = EINVAL; return -1; } savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s", strerror(savederrno)); errno = savederrno; return -1; } host = knet_h->host_index[host_id]; if (!host) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s", host_id, strerror(savederrno)); goto exit_unlock; } link = &host->link[link_id]; if (link->configured != 1) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "Host %u link %u is not configured: %s", host_id, link_id, strerror(savederrno)); goto exit_unlock; } if (link->status.enabled != 0) { err = -1; savederrno = EBUSY; log_err(knet_h, KNET_SUB_LINK, "Host %u link %u is currently in use: %s", host_id, link_id, strerror(savederrno)); goto exit_unlock; } if ((knet_h->transport_ops[link->transport_type]->transport_link_clear_config(knet_h, link) < 0) && (errno != EBUSY)) { savederrno = errno; err = -1; goto exit_unlock; } memset(link, 0, sizeof(struct knet_link)); link->link_id = link_id; if (knet_h->has_loop_link && link_id == knet_h->loop_link) { knet_h->has_loop_link = 0; if (host->active_link_entries == 0) { host->status.reachable = 0; } } log_debug(knet_h, KNET_SUB_LINK, "host: %u link: %u config has been wiped", host_id, link_id); exit_unlock: pthread_rwlock_unlock(&knet_h->global_rwlock); errno = savederrno; return err; } int knet_link_set_enable(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, unsigned int enabled) { int savederrno = 0, err = 0; struct knet_host *host; struct knet_link *link; if (!knet_h) { errno = EINVAL; return -1; } if (link_id >= KNET_MAX_LINK) { errno = EINVAL; return -1; } if (enabled > 1) { errno = EINVAL; return -1; } savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s", strerror(savederrno)); errno = savederrno; return -1; } host = knet_h->host_index[host_id]; if (!host) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s", host_id, strerror(savederrno)); goto exit_unlock; } link = &host->link[link_id]; if (!link->configured) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s", host_id, link_id, strerror(savederrno)); goto exit_unlock; } if (link->status.enabled == enabled) { err = 0; goto exit_unlock; } err = _link_updown(knet_h, host_id, link_id, enabled, link->status.connected); savederrno = errno; if (enabled) { goto exit_unlock; } log_debug(knet_h, KNET_SUB_LINK, "host: %u link: %u is disabled", host_id, link_id); exit_unlock: pthread_rwlock_unlock(&knet_h->global_rwlock); errno = savederrno; return err; } int knet_link_get_enable(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, unsigned int *enabled) { int savederrno = 0, err = 0; struct knet_host *host; struct knet_link *link; if (!knet_h) { errno = EINVAL; return -1; } if (link_id >= KNET_MAX_LINK) { errno = EINVAL; return -1; } if (!enabled) { errno = EINVAL; return -1; } savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s", strerror(savederrno)); errno = savederrno; return -1; } host = knet_h->host_index[host_id]; if (!host) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s", host_id, strerror(savederrno)); goto exit_unlock; } link = &host->link[link_id]; if (!link->configured) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s", host_id, link_id, strerror(savederrno)); goto exit_unlock; } *enabled = link->status.enabled; exit_unlock: pthread_rwlock_unlock(&knet_h->global_rwlock); errno = savederrno; return err; } int knet_link_set_pong_count(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, uint8_t pong_count) { int savederrno = 0, err = 0; struct knet_host *host; struct knet_link *link; if (!knet_h) { errno = EINVAL; return -1; } if (link_id >= KNET_MAX_LINK) { errno = EINVAL; return -1; } if (pong_count < 1) { errno = EINVAL; return -1; } savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s", strerror(savederrno)); errno = savederrno; return -1; } host = knet_h->host_index[host_id]; if (!host) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s", host_id, strerror(savederrno)); goto exit_unlock; } link = &host->link[link_id]; if (!link->configured) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s", host_id, link_id, strerror(savederrno)); goto exit_unlock; } link->pong_count = pong_count; log_debug(knet_h, KNET_SUB_LINK, "host: %u link: %u pong count update: %u", host_id, link_id, link->pong_count); exit_unlock: pthread_rwlock_unlock(&knet_h->global_rwlock); errno = savederrno; return err; } int knet_link_get_pong_count(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, uint8_t *pong_count) { int savederrno = 0, err = 0; struct knet_host *host; struct knet_link *link; if (!knet_h) { errno = EINVAL; return -1; } if (link_id >= KNET_MAX_LINK) { errno = EINVAL; return -1; } if (!pong_count) { errno = EINVAL; return -1; } savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s", strerror(savederrno)); errno = savederrno; return -1; } host = knet_h->host_index[host_id]; if (!host) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s", host_id, strerror(savederrno)); goto exit_unlock; } link = &host->link[link_id]; if (!link->configured) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s", host_id, link_id, strerror(savederrno)); goto exit_unlock; } *pong_count = link->pong_count; exit_unlock: pthread_rwlock_unlock(&knet_h->global_rwlock); errno = savederrno; return err; } int knet_link_set_ping_timers(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, time_t interval, time_t timeout, unsigned int precision) { int savederrno = 0, err = 0; struct knet_host *host; struct knet_link *link; if (!knet_h) { errno = EINVAL; return -1; } if (link_id >= KNET_MAX_LINK) { errno = EINVAL; return -1; } if (!interval) { errno = EINVAL; return -1; } if (!timeout) { errno = EINVAL; return -1; } if (!precision) { errno = EINVAL; return -1; } savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s", strerror(savederrno)); errno = savederrno; return -1; } host = knet_h->host_index[host_id]; if (!host) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s", host_id, strerror(savederrno)); goto exit_unlock; } link = &host->link[link_id]; if (!link->configured) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s", host_id, link_id, strerror(savederrno)); goto exit_unlock; } link->ping_interval = interval * 1000; /* microseconds */ link->pong_timeout = timeout * 1000; /* microseconds */ link->latency_fix = precision; link->latency_exp = precision - \ ((link->ping_interval * precision) / 8000000); log_debug(knet_h, KNET_SUB_LINK, "host: %u link: %u timeout update - interval: %llu timeout: %llu precision: %u", host_id, link_id, link->ping_interval, link->pong_timeout, precision); exit_unlock: pthread_rwlock_unlock(&knet_h->global_rwlock); errno = savederrno; return err; } int knet_link_get_ping_timers(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, time_t *interval, time_t *timeout, unsigned int *precision) { int savederrno = 0, err = 0; struct knet_host *host; struct knet_link *link; if (!knet_h) { errno = EINVAL; return -1; } if (link_id >= KNET_MAX_LINK) { errno = EINVAL; return -1; } if (!interval) { errno = EINVAL; return -1; } if (!timeout) { errno = EINVAL; return -1; } if (!precision) { errno = EINVAL; return -1; } savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s", strerror(savederrno)); errno = savederrno; return -1; } host = knet_h->host_index[host_id]; if (!host) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s", host_id, strerror(savederrno)); goto exit_unlock; } link = &host->link[link_id]; if (!link->configured) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s", host_id, link_id, strerror(savederrno)); goto exit_unlock; } *interval = link->ping_interval / 1000; /* microseconds */ *timeout = link->pong_timeout / 1000; *precision = link->latency_fix; exit_unlock: pthread_rwlock_unlock(&knet_h->global_rwlock); errno = savederrno; return err; } int knet_link_set_priority(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, uint8_t priority) { int savederrno = 0, err = 0; struct knet_host *host; struct knet_link *link; uint8_t old_priority; if (!knet_h) { errno = EINVAL; return -1; } if (link_id >= KNET_MAX_LINK) { errno = EINVAL; return -1; } savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, KNET_SUB_LINK, "Unable to get write lock: %s", strerror(savederrno)); errno = savederrno; return -1; } host = knet_h->host_index[host_id]; if (!host) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s", host_id, strerror(savederrno)); goto exit_unlock; } link = &host->link[link_id]; if (!link->configured) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s", host_id, link_id, strerror(savederrno)); goto exit_unlock; } old_priority = link->priority; if (link->priority == priority) { err = 0; goto exit_unlock; } link->priority = priority; if (_host_dstcache_update_sync(knet_h, host)) { savederrno = errno; log_debug(knet_h, KNET_SUB_LINK, "Unable to update link priority (host: %u link: %u priority: %u): %s", host_id, link_id, link->priority, strerror(savederrno)); link->priority = old_priority; err = -1; goto exit_unlock; } log_debug(knet_h, KNET_SUB_LINK, "host: %u link: %u priority set to: %u", host_id, link_id, link->priority); exit_unlock: pthread_rwlock_unlock(&knet_h->global_rwlock); errno = savederrno; return err; } int knet_link_get_priority(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, uint8_t *priority) { int savederrno = 0, err = 0; struct knet_host *host; struct knet_link *link; if (!knet_h) { errno = EINVAL; return -1; } if (link_id >= KNET_MAX_LINK) { errno = EINVAL; return -1; } if (!priority) { errno = EINVAL; return -1; } savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s", strerror(savederrno)); errno = savederrno; return -1; } host = knet_h->host_index[host_id]; if (!host) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s", host_id, strerror(savederrno)); goto exit_unlock; } link = &host->link[link_id]; if (!link->configured) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s", host_id, link_id, strerror(savederrno)); goto exit_unlock; } *priority = link->priority; exit_unlock: pthread_rwlock_unlock(&knet_h->global_rwlock); errno = savederrno; return err; } int knet_link_get_link_list(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t *link_ids, size_t *link_ids_entries) { int savederrno = 0, err = 0, i, count = 0; struct knet_host *host; struct knet_link *link; if (!knet_h) { errno = EINVAL; return -1; } if (!link_ids) { errno = EINVAL; return -1; } if (!link_ids_entries) { errno = EINVAL; return -1; } savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s", strerror(savederrno)); errno = savederrno; return -1; } host = knet_h->host_index[host_id]; if (!host) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s", host_id, strerror(savederrno)); goto exit_unlock; } for (i = 0; i < KNET_MAX_LINK; i++) { link = &host->link[i]; if (!link->configured) { continue; } link_ids[count] = i; count++; } *link_ids_entries = count; exit_unlock: pthread_rwlock_unlock(&knet_h->global_rwlock); errno = savederrno; return err; } int knet_link_get_status(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id, struct knet_link_status *status, size_t struct_size) { int savederrno = 0, err = 0; struct knet_host *host; struct knet_link *link; if (!knet_h) { errno = EINVAL; return -1; } if (link_id >= KNET_MAX_LINK) { errno = EINVAL; return -1; } if (!status) { errno = EINVAL; return -1; } savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, KNET_SUB_LINK, "Unable to get read lock: %s", strerror(savederrno)); errno = savederrno; return -1; } host = knet_h->host_index[host_id]; if (!host) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "Unable to find host %u: %s", host_id, strerror(savederrno)); goto exit_unlock; } link = &host->link[link_id]; if (!link->configured) { err = -1; savederrno = EINVAL; log_err(knet_h, KNET_SUB_LINK, "host %u link %u is not configured: %s", host_id, link_id, strerror(savederrno)); goto exit_unlock; } memmove(status, &link->status, struct_size); /* Calculate totals - no point in doing this on-the-fly */ status->stats.rx_total_packets = status->stats.rx_data_packets + status->stats.rx_ping_packets + status->stats.rx_pong_packets + status->stats.rx_pmtu_packets; status->stats.tx_total_packets = status->stats.tx_data_packets + status->stats.tx_ping_packets + status->stats.tx_pong_packets + status->stats.tx_pmtu_packets; status->stats.rx_total_bytes = status->stats.rx_data_bytes + status->stats.rx_ping_bytes + status->stats.rx_pong_bytes + status->stats.rx_pmtu_bytes; status->stats.tx_total_bytes = status->stats.tx_data_bytes + status->stats.tx_ping_bytes + status->stats.tx_pong_bytes + status->stats.tx_pmtu_bytes; status->stats.tx_total_errors = status->stats.tx_data_errors + status->stats.tx_ping_errors + status->stats.tx_pong_errors + status->stats.tx_pmtu_errors; status->stats.tx_total_retries = status->stats.tx_data_retries + status->stats.tx_ping_retries + status->stats.tx_pong_retries + status->stats.tx_pmtu_retries; /* Tell the caller our full size in case they have an old version */ status->size = sizeof(struct knet_link_status); exit_unlock: pthread_rwlock_unlock(&knet_h->global_rwlock); errno = savederrno; return err; } diff --git a/libknet/links.h b/libknet/links.h index 119470a7..bd1b3d7d 100644 --- a/libknet/links.h +++ b/libknet/links.h @@ -1,23 +1,23 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNET_LINK_H__ #define __KNET_LINK_H__ #include "internals.h" #define KNET_LINK_STATIC 0 /* link has static ip on both ends */ #define KNET_LINK_DYNIP 1 /* link has dynamic destination ip */ int _link_updown(knet_handle_t knet_h, knet_node_id_t node_id, uint8_t link_id, unsigned int enabled, unsigned int connected); void _link_clear_stats(knet_handle_t knet_h); #endif diff --git a/libknet/logging.c b/libknet/logging.c index 3b7e2ffd..785b9fbb 100644 --- a/libknet/logging.c +++ b/libknet/logging.c @@ -1,256 +1,256 @@ /* - * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 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 <strings.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <stdarg.h> #include <errno.h> #include <stdio.h> #include "internals.h" #include "logging.h" struct pretty_names { const char *name; uint8_t val; }; static struct pretty_names subsystem_names[] = { { "common", KNET_SUB_COMMON }, { "handle", KNET_SUB_HANDLE }, { "host", KNET_SUB_HOST }, { "listener", KNET_SUB_LISTENER }, { "link", KNET_SUB_LINK }, { "transport", KNET_SUB_TRANSPORT }, { "crypto", KNET_SUB_CRYPTO }, { "compress", KNET_SUB_COMPRESS }, { "filter", KNET_SUB_FILTER }, { "dstcache", KNET_SUB_DSTCACHE }, { "heartbeat", KNET_SUB_HEARTBEAT }, { "pmtud", KNET_SUB_PMTUD }, { "tx", KNET_SUB_TX }, { "rx", KNET_SUB_RX }, { "loopback", KNET_SUB_TRANSP_LOOPBACK }, { "udp", KNET_SUB_TRANSP_UDP }, { "sctp", KNET_SUB_TRANSP_SCTP }, { "nsscrypto", KNET_SUB_NSSCRYPTO }, { "opensslcrypto", KNET_SUB_OPENSSLCRYPTO }, { "zlibcomp", KNET_SUB_ZLIBCOMP }, { "lz4comp", KNET_SUB_LZ4COMP }, { "lz4hccomp", KNET_SUB_LZ4HCCOMP }, { "lzo2comp", KNET_SUB_LZO2COMP }, { "lzmacomp", KNET_SUB_LZMACOMP }, { "bzip2comp", KNET_SUB_BZIP2COMP }, { "unknown", KNET_SUB_UNKNOWN } /* unknown MUST always be last in this array */ }; const char *knet_log_get_subsystem_name(uint8_t subsystem) { unsigned int i; for (i = 0; i < KNET_MAX_SUBSYSTEMS; i++) { if (subsystem_names[i].val == KNET_SUB_UNKNOWN) { break; } if (subsystem_names[i].val == subsystem) { return subsystem_names[i].name; } } return "unknown"; } uint8_t knet_log_get_subsystem_id(const char *name) { unsigned int i; for (i = 0; i < KNET_MAX_SUBSYSTEMS; i++) { if (subsystem_names[i].val == KNET_SUB_UNKNOWN) { break; } if (strcasecmp(name, subsystem_names[i].name) == 0) { return subsystem_names[i].val; } } return KNET_SUB_UNKNOWN; } static int is_valid_subsystem(uint8_t subsystem) { unsigned int i; for (i = 0; i < KNET_MAX_SUBSYSTEMS; i++) { if ((subsystem != KNET_SUB_UNKNOWN) && (subsystem_names[i].val == KNET_SUB_UNKNOWN)) { break; } if (subsystem_names[i].val == subsystem) { return 0; } } return -1; } static struct pretty_names loglevel_names[] = { { "ERROR", KNET_LOG_ERR }, { "WARNING", KNET_LOG_WARN }, { "info", KNET_LOG_INFO }, { "debug", KNET_LOG_DEBUG } }; const char *knet_log_get_loglevel_name(uint8_t level) { unsigned int i; for (i = 0; i <= KNET_LOG_DEBUG; i++) { if (loglevel_names[i].val == level) { return loglevel_names[i].name; } } return "ERROR"; } uint8_t knet_log_get_loglevel_id(const char *name) { unsigned int i; for (i = 0; i <= KNET_LOG_DEBUG; i++) { if (strcasecmp(name, loglevel_names[i].name) == 0) { return loglevel_names[i].val; } } return KNET_LOG_ERR; } int knet_log_set_loglevel(knet_handle_t knet_h, uint8_t subsystem, uint8_t level) { int savederrno = 0; if (!knet_h) { errno = EINVAL; return -1; } if (is_valid_subsystem(subsystem) < 0) { errno = EINVAL; return -1; } if (level > KNET_LOG_DEBUG) { errno = EINVAL; return -1; } savederrno = pthread_rwlock_wrlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, subsystem, "Unable to get write lock: %s", strerror(savederrno)); errno = savederrno; return -1; } knet_h->log_levels[subsystem] = level; pthread_rwlock_unlock(&knet_h->global_rwlock); return 0; } int knet_log_get_loglevel(knet_handle_t knet_h, uint8_t subsystem, uint8_t *level) { int savederrno = 0; if (!knet_h) { errno = EINVAL; return -1; } if (is_valid_subsystem(subsystem) < 0) { errno = EINVAL; return -1; } if (!level) { errno = EINVAL; return -1; } savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, subsystem, "Unable to get write lock: %s", strerror(savederrno)); errno = savederrno; return -1; } *level = knet_h->log_levels[subsystem]; pthread_rwlock_unlock(&knet_h->global_rwlock); return 0; } void log_msg(knet_handle_t knet_h, uint8_t subsystem, uint8_t msglevel, const char *fmt, ...) { va_list ap; struct knet_log_msg msg; size_t byte_cnt = 0; int len, err; if ((!knet_h) || (subsystem == KNET_MAX_SUBSYSTEMS) || (msglevel > knet_h->log_levels[subsystem])) return; /* * most logging calls will take place with locking in place. * if we get an EINVAL and locking is initialized, then * we are getting a real error and we need to stop */ err = pthread_rwlock_tryrdlock(&knet_h->global_rwlock); if ((err == EAGAIN) && (knet_h->lock_init_done)) return; if (knet_h->logfd <= 0) goto out_unlock; memset(&msg, 0, sizeof(struct knet_log_msg)); msg.subsystem = subsystem; msg.msglevel = msglevel; va_start(ap, fmt); vsnprintf(msg.msg, sizeof(msg.msg) - 2, fmt, ap); va_end(ap); len = strlen(msg.msg); msg.msg[len+1] = '\n'; while (byte_cnt < sizeof(struct knet_log_msg)) { len = write(knet_h->logfd, &msg, sizeof(struct knet_log_msg) - byte_cnt); if (len <= 0) { goto out_unlock; } byte_cnt += len; } out_unlock: /* * unlock only if we are holding the lock */ if (!err) pthread_rwlock_unlock(&knet_h->global_rwlock); return; } diff --git a/libknet/netutils.c b/libknet/netutils.c index fbd1f2cb..cd7b616a 100644 --- a/libknet/netutils.c +++ b/libknet/netutils.c @@ -1,167 +1,167 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <errno.h> #include <string.h> #include "internals.h" #include "netutils.h" static int is_v4_mapped(const struct sockaddr_storage *ss, socklen_t salen) { char map[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) ss; return memcmp(&addr6->sin6_addr, map, 12); } int cmpaddr(const struct sockaddr_storage *ss1, socklen_t sslen1, const struct sockaddr_storage *ss2, socklen_t sslen2) { int ss1_offset = 0, ss2_offset = 0; struct sockaddr_in6 *ss1_addr6 = (struct sockaddr_in6 *)ss1; struct sockaddr_in6 *ss2_addr6 = (struct sockaddr_in6 *)ss2; struct sockaddr_in *ss1_addr = (struct sockaddr_in *)ss1; struct sockaddr_in *ss2_addr = (struct sockaddr_in *)ss2; char *addr1, *addr2; if (ss1->ss_family == ss2->ss_family) { return memcmp(ss1, ss2, sslen1); } if (ss1->ss_family == AF_INET6) { if (is_v4_mapped(ss1, sslen1)) { return 1; } addr1 = (char *)&ss1_addr6->sin6_addr; ss1_offset = 12; } else { addr1 = (char *)&ss1_addr->sin_addr; } if (ss2->ss_family == AF_INET6) { if (is_v4_mapped(ss2, sslen2)) { return 1; } addr2 = (char *)&ss2_addr6->sin6_addr; ss2_offset = 12; } else { addr2 = (char *)&ss2_addr->sin_addr; } return memcmp(addr1+ss1_offset, addr2+ss2_offset, 4); } int cpyaddrport(struct sockaddr_storage *dst, const struct sockaddr_storage *src) { struct sockaddr_in6 *dst_addr6 = (struct sockaddr_in6 *)dst; struct sockaddr_in6 *src_addr6 = (struct sockaddr_in6 *)src; memset(dst, 0, sizeof(struct sockaddr_storage)); if (src->ss_family == AF_INET6) { dst->ss_family = src->ss_family; memmove(&dst_addr6->sin6_port, &src_addr6->sin6_port, sizeof(in_port_t)); memmove(&dst_addr6->sin6_addr, &src_addr6->sin6_addr, sizeof(struct in6_addr)); } else { memmove(dst, src, sizeof(struct sockaddr_in)); } return 0; } socklen_t sockaddr_len(const struct sockaddr_storage *ss) { if (ss->ss_family == AF_INET) { return sizeof(struct sockaddr_in); } else { return sizeof(struct sockaddr_in6); } } /* * exported APIs */ int knet_strtoaddr(const char *host, const char *port, struct sockaddr_storage *ss, socklen_t sslen) { int err; struct addrinfo hints; struct addrinfo *result = NULL; if (!host) { errno = EINVAL; return -1; } if (!port) { errno = EINVAL; return -1; } if (!ss) { errno = EINVAL; return -1; } if (!sslen) { errno = EINVAL; return -1; } memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; err = getaddrinfo(host, port, &hints, &result); if (!err) { memmove(ss, result->ai_addr, (sslen < result->ai_addrlen) ? sslen : result->ai_addrlen); freeaddrinfo(result); } return err; } int knet_addrtostr(const struct sockaddr_storage *ss, socklen_t sslen, char *addr_buf, size_t addr_buf_size, char *port_buf, size_t port_buf_size) { if (!ss) { errno = EINVAL; return -1; } if (!sslen) { errno = EINVAL; return -1; } if (!addr_buf) { errno = EINVAL; return -1; } if (!port_buf) { errno = EINVAL; return -1; } return getnameinfo((struct sockaddr *)ss, sockaddr_len(ss), addr_buf, addr_buf_size, port_buf, port_buf_size, NI_NUMERICHOST | NI_NUMERICSERV); } diff --git a/libknet/netutils.h b/libknet/netutils.h index 395fabb7..4522bb9d 100644 --- a/libknet/netutils.h +++ b/libknet/netutils.h @@ -1,19 +1,19 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNET_NETUTILS_H__ #define __KNET_NETUTILS_H__ #include <sys/socket.h> int cmpaddr(const struct sockaddr_storage *ss1, socklen_t sslen1, const struct sockaddr_storage *ss2, socklen_t sslen2); int cpyaddrport(struct sockaddr_storage *dst, const struct sockaddr_storage *src); socklen_t knet_sockaddr_len(const struct sockaddr_storage *ss); #endif diff --git a/libknet/tests/api_knet_handle_add_datafd.c b/libknet/tests/api_knet_handle_add_datafd.c index 14dd89ab..a9199cfe 100644 --- a/libknet/tests/api_knet_handle_add_datafd.c +++ b/libknet/tests/api_knet_handle_add_datafd.c @@ -1,224 +1,224 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static int private_data; static void sock_notify(void *pvt_data, int datafd, int8_t channel, uint8_t tx_rx, int error, int errorno) { return; } static void test(void) { knet_handle_t knet_h; int logfds[2]; int datafd = 0, i; int8_t channel = 0; int datafdmax[KNET_DATAFD_MAX]; int8_t channels[KNET_DATAFD_MAX]; printf("Test knet_handle_add_datafd incorrect knet_h\n"); if ((!knet_handle_add_datafd(NULL, &datafd, &channel)) || (errno != EINVAL)) { printf("knet_handle_add_datafd accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } printf("Test knet_handle_add_datafd with no datafd\n"); if ((!knet_handle_add_datafd(knet_h, NULL, &channel)) || (errno != EINVAL)) { printf("knet_handle_add_datafd accepted invalid datafd or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_add_datafd with no channel\n"); if ((!knet_handle_add_datafd(knet_h, &datafd, NULL)) || (errno != EINVAL)) { printf("knet_handle_add_datafd accepted invalid channel or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_add_datafd with invalid channel\n"); channel = KNET_DATAFD_MAX; if ((!knet_handle_add_datafd(knet_h, &datafd, &channel)) || (errno != EINVAL)) { printf("knet_handle_add_datafd accepted invalid channel or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_add_datafd with no socknotify\n"); datafd = 0; channel = -1; if ((!knet_handle_add_datafd(knet_h, &datafd, &channel)) || (errno != EINVAL)) { printf("knet_handle_add_datafd accepted invalid channel or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_add_datafd with automatic config values\n"); if (knet_handle_enable_sock_notify(knet_h, &private_data, sock_notify) < 0) { printf("knet_handle_enable_sock_notify failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } datafd = 0; channel = -1; if (knet_handle_add_datafd(knet_h, &datafd, &channel) < 0) { printf("knet_handle_add_datafd failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } printf("got datafd: %d channel: %d\n", datafd, channel); flush_logs(logfds[0], stdout); printf("Test knet_handle_add_datafd with duplicated datafd\n"); if ((!knet_handle_add_datafd(knet_h, &datafd, &channel)) || (errno != EEXIST)) { printf("knet_handle_add_datafd accepted duplicated datafd or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_add_datafd with busy channel\n"); datafd = datafd + 1; if ((!knet_handle_add_datafd(knet_h, &datafd, &channel)) || (errno != EBUSY)) { printf("knet_handle_add_datafd accepted duplicated datafd or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } datafd = datafd - 1; if (knet_handle_remove_datafd(knet_h, datafd) < 0) { printf("knet_handle_remove_datafd failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_add_datafd with no available channels\n"); for (i = 0; i < KNET_DATAFD_MAX; i++) { datafdmax[i] = 0; channels[i] = -1; if (knet_handle_add_datafd(knet_h, &datafdmax[i], &channels[i]) < 0) { printf("knet_handle_add_datafd failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } } datafd = 0; channel = -1; if ((!knet_handle_add_datafd(knet_h, &datafd, &channel)) || (errno != EBUSY)) { printf("knet_handle_add_datafd accepted entry with no available channels or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } for (i = 0; i < KNET_DATAFD_MAX; i++) { if (knet_handle_remove_datafd(knet_h, datafdmax[i]) < 0) { printf("knet_handle_remove_datafd failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } } flush_logs(logfds[0], stdout); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_handle_clear_stats.c b/libknet/tests/api_knet_handle_clear_stats.c index 7a5e92b6..7166baa5 100644 --- a/libknet/tests/api_knet_handle_clear_stats.c +++ b/libknet/tests/api_knet_handle_clear_stats.c @@ -1,282 +1,282 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <inttypes.h> #include "libknet.h" #include "internals.h" #include "netutils.h" #include "test-common.h" static int private_data; static void sock_notify(void *pvt_data, int datafd, int8_t channel, uint8_t tx_rx, int error, int errorno) { return; } static void test(void) { knet_handle_t knet_h; int logfds[2]; int datafd = 0; int8_t channel = 0; struct knet_link_status link_status; char send_buff[KNET_MAX_PACKET_SIZE]; char recv_buff[KNET_MAX_PACKET_SIZE]; ssize_t send_len = 0; int recv_len = 0; int savederrno; struct sockaddr_storage lo; if (make_local_sockaddr(&lo, 0) < 0) { printf("Unable to convert loopback to sockaddr: %s\n", strerror(errno)); exit(FAIL); } memset(send_buff, 0, sizeof(send_buff)); printf("Test knet_handle_clear_stats incorrect knet_h\n"); if (!knet_handle_clear_stats(NULL, 0) || (errno != EINVAL)) { printf("knet_handle_clear_stats accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } printf("Test knet_send with valid data\n"); if (knet_handle_enable_sock_notify(knet_h, &private_data, sock_notify) < 0) { printf("knet_handle_enable_sock_notify failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } datafd = 0; channel = -1; if (knet_handle_add_datafd(knet_h, &datafd, &channel) < 0) { printf("knet_handle_add_datafd failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_host_add(knet_h, 1) < 0) { printf("knet_host_add failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_link_set_config(knet_h, 1, 0, KNET_TRANSPORT_UDP, &lo, &lo, 0) < 0) { printf("Unable to configure link: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_link_set_enable(knet_h, 1, 0, 1) < 0) { printf("knet_link_set_enable failed: %s\n", strerror(errno)); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_handle_setfwd(knet_h, 1) < 0) { printf("knet_handle_setfwd failed: %s\n", strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } while(knet_h->host_index[1]->status.reachable != 1) { printf("waiting host to be reachable\n"); sleep(1); } send_len = knet_send(knet_h, send_buff, KNET_MAX_PACKET_SIZE, channel); if (send_len <= 0) { printf("knet_send failed: %s\n", strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (send_len != sizeof(send_buff)) { printf("knet_send sent only %zd bytes: %s\n", send_len, strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); sleep(1); recv_len = knet_recv(knet_h, recv_buff, KNET_MAX_PACKET_SIZE, channel); savederrno = errno; if (recv_len != send_len) { printf("knet_recv received only %d bytes: %s (errno: %d)\n", recv_len, strerror(errno), errno); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); if ((is_helgrind()) && (recv_len == -1) && (savederrno == EAGAIN)) { printf("helgrind exception. this is normal due to possible timeouts\n"); exit(PASS); } exit(FAIL); } if (memcmp(recv_buff, send_buff, KNET_MAX_PACKET_SIZE)) { printf("recv and send buffers are different!\n"); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } /* A sanity check on the stats */ if (knet_link_get_status(knet_h, 1, 0, &link_status, sizeof(link_status)) < 0) { printf("knet_link_get_status failed: %s\n", strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (link_status.stats.tx_data_packets != 2 || link_status.stats.rx_data_packets != 2 || link_status.stats.tx_data_bytes < KNET_MAX_PACKET_SIZE || link_status.stats.rx_data_bytes < KNET_MAX_PACKET_SIZE || link_status.stats.tx_data_bytes > KNET_MAX_PACKET_SIZE*2 || link_status.stats.rx_data_bytes > KNET_MAX_PACKET_SIZE*2) { printf("stats look wrong: tx_packets: %" PRIu64 " (%" PRIu64 " bytes), rx_packets: %" PRIu64 " (%" PRIu64 " bytes)\n", link_status.stats.tx_data_packets, link_status.stats.tx_data_bytes, link_status.stats.rx_data_packets, link_status.stats.rx_data_bytes); } printf("Test knet_clear_stats (link)\n"); if (knet_handle_clear_stats(knet_h, KNET_CLEARSTATS_HANDLE_AND_LINK) < 0) { printf("knet_link_clear_stats failed: %s\n", strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } /* Check they've been cleared */ if (knet_link_get_status(knet_h, 1, 0, &link_status, sizeof(link_status)) < 0) { printf("knet_link_get_status failed: %s\n", strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (link_status.stats.tx_data_packets != 0 || link_status.stats.rx_data_packets != 0 || link_status.stats.tx_data_bytes != 0 || link_status.stats.rx_data_bytes != 0 || link_status.stats.tx_data_bytes != 0 || link_status.stats.rx_data_bytes != 0) { printf("stats not cleared: tx_packets: %" PRIu64 " (%" PRIu64 " bytes), rx_packets: %" PRIu64 " (%" PRIu64 " bytes)\n", link_status.stats.tx_data_packets, link_status.stats.tx_data_bytes, link_status.stats.rx_data_packets, link_status.stats.rx_data_bytes); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_handle_enable_pmtud_notify.c b/libknet/tests/api_knet_handle_enable_pmtud_notify.c index 1d458b7f..818c0541 100644 --- a/libknet/tests/api_knet_handle_enable_pmtud_notify.c +++ b/libknet/tests/api_knet_handle_enable_pmtud_notify.c @@ -1,149 +1,149 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static int private_data; static void pmtud_notify(void *priv_data, unsigned int data_mtu) { return; } static void test(void) { knet_handle_t knet_h; int logfds[2]; printf("Test knet_handle_enable_pmtud_notify incorrect knet_h\n"); if ((!knet_handle_enable_pmtud_notify(NULL, NULL, pmtud_notify)) || (errno != EINVAL)) { printf("knet_handle_enable_pmtud_notify accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } printf("Test knet_handle_enable_pmtud_notify with no private_data\n"); if (knet_handle_enable_pmtud_notify(knet_h, NULL, pmtud_notify) < 0) { printf("knet_handle_enable_pmtud_notify failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_h->pmtud_notify_fn_private_data != NULL) { printf("knet_handle_enable_pmtud_notify failed to unset private_data"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_enable_pmtud_notify with private_data\n"); if (knet_handle_enable_pmtud_notify(knet_h, &private_data, NULL) < 0) { printf("knet_handle_enable_pmtud_notify failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_h->pmtud_notify_fn_private_data != &private_data) { printf("knet_handle_enable_pmtud_notify failed to set private_data"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_enable_pmtud_notify with no pmtud_notify fn\n"); if (knet_handle_enable_pmtud_notify(knet_h, NULL, NULL) < 0) { printf("knet_handle_enable_pmtud_notify failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_h->pmtud_notify_fn != NULL) { printf("knet_handle_enable_pmtud_notify failed to unset pmtud_notify fn"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_enable_pmtud_notify with pmtud_notify fn\n"); if (knet_handle_enable_pmtud_notify(knet_h, NULL, pmtud_notify) < 0) { printf("knet_handle_enable_pmtud_notify failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_h->pmtud_notify_fn != &pmtud_notify) { printf("knet_handle_enable_pmtud_notify failed to set pmtud_notify fn"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_handle_enable_sock_notify.c b/libknet/tests/api_knet_handle_enable_sock_notify.c index 0c0b2efd..a545dcd1 100644 --- a/libknet/tests/api_knet_handle_enable_sock_notify.c +++ b/libknet/tests/api_knet_handle_enable_sock_notify.c @@ -1,144 +1,144 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static int private_data; static void sock_notify(void *pvt_data, int datafd, int8_t channel, uint8_t tx_rx, int error, int errorno) { return; } static void test(void) { knet_handle_t knet_h; int logfds[2]; printf("Test knet_handle_enable_sock_notify incorrect knet_h\n"); if ((!knet_handle_enable_sock_notify(NULL, NULL, sock_notify)) || (errno != EINVAL)) { printf("knet_handle_enable_sock_notify accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } printf("Test knet_handle_enable_sock_notify with no private_data\n"); if (knet_handle_enable_sock_notify(knet_h, NULL, sock_notify) < 0) { printf("knet_handle_enable_sock_notify failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_h->sock_notify_fn_private_data != NULL) { printf("knet_handle_enable_sock_notify failed to unset private_data"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_enable_sock_notify with private_data\n"); if (knet_handle_enable_sock_notify(knet_h, &private_data, sock_notify) < 0) { printf("knet_handle_enable_sock_notify failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_h->sock_notify_fn_private_data != &private_data) { printf("knet_handle_enable_sock_notify failed to set private_data"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_enable_sock_notify with no sock_notify fn\n"); if ((!knet_handle_enable_sock_notify(knet_h, NULL, NULL)) || (errno != EINVAL)) { printf("knet_handle_enable_sock_notify accepted invalid sock_notify or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_enable_sock_notify with sock_notify fn\n"); if (knet_handle_enable_sock_notify(knet_h, NULL, sock_notify) < 0) { printf("knet_handle_enable_sock_notify failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_h->sock_notify_fn != &sock_notify) { printf("knet_handle_enable_sock_notify failed to set sock_notify fn"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_handle_free.c b/libknet/tests/api_knet_handle_free.c index 907dbb9a..54dfe552 100644 --- a/libknet/tests/api_knet_handle_free.c +++ b/libknet/tests/api_knet_handle_free.c @@ -1,90 +1,90 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; setup_logpipes(logfds); printf("Test knet_handle_free with invalid knet_h\n"); if ((!knet_handle_free(NULL)) || (errno != EINVAL)) { printf("knet_handle_free failed to detect invalid parameter\n"); exit(FAIL); } printf("Test knet_handle_free with one host configured\n"); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_host_add(knet_h, 1) < 0) { printf("Unable to add new knet_host: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if ((!knet_handle_free(knet_h)) || (errno != EBUSY)) { printf("knet_handle_free didn't return error or correct errno with one host configured: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); if (knet_host_remove(knet_h, 1) < 0) { printf("Unable to remove knet_host: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_handle_free(knet_h) < 0) { printf("knet_handle_free failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_handle_get_channel.c b/libknet/tests/api_knet_handle_get_channel.c index 07770d21..8f6089c3 100644 --- a/libknet/tests/api_knet_handle_get_channel.c +++ b/libknet/tests/api_knet_handle_get_channel.c @@ -1,152 +1,152 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static int private_data; static void sock_notify(void *pvt_data, int datafd, int8_t channel, uint8_t tx_rx, int error, int errorno) { return; } static void test(void) { knet_handle_t knet_h; int logfds[2]; int datafd = 0; int8_t channel = 0, old_channel = 0; printf("Test knet_handle_get_channel incorrect knet_h\n"); if ((!knet_handle_get_channel(NULL, datafd, &channel)) || (errno != EINVAL)) { printf("knet_handle_get_channel accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } printf("Test knet_handle_get_channel with invalid datafd\n"); datafd = 0; if ((!knet_handle_get_channel(knet_h, datafd, &channel)) || (errno != EINVAL)) { printf("knet_handle_get_channel accepted invalid datafd or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_get_channel with invalid channel\n"); datafd = 10; if ((!knet_handle_get_channel(knet_h, datafd, NULL)) || (errno != EINVAL)) { printf("knet_handle_get_channel accepted invalid channel or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_get_channel with unconfigured datafd/channel\n"); datafd = 10; if ((!knet_handle_get_channel(knet_h, datafd, &channel)) || (errno != EINVAL)) { printf("knet_handle_get_channel accepted invalid channel or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_get_channel with valid datafd\n"); if (knet_handle_enable_sock_notify(knet_h, &private_data, sock_notify) < 0) { printf("knet_handle_enable_sock_notify failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } datafd = 0; old_channel = -1; if (knet_handle_add_datafd(knet_h, &datafd, &old_channel) < 0) { printf("knet_handle_add_datafd failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_handle_get_channel(knet_h, datafd, &channel) < 0) { printf("knet_handle_get_channel failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (old_channel != channel) { printf("knet_handle_get_channel got incorrect channel\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_handle_get_datafd.c b/libknet/tests/api_knet_handle_get_datafd.c index 3e536269..674662d7 100644 --- a/libknet/tests/api_knet_handle_get_datafd.c +++ b/libknet/tests/api_knet_handle_get_datafd.c @@ -1,152 +1,152 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static int private_data; static void sock_notify(void *pvt_data, int datafd, int8_t channel, uint8_t tx_rx, int error, int errorno) { return; } static void test(void) { knet_handle_t knet_h; int logfds[2]; int datafd = 0, old_datafd; int8_t channel = 0; printf("Test knet_handle_get_datafd incorrect knet_h\n"); if ((!knet_handle_get_datafd(NULL, channel, &datafd)) || (errno != EINVAL)) { printf("knet_handle_get_datafd accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } printf("Test knet_handle_get_datafd with invalid channel (< 0)\n"); channel = 0; if ((!knet_handle_get_datafd(knet_h, channel, &datafd)) || (errno != EINVAL)) { printf("knet_handle_get_datafd accepted invalid channel or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_get_datafd with invalid channel (KNET_DATAFD_MAX)\n"); channel = KNET_DATAFD_MAX; if ((!knet_handle_get_datafd(knet_h, channel, &datafd)) || (errno != EINVAL)) { printf("knet_handle_get_datafd accepted invalid channel or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_get_datafd with unconfigured datafd/channel\n"); channel = 10; if ((!knet_handle_get_datafd(knet_h, channel, &datafd)) || (errno != EINVAL)) { printf("knet_handle_get_datafd accepted unconfigured channel or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_get_datafd with valid datafd\n"); if (knet_handle_enable_sock_notify(knet_h, &private_data, sock_notify) < 0) { printf("knet_handle_enable_sock_notify failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } old_datafd = 0; channel = -1; if (knet_handle_add_datafd(knet_h, &old_datafd, &channel) < 0) { printf("knet_handle_add_datafd failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_handle_get_datafd(knet_h, channel, &datafd) < 0) { printf("knet_handle_get_datafd failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (old_datafd != datafd) { printf("knet_handle_get_datafd got incorrect channel\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_handle_get_stats.c b/libknet/tests/api_knet_handle_get_stats.c index 9efbb649..8b455593 100644 --- a/libknet/tests/api_knet_handle_get_stats.c +++ b/libknet/tests/api_knet_handle_get_stats.c @@ -1,110 +1,110 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "link.h" #include "netutils.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; struct knet_handle_stats test_byte_array[2]; struct knet_handle_stats ref_byte_array[2]; struct knet_handle_stats stats; printf("Test knet_handle_get_stats incorrect knet_h\n"); memset(&stats, 0, sizeof(struct knet_handle_stats)); if ((!knet_handle_get_stats(NULL, &stats, sizeof(struct knet_handle_stats))) || (errno != EINVAL)) { printf("knet_handle_get_stats accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } printf("Test knet_handle_get_stats with NULL structure pointer\n"); if ((!knet_handle_get_stats(knet_h, NULL, 0) || (errno != EINVAL))) { printf("knet_handle_get_stats accepted invalid stats address or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_get_stats with small structure size\n"); memset(test_byte_array, 0x55, sizeof(struct knet_handle_stats) * 2); memset(ref_byte_array, 0x55, sizeof(struct knet_handle_stats) * 2); if (knet_handle_get_stats(knet_h, (struct knet_handle_stats *)test_byte_array, sizeof(size_t)) < 0) { printf("knet_handle_get_stats failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (memcmp(&test_byte_array[1], ref_byte_array, sizeof(struct knet_handle_stats))) { printf("knet_handle_get_stats corrupted memory after stats structure\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_get_stats with valid input\n"); if (knet_handle_get_stats(knet_h, &stats, sizeof(struct knet_handle_stats)) < 0) { printf("knet_handle_get_stats failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_handle_get_transport_id_by_name.c b/libknet/tests/api_knet_handle_get_transport_id_by_name.c index a7ce4100..ef326873 100644 --- a/libknet/tests/api_knet_handle_get_transport_id_by_name.c +++ b/libknet/tests/api_knet_handle_get_transport_id_by_name.c @@ -1,95 +1,95 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; uint8_t id; printf("Test knet_handle_get_transport_id_by_name with incorrect knet_h\n"); if ((knet_handle_get_transport_id_by_name(NULL, "UDP") != KNET_MAX_TRANSPORTS) || (errno != EINVAL)) { printf("knet_handle_get_transport_id_by_name accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } printf("Test knet_handle_get_transport_id_by_name with no name\n"); if ((knet_handle_get_transport_id_by_name(knet_h, NULL) != KNET_MAX_TRANSPORTS) || (errno != EINVAL)) { printf("knet_handle_get_transport_id_by_name accepted invalid transport or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_get_transport_id_by_name with incorrect name\n"); if ((knet_handle_get_transport_id_by_name(knet_h, "ARP") != KNET_MAX_TRANSPORTS) || (errno != EINVAL)) { printf("knet_handle_get_transport_id_by_name accepted invalid transport or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_get_transport_id_by_name with correct values\n"); id = knet_handle_get_transport_id_by_name(knet_h, "UDP"); if (id != KNET_TRANSPORT_UDP) { printf("knet_handle_get_transport_id_by_name failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_handle_get_transport_name_by_id.c b/libknet/tests/api_knet_handle_get_transport_name_by_id.c index 2a02f05a..f315407b 100644 --- a/libknet/tests/api_knet_handle_get_transport_name_by_id.c +++ b/libknet/tests/api_knet_handle_get_transport_name_by_id.c @@ -1,91 +1,91 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; const char *name = NULL; printf("Test knet_handle_get_transport_name_by_id with incorrect knet_h\n"); if ((knet_handle_get_transport_name_by_id(NULL, KNET_TRANSPORT_UDP) != NULL) || (errno != EINVAL)) { printf("knet_handle_get_transport_name_by_id accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } printf("Test knet_handle_get_transport_name_by_id with incorrect transport\n"); if ((knet_handle_get_transport_name_by_id(knet_h, KNET_MAX_TRANSPORTS) != NULL) || (errno != EINVAL)) { printf("knet_handle_get_transport_name_by_id accepted invalid transport or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_get_transport_name_by_id with correct values\n"); name = knet_handle_get_transport_name_by_id(knet_h, KNET_TRANSPORT_UDP); if (!name) { printf("knet_handle_get_transport_name_by_id failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); if (strcmp(name, "UDP")) { printf("knet_handle_get_transport_name_by_id failed to get UDP transport name\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_handle_get_transport_reconnect_interval.c b/libknet/tests/api_knet_handle_get_transport_reconnect_interval.c index a3acd1cb..b77ddad7 100644 --- a/libknet/tests/api_knet_handle_get_transport_reconnect_interval.c +++ b/libknet/tests/api_knet_handle_get_transport_reconnect_interval.c @@ -1,90 +1,90 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; uint32_t msecs = 0; printf("Test knet_handle_get_transport_reconnect_interval with incorrect knet_h\n"); if ((!knet_handle_get_transport_reconnect_interval(NULL, &msecs)) || (errno != EINVAL)) { printf("knet_handle_get_transport_reconnect_interval accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } printf("Test knet_handle_get_transport_reconnect_interval with incorrect msecs\n"); if ((!knet_handle_get_transport_reconnect_interval(knet_h, NULL)) || (errno != EINVAL)) { printf("knet_handle_get_transport_reconnect_interval accepted invalid msecs or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_get_transport_reconnect_interval with correct values\n"); if (knet_handle_get_transport_reconnect_interval(knet_h, &msecs) < 0) { printf("knet_handle_get_transport_reconnect_interval failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); if (msecs != KNET_TRANSPORT_DEFAULT_RECONNECT_INTERVAL) { printf("knet_handle_get_transport_reconnect_interval failed to set correct value\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_handle_pmtud_get.c b/libknet/tests/api_knet_handle_pmtud_get.c index b2172400..bb476e0c 100644 --- a/libknet/tests/api_knet_handle_pmtud_get.c +++ b/libknet/tests/api_knet_handle_pmtud_get.c @@ -1,87 +1,87 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; unsigned int data_mtu; printf("Test knet_handle_pmtud_get incorrect knet_h\n"); if ((!knet_handle_pmtud_get(NULL, &data_mtu)) || (errno != EINVAL)) { printf("knet_handle_pmtud_get accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_pmtud_get with no data_mtu\n"); if ((!knet_handle_pmtud_get(knet_h, NULL)) || (errno != EINVAL)) { printf("knet_handle_pmtud_get accepted invalid data_mtu or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); if (knet_handle_pmtud_get(knet_h, &data_mtu) < 0) { printf("knet_handle_pmtud_get failed error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_h->data_mtu != data_mtu) { printf("knet_handle_pmtud_get failed to set the value\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_handle_pmtud_getfreq.c b/libknet/tests/api_knet_handle_pmtud_getfreq.c index 7c018eb9..2fa4d64a 100644 --- a/libknet/tests/api_knet_handle_pmtud_getfreq.c +++ b/libknet/tests/api_knet_handle_pmtud_getfreq.c @@ -1,87 +1,87 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; unsigned int interval; printf("Test knet_handle_pmtud_getfreq incorrect knet_h\n"); if ((!knet_handle_pmtud_getfreq(NULL, &interval)) || (errno != EINVAL)) { printf("knet_handle_pmtud_getfreq accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_pmtud_getfreq with no interval\n"); if ((!knet_handle_pmtud_getfreq(knet_h, NULL)) || (errno != EINVAL)) { printf("knet_handle_pmtud_getfreq accepted invalid interval or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); if (knet_handle_pmtud_getfreq(knet_h, &interval) < 0) { printf("knet_handle_pmtud_getfreq failed error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_h->pmtud_interval != interval) { printf("knet_handle_pmtud_getfreq failed to set the value\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_handle_pmtud_setfreq.c b/libknet/tests/api_knet_handle_pmtud_setfreq.c index ac3fc86d..759c4f13 100644 --- a/libknet/tests/api_knet_handle_pmtud_setfreq.c +++ b/libknet/tests/api_knet_handle_pmtud_setfreq.c @@ -1,98 +1,98 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; printf("Test knet_handle_pmtud_setfreq incorrect knet_h\n"); if ((!knet_handle_pmtud_setfreq(NULL, 1)) || (errno != EINVAL)) { printf("knet_handle_pmtud_setfreq accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_pmtud_setfreq with 0 (incorrect)\n"); if ((!knet_handle_pmtud_setfreq(NULL, 0)) || (errno != EINVAL)) { printf("knet_handle_pmtud_setfreq accepted invalid PTMUd freq or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_pmtud_setfreq with 86401 (incorrect)\n"); if ((!knet_handle_pmtud_setfreq(NULL, 86401)) || (errno != EINVAL)) { printf("knet_handle_pmtud_setfreq accepted invalid PTMUd freq or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_pmtud_setfreq with 1 (correct)\n"); if (knet_handle_pmtud_setfreq(knet_h, 1) < 0) { printf("knet_handle_pmtud_setfreq failed error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_h->pmtud_interval != 1) { printf("knet_handle_pmtud_setfreq failed to set the value\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_handle_remove_datafd.c b/libknet/tests/api_knet_handle_remove_datafd.c index 1461852c..51285c6b 100644 --- a/libknet/tests/api_knet_handle_remove_datafd.c +++ b/libknet/tests/api_knet_handle_remove_datafd.c @@ -1,130 +1,130 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static int private_data; static void sock_notify(void *pvt_data, int datafd, int8_t channel, uint8_t tx_rx, int error, int errorno) { return; } static void test(void) { knet_handle_t knet_h; int logfds[2]; int datafd = 0; int8_t channel = 0; printf("Test knet_handle_remove_datafd incorrect knet_h\n"); if ((!knet_handle_remove_datafd(NULL, datafd)) || (errno != EINVAL)) { printf("knet_handle_remove_datafd accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } printf("Test knet_handle_remove_datafd with no datafd\n"); datafd = 0; if ((!knet_handle_remove_datafd(knet_h, datafd)) || (errno != EINVAL)) { printf("knet_handle_remove_datafd accepted invalid datafd or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_remove_datafd with invalid datafd\n"); datafd = 10; if ((!knet_handle_remove_datafd(knet_h, datafd)) || (errno != EINVAL)) { printf("knet_handle_remove_datafd accepted invalid channel or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_remove_datafd with valid datafd\n"); if (knet_handle_enable_sock_notify(knet_h, &private_data, sock_notify) < 0) { printf("knet_handle_enable_sock_notify failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } datafd = 0; channel = -1; if (knet_handle_add_datafd(knet_h, &datafd, &channel) < 0) { printf("knet_handle_add_datafd failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_handle_remove_datafd(knet_h, datafd) < 0) { printf("knet_handle_remove_datafd failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_handle_set_transport_reconnect_interval.c b/libknet/tests/api_knet_handle_set_transport_reconnect_interval.c index 563e88f0..e5296f24 100644 --- a/libknet/tests/api_knet_handle_set_transport_reconnect_interval.c +++ b/libknet/tests/api_knet_handle_set_transport_reconnect_interval.c @@ -1,89 +1,89 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; printf("Test knet_handle_set_transport_reconnect_interval with incorrect knet_h\n"); if ((!knet_handle_set_transport_reconnect_interval(NULL, 1000)) || (errno != EINVAL)) { printf("knet_handle_set_transport_reconnect_interval accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } printf("Test knet_handle_set_transport_reconnect_interval with incorrect msecs\n"); if ((!knet_handle_set_transport_reconnect_interval(knet_h, 0)) || (errno != EINVAL)) { printf("knet_handle_set_transport_reconnect_interval accepted invalid msecs or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_set_transport_reconnect_interval with correct values\n"); if (knet_handle_set_transport_reconnect_interval(knet_h, 2000) < 0) { printf("knet_handle_set_transport_reconnect_interval failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); if (knet_h->reconnect_int != 2000) { printf("knet_handle_set_transport_reconnect_interval failed to set correct value\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_handle_setfwd.c b/libknet/tests/api_knet_handle_setfwd.c index 438461cc..f0a177ee 100644 --- a/libknet/tests/api_knet_handle_setfwd.c +++ b/libknet/tests/api_knet_handle_setfwd.c @@ -1,109 +1,109 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; printf("Test knet_handle_setfwd with invalid knet_h\n"); if ((!knet_handle_setfwd(NULL, 0)) || (errno != EINVAL)) { printf("knet_handle_setfwd accepted invalid knet_h parameter\n"); exit(FAIL); } setup_logpipes(logfds); printf("Test knet_handle_setfwd with invalid param (2) \n"); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if ((!knet_handle_setfwd(knet_h, 2)) || (errno != EINVAL)) { printf("knet_handle_setfwd accepted invalid param for enabled: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_setfwd with valid param (1) \n"); if (knet_handle_setfwd(knet_h, 1) < 0) { printf("knet_handle_setfwd failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_h->enabled != 1) { printf("knet_handle_setfwd failed to set correct value"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_handle_setfwd with valid param (0) \n"); if (knet_handle_setfwd(knet_h, 0) < 0) { printf("knet_handle_setfwd failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_h->enabled != 0) { printf("knet_handle_setfwd failed to set correct value"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_host_get_name_by_host_id.c b/libknet/tests/api_knet_host_get_name_by_host_id.c index 03c93fa2..4988a962 100644 --- a/libknet/tests/api_knet_host_get_name_by_host_id.c +++ b/libknet/tests/api_knet_host_get_name_by_host_id.c @@ -1,109 +1,109 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; char name[KNET_MAX_HOST_LEN]; printf("Test knet_host_get_name_by_host_id incorrect knet_h\n"); if ((!knet_host_get_name_by_host_id(NULL, 1, name)) || (errno != EINVAL)) { printf("knet_host_get_name_by_host_id accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_host_get_name_by_host_id with incorrect hostid 1\n"); if ((!knet_host_get_name_by_host_id(knet_h, 1, name)) || (errno != EINVAL)) { printf("knet_host_get_name_by_host_id accepted invalid host_id or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_host_get_name_by_host_id with incorrect name\n"); if ((!knet_host_get_name_by_host_id(knet_h, 1, NULL)) || (errno != EINVAL)) { printf("knet_host_get_name_by_host_id accepted invalid name or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_host_get_name_by_host_id with correct values for hostid 1: "); if (knet_host_add(knet_h, 1) < 0) { printf("knet_host_add failed error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_host_get_name_by_host_id(knet_h, 1, name) < 0) { printf("knet_host_get_name_by_host_id faild to retrive name: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } printf("%s\n", name); flush_logs(logfds[0], stdout); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_host_get_policy.c b/libknet/tests/api_knet_host_get_policy.c index 6a7f5cda..0e9f6d1e 100644 --- a/libknet/tests/api_knet_host_get_policy.c +++ b/libknet/tests/api_knet_host_get_policy.c @@ -1,125 +1,125 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; uint8_t policy; printf("Test knet_host_get_policy incorrect knet_h\n"); if ((!knet_host_get_policy(NULL, 1, &policy)) || (errno != EINVAL)) { printf("knet_host_get_policy accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_host_get_policy incorrect host_id\n"); if ((!knet_host_get_policy(knet_h, 1, &policy)) || (errno != EINVAL)) { printf("knet_host_get_policy accepted invalid host_id or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_host_get_policy incorrect policy\n"); if ((!knet_host_get_policy(knet_h, 1, NULL)) || (errno != EINVAL)) { printf("knet_host_get_policy accepted invalid policy or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_host_get_policy correct policy\n"); if (knet_host_add(knet_h, 1) < 0) { printf("knet_host_add failed error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_host_set_policy(knet_h, 1, KNET_LINK_POLICY_RR) < 0) { printf("knet_host_set_policy failed to set RR policy for host 1: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_host_get_policy(knet_h, 1, &policy) < 0) { printf("knet_host_get_policy failed for host 1: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (policy != KNET_LINK_POLICY_RR) { printf("knet_host_get_policy policy for host 1 does not appear to be correct\n"); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_host_get_status.c b/libknet/tests/api_knet_host_get_status.c index f9b8ddd5..3c88ec97 100644 --- a/libknet/tests/api_knet_host_get_status.c +++ b/libknet/tests/api_knet_host_get_status.c @@ -1,108 +1,108 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "host.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; struct knet_host_status status; printf("Test knet_host_get_status incorrect knet_h\n"); memset(&status, 0, sizeof(struct knet_host_status)); if ((!knet_host_get_status(NULL, 1, &status)) || (errno != EINVAL)) { printf("knet_host_get_status accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } printf("Test knet_host_get_status with unconfigured host_id\n"); if ((!knet_host_get_status(knet_h, 1, &status)) || (errno != EINVAL)) { printf("knet_host_get_status accepted invalid host_id or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_host_get_status with incorrect status\n"); if (knet_host_add(knet_h, 1) < 0) { printf("knet_host_add failed error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if ((!knet_host_get_status(knet_h, 1, NULL)) || (errno != EINVAL)) { printf("knet_host_get_status accepted invalid status or returned incorrect error: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_host_get_status with correct values\n"); if (knet_host_get_status(knet_h, 1, &status) < 0) { printf("knet_host_get_status failed: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_host_set_name.c b/libknet/tests/api_knet_host_set_name.c index ffbde350..c21eda3f 100644 --- a/libknet/tests/api_knet_host_set_name.c +++ b/libknet/tests/api_knet_host_set_name.c @@ -1,179 +1,179 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; char longhostname[KNET_MAX_HOST_LEN+2]; printf("Test knet_host_set_name incorrect knet_h\n"); if ((!knet_host_set_name(NULL, 1, "test")) || (errno != EINVAL)) { printf("knet_host_set_name accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_host_set_name with incorrect hostid 1\n"); if ((!knet_host_set_name(knet_h, 2, "test")) || (errno != EINVAL)) { printf("knet_host_set_name accepted invalid host_id or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_host_set_name with correct values\n"); if (knet_host_add(knet_h, 1) < 0) { printf("knet_host_add failed error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_host_set_name(knet_h, 1, "test") < 0) { printf("knet_host_set_name failed: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (strcmp("test", knet_h->host_index[1]->name)) { printf("knet_host_set_name failed to copy name\n"); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_host_set_name with correct values (name change)\n"); if (knet_host_set_name(knet_h, 1, "tes") < 0) { printf("knet_host_set_name failed: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (strcmp("tes", knet_h->host_index[1]->name)) { printf("knet_host_set_name failed to change name\n"); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_host_set_name with NULL name\n"); if ((!knet_host_set_name(knet_h, 1, NULL)) || (errno != EINVAL)) { printf("knet_host_set_name accepted invalid name or returned incorrect error: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_host_set_name with duplicate name\n"); if (knet_host_add(knet_h, 2) < 0) { printf("knet_host_add failed error: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if ((!knet_host_set_name(knet_h, 2, "tes")) || (errno != EEXIST)) { printf("knet_host_set_name accepted duplicated name or returned incorrect error: %s\n", strerror(errno)); knet_host_remove(knet_h, 2); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } knet_host_remove(knet_h, 2); flush_logs(logfds[0], stdout); printf("Test knet_host_set_name with (too) long name\n"); memset(longhostname, 'a', sizeof(longhostname)); longhostname[KNET_MAX_HOST_LEN] = '\0'; if ((!knet_host_set_name(knet_h, 1, longhostname)) || (errno != EINVAL)) { printf("knet_host_set_name accepted invalid (too long) name or returned incorrect error: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_host_set_policy.c b/libknet/tests/api_knet_host_set_policy.c index f1d0ccf7..e7e481cf 100644 --- a/libknet/tests/api_knet_host_set_policy.c +++ b/libknet/tests/api_knet_host_set_policy.c @@ -1,115 +1,115 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; printf("Test knet_host_set_policy incorrect knet_h\n"); if ((!knet_host_set_policy(NULL, 1, KNET_LINK_POLICY_PASSIVE)) || (errno != EINVAL)) { printf("knet_host_set_policy accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_host_set_policy incorrect host_id\n"); if ((!knet_host_set_policy(knet_h, 1, KNET_LINK_POLICY_PASSIVE)) || (errno != EINVAL)) { printf("knet_host_set_policy accepted invalid host_id or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_host_set_policy incorrect policy\n"); if ((!knet_host_set_policy(knet_h, 1, KNET_LINK_POLICY_RR + 1)) || (errno != EINVAL)) { printf("knet_host_set_policy accepted invalid policy or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_host_set_policy correct policy\n"); if (knet_host_add(knet_h, 1) < 0) { printf("knet_host_add failed error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_host_set_policy(knet_h, 1, KNET_LINK_POLICY_RR) < 0) { printf("knet_host_set_policy failed to set RR policy for host 1: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_h->host_index[1]->link_handler_policy != KNET_LINK_POLICY_RR) { printf("knet_host_set_policy failed to set RR policy for host 1: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_link_clear_config.c b/libknet/tests/api_knet_link_clear_config.c index ab413f0c..f56de055 100644 --- a/libknet/tests/api_knet_link_clear_config.c +++ b/libknet/tests/api_knet_link_clear_config.c @@ -1,174 +1,174 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "internals.h" #include "link.h" #include "netutils.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; struct sockaddr_storage src, dst; if (make_local_sockaddr(&src, 0) < 0) { printf("Unable to convert src to sockaddr: %s\n", strerror(errno)); exit(FAIL); } if (make_local_sockaddr(&dst, 1) < 0) { printf("Unable to convert dst to sockaddr: %s\n", strerror(errno)); exit(FAIL); } printf("Test knet_link_clear_config incorrect knet_h\n"); if ((!knet_link_clear_config(NULL, 1, 0)) || (errno != EINVAL)) { printf("knet_link_clear_config accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } printf("Test knet_link_clear_config with unconfigured host_id\n"); if ((!knet_link_clear_config(knet_h, 1, 0)) || (errno != EINVAL)) { printf("knet_link_clear_config accepted invalid host_id or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_link_clear_config with incorrect linkid\n"); if (knet_host_add(knet_h, 1) < 0) { printf("Unable to add host_id 1: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if ((!knet_link_clear_config(knet_h, 1, KNET_MAX_LINK)) || (errno != EINVAL)) { printf("knet_link_clear_config accepted invalid linkid or returned incorrect error: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_link_clear_config with unconfigured linkid\n"); if ((!knet_link_clear_config(knet_h, 1, 0)) || (errno != EINVAL)) { printf("knet_link_clear_config accepted unconfigured linkid or returned incorrect error: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_link_clear_config with enabled linkid\n"); if (knet_link_set_config(knet_h, 1, 0, KNET_TRANSPORT_UDP, &src, &dst, 0) < 0) { printf("Unable to configure link: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_link_set_enable(knet_h, 1, 0, 1) < 0) { printf("Unable to enable link: %s\n", strerror(errno)); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if ((!knet_link_clear_config(knet_h, 1, 0) || (errno != EBUSY))) { printf("knet_link_clear_config accepted invalid enabled link or returned incorrect error: %s\n", strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_link_clear_config with correct data\n"); if (knet_link_set_enable(knet_h, 1, 0, 0) < 0) { printf("Unable to disable link: %s\n", strerror(errno)); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_link_clear_config(knet_h, 1, 0) < 0) { printf("Unable to clear link config: %s\n", strerror(errno)); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_log_get_loglevel.c b/libknet/tests/api_knet_log_get_loglevel.c index 60023a39..02bdc0af 100644 --- a/libknet/tests/api_knet_log_get_loglevel.c +++ b/libknet/tests/api_knet_log_get_loglevel.c @@ -1,102 +1,102 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/time.h> #include <sys/resource.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; uint8_t level; int logfds[2]; printf("Test knet_log_get_loglevel incorrect knet_h\n"); if ((!knet_log_get_loglevel(NULL, KNET_SUB_UNKNOWN, &level)) || (errno != EINVAL)) { printf("knet_log_get_loglevel accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); printf("Test knet_log_get_loglevel incorrect subsystem\n"); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_INFO); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if ((!knet_log_get_loglevel(knet_h, KNET_SUB_UNKNOWN - 1, &level)) || (errno != EINVAL)) { printf("knet_log_get_loglevel accepted invalid subsystem or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_log_get_loglevel incorrect log level\n"); if ((!knet_log_get_loglevel(knet_h, KNET_SUB_UNKNOWN, NULL)) || (errno != EINVAL)) { printf("knet_log_get_loglevel accepted invalid log level or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_log_get_loglevel with valid parameters\n"); if (knet_log_get_loglevel(knet_h, KNET_SUB_UNKNOWN, &level ) < 0) { printf("knet_log_get_loglevel failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_h->log_levels[KNET_SUB_UNKNOWN] != level) { printf("knet_log_get_loglevel failed to get the right value\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_log_get_loglevel_name.c b/libknet/tests/api_knet_log_get_loglevel_name.c index 6fe2a3d4..ce888102 100644 --- a/libknet/tests/api_knet_log_get_loglevel_name.c +++ b/libknet/tests/api_knet_log_get_loglevel_name.c @@ -1,47 +1,47 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "test-common.h" static void test(void) { const char *res; printf("Testing knet_log_get_loglevel_name normal lookup\n"); res = knet_log_get_loglevel_name(KNET_LOG_DEBUG); if (strcmp(res, "debug")) { printf("knet_log_get_loglevel_name failed to get correct log level name. got: %s expected: debug\n", res); exit(FAIL); } printf("Testing knet_log_get_loglevel_name bad lookup\n"); res = knet_log_get_loglevel_name(KNET_LOG_DEBUG+1); if (strcmp(res, "ERROR")) { printf("knet_log_get_loglevel_name failed to get correct log level name. got: %s expected: ERROR\n", res); exit(FAIL); } } int main(int argc, char *argv[]) { test(); return PASS; } diff --git a/libknet/tests/api_knet_log_get_subsystem_name.c b/libknet/tests/api_knet_log_get_subsystem_name.c index 307feadf..dcbea12d 100644 --- a/libknet/tests/api_knet_log_get_subsystem_name.c +++ b/libknet/tests/api_knet_log_get_subsystem_name.c @@ -1,55 +1,55 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "libknet.h" #include "test-common.h" static void test(void) { const char *res; printf("Testing knet_log_get_subsystem_name normal lookup\n"); res = knet_log_get_subsystem_name(KNET_SUB_NSSCRYPTO); if (strcmp(res, "nsscrypto")) { printf("knet_log_get_subsystem_name failed to get correct log subsystem name. got: %s expected: nsscrypto\n", res); exit(FAIL); } printf("Testing knet_log_get_subsystem_name bad lookup (within boundaries)\n"); res = knet_log_get_subsystem_name(KNET_SUB_UNKNOWN - 1); if (strcmp(res, "unknown")) { printf("knet_log_get_subsystem_name failed to get correct log subsystem name. got: %s expected: common\n", res); exit(FAIL); } printf("Testing knet_log_get_subsystem_name bad lookup (outside boundaries)\n"); res = knet_log_get_subsystem_name(KNET_MAX_SUBSYSTEMS); if (strcmp(res, "unknown")) { printf("knet_log_get_subsystem_name failed to get correct log subsystem name. got: %s expected: common\n", res); exit(FAIL); } } int main(int argc, char *argv[]) { test(); return PASS; } diff --git a/libknet/tests/api_knet_log_set_loglevel.c b/libknet/tests/api_knet_log_set_loglevel.c index cb5970d6..1eb32225 100644 --- a/libknet/tests/api_knet_log_set_loglevel.c +++ b/libknet/tests/api_knet_log_set_loglevel.c @@ -1,109 +1,109 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/time.h> #include <sys/resource.h> #include "libknet.h" #include "internals.h" #include "test-common.h" static void test(void) { knet_handle_t knet_h; int logfds[2]; printf("Test knet_log_set_loglevel incorrect knet_h\n"); if ((!knet_log_set_loglevel(NULL, KNET_SUB_COMMON, KNET_LOG_DEBUG)) || (errno != EINVAL)) { printf("knet_log_set_loglevel accepted invalid knet_h or returned incorrect error: %s\n", strerror(errno)); exit(FAIL); } setup_logpipes(logfds); printf("Test knet_log_set_loglevel incorrect subsystem\n"); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_INFO); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if ((!knet_log_set_loglevel(knet_h, KNET_SUB_UNKNOWN - 1, KNET_LOG_DEBUG)) || (errno != EINVAL)) { printf("knet_log_set_loglevel accepted invalid subsystem or returned incorrect error: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); knet_handle_free(knet_h); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_log_set_loglevel incorrect log level\n"); if ((!knet_log_set_loglevel(knet_h, KNET_SUB_UNKNOWN, KNET_LOG_DEBUG + 1)) || (errno != EINVAL)) { printf("knet_log_set_loglevel accepted invalid log level or returned incorrect error: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_log_set_loglevel with valid parameters\n"); if (knet_h->log_levels[KNET_SUB_UNKNOWN] != KNET_LOG_INFO) { printf("knet_handle_new did not init log_levels correctly?\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_log_set_loglevel(knet_h, KNET_SUB_UNKNOWN, KNET_LOG_DEBUG) < 0) { printf("knet_log_set_loglevel failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_h->log_levels[KNET_SUB_UNKNOWN] != KNET_LOG_DEBUG) { printf("knet_log_set_loglevel did not set log level correctly\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/api_knet_send_compress.c b/libknet/tests/api_knet_send_compress.c index 23572507..71bd7d9a 100644 --- a/libknet/tests/api_knet_send_compress.c +++ b/libknet/tests/api_knet_send_compress.c @@ -1,277 +1,277 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <inttypes.h> #include "libknet.h" #include "compress.h" #include "internals.h" #include "netutils.h" #include "test-common.h" static int private_data; static void sock_notify(void *pvt_data, int datafd, int8_t channel, uint8_t tx_rx, int error, int errorno) { return; } static void test(const char *model) { knet_handle_t knet_h; int logfds[2]; int datafd = 0; int8_t channel = 0; struct knet_handle_stats stats; char send_buff[KNET_MAX_PACKET_SIZE]; char recv_buff[KNET_MAX_PACKET_SIZE]; ssize_t send_len = 0; int recv_len = 0; int savederrno; struct sockaddr_storage lo; struct knet_handle_compress_cfg knet_handle_compress_cfg; if (make_local_sockaddr(&lo, 0) < 0) { printf("Unable to convert loopback to sockaddr: %s\n", strerror(errno)); exit(FAIL); } memset(send_buff, 0, sizeof(send_buff)); setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_send with %s and valid data\n", model); memset(&knet_handle_compress_cfg, 0, sizeof(struct knet_handle_compress_cfg)); strncpy(knet_handle_compress_cfg.compress_model, model, sizeof(knet_handle_compress_cfg.compress_model) - 1); knet_handle_compress_cfg.compress_level = 4; knet_handle_compress_cfg.compress_threshold = 0; if (knet_handle_compress(knet_h, &knet_handle_compress_cfg) < 0) { printf("knet_handle_compress did not accept zlib compress mode with compress level 1 cfg\n"); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_handle_enable_sock_notify(knet_h, &private_data, sock_notify) < 0) { printf("knet_handle_enable_sock_notify failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } datafd = 0; channel = -1; if (knet_handle_add_datafd(knet_h, &datafd, &channel) < 0) { printf("knet_handle_add_datafd failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_host_add(knet_h, 1) < 0) { printf("knet_host_add failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_link_set_config(knet_h, 1, 0, KNET_TRANSPORT_UDP, &lo, &lo, 0) < 0) { printf("Unable to configure link: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_link_set_enable(knet_h, 1, 0, 1) < 0) { printf("knet_link_set_enable failed: %s\n", strerror(errno)); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_handle_setfwd(knet_h, 1) < 0) { printf("knet_handle_setfwd failed: %s\n", strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } while(knet_h->host_index[1]->status.reachable != 1) { printf("waiting host to be reachable\n"); sleep(1); } send_len = knet_send(knet_h, send_buff, KNET_MAX_PACKET_SIZE, channel); if (send_len <= 0) { printf("knet_send failed: %s\n", strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (send_len != sizeof(send_buff)) { printf("knet_send sent only %zd bytes: %s\n", send_len, strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); sleep(1); recv_len = knet_recv(knet_h, recv_buff, KNET_MAX_PACKET_SIZE, channel); savederrno = errno; if (recv_len != send_len) { printf("knet_recv received only %d bytes: %s (errno: %d)\n", recv_len, strerror(errno), errno); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); if ((is_helgrind()) && (recv_len == -1) && (savederrno == EAGAIN)) { printf("helgrind exception. this is normal due to possible timeouts\n"); exit(PASS); } exit(FAIL); } if (memcmp(recv_buff, send_buff, KNET_MAX_PACKET_SIZE)) { printf("recv and send buffers are different!\n"); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } /* A sanity check on the stats */ if (knet_handle_get_stats(knet_h, &stats, sizeof(stats)) < 0) { printf("knet_handle_get_stats failed: %s\n", strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (strcmp(model, "none") == 0) { if (stats.tx_compressed_packets != 0 || stats.rx_compressed_packets != 0) { printf("stats look wrong: s/b all 0 for model 'none' tx_packets: %" PRIu64 " (%" PRIu64 "/%" PRIu64 " comp/uncomp), rx_packets: %" PRIu64 " (%" PRIu64 "/%" PRIu64 " comp/uncomp)\n", stats.tx_compressed_packets, stats.tx_compressed_size_bytes, stats.tx_compressed_original_bytes, stats.rx_compressed_packets, stats.rx_compressed_size_bytes, stats.rx_compressed_original_bytes); } } else { if (stats.tx_compressed_packets != 1 || stats.rx_compressed_packets != 1 || stats.tx_compressed_original_bytes < stats.tx_compressed_size_bytes || stats.tx_compressed_original_bytes < stats.tx_compressed_size_bytes) { printf("stats look wrong: tx_packets: %" PRIu64 " (%" PRIu64 "/%" PRIu64 " comp/uncomp), rx_packets: %" PRIu64 " (%" PRIu64 "/%" PRIu64 " comp/uncomp)\n", stats.tx_compressed_packets, stats.tx_compressed_size_bytes, stats.tx_compressed_original_bytes, stats.rx_compressed_packets, stats.rx_compressed_size_bytes, stats.rx_compressed_original_bytes); } } flush_logs(logfds[0], stdout); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test("none"); #ifdef BUILDCOMPZLIB test("zlib"); #endif #ifdef BUILDCOMPLZ4 test("lz4"); test("lz4hc"); #endif #ifdef BUILDCOMPLZO2 test("lzo2"); #endif #ifdef BUILDCOMPLZMA test("lzma"); #endif #ifdef BUILDCOMPBZIP2 test("bzip2"); #endif return PASS; } diff --git a/libknet/tests/api_knet_send_loopback.c b/libknet/tests/api_knet_send_loopback.c index f9028364..77c5589f 100644 --- a/libknet/tests/api_knet_send_loopback.c +++ b/libknet/tests/api_knet_send_loopback.c @@ -1,384 +1,384 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <inttypes.h> #include "libknet.h" #include "internals.h" #include "netutils.h" #include "test-common.h" static int private_data; static void sock_notify(void *pvt_data, int datafd, int8_t channel, uint8_t tx_rx, int error, int errorno) { return; } static int dhost_filter(void *pvt_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 *dst_channel, knet_node_id_t *dst_host_ids, size_t *dst_host_ids_entries) { dst_host_ids[0] = 1; *dst_host_ids_entries = 1; return 0; } static void test(void) { knet_handle_t knet_h; int logfds[2]; int datafd = 0; int8_t channel = 0; struct knet_link_status link_status; char send_buff[KNET_MAX_PACKET_SIZE]; char recv_buff[KNET_MAX_PACKET_SIZE]; ssize_t send_len = 0; int recv_len = 0; int savederrno; struct sockaddr_storage lo; if (make_local_sockaddr(&lo, 1) < 0) { printf("Unable to convert loopback to sockaddr: %s\n", strerror(errno)); exit(FAIL); } memset(send_buff, 0, sizeof(send_buff)); setup_logpipes(logfds); knet_h = knet_handle_new(1, logfds[1], KNET_LOG_DEBUG); if (!knet_h) { printf("knet_handle_new failed: %s\n", strerror(errno)); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test configuring multiple links with loopback\n"); if (knet_handle_enable_sock_notify(knet_h, &private_data, sock_notify) < 0) { printf("knet_handle_enable_sock_notify failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } datafd = 0; channel = -1; if (knet_handle_add_datafd(knet_h, &datafd, &channel) < 0) { printf("knet_handle_add_datafd failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_host_add(knet_h, 1) < 0) { printf("knet_host_add failed: %s\n", strerror(errno)); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_link_set_config(knet_h, 1, 0, KNET_TRANSPORT_LOOPBACK, &lo, &lo, 0) < 0) { printf("Unable to configure link: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_link_set_config(knet_h, 1, 1, KNET_TRANSPORT_LOOPBACK, &lo, &lo, 0) == 0) { printf("Managed to configure two LOOPBACK links - this is wrong\n"); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test configuring UDP link after loopback\n"); if (knet_link_set_config(knet_h, 1, 1, KNET_TRANSPORT_UDP, &lo, &lo, 0) == 0) { printf("Managed to configure UDP and LOOPBACK links together: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test configuring UDP link before loopback\n"); if (knet_link_clear_config(knet_h, 1, 0) < 0) { printf("Failed to clear existing LOOPBACK link: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_link_set_config(knet_h, 1, 0, KNET_TRANSPORT_UDP, &lo, &lo, 0) < 0) { printf("Failed to configure UDP link for testing: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_link_set_config(knet_h, 1, 1, KNET_TRANSPORT_LOOPBACK, &lo, &lo, 0) == 0) { printf("Managed to configure LOOPBACK link after UDP: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); printf("Test knet_send with valid data\n"); if (knet_link_clear_config(knet_h, 1, 0) < 0) { printf("Failed to clear existing UDP link: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_link_set_config(knet_h, 1, 0, KNET_TRANSPORT_LOOPBACK, &lo, &lo, 0) < 0) { printf("Failed configure LOOPBACK link for sending: %s\n", strerror(errno)); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_link_set_enable(knet_h, 1, 0, 1) < 0) { printf("knet_link_set_enable failed: %s\n", strerror(errno)); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (knet_handle_setfwd(knet_h, 1) < 0) { printf("knet_handle_setfwd failed: %s\n", strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } while(knet_h->host_index[1]->status.reachable != 1) { printf("waiting host to be reachable\n"); sleep(1); } send_len = knet_send(knet_h, send_buff, KNET_MAX_PACKET_SIZE, channel); if (send_len <= 0) { printf("knet_send failed: %s\n", strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (send_len != sizeof(send_buff)) { printf("knet_send sent only %zd bytes: %s\n", send_len, strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); sleep(1); recv_len = knet_recv(knet_h, recv_buff, KNET_MAX_PACKET_SIZE, channel); savederrno = errno; if (recv_len != send_len) { printf("knet_recv received only %d bytes: %s (errno: %d)\n", recv_len, strerror(errno), errno); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); if ((is_helgrind()) && (recv_len == -1) && (savederrno == EAGAIN)) { printf("helgrind exception. this is normal due to possible timeouts\n"); exit(PASS); } exit(FAIL); } if (memcmp(recv_buff, send_buff, KNET_MAX_PACKET_SIZE)) { printf("recv and send buffers are different!\n"); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } /* A sanity check on the stats */ if (knet_link_get_status(knet_h, 1, 0, &link_status, sizeof(link_status)) < 0) { printf("knet_link_get_status failed: %s\n", strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (link_status.stats.tx_data_packets != 1 || link_status.stats.rx_data_packets != 0 || link_status.stats.tx_data_bytes != KNET_MAX_PACKET_SIZE) { printf("stats look wrong: tx_packets: %" PRIu64 " (%" PRIu64 " bytes), rx_packets: %" PRIu64 " (%" PRIu64 " bytes)\n", link_status.stats.tx_data_packets, link_status.stats.tx_data_bytes, link_status.stats.rx_data_packets, link_status.stats.rx_data_bytes); } flush_logs(logfds[0], stdout); printf("Test knet_send with only localhost\n"); if (knet_handle_enable_filter(knet_h, NULL, dhost_filter) < 0) { printf("knet_handle_enable_filter failed: %s\n", strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } send_len = knet_send(knet_h, send_buff, KNET_MAX_PACKET_SIZE, channel); if (send_len <= 0) { printf("knet_send failed: %s\n", strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } if (send_len != sizeof(send_buff)) { printf("knet_send sent only %zd bytes: %s\n", send_len, strerror(errno)); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } flush_logs(logfds[0], stdout); sleep(1); recv_len = knet_recv(knet_h, recv_buff, KNET_MAX_PACKET_SIZE, channel); savederrno = errno; if (recv_len != send_len) { printf("knet_recv received only %d bytes: %s (errno: %d)\n", recv_len, strerror(errno), errno); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); if ((is_helgrind()) && (recv_len == -1) && (savederrno == EAGAIN)) { printf("helgrind exception. this is normal due to possible timeouts\n"); exit(PASS); } exit(FAIL); } if (memcmp(recv_buff, send_buff, KNET_MAX_PACKET_SIZE)) { printf("recv and send buffers are different!\n"); knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); exit(FAIL); } knet_link_set_enable(knet_h, 1, 0, 0); knet_link_clear_config(knet_h, 1, 0); knet_host_remove(knet_h, 1); knet_handle_free(knet_h); flush_logs(logfds[0], stdout); close_logpipes(logfds); } int main(int argc, char *argv[]) { need_root(); test(); return PASS; } diff --git a/libknet/tests/int_timediff.c b/libknet/tests/int_timediff.c index 16048bba..1e0ae9bd 100644 --- a/libknet/tests/int_timediff.c +++ b/libknet/tests/int_timediff.c @@ -1,60 +1,60 @@ /* - * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <stdio.h> #include <time.h> #include <stdlib.h> #include <pthread.h> #include "threads_common.h" #include "test-common.h" #define timespec_set(x, sec, nsec) \ do { \ x.tv_sec = sec; \ x.tv_nsec = nsec; \ } while (0); static void check_timespec_diff(void) { unsigned long long diff; struct timespec start, end; timespec_set(start, 1, 30000); timespec_set(end, start.tv_sec, start.tv_nsec + 10000); timespec_diff(start, end, &diff); printf("Checking 10000 == %llu\n", diff); if (diff != 10000) { printf("Failure!\n"); exit(FAIL); } timespec_set(end, start.tv_sec + 5, start.tv_nsec - 5000); timespec_diff(start, end, &diff); printf("Checking 4999995000 == %llu\n", diff); if (diff != 4999995000llu) { printf("Failure!\n"); exit(FAIL); } } int main(int argc, char *argv[]) { check_timespec_diff(); return PASS; } diff --git a/libknet/threads_common.c b/libknet/threads_common.c index 8afe1aa2..f40d68b5 100644 --- a/libknet/threads_common.c +++ b/libknet/threads_common.c @@ -1,38 +1,38 @@ /* - * Copyright (C) 2016 Red Hat, Inc. All rights reserved. + * Copyright (C) 2016-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <pthread.h> #include <errno.h> #include <string.h> #include "internals.h" #include "logging.h" #include "threads_common.h" int shutdown_in_progress(knet_handle_t knet_h) { int savederrno = 0; int ret; savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, KNET_SUB_COMMON, "Unable to get read lock: %s", strerror(savederrno)); errno = savederrno; return -1; } ret = knet_h->fini_in_progress; pthread_rwlock_unlock(&knet_h->global_rwlock); return ret; } diff --git a/libknet/threads_common.h b/libknet/threads_common.h index 2b617957..348fa05c 100644 --- a/libknet/threads_common.h +++ b/libknet/threads_common.h @@ -1,28 +1,28 @@ /* - * Copyright (C) 2015-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNET_THREADS_COMMON_H__ #define __KNET_THREADS_COMMON_H__ #include "internals.h" #define KNET_THREADS_TIMERES 200000 #define timespec_diff(start, end, diff) \ do { \ if (end.tv_sec > start.tv_sec) \ *(diff) = ((end.tv_sec - start.tv_sec) * 1000000000llu) \ + end.tv_nsec - start.tv_nsec; \ else \ *(diff) = end.tv_nsec - start.tv_nsec; \ } while (0); int shutdown_in_progress(knet_handle_t knet_h); #endif diff --git a/libknet/threads_dsthandler.h b/libknet/threads_dsthandler.h index 45de4784..4c59f51a 100644 --- a/libknet/threads_dsthandler.h +++ b/libknet/threads_dsthandler.h @@ -1,15 +1,15 @@ /* - * Copyright (C) 2015-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNET_THREADS_DSTHANDLER_H__ #define __KNET_THREADS_DSTHANDLER_H__ void *_handle_dst_link_handler_thread(void *data); #endif diff --git a/libknet/threads_heartbeat.h b/libknet/threads_heartbeat.h index 92c5cb80..88668844 100644 --- a/libknet/threads_heartbeat.h +++ b/libknet/threads_heartbeat.h @@ -1,16 +1,16 @@ /* - * Copyright (C) 2015-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNET_THREADS_HEARTBEAT_H__ #define __KNET_THREADS_HEARTBEAT_H__ void _send_pings(knet_handle_t knet_h, int timed); void *_handle_heartbt_thread(void *data); #endif diff --git a/libknet/threads_pmtud.h b/libknet/threads_pmtud.h index 4f8bf1e8..3c7fd16d 100644 --- a/libknet/threads_pmtud.h +++ b/libknet/threads_pmtud.h @@ -1,15 +1,15 @@ /* - * Copyright (C) 2015-2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNET_THREADS_PMTUD_H__ #define __KNET_THREADS_PMTUD_H__ void *_handle_pmtud_link_thread(void *data); #endif diff --git a/libknet/threads_rx.c b/libknet/threads_rx.c index 3761c151..12d6a171 100644 --- a/libknet/threads_rx.c +++ b/libknet/threads_rx.c @@ -1,820 +1,820 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <stdio.h> #include <string.h> #include <errno.h> #include <sys/uio.h> #include <pthread.h> #include "compat.h" #include "compress.h" #include "crypto.h" #include "host.h" #include "links.h" #include "logging.h" #include "transports.h" #include "threads_common.h" #include "threads_heartbeat.h" #include "threads_rx.h" #include "netutils.h" /* * RECV */ /* * return 1 if a > b * return -1 if b > a * return 0 if they are equal */ static inline int timecmp(struct timespec a, struct timespec b) { if (a.tv_sec != b.tv_sec) { if (a.tv_sec > b.tv_sec) { return 1; } else { return -1; } } else { if (a.tv_nsec > b.tv_nsec) { return 1; } else if (a.tv_nsec < b.tv_nsec) { return -1; } else { return 0; } } } /* * this functions needs to return an index (0 to 7) * to a knet_host_defrag_buf. (-1 on errors) */ static int find_pckt_defrag_buf(knet_handle_t knet_h, struct knet_header *inbuf) { struct knet_host *src_host = knet_h->host_index[inbuf->kh_node]; int i, oldest; /* * check if there is a buffer already in use handling the same seq_num */ for (i = 0; i < KNET_MAX_LINK; i++) { if (src_host->defrag_buf[i].in_use) { if (src_host->defrag_buf[i].pckt_seq == inbuf->khp_data_seq_num) { return i; } } } /* * If there is no buffer that's handling the current seq_num * either it's new or it's been reclaimed already. * check if it's been reclaimed/seen before using the defrag circular * buffer. If the pckt has been seen before, the buffer expired (ETIME) * and there is no point to try to defrag it again. */ if (!_seq_num_lookup(src_host, inbuf->khp_data_seq_num, 1, 0)) { errno = ETIME; return -1; } /* * register the pckt as seen */ _seq_num_set(src_host, inbuf->khp_data_seq_num, 1); /* * see if there is a free buffer */ for (i = 0; i < KNET_MAX_LINK; i++) { if (!src_host->defrag_buf[i].in_use) { return i; } } /* * at this point, there are no free buffers, the pckt is new * and we need to reclaim a buffer, and we will take the one * with the oldest timestamp. It's as good as any. */ oldest = 0; for (i = 0; i < KNET_MAX_LINK; i++) { if (timecmp(src_host->defrag_buf[i].last_update, src_host->defrag_buf[oldest].last_update) < 0) { oldest = i; } } src_host->defrag_buf[oldest].in_use = 0; return oldest; } static int pckt_defrag(knet_handle_t knet_h, struct knet_header *inbuf, ssize_t *len) { struct knet_host_defrag_buf *defrag_buf; int defrag_buf_idx; defrag_buf_idx = find_pckt_defrag_buf(knet_h, inbuf); if (defrag_buf_idx < 0) { if (errno == ETIME) { log_debug(knet_h, KNET_SUB_RX, "Defrag buffer expired"); } return 1; } defrag_buf = &knet_h->host_index[inbuf->kh_node]->defrag_buf[defrag_buf_idx]; /* * if the buf is not is use, then make sure it's clean */ if (!defrag_buf->in_use) { memset(defrag_buf, 0, sizeof(struct knet_host_defrag_buf)); defrag_buf->in_use = 1; defrag_buf->pckt_seq = inbuf->khp_data_seq_num; } /* * update timestamp on the buffer */ clock_gettime(CLOCK_MONOTONIC, &defrag_buf->last_update); /* * check if we already received this fragment */ if (defrag_buf->frag_map[inbuf->khp_data_frag_seq]) { /* * if we have received this fragment and we didn't clear the buffer * it means that we don't have all fragments yet */ return 1; } /* * we need to handle the last packet with gloves due to its different size */ if (inbuf->khp_data_frag_seq == inbuf->khp_data_frag_num) { defrag_buf->last_frag_size = *len; /* * in the event when the last packet arrives first, * we still don't know the offset vs the other fragments (based on MTU), * so we store the fragment at the end of the buffer where it's safe * and take a copy of the len so that we can restore its offset later. * remember we can't use the local MTU for this calculation because pMTU * can be asymettric between the same hosts. */ if (!defrag_buf->frag_size) { defrag_buf->last_first = 1; memmove(defrag_buf->buf + (KNET_MAX_PACKET_SIZE - *len), inbuf->khp_data_userdata, *len); } } else { defrag_buf->frag_size = *len; } memmove(defrag_buf->buf + ((inbuf->khp_data_frag_seq - 1) * defrag_buf->frag_size), inbuf->khp_data_userdata, *len); defrag_buf->frag_recv++; defrag_buf->frag_map[inbuf->khp_data_frag_seq] = 1; /* * check if we received all the fragments */ if (defrag_buf->frag_recv == inbuf->khp_data_frag_num) { /* * special case the last pckt */ if (defrag_buf->last_first) { memmove(defrag_buf->buf + ((inbuf->khp_data_frag_num - 1) * defrag_buf->frag_size), defrag_buf->buf + (KNET_MAX_PACKET_SIZE - defrag_buf->last_frag_size), defrag_buf->last_frag_size); } /* * recalculate packet lenght */ *len = ((inbuf->khp_data_frag_num - 1) * defrag_buf->frag_size) + defrag_buf->last_frag_size; /* * copy the pckt back in the user data */ memmove(inbuf->khp_data_userdata, defrag_buf->buf, *len); /* * free this buffer */ defrag_buf->in_use = 0; return 0; } return 1; } static void _parse_recv_from_links(knet_handle_t knet_h, int sockfd, const struct knet_mmsghdr *msg) { int err = 0, savederrno = 0; ssize_t outlen; struct knet_host *src_host; struct knet_link *src_link; unsigned long long latency_last; knet_node_id_t dst_host_ids[KNET_MAX_HOST]; size_t dst_host_ids_entries = 0; int bcast = 1; struct timespec recvtime; struct knet_header *inbuf = msg->msg_hdr.msg_iov->iov_base; unsigned char *outbuf = (unsigned char *)msg->msg_hdr.msg_iov->iov_base; ssize_t len = msg->msg_len; struct knet_hostinfo *knet_hostinfo; struct iovec iov_out[1]; int8_t channel; struct sockaddr_storage pckt_src; seq_num_t recv_seq_num; int wipe_bufs = 0; if (knet_h->crypto_instance) { struct timespec start_time; struct timespec end_time; uint64_t crypt_time; clock_gettime(CLOCK_MONOTONIC, &start_time); if (crypto_authenticate_and_decrypt(knet_h, (unsigned char *)inbuf, len, knet_h->recv_from_links_buf_decrypt, &outlen) < 0) { log_debug(knet_h, KNET_SUB_RX, "Unable to decrypt/auth packet"); return; } clock_gettime(CLOCK_MONOTONIC, &end_time); timespec_diff(start_time, end_time, &crypt_time); if (crypt_time < knet_h->stats.rx_crypt_time_min) { knet_h->stats.rx_crypt_time_min = crypt_time; } if (crypt_time > knet_h->stats.rx_crypt_time_max) { knet_h->stats.rx_crypt_time_max = crypt_time; } knet_h->stats.rx_crypt_time_ave = (knet_h->stats.rx_crypt_time_ave * knet_h->stats.rx_crypt_packets + crypt_time) / (knet_h->stats.rx_crypt_packets+1); knet_h->stats.rx_crypt_packets++; len = outlen; inbuf = (struct knet_header *)knet_h->recv_from_links_buf_decrypt; } if (len < (ssize_t)(KNET_HEADER_SIZE + 1)) { log_debug(knet_h, KNET_SUB_RX, "Packet is too short: %ld", (long)len); return; } if (inbuf->kh_version != KNET_HEADER_VERSION) { log_debug(knet_h, KNET_SUB_RX, "Packet version does not match"); return; } inbuf->kh_node = ntohs(inbuf->kh_node); src_host = knet_h->host_index[inbuf->kh_node]; if (src_host == NULL) { /* host not found */ log_debug(knet_h, KNET_SUB_RX, "Unable to find source host for this packet"); return; } src_link = NULL; src_link = src_host->link + (inbuf->khp_ping_link % KNET_MAX_LINK); if ((inbuf->kh_type & KNET_HEADER_TYPE_PMSK) != 0) { if (src_link->dynamic == KNET_LINK_DYNIP) { /* * cpyaddrport will only copy address and port of the incoming * packet and strip extra bits such as flow and scopeid */ cpyaddrport(&pckt_src, msg->msg_hdr.msg_name); if (cmpaddr(&src_link->dst_addr, sockaddr_len(&src_link->dst_addr), &pckt_src, sockaddr_len(&pckt_src)) != 0) { log_debug(knet_h, KNET_SUB_RX, "host: %u link: %u appears to have changed ip address", src_host->host_id, src_link->link_id); memmove(&src_link->dst_addr, &pckt_src, sizeof(struct sockaddr_storage)); if (knet_addrtostr(&src_link->dst_addr, sockaddr_len(msg->msg_hdr.msg_name), src_link->status.dst_ipaddr, KNET_MAX_HOST_LEN, src_link->status.dst_port, KNET_MAX_PORT_LEN) != 0) { log_debug(knet_h, KNET_SUB_RX, "Unable to resolve ???"); snprintf(src_link->status.dst_ipaddr, KNET_MAX_HOST_LEN - 1, "Unknown!!!"); snprintf(src_link->status.dst_port, KNET_MAX_PORT_LEN - 1, "??"); } else { log_info(knet_h, KNET_SUB_RX, "host: %u link: %u new connection established from: %s %s", src_host->host_id, src_link->link_id, src_link->status.dst_ipaddr, src_link->status.dst_port); } } /* * transport has already accepted the connection here * otherwise we would not be receiving packets */ knet_h->transport_ops[src_link->transport_type]->transport_link_dyn_connect(knet_h, sockfd, src_link); } } switch (inbuf->kh_type) { case KNET_HEADER_TYPE_HOST_INFO: case KNET_HEADER_TYPE_DATA: /* * TODO: should we accept data even if we can't reply to the other node? * how would that work with SCTP and guaranteed delivery? */ if (!src_host->status.reachable) { log_debug(knet_h, KNET_SUB_RX, "Source host %u not reachable yet", src_host->host_id); //return; } inbuf->khp_data_seq_num = ntohs(inbuf->khp_data_seq_num); channel = inbuf->khp_data_channel; src_host->got_data = 1; if (src_link) { src_link->status.stats.rx_data_packets++; src_link->status.stats.rx_data_bytes += len; } if (!_seq_num_lookup(src_host, inbuf->khp_data_seq_num, 0, 0)) { if (src_host->link_handler_policy != KNET_LINK_POLICY_ACTIVE) { log_debug(knet_h, KNET_SUB_RX, "Packet has already been delivered"); } return; } if (inbuf->khp_data_frag_num > 1) { /* * len as received from the socket also includes extra stuff * that the defrag code doesn't care about. So strip it * here and readd only for repadding once we are done * defragging */ len = len - KNET_HEADER_DATA_SIZE; if (pckt_defrag(knet_h, inbuf, &len)) { return; } len = len + KNET_HEADER_DATA_SIZE; } if (inbuf->khp_data_compress) { ssize_t decmp_outlen = KNET_DATABUFSIZE_COMPRESS; struct timespec start_time; struct timespec end_time; uint64_t compress_time; clock_gettime(CLOCK_MONOTONIC, &start_time); err = decompress(knet_h, inbuf->khp_data_compress, (const unsigned char *)inbuf->khp_data_userdata, len - KNET_HEADER_DATA_SIZE, knet_h->recv_from_links_buf_decompress, &decmp_outlen); if (!err) { /* Collect stats */ clock_gettime(CLOCK_MONOTONIC, &end_time); timespec_diff(start_time, end_time, &compress_time); if (compress_time < knet_h->stats.rx_compress_time_min) { knet_h->stats.rx_compress_time_min = compress_time; } if (compress_time > knet_h->stats.rx_compress_time_max) { knet_h->stats.rx_compress_time_max = compress_time; } knet_h->stats.rx_compress_time_ave = (knet_h->stats.rx_compress_time_ave * knet_h->stats.rx_compressed_packets + compress_time) / (knet_h->stats.rx_compressed_packets+1); knet_h->stats.rx_compressed_packets++; knet_h->stats.rx_compressed_original_bytes += decmp_outlen; knet_h->stats.rx_compressed_size_bytes += len - KNET_HEADER_SIZE; memmove(inbuf->khp_data_userdata, knet_h->recv_from_links_buf_decompress, decmp_outlen); len = decmp_outlen + KNET_HEADER_DATA_SIZE; } else { log_warn(knet_h, KNET_SUB_COMPRESS, "Unable to decompress packet (%d): %s", err, strerror(errno)); return; } } if (inbuf->kh_type == KNET_HEADER_TYPE_DATA) { if (knet_h->enabled != 1) /* data forward is disabled */ break; if (knet_h->dst_host_filter_fn) { size_t host_idx; int found = 0; bcast = knet_h->dst_host_filter_fn( knet_h->dst_host_filter_fn_private_data, (const unsigned char *)inbuf->khp_data_userdata, len - KNET_HEADER_DATA_SIZE, KNET_NOTIFY_RX, knet_h->host_id, inbuf->kh_node, &channel, dst_host_ids, &dst_host_ids_entries); if (bcast < 0) { log_debug(knet_h, KNET_SUB_RX, "Error from dst_host_filter_fn: %d", bcast); return; } if ((!bcast) && (!dst_host_ids_entries)) { log_debug(knet_h, KNET_SUB_RX, "Message is unicast but no dst_host_ids_entries"); return; } /* check if we are dst for this packet */ if (!bcast) { for (host_idx = 0; host_idx < dst_host_ids_entries; host_idx++) { if (dst_host_ids[host_idx] == knet_h->host_id) { found = 1; break; } } if (!found) { log_debug(knet_h, KNET_SUB_RX, "Packet is not for us"); return; } } } } if (inbuf->kh_type == KNET_HEADER_TYPE_DATA) { if (!knet_h->sockfd[channel].in_use) { log_debug(knet_h, KNET_SUB_RX, "received packet for channel %d but there is no local sock connected", channel); return; } memset(iov_out, 0, sizeof(iov_out)); iov_out[0].iov_base = (void *) inbuf->khp_data_userdata; iov_out[0].iov_len = len - KNET_HEADER_DATA_SIZE; outlen = writev(knet_h->sockfd[channel].sockfd[knet_h->sockfd[channel].is_created], iov_out, 1); if (outlen <= 0) { knet_h->sock_notify_fn(knet_h->sock_notify_fn_private_data, knet_h->sockfd[channel].sockfd[0], channel, KNET_NOTIFY_RX, outlen, errno); return; } if ((size_t)outlen == iov_out[0].iov_len) { _seq_num_set(src_host, inbuf->khp_data_seq_num, 0); } } else { /* HOSTINFO */ knet_hostinfo = (struct knet_hostinfo *)inbuf->khp_data_userdata; if (knet_hostinfo->khi_bcast == KNET_HOSTINFO_UCAST) { bcast = 0; knet_hostinfo->khi_dst_node_id = ntohs(knet_hostinfo->khi_dst_node_id); } if (!_seq_num_lookup(src_host, inbuf->khp_data_seq_num, 0, 0)) { return; } _seq_num_set(src_host, inbuf->khp_data_seq_num, 0); switch(knet_hostinfo->khi_type) { case KNET_HOSTINFO_TYPE_LINK_UP_DOWN: break; case KNET_HOSTINFO_TYPE_LINK_TABLE: break; default: log_warn(knet_h, KNET_SUB_RX, "Receiving unknown host info message from host %u", src_host->host_id); break; } } break; case KNET_HEADER_TYPE_PING: outlen = KNET_HEADER_PING_SIZE; inbuf->kh_type = KNET_HEADER_TYPE_PONG; inbuf->kh_node = htons(knet_h->host_id); recv_seq_num = ntohs(inbuf->khp_ping_seq_num); src_link->status.stats.rx_ping_packets++; src_link->status.stats.rx_ping_bytes += len; wipe_bufs = 0; if (!inbuf->khp_ping_timed) { /* * we might be receiving this message from all links, but we want * to process it only the first time */ if (recv_seq_num != src_host->untimed_rx_seq_num) { /* * cache the untimed seq num */ src_host->untimed_rx_seq_num = recv_seq_num; /* * if the host has received data in between * untimed ping, then we don't need to wipe the bufs */ if (src_host->got_data) { src_host->got_data = 0; wipe_bufs = 0; } else { wipe_bufs = 1; } } _seq_num_lookup(src_host, recv_seq_num, 0, wipe_bufs); } else { /* * pings always arrives in bursts over all the link * catch the first of them to cache the seq num and * avoid duplicate processing */ if (recv_seq_num != src_host->timed_rx_seq_num) { src_host->timed_rx_seq_num = recv_seq_num; if (recv_seq_num == 0) { _seq_num_lookup(src_host, recv_seq_num, 0, 1); } } } if (knet_h->crypto_instance) { if (crypto_encrypt_and_sign(knet_h, (const unsigned char *)inbuf, len, knet_h->recv_from_links_buf_crypt, &outlen) < 0) { log_debug(knet_h, KNET_SUB_RX, "Unable to encrypt pong packet"); break; } outbuf = knet_h->recv_from_links_buf_crypt; } retry_pong: len = sendto(src_link->outsock, outbuf, outlen, MSG_DONTWAIT | MSG_NOSIGNAL, (struct sockaddr *) &src_link->dst_addr, sizeof(struct sockaddr_storage)); savederrno = errno; if (len != outlen) { err = knet_h->transport_ops[src_link->transport_type]->transport_tx_sock_error(knet_h, src_link->outsock, len, savederrno); switch(err) { case -1: /* unrecoverable error */ log_debug(knet_h, KNET_SUB_RX, "Unable to send pong reply (sock: %d) packet (sendto): %d %s. recorded src ip: %s src port: %s dst ip: %s dst port: %s", src_link->outsock, errno, strerror(errno), src_link->status.src_ipaddr, src_link->status.src_port, src_link->status.dst_ipaddr, src_link->status.dst_port); src_link->status.stats.tx_pong_errors++; break; case 0: /* ignore error and continue */ break; case 1: /* retry to send those same data */ src_link->status.stats.tx_pong_retries++; goto retry_pong; break; } } src_link->status.stats.tx_pong_packets++; src_link->status.stats.tx_pong_bytes += outlen; break; case KNET_HEADER_TYPE_PONG: src_link->status.stats.rx_pong_packets++; src_link->status.stats.rx_pong_bytes += len; clock_gettime(CLOCK_MONOTONIC, &src_link->status.pong_last); memmove(&recvtime, &inbuf->khp_ping_time[0], sizeof(struct timespec)); timespec_diff(recvtime, src_link->status.pong_last, &latency_last); src_link->status.latency = ((src_link->status.latency * src_link->latency_exp) + ((latency_last / 1000llu) * (src_link->latency_fix - src_link->latency_exp))) / src_link->latency_fix; if (src_link->status.latency < src_link->pong_timeout) { if (!src_link->status.connected) { if (src_link->received_pong >= src_link->pong_count) { log_info(knet_h, KNET_SUB_RX, "host: %u link: %u is up", src_host->host_id, src_link->link_id); _link_updown(knet_h, src_host->host_id, src_link->link_id, src_link->status.enabled, 1); } else { src_link->received_pong++; log_debug(knet_h, KNET_SUB_RX, "host: %u link: %u received pong: %u", src_host->host_id, src_link->link_id, src_link->received_pong); } } } /* Calculate latency stats */ if (src_link->status.latency > src_link->status.stats.latency_max) { src_link->status.stats.latency_max = src_link->status.latency; } if (src_link->status.latency < src_link->status.stats.latency_min) { src_link->status.stats.latency_min = src_link->status.latency; } src_link->status.stats.latency_ave = (src_link->status.stats.latency_ave * src_link->status.stats.latency_samples + src_link->status.latency) / (src_link->status.stats.latency_samples+1); src_link->status.stats.latency_samples++; break; case KNET_HEADER_TYPE_PMTUD: src_link->status.stats.rx_pmtu_packets++; src_link->status.stats.rx_pmtu_bytes += len; outlen = KNET_HEADER_PMTUD_SIZE; inbuf->kh_type = KNET_HEADER_TYPE_PMTUD_REPLY; inbuf->kh_node = htons(knet_h->host_id); if (knet_h->crypto_instance) { if (crypto_encrypt_and_sign(knet_h, (const unsigned char *)inbuf, len, knet_h->recv_from_links_buf_crypt, &outlen) < 0) { log_debug(knet_h, KNET_SUB_RX, "Unable to encrypt PMTUd reply packet"); break; } outbuf = knet_h->recv_from_links_buf_crypt; } retry_pmtud: len = sendto(src_link->outsock, outbuf, outlen, MSG_DONTWAIT | MSG_NOSIGNAL, (struct sockaddr *) &src_link->dst_addr, sizeof(struct sockaddr_storage)); if (len != outlen) { err = knet_h->transport_ops[src_link->transport_type]->transport_tx_sock_error(knet_h, src_link->outsock, len, savederrno); switch(err) { case -1: /* unrecoverable error */ log_debug(knet_h, KNET_SUB_RX, "Unable to send PMTUd reply (sock: %d) packet (sendto): %d %s. recorded src ip: %s src port: %s dst ip: %s dst port: %s", src_link->outsock, errno, strerror(errno), src_link->status.src_ipaddr, src_link->status.src_port, src_link->status.dst_ipaddr, src_link->status.dst_port); src_link->status.stats.tx_pmtu_errors++; break; case 0: /* ignore error and continue */ src_link->status.stats.tx_pmtu_errors++; break; case 1: /* retry to send those same data */ src_link->status.stats.tx_pmtu_retries++; goto retry_pmtud; break; } } break; case KNET_HEADER_TYPE_PMTUD_REPLY: src_link->status.stats.rx_pmtu_packets++; src_link->status.stats.rx_pmtu_bytes += len; if (pthread_mutex_lock(&knet_h->pmtud_mutex) != 0) { log_debug(knet_h, KNET_SUB_RX, "Unable to get mutex lock"); break; } src_link->last_recv_mtu = inbuf->khp_pmtud_size; pthread_cond_signal(&knet_h->pmtud_cond); pthread_mutex_unlock(&knet_h->pmtud_mutex); break; default: return; } } static void _handle_recv_from_links(knet_handle_t knet_h, int sockfd, struct knet_mmsghdr *msg) { int err, savederrno; int i, msg_recv, transport; if (pthread_rwlock_rdlock(&knet_h->global_rwlock) != 0) { log_debug(knet_h, KNET_SUB_RX, "Unable to get global read lock"); return; } if (_is_valid_fd(knet_h, sockfd) < 1) { /* * this is normal if a fd got an event and before we grab the read lock * and the link is removed by another thread */ goto exit_unlock; } transport = knet_h->knet_transport_fd_tracker[sockfd].transport; /* * reset msg_namelen to buffer size because after recvmmsg * each msg_namelen will contain sizeof sockaddr_in or sockaddr_in6 */ for (i = 0; i < PCKT_RX_BUFS; i++) { msg[i].msg_hdr.msg_namelen = sizeof(struct sockaddr_storage); } msg_recv = _recvmmsg(sockfd, &msg[0], PCKT_RX_BUFS, MSG_DONTWAIT | MSG_NOSIGNAL); savederrno = errno; /* * WARNING: man page for recvmmsg is wrong. Kernel implementation here: * recvmmsg can return: * -1 on error * 0 if the previous run of recvmmsg recorded an error on the socket * N number of messages (see exception below). * * If there is an error from recvmsg after receiving a frame or more, the recvmmsg * loop is interrupted, error recorded in the socket (getsockopt(SO_ERROR) and * it will be visibile in the next run. * * Need to be careful how we handle errors at this stage. * * error messages need to be handled on a per transport/protocol base * at this point we have different layers of error handling * - msg_recv < 0 -> error from this run * msg_recv = 0 -> error from previous run and error on socket needs to be cleared * - per-transport message data * example: msg[i].msg_hdr.msg_flags & MSG_NOTIFICATION or msg_len for SCTP == EOF, * but for UDP it is perfectly legal to receive a 0 bytes message.. go figure * - NOTE: on SCTP MSG_NOTIFICATION we get msg_recv == PCKT_FRAG_MAX messages and no * errno set. That means the error api needs to be able to abort the loop below. */ if (msg_recv <= 0) { knet_h->transport_ops[transport]->transport_rx_sock_error(knet_h, sockfd, msg_recv, savederrno); goto exit_unlock; } for (i = 0; i < msg_recv; i++) { err = knet_h->transport_ops[transport]->transport_rx_is_data(knet_h, sockfd, &msg[i]); /* * TODO: make this section silent once we are confident * all protocols packet handlers are good */ switch(err) { case -1: /* on error */ log_debug(knet_h, KNET_SUB_RX, "Transport reported error parsing packet"); goto exit_unlock; break; case 0: /* packet is not data and we should continue the packet process loop */ log_debug(knet_h, KNET_SUB_RX, "Transport reported no data, continue"); break; case 1: /* packet is not data and we should STOP the packet process loop */ log_debug(knet_h, KNET_SUB_RX, "Transport reported no data, stop"); goto exit_unlock; break; case 2: /* packet is data and should be parsed as such */ _parse_recv_from_links(knet_h, sockfd, &msg[i]); break; } } exit_unlock: pthread_rwlock_unlock(&knet_h->global_rwlock); } void *_handle_recv_from_links_thread(void *data) { int i, nev; knet_handle_t knet_h = (knet_handle_t) data; struct epoll_event events[KNET_EPOLL_MAX_EVENTS]; struct sockaddr_storage address[PCKT_RX_BUFS]; struct knet_mmsghdr msg[PCKT_RX_BUFS]; struct iovec iov_in[PCKT_RX_BUFS]; memset(&msg, 0, sizeof(msg)); for (i = 0; i < PCKT_RX_BUFS; i++) { iov_in[i].iov_base = (void *)knet_h->recv_from_links_buf[i]; iov_in[i].iov_len = KNET_DATABUFSIZE; memset(&msg[i].msg_hdr, 0, sizeof(struct msghdr)); msg[i].msg_hdr.msg_name = &address[i]; msg[i].msg_hdr.msg_namelen = sizeof(struct sockaddr_storage); msg[i].msg_hdr.msg_iov = &iov_in[i]; msg[i].msg_hdr.msg_iovlen = 1; } while (!shutdown_in_progress(knet_h)) { nev = epoll_wait(knet_h->recv_from_links_epollfd, events, KNET_EPOLL_MAX_EVENTS, -1); for (i = 0; i < nev; i++) { _handle_recv_from_links(knet_h, events[i].data.fd, msg); } } return NULL; } diff --git a/libknet/threads_rx.h b/libknet/threads_rx.h index 8b1a0ce0..5e8d7f16 100644 --- a/libknet/threads_rx.h +++ b/libknet/threads_rx.h @@ -1,15 +1,15 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNET_THREADS_RX_H__ #define __KNET_THREADS_RX_H__ void *_handle_recv_from_links_thread(void *data); #endif diff --git a/libknet/threads_tx.c b/libknet/threads_tx.c index f13867dd..969f6c03 100644 --- a/libknet/threads_tx.c +++ b/libknet/threads_tx.c @@ -1,736 +1,736 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include <math.h> #include <string.h> #include <pthread.h> #include <unistd.h> #include <sys/uio.h> #include <errno.h> #include "compat.h" #include "compress.h" #include "crypto.h" #include "host.h" #include "link.h" #include "logging.h" #include "transports.h" #include "threads_common.h" #include "threads_heartbeat.h" #include "threads_tx.h" #include "netutils.h" /* * SEND */ static int _dispatch_to_links(knet_handle_t knet_h, struct knet_host *dst_host, struct knet_mmsghdr *msg, int msgs_to_send) { int link_idx, msg_idx, sent_msgs, prev_sent, progress; int err = 0, savederrno = 0; unsigned int i; struct knet_mmsghdr *cur; struct knet_link *cur_link; for (link_idx = 0; link_idx < dst_host->active_link_entries; link_idx++) { sent_msgs = 0; prev_sent = 0; progress = 1; cur_link = &dst_host->link[dst_host->active_links[link_idx]]; if (cur_link->transport_type == KNET_TRANSPORT_LOOPBACK) { continue; } msg_idx = 0; while (msg_idx < msgs_to_send) { msg[msg_idx].msg_hdr.msg_name = &cur_link->dst_addr; /* Cast for Linux/BSD compatibility */ for (i=0; i<(unsigned int)msg[msg_idx].msg_hdr.msg_iovlen; i++) { cur_link->status.stats.tx_data_bytes += msg[msg_idx].msg_hdr.msg_iov[i].iov_len; } cur_link->status.stats.tx_data_packets++; msg_idx++; } retry: cur = &msg[prev_sent]; sent_msgs = _sendmmsg(dst_host->link[dst_host->active_links[link_idx]].outsock, &cur[0], msgs_to_send - prev_sent, MSG_DONTWAIT | MSG_NOSIGNAL); savederrno = errno; err = knet_h->transport_ops[dst_host->link[dst_host->active_links[link_idx]].transport_type]->transport_tx_sock_error(knet_h, dst_host->link[dst_host->active_links[link_idx]].outsock, sent_msgs, savederrno); switch(err) { case -1: /* unrecoverable error */ cur_link->status.stats.tx_data_errors++; goto out_unlock; break; case 0: /* ignore error and continue */ break; case 1: /* retry to send those same data */ cur_link->status.stats.tx_data_retries++; goto retry; break; } prev_sent = prev_sent + sent_msgs; if ((sent_msgs >= 0) && (prev_sent < msgs_to_send)) { if ((sent_msgs) || (progress)) { if (sent_msgs) { progress = 1; } else { progress = 0; } #ifdef DEBUG log_debug(knet_h, KNET_SUB_TX, "Unable to send all (%d/%d) data packets to host %s (%u) link %s:%s (%u)", sent_msgs, msg_idx, dst_host->name, dst_host->host_id, dst_host->link[dst_host->active_links[link_idx]].status.dst_ipaddr, dst_host->link[dst_host->active_links[link_idx]].status.dst_port, dst_host->link[dst_host->active_links[link_idx]].link_id); #endif goto retry; } if (!progress) { savederrno = EAGAIN; err = -1; goto out_unlock; } } if ((dst_host->link_handler_policy == KNET_LINK_POLICY_RR) && (dst_host->active_link_entries > 1)) { uint8_t cur_link_id = dst_host->active_links[0]; memmove(&dst_host->active_links[0], &dst_host->active_links[1], KNET_MAX_LINK - 1); dst_host->active_links[dst_host->active_link_entries - 1] = cur_link_id; break; } } out_unlock: errno = savederrno; return err; } static int _parse_recv_from_sock(knet_handle_t knet_h, size_t inlen, int8_t channel, int is_sync) { size_t outlen, frag_len; struct knet_host *dst_host; knet_node_id_t dst_host_ids_temp[KNET_MAX_HOST]; size_t dst_host_ids_entries_temp = 0; knet_node_id_t dst_host_ids[KNET_MAX_HOST]; size_t dst_host_ids_entries = 0; int bcast = 1; struct knet_hostinfo *knet_hostinfo; struct iovec iov_out[PCKT_FRAG_MAX][2]; int iovcnt_out = 2; uint8_t frag_idx; unsigned int temp_data_mtu; size_t host_idx; int send_mcast = 0; struct knet_header *inbuf; int savederrno = 0; int err = 0; seq_num_t tx_seq_num; struct knet_mmsghdr msg[PCKT_FRAG_MAX]; int msgs_to_send, msg_idx; unsigned int i; int j; int send_local = 0; int data_compressed = 0; size_t uncrypted_frag_size; inbuf = knet_h->recv_from_sock_buf; if ((knet_h->enabled != 1) && (inbuf->kh_type != KNET_HEADER_TYPE_HOST_INFO)) { /* data forward is disabled */ log_debug(knet_h, KNET_SUB_TX, "Received data packet but forwarding is disabled"); savederrno = ECANCELED; err = -1; goto out_unlock; } /* * move this into a separate function to expand on * extra switching rules */ switch(inbuf->kh_type) { case KNET_HEADER_TYPE_DATA: if (knet_h->dst_host_filter_fn) { bcast = knet_h->dst_host_filter_fn( knet_h->dst_host_filter_fn_private_data, (const unsigned char *)inbuf->khp_data_userdata, inlen, KNET_NOTIFY_TX, knet_h->host_id, knet_h->host_id, &channel, dst_host_ids_temp, &dst_host_ids_entries_temp); if (bcast < 0) { log_debug(knet_h, KNET_SUB_TX, "Error from dst_host_filter_fn: %d", bcast); savederrno = EFAULT; err = -1; goto out_unlock; } if ((!bcast) && (!dst_host_ids_entries_temp)) { log_debug(knet_h, KNET_SUB_TX, "Message is unicast but no dst_host_ids_entries"); savederrno = EINVAL; err = -1; goto out_unlock; } } /* Send to localhost if appropriate and enabled */ if (knet_h->has_loop_link) { send_local = 0; if (bcast) { send_local = 1; } else { for (i=0; i< dst_host_ids_entries_temp; i++) { if (dst_host_ids_temp[i] == knet_h->host_id) { send_local = 1; } } } if (send_local) { const unsigned char *buf = inbuf->khp_data_userdata; ssize_t buflen = inlen; struct knet_link *local_link; local_link = knet_h->host_index[knet_h->host_id]->link; local_retry: err = write(knet_h->sockfd[channel].sockfd[knet_h->sockfd[channel].is_created], buf, buflen); if (err < 0) { log_err(knet_h, KNET_SUB_TRANSP_LOOPBACK, "send local failed. error=%s\n", strerror(errno)); local_link->status.stats.tx_data_errors++; } if (err > 0 && err < buflen) { log_debug(knet_h, KNET_SUB_TRANSP_LOOPBACK, "send local incomplete=%d bytes of %zu\n", err, inlen); local_link->status.stats.tx_data_retries++; buf += err; buflen -= err; usleep(KNET_THREADS_TIMERES / 16); goto local_retry; } if (err == buflen) { local_link->status.stats.tx_data_packets++; local_link->status.stats.tx_data_bytes += inlen; } } } break; case KNET_HEADER_TYPE_HOST_INFO: knet_hostinfo = (struct knet_hostinfo *)inbuf->khp_data_userdata; if (knet_hostinfo->khi_bcast == KNET_HOSTINFO_UCAST) { bcast = 0; dst_host_ids_temp[0] = knet_hostinfo->khi_dst_node_id; dst_host_ids_entries_temp = 1; knet_hostinfo->khi_dst_node_id = htons(knet_hostinfo->khi_dst_node_id); } break; default: log_warn(knet_h, KNET_SUB_TX, "Receiving unknown messages from socket"); savederrno = ENOMSG; err = -1; goto out_unlock; break; } if (is_sync) { if ((bcast) || ((!bcast) && (dst_host_ids_entries_temp > 1))) { log_debug(knet_h, KNET_SUB_TX, "knet_send_sync is only supported with unicast packets for one destination"); savederrno = E2BIG; err = -1; goto out_unlock; } } /* * check destinations hosts before spending time * in fragmenting/encrypting packets to save * time processing data for unreachable hosts. * for unicast, also remap the destination data * to skip unreachable hosts. */ if (!bcast) { dst_host_ids_entries = 0; for (host_idx = 0; host_idx < dst_host_ids_entries_temp; host_idx++) { dst_host = knet_h->host_index[dst_host_ids_temp[host_idx]]; if (!dst_host) { continue; } if (!(dst_host->host_id == knet_h->host_id && knet_h->has_loop_link) && dst_host->status.reachable) { dst_host_ids[dst_host_ids_entries] = dst_host_ids_temp[host_idx]; dst_host_ids_entries++; } } if (!dst_host_ids_entries) { savederrno = EHOSTDOWN; err = -1; goto out_unlock; } } else { send_mcast = 0; for (dst_host = knet_h->host_head; dst_host != NULL; dst_host = dst_host->next) { if (!(dst_host->host_id == knet_h->host_id && knet_h->has_loop_link) && dst_host->status.reachable) { send_mcast = 1; break; } } if (!send_mcast) { savederrno = EHOSTDOWN; err = -1; goto out_unlock; } } if (!knet_h->data_mtu) { /* * using MIN_MTU_V4 for data mtu is not completely accurate but safe enough */ log_debug(knet_h, KNET_SUB_TX, "Received data packet but data MTU is still unknown." " Packet might not be delivered." " Assuming mininum IPv4 mtu (%d)", KNET_PMTUD_MIN_MTU_V4); temp_data_mtu = KNET_PMTUD_MIN_MTU_V4; } else { /* * take a copy of the mtu to avoid value changing under * our feet while we are sending a fragmented pckt */ temp_data_mtu = knet_h->data_mtu; } /* * compress data */ if ((knet_h->compress_model > 0) && (inlen > knet_h->compress_threshold)) { size_t cmp_outlen = KNET_DATABUFSIZE_COMPRESS; struct timespec start_time; struct timespec end_time; uint64_t compress_time; clock_gettime(CLOCK_MONOTONIC, &start_time); err = compress(knet_h, (const unsigned char *)inbuf->khp_data_userdata, inlen, knet_h->send_to_links_buf_compress, (ssize_t *)&cmp_outlen); if (err < 0) { log_warn(knet_h, KNET_SUB_COMPRESS, "Compression failed (%d): %s", err, strerror(errno)); } else { /* Collect stats */ clock_gettime(CLOCK_MONOTONIC, &end_time); timespec_diff(start_time, end_time, &compress_time); if (compress_time < knet_h->stats.tx_compress_time_min) { knet_h->stats.tx_compress_time_min = compress_time; } if (compress_time > knet_h->stats.tx_compress_time_max) { knet_h->stats.tx_compress_time_max = compress_time; } knet_h->stats.tx_compress_time_ave = (unsigned long long)(knet_h->stats.tx_compress_time_ave * knet_h->stats.tx_compressed_packets + compress_time) / (knet_h->stats.tx_compressed_packets+1); knet_h->stats.tx_compressed_packets++; knet_h->stats.tx_compressed_original_bytes += inlen; knet_h->stats.tx_compressed_size_bytes += cmp_outlen; if (cmp_outlen < inlen) { memmove(inbuf->khp_data_userdata, knet_h->send_to_links_buf_compress, cmp_outlen); inlen = cmp_outlen; data_compressed = 1; } } } if ((knet_h->compress_model > 0) && (inlen <= knet_h->compress_threshold)) { knet_h->stats.tx_uncompressed_packets++; } /* * prepare the outgoing buffers */ frag_len = inlen; frag_idx = 0; inbuf->khp_data_bcast = bcast; inbuf->khp_data_frag_num = ceil((float)inlen / temp_data_mtu); inbuf->khp_data_channel = channel; if (data_compressed) { inbuf->khp_data_compress = knet_h->compress_model; } else { inbuf->khp_data_compress = 0; } if (pthread_mutex_lock(&knet_h->tx_seq_num_mutex)) { log_debug(knet_h, KNET_SUB_TX, "Unable to get seq mutex lock"); goto out_unlock; } knet_h->tx_seq_num++; /* * force seq_num 0 to detect a node that has crashed and rejoining * the knet instance. seq_num 0 will clear the buffers in the RX * thread */ if (knet_h->tx_seq_num == 0) { knet_h->tx_seq_num++; } /* * cache the value in locked context */ tx_seq_num = knet_h->tx_seq_num; inbuf->khp_data_seq_num = htons(knet_h->tx_seq_num); pthread_mutex_unlock(&knet_h->tx_seq_num_mutex); /* * forcefully broadcast a ping to all nodes every SEQ_MAX / 8 * pckts. * this solves 2 problems: * 1) on TX socket overloads we generate extra pings to keep links alive * 2) in 3+ nodes setup, where all the traffic is flowing between node 1 and 2, * node 3+ will be able to keep in sync on the TX seq_num even without * receiving traffic or pings in betweens. This avoids issues with * rollover of the circular buffer */ if (tx_seq_num % (SEQ_MAX / 8) == 0) { _send_pings(knet_h, 0); } if (inbuf->khp_data_frag_num > 1) { while (frag_idx < inbuf->khp_data_frag_num) { /* * set the iov_base */ iov_out[frag_idx][0].iov_base = (void *)knet_h->send_to_links_buf[frag_idx]; iov_out[frag_idx][0].iov_len = KNET_HEADER_DATA_SIZE; iov_out[frag_idx][1].iov_base = inbuf->khp_data_userdata + (temp_data_mtu * frag_idx); /* * set the len */ if (frag_len > temp_data_mtu) { iov_out[frag_idx][1].iov_len = temp_data_mtu; } else { iov_out[frag_idx][1].iov_len = frag_len; } /* * copy the frag info on all buffers */ knet_h->send_to_links_buf[frag_idx]->kh_type = inbuf->kh_type; knet_h->send_to_links_buf[frag_idx]->khp_data_seq_num = inbuf->khp_data_seq_num; knet_h->send_to_links_buf[frag_idx]->khp_data_frag_num = inbuf->khp_data_frag_num; knet_h->send_to_links_buf[frag_idx]->khp_data_bcast = inbuf->khp_data_bcast; knet_h->send_to_links_buf[frag_idx]->khp_data_channel = inbuf->khp_data_channel; knet_h->send_to_links_buf[frag_idx]->khp_data_compress = inbuf->khp_data_compress; frag_len = frag_len - temp_data_mtu; frag_idx++; } iovcnt_out = 2; } else { iov_out[frag_idx][0].iov_base = (void *)inbuf; iov_out[frag_idx][0].iov_len = frag_len + KNET_HEADER_DATA_SIZE; iovcnt_out = 1; } if (knet_h->crypto_instance) { struct timespec start_time; struct timespec end_time; uint64_t crypt_time; frag_idx = 0; while (frag_idx < inbuf->khp_data_frag_num) { clock_gettime(CLOCK_MONOTONIC, &start_time); if (crypto_encrypt_and_signv( knet_h, iov_out[frag_idx], iovcnt_out, knet_h->send_to_links_buf_crypt[frag_idx], (ssize_t *)&outlen) < 0) { log_debug(knet_h, KNET_SUB_TX, "Unable to encrypt packet"); savederrno = ECHILD; err = -1; goto out_unlock; } clock_gettime(CLOCK_MONOTONIC, &end_time); timespec_diff(start_time, end_time, &crypt_time); if (crypt_time < knet_h->stats.tx_crypt_time_min) { knet_h->stats.tx_crypt_time_min = crypt_time; } if (crypt_time > knet_h->stats.tx_crypt_time_max) { knet_h->stats.tx_crypt_time_max = crypt_time; } knet_h->stats.tx_crypt_time_ave = (knet_h->stats.tx_crypt_time_ave * knet_h->stats.tx_crypt_packets + crypt_time) / (knet_h->stats.tx_crypt_packets+1); uncrypted_frag_size = 0; for (j=0; j < iovcnt_out; j++) { uncrypted_frag_size += iov_out[frag_idx][j].iov_len; } knet_h->stats.tx_crypt_byte_overhead += (outlen - uncrypted_frag_size); knet_h->stats.tx_crypt_packets++; iov_out[frag_idx][0].iov_base = knet_h->send_to_links_buf_crypt[frag_idx]; iov_out[frag_idx][0].iov_len = outlen; frag_idx++; } iovcnt_out = 1; } memset(&msg, 0, sizeof(msg)); msgs_to_send = inbuf->khp_data_frag_num; msg_idx = 0; while (msg_idx < msgs_to_send) { msg[msg_idx].msg_hdr.msg_namelen = sizeof(struct sockaddr_storage); msg[msg_idx].msg_hdr.msg_iov = &iov_out[msg_idx][0]; msg[msg_idx].msg_hdr.msg_iovlen = iovcnt_out; msg_idx++; } if (!bcast) { for (host_idx = 0; host_idx < dst_host_ids_entries; host_idx++) { dst_host = knet_h->host_index[dst_host_ids[host_idx]]; err = _dispatch_to_links(knet_h, dst_host, &msg[0], msgs_to_send); savederrno = errno; if (err) { goto out_unlock; } } } else { for (dst_host = knet_h->host_head; dst_host != NULL; dst_host = dst_host->next) { if (dst_host->status.reachable) { err = _dispatch_to_links(knet_h, dst_host, &msg[0], msgs_to_send); savederrno = errno; if (err) { goto out_unlock; } } } } out_unlock: errno = savederrno; return err; } int knet_send_sync(knet_handle_t knet_h, const char *buff, const size_t buff_len, const int8_t channel) { int savederrno = 0, err = 0; if (!knet_h) { errno = EINVAL; return -1; } if (buff == NULL) { errno = EINVAL; return -1; } if (buff_len <= 0) { errno = EINVAL; return -1; } if (buff_len > KNET_MAX_PACKET_SIZE) { errno = EINVAL; return -1; } if (channel < 0) { errno = EINVAL; return -1; } if (channel >= KNET_DATAFD_MAX) { errno = EINVAL; return -1; } savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock); if (savederrno) { log_err(knet_h, KNET_SUB_TX, "Unable to get read lock: %s", strerror(savederrno)); errno = savederrno; return -1; } if (!knet_h->sockfd[channel].in_use) { savederrno = EINVAL; err = -1; goto out; } savederrno = pthread_mutex_lock(&knet_h->tx_mutex); if (savederrno) { log_err(knet_h, KNET_SUB_TX, "Unable to get TX mutex lock: %s", strerror(savederrno)); err = -1; goto out; } knet_h->recv_from_sock_buf->kh_type = KNET_HEADER_TYPE_DATA; memmove(knet_h->recv_from_sock_buf->khp_data_userdata, buff, buff_len); err = _parse_recv_from_sock(knet_h, buff_len, channel, 1); savederrno = errno; pthread_mutex_unlock(&knet_h->tx_mutex); out: pthread_rwlock_unlock(&knet_h->global_rwlock); errno = savederrno; return err; } static void _handle_send_to_links(knet_handle_t knet_h, struct msghdr *msg, int sockfd, int8_t channel, int type) { ssize_t inlen = 0; int savederrno = 0, docallback = 0; if ((channel >= 0) && (channel < KNET_DATAFD_MAX) && (!knet_h->sockfd[channel].is_socket)) { inlen = readv(sockfd, msg->msg_iov, 1); } else { inlen = recvmsg(sockfd, msg, MSG_DONTWAIT | MSG_NOSIGNAL); } if (inlen == 0) { savederrno = 0; docallback = 1; goto out; } if (inlen < 0) { savederrno = errno; docallback = 1; goto out; } knet_h->recv_from_sock_buf->kh_type = type; _parse_recv_from_sock(knet_h, inlen, channel, 0); out: if (inlen < 0) { struct epoll_event ev; memset(&ev, 0, sizeof(struct epoll_event)); if (epoll_ctl(knet_h->send_to_links_epollfd, EPOLL_CTL_DEL, knet_h->sockfd[channel].sockfd[knet_h->sockfd[channel].is_created], &ev)) { log_err(knet_h, KNET_SUB_TX, "Unable to del datafd %d from linkfd epoll pool: %s", knet_h->sockfd[channel].sockfd[0], strerror(savederrno)); } else { knet_h->sockfd[channel].has_error = 1; } } if (docallback) { knet_h->sock_notify_fn(knet_h->sock_notify_fn_private_data, knet_h->sockfd[channel].sockfd[0], channel, KNET_NOTIFY_TX, inlen, savederrno); } } void *_handle_send_to_links_thread(void *data) { knet_handle_t knet_h = (knet_handle_t) data; struct epoll_event events[KNET_EPOLL_MAX_EVENTS]; int i, nev, type; int8_t channel; struct iovec iov_in; struct msghdr msg; struct sockaddr_storage address; memset(&iov_in, 0, sizeof(iov_in)); iov_in.iov_base = (void *)knet_h->recv_from_sock_buf->khp_data_userdata; iov_in.iov_len = KNET_MAX_PACKET_SIZE; memset(&msg, 0, sizeof(struct msghdr)); msg.msg_name = &address; msg.msg_namelen = sizeof(struct sockaddr_storage); msg.msg_iov = &iov_in; msg.msg_iovlen = 1; knet_h->recv_from_sock_buf->kh_version = KNET_HEADER_VERSION; knet_h->recv_from_sock_buf->khp_data_frag_seq = 0; knet_h->recv_from_sock_buf->kh_node = htons(knet_h->host_id); for (i = 0; i < PCKT_FRAG_MAX; i++) { knet_h->send_to_links_buf[i]->kh_version = KNET_HEADER_VERSION; knet_h->send_to_links_buf[i]->khp_data_frag_seq = i + 1; knet_h->send_to_links_buf[i]->kh_node = htons(knet_h->host_id); } while (!shutdown_in_progress(knet_h)) { nev = epoll_wait(knet_h->send_to_links_epollfd, events, KNET_EPOLL_MAX_EVENTS + 1, -1); if (pthread_rwlock_rdlock(&knet_h->global_rwlock) != 0) { log_debug(knet_h, KNET_SUB_TX, "Unable to get read lock"); continue; } for (i = 0; i < nev; i++) { if (events[i].data.fd == knet_h->hostsockfd[0]) { type = KNET_HEADER_TYPE_HOST_INFO; channel = -1; } else { type = KNET_HEADER_TYPE_DATA; for (channel = 0; channel < KNET_DATAFD_MAX; channel++) { if ((knet_h->sockfd[channel].in_use) && (knet_h->sockfd[channel].sockfd[knet_h->sockfd[channel].is_created] == events[i].data.fd)) { break; } } if (channel >= KNET_DATAFD_MAX) { log_debug(knet_h, KNET_SUB_TX, "No available channels"); continue; /* channel not found */ } } if (pthread_mutex_lock(&knet_h->tx_mutex) != 0) { log_debug(knet_h, KNET_SUB_TX, "Unable to get mutex lock"); continue; } _handle_send_to_links(knet_h, &msg, events[i].data.fd, channel, type); pthread_mutex_unlock(&knet_h->tx_mutex); } pthread_rwlock_unlock(&knet_h->global_rwlock); } return NULL; } diff --git a/libknet/threads_tx.h b/libknet/threads_tx.h index 82c64fe8..771f2ee2 100644 --- a/libknet/threads_tx.h +++ b/libknet/threads_tx.h @@ -1,15 +1,15 @@ /* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. + * Copyright (C) 2012-2017 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto <fabbione@kronosnet.org> * Federico Simoncelli <fsimon@kronosnet.org> * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNET_THREADS_TX_H__ #define __KNET_THREADS_TX_H__ void *_handle_send_to_links_thread(void *data); #endif diff --git a/libtap/libtap.h b/libtap/libtap.h index 015ef9cb..63aecfd8 100644 --- a/libtap/libtap.h +++ b/libtap/libtap.h @@ -1,40 +1,40 @@ /* - * Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2017 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 __LIBTAP_H__ #define __LIBTAP_H__ #include <sys/types.h> typedef struct _iface *tap_t; tap_t tap_open(char *dev, size_t dev_size, const char *updownpath); int tap_close(tap_t tap); tap_t tap_find(char *dev, size_t dev_size); int tap_get_fd(const tap_t tap); const char *tap_get_name(const tap_t tap); int tap_get_mtu(const tap_t tap); int tap_set_mtu(tap_t tap, const int mtu); int tap_reset_mtu(tap_t tap); int tap_get_mac(const tap_t tap, char **ether_addr); int tap_set_mac(tap_t tap, const char *ether_addr); int tap_reset_mac(tap_t tap); int tap_set_up(tap_t tap, char **error_preup, char **error_up); int tap_set_down(tap_t tap, char **error_down, char **error_postdown); int tap_add_ip(tap_t tap, const char *ip_addr, const char *prefix, char **error_string); int tap_del_ip(tap_t tap, const char *ip_addr, const char *prefix, char **error_string); int tap_get_ips(const tap_t tap, char **ip_addr_list, int *entries); #endif diff --git a/libtap/tap_updown_bad/down.d/kronostest b/libtap/tap_updown_bad/down.d/kronostest index 232759ac..bd48285e 100755 --- a/libtap/tap_updown_bad/down.d/kronostest +++ b/libtap/tap_updown_bad/down.d/kronostest @@ -1,11 +1,11 @@ #!/bin/bash # -# Copyright (C) 2011-2015 Red Hat, Inc. All rights reserved. +# Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto <fabbione@kronosnet.org> # # This software licensed under GPL-2.0+, LGPL-2.0+ # exit 1 diff --git a/libtap/tap_updown_bad/post-down.d/kronostest b/libtap/tap_updown_bad/post-down.d/kronostest index 232759ac..bd48285e 100755 --- a/libtap/tap_updown_bad/post-down.d/kronostest +++ b/libtap/tap_updown_bad/post-down.d/kronostest @@ -1,11 +1,11 @@ #!/bin/bash # -# Copyright (C) 2011-2015 Red Hat, Inc. All rights reserved. +# Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto <fabbione@kronosnet.org> # # This software licensed under GPL-2.0+, LGPL-2.0+ # exit 1 diff --git a/libtap/tap_updown_bad/pre-up.d/kronostest b/libtap/tap_updown_bad/pre-up.d/kronostest index 232759ac..bd48285e 100755 --- a/libtap/tap_updown_bad/pre-up.d/kronostest +++ b/libtap/tap_updown_bad/pre-up.d/kronostest @@ -1,11 +1,11 @@ #!/bin/bash # -# Copyright (C) 2011-2015 Red Hat, Inc. All rights reserved. +# Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto <fabbione@kronosnet.org> # # This software licensed under GPL-2.0+, LGPL-2.0+ # exit 1 diff --git a/libtap/tap_updown_bad/up.d/kronostest b/libtap/tap_updown_bad/up.d/kronostest index 232759ac..bd48285e 100755 --- a/libtap/tap_updown_bad/up.d/kronostest +++ b/libtap/tap_updown_bad/up.d/kronostest @@ -1,11 +1,11 @@ #!/bin/bash # -# Copyright (C) 2011-2015 Red Hat, Inc. All rights reserved. +# Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto <fabbione@kronosnet.org> # # This software licensed under GPL-2.0+, LGPL-2.0+ # exit 1 diff --git a/libtap/tap_updown_good/down.d/kronostest b/libtap/tap_updown_good/down.d/kronostest index b0ce74c6..b6ac8715 100755 --- a/libtap/tap_updown_good/down.d/kronostest +++ b/libtap/tap_updown_good/down.d/kronostest @@ -1,11 +1,11 @@ #!/bin/bash # -# Copyright (C) 2011-2015 Red Hat, Inc. All rights reserved. +# Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto <fabbione@kronosnet.org> # # This software licensed under GPL-2.0+, LGPL-2.0+ # exit 0 diff --git a/libtap/tap_updown_good/post-down.d/kronostest b/libtap/tap_updown_good/post-down.d/kronostest index b0ce74c6..b6ac8715 100755 --- a/libtap/tap_updown_good/post-down.d/kronostest +++ b/libtap/tap_updown_good/post-down.d/kronostest @@ -1,11 +1,11 @@ #!/bin/bash # -# Copyright (C) 2011-2015 Red Hat, Inc. All rights reserved. +# Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto <fabbione@kronosnet.org> # # This software licensed under GPL-2.0+, LGPL-2.0+ # exit 0 diff --git a/libtap/tap_updown_good/pre-up.d/kronostest b/libtap/tap_updown_good/pre-up.d/kronostest index b0ce74c6..b6ac8715 100755 --- a/libtap/tap_updown_good/pre-up.d/kronostest +++ b/libtap/tap_updown_good/pre-up.d/kronostest @@ -1,11 +1,11 @@ #!/bin/bash # -# Copyright (C) 2011-2015 Red Hat, Inc. All rights reserved. +# Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto <fabbione@kronosnet.org> # # This software licensed under GPL-2.0+, LGPL-2.0+ # exit 0 diff --git a/libtap/tap_updown_good/up.d/kronostest b/libtap/tap_updown_good/up.d/kronostest index b0ce74c6..b6ac8715 100755 --- a/libtap/tap_updown_good/up.d/kronostest +++ b/libtap/tap_updown_good/up.d/kronostest @@ -1,11 +1,11 @@ #!/bin/bash # -# Copyright (C) 2011-2015 Red Hat, Inc. All rights reserved. +# Copyright (C) 2010-2017 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto <fabbione@kronosnet.org> # # This software licensed under GPL-2.0+, LGPL-2.0+ # exit 0 diff --git a/poc-code/access-list/Makefile.am b/poc-code/access-list/Makefile.am index 35f15473..fc7a86fb 100644 --- a/poc-code/access-list/Makefile.am +++ b/poc-code/access-list/Makefile.am @@ -1,22 +1,22 @@ # -# Copyright (C) 2016 Red Hat, Inc. All rights reserved. +# Copyright (C) 2016-2017 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 include $(top_srcdir)/build-aux/check.mk # override global LIBS that pulls in lots of craft we don't need here LIBS = EXTRA_DIST = test_ipcheck.txt noinst_PROGRAMS = test_ipcheck noinst_HEADERS = ipcheck.h test_ipcheck_SOURCES = ipcheck.c test_ipcheck.c diff --git a/poc-code/iov-hash/Makefile.am b/poc-code/iov-hash/Makefile.am index b4642267..9e03b8e7 100644 --- a/poc-code/iov-hash/Makefile.am +++ b/poc-code/iov-hash/Makefile.am @@ -1,22 +1,22 @@ # -# Copyright (C) 2016 Red Hat, Inc. All rights reserved. +# Copyright (C) 2016-2017 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 include $(top_srcdir)/build-aux/check.mk # override global LIBS that pulls in lots of craft we don't need here LIBS = noinst_PROGRAMS = nss_hash nss_hash_SOURCES = main.c nss_hash_CFLAGS = $(nss_CFLAGS) nss_hash_LDFLAGS = $(nss_LIBS)