Skip to content

Commit

Permalink
vrrp: restructure
Browse files Browse the repository at this point in the history
- centralize constants to consts.rs.
- rename arpPacket to arpHeader.
- remove the use of unsafe when sending arp packet.
- Have ifindex defined outside the send_packet_*
    functions
- get rid of Arpframe

Signed-off-by: Paul Wekesa <paul1tw1@gmail.com>
  • Loading branch information
Paul-weqe committed Nov 4, 2024
1 parent 62dec6e commit b303e33
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 134 deletions.
32 changes: 32 additions & 0 deletions holo-vrrp/src/consts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// 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::net::Ipv4Addr;

// ==== VRRP ===
// valid vrrp versions
pub const VALID_VRRP_VERSIONS: [u8; 1] = [2];
pub const VRRP_PROTO_NUMBER: i32 = 112;
// maximum size of vrrp header
pub const VRRP_HDR_MAX: usize = 96;
// minimum size of vrrp header.
pub const VRRP_HDR_MIN: usize = 16;
// maximum size of IP + vrrp header.
// For when we use the layer 2 socket
pub const IP_VRRP_HDR_MAX: usize = 130;
pub const VRRP_MULTICAST_ADDRESS: Ipv4Addr = Ipv4Addr::new(224, 0, 0, 18);

// max size of ip + vrrp header maximum
// 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 = 0x806_u16;

// ==== IP ====
pub const IP_HDR_MIN: usize = 20;
3 changes: 1 addition & 2 deletions holo-vrrp/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@ use std::time::Duration;

use tracing::{debug, debug_span};

use crate::consts::VALID_VRRP_VERSIONS;
use crate::error::{Error, IoError};
use crate::instance::{Event, MasterReason, State};
use crate::interface::Interface;
use crate::packet::{DecodeResult, VrrpHdr};
use crate::tasks;

const VALID_VRRP_VERSIONS: [u8; 1] = [2];

// To collect actions to be executed later
enum VrrpAction {
Initialize(Ipv4Addr, VrrpHdr),
Expand Down
13 changes: 7 additions & 6 deletions holo-vrrp/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ use std::time::Duration;
use chrono::{DateTime, Utc};
use holo_utils::task::{IntervalTask, TimeoutTask};

use crate::interface::{MacVlanInterface, VRRP_PROTO_NUMBER};
use crate::consts::VRRP_PROTO_NUMBER;
use crate::interface::MacVlanInterface;
use crate::northbound::configuration::InstanceCfg;
use crate::packet::{ArpPacket, EthernetHdr, Ipv4Hdr, VrrpHdr};
use crate::packet::{ArpHdr, EthernetHdr, Ipv4Hdr, VrrpHdr};
use crate::tasks::messages::output::NetTxPacketMsg;

#[derive(Debug)]
Expand Down Expand Up @@ -205,7 +206,7 @@ impl Instance {
// send a gratuitous for each of the
// virutal IP addresses
for addr in self.config.virtual_addresses.clone() {
let arp_packet = ArpPacket {
let arp_hdr = ArpHdr {
hw_type: 1,
// for Ipv4
proto_type: 0x0800,
Expand All @@ -228,9 +229,9 @@ impl Instance {
};

let msg = NetTxPacketMsg::Arp {
name: self.mac_vlan.name.clone(),
eth_frame: eth_hdr,
arp_packet,
ifindex: self.mac_vlan.system.ifindex.unwrap(),
eth_hdr,
arp_hdr,
};

if let Some(net) = &self.mac_vlan.net {
Expand Down
6 changes: 1 addition & 5 deletions holo-vrrp/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
//

use std::collections::{BTreeMap, BTreeSet};
use std::net::Ipv4Addr;
use std::sync::Arc;

use async_trait::async_trait;
Expand All @@ -34,9 +33,6 @@ use crate::tasks::messages::output::NetTxPacketMsg;
use crate::tasks::messages::{ProtocolInputMsg, ProtocolOutputMsg};
use crate::{events, network, southbound, tasks};

pub const VRRP_PROTO_NUMBER: i32 = 112;
pub const VRRP_MULTICAST_ADDRESS: Ipv4Addr = Ipv4Addr::new(224, 0, 0, 18);

#[derive(Debug)]
pub struct Interface {
// Interface name.
Expand Down Expand Up @@ -257,7 +253,7 @@ impl Interface {
};

let msg = NetTxPacketMsg::Vrrp {
ifname: instance.mac_vlan.name.clone(),
ifindex: instance.mac_vlan.system.ifindex.unwrap(),
pkt,
};
if let Some(net) = &instance.mac_vlan.net {
Expand Down
1 change: 1 addition & 0 deletions holo-vrrp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
)]
#![feature(let_chains)]

pub mod consts;
pub mod debug;
pub mod error;
pub mod events;
Expand Down
93 changes: 36 additions & 57 deletions holo-vrrp/src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,24 @@
// See: https://nlnet.nl/NGI0
//

use std::ffi::CString;
use std::os::fd::AsRawFd;
use std::sync::Arc;

use bytes::BufMut;
use holo_utils::socket::{AsyncFd, Socket};
use holo_utils::{capabilities, Sender, UnboundedReceiver};
use libc::ETH_P_ARP;
use nix::sys::socket;
use libc::{AF_PACKET, ETH_P_ARP};
use nix::sys::socket::{self, sendto, LinkAddr, MsgFlags, SockaddrLike};
use socket2::{Domain, Protocol, Type};
use tokio::sync::mpsc::error::SendError;

use crate::consts::{VRRP_HDR_MAX, VRRP_MULTICAST_ADDRESS, VRRP_PROTO_NUMBER};
use crate::error::IoError;
use crate::interface::{Interface, VRRP_MULTICAST_ADDRESS, VRRP_PROTO_NUMBER};
use crate::packet::{ArpPacket, EthernetHdr, Ipv4Hdr, VrrpHdr, VrrpPacket};
use crate::interface::Interface;
use crate::packet::{ArpHdr, EthernetHdr, Ipv4Hdr, VrrpHdr, VrrpPacket};
use crate::tasks::messages::input::VrrpNetRxPacketMsg;
use crate::tasks::messages::output::NetTxPacketMsg;

pub const MAX_VRRP_HDR_LENGTH: usize = 96;

pub fn socket_vrrp_tx(
interface: &Interface,
vrid: u8,
Expand Down Expand Up @@ -109,12 +108,12 @@ pub fn socket_arp(ifname: &str) -> Result<Socket, std::io::Error> {
#[cfg(not(feature = "testing"))]
pub(crate) async fn send_packet_vrrp(
sock: &AsyncFd<Socket>,
ifname: &str,
ifindex: u32,
pkt: VrrpPacket,
) -> Result<usize, IoError> {
let c_ifname = CString::new(ifname).unwrap();
use crate::consts::IP_VRRP_HDR_MAX;

unsafe {
let ifindex = libc::if_nametoindex(c_ifname.as_ptr());
let mut sa = libc::sockaddr_ll {
sll_family: libc::AF_INET as u16,
sll_protocol: (VRRP_PROTO_NUMBER as u16).to_be(),
Expand All @@ -134,7 +133,7 @@ pub(crate) async fn send_packet_vrrp(
match libc::sendto(
sock.as_raw_fd(),
buf.as_ptr().cast(),
std::cmp::min(buf.len(), 130),
std::cmp::min(buf.len(), IP_VRRP_HDR_MAX),
0,
ptr_sockaddr,
std::mem::size_of_val(&sa) as u32,
Expand All @@ -148,53 +147,33 @@ pub(crate) async fn send_packet_vrrp(
#[cfg(not(feature = "testing"))]
pub async fn send_packet_arp(
sock: &AsyncFd<Socket>,
ifname: &str,
eth_frame: EthernetHdr,
arp_packet: ArpPacket,
ifindex: u32,
eth_hdr: EthernetHdr,
arp_hdr: ArpHdr,
) -> Result<usize, IoError> {
use std::ffi::CString;

use libc::{c_void, sendto, sockaddr, sockaddr_ll, AF_INET};
use crate::consts::ARP_PROTOCOL_NUMBER;

use crate::packet::ARPframe;
let mut arpframe = ARPframe::new(eth_frame, arp_packet);
let mut buf = eth_hdr.encode();
buf.put(arp_hdr.encode());

let c_ifname = match CString::new(ifname) {
Ok(c_ifname) => c_ifname,
Err(err) => {
return Err(IoError::SocketError(std::io::Error::new(
std::io::ErrorKind::NotFound,
err,
)))
}
};
let ifindex = unsafe { libc::if_nametoindex(c_ifname.as_ptr()) };

let mut sa = sockaddr_ll {
sll_family: AF_INET as u16,
sll_protocol: 0x806_u16.to_be(),
let mut sll = libc::sockaddr_ll {
sll_family: AF_PACKET as u16,
sll_protocol: ARP_PROTOCOL_NUMBER.to_be(),
sll_ifindex: ifindex as i32,
sll_hatype: 0,
sll_pkttype: 0,
sll_halen: 0,
sll_halen: 6,
sll_addr: [0; 8],
};

unsafe {
let ptr_sockaddr =
std::mem::transmute::<*mut sockaddr_ll, *mut sockaddr>(&mut sa);

match sendto(
sock.as_raw_fd(),
&mut arpframe as *mut _ as *const c_void,
std::mem::size_of_val(&arpframe),
0,
ptr_sockaddr,
std::mem::size_of_val(&sa) as u32,
) {
-1 => Err(IoError::SendError(std::io::Error::last_os_error())),
fd => Ok(fd as usize),
}
sll.sll_addr[..6].copy_from_slice(&eth_hdr.dst_mac);
let sll_len = size_of_val(&sll) as libc::socklen_t;
let saddr = unsafe {
LinkAddr::from_raw(&sll as *const _ as *const _, Some(sll_len))
}
.unwrap();
match sendto(sock.as_raw_fd(), &buf, &saddr, MsgFlags::empty()) {
Ok(res) => Ok(res),
Err(errno) => Err(IoError::SendError(errno.into())),
}
}

Expand All @@ -220,20 +199,20 @@ pub(crate) async fn write_loop(
) {
while let Some(msg) = net_tx_packetc.recv().await {
match msg {
NetTxPacketMsg::Vrrp { ifname, pkt } => {
NetTxPacketMsg::Vrrp { ifindex, pkt } => {
if let Err(error) =
send_packet_vrrp(&socket_vrrp, &ifname, pkt).await
send_packet_vrrp(&socket_vrrp, ifindex, pkt).await
{
error.log();
}
}
NetTxPacketMsg::Arp {
name,
eth_frame,
arp_packet,
ifindex,
eth_hdr,
arp_hdr,
} => {
if let Err(error) =
send_packet_arp(&socket_arp, &name, eth_frame, arp_packet)
send_packet_arp(&socket_arp, ifindex, eth_hdr, arp_hdr)
.await
{
error.log();
Expand All @@ -248,7 +227,7 @@ pub(crate) async fn vrrp_read_loop(
socket_vrrp: Arc<AsyncFd<Socket>>,
vrrp_net_packet_rxp: Sender<VrrpNetRxPacketMsg>,
) -> Result<(), SendError<VrrpNetRxPacketMsg>> {
let mut buf = [0u8; MAX_VRRP_HDR_LENGTH];
let mut buf = [0u8; VRRP_HDR_MAX];
loop {
match socket_vrrp
.async_io(tokio::io::Interest::READABLE, |sock| {
Expand Down
Loading

0 comments on commit b303e33

Please sign in to comment.