mac_addr_test.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. package networking
  2. import (
  3. "testing"
  4. containertypes "github.com/docker/docker/api/types/container"
  5. "github.com/docker/docker/client"
  6. "github.com/docker/docker/integration/internal/container"
  7. "github.com/docker/docker/integration/internal/network"
  8. "github.com/docker/docker/libnetwork/drivers/bridge"
  9. "github.com/docker/docker/testutil"
  10. "github.com/docker/docker/testutil/daemon"
  11. "gotest.tools/v3/assert"
  12. is "gotest.tools/v3/assert/cmp"
  13. "gotest.tools/v3/skip"
  14. )
  15. // TestMACAddrOnRestart is a regression test for https://github.com/moby/moby/issues/47146
  16. // - Start a container, let it use a generated MAC address.
  17. // - Stop that container.
  18. // - Start a second container, it'll also use a generated MAC address.
  19. // (It's likely to recycle the first container's MAC address.)
  20. // - Restart the first container.
  21. // (The bug was that it kept its original MAC address, now already in-use.)
  22. // - Check that the two containers have different MAC addresses.
  23. func TestMACAddrOnRestart(t *testing.T) {
  24. skip.If(t, testEnv.DaemonInfo.OSType == "windows")
  25. ctx := setupTest(t)
  26. d := daemon.New(t)
  27. d.StartWithBusybox(ctx, t)
  28. defer d.Stop(t)
  29. c := d.NewClientT(t)
  30. defer c.Close()
  31. const netName = "testmacaddrs"
  32. network.CreateNoError(ctx, t, c, netName,
  33. network.WithDriver("bridge"),
  34. network.WithOption(bridge.BridgeName, netName))
  35. defer network.RemoveNoError(ctx, t, c, netName)
  36. const ctr1Name = "ctr1"
  37. id1 := container.Run(ctx, t, c,
  38. container.WithName(ctr1Name),
  39. container.WithImage("busybox:latest"),
  40. container.WithCmd("top"),
  41. container.WithNetworkMode(netName))
  42. defer c.ContainerRemove(ctx, id1, containertypes.RemoveOptions{
  43. Force: true,
  44. })
  45. err := c.ContainerStop(ctx, ctr1Name, containertypes.StopOptions{})
  46. assert.Assert(t, is.Nil(err))
  47. // Start a second container, giving the daemon a chance to recycle the first container's
  48. // IP and MAC addresses.
  49. const ctr2Name = "ctr2"
  50. id2 := container.Run(ctx, t, c,
  51. container.WithName(ctr2Name),
  52. container.WithImage("busybox:latest"),
  53. container.WithCmd("top"),
  54. container.WithNetworkMode(netName))
  55. defer c.ContainerRemove(ctx, id2, containertypes.RemoveOptions{
  56. Force: true,
  57. })
  58. // Restart the first container.
  59. err = c.ContainerStart(ctx, ctr1Name, containertypes.StartOptions{})
  60. assert.Assert(t, is.Nil(err))
  61. // Check that the containers ended up with different MAC addresses.
  62. ctr1Inspect := container.Inspect(ctx, t, c, ctr1Name)
  63. ctr1MAC := ctr1Inspect.NetworkSettings.Networks[netName].MacAddress
  64. ctr2Inspect := container.Inspect(ctx, t, c, ctr2Name)
  65. ctr2MAC := ctr2Inspect.NetworkSettings.Networks[netName].MacAddress
  66. assert.Check(t, ctr1MAC != ctr2MAC,
  67. "expected containers to have different MAC addresses; got %q for both", ctr1MAC)
  68. }
  69. // Check that a configured MAC address is restored after a container restart,
  70. // and after a daemon restart.
  71. func TestCfgdMACAddrOnRestart(t *testing.T) {
  72. skip.If(t, testEnv.DaemonInfo.OSType == "windows")
  73. ctx := setupTest(t)
  74. d := daemon.New(t)
  75. d.StartWithBusybox(ctx, t)
  76. defer d.Stop(t)
  77. c := d.NewClientT(t)
  78. defer c.Close()
  79. const netName = "testcfgmacaddr"
  80. network.CreateNoError(ctx, t, c, netName,
  81. network.WithDriver("bridge"),
  82. network.WithOption(bridge.BridgeName, netName))
  83. defer network.RemoveNoError(ctx, t, c, netName)
  84. const wantMAC = "02:42:ac:11:00:42"
  85. const ctr1Name = "ctr1"
  86. id1 := container.Run(ctx, t, c,
  87. container.WithName(ctr1Name),
  88. container.WithImage("busybox:latest"),
  89. container.WithCmd("top"),
  90. container.WithNetworkMode(netName),
  91. container.WithMacAddress(netName, wantMAC))
  92. defer c.ContainerRemove(ctx, id1, containertypes.RemoveOptions{
  93. Force: true,
  94. })
  95. inspect := container.Inspect(ctx, t, c, ctr1Name)
  96. gotMAC := inspect.NetworkSettings.Networks[netName].MacAddress
  97. assert.Check(t, is.Equal(wantMAC, gotMAC))
  98. startAndCheck := func() {
  99. t.Helper()
  100. err := c.ContainerStart(ctx, ctr1Name, containertypes.StartOptions{})
  101. assert.Assert(t, is.Nil(err))
  102. inspect = container.Inspect(ctx, t, c, ctr1Name)
  103. gotMAC = inspect.NetworkSettings.Networks[netName].MacAddress
  104. assert.Check(t, is.Equal(wantMAC, gotMAC))
  105. }
  106. // Restart the container, check that the MAC address is restored.
  107. err := c.ContainerStop(ctx, ctr1Name, containertypes.StopOptions{})
  108. assert.Assert(t, is.Nil(err))
  109. startAndCheck()
  110. // Restart the daemon, check that the MAC address is restored.
  111. err = c.ContainerStop(ctx, ctr1Name, containertypes.StopOptions{})
  112. assert.Assert(t, is.Nil(err))
  113. d.Restart(t)
  114. startAndCheck()
  115. }
  116. // Regression test for https://github.com/moby/moby/issues/47228 - check that a
  117. // generated MAC address is not included in the Config section of 'inspect'
  118. // output, but a configured address is.
  119. func TestInspectCfgdMAC(t *testing.T) {
  120. skip.If(t, testEnv.DaemonInfo.OSType == "windows")
  121. ctx := setupTest(t)
  122. d := daemon.New(t)
  123. d.StartWithBusybox(ctx, t)
  124. defer d.Stop(t)
  125. testcases := []struct {
  126. name string
  127. desiredMAC string
  128. netName string
  129. ctrWide bool
  130. }{
  131. {
  132. name: "generated address default bridge",
  133. netName: "bridge",
  134. },
  135. {
  136. name: "configured address default bridge",
  137. desiredMAC: "02:42:ac:11:00:42",
  138. netName: "bridge",
  139. },
  140. {
  141. name: "generated address custom bridge",
  142. netName: "testnet",
  143. },
  144. {
  145. name: "configured address custom bridge",
  146. desiredMAC: "02:42:ac:11:00:42",
  147. netName: "testnet",
  148. },
  149. {
  150. name: "ctr-wide address default bridge",
  151. desiredMAC: "02:42:ac:11:00:42",
  152. netName: "bridge",
  153. ctrWide: true,
  154. },
  155. }
  156. for _, tc := range testcases {
  157. t.Run(tc.name, func(t *testing.T) {
  158. ctx := testutil.StartSpan(ctx, t)
  159. var copts []client.Opt
  160. if tc.ctrWide {
  161. copts = append(copts, client.WithVersion("1.43"))
  162. }
  163. c := d.NewClientT(t, copts...)
  164. defer c.Close()
  165. if tc.netName != "bridge" {
  166. const netName = "inspectcfgmac"
  167. network.CreateNoError(ctx, t, c, netName,
  168. network.WithDriver("bridge"),
  169. network.WithOption(bridge.BridgeName, netName))
  170. defer network.RemoveNoError(ctx, t, c, netName)
  171. }
  172. const ctrName = "ctr"
  173. opts := []func(*container.TestContainerConfig){
  174. container.WithName(ctrName),
  175. container.WithCmd("top"),
  176. container.WithImage("busybox:latest"),
  177. }
  178. // Don't specify the network name for the bridge network, because that
  179. // exercises a different code path (the network name isn't set until the
  180. // container starts, until then it's "default").
  181. if tc.netName != "bridge" {
  182. opts = append(opts, container.WithNetworkMode(tc.netName))
  183. }
  184. if tc.desiredMAC != "" {
  185. if tc.ctrWide {
  186. opts = append(opts, container.WithContainerWideMacAddress(tc.desiredMAC))
  187. } else {
  188. opts = append(opts, container.WithMacAddress(tc.netName, tc.desiredMAC))
  189. }
  190. }
  191. id := container.Create(ctx, t, c, opts...)
  192. defer c.ContainerRemove(ctx, id, containertypes.RemoveOptions{
  193. Force: true,
  194. })
  195. inspect := container.Inspect(ctx, t, c, ctrName)
  196. configMAC := inspect.Config.MacAddress //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
  197. assert.Check(t, is.DeepEqual(configMAC, tc.desiredMAC))
  198. })
  199. }
  200. }