diff --git a/holo-vrrp/src/debug.rs b/holo-vrrp/src/debug.rs index 7ed2a735..7221483e 100644 --- a/holo-vrrp/src/debug.rs +++ b/holo-vrrp/src/debug.rs @@ -8,7 +8,7 @@ use std::net::IpAddr; use tracing::{debug, debug_span}; -use crate::packet::VrrpPacket; +use crate::packet::VrrpHdr; // VRRP debug messages. #[derive(Debug)] @@ -16,8 +16,8 @@ pub enum Debug<'a> { InstanceCreate, InstanceDelete, // Network - PacketRx(&'a IpAddr, &'a VrrpPacket), - PacketTx(&'a IpAddr, &'a VrrpPacket), + PacketRx(&'a IpAddr, &'a VrrpHdr), + PacketTx(&'a IpAddr, &'a VrrpHdr), } // ===== impl Debug ===== diff --git a/holo-vrrp/src/events.rs b/holo-vrrp/src/events.rs index f7598edf..6d747760 100644 --- a/holo-vrrp/src/events.rs +++ b/holo-vrrp/src/events.rs @@ -8,21 +8,21 @@ use std::time::Duration; use crate::error::{Error, IoError}; use crate::instance::State; use crate::interface::Interface; -use crate::packet::{DecodeResult, VrrpPacket}; +use crate::packet::{DecodeResult, VrrpHdr}; use crate::tasks; // To collect actions to be executed later enum VrrpAction { - Initialize(Ipv4Addr, VrrpPacket), - Backup(Ipv4Addr, VrrpPacket), - Master(Ipv4Addr, VrrpPacket), + Initialize(Ipv4Addr, VrrpHdr), + Backup(Ipv4Addr, VrrpHdr), + Master(Ipv4Addr, VrrpHdr), } // ===== Vrrp Network packet receipt ===== pub(crate) fn process_vrrp_packet( interface: &mut Interface, src_ip: Ipv4Addr, - packet: DecodeResult, + packet: DecodeResult, ) -> Result<(), Error> { // Handle packet decoding errors let pkt = match packet { @@ -53,7 +53,7 @@ pub(crate) fn process_vrrp_packet( fn get_vrrp_action( interface: &mut Interface, src_ip: Ipv4Addr, - packet: VrrpPacket, + packet: VrrpHdr, ) -> Result { // Handle missing instance let instance = match interface.instances.get_mut(&packet.vrid) { diff --git a/holo-vrrp/src/instance.rs b/holo-vrrp/src/instance.rs index 5e834ecc..4fb29a8f 100644 --- a/holo-vrrp/src/instance.rs +++ b/holo-vrrp/src/instance.rs @@ -12,7 +12,7 @@ use holo_utils::task::{IntervalTask, TimeoutTask}; use crate::interface::MacVlanInterface; use crate::northbound::configuration::InstanceCfg; -use crate::packet::{ArpPacket, EthernetFrame, Ipv4Packet, VrrpPacket}; +use crate::packet::{ArpPacket, EthernetHdr, Ipv4Packet, VrrpHdr}; use crate::tasks::messages::output::NetTxPacketMsg; #[derive(Debug)] @@ -146,13 +146,13 @@ impl Instance { self.state.master_down_interval = master_down; } - pub(crate) fn adver_vrrp_pkt(&self) -> VrrpPacket { + pub(crate) fn adver_vrrp_pkt(&self) -> VrrpHdr { let mut ip_addresses: Vec = vec![]; for addr in self.config.virtual_addresses.clone() { ip_addresses.push(addr.ip()); } - let mut packet = VrrpPacket { + let mut packet = VrrpHdr { version: 2, hdr_type: 1, vrid: self.vrid, @@ -195,8 +195,8 @@ impl Instance { } } - pub(crate) fn advert_ether_frame(&self) -> EthernetFrame { - EthernetFrame::vrrp(self.vrid) + pub(crate) fn advert_ether_frame(&self) -> EthernetHdr { + EthernetHdr::vrrp(self.vrid) } pub(crate) fn send_gratuitous_arp(&self) { @@ -219,7 +219,7 @@ impl Instance { target_proto_address: addr.ip().octets(), }; - let eth_frame = EthernetFrame { + let eth_hdr = EthernetHdr { ethertype: 0x806, dst_mac: [0xff; 6], src_mac: self.mac_vlan.system.mac_address, @@ -227,7 +227,7 @@ impl Instance { let msg = NetTxPacketMsg::Arp { name: self.mac_vlan.name.clone(), - eth_frame, + eth_frame: eth_hdr, arp_packet, }; diff --git a/holo-vrrp/src/interface.rs b/holo-vrrp/src/interface.rs index 71c889e4..b1132aac 100644 --- a/holo-vrrp/src/interface.rs +++ b/holo-vrrp/src/interface.rs @@ -25,6 +25,7 @@ use tracing::{debug, debug_span, error_span}; use crate::error::{Error, IoError}; use crate::instance::{Instance, State}; +use crate::packet::VrrpPacket; use crate::tasks::messages::input::{MasterDownTimerMsg, VrrpNetRxPacketMsg}; use crate::tasks::messages::output::NetTxPacketMsg; use crate::tasks::messages::{ProtocolInputMsg, ProtocolOutputMsg}; @@ -233,21 +234,18 @@ impl Interface { { let mut buf = BytesMut::new(); - // ethernet frame - let eth_frame: &[u8] = &instance.advert_ether_frame().encode(); - buf.put(eth_frame); - - // ip packet - let ip_pkt: &[u8] = &instance.adver_ipv4_pkt(addr.ip()).encode(); - buf.put(ip_pkt); - - // vrrp packet - let vrrp_pkt: &[u8] = &instance.adver_vrrp_pkt().encode(); - buf.put(vrrp_pkt); + 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, + }; let msg = NetTxPacketMsg::Vrrp { ifname: instance.mac_vlan.name.clone(), - buf: buf.to_vec(), + pkt, }; if let Some(net) = &instance.mac_vlan.net { let _ = net.net_tx_packetp.send(msg); diff --git a/holo-vrrp/src/network.rs b/holo-vrrp/src/network.rs index c36bf799..108cf077 100644 --- a/holo-vrrp/src/network.rs +++ b/holo-vrrp/src/network.rs @@ -19,7 +19,8 @@ use tracing::{debug, debug_span}; use crate::error::IoError; use crate::interface::Interface; -use crate::packet::{ArpPacket, EthernetFrame, Ipv4Packet, VrrpPacket}; +use crate::packet::VrrpPacket; +use crate::packet::{ArpPacket, EthernetHdr, Ipv4Packet, VrrpHdr}; use crate::tasks::messages::input::VrrpNetRxPacketMsg; use crate::tasks::messages::output::NetTxPacketMsg; @@ -37,24 +38,6 @@ pub fn socket_vrrp_tx( capabilities::raise(|| sock.set_nonblocking(true))?; - // to be uncommented in due time. - //if let Some(addr) = instance.mac_vlan.system.addresses.first() { - // capabilities::raise(|| { - // match sock.set_multicast_if_v4(&addr.ip()) { - // Ok(_res) => { - // debug_span!("socket-vrrp").in_scope(|| { - // debug!("successfully joined multicast interface"); - // }); - // } - // Err(err) => { - // debug_span!("socket-vrrp").in_scope(|| { - // debug!(%addr, %err, "unable to join multicast interface"); - // }); - // } - // } - // }); - //} - // Confirm if we should bind to the primary interface's address... // bind it to the primary interface's name capabilities::raise(|| { @@ -118,15 +101,14 @@ pub fn socket_arp(ifname: &str) -> Result { pub(crate) async fn send_packet_vrrp( sock: &AsyncFd, ifname: &str, - buf: &[u8], + pkt: VrrpPacket, ) -> Result { let c_ifname = CString::new(ifname).unwrap(); - 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: (ETH_P_IP as u16).to_be(), + sll_family: libc::AF_PACKET as u16, + sll_protocol: (112 as u16).to_be(), sll_ifindex: ifindex as i32, sll_hatype: 0, sll_pkttype: 0, @@ -138,6 +120,7 @@ pub(crate) async fn send_packet_vrrp( *mut libc::sockaddr_ll, *mut libc::sockaddr, >(&mut sa); + let buf: &[u8] = &pkt.encode(); match libc::sendto( sock.as_raw_fd(), @@ -157,12 +140,12 @@ pub(crate) async fn send_packet_vrrp( pub async fn send_packet_arp( sock: &AsyncFd, ifname: &str, - eth_frame: EthernetFrame, + eth_frame: EthernetHdr, arp_packet: ArpPacket, ) -> Result { use std::ffi::CString; - use libc::{c_void, sendto, sockaddr, sockaddr_ll}; + use libc::{c_void, sendto, sockaddr, sockaddr_ll, AF_INET}; use crate::packet::ARPframe; let mut arpframe = ARPframe::new(eth_frame, arp_packet); @@ -179,7 +162,7 @@ pub async fn send_packet_arp( let ifindex = unsafe { libc::if_nametoindex(c_ifname.as_ptr()) }; let mut sa = sockaddr_ll { - sll_family: AF_PACKET as u16, + sll_family: AF_INET as u16, sll_protocol: 0x806_u16.to_be(), sll_ifindex: ifindex as i32, sll_hatype: 0, @@ -229,9 +212,9 @@ pub(crate) async fn write_loop( ) { while let Some(msg) = net_tx_packetc.recv().await { match msg { - NetTxPacketMsg::Vrrp { ifname, buf } => { + NetTxPacketMsg::Vrrp { ifname, pkt } => { if let Err(error) = - send_packet_vrrp(&socket_vrrp, &ifname, &buf[..]).await + send_packet_vrrp(&socket_vrrp, &ifname, pkt).await { error.log(); } @@ -277,8 +260,7 @@ pub(crate) async fn vrrp_read_loop( let ip_pkt = Ipv4Packet::decode(&data[0..ip_header_len]) .unwrap(); - let vrrp_pkt = - VrrpPacket::decode(&data[ip_header_len..]); + let vrrp_pkt = VrrpHdr::decode(&data[ip_header_len..]); Ok((ip_pkt.src_address, vrrp_pkt)) } Err(errno) => Err(errno.into()), diff --git a/holo-vrrp/src/packet.rs b/holo-vrrp/src/packet.rs index 07bf138e..18ed1b42 100644 --- a/holo-vrrp/src/packet.rs +++ b/holo-vrrp/src/packet.rs @@ -40,7 +40,7 @@ pub type DecodeResult = Result; // #[derive(Clone, Debug, Eq, PartialEq)] #[derive(Deserialize, Serialize)] -pub struct VrrpPacket { +pub struct VrrpHdr { pub version: u8, pub hdr_type: u8, pub vrid: u8, @@ -113,7 +113,7 @@ pub struct ARPframe { } impl ARPframe { - pub fn new(eth_pkt: EthernetFrame, arp_pkt: ArpPacket) -> Self { + pub fn new(eth_pkt: EthernetHdr, arp_pkt: ArpPacket) -> Self { Self { dst_mac: eth_pkt.dst_mac, src_mac: eth_pkt.src_mac, @@ -135,7 +135,7 @@ impl ARPframe { #[derive(Clone, Debug, Eq, PartialEq)] #[derive(Deserialize, Serialize)] -pub struct EthernetFrame { +pub struct EthernetHdr { pub dst_mac: [u8; 6], pub src_mac: [u8; 6], pub ethertype: u16, @@ -155,6 +155,14 @@ pub struct ArpPacket { pub target_proto_address: [u8; 4], // src ip } +#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Deserialize, Serialize)] +pub struct VrrpPacket { + pub eth: EthernetHdr, + pub ip: Ipv4Packet, + pub vrrp: VrrpHdr, +} + #[derive(Debug, Eq, PartialEq)] #[derive(Deserialize, Serialize)] pub enum DecodeError { @@ -185,7 +193,7 @@ impl DecodeError { // ===== impl Packet ===== -impl VrrpPacket { +impl VrrpHdr { const MIN_PKT_LENGTH: usize = 16; const MAX_PKT_LENGTH: usize = 80; const MAX_IP_COUNT: usize = 16; @@ -373,7 +381,7 @@ impl Ipv4Packet { } } -impl EthernetFrame { +impl EthernetHdr { pub fn encode(&self) -> BytesMut { let mut buf = BytesMut::new(); self.dst_mac.iter().for_each(|i| buf.put_u8(*i)); @@ -410,6 +418,16 @@ impl EthernetFrame { } } +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 + } +} + impl ArpPacket { pub fn encode(&self) -> BytesMut { let mut buf = BytesMut::with_capacity(28); diff --git a/holo-vrrp/src/tasks.rs b/holo-vrrp/src/tasks.rs index 79840dc6..f3387778 100644 --- a/holo-vrrp/src/tasks.rs +++ b/holo-vrrp/src/tasks.rs @@ -18,6 +18,7 @@ use tracing::{debug_span, Instrument}; use crate::instance::{Instance, VrrpTimer}; use crate::interface::Interface; use crate::network; +use crate::packet::VrrpPacket; // // VRRP tasks diagram: @@ -30,7 +31,6 @@ use crate::network; // +--------------+ // master_down_timer (Nx) -> | | // vrrp_net (Nx) -> | instance | -> (Nx) net_tx -// arp_net (Nx) -> | | // +--------------+ // ibus_tx (1x) | ^ (1x) ibus_rx // | | @@ -44,7 +44,7 @@ use crate::network; pub mod messages { use serde::{Deserialize, Serialize}; - use crate::packet::{DecodeError, VrrpPacket}; + use crate::packet::{DecodeError, VrrpHdr}; // Type aliases. pub type ProtocolInputMsg = input::ProtocolMsg; @@ -66,7 +66,7 @@ pub mod messages { #[derive(Debug, Deserialize, Serialize)] pub struct VrrpNetRxPacketMsg { pub src: Ipv4Addr, - pub packet: Result, + pub packet: Result, } #[derive(Debug, Deserialize, Serialize)] @@ -83,7 +83,7 @@ pub mod messages { // Output messages (main task -> child task). pub mod output { use super::*; - use crate::packet::{ArpPacket, EthernetFrame}; + use crate::packet::{ArpPacket, EthernetHdr, VrrpPacket}; #[derive(Debug, Serialize)] pub enum ProtocolMsg { @@ -94,11 +94,11 @@ pub mod messages { pub enum NetTxPacketMsg { Vrrp { ifname: String, - buf: Vec, + pkt: VrrpPacket, }, Arp { name: String, - eth_frame: EthernetFrame, + eth_frame: EthernetHdr, arp_packet: ArpPacket, }, } @@ -200,20 +200,17 @@ pub(crate) fn set_timer( crate::instance::State::Master => { // ----------------- let mut buf = BytesMut::new(); - - // ethernet frame - let eth_frame: &[u8] = &instance.advert_ether_frame().encode(); - buf.put(eth_frame); - - // ip packet let src_ip = interface.system.addresses.first().unwrap().ip(); - let ip_pkt: &[u8] = &instance.adver_ipv4_pkt(src_ip).encode(); - buf.put(ip_pkt); - // vrrp packet - let vrrp_pkt: &[u8] = &instance.adver_vrrp_pkt().encode(); - buf.put(vrrp_pkt); + 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(); // ----------------- if let Some(net) = &instance.mac_vlan.net { @@ -225,10 +222,10 @@ pub(crate) fn set_timer( true, move || { let ifname = ifname.clone(); - let buf = buf.to_vec(); let net_tx = net_tx.clone(); + let pkt = pkt.clone(); async move { - let msg = NetTxPacketMsg::Vrrp { ifname, buf }; + let msg = NetTxPacketMsg::Vrrp { ifname, pkt }; let _ = net_tx.send(msg); } },