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 }