Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions libvirt/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func getIPsFromResource(d *schema.ResourceData) ([]libvirtxml.NetworkIP, error)
}

func getNetworkIPConfig(address string) (*libvirtxml.NetworkIP, *libvirtxml.NetworkDHCP, error) {
_, ipNet, err := net.ParseCIDR(address)
ip, ipNet, err := net.ParseCIDR(address)
if err != nil {
return nil, nil, fmt.Errorf("error parsing addresses definition '%s': %w", address, err)
}
Expand All @@ -163,23 +163,26 @@ func getNetworkIPConfig(address string) (*libvirtxml.NetworkIP, *libvirtxml.Netw
return nil, nil, fmt.Errorf("netmask seems to be too strict: only %d IPs available (%s)", availableSubnetIPCount, family)
}

// we should calculate the range served by DHCP. For example, for
// calculate the range served by DHCP. For example, for
// 192.168.121.0/24 we will serve 192.168.121.2 - 192.168.121.254
start, end := networkRange(ipNet)

// skip the .0, (for the network),
// skip the .0, (for the network), and skip the .255 (for broadcast)
start[len(start)-1]++
end[len(end)-1]--

// assign .1 host address iff host address is not given (.0)
if ip.Mask(ipNet.Mask).Equal(ip) {
ip[len(ip)-1] = 1
start[len(start)-1]++ // then skip the .1 too.
}

// assign the .1 to the host interface
dni := &libvirtxml.NetworkIP{
Address: start.String(),
Address: ip.String(),
Prefix: uint(ones),
Family: family,
}

start[len(start)-1]++ // then skip the .1
end[len(end)-1]-- // and skip the .255 (for broadcast)

dhcp := &libvirtxml.NetworkDHCP{
Ranges: []libvirtxml.NetworkDHCPRange{
{
Expand Down
14 changes: 4 additions & 10 deletions libvirt/resource_libvirt_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ func resourceLibvirtNetwork() *schema.Resource {
Elem: &schema.Schema{
Type: schema.TypeString,
},
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
return sameNetworkAddress(old, new)
},
},
"autostart": {
Type: schema.TypeBool,
Expand Down Expand Up @@ -540,20 +543,11 @@ func resourceLibvirtNetworkRead(ctx context.Context, d *schema.ResourceData, met
addresses := []string{}
//nolint:mnd
for _, address := range networkDef.IPs {
// we get the host interface IP (ie, 10.10.8.1) but we want the network CIDR (ie, 10.10.8.0/24)
// so we need some transformations...
addr := net.ParseIP(address.Address)
if addr == nil {
return diag.Errorf("error parsing IP '%s': %s", address.Address, err)
}
bits := net.IPv6len * 8
if addr.To4() != nil {
bits = net.IPv4len * 8
}

mask := net.CIDRMask(int(address.Prefix), bits)
network := addr.Mask(mask)
addresses = append(addresses, fmt.Sprintf("%s/%d", network, address.Prefix))
addresses = append(addresses, fmt.Sprintf("%s/%d", addr, address.Prefix))
}
if len(addresses) > 0 {
d.Set("addresses", addresses)
Expand Down
4 changes: 2 additions & 2 deletions libvirt/resource_libvirt_network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ func TestAccLibvirtNetwork_Addresses(t *testing.T) {
resource "libvirt_network" "%s" {
name = "%s"
domain = "k8s.local"
addresses = ["10.17.3.0/24"]
addresses = ["10.17.3.1/24"]
}`, randomNetworkResource, randomNetworkName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(randomNetworkResourceFull,
"addresses.0", "10.17.3.0/24"),
"addresses.0", "10.17.3.1/24"),
resource.TestCheckResourceAttr(randomNetworkResourceFull,
"mode", "nat"),
),
Expand Down
14 changes: 14 additions & 0 deletions libvirt/utils_net.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"crypto/rand"
"fmt"
"net"
"strings"
)

// randomMACAddress returns a randomized MAC address
Expand Down Expand Up @@ -70,3 +71,16 @@ func networkRange(network *net.IPNet) (firstIP net.IP, lastIP net.IP) {

return netIP.Mask(network.Mask), getLastIP(network, netIP)
}

// sameNetworkAddress returns true if both input strings (in addr/netmask format)
// have the same network address
func sameNetworkAddress(a, b string) bool {
_, netA, errA := net.ParseCIDR(strings.TrimSpace(a))
_, netB, errB := net.ParseCIDR(strings.TrimSpace(b))

if errA != nil || errB != nil {
return false // if either can't be parsed, treat as different
}

return netA.IP.Equal(netB.IP) && netA.Mask.String() == netB.Mask.String()
}