Skip to content

Commit

Permalink
[feg] S8 disabled validation on go-gtp
Browse files Browse the repository at this point in the history
Signed-off-by: Oriol Batalla <obatalla@fb.com>
  • Loading branch information
uri200 committed Feb 26, 2021
1 parent 1a08d0f commit 6c689ec
Show file tree
Hide file tree
Showing 15 changed files with 754 additions and 417 deletions.
169 changes: 80 additions & 89 deletions feg/cloud/go/protos/s8_proxy.pb.go

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions feg/gateway/gtp/enriched_message/message.go
Expand Up @@ -25,16 +25,19 @@ import (
type MessageWithGrpc struct {
message.Message // GTP
grpcMessage proto.Message // GRPC
err error
}

func NewMessageWithGrpc(gtpMessage message.Message, grpcMessage proto.Message) *MessageWithGrpc {
// NewMessageWithGrpc returns a full valid MessageWithGrpc which include all parameters
func NewMessageWithGrpc(gtpMessage message.Message, grpcMessage proto.Message, err error) *MessageWithGrpc {
return &MessageWithGrpc{
Message: gtpMessage,
grpcMessage: grpcMessage,
err: err,
}
}

func (m *MessageWithGrpc) GetGrpcMessage() proto.Message {
func (m MessageWithGrpc) GetGrpcMessage() proto.Message {
return m.grpcMessage
}

Expand All @@ -47,6 +50,10 @@ func ExtractGrpcMessageFromGtpMessage(incomingMsg message.Message) (proto.Messag
default:
return nil, fmt.Errorf("incomming message it is not MessageWithGrpc type %+v", incomingMsg)
}
// if the mess
if withGrpc.err != nil {
return nil, withGrpc.err
}
grpcMessage := withGrpc.GetGrpcMessage()
return grpcMessage, nil
}
14 changes: 12 additions & 2 deletions feg/gateway/gtp/gtp_client.go
Expand Up @@ -72,6 +72,8 @@ func NewRunningClient(ctx context.Context, localIpAndPort string, connType uint8
if err != nil {
return nil, err
}
c.WaitUntilClientIsReady(0)
c.DisableValidation()
return c, nil
}

Expand Down Expand Up @@ -102,15 +104,17 @@ func NewConnectedClient(ctx context.Context, localAddr, remoteAddr *net.UDPAddr,
if err != nil {
return nil, fmt.Errorf("could not connect to GTP-C %s server: %s", remoteAddr.String(), err)
}
c.DisableValidation()
return c, nil
}

// NewClient creates basic configuration structure for a GTP-C client. It does
// not starts any connection or server.
func newClient(localAddr *net.UDPAddr, connType uint8) *Client {
return &Client{
cli := &Client{
connType: connType,
}
return cli
}

// Enable just creates the object connection enabling messages to be sent
Expand All @@ -133,7 +137,6 @@ func (c *Client) run(ctx context.Context) error {
}
}()
//TODO: remove this wait once there is a way to check when the listener is ready
c.WaitUntilClientIsReady(0)
return nil
}

Expand Down Expand Up @@ -168,7 +171,14 @@ func GetOutboundIP(testIp *net.UDPAddr) (net.IP, error) {
// the GTP-C client too early. Since go-gtp doesn't offer any visibuility on the readines of the connection
// we use LocalAddrs as indicator
func (c *Client) WaitUntilClientIsReady(count int) {

// TODO: only use those 3 waits for debugging
time.Sleep(time.Millisecond * 20)
time.Sleep(time.Millisecond * 20)
time.Sleep(time.Millisecond * 20)

defer func() {

if count > 50 {
time.Sleep(time.Millisecond * 20)
}
Expand Down
5 changes: 2 additions & 3 deletions feg/gateway/services/s8_proxy/client_api_test.go
Expand Up @@ -73,9 +73,8 @@ func TestS8ProxyClient(t *testing.T) {
Ipv6Prefix: 0,
},

Apn: "internet.com",
SelectionMode: "",
ApnRestriction: 0,
Apn: "internet.com",
SelectionMode: "",
Ambr: &protos.Ambr{
BrUl: 999,
BrDl: 888,
Expand Down
213 changes: 21 additions & 192 deletions feg/gateway/services/s8_proxy/servicers/gtp_handlers.go
Expand Up @@ -17,15 +17,12 @@ package servicers

import (
"fmt"
"github.com/golang/glog"
"net"
"time"

"magma/feg/cloud/go/protos"
"magma/feg/gateway/gtp/enriched_message"

proto "github.com/golang/protobuf/proto"
"github.com/wmnsk/go-gtp/gtpv2"
"github.com/wmnsk/go-gtp/gtpv2/ie"
"github.com/wmnsk/go-gtp/gtpv2/message"
)

Expand All @@ -42,177 +39,31 @@ func addS8GtpHandlers(s8p *S8Proxy) {

func getHandle_CreateSessionResponse() gtpv2.HandlerFunc {
return func(c *gtpv2.Conn, senderAddr net.Addr, msg message.Message) error {
csResGtp := msg.(*message.CreateSessionResponse)
csRes := &protos.CreateSessionResponsePgw{}
glog.V(2).Infof("Received Create Session Response (gtp):\n%s", csResGtp.String())

session, err := c.GetSessionByTEID(msg.TEID(), senderAddr)
if err != nil {
return fmt.Errorf("couldn't find session with TEID %d: %s", msg.TEID(), err)
}

// check Cause value first.
if causeIE := csResGtp.Cause; causeIE != nil {
cause, err := causeIE.Cause()
if err != nil {
return fmt.Errorf("Couldn't check cause of csRes: %s", err)
}
if cause != gtpv2.CauseRequestAccepted {
c.RemoveSession(session)
return &gtpv2.CauseNotOKError{
MsgType: csResGtp.MessageTypeName(),
Cause: cause,
Msg: fmt.Sprintf("subscriber: %s", session.IMSI),
}
}
} else {
c.RemoveSession(session)
return &gtpv2.RequiredIEMissingError{
Type: ie.Cause,
}
}

// get values sent by pgw
if paaIE := csResGtp.PAA; paaIE != nil {
ip, err := paaIE.IPAddress()
if err != nil {
return err
}
csRes.SubscriberIp = ip
} else {
c.RemoveSession(session)
return &gtpv2.RequiredIEMissingError{Type: ie.PDNAddressAllocation}
}

// Pgw control plane fteid
if pgwCFteidIE := csResGtp.PGWS5S8FTEIDC; pgwCFteidIE != nil {
pgwCFteid, interfaceType, err := handleFTEID(pgwCFteidIE)
if err != nil {
return fmt.Errorf("Couldn't get PGW control plane FTEID: %s ", err)
}
session.AddTEID(interfaceType, pgwCFteid.GetTeid())
csRes.CPgwFteid = pgwCFteid
} else {
c.RemoveSession(session)
return &gtpv2.RequiredIEMissingError{Type: ie.FullyQualifiedTEID}
}

// AGW (sgw) control plane fteid
csRes.CAgwTeid, err = session.GetTEID(gtpv2.IFTypeS5S8SGWGTPC)
if err != nil {
return fmt.Errorf("Couldn't get local (sgw) control plane TEID: %s ", err)
}

// TODO: handle more than one bearer
if brCtxIE := csResGtp.BearerContextsCreated; brCtxIE != nil {
bearerCtx := &protos.BearerContext{}
for _, childIE := range brCtxIE.ChildIEs {
switch childIE.Type {
case ie.Cause:
cause, err := childIE.Cause()
if err != nil {
return err
}
if cause != gtpv2.CauseRequestAccepted {
c.RemoveSession(session)
return &gtpv2.CauseNotOKError{
MsgType: csResGtp.MessageTypeName(),
Cause: cause,
Msg: fmt.Sprintf("subscriber: %s", session.IMSI),
}
}
case ie.EPSBearerID:
ebi, err := childIE.EPSBearerID()
if err != nil {
return err
}
if ebi != session.GetDefaultBearer().EBI {
return fmt.Errorf("Create Session Response bearer id different than "+
"default bearer id (%d != %d)", ebi, session.GetDefaultBearer().EBI)
}
bearerCtx.Id = uint32(ebi)
case ie.FullyQualifiedTEID:
uFteid, typeIf, err := handleFTEID(childIE)
if err != nil {
return err
}
bearerCtx.UserPlaneFteid = uFteid
// save uFteid in session and default bearer
session.AddTEID(typeIf, uFteid.GetTeid())
session.GetDefaultBearer().SetOutgoingTEID(uFteid.GetTeid())
case ie.ChargingID:
bearerCtx.ChargingId, err = childIE.ChargingID()
if err != nil {
return err
}
session.GetDefaultBearer().ChargingID = bearerCtx.ChargingId
}
}
csRes.BearerContext = bearerCtx
} else {
c.RemoveSession(session)
return &gtpv2.RequiredIEMissingError{Type: ie.BearerContext}
}

if err := session.Activate(); err != nil {
c.RemoveSession(session)
return fmt.Errorf("couldn't activate the session with IMSI %s: %s", session.IMSI, err)
}
// TODO: validate message before passing
enrichedMsg := enriched_message.NewMessageWithGrpc(msg, csRes)

// pass message to same session
if err := gtpv2.PassMessageTo(session, enrichedMsg, 5*time.Second); err != nil {
err = fmt.Errorf("couldn't find session with TEID %d: %s", msg.TEID(), err)
return err
}
return nil
}
}

// TODO
func getHandle_ModifyBearerRequest() gtpv2.HandlerFunc {
return func(c *gtpv2.Conn, senderAddr net.Addr, msg message.Message) error {
return nil
csRes, err := parseCreateSessionResponse(session, msg)
return passMessage(session, msg, csRes, err)
}
}

func getHandle_DeleteSessionResponse() gtpv2.HandlerFunc {
return func(c *gtpv2.Conn, senderAddr net.Addr, msg message.Message) error {
cdResGtp := msg.(*message.DeleteSessionResponse)
cdRes := &protos.DeleteSessionResponsePgw{}
glog.V(2).Infof("Received Delete Session Response (gtp):\n%s", cdResGtp.String())

session, err := c.GetSessionByTEID(msg.TEID(), senderAddr)
if err != nil {
return fmt.Errorf("couldn't find session with TEID %d: %s", msg.TEID(), err)
}

// check Cause value first.
if causeIE := cdResGtp.Cause; causeIE != nil {
cause, err := causeIE.Cause()
if err != nil {
return fmt.Errorf("Couldn't check cause of delete session response: %s", err)
}
if cause != gtpv2.CauseRequestAccepted {
return &gtpv2.CauseNotOKError{
MsgType: cdResGtp.MessageTypeName(),
Cause: cause,
Msg: fmt.Sprintf("Delete Session Response not accepted"),
}
}
} else {
return &gtpv2.RequiredIEMissingError{
Type: ie.Cause,
}
}

// TODO: validate message before passing
enrichedMsg := enriched_message.NewMessageWithGrpc(msg, cdRes)

// pass message to same session
if err := gtpv2.PassMessageTo(session, enrichedMsg, 5*time.Second); err != nil {
err = fmt.Errorf("couldn't find session with TEID %d: %s", msg.TEID(), err)
return err
}
csRes, err := parseDelteSessionResponse(session, msg)
return passMessage(session, msg, csRes, err)
}
}

// TODO
func getHandle_ModifyBearerRequest() gtpv2.HandlerFunc {
return func(c *gtpv2.Conn, senderAddr net.Addr, msg message.Message) error {
return nil
}
}
Expand All @@ -225,7 +76,7 @@ func getHandle_DeleteBearerRequest() gtpv2.HandlerFunc {
}

// getHandle_EchoResponse handles echo request received in S8_proxy. This is a special handler
// hat does not use gtpv2.PassMessageTo. It instead uses S8proxy echoChannel to pass the error if any
// that does not use gtpv2.PassMessageTo. It instead uses S8proxy echoChannel to pass the error if any
func getHandle_EchoResponse(echoCh chan error) gtpv2.HandlerFunc {
return func(c *gtpv2.Conn, senderAddr net.Addr, msg message.Message) error {
if _, ok := msg.(*message.EchoResponse); !ok {
Expand All @@ -238,34 +89,12 @@ func getHandle_EchoResponse(echoCh chan error) gtpv2.HandlerFunc {
}
}

func handleFTEID(fteidIE *ie.IE) (*protos.Fteid, uint8, error) {
interfaceType, err := fteidIE.InterfaceType()
if err != nil {
return nil, interfaceType, err
}
teid, err := fteidIE.TEID()
if err != nil {
return nil, interfaceType, err
}

fteid := &protos.Fteid{Teid: teid}

if !fteidIE.HasIPv4() && !fteidIE.HasIPv6() {
return nil, interfaceType, fmt.Errorf("Error: fteid %+v has no ips", fteidIE.String())
}
if fteidIE.HasIPv4() {
ipv4, err := fteidIE.IPv4()
if err != nil {
return nil, interfaceType, err
}
fteid.Ipv4Address = ipv4.String()
}
if fteidIE.HasIPv6() {
ipv6, err := fteidIE.IPv6()
if err != nil {
return nil, interfaceType, err
}
fteid.Ipv6Address = ipv6.String()
// passMessage will send a valid message to the caller.
func passMessage(session *gtpv2.Session, gtpMessage message.Message, grpcMessage proto.Message, err error) error {
enrichedMsg := enriched_message.NewMessageWithGrpc(gtpMessage, grpcMessage, err)
// pass message to same session
if err := gtpv2.PassMessageTo(session, enrichedMsg, GtpTimeout); err != nil {
return err
}
return fteid, interfaceType, nil
return nil
}
15 changes: 7 additions & 8 deletions feg/gateway/services/s8_proxy/servicers/ie_conversions.go
Expand Up @@ -47,12 +47,12 @@ func buildCreateSessionRequestIE(cPgwUDPAddr *net.UDPAddr, req *protos.CreateSes
}

// FEG control plane TEID
cFegFTeid := gtpCli.NewSenderFTEID(ip.String(), "")
cFegFTeid := gtpCli.NewSenderFTEID(ip.String(), "").WithInstance(0)

// AGW user plane TEID (comming from request)
uAgwFTeidReq := req.BearerContext.GetUserPlaneFteid()
uAgwFTeid := ie.NewFullyQualifiedTEID(gtpv2.IFTypeS5S8SGWGTPU,
uAgwFTeidReq.Teid, uAgwFTeidReq.Ipv4Address, uAgwFTeidReq.Ipv6Address)
uAgwFTeidReq.Teid, uAgwFTeidReq.Ipv4Address, uAgwFTeidReq.Ipv6Address).WithInstance(2)

// Qos
qos := req.BearerContext.GetQos()
Expand All @@ -67,7 +67,6 @@ func buildCreateSessionRequestIE(cPgwUDPAddr *net.UDPAddr, req *protos.CreateSes
offset := time.Duration(req.TimeZone.DeltaSeconds) * time.Second
daylightSavingTime := uint8(req.TimeZone.DaylightSavingTime)

// TODO: set charging characteristics
ies := []*ie.IE{
ie.NewIMSI(req.GetImsi()),
bearer,
Expand All @@ -80,14 +79,14 @@ func buildCreateSessionRequestIE(cPgwUDPAddr *net.UDPAddr, req *protos.CreateSes
ie.NewMobileEquipmentIdentity(req.Mei),
ie.NewServingNetwork(req.ServingNetwork.Mcc, req.ServingNetwork.Mnc),
ie.NewAccessPointName(req.Apn),
// TODO: selection mode (hadcoded for now)
ie.NewAggregateMaximumBitRate(uint32(req.Ambr.BrUl), uint32(req.Ambr.BrDl)),
ie.NewUETimeZone(offset, daylightSavingTime),

// TODO: Hardcoded values
ie.NewSelectionMode(gtpv2.SelectionModeMSorNetworkProvidedAPNSubscribedVerified),
// TODO: hardcoded indication flags
ie.NewIndicationFromOctets(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
// TODO: Hardcoded apn restriction
ie.NewAPNRestriction(gtpv2.APNRestrictionNoExistingContextsorRestriction),
ie.NewAggregateMaximumBitRate(uint32(req.Ambr.BrUl), uint32(req.Ambr.BrDl)),
ie.NewUETimeZone(offset, daylightSavingTime),
// TODO: set charging characteristics
}
sessionTeids.cFegFTeid = cFegFTeid
sessionTeids.uAgwFTeid = uAgwFTeid
Expand Down

0 comments on commit 6c689ec

Please sign in to comment.