5G/NR - Network Architecture - NRF

 

 

 

NR CORE - NRF

NRF stands for Network function Repository Function. Simply put, it works as a central registration center (registra) for all the Core Network Components. As shown in the following diagram, NRF has connected to all the 5G Core components in HPLMN and get connected to another NRF in VPLMN with N27 interface.

< 29.510 - Figure 4-1: 5G System architecture >

 

Why a network needs an NRF at all

The problem the NRF solves is easy to state. In the service based architecture any network function may need to call any other - the AMF needs the AUSF to authenticate a UE, the SMF needs the PCF for policy, almost everything needs the UDM at some point. If each of them had to be told in advance where all the others were, an operator would be maintaining a configuration file whose size grows with the square of the number of functions, and nothing could ever move without editing it.

So instead every function tells one central place what it is and what it offers, and everything else asks that place. That is the NRF. It is a registry and nothing more glamorous than that : NFs register themselves, and NFs look each other up. Once you have that, a new SMF can be started at any address at any time and the rest of the network finds it within seconds without a single configuration change.

Two things in the figure above are worth noticing. The first is that the NRF sits on the same bus as everybody else and exposes its own service interface, Nnrf. It is not infrastructure sitting underneath the architecture - it is an ordinary network function that happens to have a directory as its speciality. The second is the dotted N27 arc running across to the NRF in the VPLMN. Discovery has to work across a roaming boundary too, and it does so by one NRF asking another rather than by exposing every function of the home network to the visited one.

NOTE : this also answers a question left hanging on the network architecture page - why the NRF is drawn there with no reference point lines attached to it. A function whose whole purpose is to be reachable by everyone cannot be drawn in a diagram whose vocabulary is pairs of endpoints.

 

Followings are the name of each network component.
    AMF     Access and Mobility Management Function ==> Equivalent to MME in 4G
    AUSF    Authentication Server Function
    DN       Data Network
    NEF      Network Exposure Function
    NRF      Network Repository Function
    NSSF    Network Slice Selection Function
    PCF      Policy Control Function ==> Equivalent to PCRF in 5G
    (R)AN   (Radio) Access Network
    SMF     Session Management Function
    UDM     Unified Data Management==> Equivalent to HSS in 4G
    UPF      User Plane Function ==> Equivalent to PGW in 4G
    SMSF   SMS Function
    SEAF    SEcurity Anchor Function ==> part of AMF function
    

Since NRF is connected almost every components (Network Functions) and provide various services to all of them. Descriptions on this NF(Network Function) can be complicated. I may not be able to put all of the functionalities in this note. I will just write down those things which I have some hands-on experience with.

NF Registration to NRF

Each NF(Network Function) is supposed to register to NRF so that NRF can coordinate all the NFs whenever necessary.

< 29.510-Figure 5.2.2.2.2-1: NF Instance Registration >

That is the entire procedure - one request and one response - but the shape of the request is worth a moment because it explains several things you will see in the logs below.

   PUT  /nnrf-nfm/v1/nf-instances/{nfInstanceID}       body : the NFProfile
                                    |
                                    v
   201 Created  with the accepted NFProfile
   or 4xx / 5xx  with a ProblemDetails body
   or 3xx        a redirect to a different NRF

Notice that it is a PUT, not a POST, and that is not an arbitrary choice. In REST you use POST when the server decides the name of the new resource, and PUT when the client already knows it. Here the network function supplies its own identifier - a UUID it generated for itself - as part of the URI. It is telling the NRF "store this profile at this address", not "please create something and tell me where you put it".

The practical consequence is idempotency. Sending the same registration twice leaves the NRF in exactly the state one registration would have left it in. That matters enormously in a network of restarting containers : an SMF that crashes and comes back re-registers with the same UUID and simply replaces its own profile. There are no duplicates to clean up, and no need for the NF to check whether it is already registered before trying.

<hl1>NF Service Consumer</hl1> : Every Network Function (Core Network Components) except NRF itself.
<hl1>URI</hl1> : The URI of the NF that wants to get registered
<hl1>nfInstanceID</hl1> : UUID within the PLMN (e.g, 4947a69a-f61b-4bc1-b9da-47c9c5d14b64)

NFProfile : Network Function Profile which can carry a huge list of information as defined here.

The example messages shown below is from open5gs log. (For Official documentation of open5gs, go to open5gs.org. For basic tutorial about open5gs on sharetechnote, see the notes : Installation on Virtual Machine, Installation and test on Google Cloud, WebUI, Run)

Example : AMF Registration

The AMF is the function that owns a UE's connection - it is the only part of the core with a signalling path down to the device, and everything that needs to reach a UE has to go through it. What it registers here is a single service, namf-comm, the communication service. That is the door other functions knock on when they have something to deliver : when an SMF needs to tell a UE that a PDU session has been set up, it does not talk to the UE, it calls namf-comm on whichever AMF is currently serving it. Registering that service with the NRF is how the SMF is able to find out which AMF that is.

PUT

07/09 21:21:05.476: [sbi] DEBUG: [PUT] /nnrf-nfm/v1/nf-instances/0ab51768-ffcd-41ec-a11e-7954f71c156f
    (../lib/sbi/nghttp2-server.c:770)
07/09 21:21:05.476: [sbi] DEBUG: RECEIVED: 672 (../lib/sbi/nghttp2-server.c:773)
07/09 21:21:05.476: [sbi] DEBUG: {
    "nfInstanceId": "0ab51768-ffcd-41ec-a11e-7954f71c156f",
    "nfType":   "AMF",
    "nfStatus": "REGISTERED",
    "ipv4Addresses":    ["127.0.0.5"],
    "allowedNfTypes":   ["SMF"],
    "priority": 0,
    "capacity": 100,
    "load": 0,
    "nfServices":   [{
            "serviceInstanceId":    "0ab6167c-ffcd-41ec-a11e-7954f71c156f",
            "serviceName":  "namf-comm",
            "versions": [{
                    "apiVersionInUri":  "v1",
                    "apiFullVersion":   "1.0.0"
                }],
            "scheme":   "http",
            "nfServiceStatus":  "REGISTERED",
            "ipEndPoints":  [{
                    "ipv4Address":  "127.0.0.5",
                    "port": 7777
                }],
            "allowedNfTypes":   ["SMF"],
            "priority": 0,
            "capacity": 100,
            "load": 0
        }],
    "nfProfileChangesSupportInd":   true
}

 

201 Created

07/09 21:21:05.476: [sbi] DEBUG: STATUS [201] (../lib/sbi/nghttp2-server.c:347)
07/09 21:21:05.476: [sbi] DEBUG: SENDING...: 157 (../lib/sbi/nghttp2-server.c:355)
07/09 21:21:05.476: [sbi] DEBUG: {
    "nfInstanceId": "0ab51768-ffcd-41ec-a11e-7954f71c156f",
    "nfType":   "AMF",
    "nfStatus": "REGISTERED",
    "heartBeatTimer":   10,
    "nfProfileChangesInd":  true
}

Example : AUSF Registration

The AUSF exists to do one job and its profile reflects that - a single service, nausf-auth. When a UE registers, the AMF does not verify the subscriber's credentials itself ; it hands the problem to the AUSF, which runs the authentication exchange and tells the AMF whether it succeeded. Keeping this separate from the AMF is deliberate, because it means the sensitive part of the procedure lives in one small function that can be secured and scaled on its own. This is the shortest and simplest of the eight profiles, and it is a good one to read first.

PUT

07/08 02:45:18.834: [sbi] DEBUG: [PUT] /nnrf-nfm/v1/nf-instances/fa64abc8-fe67-41ec-b3d5-a934c5d291a8
    (../lib/sbi/nghttp2-server.c:770)
07/08 02:45:18.834: [sbi] DEBUG: RECEIVED: 676 (../lib/sbi/nghttp2-server.c:773)
07/08 02:45:18.834: [sbi] DEBUG: {
    "nfInstanceId": "fa64abc8-fe67-41ec-b3d5-a934c5d291a8",
    "nfType":   "AUSF",
    "nfStatus": "REGISTERED",
    "ipv4Addresses":    ["127.0.0.11"],
    "allowedNfTypes":   ["AMF"],
    "priority": 0,
    "capacity": 100,
    "load": 0,
    "nfServices":   [{
            "serviceInstanceId":    "fa64b79e-fe67-41ec-b3d5-a934c5d291a8",
            "serviceName":  "nausf-auth",
            "versions": [{
                    "apiVersionInUri":  "v1",
                    "apiFullVersion":   "1.0.0"
                }],
            "scheme":   "http",
            "nfServiceStatus":  "REGISTERED",
            "ipEndPoints":  [{
                    "ipv4Address":  "127.0.0.11",
                    "port": 7777
                }],
            "allowedNfTypes":   ["AMF"],
            "priority": 0,
            "capacity": 100,
            "load": 0
        }],
    "nfProfileChangesSupportInd":   true
}

 

201 Created

07/08 02:45:18.834: [sbi] DEBUG: STATUS [201] (../lib/sbi/nghttp2-server.c:347)
07/08 02:45:18.834: [sbi] DEBUG: SENDING...: 158 (../lib/sbi/nghttp2-server.c:355)
07/08 02:45:18.834: [sbi] DEBUG: {
    "nfInstanceId": "fa64abc8-fe67-41ec-b3d5-a934c5d291a8",
    "nfType":   "AUSF",
    "nfStatus": "REGISTERED",
    "heartBeatTimer":   10,
    "nfProfileChangesInd":  true
}

Example : UDM Registration

This is the most interesting profile of the eight, because the UDM registers three services rather than one and you can see all of them in the nfServices list below. nudm-sdm is subscriber data management - what this subscriber is entitled to. nudm-ueau is UE authentication, which generates the authentication vectors the AUSF needs. nudm-uecm is UE context management, which records which AMF and which SMF are currently serving this UE. Three different consumers use these at three different moments : the AUSF calls ueau during authentication, and the AMF calls sdm and uecm afterwards. Because they are registered as separate services, a consumer discovers exactly the one it needs rather than the UDM as a whole.

PUT

07/08 03:22:31.370: [sbi] DEBUG: [PUT] /nnrf-nfm/v1/nf-instances/33ae29b8-fe6d-41ec-9216-8d673c526000
    (../lib/sbi/nghttp2-server.c:770)
07/08 03:22:31.370: [sbi] DEBUG: RECEIVED: 1512 (../lib/sbi/nghttp2-server.c:773)
07/08 03:22:31.370: [sbi] DEBUG: {
    "nfInstanceId": "33ae29b8-fe6d-41ec-9216-8d673c526000",
    "nfType":   "UDM",
    "nfStatus": "REGISTERED",
    "ipv4Addresses":    ["127.0.0.12"],
    "allowedNfTypes":   ["AMF", "SMF", "AUSF"],
    "priority": 0,
    "capacity": 100,
    "load": 0,
    "nfServices":   [{
            "serviceInstanceId":    "33ae6342-fe6d-41ec-9216-8d673c526000",
            "serviceName":  "nudm-ueau",
            "versions": [{
                    "apiVersionInUri":  "v1",
                    "apiFullVersion":   "1.0.0"
                }],
            "scheme":   "http",
            "nfServiceStatus":  "REGISTERED",
            "ipEndPoints":  [{
                    "ipv4Address":  "127.0.0.12",
                    "port": 7777
                }],
            "allowedNfTypes":   ["AUSF"],
            "priority": 0,
            "capacity": 100,
            "load": 0
        }, {
            "serviceInstanceId":    "33ae6360-fe6d-41ec-9216-8d673c526000",
            "serviceName":  "nudm-uecm",
            "versions": [{
                    "apiVersionInUri":  "v1",
                    "apiFullVersion":   "1.0.0"
                }],
            "scheme":   "http",
            "nfServiceStatus":  "REGISTERED",
            "ipEndPoints":  [{
                    "ipv4Address":  "127.0.0.12",
                    "port": 7777
                }],
            "allowedNfTypes":   ["AMF"],
            "priority": 0,
            "capacity": 100,
            "load": 0
        }, {
            "serviceInstanceId":    "33ae636a-fe6d-41ec-9216-8d673c526000",
            "serviceName":  "nudm-sdm",
            "versions": [{
                    "apiVersionInUri":  "v2",
                    "apiFullVersion":   "2.0.0"
                }],
            "scheme":   "http",
            "nfServiceStatus":  "REGISTERED",
            "ipEndPoints":  [{
                    "ipv4Address":  "127.0.0.12",
                    "port": 7777
                }],
            "allowedNfTypes":   ["AMF", "SMF"],
            "priority": 0,
            "capacity": 100,
            "load": 0
        }],
    "nfProfileChangesSupportInd":   true

201 Created

07/08 03:22:31.371: [sbi] DEBUG: STATUS [201] (../lib/sbi/nghttp2-server.c:347)
07/08 03:22:31.371: [sbi] DEBUG: SENDING...: 157 (../lib/sbi/nghttp2-server.c:355)
07/08 03:22:31.371: [sbi] DEBUG: {
    "nfInstanceId": "33ae29b8-fe6d-41ec-9216-8d673c526000",
    "nfType":   "UDM",
    "nfStatus": "REGISTERED",
    "heartBeatTimer":   10,
    "nfProfileChangesInd":  true
}

Example : UDR Registration

The UDR is the storage behind the UDM, and it registers a single service, nudr-dr - the data repository. The split between the two is worth understanding as you read this profile next to the previous one : the UDM holds the logic and the UDR holds the data. In 4G both lived together inside the HSS. Separating them means the PCF and the NEF can read from the same repository without going through the UDM at all, which is the point of having made the split.

PUT

07/09 21:21:05.726: [sbi] DEBUG: [PUT] /nnrf-nfm/v1/nf-instances/0adb7b56-ffcd-41ec-8ac9-0f5331342d1b
    (../lib/sbi/nghttp2-server.c:770)
07/09 21:21:05.726: [sbi] DEBUG: RECEIVED: 686 (../lib/sbi/nghttp2-server.c:773)
07/09 21:21:05.726: [sbi] DEBUG: {
    "nfInstanceId": "0adb7b56-ffcd-41ec-8ac9-0f5331342d1b",
    "nfType":   "UDR",
    "nfStatus": "REGISTERED",
    "ipv4Addresses":    ["127.0.0.20"],
    "allowedNfTypes":   ["PCF", "UDM"],
    "priority": 0,
    "capacity": 100,
    "load": 0,
    "nfServices":   [{
            "serviceInstanceId":    "0adc404a-ffcd-41ec-8ac9-0f5331342d1b",
            "serviceName":  "nudr-dr",
            "versions": [{
                    "apiVersionInUri":  "v1",
                    "apiFullVersion":   "1.0.0"
                }],
            "scheme":   "http",
            "nfServiceStatus":  "REGISTERED",
            "ipEndPoints":  [{
                    "ipv4Address":  "127.0.0.20",
                    "port": 7777
                }],
            "allowedNfTypes":   ["PCF", "UDM"],
            "priority": 0,
            "capacity": 100,
            "load": 0
        }],
    "nfProfileChangesSupportInd":   true
}

201 Created

07/09 21:21:05.726: [sbi] DEBUG: STATUS [201] (../lib/sbi/nghttp2-server.c:347)
07/09 21:21:05.726: [sbi] DEBUG: SENDING...: 157 (../lib/sbi/nghttp2-server.c:355)
07/09 21:21:05.726: [sbi] DEBUG: {
    "nfInstanceId": "0adb7b56-ffcd-41ec-8ac9-0f5331342d1b",
    "nfType":   "UDR",
    "nfStatus": "REGISTERED",
    "heartBeatTimer":   10,
    "nfProfileChangesInd":  true
}

Example : PCF Registration

The PCF registers two services, and the reason is that it has two quite different customers. npcf-am-policy-control serves the AMF and deals with access and mobility policy - what this subscriber is allowed to do and where. npcf-smpolicycontrol serves the SMF and deals with session policy - bandwidth, charging rules and quality of service for a particular PDU session. Two consumers with two unrelated questions, so two separately discoverable services rather than one general purpose interface.

PUT

07/09 21:21:05.723: [sbi] DEBUG: [PUT] /nnrf-nfm/v1/nf-instances/0adae7a4-ffcd-41ec-aff0-b734789f4477
    (../lib/sbi/nghttp2-server.c:770)
07/09 21:21:05.723: [sbi] DEBUG: RECEIVED: 1146 (../lib/sbi/nghttp2-server.c:773)
07/09 21:21:05.723: [sbi] DEBUG: {
    "nfInstanceId": "0adae7a4-ffcd-41ec-aff0-b734789f4477",
    "nfType":   "PCF",
    "nfStatus": "REGISTERED",
    "ipv4Addresses":    ["127.0.0.13"],
    "allowedNfTypes":   ["AMF", "SMF", "NEF", "AF"],
    "priority": 0,
    "capacity": 100,
    "load": 0,
    "nfServices":   [{
            "serviceInstanceId":    "0adb8b96-ffcd-41ec-aff0-b734789f4477",
            "serviceName":  "npcf-am-policy-control",
            "versions": [{
                    "apiVersionInUri":  "v1",
                    "apiFullVersion":   "1.0.0"
                }],
            "scheme":   "http",
            "nfServiceStatus":  "REGISTERED",
            "ipEndPoints":  [{
                    "ipv4Address":  "127.0.0.13",
                    "port": 7777
                }],
            "allowedNfTypes":   ["AMF", "NEF"],
            "priority": 0,
            "capacity": 100,
            "load": 0
        }, {
            "serviceInstanceId":    "0adb8baa-ffcd-41ec-aff0-b734789f4477",
            "serviceName":  "npcf-smpolicycontrol",
            "versions": [{
                    "apiVersionInUri":  "v1",
                    "apiFullVersion":   "1.0.0"
                }],
            "scheme":   "http",
            "nfServiceStatus":  "REGISTERED",
            "ipEndPoints":  [{
                    "ipv4Address":  "127.0.0.13",
                    "port": 7777
                }],
            "allowedNfTypes":   ["SMF", "NEF", "AF"],
            "priority": 0,
            "capacity": 100,
            "load": 0
        }],
    "nfProfileChangesSupportInd":   true
}

201 Created

07/09 21:21:05.723: [sbi] DEBUG: STATUS [201] (../lib/sbi/nghttp2-server.c:347)
07/09 21:21:05.723: [sbi] DEBUG: SENDING...: 157 (../lib/sbi/nghttp2-server.c:355)
07/09 21:21:05.723: [sbi] DEBUG: {
    "nfInstanceId": "0adae7a4-ffcd-41ec-aff0-b734789f4477",
    "nfType":   "PCF",
    "nfStatus": "REGISTERED",
    "heartBeatTimer":   10,
    "nfProfileChangesInd":  true
}

Example : SMF Registration

The SMF owns PDU sessions - creating them, modifying them, tearing them down - and it controls the UPF that actually forwards the traffic. It registers one service, nsmf-pdusession, covering that entire life cycle. The consumer here is normally the AMF : when a UE asks for a data session, the AMF finds an SMF through the NRF and calls this service. Note that the interface to the UPF does not appear anywhere in this profile, because N4 is not a service based interface at all - the SMF's relationship with its UPF is not something other functions discover.

PUT

07/09 21:21:06.081: [sbi] DEBUG: [PUT] /nnrf-nfm/v1/nf-instances/0adf454c-ffcd-41ec-9f8e-25aaf51f9b14
    (../lib/sbi/nghttp2-server.c:770)
07/09 21:21:06.081: [sbi] DEBUG: RECEIVED: 678 (../lib/sbi/nghttp2-server.c:773)
07/09 21:21:06.081: [sbi] DEBUG: {
    "nfInstanceId": "0adf454c-ffcd-41ec-9f8e-25aaf51f9b14",
    "nfType":   "SMF",
    "nfStatus": "REGISTERED",
    "ipv4Addresses":    ["127.0.0.4"],
    "allowedNfTypes":   ["AMF"],
    "priority": 0,
    "capacity": 100,
    "load": 0,
    "nfServices":   [{
            "serviceInstanceId":    "0b11ac76-ffcd-41ec-9f8e-25aaf51f9b14",
            "serviceName":  "nsmf-pdusession",
            "versions": [{
                    "apiVersionInUri":  "v1",
                    "apiFullVersion":   "1.0.0"
                }],
            "scheme":   "http",
            "nfServiceStatus":  "REGISTERED",
            "ipEndPoints":  [{
                    "ipv4Address":  "127.0.0.4",
                    "port": 7777
                }],
            "allowedNfTypes":   ["AMF"],
            "priority": 0,
            "capacity": 100,
            "load": 0
        }],
    "nfProfileChangesSupportInd":   true
}

201 Created

07/09 21:21:06.081: [sbi] DEBUG: STATUS [201] (../lib/sbi/nghttp2-server.c:347)
07/09 21:21:06.081: [sbi] DEBUG: SENDING...: 157 (../lib/sbi/nghttp2-server.c:355)
07/09 21:21:06.081: [sbi] DEBUG: {
    "nfInstanceId": "0adf454c-ffcd-41ec-9f8e-25aaf51f9b14",
    "nfType":   "SMF",
    "nfStatus": "REGISTERED",
    "heartBeatTimer":   10,
    "nfProfileChangesInd":  true
}

Example : NSSF Registration

The NSSF answers one question - which network slice instance should serve this UE - and registers one service to do it, nnssf-nsselection. It is called by the AMF during registration, when the UE has asked for particular slices and the network has to decide which slice instances actually apply. This is a function with no equivalent in 4G at all, which makes its profile a small illustration of how a genuinely new capability is added to this architecture : a new function type, one service, registered by the same mechanism as everything else, and nothing in the NRF had to change to accommodate it.

PUT

07/08 03:20:40.354: [sbi] DEBUG: [PUT] /nnrf-nfm/v1/nf-instances/eaf3a41e-fe6c-41ec-9185-39782a1733b6
    (../lib/sbi/nghttp2-server.c:770)
07/08 03:20:40.354: [sbi] DEBUG: RECEIVED: 683 (../lib/sbi/nghttp2-server.c:773)
07/08 03:20:40.354: [sbi] DEBUG: {
    "nfInstanceId": "eaf3a41e-fe6c-41ec-9185-39782a1733b6",
    "nfType":   "NSSF",
    "nfStatus": "REGISTERED",
    "ipv4Addresses":    ["127.0.0.14"],
    "allowedNfTypes":   ["AMF"],
    "priority": 0,
    "capacity": 100,
    "load": 0,
    "nfServices":   [{
            "serviceInstanceId":    "eaf42bd2-fe6c-41ec-9185-39782a1733b6",
            "serviceName":  "nnssf-nsselection",
            "versions": [{
                    "apiVersionInUri":  "v2",
                    "apiFullVersion":   "2.0.0"
                }],
            "scheme":   "http",
            "nfServiceStatus":  "REGISTERED",
            "ipEndPoints":  [{
                    "ipv4Address":  "127.0.0.14",
                    "port": 7777
                }],
            "allowedNfTypes":   ["AMF"],
            "priority": 0,
            "capacity": 100,
            "load": 0
        }],
    "nfProfileChangesSupportInd":   true
}

201 Created

07/08 03:20:40.354: [sbi] DEBUG: STATUS [201] (../lib/sbi/nghttp2-server.c:347)
07/08 03:20:40.354: [sbi] DEBUG: SENDING...: 158 (../lib/sbi/nghttp2-server.c:355)
07/08 03:20:40.354: [sbi] DEBUG: {
    "nfInstanceId": "eaf3a41e-fe6c-41ec-9185-39782a1733b6",
    "nfType":   "NSSF",
    "nfStatus": "REGISTERED",
    "heartBeatTimer":   10,
    "nfProfileChangesInd":  true
} (../lib/sbi/nghttp2-server.c:356)

 

Example : BSF Registration

The BSF is the least familiar of the eight and its job is a binding problem. It registers nbsf-management, and what it keeps is the association between a UE's IP address and the PCF that is handling that UE's session. The reason this is needed is that an application function arriving later - asking for, say, prioritised treatment for a particular video flow - often knows nothing about the subscriber except an IP address. Without the BSF there would be no way to get from that address back to the right PCF. It is a small piece of plumbing, but registering it in the NRF is what allows the AF to find it.

PUT

07/09 21:21:06.262: [sbi] DEBUG: [PUT] /nnrf-nfm/v1/nf-instances/0b2e7414-ffcd-41ec-9c59-a56e64429106
    (../lib/sbi/nghttp2-server.c:770)
07/09 21:21:06.262: [sbi] DEBUG: RECEIVED: 680 (../lib/sbi/nghttp2-server.c:773)
07/09 21:21:06.262: [sbi] DEBUG: {
    "nfInstanceId": "0b2e7414-ffcd-41ec-9c59-a56e64429106",
    "nfType":   "BSF",
    "nfStatus": "REGISTERED",
    "ipv4Addresses":    ["127.0.0.15"],
    "allowedNfTypes":   ["PCF"],
    "priority": 0,
    "capacity": 100,
    "load": 0,
    "nfServices":   [{
            "serviceInstanceId":    "0b2e7aa4-ffcd-41ec-9c59-a56e64429106",
            "serviceName":  "nbsf-management",
            "versions": [{
                    "apiVersionInUri":  "v1",
                    "apiFullVersion":   "1.0.0"
                }],
            "scheme":   "http",
            "nfServiceStatus":  "REGISTERED",
            "ipEndPoints":  [{
                    "ipv4Address":  "127.0.0.15",
                    "port": 7777
                }],
            "allowedNfTypes":   ["PCF"],
            "priority": 0,
            "capacity": 100,
            "load": 0
        }],
    "nfProfileChangesSupportInd":   true
}

201 Created

07/09 21:21:06.262: [sbi] DEBUG: STATUS [201] (../lib/sbi/nghttp2-server.c:347)
07/09 21:21:06.262: [sbi] DEBUG: SENDING...: 157 (../lib/sbi/nghttp2-server.c:355)
07/09 21:21:06.262: [sbi] DEBUG: {
    "nfInstanceId": "0b2e7414-ffcd-41ec-9c59-a56e64429106",
    "nfType":   "BSF",
    "nfStatus": "REGISTERED",
    "heartBeatTimer":   10,
    "nfProfileChangesInd":  true
}

Reading the eight registrations together

Having eight of these side by side is more useful than any one of them, because the interesting thing is how little changes between them. All eight are the same request to the same endpoint carrying the same structure - and pulling out the fields that actually differ gives a very short table :

Example nfType nfServices registered heartBeat capacity

AMF

AMF

namf-comm

10

100

AUSF

AUSF

nausf-auth

10

100

UDM

UDM

nudm-sdm, nudm-ueau, nudm-uecm

10

100

UDR

UDR

nudr-dr

10

100

PCF

PCF

npcf-am-policy-control, npcf-smpolicycontrol

10

100

SMF

SMF

nsmf-pdusession

10

100

NSSF

NSSF

nnssf-nsselection

10

100

BSF

BSF

nbsf-management

10

100

Only two columns actually vary, and that is the whole argument for a service based architecture in one observation. There is no per-function registration API. A BSF registers by exactly the same mechanism as an AMF, and if a new network function type were invented tomorrow it would register the same way again without the NRF needing to know anything about it.

The service column is where the real information is. Notice that the UDM registers three separate services and the PCF two, while everything else registers one. That is not padding - it is the unit of discovery. A consumer does not ask "where is a UDM?", it asks "who provides nudm-ueau for this PLMN?". Splitting the UDM's subscriber data management, authentication and UE context management into three named services means those can be found, versioned and eventually scaled apart from each other.

The identical numbers are worth reading too. heartBeatTimer is 10 in all eight and capacity is 100 in all eight, because these logs come from one Open5GS deployment using its defaults - they are not values 3GPP mandates. What they mean is this :

Field What it does

heartBeatTimer

The NF is promising to check in at least this often, in seconds. If it stops, the NRF eventually marks the profile SUSPENDED and stops handing it out. This is how a crashed function disappears from the network without anybody deregistering it - the registry is a lease, not a permanent record

capacity and load

Static capability and current utilisation, both 0 to 100. The NRF returns them with a discovery result so that a consumer facing several candidates can choose the least busy one rather than always the first

nfStatus

REGISTERED, SUSPENDED or UNDISCOVERABLE. A function can stay registered while asking not to be handed out - useful for draining it before maintenance

nfInstanceId

The UUID in the request URI. It belongs to the function, not to the NRF, which is what makes re-registration after a restart safe

The rest of the life cycle

Registration is only the first of four operations, and the logs on this page show the first one. The complete set is small :

   PUT     /nnrf-nfm/v1/nf-instances/{id}     register, or replace the whole profile
   PATCH   /nnrf-nfm/v1/nf-instances/{id}     heartbeat, or change one field such as load
   GET     /nnrf-disc/v1/nf-instances?...     discovery - the query other NFs actually use
   DELETE  /nnrf-nfm/v1/nf-instances/{id}     deregister, on a clean shutdown

The two management operations live under nnrf-nfm and discovery lives under nnrf-disc - two separate services of the same network function, which is the same pattern the UDM uses in the table above. Note also that the heartbeat is a PATCH rather than a repeated PUT : there is no need to resend an entire profile every ten seconds just to say "still here", so the NF sends a minimal patch instead.

Structured Data Types

There are various structured data type being used in communication between NF and NRF. These data types are specified in 39.510-6.1.6.2. This section is mostly direct copies of those tables that I am interested. If you don't find any of those structures, refer to 39.510

NFProfile

The NFProfile is the only thing a network function ever tells the NRF about itself. Everything the rest of the network will later be able to discover - where this function is, what it can do, which slices and PLMNs it serves, whether it is healthy, how busy it is - has to be expressible inside this one structure. That is why it runs to sixteen pages of table. It is not describing a message ; it is describing the complete vocabulary available for one function to advertise itself.

The table has five columns, and the one worth reading first is the narrow one marked P, for presence. M means mandatory, O optional, and C conditional - required only when some stated circumstance applies. Scanning down that column rather than reading the descriptions is by far the quickest way to get the shape of the thing, and what it reveals is that the mandatory core is remarkably small. The M entries are clustered right at the top of the first page :

   nfInstanceId   M    who am I          - the UUID that also forms the registration URI
   nfType         M    what am I         - AMF, SMF, UDM and so on
   nfStatus       M    can I be used     - REGISTERED, SUSPENDED, UNDISCOVERABLE

   everything after this is O or C

Three fields is a complete, valid registration. Everything in the remaining fifteen pages is refinement on top of that : how to reach the function (fqdn, ipv4Addresses, ipEndPoints), what it actually offers (nfServices), which slices and networks it serves (sNssais, plmnList, snpnList), how much work it can take (capacity, load, priority), and how long the NRF should wait before assuming it has died (heartBeatTimer). None of that is required, because a registry that demanded all of it could not accept a function that did not have all of it.

That is also the answer to why the table is so long relative to what you actually saw in the logs above. One structure has to serve every network function type that exists or might later be invented - an NSSF, a UPF, a charging function and an AMF all register through this same definition - so it accumulates attributes that only matter to some of them. Go back and look at any of the eight profiles earlier on this page and you are seeing a small, sensible subset : the identifiers, an address, a service list, a heartbeat and a capacity figure. The other fields are simply absent, and their absence is not an omission but the normal case.

NOTE : one field on the first page is worth reading closely while you are here, because its description says more than you would expect. heartBeatTimer is negotiated rather than declared - the NF proposes a value in its registration, and the NRF returns either the same value or one of its own choosing in the response. So the number you see in a registration request is a request, and the number in the 201 Created is the one that actually applies.

< 29.510 - 29.510-Table 6.1.6.2.2-1: Definition of type NFProfile >

Reference :