blob: 476c2c616643889baa41b5a22658cd54e91d0ed6 [file] [log] [blame]
// Copyright 2016 The Netstack Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package stack
import (
"sync/atomic"
"time"
"github.com/google/netstack/tcpip"
"github.com/google/netstack/tcpip/buffer"
"github.com/google/netstack/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
}
// makeRoute initializes a new route. It takes ownership of the provided
// reference to a network endpoint.
func makeRoute(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address, ref *referencedNetworkEndpoint) Route {
return Route{
NetProto: netProto,
LocalAddress: localAddr,
RemoteAddress: remoteAddr,
ref: ref,
}
}
// 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()
}
// MutableStats returns a mutable copy of the referenced endpoint's Stats
// struct, for stats updates where we only have a reference to the Route.
func (r *Route) MutableStats() *tcpip.Stats {
return r.ref.nic.stack.MutableStats()
}
// PseudoHeaderChecksum forwards the call to the network endpoint's
// implementation.
func (r *Route) PseudoHeaderChecksum(protocol tcpip.TransportProtocolNumber) uint16 {
return header.PseudoHeaderChecksum(protocol, r.LocalAddress, r.RemoteAddress)
}
func isLoopback(addr tcpip.Address) bool {
return (len(addr) == 4 && addr[0] == 127) || addr == header.IPv6Loopback
}
// WritePacket writes the packet through the given route.
func (r *Route) WritePacket(hdr *buffer.Prependable, payload buffer.View, protocol tcpip.TransportProtocolNumber, ttl uint8) *tcpip.Error {
if r.RemoteLinkAddress == "" && r.ref.linkRes != nil && !isLoopback(r.RemoteAddress) {
nextAddr := r.NextHop
if nextAddr == "" {
nextAddr = r.RemoteAddress
}
nicid := r.ref.nic.ID()
r.RemoteLinkAddress = r.ref.linkCache.GetLinkAddress(nicid, nextAddr, 0)
if r.RemoteLinkAddress == "" {
r.ref.linkRes.LinkAddressRequest(nextAddr, r.LocalAddress, r.ref.linkEP)
r.RemoteLinkAddress = r.ref.linkCache.GetLinkAddress(nicid, nextAddr, 250*time.Millisecond)
}
if r.RemoteLinkAddress == "" {
atomic.AddUint64(&r.MutableStats().IP.OutgoingPacketErrors, 1)
return tcpip.ErrNoLinkAddress
}
}
return r.ref.ep.WritePacket(r, hdr, payload, protocol, ttl)
}
// DefaultTTL returns the default TTL of the underlying network endpoint.
func (r *Route) DefaultTTL() uint8 {
return r.ref.ep.DefaultTTL()
}
// 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
}