diff --git a/doc/api-extensions.md b/doc/api-extensions.md index fbd64eded03..b58b23749db 100644 --- a/doc/api-extensions.md +++ b/doc/api-extensions.md @@ -2744,3 +2744,7 @@ This allows specifying IPv4 and IPv6 DNS server addresses to be announced by the ## `acme_http01_port` Adds `acme.http.port` to control an alternative HTTP port for `HTTP-01` validation. + +## `network_ovn_ipv4_dhcp_expiry` + +Introduces `ipv4.dhcp.expiry` for OVN networks. diff --git a/doc/reference/network_ovn.md b/doc/reference/network_ovn.md index b051e771381..fff61ff7238 100644 --- a/doc/reference/network_ovn.md +++ b/doc/reference/network_ovn.md @@ -53,6 +53,7 @@ Key | Type | Condition | Defau `dns.zone.reverse.ipv6` | string | - | - | DNS zone name for IPv6 reverse DNS records `ipv4.address` | string | standard mode | - (initial value on creation: `auto`) | IPv4 address for the bridge (use `none` to turn off IPv4 or `auto` to generate a new random unused subnet) (CIDR) `ipv4.dhcp` | bool | IPv4 address | `true` | Whether to allocate addresses using DHCP +`ipv4.dhcp.expiry` | string | IPv4 DHCP | `1h` | When to expire DHCP leases `ipv4.dhcp.routes` | string | IPv4 DHCP | - | Static routes to provide via DHCP option 121, as a comma-separated list of alternating subnets (CIDR) and gateway addresses (same syntax as dnsmasq and OVN) `ipv4.l3only` | bool | IPv4 address | `false` | Whether to enable layer 3 only mode. `ipv4.nat` | bool | IPv4 address | `false` (initial value on creation if `ipv4.address` is set to `auto`: `true`) | Whether to NAT diff --git a/internal/server/network/driver_ovn.go b/internal/server/network/driver_ovn.go index 86cc67d35b8..99dbf6a8ee7 100644 --- a/internal/server/network/driver_ovn.go +++ b/internal/server/network/driver_ovn.go @@ -398,7 +398,11 @@ func (n *ovn) Validate(config map[string]string) error { return validate.IsNetworkAddressCIDRV4(value) }), - "ipv4.dhcp": validate.Optional(validate.IsBool), + "ipv4.dhcp": validate.Optional(validate.IsBool), + "ipv4.dhcp.expiry": validate.Optional(func(value string) error { + _, err := time.ParseDuration(value) + return err + }), "ipv4.dhcp.ranges": validate.Optional(validate.IsListOf(validate.IsNetworkRangeV4)), "ipv4.dhcp.routes": validate.Optional(validate.IsDHCPRouteList), "ipv6.address": validate.Optional(func(value string) error { @@ -2675,12 +2679,22 @@ func (n *ovn) setup(update bool) error { dhcpV4Netmask = "255.255.255.255" } + leaseTime := time.Hour * 1 + if n.config["ipv4.dhcp.expiry"] != "" { + duration, err := time.ParseDuration(n.config["ipv4.dhcp.expiry"]) + if err != nil { + return fmt.Errorf("Failed to parse expiry: %w", err) + } + + leaseTime = duration + } + opts := &networkOVN.OVNDHCPv4Opts{ ServerID: routerIntPortIPv4, ServerMAC: routerMAC, Router: routerIntPortIPv4, DomainName: n.getDomainName(), - LeaseTime: time.Duration(time.Hour * 1), + LeaseTime: leaseTime, MTU: bridgeMTU, Netmask: dhcpV4Netmask, DNSSearchList: n.getDNSSearchList(), diff --git a/internal/version/api.go b/internal/version/api.go index 47549f93c34..8a11fa8b702 100644 --- a/internal/version/api.go +++ b/internal/version/api.go @@ -470,6 +470,7 @@ var APIExtensions = []string{ "network_state_ovn_ls", "network_dns_nameservers", "acme_http01_port", + "network_ovn_ipv4_dhcp_expiry", } // APIExtensionsCount returns the number of available API extensions.