This patch add EthernetPort. EthernetPort is always a port on a switch,
So eth0.10 is modeled as VS_eth0/EP_eth0.10, and eth0 is modeled as
VS_eth0/EP_Eth0.
To make things simple enough, EtherPort belongs to VMs, are excluded from
the patch and still be modeled as NetworkPort. This means the patch only
concern about network on host side.
V7: no change.
V6: minior change according to comments.
V5: almost the same with V2.
Signed-off-by: Wenchao Xia <xiawenc(a)linux.vnet.ibm.com>
---
schema/EthernetPort.mof | 4 +
schema/EthernetPort.registration | 3 +
src/Virt_EthernetPort.c | 561 ++++++++++++++++++++++++++++++++++++++
src/Virt_EthernetPort.h | 58 ++++
4 files changed, 626 insertions(+), 0 deletions(-)
create mode 100644 schema/EthernetPort.mof
create mode 100644 schema/EthernetPort.registration
create mode 100644 src/Virt_EthernetPort.c
create mode 100644 src/Virt_EthernetPort.h
diff --git a/schema/EthernetPort.mof b/schema/EthernetPort.mof
new file mode 100644
index 0000000..9d5e23e
--- /dev/null
+++ b/schema/EthernetPort.mof
@@ -0,0 +1,4 @@
+// Copyright IBM Corp. 2012
+class Net_EthernetPort : CIM_EthernetPort
+{
+};
diff --git a/schema/EthernetPort.registration b/schema/EthernetPort.registration
new file mode 100644
index 0000000..e0e0f0c
--- /dev/null
+++ b/schema/EthernetPort.registration
@@ -0,0 +1,3 @@
+# Copyright IBM Corp. 2012
+# Classname Namespace ProviderName ProviderModule ProviderTypes
+Net_EthernetPort root/virt Virt_EthernetPort Virt_EthernetPort instance
diff --git a/src/Virt_EthernetPort.c b/src/Virt_EthernetPort.c
new file mode 100644
index 0000000..cdef910
--- /dev/null
+++ b/src/Virt_EthernetPort.c
@@ -0,0 +1,561 @@
+/*
+ * Copyright IBM Corp. 2007
+ *
+ * Authors:
+ * Wenchao Xia <xiawenc(a)cn.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+
+#include <cmpidt.h>
+#include <cmpift.h>
+#include <cmpimacs.h>
+
+#include <libcmpiutil/libcmpiutil.h>
+#include <libcmpiutil/std_instance.h>
+
+#include "misc_util.h"
+#include "cs_util.h"
+#include "device_parsing.h"
+#include "network_model_helper.h"
+
+#include "Virt_EthernetPort.h"
+
+static const CMPIBroker *_BROKER;
+
+static int set_primary_for_ep(const CMPIBroker *broker, const char* prefix,
+ struct EthIface *piface, CMPIInstance *instance)
+{
+ char *eth_name, *ep_name;
+ const char *syscls_name = "Virt_VirtualEthernetSwitchSystem";
+ int asret;
+
+ if (piface->name == NULL) {
+ return 0;
+ }
+
+ eth_name = get_ethport_name_from_iface(piface->name);
+ asret = asprintf(&ep_name, "%s/%s", prefix, eth_name);
+
+ CMSetProperty(instance, "DeviceID",
+ (CMPIValue *)ep_name, CMPI_chars);
+
+ CMSetProperty(instance, "InstanceID",
+ (CMPIValue *)ep_name, CMPI_chars);
+
+ CMSetProperty(instance, "ElementName",
+ (CMPIValue *)eth_name, CMPI_chars);
+ CU_FREE(ep_name);
+ CU_FREE(eth_name);
+
+ CMSetProperty(instance, "SystemCreationClassName",
+ (CMPIValue *)syscls_name, CMPI_chars);
+
+ CMSetProperty(instance, "SystemName",
+ (CMPIValue *)prefix, CMPI_chars);
+
+ return 1;
+}
+
+static int set_secondary_for_ep(const CMPIBroker *broker,
+ struct EthIface *piface, CMPIInstance *instance)
+{
+ int state;
+ uint16_t cim_type;
+ CMPIArray *array;
+ CMPIStatus s;
+ CMPIString *str;
+
+ if (piface->run_prop.status == ETH_STATE_INACTIVE) {
+ state = CIM_STATE_DISABLED;
+ } else if (piface->run_prop.status == ETH_STATE_ACTIVE) {
+ state = CIM_STATE_ENABLED;
+ } else {
+ state = CIM_STATE_UNKNOWN;
+ }
+ CMSetProperty(instance, "EnabledState",
+ (CMPIValue *)&state, CMPI_uint16);
+ CMSetProperty(instance, "RequestedState",
+ (CMPIValue *)&state, CMPI_uint16);
+
+ cim_type = CIM_NUM_NET_ETHERNET;
+ CMSetProperty(instance, "LinkTechnology",
+ (CMPIValue *)&cim_type, CMPI_uint16);
+
+ if (piface->mac != NULL) {
+ array = CMNewArray(broker, 1, CMPI_string, &s);
+ if ((s.rc != CMPI_RC_OK) || (CMIsNullObject(array))) {
+ CU_DEBUG("failed to create array.");
+ return 0;
+ }
+ str = CMNewString(broker, piface->mac, &s);
+ if ((s.rc != CMPI_RC_OK) || (CMIsNullObject(str))) {
+ CU_DEBUG("failed to create array.");
+ return 0;
+ }
+
+ CMSetArrayElementAt(array, 0, &str, CMPI_string);
+
+ CMSetProperty(instance, "NetworkAddresses",
+ (CMPIValue *)&array, CMPI_stringA);
+ }
+
+ return 1;
+}
+
+static CMPIStatus set_properties(const CMPIBroker *broker,
+ struct EthIface *piface,
+ const char *prefix,
+ CMPIInstance *instance)
+{
+ CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL};
+ char *errstr = NULL;
+
+ if (!set_primary_for_ep(broker, prefix, piface, instance)) {
+ errstr = "failed to set primary properties for instance.";
+ CU_DEBUG("%s, iface name %s.", errstr, piface->name);
+ cu_statusf(broker, &s,
+ CMPI_RC_ERR_FAILED,
+ errstr);
+ goto out;
+ }
+
+ if (!set_secondary_for_ep(broker, piface, instance)) {
+ errstr = "failed to set secondary properties for instance.";
+ CU_DEBUG("%s, iface name %s.", errstr, piface->name);
+ cu_statusf(broker, &s,
+ CMPI_RC_ERR_FAILED,
+ errstr);
+ goto out;
+ }
+
+ cu_statusf(broker, &s,
+ CMPI_RC_OK,
+ "");
+
+ out:
+ return s;
+}
+
+
+static CMPIStatus instance_from_ep_build(const CMPIBroker *broker,
+ struct EthIface *piface,
+ const char *prefix,
+ const CMPIObjectPath *reference,
+ const char **properties,
+ CMPIInstance **_inst)
+{
+ CMPIInstance *inst = NULL;
+ CMPIStatus s = {CMPI_RC_OK, NULL};
+ const char *keys[] = {"InstanceID", NULL};
+
+ inst = get_typed_instance(broker,
+ NETWORK_CLASS_PREFIX,
+ "EthernetPort",
+ NAMESPACE(reference));
+ if (inst == NULL) {
+ cu_statusf(broker, &s,
+ CMPI_RC_ERR_FAILED,
+ "Unable to init ep instance");
+ goto out;
+ }
+
+ s = CMSetPropertyFilter(inst, properties, keys);
+ if (s.rc != CMPI_RC_OK) {
+ CU_DEBUG("Unable to set property filter: %d", s.rc);
+ }
+
+ s = set_properties(broker,
+ piface,
+ prefix,
+ inst);
+
+ if (s.rc != CMPI_RC_OK) {
+ goto out;
+ }
+
+ *_inst = inst;
+
+ out:
+ return s;
+}
+
+
+static CMPIStatus instance_from_ep(const CMPIBroker *broker,
+ struct EthIface *piface,
+ const char *vsname,
+ const CMPIObjectPath *reference,
+ const char **properties,
+ struct inst_list *plist)
+{
+
+ CMPIStatus s = {CMPI_RC_OK, NULL};
+ CMPIInstance *inst = NULL;
+ char *br1_name = NULL, *br2_name = NULL;
+
+ get_possible_bridge_name_for_cim_model(piface, &br1_name, &br2_name);
+ if (br1_name == NULL) {
+ cu_statusf(broker, &s,
+ CMPI_RC_ERR_FAILED,
+ "failed to find any bridge for the port.");
+ CU_DEBUG("failed to find any bridge for the port %s.",
+ piface->name);
+ goto out;
+ }
+
+ /* building up the instance */
+ if ((vsname == NULL) || (0 == strcmp(vsname, br1_name))) {
+ inst = NULL;
+ s = instance_from_ep_build(broker,
+ piface,
+ br1_name,
+ reference,
+ properties,
+ &inst);
+ if (s.rc != CMPI_RC_OK) {
+ goto out;
+ }
+ inst_list_add(plist, inst);
+ }
+
+ /* following is to make it comform to CIM profile which require two
+ ethports connectted to pNIC and vswitch, but we have only one piface
+ on linux indicating it is connected to pNIC and bridge at sametime */
+ if (br2_name == NULL) {
+ goto out;
+ }
+
+ if ((vsname == NULL) || (0 == strcmp(vsname, br2_name))) {
+ inst = NULL;
+ s = instance_from_ep_build(broker,
+ piface,
+ br2_name,
+ reference,
+ properties,
+ &inst);
+ if (s.rc != CMPI_RC_OK) {
+ goto out;
+ }
+ inst_list_add(plist, inst);
+ }
+
+
+ out:
+ CU_FREE(br1_name);
+ CU_FREE(br2_name);
+ return s;
+}
+
+CMPIStatus get_ep_by_name(const CMPIBroker *broker,
+ const char *prefix,
+ const char *name,
+ const CMPIObjectPath *reference,
+ const char **properties,
+ CMPIInstance **_inst)
+{
+ CMPIStatus s = {CMPI_RC_OK, NULL};
+ CMPIInstance *inst = NULL;
+ char *eth_name = NULL;
+ char *dest = NULL;
+ char *errstr;
+ int ret;
+ struct EthIfacesList ifaces_list;
+ struct inst_list list;
+
+ eth_ifaceslist_init(&ifaces_list);
+ inst_list_init(&list);
+
+ eth_name = get_iface_name_from_ethport(name);
+ if (eth_name == NULL) {
+ cu_statusf(broker, &s,
+ CMPI_RC_ERR_FAILED,
+ "failed to convert instance name");
+ CU_DEBUG("ethport name %s failed to convert.", name);
+ goto out;
+ }
+
+ ret = get_host_ifaces(&ifaces_list,
+ eth_iface_filter_cim_ethport_for_name, eth_name);
+
+ if (ret != 1) {
+ errstr = get_host_iface_error_reason(ret);
+ CU_DEBUG("error num %d returned, reason %s.", ret, errstr);
+ cu_statusf(broker, &s,
+ CMPI_RC_ERR_FAILED,
+ errstr);
+ goto out;
+ }
+ if (ifaces_list.count != 1) {
+ errstr = "expected ethport not found.";
+ CU_DEBUG("%s\n", errstr);
+ eth_ifaceslist_print(&ifaces_list);
+ cu_statusf(broker, &s,
+ CMPI_RC_ERR_FAILED,
+ errstr);
+ goto out;
+ }
+
+ inst = NULL;
+ s = instance_from_ep(broker,
+ ifaces_list.pifaces[0],
+ prefix,
+ reference,
+ properties,
+ &list);
+
+ if (s.rc != CMPI_RC_OK) {
+ goto out;
+ }
+
+ if (list.cur == 0) {
+ CU_DEBUG("%d instance found, expect is 1.", list.cur);
+ cu_statusf(broker, &s,
+ CMPI_RC_ERR_FAILED,
+ "no such instance.");
+ goto out;
+ }
+
+ if (list.cur > 1) {
+ CU_DEBUG("%d instance found, expect is 1.", list.cur);
+ cu_statusf(broker, &s,
+ CMPI_RC_ERR_FAILED,
+ "instance found do not match expectation");
+ goto out;
+ }
+
+ *_inst = list.list[0];
+ list.list[0] = NULL;
+
+ out:
+ eth_ifaceslist_uninit(&ifaces_list);
+ inst_list_free(&list);
+ CU_FREE(eth_name);
+ CU_FREE(dest);
+ return s;
+}
+
+CMPIStatus get_ep_by_id(const CMPIBroker *broker,
+ const char *id,
+ const CMPIObjectPath *reference,
+ const char **properties,
+ CMPIInstance **_inst)
+{
+ CMPIStatus s = {CMPI_RC_OK, NULL};
+ char *prefix = NULL;
+ char *suffix = NULL;
+ if (id == NULL) {
+ cu_statusf(broker, &s,
+ CMPI_RC_ERR_INVALID_PARAMETER,
+ "ID is NULL'", id);
+ }
+ if (!parse_fq_devid(id, &prefix, &suffix) || (prefix == NULL) ||
+ (suffix == NULL)) {
+ cu_statusf(broker, &s,
+ CMPI_RC_ERR_INVALID_PARAMETER,
+ "Invalid InstanceID `%s'", id);
+ goto out;
+ }
+ s = get_ep_by_name(broker, prefix, suffix, reference,
+ properties, _inst);
+
+ out:
+ CU_FREE(prefix);
+ CU_FREE(suffix);
+ return s;
+}
+
+CMPIStatus get_ep_by_ref(const CMPIBroker *broker,
+ const CMPIObjectPath *reference,
+ const char **properties,
+ CMPIInstance **_inst)
+{
+ CMPIStatus s = {CMPI_RC_OK, NULL};
+ CMPIInstance *inst = NULL;
+ char *name = NULL;
+ char *prefix = NULL;
+ const char *id;
+
+ if (cu_get_str_path(reference, "DeviceID", &id) != CMPI_RC_OK) {
+ cu_statusf(broker, &s,
+ CMPI_RC_ERR_NOT_FOUND,
+ "No such instance (InstanceID)");
+ goto out;
+ }
+ if ((!parse_fq_devid(id, &prefix, &name)) ||
+ (name == NULL) || (prefix == NULL)) {
+ cu_statusf(broker, &s,
+ CMPI_RC_ERR_NOT_FOUND,
+ "Failed to translate (InstanceID)");
+ goto out;
+ }
+
+ s = get_ep_by_name(broker, prefix, name, reference,
+ properties, &inst);
+ if (s.rc != CMPI_RC_OK) {
+ goto out;
+ }
+
+ s = cu_validate_ref(broker, reference, inst);
+ if (s.rc != CMPI_RC_OK) {
+ goto out;
+ }
+
+ *_inst = inst;
+
+ out:
+ free(name);
+ free(prefix);
+
+ return s;
+}
+
+
+CMPIStatus enum_eps(const CMPIBroker *broker,
+ const char *ref_vsname,
+ const CMPIObjectPath *reference,
+ const char **properties,
+ struct inst_list *plist)
+{
+ CMPIStatus s = {CMPI_RC_OK, NULL};
+ struct EthIfacesList ifaces_list;
+ int ret, i;
+ char *errstr;
+
+ eth_ifaceslist_init(&ifaces_list);
+
+ ret = get_host_ifaces(&ifaces_list,
+ eth_iface_filter_cim_ethport, NULL);
+ if (ret != 1) {
+ errstr = get_host_iface_error_reason(ret);
+ CU_DEBUG("error num %d returned, reason %s.", ret, errstr);
+ cu_statusf(broker, &s,
+ CMPI_RC_ERR_FAILED,
+ errstr);
+ goto out;
+ }
+ CU_DEBUG("enum ep, found following devices.")
+ eth_ifaceslist_print(&ifaces_list);
+
+ i = 0;
+ while (i < ifaces_list.count) {
+ s = instance_from_ep(broker,
+ ifaces_list.pifaces[i],
+ ref_vsname,
+ reference,
+ properties,
+ plist);
+ i++;
+ /* this should never fail */
+ if (s.rc != CMPI_RC_OK) {
+ CU_DEBUG("unexpected fail.");
+ break;
+ }
+ }
+
+
+ out:
+ eth_ifaceslist_uninit(&ifaces_list);
+
+ return s;
+}
+
+static CMPIStatus return_enum_eps(const CMPIBroker *broker,
+ const CMPIObjectPath *reference,
+ const CMPIResult *results,
+ const char **properties,
+ const bool names_only)
+{
+ struct inst_list list;
+ CMPIStatus s = {CMPI_RC_OK, NULL};
+ inst_list_init(&list);
+ s = enum_eps(broker, NULL, reference, properties, &list);
+ if (s.rc != CMPI_RC_OK) {
+ goto out;
+ }
+
+ if (names_only) {
+ cu_return_instance_names(results, &list);
+ } else {
+ cu_return_instances(results, &list);
+ }
+
+ out:
+ inst_list_free(&list);
+ return s;
+}
+
+static CMPIStatus EnumInstanceNames(CMPIInstanceMI *self,
+ const CMPIContext *context,
+ const CMPIResult *results,
+ const CMPIObjectPath *reference)
+{
+ return return_enum_eps(_BROKER, reference, results, NULL, true);
+}
+
+static CMPIStatus EnumInstances(CMPIInstanceMI *self,
+ const CMPIContext *context,
+ const CMPIResult *results,
+ const CMPIObjectPath *reference,
+ const char **properties)
+{
+
+ return return_enum_eps(_BROKER, reference, results, properties, false);
+}
+
+static CMPIStatus GetInstance(CMPIInstanceMI *self,
+ const CMPIContext *context,
+ const CMPIResult *results,
+ const CMPIObjectPath *ref,
+ const char **properties)
+{
+ CMPIStatus s = {CMPI_RC_OK, NULL};
+ CMPIInstance *inst = NULL;
+
+ s = get_ep_by_ref(_BROKER, ref, properties, &inst);
+ if (s.rc != CMPI_RC_OK) {
+ goto out;
+ }
+
+ CMReturnInstance(results, inst);
+
+ out:
+ return s;
+}
+
+DEFAULT_CI();
+DEFAULT_MI();
+DEFAULT_DI();
+DEFAULT_INST_CLEANUP();
+DEFAULT_EQ();
+
+STD_InstanceMIStub(,
+ Virt_EthernetPort,
+ _BROKER,
+ libvirt_cim_init());
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/Virt_EthernetPort.h b/src/Virt_EthernetPort.h
new file mode 100644
index 0000000..f474af2
--- /dev/null
+++ b/src/Virt_EthernetPort.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright IBM Corp. 2011
+ *
+ * Authors:
+ * Wencao Xia <xiawenc(a)cn.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __VIRT_ETHERNETPORT_H
+#define __VIRT_ETHERNETPORT_H
+
+CMPIStatus enum_eps(const CMPIBroker *broker,
+ const char *ref_vsname,
+ const CMPIObjectPath *reference,
+ const char **properties,
+ struct inst_list *plist);
+
+CMPIStatus get_ep_by_name(const CMPIBroker *broker,
+ const char *prefix,
+ const char *name,
+ const CMPIObjectPath *reference,
+ const char **properties,
+ CMPIInstance **_inst);
+
+CMPIStatus get_ep_by_id(const CMPIBroker *broker,
+ const char *id,
+ const CMPIObjectPath *reference,
+ const char **properties,
+ CMPIInstance **_inst);
+
+CMPIStatus get_ep_by_ref(const CMPIBroker *broker,
+ const CMPIObjectPath *reference,
+ const char **properties,
+ CMPIInstance **_inst);
+
+#endif
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */
--
1.7.1