diff --git a/holo-vrrp/src/events.rs b/holo-vrrp/src/events.rs index ac2a517d..1158d52f 100644 --- a/holo-vrrp/src/events.rs +++ b/holo-vrrp/src/events.rs @@ -7,16 +7,14 @@ use std::borrow::{Borrow, BorrowMut}; use std::net::IpAddr; use std::time::Duration; -use crate::error::Error; +use crate::error::{Error, IoError}; use crate::instance::{self, Instance, InstanceState, State}; use crate::interface::Interface; -use crate::packet::{DecodeResult, VrrpPacket}; -use crate::tasks; +use crate::packet::{ArpPacket, DecodeResult, EthernetFrame, VrrpPacket}; +use crate::{network, tasks}; // To collect actions to be executed later -enum Action { - // described in 6.4.1 part 1. Is when the instance owns the - // IP addresses associated with the virtual router +enum VrrpAction { Initialize(VrrpPacket), Backup(VrrpPacket), Master(VrrpPacket), @@ -28,28 +26,123 @@ pub(crate) fn process_vrrp_packet( packet: DecodeResult, ) -> Result<(), Error> { // Handle packet decoding errors - let pkt = packet.unwrap(); + let pkt = match packet { + Ok(pkt) => pkt, + Err(e) => return Err(Error::IoError( + IoError::RecvError(std::io::Error::new( + std::io::ErrorKind::Other, "problem receiving VRRP packet") + ) + )) + }; // collect the actions that are required - let mut action = match get_action(interface, pkt) { + let mut action = match get_vrrp_action(interface, pkt) { Ok(a) => a, Err(e) => return Err(e), }; // execute all collected actions - handle_actions(interface, action); + handle_vrrp_actions(interface, action); + Ok(()) +} + +pub(crate) async fn process_arp_packet( + interface: &mut Interface, + packet: DecodeResult +) -> Result<(), Error> { + // Handle packet decoding errors + let pkt = match packet { + Ok(pkt) => pkt, + Err(e) => return Err(Error::IoError( + IoError::RecvError(std::io::Error::new( + std::io::ErrorKind::Other, "problem receiving ARP packet") + ) + )) + + }; + + let mut vrid: Option = None; + let mut instance: Option<&mut Instance> = None; + + 'outer: for (vr, inst) in interface.instances.iter_mut() { + 'inner: for addr in inst.config.virtual_addresses.clone() { + let addr_arr = addr.ip().octets(); + if addr_arr == pkt.target_proto_address { + instance = Some(inst); + vrid = Some(*vr); + break 'inner + } + } + } + + let mut instance = match instance { + Some(i) => i, + // the target ip address in the ARP request is for none of the instances + None => return Ok(()) + }; + + match instance.state.state { + State::Initialize => {} + State::Backup => { + // ======================================================== + // RFC 3768 Section 6.4.2. Backup + // While in this state, a VRRP router MUST do the following + // ======================================================== + + // MUST NOT respond to ARP requests for the IP address(es) associated with the virutal + // router + } + State::Master => { + + // ======================================================== + // RFC 3768 Section 6.4.3. Master + // While in the {Maste} state the router functions as the forwarding router for the IP + // address(es) associated with the virtual router. + // While in this state, a VRRP router MUST do the following: + // ======================================================== + + + // MUST respond to ARP requests for the IP address(es) associated with the virtual + // router + + if pkt.operation == 1 { // if is ARP request + // build ARP response packet. + let mut arp_response_pkt = pkt.clone(); + arp_response_pkt.operation = 2; // reply operation + arp_response_pkt.sender_hw_address = pkt.target_hw_address; + arp_response_pkt.target_hw_address = pkt.sender_hw_address; + arp_response_pkt.sender_proto_address = pkt.target_proto_address; + arp_response_pkt.target_proto_address = pkt.sender_proto_address; + + // build ethernet packet + let eth_frame = EthernetFrame { + ethertype: 0x806, + src_mac: interface.system.mac_address, + dst_mac: pkt.sender_hw_address, + }; + + network::send_packet_arp( + &interface.net.socket_vrrp, + &interface.name, + eth_frame, + arp_response_pkt + ).await; + } + } + } + Ok(()) } // gets all the actions that are required to be done bacsed on the interface // configs and incoming packet -fn get_action( +fn get_vrrp_action( interface: &mut Interface, packet: VrrpPacket, -) -> Result { +) -> Result { // Handle missing instance let instance = match interface.instances.get_mut(&packet.vrid) { - Some(inst) => inst, + Some(instance) => instance, None => { return Err(Error::InterfaceError(String::from( "unable to fetch VRRP instance from interface", @@ -62,25 +155,25 @@ fn get_action( // Handle the current state match instance.state.state { - State::Initialize => return Ok(Action::Initialize(packet)), - State::Backup => return Ok(Action::Backup(packet)), - State::Master => return Ok(Action::Master(packet)), + State::Initialize => return Ok(VrrpAction::Initialize(packet)), + State::Backup => return Ok(VrrpAction::Backup(packet)), + State::Master => return Ok(VrrpAction::Master(packet)), } } -fn handle_actions(interface: &mut Interface, action: Action) { +async fn handle_vrrp_actions(interface: &mut Interface, action: VrrpAction) { match action { - Action::Initialize(pkt) => { + VrrpAction::Initialize(pkt) => { let vrid = pkt.vrid; if vrid == 255 { interface.send_vrrp_advert(vrid); - interface.send_gratuitous_arp(vrid); + interface.send_gratuitous_arp(vrid).await; interface.change_state(vrid, State::Master); } else { interface.change_state(vrid, State::Backup); } } - Action::Backup(pkt) => { + VrrpAction::Backup(pkt) => { let vrid = pkt.vrid; if let Some(instance) = interface.instances.get_mut(&vrid) { @@ -105,7 +198,7 @@ fn handle_actions(interface: &mut Interface, action: Action) { } } - Action::Master(pkt) => { + VrrpAction::Master(pkt) => { let vrid = pkt.vrid; let mut send_ad = false; if let Some(instance) = interface.instances.get_mut(&vrid) { @@ -136,11 +229,9 @@ fn handle_actions(interface: &mut Interface, action: Action) { } } + + // ====== Handle Master Down Timer ===== -// This is called when the master down timer fires. -// Basically When the Instance master down timer -// ticks down. -// // RFC 3768 : Section 6.4.2 // 'If the Master_Down_timer fires' pub(crate) fn handle_master_down_timer( diff --git a/holo-vrrp/src/interface.rs b/holo-vrrp/src/interface.rs index a48645ef..035c4eb9 100644 --- a/holo-vrrp/src/interface.rs +++ b/holo-vrrp/src/interface.rs @@ -95,9 +95,9 @@ impl Interface { } } - pub(crate) fn send_vrrp_advert(&self, vrid: u8) { + pub(crate) async fn send_vrrp_advert(&self, vrid: u8) { if let Some(instance) = self.instances.get(&vrid) { - // send advertisement then reset the timer. + let mut ip_addresses: Vec = vec![]; for addr in &instance.config.virtual_addresses { ip_addresses.push(addr.ip()); @@ -117,11 +117,11 @@ impl Interface { auth_data2: 0, }; packet.generate_checksum(); - network::send_packet_vrrp(&self.net.socket_vrrp, packet); + network::send_packet_vrrp(&self.net.socket_vrrp, packet).await; } } - pub(crate) fn send_gratuitous_arp(&self, vrid: u8) { + pub(crate) async fn send_gratuitous_arp(&self, vrid: u8) { let ifname = &self.name; if let Some(instance) = self.instances.get(&vrid) { @@ -155,10 +155,11 @@ impl Interface { &self.name, eth_frame, arp_packet, - ); + ).await; } } } + } #[async_trait] diff --git a/holo-vrrp/src/network.rs b/holo-vrrp/src/network.rs index 396129db..1e2a3dbf 100644 --- a/holo-vrrp/src/network.rs +++ b/holo-vrrp/src/network.rs @@ -76,8 +76,8 @@ pub(crate) async fn send_packet_vrrp( .map_err(IoError::SendError) } -//#[cfg(not(feature = "testing"))] -pub fn send_packet_arp( +#[cfg(not(feature = "testing"))] +pub async fn send_packet_arp( sock: &AsyncFd, ifname: &str, eth_frame: EthernetFrame,