How to create your own SM?


Service models are the “contracts” that establish the allowed mechanisms and information by which near-RT RIC interacts with E2 nodes (e.g., CU/DU). O-RAN service models are defined in ASN.1 format, as they are used to be transported by SCTP from near-RT RIC to E2 nodes. In the SD-RAN project, internally the near-RT RIC implementation realizes the utilization of Service Models via gRPC, therefore the need for their definition in protobuf. In SD-RAN, the component responsible for the “translation” of ASN.1/SCTP to protobuf/gRPC format is onos-e2t. Therefore, xApps when implemented in SD-RAN utilize the library provided by the compilation of protobuf definitions of Service Models (SMs). To learn more about the definition of SMs in SD-RAN have a look at the readme of onos-e2-sm repository:

This tutorial defines how to write a Service Model and provide support for it in the SD-RAN project, so it can be utilized by the xApps for instance.

How to compile the SM from ASN1->protobuf->golang?

1. ASN.1 to Protobuf

1.1 You have to use the ONF’s distribution of the asn1c tool.

You can find it here:

Please, follow its installation steps. Once set, you can generate Protobuf out of asn1 definition using the -B option. The full command should look like:

asn1c -B my_sm.asn1 > my_sm.proto

After that, depending on which way of implementation you choose (CGo or with Go APER library), you should make some adjustments to the Protobuf file.

Note (implementation choices):

  • CGo - is the Go glue code which wraps C code generated by the asn1c tool.

    • SM with the CGo approach is complex on implementation and requires a lot of effort for maintenance (e.g., future upgrade of SM).

    • In CGo, Go doesn’t take care of garbage collection and memory leaks (due to the C code) may happen.

  • Go APER - is the Go package which implements APER encoder and decoder ( It is capable of converting the message in the APER bytes and decode the message from the APER bytes. This APER library is fully compatible with the asn1c tool.

    • Currently this is the best way to implement SM.

1.2 Make sure that the Protobuf messages in your generated Protobuf correspond to reference ones defined in the ASN.1 definition.

A good example is the Protobuf for MHO SM stored in onos-e2-sm repo.

For this tutorial, the MHO SM is being used as a reference example. So, please use as a reference the following Protobuf file:

Go APER requires the definition of tags marked as annotations in the message fields. Having these tags would help the Go APER library to correctly encode and decode the messages.

Currently, the automated definition of tags is not handled by the asn1c tool, but this feature is going to be implemented in the future.

It is necessary to insert all tags correctly, otherwise Go APER library wouldn’t be able to encode or decode the message correctly.

Here are some examples:

1.3 Add SM compilation commands into the Makefile

Embed your SM in the onos-e2-sm Makefile script to generate Protobuf with the make protos command (i.e., to facilitate the translation of the Protobuf to golang code, the proper references of packages are done using the makefile targets. In the case of SMs it is done using the commands protoc and protoc-go-inject-tag). Here is an example:

Don’t forget to create the target that calls the injection of all tag definitions from the Protobuf to the golang pb generated code, for instance:

1.3.1 Importance of protoc-gen-validate plugin.

You can benefit from protoc-gen-validate plugin, it can validate your messages and throw an error if you’ve the data inserted in your message are out of range, i.e., INTEGER has an upper bound of 255, for some reason 256 is passed instead – protoc-gen-validate will catch this error and notify you.

Asn1c tool already generates all necessary rules for this plugin, you only need to enable it in the compilation process. Here is an example on how to do that:

If it is enabled, you can then validate your messages in the following way:

Now you can run make protos, which will generate a Protobuf-based golang code of your SM.

The CGo way of implementing SMs is a legacy way now. A better (and easier) way to implement E2* is to use Go APER library:

You can refer to all SMs, the outcome of Go APER library, in the onos-e2-sm repo appended with _go to see how it’s done.

2. Create wrappers for encoder and decoder.

Each SM has a specific wrapper to encode each one of its messages to APER. You can find an example here, where all the MHO SM messages have defined their encoders:

Each definition of an SM message encoder file contains encode and decode functions associated with that message.

For example, the encoder for MHO-ControlHeader looks like that:

The encoding part is being invoked here:

Respectively, decoding is being done here:

Notice: as shown in line 24 of the file E2SM-MHO-ControlHeader.go, there is a mandatory prerequisite for marshaling (and unmarshaling). In MHO Control Header encoder look for the variable e2smmhov2.MhoChoicemap, this variable contains a map of all CHOICE structs, which are in your SM definition. Without that input, the encoder and decoder wouldn’t know which CHOICE option they’re expected to encode or decode (marshal or unmarshal a message).

The file containing the choice options, as mentioned above, can be automatically generated with a protoc-gen-choice plugin. Please study carefully the README in order to install and use this plugin:

The protoc-gen-choice tool is being modified to support the correct definitions of choices files, in the future this step is going to be added as another target in the Makefile.

Encoder/Decoder wrappers could be automatically generated via yet another protoc (Protobuf compiler) plugin modification. This implementation can be defined in a future release.

3. Create pdubuilders around it.

In general, pdubuilder should help to create messages in a faster way (i.e., to create the header and content of a message). A myriad of pdubuilders can be defined to facilitate the creation of messages. The goal of pdubuilders is to facilitate the utilization of the SM golang code by the xApp. There are certain patterns, which may lead to automation of the pdubuilder creation process. Currently, this is under investigation.

All MHO SM pdubuilders are stored here:

To outline, here are some examples provided below.

Top-level pdubuilder

Create some other helper functions which create specific/complex items:

All CHOICEs deserve their own wrappers! Like here one:

Some other helper functions are stored in a builder.go. This file contains Setter functions for all OPTIONAL items in your SM definition.

Auto generation of this file could be automated with a yet another protoc plugin.

4. Pack it as a plugin.

An example could be found here:

This is an implementation of a common plugin interface. It should correspond to the rest of the SMs.

5. Verify that encoding and decoding works with unit tests!

This is a fundamental step before you can start using your SM. Perfectly, each unit test should verify that Go APER library is able to encode the message without any errors and decode the generated set of APER bytes. Decoded message should be completely similar to the encoded one. A good example of such approach could be found here:

6. Publish the SM

Add the SM definitions (service model, proto, golang, encoder, etc) to the onos-e2-sm repository. Similar to other SMs already contained, create a golang module and push the code to the onos-e2-sm. Use the other SMs as reference to create the go.mod file and structure of folders/files.