netlink: get rid of dependency on rustjail

The netlink crate is a library to communicate with Linux kenrel by using
the netlink socket. It's generic enough to be reused by other clients.
So get rid of dependency on the rustjail crate by:
1) normalize all pub interfaces to return Result<T, nix::Error>,
2) add helpers to reduce duplicated code,
3) move parse_mac() into lib.rs,

Signed-off-by: Liu Jiang <gerry@linux.alibaba.com>
This commit is contained in:
Liu Jiang 2020-05-30 23:10:59 +08:00
parent 6995178903
commit 4774814c73
4 changed files with 70 additions and 85 deletions

1
src/agent/Cargo.lock generated
View File

@ -255,7 +255,6 @@ dependencies = [
"nix 0.17.0", "nix 0.17.0",
"protobuf", "protobuf",
"protocols", "protocols",
"rustjail",
"scan_fmt", "scan_fmt",
"slog", "slog",
"slog-async", "slog-async",

View File

@ -10,7 +10,6 @@ edition = "2018"
libc = "0.2.58" libc = "0.2.58"
nix = "0.17.0" nix = "0.17.0"
protobuf = "=2.14.0" protobuf = "=2.14.0"
rustjail = { path = "../rustjail" }
protocols = { path = "../protocols" } protocols = { path = "../protocols" }
slog = { version = "2.5.2", features = ["dynamic-keys", "max_level_trace", "release_max_level_info"] } slog = { version = "2.5.2", features = ["dynamic-keys", "max_level_trace", "release_max_level_info"] }
slog-json = "2.3.0" slog-json = "2.3.0"

View File

@ -15,7 +15,6 @@ extern crate libc;
extern crate nix; extern crate nix;
extern crate protobuf; extern crate protobuf;
extern crate protocols; extern crate protocols;
extern crate rustjail;
#[macro_use] #[macro_use]
extern crate slog; extern crate slog;
@ -29,7 +28,6 @@ extern crate scan_fmt;
use nix::errno::Errno; use nix::errno::Errno;
use protobuf::RepeatedField; use protobuf::RepeatedField;
use protocols::types::{IPAddress, IPFamily, Interface, Route}; use protocols::types::{IPAddress, IPFamily, Interface, Route};
use rustjail::errors::*;
use std::clone::Clone; use std::clone::Clone;
use std::default::Default; use std::default::Default;
use std::fmt; use std::fmt;
@ -37,6 +35,8 @@ use std::mem;
use std::net::{Ipv4Addr, Ipv6Addr}; use std::net::{Ipv4Addr, Ipv6Addr};
use std::str::FromStr; use std::str::FromStr;
type Result<T> = std::result::Result<T, nix::Error>;
// Convenience macro to obtain the scope logger // Convenience macro to obtain the scope logger
macro_rules! sl { macro_rules! sl {
() => { () => {
@ -1169,7 +1169,7 @@ impl RtnlHandle {
mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t; mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t;
if tmpfd < 0 { if tmpfd < 0 {
return Err(ErrorKind::Nix(nix::Error::Sys(Errno::last())).into()); return nix_last_os_err();
} }
let mut err = libc::setsockopt( let mut err = libc::setsockopt(
@ -1182,7 +1182,7 @@ impl RtnlHandle {
if err < 0 { if err < 0 {
libc::close(tmpfd); libc::close(tmpfd);
return Err(ErrorKind::Nix(nix::Error::Sys(Errno::last())).into()); return nix_last_os_err();
} }
err = libc::setsockopt( err = libc::setsockopt(
@ -1195,7 +1195,7 @@ impl RtnlHandle {
if err < 0 { if err < 0 {
libc::close(tmpfd); libc::close(tmpfd);
return Err(ErrorKind::Nix(nix::Error::Sys(Errno::last())).into()); return nix_last_os_err();
} }
libc::setsockopt( libc::setsockopt(
@ -1216,7 +1216,7 @@ impl RtnlHandle {
); );
if err < 0 { if err < 0 {
libc::close(tmpfd); libc::close(tmpfd);
return Err(ErrorKind::Nix(nix::Error::Sys(Errno::last())).into()); return nix_last_os_err();
} }
err = libc::getsockname( err = libc::getsockname(
@ -1226,14 +1226,14 @@ impl RtnlHandle {
); );
if err < 0 { if err < 0 {
libc::close(tmpfd); libc::close(tmpfd);
return Err(ErrorKind::Nix(nix::Error::Sys(Errno::last())).into()); return nix_last_os_err();
} }
if sa.nl_family as i32 != libc::AF_NETLINK if sa.nl_family as i32 != libc::AF_NETLINK
|| addrlen as usize != mem::size_of::<libc::sockaddr_nl>() || addrlen as usize != mem::size_of::<libc::sockaddr_nl>()
{ {
libc::close(tmpfd); libc::close(tmpfd);
return Err(ErrorKind::Nix(nix::Error::Sys(Errno::EINVAL)).into()); return nix_errno(Errno::EINVAL);
} }
tmpfd tmpfd
@ -1268,9 +1268,10 @@ impl RtnlHandle {
let err = libc::sendmsg(self.fd, &h as *const libc::msghdr, 0); let err = libc::sendmsg(self.fd, &h as *const libc::msghdr, 0);
if err < 0 { if err < 0 {
return Err(ErrorKind::Nix(nix::Error::Sys(Errno::last())).into()); return nix_last_os_err();
} }
} }
Ok(()) Ok(())
} }
@ -1296,7 +1297,7 @@ impl RtnlHandle {
); );
if rlen < 0 { if rlen < 0 {
return Err(ErrorKind::Nix(nix::Error::Sys(Errno::last())).into()); return nix_last_os_err();
} }
// if rlen < 32768 { // if rlen < 32768 {
@ -1311,16 +1312,16 @@ impl RtnlHandle {
rlen = libc::recvmsg(self.fd, &mut h as *mut libc::msghdr, 0); rlen = libc::recvmsg(self.fd, &mut h as *mut libc::msghdr, 0);
if rlen < 0 { if rlen < 0 {
return Err(ErrorKind::Nix(nix::Error::Sys(Errno::last())).into()); return nix_last_os_err();
} }
if sa.nl_pid != 0 { if sa.nl_pid != 0 {
// not our netlink message // not our netlink message
return Err(ErrorKind::Nix(nix::Error::Sys(Errno::EBADMSG)).into()); return nix_errno(Errno::EBADMSG);
} }
if h.msg_flags & libc::MSG_TRUNC != 0 { if h.msg_flags & libc::MSG_TRUNC != 0 {
return Err(ErrorKind::Nix(nix::Error::Sys(Errno::EBADMSG)).into()); return nix_errno(Errno::EBADMSG);
} }
v.resize(rlen as usize, 0); v.resize(rlen as usize, 0);
@ -1362,13 +1363,11 @@ impl RtnlHandle {
if (*nlh).nlmsg_len < NLMSG_LENGTH!(mem::size_of::<nlmsgerr>()) { if (*nlh).nlmsg_len < NLMSG_LENGTH!(mem::size_of::<nlmsgerr>()) {
// truncated // truncated
return Err(ErrorKind::ErrorCode("truncated message".to_string()).into()); return nix_errno(Errno::EBADMSG);
} }
let el: *const nlmsgerr = NLMSG_DATA!(nlh) as *const nlmsgerr; let el: *const nlmsgerr = NLMSG_DATA!(nlh) as *const nlmsgerr;
return Err( return nix_errno(Errno::from_i32(-(*el).error));
ErrorKind::Nix(nix::Error::Sys(Errno::from_i32(-(*el).error))).into(),
);
} }
lv.push(nlh); lv.push(nlh);
@ -1393,9 +1392,10 @@ impl RtnlHandle {
// still remain some bytes? // still remain some bytes?
if msglen != 0 { if msglen != 0 {
return Err(ErrorKind::Nix(nix::Error::Sys(Errno::EINVAL)).into()); return nix_errno(Errno::EINVAL);
} }
} }
Ok((slv, lv)) Ok((slv, lv))
} }
@ -1563,20 +1563,10 @@ impl RtnlHandle {
} }
fn find_link_by_hwaddr(&mut self, hwaddr: &str) -> Result<ifinfomsg> { fn find_link_by_hwaddr(&mut self, hwaddr: &str) -> Result<ifinfomsg> {
let mut hw: Vec<u8> = vec![0; 6]; let hw = parse_mac(hwaddr)?;
let p = hw.as_ptr() as *const u8 as *const libc::c_void;
unsafe { unsafe {
//parse out hwaddr in request //parse out hwaddr in request
let p = hw.as_mut_ptr() as *mut u8;
let (hw0, hw1, hw2, hw3, hw4, hw5) = scan_fmt!(hwaddr, "{x}:{x}:{x}:{x}:{x}:{x}",
[hex u8], [hex u8], [hex u8], [hex u8], [hex u8],
[hex u8])?;
hw[0] = hw0;
hw[1] = hw1;
hw[2] = hw2;
hw[3] = hw3;
hw[4] = hw4;
hw[5] = hw5;
// dump out all links // dump out all links
let (_slv, lv) = self.dump_all_links()?; let (_slv, lv) = self.dump_all_links()?;
@ -1608,7 +1598,7 @@ impl RtnlHandle {
if attrs[IFLA_ADDRESS as usize] as i64 != 0 { if attrs[IFLA_ADDRESS as usize] as i64 != 0 {
let a = RTA_DATA!(attrs[IFLA_ADDRESS as usize]) as *const libc::c_void; let a = RTA_DATA!(attrs[IFLA_ADDRESS as usize]) as *const libc::c_void;
if libc::memcmp( if libc::memcmp(
p as *const libc::c_void, p,
a, a,
RTA_PAYLOAD!(attrs[IFLA_ADDRESS as usize]) as libc::size_t, RTA_PAYLOAD!(attrs[IFLA_ADDRESS as usize]) as libc::size_t,
) == 0 ) == 0
@ -1619,7 +1609,7 @@ impl RtnlHandle {
} }
} }
return Err(ErrorKind::Nix(nix::Error::Sys(Errno::ENODEV)).into()); nix_errno(Errno::ENODEV)
} }
fn find_link_by_name(&mut self, name: &str) -> Result<ifinfomsg> { fn find_link_by_name(&mut self, name: &str) -> Result<ifinfomsg> {
@ -1688,9 +1678,7 @@ impl RtnlHandle {
if (*nlh).nlmsg_len < NLMSG_LENGTH!(mem::size_of::<nlmsgerr>()) { if (*nlh).nlmsg_len < NLMSG_LENGTH!(mem::size_of::<nlmsgerr>()) {
// truncated // truncated
return Err( return nix_errno(Errno::EBADMSG);
ErrorKind::ErrorCode("truncated message".to_string()).into()
);
} }
let el: *const nlmsgerr = NLMSG_DATA!(nlh) as *const nlmsgerr; let el: *const nlmsgerr = NLMSG_DATA!(nlh) as *const nlmsgerr;
@ -1700,9 +1688,7 @@ impl RtnlHandle {
return Ok(Vec::new()); return Ok(Vec::new());
} }
return Err( return nix_errno(Errno::from_i32(-(*el).error));
ErrorKind::Nix(nix::Error::Sys(Errno::from_i32(-(*el).error))).into(),
);
} }
// good message // good message
@ -1723,7 +1709,7 @@ impl RtnlHandle {
} }
if !(NLMSG_OK!(nlh, msglen)) { if !(NLMSG_OK!(nlh, msglen)) {
return Err(ErrorKind::Nix(nix::Error::Sys(Errno::EINVAL)).into()); return nix_errno(Errno::EINVAL);
} }
} }
} }
@ -2042,7 +2028,7 @@ impl RtnlHandle {
} }
} }
Err(ErrorKind::ErrorCode("no name".to_string()).into()) nix_errno(Errno::ENOENT)
} }
pub fn list_routes(&mut self) -> Result<Vec<Route>> { pub fn list_routes(&mut self) -> Result<Vec<Route>> {
@ -2711,7 +2697,7 @@ unsafe fn format_address(addr: *const u8, len: u32) -> Result<String> {
*/ */
} }
return Err(ErrorKind::Nix(nix::Error::Sys(Errno::EINVAL)).into()); nix_errno(Errno::EINVAL)
} }
impl Drop for RtnlHandle { impl Drop for RtnlHandle {
@ -2740,13 +2726,15 @@ impl Default for RtRoute {
} }
fn parse_cidripv4(s: &str) -> Result<(Vec<u8>, u8)> { fn parse_cidripv4(s: &str) -> Result<(Vec<u8>, u8)> {
let (a0, a1, a2, a3, len) = scan_fmt!(s, "{}.{}.{}.{}/{}", u8, u8, u8, u8, u8)?; let (a0, a1, a2, a3, len) = scan_fmt!(s, "{}.{}.{}.{}/{}", u8, u8, u8, u8, u8)
.map_err(|_| nix::Error::Sys(Errno::EINVAL))?;
let ip: Vec<u8> = vec![a0, a1, a2, a3]; let ip: Vec<u8> = vec![a0, a1, a2, a3];
Ok((ip, len)) Ok((ip, len))
} }
fn parse_ipv4(s: &str) -> Result<Vec<u8>> { fn parse_ipv4(s: &str) -> Result<Vec<u8>> {
let (a0, a1, a2, a3) = scan_fmt!(s, "{}.{}.{}.{}", u8, u8, u8, u8)?; let (a0, a1, a2, a3) =
scan_fmt!(s, "{}.{}.{}.{}", u8, u8, u8, u8).map_err(|_| nix::Error::Sys(Errno::EINVAL))?;
let ip: Vec<u8> = vec![a0, a1, a2, a3]; let ip: Vec<u8> = vec![a0, a1, a2, a3];
Ok(ip) Ok(ip)
@ -2758,12 +2746,15 @@ fn parse_ipaddr(s: &str) -> Result<Vec<u8>> {
} }
// v4 // v4
Ok(Vec::from(Ipv4Addr::from_str(s)?.octets().as_ref())) match Ipv4Addr::from_str(s) {
Ok(v) => Ok(Vec::from(v.octets().as_ref())),
Err(_e) => nix_errno(Errno::EINVAL),
}
} }
fn parse_cider(s: &str) -> Result<(Vec<u8>, u8)> { fn parse_cider(s: &str) -> Result<(Vec<u8>, u8)> {
let (addr, mask) = if s.contains("/") { let (addr, mask) = if s.contains("/") {
scan_fmt!(s, "{}/{}", String, u8)? scan_fmt!(s, "{}/{}", String, u8).map_err(|_| nix::Error::Sys(Errno::EINVAL))?
} else { } else {
(s.to_string(), 0) (s.to_string(), 0)
}; };
@ -2771,6 +2762,24 @@ fn parse_cider(s: &str) -> Result<(Vec<u8>, u8)> {
Ok((parse_ipaddr(addr.as_str())?, mask)) Ok((parse_ipaddr(addr.as_str())?, mask))
} }
fn parse_mac(hwaddr: &str) -> Result<Vec<u8>> {
let mut hw: Vec<u8> = vec![0; 6];
let (hw0, hw1, hw2, hw3, hw4, hw5) = scan_fmt!(hwaddr, "{x}:{x}:{x}:{x}:{x}:{x}",
[hex u8], [hex u8], [hex u8], [hex u8], [hex u8],
[hex u8])
.map_err(|_| nix::Error::Sys(Errno::EINVAL))?;
hw[0] = hw0;
hw[1] = hw1;
hw[2] = hw2;
hw[3] = hw3;
hw[4] = hw4;
hw[5] = hw5;
Ok(hw)
}
impl From<Route> for RtRoute { impl From<Route> for RtRoute {
fn from(r: Route) -> Self { fn from(r: Route) -> Self {
// only handle ipv4 // only handle ipv4
@ -2849,6 +2858,16 @@ impl From<IPAddress> for RtIPAddr {
} }
} }
#[inline]
fn nix_last_os_err<T>() -> Result<T> {
Err(nix::Error::Sys(Errno::last()))
}
#[inline]
fn nix_errno<T>(err: Errno) -> Result<T> {
Err(nix::Error::Sys(err))
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{nlmsghdr, NLMSG_ALIGNTO, RTA_ALIGNTO, RTM_BASE}; use crate::{nlmsghdr, NLMSG_ALIGNTO, RTA_ALIGNTO, RTM_BASE};

View File

@ -3,13 +3,8 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
use crate::{ use super::*;
__s32, __u16, __u8, addattr_var, ifinfomsg, nlmsghdr, parse_ipaddr, IFA_F_PERMANENT,
NLMSG_ALIGNTO, NLM_F_CREATE, NLM_F_EXCL, NLM_F_REQUEST, RTM_NEWNEIGH,
};
use crate::{NLMSG_ALIGN, NLMSG_DATA, NLMSG_HDRLEN, NLMSG_LENGTH};
use protocols::types::ARPNeighbor; use protocols::types::ARPNeighbor;
use rustjail::errors::*;
use std::mem; use std::mem;
#[repr(C)] #[repr(C)]
@ -58,29 +53,19 @@ impl crate::RtnlHandle {
Ok(()) Ok(())
} }
pub fn add_one_arp_neighbor(&mut self, neigh: &ARPNeighbor) -> Result<()> { pub fn add_one_arp_neighbor(&mut self, neigh: &ARPNeighbor) -> Result<()> {
let dev: ifinfomsg;
match self.find_link_by_name(&neigh.device) {
Ok(d) => dev = d,
Err(e) => {
return Err(ErrorKind::ErrorCode(format!(
"Could not find link from device {}: {}",
neigh.device, e
))
.into());
}
}
if neigh.toIPAddress.is_none() { if neigh.toIPAddress.is_none() {
return Err(ErrorKind::ErrorCode("toIPAddress is required".to_string()).into()); return nix_errno(Errno::EINVAL);
} }
let to_ip = &neigh.toIPAddress.as_ref().unwrap().address; let to_ip = &neigh.toIPAddress.as_ref().unwrap().address;
if to_ip.is_empty() { if to_ip.is_empty() {
return Err(ErrorKind::ErrorCode("toIPAddress.address is required".to_string()).into()); return nix_errno(Errno::EINVAL);
} }
let dev = self.find_link_by_name(&neigh.device)?;
let mut v: Vec<u8> = vec![0; 2048]; let mut v: Vec<u8> = vec![0; 2048];
unsafe { unsafe {
// init // init
@ -129,23 +114,6 @@ impl crate::RtnlHandle {
} }
} }
fn parse_mac(hwaddr: &str) -> Result<Vec<u8>> {
let mut hw: Vec<u8> = vec![0; 6];
let (hw0, hw1, hw2, hw3, hw4, hw5) = scan_fmt!(hwaddr, "{x}:{x}:{x}:{x}:{x}:{x}",
[hex u8], [hex u8], [hex u8], [hex u8], [hex u8],
[hex u8])?;
hw[0] = hw0;
hw[1] = hw1;
hw[2] = hw2;
hw[3] = hw3;
hw[4] = hw4;
hw[5] = hw5;
Ok(hw)
}
fn parse_addr(ip_address: &str) -> Result<(__u8, Vec<u8>)> { fn parse_addr(ip_address: &str) -> Result<(__u8, Vec<u8>)> {
let ip_data = parse_ipaddr(ip_address)?; let ip_data = parse_ipaddr(ip_address)?;
let family: __u8; let family: __u8;