mirror of
https://github.com/containers/podman.git
synced 2025-10-26 02:35:43 +08:00
The network ID is not stored. It is just the sha256 hash from
the network name. There is a risk of a potential hash collision.
However it's very unlikely and even if we hit this it will
complain that more than network with this ID exists.
The main benefit is that the compat api can have proper
network ID support. Also this adds the support for
`podman network ls --format "{{.ID}}"` and `--filter id=<ID>`.
It also ensures that we can do network rm <ID> and network
inspect <ID>.
Since we use a hash this commit is backwards compatible even for
already existing networks.
Signed-off-by: Paul Holzinger <paul.holzinger@web.de>
250 lines
6.0 KiB
Go
250 lines
6.0 KiB
Go
package network
|
|
|
|
import (
|
|
"net"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/containernetworking/cni/libcni"
|
|
"github.com/containers/podman/v2/pkg/util"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
const (
|
|
defaultIPv4Route = "0.0.0.0/0"
|
|
defaultIPv6Route = "::/0"
|
|
)
|
|
|
|
// NcList describes a generic map
|
|
type NcList map[string]interface{}
|
|
|
|
// NcArgs describes the cni args field
|
|
type NcArgs map[string]NcLabels
|
|
|
|
// NcLabels describes the label map
|
|
type NcLabels map[string]string
|
|
|
|
// PodmanLabelKey key used to store the podman network label in a cni config
|
|
const PodmanLabelKey = "podman_labels"
|
|
|
|
// NewNcList creates a generic map of values with string
|
|
// keys and adds in version and network name
|
|
func NewNcList(name, version string, labels NcLabels) NcList {
|
|
n := NcList{}
|
|
n["cniVersion"] = version
|
|
n["name"] = name
|
|
if len(labels) > 0 {
|
|
n["args"] = NcArgs{PodmanLabelKey: labels}
|
|
}
|
|
return n
|
|
}
|
|
|
|
// NewHostLocalBridge creates a new LocalBridge for host-local
|
|
func NewHostLocalBridge(name string, isGateWay, isDefaultGW, ipMasq bool, mtu int, vlan int, ipamConf IPAMHostLocalConf) *HostLocalBridge {
|
|
hostLocalBridge := HostLocalBridge{
|
|
PluginType: "bridge",
|
|
BrName: name,
|
|
IPMasq: ipMasq,
|
|
MTU: mtu,
|
|
HairpinMode: true,
|
|
Vlan: vlan,
|
|
IPAM: ipamConf,
|
|
}
|
|
if isGateWay {
|
|
hostLocalBridge.IsGW = true
|
|
}
|
|
if isDefaultGW {
|
|
hostLocalBridge.IsDefaultGW = true
|
|
}
|
|
return &hostLocalBridge
|
|
}
|
|
|
|
// NewIPAMHostLocalConf creates a new IPAMHostLocal configfuration
|
|
func NewIPAMHostLocalConf(routes []IPAMRoute, ipamRanges [][]IPAMLocalHostRangeConf) (IPAMHostLocalConf, error) {
|
|
ipamConf := IPAMHostLocalConf{
|
|
PluginType: "host-local",
|
|
Routes: routes,
|
|
// Possible future support ? Leaving for clues
|
|
//ResolveConf: "",
|
|
//DataDir: ""
|
|
}
|
|
|
|
ipamConf.Ranges = ipamRanges
|
|
return ipamConf, nil
|
|
}
|
|
|
|
// NewIPAMLocalHostRange create a new IPAM range
|
|
func NewIPAMLocalHostRange(subnet *net.IPNet, ipRange *net.IPNet, gw net.IP) ([]IPAMLocalHostRangeConf, error) { //nolint:interfacer
|
|
var ranges []IPAMLocalHostRangeConf
|
|
hostRange := IPAMLocalHostRangeConf{
|
|
Subnet: subnet.String(),
|
|
}
|
|
// an user provided a range, we add it here
|
|
if ipRange != nil && ipRange.IP != nil {
|
|
first, err := FirstIPInSubnet(ipRange)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
last, err := LastIPInSubnet(ipRange)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
hostRange.RangeStart = first.String()
|
|
hostRange.RangeEnd = last.String()
|
|
}
|
|
if gw != nil {
|
|
hostRange.Gateway = gw.String()
|
|
}
|
|
ranges = append(ranges, hostRange)
|
|
return ranges, nil
|
|
}
|
|
|
|
// NewIPAMRoute creates a new IPAM route configuration
|
|
func NewIPAMRoute(r *net.IPNet) IPAMRoute { //nolint:interfacer
|
|
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) MacVLANConfig {
|
|
i := IPAMDHCP{DHCP: "dhcp"}
|
|
|
|
m := MacVLANConfig{
|
|
PluginType: "macvlan",
|
|
Master: device,
|
|
IPAM: i,
|
|
}
|
|
return m
|
|
}
|
|
|
|
// IfPassesFilter filters NetworkListReport and returns true if the filter match the given config
|
|
func IfPassesFilter(netconf *libcni.NetworkConfigList, filters map[string][]string) (bool, error) {
|
|
result := true
|
|
for key, filterValues := range filters {
|
|
result = false
|
|
switch strings.ToLower(key) {
|
|
case "name":
|
|
// matches one name, regex allowed
|
|
result = util.StringMatchRegexSlice(netconf.Name, filterValues)
|
|
|
|
case "plugin":
|
|
// match one plugin
|
|
plugins := GetCNIPlugins(netconf)
|
|
for _, val := range filterValues {
|
|
if strings.Contains(plugins, val) {
|
|
result = true
|
|
break
|
|
}
|
|
}
|
|
|
|
case "label":
|
|
// matches all labels
|
|
labels := GetNetworkLabels(netconf)
|
|
outer:
|
|
for _, filterValue := range filterValues {
|
|
filterArray := strings.SplitN(filterValue, "=", 2)
|
|
filterKey := filterArray[0]
|
|
if len(filterArray) > 1 {
|
|
filterValue = filterArray[1]
|
|
} else {
|
|
filterValue = ""
|
|
}
|
|
for labelKey, labelValue := range labels {
|
|
if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
|
|
result = true
|
|
continue outer
|
|
}
|
|
}
|
|
result = false
|
|
}
|
|
|
|
case "driver":
|
|
// matches only for the DefaultNetworkDriver
|
|
for _, filterValue := range filterValues {
|
|
plugins := GetCNIPlugins(netconf)
|
|
if filterValue == DefaultNetworkDriver &&
|
|
strings.Contains(plugins, DefaultNetworkDriver) {
|
|
result = true
|
|
}
|
|
}
|
|
|
|
case "id":
|
|
// matches part of one id
|
|
for _, filterValue := range filterValues {
|
|
if strings.Contains(GetNetworkID(netconf.Name), filterValue) {
|
|
result = true
|
|
break
|
|
}
|
|
}
|
|
|
|
// TODO: add dangling filter
|
|
|
|
default:
|
|
return false, errors.Errorf("invalid filter %q", key)
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|