test(core): WLAN measured with Java FILIUS — a wireless cable is a cable, an SSID connects nothing

WlanRun pings on the new network wlan-lan: over wireless cables, over a
plain cable, and to and from a notebook on the switch's SSID without a
cable. The engine matches Java without a change: it runs the links only.
Swift's wirelessAssociations, which join a host to its SSID's switch at
run time, are not taken. ScenarioNetwork sets wireless cables, wireless
cards and SSIDs; a corpus test pings over the wireless cables of
multicast_server.fls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 08:04:18 +00:00
co-authored by Claude Opus 5.5
parent 7a77bc1b43
commit 65ccd9ddd7
14 changed files with 677 additions and 7 deletions
+29
View File
@@ -417,3 +417,32 @@ Threads zwischen Karte und Ethernet-Schicht sitzen):
(bei 90 % 55 Minuten), geprüft jede Sekunde, aufgefrischt nur von
eingehenden Paketen (aus dem Code, nicht gemessen).
## WLAN zur Laufzeit
`WlanRun` startet das Netz von `wlan-lan` (Notebooks 192.168.1.11 und .12
mit Funkkarte, je über ein Funkkabel am Switch mit der SSID „schule";
PC 192.168.1.13 an einem Kabel; Notebook 192.168.1.14 mit Funkkarte und
SSID „schule", aber ohne Kabel) und schreibt nach `wlan-java-<ablauf>.java.json`
die Frames und die Aufrufe. `ScenarioNetwork` setzt dazu `Kabel.setWireless`
nach dem Feld `wireless` eines Kabels, die SSID des Switches (`switches`)
und Funkkarte und SSID der Rechner (`wireless`). Abläufe: `pingWired` (.11
pingt .13), `pingWireless` (.11 pingt .12), `pingWithoutCable` (.11 pingt
.14), `pingFromWithoutCable` (.14 pingt .11).
Gemessen (01.10.2026), wie im Code (`Kabel.wireless`, `Betriebssystem.ssid`
liest nur die Oberfläche):
* Ein Funkkabel ist zur Laufzeit ein Kabel wie jedes andere: dieselben
Frames zu denselben Zeiten über Funk wie über Kabel (Ping 470 ms).
* Eine SSID verbindet nichts. Das Notebook ohne Kabel bleibt unerreichbar
(zweimal ARP, nach 5,5 s „Host unreachable" beim Absender), und es selbst
erreicht niemanden. Das Funkkabel legt nur Javas Editor
(`JHostKonfiguration.updateWifiConnection`: das alte entfernen, an den
Switch mit der SSID anschließen); ändert sich die SSID eines Switches,
entfernt er dessen Funkkabel, ohne neu zu verbinden. So entsteht in einer
Datei ein Rechner mit SSID ohne Kabel.
Swift verbindet zur Laufzeit jeden Rechner mit eingeschaltetem WLAN mit
einem freien Port des Switches seiner SSID, auch ohne Kabel
(`wirelessAssociations`). Der Kern folgt Java: Er kennt nur die Kabel.
+11 -1
View File
@@ -21,7 +21,7 @@ if [ ! -f "$upstream/target/filius.jar" ]; then
fi
classpath="$upstream/target/filius.jar:$upstream/target/lib/*"
mkdir -p "$here/.build"
javac -encoding UTF-8 -d "$here/.build" -cp "$classpath" "$here/src/FlsOracle.java" "$here/src/GetterDefaults.java" "$here/src/IpCheckCases.java" "$here/src/DnsHostsCases.java" "$here/src/EmailFileCases.java" "$here/src/BeansDump.java" "$here/src/Base64Cases.java" "$here/src/ScenarioNetwork.java" "$here/src/DhcpRun.java" "$here/src/TcpRun.java" "$here/src/DnsRun.java" "$here/src/ArpRun.java" "$here/src/RipRun.java" "$here/src/NatRun.java"
javac -encoding UTF-8 -d "$here/.build" -cp "$classpath" "$here/src/FlsOracle.java" "$here/src/GetterDefaults.java" "$here/src/IpCheckCases.java" "$here/src/DnsHostsCases.java" "$here/src/EmailFileCases.java" "$here/src/BeansDump.java" "$here/src/Base64Cases.java" "$here/src/ScenarioNetwork.java" "$here/src/DhcpRun.java" "$here/src/TcpRun.java" "$here/src/DnsRun.java" "$here/src/ArpRun.java" "$here/src/RipRun.java" "$here/src/NatRun.java" "$here/src/WlanRun.java"
# FILIUS writes its settings below $HOME; keep them out of the real one.
mkdir -p "$here/.build/home"
# Removed first: a crashed run must not leave the previous result standing.
@@ -183,3 +183,13 @@ for story in pingLan pingRouted udpTwice udpBehind routedUdpBehind routedPingBes
"$root/packages/core/test/scenarios/arp-routed.scenario.json" "$story" 16000 "$output" 2>&1 | grep -v 'logback\|^$' || true
test -s "$output"
done
# WLAN as Java FILIUS runs it: pings over wireless cables, a plain cable and
# to a host on the switch's SSID without a cable (WlanRun); frames and calls.
for story in pingWired pingWireless pingWithoutCable pingFromWithoutCable; do
output="$root/packages/core/test/scenarios/wlan-java-$story.java.json"
rm -f "$output"
HOME="$here/.build/home" xvfb-run -a java -cp "$classpath:$here/.build" WlanRun \
"$root/packages/core/test/scenarios/wlan-lan.scenario.json" "$story" 12000 "$output" 2>&1 | grep -v 'logback\|^$' || true
test -s "$output"
done
+15 -1
View File
@@ -1,5 +1,6 @@
// A core scenario's network (packages/core/test/scenarios/*.scenario.json:
// nodes, links, devices, dhcpServers, dhcpClients) built in Java FILIUS the
// nodes, links (wireless or not), devices, switches' and hosts' SSIDs,
// dhcpServers, dhcpClients, …) built in Java FILIUS the
// way the core reads it: a port's MAC is its `mac`, else the core's
// stableGeneratedMacAddress. Started as the action mode starts it (every
// system software's starten()); afterwards every frame each network card saw
@@ -22,8 +23,10 @@ import filius.rahmenprogramm.nachrichten.Lauscher;
import filius.software.dhcp.DHCPServer;
import filius.software.dns.DNSServer;
import filius.software.netzzugangsschicht.EthernetFrame;
import filius.software.system.Betriebssystem;
import filius.software.system.GatewayFirmware;
import filius.software.system.InternetKnotenBetriebssystem;
import filius.software.system.SwitchFirmware;
import filius.software.system.VermittlungsrechnerBetriebssystem;
import filius.software.transportschicht.Segment;
import filius.software.transportschicht.TcpSegment;
@@ -139,6 +142,17 @@ public class ScenarioNetwork {
Map<String, Object> link = map(each);
Kabel cable = new Kabel();
cable.setAnschluesse(new Port[] { ports.get(link.get("sourcePort")), ports.get(link.get("targetPort")) });
cable.setWireless(Boolean.TRUE.equals(link.get("wireless")));
}
// A switch's SSID, a host's wireless card and the SSID it joins: what the
// editor reads to lay a wireless cable; the simulation does not ask.
for (Map.Entry<String, Object> entry : map(scenario.getOrDefault("switches", new HashMap<>())).entrySet()) {
((SwitchFirmware) nodes.get(entry.getKey()).getSystemSoftware()).setSSID((String) map(entry.getValue()).get("ssid"));
}
for (Map.Entry<String, Object> entry : map(scenario.getOrDefault("wireless", new HashMap<>())).entrySet()) {
Betriebssystem os = (Betriebssystem) system(nodes.get(entry.getKey()));
os.nicWireless(true);
os.setSsid((String) map(entry.getValue()).get("ssid"));
}
for (Map.Entry<String, Object> entry : map(scenario.getOrDefault("dhcpServers", new HashMap<>())).entrySet()) {
Map<String, Object> config = map(entry.getValue());
+85
View File
@@ -0,0 +1,85 @@
// Runs wlan-lan's network in Java FILIUS (ScenarioNetwork) and records what a
// wireless connection does at run time: every frame each card saw and when
// each call started and ended.
//
// WlanRun <scenario.json> <story> <milliseconds> <out.json>
//
// Notebooks 192.168.1.11 and .12 with wireless cards on the switch's SSID
// "schule", each joined by a wireless cable; PC 192.168.1.13 on a plain
// cable; notebook 192.168.1.14 with a wireless card on "schule" but no cable
// (as after the switch's SSID changed: Java's editor removes the cable and
// does not lay it again). The stories:
// pingWired .11 pings .13
// pingWireless .11 pings .12
// pingWithoutCable .11 pings .14
// pingFromWithoutCable .14 pings .11
import filius.software.vermittlungsschicht.IcmpPaket;
import java.util.ArrayList;
import java.util.List;
public class WlanRun {
static final String NOTEBOOK = "00000000-0000-0000-0000-000000000601";
static final String UNCABLED = "00000000-0000-0000-0000-000000000605";
static ScenarioNetwork network;
static final List<Object[]> events = new ArrayList<>();
static synchronized void event(String what) {
events.add(new Object[] { System.currentTimeMillis() - network.start, what });
}
static String icmp(IcmpPaket packet) {
return packet == null ? "null" : "ICMP " + packet.getIcmpType() + "/" + packet.getIcmpCode() + " from " + packet.getSender();
}
static void ping(String from, String target) {
String label = "sendProbe " + target;
event(label + " called");
try {
event(label + " returned " + icmp(network.system(from).holeICMP().sendProbe(target, 64, 1, 1)));
} catch (Exception e) {
event(label + " failed " + e.getClass().getSimpleName());
}
}
public static void main(String[] args) throws Exception {
network = ScenarioNetwork.read(args[0]);
String story = args[1];
long end = Long.parseLong(args[2]);
network.start();
Thread.sleep(500);
switch (story) {
case "pingWired":
ping(NOTEBOOK, "192.168.1.13");
break;
case "pingWireless":
ping(NOTEBOOK, "192.168.1.12");
break;
case "pingWithoutCable":
ping(NOTEBOOK, "192.168.1.14");
break;
case "pingFromWithoutCable":
ping(UNCABLED, "192.168.1.11");
break;
default:
throw new IllegalArgumentException("unknown story " + story);
}
long rest = network.start + end - System.currentTimeMillis();
if (rest > 0) Thread.sleep(rest);
ScenarioNetwork.Json out = new ScenarioNetwork.Json();
out.open('{');
network.writeFrames(out);
synchronized (WlanRun.class) {
out.key("events").open('[');
for (Object[] each : events) out.open('[').number((Long) each[0]).string((String) each[1]).close(']');
out.close(']');
}
out.close('}');
network.stop();
ScenarioNetwork.write(args[3], out);
System.exit(0);
}
}