- SubReqToE2: The total number of SubscriptionRequest messages sent to E2Term
- SubReReqToE2: The total number of SubscriptionRequest messages resent to E2Term
- SubRespFromE2: The total number of SubscriptionResponse messages from E2Term
+ - PartialSubRespFromE2: The total number of partial SubscriptionResponse messages from E2Term
- SubFailFromE2: The total number of SubscriptionFailure messages from E2Term
- SubReqTimerExpiry: The total number of SubscriptionRequest timer expires
- RouteCreateFail: The total number of subscription route create failure
all E2 subscriptions sent in REST subscription request. Maximum time to complete all E2 subscriptions in Subscription Manager can be calculated like this:
t >= 3 * 2s * count_of_subscriptions in the REST request. Length of supervising timers in Subscription Manager for the requests it sends to E2 Node is by
default 2 seconds. There can be only one ongoing E2 subscription request towards per E2 Node other requests are queued in Subscription Manager.
+
+Special notes
+-------------
+ According to E2 specification E2Node may accept subscription partially. This in not properly supported in REST interface between xApp and Subscription Manager.
+ The interface specification yaml lacks ActionNotAdmittedList IE for RICSubscriptionResponse and RICSubscriptionFailure messages. That information in now embedded as
+ workaround in the descriptive error string as a valid JSON string. Missing ActionNotAdmittedList will be added in the REST interface in some coming update.
+
+ Example descriptive error string for RICSubscriptionResponse:
+
+ Error cause RICSubscriptionResponse partially accepted: ActionNotAdmittedList: [{\"ActionId\":1,\"Cause\":{\"Content\":1,\"Value\":8}}]
+
+ Example descriptive error string for RICSubscriptionFailure:
+
+ Error cause RICSubscriptionFailure: ActionNotAdmittedList: [{\"ActionId\":1,\"Cause\":{\"Content\":5,\"Value\":1}}]
\ No newline at end of file
restSubscription.AddMd5Sum(md5sum)
xapp.Logger.Debug("SubscriptionRequest index=%v processed successfullyfor %s. endpoint=%v:%v, XappEventInstanceID=%v, E2EventInstanceID=%v, %s",
index, *restSubId, clientEndpoint.Host, *clientEndpoint.HTTPPort, xAppEventInstanceID, e2EventInstanceID, idstring(nil, trans))
- c.sendSuccesfullResponseNotification(restSubId, restSubscription, xAppEventInstanceID, e2EventInstanceID, clientEndpoint, trans)
+ c.sendSuccesfullResponseNotification(restSubId, restSubscription, xAppEventInstanceID, e2EventInstanceID, clientEndpoint, trans, errorInfo)
}
}
}
case *e2ap.E2APSubscriptionResponse:
trans.Release()
if c.e2IfState.IsE2ConnectionUp(meid) == true {
+ errorInfo = c.e2ap.CheckActionNotAdmittedList(xapp.RIC_SUB_RESP, themsg.ActionNotAdmittedList, c)
return themsg, &errorInfo, nil
} else {
c.registry.RemoveFromSubscription(subs, trans, waitRouteCleanup_ms, c)
errorInfo.SetInfo(err.Error(), models.SubscriptionInstanceErrorSourceE2Node, "")
}
case *e2ap.E2APSubscriptionFailure:
- err = fmt.Errorf("E2 SubscriptionFailure received")
- errorInfo.SetInfo(err.Error(), models.SubscriptionInstanceErrorSourceE2Node, "")
+ err = fmt.Errorf("E2 RICSubscriptionFailure received")
+ errorInfo = c.e2ap.CheckActionNotAdmittedList(xapp.RIC_SUB_FAILURE, themsg.ActionNotAdmittedList, c)
case *PackSubscriptionRequestErrortEvent:
- err = fmt.Errorf("E2 SubscriptionRequest pack failure")
+ err = fmt.Errorf("E2 RICSubscriptionRequest pack failure")
errorInfo = themsg.ErrorInfo
case *SDLWriteErrortEvent:
err = fmt.Errorf("SDL write failure")
}
} else {
// Timer expiry
- err = fmt.Errorf("E2 subscription response timeout")
+ err = fmt.Errorf("E2 RICSubscriptionResponse timeout")
errorInfo.SetInfo(err.Error(), "", models.SubscriptionInstanceTimeoutTypeE2Timeout)
if subs.PolicyUpdate == true {
return nil, &errorInfo, err
restSubscription.SetProcessed(err)
c.UpdateRESTSubscriptionInDB(*restSubId, restSubscription, false)
if trans != nil {
- xapp.Logger.Debug("Sending unsuccessful REST notification (cause %s) to endpoint=%v:%v, XappEventInstanceID=%v, E2EventInstanceID=%v, %s",
+ xapp.Logger.Debug("Sending unsuccessful REST notification (Error cause %s) to endpoint=%v:%v, XappEventInstanceID=%v, E2EventInstanceID=%v, %s",
errorInfo.ErrorCause, clientEndpoint.Host, *clientEndpoint.HTTPPort, xAppEventInstanceID, e2EventInstanceID, idstring(nil, trans))
} else {
- xapp.Logger.Debug("Sending unsuccessful REST notification (cause %s) to endpoint=%v:%v, XappEventInstanceID=%v, E2EventInstanceID=%v",
+ xapp.Logger.Debug("Sending unsuccessful REST notification (Error cause %s) to endpoint=%v:%v, XappEventInstanceID=%v, E2EventInstanceID=%v",
errorInfo.ErrorCause, clientEndpoint.Host, *clientEndpoint.HTTPPort, xAppEventInstanceID, e2EventInstanceID)
}
//
//-------------------------------------------------------------------
func (c *Control) sendSuccesfullResponseNotification(restSubId *string, restSubscription *RESTSubscription, xAppEventInstanceID int64, e2EventInstanceID int64,
- clientEndpoint *models.SubscriptionParamsClientEndpoint, trans *TransactionXapp) {
+ clientEndpoint *models.SubscriptionParamsClientEndpoint, trans *TransactionXapp, errorInfo *ErrorInfo) {
// Store successfully processed InstanceId for deletion
restSubscription.AddE2InstanceId((uint32)(e2EventInstanceID))
SubscriptionID: restSubId,
SubscriptionInstances: []*models.SubscriptionInstance{
&models.SubscriptionInstance{E2EventInstanceID: &e2EventInstanceID,
- ErrorCause: "",
+ ErrorCause: errorInfo.ErrorCause,
+ ErrorSource: errorInfo.ErrorSource,
XappEventInstanceID: &xAppEventInstanceID},
},
}
// Mark REST subscription request processesd.
restSubscription.SetProcessed(nil)
c.UpdateRESTSubscriptionInDB(*restSubId, restSubscription, false)
- xapp.Logger.Debug("Sending successful REST notification to endpoint=%v:%v, XappEventInstanceID=%v, E2EventInstanceID=%v, %s",
- clientEndpoint.Host, *clientEndpoint.HTTPPort, xAppEventInstanceID, e2EventInstanceID, idstring(nil, trans))
-
+ if errorInfo.ErrorCause != " " {
+ xapp.Logger.Debug("Sending successful REST notification (Error cause %s) to endpoint=%v:%v, XappEventInstanceID=%v, E2EventInstanceID=%v, %s",
+ errorInfo.ErrorCause, clientEndpoint.Host, *clientEndpoint.HTTPPort, xAppEventInstanceID, e2EventInstanceID, idstring(nil, trans))
+ } else {
+ xapp.Logger.Debug("Sending successful REST notification to endpoint=%v:%v, XappEventInstanceID=%v, E2EventInstanceID=%v, %s",
+ clientEndpoint.Host, *clientEndpoint.HTTPPort, xAppEventInstanceID, e2EventInstanceID, idstring(nil, trans))
+ }
c.UpdateCounter(cRestSubNotifToXapp)
xapp.Subscription.Notify(resp, *clientEndpoint)
import (
"encoding/hex"
+ "encoding/json"
"fmt"
"gerrit.o-ran-sc.org/r/ric-plt/e2ap/pkg/e2ap"
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
-func (c *E2ap) SetASN1DebugPrintStatus(logLevel int) {
+func (e *E2ap) SetASN1DebugPrintStatus(logLevel int) {
e2ap_wrapper.SetASN1DebugPrintStatus(logLevel)
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
-func (c *E2ap) FillSubscriptionReqMsgs(params interface{}, subreqList *e2ap.SubscriptionRequestList, restSubscription *RESTSubscription) error {
+func (e *E2ap) FillSubscriptionReqMsgs(params interface{}, subreqList *e2ap.SubscriptionRequestList, restSubscription *RESTSubscription) error {
xapp.Logger.Debug("FillSubscriptionReqMsgs")
p := params.(*models.SubscriptionParams)
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
-func (c *E2ap) UnpackSubscriptionRequest(payload []byte) (*e2ap.E2APSubscriptionRequest, error) {
+func (e *E2ap) CheckActionNotAdmittedList(msgType int, actionNotAdmittedList e2ap.ActionNotAdmittedList, c *Control) ErrorInfo {
+
+ var prefixString string
+ var errorInfo ErrorInfo
+ var actionNotAdmittedString string
+ if len(actionNotAdmittedList.Items) > 0 {
+ if msgType == xapp.RIC_SUB_RESP {
+ prefixString = "RICSubscriptionResponse partially accepted:"
+ c.UpdateCounter(cPartialSubRespFromE2)
+ } else if msgType == xapp.RIC_SUB_FAILURE {
+ prefixString = "RICSubscriptionFailure:"
+ }
+ jsonActionNotAdmittedList, err := json.Marshal(actionNotAdmittedList.Items)
+ if err != nil {
+ actionNotAdmittedString = "ActionNotAdmittedList > 0. Submgr json.Marshal error"
+ xapp.Logger.Error("CheckActionNotAdmittedList() json.Marshal error %s", err.Error())
+ } else {
+ actionNotAdmittedString = "ActionNotAdmittedList: " + string(jsonActionNotAdmittedList)
+ }
+ }
+ err := fmt.Errorf("%s %s", prefixString, actionNotAdmittedString)
+ errorInfo.SetInfo(err.Error(), models.SubscriptionInstanceErrorSourceE2Node, "")
+ return errorInfo
+}
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+func (e *E2ap) UnpackSubscriptionRequest(payload []byte) (*e2ap.E2APSubscriptionRequest, error) {
e2SubReq := packerif.NewPackerSubscriptionRequest()
err, subReq := e2SubReq.UnPack(&e2ap.PackedData{payload})
if err != nil {
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
-func (c *E2ap) UnpackSubscriptionResponse(payload []byte) (*e2ap.E2APSubscriptionResponse, error) {
+func (e *E2ap) UnpackSubscriptionResponse(payload []byte) (*e2ap.E2APSubscriptionResponse, error) {
e2SubResp := packerif.NewPackerSubscriptionResponse()
err, subResp := e2SubResp.UnPack(&e2ap.PackedData{payload})
if err != nil {
return subResp, nil
}
-func (c *E2ap) PackSubscriptionResponse(req *e2ap.E2APSubscriptionResponse) (int, *e2ap.PackedData, error) {
+func (e *E2ap) PackSubscriptionResponse(req *e2ap.E2APSubscriptionResponse) (int, *e2ap.PackedData, error) {
e2SubResp := packerif.NewPackerSubscriptionResponse()
err, packedData := e2SubResp.Pack(req)
if err != nil {
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
-func (c *E2ap) UnpackSubscriptionFailure(payload []byte) (*e2ap.E2APSubscriptionFailure, error) {
+func (e *E2ap) UnpackSubscriptionFailure(payload []byte) (*e2ap.E2APSubscriptionFailure, error) {
e2SubFail := packerif.NewPackerSubscriptionFailure()
err, subFail := e2SubFail.UnPack(&e2ap.PackedData{payload})
if err != nil {
return subFail, nil
}
-func (c *E2ap) PackSubscriptionFailure(req *e2ap.E2APSubscriptionFailure) (int, *e2ap.PackedData, error) {
+func (e *E2ap) PackSubscriptionFailure(req *e2ap.E2APSubscriptionFailure) (int, *e2ap.PackedData, error) {
e2SubFail := packerif.NewPackerSubscriptionFailure()
err, packedData := e2SubFail.Pack(req)
if err != nil {
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
-func (c *E2ap) UnpackSubscriptionDeleteRequest(payload []byte) (*e2ap.E2APSubscriptionDeleteRequest, error) {
+func (e *E2ap) UnpackSubscriptionDeleteRequest(payload []byte) (*e2ap.E2APSubscriptionDeleteRequest, error) {
e2SubDelReq := packerif.NewPackerSubscriptionDeleteRequest()
err, subDelReq := e2SubDelReq.UnPack(&e2ap.PackedData{payload})
if err != nil {
return subDelReq, nil
}
-func (c *E2ap) PackSubscriptionDeleteRequest(req *e2ap.E2APSubscriptionDeleteRequest) (int, *e2ap.PackedData, error) {
+func (e *E2ap) PackSubscriptionDeleteRequest(req *e2ap.E2APSubscriptionDeleteRequest) (int, *e2ap.PackedData, error) {
e2SubDelReq := packerif.NewPackerSubscriptionDeleteRequest()
err, packedData := e2SubDelReq.Pack(req)
if err != nil {
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
-func (c *E2ap) UnpackSubscriptionDeleteResponse(payload []byte) (*e2ap.E2APSubscriptionDeleteResponse, error) {
+func (e *E2ap) UnpackSubscriptionDeleteResponse(payload []byte) (*e2ap.E2APSubscriptionDeleteResponse, error) {
e2SubDelResp := packerif.NewPackerSubscriptionDeleteResponse()
err, subDelResp := e2SubDelResp.UnPack(&e2ap.PackedData{payload})
if err != nil {
return subDelResp, nil
}
-func (c *E2ap) PackSubscriptionDeleteResponse(req *e2ap.E2APSubscriptionDeleteResponse) (int, *e2ap.PackedData, error) {
+func (e *E2ap) PackSubscriptionDeleteResponse(req *e2ap.E2APSubscriptionDeleteResponse) (int, *e2ap.PackedData, error) {
e2SubDelResp := packerif.NewPackerSubscriptionDeleteResponse()
err, packedData := e2SubDelResp.Pack(req)
if err != nil {
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
-func (c *E2ap) UnpackSubscriptionDeleteFailure(payload []byte) (*e2ap.E2APSubscriptionDeleteFailure, error) {
+func (e *E2ap) UnpackSubscriptionDeleteFailure(payload []byte) (*e2ap.E2APSubscriptionDeleteFailure, error) {
e2SubDelFail := packerif.NewPackerSubscriptionDeleteFailure()
err, subDelFail := e2SubDelFail.UnPack(&e2ap.PackedData{payload})
if err != nil {
}
/*
-func (c *E2ap) PackSubscriptionDeleteFailure(req *e2ap.E2APSubscriptionDeleteFailure) (int, *e2ap.PackedData, error) {
+func (e *E2ap) PackSubscriptionDeleteFailure(req *e2ap.E2APSubscriptionDeleteFailure) (int, *e2ap.PackedData, error) {
e2SubDelFail := packerif.NewPackerSubscriptionDeleteFailure()
err, packedData := e2SubDelFail.Pack(req)
if err != nil {
cSubReqToE2 string = "SubReqToE2"
cSubReReqToE2 string = "SubReReqToE2"
cSubRespFromE2 string = "SubRespFromE2"
+ cPartialSubRespFromE2 string = "PartialSubRespFromE2"
cSubFailFromE2 string = "SubFailFromE2"
cSubReqTimerExpiry string = "SubReqTimerExpiry"
cRouteCreateFail string = "RouteCreateFail"
{Name: cRestSubFailNotifToXapp, Help: "The total number of failure Rest SubscriptionNotification messages sent to xApp"},
{Name: cSubReqToE2, Help: "The total number of SubscriptionRequest messages sent to E2Term"},
{Name: cSubReReqToE2, Help: "The total number of SubscriptionRequest messages resent to E2Term"},
+ {Name: cPartialSubRespFromE2, Help: "The total number of partial SubscriptionResponse messages from E2Term"},
{Name: cSubRespFromE2, Help: "The total number of SubscriptionResponse messages from E2Term"},
{Name: cSubFailFromE2, Help: "The total number of SubscriptionFailure messages from E2Term"},
{Name: cSubReqTimerExpiry, Help: "The total number of SubscriptionRequest timer expires"},
Counter{cSubReqToE2, 1},
Counter{cSubReReqToE2, 1},
Counter{cSubRespFromE2, 1},
+ Counter{cPartialSubRespFromE2, 1},
Counter{cSubFailFromE2, 1},
Counter{cSubReqTimerExpiry, 1},
Counter{cRouteCreateFail, 1},
mainCtrl.c.UpdateCounter(cSubReqToE2)
mainCtrl.c.UpdateCounter(cSubReReqToE2)
mainCtrl.c.UpdateCounter(cSubRespFromE2)
+ mainCtrl.c.UpdateCounter(cPartialSubRespFromE2)
mainCtrl.c.UpdateCounter(cSubFailFromE2)
mainCtrl.c.UpdateCounter(cSubReqTimerExpiry)
mainCtrl.c.UpdateCounter(cRouteCreateFail)
mainCtrl.VerifyAllClean(t)
}
+//-----------------------------------------------------------------------------
+// TestRESTSubReqPartialResp
+//
+// stub stub
+// +-------+ +---------+ +---------+
+// | xapp | | submgr | | e2term |
+// +-------+ +---------+ +---------+
+// | | |
+// | RESTSubReq | |
+// |---------------->| |
+// | RESTSubResp | |
+// |<----------------| |
+// | | SubReq |
+// | |------------->|
+// | | SubResp | Partially accepted
+// | |<-------------|
+// | | |
+// | RESTNotif | |
+// |<----------------| |
+// | | |
+// | [SUBS DELETE] |
+// | | |
+//
+//-----------------------------------------------------------------------------
+
+func TestRESTSubReqPartialResp(t *testing.T) {
+
+ // Init counter check
+ mainCtrl.CounterValuesToBeVeriefied(t, CountersToBeAdded{
+ Counter{cRestSubReqFromXapp, 1},
+ Counter{cRestSubRespToXapp, 1},
+ Counter{cSubReqToE2, 1},
+ Counter{cSubRespFromE2, 1},
+ Counter{cPartialSubRespFromE2, 1},
+ Counter{cRestSubNotifToXapp, 1},
+ Counter{cRestSubDelReqFromXapp, 1},
+ Counter{cSubDelReqToE2, 1},
+ Counter{cSubDelRespFromE2, 1},
+ Counter{cRestSubDelRespToXapp, 1},
+ })
+
+ // Req
+ params := xappConn1.GetRESTSubsReqReportParams(subReqCount)
+
+ actionId := int64(2)
+ actionType := "report"
+ actionDefinition := []int64{5678, 1}
+ subsequestActionType := "continue"
+ timeToWait := "w10ms"
+ params.AppendActionToActionToBeSetupList(actionId, actionType, actionDefinition, subsequestActionType, timeToWait)
+
+ restSubId := xappConn1.SendRESTSubsReq(t, params)
+ crereq, cremsg := e2termConn1.RecvSubsReq(t)
+ xappConn1.ExpectRESTNotification(t, restSubId)
+
+ actionNotAdmittedItem := e2ap.ActionNotAdmittedItem{}
+ actionNotAdmittedItem.ActionId = 1
+ actionNotAdmittedItem.Cause.Content = 1
+ actionNotAdmittedItem.Cause.Value = 8
+ actionNotAdmittedList := e2ap.ActionNotAdmittedList{}
+ actionNotAdmittedList.Items = append(actionNotAdmittedList.Items, actionNotAdmittedItem)
+ e2termConn1.SendPartialSubsResp(t, crereq, cremsg, actionNotAdmittedList)
+ e2SubsId := xappConn1.WaitRESTNotification(t, restSubId)
+
+ queryXappSubscription(t, int64(e2SubsId), "RAN_NAME_1", []string{"localhost:13560"})
+
+ // Del
+ deleteSubscription(t, xappConn1, e2termConn1, &restSubId)
+
+ mainCtrl.wait_subs_clean(t, e2SubsId, 10)
+ //Wait that subs is cleaned
+ waitSubsCleanup(t, e2SubsId, 10)
+
+ mainCtrl.VerifyCounterValues(t)
+ mainCtrl.VerifyAllClean(t)
+}
+
//-----------------------------------------------------------------------------
// TestRESTSubDelReqRetryInSubmgr
//
resp.ActionAdmittedList.Items[index].ActionId = req.ActionSetups[index].ActionId
}
- for index := uint64(0); index < 1; index++ {
- item := e2ap.ActionNotAdmittedItem{}
- item.ActionId = index
- item.Cause.Content = 1
- item.Cause.Value = 1
- resp.ActionNotAdmittedList.Items = append(resp.ActionNotAdmittedList.Items, item)
+ packerr, packedMsg := e2SubsResp.Pack(resp)
+ if packerr != nil {
+ tc.TestError(t, "pack NOK %s", packerr.Error())
+ }
+ tc.Debug("%s", e2SubsResp.String())
+
+ params := &xapp.RMRParams{}
+ params.Mtype = xapp.RIC_SUB_RESP
+ //params.SubId = msg.SubId
+ params.SubId = -1
+ params.Payload = packedMsg.Buf
+ params.PayloadLen = len(packedMsg.Buf)
+ params.Meid = msg.Meid
+ //params.Xid = msg.Xid
+ params.Mbuf = nil
+
+ tc.Debug("SEND SUB RESP: %s", params.String())
+ snderr := tc.SendWithRetry(params, false, 5)
+ if snderr != nil {
+ tc.TestError(t, "RMR SEND FAILED: %s", snderr.Error())
+ }
+}
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+func (tc *E2Stub) SendPartialSubsResp(t *testing.T, req *e2ap.E2APSubscriptionRequest, msg *xapp.RMRParams, actionNotAdmittedList e2ap.ActionNotAdmittedList) {
+ tc.Debug("SendPartialSubsResp")
+
+ if len(actionNotAdmittedList.Items) == 0 {
+ tc.TestError(t, "SendPartialSubsResp() Empty actionNotAdmittedList.Items")
+ return
+ }
+
+ e2SubsResp := e2asnpacker.NewPackerSubscriptionResponse()
+
+ //---------------------------------
+ // e2term activity: Send Subs Resp
+ //---------------------------------
+ resp := &e2ap.E2APSubscriptionResponse{}
+
+ resp.RequestId.Id = req.RequestId.Id
+ resp.RequestId.InstanceId = req.RequestId.InstanceId
+ resp.FunctionId = req.FunctionId
+
+ for index, actionNotAdmittedItem := range actionNotAdmittedList.Items {
+ for _, ActionToBeSetupItem := range req.ActionSetups {
+ if ActionToBeSetupItem.ActionId == actionNotAdmittedItem.ActionId {
+ actionNotAdmittedItem := e2ap.ActionNotAdmittedItem{}
+ actionNotAdmittedItem.ActionId = ActionToBeSetupItem.ActionId
+ actionNotAdmittedItem.Cause.Content = 1
+ actionNotAdmittedItem.Cause.Value = 8
+ resp.ActionNotAdmittedList.Items = append(resp.ActionNotAdmittedList.Items, actionNotAdmittedItem)
+ // Remove the element
+ req.ActionSetups = append(req.ActionSetups[:index], req.ActionSetups[index+1:]...)
+
+ }
+ }
+ }
+ for _, ActionToBeSetupItem := range req.ActionSetups {
+ actionAdmittedItem := e2ap.ActionAdmittedItem{}
+ actionAdmittedItem.ActionId = ActionToBeSetupItem.ActionId
+ resp.ActionAdmittedList.Items = append(resp.ActionAdmittedList.Items, actionAdmittedItem)
}
packerr, packedMsg := e2SubsResp.Pack(resp)