Skip to content
This repository has been archived by the owner on Oct 26, 2022. It is now read-only.

rtnetlink: add a way to set netlink flags in requests #246

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions rtnetlink/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ netlink-proto = { default-features = false, version = "0.9" }
nix = "0.22.0"
tokio = { version = "1.0.1", features = ["rt"], optional = true}
async-global-executor = { version = "2.0.2", optional = true }
bitflags = "1.3.2"

[dev-dependencies]
env_logger = "0.8.2"
Expand Down
48 changes: 21 additions & 27 deletions rtnetlink/src/addr/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,19 @@
use futures::stream::StreamExt;
use std::net::{IpAddr, Ipv4Addr};

use netlink_packet_route::{
nlas::address::Nla,
AddressMessage,
NetlinkMessage,
RtnlMessage,
AF_INET,
AF_INET6,
NLM_F_ACK,
NLM_F_CREATE,
NLM_F_EXCL,
NLM_F_REPLACE,
NLM_F_REQUEST,
use crate::{
flags::NewFlags,
packet::{nlas::address::Nla, AddressMessage, NetlinkMessage, RtnlMessage, AF_INET, AF_INET6},
try_nl,
Error,
Handle,
};

use crate::{try_nl, Error, Handle};

/// A request to create a new address. This is equivalent to the `ip address add` commands.
pub struct AddressAddRequest {
handle: Handle,
message: AddressMessage,
replace: bool,
flags: NewFlags,
}

impl AddressAddRequest {
Expand Down Expand Up @@ -73,15 +65,7 @@ impl AddressAddRequest {
AddressAddRequest {
handle,
message,
replace: false,
}
}

/// Replace existing matching address.
pub fn replace(self) -> Self {
Self {
replace: true,
..self
flags: NewFlags::new() | NewFlags::EXCL,
}
}

Expand All @@ -90,11 +74,10 @@ impl AddressAddRequest {
let AddressAddRequest {
mut handle,
message,
replace,
flags,
} = self;
let mut req = NetlinkMessage::from(RtnlMessage::NewAddress(message));
let replace = if replace { NLM_F_REPLACE } else { NLM_F_EXCL };
req.header.flags = NLM_F_REQUEST | NLM_F_ACK | replace | NLM_F_CREATE;
req.header.flags = flags.bits();

let mut response = handle.request(req)?;
while let Some(message) = response.next().await {
Expand All @@ -107,4 +90,15 @@ impl AddressAddRequest {
pub fn message_mut(&mut self) -> &mut AddressMessage {
&mut self.message
}

/// Set the netlink header flags.
///
/// # Warning
///
/// Altering the request's flags may render the request
/// ineffective. Only set the flags if you know what you're doing.
pub fn set_flags(mut self, flags: NewFlags) -> Self {
self.flags = flags;
self
}
}
24 changes: 21 additions & 3 deletions rtnetlink/src/addr/del.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
use futures::stream::StreamExt;

use crate::{
packet::{AddressMessage, NetlinkMessage, RtnlMessage, NLM_F_ACK, NLM_F_REQUEST},
flags::DelFlags,
packet::{AddressMessage, NetlinkMessage, RtnlMessage},
try_nl,
Error,
Handle,
Expand All @@ -12,22 +13,28 @@ use crate::{
pub struct AddressDelRequest {
handle: Handle,
message: AddressMessage,
flags: DelFlags,
}

impl AddressDelRequest {
pub(crate) fn new(handle: Handle, message: AddressMessage) -> Self {
AddressDelRequest { handle, message }
AddressDelRequest {
handle,
message,
flags: DelFlags::new(),
}
}

/// Execute the request
pub async fn execute(self) -> Result<(), Error> {
let AddressDelRequest {
mut handle,
message,
flags,
} = self;

let mut req = NetlinkMessage::from(RtnlMessage::DelAddress(message));
req.header.flags = NLM_F_REQUEST | NLM_F_ACK;
req.header.flags = flags.bits();
let mut response = handle.request(req)?;
while let Some(msg) = response.next().await {
try_nl!(msg);
Expand All @@ -38,4 +45,15 @@ impl AddressDelRequest {
pub fn message_mut(&mut self) -> &mut AddressMessage {
&mut self.message
}

/// Set the netlink header flags.
///
/// # Warning
///
/// Altering the request's flags may render the request
/// ineffective. Only set the flags if you know what you're doing.
pub fn set_flags(mut self, flags: DelFlags) -> Self {
self.flags = flags;
self
}
}
31 changes: 21 additions & 10 deletions rtnetlink/src/addr/get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,19 @@ use futures::{
};
use std::net::IpAddr;

use netlink_packet_route::{
nlas::address::Nla,
AddressMessage,
NetlinkMessage,
RtnlMessage,
NLM_F_DUMP,
NLM_F_REQUEST,
use crate::{
flags::GetFlags,
packet::{nlas::address::Nla, AddressMessage, NetlinkMessage, RtnlMessage},
try_rtnl,
Error,
Handle,
};

use crate::{try_rtnl, Error, Handle};

pub struct AddressGetRequest {
handle: Handle,
message: AddressMessage,
filter_builder: AddressFilterBuilder,
flags: GetFlags,
}

impl AddressGetRequest {
Expand All @@ -30,22 +28,35 @@ impl AddressGetRequest {
handle,
message: AddressMessage::default(),
filter_builder: AddressFilterBuilder::new(),
flags: GetFlags::new() | GetFlags::DUMP,
}
}

pub fn message_mut(&mut self) -> &mut AddressMessage {
&mut self.message
}

/// Set the netlink header flags.
///
/// # Warning
///
/// Altering the request's flags may render the request
/// ineffective. Only set the flags if you know what you're doing.
pub fn set_flags(mut self, flags: GetFlags) -> Self {
self.flags = flags;
self
}

pub fn execute(self) -> impl TryStream<Ok = AddressMessage, Error = Error> {
let AddressGetRequest {
mut handle,
message,
filter_builder,
flags,
} = self;

let mut req = NetlinkMessage::from(RtnlMessage::GetAddress(message));
req.header.flags = NLM_F_REQUEST | NLM_F_DUMP;
req.header.flags = flags.bits();

let filter = filter_builder.build();
match handle.request(req) {
Expand Down
132 changes: 132 additions & 0 deletions rtnetlink/src/flags.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
bitflags::bitflags! {
pub struct GetFlags: u16 {
Copy link
Collaborator

Choose a reason for hiding this comment

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

The linux/netlink.h does not say these flags is for rtnetlink only. I think there is no need to distinguish Get and Del, in stead, just name them as NetlinkMessageFlag and place to netlink-proto.

The user of this crate should aware only small potion of those flags is available for get , delete and etc.

/// Must be set on all request messages (typically from user
/// space to kernel space)
///
/// **This flag is set by default**
Copy link
Collaborator

Choose a reason for hiding this comment

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

No need to mention that as people can tell that via Default trait.
At the first time I noticed this line, I am wondering does this mean bitflags has magic on setting this constant as default?

const REQUEST = 1;
/// Indicates the message is part of a multipart message
/// terminated by NLMSG_DONE
const MULTIPART = 2;
/// Request for an acknowledgment on success. Typical
/// direction of request is from user space (CPC) to kernel
/// space (FEC).
const ACK = 4;
/// Echo this request. Typical direction of request is from
/// user space (CPC) to kernel space (FEC).
const ECHO = 8;
/// Return the complete table instead of a single entry.
const ROOT = 256;
/// Return all entries matching criteria passed in message
/// content.
const MATCH = 512;
/// Return an atomic snapshot of the table. Requires
/// `CAP_NET_ADMIN` capability or a effective UID of 0.
const ATOMIC = 1024;
/// Equivalent to `ROOT|MATCH`.
const DUMP = 768;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Using integer is vulnerable to human error.
Please just copy kernel code and use sed or other regex to convert them into rust code.

The kernel code is using this kind format:

#define NLM_F_ATOMIC	0x400
#define NLM_F_DUMP	(NLM_F_ROOT|NLM_F_MATCH)

So, the rust code should be

const ATOMIC  = 0x400;
const DUMP =  Self.ROOT | Self.MATCH;

}
}

impl GetFlags {
/// Create new `GetFlags` with only `GetFlags::REQUEST`.
pub fn new() -> Self {
GetFlags::REQUEST
}
}

impl Default for GetFlags {
/// Create new `GetFlags` with only `GetFlags::REQUEST`.
fn default() -> Self {
Self::new()
}
}

bitflags::bitflags! {
pub struct NewFlags: u16 {
/// Must be set on all request messages (typically from user
/// space to kernel space).
///
/// **This flag is set by default**
const REQUEST = 1;
/// Indicates the message is part of a multipart message
/// terminated by NLMSG_DONE
const MULTIPART = 2;
/// Request for an acknowledgment on success. Typical
/// direction of request is from user space (CPC) to kernel
/// space (FEC).
///
/// **This flag is set by default**
const ACK = 4;
/// Echo this request. Typical direction of request is from
/// user space (CPC) to kernel space (FEC).
const ECHO = 8;
/// Replace existing matching object.
const REPLACE = 256;
/// Don't replace if the object already exists.
///
/// This flag is not set by default but can is pretty commonly
/// used.
const EXCL = 512;
/// Create object if it doesn't already exist.
///
/// **This flag is set by default**
const CREATE = 1024;
/// Add to the end of the object list.
const APPEND = 2048;
/// Do not delete recursively
const NONREC = 256;
}
}

impl NewFlags {
/// Create new `NewFlags` with `REQUEST | ACK | CREATE` set.
pub fn new() -> Self {
Self::REQUEST | Self::ACK | Self::CREATE
}
}

impl Default for NewFlags {
/// Create new `NewFlags` with `REQUEST | ACK | CREATE` set.
fn default() -> Self {
Self::new()
}
}

bitflags::bitflags! {
pub struct DelFlags: u16 {
/// Must be set on all request messages (typically from user
/// space to kernel space)
///
/// **This flag is set by default**
const REQUEST = 1;
/// Indicates the message is part of a multipart message
/// terminated by NLMSG_DONE
const MULTIPART = 2;
/// Request for an acknowledgment on success. Typical
/// direction of request is from user space (CPC) to kernel
/// space (FEC).
///
/// **This flag is set by default**
const ACK = 4;
/// Echo this request. Typical direction of request is from
/// user space (CPC) to kernel space (FEC).
const ECHO = 8;
/// Do not delete recursively
const NONREC = 256;
}
}

impl DelFlags {
/// Create a new `DelFlags` with `REQUEST | ACK` set
pub fn new() -> Self {
Self::REQUEST | Self::ACK
}
}

impl Default for DelFlags {
/// Create a new `DelFlags` with `REQUEST | ACK` set
fn default() -> Self {
Self::new()
}
}
1 change: 1 addition & 0 deletions rtnetlink/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,5 @@ pub mod proto {
}
pub use netlink_proto::sys;

pub mod flags;
mod macros;
Loading