route: direct route support — dev eth0 syntax without gateway

parse_route now supports three syntaxes:
  default via 10.0.2.2 metric 100   — gatewayed route (existing)
  10.0.0.0/8 via 10.0.0.1          — subnet route (existing)
  10.0.0.0/8 dev eth0              — direct route (NEW)

Direct routes use via=None (no gateway), dev=specified, src=0.0.0.0.
The routing layer will use the interface's configured IP as source.

Mirrors Linux:
  ip route add 10.0.0.0/8 dev eth0

Route flush (R61) also included: echo > /scheme/netcfg/route/flush

All 31 tests pass.
This commit is contained in:
Red Bear OS
2026-07-09 11:19:23 +03:00
parent 9dcd809778
commit d3836e9eb2
+33 -15
View File
@@ -75,23 +75,41 @@ fn parse_route(value: &str, route_table: &RouteTable) -> SyscallResult<Rule> {
.map_err(|_| SyscallError::new(syscall::EINVAL))?,
};
let via: IpAddress = match parts.next().ok_or(SyscallError::new(syscall::EINVAL))? {
"via" => parts
.next()
.ok_or(SyscallError::new(syscall::EINVAL))?
.parse()
.map_err(|_| SyscallError::new(syscall::EINVAL))?,
let dev;
let via;
let src;
// Accept "via <ip>" or "dev <name>" or both.
match parts.next() {
Some("via") => {
let gw: IpAddress = parts
.next()
.ok_or(SyscallError::new(syscall::EINVAL))?
.parse()
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
if !gw.is_unicast() {
return Err(SyscallError::new(syscall::EINVAL));
}
let rule = route_table
.lookup_rule(&gw)
.ok_or(SyscallError::new(syscall::EINVAL))?;
via = Some(gw);
dev = rule.dev.clone();
src = rule.src;
}
Some("dev") => {
dev = parts
.next()
.ok_or(SyscallError::new(syscall::EINVAL))?
.into();
via = None;
// Use 0.0.0.0 as source for direct routes — the routing
// layer will pick the correct source IP when sending.
src = IpAddress::v4(0, 0, 0, 0);
}
_ => return Err(SyscallError::new(syscall::EINVAL)),
};
if !via.is_unicast() {
return Err(SyscallError::new(syscall::EINVAL));
}
let rule = route_table
.lookup_rule(&via)
.ok_or(SyscallError::new(syscall::EINVAL))?;
let mut metric: u32 = 0;
if let Some(keyword) = parts.next() {
if keyword == "metric" {
@@ -105,7 +123,7 @@ fn parse_route(value: &str, route_table: &RouteTable) -> SyscallResult<Rule> {
}
}
Ok(Rule::new(cidr, Some(via), rule.dev.clone(), rule.src).with_metric(metric))
Ok(Rule::new(cidr, via, dev, src).with_metric(metric))
}
fn mk_root_node(