mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 17:34:18 +03:00
net-dhcp-leases: Implement the remote protocol
Implement RPC calls for virNetworkGetDHCPLeases, virNetworkGetDHCPLeasesForMAC daemon/remote.c * Define remoteSerializeNetworkDHCPLeases, remoteDispatchNetworkGetDHCPLeases * Define remoteDispatchNetworkGetDHCPLeasesForMAC * Define helper function remoteSerializeDHCPLease src/remote/remote_driver.c * Define remoteNetworkGetDHCPLeases * Define remoteNetworkGetDHCPLeasesForMAC * Define helper function remoteSerializeDHCPLease src/remote/remote_protocol.x * New RPC procedure: REMOTE_PROC_NETWORK_GET_DHCP_LEASES * Define structs remote_network_dhcp_leases, remote_network_get_dhcp_leases_args, remote_network_get_dhcp_leases_ret * New RPC procedure: REMOTE_PROC_NETWORK_GET_DHCP_LEASES_FOR_MAC * Define structs remote_network_dhcp_leases_for_mac, remote_network_get_dhcp_leases_for_mac_args, remote_network_get_dhcp_leases_for_mac_ret src/remote_protocol-structs * New structs added src/rpc/gendispatch.pl * Add exception (s/Dhcp/DHCP) for auto-generating names of the remote functions in daemon/remote_dispatch.h
This commit is contained in:
parent
03e0e79e07
commit
990c3b6554
183
daemon/remote.c
183
daemon/remote.c
@ -6202,7 +6202,190 @@ remoteDispatchNodeGetFreePages(virNetServerPtr server ATTRIBUTE_UNUSED,
|
||||
VIR_FREE(ret->counts.counts_val);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Copy contents of virNetworkDHCPLeasePtr to remote_network_dhcp_lease */
|
||||
static int
|
||||
remoteSerializeDHCPLease(remote_network_dhcp_lease *lease_dst, virNetworkDHCPLeasePtr lease_src)
|
||||
{
|
||||
char **mac_tmp = NULL;
|
||||
char **iaid_tmp = NULL;
|
||||
char **hostname_tmp = NULL;
|
||||
char **clientid_tmp = NULL;
|
||||
|
||||
if (VIR_ALLOC(mac_tmp) < 0 ||
|
||||
VIR_ALLOC(iaid_tmp) < 0 ||
|
||||
VIR_ALLOC(hostname_tmp) < 0 ||
|
||||
VIR_ALLOC(clientid_tmp) < 0)
|
||||
goto error;
|
||||
|
||||
lease_dst->expirytime = lease_src->expirytime;
|
||||
lease_dst->type = lease_src->type;
|
||||
lease_dst->prefix = lease_src->prefix;
|
||||
|
||||
if (VIR_STRDUP(lease_dst->interface, lease_src->interface) < 0 ||
|
||||
VIR_STRDUP(lease_dst->ipaddr, lease_src->ipaddr) < 0 ||
|
||||
VIR_STRDUP(*mac_tmp, lease_src->mac) < 0 ||
|
||||
VIR_STRDUP(*iaid_tmp, lease_src->iaid) < 0 ||
|
||||
VIR_STRDUP(*hostname_tmp, lease_src->hostname) < 0 ||
|
||||
VIR_STRDUP(*clientid_tmp, lease_src->clientid) < 0)
|
||||
goto error;
|
||||
|
||||
lease_dst->mac = *mac_tmp ? mac_tmp : NULL;
|
||||
lease_dst->iaid = *iaid_tmp ? iaid_tmp : NULL;
|
||||
lease_dst->hostname = *hostname_tmp ? hostname_tmp : NULL;
|
||||
lease_dst->clientid = *clientid_tmp ? clientid_tmp : NULL;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
VIR_FREE(*mac_tmp);
|
||||
VIR_FREE(*iaid_tmp);
|
||||
VIR_FREE(*hostname_tmp);
|
||||
VIR_FREE(*clientid_tmp);
|
||||
VIR_FREE(mac_tmp);
|
||||
VIR_FREE(iaid_tmp);
|
||||
VIR_FREE(hostname_tmp);
|
||||
VIR_FREE(clientid_tmp);
|
||||
VIR_FREE(lease_dst->ipaddr);
|
||||
VIR_FREE(lease_dst->interface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
remoteDispatchNetworkGetDHCPLeases(virNetServerPtr server ATTRIBUTE_UNUSED,
|
||||
virNetServerClientPtr client,
|
||||
virNetMessagePtr msg ATTRIBUTE_UNUSED,
|
||||
virNetMessageErrorPtr rerr,
|
||||
remote_network_get_dhcp_leases_args *args,
|
||||
remote_network_get_dhcp_leases_ret *ret)
|
||||
{
|
||||
int rv = -1;
|
||||
size_t i;
|
||||
struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
|
||||
virNetworkDHCPLeasePtr *leases = NULL;
|
||||
virNetworkPtr net = NULL;
|
||||
int nleases = 0;
|
||||
|
||||
if (!priv->conn) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!(net = get_nonnull_network(priv->conn, args->net)))
|
||||
goto cleanup;
|
||||
|
||||
if ((nleases = virNetworkGetDHCPLeases(net,
|
||||
args->need_results ? &leases : NULL,
|
||||
args->flags)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (nleases > REMOTE_NETWORK_DHCP_LEASES_MAX) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Number of leases is %d, which exceeds max limit: %d"),
|
||||
nleases, REMOTE_NETWORK_DHCP_LEASES_MAX);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (leases && nleases) {
|
||||
if (VIR_ALLOC_N(ret->leases.leases_val, nleases) < 0)
|
||||
goto cleanup;
|
||||
|
||||
ret->leases.leases_len = nleases;
|
||||
|
||||
for (i = 0; i < nleases; i++) {
|
||||
if (remoteSerializeDHCPLease(ret->leases.leases_val + i, leases[i]) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
} else {
|
||||
ret->leases.leases_len = 0;
|
||||
ret->leases.leases_val = NULL;
|
||||
}
|
||||
|
||||
ret->ret = nleases;
|
||||
|
||||
rv = 0;
|
||||
|
||||
cleanup:
|
||||
if (rv < 0)
|
||||
virNetMessageSaveError(rerr);
|
||||
if (leases) {
|
||||
for (i = 0; i < nleases; i++)
|
||||
virNetworkDHCPLeaseFree(leases[i]);
|
||||
VIR_FREE(leases);
|
||||
}
|
||||
virNetworkFree(net);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
remoteDispatchNetworkGetDHCPLeasesForMAC(virNetServerPtr server ATTRIBUTE_UNUSED,
|
||||
virNetServerClientPtr client,
|
||||
virNetMessagePtr msg ATTRIBUTE_UNUSED,
|
||||
virNetMessageErrorPtr rerr,
|
||||
remote_network_get_dhcp_leases_for_mac_args *args,
|
||||
remote_network_get_dhcp_leases_for_mac_ret *ret)
|
||||
{
|
||||
int rv = -1;
|
||||
size_t i;
|
||||
struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
|
||||
virNetworkDHCPLeasePtr *leases = NULL;
|
||||
virNetworkPtr net = NULL;
|
||||
int nleases = 0;
|
||||
|
||||
if (!priv->conn) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!(net = get_nonnull_network(priv->conn, args->net)))
|
||||
goto cleanup;
|
||||
|
||||
if ((nleases = virNetworkGetDHCPLeasesForMAC(net, args->mac,
|
||||
args->need_results ? &leases : NULL,
|
||||
args->flags)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (nleases > REMOTE_NETWORK_DHCP_LEASES_MAX) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Number of leases is %d, which exceeds max limit: %d"),
|
||||
nleases, REMOTE_NETWORK_DHCP_LEASES_MAX);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (leases && nleases) {
|
||||
if (VIR_ALLOC_N(ret->leases.leases_val, nleases) < 0)
|
||||
goto cleanup;
|
||||
|
||||
ret->leases.leases_len = nleases;
|
||||
|
||||
for (i = 0; i < nleases; i++) {
|
||||
if (remoteSerializeDHCPLease(ret->leases.leases_val + i, leases[i]) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
} else {
|
||||
ret->leases.leases_len = 0;
|
||||
ret->leases.leases_val = NULL;
|
||||
}
|
||||
|
||||
ret->ret = nleases;
|
||||
|
||||
rv = 0;
|
||||
|
||||
cleanup:
|
||||
if (rv < 0)
|
||||
virNetMessageSaveError(rerr);
|
||||
if (leases) {
|
||||
for (i = 0; i < nleases; i++)
|
||||
virNetworkDHCPLeaseFree(leases[i]);
|
||||
VIR_FREE(leases);
|
||||
}
|
||||
virNetworkFree(net);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
@ -7549,6 +7549,190 @@ remoteNodeGetFreePages(virConnectPtr conn,
|
||||
}
|
||||
|
||||
|
||||
/* Copy contents of remote_network_dhcp_lease to virNetworkDHCPLeasePtr */
|
||||
static int
|
||||
remoteSerializeDHCPLease(virNetworkDHCPLeasePtr lease_dst, remote_network_dhcp_lease *lease_src)
|
||||
{
|
||||
lease_dst->expirytime = lease_src->expirytime;
|
||||
lease_dst->type = lease_src->type;
|
||||
lease_dst->prefix = lease_src->prefix;
|
||||
|
||||
if (VIR_STRDUP(lease_dst->interface, lease_src->interface) < 0)
|
||||
goto error;
|
||||
|
||||
if (VIR_STRDUP(lease_dst->ipaddr, lease_src->ipaddr) < 0)
|
||||
goto error;
|
||||
|
||||
if (lease_src->mac) {
|
||||
if (VIR_STRDUP(lease_dst->mac, *lease_src->mac) < 0)
|
||||
goto error;
|
||||
} else {
|
||||
lease_src->mac = NULL;
|
||||
}
|
||||
|
||||
if (lease_src->iaid) {
|
||||
if (VIR_STRDUP(lease_dst->iaid, *lease_src->iaid) < 0)
|
||||
goto error;
|
||||
} else {
|
||||
lease_src->iaid = NULL;
|
||||
}
|
||||
|
||||
if (lease_src->hostname) {
|
||||
if (VIR_STRDUP(lease_dst->hostname, *lease_src->hostname) < 0)
|
||||
goto error;
|
||||
} else {
|
||||
lease_src->hostname = NULL;
|
||||
}
|
||||
|
||||
if (lease_src->clientid) {
|
||||
if (VIR_STRDUP(lease_dst->clientid, *lease_src->clientid) < 0)
|
||||
goto error;
|
||||
} else {
|
||||
lease_src->clientid = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
virNetworkDHCPLeaseFree(lease_dst);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
remoteNetworkGetDHCPLeases(virNetworkPtr net,
|
||||
virNetworkDHCPLeasePtr **leases,
|
||||
unsigned int flags)
|
||||
{
|
||||
int rv = -1;
|
||||
size_t i;
|
||||
struct private_data *priv = net->conn->networkPrivateData;
|
||||
remote_network_get_dhcp_leases_args args;
|
||||
remote_network_get_dhcp_leases_ret ret;
|
||||
|
||||
virNetworkDHCPLeasePtr *leases_ret = NULL;
|
||||
remoteDriverLock(priv);
|
||||
|
||||
make_nonnull_network(&args.net, net);
|
||||
args.flags = flags;
|
||||
args.need_results = !!leases;
|
||||
|
||||
memset(&ret, 0, sizeof(ret));
|
||||
|
||||
if (call(net->conn, priv, 0, REMOTE_PROC_NETWORK_GET_DHCP_LEASES,
|
||||
(xdrproc_t)xdr_remote_network_get_dhcp_leases_args, (char *)&args,
|
||||
(xdrproc_t)xdr_remote_network_get_dhcp_leases_ret, (char *)&ret) == -1)
|
||||
goto done;
|
||||
|
||||
if (ret.leases.leases_len > REMOTE_NETWORK_DHCP_LEASES_MAX) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Number of leases is %d, which exceeds max limit: %d"),
|
||||
ret.leases.leases_len, REMOTE_NETWORK_DHCP_LEASES_MAX);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (leases) {
|
||||
if (ret.leases.leases_len &&
|
||||
VIR_ALLOC_N(leases_ret, ret.leases.leases_len + 1) < 0)
|
||||
goto cleanup;
|
||||
|
||||
for (i = 0; i < ret.leases.leases_len; i++) {
|
||||
if (VIR_ALLOC(leases_ret[i]) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (remoteSerializeDHCPLease(leases_ret[i], &ret.leases.leases_val[i]) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*leases = leases_ret;
|
||||
leases_ret = NULL;
|
||||
}
|
||||
|
||||
rv = ret.ret;
|
||||
|
||||
cleanup:
|
||||
if (leases_ret) {
|
||||
for (i = 0; i < ret.leases.leases_len; i++)
|
||||
virNetworkDHCPLeaseFree(leases_ret[i]);
|
||||
VIR_FREE(leases_ret);
|
||||
}
|
||||
xdr_free((xdrproc_t)xdr_remote_network_get_dhcp_leases_ret,
|
||||
(char *) &ret);
|
||||
|
||||
done:
|
||||
remoteDriverUnlock(priv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
remoteNetworkGetDHCPLeasesForMAC(virNetworkPtr net,
|
||||
const char *mac,
|
||||
virNetworkDHCPLeasePtr **leases,
|
||||
unsigned int flags)
|
||||
{
|
||||
int rv = -1;
|
||||
size_t i;
|
||||
struct private_data *priv = net->conn->networkPrivateData;
|
||||
remote_network_get_dhcp_leases_for_mac_args args;
|
||||
remote_network_get_dhcp_leases_for_mac_ret ret;
|
||||
|
||||
virNetworkDHCPLeasePtr *leases_ret = NULL;
|
||||
remoteDriverLock(priv);
|
||||
|
||||
make_nonnull_network(&args.net, net);
|
||||
args.mac = (char *) mac;
|
||||
args.flags = flags;
|
||||
args.need_results = !!leases;
|
||||
|
||||
memset(&ret, 0, sizeof(ret));
|
||||
|
||||
if (call(net->conn, priv, 0, REMOTE_PROC_NETWORK_GET_DHCP_LEASES_FOR_MAC,
|
||||
(xdrproc_t)xdr_remote_network_get_dhcp_leases_for_mac_args, (char *)&args,
|
||||
(xdrproc_t)xdr_remote_network_get_dhcp_leases_for_mac_ret, (char *)&ret) == -1)
|
||||
goto done;
|
||||
|
||||
if (ret.leases.leases_len > REMOTE_NETWORK_DHCP_LEASES_MAX) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Number of leases is %d, which exceeds max limit: %d"),
|
||||
ret.leases.leases_len, REMOTE_NETWORK_DHCP_LEASES_MAX);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (leases) {
|
||||
if (ret.leases.leases_len &&
|
||||
VIR_ALLOC_N(leases_ret, ret.leases.leases_len + 1) < 0)
|
||||
goto cleanup;
|
||||
|
||||
for (i = 0; i < ret.leases.leases_len; i++) {
|
||||
if (VIR_ALLOC(leases_ret[i]) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (remoteSerializeDHCPLease(leases_ret[i], &ret.leases.leases_val[i]) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*leases = leases_ret;
|
||||
leases_ret = NULL;
|
||||
}
|
||||
|
||||
rv = ret.ret;
|
||||
|
||||
cleanup:
|
||||
if (leases_ret) {
|
||||
for (i = 0; i < ret.leases.leases_len; i++)
|
||||
virNetworkDHCPLeaseFree(leases_ret[i]);
|
||||
VIR_FREE(leases_ret);
|
||||
}
|
||||
xdr_free((xdrproc_t)xdr_remote_network_get_dhcp_leases_for_mac_ret,
|
||||
(char *) &ret);
|
||||
|
||||
done:
|
||||
remoteDriverUnlock(priv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/* get_nonnull_domain and get_nonnull_network turn an on-wire
|
||||
* (name, uuid) pair into virDomainPtr or virNetworkPtr object.
|
||||
* These can return NULL if underlying memory allocations fail,
|
||||
@ -7913,6 +8097,8 @@ static virNetworkDriver network_driver = {
|
||||
.networkSetAutostart = remoteNetworkSetAutostart, /* 0.3.0 */
|
||||
.networkIsActive = remoteNetworkIsActive, /* 0.7.3 */
|
||||
.networkIsPersistent = remoteNetworkIsPersistent, /* 0.7.3 */
|
||||
.networkGetDHCPLeases = remoteNetworkGetDHCPLeases, /* 1.2.6 */
|
||||
.networkGetDHCPLeasesForMAC = remoteNetworkGetDHCPLeasesForMAC, /* 1.2.6 */
|
||||
};
|
||||
|
||||
static virInterfaceDriver interface_driver = {
|
||||
|
@ -238,6 +238,9 @@ const REMOTE_CONNECT_CPU_MODELS_MAX = 8192;
|
||||
/* Upper limit on number of mountpoints to frozen */
|
||||
const REMOTE_DOMAIN_FSFREEZE_MOUNTPOINTS_MAX = 256;
|
||||
|
||||
/* Upper limit on the maximum number of leases in one lease file */
|
||||
const REMOTE_NETWORK_DHCP_LEASES_MAX = 65536;
|
||||
|
||||
/* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */
|
||||
typedef opaque remote_uuid[VIR_UUID_BUFLEN];
|
||||
|
||||
@ -3018,6 +3021,40 @@ struct remote_node_get_free_pages_ret {
|
||||
unsigned hyper counts<REMOTE_NODE_MAX_CELLS>;
|
||||
};
|
||||
|
||||
struct remote_network_dhcp_lease {
|
||||
remote_nonnull_string interface;
|
||||
hyper expirytime;
|
||||
int type;
|
||||
remote_string mac;
|
||||
remote_string iaid;
|
||||
remote_nonnull_string ipaddr;
|
||||
unsigned int prefix;
|
||||
remote_string hostname;
|
||||
remote_string clientid;
|
||||
};
|
||||
|
||||
struct remote_network_get_dhcp_leases_args {
|
||||
remote_nonnull_network net;
|
||||
int need_results;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
struct remote_network_get_dhcp_leases_ret {
|
||||
remote_network_dhcp_lease leases<REMOTE_NETWORK_DHCP_LEASES_MAX>;
|
||||
unsigned int ret;
|
||||
};
|
||||
|
||||
struct remote_network_get_dhcp_leases_for_mac_args {
|
||||
remote_nonnull_network net;
|
||||
remote_nonnull_string mac;
|
||||
int need_results;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
struct remote_network_get_dhcp_leases_for_mac_ret {
|
||||
remote_network_dhcp_lease leases<REMOTE_NETWORK_DHCP_LEASES_MAX>;
|
||||
unsigned int ret;
|
||||
};
|
||||
|
||||
/*----- Protocol. -----*/
|
||||
|
||||
@ -5370,5 +5407,17 @@ enum remote_procedure {
|
||||
* @priority: high
|
||||
* @acl: connect:read
|
||||
*/
|
||||
REMOTE_PROC_NODE_GET_FREE_PAGES = 340
|
||||
REMOTE_PROC_NODE_GET_FREE_PAGES = 340,
|
||||
|
||||
/**
|
||||
* @generate: none
|
||||
* @acl: network:read
|
||||
*/
|
||||
REMOTE_PROC_NETWORK_GET_DHCP_LEASES = 341,
|
||||
|
||||
/**
|
||||
* @generate: none
|
||||
* @acl: network:read
|
||||
*/
|
||||
REMOTE_PROC_NETWORK_GET_DHCP_LEASES_FOR_MAC = 342
|
||||
};
|
||||
|
@ -2485,6 +2485,42 @@ struct remote_node_get_free_pages_ret {
|
||||
uint64_t * counts_val;
|
||||
} counts;
|
||||
};
|
||||
struct remote_network_dhcp_lease {
|
||||
remote_nonnull_string interface;
|
||||
int64_t expirytime;
|
||||
int type;
|
||||
remote_string mac;
|
||||
remote_string iaid;
|
||||
remote_nonnull_string ipaddr;
|
||||
u_int prefix;
|
||||
remote_string hostname;
|
||||
remote_string clientid;
|
||||
};
|
||||
struct remote_network_get_dhcp_leases_args {
|
||||
remote_nonnull_network net;
|
||||
int need_results;
|
||||
u_int flags;
|
||||
};
|
||||
struct remote_network_get_dhcp_leases_ret {
|
||||
struct {
|
||||
u_int leases_len;
|
||||
remote_network_dhcp_lease * leases_val;
|
||||
} leases;
|
||||
u_int ret;
|
||||
};
|
||||
struct remote_network_get_dhcp_leases_for_mac_args {
|
||||
remote_nonnull_network net;
|
||||
remote_nonnull_string mac;
|
||||
int need_results;
|
||||
u_int flags;
|
||||
};
|
||||
struct remote_network_get_dhcp_leases_for_mac_ret {
|
||||
struct {
|
||||
u_int leases_len;
|
||||
remote_network_dhcp_lease * leases_val;
|
||||
} leases;
|
||||
u_int ret;
|
||||
};
|
||||
enum remote_procedure {
|
||||
REMOTE_PROC_CONNECT_OPEN = 1,
|
||||
REMOTE_PROC_CONNECT_CLOSE = 2,
|
||||
@ -2826,4 +2862,6 @@ enum remote_procedure {
|
||||
REMOTE_PROC_DOMAIN_SET_TIME = 338,
|
||||
REMOTE_PROC_DOMAIN_EVENT_BLOCK_JOB_2 = 339,
|
||||
REMOTE_PROC_NODE_GET_FREE_PAGES = 340,
|
||||
REMOTE_PROC_NETWORK_GET_DHCP_LEASES = 341,
|
||||
REMOTE_PROC_NETWORK_GET_DHCP_LEASES_FOR_MAC = 342,
|
||||
};
|
||||
|
@ -68,6 +68,7 @@ sub fixup_name {
|
||||
$name =~ s/Fsthaw$/FSThaw/;
|
||||
$name =~ s/Scsi/SCSI/;
|
||||
$name =~ s/Wwn$/WWN/;
|
||||
$name =~ s/Dhcp$/DHCP/;
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user