-
Notifications
You must be signed in to change notification settings - Fork 40
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
NAT RPW #3804
NAT RPW #3804
Changes from 8 commits
315ff35
e29a612
eda98c5
8af0927
8fa914e
452e4d1
ed63b1c
7fea2ac
38d6c5a
a591710
9858397
92df045
151516f
7f0c0a7
18164ee
351a0a8
d3e9c60
b38ebe5
0ffee3f
3ce9d98
e8d4768
049f324
f547f8a
7bf9e93
45cea66
eff1828
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -750,6 +750,7 @@ pub enum ResourceType { | |
UserBuiltin, | ||
Zpool, | ||
Vmm, | ||
Ipv4NatEntry, | ||
} | ||
|
||
// IDENTITY METADATA | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
use std::net::{Ipv4Addr, Ipv6Addr}; | ||
|
||
use super::MacAddr; | ||
use crate::{ | ||
schema::{ipv4_nat_entry, ipv4_nat_version}, | ||
SqlU16, SqlU32, Vni, | ||
}; | ||
use chrono::{DateTime, Utc}; | ||
use omicron_common::api::external; | ||
use schemars::JsonSchema; | ||
use serde::Serialize; | ||
use uuid::Uuid; | ||
|
||
// TODO correctness | ||
// If we're not going to store ipv4 and ipv6 | ||
// NAT entries in the same table, and we don't | ||
// need any of the special properties of the IpNetwork | ||
// column type, does it make sense to use a different | ||
// column type? | ||
/// Database representation of an Ipv4 NAT Entry. | ||
#[derive(Insertable, Debug, Clone)] | ||
#[diesel(table_name = ipv4_nat_entry)] | ||
pub struct Ipv4NatValues { | ||
pub external_address: ipnetwork::IpNetwork, | ||
pub first_port: SqlU16, | ||
pub last_port: SqlU16, | ||
pub sled_address: ipnetwork::IpNetwork, | ||
pub vni: Vni, | ||
pub mac: MacAddr, | ||
} | ||
|
||
// TODO correctness | ||
// If we're not going to store ipv4 and ipv6 | ||
// NAT entries in the same table, we should probably | ||
// make the types more restrictive to prevent an | ||
// accidental ipv6 entry from being created. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as the previous comment |
||
#[derive(Queryable, Debug, Clone, Selectable)] | ||
#[diesel(table_name = ipv4_nat_entry)] | ||
pub struct Ipv4NatEntry { | ||
pub id: Uuid, | ||
pub external_address: ipnetwork::IpNetwork, | ||
pub first_port: SqlU16, | ||
pub last_port: SqlU16, | ||
pub sled_address: ipnetwork::IpNetwork, | ||
pub vni: Vni, | ||
pub mac: MacAddr, | ||
pub version_added: SqlU32, | ||
pub version_removed: Option<SqlU32>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we be storing these versions as BigInts, rather than SqlU32s? If we overflow a u32 (very possible!) these values would start throwing deserialization errors. |
||
pub time_created: DateTime<Utc>, | ||
pub time_deleted: Option<DateTime<Utc>>, | ||
} | ||
|
||
impl Ipv4NatEntry { | ||
pub fn first_port(&self) -> u16 { | ||
self.first_port.into() | ||
} | ||
|
||
pub fn last_port(&self) -> u16 { | ||
self.last_port.into() | ||
} | ||
|
||
pub fn version_added(&self) -> u32 { | ||
self.version_added.into() | ||
} | ||
|
||
pub fn version_removed(&self) -> Option<u32> { | ||
self.version_removed.map(|i| i.into()) | ||
} | ||
} | ||
|
||
#[derive(Queryable, Debug, Clone, Selectable)] | ||
#[diesel(table_name = ipv4_nat_version)] | ||
pub struct Ipv4NatGen { | ||
pub last_value: SqlU32, | ||
pub log_cnt: SqlU32, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment about storing this as a u32 vs bigint |
||
pub is_called: bool, | ||
} | ||
|
||
/// NAT Record | ||
#[derive(Clone, Debug, Serialize, JsonSchema)] | ||
pub struct Ipv4NatEntryView { | ||
pub external_address: Ipv4Addr, | ||
pub first_port: u16, | ||
pub last_port: u16, | ||
pub sled_address: Ipv6Addr, | ||
pub vni: external::Vni, | ||
pub mac: external::MacAddr, | ||
pub gen: u32, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment about u32 vs u64 here |
||
pub deleted: bool, | ||
} | ||
|
||
impl From<Ipv4NatEntry> for Ipv4NatEntryView { | ||
fn from(value: Ipv4NatEntry) -> Self { | ||
let external_address = match value.external_address.ip() { | ||
std::net::IpAddr::V4(a) => a, | ||
std::net::IpAddr::V6(_) => unreachable!(), | ||
}; | ||
|
||
let sled_address = match value.sled_address.ip() { | ||
std::net::IpAddr::V4(_) => unreachable!(), | ||
std::net::IpAddr::V6(a) => a, | ||
}; | ||
|
||
let (gen, deleted) = match value.version_removed { | ||
Some(gen) => (*gen, true), | ||
None => (*value.version_added, false), | ||
}; | ||
|
||
Self { | ||
external_address, | ||
first_port: value.first_port(), | ||
last_port: value.last_port(), | ||
sled_address, | ||
vni: value.vni.0, | ||
mac: *value.mac, | ||
gen, | ||
deleted, | ||
} | ||
} | ||
} | ||
|
||
/// NAT Generation | ||
#[derive(Clone, Debug, Serialize, JsonSchema)] | ||
pub struct Ipv4NatGenView { | ||
pub gen: u32, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. u32 vs u64 again here |
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple questions about this:
ipnetwork::IpNetwork
encapsulate both v4 and v6 addresses? Could this entire struct just beIpNatValues
(and same elsewhere in this file) or would that be a bad idea?Either way, we should resolve this comment before merging!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By keeping the tables for v4 and v6 separate, we maintain a 1:1 mapping with the tables in
dendrite
, which does make troubleshooting, observability, and state reconciliation a bit more straightforward, so my gut says "keep them separate"There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try using
Ipv4Network
unless someone has an objection :)