51c84e3ceb811c267c81d4ba144e3ea729fbf2c2
[ric-plt/submgr.git] / pkg / control / control.go
1 /*
2 ==================================================================================
3   Copyright (c) 2019 AT&T Intellectual Property.
4   Copyright (c) 2019 Nokia
5
6    Licensed under the Apache License, Version 2.0 (the "License");
7    you may not use this file except in compliance with the License.
8    You may obtain a copy of the License at
9
10        http://www.apache.org/licenses/LICENSE-2.0
11
12    Unless required by applicable law or agreed to in writing, software
13    distributed under the License is distributed on an "AS IS" BASIS,
14    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15    See the License for the specific language governing permissions and
16    limitations under the License.
17 ==================================================================================
18 */
19
20 package control
21
22 import (
23         "fmt"
24         "gerrit.o-ran-sc.org/r/ric-plt/e2ap/pkg/e2ap"
25         rtmgrclient "gerrit.o-ran-sc.org/r/ric-plt/submgr/pkg/rtmgr_client"
26         "gerrit.o-ran-sc.org/r/ric-plt/submgr/pkg/xapptweaks"
27         "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/models"
28         "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
29         httptransport "github.com/go-openapi/runtime/client"
30         "github.com/go-openapi/strfmt"
31         "github.com/spf13/viper"
32         "time"
33 )
34
35 //-----------------------------------------------------------------------------
36 //
37 //-----------------------------------------------------------------------------
38
39 func idstring(err error, entries ...fmt.Stringer) string {
40         var retval string = ""
41         var filler string = ""
42         for _, entry := range entries {
43                 retval += filler + entry.String()
44                 filler = " "
45         }
46         if err != nil {
47                 retval += filler + "err(" + err.Error() + ")"
48                 filler = " "
49
50         }
51         return retval
52 }
53
54 //-----------------------------------------------------------------------------
55 //
56 //-----------------------------------------------------------------------------
57
58 var e2tSubReqTimeout time.Duration = 5 * time.Second
59 var e2tSubDelReqTime time.Duration = 5 * time.Second
60 var e2tMaxSubReqTryCount uint64 = 2    // Initial try + retry
61 var e2tMaxSubDelReqTryCount uint64 = 2 // Initial try + retry
62
63 var e2tRecvMsgTimeout time.Duration = 5 * time.Second
64
65 type Control struct {
66         xapptweaks.XappWrapper
67         e2ap     *E2ap
68         registry *Registry
69         tracker  *Tracker
70         //subscriber *xapp.Subscriber
71 }
72
73 type RMRMeid struct {
74         PlmnID  string
75         EnbID   string
76         RanName string
77 }
78
79 func init() {
80         xapp.Logger.Info("SUBMGR")
81         viper.AutomaticEnv()
82         viper.SetEnvPrefix("submgr")
83         viper.AllowEmptyEnv(true)
84 }
85
86 func NewControl() *Control {
87
88         transport := httptransport.New(viper.GetString("rtmgr.HostAddr")+":"+viper.GetString("rtmgr.port"), viper.GetString("rtmgr.baseUrl"), []string{"http"})
89         rtmgrClient := RtmgrClient{rtClient: rtmgrclient.New(transport, strfmt.Default)}
90
91         registry := new(Registry)
92         registry.Initialize()
93         registry.rtmgrClient = &rtmgrClient
94
95         tracker := new(Tracker)
96         tracker.Init()
97
98         //subscriber := xapp.NewSubscriber(viper.GetString("subscription.host"), viper.GetInt("subscription.timeout"))
99
100         c := &Control{e2ap: new(E2ap),
101                 registry: registry,
102                 tracker:  tracker,
103                 //subscriber: subscriber,
104         }
105         c.XappWrapper.Init("")
106         go xapp.Subscription.Listen(c.SubscriptionHandler, c.QueryHandler)
107         //go c.subscriber.Listen(c.SubscriptionHandler, c.QueryHandler)
108         return c
109 }
110
111 func (c *Control) ReadyCB(data interface{}) {
112         if c.Rmr == nil {
113                 c.Rmr = xapp.Rmr
114         }
115 }
116
117 func (c *Control) Run() {
118         xapp.SetReadyCB(c.ReadyCB, nil)
119         xapp.Run(c)
120 }
121
122 //-------------------------------------------------------------------
123 //
124 //-------------------------------------------------------------------
125 func (c *Control) SubscriptionHandler(stype models.SubscriptionType, params interface{}) (models.SubscriptionResult, error) {
126         /*
127            switch p := params.(type) {
128            case *models.ReportParams:
129                trans := c.tracker.NewXappTransaction(NewRmrEndpoint(p.ClientEndpoint),"" , 0, &xapp.RMRMeid{RanName: p.Meid})
130                if trans == nil {
131                      xapp.Logger.Error("XAPP-SubReq: %s", idstring(fmt.Errorf("transaction not created"), params))
132                      return
133                }
134                defer trans.Release()
135            case *models.ControlParams:
136            case *models.PolicyParams:
137            }
138         */
139         return models.SubscriptionResult{}, fmt.Errorf("Subscription rest interface not implemented")
140 }
141
142 func (c *Control) QueryHandler() (models.SubscriptionList, error) {
143         return c.registry.QueryHandler()
144 }
145
146 //-------------------------------------------------------------------
147 //
148 //-------------------------------------------------------------------
149
150 func (c *Control) rmrSendToE2T(desc string, subs *Subscription, trans *TransactionSubs) (err error) {
151         params := xapptweaks.NewParams(nil)
152         params.Mtype = trans.GetMtype()
153         params.SubId = int(subs.GetReqId().Seq)
154         params.Xid = ""
155         params.Meid = subs.GetMeid()
156         params.Src = ""
157         params.PayloadLen = len(trans.Payload.Buf)
158         params.Payload = trans.Payload.Buf
159         params.Mbuf = nil
160         xapp.Logger.Info("MSG to E2T: %s %s %s", desc, trans.String(), params.String())
161         return c.RmrSend(params, 5)
162 }
163
164 func (c *Control) rmrSendToXapp(desc string, subs *Subscription, trans *TransactionXapp) (err error) {
165
166         params := xapptweaks.NewParams(nil)
167         params.Mtype = trans.GetMtype()
168         params.SubId = int(subs.GetReqId().Seq)
169         params.Xid = trans.GetXid()
170         params.Meid = trans.GetMeid()
171         params.Src = ""
172         params.PayloadLen = len(trans.Payload.Buf)
173         params.Payload = trans.Payload.Buf
174         params.Mbuf = nil
175         xapp.Logger.Info("MSG to XAPP: %s %s %s", desc, trans.String(), params.String())
176         return c.RmrSend(params, 5)
177 }
178
179 func (c *Control) Consume(params *xapp.RMRParams) (err error) {
180         msg := xapptweaks.NewParams(params)
181         if c.Rmr == nil {
182                 err = fmt.Errorf("Rmr object nil can handle %s", msg.String())
183                 xapp.Logger.Error("%s", err.Error())
184                 return
185         }
186         c.CntRecvMsg++
187
188         defer c.Rmr.Free(msg.Mbuf)
189
190         switch msg.Mtype {
191         case xapp.RIC_SUB_REQ:
192                 go c.handleXAPPSubscriptionRequest(msg)
193         case xapp.RIC_SUB_RESP:
194                 go c.handleE2TSubscriptionResponse(msg)
195         case xapp.RIC_SUB_FAILURE:
196                 go c.handleE2TSubscriptionFailure(msg)
197         case xapp.RIC_SUB_DEL_REQ:
198                 go c.handleXAPPSubscriptionDeleteRequest(msg)
199         case xapp.RIC_SUB_DEL_RESP:
200                 go c.handleE2TSubscriptionDeleteResponse(msg)
201         case xapp.RIC_SUB_DEL_FAILURE:
202                 go c.handleE2TSubscriptionDeleteFailure(msg)
203         default:
204                 xapp.Logger.Info("Unknown Message Type '%d', discarding", msg.Mtype)
205         }
206         return
207 }
208
209 //-------------------------------------------------------------------
210 // handle from XAPP Subscription Request
211 //------------------------------------------------------------------
212 func (c *Control) handleXAPPSubscriptionRequest(params *xapptweaks.RMRParams) {
213         xapp.Logger.Info("MSG from XAPP: %s", params.String())
214
215         subReqMsg, err := c.e2ap.UnpackSubscriptionRequest(params.Payload)
216         if err != nil {
217                 xapp.Logger.Error("XAPP-SubReq: %s", idstring(err, params))
218                 return
219         }
220
221         trans := c.tracker.NewXappTransaction(xapptweaks.NewRmrEndpoint(params.Src), params.Xid, subReqMsg.RequestId.Seq, params.Meid)
222         if trans == nil {
223                 xapp.Logger.Error("XAPP-SubReq: %s", idstring(fmt.Errorf("transaction not created"), params))
224                 return
225         }
226         defer trans.Release()
227
228         err = c.tracker.Track(trans)
229         if err != nil {
230                 xapp.Logger.Error("XAPP-SubReq: %s", idstring(err, trans))
231                 return
232         }
233
234         subs, err := c.registry.AssignToSubscription(trans, subReqMsg)
235         if err != nil {
236                 xapp.Logger.Error("XAPP-SubReq: %s", idstring(err, trans))
237                 return
238         }
239
240         //
241         // Wake subs request
242         //
243         go c.handleSubscriptionCreate(subs, trans)
244         event, _ := trans.WaitEvent(0) //blocked wait as timeout is handled in subs side
245
246         err = nil
247         if event != nil {
248                 switch themsg := event.(type) {
249                 case *e2ap.E2APSubscriptionResponse:
250                         trans.Mtype, trans.Payload, err = c.e2ap.PackSubscriptionResponse(themsg)
251                         if err == nil {
252                                 trans.Release()
253                                 c.rmrSendToXapp("", subs, trans)
254                                 return
255                         }
256                 case *e2ap.E2APSubscriptionFailure:
257                         trans.Mtype, trans.Payload, err = c.e2ap.PackSubscriptionFailure(themsg)
258                         if err == nil {
259                                 c.rmrSendToXapp("", subs, trans)
260                         }
261                 default:
262                         break
263                 }
264         }
265         xapp.Logger.Info("XAPP-SubReq: failed %s", idstring(err, trans, subs))
266         c.registry.RemoveFromSubscription(subs, trans, 5*time.Second)
267 }
268
269 //-------------------------------------------------------------------
270 // handle from XAPP Subscription Delete Request
271 //------------------------------------------------------------------
272 func (c *Control) handleXAPPSubscriptionDeleteRequest(params *xapptweaks.RMRParams) {
273         xapp.Logger.Info("MSG from XAPP: %s", params.String())
274
275         subDelReqMsg, err := c.e2ap.UnpackSubscriptionDeleteRequest(params.Payload)
276         if err != nil {
277                 xapp.Logger.Error("XAPP-SubDelReq %s", idstring(err, params))
278                 return
279         }
280
281         trans := c.tracker.NewXappTransaction(xapptweaks.NewRmrEndpoint(params.Src), params.Xid, subDelReqMsg.RequestId.Seq, params.Meid)
282         if trans == nil {
283                 xapp.Logger.Error("XAPP-SubDelReq: %s", idstring(fmt.Errorf("transaction not created"), params))
284                 return
285         }
286         defer trans.Release()
287
288         err = c.tracker.Track(trans)
289         if err != nil {
290                 xapp.Logger.Error("XAPP-SubReq: %s", idstring(err, trans))
291                 return
292         }
293
294         subs, err := c.registry.GetSubscriptionFirstMatch([]uint32{trans.GetSubId()})
295         if err != nil {
296                 xapp.Logger.Error("XAPP-SubDelReq: %s", idstring(err, trans))
297                 return
298         }
299
300         //
301         // Wake subs delete
302         //
303         go c.handleSubscriptionDelete(subs, trans)
304         trans.WaitEvent(0) //blocked wait as timeout is handled in subs side
305
306         xapp.Logger.Debug("XAPP-SubDelReq: Handling event %s ", idstring(nil, trans, subs))
307
308         // Whatever is received send ok delete response
309         subDelRespMsg := &e2ap.E2APSubscriptionDeleteResponse{}
310         subDelRespMsg.RequestId = subs.GetReqId().RequestId
311         subDelRespMsg.FunctionId = subs.SubReqMsg.FunctionId
312         trans.Mtype, trans.Payload, err = c.e2ap.PackSubscriptionDeleteResponse(subDelRespMsg)
313         if err == nil {
314                 c.rmrSendToXapp("", subs, trans)
315         }
316
317         c.registry.RemoveFromSubscription(subs, trans, 5*time.Second)
318 }
319
320 //-------------------------------------------------------------------
321 // SUBS CREATE Handling
322 //-------------------------------------------------------------------
323 func (c *Control) handleSubscriptionCreate(subs *Subscription, parentTrans *TransactionXapp) {
324
325         trans := c.tracker.NewSubsTransaction(subs)
326         subs.WaitTransactionTurn(trans)
327         defer subs.ReleaseTransactionTurn(trans)
328         defer trans.Release()
329
330         xapp.Logger.Debug("SUBS-SubReq: Handling %s ", idstring(nil, trans, subs, parentTrans))
331
332         subRfMsg, valid := subs.GetCachedResponse()
333         if subRfMsg == nil && valid == true {
334
335                 //
336                 // In case of failure
337                 // - make internal delete
338                 // - in case duplicate cause, retry (currently max 1 retry)
339                 //
340                 maxRetries := uint64(1)
341                 doRetry := true
342                 for retries := uint64(0); retries <= maxRetries && doRetry; retries++ {
343                         doRetry = false
344
345                         event := c.sendE2TSubscriptionRequest(subs, trans, parentTrans)
346                         switch themsg := event.(type) {
347                         case *e2ap.E2APSubscriptionResponse:
348                                 subRfMsg, valid = subs.SetCachedResponse(event, true)
349                         case *e2ap.E2APSubscriptionFailure:
350                                 subRfMsg, valid = subs.SetCachedResponse(event, false)
351                                 doRetry = true
352                                 for _, item := range themsg.ActionNotAdmittedList.Items {
353                                         if item.Cause.Content != e2ap.E2AP_CauseContent_Ric || (item.Cause.Value != e2ap.E2AP_CauseValue_Ric_duplicate_action && item.Cause.Value != e2ap.E2AP_CauseValue_Ric_duplicate_event) {
354                                                 doRetry = false
355                                                 break
356                                         }
357                                 }
358                                 xapp.Logger.Info("SUBS-SubReq: internal delete and possible retry due event(%s) retry(%t,%d/%d) %s", typeofSubsMessage(event), doRetry, retries, maxRetries, idstring(nil, trans, subs, parentTrans))
359                                 c.sendE2TSubscriptionDeleteRequest(subs, trans, parentTrans)
360                         default:
361                                 xapp.Logger.Info("SUBS-SubReq: internal delete due event(%s) %s", typeofSubsMessage(event), idstring(nil, trans, subs, parentTrans))
362                                 subRfMsg, valid = subs.SetCachedResponse(nil, false)
363                                 c.sendE2TSubscriptionDeleteRequest(subs, trans, parentTrans)
364                         }
365                 }
366
367                 xapp.Logger.Debug("SUBS-SubReq: Handling (e2t response %s) %s", typeofSubsMessage(subRfMsg), idstring(nil, trans, subs, parentTrans))
368         } else {
369                 xapp.Logger.Debug("SUBS-SubReq: Handling (cached response %s) %s", typeofSubsMessage(subRfMsg), idstring(nil, trans, subs, parentTrans))
370         }
371
372         parentTrans.SendEvent(subRfMsg, 0)
373 }
374
375 //-------------------------------------------------------------------
376 // SUBS DELETE Handling
377 //-------------------------------------------------------------------
378
379 func (c *Control) handleSubscriptionDelete(subs *Subscription, parentTrans *TransactionXapp) {
380
381         trans := c.tracker.NewSubsTransaction(subs)
382         subs.WaitTransactionTurn(trans)
383         defer subs.ReleaseTransactionTurn(trans)
384         defer trans.Release()
385
386         xapp.Logger.Debug("SUBS-SubDelReq: Handling %s", idstring(nil, trans, subs, parentTrans))
387
388         subs.mutex.Lock()
389         if subs.valid && subs.EpList.HasEndpoint(parentTrans.GetEndpoint()) && subs.EpList.Size() == 1 {
390                 subs.valid = false
391                 subs.mutex.Unlock()
392                 c.sendE2TSubscriptionDeleteRequest(subs, trans, parentTrans)
393         } else {
394                 subs.mutex.Unlock()
395         }
396
397         parentTrans.SendEvent(nil, 0)
398 }
399
400 //-------------------------------------------------------------------
401 // send to E2T Subscription Request
402 //-------------------------------------------------------------------
403 func (c *Control) sendE2TSubscriptionRequest(subs *Subscription, trans *TransactionSubs, parentTrans *TransactionXapp) interface{} {
404         var err error
405         var event interface{} = nil
406         var timedOut bool = false
407
408         subReqMsg := subs.SubReqMsg
409         subReqMsg.RequestId = subs.GetReqId().RequestId
410         trans.Mtype, trans.Payload, err = c.e2ap.PackSubscriptionRequest(subReqMsg)
411         if err != nil {
412                 xapp.Logger.Error("SUBS-SubReq: %s", idstring(err, trans, subs, parentTrans))
413                 return event
414         }
415
416         for retries := uint64(0); retries < e2tMaxSubReqTryCount; retries++ {
417                 desc := fmt.Sprintf("(retry %d)", retries)
418                 c.rmrSendToE2T(desc, subs, trans)
419                 event, timedOut = trans.WaitEvent(e2tSubReqTimeout)
420                 if timedOut {
421                         continue
422                 }
423                 break
424         }
425         xapp.Logger.Debug("SUBS-SubReq: Response handling event(%s) %s", typeofSubsMessage(event), idstring(nil, trans, subs, parentTrans))
426         return event
427 }
428
429 //-------------------------------------------------------------------
430 // send to E2T Subscription Delete Request
431 //-------------------------------------------------------------------
432
433 func (c *Control) sendE2TSubscriptionDeleteRequest(subs *Subscription, trans *TransactionSubs, parentTrans *TransactionXapp) interface{} {
434         var err error
435         var event interface{}
436         var timedOut bool
437
438         subDelReqMsg := &e2ap.E2APSubscriptionDeleteRequest{}
439         subDelReqMsg.RequestId = subs.GetReqId().RequestId
440         subDelReqMsg.FunctionId = subs.SubReqMsg.FunctionId
441         trans.Mtype, trans.Payload, err = c.e2ap.PackSubscriptionDeleteRequest(subDelReqMsg)
442         if err != nil {
443                 xapp.Logger.Error("SUBS-SubDelReq: %s", idstring(err, trans, subs, parentTrans))
444                 return event
445         }
446
447         for retries := uint64(0); retries < e2tMaxSubDelReqTryCount; retries++ {
448                 desc := fmt.Sprintf("(retry %d)", retries)
449                 c.rmrSendToE2T(desc, subs, trans)
450                 event, timedOut = trans.WaitEvent(e2tSubDelReqTime)
451                 if timedOut {
452                         continue
453                 }
454                 break
455         }
456         xapp.Logger.Debug("SUBS-SubDelReq: Response handling event(%s) %s", typeofSubsMessage(event), idstring(nil, trans, subs, parentTrans))
457         return event
458 }
459
460 //-------------------------------------------------------------------
461 // handle from E2T Subscription Reponse
462 //-------------------------------------------------------------------
463 func (c *Control) handleE2TSubscriptionResponse(params *xapptweaks.RMRParams) {
464         xapp.Logger.Info("MSG from E2T: %s", params.String())
465         subRespMsg, err := c.e2ap.UnpackSubscriptionResponse(params.Payload)
466         if err != nil {
467                 xapp.Logger.Error("MSG-SubResp %s", idstring(err, params))
468                 return
469         }
470         subs, err := c.registry.GetSubscriptionFirstMatch([]uint32{subRespMsg.RequestId.Seq})
471         if err != nil {
472                 xapp.Logger.Error("MSG-SubResp: %s", idstring(err, params))
473                 return
474         }
475         trans := subs.GetTransaction()
476         if trans == nil {
477                 err = fmt.Errorf("Ongoing transaction not found")
478                 xapp.Logger.Error("MSG-SubResp: %s", idstring(err, params, subs))
479                 return
480         }
481         sendOk, timedOut := trans.SendEvent(subRespMsg, e2tRecvMsgTimeout)
482         if sendOk == false {
483                 err = fmt.Errorf("Passing event to transaction failed: sendOk(%t) timedOut(%t)", sendOk, timedOut)
484                 xapp.Logger.Error("MSG-SubResp: %s", idstring(err, trans, subs))
485         }
486         return
487 }
488
489 //-------------------------------------------------------------------
490 // handle from E2T Subscription Failure
491 //-------------------------------------------------------------------
492 func (c *Control) handleE2TSubscriptionFailure(params *xapptweaks.RMRParams) {
493         xapp.Logger.Info("MSG from E2T: %s", params.String())
494         subFailMsg, err := c.e2ap.UnpackSubscriptionFailure(params.Payload)
495         if err != nil {
496                 xapp.Logger.Error("MSG-SubFail %s", idstring(err, params))
497                 return
498         }
499         subs, err := c.registry.GetSubscriptionFirstMatch([]uint32{subFailMsg.RequestId.Seq})
500         if err != nil {
501                 xapp.Logger.Error("MSG-SubFail: %s", idstring(err, params))
502                 return
503         }
504         trans := subs.GetTransaction()
505         if trans == nil {
506                 err = fmt.Errorf("Ongoing transaction not found")
507                 xapp.Logger.Error("MSG-SubFail: %s", idstring(err, params, subs))
508                 return
509         }
510         sendOk, timedOut := trans.SendEvent(subFailMsg, e2tRecvMsgTimeout)
511         if sendOk == false {
512                 err = fmt.Errorf("Passing event to transaction failed: sendOk(%t) timedOut(%t)", sendOk, timedOut)
513                 xapp.Logger.Error("MSG-SubFail: %s", idstring(err, trans, subs))
514         }
515         return
516 }
517
518 //-------------------------------------------------------------------
519 // handle from E2T Subscription Delete Response
520 //-------------------------------------------------------------------
521 func (c *Control) handleE2TSubscriptionDeleteResponse(params *xapptweaks.RMRParams) (err error) {
522         xapp.Logger.Info("MSG from E2T: %s", params.String())
523         subDelRespMsg, err := c.e2ap.UnpackSubscriptionDeleteResponse(params.Payload)
524         if err != nil {
525                 xapp.Logger.Error("MSG-SubDelResp: %s", idstring(err, params))
526                 return
527         }
528         subs, err := c.registry.GetSubscriptionFirstMatch([]uint32{subDelRespMsg.RequestId.Seq})
529         if err != nil {
530                 xapp.Logger.Error("MSG-SubDelResp: %s", idstring(err, params))
531                 return
532         }
533         trans := subs.GetTransaction()
534         if trans == nil {
535                 err = fmt.Errorf("Ongoing transaction not found")
536                 xapp.Logger.Error("MSG-SubDelResp: %s", idstring(err, params, subs))
537                 return
538         }
539         sendOk, timedOut := trans.SendEvent(subDelRespMsg, e2tRecvMsgTimeout)
540         if sendOk == false {
541                 err = fmt.Errorf("Passing event to transaction failed: sendOk(%t) timedOut(%t)", sendOk, timedOut)
542                 xapp.Logger.Error("MSG-SubDelResp: %s", idstring(err, trans, subs))
543         }
544         return
545 }
546
547 //-------------------------------------------------------------------
548 // handle from E2T Subscription Delete Failure
549 //-------------------------------------------------------------------
550 func (c *Control) handleE2TSubscriptionDeleteFailure(params *xapptweaks.RMRParams) {
551         xapp.Logger.Info("MSG from E2T: %s", params.String())
552         subDelFailMsg, err := c.e2ap.UnpackSubscriptionDeleteFailure(params.Payload)
553         if err != nil {
554                 xapp.Logger.Error("MSG-SubDelFail: %s", idstring(err, params))
555                 return
556         }
557         subs, err := c.registry.GetSubscriptionFirstMatch([]uint32{subDelFailMsg.RequestId.Seq})
558         if err != nil {
559                 xapp.Logger.Error("MSG-SubDelFail: %s", idstring(err, params))
560                 return
561         }
562         trans := subs.GetTransaction()
563         if trans == nil {
564                 err = fmt.Errorf("Ongoing transaction not found")
565                 xapp.Logger.Error("MSG-SubDelFail: %s", idstring(err, params, subs))
566                 return
567         }
568         sendOk, timedOut := trans.SendEvent(subDelFailMsg, e2tRecvMsgTimeout)
569         if sendOk == false {
570                 err = fmt.Errorf("Passing event to transaction failed: sendOk(%t) timedOut(%t)", sendOk, timedOut)
571                 xapp.Logger.Error("MSG-SubDelFail: %s", idstring(err, trans, subs))
572         }
573         return
574 }
575
576 //-------------------------------------------------------------------
577 //
578 //-------------------------------------------------------------------
579 func typeofSubsMessage(v interface{}) string {
580         if v == nil {
581                 return "NIL"
582         }
583         switch v.(type) {
584         case *e2ap.E2APSubscriptionRequest:
585                 return "SubReq"
586         case *e2ap.E2APSubscriptionResponse:
587                 return "SubResp"
588         case *e2ap.E2APSubscriptionFailure:
589                 return "SubFail"
590         case *e2ap.E2APSubscriptionDeleteRequest:
591                 return "SubDelReq"
592         case *e2ap.E2APSubscriptionDeleteResponse:
593                 return "SubDelResp"
594         case *e2ap.E2APSubscriptionDeleteFailure:
595                 return "SubDelFail"
596         default:
597                 return "Unknown"
598         }
599 }