Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ pub enum ConfigError {
InvalidIpAddress(String),
#[error("Invalid mask length in interface address: {0}")]
InvalidMaskLength(String),
#[error("Invalid configuration: {0}")]
Invalid(String),
}

/// Result-like type for configurations
Expand Down
45 changes: 26 additions & 19 deletions dataplane/src/drivers/kernel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};

use net::buffer::test_buffer::TestBuffer;
use net::packet::{InterfaceId, Packet};
use net::interface::InterfaceIndex;
use net::packet::{DoneReason, Packet};
use netdev::Interface;
use pipeline::{DynPipeline, NetworkFunction};
use tracing::{debug, error, info, trace, warn};
Expand All @@ -50,18 +51,18 @@ type WorkerChans = (Vec<WorkerTx>, WorkerRx);

/// Simple representation of a kernel interface.
pub struct Kif {
ifindex: u32, /* ifindex of interface */
token: Token, /* token for polling */
name: String, /* name of interface */
sock: RawPacketStream, /* packet socket */
raw_fd: RawFd, /* raw desc of packet socket */
ifindex: InterfaceIndex, /* ifindex of interface */
token: Token, /* token for polling */
name: String, /* name of interface */
sock: RawPacketStream, /* packet socket */
raw_fd: RawFd, /* raw desc of packet socket */
}

impl Kif {
/// Create a kernel interface entry. Each interface gets a [`Token`] assigned
/// and a packet socket opened, which gets registered in a poller to detect
/// activity.
fn new(ifindex: u32, name: &str, token: Token) -> io::Result<Self> {
fn new(ifindex: InterfaceIndex, name: &str, token: Token) -> io::Result<Self> {
let mut sock = RawPacketStream::new().map_err(|e| {
error!("Failed to open raw sock for interface {name}: {e}");
e
Expand Down Expand Up @@ -101,7 +102,7 @@ impl KifTable {
}
/// Add a kernel interface 'representor' to this table. For each interface, a packet socket
/// is created and a poller [`Token`] assigned.
pub fn add(&mut self, ifindex: u32, name: &str) -> io::Result<()> {
pub fn add(&mut self, ifindex: InterfaceIndex, name: &str) -> io::Result<()> {
debug!("Adding interface '{name}'...");
let token = Token(self.next_token);
let interface = Kif::new(ifindex, name, token)?;
Expand All @@ -122,29 +123,27 @@ impl KifTable {
self.by_token.get_mut(&token)
}

/// Get a mutable reference to the [`Kif`] with the indicated ifindex.
/// TODO: replace this linear search with a hash lookup if needed.
pub fn get_mut_by_index(&mut self, ifindex: u32) -> Option<&mut Kif> {
/// Get a mutable reference to the [`Kif`] with the indicated ifindex
/// Todo: replace this linear search with a hash lookup
pub fn get_mut_by_index(&mut self, ifindex: InterfaceIndex) -> Option<&mut Kif> {
self.by_token
.values_mut()
.find(|kif| kif.ifindex == ifindex)
}
}

/// Get the ifindex of the interface with the given name.
fn get_interface_ifindex(interfaces: &[Interface], name: &str) -> Option<u32> {
fn get_interface_ifindex(interfaces: &[Interface], name: &str) -> Option<InterfaceIndex> {
interfaces
.iter()
.position(|interface| interface.name == name)
.map(|pos| interfaces[pos].index)
.and_then(|pos| InterfaceIndex::try_new(interfaces[pos].index).ok())
}

/// Build a table of kernel interfaces to receive packets from (or send to).
/// Interfaces of interest are indicated by --interface INTERFACE in the command line.
/// Argument --interface ANY|any instructs the driver to capture on all interfaces.
fn build_kif_table(
args: impl IntoIterator<Item = impl AsRef<str> + Clone>,
) -> io::Result<KifTable> {
fn build_kif_table(args: impl IntoIterator<Item = impl AsRef<str>>) -> io::Result<KifTable> {
/* learn about existing kernel network interfaces. We need these to know their ifindex */
let interfaces = netdev::get_interfaces();

Expand All @@ -162,7 +161,15 @@ fn build_kif_table(
if ifnames.len() == 1 && ifnames[0].eq_ignore_ascii_case("ANY") {
/* use all interfaces */
for interface in &interfaces {
if let Err(e) = kiftable.add(interface.index, &interface.name) {
let if_index = match InterfaceIndex::try_new(interface.index) {
Ok(if_index) => if_index,
Err(e) => match e {
net::interface::InterfaceIndexError::Zero => {
return Err(io::Error::new(io::ErrorKind::InvalidData, e));
}
},
};
if let Err(e) = kiftable.add(if_index, &interface.name) {
error!("Skipping interface '{}': {e}", interface.name);
}
}
Expand Down Expand Up @@ -331,7 +338,7 @@ impl DriverKernel {
// 1) Drain processed packets coming back from workers, serialize + TX
while let Ok(mut pkt) = from_workers.try_recv() {
// choose outgoing interface from meta
let oif_id_opt = pkt.get_meta().oif.as_ref().map(InterfaceId::get_id);
let oif_id_opt = pkt.get_meta().oif;
if let Some(oif_id) = oif_id_opt {
if let Some(outgoing) = kiftable.get_mut_by_index(oif_id) {
match pkt.serialize() {
Expand Down Expand Up @@ -423,7 +430,7 @@ impl DriverKernel {
let buf = TestBuffer::from_raw_data(&raw[..bytes]);
match Packet::new(buf) {
Ok(mut incoming) => {
incoming.get_meta_mut().iif = InterfaceId::new(interface.ifindex);
incoming.get_meta_mut().iif = Some(interface.ifindex);
pkts.push(Box::new(incoming));
}
Err(e) => {
Expand Down
8 changes: 4 additions & 4 deletions dataplane/src/packet_processor/egress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ use net::{
};

use net::headers::TryEthMut;
use net::interface::InterfaceIndex;
use net::packet::{DoneReason, Packet};
use pipeline::NetworkFunction;

use routing::interfaces::iftablerw::IfTableReader;
use routing::interfaces::interface::{IfIndex, IfState, IfType, Interface};
use routing::interfaces::interface::{IfState, IfType, Interface};
use routing::{atable::atablerw::AtableReader, interfaces::iftable::IfTable};

use tracectl::trace_target;
Expand Down Expand Up @@ -122,7 +123,7 @@ impl Egress {
&self,
packet: &mut Packet<Buf>,
addr: IpAddr,
ifindex: IfIndex,
ifindex: InterfaceIndex,
) -> Option<DestinationMac> {
let nfi = &self.name;

Expand Down Expand Up @@ -153,7 +154,7 @@ impl Egress {

fn resolve_next_mac<Buf: PacketBufferMut>(
&self,
ifindex: IfIndex,
ifindex: InterfaceIndex,
packet: &mut Packet<Buf>,
) -> Option<DestinationMac> {
let nfi = &self.name;
Expand Down Expand Up @@ -181,7 +182,6 @@ impl Egress {
};

/* resolve destination mac */
let oif = oif.get_id();
let Some(dst_mac) = self.resolve_next_mac(oif, packet) else {
// we could not figure out the destination MAC.
// resolve_next_mac() already calls packet.done()
Expand Down
22 changes: 15 additions & 7 deletions dataplane/src/packet_processor/ingress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl Ingress {
match &interface.attachment {
Some(Attachment::VRF(fibr)) => {
let Some(vrfid) = fibr.get_id().map(|x| x.as_u32()) else {
/* we may ocassionaly not be able to enter a fib on reconfigs */
/* we may occasionally not be able to enter a fib on reconfigs */
warn!("Failed to access fib on ingress!");
packet.done(DoneReason::Unroutable);
return;
Expand Down Expand Up @@ -145,6 +145,7 @@ impl Ingress {
}

impl<Buf: PacketBufferMut> NetworkFunction<Buf> for Ingress {
#[tracing::instrument(level = "trace", skip(self, input))]
fn process<'a, Input: Iterator<Item = Packet<Buf>> + 'a>(
&'a mut self,
input: Input,
Expand All @@ -154,12 +155,19 @@ impl<Buf: PacketBufferMut> NetworkFunction<Buf> for Ingress {
let nfi = self.name();
if !packet.is_done() {
if let Some(iftable) = self.iftr.enter() {
let iif = packet.get_meta().iif.get_id();
if let Some(interface) = iftable.get_interface(iif) {
self.interface_ingress(interface, &mut packet);
} else {
warn!("{nfi}: unknown incoming interface {iif}");
packet.done(DoneReason::InterfaceUnknown);
match packet.get_meta().iif {
None => {
warn!("no incoming interface for packet");
}
Some(iif) => match iftable.get_interface(iif) {
None => {
warn!("{nfi}: unknown incoming interface {iif}");
packet.done(DoneReason::InterfaceUnknown);
}
Some(interface) => {
self.interface_ingress(interface, &mut packet);
}
},
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions dataplane/src/packet_processor/ipforward.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::net::IpAddr;
use tracing::{debug, error, trace, warn};

use net::headers::{TryHeadersMut, TryIpv4Mut, TryIpv6Mut};
use net::packet::{DoneReason, InterfaceId, Packet};
use net::packet::{DoneReason, Packet};
use net::{buffer::PacketBufferMut, checksum::Checksum};
use pipeline::NetworkFunction;

Expand All @@ -20,12 +20,12 @@ use routing::fib::fibtable::FibTableReader;
use routing::fib::fibtype::FibId;

use routing::evpn::Vtep;
use routing::interfaces::interface::IfIndex;
use routing::rib::encapsulation::{Encapsulation, VxlanEncapsulation};
use routing::rib::vrf::VrfId;

use net::headers::Headers;
use net::headers::Net;
use net::interface::InterfaceIndex;
use net::ip::NextHeader;
use net::ipv4::Ipv4;
use net::ipv4::UnicastIpv4Addr;
Expand Down Expand Up @@ -123,7 +123,7 @@ impl IpForwarder {
&self,
packet: &mut Packet<Buf>,
fibtable: &FibTable,
_ifindex: IfIndex, /* we get it from metadata */
_ifindex: InterfaceIndex, /* we get it from metadata */
) {
let nfi = &self.name;

Expand Down Expand Up @@ -313,7 +313,7 @@ impl IpForwarder {
) {
let meta = packet.get_meta_mut();
if let Some(ifindex) = egress.ifindex() {
meta.oif = Some(InterfaceId::new(*ifindex));
meta.oif = Some(*ifindex);
}
if let Some(addr) = egress.address() {
meta.nh_addr = Some(*addr);
Expand Down
12 changes: 10 additions & 2 deletions mgmt/src/processor/confbuild/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::processor::confbuild::namegen::VpcInterfacesNames;
use std::collections::HashMap;
use tracing::{debug, error};

use net::interface::{Interface, InterfaceName, Mtu};
use net::interface::{Interface, InterfaceIndex, InterfaceName, Mtu};
use routing::interfaces::interface::{AttachConfig, IfDataEthernet, IfState, IfType};

use config::internal::interfaces::interface::InterfaceConfig;
Expand Down Expand Up @@ -61,7 +61,15 @@ fn build_router_interface_config(
vrfid: VrfId,
) -> Result<RouterInterfaceConfig, ConfigError> {
let name = kiface.name.as_str();
let mut new = RouterInterfaceConfig::new(name, kiface.index);
let ifindex = match InterfaceIndex::try_new(kiface.index) {
Ok(ifindex) => ifindex,
Err(err) => {
let msg = format!("{err}");
error!("failed to build router interface: {err}");
return Err(ConfigError::Invalid(msg));
}
};
let mut new = RouterInterfaceConfig::new(name, ifindex);

// set admin status -- currently from oper
let status = if kiface.is_up() {
Expand Down
14 changes: 12 additions & 2 deletions net/src/packet/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ use crate::udp::{Udp, UdpEncap};

use crate::buffer::PacketBufferMut;
use crate::checksum::Checksum;
use crate::packet::{BridgeDomain, DoneReason, InterfaceId, InvalidPacket, Packet, PacketMeta};
#[allow(deprecated)]
use crate::packet::InterfaceId;
use crate::packet::{BridgeDomain, DoneReason, InvalidPacket, Packet, PacketMeta};
use std::fmt::{Display, Formatter};

impl Display for Eth {
Expand Down Expand Up @@ -217,6 +219,7 @@ fn fmt_opt<T: Display>(
}
}
}
#[allow(deprecated)]
impl Display for InterfaceId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.get_id())
Expand All @@ -230,7 +233,14 @@ impl Display for BridgeDomain {
impl Display for PacketMeta {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writeln!(f, " metadata:")?;
write!(f, " iif: {}", self.iif.get_id())?;
match self.iif {
None => {
write!(f, " iif: None")?;
}
Some(iif) => {
write!(f, " iif: {iif}")?;
}
}
fmt_opt(f, " oif", self.oif, true)?;

writeln!(f, " bcast: {}", self.is_l2bcast())?;
Expand Down
14 changes: 8 additions & 6 deletions net/src/packet/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#![allow(missing_docs)] // TODO

use crate::interface::InterfaceIndex;
use crate::vxlan::Vni;
use bitflags::bitflags;
use concurrency::sync::Arc;
Expand All @@ -16,9 +17,10 @@ use tracing::error;
/// Every VRF is univocally identified with a numerical VRF id
pub type VrfId = u32;

#[deprecated = "use InterfaceIndex from net"]
#[derive(Debug, Default, Copy, Clone)]
pub struct InterfaceId(u32);
#[allow(unused)]
#[allow(deprecated)]
impl InterfaceId {
#[must_use]
pub fn new(val: u32) -> Self {
Expand Down Expand Up @@ -130,11 +132,11 @@ bitflags! {
#[derive(Debug, Default, Clone)]
pub struct PacketMeta {
flags: MetaFlags,
pub iif: InterfaceId, /* incoming interface - set early */
pub oif: Option<InterfaceId>, /* outgoing interface - set late */
pub nh_addr: Option<IpAddr>, /* IP address of next-hop */
pub vrf: Option<VrfId>, /* for IP packet, the VRF to use to route it */
pub bridge: Option<BridgeDomain>, /* the bridge domain to forward the packet to */
pub iif: Option<InterfaceIndex>, /* incoming interface - set early */
pub oif: Option<InterfaceIndex>, /* outgoing interface - set late */
pub nh_addr: Option<IpAddr>, /* IP address of next-hop */
pub vrf: Option<VrfId>, /* for IP packet, the VRF to use to route it */
pub bridge: Option<BridgeDomain>, /* the bridge domain to forward the packet to */
pub done: Option<DoneReason>, /* if Some, the reason why a packet was marked as done, including delivery to NF */
pub src_vpcd: Option<VpcDiscriminant>, /* the vpc discriminant of a received encapsulated packet */
pub dst_vpcd: Option<VpcDiscriminant>, /* the vpc discriminant of a packet to be (or already) re-encapsulated by the gateway */
Expand Down
Loading
Loading