Skip to content

Commit

Permalink
[SMF] Added Bi-Directional Flow (open5gs#2909)
Browse files Browse the repository at this point in the history
For bi-directions, the rules are created in the same form as for downlink
as shown below, so to apply them for uplink, we need to swap the rules
according to the interface.

RX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
PFCP : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
RULE : Source <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> Destination <UE_IP> <UE_PORT>
TFT : Local <UE_IP> <UE_PORT> REMOTE <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>

RX : permit in from <UE_IP> <UE_PORT> to <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
PFCP : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
RULE : Source <UE_IP> <UE_PORT> Destination <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
TFT : Local <UE_IP> <UE_PORT> REMOTE <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT>
  • Loading branch information
acetcom committed Feb 17, 2024
1 parent 843c495 commit 41d8934
Show file tree
Hide file tree
Showing 19 changed files with 1,035 additions and 136 deletions.
3 changes: 2 additions & 1 deletion lib/diameter/gx/message.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* Gx Interface, 3GPP TS 29.212 section 4
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
Expand Down Expand Up @@ -43,6 +43,7 @@ extern "C" {
#define OGS_DIAM_GX_AVP_CODE_FLOW_STATUS (511)
#define OGS_DIAM_GX_AVP_CODE_QOS_INFORMATION (1016)
#define OGS_DIAM_GX_AVP_CODE_PRECEDENCE (1010)
#define OGS_DIAM_GX_AVP_CODE_RATING_GROUP (432)

extern struct dict_object *ogs_diam_gx_application;

Expand Down
243 changes: 154 additions & 89 deletions lib/ipfw/ogs-ipfw.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
Expand Down Expand Up @@ -395,117 +395,167 @@ void ogs_pf_content_from_ipfw_rule(
* Network support Local Address in TFTs.
*/

if (rule->ipv4_src && (direction == OGS_FLOW_DOWNLINK_ONLY)) {
content->component[j].type = OGS_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE;
content->component[j].ipv4.addr = rule->ip.src.addr[0];
content->component[j].ipv4.mask = rule->ip.src.mask[0];
j++; len += 9;
}

if (rule->ipv4_src && (direction == OGS_FLOW_UPLINK_ONLY) &&
!no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type = OGS_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE;
content->component[j].ipv4.addr = rule->ip.src.addr[0];
content->component[j].ipv4.mask = rule->ip.src.mask[0];
j++; len += 9;
}

if (rule->ipv4_dst && (direction == OGS_FLOW_DOWNLINK_ONLY) &&
!no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type = OGS_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE;
content->component[j].ipv4.addr = rule->ip.dst.addr[0];
content->component[j].ipv4.mask = rule->ip.dst.mask[0];
j++; len += 9;
}

if (rule->ipv4_dst && (direction == OGS_FLOW_UPLINK_ONLY)) {
content->component[j].type = OGS_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE;
content->component[j].ipv4.addr = rule->ip.dst.addr[0];
content->component[j].ipv4.mask = rule->ip.dst.mask[0];
j++; len += 9;
}

if (rule->ipv6_src && (direction == OGS_FLOW_DOWNLINK_ONLY)) {
if (no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_TYPE;
memcpy(content->component[j].ipv6_mask.addr,
rule->ip.src.addr, sizeof rule->ip.src.addr);
memcpy(content->component[j].ipv6_mask.mask,
rule->ip.src.mask, sizeof rule->ip.src.mask);
j++; len += 33;
} else {
if (rule->ipv4_src) {
switch (direction) {
case OGS_FLOW_DOWNLINK_ONLY:
case OGS_FLOW_BIDIRECTIONAL:
content->component[j].type =
OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE;
memcpy(content->component[j].ipv6.addr,
rule->ip.src.addr, sizeof rule->ip.src.addr);
content->component[j].ipv6.prefixlen =
contigmask((uint8_t *)rule->ip.src.mask, 128);
j++; len += 18;
OGS_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE;
content->component[j].ipv4.addr = rule->ip.src.addr[0];
content->component[j].ipv4.mask = rule->ip.src.mask[0];
j++; len += 9;
break;
case OGS_FLOW_UPLINK_ONLY:
if (!no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type =
OGS_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE;
content->component[j].ipv4.addr = rule->ip.src.addr[0];
content->component[j].ipv4.mask = rule->ip.src.mask[0];
j++; len += 9;
}
break;
default:
ogs_fatal("Unsupported direction [%d]", direction);
ogs_assert_if_reached();
}
}

if (rule->ipv6_src && (direction == OGS_FLOW_UPLINK_ONLY)) {
if (!no_ipv4v6_local_addr_in_packet_filter) {
if (rule->ipv4_dst) {
switch (direction) {
case OGS_FLOW_DOWNLINK_ONLY:
case OGS_FLOW_BIDIRECTIONAL:
if (!no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type =
OGS_PACKET_FILTER_IPV4_LOCAL_ADDRESS_TYPE;
content->component[j].ipv4.addr = rule->ip.dst.addr[0];
content->component[j].ipv4.mask = rule->ip.dst.mask[0];
j++; len += 9;
}
break;
case OGS_FLOW_UPLINK_ONLY:
content->component[j].type =
OGS_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE;
memcpy(content->component[j].ipv6.addr,
rule->ip.src.addr, sizeof rule->ip.src.addr);
content->component[j].ipv6.prefixlen =
contigmask((uint8_t *)rule->ip.src.mask, 128);
j++; len += 18;
OGS_PACKET_FILTER_IPV4_REMOTE_ADDRESS_TYPE;
content->component[j].ipv4.addr = rule->ip.dst.addr[0];
content->component[j].ipv4.mask = rule->ip.dst.mask[0];
j++; len += 9;
break;
default:
ogs_fatal("Unsupported direction [%d]", direction);
ogs_assert_if_reached();
}
}

if (rule->ipv6_dst && (direction == OGS_FLOW_DOWNLINK_ONLY)) {
if (!no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE;
memcpy(content->component[j].ipv6.addr,
rule->ip.dst.addr, sizeof rule->ip.dst.addr);
content->component[j].ipv6.prefixlen =
contigmask((uint8_t *)rule->ip.dst.mask, 128);
j++; len += 18;
if (rule->ipv6_src) {
switch (direction) {
case OGS_FLOW_DOWNLINK_ONLY:
case OGS_FLOW_BIDIRECTIONAL:
if (no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_TYPE;
memcpy(content->component[j].ipv6_mask.addr,
rule->ip.src.addr, sizeof rule->ip.src.addr);
memcpy(content->component[j].ipv6_mask.mask,
rule->ip.src.mask, sizeof rule->ip.src.mask);
j++; len += 33;
} else {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE;
memcpy(content->component[j].ipv6.addr,
rule->ip.src.addr, sizeof rule->ip.src.addr);
content->component[j].ipv6.prefixlen =
contigmask((uint8_t *)rule->ip.src.mask, 128);
j++; len += 18;
}
break;
case OGS_FLOW_UPLINK_ONLY:
if (!no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE;
memcpy(content->component[j].ipv6.addr,
rule->ip.src.addr, sizeof rule->ip.src.addr);
content->component[j].ipv6.prefixlen =
contigmask((uint8_t *)rule->ip.src.mask, 128);
j++; len += 18;
}
break;
default:
ogs_fatal("Unsupported direction [%d]", direction);
ogs_assert_if_reached();
}
}

if (rule->ipv6_dst && (direction == OGS_FLOW_UPLINK_ONLY)) {
if (no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_TYPE;
memcpy(content->component[j].ipv6_mask.addr,
rule->ip.dst.addr, sizeof rule->ip.dst.addr);
memcpy(content->component[j].ipv6_mask.mask,
rule->ip.dst.mask, sizeof rule->ip.dst.mask);
j++; len += 33;
} else {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE;
memcpy(content->component[j].ipv6.addr,
if (rule->ipv6_dst) {
switch (direction) {
case OGS_FLOW_DOWNLINK_ONLY:
case OGS_FLOW_BIDIRECTIONAL:
if (!no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_LOCAL_ADDRESS_PREFIX_LENGTH_TYPE;
memcpy(content->component[j].ipv6.addr,
rule->ip.dst.addr, sizeof rule->ip.dst.addr);
content->component[j].ipv6.prefixlen =
contigmask((uint8_t *)rule->ip.dst.mask, 128);
j++; len += 18;
content->component[j].ipv6.prefixlen =
contigmask((uint8_t *)rule->ip.dst.mask, 128);
j++; len += 18;
}
break;
case OGS_FLOW_UPLINK_ONLY:
if (no_ipv4v6_local_addr_in_packet_filter) {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_TYPE;
memcpy(content->component[j].ipv6_mask.addr,
rule->ip.dst.addr, sizeof rule->ip.dst.addr);
memcpy(content->component[j].ipv6_mask.mask,
rule->ip.dst.mask, sizeof rule->ip.dst.mask);
j++; len += 33;
} else {
content->component[j].type =
OGS_PACKET_FILTER_IPV6_REMOTE_ADDRESS_PREFIX_LENGTH_TYPE;
memcpy(content->component[j].ipv6.addr,
rule->ip.dst.addr, sizeof rule->ip.dst.addr);
content->component[j].ipv6.prefixlen =
contigmask((uint8_t *)rule->ip.dst.mask, 128);
j++; len += 18;
}
break;
default:
ogs_fatal("Unsupported direction [%d]", direction);
ogs_assert_if_reached();
}
}

if (rule->port.src.low) {
if (rule->port.src.low == rule->port.src.high) {
if (direction == OGS_FLOW_DOWNLINK_ONLY)
switch (direction) {
case OGS_FLOW_DOWNLINK_ONLY:
case OGS_FLOW_BIDIRECTIONAL:
content->component[j].type =
OGS_PACKET_FILTER_SINGLE_REMOTE_PORT_TYPE;
else
break;
case OGS_FLOW_UPLINK_ONLY:
content->component[j].type =
OGS_PACKET_FILTER_SINGLE_LOCAL_PORT_TYPE;
break;
default:
ogs_fatal("Unsupported direction [%d]", direction);
ogs_assert_if_reached();
}
content->component[j].port.low = rule->port.src.low;
j++; len += 3;
} else {
if (direction == OGS_FLOW_DOWNLINK_ONLY)
switch (direction) {
case OGS_FLOW_DOWNLINK_ONLY:
case OGS_FLOW_BIDIRECTIONAL:
content->component[j].type =
OGS_PACKET_FILTER_REMOTE_PORT_RANGE_TYPE;
else
break;
case OGS_FLOW_UPLINK_ONLY:
content->component[j].type =
OGS_PACKET_FILTER_LOCAL_PORT_RANGE_TYPE;
break;
default:
ogs_fatal("Unsupported direction [%d]", direction);
ogs_assert_if_reached();
}
content->component[j].port.low = rule->port.src.low;
content->component[j].port.high = rule->port.src.high;
j++; len += 5;
Expand All @@ -514,21 +564,37 @@ void ogs_pf_content_from_ipfw_rule(

if (rule->port.dst.low) {
if (rule->port.dst.low == rule->port.dst.high) {
if (direction == OGS_FLOW_DOWNLINK_ONLY)
switch (direction) {
case OGS_FLOW_DOWNLINK_ONLY:
case OGS_FLOW_BIDIRECTIONAL:
content->component[j].type =
OGS_PACKET_FILTER_SINGLE_LOCAL_PORT_TYPE;
else
break;
case OGS_FLOW_UPLINK_ONLY:
content->component[j].type =
OGS_PACKET_FILTER_SINGLE_REMOTE_PORT_TYPE;
break;
default:
ogs_fatal("Unsupported direction [%d]", direction);
ogs_assert_if_reached();
}
content->component[j].port.low = rule->port.dst.low;
j++; len += 3;
} else {
if (direction == OGS_FLOW_DOWNLINK_ONLY)
switch (direction) {
case OGS_FLOW_DOWNLINK_ONLY:
case OGS_FLOW_BIDIRECTIONAL:
content->component[j].type =
OGS_PACKET_FILTER_LOCAL_PORT_RANGE_TYPE;
else
break;
case OGS_FLOW_UPLINK_ONLY:
content->component[j].type =
OGS_PACKET_FILTER_REMOTE_PORT_RANGE_TYPE;
break;
default:
ogs_fatal("Unsupported direction [%d]", direction);
ogs_assert_if_reached();
}
content->component[j].port.low = rule->port.dst.low;
content->component[j].port.high = rule->port.dst.high;
j++; len += 5;
Expand All @@ -538,4 +604,3 @@ void ogs_pf_content_from_ipfw_rule(
content->num_of_component = j;
content->length = len;
}

4 changes: 2 additions & 2 deletions lib/ipfw/ogs-ipfw.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
Expand Down Expand Up @@ -68,7 +68,7 @@ char *ogs_ipfw_encode_flow_description(ogs_ipfw_rule_t *ipfw_rule);
* Refer to lib/ipfw/ogs-ipfw.h
* Issue #338
*
* <DOWNLINK>
* <DOWNLINK/BI-DIRECTIONAL>>
* RX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
* GX : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
* PFCP : permit out from <P-CSCF_RTP_IP> <P-CSCF_RTP_PORT> to <UE_IP> <UE_PORT>
Expand Down
36 changes: 27 additions & 9 deletions lib/pfcp/build.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
Expand Down Expand Up @@ -364,10 +364,19 @@ void ogs_pfcp_build_create_pdr(

memset(pfcp_sdf_filter, 0, sizeof(pfcp_sdf_filter));
for (j = 0; j < pdr->num_of_flow && j < OGS_MAX_NUM_OF_FLOW_IN_PDR; j++) {
pfcp_sdf_filter[j].fd = 1;
pfcp_sdf_filter[j].flow_description_len =
strlen(pdr->flow_description[j]);
pfcp_sdf_filter[j].flow_description = pdr->flow_description[j];
ogs_assert(pdr->flow[j].fd || pdr->flow[j].bid);

if (pdr->flow[j].fd) {
pfcp_sdf_filter[j].fd = 1;
pfcp_sdf_filter[j].flow_description_len =
strlen(pdr->flow[j].description);
pfcp_sdf_filter[j].flow_description = pdr->flow[j].description;
}
if (pdr->flow[j].bid) {
pfcp_sdf_filter[j].bid = 1;
pfcp_sdf_filter[j].sdf_filter_id = pdr->flow[j].sdf_filter_id;
}

len = sizeof(ogs_pfcp_sdf_filter_t) +
pfcp_sdf_filter[j].flow_description_len;

Expand Down Expand Up @@ -493,10 +502,19 @@ void ogs_pfcp_build_update_pdr(

memset(pfcp_sdf_filter, 0, sizeof(pfcp_sdf_filter));
for (j = 0; j < pdr->num_of_flow && j < OGS_MAX_NUM_OF_FLOW_IN_PDR; j++) {
pfcp_sdf_filter[j].fd = 1;
pfcp_sdf_filter[j].flow_description_len =
strlen(pdr->flow_description[j]);
pfcp_sdf_filter[j].flow_description = pdr->flow_description[j];
ogs_assert(pdr->flow[j].fd || pdr->flow[j].bid);

if (pdr->flow[j].fd) {
pfcp_sdf_filter[j].fd = 1;
pfcp_sdf_filter[j].flow_description_len =
strlen(pdr->flow[j].description);
pfcp_sdf_filter[j].flow_description = pdr->flow[j].description;
}
if (pdr->flow[j].bid) {
pfcp_sdf_filter[j].bid = 1;
pfcp_sdf_filter[j].sdf_filter_id = pdr->flow[j].sdf_filter_id;
}

len = sizeof(ogs_pfcp_sdf_filter_t) +
pfcp_sdf_filter[j].flow_description_len;

Expand Down
Loading

0 comments on commit 41d8934

Please sign in to comment.