Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/Makefile.am b/Makefile.am
index 418b4b34..1eaab425 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,205 +1,210 @@
#
# Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
#
# Author: Fabio M. Di Nitto <fabbione@kronosnet.org>
#
# This software licensed under GPL-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 = libnozzle libknet
if BUILD_MAN
SUBDIRS += man
endif
dist_doc_DATA = \
COPYING.applications \
COPYING.libraries \
COPYRIGHT \
README.licence \
README
all-local: $(SPEC)
clean-local:
rm -rf $(SPEC) cov*
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"`" && \
gvgver="`cd $(abs_srcdir); build-aux/git-version-gen --fallback $(VERSION) .tarball-version .gitarchivever`" && \
if [ "$$gvgver" = "`echo $$gvgver | sed 's/-/./'`" ];then \
rpmver="$$gvgver" && \
alphatag="" && \
dirty="" && \
numcomm="0"; \
else \
gitver="`echo $$gvgver | sed 's/\(.*\)\./\1-/'`" && \
rpmver=`echo $$gitver | sed 's/-.*//g'` && \
alphatag=`echo $$gvgver | sed 's/[^-]*-\([^-]*\).*/\1/'` && \
numcomm=`echo $$gitver | sed 's/[^-]*-\([^-]*\).*/\1/'` && \
dirty="" && \
if [ "`echo $$gitver | sed 's/^.*-dirty$$//g'`" = "" ];then \
dirty="dirty"; \
fi \
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_CRYPTO_GCRYPT
+ sed -i -e "s#@gcrypt@#bcond_without#g" $@-t
+else
+ sed -i -e "s#@gcrypt@#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_COMPRESS_ZSTD
sed -i -e "s#@zstd@#bcond_without#g" $@-t
else
sed -i -e "s#@zstd@#bcond_with#g" $@-t
endif
if BUILD_LIBNOZZLE
sed -i -e "s#@libnozzle@#bcond_without#g" $@-t
else
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
if INSTALL_TESTS
sed -i -e "s#@installtests@#bcond_without#g" $@-t
else
sed -i -e "s#@installtests@#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/build-aux/knet_valgrind_memcheck.supp b/build-aux/knet_valgrind_memcheck.supp
index cd09f695..c705e00c 100644
--- a/build-aux/knet_valgrind_memcheck.supp
+++ b/build-aux/knet_valgrind_memcheck.supp
@@ -1,616 +1,688 @@
{
lzma internals (spotted on Debian 9 and Ubuntu 18.04 LTS x86-64)
Memcheck:Cond
obj:/lib/x86_64-linux-gnu/liblzma.so.5.2.2
obj:/lib/x86_64-linux-gnu/liblzma.so.5.2.2
obj:/lib/x86_64-linux-gnu/liblzma.so.5.2.2
obj:/lib/x86_64-linux-gnu/liblzma.so.5.2.2
fun:lzma_block_buffer_encode
fun:lzma_stream_buffer_encode
fun:lzma_easy_buffer_encode
fun:lzma_compress
fun:compress_lib_test
fun:compress_cfg
fun:knet_handle_compress
fun:test
}
{
lzma internals (spotted on Ubuntu 18.04 LTS i386)
Memcheck:Cond
obj:/lib/i386-linux-gnu/liblzma.so.5.2.2
obj:/lib/i386-linux-gnu/liblzma.so.5.2.2
obj:/lib/i386-linux-gnu/liblzma.so.5.2.2
obj:/lib/i386-linux-gnu/liblzma.so.5.2.2
obj:/lib/i386-linux-gnu/liblzma.so.5.2.2
obj:/lib/i386-linux-gnu/liblzma.so.5.2.2
fun:lzma_stream_buffer_encode
fun:lzma_easy_buffer_encode
fun:lzma_compress
fun:compress_lib_test
fun:compress_cfg
fun:knet_handle_compress
}
{
openssl internals (spotted on OpenSUSE 15)
Memcheck:Cond
fun:__memcmp_sse4_1
obj:/usr/lib64/libcrypto.so.1.1
fun:FIPS_selftest
obj:/usr/lib64/libcrypto.so.1.1
fun:FIPS_mode_set
obj:/usr/lib64/libcrypto.so.1.1
fun:call_init.part.0
fun:_dl_init
fun:dl_open_worker
fun:_dl_catch_error
fun:_dl_open
fun:dlopen_doit
}
{
openssl internals (spotted on OpenSUSE Tumbleweed)
Memcheck:Cond
obj:/usr/lib64/libcrypto.so.1.1
fun:RAND_DRBG_generate
obj:/usr/lib64/libcrypto.so.1.1
fun:RAND_DRBG_instantiate
obj:/usr/lib64/libcrypto.so.1.1
fun:RAND_DRBG_get0_public
obj:/usr/lib64/libcrypto.so.1.1
fun:encrypt_openssl.isra.0
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:_handle_check_each
fun:_send_pings
fun:_handle_heartbt_thread
fun:start_thread
}
{
openssl internals (spotted on Ubuntu Devel x86-64 - 2019-10-30)
Memcheck:Cond
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_generate
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_instantiate
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_get0_public
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:encrypt_openssl.isra.0
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:_handle_check_each
fun:_send_pings
fun:_handle_heartbt_thread
fun:start_thread
}
{
openssl internals (spotted on OpenSUSE Tumbleweed)
Memcheck:Cond
obj:/usr/lib64/libcrypto.so.1.1
obj:/usr/lib64/libcrypto.so.1.1
fun:RAND_DRBG_generate
obj:/usr/lib64/libcrypto.so.1.1
fun:RAND_DRBG_instantiate
obj:/usr/lib64/libcrypto.so.1.1
fun:RAND_DRBG_get0_public
obj:/usr/lib64/libcrypto.so.1.1
fun:encrypt_openssl.isra.0
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:_handle_check_each
fun:_send_pings
fun:_handle_heartbt_thread
}
{
openssl internals (spotted on Ubuntu Devel x86-64 - 2019-10-30)
Memcheck:Cond
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_generate
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_instantiate
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_get0_public
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:encrypt_openssl.isra.0
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:_handle_check_each
fun:_send_pings
fun:_handle_heartbt_thread
}
{
openssl internals (spotted on OpenSUSE Tumbleweed)
Memcheck:Cond
obj:/usr/lib64/libcrypto.so.1.1
obj:/usr/lib64/libcrypto.so.1.1
fun:RAND_DRBG_generate
fun:RAND_DRBG_bytes
fun:encrypt_openssl.isra.0
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:_handle_check_each
fun:_send_pings
fun:_handle_heartbt_thread
fun:start_thread
fun:clone
}
{
openssl internals (spotted on Ubuntu Devel x86-64 - 2019-10-30)
Memcheck:Cond
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_generate
fun:RAND_DRBG_bytes
fun:encrypt_openssl.isra.0
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:_handle_check_each
fun:_send_pings
fun:_handle_heartbt_thread
fun:start_thread
fun:clone
}
{
openssl internals (spotted on OpenSUSE Tumbleweed)
Memcheck:Cond
obj:/usr/lib64/libcrypto.so.1.1
fun:RAND_DRBG_generate
fun:RAND_DRBG_bytes
fun:encrypt_openssl.isra.0
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:_handle_check_each
fun:_send_pings
fun:_handle_heartbt_thread
fun:start_thread
fun:clone
}
{
openssl internals (spotted on Ubuntu Devel x86-64 - 2019-10-30)
Memcheck:Cond
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_generate
fun:RAND_DRBG_bytes
fun:encrypt_openssl.isra.0
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:_handle_check_each
fun:_send_pings
fun:_handle_heartbt_thread
fun:start_thread
fun:clone
}
{
openssl internals (spotted on OpenSUSE 15)
Memcheck:Cond
obj:/usr/lib64/libcrypto.so.1.1
fun:FIPS_mode_set
obj:/usr/lib64/libcrypto.so.1.1
fun:call_init.part.0
fun:_dl_init
fun:dl_open_worker
fun:_dl_catch_error
fun:_dl_open
fun:dlopen_doit
fun:_dl_catch_error
fun:_dlerror_run
fun:dlopen@@GLIBC_2.2.5
}
{
openssl uninitialised byte(s) (spotted on OpenSUSE Tumbleweed and Ubuntu Devel x86-64 - 2019-10-30)
Memcheck:Param
socketcall.sendto(msg)
fun:sendto
fun:_handle_check_each
fun:_send_pings
fun:_handle_heartbt_thread
fun:start_thread
fun:clone
}
{
openssl uninitialised byte(s) (spotted on OpenSUSE Tumbleweed and Ubuntu Devel x86-64 - 2019-10-30)
Memcheck:Param
socketcall.sendto(msg)
fun:sendto
fun:_parse_recv_from_links
fun:_handle_recv_from_links
fun:_handle_recv_from_links_thread
fun:start_thread
fun:clone
}
{
openssl uninitialised byte(s) (spotted on OpenSUSE Tumbleweed and Ubuntu Devel x86-64 - 2019-10-30)
Memcheck:Param
socketcall.sendto(msg)
fun:sendto
fun:_handle_check_link_pmtud
fun:_handle_check_pmtud
fun:_handle_pmtud_link_thread
fun:start_thread
fun:clone
}
{
openssl uninitialised byte(s) (spotted on OpenSUSE Tumbleweed)
Memcheck:Param
sendmsg(msg.msg_iov[0])
fun:sendmsg
fun:_sendmmsg
fun:_dispatch_to_links
fun:_parse_recv_from_sock
fun:_handle_send_to_links
fun:_handle_send_to_links_thread
fun:start_thread
fun:clone
}
{
openssl internals (spotted on Ubuntu Devel x86-64 - 2019-10-30)
Memcheck:Param
sendmsg(msg.msg_iov[0])
fun:__libc_sendmsg
fun:sendmsg
fun:_sendmmsg
fun:_dispatch_to_links
fun:_parse_recv_from_sock
fun:_handle_send_to_links
fun:_handle_send_to_links_thread
fun:start_thread
fun:clone
}
{
openssl internals (spotted on Ubuntu Devel x86-64 - 2020-07-10)
Memcheck:Cond
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_generate
fun:RAND_DRBG_bytes
fun:encrypt_openssl
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:_handle_check_each
fun:_send_pings
fun:_handle_heartbt_thread
fun:start_thread
fun:clone
}
{
openssl internals (spotted on Ubuntu Devel x86-64 - 2020-07-10)
Memcheck:Cond
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_generate
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_instantiate
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_get0_public
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:encrypt_openssl
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:_handle_check_each
fun:_send_pings
fun:_handle_heartbt_thread
}
{
openssl internals (spotted on Ubuntu Devel x86-64 - 2020-07-10)
Memcheck:Cond
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_generate
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_instantiate
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_get0_public
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:encrypt_openssl
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:_handle_check_each
fun:_send_pings
fun:_handle_heartbt_thread
}
{
openssl internals (spotted on Ubuntu Devel x86-64 - 2020-07-10)
Memcheck:Cond
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_generate
fun:RAND_DRBG_bytes
fun:encrypt_openssl
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:_handle_check_each
fun:_send_pings
fun:_handle_heartbt_thread
fun:start_thread
fun:clone
}
{
nss internal leak (3.41) non recurring (spotted on f29)
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:/usr/lib64/libnss3.so
}
{
nss internal leak (3.41) non recurring
Memcheck:Leak
match-leak-kinds: definite
fun:calloc
obj:*
obj:*
obj:*
obj:*
obj:*
fun:init_nss
fun:nsscrypto_init
fun:crypto_init
fun:knet_handle_crypto_set_config
fun:test
fun:main
}
{
nss internal leak (3.41) non recurring
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
obj:*
obj:*
obj:*
obj:*
obj:*
fun:init_nss
fun:nsscrypto_init
fun:crypto_init
fun:knet_handle_crypto_set_config
fun:test
fun:main
}
{
nss internal leak (3.55) non recurring (spotted on f34)
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
fun:realpath@@GLIBC_2.3
obj:*
obj:*
obj:*
obj:/usr/lib64/libnss3.so
fun:SECMOD_LoadModule
fun:SECMOD_LoadModule
obj:/usr/lib64/libnss3.so
fun:NSS_NoDB_Init
fun:init_nss
fun:nsscrypto_init
fun:crypto_init
fun:_knet_handle_crypto_set_config
}
{
openssl uncoditional jump (spotted on Ubuntu devel 10092020)
Memcheck:Cond
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_generate
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_instantiate
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_get0_public
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:encrypt_openssl.isra.0
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:send_ping
fun:_send_pings
fun:_handle_heartbt_thread
fun:start_thread
}
{
openssl uncoditional jump (spotted on Ubuntu devel 10092020)
Memcheck:Cond
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_generate
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_instantiate
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_get0_public
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:encrypt_openssl.isra.0
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:send_ping
fun:_send_pings
fun:_handle_heartbt_thread
}
{
openssl uncoditional jump (spotted on Ubuntu devel 10092020)
Memcheck:Cond
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_generate
fun:RAND_DRBG_bytes
fun:encrypt_openssl.isra.0
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:send_ping
fun:_send_pings
fun:_handle_heartbt_thread
fun:start_thread
fun:clone
}
{
openssl uncoditional jump (spotted on Ubuntu devel 10092020)
Memcheck:Cond
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_generate
fun:RAND_DRBG_bytes
fun:encrypt_openssl.isra.0
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:send_ping
fun:_send_pings
fun:_handle_heartbt_thread
fun:start_thread
fun:clone
}
{
ubuntu-devel new toolchain is not stable yet (spotted on Ubuntu devel 10092020)
Memcheck:Param
socketcall.sendto(msg)
fun:sendto
fun:send_ping
fun:_send_pings
fun:_handle_heartbt_thread
fun:start_thread
fun:clone
}
{
ubuntu-devel new toolchain is not stable yet (spotted on Ubuntu devel 10092020)
Memcheck:Param
socketcall.sendto(msg)
fun:sendto
fun:send_pong
fun:process_ping
fun:_parse_recv_from_links
fun:_handle_recv_from_links
fun:_handle_recv_from_links_thread
fun:start_thread
fun:clone
}
{
ubuntu-devel new toolchain is not stable yet (spotted on Ubuntu devel 10092020)
Memcheck:Param
socketcall.sendto(msg)
fun:sendto
fun:send_pmtud_reply
fun:process_pmtud
fun:_parse_recv_from_links
fun:_handle_recv_from_links
fun:_handle_recv_from_links_thread
fun:start_thread
fun:clone
}
{
ubuntu-devel new toolchain is not stable yet (spotted on Ubuntu devel 10092020)
Memcheck:Param
sendmsg(msg.msg_iov[0])
fun:__libc_sendmsg
fun:sendmsg
fun:_sendmmsg
fun:_dispatch_to_links
fun:_prep_and_send_msgs
fun:_parse_recv_from_sock
fun:_handle_send_to_links
fun:_handle_send_to_links_thread
fun:start_thread
fun:clone
}
{
openssl uncoditional jump (clang) (spotted on Ubuntu devel 10092020)
Memcheck:Cond
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_generate
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_instantiate
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_get0_public
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:encrypt_openssl
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:send_ping
fun:_send_pings
fun:_handle_heartbt_thread
fun:start_thread
}
{
openssl uncoditional jump (clang) (spotted on Ubuntu devel 10092020)
Memcheck:Cond
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_generate
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_instantiate
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_get0_public
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:encrypt_openssl
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:send_ping
fun:_send_pings
fun:_handle_heartbt_thread
}
{
openssl uncoditional jump (clang) (spotted on Ubuntu devel 10092020)
Memcheck:Cond
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_generate
fun:RAND_DRBG_bytes
fun:encrypt_openssl
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:send_ping
fun:_send_pings
fun:_handle_heartbt_thread
fun:start_thread
fun:clone
}
{
openssl uncoditional jump (clang) (spotted on Ubuntu devel 10092020)
Memcheck:Cond
obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
fun:RAND_DRBG_generate
fun:RAND_DRBG_bytes
fun:encrypt_openssl
fun:opensslcrypto_encrypt_and_signv
fun:opensslcrypto_encrypt_and_sign
fun:send_ping
fun:_send_pings
fun:_handle_heartbt_thread
fun:start_thread
fun:clone
}
{
nss internal leak (3.59) non recurring (spotted on f34)
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
fun:realpath@@GLIBC_2.3
obj:*
obj:*
obj:*
obj:*
obj:/usr/lib64/libnss3.so
fun:SECMOD_LoadModule
fun:SECMOD_LoadModule
obj:/usr/lib64/libnss3.so
fun:NSS_NoDB_Init
fun:init_nss
fun:nsscrypto_init
}
{
nss internal leak (3.59) non recurring (spotted on f34)
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
fun:realpath@@GLIBC_2.3
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
fun:init_nss
fun:nsscrypto_init
}
+{
+ libgcrypt internal conditinal (debian 10)
+ Memcheck:Cond
+ obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4
+ obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4
+ obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4
+ obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4
+ obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4
+ obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4
+ fun:encrypt_gcrypt.isra.0
+ fun:gcryptcrypto_encrypt_and_signv
+ fun:gcryptcrypto_encrypt_and_sign
+ fun:send_ping
+ fun:_send_pings
+ fun:_handle_heartbt_thread
+ fun:start_thread
+ fun:clone
+}
+{
+ libgcrypt internal conditinal (debian 10 - clang)
+ Memcheck:Cond
+ obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4
+ obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4
+ obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4
+ obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4
+ obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4
+ obj:/usr/lib/x86_64-linux-gnu/libgcrypt.so.20.2.4
+ fun:encrypt_gcrypt
+ fun:gcryptcrypto_encrypt_and_signv
+ fun:gcryptcrypto_encrypt_and_sign
+ fun:send_ping
+ fun:_send_pings
+ fun:_handle_heartbt_thread
+ fun:start_thread
+ fun:clone
+}
+{
+ libgcrypt internal conditinal (opensuse 15)
+ Memcheck:Cond
+ obj:/usr/lib64/libgcrypt.so.20.2.2
+ obj:/usr/lib64/libgcrypt.so.20.2.2
+ obj:/usr/lib64/libgcrypt.so.20.2.2
+ obj:/usr/lib64/libgcrypt.so.20.2.2
+ obj:/usr/lib64/libgcrypt.so.20.2.2
+ obj:/usr/lib64/libgcrypt.so.20.2.2
+ fun:encrypt_gcrypt.isra.0
+ fun:gcryptcrypto_encrypt_and_signv
+ fun:gcryptcrypto_encrypt_and_sign
+ fun:send_ping
+ fun:_send_pings
+ fun:_handle_heartbt_thread
+ fun:start_thread
+ fun:clone
+}
+{
+ libgcrypt internal conditinal (opensuse 15 - clang)
+ Memcheck:Cond
+ obj:/usr/lib64/libgcrypt.so.20.2.2
+ obj:/usr/lib64/libgcrypt.so.20.2.2
+ obj:/usr/lib64/libgcrypt.so.20.2.2
+ obj:/usr/lib64/libgcrypt.so.20.2.2
+ obj:/usr/lib64/libgcrypt.so.20.2.2
+ obj:/usr/lib64/libgcrypt.so.20.2.2
+ fun:encrypt_gcrypt
+ fun:gcryptcrypto_encrypt_and_signv
+ fun:gcryptcrypto_encrypt_and_sign
+ fun:send_ping
+ fun:_send_pings
+ fun:_handle_heartbt_thread
+ fun:start_thread
+ fun:clone
+}
diff --git a/configure.ac b/configure.ac
index 8677a647..e481f63e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,412 +1,421 @@
#
# Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
#
# Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
# Federico Simoncelli <fsimon@kronosnet.org>
#
# This software licensed under GPL-2.0+
#
# -*- 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([libknet/handle.c])
AC_CONFIG_HEADERS([config.h])
AC_CANONICAL_HOST
AC_LANG([C])
if test "$prefix" = "NONE"; then
prefix="/usr"
if test "$localstatedir" = "\${prefix}/var"; then
localstatedir="/var"
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"])
AC_CHECK_PROGS([COVBUILD_EXEC], [cov-build])
AM_CONDITIONAL([HAS_COVBUILD], [test x$COVBUILD_EXEC != "x"])
AC_CHECK_PROGS([COVANALYZE_EXEC], [cov-analyze])
AM_CONDITIONAL([HAS_COVANALYZE], [test x$COVANALYZE_EXEC != "x"])
AC_CHECK_PROGS([COVFORMATERRORS_EXEC], [cov-format-errors])
AM_CONDITIONAL([HAS_COVFORMATERRORS], [test x$COVFORMATERRORS_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])])
+KNET_OPTION_DEFINES([openssl],[crypto],[PKG_CHECK_MODULES([openssl], [libcrypto])])
+
+# use gcry_mac_open to detect if libgcrypt is new enough
+KNET_OPTION_DEFINES([gcrypt],[crypto],[
+ PKG_CHECK_MODULES([gcrypt], [libgcrypt >= 1.8.0],,
+ [AC_CHECK_HEADERS([gcrypt.h],
+ [AC_CHECK_LIB([gcrypt], [gcry_mac_open],
+ [AC_SUBST([gcrypt_LIBS], ["-lgcrypt -ldl -lgpg-error"])])],
+ [AC_MSG_ERROR(["missing required gcrypt.h"])])])
+])
AC_ARG_ENABLE([compress-all],
[AS_HELP_STRING([--disable-compress-all],[disable libknet all compress modules support])],,
[ enable_compress_all="yes" ])
KNET_OPTION_DEFINES([zstd],[compress],[PKG_CHECK_MODULES([libzstd], [libzstd])])
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([install-tests],
[AS_HELP_STRING([--enable-install-tests],[install tests])],,
[ enable_install_tests="no" ])
AM_CONDITIONAL([INSTALL_TESTS], [test x$enable_install_tests = 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([libnozzle],
[AS_HELP_STRING([--enable-libnozzle],[libnozzle support])],,
[ enable_libnozzle="yes" ])
AM_CONDITIONAL([BUILD_LIBNOZZLE], [test x$enable_libnozzle = xyes])
# 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"
# Check RTLD_DI_ORIGIN (not decalred by musl. glibc has it as an enum so cannot use ifdef)
AC_CHECK_DECL([RTLD_DI_ORIGIN], [AC_DEFINE([HAVE_RTLD_DI_ORIGIN], 1,
[define when RTLD_DI_ORIGIN is declared])], ,[[#include <dlfcn.h>]])
# 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])
;;
*)
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
PKG_CHECK_MODULES([libqb], [libqb])
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
AC_ARG_VAR([DOXYGEN2MAN], [override doxygen2man executable])
# required to detect doxygen2man when libqb is installed
# in non standard paths
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_VAR([libqb_BUILD_PREFIX], [libqb], [prefix])
AC_PATH_PROG([DOXYGEN2MAN], [doxygen2man], [no], [$libqb_BUILD_PREFIX/bin$PATH_SEPARATOR$PATH])
PKG_CONFIG="$saved_PKG_CONFIG"
ac_cv_path_PKG_CONFIG="$saved_ac_cv_path_PKG_CONFIG"
if test "x$DOXYGEN2MAN" = "xno"; then
AC_MSG_ERROR(["doxygen2man command not found"])
fi
AC_SUBST([DOXYGEN2MAN])
fi
# 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
# local options
AC_ARG_ENABLE([debug],
[AS_HELP_STRING([--enable-debug],[enable debug build])])
AC_ARG_WITH([sanitizers],
[AS_HELP_STRING([--with-sanitizers=...,...],
[enable SANitizer build, do *NOT* use for production. Only ASAN/UBSAN/TSAN are currently supported])],
[ SANITIZERS="$withval" ],
[ SANITIZERS="" ])
AC_ARG_WITH([testdir],
[AS_HELP_STRING([--with-testdir=DIR],[path to /usr/lib../kronosnet/tests/ dir where to install the test suite])],
[ TESTDIR="$withval" ],
[ TESTDIR="$libdir/kronosnet/tests" ])
## do subst
AC_SUBST([TESTDIR])
# 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
# --- ASAN/UBSAN/TSAN (see man gcc) ---
# when using SANitizers, we need to pass the -fsanitize..
# to both CFLAGS and LDFLAGS. The CFLAGS/LDFLAGS must be
# specified as first in the list or there will be runtime
# issues (for example user has to LD_PRELOAD asan for it to work
# properly).
if test -n "${SANITIZERS}"; then
SANITIZERS=$(echo $SANITIZERS | sed -e 's/,/ /g')
for SANITIZER in $SANITIZERS; do
case $SANITIZER in
asan|ASAN)
SANITIZERS_CFLAGS="$SANITIZERS_CFLAGS -fsanitize=address"
SANITIZERS_LDFLAGS="$SANITIZERS_LDFLAGS -fsanitize=address -lasan"
AC_CHECK_LIB([asan],[main],,AC_MSG_ERROR([Unable to find libasan]))
;;
ubsan|UBSAN)
SANITIZERS_CFLAGS="$SANITIZERS_CFLAGS -fsanitize=undefined"
SANITIZERS_LDFLAGS="$SANITIZERS_LDFLAGS -fsanitize=undefined -lubsan"
AC_CHECK_LIB([ubsan],[main],,AC_MSG_ERROR([Unable to find libubsan]))
;;
tsan|TSAN)
SANITIZERS_CFLAGS="$SANITIZERS_CFLAGS -fsanitize=thread"
SANITIZERS_LDFLAGS="$SANITIZERS_LDFLAGS -fsanitize=thread -ltsan"
AC_CHECK_LIB([tsan],[main],,AC_MSG_ERROR([Unable to find libtsan]))
;;
esac
done
fi
DEFAULT_CFLAGS="-Werror -Wall -Wextra"
# manual overrides
# generates too much noise for stub APIs
UNWANTED_CFLAGS="-Wno-unused-parameter"
AC_SUBST([AM_CFLAGS],["$SANITIZERS_CFLAGS $OPT_CFLAGS $GDB_FLAGS $DEFAULT_CFLAGS $UNWANTED_CFLAGS"])
LDFLAGS="$SANITIZERS_LDFLAGS $LDFLAGS"
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
libnozzle/Makefile
libnozzle/libnozzle.pc
libnozzle/tests/Makefile
libknet/Makefile
libknet/libknet.pc
libknet/tests/Makefile
man/Makefile
man/Doxyfile-knet
man/Doxyfile-nozzle
])
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 7a3290ce..45544ccf 100644
--- a/kronosnet.spec.in
+++ b/kronosnet.spec.in
@@ -1,461 +1,483 @@
###############################################################################
###############################################################################
##
## Copyright (C) 2012-2020 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
+%@gcrypt@ gcrypt
%@zlib@ zlib
%@lz4@ lz4
%@lzo2@ lzo2
%@lzma@ lzma
%@bzip2@ bzip2
%@zstd@ zstd
%@libnozzle@ libnozzle
%@runautogen@ runautogen
%@rpmdebuginfo@ rpmdebuginfo
%@overriderpmdebuginfo@ overriderpmdebuginfo
%@buildman@ buildman
%@installtests@ installtests
%if %{with overriderpmdebuginfo}
%undefine _enable_debug_packages
%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+
URL: https://kronosnet.org
Source0: https://kronosnet.org/releases/%{name}-%{version}%{?numcomm:.%{numcomm}}%{?alphatag:-%{alphatag}}%{?dirty:-%{dirty}}.tar.gz
# Build dependencies
BuildRequires: gcc libqb-devel
# required to build man pages
%if %{with buildman}
BuildRequires: doxygen doxygen2man
%endif
%if %{with sctp}
BuildRequires: lksctp-tools-devel
%endif
%if %{with nss}
%if 0%{?suse_version}
BuildRequires: mozilla-nss-devel
%else
BuildRequires: nss-devel
%endif
%endif
%if %{with openssl}
%if 0%{?suse_version}
BuildRequires: libopenssl-devel
%else
BuildRequires: openssl-devel
%endif
%endif
+%if %{with gcrypt}
+BuildRequires: libgcrypt-devel >= 1.8.0
+%endif
%if %{with zlib}
BuildRequires: zlib-devel
%endif
%if %{with lz4}
%if 0%{?suse_version}
BuildRequires: liblz4-devel
%else
BuildRequires: lz4-devel
%endif
%endif
%if %{with lzo2}
BuildRequires: lzo-devel
%endif
%if %{with lzma}
BuildRequires: xz-devel
%endif
%if %{with bzip2}
%if 0%{?suse_version}
BuildRequires: libbz2-devel
%else
BuildRequires: bzip2-devel
%endif
%endif
%if %{with zstd}
BuildRequires: libzstd-devel
%endif
%if %{with libnozzle}
BuildRequires: libnl3-devel
%endif
%if %{with runautogen}
BuildRequires: autoconf automake libtool
%endif
%prep
%setup -q -n %{name}-%{version}%{?numcomm:.%{numcomm}}%{?alphatag:-%{alphatag}}%{?dirty:-%{dirty}}
%build
%if %{with runautogen}
./autogen.sh
%endif
%{configure} \
%if %{with installtests}
--enable-install-tests \
%else
--disable-install-tests \
%endif
%if %{with buildman}
--enable-man \
%else
--disable-man \
%endif
%if %{with sctp}
--enable-libknet-sctp \
%else
--disable-libknet-sctp \
%endif
%if %{with nss}
--enable-crypto-nss \
%else
--disable-crypto-nss \
%endif
%if %{with openssl}
--enable-crypto-openssl \
%else
--disable-crypto-openssl \
%endif
+%if %{with gcrypt}
+ --enable-crypto-gcrypt \
+%else
+ --disable-crypto-gcrypt \
+%endif
%if %{with zlib}
--enable-compress-zlib \
%else
--disable-compress-zlib \
%endif
%if %{with lz4}
--enable-compress-lz4 \
%else
--disable-compress-lz4 \
%endif
%if %{with lzo2}
--enable-compress-lzo2 \
%else
--disable-compress-lzo2 \
%endif
%if %{with lzma}
--enable-compress-lzma \
%else
--disable-compress-lzma \
%endif
%if %{with bzip2}
--enable-compress-bzip2 \
%else
--disable-compress-bzip2 \
%endif
%if %{with zstd}
--enable-compress-zstd \
%else
--disable-compress-zstd \
%endif
%if %{with libnozzle}
--enable-libnozzle \
%else
--disable-libnozzle \
%endif
--with-initdefaultdir=%{_sysconfdir}/sysconfig/ \
--with-systemddir=%{_unitdir}
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 {} \;
-# remove init scripts
-rm -rf %{buildroot}/etc/init.d
-
# remove docs
rm -rf %{buildroot}/usr/share/doc/kronosnet
# main empty package
%description
The kronosnet source
%if %{with libnozzle}
%package -n libnozzle1
Summary: Simple userland wrapper around kernel tap devices
License: LGPLv2+
%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 libnozzle1
%license COPYING.* COPYRIGHT
%{_libdir}/libnozzle.so.*
%if 0%{?ldconfig_scriptlets}
%ldconfig_scriptlets -n libnozzle1
%else
%post -n libnozzle1 -p /sbin/ldconfig
%postun -n libnozzle1 -p /sbin/ldconfig
%endif
%package -n libnozzle1-devel
Summary: Simple userland wrapper around kernel tap devices (developer files)
License: LGPLv2+
Requires: libnozzle1%{_isa} = %{version}-%{release}
Requires: pkgconfig
%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 libnozzle1-devel
%license COPYING.* COPYRIGHT
%{_libdir}/libnozzle.so
%{_includedir}/libnozzle.h
%{_libdir}/pkgconfig/libnozzle.pc
%if %{with buildman}
%{_mandir}/man3/nozzle*.3.gz
%endif
%endif
%package -n libknet1
Summary: Kronosnet core switching implementation
License: LGPLv2+
%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
%license COPYING.* COPYRIGHT
%{_libdir}/libknet.so.*
%dir %{_libdir}/kronosnet
%if 0%{?ldconfig_scriptlets}
%ldconfig_scriptlets -n libknet1
%else
%post -n libknet1 -p /sbin/ldconfig
%postun -n libknet1 -p /sbin/ldconfig
%endif
%package -n libknet1-devel
Summary: Kronosnet core switching implementation (developer files)
License: LGPLv2+
Requires: libknet1%{_isa} = %{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
%license COPYING.* COPYRIGHT
%{_libdir}/libknet.so
%{_includedir}/libknet.h
%{_libdir}/pkgconfig/libknet.pc
%if %{with buildman}
%{_mandir}/man3/knet*.3.gz
%endif
%if %{with nss}
%package -n libknet1-crypto-nss-plugin
Summary: Provides libknet1 nss support
License: LGPLv2+
Requires: libknet1%{_isa} = %{version}-%{release}
%description -n libknet1-crypto-nss-plugin
Provides NSS crypto support for libknet1.
%files -n libknet1-crypto-nss-plugin
%{_libdir}/kronosnet/crypto_nss.so
%endif
%if %{with openssl}
%package -n libknet1-crypto-openssl-plugin
Summary: Provides libknet1 openssl support
License: LGPLv2+
Requires: libknet1%{_isa} = %{version}-%{release}
%description -n libknet1-crypto-openssl-plugin
Provides OpenSSL crypto support for libknet1.
%files -n libknet1-crypto-openssl-plugin
%{_libdir}/kronosnet/crypto_openssl.so
%endif
+%if %{with gcrypt}
+%package -n libknet1-crypto-gcrypt-plugin
+Summary: Provides libknet1 gcrypt support
+License: LGPLv2+
+Requires: libknet1%{_isa} = %{version}-%{release}
+
+%description -n libknet1-crypto-gcrypt-plugin
+ Provides libgcrypt crypto support for libknet1.
+
+%files -n libknet1-crypto-gcrypt-plugin
+%{_libdir}/kronosnet/crypto_gcrypt.so
+%endif
+
%if %{with zlib}
%package -n libknet1-compress-zlib-plugin
Summary: Provides libknet1 zlib support
License: LGPLv2+
Requires: libknet1%{_isa} = %{version}-%{release}
%description -n libknet1-compress-zlib-plugin
Provides zlib compression support for libknet1.
%files -n libknet1-compress-zlib-plugin
%{_libdir}/kronosnet/compress_zlib.so
%endif
%if %{with lz4}
%package -n libknet1-compress-lz4-plugin
Summary: Provides libknet1 lz4 and lz4hc support
License: LGPLv2+
Requires: libknet1%{_isa} = %{version}-%{release}
%description -n libknet1-compress-lz4-plugin
Provides lz4 and lz4hc compression support for libknet1.
%files -n libknet1-compress-lz4-plugin
%{_libdir}/kronosnet/compress_lz4.so
%{_libdir}/kronosnet/compress_lz4hc.so
%endif
%if %{with lzo2}
%package -n libknet1-compress-lzo2-plugin
Summary: Provides libknet1 lzo2 support
License: LGPLv2+
Requires: libknet1%{_isa} = %{version}-%{release}
%description -n libknet1-compress-lzo2-plugin
Provides lzo2 compression support for libknet1.
%files -n libknet1-compress-lzo2-plugin
%{_libdir}/kronosnet/compress_lzo2.so
%endif
%if %{with lzma}
%package -n libknet1-compress-lzma-plugin
Summary: Provides libknet1 lzma support
License: LGPLv2+
Requires: libknet1%{_isa} = %{version}-%{release}
%description -n libknet1-compress-lzma-plugin
Provides lzma compression support for libknet1.
%files -n libknet1-compress-lzma-plugin
%{_libdir}/kronosnet/compress_lzma.so
%endif
%if %{with bzip2}
%package -n libknet1-compress-bzip2-plugin
Summary: Provides libknet1 bzip2 support
License: LGPLv2+
Requires: libknet1%{_isa} = %{version}-%{release}
%description -n libknet1-compress-bzip2-plugin
Provides bzip2 compression support for libknet1.
%files -n libknet1-compress-bzip2-plugin
%{_libdir}/kronosnet/compress_bzip2.so
%endif
%if %{with zstd}
%package -n libknet1-compress-zstd-plugin
Summary: Provides libknet1 zstd support
License: LGPLv2+
Requires: libknet1%{_isa} = %{version}-%{release}
%description -n libknet1-compress-zstd-plugin
Provides zstd compression support for libknet1.
%files -n libknet1-compress-zstd-plugin
%{_libdir}/kronosnet/compress_zstd.so
%endif
%package -n libknet1-crypto-plugins-all
Summary: Provides libknet1 crypto plugins meta package
License: LGPLv2+
%if %{with nss}
Requires: libknet1-crypto-nss-plugin%{_isa} = %{version}-%{release}
%endif
%if %{with openssl}
Requires: libknet1-crypto-openssl-plugin%{_isa} = %{version}-%{release}
%endif
+%if %{with gcrypt}
+Requires: libknet1-crypto-gcrypt-plugin%{_isa} = %{version}-%{release}
+%endif
%description -n libknet1-crypto-plugins-all
Provides meta package to install all of libknet1 crypto plugins
%files -n libknet1-crypto-plugins-all
%package -n libknet1-compress-plugins-all
Summary: Provides libknet1 compress plugins meta package
License: LGPLv2+
%if %{with zlib}
Requires: libknet1-compress-zlib-plugin%{_isa} = %{version}-%{release}
%endif
%if %{with lz4}
Requires: libknet1-compress-lz4-plugin%{_isa} = %{version}-%{release}
%endif
%if %{with lzo2}
Requires: libknet1-compress-lzo2-plugin%{_isa} = %{version}-%{release}
%endif
%if %{with lzma}
Requires: libknet1-compress-lzma-plugin%{_isa} = %{version}-%{release}
%endif
%if %{with bzip2}
Requires: libknet1-compress-bzip2-plugin%{_isa} = %{version}-%{release}
%endif
%if %{with zstd}
Requires: libknet1-compress-zstd-plugin%{_isa} = %{version}-%{release}
%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
Summary: Provides libknet1 plugins meta package
License: LGPLv2+
Requires: libknet1-compress-plugins-all%{_isa} = %{version}-%{release}
Requires: libknet1-crypto-plugins-all%{_isa} = %{version}-%{release}
%description -n libknet1-plugins-all
Meta package to install all of libknet1 plugins
%files -n libknet1-plugins-all
%if %{with installtests}
%package -n kronosnet-tests
Summary: Provides kronosnet test suite
License: GPLv2+
Requires: libknet1%{_isa} = %{version}-%{release}
%description -n kronosnet-tests
This package contains all the libknet and libnozzle test suite.
%files -n kronosnet-tests
%{_libdir}/kronosnet/tests/*
%endif
%if %{with rpmdebuginfo}
%debug_package
%endif
%changelog
* @date@ Autotools generated version <nobody@nowhere.org> - @version@-1-@numcomm@.@alphatag@.@dirty@
- These aren't the droids you're looking for.
diff --git a/libknet/Makefile.am b/libknet/Makefile.am
index 695bb8a1..9e49b1db 100644
--- a/libknet/Makefile.am
+++ b/libknet/Makefile.am
@@ -1,169 +1,176 @@
#
# Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
#
# Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
# Federico Simoncelli <fsimon@kronosnet.org>
#
# This software licensed under GPL-2.0+
#
MAINTAINERCLEANFILES = Makefile.in
include $(top_srcdir)/build-aux/check.mk
SYMFILE = libknet_exported_syms
EXTRA_DIST = $(SYMFILE)
SUBDIRS = . tests
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
libversion = 2:0:0
# override global LIBS that pulls in lots of craft we don't need here
LIBS =
sources = \
common.c \
compat.c \
compress.c \
crypto.c \
handle.c \
handle_api.c \
host.c \
links.c \
links_acl.c \
links_acl_ip.c \
links_acl_loopback.c \
logging.c \
netutils.c \
onwire.c \
onwire_v1.c \
threads_common.c \
threads_dsthandler.c \
threads_heartbeat.c \
threads_pmtud.c \
threads_rx.c \
threads_tx.c \
transports.c \
transport_common.c \
transport_loopback.c \
transport_udp.c \
transport_sctp.c
include_HEADERS = libknet.h
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libknet.pc
noinst_HEADERS = \
common.h \
compat.h \
compress.h \
compress_model.h \
crypto.h \
crypto_model.h \
host.h \
internals.h \
links.h \
links_acl.h \
links_acl_ip.h \
links_acl_loopback.h \
logging.h \
netutils.h \
onwire.h \
onwire_v1.h \
threads_common.h \
threads_dsthandler.h \
threads_heartbeat.h \
threads_pmtud.h \
threads_rx.h \
threads_tx.h \
transports.h \
transport_common.h \
transport_loopback.h \
transport_udp.h \
transport_sctp.h
lib_LTLIBRARIES = libknet.la
libknet_la_SOURCES = $(sources)
AM_CFLAGS += $(libqb_CFLAGS)
libknet_la_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS)
EXTRA_libknet_la_DEPENDENCIES = $(SYMFILE)
libknet_la_LDFLAGS = $(AM_LDFLAGS) \
-Wl,--version-script=$(srcdir)/$(SYMFILE) \
-Wl,-rpath=$(pkglibdir) \
-version-info $(libversion)
libknet_la_LIBADD = $(PTHREAD_LIBS) $(dl_LIBS) $(rt_LIBS) $(m_LIBS)
# Prepare empty value for appending
pkglib_LTLIBRARIES =
# MODULE_LDFLAGS would mean a target-specific variable for Automake
MODULELDFLAGS = $(AM_LDFLAGS) -module -avoid-version -export-dynamic
if BUILD_COMPRESS_ZSTD
pkglib_LTLIBRARIES += compress_zstd.la
compress_zstd_la_LDFLAGS = $(MODULELDFLAGS)
compress_zstd_la_CFLAGS = $(AM_CFLAGS) $(libzstd_CFLAGS)
compress_zstd_la_LIBADD = $(libzstd_LIBS)
endif
if BUILD_COMPRESS_ZLIB
pkglib_LTLIBRARIES += compress_zlib.la
compress_zlib_la_LDFLAGS = $(MODULELDFLAGS)
compress_zlib_la_CFLAGS = $(AM_CFLAGS) $(zlib_CFLAGS)
compress_zlib_la_LIBADD = $(zlib_LIBS)
endif
if BUILD_COMPRESS_LZ4
pkglib_LTLIBRARIES += compress_lz4.la compress_lz4hc.la
compress_lz4_la_LDFLAGS = $(MODULELDFLAGS)
compress_lz4_la_CFLAGS = $(AM_CFLAGS) $(liblz4_CFLAGS)
compress_lz4_la_LIBADD = $(liblz4_LIBS)
compress_lz4hc_la_LDFLAGS = $(MODULELDFLAGS)
compress_lz4hc_la_CFLAGS = $(AM_CFLAGS) $(liblz4_CFLAGS)
compress_lz4hc_la_LIBADD = $(liblz4_LIBS)
endif
if BUILD_COMPRESS_LZO2
pkglib_LTLIBRARIES += compress_lzo2.la
compress_lzo2_la_LDFLAGS = $(MODULELDFLAGS)
compress_lzo2_la_CFLAGS = $(AM_CFLAGS) $(lzo2_CFLAGS)
compress_lzo2_la_LIBADD = $(lzo2_LIBS)
endif
if BUILD_COMPRESS_LZMA
pkglib_LTLIBRARIES += compress_lzma.la
compress_lzma_la_LDFLAGS = $(MODULELDFLAGS)
compress_lzma_la_CFLAGS = $(AM_CFLAGS) $(liblzma_CFLAGS)
compress_lzma_la_LIBADD = $(liblzma_LIBS)
endif
if BUILD_COMPRESS_BZIP2
pkglib_LTLIBRARIES += compress_bzip2.la
compress_bzip2_la_LDFLAGS = $(MODULELDFLAGS)
compress_bzip2_la_CFLAGS = $(AM_CFLAGS) $(bzip2_CFLAGS)
compress_bzip2_la_LIBADD = $(bzip2_LIBS)
endif
if BUILD_CRYPTO_NSS
pkglib_LTLIBRARIES += crypto_nss.la
crypto_nss_la_LDFLAGS = $(MODULELDFLAGS)
crypto_nss_la_CFLAGS = $(AM_CFLAGS) $(nss_CFLAGS)
crypto_nss_la_LIBADD = $(nss_LIBS)
endif
if BUILD_CRYPTO_OPENSSL
pkglib_LTLIBRARIES += crypto_openssl.la
crypto_openssl_la_LDFLAGS = $(MODULELDFLAGS)
crypto_openssl_la_CFLAGS = $(AM_CFLAGS) $(openssl_CFLAGS)
crypto_openssl_la_LIBADD = $(openssl_LIBS)
endif
+
+if BUILD_CRYPTO_GCRYPT
+pkglib_LTLIBRARIES += crypto_gcrypt.la
+crypto_gcrypt_la_LDFLAGS = $(MODULELDFLAGS)
+crypto_gcrypt_la_CFLAGS = $(AM_CFLAGS) $(gcrypt_CFLAGS)
+crypto_gcrypt_la_LIBADD = $(gcrypt_LIBS)
+endif
diff --git a/libknet/crypto.c b/libknet/crypto.c
index 59e1fded..317f03ab 100644
--- a/libknet/crypto.c
+++ b/libknet/crypto.c
@@ -1,459 +1,460 @@
/*
* Copyright (C) 2012-2020 Red Hat, Inc. All rights reserved.
*
* Author: Fabio M. Di Nitto <fabbione@kronosnet.org>
*
* This software licensed under LGPL-2.0+
*/
#include "config.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#include "crypto.h"
#include "crypto_model.h"
#include "internals.h"
#include "logging.h"
#include "common.h"
/*
* internal module switch data
*/
static crypto_model_t crypto_modules_cmds[] = {
{ "nss", WITH_CRYPTO_NSS, 0, NULL },
{ "openssl", WITH_CRYPTO_OPENSSL, 0, NULL },
+ { "gcrypt", WITH_CRYPTO_GCRYPT, 0, NULL },
{ NULL, 0, 0, NULL }
};
static int crypto_get_model(const char *model)
{
int idx = 0;
while (crypto_modules_cmds[idx].model_name != NULL) {
if (!strcmp(crypto_modules_cmds[idx].model_name, model))
return idx;
idx++;
}
return -1;
}
/*
* exported API
*/
int crypto_encrypt_and_sign (
knet_handle_t knet_h,
const unsigned char *buf_in,
const ssize_t buf_in_len,
unsigned char *buf_out,
ssize_t *buf_out_len)
{
return crypto_modules_cmds[knet_h->crypto_instance[knet_h->crypto_in_use_config]->model].ops->crypt(knet_h, knet_h->crypto_instance[knet_h->crypto_in_use_config], buf_in, buf_in_len, buf_out, buf_out_len);
}
int crypto_encrypt_and_signv (
knet_handle_t knet_h,
const struct iovec *iov_in,
int iovcnt_in,
unsigned char *buf_out,
ssize_t *buf_out_len)
{
return crypto_modules_cmds[knet_h->crypto_instance[knet_h->crypto_in_use_config]->model].ops->cryptv(knet_h, knet_h->crypto_instance[knet_h->crypto_in_use_config], iov_in, iovcnt_in, buf_out, buf_out_len);
}
int crypto_authenticate_and_decrypt (
knet_handle_t knet_h,
const unsigned char *buf_in,
const ssize_t buf_in_len,
unsigned char *buf_out,
ssize_t *buf_out_len)
{
int i, err = 0;
int multiple_configs = 0;
uint8_t log_level = KNET_LOG_ERR;
for (i = 1; i <= KNET_MAX_CRYPTO_INSTANCES; i++) {
if (knet_h->crypto_instance[i]) {
multiple_configs++;
}
}
/*
* attempt to decrypt first with the in-use config
* to avoid excessive performance hit.
*/
if (multiple_configs > 1) {
log_level = KNET_LOG_DEBUG;
}
if (knet_h->crypto_in_use_config) {
err = crypto_modules_cmds[knet_h->crypto_instance[knet_h->crypto_in_use_config]->model].ops->decrypt(knet_h, knet_h->crypto_instance[knet_h->crypto_in_use_config], buf_in, buf_in_len, buf_out, buf_out_len, log_level);
} else {
err = -1;
}
/*
* if we fail, try to use the other configurations
*/
if (err) {
for (i = 1; i <= KNET_MAX_CRYPTO_INSTANCES; i++) {
/*
* in-use config was already attempted
*/
if (i == knet_h->crypto_in_use_config) {
continue;
}
if (knet_h->crypto_instance[i]) {
log_debug(knet_h, KNET_SUB_CRYPTO, "Alternative crypto configuration found, attempting to decrypt with config %u", i);
err = crypto_modules_cmds[knet_h->crypto_instance[i]->model].ops->decrypt(knet_h, knet_h->crypto_instance[i], buf_in, buf_in_len, buf_out, buf_out_len, KNET_LOG_ERR);
if (!err) {
errno = 0; /* clear errno from previous failures */
return err;
}
log_debug(knet_h, KNET_SUB_CRYPTO, "Packet failed to decrypt with crypto config %u", i);
}
}
}
return err;
}
static int crypto_use_config(
knet_handle_t knet_h,
uint8_t config_num)
{
if ((config_num) && (!knet_h->crypto_instance[config_num])) {
errno = EINVAL;
return -1;
}
knet_h->crypto_in_use_config = config_num;
if (config_num) {
knet_h->sec_block_size = knet_h->crypto_instance[config_num]->sec_block_size;
knet_h->sec_hash_size = knet_h->crypto_instance[config_num]->sec_hash_size;
knet_h->sec_salt_size = knet_h->crypto_instance[config_num]->sec_salt_size;
} else {
knet_h->sec_block_size = 0;
knet_h->sec_hash_size = 0;
knet_h->sec_salt_size = 0;
}
force_pmtud_run(knet_h, KNET_SUB_CRYPTO, 1);
return 0;
}
static int crypto_init(
knet_handle_t knet_h,
struct knet_handle_crypto_cfg *knet_handle_crypto_cfg,
uint8_t config_num)
{
int err = 0, savederrno = 0;
int model = 0;
struct crypto_instance *current = NULL, *new = NULL;
current = knet_h->crypto_instance[config_num];
model = crypto_get_model(knet_handle_crypto_cfg->crypto_model);
if (model < 0) {
log_err(knet_h, KNET_SUB_CRYPTO, "model %s not supported", knet_handle_crypto_cfg->crypto_model);
return -1;
}
if (crypto_modules_cmds[model].built_in == 0) {
log_err(knet_h, KNET_SUB_CRYPTO, "this version of libknet was built without %s support. Please contact your vendor or fix the build.", knet_handle_crypto_cfg->crypto_model);
return -1;
}
savederrno = pthread_rwlock_wrlock(&shlib_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_CRYPTO, "Unable to get write lock: %s",
strerror(savederrno));
return -1;
}
if (!crypto_modules_cmds[model].loaded) {
crypto_modules_cmds[model].ops = load_module (knet_h, "crypto", crypto_modules_cmds[model].model_name);
if (!crypto_modules_cmds[model].ops) {
savederrno = errno;
err = -1;
log_err(knet_h, KNET_SUB_CRYPTO, "Unable to load %s lib", crypto_modules_cmds[model].model_name);
goto out;
}
if (crypto_modules_cmds[model].ops->abi_ver != KNET_CRYPTO_MODEL_ABI) {
savederrno = EINVAL;
err = -1;
log_err(knet_h, KNET_SUB_CRYPTO,
"ABI mismatch loading module %s. knet ver: %d, module ver: %d",
crypto_modules_cmds[model].model_name, KNET_CRYPTO_MODEL_ABI,
crypto_modules_cmds[model].ops->abi_ver);
goto out;
}
crypto_modules_cmds[model].loaded = 1;
}
log_debug(knet_h, KNET_SUB_CRYPTO,
"Initizializing crypto module [%s/%s/%s]",
knet_handle_crypto_cfg->crypto_model,
knet_handle_crypto_cfg->crypto_cipher_type,
knet_handle_crypto_cfg->crypto_hash_type);
new = malloc(sizeof(struct crypto_instance));
if (!new) {
savederrno = ENOMEM;
err = -1;
log_err(knet_h, KNET_SUB_CRYPTO, "Unable to allocate memory for crypto instance");
goto out;
}
/*
* if crypto_modules_cmds.ops->init fails, it is expected that
* it will clean everything by itself.
* crypto_modules_cmds.ops->fini is not invoked on error.
*/
new->model = model;
if (crypto_modules_cmds[model].ops->init(knet_h, new, knet_handle_crypto_cfg)) {
savederrno = errno;
err = -1;
goto out;
}
out:
if (!err) {
knet_h->crypto_instance[config_num] = new;
if (current) {
/*
* if we are replacing the current config, we need to enable it right away
*/
if (knet_h->crypto_in_use_config == config_num) {
crypto_use_config(knet_h, config_num);
}
if (crypto_modules_cmds[current->model].ops->fini != NULL) {
crypto_modules_cmds[current->model].ops->fini(knet_h, current);
}
free(current);
}
} else {
if (new) {
free(new);
}
}
pthread_rwlock_unlock(&shlib_rwlock);
errno = err ? savederrno : 0;
return err;
}
static void crypto_fini_config(
knet_handle_t knet_h,
uint8_t config_num)
{
if (knet_h->crypto_instance[config_num]) {
if (crypto_modules_cmds[knet_h->crypto_instance[config_num]->model].ops->fini != NULL) {
crypto_modules_cmds[knet_h->crypto_instance[config_num]->model].ops->fini(knet_h, knet_h->crypto_instance[config_num]);
}
free(knet_h->crypto_instance[config_num]);
knet_h->crypto_instance[config_num] = NULL;
}
}
void crypto_fini(
knet_handle_t knet_h,
uint8_t config_num)
{
int savederrno = 0, i;
savederrno = pthread_rwlock_wrlock(&shlib_rwlock);
if (savederrno) {
log_err(knet_h, KNET_SUB_CRYPTO, "Unable to get write lock: %s",
strerror(savederrno));
return;
}
if (config_num > KNET_MAX_CRYPTO_INSTANCES) {
for (i = 1; i <= KNET_MAX_CRYPTO_INSTANCES; i++) {
crypto_fini_config(knet_h, i);
}
} else {
crypto_fini_config(knet_h, config_num);
}
pthread_rwlock_unlock(&shlib_rwlock);
return;
}
int knet_handle_crypto_set_config(knet_handle_t knet_h,
struct knet_handle_crypto_cfg *knet_handle_crypto_cfg,
uint8_t config_num)
{
int savederrno = 0;
int err = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (!knet_handle_crypto_cfg) {
errno = EINVAL;
return -1;
}
if ((config_num < 1) || (config_num > KNET_MAX_CRYPTO_INSTANCES)) {
errno = EINVAL;
return -1;
}
savederrno = get_global_wrlock(knet_h);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
if (knet_h->crypto_in_use_config == config_num) {
savederrno = EBUSY;
err = -1;
goto exit_unlock;
}
if ((!strncmp("none", knet_handle_crypto_cfg->crypto_model, 4)) ||
((!strncmp("none", knet_handle_crypto_cfg->crypto_cipher_type, 4)) &&
(!strncmp("none", knet_handle_crypto_cfg->crypto_hash_type, 4)))) {
crypto_fini(knet_h, config_num);
log_debug(knet_h, KNET_SUB_CRYPTO, "crypto config %u is not enabled", config_num);
err = 0;
goto exit_unlock;
}
if (knet_handle_crypto_cfg->private_key_len < KNET_MIN_KEY_LEN) {
log_debug(knet_h, KNET_SUB_CRYPTO, "private key len too short for config %u (min %d): %u",
config_num, KNET_MIN_KEY_LEN, knet_handle_crypto_cfg->private_key_len);
savederrno = EINVAL;
err = -1;
goto exit_unlock;
}
if (knet_handle_crypto_cfg->private_key_len > KNET_MAX_KEY_LEN) {
log_debug(knet_h, KNET_SUB_CRYPTO, "private key len too long for config %u (max %d): %u",
config_num, KNET_MAX_KEY_LEN, knet_handle_crypto_cfg->private_key_len);
savederrno = EINVAL;
err = -1;
goto exit_unlock;
}
err = crypto_init(knet_h, knet_handle_crypto_cfg, config_num);
if (err) {
err = -2;
savederrno = errno;
}
exit_unlock:
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = err ? savederrno : 0;
return err;
}
int knet_handle_crypto_rx_clear_traffic(knet_handle_t knet_h,
uint8_t value)
{
int savederrno = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (value > KNET_CRYPTO_RX_DISALLOW_CLEAR_TRAFFIC) {
errno = EINVAL;
return -1;
}
savederrno = get_global_wrlock(knet_h);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
knet_h->crypto_only = value;
if (knet_h->crypto_only) {
log_debug(knet_h, KNET_SUB_CRYPTO, "Only crypto traffic allowed for RX");
} else {
log_debug(knet_h, KNET_SUB_CRYPTO, "Both crypto and clear traffic allowed for RX");
}
pthread_rwlock_unlock(&knet_h->global_rwlock);
return 0;
}
int knet_handle_crypto_use_config(knet_handle_t knet_h,
uint8_t config_num)
{
int savederrno = 0;
int err = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (config_num > KNET_MAX_CRYPTO_INSTANCES) {
errno = EINVAL;
return -1;
}
savederrno = get_global_wrlock(knet_h);
if (savederrno) {
log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
err = crypto_use_config(knet_h, config_num);
savederrno = errno;
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = err ? savederrno : 0;
return err;
}
int knet_get_crypto_list(struct knet_crypto_info *crypto_list, size_t *crypto_list_entries)
{
int err = 0;
int idx = 0;
int outidx = 0;
if (!crypto_list_entries) {
errno = EINVAL;
return -1;
}
while (crypto_modules_cmds[idx].model_name != NULL) {
if (crypto_modules_cmds[idx].built_in) {
if (crypto_list) {
crypto_list[outidx].name = crypto_modules_cmds[idx].model_name;
}
outidx++;
}
idx++;
}
*crypto_list_entries = outidx;
if (!err)
errno = 0;
return err;
}
diff --git a/libknet/crypto_gcrypt.c b/libknet/crypto_gcrypt.c
new file mode 100644
index 00000000..11c83ad8
--- /dev/null
+++ b/libknet/crypto_gcrypt.c
@@ -0,0 +1,598 @@
+/*
+ * Copyright (C) 2017-2020 Red Hat, Inc. All rights reserved.
+ *
+ * Author: Fabio M. Di Nitto <fabbione@kronosnet.org>
+ *
+ * This software licensed under LGPL-2.0+
+ */
+#define KNET_MODULE
+
+#include "config.h"
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/*
+ * make sure NOT to use deprecated API
+ */
+#define GCRYPTO_NO_DEPRECATED 1
+
+#define NEED_LIBGCRYPT_VERSION "1.8.0"
+
+#include <gcrypt.h>
+
+#include "logging.h"
+#include "crypto_model.h"
+
+/*
+ * crypto definitions and conversion tables
+ */
+
+#define SALT_SIZE 16
+
+/*
+ * gcrypt rejects private key len > crypto max keylen. openssl/nss automatically trim the key.
+ * we need to store a crypto key len and a hash keylen separately
+ * and crypto key len is trimmed automatically at gcrypt_init time.
+ */
+
+struct gcryptcrypto_instance {
+ void *private_key;
+ size_t crypt_private_key_len;
+ size_t hash_private_key_len;
+ int crypto_cipher_type;
+ int crypto_hash_type;
+};
+
+static int gcrypt_is_init = 0;
+
+/*
+ * crypt/decrypt functions
+ */
+
+static int encrypt_gcrypt(
+ knet_handle_t knet_h,
+ struct crypto_instance *crypto_instance,
+ const struct iovec *iov,
+ int iovcnt,
+ unsigned char *buf_out,
+ ssize_t *buf_out_len)
+{
+ struct gcryptcrypto_instance *instance = crypto_instance->model_instance;
+ gcry_error_t gerr;
+ gcry_cipher_hd_t handle = NULL;
+ int err = 0;
+ int i;
+ unsigned char *salt = buf_out;
+ size_t output_len = 0, pad_len = 0;
+ unsigned char inbuf[KNET_DATABUFSIZE_CRYPT];
+ unsigned char *data = buf_out + SALT_SIZE;
+
+ gerr = gcry_cipher_open(&handle, instance->crypto_cipher_type, GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_SECURE);
+ if (gerr) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "Unable to allocate gcrypt cipher context: %s/%s",
+ gcry_strsource(gerr), gcry_strerror(gerr));
+ err = -1;
+ goto out_err;
+ }
+
+ gerr = gcry_cipher_setkey(handle, instance->private_key, instance->crypt_private_key_len);
+ if (gerr) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "Unable to load private key: %s/%s",
+ gcry_strsource(gerr), gcry_strerror(gerr));
+ err = -1;
+ goto out_err;
+ }
+
+ gcry_randomize(salt, SALT_SIZE, GCRY_VERY_STRONG_RANDOM);
+
+ gerr = gcry_cipher_setiv(handle, salt, SALT_SIZE);
+ if (gerr) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "Unable to load init vector: %s/%s",
+ gcry_strsource(gerr), gcry_strerror(gerr));
+ err = -1;
+ goto out_err;
+ }
+
+ /*
+ * libgcrypt requires an input buffer that is
+ * already aligned to block size.
+ * The easiest way is to build the data in
+ * a dedicated buffer
+ */
+ output_len = 0;
+ for (i=0; i<iovcnt; i++) {
+ memcpy(inbuf + output_len, iov[i].iov_base, iov[i].iov_len);
+ output_len = output_len + iov[i].iov_len;
+ }
+
+ /*
+ * init the pad buffer (PKCS# standard)
+ * https://en.m.wikipedia.org/wiki/Padding_(cryptography)
+ */
+
+ pad_len = (crypto_instance->sec_block_size - (output_len % crypto_instance->sec_block_size));
+
+ memset(inbuf + output_len, pad_len, pad_len);
+
+ output_len = output_len + pad_len;
+
+ /*
+ * some ciphers methods require _final to be called
+ * before the last call to _encrypt, for example when
+ * encrypting big chunks of data split in multiple buffers.
+ * knet only has one buffer, so we can safely call _final here.
+ * adding a comment as the code looks backwards compared to other
+ * cipher implementations that do final _after_ encrypting the last block
+ */
+ gcry_cipher_final(handle);
+
+ gerr = gcry_cipher_encrypt(handle,
+ data, output_len,
+ inbuf, output_len);
+ if (gerr) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "Unable to encrypt data: %s/%s",
+ gcry_strsource(gerr), gcry_strerror(gerr));
+ err = -1;
+ goto out_err;
+ }
+
+ *buf_out_len = output_len + SALT_SIZE;
+
+out_err:
+ if (handle) {
+ gcry_cipher_close(handle);
+ }
+ return err;
+}
+
+static int decrypt_gcrypt(
+ knet_handle_t knet_h,
+ struct crypto_instance *crypto_instance,
+ const unsigned char *buf_in,
+ const ssize_t buf_in_len,
+ unsigned char *buf_out,
+ ssize_t *buf_out_len,
+ uint8_t log_level)
+{
+ struct gcryptcrypto_instance *instance = crypto_instance->model_instance;
+ gcry_error_t gerr;
+ gcry_cipher_hd_t handle = NULL;
+ unsigned char *salt = (unsigned char *)buf_in;
+ unsigned char *data = salt + SALT_SIZE;
+ int datalen = buf_in_len - SALT_SIZE;
+ int err = 0;
+
+ if (datalen <= 0) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "Packet is too short");
+ err = -1;
+ goto out_err;
+ }
+
+ gerr = gcry_cipher_open(&handle, instance->crypto_cipher_type, GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_SECURE);
+ if (gerr) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "Unable to allocate gcrypt cipher context: %s/%s",
+ gcry_strsource(gerr), gcry_strerror(gerr));
+ err = -1;
+ goto out_err;
+ }
+
+ gerr = gcry_cipher_setkey(handle, instance->private_key, instance->crypt_private_key_len);
+ if (gerr) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "Unable to load private key: %s/%s",
+ gcry_strsource(gerr), gcry_strerror(gerr));
+ err = -1;
+ goto out_err;
+ }
+
+ gerr = gcry_cipher_setiv(handle, salt, SALT_SIZE);
+ if (gerr) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "Unable to load init vector: %s/%s",
+ gcry_strsource(gerr), gcry_strerror(gerr));
+ err = -1;
+ goto out_err;
+ }
+
+ gerr = gcry_cipher_decrypt(handle,
+ buf_out, KNET_DATABUFSIZE_CRYPT,
+ data, datalen);
+ if (gerr) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "Unable to decrypt data: %s/%s",
+ gcry_strsource(gerr), gcry_strerror(gerr));
+ err = -1;
+ goto out_err;
+ }
+
+ /*
+ * drop the padding size based on PCKS standards
+ * (see also crypt above)
+ */
+ *buf_out_len = datalen - buf_out[datalen - 1];
+
+out_err:
+ if (handle) {
+ gcry_cipher_close(handle);
+ }
+ return err;
+}
+
+/*
+ * hash/hmac/digest functions
+ */
+
+static int calculate_gcrypt_hash(
+ knet_handle_t knet_h,
+ struct crypto_instance *crypto_instance,
+ const unsigned char *buf,
+ const size_t buf_len,
+ unsigned char *hash,
+ uint8_t log_level)
+{
+ struct gcryptcrypto_instance *instance = crypto_instance->model_instance;
+ gcry_error_t gerr;
+ gcry_mac_hd_t handle = NULL;
+ int err = 0;
+ size_t outlen = crypto_instance->sec_hash_size;
+
+ gerr = gcry_mac_open(&handle, instance->crypto_hash_type, GCRY_MAC_FLAG_SECURE, 0);
+ if (gerr) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "Unable to allocate gcrypt hmac context: %s/%s",
+ gcry_strsource(gerr), gcry_strerror(gerr));
+ err = -1;
+ goto out_err;
+ }
+
+ gerr = gcry_mac_setkey(handle, instance->private_key, instance->hash_private_key_len);
+ if (gerr) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "Unable to set gcrypt hmac key: %s/%s",
+ gcry_strsource(gerr), gcry_strerror(gerr));
+ err = -1;
+ goto out_err;
+ }
+
+ gerr = gcry_mac_write(handle, buf, buf_len);
+ if (gerr) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "Unable to calculate gcrypt hmac: %s/%s",
+ gcry_strsource(gerr), gcry_strerror(gerr));
+ err = -1;
+ goto out_err;
+ }
+
+ gerr = gcry_mac_read(handle, hash, &outlen);
+ if (gerr) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "Unable to retrive gcrypt hmac: %s/%s",
+ gcry_strsource(gerr), gcry_strerror(gerr));
+ err = -1;
+ goto out_err;
+ }
+
+out_err:
+ if (handle) {
+ gcry_mac_close(handle);
+ }
+
+ return err;
+}
+
+/*
+ * exported API
+ */
+
+static int gcryptcrypto_encrypt_and_signv (
+ knet_handle_t knet_h,
+ struct crypto_instance *crypto_instance,
+ const struct iovec *iov_in,
+ int iovcnt_in,
+ unsigned char *buf_out,
+ ssize_t *buf_out_len)
+{
+ struct gcryptcrypto_instance *instance = crypto_instance->model_instance;
+ int i;
+
+ if (instance->crypto_cipher_type) {
+ if (encrypt_gcrypt(knet_h, crypto_instance, iov_in, iovcnt_in, buf_out, buf_out_len) < 0) {
+ return -1;
+ }
+ } else {
+ *buf_out_len = 0;
+ for (i=0; i<iovcnt_in; i++) {
+ memmove(buf_out + *buf_out_len, iov_in[i].iov_base, iov_in[i].iov_len);
+ *buf_out_len = *buf_out_len + iov_in[i].iov_len;
+ }
+ }
+
+ if (instance->crypto_hash_type) {
+ if (calculate_gcrypt_hash(knet_h, crypto_instance, buf_out, *buf_out_len, buf_out + *buf_out_len, KNET_LOG_ERR) < 0) {
+ return -1;
+ }
+ *buf_out_len = *buf_out_len + crypto_instance->sec_hash_size;
+ }
+
+ return 0;
+}
+
+static int gcryptcrypto_encrypt_and_sign (
+ knet_handle_t knet_h,
+ struct crypto_instance *crypto_instance,
+ const unsigned char *buf_in,
+ const ssize_t buf_in_len,
+ unsigned char *buf_out,
+ ssize_t *buf_out_len)
+{
+ struct iovec iov_in;
+
+ memset(&iov_in, 0, sizeof(iov_in));
+ iov_in.iov_base = (unsigned char *)buf_in;
+ iov_in.iov_len = buf_in_len;
+
+ return gcryptcrypto_encrypt_and_signv(knet_h, crypto_instance, &iov_in, 1, buf_out, buf_out_len);
+}
+
+static int gcryptcrypto_authenticate_and_decrypt (
+ knet_handle_t knet_h,
+ struct crypto_instance *crypto_instance,
+ const unsigned char *buf_in,
+ const ssize_t buf_in_len,
+ unsigned char *buf_out,
+ ssize_t *buf_out_len,
+ uint8_t log_level)
+{
+ struct gcryptcrypto_instance *instance = crypto_instance->model_instance;
+ ssize_t temp_len = buf_in_len;
+
+ if (instance->crypto_hash_type) {
+ unsigned char tmp_hash[crypto_instance->sec_hash_size];
+ ssize_t temp_buf_len = buf_in_len - crypto_instance->sec_hash_size;
+
+ if ((temp_buf_len <= 0) || (temp_buf_len > KNET_MAX_PACKET_SIZE)) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "Incorrect packet size.");
+ return -1;
+ }
+
+ if (calculate_gcrypt_hash(knet_h, crypto_instance, buf_in, temp_buf_len, tmp_hash, log_level) < 0) {
+ return -1;
+ }
+
+ if (memcmp(tmp_hash, buf_in + temp_buf_len, crypto_instance->sec_hash_size) != 0) {
+ if (log_level == KNET_LOG_DEBUG) {
+ log_debug(knet_h, KNET_SUB_GCRYPTCRYPTO, "Digest does not match");
+ } else {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "Digest does not match");
+ }
+ return -1;
+ }
+
+ temp_len = temp_len - crypto_instance->sec_hash_size;
+ *buf_out_len = temp_len;
+ }
+ if (instance->crypto_cipher_type) {
+ if (decrypt_gcrypt(knet_h, crypto_instance, buf_in, temp_len, buf_out, buf_out_len, log_level) < 0) {
+ return -1;
+ }
+ } else {
+ memmove(buf_out, buf_in, temp_len);
+ *buf_out_len = temp_len;
+ }
+
+ return 0;
+}
+
+static void gcryptcrypto_fini(
+ knet_handle_t knet_h,
+ struct crypto_instance *crypto_instance)
+{
+ struct gcryptcrypto_instance *gcryptcrypto_instance = crypto_instance->model_instance;
+
+ if (gcryptcrypto_instance) {
+ if (gcryptcrypto_instance->private_key) {
+ free(gcryptcrypto_instance->private_key);
+ gcryptcrypto_instance->private_key = NULL;
+ }
+ free(gcryptcrypto_instance);
+ crypto_instance->model_instance = NULL;
+ }
+
+ return;
+}
+
+static int gcryptcrypto_init(
+ knet_handle_t knet_h,
+ struct crypto_instance *crypto_instance,
+ struct knet_handle_crypto_cfg *knet_handle_crypto_cfg)
+{
+ struct gcryptcrypto_instance *gcryptcrypto_instance = NULL;
+ gcry_error_t gerr;
+ int savederrno;
+ /*
+ * gcrypt name to ID mapping requires HMAC_ in the name.
+ * so for example to use SHA1, the name should be HMAC_SHA1
+ * that makes it not compatible with nss/openssl naming.
+ * make sure to add HMAC_ transparently so that changing crypto config
+ * can be done transparently.
+ */
+ char remap_hash_type[sizeof(knet_handle_crypto_cfg->crypto_hash_type) + strlen("HMAC_") + 1];
+
+ log_debug(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "Initizializing gcrypt crypto module [%s/%s]",
+ knet_handle_crypto_cfg->crypto_cipher_type,
+ knet_handle_crypto_cfg->crypto_hash_type);
+
+ if (!gcrypt_is_init) {
+ if (!gcry_check_version(NEED_LIBGCRYPT_VERSION)) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "libgcrypt is too old (need %s, have %s)",
+ NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL));
+ errno = EINVAL;
+ return -1;
+ }
+
+ gerr = gcry_control(GCRYCTL_SUSPEND_SECMEM_WARN);
+ if (gerr) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "Unable to suppress sec mem warnings: %s/%s",
+ gcry_strsource(gerr), gcry_strerror(gerr));
+ errno = EINVAL;
+ return -1;
+ }
+
+ gerr = gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0);
+ if (gerr) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "Unable to init sec mem: %s/%s",
+ gcry_strsource(gerr), gcry_strerror(gerr));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ gerr = gcry_control(GCRYCTL_RESUME_SECMEM_WARN);
+ if (gerr) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "Unable to restore sec mem warnings: %s/%s",
+ gcry_strsource(gerr), gcry_strerror(gerr));
+ errno = EINVAL;
+ return -1;
+ }
+
+ gerr = gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
+ if (gerr) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "Unable to notify gcrypt that init is completed: %s/%s",
+ gcry_strsource(gerr), gcry_strerror(gerr));
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO,
+ "gcrypt could not initialize properly");
+ errno = EINVAL;
+ return -1;
+ }
+
+ gcrypt_is_init = 1;
+ }
+
+ crypto_instance->model_instance = malloc(sizeof(struct gcryptcrypto_instance));
+ if (!crypto_instance->model_instance) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "Unable to allocate memory for gcrypt model instance");
+ errno = ENOMEM;
+ return -1;
+ }
+
+ gcryptcrypto_instance = crypto_instance->model_instance;
+
+ memset(gcryptcrypto_instance, 0, sizeof(struct gcryptcrypto_instance));
+
+ gcryptcrypto_instance->private_key = malloc(knet_handle_crypto_cfg->private_key_len);
+ if (!gcryptcrypto_instance->private_key) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "Unable to allocate memory for gcrypt private key");
+ savederrno = ENOMEM;
+ goto out_err;
+ }
+ memmove(gcryptcrypto_instance->private_key, knet_handle_crypto_cfg->private_key, knet_handle_crypto_cfg->private_key_len);
+
+ if (strcmp(knet_handle_crypto_cfg->crypto_cipher_type, "none") == 0) {
+ gcryptcrypto_instance->crypto_cipher_type = 0;
+ } else {
+ gcryptcrypto_instance->crypto_cipher_type = gcry_cipher_map_name(knet_handle_crypto_cfg->crypto_cipher_type);
+ if (!gcryptcrypto_instance->crypto_cipher_type) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "unknown crypto cipher type requested");
+ savederrno = EINVAL;
+ goto out_err;
+ }
+ if (gcry_cipher_test_algo(gcryptcrypto_instance->crypto_cipher_type)) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "requested crypto cipher type not available for use");
+ savederrno = EINVAL;
+ goto out_err;
+ }
+ if (gcry_cipher_get_algo_keylen(gcryptcrypto_instance->crypto_cipher_type) < knet_handle_crypto_cfg->private_key_len) {
+ log_warn(knet_h, KNET_SUB_GCRYPTCRYPTO, "requested crypto cipher key len (%u) too big (max: %zu)",
+ knet_handle_crypto_cfg->private_key_len, gcry_cipher_get_algo_keylen(gcryptcrypto_instance->crypto_cipher_type));
+ gcryptcrypto_instance->crypt_private_key_len = gcry_cipher_get_algo_keylen(gcryptcrypto_instance->crypto_cipher_type);
+ } else {
+ gcryptcrypto_instance->crypt_private_key_len = knet_handle_crypto_cfg->private_key_len;
+ }
+
+ }
+
+ if (strcmp(knet_handle_crypto_cfg->crypto_hash_type, "none") == 0) {
+ gcryptcrypto_instance->crypto_hash_type = 0;
+ } else {
+ if (!strncasecmp(knet_handle_crypto_cfg->crypto_hash_type, "HMAC_", strlen("HMAC_"))) {
+ strncpy(remap_hash_type, knet_handle_crypto_cfg->crypto_hash_type, sizeof(remap_hash_type) - 1);
+ } else {
+ snprintf(remap_hash_type, sizeof(remap_hash_type) - 1, "%s%s", "HMAC_", knet_handle_crypto_cfg->crypto_hash_type);
+ }
+ gcryptcrypto_instance->crypto_hash_type = gcry_mac_map_name(remap_hash_type);
+ if (!gcryptcrypto_instance->crypto_hash_type) {
+ savederrno = EINVAL;
+ goto out_err;
+ }
+ if (gcry_mac_test_algo(gcryptcrypto_instance->crypto_hash_type)) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "requested crypto hash type not available for use");
+ savederrno = EINVAL;
+ goto out_err;
+ }
+ gcryptcrypto_instance->hash_private_key_len = knet_handle_crypto_cfg->private_key_len;
+ }
+
+ if ((gcryptcrypto_instance->crypto_cipher_type) &&
+ (!gcryptcrypto_instance->crypto_hash_type)) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "crypto communication requires hash specified");
+ savederrno = EINVAL;
+ goto out_err;
+ }
+
+ if (gcryptcrypto_instance->crypto_hash_type) {
+ crypto_instance->sec_hash_size = gcry_mac_get_algo_maclen(gcryptcrypto_instance->crypto_hash_type);
+ if (!crypto_instance->sec_hash_size) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "unable to gather hash digest size");
+ savederrno = EINVAL;
+ goto out_err;
+ }
+ }
+
+ if (gcryptcrypto_instance->crypto_cipher_type) {
+ size_t block_size;
+
+ block_size = gcry_cipher_get_algo_blklen(gcryptcrypto_instance->crypto_cipher_type);
+ if (!block_size) {
+ log_err(knet_h, KNET_SUB_GCRYPTCRYPTO, "unable to gather cipher blocksize");
+ savederrno = EINVAL;
+ goto out_err;
+ }
+
+ crypto_instance->sec_salt_size = SALT_SIZE;
+ crypto_instance->sec_block_size = block_size;
+ }
+
+ return 0;
+
+out_err:
+ gcryptcrypto_fini(knet_h, crypto_instance);
+
+ errno = savederrno;
+ return -1;
+}
+
+crypto_ops_t crypto_model = {
+ KNET_CRYPTO_MODEL_ABI,
+ gcryptcrypto_init,
+ gcryptcrypto_fini,
+ gcryptcrypto_encrypt_and_sign,
+ gcryptcrypto_encrypt_and_signv,
+ gcryptcrypto_authenticate_and_decrypt
+};
diff --git a/libknet/libknet.h b/libknet/libknet.h
index ce76ef41..d5d5e833 100644
--- a/libknet/libknet.h
+++ b/libknet/libknet.h
@@ -1,2456 +1,2457 @@
/*
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
*
* Authors: Fabio M. Di Nitto <fabbione@kronosnet.org>
* Federico Simoncelli <fsimon@kronosnet.org>
*
* This software licensed under LGPL-2.0+
*/
#ifndef __LIBKNET_H__
#define __LIBKNET_H__
#include <stdint.h>
#include <time.h>
#include <netinet/in.h>
#include <unistd.h>
#include <limits.h>
/**
* @file libknet.h
* @brief kronosnet API include file
* @copyright Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
*
* Kronosnet is an advanced VPN system for High Availability applications.
*/
#define KNET_API_VER 2
/*
* libknet limits
*/
/*
* Maximum number of hosts
*/
typedef uint16_t knet_node_id_t;
#define KNET_MAX_HOST 65536
/*
* Maximum number of links between 2 hosts
*/
#define KNET_MAX_LINK 8
/*
* Maximum packet size that should be written to datafd
* see knet_handle_new for details
*/
#define KNET_MAX_PACKET_SIZE 65536
/*
* Buffers used for pretty logging
* host is used to store both ip addresses and hostnames
*/
#define KNET_MAX_HOST_LEN 256
#define KNET_MAX_PORT_LEN 6
/*
* Some notifications can be generated either on TX or RX
*/
#define KNET_NOTIFY_TX 0
#define KNET_NOTIFY_RX 1
/*
* Link flags
*/
/*
* Where possible, set traffic priority to high.
* On Linux this sets the TOS to INTERACTIVE (6),
* see tc-prio(8) for more infomation
*/
#define KNET_LINK_FLAG_TRAFFICHIPRIO (1ULL << 0)
/*
* Handle flags
*/
/*
* Use privileged operations during socket setup.
*/
#define KNET_HANDLE_FLAG_PRIVILEGED (1ULL << 0)
/*
* threads timer resolution (see knet_handle_set_threads_timer_res below)
*/
#define KNET_THREADS_TIMER_RES 200000
typedef struct knet_handle *knet_handle_t;
/*
* Handle structs/API calls
*/
/**
* knet_handle_new
*
* @brief create a new instance of a knet handle
*
* host_id - Each host in a knet is identified with a unique
* ID. when creating a new handle local host_id
* must be specified (0 to UINT16_MAX are all valid).
* It is the user's responsibility to check that the value
* is unique, or bad things might happen.
*
* log_fd - Write file descriptor. If set to a value > 0, it will be used
* to write log packets from libknet to the application.
* Setting to 0 will disable logging from libknet.
* It is possible to enable logging at any given time (see logging API).
* Make sure to either read from this filedescriptor properly and/or
* mark it O_NONBLOCK, otherwise if the fd becomes full, libknet could
* block.
* It is strongly encouraged to use pipes (ex: pipe(2) or pipe2(2)) for
* logging fds due to the atomic nature of writes between fds.
* See also libknet test suite for reference and guidance.
*
* default_log_level -
* If logfd is specified, it will initialize all subsystems to log
* at default_log_level value. (see logging API)
*
* flags - bitwise OR of some of the following flags:
* KNET_HANDLE_FLAG_PRIVILEGED: use privileged operations setting up the
* communication sockets. If disabled, failure to acquire large
* enough socket buffers is ignored but logged. Inadequate buffers
* lead to poor performance.
*
* @return
* on success, a new knet_handle_t is returned.
* on failure, NULL is returned and errno is set.
* knet-specific errno values:
* ENAMETOOLONG - socket buffers couldn't be set big enough and KNET_HANDLE_FLAG_PRIVILEGED was specified
* ERANGE - buffer size readback returned unexpected type
*/
knet_handle_t knet_handle_new(knet_node_id_t host_id,
int log_fd,
uint8_t default_log_level,
uint64_t flags);
/**
* knet_handle_free
*
* @brief Destroy a knet handle, free all resources
*
* knet_h - pointer to knet_handle_t
*
* @return
* knet_handle_free returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_free(knet_handle_t knet_h);
/**
* knet_handle_set_threads_timer_res
*
* @brief Change internal thread timer resolution
*
* knet_h - pointer to knet_handle_t
*
* timeres - some threads inside knet will use usleep(timeres)
* to check if any activity has to be performed, or wait
* for the next cycle. 'timeres' (expressed in nano seconds)
* defines this interval, with a default of KNET_THREADS_TIMER_RES
* (200000).
* The lower this value is, the more often knet will perform
* those checks and allows a more (time) precise execution of
* some operations (for example ping/pong), at the cost of higher
* CPU usage.
* Accepted values:
* 0 - reset timer res to default
* 1 - 999 invalid (as it would cause 100% CPU spinning on some
* epoll operations)
* 1000 or higher - valid
*
* Unless you know exactly what you are doing, stay away from
* changing the default or seek written and notarized approval
* from the knet developer team.
*
* @return
* knet_handle_set_threads_timer_res returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_set_threads_timer_res(knet_handle_t knet_h,
useconds_t timeres);
/**
* knet_handle_get_threads_timer_res
*
* @brief Get internal thread timer resolutions
*
* knet_h - pointer to knet_handle_t
*
* timeres - current timer res value
*
* @return
* knet_handle_set_threads_timer_res returns
* 0 on success and timerres will contain the current value
* -1 on error and errno is set.
*/
int knet_handle_get_threads_timer_res(knet_handle_t knet_h,
useconds_t *timeres);
/**
* knet_handle_enable_sock_notify
*
* @brief Register a callback to receive socket events
*
* knet_h - pointer to knet_handle_t
*
* sock_notify_fn_private_data
* void pointer to data that can be used to identify
* the callback.
*
* sock_notify_fn
* A callback function that is invoked every time
* a socket in the datafd pool will report an error (-1)
* or an end of read (0) (see socket.7).
* This function MUST NEVER block or add substantial delays.
* The callback is invoked in an internal unlocked area
* to allow calls to knet_handle_add_datafd/knet_handle_remove_datafd
* to swap/replace the bad fd.
* if both err and errno are 0, it means that the socket
* has received a 0 byte packet (EOF?).
* The callback function must either remove the fd from knet
* (by calling knet_handle_remove_fd()) or dup a new fd in its place.
* Failure to do this can cause problems.
*
* @return
* knet_handle_enable_sock_notify returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_enable_sock_notify(knet_handle_t knet_h,
void *sock_notify_fn_private_data,
void (*sock_notify_fn) (
void *private_data,
int datafd,
int8_t channel,
uint8_t tx_rx,
int error,
int errorno)); /* sorry! can't call it errno ;) */
#define KNET_DATAFD_MAX 32
/**
* knet_handle_add_datafd
*
* @brief Install a file descriptor for communication
*
* IMPORTANT: In order to add datafd to knet, knet_handle_enable_sock_notify
* _MUST_ be set and be able to handle both errors (-1) and
* 0 bytes read / write from the provided datafd.
* On read error (< 0) from datafd, the socket is automatically
* removed from polling to avoid spinning on dead sockets.
* It is safe to call knet_handle_remove_datafd even on sockets
* that have been removed.
*
* knet_h - pointer to knet_handle_t
*
* *datafd - read/write file descriptor.
* knet will read data here to send to the other hosts
* and will write data received from the network.
* Each data packet can be of max size KNET_MAX_PACKET_SIZE!
* Applications using knet_send/knet_recv will receive a
* proper error if the packet size is not within boundaries.
* Applications using their own functions to write to the
* datafd should NOT write more than KNET_MAX_PACKET_SIZE.
*
* Please refer to handle.c on how to set up a socketpair.
*
* datafd can be 0, and knet_handle_add_datafd will create a properly
* populated socket pair the same way as ping_test, or a value
* higher than 0. A negative number will return an error.
* On exit knet_handle_free will take care to cleanup the
* socketpair only if they have been created by knet_handle_add_datafd.
*
* It is possible to pass either sockets or normal fds.
* User provided datafd will be marked as non-blocking and close-on-exec.
*
* *channel - This value is analogous to the tag in VLAN tagging.
* A negative value will auto-allocate a channel.
* Setting a value between 0 and 31 will try to allocate that
* specific channel (unless already in use).
*
* It is possible to add up to 32 datafds but be aware that each
* one of them must have a receiving end on the other host.
*
* Example:
* hostA channel 0 will be delivered to datafd on hostB channel 0
* hostA channel 1 to hostB channel 1.
*
* Each channel must have a unique file descriptor.
*
* If your application could have 2 channels on one host and one
* channel on another host, then you can use dst_host_filter
* to manipulate channel values on TX and RX.
*
* @return
* knet_handle_add_datafd returns
* @retval 0 on success,
* *datafd will be populated with a socket if the original value was 0
* or if a specific fd was set, the value is untouched.
* *channel will be populated with a channel number if the original value
* was negative or the value is untouched if a specific channel
* was requested.
*
* @retval -1 on error and errno is set.
* *datafd and *channel are untouched or empty.
*/
int knet_handle_add_datafd(knet_handle_t knet_h, int *datafd, int8_t *channel);
/**
* knet_handle_remove_datafd
*
* @brief Remove a file descriptor from knet
*
* knet_h - pointer to knet_handle_t
*
* datafd - file descriptor to remove.
* NOTE that if the socket/fd was created by knet_handle_add_datafd,
* the socket will be closed by libknet.
*
* @return
* knet_handle_remove_datafd returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_remove_datafd(knet_handle_t knet_h, int datafd);
/**
* knet_handle_get_channel
*
* @brief Get the channel associated with a file descriptor
*
* knet_h - pointer to knet_handle_t
*
* datafd - get the channel associated to this datafd
*
* *channel - will contain the result
*
* @return
* knet_handle_get_channel returns
* @retval 0 on success
* and *channel will contain the result
* @retval -1 on error and errno is set.
* and *channel content is meaningless
*/
int knet_handle_get_channel(knet_handle_t knet_h, const int datafd, int8_t *channel);
/**
* knet_handle_get_datafd
*
* @brief Get the file descriptor associated with a channel
*
* knet_h - pointer to knet_handle_t
*
* channel - get the datafd associated to this channel
*
* *datafd - will contain the result
*
* @return
* knet_handle_get_datafd returns
* @retval 0 on success
* and *datafd will contain the results
* @retval -1 on error and errno is set.
* and *datafd content is meaningless
*/
int knet_handle_get_datafd(knet_handle_t knet_h, const int8_t channel, int *datafd);
/**
* knet_recv
*
* @brief Receive data from knet nodes
*
* knet_h - pointer to knet_handle_t
*
* buff - pointer to buffer to store the received data
*
* buff_len - buffer length
*
* channel - channel number
*
* @return
* knet_recv is a commodity function to wrap iovec operations
* around a socket. It returns a call to readv(2).
*/
ssize_t knet_recv(knet_handle_t knet_h,
char *buff,
const size_t buff_len,
const int8_t channel);
/**
* knet_send
*
* @brief Send data to knet nodes
*
* knet_h - pointer to knet_handle_t
*
* buff - pointer to the buffer of data to send
*
* buff_len - length of data to send
*
* channel - channel number
*
* @return
* knet_send is a commodity function to wrap iovec operations
* around a socket. It returns a call to writev(2).
*/
ssize_t knet_send(knet_handle_t knet_h,
const char *buff,
const size_t buff_len,
const int8_t channel);
/**
* knet_send_sync
*
* @brief Synchronously send data to knet nodes
*
* knet_h - pointer to knet_handle_t
*
* buff - pointer to the buffer of data to send
*
* buff_len - length of data to send
*
* channel - data channel to use (see knet_handle_add_datafd(3))
*
* All knet RX/TX operations are async for performance reasons.
* There are applications that might need a sync version of data
* transmission and receive errors in case of failure to deliver
* to another host.
* knet_send_sync bypasses the whole TX async layer and delivers
* data directly to the link layer, and returns errors accordingly.
* knet_send_sync sends only one packet to one host at a time.
* It does NOT support multiple destinations or multicast packets.
* Decision is still based on dst_host_filter_fn.
*
* @return
* knet_send_sync returns 0 on success and -1 on error.
* In addition to normal sendmmsg errors, knet_send_sync can fail
* due to:
*
* @retval ECANCELED - data forward is disabled
* @retval EFAULT - dst_host_filter fatal error
* @retval EINVAL - dst_host_filter did not provide dst_host_ids_entries on unicast pckts
* @retval E2BIG - dst_host_filter did return more than one dst_host_ids_entries on unicast pckts
* @retval ENOMSG - received unknown message type
* @retval EHOSTDOWN - unicast pckt cannot be delivered because dest host is not connected yet
* @retval ECHILD - crypto failed
* @retval EAGAIN - sendmmsg was unable to send all messages and there was no progress during retry
*/
int knet_send_sync(knet_handle_t knet_h,
const char *buff,
const size_t buff_len,
const int8_t channel);
/**
* knet_handle_enable_filter
*
* @brief install a filter to route packets
*
* knet_h - pointer to knet_handle_t
*
* dst_host_filter_fn_private_data
* void pointer to data that can be used to identify
* the callback.
*
* dst_host_filter_fn -
* is a callback function that is invoked every time
* a packet hits datafd (see knet_handle_new(3)).
* the function allows users to tell libknet where the
* packet has to be delivered.
*
* const unsigned char *outdata - is a pointer to the
* current packet
* ssize_t outdata_len - length of the above data
* uint8_t tx_rx - filter is called on tx or rx
* (KNET_NOTIFY_TX, KNET_NOTIFY_RX)
* knet_node_id_t this_host_id - host_id processing the packet
* knet_node_id_t src_host_id - host_id that generated the
* packet
* knet_node_id_t *dst_host_ids - array of KNET_MAX_HOST knet_node_id_t
* where to store the destinations
* size_t *dst_host_ids_entries - number of hosts to send the message
*
* dst_host_filter_fn should return
* -1 on error, packet is discarded.
* 0 packet is unicast and should be sent to dst_host_ids and there are
* dst_host_ids_entries in the buffer.
* 1 packet is broadcast/multicast and is sent all hosts.
* contents of dst_host_ids and dst_host_ids_entries are ignored.
*
* @return
* knet_handle_enable_filter returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_enable_filter(knet_handle_t knet_h,
void *dst_host_filter_fn_private_data,
int (*dst_host_filter_fn) (
void *private_data,
const unsigned char *outdata,
ssize_t outdata_len,
uint8_t tx_rx,
knet_node_id_t this_host_id,
knet_node_id_t src_host_id,
int8_t *channel,
knet_node_id_t *dst_host_ids,
size_t *dst_host_ids_entries));
/**
* knet_handle_setfwd
*
* @brief Start packet forwarding
*
* knet_h - pointer to knet_handle_t
*
* enable - set to 1 to allow data forwarding, 0 to disable data forwarding.
*
* @return
* knet_handle_setfwd returns
* 0 on success
* -1 on error and errno is set.
*
* By default data forwarding is off and no traffic will pass through knet until
* it is set on.
*/
int knet_handle_setfwd(knet_handle_t knet_h, unsigned int enabled);
/**
* knet_handle_enable_access_lists
*
* @brief Enable or disable usage of access lists (default: off)
*
* knet_h - pointer to knet_handle_t
*
* enable - set to 1 to use access lists, 0 to disable access_lists.
*
* @return
* knet_handle_enable_access_lists returns
* 0 on success
* -1 on error and errno is set.
*
* access lists are bound to links. There are 2 types of links:
* 1) point to point, where both source and destinations are well known
* at configuration time.
* 2) open links, where only the source is known at configuration time.
*
* knet will automatically generate access lists for point to point links.
*
* For open links, knet provides 4 API calls to manipulate access lists:
* knet_link_add_acl(3), knet_link_rm_acl(3), knet_link_insert_acl(3)
* and knet_link_clear_acl(3).
* Those API calls will work exclusively on open links as they
* are of no use on point to point links.
*
* knet will not enforce any access list unless specifically enabled by
* knet_handle_enable_access_lists(3).
*
* From a security / programming perspective we recommend:
* - create the knet handle
* - enable access lists
* - configure hosts and links
* - configure access lists for open links
*/
int knet_handle_enable_access_lists(knet_handle_t knet_h, unsigned int enabled);
#define KNET_PMTUD_DEFAULT_INTERVAL 60
/**
* knet_handle_pmtud_setfreq
*
* @brief Set the interval between PMTUd scans
*
* knet_h - pointer to knet_handle_t
*
* interval - define the interval in seconds between PMTUd scans
* range from 1 to 86400 (24h)
*
* @return
* knet_handle_pmtud_setfreq returns
* 0 on success
* -1 on error and errno is set.
*
* default interval is 60.
*/
int knet_handle_pmtud_setfreq(knet_handle_t knet_h, unsigned int interval);
/**
* knet_handle_pmtud_getfreq
*
* @brief Get the interval between PMTUd scans
*
* knet_h - pointer to knet_handle_t
*
* interval - pointer where to store the current interval value
*
* @return
* knet_handle_pmtud_setfreq returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_pmtud_getfreq(knet_handle_t knet_h, unsigned int *interval);
/**
* knet_handle_enable_pmtud_notify
*
* @brief install a callback to receive PMTUd changes
*
* knet_h - pointer to knet_handle_t
*
* pmtud_notify_fn_private_data
* void pointer to data that can be used to identify
* the callback.
*
* pmtud_notify_fn
* is a callback function that is invoked every time
* a path MTU size change is detected.
* The function allows libknet to notify the user
* of data MTU, that's the max value that can be send
* onwire without fragmentation. The data MTU will always
* be lower than real link MTU because it accounts for
* protocol overhead, knet packet header and (if configured)
* crypto overhead,
* This function MUST NEVER block or add substantial delays.
*
* @return
* knet_handle_enable_pmtud_notify returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_enable_pmtud_notify(knet_handle_t knet_h,
void *pmtud_notify_fn_private_data,
void (*pmtud_notify_fn) (
void *private_data,
unsigned int data_mtu));
/**
* knet_handle_pmtud_set
*
* @brief Set the current interface MTU
*
* knet_h - pointer to knet_handle_t
*
* iface_mtu - current interface MTU, value 0 to 65535. 0 will
* re-enable automatic MTU discovery.
* In a setup with multiple interfaces, please specify
* the lowest MTU between the selected intefaces.
* knet will automatically adjust this value for
* all headers overhead and set the correct data_mtu.
* data_mtu can be retrivied with knet_handle_pmtud_get(3)
* or applications will receive a pmtud_notify event
* if enabled via knet_handle_enable_pmtud_notify(3).
*
* @return
* knet_handle_pmtud_set returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_pmtud_set(knet_handle_t knet_h,
unsigned int iface_mtu);
/**
* knet_handle_pmtud_get
*
* @brief Get the current data MTU
*
* knet_h - pointer to knet_handle_t
*
* data_mtu - pointer where to store data_mtu
*
* @return
* knet_handle_pmtud_get returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_pmtud_get(knet_handle_t knet_h,
unsigned int *data_mtu);
#define KNET_MIN_KEY_LEN 128
#define KNET_MAX_KEY_LEN 4096
struct knet_handle_crypto_cfg {
char crypto_model[16];
char crypto_cipher_type[16];
char crypto_hash_type[16];
unsigned char private_key[KNET_MAX_KEY_LEN];
unsigned int private_key_len;
};
/**
* knet_handle_crypto_set_config
*
* @brief set up packet cryptographic signing & encryption
*
* knet_h - pointer to knet_handle_t
*
* knet_handle_crypto_cfg -
* pointer to a knet_handle_crypto_cfg structure
*
* crypto_model should contain the model name.
- * Currently only "openssl" and "nss" are supported.
+ * Currently "openssl", "nss" and "gcrypt" are supported.
* Setting to "none" will disable crypto.
*
* crypto_cipher_type
* should contain the cipher algo name.
* It can be set to "none" to disable
* encryption.
* Currently supported by "nss" model:
* "aes128", "aes192" and "aes256".
* "openssl" model supports more modes and it strictly
* depends on the openssl build. See: EVP_get_cipherbyname
* openssl API call for details.
*
* crypto_hash_type
* should contain the hashing algo name.
* It can be set to "none" to disable
* hashing.
* Currently supported by "nss" model:
* "md5", "sha1", "sha256", "sha384" and "sha512".
* "openssl" model supports more modes and it strictly
* depends on the openssl build. See: EVP_get_digestbyname
* openssl API call for details.
*
* private_key will contain the private shared key.
* It has to be at least KNET_MIN_KEY_LEN long.
*
* private_key_len
* length of the provided private_key.
*
* config_num - knet supports 2 concurrent sets of crypto configurations,
* to allow runtime change of crypto config and keys.
* On RX both configurations will be used sequentially
* in an attempt to decrypt/validate a packet (when 2 are available).
* Note that this might slow down performance during a reconfiguration.
* See also knet_handle_crypto_rx_clear_traffic(3) to enable / disable
* processing of clear (unencrypted) traffic.
* For TX, the user needs to specify which configuration to use via
* knet_handle_crypto_use_config(3).
* config_num accepts 0, 1 or 2 as the value. 0 should be used when
* all crypto is being disabled.
* Calling knet_handle_crypto_set_config(3) twice with
* the same config_num will REPLACE the configuration and
* NOT activate the second key. If the configuration is currently in use
* EBUSY will be returned. See also knet_handle_crypto_use_config(3).
* The correct sequence to perform a runtime rekey / reconfiguration
* is:
* - knet_handle_crypto_set_config(..., 1). -> first time config, will use config1
* - knet_handle_crypto_use_config(..., 1). -> switch TX to config 1
* - knet_handle_crypto_set_config(..., 2). -> install config2 and use it only for RX
* - knet_handle_crypto_use_config(..., 2). -> switch TX to config 2
* - knet_handle_crypto_set_config(..., 1). -> with a "none"/"none"/"none" configuration to
* release the resources previously allocated
* The application is responsible for synchronizing calls on the nodes
* to make sure the new config is in place before switching the TX configuration.
* Failure to do so will result in knet being unable to talk to some of the nodes.
*
* Implementation notes/current limitations:
* - enabling crypto, will increase latency as packets have
* to processed.
* - enabling crypto might reduce the overall throughtput
* due to crypto data overhead.
* - private/public key encryption/hashing is not currently
* planned.
* - crypto key must be the same for all hosts in the same
* knet instance / configX.
* - it is safe to call knet_handle_crypto_set_config multiple times at runtime.
* The last config will be used.
* IMPORTANT: a call to knet_handle_crypto_set_config can fail due to:
* 1) failure to obtain locking
* 2) errors to initializing the crypto level.
* This can happen even in subsequent calls to knet_handle_crypto_set_config(3).
* A failure in crypto init will restore the previous crypto configuration if any.
*
* @return
* knet_handle_crypto_set_config returns:
* @retval 0 on success
* @retval -1 on error and errno is set.
* @retval -2 on crypto subsystem initialization error. No errno is provided at the moment (yet).
*/
int knet_handle_crypto_set_config(knet_handle_t knet_h,
struct knet_handle_crypto_cfg *knet_handle_crypto_cfg,
uint8_t config_num);
#define KNET_CRYPTO_RX_ALLOW_CLEAR_TRAFFIC 0
#define KNET_CRYPTO_RX_DISALLOW_CLEAR_TRAFFIC 1
/**
* knet_handle_crypto_rx_clear_traffic
*
* @brief enable or disable RX processing of clear (unencrypted) traffic
*
* knet_h - pointer to knet_handle_t
*
* value - KNET_CRYPTO_RX_ALLOW_CLEAR_TRAFFIC or KNET_CRYPTO_RX_DISALLOW_CLEAR_TRAFFIC
*
* @return
* knet_handle_crypto_use_config returns:
* @retval 0 on success
* @retval -1 on error and errno is set.
*/
int knet_handle_crypto_rx_clear_traffic(knet_handle_t knet_h, uint8_t value);
/**
* knet_handle_crypto_use_config
*
* @brief specify crypto configuration to use for TX
*
* knet_h - pointer to knet_handle_t
*
* config_num - 1|2 use configuration 1 or 2, 0 for clear (unencrypted) traffic.
*
* @return
* knet_handle_crypto_use_config returns:
* @retval 0 on success
* @retval -1 on error and errno is set.
*/
int knet_handle_crypto_use_config(knet_handle_t knet_h,
uint8_t config_num);
#define KNET_COMPRESS_THRESHOLD 100
struct knet_handle_compress_cfg {
char compress_model[16];
uint32_t compress_threshold;
int compress_level;
};
/**
* knet_handle_compress
*
* @brief Set up packet compression
*
* knet_h - pointer to knet_handle_t
*
* knet_handle_compress_cfg -
* pointer to a knet_handle_compress_cfg structure
*
* compress_model contains the model name.
* See "compress_level" for the list of accepted values.
* Setting the value to "none" disables compression.
*
* compress_threshold
* tells the transmission thread to NOT compress
* any packets that are smaller than the value
* indicated. Default 100 bytes.
* Set to 0 to reset to the default.
* Set to 1 to compress everything.
* Max accepted value is KNET_MAX_PACKET_SIZE.
*
* compress_level is the "level" parameter for most models:
* zlib: 0 (no compression), 1 (minimal) .. 9 (max compression).
* lz4: 1 (max compression)... 9 (fastest compression).
* lz4hc: 1 (min compression) ... LZ4HC_MAX_CLEVEL (16) or LZ4HC_CLEVEL_MAX (12)
* depending on the version of lz4hc libknet was built with.
* lzma: 0 (minimal) .. 9 (max compression)
* bzip2: 1 (minimal) .. 9 (max compression)
* For lzo2 it selects the algorithm to use:
* 1 : lzo1x_1_compress (default)
* 11 : lzo1x_1_11_compress
* 12 : lzo1x_1_12_compress
* 15 : lzo1x_1_15_compress
* 999: lzo1x_999_compress
* Other values select the default algorithm.
* Please refer to the documentation of the respective
* compression library for guidance about setting this
* value.
*
* Implementation notes:
* - it is possible to enable/disable compression at any time.
* - nodes can be using a different compression algorithm at any time.
* - knet does NOT implement the compression algorithm directly. it relies
* on external libraries for this functionality. Please read
* the libraries man pages to figure out which algorithm/compression
* level is best for the data you are planning to transmit.
*
* @return
* knet_handle_compress returns
* 0 on success
* -1 on error and errno is set. EINVAL means that either the model or the
* level are not supported.
*/
int knet_handle_compress(knet_handle_t knet_h,
struct knet_handle_compress_cfg *knet_handle_compress_cfg);
struct knet_handle_stats {
size_t size;
uint64_t tx_uncompressed_packets;
uint64_t tx_compressed_packets;
uint64_t tx_compressed_original_bytes;
uint64_t tx_compressed_size_bytes;
uint64_t tx_compress_time_ave;
uint64_t tx_compress_time_min;
uint64_t tx_compress_time_max;
uint64_t tx_failed_to_compress;
uint64_t tx_unable_to_compress;
uint64_t rx_compressed_packets;
uint64_t rx_compressed_original_bytes;
uint64_t rx_compressed_size_bytes;
uint64_t rx_compress_time_ave;
uint64_t rx_compress_time_min;
uint64_t rx_compress_time_max;
uint64_t rx_failed_to_decompress;
/* Overhead times, measured in usecs */
uint64_t tx_crypt_packets;
uint64_t tx_crypt_byte_overhead;
uint64_t tx_crypt_time_ave;
uint64_t tx_crypt_time_min;
uint64_t tx_crypt_time_max;
uint64_t rx_crypt_packets;
uint64_t rx_crypt_time_ave;
uint64_t rx_crypt_time_min;
uint64_t rx_crypt_time_max;
};
/**
* knet_handle_get_stats
*
* @brief Get statistics for compression & crypto
*
* knet_h - pointer to knet_handle_t
*
* knet_handle_stats
* pointer to a knet_handle_stats structure
*
* struct_size
* size of knet_handle_stats structure to allow
* for backwards compatibility. libknet will only
* copy this much data into the stats structure
* so that older callers will not get overflowed if
* new fields are added.
*
* @return
* 0 on success
* -1 on error and errno is set.
*
*/
int knet_handle_get_stats(knet_handle_t knet_h, struct knet_handle_stats *stats, size_t struct_size);
/*
* Tell knet_handle_clear_stats whether to clear just the handle stats
* or all of them.
*/
#define KNET_CLEARSTATS_HANDLE_ONLY 1
#define KNET_CLEARSTATS_HANDLE_AND_LINK 2
/**
* knet_handle_clear_stats
*
* @brief Clear knet stats, link and/or handle
*
* knet_h - pointer to knet_handle_t
*
* clear_option - Which stats to clear, must be one of
*
* KNET_CLEARSTATS_HANDLE_ONLY or
* KNET_CLEARSTATS_HANDLE_AND_LINK
*
* @return
* 0 on success
* -1 on error and errno is set.
*
*/
int knet_handle_clear_stats(knet_handle_t knet_h, int clear_option);
struct knet_crypto_info {
const char *name; /* openssl,nss,etc.. */
uint8_t properties; /* currently unused */
char pad[256]; /* currently unused */
};
/**
* knet_get_crypto_list
*
* @brief Get a list of supported crypto libraries
*
* crypto_list - array of struct knet_crypto_info *
* If NULL then only the number of structs is returned in crypto_list_entries
* to allow the caller to allocate sufficient space.
* libknet does not allow more than 256 crypto methods at the moment.
* it is safe to allocate 256 structs to avoid calling
* knet_get_crypto_list twice.
*
* crypto_list_entries - returns the number of structs in crypto_list
*
* @return
* knet_get_crypto_list returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_get_crypto_list(struct knet_crypto_info *crypto_list,
size_t *crypto_list_entries);
struct knet_compress_info {
const char *name; /* bzip2, lz4, etc.. */
uint8_t properties; /* currently unused */
char pad[256]; /* currently unused */
};
/**
* knet_get_compress_list
*
* @brief Get a list of support compression types
*
* compress_list - array of struct knet_compress_info *
* If NULL then only the number of structs is returned in compress_list_entries
* to allow the caller to allocate sufficient space.
* libknet does not allow more than 256 compress methods at the moment.
* it is safe to allocate 256 structs to avoid calling
* knet_get_compress_list twice.
*
* compress_list_entries - returns the number of structs in compress_list
*
* @return
* knet_get_compress_list returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_get_compress_list(struct knet_compress_info *compress_list,
size_t *compress_list_entries);
/**
* knet_handle_enable_onwire_ver_notify
*
* @brief install a callback to receive onwire changes
*
* knet_h - pointer to knet_handle_t
*
* onwire_ver_notify_fn_private_data
* void pointer to data that can be used to identify
* the callback.
*
* onwire_ver_notify_fn
* is a callback function that is invoked every time
* an onwire version change is detected.
* The function allows libknet to notify the user
* of onwire version changes.
* onwire_min_ver - minimum onwire version supported
* onwire_max_ver - maximum onwire version supported
* onwire_ver - currently onwire version in use
* This function MUST NEVER block or add substantial delays.
*
* NOTE: the callback function will be invoked upon install to
* immediately notify the user of the current configuration.
* During startup, it is safer to use onwire_min_ver and
* onwire_ver on subsequent calls.
*
* @return
* knet_handle_enable_onwire_ver_notify returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_enable_onwire_ver_notify(knet_handle_t knet_h,
void *onwire_ver_notify_fn_private_data,
void (*onwire_ver_notify_fn) (
void *private_data,
uint8_t onwire_min_ver,
uint8_t onwire_max_ver,
uint8_t onwire_ver));
/**
* knet_handle_get_onwire_ver
*
* @brief get onwire protocol version information
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* onwire_min_ver - minimum onwire version supported by local node.
* this value is set to 0 for remote nodes.
*
* onwire_max_ver - maximum onwire version supported by local or
* remote node.
*
* onwire_ver - currently onwire version in use by local or
* remote node.
*
* @return
* knet_handle_get_onwire_ver returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_get_onwire_ver(knet_handle_t knet_h,
knet_node_id_t host_id,
uint8_t *onwire_min_ver,
uint8_t *onwire_max_ver,
uint8_t *onwire_ver);
/**
* knet_handle_set_onwire_ver
*
* @brief force onwire protocol version
*
* knet_h - pointer to knet_handle_t
*
* onwire_ver - onwire version to use.
* reset to 0 to allow knet to detect
* automatically the highest version.
*
* @return
* knet_handle_get_onwire_ver returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_set_onwire_ver(knet_handle_t knet_h,
uint8_t onwire_ver);
/*
* host structs/API calls
*/
/**
* knet_host_add
*
* @brief Add a new host ID to knet
*
* knet_h - pointer to knet_handle_t
*
* host_id - each host in a knet is identified with a unique ID
* (see also knet_handle_new(3))
*
* @return
* knet_host_add returns:
* 0 on success
* -1 on error and errno is set.
*/
int knet_host_add(knet_handle_t knet_h, knet_node_id_t host_id);
/**
* knet_host_remove
*
* @brief Remove a host ID from knet
*
* knet_h - pointer to knet_handle_t
*
* host_id - each host in a knet is identified with a unique ID
* (see also knet_handle_new(3))
*
* @return
* knet_host_remove returns:
* 0 on success
* -1 on error and errno is set.
*/
int knet_host_remove(knet_handle_t knet_h, knet_node_id_t host_id);
/**
* knet_host_set_name
*
* @brief Set the name of a knet host
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* name - this name will be used for pretty logging and eventually
* search for hosts (see also knet_handle_host_get_name(2) and knet_handle_host_get_id(3)).
* Only up to KNET_MAX_HOST_LEN - 1 bytes will be accepted and
* name has to be unique for each host.
*
* @return
* knet_host_set_name returns:
* 0 on success
* -1 on error and errno is set.
*/
int knet_host_set_name(knet_handle_t knet_h, knet_node_id_t host_id,
const char *name);
/**
* knet_host_get_name_by_host_id
*
* @brief Get the name of a host given its ID
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* name - pointer to a preallocated buffer of at least size KNET_MAX_HOST_LEN
* where the current host name will be stored
* (as set by knet_host_set_name or default by knet_host_add)
*
* @return
* knet_host_get_name_by_host_id returns:
* 0 on success
* -1 on error and errno is set (name is left untouched)
*/
int knet_host_get_name_by_host_id(knet_handle_t knet_h, knet_node_id_t host_id,
char *name);
/**
* knet_host_get_id_by_host_name
*
* @brief Get the ID of a host given its name
*
* knet_h - pointer to knet_handle_t
*
* name - name to lookup, max len KNET_MAX_HOST_LEN
*
* host_id - where to store the result
*
* @return
* knet_host_get_id_by_host_name returns:
* 0 on success
* -1 on error and errno is set.
*/
int knet_host_get_id_by_host_name(knet_handle_t knet_h, const char *name,
knet_node_id_t *host_id);
/**
* knet_host_get_host_list
*
* @brief Get a list of hosts known to knet
*
* knet_h - pointer to knet_handle_t
*
* host_ids - array of at lest KNET_MAX_HOST size
*
* host_ids_entries -
* number of entries writted in host_ids
*
* @return
* knet_host_get_host_list returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_host_get_host_list(knet_handle_t knet_h,
knet_node_id_t *host_ids, size_t *host_ids_entries);
/*
* define switching policies
*/
#define KNET_LINK_POLICY_PASSIVE 0
#define KNET_LINK_POLICY_ACTIVE 1
#define KNET_LINK_POLICY_RR 2
/**
* knet_host_set_policy
*
* @brief Set the switching policy for a host's links
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* policy - there are currently 3 kind of simple switching policies
* based on link configuration.
* KNET_LINK_POLICY_PASSIVE - the active link with the highest
* priority (highest number) will be used.
* if one or more active links share
* the same priority, the one with
* lowest link_id will be used.
*
* KNET_LINK_POLICY_ACTIVE - all active links will be used
* simultaneously to send traffic.
* link priority is ignored.
*
* KNET_LINK_POLICY_RR - round-robin policy, every packet
* will be send on a different active
* link.
*
* @return
* knet_host_set_policy returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_host_set_policy(knet_handle_t knet_h, knet_node_id_t host_id,
uint8_t policy);
/**
* knet_host_get_policy
*
* @brief Get the switching policy for a host's links
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* policy - will contain the current configured switching policy.
* Default is passive when creating a new host.
*
* @return
* knet_host_get_policy returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_host_get_policy(knet_handle_t knet_h, knet_node_id_t host_id,
uint8_t *policy);
/**
* knet_host_enable_status_change_notify
*
* @brief Install a callback to get host status change events
*
* knet_h - pointer to knet_handle_t
*
* host_status_change_notify_fn_private_data -
* void pointer to data that can be used to identify
* the callback
*
* host_status_change_notify_fn -
* is a callback function that is invoked every time
* there is a change in the host status.
* host status is identified by:
* - reachable, this host can send/receive data to/from host_id
* - remote, 0 if the host_id is connected locally or 1 if
* the there is one or more knet host(s) in between.
* NOTE: re-switching is NOT currently implemented,
* but this is ready for future and can avoid
* an API/ABI breakage later on.
* - external, 0 if the host_id is configured locally or 1 if
* it has been added from remote nodes config.
* NOTE: dynamic topology is NOT currently implemented,
* but this is ready for future and can avoid
* an API/ABI breakage later on.
* This function MUST NEVER block or add substantial delays.
*
* @return
* knet_host_status_change_notify returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_host_enable_status_change_notify(knet_handle_t knet_h,
void *host_status_change_notify_fn_private_data,
void (*host_status_change_notify_fn) (
void *private_data,
knet_node_id_t host_id,
uint8_t reachable,
uint8_t remote,
uint8_t external));
/*
* define host status structure for quick lookup
* struct is in flux as more stats will be added soon
*
* reachable host_id can be seen either directly connected
* or via another host_id
*
* remote 0 = node is connected locally, 1 is visible via
* via another host_id
*
* external 0 = node is configured/known locally,
* 1 host_id has been received via another host_id
*/
struct knet_host_status {
uint8_t reachable;
uint8_t remote;
uint8_t external;
/* add host statistics */
};
/**
* knet_host_get_status
*
* @brief Get the status of a host
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* status - pointer to knet_host_status struct
*
* @return
* knet_handle_pmtud_get returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_host_get_status(knet_handle_t knet_h, knet_node_id_t host_id,
struct knet_host_status *status);
/*
* link structs/API calls
*
* every host allocated/managed by knet_host_* has
* KNET_MAX_LINK structures to define the network
* paths that connect 2 hosts.
*
* Each link is identified by a link_id that has a
* values between 0 and KNET_MAX_LINK - 1.
*
* KNOWN LIMITATIONS:
*
* - let's assume the scenario where two hosts are connected
* with any number of links. link_id must match on both sides.
* If host_id 0 link_id 0 is configured to connect IP1 to IP2 and
* host_id 0 link_id 1 is configured to connect IP3 to IP4,
* host_id 1 link_id 0 _must_ connect IP2 to IP1 and likewise
* host_id 1 link_id 1 _must_ connect IP4 to IP3.
* We might be able to lift this restriction in future, by using
* other data to determine src/dst link_id, but for now, deal with it.
*/
/*
* commodity functions to convert strings to sockaddr and viceversa
*/
/**
* knet_strtoaddr
*
* @brief Convert a hostname string to an address
*
* host - IPaddr/hostname to convert
* be aware only the first IP address will be returned
* in case a hostname resolves to multiple IP
*
* port - port to connect to
*
* ss - sockaddr_storage where to store the converted data
*
* sslen - len of the sockaddr_storage
*
* @return
* knet_strtoaddr returns same error codes as getaddrinfo
*
*/
int knet_strtoaddr(const char *host, const char *port,
struct sockaddr_storage *ss, socklen_t sslen);
/**
* knet_addrtostr
*
* @brief Convert an address to a host name
*
* ss - sockaddr_storage to convert
*
* sslen - len of the sockaddr_storage
*
* host - IPaddr/hostname where to store data
* (recommended size: KNET_MAX_HOST_LEN)
*
* port - port buffer where to store data
* (recommended size: KNET_MAX_PORT_LEN)
*
* @return
* knet_strtoaddr returns same error codes as getnameinfo
*/
int knet_addrtostr(const struct sockaddr_storage *ss, socklen_t sslen,
char *addr_buf, size_t addr_buf_size,
char *port_buf, size_t port_buf_size);
#define KNET_TRANSPORT_LOOPBACK 0
#define KNET_TRANSPORT_UDP 1
#define KNET_TRANSPORT_SCTP 2
#define KNET_MAX_TRANSPORTS UINT8_MAX
/*
* The Loopback transport is only valid for connections to localhost, the host
* with the same node_id specified in knet_handle_new(). Only one link of this
* type is allowed. Data sent down a LOOPBACK link will be copied directly from
* the knet send datafd to the knet receive datafd so the application must be set
* up to take data from that socket at least as often as it is sent or deadlocks
* could occur. If used, a LOOPBACK link must be the only link configured to the
* local host.
*/
struct knet_transport_info {
const char *name; /* UDP/SCTP/etc... */
uint8_t id; /* value that can be used for link_set_config */
uint8_t properties; /* currently unused */
char pad[256]; /* currently unused */
};
/**
* knet_get_transport_list
*
* @brief Get a list of the transports support by this build of knet
*
* transport_list - an array of struct transport_info that must be
* at least of size struct transport_info * KNET_MAX_TRANSPORTS
*
* transport_list_entries - pointer to a size_t where to store how many transports
* are available in this build of libknet.
*
* @return
* knet_get_transport_list returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_get_transport_list(struct knet_transport_info *transport_list,
size_t *transport_list_entries);
/**
* knet_get_transport_name_by_id
*
* @brief Get a transport name from its ID number
*
* transport - one of the KNET_TRANSPORT_xxx constants
*
* @return
* knet_get_transport_name_by_id returns:
*
* @retval pointer to the name on success or
* @retval NULL on error and errno is set.
*/
const char *knet_get_transport_name_by_id(uint8_t transport);
/**
* knet_get_transport_id_by_name
*
* @brief Get a transport ID from its name
*
* name - transport name (UDP/SCTP/etc)
*
* @return
* knet_get_transport_name_by_id returns:
*
* @retval KNET_MAX_TRANSPORTS on error and errno is set accordingly
* @retval KNET_TRANSPORT_xxx on success.
*/
uint8_t knet_get_transport_id_by_name(const char *name);
#define KNET_TRANSPORT_DEFAULT_RECONNECT_INTERVAL 1000
/**
* knet_handle_set_transport_reconnect_interval
*
* @brief Set the interval between transport attempts to reconnect a failed link
*
* knet_h - pointer to knet_handle_t
*
* msecs - milliseconds
*
* @return
* knet_handle_set_transport_reconnect_interval returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_set_transport_reconnect_interval(knet_handle_t knet_h, uint32_t msecs);
/**
* knet_handle_get_transport_reconnect_interval
*
* @brief Get the interval between transport attempts to reconnect a failed link
*
* knet_h - pointer to knet_handle_t
*
* msecs - milliseconds
*
* @return
* knet_handle_get_transport_reconnect_interval returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_handle_get_transport_reconnect_interval(knet_handle_t knet_h, uint32_t *msecs);
/**
* knet_link_set_config
*
* @brief Configure the link to a host
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* link_id - see knet_link_set_config(3)
*
* transport - one of the KNET_TRANSPORT_xxx constants
*
* src_addr - sockaddr_storage that can be either IPv4 or IPv6
*
* dst_addr - sockaddr_storage that can be either IPv4 or IPv6
* this can be null if we don't know the incoming
* IP address/port and the link will remain quiet
* till the node on the other end will initiate a
* connection
*
* flags - KNET_LINK_FLAG_*
*
* @return
* knet_link_set_config returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_link_set_config(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
uint8_t transport,
struct sockaddr_storage *src_addr,
struct sockaddr_storage *dst_addr,
uint64_t flags);
/**
* knet_link_get_config
*
* @brief Get the link configutation information
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* link_id - see knet_link_set_config(3)
*
* transport - see knet_link_set_config(3)
*
* src_addr - sockaddr_storage that can be either IPv4 or IPv6
*
* dst_addr - sockaddr_storage that can be either IPv4 or IPv6
*
* dynamic - 0 if dst_addr is static or 1 if dst_addr is dynamic.
* In case of 1, dst_addr can be NULL and it will be left
* untouched.
*
* flags - KNET_LINK_FLAG_*
*
* @return
* knet_link_get_config returns
* 0 on success.
* -1 on error and errno is set.
*/
int knet_link_get_config(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
uint8_t *transport,
struct sockaddr_storage *src_addr,
struct sockaddr_storage *dst_addr,
uint8_t *dynamic,
uint64_t *flags);
/**
* knet_link_clear_config
*
* @brief Clear link information and disconnect the link
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* link_id - see knet_link_set_config(3)
*
* @return
* knet_link_clear_config returns
* 0 on success.
* -1 on error and errno is set.
*/
int knet_link_clear_config(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id);
/*
* Access lists management for open links
* see also knet_handle_enable_access_lists(3)
*/
/**
* check_type_t
* @brief address type enum for knet access lists
*
* CHECK_TYPE_ADDRESS is the equivalent of a single entry / IP address.
* for example: 10.1.9.3
* and the entry is stored in ss1. ss2 can be NULL.
*
* CHECK_TYPE_MASK is used to configure network/netmask.
* for example: 192.168.0.0/24
* the network is stored in ss1 and the netmask in ss2.
*
* CHECK_TYPE_RANGE defines a value / range of ip addresses.
* for example: 172.16.0.1-172.16.0.10
* the start is stored in ss1 and the end in ss2.
*
* Please be aware that the above examples refer only to IP based protocols.
* Other protocols might use ss1 and ss2 in slightly different ways.
* At the moment knet only supports IP based protocol, though that might change
* in the future.
*/
typedef enum {
CHECK_TYPE_ADDRESS,
CHECK_TYPE_MASK,
CHECK_TYPE_RANGE
} check_type_t;
/**
* check_acceptreject_t
*
* @brief enum for accept/reject in knet access lists
*
* accept or reject incoming packets defined in the access list entry
*/
typedef enum {
CHECK_ACCEPT,
CHECK_REJECT
} check_acceptreject_t;
/**
* knet_link_add_acl
*
* @brief Add access list entry to an open link
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* link_id - see knet_link_set_config(3)
*
* ss1 / ss2 / type / acceptreject - see typedef definitions for details
*
* IMPORTANT: the order in which access lists are added is critical and it
* is left to the user to add them in the right order. knet
* will not attempt to logically sort them.
*
* For example:
* 1 - accept from 10.0.0.0/8
* 2 - reject from 10.0.0.1/32
*
* is not the same as:
*
* 1 - reject from 10.0.0.1/32
* 2 - accept from 10.0.0.0/8
*
* In the first example, rule number 2 will never match because
* packets from 10.0.0.1 will be accepted by rule number 1.
*
* @return
* knet_link_add_acl returns
* 0 on success.
* -1 on error and errno is set.
*/
int knet_link_add_acl(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
struct sockaddr_storage *ss1,
struct sockaddr_storage *ss2,
check_type_t type, check_acceptreject_t acceptreject);
/**
* knet_link_insert_acl
*
* @brief Insert access list entry to an open link at given index
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* link_id - see knet_link_set_config(3)
*
* index - insert at position "index" where 0 is the first entry and -1
* appends to the current list.
*
* ss1 / ss2 / type / acceptreject - see typedef definitions for details
*
* @return
* knet_link_insert_acl returns
* 0 on success.
* -1 on error and errno is set.
*/
int knet_link_insert_acl(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
int index,
struct sockaddr_storage *ss1,
struct sockaddr_storage *ss2,
check_type_t type, check_acceptreject_t acceptreject);
/**
* knet_link_rm_acl
*
* @brief Remove access list entry from an open link
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* link_id - see knet_link_set_config(3)
*
* ss1 / ss2 / type / acceptreject - see typedef definitions for details
*
* IMPORTANT: the data passed to this API call must match exactly that passed
* to knet_link_add_acl(3).
*
* @return
* knet_link_rm_acl returns
* 0 on success.
* -1 on error and errno is set.
*/
int knet_link_rm_acl(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
struct sockaddr_storage *ss1,
struct sockaddr_storage *ss2,
check_type_t type, check_acceptreject_t acceptreject);
/**
* knet_link_clear_acl
*
* @brief Remove all access list entries from an open link
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* link_id - see knet_link_set_config(3)
*
* @return
* knet_link_clear_acl returns
* 0 on success.
* -1 on error and errno is set.
*/
int knet_link_clear_acl(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id);
/**
* knet_link_set_enable
*
* @brief Enable traffic on a link
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* link_id - see knet_link_set_config(3)
*
* enabled - 0 disable the link, 1 enable the link
*
* @return
* knet_link_set_enable returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_link_set_enable(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
unsigned int enabled);
/**
* knet_link_get_enable
*
* @brief Find out whether a link is enabled or not
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* link_id - see knet_link_set_config(3)
*
* enabled - 0 disable the link, 1 enable the link
*
* @return
* knet_link_get_enable returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_link_get_enable(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
unsigned int *enabled);
#define KNET_LINK_DEFAULT_PING_INTERVAL 1000 /* 1 second */
#define KNET_LINK_DEFAULT_PING_TIMEOUT 2000 /* 2 seconds */
#define KNET_LINK_DEFAULT_PING_PRECISION 2048 /* samples */
/**
* knet_link_set_ping_timers
*
* @brief Set the ping timers for a link
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* link_id - see knet_link_set_config(3)
*
* interval - specify the ping interval in milliseconds.
*
* timeout - if no pong is received within this time,
* the link is declared dead, in milliseconds.
* NOTE: in future it will be possible to set timeout to 0
* for an autocalculated timeout based on interval, pong_count
* and latency. The API already accept 0 as value and it will
* return ENOSYS / -1. Once the automatic calculation feature
* will be implemented, this call will only return EINVAL
* for incorrect values.
*
* precision - how many values of latency are used to calculate
* the average link latency (see also knet_link_get_status(3))
*
* @return
* knet_link_set_ping_timers returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_link_set_ping_timers(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
time_t interval, time_t timeout, unsigned int precision);
/**
* knet_link_get_ping_timers
*
* @brief Get the ping timers for a link
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* link_id - see knet_link_set_config(3)
*
* interval - ping interval
*
* timeout - if no pong is received within this time,
* the link is declared dead
*
* precision - how many values of latency are used to calculate
* the average link latency (see also knet_link_get_status(3))
*
* @return
* knet_link_get_ping_timers returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_link_get_ping_timers(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
time_t *interval, time_t *timeout, unsigned int *precision);
#define KNET_LINK_DEFAULT_PONG_COUNT 5
/**
* knet_link_set_pong_count
*
* @brief Set the pong count for a link
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* link_id - see knet_link_set_config(3)
*
* pong_count - how many valid ping/pongs before a link is marked UP.
* default: 5, value should be > 0
*
* @return
* knet_link_set_pong_count returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_link_set_pong_count(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
uint8_t pong_count);
/**
* knet_link_get_pong_count
*
* @brief Get the pong count for a link
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* link_id - see knet_link_set_config(3)
*
* pong_count - how many valid ping/pongs before a link is marked UP.
* default: 5, value should be > 0
*
* @return
* knet_link_get_pong_count returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_link_get_pong_count(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
uint8_t *pong_count);
/**
* knet_link_set_priority
*
* @brief Set the priority for a link
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* link_id - see knet_link_set_config(3)
*
* priority - specify the switching priority for this link
* see also knet_host_set_policy
*
* @return
* knet_link_set_priority returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_link_set_priority(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
uint8_t priority);
/**
* knet_link_get_priority
*
* @brief Get the priority for a link
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* link_id - see knet_link_set_config(3)
*
* priority - gather the switching priority for this link
* see also knet_host_set_policy
*
* @return
* knet_link_get_priority returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_link_get_priority(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
uint8_t *priority);
/**
* knet_link_get_link_list
*
* @brief Get a list of links connecting a host
*
* knet_h - pointer to knet_handle_t
*
* link_ids - array of at lest KNET_MAX_LINK size
* with the list of configured links for a certain host.
*
* link_ids_entries -
* number of entries contained in link_ids
*
* @return
* knet_link_get_link_list returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_link_get_link_list(knet_handle_t knet_h, knet_node_id_t host_id,
uint8_t *link_ids, size_t *link_ids_entries);
/*
* define link status structure for quick lookup
*
* src/dst_{ipaddr,port} strings are filled by
* getnameinfo(3) when configuring the link.
* if the link is dynamic (see knet_link_set_config(3))
* dst_ipaddr/port will contain ipaddr/port of the currently
* connected peer or "Unknown" if it was not possible
* to determine the ipaddr/port at runtime.
*
* enabled see also knet_link_set/get_enable.
*
* connected the link is connected to a peer and ping/pong traffic
* is flowing.
*
* dynconnected the link has dynamic ip on the other end, and
* we can see the other host is sending pings to us.
*
* pong_last if the link is down, this value tells us how long
* ago this link was active. A value of 0 means that the link
* has never been active.
*
* knet_link_stats structure that contains details statistics for the link
*/
#define MAX_LINK_EVENTS 16
struct knet_link_stats {
/* onwire values */
uint64_t tx_data_packets;
uint64_t rx_data_packets;
uint64_t tx_data_bytes;
uint64_t rx_data_bytes;
uint64_t rx_ping_packets;
uint64_t tx_ping_packets;
uint64_t rx_ping_bytes;
uint64_t tx_ping_bytes;
uint64_t rx_pong_packets;
uint64_t tx_pong_packets;
uint64_t rx_pong_bytes;
uint64_t tx_pong_bytes;
uint64_t rx_pmtu_packets;
uint64_t tx_pmtu_packets;
uint64_t rx_pmtu_bytes;
uint64_t tx_pmtu_bytes;
/* Only filled in when requested */
uint64_t tx_total_packets;
uint64_t rx_total_packets;
uint64_t tx_total_bytes;
uint64_t rx_total_bytes;
uint64_t tx_total_errors;
uint64_t tx_total_retries;
uint32_t tx_pmtu_errors;
uint32_t tx_pmtu_retries;
uint32_t tx_ping_errors;
uint32_t tx_ping_retries;
uint32_t tx_pong_errors;
uint32_t tx_pong_retries;
uint32_t tx_data_errors;
uint32_t tx_data_retries;
/* measured in usecs */
uint32_t latency_min;
uint32_t latency_max;
uint32_t latency_ave;
uint32_t latency_samples;
/* how many times the link has been going up/down */
uint32_t down_count;
uint32_t up_count;
/*
* circular buffer of time_t structs collecting the history
* of up/down events on this link.
* the index indicates current/last event.
* it is safe to walk back the history by decreasing the index
*/
time_t last_up_times[MAX_LINK_EVENTS];
time_t last_down_times[MAX_LINK_EVENTS];
int8_t last_up_time_index;
int8_t last_down_time_index;
/* Always add new stats at the end */
};
struct knet_link_status {
size_t size; /* For ABI checking */
char src_ipaddr[KNET_MAX_HOST_LEN];
char src_port[KNET_MAX_PORT_LEN];
char dst_ipaddr[KNET_MAX_HOST_LEN];
char dst_port[KNET_MAX_PORT_LEN];
uint8_t enabled; /* link is configured and admin enabled for traffic */
uint8_t connected; /* link is connected for data (local view) */
uint8_t dynconnected; /* link has been activated by remote dynip */
struct timespec pong_last;
unsigned int mtu; /* current detected MTU on this link */
unsigned int proto_overhead; /* contains the size of the IP protocol, knet headers and
* crypto headers (if configured). This value is filled in
* ONLY after the first PMTUd run on that given link,
* and can change if link configuration or crypto configuration
* changes at runtime.
* WARNING: in general mtu + proto_overhead might or might
* not match the output of ifconfig mtu due to crypto
* requirements to pad packets to some specific boundaries. */
/* Link statistics */
struct knet_link_stats stats;
};
/**
* knet_link_get_status
*
* @brief Get the status (and statistics) for a link
*
* knet_h - pointer to knet_handle_t
*
* host_id - see knet_host_add(3)
*
* link_id - see knet_link_set_config(3)
*
* status - pointer to knet_link_status struct
*
* struct_size - max size of knet_link_status - allows library to
* add fields without ABI change. Returned structure
* will be truncated to this length and .size member
* indicates the full size.
*
* @return
* knet_link_get_status returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_link_get_status(knet_handle_t knet_h, knet_node_id_t host_id, uint8_t link_id,
struct knet_link_status *status, size_t struct_size);
/**
* knet_link_enable_status_change_notify
*
* @brief Install a callback to get a link status change events
*
* knet_h - pointer to knet_handle_t
*
* host_status_change_notify_fn_private_data -
* void pointer to data that can be used to identify
* the callback
*
* host_status_change_notify_fn -
* is a callback function that is invoked every time
* there is a change in a link status.
* host status is identified by:
* - connected, 0 if the link has been disconnected, 1 if the link
* is connected.
* - remote, 0 if the host_id is connected locally or 1 if
* the there is one or more knet host(s) in between.
* NOTE: re-switching is NOT currently implemented,
* but this is ready for future and can avoid
* an API/ABI breakage later on.
* - external, 0 if the host_id is configured locally or 1 if
* it has been added from remote nodes config.
* NOTE: dynamic topology is NOT currently implemented,
* but this is ready for future and can avoid
* an API/ABI breakage later on.
* This function MUST NEVER block or add substantial delays.
*
* @return
* knet_host_status_change_notify returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_link_enable_status_change_notify(knet_handle_t knet_h,
void *link_status_change_notify_fn_private_data,
void (*link_status_change_notify_fn) (
void *private_data,
knet_node_id_t host_id,
uint8_t link_id,
uint8_t connected,
uint8_t remote,
uint8_t external));
/*
* logging structs/API calls
*/
/*
* libknet is composed of several subsystems. In order
* to easily distinguish log messages coming from different
* places, each subsystem has its own ID.
*
* 0-19 config/management
* 20-39 internal threads
* 40-59 transports
* 60-69 crypto implementations
*/
#define KNET_SUB_COMMON 0 /* common.c */
#define KNET_SUB_HANDLE 1 /* handle.c alloc/dealloc config changes */
#define KNET_SUB_HOST 2 /* host add/del/modify */
#define KNET_SUB_LISTENER 3 /* listeners add/del/modify... */
#define KNET_SUB_LINK 4 /* link add/del/modify */
#define KNET_SUB_TRANSPORT 5 /* Transport common */
#define KNET_SUB_CRYPTO 6 /* crypto.c config generic layer */
#define KNET_SUB_COMPRESS 7 /* compress.c config generic layer */
#define KNET_SUB_FILTER 19 /* allocated for users to log from dst_filter */
#define KNET_SUB_DSTCACHE 20 /* switching thread (destination cache handling) */
#define KNET_SUB_HEARTBEAT 21 /* heartbeat thread */
#define KNET_SUB_PMTUD 22 /* Path MTU Discovery thread */
#define KNET_SUB_TX 23 /* send to link thread */
#define KNET_SUB_RX 24 /* recv from link thread */
#define KNET_SUB_TRANSP_BASE 40 /* Base log level for transports */
#define KNET_SUB_TRANSP_LOOPBACK (KNET_SUB_TRANSP_BASE + KNET_TRANSPORT_LOOPBACK)
#define KNET_SUB_TRANSP_UDP (KNET_SUB_TRANSP_BASE + KNET_TRANSPORT_UDP)
#define KNET_SUB_TRANSP_SCTP (KNET_SUB_TRANSP_BASE + KNET_TRANSPORT_SCTP)
-#define KNET_SUB_NSSCRYPTO 60 /* nsscrypto.c */
-#define KNET_SUB_OPENSSLCRYPTO 61 /* opensslcrypto.c */
+#define KNET_SUB_NSSCRYPTO 60 /* crypto_nss.c */
+#define KNET_SUB_OPENSSLCRYPTO 61 /* crypto_openssl.c */
+#define KNET_SUB_GCRYPTCRYPTO 62 /* crypto_gcrypt.c */
#define KNET_SUB_ZLIBCOMP 70 /* compress_zlib.c */
#define KNET_SUB_LZ4COMP 71 /* compress_lz4.c */
#define KNET_SUB_LZ4HCCOMP 72 /* compress_lz4.c */
#define KNET_SUB_LZO2COMP 73 /* compress_lzo.c */
#define KNET_SUB_LZMACOMP 74 /* compress_lzma.c */
#define KNET_SUB_BZIP2COMP 75 /* compress_bzip2.c */
#define KNET_SUB_ZSTDCOMP 76 /* compress_zstd.c */
#define KNET_SUB_UNKNOWN UINT8_MAX - 1
#define KNET_MAX_SUBSYSTEMS UINT8_MAX
/*
* Convert between subsystem IDs and names
*/
/**
* knet_log_get_subsystem_name
*
* @brief Get a logging system name from its numeric ID
*
* @return
* returns internal name of the subsystem or "common"
*/
const char *knet_log_get_subsystem_name(uint8_t subsystem);
/**
* knet_log_get_subsystem_id
*
* @brief Get a logging system ID from its name
*
* @return
* returns internal ID of the subsystem or KNET_SUB_COMMON
*/
uint8_t knet_log_get_subsystem_id(const char *name);
/*
* 4 log levels are enough for everybody
*/
#define KNET_LOG_ERR 0 /* unrecoverable errors/conditions */
#define KNET_LOG_WARN 1 /* recoverable errors/conditions */
#define KNET_LOG_INFO 2 /* info, link up/down, config changes.. */
#define KNET_LOG_DEBUG 3
/*
* Convert between log level values and names
*/
/**
* knet_log_get_loglevel_name
*
* @brief Get a logging level name from its numeric ID
*
* @return
* returns internal name of the log level or "ERROR" for unknown values
*/
const char *knet_log_get_loglevel_name(uint8_t level);
/**
* knet_log_get_loglevel_id
*
* @brief Get a logging level ID from its name
*
* @return
* returns internal log level ID or KNET_LOG_ERR for invalid names
*/
uint8_t knet_log_get_loglevel_id(const char *name);
/*
* every log message is composed by a text message
* and message level/subsystem IDs.
* In order to make debugging easier it is possible to send those packets
* straight to stdout/stderr (see knet_bench.c stdout option).
*/
#define KNET_MAX_LOG_MSG_SIZE 254
#if KNET_MAX_LOG_MSG_SIZE > PIPE_BUF
#error KNET_MAX_LOG_MSG_SIZE cannot be bigger than PIPE_BUF for guaranteed system atomic writes
#endif
struct knet_log_msg {
char msg[KNET_MAX_LOG_MSG_SIZE];
uint8_t subsystem; /* KNET_SUB_* */
uint8_t msglevel; /* KNET_LOG_* */
knet_handle_t knet_h; /* pointer to the handle generating the log */
};
/**
* knet_log_set_loglevel
*
* @brief Set the logging level for a subsystem
*
* knet_h - same as above
*
* subsystem - same as above
*
* level - same as above
*
* knet_log_set_loglevel allows fine control of log levels by subsystem.
* See also knet_handle_new for defaults.
*
* @return
* knet_log_set_loglevel returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_log_set_loglevel(knet_handle_t knet_h, uint8_t subsystem,
uint8_t level);
/**
* knet_log_get_loglevel
*
* @brief Get the logging level for a subsystem
*
* knet_h - same as above
*
* subsystem - same as above
*
* level - same as above
*
* @return
* knet_log_get_loglevel returns
* 0 on success
* -1 on error and errno is set.
*/
int knet_log_get_loglevel(knet_handle_t knet_h, uint8_t subsystem,
uint8_t *level);
#endif
diff --git a/libknet/logging.c b/libknet/logging.c
index 9ae89e93..61c585f7 100644
--- a/libknet/logging.c
+++ b/libknet/logging.c
@@ -1,249 +1,250 @@
/*
* Copyright (C) 2010-2020 Red Hat, Inc. All rights reserved.
*
* Author: Fabio M. Di Nitto <fabbione@kronosnet.org>
*
* This software licensed under LGPL-2.0+
*/
#include "config.h"
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <stdarg.h>
#include <errno.h>
#include <stdio.h>
#include "internals.h"
#include "logging.h"
#include "threads_common.h"
static struct pretty_names subsystem_names[KNET_MAX_SUBSYSTEMS] =
{
{ "common", KNET_SUB_COMMON },
{ "handle", KNET_SUB_HANDLE },
{ "host", KNET_SUB_HOST },
{ "listener", KNET_SUB_LISTENER },
{ "link", KNET_SUB_LINK },
{ "transport", KNET_SUB_TRANSPORT },
{ "crypto", KNET_SUB_CRYPTO },
{ "compress", KNET_SUB_COMPRESS },
{ "filter", KNET_SUB_FILTER },
{ "dstcache", KNET_SUB_DSTCACHE },
{ "heartbeat", KNET_SUB_HEARTBEAT },
{ "pmtud", KNET_SUB_PMTUD },
{ "tx", KNET_SUB_TX },
{ "rx", KNET_SUB_RX },
{ "loopback", KNET_SUB_TRANSP_LOOPBACK },
{ "udp", KNET_SUB_TRANSP_UDP },
{ "sctp", KNET_SUB_TRANSP_SCTP },
{ "nsscrypto", KNET_SUB_NSSCRYPTO },
{ "opensslcrypto", KNET_SUB_OPENSSLCRYPTO },
+ { "gcryptcrypto", KNET_SUB_GCRYPTCRYPTO },
{ "zlibcomp", KNET_SUB_ZLIBCOMP },
{ "lz4comp", KNET_SUB_LZ4COMP },
{ "lz4hccomp", KNET_SUB_LZ4HCCOMP },
{ "lzo2comp", KNET_SUB_LZO2COMP },
{ "lzmacomp", KNET_SUB_LZMACOMP },
{ "bzip2comp", KNET_SUB_BZIP2COMP },
{ "zstdcomp", KNET_SUB_ZSTDCOMP },
{ "unknown", KNET_SUB_UNKNOWN } /* unknown MUST always be last in this array */
};
const char *knet_log_get_subsystem_name(uint8_t subsystem)
{
unsigned int i;
for (i = 0; i < KNET_MAX_SUBSYSTEMS; i++) {
if (subsystem_names[i].val == KNET_SUB_UNKNOWN) {
break;
}
if (subsystem_names[i].val == subsystem) {
errno = 0;
return subsystem_names[i].name;
}
}
return "unknown";
}
uint8_t knet_log_get_subsystem_id(const char *name)
{
unsigned int i;
for (i = 0; i < KNET_MAX_SUBSYSTEMS; i++) {
if (subsystem_names[i].val == KNET_SUB_UNKNOWN) {
break;
}
if (strcasecmp(name, subsystem_names[i].name) == 0) {
errno = 0;
return subsystem_names[i].val;
}
}
return KNET_SUB_UNKNOWN;
}
static int is_valid_subsystem(uint8_t subsystem)
{
unsigned int i;
for (i = 0; i < KNET_MAX_SUBSYSTEMS; i++) {
if ((subsystem != KNET_SUB_UNKNOWN) &&
(subsystem_names[i].val == KNET_SUB_UNKNOWN)) {
break;
}
if (subsystem_names[i].val == subsystem) {
return 0;
}
}
return -1;
}
static struct pretty_names loglevel_names[KNET_LOG_DEBUG + 1] =
{
{ "ERROR", KNET_LOG_ERR },
{ "WARNING", KNET_LOG_WARN },
{ "info", KNET_LOG_INFO },
{ "debug", KNET_LOG_DEBUG }
};
const char *knet_log_get_loglevel_name(uint8_t level)
{
unsigned int i;
for (i = 0; i <= KNET_LOG_DEBUG; i++) {
if (loglevel_names[i].val == level) {
errno = 0;
return loglevel_names[i].name;
}
}
return "ERROR";
}
uint8_t knet_log_get_loglevel_id(const char *name)
{
unsigned int i;
for (i = 0; i <= KNET_LOG_DEBUG; i++) {
if (strcasecmp(name, loglevel_names[i].name) == 0) {
errno = 0;
return loglevel_names[i].val;
}
}
return KNET_LOG_ERR;
}
int knet_log_set_loglevel(knet_handle_t knet_h, uint8_t subsystem,
uint8_t level)
{
int savederrno = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (is_valid_subsystem(subsystem) < 0) {
errno = EINVAL;
return -1;
}
if (level > KNET_LOG_DEBUG) {
errno = EINVAL;
return -1;
}
savederrno = get_global_wrlock(knet_h);
if (savederrno) {
log_err(knet_h, subsystem, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
knet_h->log_levels[subsystem] = level;
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = 0;
return 0;
}
int knet_log_get_loglevel(knet_handle_t knet_h, uint8_t subsystem,
uint8_t *level)
{
int savederrno = 0;
if (!knet_h) {
errno = EINVAL;
return -1;
}
if (is_valid_subsystem(subsystem) < 0) {
errno = EINVAL;
return -1;
}
if (!level) {
errno = EINVAL;
return -1;
}
savederrno = pthread_rwlock_rdlock(&knet_h->global_rwlock);
if (savederrno) {
log_err(knet_h, subsystem, "Unable to get write lock: %s",
strerror(savederrno));
errno = savederrno;
return -1;
}
*level = knet_h->log_levels[subsystem];
pthread_rwlock_unlock(&knet_h->global_rwlock);
errno = 0;
return 0;
}
void log_msg(knet_handle_t knet_h, uint8_t subsystem, uint8_t msglevel,
const char *fmt, ...)
{
va_list ap;
struct knet_log_msg msg;
size_t byte_cnt = 0;
int len;
if ((!knet_h) ||
(subsystem == KNET_MAX_SUBSYSTEMS) ||
(msglevel > knet_h->log_levels[subsystem]))
return;
if (knet_h->logfd <= 0)
goto out;
memset(&msg, 0, sizeof(struct knet_log_msg));
msg.subsystem = subsystem;
msg.msglevel = msglevel;
msg.knet_h = knet_h;
va_start(ap, fmt);
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-nonliteral"
#endif
vsnprintf(msg.msg, sizeof(msg.msg), fmt, ap);
#ifdef __clang__
#pragma clang diagnostic pop
#endif
va_end(ap);
while (byte_cnt < sizeof(struct knet_log_msg)) {
len = write(knet_h->logfd, &msg, sizeof(struct knet_log_msg) - byte_cnt);
if (len <= 0) {
goto out;
}
byte_cnt += len;
}
out:
return;
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jul 8, 5:25 PM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1986574
Default Alt Text
(164 KB)

Event Timeline