1- use std:: collections:: linked_list:: { self , LinkedList } ;
21use std:: mem;
32use std:: rc:: Rc ;
43use std:: result;
@@ -43,6 +42,13 @@ impl NetworkInterfaceConfig {
4342 } )
4443 }
4544
45+ fn update_from_body ( & mut self , mut body : NetworkInterfaceBody ) {
46+ self . id = Rc :: new ( mem:: replace ( & mut body. iface_id , String :: new ( ) ) ) ;
47+ self . rx_rate_limiter = body. rx_rate_limiter . take ( ) ;
48+ self . tx_rate_limiter = body. tx_rate_limiter . take ( ) ;
49+ self . body = body;
50+ }
51+
4652 pub fn id_as_str ( & self ) -> & str {
4753 self . id . as_str ( )
4854 }
@@ -57,36 +63,61 @@ impl NetworkInterfaceConfig {
5763}
5864
5965pub struct NetworkInterfaceConfigs {
60- // We use just a list for now, since we only add interfaces as this point.
61- if_list : LinkedList < NetworkInterfaceConfig > ,
66+ if_list : Vec < NetworkInterfaceConfig > ,
6267}
6368
6469impl NetworkInterfaceConfigs {
6570 pub fn new ( ) -> Self {
6671 NetworkInterfaceConfigs {
67- if_list : LinkedList :: new ( ) ,
72+ if_list : Vec :: new ( ) ,
6873 }
6974 }
7075
7176 pub fn put ( & mut self , body : NetworkInterfaceBody ) -> result:: Result < SyncOkStatus , SyncError > {
77+ match self . if_list
78+ . iter ( )
79+ . position ( |netif| netif. id . as_str ( ) == body. iface_id . as_str ( ) )
80+ {
81+ Some ( index) => self . update ( index, body) ,
82+ None => self . create ( body) ,
83+ }
84+ }
85+
86+ pub fn iter_mut ( & mut self ) -> :: std:: slice:: IterMut < NetworkInterfaceConfig > {
87+ self . if_list . iter_mut ( )
88+ }
89+
90+ fn create ( & mut self , body : NetworkInterfaceBody ) -> result:: Result < SyncOkStatus , SyncError > {
91+ self . validate_unique_mac ( & body. guest_mac ) ?;
7292 let cfg = NetworkInterfaceConfig :: try_from_body ( body) . map_err ( SyncError :: OpenTap ) ?;
73- for device_config in self . if_list . iter_mut ( ) {
74- if device_config. id_as_str ( ) == cfg. id_as_str ( ) {
75- device_config. tap = cfg. tap ;
76- device_config. body = cfg. body . clone ( ) ;
77- return Ok ( SyncOkStatus :: Updated ) ;
78- }
93+ self . if_list . push ( cfg) ;
94+ Ok ( SyncOkStatus :: Created )
95+ }
7996
80- if cfg. guest_mac ( ) . is_some ( ) && device_config. guest_mac ( ) == cfg. guest_mac ( ) {
81- return Err ( SyncError :: GuestMacAddressInUse ) ;
82- }
97+ fn update (
98+ & mut self ,
99+ index : usize ,
100+ body : NetworkInterfaceBody ,
101+ ) -> result:: Result < SyncOkStatus , SyncError > {
102+ if self . if_list [ index] . body . host_dev_name != body. host_dev_name {
103+ // This is a new tap device which replaces the one at the specified ID.
104+ self . if_list . remove ( index) ;
105+ self . create ( body) ?;
106+ } else {
107+ // The same tap device is being updated.
108+ self . validate_unique_mac ( & body. guest_mac ) ?;
109+ self . if_list [ index] . update_from_body ( body) ;
83110 }
84- self . if_list . push_back ( cfg) ;
85- Ok ( SyncOkStatus :: Created )
111+ Ok ( SyncOkStatus :: Updated )
86112 }
87113
88- pub fn iter_mut ( & mut self ) -> linked_list:: IterMut < NetworkInterfaceConfig > {
89- self . if_list . iter_mut ( )
114+ fn validate_unique_mac ( & self , mac : & Option < MacAddr > ) -> result:: Result < ( ) , SyncError > {
115+ for device_config in self . if_list . iter ( ) {
116+ if mac. is_some ( ) && mac == & device_config. body . guest_mac {
117+ return Err ( SyncError :: GuestMacAddressInUse ) ;
118+ }
119+ }
120+ Ok ( ( ) )
90121 }
91122}
92123
@@ -96,37 +127,68 @@ mod tests {
96127 use api_server:: request:: sync:: DeviceState ;
97128 use net_util:: MacAddr ;
98129
130+ fn make_netif ( id : & str , name : & str , mac : MacAddr ) -> NetworkInterfaceBody {
131+ NetworkInterfaceBody {
132+ iface_id : String :: from ( id) ,
133+ state : DeviceState :: Attached ,
134+ host_dev_name : String :: from ( name) ,
135+ guest_mac : Some ( mac) ,
136+ rx_rate_limiter : Some ( RateLimiterDescription :: default ( ) ) ,
137+ tx_rate_limiter : Some ( RateLimiterDescription :: default ( ) ) ,
138+ }
139+ }
140+
141+ fn make_netif_cfg ( body : NetworkInterfaceBody , id : & str ) -> NetworkInterfaceConfig {
142+ NetworkInterfaceConfig {
143+ body : body,
144+ id : Rc :: new ( String :: from ( id) ) ,
145+ tap : None ,
146+ tx_rate_limiter : None ,
147+ rx_rate_limiter : None ,
148+ }
149+ }
150+
99151 #[ test]
100152 fn test_put ( ) {
101153 let mut netif_configs = NetworkInterfaceConfigs :: new ( ) ;
102154 assert ! ( netif_configs. if_list. is_empty( ) ) ;
103155
104- if let Ok ( mac) = MacAddr :: parse_str ( "01:23:45:67:89:0A" ) {
105- let mut netif_body = NetworkInterfaceBody {
106- iface_id : String :: from ( "foo" ) ,
107- state : DeviceState :: Attached ,
108- host_dev_name : String :: from ( "bar" ) ,
109- guest_mac : Some ( mac. clone ( ) ) ,
110- rx_rate_limiter : Some ( RateLimiterDescription :: default ( ) ) ,
111- tx_rate_limiter : Some ( RateLimiterDescription :: default ( ) ) ,
112- } ;
113- assert ! ( netif_configs. put( netif_body. clone( ) ) . is_ok( ) ) ;
114- assert_eq ! ( netif_configs. if_list. len( ) , 1 ) ;
115-
116- netif_body. host_dev_name = String :: from ( "baz" ) ;
117- assert ! ( netif_configs. put( netif_body) . is_ok( ) ) ;
118- assert_eq ! ( netif_configs. if_list. len( ) , 1 ) ;
119-
120- let other_netif_body = NetworkInterfaceBody {
121- iface_id : String :: from ( "bar" ) ,
122- state : DeviceState :: Attached ,
123- host_dev_name : String :: from ( "foo" ) ,
124- guest_mac : Some ( mac. clone ( ) ) ,
125- rx_rate_limiter : None ,
126- tx_rate_limiter : None ,
127- } ;
128- assert ! ( netif_configs. put( other_netif_body) . is_err( ) ) ;
129- assert_eq ! ( netif_configs. if_list. len( ) , 1 ) ;
130- }
156+ let mac1 = MacAddr :: parse_str ( "01:23:45:67:89:0A" ) . unwrap ( ) ;
157+ let mac2 = MacAddr :: parse_str ( "23:45:67:89:0A:01" ) . unwrap ( ) ;
158+ let mac3 = MacAddr :: parse_str ( "45:67:89:0A:01:23" ) . unwrap ( ) ;
159+
160+ // Add an interface.
161+ let mut netif_body = make_netif ( "foo" , "bar" , mac1) ;
162+ netif_configs
163+ . if_list
164+ . push ( make_netif_cfg ( netif_body. clone ( ) , "foo" ) ) ;
165+ assert_eq ! ( netif_configs. if_list. len( ) , 1 ) ;
166+
167+ // Update MAC.
168+ netif_body. guest_mac = Some ( mac2. clone ( ) ) ;
169+ assert ! ( netif_configs. put( netif_body) . is_ok( ) ) ;
170+ assert_eq ! ( netif_configs. if_list. len( ) , 1 ) ;
171+
172+ // Try to add another interface with the same MAC.
173+ let mut other_netif_body = make_netif ( "bar" , "foo" , mac2. clone ( ) ) ;
174+ assert ! ( netif_configs. put( other_netif_body. clone( ) ) . is_err( ) ) ;
175+ assert_eq ! ( netif_configs. if_list. len( ) , 1 ) ;
176+
177+ // Add another interface.
178+ other_netif_body. guest_mac = Some ( mac3) ;
179+ netif_configs
180+ . if_list
181+ . push ( make_netif_cfg ( other_netif_body. clone ( ) , "foo" ) ) ;
182+ assert_eq ! ( netif_configs. if_list. len( ) , 2 ) ;
183+
184+ // Try to update with an unavailable name.
185+ other_netif_body. host_dev_name = String :: from ( "baz" ) ;
186+ assert ! ( netif_configs. put( other_netif_body. clone( ) ) . is_err( ) ) ;
187+ assert_eq ! ( netif_configs. if_list. len( ) , 2 ) ;
188+
189+ // Try to update with an unavailable MAC.
190+ other_netif_body. guest_mac = Some ( mac2) ;
191+ assert ! ( netif_configs. put( other_netif_body) . is_err( ) ) ;
192+ assert_eq ! ( netif_configs. if_list. len( ) , 2 ) ;
131193 }
132194}
0 commit comments