Skip to content

Commit 9c4fa5c

Browse files
committed
spawn dnsmasq
1 parent 6b5d1dc commit 9c4fa5c

2 files changed

Lines changed: 53 additions & 11 deletions

File tree

odorobo-agent/src/actor/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ fn default_upstream_iface() -> String {
7373
pub struct DhcpConfig {
7474
pub upstream_iface: String,
7575
pub range: (Ipv4Addr, Ipv4Addr),
76-
pub mask: Ipv4Net,
76+
pub subnet: Ipv4Net,
7777
/// lease time for DHCP clients
7878
///
7979
/// example: 12h, 6h, 30m

odorobo-agent/src/networking/actor.rs

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use tracing::info;
1515

1616
pub struct DhcpActor {
1717
pub config: DhcpConfig,
18+
bridge: String,
19+
dnsmasq_process: Option<tokio::process::Child>,
1820
}
1921

2022
pub struct NetworkConfigCommon {
@@ -23,11 +25,49 @@ pub struct NetworkConfigCommon {
2325
}
2426

2527
impl Actor for DhcpActor {
26-
type Args = DhcpConfig;
28+
type Args = (DhcpConfig, String);
2729
type Error = Report;
2830
async fn on_start(args: Self::Args, _actor_ref: ActorRef<Self>) -> Result<Self, Self::Error> {
29-
// todo: actually run dnsmasq on startup
30-
Ok(Self { config: args })
31+
let (config, bridge) = args;
32+
let dhcp_range = format!(
33+
"{},{},{},{}",
34+
config.range.0,
35+
config.range.1,
36+
config.subnet.netmask(),
37+
config.lease_time
38+
);
39+
40+
let dnsmasq_process = tokio::process::Command::new("dnsmasq")
41+
.arg("--interface")
42+
.arg(&bridge)
43+
.arg("--bind-interfaces")
44+
.arg("--dhcp-range")
45+
.arg(&dhcp_range)
46+
.arg("--no-daemon")
47+
.spawn()
48+
.wrap_err_with(|| format!("failed to start dnsmasq on bridge {bridge}"))?;
49+
50+
Ok(Self {
51+
config,
52+
bridge,
53+
dnsmasq_process: Some(dnsmasq_process),
54+
})
55+
}
56+
57+
async fn on_stop(
58+
&mut self,
59+
_actor_ref: WeakActorRef<Self>,
60+
_reason: ActorStopReason,
61+
) -> std::result::Result<(), Self::Error> {
62+
if let Some(mut dnsmasq_process) = self.dnsmasq_process.take() {
63+
dnsmasq_process
64+
.start_kill()
65+
.wrap_err_with(|| format!("failed to stop dnsmasq on bridge {}", self.bridge))?;
66+
67+
let _ = dnsmasq_process.wait().await;
68+
}
69+
70+
Ok(())
3171
}
3272
}
3373

@@ -200,7 +240,7 @@ impl NetworkAgentActor {
200240
/// NAT/NAT66 policy as well. That is a larger design decision than this
201241
/// hook should make on its own. Until odorobo has an intentional IPv6
202242
/// guest-networking story, we keep host-only NAT scoped to IPv4.
203-
///
243+
///
204244
// todo: IPv6, refer to libvirt's impl:
205245
// ```nft
206246
// table ip6 libvirt_network {
@@ -210,22 +250,21 @@ impl NetworkAgentActor {
210250
// counter packets 0 bytes 0 jump guest_input
211251
// counter packets 0 bytes 0 jump guest_output
212252
// }
213-
253+
214254
// chain guest_output {
215255
// }
216-
256+
217257
// chain guest_input {
218258
// }
219-
259+
220260
// chain guest_cross {
221261
// }
222-
262+
223263
// chain guest_nat {
224264
// type nat hook postrouting priority srcnat; policy accept;
225265
// }
226266
// }
227267
// ```
228-
229268

230269
fn ensure_nat_rules(_bridge: &str, _subnet: &str, upstream_iface: &str) -> Result<(), Report> {
231270
const TABLE_NAME: &str = "odorobo";
@@ -337,7 +376,10 @@ impl Actor for NetworkAgentActor {
337376
};
338377

339378
let dhcp_actor = if let Some(dhcp_config) = &args.dhcp_config {
340-
Some(DhcpActor::spawn_link(&actor_ref, dhcp_config.clone()).await)
379+
Some(
380+
DhcpActor::spawn_link(&actor_ref, (dhcp_config.clone(), common.bridge.clone()))
381+
.await,
382+
)
341383
} else {
342384
None
343385
};

0 commit comments

Comments
 (0)