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

Add ENOBUFS handling for unsolicited messages #2

Merged
merged 2 commits into from
Jan 21, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion src/framed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::{
fmt::Debug,
io,
marker::PhantomData,
mem::size_of,
pin::Pin,
task::{Context, Poll},
};
Expand All @@ -17,9 +18,13 @@ use crate::{
sys::{AsyncSocket, SocketAddr},
};
use netlink_packet_core::{
NetlinkDeserializable, NetlinkMessage, NetlinkSerializable,
NetlinkDeserializable, NetlinkHeader, NetlinkMessage, NetlinkPayload,
NetlinkSerializable, NLMSG_OVERRUN,
};

/// Buffer overrun condition
const ENOBUFS: i32 = 105;

pub struct NetlinkFramed<T, S, C> {
socket: S,
// see https://doc.rust-lang.org/nomicon/phantom-data.html
Expand Down Expand Up @@ -68,6 +73,30 @@ where

*in_addr = match ready!(socket.poll_recv_from(cx, reader)) {
Ok(addr) => addr,
// When receiving messages in multicast mode (i.e. we subscribed
// to notifications), the kernel will not wait
// for us to read datagrams before sending more.
// The receive buffer has a finite size, so once it is full (no
// more message can fit in), new messages will be dropped and
// recv calls will return `ENOBUFS`.
// This needs to be handled for applications to resynchronize
// with the contents of the kernel if necessary.
// We don't need to do anything special:
// - contents of the reader is still valid because we won't have
// partial messages in there anyways (large enough buffer)
// - contents of the socket's internal buffer is still valid
// because the kernel won't put partial data in it
Err(e) if e.raw_os_error() == Some(ENOBUFS) => {
warn!("netlink socket buffer full");
let mut hdr = NetlinkHeader::default();
hdr.length = size_of::<NetlinkHeader>() as u32;
hdr.message_type = NLMSG_OVERRUN;
let msg = NetlinkMessage::new(
hdr,
NetlinkPayload::Overrun(Vec::new()),
);
return Poll::Ready(Some((msg, SocketAddr::new(0, 0))));
}
Err(e) => {
error!("failed to read from netlink socket: {:?}", e);
return Poll::Ready(None);
Expand Down
Loading