If an user is trying to configure a dhcp neetwork settings, it is not
possible to change the leasetime of a range or a host entry. This is
available using dnsmasq extra options, but they are associated with
dhcp-range or dhcp-hosts fields. This patch implements a leasetime for
range and hosts tags. They can be defined under that settings:
<dhcp>
<range ...>
<lease/>
</range>
<host ...>
<lease/>
</host>
</dhcp>
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=913446
Signed-off-by: Julio Faracco <jcfaracco@gmail.com>
---
docs/schemas/basictypes.rng | 8 ++
docs/schemas/network.rng | 20 +++++
src/conf/network_conf.c | 159 +++++++++++++++++++++++++++++++-----
src/conf/network_conf.h | 27 +++++-
src/libvirt_private.syms | 3 +
src/network/bridge_driver.c | 56 +++++++++++--
src/network/bridge_driver.h | 1 +
src/test/test_driver.c | 2 +-
src/util/virdnsmasq.c | 68 ++++++++++-----
src/util/virdnsmasq.h | 3 +
src/vbox/vbox_network.c | 16 ++--
11 files changed, 305 insertions(+), 58 deletions(-)
diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
index 81465273c8..271ed18afb 100644
--- a/docs/schemas/basictypes.rng
+++ b/docs/schemas/basictypes.rng
@@ -607,4 +607,12 @@
</element>
</define>
+ <define name="leaseUnit">
+ <choice>
+ <value>seconds</value>
+ <value>mins</value>
+ <value>hours</value>
+ </choice>
+ </define>
+
</grammar>
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index 60453225d6..88b6f4dfdd 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -371,6 +371,16 @@
<element name="range">
<attribute name="start"><ref name="ipAddr"/></attribute>
<attribute name="end"><ref name="ipAddr"/></attribute>
+ <interleave>
+ <optional>
+ <element name="lease">
+ <attribute name="expiry"><ref name="unsignedLong"/></attribute>
+ <optional>
+ <attribute name="unit"><ref name="leaseUnit"/></attribute>
+ </optional>
+ </element>
+ </optional>
+ </interleave>
</element>
</zeroOrMore>
<zeroOrMore>
@@ -388,6 +398,16 @@
<attribute name="name"><text/></attribute>
</choice>
<attribute name="ip"><ref name="ipAddr"/></attribute>
+ <interleave>
+ <optional>
+ <element name="lease">
+ <attribute name="expiry"><ref name="unsignedLong"/></attribute>
+ <optional>
+ <attribute name="unit"><ref name="leaseUnit"/></attribute>
+ </optional>
+ </element>
+ </optional>
+ </interleave>
</element>
</zeroOrMore>
<optional>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 819b645df7..286a0edb7c 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -70,6 +70,13 @@ VIR_ENUM_IMPL(virNetworkTaint,
"hook-script",
);
+VIR_ENUM_IMPL(virNetworkDHCPLeaseTimeUnit,
+ VIR_NETWORK_DHCP_LEASETIME_UNIT_LAST,
+ "seconds",
+ "mins",
+ "hours",
+);
+
static virClassPtr virNetworkXMLOptionClass;
static void
@@ -132,12 +139,20 @@ virNetworkForwardPfDefClear(virNetworkForwardPfDefPtr def)
}
+static void
+virNetworkDHCPLeaseTimeDefClear(virNetworkDHCPLeaseTimeDefPtr lease)
+{
+ VIR_FREE(lease);
+}
+
+
static void
virNetworkDHCPHostDefClear(virNetworkDHCPHostDefPtr def)
{
VIR_FREE(def->mac);
VIR_FREE(def->id);
VIR_FREE(def->name);
+ VIR_FREE(def->lease);
}
@@ -145,6 +160,9 @@ static void
virNetworkIPDefClear(virNetworkIPDefPtr def)
{
VIR_FREE(def->family);
+
+ while (def->nranges)
+ virNetworkDHCPLeaseTimeDefClear(def->ranges[--def->nranges].lease);
VIR_FREE(def->ranges);
while (def->nhosts)
@@ -391,11 +409,55 @@ int virNetworkIPDefNetmask(const virNetworkIPDef *def,
static int
-virSocketAddrRangeParseXML(const char *networkName,
- virNetworkIPDefPtr ipdef,
- xmlNodePtr node,
- virSocketAddrRangePtr range)
+virNetworkDHCPLeaseTimeDefParseXML(virNetworkDHCPLeaseTimeDefPtr *lease,
+ xmlNodePtr node)
+{
+ virNetworkDHCPLeaseTimeDefPtr new_lease = *lease;
+ g_autofree char *expiry = NULL, *unit = NULL;
+
+ if (!(expiry = virXMLPropString(node, "expiry")))
+ return 0;
+
+ if (VIR_ALLOC(new_lease) < 0)
+ return -1;
+
+ if (virStrToLong_ul(expiry, NULL, 10, &new_lease->expiry) < 0)
+ return -1;
+
+ if (!(unit = virXMLPropString(node, "unit")))
+ new_lease->unit = VIR_NETWORK_DHCP_LEASETIME_UNIT_MINUTES;
+ else
+ new_lease->unit = virNetworkDHCPLeaseTimeUnitTypeFromString(unit);
+
+ /* infinite */
+ if (new_lease->expiry > 0) {
+ /* This boundary check is related to dnsmasq man page settings:
+ * "The minimum lease time is two minutes." */
+ if ((new_lease->unit == VIR_NETWORK_DHCP_LEASETIME_UNIT_SECONDS &&
+ new_lease->expiry < 120) ||
+ (new_lease->unit == VIR_NETWORK_DHCP_LEASETIME_UNIT_MINUTES &&
+ new_lease->expiry < 2)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("The minimum lease time should be greater "
+ "than 2 minutes"));
+ return -1;
+ }
+ }
+
+ *lease = new_lease;
+
+ return 0;
+}
+
+
+static int
+virNetworkDHCPRangeDefParseXML(const char *networkName,
+ virNetworkIPDefPtr ipdef,
+ xmlNodePtr node,
+ virNetworkDHCPRangeDefPtr range)
{
+ virSocketAddrRangePtr addr = &range->addr;
+ xmlNodePtr cur = node->children;
char *start = NULL, *end = NULL;
int ret = -1;
@@ -405,7 +467,7 @@ virSocketAddrRangeParseXML(const char *networkName,
networkName);
goto cleanup;
}
- if (virSocketAddrParse(&range->start, start, AF_UNSPEC) < 0)
+ if (virSocketAddrParse(&addr->start, start, AF_UNSPEC) < 0)
goto cleanup;
if (!(end = virXMLPropString(node, "end"))) {
@@ -414,14 +476,24 @@ virSocketAddrRangeParseXML(const char *networkName,
networkName);
goto cleanup;
}
- if (virSocketAddrParse(&range->end, end, AF_UNSPEC) < 0)
+ if (virSocketAddrParse(&addr->end, end, AF_UNSPEC) < 0)
goto cleanup;
/* do a sanity check of the range */
- if (virSocketAddrGetRange(&range->start, &range->end, &ipdef->address,
+ if (virSocketAddrGetRange(&addr->start, &addr->end, &ipdef->address,
virNetworkIPDefPrefix(ipdef)) < 0)
goto cleanup;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE &&
+ virXMLNodeNameEqual(cur, "lease")) {
+
+ if (virNetworkDHCPLeaseTimeDefParseXML(&range->lease, cur) < 0)
+ goto cleanup;
+ }
+ cur = cur->next;
+ }
+
ret = 0;
cleanup:
@@ -441,6 +513,7 @@ virNetworkDHCPHostDefParseXML(const char *networkName,
char *mac = NULL, *name = NULL, *ip = NULL, *id = NULL;
virMacAddr addr;
virSocketAddr inaddr;
+ xmlNodePtr cur = node->children;
int ret = -1;
mac = virXMLPropString(node, "mac");
@@ -533,6 +606,16 @@ virNetworkDHCPHostDefParseXML(const char *networkName,
}
}
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE &&
+ virXMLNodeNameEqual(cur, "lease")) {
+
+ if (virNetworkDHCPLeaseTimeDefParseXML(&host->lease, cur) < 0)
+ goto cleanup;
+ }
+ cur = cur->next;
+ }
+
host->mac = mac;
mac = NULL;
host->id = id;
@@ -559,7 +642,7 @@ virNetworkDHCPDefParseXML(const char *networkName,
{
int ret = -1;
xmlNodePtr cur;
- virSocketAddrRange range;
+ virNetworkDHCPRangeDef range;
virNetworkDHCPHostDef host;
memset(&range, 0, sizeof(range));
@@ -570,7 +653,7 @@ virNetworkDHCPDefParseXML(const char *networkName,
if (cur->type == XML_ELEMENT_NODE &&
virXMLNodeNameEqual(cur, "range")) {
- if (virSocketAddrRangeParseXML(networkName, def, cur, &range) < 0)
+ if (virNetworkDHCPRangeDefParseXML(networkName, def, cur, &range) < 0)
goto cleanup;
if (VIR_APPEND_ELEMENT(def->ranges, def->nranges, range) < 0)
goto cleanup;
@@ -583,7 +666,6 @@ virNetworkDHCPDefParseXML(const char *networkName,
goto cleanup;
if (VIR_APPEND_ELEMENT(def->hosts, def->nhosts, host) < 0)
goto cleanup;
-
} else if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET) &&
cur->type == XML_ELEMENT_NODE &&
virXMLNodeNameEqual(cur, "bootp")) {
@@ -2300,20 +2382,39 @@ virNetworkIPDefFormat(virBufferPtr buf,
virBufferAdjustIndent(buf, 2);
for (i = 0; i < def->nranges; i++) {
- char *saddr = virSocketAddrFormat(&def->ranges[i].start);
+ virSocketAddrRange addr = def->ranges[i].addr;
+ virNetworkDHCPLeaseTimeDefPtr lease = def->ranges[i].lease;
+
+ char *saddr = virSocketAddrFormat(&addr.start);
if (!saddr)
return -1;
- char *eaddr = virSocketAddrFormat(&def->ranges[i].end);
+ char *eaddr = virSocketAddrFormat(&addr.end);
if (!eaddr) {
VIR_FREE(saddr);
return -1;
}
- virBufferAsprintf(buf, "<range start='%s' end='%s'/>\n",
+ virBufferAsprintf(buf, "<range start='%s' end='%s'",
saddr, eaddr);
+ if (lease) {
+ virBufferAddLit(buf, ">\n");
+ virBufferAdjustIndent(buf, 2);
+ if (!lease->expiry) {
+ virBufferAddLit(buf, "<lease expiry='0'/>\n");
+ } else {
+ virBufferAsprintf(buf, "<lease expiry='%lu' unit='%s'/>\n",
+ lease->expiry,
+ virNetworkDHCPLeaseTimeUnitTypeToString(lease->unit));
+ }
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</range>\n");
+ } else {
+ virBufferAddLit(buf, "/>\n");
+ }
VIR_FREE(saddr);
VIR_FREE(eaddr);
}
for (i = 0; i < def->nhosts; i++) {
+ virNetworkDHCPLeaseTimeDefPtr lease = def->hosts[i].lease;
virBufferAddLit(buf, "<host");
if (def->hosts[i].mac)
virBufferAsprintf(buf, " mac='%s'", def->hosts[i].mac);
@@ -2328,7 +2429,21 @@ virNetworkIPDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, " ip='%s'", ipaddr);
VIR_FREE(ipaddr);
}
- virBufferAddLit(buf, "/>\n");
+ if (lease) {
+ virBufferAddLit(buf, ">\n");
+ virBufferAdjustIndent(buf, 2);
+ if (!lease->expiry) {
+ virBufferAddLit(buf, "<lease expiry='0'/>\n");
+ } else {
+ virBufferAsprintf(buf, "<lease expiry='%lu' unit='%s'/>\n",
+ lease->expiry,
+ virNetworkDHCPLeaseTimeUnitTypeToString(lease->unit));
+ }
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</host>\n");
+ } else {
+ virBufferAddLit(buf, "/>\n");
+ }
}
if (def->bootfile) {
virBufferEscapeString(buf, "<bootp file='%s'",
@@ -2343,7 +2458,6 @@ virNetworkIPDefFormat(virBufferPtr buf,
virBufferAddLit(buf, "/>\n");
}
-
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</dhcp>\n");
}
@@ -3080,7 +3194,7 @@ virNetworkDefUpdateIPDHCPRange(virNetworkDefPtr def,
{
size_t i;
virNetworkIPDefPtr ipdef = virNetworkIPDefByIndex(def, parentIndex);
- virSocketAddrRange range;
+ virNetworkDHCPRangeDef range;
memset(&range, 0, sizeof(range));
@@ -3100,11 +3214,11 @@ virNetworkDefUpdateIPDHCPRange(virNetworkDefPtr def,
return -1;
}
- if (virSocketAddrRangeParseXML(def->name, ipdef, ctxt->node, &range) < 0)
+ if (virNetworkDHCPRangeDefParseXML(def->name, ipdef, ctxt->node, &range) < 0)
return -1;
if (VIR_SOCKET_ADDR_FAMILY(&ipdef->address)
- != VIR_SOCKET_ADDR_FAMILY(&range.start)) {
+ != VIR_SOCKET_ADDR_FAMILY(&range.addr.start)) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("the address family of a dhcp range must match "
"the address family of the dhcp element's parent"));
@@ -3113,8 +3227,9 @@ virNetworkDefUpdateIPDHCPRange(virNetworkDefPtr def,
/* check if an entry with same name/address/ip already exists */
for (i = 0; i < ipdef->nranges; i++) {
- if (virSocketAddrEqual(&range.start, &ipdef->ranges[i].start) &&
- virSocketAddrEqual(&range.end, &ipdef->ranges[i].end)) {
+ virSocketAddrRange addr = ipdef->ranges[i].addr;
+ if (virSocketAddrEqual(&range.addr.start, &addr.start) &&
+ virSocketAddrEqual(&range.addr.end, &addr.end)) {
break;
}
}
@@ -3126,8 +3241,8 @@ virNetworkDefUpdateIPDHCPRange(virNetworkDefPtr def,
return -1;
if (i < ipdef->nranges) {
- char *startip = virSocketAddrFormat(&range.start);
- char *endip = virSocketAddrFormat(&range.end);
+ char *startip = virSocketAddrFormat(&range.addr.start);
+ char *endip = virSocketAddrFormat(&range.addr.end);
virReportError(VIR_ERR_OPERATION_INVALID,
_("there is an existing dhcp range entry in "
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index db7243eef5..f2dc388ef0 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -80,6 +80,16 @@ typedef enum {
VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_LAST,
} virNetworkForwardHostdevDeviceType;
+typedef enum {
+ VIR_NETWORK_DHCP_LEASETIME_UNIT_SECONDS = 0,
+ VIR_NETWORK_DHCP_LEASETIME_UNIT_MINUTES,
+ VIR_NETWORK_DHCP_LEASETIME_UNIT_HOURS,
+
+ VIR_NETWORK_DHCP_LEASETIME_UNIT_LAST,
+} virNetworkDHCPLeaseTimeUnitType;
+
+VIR_ENUM_DECL(virNetworkDHCPLeaseTimeUnit);
+
/* The backend driver used for devices from the pool. Currently used
* only for PCI devices (vfio vs. kvm), but could be used for other
* device types in the future.
@@ -94,6 +104,20 @@ typedef enum {
VIR_ENUM_DECL(virNetworkForwardDriverName);
+typedef struct _virNetworkDHCPLeaseTimeDef virNetworkDHCPLeaseTimeDef;
+typedef virNetworkDHCPLeaseTimeDef *virNetworkDHCPLeaseTimeDefPtr;
+struct _virNetworkDHCPLeaseTimeDef {
+ unsigned long expiry;
+ virNetworkDHCPLeaseTimeUnitType unit;
+};
+
+typedef struct _virNetworkDHCPRangeDef virNetworkDHCPRangeDef;
+typedef virNetworkDHCPRangeDef *virNetworkDHCPRangeDefPtr;
+struct _virNetworkDHCPRangeDef {
+ virSocketAddrRange addr;
+ virNetworkDHCPLeaseTimeDefPtr lease;
+};
+
typedef struct _virNetworkDHCPHostDef virNetworkDHCPHostDef;
typedef virNetworkDHCPHostDef *virNetworkDHCPHostDefPtr;
struct _virNetworkDHCPHostDef {
@@ -101,6 +125,7 @@ struct _virNetworkDHCPHostDef {
char *id;
char *name;
virSocketAddr ip;
+ virNetworkDHCPLeaseTimeDefPtr lease;
};
typedef struct _virNetworkDNSTxtDef virNetworkDNSTxtDef;
@@ -171,7 +196,7 @@ struct _virNetworkIPDef {
int localPTR; /* virTristateBool */
size_t nranges; /* Zero or more dhcp ranges */
- virSocketAddrRangePtr ranges;
+ virNetworkDHCPRangeDefPtr ranges;
size_t nhosts; /* Zero or more dhcp hosts */
virNetworkDHCPHostDefPtr hosts;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 182a570382..b7e18c146d 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -770,6 +770,8 @@ virNetworkDefParseNode;
virNetworkDefParseString;
virNetworkDefParseXML;
virNetworkDefUpdateSection;
+virNetworkDHCPLeaseTimeUnitTypeFromString;
+virNetworkDHCPLeaseTimeUnitTypeToString;
virNetworkForwardTypeToString;
virNetworkIPDefNetmask;
virNetworkIPDefPrefix;
@@ -1948,6 +1950,7 @@ dnsmasqCapsRefresh;
dnsmasqContextFree;
dnsmasqContextNew;
dnsmasqDelete;
+dnsmasqDhcpHostsToString;
dnsmasqReload;
dnsmasqSave;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index f06099297a..db17e6b2fd 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -966,6 +966,30 @@ static int networkConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED)
}
+static char *
+networkBuildDnsmasqLeaseTime(virNetworkDHCPLeaseTimeDefPtr lease)
+{
+ char *leasetime = NULL;
+ const char *unit;
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+ if (!lease)
+ return NULL;
+
+ if (lease->expiry == 0) {
+ virBufferAddLit(&buf, "infinite");
+ } else {
+ unit = virNetworkDHCPLeaseTimeUnitTypeToString(lease->unit);
+ /* We get only first compatible char from string: 's', 'm' or 'h' */
+ virBufferAsprintf(&buf, "%lu%c", lease->expiry, unit[0]);
+ }
+
+ leasetime = virBufferContentAndReset(&buf);
+
+ return leasetime;
+}
+
+
/* the following does not build a file, it builds a list
* which is later saved into a file
*/
@@ -975,14 +999,18 @@ networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
{
size_t i;
bool ipv6 = false;
+ g_autofree char *leasetime = NULL;
if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
ipv6 = true;
for (i = 0; i < ipdef->nhosts; i++) {
virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
+
+ leasetime = networkBuildDnsmasqLeaseTime(host->lease);
if (VIR_SOCKET_ADDR_VALID(&host->ip))
if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
- host->name, host->id, ipv6) < 0)
+ host->name, host->id, leasetime,
+ ipv6) < 0)
return -1;
}
@@ -1052,6 +1080,7 @@ int
networkDnsmasqConfContents(virNetworkObjPtr obj,
const char *pidfile,
char **configstr,
+ char **hostsfilestr,
dnsmasqContext *dctx,
dnsmasqCapsPtr caps G_GNUC_UNUSED)
{
@@ -1381,13 +1410,15 @@ networkDnsmasqConfContents(virNetworkObjPtr obj,
}
for (r = 0; r < ipdef->nranges; r++) {
int thisRange;
+ virNetworkDHCPRangeDef range = ipdef->ranges[r];
+ g_autofree char *leasetime = NULL;
- if (!(saddr = virSocketAddrFormat(&ipdef->ranges[r].start)) ||
- !(eaddr = virSocketAddrFormat(&ipdef->ranges[r].end)))
+ if (!(saddr = virSocketAddrFormat(&range.addr.start)) ||
+ !(eaddr = virSocketAddrFormat(&range.addr.end)))
goto cleanup;
if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) {
- virBufferAsprintf(&configbuf, "dhcp-range=%s,%s,%d\n",
+ virBufferAsprintf(&configbuf, "dhcp-range=%s,%s,%d",
saddr, eaddr, prefix);
} else {
/* IPv4 - dnsmasq requires a netmask rather than prefix */
@@ -1404,14 +1435,19 @@ networkDnsmasqConfContents(virNetworkObjPtr obj,
if (!(netmaskStr = virSocketAddrFormat(&netmask)))
goto cleanup;
- virBufferAsprintf(&configbuf, "dhcp-range=%s,%s,%s\n",
+ virBufferAsprintf(&configbuf, "dhcp-range=%s,%s,%s",
saddr, eaddr, netmaskStr);
}
+ if ((leasetime = networkBuildDnsmasqLeaseTime(range.lease)))
+ virBufferAsprintf(&configbuf, ",%s", leasetime);
+
+ virBufferAddLit(&configbuf, "\n");
+
VIR_FREE(saddr);
VIR_FREE(eaddr);
- thisRange = virSocketAddrGetRange(&ipdef->ranges[r].start,
- &ipdef->ranges[r].end,
+ thisRange = virSocketAddrGetRange(&range.addr.start,
+ &range.addr.end,
&ipdef->address,
virNetworkIPDefPrefix(ipdef));
if (thisRange < 0)
@@ -1440,6 +1476,9 @@ networkDnsmasqConfContents(virNetworkObjPtr obj,
if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
goto cleanup;
+ *hostsfilestr = dnsmasqDhcpHostsToString(dctx->hostsfile->hosts,
+ dctx->hostsfile->nhosts);
+
/* Note: the following is IPv4 only */
if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
if (ipdef->nranges || ipdef->nhosts) {
@@ -1549,11 +1588,12 @@ networkBuildDhcpDaemonCommandLine(virNetworkDriverStatePtr driver,
int ret = -1;
char *configfile = NULL;
char *configstr = NULL;
+ char *hostsfilestr = NULL;
char *leaseshelper_path = NULL;
virNetworkObjSetDnsmasqPid(obj, -1);
- if (networkDnsmasqConfContents(obj, pidfile, &configstr,
+ if (networkDnsmasqConfContents(obj, pidfile, &configstr, &hostsfilestr,
dctx, dnsmasq_caps) < 0)
goto cleanup;
if (!configstr)
diff --git a/src/network/bridge_driver.h b/src/network/bridge_driver.h
index d35850d293..fb0ccad4b1 100644
--- a/src/network/bridge_driver.h
+++ b/src/network/bridge_driver.h
@@ -46,5 +46,6 @@ int
networkDnsmasqConfContents(virNetworkObjPtr obj,
const char *pidfile,
char **configstr,
+ char **hostsfilestr,
dnsmasqContext *dctx,
dnsmasqCapsPtr caps);
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index 7759847c2d..0506147888 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -5025,7 +5025,7 @@ testDomainInterfaceAddressFromNet(testDriverPtr driver,
net_def->ips->prefix);
if (net_def->ips->nranges > 0)
- addr = net_def->ips->ranges[0].start;
+ addr = net_def->ips->ranges[0].addr.start;
else
addr = net_def->ips->address;
diff --git a/src/util/virdnsmasq.c b/src/util/virdnsmasq.c
index adc6f96bb6..ee4c458290 100644
--- a/src/util/virdnsmasq.c
+++ b/src/util/virdnsmasq.c
@@ -296,11 +296,14 @@ hostsfileAdd(dnsmasqHostsfile *hostsfile,
virSocketAddr *ip,
const char *name,
const char *id,
+ const char *leasetime,
bool ipv6)
{
- char *ipstr = NULL;
+ g_autofree char *ipstr = NULL;
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
if (VIR_REALLOC_N(hostsfile->hosts, hostsfile->nhosts + 1) < 0)
- goto error;
+ return -1;
if (!(ipstr = virSocketAddrFormat(ip)))
return -1;
@@ -308,34 +311,30 @@ hostsfileAdd(dnsmasqHostsfile *hostsfile,
/* the first test determines if it is a dhcpv6 host */
if (ipv6) {
if (name && id) {
- hostsfile->hosts[hostsfile->nhosts].host = g_strdup_printf("id:%s,%s,[%s]",
- id, name, ipstr);
+ virBufferAsprintf(&buf, "id:%s,%s", id, name);
} else if (name && !id) {
- hostsfile->hosts[hostsfile->nhosts].host = g_strdup_printf("%s,[%s]",
- name, ipstr);
+ virBufferAsprintf(&buf, "%s", name);
} else if (!name && id) {
- hostsfile->hosts[hostsfile->nhosts].host = g_strdup_printf("id:%s,[%s]",
- id, ipstr);
+ virBufferAsprintf(&buf, "id:%s", id);
}
+ virBufferAsprintf(&buf, ",[%s]", ipstr);
} else if (name && mac) {
- hostsfile->hosts[hostsfile->nhosts].host = g_strdup_printf("%s,%s,%s",
- mac, ipstr, name);
+ virBufferAsprintf(&buf, "%s,%s,%s", mac, ipstr, name);
} else if (name && !mac) {
- hostsfile->hosts[hostsfile->nhosts].host = g_strdup_printf("%s,%s", name,
- ipstr);
+ virBufferAsprintf(&buf, "%s,%s", name, ipstr);
} else {
- hostsfile->hosts[hostsfile->nhosts].host = g_strdup_printf("%s,%s", mac,
- ipstr);
+ virBufferAsprintf(&buf, "%s,%s", mac, ipstr);
}
- VIR_FREE(ipstr);
+
+ if (leasetime)
+ virBufferAsprintf(&buf, ",%s", leasetime);
+
+ if (!(hostsfile->hosts[hostsfile->nhosts].host = virBufferContentAndReset(&buf)))
+ return -1;
hostsfile->nhosts++;
return 0;
-
- error:
- VIR_FREE(ipstr);
- return -1;
}
static dnsmasqHostsfile *
@@ -501,9 +500,10 @@ dnsmasqAddDhcpHost(dnsmasqContext *ctx,
virSocketAddr *ip,
const char *name,
const char *id,
+ const char *leasetime,
bool ipv6)
{
- return hostsfileAdd(ctx->hostsfile, mac, ip, name, id, ipv6);
+ return hostsfileAdd(ctx->hostsfile, mac, ip, name, id, leasetime, ipv6);
}
/*
@@ -862,3 +862,31 @@ dnsmasqCapsGet(dnsmasqCapsPtr caps, dnsmasqCapsFlags flag)
{
return caps && virBitmapIsBitSet(caps->flags, flag);
}
+
+
+/** dnsmasqDhcpHostsToString:
+ *
+ * Turns a vector of dnsmasqDhcpHost into the string that is ought to be
+ * stored in the hostsfile, this functionality is split to make hostsfiles
+ * testable. Returs NULL if nhosts is 0.
+ */
+char *
+dnsmasqDhcpHostsToString(dnsmasqDhcpHost *hosts,
+ unsigned int nhosts)
+{
+ size_t i;
+ char *result = NULL;
+ virBuffer hostsfilebuf = VIR_BUFFER_INITIALIZER;
+
+ if (nhosts == 0)
+ goto cleanup;
+
+ for (i = 0; i < nhosts; i++)
+ virBufferAsprintf(&hostsfilebuf, "%s\n", hosts[i].host);
+
+ result = virBufferContentAndReset(&hostsfilebuf);
+
+ cleanup:
+ virBufferFreeAndReset(&hostsfilebuf);
+ return result;
+}
diff --git a/src/util/virdnsmasq.h b/src/util/virdnsmasq.h
index ff0e56d635..4c14bc6ca7 100644
--- a/src/util/virdnsmasq.h
+++ b/src/util/virdnsmasq.h
@@ -87,6 +87,7 @@ int dnsmasqAddDhcpHost(dnsmasqContext *ctx,
virSocketAddr *ip,
const char *name,
const char *id,
+ const char *leasetime,
bool ipv6);
int dnsmasqAddHost(dnsmasqContext *ctx,
virSocketAddr *ip,
@@ -104,6 +105,8 @@ int dnsmasqCapsRefresh(dnsmasqCapsPtr *caps, const char *binaryPath);
bool dnsmasqCapsGet(dnsmasqCapsPtr caps, dnsmasqCapsFlags flag);
const char *dnsmasqCapsGetBinaryPath(dnsmasqCapsPtr caps);
unsigned long dnsmasqCapsGetVersion(dnsmasqCapsPtr caps);
+char *dnsmasqDhcpHostsToString(dnsmasqDhcpHost *hosts,
+ unsigned int nhosts);
#define DNSMASQ_DHCPv6_MAJOR_REQD 2
#define DNSMASQ_DHCPv6_MINOR_REQD 64
diff --git a/src/vbox/vbox_network.c b/src/vbox/vbox_network.c
index 19b4d23ed8..cf273b9a48 100644
--- a/src/vbox/vbox_network.c
+++ b/src/vbox/vbox_network.c
@@ -379,6 +379,7 @@ vboxNetworkDefineCreateXML(virConnectPtr conn, const char *xml, bool start)
virNetworkIPDefPtr ipdef = NULL;
unsigned char uuid[VIR_UUID_BUFLEN];
vboxIID vboxnetiid;
+ virSocketAddrRange addr;
virSocketAddr netmask;
IHost *host = NULL;
virNetworkPtr ret = NULL;
@@ -440,9 +441,10 @@ vboxNetworkDefineCreateXML(virConnectPtr conn, const char *xml, bool start)
/* Currently support only one dhcp server per network
* with contigious address space from start to end
*/
+ addr = ipdef->ranges[0].addr;
if ((ipdef->nranges >= 1) &&
- VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].start) &&
- VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].end)) {
+ VIR_SOCKET_ADDR_VALID(&addr.start) &&
+ VIR_SOCKET_ADDR_VALID(&addr.end)) {
IDHCPServer *dhcpServer = NULL;
gVBoxAPI.UIVirtualBox.FindDHCPServerByNetworkName(data->vboxObj,
@@ -464,8 +466,8 @@ vboxNetworkDefineCreateXML(virConnectPtr conn, const char *xml, bool start)
ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->address);
networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
- fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].start);
- toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].end);
+ fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &addr.start);
+ toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &addr.end);
if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL ||
fromIPAddressUtf16 == NULL || toIPAddressUtf16 == NULL) {
@@ -770,6 +772,7 @@ static char *vboxNetworkGetXMLDesc(virNetworkPtr network, unsigned int flags)
vboxIID vboxnet0IID;
IHost *host = NULL;
char *ret = NULL;
+ virSocketAddrRange addr;
nsresult rc;
if (!data->vboxObj)
@@ -833,14 +836,15 @@ static char *vboxNetworkGetXMLDesc(virNetworkPtr network, unsigned int flags)
/* Currently virtualbox supports only one dhcp server per network
* with contigious address space from start to end
*/
+ addr = ipdef->ranges[0].addr;
if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
&ipdef->address) < 0 ||
vboxSocketParseAddrUtf16(data, networkMaskUtf16,
&ipdef->netmask) < 0 ||
vboxSocketParseAddrUtf16(data, fromIPAddressUtf16,
- &ipdef->ranges[0].start) < 0 ||
+ &addr.start) < 0 ||
vboxSocketParseAddrUtf16(data, toIPAddressUtf16,
- &ipdef->ranges[0].end) < 0) {
+ &addr.end) < 0) {
errorOccurred = true;
}
--
2.24.1
On 4/21/20 1:03 AM, Julio Faracco wrote:
> If an user is trying to configure a dhcp neetwork settings, it is not
s/neetwork/network
This patch failed to compile in my box on top of master at 9a13704818e:
CCLD libvirdeterministichashmock.la
../../tests/networkxml2conftest.c: In function 'testCompareXMLToConfFiles':
../../tests/networkxml2conftest.c:46:59: error: passing argument 4 of 'networkDnsmasqConfContents' from incompatible pointer type [-Werror=incompatible-pointer-types]
46 | if (networkDnsmasqConfContents(obj, pidfile, &actual, dctx, caps) < 0)
| ^~~~
| |
| dnsmasqContext * {aka struct <anonymous> *}
In file included from ../../tests/networkxml2conftest.c:13:
../../src/network/bridge_driver.h:49:35: note: expected 'char **' but argument is of type 'dnsmasqContext *' {aka 'struct <anonymous> *'}
49 | char **hostsfilestr,
| ~~~~~~~^~~~~~~~~~~~
../../tests/networkxml2conftest.c:46:65: error: passing argument 5 of 'networkDnsmasqConfContents' from incompatible pointer type [-Werror=incompatible-pointer-types]
46 | if (networkDnsmasqConfContents(obj, pidfile, &actual, dctx, caps) < 0)
| ^~~~
| |
| dnsmasqCapsPtr {aka struct _dnsmasqCaps *}
In file included from ../../tests/networkxml2conftest.c:13:
../../src/network/bridge_driver.h:50:44: note: expected 'dnsmasqContext *' {aka 'struct <anonymous> *'} but argument is of type 'dnsmasqCapsPtr' {aka 'struct _dnsmasqCaps *'}
50 | dnsmasqContext *dctx,
| ~~~~~~~~~~~~~~~~^~~~
../../tests/networkxml2conftest.c:46:9: error: too few arguments to function 'networkDnsmasqConfContents'
46 | if (networkDnsmasqConfContents(obj, pidfile, &actual, dctx, caps) < 0)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from ../../tests/networkxml2conftest.c:13:
../../src/network/bridge_driver.h:46:1: note: declared here
46 | networkDnsmasqConfContents(virNetworkObjPtr obj,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
Thanks,
DHB
Hi Daniel,
Thanks for reviewing. :-)
IMHO, I don't like to join them in one single patch because it is hard
to review.
I know that others have a different opinion (and it is good).
But I will think about it for v3.
--
Julio Cesar Faracco
Em qua., 22 de abr. de 2020 às 08:05, Daniel Henrique Barboza
<danielhb413@gmail.com> escreveu:
>
>
>
> On 4/21/20 1:03 AM, Julio Faracco wrote:
> > If an user is trying to configure a dhcp neetwork settings, it is not
>
> s/neetwork/network
>
>
>
> This patch failed to compile in my box on top of master at 9a13704818e:
>
>
> CCLD libvirdeterministichashmock.la
> ../../tests/networkxml2conftest.c: In function 'testCompareXMLToConfFiles':
> ../../tests/networkxml2conftest.c:46:59: error: passing argument 4 of 'networkDnsmasqConfContents' from incompatible pointer type [-Werror=incompatible-pointer-types]
> 46 | if (networkDnsmasqConfContents(obj, pidfile, &actual, dctx, caps) < 0)
> | ^~~~
> | |
> | dnsmasqContext * {aka struct <anonymous> *}
> In file included from ../../tests/networkxml2conftest.c:13:
> ../../src/network/bridge_driver.h:49:35: note: expected 'char **' but argument is of type 'dnsmasqContext *' {aka 'struct <anonymous> *'}
> 49 | char **hostsfilestr,
> | ~~~~~~~^~~~~~~~~~~~
> ../../tests/networkxml2conftest.c:46:65: error: passing argument 5 of 'networkDnsmasqConfContents' from incompatible pointer type [-Werror=incompatible-pointer-types]
> 46 | if (networkDnsmasqConfContents(obj, pidfile, &actual, dctx, caps) < 0)
> | ^~~~
> | |
> | dnsmasqCapsPtr {aka struct _dnsmasqCaps *}
> In file included from ../../tests/networkxml2conftest.c:13:
> ../../src/network/bridge_driver.h:50:44: note: expected 'dnsmasqContext *' {aka 'struct <anonymous> *'} but argument is of type 'dnsmasqCapsPtr' {aka 'struct _dnsmasqCaps *'}
> 50 | dnsmasqContext *dctx,
> | ~~~~~~~~~~~~~~~~^~~~
> ../../tests/networkxml2conftest.c:46:9: error: too few arguments to function 'networkDnsmasqConfContents'
> 46 | if (networkDnsmasqConfContents(obj, pidfile, &actual, dctx, caps) < 0)
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~
> In file included from ../../tests/networkxml2conftest.c:13:
> ../../src/network/bridge_driver.h:46:1: note: declared here
> 46 | networkDnsmasqConfContents(virNetworkObjPtr obj,
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~
> cc1: all warnings being treated as errors
>
>
>
>
> Thanks,
>
>
> DHB
On 4/22/20 9:22 AM, Julio Faracco wrote: > Hi Daniel, > > Thanks for reviewing. :-) Np, glad to be of assistance > IMHO, I don't like to join them in one single patch because it is hard > to review. Hmm, reading this I believe that the tests would pass after applying patch 2/2 then (didn't try). > I know that others have a different opinion (and it is good). The way you split the patch series is up to debate and so on and so forth. The issue here is that every single patch must pass 'make check', as said in docs/hacking.rst in the "Preparing patches" session: ---------- If you're going to submit multiple patches, the automated tests must pass **after each patch**, not just after the last one. ---------- You'll need to think in a way of splitting the series that allows each patch to pass 'make check' in its own. Thanks, DHB
Em qua., 22 de abr. de 2020 às 10:45, Daniel Henrique Barboza <danielhb413@gmail.com> escreveu: > > > > On 4/22/20 9:22 AM, Julio Faracco wrote: > > Hi Daniel, > > > > Thanks for reviewing. :-) > > > Np, glad to be of assistance > > > > IMHO, I don't like to join them in one single patch because it is hard > > to review. > > > Hmm, reading this I believe that the tests would pass after applying patch > 2/2 then (didn't try). > > > I know that others have a different opinion (and it is good). > > > The way you split the patch series is up to debate and so on and so > forth. The issue here is that every single patch must pass 'make check', > as said in docs/hacking.rst in the "Preparing patches" session: > > ---------- > If you're going to submit multiple patches, the automated tests > must pass **after each patch**, not just after the last one. > ---------- Yes, I usually keep a post commit hook, but I (unfortunately) moved to another Linux distro without my customization. Sorry about that. There is a memory leak also. I need to resend this series anyway. > > You'll need to think in a way of splitting the series that allows each > patch to pass 'make check' in its own. > > > Thanks, > > > DHB >
© 2016 - 2026 Red Hat, Inc.