github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/libpod/network/network.go (about) 1 package network 2 3 import ( 4 "encoding/json" 5 "net" 6 "os" 7 "path/filepath" 8 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/v2/libpod/define" 13 "github.com/containers/podman/v2/pkg/rootless" 14 "github.com/containers/podman/v2/pkg/util" 15 "github.com/pkg/errors" 16 "github.com/sirupsen/logrus" 17 ) 18 19 // DefaultNetworkDriver is the default network type used 20 var DefaultNetworkDriver = "bridge" 21 22 // SupportedNetworkDrivers describes the list of supported drivers 23 var SupportedNetworkDrivers = []string{DefaultNetworkDriver} 24 25 // isSupportedDriver checks if the user provided driver is supported 26 func isSupportedDriver(driver string) error { 27 if util.StringInSlice(driver, SupportedNetworkDrivers) { 28 return nil 29 } 30 return errors.Errorf("driver '%s' is not supported", driver) 31 } 32 33 // GetLiveNetworks returns a slice of networks representing what the system 34 // has defined as network interfaces 35 func GetLiveNetworks() ([]*net.IPNet, error) { 36 addrs, err := net.InterfaceAddrs() 37 if err != nil { 38 return nil, err 39 } 40 nets := make([]*net.IPNet, 0, len(addrs)) 41 for _, address := range addrs { 42 _, n, err := net.ParseCIDR(address.String()) 43 if err != nil { 44 return nil, err 45 } 46 nets = append(nets, n) 47 } 48 return nets, nil 49 } 50 51 // GetLiveNetworkNames returns a list of network interfaces on the system 52 func GetLiveNetworkNames() ([]string, error) { 53 liveInterfaces, err := net.Interfaces() 54 if err != nil { 55 return nil, err 56 } 57 interfaceNames := make([]string, 0, len(liveInterfaces)) 58 for _, i := range liveInterfaces { 59 interfaceNames = append(interfaceNames, i.Name) 60 } 61 return interfaceNames, nil 62 } 63 64 // GetFreeNetwork looks for a free network according to existing cni configuration 65 // files and network interfaces. 66 func GetFreeNetwork(config *config.Config) (*net.IPNet, error) { 67 networks, err := GetNetworksFromFilesystem(config) 68 if err != nil { 69 return nil, err 70 } 71 liveNetworks, err := GetLiveNetworks() 72 if err != nil { 73 return nil, err 74 } 75 nextNetwork, err := GetDefaultPodmanNetwork() 76 if err != nil { 77 return nil, err 78 } 79 logrus.Debugf("default network is %s", nextNetwork.String()) 80 for { 81 newNetwork, err := NextSubnet(nextNetwork) 82 if err != nil { 83 return nil, err 84 } 85 logrus.Debugf("checking if network %s intersects with other cni networks", nextNetwork.String()) 86 if intersectsConfig, _ := networkIntersectsWithNetworks(newNetwork, allocatorToIPNets(networks)); intersectsConfig { 87 logrus.Debugf("network %s is already being used by a cni configuration", nextNetwork.String()) 88 nextNetwork = newNetwork 89 continue 90 } 91 logrus.Debugf("checking if network %s intersects with any network interfaces", nextNetwork.String()) 92 if intersectsLive, _ := networkIntersectsWithNetworks(newNetwork, liveNetworks); !intersectsLive { 93 break 94 } 95 logrus.Debugf("network %s is being used by a network interface", nextNetwork.String()) 96 nextNetwork = newNetwork 97 } 98 return nextNetwork, nil 99 } 100 101 func allocatorToIPNets(networks []*allocator.Net) []*net.IPNet { 102 var nets []*net.IPNet 103 for _, network := range networks { 104 if len(network.IPAM.Ranges) > 0 { 105 // this is the new IPAM range style 106 // append each subnet from ipam the rangeset 107 for _, r := range network.IPAM.Ranges[0] { 108 nets = append(nets, newIPNetFromSubnet(r.Subnet)) 109 } 110 } else { 111 // looks like the old, deprecated style 112 nets = append(nets, newIPNetFromSubnet(network.IPAM.Subnet)) 113 } 114 } 115 return nets 116 } 117 118 func newIPNetFromSubnet(subnet types.IPNet) *net.IPNet { 119 n := net.IPNet{ 120 IP: subnet.IP, 121 Mask: subnet.Mask, 122 } 123 return &n 124 } 125 126 func networkIntersectsWithNetworks(n *net.IPNet, networklist []*net.IPNet) (bool, *net.IPNet) { 127 for _, nw := range networklist { 128 if networkIntersect(n, nw) { 129 return true, nw 130 } 131 } 132 return false, nil 133 } 134 135 func networkIntersect(n1, n2 *net.IPNet) bool { 136 return n2.Contains(n1.IP) || n1.Contains(n2.IP) 137 } 138 139 // ValidateUserNetworkIsAvailable returns via an error if a network is available 140 // to be used 141 func ValidateUserNetworkIsAvailable(config *config.Config, userNet *net.IPNet) error { 142 if len(userNet.IP) == 0 || len(userNet.Mask) == 0 { 143 return errors.Errorf("network %s's ip or mask cannot be empty", userNet.String()) 144 } 145 146 ones, bit := userNet.Mask.Size() 147 if ones == 0 || bit == 0 { 148 return errors.Errorf("network %s's mask is invalid", userNet.String()) 149 } 150 151 networks, err := GetNetworksFromFilesystem(config) 152 if err != nil { 153 return err 154 } 155 liveNetworks, err := GetLiveNetworks() 156 if err != nil { 157 return err 158 } 159 logrus.Debugf("checking if network %s exists in cni networks", userNet.String()) 160 if intersectsConfig, _ := networkIntersectsWithNetworks(userNet, allocatorToIPNets(networks)); intersectsConfig { 161 return errors.Errorf("network %s is already being used by a cni configuration", userNet.String()) 162 } 163 logrus.Debugf("checking if network %s exists in any network interfaces", userNet.String()) 164 if intersectsLive, _ := networkIntersectsWithNetworks(userNet, liveNetworks); intersectsLive { 165 return errors.Errorf("network %s is being used by a network interface", userNet.String()) 166 } 167 return nil 168 } 169 170 // RemoveNetwork removes a given network by name. If the network has container associated with it, that 171 // must be handled outside the context of this. 172 func RemoveNetwork(config *config.Config, name string) error { 173 l, err := acquireCNILock(filepath.Join(config.Engine.TmpDir, LockFileName)) 174 if err != nil { 175 return err 176 } 177 defer l.releaseCNILock() 178 cniPath, err := GetCNIConfigPathByName(config, name) 179 if err != nil { 180 return err 181 } 182 // Before we delete the configuration file, we need to make sure we can read and parse 183 // it to get the network interface name so we can remove that too 184 interfaceName, err := GetInterfaceNameFromConfig(cniPath) 185 if err == nil { 186 // Don't try to remove the network interface if we are not root 187 if !rootless.IsRootless() { 188 liveNetworkNames, err := GetLiveNetworkNames() 189 if err != nil { 190 return errors.Wrapf(err, "failed to get live network names") 191 } 192 if util.StringInSlice(interfaceName, liveNetworkNames) { 193 if err := RemoveInterface(interfaceName); err != nil { 194 return errors.Wrapf(err, "failed to delete the network interface %q", interfaceName) 195 } 196 } 197 } 198 } else if err != ErrNoSuchNetworkInterface { 199 // Don't error if we couldn't find the network interface name 200 return err 201 } 202 // Remove the configuration file 203 if err := os.Remove(cniPath); err != nil { 204 return errors.Wrap(err, "failed to remove network configuration") 205 } 206 return nil 207 } 208 209 // InspectNetwork reads a CNI config and returns its configuration 210 func InspectNetwork(config *config.Config, name string) (map[string]interface{}, error) { 211 b, err := ReadRawCNIConfByName(config, name) 212 if err != nil { 213 return nil, err 214 } 215 rawList := make(map[string]interface{}) 216 err = json.Unmarshal(b, &rawList) 217 return rawList, err 218 } 219 220 // Exists says whether a given network exists or not; it meant 221 // specifically for restful responses so 404s can be used 222 func Exists(config *config.Config, name string) (bool, error) { 223 _, err := ReadRawCNIConfByName(config, name) 224 if err != nil { 225 if errors.Cause(err) == define.ErrNoSuchNetwork { 226 return false, nil 227 } 228 return false, err 229 } 230 return true, nil 231 }