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