mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Resolve known link address on route creation
If a Route is being created through a link that requires link address resolution and a remote address that has a known mapping to a link address, populate the link address when the route is created. This removes the need for neighbor/link address caches to perform this check. Fixes #5149 PiperOrigin-RevId: 352122401
This commit is contained in:
committed by
gVisor bot
parent
2814a032be
commit
cd75bb163f
@@ -182,15 +182,6 @@ func (c *linkAddrCache) getOrCreateEntryLocked(k tcpip.FullAddress) *linkAddrEnt
|
||||
|
||||
// get reports any known link address for k.
|
||||
func (c *linkAddrCache) get(k tcpip.FullAddress, linkRes LinkAddressResolver, localAddr tcpip.Address, nic NetworkInterface, onResolve func(tcpip.LinkAddress, bool)) (tcpip.LinkAddress, <-chan struct{}, *tcpip.Error) {
|
||||
if linkRes != nil {
|
||||
if addr, ok := linkRes.ResolveStaticAddress(k.Addr); ok {
|
||||
if onResolve != nil {
|
||||
onResolve(addr, true)
|
||||
}
|
||||
return addr, nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
c.cache.Lock()
|
||||
defer c.cache.Unlock()
|
||||
entry := c.getOrCreateEntryLocked(k)
|
||||
|
||||
@@ -273,20 +273,3 @@ func TestCacheResolutionTimeout(t *testing.T) {
|
||||
t.Errorf("got getBlocking(_, %#v, _) = (%s, %s), want = (_, %s)", e.addr, a, err, tcpip.ErrTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
// TestStaticResolution checks that static link addresses are resolved immediately and don't
|
||||
// send resolution requests.
|
||||
func TestStaticResolution(t *testing.T) {
|
||||
c := newLinkAddrCache(1<<63-1, time.Millisecond, 1)
|
||||
linkRes := &testLinkAddressResolver{cache: c, delay: time.Minute}
|
||||
|
||||
addr := tcpip.Address("broadcast")
|
||||
want := tcpip.LinkAddress("mac_broadcast")
|
||||
got, _, err := c.get(tcpip.FullAddress{Addr: addr}, linkRes, "", nil, nil)
|
||||
if err != nil {
|
||||
t.Errorf("c.get(%q)=%q, got error: %v", string(addr), string(got), err)
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("c.get(%q)=%q, want %q", string(addr), string(got), string(want))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,20 +127,6 @@ func (n *neighborCache) getOrCreateEntry(remoteAddr tcpip.Address, linkRes LinkA
|
||||
//
|
||||
// TODO(gvisor.dev/issue/5151): Don't return the neighbor entry.
|
||||
func (n *neighborCache) entry(remoteAddr, localAddr tcpip.Address, linkRes LinkAddressResolver, onResolve func(tcpip.LinkAddress, bool)) (NeighborEntry, <-chan struct{}, *tcpip.Error) {
|
||||
// TODO(gvisor.dev/issue/5149): Handle static resolution in route.Resolve.
|
||||
if linkAddr, ok := linkRes.ResolveStaticAddress(remoteAddr); ok {
|
||||
e := NeighborEntry{
|
||||
Addr: remoteAddr,
|
||||
LinkAddr: linkAddr,
|
||||
State: Static,
|
||||
UpdatedAtNanos: 0,
|
||||
}
|
||||
if onResolve != nil {
|
||||
onResolve(linkAddr, true)
|
||||
}
|
||||
return e, nil, nil
|
||||
}
|
||||
|
||||
entry := n.getOrCreateEntry(remoteAddr, linkRes)
|
||||
entry.mu.Lock()
|
||||
defer entry.mu.Unlock()
|
||||
|
||||
@@ -1750,34 +1750,6 @@ func TestNeighborCacheRetryResolution(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestNeighborCacheStaticResolution checks that static link addresses are
|
||||
// resolved immediately and don't send resolution requests.
|
||||
func TestNeighborCacheStaticResolution(t *testing.T) {
|
||||
config := DefaultNUDConfigurations()
|
||||
clock := faketime.NewManualClock()
|
||||
neigh := newTestNeighborCache(nil, config, clock)
|
||||
store := newTestEntryStore()
|
||||
linkRes := &testNeighborResolver{
|
||||
clock: clock,
|
||||
neigh: neigh,
|
||||
entries: store,
|
||||
delay: typicalLatency,
|
||||
}
|
||||
|
||||
got, _, err := neigh.entry(testEntryBroadcastAddr, "", linkRes, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error from neigh.entry(%s, '', _, nil, nil): %s", testEntryBroadcastAddr, err)
|
||||
}
|
||||
want := NeighborEntry{
|
||||
Addr: testEntryBroadcastAddr,
|
||||
LinkAddr: testEntryBroadcastLinkAddr,
|
||||
State: Static,
|
||||
}
|
||||
if diff := cmp.Diff(got, want, entryDiffOpts()...); diff != "" {
|
||||
t.Errorf("neigh.entry(%s, '', _, nil, nil) mismatch (-got, +want):\n%s", testEntryBroadcastAddr, diff)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCacheClear(b *testing.B) {
|
||||
b.StopTimer()
|
||||
config := DefaultNUDConfigurations()
|
||||
|
||||
+45
-27
@@ -116,6 +116,7 @@ func constructAndValidateRoute(netProto tcpip.NetworkProtocolNumber, addressEndp
|
||||
|
||||
r := makeRoute(
|
||||
netProto,
|
||||
gateway,
|
||||
localAddr,
|
||||
remoteAddr,
|
||||
outgoingNIC,
|
||||
@@ -125,20 +126,12 @@ func constructAndValidateRoute(netProto tcpip.NetworkProtocolNumber, addressEndp
|
||||
multicastLoop,
|
||||
)
|
||||
|
||||
// If the route requires us to send a packet through some gateway, do not
|
||||
// broadcast it.
|
||||
if len(gateway) > 0 {
|
||||
r.NextHop = gateway
|
||||
} else if subnet := addressEndpoint.Subnet(); subnet.IsBroadcast(remoteAddr) {
|
||||
r.ResolveWith(header.EthernetBroadcastAddress)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// makeRoute initializes a new route. It takes ownership of the provided
|
||||
// AssignableAddressEndpoint.
|
||||
func makeRoute(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address, outgoingNIC, localAddressNIC *NIC, localAddressEndpoint AssignableAddressEndpoint, handleLocal, multicastLoop bool) *Route {
|
||||
func makeRoute(netProto tcpip.NetworkProtocolNumber, gateway, localAddr, remoteAddr tcpip.Address, outgoingNIC, localAddressNIC *NIC, localAddressEndpoint AssignableAddressEndpoint, handleLocal, multicastLoop bool) *Route {
|
||||
if localAddressNIC.stack != outgoingNIC.stack {
|
||||
panic(fmt.Sprintf("cannot create a route with NICs from different stacks"))
|
||||
}
|
||||
@@ -164,7 +157,44 @@ func makeRoute(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip
|
||||
}
|
||||
}
|
||||
|
||||
return makeRouteInner(netProto, localAddr, remoteAddr, outgoingNIC, localAddressNIC, localAddressEndpoint, loop)
|
||||
r := makeRouteInner(netProto, localAddr, remoteAddr, outgoingNIC, localAddressNIC, localAddressEndpoint, loop)
|
||||
if r.Loop&PacketOut == 0 {
|
||||
// Packet will not leave the stack, no need for a gateway or a remote link
|
||||
// address.
|
||||
return r
|
||||
}
|
||||
|
||||
if r.outgoingNIC.LinkEndpoint.Capabilities()&CapabilityResolutionRequired != 0 {
|
||||
if linkRes, ok := r.outgoingNIC.stack.linkAddrResolvers[r.NetProto]; ok {
|
||||
r.linkRes = linkRes
|
||||
}
|
||||
}
|
||||
|
||||
if len(gateway) > 0 {
|
||||
r.NextHop = gateway
|
||||
return r
|
||||
}
|
||||
|
||||
if r.linkRes == nil {
|
||||
return r
|
||||
}
|
||||
|
||||
if linkAddr, ok := r.linkRes.ResolveStaticAddress(r.RemoteAddress); ok {
|
||||
r.ResolveWith(linkAddr)
|
||||
return r
|
||||
}
|
||||
|
||||
if subnet := localAddressEndpoint.Subnet(); subnet.IsBroadcast(remoteAddr) {
|
||||
r.ResolveWith(header.EthernetBroadcastAddress)
|
||||
return r
|
||||
}
|
||||
|
||||
if r.RemoteAddress == r.LocalAddress {
|
||||
// Local link address is already known.
|
||||
r.ResolveWith(r.LocalLinkAddress)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func makeRouteInner(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr tcpip.Address, outgoingNIC, localAddressNIC *NIC, localAddressEndpoint AssignableAddressEndpoint, loop PacketLooping) *Route {
|
||||
@@ -184,12 +214,6 @@ func makeRouteInner(netProto tcpip.NetworkProtocolNumber, localAddr, remoteAddr
|
||||
r.mu.localAddressEndpoint = localAddressEndpoint
|
||||
r.mu.Unlock()
|
||||
|
||||
if r.outgoingNIC.LinkEndpoint.Capabilities()&CapabilityResolutionRequired != 0 {
|
||||
if linkRes, ok := r.outgoingNIC.stack.linkAddrResolvers[r.NetProto]; ok {
|
||||
r.linkRes = linkRes
|
||||
}
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -300,14 +324,13 @@ func (r *Route) Resolve(afterResolve func()) (<-chan struct{}, *tcpip.Error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Increment the route's reference count because finishResolution retains a
|
||||
// reference to the route and releases it when called.
|
||||
r.acquireLocked()
|
||||
r.mu.Unlock()
|
||||
|
||||
nextAddr := r.NextHop
|
||||
if nextAddr == "" {
|
||||
// Local link address is already known.
|
||||
if r.RemoteAddress == r.LocalAddress {
|
||||
r.mu.remoteLinkAddress = r.LocalLinkAddress
|
||||
r.mu.Unlock()
|
||||
return nil, nil
|
||||
}
|
||||
nextAddr = r.RemoteAddress
|
||||
}
|
||||
|
||||
@@ -318,11 +341,6 @@ func (r *Route) Resolve(afterResolve func()) (<-chan struct{}, *tcpip.Error) {
|
||||
linkAddressResolutionRequestLocalAddr = r.LocalAddress
|
||||
}
|
||||
|
||||
// Increment the route's reference count because finishResolution retains a
|
||||
// reference to the route and releases it when called.
|
||||
r.acquireLocked()
|
||||
r.mu.Unlock()
|
||||
|
||||
finishResolution := func(linkAddress tcpip.LinkAddress, ok bool) {
|
||||
if ok {
|
||||
r.ResolveWith(linkAddress)
|
||||
|
||||
@@ -1329,6 +1329,7 @@ func (s *Stack) FindRoute(id tcpip.NICID, localAddr, remoteAddr tcpip.Address, n
|
||||
if addressEndpoint := s.getAddressEP(nic, localAddr, remoteAddr, netProto); addressEndpoint != nil {
|
||||
return makeRoute(
|
||||
netProto,
|
||||
"", /* gateway */
|
||||
localAddr,
|
||||
remoteAddr,
|
||||
nic, /* outboundNIC */
|
||||
@@ -1518,7 +1519,7 @@ func (s *Stack) AddLinkAddress(nicID tcpip.NICID, addr tcpip.Address, linkAddr t
|
||||
// that AddLinkAddress for a particular address has been called.
|
||||
}
|
||||
|
||||
// GetLinkAddress finds the link address corresponding to the remote address.
|
||||
// GetLinkAddress finds the link address corresponding to a neighbor's address.
|
||||
//
|
||||
// Returns a link address for the remote address, if readily available.
|
||||
//
|
||||
|
||||
@@ -3572,9 +3572,10 @@ func TestOutgoingSubnetBroadcast(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
s := stack.New(stack.Options{
|
||||
NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
|
||||
NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol, ipv6.NewProtocol},
|
||||
})
|
||||
ep := channel.New(0, defaultMTU, "")
|
||||
ep.LinkEPCapabilities |= stack.CapabilityResolutionRequired
|
||||
if err := s.CreateNIC(nicID1, ep); err != nil {
|
||||
t.Fatalf("CreateNIC(%d, _): %s", nicID1, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user