conf: Add <lease/> option for <dhcp/> settings

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>
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
Julio Faracco 2020-04-22 17:05:57 -03:00 committed by Michal Privoznik
parent 5670fb5794
commit 97a0aa2467
12 changed files with 313 additions and 64 deletions

View File

@ -607,4 +607,12 @@
</element>
</define>
<define name="leaseUnit">
<choice>
<value>seconds</value>
<value>minutes</value>
<value>hours</value>
</choice>
</define>
</grammar>

View File

@ -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>

View File

@ -70,6 +70,13 @@ VIR_ENUM_IMPL(virNetworkTaint,
"hook-script",
);
VIR_ENUM_IMPL(virNetworkDHCPLeaseTimeUnit,
VIR_NETWORK_DHCP_LEASETIME_UNIT_LAST,
"seconds",
"minutes",
"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,62 @@ 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;
g_autofree char *unit = NULL;
int unitInt;
if (!(expiry = virXMLPropString(node, "expiry")))
return 0;
if (VIR_ALLOC(new_lease) < 0)
return -1;
new_lease->unit = VIR_NETWORK_DHCP_LEASETIME_UNIT_MINUTES;
if (virStrToLong_ul(expiry, NULL, 10, &new_lease->expiry) < 0)
return -1;
if ((unit = virXMLPropString(node, "unit"))) {
if ((unitInt = virNetworkDHCPLeaseTimeUnitTypeFromString(unit)) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("Invalid unit: %s"), unit);
return -1;
}
new_lease->unit = unitInt;
}
/* 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 +474,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 +483,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 +520,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 +613,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 +649,7 @@ virNetworkDHCPDefParseXML(const char *networkName,
{
int ret = -1;
xmlNodePtr cur;
virSocketAddrRange range;
virNetworkDHCPRangeDef range;
virNetworkDHCPHostDef host;
memset(&range, 0, sizeof(range));
@ -570,7 +660,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 +673,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 +2389,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 +2436,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 +2465,6 @@ virNetworkIPDefFormat(virBufferPtr buf,
virBufferAddLit(buf, "/>\n");
}
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</dhcp>\n");
}
@ -3080,7 +3201,7 @@ virNetworkDefUpdateIPDHCPRange(virNetworkDefPtr def,
{
size_t i;
virNetworkIPDefPtr ipdef = virNetworkIPDefByIndex(def, parentIndex);
virSocketAddrRange range;
virNetworkDHCPRangeDef range;
memset(&range, 0, sizeof(range));
@ -3100,11 +3221,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 +3234,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 +3248,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 "

View File

@ -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;

View File

@ -772,6 +772,8 @@ virNetworkDefParseNode;
virNetworkDefParseString;
virNetworkDefParseXML;
virNetworkDefUpdateSection;
virNetworkDHCPLeaseTimeUnitTypeFromString;
virNetworkDHCPLeaseTimeUnitTypeToString;
virNetworkForwardTypeToString;
virNetworkIPDefNetmask;
virNetworkIPDefPrefix;
@ -1950,6 +1952,7 @@ dnsmasqCapsRefresh;
dnsmasqContextFree;
dnsmasqContextNew;
dnsmasqDelete;
dnsmasqDhcpHostsToString;
dnsmasqReload;
dnsmasqSave;

View File

@ -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)
@ -1525,6 +1561,9 @@ networkDnsmasqConfContents(virNetworkObjPtr obj,
if (!(*configstr = virBufferContentAndReset(&configbuf)))
goto cleanup;
*hostsfilestr = dnsmasqDhcpHostsToString(dctx->hostsfile->hosts,
dctx->hostsfile->nhosts);
ret = 0;
cleanup:
@ -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)

View File

@ -46,5 +46,6 @@ int
networkDnsmasqConfContents(virNetworkObjPtr obj,
const char *pidfile,
char **configstr,
char **hostsfilestr,
dnsmasqContext *dctx,
dnsmasqCapsPtr caps);

View File

@ -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;

View File

@ -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,23 @@ 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;
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
for (i = 0; i < nhosts; i++)
virBufferAsprintf(&buf, "%s\n", hosts[i].host);
return virBufferContentAndReset(&buf);
}

View File

@ -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

View File

@ -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;
}

View File

@ -18,7 +18,8 @@
static int
testCompareXMLToConfFiles(const char *inxml, const char *outconf, dnsmasqCapsPtr caps)
{
char *actual = NULL;
char *confactual = NULL;
char *hostsfileactual = NULL;
int ret = -1;
virNetworkDefPtr def = NULL;
virNetworkObjPtr obj = NULL;
@ -43,28 +44,30 @@ testCompareXMLToConfFiles(const char *inxml, const char *outconf, dnsmasqCapsPtr
if (dctx == NULL)
goto fail;
if (networkDnsmasqConfContents(obj, pidfile, &actual, dctx, caps) < 0)
if (networkDnsmasqConfContents(obj, pidfile, &confactual,
&hostsfileactual, dctx, caps) < 0)
goto fail;
/* Any changes to this function ^^ should be reflected here too. */
#ifndef __linux__
char * tmp;
if (!(tmp = virStringReplace(actual,
if (!(tmp = virStringReplace(confactual,
"except-interface=lo0\n",
"except-interface=lo\n")))
goto fail;
VIR_FREE(actual);
VIR_FREE(confactual);
actual = g_steal_pointer(&tmp);
#endif
if (virTestCompareToFile(actual, outconf) < 0)
if (virTestCompareToFile(confactual, outconf) < 0)
goto fail;
ret = 0;
fail:
VIR_FREE(actual);
VIR_FREE(confactual);
VIR_FREE(hostsfileactual);
VIR_FREE(pidfile);
virCommandFree(cmd);
virObjectUnref(xmlopt);