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@xxxxxxxxx> --- 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 | 60 +++++++++----- src/util/virdnsmasq.h | 3 + src/vbox/vbox_network.c | 16 ++-- tests/networkxml2conftest.c | 15 ++-- 12 files changed, 306 insertions(+), 64 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 28610a837e..c43e8b0ca6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -772,6 +772,8 @@ virNetworkDefParseNode; virNetworkDefParseString; virNetworkDefParseXML; virNetworkDefUpdateSection; +virNetworkDHCPLeaseTimeUnitTypeFromString; +virNetworkDHCPLeaseTimeUnitTypeToString; virNetworkForwardTypeToString; virNetworkIPDefNetmask; virNetworkIPDefPrefix; @@ -1950,6 +1952,7 @@ dnsmasqCapsRefresh; dnsmasqContextFree; dnsmasqContextNew; dnsmasqDelete; +dnsmasqDhcpHostsToString; dnsmasqReload; dnsmasqSave; diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index f06099297a..87f0452611 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) @@ -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) 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..818219fbeb 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,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); +} 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; } diff --git a/tests/networkxml2conftest.c b/tests/networkxml2conftest.c index a8355272b9..83b89dd361 100644 --- a/tests/networkxml2conftest.c +++ b/tests/networkxml2conftest.c @@ -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); -- 2.25.3