Skip to content
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
16 changes: 11 additions & 5 deletions config/src/converters/k8s/config/expose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use k8s_intf::gateway_agent_crd::{
GatewayAgentPeeringsPeeringExposeIps, GatewayAgentPeeringsPeeringExposeNat,
GatewayAgentPeeringsPeeringExposeNatPortForwardPortsProto,
};
use lpm::prefix::{L4Protocol, PortRange, Prefix, PrefixString, PrefixWithOptionalPorts};
use lpm::prefix::{PortRange, Prefix, PrefixString, PrefixWithOptionalPorts};
use net::ip::NextHeader;

use crate::converters::k8s::FromK8sConversionError;
use crate::converters::k8s::config::SubnetMap;
Expand Down Expand Up @@ -238,13 +239,18 @@ fn set_port_ranges(
nat.as_range.remove(target_prefix);
}

nat.proto = match proto {
Some(GatewayAgentPeeringsPeeringExposeNatPortForwardPortsProto::Tcp) => L4Protocol::Tcp,
Some(GatewayAgentPeeringsPeeringExposeNatPortForwardPortsProto::Udp) => L4Protocol::Udp,
let proto_restriction = match proto {
Some(GatewayAgentPeeringsPeeringExposeNatPortForwardPortsProto::Tcp) => {
Some(NextHeader::TCP)
}
Some(GatewayAgentPeeringsPeeringExposeNatPortForwardPortsProto::Udp) => {
Some(NextHeader::UDP)
}
Some(GatewayAgentPeeringsPeeringExposeNatPortForwardPortsProto::KopiumEmpty) | None => {
L4Protocol::Any
None
}
};
nat.set_proto_restriction(proto_restriction)?;

vpc_exposes.push(vpc_expose_clone);
}
Expand Down
7 changes: 6 additions & 1 deletion config/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,12 @@ impl Display for VpcExpose {
if !nat.as_range.is_empty() {
write!(f, "{SEP} as:")?;
nat.as_range.iter().for_each(|pfx| {
let _ = write!(f, " {pfx} proto: {:?} NAT:{}", nat.proto, &nat.config);
let _ = write!(
f,
" {pfx} proto: {:?} NAT:{}",
nat.proto_restriction(),
&nat.config
);
});
carriage = true;
}
Expand Down
87 changes: 75 additions & 12 deletions config/src/external/overlay/vpcpeering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
//! Dataplane configuration model: vpc peering

use crate::utils::{check_private_prefixes_dont_overlap, check_public_prefixes_dont_overlap};
use crate::{ConfigError, ConfigResult};
use lpm::prefix::{
IpRangeWithPorts, L4Protocol, Prefix, PrefixPortsSet, PrefixWithOptionalPorts,
PrefixWithPortsSize,
IpRangeWithPorts, Prefix, PrefixPortsSet, PrefixWithOptionalPorts, PrefixWithPortsSize,
};
use net::ip::NextHeader;
use std::collections::BTreeMap;
use std::ops::Bound::{Excluded, Unbounded};
use std::time::Duration;
Expand Down Expand Up @@ -38,7 +39,7 @@ pub struct VpcExposeNat {
pub as_range: PrefixPortsSet,
pub not_as: PrefixPortsSet,
pub config: VpcExposeNatConfig,
pub proto: L4Protocol,
proto_restriction: Option<NextHeader>,
}

impl VpcExposeNat {
Expand All @@ -48,7 +49,7 @@ impl VpcExposeNat {
as_range: PrefixPortsSet::new(),
not_as: PrefixPortsSet::new(),
config,
proto: L4Protocol::default(),
proto_restriction: None,
}
}

Expand All @@ -66,6 +67,67 @@ impl VpcExposeNat {
pub fn is_port_forwarding(&self) -> bool {
matches!(self.config, VpcExposeNatConfig::PortForwarding(_))
}

#[must_use]
pub fn proto_restriction(&self) -> Option<NextHeader> {
self.proto_restriction
}

pub fn set_proto_restriction(&mut self, proto_restriction: Option<NextHeader>) -> ConfigResult {
match proto_restriction {
Some(NextHeader::TCP | NextHeader::UDP) => {
self.proto_restriction = proto_restriction;
Ok(())
}
None => {
self.proto_restriction = None;
Ok(())
}
Some(_) => Err(ConfigError::InternalFailure(format!(
"Trying to set invalid L4 protocol restriction for NAT: {proto_restriction:?}"
))),
}
}

/// Returns the common L4 protocol restrictions between two NAT configurations.
///
/// # Panics
///
/// Panics if either `left` or `right` contains a protocol other than TCP or UDP.
#[must_use]
pub fn l4_proto_common_restrictions(
left: &Option<NextHeader>,
right: &Option<NextHeader>,
) -> Option<Vec<NextHeader>> {
assert!(left.is_none_or(|pr| matches!(pr, NextHeader::TCP | NextHeader::UDP)));
assert!(right.is_none_or(|pr| matches!(pr, NextHeader::TCP | NextHeader::UDP)));

match (left, right) {
(Some(left), Some(right)) if left == right => Some(vec![*left]),
(Some(_), Some(_)) => None,
(None, Some(single)) | (Some(single), None) => Some(vec![*single]),
(None, None) => Some(vec![NextHeader::TCP, NextHeader::UDP]),
}
}

#[must_use]
/// Returns whether the L4 protocol restriction applies to the given protocol.
///
/// # Panics
///
/// Panics if `restriction` contains a protocol other than TCP or UDP.
pub fn l4_proto_restriction_applies_to_proto(
restriction: &Option<NextHeader>,
proto: &Option<NextHeader>,
) -> bool {
assert!(restriction.is_none_or(|pr| matches!(pr, NextHeader::TCP | NextHeader::UDP)));

match (restriction, proto) {
(None, _) => true,
(Some(_), None) => false,
(Some(restriction), Some(proto)) => restriction == proto,
}
}
}

fn empty_set() -> &'static PrefixPortsSet {
Expand All @@ -74,7 +136,6 @@ fn empty_set() -> &'static PrefixPortsSet {
&EMPTY_SET
}

use crate::{ConfigError, ConfigResult};
#[derive(Clone, Debug, Default, PartialEq)]
pub struct VpcExpose {
pub default: bool,
Expand Down Expand Up @@ -144,15 +205,19 @@ impl VpcExpose {
pub fn make_port_forwarding(
mut self,
idle_timeout: Option<Duration>,
proto: Option<L4Protocol>,
proto_restriction: Option<NextHeader>,
) -> Result<Self, ConfigError> {
if proto_restriction.is_some_and(|pr| !matches!(pr, NextHeader::TCP | NextHeader::UDP)) {
return Err(ConfigError::Invalid(format!(
"Trying to set invalid L4 protocol restriction for NAT: {proto_restriction:?}"
)));
}

let options = VpcExposePortForwarding { idle_timeout };
match self.nat.as_mut() {
Some(nat) if nat.is_port_forwarding() => {
nat.config = VpcExposeNatConfig::PortForwarding(options);
if let Some(proto) = proto {
nat.proto = proto;
}
nat.proto_restriction = proto_restriction;
}
Some(_) => {
return Err(ConfigError::Invalid(format!(
Expand All @@ -162,9 +227,7 @@ impl VpcExpose {
None => {
let mut nat =
VpcExposeNat::from_config(VpcExposeNatConfig::PortForwarding(options));
if let Some(proto) = proto {
nat.proto = proto;
}
nat.proto_restriction = proto_restriction;
self.nat = Some(nat);
}
}
Expand Down
8 changes: 6 additions & 2 deletions config/src/utils/overlap.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Open Network Fabric Authors

use crate::ConfigError;
use crate::external::overlay::vpcpeering::VpcExpose;
use crate::{ConfigError, external::overlay::vpcpeering::VpcExposeNat};
use lpm::prefix::{IpRangeWithPorts, PrefixPortsSet, PrefixWithPortsSize};

pub fn check_private_prefixes_dont_overlap(
Expand Down Expand Up @@ -52,7 +52,11 @@ fn port_forwarding_with_distinct_l4_protocols(
&& expose_right.has_port_forwarding()
&& let Some(nat_left) = expose_left.nat.as_ref()
&& let Some(nat_right) = expose_right.nat.as_ref()
&& nat_left.proto.intersection(&nat_right.proto).is_none()
&& VpcExposeNat::l4_proto_common_restrictions(
&nat_left.proto_restriction(),
&nat_right.proto_restriction(),
)
.is_none()
{
true
} else {
Expand Down
15 changes: 8 additions & 7 deletions flow-filter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@
//! peerings, get dropped.

use crate::tables::{NatRequirement, RemoteData, VpcdLookupResult};
use config::external::overlay::vpcpeering::VpcExposeNat;
use indenter::indented;
use lpm::prefix::L4Protocol;
use net::buffer::PacketBufferMut;
use net::flows::FlowStatus;
use net::flows::flow_info_item::ExtractRef;
use net::headers::{Transport, TryIp, TryTransport};
use net::ip::NextHeader;
use net::packet::{DoneReason, Packet, VpcDiscriminant};
use pipeline::{NetworkFunction, PipelineData};
use std::collections::HashSet;
Expand Down Expand Up @@ -313,7 +314,7 @@ fn deal_with_multiple_matches<Buf: PacketBufferMut>(
let Some(NatRequirement::PortForwarding(requirement_proto)) = d.src_nat_req else {
return false;
};
requirement_proto.intersection(&packet_proto).is_some()
VpcExposeNat::l4_proto_restriction_applies_to_proto(&requirement_proto, &packet_proto)
})
{
set_nat_requirements(packet, dst_data);
Expand All @@ -325,7 +326,7 @@ fn deal_with_multiple_matches<Buf: PacketBufferMut>(
let Some(NatRequirement::PortForwarding(req_proto)) = d.dst_nat_req else {
return false;
};
req_proto.intersection(&packet_proto).is_some()
VpcExposeNat::l4_proto_restriction_applies_to_proto(&req_proto, &packet_proto)
}) && data_set
.iter()
.any(|d| d.dst_nat_req == Some(NatRequirement::Stateful))
Expand Down Expand Up @@ -460,10 +461,10 @@ fn set_nat_requirements_from_flow_info<Buf: PacketBufferMut>(
}
}

pub(crate) fn get_l4_proto<Buf: PacketBufferMut>(packet: &Packet<Buf>) -> L4Protocol {
pub(crate) fn get_l4_proto<Buf: PacketBufferMut>(packet: &Packet<Buf>) -> Option<NextHeader> {
match packet.try_transport() {
Some(Transport::Tcp(_)) => L4Protocol::Tcp,
Some(Transport::Udp(_)) => L4Protocol::Udp,
_ => L4Protocol::Any,
Some(Transport::Tcp(_)) => Some(NextHeader::TCP),
Some(Transport::Udp(_)) => Some(NextHeader::UDP),
_ => None,
}
}
13 changes: 7 additions & 6 deletions flow-filter/src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,8 @@ mod tests {
use super::*;
use config::external::overlay::vpc::{Vpc, VpcTable};
use config::external::overlay::vpcpeering::{VpcExpose, VpcManifest, VpcPeeringTable};
use lpm::prefix::{L4Protocol, PortRange, Prefix, PrefixWithPortsSize};
use lpm::prefix::{PortRange, Prefix, PrefixWithPortsSize};
use net::ip::NextHeader;
use net::packet::VpcDiscriminant;
use net::vxlan::Vni;
use std::collections::BTreeSet;
Expand Down Expand Up @@ -876,7 +877,7 @@ mod tests {
name: "manifest2".to_string(),
exposes: vec![
VpcExpose::empty()
.make_port_forwarding(None, Some(L4Protocol::Tcp))
.make_port_forwarding(None, Some(NextHeader::TCP))
.unwrap()
.ip(PrefixWithOptionalPorts::new(
"1.0.0.1/32".into(),
Expand All @@ -888,7 +889,7 @@ mod tests {
))
.unwrap(),
VpcExpose::empty()
.make_port_forwarding(None, Some(L4Protocol::Udp))
.make_port_forwarding(None, Some(NextHeader::UDP))
.unwrap()
.ip(PrefixWithOptionalPorts::new(
"1.0.0.1/32".into(),
Expand Down Expand Up @@ -950,15 +951,15 @@ mod tests {
set.contains(&RemoteData::new(
vpcd,
None,
Some(NatRequirement::PortForwarding(L4Protocol::Tcp)),
Some(NatRequirement::PortForwarding(Some(NextHeader::TCP))),
)),
"{set:?}"
);
assert!(
set.contains(&RemoteData::new(
vpcd,
None,
Some(NatRequirement::PortForwarding(L4Protocol::Udp)),
Some(NatRequirement::PortForwarding(Some(NextHeader::UDP))),
)),
"{set:?}"
);
Expand Down Expand Up @@ -1054,7 +1055,7 @@ mod tests {
HashSet::from([RemoteData::new(
vpcd(200),
None,
Some(NatRequirement::PortForwarding(L4Protocol::Any)),
Some(NatRequirement::PortForwarding(None)),
)]),
);

Expand Down
29 changes: 19 additions & 10 deletions flow-filter/src/tables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
use config::ConfigError;
use config::external::overlay::vpcpeering::{VpcExposeNat, VpcExposeNatConfig};
use lpm::prefix::range_map::DisjointRangesBTreeMap;
use lpm::prefix::{L4Protocol, PortRange, Prefix};
use lpm::prefix::{PortRange, Prefix};
use lpm::trie::{IpPortPrefixTrie, ValueWithAssociatedRanges};
use net::ip::NextHeader;
use net::packet::VpcDiscriminant;
use std::collections::{HashMap, HashSet};
use std::fmt::Debug;
Expand Down Expand Up @@ -466,15 +467,17 @@ impl PortRangeMap<DstConnectionData> {
pub(crate) enum NatRequirement {
Stateless,
Stateful,
PortForwarding(L4Protocol),
PortForwarding(Option<NextHeader>),
}

impl NatRequirement {
pub(crate) fn from_nat(nat: &VpcExposeNat) -> NatRequirement {
match (&nat.config, nat.proto) {
match (&nat.config, nat.proto_restriction()) {
(VpcExposeNatConfig::Stateful(_), _) => NatRequirement::Stateful,
(VpcExposeNatConfig::Stateless(_), _) => NatRequirement::Stateless,
(VpcExposeNatConfig::PortForwarding(_), proto) => NatRequirement::PortForwarding(proto),
(VpcExposeNatConfig::PortForwarding(_), proto_restriction) => {
NatRequirement::PortForwarding(proto_restriction)
}
}
}
}
Expand Down Expand Up @@ -509,10 +512,13 @@ impl RemoteData {
|| self.dst_nat_req == Some(NatRequirement::Stateless)
}

pub(crate) fn requires_port_forwarding(&self, packet_proto: L4Protocol) -> bool {
pub(crate) fn requires_port_forwarding(&self, packet_proto: Option<NextHeader>) -> bool {
for requirement in [self.src_nat_req, self.dst_nat_req] {
if let Some(NatRequirement::PortForwarding(req_proto)) = requirement
&& packet_proto.intersection(&req_proto).is_some()
if let Some(NatRequirement::PortForwarding(req_proto_restriction)) = requirement
&& VpcExposeNat::l4_proto_restriction_applies_to_proto(
&req_proto_restriction,
&packet_proto,
)
{
return true;
}
Expand All @@ -521,10 +527,13 @@ impl RemoteData {
}

// Determines whether the NAT requirements object covers a given L4 protocol.
pub(crate) fn applies_to(&self, packet_proto: L4Protocol) -> bool {
pub(crate) fn applies_to(&self, packet_proto: Option<NextHeader>) -> bool {
for requirement in [self.src_nat_req, self.dst_nat_req] {
if let Some(NatRequirement::PortForwarding(req_proto)) = requirement
&& req_proto.intersection(&packet_proto).is_none()
if let Some(NatRequirement::PortForwarding(req_proto_restriction)) = requirement
&& !VpcExposeNat::l4_proto_restriction_applies_to_proto(
&req_proto_restriction,
&packet_proto,
)
{
return false;
}
Expand Down
Loading
Loading