Type: Master's Thesis / Research Project
Research Group: NetSys Lab, Otto-von-Guericke University Magdeburg
Prerequisites: Go programming, basic networking (TCP/IP), QUIC basics helpful
SCION is a next-generation Internet architecture that gives end hosts explicit control over the paths their traffic takes. Unlike the traditional Internet, a SCION endpoint can enumerate all available paths to a destination, inspect their topology as sequences of border router interfaces, and switch between them dynamically. Each interface is globally identified by the composite string ISD-AS-Interface (e.g., 1-ff00:0:110-2), which is central to this project.
PANAPI is a path-aware networking stack for SCION inspired by the IETF TAPS proposal. It separates concerns into two layers:
Networking API (taps/) — An application-facing interface where developers express transport intent through Capacity Profiles and Multipath Policies rather than managing sockets directly:
p.SetProperty("multipathPolicy", "aggregate")
p.SetProperty("capacityProfile", "capacitySeeking")
Connection := p.Initiate()PANAPI Daemon (cmd/daemon/main.go) — A background service listening on a Unix socket (/tmp/panapid.sock). It exposes a Go RPC server with two main pluggable components:
-
Selector (
rpc.ServerSelector) — Chooses which path to use for each connection. Currently implemented aslua.LuaSelector(lua/selector.go), driven by a user-supplied Lua script. The selector's key callbacks areInitialize,Path,PathDown,Refresh, andPeriodic. -
Stats (
rpc.ServerConnectionTracer) — A QUIC connection tracer that receives per-connection events from the QUIC stack in real time. Currently implemented aslua.Stats(lua/stats.go). The key callbacks for this project are:UpdatedMetrics(local, remote, rttStats, cwnd, bytesInFlight, packetsInFlight)— fired on every QUIC CC update, provides RTT, congestion window, and in-flight byte countsLostPacket(local, remote, level, packetNumber, reason)— fired on every QUIC packet loss eventDroppedPacket(local, remote, type, size, reason)— fired on dropped packets
Both components receive pan.PathInterface objects (IA + IfID fields) that already encode the information needed for SCION interface IDs.
UMCC (Uncoupled Multipath Congestion Control) is a research multipath transport protocol implemented as the PARTS Go library (github.com/netsys-lab/parts). It features a Shared Bottleneck Detection (SBD) algorithm that:
- Collects per-path throughput (bytes/s) and packet loss (%) from metric packets sent by the receiver.
- Detects similarity: compares all pairs of events from different paths — two paths are flagged as sharing a bottleneck if their loss rates are within ±15 percentage points of each other (both ≥5%), or their throughput values are within 20% of each other.
- Localises the bottleneck: intersects the
ISD-AS-InterfaceID sets of all affected paths. - Refines: removes any interface that also appears in a healthy (unaffected) path.
- Reroutes: excludes paths traversing the identified interfaces from the active path set.
The relevant code lives in:
scheduler_sbd.go— similarity check (isInEpsilonRange,isWithinRelativePercent), event window, bottleneck localisation (sharedBottleneckDetection), and path filtering (filterPathsByBottlenecks)paths.go— interface ID generation (InterfacesToIds,InterfacesToIds→ISD-AS-Interfaceformat)
PANAPI's Selector currently chooses paths based on static path metadata (MTU, latency, bandwidth annotations from SCION's control plane) or simple heuristics implemented in a Lua script. It has no runtime awareness of shared bottlenecks: if two paths with the highest bandwidth both traverse the same congested link, PANAPI keeps both active while a healthier disjoint path goes unused. The application degrades on both paths instead of recovering.
UMCC solves this precisely, but its SBD algorithm is embedded in UMCC's own transport and scheduler. It currently cannot operate on top of QUIC, cannot be driven by PANAPI's QUIC-sourced metrics, and is not accessible to PANAPI's Lua selector.
The goal of this project is to extract UMCC's similarity detection and shared bottleneck localisation algorithm from PARTS and integrate it into PANAPI's daemon, so that any PANAPI application — regardless of transport protocol — can benefit from bottleneck-aware path selection.
-
Understand both systems in depth — PANAPI's RPC architecture (Selector, Stats, Lua bindings) and UMCC's SBD algorithm.
-
Extract a standalone
sbdpackage from PARTS containing:isInEpsilonRange/isWithinRelativePercent(similarity functions)- The sliding metric window and all-pairs similarity check
- The interface-intersection and refinement algorithm (
sharedBottleneckDetection,filterPathsByBottlenecks) - Clean, configurable parameters (no hardcoded constants)
-
Wire the
sbdpackage into PANAPI's Stats layer — On eachUpdatedMetricsandLostPacketcallback inlua/stats.go(Stats), feed per-path metric observations into the SBD analyser. Map QUIC metrics to UMCC-compatible inputs (see §4.2). -
Expose bottleneck state to the Selector — The SBD analyser should maintain a set of identified bottleneck interface IDs accessible to
lua/selector.go(LuaSelector). WhenPath()orRefresh()is called, paths whoseMetadata.Interfacesoverlap the bottleneck set should be deprioritised or excluded. -
Expose the bottleneck state to Lua — Surface the bottleneck interface set in the Lua environment so that Lua path-selection scripts can query it directly, keeping the system scriptable.
-
Evaluate on a SCION test topology with artificially induced bottlenecks.
Three pieces from PARTS can be extracted cleanly:
Similarity functions (currently in scheduler_sbd.go:34-56)
// Zero-safe absolute epsilon comparison for uint32
func IsInEpsilonRange(x, y, epsilon uint32) bool
// Relative percentage comparison (avoids scale dependence)
func IsWithinRelativePercent(a, b, pct uint32) boolSBDAnalyser — a new struct wrapping the event window and similarity check:
type PathObservation struct {
PathInterfaces []string // ISD-AS-Interface strings
PacketLoss uint32 // percentage 0–100
Throughput uint32 // bytes/s
}
type SBDAnalyser struct {
window []PathObservation
windowSize int
lossEpsilon uint32
throughputPct uint32
minLoss uint32
}
// Observe adds a new metric observation and returns the current bottleneck interface set.
func (a *SBDAnalyser) Observe(obs PathObservation) []stringBottleneck localisation (currently sharedBottleneckDetection and filterPathsByBottlenecks in scheduler_sbd.go) — operates only on []string interface ID slices; already has no UMCC-specific dependencies and can be moved as-is.
PANAPI's Stats layer (via QUIC connection tracing) provides raw events that must be mapped to per-path PacketLoss and Throughput estimates:
| PANAPI event | Available data | Maps to |
|---|---|---|
UpdatedMetrics |
bytesInFlight, cwnd, RTT stats, packetsInFlight |
Throughput estimate: bytesInFlight / SmoothedRTT |
LostPacket |
packet number, loss reason | Increment per-path loss counter |
AcknowledgedPacket |
packet number | Increment per-path acked counter |
Packet loss rate = lostPackets / (lostPackets + ackedPackets) over a rolling time window.
The path for each event is implicitly identified by the (local, remote) address pair. PANAPI maps connections to paths in the Selector; the Stats layer needs access to the current (local, remote) → path mapping to identify which pan.PathInterface list belongs to each event.
This mapping — connecting (local, remote) pairs in Stats to their path interface lists — is the main integration challenge and a key design decision for the student to resolve.
The SBD analyser should sit as a shared component between Stats and Selector inside the daemon:
QUIC stack
│ LostPacket / UpdatedMetrics
▼
lua.Stats (lua/stats.go)
│ feed observation
▼
SBDAnalyser.Observe(PathObservation)
│ returns bottleneck interface set
▼
shared state (e.g. *SBDAnalyser passed to both components)
│
├── lua.LuaSelector.Path() ← excludes paths with bottleneck interfaces
└── lua.LuaSelector.Refresh() ← re-ranks paths on bottleneck update
In cmd/daemon/main.go, a single SBDAnalyser instance is constructed and passed to both lua.NewStats and lua.NewSelector. The Lua selector's Path function queries analyser.BottleneckInterfaces() and filters accordingly.
The lua/selector.go already passes pan.PathInterface objects to Lua as {IA: string, IfID: number} tables. The integration should extend the panapi Lua module with a new function:
-- Returns a list of bottleneck interface IDs as strings (e.g. "1-ff00:0:110-2")
local bottlenecks = panapi.BottleneckInterfaces()This allows existing Lua path-selection scripts to be extended without modifying Go code, keeping PANAPI's scriptability intact.
Expose the SBD parameters as daemon flags or a config file:
| Parameter | Default | Description |
|---|---|---|
--sbd-loss-epsilon |
15 |
Max absolute loss difference (%) for similarity |
--sbd-min-loss |
5 |
Minimum loss (%) before a path is considered degraded |
--sbd-throughput-pct |
20 |
Max relative throughput difference (%) for similarity |
--sbd-window-size |
8 |
Number of recent observations to buffer per connection |
--sbd-clearance-delay |
TBD | Delay before removing a cleared bottleneck |
- Literature review — Shared bottleneck detection (RFC 8382, MPTCP coupled CC, UMCC), TAPS/PANAPI design, passive multipath measurement.
- Design document — Interface definitions, metric mapping rationale, integration point choices, Lua API extension.
- Standalone
sbdGo package — Extracted from PARTS, with unit tests covering similarity detection (true/false positives), bottleneck localisation, and path filtering. - PANAPI integration — Modified
lua/stats.go,lua/selector.go,lua/lua.go, andcmd/daemon/main.gowiring the SBD analyser into the daemon. - Example Lua script — A path-selection script that queries
panapi.BottleneckInterfaces()and avoids bottleneck paths. - Evaluation — Experiments on SCIONLab or a local SCION topology with artificial bottlenecks, measuring detection accuracy, detection latency, and throughput recovery.
- Thesis / Report — Full written documentation.
| File | Why it matters |
|---|---|
scheduler_sbd.go |
The SBD algorithm to extract |
paths.go |
Interface ID format (InterfacesToIds) |
events.go |
CongestionEvent data model |
controlplane.go |
How metrics flow from transport to scheduler |
| File | Why it matters |
|---|---|
cmd/daemon/main.go |
Daemon entry point — where components are wired together |
lua/stats.go |
Stats — receives all per-connection QUIC events; primary integration point |
lua/selector.go |
LuaSelector — calls the Lua script for path decisions; where bottleneck filtering goes |
lua/lua.go |
Shared Lua state; where new Lua API functions are registered |
rpc/selector.go |
ServerSelector interface — defines the Selector contract |
rpc/connection_tracer.go |
ServerConnectionTracer interface — defines the Stats contract |
taps/connection_preferences.go |
ConnectionPreferences — CapacityProfile and MultipathPolicy fields |
| Skill | Level |
|---|---|
| Go programming | Required |
| Computer networking (TCP/IP, congestion control) | Required |
| QUIC basics | Helpful |
| SCION basics | Helpful — can be learned during the project |
| Lua scripting | Helpful — only basic familiarity needed |
| Weeks | Milestone |
|---|---|
| 1–2 | Set up SCION environment; run PANAPI daemon and PARTS examples |
| 3–4 | Deep-dive: trace a complete path selection cycle in both codebases |
| 5–6 | Literature review; design document |
| 7–9 | Extract standalone sbd package with unit tests |
| 10–11 | Implement metric mapping (Stats → SBD observations) |
| 12–13 | Integrate SBD analyser into daemon; extend Lua API |
| 14–15 | Write example Lua selector script using bottleneck data |
| 16–18 | Evaluation on SCION topology |
| 19–20 | Write-up and revision |
- UMCC/PARTS:
github.com/netsys-lab/parts—scheduler_sbd.gofor the SBD algorithm - PANAPI: Thorben Krüger and David Hausheer, "PANAPI: A Path-Aware Networking API", NAI'21, August 2021. Code at
github.com/netsys-lab/panapi - SCION: Barrera et al., "SCION: A Secure Internet Architecture", Springer 2017
- Shared Bottleneck Detection: IETF RFC 8382 — "Shared Bottleneck Detection for Coupled Congestion Control for RTP Media"
- IETF TAPS: RFC 9622 — "An Abstract Application Layer Interface to Transport Services"
- MPTCP Coupled CC: Raiciu et al., RFC 6356 — "Coupled Congestion Control for Multipath Transport Protocols"
- Connection Racing: RFC 8305 — "Happy Eyeballs Version 2"