1use std::fs::File;
5use std::mem;
6
7use base::AsRawDescriptor;
8#[cfg(windows)]
9use base::CloseNotifier;
10use base::Event;
11use base::RawDescriptor;
12use base::ReadNotifier;
13use zerocopy::FromBytes;
14use zerocopy::Immutable;
15use zerocopy::IntoBytes;
16
17use crate::backend::VhostUserMemoryRegionInfo;
18use crate::backend::VringConfigData;
19use crate::into_single_file;
20use crate::message::*;
21use crate::Connection;
22use crate::Error as VhostUserError;
23use crate::FrontendReq;
24use crate::Result as VhostUserResult;
25use crate::Result;
26
27pub struct BackendClient {
29 connection: Connection<FrontendReq>,
30}
31
32impl BackendClient {
33 pub fn new(connection: Connection<FrontendReq>) -> Self {
35 BackendClient { connection }
36 }
37
38 pub fn get_features(&mut self) -> Result<u64> {
40 let hdr = self.send_request_header(FrontendReq::GET_FEATURES, None)?;
41 let val = self.recv_reply::<VhostUserU64>(&hdr)?;
42 Ok(val.value)
43 }
44
45 pub fn set_features(&mut self, features: u64) -> Result<()> {
48 let val = VhostUserU64::new(features);
49 let hdr = self.send_request_with_body(FrontendReq::SET_FEATURES, &val, None)?;
50 self.wait_for_ack(&hdr)
51 }
52
53 pub fn set_owner(&self) -> Result<()> {
56 let hdr = self.send_request_header(FrontendReq::SET_OWNER, None)?;
57 self.wait_for_ack(&hdr)
58 }
59
60 pub fn reset_owner(&self) -> Result<()> {
63 let hdr = self.send_request_header(FrontendReq::RESET_OWNER, None)?;
64 self.wait_for_ack(&hdr)
65 }
66
67 pub fn set_mem_table(&self, regions: &[VhostUserMemoryRegionInfo]) -> Result<()> {
70 let mut ctx = VhostUserMemoryContext::new();
71 for region in regions.iter() {
72 let reg = VhostUserMemoryRegion {
73 guest_phys_addr: region.guest_phys_addr,
74 memory_size: region.memory_size,
75 user_addr: region.userspace_addr,
76 mmap_offset: region.mmap_offset,
77 };
78 ctx.append(®, region.mmap_handle);
79 }
80
81 let body = VhostUserMemory::new(ctx.regions.len() as u32);
82 let hdr = self.send_request_with_payload(
83 FrontendReq::SET_MEM_TABLE,
84 &body,
85 ctx.regions.as_bytes(),
86 Some(ctx.fds.as_slice()),
87 )?;
88 self.wait_for_ack(&hdr)
89 }
90
91 pub fn set_log_base(&self, base: u64, fd: Option<RawDescriptor>) -> Result<()> {
93 let val = VhostUserU64::new(base);
94 let _ = self.send_request_with_body(
95 FrontendReq::SET_LOG_BASE,
96 &val,
97 fd.as_ref().map(std::slice::from_ref),
98 )?;
99
100 Ok(())
101 }
102
103 pub fn set_log_fd(&self, fd: RawDescriptor) -> Result<()> {
105 let fds = [fd];
106 let hdr = self.send_request_header(FrontendReq::SET_LOG_FD, Some(&fds))?;
107 self.wait_for_ack(&hdr)
108 }
109
110 pub fn set_vring_num(&self, queue_index: usize, num: u16) -> Result<()> {
112 let val = VhostUserVringState::new(queue_index as u32, num.into());
113 let hdr = self.send_request_with_body(FrontendReq::SET_VRING_NUM, &val, None)?;
114 self.wait_for_ack(&hdr)
115 }
116
117 pub fn set_vring_addr(&self, queue_index: usize, config_data: &VringConfigData) -> Result<()> {
119 let val = VhostUserVringAddr::from_config_data(queue_index as u32, config_data);
120 let hdr = self.send_request_with_body(FrontendReq::SET_VRING_ADDR, &val, None)?;
121 self.wait_for_ack(&hdr)
122 }
123
124 pub fn set_vring_base(&self, queue_index: usize, base: u16) -> Result<()> {
127 let val = VhostUserVringState::new(queue_index as u32, base.into());
128 let hdr = self.send_request_with_body(FrontendReq::SET_VRING_BASE, &val, None)?;
129 self.wait_for_ack(&hdr)
130 }
131
132 pub fn get_vring_base(&self, queue_index: usize) -> Result<u32> {
135 let req = VhostUserVringState::new(queue_index as u32, 0);
136 let hdr = self.send_request_with_body(FrontendReq::GET_VRING_BASE, &req, None)?;
137 let reply = self.recv_reply::<VhostUserVringState>(&hdr)?;
138 Ok(reply.num)
139 }
140
141 pub fn set_vring_call(&self, queue_index: usize, event: &Event) -> Result<()> {
147 let hdr = self.send_fd_for_vring(
148 FrontendReq::SET_VRING_CALL,
149 queue_index,
150 event.as_raw_descriptor(),
151 )?;
152 self.wait_for_ack(&hdr)
153 }
154
155 pub fn set_vring_kick(&self, queue_index: usize, event: &Event) -> Result<()> {
162 let hdr = self.send_fd_for_vring(
163 FrontendReq::SET_VRING_KICK,
164 queue_index,
165 event.as_raw_descriptor(),
166 )?;
167 self.wait_for_ack(&hdr)
168 }
169
170 pub fn set_vring_err(&self, queue_index: usize, event: &Event) -> Result<()> {
175 let hdr = self.send_fd_for_vring(
176 FrontendReq::SET_VRING_ERR,
177 queue_index,
178 event.as_raw_descriptor(),
179 )?;
180 self.wait_for_ack(&hdr)
181 }
182
183 pub fn set_device_state_fd(
188 &self,
189 transfer_direction: VhostUserTransferDirection,
190 migration_phase: VhostUserMigrationPhase,
191 fd: &impl AsRawDescriptor,
192 ) -> Result<Option<File>> {
193 let req = DeviceStateTransferParameters {
195 transfer_direction: match transfer_direction {
196 VhostUserTransferDirection::Save => 0,
197 VhostUserTransferDirection::Load => 1,
198 },
199 migration_phase: match migration_phase {
200 VhostUserMigrationPhase::Stopped => 0,
201 },
202 };
203 let hdr = self.send_request_with_body(
204 FrontendReq::SET_DEVICE_STATE_FD,
205 &req,
206 Some(&[fd.as_raw_descriptor()]),
207 )?;
208 let (reply, files) = self.recv_reply_with_files::<VhostUserU64>(&hdr)?;
210 let has_err = reply.value & 0xff != 0;
211 let invalid_fd = reply.value & 0x100 != 0;
212 if has_err {
213 return Err(VhostUserError::BackendInternalError);
214 }
215 match (invalid_fd, files.len()) {
216 (true, 0) => Ok(None),
217 (false, 1) => Ok(files.into_iter().next()),
218 _ => Err(VhostUserError::IncorrectFds),
219 }
220 }
221
222 pub fn check_device_state(&self) -> Result<()> {
225 let hdr = self.send_request_header(FrontendReq::CHECK_DEVICE_STATE, None)?;
226 let reply = self.recv_reply::<VhostUserU64>(&hdr)?;
227 if reply.value != 0 {
228 return Err(VhostUserError::BackendInternalError);
229 }
230 Ok(())
231 }
232
233 pub fn get_protocol_features(&self) -> Result<VhostUserProtocolFeatures> {
235 let hdr = self.send_request_header(FrontendReq::GET_PROTOCOL_FEATURES, None)?;
236 let val = self.recv_reply::<VhostUserU64>(&hdr)?;
237 Ok(VhostUserProtocolFeatures::from_bits_truncate(val.value))
238 }
239
240 pub fn set_protocol_features(&mut self, features: VhostUserProtocolFeatures) -> Result<()> {
242 let val = VhostUserU64::new(features.bits());
243 let hdr = self.send_request_with_body(FrontendReq::SET_PROTOCOL_FEATURES, &val, None)?;
244 self.wait_for_ack(&hdr)
245 }
246
247 pub fn get_queue_num(&self) -> Result<u64> {
249 let hdr = self.send_request_header(FrontendReq::GET_QUEUE_NUM, None)?;
250 let val = self.recv_reply::<VhostUserU64>(&hdr)?;
251 Ok(val.value)
252 }
253
254 pub fn set_vring_enable(&self, queue_index: usize, enable: bool) -> Result<()> {
260 let val = VhostUserVringState::new(queue_index as u32, enable.into());
261 let hdr = self.send_request_with_body(FrontendReq::SET_VRING_ENABLE, &val, None)?;
262 self.wait_for_ack(&hdr)
263 }
264
265 pub fn get_config(
267 &self,
268 offset: u32,
269 size: u32,
270 flags: VhostUserConfigFlags,
271 buf: &[u8],
272 ) -> Result<(VhostUserConfig, VhostUserConfigPayload)> {
273 let body = VhostUserConfig::new(offset, size, flags);
274
275 let hdr = self.send_request_with_payload(FrontendReq::GET_CONFIG, &body, buf, None)?;
279 let (body_reply, buf_reply, rfds) =
280 self.recv_reply_with_payload::<VhostUserConfig>(&hdr)?;
281 if !rfds.is_empty() {
282 return Err(VhostUserError::InvalidMessage);
283 } else if body_reply.size == 0 {
284 return Err(VhostUserError::BackendInternalError);
285 } else if body_reply.size != body.size
286 || body_reply.size as usize != buf.len()
287 || body_reply.offset != body.offset
288 {
289 return Err(VhostUserError::InvalidMessage);
290 }
291
292 Ok((body_reply, buf_reply))
293 }
294
295 pub fn set_config(&self, offset: u32, flags: VhostUserConfigFlags, buf: &[u8]) -> Result<()> {
298 let body = VhostUserConfig::new(
299 offset,
300 buf.len()
301 .try_into()
302 .map_err(VhostUserError::InvalidCastToInt)?,
303 flags,
304 );
305
306 let hdr = self.send_request_with_payload(FrontendReq::SET_CONFIG, &body, buf, None)?;
307 self.wait_for_ack(&hdr)
308 }
309
310 pub fn set_backend_req_fd(&self, fd: &dyn AsRawDescriptor) -> Result<()> {
312 let fds = [fd.as_raw_descriptor()];
313 let hdr = self.send_request_header(FrontendReq::SET_BACKEND_REQ_FD, Some(&fds))?;
314 self.wait_for_ack(&hdr)
315 }
316
317 pub fn get_inflight_fd(
319 &self,
320 inflight: &VhostUserInflight,
321 ) -> Result<(VhostUserInflight, File)> {
322 let hdr = self.send_request_with_body(FrontendReq::GET_INFLIGHT_FD, inflight, None)?;
323 let (inflight, files) = self.recv_reply_with_files::<VhostUserInflight>(&hdr)?;
324
325 match into_single_file(files) {
326 Some(file) => Ok((inflight, file)),
327 None => Err(VhostUserError::IncorrectFds),
328 }
329 }
330
331 pub fn set_inflight_fd(&self, inflight: &VhostUserInflight, fd: RawDescriptor) -> Result<()> {
333 let hdr =
334 self.send_request_with_body(FrontendReq::SET_INFLIGHT_FD, inflight, Some(&[fd]))?;
335 self.wait_for_ack(&hdr)
336 }
337
338 pub fn get_max_mem_slots(&self) -> Result<u64> {
340 let hdr = self.send_request_header(FrontendReq::GET_MAX_MEM_SLOTS, None)?;
341 let val = self.recv_reply::<VhostUserU64>(&hdr)?;
342
343 Ok(val.value)
344 }
345
346 pub fn add_mem_region(&self, region: &VhostUserMemoryRegionInfo) -> Result<()> {
348 let body = VhostUserSingleMemoryRegion::new(
349 region.guest_phys_addr,
350 region.memory_size,
351 region.userspace_addr,
352 region.mmap_offset,
353 );
354 let fds = [region.mmap_handle];
355 let hdr = self.send_request_with_body(FrontendReq::ADD_MEM_REG, &body, Some(&fds))?;
356 self.wait_for_ack(&hdr)
357 }
358
359 pub fn remove_mem_region(&self, region: &VhostUserMemoryRegionInfo) -> Result<()> {
361 let body = VhostUserSingleMemoryRegion::new(
362 region.guest_phys_addr,
363 region.memory_size,
364 region.userspace_addr,
365 region.mmap_offset,
366 );
367 let hdr = self.send_request_with_body(FrontendReq::REM_MEM_REG, &body, None)?;
368 self.wait_for_ack(&hdr)
369 }
370
371 pub fn get_shmem_config(&self) -> Result<(VhostUserShMemConfigHeader, Vec<u64>)> {
373 let hdr = self.send_request_header(FrontendReq::GET_SHMEM_CONFIG, None)?;
374 let (body_reply, buf_reply, _rfds) =
375 self.recv_reply_with_payload::<VhostUserShMemConfigHeader>(&hdr)?;
376 let mut memory_sizes = Vec::new();
377 for i in 0..body_reply.nregions {
378 const U64_SIZE: usize = mem::size_of::<u64>();
379 let offset = (i as usize) * U64_SIZE;
380 let value =
381 VhostUserU64::read_from_bytes(&buf_reply[offset..(offset + U64_SIZE)]).unwrap();
382 memory_sizes.push(value.value);
383 }
384 Ok((body_reply, memory_sizes))
385 }
386
387 fn send_request_header(
388 &self,
389 code: FrontendReq,
390 fds: Option<&[RawDescriptor]>,
391 ) -> VhostUserResult<VhostUserMsgHeader<FrontendReq>> {
392 let hdr = self.new_request_header(code, 0);
393 self.connection.send_header_only_message(&hdr, fds)?;
394 Ok(hdr)
395 }
396
397 fn send_request_with_body<T: IntoBytes + Immutable>(
398 &self,
399 code: FrontendReq,
400 msg: &T,
401 fds: Option<&[RawDescriptor]>,
402 ) -> VhostUserResult<VhostUserMsgHeader<FrontendReq>> {
403 let hdr = self.new_request_header(code, mem::size_of::<T>() as u32);
404 self.connection.send_message(&hdr, msg, fds)?;
405 Ok(hdr)
406 }
407
408 fn send_request_with_payload<T: IntoBytes + Immutable>(
409 &self,
410 code: FrontendReq,
411 msg: &T,
412 payload: &[u8],
413 fds: Option<&[RawDescriptor]>,
414 ) -> VhostUserResult<VhostUserMsgHeader<FrontendReq>> {
415 let len = mem::size_of::<T>()
416 .checked_add(payload.len())
417 .ok_or(VhostUserError::OversizedMsg)?;
418 let hdr = self.new_request_header(
419 code,
420 len.try_into().map_err(VhostUserError::InvalidCastToInt)?,
421 );
422 self.connection
423 .send_message_with_payload(&hdr, msg, payload, fds)?;
424 Ok(hdr)
425 }
426
427 fn send_fd_for_vring(
428 &self,
429 code: FrontendReq,
430 queue_index: usize,
431 fd: RawDescriptor,
432 ) -> VhostUserResult<VhostUserMsgHeader<FrontendReq>> {
433 let msg = VhostUserU64::new(queue_index as u64);
437 let hdr = self.new_request_header(code, mem::size_of::<VhostUserU64>() as u32);
438 self.connection.send_message(&hdr, &msg, Some(&[fd]))?;
439 Ok(hdr)
440 }
441
442 fn recv_reply<T: Sized + FromBytes + IntoBytes + Default + VhostUserMsgValidator>(
443 &self,
444 hdr: &VhostUserMsgHeader<FrontendReq>,
445 ) -> VhostUserResult<T> {
446 if hdr.is_reply() {
447 return Err(VhostUserError::InvalidParam(
448 "recv_reply: header is not a reply",
449 ));
450 }
451 let (reply, body, rfds) = self.connection.recv_message::<T>()?;
452 if !reply.is_valid() || !reply.is_reply_for(hdr) || !rfds.is_empty() || !body.is_valid() {
453 return Err(VhostUserError::InvalidMessage);
454 }
455 Ok(body)
456 }
457
458 fn recv_reply_with_files<T: Sized + IntoBytes + FromBytes + Default + VhostUserMsgValidator>(
459 &self,
460 hdr: &VhostUserMsgHeader<FrontendReq>,
461 ) -> VhostUserResult<(T, Vec<File>)> {
462 if hdr.is_reply() {
463 return Err(VhostUserError::InvalidParam(
464 "with_files: expected a reply, but the header is not marked as a reply",
465 ));
466 }
467
468 let (reply, body, files) = self.connection.recv_message::<T>()?;
469 if !reply.is_valid() || !reply.is_reply_for(hdr) || !body.is_valid() {
470 return Err(VhostUserError::InvalidMessage);
471 }
472 Ok((body, files))
473 }
474
475 fn recv_reply_with_payload<
476 T: Sized + IntoBytes + FromBytes + Default + VhostUserMsgValidator,
477 >(
478 &self,
479 hdr: &VhostUserMsgHeader<FrontendReq>,
480 ) -> VhostUserResult<(T, Vec<u8>, Vec<File>)> {
481 if hdr.is_reply() {
482 return Err(VhostUserError::InvalidParam(
483 "with_payload: expected a reply, but the header is not marked as a reply",
484 ));
485 }
486
487 let (reply, body, buf, files, more_files) =
488 self.connection.recv_message_with_payload::<T>()?;
489 if !reply.is_valid()
490 || !reply.is_reply_for(hdr)
491 || !files.is_empty()
492 || !more_files.is_empty()
493 || !body.is_valid()
494 {
495 return Err(VhostUserError::InvalidMessage);
496 }
497
498 Ok((body, buf, files))
499 }
500
501 fn wait_for_ack(&self, hdr: &VhostUserMsgHeader<FrontendReq>) -> VhostUserResult<()> {
502 if !hdr.is_need_reply() {
503 return Ok(());
504 }
505
506 let (reply, body, rfds) = self.connection.recv_message::<VhostUserU64>()?;
507 if !reply.is_valid() || !reply.is_reply_for(hdr) || !rfds.is_empty() || !body.is_valid() {
508 return Err(VhostUserError::InvalidMessage);
509 }
510 if body.value != 0 {
511 return Err(VhostUserError::BackendInternalError);
512 }
513 Ok(())
514 }
515
516 #[inline]
517 fn new_request_header(
518 &self,
519 request: FrontendReq,
520 size: u32,
521 ) -> VhostUserMsgHeader<FrontendReq> {
522 VhostUserMsgHeader::new(request, 0x1, size)
523 }
524}
525
526#[cfg(windows)]
527impl CloseNotifier for BackendClient {
528 fn get_close_notifier(&self) -> &dyn AsRawDescriptor {
529 self.connection.0.get_close_notifier()
530 }
531}
532
533impl ReadNotifier for BackendClient {
534 fn get_read_notifier(&self) -> &dyn AsRawDescriptor {
535 self.connection.0.get_read_notifier()
536 }
537}
538
539struct VhostUserMemoryContext {
542 regions: VhostUserMemoryPayload,
543 fds: Vec<RawDescriptor>,
544}
545
546impl VhostUserMemoryContext {
547 pub fn new() -> Self {
549 VhostUserMemoryContext {
550 regions: VhostUserMemoryPayload::new(),
551 fds: Vec::new(),
552 }
553 }
554
555 pub fn append(&mut self, region: &VhostUserMemoryRegion, fd: RawDescriptor) {
557 self.regions.push(*region);
558 self.fds.push(fd);
559 }
560}
561
562#[cfg(test)]
563mod tests {
564 use base::INVALID_DESCRIPTOR;
565
566 use super::*;
567
568 const BUFFER_SIZE: usize = 0x1001;
569 const INVALID_PROTOCOL_FEATURE: u64 = 1 << 63;
570
571 fn create_pair() -> (BackendClient, Connection<FrontendReq>) {
572 let (client_connection, server_connection) = Connection::pair().unwrap();
573 let backend_client = BackendClient::new(client_connection);
574 (backend_client, server_connection)
575 }
576
577 #[test]
578 fn create_backend_client() {
579 let (backend_client, peer) = create_pair();
580
581 assert!(backend_client.connection.as_raw_descriptor() != INVALID_DESCRIPTOR);
582 backend_client.set_owner().unwrap();
584 backend_client.reset_owner().unwrap();
585
586 let (hdr, rfds) = peer.recv_header().unwrap();
587 assert_eq!(hdr.get_code(), Ok(FrontendReq::SET_OWNER));
588 assert_eq!(hdr.get_size(), 0);
589 assert_eq!(hdr.get_version(), 0x1);
590 assert!(rfds.is_empty());
591
592 let (hdr, rfds) = peer.recv_header().unwrap();
593 assert_eq!(hdr.get_code(), Ok(FrontendReq::RESET_OWNER));
594 assert_eq!(hdr.get_size(), 0);
595 assert_eq!(hdr.get_version(), 0x1);
596 assert!(rfds.is_empty());
597 }
598
599 #[test]
600 fn test_features() {
601 let (mut backend_client, peer) = create_pair();
602
603 backend_client.set_owner().unwrap();
604 let (hdr, rfds) = peer.recv_header().unwrap();
605 assert_eq!(hdr.get_code(), Ok(FrontendReq::SET_OWNER));
606 assert_eq!(hdr.get_size(), 0);
607 assert_eq!(hdr.get_version(), 0x1);
608 assert!(rfds.is_empty());
609
610 let hdr = VhostUserMsgHeader::new(FrontendReq::GET_FEATURES, 0x4, 8);
611 let msg = VhostUserU64::new(0x15);
612 peer.send_message(&hdr, &msg, None).unwrap();
613 let features = backend_client.get_features().unwrap();
614 assert_eq!(features, 0x15u64);
615 let (_hdr, rfds) = peer.recv_header().unwrap();
616 assert!(rfds.is_empty());
617
618 let hdr = VhostUserMsgHeader::new(FrontendReq::SET_FEATURES, 0x4, 8);
619 let msg = VhostUserU64::new(0x15);
620 peer.send_message(&hdr, &msg, None).unwrap();
621 backend_client.set_features(0x15).unwrap();
622 let (_hdr, msg, rfds) = peer.recv_message::<VhostUserU64>().unwrap();
623 assert!(rfds.is_empty());
624 let val = msg.value;
625 assert_eq!(val, 0x15);
626
627 let hdr = VhostUserMsgHeader::new(FrontendReq::GET_FEATURES, 0x4, 8);
628 let msg = 0x15u32;
629 peer.send_message(&hdr, &msg, None).unwrap();
630 assert!(backend_client.get_features().is_err());
631 }
632
633 #[test]
634 fn test_protocol_features() {
635 let (mut backend_client, peer) = create_pair();
636
637 backend_client.set_owner().unwrap();
638 let (hdr, rfds) = peer.recv_header().unwrap();
639 assert_eq!(hdr.get_code(), Ok(FrontendReq::SET_OWNER));
640 assert!(rfds.is_empty());
641
642 let pfeatures = VhostUserProtocolFeatures::all();
643 let hdr = VhostUserMsgHeader::new(FrontendReq::GET_PROTOCOL_FEATURES, 0x4, 8);
644 let msg = VhostUserU64::new(pfeatures.bits() | INVALID_PROTOCOL_FEATURE);
646 peer.send_message(&hdr, &msg, None).unwrap();
647 let features = backend_client.get_protocol_features().unwrap();
648 assert_eq!(features, pfeatures);
649 let (_hdr, rfds) = peer.recv_header().unwrap();
650 assert!(rfds.is_empty());
651
652 backend_client
653 .set_protocol_features(VhostUserProtocolFeatures::all())
654 .unwrap();
655 let (_hdr, msg, rfds) = peer.recv_message::<VhostUserU64>().unwrap();
656 assert!(rfds.is_empty());
657 let val = msg.value;
658 assert_eq!(val, pfeatures.bits());
659
660 let vfeatures = 0x15 | 1 << VHOST_USER_F_PROTOCOL_FEATURES;
661 let hdr = VhostUserMsgHeader::new(FrontendReq::GET_FEATURES, 0x4, 8);
662 let msg = VhostUserU64::new(vfeatures);
663 peer.send_message(&hdr, &msg, None).unwrap();
664 let features = backend_client.get_features().unwrap();
665 assert_eq!(features, vfeatures);
666 let (_hdr, rfds) = peer.recv_header().unwrap();
667 assert!(rfds.is_empty());
668
669 backend_client.set_features(vfeatures).unwrap();
670 let (_hdr, msg, rfds) = peer.recv_message::<VhostUserU64>().unwrap();
671 assert!(rfds.is_empty());
672 let val = msg.value;
673 assert_eq!(val, vfeatures);
674
675 let pfeatures = VhostUserProtocolFeatures::all();
676 let hdr = VhostUserMsgHeader::new(FrontendReq::GET_PROTOCOL_FEATURES, 0x4, 8);
677 let msg = VhostUserU64::new(pfeatures.bits() | INVALID_PROTOCOL_FEATURE);
679 peer.send_message(&hdr, &msg, None).unwrap();
680 let features = backend_client.get_protocol_features().unwrap();
681 assert_eq!(features, pfeatures);
682 let (_hdr, rfds) = peer.recv_header().unwrap();
683 assert!(rfds.is_empty());
684
685 backend_client.set_protocol_features(pfeatures).unwrap();
686 let (_hdr, msg, rfds) = peer.recv_message::<VhostUserU64>().unwrap();
687 assert!(rfds.is_empty());
688 let val = msg.value;
689 assert_eq!(val, pfeatures.bits());
690
691 let hdr = VhostUserMsgHeader::new(FrontendReq::SET_PROTOCOL_FEATURES, 0x4, 8);
692 let msg = VhostUserU64::new(pfeatures.bits());
693 peer.send_message(&hdr, &msg, None).unwrap();
694 assert!(backend_client.get_protocol_features().is_err());
695 }
696
697 #[test]
698 fn test_backend_client_get_config_negative0() {
699 let (backend_client, peer) = create_pair();
700 let buf = vec![0x0; BUFFER_SIZE];
701
702 let mut hdr = VhostUserMsgHeader::new(FrontendReq::GET_CONFIG, 0x4, 16);
703 let msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
704 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
705 .unwrap();
706 assert!(backend_client
707 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
708 .is_ok());
709
710 hdr.set_code(FrontendReq::GET_FEATURES);
711 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
712 .unwrap();
713 assert!(backend_client
714 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
715 .is_err());
716 hdr.set_code(FrontendReq::GET_CONFIG);
717 }
718
719 #[test]
720 fn test_backend_client_get_config_negative1() {
721 let (backend_client, peer) = create_pair();
722 let buf = vec![0x0; BUFFER_SIZE];
723
724 let mut hdr = VhostUserMsgHeader::new(FrontendReq::GET_CONFIG, 0x4, 16);
725 let msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
726 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
727 .unwrap();
728 assert!(backend_client
729 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
730 .is_ok());
731
732 hdr.set_reply(false);
733 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
734 .unwrap();
735 assert!(backend_client
736 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
737 .is_err());
738 }
739
740 #[test]
741 fn test_backend_client_get_config_negative2() {
742 let (backend_client, peer) = create_pair();
743 let buf = vec![0x0; BUFFER_SIZE];
744
745 let hdr = VhostUserMsgHeader::new(FrontendReq::GET_CONFIG, 0x4, 16);
746 let msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
747 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
748 .unwrap();
749 assert!(backend_client
750 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
751 .is_ok());
752 }
753
754 #[test]
755 fn test_backend_client_get_config_negative3() {
756 let (backend_client, peer) = create_pair();
757 let buf = vec![0x0; BUFFER_SIZE];
758
759 let hdr = VhostUserMsgHeader::new(FrontendReq::GET_CONFIG, 0x4, 16);
760 let mut msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
761 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
762 .unwrap();
763 assert!(backend_client
764 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
765 .is_ok());
766
767 msg.offset = 0;
768 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
769 .unwrap();
770 assert!(backend_client
771 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
772 .is_err());
773 }
774
775 #[test]
776 fn test_backend_client_get_config_negative4() {
777 let (backend_client, peer) = create_pair();
778 let buf = vec![0x0; BUFFER_SIZE];
779
780 let hdr = VhostUserMsgHeader::new(FrontendReq::GET_CONFIG, 0x4, 16);
781 let mut msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
782 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
783 .unwrap();
784 assert!(backend_client
785 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
786 .is_ok());
787
788 msg.offset = 0x101;
789 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
790 .unwrap();
791 assert!(backend_client
792 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
793 .is_err());
794 }
795
796 #[test]
797 fn test_backend_client_get_config_negative5() {
798 let (backend_client, peer) = create_pair();
799 let buf = vec![0x0; BUFFER_SIZE];
800
801 let hdr = VhostUserMsgHeader::new(FrontendReq::GET_CONFIG, 0x4, 16);
802 let mut msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
803 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
804 .unwrap();
805 assert!(backend_client
806 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
807 .is_ok());
808
809 msg.offset = (BUFFER_SIZE) as u32;
810 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
811 .unwrap();
812 assert!(backend_client
813 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
814 .is_err());
815 }
816
817 #[test]
818 fn test_backend_client_get_config_negative6() {
819 let (backend_client, peer) = create_pair();
820 let buf = vec![0x0; BUFFER_SIZE];
821
822 let hdr = VhostUserMsgHeader::new(FrontendReq::GET_CONFIG, 0x4, 16);
823 let mut msg = VhostUserConfig::new(0x100, 4, VhostUserConfigFlags::empty());
824 peer.send_message_with_payload(&hdr, &msg, &buf[0..4], None)
825 .unwrap();
826 assert!(backend_client
827 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
828 .is_ok());
829
830 msg.size = 6;
831 peer.send_message_with_payload(&hdr, &msg, &buf[0..6], None)
832 .unwrap();
833 assert!(backend_client
834 .get_config(0x100, 4, VhostUserConfigFlags::WRITABLE, &buf[0..4])
835 .is_err());
836 }
837}