From 5b47e8c615797e61b29c3653925e37eddb49c78a Mon Sep 17 00:00:00 2001 From: Tom Barbette Date: Tue, 1 Oct 2024 21:09:29 +0200 Subject: [PATCH] Merge most code from HIRT (ICNP'24) Changes improving IPv6 and adding SRv6 encap/decap and some processing capabilities to showcase the HIRT paper to be presented at ICNP'24. It also adds the library elements fo network-layer FEC used in the aforementioned paper. However the FEC elements themselves use RLC code that is under patent, so if you want them please ask Louis. For the same reasons, I had to squash all commits as once, sorry about the huge change. Improvements: - updated gitlab CI with much more tests - SRV6 encap and decap elements - Fix compatibility problem with aarch64 - Fix compatibility issues with MacOS @louisna was mostly involved in the code, and then me. Co-authored-by: default avatarLouis Navarre i --- .gitlab-ci.yml | 134 +- README.md | 4 +- aclocal.m4 | 4 +- config-userlevel.h.in | 11 +- config.h.in | 6 + configure | 143 +- configure.in | 50 +- deps.sh | 2 +- doc/click-elem2man | 2 +- doc/clicktest.1 | 50 +- elements/analysis/fromipsumdump.cc | 161 ++- elements/analysis/fromipsumdump.hh | 14 + elements/analysis/ipsumdump_link.cc | 20 +- elements/analysis/ipsumdumpinfo.cc | 123 +- elements/analysis/ipsumdumpinfo.hh | 70 +- elements/analysis/numberpacket.hh | 2 +- elements/analysis/settimestampdelta.hh | 4 +- elements/ethernet/truncatefcs.hh | 2 +- elements/ip/checkipheader.cc | 2 +- elements/ip/flowminloadswitch.cc | 2 +- elements/ip/flowminloadswitch.hh | 4 +- elements/ip/iprewriterbase.hh | 3 +- elements/ip/setipdscp.cc | 1 + elements/ip6/checkip6header.cc | 2 +- elements/ip6/decip6hlim.cc | 27 +- elements/ip6/ip6drop.cc | 204 +++ elements/ip6/ip6drop.hh | 105 ++ elements/ip6/ip6mirror.hh | 4 +- elements/ip6/ip6srdecap.cc | 130 ++ elements/ip6/ip6srdecap.hh | 50 + elements/ip6/ip6srencap.cc | 95 ++ elements/ip6/ip6srencap.hh | 50 + elements/ip6/ip6srprocess.cc | 67 + elements/ip6/ip6srprocess.hh | 47 + elements/ip6/lookupip6route.cc | 2 +- elements/standard/addressinfo.cc | 2 +- elements/standard/bandwidthmeter.cc | 8 +- elements/standard/bandwidthmeter.hh | 4 +- elements/standard/bwratedunqueue.cc | 2 +- elements/standard/checklength.cc | 31 + elements/standard/checklength.hh | 8 +- elements/standard/counter.cc | 1 - elements/standard/linkunqueue.cc | 113 +- elements/standard/linkunqueue.hh | 6 +- elements/standard/meter.cc | 4 +- elements/standard/print.cc | 12 +- elements/standard/print.hh | 2 +- elements/standard/ratedsource.cc | 10 +- elements/standard/ratedunqueue.cc | 6 +- elements/standard/ratedunqueue.hh | 10 +- elements/standard/shaper.cc | 2 +- elements/test/biginttest.cc | 199 +-- elements/test/confparsetest.cc | 8 +- elements/test/packettest.cc | 25 + elements/test/tokenbuckettest.cc | 2 +- elements/tunnel/gtpdecap.hh | 2 +- elements/tunnel/gtpencap.hh | 2 +- elements/tunnel/gtplookup.hh | 2 +- elements/tunnel/gtptable.hh | 2 +- elements/userlevel/counterfile.cc | 6 +- elements/userlevel/fromdevice.cc | 25 +- elements/userlevel/fromdevice.hh | 3 +- elements/userlevel/kernelfilter.cc | 2 +- elements/userlevel/kerneltun.cc | 2 +- elements/userlevel/socket.cc | 20 + elements/userlevel/socket.hh | 3 + etc/ron/divertsocket.cc | 2 +- etc/ron/todevicenotify.cc | 2 +- include/click/allocator.hh | 12 + include/click/args.hh | 2 +- include/click/batchbuilder.hh | 60 +- include/click/bigint.hh | 4 +- include/click/confparse.hh | 2 +- include/click/dpdkdevice.hh | 11 + include/click/flow/ctxelement.hh | 54 +- include/click/gaprate.hh | 46 +- include/click/glue.hh | 18 +- include/click/ip6address.hh | 8 +- include/click/llrpc.h | 4 +- include/click/loadbalancer.hh | 14 +- include/click/packet.hh | 30 +- include/click/packetbatch.hh | 37 +- include/click/routerthread.hh | 2 + include/click/standard/threadsched.hh | 2 +- include/click/sync.hh | 9 +- include/click/tokenbucket.hh | 92 +- include/click/type_traits.hh | 4 +- lib/args.cc | 12 +- lib/confparse.cc | 6 +- lib/flow.cc | 11 + lib/flowbuffer.cc | 2 + lib/gaprate.cc | 2 +- lib/packet.cc | 12 +- lib/router.cc | 8 +- lib/routerthread.cc | 11 + m4/click.m4 | 8 +- mininet/fastclick/Vagrantfile | 16 +- test/standard/RatedUnqueue-01.clicktest | 2 +- tools/click-devirtualize/cxxclass.cc | 1277 ++++++++++-------- tools/click-devirtualize/specializer.cc | 4 +- tools/click-devirtualize/specializer.hh | 4 +- tools/click-mkmindriver/click-mkmindriver.cc | 3 + userlevel/.gitignore | 1 + userlevel/Makefile.in | 3 +- vendor/nicscheduler/methods/rss.cc | 11 +- vendor/nicscheduler/methods/rss.hh | 1 + vendor/swifsymbol/swifsymbol.c | 62 + vendor/swifsymbol/swifsymbol.h | 47 + vendor/tinymt32/LICENSE | 30 + vendor/tinymt32/tinymt32.c | 145 ++ vendor/tinymt32/tinymt32.h | 257 ++++ 111 files changed, 3255 insertions(+), 1216 deletions(-) create mode 100644 elements/ip6/ip6drop.cc create mode 100644 elements/ip6/ip6drop.hh create mode 100644 elements/ip6/ip6srdecap.cc create mode 100644 elements/ip6/ip6srdecap.hh create mode 100644 elements/ip6/ip6srencap.cc create mode 100644 elements/ip6/ip6srencap.hh create mode 100644 elements/ip6/ip6srprocess.cc create mode 100644 elements/ip6/ip6srprocess.hh create mode 100644 vendor/swifsymbol/swifsymbol.c create mode 100644 vendor/swifsymbol/swifsymbol.h create mode 100644 vendor/tinymt32/LICENSE create mode 100644 vendor/tinymt32/tinymt32.c create mode 100644 vendor/tinymt32/tinymt32.h diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 366a043a5a..84ff516b97 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,87 +1,105 @@ -#This file is quite deprecated, but we keep it there in case someone has an internal GitLab CI pipeline and wants to reuse this - default: - image: ubuntu:22.04 + image: ubuntu:22.04 + tags: + - docker + +stages: + - normal + - user + - io variables: - NETMAP_VERSION: "11.1" CONFIG: "--enable-all-elements --disable-verbose-batch --enable-simtime" +.common: + stage: user + parallel: + matrix: + - HOST: ["x86_64","aarch64"] + +normal: + extends: .common + stage: normal + script: + - ./configure $CONFIG_HOST CXXFLAGS="-std=gnu++11" $CONFIG --disable-verbose-batch && make + batch: + extends: .common script: - - ./configure CXXFLAGS="-std=gnu++11" --enable-batch $CONFIG --disable-verbose-batch && make && make check + - ./configure $CONFIG_HOST CXXFLAGS="-std=gnu++11" --enable-batch $CONFIG --disable-verbose-batch && make && make check autobatch: + extends: .common script: - - ./configure CXXFLAGS="-std=gnu++11" --enable-batch $CONFIG --disable-verbose-batch --enable-auto-batch=port && make && make check + - ./configure $CONFIG_HOST CXXFLAGS="-std=gnu++11" --enable-batch $CONFIG --disable-verbose-batch --enable-auto-batch=port && make && make check ip6: + extends: .common script: - - ./configure CXXFLAGS="-std=gnu++11" --enable-ip6 --enable-json $CONFIG --disable-batch && make && make check + - ./configure $CONFIG_HOST CXXFLAGS="-std=gnu++11" --enable-ip6 --enable-json $CONFIG --disable-batch && make && make check mt: + extends: .common script: - - ./configure CXXFLAGS="-std=gnu++11" --enable-user-multithread $CONFIG --disable-batch && make && make check - + - ./configure $CONFIG_HOST CXXFLAGS="-std=gnu++11" --enable-user-multithread $CONFIG --disable-batch && make && make check noclone: + extends: .common + script: + - ./configure $CONFIG_HOST CXXFLAGS="-std=gnu++11" --enable-user-multithread $CONFIG --disable-clone && make && make check +fbatch: + extends: .common script: - - ./configure CXXFLAGS="-std=gnu++11" --enable-user-multithread $CONFIG --disable-clone && make && make check + - ./configure $CONFIG_HOST CXXFLAGS="-std=gnu++11" --enable-user-multithread --enable-flow --enable-batch $CONFIG --disable-verbose-batch && make dpdk: - parallel: - matrix: - - DPDK_VERSION: ["20.11", "23.03"] - DPDK_CONFIG: ["--enable-dpdk-packet --enable-batch", "--enable-batch", "--disable-batch", "--enable-dpdk-pool"] - before_script: - - echo "Running global pre-install..." - - !reference [before_script] - - echo "Running local pre-install..." - - mkdir /dpdk - - pushd /dpdk - - export RTE_SDK=`pwd`/dpdk-$DPDK_VERSION; - export RTE_TARGET=x86_64-native-linuxapp-gcc; - export PKG_CONFIG_PATH=${RTE_SDK}/install/lib/x86_64-linux-gnu/pkgconfig/; - export LD_LIBRARY_PATH=${RTE_SDK}/install/lib/x86_64-linux-gnu/:${RTE_SDK}/install/lib/:$LD_LIBRARY_PATH; - if [ ! -e "$RTE_SDK/$RTE_TARGET/include/rte_version.h" ]; then - wget http://dpdk.org/browse/dpdk/snapshot/dpdk-$DPDK_VERSION.tar.gz && - tar -zxf dpdk-$DPDK_VERSION.tar.gz && - cd dpdk-$DPDK_VERSION ; - pip3 install meson ninja && - meson -Dprefix=$(pwd)/install/ -Dmachine=default build && - cd build && ( ninja && ninja install ) ; cd .. ; cd .. ; - fi; - ldconfig - - popd - script: + stage: io + parallel: + matrix: + - DPDK_VERSION: ["20.11", "23.03"] + DPDK_CONFIG: ["--enable-dpdk-packet --enable-batch", "--enable-batch", "--disable-batch", "--enable-dpdk-pool"] + before_script: + - echo "Running global pre-install..." + - !reference [before_script] + - echo "Running local pre-install..." + - mkdir /dpdk + - pushd /dpdk + - export RTE_SDK=`pwd`/dpdk-$DPDK_VERSION; + export RTE_TARGET=x86_64-native-linuxapp-gcc; + export PKG_CONFIG_PATH=${RTE_SDK}/install/lib/x86_64-linux-gnu/pkgconfig/; + export LD_LIBRARY_PATH=${RTE_SDK}/install/lib/x86_64-linux-gnu/:${RTE_SDK}/install/lib/:$LD_LIBRARY_PATH; + if [ ! -e "$RTE_SDK/$RTE_TARGET/include/rte_version.h" ]; then + wget http://dpdk.org/browse/dpdk/snapshot/dpdk-$DPDK_VERSION.tar.gz && + tar -zxf dpdk-$DPDK_VERSION.tar.gz && + cd dpdk-$DPDK_VERSION ; + pip3 install meson ninja && + meson -Dprefix=$(pwd)/install/ -Dmachine=default build && + cd build && ( ninja && ninja install ) ; cd .. ; cd .. ; + fi; + ldconfig + - popd + script: - ls $PKG_CONFIG_PATH - echo $LD_LIBRARY_PATH - - ./configure CXXFLAGS="-std=gnu++11" --enable-user-multithread --without-netmap --enable-dpdk ${DPDK_CONFIG} $CONFIG RTE_SDK=$RTE_SDK RTE_TARGET=$RTE_TARGET && make - - if [[ "$DPDK_CONFIG" != *"--enable-dpdk-pool"* ]] ; then make check ; fi + - ./configure $CONFIG_HOST CXXFLAGS="-std=gnu++11" --enable-user-multithread --without-netmap --enable-dpdk ${DPDK_CONFIG} $CONFIG RTE_SDK=$RTE_SDK RTE_TARGET=$RTE_TARGET && make + - if [[ "$DPDK_CONFIG" != *"--enable-dpdk-pool"* ]] && [[ "$DPDK_CONFIG" != *"--enable-dpdk-packet"* ]] ; then make check ; fi -netmap_single: - script: - - ./configure CXXFLAGS="-std=gnu++11" $CONFIG_NETMAP $CONFIG --disable-verbose-batch && make netmap: + stage: io + parallel: + matrix: + - NETMAP_VERSION: ["11.1"] + CONFIG_NETMAP_MODE: ["--enable-netmap-pool --enable-zerocopy","--disable-netmap-pool --enable-zerocopy","--disable-netmap-pool --disable-zerocopy","--enable-flow --enable-batch --enable-netmap-pool --enable-zerocopy"] script: - - ./configure CXXFLAGS="-std=gnu++11" --enable-user-multithread $CONFIG_NETMAP --enable-netmap-pool --enable-zerocopy $CONFIG --disable-verbose-batch && make -netmap_nopool: - script: - - ./configure CXXFLAGS="-std=gnu++11" --enable-user-multithread $CONFIG_NETMAP --disable-netmap-pool --enable-zerocopy $CONFIG --disable-verbose-batch && make && make check -netmap_nopool_nozc: - script: - - ./configure CXXFLAGS="-std=gnu++11" --enable-user-multithread $CONFIG_NETMAP --disable-netmap-pool --disable-zerocopy $CONFIG --disable-verbose-batch && make && make check -fbatch: - script: - - ./configure CXXFLAGS="-std=gnu++11" --enable-user-multithread --enable-flow --enable-batch $CONFIG --disable-verbose-batch && make -fnetmap: - script: - - ./configure CXXFLAGS="-std=gnu++11" --enable-user-multithread $CONFIG_NETMAP --enable-flow --enable-batch --enable-netmap-pool --enable-zerocopy $CONFIG --disable-verbose-batch && make + - if [ ! -e "netmap-$NETMAP_VERSION/sys/net/netmap.h" ] ; then wget https://github.com/luigirizzo/netmap/archive/v$NETMAP_VERSION.tar.gz && tar -xvf v$NETMAP_VERSION.tar.gz && ( cd netmap-$NETMAP_VERSION && cd LINUX && ./configure --no-drivers ; cd .. && cd .. ) ; fi + - ls -al + - if [ `sudo -n whoami` = "root" ] && command -v insmod ; then sudo insmod netmap-$NETMAP_VERSION/LINUX/netmap.ko && sudo chmod 666 /dev/netmap ; fi + - export CONFIG_NETMAP="--with-netmap=`pwd`/netmap-$NETMAP_VERSION/sys/" + - ./configure CXXFLAGS="-std=gnu++11" $CONFIG_NETMAP_MODE $CONFIG_NETMAP $CONFIG --disable-verbose-batch && make cache: paths: - /dpdk - netmap-$NETMAP_VERSION + before_script: - - sh deps.sh + - DEBIAN_FRONTEND=noninteractive sh deps.sh - gcc -v - - if [ ! -e "netmap-$NETMAP_VERSION/sys/net/netmap.h" ] ; then wget https://github.com/luigirizzo/netmap/archive/v$NETMAP_VERSION.tar.gz && tar -xvf v$NETMAP_VERSION.tar.gz && ( cd netmap-$NETMAP_VERSION && cd LINUX && ./configure --no-drivers ; cd .. && cd .. ) ; fi - - ls -al - - if [ `sudo -n whoami` = "root" ] ; then sudo insmod netmap-$NETMAP_VERSION/LINUX/netmap.ko && sudo chmod 666 /dev/netmap ; fi - - export CONFIG_NETMAP="--with-netmap=`pwd`/netmap-$NETMAP_VERSION/sys/" + - if [ "$HOST" = "x86_64" ] ; then export CONFIG_HOST="--build x86_64-native-linuxapp-gcc" ; fi + - if [ "$HOST" = "aarch64" ] ; then apt-get -yqq install gcc-aarch64-linux-gnu && export CONFIG_HOST="--build aarch64-linux-gnu" ; fi diff --git a/README.md b/README.md index a50de757d9..e273cb0eb2 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Quick start (using DPDK for I/O) * Build FastClick, with support for DPDK using the following command: ``` -./configure --enable-dpdk --enable-intel-cpu --verbose --enable-select=poll CFLAGS="-O3" CXXFLAGS="-std=c++11 -O3" --disable-dynamic-linking --enable-poll --enable-bound-port-transfer --enable-local --enable-flow --disable-task-stats --disable-cpu-load +./configure CFLAGS="-O3" CXXFLAGS="-std=c++11 -O3" --enable-dpdk --enable-intel-cpu --disable-dynamic-linking --enable-bound-port-transfer --enable-flow --disable-task-stats --disable-cpu-load make ``` @@ -32,7 +32,7 @@ FastClick "Light" ----------------- FastClick, like Click comes with a lot of features that you may not use. The following options will improve performance further : ``` -./configure --enable-dpdk --enable-intel-cpu --verbose --enable-select=poll CFLAGS="-O3" CXXFLAGS="-std=c++11 -O3" --disable-dynamic-linking --enable-poll --enable-bound-port-transfer --enable-local --enable-flow --disable-task-stats --disable-cpu-load --enable-dpdk-packet --disable-clone --disable-dpdk-softqueue +./configure CFLAGS="-O3" CXXFLAGS="-std=c++11 -O3" --enable-dpdk --enable-intel-cpu --disable-dynamic-linking --enable-bound-port-transfer --enable-flow --disable-task-stats --disable-cpu-load --enable-dpdk-packet --disable-clone --disable-dpdk-softqueue make ``` * Disable task stats suppress statistics tracking for advanced task scheduling with e.g. BalancedThreadSched. With DPDK, it's polling anyway... And as far as scheduling is concerned, [RSS++](#rss) has a better solution. diff --git a/aclocal.m4 b/aclocal.m4 index b1cc5cfa8c..b8f86ec097 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,6 +1,6 @@ -# generated automatically by aclocal 1.16.1 -*- Autoconf -*- +# generated automatically by aclocal 1.17 -*- Autoconf -*- -# Copyright (C) 1996-2018 Free Software Foundation, Inc. +# Copyright (C) 1996-2024 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff --git a/config-userlevel.h.in b/config-userlevel.h.in index 68be606eb5..b32a5fed02 100644 --- a/config-userlevel.h.in +++ b/config-userlevel.h.in @@ -39,7 +39,7 @@ #undef HAVE_CLICK_LOAD /* Define if Click can use a packet pool */ -#undef ALLOW_CLICK_PACKET_POOL +#undef HAVE_ALLOW_CLICK_PACKET_POOL /* Define if context system is enabled. */ #undef HAVE_CTX @@ -116,12 +116,21 @@ /* Define if your C library contains large file support. */ #undef HAVE_LARGE_FILE_SUPPORT +/* Define if you have the header file. */ +#undef HAVE_LINUX_ETHTOOL_H + +/* Define if you have the header file. */ +#undef HAVE_LINUX_SOCKIOS_H + /* Define if you have the header file. */ #undef HAVE_LINUX_IF_TUN_H /* Define if you have the header file. */ #undef HAVE_LINUX_IF_PACKET_H +/* Define if you have the header file. */ +#undef HAVE_LINUX_NETLINK_H + /* Define if you have the madvise function. */ #undef HAVE_MADVISE diff --git a/config.h.in b/config.h.in index 013029e7ab..21264d847e 100644 --- a/config.h.in +++ b/config.h.in @@ -71,6 +71,9 @@ /* Define if you have the __has_trivial_copy compiler intrinsic. */ #undef HAVE___HAS_TRIVIAL_COPY +/* Define if you have the __is_trivially_copyable compiler intrinsic. */ +#undef HAVE___IS_TRIVIALLY_COPYABLE + /* Define if you have the __sync_synchronize function. */ #undef HAVE___SYNC_SYNCHRONIZE @@ -200,6 +203,9 @@ /* The size of a `void *', as computed by sizeof. */ #undef SIZEOF_VOID_P +/* Define if SSE2 instruction is available. */ +#undef HAVE_SSE2 + /* Define if SSE4.2 instruction is available. */ #undef HAVE_SSE42 diff --git a/configure b/configure index 35dd4f8f4b..e1f5c89121 100755 --- a/configure +++ b/configure @@ -938,6 +938,7 @@ enable_hash_allocator_poisoning enable_portable_binary enable_intel_cpu enable_avx2 +enable_sse2 enable_sse42 enable_atomic_builtins with_numa @@ -1710,6 +1711,7 @@ Optional Features: unportable binaries --enable-intel-cpu enable Intel-specific machine instructions --disable-avx2 Do not check whether AVX2 is enabled + --disable-sse2 Do not check whether SSE2 is enabled --disable-sse42 Do not check whether SSE4.2 is enabled --enable-atomic-builtins Use GCC builtins atomic functions instead of Click @@ -3680,8 +3682,11 @@ as_fn_append ac_header_c_list " sys/mman.h sys_mman_h HAVE_SYS_MMAN_H" as_fn_append ac_header_c_list " sys/param.h sys_param_h HAVE_SYS_PARAM_H" as_fn_append ac_func_c_list " getpagesize HAVE_GETPAGESIZE" as_fn_append ac_header_cxx_list " ifaddrs.h ifaddrs_h HAVE_IFADDRS_H" +as_fn_append ac_header_cxx_list " linux/ethtool.h linux_ethtool_h HAVE_LINUX_ETHTOOL_H" +as_fn_append ac_header_cxx_list " linux/sockios.h linux_sockios_h HAVE_LINUX_SOCKIOS_H" as_fn_append ac_header_cxx_list " linux/if_tun.h linux_if_tun_h HAVE_LINUX_IF_TUN_H" as_fn_append ac_header_cxx_list " linux/if_packet.h linux_if_packet_h HAVE_LINUX_IF_PACKET_H" +as_fn_append ac_header_cxx_list " linux/netlink.h linux_netlink_h HAVE_LINUX_NETLINK_H" as_fn_append ac_header_cxx_list " net/if_dl.h net_if_dl_h HAVE_NET_IF_DL_H" as_fn_append ac_header_cxx_list " net/if_tap.h net_if_tap_h HAVE_NET_IF_TAP_H" as_fn_append ac_header_cxx_list " net/if_tun.h net_if_tun_h HAVE_NET_IF_TUN_H" @@ -8030,7 +8035,8 @@ done if test "x$ac_have_hyperscan$ac_have_hyperscan_h" = "xyesyes"; then have_hyperscan=yes LIBS="$LIBS -lhs" - printf "%s\n" "#define HAVE_HYPERSCAN 1" >>confdefs.h + +printf "%s\n" "#define HAVE_HYPERSCAN 1" >>confdefs.h else have_hyperscan=no @@ -8109,7 +8115,8 @@ fi done if test "x$ac_have_papi_h$ac_have_papi" = "xyesyes"; then - printf "%s\n" "#define HAVE_PAPI 1" >>confdefs.h + +printf "%s\n" "#define HAVE_PAPI 1" >>confdefs.h have_papi=yes else @@ -8308,7 +8315,8 @@ if test ${enable_click_pool+y} then : enableval=$enable_click_pool; : else $as_nop - enable_click_pool=yes;printf "%s\n" "#define ALLOW_CLICK_PACKET_POOL 1" >>confdefs.h + enable_click_pool=yes; +printf "%s\n" "#define HAVE_ALLOW_CLICK_PACKET_POOL 1" >>confdefs.h fi @@ -9124,7 +9132,7 @@ int main (void) { #ifndef __linux__ -#error "fuckers! fuckers!" +#error "unsupported" #endif return 0; ; @@ -9142,6 +9150,37 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_under_linux" >&5 printf "%s\n" "$ac_cv_under_linux" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are compiling for Apple Mach" >&5 +printf %s "checking whether we are compiling for Apple Mach... " >&6; } +if test ${ac_cv_under_mach+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +#if !(defined(__MACH__) && defined(__APPLE__)) +#error "unsupported" +#endif +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO" +then : + ac_cv_under_mach=yes +else $as_nop + ac_cv_under_mach=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_under_mach" >&5 +printf "%s\n" "$ac_cv_under_mach" >&6; } + ac_ext=c @@ -10554,6 +10593,39 @@ printf "%s\n" "#define HAVE___SYNC_SYNCHRONIZE_ARGUMENTS 1" >>confdefs.h fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __is_trivially_copyable" >&5 +printf %s "checking for __is_trivially_copyable... " >&6; } +if test ${ac_cv_have___is_trivially_copyable+y} +then : + printf %s "(cached) " >&6 +else $as_nop + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main (void) +{ +long x = 1; if (__is_trivially_copyable(long)) x = 0; + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO" +then : + ac_cv_have___is_trivially_copyable=yes +else $as_nop + ac_cv_have___is_trivially_copyable=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have___is_trivially_copyable" >&5 +printf "%s\n" "$ac_cv_have___is_trivially_copyable" >&6; } + if test $ac_cv_have___is_trivially_copyable = yes; then + +printf "%s\n" "#define HAVE___IS_TRIVIALLY_COPYABLE 1" >>confdefs.h + + fi + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __has_trivial_copy" >&5 printf %s "checking for __has_trivial_copy... " >&6; } if test ${ac_cv_have___has_trivial_copy+y} @@ -14845,6 +14917,24 @@ if test $ac_cv_linux_sb_lock = yes; then fi + for ac_header in asm/ioctl.h +do : + ac_fn_cxx_check_header_compile "$LINENO" "asm/ioctl.h" "ac_cv_header_asm_ioctl_h" "$ac_includes_default" +if test "x$ac_cv_header_asm_ioctl_h" = xyes +then : + printf "%s\n" "#define HAVE_ASM_IOCTL_H 1" >>confdefs.h + have_asm_ioctl_h=yes +else $as_nop + have_asm_ioctl_h=no +fi + +done +if test "$have_asm_ioctl_h" = yes; then + printf "%s\n" "#define HAVE_ASM_IOCTL_H 1" >>confdefs.h + +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dev_ioctl kernel symbol" >&5 printf %s "checking for dev_ioctl kernel symbol... " >&6; } if test ${ac_cv_linux_dev_ioctl+y} @@ -15490,6 +15580,46 @@ fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ +#ifndef __SSE2__ +#error +#endif + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO" +then : + cpu_supports_sse2="yes" +else $as_nop + cpu_supports_sse2="no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +# Check whether --enable-sse2 was given. +if test ${enable_sse2+y} +then : + enableval=$enable_sse2; check_sse2=no +else $as_nop + check_sse2=yes +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if SSE2 should be used" >&5 +printf %s "checking if SSE2 should be used... " >&6; } +if test "x$cpu_supports_sse2$check_sse2" = "xyesyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + printf "%s\n" "#define HAVE_SSE2 1" >>confdefs.h + + save_cflags="$CFLAGS" + CFLAGS="$save_cflags -msse2" + save_cxxflags="$CXXFLAGS" + CXXFLAGS="$save_cxxflags -msse2" +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + #ifndef __SSE4_2__ #error #endif @@ -15594,6 +15724,9 @@ done + + + POSSIBLE_DRIVERS= for i in bsdmodule linuxmodule ns userlevel minios; do test -f $srcdir/$i/Makefile.in && POSSIBLE_DRIVERS="$POSSIBLE_DRIVERS $i" @@ -16438,7 +16571,6 @@ else $as_nop fi if test "$properprefix" != no; then - saveflags="$CPPFLAGS"; test -n "$properprefix" && CPPFLAGS="$CPPFLAGS -I$properprefix/include" ac_fn_c_check_header_compile "$LINENO" "prop.h" "ac_cv_header_prop_h" "$ac_includes_default" if test "x$ac_cv_header_prop_h" = xyes @@ -18510,7 +18642,6 @@ if test "x$enable_minios" = xyes; then fi - if test "x$enable_tools" != xno; then OTHER_TARGETS="$OTHER_TARGETS tools" fi diff --git a/configure.in b/configure.in index dd5ca5c1c6..85687ca465 100644 --- a/configure.in +++ b/configure.in @@ -254,7 +254,7 @@ AC_CHECK_HEADERS([hs/hs.h], [ac_have_hyperscan_h=yes], [ac_have_hyperscan_h=no]) if test "x$ac_have_hyperscan$ac_have_hyperscan_h" = "xyesyes"; then have_hyperscan=yes LIBS="$LIBS -lhs" - AC_DEFINE([HAVE_HYPERSCAN]) + AC_DEFINE([HAVE_HYPERSCAN],[1],[Have the hyperscan library for regex matching.]) else have_hyperscan=no fi @@ -262,7 +262,7 @@ fi AC_SEARCH_LIBS([PAPI_start_counters], [papi], [ac_have_papi=yes], [ac_have_papi=no]) AC_CHECK_HEADERS([papi.h], [ac_have_papi_h=yes], [ac_have_papi_h=no]) if test "x$ac_have_papi_h$ac_have_papi" = "xyesyes"; then - AC_DEFINE([HAVE_PAPI]) + AC_DEFINE([HAVE_PAPI],[1],[Have the libpapi library for performance counters.]) have_papi=yes else have_papi=no @@ -348,7 +348,7 @@ AC_ARG_ENABLE([flow-api], [AS_HELP_STRING([ --enable-flow-api], [Support for AC_ARG_ENABLE([click-pool], [AS_HELP_STRING([ --disable-click-pool], [allow usage of Click Packet pool. It will still only be effectively enabled in specific (but most) cases, see packet.hh])], - [:], [enable_click_pool=yes;AC_DEFINE(ALLOW_CLICK_PACKET_POOL)]) + [:], [enable_click_pool=yes;AC_DEFINE(HAVE_ALLOW_CLICK_PACKET_POOL,[1],[Define if Click packet pool can be used if others flags allow it (see packet.hh).])]) AC_ARG_ENABLE([pool-inlining], @@ -780,10 +780,16 @@ dnl AC_CACHE_CHECK([whether we are compiling for Linux], [ac_cv_under_linux], [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[#ifndef __linux__ -#error "fuckers! fuckers!" +#error "unsupported" #endif return 0;]])], ac_cv_under_linux=yes, ac_cv_under_linux=no)]) +AC_CACHE_CHECK([whether we are compiling for Apple Mach], [ac_cv_under_mach], + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[#if !(defined(__MACH__) && defined(__APPLE__)) +#error "unsupported" +#endif +return 0;]])], ac_cv_under_mach=yes, ac_cv_under_mach=no)]) + dnl dnl functions @@ -1234,6 +1240,12 @@ if test $ac_cv_linux_sb_lock = yes; then AC_DEFINE(HAVE_LINUX_SB_LOCK) fi +AC_CHECK_HEADERS(asm/ioctl.h, have_asm_ioctl_h=yes, have_asm_ioctl_h=no) +if test "$have_asm_ioctl_h" = yes; then + AC_DEFINE([HAVE_ASM_IOCTL_H]) +fi + + AC_CACHE_CHECK([for dev_ioctl kernel symbol], ac_cv_linux_dev_ioctl, [if grep "__ksymtab_dev_ioctl" $linux_system_map >/dev/null 2>&1; then ac_cv_linux_dev_ioctl=yes @@ -1513,6 +1525,29 @@ else AC_MSG_RESULT([no]) fi +AC_COMPILE_IFELSE([ +#ifndef __SSE2__ +#error +#endif + ], [cpu_supports_sse2="yes"], [cpu_supports_sse2="no"]) +AC_ARG_ENABLE([sse2], + AS_HELP_STRING([--disable-sse2], + [Do not check whether SSE2 is enabled]), + [check_sse2=no], + [check_sse2=yes]) + +AC_MSG_CHECKING([if SSE2 should be used]) +if test "x$cpu_supports_sse2$check_sse2" = "xyesyes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_SSE2],1) + save_cflags="$CFLAGS" + CFLAGS="$save_cflags -msse2" + save_cxxflags="$CXXFLAGS" + CXXFLAGS="$save_cxxflags -msse2" +else + AC_MSG_RESULT([no]) +fi + AC_COMPILE_IFELSE([ #ifndef __SSE4_2__ #error @@ -1596,7 +1631,7 @@ dnl dnl kernel interfaces dnl -AC_CHECK_HEADERS_ONCE([ifaddrs.h linux/if_tun.h linux/if_packet.h net/if_dl.h net/if_tap.h net/if_tun.h net/if_types.h net/bpf.h netpacket/packet.h]) +AC_CHECK_HEADERS_ONCE([ifaddrs.h linux/ethtool.h linux/sockios.h linux/if_tun.h linux/if_packet.h linux/netlink.h net/if_dl.h net/if_tap.h net/if_tun.h net/if_types.h net/bpf.h netpacket/packet.h]) dnl @@ -1879,10 +1914,6 @@ AC_ARG_WITH(proper, [[ --with-proper[=PREFIX] use PlanetLab Proper library (op [properprefix=$withval; if test -z "$withval" -o "$withval" = yes; then properprefix=; fi], [properprefix=no; explicit_proper=no]) if test "$properprefix" != no; then - dnl Proper requires libcurl - dnl AC_CHECK_HEADER(curl/curl.h, have_curl_h=yes, have_curl_h=no) - dnl AC_CHECK_LIB(curl, curl_easy_init) - saveflags="$CPPFLAGS"; test -n "$properprefix" && CPPFLAGS="$CPPFLAGS -I$properprefix/include" AC_CHECK_HEADER(prop.h, have_prop_h=yes, have_prop_h=no) CPPFLAGS="$saveflags" @@ -2490,7 +2521,6 @@ if test "x$enable_minios" = xyes; then HAVE_MINIOS_DRIVER=1 fi - dnl check tools if test "x$enable_tools" != xno; then diff --git a/deps.sh b/deps.sh index 23ca32effa..4aa4cff5c0 100755 --- a/deps.sh +++ b/deps.sh @@ -2,7 +2,7 @@ # This installs dependencies for both DPDK and FastClick, support for apt-get(Debian, Ubuntu, ...) and apk (Alpine) for now. PRs are welcome. opt=0 -if [ $1 = "--optional" ] ; then +if [ "$1" = "--optional" ] ; then opt=1 fi diff --git a/doc/click-elem2man b/doc/click-elem2man index f62565b80f..9ad7366bc3 100755 --- a/doc/click-elem2man +++ b/doc/click-elem2man @@ -91,7 +91,7 @@ my(@section_headers) = 'nat' => 'Network Address Translation', 'tcp' => 'TCP', 'udp' => 'UDP', - 'gtp' => 'GTP', + 'tunnel' => 'Tunnel (GRE, ...)', 'app' => 'Applications', 'traces' => 'Trace Manipulation', 'ipmeasure' => 'TCP/IP Measurement', diff --git a/doc/clicktest.1 b/doc/clicktest.1 index 4d343b5c7b..3e7a576f7a 100644 --- a/doc/clicktest.1 +++ b/doc/clicktest.1 @@ -46,7 +46,7 @@ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" -.\" If the F register is >0, we'll generate index entries on stderr for +.\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. @@ -219,7 +219,8 @@ ClickTest test files consist of several sections, each introduced by a line starting with \fB%\fR. There must be, at least, a \fB\f(CB%script\fB\fR section. The \fB\f(CB%file\fB\fR and \fB\f(CB%expect\fB\fR sections define input and output files by name. -.IP "\fB\f(CB%script\fB\fR" 8 +.ie n .IP "\fB\fB%script\fB\fR" 8 +.el .IP "\fB\f(CB%script\fB\fR" 8 .IX Item "%script" The \fBsh\fR shell script that controls the test. ClickTest will run each command in sequence. Every command in the script must succeed, with @@ -236,7 +237,8 @@ The script's environment is populated with any \fI\s-1VARIABLE\s0\fRs set on the clicktest command line with \fB\f(BI\s-1VARIABLE\s0\fB=\f(BI\s-1VALUE\s0\fB\fR syntax. Also, the \&\fB\f(CB$rundir\fB\fR environment variable is set to the directory in which clicktest was originally run. -.IP "\fB\f(CB%require\fB [\-q]\fR" 8 +.ie n .IP "\fB\fB%require\fB [\-q]\fR" 8 +.el .IP "\fB\f(CB%require\fB [\-q]\fR" 8 .IX Item "%require [-q]" An \fBsh\fR shell script defining prerequisites that must be satisfied before the test can run. Every command in the script must succeed, with @@ -246,15 +248,18 @@ if a requirement fails. .Sp ClickTest runs the requirement script before creating any other test files. For example, contents of \fB\f(CB%file\fB\fR sections are not available. -.IP "\fB\f(CB%info\fB\fR" 8 +.ie n .IP "\fB\fB%info\fB\fR" 8 +.el .IP "\fB\f(CB%info\fB\fR" 8 .IX Item "%info" A short description of the test. In \fB\-\-superverbose\fR mode, the first paragraph of its contents is printed before the test results. -.IP "\fB\f(CB%cut\fB\fR" 8 +.ie n .IP "\fB\fB%cut\fB\fR" 8 +.el .IP "\fB\f(CB%cut\fB\fR" 8 .IX Item "%cut" This section is ignored. It is intended to comment out obsolete parts of the test. -.IP "\fB\f(CB%file\fB [\-de] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 +.ie n .IP "\fB\fB%file\fB [\-de] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 +.el .IP "\fB\f(CB%file\fB [\-de] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 .IX Item "%file [-de] [+LENGTH] FILENAME..." Create an input file for the script. \fI\s-1FILENAME\s0\fR can be \fBstdin\fR, which sets the script's standard input. If \fB+\fR\fI\s-1LENGTH\s0\fR is provided, @@ -266,7 +271,8 @@ Base64\-encoded (see \fBbase64\fR\|(1)); it is decoded before use. To include a file with lines that start with \fB%\fR (which would normally start a new section), use \fB\-d\fR and preface each line of the file with a space, or use \fB\-e\fR. -.IP "\fB\f(CB%expect\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 +.ie n .IP "\fB\fB%expect\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 +.el .IP "\fB\f(CB%expect\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 .IX Item "%expect [-adeiw] [+LENGTH] FILENAME..." Define an expected output file. Differences between the script's output \fI\s-1FILENAME\s0\fR and the contents of the \fB\f(CB%expect\fB\fR section will @@ -308,29 +314,35 @@ The \fB\-a\fR flag marks this expected output as an alternate. ClickTest will compare the script's output file with each provided alternate; the test succeeds if any of the alternates match. The \fB\-d\fR flag behaves as in \fB\f(CB%file\fB\fR. -.IP "\fB\f(CB%expectv\fB [\-ade] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 +.ie n .IP "\fB\fB%expectv\fB [\-ade] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 +.el .IP "\fB\f(CB%expectv\fB [\-ade] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 .IX Item "%expectv [-ade] [+LENGTH] FILENAME..." Define a literal expected output file. This behaves like \fB\f(CB%expect\fB\fR, except that the script's output file must match the provided data \&\fIexactly\fR: \fB\f(CB%expectv\fB\fR never ignores whitespace differences, does not treat \f(CW\*(C`{{}}\*(C'\fR blocks as regular expressions, and does not parse \&\fB\f(CB%ignore\fB\fR patterns. -.IP "\fB\f(CB%expectx\fB [\-adiw] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 +.ie n .IP "\fB\fB%expectx\fB [\-adiw] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 +.el .IP "\fB\f(CB%expectx\fB [\-adiw] [+\f(BI\s-1LENGTH\s0\fB] \f(BI\s-1FILENAME\s0\fB...\fR" 8 .IX Item "%expectx [-adiw] [+LENGTH] FILENAME..." Define a regular-expression expected output file. This behaves like \&\fB\f(CB%expect\fB\fR, except that every line is treated as a regular expression. \&\f(CW\*(C`{{?comment}}\*(C'\fR blocks are ignored, but other brace pairs are treated according to the normal regular expression rules. -.IP "\fB\f(CB%stdin\fB [\-de] [+\f(BI\s-1LENGTH\s0\fB]\fR" 8 +.ie n .IP "\fB\fB%stdin\fB [\-de] [+\f(BI\s-1LENGTH\s0\fB]\fR" 8 +.el .IP "\fB\f(CB%stdin\fB [\-de] [+\f(BI\s-1LENGTH\s0\fB]\fR" 8 .IX Item "%stdin [-de] [+LENGTH]" Same as \fB\f(CB%file\fB stdin\fR. -.IP "\fB\f(CB%stdout\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB]\fR" 8 +.ie n .IP "\fB\fB%stdout\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB]\fR" 8 +.el .IP "\fB\f(CB%stdout\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB]\fR" 8 .IX Item "%stdout [-adeiw] [+LENGTH]" Same as \fB\f(CB%expect\fB stdout\fR. -.IP "\fB\f(CB%stderr\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB]\fR" 8 +.ie n .IP "\fB\fB%stderr\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB]\fR" 8 +.el .IP "\fB\f(CB%stderr\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB]\fR" 8 .IX Item "%stderr [-adeiw] [+LENGTH]" Same as \fB\f(CB%expect\fB stderr\fR. -.IP "\fB\f(CB%ignorex\fB [\-di] [+\f(BI\s-1LENGTH\s0\fB] [\f(BI\s-1FILENAME\s0\fB]\fR" 8 +.ie n .IP "\fB\fB%ignorex\fB [\-di] [+\f(BI\s-1LENGTH\s0\fB] [\f(BI\s-1FILENAME\s0\fB]\fR" 8 +.el .IP "\fB\f(CB%ignorex\fB [\-di] [+\f(BI\s-1LENGTH\s0\fB] [\f(BI\s-1FILENAME\s0\fB]\fR" 8 .IX Item "%ignorex [-di] [+LENGTH] [FILENAME]" Each line in the \fB\f(CB%ignorex\fB\fR section is a Perl regular expression. Lines in the supplied \fI\s-1FILENAME\s0\fR that match any of those regular expressions will not @@ -338,18 +350,22 @@ be considered when comparing files with \fB\f(CB%expect\fB\fR data. The regular expression must match the whole line. \fI\s-1FILENAME\s0\fR may be \fBall\fR, in which case the regular expressions will apply to all \fB\f(CB%expect\fB\fR files. \f(CW\*(C`{{?comment}}\*(C'\fR blocks are ignored. -.IP "\fB\f(CB%ignore\fB\fR, \fB\f(CB%ignorev\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB] [\f(BI\s-1FILENAME\s0\fB]\fR" 8 +.ie n .IP "\fB\fB%ignore\fB\fR, \fB\fB%ignorev\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB] [\f(BI\s-1FILENAME\s0\fB]\fR" 8 +.el .IP "\fB\f(CB%ignore\fB\fR, \fB\f(CB%ignorev\fB [\-adeiw] [+\f(BI\s-1LENGTH\s0\fB] [\f(BI\s-1FILENAME\s0\fB]\fR" 8 .IX Item "%ignore, %ignorev [-adeiw] [+LENGTH] [FILENAME]" Like \fB\f(CB%ignorex\fB\fR, but \fB\f(CB%ignore\fB\fR parses regular expressions only inside double braces (\f(CW\*(C`{{ }}\*(C'\fR), and \fB\f(CB%ignorev\fB\fR lines must match exactly. -.IP "\fB\f(CB%include\fB \f(BI\s-1FILENAME\s0\fB\fR" 8 +.ie n .IP "\fB\fB%include\fB \f(BI\s-1FILENAME\s0\fB\fR" 8 +.el .IP "\fB\f(CB%include\fB \f(BI\s-1FILENAME\s0\fB\fR" 8 .IX Item "%include FILENAME" Interpolate the contents of another clicktest file. -.IP "\fB\f(CB%eot\fB\fR" 8 +.ie n .IP "\fB\fB%eot\fB\fR" 8 +.el .IP "\fB\f(CB%eot\fB\fR" 8 .IX Item "%eot" Marks the end of the current test. The rest of the file will be parsed for additional tests. -.IP "\fB\f(CB%eof\fB\fR" 8 +.ie n .IP "\fB\fB%eof\fB\fR" 8 +.el .IP "\fB\f(CB%eof\fB\fR" 8 .IX Item "%eof" The rest of the file is ignored. .SH "EXAMPLE" diff --git a/elements/analysis/fromipsumdump.cc b/elements/analysis/fromipsumdump.cc index 7db402adf4..ad9487e09c 100644 --- a/elements/analysis/fromipsumdump.cc +++ b/elements/analysis/fromipsumdump.cc @@ -74,10 +74,11 @@ FromIPSummaryDump::configure(Vector &conf, ErrorHandler *errh) bool stop = false, active = true, zero = true, checksum = false, multipacket = false, timing = false, allow_nonexistent = false; uint8_t default_proto = IP_PROTO_TCP; _sampling_prob = (1 << SAMPLING_SHIFT); - String default_contents, default_flowid, data; + String default_contents, default_flowid, default_flowid6, data; unsigned burst = 1; bool migrate = false; bool timestamp = true; + bool ipv6 = false; if (_ff.configure_keywords(conf, this, errh) < 0) return -1; @@ -87,6 +88,9 @@ FromIPSummaryDump::configure(Vector &conf, ErrorHandler *errh) .read("STOP", stop) .read("ACTIVE", active) .read("ZERO", zero) +#if HAVE_IP6 + .read("IPV6", ipv6) +#endif .read("TIMING", timing) .read("CHECKSUM", checksum) .read("SAMPLE", FixedPointArg(SAMPLING_SHIFT), _sampling_prob) @@ -95,9 +99,11 @@ FromIPSummaryDump::configure(Vector &conf, ErrorHandler *errh) .read("DEFAULT_CONTENTS", AnyArg(), default_contents) .read("DEFAULT_FIELDS", AnyArg(), default_contents) .read("DEFAULT_FLOWID", AnyArg(), default_flowid) + .read("DEFAULT_FLOWID6", AnyArg(), default_flowid6) .read("CONTENTS", AnyArg(), default_contents) .read("FIELDS", AnyArg(), default_contents) .read("FLOWID", AnyArg(), default_flowid) + .read("FLOWID6", AnyArg(), default_flowid6) .read("ALLOW_NONEXISTENT", allow_nonexistent) .read("DATA", data) .read("BURST", burst) @@ -109,19 +115,21 @@ FromIPSummaryDump::configure(Vector &conf, ErrorHandler *errh) if (_sampling_prob > (1 << SAMPLING_SHIFT)) { errh->warning("SAMPLE probability reduced to 1"); _sampling_prob = (1 << SAMPLING_SHIFT); - } else if (_sampling_prob == 0) - errh->warning("SAMPLE probability is 0; emitting no packets"); + } else if (_sampling_prob == 0) { + errh->warning("SAMPLE probability is 0; emitting no packets"); + } _default_proto = default_proto; _stop = stop; _active = active; _zero = zero; + _ipv6 = ipv6; _checksum = checksum; _timing = timing; _allow_nonexistent = allow_nonexistent; _have_timing = false; _multipacket = multipacket; - _have_flowid = _have_aggregate = _binary = false; + _have_flowid = _have_flowid6 = _have_aggregate = _binary = false; _burst = burst; _migrate = migrate; _set_timestamp = timestamp; @@ -130,8 +138,12 @@ FromIPSummaryDump::configure(Vector &conf, ErrorHandler *errh) if (default_contents) bang_data(default_contents, errh); - if (default_flowid) - bang_flowid(default_flowid, errh); + if (!ipv6 && default_flowid) + bang_flowid(default_flowid, errh); +#if HAVE_IP6 + if (ipv6 && default_flowid6) + bang_flowid6(default_flowid6, errh); +#endif if (data && _ff.filename()) return errh->error("FILENAME and DATA conflict"); else if (data && _ff.set_data(data, errh) < 0) @@ -204,7 +216,8 @@ FromIPSummaryDump::initialize(ErrorHandler *errh) && !line.substring(0, 5).equals("!data", 5) && !line.substring(0, 9).equals("!contents", 9) && !line.substring(0, 6).equals("!proto", 6) - && !line.substring(0, 7).equals("!flowid", 7)) { + && !line.substring(0, 7).equals("!flowid", 7) + && !line.substring(0, 7).equals("!flowid6", 8)) { if (!_fields.size() /* don't warn on DEFAULT_CONTENTS */) _ff.warning(errh, "missing banner line; is this an IP summary dump?"); } @@ -315,6 +328,31 @@ FromIPSummaryDump::bang_flowid(const String &line, ErrorHandler *errh) _have_flowid = true; } } +#if HAVE_IP6 +void +FromIPSummaryDump::bang_flowid6(const String &line, ErrorHandler *errh) +{ + Vector words; + cp_spacevec(line, words); + + IP6Address src, dst; + uint32_t sport = 0, dport = 0; + if (words.size() < 5 + || (!IP6AddressArg().parse(words[1], src) && words[1] != "-") + || (!IntArg().parse(words[2], sport) && words[2] != "-") + || (!IP6AddressArg().parse(words[3], dst) && words[3] != "-") + || (!IntArg().parse(words[4], dport) && words[4] != "-") + || sport > 65535 || dport > 65535) { + _ff.error(errh, "bad !flowid specification"); + _have_flowid = false; + } else { + if (words.size() >= 6) + bang_proto(String::make_stable("! ", 2) + words[5], "!flowid", errh); + _given_flowid6 = IP6FlowID(src, htons(sport), dst, htons(dport)); + _have_flowid6 = true; + } +} +#endif void FromIPSummaryDump::bang_aggregate(const String &line, ErrorHandler *errh) @@ -419,6 +457,10 @@ FromIPSummaryDump::read_packet(ErrorHandler *errh) bang_data(line, errh); else if (data + 8 <= end && memcmp(data, "!flowid", 7) == 0 && isspace((unsigned char) data[7])) bang_flowid(line, errh); + #if HAVE_IP6 + else if (data + 9 <= end && memcmp(data, "!flowid6", 8) == 0 && isspace((unsigned char) data[8])) + bang_flowid6(line, errh); + #endif else if (data + 7 <= end && memcmp(data, "!proto", 6) == 0 && isspace((unsigned char) data[6])) bang_proto(line, "!proto", errh); else if (data + 11 <= end && memcmp(data, "!aggregate", 10) == 0 && isspace((unsigned char) data[10])) @@ -441,7 +483,11 @@ FromIPSummaryDump::read_packet(ErrorHandler *errh) // prepare packet data StringAccum sa; - IPSummaryDump::PacketOdesc d(this, q, _default_proto, (_have_flowid ? &_flowid : 0), _minor_version); + IPSummaryDump::PacketOdesc d(this, q, _default_proto, (_have_flowid ? &_flowid : 0), + #if HAVE_IP6 + (_have_flowid6 ? &_flowid6 : 0), + #endif + _minor_version); int nfields = 0; // new code goes here @@ -554,50 +600,69 @@ FromIPSummaryDump::read_packet(ErrorHandler *errh) } // set source and destination ports even if no transport info on packet - if (d.p && d.default_ip_flowid) - (void) d.make_ip(0); // may fail + if (!_ipv6 && d.p && d.default_ip_flowid) + (void) d.make_ip(0); // may fail +#if HAVE_IP6 + if (_ipv6 && d.p && d.default_ip6_flowid) + (void) d.make_ip6(0); // may fail +#endif // set up transport header if necessary - if (d.p && d.is_ip && d.p->ip_header()) - (void) d.make_transp(); - - if (d.p && d.is_ip && d.p->ip_header()) { - // set IP length - uint32_t ip_len; - if (!d.p->ip_header()->ip_len) { - ip_len = d.want_len; - if (ip_len >= (uint32_t) d.p->network_header_offset()) - ip_len -= d.p->network_header_offset(); - if (ip_len > 0xFFFF) - ip_len = 0xFFFF; - else if (ip_len == 0) - ip_len = d.p->network_length(); - d.p->ip_header()->ip_len = htons(ip_len); - } else - ip_len = ntohs(d.p->ip_header()->ip_len); - - // set UDP length - if (d.p->ip_header()->ip_p == IP_PROTO_UDP - && IP_FIRSTFRAG(d.p->ip_header()) - && !d.p->udp_header()->uh_ulen) { - int len = ip_len - d.p->network_header_length(); - d.p->udp_header()->uh_ulen = htons(len); - } - - // set destination IP address annotation - d.p->set_dst_ip_anno(d.p->ip_header()->ip_dst); - - // set checksum - if (_checksum) { - uint32_t xlen = 0; - if (ip_len > (uint32_t) d.p->network_length()) - xlen = ip_len - d.p->network_length(); - if (!xlen || (d.p = d.p->put(xlen))) { - if (xlen && _zero) - memset(d.p->end_data() - xlen, 0, xlen); - set_checksums(d.p, d.p->ip_header()); + if (d.p) { + if (d.is_ip && d.p->ip_header()) + (void) d.make_transp(); +#if HAVE_IP6 + else if (d.is_ip6 && d.p->ip6_header()) { + (void) d.make_transp6(); } +#endif } + + if (d.p && d.p->network_header()) { + if (d.is_ip) { + // set IP length + uint32_t ip_len; + if (!d.p->ip_header()->ip_len) { + ip_len = d.want_len; + if (ip_len >= (uint32_t) d.p->network_header_offset()) + ip_len -= d.p->network_header_offset(); + if (ip_len > 0xFFFF) + ip_len = 0xFFFF; + else if (ip_len == 0) + ip_len = d.p->network_length(); + d.p->ip_header()->ip_len = htons(ip_len); + } else + ip_len = ntohs(d.p->ip_header()->ip_len); + + // set UDP length + if (d.p->ip_header()->ip_p == IP_PROTO_UDP + && IP_FIRSTFRAG(d.p->ip_header()) + && !d.p->udp_header()->uh_ulen) { + int len = ip_len - d.p->network_header_length(); + d.p->udp_header()->uh_ulen = htons(len); + } + + // set destination IP address annotation + d.p->set_dst_ip_anno(d.p->ip_header()->ip_dst); + + // set checksum + if (_checksum) { + uint32_t xlen = 0; + if (ip_len > (uint32_t) d.p->network_length()) + xlen = ip_len - d.p->network_length(); + if (!xlen || (d.p = d.p->put(xlen))) { + if (xlen && _zero) + memset(d.p->end_data() - xlen, 0, xlen); + set_checksums(d.p, d.p->ip_header()); + } + } + } +#if HAVE_IP6 + else if (d.is_ip6) { + + //TODO XXX + } +#endif } // set extra length annotation (post-other length adjustments) diff --git a/elements/analysis/fromipsumdump.hh b/elements/analysis/fromipsumdump.hh index 3c9ab3abcb..b633fef48a 100644 --- a/elements/analysis/fromipsumdump.hh +++ b/elements/analysis/fromipsumdump.hh @@ -6,6 +6,9 @@ #include #include #include +#if HAVE_IP6 +#include +#endif #include #include "ipsumdumpinfo.hh" CLICK_DECLS @@ -189,15 +192,20 @@ class FromIPSummaryDump : public BatchElement, public IPSummaryDumpInfo { public uint16_t _default_proto; uint32_t _sampling_prob; IPFlowID _flowid; + #if HAVE_IP6 + IP6FlowID _flowid6; + #endif uint32_t _aggregate; bool _stop : 1; bool _format_complaint : 1; bool _zero : 1; + bool _ipv6 : 1; bool _checksum : 1; bool _active : 1; bool _multipacket : 1; bool _have_flowid : 1; + bool _have_flowid6 : 1; bool _have_aggregate : 1; bool _binary : 1; bool _timing : 1; @@ -219,6 +227,9 @@ class FromIPSummaryDump : public BatchElement, public IPSummaryDumpInfo { public int _minor_version; IPFlowID _given_flowid; + #if HAVE_IP6 + IP6FlowID _given_flowid6; + #endif per_thread> _args; unsigned _burst; @@ -229,6 +240,9 @@ class FromIPSummaryDump : public BatchElement, public IPSummaryDumpInfo { public void bang_data(const String &, ErrorHandler *); void bang_proto(const String &line, const char *type, ErrorHandler *errh); void bang_flowid(const String &, ErrorHandler *); + #if HAVE_IP6 + void bang_flowid6(const String &, ErrorHandler *); + #endif void bang_aggregate(const String &, ErrorHandler *); void bang_binary(const String &, ErrorHandler *); void check_defaults(); diff --git a/elements/analysis/ipsumdump_link.cc b/elements/analysis/ipsumdump_link.cc index bf285b1e30..43ac34ca9a 100644 --- a/elements/analysis/ipsumdump_link.cc +++ b/elements/analysis/ipsumdump_link.cc @@ -86,8 +86,24 @@ static void link_inject(PacketOdesc& d, const FieldReader *f) break; case T_ETH_TYPE: d.p->ether_header()->ether_type = htons(d.v); - if (d.v != ETHERTYPE_IP && d.v != ETHERTYPE_IP6) - d.is_ip = false; + + if (d.v == ETHERTYPE_IP) { + d.is_ip = true; + #if HAVE_IP6 + d.is_ip6 = false; + #endif + } else if (d.v == ETHERTYPE_IP6) { + d.is_ip = false; + #if HAVE_IP6 + d.is_ip6 = true; + #endif + } else { + d.is_ip = false; + #if HAVE_IP6 + d.is_ip6 = false; + #endif + } + break; } } diff --git a/elements/analysis/ipsumdumpinfo.cc b/elements/analysis/ipsumdumpinfo.cc index df60ac5cc2..ecb76822ff 100644 --- a/elements/analysis/ipsumdumpinfo.cc +++ b/elements/analysis/ipsumdumpinfo.cc @@ -24,6 +24,9 @@ #include #include #include +#if HAVE_IP6 +#include +#endif #include #include #include @@ -441,51 +444,125 @@ bool PacketOdesc::hard_make_ip() return true; } +#if HAVE_IP6 +bool PacketOdesc::hard_make_ip6() +{ + click_chatter("Hard make ip 6"); + if (!is_ip6) + return false; + if (!p->has_network_header()) + p->set_network_header(p->data(), 0); + if (p->network_length() < (int) sizeof(click_ip6)) { + if (!(p = p->put(sizeof(click_ip6) - p->network_length()))) + return false; + p->set_network_header(p->network_header(), sizeof(click_ip6)); + click_ip6 *iph = p->ip6_header(); + iph->ip6_flow = htonl(6 << IP6_V_SHIFT); + iph->ip6_plen = htons(p->network_length() - sizeof(click_ip6)); + iph->ip6_nxt = default_ip_p; + iph->ip6_hlim = 51; + iph->ip6_v = 6; + + if (default_ip6_flowid) { + iph->ip6_src = default_ip6_flowid->saddr(); + iph->ip6_dst = default_ip6_flowid->daddr(); + } + } + return true; +} +#endif + bool PacketOdesc::hard_make_transp() { click_ip *iph = p->ip_header(); if (IP_FIRSTFRAG(iph)) { + int len; + switch (iph->ip_p) { + case IP_PROTO_TCP: + len = sizeof(click_tcp); + break; + case IP_PROTO_UDP: + case IP_PROTO_UDPLITE: + len = sizeof(click_udp); + break; + case IP_PROTO_DCCP: + len = 12; + break; + case IP_PROTO_ICMP: + len = sizeof(click_icmp); + break; + default: + return true; + } + if (want_len > 0 + && want_len < (uint32_t) p->transport_header_offset() + len) + len = want_len - p->transport_header_offset(); + + if (p->transport_length() < len) { + int xlen = (len < 4 ? 4 : len); + if (!(p = p->put(xlen - p->transport_length()))) + return false; + if (p->ip_header()->ip_p == IP_PROTO_TCP && len >= 13) + p->tcp_header()->th_off = sizeof(click_tcp) >> 2; + if (default_ip_flowid) { + click_udp *udph = p->udp_header(); + udph->uh_sport = default_ip_flowid->sport(); + udph->uh_dport = default_ip_flowid->dport(); + } + if (xlen > len) + p->take(xlen - len); + } + } + + return true; +} + +#if HAVE_IP6 +bool PacketOdesc::hard_make_transp6() +{ + click_chatter("Make transp 6 : len %d", p->transport_length()); + click_ip6 *iph = p->ip6_header(); + int len; - switch (iph->ip_p) { + switch (iph->ip6_nxt) { case IP_PROTO_TCP: - len = sizeof(click_tcp); - break; + len = sizeof(click_tcp); + break; case IP_PROTO_UDP: case IP_PROTO_UDPLITE: - len = sizeof(click_udp); - break; + len = sizeof(click_udp); + break; case IP_PROTO_DCCP: - len = 12; - break; + len = 12; + break; case IP_PROTO_ICMP: - len = sizeof(click_icmp); - break; + len = sizeof(click_icmp); + break; default: - return true; + return true; } if (want_len > 0 - && want_len < (uint32_t) p->transport_header_offset() + len) - len = want_len - p->transport_header_offset(); + && want_len < (uint32_t) p->transport_header_offset() + len) + len = want_len - p->transport_header_offset(); if (p->transport_length() < len) { - int xlen = (len < 4 ? 4 : len); - if (!(p = p->put(xlen - p->transport_length()))) + int xlen = (len < 4 ? 4 : len); + if (!(p = p->put(xlen - p->transport_length()))) return false; - if (p->ip_header()->ip_p == IP_PROTO_TCP && len >= 13) + if (p->ip6_header()->ip6_nxt == IP_PROTO_TCP && len >= 13) p->tcp_header()->th_off = sizeof(click_tcp) >> 2; - if (default_ip_flowid) { - click_udp *udph = p->udp_header(); - udph->uh_sport = default_ip_flowid->sport(); - udph->uh_dport = default_ip_flowid->dport(); - } - if (xlen > len) + if (default_ip6_flowid) { + click_udp *udph = p->udp_header(); + udph->uh_sport = default_ip6_flowid->sport(); + udph->uh_dport = default_ip6_flowid->dport(); + } + if (xlen > len) p->take(xlen - len); } - } return true; } - +#endif const char tcp_flags_word[] = "FSRPAUECN"; diff --git a/elements/analysis/ipsumdumpinfo.hh b/elements/analysis/ipsumdumpinfo.hh index 36e09f53a2..205d12ea1b 100644 --- a/elements/analysis/ipsumdumpinfo.hh +++ b/elements/analysis/ipsumdumpinfo.hh @@ -4,9 +4,16 @@ #include #include #include +#if HAVE_IP6 +#include +#endif + CLICK_DECLS class Element; class IPFlowID; +#if HAVE_IP6 +class IP6FlowID; +#endif namespace IPSummaryDump { @@ -21,6 +28,9 @@ enum { MAJOR_VERSION = 1, MINOR_VERSION = 3 }; struct PacketDesc { const Packet *p; const click_ip *iph; +#if HAVE_IP6 + const click_ip6 *ip6; +#endif const click_udp *udph; const click_tcp *tcph; const click_icmp *icmph; @@ -64,6 +74,9 @@ struct PacketDesc { struct PacketOdesc { WritablePacket* p; bool is_ip; +#if HAVE_IP6 + bool is_ip6; +#endif bool have_icmp_type : 1; bool have_icmp_code : 1; bool have_ip_hl : 1; @@ -80,16 +93,33 @@ struct PacketOdesc { const Element *e; int default_ip_p; const IPFlowID *default_ip_flowid; +#if HAVE_IP6 + const IP6FlowID *default_ip6_flowid; +#endif int minor_version; uint32_t want_len; - inline PacketOdesc(const Element *e, WritablePacket *p, int default_ip_p, const IPFlowID *default_ip_flowid, int minor_version); + inline PacketOdesc(const Element *e, WritablePacket *p, int default_ip_p, const IPFlowID *default_ip_flowid, +#if HAVE_IP6 + const IP6FlowID *default_ip6_flowid, +#endif + int minor_version); void clear_values() { vptr[0] = vptr[1] = 0; } bool make_ip(int ip_p); +#if HAVE_IP6 + bool make_ip6(int ip_p); +#endif bool make_transp(); +#if HAVE_IP6 + bool make_transp6(); +#endif private: bool hard_make_ip(); bool hard_make_transp(); +#if HAVE_IP6 + bool hard_make_ip6(); + bool hard_make_transp6(); +#endif }; @@ -217,10 +247,21 @@ inline PacketDesc::PacketDesc(const Element *e_, Packet* p_, StringAccum* sa_, S { } -inline PacketOdesc::PacketOdesc(const Element *e_, WritablePacket* p_, int default_ip_p_, const IPFlowID *default_ip_flowid_, int minor_version_) - : p(p_), is_ip(true), have_icmp_type(false), have_icmp_code(false), +inline PacketOdesc::PacketOdesc(const Element *e_, WritablePacket* p_, int default_ip_p_, const IPFlowID *default_ip_flowid_, +#if HAVE_IP6 + const IP6FlowID *default_ip6_flowid_, +#endif + int minor_version_) + : p(p_), is_ip(true), + #if HAVE_IP6 + is_ip6(false), + #endif + have_icmp_type(false), have_icmp_code(false), have_ip_hl(false), have_tcp_hl(false), e(e_), default_ip_p(default_ip_p_), default_ip_flowid(default_ip_flowid_), + #if HAVE_IP6 + default_ip6_flowid(default_ip6_flowid_), + #endif minor_version(minor_version_), want_len(0) { } @@ -234,6 +275,17 @@ inline bool PacketOdesc::make_ip(int ip_p) return !ip_p || !p->ip_header()->ip_p || p->ip_header()->ip_p == ip_p; } +#if HAVE_IP6 +inline bool PacketOdesc::make_ip6(int nxt) +{ + if ((!is_ip6 || !p->has_network_header() + || p->network_length() < (int) sizeof(click_ip6)) + && !hard_make_ip6()) + return false; + return !nxt || !p->ip6_header()->ip6_nxt || p->ip6_header()->ip6_nxt == nxt; +} +#endif + inline bool PacketOdesc::make_transp() { // assumes make_ip() @@ -246,6 +298,18 @@ inline bool PacketOdesc::make_transp() return true; } +#if HAVE_IP6 +inline bool PacketOdesc::make_transp6() +{ + // assumes make_ip6() + assert(is_ip6 && p->network_header()); + if (p->transport_length() < 8) + return hard_make_transp6(); + else + return true; +} +#endif + inline bool field_missing(const PacketDesc &d, int proto, int l) { return (d.bad_sa ? hard_field_missing(d, proto, l) : false); diff --git a/elements/analysis/numberpacket.hh b/elements/analysis/numberpacket.hh index 6dcaf00746..c6d956d5a3 100644 --- a/elements/analysis/numberpacket.hh +++ b/elements/analysis/numberpacket.hh @@ -11,7 +11,7 @@ CLICK_DECLS NumberPacket() Set an increasing number inside packet -=s timestamps +=s analysis =d diff --git a/elements/analysis/settimestampdelta.hh b/elements/analysis/settimestampdelta.hh index 32271ba1a9..ac2e821bd0 100644 --- a/elements/analysis/settimestampdelta.hh +++ b/elements/analysis/settimestampdelta.hh @@ -1,7 +1,7 @@ // -*- mode: c++; c-basic-offset: 4 -*- #ifndef CLICK_SETTIMESTAMPDELTA_HH #define CLICK_SETTIMESTAMPDELTA_HH -#include +#include CLICK_DECLS /* @@ -44,7 +44,7 @@ relative to the next nonzero timestamp encountered. SetTimestamp, AdjustTimestamp, TimeFilter */ -class SetTimestampDelta : public Element { public: +class SetTimestampDelta : public SimpleElement { public: SetTimestampDelta() CLICK_COLD; ~SetTimestampDelta() CLICK_COLD; diff --git a/elements/ethernet/truncatefcs.hh b/elements/ethernet/truncatefcs.hh index 6d72f66c19..fb60edab7d 100644 --- a/elements/ethernet/truncatefcs.hh +++ b/elements/ethernet/truncatefcs.hh @@ -1,5 +1,5 @@ // -*- mode: c++; c-basic-offset: 4 -*- -#ifndef CLICK_TRUNCATECS_HH +#ifndef CLICK_TRUNCATEFCS_HH #define CLICK_TRUNCATEFCS_HH #include CLICK_DECLS diff --git a/elements/ip/checkipheader.cc b/elements/ip/checkipheader.cc index 07048acad5..8ad3e80f55 100644 --- a/elements/ip/checkipheader.cc +++ b/elements/ip/checkipheader.cc @@ -113,7 +113,7 @@ CheckIPHeader::configure(Vector &conf, ErrorHandler *errh) if (Args(conf, this, errh) .read("BADSRC", OldBadSrcArg(), _bad_src) - .read("OFFSET", _offset) + .read_or_set("OFFSET", _offset, 0) .complete() < 0) return -1; diff --git a/elements/ip/flowminloadswitch.cc b/elements/ip/flowminloadswitch.cc index 0664170514..830c688756 100644 --- a/elements/ip/flowminloadswitch.cc +++ b/elements/ip/flowminloadswitch.cc @@ -75,7 +75,7 @@ FlowMinLoadSwitch::round_robin() } int -FlowMinLoadSwitch::process(int port, Packet *p) +FlowMinLoadSwitch::process(int, Packet *p) { // Create a flow signature for this packet IPFlowID id(p); diff --git a/elements/ip/flowminloadswitch.hh b/elements/ip/flowminloadswitch.hh index 1fc11559bb..1cf4d9bce7 100644 --- a/elements/ip/flowminloadswitch.hh +++ b/elements/ip/flowminloadswitch.hh @@ -69,11 +69,11 @@ class FlowMinLoadSwitch : public BatchElement { return _id; } - uint32_t size() { + uint32_t size() const { return _size_bytes; } - const uint8_t output_port() { + uint8_t output_port() const { return _out_port; } diff --git a/elements/ip/iprewriterbase.hh b/elements/ip/iprewriterbase.hh index a7c71cf0a9..187a78ea78 100644 --- a/elements/ip/iprewriterbase.hh +++ b/elements/ip/iprewriterbase.hh @@ -428,8 +428,7 @@ template inline IPRewriterEntry * IPRewriterBase::search_migrate_entry(const IPFlowID &flowid, per_thread &vstate) { //If the flow does not exist, it may be in other thread's stack if there was a migration - if (vstate->rebalance > 0 && - click_jiffies() - vstate->rebalance < THREAD_MIGRATION_TIMEOUT * CLICK_HZ / 1000) { + if (vstate->rebalance > 0 && click_jiffies() - vstate->rebalance < THREAD_MIGRATION_TIMEOUT * CLICK_HZ ) { //Search in other thread's stacks for the flow for (int i = 0; i < vstate.weight(); i++) { if (vstate.get_mapping(i) == click_current_cpu_id()) diff --git a/elements/ip/setipdscp.cc b/elements/ip/setipdscp.cc index 4d4d27b70f..966fcad1a7 100644 --- a/elements/ip/setipdscp.cc +++ b/elements/ip/setipdscp.cc @@ -88,6 +88,7 @@ SetIPDSCP::pull(int) #if HAVE_BATCH PacketBatch * SetIPDSCP::pull_batch(int port, unsigned max) { + (void)port; PacketBatch *batch = input_pull_batch(0,max); FOR_EACH_PACKET(batch,p) smaction(p); diff --git a/elements/ip6/checkip6header.cc b/elements/ip6/checkip6header.cc index 80cc9356fb..f30fa09dd3 100644 --- a/elements/ip6/checkip6header.cc +++ b/elements/ip6/checkip6header.cc @@ -178,7 +178,7 @@ CheckIP6Header::read_handler(Element *e, void *thunk) switch (reinterpret_cast(thunk)) { case h_count: { PER_THREAD_SUM(uint64_t, count, c->_count); - return String(count); + return String(count); } case h_drops: { return String(c->_drops); diff --git a/elements/ip6/decip6hlim.cc b/elements/ip6/decip6hlim.cc index 6916ede611..f8787afe9c 100644 --- a/elements/ip6/decip6hlim.cc +++ b/elements/ip6/decip6hlim.cc @@ -30,16 +30,6 @@ DecIP6HLIM::~DecIP6HLIM() { } -void -DecIP6HLIM::drop_it(Packet *p) -{ - _drops++; - if (noutputs() == 2) - output(1).push(p); - else - p->kill(); -} - inline Packet * DecIP6HLIM::simple_action(Packet *p_in) { @@ -47,12 +37,21 @@ DecIP6HLIM::simple_action(Packet *p_in) const click_ip6 *ip_in = p_in->ip6_header(); if (ip_in->ip6_hlim <= 1) { - drop_it(p_in); + _drops++; + if (noutputs() == 2) { +#if HAVE_BATCH + if (in_batch_mode == BATCH_MODE_YES) + output(1).push_batch(PacketBatch::make_from_packet(p_in)); + else +#endif + output(1).push(p_in); + } else + p_in->kill(); return 0; } else { - WritablePacket *p = p_in->uniqueify(); - click_ip6 *ip = p->ip6_header(); - ip->ip6_hlim--; + WritablePacket *p = p_in->uniqueify(); + click_ip6 *ip = p->ip6_header(); + ip->ip6_hlim--; return p; } } diff --git a/elements/ip6/ip6drop.cc b/elements/ip6/ip6drop.cc new file mode 100644 index 0000000000..9975c0221e --- /dev/null +++ b/elements/ip6/ip6drop.cc @@ -0,0 +1,204 @@ +/* + * ip6drop.{cc,hh} -- element drops packets following a Gilbert Eliott model + * Louis Navarre + * + * Copyright (c) 2024 UCLouvain + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, subject to the conditions + * listed in the Click LICENSE file. These conditions include: you must + * preserve this copyright notice, and you cannot mention the copyright + * holders in advertising related to the Software without their permission. + * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This + * notice is a summary of the Click LICENSE file; the license in that file is + * legally binding. + */ + +#include +#include "ip6drop.hh" +#include +#include +#include +#include + +CLICK_DECLS + +IP6Drop::IP6Drop() +{ + +} + +IP6Drop::~IP6Drop() +{ + Stats &s = *_stats; + click_chatter("Total number of dropped packets: %u\n", s.total_drop); +} + +int +IP6Drop::configure(Vector &conf, ErrorHandler *errh) +{ + if (Args(conf, this, errh) + .read_all("ADDR", addrs) + .read_or_set("P", p, 0) + .read_or_set("R", r, 0) + .read_or_set("H", h, 0) + .read_or_set("K", k, 1) + .read_or_set("UNIFORM", is_uniform, false) + .read_or_set("UDROPRATE", uniform_drop, 0.03) + .read_or_set("DETERMINISTIC", is_deterministic, false) + .read_or_set("SEED", seed, 51) + .complete() < 0) + return -1; + + + srand(seed); + + if (is_deterministic) + { + click_chatter("Uses determistic losses with %f burst losses", uniform_drop); + if (uniform_drop > 0 && uniform_drop < 0.01) + return errh->error("Determenistic drop is limited to a decimal % precision"); + } + else + { + if (is_uniform) { + click_chatter("Uses uniformis_uniform drop with %f", uniform_drop); + } else { + click_chatter("Uses GE model with k=%.4f h=%.4f r=%.4f p=%.4f", k, h, r, p); + } + } + + return 0; +} + +void +IP6Drop::push(int input, Packet *p_in) +{ + Packet* p = drop_model(p_in); + if (p) + output(0).push(p); +} + +#if HAVE_BATCH +void +IP6Drop::push_batch(int input, PacketBatch *batch) { + EXECUTE_FOR_EACH_PACKET_DROPPABLE(drop_model, batch, [](Packet *){}); + if (batch) { + output_push_batch(0, batch); + } +} +#endif + +Packet * +IP6Drop::drop_model(Packet *p_in) +{ + Stats &s = *_stats; + + s.total_received++; + s.total_seen++; + if ((is_deterministic && deterministic_drop()) || (!is_deterministic && ((is_uniform && !uniform_model()) || (!is_uniform && !gemodel())))) { + // const click_ip6_sr *srv6 = reinterpret_cast(p_in->data() + 14 + sizeof(click_ip6)); + // if (srv6->ip6_hdrlen == 7) + // { + // ++s.total_drop_source; + // } + p_in->kill(); + s.total_drop++; + //click_chatter("Drop packet #%u", total_seen-1); + return 0; + } + return p_in; +} + +bool +IP6Drop::gemodel() +{ + _lock.acquire(); + auto &s = _protected; + bool keep_packet = true; + bool change_state = false; + // click_chatter("State is %u", state); + if (s.state == good) { + double rand_val1 = rand() / (RAND_MAX + 1.); + // click_chatter("Generated value: %f", rand_val1); + keep_packet = rand_val1 < k; + rand_val1 = rand() / (RAND_MAX + 1.); + change_state = rand_val1 < p; + // click_chatter("K and keep packet: %f, %u change state=%u (p=%u)", k * 100, keep_packet, change_state, p * 100); + if (change_state) { + s.state = bad; + } + } else { + double rand_val1 = rand() / (RAND_MAX + 1.); + keep_packet = rand_val1 < h; + rand_val1 = rand() / (RAND_MAX + 1.); + change_state = rand_val1 < r; + // change_state = nb_burst >= 4; + if (change_state) { + s.state = good; + } else { + } + } + _lock.release(); + return keep_packet; +} + +bool +IP6Drop::deterministic_drop() +{ + _lock.acquire(); + auto &p = _protected; + p.de_count++; + if ( p.de_count % 100 < uniform_drop * 100) + { + _lock.release(); + return true; + } + _lock.release(); + return false; +} + +bool +IP6Drop::uniform_model() +{ + double randval = rand() / (RAND_MAX + 1.); + return randval > uniform_drop; +} + +bool +IP6Drop::addr_eq(uint32_t *a1, uint32_t *a2) +{ + return (a1[0] == a2[0] && a1[1] == a2[1] && a1[2] == a2[2] && a1[3] == a2[3]); +} + +String +IP6Drop::read_handler(Element *e, void *thunk) +{ + IP6Drop *d = (IP6Drop *)e; + switch((uintptr_t)thunk) { + case 0: { + PER_THREAD_MEMBER_SUM(uint64_t,total_drop,d->_stats,total_drop); + return String(total_drop); } + case 1: { + PER_THREAD_MEMBER_SUM(uint64_t,total_received,d->_stats,total_received); + return String(total_received); } + case 2: { + PER_THREAD_MEMBER_SUM(uint64_t,total_drop_source,d->_stats,total_drop_source); + return String(total_drop_source); } + } + + return ""; +} + +void +IP6Drop::add_handlers() +{ + add_read_handler("drops", read_handler, 0); + add_read_handler("count", read_handler, 1); + add_read_handler("drop_source", read_handler, 2); +} + +CLICK_ENDDECLS +EXPORT_ELEMENT(IP6Drop) +ELEMENT_MT_SAFE(IP6Drop) diff --git a/elements/ip6/ip6drop.hh b/elements/ip6/ip6drop.hh new file mode 100644 index 0000000000..6563f5d045 --- /dev/null +++ b/elements/ip6/ip6drop.hh @@ -0,0 +1,105 @@ +#ifndef CLICK_IP6_DROP_HH +#define CLICK_IP6_DROP_HH +#include +#include +#include +#include +#include +#include + +CLICK_DECLS + +/* +=c + +IP6Drop(ADDR[, ADDR, ...], P, R, K, H) + +=s ip + +Gilbert-Elliott drop model + +=d + +=e + + + IP6SRv6FECDecode(fc00::a, fc00::9) + +=a IP6Encap */ + + +class IP6Drop : public BatchElement { + + public: + + IP6Drop(); + ~IP6Drop(); + + const char *class_name() const override { return "IP6Drop"; } + const char *port_count() const override { return PORTS_1_1; } + + int configure(Vector &, ErrorHandler *) CLICK_COLD; + bool can_live_reconfigure() const { return true; } + void add_handlers() CLICK_COLD; + static String read_handler(Element *e, void *thunk) CLICK_COLD; + + void push(int, Packet *p_in) override; +#if HAVE_BATCH + void push_batch(int, PacketBatch * batch_in) override; +#endif + Packet *drop_model(Packet *p_in); + + bool gemodel(); + bool uniform_model(); + bool addr_eq(uint32_t *a1, uint32_t *a2); + bool deterministic_drop(); + +private: + + Vector addrs; + + enum state_e { + good, + bad + }; + + struct Stats { + Stats() : total_seen(0), total_drop(0), total_drop_source(0), total_received(0) { + + } + + uint64_t total_seen; // Number of analyzed packets + uint64_t total_drop; + uint64_t total_drop_source; + uint64_t total_received; + }; + + struct Shared { + Shared() : state(good) { + + } + uint64_t de_count; + state_e state; // State of the machine + }; + SimpleSpinlock _lock; + per_thread _stats; + Shared _protected; + + + double p; // Good -> bad + double r; // Bad -> good + double h; // Don't drop in bad + double k; // Don't drop in good + + uint16_t seed; + bool is_uniform; + double uniform_drop; + bool is_in_good; + uint32_t nb_burst; + bool is_deterministic; +}; + +CLICK_ENDDECLS +#endif + + diff --git a/elements/ip6/ip6mirror.hh b/elements/ip6/ip6mirror.hh index 9ef681a438..b5bf48281a 100644 --- a/elements/ip6/ip6mirror.hh +++ b/elements/ip6/ip6mirror.hh @@ -1,6 +1,6 @@ #ifndef CLICK_IP6MIRROR_HH #define CLICK_IP6MIRROR_HH -#include +#include CLICK_DECLS /* @@ -24,7 +24,7 @@ swap operations do not affect checksums. */ -class IP6Mirror : public Element { +class IP6Mirror : public SimpleElement { public: diff --git a/elements/ip6/ip6srdecap.cc b/elements/ip6/ip6srdecap.cc new file mode 100644 index 0000000000..ab0ffd0db7 --- /dev/null +++ b/elements/ip6/ip6srdecap.cc @@ -0,0 +1,130 @@ +/* + * ip6srdecap.{cc,hh} -- element encapsulates packet in IP6 SRv6 header + * Tom Barbette, Louis Navarre + * + * Copyright (c) 2024 UCLouvain + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, subject to the conditions + * listed in the Click LICENSE file. These conditions include: you must + * preserve this copyright notice, and you cannot mention the copyright + * holders in advertising related to the Software without their permission. + * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This + * notice is a summary of the Click LICENSE file; the license in that file is + * legally binding. + */ + +#include +#include "ip6srdecap.hh" +#include +#include +#include +#include +CLICK_DECLS + +IP6SRDecap::IP6SRDecap() : _force(false) +{ + +} + +IP6SRDecap::~IP6SRDecap() +{ +} + +int +IP6SRDecap::configure(Vector &conf, ErrorHandler *errh) +{ + + if (Args(conf, this, errh) + .read("FORCE_DECAP", _force) + .complete() < 0) + return -1; + + return 0; +} + + +Packet * +IP6SRDecap::simple_action(Packet *p_in) +{ + + WritablePacket *p = p_in->uniqueify(); + if (!p) + return 0; + + click_ip6 *ip6 = reinterpret_cast(p->data()); + click_ip6_sr *sr = (click_ip6_sr*)ip6_find_header(ip6, IP6_EH_ROUTING, p->end_data()); + + if (sr == 0) { + return p; + } + + if (_force || sr->segment_left == 0) { + IP6Address last = IP6Address(sr->segments[0]); + + unsigned char* old_data = p->data(); + unsigned char nxt = sr->ip6_sr_next; + unsigned char *next_ptr = (unsigned char*)ip6_find_header(ip6, nxt, p->end_data()); + unsigned offset = p->transport_header_offset(); + if (next_ptr == 0) { + p->kill(); + click_chatter("Cannot find next header %d. Buggy packet?", nxt); + return 0; + } + unsigned srlen = (unsigned char*)next_ptr - (unsigned char*)sr; + + if (srlen > 64 && click_current_cpu_id() == 13) { + char buf[5000]; + char* b = buf; + for (int i = 0; i < p->length(); i++) { + if (i%4==0) + b += sprintf(b, " "); + if (i%16==0) + b += sprintf(b, "\n[%d]", click_current_cpu_id()); + b += sprintf(b, "%02x", p->data()[i] & 0xff); + } + *b = '\0'; + click_chatter("[%d] Culprit [%d]: %s / %p %p",click_current_cpu_id(), p->length(), buf, p->data(), ip6); + click_chatter("[%d] srlen %d, [nxt] %d, nxt %x", click_current_cpu_id(), srlen, nxt, ip6->ip6_nxt); + click_chatter("[%d] Sr length too big, sr at offset %d", click_current_cpu_id(), (char*)sr-(char*)ip6); + auto fnt = [p] (const uint8_t type, unsigned char* hdr) __attribute__((always_inline)) { + click_chatter("[%d] NXT %d at offset %d: %x",click_current_cpu_id(), type, hdr - p->data(), *hdr); + return true; + }; + ip6_follow_eh(ip6, (unsigned char*)p->end_data(), fnt); + + b = buf; + for (int i =0; i < p->length(); i++) { + b += sprintf(b, "%02x", p->data()[i] & 0xff); + } + *b = '\0'; + click_chatter("[%d] Culprit [%d]: %s",click_current_cpu_id(),p->length(), buf); + assert(false); + } + + p->pull(srlen); + + memmove(p->data(), old_data, (unsigned char*)sr-old_data); + ip6 = (click_ip6 *)(p->data()); + + ip6->ip6_dst = last; + ip6->ip6_nxt = nxt; + ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - srlen); + // p->set_network_header(p->data(), offset - srlen); + p->set_network_header(p->data(), 40); + + + } else if (unlikely(sr->segment_left == 0)) { + click_chatter("Invalid packet with 0 segments left?"); + return p; + } else { + ip6->ip6_dst = sr->segments[--sr->segment_left]; + } + + return p; +} + +CLICK_ENDDECLS +EXPORT_ELEMENT(IP6SRDecap) +ELEMENT_MT_SAFE(IP6SRDecap) diff --git a/elements/ip6/ip6srdecap.hh b/elements/ip6/ip6srdecap.hh new file mode 100644 index 0000000000..5feb64f40e --- /dev/null +++ b/elements/ip6/ip6srdecap.hh @@ -0,0 +1,50 @@ +#ifndef CLICK_IP6SRDECAP_HH +#define CLICK_IP6SRDECAP_HH +#include +#include +#include +#include +#include + +CLICK_DECLS + +/* +=c + +IP6SRDecap(ADDR[, ADDR, ...]) + +=s ip + +adds a SR Header to the IP6 packet + +=d + +Takes a list of adresses + +=e + + + IP6SRDecap(2000:10:1::2, 2000:20:1::3, ...) + +=a IP6Encap */ + +class IP6SRDecap : public SimpleElement { public: + + IP6SRDecap(); + ~IP6SRDecap(); + + const char *class_name() const override { return "IP6SRDecap"; } + const char *port_count() const override { return PORTS_1_1; } + + int configure(Vector &, ErrorHandler *) CLICK_COLD; + bool can_live_reconfigure() const { return true; } + + Packet *simple_action(Packet *); + +private: + bool _force; + +}; + +CLICK_ENDDECLS +#endif diff --git a/elements/ip6/ip6srencap.cc b/elements/ip6/ip6srencap.cc new file mode 100644 index 0000000000..81af40aa55 --- /dev/null +++ b/elements/ip6/ip6srencap.cc @@ -0,0 +1,95 @@ +/* + * ip6srencap.{cc,hh} -- element encapsulates packet in IP6 SRv6 header + * Tom Barbette, Louis Navarre + * + * Copyright (c) 2024 UCLouvain + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, subject to the conditions + * listed in the Click LICENSE file. These conditions include: you must + * preserve this copyright notice, and you cannot mention the copyright + * holders in advertising related to the Software without their permission. + * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This + * notice is a summary of the Click LICENSE file; the license in that file is + * legally binding. + */ + +#include +#include "ip6srencap.hh" +#include +#include +#include +#include + +CLICK_DECLS + +IP6SREncap::IP6SREncap() : _do_encap_dst(true) +{ + +} + +IP6SREncap::~IP6SREncap() +{ +} + +int +IP6SREncap::configure(Vector &conf, ErrorHandler *errh) +{ + Vector addr; + + if (Args(conf, this, errh) + .read_all("ADDR", addr) + .read("ENCAP_DST", _do_encap_dst) + .complete() < 0) + return -1; + if (_do_encap_dst) { + addr.push_front(IP6Address()); + } + + static_assert(sizeof(click_ip6_sr) == 8); + + _sr_len = sizeof(click_ip6_sr) + addr.size() * sizeof(IP6Address); + _sr = (click_ip6_sr*)CLICK_LALLOC(_sr_len); + _sr->ip6_hdrlen = sizeof(IP6Address) * addr.size() / 8; + _sr->type = 4; + _sr->segment_left = addr.size() - 1; + _sr->last_entry = addr.size() - 1; + _sr->flags = 0; + _sr->tag = 0; + memcpy(_sr->segments, addr.data(), sizeof(IP6Address) * addr.size()); + + return 0; +} + + +Packet * +IP6SREncap::simple_action(Packet *p_in) +{ + + WritablePacket *p = p_in->push(_sr_len); + if (!p) + return 0; + + click_ip6 *ip6 = reinterpret_cast(p->data()); + click_ip6_sr *sr = reinterpret_cast(p->data() + sizeof(click_ip6)); + memcpy(ip6, p->data() + _sr_len, sizeof(click_ip6)); + memcpy(sr, _sr, _sr_len); + sr->ip6_sr_next = ip6->ip6_nxt; + ip6->ip6_nxt = IP6_EH_ROUTING; + + if (_do_encap_dst) { + sr->segments[0] = ip6->ip6_dst; + } + + ip6->ip6_dst = sr->segments[sr->segment_left]; + // Also update the IPv6 Header to add the SRH length in the payload + ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) + _sr_len); + p->set_network_header(p->data(), p->network_header_length() + _sr_len); + + return p; +} + +CLICK_ENDDECLS +EXPORT_ELEMENT(IP6SREncap) +ELEMENT_MT_SAFE(IP6SREncap) diff --git a/elements/ip6/ip6srencap.hh b/elements/ip6/ip6srencap.hh new file mode 100644 index 0000000000..359e2e666c --- /dev/null +++ b/elements/ip6/ip6srencap.hh @@ -0,0 +1,50 @@ +#ifndef CLICK_IP6SRENCAP_HH +#define CLICK_IP6SRENCAP_HH +#include +#include +#include +#include +#include + +CLICK_DECLS + +/* +=c + +IP6SREncap(ADDR[, ADDR, ...]) + +=s ip + +adds a SR Header to the IP6 packet + +=d + +Takes a list of adresses + +=e + + + IP6SREncap(2000:10:1::2, 2000:20:1::3, ...) + +=a IP6Encap */ + +class IP6SREncap : public SimpleElement { public: + + IP6SREncap(); + ~IP6SREncap(); + + const char *class_name() const override { return "IP6SREncap"; } + const char *port_count() const override { return PORTS_1_1; } + + int configure(Vector &, ErrorHandler *) CLICK_COLD; + bool can_live_reconfigure() const { return true; } + + Packet *simple_action(Packet *); + + int _sr_len; + click_ip6_sr* _sr; + bool _do_encap_dst; +}; + +CLICK_ENDDECLS +#endif diff --git a/elements/ip6/ip6srprocess.cc b/elements/ip6/ip6srprocess.cc new file mode 100644 index 0000000000..6cb2fe4f14 --- /dev/null +++ b/elements/ip6/ip6srprocess.cc @@ -0,0 +1,67 @@ +/* + * IP6SRProcess.{cc,hh} -- element encapsulates packet in IP6 SRv6 header + * Tom Barbette, Louis Navarre + * + * Copyright (c) 2024 UCLouvain + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, subject to the conditions + * listed in the Click LICENSE file. These conditions include: you must + * preserve this copyright notice, and you cannot mention the copyright + * holders in advertising related to the Software without their permission. + * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This + * notice is a summary of the Click LICENSE file; the license in that file is + * legally binding. + */ + +#include +#include "ip6srprocess.hh" +#include +#include +#include +#include + +CLICK_DECLS + +IP6SRProcess::IP6SRProcess() +{ + +} + +IP6SRProcess::~IP6SRProcess() +{ +} + +int +IP6SRProcess::configure(Vector &conf, ErrorHandler *errh) +{ + return 0; +} + + +Packet * +IP6SRProcess::simple_action(Packet *p_in) +{ + + WritablePacket *p = (WritablePacket *)p_in; + + click_ip6 *ip6 = reinterpret_cast(p->data()); + click_ip6_sr *sr = reinterpret_cast(p->data() + sizeof(click_ip6)); + + // Update segment left of the SRH + --sr->segment_left; + + // Update IPv6 address according to the Segment Routing Header + ip6->ip6_dst = sr->segments[sr->segment_left]; + + // TODO: recompute the checksum with the new pseudo-header (the destination address has changed) + + // TODO: if segment left is 0, pass it to the upper layer or drop it (do it in the .click files) + + return p; +} + +CLICK_ENDDECLS +EXPORT_ELEMENT(IP6SRProcess) +ELEMENT_MT_SAFE(IP6SRProcess) diff --git a/elements/ip6/ip6srprocess.hh b/elements/ip6/ip6srprocess.hh new file mode 100644 index 0000000000..1960780caa --- /dev/null +++ b/elements/ip6/ip6srprocess.hh @@ -0,0 +1,47 @@ +#ifndef CLICK_IP6SRPROCESS_HH +#define CLICK_IP6SRPROCESS_HH +#include +#include +#include +#include +#include + +CLICK_DECLS + +/* +=c + +IP6SRProcess(ADDR[, ADDR, ...]) + +=s ip + +Processes the Segment Routing Header of the IPv6 packet. For now it simply set the IP address +to the next one in the list. + +=d + +Takes a list of adresses: SIDs triggering SRv6 functions. + +=e + + + IP6SRProcess(2000:10:1::2, 2000:20:1::3, ...) + +=a IP6SRProcess */ + +class IP6SRProcess : public SimpleElement { public: + + IP6SRProcess(); + ~IP6SRProcess(); + + const char *class_name() const override { return "IP6SRProcess"; } + const char *port_count() const override { return PORTS_1_1; } + + int configure(Vector &, ErrorHandler *) CLICK_COLD; + bool can_live_reconfigure() const { return true; } + + Packet *simple_action(Packet *); +}; + +CLICK_ENDDECLS +#endif diff --git a/elements/ip6/lookupip6route.cc b/elements/ip6/lookupip6route.cc index a42f07556e..94e9f42125 100644 --- a/elements/ip6/lookupip6route.cc +++ b/elements/ip6/lookupip6route.cc @@ -138,7 +138,7 @@ LookupIP6Route::classify(Packet *p) _last_addr = a; _last_gw = gw; _last_output = ifi; - if (gw != IP6Address("::0")) { + if (gw != IP6Address::make_zero()) { SET_DST_IP6_ANNO(p, IP6Address(gw)); } return ifi; diff --git a/elements/standard/addressinfo.cc b/elements/standard/addressinfo.cc index a577718ff8..abb5d03d58 100644 --- a/elements/standard/addressinfo.cc +++ b/elements/standard/addressinfo.cc @@ -46,7 +46,7 @@ # endif # if HAVE_NETPACKET_PACKET_H && !HAVE_LINUX_IF_PACKET_H # include -# else +# elif HAVE_LINUX_IF_PACKET_H # include # endif # include diff --git a/elements/standard/bandwidthmeter.cc b/elements/standard/bandwidthmeter.cc index 262a04db12..32b2f4b45e 100644 --- a/elements/standard/bandwidthmeter.cc +++ b/elements/standard/bandwidthmeter.cc @@ -42,7 +42,7 @@ BandwidthMeter::configure(Vector &conf, ErrorHandler *errh) if (conf.size() == 0) return errh->error("too few arguments to BandwidthMeter(bandwidth, ...)"); - Vector vals(conf.size(), 0); + Vector vals(conf.size(), 0); BandwidthArg ba; for (int i = 0; i < conf.size(); i++) if (!ba.parse(conf[i], vals[i])) @@ -63,8 +63,8 @@ BandwidthMeter::configure(Vector &conf, ErrorHandler *errh) _meter1 = vals[0]; _nmeters = 1; } else { - _meters = new uint64_t[vals.size()]; - memcpy(_meters, &vals[0], vals.size() * sizeof(uint64_t)); + _meters = new unsigned[vals.size()]; + memcpy(_meters, &vals[0], vals.size() * sizeof(int)); _nmeters = vals.size(); } @@ -83,7 +83,7 @@ BandwidthMeter::push(int, Packet *p) int n = (r >= _meter1); output(n).push(p); } else { - uint64_t *meters = _meters; + unsigned *meters = _meters; int nmeters = _nmeters; for (int i = 0; i < nmeters; i++) if (r < meters[i]) { diff --git a/elements/standard/bandwidthmeter.hh b/elements/standard/bandwidthmeter.hh index 2b3fabbf44..d2ac963fa7 100644 --- a/elements/standard/bandwidthmeter.hh +++ b/elements/standard/bandwidthmeter.hh @@ -39,8 +39,8 @@ class BandwidthMeter : public Element { protected: RateEWMA _rate; - uint64_t _meter1; - uint64_t *_meters; + unsigned _meter1; + unsigned *_meters; int _nmeters; static String meters_read_handler(Element *, void *) CLICK_COLD; diff --git a/elements/standard/bwratedunqueue.cc b/elements/standard/bwratedunqueue.cc index 32f6dd9dcf..86fedf094d 100644 --- a/elements/standard/bwratedunqueue.cc +++ b/elements/standard/bwratedunqueue.cc @@ -85,7 +85,7 @@ BandwidthRatedUnqueue::run_task(Task *) } } } else { - _timer.schedule_after(Timestamp::make_usec(_tb.time_until_contains(tb_bandwidth_thresh))); + _timer.schedule_after(Timestamp::make_jiffies(_tb.time_until_contains(tb_bandwidth_thresh))); _empty_runs++; return false; } diff --git a/elements/standard/checklength.cc b/elements/standard/checklength.cc index 06a5dd26d2..f0bc98df71 100644 --- a/elements/standard/checklength.cc +++ b/elements/standard/checklength.cc @@ -19,6 +19,8 @@ #include "checklength.hh" #include #include +#include + CLICK_DECLS CheckLength::CheckLength() @@ -54,6 +56,35 @@ CheckLength::pull(int) return p; } +#if HAVE_BATCH +void +CheckLength::push_batch(int, PacketBatch *batch) +{ + PacketList queue; + FOR_EACH_PACKET_SAFE(batch,p) { + if (p->length() + (_use_extra_length ? EXTRA_LENGTH_ANNO(p) : 0) > _max) + checked_output_push_batch(1, PacketBatch::make_from_packet(p)); + else + queue.append(p); + } + if (!queue.empty()) + output_push_batch(0, queue.finish()); +} + +PacketBatch * +CheckLength::pull_batch(int, unsigned max) { + PacketBatch *batch = input(0).pull_batch(max); + PacketList queue; + FOR_EACH_PACKET_SAFE(batch,p) { + if (p && (p->length() + (_use_extra_length ? EXTRA_LENGTH_ANNO(p) : 0)) > _max) { + checked_output_push_batch(1, PacketBatch::make_from_packet(p)); + } else + queue.append(p); + } + return queue.finish(); +} +#endif + void CheckLength::add_handlers() { diff --git a/elements/standard/checklength.hh b/elements/standard/checklength.hh index 7529f6b5f9..ac33e6d26f 100644 --- a/elements/standard/checklength.hh +++ b/elements/standard/checklength.hh @@ -1,6 +1,6 @@ #ifndef CLICK_CHECKLENGTH_HH #define CLICK_CHECKLENGTH_HH -#include +#include CLICK_DECLS /* @@ -19,7 +19,7 @@ no larger than LENGTH, it is sent to output 0; otherwise, it is sent to output 1 (or dropped if there is no output 1). */ -class CheckLength : public Element { public: +class CheckLength : public BatchElement { public: CheckLength() CLICK_COLD; @@ -31,6 +31,10 @@ class CheckLength : public Element { public: void push(int, Packet *); Packet *pull(int); +#if HAVE_BATCH + void push_batch(int, PacketBatch *); + PacketBatch *pull_batch(int, unsigned); +#endif void add_handlers() CLICK_COLD; diff --git a/elements/standard/counter.cc b/elements/standard/counter.cc index a7c40b9605..bc48dae803 100644 --- a/elements/standard/counter.cc +++ b/elements/standard/counter.cc @@ -68,7 +68,6 @@ CounterBase::configure(Vector &conf, ErrorHandler *errh) errh->warning("NO_RATE cannot be set when handlers are used. It will be ignored"); } - if (count_call) { IntArg ia; if (!ia.parse_saturating(cp_shift_spacevec(count_call), _count_trigger)) diff --git a/elements/standard/linkunqueue.cc b/elements/standard/linkunqueue.cc index 587307b56f..d553d4d50a 100644 --- a/elements/standard/linkunqueue.cc +++ b/elements/standard/linkunqueue.cc @@ -32,6 +32,9 @@ CLICK_DECLS LinkUnqueue::LinkUnqueue() : _qhead(0), _qtail(0), _task(this), _timer(&_task) { +#if HAVE_BATCH + in_batch_mode = BATCH_MODE_YES; +#endif } void * @@ -117,67 +120,79 @@ LinkUnqueue::run_task(Task *) // Read a new packet if there's room. Room is measured by the latency while (!_qtail || _qtail->timestamp_anno() <= now_delayed) { - // try to pull a packet - Packet *p = input(0).pull(); - if (!p) { - _back_to_back = false; - break; - } - - // set new timestamp to delayed timestamp - if (_qtail) { - _qtail->set_next(p); - delay_by_bandwidth(p, (_back_to_back ? _qtail->timestamp_anno() : now_delayed)); - } else { - _qhead = p; - delay_by_bandwidth(p, now_delayed); - } - - // hook up, and remember we were doing this back to back - _qtail = p; - p->set_next(0); - Storage::set_tail(Storage::tail() + 1); - worked = _back_to_back = true; + // try to pull a packet + Packet *p = input(0).pull(); + if (!p) { + _back_to_back = false; + break; + } + + // set new timestamp to delayed timestamp + if (_qtail) { + _qtail->set_next(p); + delay_by_bandwidth(p, (_back_to_back ? _qtail->timestamp_anno() : now_delayed)); + } else { + _qhead = p; + delay_by_bandwidth(p, now_delayed); + } + + // hook up, and remember we were doing this back to back + _qtail = p; + p->set_next(0); + Storage::set_tail(Storage::tail() + 1); + worked = _back_to_back = true; } // Emit packets if it's time +#if HAVE_BATCH + BATCH_CREATE_INIT(batch); +#endif while (_qhead && _qhead->timestamp_anno() <= now) { - Packet *p = _qhead; - _qhead = p->next(); - if (!_qhead) - _qtail = 0; - p->set_next(0); - //click_chatter("%p{timestamp}: RELEASE %p{timestamp}", &now, &p->timestamp_anno()); + Packet *p = _qhead; + _qhead = p->next(); + if (!_qhead) + _qtail = 0; + p->set_next(0); + //click_chatter("%p{timestamp}: RELEASE %p{timestamp}", &now, &p->timestamp_anno()); +#if HAVE_BATCH + BATCH_CREATE_APPEND(batch, p); +#else output(0).push(p); +#endif Storage::set_tail(Storage::tail() - 1); - worked = true; + worked = true; } +#if HAVE_BATCH + BATCH_CREATE_FINISH(batch); + if (batch) + output(0).push_batch(batch); +#endif // Figure out when to schedule next //print_queue(_qhead); if (_qhead) { - Timestamp expiry = _qhead->timestamp_anno(); - if (_signal) { - Timestamp expiry2 = _qtail->timestamp_anno() - _latency; - if (expiry2 < expiry) - expiry = expiry2; - } - //{ Timestamp diff = expiry - now; click_chatter("%p{timestamp}: %p{timestamp} > + %p{timestamp}", &now, &expiry, &diff); } - expiry -= Timer::adjustment(); - if (expiry <= now) { - // small delay, reschedule Task - //_state = S_TASK; - _task.fast_reschedule(); - } else { - // large delay, schedule Timer instead - //_state = S_TIMER; - _timer.schedule_at(expiry); - } + Timestamp expiry = _qhead->timestamp_anno(); + if (_signal) { + Timestamp expiry2 = _qtail->timestamp_anno() - _latency; + if (expiry2 < expiry) + expiry = expiry2; + } + //{ Timestamp diff = expiry - now; click_chatter("%p{timestamp}: %p{timestamp} > + %p{timestamp}", &now, &expiry, &diff); } + expiry -= Timer::adjustment(); + if (expiry <= now) { + // small delay, reschedule Task + //_state = S_TASK; + _task.fast_reschedule(); + } else { + // large delay, schedule Timer instead + //_state = S_TIMER; + _timer.schedule_at(expiry); + } } else if (_signal) { - //_state = S_TASK; - _task.fast_reschedule(); + //_state = S_TASK; + _task.fast_reschedule(); } else { - //_state = S_ASLEEP; + //_state = S_ASLEEP; } return worked; @@ -215,7 +230,7 @@ LinkUnqueue::write_handler(const String &s, Element *e, void *thunk, ErrorHandle break; } case H_BANDWIDTH: { - uint64_t bw; + uint32_t bw; if (!cp_bandwidth(s, &bw)) { return errh->error("invalid bandwidth"); } else if (bw < 100) { diff --git a/elements/standard/linkunqueue.hh b/elements/standard/linkunqueue.hh index ded66b6801..4849195ccb 100644 --- a/elements/standard/linkunqueue.hh +++ b/elements/standard/linkunqueue.hh @@ -1,7 +1,7 @@ // -*- c-basic-offset: 4 -*- #ifndef CLICK_LINKUNQUEUE_HH #define CLICK_LINKUNQUEUE_HH -#include +#include #include #include #include @@ -56,7 +56,7 @@ When written, drops all packets in, or partially in, the emulated link. =a DelayUnqueue, Queue, Unqueue, RatedUnqueue, BandwidthRatedUnqueue, DelayShaper, SetTimestamp */ -class LinkUnqueue : public Element, public Storage { public: +class LinkUnqueue : public BatchElement, public Storage { public: LinkUnqueue() CLICK_COLD; @@ -79,7 +79,7 @@ class LinkUnqueue : public Element, public Storage { public: Timestamp _latency; // enum { S_TASK, S_TIMER, S_ASLEEP } _state; bool _back_to_back; - uint64_t _bandwidth; + uint32_t _bandwidth; Task _task; Timer _timer; NotifierSignal _signal; diff --git a/elements/standard/meter.cc b/elements/standard/meter.cc index 81d0c65c63..8c117fca96 100644 --- a/elements/standard/meter.cc +++ b/elements/standard/meter.cc @@ -29,12 +29,12 @@ Meter::push(int, Packet *p) { _rate.update(1); // packets, not bytes - uint64_t r = _rate.scaled_average(); + unsigned r = _rate.scaled_average(); if (_nmeters < 2) { int n = (r >= _meter1); output(n).push(p); } else { - uint64_t *meters = _meters; + unsigned *meters = _meters; int nmeters = _nmeters; for (int i = 0; i < nmeters; i++) if (r < meters[i]) { diff --git a/elements/standard/print.cc b/elements/standard/print.cc index c72c0b6adf..5b6f86955d 100644 --- a/elements/standard/print.cc +++ b/elements/standard/print.cc @@ -39,7 +39,7 @@ int Print::configure(Vector &conf, ErrorHandler* errh) { bool timestamp = false; -#ifdef CLICK_LINUXMODULE +#if defined(CLICK_LINUXMODULE) || defined(CLICK_USERLEVEL) bool print_cpu = false; #endif bool print_anno = false, headroom = false, bcontents; @@ -57,7 +57,7 @@ Print::configure(Vector &conf, ErrorHandler* errh) .read("PRINTANNO", print_anno) .read("ACTIVE", _active) .read("HEADROOM", headroom) -#if CLICK_LINUXMODULE +#if defined(CLICK_LINUXMODULE) || defined(CLICK_USERLEVEL) .read("CPU", print_cpu) #endif .complete() < 0) @@ -79,7 +79,7 @@ Print::configure(Vector &conf, ErrorHandler* errh) _timestamp = timestamp; _headroom = headroom; _print_anno = print_anno; -#ifdef CLICK_LINUXMODULE +#if defined(CLICK_LINUXMODULE) || defined(CLICK_USERLEVEL) _cpu = print_cpu; #endif return 0; @@ -117,6 +117,12 @@ Print::rmaction(Packet* p) { click_put_processor(); sep = ": "; } +#elif CLICK_USERLEVEL + if (_cpu) { + click_processor_t my_cpu = click_current_cpu_id(); + sa << '(' << my_cpu << ')'; + sep = ": "; + } #endif if (_timestamp) { sa << sep << p->timestamp_anno(); diff --git a/elements/standard/print.hh b/elements/standard/print.hh index 9182aa37ca..c5742e4f3f 100644 --- a/elements/standard/print.hh +++ b/elements/standard/print.hh @@ -90,7 +90,7 @@ class Print : public BatchElement { public: bool _active; bool _timestamp : 1; bool _headroom : 1; -#ifdef CLICK_LINUXMODULE +#if defined(CLICK_LINUXMODULE) || defined(CLICK_USERLEVEL) bool _cpu : 1; #endif bool _print_anno; diff --git a/elements/standard/ratedsource.cc b/elements/standard/ratedsource.cc index fb32eb708e..e3e1e0d879 100644 --- a/elements/standard/ratedsource.cc +++ b/elements/standard/ratedsource.cc @@ -49,8 +49,8 @@ RatedSource::configure(Vector &conf, ErrorHandler *errh) String data = "Random bullshit in a packet, at least 64 bytes long. Well, now it is."; - uint64_t rate = 10; - uint64_t bandwidth = 0; + unsigned rate = 10; + unsigned bandwidth = 0; int limit = -1; int datasize = -1; bool active = true, stop = false; @@ -179,7 +179,7 @@ RatedSource::run_task(Task *) count++; } else { - _timer.schedule_after(Timestamp::make_usec(_tb.time_until_contains(_batch_size))); + _timer.schedule_after(Timestamp::make_jiffies(_tb.time_until_contains(_batch_size))); return false; } } @@ -194,7 +194,7 @@ RatedSource::run_task(Task *) } else { if (_end_h && _limit >= 0 && _count >= (ucounter_t) _limit) (void) _end_h->call_write(); - _timer.schedule_after(Timestamp::make_usec(_tb.time_until_contains(1))); + _timer.schedule_after(Timestamp::make_jiffies(_tb.time_until_contains(1))); return false; } @@ -209,7 +209,7 @@ RatedSource::run_task(Task *) } else { if (_end_h && _limit >= 0 && _count >= (ucounter_t) _limit) (void) _end_h->call_write(); - _timer.schedule_after(Timestamp::make_usec(_tb.time_until_contains(1))); + _timer.schedule_after(Timestamp::make_jiffies(_tb.time_until_contains(1))); return false; } diff --git a/elements/standard/ratedunqueue.cc b/elements/standard/ratedunqueue.cc index cbe95ae4fa..59b8556d35 100644 --- a/elements/standard/ratedunqueue.cc +++ b/elements/standard/ratedunqueue.cc @@ -48,9 +48,9 @@ RatedUnqueue::configure(Vector &conf, ErrorHandler *errh) int RatedUnqueue::configure_helper(TokenBucket *tb, bool is_bandwidth, Element *elt, Vector &conf, ErrorHandler *errh) { - uint64_t r; + unsigned r; unsigned dur_msec = 20; - uint64_t tokens; + unsigned tokens; bool dur_specified, tokens_specified; const char *burst_size = is_bandwidth ? "BURST_BYTES" : "BURST_SIZE"; @@ -133,7 +133,7 @@ RatedUnqueue::run_task(Task *) } #endif } else { - _timer.schedule_after(Timestamp::make_usec(_tb.time_until_contains(1))); + _timer.schedule_after(Timestamp::make_jiffies(_tb.time_until_contains(1))); _empty_runs++; return false; } diff --git a/elements/standard/ratedunqueue.hh b/elements/standard/ratedunqueue.hh index 3555e70c59..c824b62b3e 100644 --- a/elements/standard/ratedunqueue.hh +++ b/elements/standard/ratedunqueue.hh @@ -69,11 +69,11 @@ class RatedUnqueue : public BatchElement { public: Task _task; Timer _timer; NotifierSignal _signal; - uint64_t _runs; - uint64_t _packets; - uint64_t _pushes; - uint64_t _failed_pulls; - uint64_t _empty_runs; + uint32_t _runs; + uint32_t _packets; + uint32_t _pushes; + uint32_t _failed_pulls; + uint32_t _empty_runs; uint32_t _burst; enum { h_calls, h_rate }; diff --git a/elements/standard/shaper.cc b/elements/standard/shaper.cc index 74cae64fce..9a7ce81c5e 100644 --- a/elements/standard/shaper.cc +++ b/elements/standard/shaper.cc @@ -32,7 +32,7 @@ Shaper::Shaper() int Shaper::configure(Vector &conf, ErrorHandler *errh) { - uint64_t rate; + uint32_t rate; Args args(conf, this, errh); if (is_bandwidth()) args.read_mp("RATE", BandwidthArg(), rate); diff --git a/elements/test/biginttest.cc b/elements/test/biginttest.cc index 1d35a3e1ba..1c734c3b3c 100644 --- a/elements/test/biginttest.cc +++ b/elements/test/biginttest.cc @@ -34,12 +34,11 @@ BigintTest::BigintTest() } #define CHECK(x, a, b) if (!(x)) return errh->error("%s:%d: test `%s' failed [%llu, %u]", __FILE__, __LINE__, #x, a, b); -#define CHECKL(x, a, l, b) if (!(x)) return errh->error("%s:%d: test `%s' failed [%s, %llu]", __FILE__, __LINE__, #x, bigint::unparse_clear(a, l).c_str(), b); #define CHECK0(x) if (!(x)) return errh->error("%s:%d: test `%s' failed", __FILE__, __LINE__, #x); static bool test_multiply(uint32_t a, uint32_t b, ErrorHandler *errh) { uint32_t x[2]; - Bigint::multiply(x[1], x[0], a, b); + bigint::multiply(x[1], x[0], a, b); uint64_t c = (((uint64_t) x[1]) << 32) | x[0]; if (c != (uint64_t) a * b) { errh->error("%u * %u == %llu, not %llu", a, b, (uint64_t) a * b, c); @@ -54,7 +53,7 @@ static bool test_mul(uint64_t a, uint32_t b, ErrorHandler *errh) { ax[1] = a >> 32; uint32_t cx[2]; cx[0] = cx[1] = 0; - Bigint::multiply_add(cx, ax, 2, b); + bigint::multiply_add(cx, ax, 2, b); uint64_t c = (((uint64_t) cx[1]) << 32) | cx[0]; if (c != a * b) { errh->error("%llu * %u == %llu, not %llu", a, b, a * b, c); @@ -64,11 +63,10 @@ static bool test_mul(uint64_t a, uint32_t b, ErrorHandler *errh) { } static bool test_div(uint64_t a, uint32_t b, ErrorHandler *errh) { - assert(b); uint32_t ax[4]; ax[0] = a; ax[1] = a >> 32; - uint32_t r = Bigint::divide(ax+2, ax, 2, b); + uint32_t r = bigint::divide(ax+2, ax, 2, b); uint64_t c = ((uint64_t) ax[3] << 32) | ax[2]; if (c != a / b) { errh->error("%llu / %u == %llu, not %llu", a, b, a * b, c); @@ -83,7 +81,7 @@ static bool test_div(uint64_t a, uint32_t b, ErrorHandler *errh) { static bool test_inverse(uint32_t a, ErrorHandler *errh) { assert(a & (1 << 31)); - uint32_t a_inverse = Bigint::inverse(a); + uint32_t a_inverse = bigint::inverse(a); // "Inverse is floor((b * (b - a) - 1) / a), where b = 2^32." uint64_t b = (uint64_t) 1 << 32; uint64_t want_inverse = (b * (b - a) - 1) / a; @@ -101,7 +99,7 @@ static bool test_add(uint64_t a, uint64_t b, ErrorHandler *errh) { ax[3] = a >> 32; ax[4] = b; ax[5] = b >> 32; - Bigint::add(ax[1], ax[0], ax[3], ax[2], ax[5], ax[4]); + bigint::add(ax[1], ax[0], ax[3], ax[2], ax[5], ax[4]); uint64_t c = ((uint64_t) ax[1] << 32) | ax[0]; if (c != a + b) { errh->error("%llu + %llu == %llu, not %llu", a, b, a + b, c); @@ -110,194 +108,45 @@ static bool test_add(uint64_t a, uint64_t b, ErrorHandler *errh) { return true; } -static bool test_multiply64(uint64_t a, uint64_t b, ErrorHandler *errh) { - uint64_t x[2], y[2]; - bigint::multiply(x[1], x[0], a, b); -#ifdef __x86_64__ - int_multiply(a, b, y[0], y[1]); -#else - y[1] = (a >> 32) * (b >> 32); - y[0] = (a & ((1UL << 32) - 1)) * (uint32_t) b; - uint64_t tmp = (a >> 32) * (uint32_t) b; - bool carry = (tmp << 32) > -y[0]; - y[0] += (tmp << 32); - y[1] += (tmp >> 32) + carry; - tmp = (uint32_t) a * (b >> 32); - carry = (tmp << 32) > -y[0]; - y[0] += (tmp << 32); - y[1] += (tmp >> 32) + carry; -#endif - if (memcmp(x, y, sizeof(x))) { - errh->error("%u * %u == %s, not %s", a, b, bigint::unparse_clear(y, 2).c_str(), - bigint::unparse_clear(x, 2).c_str()); - return false; - } - return true; -} - -static bool test_mul64(uint64_t a[2], uint64_t b, ErrorHandler *errh) { - uint64_t c[2] = {0, 0}, d[2], e[2]; - bigint::multiply_add(c, a, 2, b); - bigint::multiply(d[1], d[0], a[0], b); - bigint::multiply(e[1], e[0], a[1], b); - d[1] += e[0]; - if (memcmp(c, d, sizeof(c))) { - uint64_t tmp[2] = {a[0], a[1]}; - errh->error("%s * %llu == %s, not %s", bigint::unparse_clear(tmp, 2).c_str(), b, - bigint::unparse_clear(d, 2).c_str(), bigint::unparse_clear(c, 2).c_str()); - return false; - } - return true; -} - -static bool test_div64(uint64_t a[2], uint64_t b, ErrorHandler *errh) { - assert(b); - uint64_t c[2], q[2] = {0, 0}, rem; - uint64_t r = bigint::divide(c, a, 2, b); - // Upper 64 bits of the quotient - q[1] = a[1] / b; - rem = a[1] % b; - // Lower 64 bits of the quotient -#ifdef __x86_64__ - __asm__("divq %4" : "=d"(rem), "=a"(q[0]) : "d"(rem), "a"(a[0]), "rm"(b)); -#else - if (rem) { - unsigned ashift = 0; - unsigned bshift = ffs_msb(b) - 1; - b <<= bshift; - // While remainder >= 2^64, - // subtract the divisor from the top bits of the remainder and accumulate quotient - while (ashift < 64) { - int s = ffs_msb(rem) - 1; - if (s) { - if (!rem || (unsigned) s >= 64 - ashift) - s = 64 - ashift; - q[0] <<= s; - rem = (rem << s) + ((a[0] << ashift) >> (64 - s)); - ashift += s; - if (ashift == 64) - break; - } - if (rem < b) { - q[0] <<= 1; - ashift++; - rem = (rem << 1) + (bool) (a[0] & (1ULL << (64 - ashift))); - } - rem -= b; - q[0]++; - } - q[0] <<= bshift; - b >>= bshift; - } else { - rem = a[0]; - } - // Remainder is now < 2^64, compute result directly - q[0] += rem / b; - rem = rem % b; -#endif - if (memcmp(c, q, sizeof(c))) { - uint64_t tmp[2] = {a[0], a[1]}; - errh->error("%s / %llu == %s, not %s", bigint::unparse_clear(tmp, 2).c_str(), b, - bigint::unparse_clear(q, 2).c_str(), bigint::unparse_clear(c, 2).c_str()); - return false; - } - if (r != rem) { - errh->error("%s %% %llu == %llu, not %llu", bigint::unparse_clear(a, 2).c_str(), b, rem, r); - return false; - } - return true; -} - -static bool test_inverse64(uint64_t a, ErrorHandler *errh) { - assert(a & (1ULL << 63)); - uint64_t a_inverse = bigint::inverse(a); - // "Inverse is floor((b * (b - a) - 1) / a), where b = 2^64." - uint64_t want_inverse[2] = {(uint64_t) -1, (uint64_t) -1}; // initialized to -1 - uint64_t c[2] = {0, -a}; // initialized to 2^64 * (2^64 - a) - bigint::add(want_inverse[1], want_inverse[0], want_inverse[1], want_inverse[0], c[1], c[0]); - bigint::divide(want_inverse, want_inverse, 2, a); - assert(want_inverse[1] == 0); - if (a_inverse != want_inverse[0]) { - errh->error("inverse(%llu) == %llu, not %llu", a, want_inverse[0], a_inverse); - return false; - } - return true; -} - -static bool test_add64(uint64_t a[2], uint64_t b[2], ErrorHandler *errh) { - uint64_t res[2]; - bigint::add(res[1], res[0], a[1], a[0], b[1], b[0]); - - uint64_t c[2] = {a[0] + b[0], a[1] + b[1]}; - if (a[0] > -b[0]) - c[1]++; - if (memcmp(res, c, sizeof(res))) { - uint64_t tmp[4] = {a[0], a[1], b[0], b[1]}; - errh->error("%s + %s == %s, not %s", bigint::unparse_clear(tmp, 2).c_str(), - bigint::unparse_clear(&tmp[2], 2).c_str(), bigint::unparse_clear(c, 2).c_str(), - bigint::unparse_clear(res, 2).c_str()); - return false; - } - return true; -} - int BigintTest::initialize(ErrorHandler *errh) { for (int i = 0; i < 3000; i++) { - uint64_t a[2], b; - a[0] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - a[1] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - b = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - CHECK(test_multiply(a[0], b, errh), a[0] & UINT32_MAX, (uint32_t) b); - CHECKL(test_multiply64(a[0], b, errh), a, 1, b); - CHECK(test_mul(a[0], b, errh), a[0], (uint32_t) b); - CHECKL(test_mul64(a, b, errh), a, 2, b); + uint32_t a = click_random() | (click_random() << 31); + uint32_t b = click_random() | (click_random() << 31); + CHECK(test_multiply(a, b, errh), a, b); + CHECK(test_mul(a, b, errh), a, b); } for (int i = 0; i < 8000; i++) { - uint64_t a = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - CHECK0(test_inverse(a | (1UL << 31), errh)); - CHECK0(test_inverse64(a | (1ULL << 63), errh)); + uint32_t a = click_random(); + CHECK0(test_inverse(a | 0x80000000, errh)); } CHECK0(test_inverse(0x80000000, errh)); for (int i = 0; i < 8000; i++) { - uint64_t a[2], b[2]; - a[0] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - a[1] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - b[0] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - b[1] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - CHECK0(test_add(a[0], b[0], errh)); - CHECK0(test_add64(a, b, errh)); + uint64_t a = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + uint64_t b = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + CHECK0(test_add(a, b, errh)); } CHECK0(test_div(12884758640815563913ULL, 2506284098U, errh)); for (int i = 0; i < 3000; i++) { - uint64_t a[2], b; - a[0] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - a[1] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - b = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - CHECK(test_div(a[0], b | (1UL << 31), errh), a[0], (uint32_t) b | (1UL << 31)); - CHECKL(test_div64(a, b | (1ULL << 63), errh), a, 2, b | (1ULL << 63)); + uint64_t a = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + uint32_t b = click_random(); + CHECK(test_div(a, b | 0x80000000, errh), a, b | 0x80000000); } for (int i = 0; i < 3000; i++) { - uint64_t a[2], b; - a[0] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - a[1] = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - do - b = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); - while (!b); - CHECK(test_div(a[0], b & ~(1UL << 31), errh), a[0], (uint32_t) b & ~(1UL << 31)); - CHECKL(test_div64(a, b & ~(1ULL << 63), errh), a, 2, b & ~(1ULL << 63)); - CHECK(test_div(a[0], b | (1UL << 31), errh), a[0], (uint32_t) b | (1UL << 31)); - CHECKL(test_div64(a, b | (1ULL << 63), errh), a, 2, b | (1ULL << 63)); + uint64_t a = click_random() | ((uint64_t) click_random() << 31) | ((uint64_t) click_random() << 62); + uint32_t b = click_random(); + CHECK(test_div(a, b & ~0x80000000, errh), a, b & ~0x80000000); + CHECK(test_div(a, b | 0x80000000, errh), a, b | 0x80000000); } uint32_t x[3] = { 3481, 592182, 3024921038U }; - CHECK0(Bigint::unparse_clear(x, 3) == "55799944231168388787108580761"); + CHECK0(bigint::unparse_clear(x, 3) == "55799944231168388787108580761"); x[0] = 10; x[1] = 0; - CHECK0(Bigint::multiply(x, x, 2, 10) == 0 && x[0] == 100 && x[1] == 0); - CHECK0(Bigint::multiply(x, x, 2, 4191384139U) == 0 && x[0] == 0x9698A54CU && x[1] == 0x61U); + CHECK0(bigint::multiply(x, x, 2, 10) == 0 && x[0] == 100 && x[1] == 0); + CHECK0(bigint::multiply(x, x, 2, 4191384139U) == 0 && x[0] == 0x9698A54CU && x[1] == 0x61U); { int32_t quot, rem; diff --git a/elements/test/confparsetest.cc b/elements/test/confparsetest.cc index 58749204fe..cdd2384782 100644 --- a/elements/test/confparsetest.cc +++ b/elements/test/confparsetest.cc @@ -236,10 +236,10 @@ ConfParseTest::initialize(ErrorHandler *errh) #endif BandwidthArg bwarg; - CHECK(bwarg.parse("8", u64) == true && bwarg.status == NumArg::status_unitless && u64 == 8); - CHECK(bwarg.parse("8 baud", u64) == true && bwarg.status == NumArg::status_ok && u64 == 1); - CHECK(bwarg.parse("8Kbps", u64) == true && bwarg.status == NumArg::status_ok && u64 == 1000); - CHECK(bwarg.parse("8KBps", u64) == true && bwarg.status == NumArg::status_ok && u64 == 8000); + CHECK(bwarg.parse("8", u32) == true && bwarg.status == NumArg::status_unitless && u32 == 8); + CHECK(bwarg.parse("8 baud", u32) == true && bwarg.status == NumArg::status_ok && u32 == 1); + CHECK(bwarg.parse("8Kbps", u32) == true && bwarg.status == NumArg::status_ok && u32 == 1000); + CHECK(bwarg.parse("8KBps", u32) == true && bwarg.status == NumArg::status_ok && u32 == 8000); { IPAddress a, m; diff --git a/elements/test/packettest.cc b/elements/test/packettest.cc index abd989a920..20cefde6b4 100644 --- a/elements/test/packettest.cc +++ b/elements/test/packettest.cc @@ -175,6 +175,31 @@ PacketTest::initialize(ErrorHandler *errh) CHECK_ALIGNED(p->data()); p->kill(); + PacketBatch* batch = PacketBatch::make_from_packet(Packet::make(1, lowers, 60, 2)); + for (int i = 2; i <= 100; i++) + batch->append_packet(Packet::make(i, lowers, 60, 2)); + int i = 0; + auto fnt = [](Packet *p_in, std::functionadd){ + int r = click_random() % 3; + if (r == 0) { + add(p_in->clone()->uniqueify()); + p_in->kill(); + } else if (r == 1) { + Packet* c = p_in->clone(); + add(p_in->uniqueify()); + c->kill(); + } else { + add(p_in); + } + }; + EXECUTE_FOR_EACH_PACKET_ADD(fnt, batch); + CHECK(batch->count() == 100); + CHECK(batch->first()->find_count() == 100); + i = 1; + FOR_EACH_PACKET(batch,p) { + CHECK(p->headroom() == i++); + } + // Also check some packet header definition properties. union { click_ip ip4; diff --git a/elements/test/tokenbuckettest.cc b/elements/test/tokenbuckettest.cc index 0bd516ac55..58c5f5faab 100644 --- a/elements/test/tokenbuckettest.cc +++ b/elements/test/tokenbuckettest.cc @@ -30,7 +30,7 @@ TokenBucketTest::TokenBucketTest() int TokenBucketTest::initialize(ErrorHandler *errh) { - TokenBucketX > tb; + TokenBucket tb; tb.assign(1024, 2048); CHECK(tb.rate() >= 1022 && tb.rate() <= 1026); CHECK(tb.capacity() >= 2046 && tb.capacity() <= 2050); diff --git a/elements/tunnel/gtpdecap.hh b/elements/tunnel/gtpdecap.hh index 9d00626916..9520872777 100644 --- a/elements/tunnel/gtpdecap.hh +++ b/elements/tunnel/gtpdecap.hh @@ -12,7 +12,7 @@ GTPDecap() decapsulates GTP packet -=s gtp +=s tunnel =d diff --git a/elements/tunnel/gtpencap.hh b/elements/tunnel/gtpencap.hh index 100619da5b..5b61a655de 100644 --- a/elements/tunnel/gtpencap.hh +++ b/elements/tunnel/gtpencap.hh @@ -12,7 +12,7 @@ GTPEncap(TEID eid) encapsulates GTP packets -=s gtp +=s tunnel =d diff --git a/elements/tunnel/gtplookup.hh b/elements/tunnel/gtplookup.hh index 5dde4995ae..644eba0b11 100644 --- a/elements/tunnel/gtplookup.hh +++ b/elements/tunnel/gtplookup.hh @@ -11,7 +11,7 @@ CLICK_DECLS GTPLookup() -=s gtp +=s tunnel Encapsulates packets in their intended GTP return id. diff --git a/elements/tunnel/gtptable.hh b/elements/tunnel/gtptable.hh index eed88add19..3778d0bcc7 100644 --- a/elements/tunnel/gtptable.hh +++ b/elements/tunnel/gtptable.hh @@ -57,7 +57,7 @@ GTPTable() Find mapping of the GTP tunnel id return side -=s gtp +=s tunnel =d diff --git a/elements/userlevel/counterfile.cc b/elements/userlevel/counterfile.cc index ab5ad037cb..044b7574f8 100644 --- a/elements/userlevel/counterfile.cc +++ b/elements/userlevel/counterfile.cc @@ -63,7 +63,11 @@ CounterFile::initialize(ErrorHandler *errh) return -errno; } - void *mmap_data = mmap(0, sizeof(stats_atomic), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd, 0); + unsigned long flags = MAP_SHARED; +#ifdef MAP_POPULATE + flags |= MAP_POPULATE; +#endif + void *mmap_data = mmap(0, sizeof(stats_atomic), PROT_READ | PROT_WRITE, flags, fd, 0); if (mmap_data == MAP_FAILED) { int e = -errno; diff --git a/elements/userlevel/fromdevice.cc b/elements/userlevel/fromdevice.cc index b5d2c99fc9..ca56d4fa8a 100644 --- a/elements/userlevel/fromdevice.cc +++ b/elements/userlevel/fromdevice.cc @@ -44,14 +44,21 @@ #include #include #include -#define _LINUX_IF_ETHER_H 1 +#ifndef _LINUX_IF_ETHER_H +# define _LINUX_IF_ETHER_H 1 +#endif +#ifdef HAVE_LINUX_ETHTOOL_H #include +#endif +#if HAVE_LINUX_NETLINK_H #include +#endif #include -#include #include #include "fakepcap.hh" +#if HAVE_LINUX_SOCKIOS_H #include +#endif #if FROMDEVICE_ALLOW_LINUX # include @@ -83,6 +90,7 @@ CLICK_DECLS #define offset_of_base(base,derived,derived_member) ((unsigned char*)(&(reinterpret_cast(0)->derived_member)) - (unsigned char*)(base *)0) +#if HAVE_LINUX_ETHTOOL_H static int dev_eth_set_rss_reta(EthernetDevice* eth, unsigned* reta, unsigned reta_sz) { FromDevice* fd = (FromDevice*)((unsigned char*)eth - offset_of_base(FromDevice,EthernetDevice,get_rss_reta_size)); return fd->dev_set_rss_reta(reta, reta_sz); @@ -92,6 +100,7 @@ static int dev_eth_get_rss_reta_size(EthernetDevice* eth) { FromDevice* fd = (FromDevice*)((unsigned char*)eth - offset_of_base(FromDevice,EthernetDevice,get_rss_reta_size)); return fd->dev_get_rss_reta_size(); } +#endif FromDevice::FromDevice() : @@ -109,8 +118,10 @@ FromDevice::FromDevice() #if HAVE_BATCH in_batch_mode = BATCH_MODE_YES; #endif +#if HAVE_LINUX_ETHTOOL_H set_rss_reta = &dev_eth_set_rss_reta; get_rss_reta_size = &dev_eth_get_rss_reta_size; +#endif } FromDevice::~FromDevice() @@ -463,7 +474,7 @@ FromDevice::initialize(ErrorHandler *errh) if (!_sniffer) if (KernelFilter::device_filter(_ifname, true, errh) < 0 #if HAVE_IP6 - && KernelFilter::device_filter6(_ifname, true, errh) < 0 + || KernelFilter::device_filter6(_ifname, true, errh) < 0 #endif ) { _sniffer = true; @@ -602,7 +613,9 @@ FromDevice::selected(int, int) } else p->take(_snaplen - len); p->set_packet_type_anno((Packet::PacketType)sa.sll_pkttype); +#ifdef SIOCGSTAMP p->timestamp_anno().set_timeval_ioctl(_fd, SIOCGSTAMP); +#endif p->set_mac_header(p->data()); ++nlinux; ++_count; @@ -699,8 +712,10 @@ FromDevice::read_handler(Element* e, void *thunk) { FromDevice* fd = static_cast(e); switch ((intptr_t)thunk) { +#if HAVE_LINUX_ETHTOOL_H case h_rss_reta_size: return String(fd->dev_get_rss_reta_size()); +#endif case h_kernel_drops: { int max_drops; bool known; @@ -725,6 +740,7 @@ FromDevice::write_handler(const String &input, Element *e, void *thunk, ErrorHan { FromDevice* fd = static_cast(e); switch ((intptr_t)thunk) { +#if HAVE_LINUX_ETHTOOL_H case h_rss_max: { int max; if (!IntArg().parse(input,max)) @@ -736,6 +752,7 @@ FromDevice::write_handler(const String &input, Element *e, void *thunk, ErrorHan } return fd->dev_set_rss_reta(table.data(), table.size()); } +#endif case h_reset_count: fd->_count = 0; return 0; @@ -744,6 +761,7 @@ FromDevice::write_handler(const String &input, Element *e, void *thunk, ErrorHan } } +#ifdef HAVE_LINUX_ETHTOOL_H int FromDevice::dev_get_rss_reta_size() { @@ -844,6 +862,7 @@ FromDevice::dev_set_rss_reta(unsigned* reta, unsigned reta_sz) return err; } +#endif void FromDevice::add_handlers() diff --git a/elements/userlevel/fromdevice.hh b/elements/userlevel/fromdevice.hh index 32a087b976..77584d75f8 100644 --- a/elements/userlevel/fromdevice.hh +++ b/elements/userlevel/fromdevice.hh @@ -216,9 +216,10 @@ class FromDevice : public BatchElement, public EthernetDevice { public: void kernel_drops(bool& known, int& max_drops) const; +#if HAVE_LINUX_ETHTOOL_H int dev_set_rss_reta(unsigned *reta, unsigned reta_sz); int dev_get_rss_reta_size(); - +#endif private: diff --git a/elements/userlevel/kernelfilter.cc b/elements/userlevel/kernelfilter.cc index 946b639690..a11e9fa80c 100644 --- a/elements/userlevel/kernelfilter.cc +++ b/elements/userlevel/kernelfilter.cc @@ -110,7 +110,7 @@ KernelFilter::device_filter6(const String &devname, bool add_filter, if (iptables_command) cmda << iptables_command; else if (access("/sbin/ip6tables", X_OK) == 0) - cmda << "/sbin/iptables"; + cmda << "/sbin/ip6tables"; else if (access("/usr/sbin/ip6tables", X_OK) == 0) cmda << "/usr/sbin/ip6tables"; else diff --git a/elements/userlevel/kerneltun.cc b/elements/userlevel/kerneltun.cc index 4eb5ac8c84..5e80eb3165 100644 --- a/elements/userlevel/kerneltun.cc +++ b/elements/userlevel/kerneltun.cc @@ -791,7 +791,7 @@ KernelTunMP::push_batch(int, PacketBatch *batch) { #endif CLICK_ENDDECLS -ELEMENT_REQUIRES(userlevel FakePcap) +ELEMENT_REQUIRES(userlevel FakePcap linux) EXPORT_ELEMENT(KernelTun) EXPORT_ELEMENT(KernelTunMP) ELEMENT_MT_SAFE(KernelTunMP) diff --git a/elements/userlevel/socket.cc b/elements/userlevel/socket.cc index 83e38f2c86..189420fc32 100644 --- a/elements/userlevel/socket.cc +++ b/elements/userlevel/socket.cc @@ -93,6 +93,7 @@ Socket::configure(Vector &conf, ErrorHandler *errh) .read_mp("PORT", IPPortArg(_protocol), _remote_port) .read_p("LOCAL_ADDR", _local_ip) .read_p("LOCAL_PORT", IPPortArg(_protocol), _local_port) + .read_p("WAIT_LEARN", _wait_learn) .complete() < 0) return -1; } @@ -119,6 +120,10 @@ Socket::configure(Vector &conf, ErrorHandler *errh) else return errh->error("unknown socket type `%s'", socktype.c_str()); + if (_wait_learn) { + _client = false; + } + return 0; } @@ -196,6 +201,18 @@ Socket::initialize(ErrorHandler *errh) _local_len = _remote_len; } + int one = 1; + if (_set_soreuse) { + if (setsockopt(_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)) < 0) { + errh->warning("CANNOT SET REUSR ADDR"); + } + + + if (setsockopt(_fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(int)) < 0) { + errh->warning("CANNOT SET REUSR PORT"); + } + } + // if a server, or if the optional local arguments have been // specified, bind() to the specified address/port/file if (!_client || _local_port != 0 || _local_pathname != "") { @@ -357,6 +374,9 @@ Socket::selected(int fd, int) else { // datagram server, find out who we are talking to len = recvfrom(_active, _rq->data(), _rq->length(), MSG_TRUNC, (struct sockaddr *)&from, &from_len); + if (_wait_learn) { + _remote.in.sin_port = from.in.sin_port; + } if (_family == AF_INET && !allowed(IPAddress(from.in.sin_addr))) { if (_verbose) diff --git a/elements/userlevel/socket.hh b/elements/userlevel/socket.hh index 6bc6b20b8a..df58c4d585 100644 --- a/elements/userlevel/socket.hh +++ b/elements/userlevel/socket.hh @@ -7,6 +7,7 @@ #include #include "../ip/iproutetable.hh" #include + CLICK_DECLS /* @@ -232,6 +233,8 @@ private: bool _verbose; // be verbose bool _client; // client or server bool _proper; // (PlanetLab only) use Proper to bind port + bool _wait_learn; // Does not set the remote addr before receiving a first message on local port + bool _set_soreuse;// Set SO_REUSEPORT & SO_REUSEADDR IPRouteTable *_allow; // lookup table of good hosts IPRouteTable *_deny; // lookup table of bad hosts diff --git a/etc/ron/divertsocket.cc b/etc/ron/divertsocket.cc index 734a49de87..c116a7a15f 100644 --- a/etc/ron/divertsocket.cc +++ b/etc/ron/divertsocket.cc @@ -42,7 +42,7 @@ # include # include -# if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 +# if HAVE_NETPACKET_PACKET_H && !HAVE_LINUX_IF_PACKET_H # include # include # else diff --git a/etc/ron/todevicenotify.cc b/etc/ron/todevicenotify.cc index 25d82c88ce..b4a74dcfb3 100644 --- a/etc/ron/todevicenotify.cc +++ b/etc/ron/todevicenotify.cc @@ -40,7 +40,7 @@ # include # include # include -# if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1 +# if HAVE_NETPACKET_PACKET_H && !HAVE_LINUX_IF_PACKET_H # include # else # include diff --git a/include/click/allocator.hh b/include/click/allocator.hh index 0d1857b83d..9084487d65 100644 --- a/include/click/allocator.hh +++ b/include/click/allocator.hh @@ -391,7 +391,9 @@ pool_allocator_mt::pool_allocator_mt() : _pool(Pool template pool_allocator_mt::~pool_allocator_mt() { static_assert(sizeof(T) >= sizeof(Pool), "Allocator object is too small"); +#if CLICK_DEBUG_ALLOCATOR int n_release = 0; +#endif while (_global_pool) { item* p = (item*)_global_pool; _global_pool = _global_pool->next; @@ -400,7 +402,9 @@ pool_allocator_mt::~pool_allocator_mt() { next = p->next; CLICK_LFREE(p,sizeof(T)); p = next; +#if CLICK_DEBUG_ALLOCATOR n_release++; +#endif } } for (unsigned i = 0 ; i < _pool.weight(); i++) { @@ -411,7 +415,9 @@ pool_allocator_mt::~pool_allocator_mt() { next = p-> next; CLICK_LFREE(p,sizeof(T)); p = next; +#if CLICK_DEBUG_ALLOCATOR n_release++; +#endif } } #if CLICK_DEBUG_ALLOCATOR @@ -432,7 +438,9 @@ pool_allocator_aware_mt::pool_allocator_aware_mt() : _po template pool_allocator_aware_mt::~pool_allocator_aware_mt() { static_assert(sizeof(T) >= sizeof(Pool), "Allocator object is too small"); +#if CLICK_DEBUG_ALLOCATOR int n_release = 0; +#endif while (_global_pool) { T* p = _global_pool; _global_pool = (T*)_global_pool->pool_next_pool; @@ -441,7 +449,9 @@ pool_allocator_aware_mt::~pool_allocator_aware_mt() { next = (T*)p->pool_next_item; delete p; p = next; +#if CLICK_DEBUG_ALLOCATOR n_release++; +#endif } } for (unsigned i = 0 ; i < _pool.weight(); i++) { @@ -452,7 +462,9 @@ pool_allocator_aware_mt::~pool_allocator_aware_mt() { next = (T*)p->pool_next_item; delete p; p = next; +#if CLICK_DEBUG_ALLOCATOR n_release++; +#endif } } #if CLICK_DEBUG_ALLOCATOR diff --git a/include/click/args.hh b/include/click/args.hh index 4fb644e2bf..7f42bc5901 100644 --- a/include/click/args.hh +++ b/include/click/args.hh @@ -1376,7 +1376,7 @@ class UnitArg { public: Handles suffixes such as "Gbps", "k", etc. */ class BandwidthArg : public NumArg { public: - bool parse(const String &str, uint64_t &result, const ArgContext & = blank_args); + bool parse(const String &str, uint32_t &result, const ArgContext & = blank_args); static String unparse(uint32_t x); int status; }; diff --git a/include/click/batchbuilder.hh b/include/click/batchbuilder.hh index afd978e370..42c9948c72 100644 --- a/include/click/batchbuilder.hh +++ b/include/click/batchbuilder.hh @@ -8,28 +8,42 @@ CLICK_DECLS class DPDKDevice; -struct BatchBuilder { - BatchBuilder() : first(0), count(0), last(-1), last_id() { + +struct PacketList { + PacketList() : first(0), count(0) { }; Packet* first; Packet* tail; int count; - int last; - IPFlow5ID last_id; - - inline void init() { - count = 0; - first = 0; - } + /** + * @brief Finish the construction of the batch. It is *not* reusable without calling init. + * + * @return PacketBatch* A batch with all packets queued + */ inline PacketBatch* finish() { if (!first) return 0; return PacketBatch::make_from_simple_list(first,tail,count); } + + /** + * @brief Extract all packets. The builder can be reused without calling init. + * + * @return PacketBatch* A batch with all packets queued + */ + inline PacketBatch* pop_all() { + if (!first) + return 0; + PacketBatch* b = PacketBatch::make_from_simple_list(first,tail,count); + first = 0; + count = 0; + return b; + } + inline void append(Packet* p) { count++; if (first) { @@ -41,6 +55,34 @@ struct BatchBuilder { } } + inline bool empty() const { + return first == 0; + } + + inline Packet* front() const { + return first; + } + + inline Packet* pop_front() { + Packet* f = first; + first = f->next(); + count--; + return f; + } +}; + +struct BatchBuilder : PacketList { + BatchBuilder() : last(-1), last_id() { + + }; + + int last; + IPFlow5ID last_id; + + inline void init() { + count = 0; + first = 0; + } }; diff --git a/include/click/bigint.hh b/include/click/bigint.hh index 33b274c0c0..de00f75e10 100644 --- a/include/click/bigint.hh +++ b/include/click/bigint.hh @@ -384,8 +384,8 @@ class Bigint { public: }; -/** @brief Typical Bigint usage with uint64_t limb_type. */ -typedef Bigint bigint; +/** @brief Typical Bigint usage with uint32_t limb_type. */ +typedef Bigint bigint; CLICK_ENDDECLS #endif diff --git a/include/click/confparse.hh b/include/click/confparse.hh index ef6f823760..08571c44fb 100644 --- a/include/click/confparse.hh +++ b/include/click/confparse.hh @@ -172,7 +172,7 @@ bool cp_seconds(const String& str, double* result); bool cp_time(const String &str, Timestamp *result, bool allow_negative = false); bool cp_time(const String& str, struct timeval* result); -bool cp_bandwidth(const String& str, uint64_t* result); +bool cp_bandwidth(const String& str, uint32_t* result); // network addresses class IPAddressList; diff --git a/include/click/dpdkdevice.hh b/include/click/dpdkdevice.hh index 80bae93047..d3f80ae321 100644 --- a/include/click/dpdkdevice.hh +++ b/include/click/dpdkdevice.hh @@ -277,6 +277,9 @@ public: } #endif + + inline void kill_ref(Packet* p); + inline static rte_mbuf* get_pkt(unsigned numa_node); inline static rte_mbuf* get_pkt(); inline static struct rte_mbuf* get_mbuf(Packet* p, bool create, int node, bool reset = true); @@ -507,6 +510,14 @@ inline struct rte_mbuf* DPDKDevice::get_mbuf(Packet* p, bool create, int node, b return mbuf; } +inline void DPDKDevice::kill_ref(Packet* p) { + struct rte_mbuf* mbuf = get_mbuf(p,false,-1); + if (rte_mbuf_refcnt_read(mbuf) > 1) + rte_mbuf_refcnt_update(mbuf, -1); + else + p->kill(); +} + inline rte_mbuf* DPDKDevice::get_pkt(unsigned numa_node) { struct rte_mbuf* mbuf = rte_pktmbuf_alloc(get_mpool(numa_node)); if (unlikely(!mbuf)) { diff --git a/include/click/flow/ctxelement.hh b/include/click/flow/ctxelement.hh index daa1b406af..54e1a11260 100644 --- a/include/click/flow/ctxelement.hh +++ b/include/click/flow/ctxelement.hh @@ -638,7 +638,7 @@ inline size_t sse42_strstr_anysize(const char* s, size_t n, const char* needle, return std::string::npos; } -#else +#elif HAVE_SSE2 inline size_t sse2_strstr_anysize(const char* s, size_t n, const char* needle, size_t k) { assert(k > 0); @@ -671,6 +671,54 @@ inline size_t sse2_strstr_anysize(const char* s, size_t n, const char* needle, s return std::string::npos; } +#elif __aarch64__ +#include +inline size_t aarch64_strstr_anysize(const char* s, size_t n, const char* needle, size_t k) { + + assert(k > 0); + assert(n > 0); + + const uint8x16_t first = vdupq_n_u8(needle[0]); + const uint8x16_t last = vdupq_n_u8(needle[k - 1]); + + const uint8_t* ptr = reinterpret_cast(s); + + for (size_t i = 0; i < n; i += 16) { + + const uint8x16_t block_first = vld1q_u8(ptr + i); + const uint8x16_t block_last = vld1q_u8(ptr + i + k - 1); + + const uint8x16_t eq_first = vceqq_u8(first, block_first); + const uint8x16_t eq_last = vceqq_u8(last, block_last); + const uint8x16_t pred_16 = vandq_u8(eq_first, eq_last); + + uint64_t mask; + + mask = vgetq_lane_u64(vreinterpretq_u64_u8(pred_16), 0); + if (mask) { + for (int j=0; j < 8; j++) { + if ((mask & 0xff) && (memcmp(s + i + j + 1, needle + 1, k - 2) == 0)) { + return i + j; + } + + mask >>= 8; + } + } + + mask = vgetq_lane_u64(vreinterpretq_u64_u8(pred_16), 1); + if (mask) { + for (int j=0; j < 8; j++) { + if ((mask & 0xff) && (memcmp(s + i + j + 8 + 1, needle + 1, k - 2) == 0)) { + return i + j + 8; + } + + mask >>= 8; + } + } + } + + return std::string::npos; +} #endif //Inline functions @@ -679,8 +727,10 @@ inline char* CTXElement::searchInContent(char *content, const StringRef &pattern size_t pos = avx2_strstr_anysize(content, length, pattern.data(), pattern.length()); #elif HAVE_SSE42 size_t pos = sse42_strstr_anysize(content, length, pattern.data(), pattern.length()); -#else +#elif HAVE_SSE2 size_t pos = sse2_strstr_anysize(content, length, pattern.data(), pattern.length()); +#elif __aarch64__ + size_t pos = aarch64_strstr_anysize(content, length, pattern.data(), pattern.length()); #endif if (pos == std::string::npos) return 0; diff --git a/include/click/gaprate.hh b/include/click/gaprate.hh index c2a7eae5f3..69a2fb7bf3 100644 --- a/include/click/gaprate.hh +++ b/include/click/gaprate.hh @@ -49,17 +49,17 @@ class GapRate { public: /** @brief Construct a GapRate object with initial rate @a r. * @param r initial rate (events per second) */ - inline GapRate(uint64_t r); + inline GapRate(unsigned r); /** @brief Return the current rate. */ - inline uint64_t rate() const; + inline unsigned rate() const; /** @brief Set the current rate to @a r. * @param r desired rate (events per second) * * Rates larger than MAX_RATE are reduced to MAX_RATE. Also performs the * equivalent of a reset() to flush old state. */ - inline void set_rate(uint64_t r); + inline void set_rate(unsigned r); /** @brief Set the current rate to @a r. * @param r desired rate (events per second) @@ -67,7 +67,7 @@ class GapRate { public: * * Acts like set_rate(@a r), except that an warning is reported to @a errh * if @a r is larger than MAX_RATE. */ - void set_rate(uint64_t r, ErrorHandler *errh); + void set_rate(unsigned r, ErrorHandler *errh); /** @brief Returns whether the user's rate is behind the true rate. @@ -97,7 +97,7 @@ class GapRate { public: * * @note This may be faster than calling update() @a delta times. * Furthermore, @a delta can be negative. */ - inline void update_with(int64_t delta); + inline void update_with(int delta); /** @brief Resets the true rate counter. * @@ -106,20 +106,20 @@ class GapRate { public: inline void reset(); - enum { UGAP_SHIFT = 43 }; - enum { MAX_RATE = 1000000ULL << UGAP_SHIFT }; + enum { UGAP_SHIFT = 12 }; + enum { MAX_RATE = 1000000U << UGAP_SHIFT }; private: - uint64_t _ugap; // (1000000 << UGAP_SHIFT) / _rate - int64_t _sec_count; // number of updates this second so far + unsigned _ugap; // (1000000 << UGAP_SHIFT) / _rate + int _sec_count; // number of updates this second so far Timestamp::seconds_type _tv_sec; // current second - uint64_t _rate; // desired rate + unsigned _rate; // desired rate #if DEBUG_GAPRATE Timestamp _last; #endif - inline void initialize_rate(uint64_t rate); + inline void initialize_rate(unsigned rate); }; @@ -134,7 +134,7 @@ GapRate::reset() } inline void -GapRate::initialize_rate(uint64_t r) +GapRate::initialize_rate(unsigned r) { _rate = r; _ugap = (r == 0 ? MAX_RATE + 1 : MAX_RATE / r); @@ -144,7 +144,7 @@ GapRate::initialize_rate(uint64_t r) } inline void -GapRate::set_rate(uint64_t r) +GapRate::set_rate(unsigned r) { if (r > MAX_RATE) r = MAX_RATE; @@ -152,7 +152,7 @@ GapRate::set_rate(uint64_t r) initialize_rate(r); if (_tv_sec >= 0 && r != 0) { Timestamp now = Timestamp::now(); - _sec_count = (static_cast(now.usec()) << UGAP_SHIFT) / _ugap; + _sec_count = (now.usec() << UGAP_SHIFT) / _ugap; } } } @@ -165,14 +165,14 @@ GapRate::GapRate() } inline -GapRate::GapRate(uint64_t r) +GapRate::GapRate(unsigned r) : _rate(0) { initialize_rate(r); reset(); } -inline uint64_t +inline unsigned GapRate::rate() const { return _rate; @@ -182,15 +182,15 @@ inline bool GapRate::need_update(const Timestamp &now) { // this is an approximation of: - // uint64_t need = (uint64_t) ((now.usec() / 1000000.0) * _rate) - uint64_t need = (static_cast(now.usec()) << UGAP_SHIFT) / _ugap; + // unsigned need = (unsigned) ((now.usec() / 1000000.0) * _rate) + unsigned need = (now.usec() << UGAP_SHIFT) / _ugap; if (_tv_sec < 0) { // 27.Feb.2005: often OK to send a packet after reset unless rate is // 0 -- requested by Bart Braem // check include/click/gaprate.hh (1.2) _tv_sec = now.sec(); - _sec_count = need + ((static_cast(now.usec()) << UGAP_SHIFT) - (need * _ugap) > _ugap / 2); + _sec_count = need + ((now.usec() << UGAP_SHIFT) - (need * _ugap) > _ugap / 2); } else if (now.sec() > _tv_sec) { _tv_sec = now.sec(); if (_sec_count > 0) @@ -200,7 +200,7 @@ GapRate::need_update(const Timestamp &now) #if DEBUG_GAPRATE click_chatter("%p{timestamp} -> %u @ %u [%d]", &now, need, _sec_count, (int)need >= _sec_count); #endif - return ((int64_t)need >= _sec_count); + return ((int)need >= _sec_count); } inline void @@ -210,7 +210,7 @@ GapRate::update() } inline void -GapRate::update_with(int64_t delta) +GapRate::update_with(int delta) { _sec_count += delta; } @@ -224,8 +224,8 @@ GapRate::expiry() const return Timestamp(_tv_sec, 0); else { Timestamp::seconds_type sec = _tv_sec; - int64_t count = _sec_count; - if ((uint64_t) count >= _rate) { + int count = _sec_count; + if ((unsigned) count >= _rate) { sec += count / _rate; count = count % _rate; } diff --git a/include/click/glue.hh b/include/click/glue.hh index eec46e2630..5cc6e479bd 100644 --- a/include/click/glue.hh +++ b/include/click/glue.hh @@ -103,6 +103,9 @@ extern "C" { #include } #endif +#if defined(__MACH__) && defined(__APPLE__) +# include +#endif #endif @@ -721,8 +724,9 @@ typedef uint32_t click_cycles_t; inline click_cycles_t click_get_cycles() { - -#if CLICK_LINUXMODULE && HAVE_INT64_TYPES && __i386__ +#if defined(__MACH__) && defined(__APPLE__) + return mach_absolute_time(); +#elif CLICK_LINUXMODULE && HAVE_INT64_TYPES && __i386__ uint64_t x; __asm__ __volatile__ ("rdtsc" : "=A" (x)); return x; @@ -748,6 +752,10 @@ click_get_cycles() uint32_t xlo, xhi; __asm__ __volatile__ ("rdtsc" : "=a" (xlo), "=d" (xhi)); return xlo; +#elif CLICK_USERLEVEL && __aarch64__ + uint64_t val; + asm volatile("mrs %0, cntvct_el0" : "=r" (val)); + return val; #elif CLICK_USERLEVEL && HAVE_DPDK && defined(_RTE_CYCLES_H_) // On other architectures we use DPDK implementation, if available return rte_get_tsc_cycles(); @@ -768,6 +776,10 @@ inline click_cycles_t cycles_hz() { return rte_get_timer_hz(); } return 0; +#elif defined(__MACH__) && defined(__APPLE__) + mach_timebase_info_data_t _clock_timebase; + mach_timebase_info(&_clock_timebase); // Initialize timebase_info + return _clock_timebase.denom / _clock_timebase.numer; #endif if (click_cycles_hz == 0) { click_cycles_t tsc_freq = click_get_cycles(); @@ -783,6 +795,7 @@ inline click_cycles_t cycles_hz() { #define TYPE_LITEND 1 #define TYPE_BIGEND 2 +#ifndef htonll inline unsigned long long htonll(unsigned long long src) { static int typ = TYPE_INIT; unsigned char c; @@ -807,6 +820,7 @@ inline unsigned long long htonll(unsigned long long src) { return x.ull; } +#endif CLICK_ENDDECLS diff --git a/include/click/ip6address.hh b/include/click/ip6address.hh index d562137484..8a144b2d2f 100644 --- a/include/click/ip6address.hh +++ b/include/click/ip6address.hh @@ -89,6 +89,9 @@ class IP6Address { public: int mask_to_prefix_len() const; inline bool matches_prefix(const IP6Address &addr, const IP6Address &mask) const; inline bool mask_as_specific(const IP6Address &) const; + static inline IP6Address make_zero() { + return IP6Address(); + } /** @brief Test if this address contains an embedded Ethernet address. * @@ -447,10 +450,7 @@ inline void ip6_follow_eh(const click_ip6* ip6, const unsigned char* end, F fn) inline void* ip6_find_header(const click_ip6* ip6, const uint8_t type, const unsigned char* end) { unsigned char* pos = 0; auto fnt = [&pos,type] (const uint8_t next, unsigned char* hdr) - -#if defined(__GNUC__) && __GNUC_PREREQ(11,0) - __attribute__((always_inline)) -#endif +CLICK_ALWAYS_INLINE -> bool { if (next == type) { pos = hdr; diff --git a/include/click/llrpc.h b/include/click/llrpc.h index 0c6a112b84..37758e769c 100644 --- a/include/click/llrpc.h +++ b/include/click/llrpc.h @@ -14,7 +14,9 @@ CLICK_CXX_UNPROTECT #else # include # include -# include +# if HAVE_ASM_IOCTL_H +# include +# endif #endif /* Click low-level RPC interface */ diff --git a/include/click/loadbalancer.hh b/include/click/loadbalancer.hh index 54789dae20..d6622d0240 100644 --- a/include/click/loadbalancer.hh +++ b/include/click/loadbalancer.hh @@ -4,6 +4,7 @@ #include #include +#include #include #if HAVE_DPDK #include @@ -38,6 +39,10 @@ class LoadBalancer { public: lsttrans.find_insert("packets",packets); lsttrans.find_insert("bytes",bytes); lsttrans.find_insert("cpu",cpu); +#if __cplusplus > 201402L + std::random_device rd; + _gen= std::mt19937(rd()); +#endif } enum LBMode { @@ -102,6 +107,9 @@ protected: int _awrr_interval; float _alpha; bool _autoscale; +#if __cplusplus > 201402L + std::mt19937 _gen; +#endif uint64_t get_load_metric(int idx) { return get_load_metric(idx, _lst_case); @@ -533,7 +541,11 @@ protected: weights_helper.push_back(i); } } +#if __cplusplus > 201402L + std::shuffle(weights_helper.begin(), weights_helper.end(), _gen); +#else std::random_shuffle(weights_helper.begin(), weights_helper.end()); +#endif auto& v = _weights_helper.write_begin(); v = weights_helper; _weights_helper.write_commit(); @@ -543,7 +555,7 @@ protected: switch(_mode_case) { case round_robin: { int b = _selector.unchecked_at((*_current)++); - if (*_current == (unsigned)_selector.size()) { + if ((unsigned)*_current == (unsigned)_selector.size()) { *_current = 0; } return b; diff --git a/include/click/packet.hh b/include/click/packet.hh index 58996419ee..7bc38d925e 100644 --- a/include/click/packet.hh +++ b/include/click/packet.hh @@ -23,7 +23,10 @@ #if CLICK_NS # include #endif -#if !CLICK_PACKET_USE_DPDK && (CLICK_USERLEVEL || CLICK_NS || CLICK_MINIOS) && (!HAVE_MULTITHREAD || HAVE___THREAD_STORAGE_CLASS) && !(NETMAP_PACKET_POOL) && ALLOW_CLICK_PACKET_POOL +#if !CLICK_PACKET_USE_DPDK && \ + (CLICK_USERLEVEL || CLICK_NS || CLICK_MINIOS) && \ + (!HAVE_MULTITHREAD || HAVE___THREAD_STORAGE_CLASS) && \ + HAVE_ALLOW_CLICK_PACKET_POOL # define HAVE_CLICK_PACKET_POOL 1 #endif #ifndef CLICK_PACKET_DEPRECATED_ENUM @@ -1780,7 +1783,7 @@ Packet::kill() b->list = 0; # endif skbmgr_recycle_skbs(b); - #elif CLICK_PACKET_USE_DPDK +#elif CLICK_PACKET_USE_DPDK # if HAVE_FLOW_DYNAMIC if (fcb_stack) { fcb_stack->release(1); @@ -1788,24 +1791,26 @@ Packet::kill() # endif //Dpdk takes care of indirect and related things rte_pktmbuf_free(mb()); - #elif HAVE_CLICK_PACKET_POOL && !defined(CLICK_FORCE_EXPENSIVE) +#elif HAVE_CLICK_PACKET_POOL && !defined(CLICK_FORCE_EXPENSIVE) # ifndef CLICK_NOINDIRECT if (_use_count.dec_and_test()) # endif { WritablePacket::recycle(static_cast(this)); } - #else +#else # if HAVE_FLOW_DYNAMIC if (fcb_stack) { fcb_stack->release(1); } # endif SFCB_STACK( - if (_use_count.dec_and_test()) { - - delete this; - } +# ifndef CLICK_NOINDIRECT + if (_use_count.dec_and_test()) +# endif + { + delete this; + } ) #endif } @@ -1852,9 +1857,12 @@ Packet::kill_nonatomic() } # endif SFCB_STACK( - if (_use_count.nonatomic_dec_and_test()) { - delete this; - } +#ifndef CLICK_NOINDIRECT + if (_use_count.nonatomic_dec_and_test()) +#endif + { + delete this; + } ) #endif } diff --git a/include/click/packetbatch.hh b/include/click/packetbatch.hh index 69146c89a5..4e68a78737 100644 --- a/include/click/packetbatch.hh +++ b/include/click/packetbatch.hh @@ -203,6 +203,41 @@ CLICK_DECLS }\ +/** + * Execute a function for each packet, passing parameters to easily add multiple packets to the list + * + * An example that does nothing in practice : + * void fnt(Packet *p, std::functionpush) { + * push(p); + * } + * EXECUTE_FOR_EACH_PACKET_ADD( fnt, batch ); + */ +#define EXECUTE_FOR_EACH_PACKET_ADD(fnt,batch) {\ + Packet* next = ((batch != 0)? batch->first()->next() : 0 );\ + Packet* p = batch->first();\ + Packet* last = 0;\ + int count = 0;\ + for (;p != 0;p=next,next=(p==0?0:p->next())) {\ + auto add = [&batch,&last,&count](Packet*q) {\ + if (last) { \ + last->set_next(q); \ + } else { \ + batch = reinterpret_cast(q);\ + }\ + last = q;\ + count++;\ + };\ + fnt(p,add);\ + }\ + if (likely(last)) {\ + batch->set_count(count);\ + batch->set_tail(last);\ + last->set_next(0);\ + } else {\ + batch = 0;\ + }\ + }\ + /** * Split a batch into multiple batch according to a given function which will * give the index of an output to choose. @@ -751,7 +786,7 @@ inline void PacketBatch::kill() { #if HAVE_DPDK_PACKET_POOL #define BATCH_RECYCLE_UNKNOWN_PACKET(p) {\ - if (p->data_packet() == 0 && p->buffer_destructor() == DPDKDevice::free_pkt && p->buffer() != 0) {\ + if (p->data_packet() == 0 && (DPDKDevice::is_dpdk_packet(p)) && p->buffer() != 0) {\ BATCH_RECYCLE_ADD_DATA_PACKET(p);\ } else {\ BATCH_RECYCLE_ADD_PACKET(p);}} diff --git a/include/click/routerthread.hh b/include/click/routerthread.hh index 12275475b1..4c5bf22fb3 100644 --- a/include/click/routerthread.hh +++ b/include/click/routerthread.hh @@ -75,6 +75,8 @@ class alignas(CLICK_CACHE_LINE_SIZE) RouterThread { public: #if HAVE_CLICK_LOAD float load(); + int load_unscaled(); + int load_max_scale(); unsigned long long load_cycles(); unsigned long long useful_kcycles(); #endif diff --git a/include/click/standard/threadsched.hh b/include/click/standard/threadsched.hh index 3c07031766..5201ca6435 100644 --- a/include/click/standard/threadsched.hh +++ b/include/click/standard/threadsched.hh @@ -9,7 +9,7 @@ CLICK_DECLS class ThreadSched { public: - enum { THREAD_QUIESCENT = -1, THREAD_UNKNOWN = -1000 }; + enum { THREAD_QUIESCENT = -1, THREAD_UNKNOWN = -1000, THREAD_AUTO = -1001 }; ThreadSched() { } virtual ~ThreadSched() { } diff --git a/include/click/sync.hh b/include/click/sync.hh index 70218887e0..f3bb94b625 100644 --- a/include/click/sync.hh +++ b/include/click/sync.hh @@ -630,10 +630,11 @@ SimpleSpinlock::acquire() #if CLICK_LINUXMODULE spin_lock(&_lock); #elif CLICK_MULTITHREAD_SPINLOCK - while (_lock.swap(1) != 0) - do { - click_relax_fence(); - } while (_lock != 0); + while (_lock.swap(1) != 0) { + do { + click_relax_fence(); + } while (_lock != 0); + } #endif } diff --git a/include/click/tokenbucket.hh b/include/click/tokenbucket.hh index e5318c9e86..5966e9bbf7 100644 --- a/include/click/tokenbucket.hh +++ b/include/click/tokenbucket.hh @@ -32,8 +32,6 @@ CLICK_DECLS TokenRateX template parameter P defines the time tick unit and frequency. The provided TokenBucketJiffyParameters class is designed to be used as TokenRateX's parameter; it measures ticks in units of jiffies. - TokenBucketUsecParameters is also included, which measures ticks in - units of microseconds. @sa GapRate */ @@ -50,7 +48,7 @@ CLICK_DECLS token_max. An idle TokenRateX never refills. Most users will be satisfied with the TokenRate type, which is equal to - TokenRateX >. + TokenRateX >. @sa TokenCounterX, TokenBucketX */ @@ -216,13 +214,13 @@ void TokenRateX

::assign(token_type rate, token_type capacity) token_type frequency = P::frequency(); if (rate != 0) { // constrain capacity so _tokens_per_tick fits in 1 limb - unsigned long long min_capacity = (rate - 1) / frequency + 1; + unsigned min_capacity = (rate - 1) / frequency + 1; if (capacity < min_capacity) capacity = min_capacity; } _token_scale = max_tokens / capacity; - // XXX on non-64 bit types + // XXX on non-32 bit types static_assert(sizeof(bigint::limb_type) == sizeof(token_type), "bigint::limb_type should have the same size as token_type."); bigint::limb_type l[2] = { 0, 0 }; @@ -320,7 +318,7 @@ template struct TokenRateConverter { remove(), and similar functions act as normal for idle and unlimited rates. Most users will be satisfied with the TokenCounter type, which is equal to - TokenCounterX > >. + TokenCounterX > >. @sa TokenRateX, TokenBucketX */ @@ -695,68 +693,6 @@ class TokenBucketJiffyParameters { public: }; -/** @class TokenBucketUsecParameters include/click/tokenbucket.hh - @brief Helper class for token bucket rate limiter. - - Pass this class as the parameter to TokenRateX. TokenBucketUsecParameters - measures ticks in units of microseconds. The template parameter is the type of - tokens. */ - -template -class TokenBucketUsecParameters { public: - - /** @brief The type of tokens. Always unsigned. */ - typedef T token_type; - - /** @brief The type of a time point. Always unsigned. */ - typedef click_uintmax_t time_point_type; - - /** @brief The type of a difference between time points. Always signed. */ - typedef click_intmax_t duration_type; - - /** @brief Return the current time point. - * @note TokenBucketUsecParameters measures time points in microseconds. */ - static time_point_type now() { - return Timestamp::now_steady().usecval(); - } - - static time_point_type time_point(time_point_type t) { - return t; - } - - /** @brief Return @a b - @a a, assuming that @a b was measured after @a a. - * - * Some time measurements can, in rare cases, appear to jump backwards, - * as timestamps do when the user changes the current time. If this - * happens, and @a b < @a a (even though @a b happened after @a a), - * time_monotonic_difference must return 0. */ - static duration_type time_monotonic_difference(time_point_type a, time_point_type b) { - return (likely(a <= b) ? b - a : 0); - } - - /** @brief Return true if @a a happened before @a b. */ - static bool time_less(time_point_type a, time_point_type b) { - return (duration_type) (a - b) < 0; - } - - /** @brief Return the number of time points per period. - * - * Here, this is the number of microseconds per second. */ - static unsigned frequency() { - return 1000000; - } - - /** @brief Return the Timestamp representing a given time point. */ - static Timestamp timestamp(time_point_type x) { - return Timestamp::make_usec(x); - } - - /** @brief Return the Timestamp representing a given tick count. */ - static Timestamp timestamp(duration_type x) { - return Timestamp::make_usec(x); - } - -}; /** @class TokenBucketX include/click/tokenbucket.hh @brief Token bucket rate limiter. @@ -765,7 +701,7 @@ class TokenBucketUsecParameters { public: implemented as a pair of TokenRateX and TokenCounterX. Most users will be satisfied with the TokenBucket type, which is equal to - TokenBucketX >. + TokenBucketX >. @sa GapRate */ @@ -1070,15 +1006,15 @@ inline typename TokenBucketX

::ticks_type TokenBucketX

::epochs_until_contai /** @class TokenRate include/click/tokenbucket.hh - * @brief Microsecond-based token bucket rate + * @brief Jiffy-based token bucket rate * * Equivalent to - * @link TokenRateX TokenRateX >@endlink. - * @sa TokenRateX, TokenBucketUsecParameters */ -typedef TokenRateX > TokenRate; + * @link TokenRateX TokenRateX >@endlink. + * @sa TokenRateX, TokenBucketJiffyParameters */ +typedef TokenRateX > TokenRate; /** @class TokenCounter include/click/tokenbucket.hh - * @brief Microsecond-based token counter + * @brief Jiffy-based token counter * * Equivalent to * @link TokenCounterX TokenCounterX@endlink. @@ -1086,12 +1022,12 @@ typedef TokenRateX > TokenRate; typedef TokenCounterX TokenCounter; /** @class TokenBucket include/click/tokenbucket.hh - * @brief Microsecond-based token bucket rate limiter + * @brief Jiffy-based token bucket rate limiter * * Equivalent to - * @link TokenBucketX TokenBucketX >@endlink. - * @sa TokenBucketX, TokenBucketUsecParameters */ -typedef TokenBucketX > TokenBucket; + * @link TokenBucketX TokenBucketX >@endlink. + * @sa TokenBucketX, TokenBucketJiffyParameters */ +typedef TokenBucketX > TokenBucket; CLICK_ENDDECLS #endif diff --git a/include/click/type_traits.hh b/include/click/type_traits.hh index 1d989a8c57..c384231947 100644 --- a/include/click/type_traits.hh +++ b/include/click/type_traits.hh @@ -58,7 +58,9 @@ struct conditional { has_trivial_copy is equivalent to true_type if T has a trivial copy constructor, false_type if it does not. */ -#if HAVE___HAS_TRIVIAL_COPY +#if HAVE___IS_TRIVIALLY_COPYABLE +template struct has_trivial_copy : public integral_constant {}; +#elif HAVE___HAS_TRIVIAL_COPY template struct has_trivial_copy : public integral_constant {}; #else template struct has_trivial_copy : public false_type {}; diff --git a/lib/args.cc b/lib/args.cc index 475761bb9f..ecc367f360 100644 --- a/lib/args.cc +++ b/lib/args.cc @@ -1220,7 +1220,7 @@ static const char byte_bandwidth_units[] = "\ static const char byte_bandwidth_prefixes[] = "\ k\103K\103M\106G\111"; -static uint64_t +static uint32_t multiply_factor(uint32_t ix, uint32_t fx, uint32_t factor, int &status) { if (factor == 1) { @@ -1233,14 +1233,14 @@ multiply_factor(uint32_t ix, uint32_t fx, uint32_t factor, int &status) if (int32_t(flow) < 0) ++ftoint; int_multiply(ix, factor, ilow, ihigh); - /* if (ihigh != 0 || ilow + ftoint < ftoint) - status = NumArg::status_range; */ - return ((uint64_t) ihigh << 32) + ilow + ftoint; + if (ihigh != 0 || ilow + ftoint < ftoint) + status = NumArg::status_range; + return ilow + ftoint; } } bool -BandwidthArg::parse(const String &str, uint64_t &result, const ArgContext &args) +BandwidthArg::parse(const String &str, uint32_t &result, const ArgContext &args) { int power, factor; const char *unit_end = UnitArg(byte_bandwidth_units, byte_bandwidth_prefixes).parse(str.begin(), str.end(), power, factor); @@ -1258,7 +1258,7 @@ BandwidthArg::parse(const String &str, uint64_t &result, const ArgContext &args) ix = multiply_factor(ix, fx, factor, status); if (status == status_range) { args.error("out of range"); - result = UINT64_MAX; + result = 0xFFFFFFFFU; return false; } else { if (unit_end == str.end() && ix) diff --git a/lib/confparse.cc b/lib/confparse.cc index 15be6967ea..f79f957d49 100644 --- a/lib/confparse.cc +++ b/lib/confparse.cc @@ -1589,10 +1589,10 @@ bool cp_time(const String &str, timeval *result) * otherwise, cp_errno is set to CPE_FORMAT (unparsable) or CPE_OK (if all was * well). */ -bool cp_bandwidth(const String &str, uint64_t *result) +bool cp_bandwidth(const String &str, uint32_t *result) { BandwidthArg ba; - uint64_t x; + uint32_t x; if (!ba.parse(str, x)) { cp_errno = CPE_FORMAT; return false; @@ -2592,7 +2592,7 @@ default_parsefunc(cp_value *v, const String &arg, case cpiBandwidth: { BandwidthArg ba; - if (!ba.parse(arg, v->v.u64)) + if (!ba.parse(arg, v->v.u32)) goto type_mismatch; else if (ba.status == NumArg::status_range) { String m = cp_unparse_bandwidth(v->v.u32); diff --git a/lib/flow.cc b/lib/flow.cc index 73c7cc29e4..9e7b2facd7 100644 --- a/lib/flow.cc +++ b/lib/flow.cc @@ -21,7 +21,18 @@ #include #include #include +#if defined(__aarch64__) && defined(__mach__) +static __inline uint32_t __bswap_32(uint32_t __x) +{ + return __x>>24 | __x>>8&0xff00 | __x<<8&0xff0000 | __x<<24; +} +static __inline uint64_t __bswap_64(uint64_t __x) +{ + return __bswap_32(__x)+0ULL<<32 | __bswap_32(__x>>32); +} +#else #include +#endif #include #include #include diff --git a/lib/flowbuffer.cc b/lib/flowbuffer.cc index 07d7c3c9e6..883edf8e0b 100644 --- a/lib/flowbuffer.cc +++ b/lib/flowbuffer.cc @@ -10,7 +10,9 @@ #include #include #include +#ifndef __aarch64__ #include +#endif CLICK_DECLS diff --git a/lib/gaprate.cc b/lib/gaprate.cc index c845437e9e..c8af8f3fed 100644 --- a/lib/gaprate.cc +++ b/lib/gaprate.cc @@ -24,7 +24,7 @@ CLICK_DECLS void -GapRate::set_rate(uint64_t r, ErrorHandler *errh) +GapRate::set_rate(unsigned r, ErrorHandler *errh) { if (r > GapRate::MAX_RATE && errh) errh->error("rate too large; lowered to %u", GapRate::MAX_RATE); diff --git a/lib/packet.cc b/lib/packet.cc index 0214132a72..ccafc8fce3 100644 --- a/lib/packet.cc +++ b/lib/packet.cc @@ -628,7 +628,7 @@ inline bool WritablePacket::is_from_data_pool(WritablePacket *p) { !p->_data_packet && # endif p->_head - && (p->_destructor == DPDKDevice::free_pkt)); + && (p->buffer_destructor() == DPDKDevice::free_pkt)); #else if (likely( # ifndef CLICK_NOINDIRECT @@ -1512,14 +1512,14 @@ cleanup_pool(PacketPool *pp, int global) ::operator delete((void *) p); } while (WritablePacket *pd = pp->pd) { - ++pdcount; - pp->pd = static_cast(pd->next()); + ++pdcount; + pp->pd = static_cast(pd->next()); # if HAVE_DPDK_PACKET_POOL - rte_pktmbuf_free((struct rte_mbuf*)pd->destructor_argument()); + rte_pktmbuf_free((struct rte_mbuf*)pd->destructor_argument()); # else - Packet::release_buffer(pd->buffer()); + Packet::release_buffer(pd->buffer()); # endif - ::operator delete((void *) pd); + ::operator delete((void *) pd); } # if !HAVE_BATCH_RECYCLE assert(pcount <= CLICK_PACKET_POOL_SIZE); diff --git a/lib/router.cc b/lib/router.cc index 2c28ad7fa9..94ffcf7373 100644 --- a/lib/router.cc +++ b/lib/router.cc @@ -2572,7 +2572,13 @@ Router::router_handler(int operation, String &data, Element *e, int index; IntArg arg; if (data && arg.parse(data, index, errh)) { - sa << r->master()->thread(index)->load(); + + if (opt == GH_LOAD) { + sa << r->master()->thread(index)->load(); + } else if (opt == GH_LOAD_CYCLES) + sa << String(r->master()->thread(index)->load_cycles()); + else + sa << String(r->master()->thread(index)->useful_kcycles()); } else { int n = r->master()->nthreads(); for (int i = 0; i < n; i++) { diff --git a/lib/routerthread.cc b/lib/routerthread.cc index bde12ec66b..258dc1535a 100644 --- a/lib/routerthread.cc +++ b/lib/routerthread.cc @@ -519,6 +519,17 @@ RouterThread::load() { return (float) _load_state.read().load.unscaled_average() / 1024; } +int +RouterThread::load_unscaled() { + return _load_state.read().load.unscaled_average(); +} + +int +RouterThread::load_max_scale() { + return 1024; +} + + unsigned long long RouterThread::load_cycles() { const LoadState &ls = _load_state.read_begin(); diff --git a/m4/click.m4 b/m4/click.m4 index 1d504c254b..29b523e22c 100644 --- a/m4/click.m4 +++ b/m4/click.m4 @@ -502,7 +502,7 @@ AC_DEFUN([CLICK_CHECK_NUMA], [ AC_SEARCH_LIBS([numa_available], [numa], [ac_have_libnuma=yes], [ac_have_libnuma=no]) if test "$ac_have_libnuma" = yes; then - AC_DEFINE([HAVE_NUMA], [1], [Define if you have the header file.]) + AC_DEFINE([HAVE_NUMA], [1], [Define if you have the header file.]) LDFLAGS="$LDFLAGS -lnuma" fi @@ -842,6 +842,12 @@ AC_DEFUN([CLICK_CHECK_COMPILER_INTRINSICS], [ AC_DEFINE([HAVE___SYNC_SYNCHRONIZE_ARGUMENTS], [1], [Define if the __sync_synchronize function supports arguments.]) fi + AC_CACHE_CHECK([for __is_trivially_copyable], [ac_cv_have___is_trivially_copyable], + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[long x = 1; if (__is_trivially_copyable(long)) x = 0;]])], [ac_cv_have___is_trivially_copyable=yes], [ac_cv_have___is_trivially_copyable=no])]) + if test $ac_cv_have___is_trivially_copyable = yes; then + AC_DEFINE([HAVE___IS_TRIVIALLY_COPYABLE], [1], [Define if you have the __is_trivially_copyable compiler intrinsic.]) + fi + AC_CACHE_CHECK([for __has_trivial_copy], [ac_cv_have___has_trivial_copy], [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[long x = 1; if (__has_trivial_copy(long)) x = 0;]])], [ac_cv_have___has_trivial_copy=yes], [ac_cv_have___has_trivial_copy=no])]) if test $ac_cv_have___has_trivial_copy = yes; then diff --git a/mininet/fastclick/Vagrantfile b/mininet/fastclick/Vagrantfile index e886de8db9..2ab1e5f8b2 100644 --- a/mininet/fastclick/Vagrantfile +++ b/mininet/fastclick/Vagrantfile @@ -1,7 +1,8 @@ $init = <