├── .github ├── dependabot.yml └── workflows │ ├── build-test.yml │ ├── code-scan.yml │ └── release.yml ├── .gitignore ├── .golangci.yml ├── .reuse └── dep5 ├── CODE_OF_CONDUCT.md ├── LICENSES └── Apache-2.0.txt ├── Makefile ├── README.md ├── VERSION ├── build ├── bin │ └── version_check.sh └── ran-simulator │ ├── Dockerfile │ └── certs │ ├── onfca.crt │ ├── ran-simulator.crt │ └── ran-simulator.key ├── cmd ├── honeycomb │ └── honeycomb.go ├── ransim-tests │ └── ransim-tests.go └── ransim │ └── ransim.go ├── docs ├── api.md ├── cli.md ├── e2.md ├── images │ └── ransim_architecture.jpg ├── model.md ├── quick_start.md └── topology_generator.md ├── go.mod ├── go.sum ├── pkg ├── api │ ├── cells │ │ └── cells.go │ ├── metrics │ │ └── metrics.go │ ├── model │ │ └── model.go │ ├── nodes │ │ └── nodes.go │ ├── routes │ │ └── routes.go │ ├── trafficsim │ │ ├── trafficsim.go │ │ └── trafficsim_test.go │ └── ues │ │ └── ues.go ├── controller │ └── connection │ │ ├── controller.go │ │ └── watcher.go ├── e2agent │ ├── addressing │ │ └── address.go │ ├── agent.go │ ├── agents │ │ └── agents.go │ └── connection │ │ ├── connection.go │ │ ├── options.go │ │ └── utils.go ├── handover │ ├── a3handover.go │ └── handover.go ├── manager │ └── manager.go ├── measurement │ ├── converter.go │ ├── eventa3.go │ └── measurement.go ├── mobility │ ├── driver.go │ ├── driver_test.go │ ├── routes.go │ ├── rrc.go │ └── signal.go ├── model │ ├── layout.go │ ├── load.go │ ├── model.go │ ├── model_test.go │ └── test.yaml ├── servicemodel │ ├── kpm2 │ │ ├── datasets │ │ │ └── cell.csv │ │ ├── defs.go │ │ ├── kpm.go │ │ └── util.go │ ├── mho │ │ ├── a3.go │ │ ├── defs.go │ │ ├── indication.go │ │ ├── mho.go │ │ ├── periodic.go │ │ ├── rrc.go │ │ └── util.go │ ├── rc │ │ ├── defs.go │ │ ├── rc.go │ │ ├── util.go │ │ └── v1 │ │ │ ├── defs.go │ │ │ ├── rc.go │ │ │ └── utils.go │ ├── registry │ │ ├── id.go │ │ ├── registry.go │ │ └── registry_test.go │ └── servicemodel.go ├── store │ ├── agents │ │ └── store.go │ ├── cells │ │ ├── cells.go │ │ ├── cells_test.go │ │ ├── types.go │ │ └── utils.go │ ├── connections │ │ ├── connections.go │ │ └── types.go │ ├── event │ │ └── event.go │ ├── metrics │ │ ├── metrics.go │ │ ├── metrics_test.go │ │ └── types.go │ ├── nodes │ │ ├── nodes.go │ │ ├── nodes_test.go │ │ └── types.go │ ├── routes │ │ ├── routes.go │ │ ├── routes_test.go │ │ └── types.go │ ├── subscriptions │ │ ├── store.go │ │ └── store_test.go │ ├── ues │ │ ├── types.go │ │ ├── ues.go │ │ └── ues_test.go │ └── watcher │ │ └── watcher.go └── utils │ ├── e2ap │ ├── configupdate │ │ └── configupdate.go │ ├── connectionupdate │ │ ├── connectionSetupFailedItemie │ │ │ └── connectionSetupFailedItemIes.go │ │ ├── connectionUpdateitemie │ │ │ └── connectionupdateitemIe.go │ │ └── connectionupdate.go │ ├── control │ │ ├── control.go │ │ └── getters.go │ ├── indication │ │ └── indication.go │ ├── indicationerror │ │ └── indication_error.go │ ├── setup │ │ └── setup.go │ ├── subscription │ │ ├── getters.go │ │ └── subscription.go │ └── subscriptiondelete │ │ ├── getters.go │ │ └── subscriptiondelete.go │ ├── e2sm │ ├── kpm2 │ │ ├── id │ │ │ ├── cellglobalid │ │ │ │ └── cell_global_id.go │ │ │ └── gnbid │ │ │ │ └── gnb_id.go │ │ ├── indication │ │ │ ├── indication_header.go │ │ │ ├── messageformat1 │ │ │ │ └── indication_message_format1.go │ │ │ └── messageformat2 │ │ │ │ └── indication_message_format2.go │ │ ├── labelinfo │ │ │ ├── labelinfo.go │ │ │ └── labelinfo_test.go │ │ ├── measobjectitem │ │ │ └── cell_meas_object_item.go │ │ ├── measurments │ │ │ ├── mean_info_action_item.go │ │ │ ├── meas_info_item.go │ │ │ ├── measurement_data_item.go │ │ │ ├── measurement_item.go │ │ │ └── measurement_type.go │ │ ├── nodeitem │ │ │ └── node_item.go │ │ ├── ranfuncdescription │ │ │ └── ranfuncdescription.go │ │ └── reportstyle │ │ │ └── report_style_item.go │ ├── mho │ │ ├── indication │ │ │ ├── header │ │ │ │ ├── indication_header.go │ │ │ │ └── indication_header_test.go │ │ │ ├── message_format1 │ │ │ │ ├── indication_message.go │ │ │ │ └── indication_message_test.go │ │ │ └── message_format2 │ │ │ │ ├── indication_message.go │ │ │ │ └── indication_message_test.go │ │ └── ranfundesc │ │ │ └── ranfuncdesc.go │ └── rc │ │ ├── controloutcome │ │ └── control_outcome.go │ │ ├── indication │ │ ├── header │ │ │ ├── indication_header.go │ │ │ └── indication_header_test.go │ │ └── message │ │ │ ├── indication_message.go │ │ │ └── indication_message_test.go │ │ ├── nrt │ │ └── nrt_message.go │ │ ├── ranfundesc │ │ └── ranfuncdesc.go │ │ └── v1 │ │ └── indication │ │ ├── headers │ │ ├── format1 │ │ │ └── format1.go │ │ └── format2 │ │ │ └── format2.go │ │ └── messages │ │ ├── format3 │ │ └── format3.go │ │ └── format5 │ │ └── format5.go │ ├── f1ap │ └── f1-messages.go │ ├── geo.go │ ├── gnb_id_type.go │ ├── honeycomb │ ├── README.md │ ├── honeycomb.go │ └── topo.go │ ├── measurement │ ├── qoffsetrange.go │ └── tttrange.go │ ├── ncell_id_type.go │ ├── utils.go │ ├── utils_test.go │ └── xnap │ └── xn-messages.go └── tests ├── e2t ├── connections.go └── suite.go ├── ransim ├── count_cells.go ├── count_nodes.go └── suite.go └── utils ├── e2tnodes.go ├── ransim.go └── sdran.go /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # Copyright 2024 Intel Corporation 3 | 4 | version: 2 5 | updates: 6 | 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | 12 | - package-ecosystem: "docker" 13 | directory: "build/ran-simulator" 14 | schedule: 15 | interval: "weekly" 16 | 17 | - package-ecosystem: "gomod" 18 | directory: "/" 19 | schedule: 20 | interval: "weekly" 21 | -------------------------------------------------------------------------------- /.github/workflows/build-test.yml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # Copyright 2024 Intel Corporation 3 | 4 | name: Build and test workflow 5 | on: 6 | pull_request: 7 | branches: 8 | - master 9 | push: 10 | branches: 11 | - master 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | - uses: actions/setup-go@v5 19 | with: 20 | go-version-file: 'go.mod' 21 | - name: build 22 | run: make build 23 | test: 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@v4 27 | - uses: actions/setup-go@v5 28 | with: 29 | go-version-file: 'go.mod' 30 | - name: Unit tests 31 | run: make test 32 | -------------------------------------------------------------------------------- /.github/workflows/code-scan.yml: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # Copyright 2024 Intel Corporation 3 | 4 | name: Code scan workflow 5 | 6 | on: 7 | pull_request: 8 | branches: 9 | - master 10 | push: 11 | branches: 12 | - master 13 | 14 | jobs: 15 | version-check: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | - name: check version 22 | run: make check-version 23 | lint: 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@v4 27 | - uses: actions/setup-go@v5 28 | with: 29 | go-version-file: 'go.mod' 30 | - name: golang-lint 31 | run: make lint 32 | license: 33 | runs-on: ubuntu-latest 34 | steps: 35 | - uses: actions/checkout@v4 36 | - name: check license 37 | run: make license 38 | fossa-check: 39 | runs-on: ubuntu-latest 40 | steps: 41 | - uses: actions/checkout@v4 42 | - name: FOSSA scan 43 | uses: fossa-contrib/fossa-action@v3 44 | with: 45 | fossa-api-key: 6d304c09a3ec097ba4517724e4a4d17d 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2019-present Open Networking Foundation 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | **/_output 6 | vendor/* 7 | *.DS_Store 8 | coverage.txt 9 | *.coverprofile* 10 | .idea 11 | api/e2/e2-interface.proto 12 | *report*.xml 13 | *coverage*.xml 14 | *-output.out 15 | build/build-tools 16 | venv -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2019-present Open Networking Foundation 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | linters: 6 | enable: 7 | - gofmt 8 | - gocyclo 9 | - misspell 10 | - typecheck 11 | - errcheck 12 | - dogsled 13 | - unconvert 14 | - nakedret 15 | - exportloopref 16 | issues: 17 | exclude-use-default: false 18 | exclude: 19 | - Error return value of `.*Close` is not checked 20 | - Error return value of `.*Flush` is not checked 21 | - Error return value of `.*Write` is not checked 22 | -------------------------------------------------------------------------------- /.reuse/dep5: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | 3 | Files: VERSION .gitreview go.mod go.sum build/ran-simulator/certs/* docs/images/* *.csv 4 | Copyright: 2021 Open Networking Foundation 5 | License: Apache-2.0 6 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | We expect all ONF employees, member companies, and participants to abide by our [Code of Conduct](https://www.opennetworking.org/wp-content/themes/onf/img/onf-code-of-conduct.pdf). 8 | 9 | If you are being harassed, notice that someone else is being harassed, or have any other concerns involving someone’s welfare, please notify a member of the ONF team or email [conduct@opennetworking.org](conduct@opennetworking.org). 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: Apache-2.0 2 | # Copyright 2019 Open Networking Foundation 3 | # Copyright 2024 Intel Corporation 4 | 5 | export CGO_ENABLED=1 6 | export GO111MODULE=on 7 | 8 | .PHONY: build 9 | 10 | RAN_SIMULATOR_VERSION ?= latest 11 | ONOS_PROTOC_VERSION := v0.6.9 12 | 13 | OUTPUT_DIR=./build/_output 14 | 15 | GOLANG_CI_VERSION := v1.52.2 16 | 17 | all: build docker-build 18 | 19 | build: # @HELP build the Go binaries and run all validations (default) 20 | build: 21 | go build ${BUILD_FLAGS} -o ${OUTPUT_DIR}/ransim ./cmd/ransim 22 | go build ${BUILD_FLAGS} -o ${OUTPUT_DIR}/honeycomb ./cmd/honeycomb 23 | 24 | test: # @HELP run the unit tests and source code validation producing a golang style report 25 | test: build lint license 26 | go test -race github.com/onosproject/ran-simulator/... 27 | 28 | docker-build-ran-simulator: # @HELP build ran-simulator Docker image 29 | @go mod vendor 30 | docker build . -f build/ran-simulator/Dockerfile \ 31 | -t onosproject/ran-simulator:${RAN_SIMULATOR_VERSION} 32 | 33 | docker-build: # @HELP build all Docker images 34 | docker-build: build docker-build-ran-simulator 35 | 36 | docker-push-ran-simulator: # @HELP push onos-pci Docker image 37 | docker push onosproject/ran-simulator:${RAN_SIMULATOR_VERSION} 38 | 39 | docker-push: # @HELP push docker images 40 | docker-push: docker-push-ran-simulator 41 | 42 | lint: # @HELP examines Go source code and reports coding problems 43 | golangci-lint --version | grep $(GOLANG_CI_VERSION) || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b `go env GOPATH`/bin $(GOLANG_CI_VERSION) 44 | golangci-lint run --timeout 15m 45 | 46 | license: # @HELP run license checks 47 | rm -rf venv 48 | python3 -m venv venv 49 | . ./venv/bin/activate;\ 50 | python3 -m pip install --upgrade pip;\ 51 | python3 -m pip install reuse;\ 52 | reuse lint 53 | 54 | check-version: # @HELP check version is duplicated 55 | ./build/bin/version_check.sh all 56 | 57 | clean:: # @HELP remove all the build artifacts 58 | rm -rf ${OUTPUT_DIR} ./cmd/trafficsim/trafficsim ./cmd/ransim/ransim 59 | go clean github.com/onosproject/ran-simulator/... 60 | 61 | help: 62 | @grep -E '^.*: *# *@HELP' $(MAKEFILE_LIST) \ 63 | | sort \ 64 | | awk ' \ 65 | BEGIN {FS = ": *# *@HELP"}; \ 66 | {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}; \ 67 | ' 68 | 69 | model-files: # @HELP generate various model and model-topo YAML files in sdran-helm-charts/ran-simulator 70 | go run cmd/honeycomb/honeycomb.go topo --plmnid 314628 --towers 2 --ue-count 10 --controller-yaml ../sdran-helm-charts/ran-simulator/files/topo/model-topo.yaml ../sdran-helm-charts/ran-simulator/files/model/model.yaml 71 | go run cmd/honeycomb/honeycomb.go topo --plmnid 314628 --towers 12 --ue-count 100 --sectors-per-tower 6 --controller-yaml ../sdran-helm-charts/ran-simulator/files/topo/scale-model-topo.yaml ../sdran-helm-charts/ran-simulator/files/model/scale-model.yaml 72 | go run cmd/honeycomb/honeycomb.go topo --plmnid 314628 --towers 1 --ue-count 5 --controller-yaml ../sdran-helm-charts/ran-simulator/files/topo/three-cell-model-topo.yaml ../sdran-helm-charts/ran-simulator/files/model/three-cell-model.yaml -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # RAN Simulator 8 | 9 | This software allows simulation of a number of RAN CU/DU nodes and RU cells via the O-RAN E2AP standard. 10 | The simulated RAN environment is described using a YAML model file loaded at start-up. 11 | The simulator offers a gRPC API that can be used at run-time to induce changes in order to 12 | simulate a dynamically changing environment. 13 | 14 | The main RAN simulator software is accompanied by a number of utilities that allow generation of YAML files 15 | that describe large RAN topologies and various environmental metrics, e.g. PCI. 16 | 17 | CLI for the RAN simulator is available via `onos-cli ransim` usage and allows access to all major features of 18 | the simulator gRPC API, for controlling and monitoring the changes to the simulated environment. 19 | 20 | * [Quick Start](docs/quick_start.md) 21 | * [Simulation Models and APIs](docs/model.md) 22 | * [E2 Nodes Simulation and Service Models](docs/e2.md) 23 | * [Honeycomb Topology Generator](docs/topology_generator.md) 24 | 25 | ## Architecture 26 | 27 | The following figure outlines the RAN simulator architecture: 28 | 29 | ![RAN simulator Architecture](docs/images/ransim_architecture.jpg) 30 | 31 | * **E2 nodes**: Upper half of the RAN simulator is responsible to simulate e2 nodes where each E2 node implements an E2 agent using E2AP, and implement service models. 32 | 33 | * **RAN Environment**: Lower half of the RAN simulator is responsible to simulate RAN environment to support required RAN functions 34 | for implementing E2 service models (e.g. simulating User Equipments (UEs), mobility, etc). 35 | 36 | * **Data Stores**: lower half and upper half are connected using data stores that stores information 37 | about E2-nodes, E2-agents, UEs, RAN metrics, E2 subscriptions, etc. 38 | 39 | * **RAN simulator APIs**: RAN simulator provides a variety of gRPC APIs that can be used for controlling E2 nodes and RAN environment. 40 | You can find more details about RAN simulator APIs here: [RAN simulator APIs](api.md) 41 | 42 | * **RAN simulator CLI**: RAN simulator is equipped with a command line interface which is integrated with 43 | [onos-cli](https://github.com/onosproject/onos-cli) that allows to interact with RAN simulator to retrieve required information from data stores, 44 | monitor RAN environment changes, create/remove/update RAN entities, metrics, etc. 45 | The list of ransim commands is documented here [RAN simulator CLI](https://github.com/onosproject/onos-cli/blob/master/docs/cli/onos_ransim.md) 46 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.10.17-dev 2 | -------------------------------------------------------------------------------- /build/bin/version_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # SPDX-License-Identifier: Apache-2.0 3 | # Copyright 2024 Intel Corporation 4 | 5 | set +x 6 | 7 | # input should be all, is_valid_format, is_dev, and is_unique 8 | INPUT=$1 9 | 10 | function is_valid_format() { 11 | # check if version format is matched to SemVer 12 | VER_REGEX='^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$' 13 | if [[ ! $(cat VERSION | tr -d '\n' | sed s/-dev//) =~ $VER_REGEX ]] 14 | then 15 | return 1 16 | fi 17 | return 0 18 | } 19 | 20 | function is_dev_version() { 21 | # check if version has '-dev' 22 | # if there is, no need to check version 23 | if [[ $(cat VERSION | tr -d '\n' | tail -c 4) =~ "-dev" ]] 24 | then 25 | return 0 26 | fi 27 | return 1 28 | } 29 | 30 | function is_unique_version() { 31 | # check if the version is already tagged in GitHub repository 32 | for t in $(git tag | cat) 33 | do 34 | if [[ $t == $(echo v$(cat VERSION | tr -d '\n')) ]] 35 | then 36 | return 1 37 | fi 38 | done 39 | return 0 40 | } 41 | 42 | case $INPUT in 43 | all) 44 | is_valid_format 45 | f_valid=$? 46 | if [[ $f_valid == 1 ]] 47 | then 48 | echo "ERROR: Version $(cat VERSION) is not in SemVer format" 49 | exit 2 50 | fi 51 | 52 | is_dev_version 53 | f_dev=$? 54 | if [[ $f_dev == 0 ]] 55 | then 56 | echo "This is dev version" 57 | exit 0 58 | fi 59 | 60 | is_unique_version 61 | f_unique=$? 62 | if [[ $f_unique == 1 ]] 63 | then 64 | echo "ERROR: duplicated tag $(cat VERSION)" 65 | exit 2 66 | fi 67 | ;; 68 | 69 | is_valid_format) 70 | is_valid_format 71 | ;; 72 | 73 | is_dev) 74 | is_dev_version 75 | f_dev=$? 76 | if [[ $f_dev == 0 ]] 77 | then 78 | echo "true" 79 | exit 0 80 | fi 81 | echo "false" 82 | ;; 83 | 84 | is_unique) 85 | is_unique_version 86 | ;; 87 | 88 | *) 89 | echo -n "unknown input" 90 | exit 2 91 | ;; 92 | 93 | esac 94 | -------------------------------------------------------------------------------- /build/ran-simulator/Dockerfile: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2019-present Open Networking Foundation 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | ARG ONOS_BUILD_VERSION=undefined 6 | 7 | FROM onosproject/golang-build:v1.3.0 as build 8 | 9 | ENV GO111MODULE=on 10 | ARG ONOS_MAKE_TARGET=build 11 | 12 | COPY Makefile go.mod go.sum /go/src/github.com/onosproject/ran-simulator/ 13 | COPY cmd/ /go/src/github.com/onosproject/ran-simulator/cmd/ 14 | COPY pkg/ /go/src/github.com/onosproject/ran-simulator/pkg/ 15 | COPY vendor/ /go/src/github.com/onosproject/ran-simulator/vendor/ 16 | COPY build/ /go/src/github.com/onosproject/ran-simulator/build/ 17 | 18 | RUN cd /go/src/github.com/onosproject/ran-simulator && GOFLAGS=-mod=vendor make ${ONOS_MAKE_TARGET} 19 | 20 | FROM frolvlad/alpine-glibc:alpine-3.12 21 | 22 | USER nobody 23 | 24 | COPY --from=build /go/src/github.com/onosproject/ran-simulator/build/_output/ransim /usr/local/bin/ransim 25 | COPY --from=build /go/src/github.com/onosproject/ran-simulator/pkg/servicemodel/kpm2/datasets /usr/local/datasets 26 | # COPY pkg/config/*.yaml /etc/onos/config/ 27 | 28 | ENTRYPOINT ["ransim"] 29 | -------------------------------------------------------------------------------- /build/ran-simulator/certs/onfca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDYDCCAkgCCQDe99fSN9qxSTANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJV 3 | UzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCU1lbmxvUGFyazEMMAoGA1UECgwDT05G 4 | MRQwEgYDVQQLDAtFbmdpbmVlcmluZzEeMBwGA1UEAwwVY2Eub3Blbm5ldHdvcmtp 5 | bmcub3JnMB4XDTE5MDQxMTA5MDYxM1oXDTI5MDQwODA5MDYxM1owcjELMAkGA1UE 6 | BhMCVVMxCzAJBgNVBAgMAkNBMRIwEAYDVQQHDAlNZW5sb1BhcmsxDDAKBgNVBAoM 7 | A09ORjEUMBIGA1UECwwLRW5naW5lZXJpbmcxHjAcBgNVBAMMFWNhLm9wZW5uZXR3 8 | b3JraW5nLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMEg7CZR 9 | X8Y+syKHaQCh6mNIL1D065trwX8RnuKM2kBwSu034zefQAPloWugSoJgJnf5fe0j 10 | nUD8gN3Sm8XRhCkvf67pzfabgw4n8eJmHScyL/ugyExB6Kahwzn37bt3oT3gSqhr 11 | 6PUznWJ8fvfVuCHZZkv/HPRp4eyAcGzbJ4TuB0go4s6VE0WU5OCxCSlAiK3lvpVr 12 | 3DOLdYLVoCa5q8Ctl3wXDrfTLw5/Bpfrg9fF9ED2/YKIdV8KZ2ki/gwEOQqWcKp8 13 | 0LkTlfOWsdGjp4opPuPT7njMBGXMJzJ8/J1e1aJvIsoB7n8XrfvkNiWL5U3fM4N7 14 | UZN9jfcl7ULmm7cCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAIh6FjkQuTfXddmZY 15 | FYpoTen/VD5iu2Xxc1TexwmKeH+YtaKp1Zk8PTgbCtMEwEiyslfeHTMtODfnpUIk 16 | DwvtB4W0PAnreRsqh9MBzdU6YZmzGyZ92vSUB3yukkHaYzyjeKM0AwgVl9yRNEZw 17 | Y/OM070hJXXzJh3eJpLl9dlUbMKzaoAh2bZx6y3ZJIZFs/zrpGfg4lvBAvfO/59i 18 | mxJ9bQBSN3U2Hwp6ioOQzP0LpllfXtx9N5LanWpB0cu/HN9vAgtp3kRTBZD0M1XI 19 | Ctit8bXV7Mz+1iGqoyUhfCYcCSjuWTgAxzir+hrdn7uO67Hv4ndCoSj4SQaGka3W 20 | eEfVeA== 21 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /build/ran-simulator/certs/ran-simulator.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDYzCCAksCFErBGzsXHo1l8bmZRmDkF+h2bsdUMA0GCSqGSIb3DQEBCwUAMHIx 3 | CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJTWVubG9QYXJrMQww 4 | CgYDVQQKDANPTkYxFDASBgNVBAsMC0VuZ2luZWVyaW5nMR4wHAYDVQQDDBVjYS5v 5 | cGVubmV0d29ya2luZy5vcmcwHhcNMjAwMTMxMTM0MjUwWhcNMzAwMTI4MTM0MjUw 6 | WjBqMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCU1lbmxvUGFy 7 | azEMMAoGA1UECgwDT05GMRQwEgYDVQQLDAtFbmdpbmVlcmluZzEWMBQGA1UEAwwN 8 | cmFuLXNpbXVsYXRvcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALcM 9 | 9no0909J44wj7B9mfe/WkKBqtWmFRhzPDe7B+wyC204C3ZpVjxeXgr+++V2MqEdH 10 | YercLzMjc9vYgxE+Y2CGxEV0YKgiFketTOMDkavBpYCcViWE/1GW6oqDJjHTDmkh 11 | quVnhLqKPT2K5DJLtNYrBp5UB2ZW3xII0gcyE3IcDlnxlpCIw4aW7hfFLA0kKvW8 12 | PHLjO/43xUUanKOUED99FqHGcJHsf/VaGCcLkCEXc8DKITXh2cXPhbAhLouwLeQn 13 | Jzd6ujs6r0+Qr7xpgYDiKfif2l0rBscc6Emdj6AQ+De9S998lV3FxqcM19hXrMXs 14 | e3emOJ/TJi3JIsmvpKECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAr/BQA9XG/JV 15 | G4UUvQfV93oGxXt9QyyvdMNBqsk6ys4CqSbXYA7NYglX2LFW2dWIYx85CvfXwvvR 16 | nFrY1CA2dFAnXQJ0jvbkLLf4SaRxTp+HtOJLPs4T0/FD3iWsa1GxG/RPyiaFCLpb 17 | KNt9mbFkF6Q3NAvB4WIdLDopAS0fhTSokfFXqM46dDXENXqwvbURSaKE2lU1zPCg 18 | rzc5KdZPTgrnGaVfjD/2F+Ej15ltKJjvL4UAhILk0Nditqe0Mi9FUEv4O/8sbY1K 19 | SUj0+6UdSbw/cXmtWUtQ1ZSSpQFTijKBcqOlb4K0fAarVzpqYEISQ7CUABC80x8r 20 | ZNxFGLWgOQ== 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /build/ran-simulator/certs/ran-simulator.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC3DPZ6NPdPSeOM 3 | I+wfZn3v1pCgarVphUYczw3uwfsMgttOAt2aVY8Xl4K/vvldjKhHR2Hq3C8zI3Pb 4 | 2IMRPmNghsRFdGCoIhZHrUzjA5GrwaWAnFYlhP9RluqKgyYx0w5pIarlZ4S6ij09 5 | iuQyS7TWKwaeVAdmVt8SCNIHMhNyHA5Z8ZaQiMOGlu4XxSwNJCr1vDxy4zv+N8VF 6 | GpyjlBA/fRahxnCR7H/1WhgnC5AhF3PAyiE14dnFz4WwIS6LsC3kJyc3ero7Oq9P 7 | kK+8aYGA4in4n9pdKwbHHOhJnY+gEPg3vUvffJVdxcanDNfYV6zF7Ht3pjif0yYt 8 | ySLJr6ShAgMBAAECggEAYQ3icZE7vzJyD4/MVinFhDDDpgpt/XDIZ+XwgTMgpNWM 9 | 6aPjUz0iDWQr0vayyMMXRhO2+wubiwW1HE+DztTBZCCQWDMIPJ02KvLb3VG7HtIh 10 | qjs6AdKufNgDq0U2Lxy0e1F6hv+IBE/fgI3vyCsTyqotbC0pbz2IMMu0cFRAszL+ 11 | PoxNA5nGQ6BMgCmVWiUXZTEYceAUjgq/iwf8p26rjSXrJKt/qfpSSzhM+Av2d6E+ 12 | Y0MyeJ3WO1cXqADbKQ0BmVPuuxF33VDKUufCiVtVBJdnVl4R2IBulyXqxCRg46gs 13 | 7pJccSJ8J8Ba9fosJhM67KmmYucfgKwif4K0ZR1lAQKBgQDvgF8tch4KSrOGc0ol 14 | UMyhPieXk21N4U5XL1fvwOiRwTIKFV8rWaXX6ovzORctrf31bWWCOjWncMVEuB1U 15 | CeGARlJGDmgXra911c8AQaa+JyNZVuDW2JbULu/SJoAlOKPBKdmBPsC+qWjBeO8T 16 | nuoWhzbV7ttaLTMQ02pf0TsPGQKBgQDDqRN9TlfKX/CbLlKc2rx9DtXvnVtrV4gN 17 | PFbZcoO/W01f/ItPFMfCb3QOHiFOiAZh6eGWcDi2/pE7DVjZZxPSuw3Iy/LBzKIB 18 | x+TU7UPKsGHPcKPP3mJ1yZ81AX8oZHjKyw8ANPFf/FLc4N5r2BDmBOp9+4FiWpxJ 19 | uPy/UVJayQKBgHymRmMDusjGeksmo9dqByaAj+Ce1UusULalqFHbB/AcKev/lYmd 20 | XehTZUVQWFTo8n0S07sEiro7wh/y5yi+/8NgVh+qDdkNB33/qn3KrXrYKdisk9ad 21 | 4VpLl3u7mARHR0sYeeB/hZd12lSfmWaP1eulsg+EAlwbnDFMp1d5MRC5AoGAT54B 22 | XEAA4Uzg74SOAV3QzWK4E2UIykk4B4rCHIHIsplIhwKQ/YELOEd6BjSkgPxA/J7b 23 | OQg5S92S42CvAug63MlY9phnFA1c7zSUHUDfER9s7ah8QB3SGvQMYNlXEOyxanPu 24 | irsAbXqTjWXDnEazuaXOda1eHNOaPTWVQ5Sn2mECgYEAz26IspuuQSojoF2R8I3P 25 | oxBIt6Emb5HRhWtnsQ95foAGFVnjQW2lmws5FTDzPIkGWg974EP5x9W81yFVukHj 26 | W1MY/o8vK/6wbqB7k7Hynlt7ULj0L1XGHewl9ry2kdJOUOv8z2T5SrmWryVZ7lv3 27 | QiZmoLhSpGEl6OTFsJJ+CeI= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /cmd/ransim-tests/ransim-tests.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package main 6 | 7 | import ( 8 | "github.com/onosproject/helmit/pkg/registry" 9 | "github.com/onosproject/helmit/pkg/test" 10 | "github.com/onosproject/ran-simulator/tests/e2t" 11 | "github.com/onosproject/ran-simulator/tests/ransim" 12 | ) 13 | 14 | func main() { 15 | registry.RegisterTestSuite("e2t", &e2t.TestSuite{}) 16 | registry.RegisterTestSuite("ransim", &ransim.TestSuite{}) 17 | test.Main() 18 | } 19 | -------------------------------------------------------------------------------- /cmd/ransim/ransim.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | 6 | /* 7 | Package trafficsim is the main entry point to the ONOS TrafficSim application. 8 | 9 | # Arguments 10 | 11 | -caPath 12 | 13 | -keyPath 14 | 15 | -certPath 16 | 17 | See ../../docs/run.md for how to run the application. 18 | */ 19 | package main 20 | 21 | import ( 22 | "flag" 23 | "math/rand" 24 | "time" 25 | 26 | "github.com/onosproject/onos-lib-go/pkg/logging" 27 | "github.com/onosproject/ran-simulator/pkg/manager" 28 | ) 29 | 30 | var log = logging.GetLogger("main") 31 | 32 | type arrayFlags []string 33 | 34 | func (i *arrayFlags) String() string { 35 | return "my string representation" 36 | } 37 | 38 | func (i *arrayFlags) Set(value string) error { 39 | *i = append(*i, value) 40 | return nil 41 | } 42 | 43 | // The main entry point 44 | func main() { 45 | log.Info("Starting Ran simulator") 46 | 47 | rand.Seed(time.Now().UnixNano()) 48 | 49 | ready := make(chan bool) 50 | 51 | var serviceModelPlugins arrayFlags 52 | flag.Var(&serviceModelPlugins, "serviceModel", "names of service model plugins to load (repeated)") 53 | caPath := flag.String("caPath", "", "path to CA certificate") 54 | keyPath := flag.String("keyPath", "", "path to client private key") 55 | certPath := flag.String("certPath", "", "path to client certificate") 56 | grpcPort := flag.Int("grpcPort", 5150, "GRPC port for e2T server") 57 | modelName := flag.String("modelName", "model", "RANSim model file/resource name") 58 | metricName := flag.String("metricName", "", "RANSim metric file/resource name") 59 | hoLogic := flag.String("hoLogic", "local", "the location of handover logic {local, mho}") 60 | flag.Parse() 61 | 62 | if *hoLogic != "local" && *hoLogic != "mho" { 63 | log.Errorf("hoLogic arg should be one of {local, mho}") 64 | return 65 | } 66 | 67 | cfg := &manager.Config{ 68 | CAPath: *caPath, 69 | KeyPath: *keyPath, 70 | CertPath: *certPath, 71 | GRPCPort: *grpcPort, 72 | ModelName: *modelName, 73 | MetricName: *metricName, 74 | HOLogic: *hoLogic, 75 | } 76 | 77 | mgr, err := manager.NewManager(cfg) 78 | if err == nil { 79 | mgr.Run() 80 | <-ready 81 | mgr.Close() 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /docs/api.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # RAN simulator APIs 8 | 9 | RAN simulator gRPC APIs are defined in [onos-api][onos-api] that are listed as follows: 10 | 11 | * **Model API**: provides means to create, delete and read RAN simulation model 12 | such as E2 nodes and cells. 13 | 14 | * **Metrics API**: provides means to create, delete, and read metrics for the specified entity 15 | ( e.g. A node, a cell, or a UE) 16 | 17 | * **Traffic Sim API**: provides means to create, list, and monitor UEs. 18 | 19 | [onos-api]: https://github.com/onosproject/onos-api/ -------------------------------------------------------------------------------- /docs/e2.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Simulation of E2 Nodes 8 | RAN simulator is capable of simulating an arbitrary number of E2 nodes. The E2 nodes can be defined statically in the simulation model ([Simulation Model](model.md)) from the RAN simulator helm chart or can be added/removed at runtime using [RAN simulator APIs](api.md). 9 | 10 | Each E2 node implements an E2 agent interface. Currently, each E2 agent implements E2AP procedures including *Subscription*, *Subscription Delete*, *Connection Update*, and *Configuration Update*. 11 | and *Control* procedures. 12 | 13 | # Supported Service Models 14 | The supported service models are listed as follows: 15 | 16 | ### Done ✓ 17 | 18 | - [x] ORAN-E2SM-KPM, Version 1.0 19 | - [x] ORAN-E2SM-KPM, Version 2.0 20 | - [ ] RC-PRE 21 | - [x] PCI Use case 22 | - [x] E2SM-MHO, Version 1.0 23 | 24 | ### In Progress 25 | 26 | -------------------------------------------------------------------------------- /docs/images/ransim_architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onosproject/ran-simulator/9db3dd396bef9b0eaaadc325b0de2b616dca27b4/docs/images/ransim_architecture.jpg -------------------------------------------------------------------------------- /docs/model.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Simulation Models 8 | 9 | RAN simulator defines two levels of simulation models: 10 | 11 | * **Generic model:** that defines E2 nodes, cells, service models, E2T end points in a Yaml file. RAN simulator reads this file to create E2 nodes and initializing data stores. A sample [model](https://github.com/onosproject/sdran-helm-charts/blob/master/ran-simulator/files/model/model.yaml) has been created using the [Honeycomb Topology Generator](topology_generator.md) and added to the [ran-simulator helm chart][RAN simulator helm chart]. 12 | 13 | 14 | * **Use Case Specific Models**: The simulation information that is not common between use cases can be added as new service models will be introduced. These models can be added to the [ran-simulator helm chart][RAN simulator helm chart] and can be loaded by RAN simulator. 15 | 16 | ## MHO specific model 17 | One example of a use case specific model is the **two-cell-two-node-model.yaml** model, is used by **onos-mho** xApplication to emulate UEs moving between pre-determined end-points. As opposed to the generic model that supports UEs moving on random routes (with randomly generated end-points), the two-cell-two-node-model is ideally suited to test handover scenarios deterministically. In order to support this model, RANSim supports the ability to specify the following directives in the model's yaml description: 18 | 19 | * routeEndPoints: Start and end end-point coordinates for routes 20 | * directRoute: Direct route between end-points (as opposed to the default randomly zig-zagging route) 21 | * initialRrcState: Specify the initial RRC state of UEs (as opposed to the default randomly assigned initial state) 22 | * rrcStateChangesDisabled: Disable RRC state changes 23 | 24 | 25 | [RAN simulator helm chart]: https://github.com/onosproject/sdran-helm-charts/tree/master/ran-simulator 26 | -------------------------------------------------------------------------------- /docs/topology_generator.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Honeycomb Topology Generator 8 | 9 | The RAN simulator comes with an accompanying utility that generates a RAN topology YAML file that is ready to be loaded by the RAN simulator. 10 | 11 | This utility generates a hexagonal grid of RAN towers (E2 Nodes), each with a prescribed number of cells with equal arc of coverage. The following is the command-line usage: 12 | 13 | ``` 14 | Usage: 15 | honeycomb topo outfile [flags] 16 | 17 | Flags: 18 | --cell-types strings List of cell size types (default [FEMTO,ENTERPRISE,OUTDOOR_SMALL,MACRO]) 19 | --controller-addresses strings List of E2T controller addresses or service names (default [onos-e2t]) 20 | --controller-yaml string if specified, location of yaml file for controller 21 | --deform-scale float scale factor for perturbation (default 0.01) 22 | --earfcn-start uint32 start point for EARFCN generation (default 42) 23 | --gnbid-start string GnbID start in hex (default "5152") 24 | -h, --help help for topo 25 | -a, --latitude float Map centre latitude in degrees (default 52.52) 26 | -g, --longitude float Map centre longitude in degrees (default 13.405) 27 | --max-collisions uint maximum number of collisions (default 8) 28 | -d, --max-neighbor-distance float Maximum 'distance' between neighbor cells; see docs (default 3600) 29 | --max-neighbors int Maximum number of neighbors a cell will have; -1 no limit (default 5) 30 | --max-pci uint maximum PCI value (default 503) 31 | --min-pci uint minimum PCI value 32 | -i, --pitch float32 pitch between cells in degrees (default 0.02) 33 | --plmnid string PlmnID in MCC-MNC format, e.g. CCCNNN or CCCNN (default "315010") 34 | -s, --sectors-per-tower uint sectors per tower (default 3) 35 | --service-models strings List of service models supported by the nodes (default [kpm/1,rcpre2/3,kpm2/4,mho/5]) 36 | --single-node generate a single node for all cells 37 | -t, --towers uint number of towers 38 | --ue-count uint User Equipment count 39 | --ue-count-per-cell uint Desired UE count per cell (default 15) 40 | ``` 41 | 42 | Most options have reasonable defaults and only the `--towers` is mandatory. Here is an example of how to run the command to generate topology for a network with PLMNID of `314628` with 10 E2 nodes (towers), each with default number of 3 cells. 43 | 44 | ``` 45 | go run cmd/honeycomb/honeycomb.go topo --plmnid 314628 --towers 10 pkg/utils/honeycomb/sample.yaml 46 | ``` 47 | 48 | Here is the [output generated by the above command](../pkg/utils/honeycomb/sample.yaml). 49 | 50 | Note that for options that are lists, like `--controller-addresses` for example, you can specify them as comma-separated values `--controller-addresses onos-e2t-1,onos-e2t-2` or you can simply repeat the option `--controller-addresses onos-e2t-1 --controller-addresses onos-e2t-2`. 51 | 52 | The `--max-neightbor-distance` parameter (specified in meters) works as follows: if after traveling this distance along a center line of the coverage sector, the endpoint falls within half this distance from another cell's such endpoint, those two cells will be considered neighbors. This is to assure that the two coverage arcs converge sufficiently. 53 | 54 | Note that the utility relies on random number generator and therefore its output is not deterministic. -------------------------------------------------------------------------------- /pkg/api/model/model.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | 6 | package cells 7 | 8 | import ( 9 | "context" 10 | 11 | modelapi "github.com/onosproject/onos-api/go/onos/ransim/model" 12 | liblog "github.com/onosproject/onos-lib-go/pkg/logging" 13 | service "github.com/onosproject/onos-lib-go/pkg/northbound" 14 | "google.golang.org/grpc" 15 | ) 16 | 17 | var log = liblog.GetLogger() 18 | 19 | // ManagementDelegate provides means to clear and load the model and resume the simulation 20 | type ManagementDelegate interface { 21 | // PauseAndClear pauses simulation and clears the model 22 | PauseAndClear(ctx context.Context) 23 | 24 | // LoadModel loads the new model into the simulator 25 | LoadModel(ctx context.Context, modelData []byte) error 26 | 27 | // LoadMetrics loads new metrics into the simulator 28 | LoadMetrics(ctx context.Context, name string, metricsData []byte) error 29 | 30 | // Resume resume the simulation 31 | Resume(ctx context.Context) 32 | } 33 | 34 | // NewService returns a new model Service 35 | func NewService(delegate ManagementDelegate) service.Service { 36 | return &Service{ 37 | delegate: delegate, 38 | } 39 | } 40 | 41 | // Service is a Service implementation for administration. 42 | type Service struct { 43 | service.Service 44 | delegate ManagementDelegate 45 | } 46 | 47 | // Register registers the ModelService with the gRPC server. 48 | func (s *Service) Register(r *grpc.Server) { 49 | server := &Server{ 50 | delegate: s.delegate, 51 | } 52 | modelapi.RegisterModelServiceServer(r, server) 53 | } 54 | 55 | // Server implements the ModelService gRPC service 56 | type Server struct { 57 | delegate ManagementDelegate 58 | } 59 | 60 | // Load loads new data sets into the simulator 61 | func (s *Server) Load(ctx context.Context, request *modelapi.LoadRequest) (*modelapi.LoadResponse, error) { 62 | log.Debugf("Received model load request: %v", request) 63 | 64 | // Stop simulation and clear model 65 | s.delegate.PauseAndClear(ctx) 66 | 67 | // Load all new data sets 68 | for _, ds := range request.DataSet { 69 | if ds.Type == "model" { 70 | if err := s.delegate.LoadModel(ctx, ds.Data); err != nil { 71 | return nil, err 72 | } 73 | } else { 74 | if err := s.delegate.LoadMetrics(ctx, ds.Type, ds.Data); err != nil { 75 | return nil, err 76 | } 77 | } 78 | } 79 | 80 | if request.Resume { 81 | s.delegate.Resume(ctx) 82 | } 83 | 84 | return &modelapi.LoadResponse{}, nil 85 | } 86 | 87 | // Clear clears model data 88 | func (s *Server) Clear(ctx context.Context, request *modelapi.ClearRequest) (*modelapi.ClearResponse, error) { 89 | log.Debugf("Received model clear request: %v", request) 90 | s.delegate.PauseAndClear(ctx) 91 | if request.Resume { 92 | s.delegate.Resume(ctx) 93 | } 94 | return &modelapi.ClearResponse{}, nil 95 | } 96 | -------------------------------------------------------------------------------- /pkg/api/trafficsim/trafficsim_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package trafficsim 6 | 7 | import ( 8 | "context" 9 | "google.golang.org/grpc/credentials/insecure" 10 | "net" 11 | "testing" 12 | 13 | simapi "github.com/onosproject/onos-api/go/onos/ransim/trafficsim" 14 | "github.com/onosproject/ran-simulator/pkg/model" 15 | "github.com/onosproject/ran-simulator/pkg/store/cells" 16 | "github.com/onosproject/ran-simulator/pkg/store/nodes" 17 | "github.com/onosproject/ran-simulator/pkg/store/ues" 18 | 19 | "github.com/onosproject/onos-lib-go/pkg/northbound" 20 | "github.com/stretchr/testify/assert" 21 | "google.golang.org/grpc" 22 | "google.golang.org/grpc/test/bufconn" 23 | ) 24 | 25 | var lis *bufconn.Listener 26 | 27 | func bufDialer(context.Context, string) (net.Conn, error) { 28 | return lis.Dial() 29 | } 30 | 31 | func newTestService() (northbound.Service, error) { 32 | m := &model.Model{} 33 | err := model.LoadConfig(m, "../../model/test") 34 | if err != nil { 35 | return &Service{}, err 36 | } 37 | nodeStore := nodes.NewNodeRegistry(m.Nodes) 38 | cellStore := cells.NewCellRegistry(m.Cells, nodeStore) 39 | ueStore := ues.NewUERegistry(m.UECount, cellStore, "random") 40 | return &Service{model: m, cellStore: cellStore, ueStore: ueStore}, nil 41 | } 42 | 43 | func createServerConnection(t *testing.T) *grpc.ClientConn { 44 | lis = bufconn.Listen(1024 * 1024) 45 | s, err := newTestService() 46 | assert.NoError(t, err) 47 | assert.NotNil(t, s) 48 | server := grpc.NewServer() 49 | s.Register(server) 50 | 51 | go func() { 52 | if err := server.Serve(lis); err != nil { 53 | assert.NoError(t, err, "Server exited with error: %v", err) 54 | } 55 | }() 56 | 57 | ctx := context.Background() 58 | conn, err := grpc.DialContext(ctx, "bufnet", grpc.WithContextDialer(bufDialer), grpc.WithTransportCredentials(insecure.NewCredentials())) 59 | if err != nil { 60 | t.Fatalf("Failed to dial bufnet: %v", err) 61 | } 62 | return conn 63 | } 64 | 65 | func TestMapLayout(t *testing.T) { 66 | client := simapi.NewTrafficClient(createServerConnection(t)) 67 | assert.NotNil(t, client, "unable to create gRPC client") 68 | 69 | r, err := client.GetMapLayout(context.TODO(), &simapi.MapLayoutRequest{}) 70 | assert.NoError(t, err, "unable to get map layout") 71 | assert.Equal(t, 45.0, r.Center.Lat, "incorrect latitude") 72 | assert.Equal(t, -30.0, r.Center.Lng, "incorrect longitude") 73 | assert.Equal(t, float32(0.8), r.Zoom, "incorrect zoom") 74 | assert.Equal(t, float32(1.0), r.LocationsScale, "incorrect scale") 75 | assert.Equal(t, true, r.Fade) 76 | assert.Equal(t, true, r.ShowRoutes) 77 | assert.Equal(t, true, r.ShowPower) 78 | } 79 | 80 | func TestServiceBasics(t *testing.T) { 81 | client := simapi.NewTrafficClient(createServerConnection(t)) 82 | assert.NotNil(t, client, "unable to create gRPC client") 83 | 84 | stream, err := client.ListUes(context.Background(), &simapi.ListUesRequest{}) 85 | assert.NoError(t, err, "unable to list UEs") 86 | numUes := countUEs(t, stream) 87 | assert.Equal(t, 12, numUes) 88 | _, err = client.SetNumberUEs(context.TODO(), &simapi.SetNumberUEsRequest{ 89 | Number: 16, 90 | }) 91 | assert.NoError(t, err, "unable to set UE count") 92 | 93 | stream, err = client.ListUes(context.TODO(), &simapi.ListUesRequest{}) 94 | assert.NoError(t, err, "unable to list UEs") 95 | numUes = countUEs(t, stream) 96 | assert.Equal(t, 16, numUes) 97 | 98 | } 99 | 100 | func countUEs(t *testing.T, stream simapi.Traffic_ListUesClient) int { 101 | count := 0 102 | for { 103 | _, err := stream.Recv() 104 | if err != nil { 105 | break 106 | } 107 | count = count + 1 108 | t.Log(count) 109 | } 110 | return count 111 | } 112 | -------------------------------------------------------------------------------- /pkg/controller/connection/watcher.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package connection 6 | 7 | import ( 8 | "context" 9 | "sync" 10 | 11 | "github.com/onosproject/onos-lib-go/pkg/controller" 12 | "github.com/onosproject/ran-simulator/pkg/store/connections" 13 | "github.com/onosproject/ran-simulator/pkg/store/event" 14 | ) 15 | 16 | // Watcher is a connection watcher 17 | type Watcher struct { 18 | connections connections.Store 19 | connectionCh chan event.Event 20 | cancel context.CancelFunc 21 | mu sync.Mutex 22 | } 23 | 24 | // Start starts the connection watcher 25 | func (w *Watcher) Start(ch chan<- controller.ID) error { 26 | log.Info("Starting Connection Watcher") 27 | w.mu.Lock() 28 | defer w.mu.Unlock() 29 | if w.cancel != nil { 30 | return nil 31 | } 32 | 33 | w.connectionCh = make(chan event.Event, queueSize) 34 | ctx, cancel := context.WithCancel(context.Background()) 35 | err := w.connections.Watch(ctx, w.connectionCh, connections.WatchOptions{Replay: true}) 36 | if err != nil { 37 | cancel() 38 | return err 39 | } 40 | w.cancel = cancel 41 | 42 | go func() { 43 | for connectionEvent := range w.connectionCh { 44 | log.Debugf("Received connection event: %v", connectionEvent) 45 | ch <- controller.NewID(connectionEvent.Key) 46 | 47 | } 48 | close(ch) 49 | }() 50 | 51 | return nil 52 | 53 | } 54 | 55 | // Stop stops the connection watcher 56 | func (w *Watcher) Stop() { 57 | w.mu.Lock() 58 | if w.cancel != nil { 59 | w.cancel() 60 | w.cancel = nil 61 | } 62 | w.mu.Unlock() 63 | } 64 | -------------------------------------------------------------------------------- /pkg/e2agent/addressing/address.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package addressing 6 | 7 | import ( 8 | "encoding/binary" 9 | "net" 10 | ) 11 | 12 | // RICAddress RIC IP and port number 13 | type RICAddress struct { 14 | IPAddress net.IP 15 | Port uint64 16 | } 17 | 18 | // Port byte array representation of port 19 | type Port struct { 20 | Value []byte 21 | Len uint32 22 | } 23 | 24 | // ToUint converts port in byte array to uint based on given size 25 | func (p *Port) ToUint() uint64 { 26 | var port uint64 27 | if p.Len == 16 { 28 | port = uint64(binary.BigEndian.Uint16(p.Value)) 29 | } else if p.Len == 32 { 30 | port = uint64(binary.BigEndian.Uint32(p.Value)) 31 | } else if p.Len == 64 { 32 | port = binary.BigEndian.Uint64(p.Value) 33 | } 34 | 35 | return port 36 | } 37 | -------------------------------------------------------------------------------- /pkg/e2agent/connection/options.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package connection 6 | 7 | import ( 8 | e2 "github.com/onosproject/onos-e2t/pkg/protocols/e2ap" 9 | "github.com/onosproject/ran-simulator/pkg/e2agent/addressing" 10 | "github.com/onosproject/ran-simulator/pkg/model" 11 | "github.com/onosproject/ran-simulator/pkg/servicemodel/registry" 12 | "github.com/onosproject/ran-simulator/pkg/store/cells" 13 | "github.com/onosproject/ran-simulator/pkg/store/connections" 14 | "github.com/onosproject/ran-simulator/pkg/store/subscriptions" 15 | ) 16 | 17 | // InstanceOptions e2 channel instance options 18 | type InstanceOptions struct { 19 | node model.Node 20 | model *model.Model 21 | ricAddress addressing.RICAddress 22 | e2Client e2.ClientConn 23 | registry *registry.ServiceModelRegistry 24 | subStore *subscriptions.Subscriptions 25 | connectionStore connections.Store 26 | cellStore cells.Store 27 | } 28 | 29 | // InstanceOption instance option 30 | type InstanceOption func(*InstanceOptions) 31 | 32 | // WithNode sets model node 33 | func WithNode(node model.Node) func(options *InstanceOptions) { 34 | return func(options *InstanceOptions) { 35 | options.node = node 36 | } 37 | } 38 | 39 | // WithModel sets model 40 | func WithModel(model *model.Model) func(options *InstanceOptions) { 41 | return func(options *InstanceOptions) { 42 | options.model = model 43 | } 44 | } 45 | 46 | // WithRICAddress sets RIC address 47 | func WithRICAddress(ricAddress addressing.RICAddress) func(options *InstanceOptions) { 48 | return func(options *InstanceOptions) { 49 | options.ricAddress = ricAddress 50 | } 51 | } 52 | 53 | // WithE2Client sets E2 channel 54 | func WithE2Client(e2Client e2.ClientConn) func(options *InstanceOptions) { 55 | return func(options *InstanceOptions) { 56 | options.e2Client = e2Client 57 | } 58 | } 59 | 60 | // WithSMRegistry sets service model registry 61 | func WithSMRegistry(registry *registry.ServiceModelRegistry) func(options *InstanceOptions) { 62 | return func(options *InstanceOptions) { 63 | options.registry = registry 64 | } 65 | } 66 | 67 | // WithSubStore sets subscription store 68 | func WithSubStore(subStore *subscriptions.Subscriptions) func(options *InstanceOptions) { 69 | return func(options *InstanceOptions) { 70 | options.subStore = subStore 71 | } 72 | } 73 | 74 | // WithConnectionStore sets connection store 75 | func WithConnectionStore(connectionStore connections.Store) func(options *InstanceOptions) { 76 | return func(options *InstanceOptions) { 77 | options.connectionStore = connectionStore 78 | } 79 | } 80 | 81 | // WithCellStore sets cell store 82 | func WithCellStore(cellStore cells.Store) func(options *InstanceOptions) { 83 | return func(options *InstanceOptions) { 84 | options.cellStore = cellStore 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /pkg/e2agent/connection/utils.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package connection 6 | 7 | import ( 8 | "github.com/onosproject/ran-simulator/pkg/e2agent/addressing" 9 | 10 | "time" 11 | 12 | "github.com/cenkalti/backoff/v4" 13 | e2apies "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-ies" 14 | ) 15 | 16 | func (e *e2Connection) getRICAddress(tnlInfo *e2apies.Tnlinformation) addressing.RICAddress { 17 | tnlAddr := tnlInfo.GetTnlAddress().GetValue() 18 | var ricAddress addressing.RICAddress 19 | 20 | if tnlInfo.GetTnlPort() != nil { 21 | tnlPort := tnlInfo.GetTnlPort().GetValue() 22 | tnlPortLen := tnlInfo.GetTnlPort().GetLen() 23 | p := &addressing.Port{ 24 | Value: tnlPort, 25 | Len: tnlPortLen, 26 | } 27 | ricAddress.Port = p.ToUint() 28 | 29 | } else { 30 | ricAddress.Port = e.ricAddress.Port 31 | } 32 | ricAddress.IPAddress = tnlAddr 33 | return ricAddress 34 | } 35 | 36 | const ( 37 | backoffInterval = 10 * time.Millisecond 38 | maxBackoffTime = 5 * time.Second 39 | ) 40 | 41 | func newExpBackoff() *backoff.ExponentialBackOff { 42 | b := backoff.NewExponentialBackOff() 43 | b.InitialInterval = backoffInterval 44 | // MaxInterval caps the RetryInterval 45 | b.MaxInterval = maxBackoffTime 46 | // Never stops retrying 47 | b.MaxElapsedTime = 0 48 | return b 49 | } 50 | -------------------------------------------------------------------------------- /pkg/handover/a3handover.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package handover 6 | 7 | import ( 8 | "github.com/onosproject/onos-lib-go/pkg/logging" 9 | "github.com/onosproject/rrm-son-lib/pkg/handover" 10 | "github.com/onosproject/rrm-son-lib/pkg/model/device" 11 | ) 12 | 13 | var logA3ho = logging.GetLogger() 14 | 15 | // A3Handover is an abstraction of A3 handover 16 | type A3Handover interface { 17 | // Start starts the A3 handover module 18 | Start() 19 | 20 | // GetInputChan returns the channel to push measurement 21 | GetInputChan() chan device.UE 22 | 23 | // GetOutputChan returns the channel to get handover event 24 | GetOutputChan() chan handover.A3HandoverDecision 25 | 26 | // PushMeasurementEventA3 pushes measurement to the input channel 27 | PushMeasurementEventA3(device.UE) 28 | } 29 | 30 | type a3Handover struct { 31 | a3HandoverHandler *handover.A3HandoverHandler 32 | } 33 | 34 | // NewA3Handover returns an A3 handover object 35 | func NewA3Handover() A3Handover { 36 | return &a3Handover{ 37 | a3HandoverHandler: handover.NewA3HandoverHandler(), 38 | } 39 | } 40 | 41 | func (h *a3Handover) Start() { 42 | logA3ho.Info("A3 handover handler starting") 43 | go h.a3HandoverHandler.Run() 44 | } 45 | 46 | func (h *a3Handover) GetInputChan() chan device.UE { 47 | return h.a3HandoverHandler.Chans.InputChan 48 | } 49 | 50 | func (h *a3Handover) GetOutputChan() chan handover.A3HandoverDecision { 51 | return h.a3HandoverHandler.Chans.OutputChan 52 | } 53 | 54 | func (h *a3Handover) PushMeasurementEventA3(ue device.UE) { 55 | h.a3HandoverHandler.Chans.InputChan <- ue 56 | } 57 | -------------------------------------------------------------------------------- /pkg/handover/handover.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package handover 6 | 7 | import ( 8 | "context" 9 | "github.com/onosproject/onos-lib-go/pkg/logging" 10 | "github.com/onosproject/ran-simulator/pkg/store/cells" 11 | "github.com/onosproject/ran-simulator/pkg/store/ues" 12 | "github.com/onosproject/rrm-son-lib/pkg/handover" 13 | "github.com/onosproject/rrm-son-lib/pkg/model/device" 14 | ) 15 | 16 | var logHoCtrl = logging.GetLogger("handover", "controller") 17 | 18 | // NewHOController returns the hanover controller 19 | func NewHOController(hoType HOType, cellStore cells.Store, ueStore ues.Store) HOController { 20 | return &hoController{ 21 | hoType: hoType, 22 | cellStore: cellStore, 23 | ueStore: ueStore, 24 | inputChan: make(chan device.UE), 25 | outputChan: make(chan handover.A3HandoverDecision), 26 | } 27 | } 28 | 29 | // HOController is an abstraction of the handover controller 30 | type HOController interface { 31 | // Start starts handover controller 32 | Start(ctx context.Context) 33 | 34 | // GetInputChan returns input channel 35 | GetInputChan() chan device.UE 36 | 37 | // GetOutputChan returns output channel 38 | GetOutputChan() chan handover.A3HandoverDecision 39 | } 40 | 41 | // HOType is the type of hanover - currently it is string 42 | // ToDo: define enumerated handover type into rrm-son-lib 43 | type HOType string 44 | 45 | type hoController struct { 46 | cellStore cells.Store 47 | ueStore ues.Store 48 | hoType HOType 49 | inputChan chan device.UE 50 | outputChan chan handover.A3HandoverDecision 51 | } 52 | 53 | func (h *hoController) Start(ctx context.Context) { 54 | switch h.hoType { 55 | case "A3": 56 | h.startA3HandoverHandler(ctx) 57 | } 58 | } 59 | 60 | func (h *hoController) startA3HandoverHandler(ctx context.Context) { 61 | logHoCtrl.Info("Handover controller starting with A3HandoveHandler") 62 | handler := NewA3Handover() 63 | 64 | go handler.Start() 65 | // for input 66 | go h.forwardReportToA3HandoverHandler(handler) 67 | //for output 68 | go h.forwardHandoverDecision(handler) 69 | } 70 | 71 | func (h *hoController) forwardReportToA3HandoverHandler(handler A3Handover) { 72 | for ue := range h.inputChan { 73 | logHoCtrl.Debugf("[input] Measurement report for HO decision: %v", ue) 74 | handler.PushMeasurementEventA3(ue) 75 | } 76 | } 77 | 78 | func (h *hoController) forwardHandoverDecision(handler A3Handover) { 79 | for hoDecision := range handler.GetOutputChan() { 80 | logHoCtrl.Debugf("[output] Handover decision: %v", hoDecision) 81 | h.outputChan <- hoDecision 82 | } 83 | } 84 | 85 | func (h *hoController) GetInputChan() chan device.UE { 86 | return h.inputChan 87 | } 88 | 89 | func (h *hoController) GetOutputChan() chan handover.A3HandoverDecision { 90 | return h.outputChan 91 | } 92 | -------------------------------------------------------------------------------- /pkg/measurement/eventa3.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package measurement 6 | 7 | import ( 8 | "github.com/onosproject/onos-lib-go/pkg/logging" 9 | "github.com/onosproject/rrm-son-lib/pkg/measurement" 10 | "github.com/onosproject/rrm-son-lib/pkg/model/device" 11 | ) 12 | 13 | var logEventA3 = logging.GetLogger("measurement", "eventa3") 14 | 15 | // MeasEventA3 is an abstraction of measurement Event A3 16 | type MeasEventA3 interface { 17 | 18 | // Start starts the Event A3 module 19 | Start() 20 | 21 | // GetInputChan returns the channel to push all measurements 22 | GetInputChan() chan device.UE 23 | 24 | // GetOutputChan returns the channel to get measurements for Event A3 25 | GetOutputChan() chan device.UE 26 | 27 | // PushMeasurement pushes measurements to MeasEventA3 handler 28 | PushMeasurement(device.UE) 29 | } 30 | 31 | type measEventA3 struct { 32 | eventA3Handler *measurement.MeasEventA3Handler 33 | } 34 | 35 | // NewMeasEventA3 returns the measurement Event A3 object 36 | func NewMeasEventA3() MeasEventA3 { 37 | return &measEventA3{ 38 | eventA3Handler: measurement.NewMeasEventA3Handler(), 39 | } 40 | } 41 | 42 | func (m *measEventA3) Start() { 43 | logEventA3.Info("Measurement event A3 handler starting") 44 | go m.eventA3Handler.Run() 45 | } 46 | 47 | func (m *measEventA3) GetInputChan() chan device.UE { 48 | return m.eventA3Handler.Chans.InputChan 49 | } 50 | 51 | func (m *measEventA3) GetOutputChan() chan device.UE { 52 | return m.eventA3Handler.Chans.OutputChan 53 | } 54 | 55 | func (m *measEventA3) PushMeasurement(ue device.UE) { 56 | m.eventA3Handler.Chans.InputChan <- ue 57 | } 58 | -------------------------------------------------------------------------------- /pkg/measurement/measurement.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package measurement 6 | 7 | import ( 8 | "context" 9 | "github.com/onosproject/onos-lib-go/pkg/logging" 10 | "github.com/onosproject/ran-simulator/pkg/model" 11 | "github.com/onosproject/ran-simulator/pkg/store/cells" 12 | "github.com/onosproject/ran-simulator/pkg/store/ues" 13 | "github.com/onosproject/rrm-son-lib/pkg/model/device" 14 | ) 15 | 16 | var logMeasCtrl = logging.GetLogger("measurement", "controller") 17 | 18 | // NewMeasController returns the measurement controller object 19 | func NewMeasController(measType MeasEventType, cellStore cells.Store, ueStore ues.Store) MeasController { 20 | return &measController{ 21 | measType: measType, 22 | cellStore: cellStore, 23 | ueStore: ueStore, 24 | inputChan: make(chan *model.UE), 25 | outputChan: make(chan device.UE), 26 | } 27 | } 28 | 29 | // MeasController is an abstraction of the measurement controller 30 | type MeasController interface { 31 | // Start starts measurement controller 32 | Start(ctx context.Context) 33 | 34 | // GetInputChan returns input channel 35 | GetInputChan() chan *model.UE 36 | 37 | // GetOutputChan returns output channel 38 | GetOutputChan() chan device.UE 39 | } 40 | 41 | // MeasEventType is the type for measurement event - currently it is string 42 | // ToDo: define enumerated measurement type into rrm-son-lib 43 | type MeasEventType string 44 | 45 | type measController struct { 46 | cellStore cells.Store 47 | ueStore ues.Store 48 | measType MeasEventType 49 | inputChan chan *model.UE 50 | outputChan chan device.UE 51 | } 52 | 53 | func (m *measController) Start(ctx context.Context) { 54 | switch m.measType { 55 | case "EventA3": 56 | m.startMeasEventA3Handler(ctx) 57 | } 58 | } 59 | 60 | func (m *measController) startMeasEventA3Handler(ctx context.Context) { 61 | logMeasCtrl.Info("Measurement controller starting with EventA3Handler") 62 | handler := NewMeasEventA3() 63 | converter := NewMeasReportConverter(m.cellStore, m.ueStore) 64 | 65 | go handler.Start() 66 | // for input 67 | go m.forwardReportToEventA3Handler(ctx, handler, converter) 68 | // for output 69 | go m.forwardReportFromEventA3Handler(handler) 70 | } 71 | 72 | func (m *measController) forwardReportToEventA3Handler(ctx context.Context, handler MeasEventA3, converter MeasReportConverter) { 73 | for ue := range m.inputChan { 74 | logMeasCtrl.Debugf("[input] Measurement report to Event A3 handler: %v", *ue) 75 | report := converter.Convert(ctx, ue) 76 | handler.PushMeasurement(report) 77 | } 78 | } 79 | 80 | func (m *measController) forwardReportFromEventA3Handler(handler MeasEventA3) { 81 | for report := range handler.GetOutputChan() { 82 | logMeasCtrl.Debugf("[output] Measurement report for Event A3: %v", report) 83 | m.outputChan <- report 84 | } 85 | } 86 | 87 | func (m *measController) GetInputChan() chan *model.UE { 88 | return m.inputChan 89 | } 90 | 91 | func (m *measController) GetOutputChan() chan device.UE { 92 | return m.outputChan 93 | } 94 | -------------------------------------------------------------------------------- /pkg/mobility/driver_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | //go:build !race 6 | // +build !race 7 | 8 | package mobility 9 | 10 | import ( 11 | "context" 12 | "fmt" 13 | "github.com/onosproject/ran-simulator/pkg/model" 14 | "github.com/onosproject/ran-simulator/pkg/store/cells" 15 | "github.com/onosproject/ran-simulator/pkg/store/event" 16 | "github.com/onosproject/ran-simulator/pkg/store/nodes" 17 | "github.com/onosproject/ran-simulator/pkg/store/routes" 18 | "github.com/onosproject/ran-simulator/pkg/store/ues" 19 | "github.com/stretchr/testify/assert" 20 | "testing" 21 | "time" 22 | ) 23 | 24 | func TestDriver(t *testing.T) { 25 | m := &model.Model{} 26 | err := model.LoadConfig(m, "../model/test") 27 | assert.NoError(t, err) 28 | 29 | ns := nodes.NewNodeRegistry(m.Nodes) 30 | cs := cells.NewCellRegistry(m.Cells, ns) 31 | us := ues.NewUERegistry(1, cs, "random") 32 | rs := routes.NewRouteRegistry() 33 | 34 | ctx := context.TODO() 35 | ch := make(chan event.Event) 36 | err = us.Watch(ctx, ch, ues.WatchOptions{Replay: true}) 37 | assert.NoError(t, err) 38 | 39 | e := <-ch 40 | ue := e.Value.(*model.UE) 41 | 42 | route := &model.Route{ 43 | IMSI: ue.IMSI, 44 | Points: []*model.Coordinate{{Lat: 50.0001, Lng: 0.0000}, {Lat: 50.0000, Lng: 0.0000}, {Lat: 50.0000, Lng: 0.0002}}, 45 | SpeedAvg: 40000.0, 46 | } 47 | err = rs.Add(ctx, route) 48 | assert.NoError(t, err) 49 | 50 | driver := NewMobilityDriver(cs, rs, us, "", "local", 15, false, false) 51 | tickUnit = time.Millisecond // For testing 52 | driver.Start(ctx) 53 | 54 | c := 0 55 | for e = range ch { 56 | ue = e.Value.(*model.UE) 57 | fmt.Printf("%v: %v\n", ue.Location, ue.Heading) 58 | c = c + 1 59 | if c > 10 { 60 | assert.Equal(t, 50.0, ue.Location.Lat) 61 | assert.Equal(t, 0.0, ue.Location.Lng) 62 | assert.Equal(t, uint32(180), ue.Heading) 63 | break 64 | } else if c == 6 { 65 | assert.Equal(t, uint32(270), ue.Heading) 66 | } 67 | } 68 | 69 | driver.Stop() 70 | } 71 | 72 | func TestRouteGeneration(t *testing.T) { 73 | m := &model.Model{} 74 | err := model.LoadConfig(m, "../utils/honeycomb/sample") 75 | assert.NoError(t, err) 76 | 77 | ns := nodes.NewNodeRegistry(m.Nodes) 78 | cs := cells.NewCellRegistry(m.Cells, ns) 79 | us := ues.NewUERegistry(1, cs, "random") 80 | rs := routes.NewRouteRegistry() 81 | 82 | ctx := context.TODO() 83 | us.SetUECount(ctx, 100) 84 | assert.Equal(t, 100, us.Len(ctx)) 85 | 86 | driver := NewMobilityDriver(cs, rs, us, "", "local", 15, false, false) 87 | driver.GenerateRoutes(ctx, 30000, 160000, 20000, nil, false) 88 | assert.Equal(t, 100, rs.Len(ctx)) 89 | 90 | ch := make(chan event.Event) 91 | err = us.Watch(ctx, ch, ues.WatchOptions{Replay: true}) 92 | assert.NoError(t, err) 93 | 94 | tickUnit = time.Millisecond 95 | driver.Start(ctx) 96 | 97 | c := 0 98 | for e := range ch { 99 | ue := e.Value.(*model.UE) 100 | //fmt.Printf("%v: %v\n", ue.Location, ue.Heading) 101 | assert.True(t, 52.41 < ue.Location.Lat && ue.Location.Lat < 52.57, "UE latitude is out of range") 102 | assert.True(t, 13.29 < ue.Location.Lng && ue.Location.Lng < 13.52, "UE longitude is out of range") 103 | c = c + 1 104 | if c > 500 { 105 | break 106 | } 107 | } 108 | 109 | driver.Stop() 110 | } 111 | -------------------------------------------------------------------------------- /pkg/mobility/signal.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package mobility 6 | 7 | import ( 8 | "github.com/onosproject/ran-simulator/pkg/model" 9 | "github.com/onosproject/ran-simulator/pkg/utils" 10 | "math" 11 | ) 12 | 13 | // powerFactor relates power to distance in decimal degrees 14 | const powerFactor = 0.001 15 | 16 | // StrengthAtLocation returns the signal strength at location relative to the specified cell. 17 | func StrengthAtLocation(coord model.Coordinate, cell model.Cell) float64 { 18 | distAtt := distanceAttenuation(coord, cell) 19 | angleAtt := angleAttenuation(coord, cell) 20 | pathLoss := getPathLoss(coord, cell) 21 | return cell.TxPowerDB + distAtt + angleAtt - pathLoss 22 | } 23 | 24 | // distanceAttenuation is the antenna Gain as a function of the dist 25 | // a very rough approximation to take in to account the width of 26 | // the antenna beam. A 120° wide beam with 30° height will span ≅ 2x0.5 = 1 steradians 27 | // A 60° wide beam will be half that and so will have double the gain 28 | // https://en.wikipedia.org/wiki/Sector_antenna 29 | // https://en.wikipedia.org/wiki/Steradian 30 | func distanceAttenuation(coord model.Coordinate, cell model.Cell) float64 { 31 | latDist := coord.Lat - cell.Sector.Center.Lat 32 | realLngDist := (coord.Lng - cell.Sector.Center.Lng) / utils.AspectRatio(cell.Sector.Center.Lat) 33 | r := math.Hypot(latDist, realLngDist) 34 | gain := 120.0 / float64(cell.Sector.Arc) 35 | return 10 * math.Log10(gain*math.Sqrt(powerFactor/r)) 36 | } 37 | 38 | // angleAttenuation is the attenuation of power reaching a UE due to its 39 | // position off the centre of the beam in dB 40 | // It is an approximation of the directivity of the antenna 41 | // https://en.wikipedia.org/wiki/Radiation_pattern 42 | // https://en.wikipedia.org/wiki/Sector_antenna 43 | func angleAttenuation(coord model.Coordinate, cell model.Cell) float64 { 44 | azRads := utils.AzimuthToRads(float64(cell.Sector.Azimuth)) 45 | pointRads := math.Atan2(coord.Lat-cell.Sector.Center.Lat, coord.Lng-cell.Sector.Center.Lng) 46 | angularOffset := math.Abs(azRads - pointRads) 47 | angleScaling := float64(cell.Sector.Arc) / 120.0 // Compensate for narrower beams 48 | 49 | // We just use a simple linear formula 0 => no loss 50 | // 33° => -3dB for a 120° sector according to [2] 51 | // assume this is 1:1 rads:attenuation e.g. 0.50 rads = 0.5 = -3dB attenuation 52 | //return 10 * math.Log10(1-(angularOffset/math.Pi/angleScaling)) 53 | return -math.Min(12*math.Pow((angularOffset/(math.Pi*2/3)/angleScaling), 2), 30) 54 | } 55 | 56 | func getPathLoss(coord model.Coordinate, cell model.Cell) float64 { 57 | return getFreeSpacePathLoss(coord, cell) 58 | } 59 | 60 | func getFreeSpacePathLoss(coord model.Coordinate, cell model.Cell) float64 { 61 | distanceKM := getEuclianDistanceFromGPS(coord, cell) 62 | // Assuming we're using CBRS frequency 3.6 GHz 63 | // 92.45 is the constant value of 20 * log10(4*pi / c) in Kilometer scale 64 | pathLoss := 20*math.Log10(distanceKM) + 20*math.Log10(3.6) + 92.45 65 | return pathLoss 66 | } 67 | 68 | func getEuclianDistanceFromGPS(coord model.Coordinate, cell model.Cell) float64 { 69 | earthRadius := 6378.137 70 | dLat := coord.Lat*math.Pi/180 - cell.Sector.Center.Lat*math.Pi/180 71 | dLng := coord.Lng*math.Pi/180 - cell.Sector.Center.Lng*math.Pi/180 72 | a := math.Sin(dLat/2)*math.Sin(dLat/2) + math.Cos(coord.Lat*math.Pi/180)*math.Cos(cell.Sector.Center.Lat*math.Pi/180)* 73 | math.Sin(dLng/2)*math.Sin(dLng/2) 74 | c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a)) 75 | return earthRadius * c 76 | } 77 | -------------------------------------------------------------------------------- /pkg/model/layout.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package model 6 | 7 | // MapLayout represents information required for geo-map visualizations 8 | type MapLayout struct { 9 | Center Coordinate `mapstructure:"center"` 10 | Zoom float32 `mapstructure:"zoom"` 11 | LocationsScale float32 `mapstructure:"locationsScale"` 12 | FadeMap bool `mapstructure:"fade"` 13 | ShowRoutes bool `mapstructure:"showRoutes"` 14 | ShowPower bool `mapstructure:"showPower"` 15 | } 16 | -------------------------------------------------------------------------------- /pkg/model/load.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package model 6 | 7 | import ( 8 | "bytes" 9 | 10 | "github.com/onosproject/onos-api/go/onos/ransim/types" 11 | "github.com/onosproject/onos-lib-go/pkg/logging" 12 | "github.com/spf13/viper" 13 | ) 14 | 15 | const configDir = ".onos" 16 | 17 | var log = logging.GetLogger() 18 | 19 | // ViperConfigure Sets up viper for unmarshalling configuration file 20 | func ViperConfigure(configname string) { 21 | // Set the file type of the configurations file 22 | viper.SetConfigType("yaml") 23 | 24 | // Set the file name of the configurations file 25 | viper.SetConfigName(configname) 26 | 27 | // Set the path to look for the configurations file 28 | viper.AddConfigPath("./" + configDir + "/config") 29 | viper.AddConfigPath("$HOME/" + configDir + "/config") 30 | viper.AddConfigPath("/etc/onos/config") 31 | viper.AddConfigPath(".") 32 | } 33 | 34 | // LoadConfig Loads model with data in configuration yaml file 35 | func LoadConfig(model *Model, configname string) error { 36 | var err error 37 | 38 | ViperConfigure(configname) 39 | 40 | if err := viper.ReadInConfig(); err != nil { 41 | log.Errorf("Unable to read %s config: %v", configname, err) 42 | return err 43 | } 44 | 45 | err = viper.Unmarshal(model) 46 | 47 | // Convert the MCC-MNC format into numeric PLMNID 48 | model.PlmnID = types.PlmnIDFromString(model.Plmn) 49 | 50 | // initialize neighbor's Ocn value - for mlb/handover 51 | for k, v := range model.Cells { 52 | v.MeasurementParams.NCellIndividualOffsets = make(map[types.NCGI]int32) 53 | for _, n := range v.Neighbors { 54 | v.MeasurementParams.NCellIndividualOffsets[n] = 0 55 | } 56 | model.Cells[k] = v 57 | } 58 | 59 | return err 60 | } 61 | 62 | // Load the model configuration. 63 | func Load(model *Model, modelName string) error { 64 | return LoadConfig(model, modelName) 65 | } 66 | 67 | // LoadConfigFromBytes Loads model with data in configuration yaml file 68 | func LoadConfigFromBytes(model *Model, modelData []byte) error { 69 | var err error 70 | viper.SetConfigType("yaml") 71 | 72 | if err := viper.ReadConfig(bytes.NewBuffer(modelData)); err != nil { 73 | log.Errorf("Unable to read %s config: %v", modelData, err) 74 | return err 75 | } 76 | 77 | err = viper.Unmarshal(model) 78 | 79 | // Convert the MCC-MNC format into numeric PLMNID 80 | model.PlmnID = types.PlmnIDFromString(model.Plmn) 81 | 82 | // initialize neighbor's Ocn value - for mlb/handover 83 | for k, v := range model.Cells { 84 | v.MeasurementParams.NCellIndividualOffsets = make(map[types.NCGI]int32) 85 | for _, n := range v.Neighbors { 86 | v.MeasurementParams.NCellIndividualOffsets[n] = 0 87 | } 88 | model.Cells[k] = v 89 | } 90 | log.Infof("routeEndPoints: %v", model.RouteEndPoints) 91 | return err 92 | } 93 | -------------------------------------------------------------------------------- /pkg/model/model_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package model 6 | 7 | import ( 8 | "github.com/onosproject/onos-api/go/onos/ransim/types" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | func TestModel(t *testing.T) { 15 | model := &Model{} 16 | err := LoadConfig(model, "test") 17 | assert.NoError(t, err) 18 | t.Log(model) 19 | assert.Equal(t, 2, len(model.Controllers)) 20 | assert.Equal(t, 2, len(model.Nodes)) 21 | assert.Equal(t, 4, len(model.Cells)) 22 | assert.Equal(t, 36421, model.Controllers["controller1"].Port) 23 | assert.Equal(t, 36421, model.Controllers["controller2"].Port) 24 | assert.Equal(t, "1.0.0", model.ServiceModels["kpm"].Version) 25 | assert.Equal(t, 3, model.ServiceModels["rc"].ID) 26 | assert.Equal(t, 2, model.ServiceModels["ni"].ID) 27 | assert.Equal(t, uint(12), model.UECount) 28 | assert.Equal(t, "314628", model.Plmn) 29 | assert.Equal(t, types.PlmnID(0x314628), model.PlmnID) 30 | 31 | assert.Equal(t, types.NCGI(84325717761), model.Cells["cell3"].NCGI) 32 | assert.Equal(t, 2, len(model.Nodes["node1"].Cells)) 33 | assert.Equal(t, 44.0, model.Cells["cell3"].Sector.Center.Lat) 34 | 35 | assert.Equal(t, true, model.MapLayout.FadeMap) 36 | assert.Equal(t, 45.0, model.MapLayout.Center.Lat) 37 | } 38 | -------------------------------------------------------------------------------- /pkg/model/test.yaml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | layout: 6 | center: 7 | lat: 45.00 8 | lng: -30.00 9 | zoom: 0.8 10 | locationsScale: 1.0 11 | fade: true 12 | showRoutes: true 13 | showPower: true 14 | 15 | nodes: 16 | node1: 17 | gnbid: 144470 18 | controllers: 19 | - controller1 20 | servicemodels: 21 | - kpm 22 | - rc 23 | cells: 24 | - 84325717505 25 | - 84325717506 26 | 27 | node2: 28 | gnbid: 144471 29 | controllers: 30 | - controller2 31 | servicemodels: 32 | - kpm 33 | cells: 34 | - 84325717761 35 | - 84325717762 36 | 37 | cells: 38 | cell1: 39 | ncgi: 84325717505 40 | sector: 41 | center: 42 | lat: 46.00 43 | lng: 29.00 44 | arc: 180.0 45 | azimuth: 0.0 46 | color: red 47 | txpowerdb: 30 48 | measurementParams: 49 | timeToTrigger: 0 50 | frequencyOffset: 0 51 | pcellIndividualOffset: 0 52 | ncellIndividualOffsets: 53 | 84325717506: 0 54 | 84325717761: 0 55 | 84325717762: 0 56 | hysteresis: 0 57 | eventA3Params: 58 | a3Offset: 0 59 | reportOnLeave: false 60 | cell2: 61 | ncgi: 84325717506 62 | sector: 63 | center: 64 | lat: 46.00 65 | lng: 29.00 66 | arc: 180.0 67 | azimuth: 180.0 68 | color: blue 69 | txpowerdb: 30 70 | measurementParams: 71 | timeToTrigger: 0 72 | frequencyOffset: 0 73 | pcellIndividualOffset: 0 74 | ncellIndividualOffsets: 75 | 84325717505: 0 76 | 84325717761: 0 77 | 84325717762: 0 78 | hysteresis: 0 79 | eventA3Params: 80 | a3Offset: 0 81 | reportOnLeave: false 82 | cell3: 83 | ncgi: 84325717761 84 | sector: 85 | center: 86 | lat: 44.00 87 | lng: 31.00 88 | arc: 180.0 89 | azimuth: 0.0 90 | color: red 91 | txpowerdb: 30 92 | measurementParams: 93 | timeToTrigger: 0 94 | frequencyOffset: 0 95 | pcellIndividualOffset: 0 96 | ncellIndividualOffsets: 97 | 84325717505: 0 98 | 84325717506: 0 99 | 84325717762: 0 100 | hysteresis: 0 101 | eventA3Params: 102 | a3Offset: 0 103 | reportOnLeave: false 104 | cell4: 105 | ncgi: 84325717762 106 | sector: 107 | center: 108 | lat: 44.00 109 | lng: 31.00 110 | arc: 180.0 111 | azimuth: 180.0 112 | color: blue 113 | txpowerdb: 30 114 | measurementParams: 115 | timeToTrigger: 0 116 | frequencyOffset: 0 117 | pcellIndividualOffset: 0 118 | ncellIndividualOffsets: 119 | 84325717505: 0 120 | 84325717506: 0 121 | 84325717761: 0 122 | hysteresis: 0 123 | eventA3Params: 124 | a3Offset: 0 125 | reportOnLeave: false 126 | controllers: 127 | controller1: 128 | id: E2T 129 | address: onos-e2t 130 | port: 36421 131 | controller2: 132 | id: E2T 133 | address: onos-e2t 134 | port: 36421 135 | servicemodels: 136 | kpm: 137 | id: 1 138 | version: 1.0.0 139 | description: kpm service model 140 | ni: 141 | id: 2 142 | version: 1.0.0 143 | description: NI service model 144 | rc: 145 | id: 3 146 | version: 1.0.0 147 | description: RC service model 148 | ueCount: 12 149 | plmnID: 314628 150 | 151 | 152 | -------------------------------------------------------------------------------- /pkg/servicemodel/kpm2/defs.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package kpm2 6 | 7 | // MeasTypeName name of measurement type 8 | type MeasTypeName int 9 | 10 | const ( 11 | PDUSessionSetupReq MeasTypeName = iota 12 | 13 | PDUSessionSetupSucc 14 | 15 | PDUSessionSetupFail 16 | 17 | PrbUsedDL 18 | 19 | PrbUsedUL 20 | 21 | PdcpPduVolumeDL 22 | 23 | PdcpPduVolumeUL 24 | 25 | PdcpRatePerPRBDL 26 | 27 | PdcpRatePerPRBUL 28 | // RRCConnEstabAttSum total number of RRC connection establishment attempts 29 | RRCConnEstabAttSum 30 | // RRCConnEstabSuccSum total number of successful RRC Connection establishments 31 | RRCConnEstabSuccSum 32 | // RRCConnReEstabAttSum total number of RRC connection re-establishment attempts 33 | RRCConnReEstabAttSum 34 | // RRCConnReEstabAttreconfigFail total number of RRC connection re-establishment attempts due to reconfiguration failure 35 | RRCConnReEstabAttreconfigFail 36 | // RRCConnReEstabAttHOFail total number of RRC connection re-establishment attempts due to Handover failure 37 | RRCConnReEstabAttHOFail 38 | // RRCConnReEstabAttOther total number of RRC connection re-establishment attempts due to Other reasons 39 | RRCConnReEstabAttOther 40 | // RRCConnAvg the mean number of users in RRC connected mode during each granularity period. 41 | RRCConnAvg 42 | // RRCConnMax the max number of users in RRC connected mode during each granularity period. 43 | RRCConnMax 44 | ) 45 | 46 | func (m MeasTypeName) String() string { 47 | return [...]string{ 48 | "PDUSessionSetupReq", 49 | "PDUSessionSetupSucc", 50 | "PDUSessionSetupFail", 51 | "PrbUsedDL", 52 | "PrbUsedUL", 53 | "PdcpPduVolumeDL", 54 | "PdcpPduVolumeUL", 55 | "PdcpRatePerPRBDL", 56 | "PdcpRatePerPRBUL", 57 | "RRC.ConnEstabAtt.Sum", 58 | "RRC.ConnEstabSucc.Sum", 59 | "RRC.ConnReEstabAtt.Sum", 60 | "RRC.ConnReEstabAtt.reconfigFail", 61 | "RRC.ConnReEstabAtt.HOFail", 62 | "RRC.ConnReEstabAtt.Other", 63 | "RRC.Conn.Avg", 64 | "RRC.Conn.Max"}[m] 65 | } 66 | 67 | // MeasType meas type 68 | type MeasType struct { 69 | measTypeName MeasTypeName 70 | measTypeID int32 71 | } 72 | 73 | var measTypes = []MeasType{ 74 | { 75 | measTypeName: PDUSessionSetupReq, 76 | measTypeID: 1, 77 | }, 78 | { 79 | measTypeName: PDUSessionSetupSucc, 80 | measTypeID: 2, 81 | }, 82 | { 83 | measTypeName: PDUSessionSetupFail, 84 | measTypeID: 3, 85 | }, 86 | { 87 | measTypeName: PrbUsedDL, 88 | measTypeID: 4, 89 | }, 90 | { 91 | measTypeName: PrbUsedUL, 92 | measTypeID: 5, 93 | }, 94 | { 95 | measTypeName: PdcpPduVolumeDL, 96 | measTypeID: 6, 97 | }, 98 | { 99 | measTypeName: PdcpPduVolumeUL, 100 | measTypeID: 7, 101 | }, 102 | { 103 | measTypeName: PdcpRatePerPRBDL, 104 | measTypeID: 8, 105 | }, 106 | { 107 | measTypeName: PdcpRatePerPRBUL, 108 | measTypeID: 9, 109 | }, 110 | { 111 | measTypeName: RRCConnEstabAttSum, 112 | measTypeID: 10, 113 | }, 114 | { 115 | measTypeName: RRCConnEstabSuccSum, 116 | measTypeID: 11, 117 | }, 118 | { 119 | measTypeName: RRCConnReEstabAttSum, 120 | measTypeID: 12, 121 | }, 122 | { 123 | measTypeName: RRCConnReEstabAttreconfigFail, 124 | measTypeID: 13, 125 | }, 126 | { 127 | measTypeName: RRCConnReEstabAttHOFail, 128 | measTypeID: 14, 129 | }, 130 | { 131 | measTypeName: RRCConnReEstabAttOther, 132 | measTypeID: 15, 133 | }, 134 | { 135 | measTypeName: RRCConnAvg, 136 | measTypeID: 16, 137 | }, 138 | { 139 | measTypeName: RRCConnMax, 140 | measTypeID: 17, 141 | }, 142 | } 143 | -------------------------------------------------------------------------------- /pkg/servicemodel/kpm2/util.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package kpm2 6 | 7 | import ( 8 | e2smkpmv2sm "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_kpm_v2_go/servicemodel" 9 | e2smkpmv2 "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_kpm_v2_go/v2/e2sm-kpm-v2-go" 10 | v2 "github.com/onosproject/onos-e2t/api/e2ap/v2" 11 | e2appducontents "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-pdu-contents" 12 | e2aptypes "github.com/onosproject/onos-e2t/pkg/southbound/e2ap/types" 13 | "google.golang.org/protobuf/proto" 14 | ) 15 | 16 | func (sm *Client) getActionDefinition(actionList []*e2appducontents.RicactionToBeSetupItemIes, ricActionsAccepted []*e2aptypes.RicActionID) ([]*e2smkpmv2.E2SmKpmActionDefinition, error) { 17 | var actionDefinitions []*e2smkpmv2.E2SmKpmActionDefinition 18 | for _, action := range actionList { 19 | for _, acceptedActionID := range ricActionsAccepted { 20 | if action.GetValue().GetRicactionToBeSetupItem().GetRicActionId().GetValue() == int32(*acceptedActionID) { 21 | actionDefinitionBytes := action.GetValue().GetRicactionToBeSetupItem().GetRicActionDefinition().GetValue() 22 | var kpm2ServiceModel e2smkpmv2sm.Kpm2ServiceModel 23 | 24 | actionDefinitionProtoBytes, err := kpm2ServiceModel.ActionDefinitionASN1toProto(actionDefinitionBytes) 25 | if err != nil { 26 | log.Warn(err) 27 | return nil, err 28 | } 29 | 30 | actionDefinition := &e2smkpmv2.E2SmKpmActionDefinition{} 31 | err = proto.Unmarshal(actionDefinitionProtoBytes, actionDefinition) 32 | if err != nil { 33 | log.Warn(err) 34 | return nil, err 35 | } 36 | 37 | actionDefinitions = append(actionDefinitions, actionDefinition) 38 | 39 | } 40 | } 41 | } 42 | return actionDefinitions, nil 43 | } 44 | 45 | // getReportPeriod extracts report period 46 | func (sm *Client) getReportPeriod(request *e2appducontents.RicsubscriptionRequest) (int64, error) { 47 | var eventTriggerAsnBytes []byte 48 | for _, v := range request.GetProtocolIes() { 49 | if v.Id == int32(v2.ProtocolIeIDRicsubscriptionDetails) { 50 | eventTriggerAsnBytes = v.GetValue().GetRicsubscriptionDetails().GetRicEventTriggerDefinition().GetValue() 51 | break 52 | } 53 | } 54 | var kpm2ServiceModel e2smkpmv2sm.Kpm2ServiceModel 55 | eventTriggerProtoBytes, err := kpm2ServiceModel.EventTriggerDefinitionASN1toProto(eventTriggerAsnBytes) 56 | if err != nil { 57 | return 0, err 58 | } 59 | eventTriggerDefinition := &e2smkpmv2.E2SmKpmEventTriggerDefinition{} 60 | err = proto.Unmarshal(eventTriggerProtoBytes, eventTriggerDefinition) 61 | if err != nil { 62 | return 0, err 63 | } 64 | reportPeriod := eventTriggerDefinition.GetEventDefinitionFormats().GetEventDefinitionFormat1().GetReportingPeriod() 65 | return reportPeriod, nil 66 | } 67 | -------------------------------------------------------------------------------- /pkg/servicemodel/mho/a3.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package mho 6 | 7 | import ( 8 | "context" 9 | "github.com/onosproject/onos-api/go/onos/ransim/types" 10 | ransimtypes "github.com/onosproject/onos-api/go/onos/ransim/types" 11 | "github.com/onosproject/ran-simulator/pkg/store/subscriptions" 12 | subutils "github.com/onosproject/ran-simulator/pkg/utils/e2ap/subscription" 13 | "github.com/onosproject/rrm-son-lib/pkg/model/id" 14 | ) 15 | 16 | func (m *Mho) processEventA3MeasReport(ctx context.Context, subscription *subutils.Subscription) { 17 | log.Info("Start processing event a3 measurement report") 18 | subID := subscriptions.NewID(subscription.GetRicInstanceID(), subscription.GetReqID(), subscription.GetRanFuncID()) 19 | sub, err := m.ServiceModel.Subscriptions.Get(subID) 20 | if err != nil { 21 | log.Error(err) 22 | return 23 | } 24 | for { 25 | select { 26 | case report := <-m.ServiceModel.A3Chan: 27 | log.Debugf("received event a3 measurement report: %v", report) 28 | log.Debugf("Send upon-rcv-meas-report indication for cell ecgi:%d, IMSI:%s", 29 | report.UE.GetSCell().GetID().GetID().(id.ECGI), report.UE.GetID().String()) 30 | ecgi := report.UE.GetSCell().GetID().GetID().(id.ECGI) 31 | imsi := report.UE.GetID().GetID().(id.UEID).IMSI 32 | ue, err := m.ServiceModel.UEs.Get(ctx, types.IMSI(imsi)) 33 | if err != nil { 34 | log.Warn(err) 35 | continue 36 | } 37 | err = m.sendRicIndicationFormat1(ctx, ransimtypes.NCGI(ecgi), ue, subscription) 38 | if err != nil { 39 | log.Warn(err) 40 | continue 41 | } 42 | case <-sub.E2Channel.Context().Done(): 43 | sub.Ticker.Stop() 44 | return 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /pkg/servicemodel/mho/defs.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package mho 6 | 7 | const ( 8 | modelFullName = "ORAN-E2SM-MHO" 9 | version = "v2" 10 | modelOID = "1.3.6.1.4.1.53148.1.2.2.101" 11 | ) 12 | -------------------------------------------------------------------------------- /pkg/servicemodel/mho/periodic.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package mho 6 | 7 | import ( 8 | "context" 9 | "github.com/onosproject/ran-simulator/pkg/store/subscriptions" 10 | subutils "github.com/onosproject/ran-simulator/pkg/utils/e2ap/subscription" 11 | "time" 12 | ) 13 | 14 | func (m *Mho) reportPeriodicIndication(ctx context.Context, interval int32, subscription *subutils.Subscription) { 15 | log.Debugf("Starting periodic report with interval %d ms", interval) 16 | subID := subscriptions.NewID(subscription.GetRicInstanceID(), subscription.GetReqID(), subscription.GetRanFuncID()) 17 | intervalDuration := time.Duration(interval) 18 | sub, err := m.ServiceModel.Subscriptions.Get(subID) 19 | if err != nil { 20 | return 21 | } 22 | sub.Ticker = time.NewTicker(intervalDuration * time.Millisecond) 23 | for { 24 | select { 25 | case <-sub.Ticker.C: 26 | log.Debug("Sending periodic indication report for subscription:", sub.ID) 27 | err = m.sendRicIndication(ctx, subscription) 28 | if err != nil { 29 | log.Error("Failure sending indication message: ", err) 30 | } 31 | 32 | case <-sub.E2Channel.Context().Done(): 33 | sub.Ticker.Stop() 34 | return 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /pkg/servicemodel/mho/rrc.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package mho 6 | 7 | import ( 8 | "context" 9 | subutils "github.com/onosproject/ran-simulator/pkg/utils/e2ap/subscription" 10 | ) 11 | 12 | func (m *Mho) processRrcUpdate(ctx context.Context, subscription *subutils.Subscription) { 13 | log.Info("Start processing RRC updates") 14 | for update := range m.rrcUpdateChan { 15 | log.Debugf("Received RRC Update, IMSI:%v, GnbID:%v, NCGI:%v", update.IMSI, update.Cell.ID, update.Cell.NCGI) 16 | 17 | ue, err := m.ServiceModel.UEs.Get(ctx, update.IMSI) 18 | if err != nil { 19 | log.Warn(err) 20 | continue 21 | } 22 | err = m.sendRicIndicationFormat2(ctx, update.Cell.NCGI, ue, subscription) 23 | if err != nil { 24 | log.Warn(err) 25 | continue 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /pkg/servicemodel/rc/defs.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package rc 6 | 7 | const ( 8 | modelFullName = "ORAN-E2SM-RC-PRE" 9 | version = "v2" 10 | modelOID = "1.3.6.1.4.1.53148.1.2.2.100" 11 | ) 12 | -------------------------------------------------------------------------------- /pkg/servicemodel/rc/v1/defs.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022-present Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package v1 6 | 7 | const ( 8 | modelFullName = "ORAN-E2SM-RC" 9 | version = "v1" 10 | modelOID = "1.3.6.1.4.1.53148.1.1.2.3" 11 | ) 12 | 13 | const ( 14 | eventTriggerStyle1 = "Message Event" 15 | eventTriggerStyle2 = "Call Process Breakpoint" 16 | eventTriggerStyle3 = "E2 Node Information" 17 | controlStyleType3 = 3 18 | controlStyleType200 = 200 // for PCI use-case: since there is no style for PCI use-case, define a new style 19 | controlActionID1 = 1 20 | 21 | ricInsertIndicationIDForMHO = 1 22 | ricInsertStyleType3 = 3 23 | 24 | ricPolicyStyleType3 = 3 25 | ricPolicyStyleName = "Connected Mode Mobility Control" 26 | 27 | ricPolicyActionIDForMLB = 1 28 | ricPolicyActionNameForMLB = "Policy for Handover Control" 29 | ricActionDefinitionFormatTypeForMLB = 2 30 | ) 31 | 32 | // RAN parameter IDs 33 | const ( 34 | // PCIRANParameterID PCI RAN parameter ID 35 | PCIRANParameterID = 1 36 | // NCGIRANParameterID NCGI RAN parameter ID 37 | NCGIRANParameterID = 2 38 | // NS xApp Id 39 | NSRANParameterID = 3 40 | 41 | // TargetPrimaryCellIDRANParameterID Target Primary Cell ID RAN parameter ID 42 | TargetPrimaryCellIDRANParameterID = 1 43 | // TargetPrimaryCellIDRANParameterName Target Primary Cell ID RAN parameter Name 44 | TargetPrimaryCellIDRANParameterName = "Target Primary Cell ID" 45 | // TargetCellRANParameterID Choice of Target Cell RAN parameter ID 46 | TargetCellRANParameterID = 2 47 | // NRCellRANParameterID NR Cell RAN parameter ID 48 | NRCellRANParameterID = 3 49 | // NRCGIRANParameterID NR CGI RAN parameter ID 50 | NRCGIRANParameterID = 4 51 | // EUTRACellRANParameterID E-UTRA Cell RAN parameter ID 52 | EUTRACellRANParameterID = 5 53 | // EUTRACGIRANParameterID E-UTRA CGI RAN parameter ID 54 | EUTRACGIRANParameterID = 6 55 | 56 | // CellSpecificOffsetRANParameterID Ocn RAN parameter ID 57 | CellSpecificOffsetRANParameterID = 10201 58 | // CellSpecificOffsetRANParameterName Ocn RAN parameter name 59 | CellSpecificOffsetRANParameterName = "Cell Specific Offset" 60 | ) 61 | 62 | // UE Event IDs 63 | const ( 64 | A3MeasurementReportUEEventID = 2 65 | ) 66 | 67 | // Call Process Breakpoint 68 | const ( 69 | CallProcessTypeIDMobilityManagement = 3 70 | CallBreakpointIDHandoverPreparation = 1 71 | ) 72 | -------------------------------------------------------------------------------- /pkg/servicemodel/registry/id.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022-present Intel Corporation 2 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package registry 7 | 8 | // RanFunctionID Ran function ID 9 | type RanFunctionID int32 10 | 11 | // ModelOid service model OID 12 | type ModelOid string 13 | 14 | // TODO define them using standard Ran function IDs 15 | const ( 16 | 17 | // Internal 18 | Internal RanFunctionID = iota 19 | // Kpm 20 | Kpm 21 | // Ni 22 | Ni 23 | // Rcpre2 24 | Rcpre2 25 | // ORAN-E2SM-KPM version 2 26 | Kpm2 27 | // MHO 28 | Mho 29 | // O-RAN-E2SM-RC 30 | Rc 31 | ) 32 | -------------------------------------------------------------------------------- /pkg/servicemodel/registry/registry.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package registry 6 | 7 | import ( 8 | "sync" 9 | 10 | "github.com/onosproject/rrm-son-lib/pkg/handover" 11 | 12 | e2smtypes "github.com/onosproject/onos-api/go/onos/e2t/e2sm" 13 | 14 | "github.com/onosproject/ran-simulator/pkg/store/metrics" 15 | 16 | "github.com/onosproject/ran-simulator/pkg/store/cells" 17 | 18 | "github.com/onosproject/ran-simulator/pkg/store/nodes" 19 | "github.com/onosproject/ran-simulator/pkg/store/ues" 20 | 21 | "github.com/onosproject/ran-simulator/pkg/store/subscriptions" 22 | 23 | "github.com/onosproject/ran-simulator/pkg/model" 24 | 25 | e2aptypes "github.com/onosproject/onos-e2t/pkg/southbound/e2ap/types" 26 | "github.com/onosproject/onos-lib-go/pkg/errors" 27 | "github.com/onosproject/onos-lib-go/pkg/logging" 28 | "github.com/onosproject/ran-simulator/pkg/servicemodel" 29 | ) 30 | 31 | var log = logging.GetLogger("registry") 32 | 33 | // ServiceModelRegistry stores list of registered service models 34 | type ServiceModelRegistry struct { 35 | mu sync.RWMutex 36 | serviceModels map[RanFunctionID]ServiceModel 37 | ranFunctions e2aptypes.RanFunctions 38 | } 39 | 40 | // ServiceModel service model 41 | type ServiceModel struct { 42 | RanFunctionID RanFunctionID 43 | ModelName e2smtypes.ShortName 44 | Version string 45 | Description []byte // ASN1 bytes from Service Model 46 | Revision int 47 | OID ModelOid 48 | Client servicemodel.Client 49 | Node model.Node 50 | Model *model.Model 51 | Subscriptions *subscriptions.Subscriptions 52 | Nodes nodes.Store 53 | UEs ues.Store 54 | CellStore cells.Store 55 | MetricStore metrics.Store 56 | A3Chan chan handover.A3HandoverDecision 57 | } 58 | 59 | // NewServiceModelRegistry creates a service model registry 60 | func NewServiceModelRegistry() *ServiceModelRegistry { 61 | return &ServiceModelRegistry{ 62 | serviceModels: make(map[RanFunctionID]ServiceModel), 63 | ranFunctions: make(map[e2aptypes.RanFunctionID]e2aptypes.RanFunctionItem), 64 | } 65 | } 66 | 67 | // RegisterServiceModel registers a service model 68 | func (s *ServiceModelRegistry) RegisterServiceModel(sm ServiceModel) error { 69 | log.Info("Register Service Model:", sm.ModelName, ":", sm.RanFunctionID) 70 | s.mu.Lock() 71 | defer s.mu.Unlock() 72 | if _, exists := s.serviceModels[sm.RanFunctionID]; exists { 73 | return errors.New(errors.AlreadyExists, "the service model already registered") 74 | } 75 | 76 | ranFuncID := e2aptypes.RanFunctionID(sm.RanFunctionID) 77 | s.ranFunctions[ranFuncID] = e2aptypes.RanFunctionItem{ 78 | Description: sm.Description, 79 | Revision: e2aptypes.RanFunctionRevision(sm.Revision), 80 | OID: e2aptypes.RanFunctionOID(sm.OID), 81 | } 82 | s.serviceModels[sm.RanFunctionID] = sm 83 | 84 | return nil 85 | } 86 | 87 | // GetServiceModel finds and initialize service model interface pointer 88 | func (s *ServiceModelRegistry) GetServiceModel(id RanFunctionID) (ServiceModel, error) { 89 | s.mu.RLock() 90 | defer s.mu.RUnlock() 91 | sm, ok := s.serviceModels[id] 92 | if ok { 93 | return sm, nil 94 | } 95 | return ServiceModel{}, errors.New(errors.Unknown, "no service model implementation exists for ran function ID: ", id) 96 | } 97 | 98 | // GetServiceModels get all of the registered service models 99 | func (s *ServiceModelRegistry) GetServiceModels() map[RanFunctionID]ServiceModel { 100 | s.mu.RLock() 101 | defer s.mu.RUnlock() 102 | return s.serviceModels 103 | } 104 | 105 | // GetRanFunctions returns the list of registered ran functions 106 | func (s *ServiceModelRegistry) GetRanFunctions() e2aptypes.RanFunctions { 107 | return s.ranFunctions 108 | } 109 | -------------------------------------------------------------------------------- /pkg/servicemodel/registry/registry_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package registry 6 | 7 | import ( 8 | "context" 9 | "testing" 10 | 11 | "github.com/onosproject/ran-simulator/pkg/servicemodel" 12 | "github.com/stretchr/testify/assert" 13 | 14 | e2appducontents "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-pdu-contents" 15 | ) 16 | 17 | var _ servicemodel.Client = &mockServiceModel{} 18 | 19 | type mockServiceModel struct { 20 | t *testing.T 21 | } 22 | 23 | func (sm mockServiceModel) E2ConnectionUpdate(ctx context.Context, request *e2appducontents.E2ConnectionUpdate) (response *e2appducontents.E2ConnectionUpdateAcknowledge, failure *e2appducontents.E2ConnectionUpdateFailure, err error) { 24 | panic("implement me") 25 | } 26 | 27 | func (sm mockServiceModel) RICControl(ctx context.Context, request *e2appducontents.RiccontrolRequest) (response *e2appducontents.RiccontrolAcknowledge, failure *e2appducontents.RiccontrolFailure, err error) { 28 | panic("implement me") 29 | } 30 | 31 | func (sm mockServiceModel) RICSubscription(ctx context.Context, request *e2appducontents.RicsubscriptionRequest) (response *e2appducontents.RicsubscriptionResponse, failure *e2appducontents.RicsubscriptionFailure, err error) { 32 | sm.t.Log("Test Ric Subscription") 33 | return &e2appducontents.RicsubscriptionResponse{}, &e2appducontents.RicsubscriptionFailure{}, nil 34 | } 35 | 36 | func (sm mockServiceModel) RICSubscriptionDelete(ctx context.Context, request *e2appducontents.RicsubscriptionDeleteRequest) (response *e2appducontents.RicsubscriptionDeleteResponse, failure *e2appducontents.RicsubscriptionDeleteFailure, err error) { 37 | panic("implement me") 38 | } 39 | 40 | func TestRegisterServiceModel(t *testing.T) { 41 | 42 | registry := NewServiceModelRegistry() 43 | 44 | m := &mockServiceModel{ 45 | t: t, 46 | } 47 | 48 | testServiceModelConfig := ServiceModel{ 49 | RanFunctionID: Internal, 50 | Client: m, 51 | Description: []byte{0x01, 0x02, 0x03, 0x04}, 52 | Revision: 1, 53 | } 54 | 55 | if err := registry.RegisterServiceModel(testServiceModelConfig); err != nil { 56 | t.Fatalf("failed to register the service model") 57 | } 58 | 59 | sm, err := registry.GetServiceModel(Internal) 60 | if err != nil { 61 | t.Fatal("the service model does not exist", err) 62 | } 63 | 64 | testSm := sm 65 | 66 | _, _, err = testSm.Client.RICSubscription(context.Background(), &e2appducontents.RicsubscriptionRequest{}) 67 | assert.NoError(t, err) 68 | 69 | ranFunctions := registry.GetRanFunctions() 70 | assert.Equal(t, len(ranFunctions), 1) 71 | 72 | } 73 | -------------------------------------------------------------------------------- /pkg/servicemodel/servicemodel.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package servicemodel 6 | 7 | import e2 "github.com/onosproject/onos-e2t/pkg/protocols/e2ap" 8 | 9 | // Client service model client interface 10 | type Client interface { 11 | e2.ClientInterface 12 | } 13 | -------------------------------------------------------------------------------- /pkg/store/agents/store.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package agents 6 | 7 | import ( 8 | "github.com/onosproject/onos-lib-go/pkg/logging" 9 | 10 | "sync" 11 | 12 | "github.com/onosproject/onos-lib-go/pkg/errors" 13 | 14 | "github.com/onosproject/onos-api/go/onos/ransim/types" 15 | "github.com/onosproject/ran-simulator/pkg/e2agent" 16 | ) 17 | 18 | var log = logging.GetLogger() 19 | 20 | // E2Agents e2 agents 21 | type E2Agents struct { 22 | agents map[types.GnbID]e2agent.E2Agent 23 | mu sync.RWMutex 24 | } 25 | 26 | // NewStore creates a new e2 agents store 27 | func NewStore() *E2Agents { 28 | return &E2Agents{ 29 | agents: make(map[types.GnbID]e2agent.E2Agent), 30 | mu: sync.RWMutex{}, 31 | } 32 | } 33 | 34 | // Get gets an e2 agent 35 | func (e *E2Agents) Get(id types.GnbID) (e2agent.E2Agent, error) { 36 | log.Debug("Getting e2 agent with ID:", id) 37 | e.mu.RLock() 38 | defer e.mu.RUnlock() 39 | if val, ok := e.agents[id]; ok { 40 | return val, nil 41 | } 42 | return nil, errors.New(errors.NotFound, "e2 agent has not been found") 43 | } 44 | 45 | // Add adds an e2 agent 46 | func (e *E2Agents) Add(id types.GnbID, agent e2agent.E2Agent) error { 47 | log.Debug("Adding e2 agent with ID:", id) 48 | e.mu.Lock() 49 | defer e.mu.Unlock() 50 | if id == 0 { 51 | return errors.New(errors.Invalid, "E2 node ID cannot be empty or zero") 52 | } 53 | e.agents[id] = agent 54 | return nil 55 | 56 | } 57 | 58 | // Remove removes an e2 agent 59 | func (e *E2Agents) Remove(id types.GnbID) error { 60 | log.Debug("Removing e2 agent with ID:", id) 61 | e.mu.Lock() 62 | defer e.mu.Unlock() 63 | if id == 0 { 64 | return errors.New(errors.Invalid, "E2 node ID cannot be empty or zero") 65 | } 66 | delete(e.agents, id) 67 | return nil 68 | } 69 | 70 | // List list e2 agents 71 | func (e *E2Agents) List() (map[types.GnbID]e2agent.E2Agent, error) { 72 | return e.agents, nil 73 | } 74 | 75 | // Store e2 agents store interface 76 | type Store interface { 77 | // Add an e2 agent 78 | Add(types.GnbID, e2agent.E2Agent) error 79 | 80 | // Remove an e2 agent 81 | Remove(types.GnbID) error 82 | 83 | // List list all of the e2 agents 84 | List() (map[types.GnbID]e2agent.E2Agent, error) 85 | 86 | // Get gets an e2 agent 87 | Get(types.GnbID) (e2agent.E2Agent, error) 88 | } 89 | 90 | var _ Store = &E2Agents{} 91 | -------------------------------------------------------------------------------- /pkg/store/cells/cells_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package cells 6 | 7 | import ( 8 | "context" 9 | "os" 10 | "testing" 11 | 12 | "github.com/onosproject/onos-api/go/onos/ransim/types" 13 | "github.com/onosproject/ran-simulator/pkg/store/event" 14 | 15 | "github.com/onosproject/ran-simulator/pkg/store/nodes" 16 | 17 | "github.com/onosproject/ran-simulator/pkg/model" 18 | "github.com/stretchr/testify/assert" 19 | "gopkg.in/yaml.v2" 20 | ) 21 | 22 | func TestCells(t *testing.T) { 23 | m := model.Model{} 24 | bytes, err := os.ReadFile("../../model/test.yaml") 25 | assert.NoError(t, err) 26 | err = yaml.Unmarshal(bytes, &m) 27 | assert.NoError(t, err) 28 | t.Log(m) 29 | ctx := context.Background() 30 | 31 | cellStore := NewCellRegistry(m.Cells, nodes.NewNodeRegistry(m.Nodes)) 32 | ch := make(chan event.Event) 33 | err = cellStore.Watch(ctx, ch, WatchOptions{Replay: false, Monitor: false}) 34 | assert.NoError(t, err) 35 | cell, err := cellStore.Get(ctx, 84325717505) 36 | assert.NoError(t, err) 37 | assert.Equal(t, types.NCGI(84325717505), cell.NCGI) 38 | 39 | ecgi1 := types.NCGI(84325717507) 40 | cell1 := &model.Cell{ 41 | NCGI: ecgi1, 42 | Sector: model.Sector{Center: model.Coordinate{Lat: 46, Lng: 29}, Azimuth: 180, Arc: 180, Height: 30, Tilt: -10}, 43 | Color: "blue"} 44 | 45 | err = cellStore.Add(ctx, cell1) 46 | assert.NoError(t, err) 47 | 48 | cellEvent := <-ch 49 | assert.Equal(t, Created, cellEvent.Type) 50 | 51 | cell1, err = cellStore.Get(ctx, ecgi1) 52 | assert.NoError(t, err) 53 | assert.Equal(t, ecgi1, cell1.NCGI) 54 | 55 | _, err = cellStore.Delete(ctx, ecgi1) 56 | assert.NoError(t, err) 57 | cellEvent = <-ch 58 | assert.Equal(t, Deleted, cellEvent.Type) 59 | 60 | cellStore.Clear(ctx) 61 | ids, _ := cellStore.List(ctx) 62 | assert.Equal(t, 0, len(ids), "should be empty") 63 | } 64 | -------------------------------------------------------------------------------- /pkg/store/cells/types.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package cells 6 | 7 | // CellEvent a cell event 8 | type CellEvent int 9 | 10 | const ( 11 | // None none cell event 12 | None CellEvent = iota 13 | // Created created cell event 14 | Created 15 | // Updated updated cell event 16 | Updated 17 | // UpdatedNeighbors updated cell neighbors event 18 | UpdatedNeighbors 19 | // Deleted deleted cell event 20 | Deleted 21 | ) 22 | 23 | func (e CellEvent) String() string { 24 | return [...]string{"None", "Created", "Updated", "Deleted"}[e] 25 | } 26 | -------------------------------------------------------------------------------- /pkg/store/cells/utils.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package cells 6 | 7 | import ( 8 | "github.com/onosproject/onos-api/go/onos/ransim/types" 9 | ) 10 | 11 | func equalNeighbors(a, b []types.NCGI) bool { 12 | 13 | // If one is nil, the other must also be nil. 14 | if (a == nil) != (b == nil) { 15 | return false 16 | } 17 | 18 | if len(a) != len(b) { 19 | return false 20 | } 21 | 22 | for i := range a { 23 | if a[i] != b[i] { 24 | return false 25 | } 26 | } 27 | 28 | return true 29 | } 30 | -------------------------------------------------------------------------------- /pkg/store/connections/types.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package connections 6 | 7 | import ( 8 | e2 "github.com/onosproject/onos-e2t/pkg/protocols/e2ap" 9 | ) 10 | 11 | // ConnectionEvent a connection event 12 | type ConnectionEvent int 13 | 14 | const ( 15 | // None none connection event 16 | None ConnectionEvent = iota 17 | // Created created event 18 | Created 19 | // Updated updated connection event 20 | Updated 21 | // Deleted deleted connection event 22 | Deleted 23 | ) 24 | 25 | // String converts connection event to string 26 | func (e ConnectionEvent) String() string { 27 | return [...]string{"None", "Created", "Updated", "Deleted"}[e] 28 | } 29 | 30 | // ConnectionID consists of IP and port number of E2T instance 31 | type ConnectionID struct { 32 | ricIPAddress string 33 | ricPort uint64 34 | } 35 | 36 | // Phase channel phase 37 | type Phase int 38 | 39 | const ( 40 | // Open open phase 41 | Open Phase = iota 42 | 43 | // Closed closed state 44 | Closed 45 | ) 46 | 47 | // String return phase 48 | func (p Phase) String() string { 49 | return [...]string{"Open", "Closed"}[p] 50 | } 51 | 52 | // ConnectionStatus connection status 53 | type ConnectionStatus struct { 54 | Phase Phase 55 | State State 56 | } 57 | 58 | // State channel state 59 | type State int 60 | 61 | const ( 62 | 63 | // Connecting connecting state 64 | Connecting State = iota 65 | 66 | // Connected connected state 67 | Connected 68 | 69 | // Configuring configuring state 70 | Configuring 71 | 72 | // Configured configured state 73 | Configured 74 | 75 | // Disconnecting disconnecting state 76 | Disconnecting 77 | 78 | // Disconnected disconnected state 79 | Disconnected 80 | ) 81 | 82 | // String return state in string format 83 | func (s State) String() string { 84 | return [...]string{"Connecting", "Connected", "Configuring", "Configured", "Disconnecting", "Disconnected"}[s] 85 | } 86 | 87 | // Connection connection data for storing in connection store 88 | type Connection struct { 89 | ID ConnectionID 90 | Client e2.ClientConn 91 | Status ConnectionStatus 92 | } 93 | -------------------------------------------------------------------------------- /pkg/store/event/event.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package event 6 | 7 | // Event store event data structure 8 | type Event struct { 9 | Key interface{} 10 | Value interface{} 11 | Type interface{} 12 | } 13 | -------------------------------------------------------------------------------- /pkg/store/metrics/metrics_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package metrics 6 | 7 | import ( 8 | "context" 9 | "testing" 10 | 11 | "github.com/onosproject/ran-simulator/pkg/store/event" 12 | 13 | "github.com/stretchr/testify/assert" 14 | ) 15 | 16 | func TestMetrics(t *testing.T) { 17 | store := NewMetricsStore() 18 | ctx := context.Background() 19 | ch := make(chan event.Event) 20 | 21 | err := store.Watch(ctx, ch) 22 | assert.NoError(t, err) 23 | 24 | _, ok := store.Get(ctx, 123, "foo") 25 | assert.False(t, ok) 26 | entities, err := store.ListEntities(ctx) 27 | assert.Equal(t, 0, len(entities)) 28 | assert.NoError(t, err) 29 | 30 | _ = store.Set(ctx, 123, "foo", 6.28) 31 | _ = store.Set(ctx, 123, "bar", 3.14) 32 | _ = store.Set(ctx, 123, "bah", "42") 33 | _ = store.Set(ctx, 321, "foo", 2.718) 34 | _ = store.Set(ctx, 321, "goo", 1.618) 35 | 36 | metricEvent := <-ch 37 | assert.Equal(t, Updated, metricEvent.Type) 38 | metricEvent = <-ch 39 | assert.Equal(t, Updated, metricEvent.Type) 40 | metricEvent = <-ch 41 | assert.Equal(t, Updated, metricEvent.Type) 42 | metricEvent = <-ch 43 | assert.Equal(t, Updated, metricEvent.Type) 44 | metricEvent = <-ch 45 | assert.Equal(t, Updated, metricEvent.Type) 46 | 47 | v, ok := store.Get(ctx, 123, "foo") 48 | assert.True(t, ok) 49 | assert.Equal(t, 6.28, v) 50 | 51 | entities, _ = store.ListEntities(ctx) 52 | assert.Equal(t, 2, len(entities), "incorrect entity count") 53 | metrics, _ := store.List(ctx, 123) 54 | assert.Equal(t, 3, len(metrics), "incorrect metric count") 55 | 56 | _ = store.Delete(ctx, 123, "bah") 57 | metrics, _ = store.List(ctx, 123) 58 | assert.Equal(t, 2, len(metrics), "incorrect metric count") 59 | 60 | metricEvent = <-ch 61 | assert.Equal(t, Deleted, metricEvent.Type) 62 | 63 | _, ok = store.Get(ctx, 123, "bah") 64 | assert.False(t, ok) 65 | 66 | _ = store.DeleteAll(ctx, 123) 67 | entities, _ = store.ListEntities(ctx) 68 | assert.Equal(t, 1, len(entities), "incorrect entity count") 69 | metrics, _ = store.List(ctx, 123) 70 | assert.Equal(t, 0, len(metrics), "incorrect metric count") 71 | 72 | metricEvent = <-ch 73 | assert.Equal(t, Deleted, metricEvent.Type) 74 | metricEvent = <-ch 75 | assert.Equal(t, Deleted, metricEvent.Type) 76 | assert.Equal(t, uint64(123), metricEvent.Key.(Key).EntityID) 77 | 78 | name := metricEvent.Key.(Key).Name 79 | assert.True(t, name == "bar" || name == "foo") 80 | 81 | store.Clear(ctx) 82 | ids, _ := store.ListEntities(ctx) 83 | assert.Equal(t, 0, len(ids), "should be empty") 84 | 85 | ctx.Done() 86 | } 87 | -------------------------------------------------------------------------------- /pkg/store/metrics/types.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package metrics 6 | 7 | // MetricEvent is a type of event 8 | type MetricEvent int 9 | 10 | const ( 11 | // None none cell event 12 | None MetricEvent = iota 13 | // Updated updated metric event 14 | Updated 15 | // Deleted deleted metric event 16 | Deleted 17 | ) 18 | 19 | func (e MetricEvent) String() string { 20 | return [...]string{"None", "Updated", "Deleted"}[e] 21 | } 22 | 23 | // Key key for storing a metric 24 | type Key struct { 25 | EntityID uint64 26 | Name string 27 | } 28 | -------------------------------------------------------------------------------- /pkg/store/nodes/nodes_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package nodes 6 | 7 | import ( 8 | "context" 9 | "testing" 10 | 11 | "github.com/onosproject/onos-api/go/onos/ransim/types" 12 | "github.com/onosproject/ran-simulator/pkg/model" 13 | "github.com/onosproject/ran-simulator/pkg/store/event" 14 | 15 | "github.com/stretchr/testify/assert" 16 | ) 17 | 18 | func TestNodes(t *testing.T) { 19 | m := &model.Model{} 20 | err := model.LoadConfig(m, "../../model/test") 21 | assert.NoError(t, err) 22 | t.Log(m) 23 | ctx := context.Background() 24 | 25 | nodeStore := NewNodeRegistry(m.Nodes) 26 | node1GnbID := types.GnbID(144472) 27 | node2GnbID := types.GnbID(144473) 28 | numNodes, err := nodeStore.Len(ctx) 29 | assert.NoError(t, err) 30 | assert.Equal(t, 2, numNodes) 31 | 32 | ch := make(chan event.Event) 33 | err = nodeStore.Watch(ctx, ch) 34 | assert.NoError(t, err) 35 | node1 := &model.Node{ 36 | GnbID: node1GnbID, 37 | Controllers: []string{"controller1"}, 38 | ServiceModels: []string{"kpm"}, 39 | Cells: []types.NCGI{1234, 4321}, 40 | } 41 | 42 | node2 := &model.Node{ 43 | GnbID: node2GnbID, 44 | Controllers: []string{"controller1"}, 45 | ServiceModels: []string{"kpm"}, 46 | Cells: []types.NCGI{5678, 8765}, 47 | } 48 | err = nodeStore.Add(ctx, node1) 49 | assert.NoError(t, err) 50 | err = nodeStore.Add(ctx, node2) 51 | assert.NoError(t, err) 52 | 53 | nodeEvent := <-ch 54 | assert.Equal(t, Created, nodeEvent.Type.(NodeEvent)) 55 | nodeEvent = <-ch 56 | assert.Equal(t, Created, nodeEvent.Type.(NodeEvent)) 57 | 58 | node1, err = nodeStore.Get(ctx, node1GnbID) 59 | assert.NoError(t, err) 60 | assert.Equal(t, node1.GnbID, node1GnbID) 61 | _, err = nodeStore.Delete(ctx, node1GnbID) 62 | assert.NoError(t, err) 63 | nodeEvent = <-ch 64 | assert.Equal(t, Deleted, nodeEvent.Type.(NodeEvent)) 65 | 66 | _, err = nodeStore.Get(ctx, node1GnbID) 67 | assert.Error(t, err, "node found") 68 | 69 | nodeStore.Clear(ctx) 70 | ids, _ := nodeStore.List(ctx) 71 | assert.Equal(t, 0, len(ids), "should be empty") 72 | } 73 | -------------------------------------------------------------------------------- /pkg/store/nodes/types.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package nodes 6 | 7 | // NodeEvent a node event 8 | type NodeEvent int 9 | 10 | const ( 11 | // None non node event 12 | None NodeEvent = iota 13 | // Created created node event 14 | Created 15 | // Updated updated node event 16 | Updated 17 | // Deleted deleted node event 18 | Deleted 19 | ) 20 | 21 | // String converts node event to string 22 | func (e NodeEvent) String() string { 23 | return [...]string{"None", "Created", "Updated", "Deleted"}[e] 24 | } 25 | -------------------------------------------------------------------------------- /pkg/store/routes/routes_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package routes 6 | 7 | import ( 8 | "context" 9 | "github.com/onosproject/onos-api/go/onos/ransim/types" 10 | "testing" 11 | 12 | "github.com/onosproject/ran-simulator/pkg/model" 13 | "github.com/onosproject/ran-simulator/pkg/store/event" 14 | "github.com/stretchr/testify/assert" 15 | ) 16 | 17 | func TestRouteRegistry(t *testing.T) { 18 | ctx := context.Background() 19 | routes := NewRouteRegistry() 20 | assert.NotNil(t, routes, "unable to create route registry") 21 | assert.Equal(t, 0, routes.Len(ctx)) 22 | 23 | ch := make(chan event.Event) 24 | err := routes.Watch(ctx, ch) 25 | assert.NoError(t, err) 26 | 27 | route1 := &model.Route{ 28 | IMSI: 123456789, 29 | Points: []*model.Coordinate{{Lat: 1, Lng: 2}, {Lat: 2, Lng: 1}}, 30 | Color: "green", 31 | } 32 | 33 | route2 := &model.Route{ 34 | IMSI: 923456781, 35 | Points: []*model.Coordinate{{Lat: 3, Lng: 2}, {Lat: 3, Lng: 1}}, 36 | Color: "blue", 37 | } 38 | 39 | err = routes.Add(ctx, route1) 40 | assert.NoError(t, err) 41 | assert.Equal(t, 1, routes.Len(ctx)) 42 | 43 | err = routes.Add(ctx, route2) 44 | assert.NoError(t, err) 45 | assert.Equal(t, 2, routes.Len(ctx)) 46 | 47 | nodeEvent := <-ch 48 | assert.Equal(t, Created, nodeEvent.Type.(RouteEvent)) 49 | nodeEvent = <-ch 50 | assert.Equal(t, Created, nodeEvent.Type.(RouteEvent)) 51 | 52 | list := routes.List(ctx) 53 | assert.Equal(t, 2, len(list)) 54 | 55 | r1, err := routes.Get(ctx, route1.IMSI) 56 | assert.NoError(t, err) 57 | assert.Equal(t, route1.IMSI, r1.IMSI) 58 | _, err = routes.Delete(ctx, r1.IMSI) 59 | assert.NoError(t, err) 60 | nodeEvent = <-ch 61 | assert.Equal(t, Deleted, nodeEvent.Type.(RouteEvent)) 62 | 63 | _, err = routes.Get(ctx, route1.IMSI) 64 | assert.Error(t, err, "route found") 65 | 66 | routes.Clear(ctx) 67 | assert.Equal(t, 0, routes.Len(ctx)) 68 | } 69 | 70 | func TestRouteAdvance(t *testing.T) { 71 | ctx := context.Background() 72 | routes := NewRouteRegistry() 73 | assert.NotNil(t, routes, "unable to create route registry") 74 | assert.Equal(t, 0, routes.Len(ctx)) 75 | 76 | ch := make(chan event.Event) 77 | err := routes.Watch(ctx, ch) 78 | assert.NoError(t, err) 79 | 80 | r := &model.Route{ 81 | IMSI: 123456789, 82 | Points: []*model.Coordinate{{Lat: 1, Lng: 2}, {Lat: 2, Lng: 1}, {Lat: 3, Lng: 4}}, 83 | Color: "green", 84 | } 85 | 86 | err = routes.Add(ctx, r) 87 | assert.NoError(t, err) 88 | 89 | err = routes.Start(ctx, r.IMSI, 100, 0) 90 | assert.NoError(t, err) 91 | 92 | r1, err := routes.Get(ctx, r.IMSI) 93 | assert.NoError(t, err) 94 | assert.Equal(t, uint32(1), r1.NextPoint) 95 | assert.Equal(t, false, r1.Reverse) 96 | assert.Equal(t, uint32(100), r1.SpeedAvg) 97 | assert.Equal(t, uint32(0), r1.SpeedStdDev) 98 | 99 | err = routes.Advance(ctx, r.IMSI) 100 | assert.NoError(t, err) 101 | validate(t, routes, r.IMSI, 2, false) 102 | 103 | err = routes.Advance(ctx, r.IMSI) 104 | assert.NoError(t, err) 105 | validate(t, routes, r.IMSI, 1, true) 106 | 107 | err = routes.Advance(ctx, r.IMSI) 108 | assert.NoError(t, err) 109 | validate(t, routes, r.IMSI, 0, true) 110 | 111 | err = routes.Advance(ctx, r.IMSI) 112 | assert.NoError(t, err) 113 | validate(t, routes, r.IMSI, 1, false) 114 | } 115 | 116 | func validate(t *testing.T, store Store, imsi types.IMSI, n uint32, rev bool) { 117 | r, err := store.Get(context.Background(), imsi) 118 | assert.NoError(t, err) 119 | assert.Equal(t, n, r.NextPoint) 120 | assert.Equal(t, rev, r.Reverse) 121 | } 122 | -------------------------------------------------------------------------------- /pkg/store/routes/types.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package routes 6 | 7 | // RouteEvent a node event 8 | type RouteEvent int 9 | 10 | const ( 11 | // None non route event 12 | None RouteEvent = iota 13 | // Created created ue event 14 | Created 15 | // Updated updated ue event 16 | Updated 17 | // Deleted deleted ue event 18 | Deleted 19 | ) 20 | 21 | // String converts node event to string 22 | func (e RouteEvent) String() string { 23 | return [...]string{"None", "Created", "Updated", "Deleted"}[e] 24 | } 25 | -------------------------------------------------------------------------------- /pkg/store/subscriptions/store_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package subscriptions 6 | 7 | import ( 8 | "testing" 9 | 10 | e2apies "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-ies" 11 | 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | // TestSubscriptions test subscriptions store interface 16 | func TestSubscriptions(t *testing.T) { 17 | subStore := NewStore() 18 | numSubs, err := subStore.Len() 19 | assert.NoError(t, err) 20 | assert.Equal(t, 0, numSubs) 21 | sub1 := &Subscription{ 22 | ID: "sub1", 23 | ReqID: &e2apies.RicrequestId{ 24 | RicRequestorId: 1, 25 | RicInstanceId: 1, 26 | }, 27 | } 28 | 29 | err = subStore.Add(sub1) 30 | assert.NoError(t, err) 31 | numSubs, err = subStore.Len() 32 | assert.NoError(t, err) 33 | assert.Equal(t, 1, numSubs) 34 | 35 | sub2 := &Subscription{ 36 | ID: "sub2", 37 | ReqID: &e2apies.RicrequestId{ 38 | RicRequestorId: 2, 39 | RicInstanceId: 2, 40 | }, 41 | } 42 | err = subStore.Add(sub2) 43 | assert.NoError(t, err) 44 | numSubs, err = subStore.Len() 45 | assert.NoError(t, err) 46 | assert.Equal(t, 2, numSubs) 47 | 48 | _, err = subStore.Get("sub3") 49 | assert.Error(t, err, "subscription entry has not been found") 50 | 51 | sub1Entry, err := subStore.Get("sub1") 52 | assert.NoError(t, err) 53 | assert.Equal(t, ID("sub1"), sub1Entry.ID) 54 | 55 | err = subStore.Remove("sub1") 56 | assert.NoError(t, err) 57 | numSubs, err = subStore.Len() 58 | assert.NoError(t, err) 59 | assert.Equal(t, 1, numSubs) 60 | 61 | _, err = subStore.Get("sub1") 62 | assert.Error(t, err, "subscription entry has not been found") 63 | 64 | subscriptionList, err := subStore.List() 65 | assert.NoError(t, err) 66 | numSubs, err = subStore.Len() 67 | assert.Equal(t, 1, numSubs) 68 | assert.NoError(t, err) 69 | assert.Equal(t, 1, len(subscriptionList)) 70 | 71 | } 72 | -------------------------------------------------------------------------------- /pkg/store/ues/types.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package ues 6 | 7 | // UeEvent a node event 8 | type UeEvent int 9 | 10 | const ( 11 | // None non ue event 12 | None UeEvent = iota 13 | // Created created ue event 14 | Created 15 | // Updated updated ue event 16 | Updated 17 | // Deleted deleted ue event 18 | Deleted 19 | ) 20 | 21 | // String converts node event to string 22 | func (e UeEvent) String() string { 23 | return [...]string{"None", "Created", "Updated", "Deleted"}[e] 24 | } 25 | -------------------------------------------------------------------------------- /pkg/store/watcher/watcher.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package watcher 6 | 7 | import ( 8 | "sync" 9 | 10 | "github.com/google/uuid" 11 | 12 | "github.com/onosproject/ran-simulator/pkg/store/event" 13 | ) 14 | 15 | // EventChannel is a channel which can accept an Event 16 | type EventChannel chan event.Event 17 | 18 | // Watchers stores the information about watchers 19 | type Watchers struct { 20 | watchers map[uuid.UUID]Watcher 21 | rm sync.RWMutex 22 | } 23 | 24 | // Watcher event watcher 25 | type Watcher struct { 26 | id uuid.UUID 27 | ch chan<- event.Event 28 | } 29 | 30 | // NewWatchers creates watchers 31 | func NewWatchers() *Watchers { 32 | return &Watchers{ 33 | watchers: make(map[uuid.UUID]Watcher), 34 | } 35 | } 36 | 37 | // Send sends an event for all registered watchers 38 | func (ws *Watchers) Send(event event.Event) { 39 | ws.rm.RLock() 40 | go func() { 41 | for _, watcher := range ws.watchers { 42 | watcher.ch <- event 43 | } 44 | }() 45 | ws.rm.RUnlock() 46 | } 47 | 48 | // AddWatcher adds a watcher 49 | func (ws *Watchers) AddWatcher(id uuid.UUID, ch chan<- event.Event) error { 50 | ws.rm.Lock() 51 | watcher := Watcher{ 52 | id: id, 53 | ch: ch, 54 | } 55 | ws.watchers[id] = watcher 56 | ws.rm.Unlock() 57 | return nil 58 | 59 | } 60 | 61 | // RemoveWatcher removes a watcher 62 | func (ws *Watchers) RemoveWatcher(id uuid.UUID) error { 63 | ws.rm.Lock() 64 | watchers := make(map[uuid.UUID]Watcher, len(ws.watchers)-1) 65 | for _, watcher := range ws.watchers { 66 | if watcher.id != id { 67 | watchers[id] = watcher 68 | 69 | } 70 | } 71 | ws.watchers = watchers 72 | ws.rm.Unlock() 73 | return nil 74 | 75 | } 76 | -------------------------------------------------------------------------------- /pkg/utils/e2ap/configupdate/configupdate.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package configupdate 6 | 7 | import ( 8 | ransimtypes "github.com/onosproject/onos-api/go/onos/ransim/types" 9 | "github.com/onosproject/ran-simulator/pkg/utils" 10 | 11 | e2apcommondatatypes "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-commondatatypes" 12 | e2apies "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-ies" 13 | e2appducontents "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-pdu-contents" 14 | "github.com/onosproject/onos-lib-go/api/asn1/v1/asn1" 15 | ) 16 | 17 | // ConfigurationUpdate configuration update procedure data structure 18 | type ConfigurationUpdate struct { 19 | transactionID int32 20 | plmnID ransimtypes.Uint24 21 | e2NodeID uint64 22 | } 23 | 24 | // NewConfigurationUpdate creates a new instance of configuration update 25 | func NewConfigurationUpdate(options ...func(update *ConfigurationUpdate)) *ConfigurationUpdate { 26 | configUpdate := &ConfigurationUpdate{} 27 | 28 | for _, option := range options { 29 | option(configUpdate) 30 | } 31 | return configUpdate 32 | } 33 | 34 | // WithTransactionID sets transaction ID 35 | func WithTransactionID(transID int32) func(update *ConfigurationUpdate) { 36 | return func(configUpdate *ConfigurationUpdate) { 37 | configUpdate.transactionID = transID 38 | } 39 | } 40 | 41 | // WithE2NodeID sets E2 node ID 42 | func WithE2NodeID(e2NodeID uint64) func(update *ConfigurationUpdate) { 43 | return func(configUpdate *ConfigurationUpdate) { 44 | configUpdate.e2NodeID = e2NodeID 45 | } 46 | } 47 | 48 | // WithPlmnID sets plmnID 49 | func WithPlmnID(plmnID ransimtypes.Uint24) func(update *ConfigurationUpdate) { 50 | return func(configUpdate *ConfigurationUpdate) { 51 | configUpdate.plmnID = plmnID 52 | 53 | } 54 | } 55 | 56 | // Build builds a configuration update request 57 | func (c *ConfigurationUpdate) Build() (*e2appducontents.E2NodeConfigurationUpdate, error) { 58 | gE2NodeID := &e2apies.GlobalE2NodeId{ 59 | GlobalE2NodeId: &e2apies.GlobalE2NodeId_GNb{ 60 | GNb: &e2apies.GlobalE2NodeGnbId{ 61 | GlobalGNbId: &e2apies.GlobalgNbId{ 62 | PlmnId: &e2apcommondatatypes.PlmnIdentity{ 63 | Value: c.plmnID.ToBytes(), 64 | }, 65 | GnbId: &e2apies.GnbIdChoice{ 66 | GnbIdChoice: &e2apies.GnbIdChoice_GnbId{ 67 | GnbId: &asn1.BitString{ 68 | Value: utils.Uint64ToBitString(c.e2NodeID, 28), 69 | Len: 28, 70 | }}, 71 | }, 72 | }, 73 | }, 74 | }, 75 | } 76 | 77 | configUpdate := &e2appducontents.E2NodeConfigurationUpdate{ 78 | ProtocolIes: make([]*e2appducontents.E2NodeConfigurationUpdateIes, 0), 79 | } 80 | configUpdate.SetTransactionID(c.transactionID).SetGlobalE2nodeID(gE2NodeID) 81 | 82 | return configUpdate, nil 83 | } 84 | -------------------------------------------------------------------------------- /pkg/utils/e2ap/connectionupdate/connectionSetupFailedItemie/connectionSetupFailedItemIes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package connectionsetupfaileditem 6 | 7 | import ( 8 | "github.com/onosproject/onos-e2t/api/e2ap/v2" 9 | e2ap_commondatatypes "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-commondatatypes" 10 | e2apies "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-ies" 11 | e2appducontents "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-pdu-contents" 12 | ) 13 | 14 | // IEs connection setup failed item Ies 15 | type IEs struct { 16 | tnlInfo *e2apies.Tnlinformation 17 | cause *e2apies.Cause 18 | } 19 | 20 | // NewConnectionSetupFailedItemIe creates a new instance of connection setup failed Item Ie 21 | func NewConnectionSetupFailedItemIe(options ...func(update *IEs)) *IEs { 22 | connectionSetupFailedItemIe := &IEs{} 23 | 24 | for _, option := range options { 25 | option(connectionSetupFailedItemIe) 26 | } 27 | 28 | return connectionSetupFailedItemIe 29 | } 30 | 31 | // WithTnlInfo sets tnl info 32 | func WithTnlInfo(tnlInfo *e2apies.Tnlinformation) func(ie *IEs) { 33 | return func(connectionSetupFailedItemIe *IEs) { 34 | connectionSetupFailedItemIe.tnlInfo = tnlInfo 35 | } 36 | } 37 | 38 | // BuildConnectionSetupFailedItemIes builds connection setup failed Item Ies 39 | func (c *IEs) BuildConnectionSetupFailedItemIes() *e2appducontents.E2ConnectionSetupFailedItemIes { 40 | connectionSetupFailedItemIes := &e2appducontents.E2ConnectionSetupFailedItemIes{ 41 | Id: int32(v2.ProtocolIeIDE2connectionSetupFailedItem), 42 | Criticality: int32(e2ap_commondatatypes.Criticality_CRITICALITY_IGNORE), 43 | Value: &e2appducontents.E2ConnectionSetupFailedItemIe{ 44 | E2ConnectionSetupFailedItemIe: &e2appducontents.E2ConnectionSetupFailedItemIe_E2ConnectionSetupFailedItem{ 45 | E2ConnectionSetupFailedItem: &e2appducontents.E2ConnectionSetupFailedItem{ 46 | TnlInformation: c.tnlInfo, 47 | Cause: c.cause, 48 | }, 49 | }, 50 | }, 51 | } 52 | 53 | return connectionSetupFailedItemIes 54 | } 55 | -------------------------------------------------------------------------------- /pkg/utils/e2ap/connectionupdate/connectionUpdateitemie/connectionupdateitemIe.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package connectionupdateitem 6 | 7 | import ( 8 | "github.com/onosproject/onos-e2t/api/e2ap/v2" 9 | e2ap_commondatatypes "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-commondatatypes" 10 | e2ap_ies "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-ies" 11 | e2appducontents "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-pdu-contents" 12 | ) 13 | 14 | // IEs connection item update 15 | type IEs struct { 16 | tnlInfo *e2ap_ies.Tnlinformation 17 | tnlUsage e2ap_ies.Tnlusage 18 | } 19 | 20 | // NewConnectionUpdateItemIe creates a new instance of connection update Item Ie 21 | func NewConnectionUpdateItemIe(options ...func(update *IEs)) *IEs { 22 | connectionUpdateItemIe := &IEs{} 23 | 24 | for _, option := range options { 25 | option(connectionUpdateItemIe) 26 | } 27 | 28 | return connectionUpdateItemIe 29 | } 30 | 31 | // WithTnlInfo sets tnl info 32 | func WithTnlInfo(tnlInfo *e2ap_ies.Tnlinformation) func(*IEs) { 33 | return func(connectionUpdateItemIe *IEs) { 34 | connectionUpdateItemIe.tnlInfo = tnlInfo 35 | } 36 | } 37 | 38 | // WithTnlUsage sets tnl usage 39 | func WithTnlUsage(tnlUsage e2ap_ies.Tnlusage) func(*IEs) { 40 | return func(connectionUpdateItemIe *IEs) { 41 | connectionUpdateItemIe.tnlUsage = tnlUsage 42 | } 43 | } 44 | 45 | // BuildConnectionUpdateItemIes builds connection Update Item Ies 46 | func (c *IEs) BuildConnectionUpdateItemIes() *e2appducontents.E2ConnectionUpdateItemIes { 47 | connectionUpdateItemIes := &e2appducontents.E2ConnectionUpdateItemIes{ 48 | Id: int32(v2.ProtocolIeIDE2connectionUpdateItem), 49 | Criticality: int32(e2ap_commondatatypes.Criticality_CRITICALITY_IGNORE), 50 | Value: &e2appducontents.E2ConnectionUpdateItemIe{ 51 | E2ConnectionUpdateItemIe: &e2appducontents.E2ConnectionUpdateItemIe_E2ConnectionUpdateItem{ 52 | E2ConnectionUpdateItem: &e2appducontents.E2ConnectionUpdateItem{ 53 | TnlInformation: c.tnlInfo, 54 | TnlUsage: c.tnlUsage, 55 | }, 56 | }, 57 | }, 58 | } 59 | return connectionUpdateItemIes 60 | } 61 | -------------------------------------------------------------------------------- /pkg/utils/e2ap/control/getters.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package control 6 | 7 | import ( 8 | "fmt" 9 | 10 | v2 "github.com/onosproject/onos-e2t/api/e2ap/v2" 11 | e2appducontents "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-pdu-contents" 12 | ) 13 | 14 | // GetRequesterID gets requester ID 15 | func GetRequesterID(request *e2appducontents.RiccontrolRequest) (*int32, error) { 16 | var res int32 = -1 17 | for _, v := range request.GetProtocolIes() { 18 | if v.Id == int32(v2.ProtocolIeIDRicrequestID) { 19 | res = v.GetValue().GetRicrequestId().GetRicRequestorId() 20 | break 21 | } 22 | } 23 | 24 | if res == -1 { 25 | return nil, fmt.Errorf("RicRequestID was not found") 26 | } 27 | 28 | return &res, nil 29 | } 30 | 31 | // GetRanFunctionID gets ran function ID 32 | func GetRanFunctionID(request *e2appducontents.RiccontrolRequest) (*int32, error) { 33 | var res int32 = -1 34 | for _, v := range request.GetProtocolIes() { 35 | if v.Id == int32(v2.ProtocolIeIDRanfunctionID) { 36 | res = v.GetValue().GetRanfunctionId().GetValue() 37 | break 38 | } 39 | } 40 | 41 | if res == -1 { 42 | return nil, fmt.Errorf("RanFunctionID was not found") 43 | } 44 | 45 | return &res, nil 46 | } 47 | 48 | // GetRicInstanceID gets ric instance ID 49 | func GetRicInstanceID(request *e2appducontents.RiccontrolRequest) (*int32, error) { 50 | var res int32 = -1 51 | for _, v := range request.GetProtocolIes() { 52 | if v.Id == int32(v2.ProtocolIeIDRicrequestID) { 53 | res = v.GetValue().GetRicrequestId().GetRicInstanceId() 54 | break 55 | } 56 | } 57 | 58 | if res == -1 { 59 | return nil, fmt.Errorf("RicInstanceID was not found") 60 | } 61 | 62 | return &res, nil 63 | } 64 | -------------------------------------------------------------------------------- /pkg/utils/e2ap/indication/indication.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022-present Intel Corporation 2 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | package indication 7 | 8 | import ( 9 | e2apies "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-ies" 10 | e2appducontents "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-pdu-contents" 11 | "github.com/onosproject/onos-e2t/pkg/southbound/e2ap/types" 12 | ) 13 | 14 | // Indication indication data struct 15 | type Indication struct { 16 | reqID int32 17 | ricInstanceID int32 18 | ranFuncID int32 19 | indicationHeader []byte 20 | indicationMessage []byte 21 | ricCallProcessID []byte 22 | // TODO add ric action ID and ric indication sn 23 | } 24 | 25 | // NewIndication creates a new indication 26 | func NewIndication(options ...func(*Indication)) *Indication { 27 | indication := &Indication{} 28 | 29 | for _, option := range options { 30 | option(indication) 31 | } 32 | 33 | return indication 34 | 35 | } 36 | 37 | // WithRequestID sets request ID 38 | func WithRequestID(reqID int32) func(*Indication) { 39 | return func(indication *Indication) { 40 | indication.reqID = reqID 41 | } 42 | } 43 | 44 | // WithRanFuncID sets ran function ID 45 | func WithRanFuncID(ranFuncID int32) func(*Indication) { 46 | return func(indication *Indication) { 47 | indication.ranFuncID = ranFuncID 48 | } 49 | } 50 | 51 | // WithRicInstanceID sets ric instance ID 52 | func WithRicInstanceID(ricInstanceID int32) func(*Indication) { 53 | return func(indication *Indication) { 54 | indication.ricInstanceID = ricInstanceID 55 | } 56 | } 57 | 58 | // WithIndicationHeader sets indication header 59 | func WithIndicationHeader(indicationHeader []byte) func(*Indication) { 60 | return func(indication *Indication) { 61 | indication.indicationHeader = indicationHeader 62 | } 63 | } 64 | 65 | // WithIndicationMessage sets indication message 66 | func WithIndicationMessage(indicationMessage []byte) func(*Indication) { 67 | return func(indication *Indication) { 68 | indication.indicationMessage = indicationMessage 69 | } 70 | } 71 | 72 | // WithRicCallProcessID sets RIC call process ID 73 | func WithRicCallProcessID(ricCallProcessID []byte) func(*Indication) { 74 | return func(indication *Indication) { 75 | indication.ricCallProcessID = ricCallProcessID 76 | } 77 | } 78 | 79 | // Build builds e2ap indication message 80 | func (indication *Indication) Build() (e2Indication *e2appducontents.Ricindication, err error) { 81 | rrID := types.RicRequest{ 82 | RequestorID: types.RicRequestorID(indication.reqID), 83 | InstanceID: types.RicInstanceID(indication.ricInstanceID), 84 | } 85 | ricIndication := &e2appducontents.Ricindication{ 86 | ProtocolIes: make([]*e2appducontents.RicindicationIes, 0), 87 | } 88 | ricIndication.SetRicRequestID(rrID).SetRanFunctionID(types.RanFunctionID(indication.ranFuncID)). 89 | SetRicActionID(2). 90 | SetRicIndicationSN(3).SetRicIndicationType(e2apies.RicindicationType_RICINDICATION_TYPE_REPORT). 91 | SetRicIndicationHeader(indication.indicationHeader).SetRicIndicationMessage(indication.indicationMessage). 92 | SetRicCallProcessID(indication.ricCallProcessID) 93 | 94 | return ricIndication, nil 95 | } 96 | -------------------------------------------------------------------------------- /pkg/utils/e2ap/indicationerror/indication_error.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package indicationerror 6 | 7 | import ( 8 | "github.com/onosproject/onos-e2t/api/e2ap/v2" 9 | e2ap_commondatatypes "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-commondatatypes" 10 | e2apies "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-ies" 11 | e2appducontents "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-pdu-contents" 12 | "github.com/onosproject/onos-e2t/pkg/southbound/e2ap/types" 13 | ) 14 | 15 | // ErrorIndication required fields for creating error indication error message 16 | type ErrorIndication struct { 17 | reqID int32 18 | ricInstanceID int32 19 | ranFuncID int32 20 | cause *e2apies.Cause 21 | failureProcCode int32 22 | failureTrigMsg *e2ap_commondatatypes.TriggeringMessage 23 | critDiags []*types.CritDiag 24 | failureCrit *e2ap_commondatatypes.Criticality 25 | } 26 | 27 | // NewErrorIndication creates a new error indication 28 | func NewErrorIndication(options ...func(errorIndication *ErrorIndication)) *ErrorIndication { 29 | errorIndication := &ErrorIndication{} 30 | 31 | for _, option := range options { 32 | option(errorIndication) 33 | } 34 | 35 | return errorIndication 36 | } 37 | 38 | // WithRequestID sets request ID 39 | func WithRequestID(reqID int32) func(*ErrorIndication) { 40 | return func(errorIndication *ErrorIndication) { 41 | errorIndication.reqID = reqID 42 | } 43 | } 44 | 45 | // WithRanFuncID sets ran function ID 46 | func WithRanFuncID(ranFuncID int32) func(*ErrorIndication) { 47 | return func(errorIndication *ErrorIndication) { 48 | errorIndication.ranFuncID = ranFuncID 49 | } 50 | } 51 | 52 | // WithRicInstanceID sets ric instance ID 53 | func WithRicInstanceID(ricInstanceID int32) func(*ErrorIndication) { 54 | return func(errorIndication *ErrorIndication) { 55 | errorIndication.ricInstanceID = ricInstanceID 56 | } 57 | } 58 | 59 | // WithFailureProcCode sets failure proc code 60 | func WithFailureProcCode(failureProcCode int32) func(*ErrorIndication) { 61 | return func(errorIndication *ErrorIndication) { 62 | errorIndication.failureProcCode = failureProcCode 63 | } 64 | } 65 | 66 | // WithCause sets cause of error 67 | func WithCause(cause *e2apies.Cause) func(*ErrorIndication) { 68 | return func(errorIndication *ErrorIndication) { 69 | errorIndication.cause = cause 70 | } 71 | } 72 | 73 | // Build builds an error indication message 74 | func (e *ErrorIndication) Build() (*e2appducontents.ErrorIndication, error) { 75 | rrID := types.RicRequest{ 76 | RequestorID: types.RicRequestorID(e.reqID), 77 | InstanceID: types.RicInstanceID(e.ricInstanceID), 78 | } 79 | rfID := types.RanFunctionID(e.ranFuncID) 80 | errorIndication := &e2appducontents.ErrorIndication{ 81 | ProtocolIes: make([]*e2appducontents.ErrorIndicationIes, 0), 82 | } 83 | failureProcCode := v2.ProcedureCodeT(e.failureProcCode) 84 | errorIndication.SetRicRequestID(&rrID).SetRanFunctionID(&rfID).SetCause(e.cause). 85 | SetCriticalityDiagnostics(&failureProcCode, e.failureCrit, e.failureTrigMsg, &rrID, e.critDiags) 86 | 87 | return errorIndication, nil 88 | } 89 | -------------------------------------------------------------------------------- /pkg/utils/e2ap/subscription/getters.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package subscription 6 | 7 | import ( 8 | "github.com/onosproject/onos-lib-go/pkg/errors" 9 | 10 | v2 "github.com/onosproject/onos-e2t/api/e2ap/v2" 11 | e2appducontents "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-pdu-contents" 12 | ) 13 | 14 | // GetRequesterID gets requester ID 15 | func GetRequesterID(request *e2appducontents.RicsubscriptionRequest) (*int32, error) { 16 | var res int32 = -1 17 | for _, v := range request.GetProtocolIes() { 18 | if v.Id == int32(v2.ProtocolIeIDRicrequestID) { 19 | res = v.GetValue().GetRicrequestId().GetRicRequestorId() 20 | break 21 | } 22 | } 23 | 24 | if res == -1 { 25 | return nil, errors.NewNotFound("RicRequestID was not found") 26 | } 27 | 28 | return &res, nil 29 | } 30 | 31 | // GetRanFunctionID gets ran function ID 32 | func GetRanFunctionID(request *e2appducontents.RicsubscriptionRequest) (*int32, error) { 33 | var res int32 = -1 34 | for _, v := range request.GetProtocolIes() { 35 | if v.Id == int32(v2.ProtocolIeIDRanfunctionID) { 36 | res = v.GetValue().GetRanfunctionId().GetValue() 37 | break 38 | } 39 | } 40 | 41 | if res == -1 { 42 | return nil, errors.NewNotFound("RanFunctionID was not found") 43 | } 44 | 45 | return &res, nil 46 | } 47 | 48 | // GetRicInstanceID gets ric instance ID 49 | func GetRicInstanceID(request *e2appducontents.RicsubscriptionRequest) (*int32, error) { 50 | var res int32 = -1 51 | for _, v := range request.GetProtocolIes() { 52 | if v.Id == int32(v2.ProtocolIeIDRicrequestID) { 53 | res = v.GetValue().GetRicrequestId().GetRicInstanceId() 54 | break 55 | } 56 | } 57 | 58 | if res == -1 { 59 | return nil, errors.NewNotFound("RicInstanceID was not found") 60 | } 61 | 62 | return &res, nil 63 | } 64 | 65 | // GetRicActionToBeSetupList get ric action list 66 | func GetRicActionToBeSetupList(request *e2appducontents.RicsubscriptionRequest) []*e2appducontents.RicactionToBeSetupItemIes { 67 | var res []*e2appducontents.RicactionToBeSetupItemIes 68 | for _, v := range request.GetProtocolIes() { 69 | if v.Id == int32(v2.ProtocolIeIDRicsubscriptionDetails) { 70 | res = v.GetValue().GetRicsubscriptionDetails().GetRicActionToBeSetupList().GetValue() 71 | break 72 | } 73 | } 74 | 75 | return res 76 | } 77 | -------------------------------------------------------------------------------- /pkg/utils/e2ap/subscriptiondelete/getters.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package subscriptiondelete 6 | 7 | import ( 8 | "github.com/onosproject/onos-lib-go/pkg/errors" 9 | 10 | v2 "github.com/onosproject/onos-e2t/api/e2ap/v2" 11 | e2appducontents "github.com/onosproject/onos-e2t/api/e2ap/v2/e2ap-pdu-contents" 12 | ) 13 | 14 | // GetRequesterID gets requester ID 15 | func GetRequesterID(request *e2appducontents.RicsubscriptionDeleteRequest) (*int32, error) { 16 | var res int32 = -1 17 | for _, v := range request.GetProtocolIes() { 18 | if v.Id == int32(v2.ProtocolIeIDRicrequestID) { 19 | res = v.GetValue().GetRicrequestId().GetRicRequestorId() 20 | break 21 | } 22 | } 23 | 24 | if res == -1 { 25 | return nil, errors.NewNotFound("RicRequestID was not found") 26 | } 27 | 28 | return &res, nil 29 | } 30 | 31 | // GetRanFunctionID gets ran function ID 32 | func GetRanFunctionID(request *e2appducontents.RicsubscriptionDeleteRequest) (*int32, error) { 33 | var res int32 = -1 34 | for _, v := range request.GetProtocolIes() { 35 | if v.Id == int32(v2.ProtocolIeIDRanfunctionID) { 36 | res = v.GetValue().GetRanfunctionId().GetValue() 37 | break 38 | } 39 | } 40 | 41 | if res == -1 { 42 | return nil, errors.NewNotFound("RanFunctionID was not found") 43 | } 44 | 45 | return &res, nil 46 | } 47 | 48 | // GetRicInstanceID gets ric instance ID 49 | func GetRicInstanceID(request *e2appducontents.RicsubscriptionDeleteRequest) (*int32, error) { 50 | var res int32 = -1 51 | for _, v := range request.GetProtocolIes() { 52 | if v.Id == int32(v2.ProtocolIeIDRicrequestID) { 53 | res = v.GetValue().GetRicrequestId().GetRicInstanceId() 54 | break 55 | } 56 | } 57 | 58 | if res == -1 { 59 | return nil, errors.NewNotFound("RicInstanceID was not found") 60 | } 61 | 62 | return &res, nil 63 | } 64 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/kpm2/id/cellglobalid/cell_global_id.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package cellglobalid 6 | 7 | import ( 8 | ransimtypes "github.com/onosproject/onos-api/go/onos/ransim/types" 9 | e2smkpmv2 "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_kpm_v2_go/v2/e2sm-kpm-v2-go" 10 | "github.com/onosproject/onos-lib-go/api/asn1/v1/asn1" 11 | ) 12 | 13 | // GlobalNRCGIID cell global NRCGI ID 14 | type GlobalNRCGIID struct { 15 | plmnID *ransimtypes.Uint24 16 | nrCellID *asn1.BitString 17 | } 18 | 19 | // NewGlobalNRCGIID creates new global NRCGI ID 20 | func NewGlobalNRCGIID(options ...func(*GlobalNRCGIID)) *GlobalNRCGIID { 21 | nrcgiid := &GlobalNRCGIID{} 22 | for _, option := range options { 23 | option(nrcgiid) 24 | } 25 | 26 | return nrcgiid 27 | } 28 | 29 | // WithPlmnID sets plmn ID 30 | func WithPlmnID(plmnID *ransimtypes.Uint24) func(nrcgiid *GlobalNRCGIID) { 31 | return func(nrcgid *GlobalNRCGIID) { 32 | nrcgid.plmnID = plmnID 33 | 34 | } 35 | } 36 | 37 | // WithNRCellID sets NRCellID 38 | func WithNRCellID(nrCellID *asn1.BitString) func(nrcgiid *GlobalNRCGIID) { 39 | return func(nrcgid *GlobalNRCGIID) { 40 | nrcgid.nrCellID = nrCellID 41 | } 42 | } 43 | 44 | // Build builds a global NRCGI ID 45 | func (gNRCGIID *GlobalNRCGIID) Build() (*e2smkpmv2.CellGlobalId, error) { 46 | return &e2smkpmv2.CellGlobalId{ 47 | CellGlobalId: &e2smkpmv2.CellGlobalId_NrCgi{ 48 | NrCgi: &e2smkpmv2.Nrcgi{ 49 | PLmnIdentity: &e2smkpmv2.PlmnIdentity{ 50 | Value: gNRCGIID.plmnID.ToBytes(), 51 | }, 52 | NRcellIdentity: &e2smkpmv2.NrcellIdentity{ 53 | Value: gNRCGIID.nrCellID, 54 | }, 55 | }, 56 | }, 57 | }, nil 58 | } 59 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/kpm2/id/gnbid/gnb_id.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package gnbid 6 | 7 | import ( 8 | ransimtypes "github.com/onosproject/onos-api/go/onos/ransim/types" 9 | e2smkpmv2 "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_kpm_v2_go/v2/e2sm-kpm-v2-go" 10 | "github.com/onosproject/onos-lib-go/api/asn1/v1/asn1" 11 | ) 12 | 13 | // GlobalGNBID global gNB ID 14 | type GlobalGNBID struct { 15 | plmnID ransimtypes.Uint24 16 | gNBIDChoice *asn1.BitString 17 | gNBCuUpID int64 18 | gNBDuID int64 19 | } 20 | 21 | // NewGlobalGNBID creates new global gnb ID 22 | func NewGlobalGNBID(options ...func(*GlobalGNBID)) *GlobalGNBID { 23 | gNBID := &GlobalGNBID{} 24 | for _, option := range options { 25 | option(gNBID) 26 | } 27 | 28 | return gNBID 29 | } 30 | 31 | // WithPlmnID sets plmn ID 32 | func WithPlmnID(plmnID ransimtypes.Uint24) func(gNBID *GlobalGNBID) { 33 | return func(gNBID *GlobalGNBID) { 34 | gNBID.plmnID = plmnID 35 | 36 | } 37 | } 38 | 39 | // WithGNBIDChoice sets gNBID choice 40 | func WithGNBIDChoice(gnbIDChoice *asn1.BitString) func(gNBID *GlobalGNBID) { 41 | return func(gNBID *GlobalGNBID) { 42 | gNBID.gNBIDChoice = gnbIDChoice 43 | } 44 | } 45 | 46 | // WithGNBCuUpID sets gNB CuUp ID 47 | func WithGNBCuUpID(gNBCuUpID int64) func(gNBID *GlobalGNBID) { 48 | return func(gNBID *GlobalGNBID) { 49 | gNBID.gNBCuUpID = gNBCuUpID 50 | } 51 | } 52 | 53 | // WithGNBDuID sets gNB DuID 54 | func WithGNBDuID(gNBDuID int64) func(gNBID *GlobalGNBID) { 55 | return func(gNBID *GlobalGNBID) { 56 | gNBID.gNBDuID = gNBDuID 57 | } 58 | } 59 | 60 | // Build builds a global gNB ID 61 | func (gNBID *GlobalGNBID) Build() (*e2smkpmv2.GlobalKpmnodeId, error) { 62 | return &e2smkpmv2.GlobalKpmnodeId{ 63 | GlobalKpmnodeId: &e2smkpmv2.GlobalKpmnodeId_GNb{ 64 | GNb: &e2smkpmv2.GlobalKpmnodeGnbId{ 65 | GlobalGNbId: &e2smkpmv2.GlobalgNbId{ 66 | GnbId: &e2smkpmv2.GnbIdChoice{ 67 | GnbIdChoice: &e2smkpmv2.GnbIdChoice_GnbId{ 68 | GnbId: gNBID.gNBIDChoice, 69 | }, 70 | }, 71 | PlmnId: &e2smkpmv2.PlmnIdentity{ 72 | Value: gNBID.plmnID.ToBytes(), 73 | }, 74 | }, 75 | GNbCuUpId: &e2smkpmv2.GnbCuUpId{ 76 | Value: gNBID.gNBCuUpID, 77 | }, 78 | GNbDuId: &e2smkpmv2.GnbDuId{ 79 | Value: gNBID.gNBDuID, 80 | }, 81 | }, 82 | }, 83 | }, nil 84 | } 85 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/kpm2/indication/messageformat1/indication_message_format1.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package messageformat1 6 | 7 | import ( 8 | e2smkpmv2sm "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_kpm_v2_go/servicemodel" 9 | e2smkpmv2 "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_kpm_v2_go/v2/e2sm-kpm-v2-go" 10 | "google.golang.org/protobuf/proto" 11 | ) 12 | 13 | // Message indication message format 1 fields for kpm v2 service model 14 | type Message struct { 15 | subscriptionID int64 16 | cellObjID string 17 | granularity uint32 18 | measInfoList *e2smkpmv2.MeasurementInfoList 19 | measData *e2smkpmv2.MeasurementData 20 | } 21 | 22 | // NewIndicationMessage creates a new indication message 23 | func NewIndicationMessage(options ...func(message *Message)) *Message { 24 | msg := &Message{} 25 | for _, option := range options { 26 | option(msg) 27 | } 28 | 29 | return msg 30 | } 31 | 32 | // WithSubscriptionID sets subscription id 33 | func WithSubscriptionID(subscriptionID int64) func(msg *Message) { 34 | return func(msg *Message) { 35 | msg.subscriptionID = subscriptionID 36 | } 37 | } 38 | 39 | // WithCellObjID sets cell object ID 40 | func WithCellObjID(cellObjID string) func(msg *Message) { 41 | return func(msg *Message) { 42 | msg.cellObjID = cellObjID 43 | } 44 | } 45 | 46 | // WithGranularity sets granularity 47 | func WithGranularity(granularity uint32) func(msg *Message) { 48 | return func(msg *Message) { 49 | msg.granularity = granularity 50 | } 51 | } 52 | 53 | // WithMeasData sets measurements data 54 | func WithMeasData(measData *e2smkpmv2.MeasurementData) func(msg *Message) { 55 | return func(msg *Message) { 56 | msg.measData = measData 57 | } 58 | } 59 | 60 | // WithMeasInfoList sets measurement info list 61 | func WithMeasInfoList(measInfoList *e2smkpmv2.MeasurementInfoList) func(msg *Message) { 62 | return func(msg *Message) { 63 | msg.measInfoList = measInfoList 64 | } 65 | } 66 | 67 | // ToAsn1Bytes converts to Asn1 bytes 68 | func (message *Message) ToAsn1Bytes() ([]byte, error) { 69 | indicationMessage, err := message.Build() 70 | if err != nil { 71 | return nil, err 72 | } 73 | indicationMessageProtoBytes, err := proto.Marshal(indicationMessage) 74 | if err != nil { 75 | return nil, err 76 | } 77 | 78 | var kpm2ServiceModel e2smkpmv2sm.Kpm2ServiceModel 79 | 80 | indicationMessageAsn1Bytes, err := kpm2ServiceModel.IndicationMessageProtoToASN1(indicationMessageProtoBytes) 81 | if err != nil { 82 | return nil, err 83 | } 84 | 85 | return indicationMessageAsn1Bytes, nil 86 | 87 | } 88 | 89 | // Build builds indication message format 1 for kpm service model 90 | func (message *Message) Build() (*e2smkpmv2.E2SmKpmIndicationMessage, error) { 91 | e2SmKpmPdu := e2smkpmv2.E2SmKpmIndicationMessage{ 92 | IndicationMessageFormats: &e2smkpmv2.IndicationMessageFormats{ 93 | E2SmKpmIndicationMessage: &e2smkpmv2.IndicationMessageFormats_IndicationMessageFormat1{ 94 | IndicationMessageFormat1: &e2smkpmv2.E2SmKpmIndicationMessageFormat1{ 95 | SubscriptId: &e2smkpmv2.SubscriptionId{ 96 | Value: message.subscriptionID, 97 | }, 98 | CellObjId: &e2smkpmv2.CellObjectId{ 99 | Value: message.cellObjID, 100 | }, 101 | GranulPeriod: &e2smkpmv2.GranularityPeriod{ 102 | Value: int64(message.granularity), 103 | }, 104 | MeasInfoList: message.measInfoList, 105 | MeasData: message.measData, 106 | }, 107 | }, 108 | }, 109 | } 110 | 111 | // FIXME: Add back when ready 112 | //if err := e2SmKpmPdu.Validate(); err != nil { 113 | // return nil, errors.New(errors.Invalid, err.Error()) 114 | //} 115 | 116 | return &e2SmKpmPdu, nil 117 | } 118 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/kpm2/indication/messageformat2/indication_message_format2.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package messageformat2 6 | 7 | import ( 8 | "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_kpm_v2_go/servicemodel" 9 | e2smkpmv2 "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_kpm_v2_go/v2/e2sm-kpm-v2-go" 10 | "google.golang.org/protobuf/proto" 11 | ) 12 | 13 | // Message indication message format 2 fields for kpm v2 service model 14 | type Message struct { 15 | subscriptionID int64 16 | cellObjID string 17 | granularity uint32 18 | measCondUEList *e2smkpmv2.MeasurementCondUeidList 19 | measData *e2smkpmv2.MeasurementData 20 | } 21 | 22 | // NewIndicationMessage creates a new indication message 23 | func NewIndicationMessage(options ...func(message *Message)) *Message { 24 | msg := &Message{} 25 | for _, option := range options { 26 | option(msg) 27 | } 28 | 29 | return msg 30 | } 31 | 32 | // WithSubscriptionID sets subscription id 33 | func WithSubscriptionID(subscriptionID int64) func(msg *Message) { 34 | return func(msg *Message) { 35 | msg.subscriptionID = subscriptionID 36 | } 37 | } 38 | 39 | // WithCellObjID sets cell object ID 40 | func WithCellObjID(cellObjID string) func(msg *Message) { 41 | return func(msg *Message) { 42 | msg.cellObjID = cellObjID 43 | } 44 | } 45 | 46 | // WithGranularity sets granularity 47 | func WithGranularity(granularity uint32) func(msg *Message) { 48 | return func(msg *Message) { 49 | msg.granularity = granularity 50 | } 51 | } 52 | 53 | // WithMeasCondUEList sets measurement ue list 54 | func WithMeasCondUEList(measCondUEList *e2smkpmv2.MeasurementCondUeidList) func(msg *Message) { 55 | return func(msg *Message) { 56 | msg.measCondUEList = measCondUEList 57 | } 58 | } 59 | 60 | // WithMeasData sets measurement data 61 | func WithMeasData(measData *e2smkpmv2.MeasurementData) func(msg *Message) { 62 | return func(msg *Message) { 63 | msg.measData = measData 64 | } 65 | } 66 | 67 | // ToAsn1Bytes converts to Asn1 bytes 68 | func (message *Message) ToAsn1Bytes(serviceModel servicemodel.Kpm2ServiceModel) ([]byte, error) { 69 | indicationMessage, err := message.Build() 70 | if err != nil { 71 | return nil, err 72 | } 73 | indicationMessageProtoBytes, err := proto.Marshal(indicationMessage) 74 | if err != nil { 75 | return nil, err 76 | } 77 | 78 | indicationMessageAsn1Bytes, err := serviceModel.IndicationMessageProtoToASN1(indicationMessageProtoBytes) 79 | if err != nil { 80 | return nil, err 81 | } 82 | 83 | return indicationMessageAsn1Bytes, nil 84 | 85 | } 86 | 87 | // Build builds indication message format 2 for kpm v2 service model 88 | func (message *Message) Build() (*e2smkpmv2.E2SmKpmIndicationMessage, error) { 89 | e2SmKpmPdu := e2smkpmv2.E2SmKpmIndicationMessage{ 90 | IndicationMessageFormats: &e2smkpmv2.IndicationMessageFormats{ 91 | E2SmKpmIndicationMessage: &e2smkpmv2.IndicationMessageFormats_IndicationMessageFormat2{ 92 | IndicationMessageFormat2: &e2smkpmv2.E2SmKpmIndicationMessageFormat2{ 93 | SubscriptId: &e2smkpmv2.SubscriptionId{ 94 | Value: message.subscriptionID, 95 | }, 96 | CellObjId: &e2smkpmv2.CellObjectId{ 97 | Value: message.cellObjID, 98 | }, 99 | GranulPeriod: &e2smkpmv2.GranularityPeriod{ 100 | Value: int64(message.granularity), 101 | }, 102 | MeasCondUeidList: message.measCondUEList, 103 | MeasData: message.measData, 104 | }, 105 | }, 106 | }, 107 | } 108 | 109 | // FIXME: Add back when ready 110 | //if err := e2SmKpmPdu.Validate(); err != nil { 111 | // return nil, fmt.Errorf("error validating E2SmKpmPDU %s", err.Error()) 112 | //} 113 | return &e2SmKpmPdu, nil 114 | } 115 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/kpm2/labelinfo/labelinfo_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package labelinfo 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestNewLabelInfo(t *testing.T) { 14 | labelInfo, err := NewLabelInfo(WithFiveQI(200)) 15 | assert.NoError(t, err) 16 | assert.Equal(t, int32(200), labelInfo.fiveQI) 17 | 18 | } 19 | 20 | func TestWrongFiveQI(t *testing.T) { 21 | _, err := NewLabelInfo(WithFiveQI(400)) 22 | assert.Error(t, err) 23 | 24 | } 25 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/kpm2/measobjectitem/cell_meas_object_item.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package measobjectitem 6 | 7 | import ( 8 | e2smkpmv2 "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_kpm_v2_go/v2/e2sm-kpm-v2-go" 9 | ) 10 | 11 | // CellMeasObjectItem cell measurement object item 12 | type CellMeasObjectItem struct { 13 | cellObjID string 14 | cellGlobalID *e2smkpmv2.CellGlobalId 15 | } 16 | 17 | // NewCellMeasObjectItem create new cell measurement object item 18 | func NewCellMeasObjectItem(options ...func(*CellMeasObjectItem)) *CellMeasObjectItem { 19 | cellMeasObjectItem := &CellMeasObjectItem{} 20 | for _, option := range options { 21 | option(cellMeasObjectItem) 22 | } 23 | 24 | return cellMeasObjectItem 25 | } 26 | 27 | // WithCellObjectID sets cell object ID 28 | func WithCellObjectID(cellObjID string) func(item *CellMeasObjectItem) { 29 | return func(item *CellMeasObjectItem) { 30 | item.cellObjID = cellObjID 31 | } 32 | } 33 | 34 | // WithCellGlobalID sets cell global ID 35 | func WithCellGlobalID(cellGlobalID *e2smkpmv2.CellGlobalId) func(item *CellMeasObjectItem) { 36 | return func(item *CellMeasObjectItem) { 37 | item.cellGlobalID = cellGlobalID 38 | } 39 | } 40 | 41 | // Build builds a cell measurement object item 42 | func (c *CellMeasObjectItem) Build() *e2smkpmv2.CellMeasurementObjectItem { 43 | return &e2smkpmv2.CellMeasurementObjectItem{ 44 | CellObjectId: &e2smkpmv2.CellObjectId{ 45 | Value: c.cellObjID, 46 | }, 47 | CellGlobalId: c.cellGlobalID, 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/kpm2/measurments/mean_info_action_item.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package measurments 6 | 7 | import e2smkpmv2 "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_kpm_v2_go/v2/e2sm-kpm-v2-go" 8 | 9 | // MeasurementInfoActionItem measurement info action item 10 | type MeasurementInfoActionItem struct { 11 | measTypeName string 12 | measTypeID int32 13 | } 14 | 15 | // NewMeasurementInfoActionItem creates a new measurement info action item 16 | func NewMeasurementInfoActionItem(options ...func(item *MeasurementInfoActionItem)) *MeasurementInfoActionItem { 17 | measInfoActionItem := &MeasurementInfoActionItem{} 18 | for _, option := range options { 19 | option(measInfoActionItem) 20 | } 21 | 22 | return measInfoActionItem 23 | } 24 | 25 | // WithMeasTypeName sets measurement type name 26 | func WithMeasTypeName(measTypeName string) func(item *MeasurementInfoActionItem) { 27 | return func(item *MeasurementInfoActionItem) { 28 | item.measTypeName = measTypeName 29 | } 30 | } 31 | 32 | // WithMeasTypeID sets measurement type ID 33 | func WithMeasTypeID(measTypeID int32) func(item *MeasurementInfoActionItem) { 34 | return func(item *MeasurementInfoActionItem) { 35 | item.measTypeID = measTypeID 36 | } 37 | } 38 | 39 | // Build builds measurement info action item 40 | func (m *MeasurementInfoActionItem) Build() (*e2smkpmv2.MeasurementInfoActionItem, error) { 41 | return &e2smkpmv2.MeasurementInfoActionItem{ 42 | MeasName: &e2smkpmv2.MeasurementTypeName{ 43 | Value: m.measTypeName, 44 | }, 45 | MeasId: &e2smkpmv2.MeasurementTypeId{ 46 | Value: m.measTypeID, 47 | }, 48 | }, nil 49 | } 50 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/kpm2/measurments/meas_info_item.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package measurments 6 | 7 | import ( 8 | e2smkpmv2 "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_kpm_v2_go/v2/e2sm-kpm-v2-go" 9 | ) 10 | 11 | // MeasurementInfoItem measurement info item 12 | type MeasurementInfoItem struct { 13 | measType *e2smkpmv2.MeasurementType 14 | labelInfoList *e2smkpmv2.LabelInfoList 15 | } 16 | 17 | // NewMeasurementInfoItem creates a new measurement info item 18 | func NewMeasurementInfoItem(options ...func(item *MeasurementInfoItem)) *MeasurementInfoItem { 19 | measInfoItem := &MeasurementInfoItem{} 20 | for _, option := range options { 21 | option(measInfoItem) 22 | } 23 | 24 | return measInfoItem 25 | } 26 | 27 | // WithMeasType sets measurement type 28 | func WithMeasType(measType *e2smkpmv2.MeasurementType) func(item *MeasurementInfoItem) { 29 | return func(item *MeasurementInfoItem) { 30 | item.measType = measType 31 | } 32 | } 33 | 34 | // WithLabelInfoList sets label info list 35 | func WithLabelInfoList(labelInfoList *e2smkpmv2.LabelInfoList) func(item *MeasurementInfoItem) { 36 | return func(item *MeasurementInfoItem) { 37 | item.labelInfoList = labelInfoList 38 | } 39 | } 40 | 41 | // Build builds measurement info item 42 | func (m *MeasurementInfoItem) Build() (*e2smkpmv2.MeasurementInfoItem, error) { 43 | item := e2smkpmv2.MeasurementInfoItem{ 44 | MeasType: m.measType, 45 | LabelInfoList: m.labelInfoList, 46 | } 47 | 48 | // FIXME: Add back when ready 49 | //if err := item.Validate(); err != nil { 50 | // return nil, errors.New(errors.Invalid, err.Error()) 51 | //} 52 | 53 | return &item, nil 54 | } 55 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/kpm2/measurments/measurement_data_item.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package measurments 6 | 7 | import ( 8 | e2smkpmv2 "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_kpm_v2_go/v2/e2sm-kpm-v2-go" 9 | ) 10 | 11 | // MeasurementDataItem measurement data item 12 | type MeasurementDataItem struct { 13 | mr *e2smkpmv2.MeasurementRecord 14 | incompleteFlag e2smkpmv2.IncompleteFlag 15 | } 16 | 17 | // NewMeasurementDataItem creates a new measurement data item 18 | func NewMeasurementDataItem(options ...func(item *MeasurementDataItem)) *MeasurementDataItem { 19 | measDataItem := &MeasurementDataItem{} 20 | for _, option := range options { 21 | option(measDataItem) 22 | } 23 | 24 | return measDataItem 25 | } 26 | 27 | // WithMeasurementRecord sets measurement record 28 | func WithMeasurementRecord(mr *e2smkpmv2.MeasurementRecord) func(item *MeasurementDataItem) { 29 | return func(item *MeasurementDataItem) { 30 | item.mr = mr 31 | } 32 | } 33 | 34 | // WithIncompleteFlag sets incomplete flag 35 | func WithIncompleteFlag(incompleteFlag e2smkpmv2.IncompleteFlag) func(item *MeasurementDataItem) { 36 | return func(item *MeasurementDataItem) { 37 | item.incompleteFlag = incompleteFlag 38 | } 39 | } 40 | 41 | // Build builds a measurement data item 42 | func (m *MeasurementDataItem) Build() (*e2smkpmv2.MeasurementDataItem, error) { 43 | mdi := e2smkpmv2.MeasurementDataItem{ 44 | MeasRecord: m.mr, 45 | IncompleteFlag: &m.incompleteFlag, 46 | } 47 | 48 | // FIXME: Add back when ready 49 | //if err := mdi.Validate(); err != nil { 50 | // return nil, errors.New(errors.Invalid, err.Error()) 51 | //} 52 | return &mdi, nil 53 | } 54 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/kpm2/measurments/measurement_item.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package measurments 6 | 7 | import ( 8 | e2smkpmv2 "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_kpm_v2_go/v2/e2sm-kpm-v2-go" 9 | ) 10 | 11 | // MeasurementRecordItemInteger measurement record item integer 12 | type MeasurementRecordItemInteger struct { 13 | value int64 14 | } 15 | 16 | // NewMeasurementRecordItemInteger creates a new measurement record item integer 17 | func NewMeasurementRecordItemInteger(options ...func(integer *MeasurementRecordItemInteger)) *MeasurementRecordItemInteger { 18 | measRecordItemInteger := &MeasurementRecordItemInteger{} 19 | for _, option := range options { 20 | option(measRecordItemInteger) 21 | } 22 | 23 | return measRecordItemInteger 24 | } 25 | 26 | // WithIntegerValue sets record item integer value 27 | func WithIntegerValue(value int64) func(integer *MeasurementRecordItemInteger) { 28 | return func(recordItem *MeasurementRecordItemInteger) { 29 | recordItem.value = value 30 | } 31 | } 32 | 33 | // Build builds a measurement record item integer 34 | func (m *MeasurementRecordItemInteger) Build() *e2smkpmv2.MeasurementRecordItem { 35 | return &e2smkpmv2.MeasurementRecordItem{ 36 | MeasurementRecordItem: &e2smkpmv2.MeasurementRecordItem_Integer{ 37 | Integer: m.value, 38 | }, 39 | } 40 | } 41 | 42 | // MeasurementRecordItemReal measurement record item real 43 | type MeasurementRecordItemReal struct { 44 | value float64 45 | } 46 | 47 | // NewMeasurementRecordItemReal creates a new measurement record item real 48 | func NewMeasurementRecordItemReal(options ...func(integer *MeasurementRecordItemReal)) *MeasurementRecordItemReal { 49 | measRecordItemReal := &MeasurementRecordItemReal{} 50 | for _, option := range options { 51 | option(measRecordItemReal) 52 | } 53 | 54 | return measRecordItemReal 55 | } 56 | 57 | // WithRealValue sets record item integer value 58 | func WithRealValue(value float64) func(integer *MeasurementRecordItemReal) { 59 | return func(recordItem *MeasurementRecordItemReal) { 60 | recordItem.value = value 61 | } 62 | } 63 | 64 | // Build builds measurement record item real 65 | func (m *MeasurementRecordItemReal) Build() *e2smkpmv2.MeasurementRecordItem { 66 | return &e2smkpmv2.MeasurementRecordItem{ 67 | MeasurementRecordItem: &e2smkpmv2.MeasurementRecordItem_Real{ 68 | Real: m.value, 69 | }, 70 | } 71 | } 72 | 73 | // NewMeasurementRecordItemNoValue create new measurement record item no value 74 | func NewMeasurementRecordItemNoValue() *e2smkpmv2.MeasurementRecordItem { 75 | return &e2smkpmv2.MeasurementRecordItem{ 76 | MeasurementRecordItem: &e2smkpmv2.MeasurementRecordItem_NoValue{ 77 | NoValue: 0, 78 | }, 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/kpm2/measurments/measurement_type.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package measurments 6 | 7 | import ( 8 | e2smkpmv2 "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_kpm_v2_go/v2/e2sm-kpm-v2-go" 9 | ) 10 | 11 | // MeasurementTypeMeasName measurement type meas name 12 | type MeasurementTypeMeasName struct { 13 | Name string 14 | } 15 | 16 | // NewMeasurementTypeMeasName creates a new measurement type meas name 17 | func NewMeasurementTypeMeasName(options ...func(*MeasurementTypeMeasName)) *MeasurementTypeMeasName { 18 | measTypeName := &MeasurementTypeMeasName{} 19 | for _, option := range options { 20 | option(measTypeName) 21 | } 22 | 23 | return measTypeName 24 | } 25 | 26 | // WithMeasurementName sets measurement name 27 | func WithMeasurementName(name string) func(*MeasurementTypeMeasName) { 28 | return func(measurementName *MeasurementTypeMeasName) { 29 | measurementName.Name = name 30 | } 31 | 32 | } 33 | 34 | // Build builds measurement type meas name 35 | func (m *MeasurementTypeMeasName) Build() (*e2smkpmv2.MeasurementType, error) { 36 | measType := e2smkpmv2.MeasurementType{ 37 | MeasurementType: &e2smkpmv2.MeasurementType_MeasName{ 38 | MeasName: &e2smkpmv2.MeasurementTypeName{ 39 | Value: m.Name, 40 | }, 41 | }, 42 | } 43 | 44 | // FIXME: Add back when ready 45 | //if err := measType.Validate(); err != nil { 46 | // return nil, errors.New(errors.Invalid, err.Error()) 47 | //} 48 | 49 | return &measType, nil 50 | } 51 | 52 | // MeasurementTypeMeasID measurement type meas ID 53 | type MeasurementTypeMeasID struct { 54 | ID int32 55 | } 56 | 57 | // NewMeasurementTypeMeasID creates a new measurement type meas ID 58 | func NewMeasurementTypeMeasID(options ...func(id *MeasurementTypeMeasID)) *MeasurementTypeMeasID { 59 | measTypeID := &MeasurementTypeMeasID{} 60 | for _, option := range options { 61 | option(measTypeID) 62 | } 63 | 64 | return measTypeID 65 | } 66 | 67 | // Build builds a measurement type meas ID 68 | func (m *MeasurementTypeMeasID) Build() (*e2smkpmv2.MeasurementType, error) { 69 | measType := e2smkpmv2.MeasurementType{ 70 | MeasurementType: &e2smkpmv2.MeasurementType_MeasId{ 71 | MeasId: &e2smkpmv2.MeasurementTypeId{ 72 | Value: m.ID, 73 | }, 74 | }, 75 | } 76 | 77 | // FIXME: Add back when ready 78 | //if err := measType.Validate(); err != nil { 79 | // return nil, errors.New(errors.Invalid, err.Error()) 80 | //} 81 | 82 | return &measType, nil 83 | } 84 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/kpm2/nodeitem/node_item.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package nodeitem 6 | 7 | import ( 8 | e2smkpmv2 "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_kpm_v2_go/v2/e2sm-kpm-v2-go" 9 | ) 10 | 11 | // NodeItem kpm node it 12 | type NodeItem struct { 13 | globalKPMNodeID *e2smkpmv2.GlobalKpmnodeId 14 | cellMeasObjectItems []*e2smkpmv2.CellMeasurementObjectItem 15 | } 16 | 17 | // NewNodeItem creates new kpm node item 18 | func NewNodeItem(options ...func(item *NodeItem)) *NodeItem { 19 | nodeItem := &NodeItem{} 20 | for _, option := range options { 21 | option(nodeItem) 22 | } 23 | 24 | return nodeItem 25 | } 26 | 27 | // WithGlobalKpmNodeID sets global KPM Node ID 28 | func WithGlobalKpmNodeID(globalKPMNodeID *e2smkpmv2.GlobalKpmnodeId) func(item *NodeItem) { 29 | return func(item *NodeItem) { 30 | item.globalKPMNodeID = globalKPMNodeID 31 | } 32 | } 33 | 34 | // WithCellMeasurementObjectItems sets cell measurement object items 35 | func WithCellMeasurementObjectItems(cellMeasObjectItems []*e2smkpmv2.CellMeasurementObjectItem) func(item *NodeItem) { 36 | return func(item *NodeItem) { 37 | item.cellMeasObjectItems = cellMeasObjectItems 38 | } 39 | } 40 | 41 | // Build builds global kpm node item 42 | func (item *NodeItem) Build() *e2smkpmv2.RicKpmnodeItem { 43 | return &e2smkpmv2.RicKpmnodeItem{ 44 | RicKpmnodeType: item.globalKPMNodeID, 45 | CellMeasurementObjectList: item.cellMeasObjectItems, 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/kpm2/reportstyle/report_style_item.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package reportstyle 6 | 7 | import ( 8 | e2smkpmv2 "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_kpm_v2_go/v2/e2sm-kpm-v2-go" 9 | ) 10 | 11 | // Item Report style Item fields 12 | type Item struct { 13 | ricStyleType int32 14 | ricStyleName string 15 | ricFormatType int32 16 | measInfoActionList *e2smkpmv2.MeasurementInfoActionList 17 | indicationHdrFormatType int32 18 | indicationMsgFormatType int32 19 | } 20 | 21 | // NewReportStyleItem create new report style item 22 | func NewReportStyleItem(options ...func(item *Item)) *Item { 23 | reportStyleItem := &Item{} 24 | for _, option := range options { 25 | option(reportStyleItem) 26 | } 27 | 28 | return reportStyleItem 29 | } 30 | 31 | // WithRICStyleType sets RIC style type 32 | func WithRICStyleType(ricStyleType int32) func(item *Item) { 33 | return func(item *Item) { 34 | item.ricStyleType = ricStyleType 35 | } 36 | } 37 | 38 | // WithRICStyleName sets RIC style name 39 | func WithRICStyleName(ricStyleName string) func(item *Item) { 40 | return func(item *Item) { 41 | item.ricStyleName = ricStyleName 42 | } 43 | } 44 | 45 | // WithRICFormatType sets RIC format type 46 | func WithRICFormatType(ricFormatType int32) func(item *Item) { 47 | return func(item *Item) { 48 | item.ricFormatType = ricFormatType 49 | } 50 | } 51 | 52 | // WithMeasInfoActionList sets meas info list 53 | func WithMeasInfoActionList(measInfoActionList *e2smkpmv2.MeasurementInfoActionList) func(item *Item) { 54 | return func(item *Item) { 55 | item.measInfoActionList = measInfoActionList 56 | } 57 | } 58 | 59 | // WithIndicationHdrFormatType sets indication header format type 60 | func WithIndicationHdrFormatType(indicationHdrFormatType int32) func(item *Item) { 61 | return func(item *Item) { 62 | item.indicationHdrFormatType = indicationHdrFormatType 63 | } 64 | } 65 | 66 | // WithIndicationMsgFormatType sets indication message format type 67 | func WithIndicationMsgFormatType(indicationMsgFormatType int32) func(item *Item) { 68 | return func(item *Item) { 69 | item.indicationMsgFormatType = indicationMsgFormatType 70 | } 71 | } 72 | 73 | // Build builds RIC report style item 74 | func (i *Item) Build() *e2smkpmv2.RicReportStyleItem { 75 | return &e2smkpmv2.RicReportStyleItem{ 76 | RicReportStyleType: &e2smkpmv2.RicStyleType{ 77 | Value: i.ricStyleType, 78 | }, 79 | RicReportStyleName: &e2smkpmv2.RicStyleName{ 80 | Value: i.ricStyleName, 81 | }, 82 | RicActionFormatType: &e2smkpmv2.RicFormatType{ 83 | Value: i.ricFormatType, 84 | }, 85 | MeasInfoActionList: i.measInfoActionList, 86 | RicIndicationHeaderFormatType: &e2smkpmv2.RicFormatType{ 87 | Value: i.indicationHdrFormatType, 88 | }, 89 | RicIndicationMessageFormatType: &e2smkpmv2.RicFormatType{ 90 | Value: i.indicationMsgFormatType, 91 | }, 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/mho/indication/header/indication_header.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package header 6 | 7 | import ( 8 | "fmt" 9 | e2smmhosm "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_mho_go/servicemodel" 10 | e2smv2ies "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_mho_go/v2/e2sm-v2-ies" 11 | "github.com/onosproject/onos-lib-go/api/asn1/v1/asn1" 12 | 13 | ransimtypes "github.com/onosproject/onos-api/go/onos/ransim/types" 14 | 15 | "google.golang.org/protobuf/proto" 16 | 17 | mho "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_mho_go/v2/e2sm-mho-go" 18 | "github.com/onosproject/onos-lib-go/pkg/logging" 19 | ) 20 | 21 | var log = logging.GetLogger("sm", "mho") 22 | 23 | // Header indication header for mho service model 24 | type Header struct { 25 | plmnID ransimtypes.Uint24 26 | nrCellIdentity []byte 27 | } 28 | 29 | // NewIndicationHeader creates a new indication header 30 | func NewIndicationHeader(options ...func(header *Header)) *Header { 31 | header := &Header{} 32 | for _, option := range options { 33 | option(header) 34 | } 35 | 36 | return header 37 | } 38 | 39 | // WithPlmnID sets plmnID 40 | func WithPlmnID(plmnID ransimtypes.Uint24) func(header *Header) { 41 | return func(header *Header) { 42 | header.plmnID = plmnID 43 | 44 | } 45 | } 46 | 47 | // WithNrcellIdentity sets nrCellIdentity 48 | func WithNrcellIdentity(nrCellIdentity []byte) func(header *Header) { 49 | return func(header *Header) { 50 | header.nrCellIdentity = nrCellIdentity 51 | } 52 | } 53 | 54 | // Build builds indication header for mho service model 55 | func (header *Header) Build() (*mho.E2SmMhoIndicationHeader, error) { 56 | E2SmMhoPdu := mho.E2SmMhoIndicationHeader{ 57 | E2SmMhoIndicationHeader: &mho.E2SmMhoIndicationHeader_IndicationHeaderFormat1{ 58 | IndicationHeaderFormat1: &mho.E2SmMhoIndicationHeaderFormat1{ 59 | Cgi: &e2smv2ies.Cgi{ 60 | Cgi: &e2smv2ies.Cgi_NRCgi{ 61 | NRCgi: &e2smv2ies.NrCgi{ 62 | PLmnidentity: &e2smv2ies.PlmnIdentity{ 63 | Value: header.plmnID.ToBytes(), 64 | }, 65 | NRcellIdentity: &e2smv2ies.NrcellIdentity{ 66 | Value: &asn1.BitString{ 67 | //ToDo - should be of type []byte 68 | Value: header.nrCellIdentity, //uint64 69 | Len: 36, //uint32 70 | }, 71 | }, 72 | }, 73 | }, 74 | }, 75 | }, 76 | }, 77 | } 78 | 79 | if err := E2SmMhoPdu.Validate(); err != nil { 80 | return nil, fmt.Errorf("error validating E2SmMhoPDU %s", err.Error()) 81 | } 82 | return &E2SmMhoPdu, nil 83 | 84 | } 85 | 86 | // MhoToAsn1Bytes converts header to asn1 bytes 87 | func (header *Header) MhoToAsn1Bytes() ([]byte, error) { 88 | log.Debug("MhoToAsn1Bytes") 89 | // Creating an indication header 90 | indicationHeader, err := header.Build() 91 | if err != nil { 92 | return nil, err 93 | } 94 | 95 | indicationHeaderProtoBytes, err := proto.Marshal(indicationHeader) 96 | if err != nil { 97 | return nil, err 98 | } 99 | 100 | var mhoServiceModel e2smmhosm.MhoServiceModel 101 | indicationHeaderAsn1Bytes, err := mhoServiceModel.IndicationHeaderProtoToASN1(indicationHeaderProtoBytes) 102 | 103 | if err != nil { 104 | return nil, err 105 | } 106 | return indicationHeaderAsn1Bytes, nil 107 | } 108 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/mho/indication/header/indication_header_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package header 6 | 7 | import ( 8 | "encoding/hex" 9 | "testing" 10 | 11 | ransimtypes "github.com/onosproject/onos-api/go/onos/ransim/types" 12 | 13 | "github.com/stretchr/testify/assert" 14 | ) 15 | 16 | func TestCreateIndicationHeader(t *testing.T) { 17 | plmnID := ransimtypes.NewUint24(12345) 18 | indicationHeader := NewIndicationHeader(WithPlmnID(plmnID.Value()), WithNrcellIdentity([]byte{0xAA, 0xBB, 0xCC, 0xDD, 0xE0})) 19 | assert.NotNil(t, indicationHeader) 20 | assert.Equal(t, indicationHeader.plmnID.String(), plmnID.String()) 21 | assert.Equal(t, indicationHeader.nrCellIdentity, []byte{0xAA, 0xBB, 0xCC, 0xDD, 0xE0}) 22 | 23 | aper, err := indicationHeader.MhoToAsn1Bytes() 24 | assert.NoError(t, err) 25 | t.Logf("E2SM-MHO-IndicationHeader APER bytes are\n%v", hex.Dump(aper)) 26 | } 27 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/mho/indication/message_format1/indication_message.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package messageformat1 6 | 7 | import ( 8 | "fmt" 9 | e2smmhosm "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_mho_go/servicemodel" 10 | mho "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_mho_go/v2/e2sm-mho-go" 11 | e2smv2ies "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_mho_go/v2/e2sm-v2-ies" 12 | "github.com/onosproject/onos-lib-go/api/asn1/v1/asn1" 13 | "google.golang.org/protobuf/proto" 14 | ) 15 | 16 | // Message indication message fields for MHO service model 17 | type Message struct { 18 | ueID int64 19 | MeasReport []*mho.E2SmMhoMeasurementReportItem 20 | } 21 | 22 | // NewIndicationMessage creates a new indication message 23 | func NewIndicationMessage(options ...func(msg *Message)) *Message { 24 | msg := &Message{} 25 | for _, option := range options { 26 | option(msg) 27 | } 28 | 29 | return msg 30 | } 31 | 32 | // WithUeID sets ueID 33 | func WithUeID(ueID int64) func(message *Message) { 34 | return func(message *Message) { 35 | message.ueID = ueID 36 | } 37 | } 38 | 39 | // WithMeasReport sets measReport 40 | func WithMeasReport(measReport []*mho.E2SmMhoMeasurementReportItem) func(message *Message) { 41 | return func(message *Message) { 42 | message.MeasReport = measReport 43 | } 44 | } 45 | 46 | // Build builds indication message for MHO service model 47 | func (message *Message) Build() (*mho.E2SmMhoIndicationMessage, error) { 48 | e2SmIndicationMsg := mho.E2SmMhoIndicationMessage_IndicationMessageFormat1{ 49 | IndicationMessageFormat1: &mho.E2SmMhoIndicationMessageFormat1{ 50 | UeId: &e2smv2ies.Ueid{ 51 | Ueid: &e2smv2ies.Ueid_GNbUeid{ 52 | GNbUeid: &e2smv2ies.UeidGnb{ 53 | AmfUeNgapId: &e2smv2ies.AmfUeNgapId{ 54 | Value: message.ueID, 55 | }, 56 | // ToDo - move out GUAMI hardcoding 57 | Guami: &e2smv2ies.Guami{ 58 | PLmnidentity: &e2smv2ies.PlmnIdentity{ 59 | Value: []byte{0xAA, 0xBB, 0xCC}, 60 | }, 61 | AMfregionId: &e2smv2ies.AmfregionId{ 62 | Value: &asn1.BitString{ 63 | Value: []byte{0xDD}, 64 | Len: 8, 65 | }, 66 | }, 67 | AMfsetId: &e2smv2ies.AmfsetId{ 68 | Value: &asn1.BitString{ 69 | Value: []byte{0xCC, 0xC0}, 70 | Len: 10, 71 | }, 72 | }, 73 | AMfpointer: &e2smv2ies.Amfpointer{ 74 | Value: &asn1.BitString{ 75 | Value: []byte{0xFC}, 76 | Len: 6, 77 | }, 78 | }, 79 | }, 80 | }, 81 | }, 82 | }, 83 | MeasReport: message.MeasReport, 84 | }, 85 | } 86 | 87 | E2SmMhoPdu := mho.E2SmMhoIndicationMessage{ 88 | E2SmMhoIndicationMessage: &e2SmIndicationMsg, 89 | } 90 | 91 | if err := E2SmMhoPdu.Validate(); err != nil { 92 | return nil, fmt.Errorf("error validating E2SmPDU %s", err.Error()) 93 | } 94 | return &E2SmMhoPdu, nil 95 | 96 | } 97 | 98 | // ToAsn1Bytes converts to Asn1 bytes 99 | func (message *Message) ToAsn1Bytes() ([]byte, error) { 100 | indicationMessage, err := message.Build() 101 | if err != nil { 102 | return nil, err 103 | } 104 | indicationMessageProtoBytes, err := proto.Marshal(indicationMessage) 105 | if err != nil { 106 | return nil, err 107 | } 108 | 109 | var mhoServiceModel e2smmhosm.MhoServiceModel 110 | indicationMessageAsn1Bytes, err := mhoServiceModel.IndicationMessageProtoToASN1(indicationMessageProtoBytes) 111 | if err != nil { 112 | return nil, err 113 | } 114 | 115 | return indicationMessageAsn1Bytes, nil 116 | } 117 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/mho/indication/message_format1/indication_message_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package messageformat1 6 | 7 | import ( 8 | "encoding/hex" 9 | "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_mho_go/pdubuilder" 10 | e2sm_mho_go "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_mho_go/v2/e2sm-mho-go" 11 | "github.com/onosproject/onos-lib-go/api/asn1/v1/asn1" 12 | "testing" 13 | 14 | "github.com/stretchr/testify/assert" 15 | ) 16 | 17 | func TestCreateIndicationMessage(t *testing.T) { 18 | 19 | cgi, err := pdubuilder.CreateCgiNrCGI([]byte{0xAA, 0xFD, 0xD4}, &asn1.BitString{ 20 | Value: []byte{0x00, 0x00, 0x00, 0x40, 0x00}, 21 | Len: 36, 22 | }) 23 | assert.NoError(t, err) 24 | rsrp := &e2sm_mho_go.Rsrp{ 25 | Value: 1234, 26 | } 27 | measItem, err := pdubuilder.CreateMeasurementRecordItem(cgi, rsrp) 28 | assert.NoError(t, err) 29 | measItem.SetFiveQi(21) 30 | measReport := make([]*e2sm_mho_go.E2SmMhoMeasurementReportItem, 0) 31 | measReport = append(measReport, measItem) 32 | 33 | indicationMessage := NewIndicationMessage(WithUeID(1), WithMeasReport(measReport)) 34 | assert.NotNil(t, indicationMessage) 35 | assert.Equal(t, indicationMessage.ueID, int64(1)) 36 | assert.Equal(t, len(indicationMessage.MeasReport), 1) 37 | assert.Equal(t, indicationMessage.MeasReport[0].GetFiveQi().GetValue(), int32(21)) 38 | 39 | aper, err := indicationMessage.ToAsn1Bytes() 40 | assert.NoError(t, err) 41 | t.Logf("E2SM-MHO-IndicationMessage (Format 1) APER bytes are\n%v", hex.Dump(aper)) 42 | } 43 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/mho/indication/message_format2/indication_message_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package messageformat2 6 | 7 | import ( 8 | "encoding/hex" 9 | "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_mho_go/pdubuilder" 10 | "testing" 11 | 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | func TestCreateIndicationMessage(t *testing.T) { 16 | 17 | indicationMessage := NewIndicationMessage(WithUeID(1), WithRrcStatus(pdubuilder.CreateRrcStatusConnected()), WithGuami(uint64(12345), 10, 18 | 11, 12)) 19 | assert.NotNil(t, indicationMessage) 20 | assert.Equal(t, indicationMessage.ueID, int64(1)) 21 | assert.Equal(t, indicationMessage.RrcStatus.Number(), pdubuilder.CreateRrcStatusConnected().Number()) 22 | 23 | aper, err := indicationMessage.ToAsn1Bytes() 24 | assert.NoError(t, err) 25 | t.Logf("E2SM-MHO-IndicationMessage (Format 2) APER bytes are\n%v", hex.Dump(aper)) 26 | } 27 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/mho/ranfundesc/ranfuncdesc.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package ranfundesc 6 | 7 | import ( 8 | "fmt" 9 | mho "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_mho_go/v2/e2sm-mho-go" 10 | e2smv2ies "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_mho_go/v2/e2sm-v2-ies" 11 | ) 12 | 13 | // RANFunctionDescription ran function description 14 | type RANFunctionDescription struct { 15 | ranFunctionShortName string 16 | ranFunctionE2SmOID string 17 | ranFunctionDescription string 18 | ranFunctionInstance int32 19 | ricEventTriggerStyleList []*mho.RicEventTriggerStyleList 20 | ricReportStyleList []*mho.RicReportStyleList 21 | } 22 | 23 | // NewRANFunctionDescription creates a new RAN function description 24 | func NewRANFunctionDescription(options ...func(description *RANFunctionDescription)) *RANFunctionDescription { 25 | desc := &RANFunctionDescription{} 26 | for _, option := range options { 27 | option(desc) 28 | } 29 | return desc 30 | } 31 | 32 | // WithRANFunctionShortName sets ran parameter ID 33 | func WithRANFunctionShortName(shortName string) func(description *RANFunctionDescription) { 34 | return func(description *RANFunctionDescription) { 35 | description.ranFunctionShortName = shortName 36 | 37 | } 38 | } 39 | 40 | // WithRANFunctionE2SmOID sets OID 41 | func WithRANFunctionE2SmOID(oid string) func(description *RANFunctionDescription) { 42 | return func(description *RANFunctionDescription) { 43 | description.ranFunctionE2SmOID = oid 44 | 45 | } 46 | } 47 | 48 | // WithRANFunctionDescription sets ran function description 49 | func WithRANFunctionDescription(ranFuncDesc string) func(description *RANFunctionDescription) { 50 | return func(description *RANFunctionDescription) { 51 | description.ranFunctionDescription = ranFuncDesc 52 | 53 | } 54 | } 55 | 56 | // WithRANFunctionInstance sets ran function instance 57 | func WithRANFunctionInstance(instance int32) func(description *RANFunctionDescription) { 58 | return func(description *RANFunctionDescription) { 59 | description.ranFunctionInstance = instance 60 | } 61 | } 62 | 63 | // WithRICEventTriggerStyleList sets RIC event trigger style list 64 | func WithRICEventTriggerStyleList(ricEventTriggerStyleList []*mho.RicEventTriggerStyleList) func(description *RANFunctionDescription) { 65 | return func(description *RANFunctionDescription) { 66 | description.ricEventTriggerStyleList = ricEventTriggerStyleList 67 | 68 | } 69 | } 70 | 71 | // WithRICReportStyleList sets RIC report style list 72 | func WithRICReportStyleList(ricReportStyleList []*mho.RicReportStyleList) func(description *RANFunctionDescription) { 73 | return func(description *RANFunctionDescription) { 74 | description.ricReportStyleList = ricReportStyleList 75 | 76 | } 77 | } 78 | 79 | // Build builds RAN function description 80 | func (desc *RANFunctionDescription) Build() (*mho.E2SmMhoRanfunctionDescription, error) { 81 | e2smMhoPdu := mho.E2SmMhoRanfunctionDescription{ 82 | RanFunctionName: &e2smv2ies.RanfunctionName{ 83 | RanFunctionShortName: desc.ranFunctionShortName, 84 | RanFunctionE2SmOid: desc.ranFunctionE2SmOID, 85 | RanFunctionDescription: desc.ranFunctionDescription, 86 | RanFunctionInstance: &desc.ranFunctionInstance, 87 | }, 88 | E2SmMhoRanfunctionItem: &mho.E2SmMhoRanfunctionDescription_E2SmMhoRanfunctionItem001{ 89 | RicEventTriggerStyleList: desc.ricEventTriggerStyleList, 90 | RicReportStyleList: desc.ricReportStyleList, 91 | }, 92 | } 93 | 94 | if err := e2smMhoPdu.Validate(); err != nil { 95 | return nil, fmt.Errorf("error validating E2SmPDU %s", err.Error()) 96 | } 97 | return &e2smMhoPdu, nil 98 | } 99 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/rc/controloutcome/control_outcome.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package controloutcome 6 | 7 | import ( 8 | e2smrcpresm "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc_pre_go/servicemodel" 9 | "google.golang.org/protobuf/proto" 10 | 11 | e2smrcpreies "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc_pre_go/v2/e2sm-rc-pre-v2-go" 12 | ) 13 | 14 | // ControlOutcome required fields for control outcome 15 | type ControlOutcome struct { 16 | ranParameterID int32 17 | } 18 | 19 | // NewControlOutcome creates a new control outcome 20 | func NewControlOutcome(options ...func(outcome *ControlOutcome)) *ControlOutcome { 21 | outcome := &ControlOutcome{} 22 | for _, option := range options { 23 | option(outcome) 24 | } 25 | return outcome 26 | } 27 | 28 | // WithRanParameterID sets ran parameter ID 29 | func WithRanParameterID(ranParameterID int32) func(co *ControlOutcome) { 30 | return func(co *ControlOutcome) { 31 | co.ranParameterID = ranParameterID 32 | 33 | } 34 | } 35 | 36 | // Build builds rc control outcome message 37 | func (co *ControlOutcome) Build() (*e2smrcpreies.E2SmRcPreControlOutcome, error) { 38 | e2smRcPreOutcomeFormat1 := e2smrcpreies.E2SmRcPreControlOutcomeFormat1{ 39 | OutcomeElementList: make([]*e2smrcpreies.RanparameterItem, 0), 40 | } 41 | outcomeElementList := &e2smrcpreies.RanparameterItem{ 42 | RanParameterId: &e2smrcpreies.RanparameterId{ 43 | Value: co.ranParameterID, 44 | }, 45 | } 46 | e2smRcPreOutcomeFormat1.OutcomeElementList = append(e2smRcPreOutcomeFormat1.OutcomeElementList, outcomeElementList) 47 | e2smRcPrePdu := e2smrcpreies.E2SmRcPreControlOutcome{ 48 | E2SmRcPreControlOutcome: &e2smrcpreies.E2SmRcPreControlOutcome_ControlOutcomeFormat1{ 49 | ControlOutcomeFormat1: &e2smRcPreOutcomeFormat1, 50 | }, 51 | } 52 | 53 | //ToDo - return it back once the Validation is functional again 54 | //if err := e2smRcPrePdu.Validate(); err != nil { 55 | // return nil, fmt.Errorf("error validating E2SmPDU %s", err.Error()) 56 | //} 57 | return &e2smRcPrePdu, nil 58 | 59 | } 60 | 61 | // ToAsn1Bytes converts to Asn1 bytes 62 | func (co *ControlOutcome) ToAsn1Bytes() ([]byte, error) { 63 | outcomeRcMessage, err := co.Build() 64 | if err != nil { 65 | return nil, err 66 | } 67 | outcomeProtoBytes, err := proto.Marshal(outcomeRcMessage) 68 | if err != nil { 69 | return nil, err 70 | } 71 | 72 | var rcPreServiceModel e2smrcpresm.RcPreServiceModel 73 | outcomeAsn1Bytes, err := rcPreServiceModel.ControlOutcomeProtoToASN1(outcomeProtoBytes) 74 | if err != nil { 75 | return nil, err 76 | } 77 | 78 | return outcomeAsn1Bytes, nil 79 | } 80 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/rc/indication/header/indication_header.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package header 6 | 7 | import ( 8 | e2smrcpresm "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc_pre_go/servicemodel" 9 | "github.com/onosproject/onos-lib-go/api/asn1/v1/asn1" 10 | 11 | "github.com/onosproject/ran-simulator/pkg/utils" 12 | 13 | ransimtypes "github.com/onosproject/onos-api/go/onos/ransim/types" 14 | 15 | "google.golang.org/protobuf/proto" 16 | 17 | e2smrcpreies "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc_pre_go/v2/e2sm-rc-pre-v2-go" 18 | ) 19 | 20 | // Header indication header for rc service model 21 | type Header struct { 22 | plmnID ransimtypes.Uint24 23 | eutraCellIdentity uint64 24 | } 25 | 26 | // NewIndicationHeader creates a new indication header 27 | func NewIndicationHeader(options ...func(header *Header)) *Header { 28 | header := &Header{} 29 | for _, option := range options { 30 | option(header) 31 | } 32 | 33 | return header 34 | } 35 | 36 | // WithPlmnID sets plmnID 37 | func WithPlmnID(plmnID ransimtypes.Uint24) func(header *Header) { 38 | return func(header *Header) { 39 | header.plmnID = plmnID 40 | 41 | } 42 | } 43 | 44 | // WithNRcellIdentity sets NRcellIdentity 45 | func WithNRcellIdentity(nRcellIdentity uint64) func(header *Header) { 46 | return func(header *Header) { 47 | header.eutraCellIdentity = nRcellIdentity 48 | } 49 | } 50 | 51 | // Build builds indication header for rc service model 52 | func (header *Header) Build() (*e2smrcpreies.E2SmRcPreIndicationHeader, error) { 53 | E2SmRcPrePdu := e2smrcpreies.E2SmRcPreIndicationHeader{ 54 | E2SmRcPreIndicationHeader: &e2smrcpreies.E2SmRcPreIndicationHeader_IndicationHeaderFormat1{ 55 | IndicationHeaderFormat1: &e2smrcpreies.E2SmRcPreIndicationHeaderFormat1{ 56 | Cgi: &e2smrcpreies.CellGlobalId{ 57 | CellGlobalId: &e2smrcpreies.CellGlobalId_NrCgi{ 58 | NrCgi: &e2smrcpreies.Nrcgi{ 59 | PLmnIdentity: &e2smrcpreies.PlmnIdentity{ 60 | Value: header.plmnID.ToBytes(), 61 | }, 62 | NRcellIdentity: &e2smrcpreies.NrcellIdentity{ 63 | Value: &asn1.BitString{ 64 | Value: utils.Uint64ToBitString(header.eutraCellIdentity, 36), 65 | Len: 36, 66 | }, 67 | }, 68 | }, 69 | }, 70 | }, 71 | }, 72 | }, 73 | } 74 | 75 | //ToDo - return it back once the Validation is functional again 76 | //if err := E2SmRcPrePdu.Validate(); err != nil { 77 | // return nil, fmt.Errorf("error validating E2SmRcPrePDU %s", err.Error()) 78 | //} 79 | return &E2SmRcPrePdu, nil 80 | 81 | } 82 | 83 | // ToAsn1Bytes converts header to asn1 bytes 84 | func (header *Header) ToAsn1Bytes() ([]byte, error) { 85 | // Creating an indication header 86 | indicationHeader, err := header.Build() 87 | if err != nil { 88 | return nil, err 89 | } 90 | 91 | indicationHeaderProtoBytes, err := proto.Marshal(indicationHeader) 92 | if err != nil { 93 | return nil, err 94 | } 95 | 96 | var rcPreServiceModel e2smrcpresm.RcPreServiceModel 97 | indicationHeaderAsn1Bytes, err := rcPreServiceModel.IndicationHeaderProtoToASN1(indicationHeaderProtoBytes) 98 | 99 | if err != nil { 100 | return nil, err 101 | } 102 | return indicationHeaderAsn1Bytes, nil 103 | } 104 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/rc/indication/header/indication_header_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package header 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/onosproject/ran-simulator/pkg/utils" 11 | 12 | ransimtypes "github.com/onosproject/onos-api/go/onos/ransim/types" 13 | 14 | "github.com/stretchr/testify/assert" 15 | ) 16 | 17 | func TestCreateIndicationHeader(t *testing.T) { 18 | plmnID := ransimtypes.NewUint24(12345) 19 | indicationHeader, err := NewIndicationHeader(WithPlmnID(plmnID.Value()), 20 | WithNRcellIdentity(32)).Build() 21 | assert.NoError(t, err) 22 | 23 | assert.Equal(t, plmnID.ToBytes(), indicationHeader.GetIndicationHeaderFormat1().Cgi.GetNrCgi().PLmnIdentity.Value) 24 | assert.Equal(t, uint64(32), utils.BitStringToUint64(indicationHeader.GetIndicationHeaderFormat1().Cgi.GetNrCgi().NRcellIdentity.Value.GetValue(), 36)) 25 | 26 | } 27 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/rc/indication/message/indication_message_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package message 6 | 7 | import ( 8 | "testing" 9 | 10 | ransimtypes "github.com/onosproject/onos-api/go/onos/ransim/types" 11 | 12 | e2smrcpreies "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc_pre_go/v2/e2sm-rc-pre-v2-go" 13 | "github.com/onosproject/ran-simulator/pkg/utils/e2sm/rc/nrt" 14 | "github.com/stretchr/testify/assert" 15 | ) 16 | 17 | func TestCreateIndicationMessage(t *testing.T) { 18 | 19 | plmnID := ransimtypes.NewUint24(12345) 20 | nrt1, err := nrt.NewNeighbour( 21 | nrt.WithPci(10), 22 | nrt.WithNrcellIdentity(15), 23 | nrt.WithEarfcn(40), 24 | nrt.WithCellSize(e2smrcpreies.CellSize_CELL_SIZE_MACRO), 25 | nrt.WithPlmnID(plmnID.Value())).Build() 26 | assert.NoError(t, err) 27 | nrt2, err := nrt.NewNeighbour( 28 | nrt.WithPci(20), 29 | nrt.WithNrcellIdentity(25), 30 | nrt.WithEarfcn(50), 31 | nrt.WithCellSize(e2smrcpreies.CellSize_CELL_SIZE_FEMTO), 32 | nrt.WithPlmnID(plmnID.Value())).Build() 33 | assert.NoError(t, err) 34 | 35 | indicationMessage, err := NewIndicationMessage(WithPlmnID(plmnID.Value()), 36 | WithCellSize(e2smrcpreies.CellSize_CELL_SIZE_MACRO), 37 | WithEarfcn(20), 38 | WithPci(10), 39 | WithNeighbours([]*e2smrcpreies.Nrt{nrt1, nrt2})).Build() 40 | assert.NoError(t, err) 41 | 42 | assert.Equal(t, indicationMessage.GetIndicationMessageFormat1().Neighbors[0].Pci.GetValue(), int32(10)) 43 | 44 | } 45 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/rc/nrt/nrt_message.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package nrt 6 | 7 | import ( 8 | "github.com/onosproject/onos-lib-go/api/asn1/v1/asn1" 9 | 10 | "github.com/onosproject/ran-simulator/pkg/utils" 11 | 12 | ransimtypes "github.com/onosproject/onos-api/go/onos/ransim/types" 13 | e2smrcpreies "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc_pre_go/v2/e2sm-rc-pre-v2-go" 14 | ) 15 | 16 | // Neighbour neighbour fields for nrt message 17 | type Neighbour struct { 18 | plmnID ransimtypes.Uint24 19 | nRCellIdentity uint64 20 | earfcn int32 21 | pci int32 22 | cellSize e2smrcpreies.CellSize 23 | } 24 | 25 | // NewNeighbour creates a new neighbour message 26 | func NewNeighbour(options ...func(nrb *Neighbour)) *Neighbour { 27 | nrb := &Neighbour{} 28 | for _, option := range options { 29 | option(nrb) 30 | } 31 | 32 | return nrb 33 | } 34 | 35 | // WithPlmnID sets plmnID 36 | func WithPlmnID(plmnID ransimtypes.Uint24) func(neighbour *Neighbour) { 37 | return func(neighbour *Neighbour) { 38 | neighbour.plmnID = plmnID 39 | } 40 | } 41 | 42 | // WithNrcellIdentity sets NrcellIdentity 43 | func WithNrcellIdentity(nRcellIdentity uint64) func(neighbour *Neighbour) { 44 | return func(neighbour *Neighbour) { 45 | neighbour.nRCellIdentity = nRcellIdentity 46 | } 47 | } 48 | 49 | // WithEarfcn sets earfcn 50 | func WithEarfcn(earfcn int32) func(neighbour *Neighbour) { 51 | return func(neighbour *Neighbour) { 52 | neighbour.earfcn = earfcn 53 | } 54 | } 55 | 56 | // WithPci sets pci 57 | func WithPci(pci int32) func(neighbour *Neighbour) { 58 | return func(neighbour *Neighbour) { 59 | neighbour.pci = pci 60 | } 61 | } 62 | 63 | // WithCellSize sets cell size 64 | func WithCellSize(cellSize e2smrcpreies.CellSize) func(neighbour *Neighbour) { 65 | return func(neighbour *Neighbour) { 66 | neighbour.cellSize = cellSize 67 | } 68 | } 69 | 70 | // Build builds Nrt message for RC service model 71 | func (neighbour *Neighbour) Build() (*e2smrcpreies.Nrt, error) { 72 | nrtMsg := &e2smrcpreies.Nrt{ 73 | Cgi: &e2smrcpreies.CellGlobalId{ 74 | CellGlobalId: &e2smrcpreies.CellGlobalId_NrCgi{ 75 | NrCgi: &e2smrcpreies.Nrcgi{ 76 | PLmnIdentity: &e2smrcpreies.PlmnIdentity{ 77 | Value: neighbour.plmnID.ToBytes(), 78 | }, 79 | NRcellIdentity: &e2smrcpreies.NrcellIdentity{ 80 | Value: &asn1.BitString{ 81 | Value: utils.Uint64ToBitString(neighbour.nRCellIdentity, 36), 82 | Len: 36, 83 | }, 84 | }, 85 | }, 86 | }, 87 | }, 88 | Pci: &e2smrcpreies.Pci{ 89 | Value: neighbour.pci, 90 | }, 91 | CellSize: neighbour.cellSize, 92 | DlArfcn: &e2smrcpreies.Arfcn{ 93 | Arfcn: &e2smrcpreies.Arfcn_EArfcn{ 94 | EArfcn: &e2smrcpreies.Earfcn{ 95 | Value: neighbour.earfcn, 96 | }, 97 | }, 98 | }, 99 | } 100 | 101 | //ToDo - return it back once the Validation is functional again 102 | //if err := nrtMsg.Validate(); err != nil { 103 | // return nil, fmt.Errorf("error validating E2SmPDU %s", err.Error()) 104 | //} 105 | return nrtMsg, nil 106 | } 107 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/rc/v1/indication/headers/format1/format1.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022-present Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package format1 6 | 7 | import ( 8 | "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc/pdubuilder" 9 | e2smrcsm "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc/servicemodel" 10 | e2smrcies "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc/v1/e2sm-rc-ies" 11 | "google.golang.org/protobuf/proto" 12 | ) 13 | 14 | // Header indication header format 1 15 | type Header struct { 16 | eventTriggerConditionID int32 17 | } 18 | 19 | // NewIndicationHeader creates a new indication header 20 | func NewIndicationHeader(options ...func(header *Header)) *Header { 21 | header := &Header{} 22 | for _, option := range options { 23 | option(header) 24 | } 25 | 26 | return header 27 | } 28 | 29 | // WithEventConditionID sets event condition ID 30 | func WithEventConditionID(eventConditionID int32) func(header *Header) { 31 | return func(header *Header) { 32 | header.eventTriggerConditionID = eventConditionID 33 | } 34 | } 35 | 36 | // Build builds indication header format 1 37 | func (h *Header) Build() (*e2smrcies.E2SmRcIndicationHeader, error) { 38 | header, err := pdubuilder.CreateE2SmRcIndicationHeaderFormat1() 39 | if err != nil { 40 | return nil, err 41 | } 42 | if h.eventTriggerConditionID != 0 { 43 | header.GetRicIndicationHeaderFormats().GetIndicationHeaderFormat1().SetRicEventTriggerConditionID(h.eventTriggerConditionID) 44 | } 45 | 46 | return header, nil 47 | 48 | } 49 | 50 | // ToAsn1Bytes converts header to asn1 bytes 51 | func (h *Header) ToAsn1Bytes() ([]byte, error) { 52 | // Creating an indication header 53 | indicationHeader, err := h.Build() 54 | if err != nil { 55 | return nil, err 56 | } 57 | 58 | indicationHeaderProtoBytes, err := proto.Marshal(indicationHeader) 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | var rcServiceModel e2smrcsm.RCServiceModel 64 | indicationHeaderAsn1Bytes, err := rcServiceModel.IndicationHeaderProtoToASN1(indicationHeaderProtoBytes) 65 | 66 | if err != nil { 67 | return nil, err 68 | } 69 | return indicationHeaderAsn1Bytes, nil 70 | } 71 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/rc/v1/indication/headers/format2/format2.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022-present Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package format2 6 | 7 | import ( 8 | "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc/pdubuilder" 9 | e2smrcsm "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc/servicemodel" 10 | e2smcommonies "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc/v1/e2sm-common-ies" 11 | e2smrcies "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc/v1/e2sm-rc-ies" 12 | "google.golang.org/protobuf/proto" 13 | ) 14 | 15 | // Header indication header format 1 16 | type Header struct { 17 | ueID *e2smcommonies.Ueid 18 | ricInsertStyleType int32 19 | insertIndicationID int32 20 | } 21 | 22 | // NewIndicationHeader creates a new indication header 23 | func NewIndicationHeader(options ...func(header *Header)) *Header { 24 | header := &Header{} 25 | for _, option := range options { 26 | option(header) 27 | } 28 | 29 | return header 30 | } 31 | 32 | // WithUEID sets UE ID 33 | func WithUEID(ueID *e2smcommonies.Ueid) func(header *Header) { 34 | return func(header *Header) { 35 | header.ueID = ueID 36 | } 37 | } 38 | 39 | // WithRICInsertStyleType sets RIC Insert Style Type 40 | func WithRICInsertStyleType(style int32) func(header *Header) { 41 | return func(header *Header) { 42 | header.ricInsertStyleType = style 43 | } 44 | } 45 | 46 | // WithInsertIndicationID sets Insert Indication ID 47 | func WithInsertIndicationID(id int32) func(header *Header) { 48 | return func(header *Header) { 49 | header.insertIndicationID = id 50 | } 51 | } 52 | 53 | // Build builds indication header format 2 54 | func (h *Header) Build() (*e2smrcies.E2SmRcIndicationHeader, error) { 55 | header, err := pdubuilder.CreateE2SmRcIndicationHeaderFormat2(h.ueID, h.ricInsertStyleType, h.insertIndicationID) 56 | if err != nil { 57 | return nil, err 58 | } 59 | return header, nil 60 | } 61 | 62 | // ToAsn1Bytes converts Header to ASN.1 bytes 63 | func (h *Header) ToAsn1Bytes() ([]byte, error) { 64 | indicationHeader, err := h.Build() 65 | if err != nil { 66 | return nil, err 67 | } 68 | 69 | indicationHeaderProtoBytes, err := proto.Marshal(indicationHeader) 70 | if err != nil { 71 | return nil, err 72 | } 73 | 74 | var rcServiceModel e2smrcsm.RCServiceModel 75 | indicationHeaderAsn1Bytes, err := rcServiceModel.IndicationHeaderProtoToASN1(indicationHeaderProtoBytes) 76 | if err != nil { 77 | return nil, err 78 | } 79 | 80 | return indicationHeaderAsn1Bytes, nil 81 | } 82 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/rc/v1/indication/messages/format3/format3.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022-present Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package format3 6 | 7 | import ( 8 | "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc/pdubuilder" 9 | e2smrcsm "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc/servicemodel" 10 | e2smrcies "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc/v1/e2sm-rc-ies" 11 | "google.golang.org/protobuf/proto" 12 | ) 13 | 14 | // Message indication message fields for rc service model 15 | type Message struct { 16 | indicationMessageItems []*e2smrcies.E2SmRcIndicationMessageFormat3Item 17 | } 18 | 19 | // NewIndicationMessage creates a new indication message 20 | func NewIndicationMessage(options ...func(msg *Message)) *Message { 21 | msg := &Message{} 22 | for _, option := range options { 23 | option(msg) 24 | } 25 | 26 | return msg 27 | } 28 | 29 | // WithMessageItems sets indication message items 30 | func WithMessageItems(indicationMessageItems []*e2smrcies.E2SmRcIndicationMessageFormat3Item) func(message *Message) { 31 | return func(message *Message) { 32 | message.indicationMessageItems = indicationMessageItems 33 | } 34 | } 35 | 36 | // Build builds indication message for RC service model 37 | func (message *Message) Build() (*e2smrcies.E2SmRcIndicationMessage, error) { 38 | indicationMessage, err := pdubuilder.CreateE2SmRcIndicationMessageFormat3(message.indicationMessageItems) 39 | if err != nil { 40 | return nil, err 41 | } 42 | return indicationMessage, nil 43 | 44 | } 45 | 46 | // ToAsn1Bytes converts to Asn1 bytes 47 | func (message *Message) ToAsn1Bytes() ([]byte, error) { 48 | indicationMessage, err := message.Build() 49 | if err != nil { 50 | return nil, err 51 | } 52 | indicationMessageProtoBytes, err := proto.Marshal(indicationMessage) 53 | if err != nil { 54 | return nil, err 55 | } 56 | 57 | var rcServiceModel e2smrcsm.RCServiceModel 58 | indicationMessageAsn1Bytes, err := rcServiceModel.IndicationMessageProtoToASN1(indicationMessageProtoBytes) 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | return indicationMessageAsn1Bytes, nil 64 | } 65 | -------------------------------------------------------------------------------- /pkg/utils/e2sm/rc/v1/indication/messages/format5/format5.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022-present Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package format5 6 | 7 | import ( 8 | "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc/pdubuilder" 9 | e2smrcsm "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc/servicemodel" 10 | e2smrcies "github.com/onosproject/onos-e2-sm/servicemodels/e2sm_rc/v1/e2sm-rc-ies" 11 | "google.golang.org/protobuf/proto" 12 | ) 13 | 14 | // Message indication message fields for rc service model 15 | type Message struct { 16 | indicationMessageItems []*e2smrcies.E2SmRcIndicationMessageFormat5Item 17 | } 18 | 19 | // NewIndicationMessage creates a new indication message 20 | func NewIndicationMessage(options ...func(msg *Message)) *Message { 21 | msg := &Message{} 22 | for _, option := range options { 23 | option(msg) 24 | } 25 | 26 | return msg 27 | } 28 | 29 | // WithMessageItems sets indication message items 30 | func WithMessageItems(indicationMessageItems []*e2smrcies.E2SmRcIndicationMessageFormat5Item) func(message *Message) { 31 | return func(message *Message) { 32 | message.indicationMessageItems = indicationMessageItems 33 | } 34 | } 35 | 36 | // Build builds indication message for RC service model 37 | func (message *Message) Build() (*e2smrcies.E2SmRcIndicationMessage, error) { 38 | indicationMessage, err := pdubuilder.CreateE2SmRcIndicationMessageFormat5(message.indicationMessageItems) 39 | if err != nil { 40 | return nil, err 41 | } 42 | return indicationMessage, nil 43 | 44 | } 45 | 46 | // ToAsn1Bytes converts to Asn1 bytes 47 | func (message *Message) ToAsn1Bytes() ([]byte, error) { 48 | indicationMessage, err := message.Build() 49 | if err != nil { 50 | return nil, err 51 | } 52 | indicationMessageProtoBytes, err := proto.Marshal(indicationMessage) 53 | if err != nil { 54 | return nil, err 55 | } 56 | 57 | var rcServiceModel e2smrcsm.RCServiceModel 58 | indicationMessageAsn1Bytes, err := rcServiceModel.IndicationMessageProtoToASN1(indicationMessageProtoBytes) 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | return indicationMessageAsn1Bytes, nil 64 | } 65 | -------------------------------------------------------------------------------- /pkg/utils/geo.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | 6 | package utils 7 | 8 | import ( 9 | "github.com/onosproject/ran-simulator/pkg/model" 10 | "math" 11 | ) 12 | 13 | // Earth radius in meters 14 | const earthRadius = 6378100 15 | 16 | // See: http://en.wikipedia.org/wiki/Haversine_formula 17 | 18 | // Distance returns the distance in meters between two geo coordinates 19 | func Distance(c1 model.Coordinate, c2 model.Coordinate) float64 { 20 | var la1, lo1, la2, lo2 float64 21 | la1 = c1.Lat * math.Pi / 180 22 | lo1 = c1.Lng * math.Pi / 180 23 | la2 = c2.Lat * math.Pi / 180 24 | lo2 = c2.Lng * math.Pi / 180 25 | 26 | h := hsin(la2-la1) + math.Cos(la1)*math.Cos(la2)*hsin(lo2-lo1) 27 | 28 | return 2 * earthRadius * math.Asin(math.Sqrt(h)) 29 | } 30 | 31 | // TargetPoint returns the target coordinate specified distance and heading from the starting coordinate 32 | func TargetPoint(c model.Coordinate, bearing float64, dist float64) model.Coordinate { 33 | var la1, lo1, la2, lo2, azimuth, d float64 34 | la1 = c.Lat * math.Pi / 180 35 | lo1 = c.Lng * math.Pi / 180 36 | azimuth = bearing * math.Pi / 180 37 | d = dist / earthRadius 38 | 39 | la2 = math.Asin(math.Sin(la1)*math.Cos(d) + math.Cos(la1)*math.Sin(d)*math.Cos(azimuth)) 40 | lo2 = lo1 + math.Atan2(math.Sin(azimuth)*math.Sin(d)*math.Cos(la1), math.Cos(d)-math.Sin(la1)*math.Sin(la2)) 41 | 42 | return model.Coordinate{Lat: la2 * 180 / math.Pi, Lng: lo2 * 180 / math.Pi} 43 | } 44 | 45 | // InitialBearing returns initial bearing from c1 to c2 46 | func InitialBearing(c1 model.Coordinate, c2 model.Coordinate) float64 { 47 | var la1, lo1, la2, lo2 float64 48 | la1 = c1.Lat * math.Pi / 180 49 | lo1 = c1.Lng * math.Pi / 180 50 | la2 = c2.Lat * math.Pi / 180 51 | lo2 = c2.Lng * math.Pi / 180 52 | 53 | y := math.Sin(lo2-lo1) * math.Cos(la2) 54 | x := math.Cos(la1)*math.Sin(la2) - math.Sin(la1)*math.Cos(la2)*math.Cos(lo2-lo1) 55 | theta := math.Atan2(y, x) 56 | return math.Mod(theta*180/math.Pi+360, 360.0) // in degrees 57 | } 58 | 59 | func hsin(theta float64) float64 { 60 | return math.Pow(math.Sin(theta/2), 2) 61 | } 62 | -------------------------------------------------------------------------------- /pkg/utils/gnb_id_type.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022-present Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package utils 6 | 7 | // GNbIDBytes is a type for gNB ID 8 | type GNbIDBytes [4]byte 9 | 10 | const ( 11 | // MaxGNbID22 is a max gNB ID in 22 bits 12 | MaxGNbID22 = 1<<23 - 1 13 | // MaxGNbID32 is a max gNB ID in 32 bits 14 | MaxGNbID32 = 1<<33 - 1 15 | ) 16 | 17 | // NewGNbIDWithUint64 creates gNB ID 18 | func NewGNbIDWithUint64(val uint64, length int) *GNbIDBytes { 19 | id := new(GNbIDBytes) 20 | id.Set(val, length) 21 | return id 22 | } 23 | 24 | // Set sets gNB ID with a given length 25 | func (b *GNbIDBytes) Set(val uint64, length int) { 26 | if length != 32 && length != 22 { 27 | return 28 | } else if length == 22 && val > MaxGNbID22 { 29 | return 30 | } else if length == 32 && val > MaxGNbID32 { 31 | return 32 | } 33 | 34 | (*b)[0] = byte(val & 0xFF) 35 | (*b)[1] = byte(val >> 8 & 0xFF) 36 | (*b)[2] = byte(val >> 16 & 0xFF) 37 | (*b)[3] = byte(val >> 24 & 0xFF) 38 | } 39 | 40 | // Value returns GNbIDBytes 41 | func (b *GNbIDBytes) Value() GNbIDBytes { 42 | return *b 43 | } 44 | 45 | // Bytes returns byte array types for GNbIDByte 46 | func (b *GNbIDBytes) Bytes(length int) []byte { 47 | if length == 22 { 48 | val := make([]byte, 3) 49 | val[0] = (*b)[0] 50 | val[1] = (*b)[1] 51 | val[2] = (*b)[2] 52 | return val 53 | } else if length == 32 { 54 | val := make([]byte, 4) 55 | val[0] = (*b)[0] 56 | val[1] = (*b)[1] 57 | val[2] = (*b)[2] 58 | val[3] = (*b)[3] 59 | return val 60 | } 61 | return nil 62 | } 63 | 64 | // Uint64 returns GNbIDBytes as uint64 type 65 | func (b *GNbIDBytes) Uint64() uint64 { 66 | return uint64((*b)[0]) + (uint64((*b)[1]) << 8) + (uint64((*b)[2]) << 16) + (uint64((*b)[3]) << 24) 67 | } 68 | 69 | // GNbID is a gNB ID type 70 | type GNbID struct { 71 | IDByte *GNbIDBytes 72 | Length int 73 | } 74 | 75 | // NewGNbID creates gNB ID 76 | func NewGNbID(val uint64, length int) *GNbID { 77 | return &GNbID{ 78 | IDByte: NewGNbIDWithUint64(val, length), 79 | Length: length, 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /pkg/utils/honeycomb/README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Honeycomb Utility 8 | 9 | The `sample.yaml` file was produced using the following command: 10 | 11 | ``` 12 | go run cmd/honeycomb/honeycomb.go topo --plmnid 314628 --towers 10 pkg/utils/honeycomb/sample.yaml 13 | ``` -------------------------------------------------------------------------------- /pkg/utils/measurement/qoffsetrange.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package utils 6 | 7 | import ( 8 | meastype "github.com/onosproject/rrm-son-lib/pkg/model/measurement/type" 9 | "sort" 10 | ) 11 | 12 | // QOffsetRange is a struct for QOffsetRanges element 13 | type QOffsetRange struct { 14 | Min int32 15 | Max int32 16 | Value meastype.QOffsetRange 17 | } 18 | 19 | // QOffsetRanges is the list type of QOffsetRange 20 | type QOffsetRanges []QOffsetRange 21 | 22 | // Len returns length 23 | func (q QOffsetRanges) Len() int { 24 | return len(q) 25 | } 26 | 27 | // Less checks if i is less than j 28 | func (q QOffsetRanges) Less(i, j int) bool { 29 | return q[i].Min < q[j].Min 30 | } 31 | 32 | // Swap swaps two values 33 | func (q QOffsetRanges) Swap(i, j int) { 34 | q[i], q[j] = q[j], q[i] 35 | } 36 | 37 | // Sort sorts the list 38 | func (q QOffsetRanges) Sort() { 39 | sort.Sort(q) 40 | } 41 | 42 | // Search returns an appropriate value satisfying a condition 43 | func (q QOffsetRanges) Search(v int32) meastype.QOffsetRange { 44 | length := q.Len() 45 | if i := sort.Search(length, func(i int) bool { return v < q[i].Max }); i < length { 46 | if it := &q[i]; v >= it.Min && v < it.Max { 47 | return it.Value 48 | } 49 | } 50 | return meastype.QOffset0dB 51 | } 52 | -------------------------------------------------------------------------------- /pkg/utils/measurement/tttrange.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package utils 6 | 7 | import ( 8 | meastype "github.com/onosproject/rrm-son-lib/pkg/model/measurement/type" 9 | "sort" 10 | ) 11 | 12 | // TimeToTriggerRange is a struct for TimeToTriggerRanges element 13 | type TimeToTriggerRange struct { 14 | Min int32 15 | Max int32 16 | Value meastype.TimeToTriggerRange 17 | } 18 | 19 | // TimeToTriggerRanges is the list type of TimeToTriggerRange 20 | type TimeToTriggerRanges []TimeToTriggerRange 21 | 22 | // Len returns length 23 | func (t TimeToTriggerRanges) Len() int { 24 | return len(t) 25 | } 26 | 27 | // Less checks if i is less than j 28 | func (t TimeToTriggerRanges) Less(i, j int) bool { 29 | return t[i].Min < t[j].Min 30 | } 31 | 32 | // Swap swaps two values 33 | func (t TimeToTriggerRanges) Swap(i, j int) { 34 | t[i], t[j] = t[j], t[i] 35 | } 36 | 37 | // Sort sorts the list 38 | func (t TimeToTriggerRanges) Sort() { 39 | sort.Sort(t) 40 | } 41 | 42 | // Search returns an appropriate value satisfying a condition 43 | func (t TimeToTriggerRanges) Search(v int32) meastype.TimeToTriggerRange { 44 | length := t.Len() 45 | if i := sort.Search(length, func(i int) bool { return v < t[i].Max }); i < length { 46 | if it := &t[i]; v >= it.Min && v < it.Max { 47 | return it.Value 48 | } 49 | } 50 | return meastype.TTT0ms 51 | } 52 | -------------------------------------------------------------------------------- /pkg/utils/ncell_id_type.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package utils 6 | 7 | // NCellID NCellID type 8 | type NCellID [5]byte 9 | 10 | const ( 11 | // MaxNCellID maximum value of NCellID variable 12 | MaxNCellID = 1<<40 - 1 13 | ) 14 | 15 | // NewNCellIDWithUint64 creates a new NCellID type with UInt64 16 | func NewNCellIDWithUint64(val uint64) *NCellID { 17 | id := new(NCellID) 18 | id.Set(val) 19 | return id 20 | } 21 | 22 | // NewNCellIDWithBytes creates a new NCellID type with bytes 23 | func NewNCellIDWithBytes(val []byte) *NCellID { 24 | id := new(NCellID) 25 | id[0] = val[0] 26 | id[1] = val[1] 27 | id[2] = val[2] 28 | id[3] = val[3] 29 | id[4] = val[4] 30 | return id 31 | } 32 | 33 | // Set sets NCellID 34 | func (n *NCellID) Set(val uint64) { 35 | if val > MaxNCellID { 36 | return 37 | } 38 | (*n)[0] = byte(val & 0xFF) 39 | (*n)[1] = byte(val >> 8 & 0xFF) 40 | (*n)[2] = byte(val >> 16 & 0xFF) 41 | (*n)[3] = byte(val >> 24 & 0xFF) 42 | (*n)[4] = byte(val >> 32 & 0xFF) 43 | } 44 | 45 | // Value returns NCellID value 46 | func (n *NCellID) Value() NCellID { 47 | return *n 48 | } 49 | 50 | // Bytes converts NCellID to byte array 51 | func (n *NCellID) Bytes() []byte { 52 | val := make([]byte, 5) 53 | val[0] = (*n)[0] 54 | val[1] = (*n)[1] 55 | val[2] = (*n)[2] 56 | val[3] = (*n)[3] 57 | val[4] = (*n)[4] 58 | return val 59 | } 60 | 61 | // Uint64 converts NCellID to uint64 62 | func (n *NCellID) Uint64() uint64 { 63 | return uint64((*n)[0]) + (uint64((*n)[1]) << 8) + (uint64((*n)[2]) << 16) + (uint64((*n)[3]) << 24) + (uint64((*n)[4]) << 32) 64 | } 65 | -------------------------------------------------------------------------------- /pkg/utils/utils_test.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | // 5 | 6 | package utils 7 | 8 | import ( 9 | "math" 10 | "testing" 11 | 12 | "github.com/onosproject/onos-api/go/onos/ransim/types" 13 | "gotest.tools/assert" 14 | ) 15 | 16 | const ( 17 | PosCenLat = 52.12345 18 | PosCenLng = 13.12345 19 | Pos1Lat = 52.12350 20 | Pos1Lng = 13.12350 21 | Pos2Lat = 52.12340 22 | Pos2Lng = 13.12340 23 | ) 24 | 25 | func Test_GetRotationDegrees(t *testing.T) { 26 | centre := types.Point{ 27 | Lat: PosCenLat, 28 | Lng: PosCenLng, 29 | } 30 | p1 := types.Point{ 31 | Lat: Pos1Lat, 32 | Lng: Pos1Lng, 33 | } 34 | p2 := types.Point{ 35 | Lat: Pos2Lat, 36 | Lng: Pos2Lng, 37 | } 38 | p3 := types.Point{ 39 | Lat: Pos2Lat, 40 | Lng: Pos1Lng, 41 | } 42 | p4 := types.Point{ 43 | Lat: Pos1Lat, 44 | Lng: Pos2Lng, 45 | } 46 | r1 := GetRotationDegrees(¢re, &p1) 47 | assert.Equal(t, 45.0, math.Round(r1), "Unexpected r1") 48 | 49 | r2 := GetRotationDegrees(¢re, &p2) 50 | assert.Equal(t, -135.0, math.Round(r2), "Unexpected r2") 51 | 52 | r3 := GetRotationDegrees(¢re, &p3) 53 | assert.Equal(t, -45.0, math.Round(r3), "Unexpected r3") 54 | 55 | r4 := GetRotationDegrees(¢re, &p4) 56 | assert.Equal(t, 135.0, math.Round(r4), "Unexpected r4") 57 | } 58 | 59 | func Test_RandomColor(t *testing.T) { 60 | c := RandomColor() 61 | assert.Equal(t, 7, len(c)) 62 | assert.Equal(t, uint8('#'), c[0]) 63 | } 64 | 65 | func Test_GetRandomLngLat(t *testing.T) { 66 | const scale = 0.2 67 | for i := 0; i < 100; i++ { 68 | pt := RandomLatLng(0.0, 0.0, scale, 1) 69 | assert.Assert(t, pt.GetLat() < scale, "Expecting position %f to be within scale", pt.GetLat()) 70 | } 71 | } 72 | 73 | func Test_AzimuthToRads(t *testing.T) { 74 | assert.Equal(t, math.Pi/2, AzimuthToRads(0)) 75 | assert.Equal(t, 0.0, AzimuthToRads(90)) 76 | assert.Equal(t, -math.Pi/2, AzimuthToRads(180)) 77 | assert.Equal(t, -math.Pi, AzimuthToRads(270)) 78 | assert.Equal(t, math.Round(10e6*math.Pi/3), math.Round(10e6*AzimuthToRads(30))) 79 | } 80 | 81 | func Test_AspectRatio(t *testing.T) { 82 | ar := AspectRatio(52.52) 83 | assert.Equal(t, 608, int(math.Round(ar*1e3))) 84 | } 85 | -------------------------------------------------------------------------------- /tests/e2t/connections.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package e2t 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | 12 | "github.com/onosproject/ran-simulator/tests/utils" 13 | ) 14 | 15 | // TestConnections test connectivity between e2 agents and e2t 16 | func (s *TestSuite) TestConnections(t *testing.T) { 17 | connections, err := utils.GetE2Connections() 18 | assert.NoError(t, err, "unable to connect to E2T admin service %v", err) 19 | assert.Equal(t, 2, len(connections), "incorrect connection count") 20 | } 21 | -------------------------------------------------------------------------------- /tests/e2t/suite.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package e2t 6 | 7 | import ( 8 | "github.com/onosproject/helmit/pkg/input" 9 | "github.com/onosproject/helmit/pkg/test" 10 | "github.com/onosproject/ran-simulator/tests/utils" 11 | ) 12 | 13 | // TestSuite is the primary ran-simulator test suite 14 | type TestSuite struct { 15 | test.Suite 16 | } 17 | 18 | // SetupTestSuite sets up the ran-simulator test suite 19 | func (s *TestSuite) SetupTestSuite(c *input.Context) error { 20 | sdran, err := utils.CreateSdranRelease(c) 21 | if err != nil { 22 | return err 23 | } 24 | err = sdran.Install(true) 25 | if err != nil { 26 | return err 27 | } 28 | 29 | // Create an instance of the simulator 30 | simulator := utils.CreateRanSimulatorWithName(c, "ran-simulator") 31 | return simulator.Install(true) 32 | } 33 | -------------------------------------------------------------------------------- /tests/ransim/count_cells.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package ransim 6 | 7 | import ( 8 | "context" 9 | "io" 10 | "testing" 11 | 12 | modelapi "github.com/onosproject/onos-api/go/onos/ransim/model" 13 | 14 | "github.com/stretchr/testify/assert" 15 | 16 | "github.com/onosproject/ran-simulator/tests/utils" 17 | ) 18 | 19 | // TestCountCells tests if there is the correct number of cells 20 | func (s *TestSuite) TestCountCells(t *testing.T) { 21 | cells, err := getCells() 22 | assert.NoError(t, err, "unable to connect to Ransim cell service %v", err) 23 | assert.Equal(t, 6, len(cells)) 24 | } 25 | 26 | func getCells() ([]*modelapi.ListCellsResponse, error) { 27 | client, err := utils.NewRansimCellClient() 28 | if err != nil { 29 | return nil, err 30 | } 31 | stream, err := client.ListCells(context.Background(), &modelapi.ListCellsRequest{}) 32 | if err != nil { 33 | return nil, err 34 | } 35 | 36 | connections := make([]*modelapi.ListCellsResponse, 0) 37 | for { 38 | resp, err := stream.Recv() 39 | if err == io.EOF { 40 | break 41 | } else if err == nil { 42 | connections = append(connections, resp) 43 | } 44 | } 45 | return connections, err 46 | } 47 | -------------------------------------------------------------------------------- /tests/ransim/count_nodes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package ransim 6 | 7 | import ( 8 | "context" 9 | "io" 10 | "testing" 11 | 12 | modelapi "github.com/onosproject/onos-api/go/onos/ransim/model" 13 | 14 | "github.com/stretchr/testify/assert" 15 | 16 | "github.com/onosproject/ran-simulator/tests/utils" 17 | ) 18 | 19 | // TestCountNodes tests if there is the correct number of nodes 20 | func (s *TestSuite) TestCountNodes(t *testing.T) { 21 | nodes, err := getNodes() 22 | assert.NoError(t, err, "unable to connect to Ransim node service %v", err) 23 | assert.Equal(t, 2, len(nodes)) 24 | } 25 | 26 | func getNodes() ([]*modelapi.ListNodesResponse, error) { 27 | client, err := utils.NewRansimNodeClient() 28 | if err != nil { 29 | return nil, err 30 | } 31 | stream, err := client.ListNodes(context.Background(), &modelapi.ListNodesRequest{}) 32 | if err != nil { 33 | return nil, err 34 | } 35 | 36 | connections := make([]*modelapi.ListNodesResponse, 0) 37 | for { 38 | resp, err := stream.Recv() 39 | if err == io.EOF { 40 | break 41 | } else if err == nil { 42 | connections = append(connections, resp) 43 | } 44 | } 45 | return connections, err 46 | 47 | } 48 | -------------------------------------------------------------------------------- /tests/ransim/suite.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package ransim 6 | 7 | import ( 8 | "github.com/onosproject/helmit/pkg/input" 9 | "github.com/onosproject/helmit/pkg/test" 10 | "github.com/onosproject/ran-simulator/tests/utils" 11 | ) 12 | 13 | // TestSuite is the primary ran-simulator test suite 14 | type TestSuite struct { 15 | test.Suite 16 | } 17 | 18 | // SetupTestSuite sets up the ran-simulator test suite 19 | func (s *TestSuite) SetupTestSuite(c *input.Context) error { 20 | sdran, err := utils.CreateSdranRelease(c) 21 | if err != nil { 22 | return err 23 | } 24 | err = sdran.Install(true) 25 | if err != nil { 26 | return err 27 | } 28 | 29 | // Create an instance of the simulator 30 | simulator := utils.CreateRanSimulatorWithName(c, "ran-simulator") 31 | return simulator.Install(true) 32 | } 33 | -------------------------------------------------------------------------------- /tests/utils/e2tnodes.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package utils 6 | 7 | import ( 8 | "context" 9 | "io" 10 | 11 | e2tadmin "github.com/onosproject/onos-api/go/onos/e2t/admin" 12 | "github.com/onosproject/onos-ric-sdk-go/pkg/e2/creds" 13 | "google.golang.org/grpc" 14 | "google.golang.org/grpc/credentials" 15 | ) 16 | 17 | const ( 18 | e2tAddress = "onos-e2t:5150" 19 | ) 20 | 21 | // GetE2Connections returns the list of current connections obtained via E2T admin API 22 | func GetE2Connections() ([]*e2tadmin.ListE2NodeConnectionsResponse, error) { 23 | client, err := NewE2TAdminClient() 24 | if err != nil { 25 | return nil, err 26 | } 27 | 28 | stream, err := client.ListE2NodeConnections(context.Background(), &e2tadmin.ListE2NodeConnectionsRequest{}) 29 | if err != nil { 30 | return nil, err 31 | } 32 | 33 | connections := make([]*e2tadmin.ListE2NodeConnectionsResponse, 0) 34 | for { 35 | resp, err := stream.Recv() 36 | if err == io.EOF { 37 | break 38 | } else if err == nil { 39 | connections = append(connections, resp) 40 | } 41 | } 42 | return connections, err 43 | } 44 | 45 | // NewE2TAdminClient returns a client for engaging with the E2T admin API 46 | func NewE2TAdminClient() (e2tadmin.E2TAdminServiceClient, error) { 47 | tlsConfig, err := creds.GetClientCredentials() 48 | if err != nil { 49 | return nil, err 50 | } 51 | opts := []grpc.DialOption{ 52 | grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)), 53 | } 54 | 55 | conn, err := grpc.DialContext(context.Background(), e2tAddress, opts...) 56 | if err != nil { 57 | return nil, err 58 | } 59 | return e2tadmin.NewE2TAdminServiceClient(conn), nil 60 | } 61 | -------------------------------------------------------------------------------- /tests/utils/ransim.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package utils 6 | 7 | import ( 8 | "context" 9 | 10 | modelapi "github.com/onosproject/onos-api/go/onos/ransim/model" 11 | 12 | "github.com/onosproject/onos-ric-sdk-go/pkg/e2/creds" 13 | "google.golang.org/grpc" 14 | "google.golang.org/grpc/credentials" 15 | ) 16 | 17 | const ( 18 | ransimAddress = "ran-simulator:5150" 19 | ) 20 | 21 | // NewRansimConnection returns a connection for engaging with the ransim API 22 | func NewRansimConnection() (*grpc.ClientConn, error) { 23 | tlsConfig, err := creds.GetClientCredentials() 24 | if err != nil { 25 | return nil, err 26 | } 27 | opts := []grpc.DialOption{ 28 | grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)), 29 | } 30 | 31 | conn, err := grpc.DialContext(context.Background(), ransimAddress, opts...) 32 | if err != nil { 33 | return nil, err 34 | } 35 | return conn, nil 36 | } 37 | 38 | // NewRansimNodeClient returns a node model client 39 | func NewRansimNodeClient() (modelapi.NodeModelClient, error) { 40 | conn, err := NewRansimConnection() 41 | if err != nil { 42 | return nil, err 43 | } 44 | return modelapi.NewNodeModelClient(conn), nil 45 | } 46 | 47 | // NewRansimCellClient returns a cell model client 48 | func NewRansimCellClient() (modelapi.CellModelClient, error) { 49 | conn, err := NewRansimConnection() 50 | if err != nil { 51 | return nil, err 52 | } 53 | return modelapi.NewCellModelClient(conn), nil 54 | } 55 | -------------------------------------------------------------------------------- /tests/utils/sdran.go: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020-present Open Networking Foundation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package utils 6 | 7 | import ( 8 | "context" 9 | 10 | "github.com/onosproject/helmit/pkg/helm" 11 | "github.com/onosproject/helmit/pkg/input" 12 | "github.com/onosproject/helmit/pkg/kubernetes" 13 | "github.com/onosproject/helmit/pkg/util/random" 14 | "github.com/onosproject/onos-test/pkg/onostest" 15 | ) 16 | 17 | func getCredentials() (string, string, error) { 18 | kubClient, err := kubernetes.New() 19 | if err != nil { 20 | return "", "", err 21 | } 22 | secrets, err := kubClient.CoreV1().Secrets().Get(context.Background(), onostest.SecretsName) 23 | if err != nil { 24 | return "", "", err 25 | } 26 | username := string(secrets.Object.Data["sd-ran-username"]) 27 | password := string(secrets.Object.Data["sd-ran-password"]) 28 | 29 | return username, password, nil 30 | } 31 | 32 | // CreateSdranRelease creates a helm release for an sd-ran instance 33 | func CreateSdranRelease(c *input.Context) (*helm.HelmRelease, error) { 34 | username, password, err := getCredentials() 35 | registry := c.GetArg("registry").String("") 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | sdran := helm.Chart("sd-ran", onostest.SdranChartRepo). 41 | Release("sd-ran"). 42 | SetUsername(username). 43 | SetPassword(password). 44 | Set("global.image.registry", registry). 45 | Set("import.onos-config.enabled", false) 46 | 47 | return sdran, nil 48 | } 49 | 50 | // CreateRanSimulator creates a ran simulator 51 | func CreateRanSimulator(c *input.Context) *helm.HelmRelease { 52 | return CreateRanSimulatorWithName(c, random.NewPetName(2)) 53 | } 54 | 55 | // CreateRanSimulatorWithName creates a ran simulator 56 | func CreateRanSimulatorWithName(c *input.Context, name string) *helm.HelmRelease { 57 | username, password, _ := getCredentials() 58 | registry := c.GetArg("registry").String("") 59 | 60 | simulator := helm. 61 | Chart(name, onostest.SdranChartRepo). 62 | Release(name). 63 | SetUsername(username). 64 | SetPassword(password). 65 | Set("global.image.registry", registry). 66 | Set("image.tag", "latest") 67 | return simulator 68 | } 69 | --------------------------------------------------------------------------------