Found while doing #109, which gives a secondary PDP context a user plane worth keeping.
What happens
ggsn_gn:handle_request/5 for delete_pdp_context_request (apps/smf_core/src/ggsn_gn.erl:246) discards the request's IEs entirely — ie = _IEs — and runs smf_gtp_gsn_lib:close_context_proc(?API, normal, Data0) on the whole context:
handle_request(ReqKey,
#gtp{type = delete_pdp_context_request, ie = _IEs} = Request,
_Resent, #{session := connected} = State,
#{tunnels := #{'Access' := AccessTunnel}} = Data0) ->
Proc = smf_gtp_gsn_lib:close_context_proc(?API, normal, Data0),
Neither the NSAPI (mandatory) nor the Teardown Ind (conditional) is read, so every Delete PDP Context Request deactivates the entire PDN connection.
What the spec requires (TS 29.060 §7.3.5, IE definition §7.7.16)
- Teardown Ind 1 ⇒ "all PDP contexts that share the same PDN connection with the PDP context identified by the NSAPI … shall be torn down". Teardown Ind 0 or absent ⇒ only the identified context.
- Whole-PDN-connection semantics come from the Teardown Ind, not from which NSAPI is named — unlike EPS, where naming the LBI is what means "tear everything down".
- The race guard: "If a GSN receives a Delete PDP context without a Teardown Indicator or with a Teardown Indicator with value set to '0' and only that PDP context is active for a PDN connection, then the GSN shall ignore the message." Not reject — ignore. "This is symptom of a race condition. The reliable delivery of signalling messages will eventually lead to a consistent situation."
So there are three behaviours here and the code implements one of them unconditionally.
Why it matters more now
Before #109 a secondary PDP context carried no user plane, so collapsing the whole connection on any deactivation lost little. Now that a secondary context gets its own bound PCC rule, PDR and GTP-U tunnel, an MS deactivating one service tears down the primary context's user plane with it.
What a fix needs
- Read
#nsapi{} and #teardown_ind{} from the request.
- Teardown Ind = 1, or the named NSAPI is the last active context: today's whole-context close.
- Teardown Ind 0/absent with other contexts active: remove just that bearer — drop
{'Access', NSAPI} and its {bearer_id, _} entry (smf_gsn_lib:remove_bearer_metadata_for_ebi/2 already does the metadata half), report the removal to the PCRF with Bearer-Operation TERMINATION (TS 29.212 A.3.1), and re-provision the UPF with one session modification.
- Teardown Ind 0/absent when it is the only active context: ignore the message, no response.
Test gap
ggsn_SUITE only ever deletes a whole PDN connection. The cases above want: deactivate the secondary and assert the primary's PDR survives; deactivate with Teardown Ind = 1 and assert both go; send a Teardown-Ind-less delete for a single-context connection and assert no response and a live context.
Related: #109 (the secondary context's user plane), #128 (the TFT half of the same Gx exchange).
Found while doing #109, which gives a secondary PDP context a user plane worth keeping.
What happens
ggsn_gn:handle_request/5fordelete_pdp_context_request(apps/smf_core/src/ggsn_gn.erl:246) discards the request's IEs entirely —ie = _IEs— and runssmf_gtp_gsn_lib:close_context_proc(?API, normal, Data0)on the whole context:Neither the NSAPI (mandatory) nor the Teardown Ind (conditional) is read, so every Delete PDP Context Request deactivates the entire PDN connection.
What the spec requires (TS 29.060 §7.3.5, IE definition §7.7.16)
So there are three behaviours here and the code implements one of them unconditionally.
Why it matters more now
Before #109 a secondary PDP context carried no user plane, so collapsing the whole connection on any deactivation lost little. Now that a secondary context gets its own bound PCC rule, PDR and GTP-U tunnel, an MS deactivating one service tears down the primary context's user plane with it.
What a fix needs
#nsapi{}and#teardown_ind{}from the request.{'Access', NSAPI}and its{bearer_id, _}entry (smf_gsn_lib:remove_bearer_metadata_for_ebi/2already does the metadata half), report the removal to the PCRF withBearer-OperationTERMINATION (TS 29.212 A.3.1), and re-provision the UPF with one session modification.Test gap
ggsn_SUITEonly ever deletes a whole PDN connection. The cases above want: deactivate the secondary and assert the primary's PDR survives; deactivate with Teardown Ind = 1 and assert both go; send a Teardown-Ind-less delete for a single-context connection and assert no response and a live context.Related: #109 (the secondary context's user plane), #128 (the TFT half of the same Gx exchange).