Skip to content

[flowstats 0/n] [wip] Per-port collection task, sled-agent endpoints #8607

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
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: 1 addition & 1 deletion .github/buildomat/jobs/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ z_swadm () {

# only set this if you want to override the version of opte/xde installed by the
# install_opte.sh script
OPTE_COMMIT=""
OPTE_COMMIT="355fc09545445beda7cd789033507f13e80cbbe7"
if [[ "x$OPTE_COMMIT" != "x" ]]; then
curl -sSfOL https://buildomat.eng.oxide.computer/public/file/oxidecomputer/opte/module/$OPTE_COMMIT/xde
pfexec rem_drv xde || true
Expand Down
19 changes: 11 additions & 8 deletions Cargo.lock

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

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -511,8 +511,8 @@ lldp_protocol = { git = "https://github.com/oxidecomputer/lldp", package = "prot
macaddr = { version = "1.0.1", features = ["serde_std"] }
maplit = "1.0.2"
newtype_derive = "0.1.6"
mg-admin-client = { git = "https://github.com/oxidecomputer/maghemite", rev = "fa5f15cdcd5864161a929e2ec01534f70dfba216" }
ddm-admin-client = { git = "https://github.com/oxidecomputer/maghemite", rev = "fa5f15cdcd5864161a929e2ec01534f70dfba216" }
mg-admin-client = { git = "https://github.com/oxidecomputer/maghemite", rev = "42f18f0491eccd16921c7b6b7fa2470160af00c2" }
ddm-admin-client = { git = "https://github.com/oxidecomputer/maghemite", rev = "42f18f0491eccd16921c7b6b7fa2470160af00c2" }
multimap = "0.10.1"
nexus-auth = { path = "nexus/auth" }
nexus-background-task-interface = { path = "nexus/background-task-interface" }
Expand Down Expand Up @@ -568,7 +568,7 @@ omicron-workspace-hack = "0.1.0"
omicron-zone-package = "0.12.2"
oxide-client = { path = "clients/oxide-client" }
oxide-tokio-rt = "0.1.2"
oxide-vpc = { git = "https://github.com/oxidecomputer/opte", rev = "23cebf3b1c911f09c203f7df50cc06bf780338e5", features = [ "api", "std" ] }
oxide-vpc = { git = "https://github.com/oxidecomputer/opte", rev = "355fc09545445beda7cd789033507f13e80cbbe7", features = [ "api", "std" ] }
oxlog = { path = "dev-tools/oxlog" }
oxnet = "0.1.2"
once_cell = "1.21.3"
Expand All @@ -578,7 +578,7 @@ openapiv3 = "2.2.0"
# must match samael's crate!
openssl = "0.10"
openssl-sys = "0.9"
opte-ioctl = { git = "https://github.com/oxidecomputer/opte", rev = "23cebf3b1c911f09c203f7df50cc06bf780338e5" }
opte-ioctl = { git = "https://github.com/oxidecomputer/opte", rev = "355fc09545445beda7cd789033507f13e80cbbe7" }
oso = "0.27"
owo-colors = "4.2.2"
oximeter = { path = "oximeter/oximeter" }
Expand Down
115 changes: 115 additions & 0 deletions common/src/api/external/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3474,6 +3474,121 @@ pub enum ImportExportPolicy {
Allow(Vec<oxnet::IpNet>),
}

/// A packet flow recorded on a `NetworkInterface`.
#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize, PartialEq)]
pub struct Flow {
pub metadata: FlowMetadata,
pub in_stat: FlowStat,
pub out_stat: FlowStat,
}

/// A packet flow recorded on a `NetworkInterface`.
#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize, PartialEq)]
pub struct FlowStat {
pub packets: u64,
pub bytes: u64,
pub packet_rate: f64,
pub byte_rate: f64,
}

/// Information about a flow recorded on a `NetworkInterface`.
#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize, PartialEq, Eq)]
pub struct FlowMetadata {
/// An ephemeral ID bound to this flow.
pub flow_id: Uuid,
/// The time the first packet of this flow was seen at.
pub created_at: DateTime<Utc>,
/// The direction of the first packet of this flow.
pub initial_packet: Direction,
/// The flowkey (or 5-tuple) of any packets on this flow as viewed by
/// the instance.
pub internal_key: Flowkey,
/// The flowkey (or 5-tuple) of any packets on this flow as viewed by
/// the remote half.
pub external_key: Flowkey,
/// All entities responsible for allowing packets in this flow to reach the
/// instance.
pub admitted_by_in: Option<Vec<VpcEntity>>,
/// All entities responsible for allowing packets in this flow to be sent
/// by the instance.
pub admitted_by_out: Option<Vec<VpcEntity>>,
/// How any outbound packets are to be routed.
pub forwarded: Option<ForwardClass>,
}

/// The direction of a flow or packet, with respect to its target `Instance`.
#[derive(
Clone, Debug, Deserialize, JsonSchema, Serialize, PartialEq, Eq, Hash,
)]
#[serde(rename_all = "snake_case")]
pub enum Direction {
In,
Out,
}

/// Addresses and protocol-specific information used to group packets into a flow.
#[derive(
Clone, Debug, Deserialize, JsonSchema, Serialize, PartialEq, Eq, Hash,
)]
pub struct Flowkey {
pub source_address: IpAddr,
pub destination_address: IpAddr,
pub protocol: u8,
pub info: Option<ProtocolInfo>,
}

/// Protocol-specific flow information.
#[derive(
Clone, Debug, Deserialize, JsonSchema, Serialize, PartialEq, Eq, Hash,
)]
#[serde(rename_all = "snake_case", tag = "type", content = "value")]
pub enum ProtocolInfo {
Ports(PortProtocolInfo),
Icmp(IcmpProtocolInfo),
}

/// A pair of ports, identifying a flow in protocols such as TCP or UDP.
#[derive(
Clone, Debug, Deserialize, JsonSchema, Serialize, PartialEq, Eq, Hash,
)]
pub struct PortProtocolInfo {
pub source_port: u16,
pub destination_port: u16,
}

/// Message types information carried by ICMP.
#[derive(
Clone, Debug, Deserialize, JsonSchema, Serialize, PartialEq, Eq, Hash,
)]
pub struct IcmpProtocolInfo {
pub r#type: u8,
pub code: u8,
pub id: Option<u16>,
}

/// How the remote half of a flow is reached.
#[derive(
Clone, Debug, Deserialize, JsonSchema, Serialize, PartialEq, Eq, Hash,
)]
#[serde(rename_all = "snake_case")]
pub enum ForwardClass {
VpcLocal,
External,
}

/// A control-plane object which has matched a given flow and chosen to
/// allow it.
#[derive(
Clone, Debug, Deserialize, JsonSchema, Serialize, PartialEq, Eq, Hash,
)]
#[serde(rename_all = "snake_case", tag = "type", content = "value")]
pub enum VpcEntity {
FirewallRule(Uuid),
FirewallDefaultIn,
VpcRoute(Uuid),
InternetGateway(Uuid),
}

/// Use instead of Option in API request body structs to get a field that can
/// be null (parsed as `None`) but is not optional. Unlike Option, Nullable
/// will fail to parse if the key is not present. The JSON Schema in the
Expand Down
2 changes: 2 additions & 0 deletions illumos-utils/src/opte/firewall_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use oxide_vpc::api::IpAddr;
use oxide_vpc::api::Ports;
use oxide_vpc::api::ProtoFilter;
use oxnet::IpNet;
use uuid::Uuid;

trait FromVpcFirewallRule {
fn action(&self) -> FirewallAction;
Expand Down Expand Up @@ -170,6 +171,7 @@ pub fn opte_firewall_rules(
.set_protocol(proto.clone());
filters
},
stat_id: Some(Uuid::new_v4()),
})
.collect::<Vec<FirewallRule>>()
})
Expand Down
9 changes: 4 additions & 5 deletions illumos-utils/src/opte/illumos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use crate::addrobj::AddrObject;
use crate::dladm;
use camino::Utf8Path;
use omicron_common::api::internal::shared::NetworkInterfaceKind;
use opte_ioctl::Error as OpteError;
use opte_ioctl::OpteHdl;
use slog::Logger;
Expand Down Expand Up @@ -46,11 +45,11 @@ pub enum Error {
#[error("Invalid IP configuration for port")]
InvalidPortIpConfig,

#[error("Tried to release non-existent port ({0}, {1:?})")]
ReleaseMissingPort(uuid::Uuid, NetworkInterfaceKind),
#[error("Tried to release non-existent port ({0})")]
ReleaseMissingPort(uuid::Uuid),

#[error("Tried to update external IPs on non-existent port ({0}, {1:?})")]
ExternalIpUpdateMissingPort(uuid::Uuid, NetworkInterfaceKind),
#[error("Tried to update external IPs on non-existent port ({0})")]
ExternalIpUpdateMissingPort(uuid::Uuid),

#[error("Could not find Primary NIC")]
NoPrimaryNic,
Expand Down
1 change: 1 addition & 0 deletions illumos-utils/src/opte/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ cfg_if::cfg_if! {
mod firewall_rules;
mod port;
mod port_manager;
mod stat;

pub use firewall_rules::opte_firewall_rules;
use ipnetwork::IpNetwork;
Expand Down
Loading