Skip to content

Commit 7fd91a6

Browse files
authored
Merge pull request #643 from intel-go/gregory/af_xdp
Added AF_XDP input/output. Added ctrl-C handling
2 parents d4f80e3 + 17c6dcb commit 7fd91a6

File tree

14 files changed

+464
-32
lines changed

14 files changed

+464
-32
lines changed

Dockerfile

+5-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ RUN apt-get -q update && apt-get -q -y install \
2020
libmnl-dev \
2121
libibverbs-dev
2222

23-
RUN cd /opt && curl -L -s https://dl.google.com/go/go1.12.5.linux-amd64.tar.gz | tar zx
23+
RUN cd /opt && curl -L -s https://dl.google.com/go/go1.12.9.linux-amd64.tar.gz | tar zx
24+
RUN git clone -b v0.0.4 https://github.com/libbpf/libbpf
25+
RUN make -C libbpf/src all install
26+
RUN echo "/usr/lib64" > /etc/ld.so.conf.d/usrlib64.conf
27+
RUN ldconfig
2428

2529
RUN mkdir -p ${NFF_GO}
2630
COPY . ${NFF_GO}

README.md

+21
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,27 @@ Use Go version 1.11.4 or higher. To check the version of Go, do:
118118

119119
go version
120120
121+
### AF_XDP support
122+
123+
AF_XDP support is enabled by default, and it requires you to install
124+
`libbpf` package. At the time of writing Ubuntu doesn't have this
125+
library among its packages, so it is necessary to build `libbpf` from
126+
sources or disable AF_XDP socket support.
127+
128+
To disable it set variable `NFF_GO_NO_BPF_SUPPORT` to some unempty
129+
value. When NFF_GO is built with it, AF_XDP support is disaled and
130+
using it results in errors.
131+
132+
If you want to build `libbpf` from sources you can do it in two
133+
different ways.
134+
* If you are using stock Linux kernel from distribution, [download
135+
`libbpf` from GitHub](https://github.com/libbpf/libbpf), then
136+
execute `cd src; make; sudo make install`. Add /usr/lib64 to your
137+
ldconfig path.
138+
* If you build Linux kernel from sources, you can build `libbpf` from
139+
Linux source tree using commands `cd tools/lib/bpf; make; sudo make
140+
install install_headers`. Add /usr/local/lib64 to your ldconfig path.
141+
121142
## Building NFF-GO
122143

123144
When Go compiler runs for the first time it downloads all dependent

common/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ include $(PATH_TO_MK)/include.mk
77

88
.PHONY: testing
99
testing: check-pktgen
10-
go test
10+
go test -tags "${GO_BUILD_TAGS}"
1111

1212
.PHONY: coverage
1313
coverage:

examples/OSforwarding.go

+13-5
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,23 @@ import (
1010
)
1111

1212
func main() {
13+
// If you use af-xdp mode you need to configure queues:
14+
// e.g. ethtool -N my_device flow-type tcp4 dst-port 4242 action 16
15+
afXDP := flag.Bool("af-xdp", false, "use af-xdp. need to use ethtool to setup queues")
1316
inport := flag.String("in", "", "device for receiver")
17+
inQueue := flag.Int("in-queue", 16, "queue for receiver")
1418
outport := flag.String("out", "", "device for sender")
1519
flag.Parse()
1620

1721
flow.CheckFatal(flow.SystemInit(nil))
18-
19-
inputFlow, err := flow.SetReceiverOS(*inport)
20-
flow.CheckFatal(err)
21-
flow.CheckFatal(flow.SetSenderOS(inputFlow, *outport))
22-
22+
if *afXDP {
23+
inputFlow, err := flow.SetReceiverXDP(*inport, *inQueue)
24+
flow.CheckFatal(err)
25+
flow.CheckFatal(flow.SetSenderXDP(inputFlow, *outport))
26+
} else {
27+
inputFlow, err := flow.SetReceiverOS(*inport)
28+
flow.CheckFatal(err)
29+
flow.CheckFatal(flow.SetSenderOS(inputFlow, *outport))
30+
}
2331
flow.CheckFatal(flow.SystemStart())
2432
}

flow/flow.go

+108-8
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ package flow
3232
import (
3333
"net"
3434
"os"
35+
"os/signal"
3536
"runtime"
3637
"sync/atomic"
3738
"time"
@@ -48,7 +49,7 @@ var createdPorts []port
4849
var portPair map[types.IPv4Address](*port)
4950
var schedState *scheduler
5051
var vEach [10][vBurstSize]uint8
51-
var devices map[string]int
52+
var ioDevices map[string]interface{}
5253

5354
type Timer struct {
5455
t *time.Ticker
@@ -176,6 +177,19 @@ func addOSReceiver(socket int, out low.Rings) {
176177
schedState.addFF("OS receiver", nil, recvOS, nil, par, nil, sendReceiveKNI, 0, &par.stats)
177178
}
178179

180+
type receiveXDPParameters struct {
181+
out low.Rings
182+
socket low.XDPSocket
183+
stats common.RXTXStats
184+
}
185+
186+
func addXDPReceiver(socket low.XDPSocket, out low.Rings) {
187+
par := new(receiveXDPParameters)
188+
par.socket = socket
189+
par.out = out
190+
schedState.addFF("AF_XDP receiver", nil, recvXDP, nil, par, nil, sendReceiveKNI, 0, &par.stats)
191+
}
192+
179193
type KNIParameters struct {
180194
in low.Rings
181195
out low.Rings
@@ -269,6 +283,19 @@ func addSenderOS(socket int, in low.Rings, inIndexNumber int32) {
269283
schedState.addFF("sender OS", nil, sendOS, nil, par, nil, sendReceiveKNI, inIndexNumber, &par.stats)
270284
}
271285

286+
type sendXDPParameters struct {
287+
in low.Rings
288+
socket low.XDPSocket
289+
stats common.RXTXStats
290+
}
291+
292+
func addSenderXDP(socket low.XDPSocket, in low.Rings, inIndexNumber int32) {
293+
par := new(sendXDPParameters)
294+
par.socket = socket
295+
par.in = in
296+
schedState.addFF("AF_XDP sender", nil, sendXDP, nil, par, nil, sendReceiveKNI, inIndexNumber, &par.stats)
297+
}
298+
272299
type copyParameters struct {
273300
in low.Rings
274301
out low.Rings
@@ -439,7 +466,7 @@ const reportMbits = false
439466

440467
var sizeMultiplier uint
441468
var schedTime uint
442-
var hwtxchecksum, hwrxpacketstimestamp bool
469+
var hwtxchecksum, hwrxpacketstimestamp, setSIGINTHandler bool
443470
var maxRecv int
444471

445472
type port struct {
@@ -538,6 +565,11 @@ type Config struct {
538565
// Enables hardware assisted timestamps in packet mbufs. These
539566
// timestamps can be accessed with GetPacketTimestamp function.
540567
HWRXPacketsTimestamp bool
568+
// Disable setting custom handler for SIGINT in
569+
// SystemStartScheduler. When handler is enabled
570+
// SystemStartScheduler waits for SIGINT notification and calls
571+
// SystemStop after it. It is enabled by default.
572+
NoSetSIGINTHandler bool
541573
}
542574

543575
// SystemInit is initialization of system. This function should be always called before graph construction.
@@ -665,7 +697,7 @@ func SystemInit(args *Config) error {
665697
}
666698
}
667699
portPair = make(map[types.IPv4Address](*port))
668-
devices = make(map[string]int)
700+
ioDevices = make(map[string]interface{})
669701
// Init scheduler
670702
common.LogTitle(common.Initialization, "------------***------ Initializing scheduler -----***------------")
671703
StopRing := low.CreateRings(burstSize*sizeMultiplier, maxInIndex /* Maximum possible rings */)
@@ -690,6 +722,8 @@ func SystemInit(args *Config) error {
690722
vEach[i][j] = uint8(i)
691723
}
692724
}
725+
726+
setSIGINTHandler = !args.NoSetSIGINTHandler
693727
return nil
694728
}
695729

@@ -723,7 +757,19 @@ func SystemStartScheduler() error {
723757
return common.WrapWithNFError(err, "scheduler start failed", common.Fail)
724758
}
725759
common.LogTitle(common.Initialization, "------------***---------- NFF-GO Started ---------***------------")
726-
schedState.schedule(schedTime)
760+
761+
if setSIGINTHandler {
762+
signalChan := make(chan os.Signal, 1)
763+
signal.Notify(signalChan, os.Interrupt)
764+
go func() {
765+
schedState.schedule(schedTime)
766+
}()
767+
<-signalChan
768+
common.LogTitle(common.Debug, "Received an interrupt, stopping everything")
769+
SystemStop()
770+
} else {
771+
schedState.schedule(schedTime)
772+
}
727773
return nil
728774
}
729775

@@ -819,13 +865,14 @@ func SetReceiver(portId uint16) (OUT *Flow, err error) {
819865
// Gets name of device, will return error if can't initialize socket.
820866
// Creates RAW socket, returns new opened flow with received packets.
821867
func SetReceiverOS(device string) (*Flow, error) {
822-
socketID, ok := devices[device]
868+
v, ok := ioDevices[device]
869+
socketID := v.(int)
823870
if !ok {
824871
socketID = low.InitDevice(device)
825872
if socketID == -1 {
826873
return nil, common.WrapWithNFError(nil, "Can't initialize socket", common.BadSocket)
827874
}
828-
devices[device] = socketID
875+
ioDevices[device] = socketID
829876
}
830877
rings := low.CreateRings(burstSize*sizeMultiplier, 1)
831878
addOSReceiver(socketID, rings)
@@ -839,18 +886,57 @@ func SetSenderOS(IN *Flow, device string) error {
839886
if err := checkFlow(IN); err != nil {
840887
return err
841888
}
842-
socketID, ok := devices[device]
889+
v, ok := ioDevices[device]
890+
socketID := v.(int)
843891
if !ok {
844892
socketID = low.InitDevice(device)
845893
if socketID == -1 {
846894
return common.WrapWithNFError(nil, "Can't initialize socket", common.BadSocket)
847895
}
848-
devices[device] = socketID
896+
ioDevices[device] = socketID
849897
}
850898
addSenderOS(socketID, finishFlow(IN), IN.inIndexNumber)
851899
return nil
852900
}
853901

902+
// SetReceiverXDP adds function receive from Linux AF_XDP to flow graph.
903+
// Gets name of device and queue number, will return error if can't initialize socket.
904+
// Creates AF_XDP socket, returns new opened flow with received packets.
905+
func SetReceiverXDP(device string, queue int) (*Flow, error) {
906+
_, ok := ioDevices[device]
907+
if ok {
908+
return nil, common.WrapWithNFError(nil, "Device shouldn't have any sockets before AF_XDP. AF_XDP Send and Receive for one device in forbidden now", common.BadSocket)
909+
}
910+
socketID := low.InitXDP(device, queue)
911+
if socketID == nil {
912+
return nil, common.WrapWithNFError(nil, "Can't initialize AF_XDP socket", common.BadSocket)
913+
}
914+
ioDevices[device] = socketID
915+
rings := low.CreateRings(burstSize*sizeMultiplier, 1)
916+
addXDPReceiver(socketID, rings)
917+
return newFlow(rings, 1), nil
918+
}
919+
920+
// SetSenderXDP adds function send from flow graph to Linux AF_XDP interface.
921+
// Gets name of device, will return error if can't initialize socket.
922+
// Creates RAW socket, sends packets, closes input flow.
923+
func SetSenderXDP(IN *Flow, device string) error {
924+
if err := checkFlow(IN); err != nil {
925+
return err
926+
}
927+
_, ok := ioDevices[device]
928+
if ok {
929+
return common.WrapWithNFError(nil, "Device shouldn't have any sockets before AF_XDP. AF_XDP Send and Receive for one device in forbidden now", common.BadSocket)
930+
}
931+
socketID := low.InitXDP(device, 0)
932+
if socketID == nil {
933+
return common.WrapWithNFError(nil, "Can't initialize AF_XDP socket", common.BadSocket)
934+
}
935+
ioDevices[device] = socketID
936+
addSenderXDP(socketID, finishFlow(IN), IN.inIndexNumber)
937+
return nil
938+
}
939+
854940
// SetReceiverKNI adds function receive from KNI to flow graph.
855941
// Gets KNI device from which packets will be received.
856942
// Receive queue will be added to port automatically.
@@ -1418,6 +1504,11 @@ func recvOS(parameters interface{}, inIndex []int32, flag *int32, coreID int) {
14181504
low.ReceiveOS(srp.socket, srp.out[0], flag, coreID, &srp.stats)
14191505
}
14201506

1507+
func recvXDP(parameters interface{}, inIndex []int32, flag *int32, coreID int) {
1508+
srp := parameters.(*receiveXDPParameters)
1509+
low.ReceiveXDP(srp.socket, srp.out[0], flag, coreID, &srp.stats)
1510+
}
1511+
14211512
func processKNI(parameters interface{}, inIndex []int32, flag *int32, coreID int) {
14221513
srk := parameters.(*KNIParameters)
14231514
if srk.linuxCore == true {
@@ -1607,6 +1698,11 @@ func sendOS(parameters interface{}, inIndex []int32, flag *int32, coreID int) {
16071698
low.SendOS(srp.socket, srp.in, flag, coreID, &srp.stats)
16081699
}
16091700

1701+
func sendXDP(parameters interface{}, inIndex []int32, flag *int32, coreID int) {
1702+
srp := parameters.(*sendXDPParameters)
1703+
low.SendXDP(srp.socket, srp.in, flag, coreID, &srp.stats)
1704+
}
1705+
16101706
func merge(from low.Rings, to low.Rings) {
16111707
// We should change out rings in all flow functions which we added before
16121708
// and change them to one "after merge" ring.
@@ -1620,6 +1716,10 @@ func merge(from low.Rings, to low.Rings) {
16201716
if parameters.out[0] == from[0] {
16211717
parameters.out = to
16221718
}
1719+
case *receiveOSParameters:
1720+
if parameters.out[0] == from[0] {
1721+
parameters.out = to
1722+
}
16231723
case *generateParameters:
16241724
if parameters.out[0] == from[0] {
16251725
parameters.out = to

internal/low/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ include $(PATH_TO_MK)/include.mk
77

88
.PHONY: testing
99
testing: check-pktgen
10-
go test -v
10+
go test -v -tags "${GO_BUILD_TAGS}"

internal/low/low.go

+22-4
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,10 @@ func CheckHWRXPacketsTimestamp(port uint16) bool {
760760
return bool(C.check_hwrxpackets_timestamp_capability(C.uint16_t(port)))
761761
}
762762

763+
func InitDevice(device string) int {
764+
return int(C.initDevice(C.CString(device)))
765+
}
766+
763767
func ReceiveOS(socket int, OUT *Ring, flag *int32, coreID int, stats *common.RXTXStats) {
764768
m := CreateMempool("receiveOS")
765769
C.receiveOS(C.int(socket), OUT.DPDK_ring, (*C.struct_rte_mempool)(unsafe.Pointer(m)),
@@ -772,10 +776,6 @@ func SendOS(socket int, IN Rings, flag *int32, coreID int, stats *common.RXTXSta
772776
(*C.RXTXStats)(unsafe.Pointer(stats)))
773777
}
774778

775-
func InitDevice(device string) int {
776-
return int(C.initDevice(C.CString(device)))
777-
}
778-
779779
func SetCountersEnabledInApplication(enabled bool) {
780780
C.counters_enabled_in_application = C.bool(true)
781781
}
@@ -791,3 +791,21 @@ func GetPacketOffloadFlags(mb *Mbuf) uint64 {
791791
func GetPacketTimestamp(mb *Mbuf) uint64 {
792792
return uint64(mb.timestamp)
793793
}
794+
795+
type XDPSocket *C.struct_xsk_socket_info
796+
797+
func InitXDP(device string, queue int) XDPSocket {
798+
return C.initXDP(C.CString(device), C.int(queue))
799+
}
800+
801+
func ReceiveXDP(socket XDPSocket, OUT *Ring, flag *int32, coreID int, stats *common.RXTXStats) {
802+
m := CreateMempool("receiveXDP")
803+
C.receiveXDP(socket, OUT.DPDK_ring, (*C.struct_rte_mempool)(unsafe.Pointer(m)),
804+
(*C.int)(unsafe.Pointer(flag)), C.int(coreID), (*C.RXTXStats)(unsafe.Pointer(stats)))
805+
}
806+
807+
func SendXDP(socket XDPSocket, IN Rings, flag *int32, coreID int, stats *common.RXTXStats) {
808+
C.sendXDP(socket, C.extractDPDKRings((**C.struct_nff_go_ring)(unsafe.Pointer(&(IN[0]))),
809+
C.int32_t(len(IN))), C.int32_t(len(IN)), (*C.int)(unsafe.Pointer(flag)), C.int(coreID),
810+
(*C.RXTXStats)(unsafe.Pointer(stats)))
811+
}

0 commit comments

Comments
 (0)