Giter VIP home page Giter VIP logo

go-gtp's People

Contributors

alexanderkudzevich avatar cristconst avatar dependabot-preview[bot] avatar dependabot[bot] avatar dzvancuks avatar ebengt avatar emnify-mkroli avatar faaxm avatar fossabot avatar gordeyg avatar kazukiigeta avatar krsna1729 avatar louisroyer avatar mogaika avatar ptsgr avatar radoslav-georgiev-flolive avatar uri200 avatar wmnsk avatar yt8956gh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-gtp's Issues

OffendingIE in Cause() type

Hi,

Sorry but we are very active lately on gtp side, that's why you see an increase of questions from Magma 🙂

When there is a missing IE, the server normally responds with an error cause CauseMandatoryIEIncorrect or CauseMandatoryIEMissing. Right now per what I understand, the Cause type does not implement any function to parse out from the message the OffendingIE type.

Is that correct? Or maybe I missed something?

image

PCOContainer.UnmarshalBinary not copying container data

This causes MarshalLen to return an incorrect value because MarshalLen based on Contents field and causes message parsing to fail.
Line with problem:

copy(c.Contents, b[3:3+int(c.Length)])

copy builtin: " Copy returns the number of elements copied, which will be the minimum of len(src) and len(dst).". As I understand in our case dst == nil what means len(dst) == 0, so no bytes copied.

Simplified examples

Examples currently available(mme, sgw and pgw) are to show the full feature of the package.
Providing more simple example(like v2/client, v2/server) may be helpful for those who visit the repo for the first time.

Make Relay less costly

In the current implementation v1.Relay use ReadFromGTP() and WriteToGTP() but it's a waste to decapsulate T-PDU and encapsulate it with another TEID again. Just replace the TEID field by specifying the index would be faster.

Need to change the behavior of default handlers from (*Relay) Run() to achieve this.

PAA length is off by one

i := New(PDNAddressAllocation, 0x00, make([]byte, 23))

IPv4v6 PAA is 22 bytes long, not 23.

Also, PAA is variable length, but not extendable. Therefore the length has to match, otherwise it's invalid.

Use of Map for session add/lookup

I was trying to benchmark the current implementation of adding session and a map. The performance of the current approach of iterating over the sessions seems low. Would it be better to maintain map[teid]*Session and map[imsi]*Session`? Let me know if what/how I am benchmarking is wrong.

func benchmarkAddSession(numExisitingSessions int, b *testing.B) {
    benchConn := &v2.Conn{Sessions: []*v2.Session{}}
    for i := 0; i < numExisitingSessions; i++ {
        imsi := fmt.Sprintf("%015d", i)
        benchConn.AddSession(v2.NewSession(dummyAddr, &v2.Subscriber{IMSI: imsi}))
    }
    b.ResetTimer()
    for i := 1; i <= b.N; i++ {
        benchConn.AddSession(v2.NewSession(dummyAddr, &v2.Subscriber{IMSI: "001011234567891"}))
    }
}
func BenchmarkAddSessionExist0(b *testing.B)   { benchmarkAddSession(0, b) }
func BenchmarkAddSessionExist100(b *testing.B) { benchmarkAddSession(1e2, b) }
func BenchmarkAddSessionExist1K(b *testing.B)  { benchmarkAddSession(1e3, b) }
func BenchmarkAddSessionExist10K(b *testing.B) { benchmarkAddSession(1e4, b) }
func benchmarkAddIMSISessionMap(numExisitingSessions int, b *testing.B) {
    IMSISession := make(map[string]*v2.Session)
    for i := 0; i < numExisitingSessions; i++ {
        imsi := fmt.Sprintf("%015d", i)
        IMSISession[imsi] = v2.NewSession(dummyAddr, &v2.Subscriber{IMSI: imsi})
    }
    b.ResetTimer()
    for i := 1; i <= b.N; i++ {
        IMSISession["001011234567891"] = v2.NewSession(dummyAddr, &v2.Subscriber{IMSI: "001011234567891"})
    }
}
func BenchmarkAddIMSISessionMapExist0(b *testing.B)    { benchmarkAddIMSISessionMap(0, b) }
func BenchmarkAddIMSISessionMapExist100(b *testing.B)  { benchmarkAddIMSISessionMap(1e2, b) }
func BenchmarkAddIMSISessionMapExist1K(b *testing.B)   { benchmarkAddIMSISessionMap(1e3, b) }
func BenchmarkAddIMSISessionMapExist10K(b *testing.B)  { benchmarkAddIMSISessionMap(1e4, b) }
func BenchmarkAddIMSISessionMapExist100K(b *testing.B) { benchmarkAddIMSISessionMap(1e5, b) }
func BenchmarkAddIMSISessionMapExist1M(b *testing.B)   { benchmarkAddIMSISessionMap(1e6, b) }
func benchmarkAddIMSISessionSyncMap(numExisitingSessions int, b *testing.B) {
    var IMSISession sync.Map
    for i := 0; i < numExisitingSessions; i++ {
        imsi := fmt.Sprintf("%015d", i)
        IMSISession.Store(imsi, v2.NewSession(dummyAddr, &v2.Subscriber{IMSI: imsi}))
    }
    b.ResetTimer()
    for i := 1; i <= b.N; i++ {
        IMSISession.Store("001011234567891", v2.NewSession(dummyAddr, &v2.Subscriber{IMSI: "001011234567891"}))
    }
}
func BenchmarkAddIMSISessionSyncMapExist0(b *testing.B)    { benchmarkAddIMSISessionSyncMap(0, b) }
func BenchmarkAddIMSISessionSyncMapExist100(b *testing.B)  { benchmarkAddIMSISessionSyncMap(1e2, b) }
func BenchmarkAddIMSISessionSyncMapExist1K(b *testing.B)   { benchmarkAddIMSISessionSyncMap(1e3, b) }
func BenchmarkAddIMSISessionSyncMapExist10K(b *testing.B)  { benchmarkAddIMSISessionSyncMap(1e4, b) }
func BenchmarkAddIMSISessionSyncMapExist100K(b *testing.B) { benchmarkAddIMSISessionSyncMap(1e5, b) }
func BenchmarkAddIMSISessionSyncMapExist1M(b *testing.B)   { benchmarkAddIMSISessionSyncMap(1e6, b) }
BenchmarkAddSessionExist0-88                       99534         11564 ns/op       17216 B/op         19 allocs/op
BenchmarkAddSessionExist100-88                     62908         18471 ns/op       19248 B/op         26 allocs/op
BenchmarkAddSessionExist1K-88                      28222         42054 ns/op       33584 B/op         29 allocs/op
BenchmarkAddSessionExist10K-88                      3542        401157 ns/op      403505 B/op         38 allocs/op
<too long to test>

BenchmarkAddIMSISessionMapExist0-88                84746         14651 ns/op       17208 B/op         18 allocs/op
BenchmarkAddIMSISessionMapExist100-88              81644         15163 ns/op       17208 B/op         18 allocs/op
BenchmarkAddIMSISessionMapExist1K-88               95305         12134 ns/op       17208 B/op         18 allocs/op
BenchmarkAddIMSISessionMapExist10K-88             114638          8823 ns/op       17208 B/op         18 allocs/op
BenchmarkAddIMSISessionMapExist100K-88            380025          7923 ns/op       17208 B/op         18 allocs/op
BenchmarkAddIMSISessionMapExist1M-88              388423          7936 ns/op       17208 B/op         18 allocs/op

BenchmarkAddIMSISessionSyncMapExist0-88            80818         15798 ns/op       17224 B/op         19 allocs/op
BenchmarkAddIMSISessionSyncMapExist100-88          73264         15957 ns/op       17224 B/op         19 allocs/op
BenchmarkAddIMSISessionSyncMapExist1K-88           93626         12520 ns/op       17224 B/op         19 allocs/op
BenchmarkAddIMSISessionSyncMapExist10K-88         109438          9830 ns/op       17224 B/op         19 allocs/op
BenchmarkAddIMSISessionSyncMapExist100K-88        190755          9579 ns/op       17224 B/op         19 allocs/op
BenchmarkAddIMSISessionSyncMapExist1M-88          121707          8270 ns/op       17224 B/op         19 allocs/op

Rename package names

The names of the package is somewhat confusing. At some point before tagging v1.0.0, I’ll change the names as follows.

v0, v1, v2 => gtpv0, gtpv1, gtpv2
messages => message
ies => ie

Create a local tunnel interface

I have created for a test function relayToOS and checked it on OSX.
Basically idea is to have a local tunnel interface and push traffic thru it via gtp-u to a gateway.
It was created on a code that I checked out more than a month ago so it is inefficient taking into account that recently there were made some improvements yet it proves the idea.
Upon session creation:

  • create a local tunnel interface
  • assign IP address to it from a session
  • add a route to some destination via the tunnel

Compatibility with Windows

Since #34 is merged, this project cannot be built on Windows, but it should be supported by isolating platform-specific codes.

As I think there are few people trying to run GTP nodes on Windows, I'm taking this issue as low priority at this moment.

[Bug] TEID is not added to teidmap on Handle Create Session Request

As part of #67 restructuring we addedfunc (c *Conn) AddTEID(teid uint32, session *Session), but this was used only in CreateSession, which in turn is only used to send CreateSessionRequest.

go-gtp/v2/conn.go

Lines 505 to 515 in a342610

case ies.FullyQualifiedTEID:
it, err := i.InterfaceType()
if err != nil {
return nil, 0, err
}
teid, err := i.TEID()
if err != nil {
return nil, 0, err
}
sess.AddTEID(it, teid)
c.AddTEID(teid, sess)

CreateSessionResponse message handling in the examples is missing the step of invoking AddTEID on conn.

This can be rectified in 2 ways -

  1. Add explict call to func (c *Conn) AddTEID(teid uint32, session *Session) in the examples

    • Adds to boilerplate
    • Asymmetric use of APIs where app does not need to invoke when sending CSReq but needs to for CSRes
  2. Add session arg to func (c *Conn) NewFTEID(ifType uint8, v4, v6 string) so that TEID is generated and stored at the same time.

    • Symmetric for Req/Res handling in the app
    • No additional boilerplate

Human readable format GTP messages.

Hey @wmnsk

I know this is not an easy feature, but by any chance, is there any way I may be missing to print GTP messages on a readable hunan format?

Right now I am using the String method to print the GTP message, but only shows few parameters. The rest are unstructured in binary format.

Note wireshark does work, but I was looking to see them on our logs for ease. Go-Diameter has this feature and has proven to be very useful.

Below you have an example of how we are using them right now

glog.V(2).Infof("Received Create Session Response (gtp):\n%s", csResGtp.String())

which generates something like

s8_proxy         | I0403 21:21:50.306126       1 proto_conversions.go:136] Received Delete Session Response (gtp):
s8_proxy         | {Flags: 0x48, Type: 37, Length: 53, TEID: 0x1, SequenceNumber: 0x4, Spare: 0, Payload: []byte{0x2, 0x0, 0x2, 0x0
, 0x10, 0x0, 0x4e, 0x0, 0x23, 0x0, 0x80, 0x80, 0x21, 0x10, 0x1, 0x1, 0x0, 0x10, 0x81, 0x6, 0x0, 0x0, 0x0, 0x0, 0x83, 0x6, 0x0, 0x0,
 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0xd, 0x0, 0x0, 0x5, 0x0, 0x0, 0x11, 0x0, 0x0, 0x10, 0x0}}

https://github.com/magma/magma/blob/065c757560babf622eb77868a552a5ee62379b11/feg/gateway/services/s8_proxy/servicers/proto_conversions.go#L30

And just in case you were curious, this is Go-Diameter human readable format

session_proxy    | Credit-Control-Request (CCR)
session_proxy    | {Code:272,Flags:0xc0,Version:0x1,Length:632,ApplicationId:16777238,HopByHopId:0xf7426526,EndToEndId:0xadf4d7bf}
session_proxy    |      Session-Id {Code:263,Flags:0x40,Length:44,VendorId:0,Value:UTF8String{string;109;655;IMSI999991234567810},Padding:2}
session_proxy    |      Auth-Application-Id {Code:258,Flags:0x40,Length:12,VendorId:0,Value:Unsigned32{16777238}}
session_proxy    |      CC-Request-Type {Code:416,Flags:0x40,Length:12,VendorId:0,Value:Enumerated{1}}
session_proxy    |      CC-Request-Number {Code:415,Flags:0x40,Length:12,VendorId:0,Value:Unsigned32{0}}
session_proxy    |      Subscription-Id {Code:443,Flags:0x40,Length:44,VendorId:0,Value:Grouped{
session_proxy    |              Subscription-Id-Type {Code:450,Flags:0x40,Length:12,VendorId:0,Value:Enumerated{1}},
session_proxy    |              Subscription-Id-Data {Code:444,Flags:0x40,Length:24,VendorId:0,Value:UTF8String{999991234567810},Padding:1},
session_proxy    |      }}
session_proxy    |      Subscription-Id {Code:443,Flags:0x40,Length:40,VendorId:0,Value:Grouped{
session_proxy    |              Subscription-Id-Type {Code:450,Flags:0x40,Length:12,VendorId:0,Value:Enumerated{0}},
session_proxy    |              Subscription-Id-Data {Code:444,Flags:0x40,Length:20,VendorId:0,Value:UTF8String{1234567810},Padding:2},
session_proxy    |      }}
session_proxy    |      IP-CAN-Type {Code:1027,Flags:0xc0,Length:16,VendorId:10415,Value:Enumerated{5}}
session_proxy    |      RAT-Type {Code:1032,Flags:0x80,Length:16,VendorId:10415,Value:Enumerated{1004}}
session_proxy    |      Framed-IP-Address {Code:8,Flags:0x40,Length:12,VendorId:0,Value:IPv4{172.17.185.237}}
session_proxy    |      Called-Station-Id {Code:30,Flags:0x40,Length:16,VendorId:0,Value:UTF8String{internet},Padding:0}
session_proxy    |      Supported-Features {Code:628,Flags:0x80,Length:56,VendorId:10415,Value:Grouped{
session_proxy    |              Vendor-Id {Code:266,Flags:0x40,Length:12,VendorId:0,Value:Unsigned32{10415}},
session_proxy    |              Feature-List-ID {Code:629,Flags:0x80,Length:16,VendorId:10415,Value:Unsigned32{1}},
session_proxy    |              Feature-List {Code:630,Flags:0x80,Length:16,VendorId:10415,Value:Unsigned32{3}},
session_proxy    |      }}
session_proxy    |      Network-Request-Support {Code:1024,Flags:0xc0,Length:16,VendorId:10415,Value:Enumerated{0}}
session_proxy    |      Offline {Code:1008,Flags:0xc0,Length:16,VendorId:10415,Value:Enumerated{0}}
session_proxy    |      Online {Code:1009,Flags:0xc0,Length:16,VendorId:10415,Value:Enumerated{1}}
session_proxy    |      Bearer-Usage {Code:1000,Flags:0xc0,Length:16,VendorId:10415,Value:Enumerated{0}}
session_proxy    |      TGPP-Selection-Mode {Code:12,Flags:0x80,Length:16,VendorId:10415,Value:UTF8String{0},Padding:3}
session_proxy    |      TGPP-SGSN-Address {Code:6,Flags:0x80,Length:16,VendorId:10415,Value:IPv4{172.16.1.8}}
session_proxy    |      TGPP-GGSN-Address {Code:7,Flags:0x80,Length:16,VendorId:10415,Value:IPv4{172.16.1.8}}
session_proxy    |      AN-GW-Address {Code:1050,Flags:0x80,Length:20,VendorId:10415,Value:Address{172.16.1.8},Padding:2}
session_proxy    |      Access-Network-Charging-Address {Code:501,Flags:0xc0,Length:20,VendorId:10415,Value:Address{172.16.1.8},Padding:2}
session_proxy    |      TGPP-SGSN-MCC-MNC {Code:18,Flags:0x80,Length:20,VendorId:10415,Value:UTF8String{00101},Padding:3}
session_proxy    |      TGPP-User-Location-Info {Code:22,Flags:0x80,Length:28,VendorId:10415,Value:OctetString{0x8200f110000100f11000000101},Padding:3}
session_proxy    |      QoS-Information {Code:1016,Flags:0xc0,Length:44,VendorId:10415,Value:Grouped{
session_proxy    |              APN-Aggregate-Max-Bitrate-DL {Code:1040,Flags:0x80,Length:16,VendorId:10415,Value:Unsigned32{97000000}},
session_proxy    |              APN-Aggregate-Max-Bitrate-UL {Code:1041,Flags:0x80,Length:16,VendorId:10415,Value:Unsigned32{47000000}},
session_proxy    |      }}
session_proxy    |      Default-EPS-Bearer-QoS {Code:1049,Flags:0x80,Length:88,VendorId:10415,Value:Grouped{
session_proxy    |              QoS-Class-Identifier {Code:1028,Flags:0xc0,Length:16,VendorId:10415,Value:Enumerated{9}},
session_proxy    |              Allocation-Retention-Priority {Code:1034,Flags:0x80,Length:60,VendorId:10415,Value:Grouped{
session_proxy    |                      Priority-Level {Code:1046,Flags:0x80,Length:16,VendorId:10415,Value:Unsigned32{9}},
session_proxy    |                      Pre-emption-Capability {Code:1047,Flags:0x80,Length:16,VendorId:10415,Value:Enumerated{1}},
session_proxy    |                      Pre-emption-Vulnerability {Code:1048,Flags:0x80,Length:16,VendorId:10415,Value:Enumerated{1}},
session_proxy    |              }}
session_proxy    |      }}
session_proxy    |

[Bug] ARP and BearerQoS parsing

I took create session hex stream from pcap and created a test case and started stepping through the code. I then compared it to wireshark outputs. The below seems to be divergent and might be bugs -

diff --git a/v2/ies/arp.go b/v2/ies/arp.go
index d77a326..2d732e9 100644
--- a/v2/ies/arp.go
+++ b/v2/ies/arp.go
@@ -21,7 +21,7 @@ func (i *IE) PreemptionCapability() bool {
 
        switch i.Type {
        case AllocationRetensionPriority, BearerQoS:
-               return (i.Payload[0] & 0x40) == 1
+               return (i.Payload[0] & 0x40) != 1
        default:
                return false
        }
@@ -35,7 +35,7 @@ func (i *IE) PriorityLevel() (uint8, error) {
 
        switch i.Type {
        case AllocationRetensionPriority, BearerQoS:
-               return i.Payload[0] & 0x3c, nil
+               return (i.Payload[0] & 0x3c) >> 2, nil
        default:
                return 0, &InvalidTypeError{Type: i.Type}
        }
@@ -49,7 +49,7 @@ func (i *IE) PreemptionVulnerability() bool {
 
        switch i.Type {
        case AllocationRetensionPriority, BearerQoS:
-               return (i.Payload[0] & 0x01) == 1
+               return (i.Payload[0] & 0x01) != 1
        default:
                return false
        }
diff --git a/v2/ies/bearer-qos.go b/v2/ies/bearer-qos.go
index cb80752..bbd3a7e 100644
--- a/v2/ies/bearer-qos.go
+++ b/v2/ies/bearer-qos.go
@@ -47,7 +47,7 @@ func (i *IE) MBRForUplink() (uint64, error) {
                if len(i.Payload) < 7 {
                        return 0, io.ErrUnexpectedEOF
                }
-               return utils.Uint40To64(i.Payload[3:7]), nil
+               return utils.Uint40To64(i.Payload[2:7]), nil
        case FlowQoS:
                if len(i.Payload) < 6 {
                        return 0, io.ErrUnexpectedEOF

Don’t overwrite handler

In examples/sgw handler functions for S5 is overwritten each time a subscriber establishes the Session with subscriber specific information.

Built-in Metrics support

Wondering if metrics #64 should be added to conn/sess itself? Of course it should be optional.

annotated with type/raddr/TEID/bearer/IMSI/TAI labels where possible

  1. Counters for message received/sent (already done in #64 with type/raddr labels)
  2. Histogram for time spent in system

handleMessage forces requestor to timeout in case of not valid message

Hello

When we send a message we use Session waitMessage to wait for its specific response based on its sequence number.

The response message will be catch by handlerMessage. However, I see that func (c *Conn) handleMessage(senderAddr net.Addr, msg message.Message) error { also includes c.validate. That means that in case of receiving a proper sequence number, but a bad TEID, the validation will error and waitMessage will never receive an answer for that specific sequence. That also will cause the requestor to be forced to time out, even that a reply was sent back.

Wouldn't it be better not to do that validation there, and just provide the handler with the message that matches the sequence number. The handler could implemente then the validation and trigger an error back to the caller if needed

Configuration file

A config file should be possible to use that would define exact content of each message. Otherwise each message has to be compose programatically and code needs to be rebuilt.

Thoughts on state persistence?

How/where should this be handled? How to survive a restart without losing all the sessions in case of scheduled and unscheduled maintenance?

To support scheduled, I am guessing, the app can stop serving, get list of sessions, encode (using gob?) and write to file. On startup read file, decode, start serving.

To support unscheduled, the app will have to not use the session store of library and instead operate on blob store (network/disk) on every message.

What do you think?

IE parsers should return error

Currently the helper funcs of IEs return zero-value as a first returned value but it should return error in case of unexpected payload given.

v2/Add more messages and IEs

The messages currently supported with helpers are not enough. Implement more messages(like Delete Bearer Request, Context Request, etc.) to be more useful.

5G GTP-U Load Generator

Hi,

Please I will like to ask if an example for generating GTPU load test towards a UPF can be made.

I was able to get something from the following repo https://gitlab.eurecom.fr/kharade/gtp-traffic-generator but unfortunately I could not build it (I have tried severally to contact the repo owner and the OAI forum but I did not get any response).

Currently I don't have in-depth Golang skills but I think this is something that might be of value, I will appreciate if someone can assist in this regard.

Issue of running pgw of gw-tester

Hi, I encounter some issues when running pgw of gw-tester. Pgw can not start with the pgw.yml in example. I have modified the ip address in pgw,yml to make it work. But another issue comes in the terminal of pgw when I start enb. Details are shown below:
error handling message on Conn 127.0.1.14:2123: failed to handle Create Session Request: Link not found
I am wondering if I set the ip address in pgw.yml is not correct.
Any ideas?
Thanks.

SGW from examples ignores any incoming packet

The reason for that is defer cancel() on line 66 of examples/sgw/main.go.
'defer' will be called at the end of newSGW() function while obviously it was intended to be called at the end of program life.
As result connections will be closed as soon as newSGW() returns since 'cancel' is called on underlying context.

Testing with NextEPC

Hello, has anyone tried this tester with NextEPC?
I've tried but still doesn't work.

Delete bearer from SGW/PGW

Hi, I always get error from MME (S11), when trying to delete bearer from remote side (SGW/PGW).

failed to validate Delete Bearer Request: got invalid TEID: 0xb73f837e

I can provide further logs.

Proposal: Improve printing

Currently when I try to print Message output is Header + Payload in hex:

{Flags: 0x32, Type: 0x10, Length: 57, TEID: 0x00000000, SequenceNumber: 0x01c8, Payload: []byte{0x2, 0x21, 0x43, 0x65, 0x87, 0x9, 0x21, 0x43, 0xf5, 0xe, 0x8, 0x10, 0x0, 0x2, 0x34, 0x56, 0x11, 0x0, 0x2, 0x34, 0x56, 0x14, 0x5, 0x83, 0x0, 0xd, 0x3, 0x69, 0x6f, 0x74, 0x4, 0x31, 0x6e, 0x63, 0x65, 0x3, 0x63, 0x6f, 0x6d, 0x85, 0x0, 0x4, 0xc0, 0xa8, 0x1, 0x1, 0x85, 0x0, 0x4, 0xa, 0xa, 0x2, 0x2}}

This is due to the fact that only header has String() interface: func (h *Header) String() string

For debugging purposes I'd suggest to have an option to print fully parsed message. Where instead of payload I could see IMSI, TEID, etc fields in readable format.

User Location Information incorrect ECGI ECI mask

In uli.go we have

ECI:  eci & 0xfffff,

As I understand 20 bits mask here for eNodeB Id, but since ECI includes 8bit CellId we should mask 28 bits (0xFffFFff).
At least this is how wireshark parses data.
Checking specs, will prepare commit if I find reference for this

cannot create GTP device; Operation not supported

Uname info: Linux 05911578bd58 4.18.0-193.1.2.el8_2.x86_64 #1 SMP Thu May 7 16:37:54 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

[root@05911578bd58 libgtp5gnl]# ip netns exec ue1 gtp-link add ue1
cannot create GTP device
: Operation not supported

Strace:

arch_prctl(ARCH_SET_FS, 0x7f8bb4926740) = 0
mprotect(0x7f8bb42f8000, 16384, PROT_READ) = 0
mprotect(0x7f8bb4506000, 4096, PROT_READ) = 0
mprotect(0x7f8bb470b000, 4096, PROT_READ) = 0
mprotect(0x601000, 4096, PROT_READ) = 0
mprotect(0x7f8bb4935000, 4096, PROT_READ) = 0
munmap(0x7f8bb4929000, 39001) = 0
socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 3
socket(AF_INET, SOCK_DGRAM, IPPROTO_IP) = 4
bind(3, {sa_family=AF_INET, sin_port=htons(3386), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
bind(4, {sa_family=AF_INET, sin_port=htons(2152), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
brk(NULL) = 0xf69000
brk(0xf8a000) = 0xf8a000
brk(NULL) = 0xf8a000
socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE) = 5
bind(5, {sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, 12) = 0
getsockname(5, {sa_family=AF_NETLINK, nl_pid=133, nl_groups=00000000}, [12]) = 0
sendto(5, {{len=80, type=0x10 /* NLMSG_??? /, flags=NLM_F_REQUEST|NLM_F_ACK|0x600, seq=1619647437, pid=0}, "\x02\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x07\x00\x03\x00\x75\x65\x31\x00\x28\x00\x12\x80\x07\x00\x01\x00"...}, 80, 0, {sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, 12) = 80
recvmsg(5, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base={{len=100, type=NLMSG_ERROR, flags=0, seq=1619647437, pid=133}, {error=-EOPNOTSUPP, msg={{len=80, type=0x10 /
NLMSG_??? */, flags=NLM_F_REQUEST|NLM_F_ACK|0x600, seq=1619647437, pid=0}, "\x02\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x07\x00\x03\x00\x75\x65\x31\x00\x28\x00\x12\x80\x07\x00\x01\x00"...}}}, iov_len=4096}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 100

Fork friendly go mod

Should we rename the module to be go-gtp instead of the github url and appropriately change the import path? Would this make it more fork friendly? I did face an issue when trying to build my app using forked copy. I could only build with local copy and not pointing to my github using the replace keyword

[Bug] Remove Session will delete wrong entries from TEIDSessionMap

Introduced in #67. This will iterate through all IFTypes and not just the ones allocated on this Conn.

go-gtp/v2/conn.go

Lines 695 to 702 in 7dc3c7b

func (c *Conn) RemoveSession(session *Session) {
c.imsiSessionMap.delete(session.IMSI)
session.teidMap.rangeWithFunc(func(k, v interface{}) bool {
teid := v.(uint32)
c.teidSessionMap.delete(teid)
return true
})
}

This can be solved in 3 ways -

  1. On calling NewFTEID we check if the IFType has it own TEIDSessionMap and allocate/remove TEID on that. GetSessionByTEID will have to include IFType.

  2. Declare upfront which IFTypes this Conn will be allocating TEIDs for, which will share the existing TEIDSessionMap. During allocate/remove we will check IFTypes on this Conn is enabled.

  3. Lookup and match the session pointer to current session, delete if equal.

 	session.teidMap.rangeWithFunc(func(k, v interface{}) bool { 
 		teid := v.(uint32)
                if s, ok := c.teidSessionMap.load(teid); ok && s == session {
 		        c.teidSessionMap.delete(teid) 
                }
 		return true 
 	}) 

Catch Echo Responses

Hi @wmnsk, I see that when we send any of the messages we can use session.WaitMessage(sequence, GtpTimeout) to wait for the response for this specific message. That function works because that message is received on a specific queue for that session

However, when we send and EchoRequest, there is no session concept, so we can't use WaitMessate function.

I see that you have solved that on func Dial where you manually handle the echo response. But that can be done because 'Dial` function has access to the private methods on the connection.

Maybe I am missing the function, but is there any way to wait for an EchoResponse similar to waitMessage?

Thanks

gw-tester execution problem with docker

Hi there,

I'm trying to execute GW tester in containers as described in Readme and in Gist ( https://gist.github.com/wmnsk/dd27b63cefe4fc1ac8dba32b9adc8f1d ) in authors blog, but I get error on attempt to start any container:

ERROR: for mme Cannot start service mme: attaching to network failed, make sure your network options are correct and check manager logs: context deadline exceeded

I also attempted to do the same through docker compose (as proposed in cncf/cnf-testbed#342 ), but result is still the same.

Any hints what should be done? Maybe some initial setup is missing? I was searching for solution for a while - ensured ports are opened, checked node is not in drain state, etc., but still no success. Is there something should be done out of steps describe in gist or patch? docker swarm init, ... ?

I can provide current patch on demand. Doesn't look like an issue with project itself, but issue seems like the best option to ask community.

c.MarshalLen() and c.Header.MarshalLen() return the same value

Hi, I'm trying to Marshal my CreatePDPContextRequest back to binary, but got following error for IMSI IE:
too short to serialize

First I was receiving bytes and parsing them like this:
createPDPContReq, err := gtp_messages_v1.ParseCreatePDPContextRequest(gtpPacket)
I've changed some values:
createPDPContReq.SGSNAddressForSignalling = ies_v1.NewGSNAddress(gtpcAddress) createPDPContReq.SGSNAddressForSignalling.SetLength() createPDPContReq.SGSNAddressForUserTraffic = ies_v1.NewGSNAddress(gtpuAddress) createPDPContReq.SGSNAddressForUserTraffic.SetLength() createPDPContReq.TEIDDataI = ies_v1.NewTEIDDataI(downlinkTeidProxyGGSN)

Finally I wanted to Marshal this request back to binary and send it:
createPDPContReqBytes, err := createPDPContReq.Marshal()

But, I see that in:
func (c *CreatePDPContextRequest) MarshalTo(b []byte) error {

there is line, where we are making header payload:
c.Header.Payload = make([]byte, c.MarshalLen()-c.Header.MarshalLen())

But c.MarshalLen() and c.Header.MarshalLen() return the same value, so c.Header.Payload will be equal to 0.
Could you please advice? :)

Does go-gtp allow to create the GTP headers?

Hi!

I need to go through an already established GTP tunnel. To do so, I need to create the GTP header. I was wondering if your project has any kind of facilities for it. I've been looking through it and so far I couldn't find any or a similar example.

Regards,
Víctor

GTP version 1 with extension header

Hi @wmnsk , thank you for amazing project. I need to test UPF with GTP version 1 with extension header. I was wondering if your project has any kind of facilities to do that. I tried to change message.header struct without sucess. Any help about this ? I attach an example of extension header that I tried to reproduce in go-gtp.

extension-header.zip

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.