mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add a raw socket transport endpoint and use it for raw ICMP sockets.
Having raw socket code together will make it easier to add support for other raw network protocols. Currently, only ICMP uses the raw endpoint. However, adding support for other protocols such as UDP shouldn't be much more difficult than adding a few switch cases. PiperOrigin-RevId: 241564875 Change-Id: I77e03adafe4ce0fd29ba2d5dfdc547d2ae8f25bf
This commit is contained in:
committed by
Shentubot
parent
1df3fa6997
commit
52a51a8e20
@@ -64,13 +64,24 @@ const (
|
||||
type TransportEndpoint interface {
|
||||
// HandlePacket is called by the stack when new packets arrive to
|
||||
// this transport endpoint.
|
||||
HandlePacket(r *Route, id TransportEndpointID, netHeader buffer.View, vv buffer.VectorisedView)
|
||||
HandlePacket(r *Route, id TransportEndpointID, vv buffer.VectorisedView)
|
||||
|
||||
// HandleControlPacket is called by the stack when new control (e.g.,
|
||||
// ICMP) packets arrive to this transport endpoint.
|
||||
HandleControlPacket(id TransportEndpointID, typ ControlType, extra uint32, vv buffer.VectorisedView)
|
||||
}
|
||||
|
||||
// RawTransportEndpoint is the interface that needs to be implemented by raw
|
||||
// transport protocol endpoints. RawTransportEndpoints receive the entire
|
||||
// packet - including the link, network, and transport headers - as delivered
|
||||
// to netstack.
|
||||
type RawTransportEndpoint interface {
|
||||
// HandlePacket is called by the stack when new packets arrive to
|
||||
// this transport endpoint. The packet contains all data from the link
|
||||
// layer up.
|
||||
HandlePacket(r *Route, netHeader buffer.View, packet buffer.VectorisedView)
|
||||
}
|
||||
|
||||
// TransportProtocol is the interface that needs to be implemented by transport
|
||||
// protocols (e.g., tcp, udp) that want to be part of the networking stack.
|
||||
type TransportProtocol interface {
|
||||
|
||||
+10
-10
@@ -955,11 +955,11 @@ func (s *Stack) UnregisterTransportEndpoint(nicID tcpip.NICID, netProtos []tcpip
|
||||
}
|
||||
|
||||
// RegisterRawTransportEndpoint registers the given endpoint with the stack
|
||||
// transport dispatcher. Received packets that match the provided protocol will
|
||||
// be delivered to the given endpoint.
|
||||
func (s *Stack) RegisterRawTransportEndpoint(nicID tcpip.NICID, netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, ep TransportEndpoint, reusePort bool) *tcpip.Error {
|
||||
// transport dispatcher. Received packets that match the provided transport
|
||||
// protocol will be delivered to the given endpoint.
|
||||
func (s *Stack) RegisterRawTransportEndpoint(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, ep RawTransportEndpoint) *tcpip.Error {
|
||||
if nicID == 0 {
|
||||
return s.demux.registerRawEndpoint(netProtos, protocol, ep, reusePort)
|
||||
return s.demux.registerRawEndpoint(netProto, transProto, ep)
|
||||
}
|
||||
|
||||
s.mu.RLock()
|
||||
@@ -970,14 +970,14 @@ func (s *Stack) RegisterRawTransportEndpoint(nicID tcpip.NICID, netProtos []tcpi
|
||||
return tcpip.ErrUnknownNICID
|
||||
}
|
||||
|
||||
return nic.demux.registerRawEndpoint(netProtos, protocol, ep, reusePort)
|
||||
return nic.demux.registerRawEndpoint(netProto, transProto, ep)
|
||||
}
|
||||
|
||||
// UnregisterRawTransportEndpoint removes the endpoint for the protocol from
|
||||
// the stack transport dispatcher.
|
||||
func (s *Stack) UnregisterRawTransportEndpoint(nicID tcpip.NICID, netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, ep TransportEndpoint) {
|
||||
// UnregisterRawTransportEndpoint removes the endpoint for the transport
|
||||
// protocol from the stack transport dispatcher.
|
||||
func (s *Stack) UnregisterRawTransportEndpoint(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, ep RawTransportEndpoint) {
|
||||
if nicID == 0 {
|
||||
s.demux.unregisterRawEndpoint(netProtos, protocol, ep)
|
||||
s.demux.unregisterRawEndpoint(netProto, transProto, ep)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -986,7 +986,7 @@ func (s *Stack) UnregisterRawTransportEndpoint(nicID tcpip.NICID, netProtos []tc
|
||||
|
||||
nic := s.nics[nicID]
|
||||
if nic != nil {
|
||||
nic.demux.unregisterRawEndpoint(netProtos, protocol, ep)
|
||||
nic.demux.unregisterRawEndpoint(netProto, transProto, ep)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package stack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
|
||||
@@ -37,7 +38,7 @@ type transportEndpoints struct {
|
||||
endpoints map[TransportEndpointID]TransportEndpoint
|
||||
// rawEndpoints contains endpoints for raw sockets, which receive all
|
||||
// traffic of a given protocol regardless of port.
|
||||
rawEndpoints []TransportEndpoint
|
||||
rawEndpoints []RawTransportEndpoint
|
||||
}
|
||||
|
||||
// unregisterEndpoint unregisters the endpoint with the given id such that it
|
||||
@@ -60,8 +61,10 @@ func (eps *transportEndpoints) unregisterEndpoint(id TransportEndpointID, ep Tra
|
||||
// transportDemuxer demultiplexes packets targeted at a transport endpoint
|
||||
// (i.e., after they've been parsed by the network layer). It does two levels
|
||||
// of demultiplexing: first based on the network and transport protocols, then
|
||||
// based on endpoints IDs.
|
||||
// based on endpoints IDs. It should only be instantiated via
|
||||
// newTransportDemuxer.
|
||||
type transportDemuxer struct {
|
||||
// protocol is immutable.
|
||||
protocol map[protocolIDs]*transportEndpoints
|
||||
}
|
||||
|
||||
@@ -137,22 +140,22 @@ func (ep *multiPortEndpoint) selectEndpoint(id TransportEndpointID) TransportEnd
|
||||
|
||||
// HandlePacket is called by the stack when new packets arrive to this transport
|
||||
// endpoint.
|
||||
func (ep *multiPortEndpoint) HandlePacket(r *Route, id TransportEndpointID, netHeader buffer.View, vv buffer.VectorisedView) {
|
||||
func (ep *multiPortEndpoint) HandlePacket(r *Route, id TransportEndpointID, vv buffer.VectorisedView) {
|
||||
// If this is a broadcast datagram, deliver the datagram to all endpoints
|
||||
// managed by ep.
|
||||
if id.LocalAddress == header.IPv4Broadcast {
|
||||
for i, endpoint := range ep.endpointsArr {
|
||||
// HandlePacket modifies vv, so each endpoint needs its own copy.
|
||||
if i == len(ep.endpointsArr)-1 {
|
||||
endpoint.HandlePacket(r, id, netHeader, vv)
|
||||
endpoint.HandlePacket(r, id, vv)
|
||||
break
|
||||
}
|
||||
vvCopy := buffer.NewView(vv.Size())
|
||||
copy(vvCopy, vv.ToView())
|
||||
endpoint.HandlePacket(r, id, buffer.NewViewFromBytes(netHeader), vvCopy.ToVectorisedView())
|
||||
endpoint.HandlePacket(r, id, vvCopy.ToVectorisedView())
|
||||
}
|
||||
} else {
|
||||
ep.selectEndpoint(id).HandlePacket(r, id, netHeader, vv)
|
||||
ep.selectEndpoint(id).HandlePacket(r, id, vv)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,17 +289,17 @@ func (d *transportDemuxer) deliverPacket(r *Route, protocol tcpip.TransportProto
|
||||
// As in net/ipv4/ip_input.c:ip_local_deliver, attempt to deliver via
|
||||
// raw endpoint first. If there are multipe raw endpoints, they all
|
||||
// receive the packet.
|
||||
found := false
|
||||
foundRaw := false
|
||||
for _, rawEP := range eps.rawEndpoints {
|
||||
// Each endpoint gets its own copy of the packet for the sake
|
||||
// of save/restore.
|
||||
rawEP.HandlePacket(r, id, buffer.NewViewFromBytes(netHeader), vv.ToView().ToVectorisedView())
|
||||
found = true
|
||||
rawEP.HandlePacket(r, buffer.NewViewFromBytes(netHeader), vv.ToView().ToVectorisedView())
|
||||
foundRaw = true
|
||||
}
|
||||
eps.mu.RUnlock()
|
||||
|
||||
// Fail if we didn't find at least one matching transport endpoint.
|
||||
if len(destEps) == 0 && !found {
|
||||
if len(destEps) == 0 && !foundRaw {
|
||||
// UDP packet could not be delivered to an unknown destination port.
|
||||
if protocol == header.UDPProtocolNumber {
|
||||
r.Stats().UDP.UnknownPortErrors.Increment()
|
||||
@@ -306,7 +309,7 @@ func (d *transportDemuxer) deliverPacket(r *Route, protocol tcpip.TransportProto
|
||||
|
||||
// Deliver the packet.
|
||||
for _, ep := range destEps {
|
||||
ep.HandlePacket(r, id, netHeader, vv)
|
||||
ep.HandlePacket(r, id, vv)
|
||||
}
|
||||
|
||||
return true
|
||||
@@ -371,19 +374,8 @@ func (d *transportDemuxer) findEndpointLocked(eps *transportEndpoints, vv buffer
|
||||
// that packets of the appropriate protocol are delivered to it. A single
|
||||
// packet can be sent to one or more raw endpoints along with a non-raw
|
||||
// endpoint.
|
||||
func (d *transportDemuxer) registerRawEndpoint(netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, ep TransportEndpoint, reusePort bool) *tcpip.Error {
|
||||
for i, n := range netProtos {
|
||||
if err := d.singleRegisterRawEndpoint(n, protocol, ep); err != nil {
|
||||
d.unregisterRawEndpoint(netProtos[:i], protocol, ep)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *transportDemuxer) singleRegisterRawEndpoint(netProto tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, ep TransportEndpoint) *tcpip.Error {
|
||||
eps, ok := d.protocol[protocolIDs{netProto, protocol}]
|
||||
func (d *transportDemuxer) registerRawEndpoint(netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, ep RawTransportEndpoint) *tcpip.Error {
|
||||
eps, ok := d.protocol[protocolIDs{netProto, transProto}]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
@@ -395,19 +387,20 @@ func (d *transportDemuxer) singleRegisterRawEndpoint(netProto tcpip.NetworkProto
|
||||
return nil
|
||||
}
|
||||
|
||||
// unregisterRawEndpoint unregisters the raw endpoint for the given protocol
|
||||
// such that it won't receive any more packets.
|
||||
func (d *transportDemuxer) unregisterRawEndpoint(netProtos []tcpip.NetworkProtocolNumber, protocol tcpip.TransportProtocolNumber, ep TransportEndpoint) {
|
||||
for _, n := range netProtos {
|
||||
if eps, ok := d.protocol[protocolIDs{n, protocol}]; ok {
|
||||
eps.mu.Lock()
|
||||
defer eps.mu.Unlock()
|
||||
for i, rawEP := range eps.rawEndpoints {
|
||||
if rawEP == ep {
|
||||
eps.rawEndpoints = append(eps.rawEndpoints[:i], eps.rawEndpoints[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
// unregisterRawEndpoint unregisters the raw endpoint for the given transport
|
||||
// protocol such that it won't receive any more packets.
|
||||
func (d *transportDemuxer) unregisterRawEndpoint(netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, ep RawTransportEndpoint) {
|
||||
eps, ok := d.protocol[protocolIDs{netProto, transProto}]
|
||||
if !ok {
|
||||
panic(fmt.Errorf("tried to unregister endpoint with unsupported network and transport protocol pair: %d, %d", netProto, transProto))
|
||||
}
|
||||
|
||||
eps.mu.Lock()
|
||||
defer eps.mu.Unlock()
|
||||
for i, rawEP := range eps.rawEndpoints {
|
||||
if rawEP == ep {
|
||||
eps.rawEndpoints = append(eps.rawEndpoints[:i], eps.rawEndpoints[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ func (*fakeTransportEndpoint) GetRemoteAddress() (tcpip.FullAddress, *tcpip.Erro
|
||||
return tcpip.FullAddress{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeTransportEndpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, _ buffer.View, _ buffer.VectorisedView) {
|
||||
func (f *fakeTransportEndpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, _ buffer.VectorisedView) {
|
||||
// Increment the number of received packets.
|
||||
f.proto.packetCount++
|
||||
if f.acceptQueue != nil {
|
||||
|
||||
@@ -32,6 +32,7 @@ go_library(
|
||||
"//pkg/tcpip/buffer",
|
||||
"//pkg/tcpip/header",
|
||||
"//pkg/tcpip/stack",
|
||||
"//pkg/tcpip/transport/raw",
|
||||
"//pkg/waiter",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -59,10 +59,6 @@ type endpoint struct {
|
||||
netProto tcpip.NetworkProtocolNumber
|
||||
transProto tcpip.TransportProtocolNumber
|
||||
waiterQueue *waiter.Queue
|
||||
// raw indicates whether the endpoint is intended for use by a raw
|
||||
// socket, which returns the network layer header along with the
|
||||
// payload. It is immutable.
|
||||
raw bool
|
||||
|
||||
// The following fields are used to manage the receive queue, and are
|
||||
// protected by rcvMu.
|
||||
@@ -80,32 +76,26 @@ type endpoint struct {
|
||||
shutdownFlags tcpip.ShutdownFlags
|
||||
id stack.TransportEndpointID
|
||||
state endpointState
|
||||
bindNICID tcpip.NICID
|
||||
bindAddr tcpip.Address
|
||||
regNICID tcpip.NICID
|
||||
route stack.Route `state:"manual"`
|
||||
// bindNICID and bindAddr are set via calls to Bind(). They are used to
|
||||
// reject attempts to send data or connect via a different NIC or
|
||||
// address
|
||||
bindNICID tcpip.NICID
|
||||
bindAddr tcpip.Address
|
||||
// regNICID is the default NIC to be used when callers don't specify a
|
||||
// NIC.
|
||||
regNICID tcpip.NICID
|
||||
route stack.Route `state:"manual"`
|
||||
}
|
||||
|
||||
func newEndpoint(stack *stack.Stack, netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, waiterQueue *waiter.Queue, raw bool) (*endpoint, *tcpip.Error) {
|
||||
e := &endpoint{
|
||||
func newEndpoint(stack *stack.Stack, netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, *tcpip.Error) {
|
||||
return &endpoint{
|
||||
stack: stack,
|
||||
netProto: netProto,
|
||||
transProto: transProto,
|
||||
waiterQueue: waiterQueue,
|
||||
rcvBufSizeMax: 32 * 1024,
|
||||
sndBufSize: 32 * 1024,
|
||||
raw: raw,
|
||||
}
|
||||
|
||||
// Raw endpoints must be immediately bound because they receive all
|
||||
// ICMP traffic starting from when they're created via socket().
|
||||
if raw {
|
||||
if err := e.bindLocked(tcpip.FullAddress{}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Close puts the endpoint in a closed state and frees all resources
|
||||
@@ -115,11 +105,7 @@ func (e *endpoint) Close() {
|
||||
e.shutdownFlags = tcpip.ShutdownRead | tcpip.ShutdownWrite
|
||||
switch e.state {
|
||||
case stateBound, stateConnected:
|
||||
if e.raw {
|
||||
e.stack.UnregisterRawTransportEndpoint(e.regNICID, []tcpip.NetworkProtocolNumber{e.netProto}, e.transProto, e)
|
||||
} else {
|
||||
e.stack.UnregisterTransportEndpoint(e.regNICID, []tcpip.NetworkProtocolNumber{e.netProto}, e.transProto, e.id, e)
|
||||
}
|
||||
e.stack.UnregisterTransportEndpoint(e.regNICID, []tcpip.NetworkProtocolNumber{e.netProto}, e.transProto, e.id, e)
|
||||
}
|
||||
|
||||
// Close the receive list and drain it.
|
||||
@@ -244,8 +230,9 @@ func (e *endpoint) Write(p tcpip.Payload, opts tcpip.WriteOptions) (uintptr, <-c
|
||||
route = &e.route
|
||||
|
||||
if route.IsResolutionRequired() {
|
||||
// Promote lock to exclusive if using a shared route, given that it may
|
||||
// need to change in Route.Resolve() call below.
|
||||
// Promote lock to exclusive if using a shared route,
|
||||
// given that it may need to change in Route.Resolve()
|
||||
// call below.
|
||||
e.mu.RUnlock()
|
||||
defer e.mu.RLock()
|
||||
|
||||
@@ -290,8 +277,9 @@ func (e *endpoint) Write(p tcpip.Payload, opts tcpip.WriteOptions) (uintptr, <-c
|
||||
waker := &sleep.Waker{}
|
||||
if ch, err := route.Resolve(waker); err != nil {
|
||||
if err == tcpip.ErrWouldBlock {
|
||||
// Link address needs to be resolved. Resolution was triggered the
|
||||
// background. Better luck next time.
|
||||
// Link address needs to be resolved.
|
||||
// Resolution was triggered the background.
|
||||
// Better luck next time.
|
||||
route.RemoveWaker(waker)
|
||||
return 0, ch, tcpip.ErrNoLinkAddress
|
||||
}
|
||||
@@ -368,11 +356,6 @@ func (e *endpoint) GetSockOpt(opt interface{}) *tcpip.Error {
|
||||
}
|
||||
|
||||
func (e *endpoint) send4(r *stack.Route, data buffer.View) *tcpip.Error {
|
||||
if e.raw {
|
||||
hdr := buffer.NewPrependable(len(data) + int(r.MaxHeaderLength()))
|
||||
return r.WritePacket(nil /* gso */, hdr, data.ToVectorisedView(), header.ICMPv4ProtocolNumber, r.DefaultTTL())
|
||||
}
|
||||
|
||||
if len(data) < header.ICMPv4EchoMinimumSize {
|
||||
return tcpip.ErrInvalidEndpointState
|
||||
}
|
||||
@@ -439,11 +422,6 @@ func (e *endpoint) checkV4Mapped(addr *tcpip.FullAddress, allowMismatch bool) (t
|
||||
|
||||
// Connect connects the endpoint to its peer. Specifying a NIC is optional.
|
||||
func (e *endpoint) Connect(addr tcpip.FullAddress) *tcpip.Error {
|
||||
// TODO: We don't yet support connect on a raw socket.
|
||||
if e.raw {
|
||||
return tcpip.ErrNotSupported
|
||||
}
|
||||
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
@@ -547,11 +525,6 @@ func (*endpoint) Accept() (tcpip.Endpoint, *waiter.Queue, *tcpip.Error) {
|
||||
}
|
||||
|
||||
func (e *endpoint) registerWithStack(nicid tcpip.NICID, netProtos []tcpip.NetworkProtocolNumber, id stack.TransportEndpointID) (stack.TransportEndpointID, *tcpip.Error) {
|
||||
if e.raw {
|
||||
err := e.stack.RegisterRawTransportEndpoint(nicid, netProtos, e.transProto, e, false)
|
||||
return stack.TransportEndpointID{}, err
|
||||
}
|
||||
|
||||
if id.LocalPort != 0 {
|
||||
// The endpoint already has a local port, just attempt to
|
||||
// register it.
|
||||
@@ -687,11 +660,12 @@ func (e *endpoint) Readiness(mask waiter.EventMask) waiter.EventMask {
|
||||
|
||||
// HandlePacket is called by the stack when new packets arrive to this transport
|
||||
// endpoint.
|
||||
func (e *endpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, netHeader buffer.View, vv buffer.VectorisedView) {
|
||||
func (e *endpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, vv buffer.VectorisedView) {
|
||||
e.rcvMu.Lock()
|
||||
|
||||
// Drop the packet if our buffer is currently full.
|
||||
if !e.rcvReady || e.rcvClosed || e.rcvBufSize >= e.rcvBufSizeMax {
|
||||
e.stack.Stats().DroppedPackets.Increment()
|
||||
e.rcvMu.Unlock()
|
||||
return
|
||||
}
|
||||
@@ -706,13 +680,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, ne
|
||||
},
|
||||
}
|
||||
|
||||
if e.raw {
|
||||
combinedVV := netHeader.ToVectorisedView()
|
||||
combinedVV.Append(vv)
|
||||
pkt.data = combinedVV.Clone(pkt.views[:])
|
||||
} else {
|
||||
pkt.data = vv.Clone(pkt.views[:])
|
||||
}
|
||||
pkt.data = vv.Clone(pkt.views[:])
|
||||
|
||||
e.rcvList.PushBack(pkt)
|
||||
e.rcvBufSize += pkt.data.Size()
|
||||
|
||||
@@ -30,6 +30,7 @@ import (
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/header"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/stack"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/transport/raw"
|
||||
"gvisor.googlesource.com/gvisor/pkg/waiter"
|
||||
)
|
||||
|
||||
@@ -73,7 +74,7 @@ func (p *protocol) NewEndpoint(stack *stack.Stack, netProto tcpip.NetworkProtoco
|
||||
if netProto != p.netProto() {
|
||||
return nil, tcpip.ErrUnknownProtocol
|
||||
}
|
||||
return newEndpoint(stack, netProto, p.number, waiterQueue, false)
|
||||
return newEndpoint(stack, netProto, p.number, waiterQueue)
|
||||
}
|
||||
|
||||
// NewRawEndpoint creates a new raw icmp endpoint. It implements
|
||||
@@ -82,7 +83,7 @@ func (p *protocol) NewRawEndpoint(stack *stack.Stack, netProto tcpip.NetworkProt
|
||||
if netProto != p.netProto() {
|
||||
return nil, tcpip.ErrUnknownProtocol
|
||||
}
|
||||
return newEndpoint(stack, netProto, p.number, waiterQueue, true)
|
||||
return raw.NewEndpoint(stack, netProto, p.number, waiterQueue)
|
||||
}
|
||||
|
||||
// MinimumPacketSize returns the minimum valid icmp packet size.
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package(licenses = ["notice"]) # Apache 2.0
|
||||
|
||||
load("//tools/go_generics:defs.bzl", "go_template_instance")
|
||||
load("//tools/go_stateify:defs.bzl", "go_library")
|
||||
|
||||
go_template_instance(
|
||||
name = "packet_list",
|
||||
out = "packet_list.go",
|
||||
package = "raw",
|
||||
prefix = "packet",
|
||||
template = "//pkg/ilist:generic_list",
|
||||
types = {
|
||||
"Element": "*packet",
|
||||
"Linker": "*packet",
|
||||
},
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "raw",
|
||||
srcs = [
|
||||
"packet_list.go",
|
||||
"raw.go",
|
||||
"state.go",
|
||||
],
|
||||
importpath = "gvisor.googlesource.com/gvisor/pkg/tcpip/transport/raw",
|
||||
imports = ["gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/log",
|
||||
"//pkg/sleep",
|
||||
"//pkg/tcpip",
|
||||
"//pkg/tcpip/buffer",
|
||||
"//pkg/tcpip/header",
|
||||
"//pkg/tcpip/stack",
|
||||
"//pkg/waiter",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "autogen",
|
||||
srcs = [
|
||||
"packet_list.go",
|
||||
],
|
||||
visibility = ["//:sandbox"],
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,88 @@
|
||||
// Copyright 2018 Google LLC
|
||||
//
|
||||
// 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 raw
|
||||
|
||||
import (
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
|
||||
"gvisor.googlesource.com/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
// saveData saves packet.data field.
|
||||
func (p *packet) saveData() buffer.VectorisedView {
|
||||
// We cannot save p.data directly as p.data.views may alias to p.views,
|
||||
// which is not allowed by state framework (in-struct pointer).
|
||||
return p.data.Clone(nil)
|
||||
}
|
||||
|
||||
// loadData loads packet.data field.
|
||||
func (p *packet) loadData(data buffer.VectorisedView) {
|
||||
// NOTE: We cannot do the p.data = data.Clone(p.views[:]) optimization
|
||||
// here because data.views is not guaranteed to be loaded by now. Plus,
|
||||
// data.views will be allocated anyway so there really is little point
|
||||
// of utilizing p.views for data.views.
|
||||
p.data = data
|
||||
}
|
||||
|
||||
// beforeSave is invoked by stateify.
|
||||
func (ep *endpoint) beforeSave() {
|
||||
// Stop incoming packets from being handled (and mutate endpoint state).
|
||||
// The lock will be released after saveRcvBufSizeMax(), which would have
|
||||
// saved ep.rcvBufSizeMax and set it to 0 to continue blocking incoming
|
||||
// packets.
|
||||
ep.rcvMu.Lock()
|
||||
}
|
||||
|
||||
// saveRcvBufSizeMax is invoked by stateify.
|
||||
func (ep *endpoint) saveRcvBufSizeMax() int {
|
||||
max := ep.rcvBufSizeMax
|
||||
// Make sure no new packets will be handled regardless of the lock.
|
||||
ep.rcvBufSizeMax = 0
|
||||
// Release the lock acquired in beforeSave() so regular endpoint closing
|
||||
// logic can proceed after save.
|
||||
ep.rcvMu.Unlock()
|
||||
return max
|
||||
}
|
||||
|
||||
// loadRcvBufSizeMax is invoked by stateify.
|
||||
func (ep *endpoint) loadRcvBufSizeMax(max int) {
|
||||
ep.rcvBufSizeMax = max
|
||||
}
|
||||
|
||||
// afterLoad is invoked by stateify.
|
||||
func (ep *endpoint) afterLoad() {
|
||||
// StackFromEnv is a stack used specifically for save/restore.
|
||||
ep.stack = stack.StackFromEnv
|
||||
|
||||
// If the endpoint is connected, re-connect via the save/restore stack.
|
||||
if ep.connected {
|
||||
var err *tcpip.Error
|
||||
ep.route, err = ep.stack.FindRoute(ep.registeredNIC, ep.boundAddr, ep.route.RemoteAddress, ep.netProto, false)
|
||||
if err != nil {
|
||||
panic(*err)
|
||||
}
|
||||
}
|
||||
|
||||
// If the endpoint is bound, re-bind via the save/restore stack.
|
||||
if ep.bound {
|
||||
if ep.stack.CheckLocalAddress(ep.registeredNIC, ep.netProto, ep.boundAddr) == 0 {
|
||||
panic(tcpip.ErrBadLocalAddress)
|
||||
}
|
||||
}
|
||||
|
||||
if err := ep.stack.RegisterRawTransportEndpoint(ep.registeredNIC, ep.netProto, ep.transProto, ep); err != nil {
|
||||
panic(*err)
|
||||
}
|
||||
}
|
||||
@@ -1438,7 +1438,7 @@ func (e *endpoint) GetRemoteAddress() (tcpip.FullAddress, *tcpip.Error) {
|
||||
|
||||
// HandlePacket is called by the stack when new packets arrive to this transport
|
||||
// endpoint.
|
||||
func (e *endpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, netHeader buffer.View, vv buffer.VectorisedView) {
|
||||
func (e *endpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, vv buffer.VectorisedView) {
|
||||
s := newSegment(r, id, vv)
|
||||
if !s.parse() {
|
||||
e.stack.Stats().MalformedRcvdPackets.Increment()
|
||||
|
||||
@@ -940,7 +940,7 @@ func (e *endpoint) Readiness(mask waiter.EventMask) waiter.EventMask {
|
||||
|
||||
// HandlePacket is called by the stack when new packets arrive to this transport
|
||||
// endpoint.
|
||||
func (e *endpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, netHeader buffer.View, vv buffer.VectorisedView) {
|
||||
func (e *endpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, vv buffer.VectorisedView) {
|
||||
// Get the header then trim it from the view.
|
||||
hdr := header.UDP(vv.First())
|
||||
if int(hdr.Length()) > vv.Size() {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user