github.com/AbhinandanKurakure/podman/v3@v3.4.10/libpod/network/network.go (about)

     1  package network
     2  
     3  import (
     4  	"encoding/json"
     5  	"net"
     6  	"os"
     7  
     8  	"github.com/containernetworking/cni/libcni"
     9  	"github.com/containernetworking/cni/pkg/types"
    10  	"github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator"
    11  	"github.com/containers/common/pkg/config"
    12  	"github.com/containers/podman/v3/libpod/define"
    13  	"github.com/containers/podman/v3/pkg/domain/entities"
    14  	"github.com/containers/podman/v3/pkg/rootless"
    15  	"github.com/containers/podman/v3/pkg/util"
    16  	"github.com/pkg/errors"
    17  	"github.com/sirupsen/logrus"
    18  )
    19  
    20  var (
    21  	// BridgeNetworkDriver defines the bridge cni driver
    22  	BridgeNetworkDriver = "bridge"
    23  	// DefaultNetworkDriver is the default network type used
    24  	DefaultNetworkDriver = BridgeNetworkDriver
    25  	// MacVLANNetworkDriver defines the macvlan cni driver
    26  	MacVLANNetworkDriver = "macvlan"
    27  )
    28  
    29  // SupportedNetworkDrivers describes the list of supported drivers
    30  var SupportedNetworkDrivers = []string{BridgeNetworkDriver, MacVLANNetworkDriver}
    31  
    32  // isSupportedDriver checks if the user provided driver is supported
    33  func isSupportedDriver(driver string) error {
    34  	if util.StringInSlice(driver, SupportedNetworkDrivers) {
    35  		return nil
    36  	}
    37  	return errors.Errorf("driver '%s' is not supported", driver)
    38  }
    39  
    40  // GetLiveNetworks returns a slice of networks representing what the system
    41  // has defined as network interfaces
    42  func GetLiveNetworks() ([]*net.IPNet, error) {
    43  	addrs, err := net.InterfaceAddrs()
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	nets := make([]*net.IPNet, 0, len(addrs))
    48  	for _, address := range addrs {
    49  		_, n, err := net.ParseCIDR(address.String())
    50  		if err != nil {
    51  			return nil, err
    52  		}
    53  		nets = append(nets, n)
    54  	}
    55  	return nets, nil
    56  }
    57  
    58  // GetLiveNetworkNames returns a list of network interfaces on the system
    59  func GetLiveNetworkNames() ([]string, error) {
    60  	liveInterfaces, err := net.Interfaces()
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  	interfaceNames := make([]string, 0, len(liveInterfaces))
    65  	for _, i := range liveInterfaces {
    66  		interfaceNames = append(interfaceNames, i.Name)
    67  	}
    68  	return interfaceNames, nil
    69  }
    70  
    71  // GetFreeNetwork looks for a free network according to existing cni configuration
    72  // files and network interfaces.
    73  func GetFreeNetwork(config *config.Config) (*net.IPNet, error) {
    74  	networks, err := GetNetworksFromFilesystem(config)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	liveNetworks, err := GetLiveNetworks()
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  	nextNetwork, err := GetDefaultPodmanNetwork()
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	logrus.Debugf("default network is %s", nextNetwork.String())
    87  	for {
    88  		newNetwork, err := NextSubnet(nextNetwork)
    89  		if err != nil {
    90  			return nil, err
    91  		}
    92  		logrus.Debugf("checking if network %s intersects with other cni networks", nextNetwork.String())
    93  		if intersectsConfig, _ := networkIntersectsWithNetworks(newNetwork, allocatorToIPNets(networks)); intersectsConfig {
    94  			logrus.Debugf("network %s is already being used by a cni configuration", nextNetwork.String())
    95  			nextNetwork = newNetwork
    96  			continue
    97  		}
    98  		logrus.Debugf("checking if network %s intersects with any network interfaces", nextNetwork.String())
    99  		if intersectsLive, _ := networkIntersectsWithNetworks(newNetwork, liveNetworks); !intersectsLive {
   100  			break
   101  		}
   102  		logrus.Debugf("network %s is being used by a network interface", nextNetwork.String())
   103  		nextNetwork = newNetwork
   104  	}
   105  	return nextNetwork, nil
   106  }
   107  
   108  func allocatorToIPNets(networks []*allocator.Net) []*net.IPNet {
   109  	var nets []*net.IPNet
   110  	for _, network := range networks {
   111  		if len(network.IPAM.Ranges) > 0 {
   112  			// this is the new IPAM range style
   113  			// append each subnet from ipam the rangeset
   114  			for _, allocatorRange := range network.IPAM.Ranges {
   115  				for _, r := range allocatorRange {
   116  					nets = append(nets, newIPNetFromSubnet(r.Subnet))
   117  				}
   118  			}
   119  		} else {
   120  			//	 looks like the old, deprecated style
   121  			nets = append(nets, newIPNetFromSubnet(network.IPAM.Subnet))
   122  		}
   123  	}
   124  	return nets
   125  }
   126  
   127  func newIPNetFromSubnet(subnet types.IPNet) *net.IPNet {
   128  	n := net.IPNet{
   129  		IP:   subnet.IP,
   130  		Mask: subnet.Mask,
   131  	}
   132  	return &n
   133  }
   134  
   135  func networkIntersectsWithNetworks(n *net.IPNet, networklist []*net.IPNet) (bool, *net.IPNet) {
   136  	for _, nw := range networklist {
   137  		if networkIntersect(n, nw) {
   138  			return true, nw
   139  		}
   140  	}
   141  	return false, nil
   142  }
   143  
   144  func networkIntersect(n1, n2 *net.IPNet) bool {
   145  	return n2.Contains(n1.IP) || n1.Contains(n2.IP)
   146  }
   147  
   148  // ValidateUserNetworkIsAvailable returns via an error if a network is available
   149  // to be used
   150  func ValidateUserNetworkIsAvailable(config *config.Config, userNet *net.IPNet) error {
   151  	if len(userNet.IP) == 0 || len(userNet.Mask) == 0 {
   152  		return errors.Errorf("network %s's ip or mask cannot be empty", userNet.String())
   153  	}
   154  
   155  	ones, bit := userNet.Mask.Size()
   156  	if ones == 0 || bit == 0 {
   157  		return errors.Errorf("network %s's mask is invalid", userNet.String())
   158  	}
   159  
   160  	networks, err := GetNetworksFromFilesystem(config)
   161  	if err != nil {
   162  		return err
   163  	}
   164  	liveNetworks, err := GetLiveNetworks()
   165  	if err != nil {
   166  		return err
   167  	}
   168  	logrus.Debugf("checking if network %s exists in cni networks", userNet.String())
   169  	if intersectsConfig, _ := networkIntersectsWithNetworks(userNet, allocatorToIPNets(networks)); intersectsConfig {
   170  		return errors.Errorf("network %s is already being used by a cni configuration", userNet.String())
   171  	}
   172  	logrus.Debugf("checking if network %s exists in any network interfaces", userNet.String())
   173  	if intersectsLive, _ := networkIntersectsWithNetworks(userNet, liveNetworks); intersectsLive {
   174  		return errors.Errorf("network %s is being used by a network interface", userNet.String())
   175  	}
   176  	return nil
   177  }
   178  
   179  // removeNetwork is removes a cni network without a lock and should only be called
   180  // when a lock was otherwise acquired.
   181  func removeNetwork(config *config.Config, name string) error {
   182  	cniPath, err := GetCNIConfigPathByNameOrID(config, name)
   183  	if err != nil {
   184  		return err
   185  	}
   186  	// Before we delete the configuration file, we need to make sure we can read and parse
   187  	// it to get the network interface name so we can remove that too
   188  	interfaceName, err := GetInterfaceNameFromConfig(cniPath)
   189  	if err == nil {
   190  		// Don't try to remove the network interface if we are not root
   191  		if !rootless.IsRootless() {
   192  			liveNetworkNames, err := GetLiveNetworkNames()
   193  			if err != nil {
   194  				return errors.Wrapf(err, "failed to get live network names")
   195  			}
   196  			if util.StringInSlice(interfaceName, liveNetworkNames) {
   197  				if err = RemoveInterface(interfaceName); err != nil {
   198  					// only log the error, it is not fatal
   199  					logrus.Infof("failed to remove network interface %s: %v", interfaceName, err)
   200  				}
   201  			}
   202  		}
   203  	} else if err != ErrNoSuchNetworkInterface {
   204  		// Don't error if we couldn't find the network interface name
   205  		return err
   206  	}
   207  	// Remove the configuration file
   208  	if err := os.Remove(cniPath); err != nil {
   209  		return errors.Wrap(err, "failed to remove network configuration")
   210  	}
   211  	return nil
   212  }
   213  
   214  // RemoveNetwork removes a given network by name.  If the network has container associated with it, that
   215  // must be handled outside the context of this.
   216  func RemoveNetwork(config *config.Config, name string) error {
   217  	l, err := acquireCNILock(config)
   218  	if err != nil {
   219  		return err
   220  	}
   221  	defer l.releaseCNILock()
   222  	return removeNetwork(config, name)
   223  }
   224  
   225  // InspectNetwork reads a CNI config and returns its configuration
   226  func InspectNetwork(config *config.Config, name string) (map[string]interface{}, error) {
   227  	b, err := ReadRawCNIConfByNameOrID(config, name)
   228  	if err != nil {
   229  		return nil, err
   230  	}
   231  	rawList := make(map[string]interface{})
   232  	err = json.Unmarshal(b, &rawList)
   233  	return rawList, err
   234  }
   235  
   236  // Exists says whether a given network exists or not; it meant
   237  // specifically for restful responses so 404s can be used
   238  func Exists(config *config.Config, name string) (bool, error) {
   239  	_, err := ReadRawCNIConfByNameOrID(config, name)
   240  	if err != nil {
   241  		if errors.Cause(err) == define.ErrNoSuchNetwork {
   242  			return false, nil
   243  		}
   244  		return false, err
   245  	}
   246  	return true, nil
   247  }
   248  
   249  // PruneNetworks removes networks that are not being used and that is not the default
   250  // network.  To keep proper fencing for imports, you must provide the used networks
   251  // to this function as a map.  the key is meaningful in the map, the book is a no-op
   252  func PruneNetworks(rtc *config.Config, usedNetworks map[string]bool) ([]*entities.NetworkPruneReport, error) {
   253  	var reports []*entities.NetworkPruneReport
   254  	lock, err := acquireCNILock(rtc)
   255  	if err != nil {
   256  		return nil, err
   257  	}
   258  	defer lock.releaseCNILock()
   259  	nets, err := GetNetworkNamesFromFileSystem(rtc)
   260  	if err != nil {
   261  		return nil, err
   262  	}
   263  	for _, n := range nets {
   264  		_, found := usedNetworks[n]
   265  		// Remove is not default network and not found in the used list
   266  		if n != rtc.Network.DefaultNetwork && !found {
   267  			reports = append(reports, &entities.NetworkPruneReport{
   268  				Name:  n,
   269  				Error: removeNetwork(rtc, n),
   270  			})
   271  		}
   272  	}
   273  	return reports, nil
   274  }
   275  
   276  // NormalizeName translates a network ID into a name.
   277  // If the input is a name the name is returned.
   278  func NormalizeName(config *config.Config, nameOrID string) (string, error) {
   279  	path, err := GetCNIConfigPathByNameOrID(config, nameOrID)
   280  	if err != nil {
   281  		return "", err
   282  	}
   283  	conf, err := libcni.ConfListFromFile(path)
   284  	if err != nil {
   285  		return "", err
   286  	}
   287  	return conf.Name, nil
   288  }