feat(mocn): add multi-PLMN MOCN support for OAI gNB#271
Conversation
|
There was a problem hiding this comment.
Pull request overview
This PR adds end-to-end NR gNB-side support for 5G MOCN by enabling multi-PLMN broadcast in SIB1, carrying per-PLMN slice info in F1AP served-cell structures, and letting nrUE select a PLMN from SIB1 based on IMSI so the already-existing selected-PLMN-aware NGAP/AMF routing can be exercised.
Changes:
- Extend F1AP served-cell information to represent multiple served PLMNs, each with its own slice list, and update encode/decode/copy/equality helpers plus unit tests.
- Wire multi-PLMN configuration into gNB config → MAC/RRC SIB1 generation, removing the previous single-PLMN assumption.
- Implement nrUE PLMN selection from SIB1 using IMSI MCC/MNC, and propagate selected PLMN into gNB UE context (F1 UE Context Setup).
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| targets/PROJECTS/GENERIC-NR-5GC/CONF/ue2.conf | Adds a second UE reference config for the two-PLMN validation setup. |
| targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf | Updates UE reference config to use the new PLMN/IMSI and slice parameters used in validation. |
| targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf | Updates gNB reference config for multi-PLMN broadcast and dual-AMF connectivity. |
| openair2/RRC/NR/rrc_gNB.c | Sends the UE-selected serving PLMN in F1 UE Context Setup instead of cell default PLMN. |
| openair2/RRC/NR/rrc_gNB_du.c | Replaces single-PLMN CU/DU validation with subset validation for MOCN. |
| openair2/RRC/NR_UE/rrc_UE.c | Adds nrUE PLMN selection by matching IMSI MCC/MNC against SIB1 PLMN list. |
| openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h | Extends get_SIB1_NR() API to accept a served-PLMN list. |
| openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c | Populates SIB1 with multiple PLMNs from the served-PLMN list. |
| openair2/LAYER2/NR_MAC_gNB/mac_proto.h | Extends nr_mac_configure_sib1() prototype to pass served-PLMN list. |
| openair2/LAYER2/NR_MAC_gNB/config.c | Passes served-PLMN list into SIB1 generation for SA mode. |
| openair2/GNB_APP/gnb_config.c | Parses plmn_list entries and per-PLMN slice lists into served-cell info for SIB1/F1. |
| openair2/F1AP/tests/f1ap_lib_test.c | Updates F1AP served-cell unit test to the new served-PLMN layout. |
| openair2/F1AP/lib/f1ap_lib_common.c | Updates served-cell equality helper to compare per-PLMN slice lists. |
| openair2/F1AP/lib/f1ap_interface_management.c | Encodes/decodes served-cell info as multiple served PLMNs with per-PLMN slice extensions. |
| openair2/COMMON/f1ap_messages_types.h | Introduces served-PLMN list structures and a max-PLMN constant for F1AP. |
| common/utils/telnetsrv/telnetsrv_o1.c | Adapts O1/telnet exporter to read slice info from the new served-PLMN structure. |
| prnt(" \"" SD "\": %d,\n", cell_info->served_plmn_list[0].nssai[0].sd); | ||
| prnt(" \"" SST "\": %d\n", cell_info->served_plmn_list[0].nssai[0].sst); |
| int num_plmn, | ||
| const f1ap_served_plmn_info_t *served_plmn_list) | ||
| { | ||
| AssertFatal(cellID < (1l << 36), "cellID must fit within 36 bits, but is %lu\n", cellID); |
| // Backwards-compat: if num_plmn==0 (legacy single-PLMN setup), fall back to c->plmn with no slices. | ||
| int num_splmn = c->num_plmn > 0 ? c->num_plmn : 1; |
| f1ap_served_cell_info_t dst = { | ||
| .plmn = src->plmn, | ||
| .nr_cellid = src->nr_cellid, | ||
| .nr_pci = src->nr_pci, | ||
| .num_ssi = src->num_ssi, | ||
| .num_plmn = src->num_plmn, |
| _EQ_CHECK_INT(a->num_plmn, b->num_plmn); | ||
| for (int i = 0; i < a->num_plmn; ++i) { | ||
| if (!eq_f1ap_plmn(&a->served_plmn_list[i].plmn, &b->served_plmn_list[i].plmn)) | ||
| return false; | ||
| _EQ_CHECK_INT(a->served_plmn_list[i].num_nssai, b->served_plmn_list[i].num_nssai); | ||
| for (int j = 0; j < a->served_plmn_list[i].num_nssai; ++j) { | ||
| _EQ_CHECK_INT(a->served_plmn_list[i].nssai[j].sst, b->served_plmn_list[i].nssai[j].sst); | ||
| _EQ_CHECK_INT(a->served_plmn_list[i].nssai[j].sd, b->served_plmn_list[i].nssai[j].sd); | ||
| } | ||
| } |
| } | ||
|
|
||
| NR_PLMN_IdentityInfoList_t *info_list = &sib1->cellAccessRelatedInfo.plmn_IdentityInfoList; | ||
| for (int i = 0; i < info_list->list.count && !plmn_matched; i++) { |
| dnn= "internet"; | ||
| nssai_sst=1; | ||
| nssai_sd=0x010203; |
| uicc0 = { | ||
| imsi = "208940000000004"; | ||
| key = "8baf473f2f8fd09487cccbd7097c6862"; | ||
| opc= "8e27b6af0e692e750f32667a3b14605d"; | ||
| dnn= "internet"; | ||
| nssai_sst=1; | ||
| nssai_sd=0x010204; |
| { mcc = 208; mnc = 93; mnc_length = 2; snssaiList = ({ sst = 1; sd = 0x010203; }) }, | ||
| { mcc = 208; mnc = 94; mnc_length = 2; snssaiList = ({ sst = 1; sd = 0x010204; }) } | ||
| ); | ||
| # { mcc = 208; mnc = 94; mnc_length = 2; snssaiList = ({ sst = 1; sd = 0x010204; }) } |
| amf_ip_address = ({ ipv4 = "128.105.145.152"; }, { ipv4 = "128.105.145.158"; }); | ||
|
|
||
| NETWORK_INTERFACES : | ||
| { | ||
| GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.70.129/24"; | ||
| GNB_IPV4_ADDRESS_FOR_NGU = "192.168.70.129/24"; | ||
| GNB_IPV4_ADDRESS_FOR_NG_AMF = "128.105.145.157/24"; |
|
Thanks for the contribution. We already discussed this in the past, and you had this already(!) in https://github.com/OPENAIRINTERFACE/openairinterface5g/pull/3/ (has been closed, no pull requests accepted and now that we can do this here, it's better). Please split out the commits into individual changes, e.g.:
If you don't have them anymore: I have them, let me know. overall the changes are good, but I'd like to have a second look once this is done, and also test it. |
Extend F1AP served-cell information to carry multiple served PLMNs and per-PLMN slice information (38.473 §9.3.1.10). - Add f1ap_served_plmn_info_t and F1AP_MAX_NB_PLMNS; replace the single slice list on f1ap_served_cell_info_t with a served-PLMN list. - Update F1AP encode/decode to emit and parse one ServedPLMNs item per broadcast PLMN with its own slice list, with legacy single-PLMN fallback. - Update copy/equal helpers and F1AP lib tests accordingly. Signed-off-by: Yuanhao Chang <changyuanhao15@gmail.com>
Read all configured plmn_list entries and each PLMN's snssaiList, and store them in the served-PLMN list carried in the F1AP served-cell info. - Populate info->served_plmn_list[] with every configured PLMN and its slices; keep info->plmn as the primary PLMN for backward compatibility. - Pass the served-PLMN list into nr_mac_configure_sib1() so SIB1 can advertise all PLMNs. Signed-off-by: Yuanhao Chang <changyuanhao15@gmail.com>
Carry the configured served-PLMN list into the MAC/RRC SIB1 configuration path so SIB1 can advertise multiple PLMNs. - Extend nr_mac_configure_sib1() and get_SIB1_NR() to accept the served PLMN list and count. - Remove the hard-coded single-PLMN assumption in SIB1 generation and emit one plmn-IdentityList entry per served PLMN. Signed-off-by: Yuanhao Chang <changyuanhao15@gmail.com>
Replace the legacy single-PLMN CU/DU validation with a MOCN-aware subset check and carry the UE-selected serving PLMN through the UE context. - Accept a DU/cell only if every DU-advertised served PLMN is present in the CU/gNB configured PLMN list, with legacy single-PLMN fallback. - Use the UE serving PLMN (instead of the cell's primary PLMN) when filling the F1AP UE context setup request. Signed-off-by: Yuanhao Chang <changyuanhao15@gmail.com>
Select the serving PLMN by matching the UE IMSI against the PLMNs advertised in SIB1. - Walk SIB1 plmn-IdentityInfoList / plmn-IdentityList and compare each entry's MCC/MNC against the UE IMSI (honouring the 2/3-digit MNC). - Set selected_plmn_identity (1-based) from the matched entry, falling back to the first PLMN when no match is found. Signed-off-by: Yuanhao Chang <changyuanhao15@gmail.com>
Update the O1/telnet exporter to read slice information from the new served-PLMN list layout of the F1AP served-cell structure. - Read slice info from served_plmn_list[0].nssai[0] instead of the removed top-level nssai[0]. - Pass the served-PLMN list and count into nr_mac_configure_sib1(). This is a mechanical adapter change required by the F1AP served-cell structure update. Signed-off-by: Yuanhao Chang <changyuanhao15@gmail.com>
Add the gNB/UE/UE2 configuration files used to validate the two-core MOCN setup, included as reproduction references. - gNB config broadcasts two PLMNs (20893 and 20894). - ue.conf selects PLMN 20893 (Core1); ue2.conf selects PLMN 20894 (Core2). Signed-off-by: Yuanhao Chang <changyuanhao15@gmail.com>
6c2161d to
b10a759
Compare
|
Validation: 5a04e32, 339bd38, 51e6de0, e1e59c5, a35daae, 39516a8, b10a759 Please use 'git commit -S' to sign your commits. |
Hi Robert, Thanks a lot for the feedback. I updated this PR by splitting the MOCN changes into layered commits following the structure you suggested. I remember the earlier PR/branch you mentioned. That version was based on a develop branch from a few months ago, and the old PR is no longer usable for this contribution. To make sure this contribution works with the current Duranta/OAI codebase, I re-ported the MOCN changes onto the current weekly develop branch, validated the end-to-end two-core setup again, and then split the tested changes into review-friendly commits. The PR is now organized into:
The final tree is identical to the previously tested one-commit version, so the final code content is unchanged. I hope this makes the review easier. Please let me know if you would prefer any commit to be split or combined differently. Best, |
Summary
This PR fills in the missing NR gNB-side support needed to run an end-to-end 5G MOCN setup in OAI.
The main goal is to allow one OAI gNB to advertise multiple PLMNs in SIB1 and let each UE select the appropriate PLMN based on its IMSI. The base OAI/Duranta code already has selected-PLMN-aware NGAP/AMF routing support. This PR wires up the missing NR gNB-side multi-PLMN broadcast/configuration and UE-selection path so that the selected PLMN can be used to route each UE to the Core serving that PLMN.
In other words, this PR completes the key NR gNB-side path needed for a working 5G MOCN deployment in OAI. The changes were ported onto the latest Duranta/OAI weekly
developbranch2026.w27and validated end-to-end with two independent L25GC+ cores (a free5GC-derived 5G Core).Main changes
F1AP served-cell information
gNB config and SIB1 broadcasting
plmn_listentries and theirsnssaiList.CU/DU PLMN validation
nrUE PLMN selection
plmn-IdentityInfoList.selected_plmn_identityaccording to the matched PLMN.RRC / selected PLMN propagation
O1 / telnet exporter adaptation
Reference configs
Validation
This PR was built and validated on the latest Duranta/OAI weekly
developbranch2026.w27using a two-core L25GC+ testbed.L25GC+ is a free5GC-derived 5G Core with UPF-side optimizations. In this validation setup, two independent L25GC+ cores were used to emulate two operators / two core networks.
Test topology:
node0: OAI gNB and two OAI nrUE instances.node1: L25GC+ Core1 / PLMN20893/ UPF1.node2: L25GC+ Core2 / PLMN20894/ UPF2.node3: DN1 for Core1.node4: DN2 for Core2.Validation results:
20893based on its IMSI.20894based on its IMSI.Screenshots / figures included in this PR: