github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/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  	"fmt"
    19  
    20  	"github.com/metacubex/gvisor/pkg/tcpip"
    21  	"github.com/metacubex/gvisor/pkg/tcpip/header"
    22  )
    23  
    24  // Route represents a route through the networking stack to a given destination.
    25  //
    26  // It is safe to call Route's methods from multiple goroutines.
    27  type Route struct {
    28  	routeInfo routeInfo
    29  
    30  	// localAddressNIC is the interface the address is associated with.
    31  	// TODO(gvisor.dev/issue/4548): Remove this field once we can query the
    32  	// address's assigned status without the NIC.
    33  	localAddressNIC *nic
    34  
    35  	// mu protects annotated fields below.
    36  	mu routeRWMutex
    37  
    38  	// localAddressEndpoint is the local address this route is associated with.
    39  	// +checklocks:mu
    40  	localAddressEndpoint AssignableAddressEndpoint
    41  
    42  	// remoteLinkAddress is the link-layer (MAC) address of the next hop.
    43  	// +checklocks:mu
    44  	remoteLinkAddress tcpip.LinkAddress
    45  
    46  	// outgoingNIC is the interface this route uses to write packets.
    47  	outgoingNIC *nic
    48  
    49  	// linkRes is set if link address resolution is enabled for this protocol on
    50  	// the route's NIC.
    51  	linkRes *linkResolver
    52  
    53  	// neighborEntry is the cached result of fetching a neighbor entry from the
    54  	// neighbor cache.
    55  	// +checklocks:mu
    56  	neighborEntry *neighborEntry
    57  }
    58  
    59  // +stateify savable
    60  type routeInfo struct {
    61  	RemoteAddress tcpip.Address
    62  
    63  	LocalAddress tcpip.Address
    64  
    65  	LocalLinkAddress tcpip.LinkAddress
    66  
    67  	NextHop tcpip.Address
    68  
    69  	NetProto tcpip.NetworkProtocolNumber
    70  
    71  	Loop PacketLooping
    72  }
    73  
    74  // RemoteAddress returns the route's destination.
    75  func (r *Route) RemoteAddress() tcpip.Address {
    76  	return r.routeInfo.RemoteAddress
    77  }
    78  
    79  // LocalAddress returns the route's local address.
    80  func (r *Route) LocalAddress() tcpip.Address {
    81  	return r.routeInfo.LocalAddress
    82  }
    83  
    84  // LocalLinkAddress returns the route's local link-layer address.
    85  func (r *Route) LocalLinkAddress() tcpip.LinkAddress {
    86  	return r.routeInfo.LocalLinkAddress
    87  }
    88  
    89  // NextHop returns the next node in the route's path to the destination.
    90  func (r *Route) NextHop() tcpip.Address {
    91  	return r.routeInfo.NextHop
    92  }
    93  
    94  // NetProto returns the route's network-layer protocol number.
    95  func (r *Route) NetProto() tcpip.NetworkProtocolNumber {
    96  	return r.routeInfo.NetProto
    97  }
    98  
    99  // Loop returns the route's required packet looping.
   100  func (r *Route) Loop() PacketLooping {
   101  	return r.routeInfo.Loop
   102  }
   103  
   104  // OutgoingNIC returns the route's outgoing NIC.
   105  func (r *Route) OutgoingNIC() tcpip.NICID {
   106  	return r.outgoingNIC.id
   107  }
   108  
   109  // RouteInfo contains all of Route's exported fields.
   110  //
   111  // +stateify savable
   112  type RouteInfo struct {
   113  	routeInfo
   114  
   115  	// RemoteLinkAddress is the link-layer (MAC) address of the next hop in the
   116  	// route.
   117  	RemoteLinkAddress tcpip.LinkAddress
   118  }
   119  
   120  // Fields returns a RouteInfo with all of the known values for the route's
   121  // fields.
   122  //
   123  // If any fields are unknown (e.g. remote link address when it is waiting for
   124  // link address resolution), they will be unset.
   125  func (r *Route) Fields() RouteInfo {
   126  	r.mu.RLock()
   127  	defer r.mu.RUnlock()
   128  	return r.fieldsLocked()
   129  }
   130  
   131  // +checklocksread:r.mu
   132  func (r *Route) fieldsLocked() RouteInfo {
   133  	return RouteInfo{
   134  		routeInfo:         r.routeInfo,
   135  		RemoteLinkAddress: r.remoteLinkAddress,
   136  	}
   137  }
   138  
   139  // constructAndValidateRoute validates and initializes a route. It takes
   140  // ownership of the provided local address.
   141  //
   142  // Returns an empty route if validation fails.
   143  func constructAndValidateRoute(netProto tcpip.NetworkProtocolNumber, addressEndpoint AssignableAddressEndpoint, localAddressNIC, outgoingNIC *nic, gateway, localAddr, remoteAddr tcpip.Address, handleLocal, multicastLoop bool) *Route {
   144  	if localAddr.BitLen() == 0 {
   145  		localAddr = addressEndpoint.AddressWithPrefix().Address
   146  	}
   147  
   148  	if localAddressNIC != outgoingNIC && header.IsV6LinkLocalUnicastAddress(localAddr) {
   149  		addressEndpoint.DecRef()
   150  		return nil
   151  	}
   152  
   153  	// If no remote address is provided, use the local address.
   154  	if remoteAddr.BitLen() == 0 {
   155  		remoteAddr = localAddr
   156  	}
   157  
   158  	r := makeRoute(
   159  		netProto,
   160  		gateway,
   161  		localAddr,
   162  		remoteAddr,
   163  		outgoingNIC,
   164  		localAddressNIC,
   165  		addressEndpoint,
   166  		handleLocal,
   167  		multicastLoop,
   168  	)
   169  
   170  	return r
   171  }
   172  
   173  // makeRoute initializes a new route. It takes ownership of the provided
   174  // AssignableAddressEndpoint.
   175  func makeRoute(netProto tcpip.NetworkProtocolNumber, gateway, localAddr, remoteAddr tcpip.Address, outgoingNIC, localAddressNIC *nic, localAddressEndpoint AssignableAddressEndpoint, handleLocal, multicastLoop bool) *Route {
   176  	if localAddressNIC.stack != outgoingNIC.stack {
   177  		panic(fmt.Sprintf("cannot create a route with NICs from different stacks"))
   178  	}
   179  
   180  	if localAddr.BitLen() == 0 {
   181  		localAddr = localAddressEndpoint.AddressWithPrefix().Address
   182  	}
   183  
   184  	loop := PacketOut
   185  
   186  	// TODO(gvisor.dev/issue/4689): Loopback interface loops back packets at the
   187  	// link endpoint level. We can remove this check once loopback interfaces
   188  	// loop back packets at the network layer.
   189  	if !outgoingNIC.IsLoopback() {
   190  		if handleLocal && localAddr != (tcpip.Address{}) && remoteAddr == localAddr {
   191  			loop = PacketLoop
   192  		} else if multicastLoop && (header.IsV4MulticastAddress(remoteAddr) || header.IsV6MulticastAddress(remoteAddr)) {
   193  			loop |= PacketLoop
   194  		} else if remoteAddr == header.IPv4Broadcast {
   195  			loop |= PacketLoop
   196  		} else if subnet := localAddressEndpoint.AddressWithPrefix().Subnet(); subnet.IsBroadcast(remoteAddr) {
   197  			loop |= PacketLoop
   198  		}
   199  	}
   200  
   201  	r := makeRouteInner(netProto, localAddr, remoteAddr, outgoingNIC, localAddressNIC, localAddressEndpoint, loop)
   202  	if r.Loop()&PacketOut == 0 {
   203  		// Packet will not leave the stack, no need for a gateway or a remote link
   204  		// address.
   205  		return r
   206  	}
   207  
   208  	if r.outgoingNIC.NetworkLinkEndpoint.Capabilities()&CapabilityResolutionRequired != 0 {
   209  		if linkRes, ok := r.outgoingNIC.linkAddrResolvers[r.NetProto()]; ok {
   210  			r.linkRes = linkRes
   211  		}
   212  	}
   213  
   214  	if gateway.BitLen() > 0 {
   215  		r.routeInfo.NextHop = gateway
   216  		return r
   217  	}
   218  
   219  	if r.linkRes == nil {
   220  		return r
   221  	}
   222  
   223  	if linkAddr, ok := r.linkRes.resolver.ResolveStaticAddress(r.RemoteAddress()); ok {
   224  		r.ResolveWith(linkAddr)
   225  		return r
   226  	}
   227  
   228  	if subnet := localAddressEndpoint.Subnet(); subnet.IsBroadcast(remoteAddr) {
   229  		r.ResolveWith(header.EthernetBroadcastAddress)
   230  		return r
   231  	}
   232  
   233  	if r.RemoteAddress() == r.LocalAddress() {
   234  		// Local link address is already known.
   235  		r.ResolveWith(r.LocalLinkAddress())
   236  	}
   237  
   238  	return r
   239  }
   240  
   241  func makeRouteInner(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address, outgoingNIC, localAddressNIC *nic, localAddressEndpoint AssignableAddressEndpoint, loop PacketLooping) *Route {
   242  	r := &Route{
   243  		routeInfo: routeInfo{
   244  			NetProto:         netProto,
   245  			LocalAddress:     localAddr,
   246  			LocalLinkAddress: outgoingNIC.NetworkLinkEndpoint.LinkAddress(),
   247  			RemoteAddress:    remoteAddr,
   248  			Loop:             loop,
   249  		},
   250  		localAddressNIC: localAddressNIC,
   251  		outgoingNIC:     outgoingNIC,
   252  	}
   253  
   254  	r.mu.Lock()
   255  	r.localAddressEndpoint = localAddressEndpoint
   256  	r.mu.Unlock()
   257  
   258  	return r
   259  }
   260  
   261  // makeLocalRoute initializes a new local route. It takes ownership of the
   262  // provided AssignableAddressEndpoint.
   263  //
   264  // A local route is a route to a destination that is local to the stack.
   265  func makeLocalRoute(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address, outgoingNIC, localAddressNIC *nic, localAddressEndpoint AssignableAddressEndpoint) *Route {
   266  	loop := PacketLoop
   267  	// TODO(gvisor.dev/issue/4689): Loopback interface loops back packets at the
   268  	// link endpoint level. We can remove this check once loopback interfaces
   269  	// loop back packets at the network layer.
   270  	if outgoingNIC.IsLoopback() {
   271  		loop = PacketOut
   272  	}
   273  	return makeRouteInner(netProto, localAddr, remoteAddr, outgoingNIC, localAddressNIC, localAddressEndpoint, loop)
   274  }
   275  
   276  // RemoteLinkAddress returns the link-layer (MAC) address of the next hop in
   277  // the route.
   278  func (r *Route) RemoteLinkAddress() tcpip.LinkAddress {
   279  	r.mu.RLock()
   280  	defer r.mu.RUnlock()
   281  	return r.remoteLinkAddress
   282  }
   283  
   284  // NICID returns the id of the NIC from which this route originates.
   285  func (r *Route) NICID() tcpip.NICID {
   286  	return r.outgoingNIC.ID()
   287  }
   288  
   289  // MaxHeaderLength forwards the call to the network endpoint's implementation.
   290  func (r *Route) MaxHeaderLength() uint16 {
   291  	return r.outgoingNIC.getNetworkEndpoint(r.NetProto()).MaxHeaderLength()
   292  }
   293  
   294  // Stats returns a mutable copy of current stats.
   295  func (r *Route) Stats() tcpip.Stats {
   296  	return r.outgoingNIC.stack.Stats()
   297  }
   298  
   299  // PseudoHeaderChecksum forwards the call to the network endpoint's
   300  // implementation.
   301  func (r *Route) PseudoHeaderChecksum(protocol tcpip.TransportProtocolNumber, totalLen uint16) uint16 {
   302  	return header.PseudoHeaderChecksum(protocol, r.LocalAddress(), r.RemoteAddress(), totalLen)
   303  }
   304  
   305  // RequiresTXTransportChecksum returns false if the route does not require
   306  // transport checksums to be populated.
   307  func (r *Route) RequiresTXTransportChecksum() bool {
   308  	if r.local() {
   309  		return false
   310  	}
   311  	return r.outgoingNIC.NetworkLinkEndpoint.Capabilities()&CapabilityTXChecksumOffload == 0
   312  }
   313  
   314  // HasGvisorGSOCapability returns true if the route supports gVisor GSO.
   315  func (r *Route) HasGvisorGSOCapability() bool {
   316  	if gso, ok := r.outgoingNIC.NetworkLinkEndpoint.(GSOEndpoint); ok {
   317  		return gso.SupportedGSO() == GvisorGSOSupported
   318  	}
   319  	return false
   320  }
   321  
   322  // HasHostGSOCapability returns true if the route supports host GSO.
   323  func (r *Route) HasHostGSOCapability() bool {
   324  	if gso, ok := r.outgoingNIC.NetworkLinkEndpoint.(GSOEndpoint); ok {
   325  		return gso.SupportedGSO() == HostGSOSupported
   326  	}
   327  	return false
   328  }
   329  
   330  // HasSaveRestoreCapability returns true if the route supports save/restore.
   331  func (r *Route) HasSaveRestoreCapability() bool {
   332  	return r.outgoingNIC.NetworkLinkEndpoint.Capabilities()&CapabilitySaveRestore != 0
   333  }
   334  
   335  // HasDisconnectOkCapability returns true if the route supports disconnecting.
   336  func (r *Route) HasDisconnectOkCapability() bool {
   337  	return r.outgoingNIC.NetworkLinkEndpoint.Capabilities()&CapabilityDisconnectOk != 0
   338  }
   339  
   340  // GSOMaxSize returns the maximum GSO packet size.
   341  func (r *Route) GSOMaxSize() uint32 {
   342  	if gso, ok := r.outgoingNIC.NetworkLinkEndpoint.(GSOEndpoint); ok {
   343  		return gso.GSOMaxSize()
   344  	}
   345  	return 0
   346  }
   347  
   348  // ResolveWith immediately resolves a route with the specified remote link
   349  // address.
   350  func (r *Route) ResolveWith(addr tcpip.LinkAddress) {
   351  	r.mu.Lock()
   352  	defer r.mu.Unlock()
   353  	r.remoteLinkAddress = addr
   354  }
   355  
   356  // ResolvedFieldsResult is the result of a route resolution attempt.
   357  type ResolvedFieldsResult struct {
   358  	RouteInfo RouteInfo
   359  	Err       tcpip.Error
   360  }
   361  
   362  // ResolvedFields attempts to resolve the remote link address if it is not
   363  // known.
   364  //
   365  // If a callback is provided, it will be called before ResolvedFields returns
   366  // when address resolution is not required. If address resolution is required,
   367  // the callback will be called once address resolution is complete, regardless
   368  // of success or failure.
   369  //
   370  // Note, the route will not cache the remote link address when address
   371  // resolution completes.
   372  func (r *Route) ResolvedFields(afterResolve func(ResolvedFieldsResult)) tcpip.Error {
   373  	_, _, err := r.resolvedFields(afterResolve)
   374  	return err
   375  }
   376  
   377  // resolvedFields is like ResolvedFields but also returns a notification channel
   378  // when address resolution is required. This channel will become readable once
   379  // address resolution is complete.
   380  //
   381  // The route's fields will also be returned, regardless of whether address
   382  // resolution is required or not.
   383  func (r *Route) resolvedFields(afterResolve func(ResolvedFieldsResult)) (RouteInfo, <-chan struct{}, tcpip.Error) {
   384  	r.mu.RLock()
   385  	fields := r.fieldsLocked()
   386  	resolutionRequired := r.isResolutionRequiredRLocked()
   387  	r.mu.RUnlock()
   388  	if !resolutionRequired {
   389  		if afterResolve != nil {
   390  			afterResolve(ResolvedFieldsResult{RouteInfo: fields, Err: nil})
   391  		}
   392  		return fields, nil, nil
   393  	}
   394  
   395  	// If specified, the local address used for link address resolution must be an
   396  	// address on the outgoing interface.
   397  	var linkAddressResolutionRequestLocalAddr tcpip.Address
   398  	if r.localAddressNIC == r.outgoingNIC {
   399  		linkAddressResolutionRequestLocalAddr = r.LocalAddress()
   400  	}
   401  
   402  	nEntry := r.getCachedNeighborEntry()
   403  	if nEntry != nil {
   404  		if addr, ok := nEntry.getRemoteLinkAddress(); ok {
   405  			fields.RemoteLinkAddress = addr
   406  			if afterResolve != nil {
   407  				afterResolve(ResolvedFieldsResult{RouteInfo: fields, Err: nil})
   408  			}
   409  			return fields, nil, nil
   410  		}
   411  	}
   412  	afterResolveFields := fields
   413  	entry, ch, err := r.linkRes.neigh.entry(r.nextHop(), linkAddressResolutionRequestLocalAddr, func(lrr LinkResolutionResult) {
   414  		if afterResolve != nil {
   415  			if lrr.Err == nil {
   416  				afterResolveFields.RemoteLinkAddress = lrr.LinkAddress
   417  			}
   418  
   419  			afterResolve(ResolvedFieldsResult{RouteInfo: afterResolveFields, Err: lrr.Err})
   420  		}
   421  	})
   422  	if err == nil {
   423  		fields.RemoteLinkAddress, _ = entry.getRemoteLinkAddress()
   424  	}
   425  	r.setCachedNeighborEntry(entry)
   426  	return fields, ch, err
   427  }
   428  
   429  func (r *Route) getCachedNeighborEntry() *neighborEntry {
   430  	r.mu.RLock()
   431  	defer r.mu.RUnlock()
   432  	return r.neighborEntry
   433  }
   434  
   435  func (r *Route) setCachedNeighborEntry(entry *neighborEntry) {
   436  	r.mu.Lock()
   437  	defer r.mu.Unlock()
   438  	r.neighborEntry = entry
   439  }
   440  
   441  func (r *Route) nextHop() tcpip.Address {
   442  	if r.NextHop().BitLen() == 0 {
   443  		return r.RemoteAddress()
   444  	}
   445  	return r.NextHop()
   446  }
   447  
   448  // local returns true if the route is a local route.
   449  func (r *Route) local() bool {
   450  	return r.Loop() == PacketLoop || r.outgoingNIC.IsLoopback()
   451  }
   452  
   453  // IsResolutionRequired returns true if Resolve() must be called to resolve
   454  // the link address before the route can be written to.
   455  //
   456  // The NICs the route is associated with must not be locked.
   457  func (r *Route) IsResolutionRequired() bool {
   458  	r.mu.RLock()
   459  	defer r.mu.RUnlock()
   460  	return r.isResolutionRequiredRLocked()
   461  }
   462  
   463  // +checklocksread:r.mu
   464  func (r *Route) isResolutionRequiredRLocked() bool {
   465  	return len(r.remoteLinkAddress) == 0 && r.linkRes != nil && r.isValidForOutgoingRLocked() && !r.local()
   466  }
   467  
   468  func (r *Route) isValidForOutgoing() bool {
   469  	r.mu.RLock()
   470  	defer r.mu.RUnlock()
   471  	return r.isValidForOutgoingRLocked()
   472  }
   473  
   474  // +checklocksread:r.mu
   475  func (r *Route) isValidForOutgoingRLocked() bool {
   476  	if !r.outgoingNIC.Enabled() {
   477  		return false
   478  	}
   479  
   480  	localAddressEndpoint := r.localAddressEndpoint
   481  	if localAddressEndpoint == nil || !r.localAddressNIC.isValidForOutgoing(localAddressEndpoint) {
   482  		return false
   483  	}
   484  
   485  	// If the source NIC and outgoing NIC are different, make sure the stack has
   486  	// forwarding enabled, or the packet will be handled locally.
   487  	if r.outgoingNIC != r.localAddressNIC && !isNICForwarding(r.localAddressNIC, r.NetProto()) && (!r.outgoingNIC.stack.handleLocal || !r.outgoingNIC.hasAddress(r.NetProto(), r.RemoteAddress())) {
   488  		return false
   489  	}
   490  
   491  	return true
   492  }
   493  
   494  // WritePacket writes the packet through the given route.
   495  func (r *Route) WritePacket(params NetworkHeaderParams, pkt *PacketBuffer) tcpip.Error {
   496  	if !r.isValidForOutgoing() {
   497  		return &tcpip.ErrInvalidEndpointState{}
   498  	}
   499  
   500  	return r.outgoingNIC.getNetworkEndpoint(r.NetProto()).WritePacket(r, params, pkt)
   501  }
   502  
   503  // WriteHeaderIncludedPacket writes a packet already containing a network
   504  // header through the given route.
   505  func (r *Route) WriteHeaderIncludedPacket(pkt *PacketBuffer) tcpip.Error {
   506  	if !r.isValidForOutgoing() {
   507  		return &tcpip.ErrInvalidEndpointState{}
   508  	}
   509  
   510  	return r.outgoingNIC.getNetworkEndpoint(r.NetProto()).WriteHeaderIncludedPacket(r, pkt)
   511  }
   512  
   513  // DefaultTTL returns the default TTL of the underlying network endpoint.
   514  func (r *Route) DefaultTTL() uint8 {
   515  	return r.outgoingNIC.getNetworkEndpoint(r.NetProto()).DefaultTTL()
   516  }
   517  
   518  // MTU returns the MTU of the underlying network endpoint.
   519  func (r *Route) MTU() uint32 {
   520  	return r.outgoingNIC.getNetworkEndpoint(r.NetProto()).MTU()
   521  }
   522  
   523  // Release decrements the reference counter of the resources associated with the
   524  // route.
   525  func (r *Route) Release() {
   526  	r.mu.Lock()
   527  	defer r.mu.Unlock()
   528  
   529  	if ep := r.localAddressEndpoint; ep != nil {
   530  		ep.DecRef()
   531  	}
   532  }
   533  
   534  // Acquire increments the reference counter of the resources associated with the
   535  // route.
   536  func (r *Route) Acquire() {
   537  	r.mu.RLock()
   538  	defer r.mu.RUnlock()
   539  	r.acquireLocked()
   540  }
   541  
   542  // +checklocksread:r.mu
   543  func (r *Route) acquireLocked() {
   544  	if ep := r.localAddressEndpoint; ep != nil {
   545  		if !ep.TryIncRef() {
   546  			panic(fmt.Sprintf("failed to increment reference count for local address endpoint = %s", r.LocalAddress()))
   547  		}
   548  	}
   549  }
   550  
   551  // Stack returns the instance of the Stack that owns this route.
   552  func (r *Route) Stack() *Stack {
   553  	return r.outgoingNIC.stack
   554  }
   555  
   556  func (r *Route) isV4Broadcast(addr tcpip.Address) bool {
   557  	if addr == header.IPv4Broadcast {
   558  		return true
   559  	}
   560  
   561  	r.mu.RLock()
   562  	localAddressEndpoint := r.localAddressEndpoint
   563  	r.mu.RUnlock()
   564  	if localAddressEndpoint == nil {
   565  		return false
   566  	}
   567  
   568  	subnet := localAddressEndpoint.Subnet()
   569  	return subnet.IsBroadcast(addr)
   570  }
   571  
   572  // IsOutboundBroadcast returns true if the route is for an outbound broadcast
   573  // packet.
   574  func (r *Route) IsOutboundBroadcast() bool {
   575  	// Only IPv4 has a notion of broadcast.
   576  	return r.isV4Broadcast(r.RemoteAddress())
   577  }
   578  
   579  // ConfirmReachable informs the network/link layer that the neighbour used for
   580  // the route is reachable.
   581  //
   582  // "Reachable" is defined as having full-duplex communication between the
   583  // local and remote ends of the route.
   584  func (r *Route) ConfirmReachable() {
   585  	if entry := r.getCachedNeighborEntry(); entry != nil {
   586  		entry.handleUpperLevelConfirmation()
   587  	}
   588  }