github.com/flowerwrong/netstack@v0.0.0-20191009141956-e5848263af28/tcpip/stack/route.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package stack
    16  
    17  import (
    18  	"github.com/FlowerWrong/netstack/sleep"
    19  	"github.com/FlowerWrong/netstack/tcpip"
    20  	"github.com/FlowerWrong/netstack/tcpip/buffer"
    21  	"github.com/FlowerWrong/netstack/tcpip/header"
    22  )
    23  
    24  // Route represents a route through the networking stack to a given destination.
    25  type Route struct {
    26  	// RemoteAddress is the final destination of the route.
    27  	RemoteAddress tcpip.Address
    28  
    29  	// RemoteLinkAddress is the link-layer (MAC) address of the
    30  	// final destination of the route.
    31  	RemoteLinkAddress tcpip.LinkAddress
    32  
    33  	// LocalAddress is the local address where the route starts.
    34  	LocalAddress tcpip.Address
    35  
    36  	// LocalLinkAddress is the link-layer (MAC) address of the
    37  	// where the route starts.
    38  	LocalLinkAddress tcpip.LinkAddress
    39  
    40  	// NextHop is the next node in the path to the destination.
    41  	NextHop tcpip.Address
    42  
    43  	// NetProto is the network-layer protocol.
    44  	NetProto tcpip.NetworkProtocolNumber
    45  
    46  	// ref a reference to the network endpoint through which the route
    47  	// starts.
    48  	ref *referencedNetworkEndpoint
    49  
    50  	// loop controls where WritePacket should send packets.
    51  	loop PacketLooping
    52  }
    53  
    54  // makeRoute initializes a new route. It takes ownership of the provided
    55  // reference to a network endpoint.
    56  func makeRoute(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address, localLinkAddr tcpip.LinkAddress, ref *referencedNetworkEndpoint, handleLocal, multicastLoop bool) Route {
    57  	loop := PacketOut
    58  	if handleLocal && localAddr != "" && remoteAddr == localAddr {
    59  		loop = PacketLoop
    60  	} else if multicastLoop && (header.IsV4MulticastAddress(remoteAddr) || header.IsV6MulticastAddress(remoteAddr)) {
    61  		loop |= PacketLoop
    62  	} else if remoteAddr == header.IPv4Broadcast {
    63  		loop |= PacketLoop
    64  	}
    65  
    66  	return Route{
    67  		NetProto:         netProto,
    68  		LocalAddress:     localAddr,
    69  		LocalLinkAddress: localLinkAddr,
    70  		RemoteAddress:    remoteAddr,
    71  		ref:              ref,
    72  		loop:             loop,
    73  	}
    74  }
    75  
    76  // NICID returns the id of the NIC from which this route originates.
    77  func (r *Route) NICID() tcpip.NICID {
    78  	return r.ref.ep.NICID()
    79  }
    80  
    81  // MaxHeaderLength forwards the call to the network endpoint's implementation.
    82  func (r *Route) MaxHeaderLength() uint16 {
    83  	return r.ref.ep.MaxHeaderLength()
    84  }
    85  
    86  // Stats returns a mutable copy of current stats.
    87  func (r *Route) Stats() tcpip.Stats {
    88  	return r.ref.nic.stack.Stats()
    89  }
    90  
    91  // PseudoHeaderChecksum forwards the call to the network endpoint's
    92  // implementation.
    93  func (r *Route) PseudoHeaderChecksum(protocol tcpip.TransportProtocolNumber, totalLen uint16) uint16 {
    94  	return header.PseudoHeaderChecksum(protocol, r.LocalAddress, r.RemoteAddress, totalLen)
    95  }
    96  
    97  // Capabilities returns the link-layer capabilities of the route.
    98  func (r *Route) Capabilities() LinkEndpointCapabilities {
    99  	return r.ref.ep.Capabilities()
   100  }
   101  
   102  // GSOMaxSize returns the maximum GSO packet size.
   103  func (r *Route) GSOMaxSize() uint32 {
   104  	if gso, ok := r.ref.ep.(GSOEndpoint); ok {
   105  		return gso.GSOMaxSize()
   106  	}
   107  	return 0
   108  }
   109  
   110  // Resolve attempts to resolve the link address if necessary. Returns ErrWouldBlock in
   111  // case address resolution requires blocking, e.g. wait for ARP reply. Waker is
   112  // notified when address resolution is complete (success or not).
   113  //
   114  // If address resolution is required, ErrNoLinkAddress and a notification channel is
   115  // returned for the top level caller to block. Channel is closed once address resolution
   116  // is complete (success or not).
   117  func (r *Route) Resolve(waker *sleep.Waker) (<-chan struct{}, *tcpip.Error) {
   118  	if !r.IsResolutionRequired() {
   119  		// Nothing to do if there is no cache (which does the resolution on cache miss) or
   120  		// link address is already known.
   121  		return nil, nil
   122  	}
   123  
   124  	nextAddr := r.NextHop
   125  	if nextAddr == "" {
   126  		// Local link address is already known.
   127  		if r.RemoteAddress == r.LocalAddress {
   128  			r.RemoteLinkAddress = r.LocalLinkAddress
   129  			return nil, nil
   130  		}
   131  		nextAddr = r.RemoteAddress
   132  	}
   133  	linkAddr, ch, err := r.ref.linkCache.GetLinkAddress(r.ref.nic.ID(), nextAddr, r.LocalAddress, r.NetProto, waker)
   134  	if err != nil {
   135  		return ch, err
   136  	}
   137  	r.RemoteLinkAddress = linkAddr
   138  	return nil, nil
   139  }
   140  
   141  // RemoveWaker removes a waker that has been added in Resolve().
   142  func (r *Route) RemoveWaker(waker *sleep.Waker) {
   143  	nextAddr := r.NextHop
   144  	if nextAddr == "" {
   145  		nextAddr = r.RemoteAddress
   146  	}
   147  	r.ref.linkCache.RemoveWaker(r.ref.nic.ID(), nextAddr, waker)
   148  }
   149  
   150  // IsResolutionRequired returns true if Resolve() must be called to resolve
   151  // the link address before the this route can be written to.
   152  func (r *Route) IsResolutionRequired() bool {
   153  	return r.ref.isValidForOutgoing() && r.ref.linkCache != nil && r.RemoteLinkAddress == ""
   154  }
   155  
   156  // WritePacket writes the packet through the given route.
   157  func (r *Route) WritePacket(gso *GSO, hdr buffer.Prependable, payload buffer.VectorisedView, protocol tcpip.TransportProtocolNumber, ttl uint8, useDefaultTTL bool) *tcpip.Error {
   158  	if !r.ref.isValidForOutgoing() {
   159  		return tcpip.ErrInvalidEndpointState
   160  	}
   161  
   162  	if useDefaultTTL {
   163  		ttl = r.DefaultTTL()
   164  	}
   165  
   166  	err := r.ref.ep.WritePacket(r, gso, hdr, payload, protocol, ttl, r.loop)
   167  	if err != nil {
   168  		r.Stats().IP.OutgoingPacketErrors.Increment()
   169  	} else {
   170  		r.ref.nic.stats.Tx.Packets.Increment()
   171  		r.ref.nic.stats.Tx.Bytes.IncrementBy(uint64(hdr.UsedLength() + payload.Size()))
   172  	}
   173  	return err
   174  }
   175  
   176  // WriteHeaderIncludedPacket writes a packet already containing a network
   177  // header through the given route.
   178  func (r *Route) WriteHeaderIncludedPacket(payload buffer.VectorisedView) *tcpip.Error {
   179  	if !r.ref.isValidForOutgoing() {
   180  		return tcpip.ErrInvalidEndpointState
   181  	}
   182  
   183  	if err := r.ref.ep.WriteHeaderIncludedPacket(r, payload, r.loop); err != nil {
   184  		r.Stats().IP.OutgoingPacketErrors.Increment()
   185  		return err
   186  	}
   187  	r.ref.nic.stats.Tx.Packets.Increment()
   188  	r.ref.nic.stats.Tx.Bytes.IncrementBy(uint64(payload.Size()))
   189  	return nil
   190  }
   191  
   192  // DefaultTTL returns the default TTL of the underlying network endpoint.
   193  func (r *Route) DefaultTTL() uint8 {
   194  	return r.ref.ep.DefaultTTL()
   195  }
   196  
   197  // MTU returns the MTU of the underlying network endpoint.
   198  func (r *Route) MTU() uint32 {
   199  	return r.ref.ep.MTU()
   200  }
   201  
   202  // Release frees all resources associated with the route.
   203  func (r *Route) Release() {
   204  	if r.ref != nil {
   205  		r.ref.decRef()
   206  		r.ref = nil
   207  	}
   208  }
   209  
   210  // Clone Clone a route such that the original one can be released and the new
   211  // one will remain valid.
   212  func (r *Route) Clone() Route {
   213  	r.ref.incRef()
   214  	return *r
   215  }
   216  
   217  // MakeLoopedRoute duplicates the given route with special handling for routes
   218  // used for sending multicast or broadcast packets. In those cases the
   219  // multicast/broadcast address is the remote address when sending out, but for
   220  // incoming (looped) packets it becomes the local address. Similarly, the local
   221  // interface address that was the local address going out becomes the remote
   222  // address coming in. This is different to unicast routes where local and
   223  // remote addresses remain the same as they identify location (local vs remote)
   224  // not direction (source vs destination).
   225  func (r *Route) MakeLoopedRoute() Route {
   226  	l := r.Clone()
   227  	if r.RemoteAddress == header.IPv4Broadcast || header.IsV4MulticastAddress(r.RemoteAddress) || header.IsV6MulticastAddress(r.RemoteAddress) {
   228  		l.RemoteAddress, l.LocalAddress = l.LocalAddress, l.RemoteAddress
   229  		l.RemoteLinkAddress = l.LocalLinkAddress
   230  	}
   231  	return l
   232  }
   233  
   234  // Stack returns the instance of the Stack that owns this route.
   235  func (r *Route) Stack() *Stack {
   236  	return r.ref.stack()
   237  }