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
9 changes: 9 additions & 0 deletions common/src/api/external/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1341,6 +1341,15 @@ impl From<Ipv6Addr> for IpNet {
}
}

impl From<IpAddr> for IpNet {
fn from(n: IpAddr) -> IpNet {
match n {
IpAddr::V4(v4) => IpNet::from(v4),
IpAddr::V6(v6) => IpNet::from(v6),
}
}
}

impl std::fmt::Display for IpNet {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expand Down
13 changes: 12 additions & 1 deletion common/src/api/internal/nexus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
//! APIs exposed by Nexus.

use crate::api::external::{
ByteCount, DiskState, Generation, InstanceCpuCount, InstanceState,
ByteCount, DiskState, Generation, InstanceCpuCount, InstanceState, IpNet,
Vni,
};
use chrono::{DateTime, Utc};
use parse_display::{Display, FromStr};
Expand Down Expand Up @@ -180,3 +181,13 @@ mod tests {
}
}
}

/// A `HostIdentifier` represents either an IP host or network (v4 or v6),
/// or an entire VPC (identified by its VNI). It is used in firewall rule
/// host filters.
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)]
#[serde(tag = "type", content = "value", rename_all = "snake_case")]
pub enum HostIdentifier {
Ip(IpNet),
Vpc(Vni),
}
36 changes: 28 additions & 8 deletions nexus/src/app/vpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@ use omicron_common::api::external::CreateResult;
use omicron_common::api::external::DeleteResult;
use omicron_common::api::external::Error;
use omicron_common::api::external::InternalContext;
use omicron_common::api::external::IpNet;
use omicron_common::api::external::ListResultVec;
use omicron_common::api::external::LookupResult;
use omicron_common::api::external::LookupType;
use omicron_common::api::external::NameOrId;
use omicron_common::api::external::UpdateResult;
use omicron_common::api::external::Vni;
use omicron_common::api::external::VpcFirewallRuleUpdateParams;
use omicron_common::api::internal::nexus::HostIdentifier;
use ref_cast::RefCast;
use sled_agent_client::types::IpNet;
use sled_agent_client::types::NetworkInterface;

use futures::future::join_all;
Expand Down Expand Up @@ -532,10 +534,10 @@ impl super::Nexus {
.unwrap_or(&no_interfaces)
.iter()
.filter(|nic| match (net, nic.ip) {
(external::IpNet::V4(net), IpAddr::V4(ip)) => {
(IpNet::V4(net), IpAddr::V4(ip)) => {
net.contains(ip)
}
(external::IpNet::V6(net), IpAddr::V6(ip)) => {
(IpNet::V6(net), IpAddr::V6(ip)) => {
net.contains(ip)
}
(_, _) => false,
Expand All @@ -562,7 +564,12 @@ impl super::Nexus {
.get(&name)
.unwrap_or(&no_interfaces)
{
host_addrs.push(IpNet::from(interface.ip))
host_addrs.push(
HostIdentifier::Ip(IpNet::from(
interface.ip,
))
.into(),
)
}
}
external::VpcFirewallRuleHostFilter::Subnet(
Expand All @@ -572,21 +579,34 @@ impl super::Nexus {
.get(&name)
.unwrap_or(&no_networks)
{
host_addrs.push(IpNet::from(*subnet));
host_addrs.push(
HostIdentifier::Ip(IpNet::from(
*subnet,
))
.into(),
);
}
}
external::VpcFirewallRuleHostFilter::Ip(addr) => {
host_addrs.push(IpNet::from(*addr))
host_addrs.push(
HostIdentifier::Ip(IpNet::from(*addr))
.into(),
)
}
external::VpcFirewallRuleHostFilter::IpNet(net) => {
host_addrs.push(IpNet::from(*net))
host_addrs.push(HostIdentifier::Ip(*net).into())
}
external::VpcFirewallRuleHostFilter::Vpc(name) => {
for interface in vpc_interfaces
.get(&name)
.unwrap_or(&no_interfaces)
{
host_addrs.push(IpNet::from(interface.ip))
host_addrs.push(
HostIdentifier::Vpc(Vni::try_from(
*interface.vni,
)?)
.into(),
)
}
}
}
Expand Down
43 changes: 42 additions & 1 deletion openapi/sled-agent.json
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,47 @@
"format": "uint64",
"minimum": 0
},
"HostIdentifier": {
"description": "A `HostIdentifier` represents either an IP host or network (v4 or v6), or an entire VPC (identified by its VNI). It is used in firewall rule host filters.",
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"ip"
]
},
"value": {
"$ref": "#/components/schemas/IpNet"
}
},
"required": [
"type",
"value"
]
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": [
"vpc"
]
},
"value": {
"$ref": "#/components/schemas/Vni"
}
},
"required": [
"type",
"value"
]
}
]
},
"InstanceCpuCount": {
"description": "The number of CPUs in an Instance",
"type": "integer",
Expand Down Expand Up @@ -1769,7 +1810,7 @@
"nullable": true,
"type": "array",
"items": {
"$ref": "#/components/schemas/IpNet"
"$ref": "#/components/schemas/HostIdentifier"
}
},
"filter_ports": {
Expand Down
18 changes: 18 additions & 0 deletions sled-agent-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,12 @@ impl From<omicron_common::api::external::Vni> for types::Vni {
}
}

impl From<types::Vni> for omicron_common::api::external::Vni {
fn from(s: types::Vni) -> Self {
Self::try_from(s.0 as u32).unwrap()
}
}

impl From<omicron_common::api::external::MacAddr> for types::MacAddr {
fn from(s: omicron_common::api::external::MacAddr) -> Self {
Self::try_from(s.0.to_string())
Expand Down Expand Up @@ -327,6 +333,18 @@ impl From<omicron_common::api::internal::nexus::KnownArtifactKind>
}
}

impl From<omicron_common::api::internal::nexus::HostIdentifier>
for types::HostIdentifier
{
fn from(s: omicron_common::api::internal::nexus::HostIdentifier) -> Self {
use omicron_common::api::internal::nexus::HostIdentifier::*;
match s {
Ip(net) => Self::Ip(net.into()),
Vpc(vni) => Self::Vpc(vni.into()),
}
}
}

impl From<omicron_common::api::external::VpcFirewallRuleAction>
for types::VpcFirewallRuleAction
{
Expand Down
20 changes: 14 additions & 6 deletions sled-agent/src/opte/illumos/firewall_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use omicron_common::api::external::VpcFirewallRuleAction;
use omicron_common::api::external::VpcFirewallRuleDirection;
use omicron_common::api::external::VpcFirewallRuleProtocol;
use omicron_common::api::external::VpcFirewallRuleStatus;
use omicron_common::api::internal::nexus::HostIdentifier;
use oxide_vpc::api::Address;
use oxide_vpc::api::Direction;
use oxide_vpc::api::Filters;
Expand Down Expand Up @@ -62,16 +63,23 @@ impl FromVpcFirewallRule for VpcFirewallRule {
hosts
.iter()
.map(|host| match host {
IpNet::V4(net) if net.prefix() == 32 => {
HostIdentifier::Ip(IpNet::V4(net))
if net.prefix() == 32 =>
{
Address::Ip(net.ip().into())
}
IpNet::V4(net) => Address::Subnet(Ipv4Cidr::new(
net.ip().into(),
Ipv4PrefixLen::new(net.prefix()).unwrap(),
)),
IpNet::V6(_net) => {
HostIdentifier::Ip(IpNet::V4(net)) => {
Address::Subnet(Ipv4Cidr::new(
net.ip().into(),
Ipv4PrefixLen::new(net.prefix()).unwrap(),
))
}
HostIdentifier::Ip(IpNet::V6(_net)) => {
todo!("IPv6 host filters")
}
HostIdentifier::Vpc(vni) => {
Address::Vni(Vni::new(u32::from(*vni)).unwrap())
}
})
.collect::<Vec<Address>>()
},
Expand Down
4 changes: 2 additions & 2 deletions sled-agent/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use omicron_common::address::{
};
use omicron_common::api::external;
use omicron_common::api::internal::nexus::{
DiskRuntimeState, InstanceRuntimeState,
DiskRuntimeState, HostIdentifier, InstanceRuntimeState,
};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -53,7 +53,7 @@ pub struct VpcFirewallRule {
pub status: external::VpcFirewallRuleStatus,
pub direction: external::VpcFirewallRuleDirection,
pub targets: Vec<NetworkInterface>,
pub filter_hosts: Option<Vec<external::IpNet>>,
pub filter_hosts: Option<Vec<HostIdentifier>>,
pub filter_ports: Option<Vec<external::L4PortRange>>,
pub filter_protocols: Option<Vec<external::VpcFirewallRuleProtocol>>,
pub action: external::VpcFirewallRuleAction,
Expand Down