Skip to main content

PooledConnection

Struct PooledConnection 

Source
#[non_exhaustive]
pub struct PooledConnection<'p, P: ProtocolState> { /* private fields */ }
Expand description

A pooled connection borrowed from a ConnectionPool.

Implements Deref<Target = Connection<P>> so every typed connection method is callable directly on the guard. On drop the underlying Connection is returned to the pool. Use Self::invalidate to mark the connection as bad and have it dropped (instead of returned) on guard drop.

Implementations§

Source§

impl<'p, P: ProtocolState + Send + Sync + 'static> PooledConnection<'p, P>

Source

pub fn invalidate(self)

Mark this connection as unhealthy. On drop, the connection is closed AND the pool schedules an async task to build a replacement and put it back into the pool (0.19 Finding C — closes the silent capacity decay where every invalidate permanently shrank the pool by one connection).

Use when you’ve observed a recoverable error that suggests the socket may be in a bad state (rare; most kernel errors are per-request, not per-socket).

Replenish race window. The replacement is built on a tokio::spawn (off the drop path because it’s async). Between invalidate and the new connection landing in the pool there is a brief window where acquire() may block — up to the acquire_timeout. If replacement construction itself fails (kernel module missing, namespace gone, permission revoked), the failure is tracing::error!-logged and the pool’s effective capacity drops by one. Subsequent invalidates that succeed restore capacity.

Consumes the guard (Plan 162) so a subsequent &*p is a compile error (E0382 — use of moved value) instead of a runtime panic.

p.invalidate();
let _ = &*p;  // compile error: borrow of moved value `p`

Methods from Deref<Target = Connection<P>>§

Source

pub fn subscribe_group(&self, name: &str) -> Result<()>

Send a typed GENL request and parse the typed response.

Builds a netlink message from request: M, sends it, receives the response, and parses the first non-ACK reply into R: GenlMessage + Default. Returns the parsed R.

R::default() is the parse seed: missing attributes leave fields at their type-default values (matches the #[derive(GenlMessage)] from_bytes semantics — see its docs for the rationale).

§Example
use nlink::macros::*;
use nlink::Connection;

#[genl_family(name = "my_family", version = 1)]
pub struct MyFamily;

#[derive(GenlCommand, Debug, Clone, Copy)]
#[genl_command(repr = "u8")]
pub enum MyCmd { Get = 1 }

#[derive(GenlAttribute, Debug, Clone, Copy)]
#[genl_attribute(repr = "u16")]
pub enum MyAttr { Id = 1, Name = 2 }

#[derive(GenlMessage, Debug, Default)]
#[genl_message(cmd = MyCmd::Get)]
pub struct GetReq { #[genl_attr(MyAttr::Id)] pub id: u32 }

#[derive(GenlMessage, Debug, Default)]
#[genl_message(cmd = MyCmd::Get)]
pub struct GetReply {
    #[genl_attr(MyAttr::Id)] pub id: u32,
    #[genl_attr(MyAttr::Name)] pub name: String,
}

let reply: GetReply = conn.send_typed(GetReq { id: 0 }).await?;
println!("got id={} name={}", reply.id, reply.name);

Subscribe to a named multicast group exposed by this family.

Looks up the group ID via GenlFamily::mcast_group (the map was populated at construction time by #[genl_family]’s resolve_async impl, parsing CTRL_ATTR_MCAST_GROUPS out of CTRL_CMD_GETFAMILY). Returns Error::FamilyNotFound when the named group isn’t registered on this kernel — e.g., asking for "monitor" on a kernel too old to ship that group, or a binary/kernel mismatch.

Pair with the EventSource-driven events() (when the family implements EventSource) to consume typed notifications from the kernel.

§Example
use nlink::netlink::{Connection, genl::dpll::Dpll};
use tokio_stream::StreamExt;

let conn = Connection::<Dpll>::new_async().await?;
conn.subscribe_group("monitor")?;
let mut events = conn.events().await;
while let Some(evt) = events.next().await {
    println!("{:?}", evt?);
}
Source

pub async fn send_typed<M, R>(&self, request: M) -> Result<R>

Source

pub async fn dump_typed_stream<M, R>( &self, request: M, ) -> Result<GenlTypedDumpStream<'_, F, R>>

Stream a typed GENL dump (multi-frame response).

Builds a NLM_F_REQUEST | NLM_F_DUMP request from request: M, awaits the send, and returns a Stream that yields each kernel frame parsed into R.

Compare with Self::send_typed (one request, one response). For the canonical kernel dump shape (*_CMD_GET with NLM_F_DUMP returning many frames) this is the right helper.

Source

pub fn socket(&self) -> &NetlinkSocket

Get the underlying socket.

Source

pub fn is_dispatcher_mode(&self) -> bool

Whether this connection is in dispatcher mode (#134).

Source

pub fn state(&self) -> &P

Get the protocol state.

Source

pub fn get_timeout(&self) -> Option<Duration>

Get the configured timeout.

Source

pub fn enable_strict_checking(&self, on: bool) -> Result<()>

Enable kernel-side strict checking (NETLINK_GET_STRICT_CHK, kernel 5.0+). When enabled, the kernel validates dump request filters strictly and returns an error if they reference unknown attributes — useful for catching client/kernel-version mismatches early during development.

Off by default for backwards compatibility with older kernels. The setsockopt is silently a no-op on pre-5.0 kernels (returns Ok(()) on ENOPROTOOPT), so calling enable_strict_checking(true) unconditionally is safe.

§Example
use nlink::{Connection, Route};
let conn = Connection::<Route>::new()?;
conn.enable_strict_checking(true)?;
Source

pub fn set_ext_ack(&self, on: bool) -> Result<()>

Toggle extended-ack reception (NETLINK_EXT_ACK, kernel 4.12+). Enabled by default during socket construction — disabling is rarely useful in practice. Exposed for parity with neli’s API and for callers that explicitly want to suppress the trailing TLVs in error responses.

Silently a no-op on pre-4.12 kernels (returns Ok(()) on ENOPROTOOPT).

See Error::Kernel::ext_ack for what these TLVs contain once parsed.

§Example
use nlink::{Connection, Route};
let conn = Connection::<Route>::new()?;
conn.set_ext_ack(false)?;  // disable; rarely useful
Source

pub fn dispatcher(&self) -> &Dispatcher

Plan 234 — access this Connection’s dispatcher.

The dispatcher routes ENOBUFS into ResyncMarker::ResyncStart for every active multicast subscriber and fans out multicast frames to per-group broadcast channels. Public so subscriber constructors (events, conntrack, nftables, devlink, dpll, nl80211 multicast) can register their broadcast receivers alongside the kernel-side add_membership call.

The dispatcher is cheap to clone (Arc-wrapped internally); returning &Dispatcher keeps the ownership story simple (the Connection owns the canonical handle).

Source

pub async fn dump_stream<T>( &self, msg_type: u16, ) -> Result<DumpStream<'_, P, T>>
where T: FromNetlink + Unpin,

Stream a dump response as it arrives, one typed message per next().await. Terminates on NLMSG_DONE.

Compared to Self::dump_typed, this method does not buffer the full response. On large dumps (BGP-scale route tables, conntrack tables on a busy gateway) this avoids materializing gigabytes of intermediate buffers.

§Cancellation

Dropping the stream is safe. The kernel terminates the dump when no more frames are read; any in-flight frames sit in the kernel socket buffer briefly until they age out. The next request on this connection has a different sequence number so stale frames are skipped.

§Errors

The stream yields Err for per-message parse failures but keeps iterating — kernel sometimes ships partially-parseable frames in long dumps and dropping them silently would mask real bugs. NLMSG_ERROR and socket-level errors terminate the stream after yielding the error.

§Example
use tokio_stream::StreamExt;
use nlink::{Connection, Route};
use nlink::netlink::messages::LinkMessage;
use nlink::netlink::message::NlMsgType;

let conn = Connection::<Route>::new()?;
let mut stream = conn.dump_stream::<LinkMessage>(NlMsgType::RTM_GETLINK).await?;
while let Some(link) = stream.next().await {
    let link = link?;
    println!("{}: {}", link.ifindex(), link.name_or("?"));
}
Source

pub async fn dump_stream_with_body<T>( &self, msg_type: u16, body: &[u8], ) -> Result<DumpStream<'_, P, T>>
where T: FromNetlink + Unpin,

Like dump_stream, but the caller supplies the body bytes that follow the nlmsghdr. Bypasses T::write_dump_header entirely — use this when the dump request body is runtime-parameterized (e.g. nfgenmsg.family for conntrack, or a fixed body + filter attribute for nft rules).

T still parses each frame’s body via FromNetlink::from_bytes; the per-frame body shape is whatever the kernel emits (independent of the request body).

Source

pub async fn events(&self) -> EventSubscription<'_, P>

Create an event stream that borrows this connection.

Returns a Stream that borrows the connection. The connection remains usable for non-recv operations (set_strict_checking, subscribe to add more groups, etc.) while the stream is active.

0.19 Finding B — now async. Acquires the connection’s request lock for the subscription’s lifetime so concurrent streams (multiple events(), events() + dump_stream()) no longer race on poll_recv and steal each other’s frames. Concurrent dumps on a connection with an active events stream will block until the events stream is dropped — use a second Connection (or ConnectionPool) for query-in-parallel patterns.

§Example
use nlink::netlink::{Connection, KobjectUevent};
use tokio_stream::StreamExt;

let conn = Connection::<KobjectUevent>::new()?;

// Borrow connection for streaming (0.19: now async).
let mut events = conn.events().await;
while let Some(event) = events.try_next().await? {
    if event.is_add() {
        println!("Device added: {}", event.devpath);
    }
}

// Connection still usable
drop(events);

Trait Implementations§

Source§

impl<P: ProtocolState> Deref for PooledConnection<'_, P>

Source§

type Target = Connection<P>

The resulting type after dereferencing.
Source§

fn deref(&self) -> &Connection<P>

Dereferences the value.
Source§

impl<P: ProtocolState> Drop for PooledConnection<'_, P>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

§

impl<'p, P> !RefUnwindSafe for PooledConnection<'p, P>

§

impl<'p, P> !UnwindSafe for PooledConnection<'p, P>

§

impl<'p, P> Freeze for PooledConnection<'p, P>
where P: Freeze,

§

impl<'p, P> Send for PooledConnection<'p, P>
where P: Send,

§

impl<'p, P> Sync for PooledConnection<'p, P>
where P: Sync + Send,

§

impl<'p, P> Unpin for PooledConnection<'p, P>
where P: Unpin,

§

impl<'p, P> UnsafeUnpin for PooledConnection<'p, P>
where P: UnsafeUnpin,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more