summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--pkg/sentry/kernel/kernel.go19
-rw-r--r--pkg/tcpip/faketime/faketime.go21
-rw-r--r--pkg/tcpip/faketime/faketime_test.go4
-rw-r--r--pkg/tcpip/header/ipv4.go10
-rw-r--r--pkg/tcpip/network/arp/arp_test.go2
-rw-r--r--pkg/tcpip/network/internal/fragmentation/fragmentation.go2
-rw-r--r--pkg/tcpip/network/internal/fragmentation/reassembler.go22
-rw-r--r--pkg/tcpip/network/internal/ip/generic_multicast_protocol.go2
-rw-r--r--pkg/tcpip/stack/neighbor_cache_test.go266
-rw-r--r--pkg/tcpip/stack/neighbor_entry.go22
-rw-r--r--pkg/tcpip/stack/neighbor_entry_test.go220
-rw-r--r--pkg/tcpip/stack/nud_test.go2
-rw-r--r--pkg/tcpip/stack/stack_test.go2
-rw-r--r--pkg/tcpip/stdclock.go16
-rw-r--r--pkg/tcpip/tcpip.go35
-rw-r--r--pkg/tcpip/tests/integration/link_resolution_test.go2
-rw-r--r--pkg/tcpip/timer_test.go62
-rw-r--r--pkg/tcpip/transport/icmp/endpoint.go7
-rw-r--r--pkg/tcpip/transport/icmp/endpoint_state.go12
-rw-r--r--pkg/tcpip/transport/packet/endpoint.go10
-rw-r--r--pkg/tcpip/transport/packet/endpoint_state.go12
-rw-r--r--pkg/tcpip/transport/raw/endpoint.go10
-rw-r--r--pkg/tcpip/transport/raw/endpoint_state.go12
-rw-r--r--pkg/tcpip/transport/udp/endpoint.go7
-rw-r--r--pkg/tcpip/transport/udp/endpoint_state.go26
25 files changed, 474 insertions, 331 deletions
diff --git a/pkg/sentry/kernel/kernel.go b/pkg/sentry/kernel/kernel.go
index e6e9da898..c5bcf295f 100644
--- a/pkg/sentry/kernel/kernel.go
+++ b/pkg/sentry/kernel/kernel.go
@@ -1553,22 +1553,23 @@ func (k *Kernel) SetSaveError(err error) {
var _ tcpip.Clock = (*Kernel)(nil)
-// NowNanoseconds implements tcpip.Clock.NowNanoseconds.
-func (k *Kernel) NowNanoseconds() int64 {
- now, err := k.timekeeper.GetTime(sentrytime.Realtime)
+// Now implements tcpip.Clock.NowNanoseconds.
+func (k *Kernel) Now() time.Time {
+ nsec, err := k.timekeeper.GetTime(sentrytime.Realtime)
if err != nil {
- panic("Kernel.NowNanoseconds: " + err.Error())
+ panic("timekeeper.GetTime(sentrytime.Realtime): " + err.Error())
}
- return now
+ return time.Unix(0, nsec)
}
// NowMonotonic implements tcpip.Clock.NowMonotonic.
-func (k *Kernel) NowMonotonic() int64 {
- now, err := k.timekeeper.GetTime(sentrytime.Monotonic)
+func (k *Kernel) NowMonotonic() tcpip.MonotonicTime {
+ nsec, err := k.timekeeper.GetTime(sentrytime.Monotonic)
if err != nil {
- panic("Kernel.NowMonotonic: " + err.Error())
+ panic("timekeeper.GetTime(sentrytime.Monotonic): " + err.Error())
}
- return now
+ var mt tcpip.MonotonicTime
+ return mt.Add(time.Duration(nsec) * time.Nanosecond)
}
// AfterFunc implements tcpip.Clock.AfterFunc.
diff --git a/pkg/tcpip/faketime/faketime.go b/pkg/tcpip/faketime/faketime.go
index c4dbe8440..9f8f51647 100644
--- a/pkg/tcpip/faketime/faketime.go
+++ b/pkg/tcpip/faketime/faketime.go
@@ -29,14 +29,14 @@ type NullClock struct{}
var _ tcpip.Clock = (*NullClock)(nil)
-// NowNanoseconds implements tcpip.Clock.NowNanoseconds.
-func (*NullClock) NowNanoseconds() int64 {
- return 0
+// Now implements tcpip.Clock.Now.
+func (*NullClock) Now() time.Time {
+ return time.Time{}
}
// NowMonotonic implements tcpip.Clock.NowMonotonic.
-func (*NullClock) NowMonotonic() int64 {
- return 0
+func (*NullClock) NowMonotonic() tcpip.MonotonicTime {
+ return tcpip.MonotonicTime{}
}
// AfterFunc implements tcpip.Clock.AfterFunc.
@@ -118,16 +118,17 @@ func NewManualClock() *ManualClock {
var _ tcpip.Clock = (*ManualClock)(nil)
-// NowNanoseconds implements tcpip.Clock.NowNanoseconds.
-func (mc *ManualClock) NowNanoseconds() int64 {
+// Now implements tcpip.Clock.Now.
+func (mc *ManualClock) Now() time.Time {
mc.mu.RLock()
defer mc.mu.RUnlock()
- return mc.mu.now.UnixNano()
+ return mc.mu.now
}
// NowMonotonic implements tcpip.Clock.NowMonotonic.
-func (mc *ManualClock) NowMonotonic() int64 {
- return mc.NowNanoseconds()
+func (mc *ManualClock) NowMonotonic() tcpip.MonotonicTime {
+ var mt tcpip.MonotonicTime
+ return mt.Add(mc.Now().Sub(time.Unix(0, 0)))
}
// AfterFunc implements tcpip.Clock.AfterFunc.
diff --git a/pkg/tcpip/faketime/faketime_test.go b/pkg/tcpip/faketime/faketime_test.go
index c2704df2c..fd2bb470a 100644
--- a/pkg/tcpip/faketime/faketime_test.go
+++ b/pkg/tcpip/faketime/faketime_test.go
@@ -26,7 +26,7 @@ func TestManualClockAdvance(t *testing.T) {
clock := faketime.NewManualClock()
start := clock.NowMonotonic()
clock.Advance(timeout)
- if got, want := time.Duration(clock.NowMonotonic()-start)*time.Nanosecond, timeout; got != want {
+ if got, want := clock.NowMonotonic().Sub(start), timeout; got != want {
t.Errorf("got = %d, want = %d", got, want)
}
}
@@ -87,7 +87,7 @@ func TestManualClockAfterFunc(t *testing.T) {
if got, want := counter2, test.wantCounter2; got != want {
t.Errorf("got counter2 = %d, want = %d", got, want)
}
- if got, want := time.Duration(clock.NowMonotonic()-start)*time.Nanosecond, test.advance; got != want {
+ if got, want := clock.NowMonotonic().Sub(start), test.advance; got != want {
t.Errorf("got elapsed = %d, want = %d", got, want)
}
})
diff --git a/pkg/tcpip/header/ipv4.go b/pkg/tcpip/header/ipv4.go
index 2be21ec75..6a8db84d6 100644
--- a/pkg/tcpip/header/ipv4.go
+++ b/pkg/tcpip/header/ipv4.go
@@ -17,6 +17,7 @@ package header
import (
"encoding/binary"
"fmt"
+ "time"
"gvisor.dev/gvisor/pkg/tcpip"
)
@@ -813,9 +814,12 @@ const (
// ipv4TimestampTime provides the current time as specified in RFC 791.
func ipv4TimestampTime(clock tcpip.Clock) uint32 {
- const millisecondsPerDay = 24 * 3600 * 1000
- const nanoPerMilli = 1000000
- return uint32((clock.NowNanoseconds() / nanoPerMilli) % millisecondsPerDay)
+ // Per RFC 791 page 21:
+ // The Timestamp is a right-justified, 32-bit timestamp in
+ // milliseconds since midnight UT.
+ now := clock.Now().UTC()
+ midnight := now.Truncate(24 * time.Hour)
+ return uint32(now.Sub(midnight).Milliseconds())
}
// IP Timestamp option fields.
diff --git a/pkg/tcpip/network/arp/arp_test.go b/pkg/tcpip/network/arp/arp_test.go
index f89b55561..3ca78490f 100644
--- a/pkg/tcpip/network/arp/arp_test.go
+++ b/pkg/tcpip/network/arp/arp_test.go
@@ -126,7 +126,7 @@ func (d *arpDispatcher) OnNeighborRemoved(nicID tcpip.NICID, entry stack.Neighbo
func (d *arpDispatcher) waitForEvent(ctx context.Context, want eventInfo) error {
select {
case got := <-d.C:
- if diff := cmp.Diff(want, got, cmp.AllowUnexported(got), cmpopts.IgnoreFields(stack.NeighborEntry{}, "UpdatedAtNanos")); diff != "" {
+ if diff := cmp.Diff(want, got, cmp.AllowUnexported(got), cmpopts.IgnoreFields(stack.NeighborEntry{}, "UpdatedAt")); diff != "" {
return fmt.Errorf("got invalid event (-want +got):\n%s", diff)
}
case <-ctx.Done():
diff --git a/pkg/tcpip/network/internal/fragmentation/fragmentation.go b/pkg/tcpip/network/internal/fragmentation/fragmentation.go
index 5168f5361..1ba4d0d36 100644
--- a/pkg/tcpip/network/internal/fragmentation/fragmentation.go
+++ b/pkg/tcpip/network/internal/fragmentation/fragmentation.go
@@ -251,7 +251,7 @@ func (f *Fragmentation) releaseReassemblersLocked() {
// The list is empty.
break
}
- elapsed := time.Duration(now-r.creationTime) * time.Nanosecond
+ elapsed := now.Sub(r.createdAt)
if f.timeout > elapsed {
// If the oldest reassembler has not expired, schedule the release
// job so that this function is called back when it has expired.
diff --git a/pkg/tcpip/network/internal/fragmentation/reassembler.go b/pkg/tcpip/network/internal/fragmentation/reassembler.go
index 56b76a284..5b7e4b361 100644
--- a/pkg/tcpip/network/internal/fragmentation/reassembler.go
+++ b/pkg/tcpip/network/internal/fragmentation/reassembler.go
@@ -35,21 +35,21 @@ type hole struct {
type reassembler struct {
reassemblerEntry
- id FragmentID
- memSize int
- proto uint8
- mu sync.Mutex
- holes []hole
- filled int
- done bool
- creationTime int64
- pkt *stack.PacketBuffer
+ id FragmentID
+ memSize int
+ proto uint8
+ mu sync.Mutex
+ holes []hole
+ filled int
+ done bool
+ createdAt tcpip.MonotonicTime
+ pkt *stack.PacketBuffer
}
func newReassembler(id FragmentID, clock tcpip.Clock) *reassembler {
r := &reassembler{
- id: id,
- creationTime: clock.NowMonotonic(),
+ id: id,
+ createdAt: clock.NowMonotonic(),
}
r.holes = append(r.holes, hole{
first: 0,
diff --git a/pkg/tcpip/network/internal/ip/generic_multicast_protocol.go b/pkg/tcpip/network/internal/ip/generic_multicast_protocol.go
index d22974b12..671dfbf32 100644
--- a/pkg/tcpip/network/internal/ip/generic_multicast_protocol.go
+++ b/pkg/tcpip/network/internal/ip/generic_multicast_protocol.go
@@ -611,7 +611,7 @@ func (g *GenericMulticastProtocolState) setDelayTimerForAddressRLocked(groupAddr
// If a timer for any address is already running, it is reset to the new
// random value only if the requested Maximum Response Delay is less than
// the remaining value of the running timer.
- now := time.Unix(0 /* seconds */, g.opts.Clock.NowNanoseconds())
+ now := g.opts.Clock.Now()
if info.state == delayingMember {
if info.delayedReportJobFiresAt.IsZero() {
panic(fmt.Sprintf("delayed report unscheduled while in the delaying member state; group = %s", groupAddress))
diff --git a/pkg/tcpip/stack/neighbor_cache_test.go b/pkg/tcpip/stack/neighbor_cache_test.go
index 90881169d..7de25fe37 100644
--- a/pkg/tcpip/stack/neighbor_cache_test.go
+++ b/pkg/tcpip/stack/neighbor_cache_test.go
@@ -293,10 +293,10 @@ func addReachableEntryWithRemoved(nudDisp *testNUDDispatcher, clock *faketime.Ma
EventType: entryTestRemoved,
NICID: 1,
Entry: NeighborEntry{
- Addr: removedEntry.Addr,
- LinkAddr: removedEntry.LinkAddr,
- State: Reachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: removedEntry.Addr,
+ LinkAddr: removedEntry.LinkAddr,
+ State: Reachable,
+ UpdatedAt: clock.Now(),
},
})
}
@@ -305,10 +305,10 @@ func addReachableEntryWithRemoved(nudDisp *testNUDDispatcher, clock *faketime.Ma
EventType: entryTestAdded,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: "",
- State: Incomplete,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: "",
+ State: Incomplete,
+ UpdatedAt: clock.Now(),
},
})
@@ -339,10 +339,10 @@ func addReachableEntryWithRemoved(nudDisp *testNUDDispatcher, clock *faketime.Ma
EventType: entryTestChanged,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: entry.LinkAddr,
- State: Reachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: entry.LinkAddr,
+ State: Reachable,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -411,10 +411,10 @@ func TestNeighborCacheRemoveEntry(t *testing.T) {
EventType: entryTestRemoved,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: entry.LinkAddr,
- State: Reachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: entry.LinkAddr,
+ State: Reachable,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -492,12 +492,12 @@ func (c *testContext) overflowCache(opts overflowOptions) error {
if !ok {
return fmt.Errorf("got c.linkRes.entries.entry(%d) = _, false, want = true", i)
}
- durationReachableNanos := int64(c.linkRes.entries.size()-i-1) * typicalLatency.Nanoseconds()
+ durationReachableNanos := time.Duration(c.linkRes.entries.size()-i-1) * typicalLatency
wantEntry := NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: entry.LinkAddr,
- State: Reachable,
- UpdatedAtNanos: c.clock.NowNanoseconds() - durationReachableNanos,
+ Addr: entry.Addr,
+ LinkAddr: entry.LinkAddr,
+ State: Reachable,
+ UpdatedAt: c.clock.Now().Add(-durationReachableNanos),
}
wantUnorderedEntries = append(wantUnorderedEntries, wantEntry)
}
@@ -563,10 +563,10 @@ func TestNeighborCacheRemoveEntryThenOverflow(t *testing.T) {
EventType: entryTestRemoved,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: entry.LinkAddr,
- State: Reachable,
- UpdatedAtNanos: c.clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: entry.LinkAddr,
+ State: Reachable,
+ UpdatedAt: c.clock.Now(),
},
},
}
@@ -608,10 +608,10 @@ func TestNeighborCacheDuplicateStaticEntryWithSameLinkAddress(t *testing.T) {
EventType: entryTestAdded,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: staticLinkAddr,
- State: Static,
- UpdatedAtNanos: c.clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: staticLinkAddr,
+ State: Static,
+ UpdatedAt: c.clock.Now(),
},
},
}
@@ -655,10 +655,10 @@ func TestNeighborCacheDuplicateStaticEntryWithDifferentLinkAddress(t *testing.T)
EventType: entryTestAdded,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: staticLinkAddr,
- State: Static,
- UpdatedAtNanos: c.clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: staticLinkAddr,
+ State: Static,
+ UpdatedAt: c.clock.Now(),
},
},
}
@@ -681,10 +681,10 @@ func TestNeighborCacheDuplicateStaticEntryWithDifferentLinkAddress(t *testing.T)
EventType: entryTestChanged,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: staticLinkAddr,
- State: Static,
- UpdatedAtNanos: c.clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: staticLinkAddr,
+ State: Static,
+ UpdatedAt: c.clock.Now(),
},
},
}
@@ -725,10 +725,10 @@ func TestNeighborCacheRemoveStaticEntryThenOverflow(t *testing.T) {
EventType: entryTestAdded,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: staticLinkAddr,
- State: Static,
- UpdatedAtNanos: c.clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: staticLinkAddr,
+ State: Static,
+ UpdatedAt: c.clock.Now(),
},
},
}
@@ -750,10 +750,10 @@ func TestNeighborCacheRemoveStaticEntryThenOverflow(t *testing.T) {
EventType: entryTestRemoved,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: staticLinkAddr,
- State: Static,
- UpdatedAtNanos: c.clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: staticLinkAddr,
+ State: Static,
+ UpdatedAt: c.clock.Now(),
},
},
}
@@ -806,20 +806,20 @@ func TestNeighborCacheOverwriteWithStaticEntryThenOverflow(t *testing.T) {
EventType: entryTestRemoved,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: entry.LinkAddr,
- State: Reachable,
- UpdatedAtNanos: c.clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: entry.LinkAddr,
+ State: Reachable,
+ UpdatedAt: c.clock.Now(),
},
},
{
EventType: entryTestAdded,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: staticLinkAddr,
- State: Static,
- UpdatedAtNanos: c.clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: staticLinkAddr,
+ State: Static,
+ UpdatedAt: c.clock.Now(),
},
},
}
@@ -836,10 +836,10 @@ func TestNeighborCacheOverwriteWithStaticEntryThenOverflow(t *testing.T) {
startAtEntryIndex: 1,
wantStaticEntries: []NeighborEntry{
{
- Addr: entry.Addr,
- LinkAddr: staticLinkAddr,
- State: Static,
- UpdatedAtNanos: c.clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: staticLinkAddr,
+ State: Static,
+ UpdatedAt: c.clock.Now(),
},
},
}
@@ -867,10 +867,10 @@ func TestNeighborCacheAddStaticEntryThenOverflow(t *testing.T) {
t.Errorf("unexpected error from c.linkRes.neigh.entry(%s, \"\", nil): %s", entry.Addr, err)
}
want := NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: entry.LinkAddr,
- State: Static,
- UpdatedAtNanos: c.clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: entry.LinkAddr,
+ State: Static,
+ UpdatedAt: c.clock.Now(),
}
if diff := cmp.Diff(want, e); diff != "" {
t.Errorf("c.linkRes.neigh.entry(%s, \"\", nil) mismatch (-want, +got):\n%s", entry.Addr, diff)
@@ -882,10 +882,10 @@ func TestNeighborCacheAddStaticEntryThenOverflow(t *testing.T) {
EventType: entryTestAdded,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: entry.LinkAddr,
- State: Static,
- UpdatedAtNanos: c.clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: entry.LinkAddr,
+ State: Static,
+ UpdatedAt: c.clock.Now(),
},
},
}
@@ -902,10 +902,10 @@ func TestNeighborCacheAddStaticEntryThenOverflow(t *testing.T) {
startAtEntryIndex: 1,
wantStaticEntries: []NeighborEntry{
{
- Addr: entry.Addr,
- LinkAddr: entry.LinkAddr,
- State: Static,
- UpdatedAtNanos: c.clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: entry.LinkAddr,
+ State: Static,
+ UpdatedAt: c.clock.Now(),
},
},
}
@@ -939,10 +939,10 @@ func TestNeighborCacheClear(t *testing.T) {
EventType: entryTestAdded,
NICID: 1,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr1,
- State: Static,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr1,
+ State: Static,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -965,20 +965,20 @@ func TestNeighborCacheClear(t *testing.T) {
EventType: entryTestRemoved,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: entry.LinkAddr,
- State: Reachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: entry.LinkAddr,
+ State: Reachable,
+ UpdatedAt: clock.Now(),
},
},
{
EventType: entryTestRemoved,
NICID: 1,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr1,
- State: Static,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr1,
+ State: Static,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1019,10 +1019,10 @@ func TestNeighborCacheClearThenOverflow(t *testing.T) {
EventType: entryTestRemoved,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: entry.LinkAddr,
- State: Reachable,
- UpdatedAtNanos: c.clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: entry.LinkAddr,
+ State: Reachable,
+ UpdatedAt: c.clock.Now(),
},
},
}
@@ -1054,7 +1054,7 @@ func TestNeighborCacheKeepFrequentlyUsed(t *testing.T) {
clock := faketime.NewManualClock()
linkRes := newTestNeighborResolver(&nudDisp, config, clock)
- startedAt := clock.NowNanoseconds()
+ startedAt := clock.Now()
// The following logic is very similar to overflowCache, but
// periodically refreshes the frequently used entry.
@@ -1110,7 +1110,7 @@ func TestNeighborCacheKeepFrequentlyUsed(t *testing.T) {
State: Reachable,
// Can be inferred since the frequently used entry is the first to
// be created and transitioned to Reachable.
- UpdatedAtNanos: startedAt + typicalLatency.Nanoseconds(),
+ UpdatedAt: startedAt.Add(typicalLatency),
},
}
@@ -1119,12 +1119,12 @@ func TestNeighborCacheKeepFrequentlyUsed(t *testing.T) {
if !ok {
t.Fatalf("got linkRes.entries.entry(%d) = _, false, want = true", i)
}
- durationReachableNanos := int64(linkRes.entries.size()-i-1) * typicalLatency.Nanoseconds()
+ durationReachableNanos := time.Duration(linkRes.entries.size()-i-1) * typicalLatency
wantUnsortedEntries = append(wantUnsortedEntries, NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: entry.LinkAddr,
- State: Reachable,
- UpdatedAtNanos: clock.NowNanoseconds() - durationReachableNanos,
+ Addr: entry.Addr,
+ LinkAddr: entry.LinkAddr,
+ State: Reachable,
+ UpdatedAt: clock.Now().Add(-durationReachableNanos),
})
}
@@ -1182,12 +1182,12 @@ func TestNeighborCacheConcurrent(t *testing.T) {
if !ok {
t.Errorf("got linkRes.entries.entry(%d) = _, false, want = true", i)
}
- durationReachableNanos := int64(linkRes.entries.size()-i-1) * typicalLatency.Nanoseconds()
+ durationReachableNanos := time.Duration(linkRes.entries.size()-i-1) * typicalLatency
wantUnsortedEntries = append(wantUnsortedEntries, NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: entry.LinkAddr,
- State: Reachable,
- UpdatedAtNanos: clock.NowNanoseconds() - durationReachableNanos,
+ Addr: entry.Addr,
+ LinkAddr: entry.LinkAddr,
+ State: Reachable,
+ UpdatedAt: clock.Now().Add(-durationReachableNanos),
})
}
@@ -1236,10 +1236,10 @@ func TestNeighborCacheReplace(t *testing.T) {
t.Fatalf("linkRes.neigh.entry(%s, '', nil): %s", entry.Addr, err)
}
want := NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: updatedLinkAddr,
- State: Delay,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: updatedLinkAddr,
+ State: Delay,
+ UpdatedAt: clock.Now(),
}
if diff := cmp.Diff(want, e); diff != "" {
t.Errorf("linkRes.neigh.entry(%s, '', nil) mismatch (-want, +got):\n%s", entry.Addr, diff)
@@ -1255,10 +1255,10 @@ func TestNeighborCacheReplace(t *testing.T) {
t.Errorf("unexpected error from linkRes.neigh.entry(%s, '', nil): %s", entry.Addr, err)
}
want := NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: updatedLinkAddr,
- State: Reachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: updatedLinkAddr,
+ State: Reachable,
+ UpdatedAt: clock.Now(),
}
if diff := cmp.Diff(want, e); diff != "" {
t.Errorf("linkRes.neigh.entry(%s, '', nil) mismatch (-want, +got):\n%s", entry.Addr, diff)
@@ -1293,10 +1293,10 @@ func TestNeighborCacheResolutionFailed(t *testing.T) {
t.Fatalf("unexpected error from linkRes.neigh.entry(%s, '', nil): %s", entry.Addr, err)
}
want := NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: entry.LinkAddr,
- State: Reachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: entry.LinkAddr,
+ State: Reachable,
+ UpdatedAt: clock.Now(),
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("linkRes.neigh.entry(%s, '', nil) mismatch (-want, +got):\n%s", entry.Addr, diff)
@@ -1397,10 +1397,10 @@ func TestNeighborCacheRetryResolution(t *testing.T) {
EventType: entryTestAdded,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: "",
- State: Incomplete,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: "",
+ State: Incomplete,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1428,10 +1428,10 @@ func TestNeighborCacheRetryResolution(t *testing.T) {
EventType: entryTestChanged,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: "",
- State: Unreachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: "",
+ State: Unreachable,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1447,10 +1447,10 @@ func TestNeighborCacheRetryResolution(t *testing.T) {
{
wantEntries := []NeighborEntry{
{
- Addr: entry.Addr,
- LinkAddr: "",
- State: Unreachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: "",
+ State: Unreachable,
+ UpdatedAt: clock.Now(),
},
}
if diff := cmp.Diff(linkRes.neigh.entries(), wantEntries, unorderedEntriesDiffOpts()...); diff != "" {
@@ -1480,10 +1480,10 @@ func TestNeighborCacheRetryResolution(t *testing.T) {
EventType: entryTestChanged,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: "",
- State: Incomplete,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: "",
+ State: Incomplete,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1510,10 +1510,10 @@ func TestNeighborCacheRetryResolution(t *testing.T) {
EventType: entryTestChanged,
NICID: 1,
Entry: NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: entry.LinkAddr,
- State: Reachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: entry.LinkAddr,
+ State: Reachable,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1533,10 +1533,10 @@ func TestNeighborCacheRetryResolution(t *testing.T) {
}
wantEntry := NeighborEntry{
- Addr: entry.Addr,
- LinkAddr: entry.LinkAddr,
- State: Reachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entry.Addr,
+ LinkAddr: entry.LinkAddr,
+ State: Reachable,
+ UpdatedAt: clock.Now(),
}
if diff := cmp.Diff(gotEntry, wantEntry); diff != "" {
t.Fatalf("neighbor entry mismatch (-got, +want):\n%s", diff)
diff --git a/pkg/tcpip/stack/neighbor_entry.go b/pkg/tcpip/stack/neighbor_entry.go
index 463d017fc..ab247db2e 100644
--- a/pkg/tcpip/stack/neighbor_entry.go
+++ b/pkg/tcpip/stack/neighbor_entry.go
@@ -31,10 +31,10 @@ const (
// NeighborEntry describes a neighboring device in the local network.
type NeighborEntry struct {
- Addr tcpip.Address
- LinkAddr tcpip.LinkAddress
- State NeighborState
- UpdatedAtNanos int64
+ Addr tcpip.Address
+ LinkAddr tcpip.LinkAddress
+ State NeighborState
+ UpdatedAt time.Time
}
// NeighborState defines the state of a NeighborEntry within the Neighbor
@@ -138,10 +138,10 @@ func newNeighborEntry(cache *neighborCache, remoteAddr tcpip.Address, nudState *
// calling `setStateLocked`.
func newStaticNeighborEntry(cache *neighborCache, addr tcpip.Address, linkAddr tcpip.LinkAddress, state *NUDState) *neighborEntry {
entry := NeighborEntry{
- Addr: addr,
- LinkAddr: linkAddr,
- State: Static,
- UpdatedAtNanos: cache.nic.stack.clock.NowNanoseconds(),
+ Addr: addr,
+ LinkAddr: linkAddr,
+ State: Static,
+ UpdatedAt: cache.nic.stack.clock.Now(),
}
n := &neighborEntry{
cache: cache,
@@ -224,7 +224,7 @@ func (e *neighborEntry) cancelTimerLocked() {
//
// Precondition: e.mu MUST be locked.
func (e *neighborEntry) removeLocked() {
- e.mu.neigh.UpdatedAtNanos = e.cache.nic.stack.clock.NowNanoseconds()
+ e.mu.neigh.UpdatedAt = e.cache.nic.stack.clock.Now()
e.dispatchRemoveEventLocked()
e.cancelTimerLocked()
// TODO(https://gvisor.dev/issues/5583): test the case where this function is
@@ -246,7 +246,7 @@ func (e *neighborEntry) setStateLocked(next NeighborState) {
prev := e.mu.neigh.State
e.mu.neigh.State = next
- e.mu.neigh.UpdatedAtNanos = e.cache.nic.stack.clock.NowNanoseconds()
+ e.mu.neigh.UpdatedAt = e.cache.nic.stack.clock.Now()
config := e.nudState.Config()
switch next {
@@ -354,7 +354,7 @@ func (e *neighborEntry) handlePacketQueuedLocked(localAddr tcpip.Address) {
case Unknown, Unreachable:
prev := e.mu.neigh.State
e.mu.neigh.State = Incomplete
- e.mu.neigh.UpdatedAtNanos = e.cache.nic.stack.clock.NowNanoseconds()
+ e.mu.neigh.UpdatedAt = e.cache.nic.stack.clock.Now()
switch prev {
case Unknown:
diff --git a/pkg/tcpip/stack/neighbor_entry_test.go b/pkg/tcpip/stack/neighbor_entry_test.go
index c2a291244..59d86d6d4 100644
--- a/pkg/tcpip/stack/neighbor_entry_test.go
+++ b/pkg/tcpip/stack/neighbor_entry_test.go
@@ -349,10 +349,10 @@ func unknownToIncomplete(e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *
EventType: entryTestAdded,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: tcpip.LinkAddress(""),
- State: Incomplete,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: tcpip.LinkAddress(""),
+ State: Incomplete,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -410,10 +410,10 @@ func unknownToStale(e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *entry
EventType: entryTestAdded,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr1,
- State: Stale,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr1,
+ State: Stale,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -441,7 +441,7 @@ func TestEntryIncompleteToIncompleteDoesNotChangeUpdatedAt(t *testing.T) {
// UpdatedAt should remain the same during address resolution.
e.mu.Lock()
- startedAt := e.mu.neigh.UpdatedAtNanos
+ startedAt := e.mu.neigh.UpdatedAt
e.mu.Unlock()
// Wait for the rest of the reachability probe transmissions, signifying
@@ -465,7 +465,7 @@ func TestEntryIncompleteToIncompleteDoesNotChangeUpdatedAt(t *testing.T) {
}
e.mu.Lock()
- if got, want := e.mu.neigh.UpdatedAtNanos, startedAt; got != want {
+ if got, want := e.mu.neigh.UpdatedAt, startedAt; got != want {
t.Errorf("got e.mu.neigh.UpdatedAt = %q, want = %q", got, want)
}
e.mu.Unlock()
@@ -480,10 +480,10 @@ func TestEntryIncompleteToIncompleteDoesNotChangeUpdatedAt(t *testing.T) {
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: tcpip.LinkAddress(""),
- State: Unreachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: tcpip.LinkAddress(""),
+ State: Unreachable,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -542,10 +542,10 @@ func incompleteToReachableWithFlags(e *neighborEntry, nudDisp *testNUDDispatcher
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr1,
- State: Reachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr1,
+ State: Reachable,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -639,10 +639,10 @@ func TestEntryIncompleteToStaleWhenUnsolicitedConfirmation(t *testing.T) {
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr1,
- State: Stale,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr1,
+ State: Stale,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -673,10 +673,10 @@ func TestEntryIncompleteToStaleWhenProbe(t *testing.T) {
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr1,
- State: Stale,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr1,
+ State: Stale,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -752,10 +752,10 @@ func incompleteToUnreachable(c NUDConfigurations, e *neighborEntry, nudDisp *tes
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: tcpip.LinkAddress(""),
- State: Unreachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: tcpip.LinkAddress(""),
+ State: Unreachable,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -938,10 +938,10 @@ func reachableToStale(c NUDConfigurations, e *neighborEntry, nudDisp *testNUDDis
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr1,
- State: Stale,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr1,
+ State: Stale,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -993,10 +993,10 @@ func TestEntryReachableToStaleWhenProbeWithDifferentAddress(t *testing.T) {
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr2,
- State: Stale,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr2,
+ State: Stale,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1045,10 +1045,10 @@ func TestEntryReachableToStaleWhenConfirmationWithDifferentAddress(t *testing.T)
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr1,
- State: Stale,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr1,
+ State: Stale,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1097,10 +1097,10 @@ func TestEntryReachableToStaleWhenConfirmationWithDifferentAddressAndOverride(t
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr2,
- State: Stale,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr2,
+ State: Stale,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1186,10 +1186,10 @@ func TestEntryStaleToReachableWhenSolicitedOverrideConfirmation(t *testing.T) {
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr2,
- State: Reachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr2,
+ State: Reachable,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1238,10 +1238,10 @@ func TestEntryStaleToReachableWhenSolicitedConfirmationWithoutAddress(t *testing
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr1,
- State: Reachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr1,
+ State: Reachable,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1279,10 +1279,10 @@ func TestEntryStaleToStaleWhenOverrideConfirmation(t *testing.T) {
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr2,
- State: Stale,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr2,
+ State: Stale,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1327,10 +1327,10 @@ func TestEntryStaleToStaleWhenProbeUpdateAddress(t *testing.T) {
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr2,
- State: Stale,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr2,
+ State: Stale,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1386,10 +1386,10 @@ func staleToDelay(e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *entryTe
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr1,
- State: Delay,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr1,
+ State: Delay,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1438,10 +1438,10 @@ func TestEntryDelayToReachableWhenUpperLevelConfirmation(t *testing.T) {
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr1,
- State: Reachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr1,
+ State: Reachable,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1493,10 +1493,10 @@ func TestEntryDelayToReachableWhenSolicitedOverrideConfirmation(t *testing.T) {
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr2,
- State: Reachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr2,
+ State: Reachable,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1548,10 +1548,10 @@ func TestEntryDelayToReachableWhenSolicitedConfirmationWithoutAddress(t *testing
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr1,
- State: Reachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr1,
+ State: Reachable,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1640,10 +1640,10 @@ func TestEntryDelayToStaleWhenProbeWithDifferentAddress(t *testing.T) {
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr2,
- State: Stale,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr2,
+ State: Stale,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1692,10 +1692,10 @@ func TestEntryDelayToStaleWhenConfirmationWithDifferentAddress(t *testing.T) {
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr2,
- State: Stale,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr2,
+ State: Stale,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1765,10 +1765,10 @@ func delayToProbe(c NUDConfigurations, e *neighborEntry, nudDisp *testNUDDispatc
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr1,
- State: Probe,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr1,
+ State: Probe,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1822,10 +1822,10 @@ func TestEntryProbeToStaleWhenProbeWithDifferentAddress(t *testing.T) {
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr2,
- State: Stale,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr2,
+ State: Stale,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1877,10 +1877,10 @@ func TestEntryProbeToStaleWhenConfirmationWithDifferentAddress(t *testing.T) {
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr2,
- State: Stale,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr2,
+ State: Stale,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -1998,10 +1998,10 @@ func probeToReachableWithFlags(e *neighborEntry, nudDisp *testNUDDispatcher, lin
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: linkAddr,
- State: Reachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: linkAddr,
+ State: Reachable,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -2150,10 +2150,10 @@ func probeToUnreachable(c NUDConfigurations, e *neighborEntry, nudDisp *testNUDD
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: entryTestLinkAddr1,
- State: Unreachable,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: entryTestLinkAddr1,
+ State: Unreachable,
+ UpdatedAt: clock.Now(),
},
},
}
@@ -2222,10 +2222,10 @@ func unreachableToIncomplete(e *neighborEntry, nudDisp *testNUDDispatcher, linkR
EventType: entryTestChanged,
NICID: entryTestNICID,
Entry: NeighborEntry{
- Addr: entryTestAddr1,
- LinkAddr: tcpip.LinkAddress(""),
- State: Incomplete,
- UpdatedAtNanos: clock.NowNanoseconds(),
+ Addr: entryTestAddr1,
+ LinkAddr: tcpip.LinkAddress(""),
+ State: Incomplete,
+ UpdatedAt: clock.Now(),
},
},
}
diff --git a/pkg/tcpip/stack/nud_test.go b/pkg/tcpip/stack/nud_test.go
index d85213fba..bfce2fe16 100644
--- a/pkg/tcpip/stack/nud_test.go
+++ b/pkg/tcpip/stack/nud_test.go
@@ -170,7 +170,7 @@ func TestNUDFunctions(t *testing.T) {
t.Errorf("s.Neigbors(%d, %d) error mismatch (-want +got):\n%s", test.nicID, ipv6.ProtocolNumber, diff)
} else if test.expectedErr == nil {
if diff := cmp.Diff(
- []stack.NeighborEntry{{Addr: llAddr2, LinkAddr: linkAddr1, State: stack.Static, UpdatedAtNanos: clock.NowNanoseconds()}},
+ []stack.NeighborEntry{{Addr: llAddr2, LinkAddr: linkAddr1, State: stack.Static, UpdatedAt: clock.Now()}},
neighbors,
); diff != "" {
t.Errorf("neighbors mismatch (-want +got):\n%s", diff)
diff --git a/pkg/tcpip/stack/stack_test.go b/pkg/tcpip/stack/stack_test.go
index 73e0f0d58..9c61dd939 100644
--- a/pkg/tcpip/stack/stack_test.go
+++ b/pkg/tcpip/stack/stack_test.go
@@ -4427,7 +4427,7 @@ func TestClearNeighborCacheOnNICDisable(t *testing.T) {
if neighbors, err := s.Neighbors(nicID, addr.proto); err != nil {
t.Fatalf("s.Neighbors(%d, %d): %s", nicID, addr.proto, err)
} else if diff := cmp.Diff(
- []stack.NeighborEntry{{Addr: addr.addr, LinkAddr: linkAddr, State: stack.Static, UpdatedAtNanos: clock.NowNanoseconds()}},
+ []stack.NeighborEntry{{Addr: addr.addr, LinkAddr: linkAddr, State: stack.Static, UpdatedAt: clock.Now()}},
neighbors,
); diff != "" {
t.Fatalf("proto=%d neighbors mismatch (-want +got):\n%s", addr.proto, diff)
diff --git a/pkg/tcpip/stdclock.go b/pkg/tcpip/stdclock.go
index 7ce43a68e..371da2f40 100644
--- a/pkg/tcpip/stdclock.go
+++ b/pkg/tcpip/stdclock.go
@@ -60,11 +60,11 @@ type stdClock struct {
// monotonicOffset is assigned maxMonotonic after restore so that the
// monotonic time will continue from where it "left off" before saving as part
// of S/R.
- monotonicOffset int64 `state:"nosave"`
+ monotonicOffset MonotonicTime `state:"nosave"`
// monotonicMU protects maxMonotonic.
monotonicMU sync.Mutex `state:"nosave"`
- maxMonotonic int64
+ maxMonotonic MonotonicTime
}
// NewStdClock returns an instance of a clock that uses the time package.
@@ -76,25 +76,25 @@ func NewStdClock() Clock {
var _ Clock = (*stdClock)(nil)
-// NowNanoseconds implements Clock.NowNanoseconds.
-func (*stdClock) NowNanoseconds() int64 {
- return time.Now().UnixNano()
+// Now implements Clock.Now.
+func (*stdClock) Now() time.Time {
+ return time.Now()
}
// NowMonotonic implements Clock.NowMonotonic.
-func (s *stdClock) NowMonotonic() int64 {
+func (s *stdClock) NowMonotonic() MonotonicTime {
sinceBase := time.Since(s.baseTime)
if sinceBase < 0 {
panic(fmt.Sprintf("got negative duration = %s since base time = %s", sinceBase, s.baseTime))
}
- monotonicValue := sinceBase.Nanoseconds() + s.monotonicOffset
+ monotonicValue := s.monotonicOffset.Add(sinceBase)
s.monotonicMU.Lock()
defer s.monotonicMU.Unlock()
// Monotonic time values must never decrease.
- if monotonicValue > s.maxMonotonic {
+ if s.maxMonotonic.Before(monotonicValue) {
s.maxMonotonic = monotonicValue
}
diff --git a/pkg/tcpip/tcpip.go b/pkg/tcpip/tcpip.go
index 34f820053..ca98da847 100644
--- a/pkg/tcpip/tcpip.go
+++ b/pkg/tcpip/tcpip.go
@@ -64,17 +64,42 @@ func (e *ErrSaveRejection) Error() string {
return "save rejected due to unsupported networking state: " + e.Err.Error()
}
+// MonotonicTime is a monotonic clock reading.
+//
+// +stateify savable
+type MonotonicTime struct {
+ nanoseconds int64
+}
+
+// Before reports whether the monotonic clock reading mt is before u.
+func (mt MonotonicTime) Before(u MonotonicTime) bool {
+ return mt.nanoseconds < u.nanoseconds
+}
+
+// Add returns the monotonic clock reading mt+d.
+func (mt MonotonicTime) Add(d time.Duration) MonotonicTime {
+ return MonotonicTime{
+ nanoseconds: time.Unix(0, mt.nanoseconds).Add(d).Sub(time.Unix(0, 0)).Nanoseconds(),
+ }
+}
+
+// Sub returns the duration mt-u. If the result exceeds the maximum (or minimum)
+// value that can be stored in a Duration, the maximum (or minimum) duration
+// will be returned. To compute t-d for a duration d, use t.Add(-d).
+func (mt MonotonicTime) Sub(u MonotonicTime) time.Duration {
+ return time.Unix(0, mt.nanoseconds).Sub(time.Unix(0, u.nanoseconds))
+}
+
// A Clock provides the current time and schedules work for execution.
//
// Times returned by a Clock should always be used for application-visible
// time. Only monotonic times should be used for netstack internal timekeeping.
type Clock interface {
- // NowNanoseconds returns the current real time as a number of
- // nanoseconds since the Unix epoch.
- NowNanoseconds() int64
+ // Now returns the current local time.
+ Now() time.Time
- // NowMonotonic returns a monotonic time value at nanosecond resolution.
- NowMonotonic() int64
+ // NowMonotonic returns the current monotonic clock reading.
+ NowMonotonic() MonotonicTime
// AfterFunc waits for the duration to elapse and then calls f in its own
// goroutine. It returns a Timer that can be used to cancel the call using
diff --git a/pkg/tcpip/tests/integration/link_resolution_test.go b/pkg/tcpip/tests/integration/link_resolution_test.go
index 9f727eb8f..4c06460e4 100644
--- a/pkg/tcpip/tests/integration/link_resolution_test.go
+++ b/pkg/tcpip/tests/integration/link_resolution_test.go
@@ -1034,7 +1034,7 @@ func (d *nudDispatcher) OnNeighborRemoved(nicID tcpip.NICID, entry stack.Neighbo
}
func (d *nudDispatcher) waitForEvent(want eventInfo) error {
- if diff := cmp.Diff(want, <-d.c, cmp.AllowUnexported(eventInfo{}), cmpopts.IgnoreFields(stack.NeighborEntry{}, "UpdatedAtNanos")); diff != "" {
+ if diff := cmp.Diff(want, <-d.c, cmp.AllowUnexported(eventInfo{}), cmpopts.IgnoreFields(stack.NeighborEntry{}, "UpdatedAt")); diff != "" {
return fmt.Errorf("got invalid event (-want +got):\n%s", diff)
}
return nil
diff --git a/pkg/tcpip/timer_test.go b/pkg/tcpip/timer_test.go
index 4ddb7020d..e6783b126 100644
--- a/pkg/tcpip/timer_test.go
+++ b/pkg/tcpip/timer_test.go
@@ -15,6 +15,7 @@
package tcpip_test
import (
+ "math"
"sync"
"testing"
"time"
@@ -22,6 +23,67 @@ import (
"gvisor.dev/gvisor/pkg/tcpip"
)
+func TestMonotonicTimeBefore(t *testing.T) {
+ var mt tcpip.MonotonicTime
+ if mt.Before(mt) {
+ t.Errorf("%#v.Before(%#v)", mt, mt)
+ }
+
+ one := mt.Add(1)
+ if one.Before(mt) {
+ t.Errorf("%#v.Before(%#v)", one, mt)
+ }
+ if !mt.Before(one) {
+ t.Errorf("!%#v.Before(%#v)", mt, one)
+ }
+}
+
+func TestMonotonicTimeAddSub(t *testing.T) {
+ var mt tcpip.MonotonicTime
+ if one, two := mt.Add(2), mt.Add(1).Add(1); one != two {
+ t.Errorf("mt.Add(2) != mt.Add(1).Add(1) (%#v != %#v)", one, two)
+ }
+
+ min := mt.Add(math.MinInt64)
+ max := mt.Add(math.MaxInt64)
+
+ if overflow := mt.Add(1).Add(math.MaxInt64); overflow != max {
+ t.Errorf("mt.Add(math.MaxInt64) != mt.Add(1).Add(math.MaxInt64) (%#v != %#v)", max, overflow)
+ }
+ if underflow := mt.Add(-1).Add(math.MinInt64); underflow != min {
+ t.Errorf("mt.Add(math.MinInt64) != mt.Add(-1).Add(math.MinInt64) (%#v != %#v)", min, underflow)
+ }
+
+ if got, want := min.Sub(min), time.Duration(0); want != got {
+ t.Errorf("got min.Sub(min) = %d, want %d", got, want)
+ }
+ if got, want := max.Sub(max), time.Duration(0); want != got {
+ t.Errorf("got max.Sub(max) = %d, want %d", got, want)
+ }
+
+ if overflow, want := max.Sub(min), time.Duration(math.MaxInt64); overflow != want {
+ t.Errorf("mt.Add(math.MaxInt64).Sub(mt.Add(math.MinInt64) != %s (%#v)", want, overflow)
+ }
+ if underflow, want := min.Sub(max), time.Duration(math.MinInt64); underflow != want {
+ t.Errorf("mt.Add(math.MinInt64).Sub(mt.Add(math.MaxInt64) != %s (%#v)", want, underflow)
+ }
+}
+
+func TestMonotonicTimeSub(t *testing.T) {
+ var mt tcpip.MonotonicTime
+
+ if one, two := mt.Add(2), mt.Add(1).Add(1); one != two {
+ t.Errorf("mt.Add(2) != mt.Add(1).Add(1) (%#v != %#v)", one, two)
+ }
+
+ if max, overflow := mt.Add(math.MaxInt64), mt.Add(1).Add(math.MaxInt64); max != overflow {
+ t.Errorf("mt.Add(math.MaxInt64) != mt.Add(1).Add(math.MaxInt64) (%#v != %#v)", max, overflow)
+ }
+ if max, underflow := mt.Add(math.MinInt64), mt.Add(-1).Add(math.MinInt64); max != underflow {
+ t.Errorf("mt.Add(math.MinInt64) != mt.Add(-1).Add(math.MinInt64) (%#v != %#v)", max, underflow)
+ }
+}
+
const (
shortDuration = 1 * time.Nanosecond
middleDuration = 100 * time.Millisecond
diff --git a/pkg/tcpip/transport/icmp/endpoint.go b/pkg/tcpip/transport/icmp/endpoint.go
index 517903ae7..d92b123c4 100644
--- a/pkg/tcpip/transport/icmp/endpoint.go
+++ b/pkg/tcpip/transport/icmp/endpoint.go
@@ -16,6 +16,7 @@ package icmp
import (
"io"
+ "time"
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/tcpip"
@@ -33,7 +34,7 @@ type icmpPacket struct {
icmpPacketEntry
senderAddress tcpip.FullAddress
data buffer.VectorisedView `state:".(buffer.VectorisedView)"`
- timestamp int64
+ receivedAt time.Time `state:".(int64)"`
}
type endpointState int
@@ -193,7 +194,7 @@ func (e *endpoint) Read(dst io.Writer, opts tcpip.ReadOptions) (tcpip.ReadResult
Total: p.data.Size(),
ControlMessages: tcpip.ControlMessages{
HasTimestamp: true,
- Timestamp: p.timestamp,
+ Timestamp: p.receivedAt.UnixNano(),
},
}
if opts.NeedRemoteAddr {
@@ -800,7 +801,7 @@ func (e *endpoint) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketB
e.rcvList.PushBack(packet)
e.rcvBufSize += packet.data.Size()
- packet.timestamp = e.stack.Clock().NowNanoseconds()
+ packet.receivedAt = e.stack.Clock().Now()
e.rcvMu.Unlock()
e.stats.PacketsReceived.Increment()
diff --git a/pkg/tcpip/transport/icmp/endpoint_state.go b/pkg/tcpip/transport/icmp/endpoint_state.go
index 28a56a2d5..b8b839e4a 100644
--- a/pkg/tcpip/transport/icmp/endpoint_state.go
+++ b/pkg/tcpip/transport/icmp/endpoint_state.go
@@ -15,11 +15,23 @@
package icmp
import (
+ "time"
+
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
+// saveReceivedAt is invoked by stateify.
+func (p *icmpPacket) saveReceivedAt() int64 {
+ return p.receivedAt.UnixNano()
+}
+
+// loadReceivedAt is invoked by stateify.
+func (p *icmpPacket) loadReceivedAt(nsec int64) {
+ p.receivedAt = time.Unix(0, nsec)
+}
+
// saveData saves icmpPacket.data field.
func (p *icmpPacket) saveData() buffer.VectorisedView {
// We cannot save p.data directly as p.data.views may alias to p.views,
diff --git a/pkg/tcpip/transport/packet/endpoint.go b/pkg/tcpip/transport/packet/endpoint.go
index fa703a0ed..cd8c99d41 100644
--- a/pkg/tcpip/transport/packet/endpoint.go
+++ b/pkg/tcpip/transport/packet/endpoint.go
@@ -27,6 +27,7 @@ package packet
import (
"fmt"
"io"
+ "time"
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/tcpip"
@@ -41,9 +42,8 @@ type packet struct {
packetEntry
// data holds the actual packet data, including any headers and
// payload.
- data buffer.VectorisedView `state:".(buffer.VectorisedView)"`
- // timestampNS is the unix time at which the packet was received.
- timestampNS int64
+ data buffer.VectorisedView `state:".(buffer.VectorisedView)"`
+ receivedAt time.Time `state:".(int64)"`
// senderAddr is the network address of the sender.
senderAddr tcpip.FullAddress
// packetInfo holds additional information like the protocol
@@ -189,7 +189,7 @@ func (ep *endpoint) Read(dst io.Writer, opts tcpip.ReadOptions) (tcpip.ReadResul
Total: packet.data.Size(),
ControlMessages: tcpip.ControlMessages{
HasTimestamp: true,
- Timestamp: packet.timestampNS,
+ Timestamp: packet.receivedAt.UnixNano(),
},
}
if opts.NeedRemoteAddr {
@@ -451,7 +451,7 @@ func (ep *endpoint) HandlePacket(nicID tcpip.NICID, localAddr tcpip.LinkAddress,
packet.data = buffer.NewVectorisedView(pkt.Size(), pkt.Views())
}
}
- packet.timestampNS = ep.stack.Clock().NowNanoseconds()
+ packet.receivedAt = ep.stack.Clock().Now()
ep.rcvList.PushBack(&packet)
ep.rcvBufSize += packet.data.Size()
diff --git a/pkg/tcpip/transport/packet/endpoint_state.go b/pkg/tcpip/transport/packet/endpoint_state.go
index 5bd860d20..e729921db 100644
--- a/pkg/tcpip/transport/packet/endpoint_state.go
+++ b/pkg/tcpip/transport/packet/endpoint_state.go
@@ -15,11 +15,23 @@
package packet
import (
+ "time"
+
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
+// saveReceivedAt is invoked by stateify.
+func (p *packet) saveReceivedAt() int64 {
+ return p.receivedAt.UnixNano()
+}
+
+// loadReceivedAt is invoked by stateify.
+func (p *packet) loadReceivedAt(nsec int64) {
+ p.receivedAt = time.Unix(0, nsec)
+}
+
// saveData saves packet.data field.
func (p *packet) saveData() buffer.VectorisedView {
// We cannot save p.data directly as p.data.views may alias to p.views,
diff --git a/pkg/tcpip/transport/raw/endpoint.go b/pkg/tcpip/transport/raw/endpoint.go
index 07a585444..1bce2769a 100644
--- a/pkg/tcpip/transport/raw/endpoint.go
+++ b/pkg/tcpip/transport/raw/endpoint.go
@@ -27,6 +27,7 @@ package raw
import (
"io"
+ "time"
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/tcpip"
@@ -41,9 +42,8 @@ type rawPacket struct {
rawPacketEntry
// data holds the actual packet data, including any headers and
// payload.
- data buffer.VectorisedView `state:".(buffer.VectorisedView)"`
- // timestampNS is the unix time at which the packet was received.
- timestampNS int64
+ data buffer.VectorisedView `state:".(buffer.VectorisedView)"`
+ receivedAt time.Time `state:".(int64)"`
// senderAddr is the network address of the sender.
senderAddr tcpip.FullAddress
}
@@ -219,7 +219,7 @@ func (e *endpoint) Read(dst io.Writer, opts tcpip.ReadOptions) (tcpip.ReadResult
Total: pkt.data.Size(),
ControlMessages: tcpip.ControlMessages{
HasTimestamp: true,
- Timestamp: pkt.timestampNS,
+ Timestamp: pkt.receivedAt.UnixNano(),
},
}
if opts.NeedRemoteAddr {
@@ -621,7 +621,7 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) {
}
combinedVV.Append(pkt.Data().ExtractVV())
packet.data = combinedVV
- packet.timestampNS = e.stack.Clock().NowNanoseconds()
+ packet.receivedAt = e.stack.Clock().Now()
e.rcvList.PushBack(packet)
e.rcvBufSize += packet.data.Size()
diff --git a/pkg/tcpip/transport/raw/endpoint_state.go b/pkg/tcpip/transport/raw/endpoint_state.go
index 5d6f2709c..39669b445 100644
--- a/pkg/tcpip/transport/raw/endpoint_state.go
+++ b/pkg/tcpip/transport/raw/endpoint_state.go
@@ -15,11 +15,23 @@
package raw
import (
+ "time"
+
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
+// saveReceivedAt is invoked by stateify.
+func (p *rawPacket) saveReceivedAt() int64 {
+ return p.receivedAt.UnixNano()
+}
+
+// loadReceivedAt is invoked by stateify.
+func (p *rawPacket) loadReceivedAt(nsec int64) {
+ p.receivedAt = time.Unix(0, nsec)
+}
+
// saveData saves rawPacket.data field.
func (p *rawPacket) saveData() buffer.VectorisedView {
// We cannot save p.data directly as p.data.views may alias to p.views,
diff --git a/pkg/tcpip/transport/udp/endpoint.go b/pkg/tcpip/transport/udp/endpoint.go
index 623e069a6..83b589d09 100644
--- a/pkg/tcpip/transport/udp/endpoint.go
+++ b/pkg/tcpip/transport/udp/endpoint.go
@@ -17,6 +17,7 @@ package udp
import (
"io"
"sync/atomic"
+ "time"
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/tcpip"
@@ -34,7 +35,7 @@ type udpPacket struct {
destinationAddress tcpip.FullAddress
packetInfo tcpip.IPPacketInfo
data buffer.VectorisedView `state:".(buffer.VectorisedView)"`
- timestamp int64
+ receivedAt time.Time `state:".(int64)"`
// tos stores either the receiveTOS or receiveTClass value.
tos uint8
}
@@ -321,7 +322,7 @@ func (e *endpoint) Read(dst io.Writer, opts tcpip.ReadOptions) (tcpip.ReadResult
// Control Messages
cm := tcpip.ControlMessages{
HasTimestamp: true,
- Timestamp: p.timestamp,
+ Timestamp: p.receivedAt.UnixNano(),
}
if e.ops.GetReceiveTOS() {
cm.HasTOS = true
@@ -1329,7 +1330,7 @@ func (e *endpoint) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketB
packet.packetInfo.LocalAddr = localAddr
packet.packetInfo.DestinationAddr = localAddr
packet.packetInfo.NIC = pkt.NICID
- packet.timestamp = e.stack.Clock().NowNanoseconds()
+ packet.receivedAt = e.stack.Clock().Now()
e.rcvMu.Unlock()
diff --git a/pkg/tcpip/transport/udp/endpoint_state.go b/pkg/tcpip/transport/udp/endpoint_state.go
index 4aba68b21..1f638c3f6 100644
--- a/pkg/tcpip/transport/udp/endpoint_state.go
+++ b/pkg/tcpip/transport/udp/endpoint_state.go
@@ -15,26 +15,38 @@
package udp
import (
+ "time"
+
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
"gvisor.dev/gvisor/pkg/tcpip/header"
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
+// saveReceivedAt is invoked by stateify.
+func (p *udpPacket) saveReceivedAt() int64 {
+ return p.receivedAt.UnixNano()
+}
+
+// loadReceivedAt is invoked by stateify.
+func (p *udpPacket) loadReceivedAt(nsec int64) {
+ p.receivedAt = time.Unix(0, nsec)
+}
+
// saveData saves udpPacket.data field.
-func (u *udpPacket) saveData() buffer.VectorisedView {
- // We cannot save u.data directly as u.data.views may alias to u.views,
+func (p *udpPacket) saveData() buffer.VectorisedView {
+ // We cannot save p.data directly as p.data.views may alias to p.views,
// which is not allowed by state framework (in-struct pointer).
- return u.data.Clone(nil)
+ return p.data.Clone(nil)
}
// loadData loads udpPacket.data field.
-func (u *udpPacket) loadData(data buffer.VectorisedView) {
- // NOTE: We cannot do the u.data = data.Clone(u.views[:]) optimization
+func (p *udpPacket) loadData(data buffer.VectorisedView) {
+ // NOTE: We cannot do the p.data = data.Clone(p.views[:]) optimization
// here because data.views is not guaranteed to be loaded by now. Plus,
// data.views will be allocated anyway so there really is little point
- // of utilizing u.views for data.views.
- u.data = data
+ // of utilizing p.views for data.views.
+ p.data = data
}
// afterLoad is invoked by stateify.