github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/libpod/network/files.go (about) 1 package network 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "sort" 8 "strings" 9 10 "github.com/containernetworking/cni/libcni" 11 "github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator" 12 "github.com/containers/common/pkg/config" 13 "github.com/containers/podman/v2/libpod/define" 14 "github.com/pkg/errors" 15 ) 16 17 // ErrNoSuchNetworkInterface indicates that no network interface exists 18 var ErrNoSuchNetworkInterface = errors.New("unable to find interface name for network") 19 20 // GetCNIConfDir get CNI configuration directory 21 func GetCNIConfDir(configArg *config.Config) string { 22 if len(configArg.Network.NetworkConfigDir) < 1 { 23 dc, err := config.DefaultConfig() 24 if err != nil { 25 // Fallback to hard-coded dir 26 return CNIConfigDir 27 } 28 return dc.Network.NetworkConfigDir 29 } 30 return configArg.Network.NetworkConfigDir 31 } 32 33 // LoadCNIConfsFromDir loads all the CNI configurations from a dir 34 func LoadCNIConfsFromDir(dir string) ([]*libcni.NetworkConfigList, error) { 35 files, err := libcni.ConfFiles(dir, []string{".conflist"}) 36 if err != nil { 37 return nil, err 38 } 39 sort.Strings(files) 40 41 configs := make([]*libcni.NetworkConfigList, 0, len(files)) 42 for _, confFile := range files { 43 conf, err := libcni.ConfListFromFile(confFile) 44 if err != nil { 45 return nil, errors.Wrapf(err, "in %s", confFile) 46 } 47 configs = append(configs, conf) 48 } 49 return configs, nil 50 } 51 52 // GetCNIConfigPathByName finds a CNI network by name and 53 // returns its configuration file path 54 func GetCNIConfigPathByName(config *config.Config, name string) (string, error) { 55 files, err := libcni.ConfFiles(GetCNIConfDir(config), []string{".conflist"}) 56 if err != nil { 57 return "", err 58 } 59 for _, confFile := range files { 60 conf, err := libcni.ConfListFromFile(confFile) 61 if err != nil { 62 return "", errors.Wrapf(err, "in %s", confFile) 63 } 64 if conf.Name == name { 65 return confFile, nil 66 } 67 } 68 return "", errors.Wrap(define.ErrNoSuchNetwork, fmt.Sprintf("unable to find network configuration for %s", name)) 69 } 70 71 // ReadRawCNIConfByName reads the raw CNI configuration for a CNI 72 // network by name 73 func ReadRawCNIConfByName(config *config.Config, name string) ([]byte, error) { 74 confFile, err := GetCNIConfigPathByName(config, name) 75 if err != nil { 76 return nil, err 77 } 78 b, err := ioutil.ReadFile(confFile) 79 return b, err 80 } 81 82 // GetCNIPlugins returns a list of plugins that a given network 83 // has in the form of a string 84 func GetCNIPlugins(list *libcni.NetworkConfigList) string { 85 plugins := make([]string, 0, len(list.Plugins)) 86 for _, plug := range list.Plugins { 87 plugins = append(plugins, plug.Network.Type) 88 } 89 return strings.Join(plugins, ",") 90 } 91 92 // GetNetworksFromFilesystem gets all the networks from the cni configuration 93 // files 94 func GetNetworksFromFilesystem(config *config.Config) ([]*allocator.Net, error) { 95 var cniNetworks []*allocator.Net 96 97 networks, err := LoadCNIConfsFromDir(GetCNIConfDir(config)) 98 if err != nil { 99 return nil, err 100 } 101 for _, n := range networks { 102 for _, cniplugin := range n.Plugins { 103 if cniplugin.Network.Type == "bridge" { 104 ipamConf := allocator.Net{} 105 if err := json.Unmarshal(cniplugin.Bytes, &ipamConf); err != nil { 106 return nil, err 107 } 108 cniNetworks = append(cniNetworks, &ipamConf) 109 break 110 } 111 } 112 } 113 return cniNetworks, nil 114 } 115 116 // GetNetworkNamesFromFileSystem gets all the names from the cni network 117 // configuration files 118 func GetNetworkNamesFromFileSystem(config *config.Config) ([]string, error) { 119 networks, err := LoadCNIConfsFromDir(GetCNIConfDir(config)) 120 if err != nil { 121 return nil, err 122 } 123 networkNames := []string{} 124 for _, n := range networks { 125 networkNames = append(networkNames, n.Name) 126 } 127 return networkNames, nil 128 } 129 130 // GetInterfaceNameFromConfig returns the interface name for the bridge plugin 131 func GetInterfaceNameFromConfig(path string) (string, error) { 132 var name string 133 conf, err := libcni.ConfListFromFile(path) 134 if err != nil { 135 return "", err 136 } 137 for _, cniplugin := range conf.Plugins { 138 if cniplugin.Network.Type == "bridge" { 139 plugin := make(map[string]interface{}) 140 if err := json.Unmarshal(cniplugin.Bytes, &plugin); err != nil { 141 return "", err 142 } 143 name = plugin["bridge"].(string) 144 break 145 } 146 } 147 if len(name) == 0 { 148 return "", ErrNoSuchNetworkInterface 149 } 150 return name, nil 151 } 152 153 // GetBridgeNamesFromFileSystem is a convenience function to get all the bridge 154 // names from the configured networks 155 func GetBridgeNamesFromFileSystem(config *config.Config) ([]string, error) { 156 networks, err := LoadCNIConfsFromDir(GetCNIConfDir(config)) 157 if err != nil { 158 return nil, err 159 } 160 161 bridgeNames := []string{} 162 for _, n := range networks { 163 var name string 164 // iterate network conflists 165 for _, cniplugin := range n.Plugins { 166 // iterate plugins 167 if cniplugin.Network.Type == "bridge" { 168 plugin := make(map[string]interface{}) 169 if err := json.Unmarshal(cniplugin.Bytes, &plugin); err != nil { 170 continue 171 } 172 name = plugin["bridge"].(string) 173 } 174 } 175 bridgeNames = append(bridgeNames, name) 176 } 177 return bridgeNames, nil 178 }