Prepare exersice experiments
This commit is contained in:
@@ -0,0 +1,477 @@
|
||||
# Computer Networks II — Declarative Mininet Topology Builder
|
||||
|
||||
This repository implements the programming assignment for Computer Networks II
|
||||
using a small declarative JSON topology language and a staged Python build
|
||||
pipeline.
|
||||
|
||||
The JSON describes the desired network rather than the exact Mininet commands
|
||||
used to create it.
|
||||
|
||||
The implementation loads that description, parses it into typed Python objects,
|
||||
validates its semantics, resolves all abstract interface selections into a
|
||||
concrete execution plan, renders executable Mininet Python, and then runs that
|
||||
generated artifact.
|
||||
|
||||
Start with [Quick start](#quick-start) to generate and run a topology.
|
||||
The [topology language overview](#topology-language) introduces the JSON format;
|
||||
the [JSON language reference](Mininet_DSL_Design.md)
|
||||
defines its fields, defaults, and semantic constraints.
|
||||
|
||||
## Project goals
|
||||
|
||||
The main goals of the implementation are:
|
||||
|
||||
- describe Mininet topologies declaratively in JSON,
|
||||
- keep topology intent separate from Mininet implementation details,
|
||||
- use typed Python objects throughout the processing pipeline,
|
||||
- detect grammar and semantic errors before changing the network,
|
||||
- generate an inspectable intermediate Python artifact,
|
||||
- execute exactly that generated artifact for normal runs,
|
||||
- keep runtime experiments separate from topology construction,
|
||||
- clean up services and Mininet state safely after the CLI exits.
|
||||
|
||||
The topology language is intentionally small.
|
||||
|
||||
Its core semantic entities are:
|
||||
|
||||
```text
|
||||
Node
|
||||
Interface
|
||||
Link
|
||||
Node Settings
|
||||
Service
|
||||
```
|
||||
|
||||
## Repository layout
|
||||
|
||||
```text
|
||||
source/
|
||||
build_network.py CLI coordinator and environment checks
|
||||
topology_loader.py JSON loading
|
||||
topology_parser.py Strict parsing and typed semantic model
|
||||
topology_validator.py Semantic and cross-reference checks
|
||||
topology_plan.py Fully resolved execution plan
|
||||
topology_renderer.py Executable Mininet Python generation
|
||||
report/ Assignment report workspace
|
||||
exercise/ Assignment execution files
|
||||
Mininet_DSL_Design.md Mininet JSON domain specific language rules and semantics
|
||||
README.md Repository's main documentation file
|
||||
```
|
||||
|
||||
Save a topology source as `topology.json`.
|
||||
Normal execution writes `topology.generated.py` beside that source file.
|
||||
|
||||
## Requirements
|
||||
|
||||
The implementation targets a Linux environment capable of running Mininet.
|
||||
|
||||
The current runtime and experiment dependencies are:
|
||||
|
||||
```text
|
||||
Python Mininet module
|
||||
mn
|
||||
ovs-vsctl
|
||||
ip
|
||||
tc
|
||||
sysctl
|
||||
dnsmasq
|
||||
dhclient
|
||||
tcpdump
|
||||
ping
|
||||
```
|
||||
|
||||
On Ubuntu, the corresponding packages are typically provided by:
|
||||
|
||||
```bash
|
||||
sudo apt install \
|
||||
mininet \
|
||||
openvswitch-switch \
|
||||
iproute2 \
|
||||
procps \
|
||||
dnsmasq-base \
|
||||
isc-dhcp-client \
|
||||
tcpdump \
|
||||
iputils-ping
|
||||
```
|
||||
|
||||
The exact environment can be checked without modifying the system:
|
||||
|
||||
```bash
|
||||
python3 source/build_network.py --env-check
|
||||
```
|
||||
|
||||
The check reports each required module or executable as `OK` or `MISSING`.
|
||||
|
||||
## Quick start
|
||||
|
||||
Run these commands from the repository root.
|
||||
Save the [complete assignment example](#complete-assignment-topology-example)
|
||||
as `topology.json` first, or use your own topology file.
|
||||
|
||||
### 1. Check the environment
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 source/build_network.py --env-check
|
||||
```
|
||||
|
||||
### 2. Generate the intermediate Python only
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
python3 source/build_network.py topology.json --emit
|
||||
```
|
||||
|
||||
This writes:
|
||||
|
||||
```text
|
||||
topology.generated.py
|
||||
```
|
||||
|
||||
and stops without creating a Mininet network.
|
||||
|
||||
A custom output path can be supplied:
|
||||
|
||||
```bash
|
||||
python3 source/build_network.py topology.json --emit gen-test.py
|
||||
```
|
||||
|
||||
Generation does not require root privileges.
|
||||
|
||||
### 3. Generate and execute
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
sudo python3 source/build_network.py topology.json
|
||||
```
|
||||
|
||||
The coordinator:
|
||||
|
||||
```text
|
||||
loads
|
||||
parses
|
||||
validates
|
||||
plans
|
||||
renders
|
||||
writes topology.generated.py
|
||||
executes topology.generated.py
|
||||
```
|
||||
|
||||
Network execution requires root privileges because Mininet creates namespaces,
|
||||
virtual interfaces, Open vSwitch state, and other kernel networking objects.
|
||||
|
||||
### 4. Exit the Mininet CLI
|
||||
|
||||
When finished, leave the CLI with:
|
||||
|
||||
```text
|
||||
mininet> exit
|
||||
```
|
||||
|
||||
The generated script then stops the service processes it started and calls
|
||||
`net.stop()`.
|
||||
|
||||
## Topology language
|
||||
|
||||
The JSON describes `nodes`, their `interfaces`, `links`, and `services`.
|
||||
Nodes may be hosts, Layer-2 switches, or routers; interfaces use static, DHCP,
|
||||
or no addressing.
|
||||
Links connect interfaces, and services describe processes such as a DHCP server.
|
||||
|
||||
Use the [JSON language reference](Mininet_DSL_Design.md) for field
|
||||
definitions, defaults, interface selection rules, and semantic constraints.
|
||||
The following example provides a complete starting point for the assignment.
|
||||
|
||||
## Complete assignment topology example
|
||||
|
||||
The example [here](exercise/topology.json) describes the required two-subnet topology.
|
||||
|
||||
## Configuration versus runtime state
|
||||
|
||||
The topology source describes configuration intent.
|
||||
|
||||
It does not record all runtime state.
|
||||
|
||||
Examples include:
|
||||
|
||||
```text
|
||||
JSON declaration Runtime result
|
||||
|
||||
static address -----> configured IPv4 address
|
||||
static gateway -----> configured default route
|
||||
DHCP addressing -----> dynamically learned address
|
||||
DHCP service settings -----> dynamically advertised options
|
||||
links -----> Mininet/veth interfaces
|
||||
services -----> running processes
|
||||
```
|
||||
|
||||
DHCP leases, ARP entries, packet counters, and packet captures are runtime
|
||||
state.
|
||||
|
||||
They do not belong in the topology grammar.
|
||||
|
||||
## Runtime experiments
|
||||
|
||||
After the generated topology enters the Mininet CLI, the assignment experiments
|
||||
can be performed with tools such as:
|
||||
|
||||
```text
|
||||
dhclient
|
||||
tcpdump
|
||||
ip neigh
|
||||
ping
|
||||
```
|
||||
|
||||
These commands operate on the running network and may create transient runtime
|
||||
state.
|
||||
|
||||
They do not modify the declarative topology source.
|
||||
|
||||
|
||||
### DHCP capture preparation
|
||||
|
||||
DHCP clients are intentionally not started by the generated network.
|
||||
|
||||
The assignment requires packet capture to begin before the DHCP exchange is
|
||||
triggered manually.
|
||||
|
||||
A clean client-side DHCP experiment can use a temporary lease and PID file:
|
||||
|
||||
```text
|
||||
mininet> h1 rm -f /tmp/h1-dhclient.leases /tmp/h1-dhclient.pid
|
||||
mininet> h1 dhclient -v \
|
||||
-lf /tmp/h1-dhclient.leases \
|
||||
-pf /tmp/h1-dhclient.pid \
|
||||
h1-eth0
|
||||
```
|
||||
|
||||
A successful exchange should show the normal DORA sequence:
|
||||
|
||||
```text
|
||||
DHCPDISCOVER
|
||||
DHCPOFFER
|
||||
DHCPREQUEST
|
||||
DHCPACK
|
||||
```
|
||||
|
||||
The DHCP server lease file generated by this project is reset before the
|
||||
service starts, so stale server-side leases from earlier topology runs do not
|
||||
affect a new experiment.
|
||||
|
||||
## Architecture
|
||||
|
||||
The implementation follows a compiler-like pipeline:
|
||||
|
||||
```text
|
||||
topology.json
|
||||
→ load → parse → validate → plan → render
|
||||
→ write generated Python → execute → Mininet CLI → cleanup
|
||||
```
|
||||
|
||||
The language describes network concepts that map to Mininet and Linux
|
||||
primitives: nodes, interfaces, links, network-stack settings, and services.
|
||||
Each stage has a separate responsibility so it can be tested independently.
|
||||
The generated Python is the only executable Mininet backend.
|
||||
|
||||
### Loading and parsing
|
||||
|
||||
`topology_loader.py` provides `load_topology(path)`, which reads a JSON file into
|
||||
a raw dictionary.
|
||||
`topology_parser.py` provides `parse_topology(raw)`, which converts that dictionary
|
||||
into a typed `Topology`.
|
||||
The loader's convenience API, `load(path)`, performs both operations.
|
||||
Neither stage depends on Mininet.
|
||||
|
||||
The semantic model uses dataclasses for `Topology`, `Node`, `Interface`, `Link`,
|
||||
`LinkEndpoint`, `Service`, and their structured settings.
|
||||
Enums represent node types, addressing modes, service types, and selectors.
|
||||
Interfaces and settings are composed into their owning entities.
|
||||
|
||||
Nodes, links, and services remain ordered lists during parsing.
|
||||
Keeping nodes in a list preserves duplicate declarations for diagnostics;
|
||||
converting them immediately to a name-indexed dictionary could hide duplicates.
|
||||
`Node.interfaces` uses `Optional[Dict[str, Interface]]`: `None` preserves an
|
||||
omitted interface set, while `{}` preserves an explicitly empty set.
|
||||
|
||||
### Validation
|
||||
|
||||
`topology_validator.py` exposes `validate(topology)`.
|
||||
It checks semantic and cross-reference constraints after parsing has checked
|
||||
field names, representation, and value types.
|
||||
See the [language reference](Mininet_DSL_Design.md) for those rules.
|
||||
|
||||
The validator collects `ValidationIssue(location, message)` objects and raises
|
||||
one `TopologyValidationError` containing all issues discovered in the pass.
|
||||
It does not print diagnostics or create Mininet objects.
|
||||
Validation checks whether automatic interface allocation is possible;
|
||||
planning performs the concrete allocation.
|
||||
|
||||
### Planning
|
||||
|
||||
`topology_plan.py` exposes `plan(topology)` and produces an immutable
|
||||
`ExecutionPlan` from a validated topology.
|
||||
It does not import Mininet, execute commands, or render Python.
|
||||
|
||||
The plan contains ordered tuples of node, link, interface, sysctl, and service
|
||||
operations.
|
||||
Its types include `PlannedNode`, `PlannedLinkEndpoint`, `PlannedLink`,
|
||||
`PlannedLinkSettings`, `PlannedInterface`, `PlannedSysctl`, `PlannedService`, and
|
||||
`PlannedDHCPServerSettings`.
|
||||
No unresolved `auto` or `all` selectors remain.
|
||||
|
||||
The planner reserves all explicit link-interface references before allocating
|
||||
`auto` selections from fixed pools in declaration order.
|
||||
Dynamic pools receive synthetic logical identifiers `auto0`, `auto1`, and so on.
|
||||
Concrete interface names follow `<node>-eth<N>`, starting at zero per node in
|
||||
link and endpoint traversal order.
|
||||
For example, `(r0, lan)` may resolve to `r0-eth0`.
|
||||
|
||||
Mininet creates interfaces through links.
|
||||
Planning therefore rejects configured interfaces or service bindings that have
|
||||
no corresponding link, while allowing unused empty interface declarations.
|
||||
|
||||
Switches are planned with Open vSwitch `failMode="standalone"` to operate as
|
||||
Layer-2 learning switches without an OpenFlow controller.
|
||||
Hosts and routers are created with `net.addHost(..., ip=None)`.
|
||||
Router settings generate sysctls only when explicitly supplied.
|
||||
`rp_filter` operations cover `all`, `default`, and each materialized router
|
||||
interface inside the router namespace.
|
||||
|
||||
### Rendering and runtime lifecycle
|
||||
|
||||
`topology_renderer.py` exposes `render_python(plan)`.
|
||||
It serializes the resolved plan without allocating interfaces or validating
|
||||
language semantics.
|
||||
The resulting standalone Python program is preserved for inspection.
|
||||
|
||||
The generated program:
|
||||
|
||||
1. Creates nodes and links, then builds and starts Mininet.
|
||||
2. Configures interfaces, static default routes, and namespace-scoped sysctls.
|
||||
3. Starts services and enters the Mininet CLI.
|
||||
4. Terminates tracked service processes and calls `net.stop()` in a `finally`
|
||||
block.
|
||||
|
||||
When a link has traffic-control settings, the renderer emits `TCLink`.
|
||||
Bandwidth maps to `bw`, loss to `loss`, and delay and jitter to millisecond
|
||||
strings.
|
||||
For example:
|
||||
|
||||
```python
|
||||
net.addLink(
|
||||
nodes["r0"],
|
||||
nodes["s1"],
|
||||
intfName1="r0-eth0",
|
||||
intfName2="s1-eth1",
|
||||
cls=TCLink,
|
||||
delay="1.5ms",
|
||||
)
|
||||
```
|
||||
|
||||
Interface configuration uses Linux commands such as `ip addr add`,
|
||||
`ip route replace`, and `sysctl -w` inside the appropriate node namespace.
|
||||
|
||||
DHCP services run through `dnsmasq`, with DNS disabled and a 12-hour lease time.
|
||||
These are backend choices, not configurable JSON fields.
|
||||
Each service uses indexed lease, PID, and log paths under `/tmp`.
|
||||
The generated script removes its previous lease and PID files before startup
|
||||
and tracks the background PID for cleanup.
|
||||
DHCP clients are started manually after packet capture begins, as described in
|
||||
[Runtime experiments](#runtime-experiments).
|
||||
|
||||
### Coordination and error reporting
|
||||
|
||||
`build_network.py` coordinates the stages through `compile_topology(path)`,
|
||||
which returns the execution plan and rendered source.
|
||||
The coordinator writes the generated artifact beside the input using the
|
||||
`.generated.py` suffix unless `--emit PATH` selects a different destination.
|
||||
|
||||
`--emit` stops after writing, without requiring Mininet or root privileges.
|
||||
Normal execution writes the same artifact, checks dependencies, and runs it
|
||||
with the coordinator's Python interpreter.
|
||||
Network execution requires root privileges.
|
||||
`--env-check` reports dependencies and exits without compiling a topology.
|
||||
See [Quick start](#quick-start) for commands.
|
||||
|
||||
Core stages raise typed exceptions; the command-line layer reports them.
|
||||
|
||||
| Stage | Exception |
|
||||
| --- | --- |
|
||||
| Loading | `TopologyLoadError` |
|
||||
| Parsing | `TopologyParseError` |
|
||||
| Validation | `TopologyValidationError` |
|
||||
| Planning | `TopologyPlanError` |
|
||||
| Artifact writing or process launch | `BuildNetworkError` |
|
||||
|
||||
The coordinator returns a failing status for reported errors and propagates the
|
||||
exit status of the generated program.
|
||||
|
||||
## Self-tests
|
||||
|
||||
The five core pipeline modules contain lightweight `__main__` smoke tests.
|
||||
The coordinator's `__main__` invokes its command-line interface instead.
|
||||
|
||||
They exercise each module's public interface.
|
||||
|
||||
They can be run directly:
|
||||
|
||||
```bash
|
||||
python3 source/topology_loader.py
|
||||
python3 source/topology_parser.py
|
||||
python3 source/topology_validator.py
|
||||
python3 source/topology_plan.py
|
||||
python3 source/topology_renderer.py
|
||||
```
|
||||
|
||||
These smoke tests do not require Mininet, root privileges, or network changes.
|
||||
|
||||
The environment can be checked separately with:
|
||||
|
||||
```bash
|
||||
python3 source/build_network.py --env-check
|
||||
```
|
||||
|
||||
A generated topology can then be tested in Mininet with:
|
||||
|
||||
```bash
|
||||
sudo python3 source/build_network.py topology.json
|
||||
```
|
||||
|
||||
## Current scope and extension points
|
||||
|
||||
The current language supports:
|
||||
|
||||
- hosts,
|
||||
- Layer-2 learning switches,
|
||||
- routers,
|
||||
- static IPv4 addressing,
|
||||
- DHCP client intent,
|
||||
- one optional static default gateway per node,
|
||||
- logical interface tags,
|
||||
- automatic interface allocation,
|
||||
- link bandwidth, delay, loss, and jitter,
|
||||
- DHCP server services,
|
||||
- router forwarding and reverse-path-filter settings.
|
||||
|
||||
Extending the language requires corresponding parser, validator, planner, and
|
||||
renderer support.
|
||||
Potential extensions include:
|
||||
|
||||
- additional node types,
|
||||
- additional services,
|
||||
- richer interface properties,
|
||||
- richer link behavior,
|
||||
- more general routing constructs.
|
||||
|
||||
The project currently supports IPv4 network configuration for the assignment.
|
||||
|
||||
## Further documentation
|
||||
|
||||
- [JSON language reference](Mininet_DSL_Design.md):
|
||||
complete field definitions, defaults, and semantic constraints.
|
||||
- [Assignment brief](Computer_Networks_II-Programming_task.pdf):
|
||||
required topology, experiments, and deliverables.
|
||||
|
||||
Reference in New Issue
Block a user