Repository: moby/moby
File: integration/networking/bridge_linux_test.go (Go)

Code before:
		container.WithIPv4(netName, ctr2Addr4),
		container.WithIPv6(netName, ctr2Addr6),
	)
	defer c.ContainerRemove(ctx, ctr2Id, client.ContainerRemoveOptions{Force: true})

	ctr2MAC := container.Inspect(ctx, t, c, ctr2Id).NetworkSettings.Networks[netName].MacAddress

	// Ping from ctr1 to ctr2 to populate ctr1's neighbor caches.
	pingRes := container.ExecT(ctx, t, c, ctr1Id, []string{"ping", "-4", "-c1", ctr2Name})
	assert.Assert(t, is.Equal(pingRes.ExitCode, 0))
	pingRes = container.ExecT(ctx, t, c, ctr1Id, []string{"ping", "-6", "-c1", ctr2Name})
	assert.Assert(t, is.Equal(pingRes.ExitCode, 0))

	// Verify ctr1 has neighbor entries for ctr2.
	ctr1Neighs := container.ExecT(ctx, t, c, ctr1Id, []string{"ip", "neigh", "show"})
	assert.Assert(t, is.Equal(ctr1Neighs.ExitCode, 0))
	t.Logf("ctr1 neighbours before restart:\n%s", ctr1Neighs.Combined())

	// Start listening for ARP/NA messages before restarting the daemon.
	stopARPListen := network.CollectBcastARPs(t, brName)
	defer stopARPListen()
	stopICMP6Listen := network.CollectICMP6(t, brName)
	defer stopICMP6Listen()

	// Restart the daemon - this should trigger RestoreInterfaces which sends ARP/NA.
	d.Restart(t, "--live-restore")

	// Give time for ARP/NA messages to be sent.
	t.Log("Sleeping for 5s to collect ARP/NA messages after daemon restart...")
	time.Sleep(5 * time.Second)

	// Verify that ARP/NA messages were sent for ctr2's addresses.
	arps := stopARPListen()
	var arpCount int
	for i, p := range arps {
		ha, pa, err := network.UnpackUnsolARP(p)
		if err != nil {
			t.Logf("ARP %d: %s: %s: %s", i+1, p.ReceivedAt.Format("15:04:05.000"), hex.EncodeToString(p.Data), err)
			continue
		}
		t.Logf("ARP %d: %s '%s' is at '%s'", i+1, p.ReceivedAt.Format("15:04:05.000"), pa, ha)
		if pa == netip.MustParseAddr(ctr2Addr4) && slices.Compare(ha, net.HardwareAddr(ctr2MAC)) == 0 {
			arpCount++
			t.Logf("---> found ARP for ctr2")
		}
	}
	assert.Check(t, arpCount >= 1, "expected at least 1 ARP message for ctr2 after live-restore, got %d", arpCount)

	icmps := stopICMP6Listen()
	var naCount int
	for i, p := range icmps {

Review comment (suggestion):
Should the test start listening for ARP/NA messages after restarting the daemon?

(Before the restart, it'll retransmit messages following the initial container creation for a couple of seconds - so the test wouldn't notice if none were sent after the restart?)

Code after:
		container.WithIPv4(netName, ctr2Addr4),
		container.WithIPv6(netName, ctr2Addr6),
	)
	defer c.ContainerRemove(ctx, ctr2Id, client.ContainerRemoveOptions{Force: true})

	ctr2MAC := container.Inspect(ctx, t, c, ctr2Id).NetworkSettings.Networks[netName].MacAddress

	// Ping from ctr1 to ctr2 to populate ctr1's neighbor caches.
	pingRes := container.ExecT(ctx, t, c, ctr1Id, []string{"ping", "-4", "-c1", ctr2Name})
	assert.Assert(t, is.Equal(pingRes.ExitCode, 0))
	pingRes = container.ExecT(ctx, t, c, ctr1Id, []string{"ping", "-6", "-c1", ctr2Name})
	assert.Assert(t, is.Equal(pingRes.ExitCode, 0))

	// Verify ctr1 has neighbor entries for ctr2.
	ctr1Neighs := container.ExecT(ctx, t, c, ctr1Id, []string{"ip", "neigh", "show"})
	assert.Assert(t, is.Equal(ctr1Neighs.ExitCode, 0))
	t.Logf("ctr1 neighbours before restart:\n%s", ctr1Neighs.Combined())

	// Wait for initial ARP/NA retransmits from container creation to settle.
	// The daemon sends unsolicited ARP/NA messages for a couple of seconds after
	// AddInterface, so we need to wait before starting to listen to avoid counting
	// those messages instead of the ones sent during restore.
	t.Log("Waiting for initial ARP/NA retransmits to settle...")
	time.Sleep(5 * time.Second)

	// Now start listening for ARP/NA messages.
	stopARPListen := network.CollectBcastARPs(t, brName)
	defer stopARPListen()
	stopICMP6Listen := network.CollectICMP6(t, brName)
	defer stopICMP6Listen()

	// Restart the daemon - this should trigger RestoreInterfaces which sends ARP/NA.
	d.Restart(t, "--live-restore")

	// Give time for ARP/NA messages to be sent after restart.
	t.Log("Sleeping for 5s to collect ARP/NA messages after daemon restart...")
	time.Sleep(5 * time.Second)

	// Verify that ARP/NA messages were sent for ctr2's addresses.
	arps := stopARPListen()
	var arpCount int
	for i, p := range arps {
		ha, pa, err := network.UnpackUnsolARP(p)
		if err != nil {
			t.Logf("ARP %d: %s: %s: %s", i+1, p.ReceivedAt.Format("15:04:05.000"), hex.EncodeToString(p.Data), err)
			continue
		}
		t.Logf("ARP %d: %s '%s' is at '%s'", i+1, p.ReceivedAt.Format("15:04:05.000"), pa, ha)
		if pa == netip.MustParseAddr(ctr2Addr4) && slices.Compare(ha, net.HardwareAddr(ctr2MAC)) == 0 {
			arpCount++
			t.Logf("---> found ARP for ctr2")