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
48 changes: 48 additions & 0 deletions common/src/illumos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,54 @@ pub async fn vlan_create(over: &str, vlan_id: u16, vlan: &str) -> Result<()> {
dladm_quiet(&["create-vlan", "-t", "-v", &vlan_id, "-l", over, vlan]).await
}

/// What address family to use when enabling/disabling route exchange for an
/// interface.
#[derive(Debug, Clone, Copy)]
pub enum AddressFamily {
Ipv4,
Ipv6,
}

impl AddressFamily {
fn as_str(&self) -> &'static str {
match self {
Self::Ipv4 => "ipv4",
Self::Ipv6 => "ipv6",
}
}
}

/// Enable or disable route exchange for a particular interface. Disabling
/// has the following implications.
///
/// IPv6:
/// - The host OS will ignore all NDP router solicitation (RS) and router
/// advertisement (RA) messages.
/// - The host OS will suppress RIPng send/receive
///
/// IPv4:
/// - The host OS discards inbound RIP packets
/// - The host OS suppresses ICMP router discovery
pub async fn set_interface_exchange_routes(
iface: &str,
enabled: bool,
address_family: AddressFamily,
) -> Result<()> {
let value =
if enabled { "exchange_routes=on" } else { "exchange_routes=off" };

ipadm_quiet(&[
"set-ifprop",
"-t",
"-p",
value,
"-m",
address_family.as_str(),
iface,
])
.await
}

/// Remove a vlan link
pub async fn vlan_delete(vlan: &str) -> Result<()> {
dladm_quiet(&["delete-vlan", vlan]).await
Expand Down
32 changes: 31 additions & 1 deletion uplinkd/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use anyhow::Context;
use anyhow::Result;
use anyhow::anyhow;
use clap::Parser;
use common::illumos::AddressFamily;
use libc::c_int;
use oxnet::IpNet;
use oxnet::Ipv4Net;
Expand Down Expand Up @@ -452,7 +453,36 @@ async fn create_addrobj(
// some point.
error!(log, "failed to create {addr}: {e:?}");
e
})
})?;

// The uplink ports on the switch are router ports. This means that we
// should not be modifying the switch zone OS routing tables in response to
// router advertisements we receive. Router advertisements are for hosts,
// routers are not supposed to respond to them on router ports. By disabling
// route exchange in the illumos host, we are asking the OS not to respond
// to router advertisements as a host. Maghemite takes responsibility
// for generating and handling router advertisements and solicitations as
// a router.
illumos::set_interface_exchange_routes(iface, false, AddressFamily::Ipv6)
.await
.map_err(|e| {
error!(
log,
"failed to disable ipv6 route exchange on interface {iface}: {e:?}"
);
e
})?;
illumos::set_interface_exchange_routes(iface, false, AddressFamily::Ipv4)
.await
.map_err(|e| {
error!(
log,
"failed to disable ipv4 route exchange on interface {iface}: {e:?}"
);
e
})?;

Ok(())
}

// Query illumos for all of the addresses on the interfaces we've been asked to
Expand Down