use crate::error::PfcpError;
use crate::ie::{
application_id::ApplicationId, ethernet_packet_filter::EthernetPacketFilter, f_teid::Fteid,
marshal_ies, network_instance::NetworkInstance, protocol_description::ProtocolDescription,
qfi::Qfi, redundant_transmission_parameters::RedundantTransmissionParameters,
sdf_filter::SdfFilter, source_interface::SourceInterface,
three_gpp_interface_type::ThreeGppInterfaceTypeIe, ue_ip_address::UeIpAddress, Ie, IeIterator,
IeType,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Pdi {
pub source_interface: SourceInterface,
pub f_teid: Option<Fteid>,
pub network_instance: Option<NetworkInstance>,
pub ue_ip_addresses: Vec<UeIpAddress>,
pub sdf_filters: Vec<SdfFilter>,
pub application_id: Option<ApplicationId>,
pub ethernet_packet_filters: Vec<EthernetPacketFilter>,
pub qfis: Vec<Qfi>,
pub three_gpp_interface_type: Option<ThreeGppInterfaceTypeIe>,
pub redundant_transmission_parameters: Option<RedundantTransmissionParameters>,
pub protocol_description: Option<ProtocolDescription>,
pub ies: Vec<Ie>,
}
impl Pdi {
pub fn new(source_interface: SourceInterface) -> Self {
Pdi {
source_interface,
f_teid: None,
network_instance: None,
ue_ip_addresses: Vec::new(),
sdf_filters: Vec::new(),
application_id: None,
ethernet_packet_filters: Vec::new(),
qfis: Vec::new(),
three_gpp_interface_type: None,
redundant_transmission_parameters: None,
protocol_description: None,
ies: Vec::new(),
}
}
pub fn marshal(&self) -> Vec<u8> {
let mut ies = vec![self.source_interface.to_ie()];
if let Some(f_teid) = &self.f_teid {
ies.push(f_teid.to_ie());
}
if let Some(ni) = &self.network_instance {
ies.push(ni.to_ie());
}
ies.extend(self.ue_ip_addresses.iter().map(UeIpAddress::to_ie));
ies.extend(self.sdf_filters.iter().map(SdfFilter::to_ie));
if let Some(app_id) = &self.application_id {
ies.push(app_id.to_ie());
}
ies.extend(
self.ethernet_packet_filters
.iter()
.map(EthernetPacketFilter::to_ie),
);
ies.extend(self.qfis.iter().map(Qfi::to_ie));
if let Some(interface_type) = &self.three_gpp_interface_type {
ies.push(interface_type.to_ie());
}
if let Some(ref rtp) = self.redundant_transmission_parameters {
ies.push(rtp.to_ie());
}
if let Some(ref pd) = self.protocol_description {
ies.push(pd.to_ie());
}
ies.extend(self.ies.iter().cloned());
marshal_ies(&ies)
}
pub fn unmarshal(payload: &[u8]) -> Result<Self, PfcpError> {
let mut source_interface = None;
let mut f_teid = None;
let mut network_instance = None;
let mut ue_ip_addresses = Vec::new();
let mut sdf_filters = Vec::new();
let mut application_id = None;
let mut ethernet_packet_filters = Vec::new();
let mut qfis = Vec::new();
let mut three_gpp_interface_type = None;
let mut redundant_transmission_parameters = None;
let mut protocol_description = None;
let mut ies = Vec::new();
for ie_result in IeIterator::new(payload) {
let ie = ie_result?;
match ie.ie_type {
IeType::SourceInterface => {
source_interface = Some(SourceInterface::unmarshal(&ie.payload)?);
}
IeType::Fteid => {
f_teid = Some(Fteid::unmarshal(&ie.payload)?);
}
IeType::NetworkInstance => {
network_instance = Some(NetworkInstance::unmarshal(&ie.payload)?);
}
IeType::UeIpAddress => {
ue_ip_addresses.push(UeIpAddress::unmarshal(&ie.payload)?);
}
IeType::SdfFilter => {
sdf_filters.push(SdfFilter::unmarshal(&ie.payload)?);
}
IeType::ApplicationId => {
application_id = Some(ApplicationId::unmarshal(&ie.payload)?);
}
IeType::EthernetPacketFilter => {
ethernet_packet_filters.push(EthernetPacketFilter::unmarshal(&ie.payload)?);
}
IeType::Qfi => qfis.push(Qfi::unmarshal(&ie.payload)?),
IeType::TgppInterfaceType => {
three_gpp_interface_type =
Some(ThreeGppInterfaceTypeIe::unmarshal(&ie.payload)?);
}
IeType::RedundantTransmissionParameters => {
redundant_transmission_parameters =
Some(RedundantTransmissionParameters::unmarshal(&ie.payload)?);
}
IeType::ProtocolDescription => {
protocol_description = Some(ProtocolDescription::unmarshal(&ie.payload)?);
}
_ => ies.push(ie),
}
}
Ok(Pdi {
source_interface: source_interface.ok_or(PfcpError::missing_ie_in_grouped(
IeType::SourceInterface,
IeType::Pdi,
))?,
f_teid,
network_instance,
ue_ip_addresses,
sdf_filters,
application_id,
ethernet_packet_filters,
qfis,
three_gpp_interface_type,
redundant_transmission_parameters,
protocol_description,
ies,
})
}
pub fn to_ie(&self) -> Ie {
Ie::new(IeType::Pdi, self.marshal())
}
}
#[derive(Debug, Default)]
pub struct PdiBuilder {
source_interface: Option<SourceInterface>,
f_teid: Option<Fteid>,
network_instance: Option<NetworkInstance>,
ue_ip_addresses: Vec<UeIpAddress>,
sdf_filters: Vec<SdfFilter>,
application_id: Option<ApplicationId>,
ethernet_packet_filters: Vec<EthernetPacketFilter>,
qfis: Vec<Qfi>,
three_gpp_interface_type: Option<ThreeGppInterfaceTypeIe>,
redundant_transmission_parameters: Option<RedundantTransmissionParameters>,
protocol_description: Option<ProtocolDescription>,
ies: Vec<Ie>,
}
impl PdiBuilder {
pub fn new(source_interface: SourceInterface) -> Self {
PdiBuilder {
source_interface: Some(source_interface),
..Default::default()
}
}
pub fn f_teid(mut self, f_teid: Fteid) -> Self {
self.f_teid = Some(f_teid);
self
}
pub fn network_instance(mut self, network_instance: NetworkInstance) -> Self {
self.network_instance = Some(network_instance);
self
}
pub fn ue_ip_address(mut self, ue_ip_address: UeIpAddress) -> Self {
self.ue_ip_addresses.push(ue_ip_address);
self
}
pub fn sdf_filter(mut self, sdf_filter: SdfFilter) -> Self {
self.sdf_filters.push(sdf_filter);
self
}
pub fn application_id(mut self, application_id: impl Into<ApplicationId>) -> Self {
self.application_id = Some(application_id.into());
self
}
pub fn ethernet_packet_filter(mut self, filter: EthernetPacketFilter) -> Self {
self.ethernet_packet_filters.push(filter);
self
}
pub fn qfi(mut self, qfi: Qfi) -> Self {
self.qfis.push(qfi);
self
}
pub fn three_gpp_interface_type(mut self, interface_type: ThreeGppInterfaceTypeIe) -> Self {
self.three_gpp_interface_type = Some(interface_type);
self
}
pub fn redundant_transmission_parameters(
mut self,
parameters: RedundantTransmissionParameters,
) -> Self {
self.redundant_transmission_parameters = Some(parameters);
self
}
pub fn protocol_description(mut self, description: ProtocolDescription) -> Self {
self.protocol_description = Some(description);
self
}
pub fn ie(mut self, ie: Ie) -> Self {
self.ies.push(ie);
self
}
pub fn build(self) -> Result<Pdi, PfcpError> {
let source_interface = self.source_interface.ok_or(PfcpError::MissingMandatoryIe {
ie_type: IeType::SourceInterface,
message_type: None,
parent_ie: Some(IeType::Pdi),
})?;
Ok(Pdi {
source_interface,
f_teid: self.f_teid,
network_instance: self.network_instance,
ue_ip_addresses: self.ue_ip_addresses,
sdf_filters: self.sdf_filters,
application_id: self.application_id,
ethernet_packet_filters: self.ethernet_packet_filters,
qfis: self.qfis,
three_gpp_interface_type: self.three_gpp_interface_type,
redundant_transmission_parameters: self.redundant_transmission_parameters,
protocol_description: self.protocol_description,
ies: self.ies,
})
}
pub fn uplink_access() -> Self {
use crate::ie::source_interface::{SourceInterface, SourceInterfaceValue};
PdiBuilder::new(SourceInterface::new(SourceInterfaceValue::Access))
}
pub fn downlink_core() -> Self {
use crate::ie::source_interface::{SourceInterface, SourceInterfaceValue};
PdiBuilder::new(SourceInterface::new(SourceInterfaceValue::Core))
}
pub fn sgi_lan() -> Self {
use crate::ie::source_interface::{SourceInterface, SourceInterfaceValue};
PdiBuilder::new(SourceInterface::new(SourceInterfaceValue::SgiLan))
}
pub fn cp_function() -> Self {
use crate::ie::source_interface::{SourceInterface, SourceInterfaceValue};
PdiBuilder::new(SourceInterface::new(SourceInterfaceValue::CpFunction))
}
}
impl Pdi {
pub fn builder(source_interface: SourceInterface) -> PdiBuilder {
PdiBuilder::new(source_interface)
}
pub fn uplink_access() -> Self {
PdiBuilder::uplink_access()
.build()
.expect("Uplink access PDI construction should not fail")
}
pub fn downlink_core() -> Self {
PdiBuilder::downlink_core()
.build()
.expect("Downlink core PDI construction should not fail")
}
pub fn sgi_lan() -> Self {
PdiBuilder::sgi_lan()
.build()
.expect("SGi-LAN PDI construction should not fail")
}
pub fn cp_function() -> Self {
PdiBuilder::cp_function()
.build()
.expect("CP function PDI construction should not fail")
}
pub fn uplink_access_with_teid(f_teid: Fteid) -> Self {
PdiBuilder::uplink_access()
.f_teid(f_teid)
.build()
.expect("Uplink access PDI with F-TEID construction should not fail")
}
pub fn downlink_core_with_ue_ip(ue_ip: UeIpAddress) -> Self {
PdiBuilder::downlink_core()
.ue_ip_address(ue_ip)
.build()
.expect("Downlink core PDI with UE IP construction should not fail")
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ie::f_teid::FteidBuilder;
use crate::ie::network_instance::NetworkInstance;
use crate::ie::sdf_filter::SdfFilter;
use crate::ie::source_interface::{SourceInterface, SourceInterfaceValue};
use crate::ie::three_gpp_interface_type::{ThreeGppInterfaceType, ThreeGppInterfaceTypeIe};
use crate::ie::ue_ip_address::UeIpAddress;
use std::net::Ipv4Addr;
#[test]
fn test_pdi_builder_basic() {
let source_interface = SourceInterface::new(SourceInterfaceValue::Access);
let pdi = PdiBuilder::new(source_interface).build().unwrap();
assert_eq!(pdi.source_interface, source_interface);
assert!(pdi.f_teid.is_none());
assert!(pdi.network_instance.is_none());
assert!(pdi.ue_ip_addresses.is_empty());
assert!(pdi.sdf_filters.is_empty());
assert!(pdi.application_id.is_none());
let marshaled = pdi.marshal();
let unmarshaled = Pdi::unmarshal(&marshaled).unwrap();
assert_eq!(pdi, unmarshaled);
}
#[test]
fn test_pdi_builder_with_f_teid() {
let source_interface = SourceInterface::new(SourceInterfaceValue::Access);
let fteid = FteidBuilder::new()
.teid(0x12345678)
.ipv4(Ipv4Addr::new(192, 168, 1, 1))
.build()
.unwrap();
let pdi = PdiBuilder::new(source_interface)
.f_teid(fteid.clone())
.build()
.unwrap();
assert_eq!(pdi.source_interface, source_interface);
assert_eq!(pdi.f_teid, Some(fteid));
assert!(pdi.network_instance.is_none());
assert!(pdi.ue_ip_addresses.is_empty());
assert!(pdi.sdf_filters.is_empty());
assert!(pdi.application_id.is_none());
let marshaled = pdi.marshal();
let unmarshaled = Pdi::unmarshal(&marshaled).unwrap();
assert_eq!(pdi, unmarshaled);
}
#[test]
fn test_pdi_builder_with_network_instance() {
let source_interface = SourceInterface::new(SourceInterfaceValue::Core);
let network_instance = NetworkInstance::new("internet.mnc001.mcc001.gprs");
let pdi = PdiBuilder::new(source_interface)
.network_instance(network_instance.clone())
.build()
.unwrap();
assert_eq!(pdi.source_interface, source_interface);
assert!(pdi.f_teid.is_none());
assert_eq!(pdi.network_instance, Some(network_instance));
assert!(pdi.ue_ip_addresses.is_empty());
assert!(pdi.sdf_filters.is_empty());
assert!(pdi.application_id.is_none());
let marshaled = pdi.marshal();
let unmarshaled = Pdi::unmarshal(&marshaled).unwrap();
assert_eq!(pdi, unmarshaled);
}
#[test]
fn test_pdi_with_three_gpp_interface_type() {
let interface_type = ThreeGppInterfaceTypeIe::new(ThreeGppInterfaceType::N3);
let pdi = PdiBuilder::uplink_access()
.three_gpp_interface_type(interface_type)
.build()
.unwrap();
let unmarshaled = Pdi::unmarshal(&pdi.marshal()).unwrap();
assert_eq!(unmarshaled.three_gpp_interface_type, Some(interface_type));
}
#[test]
fn test_pdi_builder_with_ue_ip() {
let source_interface = SourceInterface::new(SourceInterfaceValue::Core);
let ue_ip = UeIpAddress::new(Some(Ipv4Addr::new(10, 0, 0, 1)), None);
let pdi = PdiBuilder::new(source_interface)
.ue_ip_address(ue_ip.clone())
.build()
.unwrap();
assert_eq!(pdi.source_interface, source_interface);
assert!(pdi.f_teid.is_none());
assert!(pdi.network_instance.is_none());
assert_eq!(pdi.ue_ip_addresses, [ue_ip]);
assert!(pdi.sdf_filters.is_empty());
assert!(pdi.application_id.is_none());
let marshaled = pdi.marshal();
let unmarshaled = Pdi::unmarshal(&marshaled).unwrap();
assert_eq!(pdi, unmarshaled);
}
#[test]
fn test_pdi_builder_with_sdf_filter() {
let source_interface = SourceInterface::new(SourceInterfaceValue::Access);
let sdf_filter = SdfFilter::new("permit out ip from any to any");
let pdi = PdiBuilder::new(source_interface)
.sdf_filter(sdf_filter.clone())
.build()
.unwrap();
assert_eq!(pdi.source_interface, source_interface);
assert!(pdi.f_teid.is_none());
assert!(pdi.network_instance.is_none());
assert!(pdi.ue_ip_addresses.is_empty());
assert_eq!(pdi.sdf_filters, [sdf_filter]);
assert!(pdi.application_id.is_none());
let marshaled = pdi.marshal();
let unmarshaled = Pdi::unmarshal(&marshaled).unwrap();
assert_eq!(pdi, unmarshaled);
}
#[test]
fn test_pdi_preserves_repeated_and_unknown_ies() {
let mut pdi = PdiBuilder::uplink_access()
.ue_ip_address(UeIpAddress::new(Some(Ipv4Addr::new(10, 0, 0, 1)), None))
.ue_ip_address(UeIpAddress::new(Some(Ipv4Addr::new(10, 0, 0, 2)), None))
.sdf_filter(SdfFilter::new("permit out ip from any to any"))
.sdf_filter(SdfFilter::new("permit out tcp from any to any 443"))
.qfi(Qfi::of(8))
.qfi(Qfi::of(9))
.build()
.unwrap();
pdi.ies
.push(Ie::new(IeType::FramedRoute, b"192.0.2.0/24".to_vec()));
let decoded = Pdi::unmarshal(&pdi.marshal()).unwrap();
assert_eq!(decoded.ue_ip_addresses.len(), 2);
assert_eq!(decoded.sdf_filters.len(), 2);
assert_eq!(decoded.qfis, [Qfi::of(8), Qfi::of(9)]);
assert_eq!(decoded.ies, pdi.ies);
}
#[test]
fn test_pdi_builder_with_application_id() {
let source_interface = SourceInterface::new(SourceInterfaceValue::Access);
let app_id = "com.example.app";
let pdi = PdiBuilder::new(source_interface)
.application_id(app_id)
.build()
.unwrap();
assert_eq!(pdi.source_interface, source_interface);
assert!(pdi.f_teid.is_none());
assert!(pdi.network_instance.is_none());
assert!(pdi.ue_ip_addresses.is_empty());
assert!(pdi.sdf_filters.is_empty());
assert_eq!(pdi.application_id, Some(ApplicationId::new(app_id)));
let marshaled = pdi.marshal();
let unmarshaled = Pdi::unmarshal(&marshaled).unwrap();
assert_eq!(pdi, unmarshaled);
}
#[test]
fn test_pdi_builder_comprehensive() {
let source_interface = SourceInterface::new(SourceInterfaceValue::Access);
let fteid = FteidBuilder::new()
.teid(0)
.choose_ipv4()
.choose_id(42)
.build()
.unwrap();
let network_instance = NetworkInstance::new("ims.mnc001.mcc001.gprs");
let ue_ip = UeIpAddress::new(Some(Ipv4Addr::new(172, 16, 0, 100)), None);
let sdf_filter = SdfFilter::new("permit out tcp from any to any 80");
let app_id = "com.example.webapp";
let pdi = PdiBuilder::new(source_interface)
.f_teid(fteid.clone())
.network_instance(network_instance.clone())
.ue_ip_address(ue_ip.clone())
.sdf_filter(sdf_filter.clone())
.application_id(app_id)
.build()
.unwrap();
assert_eq!(pdi.source_interface, source_interface);
assert_eq!(pdi.f_teid, Some(fteid));
assert_eq!(pdi.network_instance, Some(network_instance));
assert_eq!(pdi.ue_ip_addresses, [ue_ip]);
assert_eq!(pdi.sdf_filters, [sdf_filter]);
assert_eq!(pdi.application_id, Some(ApplicationId::new(app_id)));
let marshaled = pdi.marshal();
let unmarshaled = Pdi::unmarshal(&marshaled).unwrap();
assert_eq!(pdi, unmarshaled);
}
#[test]
fn test_pdi_builder_missing_source_interface() {
let result = PdiBuilder::default().build();
assert!(result.is_err());
match result.unwrap_err() {
PfcpError::MissingMandatoryIe { ie_type, .. } => {
assert_eq!(ie_type, IeType::SourceInterface);
}
_ => panic!("Expected MissingMandatoryIe error"),
}
}
#[test]
fn test_pdi_builder_uplink_access() {
let pdi = PdiBuilder::uplink_access().build().unwrap();
assert_eq!(pdi.source_interface.value, SourceInterfaceValue::Access);
assert!(pdi.f_teid.is_none());
assert!(pdi.network_instance.is_none());
assert!(pdi.ue_ip_addresses.is_empty());
assert!(pdi.sdf_filters.is_empty());
assert!(pdi.application_id.is_none());
let marshaled = pdi.marshal();
let unmarshaled = Pdi::unmarshal(&marshaled).unwrap();
assert_eq!(pdi, unmarshaled);
}
#[test]
fn test_pdi_builder_downlink_core() {
let pdi = PdiBuilder::downlink_core().build().unwrap();
assert_eq!(pdi.source_interface.value, SourceInterfaceValue::Core);
assert!(pdi.f_teid.is_none());
assert!(pdi.network_instance.is_none());
assert!(pdi.ue_ip_addresses.is_empty());
assert!(pdi.sdf_filters.is_empty());
assert!(pdi.application_id.is_none());
let marshaled = pdi.marshal();
let unmarshaled = Pdi::unmarshal(&marshaled).unwrap();
assert_eq!(pdi, unmarshaled);
}
#[test]
fn test_pdi_builder_sgi_lan() {
let pdi = PdiBuilder::sgi_lan().build().unwrap();
assert_eq!(pdi.source_interface.value, SourceInterfaceValue::SgiLan);
assert!(pdi.f_teid.is_none());
assert!(pdi.network_instance.is_none());
assert!(pdi.ue_ip_addresses.is_empty());
assert!(pdi.sdf_filters.is_empty());
assert!(pdi.application_id.is_none());
let marshaled = pdi.marshal();
let unmarshaled = Pdi::unmarshal(&marshaled).unwrap();
assert_eq!(pdi, unmarshaled);
}
#[test]
fn test_pdi_builder_cp_function() {
let pdi = PdiBuilder::cp_function().build().unwrap();
assert_eq!(pdi.source_interface.value, SourceInterfaceValue::CpFunction);
assert!(pdi.f_teid.is_none());
assert!(pdi.network_instance.is_none());
assert!(pdi.ue_ip_addresses.is_empty());
assert!(pdi.sdf_filters.is_empty());
assert!(pdi.application_id.is_none());
let marshaled = pdi.marshal();
let unmarshaled = Pdi::unmarshal(&marshaled).unwrap();
assert_eq!(pdi, unmarshaled);
}
#[test]
fn test_pdi_builder_uplink_with_f_teid() {
let fteid = FteidBuilder::new().teid(0).choose_ipv6().build().unwrap();
let pdi = PdiBuilder::uplink_access()
.f_teid(fteid.clone())
.build()
.unwrap();
assert_eq!(pdi.source_interface.value, SourceInterfaceValue::Access);
assert_eq!(pdi.f_teid, Some(fteid));
assert!(pdi.network_instance.is_none());
assert!(pdi.ue_ip_addresses.is_empty());
assert!(pdi.sdf_filters.is_empty());
assert!(pdi.application_id.is_none());
let marshaled = pdi.marshal();
let unmarshaled = Pdi::unmarshal(&marshaled).unwrap();
assert_eq!(pdi, unmarshaled);
}
#[test]
fn test_pdi_builder_downlink_with_ue_ip() {
let ue_ip = UeIpAddress::new(Some(Ipv4Addr::new(192, 168, 100, 50)), None);
let pdi = PdiBuilder::downlink_core()
.ue_ip_address(ue_ip.clone())
.build()
.unwrap();
assert_eq!(pdi.source_interface.value, SourceInterfaceValue::Core);
assert!(pdi.f_teid.is_none());
assert!(pdi.network_instance.is_none());
assert_eq!(pdi.ue_ip_addresses, [ue_ip]);
assert!(pdi.sdf_filters.is_empty());
assert!(pdi.application_id.is_none());
let marshaled = pdi.marshal();
let unmarshaled = Pdi::unmarshal(&marshaled).unwrap();
assert_eq!(pdi, unmarshaled);
}
#[test]
fn test_pdi_convenience_uplink_access() {
let pdi = Pdi::uplink_access();
assert_eq!(pdi.source_interface.value, SourceInterfaceValue::Access);
assert!(pdi.f_teid.is_none());
assert!(pdi.network_instance.is_none());
assert!(pdi.ue_ip_addresses.is_empty());
assert!(pdi.sdf_filters.is_empty());
assert!(pdi.application_id.is_none());
}
#[test]
fn test_pdi_convenience_downlink_core() {
let pdi = Pdi::downlink_core();
assert_eq!(pdi.source_interface.value, SourceInterfaceValue::Core);
assert!(pdi.f_teid.is_none());
assert!(pdi.network_instance.is_none());
assert!(pdi.ue_ip_addresses.is_empty());
assert!(pdi.sdf_filters.is_empty());
assert!(pdi.application_id.is_none());
}
#[test]
fn test_pdi_convenience_sgi_lan() {
let pdi = Pdi::sgi_lan();
assert_eq!(pdi.source_interface.value, SourceInterfaceValue::SgiLan);
assert!(pdi.f_teid.is_none());
assert!(pdi.network_instance.is_none());
assert!(pdi.ue_ip_addresses.is_empty());
assert!(pdi.sdf_filters.is_empty());
assert!(pdi.application_id.is_none());
}
#[test]
fn test_pdi_convenience_cp_function() {
let pdi = Pdi::cp_function();
assert_eq!(pdi.source_interface.value, SourceInterfaceValue::CpFunction);
assert!(pdi.f_teid.is_none());
assert!(pdi.network_instance.is_none());
assert!(pdi.ue_ip_addresses.is_empty());
assert!(pdi.sdf_filters.is_empty());
assert!(pdi.application_id.is_none());
}
#[test]
fn test_pdi_convenience_uplink_access_with_teid() {
let fteid = FteidBuilder::new()
.teid(0x11223344)
.ipv4(Ipv4Addr::new(10, 10, 10, 10))
.build()
.unwrap();
let pdi = Pdi::uplink_access_with_teid(fteid.clone());
assert_eq!(pdi.source_interface.value, SourceInterfaceValue::Access);
assert_eq!(pdi.f_teid, Some(fteid));
assert!(pdi.network_instance.is_none());
assert!(pdi.ue_ip_addresses.is_empty());
assert!(pdi.sdf_filters.is_empty());
assert!(pdi.application_id.is_none());
}
#[test]
fn test_pdi_convenience_downlink_core_with_ue_ip() {
let ue_ip = UeIpAddress::new(Some(Ipv4Addr::new(203, 0, 113, 1)), None);
let pdi = Pdi::downlink_core_with_ue_ip(ue_ip.clone());
assert_eq!(pdi.source_interface.value, SourceInterfaceValue::Core);
assert!(pdi.f_teid.is_none());
assert!(pdi.network_instance.is_none());
assert_eq!(pdi.ue_ip_addresses, [ue_ip]);
assert!(pdi.sdf_filters.is_empty());
assert!(pdi.application_id.is_none());
}
#[test]
fn test_pdi_builder_method() {
let source_interface = SourceInterface::new(SourceInterfaceValue::Access);
let pdi = Pdi::builder(source_interface)
.application_id("test.app")
.build()
.unwrap();
assert_eq!(pdi.source_interface, source_interface);
assert_eq!(pdi.application_id, Some(ApplicationId::new("test.app")));
}
#[test]
fn test_pdi_builder_method_chaining() {
let source_interface = SourceInterface::new(SourceInterfaceValue::Core);
let fteid = FteidBuilder::new()
.teid(0xDEADBEEF)
.dual_stack(
Ipv4Addr::new(192, 168, 1, 100),
"2001:db8::100".parse().unwrap(),
)
.build()
.unwrap();
let network_instance = NetworkInstance::new("test.apn");
let app_id = "chained.test";
let pdi = Pdi::builder(source_interface)
.application_id(app_id)
.f_teid(fteid.clone())
.network_instance(network_instance.clone())
.build()
.unwrap();
assert_eq!(pdi.source_interface, source_interface);
assert_eq!(pdi.f_teid, Some(fteid));
assert_eq!(pdi.network_instance, Some(network_instance));
assert_eq!(pdi.application_id, Some(ApplicationId::new(app_id)));
}
}