Conversation
linux bridge works as hub
Mimidump added
Mimidump added
Добавил RSTP для switch
Add stp and rstp priority
Добавить DHCP
Изменил устаревший setup.py на pyproject.toml
Добавил выбор интерфейсов в Dnsmasq
Изменила источник mininet
* build: migrate to uv package manager uv replaces pip/setuptools for dependency management and virtualenv handling. .python-version pins the Python version and uv.lock is the lockfile. The build backend stays setuptools; no other tooling changes are introduced here. * test: add rootless local test runner and pure unit tests - scripts/run-tests-local.sh: run the suite as a non-root user; root-only tests are skipped via the existing require_root marker - tests/test_pure.py: new rootless tests for _parse_addresses, is_subnet_of, is_container, get_set, ConfigDict and ip_statement - test_misc: mark test_ip_address_format as requiring root (it calls 'ip link set dev lo up') * fix(install): make -a work with uv and inside containers - install_mininet: add a minimal path used by `-a` that only builds and installs the mnexec binary; the full install.sh -a installs packages that no longer exist on Ubuntu 24.04 and the Python package is provided by uv. OVS now comes from the openvswitch-switch apt package. - create /run/sshd for openssh-server - skip the IPv6 grub configuration when /etc/default/grub is absent, as it is inside a container - parse pip versions with packaging.version instead of pkg_resources * fix(tests): fix pre-existing failures and skip daemon-dependent tests only when missing - test_link: 2002::/16 (6to4) is now classified private by ipaddress in Python 3.12, so the global 2001::/16 sorts first - test_exabgp: fix a wrong self-comparison (asn_received == asn_received) - Replace the unconditional @pytest.mark.skip on the openr, exabgp and network_capture tests with conditional markers (require_openr, require_exabgp, require_mimidump) in tests/__init__.py. The tests now run wherever the daemon is available and skip with a reason otherwise; ExaBGP additionally requires the daemon to actually start (4.2.11 ships a broken vendored six). - Document the skip policy in tests/__init__.py and point to it from docs/contribute.rst. * ci: add containerized, rootless and heavy test workflows Three workflows replace the single test entry point: - test.yaml: bare-metal CI with a rootless job (runs the pure/rootless tests as the non-root runner user via the require_root marker) and a root job running the full suite after 'ipmininet.install -a'. - container-test.yaml: builds the self-contained Containerfile (uv venv in /opt/venv + full install) and runs a test subset inside it. - heavy-test.yaml: full suite on master and on demand. The full-suite jobs collect every test file; daemon-dependent tests skip themselves via the conditional markers in tests/__init__.py, so their reasons show up in pytest -rs output instead of being dropped with --ignore. Lint and format checks are intentionally not included; they will be added with the follow-up reformatting PR. * chore: add dependabot configuration Monthly grouped updates for uv (Python deps via uv.lock), GitHub Actions and Docker (Containerfile) ecosystems. * fix: remove -t / from named startup line for userns compatibility The '-t /' chroot makes named's working directory '/' which a user-namespace root cannot write, causing 'loading configuration: permission denied' inside rootless podman containers. The chroot to / is a no-op in rootful environments; removing it fixes named in podman while preserving rootful behavior. * fix: run node daemons in the node working directory The DNS tests (test_dns.py) were flaky in CI: 6 tests failed with "connection refused" on port 53 because named exited at startup. Root cause, reproduced locally in Docker and podman: - Daemons are launched via node.popen() (mininet), which runs the command in the node network namespace but keeps the *pytest process* cwd. On CI that cwd is the runner checkout / mounted workspace, owned by a non-root user (runner / ubuntu). - named is started with `-u root`, which makes BIND drop CAP_DAC_OVERRIDE. A uid-0 process without CAP_DAC_OVERRIDE can only write directories it owns or that are world-writable; it cannot write session.key / _default.tsigkeys into a 755 non-root-owned cwd, so named dies with "loading configuration: permission denied". - This never reproduced locally under podman because rootless podman maps the container root onto the host user, making the workspace root-owned. - The earlier `-t /` removal (commit 0fb8522) was correct: named chdirs to "/" after chroot, and a user-namespace root cannot write "/", so `-t /` breaks rootless podman. But in rootful CI the chroot made the effective working directory "/" (root-owned), which masked the bug above; without it the real failure surfaced. Changes ------- - ipmininet/router/__router.py: spawn node daemons with cwd=self.cwd (the node working directory, world-writable /tmp by default). named now has a writable cwd even after dropping CAP_DAC_OVERRIDE, in all environments. - .github/workflows/container-test.yaml: add ipmininet/tests/test_dns.py to the containerized job so DNS tests are covered there too (~5.5 min added; the job stays far below the 60 min timeout). A previous attempt installed apparmor-utils and changed the named comment, based on a wrong AppArmor hypothesis (that a confined named was the cause). It changed nothing in CI results and is reverted here; the daemon cwd was the real issue. Noted so the decision can be re-validated later. * fix(ci): create /run/sshd before running the container test suite sshd -t (the SSHd daemon dry_run check) requires the privilege separation directory /run/sshd. It is created by install -a at image build time but is lost between the image build and the container start, so test_sshd failed in the container with SystemExit 1. Create it in the test entrypoint; bare-metal CI was unaffected because install -a runs on the live runner.
…t#12) * fix: skip IPv6 DAD wait for IPv4-only nodes (use_v6=False) * fix: start interface captures only once the interface is up
Poll for interface and topology convergence faster and probe hosts in parallel; tune RIPng and STP timers in test topologies; and skip IPv6 address allocation where it buys nothing (GRE and OSPF parameter tests).
Make route assertions deterministic: assert_routing_table() waits for prefixes to be present or absent within a bounded deadline and dumps the actual table on failure. The link-restoration tests wait for each router to relearn the far host subnet in both address families before probing connectivity.
scripts/run-tests-parallel.sh distributes the suite across pytest-xdist workers, each exec'd through scripts/py-unshare.sh into private mount/net/pid namespaces. The CI test job uses the runner. Results are identical to serial: 185 passed, 8 skipped.
…ble past-header files Address review feedback: - The strict check no longer assumes a fixed 24-byte classic pcap header. _capture_header_size() reads the file's magic bytes and returns the correct header length for classic pcap (LE/BE) and pcapng, defaulting to classic pcap for unknown or unreadable files. - Strict mode now accepts a file that is already stable past its header (a bursty writer whose whole exchange landed before the first poll), instead of only growing files, so the file-growth fallback is reliable for captures that cannot signal readiness. READY remains the primary signal. Tests expanded to cover both magic byte formats, the bursty stable case and an undersized/torn header. Signed-off-by: Iakov Kirilenko <jake.kirilenko@gmail.com>
Signed-off-by: Iakov Kirilenko <jake.kirilenko@gmail.com>
test_randomFailure[3] restores all three links at once; under load (and with the coverage-instrumented full suite) OSPF can take longer than the 120s cap to repopulate r1/r2. The poll exits as soon as routes appear, so the larger cap only costs time when convergence is genuinely slow. Signed-off-by: Iakov Kirilenko <jake.kirilenko@gmail.com>
Signed-off-by: Iakov Kirilenko <jake.kirilenko@gmail.com>
pytest-cov already merges the per-worker data files into .coverage at the end of the suite, so 'coverage combine' finds nothing to merge and exits non-zero. The gate step now tolerates that and runs under sudo because the suite writes the report files as root. Signed-off-by: Iakov Kirilenko <jake.kirilenko@gmail.com>
The fork CI heavy-test run measured 84% branch coverage of the core library (3746 statements, omitting tests/examples/install); the gate now fails below that level. Signed-off-by: Iakov Kirilenko <jake.kirilenko@gmail.com>
pytest-cov enforces the [tool.coverage.report] fail_under on every --cov run, so the rootless job (26% on the small rootless subset) failed the gate meant for the full-suite master run. Disable it there with --cov-fail-under=0; the strict gate stays enforced by heavy-test on master. Signed-off-by: Iakov Kirilenko <jake.kirilenko@gmail.com>
…-net#32) * fix(install): build PCRE1 from source on Ubuntu 26.04 and newer Ubuntu 26.04 dropped the obsolete PCRE1 packages (libpcre3-dev). libyang v1, which FRRouting 7.5 requires, is still built against PCRE1, so fall back to building PCRE 8.45 from a SHA-256-pinned tarball when apt no longer ships it. Defer TRY003 in install.py, matching the rest of the codebase. * build(container): base the test container on ubuntu:26.04 Drop libpcre3-dev from the apt install list (gone in 26.04; install.py now provisions PCRE1 itself) and refresh the PEP 668 comments. * fix(install): configure libyang on CMake 4 via policy-version minimum Ubuntu 26.04 ships CMake 4.x, which dropped compatibility with projects declaring cmake_minimum_required < 3.5 (libyang v1.0.215 still declares 2.8.12). Pass -DCMAKE_POLICY_VERSION_MINIMUM=3.5, the documented escape hatch; older CMake ignores the variable. Validated locally on ubuntu:26.04: PCRE 8.45 source build + libyang v1.0.215 configure and full build. * fix(install): make FRR clippy find the uv-managed libpython FRR's build-time clippy tool embeds the Python that configured it. In the container that is a uv-managed CPython whose libpython3.12.so.1.0 sits outside the loader's default search path (on 24.04 the system Python 3.12 masked this; on 26.04 the system Python is 3.13). Expose the running interpreter's LIBDIR via LD_LIBRARY_PATH for the FRR configure/make/install. Validated on ubuntu:26.04: a Python-embedding program reproduces the clippy 'cannot open shared object file' error without the path and runs with it. * fix(link): disable iproute2 color so parsers see plain output mininet runs commands on a pty, and iproute2 >= 6.19 (Ubuntu 26.04) colorizes `ip address show` and `ip rule list` there, corrupting the parsed addresses (ipaddress.AddressValueError on the ANSI escapes). Pass ip -color=never in the two places whose output is parsed; a no-op on older iproute2. * fix(install): build PCRE1 with Unicode property support FRR 7.5's bundled YANG (ietf-inet-types) uses \p{...} regexes, which PCRE only compiles in with --enable-unicode-properties (Debian's libpcre3-dev enables it by default, so the system package worked on 24.04). Without it, libyang fails to parse the module and every FRR daemon aborts its config check. Validated on ubuntu:26.04: \p{L} compiles and matches. * fix(host,cli): named zone transfers on BIND 9.20 and iproute2 colors BIND >= 9.20 denies zone transfers unless allow-transfer is explicit, so slaves SERVFAIL their zones (24.04's 9.18 allowed transfers by default). Add allow-transfer to master zones and a directory clause (9.20 requires a writable working directory to load zones). Also pass ip -color=never for the CLI's `ip route get` output, which iproute2 >= 6.19 colorizes on a pty and would otherwise corrupt the asserted output. * fix(tests): parse multi-address ipv6.dst and resolve hostnames via system DNS - sr_path: tshark 4.x reports every IPv6 header address for SRv6 encapsulated packets (SID plus inner destination) as a single comma separated field; switching to a tab separator and keeping the outermost address restores the through-segment matching that routes 4-6 rely on. - host_connected: nmap 7.98's internal resolver ignores /etc/hosts; --system-dns routes hostname targets through the system resolver so the per-node hosts files are honoured again.
The uploader resolved the repository to the fork (iakov/ipmininet) even on runs against mimi-net, so the README badge (mimi-net/ipmininet) stayed empty. Force the slug to github.repository so the report lands on the right repo.
Set PIP_BREAK_SYSTEM_PACKAGES explicitly in pip_install instead of relying on the environment in CI scripts and the container, and key the distro package selections off a package_family helper (apt/rpm) to drop the repeated NAME comparisons. Also sync uv.lock with the 1.2.7 version bump.
OpenR has been unmaintained upstream since 2019 and its test was always skipped in CI (require_openr). Drop the installer, config generators, example, test, and docs.
Migrates the routing stack to FRRouting 10.7.1 and libyang v3, adopting the FRR 9+ mgmtd configuration architecture and slimming the test container via a two-stage build.
- install.py: FRR 10.7.1 (tag archive + bootstrap.sh), libyang v3.13.6 (drops the PCRE1 source build and CMake policy hack), new build deps, standard system paths (--sysconfdir=/etc --localstatedir=/var --runstatedir=/var/run), --enable-protobuf=no.
- New Mgmtd daemon and MgmtdBackendDaemon base: staticd, ripd and ripngd are mgmtd backends in FRR 9+ and reject -f/-C; their rendered config is pushed via vtysh once each daemon is up.
- bgpd: skip the -C dry-run (FRR 10.7.1 crashes on 'neighbor activate' in the config-check path; validated at real startup instead).
- ospf6d: attach interfaces to their area with 'ipv6 ospf6 area' inside the interface block ('interface X area Y' was removed in FRR 10.x).
- Containerfile: two-stage builder/runtime build. The builder runs install -a and builds the venv + mimidump; the runtime stage ships only test-facing apt packages plus the compiled artifacts (FRR, libyang, mnexec, exabgp, mimidump, venv + uv CPython toolchain). Final image drops from 1.74 GB to 0.98 GB (613 MB to 277 MB compressed download, -55%).
Full container test suite green (container-test, test, rootless, docs).
* feat(install): migrate ExaBGP to 5.0.13 and install it via pip ExaBGP 5.x moved to a src/ layout and a console script (entry point exabgp.application.main:main); the 4.x zipapp build no longer applies. Install with pip and symlink the entry point to /usr/sbin/exabgp. * fix(exabgp): adapt to the 5.x subcommand CLI ExaBGP 5.0.13 moved to a subcommand interface: the config is validated with `exabgp validate <file>`, the server starts with `exabgp server <file>` and the env file is passed via --env-file. Update the daemon's startup/dry-run lines and the availability probe, which used the 4.x `--validate`/`--env`/global flags. * refactor(install): install ExaBGP into the uv virtualenv ExaBGP 5.0.13 now rides in the uv-managed venv (/opt/venv) that the container image copies wholesale, so the image no longer needs the /root/exabgp zipapp or a /usr/sbin/exabgp symlink. install_exabgp() prefers 'uv pip install' inside a virtualenv and falls back to the system pip. CI dep caching no longer snapshots exabgp: it is a pure pip install, cheap enough to redo every run. Also fix _needs_rebuild() accepting None paths so the exabgp guard does not raise a TypeError on systems where the entry point is absent. * fix(exabgp): use the CRITICAL log level accepted by ExaBGP 5.x ExaBGP 4.x read syslog priority names for exabgp.log.level (e.g. CRIT), but 5.x validates the value against its Python logging levels and aborts at startup with 'invalid value for log.level : CRIT' when the env file contains one. Since the daemon died before its BGP session with FRRouting was ever set up, the injected routes never reached the RIB and the exabgp tests timed out. Use CRITICAL, and pass the env file to 'exabgp validate' (as the 4.x dry-run did via --validate --env) so a bad env file fails the router config check instead of silently killing the daemon at launch.
…ith 2 updates (mimi-net#34) Bumps the actions-dependencies group with 2 updates in the / directory: [actions/upload-artifact](https://github.com/actions/upload-artifact) and [codecov/codecov-action](https://github.com/codecov/codecov-action). Updates `actions/upload-artifact` from 4 to 7 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](actions/upload-artifact@v4...v7) Updates `codecov/codecov-action` from 4 to 7 - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](codecov/codecov-action@v4...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions-dependencies - dependency-name: codecov/codecov-action dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions-dependencies ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
test.yaml, heavy-test.yaml and container-test.yaml all ran the same full test suite on every master push, and master only changes through merged PRs whose checks already ran all three. Restrict test.yaml to pull requests: master pushes now run the coverage-gated heavy-test job plus container-test, dropping the duplicated bare-metal run (~23 min/push). Also refresh the stale heavy-test header, which still described ExaBGP as a known-broken daemon skipped in its own test module.
…et#38) test(srv6): wait for the measured IPv6 paths to converge The path assertions measure IPv6 routes, but the test only waited for IPv4 connectivity first. Under parallel CI load OSPFv6 could still be settling when sr_path started probing, so it returned an empty path and the test flaked on the routesN parametrizations. Only the endpoints exercised by each assertion are guaranteed to become reachable over IPv6 in this topology, so wait for the exact src/dst pair each path measures instead of asserting full IPv6 host connectivity.
…gnores (mimi-net#41) ci(coverage): raise gate to 85 and clear product PLR2004 ignores Raise the full-suite coverage floor from 84 to 85%. To make room for removing PLR2004 per-file ignores, introduce IP_V4/IP_V6 constants in ipmininet/utils.py and use them for the product IP-version comparisons in named, ipnet, link, router/config/utils, and zebra. Give the legacy LinkDescription integer indexes (0/1/3) named constants as well. Delete now-dead ignore entries (install.py E501+TRY003, test_gre/test_sshd PLR2004) that had zero live violations.
…et#42) Replace every remaining PLR2004 (magic-value-comparison) violation in product code, tests and examples with named constants, and drop the PLR2004 per-file ignores so the rule now covers the whole tree: - srv6.py: lowest reserved Linux table number (MIN_RESERVED_TABLE) - examples/exabgp_prefix_injector.py: max prefixes per AFI - tests/test_link.py: default/updated IPv4 and IPv6 prefix lengths - tests/test_misc.py: MAC length plus utils.IP_V4/IP_V6 reuse - tests/test_srv6.py: probe-grouping window and tshark field count - tests/test_tc.py: ping count and required matching samples - tests/utils.py: identical traceroutes before declaring convergence No per-file-ignores for PLR2004 remain, so any new magic constant in a comparison now fails ruff check in CI and pre-commit.
…imi-net#43) * test(coverage): cover the dnsmasq, DHCPRelay and IPOVSSwitch modules * test(coverage): fix rstp substring assert and xdist basetemp race
* refactor(lint): drop circular-import workarounds and split router configs * style(lint): replace file-wide PLR/PLC/TRY003 ignores with targeted noqa
…o tests (mimi-net#47) * test(coverage): expand scenario coverage toward the 90 gate Add rootless scenario tests exercising the zebra routing-policy DSL and the IPTopo/Subnet/NetworkCapture APIs, extend the rootful topology DB and link-failure suites with error-path and API corner-case scenarios, and enable workflow_dispatch on the pull-request test workflows so the full suite can be measured on this branch. Make the heavy-test coverage gate enforcement fail the job again by running 'coverage report -m' last. * test(topologydb): resolve the h1-r1 interface by link lookup mininet indexes interfaces by their own name, not by the peer node name, so looking up net['h1'].intf('r1') raises KeyError. Resolve the interface through connectionsTo() instead. * test(topologydb): make the DB lookup scenarios robust to IP layout Derive interface lookups from the recorded interface names and the DB records themselves instead of assuming naming or address-format details of the underlying interfaces, which differ before the network is started. * ci(coverage): raise the full-suite gate to 90 The scenario tests push the blended total (statements + branch arcs) to 90.9%, so the gated master heavy-test can now enforce fail_under = 90.
…imi-net#48) * fix(zebra): always set PrefixListEntry.ge, including for 'any' The 'any' prefix-list entry returned early from __init__ before assigning .ge, leaving it undefined. Template code that renders the prefix-list then raises AttributeError when it checks 'if e.ge'. Initialize .ge to None so 'all' entries expose a consistent attribute surface. * test(coverage): cover ExaBGP attribute model, link descriptions and capture headers Adds rootless scenario tests that exercise code previously only reachable inside rootful or hardware flows: - test_exabgp_model_scenarios builds known and hex-encoded attributes, flag bit layouts and route lookups, closing gaps in the ExaBGP value model. - test_topo_scenarios now drives LinkDescription indexing/ordering/errors and the pcap/pcapng magic-byte sniffing, covering the description and capture header helpers rootlessly. - Registers the new module in the heavy suite file list. * test(topo_scenarios): drop unused os import in capture header test * test(topo_scenarios): write capture headers outside the pytest basetemp The xdist workers run in a private mount namespace with a fresh /tmp (scripts/py-unshare.sh), so pytest's basetemp directory does not survive into the worker and the tmp_path fixture flaked at session wrap-up on the heavy-test run. Follow the TemporaryDirectory convention already used by test_network_capture.py for these rootless capture-header tests.
…mi-net#49) * test: reuse net teardown and parametrize rootless scenario tables - add run_ipnet() context manager to tests/utils.py (net.start with a guaranteed net.stop()+cleanup()) and use it in test_misc, test_network_capture and test_topologydb instead of hand-rolled try/finally scaffolding - parametrize test_dhcp dnsmasq pid lookups and the test_topo_scenarios subnet overlay cases into data tables - drop test_pure duplicates (ConfigDict, ip_statement) covered by richer sibling tests; import the pcap magic constants instead of redefining them * test: collapse IGP/BGP network tests onto shared scenario helpers Add assert_config_file, assert_all_paths, run_topology_scenario and the shared IGP path tables to tests/utils.py, then rewrite the rootful daemon tests (ospf/ospf6/ripng/radv/static/bgp/switch/linkfailure) to use run_ipnet and the scenario runner instead of hand-rolled start/assert/stop/cleanup scaffolding. test_bgp local_pref/med/rr/full become one parametrized test. * refactor: de-duplicate switch capture and IGP config scaffolding - factor the per-node/per-interface capture start/stop loops of IPSwitch and IPOVSSwitch into start_captures/stop_captures helpers - share is_active_interface and the per-interface ConfigDict builder between the OSPF and RIPng configs, and the interface/network population step on the common QuaggaDaemon base - replace the duplicated visited-set BFS in base.py router-id scan and utils.find_node by a shared walk_unvisited() generator * lint: enforce a zero-tolerance duplicate-code gate The product code and the test suite no longer contain duplicated blocks, so drop the duplication_max ceiling to 0, scope scripts/check-duplicates.sh to exclude the standalone examples/install demos, and add a local pre-commit hook that runs it before every push. * fix(ospf): keep OSPF.is_active_interface for the ospf6 subclass OSPF6 subclasses OSPF and calls is_active_interface from its own _build_interfaces; delegate to the shared is_l3router_interface helper instead of dropping the method. * fix(utils): expand whole router interface lists in find_node walk_unvisited must enqueue realIntfList(n.node) for every L3 neighbour like the original code did, not just the single neighbour interface, otherwise the BFS never leaves the first broadcast domain (breaks find_node and the DNS zone server resolution that relies on it). * style(utils): ruff format find_node
build: prepare v1.3.0 (version bump, metadata and install docs refresh) - bump version to 1.3.0 and refresh the Python classifiers (>=3.12 only) - regenerate uv.lock for the new version - document that install.py provisions FRRouting 10.7.1 (mgmtd; FRR >= 9 required, so existing environments must be re-provisioned) and ExaBGP 5.0.13 via pip; bump the pinned install tag in docs - drop the dead upstream Python 3.7 Jenkins badges from the README
set_local_pref/set_med/set_community now accept an optional order and place their route-map entry at that order, mirroring deny/permit/filter. Also fix a latent crash when two set actions on the same peer used different match conditions: the route-map lookup miss dereferenced None (AttributeError in add_set_action) instead of appending a new auto-ordered entry. Add a rootless model test exercising the merge, distinct-entry and explicit-order paths. Relates to cnp3#99.
build: prepare v1.3.1 Version bump 1.3.0 -> 1.3.1 (patch: bugfix + additive route-map order parameter, no API or environment change) and bump the pinned install tag in the docs.
iakov
added a commit
to iakov/ipmininet
that referenced
this pull request
Sep 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
release: ipmininet v1.3.1 — revive upstream
A note of thanks
First and foremost, I want to extend my heartfelt thanks to the IPMininet
authors, maintainers, and community. This project has been a lifesaver — in
the classroom and in research alike — turning protocol theory into something
students could actually watch converge, break, and heal. It is my genuine
pleasure to give back everything we have built on top of it downstream, and an
even greater pleasure to think the maintainers might fold these improvements
into the project so the whole community can benefit. The work in this PR comes
from the downstream fork
mimi-net/ipmininet(my branch:
iakov/ipmininet@upstream-v1.3.1),and it carries the effort of everyone who contributed there. On behalf of our
team, I offer it with deep gratitude — and real excitement for where IPMininet
goes next.
Summary
This PR brings
cnp3/ipmininetfrom its 2023 state (last push 2023-01-18, lastrelease v1.1) up to the maintained downstream release v1.3.1. It is a large
but mostly mechanical delta — 78 commits, 156 files, +11,391/-6,295, much of
it tests and CI — contributed from the downstream fork
mimi-net/ipmininet. It returns thatwork upstream, unblocks several open issues, and restores the repository to a
state that installs and passes CI on a modern machine. We are happy to split or
drop any part of this on maintainer request.
At a glance
>= 3.12(pyproject;setup.pyretired)-W, CI job greenBreaking changes and migration (read first)
setup.pyreplaced bypyproject.toml+uv.lock(setuptools backend); install with
pip install .oruv sync.installer builds FRR 10.7.1 from source. Existing environments must be
re-provisioned:
sudo python -m ipmininet.install -af.pbrd/pathdremainunimplemented and are not added here.
cnp3/master. BGP set-action defaults areunchanged, so generated configs are byte-identical unless
orderis used.What's in it
Switching / data plane
brctl setageing 0); STP/RSTP support and priority;VLAN-filtering cleanup; link packet duplication.
address churn and zebra/ospfd races); faster, reliable IPv4-only startup.
DHCP / services
dnsmasqDHCP daemon with per-interface selection, a DHCP-relayimplementation, and
mimidumpcapture tooling.BGP / routing config
set_local_pref,set_medandset_communityaccept an explicit route-maporder(parity withdeny/permit/filter).AttributeErrorin the BGP config builder when two setactions on one peer used different match conditions; zebra
PrefixListEntry("any")now sets.gecorrectly.Capture
wait_until_capturing()gainsstrict=True; header size is derived frommagic bytes (pcap/pcapng), accepting slow-grow and bursty writers.
Platforms / build
maintained fork; SRv6/IPv6 connectivity waits; Python >= 3.12 / pyproject+uv.
Quality / CI
branch-coverage gate 90 (measured 92.29%); zero duplicate-code gate.
ruff format/mdformatwith pre-commit hooks; docs built underuvwith-W; dependabot for Actions and Docker.Open upstream issues addressed or clarified
order+ crash fixIPOVSSwitchexists and is documentedbrctl setageing 0)/var/run/frr+ mgmtd pushpost_build()remains the intended hookWe are not closing any of these from this side; happy to help triage once the
PR lands.
Validation
rootless,docs,test(bare metal) andcontainer-testall green.(run
34441918630); container-test34441918620.ruff check/format,mdformat --checkandscripts/check-duplicates.sh(0 blocks) clean.uv sync --all-extrasthenpytest, orCOVERAGE=1 scripts/run-tests-parallel.shas root.For review, the diff is easiest in this order:
pyproject.toml/uv.lock+.github/workflows/*(build/CI) ->ipmininet/router/config/*(daemons) ->ipmininet/ipswitch.py,ipovs_switch.py,install/(switch/DHCP) ->ipmininet/tests/*. Most added lines areuv.lockand tests; the rest islint/format churn. Note: GitHub's compare view under-reports a few large files
(e.g.
uv.lockshows as added with 0 changes); usegit diff --stat 72cefde..<head>for exact numbers.Notes
cnp3/ipmininet(downstream equivalent:https://github.com/mimi-net/ipmininet/releases/tag/v1.3.1). Happy to adjust
the version policy or notes if upstream prefers otherwise.
downstream fork, alongside the maintainers' work. Credit for this PR belongs
to the whole downstream team.
Checklist
-Wagentic/,.tmp/, scratch) includedThank you again for building and caring for IPMininet — we are grateful for the
chance to contribute, and excited for what comes next.
References
this PR likely supersedes it; leaving that decision to you.