1use std::fs::File;
9use std::io::{Error as IoError, Read, Result as IoResult, Write};
10use std::net::UdpSocket;
11use std::os::raw::*;
12use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
13
14use vmm_sys_util::ioctl::{ioctl_with_mut_ref, ioctl_with_ref, ioctl_with_val};
15use vmm_sys_util::{ioctl_ioc_nr, ioctl_iow_nr};
16
17use crate::net::net_gen;
18
19pub(crate) const IFACE_NAME_MAX_LEN: usize = 16;
22
23#[derive(Debug, thiserror::Error)]
25pub enum Error {
26 #[error("cannot create socket. {0}")]
28 CreateSocket(#[source] IoError),
29
30 #[error("cannot create tap devic. {0}")]
32 CreateTap(IoError),
33
34 #[error("invalid network interface name")]
36 InvalidIfname,
37
38 #[error("failure while issue Tap ioctl command. {0}")]
40 IoctlError(#[source] IoError),
41
42 #[error("cannot open tap device. {0}")]
44 OpenTun(#[source] IoError),
45}
46
47pub type Result<T> = ::std::result::Result<T, Error>;
48
49const TUNTAP: ::std::os::raw::c_uint = 84;
50ioctl_iow_nr!(TUNSETIFF, TUNTAP, 202, ::std::os::raw::c_int);
51ioctl_iow_nr!(TUNSETOFFLOAD, TUNTAP, 208, ::std::os::raw::c_uint);
52ioctl_iow_nr!(TUNSETVNETHDRSZ, TUNTAP, 216, ::std::os::raw::c_int);
53
54#[derive(Debug)]
60pub struct Tap {
61 pub tap_file: File,
63 pub(crate) if_name: [u8; IFACE_NAME_MAX_LEN],
64 pub(crate) if_flags: std::os::raw::c_short,
65}
66
67impl PartialEq for Tap {
68 fn eq(&self, other: &Tap) -> bool {
69 self.if_name == other.if_name
70 }
71}
72
73fn create_socket() -> Result<UdpSocket> {
74 let sock = unsafe { libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0) };
76 if sock < 0 {
77 return Err(Error::CreateSocket(IoError::last_os_error()));
78 }
79
80 Ok(unsafe { UdpSocket::from_raw_fd(sock) })
82}
83
84fn build_terminated_if_name(if_name: &str) -> Result<[u8; IFACE_NAME_MAX_LEN]> {
87 let if_name = if_name.as_bytes();
90
91 if if_name.len() >= IFACE_NAME_MAX_LEN {
92 return Err(Error::InvalidIfname);
93 }
94
95 let mut terminated_if_name = [b'\0'; IFACE_NAME_MAX_LEN];
96 terminated_if_name[..if_name.len()].copy_from_slice(if_name);
97
98 Ok(terminated_if_name)
99}
100
101impl Tap {
102 pub fn open_named(if_name: &str, multi_vq: bool) -> Result<Tap> {
113 let terminated_if_name = build_terminated_if_name(if_name)?;
114
115 let mut ifreq: net_gen::ifreq = Default::default();
119 unsafe {
120 let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut();
121 ifrn_name.copy_from_slice(terminated_if_name.as_ref());
122 let ifru_flags = ifreq.ifr_ifru.ifru_flags.as_mut();
123 *ifru_flags = (net_gen::IFF_TAP
124 | net_gen::IFF_NO_PI
125 | net_gen::IFF_VNET_HDR
126 | if multi_vq {
127 net_gen::IFF_MULTI_QUEUE
128 } else {
129 0
130 }) as c_short;
131 }
132
133 Tap::create_tap_with_ifreq(&mut ifreq)
134 }
135
136 fn create_tap_with_ifreq(ifreq: &mut net_gen::ifreq) -> Result<Tap> {
137 let fd = unsafe {
138 libc::open(
141 b"/dev/net/tun\0".as_ptr() as *const c_char,
142 libc::O_RDWR | libc::O_NONBLOCK | libc::O_CLOEXEC,
143 )
144 };
145 if fd < 0 {
146 return Err(Error::OpenTun(IoError::last_os_error()));
147 }
148
149 let tuntap = unsafe { File::from_raw_fd(fd) };
151
152 let ret = unsafe { ioctl_with_mut_ref(&tuntap, TUNSETIFF(), ifreq) };
155
156 if ret < 0 {
157 return Err(Error::CreateTap(IoError::last_os_error()));
158 }
159
160 Ok(Tap {
162 tap_file: tuntap,
163 if_name: unsafe { *ifreq.ifr_ifrn.ifrn_name.as_ref() },
164 if_flags: unsafe { *ifreq.ifr_ifru.ifru_flags.as_ref() },
165 })
166 }
167
168 pub fn into_mq_taps(self, vq_pairs: usize) -> Result<Vec<Tap>> {
170 let mut taps = Vec::new();
171
172 if vq_pairs <= 1 {
173 taps.push(self);
174 return Ok(taps);
175 }
176
177 for _ in 0..vq_pairs - 1 {
179 let mut ifreq = self.get_ifreq();
180 let tap = Tap::create_tap_with_ifreq(&mut ifreq)?;
181
182 tap.enable()?;
183
184 taps.push(tap);
185 }
186
187 taps.insert(0, self);
188 Ok(taps)
189 }
190
191 pub fn set_offload(&self, flags: c_uint) -> Result<()> {
193 let ret = unsafe { ioctl_with_val(&self.tap_file, TUNSETOFFLOAD(), c_ulong::from(flags)) };
195 if ret < 0 {
196 return Err(Error::IoctlError(IoError::last_os_error()));
197 }
198
199 Ok(())
200 }
201
202 pub fn enable(&self) -> Result<()> {
204 let sock = create_socket()?;
205
206 let mut ifreq = self.get_ifreq();
207
208 unsafe {
210 let ifru_flags = ifreq.ifr_ifru.ifru_flags.as_mut();
211 *ifru_flags =
212 (net_gen::net_device_flags_IFF_UP | net_gen::net_device_flags_IFF_RUNNING) as i16;
213 }
214
215 let ret =
217 unsafe { ioctl_with_ref(&sock, c_ulong::from(net_gen::sockios::SIOCSIFFLAGS), &ifreq) };
218 if ret < 0 {
219 return Err(Error::IoctlError(IoError::last_os_error()));
220 }
221
222 Ok(())
223 }
224
225 pub fn set_vnet_hdr_size(&self, size: c_int) -> Result<()> {
227 let ret = unsafe { ioctl_with_ref(&self.tap_file, TUNSETVNETHDRSZ(), &size) };
229 if ret < 0 {
230 return Err(Error::IoctlError(IoError::last_os_error()));
231 }
232
233 Ok(())
234 }
235
236 fn get_ifreq(&self) -> net_gen::ifreq {
237 let mut ifreq: net_gen::ifreq = Default::default();
238
239 unsafe {
242 let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut();
243 ifrn_name.clone_from_slice(&self.if_name);
244
245 let flags = ifreq.ifr_ifru.ifru_flags.as_mut();
246 *flags = self.if_flags;
247 }
248
249 ifreq
250 }
251
252 pub fn if_flags(&self) -> u32 {
254 self.if_flags as u32
255 }
256}
257
258impl Read for Tap {
259 fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
260 self.tap_file.read(buf)
261 }
262}
263
264impl Write for Tap {
265 fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
266 self.tap_file.write(buf)
267 }
268
269 fn flush(&mut self) -> IoResult<()> {
270 Ok(())
271 }
272}
273
274impl AsRawFd for Tap {
275 fn as_raw_fd(&self) -> RawFd {
276 self.tap_file.as_raw_fd()
277 }
278}
279
280mod tests {
281 #![allow(dead_code)]
282
283 use std::mem;
284 use std::net::Ipv4Addr;
285 use std::str;
286 use std::sync::atomic::{AtomicUsize, Ordering};
287
288 use super::*;
289
290 const SUBNET_MASK: &str = "255.255.255.0";
291 const TAP_IP_PREFIX: &str = "192.168.241.";
292 const FAKE_MAC: &str = "12:34:56:78:9a:bc";
293
294 const VETH_OFFSET: usize = 10;
298 static NEXT_IP: AtomicUsize = AtomicUsize::new(1);
299
300 fn create_sockaddr(ip_addr: Ipv4Addr) -> net_gen::sockaddr {
303 let addr_in = net_gen::sockaddr_in {
306 sin_family: net_gen::AF_INET as u16,
307 sin_port: 0,
308 sin_addr: unsafe { mem::transmute(ip_addr.octets()) },
309 __pad: [0; 8usize],
310 };
311
312 unsafe { mem::transmute(addr_in) }
313 }
314 impl Tap {
315 pub fn new() -> Result<Tap> {
320 let next_ip = NEXT_IP.fetch_add(1, Ordering::SeqCst);
323 Self::open_named(&format!("dbs_tap{}", next_ip), false)
324 }
325
326 pub fn set_ip_addr(&self, ip_addr: Ipv4Addr) -> Result<()> {
328 let sock = create_socket()?;
329 let addr = create_sockaddr(ip_addr);
330
331 let mut ifreq = self.get_ifreq();
332
333 unsafe {
335 let ifru_addr = ifreq.ifr_ifru.ifru_addr.as_mut();
336 *ifru_addr = addr;
337 }
338
339 let ret = unsafe {
341 ioctl_with_ref(&sock, c_ulong::from(net_gen::sockios::SIOCSIFADDR), &ifreq)
342 };
343 if ret < 0 {
344 return Err(Error::IoctlError(IoError::last_os_error()));
345 }
346
347 Ok(())
348 }
349
350 pub fn set_netmask(&self, netmask: Ipv4Addr) -> Result<()> {
352 let sock = create_socket()?;
353 let addr = create_sockaddr(netmask);
354
355 let mut ifreq = self.get_ifreq();
356
357 unsafe {
359 let ifru_addr = ifreq.ifr_ifru.ifru_addr.as_mut();
360 *ifru_addr = addr;
361 }
362
363 let ret = unsafe {
365 ioctl_with_ref(
366 &sock,
367 c_ulong::from(net_gen::sockios::SIOCSIFNETMASK),
368 &ifreq,
369 )
370 };
371 if ret < 0 {
372 return Err(Error::IoctlError(IoError::last_os_error()));
373 }
374
375 Ok(())
376 }
377 }
378
379 fn tap_name_to_string(tap: &Tap) -> String {
380 let null_pos = tap.if_name.iter().position(|x| *x == 0).unwrap();
381 str::from_utf8(&tap.if_name[..null_pos])
382 .unwrap()
383 .to_string()
384 }
385
386 #[test]
387 fn test_tap_name() {
388 assert_eq!(
390 IFACE_NAME_MAX_LEN,
391 net_gen::ifreq__bindgen_ty_1::default()
392 .bindgen_union_field
393 .len()
394 );
395
396 let name = "a123456789abcdef";
398 match Tap::open_named(name, false) {
399 Err(Error::InvalidIfname) => (),
400 _ => panic!("Expected Error::InvalidIfname"),
401 };
402
403 let name = "a123456789abcde";
405 let tap = Tap::open_named(name, false).unwrap();
406 assert_eq!(
407 name,
408 std::str::from_utf8(&tap.if_name[0..(IFACE_NAME_MAX_LEN - 1)]).unwrap()
409 );
410 }
411
412 #[test]
413 fn test_tap_partial_eq() {
414 assert_ne!(Tap::new().unwrap(), Tap::new().unwrap());
415 }
416
417 #[test]
418 fn test_tap_configure() {
419 let next_ip = NEXT_IP.fetch_add(1, Ordering::SeqCst);
421
422 let tap = Tap::new().unwrap();
423 let ip_addr: Ipv4Addr = format!("{}{}", TAP_IP_PREFIX, next_ip).parse().unwrap();
424 let netmask: Ipv4Addr = SUBNET_MASK.parse().unwrap();
425
426 let ret = tap.set_ip_addr(ip_addr);
427 assert!(ret.is_ok());
428 let ret = tap.set_netmask(netmask);
429 assert!(ret.is_ok());
430 }
431
432 #[test]
433 fn test_set_options() {
434 let tap = Tap::new().unwrap();
436 tap.set_vnet_hdr_size(16).unwrap();
437 tap.set_offload(0).unwrap();
438
439 let faulty_tap = Tap {
440 tap_file: unsafe { File::from_raw_fd(i32::MAX) },
441 if_name: [0x01; 16],
442 if_flags: 0,
443 };
444 assert!(faulty_tap.set_vnet_hdr_size(16).is_err());
445 assert!(faulty_tap.set_offload(0).is_err());
446 }
447
448 #[test]
449 fn test_tap_enable() {
450 let tap = Tap::new().unwrap();
451 let ret = tap.enable();
452 assert!(ret.is_ok());
453 }
454
455 #[test]
456 fn test_tap_get_ifreq() {
457 let tap = Tap::new().unwrap();
458 let ret = tap.get_ifreq();
459 assert_eq!(
460 "__BindgenUnionField",
461 format!("{:?}", ret.ifr_ifrn.ifrn_name)
462 );
463 }
464
465 #[test]
466 fn test_raw_fd() {
467 let tap = Tap::new().unwrap();
468 assert_eq!(tap.as_raw_fd(), tap.tap_file.as_raw_fd());
469 }
470}