diff --git a/Makefile.am b/Makefile.am index 25398bbb..047127d5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,210 +1,210 @@ # # Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto # # This software licensed under GPL-2.0+, LGPL-2.0+ # MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure depcomp \ config.guess config.sub missing install-sh \ ltmain.sh compile config.h.in config.h.in~ \ autoscan.log configure.scan test-driver \ m4/libtool.m4 m4/lt~obsolete.m4 m4/ltoptions.m4 \ m4/ltsugar.m4 m4/ltversion.m4 include $(top_srcdir)/build-aux/check.mk AUTOMAKE_OPTIONS = foreign ACLOCAL_AMFLAGS = -I m4 SPEC = $(PACKAGE_NAME).spec TARGZFILE = $(PACKAGE_NAME)-$(VERSION).tar.gz EXTRA_DIST = autogen.sh .version \ NOTES_TO_PACKAGE_MAINTAINERS \ $(SPEC).in build-aux -SUBDIRS = init libtap libknet kronosnetd +SUBDIRS = init libnozzle libknet kronosnetd if BUILD_MAN SUBDIRS += man endif if BUILD_POC SUBDIRS += poc-code endif dist_doc_DATA = \ COPYING.applications \ COPYING.libraries \ COPYRIGHT \ README.licence \ README all-local: $(SPEC) clean-local: rm -f $(SPEC) distclean-local: rm -f $(PACKAGE_NAME)-*.tar.* $(PACKAGE_NAME)-*.sha256* tag-* ## make rpm/srpm section. $(SPEC): $(SPEC).in .version config.status rm -f $@-t $@ date="`LC_ALL=C $(UTC_DATE_AT)$(SOURCE_EPOCH) "+%a %b %d %Y"`" && \ if [ -f $(abs_srcdir)/.tarball-version ]; then \ gitver="`cat $(abs_srcdir)/.tarball-version`" && \ rpmver=$$gitver && \ alphatag="" && \ dirty="" && \ numcomm="0"; \ elif [ "`git log -1 --pretty=format:x . 2>&1`" = "x" ]; then \ gitver="`GIT_DIR=$(abs_srcdir)/.git git describe --abbrev=4 --match='v*' HEAD 2>/dev/null`" && \ rpmver=`echo $$gitver | sed -e "s/^v//" -e "s/-.*//g"` && \ alphatag=`echo $$gitver | sed -e "s/.*-//" -e "s/^g//"` && \ vtag=`echo $$gitver | sed -e "s/-.*//g"` && \ numcomm=`GIT_DIR=$(abs_srcdir)/.git git rev-list $$vtag..HEAD | wc -l` && \ cd $(abs_srcdir) && \ git update-index --refresh > /dev/null 2>&1 || true && \ dirty=`git diff-index --name-only HEAD 2>/dev/null` && cd - 2>/dev/null; \ else \ gitver="`cd $(abs_srcdir); build-aux/git-version-gen .tarball-version .gitarchivever`" && \ rpmver=$$gitver && \ alphatag="" && \ dirty="" && \ numcomm="0"; \ fi && \ if [ -n "$$dirty" ]; then dirty="dirty"; else dirty=""; fi && \ if [ "$$numcomm" = "0" ]; then \ sed \ -e "s#@version@#$$rpmver#g" \ -e "s#%glo.*alpha.*##g" \ -e "s#%glo.*numcomm.*##g" \ -e "s#@dirty@#$$dirty#g" \ -e "s#@date@#$$date#g" \ $(abs_srcdir)/$@.in > $@-t; \ else \ sed \ -e "s#@version@#$$rpmver#g" \ -e "s#@alphatag@#$$alphatag#g" \ -e "s#@numcomm@#$$numcomm#g" \ -e "s#@dirty@#$$dirty#g" \ -e "s#@date@#$$date#g" \ $(abs_srcdir)/$@.in > $@-t; \ fi; \ if [ -z "$$dirty" ]; then sed -i -e "s#%glo.*dirty.*##g" $@-t; fi if BUILD_SCTP sed -i -e "s#@sctp@#bcond_without#g" $@-t else sed -i -e "s#@sctp@#bcond_with#g" $@-t endif if BUILD_CRYPTO_NSS sed -i -e "s#@nss@#bcond_without#g" $@-t else sed -i -e "s#@nss@#bcond_with#g" $@-t endif if BUILD_CRYPTO_OPENSSL sed -i -e "s#@openssl@#bcond_without#g" $@-t else sed -i -e "s#@openssl@#bcond_with#g" $@-t endif if BUILD_COMPRESS_ZLIB sed -i -e "s#@zlib@#bcond_without#g" $@-t else sed -i -e "s#@zlib@#bcond_with#g" $@-t endif if BUILD_COMPRESS_LZ4 sed -i -e "s#@lz4@#bcond_without#g" $@-t else sed -i -e "s#@lz4@#bcond_with#g" $@-t endif if BUILD_COMPRESS_LZO2 sed -i -e "s#@lzo2@#bcond_without#g" $@-t else sed -i -e "s#@lzo2@#bcond_with#g" $@-t endif if BUILD_COMPRESS_LZMA sed -i -e "s#@lzma@#bcond_without#g" $@-t else sed -i -e "s#@lzma@#bcond_with#g" $@-t endif if BUILD_COMPRESS_BZIP2 sed -i -e "s#@bzip2@#bcond_without#g" $@-t else sed -i -e "s#@bzip2@#bcond_with#g" $@-t endif if BUILD_KRONOSNETD sed -i -e "s#@kronosnetd@#bcond_without#g" $@-t else sed -i -e "s#@kronosnetd@#bcond_with#g" $@-t endif -if BUILD_LIBTAP - sed -i -e "s#@libtap@#bcond_without#g" $@-t +if BUILD_LIBNOZZLE + sed -i -e "s#@libnozzle@#bcond_without#g" $@-t else - sed -i -e "s#@libtap@#bcond_with#g" $@-t + sed -i -e "s#@libnozzle@#bcond_with#g" $@-t endif if BUILD_RUNAUTOGEN sed -i -e "s#@runautogen@#bcond_without#g" $@-t else sed -i -e "s#@runautogen@#bcond_with#g" $@-t endif if OVERRIDE_RPM_DEBUGINFO sed -i -e "s#@overriderpmdebuginfo@#bcond_without#g" $@-t else sed -i -e "s#@overriderpmdebuginfo@#bcond_with#g" $@-t endif if BUILD_RPM_DEBUGINFO sed -i -e "s#@rpmdebuginfo@#bcond_without#g" $@-t else sed -i -e "s#@rpmdebuginfo@#bcond_with#g" $@-t endif if BUILD_MAN sed -i -e "s#@buildman@#bcond_without#g" $@-t else sed -i -e "s#@buildman@#bcond_with#g" $@-t endif sed -i -e "s#@defaultadmgroup@#$(DEFAULTADMGROUP)#g" $@-t chmod a-w $@-t mv $@-t $@ rm -f $@-t* $(TARGZFILE): $(MAKE) dist RPMBUILDOPTS = --define "_sourcedir $(abs_builddir)" \ --define "_specdir $(abs_builddir)" \ --define "_builddir $(abs_builddir)" \ --define "_srcrpmdir $(abs_builddir)" \ --define "_rpmdir $(abs_builddir)" srpm: clean $(MAKE) $(SPEC) $(TARGZFILE) rpmbuild $(RPMBUILDOPTS) --nodeps -bs $(SPEC) rpm: clean $(MAKE) $(SPEC) $(TARGZFILE) rpmbuild $(RPMBUILDOPTS) -ba $(SPEC) # release/versioning BUILT_SOURCES = .version .version: echo $(VERSION) > $@-t && mv $@-t $@ dist-hook: gen-ChangeLog echo $(VERSION) > $(distdir)/.tarball-version echo $(SOURCE_EPOCH) > $(distdir)/source_epoch gen_start_date = 2000-01-01 .PHONY: gen-ChangeLog gen-ChangeLog: if test -d $(abs_srcdir)/.git; then \ LC_ALL=C $(top_srcdir)/build-aux/gitlog-to-changelog \ --since=$(gen_start_date) > $(distdir)/cl-t; \ rm -f $(distdir)/ChangeLog; \ mv $(distdir)/cl-t $(distdir)/ChangeLog; \ fi diff --git a/NOTES_TO_PACKAGE_MAINTAINERS b/NOTES_TO_PACKAGE_MAINTAINERS index 829e7331..eae9a9da 100644 --- a/NOTES_TO_PACKAGE_MAINTAINERS +++ b/NOTES_TO_PACKAGE_MAINTAINERS @@ -1,31 +1,31 @@ To: distribution package maintainers Those are a few things about this project that you should know. I surely welcome patches to support both in a better way. DO NOT ship kronosnetd. It's an experimental piece of super crappy code. IF you decide to ship it anyway, you get to be also the upstream maintainer :-) you have been warned. -libtap is a simple commodity library used only by kronosnetd. +libnozzle is a simple commodity library used only by kronosnetd. I don't mind to support it, but don't ship just for the fun of it. It has no users, that I know of, outside of kronosnetd. libknet is still under heavy development. There might be more onwire network changes that could make current version incompatible with newer versions. Make sure to warn your users about it. Plan is to release a stable version (1.0) when we are confident that the current implementation is stable enough. libknet has a lot of build dependencies due to its modular implementation. It does not, however, link with all those libraries but uses a dlopen model to save runtime resources and provide flexibility to users to install only the libraries they are planning to use. Make sure that you do build with all feature enabled (compatible with your distribution licencing/patent policy of course) and tune your packaging to Recommend/Suggest the external libraries. Thanks Your upstream maintainers diff --git a/README b/README index bf602992..a50f27fd 100644 --- a/README +++ b/README @@ -1,35 +1,36 @@ # # Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto # # This software licensed under GPL-2.0+, LGPL-2.0+ # Upstream resources ------------------ https://github.com/kronosnet/kronosnet/ https://ci.kronosnet.org/ https://trello.com/kronosnet (TODO list and activities tracking) https://goo.gl/9ZvkLS (google shared drive) https://github.com/kronosnet/knet-ansible-ci https://lists.kronosnet.org/mailman/listinfo/users https://lists.kronosnet.org/mailman/listinfo/devel https://lists.kronosnet.org/mailman/listinfo/commits https://kronosnet.org/ (web 0.1 style) IRC: #kronosnet on Freenode Architecture ------------ Please refer to the google shared drive Presentations directory for diagrams and fancy schemas Running knet on FreeBSD ----------------------- knet requires big socket buffers and you need to set: kern.ipc.maxsockbuf=18388608 in /etc/sysctl.conf or knet will fail to run. +libnozzle requires if_tap.ko loaded in the kernel. diff --git a/build-aux/git-version-gen b/build-aux/git-version-gen index 693513e7..fc70e306 100755 --- a/build-aux/git-version-gen +++ b/build-aux/git-version-gen @@ -1,263 +1,263 @@ #!/bin/sh # Print a version string. scriptversion=2018-08-31.20; # UTC -# Copyright (C) 2018 Red Hat, Inc. +# Copyright (C) 2012-2018 Red Hat, Inc. # Copyright (C) 2007-2016 Free Software Foundation, Inc. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/. # It may be run two ways: # - from a git repository in which the "git describe" command below # produces useful output (thus requiring at least one signed tag) # - from a non-git-repo directory containing a .tarball-version file, which # presumes this script is invoked like "./git-version-gen .tarball-version". # In order to use intra-version strings in your project, you will need two # separate generated version string files: # # .tarball-version - present only in a distribution tarball, and not in # a checked-out repository. Created with contents that were learned at # the last time autoconf was run, and used by git-version-gen. Must not # be present in either $(srcdir) or $(builddir) for git-version-gen to # give accurate answers during normal development with a checked out tree, # but must be present in a tarball when there is no version control system. # Therefore, it cannot be used in any dependencies. GNUmakefile has # hooks to force a reconfigure at distribution time to get the value # correct, without penalizing normal development with extra reconfigures. # # .version - present in a checked-out repository and in a distribution # tarball. Usable in dependencies, particularly for files that don't # want to depend on config.h but do want to track version changes. # Delete this file prior to any autoconf run where you want to rebuild # files to pick up a version string change; and leave it stale to # minimize rebuild time after unrelated changes to configure sources. # # As with any generated file in a VC'd directory, you should add # /.version to .gitignore, so that you don't accidentally commit it. # .tarball-version is never generated in a VC'd directory, so needn't # be listed there. # # In order to use git archive versions another two files has to be presented: # # .gitarchive-version - present in checked-out repository and git # archive tarball, but not in the distribution tarball. Used as a last # option for version. File must contain special string $Format:%d$, # which is substitued by git on archive operation. # # .gitattributes - present in checked-out repository and git archive # tarball, but not in the distribution tarball. Must set export-subst # attribute for .gitarchive-version file. # # Use the following line in your configure.ac, so that $(VERSION) will # automatically be up-to-date each time configure is run (and note that # since configure.ac no longer includes a version string, Makefile rules # should not depend on configure.ac for version updates). # # AC_INIT([GNU project], # m4_esyscmd([build-aux/git-version-gen .tarball-version]), # [bug-project@example]) # # Then use the following lines in your Makefile.am, so that .version # will be present for dependencies, and so that .version and # .tarball-version will exist in distribution tarballs. # # EXTRA_DIST = $(top_srcdir)/.version # BUILT_SOURCES = $(top_srcdir)/.version # $(top_srcdir)/.version: # echo $(VERSION) > $@-t && mv $@-t $@ # dist-hook: # echo $(VERSION) > $(distdir)/.tarball-version me=$0 version="git-version-gen $scriptversion Copyright 2011 Free Software Foundation, Inc. There is NO warranty. You may redistribute this software under the terms of the GNU General Public License. For more information about these matters, see the files named COPYING." usage="\ Usage: $me [OPTION]... \$srcdir/.tarball-version [\$srcdir/.gitarchive-version] [TAG-NORMALIZATION-SED-SCRIPT] Print a version string. Options: --prefix PREFIX prefix of git tags (default 'v') --fallback VERSION fallback version to use if \"git --version\" fails --help display this help and exit --version output version information and exit Running without arguments will suffice in most cases." prefix=v fallback= while test $# -gt 0; do case $1 in --help) echo "$usage"; exit 0;; --version) echo "$version"; exit 0;; --prefix) shift; prefix="$1";; --fallback) shift; fallback="$1";; -*) echo "$0: Unknown option '$1'." >&2 echo "$0: Try '--help' for more information." >&2 exit 1;; *) if test "x$tarball_version_file" = x; then tarball_version_file="$1" elif test "x$gitarchive_version_file" = x; then gitarchive_version_file="$1" elif test "x$tag_sed_script" = x; then tag_sed_script="$1" else echo "$0: extra non-option argument '$1'." >&2 exit 1 fi;; esac shift done if test "x$tarball_version_file" = x; then echo "$usage" exit 1 fi tag_sed_script="${tag_sed_script:-s/x/x/}" nl=' ' # Avoid meddling by environment variable of the same name. v= v_from_git= # First see if there is a tarball-only version file. # then try "git describe", then default. if test -f $tarball_version_file then v=`cat $tarball_version_file` || v= case $v in *$nl*) v= ;; # reject multi-line output [0-9]*) ;; *) v= ;; esac test "x$v" = x \ && echo "$0: WARNING: $tarball_version_file is missing or damaged" 1>&2 fi if test "x$v" != x then : # use $v # Otherwise, if there is at least one git commit involving the working # directory, and "git describe" output looks sensible, use that to # derive a version string. elif test "`git log -1 --pretty=format:x . 2>&1`" = x \ && v=`git describe --abbrev=4 --match="$prefix*" HEAD 2>/dev/null \ || git describe --abbrev=4 HEAD 2>/dev/null` \ && v=`printf '%s\n' "$v" | sed "$tag_sed_script"` \ && case $v in $prefix[0-9]*) ;; *) (exit 1) ;; esac then # Is this a new git that lists number of commits since the last # tag or the previous older version that did not? # Newer: v6.10-77-g0f8faeb # Older: v6.10-g0f8faeb case $v in *-*-*) : git describe is okay three part flavor ;; *-*) : git describe is older two part flavor # Recreate the number of commits and rewrite such that the # result is the same as if we were using the newer version # of git describe. vtag=`echo "$v" | sed 's/-.*//'` commit_list=`git rev-list "$vtag"..HEAD 2>/dev/null` \ || { commit_list=failed; echo "$0: WARNING: git rev-list failed" 1>&2; } numcommits=`echo "$commit_list" | wc -l` v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`; test "$commit_list" = failed && v=UNKNOWN ;; esac # Change the first '-' to a '.', so version-comparing tools work properly. # Remove the "g" in git describe's output string, to save a byte. v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`; v_from_git=1 elif test "x$fallback" = x || git --version >/dev/null 2>&1; then if test -f $gitarchive_version_file then v=`sed "s/^.*tag: \($prefix[0-9)][^,)]*\).*\$/\1/" $gitarchive_version_file \ | sed "$tag_sed_script"` || exit 1 case $v in *$nl*) v= ;; # reject multi-line output $prefix[0-9]*) ;; *) v= ;; esac test -z "$v" \ && echo "$0: WARNING: $gitarchive_version_file doesn't contain valid version tag" 1>&2 \ && v=UNKNOWN else v=UNKNOWN fi else v=$fallback fi if test "x$fallback" = x -a "$v" = "UNKNOWN" then echo "$0: ERROR: Can't find valid version. Please use valid git repository," \ "released tarball or version tagged archive" 1>&2 exit 1 fi v=`echo "$v" |sed "s/^$prefix//"` # Test whether to append the "-dirty" suffix only if the version # string we're using came from git. I.e., skip the test if it's "UNKNOWN" # or if it came from .tarball-version. if test "x$v_from_git" != x; then # Don't declare a version "dirty" merely because a time stamp has changed. git update-index --refresh > /dev/null 2>&1 dirty=`exec 2>/dev/null;git diff-index --name-only HEAD` || dirty= case "$dirty" in '') ;; *) # Append the suffix only if there isn't one already. case $v in *-dirty) ;; *) v="$v-dirty" ;; esac ;; esac fi # Omit the trailing newline, so that m4_esyscmd can use the result directly. printf %s "$v" # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: diff --git a/build-aux/update-copyright.sh b/build-aux/update-copyright.sh index babb25a3..fd50f8ea 100755 --- a/build-aux/update-copyright.sh +++ b/build-aux/update-copyright.sh @@ -1,29 +1,29 @@ #!/bin/sh # # Copyright (C) 2017 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto # # This software licensed under GPL-2.0+, LGPL-2.0+ # # script to update copyright dates across the tree enddate=$(date +%Y) -input=$(grep -ril -e "Copyright.*Red Hat" |grep -v .swp |grep -v update-copyright) +input=$(grep -ril -e "Copyright.*Red Hat" |grep -v .swp |grep -v update-copyright |grep -v doxyxml.c) for i in $input; do 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/configure.ac b/configure.ac index e906e4a3..2a6608f1 100644 --- a/configure.ac +++ b/configure.ac @@ -1,531 +1,540 @@ # # Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. # # Authors: Fabio M. Di Nitto # Federico Simoncelli # # This software licensed under GPL-2.0+, LGPL-2.0+ # # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. # AC_PREREQ([2.63]) AC_INIT([kronosnet], m4_esyscmd([build-aux/git-version-gen .tarball-version .gitarchivever]), [devel@lists.kronosnet.org]) # Don't let AC_PROC_CC (invoked by AC_USE_SYSTEM_EXTENSIONS) replace # undefined CFLAGS with -g -O2, overriding our special OPT_CFLAGS. : ${CFLAGS=""} AC_USE_SYSTEM_EXTENSIONS AM_INIT_AUTOMAKE([1.13 dist-bzip2 dist-xz color-tests -Wno-portability subdir-objects]) LT_PREREQ([2.2.6]) # --enable-new-dtags: Use RUNPATH instead of RPATH. # It is necessary to have this done before libtool does linker detection. # See also: https://github.com/kronosnet/kronosnet/issues/107 # --as-needed: Modern systems have builtin ceil() making -lm superfluous but # AC_SEARCH_LIBS can't detect this because it tests with a false prototype AX_CHECK_LINK_FLAG([-Wl,--enable-new-dtags], [AM_LDFLAGS=-Wl,--enable-new-dtags], [AC_MSG_ERROR(["Linker support for --enable-new-dtags is required"])]) AX_CHECK_LINK_FLAG([-Wl,--as-needed], [AM_LDFLAGS="$AM_LDFLAGS -Wl,--as-needed"]) AC_SUBST([AM_LDFLAGS]) saved_LDFLAGS="$LDFLAGS" LDFLAGS="$AM_LDFLAGS $LDFLAGS" LT_INIT LDFLAGS="$saved_LDFLAGS" AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([kronosnetd/main.c]) AC_CONFIG_HEADERS([config.h]) AC_CANONICAL_HOST AC_LANG([C]) systemddir=${prefix}/lib/systemd/system if test "$prefix" = "NONE"; then prefix="/usr" if test "$localstatedir" = "\${prefix}/var"; then localstatedir="/var" fi if test "$sysconfdir" = "\${prefix}/etc"; then sysconfdir="/etc" fi if test "$systemddir" = "NONE/lib/systemd/system"; then systemddir=/lib/systemd/system fi if test "$libdir" = "\${exec_prefix}/lib"; then if test -e /usr/lib64; then libdir="/usr/lib64" else libdir="/usr/lib" fi fi fi AC_PROG_AWK AC_PROG_GREP AC_PROG_SED AC_PROG_CPP AC_PROG_CC AC_PROG_CC_C99 if test "x$ac_cv_prog_cc_c99" = "xno"; then AC_MSG_ERROR(["C99 support is required"]) fi AC_PROG_LN_S AC_PROG_INSTALL AC_PROG_MAKE_SET PKG_PROG_PKG_CONFIG AC_CHECK_PROGS([VALGRIND_EXEC], [valgrind]) AM_CONDITIONAL([HAS_VALGRIND], [test x$VALGRIND_EXEC != "x"]) # KNET_OPTION_DEFINES(stem,type,detection code) # stem: enters name of option, Automake conditional and preprocessor define # type: compress or crypto, determines where the default comes from AC_DEFUN([KNET_OPTION_DEFINES],[ AC_ARG_ENABLE([$2-$1],[AS_HELP_STRING([--disable-$2-$1],[disable libknet $1 support])],, [enable_$2_$1="$enable_$2_all"]) AM_CONDITIONAL([BUILD_]m4_toupper([$2_$1]),[test "x$enable_$2_$1" = xyes]) if test "x$enable_$2_$1" = xyes; then $3 fi AC_DEFINE_UNQUOTED([WITH_]m4_toupper([$2_$1]), [`test "x$enable_$2_$1" != xyes; echo $?`], $1 $2 [built in]) ]) AC_ARG_ENABLE([man], [AS_HELP_STRING([--disable-man],[disable man page creation])],, [ enable_man="yes" ]) AM_CONDITIONAL([BUILD_MAN], [test x$enable_man = xyes]) AC_ARG_ENABLE([libknet-sctp], [AS_HELP_STRING([--disable-libknet-sctp],[disable libknet SCTP support])],, [ enable_libknet_sctp="yes" ]) AM_CONDITIONAL([BUILD_SCTP], [test x$enable_libknet_sctp = xyes]) AC_ARG_ENABLE([crypto-all], [AS_HELP_STRING([--disable-crypto-all],[disable libknet all crypto modules support])],, [ enable_crypto_all="yes" ]) KNET_OPTION_DEFINES([nss],[crypto],[PKG_CHECK_MODULES([nss], [nss])]) KNET_OPTION_DEFINES([openssl],[crypto],[ PKG_CHECK_MODULES([openssl],[libcrypto < 1.1], [AC_DEFINE_UNQUOTED([BUILDCRYPTOOPENSSL10], [1], [openssl 1.0 crypto])], [PKG_CHECK_MODULES([openssl],[libcrypto >= 1.1], [AC_DEFINE_UNQUOTED([BUILDCRYPTOOPENSSL11], [1], [openssl 1.1 crypto])])]) ]) AC_ARG_ENABLE([compress-all], [AS_HELP_STRING([--disable-compress-all],[disable libknet all compress modules support])],, [ enable_compress_all="yes" ]) KNET_OPTION_DEFINES([zlib],[compress],[PKG_CHECK_MODULES([zlib], [zlib])]) KNET_OPTION_DEFINES([lz4],[compress],[PKG_CHECK_MODULES([liblz4], [liblz4])]) KNET_OPTION_DEFINES([lzo2],[compress],[ PKG_CHECK_MODULES([lzo2], [lzo2], [# work around broken pkg-config file in v2.10 AC_SUBST([lzo2_CFLAGS],[`echo $lzo2_CFLAGS | sed 's,/lzo *, ,'`])], [AC_CHECK_HEADERS([lzo/lzo1x.h], [AC_CHECK_LIB([lzo2], [lzo1x_decompress_safe], [AC_SUBST([lzo2_LIBS], [-llzo2])])], [AC_MSG_ERROR(["missing required lzo/lzo1x.h header"])])]) ]) KNET_OPTION_DEFINES([lzma],[compress],[PKG_CHECK_MODULES([liblzma], [liblzma])]) KNET_OPTION_DEFINES([bzip2],[compress],[ PKG_CHECK_MODULES([bzip2], [bzip2],, [AC_CHECK_HEADERS([bzlib.h], [AC_CHECK_LIB([bz2], [BZ2_bzBuffToBuffCompress], [AC_SUBST([bzip2_LIBS], [-lbz2])])], [AC_MSG_ERROR(["missing required bzlib.h"])])]) ]) AC_ARG_ENABLE([poc], [AS_HELP_STRING([--enable-poc],[enable building poc code])],, [ enable_poc="no" ]) AM_CONDITIONAL([BUILD_POC], [test x$enable_poc = xyes]) AC_ARG_ENABLE([kronosnetd], [AS_HELP_STRING([--enable-kronosnetd],[Kronosnetd support])],, [ enable_kronosnetd="no" ]) AM_CONDITIONAL([BUILD_KRONOSNETD], [test x$enable_kronosnetd = xyes]) AC_ARG_ENABLE([runautogen], [AS_HELP_STRING([--enable-runautogen],[run autogen.sh])],, [ enable_runautogen="no" ]) AM_CONDITIONAL([BUILD_RUNAUTOGEN], [test x$enable_runautogen = xyes]) override_rpm_debuginfo_option="yes" AC_ARG_ENABLE([rpm-debuginfo], [AS_HELP_STRING([--enable-rpm-debuginfo],[build debuginfo packages])],, [ enable_rpm_debuginfo="no", override_rpm_debuginfo_option="no" ]) AM_CONDITIONAL([BUILD_RPM_DEBUGINFO], [test x$enable_rpm_debuginfo = xyes]) AM_CONDITIONAL([OVERRIDE_RPM_DEBUGINFO], [test x$override_rpm_debuginfo_option = xyes]) -AC_ARG_ENABLE([libtap], - [AS_HELP_STRING([--enable-libtap],[libtap support])],, - [ enable_libtap="no" ]) +AC_ARG_ENABLE([libnozzle], + [AS_HELP_STRING([--enable-libnozzle],[libnozzle support])],, + [ enable_libnozzle="yes" ]) if test "x$enable_kronosnetd" = xyes; then - enable_libtap=yes + enable_libnozzle=yes fi -AM_CONDITIONAL([BUILD_LIBTAP], [test x$enable_libtap = xyes]) +AM_CONDITIONAL([BUILD_LIBNOZZLE], [test x$enable_libnozzle = xyes]) ## local helper functions # this function checks if CC support options passed as # args. Global CPPFLAGS are ignored during this test. cc_supports_flag() { saveCPPFLAGS="$CPPFLAGS" CPPFLAGS="$@" if echo $CC | grep -q clang; then CPPFLAGS="-Werror $CPPFLAGS" fi AC_MSG_CHECKING([whether $CC supports "$@"]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], [RC=0; AC_MSG_RESULT([yes])], [RC=1; AC_MSG_RESULT([no])]) CPPFLAGS="$saveCPPFLAGS" return $RC } # Checks for libraries. AX_PTHREAD(,[AC_MSG_ERROR([POSIX threads support is required])]) saved_LIBS="$LIBS" LIBS= AC_SEARCH_LIBS([ceil], [m], , [AC_MSG_ERROR([ceil not found])]) AC_SUBST([m_LIBS], [$LIBS]) LIBS= AC_SEARCH_LIBS([clock_gettime], [rt], , [AC_MSG_ERROR([clock_gettime not found])]) AC_SUBST([rt_LIBS], [$LIBS]) LIBS= AC_SEARCH_LIBS([dlopen], [dl dld], , [AC_MSG_ERROR([dlopen not found])]) AC_SUBST([dl_LIBS], [$LIBS]) LIBS="$saved_LIBS" # OS detection AC_MSG_CHECKING([for os in ${host_os}]) case "$host_os" in *linux*) AC_DEFINE_UNQUOTED([KNET_LINUX], [1], [Compiling for Linux platform]) AC_MSG_RESULT([Linux]) ;; *bsd*) AC_DEFINE_UNQUOTED([KNET_BSD], [1], [Compiling for BSD platform]) AC_MSG_RESULT([BSD]) - if test "x$enable_libtap" = xyes; then - AC_MSG_ERROR([libtap is not currently supported on BSD platforms]) - fi ;; *) AC_MSG_ERROR([Unsupported OS? hmmmm]) ;; esac # Checks for header files. AC_CHECK_HEADERS([sys/epoll.h]) AC_CHECK_FUNCS([kevent]) # if neither sys/epoll.h nor kevent are present, we should fail. if test "x$ac_cv_header_sys_epoll_h" = xno && test "x$ac_cv_func_kevent" = xno; then AC_MSG_ERROR([Both epoll and kevent unavailable on this OS]) fi if test "x$ac_cv_header_sys_epoll_h" = xyes && test "x$ac_cv_func_kevent" = xyes; then AC_MSG_ERROR([Both epoll and kevent available on this OS, please contact the maintainers to fix the code]) fi if test "x$enable_libknet_sctp" = xyes; then AC_CHECK_HEADERS([netinet/sctp.h],, [AC_MSG_ERROR(["missing required SCTP headers"])]) fi # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE AC_TYPE_PID_T AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_UINT8_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_INT8_T AC_TYPE_INT16_T AC_TYPE_INT32_T AC_TYPE_INT64_T if test "x$enable_man" = "xyes"; then AC_ARG_VAR([DOXYGEN], [override doxygen executable]) AC_CHECK_PROGS([DOXYGEN], [doxygen], [no]) if test "x$DOXYGEN" = xno; then AC_MSG_ERROR(["Doxygen command not found"]) fi # required by doxyxml to build man pages dynamically # Don't let AC_PROC_CC (invoked by AX_PROG_CC_FOR_BUILD) replace # undefined CFLAGS_FOR_BUILD with -g -O2, overriding our special OPT_CFLAGS. : ${CFLAGS_FOR_BUILD=""} AX_PROG_CC_FOR_BUILD saved_PKG_CONFIG="$PKG_CONFIG" saved_ac_cv_path_PKG_CONFIG="$ac_cv_path_PKG_CONFIG" unset PKG_CONFIG ac_cv_path_PKG_CONFIG AC_PATH_PROG([PKG_CONFIG], [pkg-config]) PKG_CHECK_MODULES([libqb_BUILD], [libqb]) PKG_CHECK_MODULES([libxml_BUILD], [libxml-2.0]) PKG_CONFIG="$saved_PKG_CONFIG" ac_cv_path_PKG_CONFIG="$saved_ac_cv_path_PKG_CONFIG" fi -# checks (for kronosnetd) +# checks for libnozzle +if test "x$enable_libnozzle" = xyes; then + if `echo $host_os | grep -q linux`; then + PKG_CHECK_MODULES([libnl], [libnl-3.0]) + PKG_CHECK_MODULES([libnlroute], [libnl-route-3.0 >= 3.3], [], + [PKG_CHECK_MODULES([libnlroute], [libnl-route-3.0 < 3.3], + [AC_DEFINE_UNQUOTED([LIBNL3_WORKAROUND], [1], [Enable libnl < 3.3 build workaround])], [])]) + fi +fi + +# checks for kronosnetd if test "x$enable_kronosnetd" = xyes; then AC_CHECK_HEADERS([security/pam_appl.h], [AC_CHECK_LIB([pam], [pam_start], [AC_SUBST([pam_LIBS], [-lpam])], [AC_MSG_ERROR([Unable to find LinuxPAM devel files])])]) AC_CHECK_HEADERS([security/pam_misc.h], [AC_CHECK_LIB([pam_misc], [misc_conv], [AC_SUBST([pam_misc_LIBS], [-lpam_misc])], [AC_MSG_ERROR([Unable to find LinuxPAM MISC devel files])])]) PKG_CHECK_MODULES([libqb], [libqb]) AC_CHECK_LIB([qb], [qb_log_thread_priority_set], [have_qb_log_thread_priority_set="yes"], [have_qb_log_thread_priority_set="no"]) if test "x${have_qb_log_thread_priority_set}" = xyes; then AC_DEFINE_UNQUOTED([HAVE_QB_LOG_THREAD_PRIORITY_SET], [1], [have qb_log_thread_priority_set]) fi fi # local options AC_ARG_ENABLE([debug], [AS_HELP_STRING([--enable-debug],[enable debug build])]) AC_ARG_WITH([initdefaultdir], [AS_HELP_STRING([--with-initdefaultdir=DIR],[path to /etc/sysconfig or /etc/default dir])], [ INITDEFAULTDIR="$withval" ], [ INITDEFAULTDIR="$sysconfdir/default" ]) AC_ARG_WITH([initddir], [AS_HELP_STRING([--with-initddir=DIR],[path to init script directory])], [ INITDDIR="$withval" ], [ INITDDIR="$sysconfdir/init.d" ]) AC_ARG_WITH([systemddir], [AS_HELP_STRING([--with-systemddir=DIR],[path to systemd unit files directory])], [ SYSTEMDDIR="$withval" ], [ SYSTEMDDIR="$systemddir" ]) AC_ARG_WITH([syslogfacility], [AS_HELP_STRING([--with-syslogfacility=FACILITY],[default syslog facility])], [ SYSLOGFACILITY="$withval" ], [ SYSLOGFACILITY="LOG_DAEMON" ]) AC_ARG_WITH([sysloglevel], [AS_HELP_STRING([--with-sysloglevel=LEVEL],[default syslog level])], [ SYSLOGLEVEL="$withval" ], [ SYSLOGLEVEL="LOG_INFO" ]) AC_ARG_WITH([defaultadmgroup], [AS_HELP_STRING([--with-defaultadmgroup=GROUP], [define PAM group. Users part of this group will be allowed to configure kronosnet. Others will only receive read-only rights.])], [ DEFAULTADMGROUP="$withval" ], [ DEFAULTADMGROUP="kronosnetadm" ]) ## random vars LOGDIR=${localstatedir}/log/ RUNDIR=${localstatedir}/run/ DEFAULT_CONFIG_DIR=${sysconfdir}/kronosnet ## do subst AC_SUBST([DEFAULT_CONFIG_DIR]) AC_SUBST([INITDEFAULTDIR]) AC_SUBST([INITDDIR]) AC_SUBST([SYSTEMDDIR]) AC_SUBST([LOGDIR]) AC_SUBST([DEFAULTADMGROUP]) AC_DEFINE_UNQUOTED([DEFAULT_CONFIG_DIR], ["$(eval echo ${DEFAULT_CONFIG_DIR})"], [Default config directory]) AC_DEFINE_UNQUOTED([DEFAULT_CONFIG_FILE], ["$(eval echo ${DEFAULT_CONFIG_DIR}/kronosnetd.conf)"], [Default config file]) AC_DEFINE_UNQUOTED([LOGDIR], ["$(eval echo ${LOGDIR})"], [Default logging directory]) AC_DEFINE_UNQUOTED([DEFAULT_LOG_FILE], ["$(eval echo ${LOGDIR}/kronosnetd.log)"], [Default log file]) AC_DEFINE_UNQUOTED([RUNDIR], ["$(eval echo ${RUNDIR})"], [Default run directory]) AC_DEFINE_UNQUOTED([SYSLOGFACILITY], [$(eval echo ${SYSLOGFACILITY})], [Default syslog facility]) AC_DEFINE_UNQUOTED([SYSLOGLEVEL], [$(eval echo ${SYSLOGLEVEL})], [Default syslog level]) AC_DEFINE_UNQUOTED([DEFAULTADMGROUP], ["$(eval echo ${DEFAULTADMGROUP})"], [Default admin group]) # debug build stuff if test "x${enable_debug}" = xyes; then AC_DEFINE_UNQUOTED([DEBUG], [1], [Compiling Debugging code]) OPT_CFLAGS="-O0" else OPT_CFLAGS="-O3" fi # gdb flags if test "x${GCC}" = xyes; then GDB_FLAGS="-ggdb3" else GDB_FLAGS="-g" fi # extra warnings EXTRA_WARNINGS="" WARNLIST=" all extra unused shadow missing-prototypes missing-declarations suggest-attribute=noreturn suggest-attribute=format property-attribute-mismatch strict-prototypes declaration-after-statement pointer-arith write-strings cast-align bad-function-cast missing-format-attribute float-equal format=2 format-signedness format-security format-nonliteral no-long-long unsigned-char gnu89-inline no-strict-aliasing error address cpp overflow parentheses sequence-point switch shift-overflow shift-overflow=2 overlength-strings retundent-decls init-self uninitialized unused-but-set-variable unused-const-variable unused-function unused-result unused-value unused-variable unknown-pragmas no-unused-parameter " for j in $WARNLIST; do if cc_supports_flag -W$j; then EXTRA_WARNINGS="$EXTRA_WARNINGS -W$j"; fi done AC_SUBST([AM_CFLAGS],["$OPT_CFLAGS $GDB_FLAGS $EXTRA_WARNINGS"]) AX_PROG_DATE AS_IF([test "$ax_cv_prog_date_gnu_date:$ax_cv_prog_date_gnu_utc" = yes:yes], [UTC_DATE_AT="date -u -d@"], [AS_IF([test "x$ax_cv_prog_date_bsd_date" = xyes], [UTC_DATE_AT="date -u -r"], [AC_MSG_ERROR([date utility unable to convert epoch to UTC])])]) AC_SUBST([UTC_DATE_AT]) AC_ARG_VAR([SOURCE_EPOCH],[last modification date of the source]) AC_MSG_NOTICE([trying to determine source epoch]) AC_MSG_CHECKING([for source epoch in \$SOURCE_EPOCH]) AS_IF([test -n "$SOURCE_EPOCH"], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) AC_MSG_CHECKING([for source epoch in source_epoch file]) AS_IF([test -e "$srcdir/source_epoch"], [read SOURCE_EPOCH <"$srcdir/source_epoch" AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) AC_MSG_CHECKING([for source epoch baked in by gitattributes export-subst]) SOURCE_EPOCH='$Format:%at$' # template for rewriting by git-archive AS_CASE([$SOURCE_EPOCH], [?Format:*], # was not rewritten [AC_MSG_RESULT([no]) AC_MSG_CHECKING([for source epoch in \$SOURCE_DATE_EPOCH]) AS_IF([test "x$SOURCE_DATE_EPOCH" != x], [SOURCE_EPOCH="$SOURCE_DATE_EPOCH" AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) AC_MSG_CHECKING([whether git log can provide a source epoch]) SOURCE_EPOCH=f${SOURCE_EPOCH#\$F} # convert into git log --pretty format SOURCE_EPOCH=$(cd "$srcdir" && git log -1 --pretty=${SOURCE_EPOCH%$} 2>/dev/null) AS_IF([test -n "$SOURCE_EPOCH"], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no, using current time and breaking reproducibility]) SOURCE_EPOCH=$(date +%s)])])], [AC_MSG_RESULT([yes])] )]) ]) AC_MSG_NOTICE([using source epoch $($UTC_DATE_AT$SOURCE_EPOCH +'%F %T %Z')]) AC_CONFIG_FILES([ Makefile init/Makefile - libtap/Makefile - libtap/libtap.pc + libnozzle/Makefile + libnozzle/libnozzle.pc + libnozzle/tests/Makefile kronosnetd/Makefile kronosnetd/kronosnetd.logrotate libknet/Makefile libknet/libknet.pc libknet/tests/Makefile man/Makefile man/Doxyfile-knet + man/Doxyfile-nozzle poc-code/Makefile poc-code/iov-hash/Makefile poc-code/access-list/Makefile ]) if test "x$VERSION" = "xUNKNOWN"; then AC_MSG_ERROR([m4_text_wrap([ configure was unable to determine the source tree's current version. This generally happens when using git archive (or the github download button) generated tarball/zip file. In order to workaround this issue, either use git clone https://github.com/kronosnet/kronosnet.git or use an official release tarball, available at https://kronosnet.org/releases/. Alternatively you can add a compatible version in a .tarball-version file at the top of the source tree, wipe your autom4te.cache dir and generated configure, and rerun autogen.sh. ], [ ], [ ], [76])]) fi AC_OUTPUT diff --git a/kronosnet.spec.in b/kronosnet.spec.in index a9cb445e..9e9903aa 100644 --- a/kronosnet.spec.in +++ b/kronosnet.spec.in @@ -1,537 +1,540 @@ ############################################################################### ############################################################################### ## ## Copyright (C) 2012-2018 Red Hat, Inc. All rights reserved. ## ## This copyrighted material is made available to anyone wishing to use, ## modify, copy, or redistribute it subject to the terms and conditions ## of the GNU General Public License v.2 or higher ## ############################################################################### ############################################################################### # keep around ready for later user %global alphatag @alphatag@ %global numcomm @numcomm@ %global dirty @dirty@ # set defaults from ./configure invokation %@sctp@ sctp %@nss@ nss %@openssl@ openssl %@zlib@ zlib %@lz4@ lz4 %@lzo2@ lzo2 %@lzma@ lzma %@bzip2@ bzip2 %@kronosnetd@ kronosnetd -%@libtap@ libtap +%@libnozzle@ libnozzle %@runautogen@ runautogen %@rpmdebuginfo@ rpmdebuginfo %@overriderpmdebuginfo@ overriderpmdebuginfo %@buildman@ buildman %if %{with overriderpmdebuginfo} %undefine _enable_debug_packages %endif %if %{with sctp} %global buildsctp 1 %endif %if %{with nss} %global buildcryptonss 1 %endif %if %{with openssl} %global buildcryptoopenssl 1 %endif %if %{with zlib} %global buildcompresszlib 1 %endif %if %{with lz4} %global buildcompresslz4 1 %endif %if %{with lzo2} %global buildcompresslzo2 1 %endif %if %{with lzma} %global buildcompresslzma 1 %endif %if %{with bzip2} %global buildcompressbzip2 1 %endif -%if %{with libtap} -%global buildlibtap 1 +%if %{with libnozzle} +%global buildlibnozzle 1 %endif %if %{with kronosnetd} -%global buildlibtap 1 +%global buildlibnozzle 1 %global buildkronosnetd 1 %endif %if %{with runautogen} %global buildautogen 1 %endif %if %{with buildman} %global buildmanpages 1 %endif # main (empty) package # http://www.rpm.org/max-rpm/s1-rpm-subpack-spec-file-changes.html Name: kronosnet Summary: Multipoint-to-Multipoint VPN daemon Version: @version@ Release: 1%{?numcomm:.%{numcomm}}%{?alphatag:.%{alphatag}}%{?dirty:.%{dirty}}%{?dist} License: GPLv2+ and LGPLv2+ Group: System Environment/Base URL: https://github.com/kronosnet/kronosnet/ Source0: https://github.com/kronosnet/kronosnet/archive/%{name}-%{version}%{?numcomm:.%{numcomm}}%{?alphatag:-%{alphatag}}%{?dirty:-%{dirty}}.tar.gz ## Setup/build bits BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) # Build dependencies BuildRequires: gcc # required to build man pages %if %{defined buildmanpages} BuildRequires: libqb-devel libxml2-devel doxygen %endif %if %{defined buildsctp} BuildRequires: lksctp-tools-devel %endif %if %{defined buildcryptonss} BuildRequires: /usr/include/nss3/nss.h /usr/include/nspr4/nspr.h %endif %if %{defined buildcryptoopenssl} BuildRequires: /usr/include/openssl/conf.h %endif %if %{defined buildcompresszlib} BuildRequires: zlib-devel %endif %if %{defined buildcompresslz4} BuildRequires: /usr/include/lz4hc.h %endif %if %{defined buildcompresslzo2} BuildRequires: lzo-devel %endif %if %{defined buildcompresslzma} BuildRequires: xz-devel %endif %if %{defined buildcompressbzip2} BuildRequires: /usr/include/bzlib.h %endif %if %{defined buildkronosnetd} BuildRequires: pam-devel %endif +%if %{defined buildlibnozzle} +BuildRequires: libnl3-devel +%endif %if %{defined buildautogen} BuildRequires: autoconf BuildRequires: automake BuildRequires: libtool %endif %prep %setup -q -n %{name}-%{version}%{?numcomm:.%{numcomm}}%{?alphatag:-%{alphatag}}%{?dirty:-%{dirty}} %build %if %{with runautogen} ./autogen.sh %endif %{configure} \ %if %{defined buildmanpages} --enable-man \ %else --disable-man \ %endif %if %{defined buildsctp} --enable-libknet-sctp \ %else --disable-libknet-sctp \ %endif %if %{defined buildcryptonss} --enable-crypto-nss \ %else --disable-crypto-nss \ %endif %if %{defined buildcryptoopenssl} --enable-crypto-openssl \ %else --disable-crypto-openssl \ %endif %if %{defined buildcompresszlib} --enable-compress-zlib \ %else --disable-compress-zlib \ %endif %if %{defined buildcompresslz4} --enable-compress-lz4 \ %else --disable-compress-lz4 \ %endif %if %{defined buildcompresslzo2} --enable-compress-lzo2 \ %else --disable-compress-lzo2 \ %endif %if %{defined buildcompresslzma} --enable-compress-lzma \ %else --disable-compress-lzma \ %endif %if %{defined buildcompressbzip2} --enable-compress-bzip2 \ %else --disable-compress-bzip2 \ %endif %if %{defined buildkronosnetd} --enable-kronosnetd \ %endif -%if %{defined buildlibtap} - --enable-libtap \ +%if %{defined buildlibnozzle} + --enable-libnozzle \ %endif --with-initdefaultdir=%{_sysconfdir}/sysconfig/ \ %if %{defined _unitdir} --with-systemddir=%{_unitdir} %else --with-initddir=%{_sysconfdir}/rc.d/init.d/ %endif make %{_smp_mflags} %install rm -rf %{buildroot} make install DESTDIR=%{buildroot} # tree cleanup # remove static libraries find %{buildroot} -name "*.a" -exec rm {} \; # remove libtools leftovers find %{buildroot} -name "*.la" -exec rm {} \; # handle systemd vs init script %if %{defined _unitdir} # remove init scripts rm -rf %{buildroot}/etc/init.d %else # remove systemd specific bits find %{buildroot} -name "*.service" -exec rm {} \; %endif # remove docs rm -rf %{buildroot}/usr/share/doc/kronosnet %clean rm -rf %{buildroot} # main empty package %description kronosnet source %if %{defined buildkronosnetd} ## Runtime and subpackages section %package -n kronosnetd Group: System Environment/Base Summary: Multipoint-to-Multipoint VPN daemon %if %{defined _unitdir} # Needed for systemd unit Requires(post): systemd-sysv Requires(post): systemd-units Requires(preun): systemd-units Requires(postun): systemd-units %else Requires(post): chkconfig Requires(preun): chkconfig, initscripts %endif Requires(post): shadow-utils Requires(preun): shadow-utils Requires: pam, /etc/pam.d/passwd %description -n kronosnetd The kronosnet daemon is a bridge between kronosnet switching engine and kernel network tap devices, to create and administer a distributed LAN over multipoint-to-multipoint VPNs. The daemon does a poor attempt to provide a configure UI similar to other known network devices/tools (Cisco, quagga). Beside looking horrific, it allows runtime changes and reconfiguration of the kronosnet(s) without daemon reload or service disruption. %post -n kronosnetd %if %{defined _unitdir} %if 0%{?systemd_post:1} %systemd_post kronosnetd.service %else /bin/systemctl daemon-reload >/dev/null 2>&1 || : %endif %else /sbin/chkconfig --add kronosnetd %endif /usr/sbin/groupadd --force --system @defaultadmgroup@ %preun -n kronosnetd %if %{defined _unitdir} %if 0%{?systemd_preun:1} %systemd_preun kronosnetd.service %else if [ "$1" -eq 0 ]; then /bin/systemctl --no-reload disable kronosnetd.service /bin/systemctl stop kronosnetd.service >/dev/null 2>&1 fi %endif %else if [ "$1" = 0 ]; then /sbin/service kronosnetd stop >/dev/null 2>&1 /sbin/chkconfig --del kronosnetd fi %endif %files -n kronosnetd %defattr(-,root,root,-) %doc COPYING.* COPYRIGHT %dir %{_sysconfdir}/kronosnet %dir %{_sysconfdir}/kronosnet/* %config(noreplace) %{_sysconfdir}/sysconfig/kronosnetd %config(noreplace) %{_sysconfdir}/pam.d/kronosnetd %config(noreplace) %{_sysconfdir}/logrotate.d/kronosnetd %if %{defined _unitdir} %{_unitdir}/kronosnetd.service %else %config(noreplace) %{_sysconfdir}/rc.d/init.d/kronosnetd %endif %{_sbindir}/* %{_mandir}/man8/* %endif -%if %{defined buildlibtap} -%package -n libtap1 +%if %{defined buildlibnozzle} +%package -n libnozzle1 Group: System Environment/Libraries Summary: Simple userland wrapper around kernel tap devices -%description -n libtap1 +%description -n libnozzle1 This is an over-engineered commodity library to manage a pool of tap devices and provides the basic pre-up.d/up.d/down.d/post-down.d infrastructure. -%files -n libtap1 +%files -n libnozzle1 %defattr(-,root,root,-) %doc COPYING.* COPYRIGHT -%{_libdir}/libtap.so.* +%{_libdir}/libnozzle.so.* -%post -n libtap1 -p /sbin/ldconfig +%post -n libnozzle1 -p /sbin/ldconfig -%postun -n libtap1 -p /sbin/ldconfig +%postun -n libnozzle1 -p /sbin/ldconfig -%package -n libtap1-devel +%package -n libnozzle1-devel Group: Development/Libraries Summary: Simple userland wrapper around kernel tap devices (developer files) -Requires: libtap1 = %{version}-%{release} +Requires: libnozzle1 = %{version}-%{release} Requires: pkgconfig -%description -n libtap1-devel +%description -n libnozzle1-devel This is an over-engineered commodity library to manage a pool of tap devices and provides the basic pre-up.d/up.d/down.d/post-down.d infrastructure. -%files -n libtap1-devel +%files -n libnozzle1-devel %defattr(-,root,root,-) %doc COPYING.* COPYRIGHT -%{_libdir}/libtap.so -%{_includedir}/libtap.h -%{_libdir}/pkgconfig/libtap.pc +%{_libdir}/libnozzle.so +%{_includedir}/libnozzle.h +%{_libdir}/pkgconfig/libnozzle.pc %endif %package -n libknet1 Group: System Environment/Libraries Summary: Kronosnet core switching implementation %description -n libknet1 The whole kronosnet core is implemented in this library. Please refer to the not-yet-existing documentation for further information. %files -n libknet1 %defattr(-,root,root,-) %doc COPYING.* COPYRIGHT %{_libdir}/libknet.so.* %dir %{_libdir}/kronosnet %post -n libknet1 -p /sbin/ldconfig %postun -n libknet1 -p /sbin/ldconfig %package -n libknet1-devel Group: Development/Libraries Summary: Kronosnet core switching implementation (developer files) Requires: libknet1 = %{version}-%{release} Requires: pkgconfig %description -n libknet1-devel The whole kronosnet core is implemented in this library. Please refer to the not-yet-existing documentation for further information. %files -n libknet1-devel %defattr(-,root,root,-) %doc COPYING.* COPYRIGHT %{_libdir}/libknet.so %{_includedir}/libknet.h %{_libdir}/pkgconfig/libknet.pc %if %{defined buildmanpages} %{_mandir}/man3/knet*.3.gz %endif %if %{defined buildcryptonss} %package -n libknet1-crypto-nss-plugin Group: System Environment/Libraries Summary: libknet1 nss support Requires: libknet1 = %{version}-%{release} %description -n libknet1-crypto-nss-plugin NSS crypto support for libknet1. %files -n libknet1-crypto-nss-plugin %defattr(-,root,root,-) %{_libdir}/kronosnet/crypto_nss.so %endif %if %{defined buildcryptoopenssl} %package -n libknet1-crypto-openssl-plugin Group: System Environment/Libraries Summary: libknet1 openssl support Requires: libknet1 = %{version}-%{release} %description -n libknet1-crypto-openssl-plugin OpenSSL crypto support for libknet1. %files -n libknet1-crypto-openssl-plugin %defattr(-,root,root,-) %{_libdir}/kronosnet/crypto_openssl.so %endif %if %{defined buildcompresszlib} %package -n libknet1-compress-zlib-plugin Group: System Environment/Libraries Summary: libknet1 zlib support Requires: libknet1 = %{version}-%{release} %description -n libknet1-compress-zlib-plugin zlib compression support for libknet1. %files -n libknet1-compress-zlib-plugin %defattr(-,root,root,-) %{_libdir}/kronosnet/compress_zlib.so %endif %if %{defined buildcompresslz4} %package -n libknet1-compress-lz4-plugin Group: System Environment/Libraries Summary: libknet1 lz4 and lz4hc support Requires: libknet1 = %{version}-%{release} %description -n libknet1-compress-lz4-plugin lz4 and lz4hc compression support for libknet1. %files -n libknet1-compress-lz4-plugin %defattr(-,root,root,-) %{_libdir}/kronosnet/compress_lz4.so %{_libdir}/kronosnet/compress_lz4hc.so %endif %if %{defined buildcompresslzo2} %package -n libknet1-compress-lzo2-plugin Group: System Environment/Libraries Summary: libknet1 lzo2 support Requires: libknet1 = %{version}-%{release} %description -n libknet1-compress-lzo2-plugin lzo2 compression support for libknet1. %files -n libknet1-compress-lzo2-plugin %defattr(-,root,root,-) %{_libdir}/kronosnet/compress_lzo2.so %endif %if %{defined buildcompresslzma} %package -n libknet1-compress-lzma-plugin Group: System Environment/Libraries Summary: libknet1 lzma support Requires: libknet1 = %{version}-%{release} %description -n libknet1-compress-lzma-plugin lzma compression support for libknet1. %files -n libknet1-compress-lzma-plugin %defattr(-,root,root,-) %{_libdir}/kronosnet/compress_lzma.so %endif %if %{defined buildcompressbzip2} %package -n libknet1-compress-bzip2-plugin Group: System Environment/Libraries Summary: libknet1 bzip2 support Requires: libknet1 = %{version}-%{release} %description -n libknet1-compress-bzip2-plugin bzip2 compression support for libknet1. %files -n libknet1-compress-bzip2-plugin %defattr(-,root,root,-) %{_libdir}/kronosnet/compress_bzip2.so %endif %package -n libknet1-crypto-plugins-all Group: System Environment/Libraries Summary: libknet1 crypto plugins meta package %if %{defined buildcryptonss} Requires: libknet1-crypto-nss-plugin %endif %if %{defined buildcryptoopenssl} Requires: libknet1-crypto-openssl-plugin %endif %description -n libknet1-crypto-plugins-all meta package to install all of libknet1 crypto plugins %files -n libknet1-crypto-plugins-all %package -n libknet1-compress-plugins-all Group: System Environment/Libraries Summary: libknet1 compress plugins meta package %if %{defined buildcompresszlib} Requires: libknet1-compress-zlib-plugin %endif %if %{defined buildcompresslz4} Requires: libknet1-compress-lz4-plugin %endif %if %{defined buildcompresslzo2} Requires: libknet1-compress-lzo2-plugin %endif %if %{defined buildcompresslzma} Requires: libknet1-compress-lzma-plugin %endif %if %{defined buildcompressbzip2} Requires: libknet1-compress-bzip2-plugin %endif %description -n libknet1-compress-plugins-all meta package to install all of libknet1 compress plugins %files -n libknet1-compress-plugins-all %package -n libknet1-plugins-all Group: System Environment/Libraries Summary: libknet1 plugins meta package Requires: libknet1-compress-plugins-all Requires: libknet1-crypto-plugins-all %description -n libknet1-plugins-all meta package to install all of libknet1 plugins %files -n libknet1-plugins-all %if %{with rpmdebuginfo} %debug_package %endif %changelog * @date@ Autotools generated version - @version@-1-@numcomm@.@alphatag@.@dirty@ - These aren't the droids you're looking for. diff --git a/kronosnetd/Makefile.am b/kronosnetd/Makefile.am index 8c233579..9dfb2445 100644 --- a/kronosnetd/Makefile.am +++ b/kronosnetd/Makefile.am @@ -1,89 +1,89 @@ # # Copyright (C) 2012-2018 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto # # This software licensed under GPL-2.0+, LGPL-2.0+ # MAINTAINERCLEANFILES = Makefile.in kronostnetd.logrotate include $(top_srcdir)/build-aux/check.mk EXTRA_DIST = kronosnetd.logrotate.in noinst_HEADERS = \ cfg.h \ etherfilter.h \ logging.h \ vty.h \ vty_auth.h \ vty_cli.h \ vty_cli_cmds.h \ vty_utils.h kronosnetd_SOURCES = \ cfg.c \ etherfilter.c \ main.c \ logging.c \ vty.c \ vty_auth.c \ vty_cli.c \ vty_cli_cmds.c \ vty_utils.c kronosnetd_CPPFLAGS = \ - -I$(top_srcdir)/libtap \ + -I$(top_srcdir)/libnozzle \ -I$(top_srcdir)/libknet kronosnetd_CFLAGS = $(AM_CFLAGS) $(libqb_CFLAGS) kronosnetd_LDADD = \ $(top_builddir)/libknet/libknet.la \ - $(top_builddir)/libtap/libtap.la \ + $(top_builddir)/libnozzle/libnozzle.la \ $(libqb_LIBS) \ $(pam_misc_LIBS) $(pam_LIBS) knet_keygen_SOURCES = keygen.c knet_keygen_CPPFLAGS = -I$(top_srcdir)/libknet if BUILD_KRONOSNETD sbin_PROGRAMS = kronosnetd \ knet-keygen install-exec-local: $(INSTALL) -d $(DESTDIR)/$(DEFAULT_CONFIG_DIR) $(INSTALL) -d $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/down.d $(INSTALL) -d $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/post-down.d $(INSTALL) -d $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/pre-up.d $(INSTALL) -d $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/up.d $(INSTALL) -d $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/cryptokeys.d $(INSTALL) -d -m 0755 $(DESTDIR)/$(sysconfdir)/logrotate.d $(INSTALL) -m 644 kronosnetd.logrotate $(DESTDIR)/$(sysconfdir)/logrotate.d/kronosnetd $(INSTALL) -d -m 0755 $(DESTDIR)/$(sysconfdir)/pam.d if [ -a $(sysconfdir)/pam.d/password-auth ]; then \ cd $(DESTDIR)/$(sysconfdir)/pam.d && \ rm -f kronosnetd && \ $(LN_S) password-auth kronosnetd; \ else \ cd $(DESTDIR)/$(sysconfdir)/pam.d && \ rm -f kronosnetd && \ $(LN_S) passwd kronosnetd; \ fi uninstall-local: rmdir $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/cryptokeys.d || :; rmdir $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/down.d || :; rmdir $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/post-down.d || :; rmdir $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/pre-up.d || :; rmdir $(DESTDIR)/$(DEFAULT_CONFIG_DIR)/up.d || :; rmdir $(DESTDIR)/$(DEFAULT_CONFIG_DIR) || :; rm -f $(DESTDIR)/$(sysconfdir)/logrotate.d/kronosnetd rmdir $(DESTDIR)/$(sysconfdir)/logrotate.d || :; rm -f $(DESTDIR)/$(sysconfdir)/pam.d/kronosnetd || :; rmdir $(DESTDIR)/$(sysconfdir)/pam.d || :; endif diff --git a/kronosnetd/cfg.c b/kronosnetd/cfg.c index 60fdc15d..d2663926 100644 --- a/kronosnetd/cfg.c +++ b/kronosnetd/cfg.c @@ -1,88 +1,88 @@ /* * Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. * * Author: Fabio M. Di Nitto * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include #include #include #include #include "cfg.h" -#include "libtap.h" +#include "libnozzle.h" struct knet_cfg *knet_get_iface(const char *name, int create) { struct knet_cfg *knet_iface = knet_cfg_head.knet_cfg; int found = 0; while (knet_iface != NULL) { if (!strcmp(tap_get_name(knet_iface->cfg_eth.tap), name)) { 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 49f66af7..b884ffb4 100644 --- a/kronosnetd/cfg.h +++ b/kronosnetd/cfg.h @@ -1,55 +1,55 @@ /* * Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto * Federico Simoncelli * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #ifndef __KNETD_CFG_H__ #define __KNETD_CFG_H__ #include #include -#include "libtap.h" +#include "libnozzle.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/vty_cli_cmds.c b/kronosnetd/vty_cli_cmds.c index 5ed875e8..bf795e6e 100644 --- a/kronosnetd/vty_cli_cmds.c +++ b/kronosnetd/vty_cli_cmds.c @@ -1,2188 +1,2188 @@ /* * Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. * * Authors: Fabio M. Di Nitto * Federico Simoncelli * * This software licensed under GPL-2.0+, LGPL-2.0+ */ #include "config.h" #include #include #include #include #include #include #include #include "cfg.h" #include "etherfilter.h" #include "logging.h" -#include "libtap.h" +#include "libnozzle.h" #include "netutils.h" #include "vty.h" #include "vty_cli.h" #include "vty_cli_cmds.h" #include "vty_utils.h" #define KNET_VTY_MAX_MATCHES 64 #define KNET_VTY_MATCH_HELP 0 #define KNET_VTY_MATCH_EXEC 1 #define KNET_VTY_MATCH_EXPAND 2 #define CMDS_PARAM_NOMORE 0 #define CMDS_PARAM_KNET 1 #define CMDS_PARAM_IP 2 #define CMDS_PARAM_IP_PREFIX 3 #define CMDS_PARAM_IP_PORT 4 #define CMDS_PARAM_BOOL 5 #define CMDS_PARAM_INT 6 #define CMDS_PARAM_NODEID 7 #define CMDS_PARAM_NAME 8 #define CMDS_PARAM_MTU 9 #define CMDS_PARAM_CRYPTO_MODEL 10 #define CMDS_PARAM_CRYPTO_TYPE 11 #define CMDS_PARAM_HASH_TYPE 12 #define CMDS_PARAM_POLICY 13 #define CMDS_PARAM_LINK_ID 14 #define CMDS_PARAM_LINK_PRI 15 #define CMDS_PARAM_LINK_KEEPAL 16 #define CMDS_PARAM_LINK_HOLDTI 17 #define CMDS_PARAM_LINK_PONG 18 #define CMDS_PARAM_VTY_TIMEOUT 19 #define CMDS_PARAM_PMTU_FREQ 20 #define CMDS_PARAM_LINK_TRANSP 21 /* * 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/libnozzle/Makefile.am b/libnozzle/Makefile.am new file mode 100644 index 00000000..3a49d23b --- /dev/null +++ b/libnozzle/Makefile.am @@ -0,0 +1,49 @@ +# +# Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. +# +# Author: Fabio M. Di Nitto +# +# This software licensed under GPL-2.0+, LGPL-2.0+ +# + +MAINTAINERCLEANFILES = Makefile.in + +include $(top_srcdir)/build-aux/check.mk + +SYMFILE = libnozzle_exported_syms + +EXTRA_DIST = $(SYMFILE) + +if BUILD_LIBNOZZLE + +SUBDIRS = . tests + +libversion = 1:0:0 + +sources = libnozzle.c \ + internals.c + +include_HEADERS = libnozzle.h + +pkgconfigdir = $(libdir)/pkgconfig + +pkgconfig_DATA = libnozzle.pc + +noinst_HEADERS = \ + internals.h + +lib_LTLIBRARIES = libnozzle.la + +libnozzle_la_SOURCES = $(sources) + +libnozzle_la_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) $(libnl_CFLAGS) $(libnlroute_CFLAGS) + +EXTRA_libnozzle_la_DEPENDENCIES = $(SYMFILE) + +libnozzle_la_LDFLAGS = $(AM_LDFLAGS) \ + -Wl,-version-script,$(srcdir)/$(SYMFILE) \ + -version-info $(libversion) + +libnozzle_la_LIBADD = $(PTHREAD_LIBS) $(libnl_LIBS) $(libnlroute_LIBS) + +endif diff --git a/libnozzle/internals.c b/libnozzle/internals.c new file mode 100644 index 00000000..c294eb4e --- /dev/null +++ b/libnozzle/internals.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libnozzle.h" +#include "internals.h" + +static int read_pipe(int fd, char **file, size_t *length) +{ + char buf[4096]; + int n; + int done = 0; + + *file = NULL; + *length = 0; + + memset(buf, 0, sizeof(buf)); + + while (!done) { + + n = read(fd, buf, sizeof(buf)); + + if (n < 0) { + if (errno == EINTR) + continue; + + if (*file) + free(*file); + + return n; + } + + if (n == 0 && (!*length)) + return 0; + + if (n == 0) + done = 1; + + if (*file) + *file = realloc(*file, (*length) + n + done); + else + *file = malloc(n + done); + + if (!*file) + return -1; + + memmove((*file) + (*length), buf, n); + *length += (done + n); + } + + /* Null terminator */ + (*file)[(*length) - 1] = 0; + + return 0; +} + +int execute_bin_sh_command(const char *command, char **error_string) +{ + pid_t pid; + int status, err = 0; + int fd[2]; + size_t size = 0; + + if ((command == NULL) || (!error_string)) { + errno = EINVAL; + return -1; + } + + *error_string = NULL; + + err = pipe(fd); + if (err) + goto out_clean; + + pid = fork(); + if (pid < 0) { + err = pid; + goto out_clean; + } + + if (pid) { /* parent */ + + close(fd[1]); + err = read_pipe(fd[0], error_string, &size); + if (err) + goto out_clean0; + + waitpid(pid, &status, 0); + if (!WIFEXITED(status)) { + err = -1; + goto out_clean0; + } + if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { + err = WEXITSTATUS(status); + goto out_clean0; + } + goto out_clean0; + } else { /* child */ + close(0); + close(1); + close(2); + + close(fd[0]); + dup2(fd[1], 1); + dup2(fd[1], 2); + close(fd[1]); + + execlp("/bin/sh", "/bin/sh", "-c", command, NULL); + exit(EXIT_FAILURE); + } + +out_clean: + close(fd[1]); +out_clean0: + close(fd[0]); + + return err; +} + +char *generate_v4_broadcast(const char *ipaddr, const char *prefix) +{ + int prefix_len; + struct in_addr mask; + struct in_addr broadcast; + struct in_addr address; + + prefix_len = atoi(prefix); + + if ((prefix_len > 32) || (prefix_len < 0)) + return NULL; + + if (inet_pton(AF_INET, ipaddr, &address) <= 0) + return NULL; + + mask.s_addr = htonl(~((1 << (32 - prefix_len)) - 1)); + + memset(&broadcast, 0, sizeof(broadcast)); + broadcast.s_addr = (address.s_addr & mask.s_addr) | ~mask.s_addr; + + return strdup(inet_ntoa(broadcast)); +} + +int find_ip(nozzle_t nozzle, + const char *ipaddr, const char *prefix, + struct nozzle_ip **ip, struct nozzle_ip **ip_prev) +{ + struct nozzle_ip *local_ip, *local_ip_prev; + int found = 0; + + local_ip = local_ip_prev = nozzle->ip; + + while(local_ip) { + if ((!strcmp(local_ip->ipaddr, ipaddr)) && (!strcmp(local_ip->prefix, prefix))) { + found = 1; + break; + } + local_ip_prev = local_ip; + local_ip = local_ip->next; + } + + if (found) { + *ip = local_ip; + *ip_prev = local_ip_prev; + } + + return found; +} diff --git a/libnozzle/internals.h b/libnozzle/internals.h new file mode 100644 index 00000000..f7bd2e1e --- /dev/null +++ b/libnozzle/internals.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#ifndef __NOZZLE_INTERNALS_H__ +#define __NOZZLE_INTERNALS_H__ + +#include "config.h" + +#ifdef KNET_LINUX +#include +#endif +#include +#include "libnozzle.h" + +struct nozzle_lib_config { + struct nozzle_iface *head; + int ioctlfd; +#ifdef KNET_LINUX + struct nl_sock *nlsock; +#endif +}; + +#define MACADDR_CHAR_MAX 18 + +/* + * 11 = post-down.d + * 1 = / + */ +#define UPDOWN_PATH_MAX PATH_MAX - 11 - 1 - IFNAMSIZ + +struct nozzle_iface { + char name[IFNAMSIZ]; /* interface name */ + int fd; /* interface fd */ + int up; /* interface status 0 is down, 1 is up */ + /* + * extra data + */ + struct nozzle_ip *ip; /* configured ip addresses */ + + /* + * default MAC address assigned by the kernel at creation time + */ + char default_mac[MACADDR_CHAR_MAX + 1]; + + int default_mtu; /* MTU assigned by the kernel at creation time */ + int current_mtu; /* MTU configured by libnozzle user */ + + int hasupdown; /* interface has up/down path to scripts configured */ + char updownpath[UPDOWN_PATH_MAX]; /* path to up/down scripts if configured */ + + struct nozzle_iface *next; +}; + +#define ifname ifr.ifr_name + +int execute_bin_sh_command(const char *command, char **error_string); + +int find_ip(nozzle_t nozzle, + const char *ipaddr, const char *prefix, + struct nozzle_ip **ip, struct nozzle_ip **ip_prev); + +char *generate_v4_broadcast(const char *ipaddr, const char *prefix); + +#endif diff --git a/libnozzle/libnozzle.c b/libnozzle/libnozzle.c new file mode 100644 index 00000000..903f36ae --- /dev/null +++ b/libnozzle/libnozzle.c @@ -0,0 +1,1207 @@ +/* + * Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef KNET_LINUX +#include +/* + * libnl3 < 3.3 includes kernel headers directly + * causing conflicts with net/if.h included above + */ +#ifdef LIBNL3_WORKAROUND +#define _LINUX_IF_H 1 +#endif +#include +#include +#include +#include +#endif +#ifdef KNET_BSD +#include +#endif + +#include "libnozzle.h" +#include "internals.h" + +/* + * internal functions are all _unlocked_ + * locking should be handled at external API functions + */ +static int lib_init = 0; +static struct nozzle_lib_config lib_cfg; +static pthread_mutex_t config_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* + * internal helpers + */ + +static void lib_fini(void) +{ + if (lib_cfg.head == NULL) { +#ifdef KNET_LINUX + nl_close(lib_cfg.nlsock); + nl_socket_free(lib_cfg.nlsock); +#endif + close(lib_cfg.ioctlfd); + lib_init = 0; + } +} + +static int is_valid_nozzle(const nozzle_t nozzle) +{ + nozzle_t temp; + + if (!nozzle) { + return 0; + } + + if (!lib_init) { + return 0; + } + + temp = lib_cfg.head; + + while (temp != NULL) { + if (nozzle == temp) + return 1; + + temp = temp->next; + } + + return 0; +} + +static void destroy_iface(nozzle_t nozzle) +{ +#ifdef KNET_BSD + struct ifreq ifr; +#endif + + if (!nozzle) + return; + + if (nozzle->fd) + close(nozzle->fd); + +#ifdef KNET_BSD + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifname, nozzle->name, IFNAMSIZ); + + ioctl(lib_cfg.ioctlfd, SIOCIFDESTROY, &ifr); +#endif + + free(nozzle); + + lib_fini(); + + return; +} + +static int get_iface_mtu(const nozzle_t nozzle) +{ + int err = 0, savederrno = 0; + struct ifreq ifr; + + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifname, nozzle->name, IFNAMSIZ); + + err = ioctl(lib_cfg.ioctlfd, SIOCGIFMTU, &ifr); + if (err) { + savederrno = errno; + goto out_clean; + } + + err = ifr.ifr_mtu; + +out_clean: + errno = savederrno; + return err; +} + +static int get_iface_mac(const nozzle_t nozzle, char **ether_addr) +{ + int err = 0, savederrno = 0; + struct ifreq ifr; + char mac[MACADDR_CHAR_MAX]; +#ifdef KNET_BSD + struct ifaddrs *ifap = NULL; + struct ifaddrs *ifa; + int found = 0; +#endif + + memset(&mac, 0, MACADDR_CHAR_MAX); + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifname, nozzle->name, IFNAMSIZ); + +#ifdef KNET_LINUX + err = ioctl(lib_cfg.ioctlfd, SIOCGIFHWADDR, &ifr); + if (err) { + savederrno = errno; + goto out_clean; + } + + ether_ntoa_r((struct ether_addr *)ifr.ifr_hwaddr.sa_data, mac); +#endif +#ifdef KNET_BSD + /* + * there is no ioctl to get the ether address of an interface on FreeBSD + * (not to be confused with hwaddr). Use workaround described here: + * https://lists.freebsd.org/pipermail/freebsd-hackers/2004-June/007394.html + */ + err = getifaddrs(&ifap); + if (err < 0) { + savederrno = errno; + goto out_clean; + } + + ifa = ifap; + + while (ifa) { + if (!strncmp(nozzle->name, ifa->ifa_name, IFNAMSIZ)) { + found = 1; + break; + } + ifa=ifa->ifa_next; + } + + if (found) { + ether_ntoa_r((struct ether_addr *)LLADDR((struct sockaddr_dl *)ifa->ifa_addr), mac); + } else { + errno = EINVAL; + err = -1; + } + + freeifaddrs(ifap); + + if (err) { + goto out_clean; + } + +#endif + *ether_addr = strdup(mac); + if (!*ether_addr) { + savederrno = errno; + err = -1; + } + +out_clean: + errno = savederrno; + return err; +} + +#define IP_ADD 1 +#define IP_DEL 2 + +static int _set_ip(nozzle_t nozzle, + int command, + const char *ipaddr, const char *prefix, + int secondary) +{ + int fam; + char *broadcast = NULL; + int err = 0; +#ifdef KNET_LINUX + struct rtnl_addr *addr = NULL; + struct nl_addr *local_addr = NULL; + struct nl_addr *bcast_addr = NULL; + struct nl_cache *cache = NULL; + int ifindex; +#endif +#ifdef KNET_BSD + char cmdline[4096]; + char proto[6]; + char *error_string = NULL; +#endif + + if (!strchr(ipaddr, ':')) { + fam = AF_INET; + broadcast = generate_v4_broadcast(ipaddr, prefix); + if (!broadcast) { + errno = EINVAL; + return -1; + } + } else { + fam = AF_INET6; + } + +#ifdef KNET_LINUX + addr = rtnl_addr_alloc(); + if (!addr) { + errno = ENOMEM; + return -1; + } + + if (rtnl_link_alloc_cache(lib_cfg.nlsock, AF_UNSPEC, &cache) < 0) { + errno = ENOMEM; + err = -1; + goto out; + } + + ifindex = rtnl_link_name2i(cache, nozzle->name); + if (ifindex == 0) { + errno = ENOENT; + err = -1; + goto out; + } + + rtnl_addr_set_ifindex(addr, ifindex); + + if (nl_addr_parse(ipaddr, fam, &local_addr) < 0) { + errno = EINVAL; + err = -1; + goto out; + } + + if (rtnl_addr_set_local(addr, local_addr) < 0) { + errno = EINVAL; + err = -1; + goto out; + } + + if (broadcast) { + if (nl_addr_parse(broadcast, fam, &bcast_addr) < 0) { + errno = EINVAL; + err = -1; + goto out; + } + + if (rtnl_addr_set_broadcast(addr, bcast_addr) < 0) { + errno = EINVAL; + err = -1; + goto out; + } + } + + rtnl_addr_set_prefixlen(addr, atoi(prefix)); + + if (command == IP_ADD) { + if (rtnl_addr_add(lib_cfg.nlsock, addr, 0) < 0) { + errno = EINVAL; + err = -1; + goto out; + } + } else { + if (rtnl_addr_delete(lib_cfg.nlsock, addr, 0) < 0) { + errno = EINVAL; + err = -1; + goto out; + } + } +out: + if (addr) { + rtnl_addr_put(addr); + } + if (local_addr) { + nl_addr_put(local_addr); + } + if (bcast_addr) { + nl_addr_put(bcast_addr); + } + if (cache) { + nl_cache_put(cache); + } + if (broadcast) { + free(broadcast); + } + return err; +#endif +#ifdef KNET_BSD + /* + * TODO: port to use ioctl and such, drop shell forking here + */ + memset(cmdline, 0, sizeof(cmdline)); + + if (fam == AF_INET) { + snprintf(proto, sizeof(proto), "inet"); + } else { + snprintf(proto, sizeof(proto), "inet6"); + } + + if (command == IP_ADD) { + snprintf(cmdline, sizeof(cmdline)-1, + "ifconfig %s %s %s/%s", + nozzle->name, proto, ipaddr, prefix); + if (broadcast) { + snprintf(cmdline + strlen(cmdline), + sizeof(cmdline) - strlen(cmdline) -1, + " broadcast %s", broadcast); + } + if ((secondary) && (fam == AF_INET)) { + snprintf(cmdline + strlen(cmdline), + sizeof(cmdline) - strlen(cmdline) -1, + " alias"); + } + } else { + snprintf(cmdline, sizeof(cmdline)-1, + "ifconfig %s %s %s/%s delete", + nozzle->name, proto, ipaddr, prefix); + } + if (broadcast) { + free(broadcast); + } + + /* + * temporary workaround as we port libnozzle to BSD ioctl + * for IP address management + */ + err = execute_bin_sh_command(cmdline, &error_string); + if (error_string) { + free(error_string); + error_string = NULL; + } + return err; +#endif +} + +/* + * Exported public API + */ + +nozzle_t nozzle_open(char *devname, size_t devname_size, const char *updownpath) +{ + int savederrno = 0; + nozzle_t nozzle = NULL; + char *temp_mac = NULL; +#ifdef KNET_LINUX + struct ifreq ifr; +#endif +#ifdef KNET_BSD + uint16_t i; + long int nozzlenum = 0; + char curnozzle[IFNAMSIZ]; +#endif + + if (devname == NULL) { + errno = EINVAL; + return NULL; + } + + if (devname_size < IFNAMSIZ) { + errno = EINVAL; + return NULL; + } + + if (strlen(devname) > IFNAMSIZ) { + errno = E2BIG; + return NULL; + } + +#ifdef KNET_BSD + /* + * BSD does not support named devices like Linux + * but it is possible to force a nozzleX device number + * where X is 0 to 255. + */ + if (strlen(devname)) { + if (strncmp(devname, "tap", 3)) { + errno = EINVAL; + return NULL; + } + errno = 0; + nozzlenum = strtol(devname+3, NULL, 10); + if (errno) { + errno = EINVAL; + return NULL; + } + if ((nozzlenum < 0) || (nozzlenum > 255)) { + errno = EINVAL; + return NULL; + } + } +#endif + + if (updownpath) { + /* only absolute paths */ + if (updownpath[0] != '/') { + errno = EINVAL; + return NULL; + } + if (strlen(updownpath) >= UPDOWN_PATH_MAX) { + errno = E2BIG; + return NULL; + } + } + + savederrno = pthread_mutex_lock(&config_mutex); + if (savederrno) { + errno = savederrno; + return NULL; + } + + if (!lib_init) { + lib_cfg.head = NULL; +#ifdef KNET_LINUX + lib_cfg.nlsock = nl_socket_alloc(); + if (!lib_cfg.nlsock) { + savederrno = errno; + goto out_error; + } + if (nl_connect(lib_cfg.nlsock, NETLINK_ROUTE) < 0) { + savederrno = EBUSY; + goto out_error; + } + lib_cfg.ioctlfd = socket(AF_INET, SOCK_STREAM, 0); +#endif +#ifdef KNET_BSD + lib_cfg.ioctlfd = socket(AF_LOCAL, SOCK_DGRAM, 0); +#endif + if (lib_cfg.ioctlfd < 0) { + savederrno = errno; + goto out_error; + } + lib_init = 1; + } + + nozzle = malloc(sizeof(struct nozzle_iface)); + if (!nozzle) { + savederrno = ENOMEM; + goto out_error; + } + + memset(nozzle, 0, sizeof(struct nozzle_iface)); + +#ifdef KNET_BSD + if (!strlen(devname)) { + for (i = 0; i < 256; i++) { + snprintf(curnozzle, sizeof(curnozzle) - 1, "/dev/tap%u", i); + nozzle->fd = open(curnozzle, O_RDWR); + savederrno = errno; + if (nozzle->fd > 0) { + break; + } + } + snprintf(curnozzle, sizeof(curnozzle) -1 , "tap%u", i); + } else { + snprintf(curnozzle, sizeof(curnozzle) - 1, "/dev/%s", devname); + nozzle->fd = open(curnozzle, O_RDWR); + savederrno = errno; + snprintf(curnozzle, sizeof(curnozzle) - 1, "%s", devname); + } + if (nozzle->fd < 0) { + savederrno = EBUSY; + goto out_error; + } + strncpy(devname, curnozzle, IFNAMSIZ); + strncpy(nozzle->name, curnozzle, IFNAMSIZ); +#endif + +#ifdef KNET_LINUX + if ((nozzle->fd = open("/dev/net/tun", O_RDWR)) < 0) { + savederrno = errno; + goto out_error; + } + + memset(&ifr, 0, sizeof(struct ifreq)); + memmove(ifname, devname, IFNAMSIZ); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + + if (ioctl(nozzle->fd, TUNSETIFF, &ifr) < 0) { + savederrno = errno; + goto out_error; + } + + if ((strlen(devname) > 0) && (strcmp(devname, ifname) != 0)) { + savederrno = EBUSY; + goto out_error; + } + + strncpy(devname, ifname, IFNAMSIZ); + strncpy(nozzle->name, ifname, IFNAMSIZ); +#endif + + nozzle->default_mtu = get_iface_mtu(nozzle); + if (nozzle->default_mtu < 0) { + savederrno = errno; + goto out_error; + } + + if (get_iface_mac(nozzle, &temp_mac) < 0) { + savederrno = errno; + goto out_error; + } + + strncpy(nozzle->default_mac, temp_mac, 18); + free(temp_mac); + + if (updownpath) { + int len = strlen(updownpath); + + strcpy(nozzle->updownpath, updownpath); + if (nozzle->updownpath[len-1] != '/') { + nozzle->updownpath[len] = '/'; + } + nozzle->hasupdown = 1; + } + + nozzle->next = lib_cfg.head; + lib_cfg.head = nozzle; + + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return nozzle; + +out_error: + destroy_iface(nozzle); + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return NULL; +} + +int nozzle_close(nozzle_t nozzle) +{ + int err = 0, savederrno = 0; + nozzle_t temp = lib_cfg.head; + nozzle_t prev = lib_cfg.head; + struct nozzle_ip *ip, *ip_next; + + savederrno = pthread_mutex_lock(&config_mutex); + if (savederrno) { + errno = savederrno; + return -1; + } + + if (!is_valid_nozzle(nozzle)) { + savederrno = EINVAL; + err = -1; + goto out_clean; + } + + while ((temp) && (temp != nozzle)) { + prev = temp; + temp = temp->next; + } + + if (nozzle == prev) { + lib_cfg.head = nozzle->next; + } else { + prev->next = nozzle->next; + } + + ip = nozzle->ip; + while (ip) { + ip_next = ip->next; + free(ip); + ip = ip_next; + } + + destroy_iface(nozzle); + +out_clean: + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return err; +} + +int nozzle_run_updown(const nozzle_t nozzle, uint8_t action, char **exec_string) +{ + int err = 0, savederrno = 0; + char command[PATH_MAX]; + const char *action_str = NULL; + struct stat sb; + + if (action > NOZZLE_POSTDOWN) { + errno = EINVAL; + return -1; + } + + if (!exec_string) { + errno = EINVAL; + return -1; + } + + savederrno = pthread_mutex_lock(&config_mutex); + if (savederrno) { + errno = savederrno; + return -1; + } + + if (!is_valid_nozzle(nozzle)) { + savederrno = EINVAL; + err = -1; + goto out_clean; + } + + if (!nozzle->hasupdown) { + savederrno = EINVAL; + err = -1; + goto out_clean; + } + + switch(action) { + case NOZZLE_PREUP: + action_str = "pre-up.d"; + break; + case NOZZLE_UP: + action_str = "up.d"; + break; + case NOZZLE_DOWN: + action_str = "down.d"; + break; + case NOZZLE_POSTDOWN: + action_str = "post-down.d"; + break; + } + + memset(command, 0, PATH_MAX); + + snprintf(command, PATH_MAX, "%s/%s/%s", nozzle->updownpath, action_str, nozzle->name); + + err = stat(command, &sb); + if (err) { + savederrno = errno; + goto out_clean; + } + + /* + * clear errno from previous calls as there is no errno + * returned from execute_bin_sh_command + */ + savederrno = 0; + err = execute_bin_sh_command(command, exec_string); + if (err) { + err = -2; + } + +out_clean: + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return err; +} + +int nozzle_set_up(nozzle_t nozzle) +{ + int err = 0, savederrno = 0; + struct ifreq ifr; + + savederrno = pthread_mutex_lock(&config_mutex); + if (savederrno) { + errno = savederrno; + return -1; + } + + if (!is_valid_nozzle(nozzle)) { + savederrno = EINVAL; + err = -1; + goto out_clean; + } + + if (nozzle->up) { + goto out_clean; + } + + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifname, nozzle->name, IFNAMSIZ); + + err = ioctl(lib_cfg.ioctlfd, SIOCGIFFLAGS, &ifr); + if (err) { + savederrno = errno; + goto out_clean; + } + + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + err = ioctl(lib_cfg.ioctlfd, SIOCSIFFLAGS, &ifr); + if (err) { + savederrno = errno; + goto out_clean; + } + + nozzle->up = 1; + +out_clean: + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return err; +} + +int nozzle_set_down(nozzle_t nozzle) +{ + int err = 0, savederrno = 0; + struct ifreq ifr; + + savederrno = pthread_mutex_lock(&config_mutex); + if (savederrno) { + errno = savederrno; + return -1; + } + + if (!is_valid_nozzle(nozzle)) { + savederrno = EINVAL; + err = -1; + goto out_clean; + } + + if (!nozzle->up) { + goto out_clean; + } + + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifname, nozzle->name, IFNAMSIZ); + + err = ioctl(lib_cfg.ioctlfd, SIOCGIFFLAGS, &ifr); + if (err) { + savederrno = errno; + goto out_clean; + } + + ifr.ifr_flags &= ~IFF_UP; + + err = ioctl(lib_cfg.ioctlfd, SIOCSIFFLAGS, &ifr); + if (err) { + savederrno = errno; + goto out_clean; + } + + nozzle->up = 0; + +out_clean: + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return err; +} + +int nozzle_get_mtu(const nozzle_t nozzle) +{ + int err = 0, savederrno = 0; + + savederrno = pthread_mutex_lock(&config_mutex); + if (savederrno) { + errno = savederrno; + return -1; + } + + if (!is_valid_nozzle(nozzle)) { + savederrno = EINVAL; + err = -1; + goto out_clean; + } + + err = get_iface_mtu(nozzle); + savederrno = errno; + +out_clean: + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return err; +} + +int nozzle_get_mac(const nozzle_t nozzle, char **ether_addr) +{ + int err = 0, savederrno = 0; + + if (!ether_addr) { + errno = EINVAL; + return -1; + } + + savederrno = pthread_mutex_lock(&config_mutex); + if (savederrno) { + errno = savederrno; + return -1; + } + + if (!is_valid_nozzle(nozzle)) { + savederrno = EINVAL; + err = -1; + goto out_clean; + } + + err = get_iface_mac(nozzle, ether_addr); + +out_clean: + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return err; +} + +int nozzle_set_mac(nozzle_t nozzle, const char *ether_addr) +{ + int err = 0, savederrno = 0; + struct ifreq ifr; + + if (!ether_addr) { + errno = EINVAL; + return -1; + } + + savederrno = pthread_mutex_lock(&config_mutex); + if (savederrno) { + errno = savederrno; + return -1; + } + + if (!is_valid_nozzle(nozzle)) { + savederrno = EINVAL; + err = -1; + goto out_clean; + } + + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifname, nozzle->name, IFNAMSIZ); +#ifdef KNET_LINUX + err = ioctl(lib_cfg.ioctlfd, SIOCGIFHWADDR, &ifr); + if (err) { + savederrno = errno; + goto out_clean; + } + + memmove(ifr.ifr_hwaddr.sa_data, ether_aton(ether_addr), ETH_ALEN); + + err = ioctl(lib_cfg.ioctlfd, SIOCSIFHWADDR, &ifr); + savederrno = errno; +#endif +#ifdef KNET_BSD + err = ioctl(lib_cfg.ioctlfd, SIOCGIFADDR, &ifr); + if (err) { + savederrno = errno; + goto out_clean; + } + + memmove(ifr.ifr_addr.sa_data, ether_aton(ether_addr), ETHER_ADDR_LEN); + ifr.ifr_addr.sa_len = ETHER_ADDR_LEN; + + err = ioctl(lib_cfg.ioctlfd, SIOCSIFLLADDR, &ifr); + savederrno = errno; +#endif +out_clean: + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return err; +} + +int nozzle_reset_mac(nozzle_t nozzle) +{ + return nozzle_set_mac(nozzle, nozzle->default_mac); +} + +nozzle_t nozzle_get_handle_by_name(const char *devname) +{ + int savederrno = 0; + nozzle_t nozzle; + + if ((devname == NULL) || (strlen(devname) > IFNAMSIZ)) { + errno = EINVAL; + return NULL; + } + + savederrno = pthread_mutex_lock(&config_mutex); + if (savederrno) { + errno = savederrno; + return NULL; + } + + nozzle = lib_cfg.head; + while (nozzle != NULL) { + if (!strcmp(devname, nozzle->name)) + break; + nozzle = nozzle->next; + } + + if (!nozzle) { + savederrno = ENOENT; + } + + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return nozzle; +} + +const char *nozzle_get_name_by_handle(const nozzle_t nozzle) +{ + int savederrno = 0; + char *name = NULL; + + savederrno = pthread_mutex_lock(&config_mutex); + if (savederrno) { + errno = savederrno; + return NULL; + } + + if (!is_valid_nozzle(nozzle)) { + savederrno = ENOENT; + goto out_clean; + } + + name = nozzle->name; + +out_clean: + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return name; +} + +int nozzle_get_fd(const nozzle_t nozzle) +{ + int fd = -1, savederrno = 0; + + savederrno = pthread_mutex_lock(&config_mutex); + if (savederrno) { + errno = savederrno; + return -1; + } + + if (!is_valid_nozzle(nozzle)) { + savederrno = ENOENT; + fd = -1; + goto out_clean; + } + + fd = nozzle->fd; + +out_clean: + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return fd; +} + +int nozzle_set_mtu(nozzle_t nozzle, const int mtu) +{ + int err = 0, savederrno = 0; + struct nozzle_ip *tmp_ip; + struct ifreq ifr; + + if (!mtu) { + errno = EINVAL; + return -1; + } + + savederrno = pthread_mutex_lock(&config_mutex); + if (savederrno) { + errno = savederrno; + return -1; + } + + if (!is_valid_nozzle(nozzle)) { + savederrno = EINVAL; + err = -1; + goto out_clean; + } + + err = nozzle->current_mtu = get_iface_mtu(nozzle); + if (err < 0) { + savederrno = errno; + goto out_clean; + } + + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifname, nozzle->name, IFNAMSIZ); + ifr.ifr_mtu = mtu; + + err = ioctl(lib_cfg.ioctlfd, SIOCSIFMTU, &ifr); + if (err) { + savederrno = errno; + goto out_clean; + } + + if ((nozzle->current_mtu < 1280) && (mtu >= 1280)) { + tmp_ip = nozzle->ip; + while(tmp_ip) { + if (tmp_ip->domain == AF_INET6) { + err = _set_ip(nozzle, IP_ADD, tmp_ip->ipaddr, tmp_ip->prefix, 0); + if (err) { + savederrno = errno; + err = -1; + goto out_clean; + } + } + tmp_ip = tmp_ip->next; + } + } + +out_clean: + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return err; +} + +int nozzle_reset_mtu(nozzle_t nozzle) +{ + return nozzle_set_mtu(nozzle, nozzle->default_mtu); +} + +int nozzle_add_ip(nozzle_t nozzle, const char *ipaddr, const char *prefix) +{ + int err = 0, savederrno = 0; + int found = 0; + struct nozzle_ip *ip = NULL, *ip_prev = NULL, *ip_last = NULL; + int secondary = 0; + + if ((!ipaddr) || (!prefix)) { + errno = EINVAL; + return -1; + } + + savederrno = pthread_mutex_lock(&config_mutex); + if (savederrno) { + errno = savederrno; + return -1; + } + + if (!is_valid_nozzle(nozzle)) { + savederrno = EINVAL; + err = -1; + goto out_clean; + } + + found = find_ip(nozzle, ipaddr, prefix, &ip, &ip_prev); + if (found) { + goto out_clean; + } + + ip = malloc(sizeof(struct nozzle_ip)); + if (!ip) { + savederrno = errno; + err = -1 ; + goto out_clean; + } + + memset(ip, 0, sizeof(struct nozzle_ip)); + strncpy(ip->ipaddr, ipaddr, IPADDR_CHAR_MAX); + strncpy(ip->prefix, prefix, PREFIX_CHAR_MAX); + if (!strchr(ip->ipaddr, ':')) { + ip->domain = AF_INET; + } else { + ip->domain = AF_INET6; + } + + /* + * if user asks for an IPv6 address, but MTU < 1280 + * store the IP and bring it up later if and when MTU > 1280 + */ + if ((ip->domain == AF_INET6) && (get_iface_mtu(nozzle) < 1280)) { + err = 0; + } else { + if (nozzle->ip) { + secondary = 1; + } + err = _set_ip(nozzle, IP_ADD, ipaddr, prefix, secondary); + savederrno = errno; + } + + if (err) { + free(ip); + goto out_clean; + } + + if (nozzle->ip) { + ip_last = nozzle->ip; + while (ip_last->next != NULL) { + ip_last = ip_last->next; + } + ip_last->next = ip; + } else { + nozzle->ip = ip; + } + +out_clean: + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return err; +} + +int nozzle_del_ip(nozzle_t nozzle, const char *ipaddr, const char *prefix) +{ + int err = 0, savederrno = 0; + int found = 0; + struct nozzle_ip *ip = NULL, *ip_prev = NULL; + + if ((!ipaddr) || (!prefix)) { + errno = EINVAL; + return -1; + } + + savederrno = pthread_mutex_lock(&config_mutex); + if (savederrno) { + errno = savederrno; + return -1; + } + + if (!is_valid_nozzle(nozzle)) { + savederrno = EINVAL; + err = -1; + goto out_clean; + } + + found = find_ip(nozzle, ipaddr, prefix, &ip, &ip_prev); + if (!found) { + goto out_clean; + } + + /* + * if user asks for an IPv6 address, but MTU < 1280 + * the IP might not be configured on the interface and we only need to + * remove it from our internal database + */ + if ((ip->domain == AF_INET6) && (get_iface_mtu(nozzle) < 1280)) { + err = 0; + } else { + err = _set_ip(nozzle, IP_DEL, ipaddr, prefix, 0); + savederrno = errno; + } + + if (!err) { + if (ip == ip_prev) { + nozzle->ip = ip->next; + } else { + ip_prev->next = ip->next; + } + free(ip); + } + +out_clean: + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return err; +} + +int nozzle_get_ips(const nozzle_t nozzle, struct nozzle_ip **nozzle_ip) +{ + int err = 0, savederrno = 0; + + if (!nozzle_ip) { + errno = EINVAL; + return -1; + } + + savederrno = pthread_mutex_lock(&config_mutex); + if (savederrno) { + errno = savederrno; + return -1; + } + + if (!is_valid_nozzle(nozzle)) { + err = -1; + savederrno = EINVAL; + goto out_clean; + } + + *nozzle_ip = nozzle->ip; + +out_clean: + pthread_mutex_unlock(&config_mutex); + errno = savederrno; + return err; +} diff --git a/libnozzle/libnozzle.h b/libnozzle/libnozzle.h new file mode 100644 index 00000000..6baf09ee --- /dev/null +++ b/libnozzle/libnozzle.h @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#ifndef __LIBNOZZLE_H__ +#define __LIBNOZZLE_H__ + +#include +#include + +/** + * + * @file libnozzle.h + * @brief tap interfaces management API include file + * @copyright Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. + * + * nozzle is a commodity library to manage tap (ethernet) interfaces + */ + +typedef struct nozzle_iface *nozzle_t; + +/** + * nozzle_open + * @brief create a new tap device on the system. + * + * devname - pointer to device name of at least size IFNAMSIZ. + * if the dev strlen is 0, then the system will assign a name automatically. + * if a string is specified, the system will try to create a device with + * the specified name. + * NOTE: on FreeBSD the tap device names can only be tapX where X is a + * number from 0 to 255. On Linux such limitation does not apply. + * The name must be unique to the system. If an interface with the same + * name is already configured on the system, an error will be returned. + * + * devname_size - length of the buffer provided in dev (has to be at least IFNAMSIZ). + * + * updownpath - nozzle supports the typical filesystem structure to execute + * actions for: down.d post-down.d pre-up.d up.d + * in the form of: + * updownpath// + * updownpath specifies where to find those directories on the + * filesystem and it must be an absolute path. + * + * @return + * nozzle_open returns + * a pointer to a nozzle struct on success + * NULL on error and errno is set. + */ + +nozzle_t nozzle_open(char *devname, size_t devname_size, const char *updownpath); + +/** + * nozzle_close + * @brief deconfigure and destroy a nozzle device + * + * nozzle - pointer to the nozzle struct to destroy + * + * @return + * 0 on success + * -1 on error and errno is set. + */ + +int nozzle_close(nozzle_t nozzle); + + +#define NOZZLE_PREUP 0 +#define NOZZLE_UP 1 +#define NOZZLE_DOWN 2 +#define NOZZLE_POSTDOWN 3 + +/** + * nozzle_run_updown + * @brief execute updown commands associated with a nozzle device. It is + * the application responsibility to call helper scripts + * before or after creating/destroying interfaces or IP addresses. + * + * nozzle - pointer to the nozzle struct + * + * action - pre-up.d / up.d / down.d / post-down.d (see defines above) + * + * exec_string - pointers to string to record executing action stdout/stderr. + * The string is malloc'ed, the caller needs to free the buffer. + * If the script generates no output this string might be NULL. + * + * @return + * 0 on success + * -1 on error and errno is set (sanity checks and internal calls. + * -2 on error from executing the shell scripts, and no errno is set. + */ + +int nozzle_run_updown(const nozzle_t nozzle, uint8_t action, char **exec_string); + +/** + * nozzle_set_up + * @brief equivalent of ifconfig up + * + * nozzle - pointer to the nozzle struct + * + * @return + * 0 on success + * -1 on error and errno is set. + */ + +int nozzle_set_up(nozzle_t nozzle); + +/** + * nozzle_set_down + * @brief equivalent of ifconfig down + * + * nozzle - pointer to the nozzle struct + * + * @return + * 0 on success + * -1 on error and errno is set. + */ + +int nozzle_set_down(nozzle_t nozzle); + +/** + * nozzle_add_ip + * @brief equivalent of ip addr or ifconfig + * + * nozzle - pointer to the nozzle struct + * + * ipaddr - string containing either an IPv4 or an IPv6 address. + * Please note that Linux will automatically remove any IPv6 addresses from an interface + * with MTU < 1280. libnozzle will cache those IPs and re-instate them when MTU is > 1280. + * MTU must be set via nozzle_set_mtu for IPv6 to be re-instated. + * + * prefix - 24, 64 or any valid network prefix for the requested address. + * + * @return + * 0 on success + * -1 on error and errno is set. + */ + +int nozzle_add_ip(nozzle_t nozzle, const char *ipaddr, const char *prefix); + +/** + * nozzle_del_ip + * @brief equivalent of ip addr del or ifconfig del + * + * nozzle - pointer to the nozzle struct + * + * ipaddr - string containing either an IPv4 or an IPv6 address. + * + * prefix - 24, 64 or any valid network prefix for the requested address. + * + * @return + * 0 on success + * -1 on error and errno is set. + */ + +int nozzle_del_ip(nozzle_t nozzle, const char *ipaddr, const char *prefix); + + +#define IPADDR_CHAR_MAX 128 +#define PREFIX_CHAR_MAX 4 + +struct nozzle_ip { + char ipaddr[IPADDR_CHAR_MAX + 1]; + char prefix[PREFIX_CHAR_MAX + 1]; + int domain; /* AF_INET or AF_INET6 */ + struct nozzle_ip *next; +}; + +/** + * nozzle_get_ips + * @brief retrive the list of all configured ips for a given interface + * + * nozzle - pointer to the nozzle struct + * + * nozzle_ip - pointer to the head of a list of nozzle_ip structs. + * The last IP will have next = NULL. + * nozzle_ip can be NULL if there are no IP addresses + * associated with this nozzle device. + * *DO NOT* free those structs as they are used internally + * for IP address tracking. + * + * @return + * 0 on success + * -1 on error and errno is set. + * + */ + +int nozzle_get_ips(const nozzle_t nozzle, struct nozzle_ip **nozzle_ip); + +/** + * nozzle_get_mtu + * @brief retrive mtu on a given nozzle interface + * + * nozzle - pointer to the nozzle struct + * + * @return + * MTU on success + * -1 on error and errno is set. + */ + +int nozzle_get_mtu(const nozzle_t nozzle); + +/** + * nozzle_set_mtu + * @brief set mtu on a given nozzle interface + * + * nozzle - pointer to the nozzle struct + * + * mtu - new MTU value + * + * @return + * 0 on success + * -1 on error and errno is set. + */ + +int nozzle_set_mtu(nozzle_t nozzle, const int mtu); + +/** + * nozzle_reset_mtu + * @brief reset mtu on a given nozzle interface to the system default + * + * nozzle - pointer to the nozzle struct + * + * @return + * 0 on success + * -1 on error and errno is set. + */ + +int nozzle_reset_mtu(nozzle_t nozzle); + +/** + * nozzle_get_mac + * @brief retrive mac address on a given nozzle interface + * + * nozzle - pointer to the nozzle struct + * + * ether_addr - pointers to string containing the current mac address. + * The string is malloc'ed, the caller needs to free this buffer. + * @return + * 0 on success. + * -1 on error and errno is set. + */ + +int nozzle_get_mac(const nozzle_t nozzle, char **ether_addr); + +/** + * nozzle_set_mac + * @brief set mac address on a given nozzle interface + * + * nozzle - pointer to the nozzle struct + * + * ether_addr - pointers to string containing the new mac address. + * + * @return + * 0 on success. + * -1 on error and errno is set. + */ + +int nozzle_set_mac(nozzle_t nozzle, const char *ether_addr); + +/** + * nozzle_reset_mac + * @brief reset mac address on a given nozzle interface to system default + * + * nozzle - pointer to the nozzle struct + * + * @return + * 0 on success. + * -1 on error and errno is set. + */ + +int nozzle_reset_mac(nozzle_t nozzle); + +/** + * nozzle_get_handle_by_name + * @brief find a nozzle handle by device name + * + * devname - string containing the name of the interface + * + * @return + * handle on success. + * NULL on error and errno is set. + */ + +nozzle_t nozzle_get_handle_by_name(const char *devname); + +/** + * nozzle_get_name_by_handle + * @brief retrive nozzle interface name by handle + * + * nozzle - pointer to the nozzle struct + * + * @return + * pointer to the interface name + * NULL on error and errno is set. + */ + +const char *nozzle_get_name_by_handle(const nozzle_t nozzle); + +/** + * nozzle_get_fd + * @brief + * + * nozzle - pointer to the nozzle struct + * + * @return + * fd associated to a given nozzle on success. + * -1 on error and errno is set. + */ + +int nozzle_get_fd(const nozzle_t nozzle); + +#endif diff --git a/libtap/libtap.pc.in b/libnozzle/libnozzle.pc.in similarity index 89% rename from libtap/libtap.pc.in rename to libnozzle/libnozzle.pc.in index 97340fc5..901e3af5 100644 --- a/libtap/libtap.pc.in +++ b/libnozzle/libnozzle.pc.in @@ -1,19 +1,19 @@ # # Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto # # This software licensed under GPL-2.0+, LGPL-2.0+ # prefix=@prefix@ exec_prefix=${prefix} libdir=@libdir@ includedir=${prefix}/include -Name: libtap +Name: libnozzle Version: @VERSION@ Description: library to manage a pool of tap devices Requires: -Libs: -L${libdir} -ltap +Libs: -L${libdir} -lnozzle Cflags: -I${includedir} diff --git a/libtap/libtap_exported_syms b/libnozzle/libnozzle_exported_syms similarity index 74% rename from libtap/libtap_exported_syms rename to libnozzle/libnozzle_exported_syms index cfb3502b..6745c9ba 100644 --- a/libtap/libtap_exported_syms +++ b/libnozzle/libnozzle_exported_syms @@ -1,15 +1,15 @@ -# Version and symbol export for libtap.so +# Version and symbol export for libnozzle.so # # Copyright (C) 2011-2018 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto # # This software licensed under GPL-2.0+, LGPL-2.0+ # -LIBTAP { +LIBNOZZLE { global: - tap_*; + nozzle_*; local: *; }; diff --git a/libnozzle/tests/Makefile.am b/libnozzle/tests/Makefile.am new file mode 100644 index 00000000..9a732d52 --- /dev/null +++ b/libnozzle/tests/Makefile.am @@ -0,0 +1,125 @@ +# +# Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. +# +# Author: Fabio M. Di Nitto +# +# This software licensed under GPL-2.0+, LGPL-2.0+ +# + +MAINTAINERCLEANFILES = Makefile.in + +include $(top_srcdir)/build-aux/check.mk + +EXTRA_DIST = \ + nozzle_run_updown_exit_true \ + nozzle_run_updown_exit_false \ + api-test-coverage + +noinst_HEADERS = \ + test-common.h + +if BUILD_LIBNOZZLE + +api_checks = \ + api_nozzle_open_test \ + api_nozzle_close_test \ + api_nozzle_set_up_test \ + api_nozzle_set_down_test \ + api_nozzle_get_mtu_test \ + api_nozzle_set_mtu_test \ + api_nozzle_get_mac_test \ + api_nozzle_set_mac_test \ + api_nozzle_get_handle_by_name_test \ + api_nozzle_get_name_by_handle_test \ + api_nozzle_get_fd_test \ + api_nozzle_run_updown_test \ + api_nozzle_add_ip_test \ + api_nozzle_del_ip_test \ + api_nozzle_get_ips_test + +int_checks = \ + int_execute_bin_sh_command_test + +fun_checks = + +benchmarks = + +check_PROGRAMS = \ + $(api_checks) \ + $(int_checks) \ + $(fun_checks) + +noinst_PROGRAMS = \ + $(benchmarks) \ + $(check_PROGRAMS) + +noinst_SCRIPTS = \ + api-test-coverage + +TESTS = $(check_PROGRAMS) + +check-local: check-api-test-coverage + +check-api-test-coverage: + chmod u+x $(top_srcdir)/libnozzle/tests/api-test-coverage + $(top_srcdir)/libnozzle/tests/api-test-coverage $(top_srcdir) $(top_builddir) + +AM_CPPFLAGS = -I$(top_srcdir)/libnozzle -DABSBUILDDIR=\"$(abs_builddir)\" -DABSSRCDIR=\"$(abs_srcdir)\" +AM_CFLAGS += $(PTHREAD_CFLAGS) $(libnl_CFLAGS) +LIBS += $(top_builddir)/libnozzle/libnozzle.la $(PTHREAD_LIBS) $(libnl_LIBS) + +api_nozzle_open_test_SOURCES = api_nozzle_open.c \ + test-common.c + +api_nozzle_close_test_SOURCES = api_nozzle_close.c \ + test-common.c + +api_nozzle_set_up_test_SOURCES = api_nozzle_set_up.c \ + test-common.c \ + ../internals.c + +api_nozzle_set_down_test_SOURCES = api_nozzle_set_down.c \ + test-common.c \ + ../internals.c + +api_nozzle_get_mtu_test_SOURCES = api_nozzle_get_mtu.c \ + test-common.c + +api_nozzle_set_mtu_test_SOURCES = api_nozzle_set_mtu.c \ + test-common.c \ + ../internals.c + +api_nozzle_get_mac_test_SOURCES = api_nozzle_get_mac.c \ + test-common.c + +api_nozzle_set_mac_test_SOURCES = api_nozzle_set_mac.c \ + test-common.c + +api_nozzle_get_handle_by_name_test_SOURCES = api_nozzle_get_handle_by_name.c \ + test-common.c + +api_nozzle_get_name_by_handle_test_SOURCES = api_nozzle_get_name_by_handle.c \ + test-common.c + +api_nozzle_get_fd_test_SOURCES = api_nozzle_get_fd.c \ + test-common.c + +api_nozzle_run_updown_test_SOURCES = api_nozzle_run_updown.c \ + test-common.c \ + ../internals.c + +api_nozzle_add_ip_test_SOURCES = api_nozzle_add_ip.c \ + test-common.c \ + ../internals.c + +api_nozzle_del_ip_test_SOURCES = api_nozzle_del_ip.c \ + test-common.c \ + ../internals.c + +api_nozzle_get_ips_test_SOURCES = api_nozzle_get_ips.c \ + test-common.c + +int_execute_bin_sh_command_test_SOURCES = int_execute_bin_sh_command.c \ + test-common.c \ + ../internals.c +endif diff --git a/libnozzle/tests/api-test-coverage b/libnozzle/tests/api-test-coverage new file mode 100755 index 00000000..eb7b5efe --- /dev/null +++ b/libnozzle/tests/api-test-coverage @@ -0,0 +1,93 @@ +#!/bin/sh +# +# Copyright (C) 2016-2018 Red Hat, Inc. All rights reserved. +# +# Author: Fabio M. Di Nitto +# +# This software licensed under GPL-2.0+, LGPL-2.0+ +# + +srcdir="$1"/libnozzle/tests +builddir="$2"/libnozzle/tests + +headerapicalls="$(grep nozzle_ "$srcdir"/../libnozzle.h | grep -v "^ \*" | grep -v ^struct | grep -v "^[[:space:]]" | grep -v typedef | sed -e 's/(.*//g' -e 's/^const //g' -e 's/\*//g' | awk '{print $2}')" + +# The PowerPC64 ELFv1 ABI defines the address of a function as that of a +# function descriptor defined in .opd, a data (D) section. Other ABIs +# use the entry address of the function itself in the text (T) section. +exportedapicalls="$(nm -B -D "$builddir"/../.libs/libnozzle.so | grep ' [DT] ' | awk '{print $3}')" + +echo "Checking for exported symbols NOT available in header file" + +for i in $exportedapicalls; do + found=0 + for x in $headerapicalls; do + if [ "$x" = "$i" ]; then + found=1 + break; + fi + done + if [ "$found" = 0 ]; then + echo "Symbol $i not found in header file" + exit 1 + fi +done + +echo "Checking for symbols in header file NOT exported by binary lib" + +for i in $headerapicalls; do + found=0 + for x in $exportedapicalls; do + if [ "$x" = "$i" ]; then + found=1 + break; + fi + done + if [ "$found" = 0 ]; then + echo "Symbol $i not found in binary lib" + exit 1 + fi +done + +echo "Checking for tests with memcheck exceptions" + +for i in $(grep -l is_memcheck "$srcdir"/*.c | grep -v test-common); do + echo "WARNING: $(basename $i) - has memcheck exception enabled" +done + +echo "Checking for tests with helgrind exceptions" + +for i in $(grep -l is_helgrind "$srcdir"/*.c | grep -v test-common); do + echo "WARNING: $(basename $i) has helgrind exception enabled" +done + +echo "Checking for api test coverage" + +numapicalls=0 +found=0 +missing=0 + +for i in $headerapicalls; do + [ "$i" = nozzle_reset_mtu ] && i=nozzle_set_mtu # tested together + [ "$i" = nozzle_reset_mac ] && i=nozzle_set_mac # tested together + numapicalls=$((numapicalls + 1)) + if [ -f $srcdir/api_${i}.c ]; then + found=$((found + 1)) + else + missing=$((missing + 1)) + echo "MISSING: $i" + fi +done + +echo "Summary" +echo "-------" +echo "Found : $found" +echo "Missing : $missing" +echo "Total : $numapicalls" +which bc > /dev/null 2>&1 && { + coverage=$(echo "scale=3; $found / $numapicalls * 100" | bc -l) + echo "Coverage: $coverage%" +} +exit 0 + +exit 0 diff --git a/libnozzle/tests/api_nozzle_add_ip.c b/libnozzle/tests/api_nozzle_add_ip.c new file mode 100644 index 00000000..af8c5f03 --- /dev/null +++ b/libnozzle/tests/api_nozzle_add_ip.c @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test-common.h" + +char testipv4_1[IPBUFSIZE]; +char testipv4_2[IPBUFSIZE]; +char testipv6_1[IPBUFSIZE]; +char testipv6_2[IPBUFSIZE]; + +static int test(void) +{ + char device_name[IFNAMSIZ]; + size_t size = IFNAMSIZ; + char verifycmd[2048]; + int err = 0; + nozzle_t nozzle; + char *error_string = NULL; + + printf("Testing interface add ip\n"); + + memset(device_name, 0, size); + + nozzle = nozzle_open(device_name, size, NULL); + if (!nozzle) { + printf("Unable to init %s\n", device_name); + return -1; + } + + printf("Testing error conditions\n"); + + printf("Testing invalid nozzle handle\n"); + err = nozzle_add_ip(NULL, testipv4_1, "24"); + if ((!err) || (errno != EINVAL)) { + printf("nozzle_add_ip accepted invalid nozzle handle\n"); + err = -1; + goto out_clean; + } + + printf("Testing empty ip address\n"); + err = nozzle_add_ip(nozzle, NULL, "24"); + if ((!err) || (errno != EINVAL)) { + printf("nozzle_add_ip accepted invalid ip address\n"); + err = -1; + goto out_clean; + } + + + printf("Testing empty netmask\n"); + err = nozzle_add_ip(nozzle, testipv4_1, NULL); + if ((!err) || (errno != EINVAL)) { + printf("nozzle_add_ip accepted invalid netmask\n"); + err = -1; + goto out_clean; + } + + printf("Adding ip: %s/24\n", testipv4_1); + + err = nozzle_add_ip(nozzle, testipv4_1, "24"); + if (err < 0) { + printf("Unable to assign IP address\n"); + err = -1; + goto out_clean; + } + + printf("Adding ip: %s/24\n", testipv4_2); + + err = nozzle_add_ip(nozzle, testipv4_2, "24"); + if (err < 0) { + printf("Unable to assign IP address\n"); + err = -1; + goto out_clean; + } + + printf("Adding duplicate ip: %s/24\n", testipv4_1); + + err = nozzle_add_ip(nozzle, testipv4_1, "24"); + if (err < 0) { + printf("Unable to find IP address in libnozzle db\n"); + err = -1; + goto out_clean; + } + + printf("Checking ip: %s/24\n", testipv4_1); + + memset(verifycmd, 0, sizeof(verifycmd)); + snprintf(verifycmd, sizeof(verifycmd)-1, +#ifdef KNET_LINUX + "ip addr show dev %s | grep -q %s/24", nozzle->name, testipv4_1); +#endif +#ifdef KNET_BSD + "ifconfig %s | grep -q %s", nozzle->name, testipv4_1); +#endif + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (err) { + printf("Unable to verify IP address\n"); + err = -1; + goto out_clean; + } + + printf("Checking ip: %s/24\n", testipv4_2); + + memset(verifycmd, 0, sizeof(verifycmd)); + snprintf(verifycmd, sizeof(verifycmd)-1, +#ifdef KNET_LINUX + "ip addr show dev %s | grep -q %s/24", nozzle->name, testipv4_2); +#endif +#ifdef KNET_BSD + "ifconfig %s | grep -q %s", nozzle->name, testipv4_2); +#endif + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (err) { + printf("Unable to verify IP address\n"); + err = -1; + goto out_clean; + } + + printf("Deleting ip: %s/24\n", testipv4_1); + + err = nozzle_del_ip(nozzle, testipv4_1, "24"); + if (err < 0) { + printf("Unable to delete IP address\n"); + err = -1; + goto out_clean; + } + + printf("Deleting ip: %s/24\n", testipv4_2); + + err = nozzle_del_ip(nozzle, testipv4_2, "24"); + if (err < 0) { + printf("Unable to delete IP address\n"); + err = -1; + goto out_clean; + } + + printf("Adding ip: %s/64\n", testipv6_1); + + err = nozzle_add_ip(nozzle, testipv6_1, "64"); + if (err < 0) { + printf("Unable to assign IP address\n"); + err = -1; + goto out_clean; + } + + memset(verifycmd, 0, sizeof(verifycmd)); + snprintf(verifycmd, sizeof(verifycmd)-1, +#ifdef KNET_LINUX + "ip addr show dev %s | grep -q %s/64", nozzle->name, testipv6_1); +#endif +#ifdef KNET_BSD + "ifconfig %s | grep -q %s", nozzle->name, testipv6_1); +#endif + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (err) { + printf("Unable to verify IP address\n"); + err = -1; + goto out_clean; + } + + printf("Deleting ip: %s/64\n", testipv6_1); + + err = nozzle_del_ip(nozzle, testipv6_1, "64"); + if (err) { + printf("Unable to delete IP address\n"); + err = -1; + goto out_clean; + } + + printf("Testing adding an IPv6 address with mtu < 1280 and restore\n"); + printf("Lowering interface MTU\n"); + + err = nozzle_set_mtu(nozzle, 1200); + if (err) { + printf("Unable to set MTU to 1200\n"); + err = -1; + goto out_clean; + } + + printf("Adding ip: %s/64\n", testipv6_1); + + err = nozzle_add_ip(nozzle, testipv6_1, "64"); + if (err < 0) { + printf("Unable to assign IP address\n"); + err = -1; + goto out_clean; + } + + memset(verifycmd, 0, sizeof(verifycmd)); + snprintf(verifycmd, sizeof(verifycmd)-1, +#ifdef KNET_LINUX + "ip addr show dev %s | grep -q %s/64", nozzle->name, testipv6_1); +#endif +#ifdef KNET_BSD + "ifconfig %s | grep -q %s", nozzle->name, testipv6_1); +#endif + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (!err) { + printf("Unable to verify IP address\n"); + err = -1; + goto out_clean; + } + + printf("Resetting MTU\n"); + + err = nozzle_reset_mtu(nozzle); + if (err) { + printf("Unable to set reset MTU\n"); + err = -1; + goto out_clean; + } + + memset(verifycmd, 0, sizeof(verifycmd)); + snprintf(verifycmd, sizeof(verifycmd)-1, +#ifdef KNET_LINUX + "ip addr show dev %s | grep -q %s/64", nozzle->name, testipv6_1); +#endif +#ifdef KNET_BSD + "ifconfig %s | grep -q %s", nozzle->name, testipv6_1); +#endif + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (err) { + printf("Unable to verify IP address\n"); + err = -1; + goto out_clean; + } + + printf("Deleting ip: %s/64\n", testipv6_1); + + err = nozzle_del_ip(nozzle, testipv6_1, "64"); + if (err) { + printf("Unable to delete IP address\n"); + err = -1; + goto out_clean; + } + +out_clean: + nozzle_close(nozzle); + + return err; +} + +int main(void) +{ + need_root(); + + make_local_ips(testipv4_1, testipv4_2, testipv6_1, testipv6_2); + + if (test() < 0) + return FAIL; + + return PASS; +} diff --git a/libnozzle/tests/api_nozzle_close.c b/libnozzle/tests/api_nozzle_close.c new file mode 100644 index 00000000..129b98c7 --- /dev/null +++ b/libnozzle/tests/api_nozzle_close.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef KNET_LINUX +#include +#include +#endif +#ifdef KNET_BSD +#include +#endif + +#include "test-common.h" + +char testipv4_1[IPBUFSIZE]; +char testipv4_2[IPBUFSIZE]; +char testipv6_1[IPBUFSIZE]; +char testipv6_2[IPBUFSIZE]; + +static int test(void) +{ + char device_name[2*IFNAMSIZ]; + size_t size = IFNAMSIZ; + nozzle_t nozzle; + + memset(device_name, 0, sizeof(device_name)); + + /* + * this test is duplicated from api_nozzle_open.c + */ + printf("Testing random nozzle interface:\n"); + if (test_iface(device_name, size, NULL) < 0) { + printf("Unable to create random interface\n"); + return -1; + } + + printf("Testing ERROR conditions\n"); + + printf("Testing nozzle_close with NULL nozzle\n"); + if ((nozzle_close(NULL) >= 0) || (errno != EINVAL)) { + printf("Something is wrong in nozzle_close sanity checks\n"); + return -1; + } + + printf("Testing nozzle_close with random bytes nozzle pointer\n"); + + nozzle = (nozzle_t)0x1; + + if ((nozzle_close(nozzle) >= 0) || (errno != EINVAL)) { + printf("Something is wrong in nozzle_close sanity checks\n"); + return -1; + } + + return 0; +} + +/* + * requires running the test suite with valgrind + */ +static int check_nozzle_close_leak(void) +{ + char device_name[IFNAMSIZ]; + size_t size = IFNAMSIZ; + int err=0; + nozzle_t nozzle; + + printf("Testing close leak (needs valgrind)\n"); + + memset(device_name, 0, size); + + nozzle = nozzle_open(device_name, size, NULL); + if (!nozzle) { + printf("Unable to init %s\n", device_name); + return -1; + } + + printf("Adding ip: %s/24\n", testipv4_1); + + err = nozzle_add_ip(nozzle, testipv4_1, "24"); + if (err < 0) { + printf("Unable to assign IP address\n"); + err=-1; + goto out_clean; + } + + printf("Adding ip: %s/24\n", testipv4_2); + + err = nozzle_add_ip(nozzle, testipv4_2, "24"); + if (err < 0) { + printf("Unable to assign IP address\n"); + err=-1; + goto out_clean; + } + +out_clean: + nozzle_close(nozzle); + + return err; +} + +int main(void) +{ + need_root(); + + make_local_ips(testipv4_1, testipv4_2, testipv6_1, testipv6_2); + + if (test() < 0) + return FAIL; + + if (check_nozzle_close_leak() < 0) + return FAIL; + + return 0; +} diff --git a/libnozzle/tests/api_nozzle_del_ip.c b/libnozzle/tests/api_nozzle_del_ip.c new file mode 100644 index 00000000..31e26c22 --- /dev/null +++ b/libnozzle/tests/api_nozzle_del_ip.c @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test-common.h" + +char testipv4_1[IPBUFSIZE]; +char testipv4_2[IPBUFSIZE]; +char testipv6_1[IPBUFSIZE]; +char testipv6_2[IPBUFSIZE]; + +static int test(void) +{ + char device_name[IFNAMSIZ]; + size_t size = IFNAMSIZ; + char verifycmd[2048]; + int err = 0; + nozzle_t nozzle; + char *error_string = NULL; + + printf("Testing interface del ip\n"); + + memset(device_name, 0, size); + + nozzle = nozzle_open(device_name, size, NULL); + if (!nozzle) { + printf("Unable to init %s\n", device_name); + return -1; + } + + printf("Testing error conditions\n"); + + printf("Testing invalid nozzle handle\n"); + err = nozzle_del_ip(NULL, testipv4_1, "24"); + if ((!err) || (errno != EINVAL)) { + printf("nozzle_del_ip accepted invalid nozzle handle\n"); + err = -1; + goto out_clean; + } + + printf("Testing empty ip address\n"); + err = nozzle_del_ip(nozzle, NULL, "24"); + if ((!err) || (errno != EINVAL)) { + printf("nozzle_del_ip accepted invalid ip address\n"); + err = -1; + goto out_clean; + } + + + printf("Testing empty netmask\n"); + err = nozzle_del_ip(nozzle, testipv4_1, NULL); + if ((!err) || (errno != EINVAL)) { + printf("nozzle_del_ip accepted invalid netmask\n"); + err = -1; + goto out_clean; + } + + printf("Adding ip: %s/24\n", testipv4_1); + + err = nozzle_add_ip(nozzle, testipv4_1, "24"); + if (err < 0) { + printf("Unable to assign IP address\n"); + err = -1; + goto out_clean; + } + + printf("Checking ip: %s/24\n", testipv4_1); + + memset(verifycmd, 0, sizeof(verifycmd)); + snprintf(verifycmd, sizeof(verifycmd)-1, +#ifdef KNET_LINUX + "ip addr show dev %s | grep -q %s/24", nozzle->name, testipv4_1); +#endif +#ifdef KNET_BSD + "ifconfig %s | grep -q %s", nozzle->name, testipv4_1); +#endif + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (err) { + printf("Unable to verify IP address\n"); + err = -1; + goto out_clean; + } + + printf("Deleting ip: %s/24\n", testipv4_1); + + err = nozzle_del_ip(nozzle, testipv4_1, "24"); + if (err < 0) { + printf("Unable to delete IP address\n"); + err = -1; + goto out_clean; + } + + printf("Checking ip: %s/24\n", testipv4_1); + + memset(verifycmd, 0, sizeof(verifycmd)); + snprintf(verifycmd, sizeof(verifycmd)-1, +#ifdef KNET_LINUX + "ip addr show dev %s | grep -q %s/24", nozzle->name, testipv4_1); +#endif +#ifdef KNET_BSD + "ifconfig %s | grep -q %s", nozzle->name, testipv4_1); +#endif + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (!err) { + printf("Unable to verify IP address\n"); + err = -1; + goto out_clean; + } + + printf("Deleting ip: %s/24 again\n", testipv4_1); + + err = nozzle_del_ip(nozzle, testipv4_1, "24"); + if (err < 0) { + printf("Unable to delete IP address\n"); + err = -1; + goto out_clean; + } + + printf("Adding ip: %s/64\n", testipv6_1); + + err = nozzle_add_ip(nozzle, testipv6_1, "64"); + if (err < 0) { + printf("Unable to assign IP address\n"); + err = -1; + goto out_clean; + } + + memset(verifycmd, 0, sizeof(verifycmd)); + snprintf(verifycmd, sizeof(verifycmd)-1, +#ifdef KNET_LINUX + "ip addr show dev %s | grep -q %s/64", nozzle->name, testipv6_1); +#endif +#ifdef KNET_BSD + "ifconfig %s | grep -q %s", nozzle->name, testipv6_1); +#endif + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (err) { + printf("Unable to verify IP address\n"); + err = -1; + goto out_clean; + } + + printf("Deleting ip: %s/64\n", testipv6_1); + + err = nozzle_del_ip(nozzle, testipv6_1, "64"); + if (err) { + printf("Unable to delete IP address\n"); + err = -1; + goto out_clean; + } + + memset(verifycmd, 0, sizeof(verifycmd)); + snprintf(verifycmd, sizeof(verifycmd)-1, +#ifdef KNET_LINUX + "ip addr show dev %s | grep -q %s/64", nozzle->name, testipv6_1); +#endif +#ifdef KNET_BSD + "ifconfig %s | grep -q %s", nozzle->name, testipv6_1); +#endif + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (!err) { + printf("Unable to verify IP address\n"); + err = -1; + goto out_clean; + } + + printf("Testing deleting an IPv6 address with mtu < 1280 (in db, not on interface)\n"); + printf("Lowering interface MTU\n"); + + err = nozzle_set_mtu(nozzle, 1200); + if (err) { + printf("Unable to set MTU to 1200\n"); + err = -1; + goto out_clean; + } + + printf("Adding ip: %s/64\n", testipv6_1); + + err = nozzle_add_ip(nozzle, testipv6_1, "64"); + if (err < 0) { + printf("Unable to assign IP address\n"); + err = -1; + goto out_clean; + } + + memset(verifycmd, 0, sizeof(verifycmd)); + snprintf(verifycmd, sizeof(verifycmd)-1, +#ifdef KNET_LINUX + "ip addr show dev %s | grep -q %s/64", nozzle->name, testipv6_1); +#endif +#ifdef KNET_BSD + "ifconfig %s | grep -q %s", nozzle->name, testipv6_1); +#endif + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (!err) { + printf("Unable to verify IP address\n"); + err = -1; + goto out_clean; + } + + printf("Deleting ip: %s/64 with low mtu\n", testipv6_1); + + err = nozzle_del_ip(nozzle, testipv6_1, "64"); + if (err) { + printf("Unable to delete IP address\n"); + err = -1; + goto out_clean; + } + +out_clean: + nozzle_close(nozzle); + + return err; +} + +int main(void) +{ + need_root(); + + make_local_ips(testipv4_1, testipv4_2, testipv6_1, testipv6_2); + + if (test() < 0) + return FAIL; + + return PASS; +} diff --git a/libnozzle/tests/api_nozzle_get_fd.c b/libnozzle/tests/api_nozzle_get_fd.c new file mode 100644 index 00000000..d32da6aa --- /dev/null +++ b/libnozzle/tests/api_nozzle_get_fd.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test-common.h" + +static int test(void) +{ + char device_name[IFNAMSIZ]; + size_t size = IFNAMSIZ; + int err=0; + nozzle_t nozzle; + int fd; + + printf("Testing get fd\n"); + + memset(device_name, 0, size); + nozzle = nozzle_open(device_name, size, NULL); + if (!nozzle) { + printf("Unable to init %s\n", device_name); + return -1; + } + + fd = nozzle_get_fd(nozzle); + if (fd < 0) { + printf("Unable to get fd\n"); + err = -1; + goto out_clean; + } + + if (fcntl(fd, F_GETFD) < 0) { + printf("Unable to get valid fd\n"); + err = -1; + goto out_clean; + } + + printf("Testing ERROR conditions\n"); + + printf("Passing empty struct to get_fd\n"); + if (nozzle_get_fd(NULL) > 0) { + printf("Something is wrong in nozzle_get_fd sanity checks\n"); + err = -1; + goto out_clean; + } + +out_clean: + if (nozzle) { + nozzle_close(nozzle); + } + + return err; +} + +int main(void) +{ + need_root(); + + if (test() < 0) + return FAIL; + + return PASS; +} diff --git a/libnozzle/tests/api_nozzle_get_handle_by_name.c b/libnozzle/tests/api_nozzle_get_handle_by_name.c new file mode 100644 index 00000000..0abc1bab --- /dev/null +++ b/libnozzle/tests/api_nozzle_get_handle_by_name.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "test-common.h" + +static int test(void) +{ + char device_name[2*IFNAMSIZ]; + size_t size = IFNAMSIZ; + nozzle_t nozzle, nozzle_tmp; + int err = 0; + + printf("Testing get handle by name\n"); + + memset(device_name, 0, size); + nozzle = nozzle_open(device_name, size, NULL); + if (!nozzle) { + printf("Unable to init %s\n", device_name); + return -1; + } + + nozzle_tmp = nozzle_get_handle_by_name(device_name); + if ((!nozzle_tmp) && (errno != ENOENT)) { + printf("Unable to get handle by name\n"); + err = -1; + goto out_clean; + } + + if (nozzle != nozzle_tmp) { + printf("get handle by name returned wrong handle!\n"); + err = -1; + goto out_clean; + } + + printf("Testing error conditions\n"); + + printf("Testing with NULL device name\n"); + + nozzle_tmp = nozzle_get_handle_by_name(NULL); + + if ((nozzle_tmp) || (errno != EINVAL)) { + printf("get handle by name returned wrong error\n"); + err = -1; + goto out_clean; + } + + printf("Testing with device name longer than IFNAMSIZ\n"); + + nozzle_tmp = nozzle_get_handle_by_name("antanisupercazzolaunpotapioca"); + if ((nozzle_tmp) || (errno != EINVAL)) { + printf("get handle by name returned wrong error\n"); + err = -1; + goto out_clean; + } + +out_clean: + + if (nozzle) { + nozzle_close(nozzle); + } + + return err; +} + +int main(void) +{ + need_root(); + + if (test() < 0) + return FAIL; + + return PASS; +} diff --git a/libnozzle/tests/api_nozzle_get_ips.c b/libnozzle/tests/api_nozzle_get_ips.c new file mode 100644 index 00000000..ce31cec5 --- /dev/null +++ b/libnozzle/tests/api_nozzle_get_ips.c @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test-common.h" + +char testipv4_1[IPBUFSIZE]; +char testipv4_2[IPBUFSIZE]; +char testipv6_1[IPBUFSIZE]; +char testipv6_2[IPBUFSIZE]; + +static int test(void) +{ + char device_name[IFNAMSIZ]; + size_t size = IFNAMSIZ; + int err = 0; + nozzle_t nozzle; + struct nozzle_ip *ip_list = NULL, *ip_list_tmp = NULL; + int ip_list_entries = 0, ipv4_list_entries = 0, ipv6_list_entries = 0; + + printf("Testing get ips\n"); + + memset(device_name, 0, size); + + nozzle = nozzle_open(device_name, size, NULL); + if (!nozzle) { + printf("Unable to init %s\n", device_name); + return -1; + } + + printf("Testing error conditions\n"); + + printf("Testing invalid nozzle\n"); + err = nozzle_get_ips(NULL, &ip_list); + if ((!err) || (errno != EINVAL)) { + printf("nozzle_get_ips accepted invalid nozzle\n"); + err = -1; + goto out_clean; + } + + printf("Testing invalid ip list\n"); + err = nozzle_get_ips(nozzle, NULL); + if ((!err) || (errno != EINVAL)) { + printf("nozzle_get_ips accepted invalid ip list\n"); + err = -1; + goto out_clean; + } + + printf("Adding ip: %s/24\n", testipv4_1); + + err = nozzle_add_ip(nozzle, testipv4_1, "24"); + if (err < 0) { + printf("Unable to assign IP address\n"); + err = -1; + goto out_clean; + } + + printf("Adding ip: %s/24\n", testipv4_2); + + err = nozzle_add_ip(nozzle, testipv4_2, "24"); + if (err < 0) { + printf("Unable to assign IP address\n"); + err = -1; + goto out_clean; + } + + printf("Adding ip: %s/64\n", testipv6_1); + + err = nozzle_add_ip(nozzle, testipv6_1, "64"); + if (err < 0) { + printf("Unable to assign IP address\n"); + err = -1; + goto out_clean; + } + + printf("Adding ip: %s/64\n", testipv6_2); + + err = nozzle_add_ip(nozzle, testipv6_2, "64"); + if (err < 0) { + printf("Unable to assign IP address\n"); + err = -1; + goto out_clean; + } + + printf("Get ip list from libnozzle:\n"); + + if (nozzle_get_ips(nozzle, &ip_list) < 0) { + printf("Not enough mem?\n"); + err = -1; + goto out_clean; + } + + ip_list_tmp = ip_list; + ip_list_entries = 0; + + while(ip_list_tmp) { + ip_list_entries++; + if (ip_list_tmp->domain == AF_INET) { + ipv4_list_entries++; + } else { + ipv6_list_entries++; + } + printf("Found IP %s %s in libnozzle db\n", ip_list_tmp->ipaddr, ip_list_tmp->prefix); + ip_list_tmp = ip_list_tmp->next; + } + + if ((ip_list_entries != 4) || + (ipv4_list_entries != 2) || + (ipv6_list_entries != 2)) { + printf("Didn't get enough ip back from libnozzle?\n"); + err = -1; + goto out_clean; + } + + printf("Deleting ip: %s/24\n", testipv4_1); + + err = nozzle_del_ip(nozzle, testipv4_1, "24"); + if (err < 0) { + printf("Unable to delete IP address\n"); + err = -1; + goto out_clean; + } + + printf("Deleting ip: %s/24\n", testipv4_2); + + err = nozzle_del_ip(nozzle, testipv4_2, "24"); + if (err < 0) { + printf("Unable to delete IP address\n"); + err = -1; + goto out_clean; + } + + printf("Deleting ip: %s/64\n", testipv6_1); + + err = nozzle_del_ip(nozzle, testipv6_1, "64"); + if (err) { + printf("Unable to delete IP address\n"); + err = -1; + goto out_clean; + } + + printf("Deleting ip: %s/64\n", testipv6_2); + + err = nozzle_del_ip(nozzle, testipv6_2, "64"); + if (err) { + printf("Unable to delete IP address\n"); + err = -1; + goto out_clean; + } + +out_clean: + nozzle_close(nozzle); + + return err; +} + +int main(void) +{ + need_root(); + + make_local_ips(testipv4_1, testipv4_2, testipv6_1, testipv6_2); + + if (test() < 0) + return FAIL; + + return PASS; +} diff --git a/libnozzle/tests/api_nozzle_get_mac.c b/libnozzle/tests/api_nozzle_get_mac.c new file mode 100644 index 00000000..81f31427 --- /dev/null +++ b/libnozzle/tests/api_nozzle_get_mac.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef KNET_LINUX +#include +#include +#endif +#ifdef KNET_BSD +#include +#endif + +#include "test-common.h" + +static int test(void) +{ + char device_name[IFNAMSIZ]; + size_t size = IFNAMSIZ; + int err=0; + nozzle_t nozzle; + char *current_mac = NULL, *temp_mac = NULL, *err_mac = NULL; + struct ether_addr *cur_mac, *tmp_mac; + + printf("Testing get MAC\n"); + + memset(device_name, 0, size); + nozzle = nozzle_open(device_name, size, NULL); + if (!nozzle) { + printf("Unable to init %s\n", device_name); + return -1; + } + + printf("Get current MAC\n"); + + if (nozzle_get_mac(nozzle, ¤t_mac) < 0) { + printf("Unable to get current MAC address.\n"); + err = -1; + goto out_clean; + } + + printf("Current MAC: %s\n", current_mac); + + printf("Setting MAC: 00:01:01:01:01:01\n"); + + if (nozzle_set_mac(nozzle, "00:01:01:01:01:01") < 0) { + printf("Unable to set current MAC address.\n"); + err = -1; + goto out_clean; + } + + if (nozzle_get_mac(nozzle, &temp_mac) < 0) { + printf("Unable to get current MAC address.\n"); + err = -1; + goto out_clean; + } + + printf("Current MAC: %s\n", temp_mac); + + cur_mac = ether_aton(current_mac); + tmp_mac = ether_aton(temp_mac); + + printf("Comparing MAC addresses\n"); + if (memcmp(cur_mac, tmp_mac, sizeof(struct ether_addr))) { + printf("Mac addresses are not the same?!\n"); + err = -1; + goto out_clean; + } + + printf("Testing ERROR conditions\n"); + + printf("Pass NULL to get_mac (pass1)\n"); + errno = 0; + if ((nozzle_get_mac(NULL, &err_mac) >= 0) || (errno != EINVAL)) { + printf("Something is wrong in nozzle_get_mac sanity checks\n"); + err = -1; + goto out_clean; + } + + printf("Pass NULL to get_mac (pass2)\n"); + errno = 0; + if ((nozzle_get_mac(nozzle, NULL) >= 0) || (errno != EINVAL)) { + printf("Something is wrong in nozzle_get_mac sanity checks\n"); + err = -1; + goto out_clean; + } + +out_clean: + if (err_mac) { + printf("Something managed to set err_mac!\n"); + err = -1; + free(err_mac); + } + + if (current_mac) + free(current_mac); + if (temp_mac) + free(temp_mac); + + if (nozzle) { + nozzle_close(nozzle); + } + + return err; +} + +int main(void) +{ + need_root(); + + if (test() < 0) + return FAIL; + + return PASS; +} diff --git a/libnozzle/tests/api_nozzle_get_mtu.c b/libnozzle/tests/api_nozzle_get_mtu.c new file mode 100644 index 00000000..2db1a527 --- /dev/null +++ b/libnozzle/tests/api_nozzle_get_mtu.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "test-common.h" + +static int test(void) +{ + char device_name[IFNAMSIZ]; + size_t size = IFNAMSIZ; + int err=0; + nozzle_t nozzle; + + int current_mtu = 0; + int expected_mtu = 1500; + + printf("Testing get MTU\n"); + + memset(device_name, 0, size); + nozzle = nozzle_open(device_name, size, NULL); + if (!nozzle) { + printf("Unable to init %s\n", device_name); + return -1; + } + + printf("Comparing default MTU\n"); + current_mtu = nozzle_get_mtu(nozzle); + if (current_mtu < 0) { + printf("Unable to get MTU\n"); + err = -1; + goto out_clean; + } + if (current_mtu != expected_mtu) { + printf("current mtu [%d] does not match expected default [%d]\n", current_mtu, expected_mtu); + err = -1; + goto out_clean; + } + + printf("Setting MTU to 9000\n"); + expected_mtu = 9000; + if (nozzle_set_mtu(nozzle, expected_mtu) < 0) { + printf("Unable to set MTU to %d\n", expected_mtu); + err = -1; + goto out_clean; + } + + current_mtu = nozzle_get_mtu(nozzle); + if (current_mtu < 0) { + printf("Unable to get MTU\n"); + err = -1; + goto out_clean; + } + if (current_mtu != expected_mtu) { + printf("current mtu [%d] does not match expected value [%d]\n", current_mtu, expected_mtu); + err = -1; + goto out_clean; + } + + printf("Testing ERROR conditions\n"); + + printf("Passing empty struct to get_mtu\n"); + if (nozzle_get_mtu(NULL) > 0) { + printf("Something is wrong in nozzle_get_mtu sanity checks\n"); + err = -1; + goto out_clean; + } + +out_clean: + if (nozzle) { + nozzle_close(nozzle); + } + + return err; +} + +int main(void) +{ + need_root(); + + if (test() < 0) + return FAIL; + + return PASS; +} diff --git a/libnozzle/tests/api_nozzle_get_name_by_handle.c b/libnozzle/tests/api_nozzle_get_name_by_handle.c new file mode 100644 index 00000000..8e85b832 --- /dev/null +++ b/libnozzle/tests/api_nozzle_get_name_by_handle.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "test-common.h" + +static int test(void) +{ + char device_name[2*IFNAMSIZ]; + const char *device_name_tmp; + size_t size = IFNAMSIZ; + nozzle_t nozzle; + int err = 0; + + printf("Testing get name by handle\n"); + + memset(device_name, 0, size); + nozzle = nozzle_open(device_name, size, NULL); + if (!nozzle) { + printf("Unable to init %s\n", device_name); + return -1; + } + + device_name_tmp = nozzle_get_name_by_handle(nozzle); + if ((!device_name_tmp) && (errno != ENOENT)) { + printf("Unable to get name by handle\n"); + err = -1; + goto out_clean; + } + + if (strcmp(device_name, device_name_tmp)) { + printf("get name by handle returned different names for the same handle\n"); + err = -1; + goto out_clean; + } + + printf("Testing error conditions\n"); + + device_name_tmp = nozzle_get_name_by_handle(NULL); + if ((device_name_tmp) || (errno != ENOENT)) { + printf("get name by handle returned wrong error\n"); + err = -1; + goto out_clean; + } + +out_clean: + + if (nozzle) { + nozzle_close(nozzle); + } + + return err; +} + +int main(void) +{ + need_root(); + + if (test() < 0) + return FAIL; + + return PASS; +} diff --git a/libnozzle/tests/api_nozzle_open.c b/libnozzle/tests/api_nozzle_open.c new file mode 100644 index 00000000..19876987 --- /dev/null +++ b/libnozzle/tests/api_nozzle_open.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "test-common.h" + +static int test_multi_eth(void) +{ + char device_name1[IFNAMSIZ]; + char device_name2[IFNAMSIZ]; + size_t size = IFNAMSIZ; + int err=0; + nozzle_t nozzle1 = NULL; + nozzle_t nozzle2 = NULL; + + printf("Testing multiple nozzle interface instances\n"); + + memset(device_name1, 0, size); + memset(device_name2, 0, size); + + nozzle1 = nozzle_open(device_name1, size, NULL); + if (!nozzle1) { + printf("Unable to init %s\n", device_name1); + err = -1; + goto out_clean; + } + + if (is_if_in_system(device_name1) > 0) { + printf("Found interface %s on the system\n", device_name1); + } else { + printf("Unable to find interface %s on the system\n", device_name1); + } + + nozzle2 = nozzle_open(device_name2, size, NULL); + if (!nozzle2) { + printf("Unable to init %s\n", device_name2); + err = -1; + goto out_clean; + } + + if (is_if_in_system(device_name2) > 0) { + printf("Found interface %s on the system\n", device_name2); + } else { + printf("Unable to find interface %s on the system\n", device_name2); + } + + if (nozzle1) { + nozzle_close(nozzle1); + } + + if (nozzle2) { + nozzle_close(nozzle2); + } + + printf("Testing error conditions\n"); + + printf("Open same device twice\n"); + + memset(device_name1, 0, size); + + nozzle1 = nozzle_open(device_name1, size, NULL); + if (!nozzle1) { + printf("Unable to init %s\n", device_name1); + err = -1; + goto out_clean; + } + + if (is_if_in_system(device_name1) > 0) { + printf("Found interface %s on the system\n", device_name1); + } else { + printf("Unable to find interface %s on the system\n", device_name1); + } + + nozzle2 = nozzle_open(device_name1, size, NULL); + if (nozzle2) { + printf("We were able to init 2 interfaces with the same name!\n"); + err = -1; + goto out_clean; + } + +out_clean: + if (nozzle1) { + nozzle_close(nozzle1); + } + + if (nozzle2) { + nozzle_close(nozzle2); + } + + return err; +} + +static int test(void) +{ + char device_name[2*IFNAMSIZ]; + char fakepath[PATH_MAX]; + size_t size = IFNAMSIZ; + uint8_t randombyte = get_random_byte(); + + memset(device_name, 0, sizeof(device_name)); + + printf("Creating random nozzle interface:\n"); + if (test_iface(device_name, size, NULL) < 0) { + printf("Unable to create random interface\n"); + return -1; + } + +#ifdef KNET_LINUX + printf("Creating kronostest%u nozzle interface:\n", randombyte); + snprintf(device_name, IFNAMSIZ, "kronostest%u", randombyte); + if (test_iface(device_name, size, NULL) < 0) { + printf("Unable to create kronostest%u interface\n", randombyte); + return -1; + } +#endif +#ifdef KNET_BSD + printf("Creating tap%u nozzle interface:\n", randombyte); + snprintf(device_name, IFNAMSIZ, "tap%u", randombyte); + if (test_iface(device_name, size, NULL) < 0) { + printf("Unable to create tap%u interface\n", randombyte); + return -1; + } + + printf("Creating kronostest%u nozzle interface:\n", randombyte); + snprintf(device_name, IFNAMSIZ, "kronostest%u", randombyte); + if (test_iface(device_name, size, NULL) == 0) { + printf("BSD should not accept kronostest%u interface\n", randombyte); + return -1; + } +#endif + + printf("Testing ERROR conditions\n"); + + printf("Testing dev == NULL\n"); + errno=0; + if ((test_iface(NULL, size, NULL) >= 0) || (errno != EINVAL)) { + printf("Something is wrong in nozzle_open sanity checks\n"); + return -1; + } + + printf("Testing size < IFNAMSIZ\n"); + errno=0; + if ((test_iface(device_name, 1, NULL) >= 0) || (errno != EINVAL)) { + printf("Something is wrong in nozzle_open sanity checks\n"); + return -1; + } + + printf("Testing device_name size > IFNAMSIZ\n"); + errno=0; + strcpy(device_name, "abcdefghilmnopqrstuvwz"); + if ((test_iface(device_name, IFNAMSIZ, NULL) >= 0) || (errno != E2BIG)) { + printf("Something is wrong in nozzle_open sanity checks\n"); + return -1; + } + + printf("Testing updown path != abs\n"); + errno=0; + + memset(device_name, 0, IFNAMSIZ); + if ((test_iface(device_name, IFNAMSIZ, "foo") >= 0) || (errno != EINVAL)) { + printf("Something is wrong in nozzle_open sanity checks\n"); + return -1; + } + + memset(fakepath, 0, PATH_MAX); + memset(fakepath, '/', PATH_MAX - 2); + + printf("Testing updown path > PATH_MAX\n"); + errno=0; + + memset(device_name, 0, IFNAMSIZ); + if ((test_iface(device_name, IFNAMSIZ, fakepath) >= 0) || (errno != E2BIG)) { + printf("Something is wrong in nozzle_open sanity checks\n"); + return -1; + } + + return 0; +} + +int main(void) +{ + need_root(); + + if (test() < 0) + return FAIL; + + if (test_multi_eth() < 0) + return FAIL; + + return PASS; +} diff --git a/libnozzle/tests/api_nozzle_run_updown.c b/libnozzle/tests/api_nozzle_run_updown.c new file mode 100644 index 00000000..ad81c457 --- /dev/null +++ b/libnozzle/tests/api_nozzle_run_updown.c @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test-common.h" + +static int test(void) +{ + char device_name[IFNAMSIZ]; + size_t size = IFNAMSIZ; + int err=0; + nozzle_t nozzle = NULL; + char *error_string = NULL; + char *tmpdir = NULL; + char tmpdirsrc[PATH_MAX]; + char tmpstr[PATH_MAX*2]; + char srcfile[PATH_MAX]; + char dstfile[PATH_MAX]; + + /* + * create a tmp dir for storing up/down scripts. + * we cannot create symlinks src dir + */ + strcpy(tmpdirsrc, ABSBUILDDIR "/nozzle_test_XXXXXX"); + + tmpdir = mkdtemp(tmpdirsrc); + if (!tmpdir) { + printf("Unable to create temporary directory %s for testing: %s\n", tmpdirsrc, strerror(errno)); + return -1; + } + + printf("Created temporary test dir: %s\n", tmpdir); + + printf("Populating test dir...\n"); + + snprintf(tmpstr, sizeof(tmpstr) - 1, "%s/pre-up.d", tmpdir); + if (mkdir(tmpstr, 0700) < 0) { + printf("Unable to create %s/pre-up.d: %s", tmpdir, strerror(errno)); + err = -1; + goto out_clean; + } + + snprintf(tmpstr, sizeof(tmpstr) - 1, "%s/up.d", tmpdir); + if (mkdir(tmpstr, 0700) < 0) { + printf("Unable to create %s/up.d: %s", tmpdir, strerror(errno)); + err = -1; + goto out_clean; + } + + snprintf(tmpstr, sizeof(tmpstr) - 1, "%s/down.d", tmpdir); + if (mkdir(tmpstr, 0700) < 0) { + printf("Unable to create %s/down.d: %s", tmpdir, strerror(errno)); + err = -1; + goto out_clean; + } + + snprintf(tmpstr, sizeof(tmpstr) - 1, "%s/post-down.d", tmpdir); + if (mkdir(tmpstr, 0700) < 0) { + printf("Unable to create %s/post-down.d: %s", tmpdir, strerror(errno)); + err = -1; + goto out_clean; + } + + printf("Testing error conditions\n"); + + printf("Init nozzle device with no path\n"); + + memset(device_name, 0, size); + nozzle = nozzle_open(device_name, size, NULL); + if (!nozzle) { + printf("Unable to init %s\n", device_name); + err = -1; + goto out_clean; + } + + err = nozzle_run_updown(nozzle, NOZZLE_POSTDOWN, &error_string); + if ((!err) || (errno != EINVAL)) { + printf("nozzle_run_updown sanity check failed\n"); + err = -1; + goto out_clean; + } + + nozzle_close(nozzle); + + printf("Init nozzle device with path\n"); + + memset(device_name, 0, size); + nozzle = nozzle_open(device_name, size, tmpdir); + if (!nozzle) { + printf("Unable to init %s\n", device_name); + err = -1; + goto out_clean; + } + + printf("Testing invalid nozzle handle\n"); + + err = nozzle_run_updown(NULL, NOZZLE_POSTDOWN, &error_string); + if ((!err) || (errno != EINVAL)) { + printf("nozzle_run_updown sanity check failed\n"); + err = -1; + goto out_clean; + } + + printf("Testing invalid action\n"); + + err = nozzle_run_updown(nozzle, NOZZLE_POSTDOWN + 1, &error_string); + if ((!err) || (errno != EINVAL)) { + printf("nozzle_run_updown sanity check failed\n"); + err = -1; + goto out_clean; + } + + printf("Testing invalid error string\n"); + + err = nozzle_run_updown(nozzle, NOZZLE_POSTDOWN + 1, NULL); + if ((!err) || (errno != EINVAL)) { + printf("nozzle_run_updown sanity check failed\n"); + err = -1; + goto out_clean; + } + + printf("Testing interface pre-up/up/down/post-down (no scripts installed)\n"); + + err = nozzle_run_updown(nozzle, NOZZLE_PREUP, &error_string); + if (!err) { + printf("nozzle_run_updown failed to detect lack of script in pre-up.d\n"); + err = -1; + goto out_clean; + } else { + if (error_string) { + free(error_string); + error_string = NULL; + } + } + + err = nozzle_run_updown(nozzle, NOZZLE_UP, &error_string); + if (!err) { + printf("nozzle_run_updown failed to detect lack of script in up.d\n"); + err = -1; + goto out_clean; + } else { + if (error_string) { + free(error_string); + error_string = NULL; + } + } + + err = nozzle_run_updown(nozzle, NOZZLE_DOWN, &error_string); + if (!err) { + printf("nozzle_run_updown failed to detect lack of script in down.d\n"); + err = -1; + goto out_clean; + } else { + if (error_string) { + free(error_string); + error_string = NULL; + } + } + + err = nozzle_run_updown(nozzle, NOZZLE_POSTDOWN, &error_string); + if (!err) { + printf("nozzle_run_updown failed to detect lack of script in post-down.d\n"); + err = -1; + goto out_clean; + } else { + if (error_string) { + free(error_string); + error_string = NULL; + } + } + + printf("Populating test dir with fail scripts\n"); + + snprintf(srcfile, sizeof(srcfile) - 1, "%s/nozzle_run_updown_exit_false", ABSSRCDIR); + + snprintf(dstfile, sizeof(dstfile) - 1, "%s/pre-up.d/%s", tmpdir, device_name); + if (link(srcfile, dstfile) < 0) { + printf("unable to create symlink\n"); + err = -1; + goto out_clean; + } + + snprintf(dstfile, sizeof(dstfile) - 1, "%s/up.d/%s", tmpdir, device_name); + if (link(srcfile, dstfile) < 0) { + printf("unable to create symlink\n"); + err = -1; + goto out_clean; + } + + snprintf(dstfile, sizeof(dstfile) - 1, "%s/down.d/%s", tmpdir, device_name); + if (link(srcfile, dstfile) < 0) { + printf("unable to create symlink\n"); + err = -1; + goto out_clean; + } + + snprintf(dstfile, sizeof(dstfile) - 1, "%s/post-down.d/%s", tmpdir, device_name); + if (link(srcfile, dstfile) < 0) { + printf("unable to create symlink\n"); + err = -1; + goto out_clean; + } + + printf("Testing interface pre-up/up/down/post-down (FAIL scripts installed)\n"); + + err = nozzle_run_updown(nozzle, NOZZLE_PREUP, &error_string); + if (err != -2) { + printf("nozzle_run_updown failed to detect script failure in pre-up.d\n"); + err = -1; + goto out_clean; + } else { + if (error_string) { + free(error_string); + error_string = NULL; + } + } + + err = nozzle_run_updown(nozzle, NOZZLE_UP, &error_string); + if (err != -2) { + printf("nozzle_run_updown failed to detect script failure in up.d\n"); + err = -1; + goto out_clean; + } else { + if (error_string) { + free(error_string); + error_string = NULL; + } + } + + err = nozzle_run_updown(nozzle, NOZZLE_DOWN, &error_string); + if (err != -2) { + printf("nozzle_run_updown failed to detect script failure in down.d\n"); + err = -1; + goto out_clean; + } else { + if (error_string) { + free(error_string); + error_string = NULL; + } + } + + err = nozzle_run_updown(nozzle, NOZZLE_POSTDOWN, &error_string); + if (err != -2) { + printf("nozzle_run_updown failed to detect script failure in post-down.d\n"); + err = -1; + goto out_clean; + } else { + if (error_string) { + free(error_string); + error_string = NULL; + } + } + + printf("Populating test dir with true scripts\n"); + + snprintf(srcfile, sizeof(srcfile) - 1, "%s/nozzle_run_updown_exit_true", ABSSRCDIR); + + snprintf(dstfile, sizeof(dstfile) - 1, "%s/pre-up.d/%s", tmpdir, device_name); + if (unlink(dstfile) < 0) { + printf("unable to remove old symlink\n"); + err = -1; + goto out_clean; + } + if (link(srcfile, dstfile) < 0) { + printf("unable to create symlink\n"); + err = -1; + goto out_clean; + } + + snprintf(dstfile, sizeof(dstfile) - 1, "%s/up.d/%s", tmpdir, device_name); + if (unlink(dstfile) < 0) { + printf("unable to remove old symlink\n"); + err = -1; + goto out_clean; + } + if (link(srcfile, dstfile) < 0) { + printf("unable to create symlink\n"); + err = -1; + goto out_clean; + } + + snprintf(dstfile, sizeof(dstfile) - 1, "%s/down.d/%s", tmpdir, device_name); + if (unlink(dstfile) < 0) { + printf("unable to remove old symlink\n"); + err = -1; + goto out_clean; + } + if (link(srcfile, dstfile) < 0) { + printf("unable to create symlink\n"); + err = -1; + goto out_clean; + } + + snprintf(dstfile, sizeof(dstfile) - 1, "%s/post-down.d/%s", tmpdir, device_name); + if (unlink(dstfile) < 0) { + printf("unable to remove old symlink\n"); + err = -1; + goto out_clean; + } + if (link(srcfile, dstfile) < 0) { + printf("unable to create symlink\n"); + err = -1; + goto out_clean; + } + + printf("Testing interface pre-up/up/down/post-down (TRUE scripts installed)\n"); + + err = nozzle_run_updown(nozzle, NOZZLE_PREUP, &error_string); + if (err) { + printf("nozzle_run_updown failed to execute true script in pre-up.d\n"); + err = -1; + goto out_clean; + } else { + if (error_string) { + free(error_string); + error_string = NULL; + } + } + + err = nozzle_run_updown(nozzle, NOZZLE_UP, &error_string); + if (err) { + printf("nozzle_run_updown failed to execute true script in up.d\n"); + err = -1; + goto out_clean; + } else { + if (error_string) { + free(error_string); + error_string = NULL; + } + } + + err = nozzle_run_updown(nozzle, NOZZLE_DOWN, &error_string); + if (err) { + printf("nozzle_run_updown failed to execite true script in down.d\n"); + err = -1; + goto out_clean; + } else { + if (error_string) { + free(error_string); + error_string = NULL; + } + } + + err = nozzle_run_updown(nozzle, NOZZLE_POSTDOWN, &error_string); + if (err) { + printf("nozzle_run_updown failed to execute true script in post-down.d\n"); + err = -1; + goto out_clean; + } else { + if (error_string) { + free(error_string); + error_string = NULL; + } + } + + +out_clean: + if (tmpdir) { + snprintf(tmpstr, sizeof(tmpstr) - 1, "rm -rf %s", tmpdir); + printf("Removing temporary dir: %s\n", tmpstr); + err = execute_bin_sh_command(tmpstr, &error_string); + if (err) { + printf("Error removing directory: %s\n", error_string); + } + if (error_string) { + free(error_string); + } + } + if (nozzle) { + nozzle_close(nozzle); + } + + return err; +} + +int main(void) +{ + need_root(); + + if (test() < 0) + return FAIL; + + return PASS; +} diff --git a/libnozzle/tests/api_nozzle_set_down.c b/libnozzle/tests/api_nozzle_set_down.c new file mode 100644 index 00000000..f477a4b2 --- /dev/null +++ b/libnozzle/tests/api_nozzle_set_down.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "test-common.h" + +static int test(void) +{ + char verifycmd[1024]; + char device_name[IFNAMSIZ]; + size_t size = IFNAMSIZ; + int err=0; + nozzle_t nozzle; + char *error_string = NULL; + + printf("Testing interface down\n"); + + memset(device_name, 0, size); + nozzle = nozzle_open(device_name, size, NULL); + if (!nozzle) { + printf("Unable to init %s\n", device_name); + return -1; + } + + printf("Put the interface up\n"); + + err = nozzle_set_up(nozzle); + if (err < 0) { + printf("Unable to set interface up\n"); + err = -1; + goto out_clean; + } + + memset(verifycmd, 0, sizeof(verifycmd)); + snprintf(verifycmd, sizeof(verifycmd)-1, +#ifdef KNET_LINUX + "ip addr show dev %s | grep -q UP", nozzle->name); +#endif +#ifdef KNET_BSD + "ifconfig %s | grep -q UP", nozzle->name); +#endif + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (err < 0) { + printf("Unable to verify inteface UP\n"); + err = -1; + goto out_clean; + } + + printf("Put the interface down\n"); + + err = nozzle_set_down(nozzle); + if (err < 0) { + printf("Unable to put the interface down\n"); + err = -1; + goto out_clean; + } + + memset(verifycmd, 0, sizeof(verifycmd)); + snprintf(verifycmd, sizeof(verifycmd)-1, +#ifdef KNET_LINUX + "ip addr show dev %s | grep -q UP", nozzle->name); +#endif +#ifdef KNET_BSD + "ifconfig %s | grep -q UP", nozzle->name); +#endif + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (!err) { + printf("Unable to verify inteface DOWN\n"); + err = -1; + goto out_clean; + } + + printf("Try to DOWN the same interface twice\n"); + if (nozzle_set_down(nozzle) < 0) { + printf("Interface was already DOWN, spurious error received from nozzle_set_down\n"); + err = -1; + goto out_clean; + } + + printf("Pass NULL to nozzle set_down\n"); + errno = 0; + if ((nozzle_set_down(NULL) >= 0) || (errno != EINVAL)) { + printf("Something is wrong in nozzle_set_down sanity checks\n"); + err = -1; + goto out_clean; + } + +out_clean: + nozzle_close(nozzle); + + return err; +} + +int main(void) +{ + need_root(); + + if (test() < 0) + return FAIL; + + return PASS; +} diff --git a/libnozzle/tests/api_nozzle_set_mac.c b/libnozzle/tests/api_nozzle_set_mac.c new file mode 100644 index 00000000..d7ea405d --- /dev/null +++ b/libnozzle/tests/api_nozzle_set_mac.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef KNET_LINUX +#include +#include +#endif +#ifdef KNET_BSD +#include +#endif + +#include "test-common.h" + +static int test(void) +{ + char device_name[IFNAMSIZ]; + size_t size = IFNAMSIZ; + int err=0; + nozzle_t nozzle; + char *original_mac = NULL, *current_mac = NULL, *temp_mac = NULL, *err_mac = NULL; + struct ether_addr *orig_mac, *cur_mac, *tmp_mac; + + printf("Testing set MAC\n"); + + memset(device_name, 0, size); + nozzle = nozzle_open(device_name, size, NULL); + if (!nozzle) { + printf("Unable to init %s\n", device_name); + return -1; + } + + printf("Get current MAC\n"); + + if (nozzle_get_mac(nozzle, &original_mac) < 0) { + printf("Unable to get current MAC address.\n"); + err = -1; + goto out_clean; + } + orig_mac = ether_aton(original_mac); + + if (nozzle_get_mac(nozzle, ¤t_mac) < 0) { + printf("Unable to get current MAC address.\n"); + err = -1; + goto out_clean; + } + + printf("Current MAC: %s\n", current_mac); + + printf("Setting MAC: 00:01:01:01:01:01\n"); + + if (nozzle_set_mac(nozzle, "00:01:01:01:01:01") < 0) { + printf("Unable to set current MAC address.\n"); + err = -1; + goto out_clean; + } + + if (nozzle_get_mac(nozzle, &temp_mac) < 0) { + printf("Unable to get current MAC address.\n"); + err = -1; + goto out_clean; + } + + printf("Current MAC: %s\n", temp_mac); + + cur_mac = ether_aton(current_mac); + tmp_mac = ether_aton(temp_mac); + + printf("Comparing MAC addresses\n"); + if (memcmp(cur_mac, tmp_mac, sizeof(struct ether_addr))) { + printf("Mac addresses are not the same?!\n"); + err = -1; + goto out_clean; + } + + printf("Testing reset_mac\n"); + if (nozzle_reset_mac(nozzle) < 0) { + printf("Unable to reset mac address\n"); + err = -1; + goto out_clean; + } + + if (current_mac) + free(current_mac); + + if (nozzle_get_mac(nozzle, ¤t_mac) < 0) { + printf("Unable to get current MAC address.\n"); + err = -1; + goto out_clean; + } + + cur_mac = ether_aton(current_mac); + if (memcmp(cur_mac, orig_mac, sizeof(struct ether_addr))) { + printf("Mac addresses are not the same?!\n"); + err = -1; + goto out_clean; + } + + printf("Testing ERROR conditions\n"); + + printf("Pass NULL to set_mac (pass1)\n"); + errno = 0; + if ((nozzle_set_mac(nozzle, NULL) >= 0) || (errno != EINVAL)) { + printf("Something is wrong in nozzle_set_mac sanity checks\n"); + err = -1; + goto out_clean; + } + + printf("Pass NULL to set_mac (pass2)\n"); + errno = 0; + if ((nozzle_set_mac(NULL, err_mac) >= 0) || (errno != EINVAL)) { + printf("Something is wrong in nozzle_set_mac sanity checks\n"); + err = -1; + goto out_clean; + } + +out_clean: + if (err_mac) { + printf("Something managed to set err_mac!\n"); + err = -1; + free(err_mac); + } + + if (current_mac) + free(current_mac); + if (temp_mac) + free(temp_mac); + if (original_mac) + free(original_mac); + + if (nozzle) { + nozzle_close(nozzle); + } + + return err; +} + +int main(void) +{ + need_root(); + + if (test() < 0) + return FAIL; + + return PASS; +} diff --git a/libnozzle/tests/api_nozzle_set_mtu.c b/libnozzle/tests/api_nozzle_set_mtu.c new file mode 100644 index 00000000..b26df345 --- /dev/null +++ b/libnozzle/tests/api_nozzle_set_mtu.c @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "test-common.h" + +char testipv4_1[IPBUFSIZE]; +char testipv4_2[IPBUFSIZE]; +char testipv6_1[IPBUFSIZE]; +char testipv6_2[IPBUFSIZE]; + +static int test(void) +{ + char device_name[IFNAMSIZ]; + size_t size = IFNAMSIZ; + int err=0; + nozzle_t nozzle; + + int current_mtu = 0; + int expected_mtu = 1500; + + printf("Testing set MTU\n"); + + memset(device_name, 0, size); + nozzle = nozzle_open(device_name, size, NULL); + if (!nozzle) { + printf("Unable to init %s\n", device_name); + return -1; + } + + printf("Comparing default MTU\n"); + current_mtu = nozzle_get_mtu(nozzle); + if (current_mtu < 0) { + printf("Unable to get MTU\n"); + err = -1; + goto out_clean; + } + if (current_mtu != expected_mtu) { + printf("current mtu [%d] does not match expected default [%d]\n", current_mtu, expected_mtu); + err = -1; + goto out_clean; + } + + printf("Setting MTU to 9000\n"); + expected_mtu = 9000; + if (nozzle_set_mtu(nozzle, expected_mtu) < 0) { + printf("Unable to set MTU to %d\n", expected_mtu); + err = -1; + goto out_clean; + } + + current_mtu = nozzle_get_mtu(nozzle); + if (current_mtu < 0) { + printf("Unable to get MTU\n"); + err = -1; + goto out_clean; + } + if (current_mtu != expected_mtu) { + printf("current mtu [%d] does not match expected value [%d]\n", current_mtu, expected_mtu); + err = -1; + goto out_clean; + } + + printf("Restoring MTU to default\n"); + expected_mtu = 1500; + if (nozzle_reset_mtu(nozzle) < 0) { + printf("Unable to reset mtu\n"); + err = -1; + goto out_clean; + } + current_mtu = nozzle_get_mtu(nozzle); + if (current_mtu < 0) { + printf("Unable to get MTU\n"); + err = -1; + goto out_clean; + } + if (current_mtu != expected_mtu) { + printf("current mtu [%d] does not match expected value [%d]\n", current_mtu, expected_mtu); + err = -1; + goto out_clean; + } + + printf("Testing ERROR conditions\n"); + + printf("Passing empty struct to set_mtu\n"); + if (nozzle_set_mtu(NULL, 1500) == 0) { + printf("Something is wrong in nozzle_set_mtu sanity checks\n"); + err = -1; + goto out_clean; + } + + printf("Passing 0 mtu to set_mtu\n"); + if (nozzle_set_mtu(nozzle, 0) == 0) { + printf("Something is wrong in nozzle_set_mtu sanity checks\n"); + err = -1; + goto out_clean; + } + +out_clean: + if (nozzle) { + nozzle_close(nozzle); + } + + return err; +} + +static int test_ipv6(void) +{ + char device_name[IFNAMSIZ]; + size_t size = IFNAMSIZ; + char verifycmd[2048]; + int err=0; + nozzle_t nozzle; + char *error_string = NULL; + int current_mtu = 0; + + printf("Testing get/set MTU with IPv6 address\n"); + + memset(device_name, 0, size); + + nozzle = nozzle_open(device_name, size, NULL); + if (!nozzle) { + printf("Unable to init %s\n", device_name); + return -1; + } + + printf("Adding ip: %s/64\n", testipv6_1); + + err = nozzle_add_ip(nozzle, testipv6_1, "64"); + if (err) { + printf("Unable to assign IP address\n"); + err=-1; + goto out_clean; + } + + memset(verifycmd, 0, sizeof(verifycmd)); + snprintf(verifycmd, sizeof(verifycmd)-1, +#ifdef KNET_LINUX + "ip addr show dev %s | grep -q %s/64", nozzle->name, testipv6_1); +#endif +#ifdef KNET_BSD + "ifconfig %s | grep -q %s", nozzle->name, testipv6_1); +#endif + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (err) { + printf("Unable to verify IP address\n"); + err=-1; + goto out_clean; + } + + printf("Setting MTU to 1200\n"); + if (nozzle_set_mtu(nozzle, 1200) < 0) { + printf("Unable to set MTU to 1200\n"); + err = -1; + goto out_clean; + } + + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } +#ifdef KNET_LINUX + if (!err) { +#endif +#ifdef KNET_BSD + if (err) { +#endif + printf("Unable to verify IP address\n"); + err=-1; + goto out_clean; + } + + printf("Adding ip: %s/64\n", testipv6_2); + err = nozzle_add_ip(nozzle, testipv6_2, "64"); + if (err < 0) { + printf("Unable to assign IP address\n"); + err=-1; + goto out_clean; + } + + memset(verifycmd, 0, sizeof(verifycmd)); + snprintf(verifycmd, sizeof(verifycmd)-1, +#ifdef KNET_LINUX + "ip addr show dev %s | grep -q %s/64", nozzle->name, testipv6_2); +#endif +#ifdef KNET_BSD + "ifconfig %s | grep -q %s", nozzle->name, testipv6_2); +#endif + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (!err) { + printf("Unable to verify IP address\n"); + err=-1; + goto out_clean; + } + + printf("Restoring MTU to default\n"); + if (nozzle_reset_mtu(nozzle) < 0) { + printf("Unable to reset mtu\n"); + err = -1; + goto out_clean; + } + + current_mtu = nozzle_get_mtu(nozzle); + if (current_mtu != 1500) { + printf("current mtu [%d] does not match expected value [1500]\n", current_mtu); + err = -1; + goto out_clean; + } + + memset(verifycmd, 0, sizeof(verifycmd)); + snprintf(verifycmd, sizeof(verifycmd)-1, +#ifdef KNET_LINUX + "ip addr show dev %s | grep -q %s/64", nozzle->name, testipv6_1); +#endif +#ifdef KNET_BSD + "ifconfig %s | grep -q %s", nozzle->name, testipv6_1); +#endif + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (err) { + printf("Unable to verify IP address\n"); + err=-1; + goto out_clean; + } + + memset(verifycmd, 0, sizeof(verifycmd)); + snprintf(verifycmd, sizeof(verifycmd)-1, +#ifdef KNET_LINUX + "ip addr show dev %s | grep -q %s/64", nozzle->name, testipv6_2); +#endif +#ifdef KNET_BSD + "ifconfig %s | grep -q %s", nozzle->name, testipv6_2); +#endif + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (err) { + printf("Unable to verify IP address\n"); + err=-1; + goto out_clean; + } + +out_clean: + if (nozzle) { + nozzle_close(nozzle); + } + + return err; +} + +int main(void) +{ + need_root(); + + make_local_ips(testipv4_1, testipv4_2, testipv6_1, testipv6_2); + + if (test() < 0) + return FAIL; + + if (test_ipv6() < 0) + return FAIL; + + return PASS; +} diff --git a/libnozzle/tests/api_nozzle_set_up.c b/libnozzle/tests/api_nozzle_set_up.c new file mode 100644 index 00000000..687e6b6b --- /dev/null +++ b/libnozzle/tests/api_nozzle_set_up.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test-common.h" + +static int test(void) +{ + char verifycmd[1024]; + char device_name[IFNAMSIZ]; + size_t size = IFNAMSIZ; + int err=0; + nozzle_t nozzle; + char *error_string = NULL; + + printf("Testing interface up/down\n"); + + memset(device_name, 0, size); + nozzle = nozzle_open(device_name, size, NULL); + if (!nozzle) { + printf("Unable to init %s\n", device_name); + return -1; + } + + printf("Put the interface up\n"); + + if (nozzle_set_up(nozzle) < 0) { + printf("Unable to set interface up\n"); + err = -1; + goto out_clean; + } + + memset(verifycmd, 0, sizeof(verifycmd)); + snprintf(verifycmd, sizeof(verifycmd)-1, +#ifdef KNET_LINUX + "ip addr show dev %s | grep -q UP", nozzle->name); +#endif +#ifdef KNET_BSD + "ifconfig %s | grep -q UP", nozzle->name); +#endif + err = execute_bin_sh_command(verifycmd, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (err < 0) { + printf("Unable to verify inteface UP\n"); + err = -1; + goto out_clean; + } + + printf("Test ERROR conditions\n"); + + printf("Try to UP the same interface twice\n"); + if (nozzle_set_up(nozzle) < 0) { + printf("Interface was already UP, spurious error received from nozzle_set_up\n"); + err = -1; + goto out_clean; + } + + printf("Pass NULL to nozzle set_up\n"); + errno = 0; + if ((nozzle_set_up(NULL) >= 0) || (errno != EINVAL)) { + printf("Something is wrong in nozzle_set_up sanity checks\n"); + err = -1; + goto out_clean; + } + +out_clean: + nozzle_set_down(nozzle); + nozzle_close(nozzle); + + return err; +} + +int main(void) +{ + need_root(); + + if (test() < 0) + return FAIL; + + return PASS; +} diff --git a/libnozzle/tests/int_execute_bin_sh_command.c b/libnozzle/tests/int_execute_bin_sh_command.c new file mode 100644 index 00000000..a6a133ff --- /dev/null +++ b/libnozzle/tests/int_execute_bin_sh_command.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test-common.h" + +static int test(void) +{ + int err = 0; + char *error_string = NULL; + + printf("Testing execute_bin_sh_command\n"); + + printf("command true\n"); + + err = execute_bin_sh_command("true", &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (err) { + printf("Unable to execute true ?!?!\n"); + goto out_clean; + } + + printf("command false\n"); + + err = execute_bin_sh_command("false", &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (!err) { + printf("Can we really execute false successfully?!?!\n"); + err = -1; + goto out_clean; + } + + printf("command that outputs to stdout (enforcing redirect)\n"); + + err = execute_bin_sh_command("grep -h 2>&1", &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (!err) { + printf("Can we really execute grep -h successfully?!?\n"); + err = -1; + goto out_clean; + } + + printf("command that outputs to stderr\n"); + err = execute_bin_sh_command("grep -h", &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if (!err) { + printf("Can we really execute grep -h successfully?!?\n"); + err = -1; + goto out_clean; + } + + printf("Testing ERROR conditions\n"); + + printf("empty command\n"); + err = execute_bin_sh_command(NULL, &error_string); + if (error_string) { + printf("Error string: %s\n", error_string); + free(error_string); + error_string = NULL; + } + if ((!err) || (errno != EINVAL)) { + printf("execute_bin_sh_command returned incorrect error or incorrect errno!\n"); + err = -1; + goto out_clean; + } + + printf("empty error\n"); + err = execute_bin_sh_command("true", NULL); + if ((!err) || (errno != EINVAL)) { + printf("execute_bin_sh_command returned incorrect error or incorrect errno!\n"); + err = -1; + goto out_clean; + } + + err = 0; + +out_clean: + + return err; +} + +int main(void) +{ + need_root(); + + if (test() < 0) + return FAIL; + + return PASS; +} diff --git a/libtap/tap_updown_bad/down.d/kronostest b/libnozzle/tests/nozzle_run_updown_exit_false similarity index 100% rename from libtap/tap_updown_bad/down.d/kronostest rename to libnozzle/tests/nozzle_run_updown_exit_false diff --git a/libtap/tap_updown_good/down.d/kronostest b/libnozzle/tests/nozzle_run_updown_exit_true similarity index 100% rename from libtap/tap_updown_good/down.d/kronostest rename to libnozzle/tests/nozzle_run_updown_exit_true diff --git a/libnozzle/tests/test-common.c b/libnozzle/tests/test-common.c new file mode 100644 index 00000000..752f1707 --- /dev/null +++ b/libnozzle/tests/test-common.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. All rights reserved. + * + * Author: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test-common.h" + +void need_root(void) +{ + if (geteuid() != 0) { + printf("This test requires root privileges\n"); + exit(SKIP); + } +} + +int test_iface(char *name, size_t size, const char *updownpath) +{ + nozzle_t nozzle; + + nozzle=nozzle_open(name, size, updownpath); + if (!nozzle) { + printf("Unable to open nozzle.\n"); + return -1; + } + printf("Created interface: %s\n", name); + + if (is_if_in_system(name) > 0) { + printf("Found interface %s on the system\n", name); + } else { + printf("Unable to find interface %s on the system\n", name); + } + + if (!nozzle_get_handle_by_name(name)) { + printf("Unable to find interface %s in nozzle db\n", name); + } else { + printf("Found interface %s in nozzle db\n", name); + } + + nozzle_close(nozzle); + + if (is_if_in_system(name) == 0) + printf("Successfully removed interface %s from the system\n", name); + + return 0; +} + +int is_if_in_system(char *name) +{ + struct ifaddrs *ifap = NULL; + struct ifaddrs *ifa; + int found = 0; + + if (getifaddrs(&ifap) < 0) { + printf("Unable to get interface list.\n"); + return -1; + } + + ifa = ifap; + + while (ifa) { + if (!strncmp(name, ifa->ifa_name, IFNAMSIZ)) { + found = 1; + break; + } + ifa=ifa->ifa_next; + } + + freeifaddrs(ifap); + return found; +} + +int get_random_byte(void) +{ + pid_t mypid; + uint8_t *pid; + uint8_t randombyte = 0; + uint8_t i; + + if (sizeof(pid_t) < 4) { + printf("pid_t is smaller than 4 bytes?\n"); + exit(77); + } + + mypid = getpid(); + pid = (uint8_t *)&mypid; + + for (i = 0; i < sizeof(pid_t); i++) { + if (pid[i] == 0) { + pid[i] = 128; + } + } + + randombyte = pid[1]; + + return randombyte; +} + +void make_local_ips(char *testipv4_1, char *testipv4_2, char *testipv6_1, char *testipv6_2) +{ + pid_t mypid; + uint8_t *pid; + uint8_t i; + + memset(testipv4_1, 0, IPBUFSIZE); + memset(testipv4_2, 0, IPBUFSIZE); + memset(testipv6_1, 0, IPBUFSIZE); + memset(testipv6_2, 0, IPBUFSIZE); + + mypid = getpid(); + pid = (uint8_t *)&mypid; + + for (i = 0; i < sizeof(pid_t); i++) { + if (pid[i] == 0) { + pid[i] = 128; + } + } + + snprintf(testipv4_1, + IPBUFSIZE - 1, + "127.%u.%u.%u", + pid[1], + pid[2], + pid[0]); + + snprintf(testipv4_2, + IPBUFSIZE - 1, + "127.%u.%d.%u", + pid[1], + pid[2]+1, + pid[0]); + + snprintf(testipv6_1, + IPBUFSIZE - 1, + "fd%x:%x%x::1", + pid[1], + pid[2], + pid[0]); + + snprintf(testipv6_2, + IPBUFSIZE - 1, + "fd%x:%x%x:1::1", + pid[1], + pid[2], + pid[0]); +} diff --git a/libnozzle/tests/test-common.h b/libnozzle/tests/test-common.h new file mode 100644 index 00000000..0bfce530 --- /dev/null +++ b/libnozzle/tests/test-common.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 Red Hat, Inc. All rights reserved. + * + * Authors: Fabio M. Di Nitto + * + * This software licensed under GPL-2.0+, LGPL-2.0+ + */ + +#ifndef __NOZZLE_TEST_COMMON_H__ +#define __NOZZLE_TEST_COMMON_H__ + +#include "internals.h" +#include "libnozzle.h" + +/* + * error codes from automake test-driver + */ + +#define PASS 0 +#define SKIP 77 +#define ERROR 99 +#define FAIL -1 + +/* + * common facilities + */ + +#define IPBUFSIZE 1024 + +void need_root(void); +int test_iface(char *name, size_t size, const char *updownpath); +int is_if_in_system(char *name); +int get_random_byte(void); +void make_local_ips(char *testipv4_1, char *testipv4_2, char *testipv6_1, char *testipv6_2); + +#endif diff --git a/libtap/Makefile.am b/libtap/Makefile.am deleted file mode 100644 index 0690daea..00000000 --- a/libtap/Makefile.am +++ /dev/null @@ -1,60 +0,0 @@ -# -# Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. -# -# Author: Fabio M. Di Nitto -# -# This software licensed under GPL-2.0+, LGPL-2.0+ -# - -MAINTAINERCLEANFILES = Makefile.in - -include $(top_srcdir)/build-aux/check.mk - - -SYMFILE = libtap_exported_syms - -EXTRA_DIST = $(SYMFILE) tap_updown_bad tap_updown_good api-test-coverage - -sources = libtap.c - -libversion = 1:0:0 - -AM_CFLAGS += $(PTHREAD_CFLAGS) -LIBS = $(PTHREAD_LIBS) - -if BUILD_LIBTAP - -include_HEADERS = libtap.h - -pkgconfigdir = $(libdir)/pkgconfig - -pkgconfig_DATA = libtap.pc - -lib_LTLIBRARIES = libtap.la - -libtap_la_SOURCES = $(sources) - -EXTRA_libtap_la_DEPENDENCIES = $(SYMFILE) - -libtap_la_LDFLAGS = $(AM_LDFLAGS) \ - -Wl,-version-script,$(srcdir)/$(SYMFILE) \ - -version-info $(libversion) - -TESTS = $(check_PROGRAMS) - -noinst_PROGRAMS = $(check_PROGRAMS) - -check_PROGRAMS = tap_test - -check-local: check-api-test-coverage - -check-api-test-coverage: - chmod u+x $(top_srcdir)/libtap/api-test-coverage - $(top_srcdir)/libtap/api-test-coverage $(top_srcdir) $(top_builddir) - -tap_test_SOURCES = $(sources) - -tap_test_CPPFLAGS = -DTEST \ - -DABSBUILDDIR=\"$(abs_builddir)\" - -endif diff --git a/libtap/api-test-coverage b/libtap/api-test-coverage deleted file mode 100755 index e25cb2b0..00000000 --- a/libtap/api-test-coverage +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -# -# Copyright (C) 2016-2018 Red Hat, Inc. All rights reserved. -# -# Author: Fabio M. Di Nitto -# -# This software licensed under GPL-2.0+, LGPL-2.0+ -# - -srcdir="$1"/libtap -builddir="$2"/libtap - -headerapicalls="$(grep tap_ "$srcdir"/libtap.h | grep -v "^ \*" | grep -v ^struct | grep -v "^[[:space:]]" | grep -v typedef | sed -e 's/(.*//g' -e 's/^const //g' -e 's/\*//g' | awk '{print $2}')" - -exportedapicalls="$(nm -B -D "$builddir"/.libs/libtap.so | grep ' T ' | awk '{print $3}')" - -echo "Checking for exported symbols NOT available in header file" - -for i in $exportedapicalls; do - found=0 - for x in $headerapicalls; do - if [ "$x" = "$i" ]; then - found=1 - break; - fi - done - if [ "$found" = 0 ]; then - echo "Symbol $i not found in header file" - exit 1 - fi -done - -echo "Checking for symbols in header file NOT exported by binary lib" - -for i in $headerapicalls; do - found=0 - for x in $exportedapicalls; do - if [ "$x" = "$i" ]; then - found=1 - break; - fi - done - if [ "$found" = 0 ]; then - echo "Symbol $i not found in binary lib" - exit 1 - fi -done - -exit 0 diff --git a/libtap/libtap.c b/libtap/libtap.c deleted file mode 100644 index 060db012..00000000 --- a/libtap/libtap.c +++ /dev/null @@ -1,2125 +0,0 @@ -/* - * Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. - * - * Author: Fabio M. Di Nitto - * - * This software licensed under GPL-2.0+, LGPL-2.0+ - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libtap.h" - -#define MAX_IP_CHAR 128 -#define MAX_PREFIX_CHAR 4 -#define MAX_MAC_CHAR 18 - -struct _ip { - char ip_addr[MAX_IP_CHAR]; - char prefix[MAX_PREFIX_CHAR]; - int domain; - struct _ip *next; -}; - -struct _iface { - struct ifreq ifr; - int fd; - char tapname[IFNAMSIZ]; - char default_mac[MAX_MAC_CHAR]; - int default_mtu; - int current_mtu; - char updownpath[PATH_MAX - 11 - 1 - IFNAMSIZ]; /* 11 = post-down.d 1 = / */ - int hasupdown; - int up; - struct _ip *ip; - struct _iface *next; -}; -#define ifname ifr.ifr_name - -struct _config { - struct _iface *head; - int sockfd; -}; - -static int lib_init = 0; -static struct _config lib_cfg; -static pthread_mutex_t lib_mutex = PTHREAD_MUTEX_INITIALIZER; - -/* forward declarations */ -static int _execute_shell(const char *command, char **error_string); -static int _exec_updown(const tap_t tap, const char *action, char **error_string); -static int _read_pipe(int fd, char **file, size_t *length); -static int _check(const tap_t tap); -static void _close(tap_t tap); -static void _close_cfg(void); -static int _get_mtu(const tap_t tap); -static int _get_mac(const tap_t tap, char **ether_addr); -static int _set_down(tap_t tap, char **error_down, char **error_postdown); -static char *_get_v4_broadcast(const char *ip_addr, const char *prefix); -static int _set_ip(tap_t tap, const char *command, - const char *ip_addr, const char *prefix, - char **error_string); -static int _find_ip(tap_t tap, - const char *ip_addr, const char *prefix, - struct _ip **ip, struct _ip **ip_prev); - -static int _read_pipe(int fd, char **file, size_t *length) -{ - char buf[4096]; - int n; - int done = 0; - - *file = NULL; - *length = 0; - - memset(buf, 0, sizeof(buf)); - - while (!done) { - - n = read(fd, buf, sizeof(buf)); - - if (n < 0) { - if (errno == EINTR) - continue; - - if (*file) - free(*file); - - return n; - } - - if (n == 0 && (!*length)) - return 0; - - if (n == 0) - done = 1; - - if (*file) - *file = realloc(*file, (*length) + n + done); - else - *file = malloc(n + done); - - if (!*file) - return -1; - - memmove((*file) + (*length), buf, n); - *length += (done + n); - } - - /* Null terminator */ - (*file)[(*length) - 1] = 0; - - return 0; -} - -static int _execute_shell(const char *command, char **error_string) -{ - pid_t pid; - int status, err = 0; - int fd[2]; - size_t size = 0; - - if ((command == NULL) || (!error_string)) { - errno = EINVAL; - return -1; - } - - *error_string = NULL; - - err = pipe(fd); - if (err) - goto out_clean; - - pid = fork(); - if (pid < 0) { - err = pid; - goto out_clean; - } - - if (pid) { /* parent */ - - close(fd[1]); - err = _read_pipe(fd[0], error_string, &size); - if (err) - goto out_clean0; - - waitpid(pid, &status, 0); - if (!WIFEXITED(status)) { - err = -1; - goto out_clean0; - } - if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { - err = WEXITSTATUS(status); - goto out_clean0; - } - goto out_clean0; - } else { /* child */ - close(0); - close(1); - close(2); - - close(fd[0]); - dup2(fd[1], 1); - dup2(fd[1], 2); - close(fd[1]); - - execlp("/bin/sh", "/bin/sh", "-c", command, NULL); - exit(EXIT_FAILURE); - } - -out_clean: - close(fd[1]); -out_clean0: - close(fd[0]); - - return err; -} - -static int _exec_updown(const tap_t tap, const char *action, char **error_string) -{ - char command[PATH_MAX]; - struct stat sb; - int err = 0; - - if (!tap->hasupdown) - return 0; - - memset(command, 0, PATH_MAX); - - snprintf(command, PATH_MAX, "%s%s/%s", tap->updownpath, action, tap->tapname); - - err = stat(command, &sb); - if ((err < 0) && (errno == ENOENT)) - return 0; - - err = _execute_shell(command, error_string); - if ((!err) && (*error_string)) { - free(*error_string); - *error_string = NULL; - } - - return err; -} - -static int _check(const tap_t tap) -{ - tap_t temp = lib_cfg.head; - - if (!tap) { - return 0; - } - - while (temp != NULL) { - if (tap == temp) - return 1; - - temp = temp->next; - } - - return 0; -} - -static void _close(tap_t tap) -{ - if (!tap) - return; - - if (tap->fd) - close(tap->fd); - - free(tap); - - return; -} - -static void _close_cfg(void) -{ - if (lib_cfg.head == NULL) { - close(lib_cfg.sockfd); - lib_init = 0; - } -} - -static int _get_mtu(const tap_t tap) -{ - int err; - - memset(&tap->ifr, 0, sizeof(struct ifreq)); - strncpy(tap->ifname, tap->tapname, IFNAMSIZ); - - err = ioctl(lib_cfg.sockfd, SIOCGIFMTU, &tap->ifr); - if (err) - goto out_clean; - - err = tap->ifr.ifr_mtu; - -out_clean: - return err; -} - -static int _get_mac(const tap_t tap, char **ether_addr) -{ - int err; - char mac[MAX_MAC_CHAR]; - - memset(&tap->ifr, 0, sizeof(struct ifreq)); - strncpy(tap->ifname, tap->tapname, IFNAMSIZ); - - err = ioctl(lib_cfg.sockfd, SIOCGIFHWADDR, &tap->ifr); - if (err) - goto out_clean; - - ether_ntoa_r((struct ether_addr *)tap->ifr.ifr_hwaddr.sa_data, mac); - - *ether_addr = strdup(mac); - if (!*ether_addr) - err = -1; - -out_clean: - - return err; -} - -tap_t tap_find(char *dev, size_t dev_size) -{ - tap_t tap; - - if (dev == NULL) { - errno = EINVAL; - return NULL; - } - - if (dev_size < IFNAMSIZ) { - errno = EINVAL; - return NULL; - } - - if (strlen(dev) > IFNAMSIZ) { - errno = E2BIG; - return NULL; - } - - pthread_mutex_lock(&lib_mutex); - - tap = lib_cfg.head; - while (tap != NULL) { - if (!strcmp(dev, tap->tapname)) - break; - tap = tap->next; - } - - pthread_mutex_unlock(&lib_mutex); - return tap; -} - -tap_t tap_open(char *dev, size_t dev_size, const char *updownpath) -{ - tap_t tap; - char *temp_mac = NULL; - - if (dev == NULL) { - errno = EINVAL; - return NULL; - } - - if (dev_size < IFNAMSIZ) { - errno = EINVAL; - return NULL; - } - - if (strlen(dev) > IFNAMSIZ) { - errno = E2BIG; - return NULL; - } - - if (updownpath) { - /* only absolute paths */ - if (updownpath[0] != '/') { - errno = EINVAL; - return NULL; - } - /* 14: 2 for /, 1 for \0 + 11 (post-down.d) */ - if (strlen(updownpath) >= (PATH_MAX - (strlen(dev) + 14))) { - errno = E2BIG; - return NULL; - } - } - - pthread_mutex_lock(&lib_mutex); - - tap = malloc(sizeof(struct _iface)); - if (!tap) - return NULL; - - memset(tap, 0, sizeof(struct _iface)); - - if ((tap->fd = open("/dev/net/tun", O_RDWR)) < 0) - goto out_error; - - strncpy(tap->tapname, dev, IFNAMSIZ); - memset(&tap->ifr, 0, sizeof(struct ifreq)); - strncpy(tap->ifname, dev, IFNAMSIZ); - tap->ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - - if (ioctl(tap->fd, TUNSETIFF, &tap->ifr) < 0) - goto out_error; - - if ((strlen(dev) > 0) && (strcmp(dev, tap->ifname) != 0)) { - errno = EBUSY; - goto out_error; - } - - strcpy(dev, tap->ifname); - strcpy(tap->tapname, tap->ifname); - - if (!lib_init) { - lib_cfg.head = NULL; - lib_cfg.sockfd = socket(AF_INET, SOCK_STREAM, 0); - if (lib_cfg.sockfd < 0) - goto out_error; - lib_init = 1; - } - - memset(&tap->ifr, 0, sizeof(struct ifreq)); - strncpy(tap->ifname, tap->tapname, IFNAMSIZ); - if (ioctl(lib_cfg.sockfd, SIOGIFINDEX, &tap->ifr) < 0) - goto out_error; - - tap->default_mtu = _get_mtu(tap); - if (tap->default_mtu < 0) - goto out_error; - - if (_get_mac(tap, &temp_mac) < 0) - goto out_error; - - strncpy(tap->default_mac, temp_mac, 18); - free(temp_mac); - - if (updownpath) { - int len = strlen(updownpath); - - strcpy(tap->updownpath, updownpath); - if (tap->updownpath[len-1] != '/') { - tap->updownpath[len] = '/'; - } - tap->hasupdown = 1; - } - - tap->next = lib_cfg.head; - lib_cfg.head = tap; - - pthread_mutex_unlock(&lib_mutex); - return tap; - -out_error: - _close(tap); - _close_cfg(); - pthread_mutex_unlock(&lib_mutex); - return NULL; -} - -// TODO: consider better error report from here -int tap_close(tap_t tap) -{ - int err = 0; - tap_t temp = lib_cfg.head; - tap_t prev = lib_cfg.head; - struct _ip *ip, *ip_next; - char *error_string = NULL; - char *error_down = NULL, *error_postdown = NULL; - - pthread_mutex_lock(&lib_mutex); - - if (!_check(tap)) { - errno = EINVAL; - err = -1; - goto out_clean; - } - - while ((temp) && (temp != tap)) { - prev = temp; - temp = temp->next; - } - - if (tap == prev) { - lib_cfg.head = tap->next; - } else { - prev->next = tap->next; - } - - _set_down(tap, &error_down, &error_postdown); - if (error_down) - free(error_down); - if (error_postdown) - free(error_postdown); - - ip = tap->ip; - while (ip) { - ip_next = ip->next; - _set_ip(tap, "del", ip->ip_addr, ip->prefix, &error_string); - if (error_string) { - free(error_string); - error_string = NULL; - } - free(ip); - ip = ip_next; - } - - _close(tap); - _close_cfg(); - -out_clean: - pthread_mutex_unlock(&lib_mutex); - - return err; -} - -int tap_get_mtu(const tap_t tap) -{ - int err; - - pthread_mutex_lock(&lib_mutex); - - if (!_check(tap)) { - errno = EINVAL; - err = -1; - goto out_clean; - } - - err = _get_mtu(tap); - -out_clean: - pthread_mutex_unlock(&lib_mutex); - - return err; -} - -int tap_set_mtu(tap_t tap, const int mtu) -{ - struct _ip *tmp_ip; - char *error_string = NULL; - int err; - - pthread_mutex_lock(&lib_mutex); - - if (!_check(tap)) { - errno = EINVAL; - err = -1; - goto out_clean; - } - - err = tap->current_mtu = _get_mtu(tap); - if (err < 0) - goto out_clean; - - tap->ifr.ifr_mtu = mtu; - - err = ioctl(lib_cfg.sockfd, SIOCSIFMTU, &tap->ifr); - - if ((!err) && (tap->current_mtu < 1280) && (mtu >= 1280)) { - tmp_ip = tap->ip; - while(tmp_ip) { - if (tmp_ip->domain == AF_INET6) { - err = _set_ip(tap, "add", tmp_ip->ip_addr, tmp_ip->prefix, &error_string); - if (error_string) { - free(error_string); - error_string = NULL; - } - } - tmp_ip = tmp_ip->next; - } - } - -out_clean: - pthread_mutex_unlock(&lib_mutex); - - return err; -} - -int tap_reset_mtu(tap_t tap) -{ - return tap_set_mtu(tap, tap->default_mtu); -} - -int tap_get_mac(const tap_t tap, char **ether_addr) -{ - int err; - - pthread_mutex_lock(&lib_mutex); - - if ((!_check(tap)) || (!ether_addr)) { - errno = EINVAL; - err = -1; - goto out_clean; - } - - err = _get_mac(tap, ether_addr); - -out_clean: - pthread_mutex_unlock(&lib_mutex); - - return err; -} - -int tap_set_mac(tap_t tap, const char *ether_addr) -{ - int err; - - pthread_mutex_lock(&lib_mutex); - - if ((!_check(tap)) || (!ether_addr)) { - errno = EINVAL; - err = -1; - goto out_clean; - } - - memset(&tap->ifr, 0, sizeof(struct ifreq)); - strncpy(tap->ifname, tap->tapname, IFNAMSIZ); - err = ioctl(lib_cfg.sockfd, SIOCGIFHWADDR, &tap->ifr); - if (err) - goto out_clean; - - memmove(tap->ifr.ifr_hwaddr.sa_data, ether_aton(ether_addr), ETH_ALEN); - - err = ioctl(lib_cfg.sockfd, SIOCSIFHWADDR, &tap->ifr); - -out_clean: - pthread_mutex_unlock(&lib_mutex); - - return err; -} - -int tap_reset_mac(tap_t tap) -{ - return tap_set_mac(tap, tap->default_mac); -} - -int tap_set_up(tap_t tap, char **error_preup, char **error_up) -{ - int err = 0; - - pthread_mutex_lock(&lib_mutex); - - if (!_check(tap)) { - errno = EINVAL; - err = -1; - goto out_clean; - } - - if ((tap->hasupdown) && ((!error_preup) || (!error_up))) { - errno = EINVAL; - err = -1; - goto out_clean; - } - - if (tap->up) - goto out_clean; - - memset(&tap->ifr, 0, sizeof(struct ifreq)); - strncpy(tap->ifname, tap->tapname, IFNAMSIZ); - - err=ioctl(lib_cfg.sockfd, SIOCGIFFLAGS, &tap->ifr); - if (err) - goto out_clean; - - _exec_updown(tap, "pre-up.d", error_preup); - - tap->ifr.ifr_flags |= IFF_UP | IFF_RUNNING; - err=ioctl(lib_cfg.sockfd, SIOCSIFFLAGS, &tap->ifr); - - if (err) - goto out_clean; - - _exec_updown(tap, "up.d", error_up); - - tap->up = 1; -out_clean: - pthread_mutex_unlock(&lib_mutex); - - return err; -} - -static int _set_down(tap_t tap, char **error_down, char **error_postdown) -{ - int err = 0; - - if (!tap->up) - goto out_clean; - - memset(&tap->ifr, 0, sizeof(struct ifreq)); - strncpy(tap->ifname, tap->tapname, IFNAMSIZ); - - err=ioctl(lib_cfg.sockfd, SIOCGIFFLAGS, &tap->ifr); - if (err) - goto out_clean; - - _exec_updown(tap, "down.d", error_down); - - tap->ifr.ifr_flags &= ~IFF_UP; - err=ioctl(lib_cfg.sockfd, SIOCSIFFLAGS, &tap->ifr); - - if (err) - goto out_clean; - - _exec_updown(tap, "post-down.d", error_postdown); - - tap->up = 0; - -out_clean: - return err; -} - -int tap_set_down(tap_t tap, char **error_down, char **error_postdown) -{ - int err = 0; - - pthread_mutex_lock(&lib_mutex); - - if (!_check(tap)) { - errno = EINVAL; - err = -1; - goto out_clean; - } - - if ((tap->hasupdown) && ((!error_down) || (!error_postdown))) { - errno = EINVAL; - err = -1; - goto out_clean; - } - - err = _set_down(tap, error_down, error_postdown); - -out_clean: - pthread_mutex_unlock(&lib_mutex); - - return err; -} - -static char *_get_v4_broadcast(const char *ip_addr, const char *prefix) -{ - int prefix_len; - struct in_addr mask; - struct in_addr broadcast; - struct in_addr address; - - prefix_len = atoi(prefix); - - if ((prefix_len > 32) || (prefix_len < 0)) - return NULL; - - if (inet_pton(AF_INET, ip_addr, &address) <= 0) - return NULL; - - mask.s_addr = htonl(~((1 << (32 - prefix_len)) - 1)); - - memset(&broadcast, 0, sizeof(broadcast)); - broadcast.s_addr = (address.s_addr & mask.s_addr) | ~mask.s_addr; - - return strdup(inet_ntoa(broadcast)); -} - -static int _set_ip(tap_t tap, const char *command, - const char *ip_addr, const char *prefix, - char **error_string) -{ - char *broadcast = NULL; - char cmdline[4096]; - - if (!strchr(ip_addr, ':')) { - broadcast = _get_v4_broadcast(ip_addr, prefix); - if (!broadcast) { - errno = EINVAL; - return -1; - } - } - - memset(cmdline, 0, sizeof(cmdline)); - - if (broadcast) { - snprintf(cmdline, sizeof(cmdline)-1, - "ip addr %s %s/%s dev %s broadcast %s", - command, ip_addr, prefix, - tap->tapname, broadcast); - free(broadcast); - } else { - snprintf(cmdline, sizeof(cmdline)-1, - "ip addr %s %s/%s dev %s", - command, ip_addr, prefix, - tap->tapname); - } - - return _execute_shell(cmdline, error_string); -} - -static int _find_ip(tap_t tap, - const char *ip_addr, const char *prefix, - struct _ip **ip, struct _ip **ip_prev) -{ - struct _ip *local_ip, *local_ip_prev; - int found = 0; - - local_ip = local_ip_prev = tap->ip; - - while(local_ip) { - if ((!strcmp(local_ip->ip_addr, ip_addr)) && (!strcmp(local_ip->prefix, prefix))) { - found = 1; - break; - } - local_ip_prev = local_ip; - local_ip = local_ip->next; - } - - if (found) { - *ip = local_ip; - *ip_prev = local_ip_prev; - } - - return found; -} - -int tap_add_ip(tap_t tap, const char *ip_addr, const char *prefix, char **error_string) -{ - int err = 0, found; - struct _ip *ip = NULL, *ip_prev = NULL, *ip_last = NULL; - - pthread_mutex_lock(&lib_mutex); - - if ((!_check(tap)) || (!ip_addr) || (!prefix) || (!error_string)) { - errno = EINVAL; - err = -1; - goto out_clean; - } - - found = _find_ip(tap, ip_addr, prefix, &ip, &ip_prev); - if (found) - goto out_clean; - - ip = malloc(sizeof(struct _ip)); - if (!ip) { - err = -1 ; - goto out_clean; - } - memset(ip, 0, sizeof(struct _ip)); - strncpy(ip->ip_addr, ip_addr, MAX_IP_CHAR); - strncpy(ip->prefix, prefix, MAX_PREFIX_CHAR); - if (!strchr(ip->ip_addr, ':')) { - ip->domain = AF_INET; - } else { - ip->domain = AF_INET6; - } - - /* - * if user asks for an IPv6 address, but MTU < 1280 - * store the IP and bring it up later if and when MTU > 1280 - */ - if ((ip->domain == AF_INET6) && (_get_mtu(tap) < 1280)) { - err = 0; - } else { - err = _set_ip(tap, "add", ip_addr, prefix, error_string); - } - - if (err) { - free(ip); - goto out_clean; - } - - if (tap->ip) { - ip_last = tap->ip; - while (ip_last->next != NULL) { - ip_last = ip_last->next; - } - ip_last->next = ip; - } else { - tap->ip = ip; - } - -out_clean: - pthread_mutex_unlock(&lib_mutex); - - return err; -} - -int tap_del_ip(tap_t tap, const char *ip_addr, const char *prefix, char **error_string) -{ - int err = 0, found; - struct _ip *ip = NULL, *ip_prev = NULL; - - pthread_mutex_lock(&lib_mutex); - - if ((!_check(tap)) || (!ip_addr) || (!prefix) || (!error_string)) { - errno = EINVAL; - err = -1; - goto out_clean; - } - - found = _find_ip(tap, ip_addr, prefix, &ip, &ip_prev); - if (!found) - goto out_clean; - - err = _set_ip(tap, "del", ip_addr, prefix, error_string); - - if (!err) { - if (ip == ip_prev) { - tap->ip = ip->next; - } else { - ip_prev->next = ip->next; - } - free(ip); - } - -out_clean: - pthread_mutex_unlock(&lib_mutex); - - return err; -} - -int tap_get_fd(const tap_t tap) -{ - int fd; - - pthread_mutex_lock(&lib_mutex); - - if (!_check(tap)) { - errno = EINVAL; - fd = -1; - goto out_clean; - } - - fd = tap->fd; - -out_clean: - pthread_mutex_unlock(&lib_mutex); - - return fd; -} - -const char *tap_get_name(const tap_t tap) -{ - char *name = NULL; - - pthread_mutex_lock(&lib_mutex); - - if (!_check(tap)) { - errno = EINVAL; - goto out_clean; - } - - name = tap->tapname; - -out_clean: - pthread_mutex_unlock(&lib_mutex); - - return name; -} - -int tap_get_ips(const tap_t tap, char **ip_addr_list, int *entries) -{ - int err = 0; - int found = 0; - char *ip_list = NULL; - int size = 0, offset = 0, len; - struct _ip *ip = tap->ip; - - pthread_mutex_lock(&lib_mutex); - - while (ip) { - found++; - ip = ip->next; - } - - size = found * (MAX_IP_CHAR + MAX_PREFIX_CHAR + 2); - ip_list = malloc(size); - if (!ip_list) { - err = -1; - goto out_clean; - } - - memset(ip_list, 0, size); - - ip = tap->ip; - - while (ip) { - len = strlen(ip->ip_addr); - memmove(ip_list + offset, ip->ip_addr, len); - offset = offset + len + 1; - len = strlen(ip->prefix); - memmove(ip_list + offset, ip->prefix, len); - offset = offset + len + 1; - ip = ip->next; - } - - *ip_addr_list = ip_list; - *entries = found; - -out_clean: - pthread_mutex_unlock(&lib_mutex); - - return err; -} - -#ifdef TEST -static int is_if_in_system(char *name) -{ - struct ifaddrs *ifap = NULL; - struct ifaddrs *ifa; - int found = 0; - - if (getifaddrs(&ifap) < 0) { - printf("Unable to get interface list.\n"); - return -1; - } - - ifa = ifap; - - while (ifa) { - if (!strncmp(name, ifa->ifa_name, IFNAMSIZ)) { - found = 1; - break; - } - ifa=ifa->ifa_next; - } - - freeifaddrs(ifap); - return found; -} - -static int test_iface(char *name, size_t size, const char *updownpath) -{ - tap_t tap; - - tap=tap_open(name, size, updownpath); - if (!tap) { - if (lib_cfg.sockfd < 0) - printf("Unable to open knet_socket\n"); - printf("Unable to open knet.\n"); - return -1; - } - printf("Created interface: %s\n", name); - - if (is_if_in_system(name) > 0) { - printf("Found interface %s on the system\n", name); - } else { - printf("Unable to find interface %s on the system\n", name); - } - - if (!tap_find(name, size)) { - printf("Unable to find interface %s in tap db\n", name); - } else { - printf("Found interface %s in tap db\n", name); - } - - tap_close(tap); - - if (is_if_in_system(name) == 0) - printf("Successfully removed interface %s from the system\n", name); - - return 0; -} - -static int check_tap_open_close(void) -{ - char device_name[2*IFNAMSIZ]; - char fakepath[PATH_MAX]; - size_t size = IFNAMSIZ; - - memset(device_name, 0, sizeof(device_name)); - - printf("Creating random tap interface:\n"); - if (test_iface(device_name, size, NULL) < 0) { - printf("Unable to create random interface\n"); - return -1; - } - - printf("Creating kronostest tap interface:\n"); - strncpy(device_name, "kronostest", IFNAMSIZ); - if (test_iface(device_name, size, NULL) < 0) { - printf("Unable to create kronosnet interface\n"); - return -1; - } - - printf("Testing ERROR conditions\n"); - - printf("Testing dev == NULL\n"); - errno=0; - if ((test_iface(NULL, size, NULL) >= 0) || (errno != EINVAL)) { - printf("Something is wrong in tap_open sanity checks\n"); - return -1; - } - - printf("Testing size < IFNAMSIZ\n"); - errno=0; - if ((test_iface(device_name, 1, NULL) >= 0) || (errno != EINVAL)) { - printf("Something is wrong in tap_open sanity checks\n"); - return -1; - } - - printf("Testing device_name size > IFNAMSIZ\n"); - errno=0; - strcpy(device_name, "abcdefghilmnopqrstuvwz"); - if ((test_iface(device_name, IFNAMSIZ, NULL) >= 0) || (errno != E2BIG)) { - printf("Something is wrong in tap_open sanity checks\n"); - return -1; - } - - printf("Testing updown path != abs\n"); - errno=0; - strcpy(device_name, "kronostest"); - if ((test_iface(device_name, IFNAMSIZ, "foo") >= 0) || (errno != EINVAL)) { - printf("Something is wrong in tap_open sanity checks\n"); - return -1; - } - - memset(fakepath, 0, PATH_MAX); - memset(fakepath, '/', PATH_MAX - 2); - - printf("Testing updown path > PATH_MAX\n"); - errno=0; - strcpy(device_name, "kronostest"); - if ((test_iface(device_name, IFNAMSIZ, fakepath) >= 0) || (errno != E2BIG)) { - printf("Something is wrong in tap_open sanity checks\n"); - return -1; - } - - return 0; -} - -static int check_knet_multi_eth(void) -{ - char device_name1[IFNAMSIZ]; - char device_name2[IFNAMSIZ]; - size_t size = IFNAMSIZ; - int err=0; - tap_t tap1 = NULL; - tap_t tap2 = NULL; - - printf("Testing multiple knet interface instances\n"); - - memset(device_name1, 0, size); - memset(device_name2, 0, size); - - strncpy(device_name1, "kronostest1", size); - strncpy(device_name2, "kronostest2", size); - - tap1 = tap_open(device_name1, size, NULL); - if (!tap1) { - printf("Unable to init %s\n", device_name1); - err = -1; - goto out_clean; - } - - if (is_if_in_system(device_name1) > 0) { - printf("Found interface %s on the system\n", device_name1); - } else { - printf("Unable to find interface %s on the system\n", device_name1); - } - - tap2 = tap_open(device_name2, size, NULL); - if (!tap2) { - printf("Unable to init %s\n", device_name2); - err = -1; - goto out_clean; - } - - if (is_if_in_system(device_name2) > 0) { - printf("Found interface %s on the system\n", device_name2); - } else { - printf("Unable to find interface %s on the system\n", device_name2); - } - - if (tap1) - tap_close(tap1); - if (tap2) - tap_close(tap2); - - printf("Testing error conditions\n"); - - printf("Open same device twice\n"); - - tap1 = tap_open(device_name1, size, NULL); - if (!tap1) { - printf("Unable to init %s\n", device_name1); - err = -1; - goto out_clean; - } - - if (is_if_in_system(device_name1) > 0) { - printf("Found interface %s on the system\n", device_name1); - } else { - printf("Unable to find interface %s on the system\n", device_name1); - } - - tap2 = tap_open(device_name1, size, NULL); - if (tap2) { - printf("We were able to init 2 interfaces with the same name!\n"); - err = -1; - goto out_clean; - } - -out_clean: - if (tap1) - tap_close(tap1); - if (tap2) - tap_close(tap2); - return err; -} - -static int check_knet_mtu(void) -{ - char device_name[IFNAMSIZ]; - size_t size = IFNAMSIZ; - int err=0; - tap_t tap; - - int current_mtu = 0; - int expected_mtu = 1500; - - printf("Testing get/set MTU\n"); - - memset(device_name, 0, size); - strncpy(device_name, "kronostest", size); - tap = tap_open(device_name, size, NULL); - if (!tap) { - printf("Unable to init %s\n", device_name); - return -1; - } - - printf("Comparing default MTU\n"); - current_mtu = tap_get_mtu(tap); - if (current_mtu < 0) { - printf("Unable to get MTU\n"); - err = -1; - goto out_clean; - } - if (current_mtu != expected_mtu) { - printf("current mtu [%d] does not match expected default [%d]\n", current_mtu, expected_mtu); - err = -1; - goto out_clean; - } - - printf("Setting MTU to 9000\n"); - expected_mtu = 9000; - if (tap_set_mtu(tap, expected_mtu) < 0) { - printf("Unable to set MTU to %d\n", expected_mtu); - err = -1; - goto out_clean; - } - - current_mtu = tap_get_mtu(tap); - if (current_mtu < 0) { - printf("Unable to get MTU\n"); - err = -1; - goto out_clean; - } - if (current_mtu != expected_mtu) { - printf("current mtu [%d] does not match expected value [%d]\n", current_mtu, expected_mtu); - err = -1; - goto out_clean; - } - - printf("Testing ERROR conditions\n"); - - printf("Passing empty struct to get_mtu\n"); - if (tap_get_mtu(NULL) > 0) { - printf("Something is wrong in tap_get_mtu sanity checks\n"); - err = -1; - goto out_clean; - } - - printf("Passing empty struct to set_mtu\n"); - if (tap_set_mtu(NULL, 1500) == 0) { - printf("Something is wrong in tap_set_mtu sanity checks\n"); - err = -1; - goto out_clean; - } - -out_clean: - tap_close(tap); - - return err; -} - -static int check_knet_mtu_ipv6(void) -{ - char device_name[IFNAMSIZ]; - size_t size = IFNAMSIZ; - int err=0; - tap_t tap; - char *error_string = NULL; - - printf("Testing get/set MTU with IPv6 address\n"); - - memset(device_name, 0, size); - strncpy(device_name, "kronostest", size); - tap = tap_open(device_name, size, NULL); - if (!tap) { - printf("Unable to init %s\n", device_name); - return -1; - } - - printf("Adding ip: 3ffe::1/64\n"); - - err = tap_add_ip(tap, "3ffe::1", "64", &error_string); - if (error_string) { - printf("add ipv6 output: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err < 0) { - printf("Unable to assign IP address\n"); - err=-1; - goto out_clean; - } - - err = _execute_shell("ip addr show dev kronostest | grep -q 3ffe::1/64", &error_string); - if (error_string) { - printf("Error string: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err) { - printf("Unable to verify IP address\n"); - err=-1; - goto out_clean; - } - - printf("Setting MTU to 1200\n"); - if (tap_set_mtu(tap, 1200) < 0) { - printf("Unable to set MTU to 1200\n"); - err = -1; - goto out_clean; - } - - err = _execute_shell("ip addr show dev kronostest | grep -q 3ffe::1/64", &error_string); - if (error_string) { - printf("Error string: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (!err) { - printf("Unable to verify IP address\n"); - err=-1; - goto out_clean; - } - - printf("Adding ip: 3ffe::2/64\n"); - err = tap_add_ip(tap, "3ffe::2", "64", &error_string); - if (error_string) { - printf("add ipv6 output: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err < 0) { - printf("Unable to assign IP address\n"); - err=-1; - goto out_clean; - } - - err = _execute_shell("ip addr show dev kronostest | grep -q 3ffe::2/64", &error_string); - if (error_string) { - printf("Error string: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (!err) { - printf("Unable to verify IP address\n"); - err=-1; - goto out_clean; - } - - printf("Restoring MTU to default\n"); - if (tap_reset_mtu(tap) < 0) { - printf("Unable to reset mtu\n"); - err = -1; - goto out_clean; - } - - err = _execute_shell("ip addr show dev kronostest | grep -q 3ffe::1/64", &error_string); - if (error_string) { - printf("Error string: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err) { - printf("Unable to verify IP address\n"); - err=-1; - goto out_clean; - } - - err = _execute_shell("ip addr show dev kronostest | grep -q 3ffe::2/64", &error_string); - if (error_string) { - printf("Error string: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err) { - printf("Unable to verify IP address\n"); - err=-1; - goto out_clean; - } - -out_clean: - tap_close(tap); - - return err; -} - -static int check_knet_mac(void) -{ - char device_name[IFNAMSIZ]; - size_t size = IFNAMSIZ; - int err=0; - tap_t tap; - char *current_mac = NULL, *temp_mac = NULL, *err_mac = NULL; - struct ether_addr *cur_mac, *tmp_mac; - - printf("Testing get/set MAC\n"); - - memset(device_name, 0, size); - strncpy(device_name, "kronostest", size); - tap = tap_open(device_name, size, NULL); - if (!tap) { - printf("Unable to init %s\n", device_name); - return -1; - } - - printf("Get current MAC\n"); - - if (tap_get_mac(tap, ¤t_mac) < 0) { - printf("Unable to get current MAC address.\n"); - err = -1; - goto out_clean; - } - - printf("Current MAC: %s\n", current_mac); - - printf("Setting MAC: 00:01:01:01:01:01\n"); - - if (tap_set_mac(tap, "00:01:01:01:01:01") < 0) { - printf("Unable to set current MAC address.\n"); - err = -1; - goto out_clean; - } - - if (tap_get_mac(tap, &temp_mac) < 0) { - printf("Unable to get current MAC address.\n"); - err = -1; - goto out_clean; - } - - printf("Current MAC: %s\n", temp_mac); - - cur_mac = ether_aton(current_mac); - tmp_mac = ether_aton(temp_mac); - - printf("Comparing MAC addresses\n"); - if (memcmp(cur_mac, tmp_mac, sizeof(struct ether_addr))) { - printf("Mac addresses are not the same?!\n"); - err = -1; - goto out_clean; - } - - printf("Testing ERROR conditions\n"); - - printf("Pass NULL to get_mac (pass1)\n"); - errno = 0; - if ((tap_get_mac(NULL, &err_mac) >= 0) || (errno != EINVAL)) { - printf("Something is wrong in tap_get_mac sanity checks\n"); - err = -1; - goto out_clean; - } - - printf("Pass NULL to get_mac (pass2)\n"); - errno = 0; - if ((tap_get_mac(tap, NULL) >= 0) || (errno != EINVAL)) { - printf("Something is wrong in tap_get_mac sanity checks\n"); - err = -1; - goto out_clean; - } - - printf("Pass NULL to set_mac (pass1)\n"); - errno = 0; - if ((tap_set_mac(tap, NULL) >= 0) || (errno != EINVAL)) { - printf("Something is wrong in tap_set_mac sanity checks\n"); - err = -1; - goto out_clean; - } - - printf("Pass NULL to set_mac (pass2)\n"); - errno = 0; - if ((tap_set_mac(NULL, err_mac) >= 0) || (errno != EINVAL)) { - printf("Something is wrong in tap_set_mac sanity checks\n"); - err = -1; - goto out_clean; - } - -out_clean: - if (err_mac) { - printf("Something managed to set err_mac!\n"); - err = -1; - free(err_mac); - } - - if (current_mac) - free(current_mac); - if (temp_mac) - free(temp_mac); - - tap_close(tap); - - return err; -} - -static int check_tap_execute_shell(void) -{ - int err = 0; - char command[4096]; - char *error_string = NULL; - - memset(command, 0, sizeof(command)); - - printf("Testing _execute_shell\n"); - - printf("command /bin/true\n"); - - err = _execute_shell("/bin/true", &error_string); - if (error_string) { - printf("Error string: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err < 0) { - printf("Unable to execute /bin/true ?!?!\n"); - goto out_clean; - } - - printf("Testing ERROR conditions\n"); - - printf("command /bin/false\n"); - - err = _execute_shell("/bin/false", &error_string); - if (error_string) { - printf("Error string: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (!err) { - printf("Can we really execute /bin/false successfully?!?!\n"); - err = -1; - goto out_clean; - } - - printf("command that outputs to stdout (enforcing redirect)\n"); - - err = _execute_shell("/bin/grep -h 2>&1", &error_string); - if (error_string) { - printf("Error string: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (!err) { - printf("Can we really execute /bin/grep -h successfully?!?\n"); - err = -1; - goto out_clean; - } - - printf("command that outputs to stderr\n"); - err = _execute_shell("/bin/grep -h", &error_string); - if (error_string) { - printf("Error string: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (!err) { - printf("Can we really execute /bin/grep -h successfully?!?\n"); - err = -1; - goto out_clean; - } - - printf("empty command\n"); - err = _execute_shell(NULL, &error_string); - if (error_string) { - printf("Error string: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (!err) { - printf("Can we really execute (nil) successfully?!?!\n"); - err = -1; - goto out_clean; - } - - printf("empty error\n"); - err = _execute_shell("/bin/true", NULL); - if (!err) { - printf("Check EINVAL filter for no error_string!\n"); - err = -1; - goto out_clean; - } - - err = 0; - -out_clean: - - return err; -} - -static int check_knet_up_down(void) -{ - char device_name[IFNAMSIZ]; - size_t size = IFNAMSIZ; - int err=0; - tap_t tap; - char *error_string = NULL; - char *error_preup = NULL, *error_up = NULL; - char *error_down = NULL, *error_postdown = NULL; - - printf("Testing interface up/down\n"); - - memset(device_name, 0, size); - strncpy(device_name, "kronostest", size); - tap = tap_open(device_name, size, NULL); - if (!tap) { - printf("Unable to init %s\n", device_name); - return -1; - } - - printf("Put the interface up\n"); - - err = tap_set_up(tap, &error_preup, &error_up); - if (error_preup) { - printf("preup output: %s\n", error_preup); - free(error_preup); - error_preup = NULL; - } - if (error_up) { - printf("up output: %s\n", error_up); - free(error_up); - error_up = NULL; - } - if (err < 0) { - printf("Unable to set interface up\n"); - err = -1; - goto out_clean; - } - - - err = _execute_shell("ip addr show dev kronostest | grep -q UP", &error_string); - if (error_string) { - printf("Error string: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err < 0) { - printf("Unable to verify inteface UP\n"); - err = -1; - goto out_clean; - } - - printf("Put the interface down\n"); - - err = tap_set_down(tap, &error_down, &error_postdown); - if (error_down) { - printf("down output: %s\n", error_down); - free(error_down); - error_down = NULL; - } - if (error_postdown) { - printf("postdown output: %s\n", error_down); - free(error_down); - error_down = NULL; - } - if (err < 0) { - printf("Unable to put the interface down\n"); - err = -1; - goto out_clean; - } - - err = _execute_shell("ifconfig kronostest | grep -q UP", &error_string); - if (error_string) { - printf("Error string: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (!err) { - printf("Unable to verify inteface DOWN\n"); - err = -1; - goto out_clean; - } - - tap_close(tap); - - printf("Testing interface pre-up/up/down/post-down (exec errors)\n"); - - tap = tap_open(device_name, size, ABSBUILDDIR "/tap_updown_bad"); - if (!tap) { - printf("Unable to init %s\n", device_name); - return -1; - } - - printf("Put the interface up\n"); - - err = tap_set_up(tap, &error_preup, &error_up); - if (error_preup) { - printf("preup output: %s\n", error_preup); - free(error_preup); - error_preup = NULL; - } - if (error_up) { - printf("up output: %s\n", error_up); - free(error_up); - error_up = NULL; - } - if (err < 0) { - printf("Unable to set interface up\n"); - err = -1; - goto out_clean; - } - - printf("Put the interface down\n"); - - err = tap_set_down(tap, &error_down, &error_postdown); - if (error_down) { - printf("down output: %s\n", error_down); - free(error_down); - error_down = NULL; - } - if (error_postdown) { - printf("postdown output: %s\n", error_down); - free(error_down); - error_down = NULL; - } - if (err < 0) { - printf("Unable to put the interface down\n"); - err = -1; - goto out_clean; - } - - tap_close(tap); - - printf("Testing interface pre-up/up/down/post-down\n"); - - tap = tap_open(device_name, size, ABSBUILDDIR "/tap_updown_good"); - if (!tap) { - printf("Unable to init %s\n", device_name); - return -1; - } - - printf("Put the interface up\n"); - - err = tap_set_up(tap, &error_preup, &error_up); - if (error_preup) { - printf("preup output: %s\n", error_preup); - free(error_preup); - error_preup = NULL; - } - if (error_up) { - printf("up output: %s\n", error_up); - free(error_up); - error_up = NULL; - } - if (err < 0) { - printf("Unable to set interface up\n"); - err = -1; - goto out_clean; - } - - printf("Put the interface down\n"); - - err = tap_set_down(tap, &error_down, &error_postdown); - if (error_down) { - printf("down output: %s\n", error_down); - free(error_down); - error_down = NULL; - } - if (error_postdown) { - printf("postdown output: %s\n", error_down); - free(error_down); - error_down = NULL; - } - if (err < 0) { - printf("Unable to put the interface down\n"); - err = -1; - goto out_clean; - } - - tap_close(tap); - - printf("Test ERROR conditions\n"); - - printf("Pass NULL to tap set_up\n"); - errno = 0; - if ((tap_set_up(NULL, &error_preup, &error_up) >= 0) || (errno != EINVAL)) { - printf("Something is wrong in tap_set_up sanity checks\n"); - err = -1; - goto out_clean; - } - - printf("Pass NULL to error_preup set_up\n"); - errno = 0; - if ((tap_set_up(tap, NULL, &error_up) >= 0) || (errno != EINVAL)) { - printf("Something is wrong in tap_set_up sanity checks\n"); - err = -1; - goto out_clean; - } - - printf("Pass NULL to error_up set_up\n"); - errno = 0; - if ((tap_set_up(tap, &error_preup, NULL) >= 0) || (errno != EINVAL)) { - printf("Something is wrong in tap_set_up sanity checks\n"); - err = -1; - goto out_clean; - } - - printf("Pass NULL to tap set_down\n"); - errno = 0; - if ((tap_set_down(NULL, &error_down, &error_postdown) >= 0) || (errno != EINVAL)) { - printf("Something is wrong in tap_set_down sanity checks\n"); - err = -1; - goto out_clean; - } - - printf("Pass NULL to error_down set_down\n"); - errno = 0; - if ((tap_set_down(tap, NULL, &error_postdown) >= 0) || (errno != EINVAL)) { - printf("Something is wrong in tap_set_down sanity checks\n"); - err = -1; - goto out_clean; - } - - printf("Pass NULL to error_postdown set_down\n"); - errno = 0; - if ((tap_set_down(tap, &error_down, NULL) >= 0) || (errno != EINVAL)) { - printf("Something is wrong in tap_set_down sanity checks\n"); - err = -1; - goto out_clean; - } - -out_clean: - - tap_close(tap); - - return err; -} - -static int check_knet_close_leak(void) -{ - char device_name[IFNAMSIZ]; - size_t size = IFNAMSIZ; - int err=0; - tap_t tap; - char *error_string = NULL; - - printf("Testing close leak (needs valgrind)\n"); - - memset(device_name, 0, size); - strncpy(device_name, "kronostest", size); - tap = tap_open(device_name, size, NULL); - if (!tap) { - printf("Unable to init %s\n", device_name); - return -1; - } - - printf("Adding ip: 192.168.168.168/24\n"); - - err = tap_add_ip(tap, "192.168.168.168", "24", &error_string); - if (error_string) { - printf("add ip output: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err < 0) { - printf("Unable to assign IP address\n"); - err=-1; - goto out_clean; - } - - printf("Adding ip: 192.168.169.169/24\n"); - - err = tap_add_ip(tap, "192.168.169.169", "24", &error_string); - if (error_string) { - printf("add ip output: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err < 0) { - printf("Unable to assign IP address\n"); - err=-1; - goto out_clean; - } - -out_clean: - - tap_close(tap); - - return err; -} - -static int check_knet_set_del_ip(void) -{ - char device_name[IFNAMSIZ]; - size_t size = IFNAMSIZ; - int err=0; - tap_t tap; - char *ip_list = NULL; - int ip_list_entries = 0, i, offset = 0; - char *error_string = NULL; - - printf("Testing interface add/remove ip\n"); - - memset(device_name, 0, size); - strncpy(device_name, "kronostest", size); - tap = tap_open(device_name, size, NULL); - if (!tap) { - printf("Unable to init %s\n", device_name); - return -1; - } - - printf("Adding ip: 192.168.168.168/24\n"); - - err = tap_add_ip(tap, "192.168.168.168", "24", &error_string); - if (error_string) { - printf("add ip output: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err < 0) { - printf("Unable to assign IP address\n"); - err=-1; - goto out_clean; - } - - printf("Adding ip: 192.168.169.169/24\n"); - - err = tap_add_ip(tap, "192.168.169.169", "24", &error_string); - if (error_string) { - printf("add ip output: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err < 0) { - printf("Unable to assign IP address\n"); - err=-1; - goto out_clean; - } - - printf("Adding duplicate ip: 192.168.168.168/24\n"); - - err = tap_add_ip(tap, "192.168.168.168", "24", &error_string); - if (error_string) { - printf("add ip output: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err < 0) { - printf("Unable to find IP address in libtap db\n"); - err=-1; - goto out_clean; - } - - printf("Checking ip: 192.168.168.168/24\n"); - - err = _execute_shell("ip addr show dev kronostest | grep -q 192.168.168.168/24", &error_string); - if (error_string) { - printf("Error string: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err) { - printf("Unable to verify IP address\n"); - err=-1; - goto out_clean; - } - - printf("Get ip list from libtap:\n"); - - if (tap_get_ips(tap, &ip_list, &ip_list_entries) < 0) { - printf("Not enough mem?\n"); - err=-1; - goto out_clean; - } - - if (ip_list_entries != 2) { - printf("Didn't get enough ip back from libtap?\n"); - err=-1; - goto out_clean; - } - - for (i = 1; i <= ip_list_entries; i++) { - printf("Found IP %s %s in libtap db\n", ip_list + offset, ip_list + offset + strlen(ip_list + offset) + 1); - offset = offset + strlen(ip_list) + 1; - offset = offset + strlen(ip_list + offset) + 1; - } - - free(ip_list); - - printf("Deleting ip: 192.168.168.168/24\n"); - - err = tap_del_ip(tap, "192.168.168.168", "24", &error_string); - if (error_string) { - printf("del ip output: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err < 0) { - printf("Unable to delete IP address\n"); - err=-1; - goto out_clean; - } - - printf("Deleting ip: 192.168.169.169/24\n"); - - err = tap_del_ip(tap, "192.168.169.169", "24", &error_string); - if (error_string) { - printf("del ip output: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err < 0) { - printf("Unable to delete IP address\n"); - err=-1; - goto out_clean; - } - - printf("Deleting again ip: 192.168.168.168/24\n"); - - err = tap_del_ip(tap, "192.168.168.168", "24", &error_string); - if (error_string) { - printf("del ip output: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err < 0) { - printf("Unable to delete IP address\n"); - err=-1; - goto out_clean; - } - - err = _execute_shell("ip addr show dev kronostest | grep -q 192.168.168.168/24", &error_string); - if (error_string) { - printf("Error string: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (!err) { - printf("Unable to verify IP address\n"); - err=-1; - goto out_clean; - } - - printf("Adding ip: 3ffe::1/64\n"); - - err = tap_add_ip(tap, "3ffe::1", "64", &error_string); - if (error_string) { - printf("add ipv6 output: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err < 0) { - printf("Unable to assign IP address\n"); - err=-1; - goto out_clean; - } - - err = _execute_shell("ip addr show dev kronostest | grep -q 3ffe::1/64", &error_string); - if (error_string) { - printf("Error string: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err) { - printf("Unable to verify IP address\n"); - err=-1; - goto out_clean; - } - - printf("Deleting ip: 3ffe::1/64\n"); - - err = tap_del_ip(tap, "3ffe::1", "64", &error_string); - if (error_string) { - printf("Error string: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (err) { - printf("Unable to delete IP address\n"); - err=-1; - goto out_clean; - } - - err = _execute_shell("ip addr show dev kronostest | grep -q 3ffe::1/64", &error_string); - if (error_string) { - printf("Error string: %s\n", error_string); - free(error_string); - error_string = NULL; - } - if (!err) { - printf("Unable to verify IP address\n"); - err=-1; - goto out_clean; - } - -out_clean: - - tap_close(tap); - - return err; -} - -int main(void) -{ - if (geteuid() != 0) { - printf("This test requires root privileges\n"); - exit(77); - } - - if (check_tap_open_close() < 0) - return -1; - - if (check_knet_multi_eth() < 0) - return -1; - - if (check_knet_mtu() < 0) - return -1; - - if (check_knet_mtu_ipv6() < 0) - return -1; - - if (check_knet_mac() < 0) - return -1; - - if (check_tap_execute_shell() < 0) - return -1; - - if (check_knet_up_down() < 0) - return -1; - - if (check_knet_set_del_ip() < 0) - return -1; - - if (check_knet_close_leak() < 0) - return -1; - - return 0; -} -#endif diff --git a/libtap/libtap.h b/libtap/libtap.h deleted file mode 100644 index 124c3292..00000000 --- a/libtap/libtap.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. - * - * Author: Fabio M. Di Nitto - * - * This software licensed under GPL-2.0+, LGPL-2.0+ - */ - -#ifndef __LIBTAP_H__ -#define __LIBTAP_H__ - -#include - -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/post-down.d/kronostest b/libtap/tap_updown_bad/post-down.d/kronostest deleted file mode 100755 index 721ecb6e..00000000 --- a/libtap/tap_updown_bad/post-down.d/kronostest +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# -# Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. -# -# Author: Fabio M. Di Nitto -# -# This software licensed under GPL-2.0+, LGPL-2.0+ -# - -exit 1 diff --git a/libtap/tap_updown_bad/pre-up.d/kronostest b/libtap/tap_updown_bad/pre-up.d/kronostest deleted file mode 100755 index 721ecb6e..00000000 --- a/libtap/tap_updown_bad/pre-up.d/kronostest +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# -# Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. -# -# Author: Fabio M. Di Nitto -# -# This software licensed under GPL-2.0+, LGPL-2.0+ -# - -exit 1 diff --git a/libtap/tap_updown_bad/up.d/kronostest b/libtap/tap_updown_bad/up.d/kronostest deleted file mode 100755 index 721ecb6e..00000000 --- a/libtap/tap_updown_bad/up.d/kronostest +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# -# Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. -# -# Author: Fabio M. Di Nitto -# -# This software licensed under GPL-2.0+, LGPL-2.0+ -# - -exit 1 diff --git a/libtap/tap_updown_good/post-down.d/kronostest b/libtap/tap_updown_good/post-down.d/kronostest deleted file mode 100755 index 6e28da18..00000000 --- a/libtap/tap_updown_good/post-down.d/kronostest +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# -# Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. -# -# Author: Fabio M. Di Nitto -# -# This software licensed under GPL-2.0+, LGPL-2.0+ -# - -exit 0 diff --git a/libtap/tap_updown_good/pre-up.d/kronostest b/libtap/tap_updown_good/pre-up.d/kronostest deleted file mode 100755 index 6e28da18..00000000 --- a/libtap/tap_updown_good/pre-up.d/kronostest +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# -# Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. -# -# Author: Fabio M. Di Nitto -# -# This software licensed under GPL-2.0+, LGPL-2.0+ -# - -exit 0 diff --git a/libtap/tap_updown_good/up.d/kronostest b/libtap/tap_updown_good/up.d/kronostest deleted file mode 100755 index 6e28da18..00000000 --- a/libtap/tap_updown_good/up.d/kronostest +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# -# Copyright (C) 2010-2018 Red Hat, Inc. All rights reserved. -# -# Author: Fabio M. Di Nitto -# -# This software licensed under GPL-2.0+, LGPL-2.0+ -# - -exit 0 diff --git a/man/Doxyfile-nozzle.in b/man/Doxyfile-nozzle.in new file mode 100644 index 00000000..0fb6f333 --- /dev/null +++ b/man/Doxyfile-nozzle.in @@ -0,0 +1,17 @@ +# +# Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. +# +# Author: Fabio M. Di Nitto +# Christine Caulfield +# +# This software licensed under GPL-2.0+, LGPL-2.0+ +# +PROJECT_NAME = @PACKAGE_NAME@ +PROJECT_NUMBER = @PACKAGE_VERSION@ +INPUT = @abs_top_srcdir@/libnozzle/libnozzle.h +XML_OUTPUT = @abs_builddir@/xml-nozzle +GENERATE_XML = YES +XML_PROGRAMLISTING = NO +AUTOLINK_SUPPORT = NO +GENERATE_HTML = NO +GENERATE_LATEX = NO diff --git a/man/Makefile.am b/man/Makefile.am index 9f2741b1..29cd45e7 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -1,111 +1,122 @@ # # Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. # # Authors: Fabio M. Di Nitto # Federico Simoncelli # # This software licensed under GPL-2.0+, LGPL-2.0+ # MAINTAINERCLEANFILES = Makefile.in include $(top_srcdir)/build-aux/check.mk EXTRA_DIST = kronosnetd.8 knet-keygen.8 # Avoid Automake warnings about overriding these user variables. # Programs in this directory are used during the build only. AUTOMAKE_OPTIONS = -Wno-gnu EXEEXT=$(BUILD_EXEEXT) CC=$(CC_FOR_BUILD) CFLAGS=$(CFLAGS_FOR_BUILD) CPPFLAGS=$(CPPFLAGS_FOR_BUILD) LDFLAGS=$(LDFLAGS_FOR_BUILD) if BUILD_MAN if BUILD_KRONOSNETD man8_MANS = kronosnetd.8 knet-keygen.8 endif noinst_PROGRAMS = doxyxml doxyxml_SOURCES = doxyxml.c doxyxml_CFLAGS = $(AM_CFLAGS) $(libqb_BUILD_CFLAGS) $(libxml_BUILD_CFLAGS) doxyxml_LDADD = $(libqb_BUILD_LIBS) $(libxml_BUILD_LIBS) knet_man3_MANS = \ knet_addrtostr.3 \ knet_handle_add_datafd.3 \ knet_handle_clear_stats.3 \ knet_handle_compress.3 \ knet_handle_crypto.3 \ knet_handle_enable_filter.3 \ knet_handle_enable_pmtud_notify.3 \ knet_handle_enable_sock_notify.3 \ knet_handle_free.3 \ knet_handle_get_channel.3 \ knet_get_compress_list.3 \ knet_get_crypto_list.3 \ knet_handle_get_datafd.3 \ knet_handle_get_stats.3 \ knet_get_transport_id_by_name.3 \ knet_get_transport_list.3 \ knet_get_transport_name_by_id.3 \ knet_handle_get_transport_reconnect_interval.3 \ knet_handle_new.3 \ knet_handle_new_ex.3 \ knet_handle_pmtud_get.3 \ knet_handle_pmtud_getfreq.3 \ knet_handle_pmtud_setfreq.3 \ knet_handle_remove_datafd.3 \ knet_handle_setfwd.3 \ knet_handle_set_transport_reconnect_interval.3 \ knet_host_add.3 \ knet_host_enable_status_change_notify.3 \ knet_host_get_host_list.3 \ knet_host_get_id_by_host_name.3 \ knet_host_get_name_by_host_id.3 \ knet_host_get_policy.3 \ knet_host_get_status.3 \ knet_host_remove.3 \ knet_host_set_name.3 \ knet_host_set_policy.3 \ knet_link_clear_config.3 \ knet_link_get_config.3 \ knet_link_get_enable.3 \ knet_link_get_link_list.3 \ knet_link_get_ping_timers.3 \ knet_link_get_pong_count.3 \ knet_link_get_priority.3 \ knet_link_get_status.3 \ knet_link_set_config.3 \ knet_link_set_enable.3 \ knet_link_set_ping_timers.3 \ knet_link_set_pong_count.3 \ knet_link_set_priority.3 \ knet_log_get_loglevel.3 \ knet_log_get_loglevel_id.3 \ knet_log_get_loglevel_name.3 \ knet_log_get_subsystem_id.3 \ knet_log_get_subsystem_name.3 \ knet_log_set_loglevel.3 \ knet_recv.3 \ knet_send.3 \ knet_send_sync.3 \ knet_strtoaddr.3 -man3_MANS = $(knet_man3_MANS) +if BUILD_LIBNOZZLE +nozzle_man3_MANS = +endif + +man3_MANS = $(knet_man3_MANS) $(nozzle_man3_MANS) -$(MANS): doxyfile-knet.stamp +$(MANS): doxyfile-knet.stamp doxyfile-nozzle.stamp doxyfile-knet.stamp: $(builddir)/doxyxml Doxyfile-knet $(top_srcdir)/libknet/libknet.h $(DOXYGEN) Doxyfile-knet $(builddir)/doxyxml -m -P -o $(builddir) -s 3 -p @PACKAGE_NAME@ -H "Kronosnet Programmer's Manual" \ $$($(UTC_DATE_AT)$(SOURCE_EPOCH) +"-D %F -Y %Y") -d $(builddir)/xml-knet/ libknet_8h.xml touch doxyfile-knet.stamp +doxyfile-nozzle.stamp: $(builddir)/doxyxml Doxyfile-nozzle $(top_srcdir)/libnozzle/libnozzle.h +if BUILD_LIBNOZZLE + $(DOXYGEN) Doxyfile-nozzle + $(builddir)/doxyxml -m -P -o $(builddir) -s 3 -p @PACKAGE_NAME@ -H "Kronosnet Programmer's Manual" -d $(builddir)/xml-nozzle/ libnozzle_8h.xml +endif + touch doxyfile-nozzle.stamp + endif clean-local: rm -rf doxyfile*.stamp xml* *.3