Add support for setting TCP segment hash.

This allows the link layer endpoints to consistenly hash a TCP
segment to a single underlying queue in case a link layer endpoint
does support multiple underlying queues.

Updates #231

PiperOrigin-RevId: 302760664
This commit is contained in:
Bhasker Hariharan
2020-03-24 15:34:43 -07:00
committed by gVisor bot
parent f97858011f
commit c8eeedcc1d
11 changed files with 280 additions and 70 deletions
+6 -4
View File
@@ -405,6 +405,7 @@ func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, protocol tcpip.Ne
eth.Encode(ethHdr)
}
fd := e.fds[pkt.Hash%uint32(len(e.fds))]
if e.Capabilities()&stack.CapabilityHardwareGSO != 0 {
vnetHdr := virtioNetHdr{}
if gso != nil {
@@ -428,14 +429,14 @@ func (e *endpoint) WritePacket(r *stack.Route, gso *stack.GSO, protocol tcpip.Ne
}
vnetHdrBuf := vnetHdrToByteSlice(&vnetHdr)
return rawfile.NonBlockingWrite3(e.fds[0], vnetHdrBuf, pkt.Header.View(), pkt.Data.ToView())
return rawfile.NonBlockingWrite3(fd, vnetHdrBuf, pkt.Header.View(), pkt.Data.ToView())
}
if pkt.Data.Size() == 0 {
return rawfile.NonBlockingWrite(e.fds[0], pkt.Header.View())
return rawfile.NonBlockingWrite(fd, pkt.Header.View())
}
return rawfile.NonBlockingWrite3(e.fds[0], pkt.Header.View(), pkt.Data.ToView(), nil)
return rawfile.NonBlockingWrite3(fd, pkt.Header.View(), pkt.Data.ToView(), nil)
}
// WritePackets writes outbound packets to the file descriptor. If it is not
@@ -551,7 +552,8 @@ func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts []stack.Pac
packets := 0
for packets < n {
sent, err := rawfile.NonBlockingSendMMsg(e.fds[0], mmsgHdrs)
fd := e.fds[pkts[packets].Hash%uint32(len(e.fds))]
sent, err := rawfile.NonBlockingSendMMsg(fd, mmsgHdrs)
if err != nil {
return packets, err
}
+55 -21
View File
@@ -49,36 +49,42 @@ type packetInfo struct {
}
type context struct {
t *testing.T
fds [2]int
ep stack.LinkEndpoint
ch chan packetInfo
done chan struct{}
t *testing.T
readFDs []int
writeFDs []int
ep stack.LinkEndpoint
ch chan packetInfo
done chan struct{}
}
func newContext(t *testing.T, opt *Options) *context {
fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_SEQPACKET, 0)
firstFDPair, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_SEQPACKET, 0)
if err != nil {
t.Fatalf("Socketpair failed: %v", err)
}
secondFDPair, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_SEQPACKET, 0)
if err != nil {
t.Fatalf("Socketpair failed: %v", err)
}
done := make(chan struct{}, 1)
done := make(chan struct{}, 2)
opt.ClosedFunc = func(*tcpip.Error) {
done <- struct{}{}
}
opt.FDs = []int{fds[1]}
opt.FDs = []int{firstFDPair[1], secondFDPair[1]}
ep, err := New(opt)
if err != nil {
t.Fatalf("Failed to create FD endpoint: %v", err)
}
c := &context{
t: t,
fds: fds,
ep: ep,
ch: make(chan packetInfo, 100),
done: done,
t: t,
readFDs: []int{firstFDPair[0], secondFDPair[0]},
writeFDs: opt.FDs,
ep: ep,
ch: make(chan packetInfo, 100),
done: done,
}
ep.Attach(c)
@@ -87,9 +93,14 @@ func newContext(t *testing.T, opt *Options) *context {
}
func (c *context) cleanup() {
syscall.Close(c.fds[0])
for _, fd := range c.readFDs {
syscall.Close(fd)
}
<-c.done
syscall.Close(c.fds[1])
<-c.done
for _, fd := range c.writeFDs {
syscall.Close(fd)
}
}
func (c *context) DeliverNetworkPacket(linkEP stack.LinkEndpoint, remote tcpip.LinkAddress, local tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBuffer) {
@@ -136,7 +147,7 @@ func TestAddress(t *testing.T) {
}
}
func testWritePacket(t *testing.T, plen int, eth bool, gsoMaxSize uint32) {
func testWritePacket(t *testing.T, plen int, eth bool, gsoMaxSize uint32, hash uint32) {
c := newContext(t, &Options{Address: laddr, MTU: mtu, EthernetHeader: eth, GSOMaxSize: gsoMaxSize})
defer c.cleanup()
@@ -171,13 +182,15 @@ func testWritePacket(t *testing.T, plen int, eth bool, gsoMaxSize uint32) {
if err := c.ep.WritePacket(r, gso, proto, stack.PacketBuffer{
Header: hdr,
Data: payload.ToVectorisedView(),
Hash: hash,
}); err != nil {
t.Fatalf("WritePacket failed: %v", err)
}
// Read from fd, then compare with what we wrote.
// Read from the corresponding FD, then compare with what we wrote.
b = make([]byte, mtu)
n, err := syscall.Read(c.fds[0], b)
fd := c.readFDs[hash%uint32(len(c.readFDs))]
n, err := syscall.Read(fd, b)
if err != nil {
t.Fatalf("Read failed: %v", err)
}
@@ -238,7 +251,7 @@ func TestWritePacket(t *testing.T) {
t.Run(
fmt.Sprintf("Eth=%v,PayloadLen=%v,GSOMaxSize=%v", eth, plen, gso),
func(t *testing.T) {
testWritePacket(t, plen, eth, gso)
testWritePacket(t, plen, eth, gso, 0)
},
)
}
@@ -246,6 +259,27 @@ func TestWritePacket(t *testing.T) {
}
}
func TestHashedWritePacket(t *testing.T) {
lengths := []int{0, 100, 1000}
eths := []bool{true, false}
gsos := []uint32{0, 32768}
hashes := []uint32{0, 1}
for _, eth := range eths {
for _, plen := range lengths {
for _, gso := range gsos {
for _, hash := range hashes {
t.Run(
fmt.Sprintf("Eth=%v,PayloadLen=%v,GSOMaxSize=%v,Hash=%d", eth, plen, gso, hash),
func(t *testing.T) {
testWritePacket(t, plen, eth, gso, hash)
},
)
}
}
}
}
}
func TestPreserveSrcAddress(t *testing.T) {
baddr := tcpip.LinkAddress("\xcc\xbb\xaa\x77\x88\x99")
@@ -270,7 +304,7 @@ func TestPreserveSrcAddress(t *testing.T) {
// Read from the FD, then compare with what we wrote.
b := make([]byte, mtu)
n, err := syscall.Read(c.fds[0], b)
n, err := syscall.Read(c.readFDs[0], b)
if err != nil {
t.Fatalf("Read failed: %v", err)
}
@@ -314,7 +348,7 @@ func TestDeliverPacket(t *testing.T) {
}
// Write packet via the file descriptor.
if _, err := syscall.Write(c.fds[0], all); err != nil {
if _, err := syscall.Write(c.readFDs[0], all); err != nil {
t.Fatalf("Write failed: %v", err)
}
+1
View File
@@ -30,6 +30,7 @@ go_library(
"nic.go",
"packet_buffer.go",
"packet_buffer_state.go",
"rand.go",
"registration.go",
"route.go",
"stack.go",
+5
View File
@@ -10,6 +10,7 @@
// 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 stack
import "gvisor.dev/gvisor/pkg/tcpip/buffer"
@@ -54,6 +55,10 @@ type PacketBuffer struct {
LinkHeader buffer.View
NetworkHeader buffer.View
TransportHeader buffer.View
// Hash is the transport layer hash of this packet. A value of zero
// indicates no valid hash has been set.
Hash uint32
}
// Clone makes a copy of pk. It clones the Data field, which creates a new
+1
View File
@@ -11,6 +11,7 @@
// 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 stack
import "gvisor.dev/gvisor/pkg/tcpip/buffer"
+40
View File
@@ -0,0 +1,40 @@
// Copyright 2020 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 stack
import (
mathrand "math/rand"
"gvisor.dev/gvisor/pkg/sync"
)
// lockedRandomSource provides a threadsafe rand.Source.
type lockedRandomSource struct {
mu sync.Mutex
src mathrand.Source
}
func (r *lockedRandomSource) Int63() (n int64) {
r.mu.Lock()
n = r.src.Int63()
r.mu.Unlock()
return n
}
func (r *lockedRandomSource) Seed(seed int64) {
r.mu.Lock()
r.src.Seed(seed)
r.mu.Unlock()
}
+42 -2
View File
@@ -20,7 +20,9 @@
package stack
import (
"bytes"
"encoding/binary"
mathrand "math/rand"
"sync/atomic"
"time"
@@ -465,6 +467,10 @@ type Stack struct {
// forwarder holds the packets that wait for their link-address resolutions
// to complete, and forwards them when each resolution is done.
forwarder *forwardQueue
// randomGenerator is an injectable pseudo random generator that can be
// used when a random number is required.
randomGenerator *mathrand.Rand
}
// UniqueID is an abstract generator of unique identifiers.
@@ -525,9 +531,16 @@ type Options struct {
// this is non-nil.
RawFactory RawFactory
// OpaqueIIDOpts hold the options for generating opaque interface identifiers
// (IIDs) as outlined by RFC 7217.
// OpaqueIIDOpts hold the options for generating opaque interface
// identifiers (IIDs) as outlined by RFC 7217.
OpaqueIIDOpts OpaqueInterfaceIdentifierOptions
// RandSource is an optional source to use to generate random
// numbers. If omitted it defaults to a Source seeded by the data
// returned by rand.Read().
//
// RandSource must be thread-safe.
RandSource mathrand.Source
}
// TransportEndpointInfo holds useful information about a transport endpoint
@@ -623,6 +636,13 @@ func New(opts Options) *Stack {
opts.UniqueID = new(uniqueIDGenerator)
}
randSrc := opts.RandSource
if randSrc == nil {
// Source provided by mathrand.NewSource is not thread-safe so
// we wrap it in a simple thread-safe version.
randSrc = &lockedRandomSource{src: mathrand.NewSource(generateRandInt64())}
}
// Make sure opts.NDPConfigs contains valid values only.
opts.NDPConfigs.validate()
@@ -645,6 +665,7 @@ func New(opts Options) *Stack {
ndpDisp: opts.NDPDisp,
opaqueIIDOpts: opts.OpaqueIIDOpts,
forwarder: newForwardQueue(),
randomGenerator: mathrand.New(randSrc),
}
// Add specified network protocols.
@@ -1818,6 +1839,12 @@ func (s *Stack) Seed() uint32 {
return s.seed
}
// Rand returns a reference to a pseudo random generator that can be used
// to generate random numbers as required.
func (s *Stack) Rand() *mathrand.Rand {
return s.randomGenerator
}
func generateRandUint32() uint32 {
b := make([]byte, 4)
if _, err := rand.Read(b); err != nil {
@@ -1825,3 +1852,16 @@ func generateRandUint32() uint32 {
}
return binary.LittleEndian.Uint32(b)
}
func generateRandInt64() int64 {
b := make([]byte, 8)
if _, err := rand.Read(b); err != nil {
panic(err)
}
buf := bytes.NewReader(b)
var v int64
if err := binary.Read(buf, binary.LittleEndian, &v); err != nil {
panic(err)
}
return v
}
+18 -2
View File
@@ -445,7 +445,15 @@ func (e *endpoint) handleListenSegment(ctx *listenContext, s *segment) {
// RFC 793 section 3.4 page 35 (figure 12) outlines that a RST
// must be sent in response to a SYN-ACK while in the listen
// state to prevent completing a handshake from an old SYN.
e.sendTCP(&s.route, s.id, buffer.VectorisedView{}, e.ttl, e.sendTOS, header.TCPFlagRst, s.ackNumber, 0, 0, nil, nil)
e.sendTCP(&s.route, tcpFields{
id: s.id,
ttl: e.ttl,
tos: e.sendTOS,
flags: header.TCPFlagRst,
seq: s.ackNumber,
ack: 0,
rcvWnd: 0,
}, buffer.VectorisedView{}, nil)
return
}
@@ -493,7 +501,15 @@ func (e *endpoint) handleListenSegment(ctx *listenContext, s *segment) {
TSEcr: opts.TSVal,
MSS: mssForRoute(&s.route),
}
e.sendSynTCP(&s.route, s.id, e.ttl, e.sendTOS, header.TCPFlagSyn|header.TCPFlagAck, cookie, s.sequenceNumber+1, ctx.rcvWnd, synOpts)
e.sendSynTCP(&s.route, tcpFields{
id: s.id,
ttl: e.ttl,
tos: e.sendTOS,
flags: header.TCPFlagSyn | header.TCPFlagAck,
seq: cookie,
ack: s.sequenceNumber + 1,
rcvWnd: ctx.rcvWnd,
}, synOpts)
e.stack.Stats().TCP.ListenOverflowSynCookieSent.Increment()
}
+98 -40
View File
@@ -308,7 +308,15 @@ func (h *handshake) synSentState(s *segment) *tcpip.Error {
if ttl == 0 {
ttl = s.route.DefaultTTL()
}
h.ep.sendSynTCP(&s.route, h.ep.ID, ttl, h.ep.sendTOS, h.flags, h.iss, h.ackNum, h.rcvWnd, synOpts)
h.ep.sendSynTCP(&s.route, tcpFields{
id: h.ep.ID,
ttl: ttl,
tos: h.ep.sendTOS,
flags: h.flags,
seq: h.iss,
ack: h.ackNum,
rcvWnd: h.rcvWnd,
}, synOpts)
return nil
}
@@ -361,7 +369,15 @@ func (h *handshake) synRcvdState(s *segment) *tcpip.Error {
SACKPermitted: h.ep.sackPermitted,
MSS: h.ep.amss,
}
h.ep.sendSynTCP(&s.route, h.ep.ID, h.ep.ttl, h.ep.sendTOS, h.flags, h.iss, h.ackNum, h.rcvWnd, synOpts)
h.ep.sendSynTCP(&s.route, tcpFields{
id: h.ep.ID,
ttl: h.ep.ttl,
tos: h.ep.sendTOS,
flags: h.flags,
seq: h.iss,
ack: h.ackNum,
rcvWnd: h.rcvWnd,
}, synOpts)
return nil
}
@@ -550,7 +566,16 @@ func (h *handshake) execute() *tcpip.Error {
synOpts.WS = -1
}
}
h.ep.sendSynTCP(&h.ep.route, h.ep.ID, h.ep.ttl, h.ep.sendTOS, h.flags, h.iss, h.ackNum, h.rcvWnd, synOpts)
h.ep.sendSynTCP(&h.ep.route, tcpFields{
id: h.ep.ID,
ttl: h.ep.ttl,
tos: h.ep.sendTOS,
flags: h.flags,
seq: h.iss,
ack: h.ackNum,
rcvWnd: h.rcvWnd,
}, synOpts)
for h.state != handshakeCompleted {
h.ep.mu.Unlock()
@@ -573,7 +598,15 @@ func (h *handshake) execute() *tcpip.Error {
// the connection with another ACK or data (as ACKs are never
// retransmitted on their own).
if h.active || !h.acked || h.deferAccept != 0 && time.Since(h.startTime) > h.deferAccept {
h.ep.sendSynTCP(&h.ep.route, h.ep.ID, h.ep.ttl, h.ep.sendTOS, h.flags, h.iss, h.ackNum, h.rcvWnd, synOpts)
h.ep.sendSynTCP(&h.ep.route, tcpFields{
id: h.ep.ID,
ttl: h.ep.ttl,
tos: h.ep.sendTOS,
flags: h.flags,
seq: h.iss,
ack: h.ackNum,
rcvWnd: h.rcvWnd,
}, synOpts)
}
case wakerForNotification:
@@ -686,18 +719,33 @@ func makeSynOptions(opts header.TCPSynOptions) []byte {
return options[:offset]
}
func (e *endpoint) sendSynTCP(r *stack.Route, id stack.TransportEndpointID, ttl, tos uint8, flags byte, seq, ack seqnum.Value, rcvWnd seqnum.Size, opts header.TCPSynOptions) *tcpip.Error {
options := makeSynOptions(opts)
// tcpFields is a struct to carry different parameters required by the
// send*TCP variant functions below.
type tcpFields struct {
id stack.TransportEndpointID
ttl uint8
tos uint8
flags byte
seq seqnum.Value
ack seqnum.Value
rcvWnd seqnum.Size
opts []byte
txHash uint32
}
func (e *endpoint) sendSynTCP(r *stack.Route, tf tcpFields, opts header.TCPSynOptions) *tcpip.Error {
tf.opts = makeSynOptions(opts)
// We ignore SYN send errors and let the callers re-attempt send.
if err := e.sendTCP(r, id, buffer.VectorisedView{}, ttl, tos, flags, seq, ack, rcvWnd, options, nil); err != nil {
if err := e.sendTCP(r, tf, buffer.VectorisedView{}, nil); err != nil {
e.stats.SendErrors.SynSendToNetworkFailed.Increment()
}
putOptions(options)
putOptions(tf.opts)
return nil
}
func (e *endpoint) sendTCP(r *stack.Route, id stack.TransportEndpointID, data buffer.VectorisedView, ttl, tos uint8, flags byte, seq, ack seqnum.Value, rcvWnd seqnum.Size, opts []byte, gso *stack.GSO) *tcpip.Error {
if err := sendTCP(r, id, data, ttl, tos, flags, seq, ack, rcvWnd, opts, gso); err != nil {
func (e *endpoint) sendTCP(r *stack.Route, tf tcpFields, data buffer.VectorisedView, gso *stack.GSO) *tcpip.Error {
tf.txHash = e.txHash
if err := sendTCP(r, tf, data, gso); err != nil {
e.stats.SendErrors.SegmentSendToNetworkFailed.Increment()
return err
}
@@ -705,8 +753,8 @@ func (e *endpoint) sendTCP(r *stack.Route, id stack.TransportEndpointID, data bu
return nil
}
func buildTCPHdr(r *stack.Route, id stack.TransportEndpointID, pkt *stack.PacketBuffer, flags byte, seq, ack seqnum.Value, rcvWnd seqnum.Size, opts []byte, gso *stack.GSO) {
optLen := len(opts)
func buildTCPHdr(r *stack.Route, tf tcpFields, pkt *stack.PacketBuffer, gso *stack.GSO) {
optLen := len(tf.opts)
hdr := &pkt.Header
packetSize := pkt.DataSize
off := pkt.DataOffset
@@ -714,15 +762,15 @@ func buildTCPHdr(r *stack.Route, id stack.TransportEndpointID, pkt *stack.Packet
tcp := header.TCP(hdr.Prepend(header.TCPMinimumSize + optLen))
pkt.TransportHeader = buffer.View(tcp)
tcp.Encode(&header.TCPFields{
SrcPort: id.LocalPort,
DstPort: id.RemotePort,
SeqNum: uint32(seq),
AckNum: uint32(ack),
SrcPort: tf.id.LocalPort,
DstPort: tf.id.RemotePort,
SeqNum: uint32(tf.seq),
AckNum: uint32(tf.ack),
DataOffset: uint8(header.TCPMinimumSize + optLen),
Flags: flags,
WindowSize: uint16(rcvWnd),
Flags: tf.flags,
WindowSize: uint16(tf.rcvWnd),
})
copy(tcp[header.TCPMinimumSize:], opts)
copy(tcp[header.TCPMinimumSize:], tf.opts)
length := uint16(hdr.UsedLength() + packetSize)
xsum := r.PseudoHeaderChecksum(ProtocolNumber, length)
@@ -737,13 +785,12 @@ func buildTCPHdr(r *stack.Route, id stack.TransportEndpointID, pkt *stack.Packet
xsum = header.ChecksumVVWithOffset(pkt.Data, xsum, off, packetSize)
tcp.SetChecksum(^tcp.CalculateChecksum(xsum))
}
}
func sendTCPBatch(r *stack.Route, id stack.TransportEndpointID, data buffer.VectorisedView, ttl, tos uint8, flags byte, seq, ack seqnum.Value, rcvWnd seqnum.Size, opts []byte, gso *stack.GSO) *tcpip.Error {
optLen := len(opts)
if rcvWnd > 0xffff {
rcvWnd = 0xffff
func sendTCPBatch(r *stack.Route, tf tcpFields, data buffer.VectorisedView, gso *stack.GSO) *tcpip.Error {
optLen := len(tf.opts)
if tf.rcvWnd > 0xffff {
tf.rcvWnd = 0xffff
}
mss := int(gso.MSS)
@@ -768,14 +815,15 @@ func sendTCPBatch(r *stack.Route, id stack.TransportEndpointID, data buffer.Vect
pkts[i].DataOffset = off
pkts[i].DataSize = packetSize
pkts[i].Data = data
buildTCPHdr(r, id, &pkts[i], flags, seq, ack, rcvWnd, opts, gso)
pkts[i].Hash = tf.txHash
buildTCPHdr(r, tf, &pkts[i], gso)
off += packetSize
seq = seq.Add(seqnum.Size(packetSize))
tf.seq = tf.seq.Add(seqnum.Size(packetSize))
}
if ttl == 0 {
ttl = r.DefaultTTL()
if tf.ttl == 0 {
tf.ttl = r.DefaultTTL()
}
sent, err := r.WritePackets(gso, pkts, stack.NetworkHeaderParams{Protocol: ProtocolNumber, TTL: ttl, TOS: tos})
sent, err := r.WritePackets(gso, pkts, stack.NetworkHeaderParams{Protocol: ProtocolNumber, TTL: tf.ttl, TOS: tf.tos})
if err != nil {
r.Stats().TCP.SegmentSendErrors.IncrementBy(uint64(n - sent))
}
@@ -785,14 +833,14 @@ func sendTCPBatch(r *stack.Route, id stack.TransportEndpointID, data buffer.Vect
// sendTCP sends a TCP segment with the provided options via the provided
// network endpoint and under the provided identity.
func sendTCP(r *stack.Route, id stack.TransportEndpointID, data buffer.VectorisedView, ttl, tos uint8, flags byte, seq, ack seqnum.Value, rcvWnd seqnum.Size, opts []byte, gso *stack.GSO) *tcpip.Error {
optLen := len(opts)
if rcvWnd > 0xffff {
rcvWnd = 0xffff
func sendTCP(r *stack.Route, tf tcpFields, data buffer.VectorisedView, gso *stack.GSO) *tcpip.Error {
optLen := len(tf.opts)
if tf.rcvWnd > 0xffff {
tf.rcvWnd = 0xffff
}
if r.Loop&stack.PacketLoop == 0 && gso != nil && gso.Type == stack.GSOSW && int(gso.MSS) < data.Size() {
return sendTCPBatch(r, id, data, ttl, tos, flags, seq, ack, rcvWnd, opts, gso)
return sendTCPBatch(r, tf, data, gso)
}
pkt := stack.PacketBuffer{
@@ -800,18 +848,19 @@ func sendTCP(r *stack.Route, id stack.TransportEndpointID, data buffer.Vectorise
DataOffset: 0,
DataSize: data.Size(),
Data: data,
Hash: tf.txHash,
}
buildTCPHdr(r, id, &pkt, flags, seq, ack, rcvWnd, opts, gso)
buildTCPHdr(r, tf, &pkt, gso)
if ttl == 0 {
ttl = r.DefaultTTL()
if tf.ttl == 0 {
tf.ttl = r.DefaultTTL()
}
if err := r.WritePacket(gso, stack.NetworkHeaderParams{Protocol: ProtocolNumber, TTL: ttl, TOS: tos}, pkt); err != nil {
if err := r.WritePacket(gso, stack.NetworkHeaderParams{Protocol: ProtocolNumber, TTL: tf.ttl, TOS: tf.tos}, pkt); err != nil {
r.Stats().TCP.SegmentSendErrors.Increment()
return err
}
r.Stats().TCP.SegmentsSent.Increment()
if (flags & header.TCPFlagRst) != 0 {
if (tf.flags & header.TCPFlagRst) != 0 {
r.Stats().TCP.ResetsSent.Increment()
}
return nil
@@ -863,7 +912,16 @@ func (e *endpoint) sendRaw(data buffer.VectorisedView, flags byte, seq, ack seqn
sackBlocks = e.sack.Blocks[:e.sack.NumBlocks]
}
options := e.makeOptions(sackBlocks)
err := e.sendTCP(&e.route, e.ID, data, e.ttl, e.sendTOS, flags, seq, ack, rcvWnd, options, e.gso)
err := e.sendTCP(&e.route, tcpFields{
id: e.ID,
ttl: e.ttl,
tos: e.sendTOS,
flags: flags,
seq: seq,
ack: ack,
rcvWnd: rcvWnd,
opts: options,
}, data, e.gso)
putOptions(options)
return err
}
+5
View File
@@ -581,6 +581,10 @@ type endpoint struct {
// endpoint and at this point the endpoint is only around
// to complete the TCP shutdown.
closed bool
// txHash is the transport layer hash to be set on outbound packets
// emitted by this endpoint.
txHash uint32
}
// UniqueID implements stack.TransportEndpoint.UniqueID.
@@ -771,6 +775,7 @@ func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, waiterQue
count: 9,
},
uniqueID: s.UniqueID(),
txHash: s.Rand().Uint32(),
}
var ss SendBufferSizeOption
+9 -1
View File
@@ -191,7 +191,15 @@ func replyWithReset(s *segment) {
flags |= header.TCPFlagAck
ack = s.sequenceNumber.Add(s.logicalLen())
}
sendTCP(&s.route, s.id, buffer.VectorisedView{}, s.route.DefaultTTL(), stack.DefaultTOS, flags, seq, ack, 0 /* rcvWnd */, nil /* options */, nil /* gso */)
sendTCP(&s.route, tcpFields{
id: s.id,
ttl: s.route.DefaultTTL(),
tos: stack.DefaultTOS,
flags: flags,
seq: seq,
ack: ack,
rcvWnd: 0,
}, buffer.VectorisedView{}, nil /* gso */)
}
// SetOption implements stack.TransportProtocol.SetOption.