From 538e13b902b78bd68c1f72cd245d9181504a38c4 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Wed, 3 Jul 2024 11:24:52 +0200 Subject: [PATCH] vxlan: convert some attributes from Vec to IP address Attributes "Group", "Group6", "Local" and "Local6" are currently stored as a Vec, however they represent IP addresses. Change their type. Signed-off-by: Beniamino Galvani --- src/link/link_info/vxlan.rs | 85 +++++++++++++++++----- src/link/tests/vxlan.rs | 136 +++++++++++++++++++++++++++++++++++- 2 files changed, 202 insertions(+), 19 deletions(-) diff --git a/src/link/link_info/vxlan.rs b/src/link/link_info/vxlan.rs index 03861717..8718c3f7 100644 --- a/src/link/link_info/vxlan.rs +++ b/src/link/link_info/vxlan.rs @@ -1,5 +1,7 @@ // SPDX-License-Identifier: MIT +use std::net::{Ipv4Addr, Ipv6Addr}; + use anyhow::Context; use byteorder::{BigEndian, ByteOrder, NativeEndian}; use netlink_packet_utils::{ @@ -45,11 +47,11 @@ const IFLA_VXLAN_LOCALBYPASS: u16 = 31; #[non_exhaustive] pub enum InfoVxlan { Id(u32), - Group(Vec), - Group6(Vec), + Group(Ipv4Addr), + Group6(Ipv6Addr), Link(u32), - Local(Vec), - Local6(Vec), + Local(Ipv4Addr), + Local6(Ipv6Addr), Tos(u8), Ttl(u8), Label(u32), @@ -105,11 +107,10 @@ impl Nla for InfoVxlan { | Self::Link(_) | Self::Ageing(_) | Self::Limit(_) - | Self::PortRange(_) => 4, - Self::Local(bytes) - | Self::Local6(bytes) - | Self::Group(bytes) - | Self::Group6(bytes) => bytes.len(), + | Self::PortRange(_) + | Self::Group(_) + | Self::Local(_) => 4, + Self::Group6(_) | Self::Local6(_) => 16, Self::Other(nla) => nla.value_len(), } } @@ -141,10 +142,12 @@ impl Nla for InfoVxlan { | Self::RemCsumTX(value) | Self::RemCsumRX(value) | Self::TtlInherit(value) => buffer[0] = *value as u8, - Self::Local(value) - | Self::Group(value) - | Self::Group6(value) - | Self::Local6(value) => buffer.copy_from_slice(value.as_slice()), + Self::Group(value) | Self::Local(value) => { + buffer.copy_from_slice(&value.octets()) + } + Self::Group6(value) | Self::Local6(value) => { + buffer.copy_from_slice(&value.octets()) + } Self::Port(value) => BigEndian::write_u16(buffer, *value), Self::PortRange(range) => { BigEndian::write_u16(buffer, range.0); @@ -199,13 +202,61 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable> for InfoVxlan { IFLA_VXLAN_ID => { Self::Id(parse_u32(payload).context("invalid IFLA_VXLAN_ID value")?) } - IFLA_VXLAN_GROUP => Self::Group(payload.to_vec()), - IFLA_VXLAN_GROUP6 => Self::Group6(payload.to_vec()), + IFLA_VXLAN_GROUP => { + if payload.len() == 4 { + let mut data = [0u8; 4]; + data.copy_from_slice(&payload[0..4]); + Self::Group(Ipv4Addr::from(data)) + } else { + return Err(DecodeError::from(format!( + "Invalid IFLA_VXLAN_GROUP, got unexpected length \ + of IPv4 address payload {:?}", + payload + ))); + } + } + IFLA_VXLAN_LOCAL => { + if payload.len() == 4 { + let mut data = [0u8; 4]; + data.copy_from_slice(&payload[0..4]); + Self::Local(Ipv4Addr::from(data)) + } else { + return Err(DecodeError::from(format!( + "Invalid IFLA_VXLAN_LOCAL, got unexpected length \ + of IPv4 address payload {:?}", + payload + ))); + } + } + IFLA_VXLAN_GROUP6 => { + if payload.len() == 16 { + let mut data = [0u8; 16]; + data.copy_from_slice(&payload[0..16]); + Self::Group6(Ipv6Addr::from(data)) + } else { + return Err(DecodeError::from(format!( + "Invalid IFLA_VXLAN_GROUP6, got unexpected length \ + of IPv6 address payload {:?}", + payload + ))); + } + }, + IFLA_VXLAN_LOCAL6 => { + if payload.len() == 16 { + let mut data = [0u8; 16]; + data.copy_from_slice(&payload[0..16]); + Self::Local6(Ipv6Addr::from(data)) + } else { + return Err(DecodeError::from(format!( + "Invalid IFLA_VXLAN_LOCAL6, got unexpected length \ + of IPv6 address payload {:?}", + payload + ))); + } + }, IFLA_VXLAN_LINK => Self::Link( parse_u32(payload).context("invalid IFLA_VXLAN_LINK value")?, ), - IFLA_VXLAN_LOCAL => Self::Local(payload.to_vec()), - IFLA_VXLAN_LOCAL6 => Self::Local6(payload.to_vec()), IFLA_VXLAN_TOS => { Self::Tos(parse_u8(payload) .context("invalid IFLA_VXLAN_TOS value")?) diff --git a/src/link/tests/vxlan.rs b/src/link/tests/vxlan.rs index 751b3f11..e9a45e09 100644 --- a/src/link/tests/vxlan.rs +++ b/src/link/tests/vxlan.rs @@ -1,5 +1,8 @@ // SPDX-License-Identifier: MIT +use std::net::{Ipv4Addr, Ipv6Addr}; +use std::str::FromStr; + use netlink_packet_utils::{nla::DefaultNla, Emitable, Parseable}; use crate::link::link_flag::LinkFlags; @@ -226,9 +229,13 @@ fn test_parsing_link_vxlan() { LinkInfo::Kind(InfoKind::Vxlan), LinkInfo::Data(InfoData::Vxlan(vec![ InfoVxlan::Id(101), - InfoVxlan::Group(vec![8, 8, 8, 8]), + InfoVxlan::Group( + Ipv4Addr::from_str("8.8.8.8").unwrap().into(), + ), InfoVxlan::Link(13), - InfoVxlan::Local(vec![1, 1, 1, 1]), + InfoVxlan::Local( + Ipv4Addr::from_str("1.1.1.1").unwrap().into(), + ), InfoVxlan::Ttl(0), InfoVxlan::TtlInherit(false), InfoVxlan::Tos(0), @@ -376,3 +383,128 @@ fn test_parsing_link_vxlan() { assert_eq!(buf, raw); } + +#[test] +fn test_parsing_link_vxlan_ipv6() { + let raw = vec![ + 0x00, 0x00, 0x01, 0x00, 0xbe, 0x69, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x76, 0x78, 0x6c, 0x61, + 0x6e, 0x31, 0x00, 0x00, 0x08, 0x00, 0x0d, 0x00, 0xe8, 0x03, 0x00, 0x00, + 0x05, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x11, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x96, 0x05, 0x00, 0x00, + 0x08, 0x00, 0x32, 0x00, 0x44, 0x00, 0x00, 0x00, 0x08, 0x00, 0x33, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x08, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1f, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x28, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x08, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x20, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x06, 0x00, 0x6e, 0x6f, 0x6f, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x2f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00, 0x0a, 0x00, 0x02, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x0c, 0x00, 0x2b, 0x00, + 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x12, 0x00, + 0x0a, 0x00, 0x01, 0x00, 0x76, 0x78, 0x6c, 0x61, 0x6e, 0x00, 0x00, 0x00, + 0xec, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x10, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x03, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x11, 0x00, 0xfd, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x1a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0b, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x08, 0x00, 0x2c, 0x01, 0x00, 0x00, 0x08, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x21, 0x18, 0x00, 0x00, + 0x05, 0x00, 0x12, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x13, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x1f, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, + ]; + + let expected = LinkMessage { + header: LinkHeader { + interface_family: AddressFamily::Unspec, + index: 27070, + link_layer_type: LinkLayerType::Ether, + flags: LinkFlags::Broadcast | LinkFlags::Multicast, + change_mask: LinkFlags::empty(), + }, + attributes: vec![ + LinkAttribute::IfName("vxlan1".into()), + LinkAttribute::TxQueueLen(1000), + LinkAttribute::OperState(State::Down), + LinkAttribute::Mode(0), + LinkAttribute::Mtu(1430), + LinkAttribute::MinMtu(68), + LinkAttribute::MaxMtu(65535), + LinkAttribute::Group(0), + LinkAttribute::Promiscuity(0), + LinkAttribute::NumTxQueues(1), + LinkAttribute::GsoMaxSegs(65535), + LinkAttribute::GsoMaxSize(65536), + LinkAttribute::NumRxQueues(1), + LinkAttribute::Carrier(1), + LinkAttribute::Qdisc("noop".to_string()), + LinkAttribute::CarrierChanges(0), + LinkAttribute::CarrierUpCount(0), + LinkAttribute::CarrierDownCount(0), + LinkAttribute::ProtoDown(0), + LinkAttribute::Address(vec![0x00, 0x01, 0x02, 0x03, 0x04, 0x05]), + LinkAttribute::Broadcast(vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), + LinkAttribute::Xdp(vec![LinkXdp::Attached(XdpAttached::None)]), + LinkAttribute::LinkInfo(vec![ + LinkInfo::Kind(InfoKind::Vxlan), + LinkInfo::Data(InfoData::Vxlan(vec![ + InfoVxlan::Id(12), + InfoVxlan::Group6( + Ipv6Addr::from_str("ff00::1").unwrap().into(), + ), + InfoVxlan::Link(2), + InfoVxlan::Local6( + Ipv6Addr::from_str("fd01::2").unwrap().into(), + ), + InfoVxlan::Ttl(0), + InfoVxlan::TtlInherit(false), + InfoVxlan::Tos(0), + InfoVxlan::Df(0), + InfoVxlan::Label(0), + InfoVxlan::Other(DefaultNla::new(32, vec![0, 0, 0, 0])), + InfoVxlan::Learning(true), + InfoVxlan::Proxy(false), + InfoVxlan::Rsc(false), + InfoVxlan::L2Miss(false), + InfoVxlan::L3Miss(false), + InfoVxlan::CollectMetadata(false), + InfoVxlan::Ageing(300), + InfoVxlan::Limit(0), + InfoVxlan::Port(8472), + InfoVxlan::UDPCsum(true), + InfoVxlan::UDPZeroCsumTX(false), + InfoVxlan::UDPZeroCsumRX(false), + InfoVxlan::RemCsumTX(false), + InfoVxlan::RemCsumRX(false), + InfoVxlan::Localbypass(true), + InfoVxlan::PortRange((0, 0)), + ])), + ]), + ], + }; + + assert_eq!( + expected, + LinkMessage::parse(&LinkMessageBuffer::new(&raw)).unwrap() + ); + + let mut buf = vec![0; expected.buffer_len()]; + + expected.emit(&mut buf); + + assert_eq!(buf, raw); +}