// +build linux package cni import ( "net" "os" "path/filepath" "github.com/containers/podman/v3/libpod/network/types" ) const ( defaultIPv4Route = "0.0.0.0/0" defaultIPv6Route = "::/0" // defaultPodmanDomainName is used for the dnsname plugin to define // a localized domain name for a created network defaultPodmanDomainName = "dns.podman" // cniDeviceName is the default name for a new bridge, it should be suffixed with an integer cniDeviceName = "cni-podman" // podmanLabelKey key used to store the podman network label in a cni config podmanLabelKey = "podman_labels" // podmanOptionsKey key used to store the podman network options in a cni config podmanOptionsKey = "podman_options" ) // cniPortMapEntry struct is used by the portmap plugin // https://github.com/containernetworking/plugins/blob/649e0181fe7b3a61e708f3e4249a798f57f25cc5/plugins/meta/portmap/main.go#L43-L50 type cniPortMapEntry struct { HostPort int `json:"hostPort"` ContainerPort int `json:"containerPort"` Protocol string `json:"protocol"` HostIP string `json:"hostIP,omitempty"` } // hostLocalBridge describes a configuration for a bridge plugin // https://github.com/containernetworking/plugins/tree/master/plugins/main/bridge#network-configuration-reference type hostLocalBridge struct { PluginType string `json:"type"` BrName string `json:"bridge,omitempty"` IsGW bool `json:"isGateway"` IsDefaultGW bool `json:"isDefaultGateway,omitempty"` ForceAddress bool `json:"forceAddress,omitempty"` IPMasq bool `json:"ipMasq,omitempty"` MTU int `json:"mtu,omitempty"` HairpinMode bool `json:"hairpinMode,omitempty"` PromiscMode bool `json:"promiscMode,omitempty"` Vlan int `json:"vlan,omitempty"` IPAM ipamConfig `json:"ipam"` Capabilities map[string]bool `json:"capabilities"` } // ipamConfig describes an IPAM configuration // https://github.com/containernetworking/plugins/tree/master/plugins/ipam/host-local#network-configuration-reference type ipamConfig struct { PluginType string `json:"type"` Routes []ipamRoute `json:"routes,omitempty"` ResolveConf string `json:"resolveConf,omitempty"` DataDir string `json:"dataDir,omitempty"` Ranges [][]ipamLocalHostRangeConf `json:"ranges,omitempty"` } // ipamLocalHostRangeConf describes the new style IPAM ranges type ipamLocalHostRangeConf struct { Subnet string `json:"subnet"` RangeStart string `json:"rangeStart,omitempty"` RangeEnd string `json:"rangeEnd,omitempty"` Gateway string `json:"gateway,omitempty"` } // ipamRoute describes a route in an ipam config type ipamRoute struct { Dest string `json:"dst"` } // portMapConfig describes the default portmapping config type portMapConfig struct { PluginType string `json:"type"` Capabilities map[string]bool `json:"capabilities"` } // macVLANConfig describes the macvlan config type macVLANConfig struct { PluginType string `json:"type"` Master string `json:"master"` IPAM ipamConfig `json:"ipam"` MTU int `json:"mtu,omitempty"` Capabilities map[string]bool `json:"capabilities"` } // firewallConfig describes the firewall plugin type firewallConfig struct { PluginType string `json:"type"` Backend string `json:"backend"` } // tuningConfig describes the tuning plugin type tuningConfig struct { PluginType string `json:"type"` } // dnsNameConfig describes the dns container name resolution plugin config type dnsNameConfig struct { PluginType string `json:"type"` DomainName string `json:"domainName"` Capabilities map[string]bool `json:"capabilities"` } // podmanMachineConfig enables port handling on the host OS type podmanMachineConfig struct { PluginType string `json:"type"` Capabilities map[string]bool `json:"capabilities"` } // ncList describes a generic map type ncList map[string]interface{} // newNcList creates a generic map of values with string // keys and adds in version and network name func newNcList(name, version string, labels, options map[string]string) ncList { n := ncList{} n["cniVersion"] = version n["name"] = name args := map[string]map[string]string{} if len(labels) > 0 { args[podmanLabelKey] = labels } if len(options) > 0 { args[podmanOptionsKey] = options } if len(args) > 0 { n["args"] = args } return n } // newHostLocalBridge creates a new LocalBridge for host-local func newHostLocalBridge(name string, isGateWay, ipMasq bool, mtu int, vlan int, ipamConf ipamConfig) *hostLocalBridge { caps := make(map[string]bool) caps["ips"] = true bridge := hostLocalBridge{ PluginType: "bridge", BrName: name, IsGW: isGateWay, IPMasq: ipMasq, MTU: mtu, HairpinMode: true, Vlan: vlan, IPAM: ipamConf, } // if we use host-local set the ips cap to ensure we can set static ips via runtime config if ipamConf.PluginType == types.HostLocalIPAMDriver { bridge.Capabilities = caps } return &bridge } // newIPAMHostLocalConf creates a new IPAMHostLocal configuration func newIPAMHostLocalConf(routes []ipamRoute, ipamRanges [][]ipamLocalHostRangeConf) ipamConfig { ipamConf := ipamConfig{ PluginType: "host-local", Routes: routes, } ipamConf.Ranges = ipamRanges return ipamConf } // newIPAMLocalHostRange create a new IPAM range func newIPAMLocalHostRange(subnet types.IPNet, leaseRange *types.LeaseRange, gw net.IP) *ipamLocalHostRangeConf { hostRange := &ipamLocalHostRangeConf{ Subnet: subnet.String(), } // an user provided a range, we add it here if leaseRange != nil { if leaseRange.StartIP != nil { hostRange.RangeStart = leaseRange.StartIP.String() } if leaseRange.EndIP != nil { hostRange.RangeStart = leaseRange.EndIP.String() } } if gw != nil { hostRange.Gateway = gw.String() } return hostRange } // newIPAMRoute creates a new IPAM route configuration // nolint:interfacer func newIPAMRoute(r *net.IPNet) ipamRoute { return ipamRoute{Dest: r.String()} } // newIPAMDefaultRoute creates a new IPAMDefault route of // 0.0.0.0/0 for IPv4 or ::/0 for IPv6 func newIPAMDefaultRoute(isIPv6 bool) (ipamRoute, error) { route := defaultIPv4Route if isIPv6 { route = defaultIPv6Route } _, n, err := net.ParseCIDR(route) if err != nil { return ipamRoute{}, err } return newIPAMRoute(n), nil } // newPortMapPlugin creates a predefined, default portmapping // configuration func newPortMapPlugin() portMapConfig { caps := make(map[string]bool) caps["portMappings"] = true p := portMapConfig{ PluginType: "portmap", Capabilities: caps, } return p } // newFirewallPlugin creates a generic firewall plugin func newFirewallPlugin() firewallConfig { return firewallConfig{ PluginType: "firewall", } } // newTuningPlugin creates a generic tuning section func newTuningPlugin() tuningConfig { return tuningConfig{ PluginType: "tuning", } } // newDNSNamePlugin creates the dnsname config with a given // domainname func newDNSNamePlugin(domainName string) dnsNameConfig { caps := make(map[string]bool, 1) caps["aliases"] = true return dnsNameConfig{ PluginType: "dnsname", DomainName: domainName, Capabilities: caps, } } // hasDNSNamePlugin looks to see if the dnsname cni plugin is present func hasDNSNamePlugin(paths []string) bool { for _, p := range paths { if _, err := os.Stat(filepath.Join(p, "dnsname")); err == nil { return true } } return false } // newMacVLANPlugin creates a macvlanconfig with a given device name func newMacVLANPlugin(device string, mtu int, ipam ipamConfig) macVLANConfig { m := macVLANConfig{ PluginType: "macvlan", IPAM: ipam, } if mtu > 0 { m.MTU = mtu } // CNI is supposed to use the default route if a // parent device is not provided if len(device) > 0 { m.Master = device } caps := make(map[string]bool) caps["ips"] = true // if we use host-local set the ips cap to ensure we can set static ips via runtime config if ipam.PluginType == types.HostLocalIPAMDriver { m.Capabilities = caps } return m } func newPodmanMachinePlugin() podmanMachineConfig { caps := make(map[string]bool, 1) caps["portMappings"] = true return podmanMachineConfig{ PluginType: "podman-machine", Capabilities: caps, } }