Skip to content

Commit

Permalink
Merge pull request #448 from Luap99/netlink-remove
Browse files Browse the repository at this point in the history
netlink: add del_{addr,route} calls
  • Loading branch information
openshift-merge-robot authored Oct 17, 2022
2 parents a97bbb3 + 59be422 commit e9752ed
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 5 deletions.
40 changes: 35 additions & 5 deletions src/network/netlink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use netlink_packet_route::{
nlas::link::{Info, InfoData, InfoKind, Nla},
AddressMessage, LinkMessage, NetlinkHeader, NetlinkMessage, NetlinkPayload, RouteMessage,
RtnlMessage, AF_INET, AF_INET6, IFF_UP, NLM_F_ACK, NLM_F_CREATE, NLM_F_DUMP, NLM_F_EXCL,
NLM_F_REQUEST, RTN_UNICAST, RTPROT_STATIC, RT_SCOPE_UNIVERSE, RT_TABLE_MAIN,
NLM_F_REQUEST, RTN_UNICAST, RTPROT_STATIC, RTPROT_UNSPEC, RT_SCOPE_UNIVERSE, RT_TABLE_MAIN,
};
use netlink_sys::{protocols::NETLINK_ROUTE, SocketAddr};

Expand Down Expand Up @@ -118,7 +118,7 @@ impl Socket {
Ok(())
}

pub fn add_addr(&mut self, link_id: u32, addr: &ipnet::IpNet) -> NetavarkResult<()> {
fn create_addr_msg(link_id: u32, addr: &ipnet::IpNet) -> AddressMessage {
let mut msg = AddressMessage::default();
msg.header.index = link_id;

Expand All @@ -139,6 +139,11 @@ impl Socket {
msg.header.prefix_len = addr.prefix_len();
msg.nlas
.push(netlink_packet_route::address::Nla::Local(addr_vec));
msg
}

pub fn add_addr(&mut self, link_id: u32, addr: &ipnet::IpNet) -> NetavarkResult<()> {
let msg = Self::create_addr_msg(link_id, addr);
let result = self.make_netlink_request(
RtnlMessage::NewAddress(msg),
NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE,
Expand All @@ -150,7 +155,17 @@ impl Socket {
Ok(())
}

pub fn add_route(&mut self, route: &Route) -> NetavarkResult<()> {
pub fn del_addr(&mut self, link_id: u32, addr: &ipnet::IpNet) -> NetavarkResult<()> {
let msg = Self::create_addr_msg(link_id, addr);
let result = self.make_netlink_request(RtnlMessage::DelAddress(msg), NLM_F_ACK)?;
if !result.is_empty() {
return Err(NetavarkError::msg_str("unexpected netlink result"));
}

Ok(())
}

fn create_route_msg(route: &Route) -> RouteMessage {
let mut msg = RouteMessage::default();

msg.header.table = RT_TABLE_MAIN;
Expand Down Expand Up @@ -182,6 +197,11 @@ impl Socket {
.push(netlink_packet_route::route::Nla::Destination(dest_vec));
msg.nlas
.push(netlink_packet_route::route::Nla::Gateway(gateway_vec));
msg
}

pub fn add_route(&mut self, route: &Route) -> NetavarkResult<()> {
let msg = Self::create_route_msg(route);

let result =
self.make_netlink_request(RtnlMessage::NewRoute(msg), NLM_F_ACK | NLM_F_CREATE)?;
Expand All @@ -192,11 +212,22 @@ impl Socket {
Ok(())
}

pub fn del_route(&mut self, route: &Route) -> NetavarkResult<()> {
let msg = Self::create_route_msg(route);

let result = self.make_netlink_request(RtnlMessage::DelRoute(msg), NLM_F_ACK)?;
if !result.is_empty() {
return Err(NetavarkError::msg_str("unexpected netlink result"));
}

Ok(())
}

pub fn dump_routes(&mut self) -> NetavarkResult<Vec<RouteMessage>> {
let mut msg = RouteMessage::default();

msg.header.table = RT_TABLE_MAIN;
msg.header.protocol = RTPROT_STATIC;
msg.header.protocol = RTPROT_UNSPEC;
msg.header.scope = RT_SCOPE_UNIVERSE;
msg.header.kind = RTN_UNICAST;

Expand Down Expand Up @@ -305,7 +336,6 @@ impl Socket {

loop {
let bytes = &self.buffer[offset..];

let rx_packet: NetlinkMessage<RtnlMessage> = NetlinkMessage::deserialize(bytes)
.map_err(|e| {
NetavarkError::Message(format!(
Expand Down
86 changes: 86 additions & 0 deletions src/test/netlink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,90 @@ mod tests {

assert!(out.contains(net), "addr does not exists");
}

#[test]
fn test_del_addr() {
test_setup!();
let mut sock = Socket::new().expect("Socket::new()");

let out = run_command!("ip", "link", "add", "test1", "type", "dummy");
eprintln!("{}", String::from_utf8(out.stderr).unwrap());
assert!(out.status.success(), "failed to add link via ip");

let net = "10.0.0.2/24";

let out = run_command!("ip", "addr", "add", net, "dev", "test1");
eprintln!("{}", String::from_utf8(out.stderr).unwrap());
assert!(out.status.success(), "failed to add addr via ip");

let link = sock
.get_link(LinkID::Name("test1".into()))
.expect("get_link failed");

sock.del_addr(link.header.index, &net.parse().unwrap())
.expect("del_addr failed");

let out = run_command!("ip", "addr", "show", "test1");
let stdout = String::from_utf8(out.stdout).unwrap();
eprintln!("{}", stdout);
assert!(out.status.success(), "failed to show addr via ip");

assert!(!stdout.contains(net), "addr does exist");
}

/// This test fails because we do not have actual functioning routes in the test netns
/// For some reason the kernel expects us to set different options to make it work but
/// I do not want to expose them just for a test.
/// With these option you could get it to work but it will not work in the actual use case
/// msg.header.protocol = RTPROT_UNSPEC;
/// msg.header.scope = RT_SCOPE_NOWHERE;
/// msg.header.kind = RTN_UNSPEC;
#[test]
#[ignore]
fn test_del_route() {
test_setup!();
let mut sock = Socket::new().expect("Socket::new()");

let out = run_command!("ip", "link", "add", "test1", "type", "dummy");
eprintln!("{}", String::from_utf8(out.stderr).unwrap());
assert!(out.status.success(), "failed to add link via ip");

let net = "10.0.0.2/24";

let out = run_command!("ip", "addr", "add", net, "dev", "test1");
eprintln!("{}", String::from_utf8(out.stderr).unwrap());
assert!(out.status.success(), "failed to add addr via ip");

// route requires that the link is up!
let out = run_command!("ip", "link", "set", "dev", "test1", "up");
eprintln!("{}", String::from_utf8(out.stderr).unwrap());
assert!(out.status.success(), "failed to set test1 up via ip");

let net = "10.0.1.0/24";
let gw = "10.0.0.2";

let out = run_command!("ip", "route", "add", net, "via", gw);
eprintln!("{}", String::from_utf8(out.stderr).unwrap());
assert!(out.status.success(), "failed to add route via ip");

let out = run_command!("ip", "route", "show");
let stdout = String::from_utf8(out.stdout).unwrap();
eprintln!("{}", stdout);
assert!(out.status.success(), "failed to show addr via ip");

assert!(stdout.contains(net), "route should exist");

sock.del_route(&Route::Ipv4 {
dest: net.parse().unwrap(),
gw: gw.parse().unwrap(),
})
.expect("del_route failed");

let out = run_command!("ip", "route", "show");
let stdout = String::from_utf8(out.stdout).unwrap();
eprintln!("{}", stdout);
assert!(out.status.success(), "failed to show addr via ip");

assert!(!stdout.contains(net), "route should not exist");
}
}

0 comments on commit e9752ed

Please sign in to comment.