#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum DataplaneSessionHandoffError {
InvalidPacket,
NoRoute,
}
#[derive(Clone, Debug, Eq, PartialEq)]
enum DataplaneSessionIngressHandoff {
Raw {
raw: DataplaneRawIngress,
coord_warmup: DataplaneFspCoordWarmup,
},
Local(DataplaneFspLocalSessionIngress),
Rejected {
output: PacketOutput,
error: DataplaneSessionHandoffError,
},
}
impl DataplaneSessionIngressHandoff {
fn rejected(output: PacketOutput, error: DataplaneSessionHandoffError) -> Self {
Self::Rejected { output, error }
}
}
fn dataplane_session_ingress_from_output(
output: PacketOutput,
local_addr: NodeAddr,
) -> DataplaneSessionIngressHandoff {
if output.owner.protocol() != PacketProtocol::Fmp {
return DataplaneSessionIngressHandoff::rejected(
output,
DataplaneSessionHandoffError::InvalidPacket,
);
}
const FMP_LINK_TIMESTAMP_LEN: usize = 4;
const FMP_LINK_MSG_TYPE_LEN: usize = 1;
const FMP_SESSION_PAYLOAD_OFFSET: usize = FMP_LINK_TIMESTAMP_LEN
+ FMP_LINK_MSG_TYPE_LEN
+ crate::protocol::SessionDatagramRef::HEADER_LEN;
let previous_hop = output.owner.node_addr();
let fmp_header = match FmpWireHeader::parse(output.payload()) {
Ok(header) => header,
Err(_) => {
return DataplaneSessionIngressHandoff::rejected(
output,
DataplaneSessionHandoffError::InvalidPacket,
);
}
};
let Some(source_path) = output.source_path() else {
return DataplaneSessionIngressHandoff::rejected(
output,
DataplaneSessionHandoffError::NoRoute,
);
};
let transport_id = source_path.transport_id;
let remote_addr = source_path.remote_addr.clone();
let handoff_facts = {
let Some(link_payload) = output.opened_payload() else {
return DataplaneSessionIngressHandoff::rejected(
output,
DataplaneSessionHandoffError::InvalidPacket,
);
};
if link_payload.len() < FMP_LINK_TIMESTAMP_LEN {
return DataplaneSessionIngressHandoff::rejected(
output,
DataplaneSessionHandoffError::InvalidPacket,
);
}
let link_payload = &link_payload[FMP_LINK_TIMESTAMP_LEN..];
let Some((&msg_type, datagram_payload)) = link_payload.split_first() else {
return DataplaneSessionIngressHandoff::rejected(
output,
DataplaneSessionHandoffError::InvalidPacket,
);
};
if msg_type != crate::protocol::LinkMessageType::SessionDatagram.to_byte() {
return DataplaneSessionIngressHandoff::rejected(
output,
DataplaneSessionHandoffError::NoRoute,
);
}
let datagram = match crate::protocol::SessionDatagramRef::decode(datagram_payload) {
Ok(datagram) => datagram,
Err(_) => {
return DataplaneSessionIngressHandoff::rejected(
output,
DataplaneSessionHandoffError::InvalidPacket,
);
}
};
if datagram.ttl == 0 || datagram.dest_addr != local_addr {
return DataplaneSessionIngressHandoff::rejected(
output,
DataplaneSessionHandoffError::NoRoute,
);
}
let Some(prefix) = crate::node::session_wire::FspCommonPrefix::parse(datagram.payload)
else {
return DataplaneSessionIngressHandoff::rejected(
output,
DataplaneSessionHandoffError::InvalidPacket,
);
};
let coord_warmup = dataplane_fsp_coord_warmup(
datagram.src_addr,
local_addr,
datagram.payload,
&prefix,
);
coord_warmup.map(|coord_warmup| {
(
datagram.src_addr,
datagram.path_mtu,
prefix.phase != FSP_PHASE_ESTABLISHED || prefix.is_unencrypted(),
coord_warmup,
)
})
};
let (source_addr, path_mtu, local_delivery, coord_warmup) = match handoff_facts {
Ok(facts) => facts,
Err(error) => return DataplaneSessionIngressHandoff::rejected(output, error),
};
let ce_flag = fmp_header.flags() & crate::node::wire::FLAG_CE != 0;
let activity_tick = output.activity_tick;
let mut output = output;
let Some(mut payload) = output.take_opened_payload() else {
return DataplaneSessionIngressHandoff::rejected(
output,
DataplaneSessionHandoffError::InvalidPacket,
);
};
debug_assert!(payload.len() >= FMP_SESSION_PAYLOAD_OFFSET);
assert!(payload.trim_front(FMP_SESSION_PAYLOAD_OFFSET));
let path = TransportPath::live(transport_id, remote_addr.clone());
if local_delivery {
return DataplaneSessionIngressHandoff::Local(
DataplaneFspLocalSessionIngress::new(
source_addr,
previous_hop,
ce_flag,
path_mtu,
payload,
),
);
}
DataplaneSessionIngressHandoff::Raw {
raw: DataplaneRawIngress {
protocol: PacketProtocol::Fsp,
transport_id,
remote_addr,
path,
fsp_source: Some(source_addr),
previous_hop: Some(previous_hop),
ce_flag,
path_mtu,
activity_tick,
payload,
},
coord_warmup,
}
}
fn dataplane_fsp_coord_warmup(
source_addr: NodeAddr,
local_addr: NodeAddr,
payload: &[u8],
prefix: &crate::node::session_wire::FspCommonPrefix,
) -> Result<DataplaneFspCoordWarmup, DataplaneSessionHandoffError> {
if prefix.phase != FSP_PHASE_ESTABLISHED
|| prefix.is_unencrypted()
|| prefix.flags & crate::node::session_wire::FSP_FLAG_CP == 0
{
return Ok(DataplaneFspCoordWarmup::default());
}
if payload.len() < FSP_HEADER_SIZE {
return Err(DataplaneSessionHandoffError::InvalidPacket);
}
let (source_coords, local_coords, _coords_len) =
crate::node::session_wire::parse_encrypted_coords(&payload[FSP_HEADER_SIZE..])
.map_err(|_| DataplaneSessionHandoffError::InvalidPacket)?;
Ok(DataplaneFspCoordWarmup::from_parsed(
source_addr,
local_addr,
source_coords,
local_coords,
))
}