@@ -11,7 +11,7 @@ use dummynet::{PacketFilter, Pipe};
1111pub mod namespace;
1212
1313pub mod assert;
14- use assert :: assert_status ;
14+ pub mod ip_tc ;
1515
1616#[ derive( Debug ) ]
1717pub struct SimulationConfig {
@@ -129,142 +129,24 @@ impl Simulation {
129129 #[ cfg( target_os = "linux" ) ]
130130 fn start ( & self ) -> io:: Result < ( ) > {
131131 // Create network namespace
132- let network_namespace = self . namespace_name ( ) ;
133-
134- let status = Command :: new ( "sudo" )
135- . args ( [ "ip" , "netns" , "add" , & network_namespace] )
136- . status ( ) ?;
137-
138- assert_status ( status, "Failed to create namespace" ) ?;
139132
140- // Create Virtual Ethernet (veth) devices and link them
141- //
142- // Note: device name length can be max 15 chars long
133+ let network_namespace = self . namespace_name ( ) ;
143134 let veth_host = self . veth_host_name ( ) ;
144135 let veth_namespace = self . veth_namespace_name ( ) ;
145- let status = Command :: new ( "sudo" )
146- . args ( [
147- "ip" ,
148- "link" ,
149- "add" ,
150- & veth_host,
151- "type" ,
152- "veth" ,
153- "peer" ,
154- "name" ,
155- & veth_namespace,
156- ] )
157- . status ( ) ?;
158-
159- assert_status ( status, "Failed add veth devices" ) ?;
160-
161- // Move veth namespace device to its namespace
162- let status = Command :: new ( "sudo" )
163- . args ( [
164- "ip" ,
165- "link" ,
166- "set" ,
167- & veth_namespace,
168- "netns" ,
169- & network_namespace,
170- ] )
171- . status ( ) ?;
172-
173- assert_status ( status, "Failed move veth device to network namespace" ) ?;
174-
175136 let ip_namespace = format ! ( "{}/24" , self . endpoint) ;
176137
177- let mut ip_host: Vec < u64 > = self
178- . endpoint
179- . to_string ( )
180- . split ( '.' )
181- . map ( |octect| octect. parse :: < u64 > ( ) . unwrap ( ) )
182- . collect ( ) ;
183- ip_host[ 3 ] += 1 ;
184- let ip_host = format ! (
185- "{}.{}.{}.{}/24" ,
186- ip_host[ 0 ] , ip_host[ 1 ] , ip_host[ 2 ] , ip_host[ 3 ]
187- ) ;
138+ ip_tc:: create_namespace ( & network_namespace) ?;
139+ ip_tc:: create_veth_pair ( & veth_host, & veth_namespace) ?;
140+ ip_tc:: move_device_to_namespace ( & veth_namespace, & network_namespace) ?;
188141
189- // Associate IP address to host veth device and spin it up
190- let status = Command :: new ( "sudo" )
191- . args ( [ "ip" , "addr" , "add" , & ip_host, "dev" , & veth_host] )
192- . status ( ) ?;
193- assert_status ( status, "Failed to associate IP address to host veth device" ) ?;
194- let status = Command :: new ( "sudo" )
195- . args ( [ "ip" , "link" , "set" , & veth_host, "up" ] )
196- . status ( ) ?;
197- assert_status ( status, "Failed to set up the host veth device" ) ?;
198-
199- // Associate IP address to namespaced veth device and spin it up
200- let status = Command :: new ( "sudo" )
201- . args ( [
202- "ip" ,
203- "netns" ,
204- "exec" ,
205- & network_namespace,
206- "ip" ,
207- "addr" ,
208- "add" ,
209- & ip_namespace,
210- "dev" ,
211- & veth_namespace,
212- ] )
213- . status ( ) ?;
214- assert_status (
215- status,
216- "Failed to associate IP address to namespaced veth device" ,
217- ) ?;
218- let status = Command :: new ( "sudo" )
219- . args ( [
220- "ip" ,
221- "netns" ,
222- "exec" ,
223- & network_namespace,
224- "ip" ,
225- "link" ,
226- "set" ,
227- & veth_namespace,
228- "up" ,
229- ] )
230- . status ( ) ?;
231- assert_status ( status, "Failed to set up the namespaced veth device" ) ?;
232-
233- // Spin up also the loopback interface on namespaced environment
234- let status = Command :: new ( "sudo" )
235- . args ( [
236- "ip" ,
237- "netns" ,
238- "exec" ,
239- & network_namespace,
240- "ip" ,
241- "link" ,
242- "set" ,
243- "lo" ,
244- "up" ,
245- ] )
246- . status ( ) ?;
247- assert_status ( status, "Failed to set up the namespaced loopback device" ) ?;
142+ let ip_host = ip_tc:: gen_host_ip_address ( & self . endpoint ) ;
248143
249- // Add network emulation parameters (delay, loss) on namespaced veth device
250- //
251- // The behaviour is specified on the top-level ("root"),
252- // with a custom handle for identification
253- let mut args = vec ! [
254- "ip" ,
255- "netns" ,
256- "exec" ,
257- & network_namespace,
258- "tc" ,
259- "qdisc" ,
260- "add" ,
261- "dev" ,
262- & veth_namespace,
263- "root" ,
264- "handle" ,
265- "1:" ,
266- "netem" ,
267- ] ;
144+ ip_tc:: add_ip_addr_to_device ( & veth_host, & ip_host, None ) ?;
145+ ip_tc:: spin_up_device ( & veth_host, None ) ?;
146+
147+ ip_tc:: add_ip_addr_to_device ( & veth_namespace, & ip_namespace, Some ( & network_namespace) ) ?;
148+ ip_tc:: spin_up_device ( & veth_namespace, Some ( & network_namespace) ) ?;
149+ ip_tc:: spin_up_device ( "lo" , Some ( & network_namespace) ) ?;
268150
269151 let delay = format ! (
270152 "{}ms" ,
@@ -274,34 +156,30 @@ impl Simulation {
274156 . as_millis( )
275157 ) ;
276158
159+ let loss = format ! ( "{}%" , self . config. plr. unwrap_or( 0_f64 ) ) ;
160+
161+ // Add delay to the host veth device to match MacOS symmetric behaviour
162+ //
163+ // The behaviour is specified on the top-level ("root"),
164+ // with a custom handle for identification
165+ let mut args = vec ! [ "root" , "handle" , "1:" , "netem" ] ;
277166 if self . config . latency . is_some ( ) {
278167 args. push ( "delay" ) ;
279168 args. push ( & delay) ;
280169 }
170+ ip_tc:: add_network_emulation_parameters ( & veth_host, args, None ) ?;
281171
282- let loss = format ! ( "{}%" , self . config. plr. unwrap_or( 0_f64 ) ) ;
283-
172+ // Add network emulation parameters (delay, loss) on namespaced veth device
173+ let mut args = vec ! [ "root" , "handle" , "1:" , "netem" ] ;
174+ if self . config . latency . is_some ( ) {
175+ args. push ( "delay" ) ;
176+ args. push ( & delay) ;
177+ }
284178 if ( self . config . plr ) . is_some ( ) {
285179 args. push ( "loss" ) ;
286180 args. push ( & loss) ;
287181 }
288-
289- let status = Command :: new ( "sudo" ) . args ( args) . status ( ) ?;
290-
291- assert_status (
292- status,
293- "Failed to set delay and loss network emulation parameters to namespaced device" ,
294- ) ?;
295-
296- // Add delay to the host veth device to match MacOS symmetric behaviour
297- let status = Command :: new ( "sudo" )
298- . args ( [
299- "tc" , "qdisc" , "add" , "dev" , & veth_host, "root" , "handle" , "1:" , "netem" , "delay" ,
300- & delay,
301- ] )
302- . status ( ) ?;
303-
304- assert_status ( status, "Failed to set delay to the host veth device" ) ?;
182+ ip_tc:: add_network_emulation_parameters ( & veth_namespace, args, Some ( & network_namespace) ) ?;
305183
306184 // Add bandwidth paramteres on namespaced veth device
307185 //
@@ -312,47 +190,16 @@ impl Simulation {
312190 let burst = format ! ( "{}kbit" , self . config. burst. unwrap_or( 32 ) ) ;
313191 let limit = format ! ( "{}" , self . config. limit. unwrap_or( 10_000 ) ) ;
314192
315- let status = Command :: new ( "sudo" )
316- . args ( [
317- "ip" ,
318- "netns" ,
319- "exec" ,
320- & network_namespace,
321- "tc" ,
322- "qdisc" ,
323- "add" ,
324- "dev" ,
325- & veth_namespace,
326- "parent" ,
327- "1:" ,
328- "handle" ,
329- "2:" ,
330- "tbf" ,
331- "rate" ,
332- & bandwidth,
333- "burst" ,
334- & burst,
335- "limit" ,
336- & limit,
337- ] )
338- . status ( ) ?;
339-
340- assert_status (
341- status,
342- "Failed to set bandwidth parameter to the namespaced device" ,
343- ) ?;
193+ let args = vec ! [
194+ "parent" , "1:" , "handle" , "2:" , "tbf" , "rate" , & bandwidth, "burst" , & burst,
195+ "limit" , & limit,
196+ ] ;
344197
345- // Add bandwidth paramteres on host veth device
346- let status = Command :: new ( "sudo" )
347- . args ( [
348- "tc" , "qdisc" , "add" , "dev" , & veth_host, "parent" , "1:" , "handle" , "2:" , "tbf" ,
349- "rate" , & bandwidth, "burst" , & burst, "limit" , & limit,
350- ] )
351- . status ( ) ?;
352-
353- assert_status (
354- status,
355- "Failed to set bandwidth parameter to the host veth device" ,
198+ ip_tc:: add_network_emulation_parameters ( & veth_host, args. clone ( ) , None ) ?;
199+ ip_tc:: add_network_emulation_parameters (
200+ & veth_namespace,
201+ args,
202+ Some ( & network_namespace) ,
356203 ) ?;
357204 }
358205 Ok ( ( ) )
0 commit comments