edgecomllc / eupf

5G User Plane Function (UPF) based on eBPF
Apache License 2.0
106 stars 20 forks source link

Research end-2-end PDU session tracing dashboard #59

Closed marknefedov closed 1 year ago

marknefedov commented 1 year ago
marknefedov commented 1 year ago

Image

marknefedov commented 1 year ago

We can implement PDU tracing as a Node graph panel in Grafana, as on image:

Screenshot 2023-03-23 141154

In order to achieve end to end PDU observability we need to obtain PDU session status from the RAN, AMF, SMF and UPF. We probably can implement an adapter API. That will poll metrics or API of the current 5G core to convert the data to the node graph API format.

This plugin (Node Graph API plugin for Grafana | Grafana Labs) with some middleware can help us to convert API to graph.

I’m still researching how to use (is it even possible or needed) Grafana’s Node Graphs with Prometheus.

API mock ```python3 from flask import Flask, request, jsonify app = Flask(__name__) @app.route('/api/graph/fields') def fetch_graph_fields(): nodes_fields = [ {"field_name": "id", "type": "string"}, {"field_name": "title", "type": "string"}, {"field_name": "mainStat", "type": "string"}, {"field_name": "arc__on", "type": "number", "color": "green",}, {"field_name": "arc__off", "type": "number", "color": "red",}, ] edges_fields = [ {"field_name": "id", "type": "string"}, {"field_name": "source", "type": "string"}, {"field_name": "target", "type": "string"}, {"field_name": "mainStat", "type": "string"}, ] result = {"nodes_fields": nodes_fields, "edges_fields": edges_fields} return jsonify(result) @app.route('/api/graph/data') def fetch_graph_data(): session_id = request.args.get('session_id') nodes = [{"id": "1", "title": "User equipment", "mainStat": "True", "arc__on": 1, "arc__off": 0}, {"id": "2", "title": "Radio access network", "mainStat": "True", "arc__on": 1, "arc__off": 0}, {"id": "3", "title": "Access and mobility management function", "mainStat": "True", "arc__on": 1, "arc__off": 0}, {"id": "4", "title": "Session management function", "mainStat": "False", "arc__on": 1, "arc__off": 0}, {"id": "5", "title": "User plane function", "mainStat": "False", "arc__on": 0, "arc__off": 1}, ] edges = [{"id": "1", "source": "1", "target": "2", "mainStat": "Connected"}, {"id": "2", "source": "2", "target": "3", "mainStat": "Connected"}, {"id": "2", "source": "3", "target": "4", "mainStat": "Connected"}, {"id": "3", "source": "4", "target": "5", "mainStat": "Disconnected"} ] result = {"nodes": nodes, "edges": edges} return jsonify(result) @app.route('/api/health') def check_health(): return "API is working well!" app.run(host='0.0.0.0', port=5000) ```
Graphana dashboard model ```json { "annotations": { "list": [ { "builtIn": 1, "datasource": { "type": "grafana", "uid": "-- Grafana --" }, "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", "name": "Annotations & Alerts", "target": { "limit": 100, "matchAny": false, "tags": [], "type": "dashboard" }, "type": "dashboard" } ] }, "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, "id": 1, "links": [], "liveNow": false, "panels": [ { "datasource": { "type": "hamedkarbasi93-nodegraphapi-datasource", "uid": "G-ihEDBVk" }, "gridPos": { "h": 18, "w": 24, "x": 0, "y": 0 }, "id": 2, "options": { "edges": { "mainStatUnit": "string" }, "nodes": { "arcs": [], "mainStatUnit": "string" } }, "targets": [ { "datasource": { "type": "hamedkarbasi93-nodegraphapi-datasource", "uid": "G-ihEDBVk" }, "queryText": "session_id=some_id", "refId": "A" } ], "title": "Panel Title", "type": "nodeGraph" } ], "refresh": "", "revision": 1, "schemaVersion": 38, "style": "dark", "tags": [], "templating": { "list": [] }, "time": { "from": "now-6h", "to": "now" }, "timepicker": {}, "timezone": "", "title": "New dashboard", "uid": "yVdu_vfVk", "version": 1, "weekStart": "" } ```
marknefedov commented 1 year ago

Find session in each component by IMSI/IP/etc.

PapaySail commented 1 year ago

ℹ️ API requests to Free5gc components:

to the AMF:

registered full list: curl 10.233.78.163/namf-oam/v1/registered-ue-context

```json [ { "AccessType": "3GPP_ACCESS", "CmState": "CONNECTED", "Guti": "20893cafe0000000001", "Mcc": "208", "Mnc": "93", "PduSessions": [ { "Dnn": "internet", "PduSessionId": "1", "Sd": "010203", "SmContextRef": "urn:uuid:bd32aba5-4bdd-403a-9a72-012f42276c7d", "Sst": "1" } ], "Supi": "imsi-208930000000003", "Tac": "000001" }, { "AccessType": "3GPP_ACCESS", "CmState": "CONNECTED", "Guti": "20893cafe0000000002", "Mcc": "208", "Mnc": "93", "PduSessions": [ { "Dnn": "internet", "PduSessionId": "1", "Sd": "010203", "SmContextRef": "urn:uuid:73e2c0fb-1804-4a4d-9885-3066ffca9c9f", "Sst": "1" } ], "Supi": "imsi-208930000000004", "Tac": "000001" } ] ```

Individual by imsi: curl 10.233.78.163/namf-oam/v1/registered-ue-context/imsi-208930000000004

```json [ { "AccessType": "3GPP_ACCESS", "CmState": "CONNECTED", "Guti": "20893cafe0000000002", "Mcc": "208", "Mnc": "93", "PduSessions": [ { "Dnn": "internet", "PduSessionId": "1", "Sd": "010203", "SmContextRef": "urn:uuid:73e2c0fb-1804-4a4d-9885-3066ffca9c9f", "Sst": "1" } ], "Supi": "imsi-208930000000004", "Tac": "000001" } ] ```

to the SMF

Individual by SmContextRef: curl 10.233.78.177/nsmf-oam/v1/ue-pdu-session-info/urn:uuid:73e2c0fb-1804-4a4d-9885-3066ffca9c9f

```json { "AnType": "3GPP_ACCESS", "Dnn": "internet", "PDUAddress": "10.1.0.11", "PDUSessionID": "1", "Sd": "010203", "SessionRule": { "sessRuleId": "" }, "Sst": "1", "Supi": "imsi-208930000000004", "Tunnel": { "ANInformation": { "IPAddress": "", "TEID": 0 }, "DataPathPool": null, "PathIDGenerator": null }, "UpCnxState": "ACTIVATED" } ```

marknefedov commented 1 year ago

Thanks!

PapaySail commented 1 year ago

ℹ There is ConfigMap free5gc/connectivity-test-configmap containing just script:

script-connectivity-test.sh

```ash Name: connectivity-test-configmap Namespace: free5gc Labels: Annotations: helm.sh/hook: test Data ==== script-connectivity-test.sh: ---- #!/bin/bash echo "Get ue pod name" export pod_name=$(kubectl get pods --namespace free5gc -l "component=ue" -o jsonpath="{.items[0[].metadata.name}") echo "${pod_name}" echo "***********************************************************************" echo "" echo "Get ip address table for ${pod_name}" ip_address="$(kubectl -n free5gc exec -i ${pod_name} -- bash -c 'ip address')" echo "${ip_address}" tun_interface="$(echo "$ip_address" | awk '$1 ~ /^[0-9[].*/ && $2 ~/^uesimtun0/ {print}')" if [ -z "$tun_interface" ] ; then echo "" echo "uesimtun0 interface not found" exit 1 fi echo "***********************************************************************" echo "" echo "Test connectivity" ping_output="$(kubectl -n free5gc exec -i ${pod_name} -- bash -c 'ping -c 10 -I uesimtun0 www.google.com')" echo "${ping_output}" echo "***********************************************************************" echo "" ping_statistics="$(echo "$ping_output" |tail -n -2 |awk -F', ' 'NR==1 {print}')" loss_rate="$(echo "$ping_statistics" |awk -F', ' '{for(i=1; i<=NF; i++){if(match($i, /packet loss$/))print $i}}')" echo "Packet loss-rate is $loss_rate" if [ "$loss_rate" != "100% packet loss" ] ; then echo "Connection test passed - ${loss_rate}" exit 0 else echo "Connection test failed - ${loss_rate}" exit 1 fi BinaryData ==== Events: ```

We can use some approaches from it, IMHO.