diff --git a/.github/workflows/netsim_integration.yml b/.github/workflows/netsim_integration.yml index bdf6eeb..1de78f3 100644 --- a/.github/workflows/netsim_integration.yml +++ b/.github/workflows/netsim_integration.yml @@ -37,20 +37,16 @@ jobs: sudo apt update ./setup.sh - - name: Build chuck - run: | - cargo build --release - - name: Fetch and build iroh run: | - git clone --depth 1 https://github.com/n0-computer/iroh.git + # git clone --depth 1 https://github.com/n0-computer/iroh.git + git clone --depth 1 --branch feat-improve-network-change https://github.com/n0-computer/iroh.git cd iroh cargo build --release --all-features -p iroh-relay -p iroh-dns-server cargo build --release --all-features -p iroh --examples - name: Copy binaries to right location run: | - cp target/release/chuck netsim/bins/chuck cp iroh/target/release/iroh-relay netsim/bins/iroh-relay cp iroh/target/release/iroh-dns-server netsim/bins/iroh-dns-server cp iroh/target/release/examples/transfer netsim/bins/iroh-transfer @@ -62,6 +58,14 @@ jobs: sudo mn --clean sudo python3 main.py --integration --max-workers=4 sims/integration + - name: Upload logs + uses: actions/upload-artifact@v4 + if: always() + with: + name: netsim-logs + path: netsim/logs/ + retention-days: 7 + - name: Setup Environment (PR) if: ${{ github.event_name == 'pull_request' }} shell: bash diff --git a/netsim/main.py b/netsim/main.py index cddd9c1..d25d03d 100644 --- a/netsim/main.py +++ b/netsim/main.py @@ -5,6 +5,7 @@ import os import sys import tempfile +import threading import time from mininet.log import setLogLevel, info, error @@ -271,6 +272,37 @@ def prep_net(net, prefix, sniff): return sniffer +def schedule_mid_run_actions(net, nodes, node_counts, node_ips, runner_id, prefix): + """Schedule mid-run actions like blocking direct connections.""" + for node in nodes: + if "mid_run_action" not in node: + continue + action = node["mid_run_action"] + for i in range(int(node["count"])): + node_name = f'{node["name"]}_{i}_r{runner_id}' + if "block_direct_to" in action: + target = action["block_direct_to"] + target_cnt = node_counts.get(target, 1) + target_name = f'{target}_{i % target_cnt}_r{runner_id}' + target_ip = node_ips.get(target_name) + if not target_ip: + continue + delay = action.get("delay_seconds", 5) + n = net.get(node_name) + + def block_after_delay(node_ref, ip, delay_sec, log_prefix, src_name): + time.sleep(delay_sec) + node_ref.cmd(f"iptables -A OUTPUT -d {ip} -p udp -j DROP") + info(f"[{log_prefix}] Blocked direct UDP to {ip} from {src_name}\n") + + t = threading.Thread( + target=block_after_delay, + args=(n, target_ip, delay, prefix, node_name) + ) + t.daemon = True + t.start() + + def run_case(nodes, runner_id, prefix, args, debug=False, visualize=False): topo = StarTopo(nodes=nodes, runner_id=runner_id) net = Mininet(topo=topo, waitConnected=True, link=TCLink) @@ -314,6 +346,8 @@ def run_case(nodes, runner_id, prefix, args, debug=False, visualize=False): # CLI(net) + schedule_mid_run_actions(net, nodes, node_counts, node_ips, runner_id, prefix) + process_errors = monitor_short_processes(p_short_box, prefix) if process_errors: error("\n" + "=" * 80 + "\n") @@ -353,7 +387,7 @@ def run(case, runner_id, name, args): viz = False if "visualize" in case: viz = case["visualize"] & args.visualize - print('Running "%s"...' % prefix) + print('Running "%s"...' % prefix, flush=True) n, s = (None, None) if not args.reports_only: (n, s) = run_case(nodes, runner_id, prefix, args, args.debug, viz) @@ -376,7 +410,7 @@ def run_parallel(cases, name, skiplist, args, max_workers=4): for case in cases: prefix = name + "__" + case["name"] if prefix in skiplist: - print("Skipping:", prefix) + print("Skipping:", prefix, flush=True) else: filtered.append(case) @@ -452,14 +486,14 @@ def run_parallel(cases, name, skiplist, args, max_workers=4): else: paths.append(args.cfg) - print("Args:", args) + print("Args:", args, flush=True) for path in paths: config_f = open(path, "r") config = json.load(config_f) config_f.close() name = config["name"] - print(f"Start testing: %s\n" % path) + print(f"Start testing: %s" % path, flush=True) run_parallel(config["cases"], name, skiplist, args, args.max_workers) write_failure_summary() diff --git a/netsim/sims/integration/adverse.json b/netsim/sims/integration/adverse.json index c22e9f0..c366053 100644 --- a/netsim/sims/integration/adverse.json +++ b/netsim/sims/integration/adverse.json @@ -15,7 +15,12 @@ "connect": { "strategy": "none" }, - "param_parser": "iroh_endpoint_with_addrs" + "param_parser": "iroh_endpoint_with_addrs", + "link": { + "bw": 4, + "latency": 200, + "loss": 0 + } }, { "name": "i_get", @@ -28,12 +33,7 @@ }, "process": "short", "parser": "iroh_cust_10M", - "integration": "magic_iroh_client", - "link": { - "bw": 4, - "latency": 200, - "loss": 0 - } + "integration": "magic_iroh_client" } ] }, @@ -51,7 +51,12 @@ "connect": { "strategy": "none" }, - "param_parser": "iroh_endpoint_with_addrs" + "param_parser": "iroh_endpoint_with_addrs", + "link": { + "bw": 8, + "latency": 200, + "loss": 1 + } }, { "name": "i_get", @@ -64,12 +69,7 @@ }, "process": "short", "parser": "iroh_cust_10M", - "integration": "magic_iroh_client", - "link": { - "loss": 1, - "bw": 8, - "latency": 200 - } + "integration": "magic_iroh_client" } ] }, @@ -107,7 +107,12 @@ "connect": { "strategy": "none" }, - "param_parser": "iroh_endpoint_with_addrs" + "param_parser": "iroh_endpoint_with_addrs", + "link": { + "bw": 4, + "latency": 200, + "loss": 0 + } }, { "name": "i_get", @@ -120,12 +125,7 @@ }, "process": "short", "parser": "iroh_cust_10M", - "integration": "magic_iroh_client", - "link": { - "bw": 4, - "latency": 200, - "loss": 0 - } + "integration": "magic_iroh_client" } ] }, @@ -163,7 +163,12 @@ "connect": { "strategy": "none" }, - "param_parser": "iroh_endpoint_with_addrs" + "param_parser": "iroh_endpoint_with_addrs", + "link": { + "bw": 8, + "latency": 200, + "loss": 1 + } }, { "name": "i_get", @@ -176,12 +181,7 @@ }, "process": "short", "parser": "iroh_cust_10M", - "integration": "magic_iroh_client", - "link": { - "loss": 1, - "bw": 8, - "latency": 200 - } + "integration": "magic_iroh_client" } ] }, @@ -209,7 +209,12 @@ "connect": { "strategy": "none" }, - "param_parser": "iroh_endpoint_with_addrs" + "param_parser": "iroh_endpoint_with_addrs", + "link": { + "bw": 4, + "latency": 200, + "loss": 0 + } }, { "name": "i_get", @@ -222,12 +227,7 @@ }, "process": "short", "parser": "iroh_cust_10M", - "integration": "magic_iroh_client", - "link": { - "bw": 4, - "latency": 200, - "loss": 0 - } + "integration": "magic_iroh_client" } ] }, @@ -255,7 +255,12 @@ "connect": { "strategy": "none" }, - "param_parser": "iroh_endpoint_with_addrs" + "param_parser": "iroh_endpoint_with_addrs", + "link": { + "bw": 8, + "latency": 200, + "loss": 1 + } }, { "name": "i_get", @@ -268,11 +273,66 @@ }, "process": "short", "parser": "iroh_cust_10M", - "integration": "magic_iroh_client", + "integration": "magic_iroh_client" + } + ] + }, + { + "name": "direct_to_relay_fallback", + "description": "Direct connection blocked mid-transfer, falls back to relay", + "visualize": true, + "nodes": [ + { + "name": "1_r", + "count": 1, + "cmd": "./bins/iroh-relay --dev --config-path ./data/relay.cfg", + "type": "public", + "wait": 2, + "connect": { + "strategy": "none" + } + }, + { + "name": "2_d", + "count": 1, + "cmd": "./bins/iroh-dns-server --config ./data/dns.test.cfg", + "type": "public", + "wait": 2, + "connect": { + "strategy": "none" + } + }, + { + "name": "i_srv", + "count": 1, + "cmd": "./bins/iroh-transfer provide --env dev --size=25M --relay-url=\"http://10.0.0.1:3340\" --pkarr-relay-url=\"http://10.0.0.2:8080/pkarr\" --dns-origin-domain=\"10.0.0.2:5300\"", + "type": "public", + "wait": 10, + "connect": { + "strategy": "none" + }, + "param_parser": "iroh_endpoint_with_addrs", "link": { - "loss": 1, "bw": 8, - "latency": 200 + "latency": 50, + "loss": 0 + } + }, + { + "name": "i_get", + "count": 1, + "cmd": "time ./bins/iroh-transfer fetch --env dev --relay-url=\"http://10.0.0.1:3340\" --remote-relay-url=\"http://10.0.0.1:3340\" --pkarr-relay-url=\"http://10.0.0.2:8080/pkarr\" --dns-origin-domain=\"10.0.0.2:5300\" --remote-direct-address=\"%s\" %s", + "type": "public", + "connect": { + "strategy": "params_with_parsed_addrs", + "node": "i_srv" + }, + "process": "short", + "parser": "iroh_cust_25M", + "integration": "magic_iroh_client", + "mid_run_action": { + "delay_seconds": 6, + "block_direct_to": "i_srv" } } ]