diff --git a/holo-vrrp/src/instance.rs b/holo-vrrp/src/instance.rs index 4fb29a8f..5b4fb5f3 100644 --- a/holo-vrrp/src/instance.rs +++ b/holo-vrrp/src/instance.rs @@ -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; @@ -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), @@ -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 diff --git a/holo-vrrp/src/interface.rs b/holo-vrrp/src/interface.rs index b1132aac..0954e7a7 100644 --- a/holo-vrrp/src/interface.rs +++ b/holo-vrrp/src/interface.rs @@ -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, }; @@ -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. @@ -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); } } @@ -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, }; @@ -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"); @@ -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) diff --git a/holo-vrrp/src/network.rs b/holo-vrrp/src/network.rs index 108cf077..d6ce2b21 100644 --- a/holo-vrrp/src/network.rs +++ b/holo-vrrp/src/network.rs @@ -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; @@ -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) @@ -55,17 +59,19 @@ pub fn socket_vrrp_tx( } } -pub fn socket_vrrp_rx(ifname: &str) -> Result { +pub fn socket_vrrp_rx(iface: &Interface) -> Result { #[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) } @@ -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, @@ -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"))] @@ -240,7 +244,7 @@ pub(crate) async fn vrrp_read_loop( socket_vrrp: Arc>, vrrp_net_packet_rxp: Sender, ) -> Result<(), SendError> { - let mut buf = [0; 128]; + let mut buf = [0u8; 96]; loop { match socket_vrrp .async_io(tokio::io::Interest::READABLE, |sock| { diff --git a/holo-vrrp/src/packet.rs b/holo-vrrp/src/packet.rs index 18ed1b42..c6d4e7c8 100644 --- a/holo-vrrp/src/packet.rs +++ b/holo-vrrp/src/packet.rs @@ -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, } @@ -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 diff --git a/holo-vrrp/src/southbound.rs b/holo-vrrp/src/southbound.rs index 7ba783b0..bad3c4b6 100644 --- a/holo-vrrp/src/southbound.rs +++ b/holo-vrrp/src/southbound.rs @@ -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); } @@ -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 { @@ -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); } } @@ -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)); } diff --git a/holo-vrrp/src/tasks.rs b/holo-vrrp/src/tasks.rs index f3387778..71ade490 100644 --- a/holo-vrrp/src/tasks.rs +++ b/holo-vrrp/src/tasks.rs @@ -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}; @@ -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();