Browse code

Don't delete IPv6 multicast addresses from a bridge

Multicast addresses aren't added by the daemon so, if they're present,
it's because they were explicitly added - possibly to a user-managed
bridge. So, don't remove.

Signed-off-by: Rob Murray <rob.murray@docker.com>

Rob Murray authored on 2024/05/01 23:11:51
Showing 2 changed files
... ...
@@ -102,6 +102,10 @@ func (i *bridgeInterface) programIPv6Addresses(config *networkConfiguration) err
102 102
 		if p, _ := ea.Prefix(64); p == linkLocalPrefix {
103 103
 			continue
104 104
 		}
105
+		// Don't delete multicast addresses as they're never added by the daemon.
106
+		if ea.IsMulticast() {
107
+			continue
108
+		}
105 109
 		// Ignore the prefix length when comparing addresses, it's informational
106 110
 		// (RFC-5942 section 4), and removing/re-adding an address that's still valid
107 111
 		// would disrupt traffic on live-restore.
... ...
@@ -2,10 +2,12 @@ package bridge
2 2
 
3 3
 import (
4 4
 	"net"
5
+	"sort"
5 6
 	"testing"
6 7
 
7 8
 	"github.com/docker/docker/internal/testutils/netnsutils"
8 9
 	"github.com/vishvananda/netlink"
10
+	"golang.org/x/sys/unix"
9 11
 	"gotest.tools/v3/assert"
10 12
 	is "gotest.tools/v3/assert/cmp"
11 13
 )
... ...
@@ -98,14 +100,16 @@ func TestProgramIPv6Addresses(t *testing.T) {
98 98
 
99 99
 	checkAddrs := func(i *bridgeInterface, nc *networkConfiguration, expAddrs []string) {
100 100
 		t.Helper()
101
-		exp := []netlink.Addr{}
102
-		for _, a := range expAddrs {
103
-			ipNet := cidrToIPNet(t, a)
104
-			exp = append(exp, netlink.Addr{IPNet: ipNet})
101
+		nladdrs, err := i.addresses(netlink.FAMILY_V6)
102
+		actual := []string{}
103
+		for _, a := range nladdrs {
104
+			actual = append(actual, a.String())
105 105
 		}
106
-		actual, err := i.addresses(netlink.FAMILY_V6)
107 106
 		assert.NilError(t, err)
108
-		assert.DeepEqual(t, exp, actual)
107
+		exp := append([]string(nil), expAddrs...)
108
+		sort.Strings(exp)
109
+		sort.Strings(actual)
110
+		assert.DeepEqual(t, actual, exp)
109 111
 		assert.Check(t, is.DeepEqual(i.bridgeIPv6, nc.AddressIPv6))
110 112
 		assert.Check(t, is.DeepEqual(i.gatewayIPv6, nc.AddressIPv6.IP))
111 113
 	}
... ...
@@ -147,4 +151,14 @@ func TestProgramIPv6Addresses(t *testing.T) {
147 147
 	err = i.programIPv6Addresses(nc)
148 148
 	assert.NilError(t, err)
149 149
 	checkAddrs(i, nc, []string{"2000:3000::1/64", "fe80::1/64"})
150
+
151
+	// Add a multicast address to the bridge and check it's not removed.
152
+	mcNlAddr, err := netlink.ParseAddr("ff05::db8:0:1234/96")
153
+	assert.NilError(t, err)
154
+	mcNlAddr.Flags = unix.IFA_F_MCAUTOJOIN
155
+	err = i.nlh.AddrAdd(i.Link, mcNlAddr)
156
+	assert.NilError(t, err)
157
+	err = i.programIPv6Addresses(nc)
158
+	assert.NilError(t, err)
159
+	checkAddrs(i, nc, []string{"2000:3000::1/64", "fe80::1/64", "ff05::db8:0:1234/96"})
150 160
 }