interface_linux.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. package bridge
  2. import (
  3. "context"
  4. "fmt"
  5. "net"
  6. "net/netip"
  7. "github.com/containerd/log"
  8. "github.com/docker/docker/errdefs"
  9. "github.com/docker/docker/libnetwork/internal/netiputil"
  10. "github.com/vishvananda/netlink"
  11. )
  12. const (
  13. // DefaultBridgeName is the default name for the bridge interface managed
  14. // by the driver when unspecified by the caller.
  15. DefaultBridgeName = "docker0"
  16. )
  17. // Interface models the bridge network device.
  18. type bridgeInterface struct {
  19. Link netlink.Link
  20. bridgeIPv4 *net.IPNet
  21. bridgeIPv6 *net.IPNet
  22. gatewayIPv4 net.IP
  23. gatewayIPv6 net.IP
  24. nlh *netlink.Handle
  25. }
  26. // newInterface creates a new bridge interface structure. It attempts to find
  27. // an already existing device identified by the configuration BridgeName field,
  28. // or the default bridge name when unspecified, but doesn't attempt to create
  29. // one when missing
  30. func newInterface(nlh *netlink.Handle, config *networkConfiguration) (*bridgeInterface, error) {
  31. var err error
  32. i := &bridgeInterface{nlh: nlh}
  33. // Initialize the bridge name to the default if unspecified.
  34. if config.BridgeName == "" {
  35. config.BridgeName = DefaultBridgeName
  36. }
  37. // Attempt to find an existing bridge named with the specified name.
  38. i.Link, err = nlh.LinkByName(config.BridgeName)
  39. if err != nil {
  40. log.G(context.TODO()).Debugf("Did not find any interface with name %s: %v", config.BridgeName, err)
  41. } else if _, ok := i.Link.(*netlink.Bridge); !ok {
  42. return nil, fmt.Errorf("existing interface %s is not a bridge", i.Link.Attrs().Name)
  43. }
  44. return i, nil
  45. }
  46. // exists indicates if the existing bridge interface exists on the system.
  47. func (i *bridgeInterface) exists() bool {
  48. return i.Link != nil
  49. }
  50. // addresses returns a bridge's addresses, IPv4 (with family=netlink.FAMILY_V4)
  51. // or IPv6 (family=netlink.FAMILY_V6).
  52. func (i *bridgeInterface) addresses(family int) ([]netlink.Addr, error) {
  53. if !i.exists() {
  54. // A nonexistent interface, by definition, cannot have any addresses.
  55. return nil, nil
  56. }
  57. addrs, err := i.nlh.AddrList(i.Link, family)
  58. if err != nil {
  59. return nil, fmt.Errorf("Failed to retrieve addresses: %v", err)
  60. }
  61. return addrs, nil
  62. }
  63. func getRequiredIPv6Addrs(config *networkConfiguration) (requiredAddrs map[netip.Addr]netip.Prefix, addr *net.IPNet, gateway net.IP, err error) {
  64. requiredAddrs = make(map[netip.Addr]netip.Prefix)
  65. // TODO(robmry) - is config.AddressIPv6 always set at this point?
  66. // The logic here is preserved from the original setupBridgeIPv6(), but
  67. // can probably be simplified.
  68. // Always give the bridge 'fe80::1' - every interface is required to have an
  69. // address in 'fe80::/64'. Linux may assign an address, but we'll replace it with
  70. // 'fe80::1'. Then, if the configured prefix is 'fe80::/64', the IPAM pool
  71. // assigned address will not be a second address in the LL subnet.
  72. addr = bridgeIPv6
  73. gateway = bridgeIPv6.IP
  74. ra, ok := netiputil.ToPrefix(bridgeIPv6)
  75. if !ok {
  76. err = fmt.Errorf("Failed to convert Link-Local IPv6 address to netip.Prefix")
  77. return nil, nil, net.IP{}, err
  78. }
  79. requiredAddrs[ra.Addr()] = ra
  80. // Set up the user-specified bridge address and gateway.
  81. if config.AddressIPv6 != nil {
  82. addr = config.AddressIPv6
  83. gateway = config.AddressIPv6.IP
  84. ra, ok := netiputil.ToPrefix(config.AddressIPv6)
  85. if !ok {
  86. err = fmt.Errorf("failed to convert bridge IPv6 address '%s' to netip.Prefix", config.AddressIPv6.String())
  87. return nil, nil, net.IP{}, err
  88. }
  89. requiredAddrs[ra.Addr()] = ra
  90. }
  91. return requiredAddrs, addr, gateway, nil
  92. }
  93. func (i *bridgeInterface) programIPv6Addresses(config *networkConfiguration) error {
  94. // Get the IPv6 addresses currently assigned to the bridge, if any.
  95. existingAddrs, err := i.addresses(netlink.FAMILY_V6)
  96. if err != nil {
  97. return errdefs.System(err)
  98. }
  99. // Get the list of required IPv6 addresses for this bridge.
  100. var requiredAddrs map[netip.Addr]netip.Prefix
  101. requiredAddrs, i.bridgeIPv6, i.gatewayIPv6, err = getRequiredIPv6Addrs(config)
  102. if err != nil {
  103. return errdefs.System(err)
  104. }
  105. // Remove addresses that aren't required.
  106. for _, existingAddr := range existingAddrs {
  107. ea, ok := netip.AddrFromSlice(existingAddr.IP)
  108. if !ok {
  109. return errdefs.System(fmt.Errorf("Failed to convert IPv6 address '%s' to netip.Addr", config.AddressIPv6))
  110. }
  111. // Ignore the prefix length when comparing addresses, it's informational
  112. // (RFC-5942 section 4), and removing/re-adding an address that's still valid
  113. // would disrupt traffic on live-restore.
  114. if _, required := requiredAddrs[ea]; !required {
  115. err := i.nlh.AddrDel(i.Link, &existingAddr) //#nosec G601 -- Memory aliasing is not an issue in practice as the &existingAddr pointer is not retained by the callee after the AddrDel() call returns.
  116. if err != nil {
  117. log.G(context.TODO()).WithFields(log.Fields{"error": err, "address": existingAddr.IPNet}).Warnf("Failed to remove residual IPv6 address from bridge")
  118. }
  119. }
  120. }
  121. // Add or update required addresses.
  122. for _, addrPrefix := range requiredAddrs {
  123. // Using AddrReplace(), rather than AddrAdd(). When the subnet is changed for an
  124. // existing bridge in a way that doesn't affect the bridge's assigned address,
  125. // the old address has not been removed at this point - because that would be
  126. // service-affecting for a running container.
  127. //
  128. // But if, for example, 'fixed-cidr-v6' is changed from '2000:dbe::/64' to
  129. // '2000:dbe::/80', the default bridge will still be assigned address
  130. // '2000:dbe::1'. In the output of 'ip a', the prefix length is displayed - and
  131. // the user is likely to expect to see it updated from '64' to '80'.
  132. // Unfortunately, 'netlink.AddrReplace()' ('RTM_NEWADDR' with 'NLM_F_REPLACE')
  133. // doesn't update the prefix length. This is a cosmetic problem, the prefix
  134. // length of an assigned address is not used to determine whether an address is
  135. // "on-link" (RFC-5942).
  136. if err := i.nlh.AddrReplace(i.Link, &netlink.Addr{IPNet: netiputil.ToIPNet(addrPrefix)}); err != nil {
  137. return errdefs.System(fmt.Errorf("failed to add IPv6 address %s to bridge: %v", i.bridgeIPv6, err))
  138. }
  139. }
  140. return nil
  141. }