2018-10-19 23:34:09 +00:00
|
|
|
// Copyright 2018 Google LLC
|
2018-07-09 21:03:03 +00:00
|
|
|
//
|
|
|
|
// 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.
|
2018-04-27 17:37:02 +00:00
|
|
|
|
|
|
|
package stack
|
|
|
|
|
|
|
|
import (
|
|
|
|
"gvisor.googlesource.com/gvisor/pkg/sleep"
|
|
|
|
"gvisor.googlesource.com/gvisor/pkg/tcpip"
|
|
|
|
"gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
|
|
|
|
"gvisor.googlesource.com/gvisor/pkg/tcpip/header"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Route represents a route through the networking stack to a given destination.
|
|
|
|
type Route struct {
|
|
|
|
// RemoteAddress is the final destination of the route.
|
|
|
|
RemoteAddress tcpip.Address
|
|
|
|
|
|
|
|
// RemoteLinkAddress is the link-layer (MAC) address of the
|
|
|
|
// final destination of the route.
|
|
|
|
RemoteLinkAddress tcpip.LinkAddress
|
|
|
|
|
|
|
|
// LocalAddress is the local address where the route starts.
|
|
|
|
LocalAddress tcpip.Address
|
|
|
|
|
|
|
|
// LocalLinkAddress is the link-layer (MAC) address of the
|
|
|
|
// where the route starts.
|
|
|
|
LocalLinkAddress tcpip.LinkAddress
|
|
|
|
|
|
|
|
// NextHop is the next node in the path to the destination.
|
|
|
|
NextHop tcpip.Address
|
|
|
|
|
|
|
|
// NetProto is the network-layer protocol.
|
|
|
|
NetProto tcpip.NetworkProtocolNumber
|
|
|
|
|
|
|
|
// ref a reference to the network endpoint through which the route
|
|
|
|
// starts.
|
|
|
|
ref *referencedNetworkEndpoint
|
2019-03-08 23:48:16 +00:00
|
|
|
|
2019-03-12 21:36:58 +00:00
|
|
|
// loop controls where WritePacket should send packets.
|
|
|
|
loop PacketLooping
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// makeRoute initializes a new route. It takes ownership of the provided
|
|
|
|
// reference to a network endpoint.
|
2019-03-12 21:36:58 +00:00
|
|
|
func makeRoute(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address, localLinkAddr tcpip.LinkAddress, ref *referencedNetworkEndpoint, handleLocal, multicastLoop bool) Route {
|
|
|
|
loop := PacketOut
|
|
|
|
if handleLocal && localAddr != "" && remoteAddr == localAddr {
|
|
|
|
loop = PacketLoop
|
|
|
|
} else if multicastLoop && (header.IsV4MulticastAddress(remoteAddr) || header.IsV6MulticastAddress(remoteAddr)) {
|
|
|
|
loop |= PacketLoop
|
|
|
|
}
|
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
return Route{
|
2018-08-09 05:02:09 +00:00
|
|
|
NetProto: netProto,
|
|
|
|
LocalAddress: localAddr,
|
|
|
|
LocalLinkAddress: localLinkAddr,
|
|
|
|
RemoteAddress: remoteAddr,
|
|
|
|
ref: ref,
|
2019-03-12 21:36:58 +00:00
|
|
|
loop: loop,
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NICID returns the id of the NIC from which this route originates.
|
|
|
|
func (r *Route) NICID() tcpip.NICID {
|
|
|
|
return r.ref.ep.NICID()
|
|
|
|
}
|
|
|
|
|
|
|
|
// MaxHeaderLength forwards the call to the network endpoint's implementation.
|
|
|
|
func (r *Route) MaxHeaderLength() uint16 {
|
|
|
|
return r.ref.ep.MaxHeaderLength()
|
|
|
|
}
|
|
|
|
|
2018-08-27 22:28:38 +00:00
|
|
|
// Stats returns a mutable copy of current stats.
|
|
|
|
func (r *Route) Stats() tcpip.Stats {
|
|
|
|
return r.ref.nic.stack.Stats()
|
|
|
|
}
|
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
// PseudoHeaderChecksum forwards the call to the network endpoint's
|
|
|
|
// implementation.
|
2019-03-27 00:14:04 +00:00
|
|
|
func (r *Route) PseudoHeaderChecksum(protocol tcpip.TransportProtocolNumber, totalLen uint16) uint16 {
|
|
|
|
return header.PseudoHeaderChecksum(protocol, r.LocalAddress, r.RemoteAddress, totalLen)
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Capabilities returns the link-layer capabilities of the route.
|
|
|
|
func (r *Route) Capabilities() LinkEndpointCapabilities {
|
|
|
|
return r.ref.ep.Capabilities()
|
|
|
|
}
|
|
|
|
|
2019-03-28 18:02:23 +00:00
|
|
|
// GSOMaxSize returns the maximum GSO packet size.
|
|
|
|
func (r *Route) GSOMaxSize() uint32 {
|
|
|
|
if gso, ok := r.ref.ep.(GSOEndpoint); ok {
|
|
|
|
return gso.GSOMaxSize()
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
// Resolve attempts to resolve the link address if necessary. Returns ErrWouldBlock in
|
|
|
|
// case address resolution requires blocking, e.g. wait for ARP reply. Waker is
|
|
|
|
// notified when address resolution is complete (success or not).
|
2018-09-28 17:59:21 +00:00
|
|
|
//
|
|
|
|
// If address resolution is required, ErrNoLinkAddress and a notification channel is
|
|
|
|
// returned for the top level caller to block. Channel is closed once address resolution
|
|
|
|
// is complete (success or not).
|
|
|
|
func (r *Route) Resolve(waker *sleep.Waker) (<-chan struct{}, *tcpip.Error) {
|
2018-04-27 17:37:02 +00:00
|
|
|
if !r.IsResolutionRequired() {
|
|
|
|
// Nothing to do if there is no cache (which does the resolution on cache miss) or
|
|
|
|
// link address is already known.
|
2018-09-28 17:59:21 +00:00
|
|
|
return nil, nil
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nextAddr := r.NextHop
|
|
|
|
if nextAddr == "" {
|
2018-08-09 05:02:09 +00:00
|
|
|
// Local link address is already known.
|
|
|
|
if r.RemoteAddress == r.LocalAddress {
|
|
|
|
r.RemoteLinkAddress = r.LocalLinkAddress
|
2018-09-28 17:59:21 +00:00
|
|
|
return nil, nil
|
2018-08-09 05:02:09 +00:00
|
|
|
}
|
2018-04-27 17:37:02 +00:00
|
|
|
nextAddr = r.RemoteAddress
|
|
|
|
}
|
2018-09-28 17:59:21 +00:00
|
|
|
linkAddr, ch, err := r.ref.linkCache.GetLinkAddress(r.ref.nic.ID(), nextAddr, r.LocalAddress, r.NetProto, waker)
|
2018-04-27 17:37:02 +00:00
|
|
|
if err != nil {
|
2018-09-28 17:59:21 +00:00
|
|
|
return ch, err
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
r.RemoteLinkAddress = linkAddr
|
2018-09-28 17:59:21 +00:00
|
|
|
return nil, nil
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// RemoveWaker removes a waker that has been added in Resolve().
|
|
|
|
func (r *Route) RemoveWaker(waker *sleep.Waker) {
|
|
|
|
nextAddr := r.NextHop
|
|
|
|
if nextAddr == "" {
|
|
|
|
nextAddr = r.RemoteAddress
|
|
|
|
}
|
|
|
|
r.ref.linkCache.RemoveWaker(r.ref.nic.ID(), nextAddr, waker)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsResolutionRequired returns true if Resolve() must be called to resolve
|
|
|
|
// the link address before the this route can be written to.
|
|
|
|
func (r *Route) IsResolutionRequired() bool {
|
|
|
|
return r.ref.linkCache != nil && r.RemoteLinkAddress == ""
|
|
|
|
}
|
|
|
|
|
|
|
|
// WritePacket writes the packet through the given route.
|
2019-03-28 18:02:23 +00:00
|
|
|
func (r *Route) WritePacket(gso *GSO, hdr buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.TransportProtocolNumber, ttl uint8) *tcpip.Error {
|
|
|
|
err := r.ref.ep.WritePacket(r, gso, hdr, payload, protocol, ttl, r.loop)
|
2019-03-19 15:29:37 +00:00
|
|
|
if err != nil {
|
2018-08-27 22:28:38 +00:00
|
|
|
r.Stats().IP.OutgoingPacketErrors.Increment()
|
2019-03-19 15:29:37 +00:00
|
|
|
} else {
|
|
|
|
r.ref.nic.stats.Tx.Packets.Increment()
|
|
|
|
r.ref.nic.stats.Tx.Bytes.IncrementBy(uint64(hdr.UsedLength() + payload.Size()))
|
2018-08-27 22:28:38 +00:00
|
|
|
}
|
|
|
|
return err
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
2018-09-13 03:38:27 +00:00
|
|
|
// DefaultTTL returns the default TTL of the underlying network endpoint.
|
|
|
|
func (r *Route) DefaultTTL() uint8 {
|
|
|
|
return r.ref.ep.DefaultTTL()
|
|
|
|
}
|
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
// MTU returns the MTU of the underlying network endpoint.
|
|
|
|
func (r *Route) MTU() uint32 {
|
|
|
|
return r.ref.ep.MTU()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release frees all resources associated with the route.
|
|
|
|
func (r *Route) Release() {
|
|
|
|
if r.ref != nil {
|
|
|
|
r.ref.decRef()
|
|
|
|
r.ref = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clone Clone a route such that the original one can be released and the new
|
|
|
|
// one will remain valid.
|
|
|
|
func (r *Route) Clone() Route {
|
|
|
|
r.ref.incRef()
|
|
|
|
return *r
|
|
|
|
}
|