From 391cb791070d5ee497396d0db041b222521f7de4 Mon Sep 17 00:00:00 2001 From: Louis Royer Date: Mon, 16 Dec 2024 16:00:47 +0100 Subject: [PATCH 1/2] Rename RadioPeerMsg.go to radio_peer_msg.go --- jsonapi/n1n2/{RadioPeerMsg.go => radio_peer_msg.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename jsonapi/n1n2/{RadioPeerMsg.go => radio_peer_msg.go} (100%) diff --git a/jsonapi/n1n2/RadioPeerMsg.go b/jsonapi/n1n2/radio_peer_msg.go similarity index 100% rename from jsonapi/n1n2/RadioPeerMsg.go rename to jsonapi/n1n2/radio_peer_msg.go From a36ba0a453aea35d99a171aa06125ed2e6543342 Mon Sep 17 00:00:00 2001 From: Louis Royer Date: Tue, 17 Dec 2024 18:15:59 +0100 Subject: [PATCH 2/2] Add n1n2 api for Handover; close #23 --- jsonapi/control_uri.go | 3 +++ jsonapi/fteid.go | 20 ++++++++++++++++++ jsonapi/n1n2/handover_command.go | 22 +++++++++++++++++++ jsonapi/n1n2/handover_confirm.go | 22 +++++++++++++++++++ jsonapi/n1n2/handover_notify.go | 22 +++++++++++++++++++ jsonapi/n1n2/handover_request.go | 22 +++++++++++++++++++ jsonapi/n1n2/handover_request_ack.go | 22 +++++++++++++++++++ jsonapi/n1n2/handover_required.go | 22 +++++++++++++++++++ jsonapi/n1n2/n2_pdu_session_req_msg.go | 5 +---- jsonapi/n1n2/n2_pdu_session_resp_msg.go | 7 ++++--- jsonapi/n1n2/session.go | 23 ++++++++++++++++++++ jsonapi_test/n1n2_test/session_test.go | 28 +++++++++++++++++++++++++ 12 files changed, 211 insertions(+), 7 deletions(-) create mode 100644 jsonapi/fteid.go create mode 100644 jsonapi/n1n2/handover_command.go create mode 100644 jsonapi/n1n2/handover_confirm.go create mode 100644 jsonapi/n1n2/handover_notify.go create mode 100644 jsonapi/n1n2/handover_request.go create mode 100644 jsonapi/n1n2/handover_request_ack.go create mode 100644 jsonapi/n1n2/handover_required.go create mode 100644 jsonapi/n1n2/session.go create mode 100644 jsonapi_test/n1n2_test/session_test.go diff --git a/jsonapi/control_uri.go b/jsonapi/control_uri.go index 61c4a16..74a5607 100644 --- a/jsonapi/control_uri.go +++ b/jsonapi/control_uri.go @@ -16,6 +16,9 @@ type ControlURI struct { } func (u *ControlURI) UnmarshalText(text []byte) error { + if len(text) == 0 { + return fmt.Errorf("Control URI should not be empty.") + } if text[len(text)-1] == '/' { return fmt.Errorf("Control URI should not contains trailing slash.") } diff --git a/jsonapi/fteid.go b/jsonapi/fteid.go new file mode 100644 index 0000000..5184c57 --- /dev/null +++ b/jsonapi/fteid.go @@ -0,0 +1,20 @@ +// Copyright 2024 Louis Royer and the NextMN contributors. All rights reserved. +// Use of this source code is governed by a MIT-style license that can be +// found in the LICENSE file. +// SPDX-License-Identifier: MIT + +package jsonapi + +import "net/netip" + +type Fteid struct { + Addr netip.Addr `json:"addr"` + Teid uint32 `json:"teid"` +} + +func NewFteid(addr netip.Addr, teid uint32) *Fteid { + return &Fteid{ + Addr: addr, + Teid: teid, + } +} diff --git a/jsonapi/n1n2/handover_command.go b/jsonapi/n1n2/handover_command.go new file mode 100644 index 0000000..016a12b --- /dev/null +++ b/jsonapi/n1n2/handover_command.go @@ -0,0 +1,22 @@ +// Copyright 2024 Louis Royer and the NextMN contributors. All rights reserved. +// Use of this source code is governed by a MIT-style license that can be +// found in the LICENSE file. +// SPDX-License-Identifier: MIT + +package n1n2 + +import ( + "github.com/nextmn/json-api/jsonapi" +) + +// HandoverCommand is sent by the CP to the source gNB to start the execution of handover, and forwarded to the UE +type HandoverCommand struct { + // Header + UeCtrl jsonapi.ControlURI `json:"ue-ctrl"` + Cp jsonapi.ControlURI `json:"cp"` + SourceGnb jsonapi.ControlURI `json:"source-gnb"` + + // Handover Command + Sessions []Session `json:"sessions"` // contains new ForwardDownlinkFteid + TargetGnb jsonapi.ControlURI `json:"target-gnb"` +} diff --git a/jsonapi/n1n2/handover_confirm.go b/jsonapi/n1n2/handover_confirm.go new file mode 100644 index 0000000..52c59f3 --- /dev/null +++ b/jsonapi/n1n2/handover_confirm.go @@ -0,0 +1,22 @@ +// Copyright 2024 Louis Royer and the NextMN contributors. All rights reserved. +// Use of this source code is governed by a MIT-style license that can be +// found in the LICENSE file. +// SPDX-License-Identifier: MIT + +package n1n2 + +import ( + "github.com/nextmn/json-api/jsonapi" +) + +// HandoverConfirm is send by the target UE to the target gNB after the UE is synchronized to the new cell +type HandoverConfirm struct { + // Header + UeCtrl jsonapi.ControlURI `json:"ue-ctrl"` + Cp jsonapi.ControlURI `json:"cp"` + + // Handover Confirm + Sessions []Session `json:"sessions"` + SourceGnb jsonapi.ControlURI `json:"source-gnb"` + TargetGnb jsonapi.ControlURI `json:"target-gnb"` +} diff --git a/jsonapi/n1n2/handover_notify.go b/jsonapi/n1n2/handover_notify.go new file mode 100644 index 0000000..a3c3f01 --- /dev/null +++ b/jsonapi/n1n2/handover_notify.go @@ -0,0 +1,22 @@ +// Copyright 2024 Louis Royer and the NextMN contributors. All rights reserved. +// Use of this source code is governed by a MIT-style license that can be +// found in the LICENSE file. +// SPDX-License-Identifier: MIT + +package n1n2 + +import ( + "github.com/nextmn/json-api/jsonapi" +) + +// HandoverNotify is send by the target gNB to the CP after handover have been confirmed by the UE +type HandoverNotify struct { + // Header + UeCtrl jsonapi.ControlURI `json:"ue-ctrl"` + Cp jsonapi.ControlURI `json:"cp"` + TargetGnb jsonapi.ControlURI `json:"target-gnb"` + + // Handover Notify + Sessions []Session `json:"sessions"` + SourceGnb jsonapi.ControlURI `json:"source-gnb"` +} diff --git a/jsonapi/n1n2/handover_request.go b/jsonapi/n1n2/handover_request.go new file mode 100644 index 0000000..30519ef --- /dev/null +++ b/jsonapi/n1n2/handover_request.go @@ -0,0 +1,22 @@ +// Copyright 2024 Louis Royer and the NextMN contributors. All rights reserved. +// Use of this source code is governed by a MIT-style license that can be +// found in the LICENSE file. +// SPDX-License-Identifier: MIT + +package n1n2 + +import ( + "github.com/nextmn/json-api/jsonapi" +) + +// HandoverRequest is send by the CP to the target gNB during the handover preparation phase +type HandoverRequest struct { + // Header + UeCtrl jsonapi.ControlURI `json:"ue-ctrl"` + Cp jsonapi.ControlURI `json:"cp"` + TargetgNB jsonapi.ControlURI `json:"target-gnb"` + + // Handover Request + SourcegNB jsonapi.ControlURI `json:"source-gnb"` + Sessions []Session `json:"sessions"` // contains new UL FTeid +} diff --git a/jsonapi/n1n2/handover_request_ack.go b/jsonapi/n1n2/handover_request_ack.go new file mode 100644 index 0000000..13b1e22 --- /dev/null +++ b/jsonapi/n1n2/handover_request_ack.go @@ -0,0 +1,22 @@ +// Copyright 2024 Louis Royer and the NextMN contributors. All rights reserved. +// Use of this source code is governed by a MIT-style license that can be +// found in the LICENSE file. +// SPDX-License-Identifier: MIT + +package n1n2 + +import ( + "github.com/nextmn/json-api/jsonapi" +) + +// HandoverRequestAck is send by the target gNB to the CP in response to an HandoverRequest +type HandoverRequestAck struct { + // Header + Cp jsonapi.ControlURI `json:"cp"` + TargetgNB jsonapi.ControlURI `json:"target-gnb"` + + // Handover Request Ack + SourcegNB jsonapi.ControlURI `json:"source-gnb"` + UeCtrl jsonapi.ControlURI `json:"ue-ctrl"` + Sessions []Session `json:"sessions"` // contains new DL FTeid +} diff --git a/jsonapi/n1n2/handover_required.go b/jsonapi/n1n2/handover_required.go new file mode 100644 index 0000000..69a392d --- /dev/null +++ b/jsonapi/n1n2/handover_required.go @@ -0,0 +1,22 @@ +// Copyright 2024 Louis Royer and the NextMN contributors. All rights reserved. +// Use of this source code is governed by a MIT-style license that can be +// found in the LICENSE file. +// SPDX-License-Identifier: MIT + +package n1n2 + +import ( + "github.com/nextmn/json-api/jsonapi" +) + +// HandoverRequired is send by the source gNB to the CP to start the handover preparation phase +type HandoverRequired struct { + // Header + SourcegNB jsonapi.ControlURI `json:"source-gnb"` + Cp jsonapi.ControlURI `json:"cp"` + + // Handover Required content + Ue jsonapi.ControlURI `json:"ue"` + Sessions []Session `json:"sessions"` // list of all pdu sessions of the UE to be moved + TargetgNB jsonapi.ControlURI `json:"target-gnb"` +} diff --git a/jsonapi/n1n2/n2_pdu_session_req_msg.go b/jsonapi/n1n2/n2_pdu_session_req_msg.go index eab8118..7426ecc 100644 --- a/jsonapi/n1n2/n2_pdu_session_req_msg.go +++ b/jsonapi/n1n2/n2_pdu_session_req_msg.go @@ -6,8 +6,6 @@ package n1n2 import ( - "net/netip" - "github.com/nextmn/json-api/jsonapi" ) @@ -17,6 +15,5 @@ type N2PduSessionReqMsg struct { UeInfo PduSessionEstabAcceptMsg `json:"ue-info"` // information to forward to the UE // Uplink FTEID: the gNB will establish an Uplink GTP Tunnel using the following - Upf netip.Addr `json:"upf"` - UplinkTeid uint32 `json:"uplink-teid"` + UplinkFteid jsonapi.Fteid `json:"uplink-fteid"` } diff --git a/jsonapi/n1n2/n2_pdu_session_resp_msg.go b/jsonapi/n1n2/n2_pdu_session_resp_msg.go index 0b8e5d3..d78f43a 100644 --- a/jsonapi/n1n2/n2_pdu_session_resp_msg.go +++ b/jsonapi/n1n2/n2_pdu_session_resp_msg.go @@ -5,13 +5,14 @@ package n1n2 -import "net/netip" +import ( + "github.com/nextmn/json-api/jsonapi" +) // N2PduSessionRespMsg is sent to the CP by the gNB as a response of N2PduSessionReqMsg. type N2PduSessionRespMsg struct { UeInfo PduSessionEstabAcceptMsg `json:"ue-info"` // used to identify the PDU Session // Downlink FTEID: the CP will use this to configure a downlink GTP Tunnel in Upf-i - DownlinkTeid uint32 `json:"downlink-teid"` - Gnb netip.Addr `json:"gnb"` + DownlinkFteid jsonapi.Fteid `json:"downlink-fteid"` } diff --git a/jsonapi/n1n2/session.go b/jsonapi/n1n2/session.go new file mode 100644 index 0000000..68047b4 --- /dev/null +++ b/jsonapi/n1n2/session.go @@ -0,0 +1,23 @@ +// Copyright 2024 Louis Royer and the NextMN contributors. All rights reserved. +// Use of this source code is governed by a MIT-style license that can be +// found in the LICENSE file. +// SPDX-License-Identifier: MIT + +package n1n2 + +import ( + "net/netip" + + "github.com/nextmn/json-api/jsonapi" +) + +type Session struct { + Addr netip.Addr `json:"ue-addr"` + Dnn string `json:"dnn"` + UplinkFteid *jsonapi.Fteid `json:"uplink-fteid,omitempty"` + DownlinkFteid *jsonapi.Fteid `json:"downlink-fteid,omitempty"` + + // when ForwardDownlinkFteid is not empty, + // PDUs received on DownlinkFteid must be forwarded to it + ForwardDownlinkFteid *jsonapi.Fteid `json:"forward-fteid,omitempty"` +} diff --git a/jsonapi_test/n1n2_test/session_test.go b/jsonapi_test/n1n2_test/session_test.go new file mode 100644 index 0000000..ab6dec9 --- /dev/null +++ b/jsonapi_test/n1n2_test/session_test.go @@ -0,0 +1,28 @@ +// Copyright 2024 Louis Royer and the NextMN contributors. All rights reserved. +// Use of this source code is governed by a MIT-style license that can be +// found in the LICENSE file. +// SPDX-License-Identifier: MIT + +package n1n2_test + +import ( + "encoding/json" + "testing" + + "github.com/nextmn/json-api/jsonapi/n1n2" +) + +func TestSession(t *testing.T) { + s := &n1n2.Session{} + if err := json.Unmarshal([]byte("{\"ue-addr\": \"127.0.0.1\", \"uplink-fteid\": {\"addr\": \"127.0.0.2\", \"teid\": 80}}"), s); err != nil { + t.Errorf("Session with only uplink FTeid could not be unmarshaled") + } + + if s.DownlinkFteid != nil { + t.Errorf("Downlink Fteid was not defined but is not nil") + } + if s.UplinkFteid == nil { + t.Errorf("Uplink Fteid was defined but is nil") + } + +}