From 7451d33e3018602756d8e075ebfc5843d8ee493a Mon Sep 17 00:00:00 2001 From: Ajay Lotan Thakur Date: Thu, 29 Sep 2022 23:54:38 -0600 Subject: [PATCH 1/5] Update gnbsim document --- PendingFeatures.md | 43 ---------------- README.md | 119 ++++++++++++++++++++++++++++++--------------- 2 files changed, 81 insertions(+), 81 deletions(-) delete mode 100644 PendingFeatures.md diff --git a/PendingFeatures.md b/PendingFeatures.md deleted file mode 100644 index f4dd22da..00000000 --- a/PendingFeatures.md +++ /dev/null @@ -1,43 +0,0 @@ - - -# Pending Feature List - -## Common features for gNodeB Simulator - - 1. Adding support for custom profile - 2. Controlling Profiles - Adding support for aborting profile - 3. Controlling Profiles - Clean profiles - 4. Controlling Profiles - Pause Profile - 5. Adding support for configurable rate of events - - ## Data Testing Features - 1. Triggering downlink data from gNB Sim (CI/CD feature as well) - 2. Provision data interface to gNBSim POD for data traffic testing - - ## CI/cd features - - 1. Adding configurable delay between profile execution - 2. Advanced logging - Logic to calculate latency per transaction/ operation - 3. Profile execution through http APIs (partially supported) - 4. Reporting profile errors from all levels - 4. HTTP APIs to fetch subscriber/profile status from gNBSim - -## Negative Testing features - - 1. Dropping incoming messages based on configuration - 2. Sending negative responses to request/command type messages based on configuration - 3. Handling security mode failure message - - ## 3gpp features for gNodeB Simulator - - 1. GUTI based registration - 2. Adding support for Resynchronization Profile - 3. Adding Support for N2 handover profile - 4. Adding Support for Xn Handover profile - 5. Adding support for handling end marker packet - 6. Generating GTPU echo request and handling incoming GTPU Request diff --git a/README.md b/README.md index 9311df7f..40377dde 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,29 @@ +# Introduction + This repository is part of the SD-Core project. It provides a tool to simulate gNodeB and UE by generating NAS and NGAP messages for the configured UEs and -call flows. The tool currently supports simulation profiles for the following -procedures: +call flows. + +## gNodeB Simulator Block Diagram + +![gNBSim](/docs/images/gnbsim_flow_diagram.png) + +## Reach out to us + +1. Please refer to the official [SD-Core documentation](https://docs.sd-core.opennetworking.org/master/developer/gnbsim.html#gnb-simulator) for more details. +2. #sdcore-dev channel in [ONF Community Slack](https://onf-community.slack.com/) +3. Raise Github issues + +## Supported 3gpp procedures - 1. Registration + 1. UE Registration 2. UE Initiated PDU Session Establishment 3. UE Initiated De-registration 4. AN Release @@ -21,36 +32,38 @@ procedures: 7. UE Requested PDU Session Release 8. N/W triggered UE Deregistration -It is also capable to generate and send user data packets (ICMP echo request) -and process downlink user data (ICMP echo response) over the established data -plane path (N3 Tunnel). +## Supported System level features -System level features + 1. Gnbsim can generate and send user data packets (ICMP echo request) + and process downlink user data (ICMP echo response) over the established data + plane path (N3 Tunnel). + 2. Executing all enabled profiles in parallel or in sequential order. + 3. Timeout for each call flow within profile + 4. Logging summary result + 5. HTTP API to execute profile + 6. Configure number of data packets to be sent + 7. Configure AS (Application Server) address. This is used to send data packets + 8. Run gNBSim with single Interface or multi interface + 9. Support of Custom Profiles + 10. Delay between Procedures + 11. Timeout for every profile - 1. Executing all enabled profiles in parallel or in sequential order. - 2. Timeout for each call flow within profile - 3. Logging summary result - 4. HTTP API to execute profile - 5. Configure number of data packets to be sent - 6. Configure AS (Application Server) address. This is used to send data packets - 7. Run gNBSim with single Interface or multi interface -Please refer to the official [SD-Core documentation](https://docs.sd-core.opennetworking.org/master/developer/gnbsim.html#gnb-simulator) for more details. -## Reach out to us thorugh - -1. #sdcore-dev channel in [ONF Community Slack](https://onf-community.slack.com/) -2. Raise Github issues - - -## gNodeB Simulator Block Diagram - -![gNBSim](/docs/images/gnbsim_flow_diagram.png) +# Using gNBSim +## Step 1: Build gNBSim + 1. Build gNBSim -## Step 1: Configure gNBSim + $ go build + + 2. Build a docker image for gNBSim + + $ make docker-build + +## Step 2: Configure gNBSim 1. The config file for gNBSim can be found at /config/gnbsim.yaml @@ -84,17 +97,6 @@ Please refer to the official [SD-Core documentation](https://docs.sd-core.openne Registration + UE initiated PDU Session Establishment + User Data packets + AN Release + UE Initiated Service Request - -## Step 2: Build gNBSim - 1. Build gNBSim - - $ go build - - 2. Build a docker image for gNBSim - - $ make docker-build - - ## Step 3: Run gNBSim If you want to run gNBSim as a standalone tool then deploy gNBSim using helm charts. If you want to run gNBSim along with @@ -123,3 +125,44 @@ All these steps are explained in detail on [AIAB documentation](https://docs.sd- below curl command will launch a profile in gNBSim $ curl -i -X POST 127.0.0.1:6000/gnbsim/v1/executeProfile -H 'Content-Type: application/json' -d '{"profileType":"nwreqpdusessrelease","profileName":"profile8","enable":true,"gnbName":"gnb1","startImsi":"208930100007497","ueCount":1,"opc":"981d464c7c52eb6e5036234984ad0bcf","key":"5122250214c33e723a5dd523fc145fc0","sequenceNumber":"16f3b3f70fc2","defaultAs":"192.168.250.1","plmnId":{"mcc":"208","mnc":"93"}}' + +# Pending Feature List + + 1. Common features for gNodeB Simulator + + - Controlling Profiles - Adding support for aborting profile + - Controlling Profiles - Suspend/Pause profiles + - Controlling Profiles - Resume Profile + - Adding support for configurable rate of events + + 2. Data Testing Features + + - Triggering downlink data from gNB Sim (CI/CD feature as well) + - Provision data interface to gNBSim POD for data traffic testing + + 3. CI/CD features + + - Advanced logging - Logic to calculate latency per transaction/ operation + - Reporting profile errors from all levels + - HTTP APIs to fetch subscriber/profile status from gNBSim + + 4. Negative Testing features + + - Dropping incoming messages based on configuration + - Sending negative responses to request/command type messages based on configuration + - Handling security mode failure message + + 5. 3gpp features for gNodeB Simulator + + - GUTI based registration + - Adding support for Resynchronization Profile + - Adding Support for N2 handover profile + - Adding Support for Xn Handover profile + - Adding support for handling end marker packet + - Generating GTPU echo request and handling incoming GTPU Request + - Support to send Error indication Message + - Support to handle Paging Request + + 6. gNBSim Deployment Features + + - Support deployment of gNBSim as standalone container From bcd67e5c4938fae6bd0cdf5743f0f27477117883 Mon Sep 17 00:00:00 2001 From: Ajay Lotan Thakur Date: Thu, 15 Jun 2023 15:59:52 -0600 Subject: [PATCH 2/5] Adding mutex for NAS encode/decode --- Dockerfile | 1 + config/gnbsim.yaml | 1 + gnbsim.go | 1 + realue/nas/nas_security.go | 8 ++++++++ 4 files changed, 11 insertions(+) diff --git a/Dockerfile b/Dockerfile index 2b6d7ee8..f9a0696f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,6 +7,7 @@ FROM golang:1.18.0-stretch AS gnb LABEL maintainer="ONF " +RUN echo "deb http://archive.debian.org/debian stretch main" > /etc/apt/sources.list RUN apt-get update && apt-get -y install vim ethtool RUN cd $GOPATH/src && mkdir -p gnbsim COPY . $GOPATH/src/gnbsim diff --git a/config/gnbsim.yaml b/config/gnbsim.yaml index 03dea859..2a0ffa3a 100644 --- a/config/gnbsim.yaml +++ b/config/gnbsim.yaml @@ -10,6 +10,7 @@ info: description: GNBSIM initial local configuration configuration: + runConfigProfilesAtStart: true singleInterface: false #default value execInParallel: false #run all profiles in parallel httpServer: # Serves APIs to create/control profiles on the go diff --git a/gnbsim.go b/gnbsim.go index 2625f768..55c59d81 100644 --- a/gnbsim.go +++ b/gnbsim.go @@ -113,6 +113,7 @@ func action(c *cli.Context) error { // Keep running gnbsim as long as profiles are not finished for _, profile := range config.Configuration.Profiles { if !profile.Enable { + logger.AppLog.Errorln("disbaled profileType ", profile.ProfileType) continue } profileWaitGrp.Add(1) diff --git a/realue/nas/nas_security.go b/realue/nas/nas_security.go index 324befee..6d452801 100644 --- a/realue/nas/nas_security.go +++ b/realue/nas/nas_security.go @@ -8,6 +8,7 @@ package nas import ( "fmt" "reflect" + "sync" realuectx "github.com/omec-project/gnbsim/realue/context" @@ -17,6 +18,8 @@ import ( "github.com/omec-project/ngap/ngapType" ) +var mutex sync.Mutex + func EncodeNasPduWithSecurity(ue *realuectx.RealUe, pdu []byte, securityHeaderType uint8, securityContextAvailable bool) ([]byte, error) { m := nas.NewMessage() @@ -68,6 +71,8 @@ func GetNasPduSetupRequest(ue *realuectx.RealUe, msg *ngapType.PDUSessionResourc func NASEncode(ue *realuectx.RealUe, msg *nas.Message, securityContextAvailable bool) ( payload []byte, err error) { + mutex.Lock() + defer mutex.Unlock() if ue == nil { err = fmt.Errorf("amfUe is nil") @@ -137,6 +142,9 @@ func NASEncode(ue *realuectx.RealUe, msg *nas.Message, securityContextAvailable } func NASDecode(ue *realuectx.RealUe, securityHeaderType uint8, payload []byte) (msg *nas.Message, err error) { + mutex.Lock() + defer mutex.Unlock() + if ue == nil { err = fmt.Errorf("amfUe is nil") return From a52e74576129b4b7945008e755dc5957d5ade5a4 Mon Sep 17 00:00:00 2001 From: Ajay Lotan Thakur Date: Sat, 22 Jul 2023 17:34:06 -0600 Subject: [PATCH 3/5] Provide ms option and send initial UE or uplinkMsg --- gnodeb/worker/gnbcpueworker/handler.go | 35 ++++++++++++++++++-------- profile/context/profile.go | 2 +- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/gnodeb/worker/gnbcpueworker/handler.go b/gnodeb/worker/gnbcpueworker/handler.go index 20fb6b64..2803493c 100644 --- a/gnodeb/worker/gnbcpueworker/handler.go +++ b/gnodeb/worker/gnbcpueworker/handler.go @@ -42,18 +42,31 @@ func HandleInitialUEMessage(gnbue *gnbctx.GnbCpUe, intfcMsg common.InterfaceMessage) { msg := intfcMsg.(*common.UuMessage) - sendMsg, err := test.GetInitialUEMessage(gnbue.GnbUeNgapId, msg.NasPdus[0], "") - if err != nil { - gnbue.Log.Errorln("GetInitialUEMessage failed:", err) - return - } - err = gnbue.Gnb.CpTransport.SendToPeer(gnbue.Amf, sendMsg) - if err != nil { - gnbue.Log.Errorln("SendToPeer failed:", err) - return + if gnbue.AmfUeNgapId != 0 { + sendMsg, err := test.GetUplinkNASTransport(gnbue.AmfUeNgapId, gnbue.GnbUeNgapId, msg.NasPdus[0]) + if err != nil { + gnbue.Log.Errorln("GetUplinkNASMessage failed:", err) + return + } + err = gnbue.Gnb.CpTransport.SendToPeer(gnbue.Amf, sendMsg) + if err != nil { + gnbue.Log.Errorln("SendToPeer failed:", err) + return + } + gnbue.Log.Traceln("Sent Uplink NAS Message to AMF") + } else { + sendMsg, err := test.GetInitialUEMessage(gnbue.GnbUeNgapId, msg.NasPdus[0], "") + if err != nil { + gnbue.Log.Errorln("GetInitialUEMessage failed:", err) + return + } + err = gnbue.Gnb.CpTransport.SendToPeer(gnbue.Amf, sendMsg) + if err != nil { + gnbue.Log.Errorln("SendToPeer failed:", err) + return + } + gnbue.Log.Traceln("Sent Initial UE Message to AMF") } - - gnbue.Log.Traceln("Sent Initial UE Message to AMF") } func HandleDownlinkNasTransport(gnbue *gnbctx.GnbCpUe, diff --git a/profile/context/profile.go b/profile/context/profile.go index c6050306..9a813ec7 100644 --- a/profile/context/profile.go +++ b/profile/context/profile.go @@ -237,7 +237,7 @@ func (p *Profile) GetNextProcedure(pCtx *ProfileUeContext, currentProcedure comm itp, found := p.PIterations[pCtx.CurrentItr] pCtx.Log.Infoln("Current Iteration map - ", itp) if itp.WaitMap[pCtx.CurrentProcIndex] != 0 { - time.Sleep(time.Second * time.Duration(itp.WaitMap[pCtx.CurrentProcIndex])) + time.Sleep(time.Millisecond * time.Duration(itp.WaitMap[pCtx.CurrentProcIndex])) } nextProcIndex := pCtx.CurrentProcIndex + 1 nextProcedure, found := itp.ProcMap[nextProcIndex] From e1778592e89901b5704ab71617e41cdd69f0e162 Mon Sep 17 00:00:00 2001 From: Ajay Lotan Thakur Date: Wed, 8 Nov 2023 14:53:57 -0700 Subject: [PATCH 4/5] Fixing go sum errors, Fixing spell check --- gnbsim.go | 2 +- go.sum | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gnbsim.go b/gnbsim.go index 55c59d81..5b23f282 100644 --- a/gnbsim.go +++ b/gnbsim.go @@ -113,7 +113,7 @@ func action(c *cli.Context) error { // Keep running gnbsim as long as profiles are not finished for _, profile := range config.Configuration.Profiles { if !profile.Enable { - logger.AppLog.Errorln("disbaled profileType ", profile.ProfileType) + logger.AppLog.Errorln("disabled profileType ", profile.ProfileType) continue } profileWaitGrp.Add(1) diff --git a/go.sum b/go.sum index b92e596f..8c5c064a 100644 --- a/go.sum +++ b/go.sum @@ -279,7 +279,7 @@ github.com/omec-project/logger_util v1.1.0 h1:R7tT80+ML1HlK4OoTrNv/UK+2H/u2GdIFN github.com/omec-project/logger_util v1.1.0/go.mod h1:UkD09amIhlh8P0k82A6Uz/atiZGeFS3C2wd334CKpuY= github.com/omec-project/milenage v1.1.0 h1:yVBtBB4hd+SQx4gFkE6mZ8mfzO5na/1d2j31G6jYlCA= github.com/omec-project/milenage v1.1.0/go.mod h1:Tw5HLvxWEQN0JA+EXEVwZ17TL9adEZk3kWqKGgsNmHc= -github.com/omec-project/nas v1.1.1/go.mod h1:WRl/gOe8pZATzTk5pHbAcqUuWbmLdVV/jzjnl5lCcJ8= +github.com/omec-project/nas v1.1.1/go.mod h1:gXqi/IZwEGXno26X8wg8ITsAUiemRQ7PkIJOWP1NzGA= github.com/omec-project/nas v1.1.3 h1:2GuvNz/1tr3M6wpHlcuDCOJaxAa3Fm54xt5Wggklwrg= github.com/omec-project/nas v1.1.3/go.mod h1:gXqi/IZwEGXno26X8wg8ITsAUiemRQ7PkIJOWP1NzGA= github.com/omec-project/ngap v1.1.0 h1:J9bkPEzzyGd1787nGY/aZVp3gckkZBoJB4tkTo59eyw= From 6f893fa83583e7205a83609a0adcb311cb1f3ea4 Mon Sep 17 00:00:00 2001 From: Ajay Lotan Thakur Date: Wed, 8 Nov 2023 14:58:15 -0700 Subject: [PATCH 5/5] Update dockerfile. Fixing lint errors Separate lock for encode & decode NAS message --- Dockerfile | 1 - gnodeb/transport/cptransport.go | 4 ++-- profile/context/profile.go | 4 ++-- realue/nas/build.go | 2 +- realue/nas/nas_security.go | 11 ++++++----- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index 76ea1542..3ddf58e6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,6 @@ FROM golang:1.21.3-bookworm AS gnb LABEL maintainer="ONF " -RUN echo "deb http://archive.debian.org/debian stretch main" > /etc/apt/sources.list RUN apt-get update && apt-get -y install vim ethtool RUN cd $GOPATH/src && mkdir -p gnbsim COPY . $GOPATH/src/gnbsim diff --git a/gnodeb/transport/cptransport.go b/gnodeb/transport/cptransport.go index 60e54ccb..0d935a8d 100644 --- a/gnodeb/transport/cptransport.go +++ b/gnodeb/transport/cptransport.go @@ -156,10 +156,10 @@ func (cpTprt *GnbCpTransport) ReceiveFromPeer(peer transportcommon.TransportPeer cpTprt.Log.Warnln("SCTP read timeout") continue case syscall.EINTR: - cpTprt.Log.Warnln("SCTPRead: %+v\n", err) + cpTprt.Log.Warnf("SCTPRead: %+v\n", err) continue default: - cpTprt.Log.Errorln("Handle connection[addr: %+v] error: %+v\n", amf.Conn.RemoteAddr(), err) + cpTprt.Log.Errorf("Handle connection[addr: %+v] error: %+v\n", amf.Conn.RemoteAddr(), err) return } } diff --git a/profile/context/profile.go b/profile/context/profile.go index 9a813ec7..466a0f7e 100644 --- a/profile/context/profile.go +++ b/profile/context/profile.go @@ -120,7 +120,7 @@ func (profile *Profile) Init() { func SendStepEventProfile(name string) error { profile, found := ProfileMap[name] if found == false { - err := fmt.Errorf("unknown profile:%s", profile) + err := fmt.Errorf("unknown profile:%s", name) log.Println(err) return err } @@ -144,7 +144,7 @@ func SendStepEventProfile(name string) error { func SendAddNewCallsEventProfile(name string, number int32) error { profile, found := ProfileMap[name] if found == false { - err := fmt.Errorf("unknown profile:%s", profile) + err := fmt.Errorf("unknown profile:%s", name) return err } msg := &common.ProfileMessage{} diff --git a/realue/nas/build.go b/realue/nas/build.go index c123ec1c..a2462f9a 100644 --- a/realue/nas/build.go +++ b/realue/nas/build.go @@ -30,7 +30,7 @@ func GetServiceRequest(ue *realuectx.RealUe) ([]byte, error) { data := new(bytes.Buffer) err := nasMsg.GmmMessageEncode(data) if err != nil { - return nil, fmt.Errorf("encode failed:", err) + return nil, fmt.Errorf("encode failed:+%v", err) } return data.Bytes(), nil diff --git a/realue/nas/nas_security.go b/realue/nas/nas_security.go index 6d452801..b6e0ecae 100644 --- a/realue/nas/nas_security.go +++ b/realue/nas/nas_security.go @@ -18,7 +18,8 @@ import ( "github.com/omec-project/ngap/ngapType" ) -var mutex sync.Mutex +var decodeMutex sync.Mutex +var encodeMutex sync.Mutex func EncodeNasPduWithSecurity(ue *realuectx.RealUe, pdu []byte, securityHeaderType uint8, securityContextAvailable bool) ([]byte, error) { @@ -71,8 +72,8 @@ func GetNasPduSetupRequest(ue *realuectx.RealUe, msg *ngapType.PDUSessionResourc func NASEncode(ue *realuectx.RealUe, msg *nas.Message, securityContextAvailable bool) ( payload []byte, err error) { - mutex.Lock() - defer mutex.Unlock() + encodeMutex.Lock() + defer encodeMutex.Unlock() if ue == nil { err = fmt.Errorf("amfUe is nil") @@ -142,8 +143,8 @@ func NASEncode(ue *realuectx.RealUe, msg *nas.Message, securityContextAvailable } func NASDecode(ue *realuectx.RealUe, securityHeaderType uint8, payload []byte) (msg *nas.Message, err error) { - mutex.Lock() - defer mutex.Unlock() + decodeMutex.Lock() + defer decodeMutex.Unlock() if ue == nil { err = fmt.Errorf("amfUe is nil")