Compare commits

..
4 Commits
Author SHA1 Message Date
baihe a4eb0fb1b6 fix: Disable rate limit in compare scenario 2024-01-20 07:04:42 +00:00
root 1a792daaa3 feat(qsccp): Add QSCCP strategy 2023-12-18 12:49:43 +08:00
SunnyQjm 34e13e9802 fix: Do calculateRate by trigger not by scheduler 2023-12-15 14:55:20 +00:00
SunnyQjm 3813f1c9ee feat: Add qsccp sched 2023-12-03 21:08:06 +08:00
259 changed files with 6374 additions and 3894 deletions

No files matched your search

-68
View File
@@ -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
-40
View File
@@ -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
+13 -7
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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:
-17
View File
@@ -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
+81
View File
@@ -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
View File
@@ -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.
![Web page showing what the "identities" panel looks like](./docs/images/gerrit-credentials-blurred.png)
In that case, add it under contact information panel.
![Web page showing what the "contact information" panel looks like](./docs/images/gerrit-email.png).
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
+3 -4
View File
@@ -1,9 +1,8 @@
# NFD - Named Data Networking Forwarding Daemon
[![CI](https://github.com/named-data/NFD/actions/workflows/ci.yml/badge.svg)](https://github.com/named-data/NFD/actions/workflows/ci.yml)
[![Docs](https://github.com/named-data/NFD/actions/workflows/docs.yml/badge.svg)](https://github.com/named-data/NFD/actions/workflows/docs.yml)
![Language](https://img.shields.io/badge/C%2B%2B-14-blue)
![Latest version](https://img.shields.io/github/v/tag/named-data/NFD?label=Latest%20version)
![Language](https://img.shields.io/badge/C%2B%2B-14-blue.svg)
[![Build Status](https://travis-ci.org/named-data/NFD.svg?branch=master)](https://travis-ci.org/named-data/NFD)
![Latest Version](https://img.shields.io/github/tag/named-data/NFD.svg?color=darkkhaki&label=latest%20version)
## Overview
+20 -17
View File
@@ -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
View File
@@ -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[];
+2 -19
View File
@@ -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
+2 -2
View File
@@ -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()
{
+2 -2
View File
@@ -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().
+9 -9
View File
@@ -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
+6 -6
View File
@@ -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
+62
View File
@@ -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;
}
}
}
}
+41
View File
@@ -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 -7
View File
@@ -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
View File
@@ -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
+10 -10
View File
@@ -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,
+14 -9
View File
@@ -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,
+5 -6
View File
@@ -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);
+5 -5
View File
@@ -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
+7 -6
View File
@@ -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)
+4 -4
View File
@@ -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
+18 -15
View File
@@ -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*>(&ethertype), ethernet::TYPE_LEN});
buffer.prependBytes(m_srcAddress);
buffer.prependBytes(m_destAddress);
buffer.prependByteArray(reinterpret_cast<const uint8_t*>(&ethertype), 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
+5 -3
View File
@@ -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,
+1
View File
@@ -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;
+3 -3
View File
@@ -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)
{
}
+2 -4
View File
@@ -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
+3 -3
View File
@@ -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
View File
@@ -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);
+93 -27
View File
@@ -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;
}
+19 -12
View File
@@ -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;
};
+11 -1
View File
@@ -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
+5 -2
View File
@@ -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
+6 -5
View File
@@ -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
+7 -5
View File
@@ -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
+5 -5
View File
@@ -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;
+2 -2
View File
@@ -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)
+3 -3
View File
@@ -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;
+5 -9
View File
@@ -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
+2 -2
View File
@@ -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;
};
+4 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+534
View File
@@ -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);
}
}
}
}
+309
View File
@@ -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
+5 -6
View File
@@ -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);
}
+8 -14
View File
@@ -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
+5 -6
View File
@@ -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,
+3 -4
View File
@@ -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;
}
+6 -6
View File
@@ -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;
};
+7 -7
View File
@@ -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;
+10 -7
View File
@@ -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,
+5 -6
View File
@@ -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();
}
+3 -13
View File
@@ -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 {};
}
+5 -6
View File
@@ -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
+5 -5
View File
@@ -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;
}
+4 -4
View File
@@ -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;
+2 -2
View File
@@ -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
+6 -6
View File
@@ -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);
+6 -6
View File
@@ -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
+4 -4
View File
@@ -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;
+2 -2
View File
@@ -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;
+3 -5
View File
@@ -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
+17 -17
View File
@@ -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) {
+11 -11
View File
@@ -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
View File
@@ -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
View File
@@ -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
+11 -11
View File
@@ -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
+10 -10
View File
@@ -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
+6 -6
View File
@@ -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);
+3 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+30 -80
View File
@@ -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
+21 -35
View File
@@ -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
+134
View File
@@ -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
+82
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+20 -26
View File
@@ -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
+8 -5
View File
@@ -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;
};
+345
View File
@@ -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
+143
View File
@@ -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
+3 -3
View File
@@ -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() <<
+6 -6
View File
@@ -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:
+527
View File
@@ -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));
}
}
}
}
+171
View File
@@ -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;
};
}
}
+7 -7
View File
@@ -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
+3 -4
View File
@@ -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:
+2 -2
View File
@@ -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
+4 -4
View File
@@ -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;
}
+13 -13
View File
@@ -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 {
+8 -7
View File
@@ -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