@@ -136,8 +136,8 @@ pub enum Error {
136
136
EpollFd ( io:: Error ) ,
137
137
/// Cannot read from an Event file descriptor.
138
138
EventFd ( std:: io:: Error ) ,
139
- /// Describes a logical problem .
140
- GeneralFailure , // TODO: there are some cases in which this error should be replaced.
139
+ /// An event arrived for a device, but the dispatcher can't find the event (epoll) handler .
140
+ DeviceEventHandlerNotFound ,
141
141
/// Cannot open /dev/kvm. Either the host does not have KVM or Firecracker does not have
142
142
/// permission to open the file descriptor.
143
143
Kvm ( io:: Error ) ,
@@ -161,11 +161,21 @@ impl std::fmt::Debug for Error {
161
161
use self :: Error :: * ;
162
162
163
163
match self {
164
- // This only implements Debug for the most common Firecracker error
165
- // which is the one coming from KVM at the time.
166
- // TODO: implement debug for the other errors as well.
164
+ ApiChannel => write ! ( f, "ApiChannel: error receiving data from the API server" ) ,
165
+ CreateLegacyDevice ( e) => write ! ( f, "Error creating legacy device: {:?}" , e) ,
166
+ EpollFd ( e) => write ! ( f, "Epoll fd error: {:?}" , e) ,
167
+ EventFd ( e) => write ! ( f, "Event fd error: {}" , e. to_string( ) ) ,
168
+ DeviceEventHandlerNotFound => write ! (
169
+ f,
170
+ "Device event handler not found. This might point to a guest device driver issue."
171
+ ) ,
167
172
Kvm ( ref os_err) => write ! ( f, "Cannot open /dev/kvm. Error: {}" , os_err. to_string( ) ) ,
168
- _ => write ! ( f, "{:?}" , self ) ,
173
+ KvmApiVersion ( ver) => write ! ( f, "Bad KVM API version: {}" , ver) ,
174
+ KvmCap ( cap) => write ! ( f, "Missing KVM capability: {:?}" , cap) ,
175
+ Poll ( e) => write ! ( f, "Epoll wait failed: {}" , e. to_string( ) ) ,
176
+ Serial ( e) => write ! ( f, "Error writing to the serial console: {:?}" , e) ,
177
+ TimerFd ( e) => write ! ( f, "Error creating timer fd: {}" , e. to_string( ) ) ,
178
+ Vm ( e) => write ! ( f, "Error opening VM fd: {:?}" , e) ,
169
179
}
170
180
}
171
181
}
@@ -250,6 +260,7 @@ impl Display for VmmActionError {
250
260
251
261
/// This enum represents the public interface of the VMM. Each action contains various
252
262
/// bits of information (ids, paths, etc.), together with an OutcomeSender, which is always present.
263
+ #[ derive( Debug ) ]
253
264
pub enum VmmAction {
254
265
/// Configure the boot source of the microVM using as input the `ConfigureBootSource`. This
255
266
/// action can only be called before the microVM has booted. The response is sent using the
@@ -543,7 +554,7 @@ impl EpollContext {
543
554
let received = maybe
544
555
. receiver
545
556
. try_recv ( )
546
- . map_err ( |_| Error :: GeneralFailure ) ?;
557
+ . map_err ( |_| Error :: DeviceEventHandlerNotFound ) ?;
547
558
Ok ( maybe. handler . get_or_insert ( received) . as_mut ( ) )
548
559
}
549
560
}
@@ -1946,6 +1957,10 @@ impl PartialEq for VmmAction {
1946
1957
& VmmAction :: InsertNetworkDevice ( ref net_dev, _) ,
1947
1958
& VmmAction :: InsertNetworkDevice ( ref other_net_dev, _) ,
1948
1959
) => net_dev == other_net_dev,
1960
+ (
1961
+ & VmmAction :: UpdateNetworkInterface ( ref net_dev, _) ,
1962
+ & VmmAction :: UpdateNetworkInterface ( ref other_net_dev, _) ,
1963
+ ) => net_dev == other_net_dev,
1949
1964
(
1950
1965
& VmmAction :: RescanBlockDevice ( ref req, _) ,
1951
1966
& VmmAction :: RescanBlockDevice ( ref other_req, _) ,
@@ -2019,6 +2034,7 @@ mod tests {
2019
2034
use devices:: virtio:: ActivateResult ;
2020
2035
use net_util:: MacAddr ;
2021
2036
use vmm_config:: machine_config:: CpuFeaturesTemplate ;
2037
+ use vmm_config:: { RateLimiterConfig , TokenBucketConfig } ;
2022
2038
2023
2039
impl Vmm {
2024
2040
fn get_kernel_cmdline_str ( & self ) -> & str {
@@ -2312,6 +2328,98 @@ mod tests {
2312
2328
assert ! ( vmm. insert_net_device( network_interface) . is_err( ) ) ;
2313
2329
}
2314
2330
2331
+ #[ test]
2332
+ fn test_update_net_device ( ) {
2333
+ let mut vmm = create_vmm_object ( InstanceState :: Uninitialized ) ;
2334
+
2335
+ let tbc_1mtps = TokenBucketConfig {
2336
+ size : 1024 * 1024 ,
2337
+ one_time_burst : None ,
2338
+ refill_time : 1000 ,
2339
+ } ;
2340
+ let tbc_2mtps = TokenBucketConfig {
2341
+ size : 2 * 1024 * 1024 ,
2342
+ one_time_burst : None ,
2343
+ refill_time : 1000 ,
2344
+ } ;
2345
+
2346
+ vmm. insert_net_device ( NetworkInterfaceConfig {
2347
+ iface_id : String :: from ( "1" ) ,
2348
+ host_dev_name : String :: from ( "hostname5" ) ,
2349
+ guest_mac : None ,
2350
+ rx_rate_limiter : Some ( RateLimiterConfig {
2351
+ bandwidth : Some ( tbc_1mtps) ,
2352
+ ops : None ,
2353
+ } ) ,
2354
+ tx_rate_limiter : None ,
2355
+ allow_mmds_requests : false ,
2356
+ tap : None ,
2357
+ } )
2358
+ . unwrap ( ) ;
2359
+
2360
+ vmm. update_net_device ( NetworkInterfaceUpdateConfig {
2361
+ iface_id : "1" . to_string ( ) ,
2362
+ rx_rate_limiter : Some ( RateLimiterConfig {
2363
+ bandwidth : None ,
2364
+ ops : Some ( tbc_2mtps) ,
2365
+ } ) ,
2366
+ tx_rate_limiter : Some ( RateLimiterConfig {
2367
+ bandwidth : None ,
2368
+ ops : Some ( tbc_2mtps) ,
2369
+ } ) ,
2370
+ } )
2371
+ . unwrap ( ) ;
2372
+
2373
+ {
2374
+ let nic_1: & mut NetworkInterfaceConfig =
2375
+ vmm. network_interface_configs . iter_mut ( ) . next ( ) . unwrap ( ) ;
2376
+ // The RX bandwidth should be unaffected.
2377
+ assert_eq ! ( nic_1. rx_rate_limiter. unwrap( ) . bandwidth. unwrap( ) , tbc_1mtps) ;
2378
+ // The RX ops should be set to 2mtps.
2379
+ assert_eq ! ( nic_1. rx_rate_limiter. unwrap( ) . ops. unwrap( ) , tbc_2mtps) ;
2380
+ // The TX bandwith should be unlimited (unaffected).
2381
+ assert_eq ! ( nic_1. tx_rate_limiter. unwrap( ) . bandwidth, None ) ;
2382
+ // The TX ops should be set to 2mtps.
2383
+ assert_eq ! ( nic_1. tx_rate_limiter. unwrap( ) . ops. unwrap( ) , tbc_2mtps) ;
2384
+ }
2385
+
2386
+ vmm. init_guest_memory ( ) . unwrap ( ) ;
2387
+ vmm. default_kernel_config ( ) ;
2388
+ let guest_mem = vmm. guest_memory . clone ( ) . unwrap ( ) ;
2389
+ let mut device_manager =
2390
+ MMIODeviceManager :: new ( guest_mem. clone ( ) , arch:: get_reserved_mem_addr ( ) as u64 ) ;
2391
+ vmm. attach_net_devices ( & mut device_manager) . unwrap ( ) ;
2392
+ vmm. set_instance_state ( InstanceState :: Running ) ;
2393
+
2394
+ // The update should fail before device activation.
2395
+ assert ! ( vmm
2396
+ . update_net_device( NetworkInterfaceUpdateConfig {
2397
+ iface_id: "1" . to_string( ) ,
2398
+ rx_rate_limiter: None ,
2399
+ tx_rate_limiter: None ,
2400
+ } )
2401
+ . is_err( ) ) ;
2402
+
2403
+ // Fake device activation by explicitly setting a dummy epoll handler.
2404
+ vmm. epoll_context . device_handlers [ 0 ] . handler = Some ( Box :: new ( DummyEpollHandler {
2405
+ evt : None ,
2406
+ flags : None ,
2407
+ payload : None ,
2408
+ } ) ) ;
2409
+ vmm. update_net_device ( NetworkInterfaceUpdateConfig {
2410
+ iface_id : "1" . to_string ( ) ,
2411
+ rx_rate_limiter : Some ( RateLimiterConfig {
2412
+ bandwidth : Some ( tbc_2mtps) ,
2413
+ ops : None ,
2414
+ } ) ,
2415
+ tx_rate_limiter : Some ( RateLimiterConfig {
2416
+ bandwidth : Some ( tbc_1mtps) ,
2417
+ ops : None ,
2418
+ } ) ,
2419
+ } )
2420
+ . unwrap ( ) ;
2421
+ }
2422
+
2315
2423
#[ test]
2316
2424
fn test_machine_configuration ( ) {
2317
2425
let mut vmm = create_vmm_object ( InstanceState :: Uninitialized ) ;
0 commit comments