Skip to content

Commit

Permalink
fix: Add multiple GRE tunnel when have multiple QFI settings (#7)
Browse files Browse the repository at this point in the history
* feat: add multiple tunnel for different QFI

* fix: fix bugs and add ping test

* fix: use map for linkGREs and add route at default path

* fix: fix linter error

* fix: error handling for linkGREs map

* feat: add specific route to each qfi
  • Loading branch information
andy89923 authored Jun 11, 2024
1 parent 8810f65 commit b0c644c
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 31 deletions.
64 changes: 45 additions & 19 deletions internal/gre/gre.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package gre
import (
"fmt"
"net"
"strconv"

"github.com/vishvananda/netlink"

Expand All @@ -11,27 +12,56 @@ import (
"github.com/free5gc/n3iwue/pkg/context"
)

func SetupGreTunnel(greIfaceName, parentIfaceName string, ueTunnelAddr, n3iwfTunnelAddr,
pduAddr net.IP, qoSInfo *Qos.PDUQoSInfo,
func SetupGreTunnels(
greIfaceName, parentIfaceName string,
ueTunnelAddr, n3iwfTunnelAddr, pduAddr net.IP,
qoSInfo *Qos.PDUQoSInfo,
) (map[uint8]*netlink.Link, error) {
parent, err := netlink.LinkByName(parentIfaceName)
if err != nil {
return nil, fmt.Errorf("netlink.LinkByName: [%+v] %+v", parentIfaceName, err)
}

if qoSInfo == nil {
linkGre, err := SetupGreTunnel(greIfaceName, parent, ueTunnelAddr, n3iwfTunnelAddr, pduAddr, 0)
return map[uint8]*netlink.Link{
1: &linkGre,
}, err
}

n3ueSelf := context.N3UESelf()
netlinks := map[uint8]*netlink.Link{}

for _, qfi := range qoSInfo.QfiList {
linkGRE, err := SetupGreTunnel(greIfaceName, parent, ueTunnelAddr, n3iwfTunnelAddr, pduAddr, qfi)
if err != nil {
return nil, fmt.Errorf("SetupGreTunnel(): [%s]", err)
}

n3ueSelf.CreatedIface = append(n3ueSelf.CreatedIface, &linkGRE)
netlinks[qfi] = &linkGRE
}
return netlinks, nil
}

func SetupGreTunnel(
greIfaceName string,
parent netlink.Link,
ueTunnelAddr, n3iwfTunnelAddr, pduAddr net.IP,
qfi uint8,
) (netlink.Link, error) {
var (
parent netlink.Link
greKeyField uint32
err error
)

if qoSInfo != nil {
greKeyField |= (uint32(qoSInfo.QfiList[0]) & 0x3F) << 24
}

if parent, err = netlink.LinkByName(parentIfaceName); err != nil {
return nil, err
}
greKeyField = (uint32(qfi) & 0x3F) << 24
newGreIfaceName := greIfaceName + "-" + strconv.Itoa(int(qfi))

// New GRE tunnel interface
newGRETunnel := &netlink.Gretun{
LinkAttrs: netlink.LinkAttrs{
Name: greIfaceName,
Name: newGreIfaceName,
MTU: 1438, // remain for endpoint IP header(most 40 bytes if IPv6) and ESP header (22 bytes)
},
Link: uint32(parent.Attrs().Index), // PHYS_DEV in iproute2; IFLA_GRE_LINK in linux kernel
Expand All @@ -40,17 +70,16 @@ func SetupGreTunnel(greIfaceName, parentIfaceName string, ueTunnelAddr, n3iwfTun
IKey: greKeyField,
OKey: greKeyField,
}

logger.AppLog.Infof("GRE Key Field: 0x%x", greKeyField)
logger.AppLog.Infof("New GRE Tunnel, Key Field: [0x%x], IfaceName: [%+v]", greKeyField, newGreIfaceName)

if err = netlink.LinkAdd(newGRETunnel); err != nil {
return nil, err
return nil, fmt.Errorf("netlink.LinkAdd: [%+v] %+v", newGreIfaceName, err)
}

// Get link info
linkGRE, err := netlink.LinkByName(greIfaceName)
linkGRE, err := netlink.LinkByName(newGreIfaceName)
if err != nil {
return nil, fmt.Errorf("No link named %s", greIfaceName)
return nil, fmt.Errorf("no link named: [%s]", newGreIfaceName)
}

linkGREAddr := &netlink.Addr{
Expand All @@ -69,8 +98,5 @@ func SetupGreTunnel(greIfaceName, parentIfaceName string, ueTunnelAddr, n3iwfTun
return nil, err
}

n3ueSelf := context.N3UESelf()
n3ueSelf.CreatedIface = append(n3ueSelf.CreatedIface, &parent)

return linkGRE, nil
}
48 changes: 36 additions & 12 deletions internal/nwucp/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/free5gc/n3iwue/internal/packet/nasPacket"
context "github.com/free5gc/n3iwue/pkg/context"
"github.com/free5gc/nas"
"github.com/free5gc/nas/nasType"
)

var naslog *logrus.Entry
Expand Down Expand Up @@ -57,24 +58,47 @@ func HandleDLNASTransport(n3ueSelf *context.N3UE, nasMsg *nas.Message) {

newGREName := fmt.Sprintf("%s-id-%d", n3ueSelf.N3ueInfo.GreIfaceName, n3ueSelf.N3ueInfo.XfrmiId)

var linkGRE netlink.Link
if linkGRE, err = gre.SetupGreTunnel(newGREName, n3ueSelf.TemporaryXfrmiName, n3ueSelf.UEInnerAddr.IP,
var linkGREs map[uint8]*netlink.Link
if linkGREs, err = gre.SetupGreTunnels(newGREName, n3ueSelf.TemporaryXfrmiName, n3ueSelf.UEInnerAddr.IP,
n3ueSelf.TemporaryUPIPAddr, pduAddress, n3ueSelf.TemporaryQosInfo); err != nil {
naslog.Errorf("Setup GRE tunnel %s Fail %+v", newGREName, err)
naslog.Errorf("Setup GRE tunnel %s Fail: %+v", newGREName, err)
return
}

// Add route
upRoute := &netlink.Route{
LinkIndex: linkGRE.Attrs().Index,
Dst: &net.IPNet{
IP: net.IPv4zero,
Mask: net.IPv4Mask(0, 0, 0, 0),
},
qfiToTargetMap, err := nasPacket.GetQFItoTargetMap(nasMsg.PDUSessionEstablishmentAccept)
if err != nil {
naslog.Errorf("GetQFItoTargetMap Fail: %+v", err)
return
}

if err := netlink.RouteAdd(upRoute); err != nil {
naslog.Warnf("netlink.RouteAdd: %+v", err)
// Add route
for qfi, link := range linkGREs {
tunnel := *link
priority := 1 // lower is higher (1 ~ 7)

var remoteAddress nasType.PacketFilterIPv4RemoteAddress
var ok bool
if qfi == uint8(1) { // default qfi
remoteAddress.Address = net.IPv4zero
remoteAddress.Mask = net.IPv4Mask(0, 0, 0, 0)
priority = 7
} else if remoteAddress, ok = qfiToTargetMap[qfi]; !ok {
naslog.Errorf("not found target address for QFI [%v] from NAS", qfi)
continue
}

naslog.Infof("Add route: QFI[%+v] remote address[%+v]", qfi, remoteAddress)
upRoute := &netlink.Route{
LinkIndex: tunnel.Attrs().Index,
Dst: &net.IPNet{
IP: remoteAddress.Address,
Mask: remoteAddress.Mask,
},
Priority: priority,
}
if err := netlink.RouteAdd(upRoute); err != nil {
naslog.Warnf("netlink.RouteAdd: %+v", err)
}
}

n3ueSelf.PduSessionCount++
Expand Down
34 changes: 34 additions & 0 deletions internal/packet/nasPacket/nasPduDl.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
n3ue_security "github.com/free5gc/n3iwue/internal/security"
"github.com/free5gc/nas"
"github.com/free5gc/nas/nasMessage"
"github.com/free5gc/nas/nasType"
)

func DecodePDUSessionEstablishmentAccept(
Expand Down Expand Up @@ -50,3 +51,36 @@ func GetPDUAddress(accept *nasMessage.PDUSessionEstablishmentAccept) (net.IP, er

return nil, fmt.Errorf("PDUAddress is nil")
}

func GetQFItoTargetMap(
accept *nasMessage.PDUSessionEstablishmentAccept,
) (
map[uint8]nasType.PacketFilterIPv4RemoteAddress, error,
) {
qfiMap := map[uint8]nasType.PacketFilterIPv4RemoteAddress{}

var rules nasType.QoSRules
if err := rules.UnmarshalBinary(accept.AuthorizedQosRules.Buffer); err != nil {
return nil, fmt.Errorf("rules UnmarshalBinary: %+v", err)
}

for _, rule := range rules {
for _, pfList := range rule.PacketFilterList {
for _, component := range pfList.Components {
if component.Type() == nasType.PacketFilterComponentTypeIPv4RemoteAddress {
var b []byte
var err error
if b, err = component.MarshalBinary(); err != nil {
return nil, fmt.Errorf("MarshalBinary err: %+v", err)
}
var addr nasType.PacketFilterIPv4RemoteAddress
if err = addr.UnmarshalBinary(b); err != nil {
return nil, fmt.Errorf("UnmarshalBinary err: %+v", err)
}
qfiMap[rule.QFI] = addr
}
}
}
}
return qfiMap, nil
}
6 changes: 6 additions & 0 deletions pkg/procedure/Procedure.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ func StartProcedure() {
}
case context.PduSessionCreated:
AppLog.Info("PduSession Created")
if err := TestConnectivity("9.9.9.9"); err != nil {
AppLog.Errorf("ping fail : %+v", err)
}
if err := TestConnectivity("1.1.1.1"); err != nil {
AppLog.Errorf("ping fail : %+v", err)
}
if err := TestConnectivity("8.8.8.8"); err != nil {
AppLog.Errorf("ping fail : %+v", err)
} else {
Expand Down

0 comments on commit b0c644c

Please sign in to comment.