diff --git a/holo-vrrp/src/instance.rs b/holo-vrrp/src/instance.rs index e585ec52..4503c4fc 100644 --- a/holo-vrrp/src/instance.rs +++ b/holo-vrrp/src/instance.rs @@ -51,6 +51,7 @@ pub struct InstanceState { pub timer: VrrpTimer, pub last_adv_src: Option, pub statistics: Statistics, + pub is_owner: bool, } #[derive(Debug)] @@ -165,7 +166,8 @@ impl Instance { match InstanceNet::new(interface, &self.mvlan) { Ok(net) => { self.net = Some(net); - if self.config.priority == 255 { + self.state.is_owner = self.check_is_owner(interface.system); + if self.config.priority == 255 || self.state.is_owner { let src_ip = interface.system.addresses.first().unwrap().ip(); self.send_vrrp_advertisement(src_ip); @@ -314,11 +316,18 @@ impl Instance { ip_addresses.push(addr.ip()); } + // RFC 3768 -> 5.3.4. Priority + let priority = if self.state.is_owner { + 255 + } else { + self.config.priority + }; + let mut packet = VrrpHdr { version: 2, hdr_type: 1, vrid: self.vrid, - priority: self.config.priority, + priority: priority, count_ip: self.config.virtual_addresses.len() as u8, auth_type: 0, adver_int: self.config.advertise_interval, @@ -403,6 +412,16 @@ impl Instance { let _ = net.net_tx_packetp.send(msg); } } + + /// an instance is an owner if the ip address of the parent interface is + /// part of the virutal addresses held by the instance. + pub(crate) fn check_is_owner(&self, interface_sys: &InterfaceSys) -> bool { + self.config + .virtual_addresses + .iter() + .any(|addr| interface_sys.addresses.contains(addr)); + false + } } impl Drop for Instance { diff --git a/holo-vrrp/src/northbound/configuration.rs b/holo-vrrp/src/northbound/configuration.rs index bd853b1e..d94f05ac 100644 --- a/holo-vrrp/src/northbound/configuration.rs +++ b/holo-vrrp/src/northbound/configuration.rs @@ -222,6 +222,10 @@ impl Provider for Interface { ); instance.timer_set(&interface); } + + // owner status may change when virtual address is added + instance.state.is_owner = + instance.check_is_owner(&interface.system); } Event::VirtualAddressDelete { vrid, addr } => { let (interface, instance) = self.get_instance(vrid).unwrap(); @@ -234,6 +238,9 @@ impl Provider for Interface { ); instance.timer_set(&interface); } + // owner status may change when virtual address is added + instance.state.is_owner = + instance.check_is_owner(&interface.system); } Event::ResetTimer { vrid } => { let (_, instance) = self.get_instance(vrid).unwrap(); diff --git a/holo-vrrp/src/northbound/state.rs b/holo-vrrp/src/northbound/state.rs index e9606327..92988791 100644 --- a/holo-vrrp/src/northbound/state.rs +++ b/holo-vrrp/src/northbound/state.rs @@ -47,7 +47,7 @@ fn load_callbacks() -> Callbacks { vrid: *vrid, state: Some(instance.state.state.to_yang()), // TODO - is_owner: None, + is_owner: Some(instance.state.is_owner), 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(),