@@ -15,6 +15,8 @@ use tracing::info;
1515
1616pub struct DhcpActor {
1717 pub config : DhcpConfig ,
18+ bridge : String ,
19+ dnsmasq_process : Option < tokio:: process:: Child > ,
1820}
1921
2022pub struct NetworkConfigCommon {
@@ -23,11 +25,49 @@ pub struct NetworkConfigCommon {
2325}
2426
2527impl 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