mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Perform DAD on IPv6 addresses when enabling a NIC
Addresses may be added before a NIC is enabled. Make sure DAD is performed on the permanent IPv6 addresses when they get enabled. Test: - stack_test.TestDoDADWhenNICEnabled - stack.TestDisabledRxStatsWhenNICDisabled PiperOrigin-RevId: 293697429
This commit is contained in:
committed by
gVisor bot
parent
bfa4a235f4
commit
940d255971
@@ -78,11 +78,15 @@ go_test(
|
||||
go_test(
|
||||
name = "stack_test",
|
||||
size = "small",
|
||||
srcs = ["linkaddrcache_test.go"],
|
||||
srcs = [
|
||||
"linkaddrcache_test.go",
|
||||
"nic_test.go",
|
||||
],
|
||||
library = ":stack",
|
||||
deps = [
|
||||
"//pkg/sleep",
|
||||
"//pkg/sync",
|
||||
"//pkg/tcpip",
|
||||
"//pkg/tcpip/buffer",
|
||||
],
|
||||
)
|
||||
|
||||
+37
-37
@@ -1539,7 +1539,7 @@ func TestPrefixDiscoveryMaxOnLinkPrefixes(t *testing.T) {
|
||||
}
|
||||
|
||||
// Checks to see if list contains an IPv6 address, item.
|
||||
func contains(list []tcpip.ProtocolAddress, item tcpip.AddressWithPrefix) bool {
|
||||
func containsV6Addr(list []tcpip.ProtocolAddress, item tcpip.AddressWithPrefix) bool {
|
||||
protocolAddress := tcpip.ProtocolAddress{
|
||||
Protocol: header.IPv6ProtocolNumber,
|
||||
AddressWithPrefix: item,
|
||||
@@ -1665,7 +1665,7 @@ func TestAutoGenAddr(t *testing.T) {
|
||||
// with non-zero lifetime.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix1, true, true, 100, 0))
|
||||
expectAutoGenAddrEvent(addr1, newAddr)
|
||||
if !contains(s.NICInfo()[1].ProtocolAddresses, addr1) {
|
||||
if !containsV6Addr(s.NICInfo()[1].ProtocolAddresses, addr1) {
|
||||
t.Fatalf("Should have %s in the list of addresses", addr1)
|
||||
}
|
||||
|
||||
@@ -1681,10 +1681,10 @@ func TestAutoGenAddr(t *testing.T) {
|
||||
// Receive an RA with prefix2 in a PI.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix2, true, true, 100, 0))
|
||||
expectAutoGenAddrEvent(addr2, newAddr)
|
||||
if !contains(s.NICInfo()[1].ProtocolAddresses, addr1) {
|
||||
if !containsV6Addr(s.NICInfo()[1].ProtocolAddresses, addr1) {
|
||||
t.Fatalf("Should have %s in the list of addresses", addr1)
|
||||
}
|
||||
if !contains(s.NICInfo()[1].ProtocolAddresses, addr2) {
|
||||
if !containsV6Addr(s.NICInfo()[1].ProtocolAddresses, addr2) {
|
||||
t.Fatalf("Should have %s in the list of addresses", addr2)
|
||||
}
|
||||
|
||||
@@ -1705,10 +1705,10 @@ func TestAutoGenAddr(t *testing.T) {
|
||||
case <-time.After(newMinVLDuration + defaultAsyncEventTimeout):
|
||||
t.Fatal("timed out waiting for addr auto gen event")
|
||||
}
|
||||
if contains(s.NICInfo()[1].ProtocolAddresses, addr1) {
|
||||
if containsV6Addr(s.NICInfo()[1].ProtocolAddresses, addr1) {
|
||||
t.Fatalf("Should not have %s in the list of addresses", addr1)
|
||||
}
|
||||
if !contains(s.NICInfo()[1].ProtocolAddresses, addr2) {
|
||||
if !containsV6Addr(s.NICInfo()[1].ProtocolAddresses, addr2) {
|
||||
t.Fatalf("Should have %s in the list of addresses", addr2)
|
||||
}
|
||||
}
|
||||
@@ -1853,7 +1853,7 @@ func TestAutoGenAddrDeprecateFromPI(t *testing.T) {
|
||||
// Receive PI for prefix1.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix1, true, true, 100, 100))
|
||||
expectAutoGenAddrEvent(addr1, newAddr)
|
||||
if !contains(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
if !containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
t.Fatalf("should have %s in the list of addresses", addr1)
|
||||
}
|
||||
expectPrimaryAddr(addr1)
|
||||
@@ -1861,7 +1861,7 @@ func TestAutoGenAddrDeprecateFromPI(t *testing.T) {
|
||||
// Deprecate addr for prefix1 immedaitely.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix1, true, true, 100, 0))
|
||||
expectAutoGenAddrEvent(addr1, deprecatedAddr)
|
||||
if !contains(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
if !containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
t.Fatalf("should have %s in the list of addresses", addr1)
|
||||
}
|
||||
// addr should still be the primary endpoint as there are no other addresses.
|
||||
@@ -1879,7 +1879,7 @@ func TestAutoGenAddrDeprecateFromPI(t *testing.T) {
|
||||
// Receive PI for prefix2.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix2, true, true, 100, 100))
|
||||
expectAutoGenAddrEvent(addr2, newAddr)
|
||||
if !contains(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
if !containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
t.Fatalf("should have %s in the list of addresses", addr2)
|
||||
}
|
||||
expectPrimaryAddr(addr2)
|
||||
@@ -1887,7 +1887,7 @@ func TestAutoGenAddrDeprecateFromPI(t *testing.T) {
|
||||
// Deprecate addr for prefix2 immedaitely.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix2, true, true, 100, 0))
|
||||
expectAutoGenAddrEvent(addr2, deprecatedAddr)
|
||||
if !contains(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
if !containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
t.Fatalf("should have %s in the list of addresses", addr2)
|
||||
}
|
||||
// addr1 should be the primary endpoint now since addr2 is deprecated but
|
||||
@@ -1982,7 +1982,7 @@ func TestAutoGenAddrTimerDeprecation(t *testing.T) {
|
||||
// Receive PI for prefix2.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix2, true, true, 100, 100))
|
||||
expectAutoGenAddrEvent(addr2, newAddr)
|
||||
if !contains(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
if !containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
t.Fatalf("should have %s in the list of addresses", addr2)
|
||||
}
|
||||
expectPrimaryAddr(addr2)
|
||||
@@ -1990,10 +1990,10 @@ func TestAutoGenAddrTimerDeprecation(t *testing.T) {
|
||||
// Receive a PI for prefix1.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix1, true, true, 100, 90))
|
||||
expectAutoGenAddrEvent(addr1, newAddr)
|
||||
if !contains(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
if !containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
t.Fatalf("should have %s in the list of addresses", addr1)
|
||||
}
|
||||
if !contains(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
if !containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
t.Fatalf("should have %s in the list of addresses", addr2)
|
||||
}
|
||||
expectPrimaryAddr(addr1)
|
||||
@@ -2009,10 +2009,10 @@ func TestAutoGenAddrTimerDeprecation(t *testing.T) {
|
||||
|
||||
// Wait for addr of prefix1 to be deprecated.
|
||||
expectAutoGenAddrEventAfter(addr1, deprecatedAddr, newMinVLDuration-time.Second+defaultAsyncEventTimeout)
|
||||
if !contains(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
if !containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
t.Fatalf("should not have %s in the list of addresses", addr1)
|
||||
}
|
||||
if !contains(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
if !containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
t.Fatalf("should have %s in the list of addresses", addr2)
|
||||
}
|
||||
// addr2 should be the primary endpoint now since addr1 is deprecated but
|
||||
@@ -2049,10 +2049,10 @@ func TestAutoGenAddrTimerDeprecation(t *testing.T) {
|
||||
|
||||
// Wait for addr of prefix1 to be deprecated.
|
||||
expectAutoGenAddrEventAfter(addr1, deprecatedAddr, newMinVLDuration-time.Second+defaultAsyncEventTimeout)
|
||||
if !contains(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
if !containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
t.Fatalf("should not have %s in the list of addresses", addr1)
|
||||
}
|
||||
if !contains(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
if !containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
t.Fatalf("should have %s in the list of addresses", addr2)
|
||||
}
|
||||
// addr2 should be the primary endpoint now since it is not deprecated.
|
||||
@@ -2063,10 +2063,10 @@ func TestAutoGenAddrTimerDeprecation(t *testing.T) {
|
||||
|
||||
// Wait for addr of prefix1 to be invalidated.
|
||||
expectAutoGenAddrEventAfter(addr1, invalidatedAddr, time.Second+defaultAsyncEventTimeout)
|
||||
if contains(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
if containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
t.Fatalf("should not have %s in the list of addresses", addr1)
|
||||
}
|
||||
if !contains(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
if !containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
t.Fatalf("should have %s in the list of addresses", addr2)
|
||||
}
|
||||
expectPrimaryAddr(addr2)
|
||||
@@ -2112,10 +2112,10 @@ func TestAutoGenAddrTimerDeprecation(t *testing.T) {
|
||||
case <-time.After(newMinVLDuration + defaultAsyncEventTimeout):
|
||||
t.Fatal("timed out waiting for addr auto gen event")
|
||||
}
|
||||
if contains(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
if containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
t.Fatalf("should not have %s in the list of addresses", addr1)
|
||||
}
|
||||
if contains(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
if containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
t.Fatalf("should not have %s in the list of addresses", addr2)
|
||||
}
|
||||
// Should not have any primary endpoints.
|
||||
@@ -2600,7 +2600,7 @@ func TestAutoGenAddrStaticConflict(t *testing.T) {
|
||||
if err := s.AddProtocolAddress(1, tcpip.ProtocolAddress{Protocol: header.IPv6ProtocolNumber, AddressWithPrefix: addr}); err != nil {
|
||||
t.Fatalf("AddAddress(_, %d, %s) = %s", header.IPv6ProtocolNumber, addr.Address, err)
|
||||
}
|
||||
if !contains(s.NICInfo()[1].ProtocolAddresses, addr) {
|
||||
if !containsV6Addr(s.NICInfo()[1].ProtocolAddresses, addr) {
|
||||
t.Fatalf("Should have %s in the list of addresses", addr1)
|
||||
}
|
||||
|
||||
@@ -2613,7 +2613,7 @@ func TestAutoGenAddrStaticConflict(t *testing.T) {
|
||||
t.Fatal("unexpectedly received an auto gen addr event for an address we already have statically")
|
||||
default:
|
||||
}
|
||||
if !contains(s.NICInfo()[1].ProtocolAddresses, addr) {
|
||||
if !containsV6Addr(s.NICInfo()[1].ProtocolAddresses, addr) {
|
||||
t.Fatalf("Should have %s in the list of addresses", addr1)
|
||||
}
|
||||
|
||||
@@ -2624,7 +2624,7 @@ func TestAutoGenAddrStaticConflict(t *testing.T) {
|
||||
t.Fatal("unexpectedly received an auto gen addr event")
|
||||
case <-time.After(lifetimeSeconds*time.Second + defaultTimeout):
|
||||
}
|
||||
if !contains(s.NICInfo()[1].ProtocolAddresses, addr) {
|
||||
if !containsV6Addr(s.NICInfo()[1].ProtocolAddresses, addr) {
|
||||
t.Fatalf("Should have %s in the list of addresses", addr1)
|
||||
}
|
||||
}
|
||||
@@ -2702,17 +2702,17 @@ func TestAutoGenAddrWithOpaqueIID(t *testing.T) {
|
||||
const validLifetimeSecondPrefix1 = 1
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix1, true, true, validLifetimeSecondPrefix1, 0))
|
||||
expectAutoGenAddrEvent(addr1, newAddr)
|
||||
if !contains(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
if !containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
t.Fatalf("should have %s in the list of addresses", addr1)
|
||||
}
|
||||
|
||||
// Receive an RA with prefix2 in a PI with a large valid lifetime.
|
||||
e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix2, true, true, 100, 0))
|
||||
expectAutoGenAddrEvent(addr2, newAddr)
|
||||
if !contains(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
if !containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
t.Fatalf("should have %s in the list of addresses", addr1)
|
||||
}
|
||||
if !contains(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
if !containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
t.Fatalf("should have %s in the list of addresses", addr2)
|
||||
}
|
||||
|
||||
@@ -2725,10 +2725,10 @@ func TestAutoGenAddrWithOpaqueIID(t *testing.T) {
|
||||
case <-time.After(validLifetimeSecondPrefix1*time.Second + defaultAsyncEventTimeout):
|
||||
t.Fatal("timed out waiting for addr auto gen event")
|
||||
}
|
||||
if contains(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
if containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr1) {
|
||||
t.Fatalf("should not have %s in the list of addresses", addr1)
|
||||
}
|
||||
if !contains(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
if !containsV6Addr(s.NICInfo()[nicID].ProtocolAddresses, addr2) {
|
||||
t.Fatalf("should have %s in the list of addresses", addr2)
|
||||
}
|
||||
}
|
||||
@@ -3014,16 +3014,16 @@ func TestCleanupHostOnlyStateOnBecomingRouter(t *testing.T) {
|
||||
nicinfo := s.NICInfo()
|
||||
nic1Addrs := nicinfo[nicID1].ProtocolAddresses
|
||||
nic2Addrs := nicinfo[nicID2].ProtocolAddresses
|
||||
if !contains(nic1Addrs, e1Addr1) {
|
||||
if !containsV6Addr(nic1Addrs, e1Addr1) {
|
||||
t.Errorf("missing %s from the list of addresses for NIC(%d): %+v", e1Addr1, nicID1, nic1Addrs)
|
||||
}
|
||||
if !contains(nic1Addrs, e1Addr2) {
|
||||
if !containsV6Addr(nic1Addrs, e1Addr2) {
|
||||
t.Errorf("missing %s from the list of addresses for NIC(%d): %+v", e1Addr2, nicID1, nic1Addrs)
|
||||
}
|
||||
if !contains(nic2Addrs, e2Addr1) {
|
||||
if !containsV6Addr(nic2Addrs, e2Addr1) {
|
||||
t.Errorf("missing %s from the list of addresses for NIC(%d): %+v", e2Addr1, nicID2, nic2Addrs)
|
||||
}
|
||||
if !contains(nic2Addrs, e2Addr2) {
|
||||
if !containsV6Addr(nic2Addrs, e2Addr2) {
|
||||
t.Errorf("missing %s from the list of addresses for NIC(%d): %+v", e2Addr2, nicID2, nic2Addrs)
|
||||
}
|
||||
|
||||
@@ -3102,16 +3102,16 @@ func TestCleanupHostOnlyStateOnBecomingRouter(t *testing.T) {
|
||||
nicinfo = s.NICInfo()
|
||||
nic1Addrs = nicinfo[nicID1].ProtocolAddresses
|
||||
nic2Addrs = nicinfo[nicID2].ProtocolAddresses
|
||||
if contains(nic1Addrs, e1Addr1) {
|
||||
if containsV6Addr(nic1Addrs, e1Addr1) {
|
||||
t.Errorf("still have %s in the list of addresses for NIC(%d): %+v", e1Addr1, nicID1, nic1Addrs)
|
||||
}
|
||||
if contains(nic1Addrs, e1Addr2) {
|
||||
if containsV6Addr(nic1Addrs, e1Addr2) {
|
||||
t.Errorf("still have %s in the list of addresses for NIC(%d): %+v", e1Addr2, nicID1, nic1Addrs)
|
||||
}
|
||||
if contains(nic2Addrs, e2Addr1) {
|
||||
if containsV6Addr(nic2Addrs, e2Addr1) {
|
||||
t.Errorf("still have %s in the list of addresses for NIC(%d): %+v", e2Addr1, nicID2, nic2Addrs)
|
||||
}
|
||||
if contains(nic2Addrs, e2Addr2) {
|
||||
if containsV6Addr(nic2Addrs, e2Addr2) {
|
||||
t.Errorf("still have %s in the list of addresses for NIC(%d): %+v", e2Addr2, nicID2, nic2Addrs)
|
||||
}
|
||||
|
||||
|
||||
+63
-21
@@ -16,6 +16,7 @@ package stack
|
||||
|
||||
import (
|
||||
"log"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
@@ -39,6 +40,7 @@ type NIC struct {
|
||||
|
||||
mu struct {
|
||||
sync.RWMutex
|
||||
enabled bool
|
||||
spoofing bool
|
||||
promiscuous bool
|
||||
primary map[tcpip.NetworkProtocolNumber][]*referencedNetworkEndpoint
|
||||
@@ -56,6 +58,14 @@ type NIC struct {
|
||||
type NICStats struct {
|
||||
Tx DirectionStats
|
||||
Rx DirectionStats
|
||||
|
||||
DisabledRx DirectionStats
|
||||
}
|
||||
|
||||
func makeNICStats() NICStats {
|
||||
var s NICStats
|
||||
tcpip.InitStatCounters(reflect.ValueOf(&s).Elem())
|
||||
return s
|
||||
}
|
||||
|
||||
// DirectionStats includes packet and byte counts.
|
||||
@@ -99,16 +109,7 @@ func newNIC(stack *Stack, id tcpip.NICID, name string, ep LinkEndpoint, ctx NICC
|
||||
name: name,
|
||||
linkEP: ep,
|
||||
context: ctx,
|
||||
stats: NICStats{
|
||||
Tx: DirectionStats{
|
||||
Packets: &tcpip.StatCounter{},
|
||||
Bytes: &tcpip.StatCounter{},
|
||||
},
|
||||
Rx: DirectionStats{
|
||||
Packets: &tcpip.StatCounter{},
|
||||
Bytes: &tcpip.StatCounter{},
|
||||
},
|
||||
},
|
||||
stats: makeNICStats(),
|
||||
}
|
||||
nic.mu.primary = make(map[tcpip.NetworkProtocolNumber][]*referencedNetworkEndpoint)
|
||||
nic.mu.endpoints = make(map[NetworkEndpointID]*referencedNetworkEndpoint)
|
||||
@@ -137,14 +138,30 @@ func newNIC(stack *Stack, id tcpip.NICID, name string, ep LinkEndpoint, ctx NICC
|
||||
// enable enables the NIC. enable will attach the link to its LinkEndpoint and
|
||||
// join the IPv6 All-Nodes Multicast address (ff02::1).
|
||||
func (n *NIC) enable() *tcpip.Error {
|
||||
n.mu.RLock()
|
||||
enabled := n.mu.enabled
|
||||
n.mu.RUnlock()
|
||||
if enabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
|
||||
if n.mu.enabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
n.mu.enabled = true
|
||||
|
||||
n.attachLinkEndpoint()
|
||||
|
||||
// Create an endpoint to receive broadcast packets on this interface.
|
||||
if _, ok := n.stack.networkProtocols[header.IPv4ProtocolNumber]; ok {
|
||||
if err := n.AddAddress(tcpip.ProtocolAddress{
|
||||
if _, err := n.addAddressLocked(tcpip.ProtocolAddress{
|
||||
Protocol: header.IPv4ProtocolNumber,
|
||||
AddressWithPrefix: tcpip.AddressWithPrefix{header.IPv4Broadcast, 8 * header.IPv4AddressSize},
|
||||
}, NeverPrimaryEndpoint); err != nil {
|
||||
}, NeverPrimaryEndpoint, permanent, static, false /* deprecated */); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -166,8 +183,22 @@ func (n *NIC) enable() *tcpip.Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
// Perform DAD on the all the unicast IPv6 endpoints that are in the permanent
|
||||
// state.
|
||||
//
|
||||
// Addresses may have aleady completed DAD but in the time since the NIC was
|
||||
// last enabled, other devices may have acquired the same addresses.
|
||||
for _, r := range n.mu.endpoints {
|
||||
addr := r.ep.ID().LocalAddress
|
||||
if k := r.getKind(); (k != permanent && k != permanentTentative) || !header.IsV6UnicastAddress(addr) {
|
||||
continue
|
||||
}
|
||||
|
||||
r.setKind(permanentTentative)
|
||||
if err := n.mu.ndp.startDuplicateAddressDetection(addr, r); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := n.joinGroupLocked(header.IPv6ProtocolNumber, header.IPv6AllNodesMulticastAddress); err != nil {
|
||||
return err
|
||||
@@ -633,7 +664,9 @@ func (n *NIC) addAddressLocked(protocolAddress tcpip.ProtocolAddress, peb Primar
|
||||
isIPv6Unicast := protocolAddress.Protocol == header.IPv6ProtocolNumber && header.IsV6UnicastAddress(protocolAddress.AddressWithPrefix.Address)
|
||||
|
||||
// If the address is an IPv6 address and it is a permanent address,
|
||||
// mark it as tentative so it goes through the DAD process.
|
||||
// mark it as tentative so it goes through the DAD process if the NIC is
|
||||
// enabled. If the NIC is not enabled, DAD will be started when the NIC is
|
||||
// enabled.
|
||||
if isIPv6Unicast && kind == permanent {
|
||||
kind = permanentTentative
|
||||
}
|
||||
@@ -668,8 +701,8 @@ func (n *NIC) addAddressLocked(protocolAddress tcpip.ProtocolAddress, peb Primar
|
||||
|
||||
n.insertPrimaryEndpointLocked(ref, peb)
|
||||
|
||||
// If we are adding a tentative IPv6 address, start DAD.
|
||||
if isIPv6Unicast && kind == permanentTentative {
|
||||
// If we are adding a tentative IPv6 address, start DAD if the NIC is enabled.
|
||||
if isIPv6Unicast && kind == permanentTentative && n.mu.enabled {
|
||||
if err := n.mu.ndp.startDuplicateAddressDetection(protocolAddress.AddressWithPrefix.Address, ref); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -700,9 +733,7 @@ func (n *NIC) AllAddresses() []tcpip.ProtocolAddress {
|
||||
// Don't include tentative, expired or temporary endpoints to
|
||||
// avoid confusion and prevent the caller from using those.
|
||||
switch ref.getKind() {
|
||||
case permanentTentative, permanentExpired, temporary:
|
||||
// TODO(b/140898488): Should tentative addresses be
|
||||
// returned?
|
||||
case permanentExpired, temporary:
|
||||
continue
|
||||
}
|
||||
addrs = append(addrs, tcpip.ProtocolAddress{
|
||||
@@ -1016,11 +1047,23 @@ func handlePacket(protocol tcpip.NetworkProtocolNumber, dst, src tcpip.Address,
|
||||
// This rule applies only to the slice itself, not to the items of the slice;
|
||||
// the ownership of the items is not retained by the caller.
|
||||
func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remote, local tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, pkt tcpip.PacketBuffer) {
|
||||
n.mu.RLock()
|
||||
enabled := n.mu.enabled
|
||||
// If the NIC is not yet enabled, don't receive any packets.
|
||||
if !enabled {
|
||||
n.mu.RUnlock()
|
||||
|
||||
n.stats.DisabledRx.Packets.Increment()
|
||||
n.stats.DisabledRx.Bytes.IncrementBy(uint64(pkt.Data.Size()))
|
||||
return
|
||||
}
|
||||
|
||||
n.stats.Rx.Packets.Increment()
|
||||
n.stats.Rx.Bytes.IncrementBy(uint64(pkt.Data.Size()))
|
||||
|
||||
netProto, ok := n.stack.networkProtocols[protocol]
|
||||
if !ok {
|
||||
n.mu.RUnlock()
|
||||
n.stack.stats.UnknownProtocolRcvdPackets.Increment()
|
||||
return
|
||||
}
|
||||
@@ -1032,7 +1075,6 @@ func (n *NIC) DeliverNetworkPacket(linkEP LinkEndpoint, remote, local tcpip.Link
|
||||
}
|
||||
|
||||
// Are any packet sockets listening for this network protocol?
|
||||
n.mu.RLock()
|
||||
packetEPs := n.mu.packetEPs[protocol]
|
||||
// Check whether there are packet sockets listening for every protocol.
|
||||
// If we received a packet with protocol EthernetProtocolAll, then the
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright 2020 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package stack
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||
)
|
||||
|
||||
func TestDisabledRxStatsWhenNICDisabled(t *testing.T) {
|
||||
// When the NIC is disabled, the only field that matters is the stats field.
|
||||
// This test is limited to stats counter checks.
|
||||
nic := NIC{
|
||||
stats: makeNICStats(),
|
||||
}
|
||||
|
||||
if got := nic.stats.DisabledRx.Packets.Value(); got != 0 {
|
||||
t.Errorf("got DisabledRx.Packets = %d, want = 0", got)
|
||||
}
|
||||
if got := nic.stats.DisabledRx.Bytes.Value(); got != 0 {
|
||||
t.Errorf("got DisabledRx.Bytes = %d, want = 0", got)
|
||||
}
|
||||
if got := nic.stats.Rx.Packets.Value(); got != 0 {
|
||||
t.Errorf("got Rx.Packets = %d, want = 0", got)
|
||||
}
|
||||
if got := nic.stats.Rx.Bytes.Value(); got != 0 {
|
||||
t.Errorf("got Rx.Bytes = %d, want = 0", got)
|
||||
}
|
||||
|
||||
if t.Failed() {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
nic.DeliverNetworkPacket(nil, "", "", 0, tcpip.PacketBuffer{Data: buffer.View([]byte{1, 2, 3, 4}).ToVectorisedView()})
|
||||
|
||||
if got := nic.stats.DisabledRx.Packets.Value(); got != 1 {
|
||||
t.Errorf("got DisabledRx.Packets = %d, want = 1", got)
|
||||
}
|
||||
if got := nic.stats.DisabledRx.Bytes.Value(); got != 4 {
|
||||
t.Errorf("got DisabledRx.Bytes = %d, want = 4", got)
|
||||
}
|
||||
if got := nic.stats.Rx.Packets.Value(); got != 0 {
|
||||
t.Errorf("got Rx.Packets = %d, want = 0", got)
|
||||
}
|
||||
if got := nic.stats.Rx.Bytes.Value(); got != 0 {
|
||||
t.Errorf("got Rx.Bytes = %d, want = 0", got)
|
||||
}
|
||||
}
|
||||
@@ -2561,3 +2561,118 @@ func TestIPv6SourceAddressSelectionScopeAndSameAddress(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestDoDADWhenNICEnabled tests that IPv6 endpoints that were added while a NIC
|
||||
// was disabled have DAD performed on them when the NIC is enabled.
|
||||
func TestDoDADWhenNICEnabled(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const dadTransmits = 1
|
||||
const retransmitTimer = time.Second
|
||||
const nicID = 1
|
||||
|
||||
ndpDisp := ndpDispatcher{
|
||||
dadC: make(chan ndpDADEvent),
|
||||
}
|
||||
opts := stack.Options{
|
||||
NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
|
||||
NDPConfigs: stack.NDPConfigurations{
|
||||
DupAddrDetectTransmits: dadTransmits,
|
||||
RetransmitTimer: retransmitTimer,
|
||||
},
|
||||
NDPDisp: &ndpDisp,
|
||||
}
|
||||
|
||||
e := channel.New(dadTransmits, 1280, linkAddr1)
|
||||
s := stack.New(opts)
|
||||
nicOpts := stack.NICOptions{Disabled: true}
|
||||
if err := s.CreateNICWithOptions(nicID, e, nicOpts); err != nil {
|
||||
t.Fatalf("CreateNIC(%d, _, %+v) = %s", nicID, nicOpts, err)
|
||||
}
|
||||
|
||||
addr := tcpip.ProtocolAddress{
|
||||
Protocol: header.IPv6ProtocolNumber,
|
||||
AddressWithPrefix: tcpip.AddressWithPrefix{
|
||||
Address: llAddr1,
|
||||
PrefixLen: 128,
|
||||
},
|
||||
}
|
||||
if err := s.AddProtocolAddress(nicID, addr); err != nil {
|
||||
t.Fatalf("AddProtocolAddress(%d, %+v): %s", nicID, addr, err)
|
||||
}
|
||||
|
||||
// Address should be in the list of all addresses.
|
||||
if addrs := s.AllAddresses()[nicID]; !containsV6Addr(addrs, addr.AddressWithPrefix) {
|
||||
t.Fatalf("got s.AllAddresses()[%d] = %+v, want = %+v", nicID, addrs, addr)
|
||||
}
|
||||
|
||||
// Address should be tentative so it should not be a main address.
|
||||
got, err := s.GetMainNICAddress(nicID, header.IPv6ProtocolNumber)
|
||||
if err != nil {
|
||||
t.Fatalf("got stack.GetMainNICAddress(%d, %d) = (_, %v), want = (_, nil)", nicID, header.IPv6ProtocolNumber, err)
|
||||
}
|
||||
if want := (tcpip.AddressWithPrefix{}); got != want {
|
||||
t.Fatalf("got stack.GetMainNICAddress(%d, %d) = (%s, nil), want = (%s, nil)", nicID, header.IPv6ProtocolNumber, got, want)
|
||||
}
|
||||
|
||||
// Enabling the NIC should start DAD for the address.
|
||||
if err := s.EnableNIC(nicID); err != nil {
|
||||
t.Fatalf("s.EnableNIC(%d): %s", nicID, err)
|
||||
}
|
||||
if addrs := s.AllAddresses()[nicID]; !containsV6Addr(addrs, addr.AddressWithPrefix) {
|
||||
t.Fatalf("got s.AllAddresses()[%d] = %+v, want = %+v", nicID, addrs, addr)
|
||||
}
|
||||
|
||||
// Address should not be considered bound to the NIC yet (DAD ongoing).
|
||||
got, err = s.GetMainNICAddress(nicID, header.IPv6ProtocolNumber)
|
||||
if err != nil {
|
||||
t.Fatalf("got stack.GetMainNICAddress(%d, %d) = (_, %v), want = (_, nil)", nicID, header.IPv6ProtocolNumber, err)
|
||||
}
|
||||
if want := (tcpip.AddressWithPrefix{}); got != want {
|
||||
t.Fatalf("got stack.GetMainNICAddress(%d, %d) = (%s, nil), want = (%s, nil)", nicID, header.IPv6ProtocolNumber, got, want)
|
||||
}
|
||||
|
||||
// Wait for DAD to resolve.
|
||||
select {
|
||||
case <-time.After(dadTransmits*retransmitTimer + defaultAsyncEventTimeout):
|
||||
t.Fatal("timed out waiting for DAD resolution")
|
||||
case e := <-ndpDisp.dadC:
|
||||
if e.err != nil {
|
||||
t.Fatal("got DAD error: ", e.err)
|
||||
}
|
||||
if e.nicID != nicID {
|
||||
t.Fatalf("got DAD event w/ nicID = %d, want = %d", e.nicID, nicID)
|
||||
}
|
||||
if e.addr != addr.AddressWithPrefix.Address {
|
||||
t.Fatalf("got DAD event w/ addr = %s, want = %s", e.addr, addr.AddressWithPrefix.Address)
|
||||
}
|
||||
if !e.resolved {
|
||||
t.Fatal("got DAD event w/ resolved = false, want = true")
|
||||
}
|
||||
}
|
||||
if addrs := s.AllAddresses()[nicID]; !containsV6Addr(addrs, addr.AddressWithPrefix) {
|
||||
t.Fatalf("got s.AllAddresses()[%d] = %+v, want = %+v", nicID, addrs, addr)
|
||||
}
|
||||
got, err = s.GetMainNICAddress(nicID, header.IPv6ProtocolNumber)
|
||||
if err != nil {
|
||||
t.Fatalf("got stack.GetMainNICAddress(%d, %d) = (_, %v), want = (_, nil)", nicID, header.IPv6ProtocolNumber, err)
|
||||
}
|
||||
if got != addr.AddressWithPrefix {
|
||||
t.Fatalf("got stack.GetMainNICAddress(%d, %d) = %s, want = %s", nicID, header.IPv6ProtocolNumber, got, addr.AddressWithPrefix)
|
||||
}
|
||||
|
||||
// Enabling the NIC again should be a no-op.
|
||||
if err := s.EnableNIC(nicID); err != nil {
|
||||
t.Fatalf("s.EnableNIC(%d): %s", nicID, err)
|
||||
}
|
||||
if addrs := s.AllAddresses()[nicID]; !containsV6Addr(addrs, addr.AddressWithPrefix) {
|
||||
t.Fatalf("got s.AllAddresses()[%d] = %+v, want = %+v", nicID, addrs, addr)
|
||||
}
|
||||
got, err = s.GetMainNICAddress(nicID, header.IPv6ProtocolNumber)
|
||||
if err != nil {
|
||||
t.Fatalf("got stack.GetMainNICAddress(%d, %d) = (_, %v), want = (_, nil)", nicID, header.IPv6ProtocolNumber, err)
|
||||
}
|
||||
if got != addr.AddressWithPrefix {
|
||||
t.Fatalf("got stack.GetMainNICAddress(%d, %d) = (%s, nil), want = (%s, nil)", nicID, header.IPv6ProtocolNumber, got, addr.AddressWithPrefix)
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -1170,7 +1170,9 @@ type TransportEndpointStats struct {
|
||||
// marker interface.
|
||||
func (*TransportEndpointStats) IsEndpointStats() {}
|
||||
|
||||
func fillIn(v reflect.Value) {
|
||||
// InitStatCounters initializes v's fields with nil StatCounter fields to new
|
||||
// StatCounters.
|
||||
func InitStatCounters(v reflect.Value) {
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
v := v.Field(i)
|
||||
if s, ok := v.Addr().Interface().(**StatCounter); ok {
|
||||
@@ -1178,14 +1180,14 @@ func fillIn(v reflect.Value) {
|
||||
*s = new(StatCounter)
|
||||
}
|
||||
} else {
|
||||
fillIn(v)
|
||||
InitStatCounters(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FillIn returns a copy of s with nil fields initialized to new StatCounters.
|
||||
func (s Stats) FillIn() Stats {
|
||||
fillIn(reflect.ValueOf(&s).Elem())
|
||||
InitStatCounters(reflect.ValueOf(&s).Elem())
|
||||
return s
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user