本文目標
SBI 是由 3GPP 提出的 interface,除了 UPF 以外的 5G NF 都使用 SBI 溝通。
個人想法:
使用 REST-style API 以及 JSON 應該是為了可讀性,如果想要降低 SBI 的 Latency 或許可以嘗試非 3GPP 定義的作法,像是使用 gRPC 替代之類的。
根據 3GPP 的定義,NF 之間的溝通都會依據 SBI (Service Based Interface) 進行實作,以 Nudm_UECM (UECM) service 為例,其他使用該服務的 NF 為 Consumer,提供服務的 UDM 在這裡則扮演 Producer。
如果其他 NF 想要註冊該服務,只需要調用 Nudm_UECM_Registration 即可。
Description: Register UE’s serving NF (if NF Type is AMF, SMSF, or NWDAF) or Session’s serving NF (if NF Type is SMF) on the UDM.
SBI 讓 NF 之間可以使用一般的 http 請求溝通,並且 NF 在實作 Producer 的邏輯時,也可以採用 RestFul API 的設計。
參考上圖,SBA(Service Based Architecture)就是整個架構圖上方方格中的骨幹網路。
下方的三張圖片更細的介紹了核心網路中的 Network Functions 如何在 SBA 上溝通:
上圖的範例中,我們可以看到三個 Network Function:
先前的文章有介紹到 SBI 是採用 HTTP/2 protocol 作為傳輸協定。
與 HTTP/1.1 相比,它支援 Multiplexing 以及 Header 的壓縮演算法 (HPACK)。並且,HTTP/2 使用 Binary 的方式傳輸,更將節省流量開銷。
不只如此,SBI 更採用了 RESTful API 的設計,讓 NF 與 NF 之間可以使用 HTTP Verb (POST, GET, PUT, DELETE) 溝通,提供了格式統一、簡潔易懂的 URL 操作。
開放應用程式介面規格 (OAS,OpenAPI Specification) 是讓 Open API 得以被標準化的關鍵,OAS 原先名為 Swagger Specification,由一家名為 SmartBear 的軟體公司所發展,後由開放軟體社群及 Linux 合作贊助推動的 API 技術規格,開發出 OAS 國際標準。
OAS 定義了一套機器可讀的 API 規範,使其可以做更多元的應用。像是建立起互動式的 API 說明文件、產生靜態文件、產生客戶端/伺服器端程式碼架構等。由於 OAS 主要是以 YAML 或 JSON 格式來呈現,這樣的規格檔較為簡潔、輕便,讓我們在運用 OAS 的方式上,不受限於 top-down 或 bottom-up 的開發模式。
-- www.fisc.com.tw
3GPP 也採用了 OpenAPI 格式,讓開發者可以利用轉換工具產生專案的部分程式碼。
我們可以在 3GPP 的網站上找到相關文件與檔案,以 Nsmf_EventExposure 為例,其 OpenAPI 的 Yaml 檔可以在 TS 29.508 取得。
補充:
國外也有開發者針對 3GPP R15 與 R16 整理了 OpenAPI Specification Files,可以參考 5GC_APIs。
前面有提到 3GPP 提供了 OpenAPI Spec Files,有了這些檔案後就能夠搭配 OpenAPI generator 產生 API 相關的程式碼:
$ git clone https://github.com/jdegre/5GC_APIs.git
$ cd 5GC_APIs
$ docker run --rm -v ${PWD}:/local openapitools/openapi-generator-cli generate -i TS29522_5GLANParameterProvision.yaml -g go-gin-server -o /local/output
上面的範例使用 TS 29.522 5GLANParameterProvision
產生相關程式碼,執行完畢後可以使用以下命令檢查輸出的資料夾結構:
$ tree output
資料夾結構如下:
output
├── Dockerfile
├── api
│ └── openapi.yaml
├── go
│ ├── README.md
│ ├── api_class5_glan_parameters_provision_subscriptions.go
│ ├── api_individual5_glan_parameters_provision_subscription.go
│ ├── model_5_g_lan_parameters.go
│ ├── model_5_g_lan_parameters_patch.go
│ ├── model_5_g_lan_parameters_provision.go
│ ├── model_5_g_lan_parameters_provision_patch.go
│ ├── model_aaa_usage.go
│ ├── model_aaa_usage_any_of.go
│ ├── model_app_descriptor.go
│ ├── model_app_descriptor_rm.go
│ ├── model_invalid_param.go
│ ├── model_ipv6_addr.go
│ ├── model_pdu_session_type.go
│ ├── model_pdu_session_type_any_of.go
│ ├── model_problem_details.go
│ ├── model_snssai.go
│ └── routers.go
└── main.go
讓我們打開其中幾個檔案觀察輸出內容:
/*
* 3gpp-5glan-pp
*
* API for 5G LAN Parameter Provision. © 2022, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved.
*
* API version: 1.1.0-alpha.3
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
// Model5GLanParameters - Represents 5G LAN service related parameters that need to be provisioned.
type Model5GLanParameters struct {
// string containing a local identifier followed by \"@\" and a domain identifier. Both the local identifier and the domain identifier shall be encoded as strings that do not contain any \"@\" characters. See Clauses 4.6.2 and 4.6.3 of 3GPP TS 23.682 for more information.
ExterGroupId string `json:"exterGroupId"`
// Contains the list of 5G VN Group members, each member is identified by GPSI. Any string value can be used as a key of the map.
Gpsis map[string]string `json:"gpsis"`
// String representing a Data Network as defined in clause 9A of 3GPP TS 23.003; it shall contain either a DNN Network Identifier, or a full DNN with both the Network Identifier and Operator Identifier, as specified in 3GPP TS 23.003 clause 9.1.1 and 9.1.2. It shall be coded as string in which the labels are separated by dots (e.g. \"Label1.Label2.Label3\").
Dnn string `json:"dnn"`
// String identifying a IPv4 address formatted in the 'dotted decimal' notation as defined in RFC 1166.
AaaIpv4Addr string `json:"aaaIpv4Addr,omitempty"`
AaaIpv6Addr Ipv6Addr `json:"aaaIpv6Addr,omitempty"`
AaaUsgs []AaaUsage `json:"aaaUsgs,omitempty"`
// String uniquely identifying MTC provider information.
MtcProviderId string `json:"mtcProviderId,omitempty"`
Snssai Snssai `json:"snssai"`
SessionType PduSessionType `json:"sessionType"`
// Further allowed PDU Session types.
SessionTypes []PduSessionType `json:"sessionTypes,omitempty"`
// Describes the operation systems and the corresponding applications for each operation systems. The key of map is osId.
AppDesps map[string]AppDescriptor `json:"appDesps"`
}
/*
* 3gpp-5glan-pp
*
* API for 5G LAN Parameter Provision. © 2022, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved.
*
* API version: 1.1.0-alpha.3
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
*/
package openapi
import (
"net/http"
"github.com/gin-gonic/gin"
)
// Route is the information for every URI.
type Route struct {
// Name is the name of this Route.
Name string
// Method is the string for the HTTP method. ex) GET, POST etc..
Method string
// Pattern is the pattern of the URI.
Pattern string
// HandlerFunc is the handler function of this route.
HandlerFunc gin.HandlerFunc
}
// Routes is the list of the generated Route.
type Routes []Route
// NewRouter returns a new router.
func NewRouter() *gin.Engine {
router := gin.Default()
for _, route := range routes {
switch route.Method {
case http.MethodGet:
router.GET(route.Pattern, route.HandlerFunc)
case http.MethodPost:
router.POST(route.Pattern, route.HandlerFunc)
case http.MethodPut:
router.PUT(route.Pattern, route.HandlerFunc)
case http.MethodPatch:
router.PATCH(route.Pattern, route.HandlerFunc)
case http.MethodDelete:
router.DELETE(route.Pattern, route.HandlerFunc)
}
}
return router
}
// Index is the index handler.
func Index(c *gin.Context) {
c.String(http.StatusOK, "Hello World!")
}
var routes = Routes{
{
"Index",
http.MethodGet,
"/3gpp-5glan-pp/v1/",
Index,
},
{
"AfIdSubscriptionsGet",
http.MethodGet,
"/3gpp-5glan-pp/v1/:afId/subscriptions",
AfIdSubscriptionsGet,
},
{
"AfIdSubscriptionsPost",
http.MethodPost,
"/3gpp-5glan-pp/v1/:afId/subscriptions",
AfIdSubscriptionsPost,
},
{
"AfIdSubscriptionsSubscriptionIdDelete",
http.MethodDelete,
"/3gpp-5glan-pp/v1/:afId/subscriptions/:subscriptionId",
AfIdSubscriptionsSubscriptionIdDelete,
},
{
"AfIdSubscriptionsSubscriptionIdGet",
http.MethodGet,
"/3gpp-5glan-pp/v1/:afId/subscriptions/:subscriptionId",
AfIdSubscriptionsSubscriptionIdGet,
},
{
"AfIdSubscriptionsSubscriptionIdPatch",
http.MethodPatch,
"/3gpp-5glan-pp/v1/:afId/subscriptions/:subscriptionId",
AfIdSubscriptionsSubscriptionIdPatch,
},
{
"AfIdSubscriptionsSubscriptionIdPut",
http.MethodPut,
"/3gpp-5glan-pp/v1/:afId/subscriptions/:subscriptionId",
AfIdSubscriptionsSubscriptionIdPut,
},
}