TUN-6744: On posix platforms, assign unique echo ID per (src, dst, echo ID)

This also refactor FunnelTracker to provide a GetOrRegister method to prevent race condition
This commit is contained in:
cthuang
2022-09-09 16:48:42 +01:00
parent e454994e3e
commit b639b6627a
7 changed files with 268 additions and 138 deletions

View File

@@ -12,80 +12,110 @@ import (
func TestSingleEchoIDTracker(t *testing.T) {
tracker := newEchoIDTracker()
srcIP := netip.MustParseAddr("127.0.0.1")
echoID, ok := tracker.get(srcIP)
require.False(t, ok)
require.Equal(t, uint16(0), echoID)
key := flow3Tuple{
srcIP: netip.MustParseAddr("172.16.0.1"),
dstIP: netip.MustParseAddr("172.16.0.2"),
originalEchoID: 5182,
}
// not assigned yet, so nothing to release
require.False(t, tracker.release(srcIP, echoID))
require.False(t, tracker.release(key, 0))
echoID, ok = tracker.assign(srcIP)
echoID, ok := tracker.getOrAssign(key)
require.True(t, ok)
require.Equal(t, uint16(0), echoID)
echoID, ok = tracker.get(srcIP)
// Second time should return the same echo ID
echoID, ok = tracker.getOrAssign(key)
require.True(t, ok)
require.Equal(t, uint16(0), echoID)
// releasing a different ID returns false
require.False(t, tracker.release(srcIP, 1999))
require.True(t, tracker.release(srcIP, echoID))
require.False(t, tracker.release(key, 1999))
require.True(t, tracker.release(key, echoID))
// releasing the second time returns false
require.False(t, tracker.release(srcIP, echoID))
echoID, ok = tracker.get(srcIP)
require.False(t, ok)
require.Equal(t, uint16(0), echoID)
require.False(t, tracker.release(key, echoID))
// Move to the next IP
echoID, ok = tracker.assign(srcIP)
echoID, ok = tracker.getOrAssign(key)
require.True(t, ok)
require.Equal(t, uint16(1), echoID)
}
func TestFullEchoIDTracker(t *testing.T) {
var (
dstIP = netip.MustParseAddr("192.168.0.1")
originalEchoID = 41820
)
tracker := newEchoIDTracker()
firstIP := netip.MustParseAddr("172.16.0.1")
srcIP := firstIP
firstSrcIP := netip.MustParseAddr("172.16.0.1")
srcIP := firstSrcIP
for i := uint16(0); i < math.MaxUint16; i++ {
echoID, ok := tracker.assign(srcIP)
key := flow3Tuple{
srcIP: srcIP,
dstIP: dstIP,
originalEchoID: originalEchoID,
}
echoID, ok := tracker.getOrAssign(key)
require.True(t, ok)
require.Equal(t, i, echoID)
echoID, ok = tracker.get(srcIP)
echoID, ok = tracker.get(key)
require.True(t, ok)
require.Equal(t, i, echoID)
srcIP = srcIP.Next()
}
key := flow3Tuple{
srcIP: srcIP.Next(),
dstIP: dstIP,
originalEchoID: originalEchoID,
}
// All echo IDs are assigned
echoID, ok := tracker.assign(srcIP.Next())
echoID, ok := tracker.getOrAssign(key)
require.False(t, ok)
require.Equal(t, uint16(0), echoID)
srcIP = firstIP
srcIP = firstSrcIP
for i := uint16(0); i < math.MaxUint16; i++ {
ok := tracker.release(srcIP, i)
key := flow3Tuple{
srcIP: srcIP,
dstIP: dstIP,
originalEchoID: originalEchoID,
}
ok := tracker.release(key, i)
require.True(t, ok)
echoID, ok = tracker.get(srcIP)
echoID, ok = tracker.get(key)
require.False(t, ok)
require.Equal(t, uint16(0), echoID)
srcIP = srcIP.Next()
}
// The IDs are assignable again
srcIP = firstIP
srcIP = firstSrcIP
for i := uint16(0); i < math.MaxUint16; i++ {
echoID, ok := tracker.assign(srcIP)
key := flow3Tuple{
srcIP: srcIP,
dstIP: dstIP,
originalEchoID: originalEchoID,
}
echoID, ok := tracker.getOrAssign(key)
require.True(t, ok)
require.Equal(t, i, echoID)
echoID, ok = tracker.get(srcIP)
echoID, ok = tracker.get(key)
require.True(t, ok)
require.Equal(t, i, echoID)
srcIP = srcIP.Next()
}
}
func (eit *echoIDTracker) get(key flow3Tuple) (id uint16, exist bool) {
eit.lock.Lock()
defer eit.lock.Unlock()
id, exists := eit.mapping[key]
return id, exists
}