[Libvir] [PATCH REPOST] DHCP host mappings using 3 arrays API
Richard W.M. Jones
rjones at redhat.com
Wed Apr 9 12:29:12 UTC 2008
Previous discussion:
http://www.redhat.com/archives/libvir-list/2008-February/thread.html#00281
http://www.redhat.com/archives/libvir-list/2008-February/thread.html#00348
This patch also contains the fix to close the file descriptor
mentioned by Jim Meyering in that second thread.
Hugh: Is this still wanted for oVirt? If oVirt don't specifically
need it then we may as well leave it out.
Rich.
--
Richard Jones, Emerging Technologies, Red Hat http://et.redhat.com/~rjones
virt-p2v converts physical machines to virtual machines. Boot with a
live CD or over the network (PXE) and turn machines into Xen guests.
http://et.redhat.com/~rjones/virt-p2v
-------------- next part --------------
Index: include/libvirt/libvirt.h.in
===================================================================
RCS file: /data/cvs/libvirt/include/libvirt/libvirt.h.in,v
retrieving revision 1.46
diff -u -p -r1.46 libvirt.h.in
--- include/libvirt/libvirt.h.in 17 Mar 2008 10:27:32 -0000 1.46
+++ include/libvirt/libvirt.h.in 9 Apr 2008 12:27:17 -0000
@@ -760,6 +760,27 @@ int virNetworkGetAutostart (virNetwork
int virNetworkSetAutostart (virNetworkPtr network,
int autostart);
+/*
+ * DHCP host mappings
+ */
+int virNetworkNumOfDHCPHostMappings
+ (virNetworkPtr network);
+int virNetworkListDHCPHostMappings
+ (virNetworkPtr network,
+ char **const hwaddrs,
+ char **const ipaddrs,
+ char **const hostnames,
+ int maxmappings);
+
+int virNetworkAddDHCPHostMapping
+ (virNetworkPtr network,
+ const char *hwaddr,
+ const char *ipaddr,
+ const char *hostname,
+ unsigned int flags);
+int virNetworkDeleteDHCPHostMapping
+ (virNetworkPtr network,
+ const char *hwaddr);
/**
* virStoragePool:
Index: qemud/remote.c
===================================================================
RCS file: /data/cvs/libvirt/qemud/remote.c,v
retrieving revision 1.28
diff -u -p -r1.28 remote.c
--- qemud/remote.c 4 Apr 2008 15:09:19 -0000 1.28
+++ qemud/remote.c 9 Apr 2008 12:27:20 -0000
@@ -2060,6 +2060,173 @@ remoteDispatchNumOfNetworks (struct qemu
static int
+remoteDispatchNetworkNumOfDhcpHostMappings (struct qemud_server *server ATTRIBUTE_UNUSED,
+ struct qemud_client *client,
+ remote_message_header *req,
+ remote_network_num_of_dhcp_host_mappings_args *args,
+ remote_network_num_of_dhcp_host_mappings_ret *ret)
+{
+ virNetworkPtr net;
+ CHECK_CONN(client);
+
+ net = get_nonnull_network (client->conn, args->net);
+ if (net == NULL) {
+ remoteDispatchError (client, req, "network not found");
+ return -2;
+ }
+
+ ret->num = virNetworkNumOfDHCPHostMappings (net);
+ if (ret->num == -1) {
+ virNetworkFree (net);
+ return -1;
+ }
+
+ virNetworkFree (net);
+ return 0;
+}
+
+
+static int
+remoteDispatchNetworkListDhcpHostMappings (struct qemud_server *server ATTRIBUTE_UNUSED,
+ struct qemud_client *client,
+ remote_message_header *req,
+ remote_network_list_dhcp_host_mappings_args *args,
+ remote_network_list_dhcp_host_mappings_ret *ret)
+{
+ virNetworkPtr net;
+ char **hwaddrs, **ipaddrs, **hostnames;
+ int nr_mappings, i;
+ CHECK_CONN(client);
+
+ net = get_nonnull_network (client->conn, args->net);
+ if (net == NULL) {
+ remoteDispatchError (client, req, "network not found");
+ return -2;
+ }
+
+ if (args->maxmappings > REMOTE_NETWORK_DHCP_HOST_MAPPINGS_LIST_MAX) {
+ remoteDispatchError (client, req,
+ "maxmappings > REMOTE_NETWORK_DHCP_HOST_MAPPINGS_LIST_MAX");
+ return -2;
+ }
+
+ hwaddrs = malloc (args->maxmappings * sizeof (char *));
+ if (!hwaddrs) {
+ remoteDispatchSendError (client, req, VIR_ERR_NO_MEMORY, "hwaddrs");
+ return -2;
+ }
+ ipaddrs = malloc (args->maxmappings * sizeof (char *));
+ if (!ipaddrs) {
+ remoteDispatchSendError (client, req, VIR_ERR_NO_MEMORY, "ipaddrs");
+ free (hwaddrs);
+ return -2;
+ }
+ hostnames = malloc (args->maxmappings * sizeof (char *));
+ if (!hostnames) {
+ remoteDispatchSendError (client, req, VIR_ERR_NO_MEMORY, "hostnames");
+ free (hwaddrs);
+ free (ipaddrs);
+ return -2;
+ }
+
+ nr_mappings = virNetworkListDHCPHostMappings (net,
+ hwaddrs, ipaddrs, hostnames,
+ args->maxmappings);
+ if (nr_mappings == -1) {
+ virNetworkFree(net);
+ free (hwaddrs);
+ free (ipaddrs);
+ free (hostnames);
+ return -1;
+ }
+
+ ret->hwaddrs.hwaddrs_len = nr_mappings;
+ ret->ipaddrs.ipaddrs_len = nr_mappings;
+ ret->hostnames.hostnames_len = nr_mappings;
+
+ ret->hwaddrs.hwaddrs_val =
+ calloc (nr_mappings, sizeof (ret->hwaddrs.hwaddrs_val[0]));
+ ret->ipaddrs.ipaddrs_val =
+ calloc (nr_mappings, sizeof (ret->ipaddrs.ipaddrs_val[0]));
+ ret->hostnames.hostnames_val =
+ calloc (nr_mappings, sizeof (ret->hostnames.hostnames_val[0]));
+ for (i = 0; i < nr_mappings; ++i) {
+ ret->hwaddrs.hwaddrs_val[i] = hwaddrs[i];
+ ret->ipaddrs.ipaddrs_val[i] = ipaddrs[i];
+ /* See note in remote_protocol.x */
+ ret->hostnames.hostnames_val[i] =
+ hostnames[i] == NULL ? strdup ("") : hostnames[i];
+ }
+
+ free (hwaddrs); /* NB: Just free the array, caller frees the rest. */
+ free (ipaddrs);
+ free (hostnames);
+
+ virNetworkFree(net);
+ return 0;
+}
+
+
+static int
+remoteDispatchNetworkAddDhcpHostMapping (struct qemud_server *server ATTRIBUTE_UNUSED,
+ struct qemud_client *client,
+ remote_message_header *req,
+ remote_network_add_dhcp_host_mapping_args *args,
+ void *ret ATTRIBUTE_UNUSED)
+{
+ virNetworkPtr net;
+ char *hwaddr, *ipaddr, *hostname;
+ CHECK_CONN(client);
+
+ net = get_nonnull_network (client->conn, args->net);
+ if (net == NULL) {
+ remoteDispatchError (client, req, "network not found");
+ return -2;
+ }
+
+ hwaddr = args->hwaddr;
+ ipaddr = args->ipaddr;
+ hostname = args->hostname == NULL ? NULL : *args->hostname;
+
+ if (virNetworkAddDHCPHostMapping (net, hwaddr, ipaddr, hostname, args->flags) == -1) {
+ virNetworkFree (net);
+ return -1;
+ }
+
+ virNetworkFree (net);
+ return 0;
+}
+
+static int
+remoteDispatchNetworkDeleteDhcpHostMapping (struct qemud_server *server ATTRIBUTE_UNUSED,
+ struct qemud_client *client,
+ remote_message_header *req,
+ remote_network_delete_dhcp_host_mapping_args *args,
+ void *ret ATTRIBUTE_UNUSED)
+{
+ virNetworkPtr net;
+ char *hwaddr;
+ CHECK_CONN(client);
+
+ net = get_nonnull_network (client->conn, args->net);
+ if (net == NULL) {
+ remoteDispatchError (client, req, "network not found");
+ return -2;
+ }
+
+ hwaddr = args->hwaddr;
+
+ if (virNetworkDeleteDHCPHostMapping (net, hwaddr) == -1) {
+ virNetworkFree (net);
+ return -1;
+ }
+
+ virNetworkFree (net);
+ return 0;
+}
+
+
+static int
remoteDispatchAuthList (struct qemud_server *server ATTRIBUTE_UNUSED,
struct qemud_client *client,
remote_message_header *req ATTRIBUTE_UNUSED,
Index: qemud/remote_protocol.x
===================================================================
RCS file: /data/cvs/libvirt/qemud/remote_protocol.x,v
retrieving revision 1.10
diff -u -p -r1.10 remote_protocol.x
--- qemud/remote_protocol.x 20 Feb 2008 15:22:35 -0000 1.10
+++ qemud/remote_protocol.x 9 Apr 2008 12:27:20 -0000
@@ -78,6 +78,9 @@ const REMOTE_MIGRATE_COOKIE_MAX = 256;
/* Upper limit on lists of network names. */
const REMOTE_NETWORK_NAME_LIST_MAX = 256;
+/* Upper limit on lists of DHCP host mappings. */
+const REMOTE_NETWORK_DHCP_HOST_MAPPINGS_LIST_MAX = 256;
+
/* Upper limit on lists of storage pool names. */
const REMOTE_STORAGE_POOL_NAME_LIST_MAX = 256;
@@ -647,6 +650,42 @@ struct remote_network_set_autostart_args
int autostart;
};
+struct remote_network_num_of_dhcp_host_mappings_args {
+ remote_nonnull_network net;
+};
+
+struct remote_network_num_of_dhcp_host_mappings_ret {
+ int num;
+};
+
+struct remote_network_list_dhcp_host_mappings_args {
+ remote_nonnull_network net;
+ int maxmappings;
+};
+
+struct remote_network_list_dhcp_host_mappings_ret {
+ remote_nonnull_string hwaddrs<REMOTE_NETWORK_DHCP_HOST_MAPPINGS_LIST_MAX>;
+ remote_nonnull_string ipaddrs<REMOTE_NETWORK_DHCP_HOST_MAPPINGS_LIST_MAX>;
+ /* Technically these can be NULL, but XDR makes it very hard
+ * to implement remoteDispatchNetworkListDhcpHostMappings without
+ * using an ugly static variable, so instead just assume "" on the
+ * wire is the same as NULL. Hostnames can't be zero length anyway.
+ */
+ remote_nonnull_string hostnames<REMOTE_NETWORK_DHCP_HOST_MAPPINGS_LIST_MAX>;
+};
+
+struct remote_network_add_dhcp_host_mapping_args {
+ remote_nonnull_network net;
+ remote_nonnull_string hwaddr;
+ remote_nonnull_string ipaddr;
+ remote_string hostname;
+ int flags;
+};
+
+struct remote_network_delete_dhcp_host_mapping_args {
+ remote_nonnull_network net;
+ remote_nonnull_string hwaddr;
+};
struct remote_auth_list_ret {
remote_auth_type types<REMOTE_AUTH_TYPE_LIST_MAX>;
@@ -1017,7 +1056,12 @@ enum remote_procedure {
REMOTE_PROC_STORAGE_VOL_LOOKUP_BY_PATH = 97,
REMOTE_PROC_STORAGE_VOL_GET_INFO = 98,
REMOTE_PROC_STORAGE_VOL_DUMP_XML = 99,
- REMOTE_PROC_STORAGE_VOL_GET_PATH = 100
+ REMOTE_PROC_STORAGE_VOL_GET_PATH = 100,
+
+ REMOTE_PROC_NETWORK_ADD_DHCP_HOST_MAPPING = 101,
+ REMOTE_PROC_NETWORK_DELETE_DHCP_HOST_MAPPING = 102,
+ REMOTE_PROC_NETWORK_LIST_DHCP_HOST_MAPPINGS = 103,
+ REMOTE_PROC_NETWORK_NUM_OF_DHCP_HOST_MAPPINGS = 104
};
/* Custom RPC structure. */
Index: src/driver.h
===================================================================
RCS file: /data/cvs/libvirt/src/driver.h,v
retrieving revision 1.44
diff -u -p -r1.44 driver.h
--- src/driver.h 21 Mar 2008 15:03:37 -0000 1.44
+++ src/driver.h 9 Apr 2008 12:27:21 -0000
@@ -381,6 +381,24 @@ typedef int
(*virDrvNetworkSetAutostart) (virNetworkPtr network,
int autostart);
+typedef int
+ (*virDrvNetworkNumOfDHCPHostMappings) (virNetworkPtr network);
+typedef int
+ (*virDrvNetworkListDHCPHostMappings) (virNetworkPtr network,
+ char **const hwaddrs,
+ char **const ipaddrs,
+ char **const hostnames,
+ int maxmappings);
+typedef int
+ (*virDrvNetworkAddDHCPHostMapping) (virNetworkPtr network,
+ const char *hwaddr,
+ const char *ipaddr,
+ const char *hostname,
+ unsigned int flags);
+typedef int
+ (*virDrvNetworkDeleteDHCPHostMapping) (virNetworkPtr network,
+ const char *hwaddr);
+
typedef struct _virNetworkDriver virNetworkDriver;
typedef virNetworkDriver *virNetworkDriverPtr;
@@ -414,6 +432,10 @@ struct _virNetworkDriver {
virDrvNetworkGetBridgeName networkGetBridgeName;
virDrvNetworkGetAutostart networkGetAutostart;
virDrvNetworkSetAutostart networkSetAutostart;
+ virDrvNetworkNumOfDHCPHostMappings networkNumOfDHCPHostMappings;
+ virDrvNetworkListDHCPHostMappings networkListDHCPHostMappings;
+ virDrvNetworkAddDHCPHostMapping networkAddDHCPHostMapping;
+ virDrvNetworkDeleteDHCPHostMapping networkDeleteDHCPHostMapping;
};
Index: src/libvirt.c
===================================================================
RCS file: /data/cvs/libvirt/src/libvirt.c,v
retrieving revision 1.134
diff -u -p -r1.134 libvirt.c
--- src/libvirt.c 4 Apr 2008 15:09:19 -0000 1.134
+++ src/libvirt.c 9 Apr 2008 12:27:24 -0000
@@ -3761,6 +3761,175 @@ virNetworkSetAutostart(virNetworkPtr net
return -1;
}
+/**
+ * virNetworkNumOfDHCPHostMappings:
+ * @network: a network object
+ *
+ * Returns the number of DHCP host mappings, or -1 in case of error.
+ */
+int
+virNetworkNumOfDHCPHostMappings (virNetworkPtr network)
+{
+ virConnectPtr conn;
+ DEBUG("network=%p", network);
+
+ if (!VIR_IS_NETWORK(network)) {
+ virLibNetworkError (NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+ return -1;
+ }
+
+ conn = network->conn;
+
+ if (conn->networkDriver &&
+ conn->networkDriver->networkNumOfDHCPHostMappings)
+ return conn->networkDriver->networkNumOfDHCPHostMappings (network);
+
+ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
+/**
+ * virNetworkListDHCPHostMappings:
+ * @network: a network object
+ * @hwaddrs: an array of hardware addresses
+ * @ipaddrs: an array of IP addresses
+ * @hostnames: an array of hostnames (which may be NULL)
+ * @maxmappings: the length of the arrays
+ *
+ * This can be used to return a list of DHCP host mappings for the
+ * network.
+ *
+ * This function fills in three arrays of corresponding pointers,
+ * thus the first tuple returned is (hwaddrs[0], ipaddrs[0],
+ * hostnames[0]). The 'hwaddrs' array contains hardware (MAC)
+ * addresses. The 'ipaddrs' array contains IP addresses as strings
+ * in dotted-quad or IPv6 colon format. The 'hostnames' array
+ * contains optional hostnames, which may be NULL.
+ *
+ * The caller is responsible for freeing the strings.
+ *
+ * Returns the number of DHCP host mappings, or -1 in case of error.
+ */
+int
+virNetworkListDHCPHostMappings (virNetworkPtr network,
+ char **const hwaddrs,
+ char **const ipaddrs,
+ char **const hostnames,
+ int maxmappings)
+{
+ virConnectPtr conn;
+ DEBUG("network=%p, hwaddrs=%p, ipaddrs=%p, hostnames=%p, maxmappings=%d",
+ network, hwaddrs, ipaddrs, hostnames, maxmappings);
+
+ if (!VIR_IS_NETWORK(network)) {
+ virLibNetworkError (NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+ return -1;
+ }
+
+ conn = network->conn;
+
+ if (!hwaddrs || !ipaddrs || !hostnames) {
+ virLibNetworkError (network, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return -1;
+ }
+
+ if (maxmappings == 0) return 0;
+
+ memset (hwaddrs, 0, sizeof (char *) * maxmappings);
+ memset (ipaddrs, 0, sizeof (char *) * maxmappings);
+ memset (hostnames, 0, sizeof (char *) * maxmappings);
+
+ if (conn->networkDriver &&
+ conn->networkDriver->networkListDHCPHostMappings)
+ return conn->networkDriver->networkListDHCPHostMappings (network,
+ hwaddrs,
+ ipaddrs,
+ hostnames,
+ maxmappings);
+
+ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
+/**
+ * virNetworkAddDHCPHostMapping:
+ * @network: a network object
+ * @hwaddr: hardware (MAC) address
+ * @ipaddr: IP address
+ * @hostname: hostname
+ * @flags: unused, pass 0
+ *
+ * Add a DHCP hardware address to IP address mapping, and optionally
+ * a DHCP hostname for the IP address (if hostname is not NULL).
+ *
+ * The mappings are keyed on the hardware (MAC) address. If the hardware
+ * address already has a mapping, then this call replaces it.
+ *
+ * Return -1 on error or 0 on success.
+ */
+int
+virNetworkAddDHCPHostMapping (virNetworkPtr network,
+ const char *hwaddr,
+ const char *ipaddr,
+ const char *hostname,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+ DEBUG("network=%p, hwaddr=%s, ipaddr=%s, hostname=%s, flags=%d",
+ network, hwaddr, ipaddr, hostname, flags);
+
+ if (!VIR_IS_NETWORK(network)) {
+ virLibNetworkError (NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+ return -1;
+ }
+
+ conn = network->conn;
+
+ if (flags != 0) {
+ virLibNetworkError (NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return -1;
+ }
+
+ if (conn->networkDriver &&
+ conn->networkDriver->networkAddDHCPHostMapping)
+ return conn->networkDriver->networkAddDHCPHostMapping
+ (network, hwaddr, ipaddr, hostname, flags);
+
+ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
+/**
+ * virNetworkDeleteDHCPHostMapping:
+ * @network: a network object
+ * @hwaddr: hardware (MAC) address
+ *
+ * Delete an existing DHCP host mapping.
+ *
+ * Return -1 on error or 0 on success.
+ */
+int
+virNetworkDeleteDHCPHostMapping (virNetworkPtr network,
+ const char *hwaddr)
+{
+ virConnectPtr conn;
+ DEBUG("network=%p, hwaddr=%s", network, hwaddr);
+
+ if (!VIR_IS_NETWORK(network)) {
+ virLibNetworkError (NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+ return -1;
+ }
+
+ conn = network->conn;
+
+ if (conn->networkDriver &&
+ conn->networkDriver->networkDeleteDHCPHostMapping)
+ return conn->networkDriver->networkDeleteDHCPHostMapping (network,
+ hwaddr);
+
+ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
/**
* virStoragePoolGetConnect:
Index: src/libvirt_sym.version
===================================================================
RCS file: /data/cvs/libvirt/src/libvirt_sym.version,v
retrieving revision 1.38
diff -u -p -r1.38 libvirt_sym.version
--- src/libvirt_sym.version 28 Feb 2008 17:06:32 -0000 1.38
+++ src/libvirt_sym.version 9 Apr 2008 12:27:24 -0000
@@ -99,6 +99,11 @@
virNetworkGetBridgeName;
virNetworkGetAutostart;
virNetworkSetAutostart;
+ virNetworkNumOfDHCPHostMappings;
+ virNetworkListDHCPHostMappings;
+ virNetworkFreeDHCPHostMappings;
+ virNetworkAddDHCPHostMapping;
+ virNetworkDeleteDHCPHostMapping;
virStoragePoolGetConnect;
virConnectNumOfStoragePools;
Index: src/qemu_driver.c
===================================================================
RCS file: /data/cvs/libvirt/src/qemu_driver.c,v
retrieving revision 1.65
diff -u -p -r1.65 qemu_driver.c
--- src/qemu_driver.c 8 Apr 2008 12:27:53 -0000 1.65
+++ src/qemu_driver.c 9 Apr 2008 12:27:26 -0000
@@ -845,6 +845,7 @@ qemudBuildDnsmasqArgv(virConnectPtr conn
2 + /* --except-interface lo */
2 + /* --listen-address 10.0.0.1 */
1 + /* --dhcp-leasefile=path */
+ 1 + /* --dhcp-hostsfile=path */
(2 * network->def->nranges) + /* --dhcp-range 10.0.0.2,10.0.0.254 */
1; /* NULL */
@@ -898,6 +899,10 @@ qemudBuildDnsmasqArgv(virConnectPtr conn
LOCAL_STATE_DIR, network->def->name);
APPEND_ARG(*argv, i++, buf);
+ snprintf(buf, sizeof(buf),
+ "--dhcp-hostsfile=" DHCP_HOSTS_FORMAT, network->def->name);
+ APPEND_ARG(*argv, i++, buf);
+
range = network->def->ranges;
while (range) {
snprintf(buf, sizeof(buf), "%s,%s",
@@ -929,6 +934,7 @@ static int
dhcpStartDhcpDaemon(virConnectPtr conn,
struct qemud_network *network)
{
+ char buf[PATH_MAX];
char **argv;
int ret, i;
@@ -938,6 +944,21 @@ dhcpStartDhcpDaemon(virConnectPtr conn,
return -1;
}
+ /* Touch the DHCP hosts file so it exists before dnsmasq starts up. */
+ snprintf (buf, sizeof buf, DHCP_HOSTS_FORMAT, network->def->name);
+ ret = open (buf, O_CREAT|O_WRONLY, 0644);
+ if (ret == -1) {
+ qemudReportError (conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR,
+ "%s: %s", buf, strerror (errno));
+ return -1;
+ }
+
+ if (close (ret) == -1) {
+ qemudReportError (conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR,
+ "%s: %s", buf, strerror (errno));
+ return -1;
+ }
+
argv = NULL;
if (qemudBuildDnsmasqArgv(conn, network, &argv) < 0)
return -1;
@@ -3008,6 +3029,382 @@ static int qemudNetworkSetAutostart(virN
return 0;
}
+/* Free the strings but NOT the underlying arrays. */
+static void
+qemudFreeDHCPHostMappings (char **hwaddrs, char **ipaddrs, char **hostnames,
+ int nr_mappings)
+{
+ int i;
+
+ for (i = 0; i < nr_mappings; ++i) {
+ free (hwaddrs[i]);
+ free (ipaddrs[i]);
+ free (hostnames[i]);
+ }
+}
+
+/* Parse the mappings file.
+ *
+ * If hwaddrs != NULL then this allocates all three arrays and
+ * stores (allocated) pointers to the strings in each one.
+ * Use qemudFreeDHCPHostMappings to free the strings, then free
+ * the arrays by hand.
+ *
+ * Returns the number of entries read from the file.
+ */
+static int
+qemudParseDHCPHostMappingsFile (virNetworkPtr net,
+ struct qemud_network *network,
+ char ***hwaddrs,
+ char ***ipaddrs,
+ char ***hostnames)
+{
+ char buf[PATH_MAX];
+ FILE *fp;
+ int col, len;
+ int lines = 0;
+ int allocated = 0;
+ char *str;
+ char *token;
+ char *saveptr = NULL;
+
+ if (hwaddrs) {
+ *hwaddrs = NULL;
+ *ipaddrs = NULL;
+ *hostnames = NULL;
+ }
+
+ snprintf (buf, sizeof buf, DHCP_HOSTS_FORMAT, network->def->name);
+ fp = fopen (buf, "r");
+ if (fp == NULL) {
+ qemudReportError (net->conn, NULL, net, VIR_ERR_SYSTEM_ERROR,
+ "%s: %s", buf, strerror (errno));
+ return -1;
+ }
+
+ while (fgets (buf, sizeof buf, fp) != 0) {
+ char *hwaddr = 0, *ipaddr = 0, *hostname = 0;
+
+ /* Dnsmasq manpage is fuzzy about what is accepted as a
+ * parameter for dhcp-host. Hopefully only we will be
+ * writing to this file, but be generous in what we
+ * accept anyway.
+ *
+ * NB: A possible improvement here: If we can't parse the
+ * line then just store the line as-is and write it back
+ * into the file.
+ */
+ /* Chomp trailing \n character. */
+ len = strlen (buf);
+ if (len > 0 && buf[len-1] == '\n') {
+ buf[len-1] = '\0';
+ len--;
+ }
+
+ /* Ignore blank lines and comments. */
+ if (len == 0 || buf[0] == '#')
+ continue;
+
+ for (str = buf, col = 0;
+ (token = strtok_r (str, ",", &saveptr)) != NULL;
+ str = NULL, col++) {
+ if (!STREQLEN (token, "net:", 4) &&
+ !STREQLEN (token, "id:", 3) &&
+ !STREQ (token, "ignore")) {
+ /* First column is the hardware address. */
+ if (col == 0) hwaddr = token;
+ else {
+ if (isdigit (token[0])) {
+ if (!ipaddr) ipaddr = token;
+ } else {
+ if (!hostname) hostname = token;
+ }
+ }
+ }
+ }
+
+ if (hwaddr && ipaddr) {
+ if (hwaddrs) {
+ if (lines >= allocated) {
+ char **old;
+
+ allocated += 16;
+
+ old = *hwaddrs;
+ *hwaddrs = realloc (old, allocated * sizeof (char *));
+ if (!*hwaddrs) {
+ *hwaddrs = old;
+ goto mem_error;
+ }
+ old = *ipaddrs;
+ *ipaddrs = realloc (old, allocated * sizeof (char *));
+ if (!*ipaddrs) {
+ *ipaddrs = old;
+ goto mem_error;
+ }
+ old = *hostnames;
+ *hostnames = realloc (old, allocated * sizeof (char *));
+ if (!*hostnames) {
+ *hostnames = old;
+ goto mem_error;
+ }
+ }
+
+ (*hwaddrs)[lines] = strdup (hwaddr);
+ if (!(*hwaddrs)[lines]) goto mem_error;
+ (*ipaddrs)[lines] = strdup (ipaddr);
+ if (!(*ipaddrs)[lines]) goto mem_error;
+ if (hostname) {
+ (*hostnames)[lines] = strdup (hostname);
+ if (!(*hostnames)[lines]) goto mem_error;
+ } else
+ (*hostnames)[lines] = NULL;
+ }
+
+ lines++;
+ }
+ }
+
+ fclose (fp);
+
+ return lines;
+
+ mem_error:
+ fclose (fp);
+
+ if (hwaddrs) {
+ qemudFreeDHCPHostMappings (*hwaddrs, *ipaddrs, *hostnames, lines);
+ free (*hwaddrs);
+ free (*ipaddrs);
+ free (*hostnames);
+ }
+
+ qemudReportError (net->conn, NULL, net, VIR_ERR_NO_MEMORY,
+ __FUNCTION__);
+
+ return -1;
+}
+
+static int
+qemudNetworkNumOfDHCPHostMappings (virNetworkPtr net)
+{
+ struct qemud_driver *driver =
+ (struct qemud_driver *)net->conn->networkPrivateData;
+ struct qemud_network *network =
+ qemudFindNetworkByUUID(driver, net->uuid);
+
+ if (!network) {
+ qemudReportError (net->conn, NULL, net, VIR_ERR_INVALID_DOMAIN,
+ "no network with matching uuid");
+ return -1;
+ }
+
+ return qemudParseDHCPHostMappingsFile (net, network, NULL, NULL, NULL);
+}
+
+static int
+qemudNetworkListDHCPHostMappings (virNetworkPtr net,
+ char **const hwaddrs_rtn,
+ char **const ipaddrs_rtn,
+ char **const hostnames_rtn,
+ int maxmappings)
+{
+ int nr_mappings, ret;
+ char **hwaddrs, **ipaddrs, **hostnames;
+ struct qemud_driver *driver =
+ (struct qemud_driver *)net->conn->networkPrivateData;
+ struct qemud_network *network =
+ qemudFindNetworkByUUID(driver, net->uuid);
+
+ if (!network) {
+ qemudReportError (net->conn, NULL, net, VIR_ERR_INVALID_DOMAIN,
+ "no network with matching uuid");
+ return -1;
+ }
+
+ nr_mappings =
+ qemudParseDHCPHostMappingsFile (net, network,
+ &hwaddrs, &ipaddrs, &hostnames);
+ if (nr_mappings == -1) return -1;
+
+ if (maxmappings >= nr_mappings) {
+ /* The return array is large enough. */
+ memcpy (hwaddrs_rtn, hwaddrs, nr_mappings * sizeof (char *));
+ memcpy (ipaddrs_rtn, ipaddrs, nr_mappings * sizeof (char *));
+ memcpy (hostnames_rtn, hostnames, nr_mappings * sizeof (char *));
+ ret = nr_mappings;
+ } else {
+ /* Partially copy the array, free the unused mappings that
+ * we didn't copy.
+ */
+ memcpy (hwaddrs_rtn, hwaddrs, maxmappings * sizeof (char *));
+ memcpy (ipaddrs_rtn, ipaddrs, maxmappings * sizeof (char *));
+ memcpy (hostnames_rtn, hostnames, maxmappings * sizeof (char *));
+ qemudFreeDHCPHostMappings (hwaddrs + maxmappings,
+ ipaddrs + maxmappings,
+ hostnames + maxmappings,
+ nr_mappings - maxmappings);
+ ret = maxmappings;
+ }
+
+ free (hwaddrs); /* NB: Just free the arrays themselves. */
+ free (ipaddrs);
+ free (hostnames);
+
+ return ret;
+}
+
+static int
+qemudNetworkAddDHCPHostMapping (virNetworkPtr net,
+ const char *hwaddr,
+ const char *ipaddr,
+ const char *hostname,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ char buf[PATH_MAX];
+ char **hwaddrs, **ipaddrs, **hostnames;
+ int nr_mappings, i, written = 0;
+ FILE *fp;
+ struct qemud_driver *driver =
+ (struct qemud_driver *)net->conn->networkPrivateData;
+ struct qemud_network *network =
+ qemudFindNetworkByUUID(driver, net->uuid);
+
+ if (!network) {
+ qemudReportError (net->conn, NULL, net, VIR_ERR_INVALID_DOMAIN,
+ "no network with matching uuid");
+ return -1;
+ }
+
+ nr_mappings =
+ qemudParseDHCPHostMappingsFile (net, network,
+ &hwaddrs, &ipaddrs, &hostnames);
+ if (nr_mappings == -1) return -1;
+
+ snprintf (buf, sizeof buf, DHCP_HOSTS_FORMAT, network->def->name);
+ fp = fopen (buf, "w");
+ if (fp == NULL) {
+ qemudReportError (net->conn, NULL, net, VIR_ERR_SYSTEM_ERROR,
+ "%s: %s", buf, strerror (errno));
+ return -1;
+ }
+
+ for (i = 0; i < nr_mappings; ++i) {
+ if (STREQ (hwaddrs[i], hwaddr)) {
+ /* Replace this entry. */
+ fputs (hwaddr, fp);
+ fputc (',', fp);
+ fputs (ipaddr, fp);
+ if (hostname) {
+ fputc (',', fp);
+ fputs (hostname, fp);
+ }
+ fputc ('\n', fp);
+ written = 1;
+ } else {
+ /* Write this entry again. */
+ fputs (hwaddrs[i], fp);
+ fputc (',', fp);
+ fputs (ipaddrs[i], fp);
+ if (hostnames[i]) {
+ fputc (',', fp);
+ fputs (hostnames[i], fp);
+ }
+ fputc ('\n', fp);
+ }
+ }
+
+ if (!written) {
+ fputs (hwaddr, fp);
+ fputc (',', fp);
+ fputs (ipaddr, fp);
+ if (hostname) {
+ fputc (',', fp);
+ fputs (hostname, fp);
+ }
+ fputc ('\n', fp);
+ }
+
+ qemudFreeDHCPHostMappings (hwaddrs, ipaddrs, hostnames, nr_mappings);
+ free (hwaddrs);
+ free (ipaddrs);
+ free (hostnames);
+
+ if (fclose (fp) == EOF) {
+ qemudReportError (net->conn, NULL, net, VIR_ERR_SYSTEM_ERROR,
+ "%s", strerror (errno));
+ return -1;
+ }
+
+ /* Tell dnsmasq to reread the configuration file. */
+ kill (network->dnsmasqPid, SIGHUP);
+
+ return 0;
+}
+
+static int
+qemudNetworkDeleteDHCPHostMapping (virNetworkPtr net,
+ const char *hwaddr)
+{
+ char buf[PATH_MAX];
+ char **hwaddrs, **ipaddrs, **hostnames;
+ int nr_mappings, i;
+ FILE *fp;
+ struct qemud_driver *driver =
+ (struct qemud_driver *)net->conn->networkPrivateData;
+ struct qemud_network *network =
+ qemudFindNetworkByUUID(driver, net->uuid);
+
+ if (!network) {
+ qemudReportError (net->conn, NULL, net, VIR_ERR_INVALID_DOMAIN,
+ "no network with matching uuid");
+ return -1;
+ }
+
+ nr_mappings =
+ qemudParseDHCPHostMappingsFile (net, network,
+ &hwaddrs, &ipaddrs, &hostnames);
+ if (nr_mappings == -1) return -1;
+
+ snprintf (buf, sizeof buf, DHCP_HOSTS_FORMAT, network->def->name);
+ fp = fopen (buf, "w");
+ if (fp == NULL) {
+ qemudReportError (net->conn, NULL, net, VIR_ERR_SYSTEM_ERROR,
+ "%s: %s", buf, strerror (errno));
+ return -1;
+ }
+
+ for (i = 0; i < nr_mappings; ++i) {
+ if (!STREQ (hwaddrs[i], hwaddr)) {
+ /* Write this entry again. */
+ fputs (hwaddrs[i], fp);
+ fputc (',', fp);
+ fputs (ipaddrs[i], fp);
+ if (hostnames[i]) {
+ fputc (',', fp);
+ fputs (hostnames[i], fp);
+ }
+ fputc ('\n', fp);
+ }
+ }
+
+ qemudFreeDHCPHostMappings (hwaddrs, ipaddrs, hostnames, nr_mappings);
+ free (hwaddrs);
+ free (ipaddrs);
+ free (hostnames);
+
+ if (fclose (fp) == EOF) {
+ qemudReportError (net->conn, NULL, net, VIR_ERR_SYSTEM_ERROR,
+ "%s", strerror (errno));
+ return -1;
+ }
+
+ /* Tell dnsmasq to reread the configuration file. */
+ kill (network->dnsmasqPid, SIGHUP);
+
+ return 0;
+}
+
static virDriver qemuDriver = {
VIR_DRV_QEMU,
"QEMU",
@@ -3087,6 +3484,10 @@ static virNetworkDriver qemuNetworkDrive
qemudNetworkGetBridgeName, /* networkGetBridgeName */
qemudNetworkGetAutostart, /* networkGetAutostart */
qemudNetworkSetAutostart, /* networkSetAutostart */
+ qemudNetworkNumOfDHCPHostMappings, /* networkNumOfDHCPHostMappings */
+ qemudNetworkListDHCPHostMappings, /* networkListDHCPHostMappings */
+ qemudNetworkAddDHCPHostMapping, /* networkAddDHCPHostMapping */
+ qemudNetworkDeleteDHCPHostMapping, /* networkDeleteDHCPHostMapping */
};
static virStateDriver qemuStateDriver = {
Index: src/qemu_driver.h
===================================================================
RCS file: /data/cvs/libvirt/src/qemu_driver.h,v
retrieving revision 1.4
diff -u -p -r1.4 qemu_driver.h
--- src/qemu_driver.h 29 Jan 2008 18:15:54 -0000 1.4
+++ src/qemu_driver.h 9 Apr 2008 12:27:26 -0000
@@ -31,6 +31,9 @@
#include "internal.h"
+/* %s is replaced with the network name. */
+#define DHCP_HOSTS_FORMAT LOCAL_STATE_DIR "/lib/libvirt/hosts-%s.conf"
+
int qemudRegister(void);
#endif /* WITH_QEMU */
Index: src/remote_internal.c
===================================================================
RCS file: /data/cvs/libvirt/src/remote_internal.c,v
retrieving revision 1.67
diff -u -p -r1.67 remote_internal.c
--- src/remote_internal.c 4 Apr 2008 07:58:29 -0000 1.67
+++ src/remote_internal.c 9 Apr 2008 12:27:30 -0000
@@ -2721,8 +2721,117 @@ remoteNetworkSetAutostart (virNetworkPtr
return 0;
}
+static int
+remoteNetworkNumOfDHCPHostMappings (virNetworkPtr network)
+{
+ remote_network_num_of_dhcp_host_mappings_args args;
+ remote_network_num_of_dhcp_host_mappings_ret ret;
+ GET_NETWORK_PRIVATE (network->conn, -1);
+
+ make_nonnull_network (&args.net, network);
+
+ memset (&ret, 0, sizeof ret);
+ if (call (network->conn, priv, 0, REMOTE_PROC_NETWORK_NUM_OF_DHCP_HOST_MAPPINGS,
+ (xdrproc_t) xdr_remote_network_num_of_dhcp_host_mappings_args, (char *) &args,
+ (xdrproc_t) xdr_remote_network_num_of_dhcp_host_mappings_ret, (char *) &ret) == -1)
+ return -1;
+
+ return ret.num;
+}
+
+
+static int
+remoteNetworkListDHCPHostMappings (virNetworkPtr network,
+ char **const hwaddrs,
+ char **const ipaddrs,
+ char **const hostnames,
+ int maxmappings)
+{
+ remote_network_list_dhcp_host_mappings_args args;
+ remote_network_list_dhcp_host_mappings_ret ret;
+ int i;
+ GET_NETWORK_PRIVATE (network->conn, -1);
+
+ make_nonnull_network (&args.net, network);
+ args.maxmappings = maxmappings;
+
+ memset (&ret, 0, sizeof ret);
+ if (call (network->conn, priv, 0, REMOTE_PROC_NETWORK_LIST_DHCP_HOST_MAPPINGS,
+ (xdrproc_t) xdr_remote_network_list_dhcp_host_mappings_args, (char *) &args,
+ (xdrproc_t) xdr_remote_network_list_dhcp_host_mappings_ret, (char *) &ret) == -1)
+ return -1;
+
+ if (ret.hwaddrs.hwaddrs_len > maxmappings ||
+ ret.ipaddrs.ipaddrs_len > maxmappings ||
+ ret.hostnames.hostnames_len > maxmappings) {
+ error (network->conn, VIR_ERR_INTERNAL_ERROR,
+ _("remote end returned more mappings than we asked for"));
+ return -1;
+ }
+
+ if (ret.hwaddrs.hwaddrs_len != ret.ipaddrs.ipaddrs_len ||
+ ret.ipaddrs.ipaddrs_len != ret.hostnames.hostnames_len) {
+ error (network->conn, VIR_ERR_INTERNAL_ERROR,
+ _("incoherent numbers of mappings from remote end"));
+ return -1;
+ }
+ /* Caller frees. Since xdr_free will free up the strings we
+ * have to strdup them here.
+ */
+ for (i = 0; i < ret.hwaddrs.hwaddrs_len; ++i) {
+ hwaddrs[i] = strdup (ret.hwaddrs.hwaddrs_val[i]);
+ ipaddrs[i] = strdup (ret.ipaddrs.ipaddrs_val[i]);
+ /* See note in remote_protocol.x */
+ hostnames[i] =
+ STREQ (ret.hostnames.hostnames_val[i], "") ?
+ NULL : strdup (ret.hostnames.hostnames_val[i]);
+ }
+
+ return ret.hwaddrs.hwaddrs_len;
+}
+
+static int
+remoteNetworkAddDHCPHostMapping (virNetworkPtr network,
+ const char *hwaddr,
+ const char *ipaddr,
+ const char *hostname,
+ unsigned int flags)
+{
+ remote_network_add_dhcp_host_mapping_args args;
+ GET_NETWORK_PRIVATE (network->conn, -1);
+
+ make_nonnull_network (&args.net, network);
+ args.hwaddr = (char *) hwaddr;
+ args.ipaddr = (char *) ipaddr;
+ args.hostname = hostname == NULL ? NULL : (char **) &hostname;
+ args.flags = flags;
+
+ if (call (network->conn, priv, 0, REMOTE_PROC_NETWORK_ADD_DHCP_HOST_MAPPING,
+ (xdrproc_t) xdr_remote_network_add_dhcp_host_mapping_args, (char *) &args,
+ (xdrproc_t) xdr_void, (char *) NULL) == -1)
+ return -1;
+ return 0;
+}
+
+static int
+remoteNetworkDeleteDHCPHostMapping (virNetworkPtr network,
+ const char *hwaddr)
+{
+ remote_network_add_dhcp_host_mapping_args args;
+ GET_NETWORK_PRIVATE (network->conn, -1);
+
+ make_nonnull_network (&args.net, network);
+ args.hwaddr = (char *) hwaddr;
+
+ if (call (network->conn, priv, 0, REMOTE_PROC_NETWORK_DELETE_DHCP_HOST_MAPPING,
+ (xdrproc_t) xdr_remote_network_delete_dhcp_host_mapping_args, (char *) &args,
+ (xdrproc_t) xdr_void, (char *) NULL) == -1)
+ return -1;
+
+ return 0;
+}
/*----------------------------------------------------------------------*/
@@ -4751,6 +4860,10 @@ static virNetworkDriver network_driver =
.networkGetBridgeName = remoteNetworkGetBridgeName,
.networkGetAutostart = remoteNetworkGetAutostart,
.networkSetAutostart = remoteNetworkSetAutostart,
+ .networkNumOfDHCPHostMappings = remoteNetworkNumOfDHCPHostMappings,
+ .networkListDHCPHostMappings = remoteNetworkListDHCPHostMappings,
+ .networkAddDHCPHostMapping = remoteNetworkAddDHCPHostMapping,
+ .networkDeleteDHCPHostMapping = remoteNetworkDeleteDHCPHostMapping,
};
static virStorageDriver storage_driver = {
Index: src/test.c
===================================================================
RCS file: /data/cvs/libvirt/src/test.c,v
retrieving revision 1.71
diff -u -p -r1.71 test.c
--- src/test.c 8 Apr 2008 09:26:24 -0000 1.71
+++ src/test.c 9 Apr 2008 12:27:31 -0000
@@ -2089,6 +2089,10 @@ static virNetworkDriver testNetworkDrive
testNetworkGetBridgeName, /* networkGetBridgeName */
testNetworkGetAutostart, /* networkGetAutostart */
testNetworkSetAutostart, /* networkSetAutostart */
+ NULL, /* networkNumOfDHCPHostMappings */
+ NULL, /* networkListDHCPHostMappings */
+ NULL, /* networkAddDHCPHostMapping */
+ NULL, /* networkDeleteDHCPHostMapping */
};
Index: src/virsh.c
===================================================================
RCS file: /data/cvs/libvirt/src/virsh.c,v
retrieving revision 1.142
diff -u -p -r1.142 virsh.c
--- src/virsh.c 4 Apr 2008 11:20:45 -0000 1.142
+++ src/virsh.c 9 Apr 2008 12:27:35 -0000
@@ -2444,6 +2444,181 @@ cmdNetworkDestroy(vshControl * ctl, vshC
/*
+ * "net-dhcp-host-list" command
+ */
+static vshCmdInfo info_network_dhcp_host_list[] = {
+ {"syntax", "net-dhcp-host-list <network>"},
+ {"help", gettext_noop("list DHCP host mappings on a network")},
+ {"desc", gettext_noop("Returns list of DHCP host mappings on a network.")},
+ {NULL, NULL}
+};
+
+static vshCmdOptDef opts_network_dhcp_host_list[] = {
+ {"network", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("network name, id or uuid")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdNetworkDHCPHostList (vshControl *ctl, vshCmd *cmd)
+{
+ virNetworkPtr network;
+ int i, ret;
+ char *name;
+ char **hwaddrs, **ipaddrs, **hostnames;
+ int nr_mappings;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ if (!(network = vshCommandOptNetwork(ctl, cmd, "network", &name)))
+ return FALSE;
+
+ nr_mappings = virNetworkNumOfDHCPHostMappings (network);
+ if (nr_mappings == -1) {
+ virNetworkFree (network);
+ return FALSE;
+ }
+
+ ipaddrs = vshMalloc (ctl, nr_mappings * sizeof (char *));
+ hwaddrs = vshMalloc (ctl, nr_mappings * sizeof (char *));
+ hostnames = vshMalloc (ctl, nr_mappings * sizeof (char *));
+ ret =
+ virNetworkListDHCPHostMappings (network,
+ hwaddrs, ipaddrs, hostnames,
+ nr_mappings);
+
+ if (ret == -1) {
+ virNetworkFree (network);
+ free (ipaddrs);
+ free (hwaddrs);
+ free (hostnames);
+ return FALSE;
+ }
+
+ for (i = 0; i < ret; ++i) {
+ printf ("%-20s %-20s ", hwaddrs[i], ipaddrs[i]);
+ if (hostnames[i]) printf ("%s", hostnames[i]);
+ printf ("\n");
+ }
+
+ for (i = 0; i < ret; ++i) {
+ free (ipaddrs[i]);
+ free (hwaddrs[i]);
+ free (hostnames[i]);
+ }
+ free (ipaddrs);
+ free (hwaddrs);
+ free (hostnames);
+
+ virNetworkFree(network);
+
+ return TRUE;
+}
+
+
+/*
+ * "net-dhcp-host-add" command
+ */
+static vshCmdInfo info_network_dhcp_host_add[] = {
+ {"syntax", "net-dhcp-host-list <network> <hwaddr> <ipaddr> [<hostname>]"},
+ {"help", gettext_noop("add a DHCP host mappings")},
+ {"desc", gettext_noop("Adds a DHCP host mapping to the given network.")},
+ {NULL, NULL}
+};
+
+static vshCmdOptDef opts_network_dhcp_host_add[] = {
+ {"network", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("network name, id or uuid")},
+ {"hwaddr", VSH_OT_STRING, VSH_OFLAG_REQ, gettext_noop("hardware (MAC) address")},
+ {"ipaddr", VSH_OT_STRING, VSH_OFLAG_REQ, gettext_noop("IP address")},
+ {"hostname", VSH_OT_STRING, VSH_OFLAG_NONE, gettext_noop("optional hostname to assign over DHCP")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdNetworkDHCPHostAdd (vshControl *ctl, vshCmd *cmd)
+{
+ virNetworkPtr network;
+ int ret;
+ char *name;
+ char *hwaddr, *ipaddr, *hostname;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ if (!(network = vshCommandOptNetwork(ctl, cmd, "network", &name)))
+ return FALSE;
+
+ if (!(hwaddr = vshCommandOptString (cmd, "hwaddr", NULL))) {
+ virNetworkFree (network);
+ return FALSE;
+ }
+ if (!(ipaddr = vshCommandOptString (cmd, "ipaddr", NULL))) {
+ virNetworkFree (network);
+ return FALSE;
+ }
+
+ hostname = vshCommandOptString (cmd, "hostname", NULL);
+
+ ret = virNetworkAddDHCPHostMapping (network, hwaddr, ipaddr, hostname, 0);
+ if (ret == -1) {
+ virNetworkFree (network);
+ return FALSE;
+ }
+
+ virNetworkFree(network);
+
+ return TRUE;
+}
+
+
+/*
+ * "net-dhcp-host-delete" command
+ */
+static vshCmdInfo info_network_dhcp_host_delete[] = {
+ {"syntax", "net-dhcp-host-list <network> <hwaddr>"},
+ {"help", gettext_noop("delete a DHCP host mappings")},
+ {"desc", gettext_noop("Deletes a DHCP host mapping from the given network.")},
+ {NULL, NULL}
+};
+
+static vshCmdOptDef opts_network_dhcp_host_delete[] = {
+ {"network", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("network name, id or uuid")},
+ {"hwaddr", VSH_OT_STRING, VSH_OFLAG_REQ, gettext_noop("hardware (MAC) address")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdNetworkDHCPHostDelete (vshControl *ctl, vshCmd *cmd)
+{
+ virNetworkPtr network;
+ int ret;
+ char *name;
+ char *hwaddr;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ if (!(network = vshCommandOptNetwork(ctl, cmd, "network", &name)))
+ return FALSE;
+
+ if (!(hwaddr = vshCommandOptString (cmd, "hwaddr", NULL))) {
+ virNetworkFree (network);
+ return FALSE;
+ }
+
+ ret = virNetworkDeleteDHCPHostMapping (network, hwaddr);
+ if (ret == -1) {
+ virNetworkFree (network);
+ return FALSE;
+ }
+
+ virNetworkFree(network);
+
+ return TRUE;
+}
+
+
+/*
* "net-dumpxml" command
*/
static vshCmdInfo info_network_dumpxml[] = {
@@ -5118,6 +5293,9 @@ static vshCmdDef commands[] = {
{"net-create", cmdNetworkCreate, opts_network_create, info_network_create},
{"net-define", cmdNetworkDefine, opts_network_define, info_network_define},
{"net-destroy", cmdNetworkDestroy, opts_network_destroy, info_network_destroy},
+ {"net-dhcp-host-add", cmdNetworkDHCPHostAdd, opts_network_dhcp_host_add, info_network_dhcp_host_add},
+ {"net-dhcp-host-delete", cmdNetworkDHCPHostDelete, opts_network_dhcp_host_delete, info_network_dhcp_host_delete},
+ {"net-dhcp-host-list", cmdNetworkDHCPHostList, opts_network_dhcp_host_list, info_network_dhcp_host_list},
{"net-dumpxml", cmdNetworkDumpXML, opts_network_dumpxml, info_network_dumpxml},
{"net-list", cmdNetworkList, opts_network_list, info_network_list},
{"net-name", cmdNetworkName, opts_network_name, info_network_name},
More information about the libvir-list
mailing list