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 = <