Skip to content

Commit a01effb

Browse files
authored
Add index_to_name_inlined (#1397)
1 parent b53e0b2 commit a01effb

File tree

3 files changed

+115
-25
lines changed

3 files changed

+115
-25
lines changed

src/backend/libc/net/netdevice.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,11 @@
22
33
#![allow(unsafe_code)]
44

5-
#[cfg(feature = "alloc")]
6-
use crate::alloc::string::String;
75
use crate::backend::c;
86
use crate::backend::io::syscalls::ioctl;
97
use crate::fd::BorrowedFd;
108
use crate::io;
11-
#[cfg(feature = "alloc")]
12-
use c::SIOCGIFNAME;
13-
use c::{__c_anonymous_ifr_ifru, c_char, ifreq, IFNAMSIZ, SIOCGIFINDEX};
9+
use c::{__c_anonymous_ifr_ifru, c_char, ifreq, IFNAMSIZ, SIOCGIFINDEX, SIOCGIFNAME};
1410

1511
pub(crate) fn name_to_index(fd: BorrowedFd<'_>, if_name: &str) -> io::Result<u32> {
1612
let if_name_bytes = if_name.as_bytes();
@@ -31,8 +27,7 @@ pub(crate) fn name_to_index(fd: BorrowedFd<'_>, if_name: &str) -> io::Result<u32
3127
Ok(index as u32)
3228
}
3329

34-
#[cfg(feature = "alloc")]
35-
pub(crate) fn index_to_name(fd: BorrowedFd<'_>, index: u32) -> io::Result<String> {
30+
pub(crate) fn index_to_name(fd: BorrowedFd<'_>, index: u32) -> io::Result<(usize, [u8; 16])> {
3631
let mut ifreq = ifreq {
3732
ifr_name: [0; 16],
3833
ifr_ifru: __c_anonymous_ifr_ifru {
@@ -43,12 +38,12 @@ pub(crate) fn index_to_name(fd: BorrowedFd<'_>, index: u32) -> io::Result<String
4338
unsafe { ioctl(fd, SIOCGIFNAME as _, &mut ifreq as *mut ifreq as _) }?;
4439

4540
if let Some(nul_byte) = ifreq.ifr_name.iter().position(|char| *char == 0) {
46-
let name: String = ifreq.ifr_name[..nul_byte]
47-
.iter()
48-
.map(|v| *v as u8 as char)
49-
.collect();
41+
let mut buf = [0u8; 16];
42+
ifreq.ifr_name.iter().enumerate().for_each(|(idx, c)| {
43+
buf[idx] = *c as u8;
44+
});
5045

51-
Ok(name)
46+
Ok((nul_byte, buf))
5247
} else {
5348
Err(io::Errno::INVAL)
5449
}

src/backend/linux_raw/net/netdevice.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,8 @@ use crate::io;
88
use core::ptr::addr_of_mut;
99
use core::{slice, str};
1010
use linux_raw_sys::ctypes::c_char;
11-
use linux_raw_sys::ioctl::SIOCGIFINDEX;
12-
#[cfg(feature = "alloc")]
13-
use linux_raw_sys::ioctl::SIOCGIFNAME;
11+
use linux_raw_sys::ioctl::{SIOCGIFINDEX, SIOCGIFNAME};
1412
use linux_raw_sys::net::{ifreq, ifreq__bindgen_ty_1, ifreq__bindgen_ty_2, IFNAMSIZ};
15-
#[cfg(feature = "alloc")]
16-
use {alloc::borrow::ToOwned, alloc::string::String};
1713

1814
pub(crate) fn name_to_index(fd: BorrowedFd<'_>, if_name: &str) -> io::Result<u32> {
1915
let if_name_bytes = if_name.as_bytes();
@@ -40,8 +36,7 @@ pub(crate) fn name_to_index(fd: BorrowedFd<'_>, if_name: &str) -> io::Result<u32
4036
Ok(index as u32)
4137
}
4238

43-
#[cfg(feature = "alloc")]
44-
pub(crate) fn index_to_name(fd: BorrowedFd<'_>, index: u32) -> io::Result<String> {
39+
pub(crate) fn index_to_name(fd: BorrowedFd<'_>, index: u32) -> io::Result<(usize, [u8; 16])> {
4540
let mut ifreq = ifreq {
4641
ifr_ifrn: ifreq__bindgen_ty_1 { ifrn_name: [0; 16] },
4742
ifr_ifru: ifreq__bindgen_ty_2 {
@@ -61,9 +56,10 @@ pub(crate) fn index_to_name(fd: BorrowedFd<'_>, index: u32) -> io::Result<String
6156
let ifrn_name =
6257
unsafe { slice::from_raw_parts(ifrn_name.as_ptr().cast::<u8>(), ifrn_name.len()) };
6358

64-
str::from_utf8(ifrn_name)
65-
.map_err(|_| io::Errno::ILSEQ)
66-
.map(ToOwned::to_owned)
59+
let mut name_buf = [0; 16];
60+
name_buf[..ifrn_name.len()].copy_from_slice(ifrn_name);
61+
62+
Ok((nul_byte, name_buf))
6763
} else {
6864
Err(io::Errno::INVAL)
6965
}

src/net/netdevice.rs

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
use crate::fd::AsFd;
2020
use crate::io;
2121
#[cfg(feature = "alloc")]
22-
use alloc::string::String;
22+
use alloc::{borrow::ToOwned, string::String};
2323

2424
/// `ioctl(fd, SIOCGIFINDEX, ifreq)`—Returns the interface index for a given
2525
/// name.
@@ -42,6 +42,8 @@ pub fn name_to_index<Fd: AsFd>(fd: Fd, if_name: &str) -> io::Result<u32> {
4242
///
4343
/// See the [module-level documentation] for information about `fd` usage.
4444
///
45+
/// See also [`index_to_name_inlined`] which does not require `alloc` feature.
46+
///
4547
/// # References
4648
/// - [Linux]
4749
///
@@ -52,12 +54,84 @@ pub fn name_to_index<Fd: AsFd>(fd: Fd, if_name: &str) -> io::Result<u32> {
5254
#[cfg(feature = "alloc")]
5355
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
5456
pub fn index_to_name<Fd: AsFd>(fd: Fd, index: u32) -> io::Result<String> {
55-
crate::backend::net::netdevice::index_to_name(fd.as_fd(), index)
57+
let (len, ifrn_name) = crate::backend::net::netdevice::index_to_name(fd.as_fd(), index)?;
58+
59+
core::str::from_utf8(&ifrn_name[..len])
60+
.map_err(|_| io::Errno::ILSEQ)
61+
.map(ToOwned::to_owned)
62+
}
63+
64+
/// `ioctl(fd, SIOCGIFNAME, ifreq)`—Returns the interface name for a given
65+
/// index.
66+
///
67+
/// See the [module-level documentation] for information about `fd` usage.
68+
///
69+
/// # References
70+
/// - [Linux]
71+
///
72+
/// [module-level documentation]: self
73+
/// [Linux]: https://man7.org/linux/man-pages/man7/netdevice.7.html
74+
#[inline]
75+
#[doc(alias = "SIOCGIFNAME")]
76+
pub fn index_to_name_inlined<Fd: AsFd>(fd: Fd, index: u32) -> io::Result<InlinedName> {
77+
let (len, ifrn_name) = crate::backend::net::netdevice::index_to_name(fd.as_fd(), index)?;
78+
79+
// Check if the name is valid UTF-8.
80+
core::str::from_utf8(&ifrn_name[..len])
81+
.map_err(|_| io::Errno::ILSEQ)
82+
.map(|_| InlinedName {
83+
len,
84+
name: ifrn_name,
85+
})
86+
}
87+
88+
/// The inlined interface name.
89+
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
90+
pub struct InlinedName {
91+
len: usize,
92+
name: [u8; 16],
93+
}
94+
95+
impl InlinedName {
96+
/// Returns the str representation of the inlined name.
97+
pub fn as_str(&self) -> &str {
98+
self.as_ref()
99+
}
100+
101+
/// Returns the bytes representation of the inlined name.
102+
pub fn as_bytes(&self) -> &[u8] {
103+
self.as_ref()
104+
}
105+
}
106+
107+
impl AsRef<[u8]> for InlinedName {
108+
fn as_ref(&self) -> &[u8] {
109+
&self.name[..self.len]
110+
}
111+
}
112+
113+
impl AsRef<str> for InlinedName {
114+
fn as_ref(&self) -> &str {
115+
// SAFETY: `InlinedName` is constructed with valid UTF-8.
116+
core::str::from_utf8(&self.name[..self.len]).unwrap()
117+
}
118+
}
119+
120+
impl core::borrow::Borrow<str> for InlinedName {
121+
fn borrow(&self) -> &str {
122+
self.as_ref()
123+
}
124+
}
125+
126+
impl core::fmt::Display for InlinedName {
127+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
128+
self.as_str().fmt(f)
129+
}
56130
}
57131

58132
#[cfg(test)]
59133
mod tests {
60-
use crate::backend::net::netdevice::{index_to_name, name_to_index};
134+
use super::{index_to_name, index_to_name_inlined, name_to_index};
61135
use crate::fd::AsFd;
62136
use crate::net::{AddressFamily, SocketFlags, SocketType};
63137

@@ -81,6 +155,31 @@ mod tests {
81155
assert_eq!(Ok(loopback_index), name_to_index(fd.as_fd(), "lo"));
82156
}
83157

158+
#[test]
159+
fn test_index_to_name_inlined() {
160+
let fd = crate::net::socket_with(
161+
AddressFamily::INET,
162+
SocketType::DGRAM,
163+
SocketFlags::CLOEXEC,
164+
None,
165+
)
166+
.unwrap();
167+
168+
let loopback_index = std::fs::read_to_string("/sys/class/net/lo/ifindex")
169+
.unwrap()
170+
.as_str()
171+
.split_at(1)
172+
.0
173+
.parse::<u32>()
174+
.unwrap();
175+
assert_eq!(
176+
"lo",
177+
index_to_name_inlined(fd.as_fd(), loopback_index)
178+
.unwrap()
179+
.as_str(),
180+
);
181+
}
182+
84183
#[test]
85184
#[cfg(feature = "alloc")]
86185
fn test_index_to_name() {

0 commit comments

Comments
 (0)