utils_linux.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. // +build linux
  2. // Network utility functions.
  3. package netutils
  4. import (
  5. "fmt"
  6. "net"
  7. "strings"
  8. "github.com/docker/libnetwork/ipamutils"
  9. "github.com/docker/libnetwork/osl"
  10. "github.com/docker/libnetwork/resolvconf"
  11. "github.com/docker/libnetwork/types"
  12. "github.com/vishvananda/netlink"
  13. )
  14. var (
  15. networkGetRoutesFct = netlink.RouteList
  16. )
  17. // CheckRouteOverlaps checks whether the passed network overlaps with any existing routes
  18. func CheckRouteOverlaps(toCheck *net.IPNet) error {
  19. networks, err := networkGetRoutesFct(nil, netlink.FAMILY_V4)
  20. if err != nil {
  21. return err
  22. }
  23. for _, network := range networks {
  24. if network.Dst != nil && NetworkOverlaps(toCheck, network.Dst) {
  25. return ErrNetworkOverlaps
  26. }
  27. }
  28. return nil
  29. }
  30. // GenerateIfaceName returns an interface name using the passed in
  31. // prefix and the length of random bytes. The api ensures that the
  32. // there are is no interface which exists with that name.
  33. func GenerateIfaceName(prefix string, len int) (string, error) {
  34. for i := 0; i < 3; i++ {
  35. name, err := GenerateRandomName(prefix, len)
  36. if err != nil {
  37. continue
  38. }
  39. if _, err := netlink.LinkByName(name); err != nil {
  40. if strings.Contains(err.Error(), "not found") {
  41. return name, nil
  42. }
  43. return "", err
  44. }
  45. }
  46. return "", types.InternalErrorf("could not generate interface name")
  47. }
  48. // ElectInterfaceAddresses looks for an interface on the OS with the
  49. // specified name and returns its IPv4 and IPv6 addresses in CIDR
  50. // form. If the interface does not exist, it chooses from a predifined
  51. // list the first IPv4 address which does not conflict with other
  52. // interfaces on the system.
  53. func ElectInterfaceAddresses(name string) (*net.IPNet, []*net.IPNet, error) {
  54. var (
  55. v4Net *net.IPNet
  56. v6Nets []*net.IPNet
  57. err error
  58. )
  59. defer osl.InitOSContext()()
  60. link, _ := netlink.LinkByName(name)
  61. if link != nil {
  62. v4addr, err := netlink.AddrList(link, netlink.FAMILY_V4)
  63. if err != nil {
  64. return nil, nil, err
  65. }
  66. v6addr, err := netlink.AddrList(link, netlink.FAMILY_V6)
  67. if err != nil {
  68. return nil, nil, err
  69. }
  70. if len(v4addr) > 0 {
  71. v4Net = v4addr[0].IPNet
  72. }
  73. for _, nlAddr := range v6addr {
  74. v6Nets = append(v6Nets, nlAddr.IPNet)
  75. }
  76. }
  77. if link == nil || v4Net == nil {
  78. // Choose from predifined broad networks
  79. v4Net, err = FindAvailableNetwork(ipamutils.PredefinedBroadNetworks)
  80. if err != nil {
  81. return nil, nil, err
  82. }
  83. }
  84. return v4Net, v6Nets, nil
  85. }
  86. // FindAvailableNetwork returns a network from the passed list which does not
  87. // overlap with existing interfaces in the system
  88. func FindAvailableNetwork(list []*net.IPNet) (*net.IPNet, error) {
  89. // We don't check for an error here, because we don't really care if we
  90. // can't read /etc/resolv.conf. So instead we skip the append if resolvConf
  91. // is nil. It either doesn't exist, or we can't read it for some reason.
  92. var nameservers []string
  93. if rc, err := resolvconf.Get(); err == nil {
  94. nameservers = resolvconf.GetNameserversAsCIDR(rc.Content)
  95. }
  96. for _, nw := range list {
  97. if err := CheckNameserverOverlaps(nameservers, nw); err == nil {
  98. if err := CheckRouteOverlaps(nw); err == nil {
  99. return nw, nil
  100. }
  101. }
  102. }
  103. return nil, fmt.Errorf("no available network")
  104. }