summaryrefslogtreecommitdiffhomepage
path: root/pkg/tcpip
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/tcpip')
-rw-r--r--pkg/tcpip/link/tun/tun_endpoint_refs.go5
-rw-r--r--pkg/tcpip/tcpip.go13
-rw-r--r--pkg/tcpip/tcpip_state_autogen.go27
-rw-r--r--pkg/tcpip/transport/tcp/endpoint.go33
-rw-r--r--pkg/tcpip/transport/tcp/tcp_state_autogen.go3
5 files changed, 79 insertions, 2 deletions
diff --git a/pkg/tcpip/link/tun/tun_endpoint_refs.go b/pkg/tcpip/link/tun/tun_endpoint_refs.go
index 9a38142f5..e0595429c 100644
--- a/pkg/tcpip/link/tun/tun_endpoint_refs.go
+++ b/pkg/tcpip/link/tun/tun_endpoint_refs.go
@@ -2,10 +2,11 @@ package tun
import (
"fmt"
- "gvisor.dev/gvisor/pkg/log"
- refs_vfs1 "gvisor.dev/gvisor/pkg/refs"
"runtime"
"sync/atomic"
+
+ "gvisor.dev/gvisor/pkg/log"
+ refs_vfs1 "gvisor.dev/gvisor/pkg/refs"
)
// ownerType is used to customize logging. Note that we use a pointer to T so
diff --git a/pkg/tcpip/tcpip.go b/pkg/tcpip/tcpip.go
index 5e34e27ba..b2ddb24ec 100644
--- a/pkg/tcpip/tcpip.go
+++ b/pkg/tcpip/tcpip.go
@@ -1194,6 +1194,19 @@ const (
TCPTimeWaitReuseLoopbackOnly
)
+// LingerOption is used by SetSockOpt/GetSockOpt to set/get the
+// duration for which a socket lingers before returning from Close.
+//
+// +stateify savable
+type LingerOption struct {
+ Enabled bool
+ Timeout time.Duration
+}
+
+func (*LingerOption) isGettableSocketOption() {}
+
+func (*LingerOption) isSettableSocketOption() {}
+
// IPPacketInfo is the message structure for IP_PKTINFO.
//
// +stateify savable
diff --git a/pkg/tcpip/tcpip_state_autogen.go b/pkg/tcpip/tcpip_state_autogen.go
index 827b27692..034b39c1f 100644
--- a/pkg/tcpip/tcpip_state_autogen.go
+++ b/pkg/tcpip/tcpip_state_autogen.go
@@ -111,6 +111,32 @@ func (x *LinkPacketInfo) StateLoad(m state.Source) {
m.Load(1, &x.PktType)
}
+func (x *LingerOption) StateTypeName() string {
+ return "pkg/tcpip.LingerOption"
+}
+
+func (x *LingerOption) StateFields() []string {
+ return []string{
+ "Enabled",
+ "Timeout",
+ }
+}
+
+func (x *LingerOption) beforeSave() {}
+
+func (x *LingerOption) StateSave(m state.Sink) {
+ x.beforeSave()
+ m.Save(0, &x.Enabled)
+ m.Save(1, &x.Timeout)
+}
+
+func (x *LingerOption) afterLoad() {}
+
+func (x *LingerOption) StateLoad(m state.Source) {
+ m.Load(0, &x.Enabled)
+ m.Load(1, &x.Timeout)
+}
+
func (x *IPPacketInfo) StateTypeName() string {
return "pkg/tcpip.IPPacketInfo"
}
@@ -144,5 +170,6 @@ func init() {
state.Register((*FullAddress)(nil))
state.Register((*ControlMessages)(nil))
state.Register((*LinkPacketInfo)(nil))
+ state.Register((*LingerOption)(nil))
state.Register((*IPPacketInfo)(nil))
}
diff --git a/pkg/tcpip/transport/tcp/endpoint.go b/pkg/tcpip/transport/tcp/endpoint.go
index 6d5046a3d..faea7f2bb 100644
--- a/pkg/tcpip/transport/tcp/endpoint.go
+++ b/pkg/tcpip/transport/tcp/endpoint.go
@@ -654,6 +654,9 @@ type endpoint struct {
// owner is used to get uid and gid of the packet.
owner tcpip.PacketOwner
+
+ // linger is used for SO_LINGER socket option.
+ linger tcpip.LingerOption
}
// UniqueID implements stack.TransportEndpoint.UniqueID.
@@ -1007,6 +1010,26 @@ func (e *endpoint) Close() {
return
}
+ if e.linger.Enabled && e.linger.Timeout == 0 {
+ s := e.EndpointState()
+ isResetState := s == StateEstablished || s == StateCloseWait || s == StateFinWait1 || s == StateFinWait2 || s == StateSynRecv
+ if isResetState {
+ // Close the endpoint without doing full shutdown and
+ // send a RST.
+ e.resetConnectionLocked(tcpip.ErrConnectionAborted)
+ e.closeNoShutdownLocked()
+
+ // Wake up worker to close the endpoint.
+ switch s {
+ case StateSynRecv:
+ e.notifyProtocolGoroutine(notifyClose)
+ default:
+ e.notifyProtocolGoroutine(notifyTickleWorker)
+ }
+ return
+ }
+ }
+
// Issue a shutdown so that the peer knows we won't send any more data
// if we're connected, or stop accepting if we're listening.
e.shutdownLocked(tcpip.ShutdownWrite | tcpip.ShutdownRead)
@@ -1807,6 +1830,11 @@ func (e *endpoint) SetSockOpt(opt tcpip.SettableSocketOption) *tcpip.Error {
case *tcpip.SocketDetachFilterOption:
return nil
+ case *tcpip.LingerOption:
+ e.LockUser()
+ e.linger = *v
+ e.UnlockUser()
+
default:
return nil
}
@@ -2031,6 +2059,11 @@ func (e *endpoint) GetSockOpt(opt tcpip.GettableSocketOption) *tcpip.Error {
Port: port,
}
+ case *tcpip.LingerOption:
+ e.LockUser()
+ *o = e.linger
+ e.UnlockUser()
+
default:
return tcpip.ErrUnknownProtocolOption
}
diff --git a/pkg/tcpip/transport/tcp/tcp_state_autogen.go b/pkg/tcpip/transport/tcp/tcp_state_autogen.go
index bed45e9a1..77e0d0e97 100644
--- a/pkg/tcpip/transport/tcp/tcp_state_autogen.go
+++ b/pkg/tcpip/transport/tcp/tcp_state_autogen.go
@@ -222,6 +222,7 @@ func (x *endpoint) StateFields() []string {
"closed",
"txHash",
"owner",
+ "linger",
}
}
@@ -293,6 +294,7 @@ func (x *endpoint) StateSave(m state.Sink) {
m.Save(59, &x.closed)
m.Save(60, &x.txHash)
m.Save(61, &x.owner)
+ m.Save(62, &x.linger)
}
func (x *endpoint) StateLoad(m state.Source) {
@@ -354,6 +356,7 @@ func (x *endpoint) StateLoad(m state.Source) {
m.Load(59, &x.closed)
m.Load(60, &x.txHash)
m.Load(61, &x.owner)
+ m.Load(62, &x.linger)
m.LoadValue(3, new(string), func(y interface{}) { x.loadLastError(y.(string)) })
m.LoadValue(10, new(EndpointState), func(y interface{}) { x.loadState(y.(EndpointState)) })
m.LoadValue(25, new(unixTime), func(y interface{}) { x.loadRecentTSTime(y.(unixTime)) })