Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4eb0fb1b6 | ||
|
|
1a792daaa3 | ||
|
|
34e13e9802 | ||
|
|
3813f1c9ee | ||
|
|
3dc9fd0b82 | ||
|
|
c0c089314b | ||
|
|
9f6a7d97bc | ||
|
|
0bba81df36 | ||
|
|
2377ada11a | ||
|
|
b7e72c3a0a | ||
|
|
c1d4837b6f | ||
|
|
bc0e617e48 | ||
|
|
5bafd2c7c4 | ||
|
|
13d582abec | ||
|
|
d82134b850 | ||
|
|
ebc20f6000 | ||
|
|
fdc0645d77 | ||
|
|
e1cf4ba46a | ||
|
|
6bead9b6de | ||
|
|
f3bc3ae906 | ||
|
|
a158370ecb | ||
|
|
34b2b57831 | ||
|
|
1f237abbf1 | ||
|
|
3a2339a1b4 | ||
|
|
1752159ae0 | ||
|
|
4995bf960d | ||
|
|
c68b2e8a46 | ||
|
|
c29eb7f50e | ||
|
|
9d283adac4 | ||
|
|
b93fb6c831 | ||
|
|
8f290fc884 | ||
|
|
cb27d91658 | ||
|
|
9cec699867 | ||
|
|
d656aff913 | ||
|
|
22974904d3 | ||
|
|
69857c37c2 | ||
|
|
feeb918ea8 | ||
|
|
13ff259ec8 | ||
|
|
cb6551e96f | ||
|
|
56c68a364a | ||
|
|
51cf75c8f0 | ||
|
|
854866f424 | ||
|
|
32f7eac7cd | ||
|
|
5ab4cf83d9 | ||
|
|
f3ee808927 | ||
|
|
97f26a2618 | ||
|
|
e89118e8be | ||
|
|
fb034219ef | ||
|
|
cf9e1c7789 | ||
|
|
5a897699cf | ||
|
|
18c2b29e41 | ||
|
|
f7d2050f70 | ||
|
|
8e53127d0a | ||
|
|
2feb4596a9 | ||
|
|
6598fb0881 | ||
|
|
a499aa230f | ||
|
|
4bd4f71f60 | ||
|
|
a4abfb010f | ||
|
|
380668b6e2 | ||
|
|
606d5ddc9e | ||
|
|
24be073413 | ||
|
|
759db61b84 | ||
|
|
6c8c2a0b9c | ||
|
|
c88d2d4a61 | ||
|
|
cf1d0c0286 | ||
|
|
f689c7944b | ||
|
|
a6f637a166 | ||
|
|
df1dc6590c | ||
|
|
55d83d449d | ||
|
|
d8315bf75b | ||
|
|
7890a9f26d | ||
|
|
eb7b7abbee | ||
|
|
1402fa153d | ||
|
|
6be9387a4f | ||
|
|
9aafc2a086 | ||
|
|
57113d1369 | ||
|
|
07f2e2f516 | ||
|
|
f190cfa470 | ||
|
|
5153338a18 | ||
|
|
cb425e83e4 | ||
|
|
d214881326 | ||
|
|
5e4a02fe9e | ||
|
|
859a69e349 | ||
|
|
115ea63ecf | ||
|
|
17a7001ae9 | ||
|
|
9d491024ac | ||
|
|
13839ac94a | ||
|
|
602c3aaa56 | ||
|
|
47c343b9f2 | ||
|
|
73b4980eb6 | ||
|
|
25d9728d2f | ||
|
|
9d727857dc | ||
|
|
5f59607a8a | ||
|
|
b3a23ca711 | ||
|
|
075bb7dac4 | ||
|
|
14b391842b |
No files matched your search
+1
-1
@@ -26,4 +26,4 @@ __pycache__/
|
||||
*.py[cod]
|
||||
|
||||
# Other
|
||||
/VERSION
|
||||
/VERSION.info
|
||||
@@ -1,10 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
source .jenkins.d/util.sh
|
||||
|
||||
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
export CACHE_DIR=${CACHE_DIR:-/tmp}
|
||||
export WAF_JOBS=${WAF_JOBS:-1}
|
||||
[[ $JOB_NAME == *"code-coverage" ]] && export DISABLE_ASAN=yes
|
||||
|
||||
for file in "$DIR"/.jenkins.d/*; do
|
||||
nanos() {
|
||||
# Cannot use date(1) because macOS does not support %N format specifier
|
||||
python3 -c 'import time; print(int(time.time() * 1e9))'
|
||||
}
|
||||
|
||||
for file in .jenkins.d/*; do
|
||||
[[ -f $file && -x $file ]] || continue
|
||||
echo "Run: $file"
|
||||
|
||||
if [[ -n $TRAVIS ]]; then
|
||||
label=$(basename "$file" | sed -E 's/[[:digit:]]+-(.*)\..*/\1/')
|
||||
echo -ne "travis_fold:start:${label}\r"
|
||||
echo -ne "travis_time:start:${label}\r"
|
||||
start=$(nanos)
|
||||
fi
|
||||
|
||||
echo "\$ $file"
|
||||
"$file"
|
||||
|
||||
if [[ -n $TRAVIS ]]; then
|
||||
finish=$(nanos)
|
||||
echo -ne "travis_time:end:${label}:start=${start},finish=${finish},duration=$((finish-start)),event=${label}\r"
|
||||
echo -ne "travis_fold:end:${label}\r"
|
||||
fi
|
||||
done
|
||||
+29
-36
@@ -1,48 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
|
||||
set -x
|
||||
set -ex
|
||||
|
||||
if has OSX $NODE_LABELS; then
|
||||
FORMULAE=(boost openssl pkg-config)
|
||||
brew update
|
||||
if [[ -n $TRAVIS ]]; then
|
||||
# travis images come with a large number of brew packages
|
||||
# pre-installed, don't waste time upgrading all of them
|
||||
for FORMULA in "${FORMULAE[@]}"; do
|
||||
brew outdated $FORMULA || brew upgrade $FORMULA
|
||||
done
|
||||
else
|
||||
brew upgrade
|
||||
if has OSX-10.13 $NODE_LABELS || has OSX-10.14 $NODE_LABELS; then
|
||||
FORMULAE+=(python)
|
||||
fi
|
||||
brew install "${FORMULAE[@]}"
|
||||
brew cleanup
|
||||
fi
|
||||
|
||||
if has Ubuntu $NODE_LABELS; then
|
||||
if [[ -n $TRAVIS ]]; then
|
||||
# Travis images come with a large number of pre-installed
|
||||
# brew packages, don't waste time upgrading all of them
|
||||
brew list --versions "${FORMULAE[@]}" || brew update
|
||||
for FORMULA in "${FORMULAE[@]}"; do
|
||||
brew list --versions "$FORMULA" || brew install "$FORMULA"
|
||||
done
|
||||
# Ensure /usr/local/opt/openssl exists
|
||||
brew reinstall openssl
|
||||
else
|
||||
brew update
|
||||
brew upgrade
|
||||
brew install "${FORMULAE[@]}"
|
||||
brew cleanup
|
||||
fi
|
||||
|
||||
elif has Ubuntu $NODE_LABELS; then
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get -qy install build-essential pkg-config libboost-all-dev \
|
||||
libsqlite3-dev libssl-dev libpcap-dev libsystemd-dev
|
||||
sudo apt-get -qy install build-essential pkg-config python3-minimal \
|
||||
libboost-all-dev libssl-dev libsqlite3-dev \
|
||||
libpcap-dev libsystemd-dev
|
||||
|
||||
if [[ $JOB_NAME == *"code-coverage" ]]; then
|
||||
sudo apt-get -qy install gcovr lcov libgd-perl
|
||||
sudo apt-get -qy install gcovr lcov
|
||||
fi
|
||||
fi
|
||||
|
||||
if has CentOS $NODE_LABELS; then
|
||||
sudo yum -y install yum-utils pkgconfig \
|
||||
openssl-devel libtranslit-icu \
|
||||
python-devel sqlite-devel \
|
||||
libpcap-devel systemd-devel \
|
||||
devtoolset-7-libasan-devel \
|
||||
devtoolset-7-liblsan-devel
|
||||
sudo yum -y groupinstall 'Development Tools'
|
||||
|
||||
svn checkout https://github.com/cmscaltech/sandie-ndn/trunk/packaging/RPMS/x86_64/boost1_58_0
|
||||
pushd boost1_58_0 >/dev/null
|
||||
sudo rpm -Uv --replacepkgs --replacefiles boost-devel* boost-license* libboost_*
|
||||
popd >/dev/null
|
||||
elif has CentOS-8 $NODE_LABELS; then
|
||||
sudo dnf config-manager --enable PowerTools
|
||||
sudo dnf -y install gcc-c++ libasan pkgconf-pkg-config python3 \
|
||||
boost-devel openssl-devel sqlite-devel \
|
||||
libpcap-devel systemd-devel
|
||||
fi
|
||||
+17
-18
@@ -1,12 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
set -ex
|
||||
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
|
||||
set -x
|
||||
|
||||
pushd "${CACHE_DIR:-/tmp}" >/dev/null
|
||||
pushd "$CACHE_DIR" >/dev/null
|
||||
|
||||
INSTALLED_VERSION=
|
||||
if has OSX $NODE_LABELS; then
|
||||
@@ -22,17 +17,15 @@ if [[ -z $INSTALLED_VERSION ]]; then
|
||||
INSTALLED_VERSION=$(git -C ndn-cxx rev-parse HEAD 2>/dev/null || echo NONE)
|
||||
fi
|
||||
|
||||
sudo rm -Rf ndn-cxx-latest
|
||||
|
||||
git clone --depth 1 git://github.com/named-data/ndn-cxx ndn-cxx-latest
|
||||
|
||||
sudo rm -rf ndn-cxx-latest
|
||||
git clone --depth 1 https://github.com/named-data/ndn-cxx.git ndn-cxx-latest
|
||||
LATEST_VERSION=$(git -C ndn-cxx-latest rev-parse HEAD 2>/dev/null || echo UNKNOWN)
|
||||
|
||||
if [[ $INSTALLED_VERSION != $LATEST_VERSION ]]; then
|
||||
sudo rm -Rf ndn-cxx
|
||||
sudo rm -rf ndn-cxx
|
||||
mv ndn-cxx-latest ndn-cxx
|
||||
else
|
||||
sudo rm -Rf ndn-cxx-latest
|
||||
sudo rm -rf ndn-cxx-latest
|
||||
fi
|
||||
|
||||
sudo rm -f /usr/local/bin/ndnsec*
|
||||
@@ -42,15 +35,21 @@ sudo rm -f /usr/local/lib{,64}/pkgconfig/libndn-cxx.pc
|
||||
|
||||
pushd ndn-cxx >/dev/null
|
||||
|
||||
./waf configure --color=yes --enable-shared --disable-static --without-osx-keychain
|
||||
./waf build --color=yes -j${WAF_JOBS:-1}
|
||||
sudo_preserve_env PATH -- ./waf install --color=yes
|
||||
if has CentOS-8 $NODE_LABELS; then
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1721553
|
||||
PCH="--without-pch"
|
||||
fi
|
||||
|
||||
./waf --color=yes configure --disable-static --enable-shared --without-osx-keychain $PCH
|
||||
./waf --color=yes build -j$WAF_JOBS
|
||||
sudo_preserve_env PATH -- ./waf --color=yes install
|
||||
|
||||
popd >/dev/null
|
||||
popd >/dev/null
|
||||
|
||||
if has CentOS-8 $NODE_LABELS; then
|
||||
sudo tee /etc/ld.so.conf.d/ndn.conf >/dev/null <<< /usr/local/lib64
|
||||
fi
|
||||
if has Linux $NODE_LABELS; then
|
||||
sudo ldconfig
|
||||
elif has FreeBSD10 $NODE_LABELS; then
|
||||
sudo ldconfig -m
|
||||
fi
|
||||
+29
-33
@@ -1,45 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
set -ex
|
||||
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
|
||||
set -x
|
||||
|
||||
git submodule init
|
||||
git submodule sync
|
||||
git submodule update
|
||||
git submodule update --init
|
||||
|
||||
if [[ $JOB_NAME == *"code-coverage" ]]; then
|
||||
COVERAGE="--with-coverage"
|
||||
elif [[ -z $DISABLE_ASAN ]]; then
|
||||
if [[ -z $DISABLE_ASAN ]]; then
|
||||
ASAN="--with-sanitizer=address"
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
sudo_preserve_env PATH -- ./waf --color=yes distclean
|
||||
|
||||
if [[ $JOB_NAME != *"code-coverage" && $JOB_NAME != *"limited-build" ]]; then
|
||||
# Configure/build in optimized mode with tests
|
||||
./waf --color=yes configure --with-tests
|
||||
./waf --color=yes build -j${WAF_JOBS:-1}
|
||||
|
||||
# Cleanup
|
||||
sudo_preserve_env PATH -- ./waf --color=yes distclean
|
||||
|
||||
# Configure/build in optimized mode without tests, but with "other tests"
|
||||
./waf --color=yes configure --with-other-tests
|
||||
./waf --color=yes build -j${WAF_JOBS:-1}
|
||||
|
||||
# Cleanup
|
||||
sudo_preserve_env PATH -- ./waf --color=yes distclean
|
||||
if [[ $JOB_NAME == *"code-coverage" ]]; then
|
||||
COVERAGE="--with-coverage"
|
||||
fi
|
||||
if has CentOS-8 $NODE_LABELS; then
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=1721553
|
||||
PCH="--without-pch"
|
||||
fi
|
||||
|
||||
# Configure/build in debug mode with tests and without precompiled headers
|
||||
./waf --color=yes configure --debug --with-tests --without-pch $ASAN $COVERAGE
|
||||
./waf --color=yes build -j${WAF_JOBS:-1}
|
||||
if [[ $JOB_NAME != *"code-coverage" && $JOB_NAME != *"limited-build" ]]; then
|
||||
# Build in release mode with tests and without precompiled headers
|
||||
./waf --color=yes configure --with-tests --without-pch
|
||||
./waf --color=yes build -j$WAF_JOBS
|
||||
|
||||
# (tests will be run against debug version)
|
||||
# Cleanup
|
||||
./waf --color=yes distclean
|
||||
|
||||
# Build in release mode without tests, but with "other tests"
|
||||
./waf --color=yes configure --with-other-tests $PCH
|
||||
./waf --color=yes build -j$WAF_JOBS
|
||||
|
||||
# Cleanup
|
||||
./waf --color=yes distclean
|
||||
fi
|
||||
|
||||
# Build in debug mode with tests
|
||||
./waf --color=yes configure --debug --with-tests $ASAN $COVERAGE $PCH
|
||||
./waf --color=yes build -j$WAF_JOBS
|
||||
|
||||
# (tests will be run against the debug version)
|
||||
|
||||
# Install
|
||||
sudo_preserve_env PATH -- ./waf --color=yes install
|
||||
+15
-29
@@ -1,13 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
|
||||
set -x
|
||||
set -ex
|
||||
|
||||
# Prepare environment
|
||||
rm -Rf ~/.ndn
|
||||
rm -rf ~/.ndn
|
||||
|
||||
if has OSX $NODE_LABELS; then
|
||||
security unlock-keychain -p named-data
|
||||
@@ -15,34 +10,25 @@ fi
|
||||
|
||||
ndnsec-keygen "/tmp/jenkins/$NODE_NAME" | ndnsec-install-cert -
|
||||
|
||||
BOOST_VERSION=$(python -c "import sys; sys.path.append('build/c4che'); import _cache; print(_cache.BOOST_VERSION_NUMBER);")
|
||||
|
||||
ut_log_args() {
|
||||
if (( BOOST_VERSION >= 106200 )); then
|
||||
echo --logger=HRF,test_suite,stdout:XML,all,build/xunit-${1:-report}.xml
|
||||
else
|
||||
if [[ -n $XUNIT ]]; then
|
||||
echo --log_level=all $( (( BOOST_VERSION >= 106000 )) && echo -- ) \
|
||||
--log_format2=XML --log_sink2=build/xunit-${1:-report}.xml
|
||||
else
|
||||
echo --log_level=test_suite
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# https://github.com/google/sanitizers/wiki/AddressSanitizerFlags
|
||||
ASAN_OPTIONS="color=always"
|
||||
ASAN_OPTIONS+=":detect_leaks=false"
|
||||
ASAN_OPTIONS+=":detect_stack_use_after_return=true"
|
||||
ASAN_OPTIONS+=":check_initialization_order=true"
|
||||
ASAN_OPTIONS+=":strict_init_order=true"
|
||||
ASAN_OPTIONS+=":detect_invalid_pointer_pairs=1"
|
||||
ASAN_OPTIONS+=":detect_container_overflow=false"
|
||||
ASAN_OPTIONS+=":strict_string_checks=true"
|
||||
ASAN_OPTIONS+=":check_initialization_order=1"
|
||||
ASAN_OPTIONS+=":detect_stack_use_after_return=1"
|
||||
ASAN_OPTIONS+=":strict_init_order=1"
|
||||
ASAN_OPTIONS+=":strict_string_checks=1"
|
||||
ASAN_OPTIONS+=":detect_invalid_pointer_pairs=2"
|
||||
ASAN_OPTIONS+=":detect_container_overflow=0"
|
||||
ASAN_OPTIONS+=":detect_leaks=0"
|
||||
ASAN_OPTIONS+=":strip_path_prefix=${PWD}/"
|
||||
export ASAN_OPTIONS
|
||||
|
||||
export BOOST_TEST_BUILD_INFO=1
|
||||
export BOOST_TEST_COLOR_OUTPUT=1
|
||||
export BOOST_TEST_DETECT_MEMORY_LEAK=0
|
||||
|
||||
ut_log_args() {
|
||||
echo --logger=HRF,test_suite,stdout:XML,all,build/xunit-log${1:+-$1}.xml
|
||||
}
|
||||
|
||||
# First run all tests as unprivileged user
|
||||
./build/unit-tests-core $(ut_log_args core)
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
source "$JDIR"/util.sh
|
||||
|
||||
set -x
|
||||
set -ex
|
||||
|
||||
if [[ $JOB_NAME == *"code-coverage" ]]; then
|
||||
gcovr --object-directory=build \
|
||||
@@ -33,7 +28,6 @@ if [[ $JOB_NAME == *"code-coverage" ]]; then
|
||||
|
||||
genhtml --branch-coverage \
|
||||
--demangle-cpp \
|
||||
--frames \
|
||||
--legend \
|
||||
--output-directory build/coverage \
|
||||
--title "NFD unit tests" \
|
||||
|
||||
+16
-24
@@ -1,36 +1,28 @@
|
||||
CONTINUOUS INTEGRATION SCRIPTS
|
||||
==============================
|
||||
# CONTINUOUS INTEGRATION SCRIPTS
|
||||
|
||||
Environment Variables Used in Build Scripts
|
||||
-------------------------------------------
|
||||
## Environment Variables Used in Build Scripts
|
||||
|
||||
- `NODE_LABELS`: the variable defines a list of OS properties. The set values are used by the
|
||||
build scripts to select proper behavior for different OS.
|
||||
- `NODE_LABELS`: space-separated list of platform properties. The included values are used by
|
||||
the build scripts to select the proper behavior for different operating systems and versions.
|
||||
|
||||
The list should include at least `[OS_TYPE]`, `[DISTRO_TYPE]`, and `[DISTRO_VERSION]`.
|
||||
The list should normally contain `[OS_TYPE]`, `[DISTRO_TYPE]`, and `[DISTRO_VERSION]`.
|
||||
|
||||
Possible values for Linux:
|
||||
Example values:
|
||||
|
||||
* `[OS_TYPE]`: `Linux`
|
||||
* `[DISTRO_TYPE]`: `Ubuntu`
|
||||
* `[DISTRO_VERSION]`: `Ubuntu-16.04`, `Ubuntu-18.04`
|
||||
- `[OS_TYPE]`: `Linux`, `OSX`
|
||||
- `[DISTRO_TYPE]`: `Ubuntu`, `CentOS`
|
||||
- `[DISTRO_VERSION]`: `Ubuntu-16.04`, `Ubuntu-18.04`, `CentOS-8`, `OSX-10.14`, `OSX-10.15`
|
||||
|
||||
Possible values for OS X / macOS:
|
||||
|
||||
* `[OS_TYPE]`: `OSX`
|
||||
* `[DISTRO_TYPE]`: `OSX` (can be absent)
|
||||
* `[DISTRO_VERSION]`: `OSX-10.11`, `OSX-10.12`, `OSX-10.13`
|
||||
|
||||
- `JOB_NAME`: optional variable to define type of the job. Depending on the defined job type,
|
||||
- `JOB_NAME`: optional variable that defines the type of build job. Depending on the job type,
|
||||
the build scripts can perform different tasks.
|
||||
|
||||
Possible values:
|
||||
|
||||
* empty: default build process
|
||||
* `code-coverage` (Ubuntu Linux is assumed): debug build with tests and code coverage analysis
|
||||
* `limited-build`: only a single debug build with tests
|
||||
- empty: default build task
|
||||
- `code-coverage`: debug build with tests and code coverage analysis (Ubuntu Linux is assumed)
|
||||
- `limited-build`: only a single debug build with tests
|
||||
|
||||
- `CACHE_DIR`: the variable defines a path to folder containing cached files from previous builds,
|
||||
e.g., a compiled version of ndn-cxx library. If not set, `/tmp` is used.
|
||||
- `CACHE_DIR`: directory containing cached files from previous builds, e.g., a compiled version
|
||||
of ndn-cxx. If not set, `/tmp` is used.
|
||||
|
||||
- `WAF_JOBS`: number of parallel build jobs used by waf, defaults to 1.
|
||||
- `WAF_JOBS`: number of parallel build threads used by waf, defaults to 1.
|
||||
@@ -16,6 +16,7 @@ has() {
|
||||
set ${saved_xtrace}
|
||||
return ${ret}
|
||||
}
|
||||
export -f has
|
||||
|
||||
sudo_preserve_env() {
|
||||
local saved_xtrace
|
||||
@@ -35,3 +36,4 @@ sudo_preserve_env() {
|
||||
set ${saved_xtrace}
|
||||
sudo env "${vars[@]}" "$@"
|
||||
}
|
||||
export -f sudo_preserve_env
|
||||
+87
-70
@@ -1,98 +1,115 @@
|
||||
version: ~> 1.0
|
||||
language: cpp
|
||||
dist: xenial
|
||||
os: linux
|
||||
dist: bionic
|
||||
|
||||
arch:
|
||||
- amd64
|
||||
#- arm64 # Too slow, exceeds time limit
|
||||
#- ppc64le # Fails transport tests
|
||||
#- s390x # Fails transport tests
|
||||
|
||||
env:
|
||||
global:
|
||||
- JOB_NAME=limited-build
|
||||
- WAF_JOBS=2
|
||||
- COMPILER=g++-7
|
||||
- COMPILER=g++-9
|
||||
- COMPILER=clang++-6.0
|
||||
- COMPILER=clang++-9
|
||||
|
||||
matrix:
|
||||
jobs:
|
||||
include:
|
||||
# Linux/gcc
|
||||
# https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test/+packages
|
||||
- os: linux
|
||||
env: COMPILER=g++-5
|
||||
- os: linux
|
||||
env: COMPILER=g++-6
|
||||
- os: linux
|
||||
env: COMPILER=g++-7
|
||||
- os: linux
|
||||
env: COMPILER=g++-8
|
||||
# Linux
|
||||
- env: COMPILER=g++-5
|
||||
- env: COMPILER=g++-6
|
||||
- env: COMPILER=g++-8
|
||||
- env: COMPILER=clang++-4.0
|
||||
- env: COMPILER=clang++-5.0
|
||||
- env: COMPILER=clang++-7
|
||||
- env: COMPILER=clang++-8
|
||||
- env: COMPILER=clang++-10
|
||||
- env: COMPILER=clang++-11
|
||||
- env: COMPILER=clang++-12
|
||||
|
||||
# Linux/clang
|
||||
# https://apt.llvm.org/
|
||||
- os: linux
|
||||
env: COMPILER=clang++-3.8
|
||||
- os: linux
|
||||
env: COMPILER=clang++-3.9
|
||||
- os: linux
|
||||
env: COMPILER=clang++-4.0
|
||||
- os: linux
|
||||
env: COMPILER=clang++-5.0
|
||||
- os: linux
|
||||
env: COMPILER=clang++-6.0
|
||||
# temporarily disable AddressSanitizer on clang-7 and later
|
||||
# due to https://bugs.llvm.org/show_bug.cgi?id=40808
|
||||
- os: linux
|
||||
env: COMPILER=clang++-7 DISABLE_ASAN=yes
|
||||
- os: linux
|
||||
env: COMPILER=clang++-8 DISABLE_ASAN=yes
|
||||
- os: linux
|
||||
env: COMPILER=clang++-9 DISABLE_ASAN=yes
|
||||
|
||||
# macOS/clang
|
||||
# https://docs.travis-ci.com/user/reference/osx/#macos-version
|
||||
- os: osx
|
||||
osx_image: xcode8.3
|
||||
env: OSX_VERSION=10.12
|
||||
- os: osx
|
||||
osx_image: xcode9.2
|
||||
env: OSX_VERSION=10.12
|
||||
# macOS
|
||||
- os: osx
|
||||
osx_image: xcode9.4
|
||||
env: OSX_VERSION=10.13
|
||||
env: # default compiler
|
||||
- os: osx
|
||||
osx_image: xcode10.1
|
||||
env: OSX_VERSION=10.13
|
||||
env: # default compiler
|
||||
- os: osx
|
||||
osx_image: xcode10.2
|
||||
env: OSX_VERSION=10.14
|
||||
osx_image: xcode10.3
|
||||
env: # default compiler
|
||||
- os: osx
|
||||
osx_image: xcode11.3
|
||||
env: # default compiler
|
||||
- os: osx
|
||||
osx_image: xcode11.6
|
||||
env: # default compiler
|
||||
- os: osx
|
||||
osx_image: xcode12
|
||||
env: # default compiler
|
||||
|
||||
allow_failures:
|
||||
- env: COMPILER=clang++-9 DISABLE_ASAN=yes
|
||||
- env: COMPILER=g++-5
|
||||
- env: COMPILER=g++-6
|
||||
- env: COMPILER=clang++-4.0
|
||||
- env: COMPILER=clang++-12
|
||||
|
||||
fast_finish: true
|
||||
|
||||
install: |
|
||||
before_install:
|
||||
- |
|
||||
: Adding apt repositories
|
||||
case ${COMPILER} in
|
||||
g++-5)
|
||||
;;
|
||||
g++-*)
|
||||
g++-9)
|
||||
# https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test/+packages
|
||||
travis_retry sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
travis_retry sudo apt-get -qq update
|
||||
travis_retry sudo apt-get -qy install "${COMPILER}"
|
||||
;;
|
||||
clang++-*)
|
||||
CLANG_VERSION=${COMPILER/clang++}
|
||||
if [[ ${CLANG_VERSION} != "-3."* ]]; then
|
||||
travis_retry wget -nv -O - "https://apt.llvm.org/llvm-snapshot.gpg.key" | sudo apt-key add -
|
||||
travis_retry sudo add-apt-repository -y "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial${CLANG_VERSION/-9} main"
|
||||
fi
|
||||
clang++-1?)
|
||||
# https://apt.llvm.org/
|
||||
LLVM_REPO=${COMPILER/clang++/llvm-toolchain-${TRAVIS_DIST}}
|
||||
travis_retry wget -nv -O - "https://apt.llvm.org/llvm-snapshot.gpg.key" | sudo apt-key add -
|
||||
travis_retry sudo add-apt-repository -y "deb http://apt.llvm.org/${TRAVIS_DIST}/ ${LLVM_REPO%-12} main"
|
||||
travis_retry sudo apt-get -qq update
|
||||
travis_retry sudo apt-get -qy install "clang${CLANG_VERSION}"
|
||||
;;
|
||||
esac
|
||||
|
||||
install:
|
||||
- |
|
||||
: Installing C++ compiler
|
||||
if [[ -n ${COMPILER} ]]; then
|
||||
travis_retry sudo apt-get -qy install ${COMPILER/clang++/clang}
|
||||
fi
|
||||
|
||||
before_script:
|
||||
- if [[ ${TRAVIS_OS_NAME} == linux ]]; then export NODE_LABELS="Linux Ubuntu Ubuntu-16.04"; fi
|
||||
- if [[ ${TRAVIS_OS_NAME} == osx ]]; then export NODE_LABELS="OSX OSX-${OSX_VERSION}"; fi
|
||||
- if [[ ${OSX_VERSION} == 10.12 ]]; then brew update; fi
|
||||
# workaround for https://github.com/Homebrew/homebrew-core/issues/26358
|
||||
- if [[ ${OSX_VERSION} == 10.12 ]]; then brew outdated python || brew upgrade python; fi
|
||||
# workaround for https://github.com/travis-ci/travis-ci/issues/6688
|
||||
- if [[ ${OSX_VERSION} == 10.12 ]]; then /usr/bin/yes | pip2 uninstall numpy || true; fi
|
||||
- if [[ -n ${COMPILER} ]]; then export CXX=${COMPILER}; fi
|
||||
- |
|
||||
: Setting environment variables
|
||||
if [[ -n ${COMPILER} ]]; then
|
||||
export CXX=${COMPILER}
|
||||
fi
|
||||
case ${TRAVIS_OS_NAME} in
|
||||
linux) export NODE_LABELS="Linux Ubuntu Ubuntu-18.04" ;;
|
||||
osx) export NODE_LABELS="OSX OSX-$(sw_vers -productVersion | cut -d . -f -2)" ;;
|
||||
esac
|
||||
export JOB_NAME=limited-build
|
||||
export WAF_JOBS=2
|
||||
- |
|
||||
: Enabling workarounds
|
||||
case "${TRAVIS_CPU_ARCH},${COMPILER}" in
|
||||
ppc64le,g++-7)
|
||||
# AddressSanitizer does not seem to be working
|
||||
export DISABLE_ASAN=yes
|
||||
;;
|
||||
*,clang++-8)
|
||||
# https://bugs.llvm.org/show_bug.cgi?id=40808
|
||||
export DISABLE_ASAN=yes
|
||||
;;
|
||||
esac
|
||||
if [[ ${TRAVIS_OS_NAME} == linux ]]; then
|
||||
sudo sysctl -e -w net.ipv6.conf.all.disable_ipv6=0
|
||||
fi
|
||||
- ${CXX:-c++} --version
|
||||
- python --version
|
||||
|
||||
script:
|
||||
- ./.jenkins
|
||||
@@ -1,30 +0,0 @@
|
||||
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
"""
|
||||
Copyright (c) 2014-2016, Regents of the University of California,
|
||||
Arizona Board of Regents,
|
||||
Colorado State University,
|
||||
University Pierre & Marie Curie, Sorbonne University,
|
||||
Washington University in St. Louis,
|
||||
Beijing Institute of Technology,
|
||||
The University of Memphis.
|
||||
|
||||
This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
|
||||
NFD is free software: you can redistribute it and/or modify it under the terms
|
||||
of the GNU General Public License as published by the Free Software Foundation,
|
||||
either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from waflib.Configure import conf
|
||||
|
||||
def configure(conf):
|
||||
pass
|
||||
@@ -1,10 +1,11 @@
|
||||
# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
|
||||
|
||||
import platform
|
||||
from waflib import Configure, Logs, Utils
|
||||
|
||||
def options(opt):
|
||||
opt.add_option('--debug', '--with-debug', action='store_true', default=False,
|
||||
help='Compile in debugging mode with minimal optimizations (-O0 or -Og)')
|
||||
help='Compile in debugging mode with minimal optimizations (-Og)')
|
||||
|
||||
def configure(conf):
|
||||
conf.start_msg('Checking C++ compiler version')
|
||||
@@ -17,15 +18,21 @@ def configure(conf):
|
||||
if cxx == 'gcc':
|
||||
if ccver < (5, 3, 0):
|
||||
errmsg = ('The version of gcc you are using is too old.\n'
|
||||
'The minimum supported gcc version is 5.3.0.')
|
||||
'The minimum supported gcc version is 7.4.0.')
|
||||
elif ccver < (7, 4, 0):
|
||||
warnmsg = ('Using a version of gcc older than 7.4.0 is not '
|
||||
'officially supported and may result in build failures.')
|
||||
conf.flags = GccFlags()
|
||||
elif cxx == 'clang':
|
||||
if ccver < (3, 6, 0):
|
||||
if Utils.unversioned_sys_platform() == 'darwin' and ccver < (9, 0, 0):
|
||||
errmsg = ('The version of Xcode you are using is too old.\n'
|
||||
'The minimum supported Xcode version is 9.0.')
|
||||
elif ccver < (4, 0, 0):
|
||||
errmsg = ('The version of clang you are using is too old.\n'
|
||||
'The minimum supported clang version is 3.6.0.')
|
||||
'The minimum supported clang version is 4.0.')
|
||||
conf.flags = ClangFlags()
|
||||
else:
|
||||
warnmsg = 'Note: %s compiler is unsupported' % cxx
|
||||
warnmsg = '%s compiler is unsupported' % cxx
|
||||
conf.flags = CompilerFlags()
|
||||
|
||||
if errmsg:
|
||||
@@ -33,7 +40,7 @@ def configure(conf):
|
||||
conf.fatal(errmsg)
|
||||
elif warnmsg:
|
||||
conf.end_msg(ccverstr, color='YELLOW')
|
||||
Logs.warn(warnmsg)
|
||||
Logs.warn('WARNING: ' + warnmsg)
|
||||
else:
|
||||
conf.end_msg(ccverstr)
|
||||
|
||||
@@ -137,13 +144,14 @@ class GccBasicFlags(CompilerFlags):
|
||||
|
||||
def getDebugFlags(self, conf):
|
||||
flags = super(GccBasicFlags, self).getDebugFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-O0',
|
||||
'-Og', # gcc >= 4.8, clang >= 4.0
|
||||
flags['CXXFLAGS'] += ['-Og',
|
||||
'-g3',
|
||||
'-pedantic',
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
'-Werror',
|
||||
'-Wcatch-value=2',
|
||||
'-Wextra-semi',
|
||||
'-Wnon-virtual-dtor',
|
||||
'-Wno-error=deprecated-declarations', # Bug #3795
|
||||
'-Wno-error=maybe-uninitialized', # Bug #1615
|
||||
@@ -159,6 +167,8 @@ class GccBasicFlags(CompilerFlags):
|
||||
'-pedantic',
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
'-Wcatch-value=2',
|
||||
'-Wextra-semi',
|
||||
'-Wnon-virtual-dtor',
|
||||
'-Wno-unused-parameter',
|
||||
]
|
||||
@@ -168,49 +178,50 @@ class GccBasicFlags(CompilerFlags):
|
||||
class GccFlags(GccBasicFlags):
|
||||
def getDebugFlags(self, conf):
|
||||
flags = super(GccFlags, self).getDebugFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-fdiagnostics-color']
|
||||
flags['CXXFLAGS'] += ['-fdiagnostics-color',
|
||||
'-Wredundant-tags',
|
||||
]
|
||||
if platform.machine() == 'armv7l' and self.getCompilerVersion(conf) >= (7, 1, 0):
|
||||
flags['CXXFLAGS'] += ['-Wno-psabi'] # Bug #5106
|
||||
return flags
|
||||
|
||||
def getOptimizedFlags(self, conf):
|
||||
flags = super(GccFlags, self).getOptimizedFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-fdiagnostics-color']
|
||||
flags['CXXFLAGS'] += ['-fdiagnostics-color',
|
||||
'-Wredundant-tags',
|
||||
]
|
||||
if platform.machine() == 'armv7l' and self.getCompilerVersion(conf) >= (7, 1, 0):
|
||||
flags['CXXFLAGS'] += ['-Wno-psabi'] # Bug #5106
|
||||
return flags
|
||||
|
||||
class ClangFlags(GccBasicFlags):
|
||||
def getGeneralFlags(self, conf):
|
||||
flags = super(ClangFlags, self).getGeneralFlags(conf)
|
||||
if Utils.unversioned_sys_platform() == 'darwin' and self.getCompilerVersion(conf) >= (9, 0, 0):
|
||||
if Utils.unversioned_sys_platform() == 'darwin':
|
||||
# Bug #4296
|
||||
flags['CXXFLAGS'] += [['-isystem', '/usr/local/include'], # for Homebrew
|
||||
['-isystem', '/opt/local/include']] # for MacPorts
|
||||
if Utils.unversioned_sys_platform() == 'freebsd':
|
||||
flags['CXXFLAGS'] += [['-isystem', '/usr/local/include']] # Bug #4790
|
||||
elif Utils.unversioned_sys_platform() == 'freebsd':
|
||||
# Bug #4790
|
||||
flags['CXXFLAGS'] += [['-isystem', '/usr/local/include']]
|
||||
return flags
|
||||
|
||||
def getDebugFlags(self, conf):
|
||||
flags = super(ClangFlags, self).getDebugFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-fcolor-diagnostics',
|
||||
'-Wextra-semi',
|
||||
'-Wundefined-func-template',
|
||||
'-Wno-unused-local-typedef', # Bugs #2657 and #3209
|
||||
]
|
||||
version = self.getCompilerVersion(conf)
|
||||
if version < (3, 9, 0) or (Utils.unversioned_sys_platform() == 'darwin' and version < (8, 1, 0)):
|
||||
flags['CXXFLAGS'] += ['-Wno-unknown-pragmas']
|
||||
if version < (6, 0, 0):
|
||||
if self.getCompilerVersion(conf) < (6, 0, 0):
|
||||
flags['CXXFLAGS'] += ['-Wno-missing-braces'] # Bug #4721
|
||||
return flags
|
||||
|
||||
def getOptimizedFlags(self, conf):
|
||||
flags = super(ClangFlags, self).getOptimizedFlags(conf)
|
||||
flags['CXXFLAGS'] += ['-fcolor-diagnostics',
|
||||
'-Wextra-semi',
|
||||
'-Wundefined-func-template',
|
||||
'-Wno-unused-local-typedef', # Bugs #2657 and #3209
|
||||
]
|
||||
version = self.getCompilerVersion(conf)
|
||||
if version < (3, 9, 0) or (Utils.unversioned_sys_platform() == 'darwin' and version < (8, 1, 0)):
|
||||
flags['CXXFLAGS'] += ['-Wno-unknown-pragmas']
|
||||
if version < (6, 0, 0):
|
||||
if self.getCompilerVersion(conf) < (6, 0, 0):
|
||||
flags['CXXFLAGS'] += ['-Wno-missing-braces'] # Bug #4721
|
||||
return flags
|
||||
+58
-78
@@ -1,82 +1,62 @@
|
||||
NFD Authors
|
||||
===========
|
||||
# NFD Authors
|
||||
|
||||
NFD is an open source project started in late 2013, includes contributions
|
||||
from many people around the world, and open for new contributions from new
|
||||
volunteers.
|
||||
The following lists maintainers, primary developers, and all much-appreciated contributors to NFD in alphabetic order.
|
||||
The specific contributions of individual authors can be obtained from the git history of the [official NFD repository](https://github.com/named-data/NFD).
|
||||
If you would like to become a contributor to the official repository, please follow the recommendations in https://github.com/named-data/.github/blob/master/CONTRIBUTING.md.
|
||||
|
||||
* Jerald Paul Abraham <https://cs.arizona.edu/~jeraldabraham>
|
||||
* ***(Maintainer)*** Alexander Afanasyev <https://users.cs.fiu.edu/~afanasyev>
|
||||
* Syed Obai Amin <http://obaidamin.weebly.com>
|
||||
* Hila Ben Abraham <https://sites.wustl.edu/hbabraham>
|
||||
* Muktadir R Chowdhury <https://github.com/alvyC>
|
||||
* Tai-Lin Chu <https://www.linkedin.com/pub/tai-lin-chu/55/5b2/669>
|
||||
* Stephanie DiBenedetto
|
||||
* Saurab Dulal <https://dulalsaurab.github.io>
|
||||
* Chengyu Fan <https://github.com/chengyu>
|
||||
* Ashlesh Gawande <https://www.linkedin.com/in/agawande>
|
||||
* Chavoosh Ghasemi <https://chavoosh.github.io>
|
||||
* Mathias Gibbens <https://calenhad.com>
|
||||
* Nick Gordon <https://github.com/gorgonical>
|
||||
* Giulio Grassi <https://www.lip6.fr/actualite/personnes-fiche.php?ident=D1461>
|
||||
* Yi Huang <https://www.linkedin.com/in/yihuang1991>
|
||||
* Jongseok Lee <https://github.com/imwhiz>
|
||||
* Spencer Lee <https://www.linkedin.com/in/spenlee>
|
||||
* Vince Lehman <http://vslehman.com>
|
||||
* Yanbiao Li <https://www.linkedin.com/pub/yanbiao-li/24/7a1/4ba>
|
||||
* Teng Liang <https://cs.arizona.edu/~philoliang>
|
||||
* Weiwei Liu <https://www.linkedin.com/in/weiweiliu10>
|
||||
* Spyridon Mastorakis <https://sites.google.com/site/spyridonmastorakis>
|
||||
* Ernest McCracken <https://github.com/emccrckn>
|
||||
* Ilya Moiseenko <https://www.linkedin.com/in/ilya-moiseenko-52884317>
|
||||
* Eric Newberry <https://ericnewberry.com>
|
||||
* Ju Pan <https://cs-jupan.com>
|
||||
* João Pereira <http://website.jpereira.co.uk>
|
||||
* Davide Pesavento <https://github.com/Pesa>
|
||||
* Felix Rabe <https://twitter.com/felixrabe>
|
||||
* Md Ashiqur Rahman <https://ashiqrahman.com>
|
||||
* Matteo Sammarco <https://www.linkedin.com/in/matteo-sammarco-9b544530>
|
||||
* Niv Sardi <http://core.evilgiggle.com>
|
||||
* Klaus Schneider <https://cs.arizona.edu/~klaus>
|
||||
* Wentao Shang <https://irl.cs.ucla.edu/~wentao>
|
||||
* Susmit Shannigrahi <https://susm.it>
|
||||
* ***(Former Maintainer)*** Junxiao Shi <https://cs.arizona.edu/~shijunxiao>
|
||||
* Yukai Tu <https://irl.cs.ucla.edu/~yukai>
|
||||
* Sebastian Wölke <https://inet.haw-hamburg.de/members/alumni-1/sebastian-woelke>
|
||||
* Yumin Xia <https://github.com/Stumble>
|
||||
* Yingdi Yu <https://irl.cs.ucla.edu/~yingdi>
|
||||
* Haowei Yuan <http://www.cse.wustl.edu/~yuanh>
|
||||
* Hang Zhang <http://netlab.bit.edu.cn/z_hang>
|
||||
* Minsheng Zhang <https://github.com/mzhang4>
|
||||
* Zhiyi Zhang <https://zhiyi-zhang.com>
|
||||
* Qi Zhao <https://web.cs.ucla.edu/~qi.zhao>
|
||||
* Wenkai Zheng <https://github.com/wenkaizheng>
|
||||
|
||||
## Project technical leads:
|
||||
## Technical Advisors
|
||||
|
||||
* Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
|
||||
* Junxiao Shi <http://www.cs.arizona.edu/people/shijunxiao/>
|
||||
|
||||
|
||||
## Technical advisors:
|
||||
|
||||
* Beichuan Zhang <http://www.cs.arizona.edu/~bzhang/>
|
||||
* Lixia Zhang <http://www.cs.ucla.edu/~lixia/>
|
||||
|
||||
|
||||
## Main project authors and their affiliations:
|
||||
|
||||
* University of California, Los Angeles
|
||||
|
||||
* Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
|
||||
* Ilya Moiseenko <http://ilyamoiseenko.com/>
|
||||
* Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/web/index.html>
|
||||
* Wentao Shang <http://irl.cs.ucla.edu/~wentao/>
|
||||
* Lixia Zhang <http://www.cs.ucla.edu/~lixia/>
|
||||
|
||||
* The University of Arizona
|
||||
|
||||
* Junxiao Shi <http://www.cs.arizona.edu/people/shijunxiao/>
|
||||
* Yi Huang <ethanhuang1991@gmail.com>
|
||||
* Jerald Paul Abraham <http://www.cs.arizona.edu/people/jeraldabraham/>
|
||||
* Beichuan Zhang <http://www.cs.arizona.edu/~bzhang/>
|
||||
|
||||
* Colorado State University
|
||||
|
||||
* Steve DiBenedetto <http://www.cs.colostate.edu/~dibenede/>
|
||||
* Chengyu Fan <chengyu@cs.colostate.edu>
|
||||
* Christos Papadopoulos <http://www.cs.colostate.edu/~christos/>
|
||||
|
||||
* University Pierre & Marie Curie, Sorbonne University
|
||||
|
||||
* Davide Pesavento <https://www.linkedin.com/in/davidepesavento>
|
||||
* Giulio Grassi <http://www.lip6.fr/actualite/personnes-fiche.php?ident=D1461>
|
||||
* Giovanni Pau <http://www.cs.ucla.edu/~gpau/Giovanni_Paus_Home_Page/Home.html>
|
||||
|
||||
* Beijing Institute of Technology
|
||||
|
||||
* Hang Zhang <http://netlab.bit.edu.cn/z_hang>
|
||||
* Tian Song <http://cs.bit.edu.cn/songtian>
|
||||
|
||||
* Washington University in St. Louis
|
||||
|
||||
* Haowei Yuan <http://www.cse.wustl.edu/~yuanh/>
|
||||
* Hila Ben Abraham <http://research.engineering.wustl.edu/~abrahamh/>
|
||||
* Patrick Crowley <http://www.arl.wustl.edu/~pcrowley/>
|
||||
|
||||
* The University of Memphis
|
||||
|
||||
* Syed Obaid Amin <http://obaidamin.weebly.com/>
|
||||
* Vince Lehman <vslehman@memphis.edu>
|
||||
* Minsheng Zhang <mzhang4@memphis.edu>
|
||||
* Lan Wang <http://www.cs.memphis.edu/~lanwang/>
|
||||
|
||||
## Project contributors
|
||||
|
||||
The following is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS,
|
||||
people who have reported bugs, submitted patches, and implemented new features
|
||||
in the library:
|
||||
|
||||
* Tai-Lin Chu <https://www.linkedin.com/pub/tai-lin-chu/55/5b2/669>
|
||||
* Spyridon Mastorakis <http://cs.ucla.edu/~mastorakis/>
|
||||
* Eric Newberry <http://cs.arizona.edu/~enewberry/>
|
||||
* Yukai Tu <tuyukai1994@gmail.com>
|
||||
* João Pereira <http://website.jpereira.co.uk>
|
||||
* Mathias Gibbens <gibmat@cs.arizona.edu>
|
||||
* Yanbiao Li <https://www.linkedin.com/pub/yanbiao-li/24/7a1/4ba>
|
||||
* Weiwei Liu <https://www.linkedin.com/in/weiweiliu10>
|
||||
* Spencer Lee <https://www.linkedin.com/in/spenlee>
|
||||
* Patrick Crowley <https://www.arl.wustl.edu/~pcrowley>
|
||||
* Christos Papadopoulos <https://www.cs.colostate.edu/~christos>
|
||||
* Giovanni Pau <http://www.cs.ucla.edu/~gpau/Giovanni_Paus_Home_Page/Home.html>
|
||||
* Tian Song <http://www.bit-netlab.org/songtian>
|
||||
* Lan Wang <http://www.cs.memphis.edu/~lanwang>
|
||||
* Beichuan Zhang <https://cs.arizona.edu/~bzhang>
|
||||
* Lixia Zhang <https://cs.ucla.edu/~lixia>
|
||||
+5
-6
@@ -1,7 +1,7 @@
|
||||
# Notes for NFD developers
|
||||
|
||||
If you are new to the NDN software community, please read the
|
||||
[Contributor's Guide](https://github.com/named-data/NFD/blob/master/CONTRIBUTING.md).
|
||||
[Contributor's Guide](https://github.com/named-data/.github/blob/master/CONTRIBUTING.md).
|
||||
|
||||
## Code style
|
||||
|
||||
@@ -61,12 +61,12 @@ The simplest way to run the tests is to launch the compiled binary without any p
|
||||
# Run NFD RIB management tests
|
||||
./build/unit-tests-rib
|
||||
|
||||
[Boost.Test framework](https://www.boost.org/doc/libs/1_58_0/libs/test/doc/html/index.html)
|
||||
The [Boost.Test framework](https://www.boost.org/doc/libs/1_65_1/libs/test/doc/html/index.html)
|
||||
is very flexible and allows a number of run-time customization of what tests should be run.
|
||||
For example, it is possible to choose to run only a specific test suite, only a specific
|
||||
test case within a suite, or specific test cases within specific test suites:
|
||||
|
||||
# Run only TCP Face test suite of NFD daemon tests (see tests/daemon/face/tcp.cpp)
|
||||
# Run only the TCP Face test suite of NFD daemon tests
|
||||
./build/unit-tests-daemon -t FaceTcp
|
||||
|
||||
# Run only test case EndToEnd4 from the same test suite
|
||||
@@ -93,6 +93,5 @@ or `-p` to show a progress bar:
|
||||
./build/unit-tests-core -p
|
||||
|
||||
There are many more command line options available, information about which can be obtained
|
||||
either from the command line using `--help` switch, or online on
|
||||
[Boost.Test library](https://www.boost.org/doc/libs/1_58_0/libs/test/doc/html/index.html)
|
||||
website.
|
||||
either from the command line using the `--help` switch, or online on the
|
||||
[Boost.Test website](https://www.boost.org/doc/libs/1_65_1/libs/test/doc/html/index.html).
|
||||
@@ -44,11 +44,12 @@ it already contains significant contributions from people outside the project te
|
||||
since broader community support is key for NDN to succeed as a new Internet architecture.
|
||||
|
||||
If you are new to the NDN software community, please read [`README-dev.md`](README-dev.md)
|
||||
and the [Contributor's Guide](CONTRIBUTING.md) to get started.
|
||||
and the [Contributor's Guide](https://github.com/named-data/.github/blob/master/CONTRIBUTING.md)
|
||||
to get started.
|
||||
|
||||
## License
|
||||
|
||||
NFD is an open and free software package licensed under the GPL version 3 and is the
|
||||
centerpiece of our committement to making NDN's core technology open and free to all
|
||||
Internet users and developers. For more information about the licensing details and
|
||||
limitations, refer to [`COPYING.md`](COPYING.md).
|
||||
NFD is a free and open-source software package licensed under the GPL version 3 and
|
||||
is the centerpiece of our committement to making NDN's core technology free and open
|
||||
to all Internet users and developers. For more information about licensing, refer to
|
||||
[`COPYING.md`](COPYING.md).
|
||||
+3
-2
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -74,8 +74,8 @@
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/core/noncopyable.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
namespace nfd {
|
||||
@@ -124,6 +124,7 @@ namespace scheduler = ndn::scheduler;
|
||||
namespace signal = ndn::util::signal;
|
||||
namespace time = ndn::time;
|
||||
using namespace ndn::time_literals;
|
||||
using ndn::operator""_block;
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include "rtt-estimator.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
RttEstimator::RttEstimator(uint16_t maxMultiplier, Duration minRto, double gain)
|
||||
: m_maxMultiplier(maxMultiplier)
|
||||
, m_minRto(minRto.count())
|
||||
, m_rtt(RttEstimator::getInitialRtt().count())
|
||||
, m_gain(gain)
|
||||
, m_variance(0)
|
||||
, m_multiplier(1)
|
||||
, m_nSamples(0)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
RttEstimator::addMeasurement(Duration measure)
|
||||
{
|
||||
double m = static_cast<double>(measure.count());
|
||||
if (m_nSamples > 0) {
|
||||
double err = m - m_rtt;
|
||||
double gErr = err * m_gain;
|
||||
m_rtt += gErr;
|
||||
double difference = std::abs(err) - m_variance;
|
||||
m_variance += difference * m_gain;
|
||||
}
|
||||
else {
|
||||
m_rtt = m;
|
||||
m_variance = m;
|
||||
}
|
||||
++m_nSamples;
|
||||
m_multiplier = 1;
|
||||
}
|
||||
|
||||
void
|
||||
RttEstimator::incrementMultiplier()
|
||||
{
|
||||
m_multiplier = std::min(static_cast<uint16_t>(m_multiplier + 1), m_maxMultiplier);
|
||||
}
|
||||
|
||||
void
|
||||
RttEstimator::doubleMultiplier()
|
||||
{
|
||||
m_multiplier = std::min(static_cast<uint16_t>(m_multiplier * 2), m_maxMultiplier);
|
||||
}
|
||||
|
||||
RttEstimator::Duration
|
||||
RttEstimator::computeRto() const
|
||||
{
|
||||
double rto = std::max(m_minRto, m_rtt + 4 * m_variance);
|
||||
rto *= m_multiplier;
|
||||
return Duration(static_cast<Duration::rep>(rto));
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -108,7 +108,9 @@ public: // parse helpers
|
||||
static_assert(std::is_arithmetic<T>::value, "T must be an arithmetic type");
|
||||
|
||||
boost::optional<T> value = node.get_value_optional<T>();
|
||||
if (value) {
|
||||
// Unsigned logic is workaround for https://redmine.named-data.net/issues/4489
|
||||
if (value &&
|
||||
(std::is_signed<T>() || node.get_value<std::string>().find("-") == std::string::npos)) {
|
||||
return *value;
|
||||
}
|
||||
NDN_THROW(Error("Invalid value '" + node.get_value<std::string>() +
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -63,25 +63,23 @@ PrivilegeHelper::initialize(const std::string& userName, const std::string& grou
|
||||
groupSize = FALLBACK_GROUP_BUFFER_SIZE;
|
||||
|
||||
std::vector<char> groupBuffer(static_cast<size_t>(groupSize));
|
||||
struct group group;
|
||||
struct group* groupResult = nullptr;
|
||||
group gr;
|
||||
group* grResult = nullptr;
|
||||
|
||||
int errorCode = getgrnam_r(groupName.data(), &group,
|
||||
groupBuffer.data(), groupBuffer.size(), &groupResult);
|
||||
int errorCode = getgrnam_r(groupName.data(), &gr, groupBuffer.data(), groupBuffer.size(), &grResult);
|
||||
|
||||
while (errorCode == ERANGE) {
|
||||
if (groupBuffer.size() * 2 > MAX_GROUP_BUFFER_SIZE)
|
||||
throw Error("Cannot allocate large enough buffer for struct group");
|
||||
|
||||
groupBuffer.resize(groupBuffer.size() * 2);
|
||||
errorCode = getgrnam_r(groupName.data(), &group,
|
||||
groupBuffer.data(), groupBuffer.size(), &groupResult);
|
||||
errorCode = getgrnam_r(groupName.data(), &gr, groupBuffer.data(), groupBuffer.size(), &grResult);
|
||||
}
|
||||
|
||||
if (errorCode != 0 || !groupResult)
|
||||
if (errorCode != 0 || !grResult)
|
||||
throw Error("Failed to get gid for \"" + groupName + "\"");
|
||||
|
||||
s_normalGid = group.gr_gid;
|
||||
s_normalGid = gr.gr_gid;
|
||||
}
|
||||
|
||||
if (!userName.empty()) {
|
||||
@@ -91,25 +89,23 @@ PrivilegeHelper::initialize(const std::string& userName, const std::string& grou
|
||||
passwdSize = FALLBACK_PASSWD_BUFFER_SIZE;
|
||||
|
||||
std::vector<char> passwdBuffer(static_cast<size_t>(passwdSize));
|
||||
struct passwd passwd;
|
||||
struct passwd* passwdResult = nullptr;
|
||||
passwd pw;
|
||||
passwd* pwResult = nullptr;
|
||||
|
||||
int errorCode = getpwnam_r(userName.data(), &passwd,
|
||||
passwdBuffer.data(), passwdBuffer.size(), &passwdResult);
|
||||
int errorCode = getpwnam_r(userName.data(), &pw, passwdBuffer.data(), passwdBuffer.size(), &pwResult);
|
||||
|
||||
while (errorCode == ERANGE) {
|
||||
if (passwdBuffer.size() * 2 > MAX_PASSWD_BUFFER_SIZE)
|
||||
throw Error("Cannot allocate large enough buffer for struct passwd");
|
||||
|
||||
passwdBuffer.resize(passwdBuffer.size() * 2);
|
||||
errorCode = getpwnam_r(userName.data(), &passwd,
|
||||
passwdBuffer.data(), passwdBuffer.size(), &passwdResult);
|
||||
errorCode = getpwnam_r(userName.data(), &pw, passwdBuffer.data(), passwdBuffer.size(), &pwResult);
|
||||
}
|
||||
|
||||
if (errorCode != 0 || !passwdResult)
|
||||
if (errorCode != 0 || !pwResult)
|
||||
throw Error("Failed to get uid for \"" + userName + "\"");
|
||||
|
||||
s_normalUid = passwd.pw_uid;
|
||||
s_normalUid = pw.pw_uid;
|
||||
}
|
||||
#else
|
||||
if (!userName.empty() || !groupName.empty()) {
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "TokenBucket.hpp"
|
||||
#include "common/global.hpp"
|
||||
#include "common/logger.hpp"
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
NFD_LOG_INIT(QSCCPTokenBucket);
|
||||
TokenBucket::TokenBucket(uint64_t rateLimit, uint64_t bucketSize, const std::string& name): rateLimit(rateLimit), bucketSize(bucketSize), name(name) {
|
||||
this->eachStep = this->rateLimit / 250.0;
|
||||
this->currentTokenSize = 0;
|
||||
this->isStart = false;
|
||||
// NFD_LOG_DEBUG("Create tokenBucket: " << name << ", eachStep: " << this->eachStep << ", rateLimit: " << this->rateLimit);
|
||||
}
|
||||
void TokenBucket::start() {
|
||||
if (this->isStart) {
|
||||
return;
|
||||
}
|
||||
// 每 4ms 增加一次令牌
|
||||
getScheduler().schedule(time::milliseconds(4), std::bind(&TokenBucket::generateToken, this));
|
||||
}
|
||||
void TokenBucket::generateToken() {
|
||||
// NFD_LOG_DEBUG(this->name << "=> do generateToken => " << this->currentTokenSize);
|
||||
if (this->currentTokenSize + this->eachStep > this->bucketSize) {
|
||||
this->currentTokenSize = this->bucketSize;
|
||||
} else {
|
||||
this->currentTokenSize += this->eachStep;
|
||||
}
|
||||
getScheduler().schedule(time::milliseconds(4), std::bind(&TokenBucket::generateToken, this));
|
||||
}
|
||||
|
||||
void TokenBucket::generateTokenByCurrentTime(long currentTime) {
|
||||
if (this->lastGenerateTokenTime == -1) {
|
||||
this->lastGenerateTokenTime = currentTime;
|
||||
return;
|
||||
}
|
||||
if (currentTime - this->lastGenerateTokenTime < 1) {
|
||||
return;
|
||||
}
|
||||
long currentStep = (currentTime - this->lastGenerateTokenTime) * this->rateLimit / 1000.0;
|
||||
// std::cout << "currentStep: " << currentStep << "currentTime: " << currentTime << "lastGenerateTokenTime: " << this->lastGenerateTokenTime << std::endl;
|
||||
// NFD_LOG_DEBUG(this->name << "=> do generateToken => " << this->currentTokenSize);
|
||||
this->lastGenerateTokenTime = currentTime;
|
||||
if (this->currentTokenSize + currentStep > this->bucketSize) {
|
||||
this->currentTokenSize = this->bucketSize;
|
||||
} else {
|
||||
this->currentTokenSize += currentStep;
|
||||
}
|
||||
}
|
||||
|
||||
bool TokenBucket::use(uint64_t tokenNum) {
|
||||
if(this->currentTokenSize > tokenNum) {
|
||||
this->currentTokenSize -= tokenNum;
|
||||
// NFD_LOG_DEBUG(this->name << "=> use success => " << this->currentTokenSize);
|
||||
return true;
|
||||
} else {
|
||||
// NFD_LOG_DEBUG(this->name << "=> use failed => " << this->currentTokenSize);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Created by gdcni21 on 3/25/22.
|
||||
//
|
||||
#ifndef NS_TOKENBUCKET_H
|
||||
#define NS_TOKENBUCKET_H
|
||||
#include <memory>
|
||||
#include <string>
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
class TokenBucket {
|
||||
public:
|
||||
explicit TokenBucket(uint64_t rateLimit, uint64_t bucketSize, const std::string& name);
|
||||
void start();
|
||||
/**
|
||||
* 周期性增加token
|
||||
**/
|
||||
void generateToken();
|
||||
|
||||
/**
|
||||
* 根据当前时间生成token
|
||||
*/
|
||||
void generateTokenByCurrentTime(long currentTime);
|
||||
|
||||
/**
|
||||
* 尝试消费n个token
|
||||
* @param tokenNum
|
||||
* @return
|
||||
*/
|
||||
bool use(uint64_t tokenNum);
|
||||
public:
|
||||
double eachStep; // 每个周期增加的令牌
|
||||
double currentTokenSize; // 当前令牌数
|
||||
uint64_t rateLimit; // 令牌生成速率
|
||||
uint64_t bucketSize; // 令牌桶容量
|
||||
std::string name;
|
||||
bool isStart; // 标识是否启动
|
||||
long lastGenerateTokenTime = -1;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif //NS_TOKENBUCKET_H
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "channel.hpp"
|
||||
#include "face.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
@@ -37,14 +38,13 @@ Channel::setUri(const FaceUri& uri)
|
||||
}
|
||||
|
||||
void
|
||||
connectFaceClosedSignal(Face& face, const std::function<void()>& f)
|
||||
connectFaceClosedSignal(Face& face, std::function<void()> f)
|
||||
{
|
||||
face.afterStateChange.connect(
|
||||
[f] (FaceState oldState, FaceState newState) {
|
||||
if (newState == FaceState::CLOSED) {
|
||||
f();
|
||||
}
|
||||
});
|
||||
face.afterStateChange.connect([f = std::move(f)] (auto, FaceState newState) {
|
||||
if (newState == FaceState::CLOSED) {
|
||||
f();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
|
||||
+14
-32
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -27,29 +27,18 @@
|
||||
#define NFD_DAEMON_FACE_CHANNEL_HPP
|
||||
|
||||
#include "channel-log.hpp"
|
||||
#include "face.hpp"
|
||||
|
||||
#include <boost/logic/tribool.hpp>
|
||||
#include "face-common.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief Prototype for the callback that is invoked when a face is created
|
||||
* (in response to an incoming connection or after a connection is established)
|
||||
*/
|
||||
using FaceCreatedCallback = std::function<void(const shared_ptr<Face>& face)>;
|
||||
|
||||
/** \brief Prototype for the callback that is invoked when a face fails to be created
|
||||
*/
|
||||
using FaceCreationFailedCallback = std::function<void(uint32_t status, const std::string& reason)>;
|
||||
|
||||
/** \brief represent a channel that communicates on a local endpoint
|
||||
/** \brief Represents a channel that listens on a local endpoint.
|
||||
* \sa FaceSystem
|
||||
*
|
||||
* A channel can listen on a local endpoint and initiate outgoing connection from a local endpoint.
|
||||
* A channel creates Face objects and retains shared ownership of them.
|
||||
*/
|
||||
class Channel : noncopyable
|
||||
class Channel : public std::enable_shared_from_this<Channel>, noncopyable
|
||||
{
|
||||
public:
|
||||
virtual
|
||||
@@ -79,31 +68,24 @@ private:
|
||||
FaceUri m_uri;
|
||||
};
|
||||
|
||||
/** \brief Parameters used to set Transport properties or LinkService options on a newly created face
|
||||
*
|
||||
* Parameters are passed as a struct rather than individually, so that a future change in the list
|
||||
* of parameters does not require an update to the method signature in all subclasses.
|
||||
/** \brief Prototype for the callback that is invoked when a face is created
|
||||
* (in response to an incoming connection or after a connection is established).
|
||||
*/
|
||||
struct FaceParams
|
||||
{
|
||||
ndn::nfd::FacePersistency persistency = ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
|
||||
optional<time::nanoseconds> baseCongestionMarkingInterval;
|
||||
optional<uint64_t> defaultCongestionThreshold;
|
||||
optional<ssize_t> mtu;
|
||||
bool wantLocalFields = false;
|
||||
bool wantLpReliability = false;
|
||||
boost::logic::tribool wantCongestionMarking = boost::logic::indeterminate;
|
||||
};
|
||||
using FaceCreatedCallback = std::function<void(const shared_ptr<Face>&)>;
|
||||
|
||||
/** \brief invokes a callback when the face is closed
|
||||
/** \brief Prototype for the callback that is invoked when a face fails to be created.
|
||||
*/
|
||||
using FaceCreationFailedCallback = std::function<void(uint32_t status, const std::string& reason)>;
|
||||
|
||||
/** \brief Invokes a callback when a face is closed.
|
||||
* \param face the face
|
||||
* \param f the callback to be invoked when the face enters CLOSED state
|
||||
*
|
||||
* This function connects a callback to the afterStateChange signal on the \p face,
|
||||
* This function connects a callback to the afterStateChange signal of \p face,
|
||||
* and invokes \p f when the state becomes CLOSED.
|
||||
*/
|
||||
void
|
||||
connectFaceClosedSignal(Face& face, const std::function<void()>& f);
|
||||
connectFaceClosedSignal(Face& face, std::function<void()> f);
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -69,7 +69,7 @@ protected:
|
||||
doClose() override;
|
||||
|
||||
void
|
||||
doSend(Transport::Packet&& packet) override;
|
||||
doSend(const Block& packet) override;
|
||||
|
||||
void
|
||||
handleSend(const boost::system::error_code& error, size_t nBytesSent);
|
||||
@@ -157,13 +157,13 @@ DatagramTransport<T, U>::doClose()
|
||||
|
||||
template<class T, class U>
|
||||
void
|
||||
DatagramTransport<T, U>::doSend(Transport::Packet&& packet)
|
||||
DatagramTransport<T, U>::doSend(const Block& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
m_socket.async_send(boost::asio::buffer(packet.packet),
|
||||
// packet.packet is copied into the lambda to retain the underlying Buffer
|
||||
[this, p = packet.packet] (auto&&... args) {
|
||||
m_socket.async_send(boost::asio::buffer(packet),
|
||||
// 'packet' is copied into the lambda to retain the underlying Buffer
|
||||
[this, packet] (auto&&... args) {
|
||||
this->handleSend(std::forward<decltype(args)>(args)...);
|
||||
});
|
||||
}
|
||||
@@ -193,9 +193,7 @@ DatagramTransport<T, U>::receiveDatagram(const uint8_t* buffer, size_t nBytesRec
|
||||
}
|
||||
m_hasRecentlyReceived = true;
|
||||
|
||||
Transport::Packet tp(std::move(element));
|
||||
tp.remoteEndpoint = makeEndpointId(m_sender);
|
||||
this->receive(std::move(tp));
|
||||
this->receive(element, makeEndpointId(m_sender));
|
||||
}
|
||||
|
||||
template<class T, class U>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "ethernet-channel.hpp"
|
||||
#include "ethernet-protocol.hpp"
|
||||
#include "face.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
#include "unicast-ethernet-transport.hpp"
|
||||
#include "common/global.hpp"
|
||||
@@ -200,12 +201,18 @@ EthernetChannel::createFace(const ethernet::Address& remoteEndpoint,
|
||||
options.allowFragmentation = true;
|
||||
options.allowReassembly = true;
|
||||
options.reliabilityOptions.isEnabled = params.wantLpReliability;
|
||||
if (params.mtu) {
|
||||
options.overrideMtu = *params.mtu;
|
||||
}
|
||||
if (params.bandwidth) {
|
||||
options.C = *params.bandwidth;
|
||||
}
|
||||
|
||||
auto linkService = make_unique<GenericLinkService>(options);
|
||||
auto transport = make_unique<UnicastEthernetTransport>(*m_localEndpoint, remoteEndpoint,
|
||||
params.persistency, m_idleFaceTimeout,
|
||||
params.mtu);
|
||||
params.persistency, m_idleFaceTimeout);
|
||||
auto face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
face->setChannel(shared_from_this()); // use weak_from_this() in C++17
|
||||
|
||||
m_channelFaces[remoteEndpoint] = face;
|
||||
connectFaceClosedSignal(*face, [this, remoteEndpoint] {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -197,10 +197,10 @@ EthernetFactory::doCreateFace(const CreateFaceRequest& req,
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.params.mtu && *req.params.mtu < Transport::MIN_MTU) {
|
||||
if (req.params.mtu && *req.params.mtu < MIN_MTU) {
|
||||
// The specified MTU must be greater than the minimum possible
|
||||
NFD_LOG_TRACE("createFace cannot create a face with an MTU less than " << Transport::MIN_MTU);
|
||||
onFailure(406, "MTU cannot be less than " + to_string(Transport::MIN_MTU));
|
||||
NFD_LOG_TRACE("createFace: override MTU cannot be less than " << MIN_MTU);
|
||||
onFailure(406, "Override MTU cannot be less than " + to_string(MIN_MTU));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -257,6 +257,9 @@ EthernetFactory::createMulticastFace(const ndn::net::NetworkInterface& netif,
|
||||
m_mcastFaces[key] = face;
|
||||
connectFaceClosedSignal(*face, [this, key] { m_mcastFaces.erase(key); });
|
||||
|
||||
auto channelIt = m_channels.find(netif.getName());
|
||||
face->setChannel(channelIt != m_channels.end() ? channelIt->second : nullptr);
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -58,11 +58,19 @@ EthernetTransport::EthernetTransport(const ndn::net::NetworkInterface& localEndp
|
||||
NDN_THROW_NESTED(Error(e.what()));
|
||||
}
|
||||
|
||||
m_netifStateConn = localEndpoint.onStateChanged.connect(
|
||||
[=] (ndn::net::InterfaceState, ndn::net::InterfaceState newState) {
|
||||
// Set initial transport state based upon the state of the underlying NetworkInterface
|
||||
handleNetifStateChange(localEndpoint.getState());
|
||||
|
||||
m_netifStateChangedConn = localEndpoint.onStateChanged.connect(
|
||||
[this] (ndn::net::InterfaceState, ndn::net::InterfaceState newState) {
|
||||
handleNetifStateChange(newState);
|
||||
});
|
||||
|
||||
m_netifMtuChangedConn = localEndpoint.onMtuChanged.connect(
|
||||
[this] (uint32_t, uint32_t mtu) {
|
||||
setMtu(mtu);
|
||||
});
|
||||
|
||||
asyncRead();
|
||||
}
|
||||
|
||||
@@ -102,11 +110,11 @@ EthernetTransport::handleNetifStateChange(ndn::net::InterfaceState netifState)
|
||||
}
|
||||
|
||||
void
|
||||
EthernetTransport::doSend(Transport::Packet&& packet)
|
||||
EthernetTransport::doSend(const Block& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
sendPacket(packet.packet);
|
||||
sendPacket(packet);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -209,13 +217,13 @@ EthernetTransport::receivePayload(const uint8_t* payload, size_t length,
|
||||
}
|
||||
m_hasRecentlyReceived = true;
|
||||
|
||||
Transport::Packet tp(std::move(element));
|
||||
static_assert(sizeof(tp.remoteEndpoint) >= ethernet::ADDR_LEN,
|
||||
"Transport::Packet::remoteEndpoint is too small");
|
||||
static_assert(sizeof(EndpointId) >= ethernet::ADDR_LEN, "EndpointId is too small");
|
||||
EndpointId endpoint = 0;
|
||||
if (m_destAddress.isMulticast()) {
|
||||
std::memcpy(&tp.remoteEndpoint, sender.data(), sender.size());
|
||||
std::memcpy(&endpoint, sender.data(), sender.size());
|
||||
}
|
||||
this->receive(std::move(tp));
|
||||
|
||||
this->receive(element, endpoint);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "ethernet-protocol.hpp"
|
||||
#include "pcap-helper.hpp"
|
||||
#include "transport.hpp"
|
||||
|
||||
#include <ndn-cxx/net/network-interface.hpp>
|
||||
|
||||
namespace nfd {
|
||||
@@ -43,11 +44,7 @@ public:
|
||||
class Error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Error(const std::string& what)
|
||||
: std::runtime_error(what)
|
||||
{
|
||||
}
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -84,7 +81,7 @@ private:
|
||||
handleNetifStateChange(ndn::net::InterfaceState netifState);
|
||||
|
||||
void
|
||||
doSend(Transport::Packet&& packet) final;
|
||||
doSend(const Block& packet) final;
|
||||
|
||||
/**
|
||||
* @brief Sends the specified TLV block on the network wrapped in an Ethernet frame
|
||||
@@ -109,7 +106,8 @@ protected:
|
||||
std::string m_interfaceName;
|
||||
|
||||
private:
|
||||
signal::ScopedConnection m_netifStateConn;
|
||||
signal::ScopedConnection m_netifStateChangedConn;
|
||||
signal::ScopedConnection m_netifMtuChangedConn;
|
||||
bool m_hasRecentlyReceived;
|
||||
#ifdef _DEBUG
|
||||
/// number of frames dropped by the kernel, as reported by libpcap
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -23,28 +23,84 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FACE_FACE_LOG_HPP
|
||||
#define NFD_DAEMON_FACE_FACE_LOG_HPP
|
||||
#ifndef NFD_DAEMON_FACE_FACE_COMMON_HPP
|
||||
#define NFD_DAEMON_FACE_FACE_COMMON_HPP
|
||||
|
||||
#include "core/common.hpp"
|
||||
#include "common/logger.hpp"
|
||||
|
||||
#include <ndn-cxx/encoding/nfd-constants.hpp>
|
||||
|
||||
#include <boost/logic/tribool.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief for internal use by FaceLogging macros
|
||||
class Face;
|
||||
class LinkService;
|
||||
|
||||
/** \brief Identifies a face.
|
||||
*/
|
||||
using FaceId = uint64_t;
|
||||
|
||||
/// indicates an invalid FaceId
|
||||
const FaceId INVALID_FACEID = ndn::nfd::INVALID_FACE_ID;
|
||||
/// identifies the InternalFace used in management
|
||||
const FaceId FACEID_INTERNAL_FACE = 1;
|
||||
/// identifies a packet comes from the ContentStore
|
||||
const FaceId FACEID_CONTENT_STORE = 254;
|
||||
/// identifies the NullFace that drops every packet
|
||||
const FaceId FACEID_NULL = 255;
|
||||
/// upper bound of reserved FaceIds
|
||||
const FaceId FACEID_RESERVED_MAX = 255;
|
||||
|
||||
/** \brief Minimum MTU that may be set
|
||||
*
|
||||
* FaceLogHelper wraps a Face, LinkService, or Transport object.
|
||||
* This is done to ensure the NDNLPv2 fragmentation feature functions properly.
|
||||
*/
|
||||
const ssize_t MIN_MTU = 64;
|
||||
|
||||
/** \brief Identifies a remote endpoint on the link.
|
||||
*
|
||||
* std::ostream& operator<<(std::ostream& os, const FaceLogHelper<T>& flh)
|
||||
* This ID is only meaningful in the context of the same Transport.
|
||||
* Incoming packets from the same remote endpoint have the same EndpointId,
|
||||
* and incoming packets from different remote endpoints have different EndpointIds.
|
||||
*
|
||||
* Typically, a point-to-point Transport has only one meaningful EndpointId (usually 0).
|
||||
*/
|
||||
using EndpointId = uint64_t;
|
||||
|
||||
/** \brief Parameters used to set Transport properties or LinkService options on a newly created face.
|
||||
*
|
||||
* Parameters are passed as a struct rather than individually, so that a future change in the list
|
||||
* of parameters does not require an update to the method signature in all subclasses.
|
||||
*/
|
||||
struct FaceParams
|
||||
{
|
||||
ndn::nfd::FacePersistency persistency = ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
|
||||
optional<time::nanoseconds> baseCongestionMarkingInterval;
|
||||
optional<uint64_t> defaultCongestionThreshold;
|
||||
optional<ssize_t> mtu;
|
||||
optional<uint64_t> bandwidth;
|
||||
bool wantLocalFields = false;
|
||||
bool wantLpReliability = false;
|
||||
boost::logic::tribool wantCongestionMarking = boost::logic::indeterminate;
|
||||
};
|
||||
|
||||
/** \brief For internal use by FaceLogging macros.
|
||||
*
|
||||
* FaceLogHelper wraps a reference to Face, LinkService, or Transport object.
|
||||
*
|
||||
* `std::ostream& operator<<(std::ostream& os, const FaceLogHelper<T>& flh)`
|
||||
* should be specialized to print "[id=888,local=scheme://local/uri,remote=scheme://remote/uri] "
|
||||
* which appears as part of the log message.
|
||||
* which will appear as part of the log message.
|
||||
*/
|
||||
template<typename T>
|
||||
class FaceLogHelper
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
FaceLogHelper(const T& obj1)
|
||||
FaceLogHelper(const T& obj1) noexcept
|
||||
: obj(obj1)
|
||||
{
|
||||
}
|
||||
@@ -54,6 +110,10 @@ public:
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
|
||||
using face::EndpointId;
|
||||
using face::FaceId;
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
/** \defgroup FaceLogging Face logging macros
|
||||
@@ -66,6 +126,7 @@ public:
|
||||
*/
|
||||
|
||||
/** \cond */
|
||||
// implementation detail
|
||||
#define NFD_LOG_FACE(level, msg) NFD_LOG_##level( \
|
||||
::nfd::face::FaceLogHelper< \
|
||||
typename std::remove_cv< \
|
||||
@@ -92,4 +153,4 @@ public:
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif // NFD_DAEMON_FACE_FACE_LOG_HPP
|
||||
#endif // NFD_DAEMON_FACE_FACE_COMMON_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -32,7 +32,7 @@ FaceCounters::FaceCounters(const LinkService::Counters& linkServiceCounters,
|
||||
const Transport::Counters& transportCounters)
|
||||
: nInInterests(linkServiceCounters.nInInterests)
|
||||
, nOutInterests(linkServiceCounters.nOutInterests)
|
||||
, nDroppedInterests(linkServiceCounters.nDroppedInterests)
|
||||
, nInterestsExceededRetx(linkServiceCounters.nInterestsExceededRetx)
|
||||
, nInData(linkServiceCounters.nInData)
|
||||
, nOutData(linkServiceCounters.nOutData)
|
||||
, nInNacks(linkServiceCounters.nInNacks)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
public:
|
||||
const PacketCounter& nInInterests;
|
||||
const PacketCounter& nOutInterests;
|
||||
const PacketCounter& nDroppedInterests;
|
||||
const PacketCounter& nInterestsExceededRetx;
|
||||
const PacketCounter& nInData;
|
||||
const PacketCounter& nOutData;
|
||||
const PacketCounter& nInNacks;
|
||||
@@ -81,6 +81,14 @@ public:
|
||||
const ByteCounter& nInBytes;
|
||||
const ByteCounter& nOutBytes;
|
||||
|
||||
/** \brief count of incoming Interests dropped due to HopLimit == 0
|
||||
*/
|
||||
PacketCounter nInHopLimitZero;
|
||||
|
||||
/** \brief count of outgoing Interests dropped due to HopLimit == 0 on non-local faces
|
||||
*/
|
||||
PacketCounter nOutHopLimitZero;
|
||||
|
||||
private:
|
||||
const LinkService::Counters& m_linkServiceCounters;
|
||||
const Transport::Counters& m_transportCounters;
|
||||
|
||||
@@ -23,14 +23,15 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FW_FACE_ENDPOINT_HPP
|
||||
#define NFD_DAEMON_FW_FACE_ENDPOINT_HPP
|
||||
#ifndef NFD_DAEMON_FACE_FACE_ENDPOINT_HPP
|
||||
#define NFD_DAEMON_FACE_FACE_ENDPOINT_HPP
|
||||
|
||||
#include "face/face.hpp"
|
||||
#include "face.hpp"
|
||||
|
||||
namespace nfd {
|
||||
|
||||
/** \brief Represents a face-endpoint pair in the forwarder
|
||||
/** \brief Represents a face-endpoint pair in the forwarder.
|
||||
* \sa face::Face, face::EndpointId
|
||||
*/
|
||||
class FaceEndpoint
|
||||
{
|
||||
@@ -49,9 +50,9 @@ public:
|
||||
inline std::ostream&
|
||||
operator<<(std::ostream& os, const FaceEndpoint& fe)
|
||||
{
|
||||
return os << "(" << fe.face.getId() << "," << fe.endpoint << ")";
|
||||
return os << '(' << fe.face.getId() << ',' << fe.endpoint << ')';
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FW_FACE_ENDPOINT_HPP
|
||||
#endif // NFD_DAEMON_FACE_FACE_ENDPOINT_HPP
|
||||
+15
-13
@@ -34,15 +34,17 @@ namespace face {
|
||||
|
||||
NFD_LOG_INIT(FaceSystem);
|
||||
|
||||
static const std::string SECTION_GENERAL = "general";
|
||||
static const std::string SECTION_NETDEVBOUND = "netdev_bound";
|
||||
const std::string CFGSEC_FACESYSTEM = "face_system";
|
||||
const std::string CFGSEC_GENERAL = "general";
|
||||
const std::string CFGSEC_GENERAL_FQ = CFGSEC_FACESYSTEM + ".general";
|
||||
const std::string CFGSEC_NETDEVBOUND = "netdev_bound";
|
||||
|
||||
FaceSystem::FaceSystem(FaceTable& faceTable, shared_ptr<ndn::net::NetworkMonitor> netmon)
|
||||
: m_faceTable(faceTable)
|
||||
, m_netmon(std::move(netmon))
|
||||
{
|
||||
auto pfCtorParams = this->makePFCtorParams();
|
||||
for (const std::string& id : ProtocolFactory::listRegistered()) {
|
||||
for (const auto& id : ProtocolFactory::listRegistered()) {
|
||||
NFD_LOG_TRACE("creating factory " << id);
|
||||
m_factories[id] = ProtocolFactory::create(id, pfCtorParams);
|
||||
}
|
||||
@@ -53,7 +55,7 @@ FaceSystem::FaceSystem(FaceTable& faceTable, shared_ptr<ndn::net::NetworkMonitor
|
||||
ProtocolFactoryCtorParams
|
||||
FaceSystem::makePFCtorParams()
|
||||
{
|
||||
auto addFace = [&ft = m_faceTable] (auto face) { ft.add(std::move(face)); };
|
||||
auto addFace = [this] (auto face) { m_faceTable.add(std::move(face)); };
|
||||
return {addFace, m_netmon};
|
||||
}
|
||||
|
||||
@@ -92,25 +94,25 @@ FaceSystem::hasFactoryForScheme(const std::string& scheme) const
|
||||
void
|
||||
FaceSystem::setConfigFile(ConfigFile& configFile)
|
||||
{
|
||||
configFile.addSectionHandler("face_system", bind(&FaceSystem::processConfig, this, _1, _2, _3));
|
||||
configFile.addSectionHandler(CFGSEC_FACESYSTEM, bind(&FaceSystem::processConfig, this, _1, _2, _3));
|
||||
}
|
||||
|
||||
void
|
||||
FaceSystem::processConfig(const ConfigSection& configSection, bool isDryRun, const std::string& filename)
|
||||
FaceSystem::processConfig(const ConfigSection& configSection, bool isDryRun, const std::string&)
|
||||
{
|
||||
ConfigContext context;
|
||||
context.isDryRun = isDryRun;
|
||||
|
||||
// process general protocol factory config section
|
||||
auto generalSection = configSection.get_child_optional(SECTION_GENERAL);
|
||||
auto generalSection = configSection.get_child_optional(CFGSEC_GENERAL);
|
||||
if (generalSection) {
|
||||
for (const auto& pair : *generalSection) {
|
||||
const std::string& key = pair.first;
|
||||
if (key == "enable_congestion_marking") {
|
||||
context.generalConfig.wantCongestionMarking = ConfigFile::parseYesNo(pair, "face_system.general");
|
||||
context.generalConfig.wantCongestionMarking = ConfigFile::parseYesNo(pair, CFGSEC_GENERAL_FQ);
|
||||
}
|
||||
else {
|
||||
NDN_THROW(ConfigFile::Error("Unrecognized option face_system.general." + key));
|
||||
NDN_THROW(ConfigFile::Error("Unrecognized option " + CFGSEC_GENERAL_FQ + "." + key));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,7 +142,7 @@ FaceSystem::processConfig(const ConfigSection& configSection, bool isDryRun, con
|
||||
}
|
||||
|
||||
// process netdev_bound section, after factories start providing *+dev schemes
|
||||
auto netdevBoundSection = configSection.get_child_optional(SECTION_NETDEVBOUND);
|
||||
auto netdevBoundSection = configSection.get_child_optional(CFGSEC_NETDEVBOUND);
|
||||
m_netdevBound->processConfig(netdevBoundSection, context);
|
||||
|
||||
// process other sections
|
||||
@@ -150,15 +152,15 @@ FaceSystem::processConfig(const ConfigSection& configSection, bool isDryRun, con
|
||||
// const ConfigSection& subSection = pair.second;
|
||||
|
||||
if (!seenSections.insert(sectionName).second) {
|
||||
NDN_THROW(ConfigFile::Error("Duplicate section face_system." + sectionName));
|
||||
NDN_THROW(ConfigFile::Error("Duplicate section " + CFGSEC_FACESYSTEM + "." + sectionName));
|
||||
}
|
||||
|
||||
if (sectionName == SECTION_GENERAL || sectionName == SECTION_NETDEVBOUND ||
|
||||
if (sectionName == CFGSEC_GENERAL || sectionName == CFGSEC_NETDEVBOUND ||
|
||||
m_factories.count(sectionName) > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NDN_THROW(ConfigFile::Error("Unrecognized option face_system." + sectionName));
|
||||
NDN_THROW(ConfigFile::Error("Unrecognized option " + CFGSEC_FACESYSTEM + "." + sectionName));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#ifndef NFD_DAEMON_FACE_FACE_SYSTEM_HPP
|
||||
#define NFD_DAEMON_FACE_FACE_SYSTEM_HPP
|
||||
|
||||
#include "channel.hpp"
|
||||
#include "network-predicate.hpp"
|
||||
#include "common/config-file.hpp"
|
||||
|
||||
|
||||
+60
-45
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,28 +26,15 @@
|
||||
#ifndef NFD_DAEMON_FACE_FACE_HPP
|
||||
#define NFD_DAEMON_FACE_FACE_HPP
|
||||
|
||||
#include "face-common.hpp"
|
||||
#include "face-counters.hpp"
|
||||
#include "face-log.hpp"
|
||||
#include "link-service.hpp"
|
||||
#include "transport.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
/** \brief identifies a face
|
||||
*/
|
||||
typedef uint64_t FaceId;
|
||||
|
||||
/// indicates an invalid FaceId
|
||||
const FaceId INVALID_FACEID = 0;
|
||||
/// identifies the InternalFace used in management
|
||||
const FaceId FACEID_INTERNAL_FACE = 1;
|
||||
/// identifies a packet comes from the ContentStore
|
||||
const FaceId FACEID_CONTENT_STORE = 254;
|
||||
/// identifies the NullFace that drops every packet
|
||||
const FaceId FACEID_NULL = 255;
|
||||
/// upper bound of reserved FaceIds
|
||||
const FaceId FACEID_RESERVED_MAX = 255;
|
||||
class Channel;
|
||||
|
||||
/** \brief indicates the state of a face
|
||||
*/
|
||||
@@ -75,39 +62,51 @@ public:
|
||||
Transport*
|
||||
getTransport() const;
|
||||
|
||||
/** \brief Request that the face be closed
|
||||
*
|
||||
* This operation is effective only if face is in the UP or DOWN state; otherwise, it has no effect.
|
||||
* The face will change state to CLOSING, and then perform a cleanup procedure.
|
||||
* When the cleanup is complete, the state will be changed to CLOSED, which may happen
|
||||
* synchronously or asynchronously.
|
||||
*
|
||||
* \warning The face must not be deallocated until its state changes to CLOSED.
|
||||
*/
|
||||
void
|
||||
close();
|
||||
|
||||
public: // upper interface connected to forwarding
|
||||
/** \brief sends Interest on Face
|
||||
/** \brief send Interest
|
||||
*/
|
||||
void
|
||||
sendInterest(const Interest& interest);
|
||||
|
||||
/** \brief sends Data on Face
|
||||
/** \brief send Data
|
||||
*/
|
||||
void
|
||||
sendData(const Data& data);
|
||||
|
||||
/** \brief sends Nack on Face
|
||||
/** \brief send Nack
|
||||
*/
|
||||
void
|
||||
sendNack(const lp::Nack& nack);
|
||||
|
||||
/** \brief signals on Interest received
|
||||
*/
|
||||
signal::Signal<LinkService, Interest>& afterReceiveInterest;
|
||||
signal::Signal<LinkService, Interest, EndpointId>& afterReceiveInterest;
|
||||
|
||||
/** \brief signals on Data received
|
||||
*/
|
||||
signal::Signal<LinkService, Data>& afterReceiveData;
|
||||
signal::Signal<LinkService, Data, EndpointId>& afterReceiveData;
|
||||
|
||||
/** \brief signals on Nack received
|
||||
*/
|
||||
signal::Signal<LinkService, lp::Nack>& afterReceiveNack;
|
||||
signal::Signal<LinkService, lp::Nack, EndpointId>& afterReceiveNack;
|
||||
|
||||
/** \brief signals on Interest dropped by reliability system for exceeding allowed number of retx
|
||||
*/
|
||||
signal::Signal<LinkService, Interest>& onDroppedInterest;
|
||||
|
||||
public: // static properties
|
||||
public: // properties
|
||||
/** \return face ID
|
||||
*/
|
||||
FaceId
|
||||
@@ -149,7 +148,13 @@ public: // static properties
|
||||
ndn::nfd::LinkType
|
||||
getLinkType() const;
|
||||
|
||||
public: // dynamic properties
|
||||
/** \brief Returns face effective MTU
|
||||
*
|
||||
* This function is a wrapper. The effective MTU of a face is determined by the link service.
|
||||
*/
|
||||
ssize_t
|
||||
getMtu() const;
|
||||
|
||||
/** \return face state
|
||||
*/
|
||||
FaceState
|
||||
@@ -165,27 +170,33 @@ public: // dynamic properties
|
||||
time::steady_clock::TimePoint
|
||||
getExpirationTime() const;
|
||||
|
||||
/** \brief request the face to be closed
|
||||
*
|
||||
* This operation is effective only if face is in UP or DOWN state,
|
||||
* otherwise it has no effect.
|
||||
* The face changes state to CLOSING, and performs cleanup procedure.
|
||||
* The state will be changed to CLOSED when cleanup is complete, which may
|
||||
* happen synchronously or asynchronously.
|
||||
*
|
||||
* \warning the face must not be deallocated until its state changes to CLOSED
|
||||
*/
|
||||
void
|
||||
close();
|
||||
|
||||
const FaceCounters&
|
||||
getCounters() const;
|
||||
|
||||
/**
|
||||
* \brief Get channel on which face was created (unicast) or the associated channel (multicast)
|
||||
*/
|
||||
weak_ptr<Channel>
|
||||
getChannel() const
|
||||
{
|
||||
return m_channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set channel on which face was created (unicast) or the associated channel (multicast)
|
||||
*/
|
||||
void
|
||||
setChannel(weak_ptr<Channel> channel)
|
||||
{
|
||||
m_channel = std::move(channel);
|
||||
}
|
||||
|
||||
private:
|
||||
FaceId m_id;
|
||||
unique_ptr<LinkService> m_service;
|
||||
unique_ptr<Transport> m_transport;
|
||||
FaceCounters m_counters;
|
||||
weak_ptr<Channel> m_channel;
|
||||
};
|
||||
|
||||
inline LinkService*
|
||||
@@ -200,6 +211,12 @@ Face::getTransport() const
|
||||
return m_transport.get();
|
||||
}
|
||||
|
||||
inline void
|
||||
Face::close()
|
||||
{
|
||||
m_transport->close();
|
||||
}
|
||||
|
||||
inline void
|
||||
Face::sendInterest(const Interest& interest)
|
||||
{
|
||||
@@ -266,6 +283,12 @@ Face::getLinkType() const
|
||||
return m_transport->getLinkType();
|
||||
}
|
||||
|
||||
inline ssize_t
|
||||
Face::getMtu() const
|
||||
{
|
||||
return m_service->getEffectiveMtu();
|
||||
}
|
||||
|
||||
inline FaceState
|
||||
Face::getState() const
|
||||
{
|
||||
@@ -278,12 +301,6 @@ Face::getExpirationTime() const
|
||||
return m_transport->getExpirationTime();
|
||||
}
|
||||
|
||||
inline void
|
||||
Face::close()
|
||||
{
|
||||
m_transport->close();
|
||||
}
|
||||
|
||||
inline const FaceCounters&
|
||||
Face::getCounters() const
|
||||
{
|
||||
@@ -295,8 +312,6 @@ operator<<(std::ostream& os, const FaceLogHelper<Face>& flh);
|
||||
|
||||
} // namespace face
|
||||
|
||||
using face::EndpointId;
|
||||
using face::FaceId;
|
||||
using face::Face;
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -24,7 +24,8 @@
|
||||
*/
|
||||
|
||||
#include "generic-link-service.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <ndn-cxx/lp/pit-token.hpp>
|
||||
#include <ndn-cxx/lp/tags.hpp>
|
||||
|
||||
#include <cmath>
|
||||
@@ -38,8 +39,6 @@ constexpr size_t CONGESTION_MARK_SIZE = tlv::sizeOfVarNumber(lp::tlv::Congestion
|
||||
tlv::sizeOfVarNumber(sizeof(uint64_t)) + // length
|
||||
tlv::sizeOfNonNegativeInteger(UINT64_MAX); // value
|
||||
|
||||
constexpr uint32_t DEFAULT_CONGESTION_THRESHOLD_DIVISOR = 2;
|
||||
|
||||
GenericLinkService::GenericLinkService(const GenericLinkService::Options& options)
|
||||
: m_options(options)
|
||||
, m_fragmenter(m_options.fragmenterOptions, this)
|
||||
@@ -47,12 +46,45 @@ GenericLinkService::GenericLinkService(const GenericLinkService::Options& option
|
||||
, m_reliability(m_options.reliabilityOptions, this)
|
||||
, m_lastSeqNo(-2)
|
||||
, m_nextMarkTime(time::steady_clock::TimePoint::max())
|
||||
, m_lastMarkTime(time::steady_clock::TimePoint::min())
|
||||
, m_nMarkedSinceInMarkingState(0)
|
||||
, globalSp(options.C * 0.99, options.vqSize)
|
||||
{
|
||||
std::cout << "C: " << options.C << std::endl;
|
||||
m_reassembler.beforeTimeout.connect([this] (auto...) { ++this->nReassemblyTimeouts; });
|
||||
m_reliability.onDroppedInterest.connect([this] (const auto& i) { this->notifyDroppedInterest(i); });
|
||||
nReassembling.observe(&m_reassembler);
|
||||
this->sendPacketCallback = [this](std::shared_ptr<VirtualQueueItem> taskPtr) {
|
||||
this->globalSp.triggerCalObjectRate();
|
||||
if (taskPtr != nullptr) {
|
||||
const Block &block = taskPtr->item->wireEncode();
|
||||
// std::cout << "interest wireEncode size: " << block.size() << std::endl;
|
||||
lp::Packet lpPacket(block);
|
||||
// std::cout << "Interest lppacket size before encode lp fields: " << lpPacket.wireEncode().size() << std::endl;
|
||||
encodeLpFields(*(taskPtr->item), lpPacket);
|
||||
// std::cout << "Interest lppacket size after encode lp fields: " << lpPacket.wireEncode().size() << std::endl;
|
||||
this->sendNetPacket(std::move(lpPacket), true);
|
||||
// lp::Packet lpPacket(taskPtr->item->wireEncode());
|
||||
// encodeLpFields(*(taskPtr->item), lpPacket);
|
||||
// this->sendNetPacket(std::move(lpPacket), taskPtr->endpointId, true);
|
||||
}
|
||||
// 得到下一个需要调度的包
|
||||
auto newTaskPtr = this->globalSp.scheduleNext();
|
||||
if (newTaskPtr == nullptr) {
|
||||
//NFD_LOG_ERROR("FUCK");
|
||||
// std::cout << "FUCK" << std::endl;
|
||||
// 如果没有可调度的包,则 1 ms 之后再调度
|
||||
this->canScheduler = true;
|
||||
// getScheduler().schedule(time::milliseconds(1), std::bind(this->sendPacketCallback, nullptr));
|
||||
} else {
|
||||
// 等待足够的 token 再发送
|
||||
this->canScheduler = false;
|
||||
// std::cout << "Route waitTime: " << newTaskPtr->waitNsTime << std::endl;
|
||||
// NFD_LOG_DEBUG("Route waitTime: " << newTaskPtr->waitNsTime);
|
||||
getScheduler().schedule(time::nanoseconds((uint32_t)(0)),
|
||||
std::bind(this->sendPacketCallback, newTaskPtr));
|
||||
}
|
||||
};
|
||||
// getScheduler().schedule(time::nanoseconds(0), std::bind(this->sendPacketCallback, nullptr));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -64,18 +96,38 @@ GenericLinkService::setOptions(const GenericLinkService::Options& options)
|
||||
m_reliability.setOptions(m_options.reliabilityOptions);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
GenericLinkService::getEffectiveMtu() const
|
||||
{
|
||||
// Since MTU_UNLIMITED is negative, it will implicitly override any finite override MTU
|
||||
return std::min(m_options.overrideMtu, getTransport()->getMtu());
|
||||
}
|
||||
|
||||
bool
|
||||
GenericLinkService::canOverrideMtuTo(ssize_t mtu) const
|
||||
{
|
||||
// Not allowed to override unlimited transport MTU
|
||||
if (getTransport()->getMtu() == MTU_UNLIMITED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Override MTU must be at least MIN_MTU (also implicitly forbids MTU_UNLIMITED and MTU_INVALID)
|
||||
return mtu >= MIN_MTU;
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::requestIdlePacket()
|
||||
{
|
||||
// No need to request Acks to attach to this packet from LpReliability, as they are already
|
||||
// attached in sendLpPacket
|
||||
NFD_LOG_FACE_TRACE("IDLE packet requested");
|
||||
this->sendLpPacket({});
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::sendLpPacket(lp::Packet&& pkt)
|
||||
{
|
||||
const ssize_t mtu = this->getTransport()->getMtu();
|
||||
const ssize_t mtu = getEffectiveMtu();
|
||||
|
||||
if (m_options.reliabilityOptions.isEnabled) {
|
||||
m_reliability.piggyback(pkt, mtu);
|
||||
@@ -85,23 +137,46 @@ GenericLinkService::sendLpPacket(lp::Packet&& pkt)
|
||||
checkCongestionLevel(pkt);
|
||||
}
|
||||
|
||||
Transport::Packet tp(pkt.wireEncode());
|
||||
if (mtu != MTU_UNLIMITED && tp.packet.size() > static_cast<size_t>(mtu)) {
|
||||
auto block = pkt.wireEncode();
|
||||
if (mtu != MTU_UNLIMITED && block.size() > static_cast<size_t>(mtu)) {
|
||||
++this->nOutOverMtu;
|
||||
NFD_LOG_FACE_WARN("attempted to send packet over MTU limit");
|
||||
return;
|
||||
}
|
||||
this->sendPacket(std::move(tp));
|
||||
this->sendPacket(block);
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::doSendInterest(const Interest& interest)
|
||||
{
|
||||
lp::Packet lpPacket(interest.wireEncode());
|
||||
if (interest.getName().getPrefix(1).toUri() == "/localhost") {
|
||||
const Block &block = interest.wireEncode();
|
||||
// // std::cout << "interest wireEncode size: " << block.size() << std::endl;
|
||||
lp::Packet lpPacket(block);
|
||||
// // std::cout << "lppacket size before encode lp fields: " << lpPacket.wireEncode().size() << std::endl;
|
||||
encodeLpFields(interest, lpPacket);
|
||||
// // std::cout << "lppacket size after encode lp fields: " << lpPacket.wireEncode().size() << std::endl;
|
||||
this->sendNetPacket(std::move(lpPacket), true);
|
||||
} else {
|
||||
this->globalSp.appendInterest(interest);
|
||||
if (this->canScheduler) {
|
||||
this->sendPacketCallback(nullptr);
|
||||
}
|
||||
//if (!success) {
|
||||
// // send Nack
|
||||
// lp::Nack nack(interest);
|
||||
// nack.setReason(lp::NackReason::CONGESTION);
|
||||
// if (this->nwfq.canMark(nack)) {
|
||||
// // 拥塞标记
|
||||
// nack.getInterest().setTag(make_shared<lp::CongestionMarkTag>(1));
|
||||
// }
|
||||
// this->receiveNack(nack, endpointId);
|
||||
//}
|
||||
}
|
||||
|
||||
encodeLpFields(interest, lpPacket);
|
||||
// encodeLpFields(interest, lpPacket);
|
||||
|
||||
this->sendNetPacket(std::move(lpPacket), true);
|
||||
// this->sendNetPacket(std::move(lpPacket), true);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -125,39 +200,52 @@ GenericLinkService::doSendNack(const lp::Nack& nack)
|
||||
this->sendNetPacket(std::move(lpPacket), false);
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::assignSequences(std::vector<lp::Packet>& pkts)
|
||||
{
|
||||
std::for_each(pkts.begin(), pkts.end(), [this] (lp::Packet& pkt) {
|
||||
pkt.set<lp::SequenceField>(++m_lastSeqNo);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::encodeLpFields(const ndn::PacketBase& netPkt, lp::Packet& lpPacket)
|
||||
{
|
||||
if (m_options.allowLocalFields) {
|
||||
shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
|
||||
auto incomingFaceIdTag = netPkt.getTag<lp::IncomingFaceIdTag>();
|
||||
if (incomingFaceIdTag != nullptr) {
|
||||
lpPacket.add<lp::IncomingFaceIdField>(*incomingFaceIdTag);
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<lp::CongestionMarkTag> congestionMarkTag = netPkt.getTag<lp::CongestionMarkTag>();
|
||||
auto congestionMarkTag = netPkt.getTag<lp::CongestionMarkTag>();
|
||||
if (congestionMarkTag != nullptr) {
|
||||
lpPacket.add<lp::CongestionMarkField>(*congestionMarkTag);
|
||||
}
|
||||
|
||||
if (m_options.allowSelfLearning) {
|
||||
shared_ptr<lp::NonDiscoveryTag> nonDiscoveryTag = netPkt.getTag<lp::NonDiscoveryTag>();
|
||||
auto nonDiscoveryTag = netPkt.getTag<lp::NonDiscoveryTag>();
|
||||
if (nonDiscoveryTag != nullptr) {
|
||||
lpPacket.add<lp::NonDiscoveryField>(*nonDiscoveryTag);
|
||||
}
|
||||
|
||||
shared_ptr<lp::PrefixAnnouncementTag> prefixAnnouncementTag = netPkt.getTag<lp::PrefixAnnouncementTag>();
|
||||
auto prefixAnnouncementTag = netPkt.getTag<lp::PrefixAnnouncementTag>();
|
||||
if (prefixAnnouncementTag != nullptr) {
|
||||
lpPacket.add<lp::PrefixAnnouncementField>(*prefixAnnouncementTag);
|
||||
}
|
||||
}
|
||||
|
||||
auto pitToken = netPkt.getTag<lp::PitToken>();
|
||||
if (pitToken != nullptr) {
|
||||
lpPacket.add<lp::PitTokenField>(*pitToken);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::sendNetPacket(lp::Packet&& pkt, bool isInterest)
|
||||
{
|
||||
std::vector<lp::Packet> frags;
|
||||
ssize_t mtu = this->getTransport()->getMtu();
|
||||
ssize_t mtu = getEffectiveMtu();
|
||||
|
||||
// Make space for feature fields in fragments
|
||||
if (m_options.reliabilityOptions.isEnabled && mtu != MTU_UNLIMITED) {
|
||||
@@ -168,7 +256,8 @@ GenericLinkService::sendNetPacket(lp::Packet&& pkt, bool isInterest)
|
||||
mtu -= CONGESTION_MARK_SIZE;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(mtu == MTU_UNLIMITED || mtu > 0);
|
||||
// An MTU of 0 is allowed but will cause all packets to be dropped before transmission
|
||||
BOOST_ASSERT(mtu == MTU_UNLIMITED || mtu >= 0);
|
||||
|
||||
if (m_options.allowFragmentation && mtu != MTU_UNLIMITED) {
|
||||
bool isOk = false;
|
||||
@@ -195,8 +284,8 @@ GenericLinkService::sendNetPacket(lp::Packet&& pkt, bool isInterest)
|
||||
BOOST_ASSERT(!frags.front().has<lp::FragCountField>());
|
||||
}
|
||||
|
||||
// Only assign sequences to fragments if packet contains more than 1 fragment
|
||||
if (frags.size() > 1) {
|
||||
// Only assign sequences to fragments if reliability enabled or if packet contains >1 fragment
|
||||
if (m_options.reliabilityOptions.isEnabled || frags.size() > 1) {
|
||||
// Assign sequences to all fragments
|
||||
this->assignSequences(frags);
|
||||
}
|
||||
@@ -210,50 +299,30 @@ GenericLinkService::sendNetPacket(lp::Packet&& pkt, bool isInterest)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::assignSequence(lp::Packet& pkt)
|
||||
{
|
||||
pkt.set<lp::SequenceField>(++m_lastSeqNo);
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::assignSequences(std::vector<lp::Packet>& pkts)
|
||||
{
|
||||
std::for_each(pkts.begin(), pkts.end(), [this] (auto& pkt) { this->assignSequence(pkt); });
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::checkCongestionLevel(lp::Packet& pkt)
|
||||
{
|
||||
ssize_t sendQueueLength = getTransport()->getSendQueueLength();
|
||||
// This operation requires that the transport supports retrieving current send queue length
|
||||
// The transport must support retrieving the current send queue length
|
||||
if (sendQueueLength < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// To avoid overflowing the queue, set the congestion threshold to at least half of the send
|
||||
// queue capacity.
|
||||
size_t congestionThreshold = m_options.defaultCongestionThreshold;
|
||||
if (getTransport()->getSendQueueCapacity() >= 0) {
|
||||
congestionThreshold = std::min(congestionThreshold,
|
||||
static_cast<size_t>(getTransport()->getSendQueueCapacity()) /
|
||||
DEFAULT_CONGESTION_THRESHOLD_DIVISOR);
|
||||
}
|
||||
|
||||
if (sendQueueLength > 0) {
|
||||
NFD_LOG_FACE_TRACE("txqlen=" << sendQueueLength << " threshold=" << congestionThreshold <<
|
||||
" capacity=" << getTransport()->getSendQueueCapacity());
|
||||
NFD_LOG_FACE_TRACE("txqlen=" << sendQueueLength << " threshold=" <<
|
||||
m_options.defaultCongestionThreshold << " capacity=" <<
|
||||
getTransport()->getSendQueueCapacity());
|
||||
}
|
||||
|
||||
if (static_cast<size_t>(sendQueueLength) > congestionThreshold) { // Send queue is congested
|
||||
// sendQueue is above target
|
||||
if (static_cast<size_t>(sendQueueLength) > m_options.defaultCongestionThreshold) {
|
||||
const auto now = time::steady_clock::now();
|
||||
if (now >= m_nextMarkTime || now >= m_lastMarkTime + m_options.baseCongestionMarkingInterval) {
|
||||
// Mark at most one initial packet per baseCongestionMarkingInterval
|
||||
if (m_nMarkedSinceInMarkingState == 0) {
|
||||
m_nextMarkTime = now;
|
||||
}
|
||||
|
||||
// Time to mark packet
|
||||
if (m_nextMarkTime == time::steady_clock::TimePoint::max()) {
|
||||
m_nextMarkTime = now + m_options.baseCongestionMarkingInterval;
|
||||
}
|
||||
// Mark packet if sendQueue stays above target for one interval
|
||||
else if (now >= m_nextMarkTime) {
|
||||
pkt.set<lp::CongestionMarkField>(1);
|
||||
++nCongestionMarked;
|
||||
NFD_LOG_FACE_DEBUG("LpPacket was marked as congested");
|
||||
@@ -261,10 +330,10 @@ GenericLinkService::checkCongestionLevel(lp::Packet& pkt)
|
||||
++m_nMarkedSinceInMarkingState;
|
||||
// Decrease the marking interval by the inverse of the square root of the number of packets
|
||||
// marked in this incident of congestion
|
||||
m_nextMarkTime += time::nanoseconds(static_cast<time::nanoseconds::rep>(
|
||||
m_options.baseCongestionMarkingInterval.count() /
|
||||
std::sqrt(m_nMarkedSinceInMarkingState)));
|
||||
m_lastMarkTime = now;
|
||||
time::nanoseconds interval(static_cast<time::nanoseconds::rep>(
|
||||
m_options.baseCongestionMarkingInterval.count() /
|
||||
std::sqrt(m_nMarkedSinceInMarkingState + 1)));
|
||||
m_nextMarkTime += interval;
|
||||
}
|
||||
}
|
||||
else if (m_nextMarkTime != time::steady_clock::TimePoint::max()) {
|
||||
@@ -276,13 +345,17 @@ GenericLinkService::checkCongestionLevel(lp::Packet& pkt)
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::doReceivePacket(Transport::Packet&& packet)
|
||||
GenericLinkService::doReceivePacket(const Block& packet, const EndpointId& endpoint)
|
||||
{
|
||||
try {
|
||||
lp::Packet pkt(packet.packet);
|
||||
lp::Packet pkt(packet);
|
||||
|
||||
if (m_options.reliabilityOptions.isEnabled) {
|
||||
m_reliability.processIncomingPacket(pkt);
|
||||
if (!m_reliability.processIncomingPacket(pkt)) {
|
||||
NFD_LOG_FACE_TRACE("received duplicate fragment: DROP");
|
||||
++this->nDuplicateSequence;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pkt.has<lp::FragmentField>()) {
|
||||
@@ -299,10 +372,9 @@ GenericLinkService::doReceivePacket(Transport::Packet&& packet)
|
||||
bool isReassembled = false;
|
||||
Block netPkt;
|
||||
lp::Packet firstPkt;
|
||||
std::tie(isReassembled, netPkt, firstPkt) = m_reassembler.receiveFragment(packet.remoteEndpoint,
|
||||
pkt);
|
||||
std::tie(isReassembled, netPkt, firstPkt) = m_reassembler.receiveFragment(endpoint, pkt);
|
||||
if (isReassembled) {
|
||||
this->decodeNetPacket(netPkt, firstPkt);
|
||||
this->decodeNetPacket(netPkt, firstPkt, endpoint);
|
||||
}
|
||||
}
|
||||
catch (const tlv::Error& e) {
|
||||
@@ -312,20 +384,21 @@ GenericLinkService::doReceivePacket(Transport::Packet&& packet)
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::decodeNetPacket(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
GenericLinkService::decodeNetPacket(const Block& netPkt, const lp::Packet& firstPkt,
|
||||
const EndpointId& endpointId)
|
||||
{
|
||||
try {
|
||||
switch (netPkt.type()) {
|
||||
case tlv::Interest:
|
||||
if (firstPkt.has<lp::NackField>()) {
|
||||
this->decodeNack(netPkt, firstPkt);
|
||||
this->decodeNack(netPkt, firstPkt, endpointId);
|
||||
}
|
||||
else {
|
||||
this->decodeInterest(netPkt, firstPkt);
|
||||
this->decodeInterest(netPkt, firstPkt, endpointId);
|
||||
}
|
||||
break;
|
||||
case tlv::Data:
|
||||
this->decodeData(netPkt, firstPkt);
|
||||
this->decodeData(netPkt, firstPkt, endpointId);
|
||||
break;
|
||||
default:
|
||||
++this->nInNetInvalid;
|
||||
@@ -335,12 +408,13 @@ GenericLinkService::decodeNetPacket(const Block& netPkt, const lp::Packet& first
|
||||
}
|
||||
catch (const tlv::Error& e) {
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
|
||||
NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP" << netPkt.type());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstPkt,
|
||||
const EndpointId& endpointId)
|
||||
{
|
||||
BOOST_ASSERT(netPkt.type() == tlv::Interest);
|
||||
BOOST_ASSERT(!firstPkt.has<lp::NackField>());
|
||||
@@ -387,11 +461,18 @@ GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstP
|
||||
return;
|
||||
}
|
||||
|
||||
this->receiveInterest(*interest);
|
||||
if (firstPkt.has<lp::PitTokenField>()) {
|
||||
interest->setTag(make_shared<lp::PitToken>(firstPkt.get<lp::PitTokenField>()));
|
||||
}
|
||||
|
||||
this->globalSp.receiveInterest(*interest);
|
||||
this->globalSp.triggerCalObjectRate();
|
||||
this->receiveInterest(*interest, endpointId);
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt,
|
||||
const EndpointId& endpointId)
|
||||
{
|
||||
BOOST_ASSERT(netPkt.type() == tlv::Data);
|
||||
|
||||
@@ -440,11 +521,19 @@ GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
}
|
||||
}
|
||||
|
||||
this->receiveData(*data);
|
||||
// 不处理本地命令通信
|
||||
if (data->getName().getPrefix(1).toUri() != "/localhost") {
|
||||
// TR = min(TR, OR)
|
||||
this->globalSp.assignObjectRate(*data);
|
||||
}
|
||||
|
||||
this->globalSp.triggerCalObjectRate();
|
||||
this->receiveData(*data, endpointId);
|
||||
}
|
||||
|
||||
void
|
||||
GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt,
|
||||
const EndpointId& endpointId)
|
||||
{
|
||||
BOOST_ASSERT(netPkt.type() == tlv::Interest);
|
||||
BOOST_ASSERT(firstPkt.has<lp::NackField>());
|
||||
@@ -484,7 +573,7 @@ GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt)
|
||||
return;
|
||||
}
|
||||
|
||||
this->receiveNack(nack);
|
||||
this->receiveNack(nack, endpointId);
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "lp-fragmenter.hpp"
|
||||
#include "lp-reassembler.hpp"
|
||||
#include "lp-reliability.hpp"
|
||||
#include "queues.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
@@ -81,6 +82,10 @@ public:
|
||||
*/
|
||||
PacketCounter nRetxExhausted;
|
||||
|
||||
/** \brief count of LpPackets dropped due to duplicate Sequence numbers
|
||||
*/
|
||||
PacketCounter nDuplicateSequence;
|
||||
|
||||
/** \brief count of outgoing LpPackets that were marked with congestion marks
|
||||
*/
|
||||
PacketCounter nCongestionMarked;
|
||||
@@ -98,7 +103,6 @@ public:
|
||||
class Options
|
||||
{
|
||||
public:
|
||||
constexpr
|
||||
Options() noexcept
|
||||
{
|
||||
}
|
||||
@@ -133,12 +137,16 @@ public:
|
||||
bool allowCongestionMarking = false;
|
||||
|
||||
/** \brief starting value for congestion marking interval
|
||||
*
|
||||
* Packets are marked if the queue size stays above THRESHOLD for at least one INTERVAL.
|
||||
*
|
||||
* The default value (100 ms) is taken from RFC 8289 (CoDel).
|
||||
*/
|
||||
time::nanoseconds baseCongestionMarkingInterval = 100_ms;
|
||||
|
||||
/** \brief default congestion threshold in bytes
|
||||
*
|
||||
* Packets are marked if the queue size stays above THRESHOLD for at least one INTERVAL.
|
||||
*
|
||||
* The default value (64 KiB) works well for a queue capacity of 200 KiB.
|
||||
*/
|
||||
@@ -147,6 +155,19 @@ public:
|
||||
/** \brief enables self-learning forwarding support
|
||||
*/
|
||||
bool allowSelfLearning = true;
|
||||
|
||||
/** \brief overrides MTU provided by Transport
|
||||
*
|
||||
* This MTU value will be used instead of the MTU provided by the transport if it is less than
|
||||
* the transport MTU. However, it will not be utilized when the transport MTU is unlimited.
|
||||
*
|
||||
* Acceptable values for the override MTU are values >= MIN_MTU, which can be validated before
|
||||
* being set with canOverrideMtuTo().
|
||||
*/
|
||||
ssize_t overrideMtu = std::numeric_limits<ssize_t>::max();
|
||||
|
||||
uint64_t C = 100000000; // 100Mbps
|
||||
size_t vqSize = 20;
|
||||
};
|
||||
|
||||
/** \brief counters provided by GenericLinkService
|
||||
@@ -169,33 +190,41 @@ public:
|
||||
const Counters&
|
||||
getCounters() const OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
|
||||
ssize_t
|
||||
getEffectiveMtu() const OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
|
||||
/** \brief Whether MTU can be overridden to the specified value
|
||||
*
|
||||
* If the transport MTU is unlimited, then this will always return false.
|
||||
*/
|
||||
bool
|
||||
canOverrideMtuTo(ssize_t mtu) const;
|
||||
|
||||
PROTECTED_WITH_TESTS_ELSE_PRIVATE: // send path
|
||||
/** \brief request an IDLE packet to transmit pending service fields
|
||||
*/
|
||||
void
|
||||
requestIdlePacket();
|
||||
|
||||
/** \brief send an LpPacket fragment
|
||||
* \param pkt LpPacket to send
|
||||
/** \brief send an LpPacket
|
||||
*/
|
||||
void
|
||||
sendLpPacket(lp::Packet&& pkt);
|
||||
|
||||
/** \brief send Interest
|
||||
*/
|
||||
void
|
||||
doSendInterest(const Interest& interest) OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
|
||||
/** \brief send Data
|
||||
*/
|
||||
void
|
||||
doSendData(const Data& data) OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
|
||||
/** \brief send Nack
|
||||
*/
|
||||
void
|
||||
doSendNack(const ndn::lp::Nack& nack) OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
|
||||
/** \brief assign consecutive sequence numbers to LpPackets
|
||||
*/
|
||||
void
|
||||
assignSequences(std::vector<lp::Packet>& pkts);
|
||||
|
||||
private: // send path
|
||||
/** \brief encode link protocol fields from tags onto an outgoing LpPacket
|
||||
* \param netPkt network-layer packet to extract tags from
|
||||
@@ -211,16 +240,6 @@ private: // send path
|
||||
void
|
||||
sendNetPacket(lp::Packet&& pkt, bool isInterest);
|
||||
|
||||
/** \brief assign a sequence number to an LpPacket
|
||||
*/
|
||||
void
|
||||
assignSequence(lp::Packet& pkt);
|
||||
|
||||
/** \brief assign consecutive sequence numbers to LpPackets
|
||||
*/
|
||||
void
|
||||
assignSequences(std::vector<lp::Packet>& pkts);
|
||||
|
||||
/** \brief if the send queue is found to be congested, add a congestion mark to the packet
|
||||
* according to CoDel
|
||||
* \sa https://tools.ietf.org/html/rfc8289
|
||||
@@ -229,24 +248,24 @@ private: // send path
|
||||
checkCongestionLevel(lp::Packet& pkt);
|
||||
|
||||
private: // receive path
|
||||
/** \brief receive Packet from Transport
|
||||
*/
|
||||
void
|
||||
doReceivePacket(Transport::Packet&& packet) OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
doReceivePacket(const Block& packet, const EndpointId& endpoint) OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
|
||||
/** \brief decode incoming network-layer packet
|
||||
* \param netPkt reassembled network-layer packet
|
||||
* \param firstPkt LpPacket of first fragment
|
||||
* \param endpointId endpoint of peer who sent the packet
|
||||
*
|
||||
* If decoding is successful, a receive signal is emitted;
|
||||
* otherwise, a warning is logged.
|
||||
*/
|
||||
void
|
||||
decodeNetPacket(const Block& netPkt, const lp::Packet& firstPkt);
|
||||
decodeNetPacket(const Block& netPkt, const lp::Packet& firstPkt, const EndpointId& endpointId);
|
||||
|
||||
/** \brief decode incoming Interest
|
||||
* \param netPkt reassembled network-layer packet; TLV-TYPE must be Interest
|
||||
* \param firstPkt LpPacket of first fragment; must not have Nack field
|
||||
* \param endpointId endpoint of peer who sent the Interest
|
||||
*
|
||||
* If decoding is successful, receiveInterest signal is emitted;
|
||||
* otherwise, a warning is logged.
|
||||
@@ -254,11 +273,12 @@ private: // receive path
|
||||
* \throw tlv::Error parse error in an LpHeader field
|
||||
*/
|
||||
void
|
||||
decodeInterest(const Block& netPkt, const lp::Packet& firstPkt);
|
||||
decodeInterest(const Block& netPkt, const lp::Packet& firstPkt, const EndpointId& endpointId);
|
||||
|
||||
/** \brief decode incoming Interest
|
||||
* \param netPkt reassembled network-layer packet; TLV-TYPE must be Data
|
||||
* \param firstPkt LpPacket of first fragment
|
||||
* \param endpointId endpoint of peer who sent the Data
|
||||
*
|
||||
* If decoding is successful, receiveData signal is emitted;
|
||||
* otherwise, a warning is logged.
|
||||
@@ -266,11 +286,12 @@ private: // receive path
|
||||
* \throw tlv::Error parse error in an LpHeader field
|
||||
*/
|
||||
void
|
||||
decodeData(const Block& netPkt, const lp::Packet& firstPkt);
|
||||
decodeData(const Block& netPkt, const lp::Packet& firstPkt, const EndpointId& endpointId);
|
||||
|
||||
/** \brief decode incoming Interest
|
||||
* \param netPkt reassembled network-layer packet; TLV-TYPE must be Interest
|
||||
* \param firstPkt LpPacket of first fragment; must have Nack field
|
||||
* \param endpointId endpoint of peer who sent the Nack
|
||||
*
|
||||
* If decoding is successful, receiveNack signal is emitted;
|
||||
* otherwise, a warning is logged.
|
||||
@@ -278,7 +299,7 @@ private: // receive path
|
||||
* \throw tlv::Error parse error in an LpHeader field
|
||||
*/
|
||||
void
|
||||
decodeNack(const Block& netPkt, const lp::Packet& firstPkt);
|
||||
decodeNack(const Block& netPkt, const lp::Packet& firstPkt, const EndpointId& endpointId);
|
||||
|
||||
PROTECTED_WITH_TESTS_ELSE_PRIVATE:
|
||||
Options m_options;
|
||||
@@ -290,11 +311,12 @@ PROTECTED_WITH_TESTS_ELSE_PRIVATE:
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
/// Time to mark next packet due to send queue congestion
|
||||
time::steady_clock::TimePoint m_nextMarkTime;
|
||||
/// Time last packet was marked
|
||||
time::steady_clock::TimePoint m_lastMarkTime;
|
||||
/// number of marked packets in the current incident of congestion
|
||||
size_t m_nMarkedSinceInMarkingState;
|
||||
|
||||
GlobalSP globalSp;
|
||||
bool canScheduler = true;
|
||||
std::function<void(std::shared_ptr<VirtualQueueItem>)> sendPacketCallback;
|
||||
friend class LpReliability;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -46,21 +46,21 @@ InternalForwarderTransport::InternalForwarderTransport(const FaceUri& localUri,
|
||||
}
|
||||
|
||||
void
|
||||
InternalForwarderTransport::receivePacket(Block&& packet)
|
||||
InternalForwarderTransport::receivePacket(const Block& packet)
|
||||
{
|
||||
getGlobalIoService().post([this, pkt = std::move(packet)] () mutable {
|
||||
NFD_LOG_FACE_TRACE("Received: " << pkt.size() << " bytes");
|
||||
receive(Packet{std::move(pkt)});
|
||||
getGlobalIoService().post([this, packet] {
|
||||
NFD_LOG_FACE_TRACE("Received: " << packet.size() << " bytes");
|
||||
receive(packet);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
InternalForwarderTransport::doSend(Packet&& packet)
|
||||
InternalForwarderTransport::doSend(const Block& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE("Sending to " << m_peer);
|
||||
|
||||
if (m_peer)
|
||||
m_peer->receivePacket(std::move(packet.packet));
|
||||
m_peer->receivePacket(packet);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -104,12 +104,12 @@ InternalClientTransport::connectToForwarder(InternalForwarderTransport* forwarde
|
||||
}
|
||||
|
||||
void
|
||||
InternalClientTransport::receivePacket(Block&& packet)
|
||||
InternalClientTransport::receivePacket(const Block& packet)
|
||||
{
|
||||
getGlobalIoService().post([this, pkt = std::move(packet)] {
|
||||
NFD_LOG_TRACE("Received: " << pkt.size() << " bytes");
|
||||
getGlobalIoService().post([this, packet] {
|
||||
NFD_LOG_TRACE("Received: " << packet.size() << " bytes");
|
||||
if (m_receiveCallback) {
|
||||
m_receiveCallback(pkt);
|
||||
m_receiveCallback(packet);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -120,7 +120,7 @@ InternalClientTransport::send(const Block& wire)
|
||||
NFD_LOG_TRACE("Sending to " << m_forwarder);
|
||||
|
||||
if (m_forwarder)
|
||||
m_forwarder->receivePacket(Block{wire});
|
||||
m_forwarder->receivePacket(wire);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
~InternalTransportBase() = default;
|
||||
|
||||
virtual void
|
||||
receivePacket(Block&& packet) = 0;
|
||||
receivePacket(const Block& packet) = 0;
|
||||
};
|
||||
|
||||
/** \brief Implements a forwarder-side transport that can be paired with another transport.
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
receivePacket(Block&& packet) final;
|
||||
receivePacket(const Block& packet) final;
|
||||
|
||||
protected:
|
||||
void
|
||||
@@ -71,7 +71,7 @@ protected:
|
||||
|
||||
private:
|
||||
void
|
||||
doSend(Packet&& packet) final;
|
||||
doSend(const Block& packet) final;
|
||||
|
||||
private:
|
||||
NFD_LOG_MEMBER_DECL();
|
||||
@@ -98,7 +98,7 @@ public:
|
||||
connectToForwarder(InternalForwarderTransport* forwarder);
|
||||
|
||||
void
|
||||
receivePacket(Block&& packet) final;
|
||||
receivePacket(const Block& packet) final;
|
||||
|
||||
void
|
||||
send(const Block& wire) final;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -85,39 +85,39 @@ LinkService::sendNack(const ndn::lp::Nack& nack)
|
||||
}
|
||||
|
||||
void
|
||||
LinkService::receiveInterest(const Interest& interest)
|
||||
LinkService::receiveInterest(const Interest& interest, const EndpointId& endpoint)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
++this->nInInterests;
|
||||
|
||||
afterReceiveInterest(interest);
|
||||
afterReceiveInterest(interest, endpoint);
|
||||
}
|
||||
|
||||
void
|
||||
LinkService::receiveData(const Data& data)
|
||||
LinkService::receiveData(const Data& data, const EndpointId& endpoint)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
++this->nInData;
|
||||
|
||||
afterReceiveData(data);
|
||||
afterReceiveData(data, endpoint);
|
||||
}
|
||||
|
||||
void
|
||||
LinkService::receiveNack(const ndn::lp::Nack& nack)
|
||||
LinkService::receiveNack(const ndn::lp::Nack& nack, const EndpointId& endpoint)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
++this->nInNacks;
|
||||
|
||||
afterReceiveNack(nack);
|
||||
afterReceiveNack(nack, endpoint);
|
||||
}
|
||||
|
||||
void
|
||||
LinkService::notifyDroppedInterest(const Interest& interest)
|
||||
{
|
||||
++this->nDroppedInterests;
|
||||
++this->nInterestsExceededRetx;
|
||||
onDroppedInterest(interest);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,15 +26,13 @@
|
||||
#ifndef NFD_DAEMON_FACE_LINK_SERVICE_HPP
|
||||
#define NFD_DAEMON_FACE_LINK_SERVICE_HPP
|
||||
|
||||
#include "face-log.hpp"
|
||||
#include "face-common.hpp"
|
||||
#include "transport.hpp"
|
||||
#include "common/counter.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
class Face;
|
||||
|
||||
/** \brief counters provided by LinkService
|
||||
* \note The type name 'LinkServiceCounters' is implementation detail.
|
||||
* Use 'LinkService::Counters' in public API.
|
||||
@@ -52,7 +50,7 @@ public:
|
||||
|
||||
/** \brief count of Interests dropped by reliability system for exceeding allowed number of retx
|
||||
*/
|
||||
PacketCounter nDroppedInterests;
|
||||
PacketCounter nInterestsExceededRetx;
|
||||
|
||||
/** \brief count of incoming Data packets
|
||||
*/
|
||||
@@ -111,20 +109,23 @@ public:
|
||||
virtual const Counters&
|
||||
getCounters() const;
|
||||
|
||||
virtual ssize_t
|
||||
getEffectiveMtu() const;
|
||||
|
||||
public: // upper interface to be used by forwarding
|
||||
/** \brief send Interest
|
||||
/** \brief Send Interest
|
||||
* \pre setTransport has been called
|
||||
*/
|
||||
void
|
||||
sendInterest(const Interest& interest);
|
||||
|
||||
/** \brief send Data
|
||||
/** \brief Send Data
|
||||
* \pre setTransport has been called
|
||||
*/
|
||||
void
|
||||
sendData(const Data& data);
|
||||
|
||||
/** \brief send Nack
|
||||
/** \brief Send Nack
|
||||
* \pre setTransport has been called
|
||||
*/
|
||||
void
|
||||
@@ -132,15 +133,15 @@ public: // upper interface to be used by forwarding
|
||||
|
||||
/** \brief signals on Interest received
|
||||
*/
|
||||
signal::Signal<LinkService, Interest> afterReceiveInterest;
|
||||
signal::Signal<LinkService, Interest, EndpointId> afterReceiveInterest;
|
||||
|
||||
/** \brief signals on Data received
|
||||
*/
|
||||
signal::Signal<LinkService, Data> afterReceiveData;
|
||||
signal::Signal<LinkService, Data, EndpointId> afterReceiveData;
|
||||
|
||||
/** \brief signals on Nack received
|
||||
*/
|
||||
signal::Signal<LinkService, lp::Nack> afterReceiveNack;
|
||||
signal::Signal<LinkService, lp::Nack, EndpointId> afterReceiveNack;
|
||||
|
||||
/** \brief signals on Interest dropped by reliability system for exceeding allowed number of retx
|
||||
*/
|
||||
@@ -150,29 +151,29 @@ public: // lower interface to be invoked by Transport
|
||||
/** \brief performs LinkService specific operations to receive a lower-layer packet
|
||||
*/
|
||||
void
|
||||
receivePacket(Transport::Packet&& packet);
|
||||
receivePacket(const Block& packet, const EndpointId& endpoint);
|
||||
|
||||
protected: // upper interface to be invoked in subclass (receive path termination)
|
||||
/** \brief delivers received Interest to forwarding
|
||||
*/
|
||||
void
|
||||
receiveInterest(const Interest& interest);
|
||||
receiveInterest(const Interest& interest, const EndpointId& endpoint);
|
||||
|
||||
/** \brief delivers received Data to forwarding
|
||||
*/
|
||||
void
|
||||
receiveData(const Data& data);
|
||||
receiveData(const Data& data, const EndpointId& endpoint);
|
||||
|
||||
/** \brief delivers received Nack to forwarding
|
||||
*/
|
||||
void
|
||||
receiveNack(const lp::Nack& nack);
|
||||
receiveNack(const lp::Nack& nack, const EndpointId& endpoint);
|
||||
|
||||
protected: // lower interface to be invoked in subclass (send path termination)
|
||||
/** \brief sends a lower-layer packet via Transport
|
||||
/** \brief send a lower-layer packet via Transport
|
||||
*/
|
||||
void
|
||||
sendPacket(Transport::Packet&& packet);
|
||||
sendPacket(const Block& packet);
|
||||
|
||||
protected:
|
||||
void
|
||||
@@ -196,7 +197,7 @@ private: // upper interface to be overridden in subclass (send path entrypoint)
|
||||
|
||||
private: // lower interface to be overridden in subclass
|
||||
virtual void
|
||||
doReceivePacket(Transport::Packet&& packet) = 0;
|
||||
doReceivePacket(const Block& packet, const EndpointId& endpoint) = 0;
|
||||
|
||||
private:
|
||||
Face* m_face;
|
||||
@@ -227,16 +228,22 @@ LinkService::getCounters() const
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void
|
||||
LinkService::receivePacket(Transport::Packet&& packet)
|
||||
inline ssize_t
|
||||
LinkService::getEffectiveMtu() const
|
||||
{
|
||||
doReceivePacket(std::move(packet));
|
||||
return m_transport->getMtu();
|
||||
}
|
||||
|
||||
inline void
|
||||
LinkService::sendPacket(Transport::Packet&& packet)
|
||||
LinkService::receivePacket(const Block& packet, const EndpointId& endpoint)
|
||||
{
|
||||
m_transport->send(std::move(packet));
|
||||
doReceivePacket(packet, endpoint);
|
||||
}
|
||||
|
||||
inline void
|
||||
LinkService::sendPacket(const Block& packet)
|
||||
{
|
||||
m_transport->send(packet);
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,16 +26,13 @@
|
||||
#ifndef NFD_DAEMON_FACE_LP_FRAGMENTER_HPP
|
||||
#define NFD_DAEMON_FACE_LP_FRAGMENTER_HPP
|
||||
|
||||
#include "core/common.hpp"
|
||||
#include "face-log.hpp"
|
||||
#include "face-common.hpp"
|
||||
|
||||
#include <ndn-cxx/lp/packet.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
class LinkService;
|
||||
|
||||
/** \brief fragments network-layer packets into NDNLPv2 link-layer packets
|
||||
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
|
||||
*/
|
||||
|
||||
@@ -26,16 +26,13 @@
|
||||
#ifndef NFD_DAEMON_FACE_LP_REASSEMBLER_HPP
|
||||
#define NFD_DAEMON_FACE_LP_REASSEMBLER_HPP
|
||||
|
||||
#include "face-log.hpp"
|
||||
#include "transport.hpp"
|
||||
#include "face-common.hpp"
|
||||
|
||||
#include <ndn-cxx/lp/packet.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
class LinkService;
|
||||
|
||||
/** \brief reassembles fragmented network-layer packets
|
||||
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
|
||||
*/
|
||||
@@ -72,13 +69,13 @@ public:
|
||||
const LinkService*
|
||||
getLinkService() const;
|
||||
|
||||
/** \brief adds received fragment to buffer
|
||||
* \param remoteEndpoint endpoint whose sends the packet
|
||||
* \param packet received fragment;
|
||||
* must have Fragment field
|
||||
* \return whether network-layer packet has been completely received,
|
||||
/** \brief adds received fragment to the buffer
|
||||
* \param remoteEndpoint endpoint that sent the packet
|
||||
* \param packet received fragment; must have Fragment field
|
||||
* \return a tuple containing:
|
||||
* whether a network-layer packet has been completely received,
|
||||
* the reassembled network-layer packet,
|
||||
* and the first fragment for inspecting other NDNLPv2 headers
|
||||
* the first fragment for inspecting other NDNLPv2 headers
|
||||
* \throw tlv::Error packet is malformed
|
||||
*/
|
||||
std::tuple<bool, Block, lp::Packet>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -31,12 +31,13 @@
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
NFD_LOG_INIT(LpReliability);
|
||||
|
||||
LpReliability::LpReliability(const LpReliability::Options& options, GenericLinkService* linkService)
|
||||
: m_options(options)
|
||||
, m_linkService(linkService)
|
||||
, m_firstUnackedFrag(m_unackedFrags.begin())
|
||||
, m_lastTxSeqNo(-1) // set to "-1" to start TxSequence numbers at 0
|
||||
, m_isIdleAckTimerRunning(false)
|
||||
{
|
||||
BOOST_ASSERT(m_linkService != nullptr);
|
||||
BOOST_ASSERT(m_options.idleAckTimerPeriod > 0_ns);
|
||||
@@ -48,7 +49,7 @@ LpReliability::setOptions(const Options& options)
|
||||
BOOST_ASSERT(options.idleAckTimerPeriod > 0_ns);
|
||||
|
||||
if (m_options.isEnabled && !options.isEnabled) {
|
||||
this->stopIdleAckTimer();
|
||||
m_idleAckTimer.cancel();
|
||||
}
|
||||
|
||||
m_options = options;
|
||||
@@ -72,6 +73,9 @@ LpReliability::handleOutgoing(std::vector<lp::Packet>& frags, lp::Packet&& pkt,
|
||||
netPkt->unackedFrags.reserve(frags.size());
|
||||
|
||||
for (lp::Packet& frag : frags) {
|
||||
// Non-IDLE packets are required to have assigned Sequence numbers with LpReliability enabled
|
||||
BOOST_ASSERT(frag.has<lp::SequenceField>());
|
||||
|
||||
// Assign TxSequence number
|
||||
lp::Sequence txSeq = assignTxSequence(frag);
|
||||
|
||||
@@ -81,8 +85,13 @@ LpReliability::handleOutgoing(std::vector<lp::Packet>& frags, lp::Packet&& pkt,
|
||||
std::forward_as_tuple(txSeq),
|
||||
std::forward_as_tuple(frag));
|
||||
unackedFragsIt->second.sendTime = sendTime;
|
||||
unackedFragsIt->second.rtoTimer = getScheduler().schedule(m_rto.computeRto(),
|
||||
[=] { onLpPacketLost(txSeq); });
|
||||
auto rto = m_rttEst.getEstimatedRto();
|
||||
lp::Sequence seq = frag.get<lp::SequenceField>();
|
||||
NFD_LOG_FACE_TRACE("transmitting seq=" << seq << ", txseq=" << txSeq << ", rto=" <<
|
||||
time::duration_cast<time::milliseconds>(rto).count() << "ms");
|
||||
unackedFragsIt->second.rtoTimer = getScheduler().schedule(rto, [=] {
|
||||
onLpPacketLost(txSeq, true);
|
||||
});
|
||||
unackedFragsIt->second.netPkt = netPkt;
|
||||
|
||||
if (m_unackedFrags.size() == 1) {
|
||||
@@ -94,18 +103,20 @@ LpReliability::handleOutgoing(std::vector<lp::Packet>& frags, lp::Packet&& pkt,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
LpReliability::processIncomingPacket(const lp::Packet& pkt)
|
||||
{
|
||||
BOOST_ASSERT(m_options.isEnabled);
|
||||
|
||||
bool isDuplicate = false;
|
||||
auto now = time::steady_clock::now();
|
||||
|
||||
// Extract and parse Acks
|
||||
for (lp::Sequence ackSeq : pkt.list<lp::AckField>()) {
|
||||
auto fragIt = m_unackedFrags.find(ackSeq);
|
||||
for (lp::Sequence ackTxSeq : pkt.list<lp::AckField>()) {
|
||||
auto fragIt = m_unackedFrags.find(ackTxSeq);
|
||||
if (fragIt == m_unackedFrags.end()) {
|
||||
// Ignore an Ack for an unknown TxSequence number
|
||||
NFD_LOG_FACE_DEBUG("received ack for unknown txseq=" << ackTxSeq);
|
||||
continue;
|
||||
}
|
||||
auto& frag = fragIt->second;
|
||||
@@ -114,12 +125,19 @@ LpReliability::processIncomingPacket(const lp::Packet& pkt)
|
||||
frag.rtoTimer.cancel();
|
||||
|
||||
if (frag.retxCount == 0) {
|
||||
// This sequence had no retransmissions, so use it to calculate the RTO
|
||||
m_rto.addMeasurement(time::duration_cast<RttEstimator::Duration>(now - frag.sendTime));
|
||||
NFD_LOG_FACE_TRACE("received ack for seq=" << frag.pkt.get<lp::SequenceField>() << ", txseq=" <<
|
||||
ackTxSeq << ", retx=0, rtt=" <<
|
||||
time::duration_cast<time::milliseconds>(now - frag.sendTime).count() << "ms");
|
||||
// This sequence had no retransmissions, so use it to estimate the RTO
|
||||
m_rttEst.addMeasurement(now - frag.sendTime);
|
||||
}
|
||||
else {
|
||||
NFD_LOG_FACE_TRACE("received ack for seq=" << frag.pkt.get<lp::SequenceField>() << ", txseq=" <<
|
||||
ackTxSeq << ", retx=" << frag.retxCount);
|
||||
}
|
||||
|
||||
// Look for frags with TxSequence numbers < ackSeq (allowing for wraparound) and consider them
|
||||
// lost if a configurable number of Acks containing greater TxSequence numbers have been
|
||||
// Look for frags with TxSequence numbers < ackTxSeq (allowing for wraparound) and consider
|
||||
// them lost if a configurable number of Acks containing greater TxSequence numbers have been
|
||||
// received.
|
||||
auto lostLpPackets = findLostLpPackets(fragIt);
|
||||
|
||||
@@ -136,8 +154,8 @@ LpReliability::processIncomingPacket(const lp::Packet& pkt)
|
||||
// Resend or fail fragments considered lost. Potentially increment the start of the window.
|
||||
for (lp::Sequence txSeq : lostLpPackets) {
|
||||
if (removedLpPackets.find(txSeq) == removedLpPackets.end()) {
|
||||
auto removedThisTxSeq = this->onLpPacketLost(txSeq);
|
||||
for (auto removedTxSeq : removedThisTxSeq) {
|
||||
auto removedTxSeqs = onLpPacketLost(txSeq, false);
|
||||
for (auto removedTxSeq : removedTxSeqs) {
|
||||
removedLpPackets.insert(removedTxSeq);
|
||||
}
|
||||
}
|
||||
@@ -146,11 +164,29 @@ LpReliability::processIncomingPacket(const lp::Packet& pkt)
|
||||
|
||||
// If packet has Fragment and TxSequence fields, extract TxSequence and add to AckQueue
|
||||
if (pkt.has<lp::FragmentField>() && pkt.has<lp::TxSequenceField>()) {
|
||||
NFD_LOG_FACE_TRACE("queueing ack for remote txseq=" << pkt.get<lp::TxSequenceField>());
|
||||
m_ackQueue.push(pkt.get<lp::TxSequenceField>());
|
||||
if (!m_isIdleAckTimerRunning) {
|
||||
this->startIdleAckTimer();
|
||||
|
||||
// Check for received frames with duplicate Sequences
|
||||
if (pkt.has<lp::SequenceField>()) {
|
||||
lp::Sequence pktSequence = pkt.get<lp::SequenceField>();
|
||||
isDuplicate = m_recentRecvSeqs.count(pktSequence) > 0;
|
||||
// Check for recent received Sequences to remove
|
||||
auto now = time::steady_clock::now();
|
||||
auto rto = m_rttEst.getEstimatedRto();
|
||||
while (m_recentRecvSeqsQueue.size() > 0 &&
|
||||
now > m_recentRecvSeqs[m_recentRecvSeqsQueue.front()] + rto) {
|
||||
m_recentRecvSeqs.erase(m_recentRecvSeqsQueue.front());
|
||||
m_recentRecvSeqsQueue.pop();
|
||||
}
|
||||
m_recentRecvSeqs.emplace(pktSequence, now);
|
||||
m_recentRecvSeqsQueue.push(pktSequence);
|
||||
}
|
||||
|
||||
startIdleAckTimer();
|
||||
}
|
||||
|
||||
return !isDuplicate;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -167,8 +203,8 @@ LpReliability::piggyback(lp::Packet& pkt, ssize_t mtu)
|
||||
remainingSpace -= pktSize;
|
||||
|
||||
while (!m_ackQueue.empty()) {
|
||||
lp::Sequence ackSeq = m_ackQueue.front();
|
||||
// Ack size = Ack TLV-TYPE (3 octets) + TLV-LENGTH (1 octet) + uint64_t (8 octets)
|
||||
lp::Sequence ackTxSeq = m_ackQueue.front();
|
||||
// Ack size = Ack TLV-TYPE (3 octets) + TLV-LENGTH (1 octet) + lp::Sequence (8 octets)
|
||||
const ssize_t ackSize = tlv::sizeOfVarNumber(lp::tlv::Ack) +
|
||||
tlv::sizeOfVarNumber(sizeof(lp::Sequence)) +
|
||||
sizeof(lp::Sequence);
|
||||
@@ -177,7 +213,9 @@ LpReliability::piggyback(lp::Packet& pkt, ssize_t mtu)
|
||||
break;
|
||||
}
|
||||
|
||||
pkt.add<lp::AckField>(ackSeq);
|
||||
NFD_LOG_FACE_TRACE("piggybacking ack for remote txseq=" << ackTxSeq);
|
||||
|
||||
pkt.add<lp::AckField>(ackTxSeq);
|
||||
m_ackQueue.pop();
|
||||
remainingSpace -= ackSize;
|
||||
}
|
||||
@@ -197,25 +235,18 @@ LpReliability::assignTxSequence(lp::Packet& frag)
|
||||
void
|
||||
LpReliability::startIdleAckTimer()
|
||||
{
|
||||
BOOST_ASSERT(!m_isIdleAckTimerRunning);
|
||||
m_isIdleAckTimerRunning = true;
|
||||
if (m_idleAckTimer) {
|
||||
// timer is already running, do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
m_idleAckTimer = getScheduler().schedule(m_options.idleAckTimerPeriod, [this] {
|
||||
while (!m_ackQueue.empty()) {
|
||||
m_linkService->requestIdlePacket();
|
||||
}
|
||||
|
||||
m_isIdleAckTimerRunning = false;
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
LpReliability::stopIdleAckTimer()
|
||||
{
|
||||
m_idleAckTimer.cancel();
|
||||
m_isIdleAckTimerRunning = false;
|
||||
}
|
||||
|
||||
std::vector<lp::Sequence>
|
||||
LpReliability::findLostLpPackets(LpReliability::UnackedFrags::iterator ackIt)
|
||||
{
|
||||
@@ -232,6 +263,8 @@ LpReliability::findLostLpPackets(LpReliability::UnackedFrags::iterator ackIt)
|
||||
|
||||
auto& unackedFrag = it->second;
|
||||
unackedFrag.nGreaterSeqAcks++;
|
||||
NFD_LOG_FACE_TRACE("received ack=" << ackIt->first << " before=" << it->first <<
|
||||
", before count=" << unackedFrag.nGreaterSeqAcks);
|
||||
|
||||
if (unackedFrag.nGreaterSeqAcks >= m_options.seqNumLossThreshold) {
|
||||
lostLpPackets.push_back(it->first);
|
||||
@@ -242,7 +275,7 @@ LpReliability::findLostLpPackets(LpReliability::UnackedFrags::iterator ackIt)
|
||||
}
|
||||
|
||||
std::vector<lp::Sequence>
|
||||
LpReliability::onLpPacketLost(lp::Sequence txSeq)
|
||||
LpReliability::onLpPacketLost(lp::Sequence txSeq, bool isTimeout)
|
||||
{
|
||||
BOOST_ASSERT(m_unackedFrags.count(txSeq) > 0);
|
||||
auto txSeqIt = m_unackedFrags.find(txSeq);
|
||||
@@ -251,9 +284,19 @@ LpReliability::onLpPacketLost(lp::Sequence txSeq)
|
||||
txFrag.rtoTimer.cancel();
|
||||
auto netPkt = txFrag.netPkt;
|
||||
std::vector<lp::Sequence> removedThisTxSeq;
|
||||
lp::Sequence seq = txFrag.pkt.get<lp::SequenceField>();
|
||||
|
||||
if (isTimeout) {
|
||||
NFD_LOG_FACE_TRACE("rto timer expired for seq=" << seq << ", txseq=" << txSeq);
|
||||
}
|
||||
else { // lost due to out-of-order TxSeqs
|
||||
NFD_LOG_FACE_TRACE("seq=" << seq << ", txseq=" << txSeq <<
|
||||
" considered lost from acks for more recent txseqs");
|
||||
}
|
||||
|
||||
// Check if maximum number of retransmissions exceeded
|
||||
if (txFrag.retxCount >= m_options.maxRetx) {
|
||||
NFD_LOG_FACE_DEBUG("seq=" << seq << " exceeded allowed retransmissions: DROP");
|
||||
// Delete all LpPackets of NetPkt from m_unackedFrags (except this one)
|
||||
for (size_t i = 0; i < netPkt->unackedFrags.size(); i++) {
|
||||
if (netPkt->unackedFrags[i] != txSeqIt) {
|
||||
@@ -273,6 +316,7 @@ LpReliability::onLpPacketLost(lp::Sequence txSeq)
|
||||
onDroppedInterest(Interest(frag));
|
||||
}
|
||||
|
||||
// Delete this LpPacket from m_unackedFrags
|
||||
removedThisTxSeq.push_back(txSeqIt->first);
|
||||
deleteUnackedFrag(txSeqIt);
|
||||
}
|
||||
@@ -304,8 +348,15 @@ LpReliability::onLpPacketLost(lp::Sequence txSeq)
|
||||
// Retransmit fragment
|
||||
m_linkService->sendLpPacket(lp::Packet(newTxFrag.pkt));
|
||||
|
||||
auto rto = m_rttEst.getEstimatedRto();
|
||||
NFD_LOG_FACE_TRACE("retransmitting seq=" << seq << ", txseq=" << newTxSeq << ", retx=" <<
|
||||
txFrag.retxCount << ", rto=" <<
|
||||
time::duration_cast<time::milliseconds>(rto).count() << "ms");
|
||||
|
||||
// Start RTO timer for this sequence
|
||||
newTxFrag.rtoTimer = getScheduler().schedule(m_rto.computeRto(), [=] { onLpPacketLost(newTxSeq); });
|
||||
newTxFrag.rtoTimer = getScheduler().schedule(rto, [=] {
|
||||
onLpPacketLost(newTxSeq, true);
|
||||
});
|
||||
}
|
||||
|
||||
return removedThisTxSeq;
|
||||
@@ -371,5 +422,17 @@ LpReliability::NetPkt::NetPkt(lp::Packet&& pkt, bool isInterest)
|
||||
{
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const FaceLogHelper<LpReliability>& flh)
|
||||
{
|
||||
if (flh.obj.getLinkService() == nullptr) {
|
||||
os << "[id=0,local=unknown,remote=unknown] ";
|
||||
}
|
||||
else {
|
||||
os << FaceLogHelper<LinkService>(*flh.obj.getLinkService());
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,10 +26,11 @@
|
||||
#ifndef NFD_DAEMON_FACE_LP_RELIABILITY_HPP
|
||||
#define NFD_DAEMON_FACE_LP_RELIABILITY_HPP
|
||||
|
||||
#include "core/rtt-estimator.hpp"
|
||||
#include "face-common.hpp"
|
||||
|
||||
#include <ndn-cxx/lp/packet.hpp>
|
||||
#include <ndn-cxx/lp/sequence.hpp>
|
||||
#include <ndn-cxx/util/rtt-estimator.hpp>
|
||||
|
||||
#include <queue>
|
||||
|
||||
@@ -92,8 +93,9 @@ public:
|
||||
|
||||
/** \brief extract and parse all Acks and add Ack for contained Fragment (if any) to AckQueue
|
||||
* \param pkt incoming LpPacket
|
||||
* \return whether incoming LpPacket is new and not a duplicate
|
||||
*/
|
||||
void
|
||||
bool
|
||||
processIncomingPacket(const lp::Packet& pkt);
|
||||
|
||||
/** \brief called by GenericLinkService to attach Acks onto an outgoing LpPacket
|
||||
@@ -126,11 +128,6 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
void
|
||||
startIdleAckTimer();
|
||||
|
||||
/** \brief cancel the idle Ack timer
|
||||
*/
|
||||
void
|
||||
stopIdleAckTimer();
|
||||
|
||||
/** \brief find and mark as lost fragments where a configurable number of Acks
|
||||
* (\p m_options.seqNumLossThreshold) have been received for greater TxSequence numbers
|
||||
* \param ackIt iterator pointing to acknowledged fragment
|
||||
@@ -143,7 +140,7 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
* \return vector of the TxSequences of fragments removed due to a network packet being removed
|
||||
*/
|
||||
std::vector<lp::Sequence>
|
||||
onLpPacketLost(lp::Sequence txSeq);
|
||||
onLpPacketLost(lp::Sequence txSeq, bool isTimeout);
|
||||
|
||||
/** \brief remove the fragment with the given sequence number from the map of unacknowledged
|
||||
* fragments, as well as its associated network packet (if any)
|
||||
@@ -198,8 +195,10 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
};
|
||||
|
||||
public:
|
||||
/// TxSequence TLV-TYPE (3 octets) + TxSequence TLV-LENGTH (1 octet) + sizeof(lp::Sequence)
|
||||
static constexpr size_t RESERVED_HEADER_SPACE = 3 + 1 + sizeof(lp::Sequence);
|
||||
/// TxSequence TLV-TYPE (3 octets) + TLV-LENGTH (1 octet) + lp::Sequence (8 octets)
|
||||
static constexpr size_t RESERVED_HEADER_SPACE = tlv::sizeOfVarNumber(lp::tlv::TxSequence) +
|
||||
tlv::sizeOfVarNumber(sizeof(lp::Sequence)) +
|
||||
sizeof(lp::Sequence);
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
Options m_options;
|
||||
@@ -212,12 +211,16 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
*/
|
||||
UnackedFrags::iterator m_firstUnackedFrag;
|
||||
std::queue<lp::Sequence> m_ackQueue;
|
||||
std::map<lp::Sequence, time::steady_clock::TimePoint> m_recentRecvSeqs;
|
||||
std::queue<lp::Sequence> m_recentRecvSeqsQueue;
|
||||
lp::Sequence m_lastTxSeqNo;
|
||||
scheduler::ScopedEventId m_idleAckTimer;
|
||||
bool m_isIdleAckTimerRunning;
|
||||
RttEstimator m_rto;
|
||||
ndn::util::RttEstimator m_rttEst;
|
||||
};
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const FaceLogHelper<LpReliability>& flh);
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -82,13 +82,13 @@ MulticastUdpTransport::getSendQueueLength()
|
||||
}
|
||||
|
||||
void
|
||||
MulticastUdpTransport::doSend(Transport::Packet&& packet)
|
||||
MulticastUdpTransport::doSend(const Block& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
m_sendSocket.async_send_to(boost::asio::buffer(packet.packet), m_multicastGroup,
|
||||
// packet.packet is copied into the lambda to retain the underlying Buffer
|
||||
[this, p = packet.packet] (auto&&... args) {
|
||||
m_sendSocket.async_send_to(boost::asio::buffer(packet), m_multicastGroup,
|
||||
// 'packet' is copied into the lambda to retain the underlying Buffer
|
||||
[this, packet] (auto&&... args) {
|
||||
this->handleSend(std::forward<decltype(args)>(args)...);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -52,11 +52,7 @@ public:
|
||||
class Error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Error(const std::string& what)
|
||||
: std::runtime_error(what)
|
||||
{
|
||||
}
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -88,7 +84,7 @@ public:
|
||||
|
||||
private:
|
||||
void
|
||||
doSend(Transport::Packet&& packet) final;
|
||||
doSend(const Block& packet) final;
|
||||
|
||||
void
|
||||
doClose() final;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -52,7 +52,7 @@ private:
|
||||
}
|
||||
|
||||
void
|
||||
doReceivePacket(Transport::Packet&&) final
|
||||
doReceivePacket(const Block&, const EndpointId&) final
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -51,7 +51,7 @@ protected:
|
||||
|
||||
private:
|
||||
void
|
||||
doSend(Packet&&) OVERRIDE_WITH_TESTS_ELSE_FINAL
|
||||
doSend(const Block&) OVERRIDE_WITH_TESTS_ELSE_FINAL
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "pcap-helper.hpp"
|
||||
#include "ethernet-protocol.hpp"
|
||||
|
||||
#include <pcap/pcap.h>
|
||||
#include <unistd.h>
|
||||
@@ -49,6 +50,9 @@ PcapHelper::PcapHelper(const std::string& interfaceName)
|
||||
// even if the kernel supports it, thus preventing bug #1511.
|
||||
if (pcap_set_immediate_mode(m_pcap, 1) < 0)
|
||||
NDN_THROW(Error("pcap_set_immediate_mode failed"));
|
||||
|
||||
pcap_set_snaplen(m_pcap, ethernet::HDR_LEN + ndn::MAX_NDN_PACKET_SIZE);
|
||||
pcap_set_buffer_size(m_pcap, 4 * 1024 * 1024);
|
||||
}
|
||||
|
||||
PcapHelper::~PcapHelper()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -27,11 +27,11 @@
|
||||
#define NFD_DAEMON_FACE_PROTOCOL_FACTORY_HPP
|
||||
|
||||
#include "channel.hpp"
|
||||
#include "face.hpp"
|
||||
#include "face-system.hpp"
|
||||
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
#include <ndn-cxx/encoding/nfd-constants.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
@@ -0,0 +1,534 @@
|
||||
#include "queues.hpp"
|
||||
#include "common/global.hpp"
|
||||
#include <ndn-cxx/encoding/estimator.hpp>
|
||||
namespace nfd
|
||||
{
|
||||
namespace face
|
||||
{
|
||||
NFD_LOG_INIT(QSCCPQueue);
|
||||
bool VirtualQueue::push(int seq, const std::shared_ptr<const Interest> &interest,
|
||||
uint64_t dataSize, bool needInsert)
|
||||
{
|
||||
this->recvBits += dataSize;
|
||||
if (!needInsert)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (this->currentSize >= this->size)
|
||||
{
|
||||
|
||||
return false;
|
||||
}
|
||||
this->lastSeq = seq;
|
||||
VirtualQueueItem vqi;
|
||||
vqi.seq = seq;
|
||||
vqi.item = interest;
|
||||
vqi.queue = shared_from_this();
|
||||
vqi.dataSize = dataSize;
|
||||
this->innerQueue.push_back(vqi);
|
||||
this->currentSize++;
|
||||
auto serviceClass = interest->getServiceClass();
|
||||
if (serviceClass && *serviceClass > 7)
|
||||
{
|
||||
this->penaltyFactor = 0.5;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
WDRRQueue::WDRRQueue(uint32_t rateLimit, uint32_t availableBandwidth, double weight, const std::string &name,
|
||||
uint32_t tos, size_t vqSize) : availableBandwidth(availableBandwidth),
|
||||
weight(weight), name(name), tos(tos), vqSize(vqSize)
|
||||
{
|
||||
|
||||
if (rateLimit > 0)
|
||||
{
|
||||
this->needRateLimit = true;
|
||||
this->tokenBucket = std::make_shared<TokenBucket>(rateLimit, 20 * 1000 * 8, name);
|
||||
// this->tokenBucket->start();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->needRateLimit = false;
|
||||
}
|
||||
}
|
||||
void WDRRQueue::updateAvailableBandwidth(uint32_t C)
|
||||
{
|
||||
this->availableBandwidth = C;
|
||||
}
|
||||
bool WDRRQueue::appendInterest(const Interest &interest)
|
||||
{
|
||||
std::string key = interest.getName().getPrefix(1).toUri();
|
||||
if (this->virtualQueues.count(key) == 0)
|
||||
{
|
||||
this->virtualQueues[key] = std::make_shared<VirtualQueue>(1, this->vqSize);
|
||||
this->virtualQueues[key]->tos = this->tos;
|
||||
this->flows.push_back(key);
|
||||
this->totalWeight += 1;
|
||||
for (auto &item : this->virtualQueues)
|
||||
{
|
||||
item.second->objectRate = this->availableBandwidth * item.second->weight / this->totalWeight;
|
||||
item.second->objectRate = item.second->objectRate * item.second->penaltyFactor;
|
||||
}
|
||||
}
|
||||
bool needInsert = true;
|
||||
if (this->cdt > 0 && this->currentPacketNum >= this->cdt)
|
||||
{
|
||||
|
||||
needInsert = false;
|
||||
}
|
||||
uint64_t dataSize = 9000;
|
||||
auto dsz = interest.getDsz();
|
||||
if (dsz)
|
||||
{
|
||||
dataSize = *dsz;
|
||||
}
|
||||
this->recvBits += dataSize;
|
||||
auto success = this->virtualQueues[key]->push(0, interest.shared_from_this(), dataSize, needInsert);
|
||||
if (success)
|
||||
{
|
||||
this->currentPacketNum++;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
std::shared_ptr<VirtualQueueItem> WDRRQueue::scheduleNext()
|
||||
{
|
||||
if (this->nextScheduleQueue >= this->flows.size())
|
||||
{
|
||||
for (auto &key : this->flows)
|
||||
{
|
||||
if (this->virtualQueues.count(key) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
auto &item = this->virtualQueues[key];
|
||||
item->balance += item->weight * item->penaltyFactor * this->MTU_QUANTA;
|
||||
}
|
||||
this->nextScheduleQueue = 0;
|
||||
}
|
||||
std::shared_ptr<VirtualQueue> selectedVQ = nullptr;
|
||||
for (; this->nextScheduleQueue < this->flows.size(); this->nextScheduleQueue++)
|
||||
{
|
||||
auto &item = this->virtualQueues[this->flows[this->nextScheduleQueue]];
|
||||
if (item->empty())
|
||||
{
|
||||
item->balance = 0;
|
||||
continue;
|
||||
}
|
||||
if (item->front().dataSize < item->balance)
|
||||
{
|
||||
selectedVQ = item;
|
||||
break;
|
||||
}
|
||||
if (item->len() > 10)
|
||||
{
|
||||
}
|
||||
}
|
||||
if (selectedVQ == nullptr && this->currentPacketNum > 0)
|
||||
{
|
||||
return scheduleNext();
|
||||
}
|
||||
if (selectedVQ != nullptr)
|
||||
{
|
||||
if (needRateLimit && !this->tokenBucket->use(selectedVQ->front().dataSize))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
auto item = std::make_shared<VirtualQueueItem>(selectedVQ->front());
|
||||
selectedVQ->balance -= item->dataSize;
|
||||
selectedVQ->pop();
|
||||
if (selectedVQ->penaltyFactor < 0.9)
|
||||
{
|
||||
item->item->setServiceClass(selectedVQ->tos + 8);
|
||||
}
|
||||
this->sendBits += item->dataSize;
|
||||
this->currentPacketNum--;
|
||||
return item;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
uint32_t WDRRQueue::calObjectRate(bool getCurrentRateOnly)
|
||||
{
|
||||
uint32_t currentRate = this->recvBits * 1000 / this->calObjectRateInterval;
|
||||
uint32_t currentSendRate = this->sendBits * 1000 / this->calObjectRateInterval;
|
||||
if (getCurrentRateOnly)
|
||||
{
|
||||
return currentRate;
|
||||
}
|
||||
// if (currentRate > 0) {
|
||||
// std::cout << "currentRate: " << currentRate << ", " << this->recvBits << "," << this->calObjectRateInterval << ", AvaliableBandwidth: " << this->availableBandwidth << std::endl;
|
||||
// }
|
||||
bool hasCleanFlow = false;
|
||||
for (auto it = this->virtualQueues.begin(); it != this->virtualQueues.end();)
|
||||
{
|
||||
// std::cout << "key: " << it->first << ", recvBits" << it->second->recvBits << std::endl;
|
||||
if (it->second->recvBits == 0 && it->second->empty())
|
||||
{
|
||||
this->totalWeight -= it->second->weight;
|
||||
this->virtualQueues.erase(it++); // here is the key
|
||||
// std::cout << "do clean: " << std::endl;
|
||||
hasCleanFlow = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
it++;
|
||||
}
|
||||
}
|
||||
if (hasCleanFlow)
|
||||
{
|
||||
this->flows.resize(this->virtualQueues.size());
|
||||
int idx = 0;
|
||||
for (auto it = this->virtualQueues.begin(); it != this->virtualQueues.end(); it++, idx++)
|
||||
{
|
||||
this->flows[idx] = it->first;
|
||||
}
|
||||
}
|
||||
double totalHightSpeedFlowWeight = 0;
|
||||
int hightSppedFlowNum = 0;
|
||||
uint32_t consumeRate = 0;
|
||||
double totalWeightThisTerm = 0;
|
||||
for (auto &item : this->virtualQueues)
|
||||
{
|
||||
totalWeightThisTerm += (item.second->weight * item.second->penaltyFactor);
|
||||
}
|
||||
|
||||
for (auto &item : this->virtualQueues)
|
||||
{
|
||||
item.second->objectRate = this->availableBandwidth * item.second->weight * item.second->penaltyFactor / totalWeightThisTerm;
|
||||
item.second->currentFlowRate = item.second->recvBits * 1000 / this->calObjectRateInterval;
|
||||
item.second->currentRatio = item.second->currentFlowRate * 1.0 / item.second->objectRate;
|
||||
|
||||
auto targetHighFlowRate = (item.second->objectRate - 500000) * 1.0 / item.second->objectRate;
|
||||
if (item.second->currentRatio > targetHighFlowRate)
|
||||
{
|
||||
|
||||
if (item.second->penaltyFactor > 0.99)
|
||||
{
|
||||
hightSppedFlowNum++;
|
||||
totalHightSpeedFlowWeight += item.second->weight;
|
||||
}
|
||||
consumeRate += item.second->objectRate;
|
||||
}
|
||||
else
|
||||
{
|
||||
consumeRate += item.second->currentFlowRate;
|
||||
}
|
||||
NFD_LOG_DEBUG(this->name << " => currentRate: " << item.second->currentFlowRate << ", consumerRate: " << consumeRate << ", objectRate: " << item.second->objectRate << ", availableBandwidth" << this->availableBandwidth << ", weight: " << item.second->weight << ", totalWeight: " << this->totalWeight << ", currentSendRate: " << currentSendRate);
|
||||
// std::cout << this->name << " => currentRate: " << item.second->currentFlowRate << ", consumerRate: " << consumeRate << ", objectRate: " << item.second->objectRate <<
|
||||
// ", availableBandwidth" << this->availableBandwidth << ", weight: " << item.second->weight << ", totalWeight: " <<
|
||||
// this->totalWeight << ", currentSendRate: " << currentSendRate << std::endl;
|
||||
|
||||
item.second->recvBits = 0;
|
||||
}
|
||||
|
||||
if (consumeRate < this->availableBandwidth && hightSppedFlowNum > 0)
|
||||
{
|
||||
|
||||
auto remainRate = this->availableBandwidth - consumeRate;
|
||||
for (auto &item : this->virtualQueues)
|
||||
{
|
||||
if (item.second->penaltyFactor > 0.99 && item.second->currentRatio > 0.8)
|
||||
{
|
||||
item.second->objectRate += (remainRate * item.second->weight / totalHightSpeedFlowWeight);
|
||||
}
|
||||
NFD_LOG_DEBUG(this->name << " => objectRate: " << item.second->objectRate << ", remainRate: " << remainRate << ", item.weight: " << item.second->weight << ", totalWeight: " << totalHightSpeedFlowWeight);
|
||||
// std::cout << this->name << " => objectRate: " << item.second->objectRate << ", remainRate: " <<
|
||||
// remainRate << ", item.weight: " << item.second->weight << ", totalWeight: " << totalHightSpeedFlowWeight << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &item : this->virtualQueues)
|
||||
{
|
||||
|
||||
if (item.second->currentFlowRate * 1.0 / item.second->objectRate > item.second->gredyRatio)
|
||||
{
|
||||
if (item.second->gredyTimes < item.second->gredyThreshold)
|
||||
{
|
||||
item.second->gredyTimes++;
|
||||
}
|
||||
if (item.second->gredyTimes == item.second->gredyThreshold)
|
||||
{
|
||||
// std::cout << item.first << ": PenaltyFactor => " << item.second->gredyTimes << ", currentFlowRate: " << item.second->currentFlowRate << ", objectRate: " << item.second->objectRate << std::endl;
|
||||
item.second->penaltyFactor = 0.5;
|
||||
item.second->size = 20;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.second->gredyTimes > 0)
|
||||
{
|
||||
item.second->gredyTimes--;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (this->virtualQueues.size() > 0)
|
||||
// {
|
||||
// std::cout << "\n\n=====================: " << this->availableBandwidth << std::endl;
|
||||
// }
|
||||
for (auto &item : this->virtualQueues)
|
||||
{
|
||||
if (item.second->penaltyFactor > 0.99)
|
||||
{
|
||||
auto rate = this->calDiscountFactor(item.second->currentSize * 1.0 / item.second->size);
|
||||
item.second->objectRate *= rate;
|
||||
}
|
||||
// std::cout << item.first << ", currentFlowRate: " << item.second->currentFlowRate
|
||||
// << ", objectRate: " << item.second->objectRate << ", size: " << item.second->currentSize
|
||||
// << ", weight: " << item.second->weight << ", penaltyFactor: " << item.second->penaltyFactor
|
||||
// << std::endl;
|
||||
}
|
||||
// if (this->virtualQueues.size() > 0)
|
||||
// {
|
||||
// std::cout << "\n----------------------" << std::endl;
|
||||
// }
|
||||
this->sendBits = 0;
|
||||
this->recvBits = 0;
|
||||
return currentRate;
|
||||
}
|
||||
uint32_t WDRRQueue::scheduleOnePacketForWFQ(uint32_t totalLastSeq)
|
||||
{
|
||||
if (this->cachePacketForWFQ != nullptr)
|
||||
{
|
||||
return this->cachePacketForWFQ->seq;
|
||||
}
|
||||
if (this->currentPacketNum == 0)
|
||||
{
|
||||
return UINT32_MAX;
|
||||
}
|
||||
this->cachePacketForWFQ = this->scheduleNext();
|
||||
if (this->cachePacketForWFQ == nullptr)
|
||||
{
|
||||
|
||||
return UINT32_MAX;
|
||||
}
|
||||
if (this->lastSeq == -1)
|
||||
{
|
||||
this->lastSeq = totalLastSeq;
|
||||
}
|
||||
this->cachePacketForWFQ->seq = this->lastSeq + 1.0 * this->cachePacketForWFQ->dataSize / this->weight;
|
||||
if (this->currentPacketNum == 0)
|
||||
{
|
||||
this->lastSeq = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->lastSeq = this->cachePacketForWFQ->seq;
|
||||
}
|
||||
|
||||
return this->cachePacketForWFQ->seq;
|
||||
}
|
||||
std::shared_ptr<VirtualQueueItem> DelaySensitiveServiceSP::scheduleNext()
|
||||
{
|
||||
auto res = this->CS7Queue->scheduleNext();
|
||||
if (res == nullptr)
|
||||
{
|
||||
res = this->CS6Queue->scheduleNext();
|
||||
}
|
||||
if (res == nullptr)
|
||||
{
|
||||
res = this->EFQueue->scheduleNext();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
uint32_t DelaySensitiveServiceSP::calObjectRate(bool getCurrentRateOnly)
|
||||
{
|
||||
uint32_t res = this->CS7Queue->calObjectRate(getCurrentRateOnly);
|
||||
res += this->CS6Queue->calObjectRate(getCurrentRateOnly);
|
||||
res += this->EFQueue->calObjectRate(getCurrentRateOnly);
|
||||
return res;
|
||||
}
|
||||
std::shared_ptr<VirtualQueueItem> WFQQueue::scheduleNext()
|
||||
{
|
||||
std::shared_ptr<WDRRQueue> selectedQueue = nullptr;
|
||||
uint32_t currentMinSeq = UINT32_MAX;
|
||||
for (auto &queue : this->queues)
|
||||
{
|
||||
uint32_t seq = queue->scheduleOnePacketForWFQ(this->lastSeq);
|
||||
if (seq < currentMinSeq)
|
||||
{
|
||||
currentMinSeq = seq;
|
||||
selectedQueue = queue;
|
||||
}
|
||||
}
|
||||
if (selectedQueue != nullptr)
|
||||
{
|
||||
this->lastSeq = currentMinSeq;
|
||||
auto selectPacket = selectedQueue->frontForWFQ(this->lastSeq);
|
||||
selectedQueue->popForWFQ();
|
||||
|
||||
return selectPacket;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
uint32_t WFQQueue::calObjectRate(uint32_t availableBandwidth)
|
||||
{
|
||||
int totalRate = 0;
|
||||
double totalHightSpeedFlowWeight = 0;
|
||||
int hightSppedFlowNum = 0;
|
||||
double totalHasFlowQueueWeight = 0;
|
||||
int hasFlowQueueNum = 0;
|
||||
for (auto &queue : this->queues)
|
||||
{
|
||||
auto recvRate = queue->calObjectRate(true);
|
||||
queue->originAvaliableBandwidth = (queue->getWeight() / totalWeight) * availableBandwidth;
|
||||
auto remainRate = queue->getRemainBandwidthRate(queue->originAvaliableBandwidth);
|
||||
if (remainRate < 0.2)
|
||||
{
|
||||
hightSppedFlowNum++;
|
||||
totalHightSpeedFlowWeight += queue->getWeight();
|
||||
totalRate += queue->originAvaliableBandwidth;
|
||||
}
|
||||
else if (remainRate < 0.95)
|
||||
{
|
||||
hasFlowQueueNum++;
|
||||
totalHasFlowQueueWeight += queue->getWeight();
|
||||
totalRate += recvRate;
|
||||
}
|
||||
else
|
||||
{
|
||||
totalRate += recvRate;
|
||||
}
|
||||
}
|
||||
this->availableBandwidth = availableBandwidth;
|
||||
int remain = this->availableBandwidth - totalRate;
|
||||
if (hightSppedFlowNum > 0)
|
||||
{
|
||||
// std::cout << "high speed flow num: " << hightSppedFlowNum << ", totalHightSpeedFlowWeight: " << totalHightSpeedFlowWeight << std::endl;
|
||||
for (auto &queue : this->queues)
|
||||
{
|
||||
if (queue->getRemainBandwidthRate(queue->originAvaliableBandwidth) < 0.2)
|
||||
{
|
||||
// std::cout << "!!!" << queue->getWeight() * remain * 1.0 / totalHightSpeedFlowWeight +
|
||||
// queue->originAvaliableBandwidth << std::endl;
|
||||
queue->updateAvailableBandwidth(
|
||||
queue->getWeight() * remain * 1.0 / totalHightSpeedFlowWeight +
|
||||
queue->originAvaliableBandwidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
queue->updateAvailableBandwidth(queue->originAvaliableBandwidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// std::cout << "has flow queue num: " << hasFlowQueueNum << ", totalHasFlowQueueWeight: " << totalHasFlowQueueWeight << std::endl;
|
||||
for (auto &queue : this->queues)
|
||||
{
|
||||
if (queue->getRemainBandwidthRate(queue->originAvaliableBandwidth) < 0.95)
|
||||
{
|
||||
queue->updateAvailableBandwidth(
|
||||
queue->getWeight() * remain * 1.0 / totalHasFlowQueueWeight +
|
||||
queue->originAvaliableBandwidth);
|
||||
}
|
||||
else
|
||||
{
|
||||
queue->updateAvailableBandwidth(queue->originAvaliableBandwidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
uint32_t currentTotalRate = 0;
|
||||
|
||||
for (auto &queue : this->queues)
|
||||
{
|
||||
currentTotalRate += queue->calObjectRate(false);
|
||||
}
|
||||
return currentTotalRate;
|
||||
}
|
||||
std::shared_ptr<VirtualQueueItem> GlobalSP::scheduleNext()
|
||||
{
|
||||
std::shared_ptr<VirtualQueueItem> selectedPacket = this->delaySensitiveServiceSp.scheduleNext();
|
||||
if (selectedPacket == nullptr)
|
||||
{
|
||||
selectedPacket = wfqQueue.scheduleNext();
|
||||
}
|
||||
if (selectedPacket != nullptr)
|
||||
{
|
||||
selectedPacket->waitNsTime = selectedPacket->dataSize * 1000000000.0 / this->availableBandwidth + 1;
|
||||
// 计算 DR => DR'(/p, j) = min(OR(/p, j), RR(/p, j) / sum(RR(/p)) * sum(AR(/p)))
|
||||
auto currentObjectRate = selectedPacket->queue->objectRate;
|
||||
auto downstreamRate = selectedPacket->item->getDownstreamRate();
|
||||
if (downstreamRate)
|
||||
{
|
||||
if (*downstreamRate > currentObjectRate)
|
||||
{
|
||||
selectedPacket->item->setDownstreamRate(currentObjectRate);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedPacket->item->setDownstreamRate(currentObjectRate);
|
||||
}
|
||||
}
|
||||
return selectedPacket;
|
||||
}
|
||||
std::shared_ptr<WDRRQueue> GlobalSP::getQueueByTos(int tosValue)
|
||||
{
|
||||
switch (tosValue)
|
||||
{
|
||||
case 0:
|
||||
return this->delaySensitiveServiceSp.getCS7Queue();
|
||||
case 1:
|
||||
return this->delaySensitiveServiceSp.getCS6Queue();
|
||||
case 2:
|
||||
return this->delaySensitiveServiceSp.getEFQueue();
|
||||
case 3:
|
||||
return this->wfqQueue.getAF4Queue();
|
||||
case 4:
|
||||
return this->wfqQueue.getAF3Queue();
|
||||
case 5:
|
||||
return this->wfqQueue.getAF2Queue();
|
||||
case 6:
|
||||
return this->wfqQueue.getAF1Queue();
|
||||
case 7:
|
||||
default:
|
||||
return this->wfqQueue.getBEQueue();
|
||||
}
|
||||
}
|
||||
bool GlobalSP::appendInterest(const Interest &interest)
|
||||
{
|
||||
int serviceClass = 7;
|
||||
if (interest.getServiceClass())
|
||||
{
|
||||
serviceClass = (*interest.getServiceClass()) % 8;
|
||||
}
|
||||
// std::cout << "appendInterest => serviceClass: " << serviceClass << std::endl;
|
||||
return this->getQueueByTos(serviceClass)->appendInterest(interest);
|
||||
}
|
||||
void GlobalSP::receiveInterest(const Interest &interest)
|
||||
{
|
||||
ndn::encoding::EncodingEstimator estimator;
|
||||
auto size = interest.wireEncode(estimator) + 9;
|
||||
this->interestBytes += size;
|
||||
// std::cout << this << "receiveInterest => size: " << size << ", interestBytes: " << this->interestBytes << std::endl;
|
||||
}
|
||||
|
||||
void GlobalSP::calObjectRate(bool getCurrentRateOnly)
|
||||
{
|
||||
// getScheduler().schedule(time::nanoseconds(1000000 * this->calObjectRateInterval),
|
||||
// [this] { this->calObjectRate(false); });
|
||||
uint32_t remain = this->availableBandwidth;
|
||||
remain -= this->interestBytes * 8000 / this->calObjectRateInterval;
|
||||
this->interestBytes = 0;
|
||||
remain -= this->delaySensitiveServiceSp.calObjectRate(false);
|
||||
|
||||
// std::cout << "AvaliableBandwidth: " << this->availableBandwidth << ", remain: " << remain << ", interestBytes" << this->interestBytes << std::endl;
|
||||
|
||||
this->wfqQueue.calObjectRate(remain);
|
||||
}
|
||||
void GlobalSP::assignObjectRate(const Data &data)
|
||||
{
|
||||
std::string key = data.getName().getPrefix(1).toUri();
|
||||
int serviceClass = 7;
|
||||
if (data.getServiceClass())
|
||||
{
|
||||
serviceClass = (*data.getServiceClass()) % 8;
|
||||
}
|
||||
// std::cout << "assignObjectRate => serviceClass: " << serviceClass << std::endl;
|
||||
auto objectRate = this->getQueueByTos(serviceClass)->getObjectRateByFlowKey(key);
|
||||
auto targetRate = data.getTargetRate();
|
||||
if (!targetRate || *targetRate > objectRate)
|
||||
{
|
||||
data.setTargetRate(objectRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
#ifndef NS_QUEUES_HPP
|
||||
#define NS_QUEUES_HPP
|
||||
#include <deque>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include "common/global.hpp"
|
||||
#include "link-service.hpp"
|
||||
#include <ndn-cxx/lp/tags.hpp>
|
||||
#include "TokenBucket.hpp"
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
class VirtualQueue;
|
||||
struct VirtualQueueItem {
|
||||
int seq;
|
||||
std::shared_ptr<const Interest> item;
|
||||
uint32_t dataSize;
|
||||
uint32_t waitNsTime;
|
||||
std::shared_ptr<VirtualQueue> queue;
|
||||
};
|
||||
class VirtualQueue : public std::enable_shared_from_this<VirtualQueue>{
|
||||
public:
|
||||
explicit VirtualQueue(double weight, int size) :
|
||||
std::enable_shared_from_this<VirtualQueue>(),
|
||||
penaltyFactor(1.0),
|
||||
weight(weight), size(size), currentSize(0), lastSeq(0),
|
||||
C(0) {
|
||||
}
|
||||
void enableTokenBucket(uint32_t limitRate) {
|
||||
this->C = limitRate;
|
||||
}
|
||||
bool push(int seq, const std::shared_ptr<const Interest>& interest,
|
||||
uint64_t dataSize, bool needInsert);
|
||||
bool empty() {
|
||||
return this->innerQueue.empty();
|
||||
}
|
||||
uint32_t frontSeq() {
|
||||
if (this->innerQueue.empty()) {
|
||||
return this->lastSeq;
|
||||
}
|
||||
return this->innerQueue.front().seq;
|
||||
}
|
||||
VirtualQueueItem front() {
|
||||
return this->innerQueue.front();
|
||||
}
|
||||
uint32_t backSeq() {
|
||||
return this->lastSeq;
|
||||
}
|
||||
VirtualQueueItem back() {
|
||||
return this->innerQueue.back();
|
||||
}
|
||||
void pop() {
|
||||
if (this->currentSize <= 0) {
|
||||
return;
|
||||
}
|
||||
this->currentSize--;
|
||||
this->innerQueue.pop_front();
|
||||
}
|
||||
void popBack() {
|
||||
if (this->currentSize <= 0) {
|
||||
return;
|
||||
}
|
||||
this->currentSize--;
|
||||
this->innerQueue.pop_back();
|
||||
}
|
||||
int len() {
|
||||
return this->innerQueue.size();
|
||||
}
|
||||
void setLastSeq(uint32_t seq) {
|
||||
this->lastSeq = seq;
|
||||
}
|
||||
uint32_t getLastSeq() {
|
||||
return lastSeq;
|
||||
}
|
||||
void setWeight(double weight) {
|
||||
this->weight = weight;
|
||||
}
|
||||
double getWeight() {
|
||||
return this->weight;
|
||||
}
|
||||
public:
|
||||
uint32_t objectRate;
|
||||
double penaltyFactor = 1.0;
|
||||
uint32_t gredyTimes = 0;
|
||||
double gredyRatio = 1.2;
|
||||
double gredyThreshold = 10;
|
||||
double weight = 1.0;
|
||||
uint32_t tos = 5;
|
||||
double balance = 0;
|
||||
int size = 0;
|
||||
int currentSize = 0;
|
||||
uint32_t recvBits = 0;
|
||||
uint32_t currentFlowRate = 0;
|
||||
double currentRatio = 0.0;
|
||||
private:
|
||||
uint32_t lastSeq;
|
||||
int C;
|
||||
std::deque<VirtualQueueItem> innerQueue;
|
||||
};
|
||||
class WDRRQueue {
|
||||
public:
|
||||
explicit WDRRQueue(uint32_t rateLimit, uint32_t availableBandwidth, double weight, const std::string& name,
|
||||
uint32_t tos = 5, size_t vqSize = 20);
|
||||
void updateAvailableBandwidth(uint32_t C);
|
||||
bool appendInterest(const Interest &interest);
|
||||
std::shared_ptr<VirtualQueueItem> scheduleNext();
|
||||
uint32_t calObjectRate(bool getCurrentRateOnly);
|
||||
void setCDTLimit(int cdt) {
|
||||
this->cdt = cdt;
|
||||
}
|
||||
uint32_t scheduleOnePacketForWFQ(uint32_t totalLastSeq);
|
||||
std::shared_ptr<VirtualQueueItem> frontForWFQ(uint32_t totalLastSeq) {
|
||||
if (this->cachePacketForWFQ == nullptr) {
|
||||
this->scheduleOnePacketForWFQ(totalLastSeq);
|
||||
}
|
||||
return this->cachePacketForWFQ;
|
||||
}
|
||||
void popForWFQ() {
|
||||
this->cachePacketForWFQ = nullptr;
|
||||
}
|
||||
double getRemainBandwidthRate(double curAvailableBandWidth) {
|
||||
auto currentRate = this->calObjectRate(true);
|
||||
if (currentRate > curAvailableBandWidth) {
|
||||
return 0;
|
||||
}
|
||||
return (curAvailableBandWidth - currentRate) * 1.0 / curAvailableBandWidth;
|
||||
}
|
||||
uint32_t getRemainBandwidth() {
|
||||
return this->availableBandwidth - this->calObjectRate(true);
|
||||
}
|
||||
double getWeight() {
|
||||
return this->weight;
|
||||
}
|
||||
uint32_t getAvailableBandwidth() {
|
||||
return this->availableBandwidth;
|
||||
}
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* \sigma=\frac{1}{3}\arccot\funcapply(8\delta-4)
|
||||
* @param x
|
||||
* @return double
|
||||
*/
|
||||
double calDiscountFactor(double x) {
|
||||
return 1.0 / 3 * (M_PI / 2 - atan(8 * x - 4)) + 0.034;
|
||||
}
|
||||
/**
|
||||
* @brief Get the Object Rate By Flow Key object
|
||||
*
|
||||
* @param key
|
||||
* @return uint32_t
|
||||
*/
|
||||
uint32_t getObjectRateByFlowKey(const std::string& key) {
|
||||
if (this->virtualQueues.count(key) == 0) {
|
||||
std::cout << "FUCK: " << key << ", count: " << this->virtualQueues.size() <<
|
||||
", flow: " << this->flows.size() << "availbleRate: " << this->availableBandwidth << std::endl;
|
||||
return 0;
|
||||
}
|
||||
return this->virtualQueues[key]->objectRate;
|
||||
}
|
||||
|
||||
void triggerByCurrentTime(long currentTime) {
|
||||
if (this->needRateLimit) {
|
||||
this->tokenBucket->generateTokenByCurrentTime(currentTime);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
double originAvaliableBandwidth = 0;
|
||||
private:
|
||||
std::unordered_map<std::string, std::shared_ptr<VirtualQueue>> virtualQueues;
|
||||
std::vector<std::string> flows;
|
||||
size_t nextScheduleQueue = 0;
|
||||
std::shared_ptr<TokenBucket> tokenBucket;
|
||||
uint32_t availableBandwidth;
|
||||
// uint32_t extraBandwidth;
|
||||
double weight;
|
||||
std::string name;
|
||||
uint32_t tos = 5;
|
||||
bool needRateLimit;
|
||||
double totalWeight;
|
||||
uint32_t sendBits = 0;
|
||||
uint32_t recvBits = 0;
|
||||
int vqSize = 20;
|
||||
int cdt = -1;
|
||||
int currentPacketNum = 0;
|
||||
int MTU_QUANTA = 2 * 1000 * 8;
|
||||
int calObjectRateInterval = 100;
|
||||
int64_t lastSeq = -1;
|
||||
std::shared_ptr<VirtualQueueItem> cachePacketForWFQ = nullptr;
|
||||
};
|
||||
class DelaySensitiveServiceSP {
|
||||
public:
|
||||
explicit DelaySensitiveServiceSP(uint32_t availableBandwidth, size_t vqSize = 20) {
|
||||
this->CS7Queue = std::make_shared<WDRRQueue>((uint32_t) (0.2 * availableBandwidth), (uint32_t) (0.2 * availableBandwidth), 2, "CS7", 2, vqSize);
|
||||
this->CS6Queue = std::make_shared<WDRRQueue>((uint32_t) (0.2 * availableBandwidth), (uint32_t) (0.2 * availableBandwidth), 2, "CS6", 1, vqSize);
|
||||
this->EFQueue = std::make_shared<WDRRQueue>((uint32_t) (0.3 * availableBandwidth), (uint32_t) (0.3 * availableBandwidth), 3, "EF", 0, vqSize);
|
||||
}
|
||||
std::shared_ptr<VirtualQueueItem> scheduleNext();
|
||||
uint32_t calObjectRate(bool getCurrentRateOnly);
|
||||
std::shared_ptr<WDRRQueue> getCS7Queue() {
|
||||
return this->CS7Queue;
|
||||
}
|
||||
std::shared_ptr<WDRRQueue> getCS6Queue() {
|
||||
return this->CS6Queue;
|
||||
}
|
||||
std::shared_ptr<WDRRQueue> getEFQueue() {
|
||||
return this->EFQueue;
|
||||
}
|
||||
void triggerByCurrentTime(long currentTime) {
|
||||
this->CS7Queue->triggerByCurrentTime(currentTime);
|
||||
this->CS6Queue->triggerByCurrentTime(currentTime);
|
||||
this->EFQueue->triggerByCurrentTime(currentTime);
|
||||
}
|
||||
private:
|
||||
std::shared_ptr<WDRRQueue> CS7Queue;
|
||||
std::shared_ptr<WDRRQueue> CS6Queue;
|
||||
std::shared_ptr<WDRRQueue> EFQueue;
|
||||
};
|
||||
class WFQQueue {
|
||||
public:
|
||||
explicit WFQQueue(uint32_t availableBandwidth, size_t vqSize) :
|
||||
AF4Weight(5),
|
||||
AF3Weight(4),
|
||||
AF2Weight(3),
|
||||
AF1Weight(2),
|
||||
BEWeight(1),
|
||||
totalWeight(AF4Weight + AF3Weight + AF2Weight + AF1Weight + BEWeight),
|
||||
queues(5),
|
||||
lastSeq(0),
|
||||
availableBandwidth(availableBandwidth) {
|
||||
this->queues[0] = std::make_shared<WDRRQueue>(0, availableBandwidth * AF4Weight / totalWeight, 5, "AF4", 3, vqSize);
|
||||
this->queues[1] = std::make_shared<WDRRQueue>(0, availableBandwidth * AF3Weight / totalWeight, 4, "AF3", 4, vqSize);
|
||||
this->queues[2] = std::make_shared<WDRRQueue>(0, availableBandwidth * AF2Weight / totalWeight, 3, "AF2", 5, vqSize);
|
||||
this->queues[3] = std::make_shared<WDRRQueue>(0, availableBandwidth * AF1Weight / totalWeight, 2, "AF1", 6, vqSize);
|
||||
this->queues[4] = std::make_shared<WDRRQueue>(0, availableBandwidth * BEWeight / totalWeight, 1, "BE", 7, vqSize);
|
||||
for (auto &queue: this->queues) {
|
||||
queue->setCDTLimit(this->cdt);
|
||||
}
|
||||
}
|
||||
std::shared_ptr<VirtualQueueItem> scheduleNext();
|
||||
uint32_t calObjectRate(uint32_t availableBandwidth);
|
||||
std::shared_ptr<WDRRQueue> getAF4Queue() {
|
||||
return this->queues[0];
|
||||
}
|
||||
std::shared_ptr<WDRRQueue> getAF3Queue() {
|
||||
return this->queues[1];
|
||||
}
|
||||
std::shared_ptr<WDRRQueue> getAF2Queue() {
|
||||
return this->queues[2];
|
||||
}
|
||||
std::shared_ptr<WDRRQueue> getAF1Queue() {
|
||||
return this->queues[3];
|
||||
}
|
||||
std::shared_ptr<WDRRQueue> getBEQueue() {
|
||||
return this->queues[4];
|
||||
}
|
||||
private:
|
||||
double AF4Weight = 5;
|
||||
double AF3Weight = 4;
|
||||
double AF2Weight = 3;
|
||||
double AF1Weight = 2;
|
||||
double BEWeight = 1;
|
||||
double totalWeight = 15;
|
||||
std::vector<std::shared_ptr<WDRRQueue>> queues;
|
||||
uint32_t lastSeq;
|
||||
u_int32_t availableBandwidth;
|
||||
int cdt = 200;
|
||||
int hql;
|
||||
};
|
||||
class GlobalSP {
|
||||
public:
|
||||
explicit GlobalSP(uint32_t availableBandwidth, size_t vqSize = 20) :
|
||||
delaySensitiveServiceSp(availableBandwidth, vqSize),
|
||||
wfqQueue(availableBandwidth, vqSize),
|
||||
availableBandwidth(availableBandwidth) {
|
||||
lastTriggerTime = getCurrentTime();
|
||||
// getScheduler().schedule(time::nanoseconds(1000000 * this->calObjectRateInterval),
|
||||
// [this] { this->calObjectRate(false); });
|
||||
}
|
||||
std::shared_ptr<VirtualQueueItem> scheduleNext();
|
||||
bool appendInterest(const Interest &interest);
|
||||
void receiveInterest(const Interest &interest);
|
||||
void calObjectRate(bool getCurrentRateOnly);
|
||||
std::shared_ptr<WDRRQueue> getQueueByTos(int tosValue);
|
||||
long getCurrentTime() {
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
void triggerCalObjectRate() {
|
||||
auto currentTime = getCurrentTime();
|
||||
this->delaySensitiveServiceSp.triggerByCurrentTime(currentTime);
|
||||
if (currentTime - lastTriggerTime > calObjectRateInterval) {
|
||||
this->calObjectRate(false);
|
||||
lastTriggerTime = currentTime;
|
||||
}
|
||||
}
|
||||
void assignObjectRate(const Data &data);
|
||||
private:
|
||||
DelaySensitiveServiceSP delaySensitiveServiceSp;
|
||||
WFQQueue wfqQueue;
|
||||
int calObjectRateInterval = 100;
|
||||
uint32_t availableBandwidth;
|
||||
size_t interestBytes = 0;
|
||||
long lastTriggerTime = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif //NS_QUEUES_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -63,7 +63,7 @@ protected:
|
||||
deferredClose();
|
||||
|
||||
void
|
||||
doSend(Transport::Packet&& packet) override;
|
||||
doSend(const Block& packet) override;
|
||||
|
||||
void
|
||||
sendFromQueue();
|
||||
@@ -180,7 +180,7 @@ StreamTransport<T>::deferredClose()
|
||||
|
||||
template<class T>
|
||||
void
|
||||
StreamTransport<T>::doSend(Transport::Packet&& packet)
|
||||
StreamTransport<T>::doSend(const Block& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
@@ -188,8 +188,8 @@ StreamTransport<T>::doSend(Transport::Packet&& packet)
|
||||
return;
|
||||
|
||||
bool wasQueueEmpty = m_sendQueue.empty();
|
||||
m_sendQueue.push(packet.packet);
|
||||
m_sendQueueBytes += packet.packet.size();
|
||||
m_sendQueue.push(packet);
|
||||
m_sendQueueBytes += packet.size();
|
||||
|
||||
if (wasQueueEmpty)
|
||||
sendFromQueue();
|
||||
@@ -255,7 +255,7 @@ StreamTransport<T>::handleReceive(const boost::system::error_code& error,
|
||||
offset += element.size();
|
||||
BOOST_ASSERT(offset <= m_receiveBufferSize);
|
||||
|
||||
this->receive(Transport::Packet(std::move(element)));
|
||||
this->receive(element);
|
||||
}
|
||||
|
||||
if (!isOk && m_receiveBufferSize == ndn::MAX_NDN_PACKET_SIZE && offset == 0) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "tcp-channel.hpp"
|
||||
#include "face.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
#include "tcp-transport.hpp"
|
||||
#include "common/global.hpp"
|
||||
@@ -122,12 +123,16 @@ TcpChannel::createFace(ip::tcp::socket&& socket,
|
||||
if (params.defaultCongestionThreshold) {
|
||||
options.defaultCongestionThreshold = *params.defaultCongestionThreshold;
|
||||
}
|
||||
if (params.bandwidth) {
|
||||
options.C = *params.bandwidth;
|
||||
}
|
||||
|
||||
auto linkService = make_unique<GenericLinkService>(options);
|
||||
auto faceScope = m_determineFaceScope(socket.local_endpoint().address(),
|
||||
socket.remote_endpoint().address());
|
||||
auto transport = make_unique<TcpTransport>(std::move(socket), params.persistency, faceScope);
|
||||
face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
face->setChannel(shared_from_this()); // use weak_from_this() in C++17
|
||||
|
||||
m_channelFaces[remoteEndpoint] = face;
|
||||
connectFaceClosedSignal(*face, [this, remoteEndpoint] { m_channelFaces.erase(remoteEndpoint); });
|
||||
|
||||
+27
-17
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -31,8 +31,6 @@ namespace face {
|
||||
|
||||
NFD_LOG_INIT(Transport);
|
||||
|
||||
const ssize_t Transport::MIN_MTU;
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, TransportState state)
|
||||
{
|
||||
@@ -52,12 +50,6 @@ operator<<(std::ostream& os, TransportState state)
|
||||
}
|
||||
}
|
||||
|
||||
Transport::Packet::Packet(Block&& packet1)
|
||||
: packet(std::move(packet1))
|
||||
, remoteEndpoint(0)
|
||||
{
|
||||
}
|
||||
|
||||
Transport::Transport()
|
||||
: m_face(nullptr)
|
||||
, m_service(nullptr)
|
||||
@@ -97,10 +89,11 @@ Transport::close()
|
||||
}
|
||||
|
||||
void
|
||||
Transport::send(Packet&& packet)
|
||||
Transport::send(const Block& packet)
|
||||
{
|
||||
BOOST_ASSERT(packet.isValid());
|
||||
BOOST_ASSERT(this->getMtu() == MTU_UNLIMITED ||
|
||||
packet.packet.size() <= static_cast<size_t>(this->getMtu()));
|
||||
packet.size() <= static_cast<size_t>(this->getMtu()));
|
||||
|
||||
TransportState state = this->getState();
|
||||
if (state != TransportState::UP && state != TransportState::DOWN) {
|
||||
@@ -110,22 +103,39 @@ Transport::send(Packet&& packet)
|
||||
|
||||
if (state == TransportState::UP) {
|
||||
++this->nOutPackets;
|
||||
this->nOutBytes += packet.packet.size();
|
||||
this->nOutBytes += packet.size();
|
||||
}
|
||||
|
||||
this->doSend(std::move(packet));
|
||||
this->doSend(packet);
|
||||
}
|
||||
|
||||
void
|
||||
Transport::receive(Packet&& packet)
|
||||
Transport::receive(const Block& packet, const EndpointId& endpoint)
|
||||
{
|
||||
BOOST_ASSERT(packet.isValid());
|
||||
BOOST_ASSERT(this->getMtu() == MTU_UNLIMITED ||
|
||||
packet.packet.size() <= static_cast<size_t>(this->getMtu()));
|
||||
packet.size() <= static_cast<size_t>(this->getMtu()));
|
||||
|
||||
++this->nInPackets;
|
||||
this->nInBytes += packet.packet.size();
|
||||
this->nInBytes += packet.size();
|
||||
|
||||
m_service->receivePacket(std::move(packet));
|
||||
m_service->receivePacket(packet, endpoint);
|
||||
}
|
||||
|
||||
void
|
||||
Transport::setMtu(ssize_t mtu)
|
||||
{
|
||||
BOOST_ASSERT(mtu == MTU_UNLIMITED || mtu >= 0);
|
||||
|
||||
if (mtu == m_mtu) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_mtu != MTU_INVALID) {
|
||||
NFD_LOG_FACE_INFO("setMtu " << m_mtu << " -> " << mtu);
|
||||
}
|
||||
|
||||
m_mtu = mtu;
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
+27
-70
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,22 +26,13 @@
|
||||
#ifndef NFD_DAEMON_FACE_TRANSPORT_HPP
|
||||
#define NFD_DAEMON_FACE_TRANSPORT_HPP
|
||||
|
||||
#include "face-log.hpp"
|
||||
#include "face-common.hpp"
|
||||
#include "common/counter.hpp"
|
||||
|
||||
#include <ndn-cxx/encoding/nfd-constants.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
|
||||
class Face;
|
||||
class LinkService;
|
||||
|
||||
/** \brief identifies an endpoint on the link
|
||||
*/
|
||||
typedef uint64_t EndpointId;
|
||||
|
||||
/** \brief indicates the state of a transport
|
||||
/** \brief Indicates the state of a transport.
|
||||
*/
|
||||
enum class TransportState {
|
||||
NONE,
|
||||
@@ -55,9 +46,9 @@ enum class TransportState {
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, TransportState state);
|
||||
|
||||
/** \brief counters provided by Transport
|
||||
* \note The type name 'TransportCounters' is implementation detail.
|
||||
* Use 'Transport::Counters' in public API.
|
||||
/** \brief Counters provided by a transport.
|
||||
* \note The type name TransportCounters is an implementation detail.
|
||||
* Use Transport::Counters in public API.
|
||||
*/
|
||||
class TransportCounters
|
||||
{
|
||||
@@ -111,43 +102,20 @@ const ssize_t QUEUE_UNSUPPORTED = -1;
|
||||
*/
|
||||
const ssize_t QUEUE_ERROR = -2;
|
||||
|
||||
/** \brief the lower part of a Face
|
||||
/** \brief The lower half of a Face.
|
||||
* \sa Face
|
||||
*/
|
||||
class Transport : protected virtual TransportCounters, noncopyable
|
||||
{
|
||||
public:
|
||||
/** \brief stores a packet along with the remote endpoint
|
||||
/** \brief Counters provided by a transport.
|
||||
* \sa TransportCounters
|
||||
*/
|
||||
class Packet
|
||||
{
|
||||
public:
|
||||
Packet() = default;
|
||||
using Counters = TransportCounters;
|
||||
|
||||
explicit
|
||||
Packet(Block&& packet);
|
||||
|
||||
public:
|
||||
/** \brief the packet as a TLV block
|
||||
*/
|
||||
Block packet;
|
||||
|
||||
/** \brief identifies the remote endpoint
|
||||
*
|
||||
* This ID is only meaningful in the context of the same Transport.
|
||||
* Incoming packets from the same remote endpoint have the same EndpointId,
|
||||
* and incoming packets from different remote endpoints have different EndpointIds.
|
||||
*/
|
||||
EndpointId remoteEndpoint;
|
||||
};
|
||||
|
||||
/** \brief counters provided by Transport
|
||||
*/
|
||||
typedef TransportCounters Counters;
|
||||
|
||||
/** \brief constructor
|
||||
/** \brief Default constructor.
|
||||
*
|
||||
* Transport constructor initializes static properties to invalid values.
|
||||
* This constructor initializes static properties to invalid values.
|
||||
* Subclass constructor must explicitly set every static property.
|
||||
*
|
||||
* This constructor initializes TransportState to UP;
|
||||
@@ -184,7 +152,7 @@ public:
|
||||
getCounters() const;
|
||||
|
||||
public: // upper interface
|
||||
/** \brief request the transport to be closed
|
||||
/** \brief Request the transport to be closed
|
||||
*
|
||||
* This operation is effective only if transport is in UP or DOWN state,
|
||||
* otherwise it has no effect.
|
||||
@@ -195,12 +163,13 @@ public: // upper interface
|
||||
void
|
||||
close();
|
||||
|
||||
/** \brief send a link-layer packet
|
||||
* \note This operation has no effect if \p getState() is neither UP nor DOWN
|
||||
* \warning undefined behavior if packet size exceeds MTU limit
|
||||
/** \brief Send a link-layer packet
|
||||
* \param packet the packet to be sent, must be a valid and well-formed TLV block
|
||||
* \note This operation has no effect if getState() is neither UP nor DOWN
|
||||
* \warning Behavior is undefined if packet size exceeds the MTU limit
|
||||
*/
|
||||
void
|
||||
send(Packet&& packet);
|
||||
send(const Block& packet);
|
||||
|
||||
public: // static properties
|
||||
/** \return a FaceUri representing local endpoint
|
||||
@@ -239,7 +208,7 @@ public: // static properties
|
||||
void
|
||||
setPersistency(ndn::nfd::FacePersistency newPersistency);
|
||||
|
||||
/** \return whether face is point-to-point or multi-access
|
||||
/** \return the link type of the transport
|
||||
*/
|
||||
ndn::nfd::LinkType
|
||||
getLinkType() const;
|
||||
@@ -290,11 +259,13 @@ public: // dynamic properties
|
||||
}
|
||||
|
||||
protected: // upper interface to be invoked by subclass
|
||||
/** \brief receive a link-layer packet
|
||||
* \warning undefined behavior if packet size exceeds MTU limit
|
||||
/** \brief Pass a received link-layer packet to the upper layer for further processing
|
||||
* \param packet the received packet, must be a valid and well-formed TLV block
|
||||
* \param endpoint the source endpoint
|
||||
* \warning Behavior is undefined if packet size exceeds the MTU limit
|
||||
*/
|
||||
void
|
||||
receive(Packet&& packet);
|
||||
receive(const Block& packet, const EndpointId& endpoint = 0);
|
||||
|
||||
protected: // properties to be set by subclass
|
||||
void
|
||||
@@ -360,18 +331,11 @@ protected: // to be overridden by subclass
|
||||
|
||||
private: // to be overridden by subclass
|
||||
/** \brief performs Transport specific operations to send a packet
|
||||
* \param packet the packet, which must be a well-formed TLV block
|
||||
* \pre state is either UP or DOWN
|
||||
* \param packet the packet to be sent, can be assumed to be valid and well-formed
|
||||
* \pre transport state is either UP or DOWN
|
||||
*/
|
||||
virtual void
|
||||
doSend(Packet&& packet) = 0;
|
||||
|
||||
public:
|
||||
/** \brief minimum MTU that may be set on a transport
|
||||
*
|
||||
* This is done to ensure the NDNLPv2 fragmentation feature functions properly.
|
||||
*/
|
||||
static constexpr ssize_t MIN_MTU = 64;
|
||||
doSend(const Block& packet) = 0;
|
||||
|
||||
private:
|
||||
Face* m_face;
|
||||
@@ -471,13 +435,6 @@ Transport::getMtu() const
|
||||
return m_mtu;
|
||||
}
|
||||
|
||||
inline void
|
||||
Transport::setMtu(ssize_t mtu)
|
||||
{
|
||||
BOOST_ASSERT(mtu == MTU_UNLIMITED || mtu > 0);
|
||||
m_mtu = mtu;
|
||||
}
|
||||
|
||||
inline ssize_t
|
||||
Transport::getSendQueueCapacity() const
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "udp-channel.hpp"
|
||||
#include "face.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
#include "unicast-udp-transport.hpp"
|
||||
#include "common/global.hpp"
|
||||
@@ -179,10 +180,19 @@ UdpChannel::createFace(const udp::Endpoint& remoteEndpoint,
|
||||
options.defaultCongestionThreshold = *params.defaultCongestionThreshold;
|
||||
}
|
||||
|
||||
if (params.mtu) {
|
||||
options.overrideMtu = *params.mtu;
|
||||
}
|
||||
|
||||
if (params.bandwidth) {
|
||||
options.C = *params.bandwidth;
|
||||
}
|
||||
|
||||
auto linkService = make_unique<GenericLinkService>(options);
|
||||
auto transport = make_unique<UnicastUdpTransport>(std::move(socket), params.persistency,
|
||||
m_idleFaceTimeout, params.mtu);
|
||||
m_idleFaceTimeout);
|
||||
auto face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
face->setChannel(shared_from_this()); // use weak_from_this() in C++17
|
||||
|
||||
m_channelFaces[remoteEndpoint] = face;
|
||||
connectFaceClosedSignal(*face, [this, remoteEndpoint] { m_channelFaces.erase(remoteEndpoint); });
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -268,10 +268,10 @@ UdpFactory::doCreateFace(const CreateFaceRequest& req,
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.params.mtu && *req.params.mtu < Transport::MIN_MTU) {
|
||||
if (req.params.mtu && *req.params.mtu < MIN_MTU) {
|
||||
// The specified MTU must be greater than the minimum possible
|
||||
NFD_LOG_TRACE("createFace cannot create a face with MTU less than " << Transport::MIN_MTU);
|
||||
onFailure(406, "MTU cannot be less than " + to_string(Transport::MIN_MTU));
|
||||
NFD_LOG_TRACE("createFace: override MTU cannot be less than " << MIN_MTU);
|
||||
onFailure(406, "Override MTU cannot be less than " + to_string(MIN_MTU));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -362,6 +362,13 @@ UdpFactory::createMulticastFace(const shared_ptr<const net::NetworkInterface>& n
|
||||
m_mcastFaces[localEp] = face;
|
||||
connectFaceClosedSignal(*face, [this, localEp] { m_mcastFaces.erase(localEp); });
|
||||
|
||||
// Associate with the first available channel of the same protocol family
|
||||
auto channelIt = std::find_if(m_channels.begin(), m_channels.end(),
|
||||
[isV4 = localEp.address().is_v4()] (const auto& it) {
|
||||
return it.first.address().is_v4() == isV4;
|
||||
});
|
||||
face->setChannel(channelIt != m_channels.end() ? channelIt->second : nullptr);
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -36,8 +36,7 @@ NFD_LOG_INIT(UnicastEthernetTransport);
|
||||
UnicastEthernetTransport::UnicastEthernetTransport(const ndn::net::NetworkInterface& localEndpoint,
|
||||
const ethernet::Address& remoteEndpoint,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
time::nanoseconds idleTimeout,
|
||||
optional<ssize_t> overrideMtu)
|
||||
time::nanoseconds idleTimeout)
|
||||
: EthernetTransport(localEndpoint, remoteEndpoint)
|
||||
, m_idleTimeout(idleTimeout)
|
||||
{
|
||||
@@ -46,13 +45,7 @@ UnicastEthernetTransport::UnicastEthernetTransport(const ndn::net::NetworkInterf
|
||||
this->setScope(ndn::nfd::FACE_SCOPE_NON_LOCAL);
|
||||
this->setPersistency(persistency);
|
||||
this->setLinkType(ndn::nfd::LINK_TYPE_POINT_TO_POINT);
|
||||
|
||||
if (overrideMtu) {
|
||||
this->setMtu(std::min<ssize_t>(localEndpoint.getMtu(), *overrideMtu));
|
||||
}
|
||||
else {
|
||||
this->setMtu(localEndpoint.getMtu());
|
||||
}
|
||||
this->setMtu(localEndpoint.getMtu());
|
||||
|
||||
NFD_LOG_FACE_DEBUG("Creating transport");
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -43,8 +43,7 @@ public:
|
||||
UnicastEthernetTransport(const ndn::net::NetworkInterface& localEndpoint,
|
||||
const ethernet::Address& remoteEndpoint,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
time::nanoseconds idleTimeout,
|
||||
optional<ssize_t> overrideMtu = {});
|
||||
time::nanoseconds idleTimeout);
|
||||
|
||||
protected:
|
||||
bool
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -41,8 +41,7 @@ NFD_LOG_MEMBER_INIT_SPECIALIZED((DatagramTransport<boost::asio::ip::udp, Unicast
|
||||
|
||||
UnicastUdpTransport::UnicastUdpTransport(protocol::socket&& socket,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
time::nanoseconds idleTimeout,
|
||||
optional<ssize_t> overrideMtu)
|
||||
time::nanoseconds idleTimeout)
|
||||
: DatagramTransport(std::move(socket))
|
||||
, m_idleTimeout(idleTimeout)
|
||||
{
|
||||
@@ -51,14 +50,7 @@ UnicastUdpTransport::UnicastUdpTransport(protocol::socket&& socket,
|
||||
this->setScope(ndn::nfd::FACE_SCOPE_NON_LOCAL);
|
||||
this->setPersistency(persistency);
|
||||
this->setLinkType(ndn::nfd::LINK_TYPE_POINT_TO_POINT);
|
||||
|
||||
if (overrideMtu) {
|
||||
this->setMtu(std::min(udp::computeMtu(m_socket.local_endpoint()), *overrideMtu));
|
||||
}
|
||||
else {
|
||||
this->setMtu(udp::computeMtu(m_socket.local_endpoint()));
|
||||
}
|
||||
BOOST_ASSERT(this->getMtu() >= MIN_MTU);
|
||||
this->setMtu(udp::computeMtu(m_socket.local_endpoint()));
|
||||
|
||||
NFD_LOG_FACE_DEBUG("Creating transport");
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -41,8 +41,7 @@ class UnicastUdpTransport final : public DatagramTransport<boost::asio::ip::udp,
|
||||
public:
|
||||
UnicastUdpTransport(protocol::socket&& socket,
|
||||
ndn::nfd::FacePersistency persistency,
|
||||
time::nanoseconds idleTimeout,
|
||||
optional<ssize_t> overrideMtu = {});
|
||||
time::nanoseconds idleTimeout);
|
||||
|
||||
protected:
|
||||
bool
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "unix-stream-channel.hpp"
|
||||
#include "face.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
#include "unix-stream-transport.hpp"
|
||||
#include "common/global.hpp"
|
||||
@@ -136,6 +137,7 @@ UnixStreamChannel::handleAccept(const boost::system::error_code& error,
|
||||
auto linkService = make_unique<GenericLinkService>(options);
|
||||
auto transport = make_unique<UnixStreamTransport>(std::move(m_socket));
|
||||
auto face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
face->setChannel(shared_from_this()); // use weak_from_this() in C++17
|
||||
|
||||
++m_size;
|
||||
connectFaceClosedSignal(*face, [this] { --m_size; });
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -46,7 +46,8 @@ UnixStreamFactory::doProcessConfig(OptionalConfigSection configSection,
|
||||
{
|
||||
// unix
|
||||
// {
|
||||
// path /var/run/nfd.sock
|
||||
// path /run/nfd.sock ; on Linux
|
||||
// path /var/run/nfd.sock ; on other platforms
|
||||
// }
|
||||
|
||||
m_wantCongestionMarking = context.generalConfig.wantCongestionMarking;
|
||||
@@ -58,7 +59,11 @@ UnixStreamFactory::doProcessConfig(OptionalConfigSection configSection,
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
std::string path = "/run/nfd.sock";
|
||||
#else
|
||||
std::string path = "/var/run/nfd.sock";
|
||||
#endif // __linux__
|
||||
|
||||
for (const auto& pair : *configSection) {
|
||||
const std::string& key = pair.first;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "websocket-channel.hpp"
|
||||
#include "face.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
#include "websocket-transport.hpp"
|
||||
#include "common/global.hpp"
|
||||
@@ -125,6 +126,7 @@ WebSocketChannel::handleOpen(websocketpp::connection_hdl hdl)
|
||||
auto linkService = make_unique<GenericLinkService>();
|
||||
auto transport = make_unique<WebSocketTransport>(hdl, m_server, m_pingInterval);
|
||||
auto face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
face->setChannel(shared_from_this()); // use weak_from_this() in C++17
|
||||
|
||||
BOOST_ASSERT(m_channelFaces.count(hdl) == 0);
|
||||
m_channelFaces[hdl] = face;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -78,17 +78,17 @@ WebSocketTransport::WebSocketTransport(websocketpp::connection_hdl hdl,
|
||||
}
|
||||
|
||||
void
|
||||
WebSocketTransport::doSend(Transport::Packet&& packet)
|
||||
WebSocketTransport::doSend(const Block& packet)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE(__func__);
|
||||
|
||||
websocketpp::lib::error_code error;
|
||||
m_server.send(m_handle, packet.packet.wire(), packet.packet.size(),
|
||||
m_server.send(m_handle, packet.wire(), packet.size(),
|
||||
websocketpp::frame::opcode::binary, error);
|
||||
if (error)
|
||||
return processErrorCode(error);
|
||||
|
||||
NFD_LOG_FACE_TRACE("Successfully sent: " << packet.packet.size() << " bytes");
|
||||
NFD_LOG_FACE_TRACE("Successfully sent: " << packet.size() << " bytes");
|
||||
}
|
||||
|
||||
void
|
||||
@@ -104,7 +104,7 @@ WebSocketTransport::receiveMessage(const std::string& msg)
|
||||
return;
|
||||
}
|
||||
|
||||
this->receive(Transport::Packet(std::move(element)));
|
||||
this->receive(element);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -83,7 +83,7 @@ protected:
|
||||
|
||||
private:
|
||||
void
|
||||
doSend(Transport::Packet&& packet) final;
|
||||
doSend(const Block& packet) final;
|
||||
|
||||
void
|
||||
schedulePing();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -36,7 +36,8 @@ NFD_REGISTER_STRATEGY(AccessStrategy);
|
||||
|
||||
AccessStrategy::AccessStrategy(Forwarder& forwarder, const Name& name)
|
||||
: Strategy(forwarder)
|
||||
, m_removeFaceInfoConn(beforeRemoveFace.connect([this] (const Face& face) { removeFaceInfo(face); }))
|
||||
, m_rttEstimatorOpts(make_shared<RttEstimator::Options>()) // use the default options
|
||||
, m_removeFaceConn(beforeRemoveFace.connect([this] (const Face& face) { m_fit.erase(face.getId()); }))
|
||||
{
|
||||
ParsedInstanceName parsed = parseInstanceName(name);
|
||||
if (!parsed.parameters.empty()) {
|
||||
@@ -129,7 +130,7 @@ AccessStrategy::sendToLastNexthop(const FaceEndpoint& ingress, const Interest& i
|
||||
}
|
||||
|
||||
Face* outFace = this->getFace(mi.lastNexthop);
|
||||
if (outFace == nullptr || !fibEntry.hasNextHop(*outFace, 0)) {
|
||||
if (outFace == nullptr || !fibEntry.hasNextHop(*outFace)) {
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " last-nexthop-gone");
|
||||
return false;
|
||||
}
|
||||
@@ -139,25 +140,27 @@ AccessStrategy::sendToLastNexthop(const FaceEndpoint& ingress, const Interest& i
|
||||
return false;
|
||||
}
|
||||
|
||||
auto rto = mi.rtt.computeRto();
|
||||
auto rto = mi.rtt.getEstimatedRto();
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " interestTo " << mi.lastNexthop
|
||||
<< " last-nexthop rto=" << time::duration_cast<time::microseconds>(rto).count());
|
||||
|
||||
this->sendInterest(pitEntry, FaceEndpoint(*outFace, 0), interest);
|
||||
if (!this->sendInterest(pitEntry, *outFace, interest)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// schedule RTO timeout
|
||||
PitInfo* pi = pitEntry->insertStrategyInfo<PitInfo>().first;
|
||||
pi->rtoTimer = getScheduler().schedule(rto, [=] {
|
||||
afterRtoTimeout(weak_ptr<pit::Entry>(pitEntry),
|
||||
ingress.face.getId(), ingress.endpoint, mi.lastNexthop);
|
||||
});
|
||||
pi->rtoTimer = getScheduler().schedule(rto,
|
||||
[this, pitWeak = weak_ptr<pit::Entry>(pitEntry), face = ingress.face.getId(), nh = mi.lastNexthop] {
|
||||
afterRtoTimeout(pitWeak, face, nh);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
AccessStrategy::afterRtoTimeout(const weak_ptr<pit::Entry>& pitWeak,
|
||||
FaceId inFaceId, EndpointId inEndpointId, FaceId firstOutFaceId)
|
||||
FaceId inFaceId, FaceId firstOutFaceId)
|
||||
{
|
||||
shared_ptr<pit::Entry> pitEntry = pitWeak.lock();
|
||||
// if PIT entry is gone, RTO timer should have been cancelled
|
||||
@@ -170,7 +173,7 @@ AccessStrategy::afterRtoTimeout(const weak_ptr<pit::Entry>& pitWeak,
|
||||
return;
|
||||
}
|
||||
|
||||
auto inRecord = pitEntry->getInRecord(*inFace, inEndpointId);
|
||||
auto inRecord = pitEntry->getInRecord(*inFace);
|
||||
// in-record is erased only if Interest is satisfied, and RTO timer should have been cancelled
|
||||
// note: if this strategy is extended to send Nacks, that would also erase the in-record,
|
||||
// and the RTO timer should be cancelled in that case as well
|
||||
@@ -197,8 +200,9 @@ AccessStrategy::multicast(const Face& inFace, const Interest& interest,
|
||||
continue;
|
||||
}
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " interestTo " << outFace.getId() << " multicast");
|
||||
this->sendInterest(pitEntry, FaceEndpoint(outFace, 0), interest);
|
||||
++nSent;
|
||||
if (this->sendInterest(pitEntry, outFace, interest)) {
|
||||
++nSent;
|
||||
}
|
||||
}
|
||||
return nSent;
|
||||
}
|
||||
@@ -217,7 +221,7 @@ AccessStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
|
||||
return;
|
||||
}
|
||||
|
||||
auto outRecord = pitEntry->getOutRecord(ingress.face, 0);
|
||||
auto outRecord = pitEntry->getOutRecord(ingress.face);
|
||||
if (outRecord == pitEntry->out_end()) { // no out-record
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " dataFrom " << ingress << " no-out-record");
|
||||
return;
|
||||
@@ -226,15 +230,16 @@ AccessStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
|
||||
auto rtt = time::steady_clock::now() - outRecord->getLastRenewed();
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " dataFrom " << ingress
|
||||
<< " rtt=" << time::duration_cast<time::microseconds>(rtt).count());
|
||||
this->updateMeasurements(ingress.face, data, time::duration_cast<RttEstimator::Duration>(rtt));
|
||||
this->updateMeasurements(ingress.face, data, rtt);
|
||||
}
|
||||
|
||||
void
|
||||
AccessStrategy::updateMeasurements(const Face& inFace, const Data& data,
|
||||
const RttEstimator::Duration& rtt)
|
||||
AccessStrategy::updateMeasurements(const Face& inFace, const Data& data, time::nanoseconds rtt)
|
||||
{
|
||||
///\todo move FaceInfoTable out of AccessStrategy instance, to Measurements or somewhere else
|
||||
FaceInfo& fi = m_fit[inFace.getId()];
|
||||
auto ret = m_fit.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(inFace.getId()),
|
||||
std::forward_as_tuple(m_rttEstimatorOpts));
|
||||
FaceInfo& fi = ret.first->second;
|
||||
fi.rtt.addMeasurement(rtt);
|
||||
|
||||
MtInfo* mi = this->addPrefixMeasurements(data);
|
||||
@@ -250,15 +255,15 @@ AccessStrategy::updateMeasurements(const Face& inFace, const Data& data,
|
||||
std::tuple<Name, AccessStrategy::MtInfo*>
|
||||
AccessStrategy::findPrefixMeasurements(const pit::Entry& pitEntry)
|
||||
{
|
||||
measurements::Entry* me = this->getMeasurements().findLongestPrefixMatch(pitEntry);
|
||||
auto me = this->getMeasurements().findLongestPrefixMatch(pitEntry);
|
||||
if (me == nullptr) {
|
||||
return std::make_tuple(Name(), nullptr);
|
||||
}
|
||||
|
||||
MtInfo* mi = me->getStrategyInfo<MtInfo>();
|
||||
BOOST_ASSERT(mi != nullptr);
|
||||
// XXX after runtime strategy change, it's possible that me exists but mi doesn't exist;
|
||||
// this case needs another longest prefix match until mi is found
|
||||
auto mi = me->getStrategyInfo<MtInfo>();
|
||||
// TODO: after a runtime strategy change, it's possible that a measurements::Entry exists but
|
||||
// the corresponding MtInfo doesn't exist (mi == nullptr); this case needs another longest
|
||||
// prefix match until an MtInfo is found.
|
||||
return std::make_tuple(me->getName(), mi);
|
||||
}
|
||||
|
||||
@@ -276,14 +281,7 @@ AccessStrategy::addPrefixMeasurements(const Data& data)
|
||||
}
|
||||
|
||||
this->getMeasurements().extendLifetime(*me, 8_s);
|
||||
|
||||
return me->insertStrategyInfo<MtInfo>().first;
|
||||
}
|
||||
|
||||
void
|
||||
AccessStrategy::removeFaceInfo(const Face& face)
|
||||
{
|
||||
m_fit.erase(face.getId());
|
||||
return me->insertStrategyInfo<MtInfo>(m_rttEstimatorOpts).first;
|
||||
}
|
||||
|
||||
} // namespace fw
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -28,7 +28,8 @@
|
||||
|
||||
#include "strategy.hpp"
|
||||
#include "retx-suppression-fixed.hpp"
|
||||
#include "core/rtt-estimator.hpp"
|
||||
|
||||
#include <ndn-cxx/util/rtt-estimator.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
@@ -43,8 +44,6 @@ namespace fw {
|
||||
* the granularity of this knowledge is the parent of Data Name.
|
||||
* 3. Forward subsequent Interests to the last working nexthop.
|
||||
* If it doesn't respond, multicast again.
|
||||
*
|
||||
* \note This strategy is not EndpointId-aware.
|
||||
*/
|
||||
class AccessStrategy : public Strategy
|
||||
{
|
||||
@@ -65,6 +64,8 @@ public: // triggers
|
||||
const FaceEndpoint& ingress, const Data& data) override;
|
||||
|
||||
private: // StrategyInfo
|
||||
using RttEstimator = ndn::util::RttEstimator;
|
||||
|
||||
/** \brief StrategyInfo on PIT entry
|
||||
*/
|
||||
class PitInfo : public StrategyInfo
|
||||
@@ -91,9 +92,15 @@ private: // StrategyInfo
|
||||
return 1011;
|
||||
}
|
||||
|
||||
explicit
|
||||
MtInfo(shared_ptr<const RttEstimator::Options> opts)
|
||||
: rtt(std::move(opts))
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
FaceId lastNexthop = face::INVALID_FACEID;
|
||||
RttEstimator rtt{1, 1_ms, 0.1};
|
||||
RttEstimator rtt;
|
||||
};
|
||||
|
||||
/** \brief find per-prefix measurements for Interest
|
||||
@@ -108,17 +115,22 @@ private: // StrategyInfo
|
||||
addPrefixMeasurements(const Data& data);
|
||||
|
||||
/** \brief global per-face StrategyInfo
|
||||
* \todo Currently stored inside AccessStrategy instance; should be moved
|
||||
* to measurements table or somewhere else.
|
||||
*/
|
||||
struct FaceInfo
|
||||
class FaceInfo
|
||||
{
|
||||
RttEstimator rtt{1, 1_ms, 0.1};
|
||||
public:
|
||||
explicit
|
||||
FaceInfo(shared_ptr<const RttEstimator::Options> opts)
|
||||
: rtt(std::move(opts))
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
RttEstimator rtt;
|
||||
};
|
||||
|
||||
typedef std::unordered_map<FaceId, FaceInfo> FaceInfoTable;
|
||||
|
||||
void
|
||||
removeFaceInfo(const Face& face);
|
||||
|
||||
private: // forwarding procedures
|
||||
void
|
||||
afterReceiveNewInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
@@ -138,11 +150,11 @@ private: // forwarding procedures
|
||||
|
||||
void
|
||||
afterRtoTimeout(const weak_ptr<pit::Entry>& pitWeak,
|
||||
FaceId inFaceId, EndpointId inEndpointId, FaceId firstOutFaceId);
|
||||
FaceId inFaceId, FaceId firstOutFaceId);
|
||||
|
||||
/** \brief multicast to all nexthops
|
||||
* \param exceptFace don't forward to this face; also, inFace is always excluded
|
||||
* \return how many Interests are sent
|
||||
* \param exceptFace don't forward to this face; also, \p inFace is always excluded
|
||||
* \return number of Interests that were sent
|
||||
*/
|
||||
size_t
|
||||
multicast(const Face& inFace, const Interest& interest,
|
||||
@@ -150,13 +162,13 @@ private: // forwarding procedures
|
||||
FaceId exceptFace = face::INVALID_FACEID);
|
||||
|
||||
void
|
||||
updateMeasurements(const Face& inFace, const Data& data,
|
||||
const RttEstimator::Duration& rtt);
|
||||
updateMeasurements(const Face& inFace, const Data& data, time::nanoseconds rtt);
|
||||
|
||||
private:
|
||||
FaceInfoTable m_fit;
|
||||
const shared_ptr<const RttEstimator::Options> m_rttEstimatorOpts;
|
||||
std::unordered_map<FaceId, FaceInfo> m_fit;
|
||||
RetxSuppressionFixed m_retxSuppression;
|
||||
signal::ScopedConnection m_removeFaceInfoConn;
|
||||
signal::ScopedConnection m_removeFaceConn;
|
||||
};
|
||||
|
||||
} // namespace fw
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -75,7 +75,7 @@ canForwardToLegacy(const pit::Entry& pitEntry, const Face& face)
|
||||
}
|
||||
|
||||
int
|
||||
findDuplicateNonce(const pit::Entry& pitEntry, uint32_t nonce, const Face& face)
|
||||
findDuplicateNonce(const pit::Entry& pitEntry, Interest::Nonce nonce, const Face& face)
|
||||
{
|
||||
int dnw = DUPLICATE_NONCE_NONE;
|
||||
|
||||
@@ -140,7 +140,7 @@ findEligibleNextHopWithEarliestOutRecord(const Face& inFace, const Interest& int
|
||||
if (!isNextHopEligible(inFace, interest, *it, pitEntry))
|
||||
continue;
|
||||
|
||||
auto outRecord = pitEntry->getOutRecord(it->getFace(), 0);
|
||||
auto outRecord = pitEntry->getOutRecord(it->getFace());
|
||||
BOOST_ASSERT(outRecord != pitEntry->out_end());
|
||||
if (outRecord->getLastRenewed() < earliestRenewed) {
|
||||
found = it;
|
||||
@@ -166,7 +166,7 @@ isNextHopEligible(const Face& inFace, const Interest& interest,
|
||||
|
||||
if (wantUnused) {
|
||||
// nexthop must not have unexpired out-record
|
||||
auto outRecord = pitEntry->getOutRecord(outFace, 0);
|
||||
auto outRecord = pitEntry->getOutRecord(outFace);
|
||||
if (outRecord != pitEntry->out_end() && outRecord->getExpiry() > now) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -23,8 +23,8 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FW_PIT_ALGORITHM_HPP
|
||||
#define NFD_DAEMON_FW_PIT_ALGORITHM_HPP
|
||||
#ifndef NFD_DAEMON_FW_ALGORITHM_HPP
|
||||
#define NFD_DAEMON_FW_ALGORITHM_HPP
|
||||
|
||||
#include "fw/scope-prefix.hpp"
|
||||
#include "table/fib.hpp"
|
||||
@@ -70,7 +70,7 @@ enum DuplicateNonceWhere {
|
||||
* \return OR'ed DuplicateNonceWhere
|
||||
*/
|
||||
int
|
||||
findDuplicateNonce(const pit::Entry& pitEntry, uint32_t nonce, const Face& face);
|
||||
findDuplicateNonce(const pit::Entry& pitEntry, Interest::Nonce nonce, const Face& face);
|
||||
|
||||
/** \brief determine whether \p pitEntry has any pending out-records
|
||||
* \return true if there is at least one out-record waiting for Data
|
||||
@@ -110,4 +110,4 @@ isNextHopEligible(const Face& inFace, const Interest& interest,
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FW_PIT_ALGORITHM_HPP
|
||||
#endif // NFD_DAEMON_FW_ALGORITHM_HPP
|
||||
+29
-147
@@ -30,171 +30,54 @@ namespace nfd {
|
||||
namespace fw {
|
||||
namespace asf {
|
||||
|
||||
NFD_LOG_INIT(AsfMeasurements);
|
||||
const time::nanoseconds FaceInfo::RTT_NO_MEASUREMENT{-1};
|
||||
const time::nanoseconds FaceInfo::RTT_TIMEOUT{-2};
|
||||
|
||||
const RttStats::Rtt RttStats::RTT_TIMEOUT(-1.0);
|
||||
const RttStats::Rtt RttStats::RTT_NO_MEASUREMENT(0.0);
|
||||
const double RttStats::ALPHA = 0.125;
|
||||
|
||||
RttStats::RttStats()
|
||||
: m_srtt(RTT_NO_MEASUREMENT)
|
||||
, m_rtt(RTT_NO_MEASUREMENT)
|
||||
time::nanoseconds
|
||||
FaceInfo::scheduleTimeout(const Name& interestName, scheduler::EventCallback cb)
|
||||
{
|
||||
BOOST_ASSERT(!m_timeoutEvent);
|
||||
m_lastInterestName = interestName;
|
||||
m_timeoutEvent = getScheduler().schedule(m_rttEstimator.getEstimatedRto(), std::move(cb));
|
||||
return m_rttEstimator.getEstimatedRto();
|
||||
}
|
||||
|
||||
void
|
||||
RttStats::addRttMeasurement(RttEstimator::Duration& durationRtt)
|
||||
FaceInfo::cancelTimeout(const Name& prefix)
|
||||
{
|
||||
m_rtt = static_cast<RttStats::Rtt>(durationRtt.count());
|
||||
|
||||
m_rttEstimator.addMeasurement(durationRtt);
|
||||
|
||||
m_srtt = computeSrtt(m_srtt, m_rtt);
|
||||
}
|
||||
|
||||
RttStats::Rtt
|
||||
RttStats::computeSrtt(Rtt previousSrtt, Rtt currentRtt)
|
||||
{
|
||||
if (previousSrtt == RTT_NO_MEASUREMENT) {
|
||||
return currentRtt;
|
||||
if (m_lastInterestName.isPrefixOf(prefix)) {
|
||||
m_timeoutEvent.cancel();
|
||||
}
|
||||
|
||||
return Rtt(ALPHA * currentRtt + (1 - ALPHA) * previousSrtt);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FaceInfo::FaceInfo()
|
||||
: m_isTimeoutScheduled(false)
|
||||
, m_nSilentTimeouts(0)
|
||||
{
|
||||
}
|
||||
|
||||
FaceInfo::~FaceInfo()
|
||||
{
|
||||
cancelTimeoutEvent();
|
||||
m_measurementExpirationId.cancel();
|
||||
}
|
||||
|
||||
void
|
||||
FaceInfo::setTimeoutEvent(const scheduler::EventId& id, const Name& interestName)
|
||||
{
|
||||
if (!m_isTimeoutScheduled) {
|
||||
m_timeoutEventId = id;
|
||||
m_isTimeoutScheduled = true;
|
||||
m_lastInterestName = interestName;
|
||||
}
|
||||
else {
|
||||
NDN_THROW(FaceInfo::Error("Tried to schedule a timeout for a face that already has a timeout scheduled"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FaceInfo::cancelTimeoutEvent()
|
||||
{
|
||||
m_timeoutEventId.cancel();
|
||||
m_isTimeoutScheduled = false;
|
||||
}
|
||||
|
||||
void
|
||||
FaceInfo::cancelTimeoutEvent(const Name& prefix)
|
||||
{
|
||||
if (isTimeoutScheduled() && doesNameMatchLastInterest(prefix)) {
|
||||
cancelTimeoutEvent();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
FaceInfo::doesNameMatchLastInterest(const Name& name)
|
||||
{
|
||||
return m_lastInterestName.isPrefixOf(name);
|
||||
}
|
||||
|
||||
void
|
||||
FaceInfo::recordRtt(const shared_ptr<pit::Entry>& pitEntry, const Face& inFace)
|
||||
{
|
||||
// Calculate RTT
|
||||
auto outRecord = pitEntry->getOutRecord(inFace, 0);
|
||||
|
||||
if (outRecord == pitEntry->out_end()) { // no out-record
|
||||
NFD_LOG_TRACE(pitEntry->getInterest() << " dataFrom inFace=" << inFace.getId() << " no-out-record");
|
||||
return;
|
||||
}
|
||||
|
||||
time::steady_clock::Duration steadyRtt = time::steady_clock::now() - outRecord->getLastRenewed();
|
||||
auto durationRtt = time::duration_cast<RttEstimator::Duration>(steadyRtt);
|
||||
|
||||
m_rttStats.addRttMeasurement(durationRtt);
|
||||
|
||||
NFD_LOG_TRACE("Recording RTT for FaceId: " << inFace.getId()
|
||||
<< " RTT: " << m_rttStats.getRtt()
|
||||
<< " SRTT: " << m_rttStats.getSrtt());
|
||||
}
|
||||
|
||||
void
|
||||
FaceInfo::recordTimeout(const Name& interestName)
|
||||
{
|
||||
m_rttStats.recordTimeout();
|
||||
cancelTimeoutEvent(interestName);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NamespaceInfo::NamespaceInfo()
|
||||
: m_isProbingDue(false)
|
||||
, m_hasFirstProbeBeenScheduled(false)
|
||||
{
|
||||
}
|
||||
|
||||
FaceInfo*
|
||||
NamespaceInfo::getFaceInfo(const fib::Entry&, FaceId faceId)
|
||||
NamespaceInfo::getFaceInfo(FaceId faceId)
|
||||
{
|
||||
auto it = m_fit.find(faceId);
|
||||
if (it != m_fit.end()) {
|
||||
return &it->second;
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
auto it = m_fiMap.find(faceId);
|
||||
return it != m_fiMap.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
FaceInfo&
|
||||
NamespaceInfo::getOrCreateFaceInfo(const fib::Entry&, FaceId faceId)
|
||||
NamespaceInfo::getOrCreateFaceInfo(FaceId faceId)
|
||||
{
|
||||
auto it = m_fit.find(faceId);
|
||||
FaceInfo* info = nullptr;
|
||||
|
||||
if (it == m_fit.end()) {
|
||||
const auto& pair = m_fit.emplace(faceId, FaceInfo());
|
||||
info = &pair.first->second;
|
||||
|
||||
extendFaceInfoLifetime(*info, faceId);
|
||||
auto ret = m_fiMap.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(faceId),
|
||||
std::forward_as_tuple(m_rttEstimatorOpts));
|
||||
auto& faceInfo = ret.first->second;
|
||||
if (ret.second) {
|
||||
extendFaceInfoLifetime(faceInfo, faceId);
|
||||
}
|
||||
else {
|
||||
info = &it->second;
|
||||
}
|
||||
|
||||
return *info;
|
||||
}
|
||||
|
||||
void
|
||||
NamespaceInfo::expireFaceInfo(FaceId faceId)
|
||||
{
|
||||
m_fit.erase(faceId);
|
||||
return faceInfo;
|
||||
}
|
||||
|
||||
void
|
||||
NamespaceInfo::extendFaceInfoLifetime(FaceInfo& info, FaceId faceId)
|
||||
{
|
||||
// Cancel previous expiration
|
||||
info.getMeasurementExpirationEventId().cancel();
|
||||
|
||||
// Refresh measurement
|
||||
auto id = getScheduler().schedule(AsfMeasurements::MEASUREMENTS_LIFETIME,
|
||||
[=] { expireFaceInfo(faceId); });
|
||||
info.setMeasurementExpirationEventId(id);
|
||||
info.m_measurementExpiration = getScheduler().schedule(AsfMeasurements::MEASUREMENTS_LIFETIME,
|
||||
[=] { m_fiMap.erase(faceId); });
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -204,22 +87,21 @@ constexpr time::microseconds AsfMeasurements::MEASUREMENTS_LIFETIME;
|
||||
|
||||
AsfMeasurements::AsfMeasurements(MeasurementsAccessor& measurements)
|
||||
: m_measurements(measurements)
|
||||
, m_rttEstimatorOpts(make_shared<ndn::util::RttEstimator::Options>())
|
||||
{
|
||||
}
|
||||
|
||||
FaceInfo*
|
||||
AsfMeasurements::getFaceInfo(const fib::Entry& fibEntry, const Interest& interest, FaceId faceId)
|
||||
{
|
||||
NamespaceInfo& info = getOrCreateNamespaceInfo(fibEntry, interest);
|
||||
return info.getFaceInfo(fibEntry, faceId);
|
||||
return getOrCreateNamespaceInfo(fibEntry, interest).getFaceInfo(faceId);
|
||||
}
|
||||
|
||||
FaceInfo&
|
||||
AsfMeasurements::getOrCreateFaceInfo(const fib::Entry& fibEntry, const Interest& interest,
|
||||
FaceId faceId)
|
||||
{
|
||||
NamespaceInfo& info = getOrCreateNamespaceInfo(fibEntry, interest);
|
||||
return info.getOrCreateFaceInfo(fibEntry, faceId);
|
||||
return getOrCreateNamespaceInfo(fibEntry, interest).getOrCreateFaceInfo(faceId);
|
||||
}
|
||||
|
||||
NamespaceInfo*
|
||||
@@ -233,7 +115,7 @@ AsfMeasurements::getNamespaceInfo(const Name& prefix)
|
||||
// Set or update entry lifetime
|
||||
extendLifetime(*me);
|
||||
|
||||
NamespaceInfo* info = me->insertStrategyInfo<NamespaceInfo>().first;
|
||||
NamespaceInfo* info = me->insertStrategyInfo<NamespaceInfo>(m_rttEstimatorOpts).first;
|
||||
BOOST_ASSERT(info != nullptr);
|
||||
return info;
|
||||
}
|
||||
@@ -256,7 +138,7 @@ AsfMeasurements::getOrCreateNamespaceInfo(const fib::Entry& fibEntry, const Inte
|
||||
// Set or update entry lifetime
|
||||
extendLifetime(*me);
|
||||
|
||||
NamespaceInfo* info = me->insertStrategyInfo<NamespaceInfo>().first;
|
||||
NamespaceInfo* info = me->insertStrategyInfo<NamespaceInfo>(m_rttEstimatorOpts).first;
|
||||
BOOST_ASSERT(info != nullptr);
|
||||
return *info;
|
||||
}
|
||||
|
||||
+57
-164
@@ -26,144 +26,68 @@
|
||||
#ifndef NFD_DAEMON_FW_ASF_MEASUREMENTS_HPP
|
||||
#define NFD_DAEMON_FW_ASF_MEASUREMENTS_HPP
|
||||
|
||||
#include "core/rtt-estimator.hpp"
|
||||
#include "fw/strategy-info.hpp"
|
||||
#include "table/measurements-accessor.hpp"
|
||||
|
||||
#include <ndn-cxx/util/rtt-estimator.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
namespace asf {
|
||||
|
||||
class RttStats
|
||||
{
|
||||
public:
|
||||
typedef time::duration<double, boost::micro> Rtt;
|
||||
|
||||
RttStats();
|
||||
|
||||
void
|
||||
addRttMeasurement(RttEstimator::Duration& durationRtt);
|
||||
|
||||
void
|
||||
recordTimeout()
|
||||
{
|
||||
m_rtt = RTT_TIMEOUT;
|
||||
}
|
||||
|
||||
Rtt
|
||||
getRtt() const
|
||||
{
|
||||
return m_rtt;
|
||||
}
|
||||
|
||||
Rtt
|
||||
getSrtt() const
|
||||
{
|
||||
return m_srtt;
|
||||
}
|
||||
|
||||
RttEstimator::Duration
|
||||
computeRto() const
|
||||
{
|
||||
return m_rttEstimator.computeRto();
|
||||
}
|
||||
|
||||
private:
|
||||
static Rtt
|
||||
computeSrtt(Rtt previousSrtt, Rtt currentRtt);
|
||||
|
||||
public:
|
||||
static const Rtt RTT_TIMEOUT;
|
||||
static const Rtt RTT_NO_MEASUREMENT;
|
||||
|
||||
private:
|
||||
Rtt m_srtt;
|
||||
Rtt m_rtt;
|
||||
RttEstimator m_rttEstimator;
|
||||
|
||||
static const double ALPHA;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** \brief Strategy information for each face in a namespace
|
||||
*/
|
||||
class FaceInfo
|
||||
{
|
||||
public:
|
||||
class Error : public std::runtime_error
|
||||
explicit
|
||||
FaceInfo(shared_ptr<const ndn::util::RttEstimator::Options> opts)
|
||||
: m_rttEstimator(std::move(opts))
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
Error(const std::string& what)
|
||||
: std::runtime_error(what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
FaceInfo();
|
||||
|
||||
~FaceInfo();
|
||||
|
||||
void
|
||||
setTimeoutEvent(const scheduler::EventId& id, const Name& interestName);
|
||||
|
||||
void
|
||||
setMeasurementExpirationEventId(const scheduler::EventId& id)
|
||||
{
|
||||
m_measurementExpirationId = id;
|
||||
}
|
||||
|
||||
const scheduler::EventId&
|
||||
getMeasurementExpirationEventId()
|
||||
{
|
||||
return m_measurementExpirationId;
|
||||
}
|
||||
|
||||
void
|
||||
cancelTimeoutEvent(const Name& prefix);
|
||||
|
||||
bool
|
||||
isTimeoutScheduled() const
|
||||
{
|
||||
return m_isTimeoutScheduled;
|
||||
return !!m_timeoutEvent;
|
||||
}
|
||||
|
||||
time::nanoseconds
|
||||
scheduleTimeout(const Name& interestName, scheduler::EventCallback cb);
|
||||
|
||||
void
|
||||
cancelTimeout(const Name& prefix);
|
||||
|
||||
void
|
||||
recordRtt(time::nanoseconds rtt)
|
||||
{
|
||||
m_lastRtt = rtt;
|
||||
m_rttEstimator.addMeasurement(rtt);
|
||||
}
|
||||
|
||||
void
|
||||
recordRtt(const shared_ptr<pit::Entry>& pitEntry, const Face& inFace);
|
||||
|
||||
void
|
||||
recordTimeout(const Name& interestName);
|
||||
recordTimeout(const Name& interestName)
|
||||
{
|
||||
m_lastRtt = RTT_TIMEOUT;
|
||||
cancelTimeout(interestName);
|
||||
}
|
||||
|
||||
bool
|
||||
isTimeout() const
|
||||
hasTimeout() const
|
||||
{
|
||||
return getRtt() == RttStats::RTT_TIMEOUT;
|
||||
return getLastRtt() == RTT_TIMEOUT;
|
||||
}
|
||||
|
||||
RttEstimator::Duration
|
||||
computeRto() const
|
||||
time::nanoseconds
|
||||
getLastRtt() const
|
||||
{
|
||||
return m_rttStats.computeRto();
|
||||
return m_lastRtt;
|
||||
}
|
||||
|
||||
RttStats::Rtt
|
||||
getRtt() const
|
||||
{
|
||||
return m_rttStats.getRtt();
|
||||
}
|
||||
|
||||
RttStats::Rtt
|
||||
time::nanoseconds
|
||||
getSrtt() const
|
||||
{
|
||||
return m_rttStats.getSrtt();
|
||||
}
|
||||
|
||||
bool
|
||||
hasSrttMeasurement() const
|
||||
{
|
||||
return getSrtt() != RttStats::RTT_NO_MEASUREMENT;
|
||||
return m_rttEstimator.getSmoothedRtt();
|
||||
}
|
||||
|
||||
size_t
|
||||
@@ -178,85 +102,53 @@ public:
|
||||
m_nSilentTimeouts = nSilentTimeouts;
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
cancelTimeoutEvent();
|
||||
|
||||
bool
|
||||
doesNameMatchLastInterest(const Name& name);
|
||||
public:
|
||||
static const time::nanoseconds RTT_NO_MEASUREMENT;
|
||||
static const time::nanoseconds RTT_TIMEOUT;
|
||||
|
||||
private:
|
||||
RttStats m_rttStats;
|
||||
ndn::util::RttEstimator m_rttEstimator;
|
||||
time::nanoseconds m_lastRtt = RTT_NO_MEASUREMENT;
|
||||
Name m_lastInterestName;
|
||||
size_t m_nSilentTimeouts = 0;
|
||||
|
||||
// Timeout associated with measurement
|
||||
scheduler::EventId m_measurementExpirationId;
|
||||
scheduler::ScopedEventId m_measurementExpiration;
|
||||
friend class NamespaceInfo;
|
||||
|
||||
// RTO associated with Interest
|
||||
scheduler::EventId m_timeoutEventId;
|
||||
bool m_isTimeoutScheduled;
|
||||
size_t m_nSilentTimeouts;
|
||||
scheduler::ScopedEventId m_timeoutEvent;
|
||||
};
|
||||
|
||||
typedef std::unordered_map<FaceId, FaceInfo> FaceInfoTable;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** \brief stores stategy information about each face in this namespace
|
||||
/** \brief Stores strategy information about each face in this namespace
|
||||
*/
|
||||
class NamespaceInfo : public StrategyInfo
|
||||
{
|
||||
public:
|
||||
NamespaceInfo();
|
||||
|
||||
static constexpr int
|
||||
getTypeId()
|
||||
{
|
||||
return 1030;
|
||||
}
|
||||
|
||||
FaceInfo&
|
||||
getOrCreateFaceInfo(const fib::Entry& fibEntry, FaceId faceId);
|
||||
explicit
|
||||
NamespaceInfo(shared_ptr<const ndn::util::RttEstimator::Options> opts)
|
||||
: m_rttEstimatorOpts(std::move(opts))
|
||||
{
|
||||
}
|
||||
|
||||
FaceInfo*
|
||||
getFaceInfo(const fib::Entry& fibEntry, FaceId faceId);
|
||||
getFaceInfo(FaceId faceId);
|
||||
|
||||
void
|
||||
expireFaceInfo(FaceId faceId);
|
||||
FaceInfo&
|
||||
getOrCreateFaceInfo(FaceId faceId);
|
||||
|
||||
void
|
||||
extendFaceInfoLifetime(FaceInfo& info, FaceId faceId);
|
||||
|
||||
FaceInfo*
|
||||
get(FaceId faceId)
|
||||
{
|
||||
if (m_fit.find(faceId) != m_fit.end()) {
|
||||
return &m_fit.at(faceId);
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
FaceInfoTable::iterator
|
||||
find(FaceId faceId)
|
||||
{
|
||||
return m_fit.find(faceId);
|
||||
}
|
||||
|
||||
FaceInfoTable::iterator
|
||||
end()
|
||||
{
|
||||
return m_fit.end();
|
||||
}
|
||||
|
||||
const FaceInfoTable::iterator
|
||||
insert(FaceId faceId)
|
||||
{
|
||||
return m_fit.emplace(faceId, FaceInfo()).first;
|
||||
}
|
||||
|
||||
bool
|
||||
isProbingDue() const
|
||||
{
|
||||
@@ -272,20 +164,20 @@ public:
|
||||
bool
|
||||
isFirstProbeScheduled() const
|
||||
{
|
||||
return m_hasFirstProbeBeenScheduled;
|
||||
return m_isFirstProbeScheduled;
|
||||
}
|
||||
|
||||
void
|
||||
setHasFirstProbeBeenScheduled(bool hasBeenScheduled)
|
||||
setIsFirstProbeScheduled(bool isScheduled)
|
||||
{
|
||||
m_hasFirstProbeBeenScheduled = hasBeenScheduled;
|
||||
m_isFirstProbeScheduled = isScheduled;
|
||||
}
|
||||
|
||||
private:
|
||||
FaceInfoTable m_fit;
|
||||
|
||||
bool m_isProbingDue;
|
||||
bool m_hasFirstProbeBeenScheduled;
|
||||
std::unordered_map<FaceId, FaceInfo> m_fiMap;
|
||||
shared_ptr<const ndn::util::RttEstimator::Options> m_rttEstimatorOpts;
|
||||
bool m_isProbingDue = false;
|
||||
bool m_isFirstProbeScheduled = false;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -320,6 +212,7 @@ public:
|
||||
|
||||
private:
|
||||
MeasurementsAccessor& m_measurements;
|
||||
shared_ptr<const ndn::util::RttEstimator::Options> m_rttEstimatorOpts;
|
||||
};
|
||||
|
||||
} // namespace asf
|
||||
|
||||
@@ -46,18 +46,16 @@ ProbingModule::ProbingModule(AsfMeasurements& measurements)
|
||||
}
|
||||
|
||||
void
|
||||
ProbingModule::scheduleProbe(const fib::Entry& fibEntry, const time::milliseconds& interval)
|
||||
ProbingModule::scheduleProbe(const fib::Entry& fibEntry, time::milliseconds interval)
|
||||
{
|
||||
Name prefix = fibEntry.getPrefix();
|
||||
|
||||
// Set the probing flag for the namespace to true after passed interval of time
|
||||
getScheduler().schedule(interval, [this, prefix] {
|
||||
NamespaceInfo* info = m_measurements.getNamespaceInfo(prefix);
|
||||
|
||||
if (info == nullptr) {
|
||||
// fib::Entry with the passed prefix has been removed or the fib::Entry has
|
||||
// a name that is not controlled by the AsfStrategy
|
||||
return;
|
||||
// FIB entry with the passed prefix has been removed or
|
||||
// it has a name that is not controlled by the AsfStrategy
|
||||
}
|
||||
else {
|
||||
info->setIsProbingDue(true);
|
||||
@@ -69,16 +67,7 @@ Face*
|
||||
ProbingModule::getFaceToProbe(const Face& inFace, const Interest& interest,
|
||||
const fib::Entry& fibEntry, const Face& faceUsed)
|
||||
{
|
||||
FaceInfoFacePairSet rankedFaces(
|
||||
[] (const auto& pairLhs, const auto& pairRhs) -> bool {
|
||||
// Sort by RTT
|
||||
// If a face has timed-out, rank it behind non-timed-out faces
|
||||
FaceInfo& lhs = *pairLhs.first;
|
||||
FaceInfo& rhs = *pairRhs.first;
|
||||
|
||||
return (!lhs.isTimeout() && rhs.isTimeout()) ||
|
||||
(lhs.isTimeout() == rhs.isTimeout() && lhs.getSrtt() < rhs.getSrtt());
|
||||
});
|
||||
FaceInfoFacePairSet rankedFaces;
|
||||
|
||||
// Put eligible faces into rankedFaces. If a face does not have an RTT measurement,
|
||||
// immediately pick the face for probing
|
||||
@@ -94,7 +83,7 @@ ProbingModule::getFaceToProbe(const Face& inFace, const Interest& interest,
|
||||
|
||||
FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace.getId());
|
||||
// If no RTT has been recorded, probe this face
|
||||
if (info == nullptr || !info->hasSrttMeasurement()) {
|
||||
if (info == nullptr || info->getLastRtt() == FaceInfo::RTT_NO_MEASUREMENT) {
|
||||
return &hopFace;
|
||||
}
|
||||
|
||||
@@ -107,7 +96,7 @@ ProbingModule::getFaceToProbe(const Face& inFace, const Interest& interest,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return getFaceBasedOnProbability(rankedFaces);
|
||||
return chooseFace(rankedFaces);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -119,10 +108,10 @@ ProbingModule::isProbingNeeded(const fib::Entry& fibEntry, const Interest& inter
|
||||
// If a first probe has not been scheduled for a namespace
|
||||
if (!info.isFirstProbeScheduled()) {
|
||||
// Schedule first probe between 0 and 5 seconds
|
||||
uint64_t interval = getRandomNumber(0, 5000);
|
||||
static std::uniform_int_distribution<> randDist(0, 5000);
|
||||
auto interval = randDist(ndn::random::getRandomNumberEngine());
|
||||
scheduleProbe(fibEntry, time::milliseconds(interval));
|
||||
|
||||
info.setHasFirstProbeBeenScheduled(true);
|
||||
info.setIsFirstProbeScheduled(true);
|
||||
}
|
||||
|
||||
return info.isProbingDue();
|
||||
@@ -140,10 +129,11 @@ ProbingModule::afterForwardingProbe(const fib::Entry& fibEntry, const Interest&
|
||||
}
|
||||
|
||||
Face*
|
||||
ProbingModule::getFaceBasedOnProbability(const FaceInfoFacePairSet& rankedFaces)
|
||||
ProbingModule::chooseFace(const FaceInfoFacePairSet& rankedFaces)
|
||||
{
|
||||
double randomNumber = getRandomNumber(0, 1);
|
||||
uint64_t rankSum = ((rankedFaces.size() + 1) * rankedFaces.size()) / 2;
|
||||
static std::uniform_real_distribution<> randDist;
|
||||
double randomNumber = randDist(ndn::random::getRandomNumberEngine());
|
||||
uint64_t rankSum = (rankedFaces.size() + 1) * rankedFaces.size() / 2;
|
||||
|
||||
uint64_t rank = 1;
|
||||
double offset = 0.0;
|
||||
@@ -164,13 +154,11 @@ ProbingModule::getFaceBasedOnProbability(const FaceInfoFacePairSet& rankedFaces)
|
||||
// Found face to probe
|
||||
return pair.second;
|
||||
}
|
||||
|
||||
offset += probability;
|
||||
}
|
||||
|
||||
// Given a set of Faces, this method should always select a Face to probe
|
||||
BOOST_ASSERT(false);
|
||||
return nullptr;
|
||||
NDN_CXX_UNREACHABLE;
|
||||
}
|
||||
|
||||
double
|
||||
@@ -182,13 +170,6 @@ ProbingModule::getProbingProbability(uint64_t rank, uint64_t rankSum, uint64_t n
|
||||
return static_cast<double>(nFaces + 1 - rank) / rankSum;
|
||||
}
|
||||
|
||||
double
|
||||
ProbingModule::getRandomNumber(double start, double end)
|
||||
{
|
||||
std::uniform_real_distribution<double> dist(start, end);
|
||||
return dist(ndn::random::getRandomNumberEngine());
|
||||
}
|
||||
|
||||
void
|
||||
ProbingModule::setProbingInterval(size_t probingInterval)
|
||||
{
|
||||
@@ -196,7 +177,7 @@ ProbingModule::setProbingInterval(size_t probingInterval)
|
||||
m_probingInterval = time::milliseconds(probingInterval);
|
||||
}
|
||||
else {
|
||||
NDN_THROW(std::invalid_argument("Probing interval should be >= " +
|
||||
NDN_THROW(std::invalid_argument("Probing interval must be >= " +
|
||||
to_string(MIN_PROBING_INTERVAL.count()) + " milliseconds"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -41,13 +41,11 @@ public:
|
||||
ProbingModule(AsfMeasurements& measurements);
|
||||
|
||||
void
|
||||
scheduleProbe(const fib::Entry& fibEntry, const time::milliseconds& interval);
|
||||
scheduleProbe(const fib::Entry& fibEntry, time::milliseconds interval);
|
||||
|
||||
Face*
|
||||
getFaceToProbe(const Face& inFace,
|
||||
const Interest& interest,
|
||||
const fib::Entry& fibEntry,
|
||||
const Face& faceUsed);
|
||||
getFaceToProbe(const Face& inFace, const Interest& interest,
|
||||
const fib::Entry& fibEntry, const Face& faceUsed);
|
||||
|
||||
bool
|
||||
isProbingNeeded(const fib::Entry& fibEntry, const Interest& interest);
|
||||
@@ -66,19 +64,30 @@ public:
|
||||
|
||||
private:
|
||||
// Used to associate FaceInfo with the face in a NextHop
|
||||
typedef std::pair<FaceInfo*, Face*> FaceInfoFacePair;
|
||||
typedef std::function<bool(FaceInfoFacePair, FaceInfoFacePair)> FaceInfoPredicate;
|
||||
typedef std::set<FaceInfoFacePair, FaceInfoPredicate> FaceInfoFacePairSet;
|
||||
using FaceInfoFacePair = std::pair<FaceInfo*, Face*>;
|
||||
|
||||
Face*
|
||||
getFaceBasedOnProbability(const FaceInfoFacePairSet& rankedFaces);
|
||||
struct FaceInfoCompare
|
||||
{
|
||||
bool
|
||||
operator()(const FaceInfoFacePair& leftPair, const FaceInfoFacePair& rightPair) const
|
||||
{
|
||||
const FaceInfo& lhs = *leftPair.first;
|
||||
const FaceInfo& rhs = *rightPair.first;
|
||||
|
||||
double
|
||||
// Sort by RTT: if a face has timed-out, rank it behind non-timed-out faces
|
||||
return (!lhs.hasTimeout() && rhs.hasTimeout()) ||
|
||||
(lhs.hasTimeout() == rhs.hasTimeout() && lhs.getSrtt() < rhs.getSrtt());
|
||||
}
|
||||
};
|
||||
|
||||
using FaceInfoFacePairSet = std::set<FaceInfoFacePair, FaceInfoCompare>;
|
||||
|
||||
static Face*
|
||||
chooseFace(const FaceInfoFacePairSet& rankedFaces);
|
||||
|
||||
static double
|
||||
getProbingProbability(uint64_t rank, uint64_t rankSum, uint64_t nFaces);
|
||||
|
||||
double
|
||||
getRandomNumber(double start, double end);
|
||||
|
||||
public:
|
||||
static constexpr time::milliseconds DEFAULT_PROBING_INTERVAL = 1_min;
|
||||
static constexpr time::milliseconds MIN_PROBING_INTERVAL = 1_s;
|
||||
|
||||
+139
-174
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -42,7 +42,6 @@ AsfStrategy::AsfStrategy(Forwarder& forwarder, const Name& name)
|
||||
: Strategy(forwarder)
|
||||
, m_measurements(getMeasurements())
|
||||
, m_probing(m_measurements)
|
||||
, m_maxSilentTimeouts(0)
|
||||
, m_retxSuppression(RETX_SUPPRESSION_INITIAL,
|
||||
RetxSuppressionExponential::DEFAULT_MULTIPLIER,
|
||||
RETX_SUPPRESSION_MAX)
|
||||
@@ -58,8 +57,8 @@ AsfStrategy::AsfStrategy(Forwarder& forwarder, const Name& name)
|
||||
}
|
||||
this->setInstanceName(makeInstanceName(name, getStrategyName()));
|
||||
|
||||
NFD_LOG_DEBUG("Probing interval=" << m_probing.getProbingInterval()
|
||||
<< ", Num silent timeouts=" << m_maxSilentTimeouts);
|
||||
NFD_LOG_DEBUG("probing-interval=" << m_probing.getProbingInterval()
|
||||
<< " n-silent-timeouts=" << m_nMaxSilentTimeouts);
|
||||
}
|
||||
|
||||
const Name&
|
||||
@@ -69,6 +68,20 @@ AsfStrategy::getStrategyName()
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
getParamValue(const std::string& param, const std::string& value)
|
||||
{
|
||||
try {
|
||||
if (!value.empty() && value[0] == '-')
|
||||
NDN_THROW(boost::bad_lexical_cast());
|
||||
|
||||
return boost::lexical_cast<uint64_t>(value);
|
||||
}
|
||||
catch (const boost::bad_lexical_cast&) {
|
||||
NDN_THROW(std::invalid_argument("Value of " + param + " must be a non-negative integer"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsfStrategy::processParams(const PartialName& parsed)
|
||||
{
|
||||
@@ -85,7 +98,7 @@ AsfStrategy::processParams(const PartialName& parsed)
|
||||
m_probing.setProbingInterval(getParamValue(f, s));
|
||||
}
|
||||
else if (f == "n-silent-timeouts") {
|
||||
m_maxSilentTimeouts = getParamValue(f, s);
|
||||
m_nMaxSilentTimeouts = getParamValue(f, s);
|
||||
}
|
||||
else {
|
||||
NDN_THROW(std::invalid_argument("Parameter should be probing-interval or n-silent-timeouts"));
|
||||
@@ -93,40 +106,14 @@ AsfStrategy::processParams(const PartialName& parsed)
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
AsfStrategy::getParamValue(const std::string& param, const std::string& value)
|
||||
{
|
||||
try {
|
||||
if (!value.empty() && value[0] == '-')
|
||||
NDN_THROW(boost::bad_lexical_cast());
|
||||
|
||||
return boost::lexical_cast<uint64_t>(value);
|
||||
}
|
||||
catch (const boost::bad_lexical_cast&) {
|
||||
NDN_THROW(std::invalid_argument("Value of " + param + " must be a non-negative integer"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsfStrategy::sendAsfProbe(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry, const Face& faceToUse,
|
||||
const fib::Entry& fibEntry)
|
||||
{
|
||||
Face* faceToProbe = m_probing.getFaceToProbe(ingress.face, interest, fibEntry, faceToUse);
|
||||
if (faceToProbe != nullptr) {
|
||||
forwardInterest(interest, fibEntry, pitEntry, *faceToProbe, true);
|
||||
m_probing.afterForwardingProbe(fibEntry, interest);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsfStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
// Should the Interest be suppressed?
|
||||
RetxSuppressionResult suppressResult = m_retxSuppression.decidePerPitEntry(*pitEntry);
|
||||
auto suppressResult = m_retxSuppression.decidePerPitEntry(*pitEntry);
|
||||
if (suppressResult == RetxSuppressionResult::SUPPRESS) {
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " suppressed");
|
||||
NFD_LOG_DEBUG(interest << " retx-interest from=" << ingress << " suppressed");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -135,36 +122,31 @@ AsfStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& i
|
||||
|
||||
if (suppressResult == RetxSuppressionResult::NEW) {
|
||||
if (nexthops.size() == 0) {
|
||||
// send noRouteNack if nexthop is not available
|
||||
sendNoRouteNack(ingress, interest, pitEntry);
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
NFD_LOG_DEBUG(interest << " new-interest from=" << ingress << " no-nexthop");
|
||||
sendNoRouteNack(ingress.face, pitEntry);
|
||||
return;
|
||||
}
|
||||
|
||||
Face* faceToUse = getBestFaceForForwarding(fibEntry, interest, ingress.face, pitEntry);
|
||||
Face* faceToUse = getBestFaceForForwarding(interest, ingress.face, fibEntry, pitEntry);
|
||||
if (faceToUse != nullptr) {
|
||||
NFD_LOG_DEBUG(interest << " new-interest from=" << ingress << " forward-to=" << faceToUse->getId());
|
||||
forwardInterest(interest, *faceToUse, fibEntry, pitEntry);
|
||||
|
||||
if (faceToUse == nullptr) {
|
||||
sendNoRouteNack(ingress, interest, pitEntry);
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
return;
|
||||
// If necessary, send probe
|
||||
sendProbe(interest, ingress, *faceToUse, fibEntry, pitEntry);
|
||||
}
|
||||
|
||||
NFD_LOG_TRACE("Forwarding interest to face: " << faceToUse->getId());
|
||||
forwardInterest(interest, fibEntry, pitEntry, *faceToUse);
|
||||
|
||||
// If necessary, send probe
|
||||
if (m_probing.isProbingNeeded(fibEntry, interest)) {
|
||||
sendAsfProbe(ingress, interest, pitEntry, *faceToUse, fibEntry);
|
||||
else {
|
||||
NFD_LOG_DEBUG(interest << " new-interest from=" << ingress << " no-nexthop");
|
||||
sendNoRouteNack(ingress.face, pitEntry);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Face* faceToUse = getBestFaceForForwarding(fibEntry, interest, ingress.face, pitEntry, false);
|
||||
Face* faceToUse = getBestFaceForForwarding(interest, ingress.face, fibEntry, pitEntry, false);
|
||||
// if unused face not found, select nexthop with earliest out record
|
||||
if (faceToUse != nullptr) {
|
||||
|
||||
NFD_LOG_TRACE("Forwarding interest to face: " << faceToUse->getId());
|
||||
forwardInterest(interest, fibEntry, pitEntry, *faceToUse);
|
||||
NFD_LOG_DEBUG(interest << " retx-interest from=" << ingress << " forward-to=" << faceToUse->getId());
|
||||
forwardInterest(interest, *faceToUse, fibEntry, pitEntry);
|
||||
// avoid probing in case of forwarding
|
||||
return;
|
||||
}
|
||||
@@ -173,12 +155,11 @@ AsfStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& i
|
||||
auto it = nexthops.end();
|
||||
it = findEligibleNextHopWithEarliestOutRecord(ingress.face, interest, nexthops, pitEntry);
|
||||
if (it == nexthops.end()) {
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmitNoNextHop");
|
||||
NFD_LOG_DEBUG(interest << " retx-interest from=" << ingress << " no-nexthop");
|
||||
}
|
||||
else {
|
||||
auto egress = FaceEndpoint(it->getFace(), 0);
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmit-retry-to=" << egress);
|
||||
this->sendInterest(pitEntry, egress, interest);
|
||||
NFD_LOG_DEBUG(interest << " retx-interest from=" << ingress << " retry-to=" << it->getFace().getId());
|
||||
this->sendInterest(pitEntry, it->getFace(), interest);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,210 +168,194 @@ AsfStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const FaceEndpoint& ingress, const Data& data)
|
||||
{
|
||||
NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(pitEntry->getName());
|
||||
|
||||
if (namespaceInfo == nullptr) {
|
||||
NFD_LOG_TRACE("Could not find measurements entry for " << pitEntry->getName());
|
||||
NFD_LOG_DEBUG(pitEntry->getName() << " data from=" << ingress << " no-measurements");
|
||||
return;
|
||||
}
|
||||
|
||||
// Record the RTT between the Interest out to Data in
|
||||
FaceInfo* faceInfo = namespaceInfo->get(ingress.face.getId());
|
||||
FaceInfo* faceInfo = namespaceInfo->getFaceInfo(ingress.face.getId());
|
||||
if (faceInfo == nullptr) {
|
||||
NFD_LOG_DEBUG(pitEntry->getName() << " data from=" << ingress << " no-face-info");
|
||||
return;
|
||||
}
|
||||
faceInfo->recordRtt(pitEntry, ingress.face);
|
||||
|
||||
auto outRecord = pitEntry->getOutRecord(ingress.face);
|
||||
if (outRecord == pitEntry->out_end()) {
|
||||
NFD_LOG_DEBUG(pitEntry->getName() << " data from=" << ingress << " no-out-record");
|
||||
}
|
||||
else {
|
||||
faceInfo->recordRtt(time::steady_clock::now() - outRecord->getLastRenewed());
|
||||
NFD_LOG_DEBUG(pitEntry->getName() << " data from=" << ingress
|
||||
<< " rtt=" << faceInfo->getLastRtt() << " srtt=" << faceInfo->getSrtt());
|
||||
}
|
||||
|
||||
// Extend lifetime for measurements associated with Face
|
||||
namespaceInfo->extendFaceInfoLifetime(*faceInfo, ingress.face.getId());
|
||||
|
||||
if (faceInfo->isTimeoutScheduled()) {
|
||||
faceInfo->cancelTimeoutEvent(data.getName());
|
||||
}
|
||||
// Extend PIT entry timer to allow slower probes to arrive
|
||||
this->setExpiryTimer(pitEntry, 50_ms);
|
||||
faceInfo->cancelTimeout(data.getName());
|
||||
}
|
||||
|
||||
void
|
||||
AsfStrategy::afterReceiveNack(const FaceEndpoint& ingress, const lp::Nack& nack,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
NFD_LOG_DEBUG("Nack for " << nack.getInterest() << " from=" << ingress << ": reason=" << nack.getReason());
|
||||
onTimeout(pitEntry->getName(), ingress.face.getId());
|
||||
NFD_LOG_DEBUG(nack.getInterest() << " nack from=" << ingress << " reason=" << nack.getReason());
|
||||
onTimeoutOrNack(pitEntry->getName(), ingress.face.getId(), true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
AsfStrategy::forwardInterest(const Interest& interest,
|
||||
const fib::Entry& fibEntry,
|
||||
const shared_ptr<pit::Entry>& pitEntry,
|
||||
Face& outFace,
|
||||
bool wantNewNonce)
|
||||
AsfStrategy::forwardInterest(const Interest& interest, Face& outFace, const fib::Entry& fibEntry,
|
||||
const shared_ptr<pit::Entry>& pitEntry, bool wantNewNonce)
|
||||
{
|
||||
auto egress = FaceEndpoint(outFace, 0);
|
||||
auto faceId = outFace.getId();
|
||||
|
||||
if (wantNewNonce) {
|
||||
//Send probe: interest with new Nonce
|
||||
// Send probe: interest with new Nonce
|
||||
Interest probeInterest(interest);
|
||||
probeInterest.refreshNonce();
|
||||
NFD_LOG_TRACE("Sending probe for " << probeInterest << probeInterest.getNonce()
|
||||
<< " to: " << egress);
|
||||
this->sendInterest(pitEntry, egress, probeInterest);
|
||||
NFD_LOG_TRACE("Sending probe for " << probeInterest << " to=" << faceId);
|
||||
this->sendInterest(pitEntry, outFace, probeInterest);
|
||||
}
|
||||
else {
|
||||
this->sendInterest(pitEntry, egress, interest);
|
||||
this->sendInterest(pitEntry, outFace, interest);
|
||||
}
|
||||
|
||||
FaceInfo& faceInfo = m_measurements.getOrCreateFaceInfo(fibEntry, interest, egress.face.getId());
|
||||
FaceInfo& faceInfo = m_measurements.getOrCreateFaceInfo(fibEntry, interest, faceId);
|
||||
|
||||
// Refresh measurements since Face is being used for forwarding
|
||||
NamespaceInfo& namespaceInfo = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
|
||||
namespaceInfo.extendFaceInfoLifetime(faceInfo, egress.face.getId());
|
||||
namespaceInfo.extendFaceInfoLifetime(faceInfo, faceId);
|
||||
|
||||
if (!faceInfo.isTimeoutScheduled()) {
|
||||
// Estimate and schedule timeout
|
||||
RttEstimator::Duration timeout = faceInfo.computeRto();
|
||||
|
||||
NFD_LOG_TRACE("Scheduling timeout for " << fibEntry.getPrefix() << " to: " << egress
|
||||
auto timeout = faceInfo.scheduleTimeout(interest.getName(),
|
||||
[this, name = interest.getName(), faceId] {
|
||||
onTimeoutOrNack(name, faceId, false);
|
||||
});
|
||||
NFD_LOG_TRACE("Scheduled timeout for " << fibEntry.getPrefix() << " to=" << faceId
|
||||
<< " in " << time::duration_cast<time::milliseconds>(timeout) << " ms");
|
||||
|
||||
auto id = getScheduler().schedule(timeout, bind(&AsfStrategy::onTimeout, this,
|
||||
interest.getName(), egress.face.getId()));
|
||||
faceInfo.setTimeoutEvent(id, interest.getName());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsfStrategy::sendProbe(const Interest& interest, const FaceEndpoint& ingress, const Face& faceToUse,
|
||||
const fib::Entry& fibEntry, const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
if (!m_probing.isProbingNeeded(fibEntry, interest))
|
||||
return;
|
||||
|
||||
Face* faceToProbe = m_probing.getFaceToProbe(ingress.face, interest, fibEntry, faceToUse);
|
||||
if (faceToProbe == nullptr)
|
||||
return;
|
||||
|
||||
forwardInterest(interest, *faceToProbe, fibEntry, pitEntry, true);
|
||||
m_probing.afterForwardingProbe(fibEntry, interest);
|
||||
}
|
||||
|
||||
struct FaceStats
|
||||
{
|
||||
Face* face;
|
||||
RttStats::Rtt rtt;
|
||||
RttStats::Rtt srtt;
|
||||
time::nanoseconds rtt;
|
||||
time::nanoseconds srtt;
|
||||
uint64_t cost;
|
||||
};
|
||||
|
||||
double
|
||||
getValueForSorting(const FaceStats& stats)
|
||||
struct FaceStatsCompare
|
||||
{
|
||||
// These values allow faces with no measurements to be ranked better than timeouts
|
||||
// srtt < RTT_NO_MEASUREMENT < RTT_TIMEOUT
|
||||
static const RttStats::Rtt SORTING_RTT_TIMEOUT = time::microseconds::max();
|
||||
static const RttStats::Rtt SORTING_RTT_NO_MEASUREMENT = SORTING_RTT_TIMEOUT / 2;
|
||||
bool
|
||||
operator()(const FaceStats& lhs, const FaceStats& rhs) const
|
||||
{
|
||||
time::nanoseconds lhsValue = getValueForSorting(lhs);
|
||||
time::nanoseconds rhsValue = getValueForSorting(rhs);
|
||||
|
||||
if (stats.rtt == RttStats::RTT_TIMEOUT) {
|
||||
return SORTING_RTT_TIMEOUT.count();
|
||||
// Sort by RTT and then by cost
|
||||
return std::tie(lhsValue, lhs.cost) < std::tie(rhsValue, rhs.cost);
|
||||
}
|
||||
else if (stats.rtt == RttStats::RTT_NO_MEASUREMENT) {
|
||||
return SORTING_RTT_NO_MEASUREMENT.count();
|
||||
|
||||
private:
|
||||
static time::nanoseconds
|
||||
getValueForSorting(const FaceStats& stats)
|
||||
{
|
||||
// These values allow faces with no measurements to be ranked better than timeouts
|
||||
// srtt < RTT_NO_MEASUREMENT < RTT_TIMEOUT
|
||||
if (stats.rtt == FaceInfo::RTT_TIMEOUT) {
|
||||
return time::nanoseconds::max();
|
||||
}
|
||||
else if (stats.rtt == FaceInfo::RTT_NO_MEASUREMENT) {
|
||||
return time::nanoseconds::max() / 2;
|
||||
}
|
||||
else {
|
||||
return stats.srtt;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return stats.srtt.count();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Face*
|
||||
AsfStrategy::getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest& interest,
|
||||
const Face& inFace, const shared_ptr<pit::Entry>& pitEntry,
|
||||
AsfStrategy::getBestFaceForForwarding(const Interest& interest, const Face& inFace,
|
||||
const fib::Entry& fibEntry, const shared_ptr<pit::Entry>& pitEntry,
|
||||
bool isInterestNew)
|
||||
{
|
||||
NFD_LOG_TRACE("Looking for best face for " << fibEntry.getPrefix());
|
||||
|
||||
typedef std::function<bool(const FaceStats&, const FaceStats&)> FaceStatsPredicate;
|
||||
typedef std::set<FaceStats, FaceStatsPredicate> FaceStatsSet;
|
||||
|
||||
FaceStatsSet rankedFaces(
|
||||
[] (const FaceStats& lhs, const FaceStats& rhs) -> bool {
|
||||
// Sort by RTT and then by cost
|
||||
double lhsValue = getValueForSorting(lhs);
|
||||
double rhsValue = getValueForSorting(rhs);
|
||||
|
||||
if (lhsValue < rhsValue) {
|
||||
return true;
|
||||
}
|
||||
else if (lhsValue == rhsValue) {
|
||||
return lhs.cost < rhs.cost;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
std::set<FaceStats, FaceStatsCompare> rankedFaces;
|
||||
|
||||
auto now = time::steady_clock::now();
|
||||
for (const fib::NextHop& hop : fibEntry.getNextHops()) {
|
||||
Face& hopFace = hop.getFace();
|
||||
|
||||
if (!isNextHopEligible(inFace, interest, hop, pitEntry, !isInterestNew, now)) {
|
||||
for (const auto& nh : fibEntry.getNextHops()) {
|
||||
if (!isNextHopEligible(inFace, interest, nh, pitEntry, !isInterestNew, now)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace.getId());
|
||||
|
||||
FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, nh.getFace().getId());
|
||||
if (info == nullptr) {
|
||||
FaceStats stats = {&hopFace,
|
||||
RttStats::RTT_NO_MEASUREMENT,
|
||||
RttStats::RTT_NO_MEASUREMENT,
|
||||
hop.getCost()};
|
||||
|
||||
rankedFaces.insert(stats);
|
||||
rankedFaces.insert({&nh.getFace(), FaceInfo::RTT_NO_MEASUREMENT,
|
||||
FaceInfo::RTT_NO_MEASUREMENT, nh.getCost()});
|
||||
}
|
||||
else {
|
||||
FaceStats stats = {&hopFace, info->getRtt(), info->getSrtt(), hop.getCost()};
|
||||
rankedFaces.insert(stats);
|
||||
rankedFaces.insert({&nh.getFace(), info->getLastRtt(), info->getSrtt(), nh.getCost()});
|
||||
}
|
||||
}
|
||||
|
||||
FaceStatsSet::iterator it = rankedFaces.begin();
|
||||
|
||||
if (it != rankedFaces.end()) {
|
||||
return it->face;
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
auto it = rankedFaces.begin();
|
||||
return it != rankedFaces.end() ? it->face : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
AsfStrategy::onTimeout(const Name& interestName, const face::FaceId faceId)
|
||||
AsfStrategy::onTimeoutOrNack(const Name& interestName, FaceId faceId, bool isNack)
|
||||
{
|
||||
NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(interestName);
|
||||
|
||||
if (namespaceInfo == nullptr) {
|
||||
NFD_LOG_TRACE("FibEntry for " << interestName << " has been removed since timeout scheduling");
|
||||
NFD_LOG_TRACE(interestName << " FibEntry has been removed since timeout scheduling");
|
||||
return;
|
||||
}
|
||||
|
||||
FaceInfoTable::iterator it = namespaceInfo->find(faceId);
|
||||
|
||||
if (it == namespaceInfo->end()) {
|
||||
it = namespaceInfo->insert(faceId);
|
||||
FaceInfo* fiPtr = namespaceInfo->getFaceInfo(faceId);
|
||||
if (fiPtr == nullptr) {
|
||||
NFD_LOG_TRACE(interestName << " FaceInfo id=" << faceId << " has been removed since timeout scheduling");
|
||||
return;
|
||||
}
|
||||
|
||||
FaceInfo& faceInfo = it->second;
|
||||
auto& faceInfo = *fiPtr;
|
||||
size_t nTimeouts = faceInfo.getNSilentTimeouts() + 1;
|
||||
faceInfo.setNSilentTimeouts(nTimeouts);
|
||||
|
||||
faceInfo.setNSilentTimeouts(faceInfo.getNSilentTimeouts() + 1);
|
||||
|
||||
if (faceInfo.getNSilentTimeouts() <= m_maxSilentTimeouts) {
|
||||
NFD_LOG_TRACE("FaceId " << faceId << " for " << interestName << " has timed-out "
|
||||
<< faceInfo.getNSilentTimeouts() << " time(s), ignoring");
|
||||
if (nTimeouts <= m_nMaxSilentTimeouts && !isNack) {
|
||||
NFD_LOG_TRACE(interestName << " face=" << faceId << " timeout-count=" << nTimeouts << " ignoring");
|
||||
// Extend lifetime for measurements associated with Face
|
||||
namespaceInfo->extendFaceInfoLifetime(faceInfo, faceId);
|
||||
|
||||
if (faceInfo.isTimeoutScheduled()) {
|
||||
faceInfo.cancelTimeoutEvent(interestName);
|
||||
}
|
||||
faceInfo.cancelTimeout(interestName);
|
||||
}
|
||||
else {
|
||||
NFD_LOG_TRACE("FaceId " << faceId << " for " << interestName << " has timed-out");
|
||||
NFD_LOG_TRACE(interestName << " face=" << faceId << " timeout-count=" << nTimeouts);
|
||||
faceInfo.recordTimeout(interestName);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsfStrategy::sendNoRouteNack(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
AsfStrategy::sendNoRouteNack(Face& face, const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " noNextHop");
|
||||
|
||||
lp::NackHeader nackHeader;
|
||||
nackHeader.setReason(lp::NackReason::NO_ROUTE);
|
||||
this->sendNack(pitEntry, ingress, nackHeader);
|
||||
this->sendNack(pitEntry, face, nackHeader);
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
}
|
||||
|
||||
} // namespace asf
|
||||
|
||||
+13
-24
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -40,8 +40,6 @@ namespace asf {
|
||||
* \see Vince Lehman, Ashlesh Gawande, Rodrigo Aldecoa, Dmitri Krioukov, Beichuan Zhang, Lixia Zhang, and Lan Wang,
|
||||
* "An Experimental Investigation of Hyperbolic Routing with a Smart Forwarding Plane in NDN,"
|
||||
* NDN Technical Report NDN-0042, 2016. http://named-data.net/techreports.html
|
||||
*
|
||||
* \note This strategy is not EndpointId-aware.
|
||||
*/
|
||||
class AsfStrategy : public Strategy
|
||||
{
|
||||
@@ -67,41 +65,32 @@ public: // triggers
|
||||
|
||||
private:
|
||||
void
|
||||
forwardInterest(const Interest& interest,
|
||||
const fib::Entry& fibEntry,
|
||||
const shared_ptr<pit::Entry>& pitEntry,
|
||||
Face& outFace,
|
||||
bool wantNewNonce = false);
|
||||
processParams(const PartialName& parsed);
|
||||
|
||||
void
|
||||
sendAsfProbe(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry, const Face& faceToUse,
|
||||
const fib::Entry& fibEntry);
|
||||
forwardInterest(const Interest& interest, Face& outFace, const fib::Entry& fibEntry,
|
||||
const shared_ptr<pit::Entry>& pitEntry, bool wantNewNonce = false);
|
||||
|
||||
void
|
||||
sendProbe(const Interest& interest, const FaceEndpoint& ingress, const Face& faceToUse,
|
||||
const fib::Entry& fibEntry, const shared_ptr<pit::Entry>& pitEntry);
|
||||
|
||||
Face*
|
||||
getBestFaceForForwarding(const fib::Entry& fibEntry, const Interest& interest,
|
||||
const Face& inFace, const shared_ptr<pit::Entry>& pitEntry,
|
||||
getBestFaceForForwarding(const Interest& interest, const Face& inFace,
|
||||
const fib::Entry& fibEntry, const shared_ptr<pit::Entry>& pitEntry,
|
||||
bool isNewInterest = true);
|
||||
|
||||
void
|
||||
onTimeout(const Name& interestName, const FaceId faceId);
|
||||
onTimeoutOrNack(const Name& interestName, FaceId faceId, bool isNack);
|
||||
|
||||
void
|
||||
sendNoRouteNack(const FaceEndpoint& ingress, const Interest& interest, const shared_ptr<pit::Entry>& pitEntry);
|
||||
|
||||
void
|
||||
processParams(const PartialName& parsed);
|
||||
|
||||
static uint64_t
|
||||
getParamValue(const std::string& param, const std::string& value);
|
||||
sendNoRouteNack(Face& face, const shared_ptr<pit::Entry>& pitEntry);
|
||||
|
||||
private:
|
||||
AsfMeasurements m_measurements;
|
||||
ProbingModule m_probing;
|
||||
size_t m_maxSilentTimeouts;
|
||||
|
||||
private:
|
||||
RetxSuppressionExponential m_retxSuppression;
|
||||
size_t m_nMaxSilentTimeouts = 3;
|
||||
|
||||
static const time::milliseconds RETX_SUPPRESSION_INITIAL;
|
||||
static const time::milliseconds RETX_SUPPRESSION_MAX;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -48,7 +48,7 @@ BestRouteStrategyBase::afterReceiveInterest(const FaceEndpoint& ingress, const I
|
||||
Face& outFace = nexthop.getFace();
|
||||
if (!wouldViolateScope(ingress.face, interest, outFace) &&
|
||||
canForwardToLegacy(*pitEntry, outFace)) {
|
||||
this->sendInterest(pitEntry, FaceEndpoint(outFace, 0), interest);
|
||||
this->sendInterest(pitEntry, outFace, interest);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -52,8 +52,6 @@ protected:
|
||||
* \note This strategy is superceded by Best Route strategy version 2,
|
||||
* which allows consumer retransmissions. This version is kept for
|
||||
* comparison purposes and is not recommended for general usage.
|
||||
*
|
||||
* \note This strategy is not EndpointId-aware.
|
||||
*/
|
||||
class BestRouteStrategy : public BestRouteStrategyBase
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -86,27 +86,28 @@ BestRouteStrategy2::afterReceiveInterest(const FaceEndpoint& ingress, const Inte
|
||||
|
||||
lp::NackHeader nackHeader;
|
||||
nackHeader.setReason(lp::NackReason::NO_ROUTE);
|
||||
this->sendNack(pitEntry, ingress, nackHeader);
|
||||
this->sendNack(pitEntry, ingress.face, nackHeader);
|
||||
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
return;
|
||||
}
|
||||
|
||||
auto egress = FaceEndpoint(it->getFace(), 0);
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " newPitEntry-to=" << egress);
|
||||
this->sendInterest(pitEntry, egress, interest);
|
||||
Face& outFace = it->getFace();
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " newPitEntry-to=" << outFace.getId());
|
||||
this->sendInterest(pitEntry, outFace, interest);
|
||||
return;
|
||||
}
|
||||
|
||||
// find an unused upstream with lowest cost except downstream
|
||||
it = std::find_if(nexthops.begin(), nexthops.end(), [&] (const auto& nexthop) {
|
||||
return isNextHopEligible(ingress.face, interest, nexthop, pitEntry, true, time::steady_clock::now());
|
||||
});
|
||||
it = std::find_if(nexthops.begin(), nexthops.end(),
|
||||
[&, now = time::steady_clock::now()] (const auto& nexthop) {
|
||||
return isNextHopEligible(ingress.face, interest, nexthop, pitEntry, true, now);
|
||||
});
|
||||
|
||||
if (it != nexthops.end()) {
|
||||
auto egress = FaceEndpoint(it->getFace(), 0);
|
||||
this->sendInterest(pitEntry, egress, interest);
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmit-unused-to=" << egress);
|
||||
Face& outFace = it->getFace();
|
||||
this->sendInterest(pitEntry, outFace, interest);
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmit-unused-to=" << outFace.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -116,9 +117,9 @@ BestRouteStrategy2::afterReceiveInterest(const FaceEndpoint& ingress, const Inte
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmitNoNextHop");
|
||||
}
|
||||
else {
|
||||
auto egress = FaceEndpoint(it->getFace(), 0);
|
||||
this->sendInterest(pitEntry, egress, interest);
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmit-retry-to=" << egress);
|
||||
Face& outFace = it->getFace();
|
||||
this->sendInterest(pitEntry, outFace, interest);
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmit-retry-to=" << outFace.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -49,8 +49,6 @@ namespace fw {
|
||||
*
|
||||
* This strategy returns Nack to all downstreams if all upstreams have returned Nacks.
|
||||
* The reason of the sent Nack equals the least severe reason among received Nacks.
|
||||
*
|
||||
* \note This strategy is not EndpointId-aware.
|
||||
*/
|
||||
class BestRouteStrategy2 : public Strategy
|
||||
, public ProcessNackTraits<BestRouteStrategy2>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -27,6 +27,7 @@
|
||||
#define NFD_DAEMON_FW_FACE_TABLE_HPP
|
||||
|
||||
#include "face/face.hpp"
|
||||
|
||||
#include <boost/range/adaptor/indirected.hpp>
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
|
||||
@@ -79,15 +80,15 @@ public: // enumeration
|
||||
end() const;
|
||||
|
||||
public: // signals
|
||||
/** \brief fires after a face is added
|
||||
/** \brief Fires immediately after a face is added.
|
||||
*/
|
||||
signal::Signal<FaceTable, Face&> afterAdd;
|
||||
signal::Signal<FaceTable, Face> afterAdd;
|
||||
|
||||
/** \brief fires before a face is removed
|
||||
/** \brief Fires immediately before a face is removed.
|
||||
*
|
||||
* When this signal is emitted, face is still in FaceTable and has valid FaceId.
|
||||
* When this signal is emitted, the face is still in FaceTable and has a valid FaceId.
|
||||
*/
|
||||
signal::Signal<FaceTable, Face&> beforeRemove;
|
||||
signal::Signal<FaceTable, Face> beforeRemove;
|
||||
|
||||
private:
|
||||
void
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
namespace nfd {
|
||||
|
||||
/** \brief counters provided by Forwarder
|
||||
/** \brief Counters provided by Forwarder
|
||||
*/
|
||||
class ForwarderCounters
|
||||
{
|
||||
@@ -41,8 +41,10 @@ public:
|
||||
PacketCounter nOutData;
|
||||
PacketCounter nInNacks;
|
||||
PacketCounter nOutNacks;
|
||||
|
||||
PacketCounter nSatisfiedInterests;
|
||||
PacketCounter nUnsatisfiedInterests;
|
||||
PacketCounter nUnsolicitedData;
|
||||
|
||||
PacketCounter nCsHits;
|
||||
PacketCounter nCsMisses;
|
||||
|
||||
+136
-62
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "common/logger.hpp"
|
||||
#include "table/cleanup.hpp"
|
||||
|
||||
#include <ndn-cxx/lp/pit-token.hpp>
|
||||
#include <ndn-cxx/lp/tags.hpp>
|
||||
|
||||
namespace nfd {
|
||||
@@ -44,36 +45,41 @@ getDefaultStrategyName()
|
||||
return fw::BestRouteStrategy2::getStrategyName();
|
||||
}
|
||||
|
||||
Forwarder::Forwarder()
|
||||
: m_unsolicitedDataPolicy(make_unique<fw::DefaultUnsolicitedDataPolicy>())
|
||||
Forwarder::Forwarder(FaceTable& faceTable)
|
||||
: m_faceTable(faceTable)
|
||||
, m_unsolicitedDataPolicy(make_unique<fw::DefaultUnsolicitedDataPolicy>())
|
||||
, m_fib(m_nameTree)
|
||||
, m_pit(m_nameTree)
|
||||
, m_measurements(m_nameTree)
|
||||
, m_strategyChoice(*this)
|
||||
{
|
||||
m_faceTable.afterAdd.connect([this] (Face& face) {
|
||||
m_faceTable.afterAdd.connect([this] (const Face& face) {
|
||||
face.afterReceiveInterest.connect(
|
||||
[this, &face] (const Interest& interest) {
|
||||
this->startProcessInterest(FaceEndpoint(face, 0), interest);
|
||||
[this, &face] (const Interest& interest, const EndpointId& endpointId) {
|
||||
this->startProcessInterest(FaceEndpoint(face, endpointId), interest);
|
||||
});
|
||||
face.afterReceiveData.connect(
|
||||
[this, &face] (const Data& data) {
|
||||
this->startProcessData(FaceEndpoint(face, 0), data);
|
||||
[this, &face] (const Data& data, const EndpointId& endpointId) {
|
||||
this->startProcessData(FaceEndpoint(face, endpointId), data);
|
||||
});
|
||||
face.afterReceiveNack.connect(
|
||||
[this, &face] (const lp::Nack& nack) {
|
||||
this->startProcessNack(FaceEndpoint(face, 0), nack);
|
||||
[this, &face] (const lp::Nack& nack, const EndpointId& endpointId) {
|
||||
this->startProcessNack(FaceEndpoint(face, endpointId), nack);
|
||||
});
|
||||
face.onDroppedInterest.connect(
|
||||
[this, &face] (const Interest& interest) {
|
||||
this->onDroppedInterest(FaceEndpoint(face, 0), interest);
|
||||
this->onDroppedInterest(face, interest);
|
||||
});
|
||||
});
|
||||
|
||||
m_faceTable.beforeRemove.connect([this] (Face& face) {
|
||||
m_faceTable.beforeRemove.connect([this] (const Face& face) {
|
||||
cleanupOnFaceRemoval(m_nameTree, m_fib, m_pit, face);
|
||||
});
|
||||
|
||||
m_fib.afterNewNextHop.connect([&] (const Name& prefix, const fib::NextHop& nextHop) {
|
||||
this->startProcessNewNextHop(prefix, nextHop);
|
||||
});
|
||||
|
||||
m_strategyChoice.setDefaultStrategy(getDefaultStrategyName());
|
||||
}
|
||||
|
||||
@@ -87,6 +93,18 @@ Forwarder::onIncomingInterest(const FaceEndpoint& ingress, const Interest& inter
|
||||
interest.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.face.getId()));
|
||||
++m_counters.nInInterests;
|
||||
|
||||
// drop if HopLimit zero, decrement otherwise (if present)
|
||||
if (interest.getHopLimit()) {
|
||||
if (*interest.getHopLimit() < 1) {
|
||||
NFD_LOG_DEBUG("onIncomingInterest in=" << ingress << " interest=" << interest.getName()
|
||||
<< " hop-limit=0");
|
||||
++const_cast<PacketCounter&>(ingress.face.getCounters().nInHopLimitZero);
|
||||
return;
|
||||
}
|
||||
|
||||
const_cast<Interest&>(interest).setHopLimit(*interest.getHopLimit() - 1);
|
||||
}
|
||||
|
||||
// /localhost scope control
|
||||
bool isViolatingLocalhost = ingress.face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
|
||||
scope_prefix::LOCALHOST.isPrefixOf(interest.getName());
|
||||
@@ -168,10 +186,7 @@ Forwarder::onContentStoreMiss(const FaceEndpoint& ingress,
|
||||
++m_counters.nCsMisses;
|
||||
|
||||
// insert in-record
|
||||
// FIXME Strategies are not prepared to handle non-zero EndpointIds, so always insert
|
||||
// the in-record with EndpointId=0 for now. Eventually, this pipeline will need
|
||||
// to be refactored so that strategies can control the in-record insertion.
|
||||
pitEntry->insertOrUpdateInRecord(ingress.face, 0, interest);
|
||||
pitEntry->insertOrUpdateInRecord(ingress.face, interest);
|
||||
|
||||
// set PIT expiry timer to the time that the last PIT in-record expires
|
||||
auto lastExpiring = std::max_element(pitEntry->in_begin(), pitEntry->in_end(),
|
||||
@@ -191,14 +206,16 @@ Forwarder::onContentStoreMiss(const FaceEndpoint& ingress,
|
||||
<< " nexthop-faceid=" << nextHopFace->getId());
|
||||
// go to outgoing Interest pipeline
|
||||
// scope control is unnecessary, because privileged app explicitly wants to forward
|
||||
this->onOutgoingInterest(pitEntry, FaceEndpoint(*nextHopFace, 0), interest);
|
||||
this->onOutgoingInterest(pitEntry, *nextHopFace, interest);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// dispatch to strategy: after incoming Interest
|
||||
this->dispatchToStrategy(*pitEntry,
|
||||
[&] (fw::Strategy& strategy) { strategy.afterReceiveInterest(ingress, interest, pitEntry); });
|
||||
[&] (fw::Strategy& strategy) {
|
||||
strategy.afterReceiveInterest(FaceEndpoint(ingress.face, 0), interest, pitEntry);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
@@ -209,6 +226,7 @@ Forwarder::onContentStoreHit(const FaceEndpoint& ingress, const shared_ptr<pit::
|
||||
++m_counters.nCsHits;
|
||||
|
||||
data.setTag(make_shared<lp::IncomingFaceIdTag>(face::FACEID_CONTENT_STORE));
|
||||
data.setTag(interest.getTag<lp::PitToken>());
|
||||
// FIXME Should we lookup PIT for other Interests that also match the data?
|
||||
|
||||
pitEntry->isSatisfied = true;
|
||||
@@ -222,18 +240,28 @@ Forwarder::onContentStoreHit(const FaceEndpoint& ingress, const shared_ptr<pit::
|
||||
[&] (fw::Strategy& strategy) { strategy.afterContentStoreHit(pitEntry, ingress, data); });
|
||||
}
|
||||
|
||||
void
|
||||
pit::OutRecord*
|
||||
Forwarder::onOutgoingInterest(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const FaceEndpoint& egress, const Interest& interest)
|
||||
Face& egress, const Interest& interest)
|
||||
{
|
||||
NFD_LOG_DEBUG("onOutgoingInterest out=" << egress << " interest=" << pitEntry->getName());
|
||||
// drop if HopLimit == 0 but sending on non-local face
|
||||
if (interest.getHopLimit() == 0 && egress.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL) {
|
||||
NFD_LOG_DEBUG("onOutgoingInterest out=" << egress.getId() << " interest=" << pitEntry->getName()
|
||||
<< " non-local hop-limit=0");
|
||||
++const_cast<PacketCounter&>(egress.getCounters().nOutHopLimitZero);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NFD_LOG_DEBUG("onOutgoingInterest out=" << egress.getId() << " interest=" << pitEntry->getName());
|
||||
|
||||
// insert out-record
|
||||
pitEntry->insertOrUpdateOutRecord(egress.face, egress.endpoint, interest);
|
||||
auto it = pitEntry->insertOrUpdateOutRecord(egress, interest);
|
||||
BOOST_ASSERT(it != pitEntry->out_end());
|
||||
|
||||
// send Interest
|
||||
egress.face.sendInterest(interest);
|
||||
egress.sendInterest(interest);
|
||||
++m_counters.nOutInterests;
|
||||
return &*it;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -303,16 +331,16 @@ Forwarder::onIncomingData(const FaceEndpoint& ingress, const Data& data)
|
||||
pitEntry->isSatisfied = true;
|
||||
pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
|
||||
|
||||
// Dead Nonce List insert if necessary (for out-record of inFace)
|
||||
// Dead Nonce List insert if necessary (for out-record of ingress face)
|
||||
this->insertDeadNonceList(*pitEntry, &ingress.face);
|
||||
|
||||
// delete PIT entry's out-record
|
||||
pitEntry->deleteOutRecord(ingress.face, ingress.endpoint);
|
||||
pitEntry->deleteOutRecord(ingress.face);
|
||||
}
|
||||
// when more than one PIT entry is matched, trigger strategy: before satisfy Interest,
|
||||
// and send Data to all matched out faces
|
||||
else {
|
||||
std::set<std::pair<Face*, EndpointId>> pendingDownstreams;
|
||||
std::set<Face*> pendingDownstreams;
|
||||
auto now = time::steady_clock::now();
|
||||
|
||||
for (const auto& pitEntry : pitMatches) {
|
||||
@@ -321,7 +349,7 @@ Forwarder::onIncomingData(const FaceEndpoint& ingress, const Data& data)
|
||||
// remember pending downstreams
|
||||
for (const pit::InRecord& inRecord : pitEntry->getInRecords()) {
|
||||
if (inRecord.getExpiry() > now) {
|
||||
pendingDownstreams.emplace(&inRecord.getFace(), inRecord.getEndpointId());
|
||||
pendingDownstreams.insert(&inRecord.getFace());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,23 +364,22 @@ Forwarder::onIncomingData(const FaceEndpoint& ingress, const Data& data)
|
||||
pitEntry->isSatisfied = true;
|
||||
pitEntry->dataFreshnessPeriod = data.getFreshnessPeriod();
|
||||
|
||||
// Dead Nonce List insert if necessary (for out-record of inFace)
|
||||
// Dead Nonce List insert if necessary (for out-record of ingress face)
|
||||
this->insertDeadNonceList(*pitEntry, &ingress.face);
|
||||
|
||||
// clear PIT entry's in and out records
|
||||
pitEntry->clearInRecords();
|
||||
pitEntry->deleteOutRecord(ingress.face, ingress.endpoint);
|
||||
pitEntry->deleteOutRecord(ingress.face);
|
||||
}
|
||||
|
||||
// foreach pending downstream
|
||||
for (const auto& pendingDownstream : pendingDownstreams) {
|
||||
if (pendingDownstream.first->getId() == ingress.face.getId() &&
|
||||
pendingDownstream.second == ingress.endpoint &&
|
||||
pendingDownstream.first->getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) {
|
||||
if (pendingDownstream->getId() == ingress.face.getId() &&
|
||||
pendingDownstream->getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) {
|
||||
continue;
|
||||
}
|
||||
// goto outgoing Data pipeline
|
||||
this->onOutgoingData(data, FaceEndpoint(*pendingDownstream.first, pendingDownstream.second));
|
||||
this->onOutgoingData(data, *pendingDownstream);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -361,38 +388,43 @@ void
|
||||
Forwarder::onDataUnsolicited(const FaceEndpoint& ingress, const Data& data)
|
||||
{
|
||||
// accept to cache?
|
||||
fw::UnsolicitedDataDecision decision = m_unsolicitedDataPolicy->decide(ingress.face, data);
|
||||
auto decision = m_unsolicitedDataPolicy->decide(ingress.face, data);
|
||||
if (decision == fw::UnsolicitedDataDecision::CACHE) {
|
||||
// CS insert
|
||||
m_cs.insert(data, true);
|
||||
}
|
||||
|
||||
NFD_LOG_DEBUG("onDataUnsolicited in=" << ingress << " data=" << data.getName() << " decision=" << decision);
|
||||
NFD_LOG_DEBUG("onDataUnsolicited in=" << ingress << " data=" << data.getName()
|
||||
<< " decision=" << decision);
|
||||
++m_counters.nUnsolicitedData;
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onOutgoingData(const Data& data, FaceEndpoint egress)
|
||||
bool
|
||||
Forwarder::onOutgoingData(const Data& data, Face& egress)
|
||||
{
|
||||
if (egress.face.getId() == face::INVALID_FACEID) {
|
||||
if (egress.getId() == face::INVALID_FACEID) {
|
||||
NFD_LOG_WARN("onOutgoingData out=(invalid) data=" << data.getName());
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
NFD_LOG_DEBUG("onOutgoingData out=" << egress << " data=" << data.getName());
|
||||
NFD_LOG_DEBUG("onOutgoingData out=" << egress.getId() << " data=" << data.getName());
|
||||
|
||||
// /localhost scope control
|
||||
bool isViolatingLocalhost = egress.face.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
|
||||
bool isViolatingLocalhost = egress.getScope() == ndn::nfd::FACE_SCOPE_NON_LOCAL &&
|
||||
scope_prefix::LOCALHOST.isPrefixOf(data.getName());
|
||||
if (isViolatingLocalhost) {
|
||||
NFD_LOG_DEBUG("onOutgoingData out=" << egress << " data=" << data.getName() << " violates /localhost");
|
||||
NFD_LOG_DEBUG("onOutgoingData out=" << egress.getId() << " data=" << data.getName()
|
||||
<< " violates /localhost");
|
||||
// (drop)
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO traffic manager
|
||||
|
||||
// send Data
|
||||
egress.face.sendData(data);
|
||||
egress.sendData(data);
|
||||
++m_counters.nOutData;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -420,7 +452,7 @@ Forwarder::onIncomingNack(const FaceEndpoint& ingress, const lp::Nack& nack)
|
||||
}
|
||||
|
||||
// has out-record?
|
||||
auto outRecord = pitEntry->getOutRecord(ingress.face, ingress.endpoint);
|
||||
auto outRecord = pitEntry->getOutRecord(ingress.face);
|
||||
// if no out-record found, drop
|
||||
if (outRecord == pitEntry->out_end()) {
|
||||
NFD_LOG_DEBUG("onIncomingNack in=" << ingress << " nack=" << nack.getInterest().getName()
|
||||
@@ -452,36 +484,36 @@ Forwarder::onIncomingNack(const FaceEndpoint& ingress, const lp::Nack& nack)
|
||||
[&] (fw::Strategy& strategy) { strategy.afterReceiveNack(ingress, nack, pitEntry); });
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
Forwarder::onOutgoingNack(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const FaceEndpoint& egress, const lp::NackHeader& nack)
|
||||
Face& egress, const lp::NackHeader& nack)
|
||||
{
|
||||
if (egress.face.getId() == face::INVALID_FACEID) {
|
||||
if (egress.getId() == face::INVALID_FACEID) {
|
||||
NFD_LOG_WARN("onOutgoingNack out=(invalid)"
|
||||
<< " nack=" << pitEntry->getInterest().getName() << "~" << nack.getReason());
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// has in-record?
|
||||
auto inRecord = pitEntry->getInRecord(egress.face, egress.endpoint);
|
||||
auto inRecord = pitEntry->getInRecord(egress);
|
||||
|
||||
// if no in-record found, drop
|
||||
if (inRecord == pitEntry->in_end()) {
|
||||
NFD_LOG_DEBUG("onOutgoingNack out=" << egress
|
||||
NFD_LOG_DEBUG("onOutgoingNack out=" << egress.getId()
|
||||
<< " nack=" << pitEntry->getInterest().getName()
|
||||
<< "~" << nack.getReason() << " no-in-record");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// if multi-access or ad hoc face, drop
|
||||
if (egress.face.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
|
||||
NFD_LOG_DEBUG("onOutgoingNack out=" << egress
|
||||
if (egress.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
|
||||
NFD_LOG_DEBUG("onOutgoingNack out=" << egress.getId()
|
||||
<< " nack=" << pitEntry->getInterest().getName() << "~" << nack.getReason()
|
||||
<< " link-type=" << egress.face.getLinkType());
|
||||
return;
|
||||
<< " link-type=" << egress.getLinkType());
|
||||
return false;
|
||||
}
|
||||
|
||||
NFD_LOG_DEBUG("onOutgoingNack out=" << egress
|
||||
NFD_LOG_DEBUG("onOutgoingNack out=" << egress.getId()
|
||||
<< " nack=" << pitEntry->getInterest().getName()
|
||||
<< "~" << nack.getReason() << " OK");
|
||||
|
||||
@@ -490,24 +522,66 @@ Forwarder::onOutgoingNack(const shared_ptr<pit::Entry>& pitEntry,
|
||||
nackPkt.setHeader(nack);
|
||||
|
||||
// erase in-record
|
||||
pitEntry->deleteInRecord(egress.face, egress.endpoint);
|
||||
pitEntry->deleteInRecord(egress);
|
||||
|
||||
// send Nack on face
|
||||
egress.face.sendNack(nackPkt);
|
||||
egress.sendNack(nackPkt);
|
||||
++m_counters.nOutNacks;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onDroppedInterest(const FaceEndpoint& egress, const Interest& interest)
|
||||
Forwarder::onDroppedInterest(const Face& egress, const Interest& interest)
|
||||
{
|
||||
m_strategyChoice.findEffectiveStrategy(interest.getName()).onDroppedInterest(egress, interest);
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onNewNextHop(const Name& prefix, const fib::NextHop& nextHop)
|
||||
{
|
||||
const auto affectedEntries = this->getNameTree().partialEnumerate(prefix,
|
||||
[&] (const name_tree::Entry& nte) -> std::pair<bool, bool> {
|
||||
const fib::Entry* fibEntry = nte.getFibEntry();
|
||||
const fw::Strategy* strategy = nullptr;
|
||||
if (nte.getStrategyChoiceEntry() != nullptr) {
|
||||
strategy = &nte.getStrategyChoiceEntry()->getStrategy();
|
||||
}
|
||||
// current nte has buffered Interests but no fibEntry (except for the root nte) and the strategy
|
||||
// enables new nexthop behavior, we enumerate the current nte and keep visiting its children.
|
||||
if (nte.getName().size() == 0 ||
|
||||
(strategy != nullptr && strategy->wantNewNextHopTrigger() &&
|
||||
fibEntry == nullptr && nte.hasPitEntries())) {
|
||||
return {true, true};
|
||||
}
|
||||
// we don't need the current nte (no pitEntry or strategy doesn't support new nexthop), but
|
||||
// if the current nte has no fibEntry, it's still possible that its children are affected by
|
||||
// the new nexthop.
|
||||
else if (fibEntry == nullptr) {
|
||||
return {false, true};
|
||||
}
|
||||
// if the current nte has a fibEntry, we ignore the current nte and don't visit its
|
||||
// children because they are already covered by the current nte's fibEntry.
|
||||
else {
|
||||
return {false, false};
|
||||
}
|
||||
});
|
||||
|
||||
for (const auto& nte : affectedEntries) {
|
||||
for (const auto& pitEntry : nte.getPitEntries()) {
|
||||
this->dispatchToStrategy(*pitEntry,
|
||||
[&] (fw::Strategy& strategy) {
|
||||
strategy.afterNewNextHop(nextHop, pitEntry);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::setExpiryTimer(const shared_ptr<pit::Entry>& pitEntry, time::milliseconds duration)
|
||||
{
|
||||
BOOST_ASSERT(pitEntry);
|
||||
BOOST_ASSERT(duration >= 0_ms);
|
||||
duration = std::max(duration, 0_ms);
|
||||
|
||||
pitEntry->expiryTimer.cancel();
|
||||
pitEntry->expiryTimer = getScheduler().schedule(duration, [=] { onInterestFinalize(pitEntry); });
|
||||
@@ -538,7 +612,7 @@ Forwarder::insertDeadNonceList(pit::Entry& pitEntry, Face* upstream)
|
||||
}
|
||||
else {
|
||||
// insert outgoing Nonce of a specific face
|
||||
auto outRecord = pitEntry.getOutRecord(*upstream, 0);
|
||||
auto outRecord = pitEntry.getOutRecord(*upstream);
|
||||
if (outRecord != pitEntry.getOutRecords().end()) {
|
||||
m_deadNonceList.add(pitEntry.getName(), outRecord->getLastNonce());
|
||||
}
|
||||
|
||||
+30
-40
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,10 +26,10 @@
|
||||
#ifndef NFD_DAEMON_FW_FORWARDER_HPP
|
||||
#define NFD_DAEMON_FW_FORWARDER_HPP
|
||||
|
||||
#include "face-endpoint.hpp"
|
||||
#include "face-table.hpp"
|
||||
#include "forwarder-counters.hpp"
|
||||
#include "unsolicited-data-policy.hpp"
|
||||
#include "face/face-endpoint.hpp"
|
||||
#include "table/fib.hpp"
|
||||
#include "table/pit.hpp"
|
||||
#include "table/cs.hpp"
|
||||
@@ -44,14 +44,15 @@ namespace fw {
|
||||
class Strategy;
|
||||
} // namespace fw
|
||||
|
||||
/** \brief Main class of NFD forwarding engine.
|
||||
/** \brief Main class of NFD's forwarding engine.
|
||||
*
|
||||
* Forwarder owns all faces and tables, and implements the forwarding pipelines.
|
||||
* Forwarder owns all tables and implements the forwarding pipelines.
|
||||
*/
|
||||
class Forwarder
|
||||
{
|
||||
public:
|
||||
Forwarder();
|
||||
explicit
|
||||
Forwarder(FaceTable& faceTable);
|
||||
|
||||
VIRTUAL_WITH_TESTS
|
||||
~Forwarder();
|
||||
@@ -62,33 +63,6 @@ public:
|
||||
return m_counters;
|
||||
}
|
||||
|
||||
public: // faces and policies
|
||||
FaceTable&
|
||||
getFaceTable()
|
||||
{
|
||||
return m_faceTable;
|
||||
}
|
||||
|
||||
/** \brief get existing Face
|
||||
*
|
||||
* shortcut to .getFaceTable().get(face)
|
||||
*/
|
||||
Face*
|
||||
getFace(FaceId id) const
|
||||
{
|
||||
return m_faceTable.get(id);
|
||||
}
|
||||
|
||||
/** \brief add new Face
|
||||
*
|
||||
* shortcut to .getFaceTable().add(face)
|
||||
*/
|
||||
void
|
||||
addFace(shared_ptr<Face> face)
|
||||
{
|
||||
m_faceTable.add(face);
|
||||
}
|
||||
|
||||
fw::UnsolicitedDataPolicy&
|
||||
getUnsolicitedDataPolicy() const
|
||||
{
|
||||
@@ -133,6 +107,16 @@ public: // forwarding entrypoints and tables
|
||||
this->onIncomingNack(ingress, nack);
|
||||
}
|
||||
|
||||
/** \brief start new nexthop processing
|
||||
* \param prefix the prefix of the FibEntry containing the new nexthop
|
||||
* \param nextHop the new NextHop
|
||||
*/
|
||||
void
|
||||
startProcessNewNextHop(const Name& prefix, const fib::NextHop& nextHop)
|
||||
{
|
||||
this->onNewNextHop(prefix, nextHop);
|
||||
}
|
||||
|
||||
NameTree&
|
||||
getNameTree()
|
||||
{
|
||||
@@ -205,10 +189,11 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE: // pipelines
|
||||
const Interest& interest, const Data& data);
|
||||
|
||||
/** \brief outgoing Interest pipeline
|
||||
* \return A pointer to the out-record created or nullptr if the Interest was dropped
|
||||
*/
|
||||
VIRTUAL_WITH_TESTS void
|
||||
VIRTUAL_WITH_TESTS pit::OutRecord*
|
||||
onOutgoingInterest(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const FaceEndpoint& egress, const Interest& interest);
|
||||
Face& egress, const Interest& interest);
|
||||
|
||||
/** \brief Interest finalize pipeline
|
||||
*/
|
||||
@@ -226,9 +211,10 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE: // pipelines
|
||||
onDataUnsolicited(const FaceEndpoint& ingress, const Data& data);
|
||||
|
||||
/** \brief outgoing Data pipeline
|
||||
* \return Whether the Data was transmitted (true) or dropped (false)
|
||||
*/
|
||||
VIRTUAL_WITH_TESTS void
|
||||
onOutgoingData(const Data& data, FaceEndpoint egress);
|
||||
VIRTUAL_WITH_TESTS bool
|
||||
onOutgoingData(const Data& data, Face& egress);
|
||||
|
||||
/** \brief incoming Nack pipeline
|
||||
*/
|
||||
@@ -236,13 +222,17 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE: // pipelines
|
||||
onIncomingNack(const FaceEndpoint& ingress, const lp::Nack& nack);
|
||||
|
||||
/** \brief outgoing Nack pipeline
|
||||
* \return Whether the Nack was transmitted (true) or dropped (false)
|
||||
*/
|
||||
VIRTUAL_WITH_TESTS void
|
||||
VIRTUAL_WITH_TESTS bool
|
||||
onOutgoingNack(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const FaceEndpoint& egress, const lp::NackHeader& nack);
|
||||
Face& egress, const lp::NackHeader& nack);
|
||||
|
||||
VIRTUAL_WITH_TESTS void
|
||||
onDroppedInterest(const FaceEndpoint& egress, const Interest& interest);
|
||||
onDroppedInterest(const Face& egress, const Interest& interest);
|
||||
|
||||
VIRTUAL_WITH_TESTS void
|
||||
onNewNextHop(const Name& prefix, const fib::NextHop& nextHop);
|
||||
|
||||
PROTECTED_WITH_TESTS_ELSE_PRIVATE:
|
||||
/** \brief set a new expiry timer (now + \p duration) on a PIT entry
|
||||
@@ -274,7 +264,7 @@ PROTECTED_WITH_TESTS_ELSE_PRIVATE:
|
||||
private:
|
||||
ForwarderCounters m_counters;
|
||||
|
||||
FaceTable m_faceTable;
|
||||
FaceTable& m_faceTable;
|
||||
unique_ptr<fw::UnsolicitedDataPolicy> m_unsolicitedDataPolicy;
|
||||
|
||||
NameTree m_nameTree;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -69,10 +69,6 @@ MulticastStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const Inter
|
||||
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
|
||||
const fib::NextHopList& nexthops = fibEntry.getNextHops();
|
||||
|
||||
int nEligibleNextHops = 0;
|
||||
|
||||
bool isSuppressed = false;
|
||||
|
||||
for (const auto& nexthop : nexthops) {
|
||||
Face& outFace = nexthop.getFace();
|
||||
|
||||
@@ -80,30 +76,26 @@ MulticastStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const Inter
|
||||
|
||||
if (suppressResult == RetxSuppressionResult::SUPPRESS) {
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " to=" << outFace.getId() << " suppressed");
|
||||
isSuppressed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((outFace.getId() == ingress.face.getId() && outFace.getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) ||
|
||||
wouldViolateScope(ingress.face, interest, outFace)) {
|
||||
if (!isNextHopEligible(ingress.face, interest, nexthop, pitEntry)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this->sendInterest(pitEntry, FaceEndpoint(outFace, 0), interest);
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " pitEntry-to=" << outFace.getId());
|
||||
|
||||
if (suppressResult == RetxSuppressionResult::FORWARD) {
|
||||
m_retxSuppression.incrementIntervalForOutRecord(*pitEntry->getOutRecord(outFace, 0));
|
||||
bool wasSent = this->sendInterest(pitEntry, outFace, interest) != nullptr;
|
||||
if (wasSent && suppressResult == RetxSuppressionResult::FORWARD) {
|
||||
m_retxSuppression.incrementIntervalForOutRecord(*pitEntry->getOutRecord(outFace));
|
||||
}
|
||||
++nEligibleNextHops;
|
||||
}
|
||||
|
||||
if (nEligibleNextHops == 0 && !isSuppressed) {
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " noNextHop");
|
||||
if (!hasPendingOutRecords(*pitEntry)) {
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " noNextHop (removing pitEntry)");
|
||||
|
||||
lp::NackHeader nackHeader;
|
||||
nackHeader.setReason(lp::NackReason::NO_ROUTE);
|
||||
this->sendNack(pitEntry, ingress, nackHeader);
|
||||
this->sendNack(pitEntry, ingress.face, nackHeader);
|
||||
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -33,9 +33,7 @@
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
/** \brief a forwarding strategy that forwards Interest to all FIB nexthops
|
||||
*
|
||||
* \note This strategy is not EndpointId-aware.
|
||||
/** \brief A forwarding strategy that forwards Interests to all FIB nexthops
|
||||
*/
|
||||
class MulticastStrategy : public Strategy
|
||||
, public ProcessNackTraits<MulticastStrategy>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -83,14 +83,14 @@ NccStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& i
|
||||
size_t nUpstreams = nexthops.size();
|
||||
|
||||
shared_ptr<Face> bestFace = meInfo.getBestFace();
|
||||
if (bestFace != nullptr && fibEntry.hasNextHop(*bestFace, 0) &&
|
||||
if (bestFace != nullptr && fibEntry.hasNextHop(*bestFace) &&
|
||||
!wouldViolateScope(ingress.face, interest, *bestFace) &&
|
||||
canForwardToLegacy(*pitEntry, *bestFace)) {
|
||||
// TODO Should we use `randlow = 100 + nrand48(h->seed) % 4096U;` ?
|
||||
deferFirst = meInfo.prediction;
|
||||
deferRange = time::microseconds((deferFirst.count() + 1) / 2);
|
||||
--nUpstreams;
|
||||
this->sendInterest(pitEntry, FaceEndpoint(*bestFace, 0), interest);
|
||||
this->sendInterest(pitEntry, *bestFace, interest);
|
||||
pitEntryInfo->bestFaceTimeout = getScheduler().schedule(meInfo.prediction,
|
||||
bind(&NccStrategy::timeoutOnBestFace, this, weak_ptr<pit::Entry>(pitEntry)));
|
||||
}
|
||||
@@ -103,7 +103,7 @@ NccStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& i
|
||||
canForwardToLegacy(*pitEntry, outFace);
|
||||
});
|
||||
if (firstEligibleNexthop != nexthops.end()) {
|
||||
this->sendInterest(pitEntry, FaceEndpoint(firstEligibleNexthop->getFace(), 0), interest);
|
||||
this->sendInterest(pitEntry, firstEligibleNexthop->getFace(), interest);
|
||||
}
|
||||
else {
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
@@ -112,7 +112,7 @@ NccStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& i
|
||||
}
|
||||
|
||||
shared_ptr<Face> previousFace = meInfo.previousFace.lock();
|
||||
if (previousFace != nullptr && fibEntry.hasNextHop(*previousFace, 0) &&
|
||||
if (previousFace != nullptr && fibEntry.hasNextHop(*previousFace) &&
|
||||
!wouldViolateScope(ingress.face, interest, *previousFace) &&
|
||||
canForwardToLegacy(*pitEntry, *previousFace)) {
|
||||
--nUpstreams;
|
||||
@@ -143,7 +143,7 @@ NccStrategy::doPropagate(FaceId inFaceId, weak_ptr<pit::Entry> pitEntryWeak)
|
||||
if (pitEntry == nullptr) {
|
||||
return;
|
||||
}
|
||||
auto inRecord = pitEntry->getInRecord(*inFace, 0);
|
||||
auto inRecord = pitEntry->getInRecord(*inFace);
|
||||
if (inRecord == pitEntry->in_end()) {
|
||||
return;
|
||||
}
|
||||
@@ -158,10 +158,10 @@ NccStrategy::doPropagate(FaceId inFaceId, weak_ptr<pit::Entry> pitEntryWeak)
|
||||
MeasurementsEntryInfo& meInfo = this->getMeasurementsEntryInfo(pitEntry);
|
||||
|
||||
shared_ptr<Face> previousFace = meInfo.previousFace.lock();
|
||||
if (previousFace != nullptr && fibEntry.hasNextHop(*previousFace, 0) &&
|
||||
if (previousFace != nullptr && fibEntry.hasNextHop(*previousFace) &&
|
||||
!wouldViolateScope(*inFace, interest, *previousFace) &&
|
||||
canForwardToLegacy(*pitEntry, *previousFace)) {
|
||||
this->sendInterest(pitEntry, FaceEndpoint(*previousFace, 0), interest);
|
||||
this->sendInterest(pitEntry, *previousFace, interest);
|
||||
}
|
||||
|
||||
bool isForwarded = false;
|
||||
@@ -170,7 +170,7 @@ NccStrategy::doPropagate(FaceId inFaceId, weak_ptr<pit::Entry> pitEntryWeak)
|
||||
if (!wouldViolateScope(*inFace, interest, face) &&
|
||||
canForwardToLegacy(*pitEntry, face)) {
|
||||
isForwarded = true;
|
||||
this->sendInterest(pitEntry, FaceEndpoint(face, 0), interest);
|
||||
this->sendInterest(pitEntry, face, interest);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -31,9 +31,7 @@
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
/** \brief a forwarding strategy similar to CCNx 0.7.2
|
||||
*
|
||||
* \note This strategy is not EndpointId-aware.
|
||||
/** \brief A forwarding strategy similar to CCNx 0.7.2
|
||||
*/
|
||||
class NccStrategy : public Strategy
|
||||
{
|
||||
|
||||
@@ -56,7 +56,7 @@ ProcessNackTraitsBase::processNack(const Face& inFace, const lp::Nack& nack,
|
||||
|
||||
if (nOutRecordsNotNacked == 1) {
|
||||
BOOST_ASSERT(lastFaceNotNacked != nullptr);
|
||||
pit::InRecordCollection::iterator inR = pitEntry->getInRecord(*lastFaceNotNacked, 0);
|
||||
pit::InRecordCollection::iterator inR = pitEntry->getInRecord(*lastFaceNotNacked);
|
||||
if (inR != pitEntry->in_end()) {
|
||||
// one out-record not Nacked, which is also a downstream
|
||||
NFD_LOG_DEBUG(nack.getInterest() << " nack-from=" << inFace.getId() <<
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -58,7 +58,7 @@ protected:
|
||||
|
||||
private:
|
||||
virtual void
|
||||
sendNackForProcessNackTraits(const shared_ptr<pit::Entry>& pitEntry, const Face& outFace,
|
||||
sendNackForProcessNackTraits(const shared_ptr<pit::Entry>& pitEntry, Face& outFace,
|
||||
const lp::NackHeader& header) = 0;
|
||||
|
||||
virtual void
|
||||
@@ -78,10 +78,10 @@ protected:
|
||||
|
||||
private:
|
||||
void
|
||||
sendNackForProcessNackTraits(const shared_ptr<pit::Entry>& pitEntry, const Face& outFace,
|
||||
sendNackForProcessNackTraits(const shared_ptr<pit::Entry>& pitEntry, Face& outFace,
|
||||
const lp::NackHeader& header) override
|
||||
{
|
||||
m_strategy->sendNack(pitEntry, FaceEndpoint(outFace, 0), header);
|
||||
m_strategy->sendNack(pitEntry, outFace, header);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -0,0 +1,527 @@
|
||||
#include "qsccp-strategy.hpp"
|
||||
#include <ndn-cxx/lp/tags.hpp>
|
||||
#include <boost/random/discrete_distribution.hpp>
|
||||
#include <boost/random/uniform_real_distribution.hpp>
|
||||
#include "common/global.hpp"
|
||||
|
||||
namespace nfd
|
||||
{
|
||||
namespace fw
|
||||
{
|
||||
|
||||
NFD_LOG_INIT(QSCCPStrategy);
|
||||
NFD_REGISTER_STRATEGY(QSCCPStrategy);
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//// QSCCPStrategy
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const time::milliseconds QSCCPStrategy::RETX_SUPPRESSION_INITIAL(10);
|
||||
const time::milliseconds QSCCPStrategy::RETX_SUPPRESSION_MAX(250);
|
||||
|
||||
QSCCPStrategy::QSCCPStrategy(nfd::Forwarder &forwarder, const ndn::Name &name)
|
||||
: Strategy(forwarder), ProcessNackTraits<QSCCPStrategy>(this)
|
||||
{
|
||||
this->setInstanceName(makeInstanceName(name, getStrategyName()));
|
||||
}
|
||||
|
||||
void
|
||||
QSCCPStrategy::afterReceiveInterest(const nfd::FaceEndpoint &ingress, const ndn::Interest &interest,
|
||||
const std::shared_ptr<nfd::pit::Entry> &pitEntry)
|
||||
{
|
||||
RetxSuppressionResult suppression = m_retxSuppression.decidePerPitEntry(*pitEntry);
|
||||
if (suppression == RetxSuppressionResult::SUPPRESS)
|
||||
{
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " suppressed");
|
||||
return;
|
||||
}
|
||||
|
||||
const fib::Entry &fibEntry = this->lookupFib(*pitEntry);
|
||||
const fib::NextHopList &nexthops = fibEntry.getNextHops();
|
||||
auto selected = nexthops.end();
|
||||
|
||||
if (ingress.face.getScope() != ndn::nfd::FACE_SCOPE_NON_LOCAL)
|
||||
{
|
||||
selected = std::find_if(nexthops.begin(), nexthops.end(), [&](const auto &nexthop)
|
||||
{ return isNextHopEligible(ingress.face, interest, nexthop, pitEntry); });
|
||||
}
|
||||
else
|
||||
{
|
||||
auto selectedFaceId = rs.afterReceiveInterest(ingress, interest, pitEntry, fibEntry);
|
||||
if (selectedFaceId == ingress.face.getId() || selectedFaceId == 0)
|
||||
{
|
||||
selected = nexthops.end();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto it = nexthops.begin(); it != nexthops.end(); it++)
|
||||
{
|
||||
if (it->getFace().getId() == selectedFaceId)
|
||||
{
|
||||
selected = it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selected == nexthops.end())
|
||||
{
|
||||
lp::NackHeader nackHeader;
|
||||
nackHeader.setReason(lp::NackReason::NO_ROUTE);
|
||||
this->sendNack(pitEntry, ingress.face, nackHeader);
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->sendInterest(pitEntry, selected->getFace(), interest);
|
||||
}
|
||||
}
|
||||
|
||||
void QSCCPStrategy::afterReceiveNack(const nfd::FaceEndpoint &ingress, const ndn::lp::Nack &nack,
|
||||
const std::shared_ptr<nfd::pit::Entry> &pitEntry)
|
||||
{
|
||||
rs.afterReceiveNack(ingress, nack, pitEntry);
|
||||
this->processNack(ingress.face, nack, pitEntry);
|
||||
}
|
||||
|
||||
void QSCCPStrategy::beforeSatisfyInterest(const std::shared_ptr<nfd::pit::Entry> &pitEntry,
|
||||
const nfd::FaceEndpoint &ingress, const ndn::Data &data)
|
||||
{
|
||||
if (ingress.face.getId() <= 256)
|
||||
{
|
||||
return;
|
||||
}
|
||||
rs.beforeSatisfyInterest(pitEntry, ingress, data);
|
||||
NFD_LOG_DEBUG("BeforeSatisfyInterest");
|
||||
}
|
||||
|
||||
const ndn::Name &QSCCPStrategy::getStrategyName()
|
||||
{
|
||||
static Name strategyName("/localhost/nfd/strategy/QSCCP/%FD%01");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
void QSCCPStrategy::afterContentStoreHit(const shared_ptr<pit::Entry> &pitEntry,
|
||||
const FaceEndpoint &ingress, const Data &data)
|
||||
{
|
||||
NFD_LOG_DEBUG("After Content Store Hit: " << pitEntry->getName().toUri());
|
||||
}
|
||||
|
||||
void QSCCPStrategy::afterReceiveData(const shared_ptr<pit::Entry> &pitEntry, const FaceEndpoint &ingress,
|
||||
const Data &data)
|
||||
{
|
||||
|
||||
if (ingress.face.getScope() != ndn::nfd::FACE_SCOPE_NON_LOCAL)
|
||||
{
|
||||
this->sendDataToAll(pitEntry, ingress.face, data);
|
||||
return;
|
||||
}
|
||||
|
||||
rs.beforeSatisfyInterest(pitEntry, ingress, data);
|
||||
//
|
||||
// this->beforeSatisfyInterest(pitEntry, ingress, data);
|
||||
|
||||
// Override sendDataToAll
|
||||
std::set<Face *> pendingDownstreams;
|
||||
auto now = time::steady_clock::now();
|
||||
|
||||
// remember pending downstreams
|
||||
for (const pit::InRecord &inRecord : pitEntry->getInRecords())
|
||||
{
|
||||
if (inRecord.getExpiry() > now)
|
||||
{
|
||||
if (inRecord.getFace().getId() == ingress.face.getId() &&
|
||||
inRecord.getFace().getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
pendingDownstreams.emplace(&inRecord.getFace());
|
||||
}
|
||||
}
|
||||
|
||||
// int downStreamNum = 0;
|
||||
for (const auto &pendingDownstream : pendingDownstreams)
|
||||
{
|
||||
FaceEndpoint egress(*pendingDownstream, 0);
|
||||
if (ingress.face.getId() > 256)
|
||||
{
|
||||
this->rs.beforeSendData(pitEntry, egress, data);
|
||||
}
|
||||
this->sendData(pitEntry, data, egress.face);
|
||||
// downStreamNum++;
|
||||
}
|
||||
// NFD_LOG_DEBUG("DownStreamNum: " << downStreamNum);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//// RateCollection
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RateCollection::doPeriodicCleaning(bool needErase, uint32_t defaultValue)
|
||||
{
|
||||
// std::cout << "\n\n===================== doPeriodicCleaning ==========================" << std::endl;
|
||||
bool hasClean = false;
|
||||
for (auto it = this->rates.begin(); it != this->rates.end();)
|
||||
{
|
||||
if (it->second->recvCount == 0)
|
||||
{
|
||||
if (needErase)
|
||||
{
|
||||
this->totalRate -= it->second->rateValue;
|
||||
// std::cout << "hasClean: " << it->second->recvCount << ", id: " << it->second->id << std::endl;
|
||||
this->rates.erase(it++); // here is the key
|
||||
}
|
||||
else
|
||||
{
|
||||
this->addOrUpdateRate(it->second->id, defaultValue);
|
||||
}
|
||||
|
||||
hasClean = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// std::cout << "recvCount: " << it->second->recvCount << ", id: " << it->second->id << std::endl;
|
||||
it->second->recvCount = 0;
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
if (needErase && hasClean)
|
||||
{
|
||||
this->items.resize(this->rates.size());
|
||||
int idx = 0;
|
||||
for (auto it = this->rates.begin(); it != this->rates.end(); it++, idx++)
|
||||
{
|
||||
this->items[idx] = it->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RateCollection::addOrUpdateRate(face::FaceId id, uint32_t rate)
|
||||
{
|
||||
bool needUpdate = false;
|
||||
bool newFace = false;
|
||||
// NFD_LOG_DEBUG("addOrUpdateRate: " << this->name << ", " << id << ", " << rate);
|
||||
if (this->rates.count(id) == 0)
|
||||
{
|
||||
needUpdate = true;
|
||||
this->rates[id] = std::make_shared<RateItem>(rate, id);
|
||||
this->rates[id]->recvCount = 1;
|
||||
this->items.push_back(this->rates[id]);
|
||||
this->totalRate += rate;
|
||||
newFace = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rate != this->rates[id]->rateValue)
|
||||
{
|
||||
needUpdate = true;
|
||||
}
|
||||
this->rates[id]->recvCount += 1;
|
||||
this->totalRate = this->totalRate - this->rates[id]->rateValue + rate;
|
||||
this->rates[id]->rateValue = rate;
|
||||
}
|
||||
|
||||
if (needUpdate)
|
||||
{
|
||||
for (size_t i = 0; i < this->items.size(); i++)
|
||||
{
|
||||
if (this->totalRate < 1)
|
||||
{
|
||||
this->items[i]->ratio = 1 / this->items.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->items[i]->ratio = this->items[i]->rateValue * 1.0 / this->totalRate;
|
||||
}
|
||||
}
|
||||
}
|
||||
return newFace;
|
||||
}
|
||||
|
||||
face::FaceId RateCollection::selectNextFace(uint64_t dataSize, face::FaceId exceptId)
|
||||
{
|
||||
if (this->nextForwardFace >= this->items.size())
|
||||
{
|
||||
for (auto &item : this->items)
|
||||
{
|
||||
if (item->balance < 100000)
|
||||
{
|
||||
item->balance += (item->ratio * this->MTU_QUANTA);
|
||||
// std::cout << "banlance+: " << item->balance << ", ratio: " << item->ratio << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
// std::cout << "banlance-: " << item->balance << ", ratio: " << item->ratio << std::endl;
|
||||
}
|
||||
// NFD_LOG_DEBUG("Begin select next face: " << item->balance << ", " << item->ratio);
|
||||
}
|
||||
this->nextForwardFace = 0;
|
||||
}
|
||||
|
||||
face::FaceId selectedId = 0;
|
||||
size_t exceptCount = 0;
|
||||
for (; this->nextForwardFace < this->items.size(); this->nextForwardFace++)
|
||||
{
|
||||
if (this->items[this->nextForwardFace]->balance > dataSize &&
|
||||
this->items[this->nextForwardFace]->id != exceptId)
|
||||
{
|
||||
selectedId = this->items[this->nextForwardFace]->id;
|
||||
this->items[this->nextForwardFace]->balance -= dataSize;
|
||||
break;
|
||||
}
|
||||
else if (this->items[this->nextForwardFace]->id == exceptId || this->items[this->nextForwardFace]->ratio < 10e-6)
|
||||
{
|
||||
exceptCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedId == 0 && (this->items.size() - exceptCount) > 0)
|
||||
{
|
||||
// std::cout << "select: " << this->items.size() << ", count: " << exceptCount << std::endl;
|
||||
return selectNextFace(dataSize, exceptId);
|
||||
}
|
||||
else
|
||||
{
|
||||
return selectedId;
|
||||
}
|
||||
}
|
||||
|
||||
face::FaceId RateCollection::selectFaceByRatio(const FaceEndpoint &ingress, const fib::Entry &fibEntry, const ndn::Interest &interest)
|
||||
{
|
||||
if (this->items.empty())
|
||||
{
|
||||
const fib::NextHopList &nexthops = fibEntry.getNextHops();
|
||||
for (auto nexthop : nexthops)
|
||||
{
|
||||
this->addOrUpdateRate(nexthop.getFace().getId(), 200000);
|
||||
}
|
||||
|
||||
if (this->items.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto inId = ingress.face.getId();
|
||||
|
||||
if (this->items.size() == 1)
|
||||
{
|
||||
// NFD_LOG_DEBUG("ONE ratio => " << ", " << this->items[0]->rateValue);
|
||||
if (this->items[0]->id == inId)
|
||||
{
|
||||
std::cout << "1" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
return this->items[0]->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
// auto res = ingress.face.getId();
|
||||
|
||||
uint64_t dataSize = 9000;
|
||||
auto dsz = interest.getDsz();
|
||||
if (dsz)
|
||||
{
|
||||
dataSize = *dsz;
|
||||
}
|
||||
// std::cout << "nexthop num: " << fibEntry.getNextHops().size() << ", item size: " << this->items.size() << std::endl;
|
||||
return this->selectNextFace(dataSize, inId);
|
||||
}
|
||||
}
|
||||
|
||||
double RateCollection::getRatioByFace(face::FaceId id)
|
||||
{
|
||||
if (totalRate == 0 && this->getFaceNum() > 0)
|
||||
{
|
||||
return 1.0 / this->getFaceNum();
|
||||
}
|
||||
else if (rates.count(id) == 0)
|
||||
{
|
||||
return 0.01;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this->rates[id]->rateValue * 1.0 / this->totalRate;
|
||||
}
|
||||
}
|
||||
|
||||
void RateCollection::calSplitRateByRate()
|
||||
{
|
||||
if (this->totalAvaliableRate == 0 || this->items.size() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (this->items.size() == 1)
|
||||
{
|
||||
this->items[0]->allocateRate = this->items[0]->rateValue < this->totalAvaliableRate ? this->items[0]->rateValue : this->totalAvaliableRate;
|
||||
return;
|
||||
}
|
||||
std::vector<shared_ptr<RateItem>> sortedItems;
|
||||
sortedItems.assign(this->items.begin(), this->items.end());
|
||||
std::sort(sortedItems.begin(), sortedItems.end(), [](shared_ptr<RateItem> &ri1, shared_ptr<RateItem> &ri2)
|
||||
{ return ri1->rateValue < ri2->rateValue; });
|
||||
|
||||
uint32_t remainRate = this->totalAvaliableRate;
|
||||
int remainCount = sortedItems.size();
|
||||
// std::cout << "\n\n=========== begin ===========" << std::endl;
|
||||
for (auto &rateItem : sortedItems)
|
||||
{
|
||||
int thisTurn = remainRate / remainCount;
|
||||
if (thisTurn <= rateItem->rateValue)
|
||||
{
|
||||
remainRate -= thisTurn;
|
||||
rateItem->allocateRate = thisTurn;
|
||||
// std::cout << "assign1: " << thisTurn << ", rateValue: " << rateItem->rateValue << ", totalReaminRate: " << this->totalAvaliableRate << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
remainRate -= rateItem->rateValue;
|
||||
rateItem->allocateRate = rateItem->rateValue;
|
||||
// std::cout << "assign2: " << rateItem->rateValue << ", rateValue: " << rateItem->rateValue << std::endl;
|
||||
}
|
||||
remainCount--;
|
||||
}
|
||||
// std::cout << "=========== end ===========\n\n" << std::endl;
|
||||
}
|
||||
|
||||
uint32_t RateCollection::getAllocateRate(face::FaceId id)
|
||||
{
|
||||
if (rates.count(id) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this->rates[id]->allocateRate;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//// RateStore
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RateStore::RateStore()
|
||||
{
|
||||
getScheduler().schedule(time::milliseconds(100), std::bind(&RateStore::periodicCleaning, this));
|
||||
}
|
||||
|
||||
void
|
||||
RateStore::periodicCleaning()
|
||||
{
|
||||
getScheduler().schedule(time::milliseconds(100), std::bind(&RateStore::periodicCleaning, this));
|
||||
if (turn % 1 == 0)
|
||||
{
|
||||
for (auto it = this->ART.begin(); it != this->ART.end(); it++)
|
||||
{
|
||||
it->second->doPeriodicCleaning(true);
|
||||
}
|
||||
for (auto it = this->RRT.begin(); it != this->RRT.end(); it++)
|
||||
{
|
||||
it->second->doPeriodicCleaning(false, 200000);
|
||||
}
|
||||
}
|
||||
// for (auto it = this->ART.begin(); it != this->ART.end(); it++) {
|
||||
// it->second->calSplitRateByRate();
|
||||
// }
|
||||
turn++;
|
||||
}
|
||||
|
||||
face::FaceId RateStore::afterReceiveInterest(const nfd::FaceEndpoint &ingress, const ndn::Interest &interest,
|
||||
const std::shared_ptr<nfd::pit::Entry> &pitEntry,
|
||||
const fib::Entry &fibEntry)
|
||||
{
|
||||
auto flowKey = interest.getName().getPrefix(1).toUri();
|
||||
|
||||
auto downstreamRate = interest.getDownstreamRate();
|
||||
if (downstreamRate)
|
||||
{
|
||||
if (this->ART.count(flowKey) == 0)
|
||||
{
|
||||
this->ART[flowKey] = make_shared<RateCollection>();
|
||||
this->ART[flowKey]->setName("ART");
|
||||
}
|
||||
auto &rc = this->ART[flowKey];
|
||||
if (rc->addOrUpdateRate(ingress.face.getId(), *downstreamRate))
|
||||
{
|
||||
rc->calSplitRateByRate();
|
||||
}
|
||||
}
|
||||
|
||||
if (this->RRT.count(flowKey) == 0)
|
||||
{
|
||||
this->RRT[flowKey] = make_shared<RateCollection>();
|
||||
this->RRT[flowKey]->setName("RRT");
|
||||
}
|
||||
|
||||
auto selectedFaceId = this->RRT[flowKey]->selectFaceByRatio(ingress, fibEntry, interest);
|
||||
|
||||
if (selectedFaceId > 0)
|
||||
{
|
||||
// DR(/p, j) = min(OR(/p, j), RR(/p, j) / sum(RR(/p)) * sum(AR(/p)))
|
||||
// 这边只计算了 RR(/p, j) / sum(RR(/p)) * sum(AR(/p)) ,和 OR 的对比见 ns3/src/ndnSIM/NFD/damon/face/queues.cpp
|
||||
auto newDR = this->RRT[flowKey]->getRatioByFace(selectedFaceId) * this->ART[flowKey]->getMergeRate();
|
||||
interest.setDownstreamRate(newDR);
|
||||
}
|
||||
return selectedFaceId;
|
||||
}
|
||||
|
||||
void RateStore::afterReceiveNack(const nfd::FaceEndpoint &ingress, const ndn::lp::Nack &nack,
|
||||
const std::shared_ptr<nfd::pit::Entry> &pitEntry)
|
||||
{
|
||||
}
|
||||
|
||||
void RateStore::beforeSatisfyInterest(const std::shared_ptr<nfd::pit::Entry> &pitEntry,
|
||||
const nfd::FaceEndpoint &ingress, const ndn::Data &data)
|
||||
{
|
||||
auto targetRate = data.getTargetRate();
|
||||
auto flowKey = data.getName().getPrefix(1).toUri();
|
||||
if (this->RRT.count(flowKey) == 0)
|
||||
{
|
||||
this->RRT[flowKey] = make_shared<RateCollection>();
|
||||
this->RRT[flowKey]->setName("RRT");
|
||||
}
|
||||
if (targetRate)
|
||||
{
|
||||
// 保存 Data 中携带的 Target Rate
|
||||
this->RRT[flowKey]->addOrUpdateRate(ingress.face.getId(), *targetRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->RRT[flowKey]->addOrUpdateRate(ingress.face.getId(), QSCCPStrategy::getMaxTR());
|
||||
}
|
||||
}
|
||||
|
||||
void RateStore::beforeSendData(const shared_ptr<pit::Entry> &pitEntry, const FaceEndpoint &egress,
|
||||
const Data &data)
|
||||
{
|
||||
auto flowKey = data.getName().getPrefix(1).toUri();
|
||||
|
||||
auto mergeRate = this->RRT[flowKey]->getMergeRate();
|
||||
if (this->ART.count(flowKey) == 0)
|
||||
{
|
||||
this->ART[flowKey] = make_shared<RateCollection>();
|
||||
this->ART[flowKey]->setName("ART");
|
||||
}
|
||||
|
||||
// if (flowKey == "/C") {
|
||||
// std::cout << "mergeRate: " << mergeRate << std::endl;
|
||||
// this->RRT[flowKey]->printItems();
|
||||
// }
|
||||
|
||||
auto rc = this->ART[flowKey];
|
||||
rc->updateTotalAvaliableRate(mergeRate);
|
||||
// rc->calSplitRateByRate();
|
||||
|
||||
if (rc->getFaceNum() <= 1)
|
||||
{
|
||||
data.setTargetRate(mergeRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
data.setTargetRate(static_cast<uint64_t>(rc->getRatioByFace(egress.face.getId()) * mergeRate));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
//
|
||||
// Created by gdcni21 on 3/24/22.
|
||||
//
|
||||
#include <boost/random/mersenne_twister.hpp>
|
||||
#include "face/face.hpp"
|
||||
#include "fw/strategy.hpp"
|
||||
#include "fw/retx-suppression-exponential.hpp"
|
||||
#include "fw/retx-suppression-fixed.hpp"
|
||||
#include "fw/algorithm.hpp"
|
||||
#include "fw/process-nack-traits.hpp"
|
||||
#include <unordered_map>
|
||||
#include <limits>
|
||||
#include <iostream>
|
||||
|
||||
namespace nfd
|
||||
{
|
||||
namespace fw
|
||||
{
|
||||
struct RateItem
|
||||
{
|
||||
uint32_t rateValue;
|
||||
face::FaceId id;
|
||||
double ratio;
|
||||
double balance;
|
||||
uint32_t allocateRate;
|
||||
uint32_t recvCount;
|
||||
explicit RateItem(uint32_t value = 0, face::FaceId faceId = 0) :
|
||||
rateValue(value), id(faceId), ratio(0),
|
||||
balance(0.0), allocateRate(0), recvCount(0) {}
|
||||
|
||||
};
|
||||
|
||||
class RateCollection
|
||||
{
|
||||
public:
|
||||
bool addOrUpdateRate(face::FaceId id, uint32_t rate);
|
||||
|
||||
size_t getFaceNum()
|
||||
{
|
||||
return this->rates.size();
|
||||
}
|
||||
|
||||
uint32_t getMergeRate() const
|
||||
{
|
||||
return this->totalRate;
|
||||
}
|
||||
|
||||
void printItems() {
|
||||
for (auto &rateItem : this->items) {
|
||||
std::cout << "id: " << rateItem->id << ", rate: " << rateItem->rateValue << ", ratio: " << rateItem->ratio << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
face::FaceId selectNextFace(uint64_t dataSize, face::FaceId exceptId);
|
||||
|
||||
face::FaceId selectFaceByRatio(const FaceEndpoint &ingress, const fib::Entry &fibEntry, const ndn::Interest &interest);
|
||||
|
||||
double getRatioByFace(face::FaceId id);
|
||||
|
||||
void calSplitRateByRate();
|
||||
|
||||
uint32_t getAllocateRate(face::FaceId id);
|
||||
|
||||
void updateTotalAvaliableRate(uint32_t totalAvailableRate) {
|
||||
if (totalAvailableRate > 1.2 * this->totalAvaliableRate || totalAvailableRate < 0.8 * this->totalAvaliableRate) {
|
||||
this->totalAvaliableRate = totalAvailableRate;
|
||||
this->calSplitRateByRate();
|
||||
} else {
|
||||
this->totalAvaliableRate = totalAvailableRate;
|
||||
}
|
||||
// std::cout << "updateRate: " << totalAvailableRate << std::endl;
|
||||
}
|
||||
|
||||
void setName(const std::string &name) { this->name = name; }
|
||||
|
||||
std::string getName() { return this->name; }
|
||||
|
||||
void doPeriodicCleaning(bool needErase = true, uint32_t defaultValue = 0);
|
||||
|
||||
private:
|
||||
std::unordered_map<face::FaceId, shared_ptr<RateItem>> rates;
|
||||
std::vector<shared_ptr<RateItem>> items;
|
||||
uint32_t totalRate;
|
||||
boost::random::mt19937 m_randomGenerator;
|
||||
|
||||
float randomThreshold = 0.99;
|
||||
int nextForwardFace;
|
||||
int MTU_QUANTA = 2 * 1000 * 8;
|
||||
std::string name = "";
|
||||
uint32_t totalAvaliableRate = 0;
|
||||
};
|
||||
|
||||
class RateStore
|
||||
{
|
||||
public:
|
||||
explicit RateStore();
|
||||
|
||||
face::FaceId
|
||||
afterReceiveInterest(const FaceEndpoint &ingress, const Interest &interest,
|
||||
const shared_ptr<pit::Entry> &pitEntry, const fib::Entry &fibEntry);
|
||||
|
||||
void
|
||||
afterReceiveNack(const FaceEndpoint &ingress, const lp::Nack &nack,
|
||||
const shared_ptr<pit::Entry> &pitEntry);
|
||||
|
||||
void
|
||||
beforeSatisfyInterest(const shared_ptr<pit::Entry> &pitEntry,
|
||||
const FaceEndpoint &ingress, const Data &data);
|
||||
|
||||
void
|
||||
beforeSendData(const shared_ptr<pit::Entry> &pitEntry,
|
||||
const FaceEndpoint &egress, const Data &data);
|
||||
|
||||
void
|
||||
periodicCleaning();
|
||||
|
||||
private:
|
||||
// ART => Available Rate Table =>
|
||||
std::unordered_map<std::string, shared_ptr<RateCollection>> ART;
|
||||
// RRT => Recommend Rate Table =>
|
||||
std::unordered_map<std::string, shared_ptr<RateCollection>> RRT;
|
||||
uint32_t turn = 0;
|
||||
};
|
||||
|
||||
class QSCCPStrategy : public Strategy, public ProcessNackTraits<QSCCPStrategy>
|
||||
{
|
||||
public:
|
||||
explicit QSCCPStrategy(Forwarder &forwarder, const Name &name = getStrategyName());
|
||||
|
||||
~QSCCPStrategy() override = default;
|
||||
|
||||
void
|
||||
afterReceiveInterest(const FaceEndpoint &ingress, const Interest &interest,
|
||||
const shared_ptr<pit::Entry> &pitEntry) override;
|
||||
|
||||
void
|
||||
afterReceiveNack(const FaceEndpoint &ingress, const lp::Nack &nack,
|
||||
const shared_ptr<pit::Entry> &pitEntry) override;
|
||||
|
||||
void
|
||||
beforeSatisfyInterest(const shared_ptr<pit::Entry> &pitEntry,
|
||||
const FaceEndpoint &ingress, const Data &data) override;
|
||||
|
||||
void
|
||||
afterReceiveData(const shared_ptr<pit::Entry> &pitEntry,
|
||||
const FaceEndpoint &ingress, const Data &data) override;
|
||||
|
||||
void
|
||||
afterContentStoreHit(const shared_ptr<pit::Entry> &pitEntry,
|
||||
const FaceEndpoint &ingress, const Data &data) override;
|
||||
|
||||
static uint64_t
|
||||
getMaxTR()
|
||||
{
|
||||
return std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
|
||||
static const Name &
|
||||
getStrategyName();
|
||||
|
||||
protected:
|
||||
friend ProcessNackTraits<QSCCPStrategy>;
|
||||
|
||||
private:
|
||||
static const time::milliseconds RETX_SUPPRESSION_INITIAL;
|
||||
static const time::milliseconds RETX_SUPPRESSION_MAX;
|
||||
RetxSuppressionFixed m_retxSuppression;
|
||||
RateStore rs;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
* Washington University in St. Louis,
|
||||
* Beijing Institute of Technology,
|
||||
* The University of Memphis.
|
||||
*
|
||||
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
||||
* See AUTHORS.md for complete list of NFD authors and contributors.
|
||||
*
|
||||
* NFD is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "random-strategy.hpp"
|
||||
#include "algorithm.hpp"
|
||||
|
||||
#include <ndn-cxx/util/random.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
NFD_REGISTER_STRATEGY(RandomStrategy);
|
||||
NFD_LOG_INIT(RandomStrategy);
|
||||
|
||||
RandomStrategy::RandomStrategy(Forwarder& forwarder, const Name& name)
|
||||
: Strategy(forwarder)
|
||||
, ProcessNackTraits(this)
|
||||
{
|
||||
ParsedInstanceName parsed = parseInstanceName(name);
|
||||
if (!parsed.parameters.empty()) {
|
||||
NDN_THROW(std::invalid_argument("RandomStrategy does not accept parameters"));
|
||||
}
|
||||
if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
|
||||
NDN_THROW(std::invalid_argument(
|
||||
"RandomStrategy does not support version " + to_string(*parsed.version)));
|
||||
}
|
||||
this->setInstanceName(makeInstanceName(name, getStrategyName()));
|
||||
}
|
||||
|
||||
const Name&
|
||||
RandomStrategy::getStrategyName()
|
||||
{
|
||||
static Name strategyName("/localhost/nfd/strategy/random/%FD%01");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
void
|
||||
RandomStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
|
||||
fib::NextHopList nhs;
|
||||
|
||||
std::copy_if(fibEntry.getNextHops().begin(), fibEntry.getNextHops().end(), std::back_inserter(nhs),
|
||||
[&] (const auto& nh) { return isNextHopEligible(ingress.face, interest, nh, pitEntry); });
|
||||
|
||||
if (nhs.empty()) {
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " no nexthop");
|
||||
|
||||
lp::NackHeader nackHeader;
|
||||
nackHeader.setReason(lp::NackReason::NO_ROUTE);
|
||||
this->sendNack(pitEntry, ingress.face, nackHeader);
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
return;
|
||||
}
|
||||
|
||||
std::shuffle(nhs.begin(), nhs.end(), ndn::random::getRandomNumberEngine());
|
||||
this->sendInterest(pitEntry, nhs.front().getFace(), interest);
|
||||
}
|
||||
|
||||
void
|
||||
RandomStrategy::afterReceiveNack(const FaceEndpoint& ingress, const lp::Nack& nack,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
this->processNack(ingress.face, nack, pitEntry);
|
||||
}
|
||||
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -23,61 +23,42 @@
|
||||
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_CORE_RTT_ESTIMATOR_HPP
|
||||
#define NFD_CORE_RTT_ESTIMATOR_HPP
|
||||
#ifndef NFD_DAEMON_FW_RANDOM_STRATEGY_HPP
|
||||
#define NFD_DAEMON_FW_RANDOM_STRATEGY_HPP
|
||||
|
||||
#include "core/common.hpp"
|
||||
#include "strategy.hpp"
|
||||
#include "process-nack-traits.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
/**
|
||||
* \brief implements the Mean-Deviation RTT estimator
|
||||
/** \brief A forwarding strategy that randomly chooses a nexthop
|
||||
*
|
||||
* \sa ns3::RttMeanDeviation
|
||||
*
|
||||
* This RttEstimator algorithm is designed for TCP, which is a continuous stream.
|
||||
* NDN Interest-Data traffic is not always a continuous stream,
|
||||
* so NDN may need a different RttEstimator.
|
||||
* The design of a more suitable RttEstimator is a research question.
|
||||
* Sends the incoming Interest to a random outgoing face, excluding the incoming face.
|
||||
*/
|
||||
class RttEstimator
|
||||
class RandomStrategy : public Strategy
|
||||
, public ProcessNackTraits<RandomStrategy>
|
||||
{
|
||||
public:
|
||||
using Duration = time::microseconds;
|
||||
explicit
|
||||
RandomStrategy(Forwarder& forwarder, const Name& name = getStrategyName());
|
||||
|
||||
RttEstimator(uint16_t maxMultiplier = 16,
|
||||
Duration minRto = 1_ms,
|
||||
double gain = 0.1);
|
||||
|
||||
static Duration
|
||||
getInitialRtt()
|
||||
{
|
||||
return 1_s;
|
||||
}
|
||||
static const Name&
|
||||
getStrategyName();
|
||||
|
||||
void
|
||||
addMeasurement(Duration measure);
|
||||
afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
void
|
||||
incrementMultiplier();
|
||||
|
||||
void
|
||||
doubleMultiplier();
|
||||
|
||||
Duration
|
||||
computeRto() const;
|
||||
afterReceiveNack(const FaceEndpoint& ingress, const lp::Nack& nack,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
private:
|
||||
uint16_t m_maxMultiplier;
|
||||
double m_minRto;
|
||||
|
||||
double m_rtt;
|
||||
double m_gain;
|
||||
double m_variance;
|
||||
uint16_t m_multiplier;
|
||||
uint32_t m_nSamples;
|
||||
friend ProcessNackTraits<RandomStrategy>;
|
||||
};
|
||||
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_CORE_RTT_ESTIMATOR_HPP
|
||||
#endif // NFD_DAEMON_FW_RANDOM_STRATEGY_HPP
|
||||
@@ -95,7 +95,7 @@ RetxSuppressionResult
|
||||
RetxSuppressionExponential::decidePerUpstream(pit::Entry& pitEntry, Face& outFace)
|
||||
{
|
||||
// NEW if outRecord for the face does not exist
|
||||
auto outRecord = pitEntry.getOutRecord(outFace, 0);
|
||||
auto outRecord = pitEntry.getOutRecord(outFace);
|
||||
if (outRecord == pitEntry.out_end()) {
|
||||
return RetxSuppressionResult::NEW;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -73,14 +73,14 @@ SelfLearningStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const In
|
||||
const fib::NextHopList& nexthops = fibEntry.getNextHops();
|
||||
|
||||
bool isNonDiscovery = interest.getTag<lp::NonDiscoveryTag>() != nullptr;
|
||||
auto inRecordInfo = pitEntry->getInRecord(ingress.face, ingress.endpoint)->insertStrategyInfo<InRecordInfo>().first;
|
||||
auto inRecordInfo = pitEntry->getInRecord(ingress.face)->insertStrategyInfo<InRecordInfo>().first;
|
||||
if (isNonDiscovery) { // "non-discovery" Interest
|
||||
inRecordInfo->isNonDiscoveryInterest = true;
|
||||
if (nexthops.empty()) { // return NACK if no matching FIB entry exists
|
||||
NFD_LOG_DEBUG("NACK non-discovery Interest=" << interest << " from=" << ingress << " noNextHop");
|
||||
lp::NackHeader nackHeader;
|
||||
nackHeader.setReason(lp::NackReason::NO_ROUTE);
|
||||
this->sendNack(pitEntry, ingress, nackHeader);
|
||||
this->sendNack(pitEntry, ingress.face, nackHeader);
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
}
|
||||
else { // multicast it if matching FIB entry exists
|
||||
@@ -103,10 +103,16 @@ void
|
||||
SelfLearningStrategy::afterReceiveData(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const FaceEndpoint& ingress, const Data& data)
|
||||
{
|
||||
OutRecordInfo* outRecordInfo = pitEntry->getOutRecord(ingress.face, ingress.endpoint)->getStrategyInfo<OutRecordInfo>();
|
||||
auto outRecord = pitEntry->getOutRecord(ingress.face);
|
||||
if (outRecord == pitEntry->out_end()) {
|
||||
NFD_LOG_DEBUG("Data " << data.getName() << " from=" << ingress << " no out-record");
|
||||
return;
|
||||
}
|
||||
|
||||
OutRecordInfo* outRecordInfo = outRecord->getStrategyInfo<OutRecordInfo>();
|
||||
if (outRecordInfo && outRecordInfo->isNonDiscoveryInterest) { // outgoing Interest was non-discovery
|
||||
if (!needPrefixAnn(pitEntry)) { // no need to attach a PA (common cases)
|
||||
sendDataToAll(pitEntry, ingress, data);
|
||||
sendDataToAll(pitEntry, ingress.face, data);
|
||||
}
|
||||
else { // needs a PA (to respond discovery Interest)
|
||||
asyncProcessData(pitEntry, ingress.face, data);
|
||||
@@ -119,7 +125,7 @@ SelfLearningStrategy::afterReceiveData(const shared_ptr<pit::Entry>& pitEntry,
|
||||
}
|
||||
else { // Data contains no PrefixAnnouncement, upstreams do not support self-learning
|
||||
}
|
||||
sendDataToAll(pitEntry, ingress, data);
|
||||
sendDataToAll(pitEntry, ingress.face, data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,13 +149,17 @@ SelfLearningStrategy::broadcastInterest(const Interest& interest, const Face& in
|
||||
{
|
||||
for (auto& outFace : this->getFaceTable() | boost::adaptors::reversed) {
|
||||
if ((outFace.getId() == inFace.getId() && outFace.getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) ||
|
||||
wouldViolateScope(inFace, interest, outFace) || outFace.getScope() == ndn::nfd::FACE_SCOPE_LOCAL) {
|
||||
wouldViolateScope(inFace, interest, outFace) ||
|
||||
outFace.getScope() == ndn::nfd::FACE_SCOPE_LOCAL) {
|
||||
continue;
|
||||
}
|
||||
this->sendInterest(pitEntry, FaceEndpoint(outFace, 0), interest);
|
||||
pitEntry->getOutRecord(outFace, 0)->insertStrategyInfo<OutRecordInfo>().first->isNonDiscoveryInterest = false;
|
||||
NFD_LOG_DEBUG("send discovery Interest=" << interest << " from="
|
||||
<< inFace.getId() << " to=" << outFace.getId());
|
||||
|
||||
NFD_LOG_DEBUG("send discovery Interest=" << interest << " from=" << inFace.getId() <<
|
||||
" to=" << outFace.getId());
|
||||
auto outRecord = this->sendInterest(pitEntry, outFace, interest);
|
||||
if (outRecord != nullptr) {
|
||||
outRecord->insertStrategyInfo<OutRecordInfo>().first->isNonDiscoveryInterest = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,15 +169,17 @@ SelfLearningStrategy::multicastInterest(const Interest& interest, const Face& in
|
||||
const fib::NextHopList& nexthops)
|
||||
{
|
||||
for (const auto& nexthop : nexthops) {
|
||||
Face& outFace = nexthop.getFace();
|
||||
if ((outFace.getId() == inFace.getId() && outFace.getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) ||
|
||||
wouldViolateScope(inFace, interest, outFace)) {
|
||||
if (!isNextHopEligible(inFace, interest, nexthop, pitEntry)) {
|
||||
continue;
|
||||
}
|
||||
this->sendInterest(pitEntry, FaceEndpoint(outFace, 0), interest);
|
||||
pitEntry->getOutRecord(outFace, 0)->insertStrategyInfo<OutRecordInfo>().first->isNonDiscoveryInterest = true;
|
||||
NFD_LOG_DEBUG("send non-discovery Interest=" << interest << " from="
|
||||
<< inFace.getId() << " to=" << outFace.getId());
|
||||
|
||||
Face& outFace = nexthop.getFace();
|
||||
NFD_LOG_DEBUG("send non-discovery Interest=" << interest << " from=" << inFace.getId() <<
|
||||
" to=" << outFace.getId());
|
||||
auto outRecord = this->sendInterest(pitEntry, outFace, interest);
|
||||
if (outRecord != nullptr) {
|
||||
outRecord->insertStrategyInfo<OutRecordInfo>().first->isNonDiscoveryInterest = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +201,7 @@ SelfLearningStrategy::asyncProcessData(const shared_ptr<pit::Entry>& pitEntry, c
|
||||
if (pitEntry && inFace) {
|
||||
NFD_LOG_DEBUG("found PrefixAnnouncement=" << pa.getAnnouncedName());
|
||||
data.setTag(make_shared<lp::PrefixAnnouncementTag>(lp::PrefixAnnouncementHeader(pa)));
|
||||
this->sendDataToAll(pitEntry, FaceEndpoint(*inFace, 0), data);
|
||||
this->sendDataToAll(pitEntry, *inFace, data);
|
||||
this->setExpiryTimer(pitEntry, 0_ms);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -33,14 +33,12 @@
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
/** \brief Self-learning strategy
|
||||
/** \brief Self-learning forwarding strategy
|
||||
*
|
||||
* This strategy first broadcasts Interest to learn a single path towards data,
|
||||
* then unicasts subsequent Interests along the learned path
|
||||
* then unicasts subsequent Interests along the learned path.
|
||||
*
|
||||
* \see https://redmine.named-data.net/attachments/864/Self-learning-strategy-v1.pdf
|
||||
*
|
||||
* \note This strategy is not EndpointId-aware
|
||||
*/
|
||||
class SelfLearningStrategy : public Strategy
|
||||
{
|
||||
|
||||
+56
-29
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2019, Regents of the University of California,
|
||||
* Copyright (c) 2014-2020, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "forwarder.hpp"
|
||||
#include "common/logger.hpp"
|
||||
|
||||
#include <ndn-cxx/lp/pit-token.hpp>
|
||||
|
||||
#include <boost/range/adaptor/map.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
|
||||
@@ -139,8 +141,8 @@ Strategy::makeInstanceName(const Name& input, const Name& strategyName)
|
||||
}
|
||||
|
||||
Strategy::Strategy(Forwarder& forwarder)
|
||||
: afterAddFace(forwarder.getFaceTable().afterAdd)
|
||||
, beforeRemoveFace(forwarder.getFaceTable().beforeRemove)
|
||||
: afterAddFace(forwarder.m_faceTable.afterAdd)
|
||||
, beforeRemoveFace(forwarder.m_faceTable.beforeRemove)
|
||||
, m_forwarder(forwarder)
|
||||
, m_measurements(m_forwarder.getMeasurements(), m_forwarder.getStrategyChoice(), *this)
|
||||
{
|
||||
@@ -163,7 +165,7 @@ Strategy::afterContentStoreHit(const shared_ptr<pit::Entry>& pitEntry,
|
||||
NFD_LOG_DEBUG("afterContentStoreHit pitEntry=" << pitEntry->getName()
|
||||
<< " in=" << ingress << " data=" << data.getName());
|
||||
|
||||
this->sendData(pitEntry, data, ingress);
|
||||
this->sendData(pitEntry, data, ingress.face);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -175,78 +177,103 @@ Strategy::afterReceiveData(const shared_ptr<pit::Entry>& pitEntry,
|
||||
|
||||
this->beforeSatisfyInterest(pitEntry, ingress, data);
|
||||
|
||||
this->sendDataToAll(pitEntry, ingress, data);
|
||||
this->sendDataToAll(pitEntry, ingress.face, data);
|
||||
}
|
||||
|
||||
void
|
||||
Strategy::afterReceiveNack(const FaceEndpoint& ingress, const lp::Nack& nack,
|
||||
Strategy::afterReceiveNack(const FaceEndpoint& ingress, const lp::Nack&,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
NFD_LOG_DEBUG("afterReceiveNack in=" << ingress << " pitEntry=" << pitEntry->getName());
|
||||
}
|
||||
|
||||
void
|
||||
Strategy::onDroppedInterest(const FaceEndpoint& egress, const Interest& interest)
|
||||
Strategy::onDroppedInterest(const Face& egress, const Interest& interest)
|
||||
{
|
||||
NFD_LOG_DEBUG("onDroppedInterest out=" << egress << " name=" << interest.getName());
|
||||
NFD_LOG_DEBUG("onDroppedInterest out=" << egress.getId() << " name=" << interest.getName());
|
||||
}
|
||||
|
||||
pit::OutRecord*
|
||||
Strategy::sendInterest(const shared_ptr<pit::Entry>& pitEntry, Face& egress, const Interest& interest)
|
||||
{
|
||||
if (interest.getTag<lp::PitToken>() != nullptr) {
|
||||
Interest interest2 = interest; // make a copy to preserve tag on original packet
|
||||
interest2.removeTag<lp::PitToken>();
|
||||
return m_forwarder.onOutgoingInterest(pitEntry, egress, interest2);
|
||||
}
|
||||
return m_forwarder.onOutgoingInterest(pitEntry, egress, interest);
|
||||
}
|
||||
|
||||
void
|
||||
Strategy::sendData(const shared_ptr<pit::Entry>& pitEntry, const Data& data,
|
||||
const FaceEndpoint& egress)
|
||||
Strategy::afterNewNextHop(const fib::NextHop& nextHop, const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
NFD_LOG_DEBUG("afterNewNextHop pitEntry=" << pitEntry->getName()
|
||||
<< " nexthop=" << nextHop.getFace().getId());
|
||||
}
|
||||
|
||||
bool
|
||||
Strategy::sendData(const shared_ptr<pit::Entry>& pitEntry, const Data& data, Face& egress)
|
||||
{
|
||||
BOOST_ASSERT(pitEntry->getInterest().matchesData(data));
|
||||
|
||||
// delete the PIT entry's in-record based on egress,
|
||||
// since Data is sent to face and endpoint from which the Interest was received
|
||||
pitEntry->deleteInRecord(egress.face, egress.endpoint);
|
||||
shared_ptr<lp::PitToken> pitToken;
|
||||
auto inRecord = pitEntry->getInRecord(egress);
|
||||
if (inRecord != pitEntry->in_end()) {
|
||||
pitToken = inRecord->getInterest().getTag<lp::PitToken>();
|
||||
}
|
||||
|
||||
m_forwarder.onOutgoingData(data, egress);
|
||||
// delete the PIT entry's in-record based on egress,
|
||||
// since the Data is sent to the face from which the Interest was received
|
||||
pitEntry->deleteInRecord(egress);
|
||||
|
||||
if (pitToken != nullptr) {
|
||||
Data data2 = data; // make a copy so each downstream can get a different PIT token
|
||||
data2.setTag(pitToken);
|
||||
return m_forwarder.onOutgoingData(data2, egress);
|
||||
}
|
||||
return m_forwarder.onOutgoingData(data, egress);
|
||||
}
|
||||
|
||||
void
|
||||
Strategy::sendDataToAll(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const FaceEndpoint& ingress, const Data& data)
|
||||
const Face& inFace, const Data& data)
|
||||
{
|
||||
std::set<std::pair<Face*, EndpointId>> pendingDownstreams;
|
||||
std::set<Face*> pendingDownstreams;
|
||||
auto now = time::steady_clock::now();
|
||||
|
||||
// remember pending downstreams
|
||||
for (const pit::InRecord& inRecord : pitEntry->getInRecords()) {
|
||||
if (inRecord.getExpiry() > now) {
|
||||
if (inRecord.getFace().getId() == ingress.face.getId() &&
|
||||
inRecord.getEndpointId() == ingress.endpoint &&
|
||||
if (inRecord.getFace().getId() == inFace.getId() &&
|
||||
inRecord.getFace().getLinkType() != ndn::nfd::LINK_TYPE_AD_HOC) {
|
||||
continue;
|
||||
}
|
||||
pendingDownstreams.emplace(&inRecord.getFace(), inRecord.getEndpointId());
|
||||
pendingDownstreams.emplace(&inRecord.getFace());
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& pendingDownstream : pendingDownstreams) {
|
||||
this->sendData(pitEntry, data, FaceEndpoint(*pendingDownstream.first, pendingDownstream.second));
|
||||
this->sendData(pitEntry, data, *pendingDownstream);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Strategy::sendNacks(const shared_ptr<pit::Entry>& pitEntry, const lp::NackHeader& header,
|
||||
std::initializer_list<FaceEndpoint> exceptFaceEndpoints)
|
||||
std::initializer_list<const Face*> exceptFaces)
|
||||
{
|
||||
// populate downstreams with all downstreams faces
|
||||
std::set<std::pair<Face*, EndpointId>> downstreams;
|
||||
std::unordered_set<Face*> downstreams;
|
||||
std::transform(pitEntry->in_begin(), pitEntry->in_end(), std::inserter(downstreams, downstreams.end()),
|
||||
[] (const pit::InRecord& inR) {
|
||||
return std::make_pair(&inR.getFace(), inR.getEndpointId());
|
||||
});
|
||||
[] (const pit::InRecord& inR) { return &inR.getFace(); });
|
||||
|
||||
// delete excluded faces
|
||||
for (const auto& exceptFaceEndpoint : exceptFaceEndpoints) {
|
||||
downstreams.erase({&exceptFaceEndpoint.face, exceptFaceEndpoint.endpoint});
|
||||
for (auto exceptFace : exceptFaces) {
|
||||
downstreams.erase(const_cast<Face*>(exceptFace));
|
||||
}
|
||||
|
||||
// send Nacks
|
||||
for (const auto& downstream : downstreams) {
|
||||
this->sendNack(pitEntry, FaceEndpoint(*downstream.first, downstream.second), header);
|
||||
for (auto downstream : downstreams) {
|
||||
this->sendNack(pitEntry, *downstream, header);
|
||||
}
|
||||
// warning: don't loop on pitEntry->getInRecords(), because in-record is deleted when sending Nack
|
||||
}
|
||||
|
||||
Loaded 100 of 314 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user