Merge branch 'master' into ipt-udp-matchers

This commit is contained in:
Kevin Krakauer
2020-01-30 14:56:50 -08:00
47 changed files with 713 additions and 94 deletions
+8 -2
View File
@@ -17,6 +17,7 @@ package tmpfs
import (
"fmt"
"io"
"math"
"time"
"gvisor.dev/gvisor/pkg/abi/linux"
@@ -444,10 +445,15 @@ func (rw *fileReadWriter) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error)
defer rw.f.dataMu.Unlock()
// Compute the range to write.
end := fs.WriteEndOffset(rw.offset, int64(srcs.NumBytes()))
if end == rw.offset { // srcs.NumBytes() == 0?
if srcs.NumBytes() == 0 {
// Nothing to do.
return 0, nil
}
end := fs.WriteEndOffset(rw.offset, int64(srcs.NumBytes()))
if end == math.MaxInt64 {
// Overflow.
return 0, syserror.EINVAL
}
// Check if seals prevent either file growth or all writes.
switch {
+3 -3
View File
@@ -88,14 +88,14 @@ const (
El0Sync_undef
El0Sync_dbg
El0Sync_inv
VirtualizationException
_NR_INTERRUPTS
)
// System call vectors.
const (
Syscall Vector = El0Sync_svc
PageFault Vector = El0Sync_da
Syscall Vector = El0Sync_svc
PageFault Vector = El0Sync_da
VirtualizationException Vector = El0Error
)
// VirtualAddressBits returns the number bits available for virtual addresses.
+13 -1
View File
@@ -601,7 +601,19 @@ TEXT ·El0_fiq(SB),NOSPLIT,$0
B ·Shutdown(SB)
TEXT ·El0_error(SB),NOSPLIT,$0
B ·Shutdown(SB)
KERNEL_ENTRY_FROM_EL0
WORD $0xd538d092 //MRS TPIDR_EL1, R18
WORD $0xd538601a //MRS FAR_EL1, R26
MOVD R26, CPU_FAULT_ADDR(RSV_REG)
MOVD $1, R3
MOVD R3, CPU_ERROR_TYPE(RSV_REG) // Set error type to user.
MOVD $VirtualizationException, R3
MOVD R3, CPU_VECTOR_CODE(RSV_REG)
B ·Halt(SB)
TEXT ·El0_sync_invalid(SB),NOSPLIT,$0
B ·Shutdown(SB)
@@ -85,6 +85,7 @@ func Emit(w io.Writer) {
fmt.Fprintf(w, "#define PageFault 0x%02x\n", PageFault)
fmt.Fprintf(w, "#define Syscall 0x%02x\n", Syscall)
fmt.Fprintf(w, "#define VirtualizationException 0x%02x\n", VirtualizationException)
p := &syscall.PtraceRegs{}
fmt.Fprintf(w, "\n// Ptrace registers.\n")
+22
View File
@@ -1260,6 +1260,18 @@ func getSockOptTCP(t *kernel.Task, ep commonEndpoint, name, outLen int) (interfa
return int32(time.Duration(v) / time.Second), nil
case linux.TCP_DEFER_ACCEPT:
if outLen < sizeOfInt32 {
return nil, syserr.ErrInvalidArgument
}
var v tcpip.TCPDeferAcceptOption
if err := ep.GetSockOpt(&v); err != nil {
return nil, syserr.TranslateNetstackError(err)
}
return int32(time.Duration(v) / time.Second), nil
default:
emitUnimplementedEventTCP(t, name)
}
@@ -1713,6 +1725,16 @@ func setSockOptTCP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *
v := usermem.ByteOrder.Uint32(optVal)
return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.TCPLingerTimeoutOption(time.Second * time.Duration(v))))
case linux.TCP_DEFER_ACCEPT:
if len(optVal) < sizeOfInt32 {
return syserr.ErrInvalidArgument
}
v := int32(usermem.ByteOrder.Uint32(optVal))
if v < 0 {
v = 0
}
return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.TCPDeferAcceptOption(time.Second * time.Duration(v))))
case linux.TCP_REPAIR_OPTIONS:
t.Kernel().EmitUnimplementedEvent(t)
+6 -10
View File
@@ -25,6 +25,10 @@ import (
// doSplice implements a blocking splice operation.
func doSplice(t *kernel.Task, outFile, inFile *fs.File, opts fs.SpliceOpts, nonBlocking bool) (int64, error) {
if opts.Length < 0 || opts.SrcStart < 0 || opts.DstStart < 0 {
return 0, syserror.EINVAL
}
var (
total int64
n int64
@@ -82,11 +86,6 @@ func Sendfile(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sysc
offsetAddr := args[2].Pointer()
count := int64(args[3].SizeT())
// Don't send a negative number of bytes.
if count < 0 {
return 0, nil, syserror.EINVAL
}
// Get files.
inFile := t.GetFile(inFD)
if inFile == nil {
@@ -136,11 +135,6 @@ func Sendfile(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sysc
return 0, nil, err
}
// The offset must be valid.
if offset < 0 {
return 0, nil, syserror.EINVAL
}
// Do the splice.
n, err = doSplice(t, outFile, inFile, fs.SpliceOpts{
Length: count,
@@ -227,6 +221,7 @@ func Splice(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal
if _, err := t.CopyIn(outOffset, &offset); err != nil {
return 0, nil, err
}
// Use the destination offset.
opts.DstOffset = true
opts.DstStart = offset
@@ -244,6 +239,7 @@ func Splice(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal
if _, err := t.CopyIn(inOffset, &offset); err != nil {
return 0, nil, err
}
// Use the source offset.
opts.SrcOffset = true
opts.SrcStart = offset
+6 -24
View File
@@ -167,8 +167,8 @@ type NDPDispatcher interface {
// reason, such as the address being removed). If an error occured
// during DAD, err will be set and resolved must be ignored.
//
// This function is permitted to block indefinitely without interfering
// with the stack's operation.
// This function is not permitted to block indefinitely. This function
// is also not permitted to call into the stack.
OnDuplicateAddressDetectionStatus(nicID tcpip.NICID, addr tcpip.Address, resolved bool, err *tcpip.Error)
// OnDefaultRouterDiscovered will be called when a new default router is
@@ -538,29 +538,11 @@ func (ndp *ndpState) sendDADPacket(addr tcpip.Address) *tcpip.Error {
r := makeRoute(header.IPv6ProtocolNumber, header.IPv6Any, snmc, ndp.nic.linkEP.LinkAddress(), ref, false, false)
defer r.Release()
linkAddr := ndp.nic.linkEP.LinkAddress()
isValidLinkAddr := header.IsValidUnicastEthernetAddress(linkAddr)
ndpNSSize := header.ICMPv6NeighborSolicitMinimumSize
if isValidLinkAddr {
// Only include a Source Link Layer Address option if the NIC has a valid
// link layer address.
//
// TODO(b/141011931): Validate a LinkEndpoint's link address (provided by
// LinkEndpoint.LinkAddress) before reaching this point.
ndpNSSize += header.NDPLinkLayerAddressSize
}
hdr := buffer.NewPrependable(int(r.MaxHeaderLength()) + ndpNSSize)
pkt := header.ICMPv6(hdr.Prepend(ndpNSSize))
hdr := buffer.NewPrependable(int(r.MaxHeaderLength()) + header.ICMPv6NeighborSolicitMinimumSize)
pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6NeighborSolicitMinimumSize))
pkt.SetType(header.ICMPv6NeighborSolicit)
ns := header.NDPNeighborSolicit(pkt.NDPPayload())
ns.SetTargetAddress(addr)
if isValidLinkAddr {
ns.Options().Serialize(header.NDPOptionsSerializer{
header.NDPSourceLinkLayerAddressOption(linkAddr),
})
}
pkt.SetChecksum(header.ICMPv6Checksum(pkt, r.LocalAddress, r.RemoteAddress, buffer.VectorisedView{}))
sent := r.Stats().ICMP.V6PacketsSent
@@ -607,8 +589,8 @@ func (ndp *ndpState) stopDuplicateAddressDetection(addr tcpip.Address) {
delete(ndp.dad, addr)
// Let the integrator know DAD did not resolve.
if ndp.nic.stack.ndpDisp != nil {
go ndp.nic.stack.ndpDisp.OnDuplicateAddressDetectionStatus(ndp.nic.ID(), addr, false, nil)
if ndpDisp := ndp.nic.stack.ndpDisp; ndpDisp != nil {
ndpDisp.OnDuplicateAddressDetectionStatus(ndp.nic.ID(), addr, false, nil)
}
}
+10 -6
View File
@@ -413,14 +413,18 @@ func TestDADResolve(t *testing.T) {
t.Fatalf("got Proto = %d, want = %d", p.Proto, header.IPv6ProtocolNumber)
}
// Check NDP packet.
// Check NDP NS packet.
//
// As per RFC 4861 section 4.3, a possible option is the Source Link
// Layer option, but this option MUST NOT be included when the source
// address of the packet is the unspecified address.
checker.IPv6(t, p.Pkt.Header.View().ToVectorisedView().First(),
checker.SrcAddr(header.IPv6Any),
checker.DstAddr(header.SolicitedNodeAddr(addr1)),
checker.TTL(header.NDPHopLimit),
checker.NDPNS(
checker.NDPNSTargetAddress(addr1),
checker.NDPNSOptions([]header.NDPOption{
header.NDPSourceLinkLayerAddressOption(linkAddr1),
}),
checker.NDPNSOptions(nil),
))
}
})
@@ -497,7 +501,7 @@ func TestDADFail(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ndpDisp := ndpDispatcher{
dadC: make(chan ndpDADEvent),
dadC: make(chan ndpDADEvent, 1),
}
ndpConfigs := stack.DefaultNDPConfigurations()
opts := stack.Options{
@@ -576,7 +580,7 @@ func TestDADFail(t *testing.T) {
// removed.
func TestDADStop(t *testing.T) {
ndpDisp := ndpDispatcher{
dadC: make(chan ndpDADEvent),
dadC: make(chan ndpDADEvent, 1),
}
ndpConfigs := stack.NDPConfigurations{
RetransmitTimer: time.Second,
+6
View File
@@ -626,6 +626,12 @@ type TCPLingerTimeoutOption time.Duration
// before being marked closed.
type TCPTimeWaitTimeoutOption time.Duration
// TCPDeferAcceptOption is used by SetSockOpt/GetSockOpt to allow a
// accept to return a completed connection only when there is data to be
// read. This usually means the listening socket will drop the final ACK
// for a handshake till the specified timeout until a segment with data arrives.
type TCPDeferAcceptOption time.Duration
// MulticastTTLOption is used by SetSockOpt/GetSockOpt to control the default
// TTL value for multicast messages. The default is 1.
type MulticastTTLOption uint8
+2
View File
@@ -57,6 +57,7 @@ go_library(
imports = ["gvisor.dev/gvisor/pkg/tcpip/buffer"],
visibility = ["//visibility:public"],
deps = [
"//pkg/log",
"//pkg/rand",
"//pkg/sleep",
"//pkg/sync",
@@ -90,6 +91,7 @@ go_test(
tags = ["flaky"],
deps = [
":tcp",
"//pkg/sync",
"//pkg/tcpip",
"//pkg/tcpip/buffer",
"//pkg/tcpip/checker",
+11 -14
View File
@@ -222,13 +222,13 @@ func (l *listenContext) isCookieValid(id stack.TransportEndpointID, cookie seqnu
// createConnectingEndpoint creates a new endpoint in a connecting state, with
// the connection parameters given by the arguments.
func (l *listenContext) createConnectingEndpoint(s *segment, iss seqnum.Value, irs seqnum.Value, rcvdSynOpts *header.TCPSynOptions) (*endpoint, *tcpip.Error) {
func (l *listenContext) createConnectingEndpoint(s *segment, iss seqnum.Value, irs seqnum.Value, rcvdSynOpts *header.TCPSynOptions, queue *waiter.Queue) (*endpoint, *tcpip.Error) {
// Create a new endpoint.
netProto := l.netProto
if netProto == 0 {
netProto = s.route.NetProto
}
n := newEndpoint(l.stack, netProto, nil)
n := newEndpoint(l.stack, netProto, queue)
n.v6only = l.v6only
n.ID = s.id
n.boundNICID = s.route.NICID()
@@ -273,16 +273,17 @@ func (l *listenContext) createConnectingEndpoint(s *segment, iss seqnum.Value, i
// createEndpoint creates a new endpoint in connected state and then performs
// the TCP 3-way handshake.
func (l *listenContext) createEndpointAndPerformHandshake(s *segment, opts *header.TCPSynOptions) (*endpoint, *tcpip.Error) {
func (l *listenContext) createEndpointAndPerformHandshake(s *segment, opts *header.TCPSynOptions, queue *waiter.Queue) (*endpoint, *tcpip.Error) {
// Create new endpoint.
irs := s.sequenceNumber
isn := generateSecureISN(s.id, l.stack.Seed())
ep, err := l.createConnectingEndpoint(s, isn, irs, opts)
ep, err := l.createConnectingEndpoint(s, isn, irs, opts, queue)
if err != nil {
return nil, err
}
// listenEP is nil when listenContext is used by tcp.Forwarder.
deferAccept := time.Duration(0)
if l.listenEP != nil {
l.listenEP.mu.Lock()
if l.listenEP.EndpointState() != StateListen {
@@ -290,13 +291,12 @@ func (l *listenContext) createEndpointAndPerformHandshake(s *segment, opts *head
return nil, tcpip.ErrConnectionAborted
}
l.addPendingEndpoint(ep)
deferAccept = l.listenEP.deferAccept
l.listenEP.mu.Unlock()
}
// Perform the 3-way handshake.
h := newHandshake(ep, seqnum.Size(ep.initialReceiveWindow()))
h.resetToSynRcvd(isn, irs, opts)
h := newPassiveHandshake(ep, seqnum.Size(ep.initialReceiveWindow()), isn, irs, opts, deferAccept)
if err := h.execute(); err != nil {
ep.Close()
if l.listenEP != nil {
@@ -377,16 +377,14 @@ func (e *endpoint) handleSynSegment(ctx *listenContext, s *segment, opts *header
defer e.decSynRcvdCount()
defer s.decRef()
n, err := ctx.createEndpointAndPerformHandshake(s, opts)
n, err := ctx.createEndpointAndPerformHandshake(s, opts, &waiter.Queue{})
if err != nil {
e.stack.Stats().TCP.FailedConnectionAttempts.Increment()
e.stats.FailedConnectionAttempts.Increment()
return
}
ctx.removePendingEndpoint(n)
// Start the protocol goroutine.
wq := &waiter.Queue{}
n.startAcceptedLoop(wq)
n.startAcceptedLoop()
e.stack.Stats().TCP.PassiveConnectionOpenings.Increment()
e.deliverAccepted(n)
@@ -546,7 +544,7 @@ func (e *endpoint) handleListenSegment(ctx *listenContext, s *segment) {
rcvdSynOptions.TSEcr = s.parsedOptions.TSEcr
}
n, err := ctx.createConnectingEndpoint(s, s.ackNumber-1, s.sequenceNumber-1, rcvdSynOptions)
n, err := ctx.createConnectingEndpoint(s, s.ackNumber-1, s.sequenceNumber-1, rcvdSynOptions, &waiter.Queue{})
if err != nil {
e.stack.Stats().TCP.FailedConnectionAttempts.Increment()
e.stats.FailedConnectionAttempts.Increment()
@@ -576,8 +574,7 @@ func (e *endpoint) handleListenSegment(ctx *listenContext, s *segment) {
// space available in the backlog.
// Start the protocol goroutine.
wq := &waiter.Queue{}
n.startAcceptedLoop(wq)
n.startAcceptedLoop()
e.stack.Stats().TCP.PassiveConnectionOpenings.Increment()
go e.deliverAccepted(n)
}
+49 -4
View File
@@ -86,6 +86,19 @@ type handshake struct {
// rcvWndScale is the receive window scale, as defined in RFC 1323.
rcvWndScale int
// startTime is the time at which the first SYN/SYN-ACK was sent.
startTime time.Time
// deferAccept if non-zero will drop the final ACK for a passive
// handshake till an ACK segment with data is received or the timeout is
// hit.
deferAccept time.Duration
// acked is true if the the final ACK for a 3-way handshake has
// been received. This is required to stop retransmitting the
// original SYN-ACK when deferAccept is enabled.
acked bool
}
func newHandshake(ep *endpoint, rcvWnd seqnum.Size) handshake {
@@ -112,6 +125,12 @@ func newHandshake(ep *endpoint, rcvWnd seqnum.Size) handshake {
return h
}
func newPassiveHandshake(ep *endpoint, rcvWnd seqnum.Size, isn, irs seqnum.Value, opts *header.TCPSynOptions, deferAccept time.Duration) handshake {
h := newHandshake(ep, rcvWnd)
h.resetToSynRcvd(isn, irs, opts, deferAccept)
return h
}
// FindWndScale determines the window scale to use for the given maximum window
// size.
func FindWndScale(wnd seqnum.Size) int {
@@ -181,7 +200,7 @@ func (h *handshake) effectiveRcvWndScale() uint8 {
// resetToSynRcvd resets the state of the handshake object to the SYN-RCVD
// state.
func (h *handshake) resetToSynRcvd(iss seqnum.Value, irs seqnum.Value, opts *header.TCPSynOptions) {
func (h *handshake) resetToSynRcvd(iss seqnum.Value, irs seqnum.Value, opts *header.TCPSynOptions, deferAccept time.Duration) {
h.active = false
h.state = handshakeSynRcvd
h.flags = header.TCPFlagSyn | header.TCPFlagAck
@@ -189,6 +208,7 @@ func (h *handshake) resetToSynRcvd(iss seqnum.Value, irs seqnum.Value, opts *hea
h.ackNum = irs + 1
h.mss = opts.MSS
h.sndWndScale = opts.WS
h.deferAccept = deferAccept
h.ep.mu.Lock()
h.ep.setEndpointState(StateSynRecv)
h.ep.mu.Unlock()
@@ -352,6 +372,14 @@ func (h *handshake) synRcvdState(s *segment) *tcpip.Error {
// We have previously received (and acknowledged) the peer's SYN. If the
// peer acknowledges our SYN, the handshake is completed.
if s.flagIsSet(header.TCPFlagAck) {
// If deferAccept is not zero and this is a bare ACK and the
// timeout is not hit then drop the ACK.
if h.deferAccept != 0 && s.data.Size() == 0 && time.Since(h.startTime) < h.deferAccept {
h.acked = true
h.ep.stack.Stats().DroppedPackets.Increment()
return nil
}
// If the timestamp option is negotiated and the segment does
// not carry a timestamp option then the segment must be dropped
// as per https://tools.ietf.org/html/rfc7323#section-3.2.
@@ -365,10 +393,16 @@ func (h *handshake) synRcvdState(s *segment) *tcpip.Error {
h.ep.updateRecentTimestamp(s.parsedOptions.TSVal, h.ackNum, s.sequenceNumber)
}
h.state = handshakeCompleted
h.ep.mu.Lock()
h.ep.transitionToStateEstablishedLocked(h)
// If the segment has data then requeue it for the receiver
// to process it again once main loop is started.
if s.data.Size() > 0 {
s.incRef()
h.ep.enqueueSegment(s)
}
h.ep.mu.Unlock()
return nil
}
@@ -471,6 +505,7 @@ func (h *handshake) execute() *tcpip.Error {
}
}
h.startTime = time.Now()
// Initialize the resend timer.
resendWaker := sleep.Waker{}
timeOut := time.Duration(time.Second)
@@ -524,11 +559,21 @@ func (h *handshake) execute() *tcpip.Error {
switch index, _ := s.Fetch(true); index {
case wakerForResend:
timeOut *= 2
if timeOut > 60*time.Second {
if timeOut > MaxRTO {
return tcpip.ErrTimeout
}
rt.Reset(timeOut)
h.ep.sendSynTCP(&h.ep.route, h.ep.ID, h.ep.ttl, h.ep.sendTOS, h.flags, h.iss, h.ackNum, h.rcvWnd, synOpts)
// Resend the SYN/SYN-ACK only if the following conditions hold.
// - It's an active handshake (deferAccept does not apply)
// - It's a passive handshake and we have not yet got the final-ACK.
// - It's a passive handshake and we got an ACK but deferAccept is
// enabled and we are now past the deferAccept duration.
// The last is required to provide a way for the peer to complete
// 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)
}
case wakerForNotification:
n := h.ep.fetchNotifications()
+31 -5
View File
@@ -498,6 +498,13 @@ type endpoint struct {
// without any data being acked.
userTimeout time.Duration
// deferAccept if non-zero specifies a user specified time during
// which the final ACK of a handshake will be dropped provided the
// ACK is a bare ACK and carries no data. If the timeout is crossed then
// the bare ACK is accepted and the connection is delivered to the
// listener.
deferAccept time.Duration
// pendingAccepted is a synchronization primitive used to track number
// of connections that are queued up to be delivered to the accepted
// channel. We use this to ensure that all goroutines blocked on writing
@@ -1574,6 +1581,15 @@ func (e *endpoint) SetSockOpt(opt interface{}) *tcpip.Error {
e.mu.Unlock()
return nil
case tcpip.TCPDeferAcceptOption:
e.mu.Lock()
if time.Duration(v) > MaxRTO {
v = tcpip.TCPDeferAcceptOption(MaxRTO)
}
e.deferAccept = time.Duration(v)
e.mu.Unlock()
return nil
default:
return nil
}
@@ -1798,6 +1814,12 @@ func (e *endpoint) GetSockOpt(opt interface{}) *tcpip.Error {
e.mu.Unlock()
return nil
case *tcpip.TCPDeferAcceptOption:
e.mu.Lock()
*o = tcpip.TCPDeferAcceptOption(e.deferAccept)
e.mu.Unlock()
return nil
default:
return tcpip.ErrUnknownProtocolOption
}
@@ -2025,8 +2047,14 @@ func (e *endpoint) Shutdown(flags tcpip.ShutdownFlags) *tcpip.Error {
// work mutex is available.
if e.workMu.TryLock() {
e.mu.Lock()
e.resetConnectionLocked(tcpip.ErrConnectionAborted)
e.notifyProtocolGoroutine(notifyTickleWorker)
// We need to double check here to make
// sure worker has not transitioned the
// endpoint out of a connected state
// before trying to send a reset.
if e.EndpointState().connected() {
e.resetConnectionLocked(tcpip.ErrConnectionAborted)
e.notifyProtocolGoroutine(notifyTickleWorker)
}
e.mu.Unlock()
e.workMu.Unlock()
} else {
@@ -2149,9 +2177,8 @@ func (e *endpoint) listen(backlog int) *tcpip.Error {
// startAcceptedLoop sets up required state and starts a goroutine with the
// main loop for accepted connections.
func (e *endpoint) startAcceptedLoop(waiterQueue *waiter.Queue) {
func (e *endpoint) startAcceptedLoop() {
e.mu.Lock()
e.waiterQueue = waiterQueue
e.workerRunning = true
e.mu.Unlock()
wakerInitDone := make(chan struct{})
@@ -2177,7 +2204,6 @@ func (e *endpoint) Accept() (tcpip.Endpoint, *waiter.Queue, *tcpip.Error) {
default:
return nil, nil, tcpip.ErrWouldBlock
}
return n, n.waiterQueue, nil
}
+2 -2
View File
@@ -157,13 +157,13 @@ func (r *ForwarderRequest) CreateEndpoint(queue *waiter.Queue) (tcpip.Endpoint,
TSVal: r.synOptions.TSVal,
TSEcr: r.synOptions.TSEcr,
SACKPermitted: r.synOptions.SACKPermitted,
})
}, queue)
if err != nil {
return nil, err
}
// Start the protocol goroutine.
ep.startAcceptedLoop(queue)
ep.startAcceptedLoop()
return ep, nil
}
+181
View File
@@ -21,6 +21,7 @@ import (
"testing"
"time"
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/checker"
@@ -6787,3 +6788,183 @@ func TestIncreaseWindowOnBufferResize(t *testing.T) {
),
)
}
func TestTCPDeferAccept(t *testing.T) {
c := context.New(t, defaultMTU)
defer c.Cleanup()
c.Create(-1)
if err := c.EP.Bind(tcpip.FullAddress{Port: context.StackPort}); err != nil {
t.Fatal("Bind failed:", err)
}
if err := c.EP.Listen(10); err != nil {
t.Fatal("Listen failed:", err)
}
const tcpDeferAccept = 1 * time.Second
if err := c.EP.SetSockOpt(tcpip.TCPDeferAcceptOption(tcpDeferAccept)); err != nil {
t.Fatalf("c.EP.SetSockOpt(TCPDeferAcceptOption(%s) failed: %v", tcpDeferAccept, err)
}
irs, iss := executeHandshake(t, c, context.TestPort, false /* synCookiesInUse */)
if _, _, err := c.EP.Accept(); err != tcpip.ErrWouldBlock {
t.Fatalf("c.EP.Accept() returned unexpected error got: %v, want: %s", err, tcpip.ErrWouldBlock)
}
// Send data. This should result in an acceptable endpoint.
c.SendPacket([]byte{1, 2, 3, 4}, &context.Headers{
SrcPort: context.TestPort,
DstPort: context.StackPort,
Flags: header.TCPFlagAck,
SeqNum: irs + 1,
AckNum: iss + 1,
})
// Receive ACK for the data we sent.
checker.IPv4(t, c.GetPacket(), checker.TCP(
checker.DstPort(context.TestPort),
checker.TCPFlags(header.TCPFlagAck),
checker.SeqNum(uint32(iss+1)),
checker.AckNum(uint32(irs+5))))
// Give a bit of time for the socket to be delivered to the accept queue.
time.Sleep(50 * time.Millisecond)
aep, _, err := c.EP.Accept()
if err != nil {
t.Fatalf("c.EP.Accept() returned unexpected error got: %v, want: nil", err)
}
aep.Close()
// Closing aep without reading the data should trigger a RST.
checker.IPv4(t, c.GetPacket(), checker.TCP(
checker.DstPort(context.TestPort),
checker.TCPFlags(header.TCPFlagRst|header.TCPFlagAck),
checker.SeqNum(uint32(iss+1)),
checker.AckNum(uint32(irs+5))))
}
func TestTCPDeferAcceptTimeout(t *testing.T) {
c := context.New(t, defaultMTU)
defer c.Cleanup()
c.Create(-1)
if err := c.EP.Bind(tcpip.FullAddress{Port: context.StackPort}); err != nil {
t.Fatal("Bind failed:", err)
}
if err := c.EP.Listen(10); err != nil {
t.Fatal("Listen failed:", err)
}
const tcpDeferAccept = 1 * time.Second
if err := c.EP.SetSockOpt(tcpip.TCPDeferAcceptOption(tcpDeferAccept)); err != nil {
t.Fatalf("c.EP.SetSockOpt(TCPDeferAcceptOption(%s) failed: %v", tcpDeferAccept, err)
}
irs, iss := executeHandshake(t, c, context.TestPort, false /* synCookiesInUse */)
if _, _, err := c.EP.Accept(); err != tcpip.ErrWouldBlock {
t.Fatalf("c.EP.Accept() returned unexpected error got: %v, want: %s", err, tcpip.ErrWouldBlock)
}
// Sleep for a little of the tcpDeferAccept timeout.
time.Sleep(tcpDeferAccept + 100*time.Millisecond)
// On timeout expiry we should get a SYN-ACK retransmission.
checker.IPv4(t, c.GetPacket(), checker.TCP(
checker.SrcPort(context.StackPort),
checker.DstPort(context.TestPort),
checker.TCPFlags(header.TCPFlagAck|header.TCPFlagSyn),
checker.AckNum(uint32(irs)+1)))
// Send data. This should result in an acceptable endpoint.
c.SendPacket([]byte{1, 2, 3, 4}, &context.Headers{
SrcPort: context.TestPort,
DstPort: context.StackPort,
Flags: header.TCPFlagAck,
SeqNum: irs + 1,
AckNum: iss + 1,
})
// Receive ACK for the data we sent.
checker.IPv4(t, c.GetPacket(), checker.TCP(
checker.SrcPort(context.StackPort),
checker.DstPort(context.TestPort),
checker.TCPFlags(header.TCPFlagAck),
checker.SeqNum(uint32(iss+1)),
checker.AckNum(uint32(irs+5))))
// Give sometime for the endpoint to be delivered to the accept queue.
time.Sleep(50 * time.Millisecond)
aep, _, err := c.EP.Accept()
if err != nil {
t.Fatalf("c.EP.Accept() returned unexpected error got: %v, want: nil", err)
}
aep.Close()
// Closing aep without reading the data should trigger a RST.
checker.IPv4(t, c.GetPacket(), checker.TCP(
checker.SrcPort(context.StackPort),
checker.DstPort(context.TestPort),
checker.TCPFlags(header.TCPFlagRst|header.TCPFlagAck),
checker.SeqNum(uint32(iss+1)),
checker.AckNum(uint32(irs+5))))
}
func TestResetDuringClose(t *testing.T) {
c := context.New(t, defaultMTU)
defer c.Cleanup()
iss := seqnum.Value(789)
c.CreateConnected(iss, 30000, -1 /* epRecvBuf */)
// Send some data to make sure there is some unread
// data to trigger a reset on c.Close.
irs := c.IRS
c.SendPacket([]byte{1, 2, 3, 4}, &context.Headers{
SrcPort: context.TestPort,
DstPort: c.Port,
Flags: header.TCPFlagAck,
SeqNum: iss.Add(1),
AckNum: irs.Add(1),
RcvWnd: 30000,
})
// Receive ACK for the data we sent.
checker.IPv4(t, c.GetPacket(), checker.TCP(
checker.DstPort(context.TestPort),
checker.TCPFlags(header.TCPFlagAck),
checker.SeqNum(uint32(irs.Add(1))),
checker.AckNum(uint32(iss.Add(5)))))
// Close in a separate goroutine so that we can trigger
// a race with the RST we send below. This should not
// panic due to the route being released depeding on
// whether Close() sends an active RST or the RST sent
// below is processed by the worker first.
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
c.SendPacket(nil, &context.Headers{
SrcPort: context.TestPort,
DstPort: c.Port,
SeqNum: iss.Add(5),
AckNum: c.IRS.Add(5),
RcvWnd: 30000,
Flags: header.TCPFlagRst,
})
}()
wg.Add(1)
go func() {
defer wg.Done()
c.EP.Close()
}()
wg.Wait()
}
+2 -2
View File
@@ -19,9 +19,9 @@ source $(dirname $0)/common.sh
install_runsc_for_test iptables
# Build the docker image for the test.
run //test/iptables/runner --norun
run //test/iptables/runner-image --norun
# TODO(gvisor.dev/issue/170): Also test this on runsc once iptables are better
# supported
test //test/iptables:iptables_test "--test_arg=--runtime=runc" \
"--test_arg=--image=bazel/test/iptables/runner:runner"
"--test_arg=--image=bazel/test/iptables/runner:runner-image"
+1 -1
View File
@@ -28,7 +28,7 @@ Your test is now runnable with bazel!
Build the testing Docker container:
```bash
$ bazel run //test/iptables/runner -- --norun
$ bazel run //test/iptables/runner-image -- --norun
```
Run an individual test via:
+1 -1
View File
@@ -30,7 +30,7 @@ import (
const timeout = 18 * time.Second
var image = flag.String("image", "bazel/test/iptables/runner:runner", "image to run tests in")
var image = flag.String("image", "bazel/test/iptables/runner:runner-image", "image to run tests in")
type result struct {
output string
+3
View File
@@ -754,6 +754,7 @@ cc_binary(
":socket_test_util",
"//test/util:cleanup",
"//test/util:eventfd_util",
"//test/util:fs_util",
"//test/util:multiprocess_util",
"//test/util:posix_error",
"//test/util:save_util",
@@ -1391,6 +1392,7 @@ cc_binary(
linkstatic = 1,
deps = [
"//test/util:file_descriptor",
"//test/util:fs_util",
"//test/util:posix_error",
"//test/util:temp_path",
"//test/util:test_main",
@@ -2173,6 +2175,7 @@ cc_library(
":socket_test_util",
"//test/util:test_util",
"//test/util:thread_util",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/time",
"@com_google_googletest//:gtest",
],
+1 -4
View File
@@ -31,6 +31,7 @@
#include "test/syscalls/linux/socket_test_util.h"
#include "test/util/cleanup.h"
#include "test/util/eventfd_util.h"
#include "test/util/fs_util.h"
#include "test/util/multiprocess_util.h"
#include "test/util/posix_error.h"
#include "test/util/save_util.h"
@@ -55,10 +56,6 @@ ABSL_FLAG(int32_t, socket_fd, -1,
namespace gvisor {
namespace testing {
// O_LARGEFILE as defined by Linux. glibc tries to be clever by setting it to 0
// because "it isn't needed", even though Linux can return it via F_GETFL.
constexpr int kOLargeFile = 00100000;
class FcntlLockTest : public ::testing::Test {
public:
void SetUp() override {

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