Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4eb0fb1b6 | ||
|
|
1a792daaa3 | ||
|
|
34e13e9802 | ||
|
|
3813f1c9ee |
No files matched your search
@@ -1,68 +0,0 @@
|
||||
name: CI
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
- '.mailmap'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
name: ${{ matrix.compiler }} on ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
compiler: [g++-8, g++-9, g++-10, g++-11,
|
||||
clang++-7, clang++-8, clang++-9, clang++-10, clang++-11, clang++-12]
|
||||
os: [ubuntu-20.04]
|
||||
include:
|
||||
- compiler: g++-7
|
||||
os: ubuntu-18.04
|
||||
- compiler: clang++-5.0
|
||||
os: ubuntu-18.04
|
||||
- compiler: clang++-6.0
|
||||
os: ubuntu-18.04
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
CXX: ${{ matrix.compiler }}
|
||||
NODE_LABELS: Linux Ubuntu
|
||||
WAF_JOBS: 2
|
||||
steps:
|
||||
- name: Install C++ compiler
|
||||
run: |
|
||||
sudo apt-get -qy install ${CXX/clang++/clang}
|
||||
${CXX} --version
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Build and test
|
||||
run: ./.jenkins
|
||||
|
||||
macos:
|
||||
name: Xcode ${{ matrix.xcode }} on ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
xcode: ['11.3', '11.7', '12.4']
|
||||
os: [macos-10.15]
|
||||
include:
|
||||
- xcode: '12.5'
|
||||
os: macos-11
|
||||
- xcode: '13.2'
|
||||
os: macos-11
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
NODE_LABELS: OSX
|
||||
WAF_JOBS: 3
|
||||
steps:
|
||||
- name: Set up Xcode
|
||||
uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: ${{ matrix.xcode }}
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Build and test
|
||||
run: ./.jenkins
|
||||
@@ -1,40 +0,0 @@
|
||||
name: Docs
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- '*.md'
|
||||
- '.mailmap'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-11, ubuntu-20.04]
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
JOB_NAME: Docs
|
||||
WAF_JOBS: 3
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
case ${RUNNER_OS} in
|
||||
Linux) export NODE_LABELS="Linux Ubuntu" ;;
|
||||
macOS) export NODE_LABELS="OSX" ;;
|
||||
esac
|
||||
find .jenkins.d/ -type f -name '[1-9]*.sh' -exec chmod -x '{}' +
|
||||
./.jenkins
|
||||
- name: Build documentation
|
||||
run: |
|
||||
./waf --color=yes configure
|
||||
./waf --color=yes build --targets=version.hpp
|
||||
./waf --color=yes build --targets=manpages
|
||||
./waf --color=yes docs
|
||||
@@ -2,25 +2,31 @@
|
||||
set -e
|
||||
source .jenkins.d/util.sh
|
||||
|
||||
if has Linux $NODE_LABELS; then
|
||||
export PATH="${HOME}/.local/bin${PATH:+:}${PATH}"
|
||||
fi
|
||||
export CACHE_DIR=${CACHE_DIR:-/tmp}
|
||||
export WAF_JOBS=${WAF_JOBS:-1}
|
||||
[[ $JOB_NAME == *"code-coverage" ]] && export DISABLE_ASAN=yes
|
||||
|
||||
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
|
||||
|
||||
if [[ -n $GITHUB_ACTIONS ]]; then
|
||||
if [[ -n $TRAVIS ]]; then
|
||||
label=$(basename "$file" | sed -E 's/[[:digit:]]+-(.*)\..*/\1/')
|
||||
echo "::group::${label}"
|
||||
echo -ne "travis_fold:start:${label}\r"
|
||||
echo -ne "travis_time:start:${label}\r"
|
||||
start=$(nanos)
|
||||
fi
|
||||
|
||||
echo "\$ $file"
|
||||
"$file"
|
||||
|
||||
if [[ -n $GITHUB_ACTIONS ]]; then
|
||||
echo "::endgroup::"
|
||||
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
|
||||
+9
-20
@@ -3,13 +3,13 @@ set -ex
|
||||
|
||||
if has OSX $NODE_LABELS; then
|
||||
FORMULAE=(boost openssl pkg-config)
|
||||
if [[ $JOB_NAME == *"Docs" ]]; then
|
||||
FORMULAE+=(doxygen graphviz)
|
||||
if has OSX-10.13 $NODE_LABELS || has OSX-10.14 $NODE_LABELS; then
|
||||
FORMULAE+=(python)
|
||||
fi
|
||||
|
||||
if [[ -n $GITHUB_ACTIONS ]]; then
|
||||
# GitHub Actions runners have a large number of pre-installed
|
||||
# Homebrew packages. Don't waste time upgrading all of them.
|
||||
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"
|
||||
@@ -23,29 +23,18 @@ if has OSX $NODE_LABELS; then
|
||||
brew cleanup
|
||||
fi
|
||||
|
||||
if [[ $JOB_NAME == *"Docs" ]]; then
|
||||
pip3 install --upgrade --upgrade-strategy=eager sphinx sphinxcontrib-doxylink
|
||||
fi
|
||||
|
||||
elif has Ubuntu $NODE_LABELS; then
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get -qy install build-essential pkg-config python3-minimal \
|
||||
libboost-all-dev libssl-dev libsqlite3-dev \
|
||||
libpcap-dev libsystemd-dev
|
||||
|
||||
case $JOB_NAME in
|
||||
*code-coverage)
|
||||
sudo apt-get -qy install lcov python3-pip
|
||||
pip3 install --user --upgrade --upgrade-strategy=eager 'gcovr~=5.0'
|
||||
;;
|
||||
*Docs)
|
||||
sudo apt-get -qy install doxygen graphviz python3-pip
|
||||
pip3 install --user --upgrade --upgrade-strategy=eager sphinx sphinxcontrib-doxylink
|
||||
;;
|
||||
esac
|
||||
if [[ $JOB_NAME == *"code-coverage" ]]; then
|
||||
sudo apt-get -qy install gcovr lcov
|
||||
fi
|
||||
|
||||
elif has CentOS-8 $NODE_LABELS; then
|
||||
sudo dnf config-manager --enable powertools
|
||||
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
|
||||
|
||||
@@ -8,7 +8,7 @@ if has OSX $NODE_LABELS; then
|
||||
security unlock-keychain -p named-data
|
||||
fi
|
||||
|
||||
ndnsec key-gen "/tmp/jenkins/$NODE_NAME" | ndnsec cert-install -
|
||||
ndnsec-keygen "/tmp/jenkins/$NODE_NAME" | ndnsec-install-cert -
|
||||
|
||||
# https://github.com/google/sanitizers/wiki/AddressSanitizerFlags
|
||||
ASAN_OPTIONS="color=always"
|
||||
|
||||
+17
-15
@@ -2,32 +2,34 @@
|
||||
set -ex
|
||||
|
||||
if [[ $JOB_NAME == *"code-coverage" ]]; then
|
||||
# Generate an XML report (Cobertura format) and a detailed HTML report using gcovr
|
||||
# Note: trailing slashes are important in the paths below. Do not remove them!
|
||||
gcovr -j$WAF_JOBS \
|
||||
--object-directory build \
|
||||
--exclude tests/ \
|
||||
--exclude websocketpp/ \
|
||||
--exclude-throw-branches \
|
||||
--exclude-unreachable-branches \
|
||||
--print-summary \
|
||||
--html-details build/gcovr/ \
|
||||
--xml build/coverage.xml
|
||||
gcovr --object-directory=build \
|
||||
--output=build/coverage.xml \
|
||||
--exclude="$PWD/(tests|websocketpp)" \
|
||||
--root=. \
|
||||
--xml
|
||||
|
||||
# Generate a detailed HTML report using lcov
|
||||
# Generate also a detailed HTML output, but using lcov (better results)
|
||||
lcov --quiet \
|
||||
--capture \
|
||||
--directory . \
|
||||
--exclude "$PWD/tests/*" \
|
||||
--exclude "$PWD/websocketpp/*" \
|
||||
--no-external \
|
||||
--rc lcov_branch_coverage=1 \
|
||||
--output-file build/coverage-with-tests-and-websocketpp.info
|
||||
|
||||
lcov --quiet \
|
||||
--remove build/coverage-with-tests-and-websocketpp.info "$PWD/websocketpp/*" \
|
||||
--rc lcov_branch_coverage=1 \
|
||||
--output-file build/coverage-with-tests.info
|
||||
|
||||
lcov --quiet \
|
||||
--remove build/coverage-with-tests.info "$PWD/tests/*" \
|
||||
--rc lcov_branch_coverage=1 \
|
||||
--output-file build/coverage.info
|
||||
|
||||
genhtml --branch-coverage \
|
||||
--demangle-cpp \
|
||||
--legend \
|
||||
--output-directory build/lcov \
|
||||
--output-directory build/coverage \
|
||||
--title "NFD unit tests" \
|
||||
build/coverage.info
|
||||
fi
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
version: ~> 1.0
|
||||
language: cpp
|
||||
os: linux
|
||||
dist: bionic
|
||||
|
||||
arch:
|
||||
- amd64
|
||||
#- arm64 # Too slow, exceeds time limit
|
||||
#- ppc64le # Fails transport tests
|
||||
#- s390x # Fails transport tests
|
||||
|
||||
env:
|
||||
- COMPILER=g++-7
|
||||
- COMPILER=g++-9
|
||||
- COMPILER=clang++-6.0
|
||||
- COMPILER=clang++-9
|
||||
|
||||
jobs:
|
||||
include:
|
||||
# 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
|
||||
|
||||
# macOS
|
||||
- os: osx
|
||||
osx_image: xcode9.4
|
||||
env: # default compiler
|
||||
- os: osx
|
||||
osx_image: xcode10.1
|
||||
env: # default compiler
|
||||
- os: osx
|
||||
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=g++-5
|
||||
- env: COMPILER=g++-6
|
||||
- env: COMPILER=clang++-4.0
|
||||
- env: COMPILER=clang++-12
|
||||
|
||||
fast_finish: true
|
||||
|
||||
before_install:
|
||||
- |
|
||||
: Adding apt repositories
|
||||
case ${COMPILER} in
|
||||
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
|
||||
;;
|
||||
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
|
||||
;;
|
||||
esac
|
||||
|
||||
install:
|
||||
- |
|
||||
: Installing C++ compiler
|
||||
if [[ -n ${COMPILER} ]]; then
|
||||
travis_retry sudo apt-get -qy install ${COMPILER/clang++/clang}
|
||||
fi
|
||||
|
||||
before_script:
|
||||
- |
|
||||
: 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
|
||||
|
||||
script:
|
||||
- ./.jenkins
|
||||
@@ -53,10 +53,10 @@ def checkWebsocket(self, **kw):
|
||||
|
||||
self.end_msg('.'.join(self.env.WEBSOCKET_VERSION))
|
||||
|
||||
self.env.append_unique('DEFINES', ['_WEBSOCKETPP_CPP11_STL_'])
|
||||
self.env.INCLUDES_WEBSOCKET = websocketDir.parent.abspath()
|
||||
self.env.HAVE_WEBSOCKET = True
|
||||
self.define('HAVE_WEBSOCKET', 1)
|
||||
self.define('_WEBSOCKETPP_CPP11_STL_', 1)
|
||||
|
||||
except Errors.WafError as error:
|
||||
if isMandatory:
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
cff-version: 1.2.0
|
||||
message: If you use NFD in your research, please cite it as below.
|
||||
license: GPL-3.0-or-later
|
||||
repository-code: "https://github.com/named-data/NFD"
|
||||
title: Named Data Networking Forwarding Daemon
|
||||
url: "https://named-data.net/doc/NFD/"
|
||||
preferred-citation:
|
||||
authors:
|
||||
- name: Named Data Networking Project Team
|
||||
date-published: "2021-07-30"
|
||||
journal: NDN Technical Report NDN-0021
|
||||
month: 7
|
||||
title: NFD Developer's Guide
|
||||
type: generic
|
||||
url: "https://named-data.net/publications/techreports/ndn-0021-11-nfd-guide/"
|
||||
version: 11
|
||||
year: 2021
|
||||
@@ -0,0 +1,81 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our
|
||||
project and our community a harassment-free experience for everyone,
|
||||
regardless of age, body size, disability, ethnicity, gender identity
|
||||
and expression, level of experience, nationality, personal appearance,
|
||||
race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive
|
||||
environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual
|
||||
attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political
|
||||
attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or
|
||||
electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in
|
||||
a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of
|
||||
acceptable behavior and are expected to take appropriate and fair
|
||||
corrective action in response to any instances of unacceptable
|
||||
behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit,
|
||||
or reject comments, commits, code, wiki edits, issues, and other
|
||||
contributions that are not aligned to this Code of Conduct, or to ban
|
||||
temporarily or permanently any contributor for other behaviors that
|
||||
they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public
|
||||
spaces when an individual is representing the project or its
|
||||
community. Examples of representing a project or community include
|
||||
using an official project e-mail address, posting via an official
|
||||
social media account, or acting as an appointed representative at an
|
||||
online or offline event. Representation of a project may be further
|
||||
defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior
|
||||
may be reported by contacting the project leaders Lixia Zhang,
|
||||
Beichuan Zhang, or Alex Afanasyev
|
||||
at
|
||||
[lixia@cs.ucla.edu](mailto:lixia@cs.ucla.edu),
|
||||
[bzhang@cs.arizona.edu](mailto:bzhang@cs.arizona.edu),
|
||||
and [aa@cs.ucla.edu](mailto:aa@cs.ucla.edu). All complaints will be
|
||||
reviewed and investigated and will result in a response that is deemed
|
||||
necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of
|
||||
an incident. Further details of specific enforcement policies may be
|
||||
posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct
|
||||
in good faith may face temporary or permanent repercussions as
|
||||
determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from
|
||||
the [Contributor Covenant](http://contributor-covenant.org), version 1.4, available
|
||||
at [http://contributor-covenant.org/version/1/4](http://contributor-covenant.org/version/1/4/)
|
||||
+489
@@ -0,0 +1,489 @@
|
||||
# Contributing to the NDN Codebase
|
||||
## Getting Started
|
||||
|
||||
The NDN team is very glad you are interested in contributing! The NDN
|
||||
(Named Data Networking) codebase is composed of many projects, with
|
||||
multiple universities across the world contributing. This
|
||||
documentation will help you understand how we work and what we expect
|
||||
from contributors.
|
||||
|
||||
### Code of Conduct
|
||||
|
||||
NDN codebase development adheres to the Contributor Covenant, located
|
||||
in `CODE_OF_CONDUCT.md`. By contributing, you are expected to also
|
||||
adhere to this code. If you feel someone has breached this code of
|
||||
conduct,
|
||||
please
|
||||
[email us](mailto:lixia@cs.ucla.edu,bzhang@cs.arizona.edu,aa@cs.ucla.edu).
|
||||
|
||||
### What can I do?
|
||||
|
||||
The NDN codebase continually needs help with, among other
|
||||
things:
|
||||
|
||||
1. Implementing new features
|
||||
2. Writing fixes for bugs
|
||||
3. Writing documentation for features that have recently changed or
|
||||
that change quickly. Sometimes people forget to update
|
||||
documentation!
|
||||
4. Code review
|
||||
|
||||
## Finding Documentation
|
||||
|
||||
The NDN team maintains a community
|
||||
([Redmine site](https://redmine.named-data.net/projects/nfd)) for
|
||||
issue tracking and documentation hosting. Redmine is the hub for
|
||||
design activity. In particular, all design discussion and decisions
|
||||
will either occur or be copied there.
|
||||
|
||||
**Why did they do it *this* way?** When writing code, if you ever have
|
||||
questions about why some design decision was made, the best approach
|
||||
is to use `git blame` on a file to inspect the last commit for some
|
||||
line of code. In this view there will be a commit hash in hex
|
||||
(e.g. `0ab12e3a`) in the first column. Using our example, `git show
|
||||
0ab12e3a` would show the commit made for that line. In the commit view
|
||||
there should be a reference number (e.g. `refs: #1234`). Using this
|
||||
number, you can find a pertaining issue on the Redmine
|
||||
(e.g., `https://redmine.named-data.net/issues/1234`).
|
||||
|
||||
Additionally, in some cases there are published papers you can read in
|
||||
order to gain a better understanding of the project. Searching for
|
||||
these papers is not difficult; in many cases you can find a pertaining
|
||||
paper or technical report listed on
|
||||
[the main NDN website](https://named-data.net/publications).
|
||||
Usually the title of a project will be a good keyword.
|
||||
|
||||
If you cannot find an answer to your question, the best place to go is
|
||||
the
|
||||
[mailing lists](https://named-data.net/codebase/platform/support/mailing-lists/).
|
||||
There are multiple different lists for different interests, so be sure you
|
||||
are mailing the right list for a quick response.
|
||||
|
||||
## Tracking work on Redmine ##
|
||||
|
||||
As mentioned above, Redmine is the organizational hub of the NDN
|
||||
projects. As such, extensive use of it is made, and learning how it
|
||||
works will help you. In particular, there is a workflow associated
|
||||
with Redmine. Generally it is:
|
||||
|
||||
1. An issue is reported by someone. At this point they should
|
||||
describe the issue, including relationships to other
|
||||
issues. Unless they know what they're doing, they should leave
|
||||
particulars blank. Such particulars are priority, target version,
|
||||
assignees, and categories.
|
||||
2. Design discussion about the issue occurs, and the issue is either
|
||||
accepted or rejected.
|
||||
3. Someone either is assigned to, or assigns themselves to work on the
|
||||
issue, setting the status to "In progress."
|
||||
**Note:** You must be a "Developer" of the project before you are
|
||||
able to toggle the Status field. A user should contact a project
|
||||
manager to be granted Developer privilege. Project managers can be
|
||||
found on "Overview" page of the project.
|
||||
4. After every useful chunk of progress, notes are made on the issue
|
||||
and the progress percentage is updated to reflect this. Remember
|
||||
that notes are actually Markdown, so it is advised to use the
|
||||
'preview' button to ensure your note looks right.
|
||||
5. The changes are uploaded to Gerrit for review. Once all changes
|
||||
pertaining to an issue are on Gerrit, an issues status should
|
||||
change to "Code review."
|
||||
6. Once all changes are cleared for merging, they either can be
|
||||
merged, or held for feedback, at which point the issue status
|
||||
should become "Feedback."
|
||||
7. After all changes have been merged, the issue should be set to
|
||||
"Closed."
|
||||
|
||||
Redmine provides other facilities for managing your work on NDN
|
||||
projects, too, such as time logging and time estimation.
|
||||
|
||||
## Contributing Guidelines
|
||||
|
||||
### Repositories ###
|
||||
|
||||
All NDN projects are hosted on GitHub, at various organizations, using git
|
||||
for version control:
|
||||
|
||||
- [Main NDN codebase](https://github.com/named-data)
|
||||
- [NDN codebase for mobile platforms](https://github.com/named-data-mobile)
|
||||
- [NDN codebase for IoT](https://github.com/named-data-iot)
|
||||
- [ndnSIM codebase](https://github.com/named-data-ndnSIM)
|
||||
- [Other NDN codebase (REMAP)](https://github.com/remap)
|
||||
|
||||
If you are unfamiliar with git, some kind
|
||||
of [tutorial on git](https://git-scm.com/book/en/v1/Getting-Started)
|
||||
should be your first step.
|
||||
|
||||
There is also a [Git game](http://learngitbranching.js.org/index.html)
|
||||
you can play. Finally, there is a
|
||||
[wiki page](https://redmine.named-data.net/projects/nfd/wiki#Development-process)
|
||||
on NFD's Redmine that has more useful links.
|
||||
|
||||
There are a lot of different projects, so take some time to look
|
||||
through them for ones that pertain to your interests. NDN projects
|
||||
use [Gerrit](https://gerrit.named-data.net/) for code review purposes.
|
||||
|
||||
Occasionally there will be other repositories used privately to test
|
||||
changes, but this is uncommon. In general, you will not need to refer
|
||||
to these repositories.
|
||||
|
||||
### Style ###
|
||||
|
||||
Most NDN projects are written in C++, and there is a
|
||||
[style guide](https://named-data.net/doc/ndn-cxx/current/code-style.html).
|
||||
In general the NDN style is similar to the GNU style, but there are
|
||||
some significant changes. This style guide is not exhaustive, and in
|
||||
all cases not covered by the guide you should emulate the current
|
||||
style of the project.
|
||||
|
||||
There is a
|
||||
[partial styleguide](https://redmine.named-data.net/projects/nfd/wiki/CodeStyle)
|
||||
for Python. It applies many of the provisions from the C++ guide, in
|
||||
addition to some other Python-specific things.
|
||||
|
||||
Some NDN projects are written in JavaScript, and there is a [style guide](https://named-data.net/codebase/platform/documentation/ndn-platform-development-guidelines/cpp-code-guidelines/) for that language, too.
|
||||
|
||||
#### Commit Messages ####
|
||||
|
||||
Commit messages are very important, as they are usually the first
|
||||
thing (besides the changelog file) a developer looks at when trying to
|
||||
understand the timeline of a project. Commit messages should:
|
||||
|
||||
- Have a short, descriptive first line, starting with the module
|
||||
they change. A good rule of thumb is a maximum length of 65
|
||||
characters.
|
||||
- If including a body, leave a blank line between the first line and
|
||||
the rest, and ensure that each line is no longer than 72 characters.
|
||||
- Include Redmine issue numbers. The exact syntax is given below.
|
||||
- Be written in an imperative mood. E.g. `"Make foo a bar"` and not
|
||||
`"Foo is now a bar"`
|
||||
- Use the present tense. E.g. `"Make foo a bar"` and not `"Made foo a
|
||||
bar"`
|
||||
|
||||
To explain, the anatomy of a typical commit message is like this:
|
||||
|
||||
docs: write contributing guide and code of conduct
|
||||
|
||||
This commit adds a guide that may be useful for new-comers to NDN in
|
||||
becoming productive contributors. This commit also adds a code of
|
||||
conduct.
|
||||
|
||||
refs: #3898
|
||||
Change-Id: Ife89360305027dba9020f0b298793c1121ae1fd6c
|
||||
|
||||
Explaining this:
|
||||
|
||||
- `docs` is the module that the commit affects. We want this because
|
||||
it lets someone know at a glance what part of the project it
|
||||
changes. For some projects, there will be only one module or only
|
||||
very small other modules. This practice should be observed in
|
||||
those cases, too.
|
||||
- `#3898` is the Redmine issue number. Gerrit transforms these into
|
||||
clickable links, and it is useful to reviewers to gain background
|
||||
understanding of the issue. You can have multiple by separating
|
||||
them with commas.
|
||||
- `Change-Id` should be filled automatically. It is used by Gerrit
|
||||
to track changes.
|
||||
|
||||
### Unit Tests ###
|
||||
With a few exceptions, every patch needs to have unit tests that
|
||||
accompany them. For C++, we use
|
||||
the [Boost unit test framework](http://www.boost.org/libs/test) to
|
||||
help us out. Note that this link points to the newest version of the
|
||||
Boost Test library documentation, and you may need to refer to older
|
||||
documentation if you are using an older version of Boost. More
|
||||
information on this is available in
|
||||
the
|
||||
[NFD Dev Guide](https://named-data.net/publications/techreports/ndn-0021-7-nfd-developer-guide/)
|
||||
|
||||
When designing and writing tests, a few things need to be kept in mind:
|
||||
|
||||
1. Unit tests are **design** tools, *not* debug tools. Just because
|
||||
your code passes some unit tests does not mean it is
|
||||
bug-free. Unit tests are tools to convince you that your code does
|
||||
what you think it does.
|
||||
2. It can be difficult to know when you should test something. If
|
||||
you find that you are having a hard time designing a test for
|
||||
something, ask yourself whether it is because it doesn't make
|
||||
sense to test what you've just written, or if it's because the way
|
||||
you designed it makes it difficult to test. Consider a second look
|
||||
at your design if you think it's the second one.
|
||||
3. The method that gave the world unit tests says that unit tests
|
||||
should be written *before* the code they test. This is
|
||||
a contentious issue, so writing them either before or after is
|
||||
acceptable. If writing them later, keep the tests in mind when
|
||||
writing the code, and it will help design good interfaces.
|
||||
4. At the very least, write the test for a completed module/unit of
|
||||
code before moving on. Doing this will ensure that the test gets
|
||||
written, and will help you think about the interface that you need
|
||||
to examine. If you don't, you may forget exactly what each piece
|
||||
is responsible for when you're looking at the whole system
|
||||
afterward.
|
||||
5. Separate your I/O, as it is very hard to test, so I/O should be
|
||||
isolated if possible. Consider something like separating a
|
||||
function that invokes I/O into two functions: one that does the
|
||||
I/O and calls the other one, which takes that I/O result. This
|
||||
will make it easier to test that second function than if they were
|
||||
combined.
|
||||
|
||||
Writing unit tests using the Boost framework is quite simple, and you
|
||||
can refer to existing unit tests for examples.
|
||||
([This is a good example.](https://github.com/named-data/NFD/blob/master/tests/rib/rib.t.cpp))
|
||||
|
||||
#### Building and running unit tests ####
|
||||
This is mentioned in greater depth in
|
||||
the [developer's readme](README-dev.md), but the basic procedure is:
|
||||
|
||||
1. In the base directory of the project, run `./waf distclean`. This
|
||||
removes all prior build files.
|
||||
2. Run `./waf configure --with-tests`. This configures the next build
|
||||
to also build the tests.
|
||||
3. Run `./waf`. This will build the tests.
|
||||
4. Then, the unit tests will be in the `build` directory, and will be
|
||||
named `unit-tests-<module name`, e.g. `unit-tests-nlsr` or
|
||||
`unit-tests-rib`. To run just one test suite, run
|
||||
`./unit-tests-exampleModule -t ExampleTestSuite`. To run a
|
||||
specific test in a suite, use `./unit-tests-exampleModule -t
|
||||
ExampleTestSuite/ExampleTestCase`.
|
||||
|
||||
## Gerrit: Uploading Patches and Code Review ##
|
||||
|
||||
As mentioned above, NDN projects
|
||||
use [Gerrit](https://gerrit.named-data.net/) for code review. This is
|
||||
a web-hosted, open code review platform that allows for interactive
|
||||
code review, rebasing, and cross-linking with the Redmine, and a
|
||||
developer interacts with it using the familiar git. For issues that
|
||||
require a tracker reference, a particularly useful feature is that
|
||||
the `refs: #...` becomes a clickable link to the issue for design
|
||||
discussion.
|
||||
|
||||
### First-time Setup ###
|
||||
|
||||
The first-time Gerrit setup goes like this:
|
||||
|
||||
1. Log in to Gerrit. You can authenticate using many different
|
||||
methods, including GitHub OAuth. You need to ensure that you have a Gerrit username:
|
||||
1. Log in.
|
||||
2. Click on your name in the top right corner and click "Settings" in the pop-up box.
|
||||
3. In the `Username` box, check for a name. If there's already one there, great.
|
||||
4. If not, type one in, and this will be used in later steps.
|
||||
|
||||
2. Set up your Gerrit credentials. This will depend on how you
|
||||
configured your Gerrit remote in step 1. Among other things, you
|
||||
need to set up identities so that the email on your Gerrit profile
|
||||
matches whatever email you will be committing with on your git
|
||||
repo.
|
||||
**Note:** We only support using
|
||||
[SSH access to Gerrit](https://gerrit.named-data.net/Documentation/user-upload.html#ssh).
|
||||
|
||||
This shows what the identities panel looks like. If you do
|
||||
not see the email here that you have configured git to use, you
|
||||
cannot upload to Gerrit.
|
||||

|
||||
|
||||
In that case, add it under contact information panel.
|
||||
.
|
||||
|
||||
Gerrit itself has
|
||||
[extensive documentation](https://gerrit.named-data.net/Documentation/error-messages.html)
|
||||
regarding error messages, and this identity-based one is by far the most
|
||||
common. This is the
|
||||
[documentation for an identity error.](https://gerrit.named-data.net/Documentation/error-invalid-author.html)
|
||||
|
||||
3. Clone the source for a project from Gerrit.
|
||||
1. While logged in to Gerrit, there will be a link in the top-left
|
||||
area, `Projects`.
|
||||
2. From this project view, click on the `Clone with commit-msg
|
||||
hook` tab.
|
||||
3. Click on the `ssh` tab to select cloning over SSH. **Note:**
|
||||
This will require setting up SSH access to Gerrit first.
|
||||
4. Copy-and-paste the `git clone ...` command into your terminal
|
||||
to fetch the project source.
|
||||
|
||||
After this, your remotes will be set up correctly, and pushing to
|
||||
Gerrit will only require `git push origin HEAD:refs/for/master` after
|
||||
committing work. This section has some
|
||||
[git tips and tricks to type less][type-less].
|
||||
|
||||
### Uploading patches ###
|
||||
|
||||
Most patches should have a corresponding Redmine issue that they can
|
||||
reference. If you search the Redmine and notice there is no relevant
|
||||
issue for a patch you are writing, please create an issue first. You
|
||||
will need a Redmine account, which can be created there.
|
||||
|
||||
After writing some changes, commit them locally as normal. After
|
||||
saving and exiting your editor, the commit hook will insert a unique
|
||||
`Change-Id` to the message.
|
||||
|
||||
|
||||
Once you have a commit message you are happy with, simply run `git
|
||||
push HEAD:refs/for/master`.
|
||||
|
||||
**Note:** Gerrit separates commits into patch sets by the unique
|
||||
`Change-Id`s. As a result, you must either:
|
||||
|
||||
* Squash your various commits into one with `git rebase -i
|
||||
<initial commit>`, ensuring that the ultimate `Change-Id` in the
|
||||
commit is the one on the patch set on Gerrit. This workflow is
|
||||
generally preferred.
|
||||
* Amend your commit with any new changes using `git commit --amend`.
|
||||
|
||||
If you do not do this, what will happen is that each commit will be
|
||||
interpreted by Gerrit as a separate patch set. This is probably not
|
||||
what you want.
|
||||
|
||||
### Code Review ###
|
||||
#### Dealing with Code Review ####
|
||||
|
||||
It is important to remember that code review is about improving
|
||||
the quality of code contributed, and nothing else. Further, code
|
||||
review is highly important, as every line of code that's
|
||||
committed comes with a burden of maintenance. Code review helps
|
||||
minimize the burden of that maintenance. Consider that when you
|
||||
are receiving comments, those comments are influenced by two
|
||||
things:
|
||||
|
||||
- How the reviewer personally feels about the change ("Would I
|
||||
be happy to see this code in a year?" or "Would I be happy if
|
||||
I wrote this?") and
|
||||
- How the reviewer feels the change abides by style and usage
|
||||
requirements ("I may not personally mind, but we have to do it
|
||||
this way.")
|
||||
|
||||
Remembering these things when reading comments helps to separate
|
||||
what can feel like needless negativity.
|
||||
|
||||
#### Doing Code Review and Writing Comments ####
|
||||
|
||||
**Code review is *extremely* important!** We need every bit of code
|
||||
review you can give. In many cases this is the bottleneck for
|
||||
new contributors who do not fully understand how certain
|
||||
language constructs should be used, what best practices are,
|
||||
etc. In these cases it is important to give constructive
|
||||
feedback.
|
||||
|
||||
Writing comments is somewhat counter-intuitive on Gerrit. If you are
|
||||
signed in through a modern browser, you can leave a comment in a file
|
||||
either by clicking on the line number, by selecting some text you want
|
||||
to comment and pressing 'c', or by clicking on someone else's
|
||||
comment. After typing, click the `Save` button there. After navigating
|
||||
through the patch set with the arrows at the top-right of the Gerrit
|
||||
UI, you then must click the up-arrow to get back to the Change
|
||||
screen. **At this point your comments have *not* been made yet!** You
|
||||
must then click the `Reply...` button, and assign a score. If you
|
||||
correctly saved your comments, they will be shown at the bottom of
|
||||
that box. Once you click post, the comments will be made public to
|
||||
others.
|
||||
|
||||
Minimally, a review *must* include:
|
||||
|
||||
- A score (usually -1, 0, or +1)
|
||||
- An "itemized" commentary on each objection you have, or a
|
||||
justification for a whole-change objection.
|
||||
|
||||
Optimally, a review should include:
|
||||
|
||||
- A useful explanation of *why* you object to some item. This is
|
||||
more important than it first appears. Consider that although
|
||||
you may have been writing code since before you could count,
|
||||
not everyone has. Some things may not be obvious to others,
|
||||
and sharing your knowledge is key to making an open-source
|
||||
project work.
|
||||
- Comments about good design decisions. These help motivate
|
||||
developers when otherwise a review is entirely negative
|
||||
comments.
|
||||
|
||||
#### Expediting the Code Review Process ####
|
||||
|
||||
If you observe that code review takes a long time, there are a
|
||||
few things that you can do to to expedite the process:
|
||||
|
||||
1. **Think about language best practices.**
|
||||
2. **Ask yourself how you would feel about this code, if you saw it "in the wild."**
|
||||
3. **When making code decisions, ask yourself "why *shouldn't* I do it this way?"**
|
||||
|
||||
#### Responding to Code Review ####
|
||||
|
||||
There are a few things to remember when responding to code review, including:
|
||||
|
||||
- **Don't** click "Done" on a comment if you agree with a comment and
|
||||
are updating the code accordingly. These comments are essentially
|
||||
useless and only clutter the discussion. Gerrit has a convenient
|
||||
mechanism to check the differences between two patch sets, so
|
||||
reviewers are expected to check that their comments have been
|
||||
addressed.
|
||||
- **Don't** blindly follow what is suggested. Review is just that: a
|
||||
review. Sometimes what is suggested is functionally equivalent to
|
||||
what you have implemented. Other times, the reviewer has not
|
||||
considered something when writing their review, and their
|
||||
suggestion will not work. Lastly, if you disagree with a suggestion
|
||||
for some other reason, feel free to object, but you may be asked to
|
||||
provide an explanation.
|
||||
- **How** to reply. To reply to a comment, click on the comment in
|
||||
the Gerrit interface, type your reply, and then press save. After
|
||||
replying, you **must remember** to go to the main patch set change
|
||||
screen, and press `Reply...`. Your comments will be shown as
|
||||
drafts, and you must click `Post` to make them visible to others.
|
||||
|
||||
### Jenkins ###
|
||||
|
||||
As a supplement to the code review process, every patch set is automatically
|
||||
compiled and tested on multiple platforms
|
||||
using [our instance of Jenkins](http://jenkins.named-data.net/), the
|
||||
continuous integration system. Interacting with Jenkins is not usually
|
||||
necessary, as Jenkins automatically picks up new patch sets and posts
|
||||
the results. Typically the only interaction needed with Jenkins is
|
||||
when some kind of glitch occurs and a build needs to be retriggered.
|
||||
|
||||
It is expected that code is checked locally. Reviewers may wait until
|
||||
Jenkins checks the code before doing a more functional review of the
|
||||
code. Since Jenkins checks can take a while, you can save some time by
|
||||
checking yourself first.
|
||||
|
||||
### Gerrit Change-Id Commit Hook ###
|
||||
|
||||
If you encounter an error like this when trying to push work:
|
||||
|
||||
remote: ERROR: [4311462] missing Change-Id in commit message footer
|
||||
remote:
|
||||
remote: Hint: To automatically insert Change-Id, install the hook:
|
||||
remote: gitdir=$(git rev-parse --git-dir); scp -p -P 29418 someuser@gerrit.named-data.net:hooks/commit-msg ${gitdir}/hooks/
|
||||
remote: And then amend the commit:
|
||||
remote: git commit --amend
|
||||
|
||||
Then your commit hook has not been set up correctly, somehow. Follow
|
||||
the instructions in the terminal to resolve this.
|
||||
|
||||
### Code Style Robot ###
|
||||
|
||||
As part of CI, there is a script that checks every patch uploaded to
|
||||
Gerrit for code style consistency. Checking these kinds of things is
|
||||
notoriously difficult, and while the robot is very good in general, it
|
||||
will occasionally report false positives and miss things. So all
|
||||
issues it raises should be inspected manually to ensure they really
|
||||
are style problems. Further, since this automated check is not
|
||||
perfect, you should take steps (e.g., configure your editor or run a
|
||||
linter before you commit) to ensure you adhere to code style rules.
|
||||
|
||||
### <a name="type-less"></a> Typing Less to Upload Patches to Gerrit ###
|
||||
|
||||
If typing `HEAD:refs/for/master` feels
|
||||
repetitive, you have a few options:
|
||||
|
||||
* You can configure git to do the work for you, as described
|
||||
in [this blog post](https://yoursunny.com/t/2017/NFD-devbox/#Uploading-to-Gerrit)
|
||||
|
||||
* Git has an alias system that you can use to specify certain
|
||||
commands. For example, you can use `git config --global alias.pg
|
||||
"push origin HEAD:refs/for/master"` to make `git pg` push to
|
||||
Gerrit. [Learn about git aliases here.](https://githowto.com/aliases)
|
||||
|
||||
* If using Linux or macOS, it is relatively simple to create a shell
|
||||
alias: `alias gs="git status"` for example, or `alias gitpush="git
|
||||
push origin HEAD:refs/for/master`. The alias itself must be one
|
||||
word, but it can represent multiple words. To persist your
|
||||
aliases, they need to go in your environment file, which is
|
||||
generally at `~/.bashrc` or `~/.zshrc` or `~/.profile`. The exact
|
||||
syntax of aliases and the environment variables file will vary by
|
||||
shell. You should be careful not to overuse aliases, however.
|
||||
|
||||
[type-less]: #type-less
|
||||
@@ -1,9 +1,8 @@
|
||||
# NFD - Named Data Networking Forwarding Daemon
|
||||
|
||||
[](https://github.com/named-data/NFD/actions/workflows/ci.yml)
|
||||
[](https://github.com/named-data/NFD/actions/workflows/docs.yml)
|
||||

|
||||

|
||||

|
||||
[](https://travis-ci.org/named-data/NFD)
|
||||

|
||||
|
||||
## Overview
|
||||
|
||||
|
||||
+20
-17
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, 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,20 +28,20 @@
|
||||
|
||||
#include "core/config.hpp"
|
||||
|
||||
#ifdef NFD_WITH_TESTS
|
||||
#define NFD_VIRTUAL_WITH_TESTS virtual
|
||||
#define NFD_PUBLIC_WITH_TESTS_ELSE_PROTECTED public
|
||||
#define NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE public
|
||||
#define NFD_PROTECTED_WITH_TESTS_ELSE_PRIVATE protected
|
||||
#define NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL override
|
||||
#define NFD_FINAL_UNLESS_WITH_TESTS
|
||||
#ifdef WITH_TESTS
|
||||
#define VIRTUAL_WITH_TESTS virtual
|
||||
#define PUBLIC_WITH_TESTS_ELSE_PROTECTED public
|
||||
#define PUBLIC_WITH_TESTS_ELSE_PRIVATE public
|
||||
#define PROTECTED_WITH_TESTS_ELSE_PRIVATE protected
|
||||
#define OVERRIDE_WITH_TESTS_ELSE_FINAL override
|
||||
#define FINAL_UNLESS_WITH_TESTS
|
||||
#else
|
||||
#define NFD_VIRTUAL_WITH_TESTS
|
||||
#define NFD_PUBLIC_WITH_TESTS_ELSE_PROTECTED protected
|
||||
#define NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE private
|
||||
#define NFD_PROTECTED_WITH_TESTS_ELSE_PRIVATE private
|
||||
#define NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL final
|
||||
#define NFD_FINAL_UNLESS_WITH_TESTS final
|
||||
#define VIRTUAL_WITH_TESTS
|
||||
#define PUBLIC_WITH_TESTS_ELSE_PROTECTED protected
|
||||
#define PUBLIC_WITH_TESTS_ELSE_PRIVATE private
|
||||
#define PROTECTED_WITH_TESTS_ELSE_PRIVATE private
|
||||
#define OVERRIDE_WITH_TESTS_ELSE_FINAL final
|
||||
#define FINAL_UNLESS_WITH_TESTS final
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
@@ -59,6 +59,8 @@
|
||||
#include <vector>
|
||||
|
||||
#include <ndn-cxx/data.hpp>
|
||||
#include <ndn-cxx/delegation.hpp>
|
||||
#include <ndn-cxx/delegation-list.hpp>
|
||||
#include <ndn-cxx/interest.hpp>
|
||||
#include <ndn-cxx/name.hpp>
|
||||
#include <ndn-cxx/encoding/block.hpp>
|
||||
@@ -66,10 +68,8 @@
|
||||
#include <ndn-cxx/net/face-uri.hpp>
|
||||
#include <ndn-cxx/util/backports.hpp>
|
||||
#include <ndn-cxx/util/exception.hpp>
|
||||
#include <ndn-cxx/util/optional.hpp>
|
||||
#include <ndn-cxx/util/scheduler.hpp>
|
||||
#include <ndn-cxx/util/signal.hpp>
|
||||
#include <ndn-cxx/util/span.hpp>
|
||||
#include <ndn-cxx/util/time.hpp>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
@@ -94,15 +94,18 @@ using std::static_pointer_cast;
|
||||
using std::dynamic_pointer_cast;
|
||||
using std::const_pointer_cast;
|
||||
|
||||
using std::bind;
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
using ndn::optional;
|
||||
using ndn::nullopt;
|
||||
using ndn::span;
|
||||
using ndn::to_string;
|
||||
|
||||
using ndn::Block;
|
||||
using ndn::Data;
|
||||
using ndn::Delegation;
|
||||
using ndn::DelegationList;
|
||||
using ndn::FaceUri;
|
||||
using ndn::Interest;
|
||||
using ndn::Name;
|
||||
|
||||
+11
-14
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, 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,15 +26,14 @@
|
||||
#ifndef NFD_CORE_VERSION_HPP
|
||||
#define NFD_CORE_VERSION_HPP
|
||||
|
||||
// NFD version follows Semantic Versioning 2.0.0 based on year and month of the release
|
||||
// NFD version follows Semantic Versioning 2.0.0
|
||||
// https://semver.org/spec/v2.0.0.html
|
||||
//
|
||||
// To change version number, modify the VERSION variable in the top-level wscript.
|
||||
// To change version number, modify VERSION variable in top-level wscript.
|
||||
|
||||
/**
|
||||
* \brief NFD version represented as an integer.
|
||||
/** \brief NFD version represented as an integer.
|
||||
*
|
||||
* Equivalent to: #NFD_VERSION_MAJOR*1000000 + #NFD_VERSION_MINOR*1000 + #NFD_VERSION_PATCH
|
||||
* Equivalent to: `#NFD_VERSION_MAJOR*1000000 + #NFD_VERSION_MINOR*1000 + #NFD_VERSION_PATCH`
|
||||
*/
|
||||
#define NFD_VERSION @VERSION@
|
||||
|
||||
@@ -45,8 +44,7 @@
|
||||
/// The patch version of NFD
|
||||
#define NFD_VERSION_PATCH @VERSION_PATCH@
|
||||
|
||||
/**
|
||||
* \brief NFD version represented as a string.
|
||||
/** \brief NFD version represented as a string.
|
||||
*
|
||||
* Format:
|
||||
* @code
|
||||
@@ -55,21 +53,20 @@
|
||||
*/
|
||||
extern const char NFD_VERSION_STRING[];
|
||||
|
||||
/**
|
||||
* \brief NFD version string, including git commit information if NFD is build from a
|
||||
* specific git commit.
|
||||
/** \brief NFD version string, including git commit information, if NFD is build from
|
||||
* specific git commit.
|
||||
*
|
||||
* #NFD_VERSION_BUILD_STRING is obtained using the following command (`NFD-` prefix is
|
||||
* afterwards removed): ``git describe --match 'NFD-*'``
|
||||
* afterwards removed): `git describe --match 'NFD-*'`
|
||||
*
|
||||
* When NFD is not built from git, #NFD_VERSION_BUILD_STRING equals #NFD_VERSION_STRING.
|
||||
*
|
||||
* Format:
|
||||
* @code
|
||||
* MAJOR.MINOR(.PATCH)(-release-candidate-tag)(-(number-of-commits-since-tag)-COMMIT-HASH)
|
||||
* MAJOR.MINOR.PATCH(-release-candidate-tag)(-(number-of-commits-since-tag)-COMMIT-HASH)
|
||||
* @endcode
|
||||
*
|
||||
* Example: 2022.02-1-g5c86570
|
||||
* Example: 0.1.0-rc1-1-g5c86570
|
||||
*/
|
||||
extern const char NFD_VERSION_BUILD_STRING[];
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -117,30 +117,13 @@ public: // parse helpers
|
||||
"' for option '" + key + "' in section '" + sectionName + "'"));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
static T
|
||||
parseNumber(const ConfigSection::value_type& option, const std::string& sectionName)
|
||||
{
|
||||
return parseNumber<T>(option.second, option.first, sectionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief check that a value is within the inclusive range [min, max]
|
||||
* \throw Error the value is out of the acceptable range
|
||||
*/
|
||||
template<typename T>
|
||||
static void
|
||||
checkRange(T value, T min, T max, const std::string& key, const std::string& sectionName)
|
||||
{
|
||||
static_assert(std::is_integral<T>::value, "T must be an integral type");
|
||||
|
||||
if (value < min || value > max) {
|
||||
NDN_THROW(Error("Invalid value '" + to_string(value) + "' for option '" + key +
|
||||
"' in section '" + sectionName + "': out of acceptable range [" +
|
||||
to_string(min) + ", " + to_string(max) + "]"));
|
||||
}
|
||||
}
|
||||
|
||||
public: // setup and parsing
|
||||
/// \brief setup notification of configuration file sections
|
||||
void
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -50,7 +50,7 @@ getScheduler()
|
||||
return *g_scheduler;
|
||||
}
|
||||
|
||||
#ifdef NFD_WITH_TESTS
|
||||
#ifdef WITH_TESTS
|
||||
void
|
||||
resetGlobalIoService()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021 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,
|
||||
@@ -61,7 +61,7 @@ runOnMainIoService(const std::function<void()>& f);
|
||||
void
|
||||
runOnRibIoService(const std::function<void()>& f);
|
||||
|
||||
#ifdef NFD_WITH_TESTS
|
||||
#ifdef WITH_TESTS
|
||||
/** \brief Destroy the global io_service instance.
|
||||
*
|
||||
* It will be recreated at the next invocation of getGlobalIoService().
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,18 +33,18 @@ namespace nfd {
|
||||
|
||||
NFD_LOG_INIT(PrivilegeHelper);
|
||||
|
||||
#ifdef NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
uid_t PrivilegeHelper::s_normalUid = ::geteuid();
|
||||
gid_t PrivilegeHelper::s_normalGid = ::getegid();
|
||||
|
||||
uid_t PrivilegeHelper::s_privilegedUid = ::geteuid();
|
||||
gid_t PrivilegeHelper::s_privilegedGid = ::getegid();
|
||||
#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
|
||||
void
|
||||
PrivilegeHelper::initialize(const std::string& userName, const std::string& groupName)
|
||||
{
|
||||
#ifdef NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
static const size_t MAX_GROUP_BUFFER_SIZE = 16384; // 16 KiB
|
||||
static const size_t MAX_PASSWD_BUFFER_SIZE = 16384;
|
||||
|
||||
@@ -111,13 +111,13 @@ PrivilegeHelper::initialize(const std::string& userName, const std::string& grou
|
||||
if (!userName.empty() || !groupName.empty()) {
|
||||
throw Error("Dropping and raising privileges is not supported on this platform");
|
||||
}
|
||||
#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
}
|
||||
|
||||
void
|
||||
PrivilegeHelper::drop()
|
||||
{
|
||||
#ifdef NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
if (::geteuid() == s_normalUid && ::getegid() == s_normalGid)
|
||||
return;
|
||||
|
||||
@@ -132,13 +132,13 @@ PrivilegeHelper::drop()
|
||||
NFD_LOG_INFO("dropped to effective uid=" << ::geteuid() << " gid=" << ::getegid());
|
||||
#else
|
||||
NFD_LOG_WARN("Dropping privileges is not supported on this platform");
|
||||
#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
}
|
||||
|
||||
void
|
||||
PrivilegeHelper::raise()
|
||||
{
|
||||
#ifdef NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
if (::geteuid() == s_privilegedUid && ::getegid() == s_privilegedGid)
|
||||
return;
|
||||
|
||||
@@ -153,7 +153,7 @@ PrivilegeHelper::raise()
|
||||
NFD_LOG_INFO("elevated to effective uid=" << ::geteuid() << " gid=" << ::getegid());
|
||||
#else
|
||||
NFD_LOG_WARN("Elevating privileges is not supported on this platform");
|
||||
#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
{
|
||||
raise();
|
||||
try {
|
||||
std::forward<F>(f)();
|
||||
f();
|
||||
}
|
||||
catch (...) {
|
||||
drop();
|
||||
@@ -80,18 +80,18 @@ public:
|
||||
drop();
|
||||
}
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
static void
|
||||
raise();
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
#ifdef NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
static uid_t s_normalUid;
|
||||
static gid_t s_normalGid;
|
||||
|
||||
static uid_t s_privilegedUid;
|
||||
static gid_t s_privilegedGid;
|
||||
#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
#endif // HAVE_PRIVILEGE_DROP_AND_ELEVATE
|
||||
};
|
||||
|
||||
} // namespace nfd
|
||||
|
||||
@@ -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-2021, 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,
|
||||
@@ -37,12 +37,6 @@ Channel::setUri(const FaceUri& uri)
|
||||
m_uri = uri;
|
||||
}
|
||||
|
||||
void
|
||||
Channel::setDefaultMtu(size_t mtu)
|
||||
{
|
||||
m_defaultMtu = mtu;
|
||||
}
|
||||
|
||||
void
|
||||
connectFaceClosedSignal(Face& face, std::function<void()> f)
|
||||
{
|
||||
|
||||
+1
-13
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -50,14 +50,6 @@ public:
|
||||
return m_uri;
|
||||
}
|
||||
|
||||
/** \brief Returns the default MTU for all faces created by this channel
|
||||
*/
|
||||
size_t
|
||||
getDefaultMtu() const
|
||||
{
|
||||
return m_defaultMtu;
|
||||
}
|
||||
|
||||
/** \brief Returns whether the channel is listening
|
||||
*/
|
||||
virtual bool
|
||||
@@ -72,12 +64,8 @@ protected:
|
||||
void
|
||||
setUri(const FaceUri& uri);
|
||||
|
||||
void
|
||||
setDefaultMtu(size_t mtu);
|
||||
|
||||
private:
|
||||
FaceUri m_uri;
|
||||
size_t m_defaultMtu = ndn::MAX_NDN_PACKET_SIZE;
|
||||
};
|
||||
|
||||
/** \brief Prototype for the callback that is invoked when a face is created
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, 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,7 @@ template<class Protocol, class Addressing = Unicast>
|
||||
class DatagramTransport : public Transport
|
||||
{
|
||||
public:
|
||||
using protocol = Protocol;
|
||||
typedef Protocol protocol;
|
||||
|
||||
/** \brief Construct datagram transport.
|
||||
*
|
||||
@@ -58,11 +58,11 @@ public:
|
||||
ssize_t
|
||||
getSendQueueLength() override;
|
||||
|
||||
/**
|
||||
* \brief Receive datagram, translate buffer into packet, deliver to parent class.
|
||||
/** \brief Receive datagram, translate buffer into packet, deliver to parent class.
|
||||
*/
|
||||
void
|
||||
receiveDatagram(span<const uint8_t> buffer, const boost::system::error_code& error);
|
||||
receiveDatagram(const uint8_t* buffer, size_t nBytesReceived,
|
||||
const boost::system::error_code& error);
|
||||
|
||||
protected:
|
||||
void
|
||||
@@ -170,23 +170,23 @@ DatagramTransport<T, U>::doSend(const Block& packet)
|
||||
|
||||
template<class T, class U>
|
||||
void
|
||||
DatagramTransport<T, U>::receiveDatagram(span<const uint8_t> buffer,
|
||||
DatagramTransport<T, U>::receiveDatagram(const uint8_t* buffer, size_t nBytesReceived,
|
||||
const boost::system::error_code& error)
|
||||
{
|
||||
if (error)
|
||||
return processErrorCode(error);
|
||||
|
||||
NFD_LOG_FACE_TRACE("Received: " << buffer.size() << " bytes from " << m_sender);
|
||||
NFD_LOG_FACE_TRACE("Received: " << nBytesReceived << " bytes from " << m_sender);
|
||||
|
||||
bool isOk = false;
|
||||
Block element;
|
||||
std::tie(isOk, element) = Block::fromBuffer(buffer);
|
||||
std::tie(isOk, element) = Block::fromBuffer(buffer, nBytesReceived);
|
||||
if (!isOk) {
|
||||
NFD_LOG_FACE_WARN("Failed to parse incoming packet from " << m_sender);
|
||||
// This packet won't extend the face lifetime
|
||||
return;
|
||||
}
|
||||
if (element.size() != buffer.size()) {
|
||||
if (element.size() != nBytesReceived) {
|
||||
NFD_LOG_FACE_WARN("Received datagram size and decoded element size don't match");
|
||||
// This packet won't extend the face lifetime
|
||||
return;
|
||||
@@ -200,7 +200,7 @@ template<class T, class U>
|
||||
void
|
||||
DatagramTransport<T, U>::handleReceive(const boost::system::error_code& error, size_t nBytesReceived)
|
||||
{
|
||||
receiveDatagram(ndn::make_span(m_receiveBuffer).first(nBytesReceived), error);
|
||||
receiveDatagram(m_receiveBuffer.data(), nBytesReceived, error);
|
||||
|
||||
if (m_socket.is_open())
|
||||
m_socket.async_receive_from(boost::asio::buffer(m_receiveBuffer), m_sender,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, 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,
|
||||
@@ -120,24 +120,26 @@ EthernetChannel::handleRead(const boost::system::error_code& error,
|
||||
return;
|
||||
}
|
||||
|
||||
span<const uint8_t> pkt;
|
||||
const uint8_t* pkt;
|
||||
size_t len;
|
||||
std::string err;
|
||||
std::tie(pkt, err) = m_pcap.readNextPacket();
|
||||
std::tie(pkt, len, err) = m_pcap.readNextPacket();
|
||||
|
||||
if (pkt.empty()) {
|
||||
if (pkt == nullptr) {
|
||||
NFD_LOG_CHAN_WARN("Read error: " << err);
|
||||
}
|
||||
else {
|
||||
const ether_header* eh;
|
||||
std::tie(eh, err) = ethernet::checkFrameHeader(pkt, m_localEndpoint->getEthernetAddress(),
|
||||
std::tie(eh, err) = ethernet::checkFrameHeader(pkt, len, m_localEndpoint->getEthernetAddress(),
|
||||
m_localEndpoint->getEthernetAddress());
|
||||
if (eh == nullptr) {
|
||||
NFD_LOG_CHAN_DEBUG(err);
|
||||
}
|
||||
else {
|
||||
ethernet::Address sender(eh->ether_shost);
|
||||
pkt = pkt.subspan(ethernet::HDR_LEN);
|
||||
processIncomingPacket(pkt, sender, onFaceCreated, onReceiveFailed);
|
||||
pkt += ethernet::HDR_LEN;
|
||||
len -= ethernet::HDR_LEN;
|
||||
processIncomingPacket(pkt, len, sender, onFaceCreated, onReceiveFailed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +154,7 @@ EthernetChannel::handleRead(const boost::system::error_code& error,
|
||||
}
|
||||
|
||||
void
|
||||
EthernetChannel::processIncomingPacket(span<const uint8_t> packet,
|
||||
EthernetChannel::processIncomingPacket(const uint8_t* packet, size_t length,
|
||||
const ethernet::Address& sender,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onReceiveFailed)
|
||||
@@ -180,7 +182,7 @@ EthernetChannel::processIncomingPacket(span<const uint8_t> packet,
|
||||
|
||||
// dispatch the packet to the face for processing
|
||||
auto* transport = static_cast<UnicastEthernetTransport*>(face->getTransport());
|
||||
transport->receivePayload(packet, sender);
|
||||
transport->receivePayload(packet, length, sender);
|
||||
}
|
||||
|
||||
std::pair<bool, shared_ptr<Face>>
|
||||
@@ -202,6 +204,9 @@ EthernetChannel::createFace(const ethernet::Address& remoteEndpoint,
|
||||
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,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "channel.hpp"
|
||||
#include "ethernet-protocol.hpp"
|
||||
#include "pcap-helper.hpp"
|
||||
|
||||
#include <ndn-cxx/net/network-interface.hpp>
|
||||
|
||||
namespace nfd {
|
||||
@@ -38,7 +37,7 @@ namespace face {
|
||||
/**
|
||||
* \brief Class implementing Ethernet-based channel to create faces
|
||||
*/
|
||||
class EthernetChannel final : public Channel
|
||||
class EthernetChannel : public Channel
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -64,13 +63,13 @@ public:
|
||||
time::nanoseconds idleTimeout);
|
||||
|
||||
bool
|
||||
isListening() const final
|
||||
isListening() const override
|
||||
{
|
||||
return m_isListening;
|
||||
}
|
||||
|
||||
size_t
|
||||
size() const final
|
||||
size() const override
|
||||
{
|
||||
return m_channelFaces.size();
|
||||
}
|
||||
@@ -111,7 +110,7 @@ private:
|
||||
const FaceCreationFailedCallback& onReceiveFailed);
|
||||
|
||||
void
|
||||
processIncomingPacket(span<const uint8_t> packet,
|
||||
processIncomingPacket(const uint8_t* packet, size_t length,
|
||||
const ethernet::Address& sender,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onReceiveFailed);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -34,7 +34,7 @@ namespace face {
|
||||
|
||||
/** \brief Protocol factory for Ethernet
|
||||
*/
|
||||
class EthernetFactory final : public ProtocolFactory
|
||||
class EthernetFactory : public ProtocolFactory
|
||||
{
|
||||
public:
|
||||
static const std::string&
|
||||
@@ -77,15 +77,15 @@ private:
|
||||
*/
|
||||
void
|
||||
doProcessConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context) final;
|
||||
FaceSystem::ConfigContext& context) override;
|
||||
|
||||
void
|
||||
doCreateFace(const CreateFaceRequest& req,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onFailure) final;
|
||||
const FaceCreationFailedCallback& onFailure) override;
|
||||
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
doGetChannels() const final;
|
||||
doGetChannels() const override;
|
||||
|
||||
/** \brief Create EthernetChannel on \p netif if requested by \p m_unicastConfig.
|
||||
* \return new or existing channel, or nullptr if no channel should be created
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -30,13 +30,14 @@
|
||||
namespace nfd {
|
||||
namespace ethernet {
|
||||
|
||||
std::tuple<const ether_header*, std::string>
|
||||
checkFrameHeader(span<const uint8_t> packet, const Address& localAddr, const Address& destAddr)
|
||||
std::pair<const ether_header*, std::string>
|
||||
checkFrameHeader(const uint8_t* packet, size_t length,
|
||||
const Address& localAddr, const Address& destAddr)
|
||||
{
|
||||
if (packet.size() < HDR_LEN + MIN_DATA_LEN)
|
||||
return {nullptr, "Received frame too short: " + to_string(packet.size()) + " bytes"};
|
||||
if (length < HDR_LEN + MIN_DATA_LEN)
|
||||
return {nullptr, "Received frame too short: " + to_string(length) + " bytes"};
|
||||
|
||||
const ether_header* eh = reinterpret_cast<const ether_header*>(packet.data());
|
||||
const ether_header* eh = reinterpret_cast<const ether_header*>(packet);
|
||||
|
||||
// in some cases VLAN-tagged frames may survive the BPF filter,
|
||||
// make sure we do not process those frames (see #3348)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -27,7 +27,6 @@
|
||||
#define NFD_DAEMON_FACE_ETHERNET_PROTOCOL_HPP
|
||||
|
||||
#include "core/common.hpp"
|
||||
|
||||
#include <ndn-cxx/net/ethernet.hpp>
|
||||
#include <net/ethernet.h>
|
||||
|
||||
@@ -36,8 +35,9 @@ namespace ethernet {
|
||||
|
||||
using namespace ndn::ethernet;
|
||||
|
||||
std::tuple<const ether_header*, std::string>
|
||||
checkFrameHeader(span<const uint8_t> packet, const Address& localAddr, const Address& destAddr);
|
||||
std::pair<const ether_header*, std::string>
|
||||
checkFrameHeader(const uint8_t* packet, size_t length,
|
||||
const Address& localAddr, const Address& destAddr);
|
||||
|
||||
} // namespace ethernet
|
||||
} // namespace nfd
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, 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,
|
||||
@@ -125,17 +125,17 @@ EthernetTransport::sendPacket(const ndn::Block& block)
|
||||
// pad with zeroes if the payload is too short
|
||||
if (block.size() < ethernet::MIN_DATA_LEN) {
|
||||
static const uint8_t padding[ethernet::MIN_DATA_LEN] = {};
|
||||
buffer.appendBytes(ndn::make_span(padding).subspan(block.size()));
|
||||
buffer.appendByteArray(padding, ethernet::MIN_DATA_LEN - block.size());
|
||||
}
|
||||
|
||||
// construct and prepend the ethernet header
|
||||
uint16_t ethertype = boost::endian::native_to_big(ethernet::ETHERTYPE_NDN);
|
||||
buffer.prependBytes({reinterpret_cast<const uint8_t*>(ðertype), ethernet::TYPE_LEN});
|
||||
buffer.prependBytes(m_srcAddress);
|
||||
buffer.prependBytes(m_destAddress);
|
||||
buffer.prependByteArray(reinterpret_cast<const uint8_t*>(ðertype), ethernet::TYPE_LEN);
|
||||
buffer.prependByteArray(m_srcAddress.data(), m_srcAddress.size());
|
||||
buffer.prependByteArray(m_destAddress.data(), m_destAddress.size());
|
||||
|
||||
// send the frame
|
||||
int sent = pcap_inject(m_pcap, buffer.data(), buffer.size());
|
||||
int sent = pcap_inject(m_pcap, buffer.buf(), buffer.size());
|
||||
if (sent < 0)
|
||||
handleError("Send operation failed: " + m_pcap.getLastError());
|
||||
else if (static_cast<size_t>(sent) < buffer.size())
|
||||
@@ -168,24 +168,26 @@ EthernetTransport::handleRead(const boost::system::error_code& error)
|
||||
return;
|
||||
}
|
||||
|
||||
span<const uint8_t> pkt;
|
||||
const uint8_t* pkt;
|
||||
size_t len;
|
||||
std::string err;
|
||||
std::tie(pkt, err) = m_pcap.readNextPacket();
|
||||
std::tie(pkt, len, err) = m_pcap.readNextPacket();
|
||||
|
||||
if (pkt.empty()) {
|
||||
if (pkt == nullptr) {
|
||||
NFD_LOG_FACE_WARN("Read error: " << err);
|
||||
}
|
||||
else {
|
||||
const ether_header* eh;
|
||||
std::tie(eh, err) = ethernet::checkFrameHeader(pkt, m_srcAddress,
|
||||
std::tie(eh, err) = ethernet::checkFrameHeader(pkt, len, m_srcAddress,
|
||||
m_destAddress.isMulticast() ? m_destAddress : m_srcAddress);
|
||||
if (eh == nullptr) {
|
||||
NFD_LOG_FACE_WARN(err);
|
||||
}
|
||||
else {
|
||||
ethernet::Address sender(eh->ether_shost);
|
||||
pkt = pkt.subspan(ethernet::HDR_LEN);
|
||||
receivePayload(pkt, sender);
|
||||
pkt += ethernet::HDR_LEN;
|
||||
len -= ethernet::HDR_LEN;
|
||||
receivePayload(pkt, len, sender);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,13 +202,14 @@ EthernetTransport::handleRead(const boost::system::error_code& error)
|
||||
}
|
||||
|
||||
void
|
||||
EthernetTransport::receivePayload(span<const uint8_t> payload, const ethernet::Address& sender)
|
||||
EthernetTransport::receivePayload(const uint8_t* payload, size_t length,
|
||||
const ethernet::Address& sender)
|
||||
{
|
||||
NFD_LOG_FACE_TRACE("Received: " << payload.size() << " bytes from " << sender);
|
||||
NFD_LOG_FACE_TRACE("Received: " << length << " bytes from " << sender);
|
||||
|
||||
bool isOk = false;
|
||||
Block element;
|
||||
std::tie(isOk, element) = Block::fromBuffer(payload);
|
||||
std::tie(isOk, element) = Block::fromBuffer(payload, length);
|
||||
if (!isOk) {
|
||||
NFD_LOG_FACE_WARN("Failed to parse incoming packet from " << sender);
|
||||
// This packet won't extend the face lifetime
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, 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,11 +49,13 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Processes the payload of an incoming frame
|
||||
* @param payload Payload bytes, starting from the first byte after the Ethernet header
|
||||
* @param payload Pointer to the first byte of data after the Ethernet header
|
||||
* @param length Payload length
|
||||
* @param sender Sender address
|
||||
*/
|
||||
void
|
||||
receivePayload(span<const uint8_t> payload, const ethernet::Address& sender);
|
||||
receivePayload(const uint8_t* payload, size_t length,
|
||||
const ethernet::Address& sender);
|
||||
|
||||
protected:
|
||||
EthernetTransport(const ndn::net::NetworkInterface& localEndpoint,
|
||||
|
||||
@@ -81,6 +81,7 @@ struct FaceParams
|
||||
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;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -36,8 +36,8 @@ namespace nfd {
|
||||
class FaceEndpoint
|
||||
{
|
||||
public:
|
||||
FaceEndpoint(Face& face, EndpointId endpoint)
|
||||
: face(face)
|
||||
FaceEndpoint(const Face& face, EndpointId endpoint)
|
||||
: face(const_cast<Face&>(face))
|
||||
, endpoint(endpoint)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -94,9 +94,7 @@ FaceSystem::hasFactoryForScheme(const std::string& scheme) const
|
||||
void
|
||||
FaceSystem::setConfigFile(ConfigFile& configFile)
|
||||
{
|
||||
configFile.addSectionHandler(CFGSEC_FACESYSTEM, [this] (auto&&... args) {
|
||||
processConfig(std::forward<decltype(args)>(args)...);
|
||||
});
|
||||
configFile.addSectionHandler(CFGSEC_FACESYSTEM, bind(&FaceSystem::processConfig, this, _1, _2, _3));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -100,7 +100,7 @@ public:
|
||||
bool isDryRun;
|
||||
};
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
ProtocolFactoryCtorParams
|
||||
makePFCtorParams();
|
||||
|
||||
@@ -109,7 +109,7 @@ private:
|
||||
processConfig(const ConfigSection& configSection, bool isDryRun,
|
||||
const std::string& filename);
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
/** \brief config section name => protocol factory
|
||||
*/
|
||||
std::map<std::string, unique_ptr<ProtocolFactory>> m_factories;
|
||||
|
||||
+9
-12
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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 @@ typedef TransportState FaceState;
|
||||
* LinkService is the upper part, which translates between network-layer packets
|
||||
* and TLV blocks, and may provide additional services such as fragmentation and reassembly.
|
||||
*/
|
||||
class Face NFD_FINAL_UNLESS_WITH_TESTS : public std::enable_shared_from_this<Face>, noncopyable
|
||||
class Face FINAL_UNLESS_WITH_TESTS : public std::enable_shared_from_this<Face>, noncopyable
|
||||
{
|
||||
public:
|
||||
Face(unique_ptr<LinkService> service, unique_ptr<Transport> transport);
|
||||
@@ -171,16 +171,7 @@ public: // properties
|
||||
getExpirationTime() const;
|
||||
|
||||
const FaceCounters&
|
||||
getCounters() const
|
||||
{
|
||||
return m_counters;
|
||||
}
|
||||
|
||||
FaceCounters&
|
||||
getCounters()
|
||||
{
|
||||
return m_counters;
|
||||
}
|
||||
getCounters() const;
|
||||
|
||||
/**
|
||||
* \brief Get channel on which face was created (unicast) or the associated channel (multicast)
|
||||
@@ -310,6 +301,12 @@ Face::getExpirationTime() const
|
||||
return m_transport->getExpirationTime();
|
||||
}
|
||||
|
||||
inline const FaceCounters&
|
||||
Face::getCounters() const
|
||||
{
|
||||
return m_counters;
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const FaceLogHelper<Face>& flh);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,7 @@
|
||||
*/
|
||||
|
||||
#include "generic-link-service.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <ndn-cxx/lp/pit-token.hpp>
|
||||
#include <ndn-cxx/lp/tags.hpp>
|
||||
|
||||
@@ -45,12 +45,46 @@ GenericLinkService::GenericLinkService(const GenericLinkService::Options& option
|
||||
, m_reassembler(m_options.reassemblerOptions, this)
|
||||
, m_reliability(m_options.reliabilityOptions, this)
|
||||
, m_lastSeqNo(-2)
|
||||
, m_nextMarkTime(time::steady_clock::time_point::max())
|
||||
, m_nextMarkTime(time::steady_clock::TimePoint::max())
|
||||
, m_nMarkedSinceInMarkingState(0)
|
||||
, globalSp(options.C * 0.99, options.vqSize)
|
||||
{
|
||||
m_reassembler.beforeTimeout.connect([this] (auto&&...) { ++nReassemblyTimeouts; });
|
||||
m_reliability.onDroppedInterest.connect([this] (const auto& i) { notifyDroppedInterest(i); });
|
||||
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
|
||||
@@ -105,7 +139,7 @@ GenericLinkService::sendLpPacket(lp::Packet&& pkt)
|
||||
|
||||
auto block = pkt.wireEncode();
|
||||
if (mtu != MTU_UNLIMITED && block.size() > static_cast<size_t>(mtu)) {
|
||||
++nOutOverMtu;
|
||||
++this->nOutOverMtu;
|
||||
NFD_LOG_FACE_WARN("attempted to send packet over MTU limit");
|
||||
return;
|
||||
}
|
||||
@@ -115,11 +149,34 @@ GenericLinkService::sendLpPacket(lp::Packet&& pkt)
|
||||
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
|
||||
@@ -207,7 +264,7 @@ GenericLinkService::sendNetPacket(lp::Packet&& pkt, bool isInterest)
|
||||
std::tie(isOk, frags) = m_fragmenter.fragmentPacket(pkt, mtu);
|
||||
if (!isOk) {
|
||||
// fragmentation failed (warning is logged by LpFragmenter)
|
||||
++nFragmentationErrors;
|
||||
++this->nFragmentationErrors;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -261,7 +318,7 @@ GenericLinkService::checkCongestionLevel(lp::Packet& pkt)
|
||||
if (static_cast<size_t>(sendQueueLength) > m_options.defaultCongestionThreshold) {
|
||||
const auto now = time::steady_clock::now();
|
||||
|
||||
if (m_nextMarkTime == time::steady_clock::time_point::max()) {
|
||||
if (m_nextMarkTime == time::steady_clock::TimePoint::max()) {
|
||||
m_nextMarkTime = now + m_options.baseCongestionMarkingInterval;
|
||||
}
|
||||
// Mark packet if sendQueue stays above target for one interval
|
||||
@@ -279,10 +336,10 @@ GenericLinkService::checkCongestionLevel(lp::Packet& pkt)
|
||||
m_nextMarkTime += interval;
|
||||
}
|
||||
}
|
||||
else if (m_nextMarkTime != time::steady_clock::time_point::max()) {
|
||||
else if (m_nextMarkTime != time::steady_clock::TimePoint::max()) {
|
||||
// Congestion incident has ended, so reset
|
||||
NFD_LOG_FACE_DEBUG("Send queue length dropped below congestion threshold");
|
||||
m_nextMarkTime = time::steady_clock::time_point::max();
|
||||
m_nextMarkTime = time::steady_clock::TimePoint::max();
|
||||
m_nMarkedSinceInMarkingState = 0;
|
||||
}
|
||||
}
|
||||
@@ -296,7 +353,7 @@ GenericLinkService::doReceivePacket(const Block& packet, const EndpointId& endpo
|
||||
if (m_options.reliabilityOptions.isEnabled) {
|
||||
if (!m_reliability.processIncomingPacket(pkt)) {
|
||||
NFD_LOG_FACE_TRACE("received duplicate fragment: DROP");
|
||||
++nDuplicateSequence;
|
||||
++this->nDuplicateSequence;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -321,7 +378,7 @@ GenericLinkService::doReceivePacket(const Block& packet, const EndpointId& endpo
|
||||
}
|
||||
}
|
||||
catch (const tlv::Error& e) {
|
||||
++nInLpInvalid;
|
||||
++this->nInLpInvalid;
|
||||
NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
|
||||
}
|
||||
}
|
||||
@@ -344,14 +401,14 @@ GenericLinkService::decodeNetPacket(const Block& netPkt, const lp::Packet& first
|
||||
this->decodeData(netPkt, firstPkt, endpointId);
|
||||
break;
|
||||
default:
|
||||
++nInNetInvalid;
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("unrecognized network-layer packet TLV-TYPE " << netPkt.type() << ": DROP");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (const tlv::Error& e) {
|
||||
++nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP" << netPkt.type());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,7 +433,7 @@ GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstP
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::CachePolicyField>()) {
|
||||
++nInNetInvalid;
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received CachePolicy with Interest: DROP");
|
||||
return;
|
||||
}
|
||||
@@ -399,7 +456,7 @@ GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstP
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::PrefixAnnouncementField>()) {
|
||||
++nInNetInvalid;
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received PrefixAnnouncement with Interest: DROP");
|
||||
return;
|
||||
}
|
||||
@@ -408,6 +465,8 @@ GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstP
|
||||
interest->setTag(make_shared<lp::PitToken>(firstPkt.get<lp::PitTokenField>()));
|
||||
}
|
||||
|
||||
this->globalSp.receiveInterest(*interest);
|
||||
this->globalSp.triggerCalObjectRate();
|
||||
this->receiveInterest(*interest, endpointId);
|
||||
}
|
||||
|
||||
@@ -421,13 +480,13 @@ GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt,
|
||||
auto data = make_shared<Data>(netPkt);
|
||||
|
||||
if (firstPkt.has<lp::NackField>()) {
|
||||
++nInNetInvalid;
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received Nack with Data: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::NextHopFaceIdField>()) {
|
||||
++nInNetInvalid;
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received NextHopFaceId with Data: DROP");
|
||||
return;
|
||||
}
|
||||
@@ -448,7 +507,7 @@ GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt,
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::NonDiscoveryField>()) {
|
||||
++nInNetInvalid;
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received NonDiscovery with Data: DROP");
|
||||
return;
|
||||
}
|
||||
@@ -462,6 +521,13 @@ GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt,
|
||||
}
|
||||
}
|
||||
|
||||
// 不处理本地命令通信
|
||||
if (data->getName().getPrefix(1).toUri() != "/localhost") {
|
||||
// TR = min(TR, OR)
|
||||
this->globalSp.assignObjectRate(*data);
|
||||
}
|
||||
|
||||
this->globalSp.triggerCalObjectRate();
|
||||
this->receiveData(*data, endpointId);
|
||||
}
|
||||
|
||||
@@ -476,13 +542,13 @@ GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt,
|
||||
nack.setHeader(firstPkt.get<lp::NackField>());
|
||||
|
||||
if (firstPkt.has<lp::NextHopFaceIdField>()) {
|
||||
++nInNetInvalid;
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received NextHopFaceId with Nack: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::CachePolicyField>()) {
|
||||
++nInNetInvalid;
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received CachePolicy with Nack: DROP");
|
||||
return;
|
||||
}
|
||||
@@ -496,13 +562,13 @@ GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt,
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::NonDiscoveryField>()) {
|
||||
++nInNetInvalid;
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received NonDiscovery with Nack: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstPkt.has<lp::PrefixAnnouncementField>()) {
|
||||
++nInNetInvalid;
|
||||
++this->nInNetInvalid;
|
||||
NFD_LOG_FACE_WARN("received PrefixAnnouncement with Nack: DROP");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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 {
|
||||
@@ -93,8 +94,8 @@ public:
|
||||
/** \brief GenericLinkService is a LinkService that implements the NDNLPv2 protocol
|
||||
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
|
||||
*/
|
||||
class GenericLinkService NFD_FINAL_UNLESS_WITH_TESTS : public LinkService
|
||||
, protected virtual GenericLinkServiceCounters
|
||||
class GenericLinkService FINAL_UNLESS_WITH_TESTS : public LinkService
|
||||
, protected virtual GenericLinkServiceCounters
|
||||
{
|
||||
public:
|
||||
/** \brief Options that control the behavior of GenericLinkService
|
||||
@@ -164,6 +165,9 @@ public:
|
||||
* 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
|
||||
@@ -184,10 +188,10 @@ public:
|
||||
setOptions(const Options& options);
|
||||
|
||||
const Counters&
|
||||
getCounters() const NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
getCounters() const OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
|
||||
ssize_t
|
||||
getEffectiveMtu() const NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
getEffectiveMtu() const OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
|
||||
/** \brief Whether MTU can be overridden to the specified value
|
||||
*
|
||||
@@ -196,7 +200,7 @@ public:
|
||||
bool
|
||||
canOverrideMtuTo(ssize_t mtu) const;
|
||||
|
||||
NFD_PROTECTED_WITH_TESTS_ELSE_PRIVATE: // send path
|
||||
PROTECTED_WITH_TESTS_ELSE_PRIVATE: // send path
|
||||
/** \brief request an IDLE packet to transmit pending service fields
|
||||
*/
|
||||
void
|
||||
@@ -208,13 +212,13 @@ NFD_PROTECTED_WITH_TESTS_ELSE_PRIVATE: // send path
|
||||
sendLpPacket(lp::Packet&& pkt);
|
||||
|
||||
void
|
||||
doSendInterest(const Interest& interest) NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
doSendInterest(const Interest& interest) OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
|
||||
void
|
||||
doSendData(const Data& data) NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
doSendData(const Data& data) OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
|
||||
void
|
||||
doSendNack(const ndn::lp::Nack& nack) NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
doSendNack(const ndn::lp::Nack& nack) OVERRIDE_WITH_TESTS_ELSE_FINAL;
|
||||
|
||||
/** \brief assign consecutive sequence numbers to LpPackets
|
||||
*/
|
||||
@@ -245,7 +249,7 @@ private: // send path
|
||||
|
||||
private: // receive path
|
||||
void
|
||||
doReceivePacket(const Block& packet, const EndpointId& endpoint) NFD_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
|
||||
@@ -297,19 +301,22 @@ private: // receive path
|
||||
void
|
||||
decodeNack(const Block& netPkt, const lp::Packet& firstPkt, const EndpointId& endpointId);
|
||||
|
||||
NFD_PROTECTED_WITH_TESTS_ELSE_PRIVATE:
|
||||
PROTECTED_WITH_TESTS_ELSE_PRIVATE:
|
||||
Options m_options;
|
||||
LpFragmenter m_fragmenter;
|
||||
LpReassembler m_reassembler;
|
||||
LpReliability m_reliability;
|
||||
lp::Sequence m_lastSeqNo;
|
||||
|
||||
NFD_PUBLIC_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;
|
||||
/// 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-2022, 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,
|
||||
@@ -123,5 +123,15 @@ InternalClientTransport::send(const Block& wire)
|
||||
m_forwarder->receivePacket(wire);
|
||||
}
|
||||
|
||||
void
|
||||
InternalClientTransport::send(const Block& header, const Block& payload)
|
||||
{
|
||||
ndn::EncodingBuffer encoder(header.size() + payload.size(), header.size() + payload.size());
|
||||
encoder.appendByteArray(header.wire(), header.size());
|
||||
encoder.appendByteArray(payload.wire(), payload.size());
|
||||
|
||||
send(encoder.block());
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, 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,
|
||||
@@ -101,7 +101,10 @@ public:
|
||||
receivePacket(const Block& packet) final;
|
||||
|
||||
void
|
||||
send(const Block& block) final;
|
||||
send(const Block& wire) final;
|
||||
|
||||
void
|
||||
send(const Block& header, const Block& payload) final;
|
||||
|
||||
void
|
||||
close() final
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, 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,
|
||||
@@ -69,9 +69,10 @@ LpReassembler::receiveFragment(EndpointId remoteEndpoint, const lp::Packet& pack
|
||||
|
||||
// check for fast path
|
||||
if (fragIndex == 0 && fragCount == 1) {
|
||||
auto frag = packet.get<lp::FragmentField>();
|
||||
Block netPkt({frag.first, frag.second});
|
||||
return {true, netPkt, packet};
|
||||
ndn::Buffer::const_iterator fragBegin, fragEnd;
|
||||
std::tie(fragBegin, fragEnd) = packet.get<lp::FragmentField>();
|
||||
Block netPkt(&*fragBegin, std::distance(fragBegin, fragEnd));
|
||||
return std::make_tuple(true, netPkt, packet);
|
||||
}
|
||||
|
||||
// check Sequence and compute message identifier
|
||||
@@ -139,7 +140,7 @@ LpReassembler::doReassembly(const Key& key)
|
||||
it = std::copy(fragBegin, fragEnd, it);
|
||||
}
|
||||
|
||||
return Block(fragBuffer);
|
||||
return Block(&*(fragBuffer.cbegin()), std::distance(fragBuffer.cbegin(), fragBuffer.cend()));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, 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,
|
||||
@@ -174,7 +174,7 @@ LpReliability::processIncomingPacket(const lp::Packet& pkt)
|
||||
// Check for recent received Sequences to remove
|
||||
auto now = time::steady_clock::now();
|
||||
auto rto = m_rttEst.getEstimatedRto();
|
||||
while (!m_recentRecvSeqsQueue.empty() &&
|
||||
while (m_recentRecvSeqsQueue.size() > 0 &&
|
||||
now > m_recentRecvSeqs[m_recentRecvSeqsQueue.front()] + rto) {
|
||||
m_recentRecvSeqs.erase(m_recentRecvSeqsQueue.front());
|
||||
m_recentRecvSeqsQueue.pop();
|
||||
@@ -226,7 +226,7 @@ LpReliability::assignTxSequence(lp::Packet& frag)
|
||||
{
|
||||
lp::Sequence txSeq = ++m_lastTxSeqNo;
|
||||
frag.set<lp::TxSequenceField>(txSeq);
|
||||
if (!m_unackedFrags.empty() && m_lastTxSeqNo == m_firstUnackedFrag->first) {
|
||||
if (m_unackedFrags.size() > 0 && m_lastTxSeqNo == m_firstUnackedFrag->first) {
|
||||
NDN_THROW(std::length_error("TxSequence range exceeded"));
|
||||
}
|
||||
return m_lastTxSeqNo;
|
||||
@@ -310,8 +310,10 @@ LpReliability::onLpPacketLost(lp::Sequence txSeq, bool isTimeout)
|
||||
// Notify strategy of dropped Interest (if any)
|
||||
if (netPkt->isInterest) {
|
||||
BOOST_ASSERT(netPkt->pkt.has<lp::FragmentField>());
|
||||
auto frag = netPkt->pkt.get<lp::FragmentField>();
|
||||
onDroppedInterest(Interest(Block({frag.first, frag.second})));
|
||||
ndn::Buffer::const_iterator fragBegin, fragEnd;
|
||||
std::tie(fragBegin, fragEnd) = netPkt->pkt.get<lp::FragmentField>();
|
||||
Block frag(&*fragBegin, std::distance(fragBegin, fragEnd));
|
||||
onDroppedInterest(Interest(frag));
|
||||
}
|
||||
|
||||
// Delete this LpPacket from m_unackedFrags
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -105,12 +105,12 @@ public:
|
||||
void
|
||||
piggyback(lp::Packet& pkt, ssize_t mtu);
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
class UnackedFrag;
|
||||
class NetPkt;
|
||||
using UnackedFrags = std::map<lp::Sequence, UnackedFrag>;
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
/** \brief assign TxSequence number to a fragment
|
||||
* \param frag fragment to assign TxSequence to
|
||||
* \return assigned TxSequence number
|
||||
@@ -162,7 +162,7 @@ NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
void
|
||||
deleteUnackedFrag(UnackedFrags::iterator fragIt);
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
/** \brief contains a sent fragment that has not been acknowledged and associated data
|
||||
*/
|
||||
class UnackedFrag
|
||||
@@ -200,7 +200,7 @@ public:
|
||||
tlv::sizeOfVarNumber(sizeof(lp::Sequence)) +
|
||||
sizeof(lp::Sequence);
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
Options m_options;
|
||||
GenericLinkService* m_linkService;
|
||||
UnackedFrags m_unackedFrags;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -150,7 +150,7 @@ MulticastUdpTransport::openRxSocket(protocol::socket& sock,
|
||||
else {
|
||||
BOOST_ASSERT(localAddress.is_v6());
|
||||
sock.set_option(boost::asio::ip::v6_only(true));
|
||||
#ifdef NFD_WITH_TESTS
|
||||
#ifdef WITH_TESTS
|
||||
// To simplify unit tests, we bind to the "any" IPv6 address if the supplied multicast
|
||||
// address lacks a scope id. Calling bind() without a scope id would otherwise fail.
|
||||
if (multicastGroup.address().to_v6().scope_id() == 0)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -61,7 +61,7 @@ public:
|
||||
processConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context);
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
struct Rule
|
||||
{
|
||||
std::vector<FaceUri> remotes;
|
||||
@@ -71,7 +71,7 @@ NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
Rule
|
||||
parseRule(int index, const ConfigSection& confRule) const;
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
const FaceSystem& m_faceSystem;
|
||||
FaceCreatedCallback m_addFace;
|
||||
shared_ptr<ndn::net::NetworkMonitor> m_netmon;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -198,10 +198,8 @@ doesNetifMatchRule(const ndn::net::NetworkInterface& netif, const std::string& r
|
||||
bool
|
||||
NetworkInterfacePredicate::operator()(const ndn::net::NetworkInterface& netif) const
|
||||
{
|
||||
return std::any_of(m_whitelist.begin(), m_whitelist.end(),
|
||||
[&netif] (const auto& rule) { return doesNetifMatchRule(netif, rule); }) &&
|
||||
std::none_of(m_blacklist.begin(), m_blacklist.end(),
|
||||
[&netif] (const auto& rule) { return doesNetifMatchRule(netif, rule); });
|
||||
return std::any_of(m_whitelist.begin(), m_whitelist.end(), bind(&doesNetifMatchRule, std::cref(netif), _1)) &&
|
||||
std::none_of(m_blacklist.begin(), m_blacklist.end(), bind(&doesNetifMatchRule, std::cref(netif), _1));
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -221,10 +219,8 @@ doesAddressMatchRule(const boost::asio::ip::address& address, const std::string&
|
||||
bool
|
||||
IpAddressPredicate::operator()(const boost::asio::ip::address& address) const
|
||||
{
|
||||
return std::any_of(m_whitelist.begin(), m_whitelist.end(),
|
||||
[&address] (const auto& rule) { return doesAddressMatchRule(address, rule); }) &&
|
||||
std::none_of(m_blacklist.begin(), m_blacklist.end(),
|
||||
[&address] (const auto& rule) { return doesAddressMatchRule(address, rule); });
|
||||
return std::any_of(m_whitelist.begin(), m_whitelist.end(), bind(&doesAddressMatchRule, std::cref(address), _1)) &&
|
||||
std::none_of(m_blacklist.begin(), m_blacklist.end(), bind(&doesAddressMatchRule, std::cref(address), _1));
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -79,7 +79,7 @@ private:
|
||||
void
|
||||
parseList(std::set<std::string>& set, std::initializer_list<std::pair<std::string, std::string>> list);
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PROTECTED:
|
||||
PUBLIC_WITH_TESTS_ELSE_PROTECTED:
|
||||
std::set<std::string> m_whitelist;
|
||||
std::set<std::string> m_blacklist;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,7 +33,7 @@ namespace face {
|
||||
|
||||
/** \brief A Transport that drops every packet.
|
||||
*/
|
||||
class NullTransport NFD_FINAL_UNLESS_WITH_TESTS : public Transport
|
||||
class NullTransport FINAL_UNLESS_WITH_TESTS : public Transport
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
@@ -44,14 +44,14 @@ public:
|
||||
|
||||
protected:
|
||||
void
|
||||
doClose() NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL
|
||||
doClose() OVERRIDE_WITH_TESTS_ELSE_FINAL
|
||||
{
|
||||
setState(TransportState::CLOSED);
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
doSend(const Block&) NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL
|
||||
doSend(const Block&) OVERRIDE_WITH_TESTS_ELSE_FINAL
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
+11
-15
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, 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,8 +26,6 @@
|
||||
#include "pcap-helper.hpp"
|
||||
#include "ethernet-protocol.hpp"
|
||||
|
||||
#include "common/privilege-helper.hpp"
|
||||
|
||||
#include <pcap/pcap.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -65,11 +63,9 @@ PcapHelper::~PcapHelper()
|
||||
void
|
||||
PcapHelper::activate(int dlt)
|
||||
{
|
||||
PrivilegeHelper::runElevated([this] {
|
||||
int ret = pcap_activate(m_pcap);
|
||||
if (ret < 0)
|
||||
NDN_THROW(Error("pcap_activate: " + std::string(pcap_statustostr(ret))));
|
||||
});
|
||||
int ret = pcap_activate(m_pcap);
|
||||
if (ret < 0)
|
||||
NDN_THROW(Error("pcap_activate: " + std::string(pcap_statustostr(ret))));
|
||||
|
||||
if (pcap_set_datalink(m_pcap, dlt) < 0)
|
||||
NDN_THROW(Error("pcap_set_datalink: " + getLastError()));
|
||||
@@ -79,7 +75,7 @@ PcapHelper::activate(int dlt)
|
||||
}
|
||||
|
||||
void
|
||||
PcapHelper::close() noexcept
|
||||
PcapHelper::close()
|
||||
{
|
||||
if (m_pcap) {
|
||||
pcap_close(m_pcap);
|
||||
@@ -100,7 +96,7 @@ PcapHelper::getFd() const
|
||||
}
|
||||
|
||||
std::string
|
||||
PcapHelper::getLastError() const noexcept
|
||||
PcapHelper::getLastError() const
|
||||
{
|
||||
return pcap_geterr(m_pcap);
|
||||
}
|
||||
@@ -128,19 +124,19 @@ PcapHelper::setPacketFilter(const char* filter) const
|
||||
NDN_THROW(Error("pcap_setfilter: " + getLastError()));
|
||||
}
|
||||
|
||||
std::tuple<span<const uint8_t>, std::string>
|
||||
PcapHelper::readNextPacket() const noexcept
|
||||
std::tuple<const uint8_t*, size_t, std::string>
|
||||
PcapHelper::readNextPacket() const
|
||||
{
|
||||
pcap_pkthdr* header;
|
||||
const uint8_t* packet;
|
||||
|
||||
int ret = pcap_next_ex(m_pcap, &header, &packet);
|
||||
if (ret < 0)
|
||||
return {span<uint8_t>{}, getLastError()};
|
||||
return std::make_tuple(nullptr, 0, getLastError());
|
||||
else if (ret == 0)
|
||||
return {span<uint8_t>{}, "timed out"};
|
||||
return std::make_tuple(nullptr, 0, "timed out");
|
||||
else
|
||||
return {{packet, header->caplen}, ""};
|
||||
return std::make_tuple(packet, header->caplen, "");
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
|
||||
+14
-13
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, Regents of the University of California,
|
||||
/**
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include "core/common.hpp"
|
||||
|
||||
#ifndef NFD_HAVE_LIBPCAP
|
||||
#ifndef HAVE_LIBPCAP
|
||||
#error "Cannot include this file when libpcap is not available"
|
||||
#endif
|
||||
|
||||
@@ -79,7 +79,7 @@ public:
|
||||
* @sa pcap_close(3pcap)
|
||||
*/
|
||||
void
|
||||
close() noexcept;
|
||||
close();
|
||||
|
||||
/**
|
||||
* @brief Obtain a file descriptor that can be used in calls such as select(2) and poll(2).
|
||||
@@ -98,7 +98,7 @@ public:
|
||||
* @sa pcap_geterr(3pcap)
|
||||
*/
|
||||
std::string
|
||||
getLastError() const noexcept;
|
||||
getLastError() const;
|
||||
|
||||
/**
|
||||
* @brief Get the number of packets dropped by the kernel, as reported by libpcap.
|
||||
@@ -120,17 +120,18 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Read the next packet captured on the interface.
|
||||
* @return If successful, returns a tuple containing a read-only view of the received
|
||||
* packet bytes (including the link-layer header) and a second element that
|
||||
* must be ignored. On failure, returns a tuple containing an empty span and
|
||||
* the reason for the failure.
|
||||
* @warning The returned span is valid only until the next call to this function.
|
||||
* @return If successful, returns a tuple containing a pointer to the received packet
|
||||
* (including the link-layer header) and the size of the packet; the third
|
||||
* element must be ignored. On failure, returns a tuple containing nullptr,
|
||||
* 0, and the reason for the failure.
|
||||
* @warning The returned pointer must not be freed by the caller, and is valid only
|
||||
* until the next call to this function.
|
||||
* @sa pcap_next_ex(3pcap)
|
||||
*/
|
||||
std::tuple<span<const uint8_t>, std::string>
|
||||
readNextPacket() const noexcept;
|
||||
std::tuple<const uint8_t*, size_t, std::string>
|
||||
readNextPacket() const;
|
||||
|
||||
operator pcap_t*() const noexcept
|
||||
operator pcap_t*() const
|
||||
{
|
||||
return m_pcap;
|
||||
}
|
||||
|
||||
@@ -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-2022, 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,7 +43,7 @@ template<class Protocol>
|
||||
class StreamTransport : public Transport
|
||||
{
|
||||
public:
|
||||
using protocol = Protocol;
|
||||
typedef Protocol protocol;
|
||||
|
||||
/** \brief Construct stream transport.
|
||||
*
|
||||
@@ -244,17 +244,16 @@ StreamTransport<T>::handleReceive(const boost::system::error_code& error,
|
||||
NFD_LOG_FACE_TRACE("Received: " << nBytesReceived << " bytes");
|
||||
|
||||
m_receiveBufferSize += nBytesReceived;
|
||||
auto bufferView = ndn::make_span(m_receiveBuffer, m_receiveBufferSize);
|
||||
size_t offset = 0;
|
||||
bool isOk = true;
|
||||
while (offset < bufferView.size()) {
|
||||
while (m_receiveBufferSize - offset > 0) {
|
||||
Block element;
|
||||
std::tie(isOk, element) = Block::fromBuffer(bufferView.subspan(offset));
|
||||
std::tie(isOk, element) = Block::fromBuffer(m_receiveBuffer + offset, m_receiveBufferSize - offset);
|
||||
if (!isOk)
|
||||
break;
|
||||
|
||||
offset += element.size();
|
||||
BOOST_ASSERT(offset <= bufferView.size());
|
||||
BOOST_ASSERT(offset <= m_receiveBufferSize);
|
||||
|
||||
this->receive(element);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, 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,
|
||||
@@ -98,19 +98,10 @@ TcpChannel::connect(const tcp::Endpoint& remoteEndpoint,
|
||||
void
|
||||
TcpChannel::createFace(ip::tcp::socket&& socket,
|
||||
const FaceParams& params,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onFaceCreationFailed)
|
||||
const FaceCreatedCallback& onFaceCreated)
|
||||
{
|
||||
shared_ptr<Face> face;
|
||||
boost::system::error_code ec;
|
||||
tcp::Endpoint remoteEndpoint = socket.remote_endpoint(ec);
|
||||
if (ec) {
|
||||
NFD_LOG_CHAN_DEBUG("Retrieve socket remote endpoint failed: " << ec.message());
|
||||
if (onFaceCreationFailed) {
|
||||
onFaceCreationFailed(500, "Retrieve socket remote endpoint failed: " + ec.message());
|
||||
}
|
||||
return;
|
||||
}
|
||||
tcp::Endpoint remoteEndpoint = socket.remote_endpoint();
|
||||
|
||||
auto it = m_channelFaces.find(remoteEndpoint);
|
||||
if (it == m_channelFaces.end()) {
|
||||
@@ -132,6 +123,9 @@ 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(),
|
||||
@@ -183,7 +177,7 @@ TcpChannel::handleAccept(const boost::system::error_code& error,
|
||||
|
||||
FaceParams params;
|
||||
params.persistency = ndn::nfd::FACE_PERSISTENCY_ON_DEMAND;
|
||||
createFace(std::move(m_socket), params, onFaceCreated, onAcceptFailed);
|
||||
createFace(std::move(m_socket), params, onFaceCreated);
|
||||
|
||||
// prepare accepting the next connection
|
||||
accept(onFaceCreated, onAcceptFailed);
|
||||
@@ -210,7 +204,7 @@ TcpChannel::handleConnect(const boost::system::error_code& error,
|
||||
}
|
||||
|
||||
NFD_LOG_CHAN_TRACE("Connected to " << socket->remote_endpoint());
|
||||
createFace(std::move(*socket), params, onFaceCreated, onConnectFailed);
|
||||
createFace(std::move(*socket), params, onFaceCreated);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, 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,
|
||||
@@ -46,7 +46,7 @@ using DetermineFaceScopeFromAddress = std::function<ndn::nfd::FaceScope(const bo
|
||||
* connections (TcpChannel::listen needs to be called for that
|
||||
* to work) or explicitly after using TcpChannel::connect method.
|
||||
*/
|
||||
class TcpChannel final : public Channel
|
||||
class TcpChannel : public Channel
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -59,13 +59,13 @@ public:
|
||||
DetermineFaceScopeFromAddress determineFaceScope);
|
||||
|
||||
bool
|
||||
isListening() const final
|
||||
isListening() const override
|
||||
{
|
||||
return m_acceptor.is_open();
|
||||
}
|
||||
|
||||
size_t
|
||||
size() const final
|
||||
size() const override
|
||||
{
|
||||
return m_channelFaces.size();
|
||||
}
|
||||
@@ -98,8 +98,7 @@ private:
|
||||
void
|
||||
createFace(boost::asio::ip::tcp::socket&& socket,
|
||||
const FaceParams& params,
|
||||
const FaceCreatedCallback& onFaceCreated,
|
||||
const FaceCreationFailedCallback& onFaceCreationFailed);
|
||||
const FaceCreatedCallback& onFaceCreated);
|
||||
|
||||
void
|
||||
accept(const FaceCreatedCallback& onFaceCreated,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -200,9 +200,8 @@ TcpFactory::createChannel(const tcp::Endpoint& endpoint)
|
||||
if (it != m_channels.end())
|
||||
return it->second;
|
||||
|
||||
auto channel = make_shared<TcpChannel>(endpoint, m_wantCongestionMarking, [this] (auto&&... args) {
|
||||
return determineFaceScopeFromAddresses(std::forward<decltype(args)>(args)...);
|
||||
});
|
||||
auto channel = make_shared<TcpChannel>(endpoint, m_wantCongestionMarking,
|
||||
bind(&TcpFactory::determineFaceScopeFromAddresses, this, _1, _2));
|
||||
m_channels[endpoint] = channel;
|
||||
return channel;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -34,7 +34,7 @@ namespace face {
|
||||
|
||||
/** \brief Protocol factory for TCP over IPv4 and IPv6
|
||||
*/
|
||||
class TcpFactory final : public ProtocolFactory
|
||||
class TcpFactory : public ProtocolFactory
|
||||
{
|
||||
public:
|
||||
static const std::string&
|
||||
@@ -61,15 +61,15 @@ private:
|
||||
*/
|
||||
void
|
||||
doProcessConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context) final;
|
||||
FaceSystem::ConfigContext& context) override;
|
||||
|
||||
void
|
||||
doCreateFace(const CreateFaceRequest& req,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onFailure) final;
|
||||
const FaceCreationFailedCallback& onFailure) override;
|
||||
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
doGetChannels() const final;
|
||||
doGetChannels() const override;
|
||||
|
||||
ndn::nfd::FaceScope
|
||||
determineFaceScopeFromAddresses(const boost::asio::ip::address& local,
|
||||
@@ -79,7 +79,7 @@ private:
|
||||
bool m_wantCongestionMarking = false;
|
||||
std::map<tcp::Endpoint, shared_ptr<TcpChannel>> m_channels;
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
IpAddressPredicate m_local;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -40,7 +40,7 @@ NFD_LOG_MEMBER_DECL_SPECIALIZED(StreamTransport<boost::asio::ip::tcp>);
|
||||
* state is set to DOWN, and the connection is retried periodically with exponential backoff
|
||||
* until it is reestablished
|
||||
*/
|
||||
class TcpTransport NFD_FINAL_UNLESS_WITH_TESTS : public StreamTransport<boost::asio::ip::tcp>
|
||||
class TcpTransport FINAL_UNLESS_WITH_TESTS : public StreamTransport<boost::asio::ip::tcp>
|
||||
{
|
||||
public:
|
||||
TcpTransport(protocol::socket&& socket, ndn::nfd::FacePersistency persistency, ndn::nfd::FaceScope faceScope);
|
||||
@@ -61,17 +61,17 @@ protected:
|
||||
void
|
||||
handleError(const boost::system::error_code& error) final;
|
||||
|
||||
NFD_PROTECTED_WITH_TESTS_ELSE_PRIVATE:
|
||||
NFD_VIRTUAL_WITH_TESTS void
|
||||
PROTECTED_WITH_TESTS_ELSE_PRIVATE:
|
||||
VIRTUAL_WITH_TESTS void
|
||||
reconnect();
|
||||
|
||||
NFD_VIRTUAL_WITH_TESTS void
|
||||
VIRTUAL_WITH_TESTS void
|
||||
handleReconnect(const boost::system::error_code& error);
|
||||
|
||||
NFD_VIRTUAL_WITH_TESTS void
|
||||
VIRTUAL_WITH_TESTS void
|
||||
handleReconnectTimeout();
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
/** \brief how long to wait before the first reconnection attempt after the TCP connection has been severed
|
||||
*/
|
||||
static time::milliseconds s_initialReconnectWait;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, 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,
|
||||
@@ -38,15 +38,13 @@ namespace ip = boost::asio::ip;
|
||||
|
||||
UdpChannel::UdpChannel(const udp::Endpoint& localEndpoint,
|
||||
time::nanoseconds idleTimeout,
|
||||
bool wantCongestionMarking,
|
||||
size_t defaultMtu)
|
||||
bool wantCongestionMarking)
|
||||
: m_localEndpoint(localEndpoint)
|
||||
, m_socket(getGlobalIoService())
|
||||
, m_idleFaceTimeout(idleTimeout)
|
||||
, m_wantCongestionMarking(wantCongestionMarking)
|
||||
{
|
||||
setUri(FaceUri(m_localEndpoint));
|
||||
setDefaultMtu(defaultMtu);
|
||||
NFD_LOG_CHAN_INFO("Creating channel");
|
||||
}
|
||||
|
||||
@@ -124,7 +122,6 @@ UdpChannel::handleNewPeer(const boost::system::error_code& error,
|
||||
try {
|
||||
FaceParams params;
|
||||
params.persistency = ndn::nfd::FACE_PERSISTENCY_ON_DEMAND;
|
||||
params.mtu = getDefaultMtu();
|
||||
std::tie(isCreated, face) = createFace(m_remoteEndpoint, params);
|
||||
}
|
||||
catch (const boost::system::system_error& e) {
|
||||
@@ -141,7 +138,7 @@ UdpChannel::handleNewPeer(const boost::system::error_code& error,
|
||||
|
||||
// dispatch the datagram to the face for processing
|
||||
auto* transport = static_cast<UnicastUdpTransport*>(face->getTransport());
|
||||
transport->receiveDatagram(ndn::make_span(m_receiveBuffer).first(nBytesReceived), error);
|
||||
transport->receiveDatagram(m_receiveBuffer.data(), nBytesReceived, error);
|
||||
|
||||
waitForNewPeer(onFaceCreated, onReceiveFailed);
|
||||
}
|
||||
@@ -183,7 +180,13 @@ UdpChannel::createFace(const udp::Endpoint& remoteEndpoint,
|
||||
options.defaultCongestionThreshold = *params.defaultCongestionThreshold;
|
||||
}
|
||||
|
||||
options.overrideMtu = params.mtu.value_or(getDefaultMtu());
|
||||
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,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -37,7 +37,7 @@ namespace face {
|
||||
/**
|
||||
* \brief Class implementing UDP-based channel to create faces
|
||||
*/
|
||||
class UdpChannel final : public Channel
|
||||
class UdpChannel : public Channel
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -49,17 +49,16 @@ public:
|
||||
*/
|
||||
UdpChannel(const udp::Endpoint& localEndpoint,
|
||||
time::nanoseconds idleTimeout,
|
||||
bool wantCongestionMarking,
|
||||
size_t defaultMtu);
|
||||
bool wantCongestionMarking);
|
||||
|
||||
bool
|
||||
isListening() const final
|
||||
isListening() const override
|
||||
{
|
||||
return m_socket.is_open();
|
||||
}
|
||||
|
||||
size_t
|
||||
size() const final
|
||||
size() const override
|
||||
{
|
||||
return m_channelFaces.size();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -66,7 +66,6 @@ UdpFactory::doProcessConfig(OptionalConfigSection configSection,
|
||||
// enable_v4 yes
|
||||
// enable_v6 yes
|
||||
// idle_timeout 600
|
||||
// unicast_mtu 8800
|
||||
// mcast yes
|
||||
// mcast_group 224.0.23.170
|
||||
// mcast_port 56363
|
||||
@@ -89,7 +88,6 @@ UdpFactory::doProcessConfig(OptionalConfigSection configSection,
|
||||
bool enableV4 = false;
|
||||
bool enableV6 = false;
|
||||
uint32_t idleTimeout = 600;
|
||||
size_t unicastMtu = ndn::MAX_NDN_PACKET_SIZE;
|
||||
MulticastConfig mcastConfig;
|
||||
|
||||
if (configSection) {
|
||||
@@ -115,11 +113,6 @@ UdpFactory::doProcessConfig(OptionalConfigSection configSection,
|
||||
else if (key == "idle_timeout") {
|
||||
idleTimeout = ConfigFile::parseNumber<uint32_t>(pair, "face_system.udp");
|
||||
}
|
||||
else if (key == "unicast_mtu") {
|
||||
unicastMtu = ConfigFile::parseNumber<size_t>(pair, "face_system.udp");
|
||||
ConfigFile::checkRange(unicastMtu, static_cast<size_t>(MIN_MTU), ndn::MAX_NDN_PACKET_SIZE,
|
||||
"unicast_mtu", "face_system.udp");
|
||||
}
|
||||
else if (key == "keep_alive_interval") {
|
||||
// ignored
|
||||
}
|
||||
@@ -184,8 +177,6 @@ UdpFactory::doProcessConfig(OptionalConfigSection configSection,
|
||||
return;
|
||||
}
|
||||
|
||||
m_defaultUnicastMtu = unicastMtu;
|
||||
|
||||
if (enableV4) {
|
||||
udp::Endpoint endpoint(ip::udp::v4(), port);
|
||||
shared_ptr<UdpChannel> v4Channel = this->createChannel(endpoint, time::seconds(idleTimeout));
|
||||
@@ -311,8 +302,7 @@ UdpFactory::createChannel(const udp::Endpoint& localEndpoint,
|
||||
", endpoint already allocated to a UDP multicast face"));
|
||||
}
|
||||
|
||||
auto channel = std::make_shared<UdpChannel>(localEndpoint, idleTimeout,
|
||||
m_wantCongestionMarking, m_defaultUnicastMtu);
|
||||
auto channel = std::make_shared<UdpChannel>(localEndpoint, idleTimeout, m_wantCongestionMarking);
|
||||
m_channels[localEndpoint] = channel;
|
||||
return channel;
|
||||
}
|
||||
@@ -434,7 +424,7 @@ UdpFactory::applyMcastConfigToNetif(const shared_ptr<const net::NetworkInterface
|
||||
NFD_LOG_DEBUG("Not creating multicast faces on " << netif->getName() << ": no viable IP address");
|
||||
// keep an eye on new addresses
|
||||
m_netifConns[netif->getIndex()].addrAddConn =
|
||||
netif->onAddressAdded.connect([=] (auto&&...) { this->applyMcastConfigToNetif(netif); });
|
||||
netif->onAddressAdded.connect([=] (auto...) { this->applyMcastConfigToNetif(netif); });
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -34,7 +34,7 @@ namespace face {
|
||||
|
||||
/** \brief Protocol factory for UDP over IPv4 and IPv6
|
||||
*/
|
||||
class UdpFactory final : public ProtocolFactory
|
||||
class UdpFactory : public ProtocolFactory
|
||||
{
|
||||
public:
|
||||
class Error : public ProtocolFactory::Error
|
||||
@@ -100,15 +100,15 @@ private:
|
||||
*/
|
||||
void
|
||||
doProcessConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context) final;
|
||||
FaceSystem::ConfigContext& context) override;
|
||||
|
||||
void
|
||||
doCreateFace(const CreateFaceRequest& req,
|
||||
const FaceCreatedCallback& onCreated,
|
||||
const FaceCreationFailedCallback& onFailure) final;
|
||||
const FaceCreationFailedCallback& onFailure) override;
|
||||
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
doGetChannels() const final;
|
||||
doGetChannels() const override;
|
||||
|
||||
/** \brief Create UDP multicast faces on \p netif if needed by \p m_mcastConfig
|
||||
* \return list of faces (just created or already existing) on \p netif
|
||||
@@ -123,7 +123,6 @@ private:
|
||||
|
||||
private:
|
||||
bool m_wantCongestionMarking = false;
|
||||
size_t m_defaultUnicastMtu = ndn::MAX_NDN_PACKET_SIZE;
|
||||
std::map<udp::Endpoint, shared_ptr<UdpChannel>> m_channels;
|
||||
|
||||
struct MulticastConfig
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -42,7 +42,7 @@ namespace face {
|
||||
* Channel can create faces as a response to incoming IPC connections
|
||||
* (UnixStreamChannel::listen needs to be called for that to work).
|
||||
*/
|
||||
class UnixStreamChannel final : public Channel
|
||||
class UnixStreamChannel : public Channel
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -66,16 +66,16 @@ public:
|
||||
*/
|
||||
UnixStreamChannel(const unix_stream::Endpoint& endpoint, bool wantCongestionMarking);
|
||||
|
||||
~UnixStreamChannel() final;
|
||||
~UnixStreamChannel() override;
|
||||
|
||||
bool
|
||||
isListening() const final
|
||||
isListening() const override
|
||||
{
|
||||
return m_acceptor.is_open();
|
||||
}
|
||||
|
||||
size_t
|
||||
size() const final
|
||||
size() const override
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -34,7 +34,7 @@ namespace face {
|
||||
|
||||
/** \brief Protocol factory for stream-oriented Unix sockets
|
||||
*/
|
||||
class UnixStreamFactory final : public ProtocolFactory
|
||||
class UnixStreamFactory : public ProtocolFactory
|
||||
{
|
||||
public:
|
||||
static const std::string&
|
||||
@@ -60,10 +60,10 @@ private:
|
||||
*/
|
||||
void
|
||||
doProcessConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context) final;
|
||||
FaceSystem::ConfigContext& context) override;
|
||||
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
doGetChannels() const final;
|
||||
doGetChannels() const override;
|
||||
|
||||
private:
|
||||
bool m_wantCongestionMarking = false;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include "stream-transport.hpp"
|
||||
|
||||
#ifndef NFD_HAVE_UNIX_SOCKETS
|
||||
#ifndef HAVE_UNIX_SOCKETS
|
||||
#error "Cannot include this file when UNIX sockets are not available"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -53,13 +53,13 @@ WebSocketChannel::WebSocketChannel(const websocket::Endpoint& localEndpoint)
|
||||
}
|
||||
return websocketpp::lib::error_code{};
|
||||
});
|
||||
m_server.set_open_handler(std::bind(&WebSocketChannel::handleOpen, this, _1));
|
||||
m_server.set_close_handler(std::bind(&WebSocketChannel::handleClose, this, _1));
|
||||
m_server.set_message_handler(std::bind(&WebSocketChannel::handleMessage, this, _1, _2));
|
||||
m_server.set_open_handler(bind(&WebSocketChannel::handleOpen, this, _1));
|
||||
m_server.set_close_handler(bind(&WebSocketChannel::handleClose, this, _1));
|
||||
m_server.set_message_handler(bind(&WebSocketChannel::handleMessage, this, _1, _2));
|
||||
|
||||
// Detect disconnections using ping-pong messages
|
||||
m_server.set_pong_handler(std::bind(&WebSocketChannel::handlePong, this, _1));
|
||||
m_server.set_pong_timeout_handler(std::bind(&WebSocketChannel::handlePongTimeout, this, _1));
|
||||
m_server.set_pong_handler(bind(&WebSocketChannel::handlePong, this, _1));
|
||||
m_server.set_pong_timeout_handler(bind(&WebSocketChannel::handlePongTimeout, this, _1));
|
||||
|
||||
// Always set SO_REUSEADDR flag
|
||||
m_server.set_reuse_addr(true);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
/**
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -40,7 +40,7 @@ namespace face {
|
||||
/**
|
||||
* \brief Class implementing WebSocket-based channel to create faces
|
||||
*/
|
||||
class WebSocketChannel final : public Channel
|
||||
class WebSocketChannel : public Channel
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -54,13 +54,13 @@ public:
|
||||
WebSocketChannel(const websocket::Endpoint& localEndpoint);
|
||||
|
||||
bool
|
||||
isListening() const final
|
||||
isListening() const override
|
||||
{
|
||||
return m_server.is_listening();
|
||||
}
|
||||
|
||||
size_t
|
||||
size() const final
|
||||
size() const override
|
||||
{
|
||||
return m_channelFaces.size();
|
||||
}
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
void
|
||||
listen(const FaceCreatedCallback& onFaceCreated);
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
/** \pre listen hasn't been invoked
|
||||
*/
|
||||
void
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -34,7 +34,7 @@ namespace face {
|
||||
|
||||
/** \brief Protocol factory for WebSocket
|
||||
*/
|
||||
class WebSocketFactory final : public ProtocolFactory
|
||||
class WebSocketFactory : public ProtocolFactory
|
||||
{
|
||||
public:
|
||||
static const std::string&
|
||||
@@ -62,10 +62,10 @@ private:
|
||||
*/
|
||||
void
|
||||
doProcessConfig(OptionalConfigSection configSection,
|
||||
FaceSystem::ConfigContext& context) final;
|
||||
FaceSystem::ConfigContext& context) override;
|
||||
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
doGetChannels() const final;
|
||||
doGetChannels() const override;
|
||||
|
||||
private:
|
||||
std::map<websocket::Endpoint, shared_ptr<WebSocketChannel>> m_channels;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2022, 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,
|
||||
@@ -98,7 +98,7 @@ WebSocketTransport::receiveMessage(const std::string& msg)
|
||||
|
||||
bool isOk = false;
|
||||
Block element;
|
||||
std::tie(isOk, element) = Block::fromBuffer({reinterpret_cast<const uint8_t*>(msg.data()), msg.size()});
|
||||
std::tie(isOk, element) = Block::fromBuffer(reinterpret_cast<const uint8_t*>(msg.data()), msg.size());
|
||||
if (!isOk) {
|
||||
NFD_LOG_FACE_WARN("Failed to parse message payload");
|
||||
return;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -26,11 +26,9 @@
|
||||
#ifndef NFD_DAEMON_FACE_WEBSOCKETPP_HPP
|
||||
#define NFD_DAEMON_FACE_WEBSOCKETPP_HPP
|
||||
|
||||
#include "core/config.hpp"
|
||||
|
||||
#ifndef NFD_HAVE_WEBSOCKET
|
||||
#ifndef HAVE_WEBSOCKET
|
||||
#error "Cannot include this file when WebSocket support is disabled"
|
||||
#endif
|
||||
#endif // HAVE_WEBSOCKET
|
||||
|
||||
// suppress websocketpp warnings
|
||||
#pragma GCC system_header
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,20 +52,20 @@ AccessStrategy::AccessStrategy(Forwarder& forwarder, const Name& name)
|
||||
const Name&
|
||||
AccessStrategy::getStrategyName()
|
||||
{
|
||||
static const auto strategyName = Name("/localhost/nfd/strategy/access").appendVersion(1);
|
||||
static Name strategyName("/localhost/nfd/strategy/access/%FD%01");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
void
|
||||
AccessStrategy::afterReceiveInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
AccessStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
auto suppressResult = m_retxSuppression.decidePerPitEntry(*pitEntry);
|
||||
switch (suppressResult) {
|
||||
case RetxSuppressionResult::NEW:
|
||||
return afterReceiveNewInterest(interest, ingress, pitEntry);
|
||||
return afterReceiveNewInterest(ingress, interest, pitEntry);
|
||||
case RetxSuppressionResult::FORWARD:
|
||||
return afterReceiveRetxInterest(interest, ingress, pitEntry);
|
||||
return afterReceiveRetxInterest(ingress, interest, pitEntry);
|
||||
case RetxSuppressionResult::SUPPRESS:
|
||||
NFD_LOG_DEBUG(interest << " interestFrom " << ingress << " retx-suppress");
|
||||
return;
|
||||
@@ -73,7 +73,7 @@ AccessStrategy::afterReceiveInterest(const Interest& interest, const FaceEndpoin
|
||||
}
|
||||
|
||||
void
|
||||
AccessStrategy::afterReceiveNewInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
AccessStrategy::afterReceiveNewInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
const auto& fibEntry = this->lookupFib(*pitEntry);
|
||||
@@ -86,7 +86,7 @@ AccessStrategy::afterReceiveNewInterest(const Interest& interest, const FaceEndp
|
||||
NFD_LOG_DEBUG(interest << " interestFrom " << ingress << " new-interest mi=" << miName);
|
||||
|
||||
// send to last working nexthop
|
||||
bool isSentToLastNexthop = this->sendToLastNexthop(interest, ingress, pitEntry, *mi, fibEntry);
|
||||
bool isSentToLastNexthop = this->sendToLastNexthop(ingress, interest, pitEntry, *mi, fibEntry);
|
||||
if (isSentToLastNexthop) {
|
||||
return;
|
||||
}
|
||||
@@ -98,7 +98,7 @@ AccessStrategy::afterReceiveNewInterest(const Interest& interest, const FaceEndp
|
||||
// no measurements, or last working nexthop unavailable
|
||||
|
||||
// multicast to all nexthops except incoming face
|
||||
size_t nMulticastSent = this->multicast(interest, ingress.face, pitEntry, fibEntry);
|
||||
size_t nMulticastSent = this->multicast(ingress.face, interest, pitEntry, fibEntry);
|
||||
|
||||
if (nMulticastSent == 0) {
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
@@ -106,16 +106,16 @@ AccessStrategy::afterReceiveNewInterest(const Interest& interest, const FaceEndp
|
||||
}
|
||||
|
||||
void
|
||||
AccessStrategy::afterReceiveRetxInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
AccessStrategy::afterReceiveRetxInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
const auto& fibEntry = this->lookupFib(*pitEntry);
|
||||
NFD_LOG_DEBUG(interest << " interestFrom " << ingress << " retx-forward");
|
||||
this->multicast(interest, ingress.face, pitEntry, fibEntry);
|
||||
this->multicast(ingress.face, interest, pitEntry, fibEntry);
|
||||
}
|
||||
|
||||
bool
|
||||
AccessStrategy::sendToLastNexthop(const Interest& interest, const FaceEndpoint& ingress,
|
||||
AccessStrategy::sendToLastNexthop(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry, MtInfo& mi,
|
||||
const fib::Entry& fibEntry)
|
||||
{
|
||||
@@ -144,7 +144,7 @@ AccessStrategy::sendToLastNexthop(const Interest& interest, const FaceEndpoint&
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " interestTo " << mi.lastNexthop
|
||||
<< " last-nexthop rto=" << time::duration_cast<time::microseconds>(rto).count());
|
||||
|
||||
if (!this->sendInterest(interest, *outFace, pitEntry)) {
|
||||
if (!this->sendInterest(pitEntry, *outFace, interest)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -184,11 +184,11 @@ AccessStrategy::afterRtoTimeout(const weak_ptr<pit::Entry>& pitWeak,
|
||||
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " timeoutFrom " << firstOutFaceId
|
||||
<< " multicast-except " << firstOutFaceId);
|
||||
this->multicast(interest, *inFace, pitEntry, fibEntry, firstOutFaceId);
|
||||
this->multicast(*inFace, interest, pitEntry, fibEntry, firstOutFaceId);
|
||||
}
|
||||
|
||||
size_t
|
||||
AccessStrategy::multicast(const Interest& interest, const Face& inFace,
|
||||
AccessStrategy::multicast(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry, const fib::Entry& fibEntry,
|
||||
FaceId exceptFace)
|
||||
{
|
||||
@@ -200,7 +200,7 @@ AccessStrategy::multicast(const Interest& interest, const Face& inFace,
|
||||
continue;
|
||||
}
|
||||
NFD_LOG_DEBUG(pitEntry->getInterest() << " interestTo " << outFace.getId() << " multicast");
|
||||
if (this->sendInterest(interest, outFace, pitEntry)) {
|
||||
if (this->sendInterest(pitEntry, outFace, interest)) {
|
||||
++nSent;
|
||||
}
|
||||
}
|
||||
@@ -208,8 +208,8 @@ AccessStrategy::multicast(const Interest& interest, const Face& inFace,
|
||||
}
|
||||
|
||||
void
|
||||
AccessStrategy::beforeSatisfyInterest(const Data& data, const FaceEndpoint& ingress,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
AccessStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const FaceEndpoint& ingress, const Data& data)
|
||||
{
|
||||
PitInfo* pi = pitEntry->getStrategyInfo<PitInfo>();
|
||||
if (pi != nullptr) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -34,7 +34,7 @@
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
/** \brief Access Router strategy
|
||||
/** \brief Access Router Strategy version 1
|
||||
*
|
||||
* This strategy is designed for the last hop on the NDN testbed,
|
||||
* where each nexthop connects to a laptop, links are lossy, and FIB is mostly correct.
|
||||
@@ -56,19 +56,19 @@ public:
|
||||
|
||||
public: // triggers
|
||||
void
|
||||
afterReceiveInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
void
|
||||
beforeSatisfyInterest(const Data& data, const FaceEndpoint& ingress,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const FaceEndpoint& ingress, const Data& data) override;
|
||||
|
||||
private: // StrategyInfo
|
||||
using RttEstimator = ndn::util::RttEstimator;
|
||||
|
||||
/** \brief StrategyInfo on PIT entry
|
||||
*/
|
||||
class PitInfo final : public StrategyInfo
|
||||
class PitInfo : public StrategyInfo
|
||||
{
|
||||
public:
|
||||
static constexpr int
|
||||
@@ -83,7 +83,7 @@ private: // StrategyInfo
|
||||
|
||||
/** \brief StrategyInfo in measurements table
|
||||
*/
|
||||
class MtInfo final : public StrategyInfo
|
||||
class MtInfo : public StrategyInfo
|
||||
{
|
||||
public:
|
||||
static constexpr int
|
||||
@@ -133,18 +133,18 @@ private: // StrategyInfo
|
||||
|
||||
private: // forwarding procedures
|
||||
void
|
||||
afterReceiveNewInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
afterReceiveNewInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry);
|
||||
|
||||
void
|
||||
afterReceiveRetxInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
afterReceiveRetxInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry);
|
||||
|
||||
/** \brief send to last working nexthop
|
||||
* \return whether an Interest is sent
|
||||
*/
|
||||
bool
|
||||
sendToLastNexthop(const Interest& interest, const FaceEndpoint& ingress,
|
||||
sendToLastNexthop(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry, MtInfo& mi,
|
||||
const fib::Entry& fibEntry);
|
||||
|
||||
@@ -157,7 +157,7 @@ private: // forwarding procedures
|
||||
* \return number of Interests that were sent
|
||||
*/
|
||||
size_t
|
||||
multicast(const Interest& interest, const Face& inFace,
|
||||
multicast(const Face& inFace, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry, const fib::Entry& fibEntry,
|
||||
FaceId exceptFace = face::INVALID_FACEID);
|
||||
|
||||
|
||||
+29
-6
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,6 @@
|
||||
*/
|
||||
|
||||
#include "algorithm.hpp"
|
||||
#include "scope-prefix.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
@@ -51,6 +50,30 @@ wouldViolateScope(const Face& inFace, const Interest& interest, const Face& outF
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
canForwardToLegacy(const pit::Entry& pitEntry, const Face& face)
|
||||
{
|
||||
time::steady_clock::TimePoint now = time::steady_clock::now();
|
||||
|
||||
bool hasUnexpiredOutRecord = std::any_of(pitEntry.out_begin(), pitEntry.out_end(),
|
||||
[&face, &now] (const pit::OutRecord& outRecord) {
|
||||
return &outRecord.getFace() == &face && outRecord.getExpiry() >= now;
|
||||
});
|
||||
if (hasUnexpiredOutRecord) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasUnexpiredOtherInRecord = std::any_of(pitEntry.in_begin(), pitEntry.in_end(),
|
||||
[&face, &now] (const pit::InRecord& inRecord) {
|
||||
return &inRecord.getFace() != &face && inRecord.getExpiry() >= now;
|
||||
});
|
||||
if (!hasUnexpiredOtherInRecord) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
findDuplicateNonce(const pit::Entry& pitEntry, Interest::Nonce nonce, const Face& face)
|
||||
{
|
||||
@@ -84,7 +107,7 @@ findDuplicateNonce(const pit::Entry& pitEntry, Interest::Nonce nonce, const Face
|
||||
bool
|
||||
hasPendingOutRecords(const pit::Entry& pitEntry)
|
||||
{
|
||||
auto now = time::steady_clock::now();
|
||||
time::steady_clock::TimePoint now = time::steady_clock::now();
|
||||
return std::any_of(pitEntry.out_begin(), pitEntry.out_end(),
|
||||
[&now] (const pit::OutRecord& outRecord) {
|
||||
return outRecord.getExpiry() >= now &&
|
||||
@@ -92,7 +115,7 @@ hasPendingOutRecords(const pit::Entry& pitEntry)
|
||||
});
|
||||
}
|
||||
|
||||
time::steady_clock::time_point
|
||||
time::steady_clock::TimePoint
|
||||
getLastOutgoing(const pit::Entry& pitEntry)
|
||||
{
|
||||
pit::OutRecordCollection::const_iterator lastOutgoing = std::max_element(
|
||||
@@ -111,7 +134,7 @@ findEligibleNextHopWithEarliestOutRecord(const Face& inFace, const Interest& int
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
auto found = nexthops.end();
|
||||
auto earliestRenewed = time::steady_clock::time_point::max();
|
||||
auto earliestRenewed = time::steady_clock::TimePoint::max();
|
||||
|
||||
for (auto it = nexthops.begin(); it != nexthops.end(); ++it) {
|
||||
if (!isNextHopEligible(inFace, interest, *it, pitEntry))
|
||||
@@ -132,7 +155,7 @@ isNextHopEligible(const Face& inFace, const Interest& interest,
|
||||
const fib::NextHop& nexthop,
|
||||
const shared_ptr<pit::Entry>& pitEntry,
|
||||
bool wantUnused,
|
||||
time::steady_clock::time_point now)
|
||||
time::steady_clock::TimePoint now)
|
||||
{
|
||||
const Face& outFace = nexthop.getFace();
|
||||
|
||||
|
||||
+17
-3
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,7 +26,8 @@
|
||||
#ifndef NFD_DAEMON_FW_ALGORITHM_HPP
|
||||
#define NFD_DAEMON_FW_ALGORITHM_HPP
|
||||
|
||||
#include "table/fib-entry.hpp"
|
||||
#include "fw/scope-prefix.hpp"
|
||||
#include "table/fib.hpp"
|
||||
#include "table/pit-entry.hpp"
|
||||
|
||||
/** \file
|
||||
@@ -42,6 +43,19 @@ namespace fw {
|
||||
bool
|
||||
wouldViolateScope(const Face& inFace, const Interest& interest, const Face& outFace);
|
||||
|
||||
/** \brief decide whether Interest can be forwarded to face
|
||||
*
|
||||
* \return true if out-record of this face does not exist or has expired,
|
||||
* and there is an in-record not of this face
|
||||
*
|
||||
* \note This algorithm has a weakness that it does not permit consumer retransmissions
|
||||
* before out-record expires. Therefore, it's not recommended to use this function
|
||||
* in new strategies.
|
||||
* \todo find a better name for this function
|
||||
*/
|
||||
bool
|
||||
canForwardToLegacy(const pit::Entry& pitEntry, const Face& face);
|
||||
|
||||
/** \brief indicates where duplicate Nonces are found
|
||||
*/
|
||||
enum DuplicateNonceWhere {
|
||||
@@ -49,7 +63,7 @@ enum DuplicateNonceWhere {
|
||||
DUPLICATE_NONCE_IN_SAME = (1 << 0), ///< in-record of same face
|
||||
DUPLICATE_NONCE_IN_OTHER = (1 << 1), ///< in-record of other face
|
||||
DUPLICATE_NONCE_OUT_SAME = (1 << 2), ///< out-record of same face
|
||||
DUPLICATE_NONCE_OUT_OTHER = (1 << 3), ///< out-record of other face
|
||||
DUPLICATE_NONCE_OUT_OTHER = (1 << 3) ///< out-record of other face
|
||||
};
|
||||
|
||||
/** \brief determine whether \p pitEntry has duplicate Nonce \p nonce
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -92,21 +92,22 @@ AsfMeasurements::AsfMeasurements(MeasurementsAccessor& measurements)
|
||||
}
|
||||
|
||||
FaceInfo*
|
||||
AsfMeasurements::getFaceInfo(const fib::Entry& fibEntry, const Name& interestName, FaceId faceId)
|
||||
AsfMeasurements::getFaceInfo(const fib::Entry& fibEntry, const Interest& interest, FaceId faceId)
|
||||
{
|
||||
return getOrCreateNamespaceInfo(fibEntry, interestName).getFaceInfo(faceId);
|
||||
return getOrCreateNamespaceInfo(fibEntry, interest).getFaceInfo(faceId);
|
||||
}
|
||||
|
||||
FaceInfo&
|
||||
AsfMeasurements::getOrCreateFaceInfo(const fib::Entry& fibEntry, const Name& interestName, FaceId faceId)
|
||||
AsfMeasurements::getOrCreateFaceInfo(const fib::Entry& fibEntry, const Interest& interest,
|
||||
FaceId faceId)
|
||||
{
|
||||
return getOrCreateNamespaceInfo(fibEntry, interestName).getOrCreateFaceInfo(faceId);
|
||||
return getOrCreateNamespaceInfo(fibEntry, interest).getOrCreateFaceInfo(faceId);
|
||||
}
|
||||
|
||||
NamespaceInfo*
|
||||
AsfMeasurements::getNamespaceInfo(const Name& prefix)
|
||||
{
|
||||
auto* me = m_measurements.findLongestPrefixMatch(prefix);
|
||||
measurements::Entry* me = m_measurements.findLongestPrefixMatch(prefix);
|
||||
if (me == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -120,16 +121,15 @@ AsfMeasurements::getNamespaceInfo(const Name& prefix)
|
||||
}
|
||||
|
||||
NamespaceInfo&
|
||||
AsfMeasurements::getOrCreateNamespaceInfo(const fib::Entry& fibEntry, const Name& prefix)
|
||||
AsfMeasurements::getOrCreateNamespaceInfo(const fib::Entry& fibEntry, const Interest& interest)
|
||||
{
|
||||
auto* me = m_measurements.get(fibEntry);
|
||||
measurements::Entry* me = m_measurements.get(fibEntry);
|
||||
|
||||
// If the FIB entry is not under the strategy's namespace, find a part of the prefix
|
||||
// that falls under the strategy's namespace
|
||||
for (size_t prefixLen = fibEntry.getPrefix().size() + 1;
|
||||
me == nullptr && prefixLen <= prefix.size();
|
||||
++prefixLen) {
|
||||
me = m_measurements.get(prefix.getPrefix(prefixLen));
|
||||
me == nullptr && prefixLen <= interest.getName().size(); ++prefixLen) {
|
||||
me = m_measurements.get(interest.getName().getPrefix(prefixLen));
|
||||
}
|
||||
|
||||
// Either the FIB entry or the Interest's name must be under this strategy's namespace
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -91,15 +91,15 @@ public:
|
||||
}
|
||||
|
||||
size_t
|
||||
getNTimeouts() const
|
||||
getNSilentTimeouts() const
|
||||
{
|
||||
return m_nTimeouts;
|
||||
return m_nSilentTimeouts;
|
||||
}
|
||||
|
||||
void
|
||||
setNTimeouts(size_t nTimeouts)
|
||||
setNSilentTimeouts(size_t nSilentTimeouts)
|
||||
{
|
||||
m_nTimeouts = nTimeouts;
|
||||
m_nSilentTimeouts = nSilentTimeouts;
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -110,7 +110,7 @@ private:
|
||||
ndn::util::RttEstimator m_rttEstimator;
|
||||
time::nanoseconds m_lastRtt = RTT_NO_MEASUREMENT;
|
||||
Name m_lastInterestName;
|
||||
size_t m_nTimeouts = 0;
|
||||
size_t m_nSilentTimeouts = 0;
|
||||
|
||||
// Timeout associated with measurement
|
||||
scheduler::ScopedEventId m_measurementExpiration;
|
||||
@@ -125,7 +125,7 @@ private:
|
||||
|
||||
/** \brief Stores strategy information about each face in this namespace
|
||||
*/
|
||||
class NamespaceInfo final : public StrategyInfo
|
||||
class NamespaceInfo : public StrategyInfo
|
||||
{
|
||||
public:
|
||||
static constexpr int
|
||||
@@ -192,16 +192,16 @@ public:
|
||||
AsfMeasurements(MeasurementsAccessor& measurements);
|
||||
|
||||
FaceInfo*
|
||||
getFaceInfo(const fib::Entry& fibEntry, const Name& interestName, FaceId faceId);
|
||||
getFaceInfo(const fib::Entry& fibEntry, const Interest& interest, FaceId faceId);
|
||||
|
||||
FaceInfo&
|
||||
getOrCreateFaceInfo(const fib::Entry& fibEntry, const Name& interestName, FaceId faceId);
|
||||
getOrCreateFaceInfo(const fib::Entry& fibEntry, const Interest& interest, FaceId faceId);
|
||||
|
||||
NamespaceInfo*
|
||||
getNamespaceInfo(const Name& prefix);
|
||||
|
||||
NamespaceInfo&
|
||||
getOrCreateNamespaceInfo(const fib::Entry& fibEntry, const Name& prefix);
|
||||
getOrCreateNamespaceInfo(const fib::Entry& fibEntry, const Interest& interest);
|
||||
|
||||
private:
|
||||
void
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -81,7 +81,7 @@ ProbingModule::getFaceToProbe(const Face& inFace, const Interest& interest,
|
||||
continue;
|
||||
}
|
||||
|
||||
FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest.getName(), hopFace.getId());
|
||||
FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, hopFace.getId());
|
||||
// If no RTT has been recorded, probe this face
|
||||
if (info == nullptr || info->getLastRtt() == FaceInfo::RTT_NO_MEASUREMENT) {
|
||||
return &hopFace;
|
||||
@@ -100,10 +100,10 @@ ProbingModule::getFaceToProbe(const Face& inFace, const Interest& interest,
|
||||
}
|
||||
|
||||
bool
|
||||
ProbingModule::isProbingNeeded(const fib::Entry& fibEntry, const Name& interestName)
|
||||
ProbingModule::isProbingNeeded(const fib::Entry& fibEntry, const Interest& interest)
|
||||
{
|
||||
// Return the probing status flag for a namespace
|
||||
NamespaceInfo& info = m_measurements.getOrCreateNamespaceInfo(fibEntry, interestName);
|
||||
NamespaceInfo& info = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
|
||||
|
||||
// If a first probe has not been scheduled for a namespace
|
||||
if (!info.isFirstProbeScheduled()) {
|
||||
@@ -118,11 +118,11 @@ ProbingModule::isProbingNeeded(const fib::Entry& fibEntry, const Name& interestN
|
||||
}
|
||||
|
||||
void
|
||||
ProbingModule::afterForwardingProbe(const fib::Entry& fibEntry, const Name& interestName)
|
||||
ProbingModule::afterForwardingProbe(const fib::Entry& fibEntry, const Interest& interest)
|
||||
{
|
||||
// After probing is done, need to set probing flag to false and
|
||||
// schedule another future probe
|
||||
NamespaceInfo& info = m_measurements.getOrCreateNamespaceInfo(fibEntry, interestName);
|
||||
NamespaceInfo& info = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
|
||||
info.setIsProbingDue(false);
|
||||
|
||||
scheduleProbe(fibEntry, m_probingInterval);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -48,10 +48,10 @@ public:
|
||||
const fib::Entry& fibEntry, const Face& faceUsed);
|
||||
|
||||
bool
|
||||
isProbingNeeded(const fib::Entry& fibEntry, const Name& interestName);
|
||||
isProbingNeeded(const fib::Entry& fibEntry, const Interest& interest);
|
||||
|
||||
void
|
||||
afterForwardingProbe(const fib::Entry& fibEntry, const Name& interestName);
|
||||
afterForwardingProbe(const fib::Entry& fibEntry, const Interest& interest);
|
||||
|
||||
void
|
||||
setProbingInterval(size_t probingInterval);
|
||||
|
||||
+73
-82
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,13 +58,13 @@ AsfStrategy::AsfStrategy(Forwarder& forwarder, const Name& name)
|
||||
this->setInstanceName(makeInstanceName(name, getStrategyName()));
|
||||
|
||||
NFD_LOG_DEBUG("probing-interval=" << m_probing.getProbingInterval()
|
||||
<< " max-timeouts=" << m_nMaxTimeouts);
|
||||
<< " n-silent-timeouts=" << m_nMaxSilentTimeouts);
|
||||
}
|
||||
|
||||
const Name&
|
||||
AsfStrategy::getStrategyName()
|
||||
{
|
||||
static const auto strategyName = Name("/localhost/nfd/strategy/asf").appendVersion(4);
|
||||
static Name strategyName("/localhost/nfd/strategy/asf/%FD%03");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
@@ -97,86 +97,75 @@ AsfStrategy::processParams(const PartialName& parsed)
|
||||
if (f == "probing-interval") {
|
||||
m_probing.setProbingInterval(getParamValue(f, s));
|
||||
}
|
||||
else if (f == "max-timeouts") {
|
||||
m_nMaxTimeouts = getParamValue(f, s);
|
||||
if (m_nMaxTimeouts <= 0)
|
||||
NDN_THROW(std::invalid_argument("max-timeouts should be greater than 0"));
|
||||
else if (f == "n-silent-timeouts") {
|
||||
m_nMaxSilentTimeouts = getParamValue(f, s);
|
||||
}
|
||||
else {
|
||||
NDN_THROW(std::invalid_argument("Parameter should be probing-interval or max-timeouts"));
|
||||
NDN_THROW(std::invalid_argument("Parameter should be probing-interval or n-silent-timeouts"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsfStrategy::afterReceiveInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
AsfStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
const auto& fibEntry = this->lookupFib(*pitEntry);
|
||||
// Should the Interest be suppressed?
|
||||
auto suppressResult = m_retxSuppression.decidePerPitEntry(*pitEntry);
|
||||
if (suppressResult == RetxSuppressionResult::SUPPRESS) {
|
||||
NFD_LOG_DEBUG(interest << " retx-interest from=" << ingress << " suppressed");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the interest is new and, if so, skip the retx suppression check
|
||||
if (!hasPendingOutRecords(*pitEntry)) {
|
||||
auto* faceToUse = getBestFaceForForwarding(interest, ingress.face, fibEntry, pitEntry);
|
||||
if (faceToUse == nullptr) {
|
||||
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
|
||||
const fib::NextHopList& nexthops = fibEntry.getNextHops();
|
||||
|
||||
if (suppressResult == RetxSuppressionResult::NEW) {
|
||||
if (nexthops.size() == 0) {
|
||||
NFD_LOG_DEBUG(interest << " new-interest from=" << ingress << " no-nexthop");
|
||||
sendNoRouteNack(ingress.face, pitEntry);
|
||||
return;
|
||||
}
|
||||
|
||||
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 necessary, send probe
|
||||
sendProbe(interest, ingress, *faceToUse, fibEntry, pitEntry);
|
||||
}
|
||||
else {
|
||||
NFD_LOG_DEBUG(interest << " new-interest from=" << ingress << " no-nexthop");
|
||||
sendNoRouteNack(ingress.face, pitEntry);
|
||||
}
|
||||
else {
|
||||
NFD_LOG_DEBUG(interest << " new-interest from=" << ingress << " forward-to=" << faceToUse->getId());
|
||||
forwardInterest(interest, *faceToUse, fibEntry, pitEntry);
|
||||
sendProbe(interest, ingress, *faceToUse, fibEntry, pitEntry);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto* faceToUse = getBestFaceForForwarding(interest, ingress.face, fibEntry, 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) {
|
||||
auto suppressResult = m_retxSuppression.decidePerUpstream(*pitEntry, *faceToUse);
|
||||
if (suppressResult == RetxSuppressionResult::SUPPRESS) {
|
||||
// Cannot be sent on this face, interest was received within the suppression window
|
||||
NFD_LOG_DEBUG(interest << " retx-interest from=" << ingress
|
||||
<< " forward-to=" << faceToUse->getId() << " suppressed");
|
||||
}
|
||||
else {
|
||||
// The retx arrived after the suppression period: forward it but don't probe, because
|
||||
// probing was done earlier for this interest when it was newly received
|
||||
NFD_LOG_DEBUG(interest << " retx-interest from=" << ingress << " forward-to=" << faceToUse->getId());
|
||||
auto* outRecord = forwardInterest(interest, *faceToUse, fibEntry, pitEntry);
|
||||
if (outRecord && suppressResult == RetxSuppressionResult::FORWARD) {
|
||||
m_retxSuppression.incrementIntervalForOutRecord(*outRecord);
|
||||
}
|
||||
}
|
||||
NFD_LOG_DEBUG(interest << " retx-interest from=" << ingress << " forward-to=" << faceToUse->getId());
|
||||
forwardInterest(interest, *faceToUse, fibEntry, pitEntry);
|
||||
// avoid probing in case of forwarding
|
||||
return;
|
||||
}
|
||||
|
||||
// If all eligible faces have been used (i.e., they all have a pending out-record),
|
||||
// choose the nexthop with the earliest out-record
|
||||
const auto& nexthops = fibEntry.getNextHops();
|
||||
auto it = findEligibleNextHopWithEarliestOutRecord(ingress.face, interest, nexthops, pitEntry);
|
||||
// find an eligible upstream that is used earliest
|
||||
auto it = nexthops.end();
|
||||
it = findEligibleNextHopWithEarliestOutRecord(ingress.face, interest, nexthops, pitEntry);
|
||||
if (it == nexthops.end()) {
|
||||
NFD_LOG_DEBUG(interest << " retx-interest from=" << ingress << " no eligible nexthop");
|
||||
return;
|
||||
}
|
||||
auto& outFace = it->getFace();
|
||||
auto suppressResult = m_retxSuppression.decidePerUpstream(*pitEntry, outFace);
|
||||
if (suppressResult == RetxSuppressionResult::SUPPRESS) {
|
||||
NFD_LOG_DEBUG(interest << " retx-interest from=" << ingress
|
||||
<< " retry-to=" << outFace.getId() << " suppressed");
|
||||
NFD_LOG_DEBUG(interest << " retx-interest from=" << ingress << " no-nexthop");
|
||||
}
|
||||
else {
|
||||
NFD_LOG_DEBUG(interest << " retx-interest from=" << ingress << " retry-to=" << outFace.getId());
|
||||
// sendInterest() is used here instead of forwardInterest() because the measurements info
|
||||
// were already attached to this face in the previous forwarding
|
||||
auto* outRecord = sendInterest(interest, outFace, pitEntry);
|
||||
if (outRecord && suppressResult == RetxSuppressionResult::FORWARD) {
|
||||
m_retxSuppression.incrementIntervalForOutRecord(*outRecord);
|
||||
}
|
||||
NFD_LOG_DEBUG(interest << " retx-interest from=" << ingress << " retry-to=" << it->getFace().getId());
|
||||
this->sendInterest(pitEntry, it->getFace(), interest);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsfStrategy::beforeSatisfyInterest(const Data& data, const FaceEndpoint& ingress,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
AsfStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const FaceEndpoint& ingress, const Data& data)
|
||||
{
|
||||
NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(pitEntry->getName());
|
||||
if (namespaceInfo == nullptr) {
|
||||
@@ -209,57 +198,59 @@ AsfStrategy::beforeSatisfyInterest(const Data& data, const FaceEndpoint& ingress
|
||||
}
|
||||
|
||||
void
|
||||
AsfStrategy::afterReceiveNack(const lp::Nack& nack, const FaceEndpoint& ingress,
|
||||
AsfStrategy::afterReceiveNack(const FaceEndpoint& ingress, const lp::Nack& nack,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
NFD_LOG_DEBUG(nack.getInterest() << " nack from=" << ingress << " reason=" << nack.getReason());
|
||||
onTimeoutOrNack(pitEntry->getName(), ingress.face.getId(), true);
|
||||
}
|
||||
|
||||
pit::OutRecord*
|
||||
void
|
||||
AsfStrategy::forwardInterest(const Interest& interest, Face& outFace, const fib::Entry& fibEntry,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
const shared_ptr<pit::Entry>& pitEntry, bool wantNewNonce)
|
||||
{
|
||||
const auto& interestName = interest.getName();
|
||||
auto faceId = outFace.getId();
|
||||
|
||||
auto* outRecord = sendInterest(interest, outFace, pitEntry);
|
||||
if (wantNewNonce) {
|
||||
// Send probe: interest with new Nonce
|
||||
Interest probeInterest(interest);
|
||||
probeInterest.refreshNonce();
|
||||
NFD_LOG_TRACE("Sending probe for " << probeInterest << " to=" << faceId);
|
||||
this->sendInterest(pitEntry, outFace, probeInterest);
|
||||
}
|
||||
else {
|
||||
this->sendInterest(pitEntry, outFace, interest);
|
||||
}
|
||||
|
||||
FaceInfo& faceInfo = m_measurements.getOrCreateFaceInfo(fibEntry, interestName, faceId);
|
||||
FaceInfo& faceInfo = m_measurements.getOrCreateFaceInfo(fibEntry, interest, faceId);
|
||||
|
||||
// Refresh measurements since Face is being used for forwarding
|
||||
NamespaceInfo& namespaceInfo = m_measurements.getOrCreateNamespaceInfo(fibEntry, interestName);
|
||||
NamespaceInfo& namespaceInfo = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
|
||||
namespaceInfo.extendFaceInfoLifetime(faceInfo, faceId);
|
||||
|
||||
if (!faceInfo.isTimeoutScheduled()) {
|
||||
auto timeout = faceInfo.scheduleTimeout(interestName,
|
||||
[this, name = interestName, faceId] {
|
||||
onTimeoutOrNack(name, faceId, false);
|
||||
});
|
||||
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));
|
||||
<< " in " << time::duration_cast<time::milliseconds>(timeout) << " ms");
|
||||
}
|
||||
|
||||
return outRecord;
|
||||
}
|
||||
|
||||
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.getName()))
|
||||
if (!m_probing.isProbingNeeded(fibEntry, interest))
|
||||
return;
|
||||
|
||||
Face* faceToProbe = m_probing.getFaceToProbe(ingress.face, interest, fibEntry, faceToUse);
|
||||
if (faceToProbe == nullptr)
|
||||
return;
|
||||
|
||||
Interest probeInterest(interest);
|
||||
probeInterest.refreshNonce();
|
||||
NFD_LOG_TRACE("Sending probe " << probeInterest << " to=" << faceToProbe->getId());
|
||||
forwardInterest(probeInterest, *faceToProbe, fibEntry, pitEntry);
|
||||
|
||||
m_probing.afterForwardingProbe(fibEntry, interest.getName());
|
||||
forwardInterest(interest, *faceToProbe, fibEntry, pitEntry, true);
|
||||
m_probing.afterForwardingProbe(fibEntry, interest);
|
||||
}
|
||||
|
||||
struct FaceStats
|
||||
@@ -313,7 +304,7 @@ AsfStrategy::getBestFaceForForwarding(const Interest& interest, const Face& inFa
|
||||
continue;
|
||||
}
|
||||
|
||||
const FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest.getName(), nh.getFace().getId());
|
||||
FaceInfo* info = m_measurements.getFaceInfo(fibEntry, interest, nh.getFace().getId());
|
||||
if (info == nullptr) {
|
||||
rankedFaces.insert({&nh.getFace(), FaceInfo::RTT_NO_MEASUREMENT,
|
||||
FaceInfo::RTT_NO_MEASUREMENT, nh.getCost()});
|
||||
@@ -343,10 +334,10 @@ AsfStrategy::onTimeoutOrNack(const Name& interestName, FaceId faceId, bool isNac
|
||||
}
|
||||
|
||||
auto& faceInfo = *fiPtr;
|
||||
size_t nTimeouts = faceInfo.getNTimeouts() + 1;
|
||||
faceInfo.setNTimeouts(nTimeouts);
|
||||
size_t nTimeouts = faceInfo.getNSilentTimeouts() + 1;
|
||||
faceInfo.setNSilentTimeouts(nTimeouts);
|
||||
|
||||
if (nTimeouts < m_nMaxTimeouts && !isNack) {
|
||||
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);
|
||||
@@ -363,7 +354,7 @@ AsfStrategy::sendNoRouteNack(Face& face, const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
lp::NackHeader nackHeader;
|
||||
nackHeader.setReason(lp::NackReason::NO_ROUTE);
|
||||
this->sendNack(nackHeader, face, pitEntry);
|
||||
this->sendNack(pitEntry, face, nackHeader);
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
}
|
||||
|
||||
|
||||
+11
-12
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -37,10 +37,9 @@ namespace asf {
|
||||
|
||||
/** \brief Adaptive SRTT-based Forwarding Strategy
|
||||
*
|
||||
* \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.
|
||||
* https://named-data.net/publications/techreports/ndn-0042-1-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
|
||||
*/
|
||||
class AsfStrategy : public Strategy
|
||||
{
|
||||
@@ -53,24 +52,24 @@ public:
|
||||
|
||||
public: // triggers
|
||||
void
|
||||
afterReceiveInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
void
|
||||
beforeSatisfyInterest(const Data& data, const FaceEndpoint& ingress,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const FaceEndpoint& ingress, const Data& data) override;
|
||||
|
||||
void
|
||||
afterReceiveNack(const lp::Nack& nack, const FaceEndpoint& ingress,
|
||||
afterReceiveNack(const FaceEndpoint& ingress, const lp::Nack& nack,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
private:
|
||||
void
|
||||
processParams(const PartialName& parsed);
|
||||
|
||||
pit::OutRecord*
|
||||
void
|
||||
forwardInterest(const Interest& interest, Face& outFace, const fib::Entry& fibEntry,
|
||||
const shared_ptr<pit::Entry>& pitEntry);
|
||||
const shared_ptr<pit::Entry>& pitEntry, bool wantNewNonce = false);
|
||||
|
||||
void
|
||||
sendProbe(const Interest& interest, const FaceEndpoint& ingress, const Face& faceToUse,
|
||||
@@ -91,7 +90,7 @@ private:
|
||||
AsfMeasurements m_measurements;
|
||||
ProbingModule m_probing;
|
||||
RetxSuppressionExponential m_retxSuppression;
|
||||
size_t m_nMaxTimeouts = 3;
|
||||
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-2021, 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,23 +25,41 @@
|
||||
|
||||
#include "best-route-strategy.hpp"
|
||||
#include "algorithm.hpp"
|
||||
#include "common/logger.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
NFD_LOG_INIT(BestRouteStrategy);
|
||||
BestRouteStrategyBase::BestRouteStrategyBase(Forwarder& forwarder)
|
||||
: Strategy(forwarder)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BestRouteStrategyBase::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
if (hasPendingOutRecords(*pitEntry)) {
|
||||
// not a new Interest, don't forward
|
||||
return;
|
||||
}
|
||||
|
||||
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
|
||||
for (const auto& nexthop : fibEntry.getNextHops()) {
|
||||
Face& outFace = nexthop.getFace();
|
||||
if (!wouldViolateScope(ingress.face, interest, outFace) &&
|
||||
canForwardToLegacy(*pitEntry, outFace)) {
|
||||
this->sendInterest(pitEntry, outFace, interest);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
}
|
||||
|
||||
NFD_REGISTER_STRATEGY(BestRouteStrategy);
|
||||
|
||||
const time::milliseconds BestRouteStrategy::RETX_SUPPRESSION_INITIAL(10);
|
||||
const time::milliseconds BestRouteStrategy::RETX_SUPPRESSION_MAX(250);
|
||||
|
||||
BestRouteStrategy::BestRouteStrategy(Forwarder& forwarder, const Name& name)
|
||||
: Strategy(forwarder)
|
||||
, ProcessNackTraits(this)
|
||||
, m_retxSuppression(RETX_SUPPRESSION_INITIAL,
|
||||
RetxSuppressionExponential::DEFAULT_MULTIPLIER,
|
||||
RETX_SUPPRESSION_MAX)
|
||||
: BestRouteStrategyBase(forwarder)
|
||||
{
|
||||
ParsedInstanceName parsed = parseInstanceName(name);
|
||||
if (!parsed.parameters.empty()) {
|
||||
@@ -57,77 +75,9 @@ BestRouteStrategy::BestRouteStrategy(Forwarder& forwarder, const Name& name)
|
||||
const Name&
|
||||
BestRouteStrategy::getStrategyName()
|
||||
{
|
||||
static const auto strategyName = Name("/localhost/nfd/strategy/best-route").appendVersion(5);
|
||||
static Name strategyName("/localhost/nfd/strategy/best-route/%FD%01");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
void
|
||||
BestRouteStrategy::afterReceiveInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
const shared_ptr<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 it = nexthops.end();
|
||||
|
||||
if (suppression == RetxSuppressionResult::NEW) {
|
||||
// forward to nexthop with lowest cost except downstream
|
||||
it = std::find_if(nexthops.begin(), nexthops.end(), [&] (const auto& nexthop) {
|
||||
return isNextHopEligible(ingress.face, interest, nexthop, pitEntry);
|
||||
});
|
||||
|
||||
if (it == nexthops.end()) {
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " noNextHop");
|
||||
|
||||
lp::NackHeader nackHeader;
|
||||
nackHeader.setReason(lp::NackReason::NO_ROUTE);
|
||||
this->sendNack(nackHeader, ingress.face, pitEntry);
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
return;
|
||||
}
|
||||
|
||||
Face& outFace = it->getFace();
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " newPitEntry-to=" << outFace.getId());
|
||||
this->sendInterest(interest, outFace, pitEntry);
|
||||
return;
|
||||
}
|
||||
|
||||
// find an unused upstream with lowest cost except downstream
|
||||
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()) {
|
||||
Face& outFace = it->getFace();
|
||||
this->sendInterest(interest, outFace, pitEntry);
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmit-unused-to=" << outFace.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
// find an eligible upstream that is used earliest
|
||||
it = findEligibleNextHopWithEarliestOutRecord(ingress.face, interest, nexthops, pitEntry);
|
||||
if (it == nexthops.end()) {
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmitNoNextHop");
|
||||
}
|
||||
else {
|
||||
Face& outFace = it->getFace();
|
||||
this->sendInterest(interest, outFace, pitEntry);
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmit-retry-to=" << outFace.getId());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BestRouteStrategy::afterReceiveNack(const lp::Nack& nack, const FaceEndpoint& ingress,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
this->processNack(nack, ingress.face, pitEntry);
|
||||
}
|
||||
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,31 +27,33 @@
|
||||
#define NFD_DAEMON_FW_BEST_ROUTE_STRATEGY_HPP
|
||||
|
||||
#include "strategy.hpp"
|
||||
#include "process-nack-traits.hpp"
|
||||
#include "retx-suppression-exponential.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
/** \brief Best Route strategy
|
||||
class BestRouteStrategyBase : public Strategy
|
||||
{
|
||||
public:
|
||||
void
|
||||
afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
protected:
|
||||
BestRouteStrategyBase(Forwarder& forwarder);
|
||||
};
|
||||
|
||||
/** \brief Best Route strategy version 1
|
||||
*
|
||||
* This strategy forwards a new Interest to the lowest-cost nexthop (except downstream).
|
||||
* After that, if consumer retransmits the Interest (and is not suppressed according to
|
||||
* exponential backoff algorithm), the strategy forwards the Interest again to
|
||||
* the lowest-cost nexthop (except downstream) that is not previously used.
|
||||
* If all nexthops have been used, the strategy starts over with the first nexthop.
|
||||
* This strategy forwards a new Interest to the lowest-cost nexthop
|
||||
* that is not same as the downstream, and does not violate scope.
|
||||
* Subsequent similar Interests or consumer retransmissions are suppressed
|
||||
* until after InterestLifetime expiry.
|
||||
*
|
||||
* This strategy returns Nack to all downstreams with reason NoRoute
|
||||
* if there is no usable nexthop, which may be caused by:
|
||||
* (a) the FIB entry contains no nexthop;
|
||||
* (b) the FIB nexthop happens to be the sole downstream;
|
||||
* (c) the FIB nexthops violate scope.
|
||||
*
|
||||
* 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 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.
|
||||
*/
|
||||
class BestRouteStrategy : public Strategy
|
||||
, public ProcessNackTraits<BestRouteStrategy>
|
||||
class BestRouteStrategy : public BestRouteStrategyBase
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
@@ -59,22 +61,6 @@ public:
|
||||
|
||||
static const Name&
|
||||
getStrategyName();
|
||||
|
||||
public: // triggers
|
||||
void
|
||||
afterReceiveInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
void
|
||||
afterReceiveNack(const lp::Nack& nack, const FaceEndpoint& ingress,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
static const time::milliseconds RETX_SUPPRESSION_INITIAL;
|
||||
static const time::milliseconds RETX_SUPPRESSION_MAX;
|
||||
RetxSuppressionExponential m_retxSuppression;
|
||||
|
||||
friend ProcessNackTraits<BestRouteStrategy>;
|
||||
};
|
||||
|
||||
} // namespace fw
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
/* -*- 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 "best-route-strategy2.hpp"
|
||||
#include "algorithm.hpp"
|
||||
#include "common/logger.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
NFD_LOG_INIT(BestRouteStrategy2);
|
||||
NFD_REGISTER_STRATEGY(BestRouteStrategy2);
|
||||
|
||||
const time::milliseconds BestRouteStrategy2::RETX_SUPPRESSION_INITIAL(10);
|
||||
const time::milliseconds BestRouteStrategy2::RETX_SUPPRESSION_MAX(250);
|
||||
|
||||
BestRouteStrategy2::BestRouteStrategy2(Forwarder& forwarder, const Name& name)
|
||||
: Strategy(forwarder)
|
||||
, ProcessNackTraits(this)
|
||||
, m_retxSuppression(RETX_SUPPRESSION_INITIAL,
|
||||
RetxSuppressionExponential::DEFAULT_MULTIPLIER,
|
||||
RETX_SUPPRESSION_MAX)
|
||||
{
|
||||
ParsedInstanceName parsed = parseInstanceName(name);
|
||||
if (!parsed.parameters.empty()) {
|
||||
NDN_THROW(std::invalid_argument("BestRouteStrategy2 does not accept parameters"));
|
||||
}
|
||||
if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
|
||||
NDN_THROW(std::invalid_argument(
|
||||
"BestRouteStrategy2 does not support version " + to_string(*parsed.version)));
|
||||
}
|
||||
this->setInstanceName(makeInstanceName(name, getStrategyName()));
|
||||
}
|
||||
|
||||
const Name&
|
||||
BestRouteStrategy2::getStrategyName()
|
||||
{
|
||||
static Name strategyName("/localhost/nfd/strategy/best-route/%FD%05");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
void
|
||||
BestRouteStrategy2::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<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 it = nexthops.end();
|
||||
|
||||
if (suppression == RetxSuppressionResult::NEW) {
|
||||
// forward to nexthop with lowest cost except downstream
|
||||
it = std::find_if(nexthops.begin(), nexthops.end(), [&] (const auto& nexthop) {
|
||||
return isNextHopEligible(ingress.face, interest, nexthop, pitEntry);
|
||||
});
|
||||
|
||||
if (it == nexthops.end()) {
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " noNextHop");
|
||||
|
||||
lp::NackHeader nackHeader;
|
||||
nackHeader.setReason(lp::NackReason::NO_ROUTE);
|
||||
this->sendNack(pitEntry, ingress.face, nackHeader);
|
||||
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
return;
|
||||
}
|
||||
|
||||
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(),
|
||||
[&, now = time::steady_clock::now()] (const auto& nexthop) {
|
||||
return isNextHopEligible(ingress.face, interest, nexthop, pitEntry, true, now);
|
||||
});
|
||||
|
||||
if (it != nexthops.end()) {
|
||||
Face& outFace = it->getFace();
|
||||
this->sendInterest(pitEntry, outFace, interest);
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmit-unused-to=" << outFace.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
// find an eligible upstream that is used earliest
|
||||
it = findEligibleNextHopWithEarliestOutRecord(ingress.face, interest, nexthops, pitEntry);
|
||||
if (it == nexthops.end()) {
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmitNoNextHop");
|
||||
}
|
||||
else {
|
||||
Face& outFace = it->getFace();
|
||||
this->sendInterest(pitEntry, outFace, interest);
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " retransmit-retry-to=" << outFace.getId());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BestRouteStrategy2::afterReceiveNack(const FaceEndpoint& ingress, const lp::Nack& nack,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
this->processNack(ingress.face, nack, pitEntry);
|
||||
}
|
||||
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,82 @@
|
||||
/* -*- 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/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FW_BEST_ROUTE_STRATEGY2_HPP
|
||||
#define NFD_DAEMON_FW_BEST_ROUTE_STRATEGY2_HPP
|
||||
|
||||
#include "strategy.hpp"
|
||||
#include "process-nack-traits.hpp"
|
||||
#include "retx-suppression-exponential.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
/** \brief Best Route strategy version 4
|
||||
*
|
||||
* This strategy forwards a new Interest to the lowest-cost nexthop (except downstream).
|
||||
* After that, if consumer retransmits the Interest (and is not suppressed according to
|
||||
* exponential backoff algorithm), the strategy forwards the Interest again to
|
||||
* the lowest-cost nexthop (except downstream) that is not previously used.
|
||||
* If all nexthops have been used, the strategy starts over with the first nexthop.
|
||||
*
|
||||
* This strategy returns Nack to all downstreams with reason NoRoute
|
||||
* if there is no usable nexthop, which may be caused by:
|
||||
* (a) the FIB entry contains no nexthop;
|
||||
* (b) the FIB nexthop happens to be the sole downstream;
|
||||
* (c) the FIB nexthops violate scope.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
class BestRouteStrategy2 : public Strategy
|
||||
, public ProcessNackTraits<BestRouteStrategy2>
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
BestRouteStrategy2(Forwarder& forwarder, const Name& name = getStrategyName());
|
||||
|
||||
static const Name&
|
||||
getStrategyName();
|
||||
|
||||
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;
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
static const time::milliseconds RETX_SUPPRESSION_INITIAL;
|
||||
static const time::milliseconds RETX_SUPPRESSION_MAX;
|
||||
RetxSuppressionExponential m_retxSuppression;
|
||||
|
||||
friend ProcessNackTraits<BestRouteStrategy2>;
|
||||
};
|
||||
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FW_BEST_ROUTE_STRATEGY2_HPP
|
||||
+78
-91
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,8 +26,7 @@
|
||||
#include "forwarder.hpp"
|
||||
|
||||
#include "algorithm.hpp"
|
||||
#include "best-route-strategy.hpp"
|
||||
#include "scope-prefix.hpp"
|
||||
#include "best-route-strategy2.hpp"
|
||||
#include "strategy.hpp"
|
||||
#include "common/global.hpp"
|
||||
#include "common/logger.hpp"
|
||||
@@ -40,12 +39,10 @@ namespace nfd {
|
||||
|
||||
NFD_LOG_INIT(Forwarder);
|
||||
|
||||
const std::string CFG_FORWARDER = "forwarder";
|
||||
|
||||
static Name
|
||||
getDefaultStrategyName()
|
||||
{
|
||||
return fw::BestRouteStrategy::getStrategyName();
|
||||
return fw::BestRouteStrategy2::getStrategyName();
|
||||
}
|
||||
|
||||
Forwarder::Forwarder(FaceTable& faceTable)
|
||||
@@ -59,19 +56,19 @@ Forwarder::Forwarder(FaceTable& faceTable)
|
||||
m_faceTable.afterAdd.connect([this] (const Face& face) {
|
||||
face.afterReceiveInterest.connect(
|
||||
[this, &face] (const Interest& interest, const EndpointId& endpointId) {
|
||||
this->onIncomingInterest(interest, FaceEndpoint(const_cast<Face&>(face), endpointId));
|
||||
this->startProcessInterest(FaceEndpoint(face, endpointId), interest);
|
||||
});
|
||||
face.afterReceiveData.connect(
|
||||
[this, &face] (const Data& data, const EndpointId& endpointId) {
|
||||
this->onIncomingData(data, FaceEndpoint(const_cast<Face&>(face), endpointId));
|
||||
this->startProcessData(FaceEndpoint(face, endpointId), data);
|
||||
});
|
||||
face.afterReceiveNack.connect(
|
||||
[this, &face] (const lp::Nack& nack, const EndpointId& endpointId) {
|
||||
this->onIncomingNack(nack, FaceEndpoint(const_cast<Face&>(face), endpointId));
|
||||
this->startProcessNack(FaceEndpoint(face, endpointId), nack);
|
||||
});
|
||||
face.onDroppedInterest.connect(
|
||||
[this, &face] (const Interest& interest) {
|
||||
this->onDroppedInterest(interest, const_cast<Face&>(face));
|
||||
this->onDroppedInterest(face, interest);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -79,8 +76,8 @@ Forwarder::Forwarder(FaceTable& faceTable)
|
||||
cleanupOnFaceRemoval(m_nameTree, m_fib, m_pit, face);
|
||||
});
|
||||
|
||||
m_fib.afterNewNextHop.connect([this] (const Name& prefix, const fib::NextHop& nextHop) {
|
||||
this->onNewNextHop(prefix, nextHop);
|
||||
m_fib.afterNewNextHop.connect([&] (const Name& prefix, const fib::NextHop& nextHop) {
|
||||
this->startProcessNewNextHop(prefix, nextHop);
|
||||
});
|
||||
|
||||
m_strategyChoice.setDefaultStrategy(getDefaultStrategyName());
|
||||
@@ -89,7 +86,7 @@ Forwarder::Forwarder(FaceTable& faceTable)
|
||||
Forwarder::~Forwarder() = default;
|
||||
|
||||
void
|
||||
Forwarder::onIncomingInterest(const Interest& interest, const FaceEndpoint& ingress)
|
||||
Forwarder::onIncomingInterest(const FaceEndpoint& ingress, const Interest& interest)
|
||||
{
|
||||
// receive Interest
|
||||
NFD_LOG_DEBUG("onIncomingInterest in=" << ingress << " interest=" << interest.getName());
|
||||
@@ -98,13 +95,13 @@ Forwarder::onIncomingInterest(const Interest& interest, const FaceEndpoint& ingr
|
||||
|
||||
// drop if HopLimit zero, decrement otherwise (if present)
|
||||
if (interest.getHopLimit()) {
|
||||
if (*interest.getHopLimit() == 0) {
|
||||
if (*interest.getHopLimit() < 1) {
|
||||
NFD_LOG_DEBUG("onIncomingInterest in=" << ingress << " interest=" << interest.getName()
|
||||
<< " hop-limit=0");
|
||||
++ingress.face.getCounters().nInHopLimitZero;
|
||||
// drop
|
||||
++const_cast<PacketCounter&>(ingress.face.getCounters().nInHopLimitZero);
|
||||
return;
|
||||
}
|
||||
|
||||
const_cast<Interest&>(interest).setHopLimit(*interest.getHopLimit() - 1);
|
||||
}
|
||||
|
||||
@@ -114,7 +111,7 @@ Forwarder::onIncomingInterest(const Interest& interest, const FaceEndpoint& ingr
|
||||
if (isViolatingLocalhost) {
|
||||
NFD_LOG_DEBUG("onIncomingInterest in=" << ingress
|
||||
<< " interest=" << interest.getName() << " violates /localhost");
|
||||
// drop
|
||||
// (drop)
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -122,7 +119,7 @@ Forwarder::onIncomingInterest(const Interest& interest, const FaceEndpoint& ingr
|
||||
bool hasDuplicateNonceInDnl = m_deadNonceList.has(interest.getName(), interest.getNonce());
|
||||
if (hasDuplicateNonceInDnl) {
|
||||
// goto Interest loop pipeline
|
||||
this->onInterestLoop(interest, ingress);
|
||||
this->onInterestLoop(ingress, interest);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -146,23 +143,23 @@ Forwarder::onIncomingInterest(const Interest& interest, const FaceEndpoint& ingr
|
||||
}
|
||||
if (hasDuplicateNonceInPit) {
|
||||
// goto Interest loop pipeline
|
||||
this->onInterestLoop(interest, ingress);
|
||||
this->onInterestLoop(ingress, interest);
|
||||
return;
|
||||
}
|
||||
|
||||
// is pending?
|
||||
if (!pitEntry->hasInRecords()) {
|
||||
m_cs.find(interest,
|
||||
[=] (const Interest& i, const Data& d) { onContentStoreHit(i, ingress, pitEntry, d); },
|
||||
[=] (const Interest& i) { onContentStoreMiss(i, ingress, pitEntry); });
|
||||
bind(&Forwarder::onContentStoreHit, this, ingress, pitEntry, _1, _2),
|
||||
bind(&Forwarder::onContentStoreMiss, this, ingress, pitEntry, _1));
|
||||
}
|
||||
else {
|
||||
this->onContentStoreMiss(interest, ingress, pitEntry);
|
||||
this->onContentStoreMiss(ingress, pitEntry, interest);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onInterestLoop(const Interest& interest, const FaceEndpoint& ingress)
|
||||
Forwarder::onInterestLoop(const FaceEndpoint& ingress, const Interest& interest)
|
||||
{
|
||||
// if multi-access or ad hoc face, drop
|
||||
if (ingress.face.getLinkType() != ndn::nfd::LINK_TYPE_POINT_TO_POINT) {
|
||||
@@ -182,17 +179,12 @@ Forwarder::onInterestLoop(const Interest& interest, const FaceEndpoint& ingress)
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onContentStoreMiss(const Interest& interest, const FaceEndpoint& ingress,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
Forwarder::onContentStoreMiss(const FaceEndpoint& ingress,
|
||||
const shared_ptr<pit::Entry>& pitEntry, const Interest& interest)
|
||||
{
|
||||
NFD_LOG_DEBUG("onContentStoreMiss interest=" << interest.getName());
|
||||
++m_counters.nCsMisses;
|
||||
|
||||
// attach HopLimit if configured and not present in Interest
|
||||
if (m_config.defaultHopLimit > 0 && !interest.getHopLimit()) {
|
||||
const_cast<Interest&>(interest).setHopLimit(m_config.defaultHopLimit);
|
||||
}
|
||||
|
||||
// insert in-record
|
||||
pitEntry->insertOrUpdateInRecord(ingress.face, interest);
|
||||
|
||||
@@ -214,19 +206,21 @@ Forwarder::onContentStoreMiss(const Interest& interest, const FaceEndpoint& ingr
|
||||
<< " nexthop-faceid=" << nextHopFace->getId());
|
||||
// go to outgoing Interest pipeline
|
||||
// scope control is unnecessary, because privileged app explicitly wants to forward
|
||||
this->onOutgoingInterest(interest, *nextHopFace, pitEntry);
|
||||
this->onOutgoingInterest(pitEntry, *nextHopFace, interest);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// dispatch to strategy: after receive Interest
|
||||
m_strategyChoice.findEffectiveStrategy(*pitEntry)
|
||||
.afterReceiveInterest(interest, FaceEndpoint(ingress.face, 0), pitEntry);
|
||||
// dispatch to strategy: after incoming Interest
|
||||
this->dispatchToStrategy(*pitEntry,
|
||||
[&] (fw::Strategy& strategy) {
|
||||
strategy.afterReceiveInterest(FaceEndpoint(ingress.face, 0), interest, pitEntry);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onContentStoreHit(const Interest& interest, const FaceEndpoint& ingress,
|
||||
const shared_ptr<pit::Entry>& pitEntry, const Data& data)
|
||||
Forwarder::onContentStoreHit(const FaceEndpoint& ingress, const shared_ptr<pit::Entry>& pitEntry,
|
||||
const Interest& interest, const Data& data)
|
||||
{
|
||||
NFD_LOG_DEBUG("onContentStoreHit interest=" << interest.getName());
|
||||
++m_counters.nCsHits;
|
||||
@@ -242,18 +236,19 @@ Forwarder::onContentStoreHit(const Interest& interest, const FaceEndpoint& ingre
|
||||
this->setExpiryTimer(pitEntry, 0_ms);
|
||||
|
||||
// dispatch to strategy: after Content Store hit
|
||||
m_strategyChoice.findEffectiveStrategy(*pitEntry).afterContentStoreHit(data, ingress, pitEntry);
|
||||
this->dispatchToStrategy(*pitEntry,
|
||||
[&] (fw::Strategy& strategy) { strategy.afterContentStoreHit(pitEntry, ingress, data); });
|
||||
}
|
||||
|
||||
pit::OutRecord*
|
||||
Forwarder::onOutgoingInterest(const Interest& interest, Face& egress,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
Forwarder::onOutgoingInterest(const shared_ptr<pit::Entry>& pitEntry,
|
||||
Face& egress, const Interest& interest)
|
||||
{
|
||||
// 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");
|
||||
++egress.getCounters().nOutHopLimitZero;
|
||||
++const_cast<PacketCounter&>(egress.getCounters().nOutHopLimitZero);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -292,7 +287,7 @@ Forwarder::onInterestFinalize(const shared_ptr<pit::Entry>& pitEntry)
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onIncomingData(const Data& data, const FaceEndpoint& ingress)
|
||||
Forwarder::onIncomingData(const FaceEndpoint& ingress, const Data& data)
|
||||
{
|
||||
// receive Data
|
||||
NFD_LOG_DEBUG("onIncomingData in=" << ingress << " data=" << data.getName());
|
||||
@@ -304,7 +299,7 @@ Forwarder::onIncomingData(const Data& data, const FaceEndpoint& ingress)
|
||||
scope_prefix::LOCALHOST.isPrefixOf(data.getName());
|
||||
if (isViolatingLocalhost) {
|
||||
NFD_LOG_DEBUG("onIncomingData in=" << ingress << " data=" << data.getName() << " violates /localhost");
|
||||
// drop
|
||||
// (drop)
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -312,7 +307,7 @@ Forwarder::onIncomingData(const Data& data, const FaceEndpoint& ingress)
|
||||
pit::DataMatchResult pitMatches = m_pit.findAllDataMatches(data);
|
||||
if (pitMatches.size() == 0) {
|
||||
// goto Data unsolicited pipeline
|
||||
this->onDataUnsolicited(data, ingress);
|
||||
this->onDataUnsolicited(ingress, data);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -329,7 +324,8 @@ Forwarder::onIncomingData(const Data& data, const FaceEndpoint& ingress)
|
||||
this->setExpiryTimer(pitEntry, 0_ms);
|
||||
|
||||
// trigger strategy: after receive Data
|
||||
m_strategyChoice.findEffectiveStrategy(*pitEntry).afterReceiveData(data, ingress, pitEntry);
|
||||
this->dispatchToStrategy(*pitEntry,
|
||||
[&] (fw::Strategy& strategy) { strategy.afterReceiveData(pitEntry, ingress, data); });
|
||||
|
||||
// mark PIT satisfied
|
||||
pitEntry->isSatisfied = true;
|
||||
@@ -361,7 +357,8 @@ Forwarder::onIncomingData(const Data& data, const FaceEndpoint& ingress)
|
||||
this->setExpiryTimer(pitEntry, 0_ms);
|
||||
|
||||
// invoke PIT satisfy callback
|
||||
m_strategyChoice.findEffectiveStrategy(*pitEntry).beforeSatisfyInterest(data, ingress, pitEntry);
|
||||
this->dispatchToStrategy(*pitEntry,
|
||||
[&] (fw::Strategy& strategy) { strategy.beforeSatisfyInterest(pitEntry, ingress, data); });
|
||||
|
||||
// mark PIT satisfied
|
||||
pitEntry->isSatisfied = true;
|
||||
@@ -388,7 +385,7 @@ Forwarder::onIncomingData(const Data& data, const FaceEndpoint& ingress)
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onDataUnsolicited(const Data& data, const FaceEndpoint& ingress)
|
||||
Forwarder::onDataUnsolicited(const FaceEndpoint& ingress, const Data& data)
|
||||
{
|
||||
// accept to cache?
|
||||
auto decision = m_unsolicitedDataPolicy->decide(ingress.face, data);
|
||||
@@ -417,7 +414,7 @@ Forwarder::onOutgoingData(const Data& data, Face& egress)
|
||||
if (isViolatingLocalhost) {
|
||||
NFD_LOG_DEBUG("onOutgoingData out=" << egress.getId() << " data=" << data.getName()
|
||||
<< " violates /localhost");
|
||||
// drop
|
||||
// (drop)
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -431,7 +428,7 @@ Forwarder::onOutgoingData(const Data& data, Face& egress)
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onIncomingNack(const lp::Nack& nack, const FaceEndpoint& ingress)
|
||||
Forwarder::onIncomingNack(const FaceEndpoint& ingress, const lp::Nack& nack)
|
||||
{
|
||||
// receive Nack
|
||||
nack.setTag(make_shared<lp::IncomingFaceIdTag>(ingress.face.getId()));
|
||||
@@ -483,12 +480,13 @@ Forwarder::onIncomingNack(const lp::Nack& nack, const FaceEndpoint& ingress)
|
||||
}
|
||||
|
||||
// trigger strategy: after receive NACK
|
||||
m_strategyChoice.findEffectiveStrategy(*pitEntry).afterReceiveNack(nack, ingress, pitEntry);
|
||||
this->dispatchToStrategy(*pitEntry,
|
||||
[&] (fw::Strategy& strategy) { strategy.afterReceiveNack(ingress, nack, pitEntry); });
|
||||
}
|
||||
|
||||
bool
|
||||
Forwarder::onOutgoingNack(const lp::NackHeader& nack, Face& egress,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
Forwarder::onOutgoingNack(const shared_ptr<pit::Entry>& pitEntry,
|
||||
Face& egress, const lp::NackHeader& nack)
|
||||
{
|
||||
if (egress.getId() == face::INVALID_FACEID) {
|
||||
NFD_LOG_WARN("onOutgoingNack out=(invalid)"
|
||||
@@ -534,9 +532,9 @@ Forwarder::onOutgoingNack(const lp::NackHeader& nack, Face& egress,
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::onDroppedInterest(const Interest& interest, Face& egress)
|
||||
Forwarder::onDroppedInterest(const Face& egress, const Interest& interest)
|
||||
{
|
||||
m_strategyChoice.findEffectiveStrategy(interest.getName()).onDroppedInterest(interest, egress);
|
||||
m_strategyChoice.findEffectiveStrategy(interest.getName()).onDroppedInterest(egress, interest);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -544,20 +542,37 @@ 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> {
|
||||
// we ignore an NTE and skip visiting its descendants if that NTE has an
|
||||
// associated FIB entry (1st condition), since in that case the new nexthop
|
||||
// won't affect any PIT entries anywhere in that subtree, *unless* this is
|
||||
// the initial NTE from which the enumeration started (2nd condition), which
|
||||
// must always be considered
|
||||
if (nte.getFibEntry() != nullptr && nte.getName().size() > prefix.size()) {
|
||||
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};
|
||||
}
|
||||
return {nte.hasPitEntries(), true};
|
||||
});
|
||||
|
||||
for (const auto& nte : affectedEntries) {
|
||||
for (const auto& pitEntry : nte.getPitEntries()) {
|
||||
m_strategyChoice.findEffectiveStrategy(*pitEntry).afterNewNextHop(nextHop, pitEntry);
|
||||
this->dispatchToStrategy(*pitEntry,
|
||||
[&] (fw::Strategy& strategy) {
|
||||
strategy.afterNewNextHop(nextHop, pitEntry);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -573,13 +588,13 @@ Forwarder::setExpiryTimer(const shared_ptr<pit::Entry>& pitEntry, time::millisec
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::insertDeadNonceList(pit::Entry& pitEntry, const Face* upstream)
|
||||
Forwarder::insertDeadNonceList(pit::Entry& pitEntry, Face* upstream)
|
||||
{
|
||||
// need Dead Nonce List insert?
|
||||
bool needDnl = true;
|
||||
if (pitEntry.isSatisfied) {
|
||||
BOOST_ASSERT(pitEntry.dataFreshnessPeriod >= 0_ms);
|
||||
needDnl = pitEntry.getInterest().getMustBeFresh() &&
|
||||
needDnl = static_cast<bool>(pitEntry.getInterest().getMustBeFresh()) &&
|
||||
pitEntry.dataFreshnessPeriod < m_deadNonceList.getLifetime();
|
||||
}
|
||||
|
||||
@@ -604,32 +619,4 @@ Forwarder::insertDeadNonceList(pit::Entry& pitEntry, const Face* upstream)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::setConfigFile(ConfigFile& configFile)
|
||||
{
|
||||
configFile.addSectionHandler(CFG_FORWARDER, [this] (auto&&... args) {
|
||||
processConfig(std::forward<decltype(args)>(args)...);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
Forwarder::processConfig(const ConfigSection& configSection, bool isDryRun, const std::string&)
|
||||
{
|
||||
Config config;
|
||||
|
||||
for (const auto& pair : configSection) {
|
||||
const std::string& key = pair.first;
|
||||
if (key == "default_hop_limit") {
|
||||
config.defaultHopLimit = ConfigFile::parseNumber<uint8_t>(pair, CFG_FORWARDER);
|
||||
}
|
||||
else {
|
||||
NDN_THROW(ConfigFile::Error("Unrecognized option " + CFG_FORWARDER + "." + key));
|
||||
}
|
||||
}
|
||||
|
||||
if (!isDryRun) {
|
||||
m_config = config;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nfd
|
||||
+87
-61
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,7 +29,6 @@
|
||||
#include "face-table.hpp"
|
||||
#include "forwarder-counters.hpp"
|
||||
#include "unsolicited-data-policy.hpp"
|
||||
#include "common/config-file.hpp"
|
||||
#include "face/face-endpoint.hpp"
|
||||
#include "table/fib.hpp"
|
||||
#include "table/pit.hpp"
|
||||
@@ -45,10 +44,9 @@ namespace fw {
|
||||
class Strategy;
|
||||
} // namespace fw
|
||||
|
||||
/**
|
||||
* \brief Main class of NFD's forwarding engine.
|
||||
/** \brief Main class of NFD's forwarding engine.
|
||||
*
|
||||
* The Forwarder class owns all tables and implements the forwarding pipelines.
|
||||
* Forwarder owns all tables and implements the forwarding pipelines.
|
||||
*/
|
||||
class Forwarder
|
||||
{
|
||||
@@ -56,7 +54,7 @@ public:
|
||||
explicit
|
||||
Forwarder(FaceTable& faceTable);
|
||||
|
||||
NFD_VIRTUAL_WITH_TESTS
|
||||
VIRTUAL_WITH_TESTS
|
||||
~Forwarder();
|
||||
|
||||
const ForwarderCounters&
|
||||
@@ -78,6 +76,47 @@ public:
|
||||
m_unsolicitedDataPolicy = std::move(policy);
|
||||
}
|
||||
|
||||
public: // forwarding entrypoints and tables
|
||||
/** \brief start incoming Interest processing
|
||||
* \param ingress face on which Interest is received and endpoint of the sender
|
||||
* \param interest the incoming Interest, must be well-formed and created with make_shared
|
||||
*/
|
||||
void
|
||||
startProcessInterest(const FaceEndpoint& ingress, const Interest& interest)
|
||||
{
|
||||
this->onIncomingInterest(ingress, interest);
|
||||
}
|
||||
|
||||
/** \brief start incoming Data processing
|
||||
* \param ingress face on which Data is received and endpoint of the sender
|
||||
* \param data the incoming Data, must be well-formed and created with make_shared
|
||||
*/
|
||||
void
|
||||
startProcessData(const FaceEndpoint& ingress, const Data& data)
|
||||
{
|
||||
this->onIncomingData(ingress, data);
|
||||
}
|
||||
|
||||
/** \brief start incoming Nack processing
|
||||
* \param ingress face on which Nack is received and endpoint of the sender
|
||||
* \param nack the incoming Nack, must be well-formed
|
||||
*/
|
||||
void
|
||||
startProcessNack(const FaceEndpoint& ingress, const lp::Nack& nack)
|
||||
{
|
||||
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()
|
||||
{
|
||||
@@ -126,87 +165,76 @@ public:
|
||||
return m_networkRegionTable;
|
||||
}
|
||||
|
||||
/** \brief register handler for forwarder section of NFD configuration file
|
||||
*/
|
||||
void
|
||||
setConfigFile(ConfigFile& configFile);
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE: // pipelines
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE: // pipelines
|
||||
/** \brief incoming Interest pipeline
|
||||
* \param interest the incoming Interest, must be well-formed and created with make_shared
|
||||
* \param ingress face on which \p interest was received and endpoint of the sender
|
||||
*/
|
||||
NFD_VIRTUAL_WITH_TESTS void
|
||||
onIncomingInterest(const Interest& interest, const FaceEndpoint& ingress);
|
||||
VIRTUAL_WITH_TESTS void
|
||||
onIncomingInterest(const FaceEndpoint& ingress, const Interest& interest);
|
||||
|
||||
/** \brief Interest loop pipeline
|
||||
*/
|
||||
NFD_VIRTUAL_WITH_TESTS void
|
||||
onInterestLoop(const Interest& interest, const FaceEndpoint& ingress);
|
||||
VIRTUAL_WITH_TESTS void
|
||||
onInterestLoop(const FaceEndpoint& ingress, const Interest& interest);
|
||||
|
||||
/** \brief Content Store miss pipeline
|
||||
*/
|
||||
NFD_VIRTUAL_WITH_TESTS void
|
||||
onContentStoreMiss(const Interest& interest, const FaceEndpoint& ingress,
|
||||
const shared_ptr<pit::Entry>& pitEntry);
|
||||
VIRTUAL_WITH_TESTS void
|
||||
onContentStoreMiss(const FaceEndpoint& ingress,
|
||||
const shared_ptr<pit::Entry>& pitEntry, const Interest& interest);
|
||||
|
||||
/** \brief Content Store hit pipeline
|
||||
*/
|
||||
NFD_VIRTUAL_WITH_TESTS void
|
||||
onContentStoreHit(const Interest& interest, const FaceEndpoint& ingress,
|
||||
const shared_ptr<pit::Entry>& pitEntry, const Data& data);
|
||||
VIRTUAL_WITH_TESTS void
|
||||
onContentStoreHit(const FaceEndpoint& ingress, const shared_ptr<pit::Entry>& pitEntry,
|
||||
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
|
||||
*/
|
||||
NFD_VIRTUAL_WITH_TESTS pit::OutRecord*
|
||||
onOutgoingInterest(const Interest& interest, Face& egress,
|
||||
const shared_ptr<pit::Entry>& pitEntry);
|
||||
VIRTUAL_WITH_TESTS pit::OutRecord*
|
||||
onOutgoingInterest(const shared_ptr<pit::Entry>& pitEntry,
|
||||
Face& egress, const Interest& interest);
|
||||
|
||||
/** \brief Interest finalize pipeline
|
||||
*/
|
||||
NFD_VIRTUAL_WITH_TESTS void
|
||||
VIRTUAL_WITH_TESTS void
|
||||
onInterestFinalize(const shared_ptr<pit::Entry>& pitEntry);
|
||||
|
||||
/** \brief incoming Data pipeline
|
||||
* \param data the incoming Data, must be well-formed and created with make_shared
|
||||
* \param ingress face on which \p data was received and endpoint of the sender
|
||||
*/
|
||||
NFD_VIRTUAL_WITH_TESTS void
|
||||
onIncomingData(const Data& data, const FaceEndpoint& ingress);
|
||||
VIRTUAL_WITH_TESTS void
|
||||
onIncomingData(const FaceEndpoint& ingress, const Data& data);
|
||||
|
||||
/** \brief Data unsolicited pipeline
|
||||
*/
|
||||
NFD_VIRTUAL_WITH_TESTS void
|
||||
onDataUnsolicited(const Data& data, const FaceEndpoint& ingress);
|
||||
VIRTUAL_WITH_TESTS void
|
||||
onDataUnsolicited(const FaceEndpoint& ingress, const Data& data);
|
||||
|
||||
/** \brief outgoing Data pipeline
|
||||
* \return Whether the Data was transmitted (true) or dropped (false)
|
||||
*/
|
||||
NFD_VIRTUAL_WITH_TESTS bool
|
||||
VIRTUAL_WITH_TESTS bool
|
||||
onOutgoingData(const Data& data, Face& egress);
|
||||
|
||||
/** \brief incoming Nack pipeline
|
||||
* \param nack the incoming Nack, must be well-formed
|
||||
* \param ingress face on which \p nack is received and endpoint of the sender
|
||||
*/
|
||||
NFD_VIRTUAL_WITH_TESTS void
|
||||
onIncomingNack(const lp::Nack& nack, const FaceEndpoint& ingress);
|
||||
VIRTUAL_WITH_TESTS void
|
||||
onIncomingNack(const FaceEndpoint& ingress, const lp::Nack& nack);
|
||||
|
||||
/** \brief outgoing Nack pipeline
|
||||
* \return Whether the Nack was transmitted (true) or dropped (false)
|
||||
*/
|
||||
NFD_VIRTUAL_WITH_TESTS bool
|
||||
onOutgoingNack(const lp::NackHeader& nack, Face& egress,
|
||||
const shared_ptr<pit::Entry>& pitEntry);
|
||||
VIRTUAL_WITH_TESTS bool
|
||||
onOutgoingNack(const shared_ptr<pit::Entry>& pitEntry,
|
||||
Face& egress, const lp::NackHeader& nack);
|
||||
|
||||
NFD_VIRTUAL_WITH_TESTS void
|
||||
onDroppedInterest(const Interest& interest, Face& egress);
|
||||
VIRTUAL_WITH_TESTS void
|
||||
onDroppedInterest(const Face& egress, const Interest& interest);
|
||||
|
||||
NFD_VIRTUAL_WITH_TESTS void
|
||||
VIRTUAL_WITH_TESTS void
|
||||
onNewNextHop(const Name& prefix, const fib::NextHop& nextHop);
|
||||
|
||||
private:
|
||||
PROTECTED_WITH_TESTS_ELSE_PRIVATE:
|
||||
/** \brief set a new expiry timer (now + \p duration) on a PIT entry
|
||||
*/
|
||||
void
|
||||
@@ -216,24 +244,22 @@ private:
|
||||
* \param upstream if null, insert Nonces from all out-records;
|
||||
* if not null, insert Nonce only on the out-records of this face
|
||||
*/
|
||||
void
|
||||
insertDeadNonceList(pit::Entry& pitEntry, const Face* upstream);
|
||||
VIRTUAL_WITH_TESTS void
|
||||
insertDeadNonceList(pit::Entry& pitEntry, Face* upstream);
|
||||
|
||||
void
|
||||
processConfig(const ConfigSection& configSection, bool isDryRun,
|
||||
const std::string& filename);
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
/**
|
||||
* \brief Configuration options from "forwarder" section
|
||||
/** \brief call trigger (method) on the effective strategy of pitEntry
|
||||
*/
|
||||
struct Config
|
||||
#ifdef WITH_TESTS
|
||||
virtual void
|
||||
dispatchToStrategy(pit::Entry& pitEntry, std::function<void(fw::Strategy&)> trigger)
|
||||
#else
|
||||
template<class Function>
|
||||
void
|
||||
dispatchToStrategy(pit::Entry& pitEntry, Function trigger)
|
||||
#endif
|
||||
{
|
||||
/// Initial value of HopLimit that should be added to Interests that don't have one.
|
||||
/// A value of zero disables the feature.
|
||||
uint8_t defaultHopLimit = 0;
|
||||
};
|
||||
Config m_config;
|
||||
trigger(m_strategyChoice.findEffectiveStrategy(pitEntry));
|
||||
}
|
||||
|
||||
private:
|
||||
ForwarderCounters m_counters;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -39,6 +39,7 @@ const time::milliseconds MulticastStrategy::RETX_SUPPRESSION_MAX(250);
|
||||
|
||||
MulticastStrategy::MulticastStrategy(Forwarder& forwarder, const Name& name)
|
||||
: Strategy(forwarder)
|
||||
, ProcessNackTraits(this)
|
||||
, m_retxSuppression(RETX_SUPPRESSION_INITIAL,
|
||||
RetxSuppressionExponential::DEFAULT_MULTIPLIER,
|
||||
RETX_SUPPRESSION_MAX)
|
||||
@@ -57,12 +58,12 @@ MulticastStrategy::MulticastStrategy(Forwarder& forwarder, const Name& name)
|
||||
const Name&
|
||||
MulticastStrategy::getStrategyName()
|
||||
{
|
||||
static const auto strategyName = Name("/localhost/nfd/strategy/multicast").appendVersion(4);
|
||||
static Name strategyName("/localhost/nfd/strategy/multicast/%FD%03");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
void
|
||||
MulticastStrategy::afterReceiveInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
MulticastStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
|
||||
@@ -83,35 +84,28 @@ MulticastStrategy::afterReceiveInterest(const Interest& interest, const FaceEndp
|
||||
}
|
||||
|
||||
NFD_LOG_DEBUG(interest << " from=" << ingress << " pitEntry-to=" << outFace.getId());
|
||||
auto* sentOutRecord = this->sendInterest(interest, outFace, pitEntry);
|
||||
if (sentOutRecord && suppressResult == RetxSuppressionResult::FORWARD) {
|
||||
m_retxSuppression.incrementIntervalForOutRecord(*sentOutRecord);
|
||||
bool wasSent = this->sendInterest(pitEntry, outFace, interest) != nullptr;
|
||||
if (wasSent && suppressResult == RetxSuppressionResult::FORWARD) {
|
||||
m_retxSuppression.incrementIntervalForOutRecord(*pitEntry->getOutRecord(outFace));
|
||||
}
|
||||
}
|
||||
|
||||
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.face, nackHeader);
|
||||
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MulticastStrategy::afterNewNextHop(const fib::NextHop& nextHop,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
MulticastStrategy::afterReceiveNack(const FaceEndpoint& ingress, const lp::Nack& nack,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
// no need to check for suppression, as it is a new next hop
|
||||
|
||||
auto nextHopFaceId = nextHop.getFace().getId();
|
||||
auto& interest = pitEntry->getInterest();
|
||||
|
||||
// try to find an incoming face record that doesn't violate scope restrictions
|
||||
for (const auto& r : pitEntry->getInRecords()) {
|
||||
auto& inFace = r.getFace();
|
||||
if (isNextHopEligible(inFace, interest, nextHop, pitEntry)) {
|
||||
|
||||
NFD_LOG_DEBUG(interest << " from=" << inFace.getId() << " pitEntry-to=" << nextHopFaceId);
|
||||
this->sendInterest(interest, nextHop.getFace(), pitEntry);
|
||||
|
||||
break; // just one eligible incoming face record is enough
|
||||
}
|
||||
}
|
||||
|
||||
// if nothing found, the interest will not be forwarded
|
||||
this->processNack(ingress.face, nack, pitEntry);
|
||||
}
|
||||
|
||||
} // namespace fw
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,7 @@
|
||||
#define NFD_DAEMON_FW_MULTICAST_STRATEGY_HPP
|
||||
|
||||
#include "strategy.hpp"
|
||||
#include "process-nack-traits.hpp"
|
||||
#include "retx-suppression-exponential.hpp"
|
||||
|
||||
namespace nfd {
|
||||
@@ -35,6 +36,7 @@ namespace fw {
|
||||
/** \brief A forwarding strategy that forwards Interests to all FIB nexthops
|
||||
*/
|
||||
class MulticastStrategy : public Strategy
|
||||
, public ProcessNackTraits<MulticastStrategy>
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
@@ -43,18 +45,19 @@ public:
|
||||
static const Name&
|
||||
getStrategyName();
|
||||
|
||||
public: // triggers
|
||||
void
|
||||
afterReceiveInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
void
|
||||
afterNewNextHop(const fib::NextHop& nextHop, const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
afterReceiveNack(const FaceEndpoint& ingress, const lp::Nack& nack,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
private:
|
||||
friend ProcessNackTraits<MulticastStrategy>;
|
||||
RetxSuppressionExponential m_retxSuppression;
|
||||
|
||||
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
static const time::milliseconds RETX_SUPPRESSION_INITIAL;
|
||||
static const time::milliseconds RETX_SUPPRESSION_MAX;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,345 @@
|
||||
/* -*- 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 "ncc-strategy.hpp"
|
||||
#include "algorithm.hpp"
|
||||
#include "common/global.hpp"
|
||||
|
||||
#include <ndn-cxx/util/random.hpp>
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
NFD_REGISTER_STRATEGY(NccStrategy);
|
||||
|
||||
const time::microseconds NccStrategy::DEFER_FIRST_WITHOUT_BEST_FACE = 4_ms;
|
||||
const time::microseconds NccStrategy::DEFER_RANGE_WITHOUT_BEST_FACE = 75_ms;
|
||||
const time::nanoseconds NccStrategy::MEASUREMENTS_LIFETIME = 16_s;
|
||||
|
||||
NccStrategy::NccStrategy(Forwarder& forwarder, const Name& name)
|
||||
: Strategy(forwarder)
|
||||
{
|
||||
ParsedInstanceName parsed = parseInstanceName(name);
|
||||
if (!parsed.parameters.empty()) {
|
||||
NDN_THROW(std::invalid_argument("NccStrategy does not accept parameters"));
|
||||
}
|
||||
if (parsed.version && *parsed.version != getStrategyName()[-1].toVersion()) {
|
||||
NDN_THROW(std::invalid_argument(
|
||||
"NccStrategy does not support version " + to_string(*parsed.version)));
|
||||
}
|
||||
this->setInstanceName(makeInstanceName(name, getStrategyName()));
|
||||
}
|
||||
|
||||
const Name&
|
||||
NccStrategy::getStrategyName()
|
||||
{
|
||||
static Name strategyName("/localhost/nfd/strategy/ncc/%FD%01");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
void
|
||||
NccStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
|
||||
const fib::NextHopList& nexthops = fibEntry.getNextHops();
|
||||
if (nexthops.size() == 0) {
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
return;
|
||||
}
|
||||
|
||||
PitEntryInfo* pitEntryInfo = pitEntry->insertStrategyInfo<PitEntryInfo>().first;
|
||||
bool isNewPitEntry = !hasPendingOutRecords(*pitEntry);
|
||||
if (!isNewPitEntry) {
|
||||
return;
|
||||
}
|
||||
|
||||
MeasurementsEntryInfo& meInfo = this->getMeasurementsEntryInfo(pitEntry);
|
||||
|
||||
time::microseconds deferFirst = DEFER_FIRST_WITHOUT_BEST_FACE;
|
||||
time::microseconds deferRange = DEFER_RANGE_WITHOUT_BEST_FACE;
|
||||
size_t nUpstreams = nexthops.size();
|
||||
|
||||
shared_ptr<Face> bestFace = meInfo.getBestFace();
|
||||
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, *bestFace, interest);
|
||||
pitEntryInfo->bestFaceTimeout = getScheduler().schedule(meInfo.prediction,
|
||||
bind(&NccStrategy::timeoutOnBestFace, this, weak_ptr<pit::Entry>(pitEntry)));
|
||||
}
|
||||
else {
|
||||
// use first eligible nexthop
|
||||
auto firstEligibleNexthop = std::find_if(nexthops.begin(), nexthops.end(),
|
||||
[&] (const fib::NextHop& nexthop) {
|
||||
Face& outFace = nexthop.getFace();
|
||||
return !wouldViolateScope(ingress.face, interest, outFace) &&
|
||||
canForwardToLegacy(*pitEntry, outFace);
|
||||
});
|
||||
if (firstEligibleNexthop != nexthops.end()) {
|
||||
this->sendInterest(pitEntry, firstEligibleNexthop->getFace(), interest);
|
||||
}
|
||||
else {
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<Face> previousFace = meInfo.previousFace.lock();
|
||||
if (previousFace != nullptr && fibEntry.hasNextHop(*previousFace) &&
|
||||
!wouldViolateScope(ingress.face, interest, *previousFace) &&
|
||||
canForwardToLegacy(*pitEntry, *previousFace)) {
|
||||
--nUpstreams;
|
||||
}
|
||||
|
||||
if (nUpstreams > 0) {
|
||||
pitEntryInfo->maxInterval = std::max(1_us,
|
||||
time::microseconds((2 * deferRange.count() + nUpstreams - 1) / nUpstreams));
|
||||
}
|
||||
else {
|
||||
// Normally, maxInterval is unused if there aren't any face beyond best and previousBest.
|
||||
// However, in case FIB entry gains a new nexthop before doPropagate executes (bug 1853),
|
||||
// this maxInterval would be used to determine when the next doPropagate would happen.
|
||||
pitEntryInfo->maxInterval = deferFirst;
|
||||
}
|
||||
pitEntryInfo->propagateTimer = getScheduler().schedule(deferFirst,
|
||||
bind(&NccStrategy::doPropagate, this, ingress.face.getId(), weak_ptr<pit::Entry>(pitEntry)));
|
||||
}
|
||||
|
||||
void
|
||||
NccStrategy::doPropagate(FaceId inFaceId, weak_ptr<pit::Entry> pitEntryWeak)
|
||||
{
|
||||
Face* inFace = this->getFace(inFaceId);
|
||||
if (inFace == nullptr) {
|
||||
return;
|
||||
}
|
||||
shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
|
||||
if (pitEntry == nullptr) {
|
||||
return;
|
||||
}
|
||||
auto inRecord = pitEntry->getInRecord(*inFace);
|
||||
if (inRecord == pitEntry->in_end()) {
|
||||
return;
|
||||
}
|
||||
const Interest& interest = inRecord->getInterest();
|
||||
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
|
||||
|
||||
PitEntryInfo* pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
|
||||
// pitEntryInfo is guaranteed to exist here, because doPropagate is triggered
|
||||
// from a timer set by NccStrategy.
|
||||
BOOST_ASSERT(pitEntryInfo != nullptr);
|
||||
|
||||
MeasurementsEntryInfo& meInfo = this->getMeasurementsEntryInfo(pitEntry);
|
||||
|
||||
shared_ptr<Face> previousFace = meInfo.previousFace.lock();
|
||||
if (previousFace != nullptr && fibEntry.hasNextHop(*previousFace) &&
|
||||
!wouldViolateScope(*inFace, interest, *previousFace) &&
|
||||
canForwardToLegacy(*pitEntry, *previousFace)) {
|
||||
this->sendInterest(pitEntry, *previousFace, interest);
|
||||
}
|
||||
|
||||
bool isForwarded = false;
|
||||
for (const auto& nexthop : fibEntry.getNextHops()) {
|
||||
Face& face = nexthop.getFace();
|
||||
if (!wouldViolateScope(*inFace, interest, face) &&
|
||||
canForwardToLegacy(*pitEntry, face)) {
|
||||
isForwarded = true;
|
||||
this->sendInterest(pitEntry, face, interest);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isForwarded) {
|
||||
std::uniform_int_distribution<time::nanoseconds::rep> dist(0, pitEntryInfo->maxInterval.count() - 1);
|
||||
time::nanoseconds deferNext(dist(ndn::random::getRandomNumberEngine()));
|
||||
pitEntryInfo->propagateTimer = getScheduler().schedule(deferNext,
|
||||
bind(&NccStrategy::doPropagate, this, inFaceId, weak_ptr<pit::Entry>(pitEntry)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NccStrategy::timeoutOnBestFace(weak_ptr<pit::Entry> pitEntryWeak)
|
||||
{
|
||||
shared_ptr<pit::Entry> pitEntry = pitEntryWeak.lock();
|
||||
if (pitEntry == nullptr) {
|
||||
return;
|
||||
}
|
||||
measurements::Entry* measurementsEntry = this->getMeasurements().get(*pitEntry);
|
||||
|
||||
for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
|
||||
if (measurementsEntry == nullptr) {
|
||||
// going out of this strategy's namespace
|
||||
break;
|
||||
}
|
||||
this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
|
||||
|
||||
MeasurementsEntryInfo& meInfo = this->getMeasurementsEntryInfo(measurementsEntry);
|
||||
meInfo.adjustPredictUp();
|
||||
|
||||
measurementsEntry = this->getMeasurements().getParent(*measurementsEntry);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NccStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const FaceEndpoint& ingress, const Data& data)
|
||||
{
|
||||
if (!pitEntry->hasInRecords()) {
|
||||
// PIT entry has already been satisfied (and is now waiting for straggler timer to expire)
|
||||
// NCC does not collect measurements for non-best face
|
||||
return;
|
||||
}
|
||||
|
||||
measurements::Entry* measurementsEntry = this->getMeasurements().get(*pitEntry);
|
||||
|
||||
for (int i = 0; i < UPDATE_MEASUREMENTS_N_LEVELS; ++i) {
|
||||
if (measurementsEntry == nullptr) {
|
||||
// going out of this strategy's namespace
|
||||
return;
|
||||
}
|
||||
this->getMeasurements().extendLifetime(*measurementsEntry, MEASUREMENTS_LIFETIME);
|
||||
|
||||
MeasurementsEntryInfo& meInfo = this->getMeasurementsEntryInfo(measurementsEntry);
|
||||
meInfo.updateBestFace(ingress.face);
|
||||
|
||||
measurementsEntry = this->getMeasurements().getParent(*measurementsEntry);
|
||||
}
|
||||
|
||||
PitEntryInfo* pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
|
||||
if (pitEntryInfo != nullptr) {
|
||||
pitEntryInfo->propagateTimer.cancel();
|
||||
|
||||
// Verify that the best face satisfied the interest before canceling the timeout call
|
||||
MeasurementsEntryInfo& meInfo = this->getMeasurementsEntryInfo(pitEntry);
|
||||
shared_ptr<Face> bestFace = meInfo.getBestFace();
|
||||
|
||||
if (bestFace.get() == &ingress.face)
|
||||
pitEntryInfo->bestFaceTimeout.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
NccStrategy::MeasurementsEntryInfo&
|
||||
NccStrategy::getMeasurementsEntryInfo(const shared_ptr<pit::Entry>& entry)
|
||||
{
|
||||
measurements::Entry* measurementsEntry = this->getMeasurements().get(*entry);
|
||||
return this->getMeasurementsEntryInfo(measurementsEntry);
|
||||
}
|
||||
|
||||
NccStrategy::MeasurementsEntryInfo&
|
||||
NccStrategy::getMeasurementsEntryInfo(measurements::Entry* entry)
|
||||
{
|
||||
BOOST_ASSERT(entry != nullptr);
|
||||
MeasurementsEntryInfo* info = nullptr;
|
||||
bool isNew = false;
|
||||
std::tie(info, isNew) = entry->insertStrategyInfo<MeasurementsEntryInfo>();
|
||||
if (!isNew) {
|
||||
return *info;
|
||||
}
|
||||
|
||||
measurements::Entry* parentEntry = this->getMeasurements().getParent(*entry);
|
||||
if (parentEntry != nullptr) {
|
||||
MeasurementsEntryInfo& parentInfo = this->getMeasurementsEntryInfo(parentEntry);
|
||||
info->inheritFrom(parentInfo);
|
||||
}
|
||||
|
||||
return *info;
|
||||
}
|
||||
|
||||
const time::microseconds NccStrategy::MeasurementsEntryInfo::INITIAL_PREDICTION = 8192_us;
|
||||
const time::microseconds NccStrategy::MeasurementsEntryInfo::MIN_PREDICTION = 127_us;
|
||||
const time::microseconds NccStrategy::MeasurementsEntryInfo::MAX_PREDICTION = 160_ms;
|
||||
|
||||
NccStrategy::MeasurementsEntryInfo::MeasurementsEntryInfo()
|
||||
: prediction(INITIAL_PREDICTION)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NccStrategy::MeasurementsEntryInfo::inheritFrom(const MeasurementsEntryInfo& other)
|
||||
{
|
||||
this->operator=(other);
|
||||
}
|
||||
|
||||
shared_ptr<Face>
|
||||
NccStrategy::MeasurementsEntryInfo::getBestFace()
|
||||
{
|
||||
shared_ptr<Face> best = this->bestFace.lock();
|
||||
if (best != nullptr) {
|
||||
return best;
|
||||
}
|
||||
this->bestFace = best = this->previousFace.lock();
|
||||
return best;
|
||||
}
|
||||
|
||||
void
|
||||
NccStrategy::MeasurementsEntryInfo::updateBestFace(const Face& face)
|
||||
{
|
||||
if (this->bestFace.expired()) {
|
||||
this->bestFace = const_cast<Face&>(face).shared_from_this();
|
||||
return;
|
||||
}
|
||||
shared_ptr<Face> bestFace = this->bestFace.lock();
|
||||
if (bestFace.get() == &face) {
|
||||
this->adjustPredictDown();
|
||||
}
|
||||
else {
|
||||
this->previousFace = this->bestFace;
|
||||
this->bestFace = const_cast<Face&>(face).shared_from_this();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NccStrategy::MeasurementsEntryInfo::adjustPredictDown()
|
||||
{
|
||||
prediction = std::max(MIN_PREDICTION,
|
||||
time::microseconds(prediction.count() - (prediction.count() >> ADJUST_PREDICT_DOWN_SHIFT)));
|
||||
}
|
||||
|
||||
void
|
||||
NccStrategy::MeasurementsEntryInfo::adjustPredictUp()
|
||||
{
|
||||
prediction = std::min(MAX_PREDICTION,
|
||||
time::microseconds(prediction.count() + (prediction.count() >> ADJUST_PREDICT_UP_SHIFT)));
|
||||
}
|
||||
|
||||
void
|
||||
NccStrategy::MeasurementsEntryInfo::ageBestFace()
|
||||
{
|
||||
this->previousFace = this->bestFace;
|
||||
this->bestFace.reset();
|
||||
}
|
||||
|
||||
NccStrategy::PitEntryInfo::~PitEntryInfo()
|
||||
{
|
||||
bestFaceTimeout.cancel();
|
||||
propagateTimer.cancel();
|
||||
}
|
||||
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
@@ -0,0 +1,143 @@
|
||||
/* -*- 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/>.
|
||||
*/
|
||||
|
||||
#ifndef NFD_DAEMON_FW_NCC_STRATEGY_HPP
|
||||
#define NFD_DAEMON_FW_NCC_STRATEGY_HPP
|
||||
|
||||
#include "strategy.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
/** \brief A forwarding strategy similar to CCNx 0.7.2
|
||||
*/
|
||||
class NccStrategy : public Strategy
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
NccStrategy(Forwarder& forwarder, const Name& name = getStrategyName());
|
||||
|
||||
static const Name&
|
||||
getStrategyName();
|
||||
|
||||
void
|
||||
afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
void
|
||||
beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const FaceEndpoint& ingress, const Data& data) override;
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PROTECTED:
|
||||
/// StrategyInfo on measurements::Entry
|
||||
class MeasurementsEntryInfo : public StrategyInfo
|
||||
{
|
||||
public:
|
||||
static constexpr int
|
||||
getTypeId()
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
|
||||
MeasurementsEntryInfo();
|
||||
|
||||
void
|
||||
inheritFrom(const MeasurementsEntryInfo& other);
|
||||
|
||||
shared_ptr<Face>
|
||||
getBestFace();
|
||||
|
||||
void
|
||||
updateBestFace(const Face& face);
|
||||
|
||||
void
|
||||
adjustPredictUp();
|
||||
|
||||
private:
|
||||
void
|
||||
adjustPredictDown();
|
||||
|
||||
void
|
||||
ageBestFace();
|
||||
|
||||
public:
|
||||
weak_ptr<Face> bestFace;
|
||||
weak_ptr<Face> previousFace;
|
||||
time::microseconds prediction;
|
||||
|
||||
static const time::microseconds INITIAL_PREDICTION;
|
||||
static const time::microseconds MIN_PREDICTION;
|
||||
static const int ADJUST_PREDICT_DOWN_SHIFT = 7;
|
||||
static const time::microseconds MAX_PREDICTION;
|
||||
static const int ADJUST_PREDICT_UP_SHIFT = 3;
|
||||
};
|
||||
|
||||
/// StrategyInfo on pit::Entry
|
||||
class PitEntryInfo : public StrategyInfo
|
||||
{
|
||||
public:
|
||||
static constexpr int
|
||||
getTypeId()
|
||||
{
|
||||
return 1001;
|
||||
}
|
||||
|
||||
~PitEntryInfo() override;
|
||||
|
||||
public:
|
||||
/// timer that expires when best face does not respond within predicted time
|
||||
scheduler::EventId bestFaceTimeout;
|
||||
/// timer for propagating to another face
|
||||
scheduler::EventId propagateTimer;
|
||||
/// maximum interval between forwarding to two nexthops except best and previous
|
||||
time::microseconds maxInterval;
|
||||
};
|
||||
|
||||
protected:
|
||||
MeasurementsEntryInfo&
|
||||
getMeasurementsEntryInfo(measurements::Entry* entry);
|
||||
|
||||
MeasurementsEntryInfo&
|
||||
getMeasurementsEntryInfo(const shared_ptr<pit::Entry>& entry);
|
||||
|
||||
/// propagate to another upstream
|
||||
void
|
||||
doPropagate(FaceId inFaceId, weak_ptr<pit::Entry> pitEntryWeak);
|
||||
|
||||
/// best face did not reply within prediction
|
||||
void
|
||||
timeoutOnBestFace(weak_ptr<pit::Entry> pitEntryWeak);
|
||||
|
||||
protected:
|
||||
static const time::microseconds DEFER_FIRST_WITHOUT_BEST_FACE;
|
||||
static const time::microseconds DEFER_RANGE_WITHOUT_BEST_FACE;
|
||||
static const int UPDATE_MEASUREMENTS_N_LEVELS = 2;
|
||||
static const time::nanoseconds MEASUREMENTS_LIFETIME;
|
||||
};
|
||||
|
||||
} // namespace fw
|
||||
} // namespace nfd
|
||||
|
||||
#endif // NFD_DAEMON_FW_NCC_STRATEGY_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -32,7 +32,7 @@ namespace fw {
|
||||
NFD_LOG_INIT(ProcessNackTraits);
|
||||
|
||||
void
|
||||
ProcessNackTraitsBase::processNack(const lp::Nack& nack, const Face& inFace,
|
||||
ProcessNackTraitsBase::processNack(const Face& inFace, const lp::Nack& nack,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
int nOutRecordsNotNacked = 0;
|
||||
@@ -56,7 +56,7 @@ ProcessNackTraitsBase::processNack(const lp::Nack& nack, const Face& inFace,
|
||||
|
||||
if (nOutRecordsNotNacked == 1) {
|
||||
BOOST_ASSERT(lastFaceNotNacked != nullptr);
|
||||
auto inR = pitEntry->getInRecord(*lastFaceNotNacked);
|
||||
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-2021, 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,7 +31,7 @@
|
||||
namespace nfd {
|
||||
namespace fw {
|
||||
|
||||
/** \brief Provides a common procedure for processing Nacks
|
||||
/** \brief provides a common procedure for processing Nacks
|
||||
*
|
||||
* This procedure works as follows:
|
||||
* 1. If Nacks have been received from all upstream faces, return a Nack with least severe reason
|
||||
@@ -44,7 +44,7 @@ namespace fw {
|
||||
*
|
||||
* To use this helper, the strategy should inherit from ProcessNackTraits<MyStrategy>,
|
||||
* and declare that specialization as a friend class.
|
||||
* Then, invoke processNack() from the Strategy::afterReceiveNack() trigger.
|
||||
* Then, invoke processNack from afterReceiveNack trigger.
|
||||
*/
|
||||
class ProcessNackTraitsBase : noncopyable
|
||||
{
|
||||
@@ -53,7 +53,7 @@ protected:
|
||||
~ProcessNackTraitsBase() = default;
|
||||
|
||||
void
|
||||
processNack(const lp::Nack& nack, const Face& inFace,
|
||||
processNack(const Face& inFace, const lp::Nack& nack,
|
||||
const shared_ptr<pit::Entry>& pitEntry);
|
||||
|
||||
private:
|
||||
@@ -81,14 +81,14 @@ private:
|
||||
sendNackForProcessNackTraits(const shared_ptr<pit::Entry>& pitEntry, Face& outFace,
|
||||
const lp::NackHeader& header) override
|
||||
{
|
||||
m_strategy->sendNack(header, outFace, pitEntry);
|
||||
m_strategy->sendNack(pitEntry, outFace, header);
|
||||
}
|
||||
|
||||
void
|
||||
sendNacksForProcessNackTraits(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const lp::NackHeader& header) override
|
||||
{
|
||||
m_strategy->sendNacks(header, pitEntry);
|
||||
m_strategy->sendNacks(pitEntry, header);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,12 +52,12 @@ RandomStrategy::RandomStrategy(Forwarder& forwarder, const Name& name)
|
||||
const Name&
|
||||
RandomStrategy::getStrategyName()
|
||||
{
|
||||
static const auto strategyName = Name("/localhost/nfd/strategy/random").appendVersion(1);
|
||||
static Name strategyName("/localhost/nfd/strategy/random/%FD%01");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
void
|
||||
RandomStrategy::afterReceiveInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
RandomStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
|
||||
@@ -71,20 +71,20 @@ RandomStrategy::afterReceiveInterest(const Interest& interest, const FaceEndpoin
|
||||
|
||||
lp::NackHeader nackHeader;
|
||||
nackHeader.setReason(lp::NackReason::NO_ROUTE);
|
||||
this->sendNack(nackHeader, ingress.face, pitEntry);
|
||||
this->sendNack(pitEntry, ingress.face, nackHeader);
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
return;
|
||||
}
|
||||
|
||||
std::shuffle(nhs.begin(), nhs.end(), ndn::random::getRandomNumberEngine());
|
||||
this->sendInterest(interest, nhs.front().getFace(), pitEntry);
|
||||
this->sendInterest(pitEntry, nhs.front().getFace(), interest);
|
||||
}
|
||||
|
||||
void
|
||||
RandomStrategy::afterReceiveNack(const lp::Nack& nack, const FaceEndpoint& ingress,
|
||||
RandomStrategy::afterReceiveNack(const FaceEndpoint& ingress, const lp::Nack& nack,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
this->processNack(nack, ingress.face, pitEntry);
|
||||
this->processNack(ingress.face, nack, pitEntry);
|
||||
}
|
||||
|
||||
} // namespace fw
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,13 +46,12 @@ public:
|
||||
static const Name&
|
||||
getStrategyName();
|
||||
|
||||
public: // triggers
|
||||
void
|
||||
afterReceiveInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
void
|
||||
afterReceiveNack(const lp::Nack& nack, const FaceEndpoint& ingress,
|
||||
afterReceiveNack(const FaceEndpoint& ingress, const lp::Nack& nack,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -32,7 +32,7 @@ const RetxSuppressionExponential::Duration RetxSuppressionExponential::DEFAULT_I
|
||||
const RetxSuppressionExponential::Duration RetxSuppressionExponential::DEFAULT_MAX_INTERVAL = 250_ms;
|
||||
const float RetxSuppressionExponential::DEFAULT_MULTIPLIER = 2.0f;
|
||||
|
||||
class RetxSuppressionExponential::PitInfo final : public StrategyInfo
|
||||
class RetxSuppressionExponential::PitInfo : public StrategyInfo
|
||||
{
|
||||
public:
|
||||
static constexpr int
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, Regents of the University of California,
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -44,9 +44,9 @@ RetxSuppressionFixed::decidePerPitEntry(pit::Entry& pitEntry) const
|
||||
return RetxSuppressionResult::NEW;
|
||||
}
|
||||
|
||||
auto lastOutgoing = getLastOutgoing(pitEntry);
|
||||
auto now = time::steady_clock::now();
|
||||
auto sinceLastOutgoing = now - lastOutgoing;
|
||||
time::steady_clock::TimePoint lastOutgoing = getLastOutgoing(pitEntry);
|
||||
time::steady_clock::TimePoint now = time::steady_clock::now();
|
||||
time::steady_clock::Duration sinceLastOutgoing = now - lastOutgoing;
|
||||
bool shouldSuppress = sinceLastOutgoing < m_minRetxInterval;
|
||||
return shouldSuppress ? RetxSuppressionResult::SUPPRESS : RetxSuppressionResult::FORWARD;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2021, 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,
|
||||
@@ -61,12 +61,12 @@ SelfLearningStrategy::SelfLearningStrategy(Forwarder& forwarder, const Name& nam
|
||||
const Name&
|
||||
SelfLearningStrategy::getStrategyName()
|
||||
{
|
||||
static const auto strategyName = Name("/localhost/nfd/strategy/self-learning").appendVersion(1);
|
||||
static Name strategyName("/localhost/nfd/strategy/self-learning/%FD%01");
|
||||
return strategyName;
|
||||
}
|
||||
|
||||
void
|
||||
SelfLearningStrategy::afterReceiveInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
SelfLearningStrategy::afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
|
||||
@@ -80,7 +80,7 @@ SelfLearningStrategy::afterReceiveInterest(const Interest& interest, const FaceE
|
||||
NFD_LOG_DEBUG("NACK non-discovery Interest=" << interest << " from=" << ingress << " noNextHop");
|
||||
lp::NackHeader nackHeader;
|
||||
nackHeader.setReason(lp::NackReason::NO_ROUTE);
|
||||
this->sendNack(nackHeader, ingress.face, pitEntry);
|
||||
this->sendNack(pitEntry, ingress.face, nackHeader);
|
||||
this->rejectPendingInterest(pitEntry);
|
||||
}
|
||||
else { // multicast it if matching FIB entry exists
|
||||
@@ -100,8 +100,8 @@ SelfLearningStrategy::afterReceiveInterest(const Interest& interest, const FaceE
|
||||
}
|
||||
|
||||
void
|
||||
SelfLearningStrategy::afterReceiveData(const Data& data, const FaceEndpoint& ingress,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
SelfLearningStrategy::afterReceiveData(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const FaceEndpoint& ingress, const Data& data)
|
||||
{
|
||||
auto outRecord = pitEntry->getOutRecord(ingress.face);
|
||||
if (outRecord == pitEntry->out_end()) {
|
||||
@@ -112,7 +112,7 @@ SelfLearningStrategy::afterReceiveData(const Data& data, const FaceEndpoint& ing
|
||||
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(data, pitEntry, ingress.face);
|
||||
sendDataToAll(pitEntry, ingress.face, data);
|
||||
}
|
||||
else { // needs a PA (to respond discovery Interest)
|
||||
asyncProcessData(pitEntry, ingress.face, data);
|
||||
@@ -125,12 +125,12 @@ SelfLearningStrategy::afterReceiveData(const Data& data, const FaceEndpoint& ing
|
||||
}
|
||||
else { // Data contains no PrefixAnnouncement, upstreams do not support self-learning
|
||||
}
|
||||
sendDataToAll(data, pitEntry, ingress.face);
|
||||
sendDataToAll(pitEntry, ingress.face, data);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SelfLearningStrategy::afterReceiveNack(const lp::Nack& nack, const FaceEndpoint& ingress,
|
||||
SelfLearningStrategy::afterReceiveNack(const FaceEndpoint& ingress, const lp::Nack& nack,
|
||||
const shared_ptr<pit::Entry>& pitEntry)
|
||||
{
|
||||
NFD_LOG_DEBUG("Nack for " << nack.getInterest() << " from=" << ingress
|
||||
@@ -138,7 +138,7 @@ SelfLearningStrategy::afterReceiveNack(const lp::Nack& nack, const FaceEndpoint&
|
||||
if (nack.getReason() == lp::NackReason::NO_ROUTE) { // remove FIB entries
|
||||
BOOST_ASSERT(this->lookupFib(*pitEntry).hasNextHops());
|
||||
NFD_LOG_DEBUG("Send NACK to all downstreams");
|
||||
this->sendNacks(nack.getHeader(), pitEntry);
|
||||
this->sendNacks(pitEntry, nack.getHeader());
|
||||
renewRoute(nack.getInterest().getName(), ingress.face.getId(), 0_ms);
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ SelfLearningStrategy::broadcastInterest(const Interest& interest, const Face& in
|
||||
|
||||
NFD_LOG_DEBUG("send discovery Interest=" << interest << " from=" << inFace.getId() <<
|
||||
" to=" << outFace.getId());
|
||||
auto outRecord = this->sendInterest(interest, outFace, pitEntry);
|
||||
auto outRecord = this->sendInterest(pitEntry, outFace, interest);
|
||||
if (outRecord != nullptr) {
|
||||
outRecord->insertStrategyInfo<OutRecordInfo>().first->isNonDiscoveryInterest = false;
|
||||
}
|
||||
@@ -176,7 +176,7 @@ SelfLearningStrategy::multicastInterest(const Interest& interest, const Face& in
|
||||
Face& outFace = nexthop.getFace();
|
||||
NFD_LOG_DEBUG("send non-discovery Interest=" << interest << " from=" << inFace.getId() <<
|
||||
" to=" << outFace.getId());
|
||||
auto outRecord = this->sendInterest(interest, outFace, pitEntry);
|
||||
auto outRecord = this->sendInterest(pitEntry, outFace, interest);
|
||||
if (outRecord != nullptr) {
|
||||
outRecord->insertStrategyInfo<OutRecordInfo>().first->isNonDiscoveryInterest = true;
|
||||
}
|
||||
@@ -201,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(data, pitEntry, *inFace);
|
||||
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-2021, 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,
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
getStrategyName();
|
||||
|
||||
/// StrategyInfo on pit::InRecord
|
||||
class InRecordInfo final : public StrategyInfo
|
||||
class InRecordInfo : public StrategyInfo
|
||||
{
|
||||
public:
|
||||
static constexpr int
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
};
|
||||
|
||||
/// StrategyInfo on pit::OutRecord
|
||||
class OutRecordInfo final : public StrategyInfo
|
||||
class OutRecordInfo : public StrategyInfo
|
||||
{
|
||||
public:
|
||||
static constexpr int
|
||||
@@ -79,18 +79,19 @@ public:
|
||||
|
||||
public: // triggers
|
||||
void
|
||||
afterReceiveInterest(const Interest& interest, const FaceEndpoint& ingress,
|
||||
afterReceiveInterest(const FaceEndpoint& ingress, const Interest& interest,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
void
|
||||
afterReceiveData(const Data& data, const FaceEndpoint& ingress,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
afterReceiveData(const shared_ptr<pit::Entry>& pitEntry,
|
||||
const FaceEndpoint& ingress, const Data& data) override;
|
||||
|
||||
void
|
||||
afterReceiveNack(const lp::Nack& nack, const FaceEndpoint& ingress,
|
||||
afterReceiveNack(const FaceEndpoint& ingress, const lp::Nack& nack,
|
||||
const shared_ptr<pit::Entry>& pitEntry) override;
|
||||
|
||||
private: // operations
|
||||
|
||||
/** \brief Send an Interest to all possible faces
|
||||
*
|
||||
* This function is invoked when the forwarder has no matching FIB entries for
|
||||
|
||||
Loaded 100 of 259 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user