E2E Slice 정보가 필요한 이유
5G 네트워크에서 Network Slice는 단순한 논리적 분리가 아니라, 서로 다른 QoS 요구사항을 갖는 서비스 단위다.
eMBB, URLLC, mMTC와 같이 요구사항이 다른 트래픽을 하나의 RAN/CN 인프라 위에서 동시에 처리하기 위해서는,
각 Slice의 상태를 정확하게 관찰하고 제어할 수 있어야 한다.
그러나 일반적인 Open RAN + 5GC 구성에서 Slice 관련 정보는 다음처럼 여러 계층에 분산되어 있다:
- RAN: PRB 사용량, UE throughput, latency (KPM 기준)
- CN: UPF bandwidth, queue 상태 (tc 기반)
- UE: RTT, 실제 체감 성능
문제는 이 데이터들이 통합되지 않는다는 점이다.
예를 들어:
- RAN에서는 PRB를 많이 쓰고 있지만
- CN에서는 bandwidth가 제한되어 있고
- 실제 UE에서는 latency가 증가하는 상황
이걸 한 번에 “Slice 단위로” 볼 수 있는 지점이 없다.
AI Agent 기반 Slice 제어를 하려면 필요한 데이터
AI Agent가 Slice별 정책을 결정하려면 단순 metric이 아니라 “의미 있는 상태 데이터”가 필요하다.
예를 들어:
- throughput (DL/UL)
- latency (RLC delay or RTT)
- PRB usage vs allocated ratio
- UPF bandwidth 상태
- packet loss
이 데이터는 다음 조건을 만족해야 한다:
- Slice 단위로 분리되어야 한다 (S-NSSAI 기준으로 분리)
- 시간 축을 포함해야 한다 (trend 분석이 가능하도록)
- RAN + CN + UE를 모두 포함해야 한다
이걸 만족하지 못하면 AI는 다음과 같은 한계에 부딪힐 수 있다.
- PRB를 늘렸는데 효과가 없는 이유를 모름
- CN 병목을 RAN 문제로 오판
- Slice 간 resource imbalance를 감지 못함
이 문제를 해결하기 위해 전체 구조를 다음과 같이 잡았다:
[ UE ]
↓ (traffic, latency)
[ gNB (RAN) ]
↓ (E2 interface)
[ Near-RT RIC ]
↓
[ xApp (KPM + RC) ] ← 핵심
↓
[ SQLite DB ] ← Slice 상태 저장
↓
[ AI Agent / MCP ]
↓
[ RAN (PRB control) + CN (tc control) ]
- FlexRIC 기반 Near-RT RIC에서 xApp이 KPM을 수집한다.
- 그리고 이 데이터를 로컬 DB(SQLite)에 저장한다. (SQLite인 이유는 추후 Core의 Promtheus와 연동하기 위함)
이 xApp은 RRU.PrbTotDl/UL, DRB.UEThpDl/UL, DRB.RlcSduDelayDl, PDCP volume 등을 수집할 수 있다.
이때 단순 수집이 아닌 S-NSSAI 기준으로 Slice filtering을 수행해야 한다.
이를 위해 실제 구현에서는 KPM subscription 시 S-NSSAI 조건을 넣고 callback에서 slice별로 분리 저장한다.
이후 제어를 수행하는 xApp은 다음을 수정할 수 있도록 할 것.
- RC STYLE 2 / ACTION 6
- Slice-level PRB quota 제어
- min_prb / max_prb / dedicated_prb 동적 변경
DB 설계 구조
xApp은 다음 역할을 수행한다: KPM metric 수집 / 파싱 및 정규화 / Slice 단위로 변환 / SQLite 저장
DB schema 예시는 다음과 같다.
- timestamp
- slice_id
- throughput_bps
- latency_ms
- prb_usage_percent
- prb_ratio_allocated
- upf_bandwidth_mbps
- packet_loss_percent
추후, 이 DB는 단순 로그를 넘어서 AI Agent가 직접 조회하는 상태 저장소 역할을 수행하게 된다.
Slice 메트릭 수집 xApp 설계 및 구현
KPM 기반 Slice 필터링 (S-NSSAI 기준)
KPM은 기본적으로 UE 단위 metric을 제공하며, “Slice metric”이라는 개념은 직접 제공되지 않는다.
따라서 핵심은 UE metric을 Slice 기준으로 재구성하는 과정이 필요하다.
여기서 사용하는 기준이 S-NSSAI인데, 구조는 다음과 같다:
- 각 Slice는 (SST, SD)로 정의됨
- KPM subscription 시 matching condition으로 S-NSSAI를 지정
- 해당 Slice에 속한 UE만 보고됨
- Slice1 → SST=1, SD=000001
- Slice2 → SST=2, SD=000002
- Slice3 → SST=3, SD=000003
이렇게 subscription을 3개로 나누면, 각 callback이 이미 Slice 단위로 분리된 데이터를 받게 된다.
FlexRIC xApp 구조 설명
xApp 구조는 크게 Monitoring path (KPM)와 Control path (RC) 두 가지 흐름으로 나뉜다:
1) Monitoring path
- KPM subscription 생성
- periodic report 수신
- callback 실행
2) Control path
- UE 식별
- Slice profile 매핑
- RC CONTROL 메시지 생성
- PRB 정책 적용
이때 Monitoring Path는 다음과 같은 순서로 동작하게 된다.
1) 초기화 : SQLite DB 초기화 및 RIC 연결
2) KPM 수집 : Slice별 subscription 생성 후 callback에서 metric 추출, DB 저장
KPM subscription (slice별)
이 과정에서 각 Slice마다 별도의 subscription을 생성한다.
구조:
- report style 4 사용
- matching condition: S-NSSAI
- report period: 100ms
핵심 포인트는:
→ subscription 자체가 Slice-aware하게 설계됨
즉, callback은 이미:
[KPM][slice-sst1]
[KPM][slice-sst2]
[KPM][slice-sst3]
형태로 구분되어 들어온다.
SQLite 기반 Metric 저장 구조
SQLite 기반 메트릭 저장 구조는 이 xApp 설계에서 핵심적인 역할을 한다.
단순히 KPM 메트릭을 실시간으로 관찰하는 것이 아니라,
모든 Slice 상태를 DB에 축적하여 이후 분석과 제어에 활용할 수 있도록 구성했다.
SQLite를 선택한 이유는 xApp과 동일 VM에서 로컬로 실행되기 때문에 지연이 거의 없고, 별도의 인프라 없이도 안정적인 저장이 가능하기 때문이다. 또한 WAL 모드를 적용해 read/write 동시성을 확보했다.
slice_metrics 테이블은 timestamp와 slice_id를 기준으로 하는 time-series 구조로 설계되었으며, throughput, latency, PRB 사용률 및 할당 비율, UPF bandwidth, packet loss 등의 필드를 포함한다.
특히 KPM raw 데이터를, throughput은 kbps→bps, latency는 μs→ms로 변환하며, PRB usage와 allocation ratio를 각각 계산하여 실제 사용량과 할당량을 비교할 수 있도록 하여 이를 통해 Slice별 과소/과다 할당 상태를 판단할 수 있다.
실행 흐름과 실제 동작 (E2E)
전체 실행 흐름
전체 시스템은 다음 순서로 올라간다:
- Near-RT RIC 실행
- gNB 실행
- UE attach
- 트래픽 생성 (iperf)
- xApp 실행
- KPM 수집 → DB 저장 → RC 제어
1) Near-RT RIC 실행
먼저 RIC을 실행하면 다음과 같은 로그가 나온다:
cd ~/openairinterface5g/openair2/E2AP
./flexric/build/examples/ric/nearRT-RIC

핵심 로그:
[NEAR-RIC]: Loading SM ID = 3 with def = ORAN-E2SM-RC
[NEAR-RIC]: Loading SM ID = 2 with def = ORAN-E2SM-KPM
이 의미는 KPM → monitoring 가능 + RC → control 가능이라는 뜻이다.
이 시점에서 xApp이 사용할 수 있는 인터페이스가 준비된다
2) gNB / UE attach
다음으로 gNB와 UE를 실행한다.
cd ~/openairinterface5g/cmake_targets/ran_build/build
sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --gNBs.[0].min_rxtxtime 6 --rfsim
cd ~/openairinterface5g/tools/scripts
sudo ./multi-ue.sh -c1
sudo ./multi-ue.sh -o1
sudo ip netns exec ue1 /home/user/openairinterface5g/cmake_targets/ran_build/build/nr-uesoftmodem \
-O /home/user/openairinterface5g/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue1.conf \
-r 106 \
--numerology 1 \
--band 78 \
-C 3619200000 \
--rfsim \
--uicc0.imsi 208930000000001 \
--rfsimulator.serveraddr 10.201.1.100 \
--telnetsrv \
--telnetsrv.listenport 9095
gNB 실행 후 UE가 attach되면 RRC 연결 완료 / NAS registration 완료 / data plane 활성화 로그가 뜬다.

3) xApp 실행 및 초기화
이제 xApp을 동작시킨다.
cd ~/openairinterface5g/openair2/E2AP/flexric
XAPP_DURATION=60 ./build/examples/xApp/c/kpm_rc/xapp_kpm_rc_prb
xApp 실행 시 가장 먼저 하는 작업은 다음과 같다.
(1) PRB 정책 로드
load_prb_from_env(&g_profile_sst1, "SLICE1");
(2) SQLite 초기화
sqlite_init_db();
[SQLITE] Database opened: /tmp/slice_metrics.db
이 시점에서 모든 metric이 저장될 준비가 완료된 상태가 된다.
4) KPM Subscription (Slice별)
xApp은 각 Slice에 대해 subscription을 생성한다:
report_sm_xapp_api(..., sm_cb_kpm_sst1);
report_sm_xapp_api(..., sm_cb_kpm_sst2);
report_sm_xapp_api(..., sm_cb_kpm_sst3);
[RIC-XAPP][KPM] subscribe slice1 snssai=(1,...)
[RIC-XAPP][KPM] subscribe slice2 snssai=(2,...)
[RIC-XAPP][KPM] subscribe slice3 snssai=(3,...)
이 시점부터 Slice별 metric stream이 분리되어 들어온다

5) KPM 수집 → 파싱 → DB 저장
실제 핵심 동작은 callback에서 발생한다:
handle_kpm_with_profile(...)
(1) 로그 출력
[KPM][slice-sst1] latency = 12345 [us]
RRU.PrbTotDl = 80
DRB.UEThpDl = 12000 kbps
(2) metric 추출
extract_kpm_metrics(...)
(3) DB 저장
sqlite_insert_metrics(...)
결과적으로 DB에는 다음과 같은 row가 쌓인다:
| timestamp | slice_id | throughput_bps | latency_ms | prb_usage_percentage |
| ... | slice_1 | 12000000 | 12.3 | 75.4 |
이 흐름이 100ms 주기로 반복된다.
6) Slice 트래픽 생성 및 DB 확인
xApp이 정상적으로 실행된 상태에서 실제 Slice metric이 DB에 저장되는지 확인하기 위해 UE에서 트래픽을 발생시킨다.
먼저 Free5GC VM의 UPF 컨테이너 안에서 iperf3 서버를 실행한다.
docker exec -it upf iperf3 -s -p 5201
이후 xApp이 KPM subscription과 SQLite 초기화를 마친 뒤, UE namespace에서 UPF 방향으로 트래픽을 흘려준다. 예를 들어 Slice 1에 해당하는 ue1에서 40초 동안 5 Mbps 트래픽을 발생시키면 다음과 같다.
sudo ip netns exec ue1 iperf3 -c 10.100.200.11 -p 5201 -t 40 -b 5M

이때 xApp은 KPM callback을 통해 DRB.UEThpDl, RRU.PrbTotDl, DRB.RlcSduDelayDl 등의 값을 주기적으로 수집하고, 이를 slice_metrics 테이블에 저장한다. xApp이 종료된 뒤에는 SQLite DB를 조회하여 실제 metric이 저장되었는지 확인할 수 있다.
sqlite3 -header -column /tmp/slice_metrics.db \
"SELECT timestamp, throughput_bps, prb_usage_percent, prb_ratio_allocated, latency_ms \
FROM slice_metrics \
WHERE slice_id='slice_1' AND throughput_bps > 0 \
ORDER BY id;"

이 조회 결과를 통해 Slice 1에 대해 트래픽이 흐른 구간의 throughput, PRB 사용률, PRB 할당 비율, latency가 시간 순서대로 저장되었는지 확인할 수 있다. 즉, iperf3로 실제 트래픽을 만들고, xApp이 이를 KPM metric으로 수집한 뒤, SQLite에 Slice 단위 time-series 데이터로 남기는 E2E 모니터링 흐름이 검증된다.
위 로그가 3초간 수집된 DB의 양이다.
추후 이 부분을 적절하게 Aggregate해서 AI Agent로 전달하는 부분을 구현해야 할 듯.
추가로 prb_usage_percentage도 100이 넘는 값이 찍히는 경우가 있다. (정확하게 어떻게 수집되는지 확인 필요)
이때 DB의 latency_ms는 ping이 아니라 DRB.RlcSduDelayDl에서 온다.
// xapp_kpm_rc_prb.c의 sqlite_insert_metrics()
sqlite3_bind_double(stmt, 4, metrics->rlc_sdu_delay_dl / 1000.0);
// DRB.RlcSduDelayDl (μs) → ms 변환
즉 xApp의 latency_ms는 RLC delay로 채워지고 있고, 이건 DL 트래픽이 없으면 0이 나오는 이유이기도 하다.
이 부분은 추후 ping 기반 ICMP RTT를 통해 UE→UPF 간 정확한 latency를 구현해야 할 듯.
'RAN CN 테스트베드 구축 > OAI+Free5GC (RAN-Core)' 카테고리의 다른 글
| OAI RAN을 Kubernetes 기반 Free5GC Cluster에 연결하기 (0) | 2026.05.28 |
|---|---|
| FlexRIC xApp에서 KPM Monitoring과 RAN Control을 동시에 구현하기 (0) | 2026.05.03 |
| 5G Network Slicing QoS 실험을 위한 Multi-UE 환경 구축 (0) | 2026.04.30 |
| 실제 UE 5G Traffic Dataset 기반으로 바라본 Network Slicing (0) | 2026.04.29 |
| VMware 환경에서 OAI gNB ↔ free5GC 연동하기 (NG Setup) (0) | 2026.04.28 |