1
- use std:: collections:: linked_list:: { self , LinkedList } ;
2
1
use std:: mem;
3
2
use std:: rc:: Rc ;
4
3
use std:: result;
@@ -43,6 +42,13 @@ impl NetworkInterfaceConfig {
43
42
} )
44
43
}
45
44
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
+
46
52
pub fn id_as_str ( & self ) -> & str {
47
53
self . id . as_str ( )
48
54
}
@@ -57,36 +63,61 @@ impl NetworkInterfaceConfig {
57
63
}
58
64
59
65
pub 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 > ,
62
67
}
63
68
64
69
impl NetworkInterfaceConfigs {
65
70
pub fn new ( ) -> Self {
66
71
NetworkInterfaceConfigs {
67
- if_list : LinkedList :: new ( ) ,
72
+ if_list : Vec :: new ( ) ,
68
73
}
69
74
}
70
75
71
76
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 ) ?;
72
92
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
+ }
79
96
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) ;
83
110
}
84
- self . if_list . push_back ( cfg) ;
85
- Ok ( SyncOkStatus :: Created )
111
+ Ok ( SyncOkStatus :: Updated )
86
112
}
87
113
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 ( ( ) )
90
121
}
91
122
}
92
123
@@ -96,37 +127,68 @@ mod tests {
96
127
use api_server:: request:: sync:: DeviceState ;
97
128
use net_util:: MacAddr ;
98
129
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
+
99
151
#[ test]
100
152
fn test_put ( ) {
101
153
let mut netif_configs = NetworkInterfaceConfigs :: new ( ) ;
102
154
assert ! ( netif_configs. if_list. is_empty( ) ) ;
103
155
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 ) ;
131
193
}
132
194
}
0 commit comments