| // 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 |
| } |