Skip to content

Commit

Permalink
Add ixgbe driver to support the Intel 82599 NIC, and support language…
Browse files Browse the repository at this point in the history
…-level NIC virtualization (theseus-os#332)

This commit also generally refactors networking driver code to deduplicate it and condense shared functionality. Below is a description of changes to certain crates.

* `device_manager` - added detection of the 82599 NIC

* `nic_initialization` - removed register types and replaced with a register struct

* `nic_queues` - Added QueueRegister traits so that queues can store their own registers, and we can create these queue objects for all drivers. Refactored common code between the NIC drivers into send and receive functions for the queue.

* `intel_ethernet` - added advanced transmit descriptor and removed register types since we now have a register trait.

* `e1000` - moved register struct definitions to a separate file. Registers are divided into four sets so that we can separate the Rx and Tx registers.

* `physcial_nic` - a NIC must implement this trait if it wants to support virtualization. This trait defines functions that return Rx and Tx queues to the original NIC when dropped.

* `virtual_nic` - a struct which contains a set of queues, and implements the `NetworkInterfaceCard` trait. Its drop handler returns the queues to the physical NIC.
  • Loading branch information
Ramla-I authored Dec 21, 2020
1 parent 777b688 commit 4a124f4
Show file tree
Hide file tree
Showing 27 changed files with 3,277 additions and 290 deletions.
60 changes: 60 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ exclude = [
"applications/test_wait_queue",
# "applications/test_panic",
# "applications/unwind_test",

"applications/test_ixgbe",
"libtheseus",
]

Expand Down
24 changes: 24 additions & 0 deletions applications/test_ixgbe/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "test_ixgbe"
version = "0.1.0"
authors = ["Ramla Ijaz <[email protected]>"]
build = "../../build.rs"

[dependencies]

[dependencies.log]
version = "0.4.8"

[dependencies.terminal_print]
path = "../../kernel/terminal_print"

[dependencies.ixgbe]
path = "../../kernel/ixgbe"

[dependencies.spawn]
path = "../../kernel/spawn"

[dependencies.network_interface_card]
path = "../../kernel/network_interface_card"


74 changes: 74 additions & 0 deletions applications/test_ixgbe/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//! Application which checks the functionality of the ixgbe driver by creating multiple virtual NICs
//! and sending and receiving packets with them.
//!
//! For the receiving functionality, you will have to set up a program on another machine that
//! sends packets to the IP addresses assigned to the virtual NICs.
//! Since we are not going through the network stack, I manually add the (mac address, ip address) pair
//! to the ARP table of the sending machine: "sudo arp -i interface_name -s ip_address mac_address"
//! e.g."sudo arp -i eno1 -s 192.168.0.20 0c:c4:7a:d2:ee:1a"
#![no_std]
#[macro_use] extern crate alloc;
// #[macro_use] extern crate log;
#[macro_use] extern crate terminal_print;
extern crate network_interface_card;
extern crate ixgbe;
extern crate spawn;

use alloc::vec::Vec;
use alloc::string::String;
use ixgbe::{
virtual_function, get_ixgbe_nics_list,
test_packets::create_raw_packet,
};
use network_interface_card::NetworkInterfaceCard;

pub fn main(_args: Vec<String>) -> isize {
println!("Ixgbe test application");

match rmain() {
Ok(()) => {
println!("Ixgbe test was successful");
return 0;
}
Err(e) => {
println!("Ixgbe test failed with error : {:?}", e);
return -1;
}
}
}

fn rmain() -> Result<(), &'static str> {

let dev_id = {
let ixgbe_devs = get_ixgbe_nics_list().ok_or("Ixgbe NICs list not initialized")?;
if ixgbe_devs.is_empty() { return Err("No ixgbe device available"); }
ixgbe_devs[0].lock().device_id()
};

let num_nics = 63;
let mut nics = Vec::with_capacity(num_nics);

for i in 0..num_nics {
nics.push(virtual_function::create_virtual_nic(dev_id, vec!([192,168,0,i as u8 + 14]), 0, 0)?);
}

for nic in &mut nics {
let mac_address = nic.mac_address();
let buffer = create_raw_packet(&[0x0, 0x1F, 0xC6, 0x9C, 0xB2, 0x07], &mac_address, &[1;46])?;
nic.send_packet(buffer)?;
}

// loop {
// for nic in &mut nics {
// nic.poll_receive()?;
// if let Some(_buffer) = nic.get_received_frame() {
// println!("Received packet on vnic {}", nic.id());
// }
// }
// }

Ok(())
}


3 changes: 3 additions & 0 deletions kernel/device_manager/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ path = "../network_manager"
[dependencies.ethernet_smoltcp_device]
path = "../ethernet_smoltcp_device"

[dependencies.ixgbe]
path = "../ixgbe"


[lib]
crate-type = ["rlib"]
46 changes: 44 additions & 2 deletions kernel/device_manager/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ extern crate storage_manager;
extern crate network_manager;
extern crate ethernet_smoltcp_device;
extern crate mpmc;

extern crate ixgbe;
extern crate alloc;

use mpmc::Queue;
use event_types::Event;
use memory::MemoryManagementInfo;
use ethernet_smoltcp_device::EthernetNetworkInterface;
use network_manager::add_to_network_interfaces;

use alloc::vec::Vec;

/// A randomly chosen IP address that must be outside of the DHCP range.. // TODO FIXME: use DHCP to acquire IP
const DEFAULT_LOCAL_IP: &'static str = "10.0.2.15/24"; // the default QEMU user-slirp network gives IP addresses of "10.0.2.*"
Expand Down Expand Up @@ -56,7 +57,11 @@ pub fn init(key_producer: Queue<Event>, mouse_producer: Queue<Event>) -> Result<
debug!("Found pci device: {:?}", dev);
}

// store all the initialized ixgbe NICs here to be added to the network interface list
let mut ixgbe_devs = Vec::new();

// Iterate over all PCI devices and initialize the drivers for the devices we support.

for dev in pci::pci_device_iter() {
// Currently we skip Bridge devices, since we have no use for them yet.
if dev.class == 0x06 {
Expand Down Expand Up @@ -86,12 +91,49 @@ pub fn init(key_producer: Queue<Event>, mouse_producer: Queue<Event>) -> Result<
add_to_network_interfaces(e1000_interface);
continue;
}
if dev.vendor_id == ixgbe::INTEL_VEND && dev.device_id == ixgbe::INTEL_82599 {
info!("ixgbe PCI device found at: {:?}", dev.location);

// Initialization parameters of the NIC.
// These can be changed according to the requirements specified in the ixgbe init function.
const VIRT_ENABLED: bool = true;
const RSS_ENABLED: bool = false;
const RX_DESCS: u16 = 8;
const TX_DESCS: u16 = 8;

let ixgbe_nic = ixgbe::IxgbeNic::init(
dev,
dev.location,
ixgbe::LinkSpeedMbps::LS10000,
VIRT_ENABLED,
None,
RSS_ENABLED,
ixgbe::RxBufferSizeKiB::Buffer8KiB,
RX_DESCS,
TX_DESCS
)?;

ixgbe_devs.push(ixgbe_nic);
continue;
}

// here: check for and initialize other ethernet cards
}

warn!("Ignoring PCI device with no handler. {:?}", dev);
}

// Once all the NICs have been initialized, we can store them and add them to the list of network interfaces.
let ixgbe_nics = ixgbe::IXGBE_NICS.call_once(|| ixgbe_devs);
for ixgbe_nic_ref in ixgbe_nics.iter() {
let ixgbe_interface = EthernetNetworkInterface::new_ipv4_interface(
ixgbe_nic_ref,
DEFAULT_LOCAL_IP,
&DEFAULT_GATEWAY_IP
)?;
add_to_network_interfaces(ixgbe_interface);
}

// Convenience notification for developers to inform them of no networking devices
if network_manager::NETWORK_INTERFACES.lock().is_empty() {
warn!("Note: no network devices found on this system.");
Expand Down
Loading

0 comments on commit 4a124f4

Please sign in to comment.