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  }