Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
38 changes: 38 additions & 0 deletions .github/buildomat/jobs/linux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,26 @@
#: series = "linux"
#: name = "mgadm.sha256.txt"
#: from_output = "/work/release/mgadm.sha256.txt"
#:
#: [[publish]]
#: series = "linux"
#: name = "ddmd"
#: from_output = "/work/release/ddmd"
#:
#: [[publish]]
#: series = "linux"
#: name = "ddmd.sha256.txt"
#: from_output = "/work/release/ddmd.sha256.txt"
#:
#: [[publish]]
#: series = "linux"
#: name = "ddmadm"
#: from_output = "/work/release/ddmadm"
#:
#: [[publish]]
#: series = "linux"
#: name = "ddmadm.sha256.txt"
#: from_output = "/work/release/ddmadm.sha256.txt"

set -o errexit
set -o pipefail
Expand Down Expand Up @@ -64,3 +84,21 @@ popd
cp target/debug/mgadm /work/debug
cp target/release/mgadm /work/release
digest /work/release/mgadm > /work/release/mgadm.sha256.txt

banner "ddmd"
pushd ddmd
cargo build --bin ddmd --no-default-features
cargo build --bin ddmd --no-default-features --release
popd
cp target/debug/ddmd /work/debug
cp target/release/ddmd /work/release
digest /work/release/ddmd > /work/release/ddmd.sha256.txt

banner "ddmadm"
pushd ddmadm
cargo build --bin ddmadm
cargo build --bin ddmadm --release
popd
cp target/debug/ddmadm /work/debug
cp target/release/ddmadm /work/release
digest /work/release/ddmadm > /work/release/ddmadm.sha256.txt
16 changes: 12 additions & 4 deletions ddm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ hyper.workspace = true
hyper-util.workspace = true
http-body-util.workspace = true
serde_json.workspace = true
libnet.workspace = true
dpd-client.workspace = true
opte-ioctl.workspace = true
oxide-vpc.workspace = true
sled.workspace = true
mg-common.workspace = true
ddm-api-types.workspace = true
Expand All @@ -35,3 +31,15 @@ oximeter-producer.workspace = true
oxnet.workspace = true
uuid.workspace = true
ddm-api.workspace = true

# illumos-only deps used by the routing state machine and platform sys layer.
# Gated by the `backend` feature so stub builds (e.g. Linux test fixtures
# running `ddmd` with `--api-only`) link cleanly.
libnet = { workspace = true, optional = true }
dpd-client = { workspace = true, optional = true }
opte-ioctl = { workspace = true, optional = true }
oxide-vpc = { workspace = true, optional = true }

[features]
default = ["backend"]
backend = ["dep:libnet", "dep:dpd-client", "dep:opte-ioctl", "dep:oxide-vpc"]
16 changes: 8 additions & 8 deletions ddm/src/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ use ddm_api_types::net::TunnelOrigin;
use dropshot::ApiDescription;
use dropshot::ApiDescriptionBuildErrors;
use dropshot::ConfigDropshot;
use dropshot::ConfigLogging;
use dropshot::ConfigLoggingLevel;
use dropshot::HttpError;
use dropshot::HttpResponseOk;
use dropshot::HttpResponseUpdatedNoContent;
Expand All @@ -23,7 +21,7 @@ use dropshot::RequestContext;
use dropshot::TypedBody;
use mg_common::lock;
use oxnet::Ipv6Net;
use slog::{Logger, error, info};
use slog::{Logger, error, info, o};
use std::collections::{HashMap, HashSet};
use std::net::{IpAddr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::sync::Arc;
Expand All @@ -35,6 +33,8 @@ use tokio::task::JoinHandle;

pub const DDM_STATS_PORT: u16 = 8001;

const UNIT_API_SERVER: &str = "api_server";

#[derive(Default)]
pub struct RouterStats {
pub originated_underlay_prefixes: AtomicU64,
Expand Down Expand Up @@ -68,11 +68,11 @@ pub fn handler(
..Default::default()
};

let ds_log = ConfigLogging::StderrTerminal {
level: ConfigLoggingLevel::Error,
}
.to_logger("admin")
.map_err(|e| e.to_string())?;
let ds_log = log.new(o!(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a change to the logging level too, right? Previously we constructed a StderrTerminal at the Error level, but now we're inheriting whatever level log has - presumably Info? Is that okay?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good discussion point. Structured-logging aside (which is good here), the move to Info matches what mgd does vs what ddm had ~ mgd/src/admin.rs has been constructing its dropshot logger as log.new(o!("component" => COMPONENT_MGD, "module" => MOD_ADMIN, "unit" => UNIT_API_SERVER)), doing what the the parent level runs at (typically Info). The Error cap was a ddm-only.

So the question is do we want both daemons quiet normally vs on error? I think, I'll keep what ddm did previously and file an issue to look at logging consistency.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to tag in @rcgoodfellow in to help give some historical context -- I just don't have the history with ddm to know why we'd filter the logs down to just >= error.

I would think info should generally not be so cluttered that we need to avoid them in the logger. If the reason for the filter was truly just noise, then we should consider converting noisy logging calls to debug instead of leaving them at info... although I'm ok if that means filing a follow-up issue to address it later, rather than holding up this PR

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#740 opened to do the logging level change separately.

"component" => crate::COMPONENT_DDM,
"module" => crate::MOD_ADMIN,
"unit" => UNIT_API_SERVER,
));

let api = api_description().map_err(|e| e.to_string())?;

Expand Down
117 changes: 117 additions & 0 deletions ddm/src/discovery/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

//! This module implements the ddm router discovery mechanisms. These
//! mechanisms are responsible for three primary things
//!
//! 1. Soliciting other routers through UDP/IPv6 link local multicast.
//! 2. Sending out router advertisements in response to solicitations.
//! 3. Continuously soliciting link-local at a configurable rate to keep
//! sessions alive and sending out notifications when peering arrangements
//! expire due to not getting a solicitation response within a configurable
//! time threshold.
//!
//! [`Version`] and [`DiscoveryError`] are platform-agnostic and stay in this
//! module so the state machine type definitions in [`crate::sm`] continue to
//! compile when the routing runtime is gated out (e.g. Linux test fixtures
//! running `ddmd` with `--api-only`). The runtime helpers that drive
//! the protocol over UDPv6 sockets live in the [`runtime`] submodule and
//! are illumos-only.
//!
//! ## Protocol
//!
//! The general sequence of events is depicted in the following diagram.
//!
//! *==========* *==========*
//! | violin | | piano |
//! *==========* *==========*
//! | |
//! | solicit(ff02::dd) |
//! |-------------------------->|
//! | advertise(fe80::47) |
//! |<--------------------------|
//! | |
//! | ... |
//! | |
//! | |
//! | solicit(ff02::dd) |
//! |-------------------------->|
//! | advertise(fe80::47) |
//! |<--------------------------|
//! | |
//! | solicit(ff02::dd) |
//! |-------------------------->|
//! | solicit(ff02::dd) |
//! |-------------------------->|
//! | solicit(ff02::dd) |
//! |-------------------------->|
//! | |
//! +----| |
//! expire | | |
//! piano | | |
//! +--->| |
//!
//! This shows violin sending a link-local multicast solicitation over the wire.
//! That solicitation is received by piano and piano respons with an
//! advertisement to violin's link-local unicast address. From this point
//! forward solicitations and responses continue. Each time violin gets a
//! response from piano, it updates the last seen timestamp for piano. If at
//! some point piano stops responding to solicitations and the last seen
//! timestamp is older than the expiration threshold, violin will expire the
//! session and send out a notification to the ddm state machine that started
//! it. Violin will continue to send out solicitations in case piano comes back.
//!
//! In the event that piano undergoes renumbering e.g. it's link-local unicast
//! address changes, this will be detected by violin and an advertisement update
//! will be sent to the ddm state machine through the notification channel
//! provided to the discovery subsystem.
//!
//! The DDM discovery multicast address is ff02::dd. Discovery packets are sent
//! over UDP using port number 0xddd.
//!
//! ## Packets
//!
//! Discovery packets follow a very simple format
//!
//! 1 2 3
//! 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//! | version |S A r r r r r r| router kind | hostname len |
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//! | hostname :
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//! : .... :
//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//!
//! The first byte indicates the version. The only valid version at present is
//! version 1. The second byte is a flags bitfield. The first position `S`
//! indicates a solicitation. The second position `A` indicates and
//! advertisement. All other positions are reserved for future use. The third
//! byte indicates the kind of router. Current values are 0 for a server router
//! and 1 for a transit routers. The fourth byte is a hostname length followed
//! directly by a hostname of up to 255 bytes in length.

use thiserror::Error;

#[cfg(all(feature = "backend", target_os = "illumos"))]
mod runtime;

#[cfg(all(feature = "backend", target_os = "illumos"))]
pub(crate) use runtime::handler;

#[derive(Debug, Copy, Clone)]
#[repr(u8)]
pub enum Version {
V2 = 2,
V3 = 3,
}

#[derive(Error, Debug)]
pub enum DiscoveryError {
#[error("io error: {0}")]
Io(#[from] std::io::Error),

#[error("serialization error: {0}")]
Serialization(#[from] ispf::Error),
}
Loading