1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
package util
import (
"errors"
"fmt"
"net"
"slices"
"github.com/containers/common/libnetwork/types"
"github.com/containers/common/pkg/config"
"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) {
names = append(names, net.Name)
})
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 !slices.Contains(names, deviceName) {
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, subnetPools []config.SubnetPool) (*types.Subnet, error) {
var err error
for _, pool := range subnetPools {
// make sure to copy the netip to prevent overwriting the subnet pool
netIP := make(net.IP, net.IPv4len)
copy(netIP, pool.Base.IP)
network := &net.IPNet{
IP: netIP,
Mask: net.CIDRMask(pool.Size, 32),
}
for pool.Base.Contains(network.IP) {
if !NetworkIntersectsWithNetworks(network, usedNetworks) {
logrus.Debugf("found free ipv4 network subnet %s", network.String())
return &types.Subnet{
Subnet: types.IPNet{IPNet: *network},
}, nil
}
network, err = NextSubnet(network)
if err != nil {
// when error go to next pool, we return the error only when all pools are done
break
}
}
}
if err != nil {
return nil, err
}
return nil, errors.New("could not find free subnet from subnet pools")
}
// 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 range 10000 {
// 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")
}
// Map docker driver network options to podman network options
func MapDockerBridgeDriverOptions(n *types.Network) {
// validate the given options
for key, value := range n.Options {
switch key {
case "com.docker.network.driver.mtu":
n.Options[types.MTUOption] = value
delete(n.Options, "com.docker.network.driver.mtu")
case "com.docker.network.bridge.name":
n.NetworkInterface = value
delete(n.Options, "com.docker.network.bridge.name")
}
}
}
|