Skip to content

Commit

Permalink
vrrp: reorganize network calls & handle clippy errors
Browse files Browse the repository at this point in the history
The network calls have been modified in this commit.
We have been making the network calls e.g send ARP,
send VRRP advertisement etc directly from
different files. The calls not send a message through
the NetTxPacketMsg. Apart from efficiency, helped in
making too many unnecessary functions async.

Finally worked on cargo clippy recommendations
which had been pending for a while and handled
cargo fmt.

Signed off by: Paul Wekesa <[email protected]>
  • Loading branch information
Paul-weqe committed Aug 2, 2024
1 parent c17e8c2 commit 2631c57
Show file tree
Hide file tree
Showing 19 changed files with 249 additions and 429 deletions.
2 changes: 1 addition & 1 deletion holo-interface/src/ibus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub(crate) fn notify_interface_update(ibus_tx: &IbusSender, iface: &Interface) {
ifindex: iface.ifindex.unwrap_or(0),
mtu: iface.mtu.unwrap_or(0),
flags: iface.flags,
mac_address: iface.mac_address.clone(),
mac_address: iface.mac_address,
});
notify(ibus_tx, msg);
}
Expand Down
1 change: 0 additions & 1 deletion holo-interface/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,6 @@ impl Interfaces {
let iface = &self.arena[iface_idx];
iface.apply_config(ifindex, netlink_handle, self).await;
}

}
None => {
// If the interface does not exist, create a new entry.
Expand Down
19 changes: 12 additions & 7 deletions holo-interface/src/netlink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ async fn process_newlink_msg(
let ifindex = msg.header.index;
let mut ifname = None;
let mut mtu = None;
let mut mac_address: [u8; 6] = [0u8; 6];
let mut mac_address: [u8; 6] = [0u8; 6];

let mut flags = InterfaceFlags::empty();
if msg.header.link_layer_type == ARPHRD_LOOPBACK {
Expand All @@ -59,11 +59,8 @@ async fn process_newlink_msg(
Nla::IfName(nla_ifname) => ifname = Some(nla_ifname),
Nla::Mtu(nla_mtu) => mtu = Some(nla_mtu),
Nla::Address(addr) => {
mac_address = match addr.try_into() {
Ok(a) => a,
Err(e) => [0u8; 6]
};
},
mac_address = addr.try_into().unwrap_or([0u8; 6]);
}
_ => (),
}
}
Expand All @@ -75,7 +72,15 @@ async fn process_newlink_msg(
let ibus_tx = notify.then_some(&master.ibus_tx);
master
.interfaces
.update(ifname, ifindex, mtu, flags, mac_address, &master.netlink_handle, ibus_tx)
.update(
ifname,
ifindex,
mtu,
flags,
mac_address,
&master.netlink_handle,
ibus_tx,
)
.await;
}

Expand Down
3 changes: 2 additions & 1 deletion holo-vrrp/src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ pub enum Debug<'a> {
}

// ===== impl Debug =====

// allow unused for the log method
#[allow(unused)]
impl<'a> Debug<'a> {
// Log debug message using the tracing API.
pub(crate) fn log(&self) {
Expand Down
4 changes: 2 additions & 2 deletions holo-vrrp/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// SPDX-License-Identifier: MIT
//

use std::fmt::{Debug, Display};
use std::fmt::Debug;
use std::net::IpAddr;

use tracing::{warn, warn_span};
Expand All @@ -14,7 +14,7 @@ use tracing::{warn, warn_span};
pub enum Error {
// I/O errors
IoError(IoError),
InterfaceError(String),
InterfaceError(String),

// vrrp-ietf-yang-2018-03-13 specific errors
GlobalError(GlobalError),
Expand Down
216 changes: 144 additions & 72 deletions holo-vrrp/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,17 @@
// SPDX-License-Identifier: MIT
//

use core::task;
use std::borrow::{Borrow, BorrowMut};
use std::net::IpAddr;
use std::time::Duration;

use crate::error::Error;
use crate::instance::{self, Instance, InstanceState, State};
use crate::error::{Error, IoError};
use crate::instance::{Instance, State};
use crate::interface::Interface;
use crate::packet::{DecodeResult, VrrpPacket};
use crate::packet::{ArpPacket, DecodeResult, EthernetFrame, VrrpPacket};
use crate::tasks;
use crate::tasks::messages::output::NetTxPacketMsg;

// 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),
Expand All @@ -28,46 +24,148 @@ pub(crate) fn process_vrrp_packet(
packet: DecodeResult<VrrpPacket>,
) -> 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 action = match get_vrrp_action(interface, pkt) {
Ok(a) => a,
Err(e) => return Err(e)
Err(e) => return Err(e),
};

// execute all collected actions
handle_actions(interface, action);
handle_vrrp_actions(interface, action);
Ok(())
}

#[allow(unused)]
pub(crate) fn process_arp_packet(
interface: &mut Interface,
packet: DecodeResult<ArpPacket>,
) -> 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 instance: Option<&mut Instance> = None;

'outer: for (_vr, inst) in interface.instances.iter_mut() {
for addr in inst.config.virtual_addresses.clone() {
let addr_arr = addr.ip().octets();
if addr_arr == pkt.target_proto_address {
instance = Some(inst);
break 'outer;
}
}
}

let 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,
};
let msg = NetTxPacketMsg::Arp {
name: interface.name.clone(),
eth_frame,
arp_packet: arp_response_pkt,
};
interface.net.net_tx_packetp.send(msg);
}
}
}

Ok(())
}

// gets all the actions that are required to be done bacsed on the interface
// configs and incoming packet
fn get_action(interface: &mut Interface, packet: VrrpPacket) -> Result<Action, Error> {
fn get_vrrp_action(
interface: &mut Interface,
packet: VrrpPacket,
) -> Result<VrrpAction, Error> {
// Handle missing instance
let instance = match interface.instances.get_mut(&packet.vrid) {
Some(inst) => inst,
None => return Err(
Error::InterfaceError(String::from("unable to fetch VRRP instance from interface"))
),
Some(instance) => instance,
None => {
return Err(Error::InterfaceError(String::from(
"unable to fetch VRRP instance from interface",
)))
}
};

// Update statistics
instance.state.statistics.adv_rcvd += 1;

// 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 => Ok(VrrpAction::Initialize(packet)),
State::Backup => Ok(VrrpAction::Backup(packet)),
State::Master => Ok(VrrpAction::Master(packet)),
}
}

}

fn handle_actions(interface: &mut Interface, action: Action) {
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);
Expand All @@ -77,95 +175,69 @@ fn handle_actions(interface: &mut Interface, action: Action) {
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) {
if pkt.priority == 0 {
let duration = Duration::from_secs_f32(instance.state.skew_time);
let duration =
Duration::from_secs_f32(instance.state.skew_time);
tasks::set_master_down_timer(interface, vrid, duration);
}
else {
} else {
// RFC 3768 Section 6.4.2
// If Preempt Mode if False, or if the priority in the ADVERTISEMENT is
// greater than or equal to local priority then:
if (instance.config.preempt == false)
|| (pkt.priority > instance.config.priority){
instance.reset_timer();
if !instance.config.preempt
|| (pkt.priority > instance.config.priority)
{
instance.reset_timer();
}

// drop the packet
else {
return
}
}
}

}

Action::Master(pkt) => {
VrrpAction::Master(pkt) => {
let vrid = pkt.vrid;
let mut send_ad = false;
if let Some(instance) = interface.instances.get_mut(&vrid) {

if pkt.priority == 0 {
send_ad = true;
send_ad = true;


instance.reset_timer();
}

else if (pkt.priority > instance.config.priority)
} else if pkt.priority > instance.config.priority
// TODO: in RFC 3768 page 18, we have a requirement, where If the priority
// in the ADVERTISEMENT is equal to the local Priority and the primary IP
// Address of the sender is greater than the local primary IP Address, then we
// proceed.
// proceed.
//
// We can get our primary IP address, but purely from the VRRP packet we cannot
// get our senders primary.
//
{
interface.change_state(vrid, State::Backup);
}

else {
return
} else {
return;
}
}

if send_ad {
interface.send_vrrp_advert(vrid);
}

}
}
}

// ====== 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
// ====== Handle Master Down Timer =====
// RFC 3768 : Section 6.4.2
// 'If the Master_Down_timer fires'
pub(crate) fn handle_master_down_timer(
interface: &mut Interface,
vrid: u8
) -> Result<(), Error>{
interface: &mut Interface,
vrid: u8,
) -> Result<(), Error> {
interface.send_vrrp_advert(vrid);
interface.send_gratuitous_arp(vrid);

let instance: &mut Instance = match interface.instances.get_mut(&vrid) {
Some(i) => i,
None => {
return Err(Error::InterfaceError(String::from(
"unable to get VRRP instance from interface"
)));
}
};
interface.change_state(vrid, State::Master);

Ok(())
}


Loading

0 comments on commit 2631c57

Please sign in to comment.