2025-12-24 23:45:00 +08:00

421 lines
12 KiB
Rust
Executable File

#![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<ArpActor> = 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<u8> {
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<u32, ArpEntry>,
// 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<ArpResponse>,
}
#[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<ArpRequest>,
}
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<ArpRequest>) {
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<u8> {
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()
}