#![allow(unused)] use std::{ collections::HashMap, sync::atomic::{AtomicU8, Ordering}, time::Duration, }; use tracing::error; use once_cell::sync::OnceCell; use sdlan_sn_rs::utils::{BROADCAST_MAC, MULTICAST_MAC, Mac, ip_to_string, net_bit_len_to_mask}; use tokio::sync::{ mpsc::{channel, Receiver, Sender}, oneshot, }; use super::{get_edge, get_route_table, init_arp_wait_list, init_route}; static GLOBAL_ARP: OnceCell = OnceCell::new(); pub fn init_arp() { init_route(); init_arp_wait_list(); let actor = ArpActor::new(); GLOBAL_ARP.set(actor).unwrap(); } pub fn get_arp() -> &'static ArpActor { GLOBAL_ARP.get().unwrap() } const ETHER_TYPE_ARP: u16 = 0x0806; const ETHER_TYPE_IP: u16 = 0x0800; #[allow(unused)] const ETHER_TYPE_IP6: u16 = 0x86dd; const ARP_MAX_AGE: u8 = 128; const ARP_HWTYPE_ETH: u16 = 1; pub const ARP_REQUEST: u16 = 1; pub const ARP_REPLY: u16 = 2; #[repr(C)] pub struct EthHdr { pub dest: [u8; 6], pub src: [u8; 6], pub eth_type: u16, } #[repr(C)] pub struct ArpHdr { pub ethhdr: EthHdr, pub hwtype: u16, pub protocol: u16, pub hwlen: u8, pub protolen: u8, pub opcode: u16, pub shwaddr: [u8; 6], pub sipaddr: [u16; 2], pub dhwaddr: [u8; 6], pub dipaddr: [u16; 2], } impl ArpHdr { pub fn from_slice(data: &[u8]) -> Self { if data.len() < 42 { panic!("data size error"); } Self { ethhdr: EthHdr { dest: data[0..6].try_into().unwrap(), src: data[6..12].try_into().unwrap(), eth_type: u16::from_be_bytes(data[12..14].try_into().unwrap()), }, hwtype: u16::from_be_bytes(data[14..16].try_into().unwrap()), protocol: u16::from_be_bytes(data[16..18].try_into().unwrap()), hwlen: data[18], protolen: data[19], opcode: u16::from_be_bytes(data[20..22].try_into().unwrap()), shwaddr: data[22..28].try_into().unwrap(), sipaddr: [ u16::from_be_bytes(data[28..30].try_into().unwrap()), u16::from_be_bytes(data[30..32].try_into().unwrap()), ], dhwaddr: data[32..38].try_into().unwrap(), dipaddr: [ u16::from_be_bytes(data[38..40].try_into().unwrap()), u16::from_be_bytes(data[40..42].try_into().unwrap()), ], } } pub fn marshal_to_bytes(&self) -> Vec { let mut result = Vec::with_capacity(64); result.extend_from_slice(&self.ethhdr.dest); result.extend_from_slice(&self.ethhdr.src); result.extend_from_slice(&self.ethhdr.eth_type.to_be_bytes()); result.extend_from_slice(&self.hwtype.to_be_bytes()); result.extend_from_slice(&self.protocol.to_be_bytes()); result.push(self.hwlen); result.push(self.protolen); result.extend_from_slice(&self.opcode.to_be_bytes()); result.extend_from_slice(&self.shwaddr); result.extend_from_slice(&self.sipaddr[0].to_be_bytes()); result.extend_from_slice(&self.sipaddr[1].to_be_bytes()); result.extend_from_slice(&self.dhwaddr); result.extend_from_slice(&self.dipaddr[0].to_be_bytes()); result.extend_from_slice(&self.dipaddr[1].to_be_bytes()); // result.extend_from_slice(&[0; 18]); // let crc = CRC_HASH.checksum(&result).to_be_bytes(); // result.extend_from_slice(&crc); result } pub fn new() -> Self { Self { ethhdr: EthHdr { dest: [0; 6], src: [0; 6], eth_type: ETHER_TYPE_ARP, }, hwtype: ARP_HWTYPE_ETH, protocol: ETHER_TYPE_IP, hwlen: 6, protolen: 4, opcode: ARP_REQUEST, shwaddr: [0; 6], sipaddr: [0; 2], dhwaddr: [0; 6], dipaddr: [0; 2], } } } // const ARP_TABLE_SIZE: usize = 8; static ARPTIME: AtomicU8 = AtomicU8::new(0); const BROADCAST_IPADDR: u32 = 0xffffffff; #[derive(Debug)] #[allow(unused)] pub struct ArpEntry { ip_addr: u32, arptime: u8, hw_addr: [u8; 6], } /* impl ArpEntry { pub fn new() -> Self { Self { ip_addr: 0, arptime: 0, hw_addr: [0; 6], } } } */ pub struct ArpInfo { // host_ip: AtomicU32, // ip representation of mask // host_netmask: AtomicU32, entry: HashMap, // entry: [ArpEntry; ARP_TABLE_SIZE], } impl ArpInfo { fn lookup_ip_mac(&self, ip: u32) -> Option<([u8; 6], u32, bool)> { if ip == BROADCAST_IPADDR { return Some((BROADCAST_MAC, ip, false)); } let edge = get_edge(); let netbit = edge.device_config.get_net_bit(); let host_netmask = net_bit_len_to_mask(netbit); let host_netmask_reverse = !host_netmask; if (ip & host_netmask_reverse) == host_netmask_reverse { return Some((BROADCAST_MAC, ip, false)); } let first_ip = (ip >> 24) as u8 & 0xff; if first_ip >= 224 && first_ip <= 239 { let mut multi = MULTICAST_MAC; multi[3] = (ip >> 16) as u8 & 0x7f; multi[4] = (ip >> 8) as u8 & 0xff; multi[5] = (ip) as u8 & 0xff; return Some((multi, ip, false)); } let mut target_ip = 0; let host_ip = edge.device_config.get_ip(); if (ip & host_netmask) == (host_ip & host_netmask) { target_ip = ip; } if target_ip == 0 { let route_table = get_route_table(); if let Some(gateway_ip) = route_table.get_gateway_ip(ip) { target_ip = gateway_ip; } } if target_ip == 0 { error!("target should not route to me: ip = {}", ip_to_string(&ip)); return None; } if let Some(entry) = self.entry.get(&target_ip) { return Some((entry.hw_addr, target_ip, false)); } /* for i in 0..ARP_TABLE_SIZE { let item = &self.entry[i]; if item.ip_addr == target_ip { return (item.hw_addr, target_ip, false); } } */ return Some((BROADCAST_MAC, target_ip, true)); } fn set_arp(&mut self, mac: [u8; 6], ip: u32) { // println!("setting ip: {:?} is at {:?}", ip.to_be_bytes(), mac); let nowage = ARPTIME.load(Ordering::Relaxed); self.entry.insert( ip, ArpEntry { ip_addr: ip, hw_addr: mac, arptime: nowage, }, ); /* for i in 0..ARP_TABLE_SIZE { let item = &mut self.entry[i]; if item.ip_addr != 0 { if item.ip_addr == ip { item.hw_addr = mac; let nowage = ARPTIME.load(Ordering::Relaxed); item.arptime = nowage; return; } } } */ /* println!("set_arp 1"); let mut itemindex = ARP_TABLE_SIZE; for i in 0..ARP_TABLE_SIZE { let temp = &self.entry[i]; println!("set arp 2"); if temp.ip_addr == 0 { itemindex = i; println!("set arp 3: itemindex = {}", itemindex); break; } } let arptime = ARPTIME.load(Ordering::Relaxed); if itemindex == ARP_TABLE_SIZE { println!("set_arp 4"); let mut tmpage = 0; let mut idx = 0; for i in 0..ARP_TABLE_SIZE { let temp = &self.entry[i]; if (arptime - temp.arptime) > tmpage { tmpage = arptime - temp.arptime; idx = i; } } itemindex = idx; } println!("set_arp 5"); let temp = &mut self.entry[itemindex]; temp.arptime = arptime; temp.ip_addr = ip; temp.hw_addr = mac; println!("set arp 6: idx={} => {:?}", itemindex, temp); */ } fn timer(&mut self) { let timer = ARPTIME.fetch_add(1, Ordering::Relaxed); let mut todelete = vec![]; for (ip, entry) in &self.entry { if (timer - entry.arptime) >= ARP_MAX_AGE { todelete.push(*ip); } } for ip in todelete { self.entry.remove(&ip); } /* for i in 0..ARP_TABLE_SIZE { let item = &mut self.entry[i]; if item.ip_addr != 0 && (timer - item.arptime) >= ARP_MAX_AGE { item.ip_addr = 0; } } */ } } pub enum ArpRequestInfo { Lookup { ip: u32 }, Set { ip: u32, mac: Mac }, } pub struct ArpRequest { req: ArpRequestInfo, tx: oneshot::Sender, } #[derive(Debug)] #[allow(unused)] pub enum ArpResponse { LookupResp { mac: Mac, ip: u32, do_arp_request: bool, }, SetResp { ok: bool, }, ArpRespError { msg: String, }, } #[derive(Debug)] pub struct ArpActor { pub tx: Sender, } impl ArpActor { pub fn new() -> Self { let (tx, rx) = channel(20); tokio::spawn(loop_arp_info(rx)); Self { tx } } } async fn loop_arp_info(mut rx: Receiver) { let mut arp = ArpInfo { // entry: array::from_fn(|_i| ArpEntry::new()), entry: HashMap::new(), }; loop { tokio::select! { data = rx.recv() => { if let Some(d) = data { match d.req { ArpRequestInfo::Lookup{ip} => { let Some(mac) = arp.lookup_ip_mac(ip) else { continue; }; if let Err(e) = d.tx.send(ArpResponse::LookupResp { mac: mac.0, ip: mac.1, do_arp_request: mac.2 } ) { error!("failed to send back arp lookup feedback: {:?}", e); }; } ArpRequestInfo::Set{ip, mac} => { arp.set_arp(mac, ip); if let Err(e) = d.tx.send(ArpResponse::SetResp { ok: true }) { error!("failed to send back arp set feedback: {:?}", e); } } } } } _ = tokio::time::sleep(Duration::from_secs(10)) => { arp.timer(); } } } } pub async fn send_arp_request(data: ArpRequestInfo) -> ArpResponse { let (tx, rx) = oneshot::channel(); let arp = get_arp(); if let Err(e) = arp.tx.send(ArpRequest { tx, req: data }).await { error!("failed to send arp request: {}", e); return ArpResponse::ArpRespError { msg: "failed to send arp request".to_owned(), }; } match rx.await { Ok(res) => res, Err(e) => ArpResponse::ArpRespError { msg: e.to_string() }, } } pub fn generate_arp_request(srcmac: [u8; 6], dstip: u32, srcip: u32) -> Vec { let mut arphdr = ArpHdr::new(); arphdr.ethhdr.dest = [0xff; 6]; arphdr.dhwaddr = [0; 6]; arphdr.ethhdr.src = srcmac; arphdr.shwaddr = srcmac; arphdr.dipaddr = [(dstip >> 16) as u16, (dstip & 0xffff) as u16]; arphdr.sipaddr = [(srcip >> 16) as u16, (srcip & 0xffff) as u16]; /* println!( "arphdr.sipaddr: {:?}, {:?}", arphdr.sipaddr[0].to_be_bytes(), arphdr.sipaddr[1].to_be_bytes() ); println!( "arphdr.dipaddr: {:?}, {:?}", arphdr.dipaddr[0].to_be_bytes(), arphdr.dipaddr[1].to_be_bytes() ); */ arphdr.marshal_to_bytes() }