parent
a6bb042bd9
commit
71808b49f5
@ -0,0 +1,511 @@
|
||||
//! Intel 10Gb Network Adapter 82599 i.e. ixgbe network driver
|
||||
|
||||
use alloc::alloc::{GlobalAlloc, Layout};
|
||||
use alloc::format;
|
||||
use alloc::prelude::*;
|
||||
use alloc::sync::Arc;
|
||||
use core::mem::size_of;
|
||||
use core::slice;
|
||||
use core::sync::atomic::{fence, Ordering};
|
||||
|
||||
use alloc::collections::BTreeMap;
|
||||
use bitflags::*;
|
||||
use log::*;
|
||||
use rcore_memory::paging::PageTable;
|
||||
use rcore_memory::PAGE_SIZE;
|
||||
use smoltcp::iface::*;
|
||||
use smoltcp::phy::{self, DeviceCapabilities};
|
||||
use smoltcp::socket::*;
|
||||
use smoltcp::time::Instant;
|
||||
use smoltcp::wire::EthernetAddress;
|
||||
use smoltcp::wire::*;
|
||||
use smoltcp::Result;
|
||||
use volatile::Volatile;
|
||||
|
||||
use crate::memory::active_table;
|
||||
use crate::sync::SpinNoIrqLock as Mutex;
|
||||
use crate::sync::{MutexGuard, SpinNoIrq};
|
||||
use crate::HEAP_ALLOCATOR;
|
||||
|
||||
use super::super::{DeviceType, Driver, NetDriver, DRIVERS, NET_DRIVERS, SOCKET_ACTIVITY};
|
||||
|
||||
// At the beginning, all transmit descriptors have there status non-zero,
|
||||
// so we need to track whether we are using the descriptor for the first time.
|
||||
// When the descriptors wrap around, we set first_trans to false,
|
||||
// and lookup status instead for checking whether it is empty.
|
||||
|
||||
pub struct IXGBE {
|
||||
header: usize,
|
||||
size: usize,
|
||||
mac: EthernetAddress,
|
||||
send_page: usize,
|
||||
send_buffers: Vec<usize>,
|
||||
recv_page: usize,
|
||||
recv_buffers: Vec<usize>,
|
||||
first_trans: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct IXGBEDriver(Arc<Mutex<IXGBE>>);
|
||||
|
||||
const IXGBE_CTRL: usize = 0x00000 / 4;
|
||||
const IXGBE_STATUS: usize = 0x00008 / 4;
|
||||
const IXGBE_CTRL_EXT: usize = 0x00018 / 4;
|
||||
const IXGBE_EICR: usize = 0x00800 / 4;
|
||||
const IXGBE_EIMS: usize = 0x00880 / 4;
|
||||
const IXGBE_EIMC: usize = 0x00888 / 4;
|
||||
const IXGBE_IVAR: usize = 0x00900 / 4;
|
||||
const IXGBE_EIMC1: usize = 0x00A90 / 4;
|
||||
const IXGBE_EIMC2: usize = 0x00A91 / 4;
|
||||
const IXGBE_RDBAL: usize = 0x01000 / 4;
|
||||
const IXGBE_RDBAH: usize = 0x01004 / 4;
|
||||
const IXGBE_RDLEN: usize = 0x01008 / 4;
|
||||
const IXGBE_DCA_RXCTRL: usize = 0x0100C / 4;
|
||||
const IXGBE_RDH: usize = 0x01010 / 4;
|
||||
const IXGBE_SRRCTL: usize = 0x01014 / 4;
|
||||
const IXGBE_RDT: usize = 0x01018 / 4;
|
||||
const IXGBE_RXDCTL: usize = 0x01028 / 4;
|
||||
const IXGBE_RDRXCTL: usize = 0x02F00 / 4;
|
||||
const IXGBE_RXCTRL: usize = 0x03000 / 4;
|
||||
const IXGBE_FCTTV: usize = 0x03200 / 4;
|
||||
const IXGBE_FCTTV_END: usize = 0x03210 / 4;
|
||||
const IXGBE_FCRTL: usize = 0x03220 / 4;
|
||||
const IXGBE_FCRTL_END: usize = 0x03240 / 4;
|
||||
const IXGBE_FCRTH: usize = 0x03260 / 4;
|
||||
const IXGBE_FCRTH_END: usize = 0x03280 / 4;
|
||||
const IXGBE_FCRTV: usize = 0x032A0 / 4;
|
||||
const IXGBE_FCCFG: usize = 0x03D00 / 4;
|
||||
const IXGBE_AUTOC: usize = 0x042A0 / 4;
|
||||
const IXGBE_LINKS: usize = 0x042A4 / 4;
|
||||
const IXGBE_AUTOC2: usize = 0x04324 / 4;
|
||||
const IXGBE_FCTRL: usize = 0x05080 / 4;
|
||||
const IXGBE_MTA: usize = 0x05200 / 4;
|
||||
const IXGBE_MTA_END: usize = 0x05400 / 4;
|
||||
const IXGBE_TDBAL: usize = 0x06000 / 4;
|
||||
const IXGBE_TDBAH: usize = 0x06004 / 4;
|
||||
const IXGBE_TDLEN: usize = 0x06008 / 4;
|
||||
const IXGBE_TDH: usize = 0x06010 / 4;
|
||||
const IXGBE_TDT: usize = 0x06018 / 4;
|
||||
const IXGBE_SECRXCTRL: usize = 0x08D00 / 4;
|
||||
const IXGBE_SECRXSTAT: usize = 0x08D04 / 4;
|
||||
const IXGBE_VFTA: usize = 0x0A000 / 4;
|
||||
const IXGBE_VFTA_END: usize = 0x0A200 / 4;
|
||||
const IXGBE_RAL: usize = 0x0A200 / 4;
|
||||
const IXGBE_RAH: usize = 0x0A204 / 4;
|
||||
const IXGBE_MPSAR: usize = 0x0A600 / 4;
|
||||
const IXGBE_MPSAR_END: usize = 0x0A800 / 4;
|
||||
const IXGBE_PFVLVF: usize = 0x0F100 / 4;
|
||||
const IXGBE_PFVLVF_END: usize = 0x0F200 / 4;
|
||||
const IXGBE_PFVLVFB: usize = 0x0F200 / 4;
|
||||
const IXGBE_PFVLVFB_END: usize = 0x0F400 / 4;
|
||||
const IXGBE_PFUTA: usize = 0x0F400 / 4;
|
||||
const IXGBE_PFUTA_END: usize = 0x0F600 / 4;
|
||||
const IXGBE_EEC: usize = 0x10010 / 4;
|
||||
|
||||
pub struct IXGBEInterface {
|
||||
iface: Mutex<EthernetInterface<'static, 'static, 'static, IXGBEDriver>>,
|
||||
driver: IXGBEDriver,
|
||||
sockets: Mutex<SocketSet<'static, 'static, 'static>>,
|
||||
}
|
||||
|
||||
impl Driver for IXGBEInterface {
|
||||
fn try_handle_interrupt(&self) -> bool {
|
||||
let irq = {
|
||||
let driver = self.driver.0.lock();
|
||||
|
||||
if let None = active_table().get_entry(driver.header) {
|
||||
let mut current_addr = driver.header;
|
||||
while current_addr < driver.header + driver.size {
|
||||
active_table().map_if_not_exists(current_addr, current_addr);
|
||||
current_addr = current_addr + PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
let ixgbe = unsafe {
|
||||
slice::from_raw_parts_mut(driver.header as *mut Volatile<u32>, driver.size / 4)
|
||||
};
|
||||
|
||||
let icr = ixgbe[IXGBE_EICR].read();
|
||||
if icr != 0 {
|
||||
// clear it
|
||||
ixgbe[IXGBE_EICR].write(icr);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
if irq {
|
||||
let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64);
|
||||
let mut sockets = self.sockets.lock();
|
||||
match self.iface.lock().poll(&mut sockets, timestamp) {
|
||||
Ok(_) => {
|
||||
SOCKET_ACTIVITY.notify_all();
|
||||
}
|
||||
Err(err) => {
|
||||
debug!("poll got err {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return irq;
|
||||
}
|
||||
|
||||
fn device_type(&self) -> DeviceType {
|
||||
DeviceType::Net
|
||||
}
|
||||
}
|
||||
|
||||
impl NetDriver for IXGBEInterface {
|
||||
fn get_mac(&self) -> EthernetAddress {
|
||||
self.iface.lock().ethernet_addr()
|
||||
}
|
||||
|
||||
fn get_ifname(&self) -> String {
|
||||
format!("ixgbe")
|
||||
}
|
||||
|
||||
fn ipv4_address(&self) -> Option<Ipv4Address> {
|
||||
self.iface.lock().ipv4_address()
|
||||
}
|
||||
|
||||
fn sockets(&self) -> MutexGuard<SocketSet<'static, 'static, 'static>, SpinNoIrq> {
|
||||
self.sockets.lock()
|
||||
}
|
||||
|
||||
fn poll(&self) {
|
||||
let timestamp = Instant::from_millis(crate::trap::uptime_msec() as i64);
|
||||
let mut sockets = self.sockets.lock();
|
||||
match self.iface.lock().poll(&mut sockets, timestamp) {
|
||||
Ok(_) => {
|
||||
SOCKET_ACTIVITY.notify_all();
|
||||
}
|
||||
Err(err) => {
|
||||
debug!("poll got err {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct IXGBESendDesc {
|
||||
addr: u64,
|
||||
len: u16,
|
||||
cso: u8,
|
||||
cmd: u8,
|
||||
status: u8,
|
||||
css: u8,
|
||||
special: u8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct IXGBERecvDesc {
|
||||
addr: u64,
|
||||
len: u16,
|
||||
frag_chksum: u16,
|
||||
status_error: u16,
|
||||
vlan_tag: u16,
|
||||
}
|
||||
|
||||
pub struct IXGBERxToken(Vec<u8>);
|
||||
pub struct IXGBETxToken(IXGBEDriver);
|
||||
|
||||
impl<'a> phy::Device<'a> for IXGBEDriver {
|
||||
type RxToken = IXGBERxToken;
|
||||
type TxToken = IXGBETxToken;
|
||||
|
||||
fn receive(&'a mut self) -> Option<(Self::RxToken, Self::TxToken)> {
|
||||
let driver = self.0.lock();
|
||||
|
||||
if let None = active_table().get_entry(driver.header) {
|
||||
let mut current_addr = driver.header;
|
||||
while current_addr < driver.header + driver.size {
|
||||
active_table().map_if_not_exists(current_addr, current_addr);
|
||||
current_addr = current_addr + PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
let ixgbe =
|
||||
unsafe { slice::from_raw_parts_mut(driver.header as *mut Volatile<u32>, driver.size / 4) };
|
||||
|
||||
let send_queue_size = PAGE_SIZE / size_of::<IXGBESendDesc>();
|
||||
let send_queue = unsafe {
|
||||
slice::from_raw_parts_mut(driver.send_page as *mut IXGBESendDesc, send_queue_size)
|
||||
};
|
||||
let tdt = ixgbe[IXGBE_TDT].read();
|
||||
let index = (tdt as usize) % send_queue_size;
|
||||
let send_desc = &mut send_queue[index];
|
||||
|
||||
let recv_queue_size = PAGE_SIZE / size_of::<IXGBERecvDesc>();
|
||||
let mut recv_queue = unsafe {
|
||||
slice::from_raw_parts_mut(driver.recv_page as *mut IXGBERecvDesc, recv_queue_size)
|
||||
};
|
||||
let mut rdt = ixgbe[IXGBE_RDT].read();
|
||||
let index = (rdt as usize + 1) % recv_queue_size;
|
||||
let recv_desc = &mut recv_queue[index];
|
||||
|
||||
//let transmit_avail = driver.first_trans || (*send_desc).status & 1 != 0;
|
||||
let transmit_avail = true;
|
||||
// Ignore packet spanning multiple descriptor
|
||||
let receive_avail = (*recv_desc).status_error & 1 != 0;
|
||||
|
||||
if transmit_avail && receive_avail {
|
||||
let buffer = unsafe {
|
||||
slice::from_raw_parts(
|
||||
driver.recv_buffers[index] as *const u8,
|
||||
recv_desc.len as usize,
|
||||
)
|
||||
};
|
||||
|
||||
recv_desc.status_error = recv_desc.status_error & !1;
|
||||
|
||||
rdt = (rdt + 1) % recv_queue_size as u32;
|
||||
ixgbe[IXGBE_RDT].write(rdt);
|
||||
|
||||
Some((IXGBERxToken(buffer.to_vec()), IXGBETxToken(self.clone())))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn transmit(&'a mut self) -> Option<Self::TxToken> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn capabilities(&self) -> DeviceCapabilities {
|
||||
let mut caps = DeviceCapabilities::default();
|
||||
caps.max_transmission_unit = 1536;
|
||||
caps.max_burst_size = Some(64);
|
||||
caps
|
||||
}
|
||||
}
|
||||
|
||||
impl phy::RxToken for IXGBERxToken {
|
||||
fn consume<R, F>(self, _timestamp: Instant, f: F) -> Result<R>
|
||||
where
|
||||
F: FnOnce(&[u8]) -> Result<R>,
|
||||
{
|
||||
f(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl phy::TxToken for IXGBETxToken {
|
||||
fn consume<R, F>(self, _timestamp: Instant, len: usize, f: F) -> Result<R>
|
||||
where
|
||||
F: FnOnce(&mut [u8]) -> Result<R>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
struct IXGBEStatus : u32 {
|
||||
const LANID0 = 1 << 2;
|
||||
const LABID1 = 1 << 3;
|
||||
const LINK_UP = 1 << 7;
|
||||
const NUM_VFS1 = 1 << 10;
|
||||
const NUM_VFS2 = 1 << 11;
|
||||
const NUM_VFS4 = 1 << 12;
|
||||
const NUM_VFS8 = 1 << 13;
|
||||
const NUM_VFS16 = 1 << 14;
|
||||
const NUM_VFS32 = 1 << 15;
|
||||
const NUM_VFS64 = 1 << 16;
|
||||
const IOV = 1 << 18;
|
||||
const PCIE_MASTER_ENABLE = 1 << 19;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ixgbe_init(header: usize, size: usize) {
|
||||
info!("Probing ixgbe");
|
||||
assert_eq!(size_of::<IXGBESendDesc>(), 16);
|
||||
assert_eq!(size_of::<IXGBERecvDesc>(), 16);
|
||||
|
||||
let send_page = unsafe {
|
||||
HEAP_ALLOCATOR.alloc_zeroed(Layout::from_size_align(PAGE_SIZE, PAGE_SIZE).unwrap())
|
||||
} as usize;
|
||||
let recv_page = unsafe {
|
||||
HEAP_ALLOCATOR.alloc_zeroed(Layout::from_size_align(PAGE_SIZE, PAGE_SIZE).unwrap())
|
||||
} as usize;
|
||||
let send_page_pa = active_table().get_entry(send_page).unwrap().target();
|
||||
let recv_page_pa = active_table().get_entry(recv_page).unwrap().target();
|
||||
let send_queue_size = PAGE_SIZE / size_of::<IXGBESendDesc>();
|
||||
let recv_queue_size = PAGE_SIZE / size_of::<IXGBERecvDesc>();
|
||||
let mut send_queue =
|
||||
unsafe { slice::from_raw_parts_mut(send_page as *mut IXGBESendDesc, send_queue_size) };
|
||||
let mut recv_queue =
|
||||
unsafe { slice::from_raw_parts_mut(recv_page as *mut IXGBERecvDesc, recv_queue_size) };
|
||||
// randomly generated
|
||||
let mac: [u8; 6] = [0x54, 0x51, 0x9F, 0x71, 0xC0, 0x3C];
|
||||
|
||||
let mut current_addr = header;
|
||||
while current_addr < header + size {
|
||||
active_table().map_if_not_exists(current_addr, current_addr);
|
||||
current_addr = current_addr + PAGE_SIZE;
|
||||
}
|
||||
|
||||
let ixgbe = unsafe { slice::from_raw_parts_mut(header as *mut Volatile<u32>, size / 4) };
|
||||
debug!(
|
||||
"status before setup: {:#?}",
|
||||
IXGBEStatus::from_bits_truncate(ixgbe[IXGBE_STATUS].read())
|
||||
);
|
||||
|
||||
// 4.6.3 Initialization Sequence
|
||||
|
||||
// 4.6.3.1 Interrupts During Initialization
|
||||
// mask all interrupts
|
||||
ixgbe[IXGBE_EIMC].write(!0);
|
||||
ixgbe[IXGBE_EIMC1].write(!0);
|
||||
ixgbe[IXGBE_EIMC2].write(!0);
|
||||
|
||||
// reset: LRST | RST
|
||||
ixgbe[IXGBE_CTRL].write(1 << 3 | 1 << 26);
|
||||
while ixgbe[IXGBE_CTRL].read() & (1 << 3 | 1 << 26) != 0 {}
|
||||
|
||||
// mask all interrupts
|
||||
ixgbe[IXGBE_EIMC].write(!0);
|
||||
ixgbe[IXGBE_EIMC1].write(!0);
|
||||
ixgbe[IXGBE_EIMC2].write(!0);
|
||||
|
||||
// 4.6.3.2 Global Reset and General Configuration
|
||||
// no flow control
|
||||
for reg in (IXGBE_FCTTV..IXGBE_FCTTV_END).step_by(4) {
|
||||
ixgbe[reg].write(0);
|
||||
}
|
||||
for reg in (IXGBE_FCRTL..IXGBE_FCRTL_END).step_by(4) {
|
||||
ixgbe[reg].write(0);
|
||||
}
|
||||
for reg in (IXGBE_FCRTH..IXGBE_FCRTH_END).step_by(4) {
|
||||
ixgbe[reg].write(0);
|
||||
}
|
||||
ixgbe[IXGBE_FCRTV].write(0);
|
||||
ixgbe[IXGBE_FCCFG].write(0);
|
||||
|
||||
// Auto-Read Done
|
||||
while ixgbe[IXGBE_EEC].read() & (1 << 9) == 0 {}
|
||||
|
||||
// DMA Init Done
|
||||
while ixgbe[IXGBE_RDRXCTL].read() & (1 << 3) == 0 {}
|
||||
|
||||
// Read MAC Address
|
||||
let ral = ixgbe[IXGBE_RAL].read();
|
||||
let rah = ixgbe[IXGBE_RAH].read();
|
||||
let mac: [u8; 6] = [
|
||||
ral as u8,
|
||||
(ral >> 8) as u8,
|
||||
(ral >> 16) as u8,
|
||||
(ral >> 24) as u8,
|
||||
rah as u8,
|
||||
(rah >> 8) as u8,
|
||||
];
|
||||
debug!("mac {:x?}", mac);
|
||||
|
||||
let mut driver = IXGBE {
|
||||
header,
|
||||
size,
|
||||
mac: EthernetAddress::from_bytes(&mac),
|
||||
send_page,
|
||||
send_buffers: Vec::with_capacity(send_queue_size),
|
||||
recv_page,
|
||||
recv_buffers: Vec::with_capacity(recv_queue_size),
|
||||
first_trans: true,
|
||||
};
|
||||
|
||||
// 4.6.7 Receive Initialization
|
||||
// PFUTA
|
||||
for i in IXGBE_PFUTA..IXGBE_PFUTA_END {
|
||||
ixgbe[i].write(0);
|
||||
}
|
||||
// VFTA
|
||||
for i in IXGBE_VFTA..IXGBE_VFTA_END {
|
||||
ixgbe[i].write(0);
|
||||
}
|
||||
// PFVLVF
|
||||
for i in IXGBE_PFVLVF..IXGBE_PFVLVF_END {
|
||||
ixgbe[i].write(0);
|
||||
}
|
||||
// MPSAR
|
||||
for i in IXGBE_MPSAR..IXGBE_MPSAR_END {
|
||||
ixgbe[i].write(0);
|
||||
}
|
||||
// PFVLVFB
|
||||
for i in IXGBE_PFVLVFB..IXGBE_PFVLVFB_END {
|
||||
ixgbe[i].write(0);
|
||||
}
|
||||
// MTA
|
||||
for i in IXGBE_MTA..IXGBE_MTA_END {
|
||||
ixgbe[i].write(0);
|
||||
}
|
||||
|
||||
// Setup receive queue 0
|
||||
ixgbe[IXGBE_RDBAL].write(recv_page_pa as u32); // RDBAL
|
||||
ixgbe[IXGBE_RDBAH].write((recv_page_pa >> 32) as u32); // RDBAH
|
||||
ixgbe[IXGBE_RDLEN].write(PAGE_SIZE as u32); // RDLEN
|
||||
|
||||
// Legacy descriptor, default SRRCTL is ok
|
||||
// BAM, Accept Broadcast packets
|
||||
ixgbe[IXGBE_FCTRL].write(ixgbe[IXGBE_FCTRL].read() | (1 << 10));
|
||||
|
||||
for i in 0..recv_queue_size {
|
||||
let buffer_page = unsafe {
|
||||
HEAP_ALLOCATOR.alloc_zeroed(Layout::from_size_align(PAGE_SIZE, PAGE_SIZE).unwrap())
|
||||
} as usize;
|
||||
let buffer_page_pa = active_table().get_entry(buffer_page).unwrap().target();
|
||||
recv_queue[i].addr = buffer_page_pa as u64;
|
||||
driver.recv_buffers.push(buffer_page);
|
||||
}
|
||||
|
||||
ixgbe[IXGBE_RDH].write(0); // RDH
|
||||
ixgbe[IXGBE_RXDCTL].write(ixgbe[IXGBE_RXDCTL].read() | (1 << 25)); // enable queue
|
||||
while ixgbe[IXGBE_RXDCTL].read() | (1 << 25) == 0 {} // wait for it
|
||||
ixgbe[IXGBE_RDT].write((recv_queue_size - 1) as u32); // RDT
|
||||
|
||||
// all queues are setup
|
||||
// halt receive data path RX_DIS
|
||||
ixgbe[IXGBE_SECRXCTRL].write(ixgbe[IXGBE_SECRXCTRL].read() | (1 << 1));
|
||||
while ixgbe[IXGBE_SECRXSTAT].read() & (1 << 0) == 0 {} // poll
|
||||
// enable receive
|
||||
ixgbe[IXGBE_RXCTRL].write(ixgbe[IXGBE_RXCTRL].read() | (1 << 0));
|
||||
// resume receive data path RX_DIS
|
||||
ixgbe[IXGBE_SECRXCTRL].write(ixgbe[IXGBE_SECRXCTRL].read() & !(1 << 1));
|
||||
// no snoop enable
|
||||
ixgbe[IXGBE_CTRL_EXT].write(ixgbe[IXGBE_CTRL_EXT].read() | (1 << 16));
|
||||
// clear bit 12
|
||||
ixgbe[IXGBE_DCA_RXCTRL].write(ixgbe[IXGBE_DCA_RXCTRL].read() & !(1 << 12));
|
||||
|
||||
// enable interrupts
|
||||
// map Rx0 and Tx0 to interrupt 0
|
||||
ixgbe[IXGBE_IVAR].write(0b00000000_00000000_10000000_10000000);
|
||||
|
||||
// clear all interrupt
|
||||
ixgbe[IXGBE_EICR].write(!0);
|
||||
// unmask tx/rx interrupts
|
||||
ixgbe[IXGBE_EIMS].write(1);
|
||||
|
||||
debug!(
|
||||
"status after setup: {:#?}",
|
||||
IXGBEStatus::from_bits_truncate(ixgbe[IXGBE_STATUS].read())
|
||||
);
|
||||
|
||||
let net_driver = IXGBEDriver(Arc::new(Mutex::new(driver)));
|
||||
|
||||
let ethernet_addr = EthernetAddress::from_bytes(&mac);
|
||||
let ip_addrs = [IpCidr::new(IpAddress::v4(10, 0, 0, 2), 24)];
|
||||
let neighbor_cache = NeighborCache::new(BTreeMap::new());
|
||||
let iface = EthernetInterfaceBuilder::new(net_driver.clone())
|
||||
.ethernet_addr(ethernet_addr)
|
||||
.ip_addrs(ip_addrs)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
.finalize();
|
||||
|
||||
let ixgbe_iface = IXGBEInterface {
|
||||
iface: Mutex::new(iface),
|
||||
sockets: Mutex::new(SocketSet::new(vec![])),
|
||||
driver: net_driver.clone(),
|
||||
};
|
||||
|
||||
let driver = Arc::new(ixgbe_iface);
|
||||
DRIVERS.write().push(driver.clone());
|
||||
NET_DRIVERS.write().push(driver);
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
pub mod virtio_net;
|
||||
pub mod e1000;
|
||||
pub mod e1000;
|
||||
pub mod ixgbe;
|
Loading…
Reference in new issue