Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fabrid: Design Document Update #1

Open
wants to merge 37 commits into
base: scionlab
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
74ee1a2
deps: bump google.golang.org/grpc, set MaxConcurrentStreams (#4424)
matzf Oct 30, 2023
adc4303
router: extend packet processing metrics (#4422)
jiceatscion Oct 30, 2023
8716518
build: update Go to 1.21.3 (#4428)
oncilla Oct 30, 2023
bd675dd
build: drop @cgrindel_bazel_starlib//updatesrc (#4427)
oncilla Oct 31, 2023
f571c58
deps: update bazel & bazel libs (#4426)
lukedirtwalker Oct 31, 2023
98573cf
build: update quic-go to v0.40.0 (#4431)
oncilla Nov 1, 2023
d711165
router: fix interface label of router metrics (#4430)
jiceatscion Nov 2, 2023
0f78c34
deps: update oapi-codegen to v2 (#4432)
matzf Nov 3, 2023
a12943a
tools: specify project name in docker-compose files (#4396)
matzf Nov 3, 2023
b13a0b6
build: make git-version not fail if no tags exist (#4438)
jiceatscion Nov 13, 2023
93acc86
testing: add router benchmark program and use it as integration test …
jiceatscion Nov 17, 2023
a16bdf7
daemon: fix docstring for latencies in protobuf file (#4443)
mlegner Nov 22, 2023
e4df23d
scion.sh: block for child processes at shutdown (#4445)
matzf Nov 23, 2023
7d95e80
processmetrics: explicit type conversion to support arm64 (#4446)
mlegner Nov 24, 2023
ddef5aa
bazel: update bazelisk and support arm64 (#4447)
mlegner Nov 27, 2023
37ef752
build: allow building without scion-ci (#4449)
mlegner Nov 27, 2023
b14695f
prometheus: fix copying of metrics labels (#4450)
sustrik Nov 30, 2023
9717dbb
daemon: error out when using drkey endpoints without configured drkey…
rohrerj Dec 7, 2023
027fe01
pkg/log: fix panic when using custom Logger (#4452)
lukedirtwalker Dec 7, 2023
bf8b6ec
testing: an improved router benchmark that only runs one router (#4444)
jiceatscion Dec 7, 2023
1a9ca59
router: deleting the old router_benchmark integration test. (#4454)
jiceatscion Dec 7, 2023
bb483d9
testing: rename "router_newbenchmark" to "router_benchmark" (#4455)
jiceatscion Dec 7, 2023
3e1c623
router: make the benchmark and the router more adaptive to core count…
jiceatscion Dec 12, 2023
8ed74fa
testing: improved stream synthesis and cores use in router benchmark …
jiceatscion Dec 20, 2023
30ed911
dist: build debian packages for multiple platforms (#4448)
matzf Dec 21, 2023
1579977
tools: fix wireshark dissector TLV options without data (#4458)
marcodermatt Dec 21, 2023
9d8159c
doc: update buildkite instance type (#4459)
matzf Dec 21, 2023
d741f8a
control: pluggable segment signer (#4460)
oncilla Dec 29, 2023
fdb98af
doc: update the port table to reflect current state (#4462)
jiceatscion Jan 11, 2024
50f0d4d
gateway: etags added to prefix discovery protobuf (#4461)
sustrik Jan 17, 2024
2cd7cc2
Add Carbon Intensity information to beacons and paths (#129)
matzf Nov 18, 2022
72ebb15
FABRID design document
rohrerj May 6, 2024
adeada4
Spelling, grammar, whitespace changes
marcodermatt Jun 3, 2024
e291e00
Add hbh reference, reorder formulas
marcodermatt Jun 5, 2024
a3ab85a
Update rationale for policy index length
marcodermatt Jun 5, 2024
168f2c7
CS and BR TOML configuration update
marcodermatt Jun 12, 2024
9d2942a
Fix fabridquery concatenation
marcodermatt Jun 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .bazelignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
bin
doc/_build
docker/_build
rules_openapi/tools/node_modules
private/mgmtapi/tools/node_modules
tools/lint/logctxcheck/testdata/src
2 changes: 1 addition & 1 deletion .bazelversion
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5.4.0
6.4.0
1 change: 1 addition & 0 deletions .buildkite/hooks/bazel-remote.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
version: "2.4"
name: bazel_remote
services:
bazel-remote:
container_name: bazel-remote-cache
1 change: 1 addition & 0 deletions .buildkite/hooks/go-module-proxy.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
version: "2.4"
name: athens
services:
go-module-proxy:
container_name: go-module-proxy
11 changes: 6 additions & 5 deletions .buildkite/hooks/pre-command
Original file line number Diff line number Diff line change
@@ -30,9 +30,10 @@ rm -f $HOME/.bazelrc
# --nostamp is required for better caching (only on non-release jobs).
if [ "$BUILDKITE_PIPELINE_SLUG" == "scion" ]; then
echo "build --nostamp" > $HOME/.bazelrc
# Also set a fixed GIT_VERSION so that the workspace_status_command always
# returns the same value on CI to improve cache reuse.
export GIT_VERSION="ci-fixed"
# Shorten the git version to omit commit information, improving cache reuse.
# The format of git-version is "<tag>-<number-of-commits-since-the-tag>-<commit-short-hash>"
# This will be shortened to "<tag>-modified-ci"
export GIT_VERSION=$(tools/git-version | sed 's/-.*/-modified-ci/')
else
echo "build --stamp" > $HOME/.bazelrc
fi
@@ -43,7 +44,7 @@ echo "~~~ Starting bazel remote cache proxy"
# Start bazel remote cache proxy for S3
# Note that S3 keys are injected by buildkite, see
# https://buildkite.com/docs/pipelines/secrets#storing-secrets-with-the-elastic-ci-stack-for-aws
docker compose --compatibility -f .buildkite/hooks/bazel-remote.yml -p bazel_remote up -d
docker compose -f .buildkite/hooks/bazel-remote.yml up -d

echo "~~~ Starting go module proxy"
docker compose --compatibility -f .buildkite/hooks/go-module-proxy.yml -p athens up -d
docker compose -f .buildkite/hooks/go-module-proxy.yml up -d
27 changes: 25 additions & 2 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ steps:
plugins:
- scionproto/metahook#v0.3.0:
post-artifact: |
cat << EOF | buildkite-agent annotate --style "info"
cat << EOF | buildkite-agent annotate --style "info" --context "binaries"
#### Build outputs
- <a href="artifact://bazel-bin/scion.tar">SCION binaries</a>
- <a href="artifact://bazel-bin/scion-ci.tar">SCION test tools and utilities</a>
@@ -23,6 +23,28 @@ steps:
- exit_status: 255 # Forced agent shutdown
timeout_in_minutes: 10
- wait
- label: "Package :debian:"
command:
- make dist-deb
- cd deb;
- tar -chaf scion-deb-amd64.tar.gz *_amd64.deb
- tar -chaf scion-deb-arm64.tar.gz *_arm64.deb
- tar -chaf scion-deb-i386.tar.gz *_i386.deb
- tar -chaf scion-deb-armel.tar.gz *_armel.deb
artifact_paths:
- "deb/*.tar.gz"
plugins:
- scionproto/metahook#v0.3.0:
post-artifact: |
cat << EOF | buildkite-agent annotate --style "info" --context "packages"
#### Packages :debian:
- <a href="artifact://deb/scion-deb-amd64.tar.gz">amd64</a>
- <a href="artifact://deb/scion-deb-arm64.tar.gz">arm64</a>
- <a href="artifact://deb/scion-deb-i386.tar.gz">i386</a>
- <a href="artifact://deb/scion-deb-armel.tar.gz">armel</a>
EOF
key: dist-deb
retry: *automatic-retry
- label: "Unit Tests :bazel:"
command:
- bazel test --config=race --config=unit_all
@@ -70,6 +92,7 @@ steps:
timeout_in_minutes: 20
key: check_generated
retry: *automatic-retry
- wait
- group: "End to End"
key: e2e
steps:
@@ -118,7 +141,7 @@ steps:
- label: "E2E: default :docker: (ping)"
command:
- echo "--- build"
- make build docker-images
- make build-dev docker-images
- echo "--- start topology"
- ./scion.sh topology -d
- ./scion.sh run
4 changes: 4 additions & 0 deletions .buildkite/pipeline_lib.sh
Original file line number Diff line number Diff line change
@@ -53,8 +53,12 @@ gen_bazel_test_steps() {
echo " - \"bazel-testlogs.tar.gz\""
echo " timeout_in_minutes: 20"
echo " retry:"
echo " manual:"
echo " permit_on_passed: true"
echo " automatic:"
echo " - exit_status: -1 # Agent was lost"
echo " - exit_status: 255 # Forced agent shutdown"
echo " - exit_status: 3 # Test may be flaky or it just didn't pass"
echo " limit: 2"
done
}
2 changes: 1 addition & 1 deletion .buildkite/provision-agent.sh
Original file line number Diff line number Diff line change
@@ -13,4 +13,4 @@ echo "~~~ Install build tools"
tools/install_bazel
tools/install_deps

sha1sum tools/install_bazel tools/install_deps tools/env/pip3/deps tools/env/pip3/requirements.txt tools/env/rhel/deps > /tmp/buildkite-scionproto-runner-provision.sum
sha1sum tools/install_bazel tools/install_deps tools/env/pip3/deps tools/env/pip3/requirements.txt tools/env/rhel/deps tools/env/rhel/pkgs.txt tools/env/debian/deps tools/env/debian/pkgs.txt > /tmp/buildkite-scionproto-runner-provision.sum
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -66,6 +66,10 @@ doc/venv/
/bin/*
!/bin/.keepme

# Generated package files
##########################
/deb/

# CTags
##########################
tags
@@ -91,6 +95,11 @@ _build
node_modules

# gobra
#######
*.vpr
tmp/
logger.log

# emacs backup files
####################
*~
21 changes: 14 additions & 7 deletions BUILD.bazel
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ load("//tools/lint:write_source_files.bzl", "write_source_files")
load("//tools/lint/python:flake8_config.bzl", "flake8_lint_config")
load("//:nogo.bzl", "nogo_deps")
load("@com_github_bazelbuild_buildtools//buildifier:def.bzl", "buildifier")
load("@cgrindel_bazel_starlib//updatesrc:defs.bzl", "updatesrc_update_all")
load("@npm//private/mgmtapi/tools:@stoplight/spectral-cli/package_json.bzl", spectral_bin = "bin")

# gazelle:prefix github.com/scionproto/scion
# gazelle:map_kind go_library go_library //tools/lint:go.bzl
@@ -198,6 +198,7 @@ pkg_tar(
"//tools/buildkite/cmd/buildkite_artifacts",
"//tools/end2end",
"//tools/end2end_integration",
"//tools/end2endblast",
"//tools/pktgen/cmd/pktgen",
"//tools/scion_integration",
"//tools/udpproxy",
@@ -233,19 +234,25 @@ buildifier(
mode = "check",
)

# Runs all update_src targets in this Workspace. Currently, generating the
# OpenAPI specs is the last target that depends on update_src. Eventually,
# this should be transitioned to write_all_source_files below.
updatesrc_update_all(
name = "update_all",
spectral_bin.spectral_binary(
name = "spectral",
)

# Runs all write_source_files targets in this Workspace. To update the list run
# bazel run @com_github_bazelbuild_buildtools//buildozer -- --root_dir $PWD "add additional_update_targets $( bazel query 'filter("^.*[^\d]$", kind(_write_source_file, //...)) except //:write_all_source_files' | tr '\n' ' ')" //:write_all_source_files
write_source_files(
name = "write_all_source_files",
additional_update_targets = [
"//doc/_build/_static/command:write_files",
"//control/mgmtapi:write_files",
"//daemon/mgmtapi:write_files",
"//dispatcher/mgmtapi:write_files",
"//doc/command:write_files",
"//gateway/mgmtapi:write_files",
"//private/ca/api:write_files",
"//private/mgmtapi/cppki/api:write_files",
"//private/mgmtapi/health/api:write_files",
"//private/mgmtapi/segments/api:write_files",
"//router/mgmtapi:write_files",
"//spec:write_files",
],
)
41 changes: 29 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,14 +1,38 @@
.PHONY: all antlr bazel clean docker-images gazelle go.mod licenses mocks protobuf scion-topo test test-integration write_all_source_files
.PHONY: all build build-dev dist-deb antlr clean docker-images gazelle go.mod licenses mocks protobuf scion-topo test test-integration write_all_source_files

build: bazel
build-dev:
rm -f bin/*
bazel build //:scion //:scion-ci
tar -kxf bazel-bin/scion.tar -C bin
tar -kxf bazel-bin/scion-ci.tar -C bin

build:
rm -f bin/*
bazel build //:scion
tar -kxf bazel-bin/scion.tar -C bin

dist-deb:
bazel build //dist:deb_all
mkdir -p deb; rm -f deb/*;
@ # Bazel cannot include the version in the filename, if we want to set it automatically from the git tag.
@ # Extract the version from the .deb "control" manifest and expand the "__" in the filename to "_<version>_".
@ # See e.g. https://en.wikipedia.org/wiki/Deb_(file_format)#Control_archive
@for f in `bazel cquery //dist:deb_all --output=files 2>/dev/null`; do \
if [ -f "$$f" ]; then \
bf=`basename $$f`; \
v="$$(ar p $$f control.tar.gz | tar -xz --to-stdout ./control | sed -n 's/Version: //p')"; \
bfv=$${bf%%__*}_$${v}_$${bf#*__}; \
cp -v "$$f" deb/$$bfv; \
fi \
done

# all: performs the code-generation steps and then builds; the generated code
# is git controlled, and therefore this is only necessary when changing the
# sources for the code generation.
# Use NOTPARALLEL to force correct order.
# Note: From GNU make 4.4, this still allows building any other targets (e.g. lint) in parallel.
.NOTPARALLEL: all
all: go_deps.bzl protobuf mocks gazelle build antlr write_all_source_files licenses
all: go_deps.bzl protobuf mocks gazelle build-dev antlr write_all_source_files licenses

clean:
bazel clean
@@ -18,12 +42,6 @@ scrub:
bazel clean --expunge
rm -f bin/*

bazel:
rm -f bin/*
bazel build //:scion //:scion-ci
tar -kxf bazel-bin/scion.tar -C bin
tar -kxf bazel-bin/scion-ci.tar -C bin

test:
bazel test --config=unit_all

@@ -70,7 +88,6 @@ antlr:

write_all_source_files:
bazel run //:write_all_source_files
bazel run //:update_all

.PHONY: lint lint-bazel lint-bazel-buildifier lint-doc lint-doc-mdlint lint-go lint-go-bazel lint-go-gazelle lint-go-golangci lint-go-semgrep lint-openapi lint-openapi-spectral lint-protobuf lint-protobuf-buf

@@ -123,11 +140,11 @@ lint-openapi: lint-openapi-spectral

lint-openapi-spectral:
$(info ==> $@)
@tools/quiet bazel run --config=quiet @rules_openapi_npm//@stoplight/spectral-cli/bin:spectral -- lint --ruleset ${PWD}/spec/.spectral.yml ${PWD}/spec/*.gen.yml
@tools/quiet bazel run --config=quiet //:spectral -- lint --ruleset ${PWD}/spec/.spectral.yml ${PWD}/spec/*.gen.yml

lint-doc: lint-doc-mdlint

lint-doc-mdlint:
$(info ==> $@)
@FILES=$$(find -type f -iname '*.md' -not -path "./rules_openapi/tools/node_modules/*" -not -path "./.github/**/*" | grep -vf tools/md/skipped); \
@FILES=$$(find -type f -iname '*.md' -not -path "./private/mgmtapi/tools/node_modules/*" -not -path "./.github/**/*" | grep -vf tools/md/skipped); \
docker run --rm -v ${PWD}:/data -v ${PWD}/tools/md/mdlintstyle.rb:/style.rb $$(docker build -q tools/md) $${FILES} -s /style.rb
52 changes: 34 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,53 @@
# SCION

[![Slack chat](https://img.shields.io/badge/chat%20on-slack-blue?logo=slack)](https://scionproto.slack.com)
[![Matrix chat](https://img.shields.io/badge/chat%20on-matrix-blue?logo=matrix)](https://matrix.to/#/#dev:matrix.scion.org)
[![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/scionproto/awesome-scion)
[![ReadTheDocs](https://img.shields.io/badge/doc-reference-blue?version=latest&style=flat&label=docs&logo=read-the-docs&logoColor=white)](https://docs.scion.org/en/latest)
[![Documentation](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white)](https://pkg.go.dev/github.com/scionproto/scion)
[![Go Docs](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white)](https://pkg.go.dev/github.com/scionproto/scion)
[![Nightly Build](https://badge.buildkite.com/b70b65b38a75eb8724f41a6f1203c9327cfb767f07a0c1934e.svg)](https://buildkite.com/scionproto/scion-nightly/builds/latest)
[![Go Report Card](https://goreportcard.com/badge/github.com/scionproto/scion)](https://goreportcard.com/report/github.com/scionproto/scion)
[![GitHub issues](https://img.shields.io/github/issues/scionproto/scion/help%20wanted.svg?label=help%20wanted&color=purple)](https://github.com/scionproto/scion/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22)
[![GitHub issues](https://img.shields.io/github/issues/scionproto/scion/good%20first%20issue.svg?label=good%20first%20issue&color=purple)](https://github.com/scionproto/scion/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)
[![Release](https://img.shields.io/github/release-pre/scionproto/scion.svg)](https://github.com/scionproto/scion/releases)
[![License](https://img.shields.io/github/license/scionproto/scion.svg?maxAge=2592000)](https://github.com/scionproto/scion/blob/master/LICENSE)

Welcome to the open-source implementation of
[SCION](http://www.scion-architecture.net) (Scalability, Control and Isolation
On next-generation Networks), a future Internet architecture. SCION is the first
clean-slate Internet architecture designed to provide route control, failure
isolation, and explicit trust information for end-to-end communication. To find
out more about the project, please visit our [documentation
site](https://docs.scion.org/en/latest/).
Welcome to the open-source implementation of [SCION](http://www.scion-architecture.net)
(Scalability, Control and Isolation On next-generation Networks), a future Internet architecture.
SCION provides route control, failure isolation, and explicit trust information for end-to-end communication.
To find out more about the project, please visit our [documentation site](https://docs.scion.org/en/latest/).

## Connecting to the SCION Test Network
## Installation

Join [SCIONLab](https://www.scionlab.org) if you're interested in playing with
SCION in an operational global test deployment of SCION. As part of the SCIONLab
project, we support [pre-built binaries as Debian
packages](https://docs.scionlab.org/content/install/).
Installation packages for Debian and derivatives are available for x86-64, arm64, x86-32 and arm.
These packages can be found in the [latest release](https://github.com/scionproto/scion/releases/latest).
Packages for in-development versions can be found from the [latest nightly build](https://buildkite.com/scionproto/scion-nightly/builds/latest).

## Building
Alternatively, "naked" pre-built binaries are available for Linux x86-64 and
can be downloaded from the [latest release](https://github.com/scionproto/scion/releases/latest) or the
[latest nightly build](https://buildkite.com/scionproto/scion-nightly/builds/latest).

To find out how to work with SCION, please visit our [documentation
site](https://docs.scion.org/en/latest/dev/setup.html)
for instructions on how to install build dependencies, build and run SCION.
### Build from sources

Pre-built binaries for x86-64 Linux are available from the [latest nightly build](https://buildkite.com/scionproto/scion-nightly/builds/latest).
SCION can be built with `go build`. To build all binaries used in a SCION deployment (i.e.
excluding the testing and development tools), run

```sh
CGO_ENABLED=0 go build -o bin ./router/... ./control/... ./dispatcher/... ./daemon/... ./scion/... ./scion-pki/... ./gateway/...
```

The default way to build SCION, however, uses Bazel.
In particular, this allows to run all the tests, linters etc.
Please visit our [documentation site](https://docs.scion.org/en/latest/dev/setup.html) for
instructions on how to set up Bazel and the full development environment.

### Connecting to the SCION Network

Join [SCIONLab](https://www.scionlab.org) if you're interested in playing with SCION in an
operational global test deployment of SCION.

The [awesome-scion](https://github.com/scionproto/awesome-scion#deployments) list contains
pointers to production deployments of SCION.

## Contributing

128 changes: 62 additions & 66 deletions WORKSPACE
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
workspace(
name = "com_github_scionproto_scion",
managed_directories = {
"@rules_openapi_npm": ["rules_openapi/tools/node_modules"],
},
)

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file")
@@ -31,57 +28,49 @@ lint_setup({

http_archive(
name = "aspect_bazel_lib",
sha256 = "e3151d87910f69cf1fc88755392d7c878034a69d6499b287bcfc00b1cf9bb415",
strip_prefix = "bazel-lib-1.32.1",
url = "https://github.com/aspect-build/bazel-lib/archive/refs/tags/v1.32.1.tar.gz",
sha256 = "a185ccff9c1b8589c63f66d7eb908de15c5d6bb05562be5f46336c53e7a7326a",
strip_prefix = "bazel-lib-2.0.0-rc1",
url = "https://github.com/aspect-build/bazel-lib/releases/download/v2.0.0-rc1/bazel-lib-v2.0.0-rc1.tar.gz",
)

load("@aspect_bazel_lib//lib:repositories.bzl", "aspect_bazel_lib_dependencies")
load("@aspect_bazel_lib//lib:repositories.bzl", "aspect_bazel_lib_dependencies", "aspect_bazel_lib_register_toolchains")

# Required bazel-lib dependencies

aspect_bazel_lib_dependencies()

# Register bazel-lib toolchains

aspect_bazel_lib_register_toolchains()

# Bazel rules for Golang
http_archive(
name = "io_bazel_rules_go",
sha256 = "278b7ff5a826f3dc10f04feaf0b70d48b68748ccd512d7f98bf442077f043fe3",
sha256 = "91585017debb61982f7054c9688857a2ad1fd823fc3f9cb05048b0025c47d023",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip",
"https://github.com/bazelbuild/rules_go/releases/download/v0.41.0/rules_go-v0.41.0.zip",
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.42.0/rules_go-v0.42.0.zip",
"https://github.com/bazelbuild/rules_go/releases/download/v0.42.0/rules_go-v0.42.0.zip",
],
)

load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")

go_register_toolchains(
nogo = "@//:nogo",
version = "1.21.1",
version = "1.21.3",
)

# Gazelle
http_archive(
name = "bazel_gazelle",
sha256 = "29218f8e0cebe583643cbf93cae6f971be8a2484cdcfa1e45057658df8d54002",
sha256 = "d3fa66a39028e97d76f9e2db8f1b0c11c099e8e01bf363a923074784e451f809",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.32.0/bazel-gazelle-v0.32.0.tar.gz",
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.32.0/bazel-gazelle-v0.32.0.tar.gz",
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.33.0/bazel-gazelle-v0.33.0.tar.gz",
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.33.0/bazel-gazelle-v0.33.0.tar.gz",
],
)

load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")

# Explictly override golang.org/x/sys. Our github.com/quic-go/quic-go cannot
# compile without at least golang.org/x/sys@v0.2.0. The rules_go version that
# we use (v0.34.0) imports an older version. A recent enough version was only introduced
# in v0.36.0. See: https://github.com/bazelbuild/rules_go/commit/64b9226a3bca997866b8831889ffb9de87405a0d
#
# This version should be kept in sync with the go_deps.bzl file. We can remove it
# once we update the rules_go version.
go_repository(
name = "org_golang_x_sys",
importpath = "golang.org/x/sys",
sum = "h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=",
version = "v0.8.0",
)
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")

go_rules_dependencies()

@@ -94,26 +83,20 @@ load("//:go_deps.bzl", "go_deps")

go_deps()

## Explictly override xerrors: https://github.com/bazelbuild/bazel-gazelle/issues/1217
# go_repository(
# name = "org_golang_x_xerrors",
# importpath = "golang.org/x/xerrors",
# sum = "h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=",
# version = "v0.0.0-20220907171357-04be3eba64a2",
# )

gazelle_dependencies()

# XXX Needs to be before rules_docker
# Python rules
http_archive(
name = "rules_python",
sha256 = "8c8fe44ef0a9afc256d1e75ad5f448bb59b81aba149b8958f02f7b3a98f5d9b4",
strip_prefix = "rules_python-0.13.0",
url = "https://github.com/bazelbuild/rules_python/archive/refs/tags/0.13.0.tar.gz",
sha256 = "9d04041ac92a0985e344235f5d946f71ac543f1b1565f2cdbc9a2aaee8adf55b",
strip_prefix = "rules_python-0.26.0",
url = "https://github.com/bazelbuild/rules_python/releases/download/0.26.0/rules_python-0.26.0.tar.gz",
)

load("@rules_python//python:repositories.bzl", "python_register_toolchains")
load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains")

py_repositories()

python_register_toolchains(
name = "python3_10",
@@ -131,10 +114,10 @@ install_python_deps()

http_archive(
name = "rules_pkg",
sha256 = "62eeb544ff1ef41d786e329e1536c1d541bb9bcad27ae984d57f18f314018e66",
sha256 = "8f9ee2dc10c1ae514ee599a8b42ed99fa262b757058f65ad3c384289ff70c4b8",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_pkg/releases/download/0.6.0/rules_pkg-0.6.0.tar.gz",
"https://github.com/bazelbuild/rules_pkg/releases/download/0.6.0/rules_pkg-0.6.0.tar.gz",
"https://mirror.bazel.build/github.com/bazelbuild/rules_pkg/releases/download/0.9.1/rules_pkg-0.9.1.tar.gz",
"https://github.com/bazelbuild/rules_pkg/releases/download/0.9.1/rules_pkg-0.9.1.tar.gz",
],
)

@@ -158,9 +141,8 @@ rules_antlr_dependencies("4.9.3")

http_archive(
name = "io_bazel_rules_docker",
sha256 = "85ffff62a4c22a74dbd98d05da6cf40f497344b3dbf1e1ab0a37ab2a1a6ca014",
strip_prefix = "rules_docker-0.23.0",
urls = ["https://github.com/bazelbuild/rules_docker/releases/download/v0.23.0/rules_docker-v0.23.0.tar.gz"],
sha256 = "b1e80761a8a8243d03ebca8845e9cc1ba6c82ce7c5179ce2b295cd36f7e394bf",
urls = ["https://github.com/bazelbuild/rules_docker/releases/download/v0.25.0/rules_docker-v0.25.0.tar.gz"],
)

load("@io_bazel_rules_docker//repositories:repositories.bzl", container_repositories = "repositories")
@@ -241,9 +223,9 @@ container_pull(
# protobuf/gRPC
http_archive(
name = "rules_proto_grpc",
sha256 = "7954abbb6898830cd10ac9714fbcacf092299fda00ed2baf781172f545120419",
strip_prefix = "rules_proto_grpc-3.1.1",
urls = ["https://github.com/rules-proto-grpc/rules_proto_grpc/archive/3.1.1.tar.gz"],
sha256 = "9ba7299c5eb6ec45b6b9a0ceb9916d0ab96789ac8218269322f0124c0c0d24e2",
strip_prefix = "rules_proto_grpc-4.5.0",
urls = ["https://github.com/rules-proto-grpc/rules_proto_grpc/releases/download/4.5.0/rules_proto_grpc-4.5.0.tar.gz"],
)

load("@rules_proto_grpc//:repositories.bzl", "rules_proto_grpc_repos", "rules_proto_grpc_toolchains")
@@ -258,18 +240,16 @@ rules_proto_dependencies()

rules_proto_toolchains()

load("@rules_proto_grpc//python:repositories.bzl", rules_proto_grpc_python_repos = "python_repos")

rules_proto_grpc_python_repos()

load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps")
load("@rules_proto_grpc//buf:repositories.bzl", rules_proto_grpc_buf_repos = "buf_repos")

grpc_deps()
rules_proto_grpc_buf_repos()

http_archive(
name = "com_github_bazelbuild_buildtools",
strip_prefix = "buildtools-master",
url = "https://github.com/bazelbuild/buildtools/archive/2.2.1.zip",
strip_prefix = "buildtools-6.3.3",
urls = [
"https://github.com/bazelbuild/buildtools/archive/refs/tags/6.3.3.tar.gz",
],
)

http_file(
@@ -290,16 +270,32 @@ load("@com_github_scionproto_scion_python_lint_deps//:requirements.bzl", install

install_python_lint_deps()

load("//rules_openapi:dependencies.bzl", "rules_openapi_dependencies")
http_archive(
name = "aspect_rules_js",
sha256 = "a949d56fed8fa0a8dd82a0a660acc949253a05b2b0c52a07e4034e27f11218f6",
strip_prefix = "rules_js-1.33.1",
url = "https://github.com/aspect-build/rules_js/releases/download/v1.33.1/rules_js-v1.33.1.tar.gz",
)

load("@aspect_rules_js//js:repositories.bzl", "rules_js_dependencies")

rules_openapi_dependencies()
rules_js_dependencies()

load("//rules_openapi:install.bzl", "rules_openapi_install_yarn_dependencies")
load("@rules_nodejs//nodejs:repositories.bzl", "DEFAULT_NODE_VERSION", "nodejs_register_toolchains")

rules_openapi_install_yarn_dependencies()
nodejs_register_toolchains(
name = "nodejs",
node_version = DEFAULT_NODE_VERSION,
)

load("@aspect_rules_js//npm:npm_import.bzl", "npm_translate_lock")

npm_translate_lock(
name = "npm",
pnpm_lock = "@com_github_scionproto_scion//private/mgmtapi/tools:pnpm-lock.yaml",
verify_node_modules_ignored = "@com_github_scionproto_scion//:.bazelignore",
)

# TODO(lukedirtwalker): can that be integrated in the rules_openapi_dependencies
# call above somehow?
load("@cgrindel_bazel_starlib//:deps.bzl", "bazel_starlib_dependencies")
load("@npm//:repositories.bzl", "npm_repositories")

bazel_starlib_dependencies()
npm_repositories()
4 changes: 2 additions & 2 deletions acceptance/cert_renewal/test.py
Original file line number Diff line number Diff line change
@@ -72,9 +72,9 @@ def _run(self):
end2end.run_fg()

logger.info("==> Shutting down control servers and purging caches")
for container in self.dc.list_containers("scion_sd.*"):
for container in self.dc.list_containers("sd.*"):
self.dc("rm", container)
for container in self.dc.list_containers("scion_cs.*"):
for container in self.dc.list_containers("cs.*"):
self.dc.stop_container(container)
for cs_config in cs_configs:
files = list((pathlib.Path(self.artifacts) /
8 changes: 2 additions & 6 deletions acceptance/common/docker.py
Original file line number Diff line number Diff line change
@@ -35,24 +35,20 @@
from plumbum import cmd

SCION_DC_FILE = "gen/scion-dc.yml"
DC_PROJECT = "scion"
SCION_TESTING_DOCKER_ASSERTIONS_OFF = 'SCION_TESTING_DOCKER_ASSERTIONS_OFF'


class Compose(object):
def __init__(self,
project: str = DC_PROJECT,
compose_file: str = SCION_DC_FILE):
self.project = project
self.compose_file = compose_file

def __call__(self, *args, **kwargs) -> str:
"""Runs docker compose with the given arguments"""
# Note: not using plumbum here due to complications with encodings in the captured output
try:
res = subprocess.run(
["docker", "compose", "--compatibility",
"-f", self.compose_file, "-p", self.project, *args],
["docker", "compose", "-f", self.compose_file, *args],
check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8")
except subprocess.CalledProcessError as e:
raise _CalledProcessErrorWithOutput(e) from None
@@ -201,7 +197,7 @@ def assert_no_networks(writer=None):
writer.write("Docker networking assertions are OFF\n")
return

allowed_nets = ['bridge', 'host', 'none']
allowed_nets = ['bridge', 'host', 'none', 'benchmark']
unexpected_nets = []
for net in _get_networks():
if net.name not in allowed_nets:
46 changes: 21 additions & 25 deletions acceptance/hidden_paths/test.py
Original file line number Diff line number Diff line change
@@ -5,10 +5,9 @@
import http.server
import threading

from plumbum import cmd

from acceptance.common import base
from acceptance.common import scion
from tools.topology.scion_addr import ISD_AS


class Test(base.TestTopogen):
@@ -108,12 +107,6 @@ def setup_start(self):

super().setup_start()

self._testers = {
"2": "tester_1-ff00_0_2",
"3": "tester_1-ff00_0_3",
"4": "tester_1-ff00_0_4",
"5": "tester_1-ff00_0_5",
}
self._ases = {
"2": "1-ff00:0:2",
"3": "1-ff00:0:3",
@@ -126,27 +119,30 @@ def _run(self):
self._server.shutdown() # by now configuration must have been downloaded everywhere

# Group 3
self._showpaths_bidirectional("2", "3", 0)
self._showpaths_bidirectional("2", "5", 0)
self._showpaths_bidirectional("3", "5", 0)
self._showpaths_bidirectional("2", "3")
self._showpaths_bidirectional("2", "5")
self._showpaths_bidirectional("3", "5")

# Group 4
self._showpaths_bidirectional("2", "4", 0)
self._showpaths_bidirectional("2", "5", 0)
self._showpaths_bidirectional("4", "5", 0)
self._showpaths_bidirectional("2", "4")
self._showpaths_bidirectional("2", "5")
self._showpaths_bidirectional("4", "5")

# Group 3 X 4
self._showpaths_bidirectional("3", "4", 1)

def _showpaths_bidirectional(self, source: str, destination: str, retcode: int):
self._showpaths_run(source, destination, retcode)
self._showpaths_run(destination, source, retcode)

def _showpaths_run(self, source_as: str, destination_as: str, retcode: int):
print(cmd.docker("exec", "-t", self._testers[source_as], "scion",
"sp", self._ases[destination_as],
"--timeout", "2s",
retcode=retcode))
try:
self._showpaths_bidirectional("3", "4")
except Exception as e:
print(e)
else:
raise AssertionError("Unexpected success; should not have paths 3 -> 4")

def _showpaths_bidirectional(self, source: str, destination: str):
self._showpaths_run(source, destination)
self._showpaths_run(destination, source)

def _showpaths_run(self, source_as: str, destination_as: str):
print(self.execute_tester(ISD_AS(self._ases[source_as]),
"scion", "sp", self._ases[destination_as], "--timeout", "2s"))


def configuration_server(server):
28 changes: 28 additions & 0 deletions acceptance/router_benchmark/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
load("//acceptance/common:raw.bzl", "raw_test")

exports_files([
"conf",
"test.py",
])

args = [
"--executable",
"brload:$(location //acceptance/router_benchmark/brload:brload)",
"--container-loader=posix-router:latest#$(location //docker:posix_router)",
]

data = [
":conf",
"//docker:posix_router",
"//acceptance/router_benchmark/brload:brload",
]

raw_test(
name = "test",
src = "test.py",
args = args,
data = data,
homedir = "$(rootpath //docker:posix_router)",
# This test uses sudo and accesses /var/run/netns.
local = True,
)
27 changes: 27 additions & 0 deletions acceptance/router_benchmark/brload/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
load("//tools/lint:go.bzl", "go_library")
load("//:scion.bzl", "scion_go_binary")

go_library(
name = "go_default_library",
srcs = ["main.go"],
importpath = "github.com/scionproto/scion/acceptance/router_benchmark/brload",
visibility = ["//visibility:private"],
deps = [
"//acceptance/router_benchmark/cases:go_default_library",
"//pkg/log:go_default_library",
"//pkg/private/serrors:go_default_library",
"//pkg/scrypto:go_default_library",
"//pkg/slayers:go_default_library",
"//private/keyconf:go_default_library",
"@com_github_google_gopacket//:go_default_library",
"@com_github_google_gopacket//afpacket:go_default_library",
"@com_github_google_gopacket//layers:go_default_library",
"@com_github_spf13_cobra//:go_default_library",
],
)

scion_go_binary(
name = "brload",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
326 changes: 326 additions & 0 deletions acceptance/router_benchmark/brload/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,326 @@
// Copyright 2023 SCION Association
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"encoding/binary"
"errors"
"fmt"
"hash"
"net"
"os"
"path/filepath"
"reflect"
"strings"
"time"

"github.com/google/gopacket"
"github.com/google/gopacket/afpacket"
"github.com/google/gopacket/layers"
"github.com/spf13/cobra"

"github.com/scionproto/scion/acceptance/router_benchmark/cases"
"github.com/scionproto/scion/pkg/log"
"github.com/scionproto/scion/pkg/private/serrors"
"github.com/scionproto/scion/pkg/scrypto"
"github.com/scionproto/scion/pkg/slayers"
"github.com/scionproto/scion/private/keyconf"
)

type Case func(payload string, mac hash.Hash) (string, string, []byte)

type caseChoice string

func (c *caseChoice) String() string {
return string(*c)
}

func (c *caseChoice) Set(v string) error {
_, ok := allCases[v]
if !ok {
return errors.New("No such case")
}
*c = caseChoice(v)
return nil
}

func (c *caseChoice) Type() string {
return "string enum"
}

func (c *caseChoice) Allowed() string {
return fmt.Sprintf("One of: %v", reflect.ValueOf(allCases).MapKeys())
}

var (
allCases = map[string]Case{
"in": cases.In,
"out": cases.Out,
"in_transit": cases.InTransit,
"out_transit": cases.OutTransit,
"br_transit": cases.BrTransit,
}
logConsole string
dir string
numPackets int
numStreams uint16
caseToRun caseChoice
interfaces []string
)

func main() {
rootCmd := &cobra.Command{
Use: "brload",
Short: "Generates traffic into a specific router of a specific topology",
}
intfCmd := &cobra.Command{
Use: "show-interfaces",
Short: "Provides a terse list of the interfaces that this test requires",
Run: func(cmd *cobra.Command, args []string) {
os.Exit(showInterfaces(cmd))
},
}
runCmd := &cobra.Command{
Use: "run",
Short: "Executes the test",
Run: func(cmd *cobra.Command, args []string) {
os.Exit(run(cmd))
},
}
runCmd.Flags().IntVar(&numPackets, "num-packets", 10, "Number of packets to send")
runCmd.Flags().Uint16Var(&numStreams, "num-streams", 4,
"Number of independent streams (flowID) to use")
runCmd.Flags().StringVar(&logConsole, "log.console", "error",
"Console logging level: debug|info|error|etc.")
runCmd.Flags().StringVar(&dir, "artifacts", "", "Artifacts directory")
runCmd.Flags().Var(&caseToRun, "case", "Case to run. "+caseToRun.Allowed())
runCmd.Flags().StringArrayVar(&interfaces, "interface", []string{},
`label=host_interface,mac,peer_mac where:
host_interface: use this to exchange traffic with interface <label>
mac: the mac address of interface <label>
peer_mac: the mac address of <host_interface>`)
runCmd.MarkFlagRequired("case")
runCmd.MarkFlagRequired("interface")

rootCmd.AddCommand(intfCmd)
rootCmd.AddCommand(runCmd)
rootCmd.CompletionOptions.HiddenDefaultCmd = true

if rootCmd.Execute() != nil {
os.Exit(1)
}
os.Exit(0)
}

func showInterfaces(cmd *cobra.Command) int {
fmt.Println(cases.ListInterfaces())
return 0
}

func run(cmd *cobra.Command) int {
logCfg := log.Config{Console: log.ConsoleConfig{Level: logConsole}}
if err := log.Setup(logCfg); err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
return 1
}
defer log.HandlePanic()

artifactsDir := dir
if v := os.Getenv("TEST_ARTIFACTS_DIR"); v != "" {
artifactsDir = v
}

if artifactsDir == "" {
log.Error("Artifacts directory not configured")
return 1
}

hfMAC, err := loadKey(artifactsDir)
if err != nil {
log.Error("Loading keys failed", "err", err)
return 1
}

cases.InitInterfaces(interfaces)
handles, err := openDevices()
if err != nil {
log.Error("Loading devices failed", "err", err)
return 1
}

registerScionPorts()

log.Info("BRLoad acceptance tests:")

payloadString := "actualpayloadbytes"
caseFunc := allCases[string(caseToRun)] // key already checked.
caseDevIn, caseDevOut, rawPkt := caseFunc(payloadString, hfMAC)

writePktTo, ok := handles[caseDevIn]
if !ok {
log.Error("device not found", "device", caseDevIn)
return 1
}

readPktFrom, ok := handles[caseDevOut]
if !ok {
log.Error("device not found", "device", caseDevOut)
return 1
}

// Try and pick-up one packet and check the payload. If that works, we're content
// that this test works.
packetSource := gopacket.NewPacketSource(readPktFrom, layers.LinkTypeEthernet)
packetChan := packetSource.Packets()
listenerChan := make(chan int)

go func() {
defer log.HandlePanic()
defer close(listenerChan)
listenerChan <- receivePackets(packetChan, payloadString)
}()

// We started everything that could be started. So the best window for perf mertics
// opens somewhere around now.
metricsBegin := time.Now().Unix()
// Because we're using IPV4 only, the UDP checksum is optional, so we are allowed to
// just set it to zero instead of recomputing it. The IP checksum does not cover the payload, so
// we don't need to update it.
binary.BigEndian.PutUint16(rawPkt[40:42], 0)

for i := 0; i < numPackets; i++ {
// Rotate through flowIDs. We patch it directly into the SCION header of the packet. The
// SCION header starts at offset 42. The flowID is the 20 least significant bits of the
// first 32 bit field. To make our life simpler, we only use the last 16 bits (so no more
// than 64K flows).
binary.BigEndian.PutUint16(rawPkt[44:46], uint16(i%int(numStreams)))
if err := writePktTo.WritePacketData(rawPkt); err != nil {
log.Error("writing input packet", "case", string(caseToRun), "error", err)
return 1
}
}
metricsEnd := time.Now().Unix()
// The test harness looks for this output.
fmt.Printf("metricsBegin: %d metricsEnd: %d\n", metricsBegin, metricsEnd)

// Get the results from the packet listener.
// Give it one second as in very short tests (<1M pkts) we get here before the first packet.
outcome := 0
timeout := time.After(1 * time.Second)
for outcome == 0 {
select {
case outcome = <-listenerChan:
if outcome == 0 {
log.Error("Listener never saw a valid packet being forwarded")
return 1
}
case <-timeout:
// If our listener is still stuck there, unstick it. Closing the device doesn't cause
// the packet channel to close (presumably a bug). Close the channel ourselves. After
// this, the next loop is guaranteed an outcome.
close(packetChan)
}
}

fmt.Printf("Listener results: %d\n", outcome)
return 0
}

// receivePkts consume some or all (at least one if it arrives) of the packets
// arriving on the given handle and checks that they contain the given payload.
// The number of consumed packets is returned.
// Currently we are content with receiving a single correct packet and we terminate after
// that.
func receivePackets(packetChan chan gopacket.Packet, payload string) int {
numRcv := 0

for {
got, ok := <-packetChan
if !ok {
// No more packets
log.Info("No more Packets")
return numRcv
}
if err := got.ErrorLayer(); err != nil {
log.Error("error decoding packet", "err", err)
continue
}
layer := got.Layer(gopacket.LayerTypePayload)
if layer == nil {
log.Error("error fetching packet payload: no PayLoad")
continue
}
if string(layer.LayerContents()) == payload {
// To return the count of all packets received, just remove the "return" below.
// Return will occur once packetChan closes (which happens after a short timeout at
// the end of the test).
numRcv++
return numRcv
}
}
}

// initDevices inventories the available network interfaces, picks the ones that a case may inject
// traffic into, and associates them with a AF Packet interface. It returns the packet interfaces
// corresponding to each network interface.
func openDevices() (map[string]*afpacket.TPacket, error) {
devs, err := net.Interfaces()
if err != nil {
return nil, serrors.WrapStr("listing network interfaces", err)
}

handles := make(map[string]*afpacket.TPacket)

for _, dev := range devs {
if !strings.HasPrefix(dev.Name, "veth_") || !strings.HasSuffix(dev.Name, "_host") {
continue
}
handle, err := afpacket.NewTPacket(afpacket.OptInterface(dev.Name))
if err != nil {
return nil, serrors.WrapStr("creating TPacket", err)
}
handles[dev.Name] = handle
}

return handles, nil
}

// loadKey loads the keys that the router under test uses to sign hop fields.
func loadKey(artifactsDir string) (hash.Hash, error) {
keysDir := filepath.Join(artifactsDir, "conf", "keys")
mk, err := keyconf.LoadMaster(keysDir)
if err != nil {
return nil, err
}
macGen, err := scrypto.HFMacFactory(mk.Key0)
if err != nil {
return nil, err
}
return macGen(), nil
}

// registerScionPorts registers the following UDP ports in gopacket such as SCION is the
// next layer. In other words, map the following ports to expect SCION as the payload.
func registerScionPorts() {
for i := 30041; i < 30043; i++ {
layers.RegisterUDPPortLayerType(layers.UDPPort(i), slayers.LayerTypeSCION)
}
for i := 30000; i < 30010; i++ {
layers.RegisterUDPPortLayerType(layers.UDPPort(i), slayers.LayerTypeSCION)
}
for i := 50000; i < 50010; i++ {
layers.RegisterUDPPortLayerType(layers.UDPPort(i), slayers.LayerTypeSCION)
}
}
28 changes: 28 additions & 0 deletions acceptance/router_benchmark/cases/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
load("//tools/lint:go.bzl", "go_library")

go_library(
name = "go_default_library",
srcs = [
"br_transit.go",
"in.go",
"in_transit.go",
"out.go",
"out_transit.go",
"topo.go",
],
importpath = "github.com/scionproto/scion/acceptance/router_benchmark/cases",
visibility = [
"//acceptance/router_benchmark:__subpackages__",
],
deps = [
"//pkg/addr:go_default_library",
"//pkg/private/util:go_default_library",
"//pkg/private/xtest:go_default_library",
"//pkg/scrypto:go_default_library",
"//pkg/slayers:go_default_library",
"//pkg/slayers/path:go_default_library",
"//pkg/slayers/path/scion:go_default_library",
"@com_github_google_gopacket//:go_default_library",
"@com_github_google_gopacket//layers:go_default_library",
],
)
133 changes: 133 additions & 0 deletions acceptance/router_benchmark/cases/br_transit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Copyright 2023 SCION Association
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cases

import (
"hash"
"time"

"github.com/google/gopacket"

"github.com/scionproto/scion/pkg/private/util"
"github.com/scionproto/scion/pkg/slayers"
"github.com/scionproto/scion/pkg/slayers/path"
"github.com/scionproto/scion/pkg/slayers/path/scion"
)

// Topology (see accept/router_benchmark/conf/topology.json)
// AS2 (br2) ---+== (br1a) AS1 (br1b) ---- (br4) AS4
// |
// AS3 (br3) ---+
// See topo.go

// BrTransit generates one packet of "br_transit" traffic over the router under test.
// The outcome is a raw packet which the test must feed to the router. The flowID field is 0.
func BrTransit(payload string, mac hash.Hash) (string, string, []byte) {

var (
originIA = ISDAS(2)
originIP = PublicIP(2, 1)
originHost = HostAddr(originIP)
srcIP, srcPort = PublicIPPort(2, 1)
dstIP, dstPort = PublicIPPort(1, 2)
targetIA = ISDAS(3)
targetIP = PublicIP(3, 1)
targetHost = HostAddr(targetIP)
)

options := gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true,
}

ethernet, ip, udp := Underlay(srcIP, srcPort, dstIP, dstPort)

// Fully correct (hopefully) path.
sp := &scion.Decoded{
Base: scion.Base{
PathMeta: scion.MetaHdr{
CurrHF: 1,
SegLen: [3]uint8{2, 2, 0},
},
NumINF: 2,
NumHops: 4,
},
InfoFields: []path.InfoField{
{
SegID: 0x111,
Timestamp: util.TimeToSecs(time.Now()),
ConsDir: false,
},
{
SegID: 0x222,
Timestamp: util.TimeToSecs(time.Now()),
ConsDir: true,
},
},
HopFields: []path.HopField{
{ConsIngress: 1, ConsEgress: 0}, // From there (non-consdir)
{ConsIngress: 0, ConsEgress: 2}, // <- Processed here (non-consdir)
{ConsIngress: 0, ConsEgress: 3}, // Down via this
{ConsIngress: 1, ConsEgress: 0}, // To there
},
}

// Calculate MACs...
// Seg0: Hops are in non-consdir.
sp.HopFields[1].Mac = path.MAC(mac, sp.InfoFields[0], sp.HopFields[1], nil)
sp.InfoFields[0].UpdateSegID(sp.HopFields[1].Mac)
sp.HopFields[0].Mac = path.MAC(FakeMAC(2), sp.InfoFields[0], sp.HopFields[0], nil)

// Seg1: in the natural order.
sp.HopFields[2].Mac = path.MAC(mac, sp.InfoFields[1], sp.HopFields[2], nil)
sp.InfoFields[1].UpdateSegID(sp.HopFields[2].Mac) // tmp
sp.HopFields[3].Mac = path.MAC(FakeMAC(3), sp.InfoFields[1], sp.HopFields[2], nil)
sp.InfoFields[1].SegID = 0x222 // Restore to initial.

// End-to-end. Src is the originator and Dst is the final destination.
scionL := &slayers.SCION{
Version: 0,
TrafficClass: 0xb8,
FlowID: 0,
NextHdr: slayers.L4UDP,
PathType: scion.PathType,
SrcIA: originIA,
DstIA: targetIA,
Path: sp,
}
if err := scionL.SetSrcAddr(originHost); err != nil {
panic(err)
}
if err := scionL.SetDstAddr(targetHost); err != nil {
panic(err)
}

scionudp := &slayers.UDP{}
scionudp.SrcPort = 50000
scionudp.DstPort = 50000
scionudp.SetNetworkLayerForChecksum(scionL)

payloadBytes := []byte(payload)

// Prepare input packet
input := gopacket.NewSerializeBuffer()
if err := gopacket.SerializeLayers(input, options,
ethernet, ip, udp, scionL, scionudp, gopacket.Payload(payloadBytes),
); err != nil {
panic(err)
}

return DeviceName(1, 2), DeviceName(1, 3), input.Bytes()
}
119 changes: 119 additions & 0 deletions acceptance/router_benchmark/cases/in.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// Copyright 2023 SCION Association
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cases

import (
"hash"
"time"

"github.com/google/gopacket"

"github.com/scionproto/scion/pkg/private/util"
"github.com/scionproto/scion/pkg/slayers"
"github.com/scionproto/scion/pkg/slayers/path"
"github.com/scionproto/scion/pkg/slayers/path/scion"
)

// Topology (see accept/router_benchmark/conf/topology.json)
// AS2 (br2) ---+== (br1a) AS1 (br1b) ---- (br4) AS4
// |
// AS3 (br3) ---+
// See topo.go

// oneIn generates one packet of incoming traffic into AS1 at br1a. The outcome is a raw packet
// that the test must feed into the router. The flow ID is 0.
func In(payload string, mac hash.Hash) (string, string, []byte) {

var (
originIA = ISDAS(2)
originIP = PublicIP(2, 1)
originHost = HostAddr(originIP)
srcIP, srcPort = PublicIPPort(2, 1)
dstIP, dstPort = PublicIPPort(1, 2)
targetIA = ISDAS(1)
targetIP = InternalIP(1, 2)
targetHost = HostAddr(targetIP)
)

options := gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true,
}

ethernet, ip, udp := Underlay(srcIP, srcPort, dstIP, dstPort)

// Fully correct (hopefully) path.
sp := &scion.Decoded{
Base: scion.Base{
PathMeta: scion.MetaHdr{
CurrHF: 1,
SegLen: [3]uint8{2, 0, 0},
},
NumINF: 1,
NumHops: 2,
},
InfoFields: []path.InfoField{
{
SegID: 0x111,
Timestamp: util.TimeToSecs(time.Now()),
ConsDir: false,
},
},
HopFields: []path.HopField{
{ConsIngress: 1, ConsEgress: 0}, // From there (non-consdir)
{ConsIngress: 0, ConsEgress: 2}, // <- Processed here (non-consdir)
},
}

// Calculate MACs...
// Seg0: Hops are in non-consdir.
sp.HopFields[1].Mac = path.MAC(mac, sp.InfoFields[0], sp.HopFields[1], nil)
sp.InfoFields[0].UpdateSegID(sp.HopFields[1].Mac)
sp.HopFields[0].Mac = path.MAC(FakeMAC(2), sp.InfoFields[0], sp.HopFields[0], nil)

// End-to-end. Src is the originator and Dst is the final destination.
scionL := &slayers.SCION{
Version: 0,
TrafficClass: 0xb8,
FlowID: 0,
NextHdr: slayers.L4UDP,
PathType: scion.PathType,
SrcIA: originIA,
DstIA: targetIA,
Path: sp,
}
if err := scionL.SetSrcAddr(originHost); err != nil {
panic(err)
}
if err := scionL.SetDstAddr(targetHost); err != nil {
panic(err)
}

scionudp := &slayers.UDP{}
scionudp.SrcPort = 50000
scionudp.DstPort = 50000
scionudp.SetNetworkLayerForChecksum(scionL)

payloadBytes := []byte(payload)

// Prepare input packet
input := gopacket.NewSerializeBuffer()
if err := gopacket.SerializeLayers(input, options,
ethernet, ip, udp, scionL, scionudp, gopacket.Payload(payloadBytes),
); err != nil {
panic(err)
}
return DeviceName(1, 2), DeviceName(1, 0), input.Bytes()
}
132 changes: 132 additions & 0 deletions acceptance/router_benchmark/cases/in_transit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Copyright 2023 SCION Association
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cases

import (
"hash"
"time"

"github.com/google/gopacket"

"github.com/scionproto/scion/pkg/private/util"
"github.com/scionproto/scion/pkg/slayers"
"github.com/scionproto/scion/pkg/slayers/path"
"github.com/scionproto/scion/pkg/slayers/path/scion"
)

// Topology (see accept/router_benchmark/conf/topology.json)
// AS2 (br2) ---+== (br1a) AS1 (br1b) ---- (br4) AS4
// |
// AS3 (br3) ---+
// See topo.go

// oneInTransit generates one packet of "in_transit" traffic over the router under test.
// The outcome is a raw packet that the test must feed into the router. The flow ID is 0.
func InTransit(payload string, mac hash.Hash) (string, string, []byte) {

var (
originIA = ISDAS(2)
originIP = PublicIP(2, 1)
originHost = HostAddr(originIP)
srcIP, srcPort = PublicIPPort(2, 1)
dstIP, dstPort = PublicIPPort(1, 2)
targetIA = ISDAS(4)
targetIP = PublicIP(4, 1)
targetHost = HostAddr(targetIP)
)

options := gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true,
}

ethernet, ip, udp := Underlay(srcIP, srcPort, dstIP, dstPort)

// Fully correct (hopefully) path.
sp := &scion.Decoded{
Base: scion.Base{
PathMeta: scion.MetaHdr{
CurrHF: 1,
SegLen: [3]uint8{2, 2, 0},
},
NumINF: 2,
NumHops: 4,
},
InfoFields: []path.InfoField{
{
SegID: 0x111,
Timestamp: util.TimeToSecs(time.Now()),
ConsDir: false,
},
{
SegID: 0x222,
Timestamp: util.TimeToSecs(time.Now()),
ConsDir: true,
},
},
HopFields: []path.HopField{
{ConsIngress: 1, ConsEgress: 0}, // From there (non-consdir)
{ConsIngress: 0, ConsEgress: 2}, // <- Processed here (non-consdir)
{ConsIngress: 0, ConsEgress: 4}, // Sideways to as4 via this
{ConsIngress: 1, ConsEgress: 0}, // To there
},
}

// Calculate MACs...
// Seg0: Hops are in non-consdir.
sp.HopFields[1].Mac = path.MAC(mac, sp.InfoFields[0], sp.HopFields[1], nil)
sp.InfoFields[0].UpdateSegID(sp.HopFields[1].Mac)
sp.HopFields[0].Mac = path.MAC(FakeMAC(2), sp.InfoFields[0], sp.HopFields[0], nil)

// Seg1: in the natural order.
sp.HopFields[2].Mac = path.MAC(mac, sp.InfoFields[1], sp.HopFields[2], nil)
sp.InfoFields[1].UpdateSegID(sp.HopFields[2].Mac) // tmp
sp.HopFields[3].Mac = path.MAC(FakeMAC(4), sp.InfoFields[1], sp.HopFields[2], nil)
sp.InfoFields[1].SegID = 0x222 // Restore to initial.

// End-to-end. Src is the originator and Dst is the final destination.
scionL := &slayers.SCION{
Version: 0,
TrafficClass: 0xb8,
FlowID: 0,
NextHdr: slayers.L4UDP,
PathType: scion.PathType,
SrcIA: originIA,
DstIA: targetIA,
Path: sp,
}
if err := scionL.SetSrcAddr(originHost); err != nil {
panic(err)
}
if err := scionL.SetDstAddr(targetHost); err != nil {
panic(err)
}

scionudp := &slayers.UDP{}
scionudp.SrcPort = 50000
scionudp.DstPort = 50000
scionudp.SetNetworkLayerForChecksum(scionL)

payloadBytes := []byte(payload)

// Prepare input packet
input := gopacket.NewSerializeBuffer()
if err := gopacket.SerializeLayers(input, options,
ethernet, ip, udp, scionL, scionudp, gopacket.Payload(payloadBytes),
); err != nil {
panic(err)
}
return DeviceName(1, 2), DeviceName(1, 0), input.Bytes()
}
121 changes: 121 additions & 0 deletions acceptance/router_benchmark/cases/out.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright 2023 SCION Association
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cases

import (
"hash"
"time"

"github.com/google/gopacket"

"github.com/scionproto/scion/pkg/private/util"
"github.com/scionproto/scion/pkg/slayers"
"github.com/scionproto/scion/pkg/slayers/path"
"github.com/scionproto/scion/pkg/slayers/path/scion"
)

// Topology (see accept/router_benchmark/conf/topology.json)
// AS2 (br2) ---+== (br1a) AS1 (br1b) ---- (br4) AS4
// |
// AS3 (br3) ---+
// See topo.go

// oneOut generates one packet of outgoing traffic from AS1 at br1a. The outcome is a raw packet
// that the test must feed into the router. The flow ID is 0.
func Out(payload string, mac hash.Hash) (string, string, []byte) {

var (
originIA = ISDAS(1)
originIP = InternalIP(1, 2)
originHost = HostAddr(originIP)
srcIP, srcPort = InternalIPPort(1, 2)
dstIP, dstPort = InternalIPPort(1, 1)
targetIA = ISDAS(2)
targetIP = PublicIP(2, 1)
targetHost = HostAddr(targetIP)
)

options := gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true,
}

ethernet, ip, udp := Underlay(srcIP, srcPort, dstIP, dstPort)

// Fully correct (hopefully) path.
sp := &scion.Decoded{
Base: scion.Base{
PathMeta: scion.MetaHdr{
CurrHF: 0,
SegLen: [3]uint8{2, 0, 0},
},
NumINF: 1,
NumHops: 2,
},
InfoFields: []path.InfoField{
{
SegID: 0x111,
Timestamp: util.TimeToSecs(time.Now()),
ConsDir: true,
},
},
HopFields: []path.HopField{
{ConsIngress: 0, ConsEgress: 2}, // <- Processed here
{ConsIngress: 1, ConsEgress: 0}, // Going there
},
}

// Calculate MACs...
// Seg0: Hops are in consdir.
sp.HopFields[0].Mac = path.MAC(mac, sp.InfoFields[0], sp.HopFields[0], nil)
sp.InfoFields[0].UpdateSegID(sp.HopFields[0].Mac) // tmp
sp.HopFields[1].Mac = path.MAC(FakeMAC(2), sp.InfoFields[0], sp.HopFields[0], nil)
sp.InfoFields[0].SegID = 0x111 // Restore to initial.

// End-to-end. Src is the originator and Dst is the final destination.
scionL := &slayers.SCION{
Version: 0,
TrafficClass: 0xb8,
FlowID: 0,
NextHdr: slayers.L4UDP,
PathType: scion.PathType,
SrcIA: originIA,
DstIA: targetIA,
Path: sp,
}
if err := scionL.SetSrcAddr(originHost); err != nil {
panic(err)
}
if err := scionL.SetDstAddr(targetHost); err != nil {
panic(err)
}

scionudp := &slayers.UDP{}
scionudp.SrcPort = 50000
scionudp.DstPort = 50000
scionudp.SetNetworkLayerForChecksum(scionL)

payloadBytes := []byte(payload)

// Prepare input packet
input := gopacket.NewSerializeBuffer()
if err := gopacket.SerializeLayers(input, options,
ethernet, ip, udp, scionL, scionudp, gopacket.Payload(payloadBytes),
); err != nil {
panic(err)
}

return DeviceName(1, 0), DeviceName(1, 2), input.Bytes()
}
133 changes: 133 additions & 0 deletions acceptance/router_benchmark/cases/out_transit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Copyright 2023 SCION Association
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cases

import (
"hash"
"time"

"github.com/google/gopacket"

"github.com/scionproto/scion/pkg/private/util"
"github.com/scionproto/scion/pkg/slayers"
"github.com/scionproto/scion/pkg/slayers/path"
"github.com/scionproto/scion/pkg/slayers/path/scion"
)

// Topology (see accept/router_benchmark/conf/topology.json)
// AS2 (br2) ---+== (br1a) AS1 (br1b) ---- (br4) AS4
// |
// AS3 (br3) ---+
// See topo.go

// oneOutTransit generates one packet of "out_transit" traffic over the router under test.
// The outcome is a raw packet that the test must feed to the router. The flow ID is 0.
func OutTransit(payload string, mac hash.Hash) (string, string, []byte) {

var (
originIA = ISDAS(4)
originIP = PublicIP(4, 1)
originHost = HostAddr(originIP)
srcIP, srcPort = InternalIPPort(1, 2)
dstIP, dstPort = InternalIPPort(1, 1)
targetIA = ISDAS(2)
targetIP = PublicIP(2, 1)
targetHost = HostAddr(targetIP)
)

options := gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true,
}

ethernet, ip, udp := Underlay(srcIP, srcPort, dstIP, dstPort)

// Fully correct (hopefully) path.
sp := &scion.Decoded{
Base: scion.Base{
PathMeta: scion.MetaHdr{
CurrINF: 1,
CurrHF: 2,
SegLen: [3]uint8{2, 2, 0},
},
NumINF: 2,
NumHops: 4,
},
InfoFields: []path.InfoField{
{
SegID: 0x111,
Timestamp: util.TimeToSecs(time.Now()),
ConsDir: false,
},
{
SegID: 0x222,
Timestamp: util.TimeToSecs(time.Now()),
ConsDir: true,
},
},
HopFields: []path.HopField{
{ConsIngress: 1, ConsEgress: 0}, // From there (non-consdir)
{ConsIngress: 0, ConsEgress: 4}, // Sideways via this
{ConsIngress: 0, ConsEgress: 2}, // <- Processed here (non-consdir)
{ConsIngress: 1, ConsEgress: 0}, // To there
},
}

// Calculate MACs...
// Seg0: Hops are in non-consdir.
sp.HopFields[1].Mac = path.MAC(mac, sp.InfoFields[0], sp.HopFields[1], nil)
sp.InfoFields[0].UpdateSegID(sp.HopFields[1].Mac)
sp.HopFields[0].Mac = path.MAC(FakeMAC(4), sp.InfoFields[0], sp.HopFields[0], nil)

// Seg1: in the natural order.
sp.HopFields[2].Mac = path.MAC(mac, sp.InfoFields[1], sp.HopFields[2], nil)
sp.InfoFields[1].UpdateSegID(sp.HopFields[2].Mac) // tmp
sp.HopFields[3].Mac = path.MAC(FakeMAC(2), sp.InfoFields[1], sp.HopFields[2], nil)
sp.InfoFields[1].SegID = 0x222 // Restore to initial.

// End-to-end. Src is the originator and Dst is the final destination.
scionL := &slayers.SCION{
Version: 0,
TrafficClass: 0xb8,
FlowID: 0,
NextHdr: slayers.L4UDP,
PathType: scion.PathType,
SrcIA: originIA,
DstIA: targetIA,
Path: sp,
}
if err := scionL.SetSrcAddr(originHost); err != nil {
panic(err)
}
if err := scionL.SetDstAddr(targetHost); err != nil {
panic(err)
}

scionudp := &slayers.UDP{}
scionudp.SrcPort = 50000
scionudp.DstPort = 50000
scionudp.SetNetworkLayerForChecksum(scionL)

payloadBytes := []byte(payload)

// Prepare input packet
input := gopacket.NewSerializeBuffer()
if err := gopacket.SerializeLayers(input, options,
ethernet, ip, udp, scionL, scionudp, gopacket.Payload(payloadBytes),
); err != nil {
panic(err)
}
return DeviceName(1, 0), DeviceName(1, 2), input.Bytes()
}
236 changes: 236 additions & 0 deletions acceptance/router_benchmark/cases/topo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
// Copyright 2023 SCION Association
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cases

import (
"fmt"
"hash"
"net"
"net/netip"
"strings"

"github.com/google/gopacket/layers"

"github.com/scionproto/scion/pkg/addr"
"github.com/scionproto/scion/pkg/private/xtest"
"github.com/scionproto/scion/pkg/scrypto"
)

// Topology (see accept/router_benchmark/conf/topology.json)
// AS2 (br2) ---+== (br1a) AS1 (br1b) ---- (br4) AS4
// |
// AS3 (br3) ---+
//
// We're only executing and monitoring br1a. All the others are a fiction (except for the knowledge
// about them configured in br1a) from which we construct packets that get injected at one of the
// br1a interfaces.
//
// To reduce maintainers headaches, the topology follows a convention to assign addresses, so that
// an address can be derived from a minimal information:
// * AS-1 is the hub of the test. Others are hereafter called children.
// * All IPs are V4.
// * Interface numbers are equal to the index of AS to which they connect.
// * ISD/AS: <1 or 2>-ff00:0:<AS index>
// * subnets are 192.168.<child AS number> except internal subnets that are 192.168.10*<AS>.<rtr>
// * hosts are 192.168.s.<interface number>
// * Mac addressed (when we can choose) derive from the IP
// * Ports are always 50000 for external interfaces and 30042 for internal interfaces.
//
// Example:
// * AS2 has only interface number 1 with IP 192.168.2.2 and mac address f0:0d:cafe:02:02 that
// connects to AS 1 interface number 2.
// * AS1's interface number 2 has IP 192.168.2.1 and mac address f0:0d:cafe:02:01.
// * AS1's 1st router interface 0 has IP 192.168.10.1 and mac address f0:0d:cafe:10:01.
//
// Functions are provided to generate all addresses following that scheme.

// intfDesc describes an interface requirement
type intfDesc struct {
ip netip.Addr
peerIP netip.Addr
}

// publicIP returns the IP address that is assigned to external interface designated by the given
// AS index and the peer AS (that is, the AS that this interface connects to).
// Per our scheme, the subnet number is the largest of the two AS numbers and the host is always
// the local AS. This works if there are no cycles. Else there could be subnet number collisions.
func PublicIP(localAS byte, remoteAS byte) netip.Addr {
subnetNr := max(remoteAS, localAS)
return netip.AddrFrom4([4]byte{192, 168, subnetNr, localAS})
}

// publicIP returns the IP address that is assigned to external interface designated by the given
// AS index and the peer AS, plus the port to go with.
func PublicIPPort(localAS byte, remoteAS byte) (netip.Addr, layers.UDPPort) {
return PublicIP(localAS, remoteAS), layers.UDPPort(50000)
}

// internalIP returns the IP address that is assigned to the internal interface of the given
// router in the AS of the given index.
func InternalIP(AS byte, routerIndex byte) netip.Addr {
return netip.AddrFrom4([4]byte{192, 168, AS * 10, routerIndex})
}

// internalIPPort returns internalIP and the UDPPort to go with.
func InternalIPPort(AS byte, routerIndex byte) (netip.Addr, layers.UDPPort) {
return InternalIP(AS, routerIndex), layers.UDPPort(30042)
}

// isdAS returns a complete string form ISD/AS number for the given AS index.
// All are in ISD-1, except AS 4.
func ISDAS(AS byte) addr.IA {
if AS == 4 {
return xtest.MustParseIA(fmt.Sprintf("2-ff00:0:%d", AS))
}
return xtest.MustParseIA(fmt.Sprintf("1-ff00:0:%d", AS))
}

func FakeMAC(AS byte) hash.Hash {
macGen, err := scrypto.HFMacFactory([]byte{AS})
if err != nil {
panic(err)
}
return macGen()
}

func Underlay(
srcIP netip.Addr,
srcPort layers.UDPPort,
dstIP netip.Addr,
dstPort layers.UDPPort) (*layers.Ethernet, *layers.IPv4, *layers.UDP) {

// Point-to-point.
ethernet := &layers.Ethernet{
SrcMAC: MACAddr(srcIP),
DstMAC: MACAddr(dstIP),
EthernetType: layers.EthernetTypeIPv4,
}

// Point-to-point. This is the real IP: the underlay network.
ip := &layers.IPv4{
Version: 4,
IHL: 5,
TTL: 64,
SrcIP: srcIP.AsSlice(),
DstIP: dstIP.AsSlice(),
Protocol: layers.IPProtocolUDP,
Flags: layers.IPv4DontFragment,
}
udp := &layers.UDP{
SrcPort: srcPort,
DstPort: dstPort,
}
_ = udp.SetNetworkLayerForChecksum(ip)

return ethernet, ip, udp
}

// interfaceLabel returns a string label for the given AS and interface indices.
// Such names are those used when responding to the show-interfaces command and when translating
// the --interface option.
func interfaceLabel(AS int, intf int) string {
return fmt.Sprintf("%d_%d", AS, intf)
}

var (
// intfMap lists the required interfaces. That's what we use to respond to showInterfaces
intfMap map[string]intfDesc = map[string]intfDesc{
interfaceLabel(1, 0): {InternalIP(1, 1), InternalIP(1, 2)},
interfaceLabel(1, 2): {PublicIP(1, 2), PublicIP(2, 1)},
interfaceLabel(1, 3): {PublicIP(1, 3), PublicIP(3, 1)},
}

// deviceNames holds the real (os-given) names of our required network interfaces. It is
// created and populated from the values of the --interface options by InitInterfaces.
deviceNames map[string]string

// macAddresses keeps the mac addresses associated with each IP. It is created and populated
// from the values of the --interface options by InitInterfaces. There can be two items for each
// interface since we record the neighbor's addresses too. Additional IPs not from intfMap have
// no known mac addresses; we are free to make them up to make credible packets.
macAddrs map[netip.Addr]net.HardwareAddr
)

// InitInterfaces collects the names and mac addresses for the interfaces setup by the invoker
// according to instructions given via listInterfaces().
// This information is indexed by our own interface labels.
func InitInterfaces(pairs []string) {
deviceNames = make(map[string]string, len(pairs))
macAddrs = make(map[netip.Addr]net.HardwareAddr, len(pairs)*2)
for _, pair := range pairs {
p := strings.Split(pair, "=")
label := p[0]
info := strings.Split(p[1], ",")
addr, err := net.ParseMAC(info[1])
if err != nil {
panic(err)
}
peerAddr, err := net.ParseMAC(info[2])
if err != nil {
panic(err)
}
deviceNames[label] = info[0] // host-side name
macAddrs[intfMap[label].ip] = addr // ip->mac
macAddrs[intfMap[label].peerIP] = peerAddr // peerIP->peerMAC
}
}

// interfaceName returns the name of the host interface that this test must use in order to exchange
// traffic with the interface designated by the given AS and interface indices.
func DeviceName(AS int, intf int) string {
return deviceNames[interfaceLabel(AS, intf)]
}

// macAddr returns the mac address assigned to the interface that has the given IP address.
// if that address is imposed by our environment it is listed in the macAddrs map and that is what
// this function returns. Else, the address is made-up according to our scheme.
func MACAddr(ip netip.Addr) net.HardwareAddr {
// Look it up or make it up.
mac, ok := macAddrs[ip]
if ok {
return mac
}
as4 := ip.As4()
return net.HardwareAddr{0xde, 0xad, 0xbe, 0xef, as4[2], as4[3]}
}

// hostAddr returns a the SCION Hosts addresse that corresponds to the given underlay address.
// Except for SVC addresses (which we do not support here), this is a restating of the underlay
// address.
func HostAddr(ip netip.Addr) addr.Host {
return addr.HostIP(ip)
}

// ListInterfaces outputs a string describing the interfaces of the router under test.
// The invoker of this test gets this when using the show-interfaces command and is expected
// to set up the network accordingly before executing the test without that option.
// We do not choose interface names or mac addresses those will be provided by the invoker
// via the --interfaces options.
func ListInterfaces() string {
var sb strings.Builder
for l, i := range intfMap {
sb.WriteString(l)
sb.WriteString(",")
sb.WriteString("24")
sb.WriteString(",")
sb.WriteString(i.ip.String())
sb.WriteString(",")
sb.WriteString(i.peerIP.String())
sb.WriteString("\n")
}
// "our_label,24,<ip on router side>,<ip on far side>\n"

return sb.String()
}
14 changes: 14 additions & 0 deletions acceptance/router_benchmark/conf/br.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[general]
id = "br1a"
config_dir = "/share/conf"

[metrics]
prometheus = "192.168.10.1:30442"

[features]

[api]
addr = "192.168.10.1:31142"

[log.console]
level = "error"
1 change: 1 addition & 0 deletions acceptance/router_benchmark/conf/keys/master0.key
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
V9SOOHqV4KdAL6utGnvEtA==
1 change: 1 addition & 0 deletions acceptance/router_benchmark/conf/keys/master1.key
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mdPcnujoYi4JmWALGeKbSQ==
10 changes: 10 additions & 0 deletions acceptance/router_benchmark/conf/prometheus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
global:
evaluation_interval: 1s
external_labels:
monitor: scion-monitor
scrape_interval: 1s
scrape_configs:
- job_name: BR
static_configs:
- targets:
- 192.168.10.1:30442
46 changes: 46 additions & 0 deletions acceptance/router_benchmark/conf/topology.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"attributes": [
"core"
],
"isd_as": "1-ff00:0:1",
"mtu": 1400,
"border_routers": {
"br1a": {
"internal_addr": "192.168.10.1:30042",
"interfaces": {
"2": {
"underlay": {
"public": "192.168.2.1:50000",
"remote": "192.168.2.2:50000"
},
"isd_as": "1-ff00:0:2",
"link_to": "child",
"mtu": 1280
},
"3": {
"underlay": {
"public": "192.168.3.1:50000",
"remote": "192.168.3.3:50000"
},
"isd_as": "1-ff00:0:3",
"link_to": "child",
"mtu": 1280
}
}
},
"br1b": {
"internal_addr": "192.168.10.2:30042",
"interfaces": {
"4": {
"underlay": {
"public": "192.168.4.1:50000",
"remote": "192.168.4.4:50000"
},
"isd_as": "2-ff00:0:4",
"link_to": "core",
"mtu": 1280
}
}
}
}
}
552 changes: 552 additions & 0 deletions acceptance/router_benchmark/test.py

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions acceptance/sig_short_exp_time/test
Original file line number Diff line number Diff line change
@@ -55,24 +55,24 @@ run_test() {(set -e
docker image load -i acceptance/sig_short_exp_time/sig1.tar
docker image load -i acceptance/sig_short_exp_time/sig2.tar

docker compose --compatibility -f acceptance/sig_short_exp_time/docker-compose.yml up -d dispatcher1 dispatcher2 sig1 sig2 patha pathb
docker compose -f acceptance/sig_short_exp_time/docker-compose.yml up -d dispatcher1 dispatcher2 sig1 sig2 patha pathb

# Set up forward route on network stack 1 and 2 through the sig tunnel
# device. The route is a property of the network stack, and persists after
# the container that added it has exited.
#
# If the route configuration fails, the test is not stopped.
docker compose --compatibility -f acceptance/sig_short_exp_time/docker-compose.yml run --name route1 --rm tester1 ip route add 242.254.200.2/32 dev sig || true
docker compose --compatibility -f acceptance/sig_short_exp_time/docker-compose.yml run --name route2 --rm tester2 ip route add 242.254.100.2/32 dev sig || true
docker compose -f acceptance/sig_short_exp_time/docker-compose.yml run --name route1 --rm tester1 ip route add 242.254.200.2/32 dev sig || true
docker compose -f acceptance/sig_short_exp_time/docker-compose.yml run --name route2 --rm tester2 ip route add 242.254.100.2/32 dev sig || true

echo "Start background ping, ping every 0.2 seconds"
docker compose --compatibility -f acceptance/sig_short_exp_time/docker-compose.yml run --name tester1 -d tester1 ping -i 0.2 242.254.200.2
docker compose -f acceptance/sig_short_exp_time/docker-compose.yml run --name tester1 -d tester1 ping -i 0.2 242.254.200.2

echo "Waiting 10 seconds for path A to expire..."
sleep 10
echo "Path A expired, simulating it by shutting down path A proxy"
# Traffic should have switched beforehand to path b, and no pings should be lost
docker compose --compatibility -f acceptance/sig_short_exp_time/docker-compose.yml stop patha
docker compose -f acceptance/sig_short_exp_time/docker-compose.yml stop patha
sleep 1
docker kill -s SIGINT tester1

@@ -104,9 +104,9 @@ OUTPUT_DIR=$TEST_UNDECLARED_OUTPUTS_DIR
mkdir -p $OUTPUT_DIR/logs

for CNTR in sig1 sig2 dispatcher1 dispatcher2; do
docker compose --compatibility -f acceptance/sig_short_exp_time/docker-compose.yml logs "$CNTR" > "$OUTPUT_DIR/logs/$CNTR.log"
docker compose -f acceptance/sig_short_exp_time/docker-compose.yml logs "$CNTR" > "$OUTPUT_DIR/logs/$CNTR.log"
done

docker compose --compatibility -f acceptance/sig_short_exp_time/docker-compose.yml down -v
docker compose -f acceptance/sig_short_exp_time/docker-compose.yml down -v

exit $RC
2 changes: 0 additions & 2 deletions acceptance/topo_cs_reload/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -8,15 +8,13 @@ networks:
- subnet: 242.253.100.0/24
services:
topo_cs_reload_dispatcher:
container_name: topo_cs_reload_dispatcher
image: bazel/acceptance/topo_cs_reload:dispatcher
networks:
bridge1:
ipv4_address: 242.253.100.2
volumes:
- vol_topo_cs_reload_disp:/run/shm/dispatcher:rw
topo_cs_reload_control_srv:
container_name: topo_cs_reload_control_srv
image: bazel/acceptance/topo_cs_reload:control
depends_on:
- topo_cs_reload_dispatcher
18 changes: 7 additions & 11 deletions acceptance/topo_cs_reload/reload_test.go
Original file line number Diff line number Diff line change
@@ -100,27 +100,23 @@ func setupTest(t *testing.T) testState {
require.NoError(t, err)
topoFile, err := bazel.Runfile(*topoLocation)
require.NoError(t, err)
s.mustExec(t, *genCryptoLocation, scionPKI,
"crypto.tar", topoFile, cryptoLib)
s.mustExec(t, *genCryptoLocation, scionPKI, "crypto.tar", topoFile, cryptoLib)
s.mustExec(t, "tar", "-xf", "crypto.tar", "-C", tmpDir)
// first load the docker images from bazel into the docker deamon, the
// tars are in the same folder as this test runs in bazel.
s.mustExec(t, "docker", "image", "load", "-i", "dispatcher.tar")
s.mustExec(t, "docker", "image", "load", "-i", "control.tar")
// now start the docker containers
s.mustExec(t, "docker", "compose", "--compatibility", "-f", "docker-compose.yml",
"up", "-d")
s.mustExec(t, "docker", "compose", "-f", "docker-compose.yml", "up", "-d")
// wait a bit to make sure the containers are ready.
time.Sleep(time.Second / 2)
t.Log("Test setup done")
s.mustExec(t, "docker", "compose", "--compatibility", "-f", "docker-compose.yml",
"ps")
s.mustExec(t, "docker", "compose", "-f", "docker-compose.yml", "ps")
return s
}

func (s testState) teardownTest(t *testing.T) {
defer s.mustExec(t, "docker", "compose", "--compatibility",
"-f", "docker-compose.yml", "down", "-v")
defer s.mustExec(t, "docker", "compose", "-f", "docker-compose.yml", "down", "-v")

outdir, exists := os.LookupEnv("TEST_UNDECLARED_OUTPUTS_DIR")
require.True(t, exists, "TEST_UNDECLARED_OUTPUTS_DIR must be defined")
@@ -130,7 +126,7 @@ func (s testState) teardownTest(t *testing.T) {
"topo_cs_reload_dispatcher": "disp.log",
"topo_cs_reload_control_srv": "control.log",
} {
cmd := exec.Command("docker", "compose", "--compatibility",
cmd := exec.Command("docker", "compose",
"-f", "docker-compose.yml", "logs", "--no-color", service)
logFileName := fmt.Sprintf("%s/logs/%s", outdir, file)
logFile, err := os.Create(logFileName)
@@ -149,9 +145,9 @@ func (s testState) teardownTest(t *testing.T) {
func (s testState) loadTopo(t *testing.T, name string) {
t.Helper()

s.mustExec(t, "docker", "compose", "--compatibility", "-f", "docker-compose.yml",
s.mustExec(t, "docker", "compose", "-f", "docker-compose.yml",
"exec", "-T", "topo_cs_reload_control_srv", "mv", name, "/topology.json")
s.mustExec(t, "docker", "compose", "--compatibility", "-f", "docker-compose.yml",
s.mustExec(t, "docker", "compose", "-f", "docker-compose.yml",
"kill", "-s", "SIGHUP", "topo_cs_reload_control_srv")
}

13 changes: 6 additions & 7 deletions acceptance/topo_daemon_reload/reload_test.go
Original file line number Diff line number Diff line change
@@ -71,18 +71,17 @@ func setupTest(t *testing.T) {
mustExec(t, "docker", "image", "load", "-i", "dispatcher.tar")
mustExec(t, "docker", "image", "load", "-i", "daemon.tar")
// now start the docker containers
mustExec(t, "docker", "compose", "--compatibility", "-f", "docker-compose.yml",
mustExec(t, "docker", "compose", "-f", "docker-compose.yml",
"up", "-d", "topo_daemon_reload_dispatcher", "topo_daemon_reload_daemon")
// wait a bit to make sure the containers are ready.
time.Sleep(time.Second / 2)
t.Log("Test setup done")
mustExec(t, "docker", "compose", "--compatibility", "-f", "docker-compose.yml",
mustExec(t, "docker", "compose", "-f", "docker-compose.yml",
"ps")
}

func teardownTest(t *testing.T) {
defer mustExec(t, "docker", "compose", "--compatibility",
"-f", "docker-compose.yml", "down", "-v")
defer mustExec(t, "docker", "compose", "-f", "docker-compose.yml", "down", "-v")

outdir, exists := os.LookupEnv("TEST_UNDECLARED_OUTPUTS_DIR")
require.True(t, exists, "TEST_UNDECLARED_OUTPUTS_DIR must be defined")
@@ -92,7 +91,7 @@ func teardownTest(t *testing.T) {
"topo_daemon_reload_dispatcher": "disp.log",
"topo_daemon_reload_daemon": "daemon.log",
} {
cmd := exec.Command("docker", "compose", "--compatibility",
cmd := exec.Command("docker", "compose",
"-f", "docker-compose.yml", "logs", "--no-color",
service)
logFileName := fmt.Sprintf("%s/logs/%s", outdir, file)
@@ -111,9 +110,9 @@ func teardownTest(t *testing.T) {
func loadTopo(t *testing.T, name string) {
t.Helper()

mustExec(t, "docker", "compose", "--compatibility", "-f", "docker-compose.yml",
mustExec(t, "docker", "compose", "-f", "docker-compose.yml",
"exec", "-T", "topo_daemon_reload_daemon", "mv", name, "/topology.json")
mustExec(t, "docker", "compose", "--compatibility", "-f", "docker-compose.yml",
mustExec(t, "docker", "compose", "-f", "docker-compose.yml",
"kill", "-s", "SIGHUP", "topo_daemon_reload_daemon")
}

2 changes: 1 addition & 1 deletion acceptance/trc_update/test.py
Original file line number Diff line number Diff line change
@@ -72,7 +72,7 @@ def _run(self):
end2end["-d", "-outDir", artifacts].run_fg()

logger.info('==> Shutting down control servers and purging caches')
cs_services = self.dc.list_containers(".*_cs.*")
cs_services = self.dc.list_containers("cs.*")
for cs in cs_services:
self.dc.stop_container(cs)

1 change: 1 addition & 0 deletions bazel-remote.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
version: "2.4"
name: bazel_remote
services:
bazel-remote:
container_name: bazel-remote-cache
2 changes: 1 addition & 1 deletion control/beaconing/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ go_library(
"//pkg/private/prom:go_default_library",
"//pkg/private/serrors:go_default_library",
"//pkg/private/util:go_default_library",
"//pkg/proto/crypto:go_default_library",
"//pkg/segment:go_default_library",
"//pkg/segment/extensions/digest:go_default_library",
"//pkg/segment/extensions/epic:go_default_library",
@@ -37,7 +38,6 @@ go_library(
"//private/segment/verifier:go_default_library",
"//private/topology:go_default_library",
"//private/tracing:go_default_library",
"//private/trust:go_default_library",
"@com_github_opentracing_opentracing_go//:go_default_library",
],
)
21 changes: 16 additions & 5 deletions control/beaconing/extender.go
Original file line number Diff line number Diff line change
@@ -26,17 +26,28 @@ import (
"github.com/scionproto/scion/pkg/metrics"
"github.com/scionproto/scion/pkg/private/serrors"
"github.com/scionproto/scion/pkg/private/util"
cryptopb "github.com/scionproto/scion/pkg/proto/crypto"
seg "github.com/scionproto/scion/pkg/segment"
"github.com/scionproto/scion/pkg/segment/extensions/digest"
"github.com/scionproto/scion/pkg/segment/extensions/epic"
"github.com/scionproto/scion/pkg/slayers/path"
"github.com/scionproto/scion/private/trust"
)

// SignerGen generates signers and returns their expiration time.
type SignerGen interface {
// Generate generates a signer it.
Generate(ctx context.Context) (trust.Signer, error)
Generate(ctx context.Context) (Signer, error)
}

type Signer interface {
Sign(context.Context, []byte, ...[]byte) (*cryptopb.SignedMessage, error)
GetExpiration() time.Time
}

type SignerGenFunc func(ctx context.Context) (Signer, error)

func (f SignerGenFunc) Generate(ctx context.Context) (Signer, error) {
return f(ctx)
}

// Extender extends path segments.
@@ -104,14 +115,14 @@ func (s *DefaultExtender) Extend(
}
// Make sure the hop expiration time is not longer than the signer expiration time.
expTime := s.MaxExpTime()
if ts.Add(path.ExpTimeToDuration(expTime)).After(signer.Expiration) {
if ts.Add(path.ExpTimeToDuration(expTime)).After(signer.GetExpiration()) {
metrics.GaugeSet(s.SegmentExpirationDeficient, 1)
var err error
expTime, err = path.ExpTimeFromDuration(signer.Expiration.Sub(ts))
expTime, err = path.ExpTimeFromDuration(signer.GetExpiration().Sub(ts))
if err != nil {
return serrors.WrapStr(
"calculating expiry time from signer expiration time", err,
"signer_expiration", signer.Expiration,
"signer_expiration", signer.GetExpiration(),
)
}
} else {
82 changes: 70 additions & 12 deletions control/beaconing/staticinfo_config.go
Original file line number Diff line number Diff line change
@@ -38,6 +38,11 @@ type InterfaceBandwidths struct {
Intra map[common.IFIDType]uint64 `json:"Intra"`
}

type InterfaceCarbonIntensities struct {
Inter uint64 `json:"Inter"`
Intra map[common.IFIDType]uint64 `json:"Intra"`
}

type InterfaceGeodata struct {
Longitude float32 `json:"Longitude"`
Latitude float32 `json:"Latitude"`
@@ -79,12 +84,13 @@ func (l *LinkType) UnmarshalText(text []byte) error {

// StaticInfoCfg is used to parse data from config.json.
type StaticInfoCfg struct {
Latency map[common.IFIDType]InterfaceLatencies `json:"Latency"`
Bandwidth map[common.IFIDType]InterfaceBandwidths `json:"Bandwidth"`
LinkType map[common.IFIDType]LinkType `json:"LinkType"`
Geo map[common.IFIDType]InterfaceGeodata `json:"Geo"`
Hops map[common.IFIDType]InterfaceHops `json:"Hops"`
Note string `json:"Note"`
Latency map[common.IFIDType]InterfaceLatencies `json:"Latency"`
Bandwidth map[common.IFIDType]InterfaceBandwidths `json:"Bandwidth"`
CarbonIntensity map[common.IFIDType]InterfaceCarbonIntensities `json:"CarbonIntensity"`
LinkType map[common.IFIDType]LinkType `json:"LinkType"`
Geo map[common.IFIDType]InterfaceGeodata `json:"Geo"`
Hops map[common.IFIDType]InterfaceHops `json:"Hops"`
Note string `json:"Note"`
}

// ParseStaticInfoCfg parses data from a config file into a StaticInfoCfg struct.
@@ -120,6 +126,10 @@ func (cfg *StaticInfoCfg) clean() {
for _, s := range cfg.Bandwidth {
delete(s.Intra, 0)
}
delete(cfg.CarbonIntensity, 0)
for _, s := range cfg.CarbonIntensity {
delete(s.Intra, 0)
}
delete(cfg.LinkType, 0)
delete(cfg.Geo, 0)
delete(cfg.Hops, 0)
@@ -129,6 +139,7 @@ func (cfg *StaticInfoCfg) clean() {

symmetrizeLatency(cfg.Latency)
symmetrizeBandwidth(cfg.Bandwidth)
symmetrizeCarbonIntensity(cfg.CarbonIntensity)
symmetrizeHops(cfg.Hops)
}

@@ -178,6 +189,29 @@ func symmetrizeBandwidth(bandwidth map[common.IFIDType]InterfaceBandwidths) {
}
}

// symmetrizeCarbonIntensity makes the Intra carbon intensity values symmetric
func symmetrizeCarbonIntensity(carbonIntensity map[common.IFIDType]InterfaceCarbonIntensities) {
for i, sub := range carbonIntensity {
delete(sub.Intra, i) // Remove loopy entry
for j, v := range sub.Intra {
if _, ok := carbonIntensity[j]; !ok {
continue
}
if carbonIntensity[j].Intra == nil {
carbonIntensity[j] = InterfaceCarbonIntensities{
Inter: carbonIntensity[j].Inter,
Intra: make(map[common.IFIDType]uint64),
}
}
vTransposed, ok := carbonIntensity[j].Intra[i]
// Set if not specified or pick more conservative value if both are specified
if !ok || v < vTransposed {
carbonIntensity[j].Intra[i] = v
}
}
}
}

// symmetrizeHops makes the Intra hops values symmetric
func symmetrizeHops(hops map[common.IFIDType]InterfaceHops) {
for i, sub := range hops {
@@ -210,12 +244,13 @@ func (cfg StaticInfoCfg) generate(ifType map[common.IFIDType]topology.LinkType,
ingress, egress common.IFIDType) *staticinfo.Extension {

return &staticinfo.Extension{
Latency: cfg.generateLatency(ifType, ingress, egress),
Bandwidth: cfg.generateBandwidth(ifType, ingress, egress),
Geo: cfg.generateGeo(ifType, ingress, egress),
LinkType: cfg.generateLinkType(ifType, egress),
InternalHops: cfg.generateInternalHops(ifType, ingress, egress),
Note: cfg.Note,
Latency: cfg.generateLatency(ifType, ingress, egress),
Bandwidth: cfg.generateBandwidth(ifType, ingress, egress),
CarbonIntensity: cfg.generateCarbonIntensity(ifType, ingress, egress),
Geo: cfg.generateGeo(ifType, ingress, egress),
LinkType: cfg.generateLinkType(ifType, egress),
InternalHops: cfg.generateInternalHops(ifType, ingress, egress),
Note: cfg.Note,
}
}

@@ -265,6 +300,29 @@ func (cfg StaticInfoCfg) generateBandwidth(ifType map[common.IFIDType]topology.L
return bw
}

// generateCarbonIntensity creates the BandwidthInfo by extracting the relevant values
// from the config.
func (cfg StaticInfoCfg) generateCarbonIntensity(ifType map[common.IFIDType]topology.LinkType,
ingress, egress common.IFIDType) staticinfo.CarbonIntensityInfo {

ci := staticinfo.CarbonIntensityInfo{
Intra: make(map[common.IFIDType]uint64),
Inter: make(map[common.IFIDType]uint64),
}
for ifid, v := range cfg.CarbonIntensity[egress].Intra {
if includeIntraInfo(ifType, ifid, ingress, egress) {
ci.Intra[ifid] = v
}
}
for ifid, v := range cfg.CarbonIntensity {
t := ifType[ifid]
if ifid == egress || t == topology.Peer {
ci.Inter[ifid] = v.Inter
}
}
return ci
}

// generateLinkType creates the LinkTypeInfo by extracting the relevant values from
// the config.
func (cfg StaticInfoCfg) generateLinkType(ifType map[common.IFIDType]topology.LinkType,
74 changes: 74 additions & 0 deletions control/beaconing/staticinfo_config_test.go
Original file line number Diff line number Diff line change
@@ -50,6 +50,10 @@ const (
bandwidth_inter_3 uint64 = 80
bandwidth_inter_5 uint64 = 120

carbon_intensity_intra_1_2 uint64 = 300
carbon_intensity_inter_1 uint64 = 780
carbon_intensity_inter_2 uint64 = 400

link_type_1 staticinfo.LinkType = staticinfo.LinkTypeDirect
link_type_2 staticinfo.LinkType = staticinfo.LinkTypeOpennet
link_type_3 staticinfo.LinkType = staticinfo.LinkTypeMultihop
@@ -163,6 +167,20 @@ func getTestConfigData() *beaconing.StaticInfoCfg {
},
},
},
CarbonIntensity: map[common.IFIDType]beaconing.InterfaceCarbonIntensities{
1: {
Inter: carbon_intensity_inter_1,
Intra: map[common.IFIDType]uint64{
2: carbon_intensity_intra_1_2,
},
},
2: {
Inter: carbon_intensity_inter_2,
Intra: map[common.IFIDType]uint64{
1: carbon_intensity_intra_1_2,
},
},
},
LinkType: map[common.IFIDType]beaconing.LinkType{
1: beaconing.LinkType(link_type_1),
2: beaconing.LinkType(link_type_2),
@@ -270,6 +288,14 @@ func TestGenerateStaticInfo(t *testing.T) {
5: bandwidth_inter_5,
},
},
CarbonIntensity: staticinfo.CarbonIntensityInfo{
Intra: map[common.IFIDType]uint64{
2: carbon_intensity_intra_1_2,
},
Inter: map[common.IFIDType]uint64{
1: carbon_intensity_inter_1,
},
},
Geo: staticinfo.GeoInfo{
1: geo_1,
3: geo_3,
@@ -313,6 +339,12 @@ func TestGenerateStaticInfo(t *testing.T) {
5: bandwidth_inter_5,
},
},
CarbonIntensity: staticinfo.CarbonIntensityInfo{
Intra: map[common.IFIDType]uint64{},
Inter: map[common.IFIDType]uint64{
2: carbon_intensity_inter_2,
},
},
Geo: staticinfo.GeoInfo{
2: geo_2,
3: geo_3,
@@ -347,6 +379,10 @@ func TestGenerateStaticInfo(t *testing.T) {
5: bandwidth_inter_5,
},
},
CarbonIntensity: staticinfo.CarbonIntensityInfo{
Intra: map[common.IFIDType]uint64{},
Inter: map[common.IFIDType]uint64{},
},
Geo: staticinfo.GeoInfo{
3: geo_3,
5: geo_5,
@@ -384,6 +420,14 @@ func TestGenerateStaticInfo(t *testing.T) {
5: bandwidth_inter_5,
},
},
CarbonIntensity: staticinfo.CarbonIntensityInfo{
Intra: map[common.IFIDType]uint64{
2: carbon_intensity_intra_1_2,
},
Inter: map[common.IFIDType]uint64{
1: carbon_intensity_inter_1,
},
},
Geo: staticinfo.GeoInfo{
1: geo_1,
5: geo_5,
@@ -423,6 +467,12 @@ func TestGenerateStaticInfo(t *testing.T) {
5: bandwidth_inter_5,
},
},
CarbonIntensity: staticinfo.CarbonIntensityInfo{
Intra: map[common.IFIDType]uint64{},
Inter: map[common.IFIDType]uint64{
2: carbon_intensity_inter_2,
},
},
Geo: staticinfo.GeoInfo{
2: geo_2,
5: geo_5,
@@ -463,6 +513,14 @@ func TestGenerateStaticInfo(t *testing.T) {
2: bandwidth_inter_2,
},
},
CarbonIntensity: staticinfo.CarbonIntensityInfo{
Intra: map[common.IFIDType]uint64{
1: carbon_intensity_intra_1_2,
},
Inter: map[common.IFIDType]uint64{
2: carbon_intensity_inter_2,
},
},
Geo: staticinfo.GeoInfo{
2: geo_2,
},
@@ -495,6 +553,12 @@ func TestGenerateStaticInfo(t *testing.T) {
1: bandwidth_inter_1,
},
},
CarbonIntensity: staticinfo.CarbonIntensityInfo{
Intra: map[common.IFIDType]uint64{},
Inter: map[common.IFIDType]uint64{
1: carbon_intensity_inter_1,
},
},
Geo: staticinfo.GeoInfo{
1: geo_1,
},
@@ -527,6 +591,12 @@ func TestGenerateStaticInfo(t *testing.T) {
1: bandwidth_inter_1,
},
},
CarbonIntensity: staticinfo.CarbonIntensityInfo{
Intra: map[common.IFIDType]uint64{},
Inter: map[common.IFIDType]uint64{
1: carbon_intensity_inter_1,
},
},
Geo: staticinfo.GeoInfo{
1: geo_1,
3: geo_3,
@@ -554,6 +624,10 @@ func TestGenerateStaticInfo(t *testing.T) {
Intra: map[common.IFIDType]uint64{},
Inter: map[common.IFIDType]uint64{},
},
CarbonIntensity: staticinfo.CarbonIntensityInfo{
Intra: map[common.IFIDType]uint64{},
Inter: map[common.IFIDType]uint64{},
},
Geo: staticinfo.GeoInfo{
3: geo_3,
},
11 changes: 11 additions & 0 deletions control/beaconing/testdata/testconfigfile.json
Original file line number Diff line number Diff line change
@@ -60,6 +60,17 @@
"Inter": 120
}
},
"CarbonIntensity": {
"1": {
"Inter": 780,
"Intra": {
"2": 300
}
},
"2": {
"Inter": 400
}
},
"Linktype": {
"1":"direct",
"2":"opennet",
2 changes: 1 addition & 1 deletion control/beaconing/writer_test.go
Original file line number Diff line number Diff line change
@@ -349,7 +349,7 @@ type testSignerGen struct {
Signer trust.Signer
}

func (s testSignerGen) Generate(ctx context.Context) (trust.Signer, error) {
func (s testSignerGen) Generate(ctx context.Context) (beaconing.Signer, error) {
return s.Signer, nil
}

22 changes: 14 additions & 8 deletions control/cmd/control/main.go
Original file line number Diff line number Diff line change
@@ -315,8 +315,12 @@ func realMain(ctx context.Context) error {
quicServer := grpc.NewServer(
grpc.Creds(libgrpc.PassThroughCredentials{}),
libgrpc.UnaryServerInterceptor(),
libgrpc.DefaultMaxConcurrentStreams(),
)
tcpServer := grpc.NewServer(
libgrpc.UnaryServerInterceptor(),
libgrpc.DefaultMaxConcurrentStreams(),
)
tcpServer := grpc.NewServer(libgrpc.UnaryServerInterceptor())

// Register trust material related handlers.
trustServer := &cstrustgrpc.MaterialServer{
@@ -776,13 +780,15 @@ func realMain(ctx context.Context) error {
},
SegmentRegister: beaconinggrpc.Registrar{Dialer: dialer},
BeaconStore: beaconStore,
SignerGen: signer.SignerGen,
Inspector: inspector,
Metrics: metrics,
DRKeyEngine: drkeyEngine,
MACGen: macGen,
NextHopper: topo,
StaticInfo: func() *beaconing.StaticInfoCfg { return staticInfo },
SignerGen: beaconing.SignerGenFunc(func(ctx context.Context) (beaconing.Signer, error) {
return signer.SignerGen.Generate(ctx)
}),
Inspector: inspector,
Metrics: metrics,
DRKeyEngine: drkeyEngine,
MACGen: macGen,
NextHopper: topo,
StaticInfo: func() *beaconing.StaticInfoCfg { return staticInfo },

OriginationInterval: globalCfg.BS.OriginationInterval.Duration,
PropagationInterval: globalCfg.BS.PropagationInterval.Duration,
7 changes: 3 additions & 4 deletions control/mgmtapi/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
load("//tools/lint:go.bzl", "go_library", "go_test")
load("@com_github_scionproto_scion//rules_openapi:defs.bzl", "openapi_build_docs", "openapi_generate_go")
load("//private/mgmtapi:api.bzl", "openapi_docs", "openapi_generate_go")

openapi_build_docs(
openapi_docs(
name = "doc",
src = "//spec:control",
out = "index.html",
@@ -42,10 +42,9 @@ go_library(
"//private/mgmtapi/segments/api:go_default_library",
"//private/storage:go_default_library",
"//private/storage/beacon:go_default_library",
"@com_github_deepmap_oapi_codegen//pkg/runtime:go_default_library", # keep
"@com_github_getkin_kin_openapi//openapi3:go_default_library", # keep
"@com_github_go_chi_chi_v5//:go_default_library", # keep
"@com_github_pkg_errors//:go_default_library", # keep
"@com_github_oapi_codegen_runtime//:go_default_library", # keep
"@org_golang_google_protobuf//proto:go_default_library",
],
)
506 changes: 257 additions & 249 deletions control/mgmtapi/client.gen.go

Large diffs are not rendered by default.

224 changes: 177 additions & 47 deletions control/mgmtapi/server.gen.go

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions control/mgmtapi/spec.gen.go
5 changes: 4 additions & 1 deletion daemon/cmd/daemon/main.go
Original file line number Diff line number Diff line change
@@ -251,7 +251,10 @@ func realMain(ctx context.Context) error {
}}
}

server := grpc.NewServer(libgrpc.UnaryServerInterceptor())
server := grpc.NewServer(
libgrpc.UnaryServerInterceptor(),
libgrpc.DefaultMaxConcurrentStreams(),
)
sdpb.RegisterDaemonServiceServer(server, daemon.NewServer(
daemon.ServerConfig{
IA: topo.IA(),
30 changes: 20 additions & 10 deletions daemon/internal/servers/grpc.go
Original file line number Diff line number Diff line change
@@ -174,16 +174,17 @@ func pathToPB(path snet.Path) *sdpb.Path {
Interface: &sdpb.Interface{
Address: &sdpb.Underlay{Address: nextHopStr},
},
Interfaces: interfaces,
Mtu: uint32(meta.MTU),
Expiration: &timestamppb.Timestamp{Seconds: meta.Expiry.Unix()},
Latency: latency,
Bandwidth: meta.Bandwidth,
Geo: geo,
LinkType: linkType,
InternalHops: meta.InternalHops,
Notes: meta.Notes,
EpicAuths: epicAuths,
Interfaces: interfaces,
Mtu: uint32(meta.MTU),
Expiration: &timestamppb.Timestamp{Seconds: meta.Expiry.Unix()},
Latency: latency,
Bandwidth: meta.Bandwidth,
CarbonIntensity: meta.CarbonIntensity,
Geo: geo,
LinkType: linkType,
InternalHops: meta.InternalHops,
Notes: meta.Notes,
EpicAuths: epicAuths,
}

}
@@ -356,6 +357,9 @@ func (s *DaemonServer) DRKeyASHost(
req *pb_daemon.DRKeyASHostRequest,
) (*pb_daemon.DRKeyASHostResponse, error) {

if s.DRKeyClient == nil {
return nil, serrors.New("DRKey is not available")
}
meta, err := requestToASHostMeta(req)
if err != nil {
return nil, serrors.WrapStr("parsing protobuf ASHostReq", err)
@@ -378,6 +382,9 @@ func (s *DaemonServer) DRKeyHostAS(
req *pb_daemon.DRKeyHostASRequest,
) (*pb_daemon.DRKeyHostASResponse, error) {

if s.DRKeyClient == nil {
return nil, serrors.New("DRKey is not available")
}
meta, err := requestToHostASMeta(req)
if err != nil {
return nil, serrors.WrapStr("parsing protobuf HostASReq", err)
@@ -400,6 +407,9 @@ func (s *DaemonServer) DRKeyHostHost(
req *pb_daemon.DRKeyHostHostRequest,
) (*pb_daemon.DRKeyHostHostResponse, error) {

if s.DRKeyClient == nil {
return nil, serrors.New("DRKey is not available")
}
meta, err := requestToHostHostMeta(req)
if err != nil {
return nil, serrors.WrapStr("parsing protobuf HostHostReq", err)
6 changes: 3 additions & 3 deletions daemon/mgmtapi/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
load("//tools/lint:go.bzl", "go_library")
load("@com_github_scionproto_scion//rules_openapi:defs.bzl", "openapi_build_docs", "openapi_generate_go")
load("//private/mgmtapi:api.bzl", "openapi_docs", "openapi_generate_go")

openapi_build_docs(
openapi_docs(
name = "doc",
src = "//spec:daemon",
out = "index.html",
@@ -32,8 +32,8 @@ go_library(
"//private/mgmtapi:go_default_library",
"//private/mgmtapi/cppki/api:go_default_library",
"//private/mgmtapi/segments/api:go_default_library",
"@com_github_deepmap_oapi_codegen//pkg/runtime:go_default_library", # keep
"@com_github_getkin_kin_openapi//openapi3:go_default_library", # keep
"@com_github_go_chi_chi_v5//:go_default_library", # keep
"@com_github_oapi_codegen_runtime//:go_default_library", # keep
],
)
288 changes: 147 additions & 141 deletions daemon/mgmtapi/client.gen.go

Large diffs are not rendered by default.

144 changes: 113 additions & 31 deletions daemon/mgmtapi/server.gen.go
12 changes: 6 additions & 6 deletions daemon/mgmtapi/spec.gen.go
9 changes: 4 additions & 5 deletions demo/drkey/test.py
Original file line number Diff line number Diff line change
@@ -71,7 +71,7 @@ def setup_prepare(self):
# Enable delegation for tester host on the fast side (server side), i.e.
# allow the tester host to directly request the secret value from which
# keys can be derived locally for any host.
tester_ip = self._container_ip("scion_disp_tester_%s" % self.server_isd_as.file_fmt())
tester_ip = self._container_ip("disp_tester_%s" % self.server_isd_as.file_fmt())
cs_config = self._conf_dir(self.server_isd_as) // "cs*-1.toml"
scion.update_toml({"drkey.delegation.scmp": [tester_ip]}, cs_config)

@@ -82,9 +82,8 @@ def _run(self):

# install demo binary in tester containers:
drkey_demo = local["realpath"](self.get_executable("drkey-demo").executable).strip()
testers = ["tester_%s" % ia.file_fmt() for ia in {self.server_isd_as, self.client_isd_as}]
for tester in testers:
local["docker"]("cp", drkey_demo, tester + ":/bin/")
for ia in {self.server_isd_as, self.client_isd_as}:
self.dc("cp", drkey_demo, "tester_%s" % ia.file_fmt() + ":/bin/")

# Define DRKey protocol identifiers and derivation typ for test
for test in [
@@ -134,7 +133,7 @@ def _endhost_ip(self, isd_as: ISD_AS) -> str:
""" Determine the IP used for the end host (client or server) in the given ISD-AS """
# The address must be the daemon IP (as it makes requests to the control
# service on behalf of the end host application).
return self._container_ip("scion_sd%s" % isd_as.file_fmt())
return self._container_ip("sd%s" % isd_as.file_fmt())

def _container_ip(self, container: str) -> str:
""" Determine the IP of the container """
17 changes: 10 additions & 7 deletions demo/file_transfer/file_transfer.py
Original file line number Diff line number Diff line change
@@ -43,7 +43,7 @@ def _set_path_count(self, path_count):
with open(config_name, "w") as f:
json.dump(t, f, indent=2)
# Reload the config.
self.dc("kill", "-s", "SIGHUP", "scion_sig_1-ff00_0_111")
self.dc("kill", "-s", "SIGHUP", "sig_1-ff00_0_111")
# Give gateway some time to start using the new path count.
time.sleep(2)

@@ -66,11 +66,15 @@ def _get_br_traffic(self, endpoint):
conn.request('GET', '/metrics')
resp = conn.getresponse()
metrics = resp.read().decode('utf-8')
total = 0
regexp = re.compile(r"""^router_input_bytes_total{.*interface="internal".*\s(.*)$""")
for line in metrics.splitlines():
m = re.search(r"""^router_input_bytes_total{interface="internal".*\s(.*)$""", line)
if m is not None:
return float(m.group(1)) / 1024 / 1024
return None
try:
m = regexp.search(line)
total += float(m.group(1)) / 1024 / 1024
except (TypeError, AttributeError, ValueError):
pass
return total

def setup_prepare(self):
print("setting up the infrastructure")
@@ -82,7 +86,6 @@ def setup_prepare(self):
with open(scion_dc, "r") as file:
dc = yaml.load(file, Loader=yaml.FullLoader)
dc["services"]["tc_setup"] = {
"container_name": "tc_setup",
"image": "tester:latest",
"cap_add": ["NET_ADMIN"],
"volumes": [{
@@ -93,7 +96,7 @@ def setup_prepare(self):
"entrypoint": ["/bin/sh", "-exc",
"ls -l /share; /share/tc_setup.sh scn_000 16.0mbit ;"
" /share/tc_setup.sh scn_001 16.0mbit"],
"depends_on": ["scion_br1-ff00_0_111-1", "scion_br1-ff00_0_111-2"],
"depends_on": ["br1-ff00_0_111-1", "br1-ff00_0_111-2"],
"network_mode": "host",
}
with open(scion_dc, "w") as file:
4 changes: 2 additions & 2 deletions dispatcher/mgmtapi/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
load("//tools/lint:go.bzl", "go_library")
load("//rules_openapi:defs.bzl", "openapi_build_docs", "openapi_generate_go")
load("//private/mgmtapi:api.bzl", "openapi_docs", "openapi_generate_go")

openapi_build_docs(
openapi_docs(
name = "doc",
src = "//spec:dispatcher",
out = "index.html",
Loading