04b33d7bbdc1d40e436e8a71450e0e91cbd11632
[ric-plt/e2mgr.git] / E2Manager / handlers / rmrmsghandlers / e2_setup_request_notification_handler.go
1 //
2 // Copyright 2019 AT&T Intellectual Property
3 // Copyright 2019 Nokia
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //      http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16
17 //  This source code is part of the near-RT RIC (RAN Intelligent Controller)
18 //  platform project (RICP).
19
20 package rmrmsghandlers
21
22 import (
23         "bytes"
24         "e2mgr/configuration"
25         "e2mgr/e2managererrors"
26         "e2mgr/logger"
27         "e2mgr/managers"
28         "e2mgr/models"
29         "e2mgr/rmrCgo"
30         "e2mgr/services"
31         "e2mgr/services/rmrsender"
32         "encoding/xml"
33         "errors"
34         "fmt"
35         "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
36         "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
37         "strconv"
38         "strings"
39 )
40
41 var (
42         emptyTagsToReplaceToSelfClosingTags = []string{"reject", "ignore", "transport-resource-unavailable", "om-intervention",
43                 "v60s", "v20s", "v10s", "v5s", "v2s", "v1s"}
44 )
45
46 type E2SetupRequestNotificationHandler struct {
47         logger                        *logger.Logger
48         config                        *configuration.Configuration
49         e2tInstancesManager           managers.IE2TInstancesManager
50         rmrSender                     *rmrsender.RmrSender
51         rNibDataService               services.RNibDataService
52         e2tAssociationManager         *managers.E2TAssociationManager
53         ranConnectStatusChangeManager managers.IRanConnectStatusChangeManager
54         ranListManager managers.RanListManager
55 }
56
57 func NewE2SetupRequestNotificationHandler(logger *logger.Logger, config *configuration.Configuration, e2tInstancesManager managers.IE2TInstancesManager, rmrSender *rmrsender.RmrSender, rNibDataService services.RNibDataService, e2tAssociationManager *managers.E2TAssociationManager, ranConnectStatusChangeManager managers.IRanConnectStatusChangeManager, ranListManager managers.RanListManager) *E2SetupRequestNotificationHandler {
58         return &E2SetupRequestNotificationHandler{
59                 logger:                        logger,
60                 config:                        config,
61                 e2tInstancesManager:           e2tInstancesManager,
62                 rmrSender:                     rmrSender,
63                 rNibDataService:               rNibDataService,
64                 e2tAssociationManager:         e2tAssociationManager,
65                 ranConnectStatusChangeManager: ranConnectStatusChangeManager,
66                 ranListManager: ranListManager,
67         }
68 }
69
70 func (h *E2SetupRequestNotificationHandler) Handle(request *models.NotificationRequest) {
71         ranName := request.RanName
72         h.logger.Infof("#E2SetupRequestNotificationHandler.Handle - RAN name: %s - received E2_SETUP_REQUEST. Payload: %x", ranName, request.Payload)
73
74         generalConfiguration, err := h.rNibDataService.GetGeneralConfiguration()
75
76         if err != nil {
77                 h.logger.Errorf("#E2SetupRequestNotificationHandler.Handle - Failed retrieving e2m general configuration - quitting e2 setup flow. error: %s", err)
78                 return
79         }
80
81         h.logger.Infof("#E2SetupRequestNotificationHandler.Handle - got general configuration from rnib - enableRic: %t", generalConfiguration.EnableRic)
82
83         if !generalConfiguration.EnableRic {
84                 cause := models.Cause{Misc: &models.CauseMisc{OmIntervention: &struct{}{}}}
85                 h.handleUnsuccessfulResponse(ranName, request, cause)
86                 return
87         }
88
89         setupRequest, e2tIpAddress, err := h.parseSetupRequest(request.Payload)
90         if err != nil {
91                 h.logger.Errorf(err.Error())
92                 return
93         }
94
95         h.logger.Infof("#E2SetupRequestNotificationHandler.Handle - E2T Address: %s - handling E2_SETUP_REQUEST", e2tIpAddress)
96         h.logger.Debugf("#E2SetupRequestNotificationHandler.Handle - E2_SETUP_REQUEST has been parsed successfully %+v", setupRequest)
97
98         _, err = h.e2tInstancesManager.GetE2TInstance(e2tIpAddress)
99
100         if err != nil {
101                 h.logger.Errorf("#E2TermInitNotificationHandler.Handle - Failed retrieving E2TInstance. error: %s", err)
102                 return
103         }
104
105         nodebInfo, err := h.rNibDataService.GetNodeb(ranName)
106
107         if err != nil {
108
109                 if _, ok := err.(*common.ResourceNotFoundError); !ok {
110                         h.logger.Errorf("#E2SetupRequestNotificationHandler.Handle - RAN name: %s - failed to retrieve nodebInfo entity. Error: %s", ranName, err)
111                         return
112
113                 }
114
115                 if nodebInfo, err = h.handleNewRan(ranName, e2tIpAddress, setupRequest); err != nil {
116                         return
117                 }
118
119         } else {
120                 if err = h.handleExistingRan(ranName, nodebInfo, setupRequest); err != nil {
121                         return
122                 }
123         }
124
125         err = h.e2tAssociationManager.AssociateRan(e2tIpAddress, nodebInfo)
126
127         if err != nil {
128
129                 h.logger.Errorf("#E2SetupRequestNotificationHandler.Handle - RAN name: %s - failed to associate E2T to nodeB entity. Error: %s", ranName, err)
130                 if _, ok := err.(*e2managererrors.RoutingManagerError); ok {
131                         cause := models.Cause{Transport: &models.CauseTransport{TransportResourceUnavailable: &struct{}{}}}
132                         h.handleUnsuccessfulResponse(nodebInfo.RanName, request, cause)
133                 }
134                 return
135         }
136
137         h.handleSuccessfulResponse(ranName, request, setupRequest)
138 }
139
140 func (h *E2SetupRequestNotificationHandler) handleNewRan(ranName string, e2tIpAddress string, setupRequest *models.E2SetupRequestMessage) (*entities.NodebInfo, error) {
141
142         nodebInfo := h.buildNodebInfo(ranName, e2tIpAddress, setupRequest)
143         err := h.rNibDataService.SaveNodeb(nodebInfo)
144
145         if err != nil {
146                 h.logger.Errorf("#E2SetupRequestNotificationHandler.handleNewRan - RAN name: %s - failed saving nodebInfo. Error: %s", ranName, err)
147                 return nil, err
148         }
149
150         nbIdentity := h.buildNbIdentity(ranName, setupRequest)
151
152         err = h.ranListManager.AddNbIdentity(entities.Node_GNB, nbIdentity)
153
154         if err != nil {
155                 return nil, err
156         }
157
158         return nodebInfo, nil
159 }
160
161 func (h *E2SetupRequestNotificationHandler) setGnbFunctions(nodebInfo *entities.NodebInfo, setupRequest *models.E2SetupRequestMessage) {
162         ranFunctions := setupRequest.ExtractRanFunctionsList()
163
164         if ranFunctions != nil {
165                 nodebInfo.GetGnb().RanFunctions = ranFunctions
166         }
167 }
168
169 func (h *E2SetupRequestNotificationHandler) handleExistingRan(ranName string, nodebInfo *entities.NodebInfo, setupRequest *models.E2SetupRequestMessage) error {
170         if nodebInfo.GetConnectionStatus() == entities.ConnectionStatus_SHUTTING_DOWN {
171                 h.logger.Errorf("#E2SetupRequestNotificationHandler.Handle - RAN name: %s, connection status: %s - nodeB entity in incorrect state", ranName, nodebInfo.ConnectionStatus)
172                 return errors.New("nodeB entity in incorrect state")
173         }
174
175         h.setGnbFunctions(nodebInfo, setupRequest)
176
177         return h.rNibDataService.UpdateNodebInfo(nodebInfo)
178 }
179
180 func (h *E2SetupRequestNotificationHandler) handleUnsuccessfulResponse(ranName string, req *models.NotificationRequest, cause models.Cause) {
181         failureResponse := models.NewE2SetupFailureResponseMessage(models.TimeToWaitEnum.V60s, cause)
182         h.logger.Debugf("#E2SetupRequestNotificationHandler.handleUnsuccessfulResponse - E2_SETUP_RESPONSE has been built successfully %+v", failureResponse)
183
184         responsePayload, err := xml.Marshal(&failureResponse.E2APPDU)
185         if err != nil {
186                 h.logger.Warnf("#E2SetupRequestNotificationHandler.handleUnsuccessfulResponse - RAN name: %s - Error marshalling RIC_E2_SETUP_RESP. Payload: %s", ranName, responsePayload)
187         }
188
189         responsePayload = replaceEmptyTagsWithSelfClosing(responsePayload)
190
191         h.logger.Infof("#E2SetupRequestNotificationHandler.handleUnsuccessfulResponse - payload: %s", responsePayload)
192         msg := models.NewRmrMessage(rmrCgo.RIC_E2_SETUP_FAILURE, ranName, responsePayload, req.TransactionId, req.GetMsgSrc())
193         h.logger.Infof("#E2SetupRequestNotificationHandler.handleUnsuccessfulResponse - RAN name: %s - RIC_E2_SETUP_RESP message has been built successfully. Message: %x", ranName, msg)
194         _ = h.rmrSender.WhSend(msg)
195
196 }
197
198 func (h *E2SetupRequestNotificationHandler) handleSuccessfulResponse(ranName string, req *models.NotificationRequest, setupRequest *models.E2SetupRequestMessage) {
199
200         plmnId := buildPlmnId(h.config.GlobalRicId.Mcc, h.config.GlobalRicId.Mnc)
201
202         ricNearRtId, err := convertTo20BitString(h.config.GlobalRicId.RicId)
203         if err != nil {
204                 return
205         }
206         successResponse := models.NewE2SetupSuccessResponseMessage(plmnId, ricNearRtId, setupRequest)
207         h.logger.Debugf("#E2SetupRequestNotificationHandler.handleSuccessfulResponse - E2_SETUP_RESPONSE has been built successfully %+v", successResponse)
208
209         responsePayload, err := xml.Marshal(&successResponse.E2APPDU)
210         if err != nil {
211                 h.logger.Warnf("#E2SetupRequestNotificationHandler.handleSuccessfulResponse - RAN name: %s - Error marshalling RIC_E2_SETUP_RESP. Payload: %s", ranName, responsePayload)
212         }
213
214         responsePayload = replaceEmptyTagsWithSelfClosing(responsePayload)
215
216         h.logger.Infof("#E2SetupRequestNotificationHandler.handleSuccessfulResponse - payload: %s", responsePayload)
217
218         msg := models.NewRmrMessage(rmrCgo.RIC_E2_SETUP_RESP, ranName, responsePayload, req.TransactionId, req.GetMsgSrc())
219         h.logger.Infof("#E2SetupRequestNotificationHandler.handleSuccessfulResponse - RAN name: %s - RIC_E2_SETUP_RESP message has been built successfully. Message: %x", ranName, msg)
220         _ = h.rmrSender.Send(msg)
221 }
222
223 func buildPlmnId(mmc string, mnc string) string {
224         var b strings.Builder
225
226         b.WriteByte(mmc[1])
227         b.WriteByte(mmc[0])
228         if len(mnc) == 2 {
229                 b.WriteString("F")
230         } else {
231                 b.WriteByte(mnc[2])
232         }
233         b.WriteByte(mmc[2])
234         b.WriteByte(mnc[1])
235         b.WriteByte(mnc[0])
236
237         return b.String()
238 }
239
240 func replaceEmptyTagsWithSelfClosing(responsePayload []byte) []byte {
241
242         emptyTagVsSelfClosingTagPairs := make([]string, len(emptyTagsToReplaceToSelfClosingTags)*2)
243
244         j := 0
245
246         for i := 0; i < len(emptyTagsToReplaceToSelfClosingTags); i++ {
247                 emptyTagVsSelfClosingTagPairs[j] = fmt.Sprintf("<%[1]s></%[1]s>", emptyTagsToReplaceToSelfClosingTags[i])
248                 emptyTagVsSelfClosingTagPairs[j+1] = fmt.Sprintf("<%s/>", emptyTagsToReplaceToSelfClosingTags[i])
249                 j += 2
250         }
251         responseString := strings.NewReplacer(emptyTagVsSelfClosingTagPairs...).Replace(string(responsePayload))
252         return []byte(responseString)
253 }
254
255 func convertTo20BitString(ricNearRtId string) (string, error) {
256         r, err := strconv.ParseUint(ricNearRtId, 16, 32)
257         if err != nil {
258                 return "", err
259         }
260         return fmt.Sprintf("%020b", r)[:20], nil
261 }
262
263 func (h *E2SetupRequestNotificationHandler) parseSetupRequest(payload []byte) (*models.E2SetupRequestMessage, string, error) {
264
265         pipInd := bytes.IndexByte(payload, '|')
266         if pipInd < 0 {
267                 return nil, "", errors.New("#E2SetupRequestNotificationHandler.parseSetupRequest - Error parsing E2 Setup Request failed extract Payload: no | separator found")
268         }
269
270         e2tIpAddress := string(payload[:pipInd])
271         if len(e2tIpAddress) == 0 {
272                 return nil, "", errors.New("#E2SetupRequestNotificationHandler.parseSetupRequest - Empty E2T Address received")
273         }
274
275         h.logger.Infof("#E2SetupRequestNotificationHandler.parseSetupRequest - payload: %s", payload[pipInd+1:])
276
277         setupRequest := &models.E2SetupRequestMessage{}
278         err := xml.Unmarshal(normalizeXml(payload[pipInd+1:]), &setupRequest.E2APPDU)
279         if err != nil {
280                 return nil, "", errors.New(fmt.Sprintf("#E2SetupRequestNotificationHandler.parseSetupRequest - Error unmarshalling E2 Setup Request payload: %x", payload))
281         }
282
283         return setupRequest, e2tIpAddress, nil
284 }
285
286 func normalizeXml(payload []byte) []byte {
287         xmlStr := string(payload)
288         normalized := strings.NewReplacer("&lt;", "<", "&gt;", ">").Replace(xmlStr)
289         return []byte(normalized)
290 }
291
292 func (h *E2SetupRequestNotificationHandler) buildNodebInfo(ranName string, e2tAddress string, request *models.E2SetupRequestMessage) *entities.NodebInfo {
293         nodebInfo := &entities.NodebInfo{
294                 AssociatedE2TInstanceAddress: e2tAddress,
295                 RanName:                      ranName,
296                 NodeType:                     entities.Node_GNB,
297                 Configuration:                &entities.NodebInfo_Gnb{Gnb: &entities.Gnb{}},
298                 GlobalNbId:                   h.buildGlobalNbId(request),
299         }
300
301         h.setGnbFunctions(nodebInfo, request)
302         return nodebInfo
303 }
304
305 func (h *E2SetupRequestNotificationHandler) buildGlobalNbId(setupRequest *models.E2SetupRequestMessage) *entities.GlobalNbId {
306         return &entities.GlobalNbId{
307                 PlmnId: setupRequest.GetPlmnId(),
308                 NbId:   setupRequest.GetNbId(),
309         }
310 }
311
312 func (h *E2SetupRequestNotificationHandler) buildNbIdentity(ranName string, setupRequest *models.E2SetupRequestMessage) *entities.NbIdentity {
313         return &entities.NbIdentity{
314                 InventoryName: ranName,
315                 GlobalNbId:    h.buildGlobalNbId(setupRequest),
316         }
317 }