github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/network/network.go (about) 1 package network 2 3 import ( 4 "encoding/json" 5 "net" 6 "os" 7 8 "github.com/containernetworking/cni/pkg/types" 9 "github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator" 10 "github.com/containers/libpod/pkg/util" 11 "github.com/pkg/errors" 12 "github.com/sirupsen/logrus" 13 ) 14 15 // SupportedNetworkDrivers describes the list of supported drivers 16 var SupportedNetworkDrivers = []string{"bridge"} 17 18 // IsSupportedDriver checks if the user provided driver is supported 19 func IsSupportedDriver(driver string) error { 20 if util.StringInSlice(driver, SupportedNetworkDrivers) { 21 return nil 22 } 23 return errors.Errorf("driver '%s' is not supported", driver) 24 } 25 26 // GetLiveNetworks returns a slice of networks representing what the system 27 // has defined as network interfaces 28 func GetLiveNetworks() ([]*net.IPNet, error) { 29 var nets []*net.IPNet 30 addrs, err := net.InterfaceAddrs() 31 if err != nil { 32 return nil, err 33 } 34 for _, address := range addrs { 35 _, n, err := net.ParseCIDR(address.String()) 36 if err != nil { 37 return nil, err 38 } 39 nets = append(nets, n) 40 } 41 return nets, nil 42 } 43 44 // GetLiveNetworkNames returns a list of network interfaces on the system 45 func GetLiveNetworkNames() ([]string, error) { 46 var interfaceNames []string 47 liveInterfaces, err := net.Interfaces() 48 if err != nil { 49 return nil, err 50 } 51 for _, i := range liveInterfaces { 52 interfaceNames = append(interfaceNames, i.Name) 53 } 54 return interfaceNames, nil 55 } 56 57 // GetFreeNetwork looks for a free network according to existing cni configuration 58 // files and network interfaces. 59 func GetFreeNetwork() (*net.IPNet, error) { 60 networks, err := GetNetworksFromFilesystem() 61 if err != nil { 62 return nil, err 63 } 64 liveNetworks, err := GetLiveNetworks() 65 if err != nil { 66 return nil, err 67 } 68 nextNetwork, err := GetDefaultPodmanNetwork() 69 if err != nil { 70 return nil, err 71 } 72 logrus.Debugf("default network is %s", nextNetwork.String()) 73 for { 74 newNetwork, err := NextSubnet(nextNetwork) 75 if err != nil { 76 return nil, err 77 } 78 logrus.Debugf("checking if network %s intersects with other cni networks", nextNetwork.String()) 79 if intersectsConfig, _ := networkIntersectsWithNetworks(newNetwork, allocatorToIPNets(networks)); intersectsConfig { 80 logrus.Debugf("network %s is already being used by a cni configuration", nextNetwork.String()) 81 nextNetwork = newNetwork 82 continue 83 } 84 logrus.Debugf("checking if network %s intersects with any network interfaces", nextNetwork.String()) 85 if intersectsLive, _ := networkIntersectsWithNetworks(newNetwork, liveNetworks); !intersectsLive { 86 break 87 } 88 logrus.Debugf("network %s is being used by a network interface", nextNetwork.String()) 89 nextNetwork = newNetwork 90 } 91 return nextNetwork, nil 92 } 93 94 func allocatorToIPNets(networks []*allocator.Net) []*net.IPNet { 95 var nets []*net.IPNet 96 for _, network := range networks { 97 if len(network.IPAM.Ranges) > 0 { 98 // this is the new IPAM range style 99 // append each subnet from ipam the rangeset 100 for _, r := range network.IPAM.Ranges[0] { 101 nets = append(nets, newIPNetFromSubnet(r.Subnet)) 102 } 103 } else { 104 // looks like the old, deprecated style 105 nets = append(nets, newIPNetFromSubnet(network.IPAM.Subnet)) 106 } 107 } 108 return nets 109 } 110 111 func newIPNetFromSubnet(subnet types.IPNet) *net.IPNet { 112 n := net.IPNet{ 113 IP: subnet.IP, 114 Mask: subnet.Mask, 115 } 116 return &n 117 } 118 119 func networkIntersectsWithNetworks(n *net.IPNet, networklist []*net.IPNet) (bool, *net.IPNet) { 120 for _, nw := range networklist { 121 if networkIntersect(n, nw) { 122 return true, nw 123 } 124 } 125 return false, nil 126 } 127 128 func networkIntersect(n1, n2 *net.IPNet) bool { 129 return n2.Contains(n1.IP) || n1.Contains(n2.IP) 130 } 131 132 // ValidateUserNetworkIsAvailable returns via an error if a network is available 133 // to be used 134 func ValidateUserNetworkIsAvailable(userNet *net.IPNet) error { 135 networks, err := GetNetworksFromFilesystem() 136 if err != nil { 137 return err 138 } 139 liveNetworks, err := GetLiveNetworks() 140 if err != nil { 141 return err 142 } 143 logrus.Debugf("checking if network %s exists in cni networks", userNet.String()) 144 if intersectsConfig, _ := networkIntersectsWithNetworks(userNet, allocatorToIPNets(networks)); intersectsConfig { 145 return errors.Errorf("network %s is already being used by a cni configuration", userNet.String()) 146 } 147 logrus.Debugf("checking if network %s exists in any network interfaces", userNet.String()) 148 if intersectsLive, _ := networkIntersectsWithNetworks(userNet, liveNetworks); intersectsLive { 149 return errors.Errorf("network %s is being used by a network interface", userNet.String()) 150 } 151 return nil 152 } 153 154 // RemoveNetwork removes a given network by name. If the network has container associated with it, that 155 // must be handled outside the context of this. 156 func RemoveNetwork(name string) error { 157 cniPath, err := GetCNIConfigPathByName(name) 158 if err != nil { 159 return err 160 } 161 // Before we delete the configuration file, we need to make sure we can read and parse 162 // it to get the network interface name so we can remove that too 163 interfaceName, err := GetInterfaceNameFromConfig(cniPath) 164 if err != nil { 165 return errors.Wrapf(err, "failed to find network interface name in %q", cniPath) 166 } 167 liveNetworkNames, err := GetLiveNetworkNames() 168 if err != nil { 169 return errors.Wrapf(err, "failed to get live network names") 170 } 171 if util.StringInSlice(interfaceName, liveNetworkNames) { 172 if err := RemoveInterface(interfaceName); err != nil { 173 return errors.Wrapf(err, "failed to delete the network interface %q", interfaceName) 174 } 175 } 176 // Remove the configuration file 177 if err := os.Remove(cniPath); err != nil { 178 return errors.Wrapf(err, "failed to remove network configuration file %q", cniPath) 179 } 180 return nil 181 } 182 183 // InspectNetwork reads a CNI config and returns its configuration 184 func InspectNetwork(name string) (map[string]interface{}, error) { 185 b, err := ReadRawCNIConfByName(name) 186 if err != nil { 187 return nil, err 188 } 189 rawList := make(map[string]interface{}) 190 err = json.Unmarshal(b, &rawList) 191 return rawList, err 192 }