mirror of
https://github.com/containers/podman.git
synced 2025-11-15 02:29:16 +08:00
use libnetwork from c/common
The libpod/network packages were moved to c/common so that buildah can use it as well. To prevent duplication use it in podman as well and remove it from here. Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
68
vendor/github.com/containers/common/libnetwork/internal/util/bridge.go
generated
vendored
Normal file
68
vendor/github.com/containers/common/libnetwork/internal/util/bridge.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/containers/common/libnetwork/types"
|
||||
"github.com/containers/common/libnetwork/util"
|
||||
pkgutil "github.com/containers/common/pkg/util"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func CreateBridge(n NetUtil, network *types.Network, usedNetworks []*net.IPNet) error {
|
||||
if network.NetworkInterface != "" {
|
||||
bridges := GetBridgeInterfaceNames(n)
|
||||
if pkgutil.StringInSlice(network.NetworkInterface, bridges) {
|
||||
return errors.Errorf("bridge name %s already in use", network.NetworkInterface)
|
||||
}
|
||||
if !types.NameRegex.MatchString(network.NetworkInterface) {
|
||||
return errors.Wrapf(types.RegexError, "bridge name %s invalid", network.NetworkInterface)
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
network.NetworkInterface, err = GetFreeDeviceName(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if network.IPAMOptions["driver"] != types.DHCPIPAMDriver {
|
||||
if len(network.Subnets) == 0 {
|
||||
freeSubnet, err := GetFreeIPv4NetworkSubnet(usedNetworks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
network.Subnets = append(network.Subnets, *freeSubnet)
|
||||
}
|
||||
// ipv6 enabled means dual stack, check if we already have
|
||||
// a ipv4 or ipv6 subnet and add one if not.
|
||||
if network.IPv6Enabled {
|
||||
ipv4 := false
|
||||
ipv6 := false
|
||||
for _, subnet := range network.Subnets {
|
||||
if util.IsIPv6(subnet.Subnet.IP) {
|
||||
ipv6 = true
|
||||
}
|
||||
if util.IsIPv4(subnet.Subnet.IP) {
|
||||
ipv4 = true
|
||||
}
|
||||
}
|
||||
if !ipv4 {
|
||||
freeSubnet, err := GetFreeIPv4NetworkSubnet(usedNetworks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
network.Subnets = append(network.Subnets, *freeSubnet)
|
||||
}
|
||||
if !ipv6 {
|
||||
freeSubnet, err := GetFreeIPv6NetworkSubnet(usedNetworks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
network.Subnets = append(network.Subnets, *freeSubnet)
|
||||
}
|
||||
}
|
||||
network.IPAMOptions["driver"] = types.HostLocalIPAMDriver
|
||||
}
|
||||
return nil
|
||||
}
|
||||
41
vendor/github.com/containers/common/libnetwork/internal/util/create.go
generated
vendored
Normal file
41
vendor/github.com/containers/common/libnetwork/internal/util/create.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"github.com/containers/common/libnetwork/types"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func CommonNetworkCreate(n NetUtil, network *types.Network) error {
|
||||
if network.Labels == nil {
|
||||
network.Labels = map[string]string{}
|
||||
}
|
||||
if network.Options == nil {
|
||||
network.Options = map[string]string{}
|
||||
}
|
||||
if network.IPAMOptions == nil {
|
||||
network.IPAMOptions = map[string]string{}
|
||||
}
|
||||
|
||||
var name string
|
||||
var err error
|
||||
// validate the name when given
|
||||
if network.Name != "" {
|
||||
if !types.NameRegex.MatchString(network.Name) {
|
||||
return errors.Wrapf(types.RegexError, "network name %s invalid", network.Name)
|
||||
}
|
||||
if _, err := n.Network(network.Name); err == nil {
|
||||
return errors.Wrapf(types.ErrNetworkExists, "network name %s already used", network.Name)
|
||||
}
|
||||
} else {
|
||||
name, err = GetFreeDeviceName(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
network.Name = name
|
||||
// also use the name as interface name when we create a bridge network
|
||||
if network.Driver == types.BridgeNetworkDriver && network.NetworkInterface == "" {
|
||||
network.NetworkInterface = name
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
19
vendor/github.com/containers/common/libnetwork/internal/util/interface.go
generated
vendored
Normal file
19
vendor/github.com/containers/common/libnetwork/internal/util/interface.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package util
|
||||
|
||||
import "github.com/containers/common/libnetwork/types"
|
||||
|
||||
// This is a helper package to allow code sharing between the different
|
||||
// network interfaces.
|
||||
|
||||
// NetUtil is a helper interface which all network interfaces should implement to allow easy code sharing
|
||||
type NetUtil interface {
|
||||
// ForEach eaxecutes the given function for each network
|
||||
ForEach(func(types.Network))
|
||||
// Len returns the number of networks
|
||||
Len() int
|
||||
// DefaultInterfaceName return the default interface name, this will be suffixed by a number
|
||||
DefaultInterfaceName() string
|
||||
// Network returns the network with the given name or ID.
|
||||
// It returns an error if the network is not found
|
||||
Network(nameOrID string) (*types.Network, error)
|
||||
}
|
||||
34
vendor/github.com/containers/common/libnetwork/internal/util/interfaces.go
generated
vendored
Normal file
34
vendor/github.com/containers/common/libnetwork/internal/util/interfaces.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package util
|
||||
|
||||
import "net"
|
||||
|
||||
// getLiveNetworkSubnets returns a slice of subnets representing what the system
|
||||
// has defined as network interfaces
|
||||
func getLiveNetworkSubnets() ([]*net.IPNet, error) {
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nets := make([]*net.IPNet, 0, len(addrs))
|
||||
for _, address := range addrs {
|
||||
_, n, err := net.ParseCIDR(address.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nets = append(nets, n)
|
||||
}
|
||||
return nets, nil
|
||||
}
|
||||
|
||||
// GetLiveNetworkNames returns a list of network interface names on the system
|
||||
func GetLiveNetworkNames() ([]string, error) {
|
||||
liveInterfaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
interfaceNames := make([]string, 0, len(liveInterfaces))
|
||||
for _, i := range liveInterfaces {
|
||||
interfaceNames = append(interfaceNames, i.Name)
|
||||
}
|
||||
return interfaceNames, nil
|
||||
}
|
||||
70
vendor/github.com/containers/common/libnetwork/internal/util/ip.go
generated
vendored
Normal file
70
vendor/github.com/containers/common/libnetwork/internal/util/ip.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"net"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func incByte(subnet *net.IPNet, idx int, shift uint) error {
|
||||
if idx < 0 {
|
||||
return errors.New("no more subnets left")
|
||||
}
|
||||
if subnet.IP[idx] == 255 {
|
||||
subnet.IP[idx] = 0
|
||||
return incByte(subnet, idx-1, 0)
|
||||
}
|
||||
subnet.IP[idx] += 1 << shift
|
||||
return nil
|
||||
}
|
||||
|
||||
// NextSubnet returns subnet incremented by 1
|
||||
func NextSubnet(subnet *net.IPNet) (*net.IPNet, error) {
|
||||
newSubnet := &net.IPNet{
|
||||
IP: subnet.IP,
|
||||
Mask: subnet.Mask,
|
||||
}
|
||||
ones, bits := newSubnet.Mask.Size()
|
||||
if ones == 0 {
|
||||
return nil, errors.Errorf("%s has only one subnet", subnet.String())
|
||||
}
|
||||
zeroes := uint(bits - ones)
|
||||
shift := zeroes % 8
|
||||
idx := ones/8 - 1
|
||||
if idx < 0 {
|
||||
idx = 0
|
||||
}
|
||||
if err := incByte(newSubnet, idx, shift); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newSubnet, nil
|
||||
}
|
||||
|
||||
func NetworkIntersectsWithNetworks(n *net.IPNet, networklist []*net.IPNet) bool {
|
||||
for _, nw := range networklist {
|
||||
if networkIntersect(n, nw) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func networkIntersect(n1, n2 *net.IPNet) bool {
|
||||
return n2.Contains(n1.IP) || n1.Contains(n2.IP)
|
||||
}
|
||||
|
||||
// getRandomIPv6Subnet returns a random internal ipv6 subnet as described in RFC3879.
|
||||
func getRandomIPv6Subnet() (net.IPNet, error) {
|
||||
ip := make(net.IP, 8, net.IPv6len)
|
||||
// read 8 random bytes
|
||||
_, err := rand.Read(ip)
|
||||
if err != nil {
|
||||
return net.IPNet{}, err
|
||||
}
|
||||
// first byte must be FD as per RFC3879
|
||||
ip[0] = 0xfd
|
||||
// add 8 zero bytes
|
||||
ip = append(ip, make([]byte, 8)...)
|
||||
return net.IPNet{IP: ip, Mask: net.CIDRMask(64, 128)}, nil
|
||||
}
|
||||
37
vendor/github.com/containers/common/libnetwork/internal/util/parse.go
generated
vendored
Normal file
37
vendor/github.com/containers/common/libnetwork/internal/util/parse.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ParseMTU parses the mtu option
|
||||
func ParseMTU(mtu string) (int, error) {
|
||||
if mtu == "" {
|
||||
return 0, nil // default
|
||||
}
|
||||
m, err := strconv.Atoi(mtu)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if m < 0 {
|
||||
return 0, errors.Errorf("mtu %d is less than zero", m)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// ParseVlan parses the vlan option
|
||||
func ParseVlan(vlan string) (int, error) {
|
||||
if vlan == "" {
|
||||
return 0, nil // default
|
||||
}
|
||||
v, err := strconv.Atoi(vlan)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if v < 0 || v > 4094 {
|
||||
return 0, errors.Errorf("vlan ID %d must be between 0 and 4094", v)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
123
vendor/github.com/containers/common/libnetwork/internal/util/util.go
generated
vendored
Normal file
123
vendor/github.com/containers/common/libnetwork/internal/util/util.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/containers/common/libnetwork/types"
|
||||
"github.com/containers/common/pkg/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// GetBridgeInterfaceNames returns all bridge interface names
|
||||
// already used by network configs
|
||||
func GetBridgeInterfaceNames(n NetUtil) []string {
|
||||
names := make([]string, 0, n.Len())
|
||||
n.ForEach(func(net types.Network) {
|
||||
if net.Driver == types.BridgeNetworkDriver {
|
||||
names = append(names, net.NetworkInterface)
|
||||
}
|
||||
})
|
||||
return names
|
||||
}
|
||||
|
||||
// GetUsedNetworkNames returns all network names already used
|
||||
// by network configs
|
||||
func GetUsedNetworkNames(n NetUtil) []string {
|
||||
names := make([]string, 0, n.Len())
|
||||
n.ForEach(func(net types.Network) {
|
||||
if net.Driver == types.BridgeNetworkDriver {
|
||||
names = append(names, net.NetworkInterface)
|
||||
}
|
||||
})
|
||||
return names
|
||||
}
|
||||
|
||||
// GetFreeDeviceName returns a free device name which can
|
||||
// be used for new configs as name and bridge interface name.
|
||||
// The base name is suffixed by a number
|
||||
func GetFreeDeviceName(n NetUtil) (string, error) {
|
||||
bridgeNames := GetBridgeInterfaceNames(n)
|
||||
netNames := GetUsedNetworkNames(n)
|
||||
liveInterfaces, err := GetLiveNetworkNames()
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
names := make([]string, 0, len(bridgeNames)+len(netNames)+len(liveInterfaces))
|
||||
names = append(names, bridgeNames...)
|
||||
names = append(names, netNames...)
|
||||
names = append(names, liveInterfaces...)
|
||||
// FIXME: Is a limit fine?
|
||||
// Start by 1, 0 is reserved for the default network
|
||||
for i := 1; i < 1000000; i++ {
|
||||
deviceName := fmt.Sprintf("%s%d", n.DefaultInterfaceName(), i)
|
||||
if !util.StringInSlice(deviceName, names) {
|
||||
logrus.Debugf("found free device name %s", deviceName)
|
||||
return deviceName, nil
|
||||
}
|
||||
}
|
||||
return "", errors.New("could not find free device name, to many iterations")
|
||||
}
|
||||
|
||||
// GetUsedSubnets returns a list of all used subnets by network
|
||||
// configs and interfaces on the host.
|
||||
func GetUsedSubnets(n NetUtil) ([]*net.IPNet, error) {
|
||||
// first, load all used subnets from network configs
|
||||
subnets := make([]*net.IPNet, 0, n.Len())
|
||||
n.ForEach(func(n types.Network) {
|
||||
for i := range n.Subnets {
|
||||
subnets = append(subnets, &n.Subnets[i].Subnet.IPNet)
|
||||
}
|
||||
})
|
||||
// second, load networks from the current system
|
||||
liveSubnets, err := getLiveNetworkSubnets()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(subnets, liveSubnets...), nil
|
||||
}
|
||||
|
||||
// GetFreeIPv4NetworkSubnet returns a unused ipv4 subnet
|
||||
func GetFreeIPv4NetworkSubnet(usedNetworks []*net.IPNet) (*types.Subnet, error) {
|
||||
// the default podman network is 10.88.0.0/16
|
||||
// start locking for free /24 networks
|
||||
network := &net.IPNet{
|
||||
IP: net.IP{10, 89, 0, 0},
|
||||
Mask: net.IPMask{255, 255, 255, 0},
|
||||
}
|
||||
|
||||
// TODO: make sure to not use public subnets
|
||||
for {
|
||||
if intersectsConfig := NetworkIntersectsWithNetworks(network, usedNetworks); !intersectsConfig {
|
||||
logrus.Debugf("found free ipv4 network subnet %s", network.String())
|
||||
return &types.Subnet{
|
||||
Subnet: types.IPNet{IPNet: *network},
|
||||
}, nil
|
||||
}
|
||||
var err error
|
||||
network, err = NextSubnet(network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetFreeIPv6NetworkSubnet returns a unused ipv6 subnet
|
||||
func GetFreeIPv6NetworkSubnet(usedNetworks []*net.IPNet) (*types.Subnet, error) {
|
||||
// FIXME: Is 10000 fine as limit? We should prevent an endless loop.
|
||||
for i := 0; i < 10000; i++ {
|
||||
// RFC4193: Choose the ipv6 subnet random and NOT sequentially.
|
||||
network, err := getRandomIPv6Subnet()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if intersectsConfig := NetworkIntersectsWithNetworks(&network, usedNetworks); !intersectsConfig {
|
||||
logrus.Debugf("found free ipv6 network subnet %s", network.String())
|
||||
return &types.Subnet{
|
||||
Subnet: types.IPNet{IPNet: network},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("failed to get random ipv6 subnet")
|
||||
}
|
||||
124
vendor/github.com/containers/common/libnetwork/internal/util/validate.go
generated
vendored
Normal file
124
vendor/github.com/containers/common/libnetwork/internal/util/validate.go
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/containers/common/libnetwork/types"
|
||||
"github.com/containers/common/libnetwork/util"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ValidateSubnet will validate a given Subnet. It checks if the
|
||||
// given gateway and lease range are part of this subnet. If the
|
||||
// gateway is empty and addGateway is true it will get the first
|
||||
// available ip in the subnet assigned.
|
||||
func ValidateSubnet(s *types.Subnet, addGateway bool, usedNetworks []*net.IPNet) error {
|
||||
if s == nil {
|
||||
return errors.New("subnet is nil")
|
||||
}
|
||||
if s.Subnet.IP == nil {
|
||||
return errors.New("subnet ip is nil")
|
||||
}
|
||||
|
||||
// Reparse to ensure subnet is valid.
|
||||
// Do not use types.ParseCIDR() because we want the ip to be
|
||||
// the network address and not a random ip in the subnet.
|
||||
_, n, err := net.ParseCIDR(s.Subnet.String())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "subnet invalid")
|
||||
}
|
||||
|
||||
// check that the new subnet does not conflict with existing ones
|
||||
if NetworkIntersectsWithNetworks(n, usedNetworks) {
|
||||
return errors.Errorf("subnet %s is already used on the host or by another config", n.String())
|
||||
}
|
||||
|
||||
s.Subnet = types.IPNet{IPNet: *n}
|
||||
if s.Gateway != nil {
|
||||
if !s.Subnet.Contains(s.Gateway) {
|
||||
return errors.Errorf("gateway %s not in subnet %s", s.Gateway, &s.Subnet)
|
||||
}
|
||||
util.NormalizeIP(&s.Gateway)
|
||||
} else if addGateway {
|
||||
ip, err := util.FirstIPInSubnet(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Gateway = ip
|
||||
}
|
||||
|
||||
if s.LeaseRange != nil {
|
||||
if s.LeaseRange.StartIP != nil {
|
||||
if !s.Subnet.Contains(s.LeaseRange.StartIP) {
|
||||
return errors.Errorf("lease range start ip %s not in subnet %s", s.LeaseRange.StartIP, &s.Subnet)
|
||||
}
|
||||
util.NormalizeIP(&s.LeaseRange.StartIP)
|
||||
}
|
||||
if s.LeaseRange.EndIP != nil {
|
||||
if !s.Subnet.Contains(s.LeaseRange.EndIP) {
|
||||
return errors.Errorf("lease range end ip %s not in subnet %s", s.LeaseRange.EndIP, &s.Subnet)
|
||||
}
|
||||
util.NormalizeIP(&s.LeaseRange.EndIP)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateSubnets will validate the subnets for this network.
|
||||
// It also sets the gateway if the gateway is empty and it sets
|
||||
// IPv6Enabled to true if at least one subnet is ipv6.
|
||||
func ValidateSubnets(network *types.Network, usedNetworks []*net.IPNet) error {
|
||||
for i := range network.Subnets {
|
||||
err := ValidateSubnet(&network.Subnets[i], !network.Internal, usedNetworks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if util.IsIPv6(network.Subnets[i].Subnet.IP) {
|
||||
network.IPv6Enabled = true
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ValidateSetupOptions(n NetUtil, namespacePath string, options types.SetupOptions) error {
|
||||
if namespacePath == "" {
|
||||
return errors.New("namespacePath is empty")
|
||||
}
|
||||
if options.ContainerID == "" {
|
||||
return errors.New("ContainerID is empty")
|
||||
}
|
||||
if len(options.Networks) == 0 {
|
||||
return errors.New("must specify at least one network")
|
||||
}
|
||||
for name, netOpts := range options.Networks {
|
||||
netOpts := netOpts
|
||||
network, err := n.Network(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = validatePerNetworkOpts(network, &netOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validatePerNetworkOpts checks that all given static ips are in a subnet on this network
|
||||
func validatePerNetworkOpts(network *types.Network, netOpts *types.PerNetworkOptions) error {
|
||||
if netOpts.InterfaceName == "" {
|
||||
return errors.Errorf("interface name on network %s is empty", network.Name)
|
||||
}
|
||||
if network.IPAMOptions["driver"] == types.HostLocalIPAMDriver {
|
||||
outer:
|
||||
for _, ip := range netOpts.StaticIPs {
|
||||
for _, s := range network.Subnets {
|
||||
if s.Subnet.Contains(ip) {
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
return errors.Errorf("requested static ip %s not in any subnet on network %s", ip.String(), network.Name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user