| // Copyright 2018 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 tcpip provides the interfaces and related types that users of the |
| // tcpip stack will use in order to create endpoints used to send and receive |
| // data over the network stack. |
| // |
| // The starting point is the creation and configuration of a stack. A stack can |
| // be created by calling the New() function of the tcpip/stack/stack package; |
| // configuring a stack involves creating NICs (via calls to Stack.CreateNIC()), |
| // adding network addresses (via calls to Stack.AddAddress()), and |
| // setting a route table (via a call to Stack.SetRouteTable()). |
| // |
| // Once a stack is configured, endpoints can be created by calling |
| // Stack.NewEndpoint(). Such endpoints can be used to send/receive data, connect |
| // to peers, listen for connections, accept connections, etc., depending on the |
| // transport protocol selected. |
| package tcpip |
| |
| import ( |
| "bytes" |
| "errors" |
| "fmt" |
| "io" |
| "math/bits" |
| "reflect" |
| "strconv" |
| "strings" |
| "sync/atomic" |
| "time" |
| |
| "gvisor.dev/gvisor/pkg/sync" |
| "gvisor.dev/gvisor/pkg/waiter" |
| ) |
| |
| // Using header.IPv4AddressSize would cause an import cycle. |
| const ipv4AddressSize = 4 |
| |
| // Errors related to Subnet |
| var ( |
| errSubnetLengthMismatch = errors.New("subnet length of address and mask differ") |
| errSubnetAddressMasked = errors.New("subnet address has bits set outside the mask") |
| ) |
| |
| // ErrSaveRejection indicates a failed save due to unsupported networking state. |
| // This type of errors is only used for save logic. |
| type ErrSaveRejection struct { |
| Err error |
| } |
| |
| // Error returns a sensible description of the save rejection error. |
| func (e *ErrSaveRejection) Error() string { |
| return "save rejected due to unsupported networking state: " + e.Err.Error() |
| } |
| |
| // A Clock provides the current time and schedules work for execution. |
| // |
| // Times returned by a Clock should always be used for application-visible |
| // time. Only monotonic times should be used for netstack internal timekeeping. |
| type Clock interface { |
| // NowNanoseconds returns the current real time as a number of |
| // nanoseconds since the Unix epoch. |
| NowNanoseconds() int64 |
| |
| // NowMonotonic returns a monotonic time value. |
| NowMonotonic() int64 |
| |
| // AfterFunc waits for the duration to elapse and then calls f in its own |
| // goroutine. It returns a Timer that can be used to cancel the call using |
| // its Stop method. |
| AfterFunc(d time.Duration, f func()) Timer |
| } |
| |
| // Timer represents a single event. A Timer must be created with |
| // Clock.AfterFunc. |
| type Timer interface { |
| // Stop prevents the Timer from firing. It returns true if the call stops the |
| // timer, false if the timer has already expired or been stopped. |
| // |
| // If Stop returns false, then the timer has already expired and the function |
| // f of Clock.AfterFunc(d, f) has been started in its own goroutine; Stop |
| // does not wait for f to complete before returning. If the caller needs to |
| // know whether f is completed, it must coordinate with f explicitly. |
| Stop() bool |
| |
| // Reset changes the timer to expire after duration d. |
| // |
| // Reset should be invoked only on stopped or expired timers. If the timer is |
| // known to have expired, Reset can be used directly. Otherwise, the caller |
| // must coordinate with the function f of Clock.AfterFunc(d, f). |
| Reset(d time.Duration) |
| } |
| |
| // Address is a byte slice cast as a string that represents the address of a |
| // network node. Or, in the case of unix endpoints, it may represent a path. |
| type Address string |
| |
| // WithPrefix returns the address with a prefix that represents a point subnet. |
| func (a Address) WithPrefix() AddressWithPrefix { |
| return AddressWithPrefix{ |
| Address: a, |
| PrefixLen: len(a) * 8, |
| } |
| } |
| |
| // Unspecified returns true if the address is unspecified. |
| func (a Address) Unspecified() bool { |
| for _, b := range a { |
| if b != 0 { |
| return false |
| } |
| } |
| return true |
| } |
| |
| // MatchingPrefix returns the matching prefix length in bits. |
| // |
| // Panics if b and a have different lengths. |
| func (a Address) MatchingPrefix(b Address) uint8 { |
| const bitsInAByte = 8 |
| |
| if len(a) != len(b) { |
| panic(fmt.Sprintf("addresses %s and %s do not have the same length", a, b)) |
| } |
| |
| var prefix uint8 |
| for i := range a { |
| aByte := a[i] |
| bByte := b[i] |
| |
| if aByte == bByte { |
| prefix += bitsInAByte |
| continue |
| } |
| |
| // Count the remaining matching bits in the byte from MSbit to LSBbit. |
| mask := uint8(1) << (bitsInAByte - 1) |
| for { |
| if aByte&mask == bByte&mask { |
| prefix++ |
| mask >>= 1 |
| continue |
| } |
| |
| break |
| } |
| |
| break |
| } |
| |
| return prefix |
| } |
| |
| // AddressMask is a bitmask for an address. |
| type AddressMask string |
| |
| // String implements Stringer. |
| func (m AddressMask) String() string { |
| return Address(m).String() |
| } |
| |
| // Prefix returns the number of bits before the first host bit. |
| func (m AddressMask) Prefix() int { |
| p := 0 |
| for _, b := range []byte(m) { |
| p += bits.LeadingZeros8(^b) |
| } |
| return p |
| } |
| |
| // Subnet is a subnet defined by its address and mask. |
| type Subnet struct { |
| address Address |
| mask AddressMask |
| } |
| |
| // NewSubnet creates a new Subnet, checking that the address and mask are the same length. |
| func NewSubnet(a Address, m AddressMask) (Subnet, error) { |
| if len(a) != len(m) { |
| return Subnet{}, errSubnetLengthMismatch |
| } |
| for i := 0; i < len(a); i++ { |
| if a[i]&^m[i] != 0 { |
| return Subnet{}, errSubnetAddressMasked |
| } |
| } |
| return Subnet{a, m}, nil |
| } |
| |
| // String implements Stringer. |
| func (s Subnet) String() string { |
| return fmt.Sprintf("%s/%d", s.ID(), s.Prefix()) |
| } |
| |
| // Contains returns true iff the address is of the same length and matches the |
| // subnet address and mask. |
| func (s *Subnet) Contains(a Address) bool { |
| if len(a) != len(s.address) { |
| return false |
| } |
| for i := 0; i < len(a); i++ { |
| if a[i]&s.mask[i] != s.address[i] { |
| return false |
| } |
| } |
| return true |
| } |
| |
| // ID returns the subnet ID. |
| func (s *Subnet) ID() Address { |
| return s.address |
| } |
| |
| // Bits returns the number of ones (network bits) and zeros (host bits) in the |
| // subnet mask. |
| func (s *Subnet) Bits() (ones int, zeros int) { |
| ones = s.mask.Prefix() |
| return ones, len(s.mask)*8 - ones |
| } |
| |
| // Prefix returns the number of bits before the first host bit. |
| func (s *Subnet) Prefix() int { |
| return s.mask.Prefix() |
| } |
| |
| // Mask returns the subnet mask. |
| func (s *Subnet) Mask() AddressMask { |
| return s.mask |
| } |
| |
| // Broadcast returns the subnet's broadcast address. |
| func (s *Subnet) Broadcast() Address { |
| addr := []byte(s.address) |
| for i := range addr { |
| addr[i] |= ^s.mask[i] |
| } |
| return Address(addr) |
| } |
| |
| // IsBroadcast returns true if the address is considered a broadcast address. |
| func (s *Subnet) IsBroadcast(address Address) bool { |
| // Only IPv4 supports the notion of a broadcast address. |
| if len(address) != ipv4AddressSize { |
| return false |
| } |
| |
| // Normally, we would just compare address with the subnet's broadcast |
| // address but there is an exception where a simple comparison is not |
| // correct. This exception is for /31 and /32 IPv4 subnets where all |
| // addresses are considered valid host addresses. |
| // |
| // For /31 subnets, the case is easy. RFC 3021 Section 2.1 states that |
| // both addresses in a /31 subnet "MUST be interpreted as host addresses." |
| // |
| // For /32, the case is a bit more vague. RFC 3021 makes no mention of /32 |
| // subnets. However, the same reasoning applies - if an exception is not |
| // made, then there do not exist any host addresses in a /32 subnet. RFC |
| // 4632 Section 3.1 also vaguely implies this interpretation by referring |
| // to addresses in /32 subnets as "host routes." |
| return s.Prefix() <= 30 && s.Broadcast() == address |
| } |
| |
| // Equal returns true if this Subnet is equal to the given Subnet. |
| func (s Subnet) Equal(o Subnet) bool { |
| // If this changes, update Route.Equal accordingly. |
| return s == o |
| } |
| |
| // NICID is a number that uniquely identifies a NIC. |
| type NICID int32 |
| |
| // ShutdownFlags represents flags that can be passed to the Shutdown() method |
| // of the Endpoint interface. |
| type ShutdownFlags int |
| |
| // Values of the flags that can be passed to the Shutdown() method. They can |
| // be OR'ed together. |
| const ( |
| ShutdownRead ShutdownFlags = 1 << iota |
| ShutdownWrite |
| ) |
| |
| // PacketType is used to indicate the destination of the packet. |
| type PacketType uint8 |
| |
| const ( |
| // PacketHost indicates a packet addressed to the local host. |
| PacketHost PacketType = iota |
| |
| // PacketOtherHost indicates an outgoing packet addressed to |
| // another host caught by a NIC in promiscuous mode. |
| PacketOtherHost |
| |
| // PacketOutgoing for a packet originating from the local host |
| // that is looped back to a packet socket. |
| PacketOutgoing |
| |
| // PacketBroadcast indicates a link layer broadcast packet. |
| PacketBroadcast |
| |
| // PacketMulticast indicates a link layer multicast packet. |
| PacketMulticast |
| ) |
| |
| // FullAddress represents a full transport node address, as required by the |
| // Connect() and Bind() methods. |
| // |
| // +stateify savable |
| type FullAddress struct { |
| // NIC is the ID of the NIC this address refers to. |
| // |
| // This may not be used by all endpoint types. |
| NIC NICID |
| |
| // Addr is the network or link layer address. |
| Addr Address |
| |
| // Port is the transport port. |
| // |
| // This may not be used by all endpoint types. |
| Port uint16 |
| } |
| |
| // Payloader is an interface that provides data. |
| // |
| // This interface allows the endpoint to request the amount of data it needs |
| // based on internal buffers without exposing them. |
| type Payloader interface { |
| io.Reader |
| |
| // Len returns the number of bytes of the unread portion of the |
| // Reader. |
| Len() int |
| } |
| |
| var _ Payloader = (*bytes.Buffer)(nil) |
| var _ Payloader = (*bytes.Reader)(nil) |
| |
| var _ io.Writer = (*SliceWriter)(nil) |
| |
| // SliceWriter implements io.Writer for slices. |
| type SliceWriter []byte |
| |
| // Write implements io.Writer.Write. |
| func (s *SliceWriter) Write(b []byte) (int, error) { |
| n := copy(*s, b) |
| *s = (*s)[n:] |
| var err error |
| if n != len(b) { |
| err = io.ErrShortWrite |
| } |
| return n, err |
| } |
| |
| var _ io.Writer = (*LimitedWriter)(nil) |
| |
| // A LimitedWriter writes to W but limits the amount of data copied to just N |
| // bytes. Each call to Write updates N to reflect the new amount remaining. |
| type LimitedWriter struct { |
| W io.Writer |
| N int64 |
| } |
| |
| func (l *LimitedWriter) Write(p []byte) (int, error) { |
| pLen := int64(len(p)) |
| if pLen > l.N { |
| p = p[:l.N] |
| } |
| n, err := l.W.Write(p) |
| n64 := int64(n) |
| if err == nil && n64 != pLen { |
| err = io.ErrShortWrite |
| } |
| l.N -= n64 |
| return n, err |
| } |
| |
| // A ControlMessages contains socket control messages for IP sockets. |
| // |
| // +stateify savable |
| type ControlMessages struct { |
| // HasTimestamp indicates whether Timestamp is valid/set. |
| HasTimestamp bool |
| |
| // Timestamp is the time (in ns) that the last packet used to create |
| // the read data was received. |
| Timestamp int64 |
| |
| // HasInq indicates whether Inq is valid/set. |
| HasInq bool |
| |
| // Inq is the number of bytes ready to be received. |
| Inq int32 |
| |
| // HasTOS indicates whether Tos is valid/set. |
| HasTOS bool |
| |
| // TOS is the IPv4 type of service of the associated packet. |
| TOS uint8 |
| |
| // HasTClass indicates whether TClass is valid/set. |
| HasTClass bool |
| |
| // TClass is the IPv6 traffic class of the associated packet. |
| TClass uint32 |
| |
| // HasIPPacketInfo indicates whether PacketInfo is set. |
| HasIPPacketInfo bool |
| |
| // PacketInfo holds interface and address data on an incoming packet. |
| PacketInfo IPPacketInfo |
| |
| // HasOriginalDestinationAddress indicates whether OriginalDstAddress is |
| // set. |
| HasOriginalDstAddress bool |
| |
| // OriginalDestinationAddress holds the original destination address |
| // and port of the incoming packet. |
| OriginalDstAddress FullAddress |
| |
| // SockErr is the dequeued socket error on recvmsg(MSG_ERRQUEUE). |
| SockErr *SockError |
| } |
| |
| // PacketOwner is used to get UID and GID of the packet. |
| type PacketOwner interface { |
| // UID returns UID of the packet. |
| UID() uint32 |
| |
| // GID returns GID of the packet. |
| GID() uint32 |
| } |
| |
| // ReadOptions contains options for Endpoint.Read. |
| type ReadOptions struct { |
| // Peek indicates whether this read is a peek. |
| Peek bool |
| |
| // NeedRemoteAddr indicates whether to return the remote address, if |
| // supported. |
| NeedRemoteAddr bool |
| |
| // NeedLinkPacketInfo indicates whether to return the link-layer information, |
| // if supported. |
| NeedLinkPacketInfo bool |
| } |
| |
| // ReadResult represents result for a successful Endpoint.Read. |
| type ReadResult struct { |
| // Count is the number of bytes received and written to the buffer. |
| Count int |
| |
| // Total is the number of bytes of the received packet. This can be used to |
| // determine whether the read is truncated. |
| Total int |
| |
| // ControlMessages is the control messages received. |
| ControlMessages ControlMessages |
| |
| // RemoteAddr is the remote address if ReadOptions.NeedAddr is true. |
| RemoteAddr FullAddress |
| |
| // LinkPacketInfo is the link-layer information of the received packet if |
| // ReadOptions.NeedLinkPacketInfo is true. |
| LinkPacketInfo LinkPacketInfo |
| } |
| |
| // Endpoint is the interface implemented by transport protocols (e.g., tcp, udp) |
| // that exposes functionality like read, write, connect, etc. to users of the |
| // networking stack. |
| type Endpoint interface { |
| // Close puts the endpoint in a closed state and frees all resources |
| // associated with it. Close initiates the teardown process, the |
| // Endpoint may not be fully closed when Close returns. |
| Close() |
| |
| // Abort initiates an expedited endpoint teardown. As compared to |
| // Close, Abort prioritizes closing the Endpoint quickly over cleanly. |
| // Abort is best effort; implementing Abort with Close is acceptable. |
| Abort() |
| |
| // Read reads data from the endpoint and optionally writes to dst. |
| // |
| // This method does not block if there is no data pending; in this case, |
| // ErrWouldBlock is returned. |
| // |
| // If non-zero number of bytes are successfully read and written to dst, err |
| // must be nil. Otherwise, if dst failed to write anything, ErrBadBuffer |
| // should be returned. |
| Read(io.Writer, ReadOptions) (ReadResult, Error) |
| |
| // Write writes data to the endpoint's peer. This method does not block if |
| // the data cannot be written. |
| // |
| // Unlike io.Writer.Write, Endpoint.Write transfers ownership of any bytes |
| // successfully written to the Endpoint. That is, if a call to |
| // Write(SlicePayload{data}) returns (n, err), it may retain data[:n], and |
| // the caller should not use data[:n] after Write returns. |
| // |
| // Note that unlike io.Writer.Write, it is not an error for Write to |
| // perform a partial write (if n > 0, no error may be returned). Only |
| // stream (TCP) Endpoints may return partial writes, and even then only |
| // in the case where writing additional data would block. Other Endpoints |
| // will either write the entire message or return an error. |
| Write(Payloader, WriteOptions) (int64, Error) |
| |
| // Connect connects the endpoint to its peer. Specifying a NIC is |
| // optional. |
| // |
| // There are three classes of return values: |
| // nil -- the attempt to connect succeeded. |
| // ErrConnectStarted/ErrAlreadyConnecting -- the connect attempt started |
| // but hasn't completed yet. In this case, the caller must call Connect |
| // or GetSockOpt(ErrorOption) when the endpoint becomes writable to |
| // get the actual result. The first call to Connect after the socket has |
| // connected returns nil. Calling connect again results in ErrAlreadyConnected. |
| // Anything else -- the attempt to connect failed. |
| // |
| // If address.Addr is empty, this means that Endpoint has to be |
| // disconnected if this is supported, otherwise |
| // ErrAddressFamilyNotSupported must be returned. |
| Connect(address FullAddress) Error |
| |
| // Disconnect disconnects the endpoint from its peer. |
| Disconnect() Error |
| |
| // Shutdown closes the read and/or write end of the endpoint connection |
| // to its peer. |
| Shutdown(flags ShutdownFlags) Error |
| |
| // Listen puts the endpoint in "listen" mode, which allows it to accept |
| // new connections. |
| Listen(backlog int) Error |
| |
| // Accept returns a new endpoint if a peer has established a connection |
| // to an endpoint previously set to listen mode. This method does not |
| // block if no new connections are available. |
| // |
| // The returned Queue is the wait queue for the newly created endpoint. |
| // |
| // If peerAddr is not nil then it is populated with the peer address of the |
| // returned endpoint. |
| Accept(peerAddr *FullAddress) (Endpoint, *waiter.Queue, Error) |
| |
| // Bind binds the endpoint to a specific local address and port. |
| // Specifying a NIC is optional. |
| Bind(address FullAddress) Error |
| |
| // GetLocalAddress returns the address to which the endpoint is bound. |
| GetLocalAddress() (FullAddress, Error) |
| |
| // GetRemoteAddress returns the address to which the endpoint is |
| // connected. |
| GetRemoteAddress() (FullAddress, Error) |
| |
| // Readiness returns the current readiness of the endpoint. For example, |
| // if waiter.EventIn is set, the endpoint is immediately readable. |
| Readiness(mask waiter.EventMask) waiter.EventMask |
| |
| // SetSockOpt sets a socket option. |
| SetSockOpt(opt SettableSocketOption) Error |
| |
| // SetSockOptInt sets a socket option, for simple cases where a value |
| // has the int type. |
| SetSockOptInt(opt SockOptInt, v int) Error |
| |
| // GetSockOpt gets a socket option. |
| GetSockOpt(opt GettableSocketOption) Error |
| |
| // GetSockOptInt gets a socket option for simple cases where a return |
| // value has the int type. |
| GetSockOptInt(SockOptInt) (int, Error) |
| |
| // State returns a socket's lifecycle state. The returned value is |
| // protocol-specific and is primarily used for diagnostics. |
| State() uint32 |
| |
| // ModerateRecvBuf should be called everytime data is copied to the user |
| // space. This allows for dynamic tuning of recv buffer space for a |
| // given socket. |
| // |
| // NOTE: This method is a no-op for sockets other than TCP. |
| ModerateRecvBuf(copied int) |
| |
| // Info returns a copy to the transport endpoint info. |
| Info() EndpointInfo |
| |
| // Stats returns a reference to the endpoint stats. |
| Stats() EndpointStats |
| |
| // SetOwner sets the task owner to the endpoint owner. |
| SetOwner(owner PacketOwner) |
| |
| // LastError clears and returns the last error reported by the endpoint. |
| LastError() Error |
| |
| // SocketOptions returns the structure which contains all the socket |
| // level options. |
| SocketOptions() *SocketOptions |
| } |
| |
| // LinkPacketInfo holds Link layer information for a received packet. |
| // |
| // +stateify savable |
| type LinkPacketInfo struct { |
| // Protocol is the NetworkProtocolNumber for the packet. |
| Protocol NetworkProtocolNumber |
| |
| // PktType is used to indicate the destination of the packet. |
| PktType PacketType |
| } |
| |
| // EndpointInfo is the interface implemented by each endpoint info struct. |
| type EndpointInfo interface { |
| // IsEndpointInfo is an empty method to implement the tcpip.EndpointInfo |
| // marker interface. |
| IsEndpointInfo() |
| } |
| |
| // EndpointStats is the interface implemented by each endpoint stats struct. |
| type EndpointStats interface { |
| // IsEndpointStats is an empty method to implement the tcpip.EndpointStats |
| // marker interface. |
| IsEndpointStats() |
| } |
| |
| // WriteOptions contains options for Endpoint.Write. |
| type WriteOptions struct { |
| // If To is not nil, write to the given address instead of the endpoint's |
| // peer. |
| To *FullAddress |
| |
| // More has the same semantics as Linux's MSG_MORE. |
| More bool |
| |
| // EndOfRecord has the same semantics as Linux's MSG_EOR. |
| EndOfRecord bool |
| |
| // Atomic means that all data fetched from Payloader must be written to the |
| // endpoint. If Atomic is false, then data fetched from the Payloader may be |
| // discarded if available endpoint buffer space is unsufficient. |
| Atomic bool |
| } |
| |
| // SockOptInt represents socket options which values have the int type. |
| type SockOptInt int |
| |
| const ( |
| // KeepaliveCountOption is used by SetSockOptInt/GetSockOptInt to |
| // specify the number of un-ACKed TCP keepalives that will be sent |
| // before the connection is closed. |
| KeepaliveCountOption SockOptInt = iota |
| |
| // IPv4TOSOption is used by SetSockOptInt/GetSockOptInt to specify TOS |
| // for all subsequent outgoing IPv4 packets from the endpoint. |
| IPv4TOSOption |
| |
| // IPv6TrafficClassOption is used by SetSockOptInt/GetSockOptInt to |
| // specify TOS for all subsequent outgoing IPv6 packets from the |
| // endpoint. |
| IPv6TrafficClassOption |
| |
| // MaxSegOption is used by SetSockOptInt/GetSockOptInt to set/get the |
| // current Maximum Segment Size(MSS) value as specified using the |
| // TCP_MAXSEG option. |
| MaxSegOption |
| |
| // MTUDiscoverOption is used to set/get the path MTU discovery setting. |
| // |
| // NOTE: Setting this option to any other value than PMTUDiscoveryDont |
| // is not supported and will fail as such, and getting this option will |
| // always return PMTUDiscoveryDont. |
| MTUDiscoverOption |
| |
| // MulticastTTLOption is used by SetSockOptInt/GetSockOptInt to control |
| // the default TTL value for multicast messages. The default is 1. |
| MulticastTTLOption |
| |
| // ReceiveQueueSizeOption is used in GetSockOptInt to specify that the |
| // number of unread bytes in the input buffer should be returned. |
| ReceiveQueueSizeOption |
| |
| // ReceiveBufferSizeOption is used by SetSockOptInt/GetSockOptInt to |
| // specify the receive buffer size option. |
| ReceiveBufferSizeOption |
| |
| // SendQueueSizeOption is used in GetSockOptInt to specify that the |
| // number of unread bytes in the output buffer should be returned. |
| SendQueueSizeOption |
| |
| // TTLOption is used by SetSockOptInt/GetSockOptInt to control the |
| // default TTL/hop limit value for unicast messages. The default is |
| // protocol specific. |
| // |
| // A zero value indicates the default. |
| TTLOption |
| |
| // TCPSynCountOption is used by SetSockOptInt/GetSockOptInt to specify |
| // the number of SYN retransmits that TCP should send before aborting |
| // the attempt to connect. It cannot exceed 255. |
| // |
| // NOTE: This option is currently only stubbed out and is no-op. |
| TCPSynCountOption |
| |
| // TCPWindowClampOption is used by SetSockOptInt/GetSockOptInt to bound |
| // the size of the advertised window to this value. |
| // |
| // NOTE: This option is currently only stubed out and is a no-op |
| TCPWindowClampOption |
| ) |
| |
| const ( |
| // PMTUDiscoveryWant is a setting of the MTUDiscoverOption to use |
| // per-route settings. |
| PMTUDiscoveryWant int = iota |
| |
| // PMTUDiscoveryDont is a setting of the MTUDiscoverOption to disable |
| // path MTU discovery. |
| PMTUDiscoveryDont |
| |
| // PMTUDiscoveryDo is a setting of the MTUDiscoverOption to always do |
| // path MTU discovery. |
| PMTUDiscoveryDo |
| |
| // PMTUDiscoveryProbe is a setting of the MTUDiscoverOption to set DF |
| // but ignore path MTU. |
| PMTUDiscoveryProbe |
| ) |
| |
| // GettableNetworkProtocolOption is a marker interface for network protocol |
| // options that may be queried. |
| type GettableNetworkProtocolOption interface { |
| isGettableNetworkProtocolOption() |
| } |
| |
| // SettableNetworkProtocolOption is a marker interface for network protocol |
| // options that may be set. |
| type SettableNetworkProtocolOption interface { |
| isSettableNetworkProtocolOption() |
| } |
| |
| // DefaultTTLOption is used by stack.(*Stack).NetworkProtocolOption to specify |
| // a default TTL. |
| type DefaultTTLOption uint8 |
| |
| func (*DefaultTTLOption) isGettableNetworkProtocolOption() {} |
| |
| func (*DefaultTTLOption) isSettableNetworkProtocolOption() {} |
| |
| // GettableTransportProtocolOption is a marker interface for transport protocol |
| // options that may be queried. |
| type GettableTransportProtocolOption interface { |
| isGettableTransportProtocolOption() |
| } |
| |
| // SettableTransportProtocolOption is a marker interface for transport protocol |
| // options that may be set. |
| type SettableTransportProtocolOption interface { |
| isSettableTransportProtocolOption() |
| } |
| |
| // TCPSACKEnabled the SACK option for TCP. |
| // |
| // See: https://tools.ietf.org/html/rfc2018. |
| type TCPSACKEnabled bool |
| |
| func (*TCPSACKEnabled) isGettableTransportProtocolOption() {} |
| |
| func (*TCPSACKEnabled) isSettableTransportProtocolOption() {} |
| |
| // TCPRecovery is the loss deteoction algorithm used by TCP. |
| type TCPRecovery int32 |
| |
| func (*TCPRecovery) isGettableTransportProtocolOption() {} |
| |
| func (*TCPRecovery) isSettableTransportProtocolOption() {} |
| |
| const ( |
| // TCPRACKLossDetection indicates RACK is used for loss detection and |
| // recovery. |
| TCPRACKLossDetection TCPRecovery = 1 << iota |
| |
| // TCPRACKStaticReoWnd indicates the reordering window should not be |
| // adjusted when DSACK is received. |
| TCPRACKStaticReoWnd |
| |
| // TCPRACKNoDupTh indicates RACK should not consider the classic three |
| // duplicate acknowledgements rule to mark the segments as lost. This |
| // is used when reordering is not detected. |
| TCPRACKNoDupTh |
| ) |
| |
| // TCPDelayEnabled enables/disables Nagle's algorithm in TCP. |
| type TCPDelayEnabled bool |
| |
| func (*TCPDelayEnabled) isGettableTransportProtocolOption() {} |
| |
| func (*TCPDelayEnabled) isSettableTransportProtocolOption() {} |
| |
| // TCPSendBufferSizeRangeOption is the send buffer size range for TCP. |
| type TCPSendBufferSizeRangeOption struct { |
| Min int |
| Default int |
| Max int |
| } |
| |
| func (*TCPSendBufferSizeRangeOption) isGettableTransportProtocolOption() {} |
| |
| func (*TCPSendBufferSizeRangeOption) isSettableTransportProtocolOption() {} |
| |
| // TCPReceiveBufferSizeRangeOption is the receive buffer size range for TCP. |
| type TCPReceiveBufferSizeRangeOption struct { |
| Min int |
| Default int |
| Max int |
| } |
| |
| func (*TCPReceiveBufferSizeRangeOption) isGettableTransportProtocolOption() {} |
| |
| func (*TCPReceiveBufferSizeRangeOption) isSettableTransportProtocolOption() {} |
| |
| // TCPAvailableCongestionControlOption is the supported congestion control |
| // algorithms for TCP |
| type TCPAvailableCongestionControlOption string |
| |
| func (*TCPAvailableCongestionControlOption) isGettableTransportProtocolOption() {} |
| |
| func (*TCPAvailableCongestionControlOption) isSettableTransportProtocolOption() {} |
| |
| // TCPModerateReceiveBufferOption enables/disables receive buffer moderation |
| // for TCP. |
| type TCPModerateReceiveBufferOption bool |
| |
| func (*TCPModerateReceiveBufferOption) isGettableTransportProtocolOption() {} |
| |
| func (*TCPModerateReceiveBufferOption) isSettableTransportProtocolOption() {} |
| |
| // GettableSocketOption is a marker interface for socket options that may be |
| // queried. |
| type GettableSocketOption interface { |
| isGettableSocketOption() |
| } |
| |
| // SettableSocketOption is a marker interface for socket options that may be |
| // configured. |
| type SettableSocketOption interface { |
| isSettableSocketOption() |
| } |
| |
| // CongestionControlState indicates the current congestion control state for |
| // TCP sender. |
| type CongestionControlState int |
| |
| const ( |
| // Open indicates that the sender is receiving acks in order and |
| // no loss or dupACK's etc have been detected. |
| Open CongestionControlState = iota |
| // RTORecovery indicates that an RTO has occurred and the sender |
| // has entered an RTO based recovery phase. |
| RTORecovery |
| // FastRecovery indicates that the sender has entered FastRecovery |
| // based on receiving nDupAck's. This state is entered only when |
| // SACK is not in use. |
| FastRecovery |
| // SACKRecovery indicates that the sender has entered SACK based |
| // recovery. |
| SACKRecovery |
| // Disorder indicates the sender either received some SACK blocks |
| // or dupACK's. |
| Disorder |
| ) |
| |
| // TCPInfoOption is used by GetSockOpt to expose TCP statistics. |
| // |
| // TODO(b/64800844): Add and populate stat fields. |
| type TCPInfoOption struct { |
| // RTT is the smoothed round trip time. |
| RTT time.Duration |
| |
| // RTTVar is the round trip time variation. |
| RTTVar time.Duration |
| |
| // RTO is the retransmission timeout for the endpoint. |
| RTO time.Duration |
| |
| // CcState is the congestion control state. |
| CcState CongestionControlState |
| |
| // SndCwnd is the congestion window, in packets. |
| SndCwnd uint32 |
| |
| // SndSsthresh is the threshold between slow start and congestion |
| // avoidance. |
| SndSsthresh uint32 |
| |
| // ReorderSeen indicates if reordering is seen in the endpoint. |
| ReorderSeen bool |
| } |
| |
| func (*TCPInfoOption) isGettableSocketOption() {} |
| |
| // KeepaliveIdleOption is used by SetSockOpt/GetSockOpt to specify the time a |
| // connection must remain idle before the first TCP keepalive packet is sent. |
| // Once this time is reached, KeepaliveIntervalOption is used instead. |
| type KeepaliveIdleOption time.Duration |
| |
| func (*KeepaliveIdleOption) isGettableSocketOption() {} |
| |
| func (*KeepaliveIdleOption) isSettableSocketOption() {} |
| |
| // KeepaliveIntervalOption is used by SetSockOpt/GetSockOpt to specify the |
| // interval between sending TCP keepalive packets. |
| type KeepaliveIntervalOption time.Duration |
| |
| func (*KeepaliveIntervalOption) isGettableSocketOption() {} |
| |
| func (*KeepaliveIntervalOption) isSettableSocketOption() {} |
| |
| // TCPUserTimeoutOption is used by SetSockOpt/GetSockOpt to specify a user |
| // specified timeout for a given TCP connection. |
| // See: RFC5482 for details. |
| type TCPUserTimeoutOption time.Duration |
| |
| func (*TCPUserTimeoutOption) isGettableSocketOption() {} |
| |
| func (*TCPUserTimeoutOption) isSettableSocketOption() {} |
| |
| // CongestionControlOption is used by SetSockOpt/GetSockOpt to set/get |
| // the current congestion control algorithm. |
| type CongestionControlOption string |
| |
| func (*CongestionControlOption) isGettableSocketOption() {} |
| |
| func (*CongestionControlOption) isSettableSocketOption() {} |
| |
| func (*CongestionControlOption) isGettableTransportProtocolOption() {} |
| |
| func (*CongestionControlOption) isSettableTransportProtocolOption() {} |
| |
| // TCPLingerTimeoutOption is used by SetSockOpt/GetSockOpt to set/get the |
| // maximum duration for which a socket lingers in the TCP_FIN_WAIT_2 state |
| // before being marked closed. |
| type TCPLingerTimeoutOption time.Duration |
| |
| func (*TCPLingerTimeoutOption) isGettableSocketOption() {} |
| |
| func (*TCPLingerTimeoutOption) isSettableSocketOption() {} |
| |
| func (*TCPLingerTimeoutOption) isGettableTransportProtocolOption() {} |
| |
| func (*TCPLingerTimeoutOption) isSettableTransportProtocolOption() {} |
| |
| // TCPTimeWaitTimeoutOption is used by SetSockOpt/GetSockOpt to set/get the |
| // maximum duration for which a socket lingers in the TIME_WAIT state |
| // before being marked closed. |
| type TCPTimeWaitTimeoutOption time.Duration |
| |
| func (*TCPTimeWaitTimeoutOption) isGettableSocketOption() {} |
| |
| func (*TCPTimeWaitTimeoutOption) isSettableSocketOption() {} |
| |
| func (*TCPTimeWaitTimeoutOption) isGettableTransportProtocolOption() {} |
| |
| func (*TCPTimeWaitTimeoutOption) isSettableTransportProtocolOption() {} |
| |
| // 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 |
| |
| func (*TCPDeferAcceptOption) isGettableSocketOption() {} |
| |
| func (*TCPDeferAcceptOption) isSettableSocketOption() {} |
| |
| // TCPMinRTOOption is use by SetSockOpt/GetSockOpt to allow overriding |
| // default MinRTO used by the Stack. |
| type TCPMinRTOOption time.Duration |
| |
| func (*TCPMinRTOOption) isGettableSocketOption() {} |
| |
| func (*TCPMinRTOOption) isSettableSocketOption() {} |
| |
| func (*TCPMinRTOOption) isGettableTransportProtocolOption() {} |
| |
| func (*TCPMinRTOOption) isSettableTransportProtocolOption() {} |
| |
| // TCPMaxRTOOption is use by SetSockOpt/GetSockOpt to allow overriding |
| // default MaxRTO used by the Stack. |
| type TCPMaxRTOOption time.Duration |
| |
| func (*TCPMaxRTOOption) isGettableSocketOption() {} |
| |
| func (*TCPMaxRTOOption) isSettableSocketOption() {} |
| |
| func (*TCPMaxRTOOption) isGettableTransportProtocolOption() {} |
| |
| func (*TCPMaxRTOOption) isSettableTransportProtocolOption() {} |
| |
| // TCPMaxRetriesOption is used by SetSockOpt/GetSockOpt to set/get the |
| // maximum number of retransmits after which we time out the connection. |
| type TCPMaxRetriesOption uint64 |
| |
| func (*TCPMaxRetriesOption) isGettableSocketOption() {} |
| |
| func (*TCPMaxRetriesOption) isSettableSocketOption() {} |
| |
| func (*TCPMaxRetriesOption) isGettableTransportProtocolOption() {} |
| |
| func (*TCPMaxRetriesOption) isSettableTransportProtocolOption() {} |
| |
| // TCPSynRcvdCountThresholdOption is used by SetSockOpt/GetSockOpt to specify |
| // the number of endpoints that can be in SYN-RCVD state before the stack |
| // switches to using SYN cookies. |
| type TCPSynRcvdCountThresholdOption uint64 |
| |
| func (*TCPSynRcvdCountThresholdOption) isGettableSocketOption() {} |
| |
| func (*TCPSynRcvdCountThresholdOption) isSettableSocketOption() {} |
| |
| func (*TCPSynRcvdCountThresholdOption) isGettableTransportProtocolOption() {} |
| |
| func (*TCPSynRcvdCountThresholdOption) isSettableTransportProtocolOption() {} |
| |
| // TCPSynRetriesOption is used by SetSockOpt/GetSockOpt to specify stack-wide |
| // default for number of times SYN is retransmitted before aborting a connect. |
| type TCPSynRetriesOption uint8 |
| |
| func (*TCPSynRetriesOption) isGettableSocketOption() {} |
| |
| func (*TCPSynRetriesOption) isSettableSocketOption() {} |
| |
| func (*TCPSynRetriesOption) isGettableTransportProtocolOption() {} |
| |
| func (*TCPSynRetriesOption) isSettableTransportProtocolOption() {} |
| |
| // MulticastInterfaceOption is used by SetSockOpt/GetSockOpt to specify a |
| // default interface for multicast. |
| type MulticastInterfaceOption struct { |
| NIC NICID |
| InterfaceAddr Address |
| } |
| |
| func (*MulticastInterfaceOption) isGettableSocketOption() {} |
| |
| func (*MulticastInterfaceOption) isSettableSocketOption() {} |
| |
| // MembershipOption is used to identify a multicast membership on an interface. |
| type MembershipOption struct { |
| NIC NICID |
| InterfaceAddr Address |
| MulticastAddr Address |
| } |
| |
| // AddMembershipOption identifies a multicast group to join on some interface. |
| type AddMembershipOption MembershipOption |
| |
| func (*AddMembershipOption) isSettableSocketOption() {} |
| |
| // RemoveMembershipOption identifies a multicast group to leave on some |
| // interface. |
| type RemoveMembershipOption MembershipOption |
| |
| func (*RemoveMembershipOption) isSettableSocketOption() {} |
| |
| // SocketDetachFilterOption is used by SetSockOpt to detach a previously attached |
| // classic BPF filter on a given endpoint. |
| type SocketDetachFilterOption int |
| |
| func (*SocketDetachFilterOption) isSettableSocketOption() {} |
| |
| // OriginalDestinationOption is used to get the original destination address |
| // and port of a redirected packet. |
| type OriginalDestinationOption FullAddress |
| |
| func (*OriginalDestinationOption) isGettableSocketOption() {} |
| |
| // TCPTimeWaitReuseOption is used stack.(*Stack).TransportProtocolOption to |
| // specify if the stack can reuse the port bound by an endpoint in TIME-WAIT for |
| // new connections when it is safe from protocol viewpoint. |
| type TCPTimeWaitReuseOption uint8 |
| |
| func (*TCPTimeWaitReuseOption) isGettableSocketOption() {} |
| |
| func (*TCPTimeWaitReuseOption) isSettableSocketOption() {} |
| |
| func (*TCPTimeWaitReuseOption) isGettableTransportProtocolOption() {} |
| |
| func (*TCPTimeWaitReuseOption) isSettableTransportProtocolOption() {} |
| |
| const ( |
| // TCPTimeWaitReuseDisabled indicates reuse of port bound by endponts in TIME-WAIT cannot |
| // be reused for new connections. |
| TCPTimeWaitReuseDisabled TCPTimeWaitReuseOption = iota |
| |
| // TCPTimeWaitReuseGlobal indicates reuse of port bound by endponts in TIME-WAIT can |
| // be reused for new connections irrespective of the src/dest addresses. |
| TCPTimeWaitReuseGlobal |
| |
| // TCPTimeWaitReuseLoopbackOnly indicates reuse of port bound by endpoint in TIME-WAIT can |
| // only be reused if the connection was a connection over loopback. i.e src/dest adddresses |
| // are loopback addresses. |
| 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 |
| } |
| |
| // IPPacketInfo is the message structure for IP_PKTINFO. |
| // |
| // +stateify savable |
| type IPPacketInfo struct { |
| // NIC is the ID of the NIC to be used. |
| NIC NICID |
| |
| // LocalAddr is the local address. |
| LocalAddr Address |
| |
| // DestinationAddr is the destination address found in the IP header. |
| DestinationAddr Address |
| } |
| |
| // SendBufferSizeOption is used by stack.(Stack*).Option/SetOption to |
| // get/set the default, min and max send buffer sizes. |
| type SendBufferSizeOption struct { |
| // Min is the minimum size for send buffer. |
| Min int |
| |
| // Default is the default size for send buffer. |
| Default int |
| |
| // Max is the maximum size for send buffer. |
| Max int |
| } |
| |
| // GetSendBufferLimits is used to get the send buffer size limits. |
| type GetSendBufferLimits func(StackHandler) SendBufferSizeOption |
| |
| // GetStackSendBufferLimits is used to get default, min and max send buffer size. |
| func GetStackSendBufferLimits(so StackHandler) SendBufferSizeOption { |
| var ss SendBufferSizeOption |
| if err := so.Option(&ss); err != nil { |
| panic(fmt.Sprintf("s.Option(%#v) = %s", ss, err)) |
| } |
| return ss |
| } |
| |
| // Route is a row in the routing table. It specifies through which NIC (and |
| // gateway) sets of packets should be routed. A row is considered viable if the |
| // masked target address matches the destination address in the row. |
| type Route struct { |
| // Destination must contain the target address for this row to be viable. |
| Destination Subnet |
| |
| // Gateway is the gateway to be used if this row is viable. |
| Gateway Address |
| |
| // NIC is the id of the nic to be used if this row is viable. |
| NIC NICID |
| } |
| |
| // String implements the fmt.Stringer interface. |
| func (r Route) String() string { |
| var out strings.Builder |
| fmt.Fprintf(&out, "%s", r.Destination) |
| if len(r.Gateway) > 0 { |
| fmt.Fprintf(&out, " via %s", r.Gateway) |
| } |
| fmt.Fprintf(&out, " nic %d", r.NIC) |
| return out.String() |
| } |
| |
| // Equal returns true if the given Route is equal to this Route. |
| func (r Route) Equal(to Route) bool { |
| // NOTE: This relies on the fact that r.Destination == to.Destination |
| return r == to |
| } |
| |
| // TransportProtocolNumber is the number of a transport protocol. |
| type TransportProtocolNumber uint32 |
| |
| // NetworkProtocolNumber is the EtherType of a network protocol in an Ethernet |
| // frame. |
| // |
| // See: https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml |
| type NetworkProtocolNumber uint32 |
| |
| // A StatCounter keeps track of a statistic. |
| type StatCounter struct { |
| count uint64 |
| } |
| |
| // Increment adds one to the counter. |
| func (s *StatCounter) Increment() { |
| s.IncrementBy(1) |
| } |
| |
| // Decrement minuses one to the counter. |
| func (s *StatCounter) Decrement() { |
| s.IncrementBy(^uint64(0)) |
| } |
| |
| // Value returns the current value of the counter. |
| func (s *StatCounter) Value() uint64 { |
| return atomic.LoadUint64(&s.count) |
| } |
| |
| // IncrementBy increments the counter by v. |
| func (s *StatCounter) IncrementBy(v uint64) { |
| atomic.AddUint64(&s.count, v) |
| } |
| |
| func (s *StatCounter) String() string { |
| return strconv.FormatUint(s.Value(), 10) |
| } |
| |
| // A MultiCounterStat keeps track of two counters at once. |
| type MultiCounterStat struct { |
| a, b *StatCounter |
| } |
| |
| // Init sets both internal counters to point to a and b. |
| func (m *MultiCounterStat) Init(a, b *StatCounter) { |
| m.a = a |
| m.b = b |
| } |
| |
| // Increment adds one to the counters. |
| func (m *MultiCounterStat) Increment() { |
| m.a.Increment() |
| m.b.Increment() |
| } |
| |
| // IncrementBy increments the counters by v. |
| func (m *MultiCounterStat) IncrementBy(v uint64) { |
| m.a.IncrementBy(v) |
| m.b.IncrementBy(v) |
| } |
| |
| // ICMPv4PacketStats enumerates counts for all ICMPv4 packet types. |
| type ICMPv4PacketStats struct { |
| // LINT.IfChange(ICMPv4PacketStats) |
| |
| // EchoRequest is the number of ICMPv4 echo packets counted. |
| EchoRequest *StatCounter |
| |
| // EchoReply is the number of ICMPv4 echo reply packets counted. |
| EchoReply *StatCounter |
| |
| // DstUnreachable is the number of ICMPv4 destination unreachable packets |
| // counted. |
| DstUnreachable *StatCounter |
| |
| // SrcQuench is the number of ICMPv4 source quench packets counted. |
| SrcQuench *StatCounter |
| |
| // Redirect is the number of ICMPv4 redirect packets counted. |
| Redirect *StatCounter |
| |
| // TimeExceeded is the number of ICMPv4 time exceeded packets counted. |
| TimeExceeded *StatCounter |
| |
| // ParamProblem is the number of ICMPv4 parameter problem packets counted. |
| ParamProblem *StatCounter |
| |
| // Timestamp is the number of ICMPv4 timestamp packets counted. |
| Timestamp *StatCounter |
| |
| // TimestampReply is the number of ICMPv4 timestamp reply packets counted. |
| TimestampReply *StatCounter |
| |
| // InfoRequest is the number of ICMPv4 information request packets counted. |
| InfoRequest *StatCounter |
| |
| // InfoReply is the number of ICMPv4 information reply packets counted. |
| InfoReply *StatCounter |
| |
| // LINT.ThenChange(network/ipv4/stats.go:multiCounterICMPv4PacketStats) |
| } |
| |
| // ICMPv4SentPacketStats collects outbound ICMPv4-specific stats. |
| type ICMPv4SentPacketStats struct { |
| // LINT.IfChange(ICMPv4SentPacketStats) |
| |
| ICMPv4PacketStats |
| |
| // Dropped is the number of ICMPv4 packets dropped due to link layer errors. |
| Dropped *StatCounter |
| |
| // RateLimited is the number of ICMPv4 packets dropped due to rate limit being |
| // exceeded. |
| RateLimited *StatCounter |
| |
| // LINT.ThenChange(network/ipv4/stats.go:multiCounterICMPv4SentPacketStats) |
| } |
| |
| // ICMPv4ReceivedPacketStats collects inbound ICMPv4-specific stats. |
| type ICMPv4ReceivedPacketStats struct { |
| // LINT.IfChange(ICMPv4ReceivedPacketStats) |
| |
| ICMPv4PacketStats |
| |
| // Invalid is the number of invalid ICMPv4 packets received. |
| Invalid *StatCounter |
| |
| // LINT.ThenChange(network/ipv4/stats.go:multiCounterICMPv4ReceivedPacketStats) |
| } |
| |
| // ICMPv4Stats collects ICMPv4-specific stats. |
| type ICMPv4Stats struct { |
| // LINT.IfChange(ICMPv4Stats) |
| |
| // PacketsSent contains statistics about sent packets. |
| PacketsSent ICMPv4SentPacketStats |
| |
| // PacketsReceived contains statistics about received packets. |
| PacketsReceived ICMPv4ReceivedPacketStats |
| |
| // LINT.ThenChange(network/ipv4/stats.go:multiCounterICMPv4Stats) |
| } |
| |
| // ICMPv6PacketStats enumerates counts for all ICMPv6 packet types. |
| type ICMPv6PacketStats struct { |
| // LINT.IfChange(ICMPv6PacketStats) |
| |
| // EchoRequest is the number of ICMPv6 echo request packets counted. |
| EchoRequest *StatCounter |
| |
| // EchoReply is the number of ICMPv6 echo reply packets counted. |
| EchoReply *StatCounter |
| |
| // DstUnreachable is the number of ICMPv6 destination unreachable packets |
| // counted. |
| DstUnreachable *StatCounter |
| |
| // PacketTooBig is the number of ICMPv6 packet too big packets counted. |
| PacketTooBig *StatCounter |
| |
| // TimeExceeded is the number of ICMPv6 time exceeded packets counted. |
| TimeExceeded *StatCounter |
| |
| // ParamProblem is the number of ICMPv6 parameter problem packets counted. |
| ParamProblem *StatCounter |
| |
| // RouterSolicit is the number of ICMPv6 router solicit packets counted. |
| RouterSolicit *StatCounter |
| |
| // RouterAdvert is the number of ICMPv6 router advert packets counted. |
| RouterAdvert *StatCounter |
| |
| // NeighborSolicit is the number of ICMPv6 neighbor solicit packets counted. |
| NeighborSolicit *StatCounter |
| |
| // NeighborAdvert is the number of ICMPv6 neighbor advert packets counted. |
| NeighborAdvert *StatCounter |
| |
| // RedirectMsg is the number of ICMPv6 redirect message packets counted. |
| RedirectMsg *StatCounter |
| |
| // MulticastListenerQuery is the number of Multicast Listener Query messages |
| // counted. |
| MulticastListenerQuery *StatCounter |
| |
| // MulticastListenerReport is the number of Multicast Listener Report messages |
| // counted. |
| MulticastListenerReport *StatCounter |
| |
| // MulticastListenerDone is the number of Multicast Listener Done messages |
| // counted. |
| MulticastListenerDone *StatCounter |
| |
| // LINT.ThenChange(network/ipv6/stats.go:multiCounterICMPv6PacketStats) |
| } |
| |
| // ICMPv6SentPacketStats collects outbound ICMPv6-specific stats. |
| type ICMPv6SentPacketStats struct { |
| // LINT.IfChange(ICMPv6SentPacketStats) |
| |
| ICMPv6PacketStats |
| |
| // Dropped is the number of ICMPv6 packets dropped due to link layer errors. |
| Dropped *StatCounter |
| |
| // RateLimited is the number of ICMPv6 packets dropped due to rate limit being |
| // exceeded. |
| RateLimited *StatCounter |
| |
| // LINT.ThenChange(network/ipv6/stats.go:multiCounterICMPv6SentPacketStats) |
| } |
| |
| // ICMPv6ReceivedPacketStats collects inbound ICMPv6-specific stats. |
| type ICMPv6ReceivedPacketStats struct { |
| // LINT.IfChange(ICMPv6ReceivedPacketStats) |
| |
| ICMPv6PacketStats |
| |
| // Unrecognized is the number of ICMPv6 packets received that the transport |
| // layer does not know how to parse. |
| Unrecognized *StatCounter |
| |
| // Invalid is the number of invalid ICMPv6 packets received. |
| Invalid *StatCounter |
| |
| // RouterOnlyPacketsDroppedByHost is the number of ICMPv6 packets dropped due |
| // to being router-specific packets. |
| RouterOnlyPacketsDroppedByHost *StatCounter |
| |
| // LINT.ThenChange(network/ipv6/stats.go:multiCounterICMPv6ReceivedPacketStats) |
| } |
| |
| // ICMPv6Stats collects ICMPv6-specific stats. |
| type ICMPv6Stats struct { |
| // LINT.IfChange(ICMPv6Stats) |
| |
| // PacketsSent contains statistics about sent packets. |
| PacketsSent ICMPv6SentPacketStats |
| |
| // PacketsReceived contains statistics about received packets. |
| PacketsReceived ICMPv6ReceivedPacketStats |
| |
| // LINT.ThenChange(network/ipv6/stats.go:multiCounterICMPv6Stats) |
| } |
| |
| // ICMPStats collects ICMP-specific stats (both v4 and v6). |
| type ICMPStats struct { |
| // V4 contains the ICMPv4-specifics stats. |
| V4 ICMPv4Stats |
| |
| // V6 contains the ICMPv4-specifics stats. |
| V6 ICMPv6Stats |
| } |
| |
| // IGMPPacketStats enumerates counts for all IGMP packet types. |
| type IGMPPacketStats struct { |
| // LINT.IfChange(IGMPPacketStats) |
| |
| // MembershipQuery is the number of Membership Query messages counted. |
| MembershipQuery *StatCounter |
| |
| // V1MembershipReport is the number of Version 1 Membership Report messages |
| // counted. |
| V1MembershipReport *StatCounter |
| |
| // V2MembershipReport is the number of Version 2 Membership Report messages |
| // counted. |
| V2MembershipReport *StatCounter |
| |
| // LeaveGroup is the number of Leave Group messages counted. |
| LeaveGroup *StatCounter |
| |
| // LINT.ThenChange(network/ipv4/stats.go:multiCounterIGMPPacketStats) |
| } |
| |
| // IGMPSentPacketStats collects outbound IGMP-specific stats. |
| type IGMPSentPacketStats struct { |
| // LINT.IfChange(IGMPSentPacketStats) |
| |
| IGMPPacketStats |
| |
| // Dropped is the number of IGMP packets dropped. |
| Dropped *StatCounter |
| |
| // LINT.ThenChange(network/ipv4/stats.go:multiCounterIGMPSentPacketStats) |
| } |
| |
| // IGMPReceivedPacketStats collects inbound IGMP-specific stats. |
| type IGMPReceivedPacketStats struct { |
| // LINT.IfChange(IGMPReceivedPacketStats) |
| |
| IGMPPacketStats |
| |
| // Invalid is the number of invalid IGMP packets received. |
| Invalid *StatCounter |
| |
| // ChecksumErrors is the number of IGMP packets dropped due to bad checksums. |
| ChecksumErrors *StatCounter |
| |
| // Unrecognized is the number of unrecognized messages counted, these are |
| // silently ignored for forward-compatibilty. |
| Unrecognized *StatCounter |
| |
| // LINT.ThenChange(network/ipv4/stats.go:multiCounterIGMPReceivedPacketStats) |
| } |
| |
| // IGMPStats collects IGMP-specific stats. |
| type IGMPStats struct { |
| // LINT.IfChange(IGMPStats) |
| |
| // PacketsSent contains statistics about sent packets. |
| PacketsSent IGMPSentPacketStats |
| |
| // PacketsReceived contains statistics about received packets. |
| PacketsReceived IGMPReceivedPacketStats |
| |
| // LINT.ThenChange(network/ipv4/stats.go:multiCounterIGMPStats) |
| } |
| |
| // IPStats collects IP-specific stats (both v4 and v6). |
| type IPStats struct { |
| // LINT.IfChange(IPStats) |
| |
| // PacketsReceived is the number of IP packets received from the link layer. |
| PacketsReceived *StatCounter |
| |
| // DisabledPacketsReceived is the number of IP packets received from the link |
| // layer when the IP layer is disabled. |
| DisabledPacketsReceived *StatCounter |
| |
| // InvalidDestinationAddressesReceived is the number of IP packets received |
| // with an unknown or invalid destination address. |
| InvalidDestinationAddressesReceived *StatCounter |
| |
| // InvalidSourceAddressesReceived is the number of IP packets received with a |
| // source address that should never have been received on the wire. |
| InvalidSourceAddressesReceived *StatCounter |
| |
| // PacketsDelivered is the number of incoming IP packets that are successfully |
| // delivered to the transport layer. |
| PacketsDelivered *StatCounter |
| |
| // PacketsSent is the number of IP packets sent via WritePacket. |
| PacketsSent *StatCounter |
| |
| // OutgoingPacketErrors is the number of IP packets which failed to write to a |
| // link-layer endpoint. |
| OutgoingPacketErrors *StatCounter |
| |
| // MalformedPacketsReceived is the number of IP Packets that were dropped due |
| // to the IP packet header failing validation checks. |
| MalformedPacketsReceived *StatCounter |
| |
| // MalformedFragmentsReceived is the number of IP Fragments that were dropped |
| // due to the fragment failing validation checks. |
| MalformedFragmentsReceived *StatCounter |
| |
| // IPTablesPreroutingDropped is the number of IP packets dropped in the |
| // Prerouting chain. |
| IPTablesPreroutingDropped *StatCounter |
| |
| // IPTablesInputDropped is the number of IP packets dropped in the Input |
| // chain. |
| IPTablesInputDropped *StatCounter |
| |
| // IPTablesOutputDropped is the number of IP packets dropped in the Output |
| // chain. |
| IPTablesOutputDropped *StatCounter |
| |
| // TODO(https://gvisor.dev/issues/5529): Move the IPv4-only option stats out |
| // of IPStats. |
| // OptionTimestampReceived is the number of Timestamp options seen. |
| OptionTimestampReceived *StatCounter |
| |
| // OptionRecordRouteReceived is the number of Record Route options seen. |
| OptionRecordRouteReceived *StatCounter |
| |
| // OptionRouterAlertReceived is the number of Router Alert options seen. |
| OptionRouterAlertReceived *StatCounter |
| |
| // OptionUnknownReceived is the number of unknown IP options seen. |
| OptionUnknownReceived *StatCounter |
| |
| // LINT.ThenChange(network/internal/ip/stats.go:MultiCounterIPStats) |
| } |
| |
| // ARPStats collects ARP-specific stats. |
| type ARPStats struct { |
| // LINT.IfChange(ARPStats) |
| |
| // PacketsReceived is the number of ARP packets received from the link layer. |
| PacketsReceived *StatCounter |
| |
| // DisabledPacketsReceived is the number of ARP packets received from the link |
| // layer when the ARP layer is disabled. |
| DisabledPacketsReceived *StatCounter |
| |
| // MalformedPacketsReceived is the number of ARP packets that were dropped due |
| // to being malformed. |
| MalformedPacketsReceived *StatCounter |
| |
| // RequestsReceived is the number of ARP requests received. |
| RequestsReceived *StatCounter |
| |
| // RequestsReceivedUnknownTargetAddress is the number of ARP requests that |
| // were targeted to an interface different from the one it was received on. |
| RequestsReceivedUnknownTargetAddress *StatCounter |
| |
| // OutgoingRequestInterfaceHasNoLocalAddressErrors is the number of failures |
| // to send an ARP request because the interface has no network address |
| // assigned to it. |
| OutgoingRequestInterfaceHasNoLocalAddressErrors *StatCounter |
| |
| // OutgoingRequestBadLocalAddressErrors is the number of failures to send an |
| // ARP request with a bad local address. |
| OutgoingRequestBadLocalAddressErrors *StatCounter |
| |
| // OutgoingRequestsDropped is the number of ARP requests which failed to write |
| // to a link-layer endpoint. |
| OutgoingRequestsDropped *StatCounter |
| |
| // OutgoingRequestSent is the number of ARP requests successfully written to a |
| // link-layer endpoint. |
| OutgoingRequestsSent *StatCounter |
| |
| // RepliesReceived is the number of ARP replies received. |
| RepliesReceived *StatCounter |
| |
| // OutgoingRepliesDropped is the number of ARP replies which failed to write |
| // to a link-layer endpoint. |
| OutgoingRepliesDropped *StatCounter |
| |
| // OutgoingRepliesSent is the number of ARP replies successfully written to a |
| // link-layer endpoint. |
| OutgoingRepliesSent *StatCounter |
| |
| // LINT.ThenChange(network/arp/stats.go:multiCounterARPStats) |
| } |
| |
| // TCPStats collects TCP-specific stats. |
| type TCPStats struct { |
| // ActiveConnectionOpenings is the number of connections opened |
| // successfully via Connect. |
| ActiveConnectionOpenings *StatCounter |
| |
| // PassiveConnectionOpenings is the number of connections opened |
| // successfully via Listen. |
| PassiveConnectionOpenings *StatCounter |
| |
| // CurrentEstablished is the number of TCP connections for which the |
| // current state is ESTABLISHED. |
| CurrentEstablished *StatCounter |
| |
| // CurrentConnected is the number of TCP connections that |
| // are in connected state. |
| CurrentConnected *StatCounter |
| |
| // EstablishedResets is the number of times TCP connections have made |
| // a direct transition to the CLOSED state from either the |
| // ESTABLISHED state or the CLOSE-WAIT state. |
| EstablishedResets *StatCounter |
| |
| // EstablishedClosed is the number of times established TCP connections |
| // made a transition to CLOSED state. |
| EstablishedClosed *StatCounter |
| |
| // EstablishedTimedout is the number of times an established connection |
| // was reset because of keep-alive time out. |
| EstablishedTimedout *StatCounter |
| |
| // ListenOverflowSynDrop is the number of times the listen queue overflowed |
| // and a SYN was dropped. |
| ListenOverflowSynDrop *StatCounter |
| |
| // ListenOverflowAckDrop is the number of times the final ACK |
| // in the handshake was dropped due to overflow. |
| ListenOverflowAckDrop *StatCounter |
| |
| // ListenOverflowCookieSent is the number of times a SYN cookie was sent. |
| ListenOverflowSynCookieSent *StatCounter |
| |
| // ListenOverflowSynCookieRcvd is the number of times a valid SYN |
| // cookie was received. |
| ListenOverflowSynCookieRcvd *StatCounter |
| |
| // ListenOverflowInvalidSynCookieRcvd is the number of times an invalid SYN cookie |
| // was received. |
| ListenOverflowInvalidSynCookieRcvd *StatCounter |
| |
| // FailedConnectionAttempts is the number of calls to Connect or Listen |
| // (active and passive openings, respectively) that end in an error. |
| FailedConnectionAttempts *StatCounter |
| |
| // ValidSegmentsReceived is the number of TCP segments received that |
| // the transport layer successfully parsed. |
| ValidSegmentsReceived *StatCounter |
| |
| // InvalidSegmentsReceived is the number of TCP segments received that |
| // the transport layer could not parse. |
| InvalidSegmentsReceived *StatCounter |
| |
| // SegmentsSent is the number of TCP segments sent. |
| SegmentsSent *StatCounter |
| |
| // SegmentSendErrors is the number of TCP segments failed to be sent. |
| SegmentSendErrors *StatCounter |
| |
| // ResetsSent is the number of TCP resets sent. |
| ResetsSent *StatCounter |
| |
| // ResetsReceived is the number of TCP resets received. |
| ResetsReceived *StatCounter |
| |
| // Retransmits is the number of TCP segments retransmitted. |
| Retransmits *StatCounter |
| |
| // FastRecovery is the number of times Fast Recovery was used to |
| // recover from packet loss. |
| FastRecovery *StatCounter |
| |
| // SACKRecovery is the number of times SACK Recovery was used to |
| // recover from packet loss. |
| SACKRecovery *StatCounter |
| |
| // TLPRecovery is the number of times recovery was accomplished by the tail |
| // loss probe. |
| TLPRecovery *StatCounter |
| |
| // SlowStartRetransmits is the number of segments retransmitted in slow |
| // start. |
| SlowStartRetransmits *StatCounter |
| |
| // FastRetransmit is the number of segments retransmitted in fast |
| // recovery. |
| FastRetransmit *StatCounter |
| |
| // Timeouts is the number of times the RTO expired. |
| Timeouts *StatCounter |
| |
| // ChecksumErrors is the number of segments dropped due to bad checksums. |
| ChecksumErrors *StatCounter |
| } |
| |
| // UDPStats collects UDP-specific stats. |
| type UDPStats struct { |
| // PacketsReceived is the number of UDP datagrams received via |
| // HandlePacket. |
| PacketsReceived *StatCounter |
| |
| // UnknownPortErrors is the number of incoming UDP datagrams dropped |
| // because they did not have a known destination port. |
| UnknownPortErrors *StatCounter |
| |
| // ReceiveBufferErrors is the number of incoming UDP datagrams dropped |
| // due to the receiving buffer being in an invalid state. |
| ReceiveBufferErrors *StatCounter |
| |
| // MalformedPacketsReceived is the number of incoming UDP datagrams |
| // dropped due to the UDP header being in a malformed state. |
| MalformedPacketsReceived *StatCounter |
| |
| // PacketsSent is the number of UDP datagrams sent via sendUDP. |
| PacketsSent *StatCounter |
| |
| // PacketSendErrors is the number of datagrams failed to be sent. |
| PacketSendErrors *StatCounter |
| |
| // ChecksumErrors is the number of datagrams dropped due to bad checksums. |
| ChecksumErrors *StatCounter |
| } |
| |
| // Stats holds statistics about the networking stack. |
| // |
| // All fields are optional. |
| type Stats struct { |
| // UnknownProtocolRcvdPackets is the number of packets received by the |
| // stack that were for an unknown or unsupported protocol. |
| UnknownProtocolRcvdPackets *StatCounter |
| |
| // MalformedRcvdPackets is the number of packets received by the stack |
| // that were deemed malformed. |
| MalformedRcvdPackets *StatCounter |
| |
| // DroppedPackets is the number of packets dropped due to full queues. |
| DroppedPackets *StatCounter |
| |
| // ICMP breaks out ICMP-specific stats (both v4 and v6). |
| ICMP ICMPStats |
| |
| // IGMP breaks out IGMP-specific stats. |
| IGMP IGMPStats |
| |
| // IP breaks out IP-specific stats (both v4 and v6). |
| IP IPStats |
| |
| // ARP breaks out ARP-specific stats. |
| ARP ARPStats |
| |
| // TCP breaks out TCP-specific stats. |
| TCP TCPStats |
| |
| // UDP breaks out UDP-specific stats. |
| UDP UDPStats |
| } |
| |
| // ReceiveErrors collects packet receive errors within transport endpoint. |
| type ReceiveErrors struct { |
| // ReceiveBufferOverflow is the number of received packets dropped |
| // due to the receive buffer being full. |
| ReceiveBufferOverflow StatCounter |
| |
| // MalformedPacketsReceived is the number of incoming packets |
| // dropped due to the packet header being in a malformed state. |
| MalformedPacketsReceived StatCounter |
| |
| // ClosedReceiver is the number of received packets dropped because |
| // of receiving endpoint state being closed. |
| ClosedReceiver StatCounter |
| |
| // ChecksumErrors is the number of packets dropped due to bad checksums. |
| ChecksumErrors StatCounter |
| } |
| |
| // SendErrors collects packet send errors within the transport layer for |
| // an endpoint. |
| type SendErrors struct { |
| // SendToNetworkFailed is the number of packets failed to be written to |
| // the network endpoint. |
| SendToNetworkFailed StatCounter |
| |
| // NoRoute is the number of times we failed to resolve IP route. |
| NoRoute StatCounter |
| } |
| |
| // ReadErrors collects segment read errors from an endpoint read call. |
| type ReadErrors struct { |
| // ReadClosed is the number of received packet drops because the endpoint |
| // was shutdown for read. |
| ReadClosed StatCounter |
| |
| // InvalidEndpointState is the number of times we found the endpoint state |
| // to be unexpected. |
| InvalidEndpointState StatCounter |
| |
| // NotConnected is the number of times we tried to read but found that the |
| // endpoint was not connected. |
| NotConnected StatCounter |
| } |
| |
| // WriteErrors collects packet write errors from an endpoint write call. |
| type WriteErrors struct { |
| // WriteClosed is the number of packet drops because the endpoint |
| // was shutdown for write. |
| WriteClosed StatCounter |
| |
| // InvalidEndpointState is the number of times we found the endpoint state |
| // to be unexpected. |
| InvalidEndpointState StatCounter |
| |
| // InvalidArgs is the number of times invalid input arguments were |
| // provided for endpoint Write call. |
| InvalidArgs StatCounter |
| } |
| |
| // TransportEndpointStats collects statistics about the endpoint. |
| type TransportEndpointStats struct { |
| // PacketsReceived is the number of successful packet receives. |
| PacketsReceived StatCounter |
| |
| // PacketsSent is the number of successful packet sends. |
| PacketsSent StatCounter |
| |
| // ReceiveErrors collects packet receive errors within transport layer. |
| ReceiveErrors ReceiveErrors |
| |
| // ReadErrors collects packet read errors from an endpoint read call. |
| ReadErrors ReadErrors |
| |
| // SendErrors collects packet send errors within the transport layer. |
| SendErrors SendErrors |
| |
| // WriteErrors collects packet write errors from an endpoint write call. |
| WriteErrors WriteErrors |
| } |
| |
| // IsEndpointStats is an empty method to implement the tcpip.EndpointStats |
| // marker interface. |
| func (*TransportEndpointStats) IsEndpointStats() {} |
| |
| // InitStatCounters initializes v's fields with nil StatCounter fields to new |
| // StatCounters. |
| func InitStatCounters(v reflect.Value) { |
| for i := 0; i < v.NumField(); i++ { |
| v := v.Field(i) |
| if s, ok := v.Addr().Interface().(**StatCounter); ok { |
| if *s == nil { |
| *s = new(StatCounter) |
| } |
| } else { |
| InitStatCounters(v) |
| } |
| } |
| } |
| |
| // FillIn returns a copy of s with nil fields initialized to new StatCounters. |
| func (s Stats) FillIn() Stats { |
| InitStatCounters(reflect.ValueOf(&s).Elem()) |
| return s |
| } |
| |
| // Clone returns a copy of the TransportEndpointStats by atomically reading |
| // each field. |
| func (src *TransportEndpointStats) Clone() TransportEndpointStats { |
| var dst TransportEndpointStats |
| clone(reflect.ValueOf(&dst).Elem(), reflect.ValueOf(src).Elem()) |
| return dst |
| } |
| |
| func clone(dst reflect.Value, src reflect.Value) { |
| for i := 0; i < dst.NumField(); i++ { |
| d := dst.Field(i) |
| s := src.Field(i) |
| if c, ok := s.Addr().Interface().(*StatCounter); ok { |
| d.Addr().Interface().(*StatCounter).IncrementBy(c.Value()) |
| } else { |
| clone(d, s) |
| } |
| } |
| } |
| |
| // String implements the fmt.Stringer interface. |
| func (a Address) String() string { |
| switch len(a) { |
| case 4: |
| return fmt.Sprintf("%d.%d.%d.%d", int(a[0]), int(a[1]), int(a[2]), int(a[3])) |
| case 16: |
| // Find the longest subsequence of hexadecimal zeros. |
| start, end := -1, -1 |
| for i := 0; i < len(a); i += 2 { |
| j := i |
| for j < len(a) && a[j] == 0 && a[j+1] == 0 { |
| j += 2 |
| } |
| if j > i+2 && j-i > end-start { |
| start, end = i, j |
| } |
| } |
| |
| var b strings.Builder |
| for i := 0; i < len(a); i += 2 { |
| if i == start { |
| b.WriteString("::") |
| i = end |
| if end >= len(a) { |
| break |
| } |
| } else if i > 0 { |
| b.WriteByte(':') |
| } |
| v := uint16(a[i+0])<<8 | uint16(a[i+1]) |
| if v == 0 { |
| b.WriteByte('0') |
| } else { |
| const digits = "0123456789abcdef" |
| for i := uint(3); i < 4; i-- { |
| if v := v >> (i * 4); v != 0 { |
| b.WriteByte(digits[v&0xf]) |
| } |
| } |
| } |
| } |
| return b.String() |
| default: |
| return fmt.Sprintf("%x", []byte(a)) |
| } |
| } |
| |
| // To4 converts the IPv4 address to a 4-byte representation. |
| // If the address is not an IPv4 address, To4 returns "". |
| func (a Address) To4() Address { |
| const ( |
| ipv4len = 4 |
| ipv6len = 16 |
| ) |
| if len(a) == ipv4len { |
| return a |
| } |
| if len(a) == ipv6len && |
| isZeros(a[0:10]) && |
| a[10] == 0xff && |
| a[11] == 0xff { |
| return a[12:16] |
| } |
| return "" |
| } |
| |
| // isZeros reports whether a is all zeros. |
| func isZeros(a Address) bool { |
| for i := 0; i < len(a); i++ { |
| if a[i] != 0 { |
| return false |
| } |
| } |
| return true |
| } |
| |
| // LinkAddress is a byte slice cast as a string that represents a link address. |
| // It is typically a 6-byte MAC address. |
| type LinkAddress string |
| |
| // String implements the fmt.Stringer interface. |
| func (a LinkAddress) String() string { |
| switch len(a) { |
| case 6: |
| return fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x", a[0], a[1], a[2], a[3], a[4], a[5]) |
| default: |
| return fmt.Sprintf("%x", []byte(a)) |
| } |
| } |
| |
| // ParseMACAddress parses an IEEE 802 address. |
| // |
| // It must be in the format aa:bb:cc:dd:ee:ff or aa-bb-cc-dd-ee-ff. |
| func ParseMACAddress(s string) (LinkAddress, error) { |
| parts := strings.FieldsFunc(s, func(c rune) bool { |
| return c == ':' || c == '-' |
| }) |
| if len(parts) != 6 { |
| return "", fmt.Errorf("inconsistent parts: %s", s) |
| } |
| addr := make([]byte, 0, len(parts)) |
| for _, part := range parts { |
| u, err := strconv.ParseUint(part, 16, 8) |
| if err != nil { |
| return "", fmt.Errorf("invalid hex digits: %s", s) |
| } |
| addr = append(addr, byte(u)) |
| } |
| return LinkAddress(addr), nil |
| } |
| |
| // AddressWithPrefix is an address with its subnet prefix length. |
| type AddressWithPrefix struct { |
| // Address is a network address. |
| Address Address |
| |
| // PrefixLen is the subnet prefix length. |
| PrefixLen int |
| } |
| |
| // String implements the fmt.Stringer interface. |
| func (a AddressWithPrefix) String() string { |
| return fmt.Sprintf("%s/%d", a.Address, a.PrefixLen) |
| } |
| |
| // Subnet converts the address and prefix into a Subnet value and returns it. |
| func (a AddressWithPrefix) Subnet() Subnet { |
| addrLen := len(a.Address) |
| if a.PrefixLen <= 0 { |
| return Subnet{ |
| address: Address(strings.Repeat("\x00", addrLen)), |
| mask: AddressMask(strings.Repeat("\x00", addrLen)), |
| } |
| } |
| if a.PrefixLen >= addrLen*8 { |
| return Subnet{ |
| address: a.Address, |
| mask: AddressMask(strings.Repeat("\xff", addrLen)), |
| } |
| } |
| |
| sa := make([]byte, addrLen) |
| sm := make([]byte, addrLen) |
| n := uint(a.PrefixLen) |
| for i := 0; i < addrLen; i++ { |
| if n >= 8 { |
| sa[i] = a.Address[i] |
| sm[i] = 0xff |
| n -= 8 |
| continue |
| } |
| sm[i] = ^byte(0xff >> n) |
| sa[i] = a.Address[i] & sm[i] |
| n = 0 |
| } |
| |
| // For extra caution, call NewSubnet rather than directly creating the Subnet |
| // value. If that fails it indicates a serious bug in this code, so panic is |
| // in order. |
| s, err := NewSubnet(Address(sa), AddressMask(sm)) |
| if err != nil { |
| panic("invalid subnet: " + err.Error()) |
| } |
| return s |
| } |
| |
| // ProtocolAddress is an address and the network protocol it is associated |
| // with. |
| type ProtocolAddress struct { |
| // Protocol is the protocol of the address. |
| Protocol NetworkProtocolNumber |
| |
| // AddressWithPrefix is a network address with its subnet prefix length. |
| AddressWithPrefix AddressWithPrefix |
| } |
| |
| var ( |
| // danglingEndpointsMu protects access to danglingEndpoints. |
| danglingEndpointsMu sync.Mutex |
| |
| // danglingEndpoints tracks all dangling endpoints no longer owned by the app. |
| danglingEndpoints = make(map[Endpoint]struct{}) |
| ) |
| |
| // GetDanglingEndpoints returns all dangling endpoints. |
| func GetDanglingEndpoints() []Endpoint { |
| danglingEndpointsMu.Lock() |
| es := make([]Endpoint, 0, len(danglingEndpoints)) |
| for e := range danglingEndpoints { |
| es = append(es, e) |
| } |
| danglingEndpointsMu.Unlock() |
| return es |
| } |
| |
| // AddDanglingEndpoint adds a dangling endpoint. |
| func AddDanglingEndpoint(e Endpoint) { |
| danglingEndpointsMu.Lock() |
| danglingEndpoints[e] = struct{}{} |
| danglingEndpointsMu.Unlock() |
| } |
| |
| // DeleteDanglingEndpoint removes a dangling endpoint. |
| func DeleteDanglingEndpoint(e Endpoint) { |
| danglingEndpointsMu.Lock() |
| delete(danglingEndpoints, e) |
| danglingEndpointsMu.Unlock() |
| } |
| |
| // AsyncLoading is the global barrier for asynchronous endpoint loading |
| // activities. |
| var AsyncLoading sync.WaitGroup |