@@ -19,16 +19,26 @@ use utils::{ioctl_ioc_nr, ioctl_iow_nr};
19
19
const IFACE_NAME_MAX_LEN : usize = 16 ;
20
20
21
21
/// List of errors the tap implementation can throw.
22
- #[ derive( Debug ) ]
22
+ #[ derive( Debug , thiserror :: Error ) ]
23
23
pub enum Error {
24
- /// Unable to create tap interface.
25
- CreateTap ( IoError ) ,
26
- /// Invalid interface name.
27
- InvalidIfname ,
28
- /// ioctl failed.
29
- IoctlError ( IoError ) ,
30
- /// Couldn't open /dev/net/tun.
24
+ /// Couldn't open /dev/net/tun
25
+ #[ error( "Couldn't open /dev/net/tun: {0}" ) ]
31
26
OpenTun ( IoError ) ,
27
+ /// Invalid interface name
28
+ #[ error( "Invalid interface name" ) ]
29
+ InvalidIfname ,
30
+ /// Error while creating ifreq structure
31
+ #[ error(
32
+ "Error while creating ifreq structure: {0}. Invalid TUN/TAP Backend provided by {1}. \
33
+ Check our documentation on setting up the network devices"
34
+ ) ]
35
+ IfreqExecuteError ( IoError , String ) ,
36
+ /// Error while setting the offload flags
37
+ #[ error( "Error while setting the offload flags: {0}" ) ]
38
+ SetOffloadFlags ( IoError ) ,
39
+ /// Error while setting size of the vnet header
40
+ #[ error( "Error while setting size of the vnet header: {0}" ) ]
41
+ SetSizeOfVnetHdr ( IoError ) ,
32
42
}
33
43
34
44
pub type Result < T > = :: std:: result:: Result < T , Error > ;
@@ -66,6 +76,7 @@ fn build_terminated_if_name(if_name: &str) -> Result<[u8; IFACE_NAME_MAX_LEN]> {
66
76
Ok ( terminated_if_name)
67
77
}
68
78
79
+ #[ derive( Copy , Clone ) ]
69
80
pub struct IfReqBuilder ( ifreq ) ;
70
81
71
82
impl IfReqBuilder {
@@ -87,11 +98,10 @@ impl IfReqBuilder {
87
98
self
88
99
}
89
100
90
- pub ( crate ) fn execute < F : AsRawFd > ( mut self , socket : & F , ioctl : u64 ) -> Result < ifreq > {
101
+ pub ( crate ) fn execute < F : AsRawFd > ( mut self , socket : & F , ioctl : u64 ) -> std :: io :: Result < ifreq > {
91
102
// SAFETY: ioctl is safe. Called with a valid socket fd, and we check the return.
92
- let ret = unsafe { ioctl_with_mut_ref ( socket, ioctl, & mut self . 0 ) } ;
93
- if ret < 0 {
94
- return Err ( Error :: IoctlError ( IoError :: last_os_error ( ) ) ) ;
103
+ if unsafe { ioctl_with_mut_ref ( socket, ioctl, & mut self . 0 ) } < 0 {
104
+ return Err ( IoError :: last_os_error ( ) ) ;
95
105
}
96
106
97
107
Ok ( self . 0 )
@@ -104,8 +114,6 @@ impl Tap {
104
114
///
105
115
/// * `if_name` - the name of the interface.
106
116
pub fn open_named ( if_name : & str ) -> Result < Tap > {
107
- let terminated_if_name = build_terminated_if_name ( if_name) ?;
108
-
109
117
// SAFETY: Open calls are safe because we give a constant null-terminated
110
118
// string and verify the result.
111
119
let fd = unsafe {
@@ -117,13 +125,16 @@ impl Tap {
117
125
if fd < 0 {
118
126
return Err ( Error :: OpenTun ( IoError :: last_os_error ( ) ) ) ;
119
127
}
128
+
120
129
// SAFETY: We just checked that the fd is valid.
121
130
let tuntap = unsafe { File :: from_raw_fd ( fd) } ;
122
131
132
+ let terminated_if_name = build_terminated_if_name ( if_name) ?;
123
133
let ifreq = IfReqBuilder :: new ( )
124
134
. if_name ( & terminated_if_name)
125
135
. flags ( ( net_gen:: IFF_TAP | net_gen:: IFF_NO_PI | net_gen:: IFF_VNET_HDR ) as i16 )
126
- . execute ( & tuntap, TUNSETIFF ( ) ) ?;
136
+ . execute ( & tuntap, TUNSETIFF ( ) )
137
+ . map_err ( |io_error| Error :: IfreqExecuteError ( io_error, if_name. to_owned ( ) ) ) ?;
127
138
128
139
Ok ( Tap {
129
140
tap_file : tuntap,
@@ -144,9 +155,8 @@ impl Tap {
144
155
/// Set the offload flags for the tap interface.
145
156
pub fn set_offload ( & self , flags : c_uint ) -> Result < ( ) > {
146
157
// SAFETY: ioctl is safe. Called with a valid tap fd, and we check the return.
147
- let ret = unsafe { ioctl_with_val ( & self . tap_file , TUNSETOFFLOAD ( ) , c_ulong:: from ( flags) ) } ;
148
- if ret < 0 {
149
- return Err ( Error :: IoctlError ( IoError :: last_os_error ( ) ) ) ;
158
+ if unsafe { ioctl_with_val ( & self . tap_file , TUNSETOFFLOAD ( ) , c_ulong:: from ( flags) ) } < 0 {
159
+ return Err ( Error :: SetOffloadFlags ( IoError :: last_os_error ( ) ) ) ;
150
160
}
151
161
152
162
Ok ( ( ) )
@@ -155,9 +165,8 @@ impl Tap {
155
165
/// Set the size of the vnet hdr.
156
166
pub fn set_vnet_hdr_size ( & self , size : c_int ) -> Result < ( ) > {
157
167
// SAFETY: ioctl is safe. Called with a valid tap fd, and we check the return.
158
- let ret = unsafe { ioctl_with_ref ( & self . tap_file , TUNSETVNETHDRSZ ( ) , & size) } ;
159
- if ret < 0 {
160
- return Err ( Error :: IoctlError ( IoError :: last_os_error ( ) ) ) ;
168
+ if unsafe { ioctl_with_ref ( & self . tap_file , TUNSETVNETHDRSZ ( ) , & size) } < 0 {
169
+ return Err ( Error :: SetSizeOfVnetHdr ( IoError :: last_os_error ( ) ) ) ;
161
170
}
162
171
163
172
Ok ( ( ) )
@@ -247,8 +256,14 @@ pub mod tests {
247
256
tap_file : unsafe { File :: from_raw_fd ( -2 ) } ,
248
257
if_name : [ 0x01 ; 16 ] ,
249
258
} ;
250
- assert ! ( faulty_tap. set_vnet_hdr_size( 16 ) . is_err( ) ) ;
251
- assert ! ( faulty_tap. set_offload( 0 ) . is_err( ) ) ;
259
+ assert_eq ! (
260
+ faulty_tap. set_vnet_hdr_size( 16 ) . unwrap_err( ) . to_string( ) ,
261
+ Error :: SetSizeOfVnetHdr ( IoError :: from_raw_os_error( 9 ) ) . to_string( )
262
+ ) ;
263
+ assert_eq ! (
264
+ faulty_tap. set_offload( 0 ) . unwrap_err( ) . to_string( ) ,
265
+ Error :: SetOffloadFlags ( IoError :: from_raw_os_error( 9 ) ) . to_string( )
266
+ ) ;
252
267
}
253
268
254
269
#[ test]
0 commit comments