From 491f785cca78a91b9686eb4b41eb4d711fea2ce6 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Wed, 4 Dec 2024 22:19:59 -0300 Subject: [PATCH] refactor cont. --- holo-rip/src/ripng/network.rs | 2 +- holo-rip/src/ripv2/network.rs | 2 +- holo-utils/src/socket.rs | 60 +++--- holo-vrrp/src/consts.rs | 4 - holo-vrrp/src/debug.rs | 6 +- holo-vrrp/src/error.rs | 22 +-- holo-vrrp/src/events.rs | 3 +- holo-vrrp/src/instance.rs | 228 ++++++++++++++++++---- holo-vrrp/src/interface.rs | 25 +-- holo-vrrp/src/lib.rs | 1 - holo-vrrp/src/macvlan.rs | 110 ----------- holo-vrrp/src/network.rs | 16 +- holo-vrrp/src/northbound/configuration.rs | 47 ++--- holo-vrrp/src/packet.rs | 10 +- holo-vrrp/src/southbound/rx.rs | 26 +-- holo-vrrp/tests/packet/mod.rs | 2 +- 16 files changed, 283 insertions(+), 281 deletions(-) delete mode 100644 holo-vrrp/src/macvlan.rs diff --git a/holo-rip/src/ripng/network.rs b/holo-rip/src/ripng/network.rs index 6e6df99a..447375de 100644 --- a/holo-rip/src/ripng/network.rs +++ b/holo-rip/src/ripng/network.rs @@ -89,7 +89,7 @@ impl NetworkVersion for Ripng { ) -> std::io::Result<()> { #[cfg(not(feature = "testing"))] { - socket.set_multicast_if_v6(ifindex) + socket.set_multicast_ifindex_v6(ifindex) } #[cfg(feature = "testing")] { diff --git a/holo-rip/src/ripv2/network.rs b/holo-rip/src/ripv2/network.rs index 59ec868c..eee855ed 100644 --- a/holo-rip/src/ripv2/network.rs +++ b/holo-rip/src/ripv2/network.rs @@ -81,7 +81,7 @@ impl NetworkVersion for Ripv2 { ) -> std::io::Result<()> { #[cfg(not(feature = "testing"))] { - socket.set_multicast_if_v4(ifindex) + socket.set_multicast_ifindex_v4(ifindex) } #[cfg(feature = "testing")] { diff --git a/holo-utils/src/socket.rs b/holo-utils/src/socket.rs index d9892574..3544ccfe 100644 --- a/holo-utils/src/socket.rs +++ b/holo-utils/src/socket.rs @@ -98,6 +98,23 @@ pub trait SocketExt: Sized + AsRawFd { ) } + // Sets the value of the IP_MULTICAST_IF option for this socket. + fn set_multicast_ifindex_v4(&self, ifindex: u32) -> Result<()> { + let optval = ip_mreqn { + imr_multiaddr: libc::in_addr { s_addr: 0 }, + imr_address: libc::in_addr { s_addr: 0 }, + imr_ifindex: ifindex as i32, + }; + + setsockopt( + self, + libc::IPPROTO_IP, + libc::IP_MULTICAST_IF, + &optval as *const _ as *const c_void, + std::mem::size_of::() as libc::socklen_t, + ) + } + // Sets the value of the IPV6_TCLASS option for this socket. fn set_ipv6_tclass(&self, dscp: u8) -> Result<()> { let optval = dscp as c_int; @@ -137,6 +154,19 @@ pub trait SocketExt: Sized + AsRawFd { ) } + // Sets the value of the IPV6_MULTICAST_IF option for this socket. + fn set_multicast_ifindex_v6(&self, ifindex: u32) -> Result<()> { + let optval = ifindex as i32; + + setsockopt( + self, + libc::IPPROTO_IPV6, + libc::IPV6_MULTICAST_IF, + &optval as *const _ as *const c_void, + std::mem::size_of::() as libc::socklen_t, + ) + } + // Executes an operation of the PACKET_ADD_MEMBERSHIP type. fn join_packet_multicast(&self, addr: [u8; 6], ifindex: u32) -> Result<()> { let mut optval = packet_mreq { @@ -242,36 +272,6 @@ pub trait UdpSocketExt: SocketExt { ) } - // Sets the value of the IP_MULTICAST_IF option for this socket. - fn set_multicast_if_v4(&self, ifindex: u32) -> Result<()> { - let optval = ip_mreqn { - imr_multiaddr: libc::in_addr { s_addr: 0 }, - imr_address: libc::in_addr { s_addr: 0 }, - imr_ifindex: ifindex as i32, - }; - - setsockopt( - self, - libc::IPPROTO_IP, - libc::IP_MULTICAST_IF, - &optval as *const _ as *const c_void, - std::mem::size_of::() as libc::socklen_t, - ) - } - - // Sets the value of the IPV6_MULTICAST_IF option for this socket. - fn set_multicast_if_v6(&self, ifindex: u32) -> Result<()> { - let optval = ifindex as i32; - - setsockopt( - self, - libc::IPPROTO_IPV6, - libc::IPV6_MULTICAST_IF, - &optval as *const _ as *const c_void, - std::mem::size_of::() as libc::socklen_t, - ) - } - // Sets the value of the IPV6_MULTICAST_HOPS option for this socket. fn set_ipv6_multicast_hopcount(&self, hopcount: u8) -> Result<()> { let optval = hopcount as c_int; diff --git a/holo-vrrp/src/consts.rs b/holo-vrrp/src/consts.rs index e1df4009..3ea5a33d 100644 --- a/holo-vrrp/src/consts.rs +++ b/holo-vrrp/src/consts.rs @@ -27,10 +27,6 @@ pub const VRRP_MULTICAST_ADDRESS: Ipv4Addr = Ipv4Addr::new(224, 0, 0, 18); // number of virtual IP addresses that can be on a VRRP header. pub const VRRP_IP_COUNT_MAX: usize = 20; -// ==== ARP ==== - -pub const ARP_PROTOCOL_NUMBER: u16 = 0x0806; - // ==== IP ==== pub const IP_HDR_MIN: usize = 20; diff --git a/holo-vrrp/src/debug.rs b/holo-vrrp/src/debug.rs index 09025f1a..b93f6e1f 100644 --- a/holo-vrrp/src/debug.rs +++ b/holo-vrrp/src/debug.rs @@ -20,7 +20,7 @@ pub enum Debug<'a> { // Instances InstanceCreate(u8), InstanceDelete(u8), - InstanceStateChange(u8, fsm::State, fsm::State), + InstanceStateChange(u8, fsm::Event, fsm::State, fsm::State), // Network PacketRx(&'a Ipv4Addr, &'a VrrpHdr), PacketTx(&'a VrrpHdr), @@ -37,9 +37,9 @@ impl Debug<'_> { // Parent span(s): vrrp debug!(%vrid, "{}", self); } - Debug::InstanceStateChange(vrid, old_state, new_state) => { + Debug::InstanceStateChange(vrid, event, old_state, new_state) => { // Parent span(s): vrrp - debug!(%vrid, ?old_state, ?new_state, "{}", self); + debug!(%vrid, ?event, ?old_state, ?new_state, "{}", self); } Debug::PacketRx(src, packet) => { // Parent span(s): vrrp diff --git a/holo-vrrp/src/error.rs b/holo-vrrp/src/error.rs index 6628eb37..dd82eca5 100644 --- a/holo-vrrp/src/error.rs +++ b/holo-vrrp/src/error.rs @@ -10,16 +10,14 @@ use std::fmt::Debug; use std::net::{IpAddr, Ipv4Addr}; -use tracing::warn; +use tracing::{error, warn}; use crate::packet::DecodeError; // VRRP errors. #[derive(Debug)] pub enum Error { - // I/O errors - IoError(IoError), - // Packet input + InstanceStartError(u8, IoError), GlobalError(Ipv4Addr, GlobalError), VirtualRouterError(Ipv4Addr, VirtualRouterError), } @@ -57,8 +55,8 @@ pub enum VirtualRouterError { impl Error { pub(crate) fn log(&self) { match self { - Error::IoError(error) => { - error.log(); + Error::InstanceStartError(vrid, error) => { + error!(%vrid, error = %with_source(error), "{}", self); } Error::GlobalError(source, error) => { warn!(?source, %error, "{}", self); @@ -73,7 +71,9 @@ impl Error { impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Error::IoError(error) => std::fmt::Display::fmt(error, f), + Error::InstanceStartError(..) => { + write!(f, "failed to start VRRP instance") + } Error::GlobalError(_, error) => std::fmt::Display::fmt(error, f), Error::VirtualRouterError(_, error) => { std::fmt::Display::fmt(error, f) @@ -85,19 +85,13 @@ impl std::fmt::Display for Error { impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { - Error::IoError(error) => Some(error), + Error::InstanceStartError(_, error) => Some(error), Error::GlobalError(_, error) => Some(error), Error::VirtualRouterError(_, error) => Some(error), } } } -impl From for Error { - fn from(error: IoError) -> Error { - Error::IoError(error) - } -} - impl From<(Ipv4Addr, DecodeError)> for Error { fn from((src, error): (Ipv4Addr, DecodeError)) -> Error { match error { diff --git a/holo-vrrp/src/events.rs b/holo-vrrp/src/events.rs index 0e6bbcbe..9847ec28 100644 --- a/holo-vrrp/src/events.rs +++ b/holo-vrrp/src/events.rs @@ -116,6 +116,7 @@ pub(crate) fn process_vrrp_packet( instance.change_state( &interface, fsm::State::Backup, + fsm::Event::HigherPriorityBackup, MasterReason::NotMaster, ); } @@ -141,12 +142,12 @@ pub(crate) fn handle_master_down_timer( }; // RFC 3768: Section 6.4.2 ("If the Master_Down_timer fires") - instance.state.last_event = fsm::Event::MasterTimeout; instance.send_vrrp_advertisement(src_ip); instance.send_gratuitous_arp(); instance.change_state( &interface, fsm::State::Master, + fsm::Event::MasterTimeout, MasterReason::NoResponse, ); diff --git a/holo-vrrp/src/instance.rs b/holo-vrrp/src/instance.rs index 33f8c09f..aced716b 100644 --- a/holo-vrrp/src/instance.rs +++ b/holo-vrrp/src/instance.rs @@ -14,16 +14,19 @@ use std::time::Duration; use chrono::{DateTime, Utc}; use enum_as_inner::EnumAsInner; -use holo_utils::task::{IntervalTask, TimeoutTask}; +use holo_utils::socket::{AsyncFd, Socket}; +use holo_utils::task::{IntervalTask, Task, TimeoutTask}; +use holo_utils::UnboundedSender; +use tokio::sync::mpsc; use crate::consts::{VRRP_MULTICAST_ADDRESS, VRRP_PROTO_NUMBER}; use crate::debug::Debug; -use crate::interface::InterfaceView; -use crate::macvlan::{MacvlanInterface, MacvlanNet}; +use crate::error::{Error, IoError}; +use crate::interface::{InterfaceSys, InterfaceView}; use crate::northbound::configuration::InstanceCfg; use crate::packet::{ArpHdr, EthernetHdr, Ipv4Hdr, VrrpHdr, VrrpPacket}; use crate::tasks::messages::output::NetTxPacketMsg; -use crate::{southbound, tasks}; +use crate::{network, southbound, tasks}; #[derive(Debug)] pub struct Instance { @@ -34,7 +37,9 @@ pub struct Instance { // Instance state data. pub state: InstanceState, // Macvlan interface. - pub mvlan: MacvlanInterface, + pub mvlan: InstanceMacvlan, + // Interface raw sockets and Tx/Rx tasks. + pub net: Option, } #[derive(Debug, Default)] @@ -48,6 +53,27 @@ pub struct InstanceState { pub statistics: Statistics, } +#[derive(Debug)] +pub struct InstanceMacvlan { + // Interface name. + pub name: String, + // Interface system data. + pub system: InterfaceSys, +} + +#[derive(Debug)] +pub struct InstanceNet { + // Raw sockets. + pub socket_vrrp_tx: Arc>, + pub socket_vrrp_rx: Arc>, + pub socket_arp: Arc>, + // Network Tx/Rx tasks. + _net_tx_task: Task<()>, + _vrrp_net_rx_task: Task<()>, + // Network Tx output channel. + pub net_tx_packetp: UnboundedSender, +} + // Protocol state machine. pub mod fsm { #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] @@ -119,25 +145,75 @@ impl Instance { vrid, config: InstanceCfg::default(), state: InstanceState::default(), - mvlan: MacvlanInterface::new(vrid), + mvlan: InstanceMacvlan::new(vrid), + net: None, } } pub(crate) fn update(&mut self, interface: &InterfaceView) { - if interface.system.is_ready() && self.mvlan.system.is_ready() { - if let Ok(net) = MacvlanNet::new(interface, &self.mvlan) { - self.mvlan.net = Some(net); - self.timer_set(interface); + let is_ready = interface.system.ifindex.is_some() + && !interface.system.addresses.is_empty() + && self.mvlan.system.ifindex.is_some(); + if is_ready && self.state.state == fsm::State::Initialize { + self.startup(interface); + } else if !is_ready && self.state.state != fsm::State::Initialize { + self.shutdown(interface); + } + } + + fn startup(&mut self, interface: &InterfaceView) { + match InstanceNet::new(interface, &self.mvlan) { + Ok(net) => { + if self.config.priority == 255 { + let src_ip = + interface.system.addresses.first().unwrap().ip(); + self.send_vrrp_advertisement(src_ip); + self.send_gratuitous_arp(); + self.change_state( + interface, + fsm::State::Master, + fsm::Event::Startup, + MasterReason::Priority, + ); + } else { + self.change_state( + interface, + fsm::State::Backup, + fsm::Event::Startup, + MasterReason::NotMaster, + ); + } + self.net = Some(net); + } + Err(error) => { + Error::InstanceStartError(self.vrid, error).log(); } - } else { - self.mvlan.net = None; } } + pub(crate) fn shutdown(&mut self, interface: &InterfaceView) { + if self.state.state == fsm::State::Master { + // Send an advertisement with Priority = 0. + // TODO + } + + // Transition to the Initialize state. + self.change_state( + interface, + fsm::State::Initialize, + fsm::Event::Shutdown, + MasterReason::NotMaster, + ); + + // Close network sockets and tasks. + self.net = None; + } + pub(crate) fn change_state( &mut self, interface: &InterfaceView, state: fsm::State, + event: fsm::Event, new_master_reason: MasterReason, ) { if self.state.state == state { @@ -145,27 +221,44 @@ impl Instance { } // Log the state transition. - Debug::InstanceStateChange(self.vrid, self.state.state, state).log(); - - if state == fsm::State::Backup { - for addr in &self.config.virtual_addresses { - southbound::tx::ip_addr_del( - &interface.tx.ibus, - &self.mvlan.name, - *addr, - ); + Debug::InstanceStateChange(self.vrid, event, self.state.state, state) + .log(); + + match (self.state.state, state) { + (fsm::State::Initialize, _) => { + // Set the up-time to the current time. + self.state.up_time = Some(Utc::now()); } - } else if state == fsm::State::Master { - for addr in &self.config.virtual_addresses { - southbound::tx::ip_addr_add( - &interface.tx.ibus, - &self.mvlan.name, - *addr, - ); + (_, fsm::State::Initialize) => { + // Reset state attributes. + self.state.up_time = None; + self.state.last_adv_src = None; + } + (_, fsm::State::Backup) => { + // Remove virtual IPs from the macvlan interface. + for addr in &self.config.virtual_addresses { + southbound::tx::ip_addr_del( + &interface.tx.ibus, + &self.mvlan.name, + *addr, + ); + } + } + (_, fsm::State::Master) => { + // Add virtual IPs to the macvlan interface. + for addr in &self.config.virtual_addresses { + southbound::tx::ip_addr_add( + &interface.tx.ibus, + &self.mvlan.name, + *addr, + ); + } } } + // Update state and initialize the corresponding timer. self.state.state = state; + self.state.last_event = event; self.state.new_master_reason = new_master_reason; self.timer_set(interface); } @@ -187,7 +280,7 @@ impl Instance { self.state.timer = VrrpTimer::MasterDownTimer(task); } fsm::State::Master => { - let Some(net) = &self.mvlan.net else { + let Some(net) = &self.net else { return; }; let src_ip = interface.system.addresses.first().unwrap().ip(); @@ -219,7 +312,7 @@ impl Instance { pub(crate) fn generate_vrrp_packet(&self) -> VrrpHdr { let mut ip_addresses: Vec = vec![]; - for addr in self.config.virtual_addresses.clone() { + for addr in &self.config.virtual_addresses { ip_addresses.push(addr.ip()); } @@ -270,7 +363,7 @@ impl Instance { } pub(crate) fn send_vrrp_advertisement(&mut self, src_ip: Ipv4Addr) { - let Some(net) = &self.mvlan.net else { + let Some(net) = &self.net else { return; }; @@ -283,7 +376,7 @@ impl Instance { } pub(crate) fn send_gratuitous_arp(&self) { - let Some(net) = &self.mvlan.net else { + let Some(net) = &self.net else { return; }; @@ -296,13 +389,12 @@ impl Instance { for addr in &self.config.virtual_addresses { let arp_hdr = ArpHdr { hw_type: 1, - // IPv4 - proto_type: 0x0800, + proto_type: libc::ETH_P_IP as _, // MAC address length hw_length: 6, proto_length: 4, operation: 1, - // Sender HW address is virtual mac. + // Sender HW address is virtual MAC // https://datatracker.ietf.org/doc/html/rfc3768#section-7.3 sender_hw_address: self.mvlan.system.mac_address, sender_proto_address: addr.ip(), @@ -326,6 +418,72 @@ impl Drop for Instance { } } +// ==== impl InstanceMacvlan ==== + +impl InstanceMacvlan { + pub(crate) fn new(vrid: u8) -> Self { + let name = format!("mvlan-vrrp-{}", vrid); + Self { + name, + system: InterfaceSys::default(), + } + } +} + +// ==== impl InstanceNet ==== + +impl InstanceNet { + pub(crate) fn new( + parent_iface: &InterfaceView, + mvlan: &InstanceMacvlan, + ) -> Result { + let instance_channels_tx = &parent_iface.tx; + + // Create raw sockets. + let socket_vrrp_rx = network::socket_vrrp_rx(parent_iface) + .map_err(IoError::SocketError) + .and_then(|socket| { + AsyncFd::new(socket).map_err(IoError::SocketError) + }) + .map(Arc::new)?; + let socket_vrrp_tx = network::socket_vrrp_tx(mvlan) + .map_err(IoError::SocketError) + .and_then(|socket| { + AsyncFd::new(socket).map_err(IoError::SocketError) + }) + .map(Arc::new)?; + let socket_arp = network::socket_arp(&mvlan.name) + .map_err(IoError::SocketError) + .and_then(|socket| { + AsyncFd::new(socket).map_err(IoError::SocketError) + }) + .map(Arc::new)?; + + // Start network Tx/Rx tasks. + let (net_tx_packetp, net_tx_packetc) = mpsc::unbounded_channel(); + let net_tx_task = tasks::net_tx( + socket_vrrp_tx.clone(), + socket_arp.clone(), + net_tx_packetc, + #[cfg(feature = "testing")] + &instance_channels_tx.protocol_output, + ); + let vrrp_net_rx_task = tasks::vrrp_net_rx( + socket_vrrp_rx.clone(), + &instance_channels_tx.protocol_input.vrrp_net_packet_tx, + ); + + Ok(Self { + socket_vrrp_tx, + socket_vrrp_rx, + socket_arp, + _net_tx_task: net_tx_task, + _vrrp_net_rx_task: vrrp_net_rx_task, + net_tx_packetp, + }) + } +} + // ===== impl Statistics ===== impl Default for Statistics { diff --git a/holo-vrrp/src/interface.rs b/holo-vrrp/src/interface.rs index 4791a7ee..88b6d6d5 100644 --- a/holo-vrrp/src/interface.rs +++ b/holo-vrrp/src/interface.rs @@ -124,6 +124,16 @@ impl Interface { self.instances.values_mut(), ) } + + pub(crate) fn as_view(&mut self) -> InterfaceView<'_> { + InterfaceView { + name: &self.name, + system: &mut self.system, + statistics: &mut self.statistics, + tx: &self.tx, + shared: &self.shared, + } + } } #[async_trait] @@ -202,21 +212,6 @@ impl ProtocolInstance for Interface { } } -// ===== impl InterfaceSys ===== - -impl InterfaceSys { - pub(crate) fn is_ready(&self) -> bool { - if self.ifindex.is_none() { - return false; - } - if self.addresses.is_empty() { - return false; - } - - true - } -} - // ===== impl ProtocolInputChannelsRx ===== #[async_trait] diff --git a/holo-vrrp/src/lib.rs b/holo-vrrp/src/lib.rs index 903606a0..34fe3bc0 100644 --- a/holo-vrrp/src/lib.rs +++ b/holo-vrrp/src/lib.rs @@ -19,7 +19,6 @@ pub mod error; pub mod events; pub mod instance; pub mod interface; -pub mod macvlan; pub mod network; pub mod northbound; pub mod packet; diff --git a/holo-vrrp/src/macvlan.rs b/holo-vrrp/src/macvlan.rs deleted file mode 100644 index 3ae4fa37..00000000 --- a/holo-vrrp/src/macvlan.rs +++ /dev/null @@ -1,110 +0,0 @@ -// -// Copyright (c) The Holo Core Contributors -// -// SPDX-License-Identifier: MIT -// -// Sponsored by NLnet as part of the Next Generation Internet initiative. -// See: https://nlnet.nl/NGI0 -// - -use std::sync::Arc; - -use holo_utils::socket::{AsyncFd, Socket}; -use holo_utils::task::Task; -use holo_utils::UnboundedSender; -use tokio::sync::mpsc; - -use crate::error::IoError; -use crate::interface::{InterfaceSys, InterfaceView}; -use crate::tasks::messages::output::NetTxPacketMsg; -use crate::{network, tasks}; - -#[derive(Debug)] -pub struct MacvlanInterface { - // Interface name. - pub name: String, - // Interface system data. - pub system: InterfaceSys, - // Interface raw sockets and Tx/Rx tasks. - pub net: Option, -} - -#[derive(Debug)] -pub struct MacvlanNet { - // Raw sockets. - pub socket_vrrp_tx: Arc>, - pub socket_vrrp_rx: Arc>, - pub socket_arp: Arc>, - // Network Tx/Rx tasks. - _net_tx_task: Task<()>, - _vrrp_net_rx_task: Task<()>, - // Network Tx output channel. - pub net_tx_packetp: UnboundedSender, -} - -// ==== impl MacvlanInterface ==== - -impl MacvlanInterface { - pub(crate) fn new(vrid: u8) -> Self { - let name = format!("mvlan-vrrp-{}", vrid); - Self { - name, - system: InterfaceSys::default(), - net: None, - } - } -} - -// ==== impl MacvlanNet ==== - -impl MacvlanNet { - pub(crate) fn new( - parent_iface: &InterfaceView, - mvlan: &MacvlanInterface, - ) -> Result { - let instance_channels_tx = &parent_iface.tx; - - // Create raw sockets. - let socket_vrrp_rx = network::socket_vrrp_rx(parent_iface) - .map_err(IoError::SocketError) - .and_then(|socket| { - AsyncFd::new(socket).map_err(IoError::SocketError) - }) - .map(Arc::new)?; - let socket_vrrp_tx = network::socket_vrrp_tx(mvlan) - .map_err(IoError::SocketError) - .and_then(|socket| { - AsyncFd::new(socket).map_err(IoError::SocketError) - }) - .map(Arc::new)?; - let socket_arp = network::socket_arp(&mvlan.name) - .map_err(IoError::SocketError) - .and_then(|socket| { - AsyncFd::new(socket).map_err(IoError::SocketError) - }) - .map(Arc::new)?; - - // Start network Tx/Rx tasks. - let (net_tx_packetp, net_tx_packetc) = mpsc::unbounded_channel(); - let net_tx_task = tasks::net_tx( - socket_vrrp_tx.clone(), - socket_arp.clone(), - net_tx_packetc, - #[cfg(feature = "testing")] - &instance_channels_tx.protocol_output, - ); - let vrrp_net_rx_task = tasks::vrrp_net_rx( - socket_vrrp_rx.clone(), - &instance_channels_tx.protocol_input.vrrp_net_packet_tx, - ); - - Ok(Self { - socket_vrrp_tx, - socket_vrrp_rx, - socket_arp, - _net_tx_task: net_tx_task, - _vrrp_net_rx_task: vrrp_net_rx_task, - net_tx_packetp, - }) - } -} diff --git a/holo-vrrp/src/network.rs b/holo-vrrp/src/network.rs index 87532846..7769f816 100644 --- a/holo-vrrp/src/network.rs +++ b/holo-vrrp/src/network.rs @@ -12,20 +12,18 @@ use std::os::fd::AsRawFd; use std::sync::Arc; use bytes::BufMut; -use holo_utils::socket::{AsyncFd, Socket}; +use holo_utils::socket::{AsyncFd, Socket, SocketExt}; use holo_utils::{capabilities, Sender, UnboundedReceiver}; use libc::{AF_PACKET, ETH_P_ARP}; use nix::sys::socket::{self, LinkAddr, SockaddrIn, SockaddrLike}; use socket2::{Domain, Protocol, Type}; use tokio::sync::mpsc::error::SendError; -use crate::consts::{ - ARP_PROTOCOL_NUMBER, VRRP_MULTICAST_ADDRESS, VRRP_PROTO_NUMBER, -}; +use crate::consts::{VRRP_MULTICAST_ADDRESS, VRRP_PROTO_NUMBER}; use crate::debug::Debug; use crate::error::IoError; +use crate::instance::InstanceMacvlan; use crate::interface::InterfaceView; -use crate::macvlan::MacvlanInterface; use crate::packet::{ArpHdr, EthernetHdr, Ipv4Hdr, VrrpHdr, VrrpPacket}; use crate::tasks::messages::input::VrrpNetRxPacketMsg; use crate::tasks::messages::output::NetTxPacketMsg; @@ -33,7 +31,7 @@ use crate::tasks::messages::output::NetTxPacketMsg; // ===== global functions ===== pub(crate) fn socket_vrrp_tx( - mvlan: &MacvlanInterface, + mvlan: &InstanceMacvlan, ) -> Result { #[cfg(not(feature = "testing"))] { @@ -46,9 +44,7 @@ pub(crate) fn socket_vrrp_tx( })?; socket.set_nonblocking(true)?; socket.set_reuse_address(true)?; - socket.set_multicast_if_v4( - &mvlan.system.addresses.first().unwrap().ip(), - )?; + socket.set_multicast_ifindex_v4(mvlan.system.ifindex.unwrap())?; socket.set_header_included(true)?; socket.set_multicast_ttl_v4(255)?; socket.set_tos(libc::IPTOS_PREC_INTERNETCONTROL as u32)?; @@ -160,7 +156,7 @@ async fn send_packet_arp( let iov = [IoSlice::new(&buf)]; let mut sll = libc::sockaddr_ll { sll_family: AF_PACKET as u16, - sll_protocol: ARP_PROTOCOL_NUMBER.to_be(), + sll_protocol: (libc::ETH_P_ARP as u16).to_be(), sll_ifindex: ifindex as i32, sll_hatype: 0, sll_pkttype: 0, diff --git a/holo-vrrp/src/northbound/configuration.rs b/holo-vrrp/src/northbound/configuration.rs index 469cd175..bd853b1e 100644 --- a/holo-vrrp/src/northbound/configuration.rs +++ b/holo-vrrp/src/northbound/configuration.rs @@ -20,7 +20,7 @@ use holo_northbound::yang::interfaces; use holo_utils::yang::DataNodeRefExt; use ipnetwork::Ipv4Network; -use crate::instance::{fsm, Instance, MasterReason}; +use crate::instance::{fsm, Instance}; use crate::interface::Interface; use crate::southbound; @@ -197,40 +197,43 @@ impl Provider for Interface { instance.mvlan.name.clone(), virtual_mac_addr, ); - - // reminder to remove the following line. - // currently up due to state not being properly maintained on startup. - instance.change_state( - &interface, - fsm::State::Backup, - MasterReason::NotMaster, - ); } Event::InstanceDelete { vrid } => { - let instance = self.instances.remove(&vrid).unwrap(); + let mut instance = self.instances.remove(&vrid).unwrap(); + let interface = self.as_view(); + + // Shut down the instance. + instance.shutdown(&interface); // Delete macvlan interface. southbound::tx::mvlan_delete( - &self.tx.ibus, + &interface.tx.ibus, &instance.mvlan.name, ); } Event::VirtualAddressCreate { vrid, addr } => { let (interface, instance) = self.get_instance(vrid).unwrap(); - southbound::tx::ip_addr_add( - &interface.tx.ibus, - &instance.mvlan.name, - addr, - ); - instance.timer_set(&interface); + + if instance.state.state == fsm::State::Master { + southbound::tx::ip_addr_add( + &interface.tx.ibus, + &instance.mvlan.name, + addr, + ); + instance.timer_set(&interface); + } } Event::VirtualAddressDelete { vrid, addr } => { let (interface, instance) = self.get_instance(vrid).unwrap(); - southbound::tx::ip_addr_del( - &interface.tx.ibus, - &instance.mvlan.name, - addr, - ); + + if instance.state.state == fsm::State::Master { + southbound::tx::ip_addr_del( + &interface.tx.ibus, + &instance.mvlan.name, + addr, + ); + instance.timer_set(&interface); + } } Event::ResetTimer { vrid } => { let (_, instance) = self.get_instance(vrid).unwrap(); diff --git a/holo-vrrp/src/packet.rs b/holo-vrrp/src/packet.rs index 42924b9f..01688dc4 100644 --- a/holo-vrrp/src/packet.rs +++ b/holo-vrrp/src/packet.rs @@ -312,17 +312,9 @@ impl EthernetHdr { Ok(Self { dst_mac, src_mac, - ethertype: 0x0800, + ethertype: libc::ETH_P_IP as _, }) } - - pub fn vrrp(vrid: u8) -> Self { - Self { - dst_mac: [0x01, 0x00, 0x5e, 0x00, 0x00, 0x12], - src_mac: [0x00, 0x00, 0x5e, 0x00, 0x01, vrid], - ethertype: 0x0800, // IP ethertype - } - } } impl VrrpPacket { diff --git a/holo-vrrp/src/southbound/rx.rs b/holo-vrrp/src/southbound/rx.rs index 8c1a217f..17df9364 100644 --- a/holo-vrrp/src/southbound/rx.rs +++ b/holo-vrrp/src/southbound/rx.rs @@ -43,7 +43,7 @@ pub(crate) fn process_iface_update( } pub(crate) fn process_addr_add(interface: &mut Interface, msg: AddressMsg) { - let (interface, mut instances) = interface.iter_instances(); + let (interface, instances) = interface.iter_instances(); // Handle address updates for the primary VRRP interface. if msg.ifname == interface.name { @@ -53,22 +53,11 @@ pub(crate) fn process_addr_add(interface: &mut Interface, msg: AddressMsg) { instance.update(&interface); } } - return; - } - - // Handle address updates for VRRP macvlan interfaces. - if let Some(instance) = - instances.find(|instance| msg.ifname == instance.mvlan.name) - { - if let IpNetwork::V4(addr) = msg.addr { - instance.mvlan.system.addresses.insert(addr); - instance.update(&interface); - } } } pub(crate) fn process_addr_del(interface: &mut Interface, msg: AddressMsg) { - let (interface, mut instances) = interface.iter_instances(); + let (interface, instances) = interface.iter_instances(); // Handle address updates for the primary VRRP interface. if msg.ifname == interface.name { @@ -78,16 +67,5 @@ pub(crate) fn process_addr_del(interface: &mut Interface, msg: AddressMsg) { instance.update(&interface); } } - return; - } - - // Handle address updates for VRRP macvlan interfaces. - if let Some(instance) = - instances.find(|instance| msg.ifname == instance.mvlan.name) - { - if let IpNetwork::V4(addr) = msg.addr { - instance.mvlan.system.addresses.remove(&addr); - instance.update(&interface); - } } } diff --git a/holo-vrrp/tests/packet/mod.rs b/holo-vrrp/tests/packet/mod.rs index a4943d54..b0f81f81 100644 --- a/holo-vrrp/tests/packet/mod.rs +++ b/holo-vrrp/tests/packet/mod.rs @@ -69,7 +69,7 @@ static ETHERNETHDR: LazyLock<(Vec, EthernetHdr)> = LazyLock::new(|| { EthernetHdr { dst_mac: [0x01, 0x00, 0x5e, 0x00, 0x00, 0x12], src_mac: [0x00, 0x00, 0x5e, 0x00, 0x01, 0x33], - ethertype: 0x0800, + ethertype: libc::ETH_P_IP as _, }, ) });