diff --git a/Cargo.toml b/Cargo.toml index 2613935..f06c84c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,8 @@ [workspace] - members = [ "bgpd", -# "netlink", # Tests - "tests/integration_tests" + "tests/integration_tests", ] +resolver = "2" diff --git a/bgpd/Cargo.toml b/bgpd/Cargo.toml index 602c901..bdc19e7 100644 --- a/bgpd/Cargo.toml +++ b/bgpd/Cargo.toml @@ -1,47 +1,50 @@ [package] -name = "bgpd" -version = "0.1.0" authors = ["Rayhaan Jaufeerally "] edition = "2021" +name = "bgpd" +version = "0.1.0" [[bin]] name = "bgp_server" path = "src/main.rs" -#[[bin]] -#name = "route_client" -#path = "src/route_client/main.rs" +[[bin]] +name = "route_client" +path = "src/route_client/main.rs" [[bin]] name = "streamer_cli" path = "src/streamer_cli/main.rs" [dependencies] -anyhow = "1.0.71" -byteorder = "1.4.3" -bytes = "1.*" -clap = {version = "3.2.8", features = ["cargo", "derive"]} -futures = "0.3" -ipnet = "2.3.0" -libc = "0.2.126" -log = "0.4" -nom = "7.1" -prost = "0.8" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0.64" -signal-hook = { version = "0.3.10", features = ["extended-siginfo"] } -signal-hook-tokio = "0.3.0" -stderrlog = "0.5.1" -tokio = { version = "1.13.0", features = ["full"] } -tokio-stream = { version = "0.1.7", features = ["net"] } -tokio-util = { version = "0.6.7", features = ["codec"] } -tonic = { version = "0.5", features = ["compression"] } -tracing = "0.1" -tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } +anyhow = "1.0.71" +async-trait = "0.1.57" +byteorder = "1.4.3" +bytes = "1.*" +clap = { version = "3.2.8", features = ["cargo", "derive"] } +futures = "0.3" ip_network_table-deps-treebitmap = "0.5.0" -warp = "0.3.5" -# neli = "0.6.2" -async-trait = "0.1.57" +ipnet = "2.3.0" +libc = "0.2.126" +log = "0.4" +netlink = "0.1.1" +netlink-packet-route = "0.19.0" +netlink-packet-utils = "0.5.2" +nom = "7.1" +prost = "0.8" +rtnetlink = "0.14.1" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0.64" +signal-hook = { version = "0.3.17", features = ["extended-siginfo"] } +signal-hook-tokio = "0.3.0" +stderrlog = "0.5.1" +tokio = { version = "1.13.0", features = ["full"] } +tokio-stream = { version = "0.1.7", features = ["net"] } +tokio-util = { version = "0.6.7", features = ["codec"] } +tonic = { version = "0.5", features = ["compression"] } +tracing = "0.1" +tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } +warp = "0.3.5" [build-dependencies] -tonic-build = { version = "0.5.1", features = ["prost", "compression"] } +tonic-build = { version = "0.5.1", features = ["compression", "prost"] } diff --git a/bgpd/src/lib.rs b/bgpd/src/lib.rs index 786c428..a393cbc 100644 --- a/bgpd/src/lib.rs +++ b/bgpd/src/lib.rs @@ -1,3 +1,3 @@ pub mod bgp_packet; -// pub mod route_client; +pub mod route_client; pub mod server; diff --git a/bgpd/src/route_client/netlink.rs b/bgpd/src/route_client/netlink.rs index 3cec408..e51126b 100644 --- a/bgpd/src/route_client/netlink.rs +++ b/bgpd/src/route_client/netlink.rs @@ -1,10 +1,15 @@ use crate::bgp_packet::{constants::AddressFamilyIdentifier, nlri::NLRI}; -use anyhow::Result; +use anyhow::{anyhow, Result}; use async_trait::async_trait; use futures::TryStreamExt; -use netlink::constants::RTN_UNICAST; -use netlink_packet_route::{rtnl::route::nlas::Nla, RouteHeader}; -use netlink_packet_route::{RouteMessage, RTPROT_STATIC}; +use netlink_packet_route::route::RouteAddress; +use netlink_packet_route::route::RouteAttribute; +use netlink_packet_route::route::RouteHeader; +use netlink_packet_route::route::RouteMessage; +use netlink_packet_route::route::RouteProtocol; +use netlink_packet_route::route::RouteType; +use netlink_packet_route::AddressFamily as NetlinkAddressFamily; +use netlink_packet_utils::nla::Nla; use rtnetlink::IpVersion; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::{convert::TryInto, io::ErrorKind}; @@ -29,7 +34,8 @@ impl SouthboundInterface for NetlinkConnector { let route = self.handle.route(); match address_family { AddressFamilyIdentifier::Ipv6 => { - let addr: Ipv6Addr = match prefix.clone().try_into()? { + let prefix_len = prefix.prefixlen; + let addr: Ipv6Addr = match prefix.try_into()? { IpAddr::V6(addr) => addr, _ => { return Err(anyhow::Error::from(std::io::Error::new( @@ -50,7 +56,7 @@ impl SouthboundInterface for NetlinkConnector { let mut mutation = route .add() .v6() - .destination_prefix(addr, prefix.prefixlen) + .destination_prefix(addr, prefix_len) .gateway(gw_addr); if let Some(table_id) = self.table { mutation = mutation.table(table_id.try_into().unwrap()); @@ -58,6 +64,7 @@ impl SouthboundInterface for NetlinkConnector { mutation.execute().await.map_err(|e| anyhow::Error::from(e)) } AddressFamilyIdentifier::Ipv4 => { + let prefix_len = prefix.prefixlen; let addr: Ipv4Addr = match prefix.clone().try_into()? { IpAddr::V4(addr) => addr, _ => { @@ -79,7 +86,7 @@ impl SouthboundInterface for NetlinkConnector { let mut mutation = route .add() .v4() - .destination_prefix(addr, prefix.prefixlen) + .destination_prefix(addr, prefix_len) .gateway(gw_addr); if let Some(table_id) = self.table { mutation = mutation.table(table_id.try_into().unwrap()); @@ -90,55 +97,36 @@ impl SouthboundInterface for NetlinkConnector { } async fn route_del(&mut self, prefix: NLRI, nexthop: IpAddr) -> Result<()> { - let nh_octets = match nexthop { - IpAddr::V6(addr) => addr.octets().to_vec(), - IpAddr::V4(addr) => addr.octets().to_vec(), - }; let rt_handle = self.handle.route(); - let address_family = match prefix.afi { - AddressFamilyIdentifier::Ipv4 => netlink_packet_route::rtnl::constants::AF_INET as u8, - AddressFamilyIdentifier::Ipv6 => netlink_packet_route::rtnl::constants::AF_INET6 as u8, - }; - let header = RouteHeader { - address_family, - destination_prefix_length: prefix.prefixlen, - table: self.table.unwrap_or(0) as u8, - protocol: RTPROT_STATIC, - kind: RTN_UNICAST, - ..Default::default() - }; - let mut rt_msg = RouteMessage { - header, - ..Default::default() - }; - let prefix_octets = match prefix.afi { + let destination = match prefix.afi { AddressFamilyIdentifier::Ipv4 => { - let addr: Ipv4Addr = match prefix.clone().try_into()? { - IpAddr::V4(addr) => addr, - _ => { - return Err(anyhow::Error::from(std::io::Error::new( - ErrorKind::InvalidInput, - "Got non-IPv4 address from NLRI", - ))) - } - }; - addr.octets().to_vec() + RouteAddress::Inet(prefix.clone().try_into().map_err(|e: String| anyhow!(e))?) } AddressFamilyIdentifier::Ipv6 => { - let addr: Ipv6Addr = match prefix.clone().try_into()? { - IpAddr::V6(addr) => addr, - _ => { - return Err(anyhow::Error::from(std::io::Error::new( - ErrorKind::InvalidInput, - "Got non-IPv6 address from NLRI", - ))) - } - }; - addr.octets().to_vec() + RouteAddress::Inet6(prefix.clone().try_into().map_err(|e: String| anyhow!(e))?) } }; - rt_msg.nlas.push(Nla::Destination(prefix_octets)); - rt_msg.nlas.push(Nla::Gateway(nh_octets)); + let nexthop = match nexthop { + IpAddr::V4(ipv4) => RouteAddress::Inet(ipv4), + IpAddr::V6(ipv6) => RouteAddress::Inet6(ipv6), + }; + let header = RouteHeader { + address_family: match prefix.afi { + AddressFamilyIdentifier::Ipv4 => NetlinkAddressFamily::Inet, + AddressFamilyIdentifier::Ipv6 => NetlinkAddressFamily::Inet6, + }, + destination_prefix_length: prefix.prefixlen, + table: self.table.unwrap_or(0) as u8, + protocol: RouteProtocol::Bgp, + kind: RouteType::Unicast, + ..Default::default() + }; + let mut rt_msg: RouteMessage = Default::default(); + rt_msg.header = header; + rt_msg.attributes = vec![ + RouteAttribute::Destination(destination), + RouteAttribute::Gateway(nexthop), + ]; rt_handle .del(rt_msg) .execute() @@ -165,8 +153,8 @@ impl NetlinkConnector { }); if let Some(table_id) = table { req.message_mut() - .nlas - .push(Nla::Table(table_id.try_into().unwrap())); + .attributes + .push(RouteAttribute::Table(table_id)); } req.execute().try_collect().await } diff --git a/bgpd/src/route_client/southbound_interface.rs b/bgpd/src/route_client/southbound_interface.rs index b93cfa3..c362914 100644 --- a/bgpd/src/route_client/southbound_interface.rs +++ b/bgpd/src/route_client/southbound_interface.rs @@ -22,15 +22,16 @@ use log::info; /// SouthboundInterface provides a uniform API to network forwarding elements /// These are devices or targets that perform packet routing and are the end /// consumers of packet routing data. - #[async_trait] pub trait SouthboundInterface { + /// route_add adds a route towards a particular address_family/NLRI via the given nexthop. async fn route_add( &mut self, address_family: AddressFamilyIdentifier, prefix: NLRI, nexthop: IpAddr, ) -> Result<()>; + /// route_del removes the route towards a particular prefix via a given nexthop. async fn route_del(&mut self, prefix: NLRI, nexthop: IpAddr) -> Result<()>; }