From f3440d87e8d8908764b676c305c08096ff0f4d9c Mon Sep 17 00:00:00 2001 From: Bochev Date: Mon, 28 Feb 2022 18:42:46 +0000 Subject: [PATCH 1/2] rtnl/neighs: add append method to af_bridge --- rtnetlink/src/neighbour/add.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/rtnetlink/src/neighbour/add.rs b/rtnetlink/src/neighbour/add.rs index 49cf243a..8e81e839 100644 --- a/rtnetlink/src/neighbour/add.rs +++ b/rtnetlink/src/neighbour/add.rs @@ -18,6 +18,7 @@ pub struct NeighbourAddRequest { handle: Handle, message: NeighbourMessage, replace: bool, + append: bool, } impl NeighbourAddRequest { @@ -42,6 +43,7 @@ impl NeighbourAddRequest { handle, message, replace: false, + append: false, } } @@ -59,6 +61,7 @@ impl NeighbourAddRequest { handle, message, replace: false, + append: false, } } @@ -128,17 +131,31 @@ impl NeighbourAddRequest { } } + /// Append to the end of the neighbours list (equivalent to `bridge fdb append`). + pub fn replace(self) -> Self { + Self { + replace: true, + ..self + } + } + /// Execute the request. pub async fn execute(self) -> Result<(), Error> { let NeighbourAddRequest { mut handle, message, replace, + append, } = self; let mut req = NetlinkMessage::from(RtnlMessage::NewNeighbour(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; + let mut flag = if replace { NLM_F_REPLACE } else { NLM_F_EXCL }; + + if append { + flag = NLM_F_APPEND; + } + + req.header.flags = NLM_F_REQUEST | NLM_F_ACK | flag | NLM_F_CREATE; let mut response = handle.request(req)?; while let Some(message) = response.next().await { From 6a1ae03abc9268eef3e894d4a5e886b3c6c22ef4 Mon Sep 17 00:00:00 2001 From: little-dude Date: Sun, 6 Mar 2022 16:51:57 +0100 Subject: [PATCH 2/2] rtnetlink: add a way to set netlink flags in requests There has been several PRs to add helper methods to set the flags in the netlink header, so it seems that this is something we should provide systematically. This PR introduces three new types to manipulate netlink flags: - `NewFlags`: flags used for "set" and "add" requests - `DelFlags`: flags used to "del" requests - `GetFlags:` flags used for "get" requests Each request now has a `set_flags` method to force a certain set of flags. This may interfere with other builder methods for certain requests, or may simply render the request ineffective, so the documentation always warns users. --- rtnetlink/Cargo.toml | 1 + rtnetlink/src/addr/add.rs | 48 +++++------ rtnetlink/src/addr/del.rs | 24 +++++- rtnetlink/src/addr/get.rs | 31 ++++--- rtnetlink/src/flags.rs | 132 +++++++++++++++++++++++++++++ rtnetlink/src/lib.rs | 1 + rtnetlink/src/link/add.rs | 34 ++++---- rtnetlink/src/link/del.rs | 32 ++++--- rtnetlink/src/link/get.rs | 37 ++++---- rtnetlink/src/link/property_add.rs | 28 ++++-- rtnetlink/src/link/property_del.rs | 26 ++++-- rtnetlink/src/link/set.rs | 27 ++++-- rtnetlink/src/neighbour/add.rs | 49 ++++------- rtnetlink/src/neighbour/del.rs | 35 +++++--- rtnetlink/src/neighbour/get.rs | 42 ++++++--- rtnetlink/src/route/add.rs | 49 +++++------ rtnetlink/src/route/del.rs | 24 +++++- rtnetlink/src/route/get.rs | 31 +++++-- rtnetlink/src/rule/add.rs | 49 +++++------ rtnetlink/src/rule/del.rs | 24 +++++- rtnetlink/src/rule/get.rs | 33 ++++++-- 21 files changed, 533 insertions(+), 224 deletions(-) create mode 100644 rtnetlink/src/flags.rs diff --git a/rtnetlink/Cargo.toml b/rtnetlink/Cargo.toml index 337f1871..cbff579f 100644 --- a/rtnetlink/Cargo.toml +++ b/rtnetlink/Cargo.toml @@ -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" diff --git a/rtnetlink/src/addr/add.rs b/rtnetlink/src/addr/add.rs index 7f73768d..b64f0b08 100644 --- a/rtnetlink/src/addr/add.rs +++ b/rtnetlink/src/addr/add.rs @@ -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 { @@ -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, } } @@ -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 { @@ -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 + } } diff --git a/rtnetlink/src/addr/del.rs b/rtnetlink/src/addr/del.rs index 9f581185..a895f070 100644 --- a/rtnetlink/src/addr/del.rs +++ b/rtnetlink/src/addr/del.rs @@ -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, @@ -12,11 +13,16 @@ 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 @@ -24,10 +30,11 @@ impl AddressDelRequest { 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); @@ -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 + } } diff --git a/rtnetlink/src/addr/get.rs b/rtnetlink/src/addr/get.rs index 6b279067..f7704f85 100644 --- a/rtnetlink/src/addr/get.rs +++ b/rtnetlink/src/addr/get.rs @@ -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 { @@ -30,6 +28,7 @@ impl AddressGetRequest { handle, message: AddressMessage::default(), filter_builder: AddressFilterBuilder::new(), + flags: GetFlags::new() | GetFlags::DUMP, } } @@ -37,15 +36,27 @@ impl AddressGetRequest { &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 { 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) { diff --git a/rtnetlink/src/flags.rs b/rtnetlink/src/flags.rs new file mode 100644 index 00000000..6cea75c0 --- /dev/null +++ b/rtnetlink/src/flags.rs @@ -0,0 +1,132 @@ +bitflags::bitflags! { + pub struct GetFlags: 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). + 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; + } +} + +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() + } +} diff --git a/rtnetlink/src/lib.rs b/rtnetlink/src/lib.rs index c4aa3f08..997f71a9 100644 --- a/rtnetlink/src/lib.rs +++ b/rtnetlink/src/lib.rs @@ -48,4 +48,5 @@ pub mod proto { } pub use netlink_proto::sys; +pub mod flags; mod macros; diff --git a/rtnetlink/src/link/add.rs b/rtnetlink/src/link/add.rs index c8cf73ad..4c3e1708 100644 --- a/rtnetlink/src/link/add.rs +++ b/rtnetlink/src/link/add.rs @@ -3,17 +3,13 @@ use futures::stream::StreamExt; use crate::{ + flags::NewFlags, packet::{ nlas::link::{Info, InfoData, InfoKind, InfoMacVlan, InfoVlan, InfoVxlan, Nla, VethInfo}, LinkMessage, NetlinkMessage, RtnlMessage, IFF_UP, - NLM_F_ACK, - NLM_F_CREATE, - NLM_F_EXCL, - NLM_F_REPLACE, - NLM_F_REQUEST, }, try_nl, Error, @@ -247,7 +243,7 @@ impl VxlanAddRequest { pub struct LinkAddRequest { handle: Handle, message: LinkMessage, - replace: bool, + flags: NewFlags, } impl LinkAddRequest { @@ -255,7 +251,7 @@ impl LinkAddRequest { LinkAddRequest { handle, message: LinkMessage::default(), - replace: false, + flags: NewFlags::new(), } } @@ -264,11 +260,10 @@ impl LinkAddRequest { let LinkAddRequest { mut handle, message, - replace, + flags, } = self; let mut req = NetlinkMessage::from(RtnlMessage::NewLink(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 { @@ -304,6 +299,17 @@ impl LinkAddRequest { &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 + } + /// Create a dummy link. /// This is equivalent to `ip link add NAME type dummy`. pub fn dummy(self, name: String) -> Self { @@ -376,14 +382,6 @@ impl LinkAddRequest { .append_nla(Nla::IfName(name)) } - /// Replace existing matching link. - pub fn replace(self) -> Self { - Self { - replace: true, - ..self - } - } - fn up(mut self) -> Self { self.message.header.flags = IFF_UP; self.message.header.change_mask = IFF_UP; diff --git a/rtnetlink/src/link/del.rs b/rtnetlink/src/link/del.rs index 298d37f2..ecd6ca1d 100644 --- a/rtnetlink/src/link/del.rs +++ b/rtnetlink/src/link/del.rs @@ -3,15 +3,8 @@ use futures::stream::StreamExt; use crate::{ - packet::{ - LinkMessage, - NetlinkMessage, - RtnlMessage, - NLM_F_ACK, - NLM_F_CREATE, - NLM_F_EXCL, - NLM_F_REQUEST, - }, + flags::DelFlags, + packet::{LinkMessage, NetlinkMessage, RtnlMessage}, try_nl, Error, Handle, @@ -20,13 +13,18 @@ use crate::{ pub struct LinkDelRequest { handle: Handle, message: LinkMessage, + flags: DelFlags, } impl LinkDelRequest { pub(crate) fn new(handle: Handle, index: u32) -> Self { let mut message = LinkMessage::default(); message.header.index = index; - LinkDelRequest { handle, message } + LinkDelRequest { + handle, + message, + flags: DelFlags::new(), + } } /// Execute the request @@ -34,9 +32,10 @@ impl LinkDelRequest { let LinkDelRequest { mut handle, message, + flags, } = self; let mut req = NetlinkMessage::from(RtnlMessage::DelLink(message)); - req.header.flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE; + req.header.flags = flags.bits(); let mut response = handle.request(req)?; while let Some(message) = response.next().await { @@ -49,4 +48,15 @@ impl LinkDelRequest { pub fn message_mut(&mut self) -> &mut LinkMessage { &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 + } } diff --git a/rtnetlink/src/link/get.rs b/rtnetlink/src/link/get.rs index 4ed4d706..41a3ad80 100644 --- a/rtnetlink/src/link/get.rs +++ b/rtnetlink/src/link/get.rs @@ -7,7 +7,8 @@ use futures::{ }; use crate::{ - packet::{constants::*, nlas::link::Nla, LinkMessage, NetlinkMessage, RtnlMessage}, + flags::GetFlags, + packet::{nlas::link::Nla, LinkMessage, NetlinkMessage, RtnlMessage}, try_rtnl, Error, Handle, @@ -16,13 +17,7 @@ use crate::{ pub struct LinkGetRequest { handle: Handle, message: LinkMessage, - // There are two ways to retrieve links: we can either dump them - // all and filter the result, or if we already know the index or - // the name of the link we're looking for, we can just retrieve - // that one. If `dump` is `true`, all the links are fetched. - // Otherwise, only the link that match the given index or name - // is fetched. - dump: bool, + flags: GetFlags, } impl LinkGetRequest { @@ -30,7 +25,7 @@ impl LinkGetRequest { LinkGetRequest { handle, message: LinkMessage::default(), - dump: true, + flags: GetFlags::new() | GetFlags::DUMP, } } @@ -46,16 +41,11 @@ impl LinkGetRequest { let LinkGetRequest { mut handle, message, - dump, + flags, } = self; let mut req = NetlinkMessage::from(RtnlMessage::GetLink(message)); - - if dump { - req.header.flags = NLM_F_REQUEST | NLM_F_DUMP; - } else { - req.header.flags = NLM_F_REQUEST; - } + req.header.flags = flags.bits(); match handle.request(req) { Ok(response) => { @@ -72,7 +62,7 @@ impl LinkGetRequest { /// Lookup a link by index pub fn match_index(mut self, index: u32) -> Self { - self.dump = false; + self.flags.remove(GetFlags::DUMP); self.message.header.index = index; self } @@ -82,8 +72,19 @@ impl LinkGetRequest { /// This function requires support from your kernel (>= 2.6.33). If yours is /// older, consider filtering the resulting stream of links. pub fn match_name(mut self, name: String) -> Self { - self.dump = false; + self.flags.remove(GetFlags::DUMP); self.message.nlas.push(Nla::IfName(name)); self } + + /// 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 + } } diff --git a/rtnetlink/src/link/property_add.rs b/rtnetlink/src/link/property_add.rs index 5780a3c0..ece659c5 100644 --- a/rtnetlink/src/link/property_add.rs +++ b/rtnetlink/src/link/property_add.rs @@ -1,17 +1,13 @@ // SPDX-License-Identifier: MIT use crate::{ + flags::NewFlags, packet::{ nlas::link::{Nla, Prop}, LinkMessage, NetlinkMessage, NetlinkPayload, RtnlMessage, - NLM_F_ACK, - NLM_F_APPEND, - NLM_F_CREATE, - NLM_F_EXCL, - NLM_F_REQUEST, }, Error, Handle, @@ -21,13 +17,19 @@ use futures::stream::StreamExt; pub struct LinkNewPropRequest { handle: Handle, message: LinkMessage, + flags: NewFlags, } impl LinkNewPropRequest { pub(crate) fn new(handle: Handle, index: u32) -> Self { let mut message = LinkMessage::default(); message.header.index = index; - LinkNewPropRequest { handle, message } + let flags = NewFlags::new() | NewFlags::EXCL | NewFlags::APPEND; + LinkNewPropRequest { + handle, + message, + flags, + } } /// Execute the request @@ -35,9 +37,10 @@ impl LinkNewPropRequest { let LinkNewPropRequest { mut handle, message, + flags, } = self; let mut req = NetlinkMessage::from(RtnlMessage::NewLinkProp(message)); - req.header.flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE | NLM_F_APPEND; + req.header.flags = flags.bits(); let mut response = handle.request(req)?; while let Some(message) = response.next().await { @@ -53,6 +56,17 @@ impl LinkNewPropRequest { &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 + } + /// Add alternative name to the link. This is equivalent to `ip link property add altname /// ALT_IFNAME dev LINK`. pub fn alt_ifname(mut self, alt_ifnames: &[&str]) -> Self { diff --git a/rtnetlink/src/link/property_del.rs b/rtnetlink/src/link/property_del.rs index aa5edd1b..d0b80920 100644 --- a/rtnetlink/src/link/property_del.rs +++ b/rtnetlink/src/link/property_del.rs @@ -1,15 +1,13 @@ // SPDX-License-Identifier: MIT use crate::{ + flags::NewFlags, packet::{ nlas::link::{Nla, Prop}, LinkMessage, NetlinkMessage, NetlinkPayload, RtnlMessage, - NLM_F_ACK, - NLM_F_EXCL, - NLM_F_REQUEST, }, Error, Handle, @@ -19,13 +17,19 @@ use futures::stream::StreamExt; pub struct LinkDelPropRequest { handle: Handle, message: LinkMessage, + flags: NewFlags, } impl LinkDelPropRequest { pub(crate) fn new(handle: Handle, index: u32) -> Self { let mut message = LinkMessage::default(); message.header.index = index; - LinkDelPropRequest { handle, message } + let flags = NewFlags::new() | NewFlags::EXCL | NewFlags::APPEND; + LinkDelPropRequest { + handle, + message, + flags, + } } /// Execute the request @@ -33,9 +37,10 @@ impl LinkDelPropRequest { let LinkDelPropRequest { mut handle, message, + flags, } = self; let mut req = NetlinkMessage::from(RtnlMessage::DelLinkProp(message)); - req.header.flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL; + req.header.flags = flags.bits(); let mut response = handle.request(req)?; while let Some(message) = response.next().await { @@ -51,6 +56,17 @@ impl LinkDelPropRequest { &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 + } + /// Remove alternative name to the link. This is equivalent to `ip link property del altname /// ALT_IFNAME dev LINK`. pub fn alt_ifname(mut self, alt_ifnames: &[&str]) -> Self { diff --git a/rtnetlink/src/link/set.rs b/rtnetlink/src/link/set.rs index 43f9fe72..80a0489b 100644 --- a/rtnetlink/src/link/set.rs +++ b/rtnetlink/src/link/set.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT use crate::{ + flags::NewFlags, packet::{ nlas::link::Nla, LinkMessage, @@ -9,10 +10,6 @@ use crate::{ IFF_NOARP, IFF_PROMISC, IFF_UP, - NLM_F_ACK, - NLM_F_CREATE, - NLM_F_EXCL, - NLM_F_REQUEST, }, try_nl, Error, @@ -24,13 +21,19 @@ use std::os::unix::io::RawFd; pub struct LinkSetRequest { handle: Handle, message: LinkMessage, + flags: NewFlags, } impl LinkSetRequest { pub(crate) fn new(handle: Handle, index: u32) -> Self { let mut message = LinkMessage::default(); message.header.index = index; - LinkSetRequest { handle, message } + let flags = NewFlags::new() | NewFlags::EXCL; + LinkSetRequest { + handle, + message, + flags, + } } /// Execute the request @@ -38,9 +41,10 @@ impl LinkSetRequest { let LinkSetRequest { mut handle, message, + flags, } = self; let mut req = NetlinkMessage::from(RtnlMessage::SetLink(message)); - req.header.flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE; + req.header.flags = flags.bits(); let mut response = handle.request(req)?; while let Some(message) = response.next().await { @@ -54,6 +58,17 @@ impl LinkSetRequest { &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 + } + /// Attach the link to a bridge (its _master_). This is equivalent to `ip link set LINK master /// BRIDGE`. To succeed, both the bridge and the link that is being attached must be UP. /// diff --git a/rtnetlink/src/neighbour/add.rs b/rtnetlink/src/neighbour/add.rs index 8e81e839..a827c456 100644 --- a/rtnetlink/src/neighbour/add.rs +++ b/rtnetlink/src/neighbour/add.rs @@ -11,14 +11,13 @@ use netlink_packet_route::{ use netlink_proto::packet::NetlinkMessage; -use crate::{Error, Handle}; +use crate::{flags::NewFlags, Error, Handle}; use std::net::IpAddr; pub struct NeighbourAddRequest { handle: Handle, message: NeighbourMessage, - replace: bool, - append: bool, + flags: NewFlags, } impl NeighbourAddRequest { @@ -42,8 +41,7 @@ impl NeighbourAddRequest { NeighbourAddRequest { handle, message, - replace: false, - append: false, + flags: NewFlags::new() | NewFlags::EXCL, } } @@ -60,8 +58,7 @@ impl NeighbourAddRequest { NeighbourAddRequest { handle, message, - replace: false, - append: false, + flags: NewFlags::new() | NewFlags::EXCL, } } @@ -123,39 +120,16 @@ impl NeighbourAddRequest { self } - /// Replace existing matching neighbor. - pub fn replace(self) -> Self { - Self { - replace: true, - ..self - } - } - - /// Append to the end of the neighbours list (equivalent to `bridge fdb append`). - pub fn replace(self) -> Self { - Self { - replace: true, - ..self - } - } - /// Execute the request. pub async fn execute(self) -> Result<(), Error> { let NeighbourAddRequest { mut handle, message, - replace, - append, + flags, } = self; let mut req = NetlinkMessage::from(RtnlMessage::NewNeighbour(message)); - let mut flag = if replace { NLM_F_REPLACE } else { NLM_F_EXCL }; - - if append { - flag = NLM_F_APPEND; - } - - req.header.flags = NLM_F_REQUEST | NLM_F_ACK | flag | NLM_F_CREATE; + req.header.flags = flags.bits(); let mut response = handle.request(req)?; while let Some(message) = response.next().await { @@ -171,4 +145,15 @@ impl NeighbourAddRequest { pub fn message_mut(&mut self) -> &mut NeighbourMessage { &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 + } } diff --git a/rtnetlink/src/neighbour/del.rs b/rtnetlink/src/neighbour/del.rs index ee13c6f7..4dd4d625 100644 --- a/rtnetlink/src/neighbour/del.rs +++ b/rtnetlink/src/neighbour/del.rs @@ -2,25 +2,26 @@ use futures::stream::StreamExt; -use netlink_packet_route::{ - constants::*, - neighbour::NeighbourMessage, - NetlinkPayload, - RtnlMessage, +use crate::{ + flags::DelFlags, + packet::{neighbour::NeighbourMessage, NetlinkMessage, NetlinkPayload, RtnlMessage}, + Error, + Handle, }; -use netlink_proto::packet::NetlinkMessage; - -use crate::{Error, Handle}; - pub struct NeighbourDelRequest { handle: Handle, message: NeighbourMessage, + flags: DelFlags, } impl NeighbourDelRequest { pub(crate) fn new(handle: Handle, message: NeighbourMessage) -> Self { - NeighbourDelRequest { handle, message } + NeighbourDelRequest { + handle, + message, + flags: DelFlags::new(), + } } /// Execute the request @@ -28,10 +29,11 @@ impl NeighbourDelRequest { let NeighbourDelRequest { mut handle, message, + flags, } = self; let mut req = NetlinkMessage::from(RtnlMessage::DelNeighbour(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 { if let NetlinkPayload::Error(e) = msg.payload { @@ -44,4 +46,15 @@ impl NeighbourDelRequest { pub fn message_mut(&mut self) -> &mut NeighbourMessage { &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 + } } diff --git a/rtnetlink/src/neighbour/get.rs b/rtnetlink/src/neighbour/get.rs index df2c9efa..da2c8273 100644 --- a/rtnetlink/src/neighbour/get.rs +++ b/rtnetlink/src/neighbour/get.rs @@ -6,26 +6,34 @@ use futures::{ FutureExt, }; -use netlink_packet_route::{ - constants::*, - neighbour::NeighbourMessage, - NetlinkPayload, - RtnlMessage, +use crate::{ + flags::GetFlags, + packet::{ + constants::*, + neighbour::NeighbourMessage, + NetlinkMessage, + NetlinkPayload, + RtnlMessage, + }, + Error, + Handle, + IpVersion, }; -use netlink_proto::packet::NetlinkMessage; - -use crate::{Error, Handle, IpVersion}; - pub struct NeighbourGetRequest { handle: Handle, message: NeighbourMessage, + flags: GetFlags, } impl NeighbourGetRequest { pub(crate) fn new(handle: Handle) -> Self { let message = NeighbourMessage::default(); - NeighbourGetRequest { handle, message } + NeighbourGetRequest { + handle, + message, + flags: GetFlags::new() | GetFlags::DUMP, + } } /// List neighbor proxies in the system (equivalent to: `ip neighbor show proxy`). @@ -44,10 +52,11 @@ impl NeighbourGetRequest { let NeighbourGetRequest { mut handle, message, + flags, } = self; let mut req = NetlinkMessage::from(RtnlMessage::GetNeighbour(message)); - req.header.flags = NLM_F_REQUEST | NLM_F_DUMP; + req.header.flags = flags.bits(); match handle.request(req) { Ok(response) => Either::Left(response.map(move |msg| { @@ -68,4 +77,15 @@ impl NeighbourGetRequest { pub fn message_mut(&mut self) -> &mut NeighbourMessage { &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 + } } diff --git a/rtnetlink/src/route/add.rs b/rtnetlink/src/route/add.rs index d6d7c5cd..98887e37 100644 --- a/rtnetlink/src/route/add.rs +++ b/rtnetlink/src/route/add.rs @@ -1,26 +1,25 @@ // SPDX-License-Identifier: MIT -use futures::stream::StreamExt; use std::{ marker::PhantomData, net::{Ipv4Addr, Ipv6Addr}, }; -use netlink_packet_route::{ - constants::*, - nlas::route::Nla, - NetlinkMessage, - RouteMessage, - RtnlMessage, -}; +use futures::stream::StreamExt; -use crate::{try_nl, Error, Handle}; +use crate::{ + flags::NewFlags, + packet::{constants::*, nlas::route::Nla, NetlinkMessage, RouteMessage, RtnlMessage}, + try_nl, + Error, + Handle, +}; /// A request to create a new route. This is equivalent to the `ip route add` commands. pub struct RouteAddRequest { handle: Handle, message: RouteMessage, - replace: bool, + flags: NewFlags, _phantom: PhantomData, } @@ -36,7 +35,7 @@ impl RouteAddRequest { RouteAddRequest { handle, message, - replace: false, + flags: NewFlags::new() | NewFlags::EXCL, _phantom: Default::default(), } } @@ -91,7 +90,7 @@ impl RouteAddRequest { RouteAddRequest { handle: self.handle, message: self.message, - replace: false, + flags: self.flags, _phantom: Default::default(), } } @@ -102,30 +101,21 @@ impl RouteAddRequest { RouteAddRequest { handle: self.handle, message: self.message, - replace: false, + flags: self.flags, _phantom: Default::default(), } } - /// Replace existing matching route. - pub fn replace(self) -> Self { - Self { - replace: true, - ..self - } - } - /// Execute the request. pub async fn execute(self) -> Result<(), Error> { let RouteAddRequest { mut handle, message, - replace, + flags, .. } = self; let mut req = NetlinkMessage::from(RtnlMessage::NewRoute(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 { @@ -138,6 +128,17 @@ impl RouteAddRequest { pub fn message_mut(&mut self) -> &mut RouteMessage { &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 + } } impl RouteAddRequest { diff --git a/rtnetlink/src/route/del.rs b/rtnetlink/src/route/del.rs index c10bcbf6..d295a125 100644 --- a/rtnetlink/src/route/del.rs +++ b/rtnetlink/src/route/del.rs @@ -3,7 +3,8 @@ use futures::stream::StreamExt; use crate::{ - packet::{NetlinkMessage, NetlinkPayload, RouteMessage, RtnlMessage, NLM_F_ACK, NLM_F_REQUEST}, + flags::DelFlags, + packet::{NetlinkMessage, NetlinkPayload, RouteMessage, RtnlMessage}, Error, Handle, }; @@ -11,11 +12,16 @@ use crate::{ pub struct RouteDelRequest { handle: Handle, message: RouteMessage, + flags: DelFlags, } impl RouteDelRequest { pub(crate) fn new(handle: Handle, message: RouteMessage) -> Self { - RouteDelRequest { handle, message } + RouteDelRequest { + handle, + message, + flags: DelFlags::new(), + } } /// Execute the request @@ -23,10 +29,11 @@ impl RouteDelRequest { let RouteDelRequest { mut handle, message, + flags, } = self; let mut req = NetlinkMessage::from(RtnlMessage::DelRoute(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 { if let NetlinkPayload::Error(e) = msg.payload { @@ -39,4 +46,15 @@ impl RouteDelRequest { pub fn message_mut(&mut self) -> &mut RouteMessage { &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 + } } diff --git a/rtnetlink/src/route/get.rs b/rtnetlink/src/route/get.rs index 8429f674..3a384ee6 100644 --- a/rtnetlink/src/route/get.rs +++ b/rtnetlink/src/route/get.rs @@ -6,13 +6,18 @@ use futures::{ FutureExt, }; -use netlink_packet_route::{constants::*, NetlinkMessage, RouteMessage, RtnlMessage}; - -use crate::{try_rtnl, Error, Handle}; +use crate::{ + flags::GetFlags, + packet::{constants::*, NetlinkMessage, RouteMessage, RtnlMessage}, + try_rtnl, + Error, + Handle, +}; pub struct RouteGetRequest { handle: Handle, message: RouteMessage, + flags: GetFlags, } /// Internet Protocol (IP) version. @@ -54,21 +59,37 @@ impl RouteGetRequest { message.header.table = RT_TABLE_UNSPEC; message.header.protocol = RTPROT_UNSPEC; - RouteGetRequest { handle, message } + RouteGetRequest { + handle, + message, + flags: GetFlags::new() | GetFlags::DUMP, + } } pub fn message_mut(&mut self) -> &mut RouteMessage { &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 { let RouteGetRequest { mut handle, message, + flags, } = self; let mut req = NetlinkMessage::from(RtnlMessage::GetRoute(message)); - req.header.flags = NLM_F_REQUEST | NLM_F_DUMP; + req.header.flags = flags.bits(); match handle.request(req) { Ok(response) => { diff --git a/rtnetlink/src/rule/add.rs b/rtnetlink/src/rule/add.rs index 1de05e61..13d10733 100644 --- a/rtnetlink/src/rule/add.rs +++ b/rtnetlink/src/rule/add.rs @@ -1,26 +1,25 @@ // SPDX-License-Identifier: MIT -use futures::stream::StreamExt; use std::{ marker::PhantomData, net::{Ipv4Addr, Ipv6Addr}, }; -use netlink_packet_route::{ - constants::*, - nlas::rule::Nla, - NetlinkMessage, - RtnlMessage, - RuleMessage, -}; +use futures::stream::StreamExt; -use crate::{try_nl, Error, Handle}; +use crate::{ + flags::NewFlags, + packet::{constants::*, nlas::rule::Nla, NetlinkMessage, RtnlMessage, RuleMessage}, + try_nl, + Error, + Handle, +}; /// A request to create a new rule. This is equivalent to the `ip rule add` command. pub struct RuleAddRequest { handle: Handle, message: RuleMessage, - replace: bool, + flags: NewFlags, _phantom: PhantomData, } @@ -34,7 +33,7 @@ impl RuleAddRequest { RuleAddRequest { handle, message, - replace: false, + flags: NewFlags::new() | NewFlags::EXCL, _phantom: Default::default(), } } @@ -77,7 +76,7 @@ impl RuleAddRequest { RuleAddRequest { handle: self.handle, message: self.message, - replace: false, + flags: self.flags, _phantom: Default::default(), } } @@ -88,30 +87,21 @@ impl RuleAddRequest { RuleAddRequest { handle: self.handle, message: self.message, - replace: false, + flags: self.flags, _phantom: Default::default(), } } - /// Replace existing matching rule. - pub fn replace(self) -> Self { - Self { - replace: true, - ..self - } - } - /// Execute the request. pub async fn execute(self) -> Result<(), Error> { let RuleAddRequest { mut handle, message, - replace, + flags, .. } = self; let mut req = NetlinkMessage::from(RtnlMessage::NewRule(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 { @@ -124,6 +114,17 @@ impl RuleAddRequest { pub fn message_mut(&mut self) -> &mut RuleMessage { &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 + } } impl RuleAddRequest { diff --git a/rtnetlink/src/rule/del.rs b/rtnetlink/src/rule/del.rs index a296b37c..205fc9f4 100644 --- a/rtnetlink/src/rule/del.rs +++ b/rtnetlink/src/rule/del.rs @@ -3,7 +3,8 @@ use futures::stream::StreamExt; use crate::{ - packet::{NetlinkMessage, RtnlMessage, RuleMessage, NLM_F_ACK, NLM_F_REQUEST}, + flags::DelFlags, + packet::{NetlinkMessage, RtnlMessage, RuleMessage}, try_nl, Error, Handle, @@ -12,11 +13,16 @@ use crate::{ pub struct RuleDelRequest { handle: Handle, message: RuleMessage, + flags: DelFlags, } impl RuleDelRequest { pub(crate) fn new(handle: Handle, message: RuleMessage) -> Self { - RuleDelRequest { handle, message } + RuleDelRequest { + handle, + message, + flags: DelFlags::new(), + } } /// Execute the request @@ -24,10 +30,11 @@ impl RuleDelRequest { let RuleDelRequest { mut handle, message, + flags, } = self; let mut req = NetlinkMessage::from(RtnlMessage::DelRule(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); @@ -38,4 +45,15 @@ impl RuleDelRequest { pub fn message_mut(&mut self) -> &mut RuleMessage { &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 + } } diff --git a/rtnetlink/src/rule/get.rs b/rtnetlink/src/rule/get.rs index 4d28a848..2da5df7e 100644 --- a/rtnetlink/src/rule/get.rs +++ b/rtnetlink/src/rule/get.rs @@ -1,19 +1,24 @@ // SPDX-License-Identifier: MIT -use crate::IpVersion; use futures::{ future::{self, Either}, stream::{StreamExt, TryStream}, FutureExt, }; -use netlink_packet_route::{constants::*, NetlinkMessage, RtnlMessage, RuleMessage}; - -use crate::{try_rtnl, Error, Handle}; +use crate::{ + flags::GetFlags, + packet::{constants::*, NetlinkMessage, RtnlMessage, RuleMessage}, + try_rtnl, + Error, + Handle, + IpVersion, +}; pub struct RuleGetRequest { handle: Handle, message: RuleMessage, + flags: GetFlags, } impl RuleGetRequest { @@ -27,21 +32,37 @@ impl RuleGetRequest { message.header.action = FR_ACT_UNSPEC; message.header.table = RT_TABLE_UNSPEC; - RuleGetRequest { handle, message } + RuleGetRequest { + handle, + message, + flags: GetFlags::new() | GetFlags::DUMP, + } } pub fn message_mut(&mut self) -> &mut RuleMessage { &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 { let RuleGetRequest { mut handle, message, + flags, } = self; let mut req = NetlinkMessage::from(RtnlMessage::GetRule(message)); - req.header.flags = NLM_F_REQUEST | NLM_F_DUMP; + req.header.flags = flags.bits(); match handle.request(req) { Ok(response) => {