Use packed data to store cache encoded message
[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         "gerrit.o-ran-sc.org/r/ric-plt/e2ap/pkg/packer"
26         rtmgrclient "gerrit.o-ran-sc.org/r/ric-plt/submgr/pkg/rtmgr_client"
27         rtmgrhandle "gerrit.o-ran-sc.org/r/ric-plt/submgr/pkg/rtmgr_client/handle"
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         "math/rand"
33         "sync"
34         "time"
35 )
36
37 //-----------------------------------------------------------------------------
38 //
39 //-----------------------------------------------------------------------------
40
41 var subReqTime time.Duration = 5 * time.Second
42 var subDelReqTime time.Duration = 5 * time.Second
43 var maxSubReqTryCount uint64 = 2    // Initial try + retry
44 var maxSubDelReqTryCount uint64 = 2 // Initial try + retry
45
46 type Control struct {
47         e2ap         *E2ap
48         registry     *Registry
49         tracker      *Tracker
50         timerMap     *TimerMap
51         rmrSendMutex sync.Mutex
52         msgCounter   uint64
53 }
54
55 type RMRMeid struct {
56         PlmnID  string
57         EnbID   string
58         RanName string
59 }
60
61 var seedSN uint16
62
63 const (
64         CREATE Action = 0
65         MERGE  Action = 1
66         NONE   Action = 2
67         DELETE Action = 3
68 )
69
70 func init() {
71         xapp.Logger.Info("SUBMGR")
72         viper.AutomaticEnv()
73         viper.SetEnvPrefix("submgr")
74         viper.AllowEmptyEnv(true)
75         seedSN = uint16(viper.GetInt("seed_sn"))
76         if seedSN == 0 {
77                 rand.Seed(time.Now().UnixNano())
78                 seedSN = uint16(rand.Intn(65535))
79         }
80         if seedSN > 65535 {
81                 seedSN = 0
82         }
83         xapp.Logger.Info("SUBMGR: Initial Sequence Number: %v", seedSN)
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         client := rtmgrclient.New(transport, strfmt.Default)
90         handle := rtmgrhandle.NewProvideXappSubscriptionHandleParamsWithTimeout(10 * time.Second)
91         deleteHandle := rtmgrhandle.NewDeleteXappSubscriptionHandleParamsWithTimeout(10 * time.Second)
92         rtmgrClient := RtmgrClient{client, handle, deleteHandle}
93
94         registry := new(Registry)
95         registry.Initialize(seedSN)
96         registry.rtmgrClient = &rtmgrClient
97
98         tracker := new(Tracker)
99         tracker.Init()
100
101         timerMap := new(TimerMap)
102         timerMap.Init()
103
104         return &Control{e2ap: new(E2ap),
105                 registry:   registry,
106                 tracker:    tracker,
107                 timerMap:   timerMap,
108                 msgCounter: 0,
109         }
110 }
111
112 func (c *Control) Run() {
113         xapp.Run(c)
114 }
115
116 func (c *Control) rmrSendRaw(desc string, params *RMRParams) (err error) {
117
118         xapp.Logger.Info("%s: %s", desc, params.String())
119         status := false
120         i := 1
121         for ; i <= 10 && status == false; i++ {
122                 c.rmrSendMutex.Lock()
123                 status = xapp.Rmr.Send(params.RMRParams, false)
124                 c.rmrSendMutex.Unlock()
125                 if status == false {
126                         xapp.Logger.Info("rmr.Send() failed. Retry count %d, %s", i, params.String())
127                         time.Sleep(500 * time.Millisecond)
128                 }
129         }
130         if status == false {
131                 err = fmt.Errorf("rmr.Send() failed. Retry count %d, %s", i, params.String())
132                 xapp.Logger.Error("%s: %s", desc, err.Error())
133                 xapp.Rmr.Free(params.Mbuf)
134         }
135         return
136 }
137
138 func (c *Control) rmrSend(desc string, subs *Subscription, trans *Transaction, payload *packer.PackedData) (err error) {
139         params := &RMRParams{&xapp.RMRParams{}}
140         params.Mtype = trans.GetMtype()
141         params.SubId = int(subs.GetSubId())
142         params.Xid = ""
143         params.Meid = subs.GetMeid()
144         params.Src = ""
145         params.PayloadLen = len(payload.Buf)
146         params.Payload = payload.Buf
147         params.Mbuf = nil
148
149         return c.rmrSendRaw(desc, params)
150 }
151
152 func (c *Control) rmrReplyToSender(desc string, subs *Subscription, trans *Transaction, mType int, payload *packer.PackedData) (err error) {
153         params := &RMRParams{&xapp.RMRParams{}}
154         params.Mtype = mType
155         params.SubId = int(subs.GetSubId())
156         params.Xid = trans.GetXid()
157         params.Meid = trans.GetMeid()
158         params.Src = ""
159         params.PayloadLen = len(payload.Buf)
160         params.Payload = payload.Buf
161         params.Mbuf = nil
162
163         return c.rmrSendRaw(desc, params)
164 }
165
166 func (c *Control) Consume(params *xapp.RMRParams) (err error) {
167         xapp.Rmr.Free(params.Mbuf)
168         params.Mbuf = nil
169         msg := &RMRParams{params}
170         c.msgCounter++
171         switch msg.Mtype {
172         case xapp.RICMessageTypes["RIC_SUB_REQ"]:
173                 go c.handleSubscriptionRequest(msg)
174         case xapp.RICMessageTypes["RIC_SUB_RESP"]:
175                 go c.handleSubscriptionResponse(msg)
176         case xapp.RICMessageTypes["RIC_SUB_FAILURE"]:
177                 go c.handleSubscriptionFailure(msg)
178         case xapp.RICMessageTypes["RIC_SUB_DEL_REQ"]:
179                 go c.handleSubscriptionDeleteRequest(msg)
180         case xapp.RICMessageTypes["RIC_SUB_DEL_RESP"]:
181                 go c.handleSubscriptionDeleteResponse(msg)
182         case xapp.RICMessageTypes["RIC_SUB_DEL_FAILURE"]:
183                 go c.handleSubscriptionDeleteFailure(msg)
184         default:
185                 xapp.Logger.Info("Unknown Message Type '%d', discarding", msg.Mtype)
186         }
187
188         return nil
189 }
190
191 func (c *Control) handleSubscriptionRequest(params *RMRParams) {
192         xapp.Logger.Info("SubReq from xapp: %s", params.String())
193
194         //
195         //
196         //
197         trans, err := c.tracker.TrackTransaction(NewRmrEndpoint(params.Src),
198                 params.Mtype,
199                 params.Xid,
200                 params.Meid,
201                 false,
202                 true)
203
204         if err != nil {
205                 xapp.Logger.Error("SubReq: %s, Dropping this msg. %s", err.Error(), params.String())
206                 return
207         }
208
209         //
210         //
211         //
212         trans.SubReqMsg, err = c.e2ap.UnpackSubscriptionRequest(params.Payload)
213         if err != nil {
214                 xapp.Logger.Error("SubReq: %s Dropping this msg. %s", err.Error(), trans)
215                 trans.Release()
216                 return
217         }
218
219         //
220         //
221         //
222         subs, err := c.registry.ReserveSubscription(&trans.RmrEndpoint, trans.Meid)
223         if err != nil {
224                 xapp.Logger.Error("SubReq: %s, Dropping this msg. %s", err.Error(), trans)
225                 trans.Release()
226                 return
227         }
228
229         err = subs.SetTransaction(trans)
230         if err != nil {
231                 xapp.Logger.Error("SubReq: %s, Dropping this msg. %s", err.Error(), trans)
232                 subs.Release()
233                 trans.Release()
234                 return
235         }
236
237         trans.SubReqMsg.RequestId.Seq = uint32(subs.GetSubId())
238
239         //
240         // TODO: subscription create is in fact owned by subscription and not transaction.
241         //       Transaction is toward xapp while Subscription is toward ran.
242         //       In merge several xapps may wake transactions, while only one subscription
243         //       toward ran occurs -> subscription owns subscription creation toward ran
244         //
245         //       This is intermediate solution while improving message handling
246         //
247         trans.Payload, err = c.e2ap.PackSubscriptionRequest(trans.SubReqMsg)
248         if err != nil {
249                 xapp.Logger.Error("SubReq: %s for trans %s", err.Error(), trans)
250                 subs.Release()
251                 trans.Release()
252                 return
253         }
254
255         c.rmrSend("SubReq: SubReq to E2T", subs, trans, trans.Payload)
256
257         c.timerMap.StartTimer("RIC_SUB_REQ", int(subs.GetSubId()), subReqTime, FirstTry, c.handleSubscriptionRequestTimer)
258         xapp.Logger.Debug("SubReq: Debugging trans table = %v", c.tracker.transactionXappTable)
259         return
260 }
261
262 func (c *Control) handleSubscriptionResponse(params *RMRParams) {
263         xapp.Logger.Info("SubResp from E2T: %s", params.String())
264
265         //
266         //
267         //
268         SubRespMsg, err := c.e2ap.UnpackSubscriptionResponse(params.Payload)
269         if err != nil {
270                 xapp.Logger.Error("SubDelReq: %s Dropping this msg. %s", err.Error(), params.String())
271                 return
272         }
273
274         //
275         //
276         //
277         subs := c.registry.GetSubscription(uint16(SubRespMsg.RequestId.Seq))
278         if subs == nil && params.SubId > 0 {
279                 subs = c.registry.GetSubscription(uint16(params.SubId))
280         }
281
282         if subs == nil {
283                 xapp.Logger.Error("SubResp: Not valid subscription found payloadSeqNum: %d, SubId: %d. Dropping this msg. %s", SubRespMsg.RequestId.Seq, params.SubId, params.String())
284                 return
285         }
286         xapp.Logger.Info("SubResp: subscription found payloadSeqNum: %d, SubId: %d", SubRespMsg.RequestId.Seq, subs.GetSubId())
287
288         //
289         //
290         //
291         trans := subs.GetTransaction()
292         if trans == nil {
293                 xapp.Logger.Error("SubResp: Unknown trans. Dropping this msg. SubId: %d", subs.GetSubId())
294                 return
295         }
296
297         trans.SubRespMsg = SubRespMsg
298
299         //
300         //
301         //
302         c.timerMap.StopTimer("RIC_SUB_REQ", int(subs.GetSubId()))
303
304         responseReceived := trans.CheckResponseReceived()
305         if responseReceived == true {
306                 // Subscription timer already received
307                 return
308         }
309
310         trans.Payload, err = c.e2ap.PackSubscriptionResponse(trans.SubRespMsg)
311         if err != nil {
312                 xapp.Logger.Error("SubResp: %s for trans %s", err.Error(), trans)
313                 trans.Release()
314                 return
315         }
316
317         subs.Confirmed()
318         trans.Release()
319         c.rmrReplyToSender("SubResp: SubResp to xapp", subs, trans, 12011, trans.Payload)
320         return
321 }
322
323 func (c *Control) handleSubscriptionFailure(params *RMRParams) {
324         xapp.Logger.Info("SubFail from E2T: %s", params.String())
325
326         //
327         //
328         //
329         SubFailMsg, err := c.e2ap.UnpackSubscriptionFailure(params.Payload)
330         if err != nil {
331                 xapp.Logger.Error("SubFail: %s Dropping this msg. %s", err.Error(), params.String())
332                 return
333         }
334
335         //
336         //
337         //
338         subs := c.registry.GetSubscription(uint16(SubFailMsg.RequestId.Seq))
339         if subs == nil && params.SubId > 0 {
340                 subs = c.registry.GetSubscription(uint16(params.SubId))
341         }
342
343         if subs == nil {
344                 xapp.Logger.Error("SubFail: Not valid subscription found payloadSeqNum: %d, SubId: %d. Dropping this msg. %s", SubFailMsg.RequestId.Seq, params.SubId, params.String())
345                 return
346         }
347         xapp.Logger.Info("SubFail: subscription found payloadSeqNum: %d, SubId: %d", SubFailMsg.RequestId.Seq, subs.GetSubId())
348
349         //
350         //
351         //
352         trans := subs.GetTransaction()
353         if trans == nil {
354                 xapp.Logger.Error("SubFail: Unknown trans. Dropping this msg. SubId: %d", subs.GetSubId())
355                 return
356         }
357         trans.SubFailMsg = SubFailMsg
358
359         //
360         //
361         //
362         c.timerMap.StopTimer("RIC_SUB_REQ", int(subs.GetSubId()))
363
364         responseReceived := trans.CheckResponseReceived()
365         if err != nil {
366                 return
367         }
368
369         if responseReceived == true {
370                 // Subscription timer already received
371                 return
372         }
373
374         trans.Payload, err = c.e2ap.PackSubscriptionFailure(trans.SubFailMsg)
375         if err == nil {
376                 c.rmrReplyToSender("SubFail: SubFail to xapp", subs, trans, 12012, trans.Payload)
377                 time.Sleep(3 * time.Second)
378         } else {
379                 //TODO error handling improvement
380                 xapp.Logger.Error("SubFail: %s for trans %s (continuing cleaning)", err.Error(), trans)
381         }
382
383         trans.Release()
384         subs.Release()
385         return
386 }
387
388 func (c *Control) handleSubscriptionRequestTimer(strId string, nbrId int, tryCount uint64) {
389         xapp.Logger.Info("SubReq timeout: subId: %v,  tryCount: %v", nbrId, tryCount)
390
391         subs := c.registry.GetSubscription(uint16(nbrId))
392         if subs == nil {
393                 xapp.Logger.Error("SubReq timeout: Unknown payloadSeqNum. Dropping this msg. SubId: %v", nbrId)
394                 return
395         }
396
397         trans := subs.GetTransaction()
398         if trans == nil {
399                 xapp.Logger.Error("SubReq timeout: Unknown trans. Dropping this msg. SubId: %v", subs.GetSubId())
400                 return
401         }
402
403         responseReceived := trans.CheckResponseReceived()
404
405         if responseReceived == true {
406                 // Subscription Response or Failure already received
407                 return
408         }
409
410         if tryCount < maxSubReqTryCount {
411                 xapp.Logger.Info("SubReq timeout: Resending SubReq to E2T: Mtype: %v, SubId: %v, Xid %s, Meid %v", trans.GetMtype(), subs.GetSubId(), trans.GetXid(), trans.GetMeid())
412
413                 trans.RetryTransaction()
414
415                 c.rmrSend("SubReq timeout: SubReq to E2T", subs, trans, trans.Payload)
416
417                 tryCount++
418                 c.timerMap.StartTimer("RIC_SUB_REQ", int(subs.GetSubId()), subReqTime, tryCount, c.handleSubscriptionRequestTimer)
419                 return
420         }
421
422         // Release CREATE transaction
423         trans.Release()
424
425         // Create DELETE transaction (internal and no messages toward xapp)
426         deltrans, err := c.tracker.TrackTransaction(&trans.RmrEndpoint,
427                 12020, // RIC SUBSCRIPTION DELETE
428                 trans.GetXid(),
429                 trans.GetMeid(),
430                 false,
431                 false)
432
433         if err != nil {
434                 xapp.Logger.Error("SubReq timeout: %s, Dropping this msg.", err.Error())
435                 //TODO improve error handling. Important at least in merge
436                 subs.Release()
437                 return
438         }
439
440         deltrans.SubDelReqMsg = &e2ap.E2APSubscriptionDeleteRequest{}
441         deltrans.SubDelReqMsg.RequestId.Id = trans.SubReqMsg.RequestId.Id
442         deltrans.SubDelReqMsg.RequestId.Seq = uint32(subs.GetSubId())
443         deltrans.SubDelReqMsg.FunctionId = trans.SubReqMsg.FunctionId
444         deltrans.Payload, err = c.e2ap.PackSubscriptionDeleteRequest(deltrans.SubDelReqMsg)
445         if err != nil {
446                 xapp.Logger.Error("SubReq timeout: Packing SubDelReq failed. Err: %v", err)
447                 //TODO improve error handling. Important at least in merge
448                 deltrans.Release()
449                 subs.Release()
450                 return
451         }
452
453         err = subs.SetTransaction(deltrans)
454         if err != nil {
455                 xapp.Logger.Error("SubReq timeout: %s, Dropping this msg.", err.Error())
456                 //TODO improve error handling. Important at least in merge
457                 deltrans.Release()
458                 return
459         }
460
461         c.rmrSend("SubReq timer: SubDelReq to E2T", subs, deltrans, deltrans.Payload)
462         c.timerMap.StartTimer("RIC_SUB_DEL_REQ", int(subs.GetSubId()), subDelReqTime, FirstTry, c.handleSubscriptionDeleteRequestTimer)
463         return
464 }
465
466 func (c *Control) handleSubscriptionDeleteRequest(params *RMRParams) {
467         xapp.Logger.Info("SubDelReq from xapp: %s", params.String())
468
469         //
470         //
471         //
472         trans, err := c.tracker.TrackTransaction(NewRmrEndpoint(params.Src),
473                 params.Mtype,
474                 params.Xid,
475                 params.Meid,
476                 false,
477                 true)
478
479         if err != nil {
480                 xapp.Logger.Error("SubDelReq: %s, Dropping this msg. %s", err.Error(), params.String())
481                 return
482         }
483
484         //
485         //
486         //
487         trans.SubDelReqMsg, err = c.e2ap.UnpackSubscriptionDeleteRequest(params.Payload)
488         if err != nil {
489                 xapp.Logger.Error("SubDelReq: %s Dropping this msg. %s", err.Error(), trans)
490                 trans.Release()
491                 return
492         }
493
494         //
495         //
496         //
497         subs := c.registry.GetSubscription(uint16(trans.SubDelReqMsg.RequestId.Seq))
498         if subs == nil && params.SubId > 0 {
499                 subs = c.registry.GetSubscription(uint16(params.SubId))
500         }
501
502         if subs == nil {
503                 xapp.Logger.Error("SubDelReq: Not valid subscription found payloadSeqNum: %d, SubId: %d. Dropping this msg. %s", trans.SubDelReqMsg.RequestId.Seq, params.SubId, trans)
504                 trans.Release()
505                 return
506         }
507         xapp.Logger.Info("SubDelReq: subscription found payloadSeqNum: %d, SubId: %d. %s", trans.SubDelReqMsg.RequestId.Seq, params.SubId, trans)
508
509         err = subs.SetTransaction(trans)
510         if err != nil {
511                 xapp.Logger.Error("SubDelReq: %s, Dropping this msg. %s", err.Error(), trans)
512                 trans.Release()
513                 return
514         }
515
516         //
517         // TODO: subscription delete is in fact owned by subscription and not transaction.
518         //       Transaction is toward xapp while Subscription is toward ran.
519         //       In merge several xapps may wake transactions, while only one subscription
520         //       toward ran occurs -> subscription owns subscription creation toward ran
521         //
522         //       This is intermediate solution while improving message handling
523         //
524         trans.Payload, err = c.e2ap.PackSubscriptionDeleteRequest(trans.SubDelReqMsg)
525         if err != nil {
526                 xapp.Logger.Error("SubDelReq: %s for trans %s", err.Error(), trans)
527                 trans.Release()
528                 return
529         }
530
531         subs.UnConfirmed()
532
533         c.rmrSend("SubDelReq: SubDelReq to E2T", subs, trans, trans.Payload)
534
535         c.timerMap.StartTimer("RIC_SUB_DEL_REQ", int(subs.GetSubId()), subDelReqTime, FirstTry, c.handleSubscriptionDeleteRequestTimer)
536         return
537 }
538
539 func (c *Control) handleSubscriptionDeleteResponse(params *RMRParams) (err error) {
540         xapp.Logger.Info("SubDelResp from E2T:%s", params.String())
541
542         //
543         //
544         //
545         SubDelRespMsg, err := c.e2ap.UnpackSubscriptionDeleteResponse(params.Payload)
546         if err != nil {
547                 xapp.Logger.Error("SubDelResp: %s Dropping this msg. %s", err.Error(), params.String())
548                 return
549         }
550
551         //
552         //
553         //
554         subs := c.registry.GetSubscription(uint16(SubDelRespMsg.RequestId.Seq))
555         if subs == nil && params.SubId > 0 {
556                 subs = c.registry.GetSubscription(uint16(params.SubId))
557         }
558
559         if subs == nil {
560                 xapp.Logger.Error("SubDelResp: Not valid subscription found payloadSeqNum: %d, SubId: %d. Dropping this msg. %s", SubDelRespMsg.RequestId.Seq, params.SubId, params.String())
561                 return
562         }
563         xapp.Logger.Info("SubDelResp: subscription found payloadSeqNum: %d, SubId: %d", SubDelRespMsg.RequestId.Seq, subs.GetSubId())
564
565         //
566         //
567         //
568         trans := subs.GetTransaction()
569         if trans == nil {
570                 xapp.Logger.Error("SubDelResp: Unknown trans. Dropping this msg. SubId: %d", subs.GetSubId())
571                 return
572         }
573
574         trans.SubDelRespMsg = SubDelRespMsg
575
576         //
577         //
578         //
579         c.timerMap.StopTimer("RIC_SUB_DEL_REQ", int(subs.GetSubId()))
580
581         responseReceived := trans.CheckResponseReceived()
582         if responseReceived == true {
583                 // Subscription Delete timer already received
584                 return
585         }
586
587         c.sendSubscriptionDeleteResponse("SubDelResp", trans, subs)
588         return
589 }
590
591 func (c *Control) handleSubscriptionDeleteFailure(params *RMRParams) {
592         xapp.Logger.Info("SubDelFail from E2T:%s", params.String())
593
594         //
595         //
596         //
597         SubDelFailMsg, err := c.e2ap.UnpackSubscriptionDeleteFailure(params.Payload)
598         if err != nil {
599                 xapp.Logger.Error("SubDelFail: %s Dropping this msg. %s", err.Error(), params.String())
600                 return
601         }
602
603         //
604         //
605         //
606         subs := c.registry.GetSubscription(uint16(SubDelFailMsg.RequestId.Seq))
607         if subs == nil && params.SubId > 0 {
608                 subs = c.registry.GetSubscription(uint16(params.SubId))
609         }
610
611         if subs == nil {
612                 xapp.Logger.Error("SubDelFail: Not valid subscription found payloadSeqNum: %d, SubId: %d. Dropping this msg. %s", SubDelFailMsg.RequestId.Seq, params.SubId, params.String())
613                 return
614         }
615         xapp.Logger.Info("SubDelFail: subscription found payloadSeqNum: %d, SubId: %d", SubDelFailMsg.RequestId.Seq, subs.GetSubId())
616
617         //
618         //
619         //
620         trans := subs.GetTransaction()
621         if trans == nil {
622                 xapp.Logger.Error("SubDelFail: Unknown trans. Dropping this msg. SubId: %d", subs.GetSubId())
623                 return
624         }
625         trans.SubDelFailMsg = SubDelFailMsg
626
627         //
628         //
629         //
630         c.timerMap.StopTimer("RIC_SUB_DEL_REQ", int(subs.GetSubId()))
631
632         responseReceived := trans.CheckResponseReceived()
633         if responseReceived == true {
634                 // Subscription Delete timer already received
635                 return
636         }
637
638         c.sendSubscriptionDeleteResponse("SubDelFail", trans, subs)
639         return
640 }
641
642 func (c *Control) handleSubscriptionDeleteRequestTimer(strId string, nbrId int, tryCount uint64) {
643         xapp.Logger.Info("SubDelReq timeout: subId: %v, tryCount: %v", nbrId, tryCount)
644
645         subs := c.registry.GetSubscription(uint16(nbrId))
646         if subs == nil {
647                 xapp.Logger.Error("SubDelReq timeout: Unknown payloadSeqNum. Dropping this msg. SubId: %v", nbrId)
648                 return
649         }
650
651         trans := subs.GetTransaction()
652         if trans == nil {
653                 xapp.Logger.Error("SubDelReq timeout: Unknown trans. Dropping this msg. SubId: %v", subs.GetSubId())
654                 return
655         }
656
657         responseReceived := trans.CheckResponseReceived()
658         if responseReceived == true {
659                 // Subscription Delete Response or Failure already received
660                 return
661         }
662
663         if tryCount < maxSubDelReqTryCount {
664                 // Set possible to handle new response for the subId
665                 trans.RetryTransaction()
666                 c.rmrSend("SubDelReq timeout: SubDelReq to E2T", subs, trans, trans.Payload)
667                 tryCount++
668                 c.timerMap.StartTimer("RIC_SUB_DEL_REQ", int(subs.GetSubId()), subReqTime, tryCount, c.handleSubscriptionDeleteRequestTimer)
669                 return
670         }
671
672         c.sendSubscriptionDeleteResponse("SubDelReq(timer)", trans, subs)
673         return
674 }
675
676 func (c *Control) sendSubscriptionDeleteResponse(desc string, trans *Transaction, subs *Subscription) {
677
678         if trans.ForwardRespToXapp == true {
679                 //Always generate SubDelResp
680                 trans.SubDelRespMsg = &e2ap.E2APSubscriptionDeleteResponse{}
681                 trans.SubDelRespMsg.RequestId.Id = trans.SubDelReqMsg.RequestId.Id
682                 trans.SubDelRespMsg.RequestId.Seq = uint32(subs.GetSubId())
683                 trans.SubDelRespMsg.FunctionId = trans.SubDelReqMsg.FunctionId
684
685                 var err error
686                 trans.Payload, err = c.e2ap.PackSubscriptionDeleteResponse(trans.SubDelRespMsg)
687                 if err == nil {
688                         c.rmrReplyToSender(desc+": SubDelResp to xapp", subs, trans, 12021, trans.Payload)
689                         time.Sleep(3 * time.Second)
690                 } else {
691                         //TODO error handling improvement
692                         xapp.Logger.Error("%s: %s for trans %s (continuing cleaning)", desc, err.Error(), trans)
693                 }
694         }
695
696         trans.Release()
697         subs.Release()
698 }