/
af_xdp.go
97 lines (83 loc) · 2.07 KB
/
af_xdp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package pktgen
import (
"context"
"fmt"
"math"
"net"
"github.com/asavie/xdp"
"github.com/vishvananda/netlink"
)
// AFXdpSender implements the Sender interface using AF_XDP
type AFXdpSender struct {
queueID int
iface string
srcIP net.IP
dstIP net.IP
srcPort uint16
dstPort uint16
payloadSize int
srcMAC, dstMAC net.HardwareAddr
}
// NewAFXdpSender creates a new AFXdpSender with specified parameters
func NewAFXdpSender(iface string, srcIP, dstIP net.IP, srcPort, dstPort, payloadSize int, srcMAC, dstMAC net.HardwareAddr, queueID int) *AFXdpSender {
return &AFXdpSender{
queueID: queueID,
srcMAC: srcMAC,
dstMAC: dstMAC,
iface: iface,
srcIP: srcIP,
dstIP: dstIP,
srcPort: uint16(srcPort),
dstPort: uint16(dstPort),
payloadSize: payloadSize,
}
}
// Send sends packets using AFXdpSender
func (s *AFXdpSender) Send(ctx context.Context) error {
// Initialize the XDP socket.
link, err := netlink.LinkByName(s.iface)
if err != nil {
panic(err)
}
xsk, err := xdp.NewSocket(link.Attrs().Index, s.queueID, nil)
if err != nil {
panic(err)
}
// create a packet configuration
config, err := NewPacketConfig(
WithEthernetLayer(s.srcMAC, s.dstMAC),
WithIpLayer(s.srcIP, s.dstIP),
WithUdpLayer(int(s.srcPort), int(s.dstPort)),
WithPayloadSize(s.payloadSize),
)
if err != nil {
return fmt.Errorf("error configuring packet: %v", err)
}
// build the packet
packet, err := BuildPacket(config)
if err != nil {
return fmt.Errorf("failed to build packet: %w", err)
}
frameLen := len(packet)
// Fill all the frames in UMEM with the pre-generated UDP packet.
descs := xsk.GetDescs(math.MaxInt32, false)
for i := range descs {
frameLen = copy(xsk.GetFrame(descs[i]), packet)
}
for {
select {
case <-ctx.Done():
return nil
default:
descs := xsk.GetDescs(xsk.NumFreeTxSlots(), false)
for i := range descs {
descs[i].Len = uint32(frameLen)
}
xsk.Transmit(descs)
_, _, err = xsk.Poll(-1)
if err != nil {
panic(err)
}
}
}
}