Add option to ignore duplicate bridge use detection

pull/20/head
Jack O'Sullivan 3 years ago
parent 4f9e4aa925
commit afe690fe93

@ -50,52 +50,54 @@ func (p *Plugin) CreateNetwork(r CreateNetworkRequest) error {
return util.ErrNotBridge
}
v4Addrs, err := netlink.AddrList(link, unix.AF_INET)
if err != nil {
return fmt.Errorf("failed to retrieve IPv4 addresses for %v: %w", opts.Bridge, err)
}
v6Addrs, err := netlink.AddrList(link, unix.AF_INET6)
if err != nil {
return fmt.Errorf("failed to retrieve IPv6 addresses for %v: %w", opts.Bridge, err)
}
bridgeAddrs := append(v4Addrs, v6Addrs...)
nets, err := p.docker.NetworkList(context.Background(), dTypes.NetworkListOptions{})
if err != nil {
return fmt.Errorf("failed to retrieve list of networks from Docker: %w", err)
}
// Make sure the addresses on this bridge aren't used by another network
for _, n := range nets {
if IsDHCPPlugin(n.Driver) {
otherOpts, err := decodeOpts(n.Options)
if err != nil {
log.
WithField("network", n.Name).
WithError(err).
Warn("Failed to parse other DHCP network's options")
} else if otherOpts.Bridge == opts.Bridge {
return util.ErrBridgeUsed
}
if !opts.IgnoreConflicts {
v4Addrs, err := netlink.AddrList(link, unix.AF_INET)
if err != nil {
return fmt.Errorf("failed to retrieve IPv4 addresses for %v: %w", opts.Bridge, err)
}
if n.IPAM.Driver == "null" {
// Null driver networks will have 0.0.0.0/0 which covers any address range!
continue
v6Addrs, err := netlink.AddrList(link, unix.AF_INET6)
if err != nil {
return fmt.Errorf("failed to retrieve IPv6 addresses for %v: %w", opts.Bridge, err)
}
bridgeAddrs := append(v4Addrs, v6Addrs...)
for _, c := range n.IPAM.Config {
_, dockerCIDR, err := net.ParseCIDR(c.Subnet)
if err != nil {
return fmt.Errorf("failed to parse subnet %v on Docker network %v: %w", c.Subnet, n.ID, err)
nets, err := p.docker.NetworkList(context.Background(), dTypes.NetworkListOptions{})
if err != nil {
return fmt.Errorf("failed to retrieve list of networks from Docker: %w", err)
}
// Make sure the addresses on this bridge aren't used by another network
for _, n := range nets {
if IsDHCPPlugin(n.Driver) {
otherOpts, err := decodeOpts(n.Options)
if err != nil {
log.
WithField("network", n.Name).
WithError(err).
Warn("Failed to parse other DHCP network's options")
} else if otherOpts.Bridge == opts.Bridge {
return util.ErrBridgeUsed
}
}
if bytes.Equal(dockerCIDR.Mask, net.CIDRMask(0, 32)) || bytes.Equal(dockerCIDR.Mask, net.CIDRMask(0, 128)) {
// Last check to make sure the network isn't 0.0.0.0/0 or ::/0 (which would always pass the check below)
if n.IPAM.Driver == "null" {
// Null driver networks will have 0.0.0.0/0 which covers any address range!
continue
}
for _, bridgeAddr := range bridgeAddrs {
if bridgeAddr.IPNet.Contains(dockerCIDR.IP) || dockerCIDR.Contains(bridgeAddr.IP) {
return util.ErrBridgeUsed
for _, c := range n.IPAM.Config {
_, dockerCIDR, err := net.ParseCIDR(c.Subnet)
if err != nil {
return fmt.Errorf("failed to parse subnet %v on Docker network %v: %w", c.Subnet, n.ID, err)
}
if bytes.Equal(dockerCIDR.Mask, net.CIDRMask(0, 32)) || bytes.Equal(dockerCIDR.Mask, net.CIDRMask(0, 128)) {
// Last check to make sure the network isn't 0.0.0.0/0 or ::/0 (which would always pass the check below)
continue
}
for _, bridgeAddr := range bridgeAddrs {
if bridgeAddr.IPNet.Contains(dockerCIDR.IP) || dockerCIDR.Contains(bridgeAddr.IP) {
return util.ErrBridgeUsed
}
}
}
}

@ -29,9 +29,10 @@ func IsDHCPPlugin(driver string) bool {
// DHCPNetworkOptions contains options for the DHCP network driver
type DHCPNetworkOptions struct {
Bridge string
IPv6 bool
LeaseTimeout time.Duration `mapstructure:"lease_timeout"`
Bridge string
IPv6 bool
LeaseTimeout time.Duration `mapstructure:"lease_timeout"`
IgnoreConflicts bool `mapstructure:"ignore_conflicts"`
}
func decodeOpts(input interface{}) (DHCPNetworkOptions, error) {

Loading…
Cancel
Save