How it works
Open5GS has a lightweight HTTP server (already used for /metrics
) embedded in some NFs.
New optional JSON endpoints were added:
NF | Endpoint | Content |
---|---|---|
SMF | /pdu-info | All currently connected UEs + their PDU sessions (IMSI/SUPI, DNN, IPs, S-NSSAI, QoS, state, etc.) |
AMF | /gnb-info | All currently connected gNBs and their supported TAs, PLMNs, SCTP info, number of UEs |
AMF | /ue-info | All currently connected NR UEs and their info, active gNB, tai, security, slices, am_policy |
MME | /enb-info | All currently connected eNBs and their supported TAs, PLMNs, SCTP info, number of UEs |
MME | /ue-info | All currently connected LTE UEs and their info, active eNB, tai, pdn info |
They are exposed on the same HTTP port used by Prometheus metrics (default :9090
).
To reduce processor load when there are a large number of devices, the API includes a pager that limits output.
/ue-info?page=0&page_size=100
page in the range 0-n (0 is default),
page=-1
to avoid paging
page_size=100
(default and MAX)
How to enable
You need to build Open5GS from the latest main
branch:
git clone https://github.com/open5gs/open5gs.git
cd open5gsgit checkout mainmeson build --prefix=`pwd`/installninja -C build install
How to use
### Get info about PDUs from all UEs connected to 5G NR and LTE basestation
contains session info as APN/DNN, IP addresses, slice info, QoS info, PDU/PDN_state and UE_activity status
curl -s "http://127.0.0.4:9090/pdu-info" |jq .
Example response
{
"items": [
{
"supi": "imsi-231510000114763",
"pdu": [
{
"psi": 1,
"dnn": "internet",
"ipv4": "10.45.0.11",
"snssai": {
"sst": 1,
"sd": "ffffff"
},
"qos_flows": [
{
"qfi": 1,
"5qi": 9
}
],
"pdu_state": "inactive"
}
],
"ue_activity": "idle"
}
],
"pager": {
"page": 0,
"page_size": 100,
"count": 1,
}
}
### Get all 5G NR connected UEs (from AMF)
contains the UE_ID as SUPI, SUCI, PEI, GUTI, TMSI, GNB_ID to which the UE is connected, AMBR, slices ..
curl -s "http://127.0.0.5:9090/ue-info" |jq .
Example response
{
"items": [
{
"supi": "imsi-001010000056492",
"suci": "suci-0-001-01-0000-1-1-85731c4241d466407311a85135e914987944f361550f13f4532e29bdc5859548a363cc1a81798bb4cc59f2b4db",
"pei": "imeisv-3535938300494715",
"cm_state": "connected",
"guti": "00101-030080-CC00007AB",
"m_tmsi": 3221227435,
"gnb": {
"ostream_id": 1,
"amf_ue_ngap_id": 2,
"ran_ue_ngap_id": 39,
"gnb_id": 100,
"cell_id": 1
},
"location": {
"timestamp": 1758733375895512,
"nr_tai": {
"plmn": "99970",
"tac_hex": "000001",
"tac": 1
},
"nr_cgi": {
"plmn": "99970",
"nci": 1638401,
"gnb_id": 100,
"cell_id": 1
},
"last_visited_plmn_id": "000000"
},
"msisdn": [],
"security": {
"valid": 1,
"enc": "nea2",
"int": "nia2"
},
"ambr": {
"downlink": 1000000000,
"uplink": 1000000000
},
"pdu_sessions": [],
"pdu_sessions_count": 0,
"requested_slices": [
{
"sst": 1,
"sd": "ffffff"
}
],
"allowed_slices": [
{
"sst": 1,
"sd": "ffffff"
}
],
"requested_slices_count": 1,
"allowed_slices_count": 1,
"am_policy_features": 4,
"am_policy_features_info": {
"hex": "0x0000000000000004",
"bits": [
2
],
"labels": [
"QoS Policy Control"
]
}
}
],
"pager": {
"page": 0,
"page_size": 100,
"count": 2
}
}
### Get all LTE connected UEs ( from MME )
contains the ENB_ID to which the UE is connected
curl -s "http://127.0.0.2:9090/ue-info?" |jq .
Example response
{
"items": [
{
"supi": "999700000021632",
"domain": "EPS",
"rat": "E-UTRA",
"cm_state": "connected",
"enb": {
"ostream_id": 3,
"mme_ue_ngap_id": 3,
"ran_ue_ngap_id": 9,
"enb_id": 264040,
"cell_id": 67594275
},
"location": {
"tai": {
"plmn": "99970",
"tac_hex": "0001",
"tac": 1
}
},
"ambr": {
"downlink": 1000000000,
"uplink": 1000000000
},
"pdn": [
{
"apn": "internet",
"qos_flows": [
{
"ebi": 5
}
],
"qci": 9,
"ebi": 5,
"bearer_count": 1,
"pdu_state": "active"
}
],
"pdn_count": 1
}
],
"pager": {
"page": 0,
"page_size": 100,
"count": 1
}
}
### Get all connected gNBs (from AMF)
contains gNB info and number of RRC connected UEs
curl -s "http://127.0.0.5:9090/gnb-info?" |jq .
Example response
{
"items": [
{
"gnb_id": 100,
"plmn": "99970",
"network": {
"amf_name": "efire-amf0",
"ngap_port": 38412
},
"ng": {
"sctp": {
"peer": "[192.168.168.100]:60110",
"max_out_streams": 2,
"next_ostream_id": 1
},
"setup_success": true
},
"supported_ta_list": [
{
"tac": "000001",
"bplmns": [
{
"plmn": "99970",
"snssai": [
{
"sst": 1,
"sd": "ffffff"
}
]
},
{
"plmn": "99971",
"snssai": [
{
"sst": 2,
"sd": "000000"
}
]
}
]
}
],
"num_connected_ues": 2
}
],
"pager": {
"page": 0,
"page_size": 100,
"count": 1
}
}
### Get all connected eNBs (from MME)
contains eNB info and number of connected UEs
curl -s "http://127.0.0.2:9090/enb-info?" |jq .
Example response
{
"items": [
{
"enb_id": 264040,
"plmn": "99970",
"network": {
"mme_name": "efire-mme0"
},
"s1": {
"sctp": {
"peer": "[192.168.168.254]:36412",
"max_out_streams": 10,
"next_ostream_id": 3
},
"setup_success": true
},
"supported_ta_list": [
{
"tac": "0001",
"plmn": "99970"
}
],
"num_connected_ues": 1
}
],
"pager": {
"page": 0,
"page_size": 100,
"count": 1
}
}
Using a suitable filter in jq, the output can be simplified and adapted to the desired form.
AMF/ue-info sorted on supi ( page=-1 to avoid paging and show all UEs )
./amf_ue_sort.sh
supi cm-state gnb_id dnn
imsi-001010000056492 connected 100 internet
imsi-231510000114763 connected 100 internet
imsi-999700000021630 connected 100 internet
imsi-999700000083810 idle 100 internet
imsi-999700000114762 idle 100 internet
curl -s "http://127.0.0.5:9090/ue-info?page=-1" \
| jq -r '
# Unwrap common list keys or accept a bare array/object
( .ue_infos // .items // .data // .results // .list // . )
| (if type=="array" then . else [.] end)
| sort_by(.supi // "")| group_by(.supi)| map({supi: (.[0].supi // "-"),
cm: (if any(.[]; .cm_state == "connected") then "connected"
else (.[-1].cm_state // "-") end),
gnb_id: (
( [ .[] | select(.cm_state=="connected")
| (.gnb.gnb_id? // .location.nr_cgi.gnb_id?) ]
| map(select(.!=null)) | .[0] )
// ( [ .[] | (.gnb.gnb_id? // .location.nr_cgi.gnb_id?) ]
| map(select(.!=null)) | .[0] )
// "-"
),
dnns: (
[ .[].pdu_sessions[]?.dnn ]
| map(select(. != null and . != ""))
| unique | sort
| if length==0 then ["-"] else . end
)
})
| sort_by( ( .supi | tostring | sub("^imsi-"; "") | tonumber? ) // 0 )
AMF/gnb-info
./amf_gnb_sort.sh
gnb_id peer plmn num_connected_ues
100 [192.168.168.100]:60110 99970 1
411 [192.168.168.99]:34349 99970 0
curl -s "http://127.0.0.5:9090/gnb-info" \
| jq -r '
( .items // .gnbs // .data // .results // .list // . )
| (if type=="array" then . else [.] end)
| sort_by(.gnb_id // 0)
| (["gnb_id","peer","plmn","num_connected_ues"]),
( .[] |
[ (.gnb_id // "-"),
(.ng?.sctp?.peer // "-"),
(.plmn // "-"),
((.num_connected_ues // 0) | tostring)
])
| @tsv
' | column -s $'\t' -t
MME/enb-info
./mme_enb_sort.sh
enb_id peer plmn num_connected_ues
264040 [192.168.168.254]:36412 99970 1
curl -s "http://127.0.0.2:9090/enb-info" \
| jq -r '
( .items // .enbs // .data // .results // .list // . )
| (if type=="array" then . else [.] end)
| sort_by(.enb_id // 0)
| (["enb_id","peer","plmn","num_connected_ues"]),
( .[] |
[ (.enb_id // "-"),
(.s1?.sctp?.peer // "-"),
(.plmn // "-"),
((.num_connected_ues // 0) | tostring)
])
| @tsv
' | column -s $'\t' -t
MME/ue-info
./mme_ue_sort.sh
supi cm-state enb_id apn
001010000056492 connected 264040 internet
999700000021632 connected 264040 internet
999700000083811 connected 264040 internet
curl -s "http://127.0.0.2:9090/ue-info?page=-1" \
| jq -r '
( .items // .ue_infos // .data // .results // .list // . )
| (if type=="array" then . else [.] end)
| map(select(((.rat? // "") | test("^(E-?UTRA|LTE)$"; "i")) or((.domain? // "") | test("^EPS$"; "i"))))
| sort_by(.supi // "")| group_by(.supi)| map({supi: (.[0].supi // "-"),cm: (if any(.[]; .cm_state == "connected") then "connected"else (.[-1].cm_state // "-") end),enb_id: (( [ .[] | select(.cm_state=="connected") | .enb.enb_id? ]| map(select(.!=null)) | .[0] )// ( [ .[] | .enb.enb_id? ] | map(select(.!=null)) | .[0] )// "-"),apns: ([ .[].pdn[]?.apn ]| map(select(. != null and . != ""))| unique | sort| if length==0 then ["-"] else . end)})
| sort_by( ( .supi | tostring | sub("^imsi-"; "") | tonumber? ) // 0 )
SMF/pdu-info
./smf_pdu_sort.sh
supi ue_activity dnn ipv4/ipv6 pdu_state
imsi-001010000056492 active internet 10.45.0.59 active
imsi-231510000114763 idle internet 10.45.0.52 inactive
imsi-999700000021630 idle internet 10.45.250.250 inactive
999700000021632 unknown internet 10.45.0.8 unknown
imsi-999700000083810 idle internet 10.45.0.12 inactive
imsi-999700000114762 idle internet 10.45.0.10 inactive
curl -s "http://127.0.0.4:9090/pdu-info?page=-1" \
| jq -r '
( .items // .ue_infos // .data // .results // .list // . )
| (if type=="array" then . else [.] end) as $arr
| ($arr | map((.pdu // []) | length) | max // 0) as $maxp
| ( ["supi","ue_activity"]+ ([ range(0; $maxp) | "dnn","ipv4/ipv6","pdu_state" ]) ),
# Rows
( $arr
| sort_by( ( .supi | tostring | sub("^imsi-"; "") | tonumber? ) // 0 )
| .[]
| . as $ue
| ( $ue.pdu // [] | sort_by(.psi // .ebi // 0) ) as $pdus
| [ ($ue.supi // "-"), ($ue.ue_activity // "-") ]
+ (
$pdus
| map([
(.dnn // .apn // "-"),
( ([.ipv4?, .ipv6?] | map(select(.!=null and .!="")) | join("/") )
| if .=="" then "-" else . end ),
(.pdu_state // "-")
])
| add // []
)
+ ( [ range( ( ($pdus|length) * 3 ); ($maxp * 3) ) | "-" ] )
)