Compare commits

..
76 Commits
Author SHA1 Message Date
Davide Pesavento 3bc8e19a89 Prepare release 22.12
Refs: #5250
Change-Id: I6b9a3daab498cbffb78a108207e92bc2596be378
2022-12-31 01:40:11 -05:00
Davide Pesavento 0b0156887b face: put the pcap handle in non-blocking mode
This prevents NFD from getting stuck in pcap_next_ex()
when the network interface goes down

Change-Id: I5760fcc7c950b46aecb7619bd889508ee24133aa
2022-12-12 22:01:28 -05:00
Davide Pesavento 6b78a53cf7 build: update waf to version 2.0.24
Change-Id: I57b597fb5933e46b55979ad6b1a62a7fd40c645d
2022-12-02 18:24:16 -05:00
Ikko Ashimine a68af8129e docs: fix typo in release-notes-22.02.rst
accomodate -> accommodate

Closes: https://github.com/named-data/NFD/pull/11
Change-Id: Ibad215a723cd51881760d2e43c05694a0e8928fe
2022-11-25 22:15:12 -05:00
Davide Pesavento a42efcb408 ci: add Xcode 14.1
Change-Id: I8415fb1375da16813a69fa7a03bf37a7b0efc8b7
2022-11-15 02:43:16 -05:00
Davide Pesavento aa9e3b2148 docs: fix capitalization in doxygen comments
Change-Id: Ibf5ee5119d12d60d382b0acef8dfd08277c18fcb
2022-10-29 21:45:24 -04:00
Davide Pesavento b83d3df256 mgmt: finalize migration to the new signed Interest format
Change-Id: I6d3fe1bd092fa80e185d36746a42c188ab00a60e
2022-10-13 09:45:33 -04:00
Davide Pesavento 6d6f207661 mgmt: rename extractRequester() and support signed Interest v0.3
Change-Id: I6bb6635896fa1b9fa54beb70b902c5a35831dc9c
2022-10-13 08:55:42 -04:00
Davide Pesavento 9bfdaef62d build: link with lld if available
Change-Id: Ie390c511c711508b6bb8c326a9a62fb1eca291c5
2022-10-05 17:38:44 -04:00
Davide Pesavento 20d94f67f8 Use inline on all namespace-scope constants defined in headers
Change-Id: Ic61f8d26f59fdc2895415ca47065c02d6eec28ed
2022-09-26 03:30:53 -04:00
Davide Pesavento 36184f6893 docs: restore exception handling in conf.py
Change-Id: Ie6408385e821e509e964bcea001a39f8cfdc5da0
2022-09-25 03:48:58 -04:00
Davide Pesavento 6cc9541220 docs: simplify conf.py and fix compatibility with upcoming Sphinx 6.0
Change-Id: Iacf4a72d30babc4a7c3fab0fea619a798eff2df1
2022-09-20 19:10:55 -04:00
Davide Pesavento 279af1ceac tests: fix UDP multicast transport tests with IPv6
A valid scope id is always required on the multicast address

Change-Id: Ic676fcde0ee50daf75eb38c137e3cb917f43699f
2022-08-29 20:18:32 -04:00
Teng Liang d94b7b3b24 face: reimplement EndpointId with std::variant
Refs: #5041
Change-Id: Ib8aced49a7aa14b137fb06de4a0ae8b979f07587
2022-08-24 19:38:47 -04:00
Davide Pesavento e541d1b250 build+ci: support macOS on arm64
Refs: #5135
Change-Id: I86f1955366df12cfb8b3e6f9d5e9f202778cc211
2022-08-18 20:50:05 -04:00
Davide Pesavento 4791fcb8ba ci: refresh GitHub Actions matrix
* Add ubuntu-22.04, remove 18.04
 * Add macos-12, remove 10.15

Change-Id: I775ea45661259ba1353e3f6ee0c602abee58acbd
2022-08-14 17:40:05 -04:00
Davide Pesavento 72517b5510 ci: auto-detect the OS instead of relying on NODE_LABELS
And remove WAF_JOBS: waf already defaults to the number of available
CPUs, which is appropriate in most cases, and we can always use the
built-in JOBS variable to override it where necessary.

Change-Id: I555dda0ccc48ee791271dbdaf4225cd1cfec4f3d
2022-08-13 18:50:55 -04:00
Davide Pesavento 20cafa8715 tests: minor code cleanups
Change-Id: I9759ba4b7eb467d4d1df4b379efad91bc4f5cc3a
2022-07-25 01:15:03 -04:00
Davide Pesavento 2150da8ee5 build+docs: support CentOS Stream 9, drop CentOS 8
Refs: #5181
Change-Id: I2d8bc595bad047ceaa78bd3729848491b843e83d
2022-07-08 18:18:51 -04:00
Davide Pesavento 990620ac3b nfdc: merge canonizer.hpp and find-face.hpp into face-helpers.hpp
Change-Id: I19ca5cbce8cab54e61eb7af0a32c33c3aa73faf1
2022-06-13 16:33:25 -04:00
Davide Pesavento a9b09b6994 build: make precompiled headers more useful
This can reduce the compilation time of a release
build (without tests) by more than 40%

Refs: #5212
Change-Id: I977aff0c0c7becbfee8a8b55605b81d0c014829b
2022-06-13 16:30:11 -04:00
Davide Pesavento 9a28c3f752 fw+table: workaround bogus doxygen warnings
Change-Id: I0a093658f4b27620ba9731a0640ca71c3d03360a
2022-06-11 21:52:05 -04:00
Davide Pesavento e422f9e1e9 Refactor and modernize namespace declarations
Move all unit tests to namespace nfd::tests

Delete unused header core/algorithm.hpp

Change-Id: I5591f0c5f3bb5db67f8b45fae95471f8a555ca68
2022-06-11 20:10:26 -04:00
Davide Pesavento a3a7a4e330 Use more C++17 features
Mainly structured bindings, inline variables, and class template
argument deduction, plus many more smaller things.

Change-Id: I810d17e0adb470426e4e30c898e03b3140ad052f
2022-06-04 20:26:02 -04:00
Davide Pesavento b7bfcb904a build: switch to C++17
Change-Id: Ie68020a04b7e20b74778b6d0370544ded55c5e26
2022-05-23 03:42:32 -04:00
Junxiao Shi 4b84a2c9be tests: expect certificate name in KeyLocator
Also, delete unused KeyChainFixture::makeCert function.

refs #5112

Change-Id: I59b1ca81fca0481a37126270c447f639080ec75f
2022-04-28 03:17:05 +00:00
Davide Pesavento 6153eafa62 ci: require gcovr 5.1 for code coverage reports
Stop passing `-j`, it wasn't very useful and it's broken in gcovr 5.1

Change-Id: I17ffb97c2dc9cd8db7c900fbbd4ab5f8f92184dd
2022-04-19 19:45:03 -04:00
Ashlesh Gawande 1ef93d0316 fw: add strategy parameters to configure exponential retx suppression
Supported by ASF, BestRoute, and Multicast strategies

Refs: #4924
Change-Id: I215d9212d90b93fa622cc65278703dc5198d0c9d
2022-04-08 00:27:27 -04:00
Davide Pesavento deb5427bb4 daemon+tests: avoid deprecated ndn-cxx functions
Change-Id: Idfa341629919d63fac140eda0b465f8f8abd38e6
2022-03-11 18:51:05 -05:00
Davide Pesavento 1b22a8c156 tests: drop redundant calls to Interest::setCanBePrefix(false)
Change-Id: I6afd1028ab370633c64a74ab4310396dab3c8a03
2022-03-07 21:23:23 -05:00
Davide Pesavento c52cd5eec1 build: align minimum build dependencies with ndn-cxx
* boost 1.65.1
 * gcc 7.4
 * clang 6.0
 * Xcode 10.0 (11.3 or later recommended)

Change-Id: I5e41f2a70d6c510dcb889a083a51504121b4627d
2022-03-05 20:40:54 -05:00
Alexander Afanasyev 5006c1d6af Prepare release 22.02
Change-Id: Ie0d8db596c11c4f298755aa4b7fde5e616f32ceb
Refs: #5172, #5184
2022-02-17 16:07:18 -05:00
Davide Pesavento a599d2aac9 Convert to span and avoid deprecated ndn-cxx functions
Change-Id: I45c50527fe53498b53a3d951458bdff8e7d7778c
2022-02-16 18:52:43 -05:00
Junxiao Shi b98aa3aca6 face: handle error in TCP socket remote_endpoint
refs #5158

Change-Id: I67fa134cd01a80a4f91122bbdcfc64e089d8145e
2022-01-12 01:14:08 +00:00
Junxiao Shi 727b61087a table+fw: update ForwardingHint format
refs #5187

Change-Id: Ic8e32c83caeb60404f1b035a4f7e9841cc513f0b
2022-01-11 18:40:04 +00:00
Davide Pesavento 80111b72f9 face: adapt to API change in ndn::Transport
Change-Id: Ib424af03b7ec7d7bccce8d9498da6c593e16362f
2022-01-09 16:32:33 -05:00
Davide Pesavento 07da3fec95 build: update waf to version 2.0.23
Change-Id: I33bccd3f9aacdd22b690b6ff08fabd964dc022db
2021-12-29 19:14:42 -05:00
Alexander Afanasyev 5e02c04ca7 docs: Update sample nfd.conf to allow use of v0.3 Signed Interests
Change-Id: I72769d6caf52718b0e9ce4f6d3d8b0a29cf04925
2021-12-22 23:01:07 -05:00
Alexander Afanasyev c414ca5895 tools: Allow batch command processing by nfdc
Change-Id: Ia6f70fed88f2d4c918e2ca2b786222840dbd9076
Refs: #5169
2021-12-21 14:27:26 -05:00
Davide Pesavento f28a061c22 ci: add macOS 11 Big Sur
Remove all traces of Travis CI

Change-Id: Ie9ad527af4921c4f3c56903851200131ed0d5e87
2021-09-29 23:13:32 -04:00
Saurab Dulal af3ff5a8c6 fw: rename n-silent-timeouts to max-timeouts in AsfStrategy
Change-Id: Ie2790a4e1fd545aacf8b297d7ec33b204f2cdbfc
2021-09-19 19:45:25 -04:00
Davide Pesavento 2c61bad944 ci: use gcovr 5.0 to generate code coverage reports
Change-Id: Ib7284d1616f9bce527aa98ccbb32e58d0bfa9dfb
2021-08-30 22:40:35 -04:00
Davide Pesavento 4d030c3896 Add CITATION.cff
Remove duplicate/obsolete files. Use the corresponding
files in https://github.com/named-data/.github instead.

Change-Id: Ife0d7551dd44091a8343ea233072c22a03149a71
2021-08-30 21:48:42 -04:00
Davide Pesavento 13dae355cb ci: restrict token permissions and add badges to README.md
Change-Id: Ia7e254eefb6658aa5110a7fea5a6847cb257a84b
2021-08-13 15:40:54 -04:00
Davide Pesavento 8f0028de4e ci: add GitHub Actions
Change-Id: Idc715edf136550b088f89c19b581f5478b296653
2021-07-30 19:26:03 -04:00
Davide Pesavento 412c982a63 Reduce usage of std::bind()
C++14 lambdas are easier to read, easier to debug,
and can usually be better optimized by the compiler.

Change-Id: I294f275904f91942a8de946fe63e77078a7608a6
2021-07-02 00:21:05 -04:00
Philipp Moll a103334b1c fw: Add default HopLimit to Interest when missing
Refs: #5171
Change-Id: I5973811b5ca7c7cf5ff344872afa51b253b9cae8
2021-06-25 00:24:23 -04:00
Davide Pesavento 0498ce85b0 fw: reorder function params to make the strategy API more uniform
Also add a non-const overload of Face::getCounters to avoid const_cast

Refs: #5173
Change-Id: Iff0bfbdedb90e68a373090cf3f247d9a7501f58d
2021-06-14 14:18:03 -04:00
Davide Pesavento 7647cc7635 table: increase initial and minimum capacity of DeadNonceList
Change-Id: Iaec6299ed985fcf165e23d31a339a6cbf073b55d
2021-06-10 14:30:04 -04:00
Davide Pesavento e08cc4cd7e table: improve logging in DeadNonceList
Refs: #5165
Change-Id: I97f9e28af90d857b33808d385eb077380cafe00a
2021-06-09 03:03:32 -04:00
Varun Patil 67ad70fbd5 table: prevent duplicates in DeadNonceList
refs #5167

Change-Id: Ia7546f75b844cfa1d857a641b015fbc6e9dfaf3d
2021-06-07 16:18:02 -07:00
Davide Pesavento d69070ef50 ci+docs+tools: stop using deprecated ndnsec commands
Change-Id: If77f479b45581a9a70619c329e713524678e35fb
2021-06-04 18:50:52 -04:00
Davide Pesavento d412393379 table: DeadNonceList code cleanup/modernization
Change-Id: I7d2bb8982b60b138c979470406b0a607301f2768
2021-05-28 19:21:03 -04:00
Davide Pesavento 6a699be8cd tests: use InterestSigner instead of deprecated CommandInterestSigner
Change-Id: Iaf98026c9c0a7ee3950d79f4d810e0a7abba43b1
2021-05-17 02:13:37 -04:00
Davide Pesavento a47cca2634 build: make graphviz optional for building documentation
Change-Id: I5434bbef22c840341623bff16f9e8de129249be2
2021-04-16 02:30:11 -04:00
Eric Newberry 7249fb4d52 docs+tests: finalize migration to typed naming conventions
refs #5044

Change-Id: Ia6f52ae0a31db33ca0f9fa6c4553b8fbbc7809bc
2021-04-05 18:16:44 -04:00
Davide Pesavento 86644d36ff mgmt: don't extend the dataset expiration in ForwarderStatusManager
No other managers do this. Moreover, StatusDatasetContext::setExpiry()
has odd semantics and is being removed from ndn-cxx.

Change-Id: I5255aec5c6464e48f4b4765ae2c06f557e094044
2021-04-02 15:20:16 -04:00
Eric Newberry 358414d82f fw: remove reliance upon marker name components
refs #5044

Change-Id: Iea6c98e03dbd3e4463f7bb6fca0be4953a2cdc40
2021-03-25 21:10:38 -07:00
Davide Pesavento 22085365d2 mgmt: fix construction of CertificateRequest in CommandAuthenticatorValidationPolicy
Just pass the KeyLocator name and let CertificateRequest deal
with constructing the Interest and setting CanBePrefix

Refs: #4582
Change-Id: I323d8ac5e16605bb978addc623e525b2536238bf
2021-03-18 22:08:03 -04:00
Saurab Dulal 432be57380 fw: use per-upstream suppression in ASF strategy
Refs: #5140
Change-Id: I49b27ce6b55d01724d0eafa792785d081c6009f7
2021-03-17 16:50:10 -04:00
Davide Pesavento 3db9807200 daemon: mark some classes and methods 'final'
As suggested by gcc's -Wsuggest-final-types and -Wsuggest-final-methods

Change-Id: I1622857ee53581efd0c6ce3fe93199c72202d817
2021-03-15 18:15:01 -04:00
Davide Pesavento 03a75f6c88 tests: add test case for retx suppression in multicast strategy
Refs: #4066
Change-Id: I78953b91b1fc1c6599b83cd1f39c11722261dd98
2021-03-15 18:14:26 -04:00
Davide Pesavento 7922d12449 fw: rename BestRouteStrategy2 class to BestRouteStrategy
Also rename ad-hoc-forwarding.t.cpp to strategy-ad-hoc-face.t.cpp
and broadcast-medium.t.cpp to strategy-broadcast-medium.t.cpp,
for consistency with the other strategy-*.t.cpp test suites.

Change-Id: Ia8f5257260563732d74c7d58e35481b73a231f06
2021-03-09 20:11:24 -05:00
Davide Pesavento 580915891e fw: remove best-route strategy version 1
Change-Id: I7e86d5c19c01db65a84fdc0f289e7534f0774f4e
2021-03-09 11:45:43 -05:00
Davide Pesavento 29abf4cda2 fw: remove ncc strategy
Change-Id: I6de0acf51e965afcbda5cc943cb39daa78cabf2d
2021-03-09 01:43:46 -05:00
Junxiao Shi a6286a9e5a face: allow setting default UDP face MTU in config
refs #5138

Change-Id: Ibb3767b27aec2b046d1f41292f3d61001866f8c0
2021-02-24 12:11:45 -08:00
Alexander Afanasyev 40604e3a1f fw: Dispatch pending interests on new nexhop in multicast strategy
Change-Id: Ifac7b27c9943bd164d0a6579edc68fb959ebe887
Refs: #4931
2021-02-24 11:49:05 -05:00
Alexander Afanasyev 4400e428d4 fw: Remove NACKs from multicast strategy
Change-Id: I49b833ec0ad990dfdf547aef80915e3fc83389ec
Refs: #5146
2021-02-19 18:45:55 -05:00
Davide Pesavento 05590471e0 fw: eliminate Forwarder::dispatchToStrategy()
Change-Id: Ia2e58c66548644fe3395f7e8c65e860554484fc8
2021-02-17 15:53:27 -05:00
Davide Pesavento b21bed88ed fw: fix and simplify enumeration logic in Forwarder::onNewNextHop()
Also remove Strategy::enableNewNextHopTrigger(). Strategies can already
opt-in by overriding afterNewNextHop(), there is no need for a separate
enablement flag.

Refs: #4931
Change-Id: Ifcbdbc7e954bd20d9969fd99882a2a9aebbc8fcc
2021-02-17 15:09:32 -05:00
Davide Pesavento 264af77369 build: prepend "NFD_" to various macro names to avoid conflicts
Change-Id: Icc370968e3d38fef80ece35a2aed56450f54b653
2021-02-10 14:48:07 -05:00
Junxiao Shi 6aecc500e5 doc: accommodate certificate name in KeyLocator in sample nfd.conf
refs #5114

Change-Id: I648318e035fd06722dedc5181e03c108ac275e66
2021-02-07 13:11:56 -07:00
Junxiao Shi 7fb9071230 face: execute pcap_activate as root
refs #4647

Change-Id: Ib88bbebe5d6495e138b65b5b66865a0001aebef9
2021-01-27 10:31:16 -07:00
Davide Pesavento 9ab43e67db ci+docs: CentOS renamed the PowerTools repo to lowercase
Change-Id: I4b78986f3af17d2124824992e31b408ebe8de03a
2020-12-27 20:50:22 -05:00
Davide Pesavento cabd980030 build: upgrade waf to version 2.0.21
Change-Id: I63a240ce9386076dcfae429f954dc0eadb25f6fc
2020-11-20 01:01:43 -05:00
Davide Pesavento 2135375d36 tests: sync common testing infrastructure with ndn-cxx
Change-Id: I6feab5247231abc35b8daa96bca21ad17c9cc4b3
2020-11-20 00:43:44 -05:00
524 changed files with 8636 additions and 12433 deletions

No files matched your search

+69
View File
@@ -0,0 +1,69 @@
name: CI
on:
push:
paths-ignore:
- 'docs/**'
- '*.md'
- '.mailmap'
workflow_dispatch:
permissions:
contents: read
jobs:
linux:
name: ${{ matrix.compiler }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04]
compiler: [g++-7, g++-8, g++-9, g++-10,
clang++-7, clang++-8, clang++-9, clang++-10, clang++-11, clang++-12]
include:
- os: ubuntu-22.04
compiler: g++-11
- os: ubuntu-22.04
compiler: g++-12
- os: ubuntu-22.04
compiler: clang++-13
- os: ubuntu-22.04
compiler: clang++-14
env:
CXX: ${{ matrix.compiler }}
steps:
- name: Install C++ compiler
run: |
sudo apt-get -qy install ${CXX/clang++/clang}
${CXX} --version
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Build and test
run: ./.jenkins
macos:
name: Xcode ${{ matrix.xcode }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-11]
xcode: ['12.4', '12.5', '13.2']
include:
- os: macos-12
xcode: '13.4'
- os: macos-12
xcode: '14.2'
steps:
- name: Set up Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: ${{ matrix.xcode }}
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Build and test
run: ./.jenkins
+37
View File
@@ -0,0 +1,37 @@
name: Docs
on:
push:
paths-ignore:
- '*.md'
- '.mailmap'
workflow_dispatch:
permissions:
contents: read
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, ubuntu-latest]
env:
JOB_NAME: Docs
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
- name: Install dependencies
run: |
find .jenkins.d/ -type f -name '[1-9]*.sh' -exec chmod -x '{}' +
./.jenkins
- name: Build documentation
run: |
pybindir=$(python3 -c 'import sysconfig; print(sysconfig.get_path("scripts", "posix_user"))')
export PATH="${pybindir}${PATH:+:}${PATH}"
./waf --color=yes configure
./waf --color=yes build --targets=version.hpp
./waf --color=yes build --targets=manpages
./waf --color=yes docs
+33 -16
View File
@@ -1,32 +1,49 @@
#!/usr/bin/env bash
set -e
source .jenkins.d/util.sh
set -eo pipefail
case $(uname) in
Linux)
if [[ -e /etc/os-release ]]; then
source /etc/os-release
else
source /usr/lib/os-release
fi
export ID VERSION_ID
export ID_LIKE="${ID} ${ID_LIKE} linux"
export PATH="${HOME}/.local/bin${PATH:+:}${PATH}"
;;
Darwin)
# Emulate a subset of os-release(5)
export ID=macos
export VERSION_ID=$(sw_vers -productVersion)
export PATH="/usr/local/bin${PATH:+:}${PATH}"
if [[ -x /opt/homebrew/bin/brew ]]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [[ -x /usr/local/bin/brew ]]; then
eval "$(/usr/local/bin/brew shellenv)"
fi
;;
esac
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))'
}
if [[ $JOB_NAME == *"code-coverage" ]]; then
export DISABLE_ASAN=yes
export DISABLE_HEADERS_CHECK=yes
fi
for file in .jenkins.d/*; do
[[ -f $file && -x $file ]] || continue
if [[ -n $TRAVIS ]]; then
if [[ -n $GITHUB_ACTIONS ]]; then
label=$(basename "$file" | sed -E 's/[[:digit:]]+-(.*)\..*/\1/')
echo -ne "travis_fold:start:${label}\r"
echo -ne "travis_time:start:${label}\r"
start=$(nanos)
echo "::group::${label}"
fi
echo "\$ $file"
"$file"
if [[ -n $TRAVIS ]]; then
finish=$(nanos)
echo -ne "travis_time:end:${label}:start=${start},finish=${finish},duration=$((finish-start)),event=${label}\r"
echo -ne "travis_fold:end:${label}\r"
if [[ -n $GITHUB_ACTIONS ]]; then
echo "::endgroup::"
fi
done
+33 -34
View File
@@ -1,41 +1,40 @@
#!/usr/bin/env bash
set -ex
set -eo pipefail
if has OSX $NODE_LABELS; then
FORMULAE=(boost openssl pkg-config)
if has OSX-10.13 $NODE_LABELS || has OSX-10.14 $NODE_LABELS; then
FORMULAE+=(python)
APT_PKGS=(build-essential pkg-config python3-minimal
libboost-all-dev libssl-dev libsqlite3-dev
libpcap-dev libsystemd-dev)
FORMULAE=(boost openssl pkg-config)
PIP_PKGS=()
case $JOB_NAME in
*code-coverage)
APT_PKGS+=(lcov python3-pip)
PIP_PKGS+=('gcovr~=5.2')
;;
*Docs)
APT_PKGS+=(doxygen graphviz python3-pip)
FORMULAE+=(doxygen graphviz)
PIP_PKGS+=(sphinx sphinxcontrib-doxylink)
;;
esac
set -x
if [[ $ID == macos ]]; then
if [[ -n $GITHUB_ACTIONS ]]; then
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
fi
if [[ -n $TRAVIS ]]; then
# Travis images come with a large number of pre-installed
# brew packages, don't waste time upgrading all of them
brew list --versions "${FORMULAE[@]}" || brew update
for FORMULA in "${FORMULAE[@]}"; do
brew list --versions "$FORMULA" || brew install "$FORMULA"
done
# Ensure /usr/local/opt/openssl exists
brew reinstall openssl
else
brew update
brew upgrade
brew install "${FORMULAE[@]}"
brew cleanup
fi
elif has Ubuntu $NODE_LABELS; then
brew update
brew install --formula "${FORMULAE[@]}"
elif [[ $ID_LIKE == *debian* ]]; 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
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 -y install gcc-c++ libasan pkgconf-pkg-config python3 \
sudo apt-get -qy install "${APT_PKGS[@]}"
elif [[ $ID_LIKE == *fedora* ]]; then
sudo dnf -y install gcc-c++ libasan lld pkgconf-pkg-config python3 \
boost-devel openssl-devel sqlite-devel \
libpcap-devel systemd-devel
fi
if (( ${#PIP_PKGS[@]} )); then
pip3 install --user --upgrade --upgrade-strategy=eager "${PIP_PKGS[@]}"
fi
+8 -13
View File
@@ -1,11 +1,11 @@
#!/usr/bin/env bash
set -ex
set -exo pipefail
pushd "$CACHE_DIR" >/dev/null
INSTALLED_VERSION=
if has OSX $NODE_LABELS; then
BOOST=$(brew ls --versions boost)
if [[ $ID == macos ]]; then
BOOST=$(brew list --formula --versions boost)
OLD_BOOST=$(cat boost.txt || :)
if [[ $OLD_BOOST != $BOOST ]]; then
echo "$BOOST" > boost.txt
@@ -35,21 +35,16 @@ sudo rm -f /usr/local/lib{,64}/pkgconfig/libndn-cxx.pc
pushd ndn-cxx >/dev/null
if has CentOS-8 $NODE_LABELS; then
# https://bugzilla.redhat.com/show_bug.cgi?id=1721553
PCH="--without-pch"
fi
./waf --color=yes configure --disable-static --enable-shared --without-osx-keychain $PCH
./waf --color=yes build -j$WAF_JOBS
sudo_preserve_env PATH -- ./waf --color=yes install
./waf --color=yes configure --without-osx-keychain
./waf --color=yes build
sudo ./waf --color=yes install
popd >/dev/null
popd >/dev/null
if has CentOS-8 $NODE_LABELS; then
if [[ $ID_LIKE == *fedora* ]]; then
sudo tee /etc/ld.so.conf.d/ndn.conf >/dev/null <<< /usr/local/lib64
fi
if has Linux $NODE_LABELS; then
if [[ $ID_LIKE == *linux* ]]; then
sudo ldconfig
fi
+8 -10
View File
@@ -1,8 +1,5 @@
#!/usr/bin/env bash
set -ex
git submodule sync
git submodule update --init
set -eo pipefail
if [[ -z $DISABLE_ASAN ]]; then
ASAN="--with-sanitizer=address"
@@ -10,22 +7,23 @@ fi
if [[ $JOB_NAME == *"code-coverage" ]]; then
COVERAGE="--with-coverage"
fi
if has CentOS-8 $NODE_LABELS; then
# https://bugzilla.redhat.com/show_bug.cgi?id=1721553
if [[ -n $DISABLE_PCH ]]; then
PCH="--without-pch"
fi
set -x
if [[ $JOB_NAME != *"code-coverage" && $JOB_NAME != *"limited-build" ]]; then
# Build in release mode with tests and without precompiled headers
./waf --color=yes configure --with-tests --without-pch
./waf --color=yes build -j$WAF_JOBS
./waf --color=yes build
# Cleanup
./waf --color=yes distclean
# Build in release mode without tests, but with "other tests"
./waf --color=yes configure --with-other-tests $PCH
./waf --color=yes build -j$WAF_JOBS
./waf --color=yes build
# Cleanup
./waf --color=yes distclean
@@ -33,9 +31,9 @@ fi
# Build in debug mode with tests
./waf --color=yes configure --debug --with-tests $ASAN $COVERAGE $PCH
./waf --color=yes build -j$WAF_JOBS
./waf --color=yes build
# (tests will be run against the debug version)
# Install
sudo_preserve_env PATH -- ./waf --color=yes install
sudo ./waf --color=yes install
+10 -13
View File
@@ -1,14 +1,5 @@
#!/usr/bin/env bash
set -ex
# Prepare environment
rm -rf ~/.ndn
if has OSX $NODE_LABELS; then
security unlock-keychain -p named-data
fi
ndnsec-keygen "/tmp/jenkins/$NODE_NAME" | ndnsec-install-cert -
set -eo pipefail
# https://github.com/google/sanitizers/wiki/AddressSanitizerFlags
ASAN_OPTIONS="color=always"
@@ -22,6 +13,7 @@ ASAN_OPTIONS+=":detect_leaks=0"
ASAN_OPTIONS+=":strip_path_prefix=${PWD}/"
export ASAN_OPTIONS
# https://www.boost.org/doc/libs/release/libs/test/doc/html/boost_test/runtime_config/summary.html
export BOOST_TEST_BUILD_INFO=1
export BOOST_TEST_COLOR_OUTPUT=1
export BOOST_TEST_DETECT_MEMORY_LEAK=0
@@ -30,6 +22,11 @@ ut_log_args() {
echo --logger=HRF,test_suite,stdout:XML,all,build/xunit-log${1:+-$1}.xml
}
set -x
# Prepare environment
rm -rf ~/.ndn
# First run all tests as unprivileged user
./build/unit-tests-core $(ut_log_args core)
./build/unit-tests-daemon $(ut_log_args daemon)
@@ -37,9 +34,9 @@ ut_log_args() {
./build/unit-tests-tools $(ut_log_args tools)
# Then use sudo to run those tests that need superuser powers
sudo_preserve_env ASAN_OPTIONS BOOST_TEST_COLOR_OUTPUT -- \
sudo --preserve-env=ASAN_OPTIONS,BOOST_TEST_COLOR_OUTPUT \
./build/unit-tests-daemon -t TestPrivilegeHelper $(ut_log_args daemon-privilege-helper)
sudo_preserve_env ASAN_OPTIONS BOOST_TEST_COLOR_OUTPUT -- \
sudo --preserve-env=ASAN_OPTIONS,BOOST_TEST_COLOR_OUTPUT \
./build/unit-tests-daemon -t Face/*Ethernet* $(ut_log_args daemon-ethernet)
sudo_preserve_env ASAN_OPTIONS BOOST_TEST_COLOR_OUTPUT -- \
sudo --preserve-env=ASAN_OPTIONS,BOOST_TEST_COLOR_OUTPUT \
./build/unit-tests-daemon -t Face/TestUdpFactory $(ut_log_args daemon-udp)
+15 -18
View File
@@ -1,35 +1,32 @@
#!/usr/bin/env bash
set -ex
set -exo pipefail
if [[ $JOB_NAME == *"code-coverage" ]]; then
gcovr --object-directory=build \
--output=build/coverage.xml \
--exclude="$PWD/(tests|websocketpp)" \
--root=. \
--xml
# 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 --object-directory build \
--exclude tests/ \
--exclude websocketpp/ \
--exclude-throw-branches \
--exclude-unreachable-branches \
--cobertura build/coverage.xml \
--html-details build/gcovr/ \
--print-summary
# Generate also a detailed HTML output, but using lcov (better results)
# Generate a detailed HTML report using lcov
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/coverage \
--output-directory build/lcov \
--title "NFD unit tests" \
build/coverage.info
fi
+24 -16
View File
@@ -1,28 +1,36 @@
# CONTINUOUS INTEGRATION SCRIPTS
# Continuous Integration Scripts
## Environment Variables Used in Build Scripts
## Environment Variables
- `NODE_LABELS`: space-separated list of platform properties. The included values are used by
the build scripts to select the proper behavior for different operating systems and versions.
- `ID`: lower-case string that identifies the operating system, for example: `ID=ubuntu`,
`ID=centos`. See [os-release(5)] for more information. On macOS, where `os-release` is
not available, we emulate it by setting `ID=macos`.
The list should normally contain `[OS_TYPE]`, `[DISTRO_TYPE]`, and `[DISTRO_VERSION]`.
- `ID_LIKE`: space-separated list of operating system identifiers that are closely related
to the running OS. See [os-release(5)] for more information. The listed values are used
by the CI scripts to select the proper behavior for different platforms and OS flavors.
Example values:
Examples:
- `[OS_TYPE]`: `Linux`, `OSX`
- `[DISTRO_TYPE]`: `Ubuntu`, `CentOS`
- `[DISTRO_VERSION]`: `Ubuntu-16.04`, `Ubuntu-18.04`, `CentOS-8`, `OSX-10.14`, `OSX-10.15`
- On CentOS, `ID_LIKE="centos rhel fedora linux"`
- On Ubuntu, `ID_LIKE="ubuntu debian linux"`
- `JOB_NAME`: optional variable that defines the type of build job. Depending on the job type,
the build scripts can perform different tasks.
- `VERSION_ID`: identifies the operating system version, excluding any release code names.
See [os-release(5)] for more information. Examples: `VERSION_ID=42`, `VERSION_ID=22.04`.
Possible values:
- `JOB_NAME`: defines the type of the current CI job. Depending on the job type, the CI
scripts can perform different tasks.
Supported values:
- empty: default build task
- `code-coverage`: debug build with tests and code coverage analysis (Ubuntu Linux is assumed)
- `code-coverage`: debug build with tests and code coverage analysis
- `limited-build`: only a single debug build with tests
- `CACHE_DIR`: directory containing cached files from previous builds, e.g., a compiled version
of ndn-cxx. If not set, `/tmp` is used.
- `CACHE_DIR`: directory containing cached files from previous builds, e.g., a compiled
version of ndn-cxx. If not set, `/tmp` is used.
- `WAF_JOBS`: number of parallel build threads used by waf, defaults to 1.
- `DISABLE_ASAN`: disable building with AddressSanitizer. This is automatically set for
the `code-coverage` job type.
[os-release(5)]: https://www.freedesktop.org/software/systemd/man/os-release.html
-39
View File
@@ -1,39 +0,0 @@
has() {
local saved_xtrace
[[ $- == *x* ]] && saved_xtrace=-x || saved_xtrace=+x
set +x
local p=$1
shift
local i ret=1
for i in "$@"; do
if [[ "${i}" == "${p}" ]]; then
ret=0
break
fi
done
set ${saved_xtrace}
return ${ret}
}
export -f has
sudo_preserve_env() {
local saved_xtrace
[[ $- == *x* ]] && saved_xtrace=-x || saved_xtrace=+x
set +x
local vars=()
while [[ $# -gt 0 ]]; do
local arg=$1
shift
case ${arg} in
--) break ;;
*) vars+=("${arg}=${!arg}") ;;
esac
done
set ${saved_xtrace}
sudo env "${vars[@]}" "$@"
}
export -f sudo_preserve_env
-115
View File
@@ -1,115 +0,0 @@
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
+2 -2
View File
@@ -54,8 +54,8 @@ from waflib import Utils, Logs, Errors
from waflib.Configure import conf
from waflib.TaskGen import feature, after_method
BOOST_LIBS = ['/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib']
BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include']
BOOST_LIBS = ['/usr/lib', '/usr/local/lib', '/opt/homebrew/lib', '/opt/local/lib', '/sw/lib', '/lib']
BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/homebrew/include', '/opt/local/include', '/sw/include']
BOOST_VERSION_FILE = 'boost/version.hpp'
BOOST_VERSION_CODE = '''
+20 -24
View File
@@ -16,23 +16,24 @@ def configure(conf):
errmsg = ''
warnmsg = ''
if cxx == 'gcc':
if ccver < (5, 3, 0):
if ccver < (7, 4, 0):
errmsg = ('The version of gcc you are using is too old.\n'
'The minimum supported gcc version is 7.4.0.')
elif ccver < (7, 4, 0):
warnmsg = ('Using a version of gcc older than 7.4.0 is not '
'officially supported and may result in build failures.')
'The minimum supported gcc version is 7.4.')
conf.flags = GccFlags()
elif cxx == 'clang':
if Utils.unversioned_sys_platform() == 'darwin' and ccver < (9, 0, 0):
errmsg = ('The version of Xcode you are using is too old.\n'
'The minimum supported Xcode version is 9.0.')
elif ccver < (4, 0, 0):
if Utils.unversioned_sys_platform() == 'darwin':
if ccver < (10, 0, 0):
errmsg = ('The version of Xcode you are using is too old.\n'
'The minimum supported Xcode version is 11.3.')
elif ccver < (11, 0, 0):
warnmsg = ('Using a version of Xcode older than 11.3 is not '
'officially supported and may result in build failures.')
elif ccver < (6, 0, 0):
errmsg = ('The version of clang you are using is too old.\n'
'The minimum supported clang version is 4.0.')
'The minimum supported clang version is 6.0.')
conf.flags = ClangFlags()
else:
warnmsg = '%s compiler is unsupported' % cxx
warnmsg = f'{cxx} compiler is unsupported'
conf.flags = CompilerFlags()
if errmsg:
@@ -135,10 +136,8 @@ class GccBasicFlags(CompilerFlags):
"""
def getGeneralFlags(self, conf):
flags = super(GccBasicFlags, self).getGeneralFlags(conf)
flags['CXXFLAGS'] += ['-std=c++14']
if Utils.unversioned_sys_platform() == 'linux':
flags['LINKFLAGS'] += ['-fuse-ld=gold']
elif Utils.unversioned_sys_platform() == 'freebsd':
flags['CXXFLAGS'] += ['-std=c++17']
if Utils.unversioned_sys_platform() != 'darwin':
flags['LINKFLAGS'] += ['-fuse-ld=lld']
return flags
@@ -146,9 +145,9 @@ class GccBasicFlags(CompilerFlags):
flags = super(GccBasicFlags, self).getDebugFlags(conf)
flags['CXXFLAGS'] += ['-Og',
'-g3',
'-pedantic',
'-Wall',
'-Wextra',
'-Wpedantic',
'-Werror',
'-Wcatch-value=2',
'-Wextra-semi',
@@ -164,9 +163,9 @@ class GccBasicFlags(CompilerFlags):
flags = super(GccBasicFlags, self).getOptimizedFlags(conf)
flags['CXXFLAGS'] += ['-O2',
'-g',
'-pedantic',
'-Wall',
'-Wextra',
'-Wpedantic',
'-Wcatch-value=2',
'-Wextra-semi',
'-Wnon-virtual-dtor',
@@ -181,7 +180,7 @@ class GccFlags(GccBasicFlags):
flags['CXXFLAGS'] += ['-fdiagnostics-color',
'-Wredundant-tags',
]
if platform.machine() == 'armv7l' and self.getCompilerVersion(conf) >= (7, 1, 0):
if platform.machine() == 'armv7l':
flags['CXXFLAGS'] += ['-Wno-psabi'] # Bug #5106
return flags
@@ -190,7 +189,7 @@ class GccFlags(GccBasicFlags):
flags['CXXFLAGS'] += ['-fdiagnostics-color',
'-Wredundant-tags',
]
if platform.machine() == 'armv7l' and self.getCompilerVersion(conf) >= (7, 1, 0):
if platform.machine() == 'armv7l':
flags['CXXFLAGS'] += ['-Wno-psabi'] # Bug #5106
return flags
@@ -199,7 +198,8 @@ class ClangFlags(GccBasicFlags):
flags = super(ClangFlags, self).getGeneralFlags(conf)
if Utils.unversioned_sys_platform() == 'darwin':
# Bug #4296
flags['CXXFLAGS'] += [['-isystem', '/usr/local/include'], # for Homebrew
brewdir = '/opt/homebrew' if platform.machine() == 'arm64' else '/usr/local'
flags['CXXFLAGS'] += [['-isystem', f'{brewdir}/include'], # for Homebrew
['-isystem', '/opt/local/include']] # for MacPorts
elif Utils.unversioned_sys_platform() == 'freebsd':
# Bug #4790
@@ -212,8 +212,6 @@ class ClangFlags(GccBasicFlags):
'-Wundefined-func-template',
'-Wno-unused-local-typedef', # Bugs #2657 and #3209
]
if self.getCompilerVersion(conf) < (6, 0, 0):
flags['CXXFLAGS'] += ['-Wno-missing-braces'] # Bug #4721
return flags
def getOptimizedFlags(self, conf):
@@ -222,6 +220,4 @@ class ClangFlags(GccBasicFlags):
'-Wundefined-func-template',
'-Wno-unused-local-typedef', # Bugs #2657 and #3209
]
if self.getCompilerVersion(conf) < (6, 0, 0):
flags['CXXFLAGS'] += ['-Wno-missing-braces'] # Bug #4721
return flags
+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:
+5 -5
View File
@@ -1,12 +1,12 @@
# NFD Authors
The following lists maintainers, primary developers, and all much-appreciated contributors to NFD in alphabetic order.
The following lists maintainers, primary developers, and all much-appreciated contributors to NFD in alphabetical order.
The specific contributions of individual authors can be obtained from the git history of the [official NFD repository](https://github.com/named-data/NFD).
If you would like to become a contributor to the official repository, please follow the recommendations in https://github.com/named-data/.github/blob/master/CONTRIBUTING.md.
If you would like to become a contributor to the official repository, please follow the recommendations in <https://github.com/named-data/.github/blob/master/CONTRIBUTING.md>.
* Jerald Paul Abraham <https://cs.arizona.edu/~jeraldabraham>
* ***(Maintainer)*** Alexander Afanasyev <https://users.cs.fiu.edu/~afanasyev>
* Syed Obai Amin <http://obaidamin.weebly.com>
* Syed Obaid Amin <http://obaidamin.weebly.com>
* Hila Ben Abraham <https://sites.wustl.edu/hbabraham>
* Muktadir R Chowdhury <https://github.com/alvyC>
* Tai-Lin Chu <https://www.linkedin.com/pub/tai-lin-chu/55/5b2/669>
@@ -31,7 +31,7 @@ If you would like to become a contributor to the official repository, please fol
* Eric Newberry <https://ericnewberry.com>
* Ju Pan <https://cs-jupan.com>
* João Pereira <http://website.jpereira.co.uk>
* Davide Pesavento <https://github.com/Pesa>
* ***(Maintainer)*** Davide Pesavento <https://github.com/Pesa>
* Felix Rabe <https://twitter.com/felixrabe>
* Md Ashiqur Rahman <https://ashiqrahman.com>
* Matteo Sammarco <https://www.linkedin.com/in/matteo-sammarco-9b544530>
@@ -55,7 +55,7 @@ If you would like to become a contributor to the official repository, please fol
* Patrick Crowley <https://www.arl.wustl.edu/~pcrowley>
* Christos Papadopoulos <https://www.cs.colostate.edu/~christos>
* Giovanni Pau <http://www.cs.ucla.edu/~gpau/Giovanni_Paus_Home_Page/Home.html>
* Giovanni Pau <https://www.unibo.it/sitoweb/giovanni.pau/en>
* Tian Song <http://www.bit-netlab.org/songtian>
* Lan Wang <http://www.cs.memphis.edu/~lanwang>
* Beichuan Zhang <https://cs.arizona.edu/~bzhang>
+17
View File
@@ -0,0 +1,17 @@
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
@@ -1,81 +0,0 @@
# 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
@@ -1,489 +0,0 @@
# 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
+4 -5
View File
@@ -9,10 +9,10 @@ NFD relies on third-party software, licensed under the following licenses:
- The Boost libraries are licensed under the
[Boost Software License 1.0](https://www.boost.org/users/license.html)
- CityHash is licensed under a
- CityHash is licensed under the
[MIT license](https://github.com/google/cityhash/blob/master/COPYING)
- Libpcap is licensed under a
- Libpcap is licensed under the
[3-clause BSD license](https://github.com/the-tcpdump-group/libpcap/blob/master/LICENSE)
- The WebSocket++ library is licensed under the terms of the
@@ -21,11 +21,10 @@ NFD relies on third-party software, licensed under the following licenses:
- The waf build system is licensed under the terms of the
[BSD license](https://github.com/named-data/NFD/blob/master/waf)
The GPL license is provided below in this file. For more information about
these licenses, see https://www.gnu.org/licenses/
these licenses, see <https://www.gnu.org/licenses/>
----------------------------------------------------------------------------------
--------------------------------------------------------------------------------
### GNU GENERAL PUBLIC LICENSE
+11 -4
View File
@@ -1,8 +1,15 @@
# NFD - Named Data Networking Forwarding Daemon
<div align="center">
![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)
[<img alt height="70" src="docs/named_data_theme/static/ndn-logo.svg"/>](https://named-data.net/)
# NFD: Named Data Networking Forwarding Daemon
</div>
[![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-17-blue)
![Latest version](https://img.shields.io/github/v/tag/named-data/NFD?label=Latest%20version)
## Overview
-1
View File
@@ -1 +0,0 @@
docs/release-notes-latest.rst
-58
View File
@@ -1,58 +0,0 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, 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_CORE_ALGORITHM_HPP
#define NFD_CORE_ALGORITHM_HPP
#include "common.hpp"
#include <boost/concept/requires.hpp>
namespace nfd {
/** \brief finds the last element satisfying a predicate
* \tparam It BidirectionalIterator
* \tparam Pred UnaryPredicate
*
* \return Iterator to the last element satisfying the condition,
* or \p last if no such element is found.
*
* Complexity: at most \p last-first invocations of \p p
*/
template<typename It, typename Pred>
BOOST_CONCEPT_REQUIRES(
((boost::BidirectionalIterator<It>))
((boost::UnaryPredicate<Pred, typename std::iterator_traits<It>::value_type>)),
(It)
)
find_last_if(It first, It last, Pred p)
{
std::reverse_iterator<It> firstR(first), lastR(last);
auto found = std::find_if(lastR, firstR, p);
return found == firstR ? last : std::prev(found.base());
}
} // namespace nfd
#endif // NFD_CORE_ALGORITHM_HPP
+19 -27
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, 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 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
#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
#else
#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
#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
#endif
#include <cstddef>
@@ -50,17 +50,15 @@
#include <limits>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <string_view>
#include <utility>
#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>
@@ -70,13 +68,11 @@
#include <ndn-cxx/util/exception.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>
#include <boost/assert.hpp>
#include <boost/core/noncopyable.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/property_tree/ptree.hpp>
namespace nfd {
@@ -94,18 +90,14 @@ using std::static_pointer_cast;
using std::dynamic_pointer_cast;
using std::const_pointer_cast;
using std::bind;
using namespace std::string_literals;
using namespace std::string_view_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;
+6 -2
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2018, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -25,9 +25,13 @@
#include "network.hpp"
#include <boost/lexical_cast.hpp>
#include <boost/utility/value_init.hpp>
#include <algorithm>
#include <cctype>
#include <istream>
#include <ostream>
namespace nfd {
@@ -59,7 +63,7 @@ Network::getMaxRangeV6()
}
bool
Network::isValidCidr(const std::string& cidr)
Network::isValidCidr(std::string_view cidr)
{
auto pos = cidr.find('/');
if (pos == std::string::npos) {
+5 -4
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2016, Regents of the University of California,
/*
* Copyright (c) 2014-2022, 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_CORE_NETWORK_HPP
#define NFD_CORE_NETWORK_HPP
#include "common.hpp"
#include <boost/asio/ip/address.hpp>
#include <string_view>
namespace nfd {
@@ -51,7 +52,7 @@ public:
getMaxRangeV6();
static bool
isValidCidr(const std::string& cidr);
isValidCidr(std::string_view cidr);
bool
operator==(const Network& rhs) const
+16 -12
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -26,14 +26,16 @@
#ifndef NFD_CORE_VERSION_HPP
#define NFD_CORE_VERSION_HPP
// NFD version follows Semantic Versioning 2.0.0
// https://semver.org/spec/v2.0.0.html
// The NFD version follows the approach of Calendar Versioning (https://calver.org/)
// based on the year and month of the release, followed by an optional "patch" number,
// i.e., `YY.0M[.MICRO]` using CalVer notation.
//
// To change version number, modify VERSION variable in top-level wscript.
// To change version number, modify the VERSION variable in the 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@
@@ -44,7 +46,8 @@
/// 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
@@ -53,20 +56,21 @@
*/
extern const char NFD_VERSION_STRING[];
/** \brief NFD version string, including git commit information, if NFD is build from
* specific git commit.
/**
* \brief NFD version string, including git commit information if NFD is build from a
* 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: 0.1.0-rc1-1-g5c86570
* Example: 2022.02-1-g5c86570
*/
extern const char NFD_VERSION_BUILD_STRING[];
+4 -4
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -32,8 +32,8 @@
namespace nfd {
ConfigFile::ConfigFile(UnknownConfigSectionHandler unknownSectionCallback)
: m_unknownSectionCallback(unknownSectionCallback)
ConfigFile::ConfigFile(UnknownConfigSectionHandler callback)
: m_unknownSectionCallback(std::move(callback))
{
}
@@ -77,7 +77,7 @@ void
ConfigFile::addSectionHandler(const std::string& sectionName,
ConfigSectionHandler subscriber)
{
m_subscriptions[sectionName] = subscriber;
m_subscriptions[sectionName] = std::move(subscriber);
}
void
+34 -12
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -32,27 +32,32 @@
namespace nfd {
/** \brief a config file section
/**
* \brief A configuration file section.
*/
using ConfigSection = boost::property_tree::ptree;
/** \brief an optional config file section
/**
* \brief An optional configuration file section.
*/
using OptionalConfigSection = boost::optional<const ConfigSection&>;
/** \brief callback to process a config file section
/**
* \brief Callback to process a configuration file section.
*/
using ConfigSectionHandler = std::function<void(const ConfigSection& section, bool isDryRun,
const std::string& filename)>;
/** \brief callback to process a config file section without a \p ConfigSectionHandler
/**
* \brief Callback to process a configuration file section without a #ConfigSectionHandler.
*/
using UnknownConfigSectionHandler = std::function<void(const std::string& filename,
const std::string& sectionName,
const ConfigSection& section,
bool isDryRun)>;
/** \brief configuration file parsing utility
/**
* \brief Configuration file parsing utility.
*/
class ConfigFile : noncopyable
{
@@ -80,7 +85,7 @@ public: // unknown section handlers
bool isDryRun);
public: // parse helpers
/** \brief parse a config option that can be either "yes" or "no"
/** \brief Parse a config option that can be either "yes" or "no".
* \retval true "yes"
* \retval false "no"
* \throw Error the value is neither "yes" nor "no"
@@ -95,7 +100,7 @@ public: // parse helpers
}
/**
* \brief parse a numeric (integral or floating point) config option
* \brief Parse a numeric (integral or floating point) config option.
* \tparam T an arithmetic type
*
* \return the numeric value of the parsed option
@@ -105,9 +110,9 @@ public: // parse helpers
static T
parseNumber(const ConfigSection& node, const std::string& key, const std::string& sectionName)
{
static_assert(std::is_arithmetic<T>::value, "T must be an arithmetic type");
static_assert(std::is_arithmetic_v<T>);
boost::optional<T> value = node.get_value_optional<T>();
auto value = node.get_value_optional<T>();
// Unsigned logic is workaround for https://redmine.named-data.net/issues/4489
if (value &&
(std::is_signed<T>() || node.get_value<std::string>().find("-") == std::string::npos)) {
@@ -117,15 +122,32 @@ 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_v<T>);
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
/// \brief Setup notification of configuration file sections.
void
addSectionHandler(const std::string& sectionName,
ConfigSectionHandler subscriber);
+15 -12
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -30,24 +30,27 @@
namespace nfd {
/** \brief represents a counter that encloses an integer value
/**
* \brief Represents a counter that encloses an integer value.
*
* SimpleCounter is noncopyable, because increment should be called on the counter,
* not a copy of it; it's implicitly convertible to an integral type to be observed
* SimpleCounter is noncopyable, because increment should be called on the counter,
* not a copy of it; it's implicitly convertible to an integral type to be observed.
*/
class SimpleCounter : noncopyable
{
public:
typedef uint64_t rep;
/** \brief observe the counter
/**
* \brief Observe the counter's value.
*/
operator rep() const noexcept
{
return m_value;
}
/** \brief replace the counter value
/**
* \brief Replace the counter's value.
*/
void
set(rep value) noexcept
@@ -59,14 +62,14 @@ protected:
rep m_value = 0;
};
/** \brief represents a counter of number of packets
/** \brief Represents a counter of number of packets.
*
* \warning The counter value may wrap after exceeding the range of underlying integer type.
*/
class PacketCounter : public SimpleCounter
{
public:
/** \brief increment the counter by one
/** \brief Increment the counter by one.
*/
PacketCounter&
operator++() noexcept
@@ -77,14 +80,14 @@ public:
// postfix ++ operator is not provided because it's not needed
};
/** \brief represents a counter of number of bytes
/** \brief Represents a counter of number of bytes.
*
* \warning The counter value may wrap after exceeding the range of underlying integer type.
*/
class ByteCounter : public SimpleCounter
{
public:
/** \brief increase the counter
/** \brief Increase the counter.
*/
ByteCounter&
operator+=(rep n) noexcept
@@ -94,7 +97,7 @@ public:
}
};
/** \brief provides a counter that observes the size of a table
/** \brief Provides a counter that observes the size of a table.
* \tparam T a type that provides a size() const member function
*
* if table not specified in constructor, it can be added later by invoking observe()
@@ -117,7 +120,7 @@ public:
m_table = table;
}
/** \brief observe the counter
/** \brief Observe the counter.
*/
operator Rep() const
{
+2 -2
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2021, 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 WITH_TESTS
#ifdef NFD_WITH_TESTS
void
resetGlobalIoService()
{
+4 -2
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019 Regents of the University of California,
* Copyright (c) 2014-2022 Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,6 +27,8 @@
#include "core/common.hpp"
#include <boost/asio/io_service.hpp>
namespace nfd {
/** \brief Returns the global io_service instance for the calling thread.
@@ -61,7 +63,7 @@ runOnMainIoService(const std::function<void()>& f);
void
runOnRibIoService(const std::function<void()>& f);
#ifdef WITH_TESTS
#ifdef NFD_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-2020, Regents of the University of California,
* Copyright (c) 2014-2021, 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 HAVE_PRIVILEGE_DROP_AND_ELEVATE
#ifdef NFD_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 // HAVE_PRIVILEGE_DROP_AND_ELEVATE
#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
void
PrivilegeHelper::initialize(const std::string& userName, const std::string& groupName)
{
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
#ifdef NFD_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 // HAVE_PRIVILEGE_DROP_AND_ELEVATE
#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
}
void
PrivilegeHelper::drop()
{
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
#ifdef NFD_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 // HAVE_PRIVILEGE_DROP_AND_ELEVATE
#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
}
void
PrivilegeHelper::raise()
{
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
#ifdef NFD_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 // HAVE_PRIVILEGE_DROP_AND_ELEVATE
#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
}
} // namespace nfd
+11 -9
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -35,10 +35,12 @@ namespace nfd {
class PrivilegeHelper
{
public:
/** \brief represents a serious seteuid/gid failure
/**
* \brief Indicates a serious seteuid/setegid failure.
*
* This should only be caught by main as part of a graceful program termination.
* \note This is not an std::exception and NDN_THROW should not be used.
* This should only be caught by main as part of a graceful program termination.
*
* \note This is not an std::exception and NDN_THROW should not be used.
*/
class Error
{
@@ -71,7 +73,7 @@ public:
{
raise();
try {
f();
std::invoke(std::forward<F>(f));
}
catch (...) {
drop();
@@ -80,18 +82,18 @@ public:
drop();
}
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
static void
raise();
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
#ifdef HAVE_PRIVILEGE_DROP_AND_ELEVATE
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
#ifdef NFD_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 // HAVE_PRIVILEGE_DROP_AND_ELEVATE
#endif // NFD_HAVE_PRIVILEGE_DROP_AND_ELEVATE
};
} // namespace nfd
-62
View File
@@ -1,62 +0,0 @@
#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
@@ -1,41 +0,0 @@
//
// 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
+10 -6
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -26,17 +26,22 @@
#include "channel.hpp"
#include "face.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
Channel::~Channel() = default;
void
Channel::setUri(const FaceUri& uri)
Channel::setUri(const FaceUri& uri) noexcept
{
m_uri = uri;
}
void
Channel::setDefaultMtu(size_t mtu) noexcept
{
m_defaultMtu = mtu;
}
void
connectFaceClosedSignal(Face& face, std::function<void()> f)
{
@@ -47,5 +52,4 @@ connectFaceClosedSignal(Face& face, std::function<void()> f)
});
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+22 -9
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -29,8 +29,7 @@
#include "channel-log.hpp"
#include "face-common.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
/** \brief Represents a channel that listens on a local endpoint.
* \sa FaceSystem
@@ -45,27 +44,42 @@ public:
~Channel();
const FaceUri&
getUri() const
getUri() const noexcept
{
return m_uri;
}
/** \brief Returns whether the channel is listening
/**
* \brief Returns the default MTU for all faces created by this channel.
*/
size_t
getDefaultMtu() const noexcept
{
return m_defaultMtu;
}
/**
* \brief Returns whether the channel is listening.
*/
virtual bool
isListening() const = 0;
/** \brief Returns the number of faces in the channel
/**
* \brief Returns the number of faces in the channel.
*/
virtual size_t
size() const = 0;
protected:
void
setUri(const FaceUri& uri);
setUri(const FaceUri& uri) noexcept;
void
setDefaultMtu(size_t mtu) noexcept;
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
@@ -87,7 +101,6 @@ using FaceCreationFailedCallback = std::function<void(uint32_t status, const std
void
connectFaceClosedSignal(Face& face, std::function<void()> f);
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_CHANNEL_HPP
+22 -30
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -32,21 +32,23 @@
#include <array>
namespace nfd {
namespace face {
namespace nfd::face {
struct Unicast {};
struct Multicast {};
/** \brief Implements Transport for datagram-based protocols.
/**
* \brief Implements Transport for datagram-based protocols.
*
* \tparam Protocol a datagram-based protocol in Boost.Asio
* \tparam Protocol A datagram-based protocol in Boost.Asio
* \tparam Addressing The addressing mode, either Unicast or Multicast
*/
template<class Protocol, class Addressing = Unicast>
template<class Protocol, class Addressing>
class DatagramTransport : public Transport
{
public:
typedef Protocol protocol;
using protocol = Protocol;
using addressing = Addressing;
/** \brief Construct datagram transport.
*
@@ -58,11 +60,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(const uint8_t* buffer, size_t nBytesReceived,
const boost::system::error_code& error);
receiveDatagram(span<const uint8_t> buffer, const boost::system::error_code& error);
protected:
void
@@ -86,9 +88,6 @@ protected:
void
resetRecentlyReceived();
static EndpointId
makeEndpointId(const typename protocol::endpoint& ep);
protected:
typename protocol::socket m_socket;
typename protocol::endpoint m_sender;
@@ -170,37 +169,38 @@ DatagramTransport<T, U>::doSend(const Block& packet)
template<class T, class U>
void
DatagramTransport<T, U>::receiveDatagram(const uint8_t* buffer, size_t nBytesReceived,
DatagramTransport<T, U>::receiveDatagram(span<const uint8_t> buffer,
const boost::system::error_code& error)
{
if (error)
return processErrorCode(error);
NFD_LOG_FACE_TRACE("Received: " << nBytesReceived << " bytes from " << m_sender);
NFD_LOG_FACE_TRACE("Received: " << buffer.size() << " bytes from " << m_sender);
bool isOk = false;
Block element;
std::tie(isOk, element) = Block::fromBuffer(buffer, nBytesReceived);
auto [isOk, element] = Block::fromBuffer(buffer);
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() != nBytesReceived) {
if (element.size() != buffer.size()) {
NFD_LOG_FACE_WARN("Received datagram size and decoded element size don't match");
// This packet won't extend the face lifetime
return;
}
m_hasRecentlyReceived = true;
this->receive(element, makeEndpointId(m_sender));
if constexpr (std::is_same_v<addressing, Multicast>)
this->receive(element, m_sender);
else
this->receive(element);
}
template<class T, class U>
void
DatagramTransport<T, U>::handleReceive(const boost::system::error_code& error, size_t nBytesReceived)
{
receiveDatagram(m_receiveBuffer.data(), nBytesReceived, error);
receiveDatagram(ndn::make_span(m_receiveBuffer).first(nBytesReceived), error);
if (m_socket.is_open())
m_socket.async_receive_from(boost::asio::buffer(m_receiveBuffer), m_sender,
@@ -257,14 +257,6 @@ DatagramTransport<T, U>::resetRecentlyReceived()
m_hasRecentlyReceived = false;
}
template<class T, class U>
EndpointId
DatagramTransport<T, U>::makeEndpointId(const typename protocol::endpoint&)
{
return 0;
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_DATAGRAM_TRANSPORT_HPP
+14 -25
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -33,8 +33,7 @@
#include <boost/range/adaptor/map.hpp>
#include <pcap/pcap.h>
namespace nfd {
namespace face {
namespace nfd::face {
NFD_LOG_INIT(EthernetChannel);
@@ -120,26 +119,20 @@ EthernetChannel::handleRead(const boost::system::error_code& error,
return;
}
const uint8_t* pkt;
size_t len;
std::string err;
std::tie(pkt, len, err) = m_pcap.readNextPacket();
if (pkt == nullptr) {
NFD_LOG_CHAN_WARN("Read error: " << err);
auto [pkt, readErr] = m_pcap.readNextPacket();
if (pkt.empty()) {
NFD_LOG_CHAN_WARN("Read error: " << readErr);
}
else {
const ether_header* eh;
std::tie(eh, err) = ethernet::checkFrameHeader(pkt, len, m_localEndpoint->getEthernetAddress(),
m_localEndpoint->getEthernetAddress());
auto [eh, frameErr] = ethernet::checkFrameHeader(pkt, m_localEndpoint->getEthernetAddress(),
m_localEndpoint->getEthernetAddress());
if (eh == nullptr) {
NFD_LOG_CHAN_DEBUG(err);
NFD_LOG_CHAN_DEBUG(frameErr);
}
else {
ethernet::Address sender(eh->ether_shost);
pkt += ethernet::HDR_LEN;
len -= ethernet::HDR_LEN;
processIncomingPacket(pkt, len, sender, onFaceCreated, onReceiveFailed);
pkt = pkt.subspan(ethernet::HDR_LEN);
processIncomingPacket(pkt, sender, onFaceCreated, onReceiveFailed);
}
}
@@ -154,7 +147,7 @@ EthernetChannel::handleRead(const boost::system::error_code& error,
}
void
EthernetChannel::processIncomingPacket(const uint8_t* packet, size_t length,
EthernetChannel::processIncomingPacket(span<const uint8_t> packet,
const ethernet::Address& sender,
const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onReceiveFailed)
@@ -182,7 +175,7 @@ EthernetChannel::processIncomingPacket(const uint8_t* packet, size_t length,
// dispatch the packet to the face for processing
auto* transport = static_cast<UnicastEthernetTransport*>(face->getTransport());
transport->receivePayload(packet, length, sender);
transport->receivePayload(packet, sender);
}
std::pair<bool, shared_ptr<Face>>
@@ -204,15 +197,12 @@ 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,
params.persistency, m_idleFaceTimeout);
auto face = make_shared<Face>(std::move(linkService), std::move(transport));
face->setChannel(shared_from_this()); // use weak_from_this() in C++17
face->setChannel(weak_from_this());
m_channelFaces[remoteEndpoint] = face;
connectFaceClosedSignal(*face, [this, remoteEndpoint] {
@@ -243,5 +233,4 @@ EthernetChannel::updateFilter()
m_pcap.setPacketFilter(filter.data());
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+10 -14
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2018, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -29,15 +29,16 @@
#include "channel.hpp"
#include "ethernet-protocol.hpp"
#include "pcap-helper.hpp"
#include <boost/asio/posix/stream_descriptor.hpp>
#include <ndn-cxx/net/network-interface.hpp>
namespace nfd {
namespace face {
namespace nfd::face {
/**
* \brief Class implementing Ethernet-based channel to create faces
*/
class EthernetChannel : public Channel
class EthernetChannel final : public Channel
{
public:
/**
@@ -46,11 +47,7 @@ public:
class Error : public std::runtime_error
{
public:
explicit
Error(const std::string& what)
: std::runtime_error(what)
{
}
using std::runtime_error::runtime_error;
};
/**
@@ -63,13 +60,13 @@ public:
time::nanoseconds idleTimeout);
bool
isListening() const override
isListening() const final
{
return m_isListening;
}
size_t
size() const override
size() const final
{
return m_channelFaces.size();
}
@@ -110,7 +107,7 @@ private:
const FaceCreationFailedCallback& onReceiveFailed);
void
processIncomingPacket(const uint8_t* packet, size_t length,
processIncomingPacket(span<const uint8_t> packet,
const ethernet::Address& sender,
const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onReceiveFailed);
@@ -136,7 +133,6 @@ private:
#endif
};
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_ETHERNET_CHANNEL_HPP
+5 -7
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -30,8 +30,7 @@
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm/copy.hpp>
namespace nfd {
namespace face {
namespace nfd::face {
NFD_LOG_INIT(EthernetFactory);
NFD_REGISTER_PROTOCOL_FACTORY(EthernetFactory);
@@ -240,7 +239,7 @@ EthernetFactory::createMulticastFace(const ndn::net::NetworkInterface& netif,
{
BOOST_ASSERT(address.isMulticast());
auto key = std::make_pair(netif.getName(), address);
std::pair key(netif.getName(), address);
auto found = m_mcastFaces.find(key);
if (found != m_mcastFaces.end()) {
return found->second;
@@ -339,7 +338,7 @@ EthernetFactory::applyMcastConfigToNetif(const ndn::net::NetworkInterface& netif
return nullptr;
}
if (face->getId() == face::INVALID_FACEID) {
if (face->getId() == INVALID_FACEID) {
// new face: register with forwarding
this->addFace(face);
}
@@ -377,5 +376,4 @@ EthernetFactory::applyConfig(const FaceSystem::ConfigContext&)
}
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+11 -15
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2018, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -29,12 +29,11 @@
#include "protocol-factory.hpp"
#include "ethernet-channel.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
/** \brief Protocol factory for Ethernet
/** \brief Protocol factory for Ethernet.
*/
class EthernetFactory : public ProtocolFactory
class EthernetFactory final : public ProtocolFactory
{
public:
static const std::string&
@@ -44,7 +43,7 @@ public:
EthernetFactory(const CtorParams& params);
/**
* \brief Create Ethernet-based channel on the specified network interface
* \brief Create Ethernet-based channel on the specified network interface.
*
* If this method is called twice with the same endpoint, only one channel
* will be created. The second call will just return the existing channel.
@@ -58,7 +57,7 @@ public:
time::nanoseconds idleTimeout);
/**
* \brief Create a face to communicate on the given Ethernet multicast group
* \brief Create a face to communicate on the given Ethernet multicast group.
*
* If this method is called twice with the same arguments, only one face
* will be created. The second call will just return the existing face.
@@ -73,19 +72,17 @@ public:
const ethernet::Address& group);
private:
/** \brief process face_system.ether config section
*/
void
doProcessConfig(OptionalConfigSection configSection,
FaceSystem::ConfigContext& context) override;
FaceSystem::ConfigContext& context) final;
void
doCreateFace(const CreateFaceRequest& req,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onFailure) override;
const FaceCreationFailedCallback& onFailure) final;
std::vector<shared_ptr<const Channel>>
doGetChannels() const override;
doGetChannels() const final;
/** \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
@@ -122,13 +119,12 @@ private:
};
MulticastConfig m_mcastConfig;
/// (ifname, group) => face
// [ifname, group] => face
std::map<std::pair<std::string, ethernet::Address>, shared_ptr<Face>> m_mcastFaces;
signal::ScopedConnection m_netifAddConn;
};
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_ETHERNET_FACTORY_HPP
+8 -11
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2018, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,17 +27,15 @@
#include <boost/endian/conversion.hpp>
namespace nfd {
namespace ethernet {
namespace nfd::ethernet {
std::pair<const ether_header*, std::string>
checkFrameHeader(const uint8_t* packet, size_t length,
const Address& localAddr, const Address& destAddr)
std::tuple<const ether_header*, std::string>
checkFrameHeader(span<const uint8_t> packet, const Address& localAddr, const Address& destAddr)
{
if (length < HDR_LEN + MIN_DATA_LEN)
return {nullptr, "Received frame too short: " + to_string(length) + " bytes"};
if (packet.size() < HDR_LEN + MIN_DATA_LEN)
return {nullptr, "Received frame too short: " + to_string(packet.size()) + " bytes"};
const ether_header* eh = reinterpret_cast<const ether_header*>(packet);
const ether_header* eh = reinterpret_cast<const ether_header*>(packet.data());
// in some cases VLAN-tagged frames may survive the BPF filter,
// make sure we do not process those frames (see #3348)
@@ -58,5 +56,4 @@ checkFrameHeader(const uint8_t* packet, size_t length,
return {eh, ""};
}
} // namespace ethernet
} // namespace nfd
} // namespace nfd::ethernet
+6 -8
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2017, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,19 +27,17 @@
#define NFD_DAEMON_FACE_ETHERNET_PROTOCOL_HPP
#include "core/common.hpp"
#include <ndn-cxx/net/ethernet.hpp>
#include <net/ethernet.h>
namespace nfd {
namespace ethernet {
namespace nfd::ethernet {
using namespace ndn::ethernet;
std::pair<const ether_header*, std::string>
checkFrameHeader(const uint8_t* packet, size_t length,
const Address& localAddr, const Address& destAddr);
std::tuple<const ether_header*, std::string>
checkFrameHeader(span<const uint8_t> packet, const Address& localAddr, const Address& destAddr);
} // namespace ethernet
} // namespace nfd
} // namespace nfd::ethernet
#endif // NFD_DAEMON_FACE_ETHERNET_PROTOCOL_HPP
+20 -39
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -29,12 +29,9 @@
#include <pcap/pcap.h>
#include <cstring> // for memcpy()
#include <boost/endian/conversion.hpp>
namespace nfd {
namespace face {
namespace nfd::face {
NFD_LOG_INIT(EthernetTransport);
@@ -125,17 +122,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.appendByteArray(padding, ethernet::MIN_DATA_LEN - block.size());
buffer.appendBytes(ndn::make_span(padding).subspan(block.size()));
}
// construct and prepend the ethernet header
uint16_t ethertype = boost::endian::native_to_big(ethernet::ETHERTYPE_NDN);
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());
buffer.prependBytes({reinterpret_cast<const uint8_t*>(&ethertype), ethernet::TYPE_LEN});
buffer.prependBytes(m_srcAddress);
buffer.prependBytes(m_destAddress);
// send the frame
int sent = pcap_inject(m_pcap, buffer.buf(), buffer.size());
int sent = pcap_inject(m_pcap, buffer.data(), buffer.size());
if (sent < 0)
handleError("Send operation failed: " + m_pcap.getLastError());
else if (static_cast<size_t>(sent) < buffer.size())
@@ -168,26 +165,20 @@ EthernetTransport::handleRead(const boost::system::error_code& error)
return;
}
const uint8_t* pkt;
size_t len;
std::string err;
std::tie(pkt, len, err) = m_pcap.readNextPacket();
if (pkt == nullptr) {
NFD_LOG_FACE_WARN("Read error: " << err);
auto [pkt, readErr] = m_pcap.readNextPacket();
if (pkt.empty()) {
NFD_LOG_FACE_DEBUG("Read error: " << readErr);
}
else {
const ether_header* eh;
std::tie(eh, err) = ethernet::checkFrameHeader(pkt, len, m_srcAddress,
m_destAddress.isMulticast() ? m_destAddress : m_srcAddress);
auto [eh, frameErr] = ethernet::checkFrameHeader(pkt, m_srcAddress,
m_destAddress.isMulticast() ? m_destAddress : m_srcAddress);
if (eh == nullptr) {
NFD_LOG_FACE_WARN(err);
NFD_LOG_FACE_WARN(frameErr);
}
else {
ethernet::Address sender(eh->ether_shost);
pkt += ethernet::HDR_LEN;
len -= ethernet::HDR_LEN;
receivePayload(pkt, len, sender);
pkt = pkt.subspan(ethernet::HDR_LEN);
receivePayload(pkt, sender);
}
}
@@ -202,14 +193,11 @@ EthernetTransport::handleRead(const boost::system::error_code& error)
}
void
EthernetTransport::receivePayload(const uint8_t* payload, size_t length,
const ethernet::Address& sender)
EthernetTransport::receivePayload(span<const uint8_t> payload, const ethernet::Address& sender)
{
NFD_LOG_FACE_TRACE("Received: " << length << " bytes from " << sender);
NFD_LOG_FACE_TRACE("Received: " << payload.size() << " bytes from " << sender);
bool isOk = false;
Block element;
std::tie(isOk, element) = Block::fromBuffer(payload, length);
auto [isOk, element] = Block::fromBuffer(payload);
if (!isOk) {
NFD_LOG_FACE_WARN("Failed to parse incoming packet from " << sender);
// This packet won't extend the face lifetime
@@ -217,13 +205,7 @@ EthernetTransport::receivePayload(const uint8_t* payload, size_t length,
}
m_hasRecentlyReceived = true;
static_assert(sizeof(EndpointId) >= ethernet::ADDR_LEN, "EndpointId is too small");
EndpointId endpoint = 0;
if (m_destAddress.isMulticast()) {
std::memcpy(&endpoint, sender.data(), sender.size());
}
this->receive(element, endpoint);
this->receive(element, m_destAddress.isMulticast() ? sender : EndpointId{});
}
void
@@ -239,5 +221,4 @@ EthernetTransport::handleError(const std::string& errorMessage)
doClose();
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+6 -9
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -30,10 +30,10 @@
#include "pcap-helper.hpp"
#include "transport.hpp"
#include <boost/asio/posix/stream_descriptor.hpp>
#include <ndn-cxx/net/network-interface.hpp>
namespace nfd {
namespace face {
namespace nfd::face {
/**
* @brief Base class for Ethernet-based Transports
@@ -49,13 +49,11 @@ public:
/**
* @brief Processes the payload of an incoming frame
* @param payload Pointer to the first byte of data after the Ethernet header
* @param length Payload length
* @param payload Payload bytes, starting from the first byte after the Ethernet header
* @param sender Sender address
*/
void
receivePayload(const uint8_t* payload, size_t length,
const ethernet::Address& sender);
receivePayload(span<const uint8_t> payload, const ethernet::Address& sender);
protected:
EthernetTransport(const ndn::net::NetworkInterface& localEndpoint,
@@ -115,7 +113,6 @@ private:
#endif
};
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_ETHERNET_TRANSPORT_HPP
+32 -29
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -26,12 +26,14 @@
#ifndef NFD_DAEMON_FACE_FACE_COMMON_HPP
#define NFD_DAEMON_FACE_FACE_COMMON_HPP
#include "core/common.hpp"
#include "ethernet-protocol.hpp"
#include "udp-protocol.hpp"
#include "common/logger.hpp"
#include <ndn-cxx/encoding/nfd-constants.hpp>
#include <boost/logic/tribool.hpp>
#include <variant>
namespace nfd {
namespace face {
@@ -39,36 +41,40 @@ namespace face {
class Face;
class LinkService;
/** \brief Identifies a face.
/**
* \brief Identifies a face.
*/
using FaceId = uint64_t;
/// indicates an invalid FaceId
const FaceId INVALID_FACEID = ndn::nfd::INVALID_FACE_ID;
/// identifies the InternalFace used in management
const FaceId FACEID_INTERNAL_FACE = 1;
/// identifies a packet comes from the ContentStore
const FaceId FACEID_CONTENT_STORE = 254;
/// identifies the NullFace that drops every packet
const FaceId FACEID_NULL = 255;
/// upper bound of reserved FaceIds
const FaceId FACEID_RESERVED_MAX = 255;
/// Indicates an invalid FaceId
inline constexpr FaceId INVALID_FACEID = ndn::nfd::INVALID_FACE_ID;
/// Identifies the InternalFace used in management
inline constexpr FaceId FACEID_INTERNAL_FACE = 1;
/// Identifies a packet comes from the ContentStore
inline constexpr FaceId FACEID_CONTENT_STORE = 254;
/// Identifies the NullFace that drops every packet
inline constexpr FaceId FACEID_NULL = 255;
/// Upper bound of reserved FaceIds
inline constexpr FaceId FACEID_RESERVED_MAX = 255;
/** \brief Minimum MTU that may be set
/**
* \brief Minimum MTU that may be set.
*
* This is done to ensure the NDNLPv2 fragmentation feature functions properly.
* This is done to ensure the NDNLPv2 fragmentation feature functions properly.
*/
const ssize_t MIN_MTU = 64;
inline constexpr ssize_t MIN_MTU = 64;
/** \brief Identifies a remote endpoint on the link.
/**
* \brief Identifies a remote endpoint on the link.
*
* This ID is only meaningful in the context of the same Transport.
* Incoming packets from the same remote endpoint have the same EndpointId,
* and incoming packets from different remote endpoints have different EndpointIds.
* This ID is only meaningful in the context of the same Transport.
* Incoming packets from the same remote endpoint have the same EndpointId,
* and incoming packets from different remote endpoints have different EndpointIds.
*
* Typically, a point-to-point Transport has only one meaningful EndpointId (usually 0).
* Typically, a point-to-point Transport has only one meaningful EndpointId,
* represented by `std::monostate`.
*/
using EndpointId = uint64_t;
using EndpointId = std::variant<std::monostate, ethernet::Address, udp::Endpoint>;
/** \brief Parameters used to set Transport properties or LinkService options on a newly created face.
*
@@ -78,10 +84,9 @@ using EndpointId = uint64_t;
struct FaceParams
{
ndn::nfd::FacePersistency persistency = ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
optional<time::nanoseconds> baseCongestionMarkingInterval;
optional<uint64_t> defaultCongestionThreshold;
optional<ssize_t> mtu;
optional<uint64_t> bandwidth;
std::optional<time::nanoseconds> baseCongestionMarkingInterval;
std::optional<uint64_t> defaultCongestionThreshold;
std::optional<ssize_t> mtu;
bool wantLocalFields = false;
bool wantLpReliability = false;
boost::logic::tribool wantCongestionMarking = boost::logic::indeterminate;
@@ -129,9 +134,7 @@ using face::FaceId;
// implementation detail
#define NFD_LOG_FACE(level, msg) NFD_LOG_##level( \
::nfd::face::FaceLogHelper< \
typename std::remove_cv< \
typename std::remove_reference<decltype(*this)>::type \
>::type \
std::remove_cv_t<std::remove_reference_t<decltype(*this)>> \
>(*this) \
<< msg)
/** \endcond */
+3 -5
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -25,8 +25,7 @@
#include "face-counters.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
FaceCounters::FaceCounters(const LinkService::Counters& linkServiceCounters,
const Transport::Counters& transportCounters)
@@ -46,5 +45,4 @@ FaceCounters::FaceCounters(const LinkService::Counters& linkServiceCounters,
{
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+8 -10
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -29,10 +29,9 @@
#include "link-service.hpp"
#include "transport.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
/** \brief gives access to counters provided by Face
/** \brief Gives access to counters provided by Face.
*
* This type is a facade that exposes common counters of a Face.
*
@@ -50,7 +49,7 @@ public:
* \throw std::bad_cast counters type mismatch
*/
template<typename T>
typename std::enable_if<std::is_base_of<LinkService::Counters, T>::value, const T&>::type
std::enable_if_t<std::is_base_of_v<LinkService::Counters, T>, const T&>
get() const
{
return dynamic_cast<const T&>(m_linkServiceCounters);
@@ -61,7 +60,7 @@ public:
* \throw std::bad_cast counters type mismatch
*/
template<typename T>
typename std::enable_if<std::is_base_of<Transport::Counters, T>::value, const T&>::type
std::enable_if_t<std::is_base_of_v<Transport::Counters, T>, const T&>
get() const
{
return dynamic_cast<const T&>(m_transportCounters);
@@ -81,11 +80,11 @@ public:
const ByteCounter& nInBytes;
const ByteCounter& nOutBytes;
/** \brief count of incoming Interests dropped due to HopLimit == 0
/** \brief Count of incoming Interests dropped due to HopLimit == 0.
*/
PacketCounter nInHopLimitZero;
/** \brief count of outgoing Interests dropped due to HopLimit == 0 on non-local faces
/** \brief Count of outgoing Interests dropped due to HopLimit == 0 on non-local faces.
*/
PacketCounter nOutHopLimitZero;
@@ -94,7 +93,6 @@ private:
const Transport::Counters& m_transportCounters;
};
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_FACE_COUNTERS_HPP
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2018, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -23,27 +23,31 @@
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "available-commands.hpp"
#include "cs-module.hpp"
#include "face-module.hpp"
#include "rib-module.hpp"
#include "status.hpp"
#include "strategy-choice-module.hpp"
#include "face-endpoint.hpp"
#include <boost/hana/functional/overload.hpp>
namespace nfd {
namespace tools {
namespace nfdc {
void
registerCommands(CommandParser& parser)
FaceEndpoint::FaceEndpoint(Face& face, const EndpointId& endpoint)
: face(face)
, endpoint(endpoint)
{
registerStatusCommands(parser);
FaceModule::registerCommands(parser);
RibModule::registerCommands(parser);
CsModule::registerCommands(parser);
StrategyChoiceModule::registerCommands(parser);
}
} // namespace nfdc
} // namespace tools
void
FaceEndpoint::print(std::ostream& os) const
{
std::visit(boost::hana::overload(
[&] (std::monostate) {
os << face.getId();
},
[&] (const ethernet::Address& ep) {
os << '(' << face.getId() << ", " << ep << ')';
},
[&] (const udp::Endpoint& ep) {
os << '(' << face.getId() << ", " << ep << ')';
}), endpoint);
}
} // namespace nfd
+15 -12
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -30,16 +30,25 @@
namespace nfd {
/** \brief Represents a face-endpoint pair in the forwarder.
* \sa face::Face, face::EndpointId
/**
* \brief Represents a face-endpoint pair in the forwarder.
* \sa face::Face, face::EndpointId
*/
class FaceEndpoint
{
public:
FaceEndpoint(const Face& face, EndpointId endpoint)
: face(const_cast<Face&>(face))
, endpoint(endpoint)
explicit
FaceEndpoint(Face& face, const EndpointId& endpoint = {});
private:
void
print(std::ostream& os) const;
friend std::ostream&
operator<<(std::ostream& os, const FaceEndpoint& fe)
{
fe.print(os);
return os;
}
public:
@@ -47,12 +56,6 @@ public:
const EndpointId endpoint;
};
inline std::ostream&
operator<<(std::ostream& os, const FaceEndpoint& fe)
{
return os << '(' << fe.face.getId() << ',' << fe.endpoint << ')';
}
} // namespace nfd
#endif // NFD_DAEMON_FACE_FACE_ENDPOINT_HPP
+10 -13
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -29,8 +29,7 @@
#include "common/global.hpp"
#include "fw/face-table.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
NFD_LOG_INIT(FaceSystem);
@@ -94,7 +93,9 @@ FaceSystem::hasFactoryForScheme(const std::string& scheme) const
void
FaceSystem::setConfigFile(ConfigFile& configFile)
{
configFile.addSectionHandler(CFGSEC_FACESYSTEM, bind(&FaceSystem::processConfig, this, _1, _2, _3));
configFile.addSectionHandler(CFGSEC_FACESYSTEM, [this] (auto&&... args) {
processConfig(std::forward<decltype(args)>(args)...);
});
}
void
@@ -118,22 +119,19 @@ FaceSystem::processConfig(const ConfigSection& configSection, bool isDryRun, con
}
// process in protocol factories
for (const auto& pair : m_factories) {
const std::string& sectionName = pair.first;
ProtocolFactory* factory = pair.second.get();
for (const auto& [sectionName, factory] : m_factories) {
std::set<std::string> oldProvidedSchemes = factory->getProvidedSchemes();
factory->processConfig(configSection.get_child_optional(sectionName), context);
if (!isDryRun) {
for (const std::string& scheme : factory->getProvidedSchemes()) {
m_factoryByScheme[scheme] = factory;
for (const auto& scheme : factory->getProvidedSchemes()) {
m_factoryByScheme[scheme] = factory.get();
if (oldProvidedSchemes.erase(scheme) == 0) {
NFD_LOG_TRACE("factory " << sectionName <<
" provides " << scheme << " FaceUri scheme");
}
}
for (const std::string& scheme : oldProvidedSchemes) {
for (const auto& scheme : oldProvidedSchemes) {
m_factoryByScheme.erase(scheme);
NFD_LOG_TRACE("factory " << sectionName <<
" no longer provides " << scheme << " FaceUri scheme");
@@ -164,5 +162,4 @@ FaceSystem::processConfig(const ConfigSection& configSection, bool isDryRun, con
}
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+17 -15
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -43,10 +43,11 @@ class NetdevBound;
class ProtocolFactory;
struct ProtocolFactoryCtorParams;
/** \brief entry point of the face system
/**
* \brief Entry point of NFD's face system.
*
* NFD's face system is organized as a FaceSystem-ProtocolFactory-Channel-Face hierarchy.
* FaceSystem class is the entry point of NFD's face system and owns ProtocolFactory objects.
* NFD's face system is organized as a FaceSystem-ProtocolFactory-Channel-Face hierarchy.
* The FaceSystem class is the entry point of the face system and owns all ProtocolFactory objects.
*/
class FaceSystem : noncopyable
{
@@ -55,17 +56,18 @@ public:
~FaceSystem();
/** \return ProtocolFactory objects owned by the FaceSystem
/**
* \brief Returns all ProtocolFactory objects owned by the face system.
*/
std::set<const ProtocolFactory*>
[[nodiscard]] std::set<const ProtocolFactory*>
listProtocolFactories() const;
/** \return ProtocolFactory for the specified registered factory id or nullptr if not found
/** \return ProtocolFactory for the specified registered factory id or nullptr if not found.
*/
ProtocolFactory*
getFactoryById(const std::string& id);
/** \return ProtocolFactory for the specified FaceUri scheme or nullptr if not found
/** \return ProtocolFactory for the specified FaceUri scheme or nullptr if not found.
*/
ProtocolFactory*
getFactoryByScheme(const std::string& scheme);
@@ -79,19 +81,19 @@ public:
return m_faceTable;
}
/** \brief register handler for face_system section of NFD configuration file
/** \brief Register handler for the `face_system` section of NFD's configuration file.
*/
void
setConfigFile(ConfigFile& configFile);
/** \brief configuration options from "general" section
/** \brief Configuration options from `general` section.
*/
struct GeneralConfig
{
bool wantCongestionMarking = true;
};
/** \brief context for processing a config section in ProtocolFactory
/** \brief Context for processing a config section in ProtocolFactory.
*/
class ConfigContext : noncopyable
{
@@ -100,7 +102,7 @@ public:
bool isDryRun;
};
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
ProtocolFactoryCtorParams
makePFCtorParams();
@@ -109,14 +111,14 @@ private:
processConfig(const ConfigSection& configSection, bool isDryRun,
const std::string& filename);
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/** \brief config section name => protocol factory
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/** \brief Config section name => protocol factory.
*/
std::map<std::string, unique_ptr<ProtocolFactory>> m_factories;
unique_ptr<NetdevBound> m_netdevBound;
private:
/** \brief scheme => protocol factory
/** \brief Scheme => protocol factory.
*
* The same protocol factory may be available under multiple schemes.
*/
+3 -6
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2017, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -25,8 +25,7 @@
#include "face.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
Face::Face(unique_ptr<LinkService> service, unique_ptr<Transport> transport)
: afterReceiveInterest(service->afterReceiveInterest)
@@ -34,7 +33,6 @@ Face::Face(unique_ptr<LinkService> service, unique_ptr<Transport> transport)
, afterReceiveNack(service->afterReceiveNack)
, onDroppedInterest(service->onDroppedInterest)
, afterStateChange(transport->afterStateChange)
, m_id(INVALID_FACEID)
, m_service(std::move(service))
, m_transport(std::move(transport))
, m_counters(m_service->getCounters(), m_transport->getCounters())
@@ -52,5 +50,4 @@ operator<<(std::ostream& os, const FaceLogHelper<Face>& flh)
return os;
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+72 -68
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -36,11 +36,12 @@ namespace face {
class Channel;
/** \brief indicates the state of a face
/**
* \brief Indicates the state of a face.
*/
typedef TransportState FaceState;
using FaceState = TransportState;
/** \brief generalization of a network interface
/** \brief Generalization of a network interface.
*
* A face generalizes a network interface.
* It provides best-effort network-layer packet delivery services
@@ -51,18 +52,24 @@ 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 FINAL_UNLESS_WITH_TESTS : public std::enable_shared_from_this<Face>, noncopyable
class Face NFD_FINAL_UNLESS_WITH_TESTS : public std::enable_shared_from_this<Face>, noncopyable
{
public:
Face(unique_ptr<LinkService> service, unique_ptr<Transport> transport);
LinkService*
getLinkService() const;
getLinkService() const noexcept
{
return m_service.get();
}
Transport*
getTransport() const;
getTransport() const noexcept
{
return m_transport.get();
}
/** \brief Request that the face be closed
/** \brief Request that the face be closed.
*
* This operation is effective only if face is in the UP or DOWN state; otherwise, it has no effect.
* The face will change state to CLOSING, and then perform a cleanup procedure.
@@ -75,106 +82,133 @@ public:
close();
public: // upper interface connected to forwarding
/** \brief send Interest
/** \brief Send Interest.
*/
void
sendInterest(const Interest& interest);
/** \brief send Data
/** \brief Send Data.
*/
void
sendData(const Data& data);
/** \brief send Nack
/** \brief Send Nack.
*/
void
sendNack(const lp::Nack& nack);
/** \brief signals on Interest received
/** \brief Signals on Interest received.
*/
signal::Signal<LinkService, Interest, EndpointId>& afterReceiveInterest;
/** \brief signals on Data received
/** \brief Signals on Data received.
*/
signal::Signal<LinkService, Data, EndpointId>& afterReceiveData;
/** \brief signals on Nack received
/** \brief Signals on Nack received.
*/
signal::Signal<LinkService, lp::Nack, EndpointId>& afterReceiveNack;
/** \brief signals on Interest dropped by reliability system for exceeding allowed number of retx
/** \brief Signals on Interest dropped by reliability system for exceeding allowed number of retx.
*/
signal::Signal<LinkService, Interest>& onDroppedInterest;
public: // properties
/** \return face ID
/**
* \brief Returns the face ID.
*/
FaceId
getId() const;
getId() const noexcept
{
return m_id;
}
/** \brief sets face ID
* \note Normally, this should only be invoked by FaceTable.
/**
* \brief Sets the face ID.
* \note Normally, this should only be invoked by FaceTable.
*/
void
setId(FaceId id);
setId(FaceId id) noexcept
{
m_id = id;
}
/** \return a FaceUri representing local endpoint
/**
* \brief Returns a FaceUri representing the local endpoint.
*/
FaceUri
getLocalUri() const;
/** \return a FaceUri representing remote endpoint
/**
* \brief Returns a FaceUri representing the remote endpoint.
*/
FaceUri
getRemoteUri() const;
/** \return whether face is local or non-local for scope control purpose
/**
* \brief Returns whether the face is local or non-local for scope control purposes.
*/
ndn::nfd::FaceScope
getScope() const;
/** \return face persistency setting
/**
* \brief Returns the current persistency setting of the face.
*/
ndn::nfd::FacePersistency
getPersistency() const;
/** \brief changes face persistency setting
/**
* \brief Changes the face persistency setting.
*/
void
setPersistency(ndn::nfd::FacePersistency persistency);
/** \return whether face is point-to-point or multi-access
/**
* \brief Returns the link type of the face (point-to-point, multi-access, ...).
*/
ndn::nfd::LinkType
getLinkType() const;
/** \brief Returns face effective MTU
/**
* \brief Returns the effective MTU of the face.
*
* This function is a wrapper. The effective MTU of a face is determined by the link service.
* This function is a wrapper. The effective MTU of a face is determined by the link service.
*/
ssize_t
getMtu() const;
/** \return face state
/**
* \brief Returns the face state.
*/
FaceState
getState() const;
/** \brief signals after face state changed
/**
* \brief Signals after face state changed.
*/
signal::Signal<Transport, FaceState/*old*/, FaceState/*new*/>& afterStateChange;
/** \return expiration time of the face
* \retval time::steady_clock::TimePoint::max() the face has an indefinite lifetime
/**
* \brief Returns the expiration time of the face.
* \retval time::steady_clock::time_point::max() The face has an indefinite lifetime.
*/
time::steady_clock::TimePoint
time::steady_clock::time_point
getExpirationTime() const;
const FaceCounters&
getCounters() const;
getCounters() const noexcept
{
return m_counters;
}
FaceCounters&
getCounters() noexcept
{
return m_counters;
}
/**
* \brief Get channel on which face was created (unicast) or the associated channel (multicast)
* \brief Get channel on which face was created (unicast) or the associated channel (multicast).
*/
weak_ptr<Channel>
getChannel() const
@@ -183,7 +217,7 @@ public: // properties
}
/**
* \brief Set channel on which face was created (unicast) or the associated channel (multicast)
* \brief Set channel on which face was created (unicast) or the associated channel (multicast).
*/
void
setChannel(weak_ptr<Channel> channel)
@@ -192,25 +226,13 @@ public: // properties
}
private:
FaceId m_id;
FaceId m_id = INVALID_FACEID;
unique_ptr<LinkService> m_service;
unique_ptr<Transport> m_transport;
FaceCounters m_counters;
weak_ptr<Channel> m_channel;
};
inline LinkService*
Face::getLinkService() const
{
return m_service.get();
}
inline Transport*
Face::getTransport() const
{
return m_transport.get();
}
inline void
Face::close()
{
@@ -235,18 +257,6 @@ Face::sendNack(const lp::Nack& nack)
m_service->sendNack(nack);
}
inline FaceId
Face::getId() const
{
return m_id;
}
inline void
Face::setId(FaceId id)
{
m_id = id;
}
inline FaceUri
Face::getLocalUri() const
{
@@ -295,18 +305,12 @@ Face::getState() const
return m_transport->getState();
}
inline time::steady_clock::TimePoint
inline time::steady_clock::time_point
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);
+30 -101
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -24,14 +24,13 @@
*/
#include "generic-link-service.hpp"
#include <iostream>
#include <ndn-cxx/lp/pit-token.hpp>
#include <ndn-cxx/lp/tags.hpp>
#include <cmath>
namespace nfd {
namespace face {
namespace nfd::face {
NFD_LOG_INIT(GenericLinkService);
@@ -45,46 +44,12 @@ 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::TimePoint::max())
, m_nextMarkTime(time::steady_clock::time_point::max())
, m_nMarkedSinceInMarkingState(0)
, globalSp(options.C * 0.99, options.vqSize)
{
std::cout << "C: " << options.C << std::endl;
m_reassembler.beforeTimeout.connect([this] (auto...) { ++this->nReassemblyTimeouts; });
m_reliability.onDroppedInterest.connect([this] (const auto& i) { this->notifyDroppedInterest(i); });
m_reassembler.beforeTimeout.connect([this] (auto&&...) { ++nReassemblyTimeouts; });
m_reliability.onDroppedInterest.connect([this] (const auto& i) { 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
@@ -139,7 +104,7 @@ GenericLinkService::sendLpPacket(lp::Packet&& pkt)
auto block = pkt.wireEncode();
if (mtu != MTU_UNLIMITED && block.size() > static_cast<size_t>(mtu)) {
++this->nOutOverMtu;
++nOutOverMtu;
NFD_LOG_FACE_WARN("attempted to send packet over MTU limit");
return;
}
@@ -149,34 +114,11 @@ GenericLinkService::sendLpPacket(lp::Packet&& pkt)
void
GenericLinkService::doSendInterest(const Interest& interest)
{
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);
//}
}
lp::Packet lpPacket(interest.wireEncode());
// encodeLpFields(interest, lpPacket);
encodeLpFields(interest, lpPacket);
// this->sendNetPacket(std::move(lpPacket), true);
this->sendNetPacket(std::move(lpPacket), true);
}
void
@@ -264,7 +206,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)
++this->nFragmentationErrors;
++nFragmentationErrors;
return;
}
}
@@ -318,7 +260,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::TimePoint::max()) {
if (m_nextMarkTime == time::steady_clock::time_point::max()) {
m_nextMarkTime = now + m_options.baseCongestionMarkingInterval;
}
// Mark packet if sendQueue stays above target for one interval
@@ -336,10 +278,10 @@ GenericLinkService::checkCongestionLevel(lp::Packet& pkt)
m_nextMarkTime += interval;
}
}
else if (m_nextMarkTime != time::steady_clock::TimePoint::max()) {
else if (m_nextMarkTime != time::steady_clock::time_point::max()) {
// Congestion incident has ended, so reset
NFD_LOG_FACE_DEBUG("Send queue length dropped below congestion threshold");
m_nextMarkTime = time::steady_clock::TimePoint::max();
m_nextMarkTime = time::steady_clock::time_point::max();
m_nMarkedSinceInMarkingState = 0;
}
}
@@ -353,7 +295,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");
++this->nDuplicateSequence;
++nDuplicateSequence;
return;
}
}
@@ -369,16 +311,13 @@ GenericLinkService::doReceivePacket(const Block& packet, const EndpointId& endpo
return;
}
bool isReassembled = false;
Block netPkt;
lp::Packet firstPkt;
std::tie(isReassembled, netPkt, firstPkt) = m_reassembler.receiveFragment(endpoint, pkt);
auto [isReassembled, netPkt, firstPkt] = m_reassembler.receiveFragment(endpoint, pkt);
if (isReassembled) {
this->decodeNetPacket(netPkt, firstPkt, endpoint);
}
}
catch (const tlv::Error& e) {
++this->nInLpInvalid;
++nInLpInvalid;
NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
}
}
@@ -401,14 +340,14 @@ GenericLinkService::decodeNetPacket(const Block& netPkt, const lp::Packet& first
this->decodeData(netPkt, firstPkt, endpointId);
break;
default:
++this->nInNetInvalid;
++nInNetInvalid;
NFD_LOG_FACE_WARN("unrecognized network-layer packet TLV-TYPE " << netPkt.type() << ": DROP");
return;
}
}
catch (const tlv::Error& e) {
++this->nInNetInvalid;
NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP" << netPkt.type());
++nInNetInvalid;
NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
}
}
@@ -433,7 +372,7 @@ GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstP
}
if (firstPkt.has<lp::CachePolicyField>()) {
++this->nInNetInvalid;
++nInNetInvalid;
NFD_LOG_FACE_WARN("received CachePolicy with Interest: DROP");
return;
}
@@ -456,7 +395,7 @@ GenericLinkService::decodeInterest(const Block& netPkt, const lp::Packet& firstP
}
if (firstPkt.has<lp::PrefixAnnouncementField>()) {
++this->nInNetInvalid;
++nInNetInvalid;
NFD_LOG_FACE_WARN("received PrefixAnnouncement with Interest: DROP");
return;
}
@@ -465,8 +404,6 @@ 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);
}
@@ -480,13 +417,13 @@ GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt,
auto data = make_shared<Data>(netPkt);
if (firstPkt.has<lp::NackField>()) {
++this->nInNetInvalid;
++nInNetInvalid;
NFD_LOG_FACE_WARN("received Nack with Data: DROP");
return;
}
if (firstPkt.has<lp::NextHopFaceIdField>()) {
++this->nInNetInvalid;
++nInNetInvalid;
NFD_LOG_FACE_WARN("received NextHopFaceId with Data: DROP");
return;
}
@@ -507,7 +444,7 @@ GenericLinkService::decodeData(const Block& netPkt, const lp::Packet& firstPkt,
}
if (firstPkt.has<lp::NonDiscoveryField>()) {
++this->nInNetInvalid;
++nInNetInvalid;
NFD_LOG_FACE_WARN("received NonDiscovery with Data: DROP");
return;
}
@@ -521,13 +458,6 @@ 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);
}
@@ -542,13 +472,13 @@ GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt,
nack.setHeader(firstPkt.get<lp::NackField>());
if (firstPkt.has<lp::NextHopFaceIdField>()) {
++this->nInNetInvalid;
++nInNetInvalid;
NFD_LOG_FACE_WARN("received NextHopFaceId with Nack: DROP");
return;
}
if (firstPkt.has<lp::CachePolicyField>()) {
++this->nInNetInvalid;
++nInNetInvalid;
NFD_LOG_FACE_WARN("received CachePolicy with Nack: DROP");
return;
}
@@ -562,13 +492,13 @@ GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt,
}
if (firstPkt.has<lp::NonDiscoveryField>()) {
++this->nInNetInvalid;
++nInNetInvalid;
NFD_LOG_FACE_WARN("received NonDiscovery with Nack: DROP");
return;
}
if (firstPkt.has<lp::PrefixAnnouncementField>()) {
++this->nInNetInvalid;
++nInNetInvalid;
NFD_LOG_FACE_WARN("received PrefixAnnouncement with Nack: DROP");
return;
}
@@ -576,5 +506,4 @@ GenericLinkService::decodeNack(const Block& netPkt, const lp::Packet& firstPkt,
this->receiveNack(nack, endpointId);
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+70 -84
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -30,75 +30,74 @@
#include "lp-fragmenter.hpp"
#include "lp-reassembler.hpp"
#include "lp-reliability.hpp"
#include "queues.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
/** \brief counters provided by GenericLinkService
* \note The type name 'GenericLinkServiceCounters' is implementation detail.
* Use 'GenericLinkService::Counters' in public API.
/** \brief Counters provided by GenericLinkService.
* \note The type name GenericLinkServiceCounters is an implementation detail.
* Use GenericLinkService::Counters in public API.
*/
class GenericLinkServiceCounters : public virtual LinkService::Counters
{
public:
/** \brief count of failed fragmentations
/** \brief Count of failed fragmentations.
*/
PacketCounter nFragmentationErrors;
/** \brief count of outgoing LpPackets dropped due to exceeding MTU limit
/** \brief Count of outgoing LpPackets dropped due to exceeding MTU limit.
*
* If this counter is non-zero, the operator should enable fragmentation.
*/
PacketCounter nOutOverMtu;
/** \brief count of invalid LpPackets dropped before reassembly
/** \brief Count of invalid LpPackets dropped before reassembly.
*/
PacketCounter nInLpInvalid;
/** \brief count of network-layer packets currently being reassembled
/** \brief Count of network-layer packets currently being reassembled.
*/
SizeCounter<LpReassembler> nReassembling;
/** \brief count of dropped partial network-layer packets due to reassembly timeout
/** \brief Count of dropped partial network-layer packets due to reassembly timeout.
*/
PacketCounter nReassemblyTimeouts;
/** \brief count of invalid reassembled network-layer packets dropped
/** \brief Count of invalid reassembled network-layer packets dropped.
*/
PacketCounter nInNetInvalid;
/** \brief count of network-layer packets that did not require retransmission of a fragment
/** \brief Count of network-layer packets that did not require retransmission of a fragment.
*/
PacketCounter nAcknowledged;
/** \brief count of network-layer packets that had at least one fragment retransmitted, but were
* eventually received in full
/** \brief Count of network-layer packets that had at least one fragment retransmitted, but were
* eventually received in full.
*/
PacketCounter nRetransmitted;
/** \brief count of network-layer packets dropped because a fragment reached the maximum number
* of retransmissions
/** \brief Count of network-layer packets dropped because a fragment reached the maximum number
* of retransmissions.
*/
PacketCounter nRetxExhausted;
/** \brief count of LpPackets dropped due to duplicate Sequence numbers
/** \brief Count of LpPackets dropped due to duplicate Sequence numbers.
*/
PacketCounter nDuplicateSequence;
/** \brief count of outgoing LpPackets that were marked with congestion marks
/** \brief Count of outgoing LpPackets that were marked with congestion marks.
*/
PacketCounter nCongestionMarked;
};
/** \brief GenericLinkService is a LinkService that implements the NDNLPv2 protocol
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
/**
* \brief GenericLinkService is a LinkService that implements the NDNLPv2 protocol.
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
*/
class GenericLinkService FINAL_UNLESS_WITH_TESTS : public LinkService
, protected virtual GenericLinkServiceCounters
class GenericLinkService NFD_FINAL_UNLESS_WITH_TESTS : public LinkService
, protected virtual GenericLinkServiceCounters
{
public:
/** \brief Options that control the behavior of GenericLinkService
/** \brief %Options that control the behavior of GenericLinkService.
*/
class Options
{
@@ -108,35 +107,35 @@ public:
}
public:
/** \brief enables encoding of IncomingFaceId, and decoding of NextHopFaceId and CachePolicy
/** \brief Enables encoding of IncomingFaceId, and decoding of NextHopFaceId and CachePolicy.
*/
bool allowLocalFields = false;
/** \brief enables fragmentation
/** \brief Enables fragmentation.
*/
bool allowFragmentation = false;
/** \brief options for fragmentation
/** \brief Options for fragmentation.
*/
LpFragmenter::Options fragmenterOptions;
/** \brief enables reassembly
/** \brief Enables reassembly.
*/
bool allowReassembly = false;
/** \brief options for reassembly
/** \brief Options for reassembly.
*/
LpReassembler::Options reassemblerOptions;
/** \brief options for reliability
/** \brief Options for reliability.
*/
LpReliability::Options reliabilityOptions;
/** \brief enables send queue congestion detection and marking
/** \brief Enables send queue congestion detection and marking.
*/
bool allowCongestionMarking = false;
/** \brief starting value for congestion marking interval
/** \brief Starting value for congestion marking interval.
*
* Packets are marked if the queue size stays above THRESHOLD for at least one INTERVAL.
*
@@ -144,7 +143,7 @@ public:
*/
time::nanoseconds baseCongestionMarkingInterval = 100_ms;
/** \brief default congestion threshold in bytes
/** \brief Default congestion threshold in bytes.
*
* Packets are marked if the queue size stays above THRESHOLD for at least one INTERVAL.
*
@@ -152,96 +151,99 @@ public:
*/
size_t defaultCongestionThreshold = 65536;
/** \brief enables self-learning forwarding support
/** \brief Enables self-learning forwarding support.
*/
bool allowSelfLearning = true;
/** \brief overrides MTU provided by Transport
/** \brief Overrides the MTU provided by Transport.
*
* This MTU value will be used instead of the MTU provided by the transport if it is less than
* the transport MTU. However, it will not be utilized when the transport MTU is unlimited.
*
* Acceptable values for the override MTU are values >= MIN_MTU, which can be validated before
* Acceptable values for this option are values >= #MIN_MTU, which can be validated before
* being set with canOverrideMtuTo().
*/
ssize_t overrideMtu = std::numeric_limits<ssize_t>::max();
uint64_t C = 100000000; // 100Mbps
size_t vqSize = 20;
};
/** \brief counters provided by GenericLinkService
/** \brief %Counters provided by GenericLinkService.
*/
using Counters = GenericLinkServiceCounters;
explicit
GenericLinkService(const Options& options = {});
/** \brief get Options used by GenericLinkService
/** \brief Get the options used by GenericLinkService.
*/
const Options&
getOptions() const;
getOptions() const
{
return m_options;
}
/** \brief sets Options used by GenericLinkService
/** \brief Sets the options used by GenericLinkService.
*/
void
setOptions(const Options& options);
const Counters&
getCounters() const OVERRIDE_WITH_TESTS_ELSE_FINAL;
getCounters() const NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL
{
return *this;
}
ssize_t
getEffectiveMtu() const OVERRIDE_WITH_TESTS_ELSE_FINAL;
getEffectiveMtu() const NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL;
/** \brief Whether MTU can be overridden to the specified value
/** \brief Whether MTU can be overridden to the specified value.
*
* If the transport MTU is unlimited, then this will always return false.
*/
bool
canOverrideMtuTo(ssize_t mtu) const;
PROTECTED_WITH_TESTS_ELSE_PRIVATE: // send path
/** \brief request an IDLE packet to transmit pending service fields
NFD_PROTECTED_WITH_TESTS_ELSE_PRIVATE: // send path
/** \brief Request an IDLE packet to transmit pending service fields.
*/
void
requestIdlePacket();
/** \brief send an LpPacket
/** \brief Send an LpPacket.
*/
void
sendLpPacket(lp::Packet&& pkt);
void
doSendInterest(const Interest& interest) OVERRIDE_WITH_TESTS_ELSE_FINAL;
doSendInterest(const Interest& interest) NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL;
void
doSendData(const Data& data) OVERRIDE_WITH_TESTS_ELSE_FINAL;
doSendData(const Data& data) NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL;
void
doSendNack(const ndn::lp::Nack& nack) OVERRIDE_WITH_TESTS_ELSE_FINAL;
doSendNack(const ndn::lp::Nack& nack) NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL;
/** \brief assign consecutive sequence numbers to LpPackets
/** \brief Assign consecutive sequence numbers to LpPackets.
*/
void
assignSequences(std::vector<lp::Packet>& pkts);
private: // send path
/** \brief encode link protocol fields from tags onto an outgoing LpPacket
/** \brief Encode link protocol fields from tags onto an outgoing LpPacket.
* \param netPkt network-layer packet to extract tags from
* \param lpPacket LpPacket to add link protocol fields to
*/
void
encodeLpFields(const ndn::PacketBase& netPkt, lp::Packet& lpPacket);
/** \brief send a complete network layer packet
/** \brief Send a complete network layer packet.
* \param pkt LpPacket containing a complete network layer packet
* \param isInterest whether the network layer packet is an Interest
*/
void
sendNetPacket(lp::Packet&& pkt, bool isInterest);
/** \brief if the send queue is found to be congested, add a congestion mark to the packet
* according to CoDel
/** \brief If the send queue is found to be congested, add a congestion mark to the packet
* according to CoDel.
* \sa https://tools.ietf.org/html/rfc8289
*/
void
@@ -249,9 +251,9 @@ private: // send path
private: // receive path
void
doReceivePacket(const Block& packet, const EndpointId& endpoint) OVERRIDE_WITH_TESTS_ELSE_FINAL;
doReceivePacket(const Block& packet, const EndpointId& endpoint) NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL;
/** \brief decode incoming network-layer packet
/** \brief Decode incoming network-layer packet.
* \param netPkt reassembled network-layer packet
* \param firstPkt LpPacket of first fragment
* \param endpointId endpoint of peer who sent the packet
@@ -262,7 +264,7 @@ private: // receive path
void
decodeNetPacket(const Block& netPkt, const lp::Packet& firstPkt, const EndpointId& endpointId);
/** \brief decode incoming Interest
/** \brief Decode incoming Interest.
* \param netPkt reassembled network-layer packet; TLV-TYPE must be Interest
* \param firstPkt LpPacket of first fragment; must not have Nack field
* \param endpointId endpoint of peer who sent the Interest
@@ -275,7 +277,7 @@ private: // receive path
void
decodeInterest(const Block& netPkt, const lp::Packet& firstPkt, const EndpointId& endpointId);
/** \brief decode incoming Interest
/** \brief Decode incoming Interest.
* \param netPkt reassembled network-layer packet; TLV-TYPE must be Data
* \param firstPkt LpPacket of first fragment
* \param endpointId endpoint of peer who sent the Data
@@ -288,7 +290,7 @@ private: // receive path
void
decodeData(const Block& netPkt, const lp::Packet& firstPkt, const EndpointId& endpointId);
/** \brief decode incoming Interest
/** \brief Decode incoming Interest.
* \param netPkt reassembled network-layer packet; TLV-TYPE must be Interest
* \param firstPkt LpPacket of first fragment; must have Nack field
* \param endpointId endpoint of peer who sent the Nack
@@ -301,38 +303,22 @@ private: // receive path
void
decodeNack(const Block& netPkt, const lp::Packet& firstPkt, const EndpointId& endpointId);
PROTECTED_WITH_TESTS_ELSE_PRIVATE:
NFD_PROTECTED_WITH_TESTS_ELSE_PRIVATE:
Options m_options;
LpFragmenter m_fragmenter;
LpReassembler m_reassembler;
LpReliability m_reliability;
lp::Sequence m_lastSeqNo;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/// Time to mark next packet due to send queue congestion
time::steady_clock::TimePoint m_nextMarkTime;
time::steady_clock::time_point 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;
friend LpReliability;
};
inline const GenericLinkService::Options&
GenericLinkService::getOptions() const
{
return m_options;
}
inline const GenericLinkService::Counters&
GenericLinkService::getCounters() const
{
return *this;
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_GENERIC_LINK_SERVICE_HPP
+4 -6
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,8 +28,7 @@
#include "internal-transport.hpp"
#include "common/global.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
std::tuple<shared_ptr<Face>, shared_ptr<ndn::Face>>
makeInternalFace(ndn::KeyChain& clientKeyChain)
@@ -46,8 +45,7 @@ makeInternalFace(ndn::KeyChain& clientKeyChain)
auto clientFace = make_shared<ndn::Face>(clientTransport, getGlobalIoService(), clientKeyChain);
return std::make_tuple(face, clientFace);
return {face, clientFace};
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+8 -9
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
/*
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,16 +27,16 @@
#define NFD_DAEMON_FACE_INTERNAL_FACE_HPP
#include "face.hpp"
#include <ndn-cxx/face.hpp>
namespace nfd {
namespace face {
namespace nfd::face {
/** \brief make a pair of forwarder-side face and client-side face
* that are connected with each other
/** \brief Make a pair of forwarder-side face and client-side face
* that are connected to each other.
*
* Network-layer packets sent by one face will be received by the other face
* after io.poll().
* after `io.poll()`.
*
* \param clientKeyChain A KeyChain used by client-side face to sign
* prefix registration commands.
@@ -45,7 +45,6 @@ namespace face {
std::tuple<shared_ptr<Face>, shared_ptr<ndn::Face>>
makeInternalFace(ndn::KeyChain& clientKeyChain);
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_INTERNAL_FACE_HPP
+3 -15
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -26,8 +26,7 @@
#include "internal-transport.hpp"
#include "common/global.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
NFD_LOG_MEMBER_INIT(InternalForwarderTransport, InternalForwarderTransport);
NFD_LOG_MEMBER_INIT(InternalClientTransport, InternalClientTransport);
@@ -123,15 +122,4 @@ 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
} // namespace nfd::face
+4 -9
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -30,8 +30,7 @@
#include <ndn-cxx/transport/transport.hpp>
namespace nfd {
namespace face {
namespace nfd::face {
/** \brief Abstracts a transport that can be paired with another.
*/
@@ -101,10 +100,7 @@ public:
receivePacket(const Block& packet) final;
void
send(const Block& wire) final;
void
send(const Block& header, const Block& payload) final;
send(const Block& block) final;
void
close() final
@@ -128,7 +124,6 @@ private:
signal::ScopedConnection m_fwTransportStateConn;
};
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_INTERNAL_TRANSPORT_HPP
+5 -15
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -26,23 +26,14 @@
#include "link-service.hpp"
#include "face.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
NFD_LOG_INIT(LinkService);
LinkService::LinkService()
: m_face(nullptr)
, m_transport(nullptr)
{
}
LinkService::~LinkService()
{
}
LinkService::~LinkService() = default;
void
LinkService::setFaceAndTransport(Face& face, Transport& transport)
LinkService::setFaceAndTransport(Face& face, Transport& transport) noexcept
{
BOOST_ASSERT(m_face == nullptr);
BOOST_ASSERT(m_transport == nullptr);
@@ -135,5 +126,4 @@ operator<<(std::ostream& os, const FaceLogHelper<LinkService>& flh)
return os;
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+67 -77
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -30,147 +30,162 @@
#include "transport.hpp"
#include "common/counter.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
/** \brief counters provided by LinkService
* \note The type name 'LinkServiceCounters' is implementation detail.
* Use 'LinkService::Counters' in public API.
/** \brief Counters provided by LinkService.
* \note The type name LinkServiceCounters is an implementation detail.
* Use LinkService::Counters in public API.
*/
class LinkServiceCounters
{
public:
/** \brief count of incoming Interests
/** \brief Count of incoming Interests.
*/
PacketCounter nInInterests;
/** \brief count of outgoing Interests
/** \brief Count of outgoing Interests.
*/
PacketCounter nOutInterests;
/** \brief count of Interests dropped by reliability system for exceeding allowed number of retx
/** \brief Count of Interests dropped by reliability system for exceeding allowed number of retx.
*/
PacketCounter nInterestsExceededRetx;
/** \brief count of incoming Data packets
/** \brief Count of incoming Data packets.
*/
PacketCounter nInData;
/** \brief count of outgoing Data packets
/** \brief Count of outgoing Data packets.
*/
PacketCounter nOutData;
/** \brief count of incoming Nacks
/** \brief Count of incoming Nacks.
*/
PacketCounter nInNacks;
/** \brief count of outgoing Nacks
/** \brief Count of outgoing Nacks.
*/
PacketCounter nOutNacks;
};
/** \brief the upper part of a Face
* \sa Face
/**
* \brief The upper half of a Face.
* \sa Face, Transport
*/
class LinkService : protected virtual LinkServiceCounters, noncopyable
{
public:
/** \brief counters provided by LinkService
/**
* \brief %Counters provided by LinkService.
*/
typedef LinkServiceCounters Counters;
using Counters = LinkServiceCounters;
public:
LinkService();
virtual
~LinkService();
/** \brief set Face and Transport for LinkService
* \pre setFaceAndTransport has not been called
/**
* \brief Set Face and Transport for this LinkService.
* \pre setFaceAndTransport() has not been called.
*/
void
setFaceAndTransport(Face& face, Transport& transport);
setFaceAndTransport(Face& face, Transport& transport) noexcept;
/** \return Face to which this LinkService is attached
/**
* \brief Returns the Face to which this LinkService is attached.
*/
const Face*
getFace() const;
getFace() const noexcept
{
return m_face;
}
/** \return Transport to which this LinkService is attached
/**
* \brief Returns the Transport to which this LinkService is attached.
*/
const Transport*
getTransport() const;
getTransport() const noexcept
{
return m_transport;
}
/** \return Transport to which this LinkService is attached
/**
* \brief Returns the Transport to which this LinkService is attached.
*/
Transport*
getTransport();
getTransport() noexcept
{
return m_transport;
}
virtual const Counters&
getCounters() const;
getCounters() const
{
return *this;
}
virtual ssize_t
getEffectiveMtu() const;
public: // upper interface to be used by forwarding
/** \brief Send Interest
* \pre setTransport has been called
/** \brief Send Interest.
* \pre setFaceAndTransport() has been called.
*/
void
sendInterest(const Interest& interest);
/** \brief Send Data
* \pre setTransport has been called
/** \brief Send Data.
* \pre setFaceAndTransport() has been called.
*/
void
sendData(const Data& data);
/** \brief Send Nack
* \pre setTransport has been called
/** \brief Send Nack.
* \pre setFaceAndTransport() has been called.
*/
void
sendNack(const ndn::lp::Nack& nack);
/** \brief signals on Interest received
/** \brief Signals on Interest received.
*/
signal::Signal<LinkService, Interest, EndpointId> afterReceiveInterest;
/** \brief signals on Data received
/** \brief Signals on Data received.
*/
signal::Signal<LinkService, Data, EndpointId> afterReceiveData;
/** \brief signals on Nack received
/** \brief Signals on Nack received.
*/
signal::Signal<LinkService, lp::Nack, EndpointId> afterReceiveNack;
/** \brief signals on Interest dropped by reliability system for exceeding allowed number of retx
/** \brief Signals on Interest dropped by reliability system for exceeding allowed number of retx.
*/
signal::Signal<LinkService, Interest> onDroppedInterest;
public: // lower interface to be invoked by Transport
/** \brief performs LinkService specific operations to receive a lower-layer packet
/** \brief Performs LinkService specific operations to receive a lower-layer packet.
*/
void
receivePacket(const Block& packet, const EndpointId& endpoint);
protected: // upper interface to be invoked in subclass (receive path termination)
/** \brief delivers received Interest to forwarding
/** \brief Delivers received Interest to forwarding.
*/
void
receiveInterest(const Interest& interest, const EndpointId& endpoint);
/** \brief delivers received Data to forwarding
/** \brief Delivers received Data to forwarding.
*/
void
receiveData(const Data& data, const EndpointId& endpoint);
/** \brief delivers received Nack to forwarding
/** \brief Delivers received Nack to forwarding.
*/
void
receiveNack(const lp::Nack& nack, const EndpointId& endpoint);
protected: // lower interface to be invoked in subclass (send path termination)
/** \brief send a lower-layer packet via Transport
/** \brief Send a lower-layer packet via Transport.
*/
void
sendPacket(const Block& packet);
@@ -180,17 +195,17 @@ protected:
notifyDroppedInterest(const Interest& packet);
private: // upper interface to be overridden in subclass (send path entrypoint)
/** \brief performs LinkService specific operations to send an Interest
/** \brief Performs LinkService specific operations to send an Interest.
*/
virtual void
doSendInterest(const Interest& interest) = 0;
/** \brief performs LinkService specific operations to send a Data
/** \brief Performs LinkService specific operations to send a Data.
*/
virtual void
doSendData(const Data& data) = 0;
/** \brief performs LinkService specific operations to send a Nack
/** \brief Performs LinkService specific operations to send a Nack.
*/
virtual void
doSendNack(const lp::Nack& nack) = 0;
@@ -200,34 +215,10 @@ private: // lower interface to be overridden in subclass
doReceivePacket(const Block& packet, const EndpointId& endpoint) = 0;
private:
Face* m_face;
Transport* m_transport;
Face* m_face = nullptr;
Transport* m_transport = nullptr;
};
inline const Face*
LinkService::getFace() const
{
return m_face;
}
inline const Transport*
LinkService::getTransport() const
{
return m_transport;
}
inline Transport*
LinkService::getTransport()
{
return m_transport;
}
inline const LinkService::Counters&
LinkService::getCounters() const
{
return *this;
}
inline ssize_t
LinkService::getEffectiveMtu() const
{
@@ -250,14 +241,13 @@ std::ostream&
operator<<(std::ostream& os, const FaceLogHelper<LinkService>& flh);
template<typename T>
typename std::enable_if<std::is_base_of<LinkService, T>::value &&
!std::is_same<LinkService, T>::value, std::ostream&>::type
std::enable_if_t<std::is_base_of_v<LinkService, T> && !std::is_same_v<LinkService, T>,
std::ostream&>
operator<<(std::ostream& os, const FaceLogHelper<T>& flh)
{
return os << FaceLogHelper<LinkService>(flh.obj);
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_LINK_SERVICE_HPP
+16 -19
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2018, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,8 +28,7 @@
#include <ndn-cxx/encoding/tlv.hpp>
namespace nfd {
namespace face {
namespace nfd::face {
NFD_LOG_INIT(LpFragmenter);
@@ -39,18 +38,18 @@ static_assert(lp::tlv::FragIndex < 253, "FragIndex TLV-TYPE must fit in 1 octet"
static_assert(lp::tlv::FragCount < 253, "FragCount TLV-TYPE must fit in 1 octet");
static_assert(lp::tlv::Fragment < 253, "Fragment TLV-TYPE must fit in 1 octet");
/** \brief maximum overhead on a single fragment,
* not counting other NDNLPv2 headers
/**
* \brief Maximum overhead on a single fragment, not counting other NDNLPv2 headers.
*/
static const size_t MAX_SINGLE_FRAG_OVERHEAD =
constexpr size_t MAX_SINGLE_FRAG_OVERHEAD =
1 + 9 + // LpPacket TLV-TYPE and TLV-LENGTH
1 + 1 + 8 + // Sequence TLV
1 + 9; // Fragment TLV-TYPE and TLV-LENGTH
/** \brief maximum overhead of adding fragmentation to payload,
* not counting other NDNLPv2 headers
/**
* \brief Maximum overhead of adding fragmentation to payload, not counting other NDNLPv2 headers.
*/
static const size_t MAX_FRAG_OVERHEAD =
constexpr size_t MAX_FRAG_OVERHEAD =
1 + 9 + // LpPacket TLV-TYPE and TLV-LENGTH
1 + 1 + 8 + // Sequence TLV
1 + 1 + 8 + // FragIndex TLV
@@ -86,18 +85,17 @@ LpFragmenter::fragmentPacket(const lp::Packet& packet, size_t mtu)
// fast path: fragmentation not needed
// To qualify for fast path, the packet must have space for adding a sequence number,
// because another NDNLPv2 feature may require the sequence number.
return std::make_tuple(true, std::vector<lp::Packet>{packet});
return {true, {packet}};
}
ndn::Buffer::const_iterator netPktBegin, netPktEnd;
std::tie(netPktBegin, netPktEnd) = packet.get<lp::FragmentField>();
auto [netPktBegin, netPktEnd] = packet.get<lp::FragmentField>();
size_t netPktSize = std::distance(netPktBegin, netPktEnd);
// compute size of other NDNLPv2 headers to be placed on the first fragment
size_t firstHeaderSize = 0;
const Block& packetWire = packet.wireEncode();
const auto& packetWire = packet.wireEncode();
if (packetWire.type() == lp::tlv::LpPacket) {
for (const Block& element : packetWire.elements()) {
for (const auto& element : packetWire.elements()) {
if (element.type() != lp::tlv::Fragment) {
firstHeaderSize += element.size();
}
@@ -107,7 +105,7 @@ LpFragmenter::fragmentPacket(const lp::Packet& packet, size_t mtu)
// compute payload size
if (MAX_FRAG_OVERHEAD + firstHeaderSize + 1 > mtu) { // 1-octet fragment
NFD_LOG_FACE_WARN("fragmentation error, MTU too small for first fragment: DROP");
return std::make_tuple(false, std::vector<lp::Packet>{});
return {false, {}};
}
size_t firstPayloadSize = std::min(netPktSize, mtu - firstHeaderSize - MAX_FRAG_OVERHEAD);
size_t payloadSize = mtu - MAX_FRAG_OVERHEAD;
@@ -117,7 +115,7 @@ LpFragmenter::fragmentPacket(const lp::Packet& packet, size_t mtu)
// compute FragCount
if (fragCount > m_options.nMaxFragments) {
NFD_LOG_FACE_WARN("fragmentation error, FragCount over limit: DROP");
return std::make_tuple(false, std::vector<lp::Packet>{});
return {false, {}};
}
// populate fragments
@@ -139,7 +137,7 @@ LpFragmenter::fragmentPacket(const lp::Packet& packet, size_t mtu)
}
BOOST_ASSERT(fragIndex == fragCount);
return std::make_tuple(true, frags);
return {true, frags};
}
std::ostream&
@@ -154,5 +152,4 @@ operator<<(std::ostream& os, const FaceLogHelper<LpFragmenter>& flh)
return os;
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+8 -10
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -30,20 +30,19 @@
#include <ndn-cxx/lp/packet.hpp>
namespace nfd {
namespace face {
namespace nfd::face {
/** \brief fragments network-layer packets into NDNLPv2 link-layer packets
/** \brief Fragments network-layer packets into NDNLPv2 link-layer packets.
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
*/
class LpFragmenter
{
public:
/** \brief Options that control the behavior of LpFragmenter
/** \brief %Options that control the behavior of LpFragmenter.
*/
struct Options
{
/** \brief maximum number of fragments in a packet
/** \brief Maximum number of fragments in a packet.
*/
size_t nMaxFragments = 400;
};
@@ -51,7 +50,7 @@ public:
explicit
LpFragmenter(const Options& options, const LinkService* linkService = nullptr);
/** \brief set options for fragmenter
/** \brief Set options for fragmenter.
*/
void
setOptions(const Options& options);
@@ -63,7 +62,7 @@ public:
const LinkService*
getLinkService() const;
/** \brief fragments a network-layer packet into link-layer packets
/** \brief Fragments a network-layer packet into link-layer packets.
* \param packet an LpPacket that contains a network-layer packet;
* must have Fragment field, must not have FragIndex and FragCount fields
* \param mtu maximum allowable LpPacket size after fragmentation and sequence number assignment
@@ -80,7 +79,6 @@ private:
std::ostream&
operator<<(std::ostream& os, const FaceLogHelper<LpFragmenter>& flh);
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_LP_FRAGMENTER_HPP
+19 -27
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -29,8 +29,7 @@
#include <numeric>
namespace nfd {
namespace face {
namespace nfd::face {
NFD_LOG_INIT(LpReassembler);
@@ -41,12 +40,10 @@ LpReassembler::LpReassembler(const LpReassembler::Options& options, const LinkSe
}
std::tuple<bool, Block, lp::Packet>
LpReassembler::receiveFragment(EndpointId remoteEndpoint, const lp::Packet& packet)
LpReassembler::receiveFragment(const EndpointId& remoteEndpoint, const lp::Packet& packet)
{
BOOST_ASSERT(packet.has<lp::FragmentField>());
static auto FALSE_RETURN = std::make_tuple(false, Block(), lp::Packet());
// read and check FragIndex and FragCount
uint64_t fragIndex = 0;
uint64_t fragCount = 1;
@@ -59,29 +56,29 @@ LpReassembler::receiveFragment(EndpointId remoteEndpoint, const lp::Packet& pack
if (fragIndex >= fragCount) {
NFD_LOG_FACE_WARN("reassembly error, FragIndex>=FragCount: DROP");
return FALSE_RETURN;
return {false, {}, {}};
}
if (fragCount > m_options.nMaxFragments) {
NFD_LOG_FACE_WARN("reassembly error, FragCount over limit: DROP");
return FALSE_RETURN;
return {false, {}, {}};
}
// check for fast path
if (fragIndex == 0 && fragCount == 1) {
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);
auto frag = packet.get<lp::FragmentField>();
Block netPkt({frag.first, frag.second});
return {true, netPkt, packet};
}
// check Sequence and compute message identifier
if (!packet.has<lp::SequenceField>()) {
NFD_LOG_FACE_WARN("reassembly error, Sequence missing: DROP");
return FALSE_RETURN;
return {false, {}, {}};
}
lp::Sequence messageIdentifier = packet.get<lp::SequenceField>() - fragIndex;
Key key = std::make_tuple(remoteEndpoint, messageIdentifier);
Key key(remoteEndpoint, messageIdentifier);
// add to PartialPacket
PartialPacket& pp = m_partialPackets[key];
@@ -93,13 +90,13 @@ LpReassembler::receiveFragment(EndpointId remoteEndpoint, const lp::Packet& pack
else {
if (fragCount != pp.fragCount) {
NFD_LOG_FACE_WARN("reassembly error, FragCount changed: DROP");
return FALSE_RETURN;
return {false, {}, {}};
}
}
if (pp.fragments[fragIndex].has<lp::SequenceField>()) {
NFD_LOG_FACE_TRACE("fragment already received: DROP");
return FALSE_RETURN;
return {false, {}, {}};
}
pp.fragments[fragIndex] = packet;
@@ -110,13 +107,13 @@ LpReassembler::receiveFragment(EndpointId remoteEndpoint, const lp::Packet& pack
Block reassembled = doReassembly(key);
lp::Packet firstFrag(std::move(pp.fragments[0]));
m_partialPackets.erase(key);
return std::make_tuple(true, reassembled, firstFrag);
return {true, reassembled, firstFrag};
}
// set drop timer
pp.dropTimer = getScheduler().schedule(m_options.reassemblyTimeout, [=] { timeoutPartialPacket(key); });
return FALSE_RETURN;
return {false, {}, {}};
}
Block
@@ -126,21 +123,17 @@ LpReassembler::doReassembly(const Key& key)
size_t payloadSize = std::accumulate(pp.fragments.begin(), pp.fragments.end(), 0U,
[&] (size_t sum, const lp::Packet& pkt) -> size_t {
ndn::Buffer::const_iterator fragBegin, fragEnd;
std::tie(fragBegin, fragEnd) = pkt.get<lp::FragmentField>();
auto [fragBegin, fragEnd] = pkt.get<lp::FragmentField>();
return sum + std::distance(fragBegin, fragEnd);
});
ndn::Buffer fragBuffer(payloadSize);
auto it = fragBuffer.begin();
for (const lp::Packet& frag : pp.fragments) {
ndn::Buffer::const_iterator fragBegin, fragEnd;
std::tie(fragBegin, fragEnd) = frag.get<lp::FragmentField>();
auto [fragBegin, fragEnd] = frag.get<lp::FragmentField>();
it = std::copy(fragBegin, fragEnd, it);
}
return Block(&*(fragBuffer.cbegin()), std::distance(fragBuffer.cbegin(), fragBuffer.cend()));
return Block(fragBuffer);
}
void
@@ -167,5 +160,4 @@ operator<<(std::ostream& os, const FaceLogHelper<LpReassembler>& flh)
return os;
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+27 -25
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -30,26 +30,26 @@
#include <ndn-cxx/lp/packet.hpp>
namespace nfd {
namespace face {
namespace nfd::face {
/** \brief reassembles fragmented network-layer packets
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
/**
* \brief Reassembles fragmented network-layer packets.
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
*/
class LpReassembler : noncopyable
{
public:
/** \brief Options that control the behavior of LpReassembler
/** \brief %Options that control the behavior of LpReassembler.
*/
struct Options
{
/** \brief maximum number of fragments in a packet
/** \brief Maximum number of fragments in a packet.
*
* LpPackets with FragCount over this limit are dropped.
*/
size_t nMaxFragments = 400;
/** \brief timeout before a partially reassembled packet is dropped
/** \brief Timeout before a partially reassembled packet is dropped.
*/
time::nanoseconds reassemblyTimeout = 500_ms;
};
@@ -57,7 +57,7 @@ public:
explicit
LpReassembler(const Options& options, const LinkService* linkService = nullptr);
/** \brief set options for reassembler
/** \brief Set options for reassembler.
*/
void
setOptions(const Options& options);
@@ -69,7 +69,7 @@ public:
const LinkService*
getLinkService() const;
/** \brief adds received fragment to the buffer
/** \brief Adds received fragment to the buffer.
* \param remoteEndpoint endpoint that sent the packet
* \param packet received fragment; must have Fragment field
* \return a tuple containing:
@@ -79,24 +79,26 @@ public:
* \throw tlv::Error packet is malformed
*/
std::tuple<bool, Block, lp::Packet>
receiveFragment(EndpointId remoteEndpoint, const lp::Packet& packet);
receiveFragment(const EndpointId& remoteEndpoint, const lp::Packet& packet);
/** \brief count of partial packets
/** \brief Count of partial packets.
*/
size_t
size() const;
/** \brief signals before a partial packet is dropped due to timeout
/**
* \brief Notifies before a partial packet is dropped due to timeout.
*
* If a partial packet is incomplete and no new fragment is received
* within Options::reassemblyTimeout, it would be dropped due to timeout.
* Before it's erased, this signal is emitted with the remote endpoint,
* and the number of fragments being dropped.
* If a partial packet is incomplete and no new fragments are received within
* Options::reassemblyTimeout, the partial packet is dropped due to timeout.
* Before dropping the packet, this signal is emitted with the remote endpoint
* and the number of fragments being dropped.
*/
signal::Signal<LpReassembler, EndpointId, size_t> beforeTimeout;
private:
/** \brief holds all fragments of packet until reassembled
/**
* \brief Holds all fragments of a packet until reassembled.
*/
struct PartialPacket
{
@@ -106,12 +108,13 @@ private:
scheduler::ScopedEventId dropTimer;
};
/** \brief index key for PartialPackets
/**
* \brief Index key for PartialPackets.
*/
typedef std::tuple<
EndpointId, // remoteEndpoint
lp::Sequence // message identifier (sequence of the first fragment)
> Key;
using Key = std::tuple<
EndpointId, // remote endpoint
lp::Sequence // message identifier (sequence number of the first fragment)
>;
Block
doReassembly(const Key& key);
@@ -146,7 +149,6 @@ LpReassembler::size() const
return m_partialPackets.size();
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_LP_REASSEMBLER_HPP
+13 -23
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,8 +28,7 @@
#include "transport.hpp"
#include "common/global.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
NFD_LOG_INIT(LpReliability);
@@ -80,10 +79,7 @@ LpReliability::handleOutgoing(std::vector<lp::Packet>& frags, lp::Packet&& pkt,
lp::Sequence txSeq = assignTxSequence(frag);
// Store LpPacket for future retransmissions
unackedFragsIt = m_unackedFrags.emplace_hint(unackedFragsIt,
std::piecewise_construct,
std::forward_as_tuple(txSeq),
std::forward_as_tuple(frag));
unackedFragsIt = m_unackedFrags.try_emplace(unackedFragsIt, txSeq, frag);
unackedFragsIt->second.sendTime = sendTime;
auto rto = m_rttEst.getEstimatedRto();
lp::Sequence seq = frag.get<lp::SequenceField>();
@@ -174,12 +170,12 @@ 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.size() > 0 &&
while (!m_recentRecvSeqsQueue.empty() &&
now > m_recentRecvSeqs[m_recentRecvSeqsQueue.front()] + rto) {
m_recentRecvSeqs.erase(m_recentRecvSeqsQueue.front());
m_recentRecvSeqsQueue.pop();
}
m_recentRecvSeqs.emplace(pktSequence, now);
m_recentRecvSeqs.try_emplace(pktSequence, now);
m_recentRecvSeqsQueue.push(pktSequence);
}
@@ -226,7 +222,7 @@ LpReliability::assignTxSequence(lp::Packet& frag)
{
lp::Sequence txSeq = ++m_lastTxSeqNo;
frag.set<lp::TxSequenceField>(txSeq);
if (m_unackedFrags.size() > 0 && m_lastTxSeqNo == m_firstUnackedFrag->first) {
if (!m_unackedFrags.empty() && m_lastTxSeqNo == m_firstUnackedFrag->first) {
NDN_THROW(std::length_error("TxSequence range exceeded"));
}
return m_lastTxSeqNo;
@@ -310,10 +306,8 @@ LpReliability::onLpPacketLost(lp::Sequence txSeq, bool isTimeout)
// Notify strategy of dropped Interest (if any)
if (netPkt->isInterest) {
BOOST_ASSERT(netPkt->pkt.has<lp::FragmentField>());
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));
auto frag = netPkt->pkt.get<lp::FragmentField>();
onDroppedInterest(Interest(Block({frag.first, frag.second})));
}
// Delete this LpPacket from m_unackedFrags
@@ -326,13 +320,10 @@ LpReliability::onLpPacketLost(lp::Sequence txSeq, bool isTimeout)
netPkt->didRetx = true;
// Move fragment to new TxSequence mapping
auto newTxFragIt = m_unackedFrags.emplace_hint(
m_firstUnackedFrag != m_unackedFrags.end() && m_firstUnackedFrag->first > newTxSeq
? m_firstUnackedFrag
: m_unackedFrags.end(),
std::piecewise_construct,
std::forward_as_tuple(newTxSeq),
std::forward_as_tuple(txFrag.pkt));
auto hint = m_firstUnackedFrag != m_unackedFrags.end() && m_firstUnackedFrag->first > newTxSeq
? m_firstUnackedFrag
: m_unackedFrags.end();
auto newTxFragIt = m_unackedFrags.try_emplace(hint, newTxSeq, txFrag.pkt);
auto& newTxFrag = newTxFragIt->second;
newTxFrag.retxCount = txFrag.retxCount + 1;
newTxFrag.netPkt = netPkt;
@@ -434,5 +425,4 @@ operator<<(std::ostream& os, const FaceLogHelper<LpReliability>& flh)
return os;
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+42 -45
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -34,44 +34,49 @@
#include <queue>
namespace nfd {
namespace face {
namespace nfd::face {
class GenericLinkService;
/** \brief provides for reliable sending and receiving of link-layer packets
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
/**
* \brief Provides for reliable sending and receiving of link-layer packets.
* \sa https://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
*/
class LpReliability : noncopyable
{
public:
/// TxSequence TLV-TYPE (3 octets) + TLV-LENGTH (1 octet) + lp::Sequence (8 octets)
static constexpr size_t RESERVED_HEADER_SPACE = tlv::sizeOfVarNumber(lp::tlv::TxSequence) +
tlv::sizeOfVarNumber(sizeof(lp::Sequence)) +
sizeof(lp::Sequence);
struct Options
{
/** \brief enables link-layer reliability
/** \brief Enables link-layer reliability.
*/
bool isEnabled = false;
/** \brief maximum number of retransmissions for an LpPacket
/** \brief Maximum number of retransmissions for an LpPacket.
*/
size_t maxRetx = 3;
/** \brief period between sending pending Acks in an IDLE packet
/** \brief Period between sending pending Acks in an IDLE packet.
*/
time::nanoseconds idleAckTimerPeriod = 5_ms;
/** \brief a fragment is considered lost if this number of fragments with greater sequence
* numbers are acknowledged
/** \brief A fragment is considered lost if this number of fragments with greater sequence
* numbers are acknowledged.
*/
size_t seqNumLossThreshold = 3;
};
LpReliability(const Options& options, GenericLinkService* linkService);
/** \brief signals on Interest dropped by reliability system for exceeding allowed number of retx
/** \brief Signals on Interest dropped by reliability system for exceeding allowed number of retx.
*/
signal::Signal<LpReliability, Interest> onDroppedInterest;
/** \brief set options for reliability
/** \brief Set options for reliability.
*/
void
setOptions(const Options& options);
@@ -83,7 +88,7 @@ public:
const GenericLinkService*
getLinkService() const;
/** \brief observe outgoing fragment(s) of a network packet and store for potential retransmission
/** \brief Observe outgoing fragment(s) of a network packet and store for potential retransmission.
* \param frags fragments of network packet
* \param pkt encapsulated network packet
* \param isInterest whether the network packet is an Interest
@@ -91,27 +96,26 @@ public:
void
handleOutgoing(std::vector<lp::Packet>& frags, lp::Packet&& pkt, bool isInterest);
/** \brief extract and parse all Acks and add Ack for contained Fragment (if any) to AckQueue
/** \brief Extract and parse all Acks and add Ack for contained Fragment (if any) to AckQueue.
* \param pkt incoming LpPacket
* \return whether incoming LpPacket is new and not a duplicate
*/
bool
processIncomingPacket(const lp::Packet& pkt);
/** \brief called by GenericLinkService to attach Acks onto an outgoing LpPacket
/** \brief Called by GenericLinkService to attach Acks onto an outgoing LpPacket.
* \param pkt outgoing LpPacket to attach Acks to
* \param mtu MTU of the Transport
* \param mtu MTU of the transport
*/
void
piggyback(lp::Packet& pkt, ssize_t mtu);
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
class UnackedFrag;
class NetPkt;
using UnackedFrags = std::map<lp::Sequence, UnackedFrag>;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/** \brief assign TxSequence number to a fragment
/** \brief Assign TxSequence number to a fragment.
* \param frag fragment to assign TxSequence to
* \return assigned TxSequence number
* \throw std::length_error assigned TxSequence is equal to the start of the existing window
@@ -119,7 +123,7 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
lp::Sequence
assignTxSequence(lp::Packet& frag);
/** \brief start the idle Ack timer
/** \brief Start the idle Ack timer.
*
* This timer requests an IDLE packet to acknowledge pending fragments not already piggybacked.
* It is called regularly on a period configured in Options::idleAckTimerPeriod. This allows Acks
@@ -128,22 +132,22 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
void
startIdleAckTimer();
/** \brief find and mark as lost fragments where a configurable number of Acks
* (\p m_options.seqNumLossThreshold) have been received for greater TxSequence numbers
/** \brief Find and mark as lost fragments where a configurable number of Acks
* (Options::seqNumLossThreshold) have been received for greater TxSequence numbers.
* \param ackIt iterator pointing to acknowledged fragment
* \return vector containing TxSequences of fragments marked lost by this mechanism
*/
std::vector<lp::Sequence>
findLostLpPackets(UnackedFrags::iterator ackIt);
/** \brief resend (or give up on) a lost fragment
/** \brief Resend (or give up on) a lost fragment.
* \return vector of the TxSequences of fragments removed due to a network packet being removed
*/
std::vector<lp::Sequence>
onLpPacketLost(lp::Sequence txSeq, bool isTimeout);
/** \brief remove the fragment with the given sequence number from the map of unacknowledged
* fragments, as well as its associated network packet (if any)
/** \brief Remove the fragment with the given sequence number from the map of unacknowledged
* fragments, as well as its associated network packet (if any).
* \param fragIt iterator to acknowledged fragment
*
* If the given TxSequence marks the beginning of the send window, the window will be incremented.
@@ -152,7 +156,7 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
void
onLpPacketAcknowledged(UnackedFrags::iterator fragIt);
/** \brief delete a fragment from UnackedFrags and advance acknowledge window if necessary
/** \brief Delete a fragment from UnackedFrags and advance acknowledge window if necessary.
* \param fragIt iterator to an UnackedFrag, must be dereferencable
* \post fragIt is not in m_unackedFrags
* \post if was equal to m_firstUnackedFrag,
@@ -162,8 +166,9 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
void
deleteUnackedFrag(UnackedFrags::iterator fragIt);
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/** \brief contains a sent fragment that has not been acknowledged and associated data
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/**
* \brief Contains a sent fragment that has not been acknowledged and associated data.
*/
class UnackedFrag
{
@@ -174,13 +179,14 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
public:
lp::Packet pkt;
scheduler::ScopedEventId rtoTimer;
time::steady_clock::TimePoint sendTime;
time::steady_clock::time_point sendTime;
size_t retxCount;
size_t nGreaterSeqAcks; //!< number of Acks received for sequences greater than this fragment
shared_ptr<NetPkt> netPkt;
};
/** \brief contains a network-layer packet with unacknowledged fragments
/**
* \brief Contains a network-layer packet with unacknowledged fragments.
*/
class NetPkt
{
@@ -194,24 +200,16 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
bool didRetx;
};
public:
/// TxSequence TLV-TYPE (3 octets) + TLV-LENGTH (1 octet) + lp::Sequence (8 octets)
static constexpr size_t RESERVED_HEADER_SPACE = tlv::sizeOfVarNumber(lp::tlv::TxSequence) +
tlv::sizeOfVarNumber(sizeof(lp::Sequence)) +
sizeof(lp::Sequence);
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
Options m_options;
GenericLinkService* m_linkService;
UnackedFrags m_unackedFrags;
/** An iterator that points to the first unacknowledged fragment in the current window. The window
* can wrap around so that the beginning of the window is at a TxSequence greater than other
* fragments in the window. When the window is moved past the last item in the iterator, the
* first fragment in the map will become the start of the window.
*/
// An iterator that points to the first unacknowledged fragment in the current window. The window
// can wrap around so that the beginning of the window is at a TxSequence greater than other
// fragments in the window. When the window is moved past the last item in the iterator, the
// first fragment in the map will become the start of the window.
UnackedFrags::iterator m_firstUnackedFrag;
std::queue<lp::Sequence> m_ackQueue;
std::map<lp::Sequence, time::steady_clock::TimePoint> m_recentRecvSeqs;
std::map<lp::Sequence, time::steady_clock::time_point> m_recentRecvSeqs;
std::queue<lp::Sequence> m_recentRecvSeqsQueue;
lp::Sequence m_lastTxSeqNo;
scheduler::ScopedEventId m_idleAckTimer;
@@ -221,7 +219,6 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
std::ostream&
operator<<(std::ostream& os, const FaceLogHelper<LpReliability>& flh);
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_LP_RELIABILITY_HPP
+13 -16
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,9 +27,9 @@
#include "common/global.hpp"
#include <cerrno> // for errno
#include <cstdio> // for snprintf()
#include <cstring> // for memcpy(), strerror(), strncpy()
#include <net/if.h> // for struct ifreq
#include <stdio.h> // for snprintf()
#include <sys/ioctl.h> // for ioctl()
#if defined(__linux__)
@@ -43,8 +43,7 @@
#endif
#endif
namespace nfd {
namespace face {
namespace nfd::face {
NFD_LOG_INIT(MulticastEthernetTransport);
@@ -66,20 +65,19 @@ MulticastEthernetTransport::MulticastEthernetTransport(const ndn::net::NetworkIn
NFD_LOG_FACE_DEBUG("Creating transport");
char filter[110];
// note #1: we cannot use std::snprintf because it's not available
// on some platforms (see #2299)
// note #2: "not vlan" must appear last in the filter expression, or the
// rest of the filter won't work as intended (see pcap-filter(7))
snprintf(filter, sizeof(filter),
"(ether proto 0x%x) && (ether dst %s) && (not ether src %s) && (not vlan)",
ethernet::ETHERTYPE_NDN,
m_destAddress.toString().data(),
m_srcAddress.toString().data());
// Note: "not vlan" must appear last in the filter expression, or the
// rest of the filter won't work as intended (see pcap-filter(7))
std::snprintf(filter, sizeof(filter),
"(ether proto 0x%x) && (ether dst %s) && (not ether src %s) && (not vlan)",
ethernet::ETHERTYPE_NDN,
m_destAddress.toString().data(),
m_srcAddress.toString().data());
m_pcap.setPacketFilter(filter);
BOOST_ASSERT(m_destAddress.isMulticast());
if (!m_destAddress.isBroadcast())
if (!m_destAddress.isBroadcast()) {
joinMulticastGroup();
}
}
void
@@ -147,5 +145,4 @@ MulticastEthernetTransport::joinMulticastGroup()
NDN_THROW(Error("Failed to join multicast group"));
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+3 -5
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2017, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,8 +28,7 @@
#include "ethernet-transport.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
/**
* @brief A multicast Transport that uses raw Ethernet II frames
@@ -57,7 +56,6 @@ private:
#endif
};
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_MULTICAST_ETHERNET_TRANSPORT_HPP
+9 -34
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -29,7 +29,8 @@
#include "common/privilege-helper.hpp"
#include <boost/functional/hash.hpp>
#include <boost/asio/ip/multicast.hpp>
#include <boost/asio/ip/v6_only.hpp>
#ifdef __linux__
#include <cerrno> // for errno
@@ -37,8 +38,7 @@
#include <sys/socket.h> // for setsockopt()
#endif // __linux__
namespace nfd {
namespace face {
namespace nfd::face {
NFD_LOG_MEMBER_INIT_SPECIALIZED((DatagramTransport<boost::asio::ip::udp, Multicast>), MulticastUdpTransport);
@@ -134,7 +134,7 @@ void
MulticastUdpTransport::openRxSocket(protocol::socket& sock,
const protocol::endpoint& multicastGroup,
const boost::asio::ip::address& localAddress,
const shared_ptr<const ndn::net::NetworkInterface>& netif)
const ndn::net::NetworkInterface* netif)
{
BOOST_ASSERT(!sock.is_open());
@@ -148,16 +148,9 @@ MulticastUdpTransport::openRxSocket(protocol::socket& sock,
localAddress.to_v4()));
}
else {
BOOST_ASSERT(localAddress.is_v6());
BOOST_ASSERT(multicastGroup.address().to_v6().scope_id() != 0);
sock.set_option(boost::asio::ip::v6_only(true));
#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)
sock.bind(protocol::endpoint(boost::asio::ip::address_v6::any(), multicastGroup.port()));
else
#endif
sock.bind(multicastGroup);
sock.bind(multicastGroup);
sock.set_option(boost::asio::ip::multicast::join_group(multicastGroup.address().to_v6()));
}
@@ -168,7 +161,7 @@ MulticastUdpTransport::openRxSocket(protocol::socket& sock,
void
MulticastUdpTransport::openTxSocket(protocol::socket& sock,
const protocol::endpoint& localEndpoint,
const shared_ptr<const ndn::net::NetworkInterface>& netif,
const ndn::net::NetworkInterface* netif,
bool enableLoopback)
{
BOOST_ASSERT(!sock.is_open());
@@ -190,22 +183,4 @@ MulticastUdpTransport::openTxSocket(protocol::socket& sock,
}
}
template<>
EndpointId
DatagramTransport<boost::asio::ip::udp, Multicast>::makeEndpointId(const protocol::endpoint& ep)
{
if (ep.address().is_v4()) {
return (static_cast<uint64_t>(ep.port()) << 32) |
static_cast<uint64_t>(ep.address().to_v4().to_ulong());
}
else {
size_t seed = 0;
const auto& addrBytes = ep.address().to_v6().to_bytes();
boost::hash_range(seed, addrBytes.begin(), addrBytes.end());
boost::hash_combine(seed, ep.port());
return seed;
}
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+13 -16
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,21 +28,13 @@
#include "datagram-transport.hpp"
#include <boost/asio/ip/udp.hpp>
#include <ndn-cxx/net/network-interface.hpp>
namespace nfd {
namespace face {
namespace nfd::face {
NFD_LOG_MEMBER_DECL_SPECIALIZED((DatagramTransport<boost::asio::ip::udp, Multicast>));
// Explicit specialization of makeEndpointId for the UDP multicast case.
// Note that this "shall be declared before the first use of the specialization
// that would cause an implicit instantiation to take place, in every translation
// unit in which such a use occurs".
template<>
EndpointId
DatagramTransport<boost::asio::ip::udp, Multicast>::makeEndpointId(const protocol::endpoint& ep);
/**
* \brief A Transport that communicates on a UDP multicast group
*/
@@ -70,16 +62,22 @@ public:
ssize_t
getSendQueueLength() final;
/**
* \brief Opens and configures the receive-side socket
*/
static void
openRxSocket(protocol::socket& sock,
const protocol::endpoint& multicastGroup,
const boost::asio::ip::address& localAddress,
const shared_ptr<const ndn::net::NetworkInterface>& netif = nullptr);
const boost::asio::ip::address& localAddress = {},
const ndn::net::NetworkInterface* netif = nullptr);
/**
* \brief Opens and configures the transmit-side socket
*/
static void
openTxSocket(protocol::socket& sock,
const protocol::endpoint& localEndpoint,
const shared_ptr<const ndn::net::NetworkInterface>& netif = nullptr,
const ndn::net::NetworkInterface* netif = nullptr,
bool enableLoopback = false);
private:
@@ -94,7 +92,6 @@ private:
protocol::socket m_sendSocket;
};
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_MULTICAST_UDP_TRANSPORT_HPP
+5 -11
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,8 +27,7 @@
#include "face-system.hpp"
#include "common/logger.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
NFD_LOG_INIT(NetdevBound);
@@ -46,9 +45,7 @@ NetdevBound::processConfig(OptionalConfigSection configSection,
std::vector<Rule> rules;
if (configSection) {
int ruleIndex = 0;
for (const auto& pair : *configSection) {
const std::string& key = pair.first;
const ConfigSection& value = pair.second;
for (const auto& [key, value] : *configSection) {
if (key == "rule") {
rules.push_back(parseRule(ruleIndex++, value));
}
@@ -94,9 +91,7 @@ NetdevBound::parseRule(int index, const ConfigSection& confRule) const
bool hasWhitelist = false;
bool hasBlacklist = false;
for (const auto& pair : confRule) {
const std::string& key = pair.first;
const ConfigSection& value = pair.second;
for (const auto& [key, value] : confRule) {
if (key == "remote") {
try {
rule.remotes.emplace_back(value.get_value<std::string>());
@@ -145,5 +140,4 @@ NetdevBound::parseRule(int index, const ConfigSection& confRule) const
return rule;
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+7 -9
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,12 +28,11 @@
#include "protocol-factory.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
class FaceSystem;
/** \brief manages netdev-bound faces
/** \brief Manages netdev-bound faces.
*/
class NetdevBound : noncopyable
{
@@ -55,13 +54,13 @@ public:
NetdevBound(const ProtocolFactoryCtorParams& params, const FaceSystem& faceSystem);
/** \brief process face_system.netdev_bound config section
/** \brief Process `face_system.netdev_bound` config section.
*/
void
processConfig(OptionalConfigSection configSection,
FaceSystem::ConfigContext& context);
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
struct Rule
{
std::vector<FaceUri> remotes;
@@ -71,7 +70,7 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
Rule
parseRule(int index, const ConfigSection& confRule) const;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
const FaceSystem& m_faceSystem;
FaceCreatedCallback m_addFace;
shared_ptr<ndn::net::NetworkMonitor> m_netmon;
@@ -82,7 +81,6 @@ PUBLIC_WITH_TESTS_ELSE_PRIVATE:
std::map<Key, shared_ptr<Face>> m_faces;
};
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_NETDEV_BOUND_HPP
+13 -9
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -29,8 +29,9 @@
#include <fnmatch.h>
namespace nfd {
namespace face {
#include <boost/lexical_cast.hpp>
namespace nfd::face {
NetworkPredicateBase::NetworkPredicateBase()
{
@@ -198,8 +199,10 @@ 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(), bind(&doesNetifMatchRule, std::cref(netif), _1)) &&
std::none_of(m_blacklist.begin(), m_blacklist.end(), bind(&doesNetifMatchRule, std::cref(netif), _1));
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); });
}
static bool
@@ -219,9 +222,10 @@ 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(), bind(&doesAddressMatchRule, std::cref(address), _1)) &&
std::none_of(m_blacklist.begin(), m_blacklist.end(), bind(&doesAddressMatchRule, std::cref(address), _1));
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); });
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+5 -6
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,10 +28,10 @@
#include "core/common.hpp"
#include <boost/property_tree/ptree_fwd.hpp>
#include <ndn-cxx/net/network-interface.hpp>
namespace nfd {
namespace face {
namespace nfd::face {
class NetworkPredicateBase
{
@@ -79,7 +79,7 @@ private:
void
parseList(std::set<std::string>& set, std::initializer_list<std::pair<std::string, std::string>> list);
PUBLIC_WITH_TESTS_ELSE_PROTECTED:
NFD_PUBLIC_WITH_TESTS_ELSE_PROTECTED:
std::set<std::string> m_whitelist;
std::set<std::string> m_blacklist;
};
@@ -130,7 +130,6 @@ private:
isRuleValid(const std::string& key, const std::string& value) final;
};
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_NETWORK_PREDICATE_HPP
+3 -5
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -27,8 +27,7 @@
#include "null-link-service.hpp"
#include "null-transport.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
shared_ptr<Face>
makeNullFace(const FaceUri& uri)
@@ -39,5 +38,4 @@ makeNullFace(const FaceUri& uri)
make_unique<NullTransport>(uri, uri, ndn::nfd::FACE_SCOPE_LOCAL));
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+6 -7
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2015, Regents of the University of California,
/*
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,15 +28,14 @@
#include "face.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
/** \return a Face that has no underlying transport and drops every packet
/**
* \brief Returns a Face that has no underlying transport and drops every packet.
*/
shared_ptr<Face>
makeNullFace(const FaceUri& uri = FaceUri("null://"));
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_NULL_FACE_HPP
+3 -5
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,8 +28,7 @@
#include "link-service.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
/** \brief A LinkService that drops every packet.
*/
@@ -57,7 +56,6 @@ private:
}
};
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_NULL_LINK_SERVICE_HPP
+3 -5
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -25,8 +25,7 @@
#include "null-transport.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
NFD_LOG_INIT(NullTransport);
@@ -43,5 +42,4 @@ NullTransport::NullTransport(const FaceUri& localUri, const FaceUri& remoteUri,
NFD_LOG_FACE_DEBUG("Creating transport");
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+6 -8
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,12 +28,11 @@
#include "transport.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
/** \brief A Transport that drops every packet.
*/
class NullTransport FINAL_UNLESS_WITH_TESTS : public Transport
class NullTransport NFD_FINAL_UNLESS_WITH_TESTS : public Transport
{
public:
explicit
@@ -44,19 +43,18 @@ public:
protected:
void
doClose() OVERRIDE_WITH_TESTS_ELSE_FINAL
doClose() NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL
{
setState(TransportState::CLOSED);
}
private:
void
doSend(const Block&) OVERRIDE_WITH_TESTS_ELSE_FINAL
doSend(const Block&) NFD_OVERRIDE_WITH_TESTS_ELSE_FINAL
{
}
};
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_NULL_TRANSPORT_HPP
+22 -17
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -26,6 +26,8 @@
#include "pcap-helper.hpp"
#include "ethernet-protocol.hpp"
#include "common/privilege-helper.hpp"
#include <pcap/pcap.h>
#include <unistd.h>
@@ -33,11 +35,9 @@
#define PCAP_NETMASK_UNKNOWN 0xffffffff
#endif
namespace nfd {
namespace face {
namespace nfd::face {
PcapHelper::PcapHelper(const std::string& interfaceName)
: m_pcap(nullptr)
{
char errbuf[PCAP_ERRBUF_SIZE] = {};
m_pcap = pcap_create(interfaceName.data(), errbuf);
@@ -55,7 +55,7 @@ PcapHelper::PcapHelper(const std::string& interfaceName)
pcap_set_buffer_size(m_pcap, 4 * 1024 * 1024);
}
PcapHelper::~PcapHelper()
PcapHelper::~PcapHelper() noexcept
{
close();
}
@@ -63,9 +63,15 @@ PcapHelper::~PcapHelper()
void
PcapHelper::activate(int dlt)
{
int ret = pcap_activate(m_pcap);
if (ret < 0)
NDN_THROW(Error("pcap_activate: " + std::string(pcap_statustostr(ret))));
PrivilegeHelper::runElevated([this] {
int ret = pcap_activate(m_pcap);
if (ret < 0)
NDN_THROW(Error("pcap_activate: " + std::string(pcap_statustostr(ret))));
});
char errbuf[PCAP_ERRBUF_SIZE] = {};
if (pcap_setnonblock(m_pcap, 1, errbuf) < 0)
NDN_THROW(Error("pcap_setnonblock: " + std::string(errbuf)));
if (pcap_set_datalink(m_pcap, dlt) < 0)
NDN_THROW(Error("pcap_set_datalink: " + getLastError()));
@@ -75,7 +81,7 @@ PcapHelper::activate(int dlt)
}
void
PcapHelper::close()
PcapHelper::close() noexcept
{
if (m_pcap) {
pcap_close(m_pcap);
@@ -96,7 +102,7 @@ PcapHelper::getFd() const
}
std::string
PcapHelper::getLastError() const
PcapHelper::getLastError() const noexcept
{
return pcap_geterr(m_pcap);
}
@@ -124,20 +130,19 @@ PcapHelper::setPacketFilter(const char* filter) const
NDN_THROW(Error("pcap_setfilter: " + getLastError()));
}
std::tuple<const uint8_t*, size_t, std::string>
PcapHelper::readNextPacket() const
std::tuple<span<const uint8_t>, std::string>
PcapHelper::readNextPacket() const noexcept
{
pcap_pkthdr* header;
const uint8_t* packet;
int ret = pcap_next_ex(m_pcap, &header, &packet);
if (ret < 0)
return std::make_tuple(nullptr, 0, getLastError());
return {span<uint8_t>{}, getLastError()};
else if (ret == 0)
return std::make_tuple(nullptr, 0, "timed out");
return {span<uint8_t>{}, "Nothing to read"};
else
return std::make_tuple(packet, header->caplen, "");
return {{packet, header->caplen}, ""};
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+18 -25
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
* Copyright (c) 2014-2017, Regents of the University of California,
/*
* Copyright (c) 2014-2022, 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 HAVE_LIBPCAP
#ifndef NFD_HAVE_LIBPCAP
#error "Cannot include this file when libpcap is not available"
#endif
@@ -36,8 +36,7 @@
struct pcap;
typedef pcap pcap_t;
namespace nfd {
namespace face {
namespace nfd::face {
/**
* @brief Helper class for dealing with libpcap handles.
@@ -48,11 +47,7 @@ public:
class Error : public std::runtime_error
{
public:
explicit
Error(const std::string& what)
: std::runtime_error(what)
{
}
using std::runtime_error::runtime_error;
};
/**
@@ -63,7 +58,7 @@ public:
explicit
PcapHelper(const std::string& interfaceName);
~PcapHelper();
~PcapHelper() noexcept;
/**
* @brief Start capturing packets.
@@ -79,7 +74,7 @@ public:
* @sa pcap_close(3pcap)
*/
void
close();
close() noexcept;
/**
* @brief Obtain a file descriptor that can be used in calls such as select(2) and poll(2).
@@ -98,7 +93,7 @@ public:
* @sa pcap_geterr(3pcap)
*/
std::string
getLastError() const;
getLastError() const noexcept;
/**
* @brief Get the number of packets dropped by the kernel, as reported by libpcap.
@@ -120,27 +115,25 @@ public:
/**
* @brief Read the next packet captured on the interface.
* @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.
* @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.
* @sa pcap_next_ex(3pcap)
*/
std::tuple<const uint8_t*, size_t, std::string>
readNextPacket() const;
std::tuple<span<const uint8_t>, std::string>
readNextPacket() const noexcept;
operator pcap_t*() const
operator pcap_t*() const noexcept
{
return m_pcap;
}
private:
pcap_t* m_pcap;
pcap_t* m_pcap = nullptr;
};
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_PCAP_HELPER_HPP
+3 -5
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,8 +28,7 @@
#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/copy.hpp>
namespace nfd {
namespace face {
namespace nfd::face {
ProtocolFactory::Registry&
ProtocolFactory::getRegistry()
@@ -129,5 +128,4 @@ ProtocolFactory::doGetChannels() const
return {};
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+41 -31
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -33,15 +33,16 @@
#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/copy.hpp>
namespace nfd {
namespace face {
namespace nfd::face {
/** \brief Parameters to ProtocolFactory constructor
/**
* \brief Parameters to ProtocolFactory constructor.
*
* Every ProtocolFactory subclass is expected to have a constructor that accepts CtorParams,
* which in turn passes it to ProtocolFactory base class constructor. Parameters are passed as a
* struct rather than individually, so that a future change in list of parameters does not
* require updates to subclass constructors.
* Every ProtocolFactory subclass is expected to have a constructor that accepts
* ProtocolFactory::CtorParams, which in turn passes it to ProtocolFactory base class
* constructor. Parameters are passed as a struct rather than individually, so that
* any future changes in the list of parameters will not require updates to all subclass
* constructors.
*/
struct ProtocolFactoryCtorParams
{
@@ -49,44 +50,52 @@ struct ProtocolFactoryCtorParams
shared_ptr<ndn::net::NetworkMonitor> netmon;
};
/** \brief Provides support for an underlying protocol
* \sa FaceSystem
/**
* \brief Provides support for an underlying protocol.
*
* A protocol factory provides support for an underlying protocol and owns Channel objects.
* It can process a subsection of face_system config section and create channels and multicast
* faces accordingly.
* A protocol factory provides support for an underlying protocol and owns Channel objects.
* It can process a subsection of the `face_system` configuration section and create channels
* and multicast faces accordingly.
*
* \sa FaceSystem
*/
class ProtocolFactory : noncopyable
{
public: // registry
using CtorParams = ProtocolFactoryCtorParams;
/** \brief Register a protocol factory type
* \tparam PF subclass of ProtocolFactory
* \param id factory identifier
/**
* \brief Register a protocol factory type.
* \tparam PF subclass of ProtocolFactory
* \param id factory identifier
*/
template<typename PF>
static void
registerType(const std::string& id = PF::getId())
{
Registry& registry = getRegistry();
BOOST_ASSERT(registry.count(id) == 0);
registry[id] = [] (const CtorParams& p) { return make_unique<PF>(p); };
BOOST_ASSERT(!id.empty());
auto r = getRegistry().insert_or_assign(id, [] (auto&&... p) {
return make_unique<PF>(std::forward<decltype(p)>(p)...);
});
BOOST_VERIFY(r.second);
}
/** \brief Create a protocol factory instance
* \retval nullptr if a factory with the given \p id is not registered
/**
* \brief Create a protocol factory instance.
* \retval nullptr if a factory with the given \p id is not registered
*/
static unique_ptr<ProtocolFactory>
create(const std::string& id, const CtorParams& params);
/** \brief Get all registered protocol factory ids
/**
* \brief Get all registered protocol factory IDs.
*/
static std::set<std::string>
[[nodiscard]] static std::set<std::string>
listRegistered();
public:
/** \brief Base class for all exceptions thrown by ProtocolFactory subclasses
/**
* \brief Base class for all exceptions thrown by ProtocolFactory subclasses.
*/
class Error : public std::runtime_error
{
@@ -101,18 +110,20 @@ public:
~ProtocolFactory() = 0;
#ifdef DOXYGEN
/** \brief Get id for this protocol factory
/**
* \brief Get the ID of this protocol factory.
*
* face_system.factory-id config section is processed by the protocol factory.
* `face_system.<factory-id>` config section is processed by the protocol factory.
*/
static const std::string&
getId() noexcept;
#endif
/** \brief Get FaceUri schemes accepted by this protocol factory
/**
* \brief Get FaceUri schemes accepted by this protocol factory.
*/
const std::set<std::string>&
getProvidedSchemes() const
getProvidedSchemes() const noexcept
{
return providedSchemes;
}
@@ -133,7 +144,7 @@ public:
struct CreateFaceRequest
{
FaceUri remoteUri;
optional<FaceUri> localUri;
std::optional<FaceUri> localUri;
FaceParams params;
};
@@ -246,8 +257,7 @@ protected:
shared_ptr<ndn::net::NetworkMonitor> netmon;
};
} // namespace face
} // namespace nfd
} // namespace nfd::face
/** \brief Registers a protocol factory
*
-534
View File
@@ -1,534 +0,0 @@
#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
@@ -1,309 +0,0 @@
#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
+3 -5
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2018, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -33,8 +33,7 @@
#include <sys/socket.h>
#endif
namespace nfd {
namespace face {
namespace nfd::face {
ssize_t
getTxQueueLength(int fd)
@@ -53,5 +52,4 @@ getTxQueueLength(int fd)
return queueLength;
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+4 -6
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2018, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,10 +28,9 @@
#include "core/common.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
/** \brief obtain send queue length from a specified system socket
/** \brief Obtain send queue length from a specified system socket.
* \param fd file descriptor of the socket
* \retval QUEUE_UNSUPPORTED this operation is unsupported on the current platform
* \retval QUEUE_ERROR there was an error retrieving the send queue length
@@ -42,7 +41,6 @@ namespace face {
ssize_t
getTxQueueLength(int fd);
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_SOCKET_UTILS_HPP
+10 -9
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -32,8 +32,9 @@
#include <queue>
namespace nfd {
namespace face {
#include <boost/asio/write.hpp>
namespace nfd::face {
/** \brief Implements Transport for stream-based protocols.
*
@@ -43,7 +44,7 @@ template<class Protocol>
class StreamTransport : public Transport
{
public:
typedef Protocol protocol;
using protocol = Protocol;
/** \brief Construct stream transport.
*
@@ -244,16 +245,17 @@ 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 (m_receiveBufferSize - offset > 0) {
while (offset < bufferView.size()) {
Block element;
std::tie(isOk, element) = Block::fromBuffer(m_receiveBuffer + offset, m_receiveBufferSize - offset);
std::tie(isOk, element) = Block::fromBuffer(bufferView.subspan(offset));
if (!isOk)
break;
offset += element.size();
BOOST_ASSERT(offset <= m_receiveBufferSize);
BOOST_ASSERT(offset <= bufferView.size());
this->receive(element);
}
@@ -332,7 +334,6 @@ StreamTransport<T>::getSendQueueBytes() const
return m_sendQueueBytes;
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_STREAM_TRANSPORT_HPP
+19 -13
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -29,8 +29,9 @@
#include "tcp-transport.hpp"
#include "common/global.hpp"
namespace nfd {
namespace face {
#include <boost/asio/ip/v6_only.hpp>
namespace nfd::face {
NFD_LOG_INIT(TcpChannel);
@@ -98,10 +99,19 @@ TcpChannel::connect(const tcp::Endpoint& remoteEndpoint,
void
TcpChannel::createFace(ip::tcp::socket&& socket,
const FaceParams& params,
const FaceCreatedCallback& onFaceCreated)
const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onFaceCreationFailed)
{
shared_ptr<Face> face;
tcp::Endpoint remoteEndpoint = socket.remote_endpoint();
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;
}
auto it = m_channelFaces.find(remoteEndpoint);
if (it == m_channelFaces.end()) {
@@ -123,16 +133,13 @@ TcpChannel::createFace(ip::tcp::socket&& socket,
if (params.defaultCongestionThreshold) {
options.defaultCongestionThreshold = *params.defaultCongestionThreshold;
}
if (params.bandwidth) {
options.C = *params.bandwidth;
}
auto linkService = make_unique<GenericLinkService>(options);
auto faceScope = m_determineFaceScope(socket.local_endpoint().address(),
socket.remote_endpoint().address());
auto transport = make_unique<TcpTransport>(std::move(socket), params.persistency, faceScope);
face = make_shared<Face>(std::move(linkService), std::move(transport));
face->setChannel(shared_from_this()); // use weak_from_this() in C++17
face->setChannel(weak_from_this());
m_channelFaces[remoteEndpoint] = face;
connectFaceClosedSignal(*face, [this, remoteEndpoint] { m_channelFaces.erase(remoteEndpoint); });
@@ -177,7 +184,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);
createFace(std::move(m_socket), params, onFaceCreated, onAcceptFailed);
// prepare accepting the next connection
accept(onFaceCreated, onAcceptFailed);
@@ -204,7 +211,7 @@ TcpChannel::handleConnect(const boost::system::error_code& error,
}
NFD_LOG_CHAN_TRACE("Connected to " << socket->remote_endpoint());
createFace(std::move(*socket), params, onFaceCreated);
createFace(std::move(*socket), params, onFaceCreated, onConnectFailed);
}
void
@@ -222,5 +229,4 @@ TcpChannel::handleConnectTimeout(const tcp::Endpoint& remoteEndpoint,
onConnectFailed(504, "Connection timed out");
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+12 -12
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,13 +28,13 @@
#include "channel.hpp"
namespace nfd {
#include <boost/asio/ip/tcp.hpp>
namespace tcp {
typedef boost::asio::ip::tcp::endpoint Endpoint;
} // namespace tcp
namespace nfd::tcp {
using Endpoint = boost::asio::ip::tcp::endpoint;
} // namespace nfd::tcp
namespace face {
namespace nfd::face {
using DetermineFaceScopeFromAddress = std::function<ndn::nfd::FaceScope(const boost::asio::ip::address& local,
const boost::asio::ip::address& remote)>;
@@ -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 : public Channel
class TcpChannel final : public Channel
{
public:
/**
@@ -59,13 +59,13 @@ public:
DetermineFaceScopeFromAddress determineFaceScope);
bool
isListening() const override
isListening() const final
{
return m_acceptor.is_open();
}
size_t
size() const override
size() const final
{
return m_channelFaces.size();
}
@@ -98,7 +98,8 @@ private:
void
createFace(boost::asio::ip::tcp::socket&& socket,
const FaceParams& params,
const FaceCreatedCallback& onFaceCreated);
const FaceCreatedCallback& onFaceCreated,
const FaceCreationFailedCallback& onFaceCreationFailed);
void
accept(const FaceCreatedCallback& onFaceCreated,
@@ -132,7 +133,6 @@ private:
DetermineFaceScopeFromAddress m_determineFaceScope;
};
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_TCP_CHANNEL_HPP
+8 -7
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -25,8 +25,9 @@
#include "tcp-factory.hpp"
namespace nfd {
namespace face {
#include <boost/lexical_cast.hpp>
namespace nfd::face {
namespace ip = boost::asio::ip;
@@ -200,8 +201,9 @@ TcpFactory::createChannel(const tcp::Endpoint& endpoint)
if (it != m_channels.end())
return it->second;
auto channel = make_shared<TcpChannel>(endpoint, m_wantCongestionMarking,
bind(&TcpFactory::determineFaceScopeFromAddresses, this, _1, _2));
auto channel = make_shared<TcpChannel>(endpoint, m_wantCongestionMarking, [this] (auto&&... args) {
return determineFaceScopeFromAddresses(std::forward<decltype(args)>(args)...);
});
m_channels[endpoint] = channel;
return channel;
}
@@ -222,5 +224,4 @@ TcpFactory::determineFaceScopeFromAddresses(const boost::asio::ip::address& loca
return ndn::nfd::FACE_SCOPE_NON_LOCAL;
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+10 -14
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2018, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -29,12 +29,11 @@
#include "protocol-factory.hpp"
#include "tcp-channel.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
/** \brief Protocol factory for TCP over IPv4 and IPv6
/** \brief Protocol factory for TCP over IPv4 and IPv6.
*/
class TcpFactory : public ProtocolFactory
class TcpFactory final : public ProtocolFactory
{
public:
static const std::string&
@@ -43,7 +42,7 @@ public:
using ProtocolFactory::ProtocolFactory;
/**
* \brief Create TCP-based channel using tcp::Endpoint
* \brief Create TCP-based channel using tcp::Endpoint.
*
* tcp::Endpoint is really an alias for boost::asio::ip::tcp::endpoint.
*
@@ -57,19 +56,17 @@ public:
createChannel(const tcp::Endpoint& localEndpoint);
private:
/** \brief process face_system.tcp config section
*/
void
doProcessConfig(OptionalConfigSection configSection,
FaceSystem::ConfigContext& context) override;
FaceSystem::ConfigContext& context) final;
void
doCreateFace(const CreateFaceRequest& req,
const FaceCreatedCallback& onCreated,
const FaceCreationFailedCallback& onFailure) override;
const FaceCreationFailedCallback& onFailure) final;
std::vector<shared_ptr<const Channel>>
doGetChannels() const override;
doGetChannels() const final;
ndn::nfd::FaceScope
determineFaceScopeFromAddresses(const boost::asio::ip::address& local,
@@ -79,11 +76,10 @@ private:
bool m_wantCongestionMarking = false;
std::map<tcp::Endpoint, shared_ptr<TcpChannel>> m_channels;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
IpAddressPredicate m_local;
};
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_TCP_FACTORY_HPP
+7 -13
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -31,21 +31,16 @@
#include <sys/ioctl.h>
#endif
namespace nfd {
namespace face {
namespace nfd::face {
NFD_LOG_MEMBER_INIT_SPECIALIZED(StreamTransport<boost::asio::ip::tcp>, TcpTransport);
time::milliseconds TcpTransport::s_initialReconnectWait = 1_s;
time::milliseconds TcpTransport::s_maxReconnectWait = 5_min;
float TcpTransport::s_reconnectWaitMultiplier = 2.0f;
TcpTransport::TcpTransport(protocol::socket&& socket,
ndn::nfd::FacePersistency persistency,
ndn::nfd::FaceScope faceScope)
: StreamTransport(std::move(socket))
, m_remoteEndpoint(m_socket.remote_endpoint())
, m_nextReconnectWait(s_initialReconnectWait)
, m_nextReconnectWait(INITIAL_RECONNECT_DELAY)
{
this->setLocalUri(FaceUri(m_socket.local_endpoint()));
this->setRemoteUri(FaceUri(m_socket.remote_endpoint()));
@@ -165,7 +160,7 @@ TcpTransport::handleReconnect(const boost::system::error_code& error)
}
m_reconnectEvent.cancel();
m_nextReconnectWait = s_initialReconnectWait;
m_nextReconnectWait = INITIAL_RECONNECT_DELAY;
this->setLocalUri(FaceUri(m_socket.local_endpoint()));
NFD_LOG_FACE_TRACE("TCP connection reestablished");
@@ -182,8 +177,8 @@ TcpTransport::handleReconnectTimeout()
// exponentially back off the reconnection timer
m_nextReconnectWait =
std::min(time::duration_cast<time::milliseconds>(m_nextReconnectWait * s_reconnectWaitMultiplier),
s_maxReconnectWait);
std::min(time::duration_cast<time::milliseconds>(m_nextReconnectWait * RECONNECT_DELAY_MULTIPLIER),
MAX_RECONNECT_DELAY);
// do this asynchronously because there could be some callbacks still pending
getGlobalIoService().post([this] { reconnect(); });
@@ -196,5 +191,4 @@ TcpTransport::doClose()
StreamTransport::doClose();
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+20 -17
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2019, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -28,8 +28,9 @@
#include "stream-transport.hpp"
namespace nfd {
namespace face {
#include <boost/asio/ip/tcp.hpp>
namespace nfd::face {
NFD_LOG_MEMBER_DECL_SPECIALIZED(StreamTransport<boost::asio::ip::tcp>);
@@ -40,7 +41,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 FINAL_UNLESS_WITH_TESTS : public StreamTransport<boost::asio::ip::tcp>
class TcpTransport NFD_FINAL_UNLESS_WITH_TESTS : public StreamTransport<boost::asio::ip::tcp>
{
public:
TcpTransport(protocol::socket&& socket, ndn::nfd::FacePersistency persistency, ndn::nfd::FaceScope faceScope);
@@ -61,28 +62,31 @@ protected:
void
handleError(const boost::system::error_code& error) final;
PROTECTED_WITH_TESTS_ELSE_PRIVATE:
VIRTUAL_WITH_TESTS void
NFD_PROTECTED_WITH_TESTS_ELSE_PRIVATE:
NFD_VIRTUAL_WITH_TESTS void
reconnect();
VIRTUAL_WITH_TESTS void
NFD_VIRTUAL_WITH_TESTS void
handleReconnect(const boost::system::error_code& error);
VIRTUAL_WITH_TESTS void
NFD_VIRTUAL_WITH_TESTS void
handleReconnectTimeout();
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/** \brief how long to wait before the first reconnection attempt after the TCP connection has been severed
NFD_PUBLIC_WITH_TESTS_ELSE_PRIVATE:
/**
* \brief Delay before the first reconnection attempt after the TCP connection has been severed
*/
static time::milliseconds s_initialReconnectWait;
static constexpr time::milliseconds INITIAL_RECONNECT_DELAY = 1_s;
/** \brief maximum amount of time to wait before a reconnection attempt
/**
* \brief Maximum amount of time to wait before a reconnection attempt
*/
static time::milliseconds s_maxReconnectWait;
static constexpr time::milliseconds MAX_RECONNECT_DELAY = 5_min;
/** \brief multiplier for the exponential backoff of the reconnection timer
/**
* \brief Multiplier for the exponential backoff of the reconnection timer
*/
static float s_reconnectWaitMultiplier;
static constexpr float RECONNECT_DELAY_MULTIPLIER = 2.0f;
private:
typename protocol::endpoint m_remoteEndpoint;
@@ -96,7 +100,6 @@ private:
time::milliseconds m_nextReconnectWait;
};
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_TCP_TRANSPORT_HPP
+6 -19
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -26,8 +26,7 @@
#include "transport.hpp"
#include "face.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
NFD_LOG_INIT(Transport);
@@ -50,23 +49,12 @@ operator<<(std::ostream& os, TransportState state)
}
}
Transport::Transport()
: m_face(nullptr)
, m_service(nullptr)
, m_scope(ndn::nfd::FACE_SCOPE_NONE)
, m_persistency(ndn::nfd::FACE_PERSISTENCY_NONE)
, m_linkType(ndn::nfd::LINK_TYPE_NONE)
, m_mtu(MTU_INVALID)
, m_sendQueueCapacity(QUEUE_UNSUPPORTED)
, m_state(TransportState::UP)
, m_expirationTime(time::steady_clock::TimePoint::max())
{
}
Transport::Transport() = default;
Transport::~Transport() = default;
void
Transport::setFaceAndLinkService(Face& face, LinkService& service)
Transport::setFaceAndLinkService(Face& face, LinkService& service) noexcept
{
BOOST_ASSERT(m_face == nullptr);
BOOST_ASSERT(m_service == nullptr);
@@ -123,7 +111,7 @@ Transport::receive(const Block& packet, const EndpointId& endpoint)
}
void
Transport::setMtu(ssize_t mtu)
Transport::setMtu(ssize_t mtu) noexcept
{
BOOST_ASSERT(mtu == MTU_UNLIMITED || mtu >= 0);
@@ -235,5 +223,4 @@ operator<<(std::ostream& os, const FaceLogHelper<Transport>& flh)
return os;
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
+177 -212
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -29,10 +29,10 @@
#include "face-common.hpp"
#include "common/counter.hpp"
namespace nfd {
namespace face {
namespace nfd::face {
/** \brief Indicates the state of a transport.
/**
* \brief Indicates the state of a transport.
*/
enum class TransportState {
NONE,
@@ -53,7 +53,7 @@ operator<<(std::ostream& os, TransportState state);
class TransportCounters
{
public:
/** \brief count of incoming packets
/** \brief Count of incoming packets.
*
* A 'packet' typically means a top-level TLV block.
* For a datagram-based transport, an incoming packet that cannot be parsed as TLV
@@ -61,14 +61,14 @@ public:
*/
PacketCounter nInPackets;
/** \brief count of outgoing packets
/** \brief Count of outgoing packets.
*
* A 'packet' typically means a top-level TLV block.
* This counter is incremented only if transport is UP.
*/
PacketCounter nOutPackets;
/** \brief total incoming bytes
/** \brief Total incoming bytes.
*
* This counter includes headers imposed by NFD (such as NDNLP),
* but excludes overhead of underlying protocol (such as IP header).
@@ -77,7 +77,7 @@ public:
*/
ByteCounter nInBytes;
/** \brief total outgoing bytes
/** \brief Total outgoing bytes.
*
* This counter includes headers imposed by NFD (such as NDNLP),
* but excludes overhead of underlying protocol (such as IP header).
@@ -86,24 +86,29 @@ public:
ByteCounter nOutBytes;
};
/** \brief indicates the transport has no limit on payload size
/**
* \brief Indicates that the transport has no limit on payload size.
*/
const ssize_t MTU_UNLIMITED = -1;
inline constexpr ssize_t MTU_UNLIMITED = -1;
/** \brief (for internal use) indicates MTU field is unset
/**
* \brief (for internal use) Indicates that the MTU field is unset.
*/
const ssize_t MTU_INVALID = -2;
inline constexpr ssize_t MTU_INVALID = -2;
/** \brief indicates that the transport does not support reading the queue capacity/length
/**
* \brief Indicates that the transport does not support reading the queue capacity/length.
*/
const ssize_t QUEUE_UNSUPPORTED = -1;
inline constexpr ssize_t QUEUE_UNSUPPORTED = -1;
/** \brief indicates that the transport was unable to retrieve the queue capacity/length
/**
* \brief Indicates that the transport was unable to retrieve the queue capacity/length.
*/
const ssize_t QUEUE_ERROR = -2;
inline constexpr ssize_t QUEUE_ERROR = -2;
/** \brief The lower half of a Face.
* \sa Face
/**
* \brief The lower half of a Face.
* \sa Face, LinkService
*/
class Transport : protected virtual TransportCounters, noncopyable
{
@@ -127,32 +132,48 @@ public:
~Transport();
public:
/** \brief set Face and LinkService for Transport
* \pre setFaceAndLinkService has not been called
/**
* \brief Set Face and LinkService for this transport.
* \pre setFaceAndLinkService() has not been called.
*/
void
setFaceAndLinkService(Face& face, LinkService& service);
setFaceAndLinkService(Face& face, LinkService& service) noexcept;
/** \return Face to which this Transport is attached
/**
* \brief Returns the Face to which this transport is attached.
*/
const Face*
getFace() const;
getFace() const noexcept
{
return m_face;
}
/** \return LinkService to which this Transport is attached
/**
* \brief Returns the LinkService to which this transport is attached.
*/
const LinkService*
getLinkService() const;
getLinkService() const noexcept
{
return m_service;
}
/** \return LinkService to which this Transport is attached
/**
* \brief Returns the LinkService to which this transport is attached.
*/
LinkService*
getLinkService();
getLinkService() noexcept
{
return m_service;
}
virtual const Counters&
getCounters() const;
getCounters() const
{
return *this;
}
public: // upper interface
/** \brief Request the transport to be closed
/** \brief Request the transport to be closed.
*
* This operation is effective only if transport is in UP or DOWN state,
* otherwise it has no effect.
@@ -163,7 +184,7 @@ public: // upper interface
void
close();
/** \brief Send a link-layer packet
/** \brief Send a link-layer packet.
* \param packet the packet to be sent, must be a valid and well-formed TLV block
* \note This operation has no effect if getState() is neither UP nor DOWN
* \warning Behavior is undefined if packet size exceeds the MTU limit
@@ -172,85 +193,125 @@ public: // upper interface
send(const Block& packet);
public: // static properties
/** \return a FaceUri representing local endpoint
/**
* \brief Returns a FaceUri representing the local endpoint.
*/
FaceUri
getLocalUri() const;
getLocalUri() const noexcept
{
return m_localUri;
}
/** \return a FaceUri representing remote endpoint
/**
* \brief Returns a FaceUri representing the remote endpoint.
*/
FaceUri
getRemoteUri() const;
getRemoteUri() const noexcept
{
return m_remoteUri;
}
/** \return whether face is local or non-local for scope control purpose
/**
* \brief Returns whether the transport is local or non-local for scope control purposes.
*/
ndn::nfd::FaceScope
getScope() const;
getScope() const noexcept
{
return m_scope;
}
/** \return face persistency setting
/**
* \brief Returns the current persistency setting of the transport.
*/
ndn::nfd::FacePersistency
getPersistency() const;
getPersistency() const noexcept
{
return m_persistency;
}
/** \brief check whether the face persistency can be changed to \p newPersistency
/**
* \brief Check whether the persistency can be changed to \p newPersistency.
*
* This function serves as the external API, and invokes the protected function
* canChangePersistencyToImpl to perform further checks if \p newPersistency differs
* from the current persistency.
* This function serves as the external API, and invokes the protected function
* canChangePersistencyToImpl() to perform further checks if \p newPersistency differs
* from the current persistency.
*
* \return true if the change can be performed, false otherwise
* \return true if the change can be performed, false otherwise
*/
bool
canChangePersistencyTo(ndn::nfd::FacePersistency newPersistency) const;
/** \brief changes face persistency setting
/**
* \brief Changes the persistency setting of the transport.
*/
void
setPersistency(ndn::nfd::FacePersistency newPersistency);
/** \return the link type of the transport
/**
* \brief Returns the link type of the transport.
*/
ndn::nfd::LinkType
getLinkType() const;
getLinkType() const noexcept
{
return m_linkType;
}
/** \return maximum payload size
* \retval MTU_UNLIMITED transport has no limit on payload size
/**
* \brief Returns the maximum payload size.
* \retval MTU_UNLIMITED The transport has no limit on payload size.
*
* This size is the maximum packet size that can be sent or received through this transport.
* This size is the maximum packet size that can be sent or received through this transport.
*
* For a datagram-based transport, this is typically the Maximum Transmission Unit (MTU),
* after the overhead of headers introduced by the transport has been accounted for.
* For a stream-based transport, this is typically unlimited (MTU_UNLIMITED).
* For a datagram-based transport, this is typically the Maximum Transmission Unit (MTU),
* after the overhead of headers introduced by the transport has been accounted for.
* For a stream-based transport, this is typically unlimited (MTU_UNLIMITED).
*/
ssize_t
getMtu() const;
getMtu() const noexcept
{
return m_mtu;
}
/** \return capacity of the send queue (in bytes)
* \retval QUEUE_UNSUPPORTED transport does not support queue capacity retrieval
* \retval QUEUE_ERROR transport was unable to retrieve the queue capacity
/**
* \brief Returns the capacity of the send queue (in bytes).
* \retval QUEUE_UNSUPPORTED The transport does not support queue capacity retrieval.
* \retval QUEUE_ERROR The transport was unable to retrieve the queue capacity.
*/
ssize_t
getSendQueueCapacity() const;
getSendQueueCapacity() const noexcept
{
return m_sendQueueCapacity;
}
public: // dynamic properties
/** \return transport state
/**
* \brief Returns the current transport state.
*/
TransportState
getState() const;
getState() const noexcept
{
return m_state;
}
/** \brief signals when transport state changes
/**
* \brief Signals when the transport state changes.
*/
signal::Signal<Transport, TransportState/*old*/, TransportState/*new*/> afterStateChange;
/** \return expiration time of the transport
* \retval time::steady_clock::TimePoint::max() the transport has indefinite lifetime
/**
* \brief Returns the expiration time of the transport.
* \retval time::steady_clock::time_point::max() The transport has an indefinite lifetime.
*/
time::steady_clock::TimePoint
getExpirationTime() const;
time::steady_clock::time_point
getExpirationTime() const noexcept
{
return m_expirationTime;
}
/** \return current send queue length of the transport (in octets)
* \retval QUEUE_UNSUPPORTED transport does not support queue length retrieval
* \retval QUEUE_ERROR transport was unable to retrieve the queue length
/**
* \brief Returns the current send queue length of the transport (in octets).
* \retval QUEUE_UNSUPPORTED The transport does not support queue length retrieval.
* \retval QUEUE_ERROR The transport was unable to retrieve the queue length.
*/
virtual ssize_t
getSendQueueLength()
@@ -259,34 +320,50 @@ public: // dynamic properties
}
protected: // upper interface to be invoked by subclass
/** \brief Pass a received link-layer packet to the upper layer for further processing
* \param packet the received packet, must be a valid and well-formed TLV block
* \param endpoint the source endpoint
* \warning Behavior is undefined if packet size exceeds the MTU limit
/**
* \brief Pass a received link-layer packet to the upper layer for further processing.
* \param packet The received packet, must be a valid and well-formed TLV block
* \param endpoint The source endpoint, optional for unicast transports
* \warning Behavior is undefined if packet size exceeds the MTU limit.
*/
void
receive(const Block& packet, const EndpointId& endpoint = 0);
receive(const Block& packet, const EndpointId& endpoint = {});
protected: // properties to be set by subclass
void
setLocalUri(const FaceUri& uri);
setLocalUri(const FaceUri& uri) noexcept
{
m_localUri = uri;
}
void
setRemoteUri(const FaceUri& uri);
setRemoteUri(const FaceUri& uri) noexcept
{
m_remoteUri = uri;
}
void
setScope(ndn::nfd::FaceScope scope);
setScope(ndn::nfd::FaceScope scope) noexcept
{
m_scope = scope;
}
void
setLinkType(ndn::nfd::LinkType linkType);
setLinkType(ndn::nfd::LinkType linkType) noexcept
{
m_linkType = linkType;
}
void
setMtu(ssize_t mtu);
setMtu(ssize_t mtu) noexcept;
void
setSendQueueCapacity(ssize_t sendQueueCapacity);
setSendQueueCapacity(ssize_t sendQueueCapacity) noexcept
{
m_sendQueueCapacity = sendQueueCapacity;
}
/** \brief set transport state
/** \brief Set transport state.
*
* Only the following transitions are valid:
* UP->DOWN, DOWN->UP, UP/DOWN->CLOSING/FAILED, CLOSING/FAILED->CLOSED
@@ -297,10 +374,13 @@ protected: // properties to be set by subclass
setState(TransportState newState);
void
setExpirationTime(const time::steady_clock::TimePoint& expirationTime);
setExpirationTime(const time::steady_clock::time_point& expirationTime) noexcept
{
m_expirationTime = expirationTime;
}
protected: // to be overridden by subclass
/** \brief invoked by canChangePersistencyTo to perform the check
/** \brief Invoked by canChangePersistencyTo to perform the check.
*
* Base class implementation returns false.
*
@@ -309,7 +389,7 @@ protected: // to be overridden by subclass
virtual bool
canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const;
/** \brief invoked after the persistency has been changed
/** \brief Invoked after the persistency has been changed.
*
* The base class implementation does nothing.
* When overridden in a subclass, the function should update internal states
@@ -318,9 +398,9 @@ protected: // to be overridden by subclass
virtual void
afterChangePersistency(ndn::nfd::FacePersistency oldPersistency);
/** \brief performs Transport specific operations to close the transport
/** \brief Performs Transport specific operations to close the transport.
*
* This is invoked once by \p close() after changing state to CLOSING.
* This is invoked once by close() after changing state to CLOSING.
* It will not be invoked by Transport class if the transport is already CLOSING or CLOSED.
*
* When the cleanup procedure is complete, this method should change state to CLOSED.
@@ -330,7 +410,7 @@ protected: // to be overridden by subclass
doClose() = 0;
private: // to be overridden by subclass
/** \brief performs Transport specific operations to send a packet
/** \brief Performs Transport specific operations to send a packet.
* \param packet the packet to be sent, can be assumed to be valid and well-formed
* \pre transport state is either UP or DOWN
*/
@@ -338,145 +418,30 @@ private: // to be overridden by subclass
doSend(const Block& packet) = 0;
private:
Face* m_face;
LinkService* m_service;
Face* m_face = nullptr;
LinkService* m_service = nullptr;
FaceUri m_localUri;
FaceUri m_remoteUri;
ndn::nfd::FaceScope m_scope;
ndn::nfd::FacePersistency m_persistency;
ndn::nfd::LinkType m_linkType;
ssize_t m_mtu;
ssize_t m_sendQueueCapacity;
TransportState m_state;
time::steady_clock::TimePoint m_expirationTime;
ndn::nfd::FaceScope m_scope = ndn::nfd::FACE_SCOPE_NONE;
ndn::nfd::FacePersistency m_persistency = ndn::nfd::FACE_PERSISTENCY_NONE;
ndn::nfd::LinkType m_linkType = ndn::nfd::LINK_TYPE_NONE;
ssize_t m_mtu = MTU_INVALID;
ssize_t m_sendQueueCapacity = QUEUE_UNSUPPORTED;
TransportState m_state = TransportState::UP;
time::steady_clock::time_point m_expirationTime = time::steady_clock::time_point::max();
};
inline const Face*
Transport::getFace() const
{
return m_face;
}
inline const LinkService*
Transport::getLinkService() const
{
return m_service;
}
inline LinkService*
Transport::getLinkService()
{
return m_service;
}
inline const Transport::Counters&
Transport::getCounters() const
{
return *this;
}
inline FaceUri
Transport::getLocalUri() const
{
return m_localUri;
}
inline void
Transport::setLocalUri(const FaceUri& uri)
{
m_localUri = uri;
}
inline FaceUri
Transport::getRemoteUri() const
{
return m_remoteUri;
}
inline void
Transport::setRemoteUri(const FaceUri& uri)
{
m_remoteUri = uri;
}
inline ndn::nfd::FaceScope
Transport::getScope() const
{
return m_scope;
}
inline void
Transport::setScope(ndn::nfd::FaceScope scope)
{
m_scope = scope;
}
inline ndn::nfd::FacePersistency
Transport::getPersistency() const
{
return m_persistency;
}
inline ndn::nfd::LinkType
Transport::getLinkType() const
{
return m_linkType;
}
inline void
Transport::setLinkType(ndn::nfd::LinkType linkType)
{
m_linkType = linkType;
}
inline ssize_t
Transport::getMtu() const
{
return m_mtu;
}
inline ssize_t
Transport::getSendQueueCapacity() const
{
return m_sendQueueCapacity;
}
inline void
Transport::setSendQueueCapacity(ssize_t sendQueueCapacity)
{
m_sendQueueCapacity = sendQueueCapacity;
}
inline TransportState
Transport::getState() const
{
return m_state;
}
inline time::steady_clock::TimePoint
Transport::getExpirationTime() const
{
return m_expirationTime;
}
inline void
Transport::setExpirationTime(const time::steady_clock::TimePoint& expirationTime)
{
m_expirationTime = expirationTime;
}
std::ostream&
operator<<(std::ostream& os, const FaceLogHelper<Transport>& flh);
template<typename T>
typename std::enable_if<std::is_base_of<Transport, T>::value &&
!std::is_same<Transport, T>::value, std::ostream&>::type
std::enable_if_t<std::is_base_of_v<Transport, T> && !std::is_same_v<Transport, T>,
std::ostream&>
operator<<(std::ostream& os, const FaceLogHelper<T>& flh)
{
return os << FaceLogHelper<Transport>(flh.obj);
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
#endif // NFD_DAEMON_FACE_TRANSPORT_HPP
+12 -15
View File
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2020, Regents of the University of California,
* Copyright (c) 2014-2022, Regents of the University of California,
* Arizona Board of Regents,
* Colorado State University,
* University Pierre & Marie Curie, Sorbonne University,
@@ -29,8 +29,9 @@
#include "unicast-udp-transport.hpp"
#include "common/global.hpp"
namespace nfd {
namespace face {
#include <boost/asio/ip/v6_only.hpp>
namespace nfd::face {
NFD_LOG_INIT(UdpChannel);
@@ -38,13 +39,15 @@ namespace ip = boost::asio::ip;
UdpChannel::UdpChannel(const udp::Endpoint& localEndpoint,
time::nanoseconds idleTimeout,
bool wantCongestionMarking)
bool wantCongestionMarking,
size_t defaultMtu)
: m_localEndpoint(localEndpoint)
, m_socket(getGlobalIoService())
, m_idleFaceTimeout(idleTimeout)
, m_wantCongestionMarking(wantCongestionMarking)
{
setUri(FaceUri(m_localEndpoint));
setDefaultMtu(defaultMtu);
NFD_LOG_CHAN_INFO("Creating channel");
}
@@ -122,6 +125,7 @@ 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) {
@@ -138,7 +142,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(m_receiveBuffer.data(), nBytesReceived, error);
transport->receiveDatagram(ndn::make_span(m_receiveBuffer).first(nBytesReceived), error);
waitForNewPeer(onFaceCreated, onReceiveFailed);
}
@@ -180,19 +184,13 @@ UdpChannel::createFace(const udp::Endpoint& remoteEndpoint,
options.defaultCongestionThreshold = *params.defaultCongestionThreshold;
}
if (params.mtu) {
options.overrideMtu = *params.mtu;
}
if (params.bandwidth) {
options.C = *params.bandwidth;
}
options.overrideMtu = params.mtu.value_or(getDefaultMtu());
auto linkService = make_unique<GenericLinkService>(options);
auto transport = make_unique<UnicastUdpTransport>(std::move(socket), params.persistency,
m_idleFaceTimeout);
auto face = make_shared<Face>(std::move(linkService), std::move(transport));
face->setChannel(shared_from_this()); // use weak_from_this() in C++17
face->setChannel(weak_from_this());
m_channelFaces[remoteEndpoint] = face;
connectFaceClosedSignal(*face, [this, remoteEndpoint] { m_channelFaces.erase(remoteEndpoint); });
@@ -200,5 +198,4 @@ UdpChannel::createFace(const udp::Endpoint& remoteEndpoint,
return {true, face};
}
} // namespace face
} // namespace nfd
} // namespace nfd::face
Loaded 100 of 524 files, more files were not shown because too many files have changed in this diff. Show more