Skip to content

Commit

Permalink
vrrp: packet reformating & fixes on vrrp rx socket
Browse files Browse the repository at this point in the history
Make sure that the transmission of VRRP packets
is done with the correct virtual MAC as source
and correct multicast destination MAC.

Also making sure the vrrp sockets can receive an
advertisement.
  • Loading branch information
Paul-weqe committed Oct 10, 2024
1 parent 6c849b3 commit 2cca732
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 55 deletions.
8 changes: 2 additions & 6 deletions holo-vrrp/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::time::Duration;
use chrono::{DateTime, Utc};
use holo_utils::task::{IntervalTask, TimeoutTask};

use crate::interface::MacVlanInterface;
use crate::interface::{MacVlanInterface, VRRP_PROTO_NUMBER};
use crate::northbound::configuration::InstanceCfg;
use crate::packet::{ArpPacket, EthernetHdr, Ipv4Packet, VrrpHdr};
use crate::tasks::messages::output::NetTxPacketMsg;
Expand Down Expand Up @@ -186,7 +186,7 @@ impl Instance {
flags: 0x00,
offset: 0x00,
ttl: 255,
protocol: 112,
protocol: VRRP_PROTO_NUMBER as u8,
checksum: 0x00,
src_address,
dst_address: Ipv4Addr::new(224, 0, 0, 18),
Expand All @@ -195,10 +195,6 @@ impl Instance {
}
}

pub(crate) fn advert_ether_frame(&self) -> EthernetHdr {
EthernetHdr::vrrp(self.vrid)
}

pub(crate) fn send_gratuitous_arp(&self) {
// send a gratuitous for each of the
// virutal IP addresses
Expand Down
15 changes: 7 additions & 8 deletions holo-vrrp/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
//

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

use async_trait::async_trait;
use bytes::{BufMut, BytesMut};
use holo_protocol::{
InstanceChannelsTx, InstanceShared, MessageReceiver, ProtocolInstance,
};
Expand All @@ -31,6 +31,9 @@ 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 @@ -136,7 +139,7 @@ impl Interface {

self.instances.remove(&vrid);
if let Some(ifindex) = mvlan_ifindex {
southbound::delete_iface(ifindex, &self.tx.ibus);
southbound::mvlan_delete(ifindex, &self.tx.ibus);
}
}

Expand Down Expand Up @@ -232,13 +235,9 @@ impl Interface {
// ...and confirm if the instance's parent Interface has an IP address
&& let Some(addr) = self.system.addresses.first()
{
let mut buf = BytesMut::new();

let eth_hdr = instance.advert_ether_frame();
let ip_hdr = instance.adver_ipv4_pkt(addr.ip());
let vrrp_hdr = instance.adver_vrrp_pkt();
let pkt = VrrpPacket {
eth: eth_hdr,
ip: ip_hdr,
vrrp: vrrp_hdr,
};
Expand All @@ -259,7 +258,7 @@ impl Interface {

// creates the MvlanInterfaceNet for the instance of said
// vrid. Must be done here to get some interface specifics.
pub(crate) fn create_mvlan_net(&mut self, vrid: u8) {
pub(crate) fn macvlan_create(&mut self, vrid: u8) {
let net = MvlanInterfaceNet::new(self, vrid)
.expect("Failed to intialize VRRP tasks");

Expand Down Expand Up @@ -363,7 +362,7 @@ impl MvlanInterfaceNet {
let ifname = &instance.mac_vlan.name;
let instance_channels_tx = &parent_iface.tx;

let socket_vrrp_rx = network::socket_vrrp_rx(ifname)
let socket_vrrp_rx = network::socket_vrrp_rx(parent_iface)
.map_err(IoError::SocketError)
.and_then(|socket| {
AsyncFd::new(socket).map_err(IoError::SocketError)
Expand Down
62 changes: 33 additions & 29 deletions holo-vrrp/src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,19 @@
//

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

use holo_utils::socket::{AsyncFd, Socket};
use holo_utils::{capabilities, Sender, UnboundedReceiver};
use libc::{if_nametoindex, AF_PACKET, ETH_P_ARP, ETH_P_IP};
use libc::ETH_P_ARP;
use nix::sys::socket;
use socket2::{Domain, InterfaceIndexOrAddress, Protocol, Type};
use socket2::{Domain, Protocol, Type};
use tokio::sync::mpsc::error::SendError;
use tracing::{debug, debug_span};

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

Expand All @@ -31,20 +28,27 @@ pub fn socket_vrrp_tx(
#[cfg(not(feature = "testing"))]
{
let instance = interface.instances.get(&vrid).unwrap();

let sock = capabilities::raise(|| {
Socket::new(Domain::PACKET, Type::RAW, Some(Protocol::from(112)))
Socket::new(
Domain::IPV4,
Type::RAW,
Some(Protocol::from(VRRP_PROTO_NUMBER)),
)
})?;

capabilities::raise(|| sock.set_nonblocking(true))?;
if let Some(addr) = instance.mac_vlan.system.addresses.first() {
capabilities::raise(|| sock.set_multicast_if_v4(&addr.ip()))?;
}

capabilities::raise(|| sock.set_header_included(true))?;

// Confirm if we should bind to the primary interface's address...
// bind it to the primary interface's name
capabilities::raise(|| {
sock.bind_device(Some(interface.name.as_str().as_bytes()))
sock.bind_device(Some(instance.mac_vlan.name.as_bytes()))
})?;
capabilities::raise(|| {
sock.set_reuse_address(true);
let _ = sock.set_reuse_address(true);
});

Ok(sock)
Expand All @@ -55,17 +59,19 @@ pub fn socket_vrrp_tx(
}
}

pub fn socket_vrrp_rx(ifname: &str) -> Result<Socket, std::io::Error> {
pub fn socket_vrrp_rx(iface: &Interface) -> Result<Socket, std::io::Error> {
#[cfg(not(feature = "testing"))]
{
let sock = capabilities::raise(|| {
Socket::new(Domain::IPV4, Type::RAW, Some(Protocol::from(112)))
Socket::new(
Domain::IPV4,
Type::RAW,
Some(Protocol::from(VRRP_PROTO_NUMBER)),
)
})?;

capabilities::raise(|| sock.bind_device(Some(ifname.as_bytes())))?;
capabilities::raise(|| sock.set_broadcast(true))?;
capabilities::raise(|| sock.bind_device(Some(iface.name.as_bytes())))?;
capabilities::raise(|| sock.set_nonblocking(true))?;
capabilities::raise(|| join_multicast(&sock, ifname))?;
capabilities::raise(|| join_multicast(&sock, iface))?;

Ok(sock)
}
Expand Down Expand Up @@ -107,8 +113,8 @@ pub(crate) async fn send_packet_vrrp(
unsafe {
let ifindex = libc::if_nametoindex(c_ifname.as_ptr());
let mut sa = libc::sockaddr_ll {
sll_family: libc::AF_PACKET as u16,
sll_protocol: (112 as u16).to_be(),
sll_family: libc::AF_INET as u16,
sll_protocol: (VRRP_PROTO_NUMBER as u16).to_be(),
sll_ifindex: ifindex as i32,
sll_hatype: 0,
sll_pkttype: 0,
Expand Down Expand Up @@ -192,16 +198,14 @@ pub async fn send_packet_arp(
// for joining the VRRP multicast
pub fn join_multicast(
sock: &Socket,
ifname: &str,
iface: &Interface,
) -> Result<(), std::io::Error> {
let sock = socket2::SockRef::from(sock);
let ifname = CString::new(ifname).unwrap();
let ifindex = unsafe { if_nametoindex(ifname.as_ptr()) };

sock.join_multicast_v4_n(
&Ipv4Addr::new(224, 0, 0, 18),
&InterfaceIndexOrAddress::Index(ifindex),
)
if let Some(addr) = iface.system.addresses.first() {
let ip = addr.ip();
return sock.join_multicast_v4(&VRRP_MULTICAST_ADDRESS, &ip);
}
Err(std::io::Error::last_os_error())
}

#[cfg(not(feature = "testing"))]
Expand Down Expand Up @@ -240,7 +244,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 = [0; 128];
let mut buf = [0u8; 96];
loop {
match socket_vrrp
.async_io(tokio::io::Interest::READABLE, |sock| {
Expand Down
2 changes: 0 additions & 2 deletions holo-vrrp/src/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ pub struct ArpPacket {
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Deserialize, Serialize)]
pub struct VrrpPacket {
pub eth: EthernetHdr,
pub ip: Ipv4Packet,
pub vrrp: VrrpHdr,
}
Expand Down Expand Up @@ -421,7 +420,6 @@ impl EthernetHdr {
impl VrrpPacket {
pub fn encode(&self) -> BytesMut {
let mut buf = BytesMut::with_capacity(130);
buf.put(self.eth.encode());
buf.put(self.ip.encode());
buf.put(self.vrrp.encode());
buf
Expand Down
11 changes: 6 additions & 5 deletions holo-vrrp/src/southbound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ pub(crate) fn process_iface_update(
}

if let Some(vrid) = target_vrid {
iface.create_mvlan_net(vrid);
iface.macvlan_create(vrid);
}
}

pub(crate) fn process_addr_add(iface: &mut Interface, msg: AddressMsg) {
if msg.ifname != iface.name {
if msg.ifname == iface.name {
if let IpNetwork::V4(addr) = msg.addr {
iface.system.addresses.insert(addr);
}
Expand All @@ -88,7 +88,7 @@ pub(crate) fn process_addr_add(iface: &mut Interface, msg: AddressMsg) {
for (vrid, instance) in iface.instances.iter_mut() {
let name = format!("mvlan-vrrp-{}", vrid);
let mvlan_iface = &mut instance.mac_vlan;
if mvlan_iface.system.addresses.len() == 0 {
if mvlan_iface.system.addresses.is_empty() {
target_vrid = Some(*vrid);
}
if mvlan_iface.name == name {
Expand All @@ -99,7 +99,8 @@ pub(crate) fn process_addr_add(iface: &mut Interface, msg: AddressMsg) {
}

if let Some(vrid) = target_vrid {
iface.create_mvlan_net(vrid);
iface.macvlan_create(vrid);
iface.reset_timer(vrid);
}
}

Expand Down Expand Up @@ -142,7 +143,7 @@ pub(crate) fn create_macvlan_iface(
}

// deletes and interface e.g eth0 entirely
pub(crate) fn delete_iface(ifindex: u32, ibus_tx: &IbusSender) {
pub(crate) fn mvlan_delete(ifindex: u32, ibus_tx: &IbusSender) {
let _ = ibus_tx.send(IbusMsg::InterfaceDeleteRequest(ifindex));
}

Expand Down
6 changes: 1 addition & 5 deletions holo-vrrp/src/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@
use std::sync::Arc;
use std::time::Duration;

use bytes::{BufMut, BytesMut};
use holo_utils::socket::{AsyncFd, Socket};
use holo_utils::task::{IntervalTask, Task, TimeoutTask};
use holo_utils::{Sender, UnboundedReceiver, UnboundedSender};
use holo_utils::{Sender, UnboundedReceiver};
use messages::input::MasterDownTimerMsg;
use messages::output::NetTxPacketMsg;
use tracing::{debug_span, Instrument};
Expand Down Expand Up @@ -199,16 +198,13 @@ pub(crate) fn set_timer(
// every ADVERT_INTERVAL seconds until otherwise.
crate::instance::State::Master => {
// -----------------
let mut buf = BytesMut::new();
let src_ip = interface.system.addresses.first().unwrap().ip();

let eth_hdr = instance.advert_ether_frame();
let ip_hdr = instance.adver_ipv4_pkt(src_ip);
let vrrp_hdr = instance.adver_vrrp_pkt();

let pkt = VrrpPacket {
ip: ip_hdr,
eth: eth_hdr,
vrrp: vrrp_hdr,
};
let ifname = instance.mac_vlan.name.clone();
Expand Down

0 comments on commit 2cca732

Please sign in to comment.