netstack/tcp: software segmentation offload

Right now, we send each tcp packet separately, we call one system
call per-packet. This patch allows to generate multiple tcp packets
and send them by sendmmsg.

The arguable part of this CL is a way how to handle multiple headers.
This CL adds the next field to the Prepandable buffer.

Nginx test results:

Server Software:        nginx/1.15.9
Server Hostname:        10.138.0.2
Server Port:            8080

Document Path:          /10m.txt
Document Length:        10485760 bytes

w/o gso:
Concurrency Level:      5
Time taken for tests:   5.491 seconds
Complete requests:      100
Failed requests:        0
Total transferred:      1048600200 bytes
HTML transferred:       1048576000 bytes
Requests per second:    18.21 [#/sec] (mean)
Time per request:       274.525 [ms] (mean)
Time per request:       54.905 [ms] (mean, across all concurrent requests)
Transfer rate:          186508.03 [Kbytes/sec] received

sw-gso:

Concurrency Level:      5
Time taken for tests:   3.852 seconds
Complete requests:      100
Failed requests:        0
Total transferred:      1048600200 bytes
HTML transferred:       1048576000 bytes
Requests per second:    25.96 [#/sec] (mean)
Time per request:       192.576 [ms] (mean)
Time per request:       38.515 [ms] (mean, across all concurrent requests)
Transfer rate:          265874.92 [Kbytes/sec] received

w/o gso:
$ ./tcp_benchmark --client --duration 15  --ideal
[SUM]  0.0-15.1 sec  2.20 GBytes  1.25 Gbits/sec

software gso:
$ tcp_benchmark --client --duration 15  --ideal --gso $((1<<16)) --swgso
[SUM]  0.0-15.1 sec  3.99 GBytes  2.26 Gbits/sec

PiperOrigin-RevId: 276112677
This commit is contained in:
Andrei Vagin
2019-10-22 11:55:56 -07:00
committed by gVisor bot
parent fb69de696b
commit 8720bd643e
33 changed files with 676 additions and 71 deletions
+9
View File
@@ -0,0 +1,9 @@
build_file: "repo/scripts/swgso_tests.sh"
action {
define_artifacts {
regex: "**/sponge_log.xml"
regex: "**/sponge_log.log"
regex: "**/outputs.zip"
}
}
+5
View File
@@ -41,6 +41,11 @@ func NewPrependableFromView(v View) Prependable {
return Prependable{buf: v, usedIdx: 0}
}
// NewEmptyPrependableFromView creates a new prependable buffer from a View.
func NewEmptyPrependableFromView(v View) Prependable {
return Prependable{buf: v, usedIdx: len(v)}
}
// View returns a View of the backing buffer that contains all prepended
// data so far.
func (p Prependable) View() View {
+5 -1
View File
@@ -36,10 +36,14 @@ go_test(
name = "header_x_test",
size = "small",
srcs = [
"checksum_test.go",
"ipversion_test.go",
"tcp_test.go",
],
deps = [":header"],
deps = [
":header",
"//pkg/tcpip/buffer",
],
)
go_test(
+39 -11
View File
@@ -23,11 +23,17 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/buffer"
)
func calculateChecksum(buf []byte, initial uint32) uint16 {
func calculateChecksum(buf []byte, odd bool, initial uint32) (uint16, bool) {
v := initial
if odd {
v += uint32(buf[0])
buf = buf[1:]
}
l := len(buf)
if l&1 != 0 {
odd = l&1 != 0
if odd {
l--
v += uint32(buf[l]) << 8
}
@@ -36,7 +42,7 @@ func calculateChecksum(buf []byte, initial uint32) uint16 {
v += (uint32(buf[i]) << 8) + uint32(buf[i+1])
}
return ChecksumCombine(uint16(v), uint16(v>>16))
return ChecksumCombine(uint16(v), uint16(v>>16)), odd
}
// Checksum calculates the checksum (as defined in RFC 1071) of the bytes in the
@@ -44,7 +50,8 @@ func calculateChecksum(buf []byte, initial uint32) uint16 {
//
// The initial checksum must have been computed on an even number of bytes.
func Checksum(buf []byte, initial uint16) uint16 {
return calculateChecksum(buf, uint32(initial))
s, _ := calculateChecksum(buf, false, uint32(initial))
return s
}
// ChecksumVV calculates the checksum (as defined in RFC 1071) of the bytes in
@@ -52,19 +59,40 @@ func Checksum(buf []byte, initial uint16) uint16 {
//
// The initial checksum must have been computed on an even number of bytes.
func ChecksumVV(vv buffer.VectorisedView, initial uint16) uint16 {
var odd bool
return ChecksumVVWithOffset(vv, initial, 0, vv.Size())
}
// ChecksumVVWithOffset calculates the checksum (as defined in RFC 1071) of the
// bytes in the given VectorizedView.
//
// The initial checksum must have been computed on an even number of bytes.
func ChecksumVVWithOffset(vv buffer.VectorisedView, initial uint16, off int, size int) uint16 {
odd := false
sum := initial
for _, v := range vv.Views() {
if len(v) == 0 {
continue
}
s := uint32(sum)
if odd {
s += uint32(v[0])
v = v[1:]
if off >= len(v) {
off -= len(v)
continue
}
odd = len(v)&1 != 0
sum = calculateChecksum(v, s)
v = v[off:]
l := len(v)
if l > size {
l = size
}
v = v[:l]
sum, odd = calculateChecksum(v, odd, uint32(sum))
size -= len(v)
if size == 0 {
break
}
off = 0
}
return sum
}
+109
View File
@@ -0,0 +1,109 @@
// Copyright 2019 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package header provides the implementation of the encoding and decoding of
// network protocol headers.
package header_test
import (
"testing"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/header"
)
func TestChecksumVVWithOffset(t *testing.T) {
testCases := []struct {
name string
vv buffer.VectorisedView
off, size int
initial uint16
want uint16
}{
{
name: "empty",
vv: buffer.NewVectorisedView(0, []buffer.View{
buffer.NewViewFromBytes([]byte{1, 9, 0, 5, 4}),
}),
off: 0,
size: 0,
want: 0,
},
{
name: "OneView",
vv: buffer.NewVectorisedView(0, []buffer.View{
buffer.NewViewFromBytes([]byte{1, 9, 0, 5, 4}),
}),
off: 0,
size: 5,
want: 1294,
},
{
name: "TwoViews",
vv: buffer.NewVectorisedView(0, []buffer.View{
buffer.NewViewFromBytes([]byte{1, 9, 0, 5, 4}),
buffer.NewViewFromBytes([]byte{4, 3, 7, 1, 2, 123}),
}),
off: 0,
size: 11,
want: 33819,
},
{
name: "TwoViewsWithOffset",
vv: buffer.NewVectorisedView(0, []buffer.View{
buffer.NewViewFromBytes([]byte{98, 1, 9, 0, 5, 4}),
buffer.NewViewFromBytes([]byte{4, 3, 7, 1, 2, 123}),
}),
off: 1,
size: 11,
want: 33819,
},
{
name: "ThreeViewsWithOffset",
vv: buffer.NewVectorisedView(0, []buffer.View{
buffer.NewViewFromBytes([]byte{98, 1, 9, 0, 5, 4}),
buffer.NewViewFromBytes([]byte{98, 1, 9, 0, 5, 4}),
buffer.NewViewFromBytes([]byte{4, 3, 7, 1, 2, 123}),
}),
off: 7,
size: 11,
want: 33819,
},
{
name: "ThreeViewsWithInitial",
vv: buffer.NewVectorisedView(0, []buffer.View{
buffer.NewViewFromBytes([]byte{77, 11, 33, 0, 55, 44}),
buffer.NewViewFromBytes([]byte{98, 1, 9, 0, 5, 4}),
buffer.NewViewFromBytes([]byte{4, 3, 7, 1, 2, 123, 99}),
}),
initial: 77,
off: 7,
size: 11,
want: 33896,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if got, want := header.ChecksumVVWithOffset(tc.vv, tc.initial, tc.off, tc.size), tc.want; got != want {
t.Errorf("header.ChecksumVVWithOffset(%v) = %v, want: %v", tc, got, tc.want)
}
v := tc.vv.ToView()
v.TrimFront(tc.off)
v.CapLength(tc.size)
if got, want := header.Checksum(v, tc.initial), tc.want; got != want {
t.Errorf("header.Checksum(%v) = %v, want: %v", tc, got, tc.want)
}
})
}
}
+28 -1
View File
@@ -96,7 +96,7 @@ func (e *Endpoint) MTU() uint32 {
func (e *Endpoint) Capabilities() stack.LinkEndpointCapabilities {
caps := stack.LinkEndpointCapabilities(0)
if e.GSO {
caps |= stack.CapabilityGSO
caps |= stack.CapabilityHardwareGSO
}
return caps
}
@@ -134,6 +134,33 @@ func (e *Endpoint) WritePacket(_ *stack.Route, gso *stack.GSO, hdr buffer.Prepen
return nil
}
// WritePackets stores outbound packets into the channel.
func (e *Endpoint) WritePackets(_ *stack.Route, gso *stack.GSO, hdrs []stack.PacketDescriptor, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) (int, *tcpip.Error) {
payloadView := payload.ToView()
n := 0
packetLoop:
for i := range hdrs {
hdr := &hdrs[i].Hdr
off := hdrs[i].Off
size := hdrs[i].Size
p := PacketInfo{
Header: hdr.View(),
Proto: protocol,
Payload: buffer.NewViewFromBytes(payloadView[off : off+size]),
GSO: gso,
}
select {
case e.C <- p:
n++
default:
break packetLoop
}
}
return n, nil
}
// WriteRawPacket implements stack.LinkEndpoint.WriteRawPacket.
func (e *Endpoint) WriteRawPacket(packet buffer.VectorisedView) *tcpip.Error {
p := PacketInfo{
+126 -2
View File
@@ -165,6 +165,9 @@ type Options struct {
// disabled.
GSOMaxSize uint32
// SoftwareGSOEnabled indicates whether software GSO is enabled or not.
SoftwareGSOEnabled bool
// PacketDispatchMode specifies the type of inbound dispatcher to be
// used for this endpoint.
PacketDispatchMode PacketDispatchMode
@@ -242,7 +245,11 @@ func New(opts *Options) (stack.LinkEndpoint, error) {
}
if isSocket {
if opts.GSOMaxSize != 0 {
e.caps |= stack.CapabilityGSO
if opts.SoftwareGSOEnabled {
e.caps |= stack.CapabilitySoftwareGSO
} else {
e.caps |= stack.CapabilityHardwareGSO
}
e.gsoMaxSize = opts.GSOMaxSize
}
}
@@ -397,7 +404,7 @@ func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, hdr buffer.Prepen
eth.Encode(ethHdr)
}
if e.Capabilities()&stack.CapabilityGSO != 0 {
if e.Capabilities()&stack.CapabilityHardwareGSO != 0 {
vnetHdr := virtioNetHdr{}
vnetHdrBuf := vnetHdrToByteSlice(&vnetHdr)
if gso != nil {
@@ -430,6 +437,123 @@ func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, hdr buffer.Prepen
return rawfile.NonBlockingWrite3(e.fds[0], hdr.View(), payload.ToView(), nil)
}
// WritePackets writes outbound packets to the file descriptor. If it is not
// currently writable, the packet is dropped.
func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, hdrs []stack.PacketDescriptor, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) (int, *tcpip.Error) {
var ethHdrBuf []byte
// hdr + data
iovLen := 2
if e.hdrSize > 0 {
// Add ethernet header if needed.
ethHdrBuf = make([]byte, header.EthernetMinimumSize)
eth := header.Ethernet(ethHdrBuf)
ethHdr := &header.EthernetFields{
DstAddr: r.RemoteLinkAddress,
Type: protocol,
}
// Preserve the src address if it's set in the route.
if r.LocalLinkAddress != "" {
ethHdr.SrcAddr = r.LocalLinkAddress
} else {
ethHdr.SrcAddr = e.addr
}
eth.Encode(ethHdr)
iovLen++
}
n := len(hdrs)
views := payload.Views()
/*
* Each bondary in views can add one more iovec.
*
* payload | | | |
* -----------------------------
* packets | | | | | | |
* -----------------------------
* iovecs | | | | | | | | |
*/
iovec := make([]syscall.Iovec, n*iovLen+len(views)-1)
mmsgHdrs := make([]rawfile.MMsgHdr, n)
iovecIdx := 0
viewIdx := 0
viewOff := 0
off := 0
nextOff := 0
for i := range hdrs {
prevIovecIdx := iovecIdx
mmsgHdr := &mmsgHdrs[i]
mmsgHdr.Msg.Iov = &iovec[iovecIdx]
packetSize := hdrs[i].Size
hdr := &hdrs[i].Hdr
off = hdrs[i].Off
if off != nextOff {
// We stop in a different point last time.
size := packetSize
viewIdx = 0
viewOff = 0
for size > 0 {
if size >= len(views[viewIdx]) {
viewIdx++
viewOff = 0
size -= len(views[viewIdx])
} else {
viewOff = size
size = 0
}
}
}
nextOff = off + packetSize
if ethHdrBuf != nil {
v := &iovec[iovecIdx]
v.Base = &ethHdrBuf[0]
v.Len = uint64(len(ethHdrBuf))
iovecIdx++
}
v := &iovec[iovecIdx]
hdrView := hdr.View()
v.Base = &hdrView[0]
v.Len = uint64(len(hdrView))
iovecIdx++
for packetSize > 0 {
vec := &iovec[iovecIdx]
iovecIdx++
v := views[viewIdx]
vec.Base = &v[viewOff]
s := len(v) - viewOff
if s <= packetSize {
viewIdx++
viewOff = 0
} else {
s = packetSize
viewOff += s
}
vec.Len = uint64(s)
packetSize -= s
}
mmsgHdr.Msg.Iovlen = uint64(iovecIdx - prevIovecIdx)
}
packets := 0
for packets < n {
sent, err := rawfile.NonBlockingSendMMsg(e.fds[0], mmsgHdrs)
if err != nil {
return packets, err
}
packets += sent
mmsgHdrs = mmsgHdrs[sent:]
}
return packets, nil
}
// WriteRawPacket implements stack.LinkEndpoint.WriteRawPacket.
func (e *endpoint) WriteRawPacket(packet buffer.VectorisedView) *tcpip.Error {
return rawfile.NonBlockingWrite(e.fds[0], packet.ToView())
+6 -6
View File
@@ -53,7 +53,7 @@ func newReadVDispatcher(fd int, e *endpoint) (linkDispatcher, error) {
d := &readVDispatcher{fd: fd, e: e}
d.views = make([]buffer.View, len(BufConfig))
iovLen := len(BufConfig)
if d.e.Capabilities()&stack.CapabilityGSO != 0 {
if d.e.Capabilities()&stack.CapabilityHardwareGSO != 0 {
iovLen++
}
d.iovecs = make([]syscall.Iovec, iovLen)
@@ -63,7 +63,7 @@ func newReadVDispatcher(fd int, e *endpoint) (linkDispatcher, error) {
func (d *readVDispatcher) allocateViews(bufConfig []int) {
var vnetHdr [virtioNetHdrSize]byte
vnetHdrOff := 0
if d.e.Capabilities()&stack.CapabilityGSO != 0 {
if d.e.Capabilities()&stack.CapabilityHardwareGSO != 0 {
// The kernel adds virtioNetHdr before each packet, but
// we don't use it, so so we allocate a buffer for it,
// add it in iovecs but don't add it in a view.
@@ -106,7 +106,7 @@ func (d *readVDispatcher) dispatch() (bool, *tcpip.Error) {
if err != nil {
return false, err
}
if d.e.Capabilities()&stack.CapabilityGSO != 0 {
if d.e.Capabilities()&stack.CapabilityHardwareGSO != 0 {
// Skip virtioNetHdr which is added before each packet, it
// isn't used and it isn't in a view.
n -= virtioNetHdrSize
@@ -195,7 +195,7 @@ func newRecvMMsgDispatcher(fd int, e *endpoint) (linkDispatcher, error) {
}
d.iovecs = make([][]syscall.Iovec, MaxMsgsPerRecv)
iovLen := len(BufConfig)
if d.e.Capabilities()&stack.CapabilityGSO != 0 {
if d.e.Capabilities()&stack.CapabilityHardwareGSO != 0 {
// virtioNetHdr is prepended before each packet.
iovLen++
}
@@ -226,7 +226,7 @@ func (d *recvMMsgDispatcher) allocateViews(bufConfig []int) {
for k := 0; k < len(d.views); k++ {
var vnetHdr [virtioNetHdrSize]byte
vnetHdrOff := 0
if d.e.Capabilities()&stack.CapabilityGSO != 0 {
if d.e.Capabilities()&stack.CapabilityHardwareGSO != 0 {
// The kernel adds virtioNetHdr before each packet, but
// we don't use it, so so we allocate a buffer for it,
// add it in iovecs but don't add it in a view.
@@ -262,7 +262,7 @@ func (d *recvMMsgDispatcher) dispatch() (bool, *tcpip.Error) {
// Process each of received packets.
for k := 0; k < nMsgs; k++ {
n := int(d.msgHdrs[k].Len)
if d.e.Capabilities()&stack.CapabilityGSO != 0 {
if d.e.Capabilities()&stack.CapabilityHardwareGSO != 0 {
n -= virtioNetHdrSize
}
if n <= d.e.hdrSize {
+5
View File
@@ -90,6 +90,11 @@ func (e *endpoint) WritePacket(_ *stack.Route, _ *stack.GSO, hdr buffer.Prependa
return nil
}
// WritePackets implements stack.LinkEndpoint.WritePackets.
func (e *endpoint) WritePackets(_ *stack.Route, _ *stack.GSO, hdrs []stack.PacketDescriptor, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) (int, *tcpip.Error) {
panic("not implemented")
}
// WriteRawPacket implements stack.LinkEndpoint.WriteRawPacket.
func (e *endpoint) WriteRawPacket(packet buffer.VectorisedView) *tcpip.Error {
// Reject the packet if it's shorter than an ethernet header.
+13 -2
View File
@@ -84,12 +84,23 @@ func (m *InjectableEndpoint) InjectInbound(protocol tcpip.NetworkProtocolNumber,
m.dispatcher.DeliverNetworkPacket(m, "" /* remote */, "" /* local */, protocol, vv, nil /* linkHeader */)
}
// WritePackets writes outbound packets to the appropriate
// LinkInjectableEndpoint based on the RemoteAddress. HandleLocal only works if
// r.RemoteAddress has a route registered in this endpoint.
func (m *InjectableEndpoint) WritePackets(r *stack.Route, gso *stack.GSO, hdrs []stack.PacketDescriptor, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) (int, *tcpip.Error) {
endpoint, ok := m.routes[r.RemoteAddress]
if !ok {
return 0, tcpip.ErrNoRoute
}
return endpoint.WritePackets(r, gso, hdrs, payload, protocol)
}
// WritePacket writes outbound packets to the appropriate LinkInjectableEndpoint
// based on the RemoteAddress. HandleLocal only works if r.RemoteAddress has a
// route registered in this endpoint.
func (m *InjectableEndpoint) WritePacket(r *stack.Route, _ *stack.GSO, hdr buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) *tcpip.Error {
func (m *InjectableEndpoint) WritePacket(r *stack.Route, gso *stack.GSO, hdr buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) *tcpip.Error {
if endpoint, ok := m.routes[r.RemoteAddress]; ok {
return endpoint.WritePacket(r, nil /* gso */, hdr, payload, protocol)
return endpoint.WritePacket(r, gso, hdr, payload, protocol)
}
return tcpip.ErrNoRoute
}
+4 -1
View File
@@ -16,5 +16,8 @@ go_library(
visibility = [
"//visibility:public",
],
deps = ["//pkg/tcpip"],
deps = [
"//pkg/tcpip",
"@org_golang_x_sys//unix:go_default_library",
],
)
+11
View File
@@ -22,6 +22,7 @@ import (
"syscall"
"unsafe"
"golang.org/x/sys/unix"
"gvisor.dev/gvisor/pkg/tcpip"
)
@@ -101,6 +102,16 @@ func NonBlockingWrite3(fd int, b1, b2, b3 []byte) *tcpip.Error {
return nil
}
// NonBlockingSendMMsg sends multiple messages on a socket.
func NonBlockingSendMMsg(fd int, msgHdrs []MMsgHdr) (int, *tcpip.Error) {
n, _, e := syscall.RawSyscall6(unix.SYS_SENDMMSG, uintptr(fd), uintptr(unsafe.Pointer(&msgHdrs[0])), uintptr(len(msgHdrs)), syscall.MSG_DONTWAIT, 0, 0)
if e != 0 {
return 0, TranslateErrno(e)
}
return int(n), nil
}
// PollEvent represents the pollfd structure passed to a poll() system call.
type PollEvent struct {
FD int32
+5
View File
@@ -212,6 +212,11 @@ func (e *endpoint) WritePacket(r *stack.Route, _ *stack.GSO, hdr buffer.Prependa
return nil
}
// WritePackets implements stack.LinkEndpoint.WritePackets.
func (e *endpoint) WritePackets(r *stack.Route, _ *stack.GSO, hdrs []stack.PacketDescriptor, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) (int, *tcpip.Error) {
panic("not implemented")
}
// WriteRawPacket implements stack.LinkEndpoint.WriteRawPacket.
func (e *endpoint) WriteRawPacket(packet buffer.VectorisedView) *tcpip.Error {
v := packet.ToView()
+19 -4
View File
@@ -193,10 +193,7 @@ func (e *endpoint) GSOMaxSize() uint32 {
return 0
}
// WritePacket implements the stack.LinkEndpoint interface. It is called by
// higher-level protocols to write packets; it just logs the packet and forwards
// the request to the lower endpoint.
func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, hdr buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) *tcpip.Error {
func (e *endpoint) dumpPacket(gso *stack.GSO, hdr buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) {
if atomic.LoadUint32(&LogPackets) == 1 && e.file == nil {
logPacket("send", protocol, hdr.View(), gso)
}
@@ -223,9 +220,27 @@ func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, hdr buffer.Prepen
panic(err)
}
}
}
// WritePacket implements the stack.LinkEndpoint interface. It is called by
// higher-level protocols to write packets; it just logs the packet and
// forwards the request to the lower endpoint.
func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, hdr buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) *tcpip.Error {
e.dumpPacket(gso, hdr, payload, protocol)
return e.lower.WritePacket(r, gso, hdr, payload, protocol)
}
// WritePackets implements the stack.LinkEndpoint interface. It is called by
// higher-level protocols to write packets; it just logs the packet and
// forwards the request to the lower endpoint.
func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, hdrs []stack.PacketDescriptor, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) (int, *tcpip.Error) {
view := payload.ToView()
for _, d := range hdrs {
e.dumpPacket(gso, d.Hdr, buffer.NewVectorisedView(d.Size, []buffer.View{view[d.Off:][:d.Size]}), protocol)
}
return e.lower.WritePackets(r, gso, hdrs, payload, protocol)
}
// WriteRawPacket implements stack.LinkEndpoint.WriteRawPacket.
func (e *endpoint) WriteRawPacket(packet buffer.VectorisedView) *tcpip.Error {
if atomic.LoadUint32(&LogPackets) == 1 && e.file == nil {
+13
View File
@@ -109,6 +109,19 @@ func (e *Endpoint) WritePacket(r *stack.Route, gso *stack.GSO, hdr buffer.Prepen
return err
}
// WritePackets implements stack.LinkEndpoint.WritePackets. It is called by
// higher-level protocols to write packets. It only forwards packets to the
// lower endpoint if Wait or WaitWrite haven't been called.
func (e *Endpoint) WritePackets(r *stack.Route, gso *stack.GSO, hdrs []stack.PacketDescriptor, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) (int, *tcpip.Error) {
if !e.writeGate.Enter() {
return len(hdrs), nil
}
n, err := e.lower.WritePackets(r, gso, hdrs, payload, protocol)
e.writeGate.Leave()
return n, err
}
// WriteRawPacket implements stack.LinkEndpoint.WriteRawPacket.
func (e *Endpoint) WriteRawPacket(packet buffer.VectorisedView) *tcpip.Error {
if !e.writeGate.Enter() {
+6
View File
@@ -70,6 +70,12 @@ func (e *countedEndpoint) WritePacket(r *stack.Route, _ *stack.GSO, hdr buffer.P
return nil
}
// WritePackets implements stack.LinkEndpoint.WritePackets.
func (e *countedEndpoint) WritePackets(r *stack.Route, _ *stack.GSO, hdrs []stack.PacketDescriptor, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) (int, *tcpip.Error) {
e.writeCount += len(hdrs)
return len(hdrs), nil
}
func (e *countedEndpoint) WriteRawPacket(packet buffer.VectorisedView) *tcpip.Error {
e.writeCount++
return nil
+5
View File
@@ -83,6 +83,11 @@ func (e *endpoint) WritePacket(*stack.Route, *stack.GSO, buffer.Prependable, buf
return tcpip.ErrNotSupported
}
// WritePackets implements stack.NetworkEndpoint.WritePackets.
func (e *endpoint) WritePackets(*stack.Route, *stack.GSO, []stack.PacketDescriptor, buffer.VectorisedView, stack.NetworkHeaderParams, stack.PacketLooping) (int, *tcpip.Error) {
return 0, tcpip.ErrNotSupported
}
func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, payload buffer.VectorisedView, loop stack.PacketLooping) *tcpip.Error {
return tcpip.ErrNotSupported
}
+5
View File
@@ -171,6 +171,11 @@ func (t *testObject) WritePacket(_ *stack.Route, _ *stack.GSO, hdr buffer.Prepen
return nil
}
// WritePackets implements stack.LinkEndpoint.WritePackets.
func (t *testObject) WritePackets(_ *stack.Route, _ *stack.GSO, hdr []stack.PacketDescriptor, payload buffer.VectorisedView, protocol tcpip.NetworkProtocolNumber) (int, *tcpip.Error) {
panic("not implemented")
}
func (t *testObject) WriteRawPacket(_ buffer.VectorisedView) *tcpip.Error {
return tcpip.ErrNotSupported
}
+24 -3
View File
@@ -198,10 +198,9 @@ func (e *endpoint) writePacketFragments(r *stack.Route, gso *stack.GSO, hdr buff
return nil
}
// WritePacket writes a packet to the given destination address and protocol.
func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, hdr buffer.Prependable, payload buffer.VectorisedView, params stack.NetworkHeaderParams, loop stack.PacketLooping) *tcpip.Error {
func (e *endpoint) addIPHeader(r *stack.Route, hdr *buffer.Prependable, payloadSize int, params stack.NetworkHeaderParams) {
ip := header.IPv4(hdr.Prepend(header.IPv4MinimumSize))
length := uint16(hdr.UsedLength() + payload.Size())
length := uint16(hdr.UsedLength() + payloadSize)
id := uint32(0)
if length > header.IPv4MaximumHeaderSize+8 {
// Packets of 68 bytes or less are required by RFC 791 to not be
@@ -219,6 +218,11 @@ func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, hdr buffer.Prepen
DstAddr: r.RemoteAddress,
})
ip.SetChecksum(^ip.CalculateChecksum())
}
// WritePacket writes a packet to the given destination address and protocol.
func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, hdr buffer.Prependable, payload buffer.VectorisedView, params stack.NetworkHeaderParams, loop stack.PacketLooping) *tcpip.Error {
e.addIPHeader(r, &hdr, payload.Size(), params)
if loop&stack.PacketLoop != 0 {
views := make([]buffer.View, 1, 1+len(payload.Views()))
@@ -242,6 +246,23 @@ func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, hdr buffer.Prepen
return nil
}
// WritePackets implements stack.NetworkEndpoint.WritePackets.
func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, hdrs []stack.PacketDescriptor, payload buffer.VectorisedView, params stack.NetworkHeaderParams, loop stack.PacketLooping) (int, *tcpip.Error) {
if loop&stack.PacketLoop != 0 {
panic("multiple packets in local loop")
}
if loop&stack.PacketOut == 0 {
return len(hdrs), nil
}
for i := range hdrs {
e.addIPHeader(r, &hdrs[i].Hdr, hdrs[i].Size, params)
}
n, err := e.linkEP.WritePackets(r, gso, hdrs, payload, ProtocolNumber)
r.Stats().IP.PacketsSent.IncrementBy(uint64(n))
return n, err
}
// WriteHeaderIncludedPacket writes a packet already containing a network
// header through the given route.
func (e *endpoint) WriteHeaderIncludedPacket(r *stack.Route, payload buffer.VectorisedView, loop stack.PacketLooping) *tcpip.Error {
+27 -3
View File
@@ -97,9 +97,8 @@ func (e *endpoint) GSOMaxSize() uint32 {
return 0
}
// WritePacket writes a packet to the given destination address and protocol.
func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, hdr buffer.Prependable, payload buffer.VectorisedView, params stack.NetworkHeaderParams, loop stack.PacketLooping) *tcpip.Error {
length := uint16(hdr.UsedLength() + payload.Size())
func (e *endpoint) addIPHeader(r *stack.Route, hdr *buffer.Prependable, payloadSize int, params stack.NetworkHeaderParams) {
length := uint16(hdr.UsedLength() + payloadSize)
ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
ip.Encode(&header.IPv6Fields{
PayloadLength: length,
@@ -109,6 +108,11 @@ func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, hdr buffer.Prepen
SrcAddr: r.LocalAddress,
DstAddr: r.RemoteAddress,
})
}
// WritePacket writes a packet to the given destination address and protocol.
func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, hdr buffer.Prependable, payload buffer.VectorisedView, params stack.NetworkHeaderParams, loop stack.PacketLooping) *tcpip.Error {
e.addIPHeader(r, &hdr, payload.Size(), params)
if loop&stack.PacketLoop != 0 {
views := make([]buffer.View, 1, 1+len(payload.Views()))
@@ -127,6 +131,26 @@ func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, hdr buffer.Prepen
return e.linkEP.WritePacket(r, gso, hdr, payload, ProtocolNumber)
}
// WritePackets implements stack.LinkEndpoint.WritePackets.
func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, hdrs []stack.PacketDescriptor, payload buffer.VectorisedView, params stack.NetworkHeaderParams, loop stack.PacketLooping) (int, *tcpip.Error) {
if loop&stack.PacketLoop != 0 {
panic("not implemented")
}
if loop&stack.PacketOut == 0 {
return len(hdrs), nil
}
for i := range hdrs {
hdr := &hdrs[i].Hdr
size := hdrs[i].Size
e.addIPHeader(r, hdr, size, params)
}
n, err := e.linkEP.WritePackets(r, gso, hdrs, payload, ProtocolNumber)
r.Stats().IP.PacketsSent.IncrementBy(uint64(n))
return n, err
}
// WriteHeaderIncludedPacker implements stack.NetworkEndpoint. It is not yet
// supported by IPv6.
func (*endpoint) WriteHeaderIncludedPacket(r *stack.Route, payload buffer.VectorisedView, loop stack.PacketLooping) *tcpip.Error {

Some files were not shown because too many files have changed in this diff Show More