Skip to content

aya: support socket filter reuseport attach - #1578

Merged
tamird merged 2 commits into
aya-rs:mainfrom
swananan:feat/socket-filter-reuseport
May 27, 2026
Merged

aya: support socket filter reuseport attach#1578
tamird merged 2 commits into
aya-rs:mainfrom
swananan:feat/socket-filter-reuseport

Conversation

@swananan

@swananan swananan commented May 22, 2026

Copy link
Copy Markdown
Contributor

Add ReusePortSocketFilter as the aya program abstraction for attaching a BPF_PROG_TYPE_SOCKET_FILTER program as a SO_REUSEPORT selector. Regular socket filters and reuseport selectors use different attachment paths, different kernel slots, and different return-value semantics, so modeling them as separate aya program views makes the user-facing API explicit.

Aya still follows libbpf section rules: socket filter programs load from SEC("socket"), and aya does not introduce a socket/reuseport section. Since the section cannot distinguish the two views, ReusePortSocketFilter is selected by the user's try_into target type over the same loaded program type.

Fixes #441.

Added/updated tests?

We strongly encourage you to add a test for your changes.

  • Yes

Checklist

  • Rust code has been formatted with cargo +nightly fmt.
  • All clippy lints have been fixed.
    You can find failing lints with cargo xtask clippy.
  • Unit tests are passing locally with cargo test.
  • The Integration tests are passing locally.
  • I have blessed any API changes with cargo xtask public-api --bless.

(Optional) What GIF best describes this PR or how it makes you feel?


This change is Reviewable

@swananan
swananan requested a review from a team as a code owner May 22, 2026 12:31
@netlify

netlify Bot commented May 22, 2026

Copy link
Copy Markdown

Deploy Preview for aya-rs-docs ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 9dc3dbf
🔍 Latest deploy log https://app.netlify.com/projects/aya-rs-docs/deploys/6a15bc32f8e40d00086aa75c
😎 Deploy Preview https://deploy-preview-1578--aya-rs-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@tamird tamird 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.

@tamird reviewed 5 files and all commit messages, and made 6 comments.
Reviewable status: 5 of 7 files reviewed, 6 unresolved discussions (waiting on swananan).


aya/src/programs/mod.rs line 78 at r1 (raw file):

// `libc` exposes `SO_ATTACH_REUSEPORT_EBPF` on all architectures, but
// `SO_DETACH_REUSEPORT_BPF` is still commented out in libc's
// `src/unix/linux_like/linux/arch/{mips,powerpc,sparc}/mod.rs`.

can we fix upstream? did we already discuss this?


aya/src/programs/socket_filter.rs line 88 at r1 (raw file):

/// A program used to inspect and filter incoming packets on a socket.
///
/// [`SocketFilter`] programs can be attached as regular socket filters with

this is interesting - this really means that these are two different program types. it's hard to imagine a program that would make sense for both attachment types.

should we encode the attachment type on the program itself so that the constant we pass is implied?


aya/src/programs/socket_filter.rs line 91 at r1 (raw file):

/// [`SocketFilterAttachType::SocketFilter`]. In that mode, the return value is
/// interpreted as a packet length: `0` drops the packet, and a non-zero value
/// accepts or trims it.

what do you mean by "or" here?


aya/src/programs/socket_filter.rs line 169 at r1 (raw file):

    /// already-attached error. The program return value is interpreted as a
    /// packet length: `0` drops the packet, and a non-zero value accepts or
    /// trims it.

this last sentence is redundant and misplaced - it already exists on the type

Code quote:

    /// already-attached error. The program return value is interpreted as a
    /// packet length: `0` drops the packet, and a non-zero value accepts or
    /// trims it.

aya/src/programs/socket_filter.rs line 204 at r1 (raw file):

    }

    /// Detaches the current program for `attach_type` from the given socket.

There's something I don't understand: is there one slot per attachment type or one slot total? What happens if you attach with one and attempt to detach with the other?


test/integration-common/src/lib.rs line 187 at r1 (raw file):

}

pub mod socket_filter {

logical separation between groups please

@swananan
swananan force-pushed the feat/socket-filter-reuseport branch from 8e97f3e to fd0b17d Compare May 22, 2026 16:13

@swananan swananan left a comment

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.

@swananan made 6 comments.
Reviewable status: 3 of 7 files reviewed, 6 unresolved discussions (waiting on tamird).


aya/src/programs/mod.rs line 78 at r1 (raw file):

Previously, tamird (Tamir Duberstein) wrote…

can we fix upstream? did we already discuss this?

Yes, rust-lang/libc#5081 has been merged, but the change haven't been released yet. So I just moved constants here for now. I will open a follow up PR, once the libc releases a new version.


aya/src/programs/socket_filter.rs line 88 at r1 (raw file):

Previously, tamird (Tamir Duberstein) wrote…

this is interesting - this really means that these are two different program types. it's hard to imagine a program that would make sense for both attachment types.

should we encode the attachment type on the program itself so that the constant we pass is implied?

Got your point, these programs won't make sense for both attachment modes because the return values semantics differ.

But in my understanding, aya loader follows libbpf section rules, so I don't think we should add SEC("socket/reuseport"). libbpf only has SEC("socket")` for socket filters program type.
https://github.com/libbpf/libbpf/blob/dd92bef7f6c7a00bb0312554119b6d9cf38e4f32/src/libbpf.c#L9979-L9981


aya/src/programs/socket_filter.rs line 91 at r1 (raw file):

Previously, tamird (Tamir Duberstein) wrote…

what do you mean by "or" here?

Done.


aya/src/programs/socket_filter.rs line 169 at r1 (raw file):

Previously, tamird (Tamir Duberstein) wrote…

this last sentence is redundant and misplaced - it already exists on the type

Done.


aya/src/programs/socket_filter.rs line 204 at r1 (raw file):

Previously, tamird (Tamir Duberstein) wrote…

There's something I don't understand: is there one slot per attachment type or one slot total? What happens if you attach with one and attempt to detach with the other?

Good question, I hadn't realized this case (:

I tested it, and reuseport and socket filter don't share the same kernel slot. Attaching one attachment type and detaching with the other returns ENOENT instead of removing the other attachment. I added a test case covering both directions.

IMO, UDP socket would be more appropriate for this test. To keep it consistent with the existing tests, I only added a smoke test using a TCP listener.


test/integration-common/src/lib.rs line 187 at r1 (raw file):

Previously, tamird (Tamir Duberstein) wrote…

logical separation between groups please

Done.

@tamird tamird 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.

@tamird reviewed 3 files and all commit messages, made 2 comments, and resolved 4 discussions.
Reviewable status: 5 of 7 files reviewed, 2 unresolved discussions (waiting on swananan).


aya/src/programs/mod.rs line 78 at r1 (raw file):

Previously, swananan (swananan) wrote…

Yes, rust-lang/libc#5081 has been merged, but the change haven't been released yet. So I just moved constants here for now. I will open a follow up PR, once the libc releases a new version.

Ah ok! Might be good to add a TODO(rust-lang/libc@95c9572): ...

the link to the commit makes it easy to check in one click if the commit is included in a release


aya/src/programs/socket_filter.rs line 88 at r1 (raw file):

Previously, swananan (swananan) wrote…

Got your point, these programs won't make sense for both attachment modes because the return values semantics differ.

But in my understanding, aya loader follows libbpf section rules, so I don't think we should add SEC("socket/reuseport"). libbpf only has SEC("socket")` for socket filters program type.
https://github.com/libbpf/libbpf/blob/dd92bef7f6c7a00bb0312554119b6d9cf38e4f32/src/libbpf.c#L9979-L9981

I see. Well, could we still model it as two different program types in aya that both impl TryFrom for the underlying "libbpf type"?

@swananan
swananan force-pushed the feat/socket-filter-reuseport branch from fd0b17d to 6b515f7 Compare May 23, 2026 14:23

@swananan swananan left a comment

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.

@swananan made 2 comments.
Reviewable status: 3 of 8 files reviewed, 2 unresolved discussions (waiting on tamird).


aya/src/programs/mod.rs line 78 at r1 (raw file):

Previously, tamird (Tamir Duberstein) wrote…

Ah ok! Might be good to add a TODO(rust-lang/libc@95c9572): ...

the link to the commit makes it easy to check in one click if the commit is included in a release

Done.


aya/src/programs/socket_filter.rs line 88 at r1 (raw file):

Previously, tamird (Tamir Duberstein) wrote…

I see. Well, could we still model it as two different program types in aya that both impl TryFrom for the underlying "libbpf type"?

Done. Added a separate ReusePortSocketFilter program abstraction for reuseport socket filters, which makes the API more explicit. This still has some constraints because Aya follows libbpf’s SEC("socket") section rules, so I documented those as well.

@swananan

Copy link
Copy Markdown
Contributor Author

This looks like a GitHub-side CI failure rather than a code regression.

@swananan
swananan force-pushed the feat/socket-filter-reuseport branch 3 times, most recently from 2c56b1f to 793bd24 Compare May 24, 2026 02:41

@tamird tamird 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.

@codex review

@tamird reviewed 6 files and all commit messages, made 6 comments, and resolved 2 discussions.
Reviewable status: all files reviewed, 5 unresolved discussions (waiting on swananan).


test/integration-test/src/tests/prog_test_run.rs line 22 at r4 (raw file):

}

fn skip_if_socket_filter_test_run_unsupported() -> bool {

i left this kind of comment on another recent PR: the word "skip" in this function name does not make sense.

but also why did we need to extract this function?


test/integration-test/src/tests/socket_filter.rs line 32 at r4 (raw file):

const ACCEPT_TIMEOUT: Duration = Duration::from_secs(10);
const TEST_PAYLOAD: &[u8] = b"hello-world";
const LISTEN_BACKLOG: u32 = SOMAXCONN as u32;

do we need this? why not pass 0 or 1?


test/integration-test/src/tests/socket_filter.rs line 41 at r4 (raw file):

}

fn skip_if_reuseport_detach_unsupported() -> bool {

same comment as above


test/integration-test/src/tests/socket_filter.rs line 84 at r4 (raw file):

    //   https://github.com/torvalds/linux/blob/v6.9/net/core/sock_reuseport.c#L124-L130
    let first_accept = async {
        let (_stream, _) = first

why even bind this?


test/integration-test/src/tests/socket_filter.rs line 193 at r4 (raw file):

    }

    let _netns = NetNsGuard::new();

do we need all these guards? why?

@tamird
tamird self-requested a review May 25, 2026 14:51
@swananan
swananan force-pushed the feat/socket-filter-reuseport branch from 793bd24 to 3f1f8b3 Compare May 26, 2026 12:16
Add ReusePortSocketFilter as the aya program abstraction for
attaching a BPF_PROG_TYPE_SOCKET_FILTER program as a SO_REUSEPORT
selector. Regular socket filters and reuseport selectors use different
attachment paths, different kernel slots, and different return-value
semantics, so modeling them as separate aya program views makes the
user-facing API explicit.

Aya still follows libbpf section rules: socket filter programs load
from SEC("socket"), and aya does not introduce a socket/reuseport
section. Since the section cannot distinguish the two views,
ReusePortSocketFilter is selected by the user's try_into target type
over the same loaded program type.

Fixes aya-rs#441.
@swananan
swananan force-pushed the feat/socket-filter-reuseport branch 2 times, most recently from 32efc36 to f2266ea Compare May 26, 2026 12:36

@swananan swananan left a comment

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.

@swananan made 6 comments.
Reviewable status: 2 of 9 files reviewed, 6 unresolved discussions (waiting on tamird).


test/integration-test/src/tests/socket_filter.rs line 32 at r4 (raw file):

Previously, tamird (Tamir Duberstein) wrote…

do we need this? why not pass 0 or 1?

I used the constant to avoid a magic number😂, but SOMAXCONN is misleading here since the exact backlog does not matter. I changed it to 1.


test/integration-test/src/tests/socket_filter.rs line 41 at r4 (raw file):

Previously, tamird (Tamir Duberstein) wrote…

same comment as above

Done.


test/integration-test/src/tests/socket_filter.rs line 84 at r4 (raw file):

Previously, tamird (Tamir Duberstein) wrote…

why even bind this?

I introduced a small helper function here, let me know if you prefer this inline.


test/integration-test/src/tests/socket_filter.rs line 193 at r4 (raw file):

Previously, tamird (Tamir Duberstein) wrote…

do we need all these guards? why?

Just realized these guards are not needed here. I also removed the same guards from the sk_reuseport tests, except for the migration test.


test/integration-test/src/tests/prog_test_run.rs line 22 at r4 (raw file):

Previously, tamird (Tamir Duberstein) wrote…

i left this kind of comment on another recent PR: the word "skip" in this function name does not make sense.

but also why did we need to extract this function?

Done. we shouldn't extract this logic, removed the change from this file.


a discussion (no related file):
Split the integration test changes into a separate commit.

@swananan

Copy link
Copy Markdown
Contributor Author

Looks like GitHub is having some issues.

@swananan
swananan force-pushed the feat/socket-filter-reuseport branch 4 times, most recently from b12d94d to 378a648 Compare May 26, 2026 14:36

@swananan swananan left a comment

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.

@swananan made 1 comment.
Reviewable status: 2 of 9 files reviewed, 6 unresolved discussions (waiting on tamird).


test/integration-test/src/tests/socket_filter.rs line 193 at r4 (raw file):

Previously, swananan (swananan) wrote…

Just realized these guards are not needed here. I also removed the same guards from the sk_reuseport tests, except for the migration test.

failures:
tests::sk_reuseport::sk_reuseport_clear_index_changes_selection::case_1_legacy

tests::sk_reuseport::sk_reuseport_clear_index_changes_selection::case_2_btf

tests::sk_reuseport::sk_reuseport_selects_expected_listener::case_1_legacy

tests::sk_reuseport::sk_reuseport_selects_expected_listener::case_2_btf

tests::socket_filter::socket_filter_attach_types_use_separate_slots

tests::socket_filter::socket_filter_reuseport_replacement_uses_latest_program

tests::socket_filter::socket_filter_reuseport_selects_listener_and_detaches

tests::socket_filter::socket_filter_reuseport_stays_attached_after_ebpf_drop

Error: called `Result::unwrap()` on an `Err` value: Os { code: 101, kind: NetworkUnreachable, message: "Network unreachable" }

The interface lo is brought up by NetNsGuard, while the CI VM init does not bring up the lo interface. So we do need these guards. I also added comments for them.

@tamird tamird 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.

@tamird reviewed 7 files and all commit messages, made 2 comments, and resolved 6 discussions.
Reviewable status: all files reviewed, 2 unresolved discussions (waiting on swananan).


test/integration-test/src/tests/socket_filter.rs line 76 at r10 (raw file):

async fn accept_and_return_index(listener: &TcpListener, index: i64) -> i64 {
    let (_stream, _) = listener

the question from below is still relevant here. why even have anything at all on the left hand side of the =?


test/integration-test/src/tests/socket_filter.rs line 93 at r10 (raw file):

    //   https://github.com/torvalds/linux/blob/v6.9/net/core/sock_reuseport.c#L124-L130
    let accepted = select(
        Box::pin(accept_and_return_index(

you shouldn't have to box these futures

@swananan
swananan force-pushed the feat/socket-filter-reuseport branch from 378a648 to 9dc3dbf Compare May 26, 2026 15:28

@swananan swananan left a comment

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.

@swananan made 2 comments.
Reviewable status: 5 of 9 files reviewed, 2 unresolved discussions (waiting on tamird).


test/integration-test/src/tests/socket_filter.rs line 76 at r10 (raw file):

Previously, tamird (Tamir Duberstein) wrote…

the question from below is still relevant here. why even have anything at all on the left hand side of the =?

Done.


test/integration-test/src/tests/socket_filter.rs line 93 at r10 (raw file):

Previously, tamird (Tamir Duberstein) wrote…

you shouldn't have to box these futures

Switched to the tokio::select!, which doesn't use the box.

@tamird tamird 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.

@codex review

@tamird reviewed 4 files and all commit messages, made 1 comment, and resolved 2 discussions.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on swananan).

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR extends Aya’s socket-filter support to cover the SO_ATTACH_REUSEPORT_EBPF attachment mode by introducing a dedicated ReusePortSocketFilter wrapper alongside the existing SocketFilter, and plumbing this through the core Program API and integration tests.

Changes:

  • Add ReusePortSocketFilter as a separate program wrapper for attaching BPF_PROG_TYPE_SOCKET_FILTER programs via SO_ATTACH_REUSEPORT_EBPF and detaching via SO_DETACH_REUSEPORT_BPF.
  • Extend aya::programs::Program with a ReusePortSocketFilter variant and custom TryFrom handling to allow selecting the wrapper type at conversion time.
  • Add/extend integration eBPF programs and integration tests to validate reuseport selection behavior, detach semantics, and coexistence with regular socket filters.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
aya/src/programs/mod.rs Adds reuseport sockopt constants, re-exports ReusePortSocketFilter, adds Program variant, and custom TryFrom logic for socket-filter wrappers.
aya/src/programs/socket_filter.rs Introduces ReusePortSocketFilter and expands docs/behavior around regular vs reuseport socket-filter attachment semantics.
aya/src/programs/sk_reuseport.rs Switches reuseport sockopt constants to the shared definitions in programs::mod.
test/integration-common/src/lib.rs Adds new shared constants/indices used by reuseport socket-filter integration tests.
test/integration-ebpf/src/socket_filter.rs Adds two new socket-filter programs that return reuseport selection indices.
test/integration-test/src/tests/socket_filter.rs Adds integration tests covering reuseport attach/detach behavior and slot separation vs regular socket filters.
test/integration-test/src/tests/sk_reuseport.rs Adds comments clarifying network namespace setup for CI reliability.
xtask/public-api/aya.txt Updates the blessed public API surface to include ReusePortSocketFilter and related Program enum changes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread aya/src/programs/socket_filter.rs
@tamird

tamird commented May 27, 2026

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

$option as libc::c_int,
$option,
ptr::from_ref(value).cast(),
size_of_val(value) as libc::socklen_t,
Comment on lines 14 to 20
use crate::{
VerifierLogLevel,
programs::{
ProgramData, ProgramError, ProgramType, links::FdLink, load_program_with_attach_type,
ProgramData, ProgramError, ProgramType, SO_ATTACH_REUSEPORT_EBPF, SO_DETACH_REUSEPORT_BPF,
links::FdLink, load_program_with_attach_type,
},
};
@tamird
tamird merged commit b6cfeb5 into aya-rs:main May 27, 2026
21 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

attach() for SocketFilter needs an enum

3 participants