diff --git a/src/agent/Cargo.toml b/src/agent/Cargo.toml index 34a39b5618..87c9ae826d 100644 --- a/src/agent/Cargo.toml +++ b/src/agent/Cargo.toml @@ -40,8 +40,9 @@ tokio = { version = "1.39.0", features = ["full"] } tokio-vsock = "0.3.4" netlink-sys = { version = "0.7.0", features = ["tokio_socket"] } -rtnetlink = "0.8.0" -netlink-packet-utils = "0.4.1" +rtnetlink = "0.14.0" +netlink-packet-route = "0.19.0" +netlink-packet-core = "0.7.0" ipnetwork = "0.17.0" # Note: this crate sets the slog 'max_*' features which allows the log level diff --git a/src/agent/src/netlink.rs b/src/agent/src/netlink.rs index 0b6767c242..d07b939cd6 100644 --- a/src/agent/src/netlink.rs +++ b/src/agent/src/netlink.rs @@ -6,9 +6,18 @@ use anyhow::{anyhow, Context, Result}; use futures::{future, StreamExt, TryStreamExt}; use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network}; +use netlink_packet_route::address::{AddressAttribute, AddressMessage}; +use netlink_packet_route::link::{LinkAttribute, LinkMessage}; +use netlink_packet_route::neighbour::{self, NeighbourFlag}; +use netlink_packet_route::route::{RouteFlag, RouteHeader, RouteProtocol, RouteScope, RouteType}; +use netlink_packet_route::{ + neighbour::{NeighbourAddress, NeighbourAttribute, NeighbourState}, + route::{RouteAddress, RouteAttribute, RouteMessage}, + AddressFamily, +}; use nix::errno::Errno; use protocols::types::{ARPNeighbor, IPAddress, IPFamily, Interface, Route}; -use rtnetlink::{new_connection, packet, IpVersion}; +use rtnetlink::{new_connection, IpVersion}; use std::convert::{TryFrom, TryInto}; use std::fmt; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; @@ -35,6 +44,36 @@ impl fmt::Display for LinkFilter<'_> { } } +const ALL_RULE_FLAGS: [NeighbourFlag; 8] = [ + NeighbourFlag::Use, + NeighbourFlag::Own, + NeighbourFlag::Controller, + NeighbourFlag::Proxy, + NeighbourFlag::ExtLearned, + NeighbourFlag::Offloaded, + NeighbourFlag::Sticky, + NeighbourFlag::Router, +]; + +const ALL_ROUTE_FLAGS: [RouteFlag; 16] = [ + RouteFlag::Dead, + RouteFlag::Pervasive, + RouteFlag::Onlink, + RouteFlag::Offload, + RouteFlag::Linkdown, + RouteFlag::Unresolved, + RouteFlag::Trap, + RouteFlag::Notify, + RouteFlag::Cloned, + RouteFlag::Equalize, + RouteFlag::Prefix, + RouteFlag::LookupTable, + RouteFlag::FibMatch, + RouteFlag::RtOffload, + RouteFlag::RtTrap, + RouteFlag::OffloadFailed, +]; + /// A filter to query addresses. pub enum AddressFilter { /// Return addresses that belong to the given interface. @@ -74,12 +113,6 @@ impl Handle { self.enable_link(link.index(), false).await?; } - // Delete all addresses associated with the link - let addresses = self - .list_addresses(AddressFilter::LinkIndex(link.index())) - .await?; - self.delete_addresses(addresses).await?; - // Add new ip addresses from request for ip_address in &iface.IPAddresses { let ip = IpAddr::from_str(ip_address.address())?; @@ -125,6 +158,7 @@ impl Handle { } // Update link + let link = self.find_link(LinkFilter::Address(&iface.hwAddr)).await?; let mut request = self.handle.link().set(link.index()); request.message_mut().header = link.header.clone(); @@ -172,26 +206,6 @@ impl Handle { Ok(()) } - pub async fn update_routes(&mut self, list: I) -> Result<()> - where - I: IntoIterator, - { - let old_routes = self - .query_routes(None) - .await - .with_context(|| "Failed to query old routes")?; - - self.delete_routes(old_routes) - .await - .with_context(|| "Failed to delete old routes")?; - - self.add_routes(list) - .await - .with_context(|| "Failed to add new routes")?; - - Ok(()) - } - /// Retireve available network interfaces. pub async fn list_interfaces(&self) -> Result> { let mut list = Vec::new(); @@ -225,7 +239,7 @@ impl Handle { let request = self.handle.link().get(); let filtered = match filter { - LinkFilter::Name(name) => request.set_name_filter(name.to_owned()), + LinkFilter::Name(name) => request.match_name(name.to_owned()), LinkFilter::Index(index) => request.match_index(index), _ => request, // Post filters }; @@ -233,7 +247,7 @@ impl Handle { let mut stream = filtered.execute(); let next = if let LinkFilter::Address(addr) = filter { - use packet::link::nlas::Nla; + use LinkAttribute as Nla; let mac_addr = parse_mac_address(addr) .with_context(|| format!("Failed to parse MAC address: {}", addr))?; @@ -242,7 +256,7 @@ impl Handle { // we may have to dump link list and then find the target link. stream .try_filter(|f| { - let result = f.nlas.iter().any(|n| match n { + let result = f.attributes.iter().any(|n| match n { Nla::Address(data) => data.eq(&mac_addr), _ => false, }); @@ -278,10 +292,7 @@ impl Handle { Ok(()) } - async fn query_routes( - &self, - ip_version: Option, - ) -> Result> { + async fn query_routes(&self, ip_version: Option) -> Result> { let list = if let Some(ip_version) = ip_version { self.handle .route() @@ -321,36 +332,46 @@ impl Handle { for msg in self.query_routes(None).await? { // Ignore non-main tables - if msg.header.table != packet::constants::RT_TABLE_MAIN { + if msg.header.table != RouteHeader::RT_TABLE_MAIN { continue; } let mut route = Route { - scope: msg.header.scope as _, + scope: u8::from(msg.header.scope) as u32, ..Default::default() }; - if let Some((ip, mask)) = msg.destination_prefix() { - route.dest = format!("{}/{}", ip, mask); - } - - if let Some((ip, mask)) = msg.source_prefix() { - route.source = format!("{}/{}", ip, mask); - } - - if let Some(addr) = msg.gateway() { - route.gateway = addr.to_string(); - - // For gateway, destination is 0.0.0.0 - route.dest = if addr.is_ipv4() { - String::from("0.0.0.0") - } else { - String::from("::1") + for attribute in &msg.attributes { + if let RouteAttribute::Destination(dest) = attribute { + if let Ok(dest) = parse_route_addr(dest) { + route.dest = format!("{}/{}", dest, msg.header.destination_prefix_length); + } } - } - if let Some(index) = msg.output_interface() { - route.device = self.find_link(LinkFilter::Index(index)).await?.name(); + if let RouteAttribute::Source(src) = attribute { + if let Ok(src) = parse_route_addr(src) { + route.source = format!("{}/{}", src, msg.header.source_prefix_length) + } + } + + if let RouteAttribute::Gateway(g) = attribute { + if let Ok(addr) = parse_route_addr(g) { + // For gateway, destination is 0.0.0.0 + if addr.is_ipv4() { + route.dest = String::from("0.0.0.0"); + } else { + route.dest = String::from("::1"); + } + } + + route.gateway = parse_route_addr(g) + .map(|g| g.to_string()) + .unwrap_or_default(); + } + + if let RouteAttribute::Oif(index) = attribute { + route.device = self.find_link(LinkFilter::Index(*index)).await?.name(); + } } if !route.dest.is_empty() { @@ -361,10 +382,11 @@ impl Handle { Ok(result) } - /// Adds a list of routes from iterable object `I`. + /// Add a list of routes from iterable object `I`. + /// If the route existed, then replace it with the latest. /// It can accept both a collection of routes or a single item (via `iter::once()`). /// It'll also take care of proper order when adding routes (gateways first, everything else after). - async fn add_routes(&mut self, list: I) -> Result<()> + pub async fn update_routes(&mut self, list: I) -> Result<()> where I: IntoIterator, { @@ -377,24 +399,41 @@ impl Handle { for route in list { let link = self.find_link(LinkFilter::Name(&route.device)).await?; - const MAIN_TABLE: u8 = packet::constants::RT_TABLE_MAIN; - const UNICAST: u8 = packet::constants::RTN_UNICAST; - const BOOT_PROT: u8 = packet::constants::RTPROT_BOOT; + const MAIN_TABLE: u32 = libc::RT_TABLE_MAIN as u32; + let uni_cast: RouteType = RouteType::from(libc::RTN_UNICAST); + let boot_prot: RouteProtocol = RouteProtocol::from(libc::RTPROT_BOOT); - let scope = route.scope as u8; + let scope = RouteScope::from(route.scope as u8); - use packet::nlas::route::Nla; + use RouteAttribute as Nla; // Build a common indeterminate ip request - let request = self + let mut request = self .handle .route() .add() - .table(MAIN_TABLE) - .kind(UNICAST) - .protocol(BOOT_PROT) + .table_id(MAIN_TABLE) + .kind(uni_cast) + .protocol(boot_prot) .scope(scope); + let message = request.message_mut(); + + // calculate the Flag vec from the u32 flags + let mut got: u32 = 0; + let mut flags = Vec::new(); + for flag in ALL_ROUTE_FLAGS { + if (route.flags & (u32::from(flag))) > 0 { + flags.push(flag); + got += u32::from(flag); + } + } + if got != route.flags { + flags.push(RouteFlag::Other(route.flags - got)); + } + + message.header.flags = flags; + // `rtnetlink` offers a separate request builders for different IP versions (IP v4 and v6). // This if branch is a bit clumsy because it does almost the same. if route.family() == IPFamily::v6 { @@ -408,7 +447,8 @@ impl Handle { let mut request = request .v6() .destination_prefix(dest_addr.ip(), dest_addr.prefix()) - .output_interface(link.index()); + .output_interface(link.index()) + .replace(); if !route.source.is_empty() { let network = Ipv6Network::from_str(&route.source)?; @@ -417,8 +457,8 @@ impl Handle { } else { request .message_mut() - .nlas - .push(Nla::PrefSource(network.ip().octets().to_vec())); + .attributes + .push(Nla::PrefSource(RouteAddress::from(network.ip()))); } } @@ -428,14 +468,16 @@ impl Handle { } if let Err(rtnetlink::Error::NetlinkError(message)) = request.execute().await { - if Errno::from_i32(message.code.abs()) != Errno::EEXIST { - return Err(anyhow!( - "Failed to add IP v6 route (src: {}, dst: {}, gtw: {},Err: {})", - route.source(), - route.dest(), - route.gateway(), - message - )); + if let Some(code) = message.code { + if Errno::from_i32(code.get()) != Errno::EEXIST { + return Err(anyhow!( + "Failed to add IP v6 route (src: {}, dst: {}, gtw: {},Err: {})", + route.source(), + route.dest(), + route.gateway(), + message + )); + } } } } else { @@ -449,7 +491,8 @@ impl Handle { let mut request = request .v4() .destination_prefix(dest_addr.ip(), dest_addr.prefix()) - .output_interface(link.index()); + .output_interface(link.index()) + .replace(); if !route.source.is_empty() { let network = Ipv4Network::from_str(&route.source)?; @@ -458,8 +501,8 @@ impl Handle { } else { request .message_mut() - .nlas - .push(Nla::PrefSource(network.ip().octets().to_vec())); + .attributes + .push(RouteAttribute::PrefSource(RouteAddress::from(network.ip()))); } } @@ -469,14 +512,16 @@ impl Handle { } if let Err(rtnetlink::Error::NetlinkError(message)) = request.execute().await { - if Errno::from_i32(message.code.abs()) != Errno::EEXIST { - return Err(anyhow!( - "Failed to add IP v4 route (src: {}, dst: {}, gtw: {},Err: {})", - route.source(), - route.dest(), - route.gateway(), - message - )); + if let Some(code) = message.code { + if Errno::from_i32(code.get()) != Errno::EEXIST { + return Err(anyhow!( + "Failed to add IP v4 route (src: {}, dst: {}, gtw: {},Err: {})", + route.source(), + route.dest(), + route.gateway(), + message + )); + } } } } @@ -485,34 +530,6 @@ impl Handle { Ok(()) } - async fn delete_routes(&mut self, routes: I) -> Result<()> - where - I: IntoIterator, - { - for route in routes.into_iter() { - if route.header.protocol == packet::constants::RTPROT_KERNEL { - continue; - } - - let index = if let Some(index) = route.output_interface() { - index - } else { - continue; - }; - - let link = self.find_link(LinkFilter::Index(index)).await?; - - let name = link.name(); - if name.contains("lo") || name.contains("::1") { - continue; - } - - self.handle.route().del(route).execute().await?; - } - - Ok(()) - } - async fn list_addresses(&self, filter: F) -> Result> where F: Into>, @@ -534,6 +551,8 @@ impl Handle { Ok(list) } + // add the addresses to the specified interface, if the addresses existed, + // replace it with the latest one. async fn add_addresses(&mut self, index: u32, list: I) -> Result<()> where I: IntoIterator, @@ -542,6 +561,7 @@ impl Handle { self.handle .address() .add(index, net.ip(), net.prefix()) + .replace() .execute() .await .map_err(|err| anyhow!("Failed to add address {}: {:?}", net.ip(), err))?; @@ -550,17 +570,6 @@ impl Handle { Ok(()) } - async fn delete_addresses(&mut self, list: I) -> Result<()> - where - I: IntoIterator, - { - for addr in list.into_iter() { - self.handle.address().del(addr.0).execute().await?; - } - - Ok(()) - } - pub async fn add_arp_neighbors(&mut self, list: I) -> Result<()> where I: IntoIterator, @@ -592,52 +601,57 @@ impl Handle { .map_err(|e| anyhow!("Failed to parse IP {}: {:?}", ip_address, e))?; // Import rtnetlink objects that make sense only for this function - use packet::constants::{ - NDA_UNSPEC, NLM_F_ACK, NLM_F_CREATE, NLM_F_REPLACE, NLM_F_REQUEST, - }; - use packet::neighbour::{NeighbourHeader, NeighbourMessage}; - use packet::nlas::neighbour::Nla; - use packet::{NetlinkMessage, NetlinkPayload, RtnlMessage}; + use libc::{NDA_UNSPEC, NLM_F_ACK, NLM_F_CREATE, NLM_F_REPLACE, NLM_F_REQUEST}; + use neighbour::{NeighbourHeader, NeighbourMessage}; + use netlink_packet_core::{NetlinkMessage, NetlinkPayload}; + use netlink_packet_route::RouteNetlinkMessage as RtnlMessage; use rtnetlink::Error; const IFA_F_PERMANENT: u16 = 0x80; // See https://github.com/little-dude/netlink/blob/0185b2952505e271805902bf175fee6ea86c42b8/netlink-packet-route/src/rtnl/constants.rs#L770 + let state = if neigh.state != 0 { + neigh.state as u16 + } else { + IFA_F_PERMANENT + }; let link = self.find_link(LinkFilter::Name(&neigh.device)).await?; - let message = NeighbourMessage { - header: NeighbourHeader { - family: match ip { - IpAddr::V4(_) => packet::AF_INET, - IpAddr::V6(_) => packet::AF_INET6, - } as u8, - ifindex: link.index(), - state: if neigh.state != 0 { - neigh.state as u16 - } else { - IFA_F_PERMANENT - }, - flags: neigh.flags as u8, - ntype: NDA_UNSPEC as u8, - }, - nlas: { - let mut nlas = vec![Nla::Destination(match ip { - IpAddr::V4(v4) => v4.octets().to_vec(), - IpAddr::V6(v6) => v6.octets().to_vec(), - })]; + let mut flags = Vec::new(); + for flag in ALL_RULE_FLAGS { + if (neigh.flags as u8 & (u8::from(flag))) > 0 { + flags.push(flag); + } + } - if !neigh.lladdr.is_empty() { - nlas.push(Nla::LinkLocalAddress( - parse_mac_address(&neigh.lladdr)?.to_vec(), - )); - } + let mut message = NeighbourMessage::default(); - nlas + message.header = NeighbourHeader { + family: match ip { + IpAddr::V4(_) => AddressFamily::Inet, + IpAddr::V6(_) => AddressFamily::Inet6, }, + ifindex: link.index(), + state: NeighbourState::from(state), + flags, + kind: RouteType::from(NDA_UNSPEC as u8), }; + let mut nlas = vec![NeighbourAttribute::Destination(match ip { + IpAddr::V4(ipv4_addr) => NeighbourAddress::from(ipv4_addr), + IpAddr::V6(ipv6_addr) => NeighbourAddress::from(ipv6_addr), + })]; + + if !neigh.lladdr.is_empty() { + nlas.push(NeighbourAttribute::LinkLocalAddress( + parse_mac_address(&neigh.lladdr)?.to_vec(), + )); + } + + message.attributes = nlas; + // Send request and ACK let mut req = NetlinkMessage::from(RtnlMessage::NewNeighbour(message)); - req.header.flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_REPLACE; + req.header.flags = (NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_REPLACE) as u16; let mut response = self.handle.request(req)?; while let Some(message) = response.next().await { @@ -700,13 +714,13 @@ fn parse_mac_address(addr: &str) -> Result<[u8; 6]> { } /// Wraps external type with the local one, so we can implement various extensions and type conversions. -struct Link(packet::LinkMessage); +struct Link(LinkMessage); impl Link { /// If name. fn name(&self) -> String { - use packet::nlas::link::Nla; - self.nlas + use LinkAttribute as Nla; + self.attributes .iter() .find_map(|n| { if let Nla::IfName(name) = n { @@ -720,8 +734,8 @@ impl Link { /// Extract Mac address. fn address(&self) -> String { - use packet::nlas::link::Nla; - self.nlas + use LinkAttribute as Nla; + self.attributes .iter() .find_map(|n| { if let Nla::Address(data) = n { @@ -735,7 +749,12 @@ impl Link { /// Returns whether the link is UP fn is_up(&self) -> bool { - self.header.flags & packet::rtnl::constants::IFF_UP > 0 + let mut flags: u32 = 0; + for flag in &self.header.flags { + flags += u32::from(*flag); + } + + flags as i32 & libc::IFF_UP > 0 } fn index(&self) -> u32 { @@ -743,8 +762,8 @@ impl Link { } fn mtu(&self) -> Option { - use packet::nlas::link::Nla; - self.nlas.iter().find_map(|n| { + use LinkAttribute as Nla; + self.attributes.iter().find_map(|n| { if let Nla::Mtu(mtu) = n { Some(*mtu as u64) } else { @@ -754,21 +773,21 @@ impl Link { } } -impl From for Link { - fn from(msg: packet::LinkMessage) -> Self { +impl From for Link { + fn from(msg: LinkMessage) -> Self { Link(msg) } } impl Deref for Link { - type Target = packet::LinkMessage; + type Target = LinkMessage; fn deref(&self) -> &Self::Target { &self.0 } } -struct Address(packet::AddressMessage); +struct Address(AddressMessage); impl TryFrom
for IPAddress { type Error = anyhow::Error; @@ -798,7 +817,7 @@ impl TryFrom
for IPAddress { impl Address { fn is_ipv6(&self) -> bool { - self.0.header.family == packet::constants::AF_INET6 as u8 + u8::from(self.0.header.family) == libc::AF_INET6 as u8 } #[allow(dead_code)] @@ -807,13 +826,13 @@ impl Address { } fn address(&self) -> String { - use packet::nlas::address::Nla; + use AddressAttribute as Nla; self.0 - .nlas + .attributes .iter() .find_map(|n| { if let Nla::Address(data) = n { - format_address(data).ok() + Some(data.to_string()) } else { None } @@ -822,13 +841,13 @@ impl Address { } fn local(&self) -> String { - use packet::nlas::address::Nla; + use AddressAttribute as Nla; self.0 - .nlas + .attributes .iter() .find_map(|n| { if let Nla::Local(data) = n { - format_address(data).ok() + Some(data.to_string()) } else { None } @@ -837,10 +856,21 @@ impl Address { } } +fn parse_route_addr(ra: &RouteAddress) -> Result { + let ipaddr = match ra { + RouteAddress::Inet6(ipv6_addr) => ipv6_addr.to_canonical(), + RouteAddress::Inet(ipv4_addr) => IpAddr::from(*ipv4_addr), + _ => return Err(anyhow!("got invalid route address")), + }; + + Ok(ipaddr) +} + #[cfg(test)] mod tests { use super::*; - use rtnetlink::packet; + use netlink_packet_route::address::AddressHeader; + use netlink_packet_route::link::LinkHeader; use std::iter; use std::process::Command; use test_utils::skip_if_not_root; @@ -853,7 +883,7 @@ mod tests { .await .expect("Loopback not found"); - assert_ne!(message.header, packet::LinkHeader::default()); + assert_ne!(message.header, LinkHeader::default()); assert_eq!(message.name(), "lo"); } @@ -928,7 +958,7 @@ mod tests { assert_ne!(list.len(), 0); for addr in &list { - assert_ne!(addr.0.header, packet::AddressHeader::default()); + assert_ne!(addr.0.header, AddressHeader::default()); } } @@ -952,7 +982,7 @@ mod tests { } #[tokio::test] - async fn add_delete_addresses() { + async fn add_update_addresses() { skip_if_not_root!(); let list = vec![ @@ -981,9 +1011,9 @@ mod tests { assert!(result.is_some()); - // Delete it + // Update it handle - .delete_addresses(iter::once(result.unwrap())) + .add_addresses(lo.index(), iter::once(network)) .await .expect("Failed to delete address"); } diff --git a/src/libs/protocols/protos/types.proto b/src/libs/protocols/protos/types.proto index c09a4faff6..a45b15f610 100644 --- a/src/libs/protocols/protos/types.proto +++ b/src/libs/protocols/protos/types.proto @@ -58,6 +58,7 @@ message Route { string source = 4; uint32 scope = 5; IPFamily family = 6; + uint32 flags = 7; } message ARPNeighbor { diff --git a/src/runtime-rs/Cargo.lock b/src/runtime-rs/Cargo.lock index 13d49ffdea..eea1ad475d 100644 --- a/src/runtime-rs/Cargo.lock +++ b/src/runtime-rs/Cargo.lock @@ -9,7 +9,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -238,7 +238,7 @@ checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -316,7 +316,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78d456f91b4c1fdebf2698214e599fec3d7f8b46e3140fb254a9ea88c970ab0a" dependencies = [ "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -412,7 +412,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" dependencies = [ "libc", - "thiserror", + "thiserror 1.0.44", ] [[package]] @@ -446,7 +446,7 @@ dependencies = [ "log", "nix 0.25.1", "regex", - "thiserror", + "thiserror 1.0.44", ] [[package]] @@ -460,7 +460,7 @@ dependencies = [ "nix 0.26.2", "serde", "serde_json", - "thiserror", + "thiserror 1.0.44", "tokio", ] @@ -495,7 +495,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f190f3c954f7bca3c6296d0ec561c739bdbe6c7e990294ed168d415f6e1b5b01" dependencies = [ "nix 0.27.1", - "thiserror", + "thiserror 1.0.44", ] [[package]] @@ -520,7 +520,7 @@ dependencies = [ "slog", "slog-scope", "strum 0.24.1", - "thiserror", + "thiserror 1.0.44", "tokio", "ttrpc", ] @@ -571,7 +571,7 @@ dependencies = [ "serde_json", "signal-hook", "signal-hook-tokio", - "thiserror", + "thiserror 1.0.44", "time 0.3.37", "tokio", "windows-sys 0.48.0", @@ -750,7 +750,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -772,7 +772,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -796,7 +796,7 @@ dependencies = [ "lazy_static", "libc", "nix 0.23.2", - "thiserror", + "thiserror 1.0.44", "vm-memory", "vmm-sys-util 0.11.1", ] @@ -805,7 +805,7 @@ dependencies = [ name = "dbs-allocator" version = "0.1.1" dependencies = [ - "thiserror", + "thiserror 1.0.44", ] [[package]] @@ -816,7 +816,7 @@ dependencies = [ "kvm-ioctls", "libc", "memoffset 0.6.5", - "thiserror", + "thiserror 1.0.44", "vm-memory", "vmm-sys-util 0.11.1", ] @@ -830,7 +830,7 @@ dependencies = [ "kvm-ioctls", "lazy_static", "libc", - "thiserror", + "thiserror 1.0.44", "vm-fdt", "vm-memory", ] @@ -839,7 +839,7 @@ dependencies = [ name = "dbs-device" version = "0.2.0" dependencies = [ - "thiserror", + "thiserror 1.0.44", ] [[package]] @@ -881,7 +881,7 @@ dependencies = [ "kvm-ioctls", "libc", "log", - "thiserror", + "thiserror 1.0.44", "vfio-bindings", "vfio-ioctls", "vm-memory", @@ -895,7 +895,7 @@ dependencies = [ "dbs-utils", "dbs-virtio-devices", "log", - "thiserror", + "thiserror 1.0.44", "timerfd", ] @@ -908,7 +908,7 @@ dependencies = [ "libc", "log", "serde", - "thiserror", + "thiserror 1.0.44", "timerfd", "vmm-sys-util 0.11.1", ] @@ -939,7 +939,7 @@ dependencies = [ "sendfd", "serde", "serde_json", - "thiserror", + "thiserror 1.0.44", "threadpool", "timerfd", "vhost", @@ -999,7 +999,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -1009,7 +1009,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" dependencies = [ "derive_builder_core", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -1101,7 +1101,7 @@ dependencies = [ "serde_json", "slog", "slog-scope", - "thiserror", + "thiserror 1.0.44", "tracing", "vfio-bindings", "vfio-ioctls", @@ -1360,7 +1360,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -1716,7 +1716,7 @@ dependencies = [ "tempdir", "test-utils", "tests_utils", - "thiserror", + "thiserror 1.0.44", "tokio", "tracing", "ttrpc", @@ -1872,7 +1872,7 @@ dependencies = [ "slog", "slog-scope", "subprocess", - "thiserror", + "thiserror 1.0.44", ] [[package]] @@ -1895,7 +1895,7 @@ dependencies = [ "slog", "slog-scope", "sysinfo", - "thiserror", + "thiserror 1.0.44", "toml 0.5.11", ] @@ -2004,9 +2004,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" dependencies = [ "value-bag", ] @@ -2131,26 +2131,25 @@ dependencies = [ [[package]] name = "netlink-packet-core" -version = "0.4.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345b8ab5bd4e71a2986663e88c56856699d060e78e152e6e9d7966fcd5491297" +checksum = "72724faf704479d67b388da142b186f916188505e7e0b26719019c525882eda4" dependencies = [ "anyhow", "byteorder", - "libc", "netlink-packet-utils", ] [[package]] name = "netlink-packet-route" -version = "0.13.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5dee5ed749373c298237fe694eb0a51887f4cc1a27370c8464bac4382348f1a" +checksum = "74c171cd77b4ee8c7708da746ce392440cb7bcf618d122ec9ecc607b12938bf4" dependencies = [ "anyhow", - "bitflags 1.3.2", "byteorder", "libc", + "log", "netlink-packet-core", "netlink-packet-utils", ] @@ -2164,21 +2163,21 @@ dependencies = [ "anyhow", "byteorder", "paste", - "thiserror", + "thiserror 1.0.44", ] [[package]] name = "netlink-proto" -version = "0.10.0" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6" +checksum = "86b33524dc0968bfad349684447bfce6db937a9ac3332a1fe60c0c5a5ce63f21" dependencies = [ "bytes", "futures 0.3.28", "log", "netlink-packet-core", "netlink-sys", - "thiserror", + "thiserror 1.0.44", "tokio", ] @@ -2202,7 +2201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23541694f1d7d18cd1a0da3a1352a6ea48b01cbb4a8e7a6e547963823fd5276e" dependencies = [ "nix 0.23.2", - "thiserror", + "thiserror 1.0.44", ] [[package]] @@ -2435,7 +2434,7 @@ dependencies = [ "serde_json", "strum 0.26.3", "strum_macros 0.26.4", - "thiserror", + "thiserror 1.0.44", ] [[package]] @@ -2473,7 +2472,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -2544,7 +2543,7 @@ dependencies = [ "opentelemetry", "opentelemetry-http", "opentelemetry-semantic-conventions", - "thiserror", + "thiserror 1.0.44", "thrift", "tokio", ] @@ -2571,7 +2570,7 @@ dependencies = [ "js-sys", "once_cell", "pin-project-lite", - "thiserror", + "thiserror 1.0.44", ] [[package]] @@ -2591,7 +2590,7 @@ dependencies = [ "opentelemetry_api", "percent-encoding", "rand 0.8.5", - "thiserror", + "thiserror 1.0.44", "tokio", "tokio-stream", ] @@ -2755,7 +2754,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -2840,9 +2839,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.75" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -2889,7 +2888,7 @@ dependencies = [ "parking_lot 0.12.1", "procfs 0.14.2", "protobuf 2.28.0", - "thiserror", + "thiserror 1.0.44", ] [[package]] @@ -2957,7 +2956,7 @@ checksum = "b55bad9126f378a853655831eb7363b7b01b81d19f8cb1218861086ca4a1a61e" dependencies = [ "once_cell", "protobuf-support", - "thiserror", + "thiserror 1.0.44", ] [[package]] @@ -2981,7 +2980,7 @@ dependencies = [ "protobuf-parse", "regex", "tempfile", - "thiserror", + "thiserror 1.0.44", ] [[package]] @@ -2996,7 +2995,7 @@ dependencies = [ "protobuf 3.2.0", "protobuf-support", "tempfile", - "thiserror", + "thiserror 1.0.44", "which", ] @@ -3006,7 +3005,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5d4d7b8601c814cfb36bcebb79f0e61e45e1e93640cf778837833bbed05c372" dependencies = [ - "thiserror", + "thiserror 1.0.44", ] [[package]] @@ -3254,7 +3253,7 @@ checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom 0.2.10", "redox_syscall 0.2.16", - "thiserror", + "thiserror 1.0.44", ] [[package]] @@ -3382,16 +3381,19 @@ dependencies = [ [[package]] name = "rtnetlink" -version = "0.11.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f1cfa18f8cebe685373a2697915d7e0db3b4554918bba118385e0f71f258a7" +checksum = "b684475344d8df1859ddb2d395dd3dac4f8f3422a1aa0725993cb375fc5caba5" dependencies = [ "futures 0.3.28", "log", + "netlink-packet-core", "netlink-packet-route", + "netlink-packet-utils", "netlink-proto", - "nix 0.24.3", - "thiserror", + "netlink-sys", + "nix 0.27.1", + "thiserror 1.0.44", "tokio", ] @@ -3642,7 +3644,7 @@ checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -3712,7 +3714,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -3807,7 +3809,7 @@ dependencies = [ "slog-stdlog", "tempfile", "tests_utils", - "thiserror", + "thiserror 1.0.44", "tokio", "tracing", "tracing-opentelemetry", @@ -4019,7 +4021,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -4051,9 +4053,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", @@ -4148,7 +4150,16 @@ version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.44", +] + +[[package]] +name = "thiserror" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +dependencies = [ + "thiserror-impl 2.0.11", ] [[package]] @@ -4159,7 +4170,18 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", ] [[package]] @@ -4289,7 +4311,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -4384,7 +4406,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", ] [[package]] @@ -4458,7 +4480,7 @@ dependencies = [ "nix 0.26.2", "protobuf 3.2.0", "protobuf-codegen 3.2.0", - "thiserror", + "thiserror 1.0.44", "tokio", "tokio-vsock", "windows-sys 0.48.0", @@ -4567,9 +4589,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" -version = "1.4.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d92ccd67fb88503048c01b59152a04effd0782d035a83a6d256ce6085f08f4a3" +checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" [[package]] name = "vcpkg" @@ -4600,7 +4622,7 @@ dependencies = [ "kvm-ioctls", "libc", "log", - "thiserror", + "thiserror 2.0.11", "vfio-bindings", "vm-memory", "vmm-sys-util 0.11.1", @@ -4780,7 +4802,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", "wasm-bindgen-shared", ] @@ -4814,7 +4836,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.96", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/src/runtime-rs/crates/agent/src/kata/trans.rs b/src/runtime-rs/crates/agent/src/kata/trans.rs index 895540c8b0..6cd808054a 100644 --- a/src/runtime-rs/crates/agent/src/kata/trans.rs +++ b/src/runtime-rs/crates/agent/src/kata/trans.rs @@ -228,6 +228,7 @@ impl From for types::Route { source: from.source, scope: from.scope, family: protobuf::EnumOrUnknown::new(from.family.into()), + flags: from.flags, ..Default::default() } } @@ -242,6 +243,7 @@ impl From for Route { source: src.source, scope: src.scope, family: src.family.unwrap().into(), + flags: src.flags, } } } diff --git a/src/runtime-rs/crates/agent/src/types.rs b/src/runtime-rs/crates/agent/src/types.rs index ed4f1cf603..51f2fe3f3e 100644 --- a/src/runtime-rs/crates/agent/src/types.rs +++ b/src/runtime-rs/crates/agent/src/types.rs @@ -113,6 +113,7 @@ pub struct Route { pub source: String, pub scope: u32, pub family: IPFamily, + pub flags: u32, } #[derive(Deserialize, Debug, PartialEq, Clone, Default)] diff --git a/src/runtime-rs/crates/resource/Cargo.toml b/src/runtime-rs/crates/resource/Cargo.toml index 31d111e7fb..a8d750dcf1 100644 --- a/src/runtime-rs/crates/resource/Cargo.toml +++ b/src/runtime-rs/crates/resource/Cargo.toml @@ -21,10 +21,10 @@ lazy_static = "1.4.0" libc = ">=0.2.39" netns-rs = "0.1.0" netlink-sys = "0.8.3" -netlink-packet-route = "0.13.0" +netlink-packet-route = "0.19.0" nix = "0.24.2" rand = "^0.7.2" -rtnetlink = "0.11.0" +rtnetlink = "0.14.0" scopeguard = "1.0.0" serde = { version = "1.0.138", features = ["derive"] } serde_json = "1.0.82" diff --git a/src/runtime-rs/crates/resource/src/network/dan.rs b/src/runtime-rs/crates/resource/src/network/dan.rs index f8638fd8bc..7c8025da34 100644 --- a/src/runtime-rs/crates/resource/src/network/dan.rs +++ b/src/runtime-rs/crates/resource/src/network/dan.rs @@ -290,6 +290,8 @@ pub(crate) struct Route { // Scope #[serde(default)] pub scope: u32, + #[serde(default)] + pub flags: u32, } impl Route { @@ -399,6 +401,7 @@ mod tests { source: "172.18.0.1".to_owned(), gateway: "172.18.31.1".to_owned(), scope: 0, + flags: 0, }], neighbors: vec![ARPNeighbor { ip_address: Some("192.168.0.3/16".to_owned()), diff --git a/src/runtime-rs/crates/resource/src/network/endpoint/endpoints_test.rs b/src/runtime-rs/crates/resource/src/network/endpoint/endpoints_test.rs index 2281703699..f7200a8a78 100644 --- a/src/runtime-rs/crates/resource/src/network/endpoint/endpoints_test.rs +++ b/src/runtime-rs/crates/resource/src/network/endpoint/endpoints_test.rs @@ -10,7 +10,6 @@ mod tests { use anyhow::{anyhow, Context, Result}; use kata_types::config::hypervisor::TopologyConfigInfo; - use netlink_packet_route::MACVLAN_MODE_PRIVATE; use scopeguard::defer; use tests_utils::load_test_config; use tokio::sync::RwLock; @@ -200,6 +199,9 @@ mod tests { .await .expect("failed to get the index of dummy link"); + // Available MACVLAN MODES + let macvlan_mode_private: u32 = 1; + // the mode here does not matter, could be any of available modes if let Ok(()) = handle .link() @@ -207,7 +209,7 @@ mod tests { .macvlan( manual_macvlan_iface_name.clone(), dummy_index, - MACVLAN_MODE_PRIVATE, + macvlan_mode_private, ) .execute() .await diff --git a/src/runtime-rs/crates/resource/src/network/network_info/network_info_from_dan.rs b/src/runtime-rs/crates/resource/src/network/network_info/network_info_from_dan.rs index 1c8c684a14..9d2adfed0d 100644 --- a/src/runtime-rs/crates/resource/src/network/network_info/network_info_from_dan.rs +++ b/src/runtime-rs/crates/resource/src/network/network_info/network_info_from_dan.rs @@ -7,7 +7,7 @@ use agent::{ARPNeighbor, IPAddress, Interface, Route}; use anyhow::Result; use async_trait::async_trait; -use netlink_packet_route::IFF_NOARP; +use netlink_packet_route::link::LinkFlag::Noarp; use super::NetworkInfo; use crate::network::dan::DanDevice; @@ -55,7 +55,7 @@ impl NetworkInfoFromDan { hw_addr: dan_device.guest_mac.clone(), device_path: String::default(), field_type: dan_device.network_info.interface.ntype.clone(), - raw_flags: dan_device.network_info.interface.flags & IFF_NOARP, + raw_flags: dan_device.network_info.interface.flags & u32::from(Noarp), }; let routes = dan_device @@ -74,6 +74,7 @@ impl NetworkInfoFromDan { source: route.source.clone(), scope: route.scope, family, + flags: route.flags, }) }) .collect(); @@ -159,6 +160,7 @@ mod tests { source: "172.18.0.1".to_owned(), gateway: "172.18.31.1".to_owned(), scope: 0, + flags: 0, }], neighbors: vec![DanARPNeighbor { ip_address: Some("192.168.0.3/16".to_owned()), @@ -194,6 +196,7 @@ mod tests { source: "172.18.0.1".to_owned(), scope: 0, family: IPFamily::V4, + flags: 0, }]; assert_eq!(routes, network_info.routes().await.unwrap()); diff --git a/src/runtime-rs/crates/resource/src/network/network_info/network_info_from_link.rs b/src/runtime-rs/crates/resource/src/network/network_info/network_info_from_link.rs index bc969d7de3..d46628ec67 100644 --- a/src/runtime-rs/crates/resource/src/network/network_info/network_info_from_link.rs +++ b/src/runtime-rs/crates/resource/src/network/network_info/network_info_from_link.rs @@ -4,19 +4,21 @@ // SPDX-License-Identifier: Apache-2.0 // -use std::convert::TryFrom; +use std::{convert::TryFrom, net::IpAddr}; use agent::{ARPNeighbor, IPAddress, IPFamily, Interface, Route}; -use anyhow::{Context, Result}; +use anyhow::{anyhow, Context, Result}; use async_trait::async_trait; use futures::stream::TryStreamExt; use netlink_packet_route::{ - self, neighbour::NeighbourMessage, nlas::neighbour::Nla, route::RouteMessage, + self, + neighbour::{NeighbourAddress, NeighbourAttribute, NeighbourMessage}, + route::{RouteAddress, RouteAttribute, RouteMessage}, }; use super::NetworkInfo; use crate::network::utils::{ - address::{parse_ip, Address}, + address::Address, link::{self, LinkAttrs}, }; @@ -74,7 +76,7 @@ pub async fn handle_addresses( .await .context("try next address msg")? { - let family = addr_msg.header.family as i32; + let family = u8::from(addr_msg.header.family) as i32; if family != libc::AF_INET && family != libc::AF_INET6 { warn!(sl!(), "unsupported ip family {}", family); continue; @@ -100,13 +102,17 @@ pub async fn handle_addresses( fn generate_neigh(name: &str, n: &NeighbourMessage) -> Result { let mut neigh = ARPNeighbor { device: name.to_string(), - state: n.header.state as i32, + state: u16::from(n.header.state) as i32, ..Default::default() }; - for nla in &n.nlas { + for nla in &n.attributes { match nla { - Nla::Destination(addr) => { - let dest = parse_ip(addr, n.header.family).context("parse ip")?; + NeighbourAttribute::Destination(addr) => { + let dest = match addr { + NeighbourAddress::Inet6(ipv6_addr) => ipv6_addr.to_canonical(), + NeighbourAddress::Inet(ipv4_addr) => IpAddr::from(*ipv4_addr), + _ => return Err(anyhow!("invalid address")), + }; let addr = Some(IPAddress { family: if dest.is_ipv4() { IPFamily::V4 @@ -118,7 +124,7 @@ fn generate_neigh(name: &str, n: &NeighbourMessage) -> Result { }); neigh.to_ip_address = addr; } - Nla::LinkLocalAddress(addr) => { + NeighbourAttribute::LinkLocalAddress(addr) => { if addr.len() < 6 { continue; } @@ -157,29 +163,49 @@ async fn handle_neighbors( Ok(neighs) } -fn generate_route(name: &str, route: &RouteMessage) -> Result> { - if route.header.protocol == libc::RTPROT_KERNEL { +fn generate_route(name: &str, route_msg: &RouteMessage) -> Result> { + if u8::from(route_msg.header.protocol) == libc::RTPROT_KERNEL { return Ok(None); } - Ok(Some(Route { - dest: route - .destination_prefix() - .map(|(addr, prefix)| format!("{}/{}", addr, prefix)) - .unwrap_or_default(), - gateway: route.gateway().map(|v| v.to_string()).unwrap_or_default(), + let mut flags: u32 = 0; + for flag in &route_msg.header.flags { + flags += u32::from(*flag); + } + + let mut route = Route { + scope: u8::from(route_msg.header.scope) as u32, device: name.to_string(), - source: route - .source_prefix() - .map(|(addr, _)| addr.to_string()) - .unwrap_or_default(), - scope: route.header.scope as u32, - family: if route.header.address_family == libc::AF_INET as u8 { + family: if u8::from(route_msg.header.address_family) == libc::AF_INET as u8 { IPFamily::V4 } else { IPFamily::V6 }, - })) + flags, + ..Default::default() + }; + + for nla in &route_msg.attributes { + match nla { + RouteAttribute::Destination(d) => { + let dest = parse_route_addr(d)?; + route.dest = dest.to_string(); + } + RouteAttribute::Gateway(g) => { + let dest = parse_route_addr(g)?; + + route.gateway = dest.to_string(); + } + RouteAttribute::Source(s) => { + let dest = parse_route_addr(s)?; + + route.source = dest.to_string(); + } + _ => {} + } + } + + Ok(Some(route)) } async fn get_route_from_msg( @@ -190,12 +216,16 @@ async fn get_route_from_msg( ) -> Result<()> { let name = &attrs.name; let mut route_msg_list = handle.route().get(ip_version).execute(); - while let Some(route) = route_msg_list.try_next().await? { + while let Some(route_msg) = route_msg_list.try_next().await? { // get route filter with index - if let Some(index) = route.output_interface() { - if index == attrs.index { - if let Some(route) = generate_route(name, &route).context("generate route")? { - routes.push(route); + for attr in &route_msg.attributes { + if let RouteAttribute::Oif(index) = attr { + if *index == attrs.index { + if let Some(route) = + generate_route(name, &route_msg).context("generate route")? + { + routes.push(route); + } } } } @@ -228,3 +258,13 @@ impl NetworkInfo for NetworkInfoFromLink { Ok(self.neighs.clone()) } } + +fn parse_route_addr(ra: &RouteAddress) -> Result { + let ipaddr = match ra { + RouteAddress::Inet6(ipv6_addr) => ipv6_addr.to_canonical(), + RouteAddress::Inet(ipv4_addr) => IpAddr::from(*ipv4_addr), + _ => return Err(anyhow!("got invalid route address")), + }; + + Ok(ipaddr) +} diff --git a/src/runtime-rs/crates/resource/src/network/network_model/tc_filter_model.rs b/src/runtime-rs/crates/resource/src/network/network_model/tc_filter_model.rs index ff689b9b84..882003e669 100644 --- a/src/runtime-rs/crates/resource/src/network/network_model/tc_filter_model.rs +++ b/src/runtime-rs/crates/resource/src/network/network_model/tc_filter_model.rs @@ -64,7 +64,7 @@ impl NetworkModel for TcFilterModel { .parent(0xffff0000) // get protocol with network byte order .protocol(0x0003_u16.to_be()) - .redirect(virt_index) + .redirect(virt_index)? .execute() .await .context("add redirect for tap")?; @@ -75,7 +75,7 @@ impl NetworkModel for TcFilterModel { .parent(0xffff0000) // get protocol with network byte order .protocol(0x0003_u16.to_be()) - .redirect(tap_index) + .redirect(tap_index)? .execute() .await .context("add redirect for virt")?; diff --git a/src/runtime-rs/crates/resource/src/network/network_pair.rs b/src/runtime-rs/crates/resource/src/network/network_pair.rs index 7da02682ce..1816feb6b7 100644 --- a/src/runtime-rs/crates/resource/src/network/network_pair.rs +++ b/src/runtime-rs/crates/resource/src/network/network_pair.rs @@ -157,7 +157,7 @@ pub async fn create_link( handle .link() .set(base.index) - .master(base.master_index) + .controller(base.master_index) .execute() .await .context("set index")?; diff --git a/src/runtime-rs/crates/resource/src/network/utils/address.rs b/src/runtime-rs/crates/resource/src/network/utils/address.rs index a9a4c75002..18ea30c469 100644 --- a/src/runtime-rs/crates/resource/src/network/utils/address.rs +++ b/src/runtime-rs/crates/resource/src/network/utils/address.rs @@ -5,13 +5,13 @@ // use std::convert::TryFrom; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +use std::net::{IpAddr, Ipv4Addr}; use std::str::FromStr; use agent::IPFamily; use anyhow::{anyhow, Context, Result}; -use netlink_packet_route::nlas::address::Nla; -use netlink_packet_route::{AddressMessage, AF_INET, AF_INET6}; +use netlink_packet_route::address::AddressAttribute; +use netlink_packet_route::address::AddressMessage; #[derive(Debug, PartialEq, Eq, Clone)] pub struct Address { @@ -29,34 +29,42 @@ pub struct Address { impl TryFrom for Address { type Error = anyhow::Error; fn try_from(msg: AddressMessage) -> Result { - let AddressMessage { header, nlas } = msg; + let AddressMessage { + header, attributes, .. + } = msg; let mut addr = Address { addr: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), peer: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), broadcast: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), label: String::default(), flags: 0, - scope: header.scope, + scope: u8::from(header.scope), perfix_len: header.prefix_len, prefered_lft: 0, valid_ltf: 0, }; - for nla in nlas.into_iter() { + for nla in attributes.into_iter() { match nla { - Nla::Address(a) => { - addr.addr = parse_ip(&a, header.family)?; + AddressAttribute::Address(a) => { + addr.addr = a; } - Nla::Broadcast(b) => { - addr.broadcast = parse_ip(&b, header.family)?; + AddressAttribute::Broadcast(b) => { + addr.broadcast = IpAddr::V4(b); } - Nla::Label(l) => { + AddressAttribute::Label(l) => { addr.label = l; } - Nla::Flags(f) => { - addr.flags = f; + AddressAttribute::Flags(f) => { + //since the AddressAttribute::Flags(f) didn't implemented the u32 from trait, + //thus here just implemeted a simple transformer. + let mut d: u32 = 0; + for flag in &f { + d += u32::from(*flag); + } + addr.flags = d; } - Nla::CacheInfo(_c) => {} + AddressAttribute::CacheInfo(_c) => {} _ => {} } } @@ -65,26 +73,6 @@ impl TryFrom for Address { } } -pub(crate) fn parse_ip(ip: &[u8], family: u8) -> Result { - let support_len = if family as u16 == AF_INET { 4 } else { 16 }; - if ip.len() != support_len { - return Err(anyhow!( - "invalid ip addresses {:?} support {}", - &ip, - support_len - )); - } - match family as u16 { - AF_INET => Ok(IpAddr::V4(Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]))), - AF_INET6 => { - let mut octets = [0u8; 16]; - octets.copy_from_slice(&ip[..16]); - Ok(IpAddr::V6(Ipv6Addr::from(octets))) - } - _ => Err(anyhow!("unknown IP network family {}", family)), - } -} - pub(crate) fn parse_ip_cidr(ip: &str) -> Result<(IpAddr, u8)> { let items: Vec<&str> = ip.split('/').collect(); if items.len() != 2 { @@ -124,28 +112,6 @@ pub(crate) fn ip_family_from_ip_addr(ip_addr: &IpAddr) -> IPFamily { mod tests { use super::*; - #[test] - fn test_parse_ip() { - let test_ipv4 = [10, 25, 64, 128]; - let ipv4 = parse_ip(test_ipv4.as_slice(), AF_INET as u8).unwrap(); - let expected_ipv4 = IpAddr::V4(Ipv4Addr::new(10, 25, 64, 128)); - assert_eq!(ipv4, expected_ipv4); - - let test_ipv6 = [0, 2, 4, 0, 0, 2, 4, 0, 0, 2, 4, 0, 0, 2, 4, 0]; - let ipv6 = parse_ip(test_ipv6.as_slice(), AF_INET6 as u8).unwrap(); - // two u8 => one u16, (0u8, 2u8 => 0x0002), (4u8, 0u8 => 0x0400) - let expected_ipv6 = IpAddr::V6(Ipv6Addr::new( - 0x0002, 0x0400, 0x0002, 0x0400, 0x0002, 0x0400, 0x0002, 0x0400, - )); - assert_eq!(ipv6, expected_ipv6); - - let fail_ipv4 = [10, 22, 33, 44, 55]; - assert!(parse_ip(fail_ipv4.as_slice(), AF_INET as u8).is_err()); - - let fail_ipv6 = [1, 2, 3, 4, 5, 6, 7, 8, 2, 3]; - assert!(parse_ip(fail_ipv6.as_slice(), AF_INET6 as u8).is_err()); - } - #[test] fn test_parse_ip_cidr() { let test_cases = [ diff --git a/src/runtime-rs/crates/resource/src/network/utils/link/manager.rs b/src/runtime-rs/crates/resource/src/network/utils/link/manager.rs index f628ec03f4..e2c41c69aa 100644 --- a/src/runtime-rs/crates/resource/src/network/utils/link/manager.rs +++ b/src/runtime-rs/crates/resource/src/network/utils/link/manager.rs @@ -4,73 +4,84 @@ // SPDX-License-Identifier: Apache-2.0 // -use netlink_packet_route::{ - link::nlas::{Info, InfoBridge, InfoData, InfoKind, Nla}, - LinkMessage, +use netlink_packet_route::link::{ + InfoBridge, InfoData, InfoKind, LinkAttribute, LinkFlag, LinkInfo, LinkMessage, }; use super::{Link, LinkAttrs}; +pub(crate) struct VecLinkFlag(pub Vec); + +impl From<&VecLinkFlag> for u32 { + fn from(v: &VecLinkFlag) -> u32 { + let mut d: u32 = 0; + for flag in &v.0 { + d += u32::from(*flag); + } + d + } +} + #[allow(clippy::box_default)] pub fn get_link_from_message(mut msg: LinkMessage) -> Box { + let flags = u32::from(&VecLinkFlag(msg.header.flags)); let mut base = LinkAttrs { index: msg.header.index, - flags: msg.header.flags, - link_layer_type: msg.header.link_layer_type, + flags, + link_layer_type: u16::from(msg.header.link_layer_type), ..Default::default() }; - if msg.header.flags & libc::IFF_PROMISC as u32 != 0 { + if flags & libc::IFF_PROMISC as u32 != 0 { base.promisc = 1; } let mut link: Option> = None; - while let Some(attr) = msg.nlas.pop() { + while let Some(attr) = msg.attributes.pop() { match attr { - Nla::Info(infos) => { + LinkAttribute::LinkInfo(infos) => { link = Some(link_info(infos)); } - Nla::Address(a) => { + LinkAttribute::Address(a) => { base.hardware_addr = a; } - Nla::IfName(i) => { + LinkAttribute::IfName(i) => { base.name = i; } - Nla::Mtu(m) => { + LinkAttribute::Mtu(m) => { base.mtu = m; } - Nla::Link(l) => { + LinkAttribute::Link(l) => { base.parent_index = l; } - Nla::Master(m) => { + LinkAttribute::Controller(m) => { base.master_index = m; } - Nla::TxQueueLen(t) => { + LinkAttribute::TxQueueLen(t) => { base.txq_len = t; } - Nla::IfAlias(a) => { + LinkAttribute::IfAlias(a) => { base.alias = a; } - Nla::Stats(_s) => {} - Nla::Stats64(_s) => {} - Nla::Xdp(_x) => {} - Nla::ProtoInfo(_) => {} - Nla::OperState(_) => {} - Nla::NetnsId(n) => { + LinkAttribute::Stats(_s) => {} + LinkAttribute::Stats64(_s) => {} + LinkAttribute::Xdp(_x) => {} + LinkAttribute::OperState(_) => {} + LinkAttribute::NetnsId(n) => { base.net_ns_id = n; } - Nla::GsoMaxSize(i) => { + LinkAttribute::GsoMaxSize(i) => { base.gso_max_size = i; } - Nla::GsoMaxSegs(e) => { + LinkAttribute::GsoMaxSegs(e) => { base.gso_max_seqs = e; } - Nla::VfInfoList(_) => {} - Nla::NumTxQueues(t) => { + LinkAttribute::VfInfoList(_) => {} + LinkAttribute::NumTxQueues(t) => { base.num_tx_queues = t; } - Nla::NumRxQueues(r) => { + LinkAttribute::NumRxQueues(r) => { base.num_rx_queues = r; } - Nla::Group(g) => { + LinkAttribute::Group(g) => { base.group = g; } _ => { @@ -85,11 +96,11 @@ pub fn get_link_from_message(mut msg: LinkMessage) -> Box { } #[allow(clippy::box_default)] -fn link_info(mut infos: Vec) -> Box { +fn link_info(mut infos: Vec) -> Box { let mut link: Option> = None; while let Some(info) = infos.pop() { match info { - Info::Kind(kind) => match kind { + LinkInfo::Kind(kind) => match kind { InfoKind::Tun => { if link.is_none() { link = Some(Box::new(Tuntap::default())); @@ -126,7 +137,7 @@ fn link_info(mut infos: Vec) -> Box { } } }, - Info::Data(data) => match data { + LinkInfo::Data(data) => match data { InfoData::Tun(_) => { link = Some(Box::new(Tuntap::default())); } @@ -149,12 +160,12 @@ fn link_info(mut infos: Vec) -> Box { link = Some(Box::new(Device::default())); } }, - Info::SlaveKind(_sk) => { + LinkInfo::PortKind(_sk) => { if link.is_none() { link = Some(Box::new(Device::default())); } } - Info::SlaveData(_sd) => { + LinkInfo::PortData(_sd) => { link = Some(Box::new(Device::default())); } _ => { diff --git a/src/runtime-rs/crates/resource/src/network/utils/link/mod.rs b/src/runtime-rs/crates/resource/src/network/utils/link/mod.rs index 84ccfc4ff4..86027f2fee 100644 --- a/src/runtime-rs/crates/resource/src/network/utils/link/mod.rs +++ b/src/runtime-rs/crates/resource/src/network/utils/link/mod.rs @@ -14,7 +14,7 @@ pub use manager::get_link_from_message; use std::os::unix::io::RawFd; -use netlink_packet_route::link::nlas::State; +use netlink_packet_route::link::State; #[cfg(test)] pub use create::net_test_utils; diff --git a/src/runtime/virtcontainers/network.go b/src/runtime/virtcontainers/network.go index 975e15bb12..3dd3bbc318 100644 --- a/src/runtime/virtcontainers/network.go +++ b/src/runtime/virtcontainers/network.go @@ -309,6 +309,7 @@ func generateVCNetworkStructures(ctx context.Context, endpoints []Endpoint) ([]* r.Device = endpoint.Name() r.Scope = uint32(route.Scope) r.Family = utils.ConvertAddressFamily((int32)(route.Family)) + r.Flags = uint32(route.Flags) routes = append(routes, &r) } diff --git a/src/runtime/virtcontainers/pkg/agent/protocols/types.pb.go b/src/runtime/virtcontainers/pkg/agent/protocols/types.pb.go index ae81edfed6..4626f982b1 100644 --- a/src/runtime/virtcontainers/pkg/agent/protocols/types.pb.go +++ b/src/runtime/virtcontainers/pkg/agent/protocols/types.pb.go @@ -7,8 +7,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 -// protoc v3.21.12 +// protoc-gen-go v1.32.0 +// protoc v5.29.3 // source: types.proto package protocols @@ -307,6 +307,7 @@ type Route struct { Source string `protobuf:"bytes,4,opt,name=source,proto3" json:"source,omitempty"` Scope uint32 `protobuf:"varint,5,opt,name=scope,proto3" json:"scope,omitempty"` Family IPFamily `protobuf:"varint,6,opt,name=family,proto3,enum=types.IPFamily" json:"family,omitempty"` + Flags uint32 `protobuf:"varint,7,opt,name=flags,proto3" json:"flags,omitempty"` } func (x *Route) Reset() { @@ -383,6 +384,13 @@ func (x *Route) GetFamily() IPFamily { return IPFamily_v4 } +func (x *Route) GetFlags() uint32 { + if x != nil { + return x.Flags + } + return 0 +} + type ARPNeighbor struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -486,7 +494,7 @@ var file_types_proto_rawDesc = []byte{ 0x09, 0x52, 0x07, 0x70, 0x63, 0x69, 0x50, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x61, 0x77, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x08, 0x72, 0x61, 0x77, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x22, 0xa4, 0x01, 0x0a, 0x05, + 0x0d, 0x52, 0x08, 0x72, 0x61, 0x77, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x22, 0xba, 0x01, 0x0a, 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x61, 0x74, 0x65, @@ -497,28 +505,29 @@ var file_types_proto_rawDesc = []byte{ 0x28, 0x0d, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x27, 0x0a, 0x06, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x50, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x52, 0x06, 0x66, 0x61, 0x6d, 0x69, - 0x6c, 0x79, 0x22, 0x9d, 0x01, 0x0a, 0x0b, 0x41, 0x52, 0x50, 0x4e, 0x65, 0x69, 0x67, 0x68, 0x62, - 0x6f, 0x72, 0x12, 0x32, 0x0a, 0x0b, 0x74, 0x6f, 0x49, 0x50, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, - 0x49, 0x50, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x0b, 0x74, 0x6f, 0x49, 0x50, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x6c, 0x6c, 0x61, 0x64, 0x64, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x6c, 0x6c, 0x61, 0x64, 0x64, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x66, 0x6c, 0x61, - 0x67, 0x73, 0x2a, 0x1a, 0x0a, 0x08, 0x49, 0x50, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x12, 0x06, - 0x0a, 0x02, 0x76, 0x34, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, 0x76, 0x36, 0x10, 0x01, 0x2a, 0x35, - 0x0a, 0x13, 0x46, 0x53, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, - 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x10, - 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4f, 0x6e, 0x52, 0x6f, 0x6f, 0x74, 0x4d, 0x69, 0x73, 0x6d, 0x61, - 0x74, 0x63, 0x68, 0x10, 0x01, 0x42, 0x5b, 0x5a, 0x59, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x61, 0x74, 0x61, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x73, 0x2f, 0x6b, 0x61, 0x74, 0x61, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x73, 0x2f, 0x73, 0x72, 0x63, 0x2f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, - 0x76, 0x69, 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2f, 0x70, - 0x6b, 0x67, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6c, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x22, 0x9d, 0x01, 0x0a, 0x0b, 0x41, 0x52, 0x50, + 0x4e, 0x65, 0x69, 0x67, 0x68, 0x62, 0x6f, 0x72, 0x12, 0x32, 0x0a, 0x0b, 0x74, 0x6f, 0x49, 0x50, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, + 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x50, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, + 0x0b, 0x74, 0x6f, 0x49, 0x50, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x0a, 0x06, + 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x6c, 0x61, 0x64, 0x64, 0x72, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6c, 0x6c, 0x61, 0x64, 0x64, 0x72, 0x12, 0x14, 0x0a, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2a, 0x1a, 0x0a, 0x08, 0x49, 0x50, 0x46, 0x61, + 0x6d, 0x69, 0x6c, 0x79, 0x12, 0x06, 0x0a, 0x02, 0x76, 0x34, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, + 0x76, 0x36, 0x10, 0x01, 0x2a, 0x35, 0x0a, 0x13, 0x46, 0x53, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x0a, 0x0a, 0x06, 0x41, + 0x6c, 0x77, 0x61, 0x79, 0x73, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x4f, 0x6e, 0x52, 0x6f, 0x6f, + 0x74, 0x4d, 0x69, 0x73, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x10, 0x01, 0x42, 0x5b, 0x5a, 0x59, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x61, 0x74, 0x61, 0x2d, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2f, 0x6b, 0x61, 0x74, 0x61, 0x2d, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2f, 0x73, 0x72, 0x63, 0x2f, 0x72, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x76, 0x69, 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x65, 0x72, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var (