Skip to content

freebsd(13.2): add netlink/netlink.h support - #5326

Open
dybucc wants to merge 2 commits into
rust-lang:mainfrom
dybucc:freebsd-netlink
Open

freebsd(13.2): add netlink/netlink.h support#5326
dybucc wants to merge 2 commits into
rust-lang:mainfrom
dybucc:freebsd-netlink

Conversation

@dybucc

@dybucc dybucc commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Description

This PR updates #3201 with merge conflicts resolved and follows the new plan at
1.

The patch adds support for netlink.h interfaces in OpenBSD, where there's an
item resolution conflict if we expose the Rust bindings alongside those of
if_mib.h. This set of APIs is "scoped" in C because they live on separate
headers. In rust-lang/libc, we reexport all items at the root crate level, which
makes item resolution fail.

Note this depends on #5325. It won't pass tests but it will build. This is
because the test templates will gather all items in a single file, so item
resolution fails. We can't really skip these items altogether from the tests, so
it may just be necessary to extend ctest to allow skipping module-specific
Rust items.

Checklist

  • Relevant tests in libc-test/semver have been updated
  • Commit messages permalink to headers for added or changed API
  • Placeholder or unstable values like *LAST or *MAX have the standard
    doc comment
  • Tested locally (cargo test -p libc-test --target mytarget); especially
    relevant for platforms that may not be checked in CI

@rustbot label +stable-nominated

Footnotes

  1. https://github.com/rust-lang/libc/pull/3201#issuecomment-4736374182

@rustbot rustbot added O-bsd O-freebsd S-waiting-on-review stable-nominated This PR should be considered for cherry-pick to libc's stable release branch labels Jul 24, 2026
@dybucc dybucc mentioned this pull request Jul 24, 2026
2 tasks
@dybucc
dybucc force-pushed the freebsd-netlink branch from f53fbf1 to c7886ff Compare July 27, 2026 06:28
@rustbot rustbot added the A-CI Area: CI-related items label Jul 27, 2026
@rustbot

This comment has been minimized.

@dybucc
dybucc force-pushed the freebsd-netlink branch 3 times, most recently from 653f197 to 0b6bb29 Compare July 29, 2026 07:34
@rustbot

This comment has been minimized.

@tgross35

Copy link
Copy Markdown
Member

The API looks fine from a quick skim, but since there is no hurry, I think it may be worth trying to add support to ctest first so the tricky test setup isn't needed. (It's useful otherwise too.)

Sketched some of that up at #5344

@dybucc

dybucc commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

Noted. Since you already pinged some contributor on that issue, I'll wait and
see whether they want to implement it. Otherwise, I'll do it.

@tgross35

tgross35 commented Aug 4, 2026

Copy link
Copy Markdown
Member

Could you try adding a separate TestGenerator instance like @mbyx recommended in that issue? Since it's split off, that should avoid the need to reexport libc::netlink at test root too.

@tgross35

tgross35 commented Aug 4, 2026

Copy link
Copy Markdown
Member

Either author or blocked, depending on whether that works.

@rustbot author

@rustbot

rustbot commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@rustbot

This comment has been minimized.

@rustbot

This comment has been minimized.

@rustbot

This comment has been minimized.

Comment thread libc-test/build/main.rs Outdated
Comment thread libc-test/build/main.rs Outdated
Comment thread src/new/freebsd/netlink/mod.rs Outdated
@dybucc

dybucc commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

It seems having separate invocations gets the job done just fine. Still, that
was the same thing I tried in the initial patch. The added complexity comes when
we need to get the SemVer tests to pass.

Those seem to me like they're going to need extending (though it's notably less
work than with ctest as it's all in libc-test's build script.)

@rustbot

This comment has been minimized.

@dybucc

dybucc commented Aug 11, 2026

Copy link
Copy Markdown
Contributor Author

I haven't tried this but do things just work™️ if the semver tests have lines
like netlink::NETLINK_ADD_MEMBERSHIP?

@tgross35 They do. Just cleaned up commit history as all tests seem to pass now.

@dybucc
dybucc force-pushed the freebsd-netlink branch 2 times, most recently from 2b52cf7 to 30133e0 Compare August 11, 2026 07:19
Comment thread src/new/mod.rs Outdated
Comment thread src/new/freebsd/netlink/netlink_generic.rs Outdated
Comment thread libc-test/semver/freebsd.txt Outdated
Comment thread libc-test/build/main.rs Outdated
Comment on lines +2609 to +2629
let mut netlink_cfg = cfg.clone();
headers!(netlink_cfg, "netlink/netlink.h",);
netlink_cfg
.skip_struct(|ty| !matches!(ty.ident(), "sockaddr_nl"))
.skip_const(|c| !is_netlink_const(c))
.skip_union(|_| true)
.skip_alias(|_| true)
.skip_static(|_| true)
.skip_fn(|_| true)
.skip_c_enum(|_| true);
ctest::generate_test(&mut netlink_cfg, "../src/lib.rs", "netlink_ctest_output.rs").unwrap();

// We must restore the above sure-skips because `TestGenerator` shares skips
// between cloned instances (here `cfg` and `netlink_cfg`.)
cfg.skip_struct(|_| false)
.skip_const(|_| false)
.skip_union(|_| false)
.skip_alias(|_| false)
.skip_static(|_| false)
.skip_fn(|_| false)
.skip_c_enum(|_| false);

@tgross35 tgross35 Aug 11, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sharing skips isn't intentional, why does this happen?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

A prior review comment 1 mentioned a recent patch that allows sharing skips
between instances of TestGenerator. I assumed you wanted me to use the now
shallow copy semantics of that type to avoid calling anew ctest_cfg() for
netlink_cfg.

This then needs resetting to the "defaults," because otherwise some skipping
functions that we do call with netlink_cfg but not with cfg end up affecting
cfg.

Footnotes

  1. https://github.com/rust-lang/libc/pull/5326#discussion_r3747219428

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sort of, but there's no shallow copy. I guess the Rc<dyn Fn()> might look that way but it's just letting closures be used from multiple places like function pointers - it's not like cloning to a TestGenerator then adding skips to one means that the other TestGenerator gets those same skips.

(The pattern for something like that would be field: Rc<RefCell<Box<dyn Fn()>>> or field: Rc<RefCell<Vec<Box<dyn Fn()>>>.)

So you can delete the .skip_union(|_| false) ...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done, but I've still got questions.

How is there not? TestGenerator automatically derives Clone and that would
make the inner Vec<Skip> use its Clone implementation, which itself depends
on the Clone impl of Skip. Skip is just an alias to a Rc<...>, so it
would call into the Clone impl for Rc<T: ?Sized>, which will yield a shallow
copy of T.

Granted, you'd still need some form of interior mutability to change those
skips, but I don't think skips are made to be "modified" once "registered."

What am I missing?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

IME the term "shallow copy" typically means (1) there exists a real or theoretical corresponding deep copy, and (2) the difference between a shallow and deep copy is observable. With this code:

let cfg1 = TestGenerator::new();
let cfg2 = cfg1.clone();
cfg1.skip_struct(|ty| ty.ident() == "foo");
// ...

I'd definitely consider it a shallow copy if both cfg1 and cfg2 skip foo as a result (would be pretty surprising API). I thought that's what you were expecting at first based on the comments and is why I mentioned the RefCell patterns, but perhaps this wasn't correct?

That shouldn't be what happens, cfg1 and cfg2 are decoupled. Existing skips do stick around when cloning, but it's more like cloning a Vec to get the same base items then being able to add on independently.

There is a "shallow copy" with the Rc<dyn Fn()> and it wouldn't be technically incorrect to refer to it as such, but I'd find it an unintuitive use of the term because you need to go out of your way and use interior mutability to observe it. It's not too far off from duplicating a fn() or &u32—technically shallow and observable, but the distinction isn't especially meaningful.

This is mostly just opinion, though, I'm sure others may look at it differently.

Comment thread libc-test/build/main.rs Outdated
@rustbot

This comment has been minimized.

@rustbot

This comment has been minimized.

@rustbot

This comment has been minimized.

@dybucc
dybucc force-pushed the freebsd-netlink branch 3 times, most recently from 745bf15 to be6cc74 Compare August 12, 2026 07:14
@dybucc

dybucc commented Aug 15, 2026

Copy link
Copy Markdown
Contributor Author

@rustbot ready

@tgross35 tgross35 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Cc @asomers, could you take a look when you get the chance?

View changes since this review

Comment thread libc-test/build/main.rs Outdated
Comment on lines +2609 to +2629
let mut netlink_cfg = cfg.clone();
headers!(netlink_cfg, "netlink/netlink.h",);
netlink_cfg
.skip_struct(|ty| !matches!(ty.ident(), "sockaddr_nl"))
.skip_const(|c| !is_netlink_const(c))
.skip_union(|_| true)
.skip_alias(|_| true)
.skip_static(|_| true)
.skip_fn(|_| true)
.skip_c_enum(|_| true);
ctest::generate_test(&mut netlink_cfg, "../src/lib.rs", "netlink_ctest_output.rs").unwrap();

// We must restore the above sure-skips because `TestGenerator` shares skips
// between cloned instances (here `cfg` and `netlink_cfg`.)
cfg.skip_struct(|_| false)
.skip_const(|_| false)
.skip_union(|_| false)
.skip_alias(|_| false)
.skip_static(|_| false)
.skip_fn(|_| false)
.skip_c_enum(|_| false);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sort of, but there's no shallow copy. I guess the Rc<dyn Fn()> might look that way but it's just letting closures be used from multiple places like function pointers - it's not like cloning to a TestGenerator then adding skips to one means that the other TestGenerator gets those same skips.

(The pattern for something like that would be field: Rc<RefCell<Box<dyn Fn()>>> or field: Rc<RefCell<Vec<Box<dyn Fn()>>>.)

So you can delete the .skip_union(|_| false) ...

Comment thread libc-test/build/main.rs Outdated
Comment thread src/new/freebsd/netlink/mod.rs Outdated
Comment thread src/new/freebsd/netlink/netlink_generic.rs Outdated
Comment thread src/new/mod.rs Outdated
@rustbot

rustbot commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

dybucc and others added 2 commits August 21, 2026 09:05
This is an early subset of the Netlink interface, but it proves
sufficient for monitoring changes in IP addresses. Coverage can be
extended later as needed.  See [^1] and [^2].

[^1]: <https://github.com/freebsd/freebsd-src/blob/df9d6403caa6426e92f5e100602f4d2be474bbae/sys/netlink/netlink.h>
[^2]: <https://github.com/freebsd/freebsd-src/blob/df9d6403caa6426e92f5e100602f4d2be474bbae/sys/netlink/netlink_generic.h>

A small workaround has been necessary in the SemVer tests to ensure we
get the right paths to the public submodules for the `netlink/netlink.h`
and `netlink/netling_generic.h` interfaces. Those symbols now are
prepended a `netlink` super module path.

Signed-off-by: Yann Dirson <yann.dirson@vates.fr>

Co-authored-by: Yann Dirson <yann.dirson@vates.fr>
Add specific test for `netlink/netlink.h` bindings. This is necessary to
avoid conflicts with the bindings for `net/if_mib.h`. libc-test now
builds two different `TestGenerator` instances.

One of the instances builds tests for the same set of bindings as before
this patchset, while the other builds tests only for the
`netlink/netlink.h` bindings.
@dybucc

dybucc commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

@rustbot ready

@tgross35 tgross35 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Also it looks like CI isn't yet passing, currently stuck on style but make sure the FreeBSD tests pass too.

View changes since this review

Comment thread libc-test/build/main.rs
Comment on lines +2476 to +2477
#[inline]
fn is_netlink_const(it: &ctest::Const) -> bool {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Drop #[inline], no need to really worried about that kind of performance optimizations in tests and this isn't a bottleneck.

Comment thread src/new/freebsd/mod.rs

pub(crate) mod net;
pub(crate) mod netinet6;
pub mod netlink;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can now be pub(crate) right?

Comment thread src/new/mod.rs

pub use freebsd::netlink::netlink::*;
pub use freebsd::netlink::netlink_generic::*;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe just rename src/new/freebsd/netlink/netlink.rs to netlink_.rs or something, so we can keep the glob export? Think this might be done elsewhere as well.

Just add a comment by the mod netlink_ explaining why it has that name.

Comment thread libc-test/build/main.rs
Comment on lines +2617 to +2621
.skip_union(|_| true)
.skip_alias(|_| true)
.skip_static(|_| true)
.skip_fn(|_| true)
.skip_c_enum(|_| true);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These shouldn't be needed anymore right?

Comment thread libc-test/build/main.rs Outdated
Comment on lines +2609 to +2629
let mut netlink_cfg = cfg.clone();
headers!(netlink_cfg, "netlink/netlink.h",);
netlink_cfg
.skip_struct(|ty| !matches!(ty.ident(), "sockaddr_nl"))
.skip_const(|c| !is_netlink_const(c))
.skip_union(|_| true)
.skip_alias(|_| true)
.skip_static(|_| true)
.skip_fn(|_| true)
.skip_c_enum(|_| true);
ctest::generate_test(&mut netlink_cfg, "../src/lib.rs", "netlink_ctest_output.rs").unwrap();

// We must restore the above sure-skips because `TestGenerator` shares skips
// between cloned instances (here `cfg` and `netlink_cfg`.)
cfg.skip_struct(|_| false)
.skip_const(|_| false)
.skip_union(|_| false)
.skip_alias(|_| false)
.skip_static(|_| false)
.skip_fn(|_| false)
.skip_c_enum(|_| false);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

IME the term "shallow copy" typically means (1) there exists a real or theoretical corresponding deep copy, and (2) the difference between a shallow and deep copy is observable. With this code:

let cfg1 = TestGenerator::new();
let cfg2 = cfg1.clone();
cfg1.skip_struct(|ty| ty.ident() == "foo");
// ...

I'd definitely consider it a shallow copy if both cfg1 and cfg2 skip foo as a result (would be pretty surprising API). I thought that's what you were expecting at first based on the comments and is why I mentioned the RefCell patterns, but perhaps this wasn't correct?

That shouldn't be what happens, cfg1 and cfg2 are decoupled. Existing skips do stick around when cloning, but it's more like cloning a Vec to get the same base items then being able to add on independently.

There is a "shallow copy" with the Rc<dyn Fn()> and it wouldn't be technically incorrect to refer to it as such, but I'd find it an unintuitive use of the term because you need to go out of your way and use interior mutability to observe it. It's not too far off from duplicating a fn() or &u32—technically shallow and observable, but the distinction isn't especially meaningful.

This is mostly just opinion, though, I'm sure others may look at it differently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-CI Area: CI-related items O-bsd O-freebsd S-waiting-on-author stable-nominated This PR should be considered for cherry-pick to libc's stable release branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants