From 4ff98370dbacd084addb06aeab054ee00571374e Mon Sep 17 00:00:00 2001 From: Wongyu Lee Date: Sat, 16 Mar 2024 13:38:06 +0000 Subject: [PATCH] feat(rsln): support genl netlink --- agent/src/netlink.rs | 2 +- cni/src/command/add.rs | 2 +- cni/src/command/delete.rs | 2 +- rsln/Cargo.toml | 2 +- rsln/README.md | 13 +++ rsln/src/core/message.rs | 2 +- rsln/src/core/socket.rs | 26 +++++ rsln/src/handle/addr.rs | 4 +- rsln/src/handle/generic.rs | 68 ++++++++++++ rsln/src/handle/link.rs | 4 +- rsln/src/handle/mod.rs | 1 + rsln/src/handle/neigh.rs | 7 +- rsln/src/handle/routing.rs | 4 +- rsln/src/handle/sock_handle.rs | 9 +- rsln/src/lib.rs | 2 +- rsln/src/netlink.rs | 21 +++- rsln/src/{route => types}/addr.rs | 6 +- rsln/src/types/generic.rs | 158 +++++++++++++++++++++++++++ rsln/src/{route => types}/link.rs | 77 ++++--------- rsln/src/{route => types}/message.rs | 55 ++++++++-- rsln/src/{route => types}/mod.rs | 4 + rsln/src/{route => types}/neigh.rs | 4 +- rsln/src/{route => types}/routing.rs | 2 +- 23 files changed, 383 insertions(+), 92 deletions(-) create mode 100644 rsln/src/handle/generic.rs rename rsln/src/{route => types}/addr.rs (95%) create mode 100644 rsln/src/types/generic.rs rename rsln/src/{route => types}/link.rs (88%) rename rsln/src/{route => types}/message.rs (94%) rename rsln/src/{route => types}/mod.rs (94%) rename rsln/src/{route => types}/neigh.rs (96%) rename rsln/src/{route => types}/routing.rs (98%) diff --git a/agent/src/netlink.rs b/agent/src/netlink.rs index d7b6bd8..8c4191e 100644 --- a/agent/src/netlink.rs +++ b/agent/src/netlink.rs @@ -5,7 +5,7 @@ use std::{ use anyhow::{anyhow, Result}; use ipnet::IpNet; -use rsln::route::{ +use rsln::types::{ addr::AddressBuilder, link::{Kind, Link, LinkAttrs, VxlanAttrs}, neigh::NeighborBuilder, diff --git a/cni/src/command/add.rs b/cni/src/command/add.rs index e6e6c7c..06dfc75 100644 --- a/cni/src/command/add.rs +++ b/cni/src/command/add.rs @@ -7,7 +7,7 @@ use nix::sched::{setns, CloneFlags}; use rand::Rng; use rsln::{ netlink::Netlink, - route::{ + types::{ addr::AddressBuilder, link::{Kind, LinkAttrs}, routing::RoutingBuilder, diff --git a/cni/src/command/delete.rs b/cni/src/command/delete.rs index 674bcac..202e201 100644 --- a/cni/src/command/delete.rs +++ b/cni/src/command/delete.rs @@ -6,7 +6,7 @@ use nix::sched::{setns, CloneFlags}; use reqwest::Client; use rsln::{ netlink::Netlink, - route::{addr::AddrFamily, link::LinkAttrs}, + types::{addr::AddrFamily, link::LinkAttrs}, }; use sinabro_config::Config; use tokio::task::spawn_blocking; diff --git a/rsln/Cargo.toml b/rsln/Cargo.toml index 5ab5dcb..d1b0171 100644 --- a/rsln/Cargo.toml +++ b/rsln/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rsln" -version = "0.0.1" +version = "0.0.2" edition = "2021" license = "Apache-2.0" repository = "https://github.com/wqld/sinabro/tree/main/rsln" diff --git a/rsln/README.md b/rsln/README.md index 0048314..264f6c5 100644 --- a/rsln/README.md +++ b/rsln/README.md @@ -1,3 +1,16 @@ # rsln Implements the netlink protocol based kernel interfaces required by the sinabro project in Rust. + +## Supported netlink protocols + +### Netlink route + +- link +- address +- route +- neighbor + +### Generic netlink + +- family diff --git a/rsln/src/core/message.rs b/rsln/src/core/message.rs index 1861080..cd8b9f5 100644 --- a/rsln/src/core/message.rs +++ b/rsln/src/core/message.rs @@ -149,7 +149,7 @@ impl Header { #[cfg(test)] mod tests { - use crate::route::message::{Attribute, RouteAttr}; + use crate::types::message::{Attribute, RouteAttr}; use super::*; diff --git a/rsln/src/core/socket.rs b/rsln/src/core/socket.rs index 530071d..4c44f00 100644 --- a/rsln/src/core/socket.rs +++ b/rsln/src/core/socket.rs @@ -38,6 +38,32 @@ impl Socket { } } + pub fn block(&self) -> Result<()> { + match unsafe { + libc::fcntl( + self.fd, + libc::F_SETFL, + libc::fcntl(self.fd, libc::F_GETFL, 0) & !libc::O_NONBLOCK, + ) + } { + -1 => Err(Error::last_os_error()), + _ => Ok(()), + } + } + + pub fn non_block(&self) -> Result<()> { + match unsafe { + libc::fcntl( + self.fd, + libc::F_SETFL, + libc::fcntl(self.fd, libc::F_GETFL, 0) | libc::O_NONBLOCK, + ) + } { + -1 => Err(Error::last_os_error()), + _ => Ok(()), + } + } + pub fn send(&self, buf: &[u8]) -> Result<()> { let (addr, addr_len) = self.sa.as_raw(); diff --git a/rsln/src/handle/addr.rs b/rsln/src/handle/addr.rs index d0f98d1..bb3a41c 100644 --- a/rsln/src/handle/addr.rs +++ b/rsln/src/handle/addr.rs @@ -8,7 +8,7 @@ use ipnet::IpNet; use crate::{ core::message::Message, - route::{ + types::{ addr::Address, link::Link, message::{AddressMessage, Attribute, RouteAttr}, @@ -144,8 +144,8 @@ impl AddrHandle<'_> { #[cfg(test)] mod tests { use crate::{ - route::{addr::AddressBuilder, link::LinkAttrs}, test_setup, + types::{addr::AddressBuilder, link::LinkAttrs}, }; #[test] diff --git a/rsln/src/handle/generic.rs b/rsln/src/handle/generic.rs new file mode 100644 index 0000000..d5f084e --- /dev/null +++ b/rsln/src/handle/generic.rs @@ -0,0 +1,68 @@ +use std::ops::{Deref, DerefMut}; + +use anyhow::{anyhow, Result}; + +use crate::{ + core::message::Message, + handle::zero_terminated, + types::{ + generic::{GenlFamilies, GenlFamily}, + message::{Attribute, GenlMessage, RouteAttr}, + }, +}; + +use super::sock_handle::SocketHandle; + +pub struct GenericHandle<'a> { + pub socket: &'a mut SocketHandle, +} + +impl<'a> Deref for GenericHandle<'a> { + type Target = SocketHandle; + + fn deref(&self) -> &Self::Target { + self.socket + } +} + +impl DerefMut for GenericHandle<'_> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.socket + } +} + +impl<'a> From<&'a mut SocketHandle> for GenericHandle<'a> { + fn from(socket: &'a mut SocketHandle) -> Self { + Self { socket } + } +} + +impl GenericHandle<'_> { + pub fn list_family(&mut self) -> Result { + let mut req = Message::new(libc::GENL_ID_CTRL as u16, libc::NLM_F_DUMP); + let msg = GenlMessage::get_family_message(); + + req.add(&msg.serialize()?); + + let msgs = self.request(&mut req, 0)?; + + GenlFamilies::try_from(msgs) + } + + pub fn get_family(&mut self, name: &str) -> Result { + let mut req = Message::new(libc::GENL_ID_CTRL as u16, 0); + let msg = GenlMessage::get_family_message(); + let family_name = + RouteAttr::new(libc::CTRL_ATTR_FAMILY_NAME as u16, &zero_terminated(name)); + + req.add(&msg.serialize()?); + req.add(&family_name.serialize()?); + + let msgs = self.request(&mut req, 0)?; + + GenlFamilies::try_from(msgs)? + .first() + .cloned() + .ok_or_else(|| anyhow!("invalid response for GENL_CTRL_CMD_GETFAMILY")) + } +} diff --git a/rsln/src/handle/link.rs b/rsln/src/handle/link.rs index c899406..e27e189 100644 --- a/rsln/src/handle/link.rs +++ b/rsln/src/handle/link.rs @@ -4,7 +4,7 @@ use anyhow::{anyhow, Result}; use crate::{ core::message::Message, - route::{ + types::{ link::{Kind, Link, LinkAttrs}, message::{Attribute, LinkMessage, RouteAttr}, }, @@ -209,8 +209,8 @@ impl LinkHandle<'_> { mod tests { use crate::{ handle::sock_handle, - route::link::{Kind, LinkAttrs}, test_setup, + types::link::{Kind, LinkAttrs}, }; #[tokio::test] diff --git a/rsln/src/handle/mod.rs b/rsln/src/handle/mod.rs index ff3af0a..078920b 100644 --- a/rsln/src/handle/mod.rs +++ b/rsln/src/handle/mod.rs @@ -1,4 +1,5 @@ pub mod addr; +pub mod generic; pub mod link; pub mod neigh; pub mod routing; diff --git a/rsln/src/handle/neigh.rs b/rsln/src/handle/neigh.rs index ad40839..65fd093 100644 --- a/rsln/src/handle/neigh.rs +++ b/rsln/src/handle/neigh.rs @@ -7,7 +7,7 @@ use anyhow::{anyhow, Result}; use crate::{ core::message::Message, - route::{ + types::{ message::{Attribute, NeighborMessage, RouteAttr}, neigh::Neighbor, }, @@ -78,12 +78,11 @@ impl NeighHandle<'_> { #[cfg(test)] mod tests { use crate::{ - parse_mac, - route::{ + parse_mac, test_setup, + types::{ link::{Kind, LinkAttrs}, neigh::NeighborBuilder, }, - test_setup, }; use super::*; diff --git a/rsln/src/handle/routing.rs b/rsln/src/handle/routing.rs index 2929c60..74fcf35 100644 --- a/rsln/src/handle/routing.rs +++ b/rsln/src/handle/routing.rs @@ -8,7 +8,7 @@ use ipnet::IpNet; use crate::{ core::message::Message, - route::{ + types::{ message::{Attribute, RouteAttr, RouteMessage}, routing::Routing, }, @@ -158,8 +158,8 @@ impl RouteHandle<'_> { #[cfg(test)] mod tests { use crate::{ - route::{link::LinkAttrs, routing::Via}, test_setup, + types::{link::LinkAttrs, routing::Via}, }; use super::*; diff --git a/rsln/src/handle/sock_handle.rs b/rsln/src/handle/sock_handle.rs index 9869906..037cf80 100644 --- a/rsln/src/handle/sock_handle.rs +++ b/rsln/src/handle/sock_handle.rs @@ -2,7 +2,10 @@ use anyhow::{bail, Result}; use crate::core::{message::Message, socket::Socket}; -use super::{addr::AddrHandle, link::LinkHandle, neigh::NeighHandle, routing::RouteHandle}; +use super::{ + addr::AddrHandle, generic::GenericHandle, link::LinkHandle, neigh::NeighHandle, + routing::RouteHandle, +}; const PID_KERNEL: u32 = 0; @@ -44,6 +47,10 @@ impl SocketHandle { NeighHandle::from(self) } + pub fn handle_generic(&mut self) -> GenericHandle<'_> { + GenericHandle::from(self) + } + pub fn request(&mut self, msg: &mut Message, res_type: u16) -> Result>> { let next_seq = self.next_seq(); msg.header.nlmsg_seq = next_seq; diff --git a/rsln/src/lib.rs b/rsln/src/lib.rs index 34861da..cdb2d30 100644 --- a/rsln/src/lib.rs +++ b/rsln/src/lib.rs @@ -3,7 +3,7 @@ use anyhow::{anyhow, Result}; pub mod core; pub mod handle; pub mod netlink; -pub mod route; +pub mod types; const RTA_MTU: u16 = 0x2; const RTA_VIA: u16 = 18; diff --git a/rsln/src/netlink.rs b/rsln/src/netlink.rs index f5389f7..2d15d05 100644 --- a/rsln/src/netlink.rs +++ b/rsln/src/netlink.rs @@ -5,8 +5,9 @@ use sysctl::Sysctl; use crate::{ handle::sock_handle::SocketHandle, - route::{ + types::{ addr::{AddrCmd, AddrFamily, Address}, + generic::{GenlFamilies, GenlFamily}, link::{Link, LinkAttrs}, neigh::Neighbor, routing::{Routing, RtCmd}, @@ -201,13 +202,29 @@ impl Netlink { libc::NLM_F_CREATE | libc::NLM_F_REPLACE | libc::NLM_F_ACK, ) } + + pub fn genl_family_list(&mut self) -> Result { + self.sockets + .entry(libc::NETLINK_GENERIC) + .or_insert(SocketHandle::new(libc::NETLINK_GENERIC)) + .handle_generic() + .list_family() + } + + pub fn genl_family_get(&mut self, name: &str) -> Result { + self.sockets + .entry(libc::NETLINK_GENERIC) + .or_insert(SocketHandle::new(libc::NETLINK_GENERIC)) + .handle_generic() + .get_family(name) + } } #[cfg(test)] mod tests { use crate::{ - route::link::{Kind, VxlanAttrs}, test_setup, + types::link::{Kind, VxlanAttrs}, }; use super::*; diff --git a/rsln/src/route/addr.rs b/rsln/src/types/addr.rs similarity index 95% rename from rsln/src/route/addr.rs rename to rsln/src/types/addr.rs index be0ce76..ee1e472 100644 --- a/rsln/src/route/addr.rs +++ b/rsln/src/types/addr.rs @@ -55,7 +55,7 @@ pub struct Address { impl From<&[u8]> for Address { fn from(buf: &[u8]) -> Self { let addr_msg: AddressMessage = bincode::deserialize(buf).unwrap(); - let rt_attrs = RouteAttrs::from(&buf[addr_msg.len()..]); + let attrs = RouteAttrs::from(&buf[addr_msg.len()..]); let mut addr = Self { index: addr_msg.index, @@ -63,7 +63,7 @@ impl From<&[u8]> for Address { ..Default::default() }; - for attr in rt_attrs { + for attr in attrs { match attr.header.rta_type { libc::IFA_ADDRESS => { addr.update_address(&attr.payload, addr_msg.prefix_len) @@ -88,7 +88,7 @@ impl Address { #[cfg(test)] mod tests { - use crate::route::message::{Payload, RouteAttr, RouteAttrHeader}; + use crate::types::message::{Payload, RouteAttr, RouteAttrHeader}; use super::*; diff --git a/rsln/src/types/generic.rs b/rsln/src/types/generic.rs new file mode 100644 index 0000000..d883801 --- /dev/null +++ b/rsln/src/types/generic.rs @@ -0,0 +1,158 @@ +use std::ops::{Deref, DerefMut}; + +use anyhow::Result; + +use crate::types::message::RouteAttrs; + +#[derive(Default, Clone)] +pub struct GenlOp { + pub id: u32, + pub flags: u32, +} + +impl TryFrom<&[u8]> for GenlOp { + type Error = anyhow::Error; + + fn try_from(bytes: &[u8]) -> Result { + let attrs = RouteAttrs::from(bytes); + let mut op = GenlOp::default(); + + for attr in attrs { + match attr.header.rta_type as i32 { + libc::CTRL_ATTR_OP_ID => op.id = attr.payload.to_u32()?, + libc::CTRL_ATTR_OP_FLAGS => op.flags = attr.payload.to_u32()?, + _ => {} + } + } + + Ok(op) + } +} + +#[derive(Default, Clone)] +pub struct GenlOps(Vec); + +impl TryFrom<&[u8]> for GenlOps { + type Error = anyhow::Error; + + fn try_from(bytes: &[u8]) -> Result { + let attrs = RouteAttrs::from(bytes); + let ops: Result> = attrs + .iter() + .map(|attr| GenlOp::try_from(attr.payload.as_slice())) + .collect(); + + Ok(Self(ops?)) + } +} + +#[derive(Default, Clone)] +pub struct GenlMulticastGroup { + pub id: u32, + pub name: String, +} + +impl TryFrom<&[u8]> for GenlMulticastGroup { + type Error = anyhow::Error; + + fn try_from(bytes: &[u8]) -> Result { + let attrs = RouteAttrs::from(bytes); + let mut group = GenlMulticastGroup::default(); + + for attr in attrs { + match attr.header.rta_type as i32 { + libc::CTRL_ATTR_MCAST_GRP_ID => group.id = attr.payload.to_u32()?, + libc::CTRL_ATTR_MCAST_GRP_NAME => group.name = attr.payload.to_string()?, + _ => {} + } + } + + Ok(group) + } +} + +#[derive(Default, Clone)] +pub struct GenlMulticastGroups(Vec); + +impl TryFrom<&[u8]> for GenlMulticastGroups { + type Error = anyhow::Error; + + fn try_from(bytes: &[u8]) -> Result { + let attrs = RouteAttrs::from(bytes); + let groups: Result> = attrs + .iter() + .map(|attr| GenlMulticastGroup::try_from(attr.payload.as_slice())) + .collect(); + + Ok(Self(groups?)) + } +} + +#[derive(Default, Clone)] +pub struct GenlFamily { + pub id: u16, + pub header_size: u32, + pub name: String, + pub version: u32, + pub max_attr: u32, + pub ops: GenlOps, + pub groups: GenlMulticastGroups, +} + +impl TryFrom<&RouteAttrs> for GenlFamily { + type Error = anyhow::Error; + + fn try_from(attrs: &RouteAttrs) -> Result { + let mut family = GenlFamily::default(); + + for attr in attrs.iter() { + let payload_slice = attr.payload.as_slice(); + match attr.header.rta_type as i32 { + libc::CTRL_ATTR_FAMILY_ID => family.id = attr.payload.to_u16()?, + libc::CTRL_ATTR_FAMILY_NAME => family.name = attr.payload.to_string()?, + libc::CTRL_ATTR_VERSION => family.version = attr.payload.to_u32()?, + libc::CTRL_ATTR_HDRSIZE => family.header_size = attr.payload.to_u32()?, + libc::CTRL_ATTR_MAXATTR => family.max_attr = attr.payload.to_u32()?, + libc::CTRL_ATTR_OPS => family.ops = GenlOps::try_from(payload_slice)?, + libc::CTRL_ATTR_MCAST_GROUPS => { + family.groups = GenlMulticastGroups::try_from(payload_slice)? + } + _ => {} + } + } + + Ok(family) + } +} + +pub struct GenlFamilies(Vec); + +impl Deref for GenlFamilies { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for GenlFamilies { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl TryFrom>> for GenlFamilies { + type Error = anyhow::Error; + + fn try_from(msgs: Vec>) -> Result { + let families: Result> = msgs + .iter() + .map(|msg| { + let attrs = RouteAttrs::from(&msg.as_slice()[4..]); + GenlFamily::try_from(&attrs) + }) + .collect(); + + Ok(Self(families?)) + } +} diff --git a/rsln/src/route/link.rs b/rsln/src/types/link.rs similarity index 88% rename from rsln/src/route/link.rs rename to rsln/src/types/link.rs index b6e7467..3fe58e4 100644 --- a/rsln/src/route/link.rs +++ b/rsln/src/types/link.rs @@ -80,67 +80,30 @@ impl From<&[u8]> for Kind { for attr in attrs { match attr.header.rta_type { libc::IFLA_LINKINFO => { - for attr in RouteAttrs::from(attr.payload.as_slice()) { - match attr.header.rta_type { - libc::IFLA_INFO_KIND => { - base.link_type = - attr.payload.to_string(attr.payload.len() - 1).unwrap(); - } - libc::IFLA_INFO_DATA => { - data = RouteAttrs::from(attr.payload.as_slice()); - } + for a in RouteAttrs::from(attr.payload.as_slice()) { + match a.header.rta_type { + libc::IFLA_INFO_KIND => base.link_type = a.payload.to_string().unwrap(), + libc::IFLA_INFO_DATA => data = RouteAttrs::from(a.payload.as_slice()), _ => {} } } } - libc::IFLA_ADDRESS => { - base.hw_addr = (*attr.payload).to_vec(); - } - libc::IFLA_IFNAME => { - base.name = attr.payload.to_string(attr.payload.len() - 1).unwrap(); - } - libc::IFLA_MTU => { - base.mtu = attr.payload.to_u32(4).unwrap(); - } - libc::IFLA_LINK => { - base.parent_index = attr.payload.to_i32(4).unwrap(); - } - libc::IFLA_MASTER => { - base.master_index = attr.payload.to_i32(4).unwrap(); - } - libc::IFLA_TXQLEN => { - base.tx_queue_len = attr.payload.to_i32(4).unwrap(); - } - libc::IFLA_IFALIAS => { - base.alias = attr.payload.to_string(attr.payload.len() - 1).unwrap(); - } - libc::IFLA_OPERSTATE => { - base.oper_state = attr.payload[0]; - } - libc::IFLA_PHYS_SWITCH_ID => { - base.phys_switch_id = attr.payload.to_i32(4).unwrap(); - } - libc::IFLA_LINK_NETNSID => { - base.netns_id = attr.payload.to_i32(4).unwrap(); - } - libc::IFLA_GSO_MAX_SIZE => { - base.gso_max_size = attr.payload.to_u32(4).unwrap(); - } - libc::IFLA_GSO_MAX_SEGS => { - base.gso_max_segs = attr.payload.to_u32(4).unwrap(); - } - libc::IFLA_GRO_MAX_SIZE => { - base.gro_max_size = attr.payload.to_u32(4).unwrap(); - } - libc::IFLA_NUM_TX_QUEUES => { - base.num_tx_queues = attr.payload.to_i32(4).unwrap(); - } - libc::IFLA_NUM_RX_QUEUES => { - base.num_rx_queues = attr.payload.to_i32(4).unwrap(); - } - libc::IFLA_GROUP => { - base.group = attr.payload.to_u32(4).unwrap(); - } + libc::IFLA_ADDRESS => base.hw_addr = (*attr.payload).to_vec(), + libc::IFLA_IFNAME => base.name = attr.payload.to_string().unwrap(), + libc::IFLA_MTU => base.mtu = attr.payload.to_u32().unwrap(), + libc::IFLA_LINK => base.parent_index = attr.payload.to_i32().unwrap(), + libc::IFLA_MASTER => base.master_index = attr.payload.to_i32().unwrap(), + libc::IFLA_TXQLEN => base.tx_queue_len = attr.payload.to_i32().unwrap(), + libc::IFLA_IFALIAS => base.alias = attr.payload.to_string().unwrap(), + libc::IFLA_OPERSTATE => base.oper_state = attr.payload[0], + libc::IFLA_PHYS_SWITCH_ID => base.phys_switch_id = attr.payload.to_i32().unwrap(), + libc::IFLA_LINK_NETNSID => base.netns_id = attr.payload.to_i32().unwrap(), + libc::IFLA_GSO_MAX_SIZE => base.gso_max_size = attr.payload.to_u32().unwrap(), + libc::IFLA_GSO_MAX_SEGS => base.gso_max_segs = attr.payload.to_u32().unwrap(), + libc::IFLA_GRO_MAX_SIZE => base.gro_max_size = attr.payload.to_u32().unwrap(), + libc::IFLA_NUM_TX_QUEUES => base.num_tx_queues = attr.payload.to_i32().unwrap(), + libc::IFLA_NUM_RX_QUEUES => base.num_rx_queues = attr.payload.to_i32().unwrap(), + libc::IFLA_GROUP => base.group = attr.payload.to_u32().unwrap(), _ => {} } } diff --git a/rsln/src/route/message.rs b/rsln/src/types/message.rs similarity index 94% rename from rsln/src/route/message.rs rename to rsln/src/types/message.rs index 5542ec1..5d6168d 100644 --- a/rsln/src/route/message.rs +++ b/rsln/src/types/message.rs @@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize}; use crate::{ align_of, handle::zero_terminated, - route::{ + types::{ IFLA_VXLAN_AGEING, IFLA_VXLAN_FLOWBASED, IFLA_VXLAN_GBP, IFLA_VXLAN_GROUP, IFLA_VXLAN_GROUP6, IFLA_VXLAN_ID, IFLA_VXLAN_L2MISS, IFLA_VXLAN_L3MISS, IFLA_VXLAN_LEARNING, IFLA_VXLAN_LIMIT, IFLA_VXLAN_LINK, IFLA_VXLAN_LOCAL, @@ -22,7 +22,10 @@ use crate::{ }, }; -use super::link::{Kind, LinkAttrs, Namespace, VxlanAttrs}; +use super::{ + link::{Kind, LinkAttrs, Namespace, VxlanAttrs}, + GENL_CTRL_CMD_GETFAMILY, GENL_CTRL_VERSION, +}; const RTA_ALIGNTO: usize = 0x4; const RT_ATTR_HDR_SIZE: usize = 0x4; @@ -440,21 +443,27 @@ impl Deref for Payload { } impl Payload { - pub fn to_string(&self, len: usize) -> Result { + pub fn to_string(&self) -> Result { let mut buf = self.to_vec(); - buf.truncate(len); + buf.truncate(self.len() - 1); String::from_utf8(buf).map_err(|e| e.into()) } - pub fn to_u32(&self, len: usize) -> Result { + pub fn to_u16(&self) -> Result { + let mut buf = self.to_vec(); + buf.truncate(2); + Ok(u16::from_ne_bytes(buf.try_into().unwrap())) + } + + pub fn to_u32(&self) -> Result { let mut buf = self.to_vec(); - buf.truncate(len); + buf.truncate(4); Ok(u32::from_ne_bytes(buf.try_into().unwrap())) } - pub fn to_i32(&self, len: usize) -> Result { + pub fn to_i32(&self) -> Result { let mut buf = self.to_vec(); - buf.truncate(len); + buf.truncate(4); Ok(i32::from_ne_bytes(buf.try_into().unwrap())) } } @@ -596,6 +605,32 @@ impl NeighborMessage { } } +#[repr(C)] +#[derive(Serialize, Deserialize, Default)] +pub struct GenlMessage { + pub command: u8, + pub version: u8, +} + +impl Attribute for GenlMessage { + fn len(&self) -> usize { + 4 + } + + fn serialize(&self) -> Result> { + Ok(bincode::serialize(self)?) + } +} + +impl GenlMessage { + pub fn get_family_message() -> Self { + Self { + command: GENL_CTRL_CMD_GETFAMILY, + version: GENL_CTRL_VERSION, + } + } +} + pub struct Buffer<'a>(&'a mut [u8]); impl<'a> From<&'a mut [u8]> for Buffer<'a> { @@ -629,8 +664,8 @@ impl<'a> Buffer<'a> { #[cfg(test)] mod tests { - use crate::route::message::LinkMessage; - use crate::route::message::RouteAttrHeader; + use crate::types::message::LinkMessage; + use crate::types::message::RouteAttrHeader; use super::*; diff --git a/rsln/src/route/mod.rs b/rsln/src/types/mod.rs similarity index 94% rename from rsln/src/route/mod.rs rename to rsln/src/types/mod.rs index db6c878..e2bdc44 100644 --- a/rsln/src/route/mod.rs +++ b/rsln/src/types/mod.rs @@ -4,6 +4,7 @@ use anyhow::Result; use thiserror::Error; pub mod addr; +pub mod generic; pub mod link; pub mod message; pub mod neigh; @@ -37,6 +38,9 @@ pub const IFLA_VXLAN_REMCSUM_NOPARTIAL: u16 = 24; pub const IFLA_VXLAN_FLOWBASED: u16 = 25; pub const IFLA_VXLAN_MAX: u16 = IFLA_VXLAN_FLOWBASED; +pub const GENL_CTRL_VERSION: u8 = 2; +pub const GENL_CTRL_CMD_GETFAMILY: u8 = 3; + #[derive(Error, Debug)] pub enum RouteError { #[error("invalid address length")] diff --git a/rsln/src/route/neigh.rs b/rsln/src/types/neigh.rs similarity index 96% rename from rsln/src/route/neigh.rs rename to rsln/src/types/neigh.rs index a9af86e..312c376 100644 --- a/rsln/src/route/neigh.rs +++ b/rsln/src/types/neigh.rs @@ -3,7 +3,7 @@ use std::net::IpAddr; use anyhow::Result; use derive_builder::Builder; -use crate::route::message::{Attribute, NeighborMessage, RouteAttrs}; +use crate::types::message::{Attribute, NeighborMessage, RouteAttrs}; use super::vec_to_addr; @@ -62,7 +62,7 @@ impl NeighborBuilder { mod tests { use crate::{ parse_mac, - route::message::{Payload, RouteAttr, RouteAttrHeader}, + types::message::{Payload, RouteAttr, RouteAttrHeader}, }; use super::*; diff --git a/rsln/src/route/routing.rs b/rsln/src/types/routing.rs similarity index 98% rename from rsln/src/route/routing.rs rename to rsln/src/types/routing.rs index bf14157..32aa3ae 100644 --- a/rsln/src/route/routing.rs +++ b/rsln/src/types/routing.rs @@ -124,7 +124,7 @@ impl Via { #[cfg(test)] mod tests { - use crate::route::message::{Payload, RouteAttr, RouteAttrHeader}; + use crate::types::message::{Payload, RouteAttr, RouteAttrHeader}; use super::*;