Skip to content

Commit aa086fc

Browse files
authored
Merge pull request #202 from solar224/fix/amf-oauth2-callback-token
fix(notifier): add OAuth2 token to namf-callback outbound calls; fix SCTP EBADF teardown
2 parents dcc3045 + 6241ed2 commit aa086fc

8 files changed

Lines changed: 136 additions & 32 deletions

File tree

internal/ngap/service/service.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ func handleConnection(conn *sctp.SCTPConn, bufsize uint32, handler NGAPHandler)
210210
case syscall.EINTR:
211211
logger.NgapLog.Debugf("SCTPRead: %+v", err)
212212
continue
213+
case syscall.EBADF:
214+
logger.NgapLog.Debugln("SCTP connection already closed")
215+
return
213216
default:
214217
logger.NgapLog.Errorf(
215218
"Handle connection[addr: %+v] error: %+v",

internal/sbi/processor/callback.go

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,24 @@ func (p *Processor) N1MessageNotifyProcedure(n1MessageNotify models.N1MessageNot
292292
return problemDetails
293293
}
294294

295+
if registrationCtxtContainer.RanNodeId == nil {
296+
problemDetails := &models.ProblemDetails{
297+
Status: http.StatusBadRequest,
298+
Cause: "MANDATORY_IE_MISSING",
299+
Detail: "Missing IE [RanNodeId] in RegistrationCtxtContainer",
300+
}
301+
return problemDetails
302+
}
303+
304+
if registrationCtxtContainer.UserLocation == nil {
305+
problemDetails := &models.ProblemDetails{
306+
Status: http.StatusBadRequest,
307+
Cause: "MANDATORY_IE_MISSING",
308+
Detail: "Missing IE [UserLocation] in RegistrationCtxtContainer",
309+
}
310+
return problemDetails
311+
}
312+
295313
ran, ok := amfSelf.AmfRanFindByRanID(*registrationCtxtContainer.RanNodeId)
296314
if !ok {
297315
logger.CallbackLog.Warnln("AmfRanFindByRanID not found: ", *registrationCtxtContainer.RanNodeId)
@@ -337,10 +355,16 @@ func (p *Processor) N1MessageNotifyProcedure(n1MessageNotify models.N1MessageNot
337355

338356
amfUe.CopyDataFromUeContextModel(ueContext)
339357

340-
ranUe.Location = *registrationCtxtContainer.UserLocation
358+
currentRanUe := ran.RanUeFindByRanUeNgapID(int64(registrationCtxtContainer.AnN2ApId))
359+
if currentRanUe == nil {
360+
logger.CallbackLog.Warnf("RanUe not found for AnN2ApId: %d", registrationCtxtContainer.AnN2ApId)
361+
return
362+
}
363+
364+
currentRanUe.Location = *registrationCtxtContainer.UserLocation
341365
amfUe.Location = *registrationCtxtContainer.UserLocation
342-
ranUe.UeContextRequest = registrationCtxtContainer.UeContextRequest
343-
ranUe.OldAmfName = registrationCtxtContainer.InitialAmfName
366+
currentRanUe.UeContextRequest = registrationCtxtContainer.UeContextRequest
367+
currentRanUe.OldAmfName = registrationCtxtContainer.InitialAmfName
344368

345369
if registrationCtxtContainer.AllowedNssai != nil {
346370
allowedNssai := registrationCtxtContainer.AllowedNssai
@@ -351,9 +375,9 @@ func (p *Processor) N1MessageNotifyProcedure(n1MessageNotify models.N1MessageNot
351375
amfUe.ConfiguredNssai = registrationCtxtContainer.ConfiguredNssai
352376
}
353377

354-
gmm_common.AttachRanUeToAmfUeAndReleaseOldIfAny(amfUe, ranUe)
378+
gmm_common.AttachRanUeToAmfUeAndReleaseOldIfAny(amfUe, currentRanUe)
355379

356-
amf_nas.HandleNAS(ranUe, ngapType.ProcedureCodeInitialUEMessage, n1MessageNotify.BinaryDataN1Message, true)
380+
amf_nas.HandleNAS(currentRanUe, ngapType.ProcedureCodeInitialUEMessage, n1MessageNotify.BinaryDataN1Message, true)
357381
}()
358382
return nil
359383
}

internal/sbi/processor/notifier/n1n2message.go

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package callback
22

33
import (
4-
"context"
54
"strconv"
65

76
"github.com/sirupsen/logrus"
@@ -35,8 +34,15 @@ func SendN1N2TransferFailureNotification(ue *amf_context.AmfUe, cause models.N1N
3534
},
3635
}
3736

38-
_, err := client.N1N2MessageCollectionCollectionApi.
39-
N1N2TransferFailureNotification(context.Background(), uri, &n1N2MsgTxfrFailureNotificationReq)
37+
ctx, pd, err := amf_context.GetSelf().GetTokenCtx(
38+
models.ServiceName("namf-callback"), models.NrfNfManagementNfType_SMF)
39+
if err != nil {
40+
HttpLog.Warnf("SendN1N2TransferFailureNotification get token failed: %+v", pd)
41+
return
42+
}
43+
44+
_, err = client.N1N2MessageCollectionCollectionApi.
45+
N1N2TransferFailureNotification(ctx, uri, &n1N2MsgTxfrFailureNotificationReq)
4046

4147
if err != nil {
4248
HttpLog.Errorln(err.Error())
@@ -73,8 +79,16 @@ func SendN1MessageNotify(ue *amf_context.AmfUe, n1class models.N1MessageClass, n
7379
n1MessageNotifyReq := Namf_Communication.N1MessageNotifyRequest{
7480
N1MessageNotifyRequest: &n1MessageNotify,
7581
}
76-
_, err := client.N1N2SubscriptionsCollectionForIndividualUEContextsCollectionApi.
77-
N1MessageNotify(context.Background(), subscription.N1NotifyCallbackUri, &n1MessageNotifyReq)
82+
83+
ctx, pd, err := amf_context.GetSelf().GetTokenCtx(
84+
models.ServiceName("namf-callback"), models.NrfNfManagementNfType_SMF)
85+
if err != nil {
86+
HttpLog.Warnf("SendN1MessageNotify get token failed: %+v", pd)
87+
return false
88+
}
89+
90+
_, err = client.N1N2SubscriptionsCollectionForIndividualUEContextsCollectionApi.
91+
N1MessageNotify(ctx, subscription.N1NotifyCallbackUri, &n1MessageNotifyReq)
7892
if err != nil {
7993
HttpLog.Errorln(err.Error())
8094
}
@@ -117,8 +131,15 @@ func SendN1MessageNotifyAtAMFReAllocation(
117131
}
118132
}
119133

120-
_, err := client.N1N2SubscriptionsCollectionForIndividualUEContextsCollectionApi.
121-
N1MessageNotify(context.Background(), callbackUri, &n1MessageNotifyReq)
134+
ctx, pd, err := amf_context.GetSelf().GetTokenCtx(
135+
models.ServiceName("namf-callback"), models.NrfNfManagementNfType_AMF)
136+
if err != nil {
137+
HttpLog.Warnf("SendN1MessageNotifyAtAMFReAllocation get token failed: %+v", pd)
138+
return err
139+
}
140+
141+
_, err = client.N1N2SubscriptionsCollectionForIndividualUEContextsCollectionApi.
142+
N1MessageNotify(ctx, callbackUri, &n1MessageNotifyReq)
122143
if err != nil {
123144
HttpLog.Errorln(err.Error())
124145
return err
@@ -187,8 +208,15 @@ func SendN2InfoNotify(ue *amf_context.AmfUe, n2class models.N2InformationClass,
187208
N2InfoNotifyRequest: &n2InformationNotify,
188209
}
189210

190-
_, err := client.N1N2SubscriptionsCollectionForIndividualUEContextsCollectionApi.
191-
N2InfoNotify(context.Background(), subscription.N2NotifyCallbackUri, &n2InformationNotifyReq)
211+
ctx, pd, err := amf_context.GetSelf().GetTokenCtx(
212+
models.ServiceName("namf-callback"), models.NrfNfManagementNfType_SMF)
213+
if err != nil {
214+
HttpLog.Warnf("SendN2InfoNotify get token failed: %+v", pd)
215+
return false
216+
}
217+
218+
_, err = client.N1N2SubscriptionsCollectionForIndividualUEContextsCollectionApi.
219+
N2InfoNotify(ctx, subscription.N2NotifyCallbackUri, &n2InformationNotifyReq)
192220
if err != nil {
193221
HttpLog.Errorln(err.Error())
194222
}

internal/sbi/processor/notifier/subscription.go

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,33 @@
11
package callback
22

33
import (
4-
"context"
4+
"net/url"
55
"reflect"
6+
"strings"
67

78
amf_context "github.com/free5gc/amf/internal/context"
89
"github.com/free5gc/amf/internal/logger"
910
Namf_Communication "github.com/free5gc/openapi/amf/Communication"
1011
"github.com/free5gc/openapi/models"
1112
)
1213

14+
func callbackServiceNfType(svcName string) (models.NrfNfManagementNfType, bool) {
15+
switch {
16+
case strings.HasPrefix(svcName, "npcf"):
17+
return models.NrfNfManagementNfType_PCF, true
18+
case strings.HasPrefix(svcName, "nsmf"):
19+
return models.NrfNfManagementNfType_SMF, true
20+
case strings.HasPrefix(svcName, "nudm"):
21+
return models.NrfNfManagementNfType_UDM, true
22+
case strings.HasPrefix(svcName, "nausf"):
23+
return models.NrfNfManagementNfType_AUSF, true
24+
case strings.HasPrefix(svcName, "namf"):
25+
return models.NrfNfManagementNfType_AMF, true
26+
default:
27+
return "", false
28+
}
29+
}
30+
1331
func SendAmfStatusChangeNotify(amfStatus string, guamiList []models.Guami) {
1432
amfSelf := amf_context.GetSelf()
1533

@@ -42,9 +60,26 @@ func SendAmfStatusChangeNotify(amfStatus string, guamiList []models.Guami) {
4260
amfStatusNotificationReq := Namf_Communication.AmfStatusChangeNotifyRequest{
4361
AmfStatusChangeNotification: &amfStatusNotification,
4462
}
63+
64+
var callbackSvcName models.ServiceName
65+
var targetNFType models.NrfNfManagementNfType
66+
if parsedURI, err := url.Parse(uri); err == nil {
67+
seg := strings.SplitN(strings.TrimPrefix(parsedURI.Path, "/"), "/", 2)[0]
68+
if nfType, ok := callbackServiceNfType(seg); ok {
69+
callbackSvcName = models.ServiceName(seg)
70+
targetNFType = nfType
71+
}
72+
}
73+
74+
ctx, pd, err := amfSelf.GetTokenCtx(callbackSvcName, targetNFType)
75+
if err != nil {
76+
HttpLog.Warnf("SendAmfStatusChangeNotify get token failed: %+v", pd)
77+
return false
78+
}
79+
4580
logger.ProducerLog.Infof("[AMF] Send Amf Status Change Notify to %s", uri)
46-
_, err := client.IndividualSubscriptionDocumentApi.
47-
AmfStatusChangeNotify(context.Background(), uri, &amfStatusNotificationReq)
81+
_, err = client.IndividualSubscriptionDocumentApi.
82+
AmfStatusChangeNotify(ctx, uri, &amfStatusNotificationReq)
4883
if err != nil {
4984
HttpLog.Errorln(err.Error())
5085
}

internal/sbi/processor/notifier/ue_context.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package callback
22

33
import (
4-
"context"
54
"fmt"
65

76
amf_context "github.com/free5gc/amf/internal/context"
@@ -26,8 +25,15 @@ func SendN2InfoNotifyN2Handover(ue *amf_context.AmfUe, releaseList []int32) erro
2625
N2InformationNotification: &n2InformationNotification,
2726
}
2827

29-
_, err := client.IndividualUeContextDocumentApi.
30-
N2InfoNotifyHandoverComplete(context.Background(), ue.HandoverNotifyUri, &n2InformationNotificationReq)
28+
ctx, pd, err := amf_context.GetSelf().GetTokenCtx(
29+
models.ServiceName("namf-callback"), models.NrfNfManagementNfType_AMF)
30+
if err != nil {
31+
HttpLog.Warnf("SendN2InfoNotifyN2Handover get token failed: %+v", pd)
32+
return err
33+
}
34+
35+
_, err = client.IndividualUeContextDocumentApi.
36+
N2InfoNotifyHandoverComplete(ctx, ue.HandoverNotifyUri, &n2InformationNotificationReq)
3137

3238
if err == nil {
3339
// TODO: handle Msg

internal/sbi/server.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ func newRouter(s *Server) *gin.Engine {
7171
router.Use(metrics.InboundMetrics())
7272
amfHttpCallBackGroup := router.Group(factory.AmfCallbackResUriPrefix)
7373
amfHttpCallBackRoutes := s.getHttpCallBackRoutes()
74+
callbackAuthCheck := util_oauth.NewRouterAuthorizationCheck(models.ServiceName("namf-callback"))
75+
amfHttpCallBackGroup.Use(func(c *gin.Context) {
76+
callbackAuthCheck.Check(c, amf_context.GetSelf())
77+
})
7478
applyRoutes(amfHttpCallBackGroup, amfHttpCallBackRoutes)
7579

7680
for _, serverName := range factory.AmfConfig.Configuration.ServiceNameList {

pkg/factory/config.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,10 @@ func (c *Configuration) validate() (bool, error) {
158158
if c.ServiceNameList != nil {
159159
var errs govalidator.Errors
160160
for _, v := range c.ServiceNameList {
161-
if v != "namf-comm" && v != "namf-evts" && v != "namf-mt" && v != "namf-loc" && v != "namf-oam" {
162-
err := fmt.Errorf("invalid ServiceNameList: %s,"+
163-
" value should be namf-comm or namf-evts or namf-mt or namf-loc or namf-oam", v)
161+
if v != "namf-comm" && v != "namf-evts" && v != "namf-mt" &&
162+
v != "namf-loc" && v != "namf-oam" && v != "namf-callback" {
163+
err := fmt.Errorf("invalid ServiceNameList: %s, "+
164+
"value should be namf-comm, namf-evts, namf-mt, namf-loc, namf-oam or namf-callback", v)
164165
errs = append(errs, err)
165166
}
166167
}

pkg/service/init.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -291,15 +291,6 @@ func (a *AmfApp) WaitRoutineStopped() {
291291
func (a *AmfApp) terminateProcedure() {
292292
logger.MainLog.Infof("Terminating AMF...")
293293
a.CallServerStop()
294-
// deregister with NRF
295-
problemDetails, err_deg := a.Consumer().SendDeregisterNFInstance()
296-
if problemDetails != nil {
297-
logger.MainLog.Errorf("Deregister NF instance Failed Problem[%+v]", problemDetails)
298-
} else if err_deg != nil {
299-
logger.MainLog.Errorf("Deregister NF instance Error[%+v]", err_deg)
300-
} else {
301-
logger.MainLog.Infof("[AMF] Deregister from NRF successfully")
302-
}
303294

304295
// TODO: forward registered UE contexts to target AMF in the same AMF set if there is one
305296

@@ -319,5 +310,17 @@ func (a *AmfApp) terminateProcedure() {
319310
ngap.ShutdownScheduler()
320311

321312
ngap_service.Stop()
313+
314+
// notify SBI subscribers before deregistering so NRF still recognizes AMF as a valid OAuth client
322315
callback.SendAmfStatusChangeNotify((string)(models.StatusChange_UNAVAILABLE), amfSelf.ServedGuamiList)
316+
317+
// deregister with NRF
318+
problemDetails, err_deg := a.Consumer().SendDeregisterNFInstance()
319+
if problemDetails != nil {
320+
logger.MainLog.Errorf("Deregister NF instance Failed Problem[%+v]", problemDetails)
321+
} else if err_deg != nil {
322+
logger.MainLog.Errorf("Deregister NF instance Error[%+v]", err_deg)
323+
} else {
324+
logger.MainLog.Infof("[AMF] Deregister from NRF successfully")
325+
}
323326
}

0 commit comments

Comments
 (0)