Skip to content
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

DRAFT: [RFC]: Add rust net_device wrappers #439

Draft
wants to merge 4 commits into
base: rust
Choose a base branch
from

Conversation

Kloenk
Copy link
Member

@Kloenk Kloenk commented Jul 10, 2021

Second attempt of #208

I will try to add the dummyrs driver in the following day as second commit.

@Kloenk Kloenk force-pushed the rust-netdev-2 branch 2 times, most recently from 419ef04 to 07cd559 Compare July 10, 2021 10:48
rust/macros/module.rs Outdated Show resolved Hide resolved
Copy link
Member

@bjorn3 bjorn3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no obvious problems on a quick glance

@Kloenk Kloenk force-pushed the rust-netdev-2 branch 3 times, most recently from 3878bda to 9a65083 Compare July 10, 2021 13:25
@Kloenk
Copy link
Member Author

Kloenk commented Jul 10, 2021

Could somebody restart the CI, I don't think risc does not have the symbol kfree_skb

@ksquirrel
Copy link
Member

Review of 9a650833f0ca:

  • ⚠️ This PR adds/deletes more than 500 lines.
  • ✔️ Commit 9a65083: Looks fine!

@tivrfoa
Copy link

tivrfoa commented Jul 10, 2021

Hi! I'm a Rust newbie, and I'm just curious if all those unsafe are really necessary.

I thought unsafe would be used basically when interacting with C and probably with hardware too.

It's because the Linux kernel folks will probably notice and be suspicious about it, like: "ok, it promises to bring safety, but there's unsafe everywhere."

The SAFETY comments are good, but they are just comments in the end right? Or are they evaluated somehow?

I saw many unsafe code (in general, not in this PR) that says things like: "this is safe because some other code behaves like x"
But then it has a really tight coupling. What if "x" changes to "y"?

Will kernel driver developers have to use a lot of unsafe too if they want to use Rust?

@Kloenk
Copy link
Member Author

Kloenk commented Jul 10, 2021

I a perfect world Drivers will need no unsafe at all. Sadly at this time my only idea on how to implement the rtnl_ops is via a static mut. Static mut is usafe by design, so there unsafe is needed for every access.

In the abstraction of this pr unsafe is used quite often, because I'm only storing a pointer which I got from the C side. This is not optimal, but that is the current state of network in rust (from my side).

rust/kernel/net/ethtool.rs Outdated Show resolved Hide resolved
rust/macros/module.rs Outdated Show resolved Hide resolved
@Kloenk Kloenk force-pushed the rust-netdev-2 branch 3 times, most recently from 4b0adf7 to 60e7f47 Compare July 12, 2021 17:26
@Kloenk Kloenk mentioned this pull request Jul 12, 2021
@Kloenk Kloenk requested a review from nbdd0121 July 12, 2021 17:35
@Kloenk
Copy link
Member Author

Kloenk commented Jul 12, 2021

Let's hope the pipeline succeeds. I don't now anything else I would like to change for this pr.


int rust_helper_net_device_set_new_lstats(struct net_device *dev)
{
dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to have rust_helper_netdev_alloc_pcpu_stats and move the other logic to Rust side? Ideally rust_helper_foo should be functionally equivalent to foo.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't able do to that. because of the union stuff.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I have to rework this as part of my e1000 driver that I want to write. Really don't want to that before that :-)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Gary -- logic should not be in rust_helper_*s.

If it cannot be done for some reason, please add a comment explaining why.

rust/kernel/error.rs Show resolved Hide resolved
rust/kernel/net/device.rs Outdated Show resolved Hide resolved
rust/kernel/net/device.rs Outdated Show resolved Hide resolved
}
}

impl Add for NetIF {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to use Add and Sub? Why not implement BitOr, BitAnd, Not?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it more intuitive to read flagA + flagB. That's all. So I'm open to both. What should I do? both of them?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally tend to use flagA | flagB because flagA + flagA = flagA may seem a bit counter-intuitive for C users. But someflag - flagA does seem nicer than someflag & !flagA.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think implementing both would be a real mess. Also implementing BitOR BitAnd and Sub is also not nice. so? I find this much more intuitive, and rust is also with borrow checking and so on quite different to c

rust/kernel/net/device.rs Outdated Show resolved Hide resolved
rust/kernel/net/device.rs Outdated Show resolved Hide resolved
rust/kernel/net/mod.rs Outdated Show resolved Hide resolved
/// 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 {
// SAFETY: function already unsafe
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not correct. You should explain why the function is unsafe on the safety requirement above, e.g. say "addr must point to a valid ethernet address and 16-bit aligned, and then use the safety requirement to justify why the function is safe.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this better now?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if an encapsulation for a known-to-be-valid ethernet address pointer would help, so that we don't need these unsafe-to-call functions.

Or maybe we should just bind directly to C implementations via helpers for now, and we can come back for performance optimisations later.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I would like an Wrapper for that in the long run. for now I think it's a bit much, It's already +4k. Keep it like this until I probably need to change it for e1000?

rust/macros/net.rs Outdated Show resolved Hide resolved
@Kloenk
Copy link
Member Author

Kloenk commented Jul 12, 2021

Whey features (plural) and Flag (singular)? Because Flag is alway just one, und Features is a bit mask?

@Kloenk
Copy link
Member Author

Kloenk commented Jul 12, 2021

Moved code a bit around. I have the mod features internal, but it is private. @nbdd0121 can you take a look?

rust/kernel/net/device/mod.rs Outdated Show resolved Hide resolved
rust/kernel/net/rtnl.rs Outdated Show resolved Hide resolved
rust/kernel/net/skbuff.rs Outdated Show resolved Hide resolved
rust/macros/lib.rs Outdated Show resolved Hide resolved
rust/macros/net.rs Outdated Show resolved Hide resolved
rust/macros/net.rs Outdated Show resolved Hide resolved
@Kloenk
Copy link
Member Author

Kloenk commented Jul 12, 2021

@nbdd0121 all should have been applied now

Kloenk and others added 4 commits July 12, 2021 23:44
Signed-off-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
Enables networking support and network device drivers support
required by net_device wrappers and dummy_rs module.

Signed-off-by: Dariusz Sosnowski <dsosnowski@dsosnowski.pl>
Signed-off-by: Finn Behrens <me@kloenk.de>
Signed-off-by: Finn Behrens <me@kloenk.de>
@Kloenk
Copy link
Member Author

Kloenk commented Jul 13, 2021

@ojeda I only got one review of @ksquirrel . Is this correct behaviour? I thought it would look at every force push?

@ksquirrel
Copy link
Member

Review of 5d64fb90f526:

  • ⚠️ This PR changes more than 20 files.
  • ⚠️ This PR adds/deletes more than 500 lines.
  • ✔️ Commit efda5a1: Looks fine!
  • ✔️ Commit e2dbf35: Looks fine!
  • ⚠️ Commit 0dc000d: The commit committer does not match the commit author.
  • ❌ Commit 0dc000d: The last line of the commit message must be a Signed-off-by and must match the submitter of the PR.
  • ✔️ Commit 5d64fb9: Looks fine!

@ojeda
Copy link
Member

ojeda commented Jul 13, 2021

@ojeda I only got one review of @ksquirrel . Is this correct behaviour? I thought it would look at every force push?

I am manually running it now as needed, so you may see delays.


int rust_helper_net_device_set_new_lstats(struct net_device *dev)
{
dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Gary -- logic should not be in rust_helper_*s.

If it cannot be done for some reason, please add a comment explaining why.

@@ -276,7 +279,7 @@ where
#[macro_export]
macro_rules! from_kernel_result {
($($tt:tt)*) => {{
$crate::error::from_kernel_result_helper((|| {
$crate::from_kernel_result_helper((|| {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change? Should it be separate?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rtnl macro uses this

Self(0)
}

/// Add flag to Self.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Add flag to Self.
/// Inserts flag into the set.

/// Remove the given flag from Self.
#[inline]
pub fn remove(&mut self, flag: u64) {
self.0 &= !(flag);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the parenthesis needed? Is there no warning about it?

Suggested change
self.0 &= !(flag);
self.0 &= !flag;

self.0 |= flag;
}

/// Remove the given flag from Self.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Remove the given flag from Self.
/// Removes a flag from the set.

/// Noop if `CONFIG_NETWORK_PHY_TIMESTAMPING` is not enabled.
#[cfg(CONFIG_NETWORK_PHY_TIMESTAMPING)]
pub fn clone_tx_timestamp(&mut self) {
// SAFETY: self.ptr is valid if self is valid.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should say self.ptr is always valid by the type invariant.

self.get_internal().len
}

/// Get the Shared info for this SKBuffer.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would avoid repeating "for this SKBuffer", "for Self", etc. if they are methods.

Also, not sure why Shared is capitalized.

Suggested change
/// Get the Shared info for this SKBuffer.
/// Get shared information.

self.end_pointer() as *mut bindings::skb_shared_info
}

// NET_SKBUFF_DATA_USES_OFFSET
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is a CONFIG, perhaps we can be more clear:

Suggested change
// NET_SKBUFF_DATA_USES_OFFSET
// CONFIG_NET_SKBUFF_DATA_USES_OFFSET

We should also explain why this is done with target_pointer_width instead of the CONFIG itself.

@@ -247,3 +247,53 @@ impl<T: FnOnce()> Drop for ScopeGuard<T> {
}
}
}

/// Trait for wrappers which are holding a direct pointer that they are getting from a C side function.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a new PointerWrapper?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, types implementing this trait only have a pointer, and are not Owned like the PointerWrapper.

/// helper functions
mod helpers;

/// generic module/driver macros
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please capitalize like the rest of the code, end with period, etc.

Also, all these refactors should probably go first in another PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This refectory is there, because of need created here. It's needed now, as the rtnl macro is not a module macro. What about not a pr, but a commit?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finn, I think you need to break this whole thing up into separate a bunch of PRs. This is so that we can carefully review this in increments rather than in one huge go.

For example, and as Miguel has already suggested, changes to existing code should be factored out so that they can be reviewed separately. In fact, pure refactors without functional changes should also have their own PRs. Even if they are not immediately needed, you can say something to the effect of "This is in preparation for XXX because XXX" -- see for example #386, where there are no users yet of an enhancement, they come in a subsequent PR. See also #239 as an example of a pure refactor. They (and many others) were broken into different PRs to make reviewing easier.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I will try to add all open reviews on this I to this one, then keep this one open, but without the intention to merge as a meta, and create small prs

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Finn -- I know it takes time on the submitter's side, but it is best for everyone and reduces the overall time to get things merged.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem. But I think I can't do it until this weekend

@Kloenk Kloenk added • drivers Related to the example drivers in `drivers/`. • lib Related to the `rust/` library. labels Jul 13, 2021
@Kloenk
Copy link
Member Author

Kloenk commented Jul 16, 2021

I created to prs emerging from this one. I think I will wait until those 2 at least got some reviews, as all others would depend on at least on of them

@Kloenk Kloenk changed the title [RFC]: Add rust net_device wrappers DRAFT: [RFC]: Add rust net_device wrappers Jul 23, 2021
@Kloenk Kloenk marked this pull request as draft July 23, 2021 12:21
ojeda added a commit to ojeda/linux that referenced this pull request Jan 20, 2022
`rustfmt` (in its default config, at least) does not add a comma
in the last feature of the list, which means diffs are bigger at times.

In addition, this is how the standard library does it, and one
may argue it allows for easier `grep`ing too.

Link: Rust-for-Linux#439 (comment).

Indirectly-suggested-by: Benoit de Chezelles <benoit.dechezelles@gmail.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
• drivers Related to the example drivers in `drivers/`. • lib Related to the `rust/` library.
Development

Successfully merging this pull request may close these issues.

None yet

9 participants