xdp icon indicating copy to clipboard operation
xdp copied to clipboard

Allowing offset into frame

Open vulcanfan opened this issue 3 years ago • 1 comments

Hi, In some scenarios its advantageous to receive a packet, remove a header and then transmit it out again. From what I can see the packet is always expected to start at the beginning of the frame in umem. However ideally what we wouldn't want when removing a header is to have to copy or shunt the rest of the packet forward to the beginning of the frame. For performance reasons it would be nice to just increment a pointer or reference to where the packet really starts in the frame, ie an offset into the frame, and transmission starts from that point. Is this possible? It would be like the add/remove prefix BPF helper functions. Thanks

vulcanfan avatar May 25 '21 16:05 vulcanfan

Yes, it should be possible by adding an offset to the xdp.Desc.Addr before Transmit()ing them.

For example,

diff --git a/examples/sendudp/sendudp.go b/examples/sendudp/sendudp.go
index c193c68..45e4a2d 100644
--- a/examples/sendudp/sendudp.go
+++ b/examples/sendudp/sendudp.go
@@ -61,11 +61,16 @@ func main() {
        srcMAC, _ := hex.DecodeString(SrcMAC)
        dstMAC, _ := hex.DecodeString(DstMAC)
 
-       eth := &layers.Ethernet{
+       eth1 := &layers.Ethernet{
                SrcMAC:       net.HardwareAddr(srcMAC),
                DstMAC:       net.HardwareAddr(dstMAC),
                EthernetType: layers.EthernetTypeIPv4,
        }
+       eth2 := &layers.Ethernet{
+               SrcMAC:       net.HardwareAddr{ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, },
+               DstMAC:       net.HardwareAddr{ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, },
+               EthernetType: layers.EthernetTypeIPv4,
+       }
        ip := &layers.IPv4{
                Version:  4,
                IHL:      5,
@@ -90,7 +95,7 @@ func main() {
                FixLengths:       true,
                ComputeChecksums: true,
        }
-       err = gopacket.SerializeLayers(buf, opts, eth, ip, udp, gopacket.Payload(payload))
+       err = gopacket.SerializeLayers(buf, opts, eth1, eth2, ip, udp, gopacket.Payload(payload))
        if err != nil {
                panic(err)
        }
@@ -107,7 +112,7 @@ func main() {
        // endless loop printing statistics of the number of sent frames and
        // the number of sent bytes every second.
 
-       fmt.Printf("sending UDP packets from %v (%v) to %v (%v)...\n", ip.SrcIP, eth.SrcMAC, ip.DstIP, eth.DstMAC)
+       fmt.Printf("sending UDP packets from %v (%v) to %v (%v)...\n", ip.SrcIP, eth2.SrcMAC, ip.DstIP, eth2.DstMAC)
 
        go func() {
                var err error
@@ -129,6 +134,7 @@ func main() {
        for {
                descs := xsk.GetDescs(xsk.NumFreeTxSlots())
                for i := range descs {
+                       descs[i].Addr += 14
                        descs[i].Len = uint32(frameLen)
                }
                xsk.Transmit(descs)

the descs[i].Addr += 14 line above "removes" the eth1 layer.

slavc avatar Jun 25 '21 14:06 slavc