Skip to content

Commit

Permalink
Multi-upf
Browse files Browse the repository at this point in the history
  • Loading branch information
louisroyer committed Dec 10, 2024
1 parent ce1be96 commit 888dea1
Show file tree
Hide file tree
Showing 21 changed files with 1,022 additions and 466 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.22.7
require (
github.com/adrg/xdg v0.5.3
github.com/gin-gonic/gin v1.10.0
github.com/nextmn/go-pfcp-networking v0.0.39
github.com/nextmn/go-pfcp-networking v0.0.40-0.20241210144909-788cba7178ed
github.com/nextmn/json-api v0.0.14
github.com/nextmn/logrus-formatter v0.0.1
github.com/sirupsen/logrus v1.9.3
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/nextmn/go-pfcp-networking v0.0.39 h1:8LDz3O0pjQ3PPLGDnds3z369mB7xBEkTtLqAzMMrtFE=
github.com/nextmn/go-pfcp-networking v0.0.39/go.mod h1:KYoKLiltDmHL2YMU5mz2k/E1xMoz4TpmzTz6Nr5u5gA=
github.com/nextmn/go-pfcp-networking v0.0.40-0.20241209181313-d2a4f5e5d557 h1:8DVrxu7roGv1vs+5Su1lbD23GQApzhP+h6Rk1SWiuDQ=
github.com/nextmn/go-pfcp-networking v0.0.40-0.20241209181313-d2a4f5e5d557/go.mod h1:KYoKLiltDmHL2YMU5mz2k/E1xMoz4TpmzTz6Nr5u5gA=
github.com/nextmn/go-pfcp-networking v0.0.40-0.20241210142758-3ca58ba7258d h1:RRrz3IANGdLTRm55J7AxUR6Ger5SYXFduzAaQA6FuRc=
github.com/nextmn/go-pfcp-networking v0.0.40-0.20241210142758-3ca58ba7258d/go.mod h1:KYoKLiltDmHL2YMU5mz2k/E1xMoz4TpmzTz6Nr5u5gA=
github.com/nextmn/go-pfcp-networking v0.0.40-0.20241210144909-788cba7178ed h1:Rum21YTERWhYzO7WipfKymhbzH0MYh6JG4U839a2b1Y=
github.com/nextmn/go-pfcp-networking v0.0.40-0.20241210144909-788cba7178ed/go.mod h1:KYoKLiltDmHL2YMU5mz2k/E1xMoz4TpmzTz6Nr5u5gA=
github.com/nextmn/json-api v0.0.14 h1:m4uHOVcXsxkXoxbrhqemLTRG4T86eYkejjirew1nDUU=
github.com/nextmn/json-api v0.0.14/go.mod h1:CQXeNPj9MDGsEExtnqJFIGjLgZAKsmOoO2fy+mep7Ak=
github.com/nextmn/logrus-formatter v0.0.1 h1:Bsf78jjiEESc+rV8xE6IyKj4frDPGMwXFNrLQzm6A1E=
Expand Down
88 changes: 88 additions & 0 deletions internal/amf/amf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright 2024 Louis Royer and the NextMN contributors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.
// SPDX-License-Identifier: MIT

package amf

import (
"context"
"net"
"net/http"
"net/netip"
"time"

"github.com/nextmn/cp-lite/internal/smf"

"github.com/nextmn/json-api/healthcheck"
"github.com/nextmn/json-api/jsonapi"

"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)

type Amf struct {
control jsonapi.ControlURI
client http.Client
userAgent string
smf *smf.Smf
srv *http.Server
}

func NewAmf(bindAddr netip.AddrPort, control jsonapi.ControlURI, userAgent string, smf *smf.Smf) *Amf {
amf := Amf{
control: control,
client: http.Client{},
userAgent: userAgent,
smf: smf,
}
// TODO: gin.SetMode(gin.DebugMode) / gin.SetMode(gin.ReleaseMode) depending on log level
r := gin.Default()
r.GET("/status", Status)

// PDU Sessions
r.POST("/ps/establishment-request", amf.EstablishmentRequest)
r.POST("/ps/n2-establishment-response", amf.N2EstablishmentResponse)

logrus.WithFields(logrus.Fields{"http-addr": bindAddr}).Info("HTTP Server created")
amf.srv = &http.Server{
Addr: bindAddr.String(),
Handler: r,
}

return &amf
}

func (amf *Amf) Start(ctx context.Context) error {
l, err := net.Listen("tcp", amf.srv.Addr)
if err != nil {
return err
}
go func(ln net.Listener) {
logrus.Info("Starting HTTP Server")
if err := amf.srv.Serve(ln); err != nil && err != http.ErrServerClosed {
logrus.WithError(err).Error("Http Server error")
}
}(l)
go func(ctx context.Context) {
select {
case <-ctx.Done():
ctxShutdown, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
if err := amf.srv.Shutdown(ctxShutdown); err != nil {
logrus.WithError(err).Info("HTTP Server Shutdown")
}
}
}(ctx)

return nil
}

// get status of the controller
func Status(c *gin.Context) {
status := healthcheck.Status{
Ready: true,
}
c.Header("Cache-Control", "no-cache")
c.JSON(http.StatusOK, status)
}
67 changes: 67 additions & 0 deletions internal/amf/establishment_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright 2024 Louis Royer and the NextMN contributors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.
// SPDX-License-Identifier: MIT

package amf

import (
"bytes"
"encoding/json"
"net/http"

"github.com/nextmn/json-api/jsonapi"
"github.com/nextmn/json-api/jsonapi/n1n2"

"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)

func (amf *Amf) EstablishmentRequest(c *gin.Context) {
var ps n1n2.PduSessionEstabReqMsg
if err := c.BindJSON(&ps); err != nil {
logrus.WithError(err).Error("could not deserialize")
c.JSON(http.StatusBadRequest, jsonapi.MessageWithError{Message: "could not deserialize", Error: err})
return
}
logrus.WithFields(logrus.Fields{
"ue": ps.Ue.String(),
"gnb": ps.Gnb.String(),
"dnn": ps.Dnn,
}).Info("New PDU Session establishment Request")

pduSession, err := amf.smf.CreateSessionUplink(c, ps.Ue, ps.Gnb, ps.Dnn)
if err != nil {
c.JSON(http.StatusInternalServerError, jsonapi.MessageWithError{Message: "could not create pdu session uplink", Error: err})
return
}

// send PseAccept to UE
n2PsReq := n1n2.N2PduSessionReqMsg{
Cp: amf.control,
UeInfo: n1n2.PduSessionEstabAcceptMsg{
Header: ps,
Addr: pduSession.UeIpAddr,
},
Upf: pduSession.UplinkFteid.Addr,
UplinkTeid: pduSession.UplinkFteid.Teid,
}
reqBody, err := json.Marshal(n2PsReq)
if err != nil {
c.JSON(http.StatusInternalServerError, jsonapi.MessageWithError{Message: "could not marshal json", Error: err})
return
}
req, err := http.NewRequestWithContext(c, http.MethodPost, ps.Gnb.JoinPath("ps/n2-establishment-request").String(), bytes.NewBuffer(reqBody))
if err != nil {
c.JSON(http.StatusInternalServerError, jsonapi.MessageWithError{Message: "could not create request", Error: err})
return
}
req.Header.Set("User-Agent", amf.userAgent)
req.Header.Set("Content-Type", "application/json; charset=UTF-8")
resp, err := amf.client.Do(req)
if err != nil {
c.JSON(http.StatusInternalServerError, jsonapi.MessageWithError{Message: "no http response", Error: err})
return
}
defer resp.Body.Close()
}
46 changes: 46 additions & 0 deletions internal/amf/n2_establishment_response.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2024 Louis Royer and the NextMN contributors. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.
// SPDX-License-Identifier: MIT

package amf

import (
"net/http"

"github.com/nextmn/json-api/jsonapi"
"github.com/nextmn/json-api/jsonapi/n1n2"

"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)

func (amf *Amf) N2EstablishmentResponse(c *gin.Context) {
var ps n1n2.N2PduSessionRespMsg
if err := c.BindJSON(&ps); err != nil {
logrus.WithError(err).Error("could not deserialize")
c.JSON(http.StatusBadRequest, jsonapi.MessageWithError{Message: "could not deserialize", Error: err})
return
}
pduSession, err := amf.smf.CreateSessionDownlink(c, ps.UeInfo.Header.Ue, ps.UeInfo.Header.Dnn, ps.Gnb, ps.DownlinkTeid)
if err != nil {
logrus.WithError(err).WithFields(logrus.Fields{
"ue-ip-addr": ps.UeInfo.Addr,
"ue": ps.UeInfo.Header.Ue,
"gnb": ps.UeInfo.Header.Gnb,
"dnn": ps.UeInfo.Header.Dnn,
}).Error("could not create downlink path")
c.JSON(http.StatusInternalServerError, jsonapi.MessageWithError{Message: "could not create downlink path", Error: err})
return
}
logrus.WithFields(logrus.Fields{
"ue": ps.UeInfo.Header.Ue.String(),
"gnb": ps.UeInfo.Header.Gnb.String(),
"ip-addr": ps.UeInfo.Addr,
"gtp-upf": pduSession.UplinkFteid.Addr,
"gtp-uplink-teid": pduSession.UplinkFteid.Teid,
"gtp-gnb": pduSession.DownlinkFteid.Addr,
"gtp-downlink-teid": pduSession.DownlinkFteid.Teid,
"dnn": ps.UeInfo.Header.Dnn,
}).Info("New PDU Session Established")
}
75 changes: 0 additions & 75 deletions internal/app/control.go

This file was deleted.

Loading

0 comments on commit 888dea1

Please sign in to comment.