interface_linux_test.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. package bridge
  2. import (
  3. "net"
  4. "net/netip"
  5. "strings"
  6. "testing"
  7. "github.com/docker/docker/internal/testutils/netnsutils"
  8. "github.com/google/go-cmp/cmp"
  9. "github.com/vishvananda/netlink"
  10. "gotest.tools/v3/assert"
  11. is "gotest.tools/v3/assert/cmp"
  12. )
  13. func cidrToIPNet(t *testing.T, cidr string) *net.IPNet {
  14. t.Helper()
  15. ip, ipNet, err := net.ParseCIDR(cidr)
  16. assert.Assert(t, is.Nil(err))
  17. return &net.IPNet{IP: ip, Mask: ipNet.Mask}
  18. }
  19. func addAddr(t *testing.T, link netlink.Link, addr string) {
  20. t.Helper()
  21. ipNet := cidrToIPNet(t, addr)
  22. err := netlink.AddrAdd(link, &netlink.Addr{IPNet: ipNet})
  23. assert.Assert(t, is.Nil(err))
  24. }
  25. func prepTestBridge(t *testing.T, nc *networkConfiguration) *bridgeInterface {
  26. t.Helper()
  27. nh, err := netlink.NewHandle()
  28. assert.Assert(t, err)
  29. i, err := newInterface(nh, nc)
  30. assert.Assert(t, err)
  31. err = setupDevice(nc, i)
  32. assert.Assert(t, err)
  33. return i
  34. }
  35. func TestInterfaceDefaultName(t *testing.T) {
  36. defer netnsutils.SetupTestOSContext(t)()
  37. nh, err := netlink.NewHandle()
  38. if err != nil {
  39. t.Fatal(err)
  40. }
  41. config := &networkConfiguration{}
  42. _, err = newInterface(nh, config)
  43. assert.Check(t, err)
  44. assert.Equal(t, config.BridgeName, DefaultBridgeName)
  45. }
  46. func TestAddressesNoInterface(t *testing.T) {
  47. i := bridgeInterface{}
  48. addrs, err := i.addresses(netlink.FAMILY_V6)
  49. assert.NilError(t, err)
  50. assert.Check(t, is.Len(addrs, 0))
  51. }
  52. func TestAddressesEmptyInterface(t *testing.T) {
  53. defer netnsutils.SetupTestOSContext(t)()
  54. nh, err := netlink.NewHandle()
  55. assert.NilError(t, err)
  56. inf, err := newInterface(nh, &networkConfiguration{})
  57. assert.NilError(t, err)
  58. addrsv4, err := inf.addresses(netlink.FAMILY_V4)
  59. assert.NilError(t, err)
  60. assert.Check(t, is.Len(addrsv4, 0))
  61. addrsv6, err := inf.addresses(netlink.FAMILY_V6)
  62. assert.NilError(t, err)
  63. assert.Check(t, is.Len(addrsv6, 0))
  64. }
  65. func TestAddressesNonEmptyInterface(t *testing.T) {
  66. defer netnsutils.SetupTestOSContext(t)()
  67. i := prepTestBridge(t, &networkConfiguration{})
  68. const expAddrV4, expAddrV6 = "192.168.1.2/24", "fd00:1234::/64"
  69. addAddr(t, i.Link, expAddrV4)
  70. addAddr(t, i.Link, expAddrV6)
  71. addrs, err := i.addresses(netlink.FAMILY_V4)
  72. assert.NilError(t, err)
  73. assert.Check(t, is.Len(addrs, 1))
  74. assert.Equal(t, addrs[0].IPNet.String(), expAddrV4)
  75. addrs, err = i.addresses(netlink.FAMILY_V6)
  76. assert.NilError(t, err)
  77. assert.Check(t, is.Len(addrs, 1))
  78. assert.Equal(t, addrs[0].IPNet.String(), expAddrV6)
  79. }
  80. func TestGetRequiredIPv6Addrs(t *testing.T) {
  81. testcases := []struct {
  82. name string
  83. addressIPv6 string
  84. expReqdAddrs []string
  85. }{
  86. {
  87. name: "Regular address, expect default link local",
  88. addressIPv6: "2000:3000::1/80",
  89. expReqdAddrs: []string{"fe80::1/64", "2000:3000::1/80"},
  90. },
  91. {
  92. name: "Standard link local address only",
  93. addressIPv6: "fe80::1/64",
  94. expReqdAddrs: []string{"fe80::1/64"},
  95. },
  96. {
  97. name: "Nonstandard link local address",
  98. addressIPv6: "fe80:abcd::1/42",
  99. expReqdAddrs: []string{"fe80:abcd::1/42", "fe80::1/64"},
  100. },
  101. }
  102. for _, tc := range testcases {
  103. t.Run(tc.name, func(t *testing.T) {
  104. config := &networkConfiguration{
  105. AddressIPv6: cidrToIPNet(t, tc.addressIPv6),
  106. }
  107. expResult := map[netip.Addr]netip.Prefix{}
  108. for _, addr := range tc.expReqdAddrs {
  109. expResult[netip.MustParseAddr(strings.Split(addr, "/")[0])] = netip.MustParsePrefix(addr)
  110. }
  111. reqd, addr, gw, err := getRequiredIPv6Addrs(config)
  112. assert.Check(t, is.Nil(err))
  113. assert.Check(t, is.DeepEqual(addr, config.AddressIPv6))
  114. assert.Check(t, is.DeepEqual(gw, config.AddressIPv6.IP))
  115. assert.Check(t, is.DeepEqual(reqd, expResult,
  116. cmp.Comparer(func(a, b netip.Prefix) bool { return a == b })))
  117. })
  118. }
  119. }
  120. func TestProgramIPv6Addresses(t *testing.T) {
  121. defer netnsutils.SetupTestOSContext(t)()
  122. checkAddrs := func(i *bridgeInterface, expAddrs []string) {
  123. t.Helper()
  124. exp := []netlink.Addr{}
  125. for _, a := range expAddrs {
  126. ipNet := cidrToIPNet(t, a)
  127. exp = append(exp, netlink.Addr{IPNet: ipNet})
  128. }
  129. actual, err := i.addresses(netlink.FAMILY_V6)
  130. assert.NilError(t, err)
  131. assert.DeepEqual(t, exp, actual)
  132. }
  133. nc := &networkConfiguration{}
  134. i := prepTestBridge(t, nc)
  135. // The bridge has no addresses, ask for a regular IPv6 network and expect it to
  136. // be added to the bridge, with the default link local address.
  137. nc.AddressIPv6 = cidrToIPNet(t, "2000:3000::1/64")
  138. err := i.programIPv6Addresses(nc)
  139. assert.NilError(t, err)
  140. checkAddrs(i, []string{"2000:3000::1/64", "fe80::1/64"})
  141. // Shrink the subnet of that regular address, the prefix length of the address
  142. // will not be modified - but it's informational-only, the address itself has
  143. // not changed.
  144. nc.AddressIPv6 = cidrToIPNet(t, "2000:3000::1/80")
  145. err = i.programIPv6Addresses(nc)
  146. assert.NilError(t, err)
  147. checkAddrs(i, []string{"2000:3000::1/64", "fe80::1/64"})
  148. // Ask for link-local only, by specifying an address with the Link Local prefix.
  149. // The regular address should be removed.
  150. nc.AddressIPv6 = cidrToIPNet(t, "fe80::1/64")
  151. err = i.programIPv6Addresses(nc)
  152. assert.NilError(t, err)
  153. checkAddrs(i, []string{"fe80::1/64"})
  154. // Swap the standard link local address for a nonstandard one.
  155. nc.AddressIPv6 = cidrToIPNet(t, "fe80:5555::1/55")
  156. err = i.programIPv6Addresses(nc)
  157. assert.NilError(t, err)
  158. checkAddrs(i, []string{"fe80:5555::1/55", "fe80::1/64"})
  159. }