wgengine/magicsock: don't update control if only endpoint order changes

Updates #1559

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2021-03-22 10:23:26 -07:00 committed by Brad Fitzpatrick
parent 1eb95c7e32
commit 7e0d12e7cc
2 changed files with 84 additions and 6 deletions

View File

@ -630,7 +630,7 @@ func (c *Conn) setEndpoints(endpoints []string, reasons map[string]string) (chan
delete(c.onEndpointRefreshed, de)
}
if stringsEqual(endpoints, c.lastEndpoints) {
if stringSetsEqual(endpoints, c.lastEndpoints) {
return false
}
c.lastEndpoints = endpoints
@ -1111,12 +1111,32 @@ func (c *Conn) determineEndpoints(ctx context.Context) (ipPorts []string, reason
return eps, already, nil
}
func stringsEqual(x, y []string) bool {
if len(x) != len(y) {
return false
// stringSetsEqual reports whether x and y represent the same set of
// strings. The order doesn't matter.
//
// It does not mutate the slices.
func stringSetsEqual(x, y []string) bool {
if len(x) == len(y) {
orderMatches := true
for i := range x {
if x[i] != y[i] {
orderMatches = false
break
}
}
if orderMatches {
return true
}
}
for i := range x {
if x[i] != y[i] {
m := map[string]int{}
for _, v := range x {
m[v] |= 1
}
for _, v := range y {
m[v] |= 2
}
for _, n := range m {
if n != 3 {
return false
}
}

View File

@ -1793,3 +1793,61 @@ func TestRebindStress(t *testing.T) {
t.Fatalf("Got ReceiveIPv4 error: %v (is closed = %v). Log:\n%s", err, errors.Is(err, net.ErrClosed), logBuf.Bytes())
}
}
func TestStringSetsEqual(t *testing.T) {
s := func(nn ...int) (ret []string) {
for _, n := range nn {
ret = append(ret, strconv.Itoa(n))
}
return
}
tests := []struct {
a, b []string
want bool
}{
{
want: true,
},
{
a: s(1, 2, 3),
b: s(1, 2, 3),
want: true,
},
{
a: s(1, 2),
b: s(2, 1),
want: true,
},
{
a: s(1, 2),
b: s(2, 1, 1),
want: true,
},
{
a: s(1, 2, 2),
b: s(2, 1),
want: true,
},
{
a: s(1, 2, 2),
b: s(2, 1, 1),
want: true,
},
{
a: s(1, 2, 2, 3),
b: s(2, 1, 1),
want: false,
},
{
a: s(1, 2, 2),
b: s(2, 1, 1, 3),
want: false,
},
}
for _, tt := range tests {
if got := stringSetsEqual(tt.a, tt.b); got != tt.want {
t.Errorf("%q vs %q = %v; want %v", tt.a, tt.b, got, tt.want)
}
}
}