-
Notifications
You must be signed in to change notification settings - Fork 431
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rust NetDevice and NetDeviceOperationsVtable struct #208
Conversation
I'm a bit struggling with the Also I'm unsure on how to populate the kind field of that struct |
Maybe I'm misunderstanding your issue, but if you're thinking of doing something similar to the existing For the |
@adamrk I think I understand how the |
I created a proc macro, which creates a wrapped |
14ea91c
to
6e3bed3
Compare
and Now I have to document everything. help is appreciated :-) |
drivers/android/rust_binder.rs
Outdated
description: b"Android Binder", | ||
license: b"GPL v2", | ||
params: {}, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should likely go into a different commit -- or is GitHub confused due to having several commits in the PR? Please rebase to have 1 commit anyway.
//! This is a demonstration of what a small driver looks like in Rust, based on drivers/net/dummy.c. | ||
//! This code is provided as a demonstration only, not as a proposal to mass-rewrite existing drivers in Rust |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comment on #254 (comment).
I guess we can talk about this tomorrow in the call :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that was the wording of @joshtriplett, while talking about this at our last call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not fixated on the exact wording, I just want to make sure that people don't see a Rust version of an existing C driver and assume we're trying to rewrite the world in Rust. In this context, we're providing samples of what drivers would look like; we're not writing replacements.
In the future, some driver maintainers may choose to use Rust in existing drivers, but that's up to those driver maintainers, not us.
rust/helpers.c
Outdated
// See https://github.com/rust-lang/rust-bindgen/issues/1671 | ||
#if !defined(CONFIG_ARM) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
? Perhaps GitHub is confused -- please rebase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried that yesterday, but not even the rust branch builds on my system currently. Something with exports.o and symbols
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
after a git clean -xfd
(as make mrproper does not work #255 ) it builds the rebased version.
I pushed the rebased version, but I'm sot sure if/why it still makes this as a change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, now it is clear -- somehow you ended up with the comment moved outside of the #ifdef
.
rust/kernel/error.rs
Outdated
/// Used by the rtnl_link_ops macro to interface with C | ||
pub fn c_from_kernel_result<T>(r: KernelResult<T>) -> T |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it is not intended to be used by users, hide the docs.
rust/kernel/net/device.rs
Outdated
} | ||
} | ||
|
||
/// register_locked - register a network device if the RtnlLock is already hold |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this is copied from C docs, but do not put the name of the function etc.
/// | ||
/// # Safety | ||
/// | ||
/// caller must hold the RtnlLock and semaphore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// caller must hold the RtnlLock and semaphore | |
/// Caller must hold the [`RtnlLock`] and semaphore. |
And similar everywhere else.
rust/kernel/net/netlink.rs
Outdated
/*pub unsafe fn from_ptr(ptr: *const bindings::nlattr) -> &'static mut Self { | ||
(ptr as *mut NlAttr).as_mut().unwrap() | ||
}*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see a bunch of commented out code etc.
From the quick review I did above, I assume you are still working on this (i.e. there is a bunch of commented out code, |
rust/kernel/net/device.rs
Outdated
} | ||
} | ||
|
||
impl<I: NetDeviceAdapter> Deref for NetDevice<I> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we implement this Deref
and DerefMut
or should we consider this unsafe, as this exposes the direct bindings?
f3ddd55
to
018db0a
Compare
To summarise what I understood in the meeting. I will remove the line saying it is just a test driver. I finish up the abstraction in the |
If you prefer, you can put it here if you want, too. Like with Binder, for the moment we have it in this tree to have everything in one place. While they will not be merged with the Rust support, I can submit it as an extra patch (with you as the author etc.) like I did with Binder from Wedson in the RFC. @wedsonaf @TheSven73 since they have the other two potential drivers. |
Sounds great. I will create a second commit like Wedson explained, so one with abstractions and one with the driver. |
If you prefer, different PRs is also fine (and allows us to merge things bit by bit). |
I would prefer 2 commits. One pr is easier I guess, but two is also fine. Whatever you prefer. |
FYI: there's a merge conflict here. |
6ca2cb4
to
f973478
Compare
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are quite a few places where I'd like more safety comments and the address functions in net/mod.rs
could probably be safer (see my comment there).
(I didn't look at the changes to module.rs
)
pub get_ts_info: bool, | ||
} | ||
|
||
/// This trait does not include any functions. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These comments should probably be updated to reflect that this struct describes which methods are implemented by an implementation of EthToolOps
not which ones are defined by the trait itself.
/// Operations table needed for ethtool. | ||
/// [`Self::TO_USE`] defines which functions are implemented by this type. | ||
pub trait EthToolOps<T: NetDeviceAdapter>: Send + Sync + Sized { | ||
/// Struct [`EthToolToUse`] which signals which function are ipmlemeted by this type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/ipmlemeted/implemeted/
pub const RTNL_LINK_OPS_EMPTY: bindings::rtnl_link_ops = bindings::rtnl_link_ops { | ||
list: bindings::list_head { | ||
next: ptr::null::<bindings::list_head>() as *mut bindings::list_head, | ||
prev: ptr::null::<bindings::list_head>() as *mut bindings::list_head, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could use ptr::null_mut
|
||
/// Get a pointer to this struct. | ||
pub unsafe fn get_pointer(&self) -> *const bindings::rtnl_link_ops { | ||
&self.0 as *const _ as *const bindings::rtnl_link_ops |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the as *const _
seems redundant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but I think rust wants them, as this is not directly the right type for the view of rust
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think in this case you don't need it is since you're turning a &rtnl_link_ops
into a *const rtnl_link_ops
. I agree that the other ones are necessary.
(I could of course be wrong about that and it's ultimately not that important)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be that I missed .0 befor. And then you need this. Is it is valid, but rust doesn't know that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was probably the case, you can only do &T as *const T
but not &U as *const T
, even if U
only contains a T
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, as U has repr Transparent. It would also be valid, but rust isn't able to check that. That's the reason to go over *const _
But yeah, will change it.
|
||
/// Deregister the op table from the kernel. | ||
pub fn unregister(&self) { | ||
let ptr = self as *const _ as *mut bindings::rtnl_link_ops; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this could be self.get_pointer() as *mut bindings::rtnl_link_ops
/// Specifically, one should make absolutely sure that this function is | ||
/// called before TX completion of this packet can trigger. Otherwise | ||
/// the packet could potentially already be freed. | ||
pub fn tx_timestamp(&mut self) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Otherwise the packet could potentially already be freed.
This sounds like this function should potentially be unsafe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think It couldn't, as then we don't have self anymore? But not completely sure right now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't follow completely, are you saying that this is indeed safe/you're not sure about it's safety or that this could't be an unsafe method?
If we're not certain about about the safety of a method, the default should really be making it unsafe.
#[cfg(not(target_pointer_width = "64"))] | ||
fn end_pointer(&self) -> *mut u8 { | ||
let sk_reff = self.get_internal(); | ||
(sk_reff.end) as *mut u8 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unnecessary parenthesis
} | ||
|
||
fn start_xmit(skb: SkBuff, dev: &mut NetDevice<Self>) -> kernel::net::device::NetdevTX { | ||
let mut skb = skb; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use fn start_xmit(mut skb: SkBuff, ...
and remove the let mut skb = skb;
.
dev.carrier_set(new_carrier); | ||
|
||
Ok(()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this return a Result
if it can't fail?
unsafe { | ||
kernel::bindings::strlcpy( | ||
&(info.driver) as *const _ as *mut i8, | ||
b"dummy_rs\0" as *const _ as *mut i8, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you could use the cstr!
macro here
rust/kernel/net/mod.rs
Outdated
/// Please note: addr must be aligned to u16. | ||
#[cfg(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)] | ||
pub unsafe fn is_zero_ether_addr(addr: *const u8) -> bool { | ||
*(addr as *const u32) | (*((addr as usize + 4) as *const u16) as u32) == 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am pretty sure this will need to use ptr::read_unaligned
. Even if the underlying cpu architecture allows efficient unaligned accesses using normal load instructions, LLVM can optimize based on the assumption that addr as usize % 4 == 0
. For example it could vectorize in ways that would cause overlap if the address is not aligned to 4 bytes. Or it could optimize away manual alignment checks. By the way you can use addr.offset(4)
instead of addr as usize + 4
.
*(addr as *const u16) | ||
| *((addr as usize + 2) as *const u16) | ||
| *((addr as usize + 4) as *const u16) | ||
== 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking that
*(addr as *const u16) | |
| *((addr as usize + 2) as *const u16) | |
| *((addr as usize + 4) as *const u16) | |
== 0 | |
*(addr as *const [u16; 3]) == [0; 3] |
would be nicer to read. When I tested if LLVM would be able to optimize it I noticed the following: On x86_64 and aarch64 the current version uses 3 loads while the suggested version does 2 loads just like the CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
version. On armv7 this results in a branch + load from a constant pool for the suggested version while version uses 3 loads and no constant pool.
Because of this I think this suggestion should be used for CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
to avoid UB at no perf cost, but not(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
should remain the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it maybe make sense for all of these methods to take a &[u8; 6]
and be completely safe to call or is there an inherent reason we need to treat these values as u16
s?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
there would be no change. for not(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
that would require 6 loads (one for each u8) instead of 3 (one for each u16).
|
||
unsafe impl<T: NetDeviceAdapter> Sync for NetDevice<T> {} | ||
|
||
impl<T: NetDeviceAdapter> NetDevice<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that Rust's polymorphize support is not yet mature, so one copy of each function might be monomorphized for each T
. Not a big concern here though.
|
||
/// Iff flags | ||
#[repr(u32)] | ||
#[allow(non_camel_case_types)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any particular reason to use SCREAMING_SNAKE_CASE here?
use core::convert::{From, Into}; | ||
use core::ops::{Add, AddAssign, Deref, DerefMut, Sub, SubAssign}; | ||
|
||
/// Holds multiple flags to give to an interface via [`NetDevice::set_flag`]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is likely to be very common in bindings. We may want a mini version of bitflags!
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excluding tests and docs the bitflags
crate is a little less than 600 lines big. bitflags
is a slow moving crate and doesn't implement a huge set of features. I don't know what the policy on vendoring extern crates is, but I don't think there is much benefit of writing a mini version over just vendoring bitflags
. At most it would save codegen of a couple of methods, though most methods are marked as #[inline]
and thus only codegened when used.
} | ||
|
||
/// Represents which fields of [`struct ethtool_ops`] should pe populated with pointers for the trait [`EthToolOps`] | ||
pub struct EthToolToUse { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also seems to be pretty common for bindings. Maybe we need to have a attribute macro. I'll think about a sensible design.
}) | ||
} | ||
|
||
/// Return a refference to the private data of the [`NetDevice`]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/refference/reference/g
} | ||
} | ||
|
||
/// Represents which fields of [`struct ethtool_ops`] should pe populated with pointers for the trait [`EthToolOps`] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Represents which fields of [`struct ethtool_ops`] should pe populated with pointers for the trait [`EthToolOps`] | |
/// Represents which fields of [`struct ethtool_ops`] should be populated with pointers for the trait [`EthToolOps`] |
nit
ci: retry add-apt-repository to deal with network issues
Review of
|
Closing this, as it is quite outdated, and the commit history Is completely broken. |
add function for net_device functions
Contains #226 and #227