Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions clean.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,11 @@ for XFRMI in ${XFRMIs}; do
sudo ip link del ${XFRMI}
echo del ${XFRMI}
done

# Remove all VRF interfaces
echo "[Info] Remove all VRF interfaces"
VRFs=$(ip link show type vrf | awk 'NR%2==1 {print $2}' | cut -d @ -f 1)
for VRF in ${VRFs}; do
sudo ip link del ${VRF}
echo del ${VRF}
done
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ require (
github.com/free5gc/ngap v1.1.2
github.com/free5gc/openapi v1.2.3
github.com/free5gc/util v1.0.7-0.20241017071924-da29aef99a1c
github.com/go-ping/ping v0.0.0-20211014180314-6e2b003bffdd
github.com/google/gopacket v1.1.19
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.9.3
Expand Down
19 changes: 19 additions & 0 deletions internal/nwucp/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/free5gc/n3iwue/internal/gre"
"github.com/free5gc/n3iwue/internal/logger"
"github.com/free5gc/n3iwue/internal/packet/nasPacket"
"github.com/free5gc/n3iwue/internal/vrf"
context "github.com/free5gc/n3iwue/pkg/context"
"github.com/free5gc/nas"
"github.com/free5gc/nas/nasType"
Expand Down Expand Up @@ -87,6 +88,17 @@ func (s *Server) handleDLNASTransport(evt *context.HandleDLNASTransportEvt) {

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

// Create VRF
vrfName := fmt.Sprintf("vrf-pdu-%d", n3ueSelf.PduSessionCount)
vrfTableID := 100 + int(n3ueSelf.PduSessionCount)

vrfLink, err := vrf.CreateOrGetVRF(vrfName, vrfTableID)
if err != nil {
nwucpLog.Errorf("Create VRF failed:%s: %v", vrfName, err)
return
}
nwucpLog.Infof("Use VRF %s (Table %d)", vrfName, vrfTableID)

var linkGREs map[uint8]*netlink.Link
if linkGREs, err = gre.SetupGreTunnels(newGREName, n3ueSelf.TemporaryXfrmiName, n3ueSelf.UEInnerAddr.IP,
n3ueSelf.TemporaryUPIPAddr, pduAddress, n3ueSelf.TemporaryQosInfo); err != nil {
Expand Down Expand Up @@ -115,6 +127,12 @@ func (s *Server) handleDLNASTransport(evt *context.HandleDLNASTransportEvt) {
nwucpLog.Errorf("not found target address for QFI [%v] from NAS", qfi)
continue
}
// Bind GRE interface to VRF
if err := netlink.LinkSetMaster(tunnel, vrfLink); err != nil {
nwucpLog.Errorf("Failed to bind %s to VRF %s", tunnel.Attrs().Name, vrfName)
continue
}
nwucpLog.Infof("Interface %s bound to VRF %s", tunnel.Attrs().Name, vrfName)

nwucpLog.Infof("Add route: QFI[%+v] remote address[%+v]", qfi, remoteAddress)
upRoute := &netlink.Route{
Expand All @@ -124,6 +142,7 @@ func (s *Server) handleDLNASTransport(evt *context.HandleDLNASTransportEvt) {
Mask: remoteAddress.Mask,
},
Priority: priority,
Table: vrfTableID,
}
if err := netlink.RouteAdd(upRoute); err != nil {
nwucpLog.Warnf("netlink.RouteAdd: %+v", err)
Expand Down
46 changes: 46 additions & 0 deletions internal/vrf/vrf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package vrf

import (
"fmt"

"github.com/vishvananda/netlink"

"github.com/free5gc/n3iwue/pkg/context"
)

func CreateOrGetVRF(vrfName string, tableID int) (netlink.Link, error) {
// Try to get VRF
link, err := netlink.LinkByName(vrfName)
if err == nil {
// Found, check if it is a VRF
if vrf, ok := link.(*netlink.Vrf); ok {
if vrf.Table == uint32(tableID) {
return vrf, nil // VRF exists and is correct
}
return nil, fmt.Errorf("VRF %s exists but Table ID mismatch (need %d, actual %d)", vrfName, tableID, vrf.Table)
}
return nil, fmt.Errorf("device %s exists but is not a VRF", vrfName)
}

// Create VRF (l3mdev) device
vrfLink := &netlink.Vrf{
LinkAttrs: netlink.LinkAttrs{Name: vrfName},
Table: uint32(tableID),
}

if err := netlink.LinkAdd(vrfLink); err != nil {
return nil, fmt.Errorf("netlink.LinkAdd VRF %s failed: %v", vrfName, err)
}

// Enable VRF device
if err := netlink.LinkSetUp(vrfLink); err != nil {
return nil, fmt.Errorf("netlink.LinkSetUp VRF %s failed: %v", vrfName, err)
}

// Add to CreatedIface for auto cleanup
n3ueSelf := context.N3UESelf()
var createdLink netlink.Link = vrfLink
n3ueSelf.CreatedIface = append(n3ueSelf.CreatedIface, &createdLink)

return vrfLink, nil
}
50 changes: 16 additions & 34 deletions pkg/procedure/Procedure.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ package procedure
import (
"context"
"fmt"
"os/exec"
"runtime/debug"
"sync"
"time"

"github.com/go-ping/ping"
"github.com/sirupsen/logrus"

"github.com/free5gc/n3iwue/internal/logger"
Expand Down Expand Up @@ -127,46 +126,29 @@ func (s *Server) handleEvent(evt n3iwue_context.ProcedureEvt) {
func (s *Server) TestConnectivity(addr string) error {
n3ueSelf := s.Context()

// Ping remote
pinger, err := ping.NewPinger(addr)
if err != nil {
return err
}

// Run with root
pinger.SetPrivileged(true)
// Calculate the VRF ID used for the last session
// Since PduSessionCount is incremented after session establishment, we subtract 1
vrfID := n3ueSelf.PduSessionCount - 1
vrfName := fmt.Sprintf("vrf-pdu-%d", vrfID)

pinger.OnRecv = func(pkt *ping.Packet) {
AppLog.Infof("%d bytes from %s: icmp_seq=%d time=%v\n",
pkt.Nbytes, pkt.IPAddr, pkt.Seq, pkt.Rtt)
}
pinger.OnFinish = func(stats *ping.Statistics) {
AppLog.Infof("\n--- %s ping statistics ---\n", stats.Addr)
AppLog.Infof("%d packets transmitted, %d packets received, %v%% packet loss\n",
stats.PacketsSent, stats.PacketsRecv, stats.PacketLoss)
AppLog.Infof("round-trip min/avg/max/stddev = %v/%v/%v/%v\n",
stats.MinRtt, stats.AvgRtt, stats.MaxRtt, stats.StdDevRtt)
}
AppLog.Infof("Ping %s using VRF %s", addr, vrfName)

pinger.Count = 5
pinger.Timeout = 10 * time.Second
args := []string{"vrf", "exec", vrfName, "ping", "-c", "5"}
if n3ueSelf.N3ueInfo.DnIPAddr != "" {
pinger.Source = n3ueSelf.N3ueInfo.DnIPAddr
args = append(args, "-I", n3ueSelf.N3ueInfo.DnIPAddr)
}
args = append(args, addr)

time.Sleep(3 * time.Second)
// Use ip vrf exec to ping
cmd := exec.CommandContext(context.Background(), "ip", args...)

if err := pinger.Run(); err != nil {
return fmt.Errorf("running ping failed: %+v", err)
}

time.Sleep(1 * time.Second)

stats := pinger.Statistics()
if stats.PacketsSent != stats.PacketsRecv {
return fmt.Errorf("ping failed")
// We can capture output to log it
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("ping failed: %v, output: %s", err, string(output))
}

AppLog.Infof("Ping output:\n%s", string(output))
return nil
}

Expand Down
Loading