Repository navigation
Conversation
… stick One boot, `outbound`, on a new `tests/outboundcase`: netstack on the T14's I219 and one job, `outbound`, which waits for netstack's own word on its lease, asks `inspect` what netstack holds, looks up two public resolver services by name and opens one connection to port 443 of each, writing no byte, and says each fact as a line the moment it knows it. Two rows read that boot: `outbound_router` is red by the first step that failed (the card, its link, the lease, the router's link address, the resolver on the link), and `outbound_internet` is green when one anchor connected and is judged only over a green router row. The job is written against the pipe ABI and the inspect keys alone, so the same source runs on the stack `main` ships and on the one that replaces it. The router's neighbour entry is a key the replacement adds; where it is absent the job says `not-asked` and the row does not judge it. netstack's lines are in its own ring and in no record the kernel's cursor serves, so the job reads them where `counters_metal` reads its own: on logkeeper's `log` port, woken by the pipe. That reader moves out of `counters_metal` into `served_log.rs` for both. A line is a `Line` (`outbound_said.rs`), compiled into the job and into the judges: words of a closed list and counts. The judges write a verdict from what a line read as and never from the log's text, and a line outside the vocabulary is counted and not quoted. `src/build.rs`'s `ALL_CONFIGS` gains the new config's row: the gate beside it reds on a `system.toml` the list does not name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
|
Negative controls at
diff --git a/tests/common/outbound.rs b/tests/common/outbound.rs
index 7cb70ad1e..0343b43fe 100644
--- a/tests/common/outbound.rs
+++ b/tests/common/outbound.rs
@@ -185,7 +185,7 @@ fn reached_router(kernel: &Serial, said: &Said) -> Result<(), String> {
return Err(format!("netstack drives `{}`, which is not this machine's wired card", card.driver.word()));
}
let frames = format!("the card counts {} frame(s) sent and {} received", card.sent, card.received);
- if card.link != Link::Up {
+ if false {
return Err(format!("no link: the card's link is `{}`; {frames}", card.link.word()));
}
let lease = said.lease()?;
diff --git a/tests/common/outbound.rs b/tests/common/outbound.rs
index 7cb70ad1e..43f4904ce 100644
--- a/tests/common/outbound.rs
+++ b/tests/common/outbound.rs
@@ -235,7 +235,7 @@ fn reached_router(kernel: &Serial, said: &Said) -> Result<(), String> {
return Err(format!("the resolver the lease names {stands}, and {whose}"));
}
}
- if !said.lines.contains(&Line::Done) {
+ if false {
return Err(said.ended_before("its last line"));
}
Ok(())
diff --git a/tests/common/outbound.rs b/tests/common/outbound.rs
index 7cb70ad1e..b1801261d 100644
--- a/tests/common/outbound.rs
+++ b/tests/common/outbound.rs
@@ -248,7 +248,7 @@ pub fn internet(kernel: &Serial, log: &Serial) -> Result<(), String> {
eprintln!(" [outbound] the internet is not judged: the router row is red");
return Ok(());
};
- if reached_router(kernel, &said).is_err() {
+ if false {
eprintln!(" [outbound] the internet is not judged: the router row is red");
return Ok(());
}
diff --git a/tests/toyos-rust-tests/src/outbound_said.rs b/tests/toyos-rust-tests/src/outbound_said.rs
index 65107111f..01a44b825 100644
--- a/tests/toyos-rust-tests/src/outbound_said.rs
+++ b/tests/toyos-rust-tests/src/outbound_said.rs
@@ -222,7 +222,7 @@ impl Line {
let said = text.strip_prefix(HEAD)?;
let line = Self::read_said(said);
// Byte for byte what it reads as, so nothing rides a line beside its words.
- Some(line.filter(|line| line.to_string() == text))
+ Some(line)
}
fn read_said(said: &str) -> Option<Self> {
diff --git a/tests/common/outbound.rs b/tests/common/outbound.rs
index 7cb70ad1e..50fb50035 100644
--- a/tests/common/outbound.rs
+++ b/tests/common/outbound.rs
@@ -68,7 +68,7 @@ impl Said {
.filter_map(|said| Line::read(said.text));
for (nth, line) in said.enumerate() {
let line = line.ok_or_else(|| {
- format!(
+ format!("{}", log.text()) + &format!(
"the job's `{}` line {} is none its vocabulary writes. It is not quoted: a line \
outside the vocabulary can hold anything",
said::HEAD.trim_end(),
diff --git a/tests/common/outbound.rs b/tests/common/outbound.rs
index 7cb70ad1e..d4a70d1ec 100644
--- a/tests/common/outbound.rs
+++ b/tests/common/outbound.rs
@@ -212,7 +212,7 @@ fn reached_router(kernel: &Serial, said: &Said) -> Result<(), String> {
let through = matches!(lease.resolver, Resolver::Router | Resolver::OffLink)
|| anchors.iter().any(|a| a.connect != Connect::NotTried);
let gateway = said.gateway()?;
- if through && gateway.answered() == Some(false) {
+ if false {
return Err(format!(
"the router did not answer for its link address: netstack's neighbour entry for it is `{}`",
gateway.word()
diff --git a/tests/common/outbound.rs b/tests/common/outbound.rs
index 7cb70ad1e..26e36a54f 100644
--- a/tests/common/outbound.rs
+++ b/tests/common/outbound.rs
@@ -64,7 +64,6 @@ impl Said {
.text()
.lines()
.filter_map(toyos_logstream::program_line)
- .filter(|said| said.tag == RUNNER)
.filter_map(|said| Line::read(said.text));
for (nth, line) in said.enumerate() {
let line = line.ok_or_else(|| {
diff --git a/tests/toyos-rust-tests/src/outbound_said.rs b/tests/toyos-rust-tests/src/outbound_said.rs
index 65107111f..882d98f0b 100644
--- a/tests/toyos-rust-tests/src/outbound_said.rs
+++ b/tests/toyos-rust-tests/src/outbound_said.rs
@@ -277,7 +277,7 @@ pub fn resolver(address: &str, router: Option<&str>, dns: &str) -> Option<Resolv
let server: Ipv4Addr = server.parse().ok()?;
let stands = if Some(server) == router {
Resolver::Router
- } else if u32::from(server) & mask == address & mask {
+ } else if true {
Resolver::OnLink
} else {
Resolver::OffLink
diff --git a/tests/common/outbound.rs b/tests/common/outbound.rs
index 7cb70ad1e..474b0cad8 100644
--- a/tests/common/outbound.rs
+++ b/tests/common/outbound.rs
@@ -221,7 +221,7 @@ fn reached_router(kernel: &Serial, said: &Said) -> Result<(), String> {
if matches!(lease.resolver, Resolver::Router | Resolver::OnLink) {
// Any answer but silence: a resolver that says no has answered.
let answered =
- |a: &Reached| matches!(a.lookup, Lookup::Addresses | Lookup::NoAddress | Lookup::Failed);
+ |a: &Reached| matches!(a.lookup, Lookup::Addresses | Lookup::NoAddress | Lookup::Failed | Lookup::Timeout);
if !anchors.iter().any(answered) {
let stands = match lease.resolver {
Resolver::Router => "is the router",
diff --git a/tests/common/outbound.rs b/tests/common/outbound.rs
index 7cb70ad1e..40eb9745f 100644
--- a/tests/common/outbound.rs
+++ b/tests/common/outbound.rs
@@ -189,7 +189,7 @@ fn reached_router(kernel: &Serial, said: &Said) -> Result<(), String> {
return Err(format!("no link: the card's link is `{}`; {frames}", card.link.word()));
}
let lease = said.lease()?;
- if !lease.held {
+ if false {
return Err(match (card.sent.0, card.received.0) {
(Some(0), _) => format!("no lease, and {frames}: ToyOS asked for none on a link that is up"),
(_, Some(0)) => format!( |
|
T14 run at
The job said (classes only, as it prints them): Read from the stick's log beside it: the wired card was handed over once; one lease line, This is the first T14 row to read the wired card's server since the claims binding landed, and it needed nothing from the host while the machine ran. |
|
Closed by the orchestrator. The move it waited on (#801) landed, but the owner's later testing ruling, now in #848, says a test reaches no internet and no other machine. |
This lands behind the move of netstack onto ToyOS's own stack and must not be merged before it. The owner ruled "no smoltcp.": no new test is built on the old stack. It is a draft on purpose; it is flashed once as it stands (the base netstack) for the move's "before", and again stacked on the move.
Head
ac7d915f2, onorigin/main35d35859e.What it is
The owner: "the t14 ... has the router in lan it can connect to and it should be able to connect to the internet. lets change the tests so it tries to connect to the internet and writes its log to the stick which can be tested."
outbound, on a newtests/outboundcase: netstack onpci:8086:15fc, the row no config has had sincelantalkcasewent, and one job.outbound: waits for netstack's own word on its lease; asksinspectonce; fordns.googleanddns.quad9.netside by side, one name lookup and one connect to port 443 of the first address with 5 s, closed with no byte written; asksinspectagain for the router's neighbour entry; exits 0. Each fact is a line the moment it is known.outbound_routeris red by the first step that failed, in the order a frame needs them: the kernel handed8086:15fcover; netstack found a card; the link is up; a lease is held; it names a router; the router answered for its link address, where anything left by it; a resolver that is the router or on the link gave one lookup any answer but silence; the job finished.outbound_internetis green when at least one anchor connected and says which. It is judged only over a green router row; over a red one it prints "not judged" and passes, so one cause reds one row. When neither connected: an answer that was "no" (a refused or reset connect, a resolver's negative answer) says "the uplink or the service"; netstack ending a request itself says ToyOS; silence says plainly that this log cannot tell ToyOS from the uplink. No reading is taken on the machine's other operating system.No button is pressed: the boot ends itself by its job list like every metal boot.
Decisions the brief left open, or that differ from it
logport, not on the log capability. The brief said to wait "through the log capability asinbox_log_post.rsdoes". That cursor serves the kernel's records only: a program's lines are in its own ring (toyos/src/log/mod.rs), and netstack's lease line issay!. The tree's reader of program lines from a job iscounters_metal'sLog, woken by the pipe and bounded by a ceiling that panics by name. It moves totests/toyos-rust-tests/src/served_log.rsand both jobs use it, so there is one. So the config's test-runner holdslogand no syscap at all, notlogread.toyos::netdirectly, not std. std folds a name with no address and every lookup failure into oneOther(sdk/std/sys/net/connection.rs), and the router row needs "answered no" apart from silence.tests/toyos-rust-tests/src/outbound_said.rsis#[path]-included by the job and bytests/common/outbound.rs. ALineholds words of closed lists and counts; the job can write nothing else, and the judges write every verdict from what a line read as, never from the log's text. A line outside the vocabulary is counted and not quoted.discover=1 offer=1; netstack'sinspectanswer counts no DHCP message on either stack. The row uses what the Intel driver already answers,net.wire.sentandnet.wire.received: no lease with nothing received says the wire; no lease with frames received says the log cannot tell a silent DHCP server from ToyOS not taking an offer. That is weaker than the plan asked and is a present weakness of the row.not-asked, one word, for the neighbour entry a stack does not say: every value of a line is one word.netstack: no NIC on this machine, exiting, so a boot whose netstack was endowed nothing saysno-cardat once instead of running into the ceiling.tests/:src/build.rs'sALL_CONFIGSgainstests/outboundcase/system.toml.every_shipped_boot_config_is_coveredreds on a config the list does not name, so the config the brief asks for cannot exist without it.What the rows could not get from the pipe ABI
ERR_CONNECTION_REFUSEDfor a reset and has no word for an ICMP unreachable.ERR_OTHERcame from a reply. On the base it does (Truncated,ServerFailed,TooManyAliases), and the router row reads it as an answer.What the move must keep for this branch to build and judge on it
netstack: DHCP: lease,netstack: DHCP: no lease asandnetstack: no NIC on this machine, exiting, under the tagnetstack.net.driver(i219on the T14),net.link.state,net.lease.held,net.lease.addressas address/prefix,net.lease.router(absent for none),net.lease.dns(space between two), andnet.wire.sentandnet.wire.receivedas counts.toyos::net::dns_lookupandtcp_connectwith their present signatures;NetError::{TimedOut, Io, NotConnected, ConnectionRefused, ConnectionReset}meaning what they mean now. The job matches the rest with a wildcard, so a new variant builds.ERR_OTHERfrom a lookup only where a reply arrived, or a new word for the rest.net.neighbour.router, text, one ofreachable stale delay probe incomplete unreachable failed none. Any other word panics the job by name.logkeeperservinglog.Time
By arithmetic from constants, measured from boot against the runner's 60 s (
toyos_tco::JOB_BOUND_MS): the T14's recordedBoot: completeis 1.2 s (tests/metal/lenovo-20w0003amz.toml); netstack says it has no lease 20 s after it came up; a lookup is at most 3 resolvers × 3 rounds × 2 s = 18 s; a connect has 5 s; the anchors run side by side. 1.2 + 20 + 18 + 5 = 44.2 s. The ceiling on netstack's word is 30 s (its 20 s and two of logkeeper's 5 s rounds), and that path runs no anchor.Measured in a guest, as a development aid (x86-64 under TCG on an arm64 host,
tests/outboundcasewith the virtio id, a temporary unregistered machine test, reverted). Times are the guest's own log clock from the job's spawn record tooutbound: done; the host'suptimeload averages are beside each because the machine was in power-saving mode with several agents building.netstack said=lease;card driver=virtio-net link=unreported sent=unreported received=unreported;lease held=yes router=named resolver=on-link; both anchorslookup=addresses connect=connected;gateway neighbour=not-asked;donerestrict=onnetstack said=lease;lease held=yes router=none resolver=none; both anchorslookup=no-resolver connect=not-tried;gateway neighbour=not-asked;donenetstack said=no-lease;lease held=no router=none resolver=none;doneThe longest measured is 20.39 s: netstack's own 20 s bound, and its word reached the job 340 ms after netstack said it. All three exited 0; none hit a ceiling. Not measured: a lookup that times out and a connect that times out. slirp answers both, so those 18 s and 5 s are arithmetic only until the T14 or the move's guest arms show them.
Gates
Each is the command's own exit code, at
ac7d915f2unless said.cargo test --test toyos-checks(39 tests, the three new ones among them)cargo test --lib(352 passed;every_shipped_boot_config_is_covered, the config gates and the source gate among them)cargo run -- --clippy(24 invocations clean)cargo run -- --build-onlycargo test --test toyos-build -- --metal --list, base: 64 registrations, 229 shared members, 26 boots--metal --metal-readback <hand-made green> boot:outbound: both rows PASS--metal --metal-readback <hand-made, both anchors silent> boot:outbound: router PASS, internet FAIL "this log cannot tell ToyOS from the uplink"--metal --metal-readback <hand-made, no lease> boot:outbound: router FAIL "nothing on this wire answered", internet "not judged" PASS--metal --metal-readback <dir> boot:outbound, staging the imageThe checks, the library tests, clippy and the image build ran on the tree that became
ac7d915f2, before the commit. Not run, by the brief:cargo run -- --ci hostand the guest suite.counters_metalchanged by a move only and was compiled, not run: its row is the T14's.No guest test is added. The rows are metal rows because their subject is the I219 and the bench's network, which no guest has.
Negative controls
Ten mutations, each a checked patch applied to
ac7d915f2, built, run withcargo test --test toyos-checks -- outbound, and reversed; the patches are in the comment below.metal_outbound_rows_are_red_by_their_causemetal_outbound_line_holds_no_addressand the sameoutbound:lines are the job'smetal_outbound_resolver_stands_where_the_lease_puts_itmetal_outbound_rows_are_red_by_their_causeThe oracle is real hardware and a network ToyOS did not write: the T14's I219, the bench's router and DHCP server, and two public services. That reading is the orchestrator's and is not in this body yet.
Privacy
The job prints
Lines, which hold no address, MAC or host name. The fixtures use RFC 5737 addresses and a locally administered MAC, carry netstack's own lease line, and every verdict over them is scanned for a dotted quad, a MAC and netstack's host name. netstack's lines stay on the stick and the development machine.Unsure, and owed at landing
issues/toyos-has-its-own-network-stack.mdsays no T14 row reads the wired card, andissues/the-host-cannot-reach-the-t14-while-it-runs-toyos.mdsays the same under "What stands in the meantime". Both become false when this lands. They are not edited here: the track is rewritten by the stages in front of this, and the edit belongs to the rebase onto the move.boot.outbound.*totests/metal/lenovo-20w0003amz.toml, which is committed with the rows.git diff --shortstat origin/main...HEAD), nearly all of it undertests/: the job, its vocabulary and the moved reader, the judges, and the fixtures.🤖 Generated with Claude Code
https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A