[HR] V-UPF: preserve PSC on N2 indirect (Access->Access) without QER (#2194)

Home-Routed roaming: during Xn/N2 handover the source gNB may forward
remaining DL data to the core using UL PDU Session Information (PSC).
On the V-UPF the PSC was lost on the indirect path because OHR+OHC
removed the incoming GTP-U header (and its extensions) and we did not
recreate PSC when no QER/QFI was provisioned by the V-SMF.

This change makes the V-UPF rebuild a DL PSC for the target gNB even
when QER is absent, limited to the Access->Access indirect path
(source gNB -> V-UPF -> target gNB).

Why this is needed in HR:
- In HR deployments the V-SMF typically does not provision QER/QFI for
  the temporary indirect path. Without recreating PSC from recvhdr, the
  extension header disappears after OHR+OHC and the target gNB cannot
  see the QFI during handover buffering/forwarding.
This commit is contained in:
Sukchan Lee
2025-08-15 11:03:54 +09:00
parent 0c56903c98
commit fb3cba40e5
3 changed files with 50 additions and 1 deletions

View File

@@ -1,6 +1,6 @@
---
title: "v2.7.6 - Bug fixed"
date: 2025-03-30 22:05:00 +0900
date: 2025-07-19 22:05:00 +0900
categories:
- Release
tags:

View File

@@ -303,6 +303,39 @@ bool ogs_pfcp_up_handle_pdr(
sendhdr.pdu_type =
OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_DL_PDU_SESSION_INFORMATION;
sendhdr.qos_flow_identifier = pdr->qer->qfi;
} else if (pdr->src_if == OGS_PFCP_INTERFACE_ACCESS &&
far->dst_if == OGS_PFCP_INTERFACE_ACCESS &&
recvhdr->qos_flow_identifier) {
/*
* HR Indirect Forwarding (source gNB -> V-UPF -> target gNB)
*
* Context:
* - Home-Routed roaming: the V-UPF is controlled by the V-SMF, which
* typically does not provision QER/QFI for the indirect path.
* - During Xn/N2 handover the source gNB may forward remaining DL data
* to the core using UL PDU Session Information (PSC PDU type = UL).
*
* Goal:
* - Preserve the PDU Session Container across the V-UPF hop and deliver
* it to the target gNB with PDU type = DL while keeping the same QFI.
*
* What we do here:
* - If this PDR has no QER/QFI and the path is Access->Access, derive
* PSC fields from the received header (recvhdr).
* - Force sendhdr.pdu_type = DL PDU Session Information.
* - Copy recvhdr->qos_flow_identifier into sendhdr.qos_flow_identifier.
* - The encapsulation routine will build a fresh GTP-U header and
* generate the PSC extension from sendhdr fields. This converts UL
* PSC to DL PSC and preserves the QFI for the target gNB.
*
* Why this is needed in HR:
* - With OHR+OHC, the incoming GTP-U (extensions included) is removed
* and a new one is created. Without recreating PSC from sendhdr.*, the
* extension header would be lost when QER is absent on the V-UPF.
*/
sendhdr.pdu_type =
OGS_GTP2_EXTENSION_HEADER_PDU_TYPE_DL_PDU_SESSION_INFORMATION;
sendhdr.qos_flow_identifier = recvhdr->qos_flow_identifier;
}
if (recvhdr) {
@@ -962,6 +995,14 @@ ogs_pfcp_pdr_t *ogs_pfcp_handle_update_pdr(ogs_pfcp_sess_t *sess,
}
}
if (message->outer_header_removal.presence) {
pdr->outer_header_removal_len =
ogs_min(message->outer_header_removal.len,
sizeof(pdr->outer_header_removal));
memcpy(&pdr->outer_header_removal, message->outer_header_removal.data,
pdr->outer_header_removal_len);
}
return pdr;
}

View File

@@ -198,6 +198,14 @@ void sgwu_sxa_handle_session_modification_request(
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
if (ogs_pfcp_handle_update_pdr(&sess->pfcp, &req->update_pdr[i],
&cause_value, &offending_ie_value) == NULL)
break;
}
if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
goto cleanup;
for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
if (ogs_pfcp_handle_remove_pdr(&sess->pfcp, &req->remove_pdr[i],
&cause_value, &offending_ie_value) == false)