diff --git a/holo-bgp/src/events.rs b/holo-bgp/src/events.rs index 116775f1..76b033f7 100644 --- a/holo-bgp/src/events.rs +++ b/holo-bgp/src/events.rs @@ -718,7 +718,7 @@ where let mut nbr_reach = reach.clone(); nbr_unreach.extend( nbr_reach - .extract_if(|(_, route)| !nbr.distribute_filter(route)) + .extract_if(.., |(_, route)| !nbr.distribute_filter(route)) .map(|(prefix, _)| prefix), ); diff --git a/holo-northbound/src/configuration.rs b/holo-northbound/src/configuration.rs index c77b5c1f..963f1cf8 100644 --- a/holo-northbound/src/configuration.rs +++ b/holo-northbound/src/configuration.rs @@ -681,7 +681,7 @@ where // Move to a separate vector the changes that need to be relayed. let callbacks = P::callbacks().unwrap(); let relayed_changes = changes - .extract_if(|(cb_key, _)| !callbacks.0.contains_key(cb_key)) + .extract_if(.., |(cb_key, _)| !callbacks.0.contains_key(cb_key)) .collect(); // Process local changes. diff --git a/holo-vrrp/src/events.rs b/holo-vrrp/src/events.rs index 9847ec28..3170e7d0 100644 --- a/holo-vrrp/src/events.rs +++ b/holo-vrrp/src/events.rs @@ -107,7 +107,8 @@ pub(crate) fn process_vrrp_packet( fsm::State::Master => { let primary_addr = interface.system.addresses.first().unwrap().ip(); if packet.priority == 0 { - instance.send_vrrp_advertisement(primary_addr); + instance + .send_vrrp_advertisement(primary_addr, interface.system); instance.timer_reset(); } else if packet.priority > instance.config.priority || (packet.priority == instance.config.priority @@ -142,7 +143,7 @@ pub(crate) fn handle_master_down_timer( }; // RFC 3768: Section 6.4.2 ("If the Master_Down_timer fires") - instance.send_vrrp_advertisement(src_ip); + instance.send_vrrp_advertisement(src_ip, interface.system); instance.send_gratuitous_arp(); instance.change_state( &interface, diff --git a/holo-vrrp/src/instance.rs b/holo-vrrp/src/instance.rs index e585ec52..2d30043d 100644 --- a/holo-vrrp/src/instance.rs +++ b/holo-vrrp/src/instance.rs @@ -165,10 +165,13 @@ impl Instance { match InstanceNet::new(interface, &self.mvlan) { Ok(net) => { self.net = Some(net); - if self.config.priority == 255 { + let iface_system = &interface.system; + if self.config.priority == 255 + || self.check_is_owner(iface_system) + { let src_ip = interface.system.addresses.first().unwrap().ip(); - self.send_vrrp_advertisement(src_ip); + self.send_vrrp_advertisement(src_ip, iface_system); self.send_gratuitous_arp(); self.change_state( interface, @@ -285,6 +288,7 @@ impl Instance { let task = tasks::advertisement_interval( self, src_ip, + interface.system, &net.net_tx_packetp, ); self.state.timer = VrrpTimer::AdvTimer(task); @@ -308,17 +312,27 @@ impl Instance { } } - pub(crate) fn generate_vrrp_packet(&self) -> VrrpHdr { + pub(crate) fn generate_vrrp_packet( + &self, + iface_system: &InterfaceSys, + ) -> VrrpHdr { let mut ip_addresses: Vec = vec![]; for addr in &self.config.virtual_addresses { ip_addresses.push(addr.ip()); } + // RFC 3768 -> 5.3.4. Priority + let priority = if self.check_is_owner(iface_system) { + 255 + } else { + self.config.priority + }; + let mut packet = VrrpHdr { version: 2, hdr_type: 1, vrid: self.vrid, - priority: self.config.priority, + priority, count_ip: self.config.virtual_addresses.len() as u8, auth_type: 0, adver_int: self.config.advertise_interval, @@ -360,10 +374,14 @@ impl Instance { } } - pub(crate) fn send_vrrp_advertisement(&mut self, src_ip: Ipv4Addr) { + pub(crate) fn send_vrrp_advertisement( + &mut self, + src_ip: Ipv4Addr, + iface_system: &InterfaceSys, + ) { let packet = VrrpPacket { ip: self.generate_ipv4_packet(src_ip), - vrrp: self.generate_vrrp_packet(), + vrrp: self.generate_vrrp_packet(iface_system), }; let msg = NetTxPacketMsg::Vrrp { packet }; let net = self.net.as_ref().unwrap(); @@ -403,6 +421,15 @@ impl Instance { let _ = net.net_tx_packetp.send(msg); } } + + /// An instance is an owner if all its virtual addresses are + /// also addresses part of the parent interface's IP addresses + pub(crate) fn check_is_owner(&self, interface_sys: &InterfaceSys) -> bool { + self.config + .virtual_addresses + .iter() + .all(|addr| interface_sys.addresses.contains(addr)) + } } impl Drop for Instance { diff --git a/holo-vrrp/src/northbound/state.rs b/holo-vrrp/src/northbound/state.rs index e9606327..53904ed8 100644 --- a/holo-vrrp/src/northbound/state.rs +++ b/holo-vrrp/src/northbound/state.rs @@ -40,14 +40,13 @@ fn load_callbacks() -> Callbacks { let iter = interface.instances.iter().map(|(vrid, instance)| ListEntry::Instance(*vrid, instance)); Some(Box::new(iter)) }) - .get_object(|_interface, args| { + .get_object(|interface, args| { use interfaces::interface::ipv4::vrrp::vrrp_instance::VrrpInstance; let (vrid, instance) = args.list_entry.as_instance().unwrap(); Box::new(VrrpInstance { vrid: *vrid, state: Some(instance.state.state.to_yang()), - // TODO - is_owner: None, + is_owner: Some(instance.check_is_owner(&interface.system)), last_adv_source: instance.state.last_adv_src.map(std::convert::Into::into).map(Cow::Owned).ignore_in_testing(), up_datetime: instance.state.up_time.as_ref().map(Cow::Borrowed).ignore_in_testing(), master_down_interval: instance.state.timer.as_master_down_timer().map(|task| task.remaining().as_millis() as u32 / 10).ignore_in_testing(), diff --git a/holo-vrrp/src/tasks.rs b/holo-vrrp/src/tasks.rs index fdc8aed4..27ce5908 100644 --- a/holo-vrrp/src/tasks.rs +++ b/holo-vrrp/src/tasks.rs @@ -20,6 +20,7 @@ use messages::output::NetTxPacketMsg; use tracing::{debug_span, Instrument}; use crate::instance::Instance; +use crate::interface::InterfaceSys; use crate::network; use crate::packet::VrrpPacket; @@ -203,13 +204,14 @@ pub(crate) fn master_down_timer( pub(crate) fn advertisement_interval( instance: &Instance, src_ip: Ipv4Addr, + iface_system: &InterfaceSys, net_tx_packetp: &UnboundedSender, ) -> IntervalTask { #[cfg(not(feature = "testing"))] { let packet = VrrpPacket { ip: instance.generate_ipv4_packet(src_ip), - vrrp: instance.generate_vrrp_packet(), + vrrp: instance.generate_vrrp_packet(iface_system), }; let adv_sent = instance.state.statistics.adv_sent.clone(); let net_tx_packetp = net_tx_packetp.clone();