github.com/AbhinandanKurakure/podman/v3@v3.4.10/libpod/network/cni/config.go (about) 1 // +build linux 2 3 package cni 4 5 import ( 6 "net" 7 "os" 8 9 "github.com/containers/podman/v3/libpod/define" 10 "github.com/containers/podman/v3/libpod/network/types" 11 "github.com/containers/podman/v3/libpod/network/util" 12 pkgutil "github.com/containers/podman/v3/pkg/util" 13 "github.com/pkg/errors" 14 "github.com/sirupsen/logrus" 15 "github.com/vishvananda/netlink" 16 ) 17 18 // NetworkCreate will take a partial filled Network and fill the 19 // missing fields. It creates the Network and returns the full Network. 20 func (n *cniNetwork) NetworkCreate(net types.Network) (types.Network, error) { 21 n.lock.Lock() 22 defer n.lock.Unlock() 23 err := n.loadNetworks() 24 if err != nil { 25 return types.Network{}, err 26 } 27 network, err := n.networkCreate(net, true) 28 if err != nil { 29 return types.Network{}, err 30 } 31 // add the new network to the map 32 n.networks[network.libpodNet.Name] = network 33 return *network.libpodNet, nil 34 } 35 36 func (n *cniNetwork) networkCreate(net types.Network, writeToDisk bool) (*network, error) { 37 // if no driver is set use the default one 38 if net.Driver == "" { 39 net.Driver = types.DefaultNetworkDriver 40 } 41 42 // FIXME: Should we use a different type for network create without the ID field? 43 // the caller is not allowed to set a specific ID 44 if net.ID != "" { 45 return nil, errors.Wrap(define.ErrInvalidArg, "ID can not be set for network create") 46 } 47 48 if net.Labels == nil { 49 net.Labels = map[string]string{} 50 } 51 if net.Options == nil { 52 net.Options = map[string]string{} 53 } 54 if net.IPAMOptions == nil { 55 net.IPAMOptions = map[string]string{} 56 } 57 58 var name string 59 var err error 60 // validate the name when given 61 if net.Name != "" { 62 if !define.NameRegex.MatchString(net.Name) { 63 return nil, errors.Wrapf(define.RegexError, "network name %s invalid", net.Name) 64 } 65 if _, ok := n.networks[net.Name]; ok { 66 return nil, errors.Wrapf(define.ErrNetworkExists, "network name %s already used", net.Name) 67 } 68 } else { 69 name, err = n.getFreeDeviceName() 70 if err != nil { 71 return nil, err 72 } 73 net.Name = name 74 } 75 76 switch net.Driver { 77 case types.BridgeNetworkDriver: 78 // if the name was created with getFreeDeviceName set the interface to it as well 79 if name != "" && net.NetworkInterface == "" { 80 net.NetworkInterface = name 81 } 82 err = n.createBridge(&net) 83 if err != nil { 84 return nil, err 85 } 86 case types.MacVLANNetworkDriver: 87 err = createMacVLAN(&net) 88 if err != nil { 89 return nil, err 90 } 91 default: 92 return nil, errors.Wrapf(define.ErrInvalidArg, "unsupported driver %s", net.Driver) 93 } 94 95 for i := range net.Subnets { 96 err := validateSubnet(&net.Subnets[i], !net.Internal) 97 if err != nil { 98 return nil, err 99 } 100 if util.IsIPv6(net.Subnets[i].Subnet.IP) { 101 net.IPv6Enabled = true 102 } 103 } 104 105 // generate the network ID 106 net.ID = getNetworkIDFromName(net.Name) 107 108 // FIXME: Should this be a hard error? 109 if net.DNSEnabled && net.Internal && hasDNSNamePlugin(n.cniPluginDirs) { 110 logrus.Warnf("dnsname and internal networks are incompatible. dnsname plugin not configured for network %s", net.Name) 111 net.DNSEnabled = false 112 } 113 114 cniConf, path, err := n.createCNIConfigListFromNetwork(&net, writeToDisk) 115 if err != nil { 116 return nil, err 117 } 118 return &network{cniNet: cniConf, libpodNet: &net, filename: path}, nil 119 } 120 121 // NetworkRemove will remove the Network with the given name or ID. 122 // It does not ensure that the network is unused. 123 func (n *cniNetwork) NetworkRemove(nameOrID string) error { 124 n.lock.Lock() 125 defer n.lock.Unlock() 126 err := n.loadNetworks() 127 if err != nil { 128 return err 129 } 130 131 network, err := n.getNetwork(nameOrID) 132 if err != nil { 133 return err 134 } 135 136 // Removing the default network is not allowed. 137 if network.libpodNet.Name == n.defaultNetwork { 138 return errors.Errorf("default network %s cannot be removed", n.defaultNetwork) 139 } 140 141 // Remove the bridge network interface on the host. 142 if network.libpodNet.Driver == types.BridgeNetworkDriver { 143 link, err := netlink.LinkByName(network.libpodNet.NetworkInterface) 144 if err == nil { 145 err = netlink.LinkDel(link) 146 // only log the error, it is not fatal 147 if err != nil { 148 logrus.Infof("failed to remove network interface %s: %v", network.libpodNet.NetworkInterface, err) 149 } 150 } 151 } 152 153 file := network.filename 154 delete(n.networks, network.libpodNet.Name) 155 156 return os.Remove(file) 157 } 158 159 // NetworkList will return all known Networks. Optionally you can 160 // supply a list of filter functions. Only if a network matches all 161 // functions it is returned. 162 func (n *cniNetwork) NetworkList(filters ...types.FilterFunc) ([]types.Network, error) { 163 n.lock.Lock() 164 defer n.lock.Unlock() 165 err := n.loadNetworks() 166 if err != nil { 167 return nil, err 168 } 169 170 networks := make([]types.Network, 0, len(n.networks)) 171 outer: 172 for _, net := range n.networks { 173 for _, filter := range filters { 174 // All filters have to match, if one does not match we can skip to the next network. 175 if !filter(*net.libpodNet) { 176 continue outer 177 } 178 } 179 networks = append(networks, *net.libpodNet) 180 } 181 return networks, nil 182 } 183 184 // NetworkInspect will return the Network with the given name or ID. 185 func (n *cniNetwork) NetworkInspect(nameOrID string) (types.Network, error) { 186 n.lock.Lock() 187 defer n.lock.Unlock() 188 err := n.loadNetworks() 189 if err != nil { 190 return types.Network{}, err 191 } 192 193 network, err := n.getNetwork(nameOrID) 194 if err != nil { 195 return types.Network{}, err 196 } 197 return *network.libpodNet, nil 198 } 199 200 func createMacVLAN(network *types.Network) error { 201 if network.Internal { 202 return errors.New("internal is not supported with macvlan") 203 } 204 if network.NetworkInterface != "" { 205 interfaceNames, err := util.GetLiveNetworkNames() 206 if err != nil { 207 return err 208 } 209 if !pkgutil.StringInSlice(network.NetworkInterface, interfaceNames) { 210 return errors.Errorf("parent interface %s does not exists", network.NetworkInterface) 211 } 212 } 213 if len(network.Subnets) == 0 { 214 network.IPAMOptions["driver"] = types.DHCPIPAMDriver 215 } else { 216 network.IPAMOptions["driver"] = types.HostLocalIPAMDriver 217 } 218 return nil 219 } 220 221 func (n *cniNetwork) createBridge(network *types.Network) error { 222 if network.NetworkInterface != "" { 223 bridges := n.getBridgeInterfaceNames() 224 if pkgutil.StringInSlice(network.NetworkInterface, bridges) { 225 return errors.Errorf("bridge name %s already in use", network.NetworkInterface) 226 } 227 if !define.NameRegex.MatchString(network.NetworkInterface) { 228 return errors.Wrapf(define.RegexError, "bridge name %s invalid", network.NetworkInterface) 229 } 230 } else { 231 var err error 232 network.NetworkInterface, err = n.getFreeDeviceName() 233 if err != nil { 234 return err 235 } 236 } 237 238 if len(network.Subnets) == 0 { 239 freeSubnet, err := n.getFreeIPv4NetworkSubnet() 240 if err != nil { 241 return err 242 } 243 network.Subnets = append(network.Subnets, *freeSubnet) 244 } 245 // ipv6 enabled means dual stack, check if we already have 246 // a ipv4 or ipv6 subnet and add one if not. 247 if network.IPv6Enabled { 248 ipv4 := false 249 ipv6 := false 250 for _, subnet := range network.Subnets { 251 if util.IsIPv6(subnet.Subnet.IP) { 252 ipv6 = true 253 } 254 if util.IsIPv4(subnet.Subnet.IP) { 255 ipv4 = true 256 } 257 } 258 if !ipv4 { 259 freeSubnet, err := n.getFreeIPv4NetworkSubnet() 260 if err != nil { 261 return err 262 } 263 network.Subnets = append(network.Subnets, *freeSubnet) 264 } 265 if !ipv6 { 266 freeSubnet, err := n.getFreeIPv6NetworkSubnet() 267 if err != nil { 268 return err 269 } 270 network.Subnets = append(network.Subnets, *freeSubnet) 271 } 272 } 273 network.IPAMOptions["driver"] = types.HostLocalIPAMDriver 274 return nil 275 } 276 277 // validateSubnet will validate a given Subnet. It checks if the 278 // given gateway and lease range are part of this subnet. If the 279 // gateway is empty and addGateway is true it will get the first 280 // available ip in the subnet assigned. 281 func validateSubnet(s *types.Subnet, addGateway bool) error { 282 if s == nil { 283 return errors.New("subnet is nil") 284 } 285 // Reparse to ensure subnet is valid. 286 // Do not use types.ParseCIDR() because we want the ip to be 287 // the network address and not a random ip in the subnet. 288 _, net, err := net.ParseCIDR(s.Subnet.String()) 289 if err != nil { 290 return errors.Wrap(err, "subnet invalid") 291 } 292 s.Subnet = types.IPNet{IPNet: *net} 293 if s.Gateway != nil { 294 if !s.Subnet.Contains(s.Gateway) { 295 return errors.Errorf("gateway %s not in subnet %s", s.Gateway, &s.Subnet) 296 } 297 } else if addGateway { 298 ip, err := util.FirstIPInSubnet(net) 299 if err != nil { 300 return err 301 } 302 s.Gateway = ip 303 } 304 if s.LeaseRange != nil { 305 if s.LeaseRange.StartIP != nil && !s.Subnet.Contains(s.LeaseRange.StartIP) { 306 return errors.Errorf("lease range start ip %s not in subnet %s", s.LeaseRange.StartIP, &s.Subnet) 307 } 308 if s.LeaseRange.EndIP != nil && !s.Subnet.Contains(s.LeaseRange.EndIP) { 309 return errors.Errorf("lease range end ip %s not in subnet %s", s.LeaseRange.EndIP, &s.Subnet) 310 } 311 } 312 return nil 313 }