-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support QoS parameters in NWu and N3 and update go-gtp (#6)
* Adapt gtp to go-gtp v0.8.0 * Revise archecture of GTP and Add GRE * Support QoS info between Nwu and N3 * Revise IKE SA output foramt
- Loading branch information
Showing
9 changed files
with
368 additions
and
214 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package gre | ||
|
||
import "encoding/binary" | ||
|
||
// [TS 24.502] 9.3.3 GRE encapsulated user data packet | ||
const ( | ||
GREHeaderFieldLength = 8 | ||
GREHeaderKeyFieldLength = 4 | ||
) | ||
|
||
// Ethertypes Specified by the IETF | ||
const ( | ||
IPv4 uint16 = 0x0800 | ||
IPv6 uint16 = 0x86DD | ||
) | ||
|
||
type GREPacket struct { | ||
flags uint8 | ||
version uint8 | ||
protocolType uint16 | ||
key uint32 | ||
payload []byte | ||
} | ||
|
||
func (p *GREPacket) Marshal() []byte { | ||
packet := make([]byte, GREHeaderFieldLength+len(p.payload)) | ||
|
||
packet[0] = p.flags | ||
packet[1] = p.version | ||
binary.BigEndian.PutUint16(packet[2:4], p.protocolType) | ||
binary.BigEndian.PutUint32(packet[4:8], p.key) | ||
copy(packet[GREHeaderFieldLength:], p.payload) | ||
return packet | ||
} | ||
|
||
func (p *GREPacket) Unmarshal(b []byte) error { | ||
p.flags = b[0] | ||
p.version = b[1] | ||
|
||
p.protocolType = binary.BigEndian.Uint16(b[2:4]) | ||
|
||
offset := 4 | ||
|
||
if p.GetKeyFlag() { | ||
p.key = binary.BigEndian.Uint32(b[offset : offset+GREHeaderKeyFieldLength]) | ||
offset += GREHeaderKeyFieldLength | ||
} | ||
|
||
p.payload = append(p.payload, b[offset:]...) | ||
return nil | ||
} | ||
|
||
func (p *GREPacket) SetPayload(payload []byte, protocolType uint16) { | ||
p.payload = payload | ||
p.protocolType = protocolType | ||
} | ||
|
||
func (p *GREPacket) GetPayload() ([]byte, uint16) { | ||
return p.payload, p.protocolType | ||
} | ||
|
||
func (p *GREPacket) setKeyFlag() { | ||
p.flags |= 0x20 | ||
} | ||
|
||
func (p *GREPacket) GetKeyFlag() bool { | ||
return (p.flags & 0x20) > 0 | ||
} | ||
|
||
func (p *GREPacket) setQFI(qfi uint8) { | ||
p.key |= (uint32(qfi) & 0x3F) << 24 | ||
} | ||
|
||
func (p *GREPacket) setRQI(rqi bool) { | ||
if rqi { | ||
p.key |= 0x80 | ||
} | ||
} | ||
|
||
func (p *GREPacket) GetQFI() uint8 { | ||
return uint8((p.key >> 24) & 0x3F) | ||
} | ||
|
||
func (p *GREPacket) GetRQI() bool { | ||
return (p.key & 0x80) > 0 | ||
} | ||
|
||
func (p *GREPacket) GetKeyField() uint32 { | ||
return p.key | ||
} | ||
|
||
func (p *GREPacket) SetQoS(qfi uint8, rqi bool) { | ||
p.setQFI(qfi) | ||
p.setRQI(rqi) | ||
p.setKeyFlag() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package handler | ||
|
||
import ( | ||
"net" | ||
"runtime/debug" | ||
|
||
"github.com/sirupsen/logrus" | ||
gtp "github.com/wmnsk/go-gtp/gtpv1" | ||
gtpMsg "github.com/wmnsk/go-gtp/gtpv1/message" | ||
|
||
n3iwfContext "github.com/free5gc/n3iwf/context" | ||
"github.com/free5gc/n3iwf/gre" | ||
gtpQoSMsg "github.com/free5gc/n3iwf/gtp/message" | ||
"github.com/free5gc/n3iwf/logger" | ||
) | ||
|
||
var gtpLog *logrus.Entry | ||
|
||
func init() { | ||
gtpLog = logger.GTPLog | ||
} | ||
|
||
// Parse the fields not supported by go-gtp and forward data to UE. | ||
func HandleQoSTPDU(c gtp.Conn, senderAddr net.Addr, msg gtpMsg.Message) error { | ||
pdu := gtpQoSMsg.QoSTPDUPacket{} | ||
if err := pdu.Unmarshal(msg.(*gtpMsg.TPDU)); err != nil { | ||
return err | ||
} | ||
|
||
forward(pdu) | ||
return nil | ||
} | ||
|
||
// Forward user plane packets from N3 to UE with GRE header and new IP header encapsulated | ||
func forward(packet gtpQoSMsg.QoSTPDUPacket) { | ||
defer func() { | ||
if p := recover(); p != nil { | ||
// Print stack for panic to log. Fatalf() will let program exit. | ||
gtpLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) | ||
} | ||
}() | ||
|
||
// N3IWF context | ||
self := n3iwfContext.N3IWFSelf() | ||
|
||
// Nwu connection in IPv4 | ||
NWuConn := self.NWuIPv4PacketConn | ||
|
||
// Find UE information | ||
ue, ok := self.AllocatedUETEIDLoad(packet.GetTEID()) | ||
if !ok { | ||
gtpLog.Error("UE context not found") | ||
return | ||
} | ||
|
||
// UE inner IP in IPSec | ||
ueInnerIPAddr := ue.IPSecInnerIPAddr | ||
|
||
var ( | ||
qfi uint8 | ||
rqi bool | ||
) | ||
|
||
// QoS Related Parameter | ||
if packet.HasQoS() { | ||
qfi, rqi = packet.GetQoSParameters() | ||
gtpLog.Tracef("QFI: %v, RQI: %v", qfi, rqi) | ||
} | ||
|
||
// Encasulate IPv4 packet with GRE header before forward to UE through IPsec | ||
grePacket := gre.GREPacket{} | ||
|
||
// TODO:[24.502(v15.7) 9.3.3 ] The Protocol Type field should be set to zero | ||
grePacket.SetPayload(packet.GetPayload(), gre.IPv4) | ||
grePacket.SetQoS(qfi, rqi) | ||
forwardData := grePacket.Marshal() | ||
|
||
// Send to UE through Nwu | ||
if n, err := NWuConn.WriteTo(forwardData, nil, ueInnerIPAddr); err != nil { | ||
gtpLog.Errorf("Write to UE failed: %+v", err) | ||
return | ||
} else { | ||
gtpLog.Trace("Forward NWu <- N3") | ||
gtpLog.Tracef("Wrote %d bytes", n) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package message | ||
|
||
import ( | ||
"encoding/hex" | ||
"errors" | ||
|
||
gtpMessage "github.com/wmnsk/go-gtp/gtpv1/message" | ||
|
||
"github.com/free5gc/n3iwf/logger" | ||
) | ||
|
||
// [TS 38.415] 5.5.2 Frame format for the PDU Session user plane protocol | ||
const ( | ||
DL_PDU_SESSION_INFORMATION_TYPE = 0x00 | ||
UL_PDU_SESSION_INFORMATION_TYPE = 0x10 | ||
) | ||
|
||
type QoSTPDUPacket struct { | ||
tPDU *gtpMessage.TPDU | ||
qos bool | ||
rqi bool | ||
qfi uint8 | ||
} | ||
|
||
func (p *QoSTPDUPacket) GetPayload() []byte { | ||
return p.tPDU.Payload | ||
} | ||
|
||
func (p *QoSTPDUPacket) GetTEID() uint32 { | ||
return p.tPDU.TEID() | ||
} | ||
|
||
func (p *QoSTPDUPacket) GetExtensionHeader() []*gtpMessage.ExtensionHeader { | ||
return p.tPDU.ExtensionHeaders | ||
} | ||
|
||
func (p *QoSTPDUPacket) HasQoS() bool { | ||
return p.qos | ||
} | ||
|
||
func (p *QoSTPDUPacket) GetQoSParameters() (uint8, bool) { | ||
return p.qfi, p.rqi | ||
} | ||
|
||
func (p *QoSTPDUPacket) Unmarshal(pdu *gtpMessage.TPDU) error { | ||
p.tPDU = pdu | ||
if p.tPDU.HasExtensionHeader() { | ||
if err := p.unmarshalExtensionHeader(); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// [TS 29.281] [TS 38.415] | ||
// Define GTP extension header | ||
// [TS 38.415] | ||
// Define PDU Session User Plane protocol | ||
func (p *QoSTPDUPacket) unmarshalExtensionHeader() error { | ||
for _, eh := range p.tPDU.ExtensionHeaders { | ||
switch eh.Type { | ||
case gtpMessage.ExtHeaderTypePDUSessionContainer: | ||
p.qos = true | ||
p.rqi = ((int(eh.Content[1]) >> 6) & 0x1) == 1 | ||
p.qfi = eh.Content[1] & 0x3F | ||
logger.GTPLog.Tracef("Parsed Extension Header: Len=%d, Next Type=%d, Content Dump:\n%s", | ||
eh.Length, eh.NextType, hex.Dump(eh.Content)) | ||
default: | ||
logger.GTPLog.Warningf("Unsupported Extension Header Field Value: %x", eh.Type) | ||
} | ||
} | ||
|
||
if !p.qos { | ||
return errors.New("unmarshalExtensionHeader err: no PDUSessionContainer in ExtensionHeaders.") | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.