mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Migrate to PacketHeader API for PacketBuffer.
Formerly, when a packet is constructed or parsed, all headers are set by the client code. This almost always involved prepending to pk.Header buffer or trimming pk.Data portion. This is known to prone to bugs, due to the complexity and number of the invariants assumed across netstack to maintain. In the new PacketHeader API, client will call Push()/Consume() method to construct/parse an outgoing/incoming packet. All invariants, such as slicing and trimming, are maintained by the API itself. NewPacketBuffer() is introduced to create new PacketBuffer. Zero value is no longer valid. PacketBuffer now assumes the packet is a concatenation of following portions: * LinkHeader * NetworkHeader * TransportHeader * Data Any of them could be empty, or zero-length. PiperOrigin-RevId: 326507688
This commit is contained in:
@@ -97,7 +97,7 @@ func (*TCPMatcher) Name() string {
|
||||
|
||||
// Match implements Matcher.Match.
|
||||
func (tm *TCPMatcher) Match(hook stack.Hook, pkt *stack.PacketBuffer, interfaceName string) (bool, bool) {
|
||||
netHeader := header.IPv4(pkt.NetworkHeader)
|
||||
netHeader := header.IPv4(pkt.NetworkHeader().View())
|
||||
|
||||
if netHeader.TransportProtocol() != header.TCPProtocolNumber {
|
||||
return false, false
|
||||
@@ -111,7 +111,7 @@ func (tm *TCPMatcher) Match(hook stack.Hook, pkt *stack.PacketBuffer, interfaceN
|
||||
return false, false
|
||||
}
|
||||
|
||||
tcpHeader := header.TCP(pkt.TransportHeader)
|
||||
tcpHeader := header.TCP(pkt.TransportHeader().View())
|
||||
if len(tcpHeader) < header.TCPMinimumSize {
|
||||
// There's no valid TCP header here, so we drop the packet immediately.
|
||||
return false, true
|
||||
|
||||
@@ -94,7 +94,7 @@ func (*UDPMatcher) Name() string {
|
||||
|
||||
// Match implements Matcher.Match.
|
||||
func (um *UDPMatcher) Match(hook stack.Hook, pkt *stack.PacketBuffer, interfaceName string) (bool, bool) {
|
||||
netHeader := header.IPv4(pkt.NetworkHeader)
|
||||
netHeader := header.IPv4(pkt.NetworkHeader().View())
|
||||
|
||||
// TODO(gvisor.dev/issue/170): Proto checks should ultimately be moved
|
||||
// into the stack.Check codepath as matchers are added.
|
||||
@@ -110,7 +110,7 @@ func (um *UDPMatcher) Match(hook stack.Hook, pkt *stack.PacketBuffer, interfaceN
|
||||
return false, false
|
||||
}
|
||||
|
||||
udpHeader := header.UDP(pkt.TransportHeader)
|
||||
udpHeader := header.UDP(pkt.TransportHeader().View())
|
||||
if len(udpHeader) < header.UDPMinimumSize {
|
||||
// There's no valid UDP header here, so we drop the packet immediately.
|
||||
return false, true
|
||||
|
||||
@@ -65,6 +65,16 @@ func (v View) ToVectorisedView() VectorisedView {
|
||||
return NewVectorisedView(len(v), []View{v})
|
||||
}
|
||||
|
||||
// IsEmpty returns whether v is of length zero.
|
||||
func (v View) IsEmpty() bool {
|
||||
return len(v) == 0
|
||||
}
|
||||
|
||||
// Size returns the length of v.
|
||||
func (v View) Size() int {
|
||||
return len(v)
|
||||
}
|
||||
|
||||
// VectorisedView is a vectorised version of View using non contiguous memory.
|
||||
// It supports all the convenience methods supported by View.
|
||||
//
|
||||
|
||||
@@ -274,7 +274,9 @@ func (e *Endpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.Packe
|
||||
// WriteRawPacket implements stack.LinkEndpoint.WriteRawPacket.
|
||||
func (e *Endpoint) WriteRawPacket(vv buffer.VectorisedView) *tcpip.Error {
|
||||
p := PacketInfo{
|
||||
Pkt: &stack.PacketBuffer{Data: vv},
|
||||
Pkt: stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: vv,
|
||||
}),
|
||||
Proto: 0,
|
||||
GSO: nil,
|
||||
}
|
||||
|
||||
@@ -37,5 +37,6 @@ go_test(
|
||||
"//pkg/tcpip/header",
|
||||
"//pkg/tcpip/link/rawfile",
|
||||
"//pkg/tcpip/stack",
|
||||
"@com_github_google_go_cmp//cmp:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -390,8 +390,7 @@ const (
|
||||
func (e *endpoint) AddHeader(local, remote tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) {
|
||||
if e.hdrSize > 0 {
|
||||
// Add ethernet header if needed.
|
||||
eth := header.Ethernet(pkt.Header.Prepend(header.EthernetMinimumSize))
|
||||
pkt.LinkHeader = buffer.View(eth)
|
||||
eth := header.Ethernet(pkt.LinkHeader().Push(header.EthernetMinimumSize))
|
||||
ethHdr := &header.EthernetFields{
|
||||
DstAddr: remote,
|
||||
Type: protocol,
|
||||
@@ -420,7 +419,7 @@ func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, protocol tcpip.Ne
|
||||
if e.Capabilities()&stack.CapabilityHardwareGSO != 0 {
|
||||
vnetHdr := virtioNetHdr{}
|
||||
if gso != nil {
|
||||
vnetHdr.hdrLen = uint16(pkt.Header.UsedLength())
|
||||
vnetHdr.hdrLen = uint16(pkt.HeaderSize())
|
||||
if gso.NeedsCsum {
|
||||
vnetHdr.flags = _VIRTIO_NET_HDR_F_NEEDS_CSUM
|
||||
vnetHdr.csumStart = header.EthernetMinimumSize + gso.L3HdrLen
|
||||
@@ -443,11 +442,9 @@ func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, protocol tcpip.Ne
|
||||
builder.Add(vnetHdrBuf)
|
||||
}
|
||||
|
||||
builder.Add(pkt.Header.View())
|
||||
for _, v := range pkt.Data.Views() {
|
||||
for _, v := range pkt.Views() {
|
||||
builder.Add(v)
|
||||
}
|
||||
|
||||
return rawfile.NonBlockingWriteIovec(fd, builder.Build())
|
||||
}
|
||||
|
||||
@@ -463,7 +460,7 @@ func (e *endpoint) sendBatch(batchFD int, batch []*stack.PacketBuffer) (int, *tc
|
||||
if e.Capabilities()&stack.CapabilityHardwareGSO != 0 {
|
||||
vnetHdr := virtioNetHdr{}
|
||||
if pkt.GSOOptions != nil {
|
||||
vnetHdr.hdrLen = uint16(pkt.Header.UsedLength())
|
||||
vnetHdr.hdrLen = uint16(pkt.HeaderSize())
|
||||
if pkt.GSOOptions.NeedsCsum {
|
||||
vnetHdr.flags = _VIRTIO_NET_HDR_F_NEEDS_CSUM
|
||||
vnetHdr.csumStart = header.EthernetMinimumSize + pkt.GSOOptions.L3HdrLen
|
||||
@@ -486,8 +483,7 @@ func (e *endpoint) sendBatch(batchFD int, batch []*stack.PacketBuffer) (int, *tc
|
||||
|
||||
var builder iovec.Builder
|
||||
builder.Add(vnetHdrBuf)
|
||||
builder.Add(pkt.Header.View())
|
||||
for _, v := range pkt.Data.Views() {
|
||||
for _, v := range pkt.Views() {
|
||||
builder.Add(v)
|
||||
}
|
||||
iovecs := builder.Build()
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
@@ -43,9 +44,36 @@ const (
|
||||
)
|
||||
|
||||
type packetInfo struct {
|
||||
raddr tcpip.LinkAddress
|
||||
proto tcpip.NetworkProtocolNumber
|
||||
contents *stack.PacketBuffer
|
||||
Raddr tcpip.LinkAddress
|
||||
Proto tcpip.NetworkProtocolNumber
|
||||
Contents *stack.PacketBuffer
|
||||
}
|
||||
|
||||
type packetContents struct {
|
||||
LinkHeader buffer.View
|
||||
NetworkHeader buffer.View
|
||||
TransportHeader buffer.View
|
||||
Data buffer.View
|
||||
}
|
||||
|
||||
func checkPacketInfoEqual(t *testing.T, got, want packetInfo) {
|
||||
t.Helper()
|
||||
if diff := cmp.Diff(
|
||||
want, got,
|
||||
cmp.Transformer("ExtractPacketBuffer", func(pk *stack.PacketBuffer) *packetContents {
|
||||
if pk == nil {
|
||||
return nil
|
||||
}
|
||||
return &packetContents{
|
||||
LinkHeader: pk.LinkHeader().View(),
|
||||
NetworkHeader: pk.NetworkHeader().View(),
|
||||
TransportHeader: pk.TransportHeader().View(),
|
||||
Data: pk.Data.ToView(),
|
||||
}
|
||||
}),
|
||||
); diff != "" {
|
||||
t.Errorf("unexpected packetInfo (-want +got):\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
type context struct {
|
||||
@@ -159,19 +187,28 @@ func testWritePacket(t *testing.T, plen int, eth bool, gsoMaxSize uint32, hash u
|
||||
RemoteLinkAddress: raddr,
|
||||
}
|
||||
|
||||
// Build header.
|
||||
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()) + 100)
|
||||
b := hdr.Prepend(100)
|
||||
for i := range b {
|
||||
b[i] = uint8(rand.Intn(256))
|
||||
// Build payload.
|
||||
payload := buffer.NewView(plen)
|
||||
if _, err := rand.Read(payload); err != nil {
|
||||
t.Fatalf("rand.Read(payload): %s", err)
|
||||
}
|
||||
|
||||
// Build payload and write.
|
||||
payload := make(buffer.View, plen)
|
||||
for i := range payload {
|
||||
payload[i] = uint8(rand.Intn(256))
|
||||
// Build packet buffer.
|
||||
const netHdrLen = 100
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(c.ep.MaxHeaderLength()) + netHdrLen,
|
||||
Data: payload.ToVectorisedView(),
|
||||
})
|
||||
pkt.Hash = hash
|
||||
|
||||
// Build header.
|
||||
b := pkt.NetworkHeader().Push(netHdrLen)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
t.Fatalf("rand.Read(b): %s", err)
|
||||
}
|
||||
want := append(hdr.View(), payload...)
|
||||
|
||||
// Write.
|
||||
want := append(append(buffer.View(nil), b...), payload...)
|
||||
var gso *stack.GSO
|
||||
if gsoMaxSize != 0 {
|
||||
gso = &stack.GSO{
|
||||
@@ -183,11 +220,7 @@ func testWritePacket(t *testing.T, plen int, eth bool, gsoMaxSize uint32, hash u
|
||||
L3HdrLen: header.IPv4MaximumHeaderSize,
|
||||
}
|
||||
}
|
||||
if err := c.ep.WritePacket(r, gso, proto, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
Data: payload.ToVectorisedView(),
|
||||
Hash: hash,
|
||||
}); err != nil {
|
||||
if err := c.ep.WritePacket(r, gso, proto, pkt); err != nil {
|
||||
t.Fatalf("WritePacket failed: %v", err)
|
||||
}
|
||||
|
||||
@@ -296,13 +329,14 @@ func TestPreserveSrcAddress(t *testing.T) {
|
||||
LocalLinkAddress: baddr,
|
||||
}
|
||||
|
||||
// WritePacket panics given a prependable with anything less than
|
||||
// the minimum size of the ethernet header.
|
||||
hdr := buffer.NewPrependable(header.EthernetMinimumSize)
|
||||
if err := c.ep.WritePacket(r, nil /* gso */, proto, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
Data: buffer.VectorisedView{},
|
||||
}); err != nil {
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
// WritePacket panics given a prependable with anything less than
|
||||
// the minimum size of the ethernet header.
|
||||
// TODO(b/153685824): Figure out if this should use c.ep.MaxHeaderLength().
|
||||
ReserveHeaderBytes: header.EthernetMinimumSize,
|
||||
Data: buffer.VectorisedView{},
|
||||
})
|
||||
if err := c.ep.WritePacket(r, nil /* gso */, proto, pkt); err != nil {
|
||||
t.Fatalf("WritePacket failed: %v", err)
|
||||
}
|
||||
|
||||
@@ -331,24 +365,25 @@ func TestDeliverPacket(t *testing.T) {
|
||||
defer c.cleanup()
|
||||
|
||||
// Build packet.
|
||||
b := make([]byte, plen)
|
||||
all := b
|
||||
for i := range b {
|
||||
b[i] = uint8(rand.Intn(256))
|
||||
all := make([]byte, plen)
|
||||
if _, err := rand.Read(all); err != nil {
|
||||
t.Fatalf("rand.Read(all): %s", err)
|
||||
}
|
||||
// Make it look like an IPv4 packet.
|
||||
all[0] = 0x40
|
||||
|
||||
var hdr header.Ethernet
|
||||
if !eth {
|
||||
// So that it looks like an IPv4 packet.
|
||||
b[0] = 0x40
|
||||
} else {
|
||||
hdr = make(header.Ethernet, header.EthernetMinimumSize)
|
||||
wantPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: header.EthernetMinimumSize,
|
||||
Data: buffer.NewViewFromBytes(all).ToVectorisedView(),
|
||||
})
|
||||
if eth {
|
||||
hdr := header.Ethernet(wantPkt.LinkHeader().Push(header.EthernetMinimumSize))
|
||||
hdr.Encode(&header.EthernetFields{
|
||||
SrcAddr: raddr,
|
||||
DstAddr: laddr,
|
||||
Type: proto,
|
||||
})
|
||||
all = append(hdr, b...)
|
||||
all = append(hdr, all...)
|
||||
}
|
||||
|
||||
// Write packet via the file descriptor.
|
||||
@@ -360,24 +395,15 @@ func TestDeliverPacket(t *testing.T) {
|
||||
select {
|
||||
case pi := <-c.ch:
|
||||
want := packetInfo{
|
||||
raddr: raddr,
|
||||
proto: proto,
|
||||
contents: &stack.PacketBuffer{
|
||||
Data: buffer.View(b).ToVectorisedView(),
|
||||
LinkHeader: buffer.View(hdr),
|
||||
},
|
||||
Raddr: raddr,
|
||||
Proto: proto,
|
||||
Contents: wantPkt,
|
||||
}
|
||||
if !eth {
|
||||
want.proto = header.IPv4ProtocolNumber
|
||||
want.raddr = ""
|
||||
}
|
||||
// want.contents.Data will be a single
|
||||
// view, so make pi do the same for the
|
||||
// DeepEqual check.
|
||||
pi.contents.Data = pi.contents.Data.ToView().ToVectorisedView()
|
||||
if !reflect.DeepEqual(want, pi) {
|
||||
t.Fatalf("Unexpected received packet: %+v, want %+v", pi, want)
|
||||
want.Proto = header.IPv4ProtocolNumber
|
||||
want.Raddr = ""
|
||||
}
|
||||
checkPacketInfoEqual(t, pi, want)
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatalf("Timed out waiting for packet")
|
||||
}
|
||||
@@ -572,8 +598,8 @@ func TestDispatchPacketFormat(t *testing.T) {
|
||||
t.Fatalf("len(sink.pkts) = %d, want %d", got, want)
|
||||
}
|
||||
pkt := sink.pkts[0]
|
||||
if got, want := len(pkt.LinkHeader), header.EthernetMinimumSize; got != want {
|
||||
t.Errorf("len(pkt.LinkHeader) = %d, want %d", got, want)
|
||||
if got, want := pkt.LinkHeader().View().Size(), header.EthernetMinimumSize; got != want {
|
||||
t.Errorf("pkt.LinkHeader().View().Size() = %d, want %d", got, want)
|
||||
}
|
||||
if got, want := pkt.Data.Size(), 4; got != want {
|
||||
t.Errorf("pkt.Data.Size() = %d, want %d", got, want)
|
||||
|
||||
@@ -18,6 +18,7 @@ package fdbased
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
@@ -170,10 +171,9 @@ func (d *packetMMapDispatcher) dispatch() (bool, *tcpip.Error) {
|
||||
var (
|
||||
p tcpip.NetworkProtocolNumber
|
||||
remote, local tcpip.LinkAddress
|
||||
eth header.Ethernet
|
||||
)
|
||||
if d.e.hdrSize > 0 {
|
||||
eth = header.Ethernet(pkt)
|
||||
eth := header.Ethernet(pkt)
|
||||
p = eth.Type()
|
||||
remote = eth.SourceAddress()
|
||||
local = eth.DestinationAddress()
|
||||
@@ -190,10 +190,14 @@ func (d *packetMMapDispatcher) dispatch() (bool, *tcpip.Error) {
|
||||
}
|
||||
}
|
||||
|
||||
pkt = pkt[d.e.hdrSize:]
|
||||
d.e.dispatcher.DeliverNetworkPacket(remote, local, p, &stack.PacketBuffer{
|
||||
Data: buffer.View(pkt).ToVectorisedView(),
|
||||
LinkHeader: buffer.View(eth),
|
||||
pbuf := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: buffer.View(pkt).ToVectorisedView(),
|
||||
})
|
||||
if d.e.hdrSize > 0 {
|
||||
if _, ok := pbuf.LinkHeader().Consume(d.e.hdrSize); !ok {
|
||||
panic(fmt.Sprintf("LinkHeader().Consume(%d) must succeed", d.e.hdrSize))
|
||||
}
|
||||
}
|
||||
d.e.dispatcher.DeliverNetworkPacket(remote, local, p, pbuf)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ func (d *readVDispatcher) dispatch() (bool, *tcpip.Error) {
|
||||
d.allocateViews(BufConfig)
|
||||
|
||||
n, err := rawfile.BlockingReadv(d.fd, d.iovecs)
|
||||
if err != nil {
|
||||
if n == 0 || err != nil {
|
||||
return false, err
|
||||
}
|
||||
if d.e.Capabilities()&stack.CapabilityHardwareGSO != 0 {
|
||||
@@ -111,17 +111,22 @@ func (d *readVDispatcher) dispatch() (bool, *tcpip.Error) {
|
||||
// isn't used and it isn't in a view.
|
||||
n -= virtioNetHdrSize
|
||||
}
|
||||
if n <= d.e.hdrSize {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
used := d.capViews(n, BufConfig)
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: buffer.NewVectorisedView(n, append([]buffer.View(nil), d.views[:used]...)),
|
||||
})
|
||||
|
||||
var (
|
||||
p tcpip.NetworkProtocolNumber
|
||||
remote, local tcpip.LinkAddress
|
||||
eth header.Ethernet
|
||||
)
|
||||
if d.e.hdrSize > 0 {
|
||||
eth = header.Ethernet(d.views[0][:header.EthernetMinimumSize])
|
||||
hdr, ok := pkt.LinkHeader().Consume(d.e.hdrSize)
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
eth := header.Ethernet(hdr)
|
||||
p = eth.Type()
|
||||
remote = eth.SourceAddress()
|
||||
local = eth.DestinationAddress()
|
||||
@@ -138,13 +143,6 @@ func (d *readVDispatcher) dispatch() (bool, *tcpip.Error) {
|
||||
}
|
||||
}
|
||||
|
||||
used := d.capViews(n, BufConfig)
|
||||
pkt := &stack.PacketBuffer{
|
||||
Data: buffer.NewVectorisedView(n, append([]buffer.View(nil), d.views[:used]...)),
|
||||
LinkHeader: buffer.View(eth),
|
||||
}
|
||||
pkt.Data.TrimFront(d.e.hdrSize)
|
||||
|
||||
d.e.dispatcher.DeliverNetworkPacket(remote, local, p, pkt)
|
||||
|
||||
// Prepare e.views for another packet: release used views.
|
||||
@@ -268,17 +266,22 @@ func (d *recvMMsgDispatcher) dispatch() (bool, *tcpip.Error) {
|
||||
if d.e.Capabilities()&stack.CapabilityHardwareGSO != 0 {
|
||||
n -= virtioNetHdrSize
|
||||
}
|
||||
if n <= d.e.hdrSize {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
used := d.capViews(k, int(n), BufConfig)
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: buffer.NewVectorisedView(int(n), append([]buffer.View(nil), d.views[k][:used]...)),
|
||||
})
|
||||
|
||||
var (
|
||||
p tcpip.NetworkProtocolNumber
|
||||
remote, local tcpip.LinkAddress
|
||||
eth header.Ethernet
|
||||
)
|
||||
if d.e.hdrSize > 0 {
|
||||
eth = header.Ethernet(d.views[k][0][:header.EthernetMinimumSize])
|
||||
hdr, ok := pkt.LinkHeader().Consume(d.e.hdrSize)
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
eth := header.Ethernet(hdr)
|
||||
p = eth.Type()
|
||||
remote = eth.SourceAddress()
|
||||
local = eth.DestinationAddress()
|
||||
@@ -295,12 +298,6 @@ func (d *recvMMsgDispatcher) dispatch() (bool, *tcpip.Error) {
|
||||
}
|
||||
}
|
||||
|
||||
used := d.capViews(k, int(n), BufConfig)
|
||||
pkt := &stack.PacketBuffer{
|
||||
Data: buffer.NewVectorisedView(int(n), append([]buffer.View(nil), d.views[k][:used]...)),
|
||||
LinkHeader: buffer.View(eth),
|
||||
}
|
||||
pkt.Data.TrimFront(d.e.hdrSize)
|
||||
d.e.dispatcher.DeliverNetworkPacket(remote, local, p, pkt)
|
||||
|
||||
// Prepare e.views for another packet: release used views.
|
||||
|
||||
@@ -77,16 +77,16 @@ func (*endpoint) Wait() {}
|
||||
// WritePacket implements stack.LinkEndpoint.WritePacket. It delivers outbound
|
||||
// packets to the network-layer dispatcher.
|
||||
func (e *endpoint) WritePacket(_ *stack.Route, _ *stack.GSO, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
views := make([]buffer.View, 1, 1+len(pkt.Data.Views()))
|
||||
views[0] = pkt.Header.View()
|
||||
views = append(views, pkt.Data.Views()...)
|
||||
// Construct data as the unparsed portion for the loopback packet.
|
||||
data := buffer.NewVectorisedView(pkt.Size(), pkt.Views())
|
||||
|
||||
// Because we're immediately turning around and writing the packet back
|
||||
// to the rx path, we intentionally don't preserve the remote and local
|
||||
// link addresses from the stack.Route we're passed.
|
||||
e.dispatcher.DeliverNetworkPacket("" /* remote */, "" /* local */, protocol, &stack.PacketBuffer{
|
||||
Data: buffer.NewVectorisedView(len(views[0])+pkt.Data.Size(), views),
|
||||
newPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: data,
|
||||
})
|
||||
e.dispatcher.DeliverNetworkPacket("" /* remote */, "" /* local */, protocol, newPkt)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -98,18 +98,17 @@ func (e *endpoint) WritePackets(*stack.Route, *stack.GSO, stack.PacketBufferList
|
||||
|
||||
// WriteRawPacket implements stack.LinkEndpoint.WriteRawPacket.
|
||||
func (e *endpoint) WriteRawPacket(vv buffer.VectorisedView) *tcpip.Error {
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: vv,
|
||||
})
|
||||
// There should be an ethernet header at the beginning of vv.
|
||||
hdr, ok := vv.PullUp(header.EthernetMinimumSize)
|
||||
hdr, ok := pkt.LinkHeader().Consume(header.EthernetMinimumSize)
|
||||
if !ok {
|
||||
// Reject the packet if it's shorter than an ethernet header.
|
||||
return tcpip.ErrBadAddress
|
||||
}
|
||||
linkHeader := header.Ethernet(hdr)
|
||||
vv.TrimFront(len(linkHeader))
|
||||
e.dispatcher.DeliverNetworkPacket("" /* remote */, "" /* local */, linkHeader.Type(), &stack.PacketBuffer{
|
||||
Data: vv,
|
||||
LinkHeader: buffer.View(linkHeader),
|
||||
})
|
||||
e.dispatcher.DeliverNetworkPacket("" /* remote */, "" /* local */, linkHeader.Type(), pkt)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -46,14 +46,14 @@ func TestInjectableEndpointRawDispatch(t *testing.T) {
|
||||
func TestInjectableEndpointDispatch(t *testing.T) {
|
||||
endpoint, sock, dstIP := makeTestInjectableEndpoint(t)
|
||||
|
||||
hdr := buffer.NewPrependable(1)
|
||||
hdr.Prepend(1)[0] = 0xFA
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: 1,
|
||||
Data: buffer.NewViewFromBytes([]byte{0xFB}).ToVectorisedView(),
|
||||
})
|
||||
pkt.TransportHeader().Push(1)[0] = 0xFA
|
||||
packetRoute := stack.Route{RemoteAddress: dstIP}
|
||||
|
||||
endpoint.WritePacket(&packetRoute, nil /* gso */, ipv4.ProtocolNumber, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
Data: buffer.NewViewFromBytes([]byte{0xFB}).ToVectorisedView(),
|
||||
})
|
||||
endpoint.WritePacket(&packetRoute, nil /* gso */, ipv4.ProtocolNumber, pkt)
|
||||
|
||||
buf := make([]byte, 6500)
|
||||
bytesRead, err := sock.Read(buf)
|
||||
@@ -67,13 +67,14 @@ func TestInjectableEndpointDispatch(t *testing.T) {
|
||||
|
||||
func TestInjectableEndpointDispatchHdrOnly(t *testing.T) {
|
||||
endpoint, sock, dstIP := makeTestInjectableEndpoint(t)
|
||||
hdr := buffer.NewPrependable(1)
|
||||
hdr.Prepend(1)[0] = 0xFA
|
||||
packetRoute := stack.Route{RemoteAddress: dstIP}
|
||||
endpoint.WritePacket(&packetRoute, nil /* gso */, ipv4.ProtocolNumber, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
Data: buffer.NewView(0).ToVectorisedView(),
|
||||
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: 1,
|
||||
Data: buffer.NewView(0).ToVectorisedView(),
|
||||
})
|
||||
pkt.TransportHeader().Push(1)[0] = 0xFA
|
||||
packetRoute := stack.Route{RemoteAddress: dstIP}
|
||||
endpoint.WritePacket(&packetRoute, nil /* gso */, ipv4.ProtocolNumber, pkt)
|
||||
buf := make([]byte, 6500)
|
||||
bytesRead, err := sock.Read(buf)
|
||||
if err != nil {
|
||||
|
||||
@@ -87,7 +87,7 @@ func TestNestedLinkEndpoint(t *testing.T) {
|
||||
t.Error("After attach, nestedEP.IsAttached() = false, want = true")
|
||||
}
|
||||
|
||||
nestedEP.DeliverNetworkPacket(emptyAddress, emptyAddress, header.IPv4ProtocolNumber, &stack.PacketBuffer{})
|
||||
nestedEP.DeliverNetworkPacket(emptyAddress, emptyAddress, header.IPv4ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{}))
|
||||
if disp.count != 1 {
|
||||
t.Errorf("After first packet with dispatcher attached, got disp.count = %d, want = 1", disp.count)
|
||||
}
|
||||
@@ -101,7 +101,7 @@ func TestNestedLinkEndpoint(t *testing.T) {
|
||||
}
|
||||
|
||||
disp.count = 0
|
||||
nestedEP.DeliverNetworkPacket(emptyAddress, emptyAddress, header.IPv4ProtocolNumber, &stack.PacketBuffer{})
|
||||
nestedEP.DeliverNetworkPacket(emptyAddress, emptyAddress, header.IPv4ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{}))
|
||||
if disp.count != 0 {
|
||||
t.Errorf("After second packet with dispatcher detached, got disp.count = %d, want = 0", disp.count)
|
||||
}
|
||||
|
||||
@@ -186,8 +186,7 @@ func (e *endpoint) LinkAddress() tcpip.LinkAddress {
|
||||
// AddHeader implements stack.LinkEndpoint.AddHeader.
|
||||
func (e *endpoint) AddHeader(local, remote tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) {
|
||||
// Add ethernet header if needed.
|
||||
eth := header.Ethernet(pkt.Header.Prepend(header.EthernetMinimumSize))
|
||||
pkt.LinkHeader = buffer.View(eth)
|
||||
eth := header.Ethernet(pkt.LinkHeader().Push(header.EthernetMinimumSize))
|
||||
ethHdr := &header.EthernetFields{
|
||||
DstAddr: remote,
|
||||
Type: protocol,
|
||||
@@ -207,10 +206,10 @@ func (e *endpoint) AddHeader(local, remote tcpip.LinkAddress, protocol tcpip.Net
|
||||
func (e *endpoint) WritePacket(r *stack.Route, _ *stack.GSO, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) *tcpip.Error {
|
||||
e.AddHeader(r.LocalLinkAddress, r.RemoteLinkAddress, protocol, pkt)
|
||||
|
||||
v := pkt.Data.ToView()
|
||||
views := pkt.Views()
|
||||
// Transmit the packet.
|
||||
e.mu.Lock()
|
||||
ok := e.tx.transmit(pkt.Header.View(), v)
|
||||
ok := e.tx.transmit(views...)
|
||||
e.mu.Unlock()
|
||||
|
||||
if !ok {
|
||||
@@ -227,10 +226,10 @@ func (e *endpoint) WritePackets(r *stack.Route, _ *stack.GSO, pkts stack.PacketB
|
||||
|
||||
// WriteRawPacket implements stack.LinkEndpoint.WriteRawPacket.
|
||||
func (e *endpoint) WriteRawPacket(vv buffer.VectorisedView) *tcpip.Error {
|
||||
v := vv.ToView()
|
||||
views := vv.Views()
|
||||
// Transmit the packet.
|
||||
e.mu.Lock()
|
||||
ok := e.tx.transmit(v, buffer.View{})
|
||||
ok := e.tx.transmit(views...)
|
||||
e.mu.Unlock()
|
||||
|
||||
if !ok {
|
||||
@@ -276,16 +275,18 @@ func (e *endpoint) dispatchLoop(d stack.NetworkDispatcher) {
|
||||
rxb[i].Size = e.bufferSize
|
||||
}
|
||||
|
||||
if n < header.EthernetMinimumSize {
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: buffer.View(b).ToVectorisedView(),
|
||||
})
|
||||
|
||||
hdr, ok := pkt.LinkHeader().Consume(header.EthernetMinimumSize)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
eth := header.Ethernet(hdr)
|
||||
|
||||
// Send packet up the stack.
|
||||
eth := header.Ethernet(b[:header.EthernetMinimumSize])
|
||||
d.DeliverNetworkPacket(eth.SourceAddress(), eth.DestinationAddress(), eth.Type(), &stack.PacketBuffer{
|
||||
Data: buffer.View(b[header.EthernetMinimumSize:]).ToVectorisedView(),
|
||||
LinkHeader: buffer.View(eth),
|
||||
})
|
||||
d.DeliverNetworkPacket(eth.SourceAddress(), eth.DestinationAddress(), eth.Type(), pkt)
|
||||
}
|
||||
|
||||
// Clean state.
|
||||
|
||||
@@ -266,21 +266,23 @@ func TestSimpleSend(t *testing.T) {
|
||||
|
||||
for iters := 1000; iters > 0; iters-- {
|
||||
func() {
|
||||
hdrLen, dataLen := rand.Intn(10000), rand.Intn(10000)
|
||||
|
||||
// Prepare and send packet.
|
||||
n := rand.Intn(10000)
|
||||
hdr := buffer.NewPrependable(n + int(c.ep.MaxHeaderLength()))
|
||||
hdrBuf := hdr.Prepend(n)
|
||||
hdrBuf := buffer.NewView(hdrLen)
|
||||
randomFill(hdrBuf)
|
||||
|
||||
n = rand.Intn(10000)
|
||||
buf := buffer.NewView(n)
|
||||
randomFill(buf)
|
||||
data := buffer.NewView(dataLen)
|
||||
randomFill(data)
|
||||
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: hdrLen + int(c.ep.MaxHeaderLength()),
|
||||
Data: data.ToVectorisedView(),
|
||||
})
|
||||
copy(pkt.NetworkHeader().Push(hdrLen), hdrBuf)
|
||||
|
||||
proto := tcpip.NetworkProtocolNumber(rand.Intn(0x10000))
|
||||
if err := c.ep.WritePacket(&r, nil /* gso */, proto, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
Data: buf.ToVectorisedView(),
|
||||
}); err != nil {
|
||||
if err := c.ep.WritePacket(&r, nil /* gso */, proto, pkt); err != nil {
|
||||
t.Fatalf("WritePacket failed: %v", err)
|
||||
}
|
||||
|
||||
@@ -317,7 +319,7 @@ func TestSimpleSend(t *testing.T) {
|
||||
|
||||
// Compare contents skipping the ethernet header added by the
|
||||
// endpoint.
|
||||
merged := append(hdrBuf, buf...)
|
||||
merged := append(hdrBuf, data...)
|
||||
if uint32(len(contents)) < pi.Size {
|
||||
t.Fatalf("Sum of buffers is less than packet size: %v < %v", len(contents), pi.Size)
|
||||
}
|
||||
@@ -344,14 +346,14 @@ func TestPreserveSrcAddressInSend(t *testing.T) {
|
||||
LocalLinkAddress: newLocalLinkAddress,
|
||||
}
|
||||
|
||||
// WritePacket panics given a prependable with anything less than
|
||||
// the minimum size of the ethernet header.
|
||||
hdr := buffer.NewPrependable(header.EthernetMinimumSize)
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
// WritePacket panics given a prependable with anything less than
|
||||
// the minimum size of the ethernet header.
|
||||
ReserveHeaderBytes: header.EthernetMinimumSize,
|
||||
})
|
||||
|
||||
proto := tcpip.NetworkProtocolNumber(rand.Intn(0x10000))
|
||||
if err := c.ep.WritePacket(&r, nil /* gso */, proto, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
}); err != nil {
|
||||
if err := c.ep.WritePacket(&r, nil /* gso */, proto, pkt); err != nil {
|
||||
t.Fatalf("WritePacket failed: %v", err)
|
||||
}
|
||||
|
||||
@@ -403,12 +405,12 @@ func TestFillTxQueue(t *testing.T) {
|
||||
// until the tx queue if full.
|
||||
ids := make(map[uint64]struct{})
|
||||
for i := queuePipeSize / 40; i > 0; i-- {
|
||||
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(c.ep.MaxHeaderLength()),
|
||||
Data: buf.ToVectorisedView(),
|
||||
})
|
||||
|
||||
if err := c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
Data: buf.ToVectorisedView(),
|
||||
}); err != nil {
|
||||
if err := c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, pkt); err != nil {
|
||||
t.Fatalf("WritePacket failed unexpectedly: %v", err)
|
||||
}
|
||||
|
||||
@@ -422,11 +424,11 @@ func TestFillTxQueue(t *testing.T) {
|
||||
}
|
||||
|
||||
// Next attempt to write must fail.
|
||||
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
|
||||
if want, err := tcpip.ErrWouldBlock, c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
Data: buf.ToVectorisedView(),
|
||||
}); err != want {
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(c.ep.MaxHeaderLength()),
|
||||
Data: buf.ToVectorisedView(),
|
||||
})
|
||||
if want, err := tcpip.ErrWouldBlock, c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, pkt); err != want {
|
||||
t.Fatalf("WritePacket return unexpected result: got %v, want %v", err, want)
|
||||
}
|
||||
}
|
||||
@@ -450,11 +452,11 @@ func TestFillTxQueueAfterBadCompletion(t *testing.T) {
|
||||
|
||||
// Send two packets so that the id slice has at least two slots.
|
||||
for i := 2; i > 0; i-- {
|
||||
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
|
||||
if err := c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
Data: buf.ToVectorisedView(),
|
||||
}); err != nil {
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(c.ep.MaxHeaderLength()),
|
||||
Data: buf.ToVectorisedView(),
|
||||
})
|
||||
if err := c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, pkt); err != nil {
|
||||
t.Fatalf("WritePacket failed unexpectedly: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -473,11 +475,11 @@ func TestFillTxQueueAfterBadCompletion(t *testing.T) {
|
||||
// until the tx queue if full.
|
||||
ids := make(map[uint64]struct{})
|
||||
for i := queuePipeSize / 40; i > 0; i-- {
|
||||
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
|
||||
if err := c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
Data: buf.ToVectorisedView(),
|
||||
}); err != nil {
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(c.ep.MaxHeaderLength()),
|
||||
Data: buf.ToVectorisedView(),
|
||||
})
|
||||
if err := c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, pkt); err != nil {
|
||||
t.Fatalf("WritePacket failed unexpectedly: %v", err)
|
||||
}
|
||||
|
||||
@@ -491,11 +493,11 @@ func TestFillTxQueueAfterBadCompletion(t *testing.T) {
|
||||
}
|
||||
|
||||
// Next attempt to write must fail.
|
||||
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
|
||||
if want, err := tcpip.ErrWouldBlock, c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
Data: buf.ToVectorisedView(),
|
||||
}); err != want {
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(c.ep.MaxHeaderLength()),
|
||||
Data: buf.ToVectorisedView(),
|
||||
})
|
||||
if want, err := tcpip.ErrWouldBlock, c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, pkt); err != want {
|
||||
t.Fatalf("WritePacket return unexpected result: got %v, want %v", err, want)
|
||||
}
|
||||
}
|
||||
@@ -517,11 +519,11 @@ func TestFillTxMemory(t *testing.T) {
|
||||
// we fill the memory.
|
||||
ids := make(map[uint64]struct{})
|
||||
for i := queueDataSize / bufferSize; i > 0; i-- {
|
||||
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
|
||||
if err := c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
Data: buf.ToVectorisedView(),
|
||||
}); err != nil {
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(c.ep.MaxHeaderLength()),
|
||||
Data: buf.ToVectorisedView(),
|
||||
})
|
||||
if err := c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, pkt); err != nil {
|
||||
t.Fatalf("WritePacket failed unexpectedly: %v", err)
|
||||
}
|
||||
|
||||
@@ -536,11 +538,11 @@ func TestFillTxMemory(t *testing.T) {
|
||||
}
|
||||
|
||||
// Next attempt to write must fail.
|
||||
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
|
||||
err := c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
Data: buf.ToVectorisedView(),
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(c.ep.MaxHeaderLength()),
|
||||
Data: buf.ToVectorisedView(),
|
||||
})
|
||||
err := c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, pkt)
|
||||
if want := tcpip.ErrWouldBlock; err != want {
|
||||
t.Fatalf("WritePacket return unexpected result: got %v, want %v", err, want)
|
||||
}
|
||||
@@ -564,11 +566,11 @@ func TestFillTxMemoryWithMultiBuffer(t *testing.T) {
|
||||
// Each packet is uses up one buffer, so write as many as possible
|
||||
// until there is only one buffer left.
|
||||
for i := queueDataSize/bufferSize - 1; i > 0; i-- {
|
||||
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
|
||||
if err := c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
Data: buf.ToVectorisedView(),
|
||||
}); err != nil {
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(c.ep.MaxHeaderLength()),
|
||||
Data: buf.ToVectorisedView(),
|
||||
})
|
||||
if err := c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, pkt); err != nil {
|
||||
t.Fatalf("WritePacket failed unexpectedly: %v", err)
|
||||
}
|
||||
|
||||
@@ -579,23 +581,22 @@ func TestFillTxMemoryWithMultiBuffer(t *testing.T) {
|
||||
|
||||
// Attempt to write a two-buffer packet. It must fail.
|
||||
{
|
||||
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
|
||||
uu := buffer.NewView(bufferSize).ToVectorisedView()
|
||||
if want, err := tcpip.ErrWouldBlock, c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
Data: uu,
|
||||
}); err != want {
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(c.ep.MaxHeaderLength()),
|
||||
Data: buffer.NewView(bufferSize).ToVectorisedView(),
|
||||
})
|
||||
if want, err := tcpip.ErrWouldBlock, c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, pkt); err != want {
|
||||
t.Fatalf("WritePacket return unexpected result: got %v, want %v", err, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to write the one-buffer packet again. It must succeed.
|
||||
{
|
||||
hdr := buffer.NewPrependable(int(c.ep.MaxHeaderLength()))
|
||||
if err := c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
Data: buf.ToVectorisedView(),
|
||||
}); err != nil {
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(c.ep.MaxHeaderLength()),
|
||||
Data: buf.ToVectorisedView(),
|
||||
})
|
||||
if err := c.ep.WritePacket(&r, nil /* gso */, header.IPv4ProtocolNumber, pkt); err != nil {
|
||||
t.Fatalf("WritePacket failed unexpectedly: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"math"
|
||||
"syscall"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/link/sharedmem/queue"
|
||||
)
|
||||
|
||||
@@ -76,9 +77,9 @@ func (t *tx) cleanup() {
|
||||
syscall.Munmap(t.data)
|
||||
}
|
||||
|
||||
// transmit sends a packet made up of up to two buffers. Returns a boolean that
|
||||
// specifies whether the packet was successfully transmitted.
|
||||
func (t *tx) transmit(a, b []byte) bool {
|
||||
// transmit sends a packet made of bufs. Returns a boolean that specifies
|
||||
// whether the packet was successfully transmitted.
|
||||
func (t *tx) transmit(bufs ...buffer.View) bool {
|
||||
// Pull completions from the tx queue and add their buffers back to the
|
||||
// pool so that we can reuse them.
|
||||
for {
|
||||
@@ -93,7 +94,10 @@ func (t *tx) transmit(a, b []byte) bool {
|
||||
}
|
||||
|
||||
bSize := t.bufs.entrySize
|
||||
total := uint32(len(a) + len(b))
|
||||
total := uint32(0)
|
||||
for _, data := range bufs {
|
||||
total += uint32(len(data))
|
||||
}
|
||||
bufCount := (total + bSize - 1) / bSize
|
||||
|
||||
// Allocate enough buffers to hold all the data.
|
||||
@@ -115,7 +119,7 @@ func (t *tx) transmit(a, b []byte) bool {
|
||||
// Copy data into allocated buffers.
|
||||
nBuf := buf
|
||||
var dBuf []byte
|
||||
for _, data := range [][]byte{a, b} {
|
||||
for _, data := range bufs {
|
||||
for len(data) > 0 {
|
||||
if len(dBuf) == 0 {
|
||||
dBuf = t.data[nBuf.Offset:][:nBuf.Size]
|
||||
|
||||
@@ -134,7 +134,7 @@ func (e *endpoint) dumpPacket(prefix string, gso *stack.GSO, protocol tcpip.Netw
|
||||
logPacket(prefix, protocol, pkt, gso)
|
||||
}
|
||||
if writer != nil && atomic.LoadUint32(&LogPacketsToPCAP) == 1 {
|
||||
totalLength := pkt.Header.UsedLength() + pkt.Data.Size()
|
||||
totalLength := pkt.Size()
|
||||
length := totalLength
|
||||
if max := int(e.maxPCAPLen); length > max {
|
||||
length = max
|
||||
@@ -155,12 +155,11 @@ func (e *endpoint) dumpPacket(prefix string, gso *stack.GSO, protocol tcpip.Netw
|
||||
length -= n
|
||||
}
|
||||
}
|
||||
write(pkt.Header.View())
|
||||
for _, view := range pkt.Data.Views() {
|
||||
for _, v := range pkt.Views() {
|
||||
if length == 0 {
|
||||
break
|
||||
}
|
||||
write(view)
|
||||
write(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,9 +184,9 @@ func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.Packe
|
||||
|
||||
// WriteRawPacket implements stack.LinkEndpoint.WriteRawPacket.
|
||||
func (e *endpoint) WriteRawPacket(vv buffer.VectorisedView) *tcpip.Error {
|
||||
e.dumpPacket("send", nil, 0, &stack.PacketBuffer{
|
||||
e.dumpPacket("send", nil, 0, stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: vv,
|
||||
})
|
||||
}))
|
||||
return e.Endpoint.WriteRawPacket(vv)
|
||||
}
|
||||
|
||||
@@ -201,12 +200,8 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, pkt *stack.P
|
||||
var fragmentOffset uint16
|
||||
var moreFragments bool
|
||||
|
||||
// Create a clone of pkt, including any headers if present. Avoid allocating
|
||||
// backing memory for the clone.
|
||||
views := [8]buffer.View{}
|
||||
vv := buffer.NewVectorisedView(0, views[:0])
|
||||
vv.AppendView(pkt.Header.View())
|
||||
vv.Append(pkt.Data)
|
||||
// Examine the packet using a new VV. Backing storage must not be written.
|
||||
vv := buffer.NewVectorisedView(pkt.Size(), pkt.Views())
|
||||
|
||||
switch protocol {
|
||||
case header.IPv4ProtocolNumber:
|
||||
|
||||
@@ -215,12 +215,11 @@ func (d *Device) Write(data []byte) (int64, error) {
|
||||
remote = tcpip.LinkAddress(zeroMAC[:])
|
||||
}
|
||||
|
||||
pkt := &stack.PacketBuffer{
|
||||
Data: buffer.View(data).ToVectorisedView(),
|
||||
}
|
||||
if ethHdr != nil {
|
||||
pkt.LinkHeader = buffer.View(ethHdr)
|
||||
}
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: len(ethHdr),
|
||||
Data: buffer.View(data).ToVectorisedView(),
|
||||
})
|
||||
copy(pkt.LinkHeader().Push(len(ethHdr)), ethHdr)
|
||||
endpoint.InjectLinkAddr(protocol, remote, pkt)
|
||||
return dataLen, nil
|
||||
}
|
||||
@@ -265,21 +264,22 @@ func (d *Device) encodePkt(info *channel.PacketInfo) (buffer.View, bool) {
|
||||
// If the packet does not already have link layer header, and the route
|
||||
// does not exist, we can't compute it. This is possibly a raw packet, tun
|
||||
// device doesn't support this at the moment.
|
||||
if info.Pkt.LinkHeader == nil && info.Route.RemoteLinkAddress == "" {
|
||||
if info.Pkt.LinkHeader().View().IsEmpty() && info.Route.RemoteLinkAddress == "" {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Ethernet header (TAP only).
|
||||
if d.hasFlags(linux.IFF_TAP) {
|
||||
// Add ethernet header if not provided.
|
||||
if info.Pkt.LinkHeader == nil {
|
||||
if info.Pkt.LinkHeader().View().IsEmpty() {
|
||||
d.endpoint.AddHeader(info.Route.LocalLinkAddress, info.Route.RemoteLinkAddress, info.Proto, info.Pkt)
|
||||
}
|
||||
vv.AppendView(info.Pkt.LinkHeader)
|
||||
vv.AppendView(info.Pkt.LinkHeader().View())
|
||||
}
|
||||
|
||||
// Append upper headers.
|
||||
vv.AppendView(buffer.View(info.Pkt.Header.View()[len(info.Pkt.LinkHeader):]))
|
||||
vv.AppendView(info.Pkt.NetworkHeader().View())
|
||||
vv.AppendView(info.Pkt.TransportHeader().View())
|
||||
// Append data payload.
|
||||
vv.Append(info.Pkt.Data)
|
||||
|
||||
@@ -361,8 +361,7 @@ func (e *tunEndpoint) AddHeader(local, remote tcpip.LinkAddress, protocol tcpip.
|
||||
if !e.isTap {
|
||||
return
|
||||
}
|
||||
eth := header.Ethernet(pkt.Header.Prepend(header.EthernetMinimumSize))
|
||||
pkt.LinkHeader = buffer.View(eth)
|
||||
eth := header.Ethernet(pkt.LinkHeader().Push(header.EthernetMinimumSize))
|
||||
hdr := &header.EthernetFields{
|
||||
SrcAddr: local,
|
||||
DstAddr: remote,
|
||||
|
||||
@@ -104,21 +104,21 @@ func TestWaitWrite(t *testing.T) {
|
||||
wep := New(ep)
|
||||
|
||||
// Write and check that it goes through.
|
||||
wep.WritePacket(nil, nil /* gso */, 0, &stack.PacketBuffer{})
|
||||
wep.WritePacket(nil, nil /* gso */, 0, stack.NewPacketBuffer(stack.PacketBufferOptions{}))
|
||||
if want := 1; ep.writeCount != want {
|
||||
t.Fatalf("Unexpected writeCount: got=%v, want=%v", ep.writeCount, want)
|
||||
}
|
||||
|
||||
// Wait on dispatches, then try to write. It must go through.
|
||||
wep.WaitDispatch()
|
||||
wep.WritePacket(nil, nil /* gso */, 0, &stack.PacketBuffer{})
|
||||
wep.WritePacket(nil, nil /* gso */, 0, stack.NewPacketBuffer(stack.PacketBufferOptions{}))
|
||||
if want := 2; ep.writeCount != want {
|
||||
t.Fatalf("Unexpected writeCount: got=%v, want=%v", ep.writeCount, want)
|
||||
}
|
||||
|
||||
// Wait on writes, then try to write. It must not go through.
|
||||
wep.WaitWrite()
|
||||
wep.WritePacket(nil, nil /* gso */, 0, &stack.PacketBuffer{})
|
||||
wep.WritePacket(nil, nil /* gso */, 0, stack.NewPacketBuffer(stack.PacketBufferOptions{}))
|
||||
if want := 2; ep.writeCount != want {
|
||||
t.Fatalf("Unexpected writeCount: got=%v, want=%v", ep.writeCount, want)
|
||||
}
|
||||
@@ -135,21 +135,21 @@ func TestWaitDispatch(t *testing.T) {
|
||||
}
|
||||
|
||||
// Dispatch and check that it goes through.
|
||||
ep.dispatcher.DeliverNetworkPacket("", "", 0, &stack.PacketBuffer{})
|
||||
ep.dispatcher.DeliverNetworkPacket("", "", 0, stack.NewPacketBuffer(stack.PacketBufferOptions{}))
|
||||
if want := 1; ep.dispatchCount != want {
|
||||
t.Fatalf("Unexpected dispatchCount: got=%v, want=%v", ep.dispatchCount, want)
|
||||
}
|
||||
|
||||
// Wait on writes, then try to dispatch. It must go through.
|
||||
wep.WaitWrite()
|
||||
ep.dispatcher.DeliverNetworkPacket("", "", 0, &stack.PacketBuffer{})
|
||||
ep.dispatcher.DeliverNetworkPacket("", "", 0, stack.NewPacketBuffer(stack.PacketBufferOptions{}))
|
||||
if want := 2; ep.dispatchCount != want {
|
||||
t.Fatalf("Unexpected dispatchCount: got=%v, want=%v", ep.dispatchCount, want)
|
||||
}
|
||||
|
||||
// Wait on dispatches, then try to dispatch. It must not go through.
|
||||
wep.WaitDispatch()
|
||||
ep.dispatcher.DeliverNetworkPacket("", "", 0, &stack.PacketBuffer{})
|
||||
ep.dispatcher.DeliverNetworkPacket("", "", 0, stack.NewPacketBuffer(stack.PacketBufferOptions{}))
|
||||
if want := 2; ep.dispatchCount != want {
|
||||
t.Fatalf("Unexpected dispatchCount: got=%v, want=%v", ep.dispatchCount, want)
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, pkt *stack.PacketBu
|
||||
}
|
||||
|
||||
func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
h := header.ARP(pkt.NetworkHeader)
|
||||
h := header.ARP(pkt.NetworkHeader().View())
|
||||
if !h.IsValid() {
|
||||
return
|
||||
}
|
||||
@@ -110,17 +110,17 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
|
||||
if e.linkAddrCache.CheckLocalAddress(e.nicID, header.IPv4ProtocolNumber, localAddr) == 0 {
|
||||
return // we have no useful answer, ignore the request
|
||||
}
|
||||
hdr := buffer.NewPrependable(int(e.linkEP.MaxHeaderLength()) + header.ARPSize)
|
||||
packet := header.ARP(hdr.Prepend(header.ARPSize))
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(e.linkEP.MaxHeaderLength()) + header.ARPSize,
|
||||
})
|
||||
packet := header.ARP(pkt.NetworkHeader().Push(header.ARPSize))
|
||||
packet.SetIPv4OverEthernet()
|
||||
packet.SetOp(header.ARPReply)
|
||||
copy(packet.HardwareAddressSender(), r.LocalLinkAddress[:])
|
||||
copy(packet.ProtocolAddressSender(), h.ProtocolAddressTarget())
|
||||
copy(packet.HardwareAddressTarget(), h.HardwareAddressSender())
|
||||
copy(packet.ProtocolAddressTarget(), h.ProtocolAddressSender())
|
||||
e.linkEP.WritePacket(r, nil /* gso */, ProtocolNumber, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
})
|
||||
_ = e.linkEP.WritePacket(r, nil /* gso */, ProtocolNumber, pkt)
|
||||
fallthrough // also fill the cache from requests
|
||||
case header.ARPReply:
|
||||
addr := tcpip.Address(h.ProtocolAddressSender())
|
||||
@@ -168,17 +168,17 @@ func (*protocol) LinkAddressRequest(addr, localAddr tcpip.Address, remoteLinkAdd
|
||||
r.RemoteLinkAddress = header.EthernetBroadcastAddress
|
||||
}
|
||||
|
||||
hdr := buffer.NewPrependable(int(linkEP.MaxHeaderLength()) + header.ARPSize)
|
||||
h := header.ARP(hdr.Prepend(header.ARPSize))
|
||||
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
ReserveHeaderBytes: int(linkEP.MaxHeaderLength()) + header.ARPSize,
|
||||
})
|
||||
h := header.ARP(pkt.NetworkHeader().Push(header.ARPSize))
|
||||
h.SetIPv4OverEthernet()
|
||||
h.SetOp(header.ARPRequest)
|
||||
copy(h.HardwareAddressSender(), linkEP.LinkAddress())
|
||||
copy(h.ProtocolAddressSender(), localAddr)
|
||||
copy(h.ProtocolAddressTarget(), addr)
|
||||
|
||||
return linkEP.WritePacket(r, nil /* gso */, ProtocolNumber, &stack.PacketBuffer{
|
||||
Header: hdr,
|
||||
})
|
||||
return linkEP.WritePacket(r, nil /* gso */, ProtocolNumber, pkt)
|
||||
}
|
||||
|
||||
// ResolveStaticAddress implements stack.LinkAddressResolver.ResolveStaticAddress.
|
||||
@@ -210,12 +210,10 @@ func (*protocol) Wait() {}
|
||||
|
||||
// Parse implements stack.NetworkProtocol.Parse.
|
||||
func (*protocol) Parse(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNumber, hasTransportHdr bool, ok bool) {
|
||||
hdr, ok := pkt.Data.PullUp(header.ARPSize)
|
||||
_, ok = pkt.NetworkHeader().Consume(header.ARPSize)
|
||||
if !ok {
|
||||
return 0, false, false
|
||||
}
|
||||
pkt.NetworkHeader = hdr
|
||||
pkt.Data.TrimFront(header.ARPSize)
|
||||
return 0, false, true
|
||||
}
|
||||
|
||||
|
||||
@@ -106,9 +106,9 @@ func TestDirectRequest(t *testing.T) {
|
||||
|
||||
inject := func(addr tcpip.Address) {
|
||||
copy(h.ProtocolAddressTarget(), addr)
|
||||
c.linkEP.InjectInbound(arp.ProtocolNumber, &stack.PacketBuffer{
|
||||
c.linkEP.InjectInbound(arp.ProtocolNumber, stack.NewPacketBuffer(stack.PacketBufferOptions{
|
||||
Data: v.ToVectorisedView(),
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
for i, address := range []tcpip.Address{stackAddr1, stackAddr2} {
|
||||
@@ -118,9 +118,9 @@ func TestDirectRequest(t *testing.T) {
|
||||
if pi.Proto != arp.ProtocolNumber {
|
||||
t.Fatalf("expected ARP response, got network protocol number %d", pi.Proto)
|
||||
}
|
||||
rep := header.ARP(pi.Pkt.Header.View())
|
||||
rep := header.ARP(pi.Pkt.NetworkHeader().View())
|
||||
if !rep.IsValid() {
|
||||
t.Fatalf("invalid ARP response pi.Pkt.Header.UsedLength()=%d", pi.Pkt.Header.UsedLength())
|
||||
t.Fatalf("invalid ARP response: len = %d; response = %x", len(rep), rep)
|
||||
}
|
||||
if got, want := tcpip.LinkAddress(rep.HardwareAddressSender()), stackLinkAddr1; got != want {
|
||||
t.Errorf("got HardwareAddressSender = %s, want = %s", got, want)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user