[PATCH 05/15] vlan extension - CIM model - add class EASD

add the class Net_EthernetPortAllocationSettingData. According To DSP1050, there are two kinds of EASD, EASD_EA and EASD_EC, which describe Ethernetprot settings and connection settings. Signed-off-by: Wayne Xia <xiawenc@linux.vnet.ibm.com> --- schema/EthernetPortAllocationSettingData.mof | 21 + .../EthernetPortAllocationSettingData.registration | 3 + src/Virt_EASD.c | 733 ++++++++++++++++++++ src/Virt_EASD.h | 61 ++ 4 files changed, 818 insertions(+), 0 deletions(-) create mode 100644 schema/EthernetPortAllocationSettingData.mof create mode 100644 schema/EthernetPortAllocationSettingData.registration create mode 100644 src/Virt_EASD.c create mode 100644 src/Virt_EASD.h diff --git a/schema/EthernetPortAllocationSettingData.mof b/schema/EthernetPortAllocationSettingData.mof new file mode 100644 index 0000000..8a1b38b --- /dev/null +++ b/schema/EthernetPortAllocationSettingData.mof @@ -0,0 +1,21 @@ +// Copyright IBM Corp. 2011 + +[Description ("Virtutal EthernetPort Setting Data"), + Provider("cmpi::Virt_EASD") +] + +class Net_EthernetPortAllocationSettingData : CIM_EthernetPortAllocationSettingData +{ + uint16 PortVID; + uint16 DesiredEndPointMode; + + [Description("VLAN type of the port, " + "Now only support IEEE 802.1.q."), + ValueMap { "0", "1", "2", "3" }, + Values { "Not VLAN", "IEEE 802.1.q", "IEEE 802.1.qbg", "IEEE 802.1.qbh" }] + uint16 VLANType; + + uint16 ReorderHdr; + string VLANQosIngress; + string VLANQosEgress; +}; diff --git a/schema/EthernetPortAllocationSettingData.registration b/schema/EthernetPortAllocationSettingData.registration new file mode 100644 index 0000000..bedd029 --- /dev/null +++ b/schema/EthernetPortAllocationSettingData.registration @@ -0,0 +1,3 @@ +# Copyright IBM Corp. 2011 +# Classname Namespace ProviderName ProviderModule ProviderTypes +Net_EthernetPortAllocationSettingData root/virt Virt_EASD Virt_EASD instance diff --git a/src/Virt_EASD.c b/src/Virt_EASD.c new file mode 100644 index 0000000..cb786a5 --- /dev/null +++ b/src/Virt_EASD.c @@ -0,0 +1,733 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia <xiawenc@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 "infostore.h" + +#include "Virt_EASD.h" +#include "svpc_types.h" +#include "Virt_Device.h" +#include "Virt_VirtualEthernetSwitchSystem.h" +#include "network_model.h" + +static const CMPIBroker *_BROKER; + +static int set_primary_for_easd(const CMPIBroker *broker, const char* prefix, + EthIface *piface, int type, CMPIInstance *instance) +{ + char *eth_name, *easd_name; + int asret; + uint16_t res_type = CIM_NUM_SWITCHPORT; + uint16_t vlan_mode; + + if (piface->name == NULL) { + return 0; + } + + eth_name = get_ethportsd_name_from_iface(piface->name, type); + asret = asprintf(&easd_name, "%s/%s", prefix, eth_name); + + CMSetProperty(instance, "InstanceID", + (CMPIValue *)easd_name, CMPI_chars); + CMSetProperty(instance, "ElementName", + (CMPIValue *)eth_name, CMPI_chars); + SAFE_FREE(easd_name); + SAFE_FREE(eth_name); + + CMSetProperty(instance, "ResourceType", + (CMPIValue *)&res_type, CMPI_uint16); + + if (piface->eth_type == ETH_TYPE_PHYSICAL) { + vlan_mode = CIM_NUM_VLAN_MODE_TRUNK; + CMSetProperty(instance, "DesiredEndPointMode", + (CMPIValue *)&vlan_mode, CMPI_uint16); + } + + + if (piface->mac != NULL) { + CMSetProperty(instance, "Address", + (CMPIValue *)piface->mac, CMPI_chars); + } + + return 1; +} + +static int set_secondary_for_easd(const CMPIBroker *broker, EthIface *piface, + CMPIInstance *instance) +{ + VLAN_Prop *pvlan; + VLAN_Prop_8021q *pvlan8021q; + uint16_t vid, hdr; + CMPIArray *conn_array; + CMPIString *cm_str; + char *str = NULL, *egress = NULL, *ingress = NULL; + CMPIStatus s; + int ret; + uint16_t vlantype = 0; + uint16_t visibility = CIM_NUM_CONSUMERVISIBILITY_VIRTUALIZED; + + if (piface->eth_type == ETH_TYPE_PHYSICAL) { + visibility = CIM_NUM_CONSUMERVISIBILITY_PASSEDTHROUGH; + } + CMSetProperty(instance, "ConsumerVisibility", + (CMPIValue *)&visibility, CMPI_uint16); + + if ((piface->eth_type != ETH_TYPE_VLAN) || + (piface->pvlan_prop == NULL)) { + goto out; + } + pvlan = piface->pvlan_prop; + + if (pvlan->vlan_type == VLAN_TYPE_802_1_Q) { + pvlan8021q = &(pvlan->props.prop_8021q); + vid = pvlan8021q->vlan_id; + CMSetProperty(instance, "PortVID", + (CMPIValue *)&vid, CMPI_uint16); + + str = vlanid_to_connection_name(vid); + conn_array = CMNewArray(broker, 1, CMPI_string, &s); + if ((s.rc != CMPI_RC_OK) || (str == NULL)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Error creating Connection " + "list and its string"); + CU_DEBUG("CMNewArray or string creation failed"); + goto out; + } + cm_str = CMNewString(broker, str, &s); + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("Error creating CMPIString"); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Error creating CMPIString for " + "BootDevices item"); + + goto out; + } + CMSetArrayElementAt(conn_array, 0, (CMPIValue *)&cm_str, + CMPI_string); + CMSetProperty(instance, "Connection", + (CMPIValue *)&conn_array, CMPI_stringA); + hdr = pvlan8021q->reorder_hdr; + CMSetProperty(instance, "ReorderHdr", + (CMPIValue *)&hdr, CMPI_uint16); + + if ((pvlan8021q->ingress.count > 0) && + (pvlan8021q->ingress.count <= 8)) { + ret = vlan_8021q_qos_num_to_str(&ingress, + &(pvlan8021q->ingress)); + if (ret == 1) { + CMSetProperty(instance, "VLANQosIngress", + (CMPIValue *)ingress, CMPI_chars); + } else { + CU_DEBUG("failed to generate vlan qos " + "string."); + } + } + if ((pvlan8021q->egress.count > 0) && + (pvlan8021q->egress.count <= 8)) { + ret = vlan_8021q_qos_num_to_str(&egress, + &(pvlan8021q->egress)); + if (ret == 1) { + CMSetProperty(instance, "VLANQosEgress", + (CMPIValue *)egress, CMPI_chars); + } else { + CU_DEBUG("failed to generate vlan qos " + "string."); + } + } + vlantype = 1; + } + CMSetProperty(instance, "VLANType", + (CMPIValue *)&vlantype, CMPI_uint16); + +out: + SAFE_FREE(str); + SAFE_FREE(egress); + SAFE_FREE(ingress); + return 1; +} + +static CMPIStatus add_conn_properties(const CMPIBroker *broker, + EthIface *piface, + const char *prefix, + const char *dest, + CMPIInstance *instance) +{ + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; + char *eth_name, *easd_name; + int asret; + CMPIArray *array; + CMPIString *tmp; + + if (piface->name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "device name not set"); + goto out; + } + if (dest == NULL) { + CU_DEBUG("warn: connection dest is NULL."); + } + + eth_name = get_ethportsd_name_from_iface(piface->name, EASD_TYPE_EA); + asret = asprintf(&easd_name, "%s:%s", prefix, eth_name); + CMSetProperty(instance, "Parent", + (CMPIValue *)easd_name, CMPI_chars); + SAFE_FREE(easd_name); + SAFE_FREE(eth_name); + + array = CMNewArray(broker, 1, CMPI_string, &s); + tmp = CMNewString(broker, dest, NULL); + CMSetArrayElementAt(array, 0, &(tmp), CMPI_string); + CMSetProperty(instance, "HostResource", + (CMPIValue *)&array, CMPI_stringA); + + + out: + return s; +} + +static CMPIStatus set_properties(const CMPIBroker *broker, + EthIface *piface, + const char *prefix, + const char *dest, + int type, + CMPIInstance *instance) +{ + CMPIStatus s = {CMPI_RC_ERR_FAILED, NULL}; + char *errstr; + + if (!set_primary_for_easd(broker, prefix, piface, type, 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 (type == EASD_TYPE_EA) { + if (!set_secondary_for_easd(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; + } + } else { + s = add_conn_properties(broker, + piface, + prefix, + dest, + instance); + if (s.rc != CMPI_RC_OK) { + goto out; + } + } + + cu_statusf(broker, &s, + CMPI_RC_OK, + ""); + + out: + return s; +} + +static CMPIStatus instance_from_easd_build(const CMPIBroker *broker, + EthIface *piface, + const char *prefix, + const char *dest, + int type, + 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, + "EthernetPortAllocationSettingData", + NAMESPACE(reference)); + if (inst == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Unable to init SwitchSystem 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, + dest, + type, + inst); + + if (s.rc != CMPI_RC_OK) { + goto out; + } + + *_inst = inst; + + out: + return s; +} + +/* vsname and req_type are filter conditions */ +static CMPIStatus instance_from_easd(const CMPIBroker *broker, + EthIface *piface, + const char *vsname, + int req_type, + 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; + + CU_DEBUG("enter instance_for_easd with vsname %s, type %d.", + vsname, req_type); + 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 the EA instance */ + if (!(req_type&EASD_TYPE_EA)) { + goto ea_build_end; + } + if ((vsname == NULL) || (0 == strcmp(vsname, br1_name))) { + inst = NULL; + s = instance_from_easd_build(broker, + piface, + br1_name, + NULL, + EASD_TYPE_EA, + 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_easd_build(broker, + piface, + br2_name, + NULL, + EASD_TYPE_EA, + reference, + properties, + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + inst_list_add(plist, inst); + } + ea_build_end: + + /* building the EC instance */ + if (!(req_type&EASD_TYPE_EC)) { + goto ec_build_end; + } + if ((br1_name == NULL) || (br2_name == NULL)) { + goto ec_build_end; + } + /* connection exist, so a EC_easd should be added for each bridge */ + if ((vsname == NULL) || (0 == strcmp(vsname, br1_name))) { + inst = NULL; + s = instance_from_easd_build(broker, + piface, + br1_name, + br2_name, + EASD_TYPE_EC, + reference, + properties, + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + inst_list_add(plist, inst); + } + if ((vsname == NULL) || (0 == strcmp(vsname, br2_name))) { + inst = NULL; + s = instance_from_easd_build(broker, + piface, + br2_name, + br1_name, + EASD_TYPE_EC, + reference, + properties, + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + inst_list_add(plist, inst); + } + ec_build_end: + + out: + SAFE_FREE(br1_name); + SAFE_FREE(br2_name); + return s; +} + +CMPIStatus get_easd_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; + int type; + EthIfacesList ifaces_list; + struct inst_list list; + + CU_DEBUG("####prefix %s", prefix); + eth_ifaceslist_init(&ifaces_list); + inst_list_init(&list); + + eth_name = get_iface_name_from_ethportsd(name, &type); + 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("%d ethportd found.", ifaces_list.count); + eth_ifaceslist_print(&ifaces_list); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + + inst = NULL; + s = instance_from_easd(broker, + ifaces_list.pifaces[0], + prefix, + type, + 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); + SAFE_FREE(eth_name); + SAFE_FREE(dest); + return s; +} + +CMPIStatus get_easd_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_easd_by_name(broker, prefix, suffix, reference, + properties, _inst); + + out: + SAFE_FREE(prefix); + SAFE_FREE(suffix); + return s; +} + +CMPIStatus get_easd_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, "InstanceID", &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_easd_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_easds(const CMPIBroker *broker, + const char *ref_vsname, + const CMPIObjectPath *reference, + const char **properties, + struct inst_list *plist) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + 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 easd, found following devices.") + eth_ifaceslist_print(&ifaces_list); + + i = 0; + while (i < ifaces_list.count) { + s = instance_from_easd(broker, + ifaces_list.pifaces[i], + ref_vsname, + EASD_TYPE_EA|EASD_TYPE_EC, + 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_easds(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_easds(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_easds(_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_easds(_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_easd_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_EASD, + _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_EASD.h b/src/Virt_EASD.h new file mode 100644 index 0000000..215553b --- /dev/null +++ b/src/Virt_EASD.h @@ -0,0 +1,61 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia <xiawenc@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_EASD_H +#define __VIRT_EASD_H + +#include "device_parsing.h" + +CMPIStatus enum_easds(const CMPIBroker *broker, + const char *ref_vsname, + const CMPIObjectPath *reference, + const char **properties, + struct inst_list *plist); + +CMPIStatus get_easd_by_name(const CMPIBroker *broker, + const char *prefix, + const char *name, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst); + +CMPIStatus get_easd_by_id(const CMPIBroker *broker, + const char *id, + const CMPIObjectPath *reference, + const char **properties, + CMPIInstance **_inst); + +CMPIStatus get_easd_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.6

add the association of Net_SettingSDefineState. Signed-off-by: Wayne Xia <xiawenc@linux.vnet.ibm.com> --- schema/SettingsDefineState.mof | 9 +- schema/SettingsDefineState.registration | 3 +- src/Virt_SettingsDefineState.c | 256 +++++++++++++++++++++++++++++++ 3 files changed, 266 insertions(+), 2 deletions(-) diff --git a/schema/SettingsDefineState.mof b/schema/SettingsDefineState.mof index 7664ae2..1ee6698 100644 --- a/schema/SettingsDefineState.mof +++ b/schema/SettingsDefineState.mof @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2007 +// Copyright IBM Corp. 2011 [Association, Provider("cmpi::Virt_SettingsDefineState") @@ -20,3 +20,10 @@ class KVM_SettingsDefineState : CIM_SettingsDefineState class LXC_SettingsDefineState : CIM_SettingsDefineState { }; + +[Association, + Provider("cmpi::Virt_SettingsDefineState") +] +class Net_SettingsDefineState : CIM_SettingsDefineState +{ +}; diff --git a/schema/SettingsDefineState.registration b/schema/SettingsDefineState.registration index 0563491..b5e03ba 100644 --- a/schema/SettingsDefineState.registration +++ b/schema/SettingsDefineState.registration @@ -1,5 +1,6 @@ -# Copyright IBM Corp. 2007 +# Copyright IBM Corp. 2011 # Classname Namespace ProviderName ProviderModule ProviderTypes Xen_SettingsDefineState root/virt Virt_SettingsDefineState Virt_SettingsDefineState association KVM_SettingsDefineState root/virt Virt_SettingsDefineState Virt_SettingsDefineState association LXC_SettingsDefineState root/virt Virt_SettingsDefineState Virt_SettingsDefineState association +Net_SettingsDefineState root/virt Virt_SettingsDefineState Virt_SettingsDefineState association diff --git a/src/Virt_SettingsDefineState.c b/src/Virt_SettingsDefineState.c index b4e4b80..ae7054f 100644 --- a/src/Virt_SettingsDefineState.c +++ b/src/Virt_SettingsDefineState.c @@ -4,6 +4,9 @@ * Authors: * Dan Smith <danms@us.ibm.com> * + * Modified by: + * Wenchao Xia <xiawenc@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 @@ -36,6 +39,11 @@ #include "Virt_ComputerSystem.h" #include "Virt_VSSD.h" #include "svpc_types.h" +#include "Virt_VESSSD.h" +#include "Virt_VirtualEthernetSwitchSystem.h" +#include "Virt_EASD.h" +#include "Virt_EthernetPort.h" +#include "network_model.h" const static CMPIBroker *_BROKER; @@ -319,6 +327,172 @@ static CMPIStatus vssd_to_vs(const CMPIObjectPath *ref, return s; } +static CMPIStatus vess_to_vesssd(const CMPIObjectPath *ref, + struct std_assoc_info *info, + struct inst_list *list) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst; + const char *name = NULL; + + if (!match_hypervisor_prefix(ref, info)) { + return s; + } + /* the step of creating a vess instance is skipped to make it fast */ + if (cu_get_str_path(ref, "Name", &name) != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Missing Name property"); + goto out; + } + + CU_DEBUG("vess to vesssd , name %s", name); + s = get_vesssd_by_name(_BROKER, name, ref, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + inst_list_add(list, inst); + + out: + return s; +} + +static CMPIStatus vesssd_to_vess(const CMPIObjectPath *ref, + struct std_assoc_info *info, + struct inst_list *list) +{ + const char *id = NULL; + char *pfx = NULL; + char *name = NULL; + int ret; + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + + if (!match_hypervisor_prefix(ref, info)) { + return s; + } + + /* the step of creating a vesssd instance is skipped to make it fast */ + if (cu_get_str_path(ref, "InstanceID", &id) != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Missing InstanceID"); + goto out; + } + + ret = sscanf(id, "%a[^:]:%as", &pfx, &name); + if (ret != 2) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Invalid InstanceID"); + goto out; + } + + CU_DEBUG("vesssd to vess , name %s", name); + s = get_switch_by_name(_BROKER, name, ref, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + inst_list_add(list, inst); + + out: + free(name); + free(pfx); + + return s; +} + +/* according to DSP 1050.1.0.0_0 page 41, SDS only associate EP with EASD_EA */ +static CMPIStatus ep_to_easd(const CMPIObjectPath *ref, + struct std_assoc_info *info, + struct inst_list *list) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *newid = NULL; + const char *name; + + if (!match_hypervisor_prefix(ref, info)) { + return s; + } + + /* the step of creating a ep instance is skipped to make it fast */ + if (cu_get_str_path(ref, "DeviceID", &name) != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "No DeviceID specified"); + goto out; + } + + newid = ep_id_to_easdea_id(name); + if (newid == NULL) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_NOT_FOUND, + "Invalid DeviceID set."); + goto out; + } + + s = get_easd_by_id(_BROKER, + newid, + ref, + NULL, + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + inst_list_add(list, inst); + + out: + free(newid); + return s; +} + +static CMPIStatus easd_to_ep(const CMPIObjectPath *ref, + struct std_assoc_info *info, + struct inst_list *list) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + const char *name = NULL; + char *newid = NULL; + + if (!match_hypervisor_prefix(ref, info)) { + return s; + } + + /* the step of creating a easd instance is skipped to make it fast */ + + if (cu_get_str_path(ref, "InstanceID", &name) != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Missing InstanceID"); + goto out; + } + newid = easdea_id_to_ep_id(name); + + if (newid == NULL) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_NOT_FOUND, + "Invalid InstanceID set."); + goto out; + } + + s = get_ep_by_id(_BROKER, newid, ref, NULL, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + inst_list_add(list, inst); + + + out: + free(newid); + return s; +} + LIBVIRT_CIM_DEFAULT_MAKEREF() static char* logical_device[] = { @@ -386,6 +560,32 @@ static char* assoc_classname[] = { NULL }; + +static char *vess_name[] = { + "Net_VirtualEthernetSwitchSystem", + NULL +}; + +static char *vesssd_name[] = { + "Net_VirtualEthernetSwitchSystemSettingData", + NULL +}; + +static char *ep_name[] = { + "Net_EthernetPort", + NULL +}; + +static char *easd_name[] = { + "Net_EthernetPortAllocationSettingData", + NULL +}; + +static char *vess_assoc_name[] = { + "Net_SettingsDefineState", + NULL +}; + static struct std_assoc _dev_to_rasd = { .source_class = (char**)&logical_device, .source_prop = "ManagedElement", @@ -438,11 +638,67 @@ static struct std_assoc _vssd_to_vs = { .make_ref = make_ref }; +static struct std_assoc _vess_to_vesssd = { + .source_class = (char **)&vess_name, + .source_prop = "ManagedElement", + + .target_class = (char **)&vesssd_name, + .target_prop = "SettingData", + + .assoc_class = (char **)&vess_assoc_name, + + .handler = vess_to_vesssd, + .make_ref = make_ref +}; + +static struct std_assoc _vesssd_to_vess = { + .source_class = (char **)&vesssd_name, + .source_prop = "SettingData", + + .target_class = (char **)&vess_name, + .target_prop = "ManagedElement", + + .assoc_class = (char **)&vess_assoc_name, + + .handler = vesssd_to_vess, + .make_ref = make_ref +}; + +static struct std_assoc _ep_to_easd = { + .source_class = (char **)&ep_name, + .source_prop = "ManagedElement", + + .target_class = (char **)&easd_name, + .target_prop = "SettingData", + + .assoc_class = (char **)&vess_assoc_name, + + .handler = ep_to_easd, + .make_ref = make_ref +}; + +static struct std_assoc _easd_to_ep = { + .source_class = (char **)&easd_name, + .source_prop = "SettingData", + + .target_class = (char **)&ep_name, + .target_prop = "ManagedElement", + + .assoc_class = (char **)&vess_assoc_name, + + .handler = easd_to_ep, + .make_ref = make_ref +}; + static struct std_assoc *handlers[] = { &_dev_to_rasd, &_rasd_to_dev, &_vs_to_vssd, &_vssd_to_vs, + &_vess_to_vesssd, + &_vesssd_to_vess, + &_ep_to_easd, + &_easd_to_ep, NULL }; -- 1.7.6

add the class Net_VirtualEthernetSwitchSystemDevice. Signed-off-by: Wayne Xia <xiawenc@linux.vnet.ibm.com> --- schema/SystemDevice.mof | 18 +++++- schema/SystemDevice.registration | 3 +- src/Virt_SystemDevice.c | 126 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 2 deletions(-) diff --git a/schema/SystemDevice.mof b/schema/SystemDevice.mof index e13b265..13f45ae 100644 --- a/schema/SystemDevice.mof +++ b/schema/SystemDevice.mof @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2007 +// Copyright IBM Corp. 2011 [Association, Description ( @@ -47,3 +47,19 @@ class LXC_SystemDevice : CIM_SystemDevice CIM_LogicalDevice REF PartComponent; }; + +[Association, + Description ( + "A class to associate switch system." ), + Provider("cmpi::Virt_SwitchSystemDevice") +] +class Net_VirtualEthernetSwitchSystemDevice : CIM_SystemDevice +{ + + [Override ( "GroupComponent" )] + Net_VirtualEthernetSwitchSystem REF GroupComponent; + + [Override ( "PartComponent" )] + Net_EthernetPort REF PartComponent; + +}; diff --git a/schema/SystemDevice.registration b/schema/SystemDevice.registration index d6c331d..83dcbc6 100644 --- a/schema/SystemDevice.registration +++ b/schema/SystemDevice.registration @@ -1,5 +1,6 @@ -# Copyright IBM Corp. 2007 +# Copyright IBM Corp. 2011 # Classname Namespace ProviderName ProviderModule ProviderTypes Xen_SystemDevice root/virt Virt_SystemDevice Virt_SystemDevice association KVM_SystemDevice root/virt Virt_SystemDevice Virt_SystemDevice association LXC_SystemDevice root/virt Virt_SystemDevice Virt_SystemDevice association +Net_VirtualEthernetSwitchSystemDevice root/virt Virt_SystemDevice Virt_SystemDevice association diff --git a/src/Virt_SystemDevice.c b/src/Virt_SystemDevice.c index 31d6b61..0b166fa 100644 --- a/src/Virt_SystemDevice.c +++ b/src/Virt_SystemDevice.c @@ -6,6 +6,9 @@ * Jay Gagnon <grendel@linux.vnet.ibm.com> * Zhengang Li <lizg@cn.ibm.com> * + * Modified by: + * Wenchao Xia <xiawenc@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 @@ -37,6 +40,8 @@ #include "Virt_ComputerSystem.h" #include "Virt_Device.h" +#include "Virt_VirtualEthernetSwitchSystem.h" +#include "Virt_EthernetPort.h" /* Associate an XXX_ComputerSystem to the proper XXX_LogicalDisk * and XXX_NetworkPort instances. @@ -44,6 +49,11 @@ * -- or -- * * Associate an XXX_LogicalDevice to the proper XXX_ComputerSystem + * + * -- or -- + * + * Virtual Ethernet Switch System with Ethernet Port + * */ const static CMPIBroker *_BROKER; @@ -120,6 +130,79 @@ static CMPIStatus dev_to_sys(const CMPIObjectPath *ref, return s; } +static CMPIStatus vess_to_ep(const CMPIObjectPath *ref, + struct std_assoc_info *info, + struct inst_list *list) +{ + const char *host = NULL; + CMPIStatus s = {CMPI_RC_OK, NULL}; + + if (!match_hypervisor_prefix(ref, info)) { + return s; + } + + /* the step of creating a vess instance is skipped to make it fast */ + if (cu_get_str_path(ref, "Name", &host) != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Missing Name"); + goto out; + } + + s = enum_eps(_BROKER, + host, + ref, + info->properties, + list); + + + out: + return s; +} + +static CMPIStatus ep_to_vess(const CMPIObjectPath *ref, + struct std_assoc_info *info, + struct inst_list *list) +{ + const char *devid = NULL; + char *host = NULL; + char *dev = NULL; + CMPIInstance *inst = NULL; + CMPIStatus s = {CMPI_RC_OK, NULL}; + + if (!match_hypervisor_prefix(ref, info)) { + return s; + } + + /* the step of creating a ep instance is skipped to make it fast */ + + if (cu_get_str_path(ref, "DeviceID", &devid) != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Missing DeviceID"); + goto out; + } + + if (!parse_fq_devid(devid, &host, &dev)) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Invalid DeviceID"); + goto out; + } + + s = get_switch_by_name(_BROKER, host, ref, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + inst_list_add(list, inst); + + out: + free(host); + free(dev); + return s; +} + LIBVIRT_CIM_DEFAULT_MAKEREF() static char* group_component[] = { @@ -158,6 +241,21 @@ static char* assoc_classname[] = { NULL }; +static char *vess_group_component[] = { + "Net_VirtualEthernetSwitchSystem", + NULL +}; + +static char *vess_part_component[] = { + "Net_EthernetPort", + NULL +}; + +static char *vess_assoc_classname[] = { + "Net_VirtualEthernetSwitchSystemDevice", + NULL +}; + static struct std_assoc forward = { .source_class = (char**)&group_component, .source_prop = "GroupComponent", @@ -184,9 +282,37 @@ static struct std_assoc backward = { .make_ref = make_ref }; +static struct std_assoc assoc_vess_to_ep = { + .source_class = (char **)&vess_group_component, + .source_prop = "GroupComponent", + + .target_class = (char **)&vess_part_component, + .target_prop = "PartComponent", + + .assoc_class = (char **)&vess_assoc_classname, + + .handler = vess_to_ep, + .make_ref = make_ref +}; + +static struct std_assoc assoc_ep_to_vess = { + .source_class = (char **)&vess_part_component, + .source_prop = "PartComponent", + + .target_class = (char **)&vess_group_component, + .target_prop = "GroupComponent", + + .assoc_class = (char **)&vess_assoc_classname, + + .handler = ep_to_vess, + .make_ref = make_ref +}; + static struct std_assoc *assoc_handlers[] = { &forward, &backward, + &assoc_vess_to_ep, + &assoc_ep_to_vess, NULL }; -- 1.7.6

add the class Net_VirtualEthernetSwitchSystemSettingDataComponent. Signed-off-by: Wayne Xia <xiawenc@linux.vnet.ibm.com> --- schema/VESSSDComponent.mof | 8 ++ schema/VESSSDComponent.registration | 3 + src/Virt_VESSSDComponent.c | 181 +++++++++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+), 0 deletions(-) create mode 100644 schema/VESSSDComponent.mof create mode 100644 schema/VESSSDComponent.registration create mode 100644 src/Virt_VESSSDComponent.c diff --git a/schema/VESSSDComponent.mof b/schema/VESSSDComponent.mof new file mode 100644 index 0000000..a96d837 --- /dev/null +++ b/schema/VESSSDComponent.mof @@ -0,0 +1,8 @@ +// Copyright IBM Corp. 2011 + +[Association, + Provider("cmpi::Virt_VESSSDComponent") +] +class Net_VirtualEthernetSwitchSystemSettingDataComponent : CIM_VirtualSystemSettingDataComponent +{ +}; diff --git a/schema/VESSSDComponent.registration b/schema/VESSSDComponent.registration new file mode 100644 index 0000000..0416881 --- /dev/null +++ b/schema/VESSSDComponent.registration @@ -0,0 +1,3 @@ +# Copyright IBM Corp. 2011 +# Classname Namespace ProviderName ProviderModule ProviderTypes +Net_VirtualEthernetSwitchSystemSettingDataComponent root/virt Virt_VESSSDComponent Virt_VESSSDComponent association diff --git a/src/Virt_VESSSDComponent.c b/src/Virt_VESSSDComponent.c new file mode 100644 index 0000000..34f2cbc --- /dev/null +++ b/src/Virt_VESSSDComponent.c @@ -0,0 +1,181 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia <xiawenc@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 "cmpidt.h" +#include "cmpift.h" +#include "cmpimacs.h" + +#include <libcmpiutil/libcmpiutil.h> +#include <libcmpiutil/std_association.h> +#include "misc_util.h" +#include "device_parsing.h" + +#include "Virt_VESSSD.h" +#include "Virt_EASD.h" +#include "svpc_types.h" +#include "misc_util.h" + +static const CMPIBroker *_BROKER; + +static CMPIStatus vesssd_to_easd(const CMPIObjectPath *ref, + struct std_assoc_info *info, + struct inst_list *list) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + char *name = NULL; + + if (!match_hypervisor_prefix(ref, info)) { + CU_DEBUG("Requested a unexpectted assoc."); + goto out; + } + + /* the step of creating a vesssd instance is skipped to make it fast */ + if (!parse_instanceid(ref, NULL, &name)) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Unable to get system name"); + goto out; + } + + s = enum_easds(_BROKER, + name, + ref, + info->properties, + list); + + free(name); + + out: + return s; +} + +static CMPIStatus easd_to_vesssd(const CMPIObjectPath *ref, + struct std_assoc_info *info, + struct inst_list *list) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + const char *id = NULL; + char *host = NULL; + char *devid = NULL; + int ret; + + if (!match_hypervisor_prefix(ref, info)) { + CU_DEBUG("Requested a unexpectted assoc."); + goto out; + } + + /* the step of creating a easd instance is skipped to make it fast */ + if (cu_get_str_path(ref, "InstanceID", &id) != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Missing InstanceID"); + goto out; + } + + ret = parse_fq_devid(id, &host, &devid); + if (!ret) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Invalid InstanceID"); + goto out; + } + + s = get_vesssd_by_name(_BROKER, host, ref, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + inst_list_add(list, inst); + + out: + free(host); + free(devid); + + return s; +} + +LIBVIRT_CIM_DEFAULT_MAKEREF() + +static char *group_component[] = { + "Net_VirtualEthernetSwitchSystemSettingData", + NULL +}; + +static char *part_component[] = { + "Net_EthernetPortAllocationSettingData", + NULL +}; + +static char *assoc_classname[] = { + "Net_VirtualEthernetSwitchSystemSettingDataComponent", + NULL +}; + +static struct std_assoc forward = { + .source_class = (char **)&group_component, + .source_prop = "GroupComponent", + + .target_class = (char **)&part_component, + .target_prop = "PartComponent", + + .assoc_class = (char **)&assoc_classname, + + .handler = vesssd_to_easd, + .make_ref = make_ref +}; + +static struct std_assoc backward = { + .source_class = (char **)&part_component, + .source_prop = "PartComponent", + + .target_class = (char **)&group_component, + .target_prop = "GroupComponent", + + .assoc_class = (char **)&assoc_classname, + + .handler = easd_to_vesssd, + .make_ref = make_ref +}; + +static struct std_assoc *handlers[] = { + &forward, + &backward, + NULL +}; + +STDA_AssocMIStub(, + Virt_VESSSDComponent, + _BROKER, + libvirt_cim_init(), + handlers); + +/* + * Local Variables: + * mode: C + * c-set-style: "K&R" + * tab-width: 8 + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */ -- 1.7.6

add two association class accroding to DSP1050, Net_ElementSettingData and Net_EthernetPortConnectionSettingData. Signed-off-by: Wayne Xia <xiawenc@linux.vnet.ibm.com> --- schema/ElementSettingData.mof | 16 ++- schema/ElementSettingData.registration | 4 +- src/Virt_ElementSettingData.c | 229 +++++++++++++++++++++++++++++++- 3 files changed, 246 insertions(+), 3 deletions(-) diff --git a/schema/ElementSettingData.mof b/schema/ElementSettingData.mof index 2bfc52a..9ba116f 100644 --- a/schema/ElementSettingData.mof +++ b/schema/ElementSettingData.mof @@ -1,4 +1,4 @@ -// Copyright IBM Corp. 2007 +// Copyright IBM Corp. 2011 [Association, Provider("cmpi::Virt_ElementSettingData") @@ -20,3 +20,17 @@ class KVM_ElementSettingData : CIM_ElementSettingData class LXC_ElementSettingData : CIM_ElementSettingData { }; + +[Association, + Provider("cmpi::Virt_ElementSettingData") +] +class Net_ElementSettingData : CIM_ElementSettingData +{ +}; + +[Association, + Provider("cmpi::Virt_ElementSettingData") +] +class Net_EthernetPortConnectionSettingData : CIM_ElementSettingData +{ +}; diff --git a/schema/ElementSettingData.registration b/schema/ElementSettingData.registration index edec78c..8cff13b 100644 --- a/schema/ElementSettingData.registration +++ b/schema/ElementSettingData.registration @@ -1,5 +1,7 @@ -# Copyright IBM Corp. 2007 +# Copyright IBM Corp. 2011 # Classname Namespace ProviderName ProviderModule ProviderTypes Xen_ElementSettingData root/virt Virt_ElementSettingData Virt_ElementSettingData association KVM_ElementSettingData root/virt Virt_ElementSettingData Virt_ElementSettingData association LXC_ElementSettingData root/virt Virt_ElementSettingData Virt_ElementSettingData association +Net_ElementSettingData root/virt Virt_ElementSettingData Virt_ElementSettingData association +Net_EthernetPortConnectionSettingData root/virt Virt_ElementSettingData Virt_ElementSettingData association diff --git a/src/Virt_ElementSettingData.c b/src/Virt_ElementSettingData.c index b5b7b02..269b3d2 100644 --- a/src/Virt_ElementSettingData.c +++ b/src/Virt_ElementSettingData.c @@ -1,9 +1,12 @@ /* - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2011 * * Authors: * Kaitlin Rupert <karupert@us.ibm.com> * + * Modified by: + * Wenchao Xia <xiawenc@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 @@ -32,6 +35,10 @@ #include "Virt_VSSD.h" #include "Virt_RASD.h" +#include "Virt_VESSSD.h" +#include "Virt_EASD.h" +#include "Virt_EthernetPort.h" +#include "network_model.h" const static CMPIBroker *_BROKER; @@ -81,6 +88,145 @@ static CMPIStatus rasd_to_rasd(const CMPIObjectPath *ref, return s; } +static CMPIStatus vesssd_to_vesssd(const CMPIObjectPath *ref, + struct std_assoc_info *info, + struct inst_list *list) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst; + + if (!match_hypervisor_prefix(ref, info)) { + return s; + } + + /* Special association case: + * VESSSD instance is pointing to itself + */ + s = get_vesssd_by_ref(_BROKER, ref, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + inst_list_add(list, inst); + + out: + return s; +} + +static CMPIStatus easd_to_easd(const CMPIObjectPath *ref, + struct std_assoc_info *info, + struct inst_list *list) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + + if (!match_hypervisor_prefix(ref, info)) { + return s; + } + + /* Special association case: + * EASD instance is pointing to itself + */ + s = get_easd_by_ref(_BROKER, ref, info->properties, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + inst_list_add(list, inst); + + out: + return s; +} + +/* according to DSP 1050.1.0.0_0 page 41, ESD only associate EP with EASD_EC */ +static CMPIStatus easd_to_ep(const CMPIObjectPath *ref, + struct std_assoc_info *info, + struct inst_list *list) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + const char *name = NULL; + char *newid = NULL; + + if (!match_hypervisor_prefix(ref, info)) { + return s; + } + + /* the step of creating a easd instance is skipped to make it fast */ + + if (cu_get_str_path(ref, "InstanceID", &name) != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Missing InstanceID"); + goto out; + } + newid = easdec_id_to_ep_id(name); + + if (newid == NULL) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_NOT_FOUND, + "Invalid InstanceID set."); + goto out; + } + + s = get_ep_by_id(_BROKER, newid, ref, NULL, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + inst_list_add(list, inst); + + + out: + free(newid); + return s; +} + +static CMPIStatus ep_to_easd(const CMPIObjectPath *ref, + struct std_assoc_info *info, + struct inst_list *list) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char *newid = NULL; + const char *name; + + if (!match_hypervisor_prefix(ref, info)) { + return s; + } + + /* the step of creating a ep instance is skipped to make it fast */ + if (cu_get_str_path(ref, "DeviceID", &name) != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "No DeviceID specified"); + goto out; + } + + newid = ep_id_to_easdec_id(name); + if (newid == NULL) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_NOT_FOUND, + "Invalid DeviceID set."); + goto out; + } + + s = get_easd_by_id(_BROKER, + newid, + ref, + NULL, + &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + inst_list_add(list, inst); + + out: + free(newid); + return s; +} + static CMPIInstance *make_ref(const CMPIObjectPath *source_ref, const CMPIInstance *target_inst, struct std_assoc_info *info, @@ -151,6 +297,31 @@ static char* assoc_classname[] = { NULL }; +static char *vesssd[] = { + "Net_VirtualEthernetSwitchSystemSettingData", + NULL +}; + +static char *easd[] = { + "Net_EthernetPortAllocationSettingData", + NULL +}; + +static char *ep[] = { + "Net_EthernetPort", + NULL +}; + +static char *assoc_vess[] = { + "Net_ElementSettingData", + NULL +}; + +static char *assoc_conn[] = { + "Net_EthernetPortConnectionSettingData", + NULL +}; + static struct std_assoc _vssd_to_vssd = { .source_class = (char**)&virtual_system_setting_data, .source_prop = "ManagedElement", @@ -177,9 +348,65 @@ static struct std_assoc _rasd_to_rasd = { .make_ref = make_ref }; +static struct std_assoc _vesssd_to_vesssd = { + .source_class = (char **)&vesssd, + .source_prop = "ManagedElement", + + .target_class = (char **)&vesssd, + .target_prop = "SettingData", + + .assoc_class = (char **)&assoc_vess, + + .handler = vesssd_to_vesssd, + .make_ref = make_ref +}; + +static struct std_assoc _easd_to_easd = { + .source_class = (char **)&easd, + .source_prop = "ManagedElement", + + .target_class = (char **)&easd, + .target_prop = "SettingData", + + .assoc_class = (char **)&assoc_vess, + + .handler = easd_to_easd, + .make_ref = make_ref +}; + +static struct std_assoc _easd_to_ep = { + .source_class = (char **)&easd, + .source_prop = "ManagedElement", + + .target_class = (char **)&ep, + .target_prop = "SettingData", + + .assoc_class = (char **)&assoc_conn, + + .handler = easd_to_ep, + .make_ref = make_ref +}; + +static struct std_assoc _ep_to_easd = { + .source_class = (char **)&ep, + .source_prop = "ManagedElement", + + .target_class = (char **)&easd, + .target_prop = "SettingData", + + .assoc_class = (char **)&assoc_conn, + + .handler = ep_to_easd, + .make_ref = make_ref +}; + static struct std_assoc *handlers[] = { &_vssd_to_vssd, &_rasd_to_rasd, + &_vesssd_to_vesssd, + &_easd_to_easd, + &_easd_to_ep, + &_ep_to_easd, NULL }; -- 1.7.6

This patch add the core functions in CIM model, which provided the capabilities to configure the bridge and vlan child ports. It is based on DSP1050. Signed-off-by: Wayne Xia <xiawenc@linux.vnet.ibm.com> --- ...irtualEthernetSwitchSystemManagementService.mof | 14 + ...ernetSwitchSystemManagementService.registration | 3 + ..._VirtualEthernetSwitchSystemManagementService.c | 1342 ++++++++++++++++++++ ..._VirtualEthernetSwitchSystemManagementService.h | 31 + 4 files changed, 1390 insertions(+), 0 deletions(-) create mode 100644 schema/VirtualEthernetSwitchSystemManagementService.mof create mode 100644 schema/VirtualEthernetSwitchSystemManagementService.registration create mode 100644 src/Virt_VirtualEthernetSwitchSystemManagementService.c create mode 100644 src/Virt_VirtualEthernetSwitchSystemManagementService.h diff --git a/schema/VirtualEthernetSwitchSystemManagementService.mof b/schema/VirtualEthernetSwitchSystemManagementService.mof new file mode 100644 index 0000000..5317305 --- /dev/null +++ b/schema/VirtualEthernetSwitchSystemManagementService.mof @@ -0,0 +1,14 @@ +// Copyright IBM Corp. 2011 + +[Provider("cmpi::Virt_VirtualEthernetSwitchSystemManagementService")] +class Net_VirtualEthernetSwitchSystemManagementService : CIM_VirtualSystemManagementService +{ + [Description("HG changeset id of the providers")] + string Changeset; + + [Description("HG revision number of the providers")] + string Revision; + + [Description("Package Version")] + string Release; +}; diff --git a/schema/VirtualEthernetSwitchSystemManagementService.registration b/schema/VirtualEthernetSwitchSystemManagementService.registration new file mode 100644 index 0000000..ef2b4b1 --- /dev/null +++ b/schema/VirtualEthernetSwitchSystemManagementService.registration @@ -0,0 +1,3 @@ +# Copyright IBM Corp. 2011 +# Classname Namespace ProviderName ProviderModule ProviderTypes +Net_VirtualEthernetSwitchSystemManagementService root/virt Virt_VirtualEthernetSwitchSystemManagementService Virt_VirtualEthernetSwitchSystemManagementService method instance diff --git a/src/Virt_VirtualEthernetSwitchSystemManagementService.c b/src/Virt_VirtualEthernetSwitchSystemManagementService.c new file mode 100644 index 0000000..c60068c --- /dev/null +++ b/src/Virt_VirtualEthernetSwitchSystemManagementService.c @@ -0,0 +1,1342 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia <xiawenc@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 <string.h> +#include <stdlib.h> +#include <stdbool.h> +#include <inttypes.h> +#include <time.h> +#include <sys/time.h> +#include <libvirt/libvirt.h> + +#include "cmpidt.h" +#include "cmpift.h" +#include "cmpimacs.h" + +#include "cs_util.h" +#include "misc_util.h" +#include "device_parsing.h" +#include "xmlgen.h" + +#include <libcmpiutil/libcmpiutil.h> +#include <libcmpiutil/std_invokemethod.h> +#include <libcmpiutil/std_indication.h> +#include <libcmpiutil/std_instance.h> + +#include "misc_util.h" +#include "infostore.h" + +#include "Virt_VirtualSystemManagementService.h" +#include "Virt_VirtualEthernetSwitchSystemManagementService.h" +#include "Virt_VirtualEthernetSwitchSystem.h" +#include "Virt_HostSystem.h" +#include "Virt_EASD.h" +#include "network_model.h" +#include "svpc_types.h" + +#include "config.h" + + +static const CMPIBroker *_BROKER; + +typedef enum ResourceAction { + RESOURCE_ADD, + RESOURCE_DEL, + RESOURCE_MOD, +} ResourceAction; + +static CMPIArray *set_result_res_vessms(struct inst_list *list, + const char *ns) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIObjectPath *op = NULL; + CMPIArray *res = NULL; + int i = 0; + + if (list->cur == 0) { + CU_DEBUG("No resources were added or modified"); + return res; + } + + res = CMNewArray(_BROKER, list->cur, CMPI_ref, &s); + if ((s.rc != CMPI_RC_OK) || (res == NULL)) { + CU_DEBUG("Unable to create results array"); + goto out; + } + + for (i = 0; list->list[i] != NULL; i++) { + op = CMGetObjectPath(list->list[i], NULL); + if (op == NULL) { + CU_DEBUG("Unable to EASD reference"); + goto out; + } + CMSetNameSpace(op, ns); + + s = CMSetArrayElementAt(res, i, (CMPIValue *)&op, CMPI_ref); + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("Error setting results array element"); + goto out; + } + } + + out: + if (s.rc != CMPI_RC_OK) { + res = NULL; + } + + return res; +} + +static CMPIStatus check_piface_for_easd_ea(const CMPIBroker *broker, + EthIface *piface) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + VLAN_Prop_8021q *pvlan_8021q; + if ((piface->eth_type != ETH_TYPE_VLAN) || + (piface->pvlan_prop->vlan_type != VLAN_TYPE_802_1_Q)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "now only support opertaion for IEEE 802.1.q."); + CU_DEBUG("only support IEEE 802.1.q."); + eth_iface_print(piface); + goto out; + } + + pvlan_8021q = &(piface->pvlan_prop->props.prop_8021q); + if ((pvlan_8021q->vlan_id < 0) || (pvlan_8021q->vlan_id > 4095)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "invalid vlan id set."); + CU_DEBUG("invalid vlan id %d set.", pvlan_8021q->vlan_id); + goto out; + } + + out: + return s; +} + +static CMPIStatus check_piface_for_easd_ec(const CMPIBroker *broker, + EthIface *piface_src, + EthIface *piface_dest) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + if ((piface_dest->eth_type != ETH_TYPE_BRIDGE) || + (piface_dest->name == NULL)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "now only support connection between bridge and " + "port, but the dest is not a bridge or " + "dest name not got."); + CU_DEBUG("requested connectting device %s is not a bridge.", + piface_dest->name); + goto out; + } + + if (piface_src->name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "connection src port was not got."); + CU_DEBUG("connection src port was not got."); + goto out; + } + + out: + return s; +} + +/* piface need to be created before calling the funtion */ +static CMPIStatus instance_to_vesssd(const CMPIBroker *broker, + EthIface *piface, + CMPIInstance *inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIObjectPath *opathp = NULL; + const char *brname = NULL; + const char *cn; + char *pfx = NULL; + uint16_t stp; + int ret; + + opathp = CMGetObjectPath(inst, NULL); + if (opathp == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_NOT_FOUND, + "failed to get object path."); + goto out; + } + + cn = CLASSNAME(opathp); + pfx = class_prefix_name(cn); + if (pfx == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_NOT_FOUND, + "Unknown prefix for the class."); + goto out; + } + + ret = cu_get_str_prop(inst, "VirtualSystemIdentifier", &brname); + if (ret != CMPI_RC_OK) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "property VirtualSystemIdentifier not set."); + CU_DEBUG("failed to get property VirtualSystemIdentifier."); + goto out; + } + piface->name = get_iface_name_from_switch(brname); + if (piface->name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to convert switch_name"); + CU_DEBUG("switch name %s failed to convert.", brname); + goto out; + } + + ret = cu_get_u16_prop(inst, "STP", &stp); + if (ret == CMPI_RC_OK) { + piface->pbr_prop->STP = stp; + } + + out: + free(pfx); + return s; +} + +static CMPIStatus instance_to_easd_ea(const CMPIBroker *broker, + EthIface *piface, + CMPIInstance *inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIStatus s_tmp; + int ret, temp; + uint16_t vlan_type = 0; + uint16_t hdr = 0; + char *charpvalues[8]; + int charpcount = 0; + VLAN_Prop_8021q *pvlan_8021q = NULL; + VLAN_Qos_8021q qos; + const char *ingress; + const char *egress; + + ret = cu_get_u16_prop(inst, "VLANType", &vlan_type); + if (ret == CMPI_RC_OK) { + if (vlan_type == 1) { + piface->eth_type = ETH_TYPE_VLAN; + piface->pvlan_prop->vlan_type = VLAN_TYPE_802_1_Q; + pvlan_8021q = &(piface->pvlan_prop->props.prop_8021q); + } else { + CU_DEBUG("unsupported VLANType " + "%d requested", vlan_type); + } + } else { + CU_DEBUG("VLANType is missing"); + } + + if ((pvlan_8021q == NULL) || + (piface->pvlan_prop->vlan_type != VLAN_TYPE_802_1_Q)) { + goto end_of_8021q; + } + + pvlan_8021q->parent = SAFE_STRDUP(piface->dep_ifname); + + s_tmp = get_array_string_from_instance(broker, inst, "Connection", + charpvalues, &charpcount, 8); + if ((s_tmp.rc == CMPI_RC_OK) && (charpcount == 1)) { + temp = vlanid_from_connection_name(charpvalues[0]); + if ((temp >= 0) && (temp < 4096)) { + pvlan_8021q->vlan_id = temp; + } + } else { + CU_DEBUG("Connnection property have %d settings.", charpcount); + } + + /* optional settings */ + ret = cu_get_u16_prop(inst, "ReorderHdr", &hdr); + if (ret == CMPI_RC_OK) { + pvlan_8021q->reorder_hdr = hdr; + } + + ret = cu_get_str_prop(inst, "VLANQosIngress", &ingress); + if (ret == CMPI_RC_OK) { + CU_DEBUG("vlan qos ingress was got."); + if (1 == vlan_8021q_qos_str_to_num(&qos, ingress)) { + pvlan_8021q->ingress = qos; + } else { + CU_DEBUG("invalid ingress string.") + } + } + + ret = cu_get_str_prop(inst, "VLANQosEgress", &egress); + if (ret == CMPI_RC_OK) { + CU_DEBUG("vlan qos egress was got."); + if (1 == vlan_8021q_qos_str_to_num(&qos, egress)) { + pvlan_8021q->egress = qos; + } else { + CU_DEBUG("invalid ingress string.") + } + } + + end_of_8021q: + return s; +} + +static CMPIStatus instance_to_easd_ec(const CMPIBroker *broker, + EthIface *piface_src, + EthIface *piface_dest, + CMPIInstance *inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}, s_tmp; + int ret, i; + char *charpvalues[8]; + int charpcount = 0; + char *prefix = NULL, *portname = NULL; + const char *tmp; + + s_tmp = get_array_string_from_instance(broker, inst, "HostResource", + charpvalues, &charpcount, 8); + if ((s_tmp.rc == CMPI_RC_OK) && (charpcount == 1)) { + piface_dest->name = get_iface_name_from_switch(charpvalues[0]); + if (piface_dest->name != NULL) { + piface_dest->eth_type = ETH_TYPE_BRIDGE; + } + } else { + CU_DEBUG("HostResource have %d settings.", charpcount); + } + i = 0; + while (i < charpcount) { + SAFE_FREE(charpvalues[i]); + i++; + } + + ret = cu_get_str_prop(inst, "Parent", &tmp); + if (ret == CMPI_RC_OK) { + if (1 == parse_fq_devid(tmp, &prefix, &portname)) { + SAFE_FREE(piface_src->name); + piface_src->name = get_iface_name_from_ethportsd(portname, + NULL); + } + } + + SAFE_FREE(prefix); + SAFE_FREE(portname); + return s; +} + +/* pifaces need to be created before calling the funtion */ +static CMPIStatus instance_to_easd(const CMPIBroker *broker, + const char *preset_parent, + EthIface *piface_src, + EthIface *piface_dest, + CMPIInstance *inst, + int *type) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + char *prefix = NULL; + char *name = NULL; + char *port_name = NULL; + char *switch_name = NULL; + const char *tmp; + int request_type = 0; + int ret; + + CU_DEBUG("enter inst to easd, preset_parent is %s.", preset_parent); + /* If a preset_parent is set by the user, then the code use it as + parent device. This parameter was used when user call the method + with parameter AffectedSystem was set. */ + if (preset_parent == NULL) { + s = get_instanceid(inst, &prefix, &name); + if ((s.rc != CMPI_RC_OK) || + (prefix == NULL) || (name == NULL)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_NOT_FOUND, + "failed to translate InstanceId"); + CU_DEBUG("failed to translate InstanceId, " + "prefix %s, name %s.", prefix, name); + goto out; + } + } else { + /*fix me, use value from Parent if ElementName was not set */ + ret = cu_get_str_prop(inst, "ElementName", &tmp); + if (ret == CMPI_RC_OK) { + name = SAFE_STRDUP(tmp); + prefix = SAFE_STRDUP(preset_parent); + } else { + s = get_instanceid(inst, &prefix, &name); + if ((s.rc != CMPI_RC_OK) || (name == NULL)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_NOT_FOUND, + "failed to get port name, " + "InstanceID or ElementName " + "need to be set correctly."); + CU_DEBUG("failed to geto port name, " + "prefix %s, name %s.", prefix, name); + goto out; + } + } + } + + if (name == NULL) { + s = get_instanceid(inst, &prefix, &name); + if ((s.rc != CMPI_RC_OK) || + (prefix == NULL) || (name == NULL)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_NOT_FOUND, + "failed to translate InstanceId"); + CU_DEBUG("failed to translate InstanceId, " + "prefix %s, name %s.", prefix, name); + goto out; + } + } + + switch_name = get_iface_name_from_switch(prefix); + if (switch_name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to convert instance prefix name"); + CU_DEBUG("switch name %s failed to convert.", prefix); + goto out; + } + port_name = get_iface_name_from_ethportsd(name, &request_type); + if (port_name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to convert instance suffix name"); + CU_DEBUG("ethport name %s failed to convert.", name); + goto out; + } + + if (request_type == EASD_TYPE_EA) { + piface_src->name = port_name; + piface_src->dep_ifname = switch_name; + port_name = NULL; + switch_name = NULL; + s = instance_to_easd_ea(broker, piface_src, inst); + } else { + piface_src->name = port_name; + port_name = NULL; + s = instance_to_easd_ec(broker, piface_src, piface_dest, inst); + } + + out: + *type = request_type; + SAFE_FREE(prefix); + SAFE_FREE(name); + SAFE_FREE(port_name); + SAFE_FREE(switch_name); + return s; +} + +static CMPIStatus find_merge_existing_easd(const CMPIBroker *broker, + EthIface *piface) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + EthIface iface_ref; + EthIfacesList ifaces_list; + int ret; + + eth_ifaceslist_init(&ifaces_list); + eth_iface_init(&iface_ref); + if (piface->name == NULL) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "switch name not set."); + goto out; + } + iface_ref.name = SAFE_STRDUP(piface->name); + iface_ref.eth_type = piface->eth_type; + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_by_ref, &iface_ref); + if ((ret != 1) || (ifaces_list.count != 1)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to get original easd settings," + " maybe it do not exist."); + goto out; + } + eth_iface_merge(piface, ifaces_list.pifaces[0], 1); + out: + eth_ifaceslist_uninit(&ifaces_list); + eth_iface_uninit(&iface_ref); + return s; +} + +static CMPIStatus _update_easd_for(const CMPIBroker *broker, + const CMPIContext *context, + const CMPIObjectPath *ref, + const char *preset_parent, + CMPIInstance *rasd, + ResourceAction action) +{ + CMPIStatus s; + int type; + EthIface iface_src, iface_dest; + int ret; + char *errstr; + + eth_iface_init(&iface_src); + eth_iface_init(&iface_dest); + eth_iface_add_br_prop(&iface_src); + eth_iface_add_vlan_prop(&iface_src, VLAN_TYPE_802_1_Q); + eth_iface_add_br_prop(&iface_dest); + eth_iface_add_vlan_prop(&iface_dest, VLAN_TYPE_802_1_Q); + + + CU_DEBUG("Enter _update_easd_for"); + s = instance_to_easd(broker, preset_parent, + &iface_src, &iface_dest, rasd, &type); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + if (type == EASD_TYPE_EA) { + s = check_piface_for_easd_ea(broker, &iface_src); + if (s.rc != CMPI_RC_OK) { + goto out; + } + CU_DEBUG("easd-EA operation with request type %d," + "iface settings is :", action); + eth_iface_print(&iface_src); + if (action == RESOURCE_ADD) { + ret = add_host_iface(&iface_src, 1); + } else if (action == RESOURCE_MOD) { + s = find_merge_existing_easd(broker, &iface_src); + if (s.rc != CMPI_RC_OK) { + goto out; + } + ret = mod_host_iface(&iface_src, 1); + } else if (action == RESOURCE_DEL) { + ret = del_host_iface(&iface_src, 1); + } else { + errstr = "requested an unsupported operation."; + CU_DEBUG("%s", errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + } else { + s = check_piface_for_easd_ec(broker, &iface_src, &iface_dest); + if (s.rc != CMPI_RC_OK) { + goto out; + } + CU_DEBUG("easd-EC operation with request type %d," + "iface settings are :", action); + eth_iface_print(&iface_src); + eth_iface_print(&iface_dest); + if (action == RESOURCE_ADD) { + ret = connect_two_ifaces(&iface_src, &iface_dest, 1); + } else if (action == RESOURCE_DEL) { + ret = disconnect_two_ifaces(&iface_src, &iface_dest, 1); + } else { + errstr = "requested an unsupported operation."; + CU_DEBUG("%s", errstr); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + errstr); + goto out; + } + } + + 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; + } + + out: + eth_iface_uninit(&iface_src); + eth_iface_uninit(&iface_dest); + return s; +} + +static CMPIStatus _update_easd_settings(const CMPIContext *context, + const CMPIObjectPath *ref, + const char *bridge, + CMPIArray *resources, + const CMPIResult *results, + ResourceAction action, + struct inst_list *list) +{ + int i; + CMPIStatus s = {CMPI_RC_OK, NULL}; + int count = 0; + uint32_t rc = CIM_SVPC_RETURN_FAILED; + + CU_DEBUG("Enter _update_easd_settings"); + if (resources == NULL) { + CU_DEBUG("No easd settings."); + goto out; + } + + count = CMGetArrayCount(resources, &s); + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("failed to get array size."); + goto out; + } + + i = 0; + CU_DEBUG("Trying update %d easds.", count); + while (i < count) { + CMPIData item; + CMPIInstance *inst; + item = CMGetArrayElementAt(resources, i, NULL); + inst = item.value.inst; + + s = _update_easd_for(_BROKER, + context, + ref, + bridge, + inst, + action); + if (s.rc != CMPI_RC_OK) { + break; + } + inst_list_add(list, inst); + i++; + } + + out: + if (s.rc == CMPI_RC_OK) { + rc = CIM_SVPC_RETURN_COMPLETED; + } + if ((results != NULL) && (resources != NULL)) { + CMReturnData(results, &rc, CMPI_uint32); + } + + return s; +} + +static CMPIStatus easd_refs_to_insts(const CMPIBroker *broker, + const CMPIContext *ctx, + const CMPIObjectPath *reference, + CMPIArray *arr, + CMPIArray **ret_arr) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIArray *tmp_arr; + int i; + int c; + + c = CMGetArrayCount(arr, &s); + if (s.rc != CMPI_RC_OK) { + return s; + } + + tmp_arr = CMNewArray(broker, + c, + CMPI_instance, + &s); + + for (i = 0; i < c; i++) { + CMPIData d; + CMPIObjectPath *ref; + CMPIInstance *inst = NULL; + const char *id; + + d = CMGetArrayElementAt(arr, i, &s); + ref = d.value.ref; + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("Unable to get ResourceSettings[%i]", i); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Unable to get ResourceSettings"); + goto out; + } + + if (cu_get_str_path(ref, "InstanceID", &id) != CMPI_RC_OK) { + CU_DEBUG("Unable to get InstanceID of `%s'", + REF2STR(ref)); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Unable to get InstanceID"); + goto out; + } + + s = get_easd_by_id(broker, id, reference, NULL, &inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + CMSetArrayElementAt(tmp_arr, i, + &inst, + CMPI_instance); + + } + + *ret_arr = tmp_arr; + + out: + return s; +} + +static CMPIInstance *create_switch_system(const CMPIContext *context, + CMPIInstance *vsssd, + CMPIArray *resources, + const CMPIObjectPath *ref, + const CMPIObjectPath *refconf, + CMPIStatus *s) +{ + CMPIInstance *inst = NULL; + EthIface iface_br; + int ret; + char *errstr; + char *br_name = NULL; + struct inst_list list; + + inst_list_init(&list); + eth_iface_init(&iface_br); + eth_iface_add_br_prop(&iface_br); + + CU_DEBUG("Enter create_switch_system"); + if (refconf != NULL) { + cu_statusf(_BROKER, s, + CMPI_RC_ERR_FAILED, + "creating switch system with" + " reference is not supported now."); + goto out; + } + + *s = instance_to_vesssd(_BROKER, &iface_br, vsssd); + if (s->rc != CMPI_RC_OK) { + cu_statusf(_BROKER, s, + CMPI_RC_ERR_FAILED, + "failed to translate settings."); + goto out; + } + iface_br.eth_type = ETH_TYPE_BRIDGE; + CU_DEBUG("Creating Switch System as follow:"); + eth_iface_print(&iface_br); + + ret = add_host_iface(&iface_br, 1); + 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; + } + + br_name = get_switch_name_from_iface(iface_br.name); + *s = _update_easd_settings(context, + ref, + br_name, + resources, + NULL, + RESOURCE_ADD, + &list); + + + *s = get_switch_by_name(_BROKER, + br_name, + ref, + &inst); + + out: + inst_list_free(&list); + eth_iface_uninit(&iface_br); + free(br_name); + + return inst; +} + +static CMPIStatus update_switchsystem_settings(const CMPIContext *context, + const CMPIObjectPath *ref, + CMPIInstance *vsssd) +{ + CMPIStatus s; + EthIface iface_br, iface_ref; + EthIfacesList ifaces_list; + int ret; + char *errstr; + + eth_ifaceslist_init(&ifaces_list); + eth_iface_init(&iface_br); + eth_iface_init(&iface_ref); + eth_iface_add_br_prop(&iface_br); + + s = instance_to_vesssd(_BROKER, &iface_br, vsssd); + if (s.rc != CMPI_RC_OK || (iface_br.name == NULL)) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "failed to translate settings."); + goto out; + + } + + iface_ref.name = SAFE_STRDUP(iface_br.name); + iface_ref.eth_type = iface_br.eth_type; + ret = get_host_ifaces(&ifaces_list, + eth_iface_filter_by_ref, &iface_ref); + if ((ret != 1) || (ifaces_list.count != 1)) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "failed to get original vs settings," + " maybe it do not exist."); + goto out; + } + eth_iface_merge(&iface_br, ifaces_list.pifaces[0], 1); + CU_DEBUG("update switch settings as following settings:"); + eth_iface_print(&iface_br); + ret = mod_host_iface(&iface_br, 1); + 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; + } + + out: + eth_ifaceslist_uninit(&ifaces_list); + eth_iface_uninit(&iface_ref); + eth_iface_uninit(&iface_br); + return s; +} + +static CMPIStatus define_switch_system_parse_args(const CMPIArgs *argsin, + CMPIInstance **sys, + const char *ns, + CMPIArray **res, + CMPIObjectPath **refconf) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + + if (cu_get_inst_arg(argsin, "SystemSettings", sys) != CMPI_RC_OK) { + CU_DEBUG("No SystemSettings string argument"); + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_INVALID_PARAMETER, + "Missing argument `SystemSettings'"); + goto out; + } + + if (cu_get_array_arg(argsin, "ResourceSettings", res) != + CMPI_RC_OK) { + CU_DEBUG("Did not get ResourceSettings arg"); + *res = NULL; + } + + if (cu_get_ref_arg(argsin, "ReferenceConfiguration", refconf) != + CMPI_RC_OK) { + CU_DEBUG("Did not get ReferenceConfiguration arg"); + *refconf = NULL; + } + out: + return s; +} + +static CMPIStatus define_system(CMPIMethodMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const CMPIArgs *argsin, + CMPIArgs *argsout) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *vsssd; + CMPIArray *res; + CMPIObjectPath *refconf; + CMPIInstance *sys = NULL; + CMPIObjectPath *result; + uint32_t rc = CIM_SVPC_RETURN_FAILED; + + CU_DEBUG("DefineSystem"); + + s = define_switch_system_parse_args(argsin, + &vsssd, + NAMESPACE(reference), + &res, + &refconf); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + sys = create_switch_system(context, vsssd, res, reference, refconf, &s); + if (sys == NULL) { + goto out; + } + + result = CMGetObjectPath(sys, &s); + if ((result != NULL) && (s.rc == CMPI_RC_OK)) { + CMSetNameSpace(result, NAMESPACE(reference)); + CMAddArg(argsout, "ResultingSystem", &result, CMPI_ref); + } + + + out: + if (s.rc == CMPI_RC_OK) { + rc = CIM_SVPC_RETURN_COMPLETED; + } + CMReturnData(results, &rc, CMPI_uint32); + + return s; +} + +static CMPIStatus destroy_system(CMPIMethodMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const CMPIArgs *argsin, + CMPIArgs *argsout) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + const char *br_name = NULL; + EthIface iface_br; + uint32_t rc = IM_RC_FAILED; + CMPIObjectPath *sys; + int ret; + char *errstr; + + eth_iface_init(&iface_br); + CU_DEBUG("entering destroy switch system."); + + if (cu_get_ref_arg(argsin, "AffectedSystem", &sys) != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "AffectedSystem not set"); + goto out; + } + + br_name = get_key_from_ref_arg(argsin, "AffectedSystem", "Name"); + if (br_name == NULL) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Failed get Name of AffectedSystem"); + goto out; + } + + iface_br.name = get_iface_name_from_switch(br_name); + if (iface_br.name == NULL) { + CU_DEBUG("failed to get iface name from %s.", br_name); + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Failed to translate Name of AffectedSystem"); + goto out; + } + + iface_br.eth_type = ETH_TYPE_BRIDGE; + CU_DEBUG("Deleting Switch System as follow:"); + eth_iface_print(&iface_br); + + ret = del_host_iface(&iface_br, 1); + 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; + } + + rc = IM_RC_OK; + + out: + eth_iface_uninit(&iface_br); + CMReturnData(results, &rc, CMPI_uint32); + return s; +} + + +static CMPIStatus mod_system_settings(CMPIMethodMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const CMPIArgs *argsin, + CMPIArgs *argsout) +{ + CMPIInstance *inst; + CMPIStatus s; + uint32_t rc; + + if (cu_get_inst_arg(argsin, "SystemSettings", &inst) != CMPI_RC_OK) { + + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Missing SystemSettings"); + goto out; + } + + s = update_switchsystem_settings(context, reference, inst); + out: + if (s.rc == CMPI_RC_OK) { + rc = CIM_SVPC_RETURN_COMPLETED; + } else { + rc = CIM_SVPC_RETURN_FAILED; + } + + CMReturnData(results, &rc, CMPI_uint32); + + return s; +} + +static CMPIStatus add_resource_settings(CMPIMethodMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const CMPIArgs *argsin, + CMPIArgs *argsout) +{ + CMPIArray *arr; + CMPIStatus s; + CMPIObjectPath *sys; + char *bridge = NULL; + CMPIArray *res = NULL; + struct inst_list list; + + inst_list_init(&list); + + if (cu_get_array_arg(argsin, "ResourceSettings", &arr) != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Missing ResourceSettings"); + return s; + } + + if (cu_get_ref_arg(argsin, + "AffectedConfiguration", + &sys) != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_INVALID_PARAMETER, + "Missing AffectedConfiguration parameter"); + return s; + } + + if (!parse_instanceid(sys, NULL, &bridge)) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_INVALID_PARAMETER, + "AffectedConfiguration has invalid InstanceID"); + return s; + } + + s = _update_easd_settings(context, + reference, + bridge, + arr, + results, + RESOURCE_ADD, + &list); + + free(bridge); + + res = set_result_res_vessms(&list, NAMESPACE(reference)); + inst_list_free(&list); + CMAddArg(argsout, "ResultingResourceSettings", &res, CMPI_refA); + + + return s; +} + +static CMPIStatus mod_resource_settings(CMPIMethodMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const CMPIArgs *argsin, + CMPIArgs *argsout) +{ + CMPIArray *arr; + CMPIStatus s; + CMPIArray *res = NULL; + struct inst_list list; + + CU_DEBUG("Enter mod_resource_settings"); + inst_list_init(&list); + + if (cu_get_array_arg(argsin, "ResourceSettings", &arr) != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Missing ResourceSettings"); + return s; + } + + s = _update_easd_settings(context, + reference, + NULL, + arr, + results, + RESOURCE_MOD, + &list); + + res = set_result_res_vessms(&list, NAMESPACE(reference)); + CMAddArg(argsout, "ResultingResourceSettings", &res, CMPI_refA); + inst_list_free(&list); + + return s; +} + +static CMPIStatus rm_resource_settings(CMPIMethodMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const CMPIArgs *argsin, + CMPIArgs *argsout) +{ + /* The RemoveResources case is different from either Add or + * Modify, because it takes references instead of instances + */ + + CMPIArray *arr; + CMPIArray *resource_arr = NULL; + CMPIStatus s; + struct inst_list list; + + inst_list_init(&list); + + if (cu_get_array_arg(argsin, "ResourceSettings", &arr) != CMPI_RC_OK) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Missing ResourceSettings"); + goto out; + } + + /* delete is simple, just specify the names */ + s = easd_refs_to_insts(_BROKER, context, reference, arr, + &resource_arr); + if (s.rc != CMPI_RC_OK) { + goto out; + } + + s = _update_easd_settings(context, + reference, + NULL, + resource_arr, + results, + RESOURCE_DEL, + &list); + out: + inst_list_free(&list); + + return s; +} + +static struct method_handler DefineSystem = { + .name = "DefineSystem", + .handler = define_system, + .args = {{"SystemSettings", CMPI_instance, false}, + {"ResourceSettings", CMPI_instanceA, true}, + {"ReferenceConfiguration", CMPI_ref, true}, + ARG_END + } +}; + +static struct method_handler DestroySystem = { + .name = "DestroySystem", + .handler = destroy_system, + .args = {{"AffectedSystem", CMPI_ref, false}, + ARG_END + } +}; + +static struct method_handler AddResourceSettings = { + .name = "AddResourceSettings", + .handler = add_resource_settings, + .args = {{"AffectedConfiguration", CMPI_ref, false}, + {"ResourceSettings", CMPI_instanceA, false}, + ARG_END + } +}; + +static struct method_handler ModifyResourceSettings = { + .name = "ModifyResourceSettings", + .handler = mod_resource_settings, + .args = {{"ResourceSettings", CMPI_instanceA, false}, + ARG_END + } +}; + +static struct method_handler ModifySystemSettings = { + .name = "ModifySystemSettings", + .handler = mod_system_settings, + .args = {{"SystemSettings", CMPI_instance, false}, + ARG_END + } +}; + +static struct method_handler RemoveResourceSettings = { + .name = "RemoveResourceSettings", + .handler = rm_resource_settings, + .args = {{"ResourceSettings", CMPI_refA, false}, + ARG_END + } +}; + +static struct method_handler *my_handlers[] = { + &DefineSystem, + &DestroySystem, + &AddResourceSettings, + &ModifyResourceSettings, + &ModifySystemSettings, + &RemoveResourceSettings, + NULL, +}; + +STDIM_MethodMIStub(, Virt_VirtualEthernetSwitchSystemManagementService, + _BROKER, libvirt_cim_init(), my_handlers); + + +CMPIStatus get_vessms(const CMPIObjectPath *reference, + CMPIInstance **_inst, + const CMPIBroker *broker, + const CMPIContext *context, + bool is_get_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst = NULL; + char host_name[256]; + CMPIArray *array; + uint16_t op_status; + + *_inst = NULL; + + inst = get_typed_instance(broker, + NETWORK_CLASS_PREFIX, + "VirtualEthernetSwitchSystemManagementService", + NAMESPACE(reference)); + + if (inst == NULL) { + CU_DEBUG("Failed to get typed instance"); + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "Failed to create instance"); + goto out; + } + + CMSetProperty(inst, "Caption", + (CMPIValue *)"VLAN and VBridge services", CMPI_chars); + + CMSetProperty(inst, "Name", + (CMPIValue *)"Management Service", CMPI_chars); + + if (0 == get_fqdn(host_name, sizeof(host_name))) { + CMSetProperty(inst, "SystemName", + (CMPIValue *)host_name, CMPI_chars); + } + + CMSetProperty(inst, "SystemCreationClassName", + (CMPIValue *)"KVM_HostSystem", CMPI_chars); + + + CMSetProperty(inst, "Revision", + (CMPIValue *)LIBVIRT_CIM_RV, CMPI_chars); + + CMSetProperty(inst, "Release", + (CMPIValue *)PACKAGE_VERSION, CMPI_chars); + + array = CMNewArray(broker, 1, CMPI_uint16, &s); + if ((s.rc != CMPI_RC_OK) || (CMIsNullObject(array))) { + goto out; + } + + op_status = CIM_OPERATIONAL_STATUS; + CMSetArrayElementAt(array, 0, &op_status, CMPI_uint16); + + CMSetProperty(inst, "OperationalStatus", + (CMPIValue *)&array, CMPI_uint16A); + + if (is_get_inst) { + s = cu_validate_ref(broker, reference, inst); + if (s.rc != CMPI_RC_OK) { + goto out; + } + } + + cu_statusf(broker, &s, + CMPI_RC_OK, + ""); + out: + *_inst = inst; + + return s; +} + +static CMPIStatus return_vessms(const CMPIContext *context, + const CMPIObjectPath *reference, + const CMPIResult *results, + bool name_only, + bool is_get_inst) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIInstance *inst; + + s = get_vessms(reference, &inst, _BROKER, context, is_get_inst); + if ((s.rc != CMPI_RC_OK) || (inst == NULL)) { + goto out; + } + + if (name_only) { + cu_return_instance_name(results, inst); + } else { + CMReturnInstance(results, inst); + } + out: + return s; +} + +static CMPIStatus EnumInstanceNames(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference) +{ + return return_vessms(context, reference, results, true, false); +} + +static CMPIStatus EnumInstances(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *reference, + const char **properties) +{ + + return return_vessms(context, reference, results, false, false); +} + +static CMPIStatus GetInstance(CMPIInstanceMI *self, + const CMPIContext *context, + const CMPIResult *results, + const CMPIObjectPath *ref, + const char **properties) +{ + return return_vessms(context, ref, results, false, true); +} + +DEFAULT_CI(); +DEFAULT_MI(); +DEFAULT_DI(); +DEFAULT_EQ(); +DEFAULT_INST_CLEANUP(); + +STD_InstanceMIStub(, + Virt_VirtualEthernetSwitchSystemManagementService, + _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_VirtualEthernetSwitchSystemManagementService.h b/src/Virt_VirtualEthernetSwitchSystemManagementService.h new file mode 100644 index 0000000..07c0f4e --- /dev/null +++ b/src/Virt_VirtualEthernetSwitchSystemManagementService.h @@ -0,0 +1,31 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia <xiawenc@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 VESSMS_H +#define VESSMS_H + +CMPIStatus get_vessms(const CMPIObjectPath *reference, + CMPIInstance **_inst, + const CMPIBroker *broker, + const CMPIContext *context, + bool is_get_inst); + +#endif -- 1.7.6

this patch modified some existing files to let some function could be used by the new codes, and added new help functions in network_model.c. Signed-off-by: Wayne Xia <xiawenc@linux.vnet.ibm.com> --- libxkutil/network_model.c | 466 +++++++++++++++++++++++++++++ libxkutil/network_model.h | 105 +++++++ src/Virt_HostSystem.c | 2 +- src/Virt_HostSystem.h | 2 + src/Virt_VirtualSystemManagementService.c | 17 +- src/Virt_VirtualSystemManagementService.h | 10 + 6 files changed, 592 insertions(+), 10 deletions(-) create mode 100644 libxkutil/network_model.c create mode 100644 libxkutil/network_model.h diff --git a/libxkutil/network_model.c b/libxkutil/network_model.c new file mode 100644 index 0000000..eeee1aa --- /dev/null +++ b/libxkutil/network_model.c @@ -0,0 +1,466 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia <xiawenc@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 <string.h> + +#include "network_model.h" +#include "device_parsing.h" + +#include "cmpidt.h" +#include "cmpift.h" +#include "cmpimacs.h" + +/* this function would return a new allocated string or NULL */ +char *compare_and_switch_prefix(const char *orig_str, + const char *orig_prefix, + const char *dest_prefix) +{ + int orig_prefix_len, dest_prefix_len, asret; + char *retstr = NULL; + const char *suffix; + if (orig_str == NULL) { + goto out; + } + orig_prefix_len = strlen(orig_prefix); + dest_prefix_len = strlen(dest_prefix); + if (0 != strncmp(orig_str, orig_prefix, orig_prefix_len)) { + goto out; + } + suffix = orig_str + orig_prefix_len; + asret = asprintf(&retstr, "%s%s", dest_prefix, suffix); + if (asret == -1) { + free(retstr); + retstr = NULL; + } + out: + return retstr; +} + +char *switch_device_id_prefix(const char *whole_id, + const char *orig_prefix, + const char *dest_prefix) +{ + char *system = NULL; + char *device = NULL; + char *new_id = NULL; + char *retstr = NULL; + int asret; + + + if (0 == parse_fq_devid(whole_id, &system, &device)) { + goto out; + } + + new_id = compare_and_switch_prefix(device, + orig_prefix, dest_prefix); + + if (new_id == NULL) { + goto out; + } + asret = asprintf(&retstr, "%s/%s", system, new_id); + if (asret == -1) { + free(retstr); + retstr = NULL; + } + + out: + free(system); + free(device); + free(new_id); + return retstr; +} + +char *ep_id_to_easdea_id(const char *epid) +{ + return switch_device_id_prefix(epid, + ETHPORT_PREFIX, ETHPORT_ALLOCATION_SD_PREFIX); +} + +char *easdea_id_to_ep_id(const char *epid) +{ + return switch_device_id_prefix(epid, + ETHPORT_ALLOCATION_SD_PREFIX, ETHPORT_PREFIX); +} + +char *ep_id_to_easdec_id(const char *epid) +{ + return switch_device_id_prefix(epid, + ETHPORT_PREFIX, ETHPORT_CONNECTION_SD_PREFIX); +} + +char *easdec_id_to_ep_id(const char *epid) +{ + return switch_device_id_prefix(epid, + ETHPORT_CONNECTION_SD_PREFIX, ETHPORT_PREFIX); +} + +char *vlanid_to_connection_name(const int id) +{ + int asret; + char *str = NULL; + char *prefix = CONNECTION_VLAN_PREFIX; + asret = asprintf(&str, "%s%d", prefix, id); + if (asret == -1) { + return NULL; + } + return str; +} + +int vlanid_from_connection_name(const char *name) +{ + int id = -1; + int temp = -1; + char *prefix = CONNECTION_VLAN_PREFIX; + char *dig_start, *dig_end; + if (name == NULL) { + goto out; + } + dig_start = strstr(name, prefix); + if (dig_start == NULL) { + goto out; + } + dig_start += strlen(prefix); + temp = strtol(dig_start, &dig_end, 10); + if ((dig_start == dig_end) || (temp < 0) || (temp > 4095)) { + goto out; + } + id = temp; + out: + return id; +} + +int eth_iface_filter_cim_ethport(const EthIface *piface, + void *nouse) +{ + if (piface->eth_type == ETH_TYPE_BRIDGE) { + return 0; + } + if (piface->eth_type == ETH_TYPE_LOOPBACK) { + return 0; + } + return 1; +} + +int eth_iface_filter_cim_ethport_for_name(const EthIface *piface, + void *name) +{ + int cim_ethport_flag; + cim_ethport_flag = eth_iface_filter_cim_ethport(piface, NULL); + if (cim_ethport_flag == 1) { + if (0 == strcmp(piface->name, name)) { + return 1; + } + } + return 0; +} + +/* returned value need to be freed */ +char *get_ethportsd_name_from_iface(const char *iface_name, const int type) +{ + char *prefix; + char *name; + int size; + + if (iface_name == NULL) { + return NULL; + } + + if (type == EASD_TYPE_EA) { + prefix = ETHPORT_ALLOCATION_SD_PREFIX; + } else { + prefix = ETHPORT_CONNECTION_SD_PREFIX; + } + + size = strlen(iface_name)+strlen(prefix)+1; + SAFE_MALLOC(name, size); + snprintf(name, size, "%s%s", prefix, iface_name); + return name; +} + +/* returned value need to be freed */ +char *get_iface_name_from_ethportsd(const char *ethport_name, int *ptype) +{ + char *prefix; + char *name = NULL; + int size; + int prefix_len; + int t = -1; + + if (ethport_name == NULL) { + goto out; + } + + prefix = ETHPORT_ALLOCATION_SD_PREFIX; + prefix_len = strlen(prefix); + if (0 != strncmp(ethport_name, prefix, prefix_len)) { + prefix = ETHPORT_CONNECTION_SD_PREFIX; + prefix_len = strlen(prefix); + if (0 != strncmp(ethport_name, prefix, prefix_len)) { + goto out; + } else { + t = EASD_TYPE_EC; + } + } else { + t = EASD_TYPE_EA; + } + size = strlen(ethport_name)-strlen(prefix)+1; + SAFE_MALLOC(name, size); + snprintf(name, size, "%s", ethport_name+prefix_len); + + out: + if (ptype != NULL) { + *ptype = t; + } + return name; +} + +int eth_iface_filter_cim_switch(const EthIface *piface, + void *nouse) +{ + if (piface->eth_type == ETH_TYPE_BRIDGE) { + return 1; + } + return eth_iface_filter_peths(piface, nouse); +} + +int eth_iface_filter_cim_switch_for_name(const EthIface *piface, + void *name) +{ + int cim_switch_flag; + cim_switch_flag = eth_iface_filter_cim_switch(piface, NULL); + if (cim_switch_flag == 1) { + if (0 == strcmp(piface->name, name)) { + return 1; + } + } + return 0; +} + +/* returned value need to be freed */ +char *get_switch_name_from_iface(const char *iface_name) +{ + char *prefix = SWITCH_PREFIX; + char *name; + int size; + + size = strlen(iface_name)+strlen(prefix)+1; + SAFE_MALLOC(name, size); + snprintf(name, size, "%s%s", prefix, iface_name); + return name; +} + +/* returned value need to be freed */ +char *get_iface_name_from_switch(const char *switch_name) +{ + char *prefix = SWITCH_PREFIX; + char *name; + int size; + int prefix_len; + + prefix_len = strlen(prefix); + if (0 != strncmp(switch_name, prefix, prefix_len)) { + return NULL; + } + size = strlen(switch_name)-strlen(prefix)+1; + SAFE_MALLOC(name, size); + snprintf(name, size, "%s", switch_name+prefix_len); + return name; +} + +/* returned value need to be freed */ +char *get_ethport_name_from_iface(const char *iface_name) +{ + char *prefix; + char *name; + int size; + + if (iface_name == NULL) { + return NULL; + } + + prefix = ETHPORT_PREFIX; + size = strlen(iface_name)+strlen(prefix)+1; + SAFE_MALLOC(name, size); + snprintf(name, size, "%s%s", prefix, iface_name); + return name; +} + +/* returned value need to be freed */ +char *get_iface_name_from_ethport(const char *ethport_name) +{ + char *prefix = ETHPORT_PREFIX; + char *name = NULL; + int size; + int prefix_len; + + if (ethport_name == NULL) { + goto out; + } + + prefix = ETHPORT_PREFIX; + prefix_len = strlen(prefix); + if (0 != strncmp(ethport_name, prefix, prefix_len)) { + goto out; + } + size = strlen(ethport_name)-prefix_len+1; + SAFE_MALLOC(name, size); + snprintf(name, size, "%s", ethport_name+prefix_len); + + out: + return name; +} + +int get_possible_bridge_name_for_cim_model(EthIface *piface, + char **pbr1name, char **pbr2name) +{ + char *br1_name; + char *br2_name; + if (piface->attach_bridge != NULL) { + br1_name = get_switch_name_from_iface(piface->attach_bridge); + } else if (piface->dep_ifname != NULL) { + br1_name = get_switch_name_from_iface(piface->dep_ifname); + } else if (piface->eth_type == ETH_TYPE_PHYSICAL) { + br1_name = get_switch_name_from_iface(piface->name); + } else { + br1_name = NULL; + } + + if ((piface->attach_bridge != NULL) && (piface->dep_ifname != NULL)) { + br2_name = get_switch_name_from_iface(piface->dep_ifname); + } else { + br2_name = NULL; + } + + *pbr1name = br1_name; + *pbr2name = br2_name; + return 1; +} + +CMPIStatus get_array_uint16_from_instance(const CMPIBroker *broker, + CMPIInstance *inst, + char *array_name, + int *ret_result, + int *ret_size, + int max_size) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIArray *array; + CMPICount array_size; + CMPIData elem; + int i, ret, count = 0; + + ret = cu_get_array_prop(inst, array_name, &array); + if (ret != CMPI_RC_OK) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "array property not found."); + CU_DEBUG("Failed to get array property %s.", array_name); + goto out; + } + array_size = CMGetArrayCount(array, &s); + if ((s.rc != CMPI_RC_OK) || (array_size > max_size) || + (array_size <= 0)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to get size of array property," + " or its size is 0 or too big."); + CU_DEBUG("failed in getting size of %s property.", array_name); + goto out; + } + for (i = 0; i < array_size; i++) { + elem = CMGetArrayElementAt(array, i, NULL); + if (CMIsNullValue(elem)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "NULL content of array property."); + CU_DEBUG("NULL content of %s property.", array_name); + goto out; + } + if (!(elem.type & CMPI_INTEGER)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "wrong type of array property."); + CU_DEBUG("wrong type of %s property.", array_name); + goto out; + } + ret_result[count] = elem.value.uint16; + count++; + } + out: + *ret_size = count; + return s; +} + +CMPIStatus get_array_string_from_instance(const CMPIBroker *broker, + CMPIInstance *inst, + char *array_name, + char **ret_result, + int *ret_size, + int max_size) +{ + CMPIStatus s = {CMPI_RC_OK, NULL}; + CMPIArray *array; + CMPICount array_size; + CMPIData elem; + const char *str; + int i, ret, count = 0; + + ret = cu_get_array_prop(inst, array_name, &array); + if (ret != CMPI_RC_OK) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "array property not found."); + CU_DEBUG("Failed to get array property %s.", array_name); + goto out; + } + array_size = CMGetArrayCount(array, &s); + if ((s.rc != CMPI_RC_OK) || (array_size > max_size) || + (array_size <= 0)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "failed to get size of array property," + " or its size is 0 or too big."); + CU_DEBUG("failed in getting size of %s property.", array_name); + goto out; + } + for (i = 0; i < array_size; i++) { + elem = CMGetArrayElementAt(array, i, NULL); + if (CMIsNullValue(elem)) { + cu_statusf(broker, &s, + CMPI_RC_ERR_FAILED, + "NULL content of array property."); + CU_DEBUG("NULL content of %s property.", array_name); + goto out; + } + str = NULL; + str = CMGetCharPtr(elem.value.string); + if (str == NULL) { + CU_DEBUG("Could not extract char pointer from " + "CMPIArray %s.", array_name); + goto out; + } + ret_result[count] = SAFE_STRDUP(str); + count++; + } + out: + *ret_size = count; + return s; +} diff --git a/libxkutil/network_model.h b/libxkutil/network_model.h new file mode 100644 index 0000000..3452836 --- /dev/null +++ b/libxkutil/network_model.h @@ -0,0 +1,105 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia <xiawenc@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 NETWORK_MODEL_H +#define NETWORK_MODEL_H + +#include "host_network_API.h" + +#define EASD_TYPE_EA 1 +#define EASD_TYPE_EC 2 + +#define NETWORK_CLASS_PREFIX "Net" + +#define SWITCH_PREFIX "VS_" +#define VESSD_SYSTEM_PREFIX "Virt" +#define ETHPORT_PREFIX "EP_" +#define ETHPORT_ALLOCATION_SD_PREFIX "EA_" +#define ETHPORT_CONNECTION_SD_PREFIX "EC_" + +#define CONNECTION_VLAN_PREFIX "VLAN" + +#define CIM_NUM_NET_ETHERNET 2 +#define CIM_NUM_SWITCH_DEDICATED 38 +#define CIM_NUM_SWITCHPORT 30 +#define CIM_NUM_VLAN_MODE_TRUNK 5 +#define CIM_NUM_CONSUMERVISIBILITY_PASSEDTHROUGH 2 +#define CIM_NUM_CONSUMERVISIBILITY_VIRTUALIZED 3 + +char *get_switch_name_from_iface(const char *iface_name); +char *get_iface_name_from_switch(const char *switch_name); + +char *get_ethport_name_from_iface(const char *iface_name); +char *get_iface_name_from_ethport(const char *ethport_name); + +char *get_ethportsd_name_from_iface(const char *iface_name, const int type); +char *get_iface_name_from_ethportsd(const char *ethport_name, int *ptype); + +char *ep_id_to_easdea_id(const char *epid); +char *easdea_id_to_ep_id(const char *epid); +char *ep_id_to_easdec_id(const char *epid); +char *easdec_id_to_ep_id(const char *epid); + +char *vlanid_to_connection_name(const int id); +int vlanid_from_connection_name(const char *name); + + + + + +int eth_iface_filter_cim_switch(const EthIface *piface, + void *nouse); +int eth_iface_filter_cim_switch_for_name(const EthIface *piface, + void *name); +int eth_iface_filter_cim_ethport(const EthIface *piface, + void *nouse); +int eth_iface_filter_cim_ethport_for_name(const EthIface *piface, + void *name); + +int get_possible_bridge_name_for_cim_model(EthIface *piface, + char **pbr1name, char **pbr2name); + + +char *compare_and_switch_prefix(const char *orig_str, + const char *orig_prefix, + const char *dest_prefix); + +char *switch_device_id_prefix(const char *whole_id, + const char *orig_prefix, + const char *dest_prefix); + +/* other help function related to CIM */ +CMPIStatus get_array_uint16_from_instance(const CMPIBroker *broker, + CMPIInstance *inst, + char *array_name, + int *ret_result, + int *ret_size, + int max_size); + +CMPIStatus get_array_string_from_instance(const CMPIBroker *broker, + CMPIInstance *inst, + char *array_name, + char **ret_result, + int *ret_size, + int max_size); + + +#endif diff --git a/src/Virt_HostSystem.c b/src/Virt_HostSystem.c index 724a5ea..de8ec13 100644 --- a/src/Virt_HostSystem.c +++ b/src/Virt_HostSystem.c @@ -76,7 +76,7 @@ static int resolve_host(char *host, char *buf, int size) return 0; } -static int get_fqdn(char *buf, int size) +int get_fqdn(char *buf, int size) { char host[256]; int ret = 0; diff --git a/src/Virt_HostSystem.h b/src/Virt_HostSystem.h index 53ebf1c..3b988c1 100644 --- a/src/Virt_HostSystem.h +++ b/src/Virt_HostSystem.h @@ -21,6 +21,8 @@ #ifndef __VIRT_HOSTSYSTEM_H #define __VIRT_HOSTSYSTEM_H +int get_fqdn(char *buf, int size); + CMPIStatus get_host(const CMPIBroker *broker, const CMPIContext *context, const CMPIObjectPath *reference, diff --git a/src/Virt_VirtualSystemManagementService.c b/src/Virt_VirtualSystemManagementService.c index 21979c3..cd1672f 100644 --- a/src/Virt_VirtualSystemManagementService.c +++ b/src/Virt_VirtualSystemManagementService.c @@ -1,9 +1,8 @@ /* - * Copyright IBM Corp. 2007 + * Copyright IBM Corp. 2011 * * Authors: - * Dan Smith <danms@us.ibm.com> - * Jay Gagnon <grendel@linux.vnet.ibm.com> + * Wayne Xia <xiawenc@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 @@ -234,11 +233,11 @@ static CMPIStatus check_uuid_in_use(const CMPIObjectPath *ref, return s; } -static CMPIStatus define_system_parse_args(const CMPIArgs *argsin, - CMPIInstance **sys, - const char *ns, - CMPIArray **res, - CMPIObjectPath **refconf) +CMPIStatus define_system_parse_args(const CMPIArgs *argsin, + CMPIInstance **sys, + const char *ns, + CMPIArray **res, + CMPIObjectPath **refconf) { CMPIStatus s = {CMPI_RC_OK, NULL}; @@ -2877,7 +2876,7 @@ static CMPIStatus _update_resources_for(const CMPIContext *context, return s; } -static CMPIStatus get_instanceid(CMPIInstance *rasd, +CMPIStatus get_instanceid(CMPIInstance *rasd, char **domain, char **devid) { diff --git a/src/Virt_VirtualSystemManagementService.h b/src/Virt_VirtualSystemManagementService.h index dbf17cb..eba7124 100644 --- a/src/Virt_VirtualSystemManagementService.h +++ b/src/Virt_VirtualSystemManagementService.h @@ -29,6 +29,16 @@ #define INC_KVM_WEIGHT 1 #define DEFAULT_KVM_WEIGHT 1024 +CMPIStatus get_instanceid(CMPIInstance *rasd, + char **domain, + char **devid); + +CMPIStatus define_system_parse_args(const CMPIArgs *argsin, + CMPIInstance **sys, + const char *ns, + CMPIArray **res, + CMPIObjectPath **refconf); + CMPIStatus get_vsms(const CMPIObjectPath *reference, CMPIInstance **_inst, const CMPIBroker *broker, -- 1.7.6

this is the API layer let the libvirt-cim call. Signed-off-by: Wayne Xia <xiawenc@linux.vnet.ibm.com> --- libxkutil/host_network_API.c | 150 ++++++++++++++++++++++++++++++++++++++++++ libxkutil/host_network_API.h | 32 +++++++++ 2 files changed, 182 insertions(+), 0 deletions(-) create mode 100644 libxkutil/host_network_API.c create mode 100644 libxkutil/host_network_API.h diff --git a/libxkutil/host_network_API.c b/libxkutil/host_network_API.c new file mode 100644 index 0000000..89a9879 --- /dev/null +++ b/libxkutil/host_network_API.c @@ -0,0 +1,150 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia <xiawenc@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. + */ + + +#include "host_network_API.h" +#include "host_network_implement_cmdline.h" +#include "host_network_error.h" + +/* this layer is added to devide the abstraction and implemention, so that + different implemention could be used and switched */ + +int get_host_ifaces(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque) +{ + return get_host_eth_ifaces_cmd_all(plist, filter_func, filter_opaque); +} + +int add_host_iface(EthIface *piface, int persist_flag) +{ + int ret = 0; + if (piface->eth_type == ETH_TYPE_BRIDGE) { + ret = add_host_br_cmd(piface, persist_flag); + } else if (piface->eth_type == ETH_TYPE_VLAN) { + + if (piface->pvlan_prop == NULL) { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } else { + if (piface->pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + ret = add_host_vlan_8021q_cmd(piface, persist_flag); + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + } + + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + + return ret; +} + +int del_host_iface(EthIface *piface, int persist_flag) +{ + int ret = 0; + if (piface->eth_type == ETH_TYPE_BRIDGE) { + ret = del_host_br_cmd(piface, persist_flag); + } else if (piface->eth_type == ETH_TYPE_VLAN) { + + if (piface->pvlan_prop == NULL) { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } else { + if (piface->pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + ret = del_host_vlan_8021q_cmd(piface, persist_flag); + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + } + + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + + return ret; +} + +int mod_host_iface(EthIface *piface, int persist_flag) +{ + int ret = 0; + if (piface->eth_type == ETH_TYPE_BRIDGE) { + ret = mod_host_br_cmd(piface, persist_flag); + } else if (piface->eth_type == ETH_TYPE_VLAN) { + + if (piface->pvlan_prop == NULL) { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } else { + if (piface->pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + ret = mod_host_vlan_8021q_cmd(piface, persist_flag); + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + } + + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + + return ret; +} + +int change_state_host_iface(EthIface *piface, int state) +{ + return change_state_host_iface_cmd(piface, state); +} + +int connect_two_ifaces(EthIface *p1, EthIface *p2, int persist_flag) +{ + if ((p1 == NULL) || (p2 == NULL)) { + return 0; + } + if ((p1->eth_type == ETH_TYPE_BRIDGE) && + (p2->eth_type != ETH_TYPE_BRIDGE)) { + return add_host_iface_to_br_cmd(p2, p1, persist_flag); + } else if ((p1->eth_type != ETH_TYPE_BRIDGE) && + (p2->eth_type == ETH_TYPE_BRIDGE)) { + return add_host_iface_to_br_cmd(p1, p2, persist_flag); + } else { + CU_DEBUG("requested an unsupported operation."); + return ERR_REQUEST_NOT_SUPPORT; + } +} + +int disconnect_two_ifaces(EthIface *p1, EthIface *p2, int persist_flag) +{ + if ((p1 == NULL) || (p2 == NULL)) { + return 0; + } + if ((p1->eth_type == ETH_TYPE_BRIDGE) && + (p2->eth_type != ETH_TYPE_BRIDGE)) { + return remove_host_iface_from_br_cmd(p2, p1, persist_flag); + } else if ((p1->eth_type != ETH_TYPE_BRIDGE) && + (p2->eth_type == ETH_TYPE_BRIDGE)) { + return remove_host_iface_from_br_cmd(p1, p2, persist_flag); + } else { + CU_DEBUG("requested an unsupported operation."); + return ERR_REQUEST_NOT_SUPPORT; + } +} + +char *get_host_iface_error_reason(int errno) +{ + return translate_error_no(errno); +} diff --git a/libxkutil/host_network_API.h b/libxkutil/host_network_API.h new file mode 100644 index 0000000..b821d58 --- /dev/null +++ b/libxkutil/host_network_API.h @@ -0,0 +1,32 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia <xiawenc@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. + */ + +#ifndef HOST_NETWORK_API +#define HOST_NETWORK_API + +#include "host_network_basic.h" +#include "host_network_helper.h" + +int get_host_ifaces(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque); + +int add_host_iface(EthIface *piface, int persist_flag); +int del_host_iface(EthIface *piface, int persist_flag); +int mod_host_iface(EthIface *piface, int persist_flag); +int change_state_host_iface(EthIface *piface, int state); + +int connect_two_ifaces(EthIface *p1, EthIface *p2, int persist_flag); +int disconnect_two_ifaces(EthIface *p1, EthIface *p2, int persist_flag); + +char *get_host_iface_error_reason(int errno); + +#endif -- 1.7.6

Just a thought: I would expect the ordering of the patches to be library (libxkutil) files first, followed by the providers and schema. That's because you have to review the library code to be able to make sense of the providers, etc. On 12/07/2011 04:25 AM, Wayne Xia wrote:
this is the API layer let the libvirt-cim call.
Signed-off-by: Wayne Xia<xiawenc@linux.vnet.ibm.com> --- libxkutil/host_network_API.c | 150 ++++++++++++++++++++++++++++++++++++++++++ libxkutil/host_network_API.h | 32 +++++++++ 2 files changed, 182 insertions(+), 0 deletions(-) create mode 100644 libxkutil/host_network_API.c create mode 100644 libxkutil/host_network_API.h
diff --git a/libxkutil/host_network_API.c b/libxkutil/host_network_API.c new file mode 100644 index 0000000..89a9879 --- /dev/null +++ b/libxkutil/host_network_API.c @@ -0,0 +1,150 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia<xiawenc@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. + */ + + +#include "host_network_API.h" +#include "host_network_implement_cmdline.h" +#include "host_network_error.h"
+ +/* this layer is added to devide the abstraction and implemention, so that + different implemention could be used and switched */ + +int get_host_ifaces(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque) +{ + return get_host_eth_ifaces_cmd_all(plist, filter_func, filter_opaque); +} + Question: Is there any checking to ensure the iface is active? How do we handle inactive ifaces? Ignore if this is presented elsewhere. I'm working backwards
Is there a good reason we can combine some of this into a network_device and/or host_network files? through the code.
+int add_host_iface(EthIface *piface, int persist_flag) +{ + int ret = 0; + if (piface->eth_type == ETH_TYPE_BRIDGE) { + ret = add_host_br_cmd(piface, persist_flag); + } else if (piface->eth_type == ETH_TYPE_VLAN) { + + if (piface->pvlan_prop == NULL) { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } else { + if (piface->pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + ret = add_host_vlan_8021q_cmd(piface, persist_flag); + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + } + + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + + return ret; +} + +int del_host_iface(EthIface *piface, int persist_flag) +{ + int ret = 0; + if (piface->eth_type == ETH_TYPE_BRIDGE) { + ret = del_host_br_cmd(piface, persist_flag); + } else if (piface->eth_type == ETH_TYPE_VLAN) { + + if (piface->pvlan_prop == NULL) { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } else { + if (piface->pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + ret = del_host_vlan_8021q_cmd(piface, persist_flag); + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + } + + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + + return ret; +} It appears we can never delete a physical NIC. Good. + +int mod_host_iface(EthIface *piface, int persist_flag) +{ + int ret = 0; + if (piface->eth_type == ETH_TYPE_BRIDGE) { + ret = mod_host_br_cmd(piface, persist_flag); + } else if (piface->eth_type == ETH_TYPE_VLAN) { + + if (piface->pvlan_prop == NULL) { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } else { + if (piface->pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + ret = mod_host_vlan_8021q_cmd(piface, persist_flag); + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + } + + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + + return ret; +} + +int change_state_host_iface(EthIface *piface, int state) +{ + return change_state_host_iface_cmd(piface, state); +} + +int connect_two_ifaces(EthIface *p1, EthIface *p2, int persist_flag) +{ + if ((p1 == NULL) || (p2 == NULL)) { + return 0; + } + if ((p1->eth_type == ETH_TYPE_BRIDGE)&& + (p2->eth_type != ETH_TYPE_BRIDGE)) { + return add_host_iface_to_br_cmd(p2, p1, persist_flag); + } else if ((p1->eth_type != ETH_TYPE_BRIDGE)&& + (p2->eth_type == ETH_TYPE_BRIDGE)) { + return add_host_iface_to_br_cmd(p1, p2, persist_flag); + } else { + CU_DEBUG("requested an unsupported operation."); + return ERR_REQUEST_NOT_SUPPORT; + } +} + +int disconnect_two_ifaces(EthIface *p1, EthIface *p2, int persist_flag) +{ + if ((p1 == NULL) || (p2 == NULL)) { + return 0; + } + if ((p1->eth_type == ETH_TYPE_BRIDGE)&& + (p2->eth_type != ETH_TYPE_BRIDGE)) { + return remove_host_iface_from_br_cmd(p2, p1, persist_flag); + } else if ((p1->eth_type != ETH_TYPE_BRIDGE)&& + (p2->eth_type == ETH_TYPE_BRIDGE)) { + return remove_host_iface_from_br_cmd(p1, p2, persist_flag); + } else { + CU_DEBUG("requested an unsupported operation."); + return ERR_REQUEST_NOT_SUPPORT; + } +} + +char *get_host_iface_error_reason(int errno) +{ + return translate_error_no(errno); +} I would expect the errno checks would be abstracted. That is, they would be checked after the relevant syscalls and be translated into internal error codes and returned by our wrapper functions.
diff --git a/libxkutil/host_network_API.h b/libxkutil/host_network_API.h new file mode 100644 index 0000000..b821d58 --- /dev/null +++ b/libxkutil/host_network_API.h @@ -0,0 +1,32 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia<xiawenc@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. + */ + +#ifndef HOST_NETWORK_API +#define HOST_NETWORK_API + +#include "host_network_basic.h" +#include "host_network_helper.h" + +int get_host_ifaces(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque); + +int add_host_iface(EthIface *piface, int persist_flag); +int del_host_iface(EthIface *piface, int persist_flag); +int mod_host_iface(EthIface *piface, int persist_flag); +int change_state_host_iface(EthIface *piface, int state); + +int connect_two_ifaces(EthIface *p1, EthIface *p2, int persist_flag); +int disconnect_two_ifaces(EthIface *p1, EthIface *p2, int persist_flag); + +char *get_host_iface_error_reason(int errno); + +#endif
-- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent@linux.vnet.ibm.com

于 2011-12-24 4:01, Chip Vincent 写道:
Just a thought: I would expect the ordering of the patches to be library (libxkutil) files first, followed by the providers and schema. That's because you have to review the library code to be able to make sense of the providers, etc.
OK. A pure C project which would include only the function code and C testing cases was sent before. Running that would be easy to view what it does.
On 12/07/2011 04:25 AM, Wayne Xia wrote:
this is the API layer let the libvirt-cim call.
Signed-off-by: Wayne Xia<xiawenc@linux.vnet.ibm.com> --- libxkutil/host_network_API.c | 150 ++++++++++++++++++++++++++++++++++++++++++ libxkutil/host_network_API.h | 32 +++++++++ 2 files changed, 182 insertions(+), 0 deletions(-) create mode 100644 libxkutil/host_network_API.c create mode 100644 libxkutil/host_network_API.h
diff --git a/libxkutil/host_network_API.c b/libxkutil/host_network_API.c new file mode 100644 index 0000000..89a9879 --- /dev/null +++ b/libxkutil/host_network_API.c @@ -0,0 +1,150 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia<xiawenc@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. + */ + + +#include "host_network_API.h" +#include "host_network_implement_cmdline.h" +#include "host_network_error.h"
Is there a good reason we can combine some of this into a network_device and/or host_network files?
Sorry I did not catch your idea. Do you mean that this file should be merged to another host_network files?
+ +/* this layer is added to devide the abstraction and implemention, so that + different implemention could be used and switched */ + +int get_host_ifaces(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque) +{ + return get_host_eth_ifaces_cmd_all(plist, filter_func, filter_opaque); +} + Question: Is there any checking to ensure the iface is active? How do we handle inactive ifaces? Ignore if this is presented elsewhere. I'm working backwards through the code.
There is a member in struct iface recording the active state, so this function would retrieve all ifaces information.
+int add_host_iface(EthIface *piface, int persist_flag) +{ + int ret = 0; + if (piface->eth_type == ETH_TYPE_BRIDGE) { + ret = add_host_br_cmd(piface, persist_flag); + } else if (piface->eth_type == ETH_TYPE_VLAN) { + + if (piface->pvlan_prop == NULL) { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } else { + if (piface->pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + ret = add_host_vlan_8021q_cmd(piface, persist_flag); + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + } + + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + + return ret; +} + +int del_host_iface(EthIface *piface, int persist_flag) +{ + int ret = 0; + if (piface->eth_type == ETH_TYPE_BRIDGE) { + ret = del_host_br_cmd(piface, persist_flag); + } else if (piface->eth_type == ETH_TYPE_VLAN) { + + if (piface->pvlan_prop == NULL) { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } else { + if (piface->pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + ret = del_host_vlan_8021q_cmd(piface, persist_flag); + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + } + + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + + return ret; +} It appears we can never delete a physical NIC. Good. + +int mod_host_iface(EthIface *piface, int persist_flag) +{ + int ret = 0; + if (piface->eth_type == ETH_TYPE_BRIDGE) { + ret = mod_host_br_cmd(piface, persist_flag); + } else if (piface->eth_type == ETH_TYPE_VLAN) { + + if (piface->pvlan_prop == NULL) { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } else { + if (piface->pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + ret = mod_host_vlan_8021q_cmd(piface, persist_flag); + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + } + + } else { + CU_DEBUG("requested an unsupported operation."); + ret = ERR_REQUEST_NOT_SUPPORT; + } + + return ret; +} + +int change_state_host_iface(EthIface *piface, int state) +{ + return change_state_host_iface_cmd(piface, state); +} + +int connect_two_ifaces(EthIface *p1, EthIface *p2, int persist_flag) +{ + if ((p1 == NULL) || (p2 == NULL)) { + return 0; + } + if ((p1->eth_type == ETH_TYPE_BRIDGE)&& + (p2->eth_type != ETH_TYPE_BRIDGE)) { + return add_host_iface_to_br_cmd(p2, p1, persist_flag); + } else if ((p1->eth_type != ETH_TYPE_BRIDGE)&& + (p2->eth_type == ETH_TYPE_BRIDGE)) { + return add_host_iface_to_br_cmd(p1, p2, persist_flag); + } else { + CU_DEBUG("requested an unsupported operation."); + return ERR_REQUEST_NOT_SUPPORT; + } +} + +int disconnect_two_ifaces(EthIface *p1, EthIface *p2, int persist_flag) +{ + if ((p1 == NULL) || (p2 == NULL)) { + return 0; + } + if ((p1->eth_type == ETH_TYPE_BRIDGE)&& + (p2->eth_type != ETH_TYPE_BRIDGE)) { + return remove_host_iface_from_br_cmd(p2, p1, persist_flag); + } else if ((p1->eth_type != ETH_TYPE_BRIDGE)&& + (p2->eth_type == ETH_TYPE_BRIDGE)) { + return remove_host_iface_from_br_cmd(p1, p2, persist_flag); + } else { + CU_DEBUG("requested an unsupported operation."); + return ERR_REQUEST_NOT_SUPPORT; + } +} + +char *get_host_iface_error_reason(int errno) +{ + return translate_error_no(errno); +} I would expect the errno checks would be abstracted. That is, they would be checked after the relevant syscalls and be translated into internal error codes and returned by our wrapper functions.
What I intended to do is that errno was returned when CIM model code call the "API" functions, and CIM model code could use the errno to call this function to get a string, which was used to tell the user like wbemcli what was happening. Do you mean that this details should be hidden inside libvirt-cim?
diff --git a/libxkutil/host_network_API.h b/libxkutil/host_network_API.h new file mode 100644 index 0000000..b821d58 --- /dev/null +++ b/libxkutil/host_network_API.h @@ -0,0 +1,32 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia<xiawenc@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. + */ + +#ifndef HOST_NETWORK_API +#define HOST_NETWORK_API + +#include "host_network_basic.h" +#include "host_network_helper.h" + +int get_host_ifaces(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque); + +int add_host_iface(EthIface *piface, int persist_flag); +int del_host_iface(EthIface *piface, int persist_flag); +int mod_host_iface(EthIface *piface, int persist_flag); +int change_state_host_iface(EthIface *piface, int state); + +int connect_two_ifaces(EthIface *p1, EthIface *p2, int persist_flag); +int disconnect_two_ifaces(EthIface *p1, EthIface *p2, int persist_flag); + +char *get_host_iface_error_reason(int errno); + +#endif
-- Best Regards Wayne Xia mail:xiawenc@linux.vnet.ibm.com tel:86-010-82450803

this is the core abstraction and structure for ethernet devices. Signed-off-by: Wayne Xia <xiawenc@linux.vnet.ibm.com> --- libxkutil/host_network_basic.c | 639 ++++++++++++++++++++++++++++++++++++++++ libxkutil/host_network_basic.h | 166 +++++++++++ 2 files changed, 805 insertions(+), 0 deletions(-) create mode 100644 libxkutil/host_network_basic.c create mode 100644 libxkutil/host_network_basic.h diff --git a/libxkutil/host_network_basic.c b/libxkutil/host_network_basic.c new file mode 100644 index 0000000..3bcb32e --- /dev/null +++ b/libxkutil/host_network_basic.c @@ -0,0 +1,639 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia <xiawenc@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. + */ + +#include "host_network_basic.h" +#include "host_network_helper.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +static void vlan_prop_print(VLAN_Prop *pvlan_prop) +{ + VLAN_Prop_8021q *p_8021q; + char *ingress = NULL, *egress = NULL; + CMD_DEBUG(1, "--VLAN props: type %d.\n", + pvlan_prop->vlan_type); + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + vlan_8021q_qos_num_to_str(&ingress, &(p_8021q->ingress)); + vlan_8021q_qos_num_to_str(&egress, &(p_8021q->egress)); + CMD_DEBUG(1, "----IEEE802.1.Q: id %d, reorder %d, priority %d, " + "ingress %s, egress %s, parent %s.\n", + p_8021q->vlan_id, p_8021q->reorder_hdr, p_8021q->priv_flag, + ingress, egress, p_8021q->parent); + } + SAFE_FREE(ingress); + SAFE_FREE(egress); +} + +static void br_prop_print(BR_Prop *pbr_prop) +{ + int i = 0; + CMD_DEBUG(1, "--Bridge props: id %s, stp %d, " + "bridge type %d, port_num %d.\n", + pbr_prop->bridge_id, pbr_prop->STP, + pbr_prop->type, pbr_prop->port_num); + if (pbr_prop->port_names != NULL) { + CMD_DEBUG(1, "----Ports attached: "); + while (i < pbr_prop->port_num) { + CMD_DEBUG(1, " %s,", *(pbr_prop->port_names+i)); + i++; + } + CMD_DEBUG(1, "\n"); + } +} + +void eth_iface_print(EthIface *piface) +{ + CMD_DEBUG(1, "Iface device: name %s.\n" + "--Main Props: parent %s, attach to %s, mac %s, ip %s, ip_mask %s," + " RX %lld, TX %lld, state %d, iface type %d.\n", + piface->name, piface->dep_ifname, piface->attach_bridge, + piface->mac, piface->ipv4_prop.ip, piface->ipv4_prop.ip_mask, + piface->run_prop.rx_bytes, piface->run_prop.tx_bytes, + piface->run_prop.state, piface->eth_type); + if (piface->pbr_prop != NULL) { + br_prop_print(piface->pbr_prop); + } + if (piface->pvlan_prop != NULL) { + vlan_prop_print(piface->pvlan_prop); + } + return; +} + +void eth_ifaceslist_print(EthIfacesList *plist) +{ + int i = 0; + CMD_DEBUG(1, "Have %d ifaces in the list:\n", plist->count); + while (i < plist->count) { + CMD_DEBUG(1, "%04d ", i); + eth_iface_print(plist->pifaces[i]); + i++; + } +} + +void vlan_prop_init(VLAN_Prop *pvlan_prop, int vlan_type) +{ + VLAN_Prop_8021q *p_8021q; + memset(pvlan_prop, 0, sizeof(VLAN_Prop)); + pvlan_prop->vlan_type = vlan_type; + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + p_8021q->ingress.count = NUM_NOT_GOT; + p_8021q->egress.count = NUM_NOT_GOT; + p_8021q->vlan_id = NUM_NOT_GOT; + p_8021q->reorder_hdr = NUM_NOT_GOT; + p_8021q->priv_flag = NUM_NOT_GOT; + } +} + +void br_prop_init(BR_Prop *pbr_prop) +{ + memset(pbr_prop, 0, sizeof(BR_Prop)); + pbr_prop->STP = NUM_NOT_GOT; + pbr_prop->type = BR_TYPE_NOT_GOT; + pbr_prop->port_num = NUM_NOT_GOT; +} + +void eth_iface_init(EthIface *piface) +{ + memset(piface, 0, sizeof(EthIface)); + piface->eth_type = ETH_TYPE_NOT_GOT; + piface->run_prop.rx_bytes = NUM_NOT_GOT; + piface->run_prop.tx_bytes = NUM_NOT_GOT; + piface->run_prop.state = ETH_STATE_NOT_GOT; + return; +} + +void eth_iface_add_br_prop(EthIface *piface) +{ + SAFE_MALLOC(piface->pbr_prop, sizeof(BR_Prop)); + br_prop_init(piface->pbr_prop); +} + +void eth_iface_add_vlan_prop(EthIface *piface, int vlan_type) +{ + SAFE_MALLOC(piface->pvlan_prop, sizeof(VLAN_Prop)); + vlan_prop_init(piface->pvlan_prop, vlan_type); +} + +void vlan_prop_uninit(VLAN_Prop *pvlan_prop) +{ + VLAN_Prop_8021q *p_8021q; + if (pvlan_prop == NULL) { + return; + } + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q = &(pvlan_prop->props.prop_8021q); + SAFE_FREE(p_8021q->parent); + } +} + +void br_prop_uninit(BR_Prop *pbr_prop) +{ + int i; + if (pbr_prop == NULL) { + return; + } + SAFE_FREE(pbr_prop->bridge_id); + i = 0; + if (pbr_prop->port_names != NULL) { + while (i < pbr_prop->port_num) { + SAFE_FREE(pbr_prop->port_names[i]); + i++; + } + SAFE_FREE(pbr_prop->port_names); + } +} + +void eth_iface_uninit(EthIface *piface) +{ + if (piface == NULL) { + return; + } + SAFE_FREE(piface->name); + SAFE_FREE(piface->dep_ifname); + SAFE_FREE(piface->attach_bridge); + SAFE_FREE(piface->mac); + SAFE_FREE(piface->ipv4_prop.ip); + SAFE_FREE(piface->ipv4_prop.ip_mask); + br_prop_uninit(piface->pbr_prop); + SAFE_FREE(piface->pbr_prop); + vlan_prop_uninit(piface->pvlan_prop); + SAFE_FREE(piface->pvlan_prop); + return; +} + +void eth_ifaces_clear(EthIface **ppifaces, int num) +{ + EthIface **t; + int i; + if (num <= 0) { + return; + } + t = ppifaces; + i = 0; + while (i < num) { + if (*t != NULL) { + eth_iface_uninit(*t); + SAFE_FREE(*t); + } + t++; + i++; + } + return; +} + +void eth_ifaceslist_init(EthIfacesList *plist) +{ + plist->count = 0; +} + +void eth_ifaceslist_uninit(EthIfacesList *plist) +{ + eth_ifaces_clear(plist->pifaces, plist->count); +} + +static void vlan_prop_dup(VLAN_Prop *dest, const VLAN_Prop *src) +{ + VLAN_Prop_8021q *pd_8021q; + const VLAN_Prop_8021q *ps_8021q; + dest->vlan_type = src->vlan_type; + if (dest->vlan_type == VLAN_TYPE_802_1_Q) { + pd_8021q = &(dest->props.prop_8021q); + ps_8021q = &(src->props.prop_8021q); + pd_8021q->vlan_id = ps_8021q->vlan_id; + pd_8021q->reorder_hdr = ps_8021q->reorder_hdr; + pd_8021q->priv_flag = ps_8021q->priv_flag; + pd_8021q->ingress = ps_8021q->ingress; + pd_8021q->egress = ps_8021q->egress; + pd_8021q->parent = SAFE_STRDUP(ps_8021q->parent); + } +} + +static void br_prop_dup(BR_Prop *dest, const BR_Prop *src) +{ + int i; + dest->bridge_id = SAFE_STRDUP(src->bridge_id); + dest->STP = src->STP; + dest->type = src->type; + SAFE_PSTR_ARRAY_DUP(dest->port_names, dest->port_num, + src->port_names, src->port_num, i); +} + +void eth_iface_dup(EthIface *dest, const EthIface *src) +{ + dest->name = SAFE_STRDUP(src->name); + dest->dep_ifname = SAFE_STRDUP(src->dep_ifname); + dest->attach_bridge = SAFE_STRDUP(src->attach_bridge); + dest->mac = SAFE_STRDUP(src->mac); + dest->eth_type = src->eth_type; + dest->ipv4_prop.ip = SAFE_STRDUP(src->ipv4_prop.ip); + dest->ipv4_prop.ip_mask = SAFE_STRDUP(src->ipv4_prop.ip_mask); + dest->run_prop.rx_bytes = src->run_prop.rx_bytes; + dest->run_prop.tx_bytes = src->run_prop.tx_bytes; + dest->run_prop.state = src->run_prop.state; + + if (src->pbr_prop != NULL) { + SAFE_MALLOC(dest->pbr_prop, sizeof(BR_Prop)); + /* doesn't need init it for that it would be copied at once */ + br_prop_dup(dest->pbr_prop, src->pbr_prop); + } else { + dest->pbr_prop = NULL; + } + + if (src->pvlan_prop != NULL) { + SAFE_MALLOC(dest->pvlan_prop, sizeof(VLAN_Prop)); + /* doesn't need init it for that it would be copied at once */ + vlan_prop_dup(dest->pvlan_prop, src->pvlan_prop); + } else { + dest->pvlan_prop = NULL; + } + +} + +int eth_iface_compare(const EthIface *p1, const EthIface *p2) +{ + int ret = 0; + if ((p1->name != NULL) || (p2->name != NULL)) { + if (0 == strcmp(p1->name, p2->name)) { + ret = 1; + } + } + return ret; +} + +static void vlan_prop_merge(VLAN_Prop *pdest, VLAN_Prop *psrc, int style) +{ + VLAN_Prop_8021q *pd_8021q, *ps_8021q; + + NUM_MERGE(pdest->vlan_type, psrc->vlan_type, VLAN_TYPE_NOT_GOT); + + if (psrc->vlan_type == VLAN_TYPE_802_1_Q) { + pd_8021q = &(pdest->props.prop_8021q); + ps_8021q = &(psrc->props.prop_8021q); + NUM_MERGE(pd_8021q->vlan_id, ps_8021q->vlan_id, NUM_NOT_GOT); + NUM_MERGE(pd_8021q->reorder_hdr, ps_8021q->reorder_hdr, NUM_NOT_GOT); + NUM_MERGE(pd_8021q->priv_flag, ps_8021q->priv_flag, NUM_NOT_GOT); + if (pd_8021q->ingress.count == NUM_NOT_GOT) { + pd_8021q->ingress = ps_8021q->ingress; + } + if (pd_8021q->egress.count == NUM_NOT_GOT) { + pd_8021q->egress = ps_8021q->egress; + } + if (style == 0) { + CHARS_MERGE_NORMAL(pd_8021q->parent, ps_8021q->parent); + } else { + CHARS_MERGE_MOVE(pd_8021q->parent, ps_8021q->parent); + } + } +} + +static void br_prop_merge(BR_Prop *pdest, BR_Prop *psrc, int style) +{ + int i; + + if (style == 0) { + CHARS_MERGE_NORMAL(pdest->bridge_id, psrc->bridge_id); + /*merge it when dest have not been set */ + if (pdest->port_names == NULL) { + SAFE_PSTR_ARRAY_DUP(pdest->port_names, pdest->port_num, + psrc->port_names, psrc->port_num, i); + } + } else { + CHARS_MERGE_MOVE(pdest->bridge_id, psrc->bridge_id); + /*merge it when dest have not been set */ + if (pdest->port_names == NULL) { + pdest->port_names = psrc->port_names; + pdest->port_num = psrc->port_num; + psrc->port_names = NULL; + psrc->port_num = NUM_NOT_GOT; + } + } + NUM_MERGE(pdest->STP, psrc->STP, NUM_NOT_GOT); + NUM_MERGE(pdest->type, psrc->type, BR_TYPE_NOT_GOT); +} + +void eth_iface_merge(EthIface *dest, EthIface *src, int style) +{ + if (style == 0) { + CHARS_MERGE_NORMAL(dest->name, src->name); + CHARS_MERGE_NORMAL(dest->dep_ifname, src->dep_ifname); + CHARS_MERGE_NORMAL(dest->attach_bridge, src->attach_bridge); + CHARS_MERGE_NORMAL(dest->mac, src->mac); + CHARS_MERGE_NORMAL(dest->ipv4_prop.ip, src->ipv4_prop.ip); + CHARS_MERGE_NORMAL(dest->ipv4_prop.ip_mask, src->ipv4_prop.ip_mask); + } else { + CHARS_MERGE_MOVE(dest->name, src->name); + CHARS_MERGE_MOVE(dest->dep_ifname, src->dep_ifname); + CHARS_MERGE_MOVE(dest->attach_bridge, src->attach_bridge); + CHARS_MERGE_MOVE(dest->mac, src->mac); + CHARS_MERGE_MOVE(dest->ipv4_prop.ip, src->ipv4_prop.ip); + CHARS_MERGE_MOVE(dest->ipv4_prop.ip_mask, src->ipv4_prop.ip_mask); + } + NUM_MERGE(dest->eth_type, src->eth_type, ETH_TYPE_NOT_GOT); + NUM_MERGE(dest->run_prop.rx_bytes, src->run_prop.rx_bytes, + NUM_NOT_GOT); + NUM_MERGE(dest->run_prop.tx_bytes, src->run_prop.tx_bytes, + NUM_NOT_GOT); + NUM_MERGE(dest->run_prop.state, src->run_prop.state, ETH_STATE_NOT_GOT); + + if (src->pbr_prop != NULL) { + if (dest->pbr_prop == NULL) { + SAFE_MALLOC(dest->pbr_prop, sizeof(BR_Prop)); + br_prop_init(dest->pbr_prop); + } + br_prop_merge(dest->pbr_prop, src->pbr_prop, style); + } + + if (src->pvlan_prop != NULL) { + if (dest->pvlan_prop == NULL) { + SAFE_MALLOC(dest->pvlan_prop, sizeof(VLAN_Prop)); + vlan_prop_init(dest->pvlan_prop, src->pvlan_prop->vlan_type); + } + vlan_prop_merge(dest->pvlan_prop, src->pvlan_prop, style); + } + +} + +/* compare qos values */ +static int VLAN_Qos_8021q_compare_by_ref(const VLAN_Qos_8021q *pqos, + const VLAN_Qos_8021q *pref) +{ + int ret = 1; + int i, j; + if (pref->count == NUM_NOT_GOT) { + /* do not need to compare*/ + goto out; + } + if ((pref->count < 0) || (pref->count > 8)) { + ret = 0; + goto out; + } + if ((pqos->count < 0) || (pqos->count > 8)) { + ret = 0; + goto out; + } + + i = 0; + while (i < pref->count) { + j = 0; + while (j < pqos->count) { + if (pref->values[i].from == pqos->values[j].from) { + if (pref->values[i].to != pqos->values[j].to) { + ret = 0; + goto out; + } + break; + } + j++; + } + if (j == pqos->count) { + ret = 0; + goto out; + } + i++; + } + + out: + return ret; +} + +static int vlan_prop_filter_by_ref(const VLAN_Prop *pvlan_prop, void *pref) +{ + int compare_result = 1; + VLAN_Prop *ref = (VLAN_Prop *)pref; + char *p1, *p2; + const VLAN_Prop_8021q *pd_8021q; + VLAN_Prop_8021q *pref_8021q; + + NUM_COMPARE_BY_REF(pvlan_prop->vlan_type, ref->vlan_type, + compare_result, VLAN_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + if (ref->vlan_type == VLAN_TYPE_802_1_Q) { + pd_8021q = &(pvlan_prop->props.prop_8021q); + pref_8021q = &(ref->props.prop_8021q); + + NUM_COMPARE_BY_REF(pd_8021q->vlan_id, pref_8021q->vlan_id, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pd_8021q->reorder_hdr, pref_8021q->reorder_hdr, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pd_8021q->priv_flag, pref_8021q->priv_flag, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + compare_result = VLAN_Qos_8021q_compare_by_ref(&(pd_8021q->ingress), + &(pref_8021q->ingress)); + if (compare_result == 0) { + goto out; + } + + compare_result = VLAN_Qos_8021q_compare_by_ref(&(pd_8021q->egress), + &(pref_8021q->egress)); + if (compare_result == 0) { + goto out; + } + + p1 = pd_8021q->parent; + p2 = pref_8021q->parent; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + } + + out: + return compare_result; + +} + +static int br_prop_filter_by_ref(const BR_Prop *pbr_prop, void *pref) +{ + int compare_result = 1; + BR_Prop *ref = (BR_Prop *)pref; + char *p1, *p2; + + p1 = pbr_prop->bridge_id; + p2 = ref->bridge_id; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->STP, ref->STP, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->type, ref->type, + compare_result, BR_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->port_num, ref->port_num, + compare_result, NUM_NOT_GOT); + /* skip the comparation of ports it attached, user can define + a special filter for that */ + out: + return compare_result; +} + +int eth_iface_filter_by_ref(const EthIface *piface, void *pref) +{ + int compare_result = 1; + EthIface *ref = (EthIface *)pref; + char *p1, *p2; + + p1 = piface->name; + p2 = ref->name; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->dep_ifname; + p2 = ref->dep_ifname; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->attach_bridge; + p2 = ref->attach_bridge; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->mac; + p2 = ref->mac; + CHARS_COMPARE_CASE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(piface->eth_type, ref->eth_type, + compare_result, ETH_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + p1 = piface->ipv4_prop.ip; + p2 = ref->ipv4_prop.ip; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->ipv4_prop.ip_mask; + p2 = ref->ipv4_prop.ip_mask; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(piface->run_prop.state, ref->run_prop.state, + compare_result, ETH_STATE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + if (ref->pbr_prop != NULL) { + if (piface->pbr_prop != NULL) { + compare_result = br_prop_filter_by_ref(piface->pbr_prop, + ref->pbr_prop); + } else { + compare_result = 0; + } + if (compare_result == 0) { + goto out; + } + } + + if (ref->pvlan_prop != NULL) { + if (piface->pvlan_prop != NULL) { + compare_result = vlan_prop_filter_by_ref(piface->pvlan_prop, + ref->pvlan_prop); + + } else { + compare_result = 0; + } + if (compare_result == 0) { + goto out; + } + } + + out: + return compare_result; +} + +int eth_iface_filter_by_refname(const EthIface *piface, void *pref) +{ + int compare_result = 1; + EthIface *ref = (EthIface *)pref; + char *p1, *p2; + + p1 = piface->name; + p2 = ref->name; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + out: + return compare_result; +} + +int eth_iface_filter_vlans(const EthIface *piface, void *nouse) +{ + if (piface->name == NULL) { + return 0; + } + if (NULL == strstr(piface->name, ".")) { + return 0; + } else { + return 1; + } +} + +/* the judgement condition is weak, but I can't find a better way */ +int eth_iface_filter_peths(const EthIface *piface, void *nouse) +{ + if (piface->name == NULL) { + return 0; + } + if (NULL == strstr(piface->name, ".")) { + if (0 == strncmp(piface->name, "eth", 3)) { + return 1; + } else { + return 0; + } + } else { + return 0; + } +} diff --git a/libxkutil/host_network_basic.h b/libxkutil/host_network_basic.h new file mode 100644 index 0000000..d1dd128 --- /dev/null +++ b/libxkutil/host_network_basic.h @@ -0,0 +1,166 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia <xiawenc@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. + */ + +#ifndef NETWORK_BASIC_HOST_H +#define NETWORK_BASIC_HOST_H + +/* value defines */ +#define MAX_IFACE_NUM 4096 + +#define NUM_NOT_GOT -1 + +typedef enum { + ETH_STATE_NOT_GOT = NUM_NOT_GOT, + ETH_STATE_UNKNOWN = 0, + ETH_STATE_DOWN = 1, + ETH_STATE_UP = 2 +} EthState; + +typedef enum { + ETH_TYPE_NOT_GOT = NUM_NOT_GOT, + ETH_TYPE_UNKNOWN = 0, + ETH_TYPE_LOOPBACK = 1, + ETH_TYPE_PHYSICAL = 2, + ETH_TYPE_NORMAL = 4, + ETH_TYPE_BRIDGE = 8, + ETH_TYPE_VLAN = 16 +} EthType; + +typedef enum { + BR_TYPE_NOT_GOT = NUM_NOT_GOT, + BR_TYPE_UNKNOWN = 0, + BR_TYPE_SWITCH = 1, + BR_TYPE_NAT = 2 +} BrType; + +typedef enum { + VLAN_TYPE_NOT_GOT = NUM_NOT_GOT, + VLAN_TYPE_802_1_Q = 1, + VLAN_TYPE_802_1_QBG = 2, + VLAN_TYPE_802_1_QBH = 4 +} VLANType; + +/* structure defines */ +typedef struct IPV4_Prop { + char *ip; + char *ip_mask; +} IPV4_Prop; + +typedef struct BR_Prop { + char *bridge_id; + int STP; + BrType type; + char **port_names; + int port_num; +} BR_Prop; + +typedef struct Run_Prop { + long long rx_bytes; + long long tx_bytes; + EthState state; +} Run_Prop; + +typedef struct VLAN_Qos_8021q_elem { + int from; + int to; +} VLAN_Qos_8021q_elem; + +typedef struct VLAN_Qos_8021q { + VLAN_Qos_8021q_elem values[8]; + int count; +} VLAN_Qos_8021q; + +typedef struct VLAN_Prop_8021q { + int vlan_id; + int reorder_hdr; + int priv_flag; + VLAN_Qos_8021q ingress; + VLAN_Qos_8021q egress; + char *parent; +} VLAN_Prop_8021q; + +/* HP vlan standard, TBD */ +typedef struct VLAN_Prop_8021qbg { + int invalid; +} VLAN_Prop_8021qbg; + +/* Cisco and VMware vlan standard, TBD */ +typedef struct VLAN_Prop_8021qbh { + int invalid; +} VLAN_Prop_8021qbh; + +typedef struct VLAN_Prop { + int vlan_type; + union { + VLAN_Prop_8021q prop_8021q; + VLAN_Prop_8021qbg prop_8021qbg; + VLAN_Prop_8021qbh prop_8021qbh; + } props; +} VLAN_Prop; + +/* EthIface is logical devices include eth ports and bridges */ +typedef struct EthIface { + char *name; + char *dep_ifname; /* parent dev name */ + char *attach_bridge; /* bridge the iface is attached to */ + char *mac; + EthType eth_type; + Run_Prop run_prop; + IPV4_Prop ipv4_prop; + /* optional properties */ + BR_Prop *pbr_prop; + VLAN_Prop *pvlan_prop; +} EthIface; + +typedef struct EthIfacesList { + EthIface *pifaces[MAX_IFACE_NUM]; + int count; +} EthIfacesList; + +typedef int (*eth_iface_filter_func)(const EthIface *piface, void *opaque); + +/* uninit functions are only called when there is resource malloc */ +void vlan_prop_init(VLAN_Prop *pvlan_prop, int vlan_type); +void vlan_prop_uninit(VLAN_Prop *pvlan_prop); + +void br_prop_init(BR_Prop *pbr_prop); +void br_prop_uninit(BR_Prop *pbr_prop); + +void eth_iface_print(EthIface *piface); +void eth_iface_init(EthIface *piface); +void eth_iface_add_br_prop(EthIface *piface); +void eth_iface_add_vlan_prop(EthIface *piface, int vlan_type); +void eth_iface_uninit(EthIface *piface); +void eth_ifaces_clear(EthIface **ppifaces, int num); + +void eth_ifaceslist_init(EthIfacesList *plist); +void eth_ifaceslist_uninit(EthIfacesList *plist); +void eth_ifaceslist_print(EthIfacesList *plist); + +/* this function assume dest have been uninited if it was used before*/ +void eth_iface_dup(EthIface *dest, const EthIface *src); + +/* see if it is refered to the same device */ +int eth_iface_compare(const EthIface *p1, const EthIface *p2); + +/* merge the properties that dest do not have value set, if style is set to 1, + the char* properties was moved instead of copy, safely reduce the memory + fragments, but src is modified. */ +void eth_iface_merge(EthIface *dest, EthIface *src, int style); + +int eth_iface_filter_by_ref(const EthIface *piface, void *pref); +int eth_iface_filter_by_refname(const EthIface *piface, void *pref); +int eth_iface_filter_vlans(const EthIface *piface, void *nouse); +int eth_iface_filter_peths(const EthIface *piface, void *nouse); + + +#endif -- 1.7.6

On 12/07/2011 04:25 AM, Wayne Xia wrote:
this is the core abstraction and structure for ethernet devices.
Signed-off-by: Wayne Xia<xiawenc@linux.vnet.ibm.com> --- libxkutil/host_network_basic.c | 639 ++++++++++++++++++++++++++++++++++++++++ libxkutil/host_network_basic.h | 166 +++++++++++ 2 files changed, 805 insertions(+), 0 deletions(-) create mode 100644 libxkutil/host_network_basic.c create mode 100644 libxkutil/host_network_basic.h
diff --git a/libxkutil/host_network_basic.c b/libxkutil/host_network_basic.c new file mode 100644 index 0000000..3bcb32e --- /dev/null +++ b/libxkutil/host_network_basic.c @@ -0,0 +1,639 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia<xiawenc@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. + */ + +#include "host_network_basic.h" +#include "host_network_helper.h" + +#include<stdio.h> +#include<string.h> +#include<stdlib.h> + +static void vlan_prop_print(VLAN_Prop *pvlan_prop) +{ + VLAN_Prop_8021q *p_8021q; + char *ingress = NULL, *egress = NULL; + CMD_DEBUG(1, "--VLAN props: type %d.\n", + pvlan_prop->vlan_type); + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q =&(pvlan_prop->props.prop_8021q); + vlan_8021q_qos_num_to_str(&ingress,&(p_8021q->ingress)); + vlan_8021q_qos_num_to_str(&egress,&(p_8021q->egress)); + CMD_DEBUG(1, "----IEEE802.1.Q: id %d, reorder %d, priority %d, " + "ingress %s, egress %s, parent %s.\n", + p_8021q->vlan_id, p_8021q->reorder_hdr, p_8021q->priv_flag, + ingress, egress, p_8021q->parent); + } + SAFE_FREE(ingress); + SAFE_FREE(egress); +} + +static void br_prop_print(BR_Prop *pbr_prop) +{ + int i = 0; + CMD_DEBUG(1, "--Bridge props: id %s, stp %d, " + "bridge type %d, port_num %d.\n", + pbr_prop->bridge_id, pbr_prop->STP, + pbr_prop->type, pbr_prop->port_num); + if (pbr_prop->port_names != NULL) { + CMD_DEBUG(1, "----Ports attached: "); + while (i< pbr_prop->port_num) { + CMD_DEBUG(1, " %s,", *(pbr_prop->port_names+i)); + i++; + } + CMD_DEBUG(1, "\n"); + } +} + +void eth_iface_print(EthIface *piface) +{ + CMD_DEBUG(1, "Iface device: name %s.\n" + "--Main Props: parent %s, attach to %s, mac %s, ip %s, ip_mask %s," + " RX %lld, TX %lld, state %d, iface type %d.\n", + piface->name, piface->dep_ifname, piface->attach_bridge, + piface->mac, piface->ipv4_prop.ip, piface->ipv4_prop.ip_mask, + piface->run_prop.rx_bytes, piface->run_prop.tx_bytes, + piface->run_prop.state, piface->eth_type); + if (piface->pbr_prop != NULL) { + br_prop_print(piface->pbr_prop); + } + if (piface->pvlan_prop != NULL) { + vlan_prop_print(piface->pvlan_prop); + } + return; +} + +void eth_ifaceslist_print(EthIfacesList *plist) +{ + int i = 0; + CMD_DEBUG(1, "Have %d ifaces in the list:\n", plist->count); + while (i< plist->count) { + CMD_DEBUG(1, "%04d ", i); + eth_iface_print(plist->pifaces[i]); + i++; + } +} Are these debug functions always needed? Perhaps they should be wrapped in a #ifdef DEBUG to keep the code and runtime minimal. + +void vlan_prop_init(VLAN_Prop *pvlan_prop, int vlan_type) +{ + VLAN_Prop_8021q *p_8021q; + memset(pvlan_prop, 0, sizeof(VLAN_Prop)); + pvlan_prop->vlan_type = vlan_type; + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q =&(pvlan_prop->props.prop_8021q); + p_8021q->ingress.count = NUM_NOT_GOT; + p_8021q->egress.count = NUM_NOT_GOT; + p_8021q->vlan_id = NUM_NOT_GOT; + p_8021q->reorder_hdr = NUM_NOT_GOT; + p_8021q->priv_flag = NUM_NOT_GOT; + } +} + +void br_prop_init(BR_Prop *pbr_prop) +{ + memset(pbr_prop, 0, sizeof(BR_Prop)); + pbr_prop->STP = NUM_NOT_GOT; + pbr_prop->type = BR_TYPE_NOT_GOT; + pbr_prop->port_num = NUM_NOT_GOT; +} + +void eth_iface_init(EthIface *piface) I have not yet looked up the definition of EthIface but assume it's a struct. I'd prefer to see 'struct EthIface' so that's clear. In general, we should avoid using #defines and #typedefs to obscure the actual type of something. +{ + memset(piface, 0, sizeof(EthIface)); + piface->eth_type = ETH_TYPE_NOT_GOT; + piface->run_prop.rx_bytes = NUM_NOT_GOT; + piface->run_prop.tx_bytes = NUM_NOT_GOT; + piface->run_prop.state = ETH_STATE_NOT_GOT; + return; +} + +void eth_iface_add_br_prop(EthIface *piface) +{ + SAFE_MALLOC(piface->pbr_prop, sizeof(BR_Prop)); + br_prop_init(piface->pbr_prop); +} + +void eth_iface_add_vlan_prop(EthIface *piface, int vlan_type) +{ + SAFE_MALLOC(piface->pvlan_prop, sizeof(VLAN_Prop)); + vlan_prop_init(piface->pvlan_prop, vlan_type); +} + +void vlan_prop_uninit(VLAN_Prop *pvlan_prop) +{ + VLAN_Prop_8021q *p_8021q; + if (pvlan_prop == NULL) { + return; + } + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q =&(pvlan_prop->props.prop_8021q); + SAFE_FREE(p_8021q->parent); + } +} + +void br_prop_uninit(BR_Prop *pbr_prop) +{ + int i; + if (pbr_prop == NULL) { + return; + } + SAFE_FREE(pbr_prop->bridge_id); + i = 0; + if (pbr_prop->port_names != NULL) { + while (i< pbr_prop->port_num) { + SAFE_FREE(pbr_prop->port_names[i]); + i++; + } + SAFE_FREE(pbr_prop->port_names); + } +} + +void eth_iface_uninit(EthIface *piface) +{ + if (piface == NULL) { + return; + } + SAFE_FREE(piface->name); + SAFE_FREE(piface->dep_ifname); + SAFE_FREE(piface->attach_bridge); + SAFE_FREE(piface->mac); + SAFE_FREE(piface->ipv4_prop.ip); + SAFE_FREE(piface->ipv4_prop.ip_mask); + br_prop_uninit(piface->pbr_prop); + SAFE_FREE(piface->pbr_prop); + vlan_prop_uninit(piface->pvlan_prop); + SAFE_FREE(piface->pvlan_prop); + return; +} + +void eth_ifaces_clear(EthIface **ppifaces, int num) +{ + EthIface **t; + int i; + if (num<= 0) { + return; + } + t = ppifaces; + i = 0; + while (i< num) { + if (*t != NULL) { + eth_iface_uninit(*t); + SAFE_FREE(*t); + } + t++; + i++; + } + return; +} + +void eth_ifaceslist_init(EthIfacesList *plist) +{ + plist->count = 0; +} + +void eth_ifaceslist_uninit(EthIfacesList *plist) +{ + eth_ifaces_clear(plist->pifaces, plist->count); +} + +static void vlan_prop_dup(VLAN_Prop *dest, const VLAN_Prop *src) +{ + VLAN_Prop_8021q *pd_8021q; + const VLAN_Prop_8021q *ps_8021q; + dest->vlan_type = src->vlan_type; + if (dest->vlan_type == VLAN_TYPE_802_1_Q) { + pd_8021q =&(dest->props.prop_8021q); + ps_8021q =&(src->props.prop_8021q); + pd_8021q->vlan_id = ps_8021q->vlan_id; + pd_8021q->reorder_hdr = ps_8021q->reorder_hdr; + pd_8021q->priv_flag = ps_8021q->priv_flag; + pd_8021q->ingress = ps_8021q->ingress; + pd_8021q->egress = ps_8021q->egress; + pd_8021q->parent = SAFE_STRDUP(ps_8021q->parent); + } +} + +static void br_prop_dup(BR_Prop *dest, const BR_Prop *src) +{ + int i; + dest->bridge_id = SAFE_STRDUP(src->bridge_id); + dest->STP = src->STP; + dest->type = src->type; + SAFE_PSTR_ARRAY_DUP(dest->port_names, dest->port_num, + src->port_names, src->port_num, i); +} + +void eth_iface_dup(EthIface *dest, const EthIface *src) +{ + dest->name = SAFE_STRDUP(src->name); + dest->dep_ifname = SAFE_STRDUP(src->dep_ifname); + dest->attach_bridge = SAFE_STRDUP(src->attach_bridge); + dest->mac = SAFE_STRDUP(src->mac); + dest->eth_type = src->eth_type; + dest->ipv4_prop.ip = SAFE_STRDUP(src->ipv4_prop.ip); + dest->ipv4_prop.ip_mask = SAFE_STRDUP(src->ipv4_prop.ip_mask); + dest->run_prop.rx_bytes = src->run_prop.rx_bytes; + dest->run_prop.tx_bytes = src->run_prop.tx_bytes; + dest->run_prop.state = src->run_prop.state; + + if (src->pbr_prop != NULL) { + SAFE_MALLOC(dest->pbr_prop, sizeof(BR_Prop)); + /* doesn't need init it for that it would be copied at once */ + br_prop_dup(dest->pbr_prop, src->pbr_prop); + } else { + dest->pbr_prop = NULL; + } + + if (src->pvlan_prop != NULL) { + SAFE_MALLOC(dest->pvlan_prop, sizeof(VLAN_Prop)); + /* doesn't need init it for that it would be copied at once */ + vlan_prop_dup(dest->pvlan_prop, src->pvlan_prop); + } else { + dest->pvlan_prop = NULL; + } + +} + +int eth_iface_compare(const EthIface *p1, const EthIface *p2) +{ + int ret = 0; + if ((p1->name != NULL) || (p2->name != NULL)) { + if (0 == strcmp(p1->name, p2->name)) { + ret = 1; + } + } + return ret; +} + +static void vlan_prop_merge(VLAN_Prop *pdest, VLAN_Prop *psrc, int style) +{ + VLAN_Prop_8021q *pd_8021q, *ps_8021q; + + NUM_MERGE(pdest->vlan_type, psrc->vlan_type, VLAN_TYPE_NOT_GOT); + + if (psrc->vlan_type == VLAN_TYPE_802_1_Q) { + pd_8021q =&(pdest->props.prop_8021q); + ps_8021q =&(psrc->props.prop_8021q); + NUM_MERGE(pd_8021q->vlan_id, ps_8021q->vlan_id, NUM_NOT_GOT); + NUM_MERGE(pd_8021q->reorder_hdr, ps_8021q->reorder_hdr, NUM_NOT_GOT); + NUM_MERGE(pd_8021q->priv_flag, ps_8021q->priv_flag, NUM_NOT_GOT); + if (pd_8021q->ingress.count == NUM_NOT_GOT) { + pd_8021q->ingress = ps_8021q->ingress; + } + if (pd_8021q->egress.count == NUM_NOT_GOT) { + pd_8021q->egress = ps_8021q->egress; + } + if (style == 0) { + CHARS_MERGE_NORMAL(pd_8021q->parent, ps_8021q->parent); + } else { + CHARS_MERGE_MOVE(pd_8021q->parent, ps_8021q->parent); + } + } +} + +static void br_prop_merge(BR_Prop *pdest, BR_Prop *psrc, int style) +{ + int i; + + if (style == 0) { + CHARS_MERGE_NORMAL(pdest->bridge_id, psrc->bridge_id); + /*merge it when dest have not been set */ + if (pdest->port_names == NULL) { + SAFE_PSTR_ARRAY_DUP(pdest->port_names, pdest->port_num, + psrc->port_names, psrc->port_num, i); + } + } else { + CHARS_MERGE_MOVE(pdest->bridge_id, psrc->bridge_id); + /*merge it when dest have not been set */ + if (pdest->port_names == NULL) { + pdest->port_names = psrc->port_names; + pdest->port_num = psrc->port_num; + psrc->port_names = NULL; + psrc->port_num = NUM_NOT_GOT; + } + } + NUM_MERGE(pdest->STP, psrc->STP, NUM_NOT_GOT); + NUM_MERGE(pdest->type, psrc->type, BR_TYPE_NOT_GOT); +} + +void eth_iface_merge(EthIface *dest, EthIface *src, int style) +{ + if (style == 0) { + CHARS_MERGE_NORMAL(dest->name, src->name); These macro names are not obvious. Consider clarifying. + CHARS_MERGE_NORMAL(dest->dep_ifname, src->dep_ifname); + CHARS_MERGE_NORMAL(dest->attach_bridge, src->attach_bridge); + CHARS_MERGE_NORMAL(dest->mac, src->mac); + CHARS_MERGE_NORMAL(dest->ipv4_prop.ip, src->ipv4_prop.ip); + CHARS_MERGE_NORMAL(dest->ipv4_prop.ip_mask, src->ipv4_prop.ip_mask); + } else { + CHARS_MERGE_MOVE(dest->name, src->name); + CHARS_MERGE_MOVE(dest->dep_ifname, src->dep_ifname); + CHARS_MERGE_MOVE(dest->attach_bridge, src->attach_bridge); + CHARS_MERGE_MOVE(dest->mac, src->mac); + CHARS_MERGE_MOVE(dest->ipv4_prop.ip, src->ipv4_prop.ip); + CHARS_MERGE_MOVE(dest->ipv4_prop.ip_mask, src->ipv4_prop.ip_mask); + } + NUM_MERGE(dest->eth_type, src->eth_type, ETH_TYPE_NOT_GOT); + NUM_MERGE(dest->run_prop.rx_bytes, src->run_prop.rx_bytes, + NUM_NOT_GOT); + NUM_MERGE(dest->run_prop.tx_bytes, src->run_prop.tx_bytes, + NUM_NOT_GOT); + NUM_MERGE(dest->run_prop.state, src->run_prop.state, ETH_STATE_NOT_GOT); + + if (src->pbr_prop != NULL) { + if (dest->pbr_prop == NULL) { + SAFE_MALLOC(dest->pbr_prop, sizeof(BR_Prop)); + br_prop_init(dest->pbr_prop); + } + br_prop_merge(dest->pbr_prop, src->pbr_prop, style); + } + + if (src->pvlan_prop != NULL) { + if (dest->pvlan_prop == NULL) { + SAFE_MALLOC(dest->pvlan_prop, sizeof(VLAN_Prop)); + vlan_prop_init(dest->pvlan_prop, src->pvlan_prop->vlan_type); + } + vlan_prop_merge(dest->pvlan_prop, src->pvlan_prop, style); + } + +} + +/* compare qos values */ +static int VLAN_Qos_8021q_compare_by_ref(const VLAN_Qos_8021q *pqos, + const VLAN_Qos_8021q *pref) +{ + int ret = 1; + int i, j; + if (pref->count == NUM_NOT_GOT) { + /* do not need to compare*/ + goto out; + } + if ((pref->count< 0) || (pref->count> 8)) { + ret = 0; + goto out; + } + if ((pqos->count< 0) || (pqos->count> 8)) { + ret = 0; + goto out; + } + + i = 0; + while (i< pref->count) { + j = 0; + while (j< pqos->count) { + if (pref->values[i].from == pqos->values[j].from) { + if (pref->values[i].to != pqos->values[j].to) { + ret = 0; + goto out; + } + break; + } + j++; + } + if (j == pqos->count) { + ret = 0; + goto out; + } + i++; + } + + out: + return ret; +} + +static int vlan_prop_filter_by_ref(const VLAN_Prop *pvlan_prop, void *pref) +{ + int compare_result = 1; + VLAN_Prop *ref = (VLAN_Prop *)pref; + char *p1, *p2; + const VLAN_Prop_8021q *pd_8021q; + VLAN_Prop_8021q *pref_8021q; + + NUM_COMPARE_BY_REF(pvlan_prop->vlan_type, ref->vlan_type, + compare_result, VLAN_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + if (ref->vlan_type == VLAN_TYPE_802_1_Q) { + pd_8021q =&(pvlan_prop->props.prop_8021q); + pref_8021q =&(ref->props.prop_8021q); + + NUM_COMPARE_BY_REF(pd_8021q->vlan_id, pref_8021q->vlan_id, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pd_8021q->reorder_hdr, pref_8021q->reorder_hdr, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pd_8021q->priv_flag, pref_8021q->priv_flag, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + compare_result = VLAN_Qos_8021q_compare_by_ref(&(pd_8021q->ingress), +&(pref_8021q->ingress)); + if (compare_result == 0) { + goto out; + } + + compare_result = VLAN_Qos_8021q_compare_by_ref(&(pd_8021q->egress), +&(pref_8021q->egress)); + if (compare_result == 0) { + goto out; + } + + p1 = pd_8021q->parent; + p2 = pref_8021q->parent; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + } + + out: + return compare_result; + +} + +static int br_prop_filter_by_ref(const BR_Prop *pbr_prop, void *pref) +{ + int compare_result = 1; + BR_Prop *ref = (BR_Prop *)pref; + char *p1, *p2; + + p1 = pbr_prop->bridge_id; + p2 = ref->bridge_id; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->STP, ref->STP, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->type, ref->type, + compare_result, BR_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->port_num, ref->port_num, + compare_result, NUM_NOT_GOT); + /* skip the comparation of ports it attached, user can define + a special filter for that */ + out: + return compare_result; +} + +int eth_iface_filter_by_ref(const EthIface *piface, void *pref) +{ + int compare_result = 1; + EthIface *ref = (EthIface *)pref; + char *p1, *p2; + + p1 = piface->name; + p2 = ref->name; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->dep_ifname; + p2 = ref->dep_ifname; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->attach_bridge; + p2 = ref->attach_bridge; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->mac; + p2 = ref->mac; + CHARS_COMPARE_CASE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(piface->eth_type, ref->eth_type, + compare_result, ETH_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + p1 = piface->ipv4_prop.ip; + p2 = ref->ipv4_prop.ip; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->ipv4_prop.ip_mask; + p2 = ref->ipv4_prop.ip_mask; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(piface->run_prop.state, ref->run_prop.state, + compare_result, ETH_STATE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + if (ref->pbr_prop != NULL) { + if (piface->pbr_prop != NULL) { + compare_result = br_prop_filter_by_ref(piface->pbr_prop, + ref->pbr_prop); + } else { + compare_result = 0; + } + if (compare_result == 0) { + goto out; + } + } + + if (ref->pvlan_prop != NULL) { + if (piface->pvlan_prop != NULL) { + compare_result = vlan_prop_filter_by_ref(piface->pvlan_prop, + ref->pvlan_prop); + + } else { + compare_result = 0; + } + if (compare_result == 0) { + goto out; + } + } + + out: + return compare_result; +} + +int eth_iface_filter_by_refname(const EthIface *piface, void *pref) +{ + int compare_result = 1; + EthIface *ref = (EthIface *)pref; + char *p1, *p2; + + p1 = piface->name; + p2 = ref->name; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + out: + return compare_result; +} + +int eth_iface_filter_vlans(const EthIface *piface, void *nouse) +{ + if (piface->name == NULL) { + return 0; + } + if (NULL == strstr(piface->name, ".")) { + return 0; + } else { + return 1; + } +} + +/* the judgement condition is weak, but I can't find a better way */ +int eth_iface_filter_peths(const EthIface *piface, void *nouse) +{ + if (piface->name == NULL) { + return 0; + } + if (NULL == strstr(piface->name, ".")) { + if (0 == strncmp(piface->name, "eth", 3)) { + return 1; + } else { + return 0; + } + } else { + return 0; + } +} diff --git a/libxkutil/host_network_basic.h b/libxkutil/host_network_basic.h new file mode 100644 index 0000000..d1dd128 --- /dev/null +++ b/libxkutil/host_network_basic.h @@ -0,0 +1,166 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia<xiawenc@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. + */ + +#ifndef NETWORK_BASIC_HOST_H +#define NETWORK_BASIC_HOST_H + +/* value defines */ +#define MAX_IFACE_NUM 4096 + +#define NUM_NOT_GOT -1 Why not name 'NUM_NOT_GOT' to something like 'NONE' or 'NOT_DEFINED'? + +typedef enum { + ETH_STATE_NOT_GOT = NUM_NOT_GOT, + ETH_STATE_UNKNOWN = 0, + ETH_STATE_DOWN = 1, + ETH_STATE_UP = 2 +} EthState; + +typedef enum { + ETH_TYPE_NOT_GOT = NUM_NOT_GOT, + ETH_TYPE_UNKNOWN = 0, + ETH_TYPE_LOOPBACK = 1, + ETH_TYPE_PHYSICAL = 2, + ETH_TYPE_NORMAL = 4, + ETH_TYPE_BRIDGE = 8, + ETH_TYPE_VLAN = 16 +} EthType; + +typedef enum { + BR_TYPE_NOT_GOT = NUM_NOT_GOT, + BR_TYPE_UNKNOWN = 0, + BR_TYPE_SWITCH = 1, + BR_TYPE_NAT = 2 +} BrType; + +typedef enum { + VLAN_TYPE_NOT_GOT = NUM_NOT_GOT, + VLAN_TYPE_802_1_Q = 1, + VLAN_TYPE_802_1_QBG = 2, + VLAN_TYPE_802_1_QBH = 4 +} VLANType; + +/* structure defines */ +typedef struct IPV4_Prop { + char *ip; + char *ip_mask; +} IPV4_Prop; What about IPv6?
+ +typedef struct BR_Prop { + char *bridge_id; + int STP; + BrType type; + char **port_names; + int port_num; +} BR_Prop; + +typedef struct Run_Prop { + long long rx_bytes; + long long tx_bytes; + EthState state; +} Run_Prop; + +typedef struct VLAN_Qos_8021q_elem { + int from; + int to; +} VLAN_Qos_8021q_elem; + +typedef struct VLAN_Qos_8021q { + VLAN_Qos_8021q_elem values[8]; + int count; +} VLAN_Qos_8021q; + +typedef struct VLAN_Prop_8021q { + int vlan_id; + int reorder_hdr; + int priv_flag; + VLAN_Qos_8021q ingress; + VLAN_Qos_8021q egress; + char *parent; +} VLAN_Prop_8021q; + +/* HP vlan standard, TBD */ +typedef struct VLAN_Prop_8021qbg { + int invalid; +} VLAN_Prop_8021qbg; + +/* Cisco and VMware vlan standard, TBD */ +typedef struct VLAN_Prop_8021qbh { + int invalid; +} VLAN_Prop_8021qbh; + +typedef struct VLAN_Prop { + int vlan_type; + union { + VLAN_Prop_8021q prop_8021q; + VLAN_Prop_8021qbg prop_8021qbg; + VLAN_Prop_8021qbh prop_8021qbh; + } props; +} VLAN_Prop; + +/* EthIface is logical devices include eth ports and bridges */ +typedef struct EthIface { + char *name; + char *dep_ifname; /* parent dev name */ + char *attach_bridge; /* bridge the iface is attached to */ + char *mac; + EthType eth_type; + Run_Prop run_prop; + IPV4_Prop ipv4_prop; + /* optional properties */ + BR_Prop *pbr_prop; + VLAN_Prop *pvlan_prop; +} EthIface; + +typedef struct EthIfacesList { + EthIface *pifaces[MAX_IFACE_NUM]; + int count; +} EthIfacesList; + +typedef int (*eth_iface_filter_func)(const EthIface *piface, void *opaque); + +/* uninit functions are only called when there is resource malloc */ +void vlan_prop_init(VLAN_Prop *pvlan_prop, int vlan_type); +void vlan_prop_uninit(VLAN_Prop *pvlan_prop); + +void br_prop_init(BR_Prop *pbr_prop); +void br_prop_uninit(BR_Prop *pbr_prop); + +void eth_iface_print(EthIface *piface); +void eth_iface_init(EthIface *piface); +void eth_iface_add_br_prop(EthIface *piface); +void eth_iface_add_vlan_prop(EthIface *piface, int vlan_type); +void eth_iface_uninit(EthIface *piface); +void eth_ifaces_clear(EthIface **ppifaces, int num); + +void eth_ifaceslist_init(EthIfacesList *plist); +void eth_ifaceslist_uninit(EthIfacesList *plist); +void eth_ifaceslist_print(EthIfacesList *plist); + +/* this function assume dest have been uninited if it was used before*/ +void eth_iface_dup(EthIface *dest, const EthIface *src); + +/* see if it is refered to the same device */ +int eth_iface_compare(const EthIface *p1, const EthIface *p2); + +/* merge the properties that dest do not have value set, if style is set to 1, + the char* properties was moved instead of copy, safely reduce the memory + fragments, but src is modified. */ +void eth_iface_merge(EthIface *dest, EthIface *src, int style); + +int eth_iface_filter_by_ref(const EthIface *piface, void *pref); +int eth_iface_filter_by_refname(const EthIface *piface, void *pref); +int eth_iface_filter_vlans(const EthIface *piface, void *nouse); +int eth_iface_filter_peths(const EthIface *piface, void *nouse); + + +#endif
-- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent@linux.vnet.ibm.com

于 2011-12-24 4:10, Chip Vincent 写道:
On 12/07/2011 04:25 AM, Wayne Xia wrote:
this is the core abstraction and structure for ethernet devices.
Signed-off-by: Wayne Xia<xiawenc@linux.vnet.ibm.com> --- libxkutil/host_network_basic.c | 639 ++++++++++++++++++++++++++++++++++++++++ libxkutil/host_network_basic.h | 166 +++++++++++ 2 files changed, 805 insertions(+), 0 deletions(-) create mode 100644 libxkutil/host_network_basic.c create mode 100644 libxkutil/host_network_basic.h
diff --git a/libxkutil/host_network_basic.c b/libxkutil/host_network_basic.c new file mode 100644 index 0000000..3bcb32e --- /dev/null +++ b/libxkutil/host_network_basic.c @@ -0,0 +1,639 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia<xiawenc@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. + */ + +#include "host_network_basic.h" +#include "host_network_helper.h" + +#include<stdio.h> +#include<string.h> +#include<stdlib.h> + +static void vlan_prop_print(VLAN_Prop *pvlan_prop) +{ + VLAN_Prop_8021q *p_8021q; + char *ingress = NULL, *egress = NULL; + CMD_DEBUG(1, "--VLAN props: type %d.\n", + pvlan_prop->vlan_type); + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q =&(pvlan_prop->props.prop_8021q); + vlan_8021q_qos_num_to_str(&ingress,&(p_8021q->ingress)); + vlan_8021q_qos_num_to_str(&egress,&(p_8021q->egress)); + CMD_DEBUG(1, "----IEEE802.1.Q: id %d, reorder %d, priority %d, " + "ingress %s, egress %s, parent %s.\n", + p_8021q->vlan_id, p_8021q->reorder_hdr, p_8021q->priv_flag, + ingress, egress, p_8021q->parent); + } + SAFE_FREE(ingress); + SAFE_FREE(egress); +} + +static void br_prop_print(BR_Prop *pbr_prop) +{ + int i = 0; + CMD_DEBUG(1, "--Bridge props: id %s, stp %d, " + "bridge type %d, port_num %d.\n", + pbr_prop->bridge_id, pbr_prop->STP, + pbr_prop->type, pbr_prop->port_num); + if (pbr_prop->port_names != NULL) { + CMD_DEBUG(1, "----Ports attached: "); + while (i< pbr_prop->port_num) { + CMD_DEBUG(1, " %s,", *(pbr_prop->port_names+i)); + i++; + } + CMD_DEBUG(1, "\n"); + } +} + +void eth_iface_print(EthIface *piface) +{ + CMD_DEBUG(1, "Iface device: name %s.\n" + "--Main Props: parent %s, attach to %s, mac %s, ip %s, ip_mask %s," + " RX %lld, TX %lld, state %d, iface type %d.\n", + piface->name, piface->dep_ifname, piface->attach_bridge, + piface->mac, piface->ipv4_prop.ip, piface->ipv4_prop.ip_mask, + piface->run_prop.rx_bytes, piface->run_prop.tx_bytes, + piface->run_prop.state, piface->eth_type); + if (piface->pbr_prop != NULL) { + br_prop_print(piface->pbr_prop); + } + if (piface->pvlan_prop != NULL) { + vlan_prop_print(piface->pvlan_prop); + } + return; +} + +void eth_ifaceslist_print(EthIfacesList *plist) +{ + int i = 0; + CMD_DEBUG(1, "Have %d ifaces in the list:\n", plist->count); + while (i< plist->count) { + CMD_DEBUG(1, "%04d ", i); + eth_iface_print(plist->pifaces[i]); + i++; + } +} Are these debug functions always needed? Perhaps they should be wrapped in a #ifdef DEBUG to keep the code and runtime minimal.
there is a macro in network_helper.h: #define CMD_DEBUG_LEVEL 2 if the CMD_DEBUG_LEVEL < number in CMD_DEBUG(number, ""), the code would not be compiled.
+ +void vlan_prop_init(VLAN_Prop *pvlan_prop, int vlan_type) +{ + VLAN_Prop_8021q *p_8021q; + memset(pvlan_prop, 0, sizeof(VLAN_Prop)); + pvlan_prop->vlan_type = vlan_type; + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q =&(pvlan_prop->props.prop_8021q); + p_8021q->ingress.count = NUM_NOT_GOT; + p_8021q->egress.count = NUM_NOT_GOT; + p_8021q->vlan_id = NUM_NOT_GOT; + p_8021q->reorder_hdr = NUM_NOT_GOT; + p_8021q->priv_flag = NUM_NOT_GOT; + } +} + +void br_prop_init(BR_Prop *pbr_prop) +{ + memset(pbr_prop, 0, sizeof(BR_Prop)); + pbr_prop->STP = NUM_NOT_GOT; + pbr_prop->type = BR_TYPE_NOT_GOT; + pbr_prop->port_num = NUM_NOT_GOT; +} + +void eth_iface_init(EthIface *piface) I have not yet looked up the definition of EthIface but assume it's a struct. I'd prefer to see 'struct EthIface' so that's clear. In general, we should avoid using #defines and #typedefs to obscure the actual type of something.
OK, this style is brought from qemu...
+{ + memset(piface, 0, sizeof(EthIface)); + piface->eth_type = ETH_TYPE_NOT_GOT; + piface->run_prop.rx_bytes = NUM_NOT_GOT; + piface->run_prop.tx_bytes = NUM_NOT_GOT; + piface->run_prop.state = ETH_STATE_NOT_GOT; + return; +} + +void eth_iface_add_br_prop(EthIface *piface) +{ + SAFE_MALLOC(piface->pbr_prop, sizeof(BR_Prop)); + br_prop_init(piface->pbr_prop); +} + +void eth_iface_add_vlan_prop(EthIface *piface, int vlan_type) +{ + SAFE_MALLOC(piface->pvlan_prop, sizeof(VLAN_Prop)); + vlan_prop_init(piface->pvlan_prop, vlan_type); +} + +void vlan_prop_uninit(VLAN_Prop *pvlan_prop) +{ + VLAN_Prop_8021q *p_8021q; + if (pvlan_prop == NULL) { + return; + } + if (pvlan_prop->vlan_type == VLAN_TYPE_802_1_Q) { + p_8021q =&(pvlan_prop->props.prop_8021q); + SAFE_FREE(p_8021q->parent); + } +} + +void br_prop_uninit(BR_Prop *pbr_prop) +{ + int i; + if (pbr_prop == NULL) { + return; + } + SAFE_FREE(pbr_prop->bridge_id); + i = 0; + if (pbr_prop->port_names != NULL) { + while (i< pbr_prop->port_num) { + SAFE_FREE(pbr_prop->port_names[i]); + i++; + } + SAFE_FREE(pbr_prop->port_names); + } +} + +void eth_iface_uninit(EthIface *piface) +{ + if (piface == NULL) { + return; + } + SAFE_FREE(piface->name); + SAFE_FREE(piface->dep_ifname); + SAFE_FREE(piface->attach_bridge); + SAFE_FREE(piface->mac); + SAFE_FREE(piface->ipv4_prop.ip); + SAFE_FREE(piface->ipv4_prop.ip_mask); + br_prop_uninit(piface->pbr_prop); + SAFE_FREE(piface->pbr_prop); + vlan_prop_uninit(piface->pvlan_prop); + SAFE_FREE(piface->pvlan_prop); + return; +} + +void eth_ifaces_clear(EthIface **ppifaces, int num) +{ + EthIface **t; + int i; + if (num<= 0) { + return; + } + t = ppifaces; + i = 0; + while (i< num) { + if (*t != NULL) { + eth_iface_uninit(*t); + SAFE_FREE(*t); + } + t++; + i++; + } + return; +} + +void eth_ifaceslist_init(EthIfacesList *plist) +{ + plist->count = 0; +} + +void eth_ifaceslist_uninit(EthIfacesList *plist) +{ + eth_ifaces_clear(plist->pifaces, plist->count); +} + +static void vlan_prop_dup(VLAN_Prop *dest, const VLAN_Prop *src) +{ + VLAN_Prop_8021q *pd_8021q; + const VLAN_Prop_8021q *ps_8021q; + dest->vlan_type = src->vlan_type; + if (dest->vlan_type == VLAN_TYPE_802_1_Q) { + pd_8021q =&(dest->props.prop_8021q); + ps_8021q =&(src->props.prop_8021q); + pd_8021q->vlan_id = ps_8021q->vlan_id; + pd_8021q->reorder_hdr = ps_8021q->reorder_hdr; + pd_8021q->priv_flag = ps_8021q->priv_flag; + pd_8021q->ingress = ps_8021q->ingress; + pd_8021q->egress = ps_8021q->egress; + pd_8021q->parent = SAFE_STRDUP(ps_8021q->parent); + } +} + +static void br_prop_dup(BR_Prop *dest, const BR_Prop *src) +{ + int i; + dest->bridge_id = SAFE_STRDUP(src->bridge_id); + dest->STP = src->STP; + dest->type = src->type; + SAFE_PSTR_ARRAY_DUP(dest->port_names, dest->port_num, + src->port_names, src->port_num, i); +} + +void eth_iface_dup(EthIface *dest, const EthIface *src) +{ + dest->name = SAFE_STRDUP(src->name); + dest->dep_ifname = SAFE_STRDUP(src->dep_ifname); + dest->attach_bridge = SAFE_STRDUP(src->attach_bridge); + dest->mac = SAFE_STRDUP(src->mac); + dest->eth_type = src->eth_type; + dest->ipv4_prop.ip = SAFE_STRDUP(src->ipv4_prop.ip); + dest->ipv4_prop.ip_mask = SAFE_STRDUP(src->ipv4_prop.ip_mask); + dest->run_prop.rx_bytes = src->run_prop.rx_bytes; + dest->run_prop.tx_bytes = src->run_prop.tx_bytes; + dest->run_prop.state = src->run_prop.state; + + if (src->pbr_prop != NULL) { + SAFE_MALLOC(dest->pbr_prop, sizeof(BR_Prop)); + /* doesn't need init it for that it would be copied at once */ + br_prop_dup(dest->pbr_prop, src->pbr_prop); + } else { + dest->pbr_prop = NULL; + } + + if (src->pvlan_prop != NULL) { + SAFE_MALLOC(dest->pvlan_prop, sizeof(VLAN_Prop)); + /* doesn't need init it for that it would be copied at once */ + vlan_prop_dup(dest->pvlan_prop, src->pvlan_prop); + } else { + dest->pvlan_prop = NULL; + } + +} + +int eth_iface_compare(const EthIface *p1, const EthIface *p2) +{ + int ret = 0; + if ((p1->name != NULL) || (p2->name != NULL)) { + if (0 == strcmp(p1->name, p2->name)) { + ret = 1; + } + } + return ret; +} + +static void vlan_prop_merge(VLAN_Prop *pdest, VLAN_Prop *psrc, int style) +{ + VLAN_Prop_8021q *pd_8021q, *ps_8021q; + + NUM_MERGE(pdest->vlan_type, psrc->vlan_type, VLAN_TYPE_NOT_GOT); + + if (psrc->vlan_type == VLAN_TYPE_802_1_Q) { + pd_8021q =&(pdest->props.prop_8021q); + ps_8021q =&(psrc->props.prop_8021q); + NUM_MERGE(pd_8021q->vlan_id, ps_8021q->vlan_id, NUM_NOT_GOT); + NUM_MERGE(pd_8021q->reorder_hdr, ps_8021q->reorder_hdr, NUM_NOT_GOT); + NUM_MERGE(pd_8021q->priv_flag, ps_8021q->priv_flag, NUM_NOT_GOT); + if (pd_8021q->ingress.count == NUM_NOT_GOT) { + pd_8021q->ingress = ps_8021q->ingress; + } + if (pd_8021q->egress.count == NUM_NOT_GOT) { + pd_8021q->egress = ps_8021q->egress; + } + if (style == 0) { + CHARS_MERGE_NORMAL(pd_8021q->parent, ps_8021q->parent); + } else { + CHARS_MERGE_MOVE(pd_8021q->parent, ps_8021q->parent); + } + } +} + +static void br_prop_merge(BR_Prop *pdest, BR_Prop *psrc, int style) +{ + int i; + + if (style == 0) { + CHARS_MERGE_NORMAL(pdest->bridge_id, psrc->bridge_id); + /*merge it when dest have not been set */ + if (pdest->port_names == NULL) { + SAFE_PSTR_ARRAY_DUP(pdest->port_names, pdest->port_num, + psrc->port_names, psrc->port_num, i); + } + } else { + CHARS_MERGE_MOVE(pdest->bridge_id, psrc->bridge_id); + /*merge it when dest have not been set */ + if (pdest->port_names == NULL) { + pdest->port_names = psrc->port_names; + pdest->port_num = psrc->port_num; + psrc->port_names = NULL; + psrc->port_num = NUM_NOT_GOT; + } + } + NUM_MERGE(pdest->STP, psrc->STP, NUM_NOT_GOT); + NUM_MERGE(pdest->type, psrc->type, BR_TYPE_NOT_GOT); +} + +void eth_iface_merge(EthIface *dest, EthIface *src, int style) +{ + if (style == 0) { + CHARS_MERGE_NORMAL(dest->name, src->name); These macro names are not obvious. Consider clarifying.
OK.
+ CHARS_MERGE_NORMAL(dest->dep_ifname, src->dep_ifname); + CHARS_MERGE_NORMAL(dest->attach_bridge, src->attach_bridge); + CHARS_MERGE_NORMAL(dest->mac, src->mac); + CHARS_MERGE_NORMAL(dest->ipv4_prop.ip, src->ipv4_prop.ip); + CHARS_MERGE_NORMAL(dest->ipv4_prop.ip_mask, src->ipv4_prop.ip_mask); + } else { + CHARS_MERGE_MOVE(dest->name, src->name); + CHARS_MERGE_MOVE(dest->dep_ifname, src->dep_ifname); + CHARS_MERGE_MOVE(dest->attach_bridge, src->attach_bridge); + CHARS_MERGE_MOVE(dest->mac, src->mac); + CHARS_MERGE_MOVE(dest->ipv4_prop.ip, src->ipv4_prop.ip); + CHARS_MERGE_MOVE(dest->ipv4_prop.ip_mask, src->ipv4_prop.ip_mask); + } + NUM_MERGE(dest->eth_type, src->eth_type, ETH_TYPE_NOT_GOT); + NUM_MERGE(dest->run_prop.rx_bytes, src->run_prop.rx_bytes, + NUM_NOT_GOT); + NUM_MERGE(dest->run_prop.tx_bytes, src->run_prop.tx_bytes, + NUM_NOT_GOT); + NUM_MERGE(dest->run_prop.state, src->run_prop.state, ETH_STATE_NOT_GOT); + + if (src->pbr_prop != NULL) { + if (dest->pbr_prop == NULL) { + SAFE_MALLOC(dest->pbr_prop, sizeof(BR_Prop)); + br_prop_init(dest->pbr_prop); + } + br_prop_merge(dest->pbr_prop, src->pbr_prop, style); + } + + if (src->pvlan_prop != NULL) { + if (dest->pvlan_prop == NULL) { + SAFE_MALLOC(dest->pvlan_prop, sizeof(VLAN_Prop)); + vlan_prop_init(dest->pvlan_prop, src->pvlan_prop->vlan_type); + } + vlan_prop_merge(dest->pvlan_prop, src->pvlan_prop, style); + } + +} + +/* compare qos values */ +static int VLAN_Qos_8021q_compare_by_ref(const VLAN_Qos_8021q *pqos, + const VLAN_Qos_8021q *pref) +{ + int ret = 1; + int i, j; + if (pref->count == NUM_NOT_GOT) { + /* do not need to compare*/ + goto out; + } + if ((pref->count< 0) || (pref->count> 8)) { + ret = 0; + goto out; + } + if ((pqos->count< 0) || (pqos->count> 8)) { + ret = 0; + goto out; + } + + i = 0; + while (i< pref->count) { + j = 0; + while (j< pqos->count) { + if (pref->values[i].from == pqos->values[j].from) { + if (pref->values[i].to != pqos->values[j].to) { + ret = 0; + goto out; + } + break; + } + j++; + } + if (j == pqos->count) { + ret = 0; + goto out; + } + i++; + } + + out: + return ret; +} + +static int vlan_prop_filter_by_ref(const VLAN_Prop *pvlan_prop, void *pref) +{ + int compare_result = 1; + VLAN_Prop *ref = (VLAN_Prop *)pref; + char *p1, *p2; + const VLAN_Prop_8021q *pd_8021q; + VLAN_Prop_8021q *pref_8021q; + + NUM_COMPARE_BY_REF(pvlan_prop->vlan_type, ref->vlan_type, + compare_result, VLAN_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + if (ref->vlan_type == VLAN_TYPE_802_1_Q) { + pd_8021q =&(pvlan_prop->props.prop_8021q); + pref_8021q =&(ref->props.prop_8021q); + + NUM_COMPARE_BY_REF(pd_8021q->vlan_id, pref_8021q->vlan_id, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pd_8021q->reorder_hdr, pref_8021q->reorder_hdr, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pd_8021q->priv_flag, pref_8021q->priv_flag, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + compare_result = VLAN_Qos_8021q_compare_by_ref(&(pd_8021q->ingress), +&(pref_8021q->ingress)); + if (compare_result == 0) { + goto out; + } + + compare_result = VLAN_Qos_8021q_compare_by_ref(&(pd_8021q->egress), +&(pref_8021q->egress)); + if (compare_result == 0) { + goto out; + } + + p1 = pd_8021q->parent; + p2 = pref_8021q->parent; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + } + + out: + return compare_result; + +} + +static int br_prop_filter_by_ref(const BR_Prop *pbr_prop, void *pref) +{ + int compare_result = 1; + BR_Prop *ref = (BR_Prop *)pref; + char *p1, *p2; + + p1 = pbr_prop->bridge_id; + p2 = ref->bridge_id; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->STP, ref->STP, + compare_result, NUM_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->type, ref->type, + compare_result, BR_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(pbr_prop->port_num, ref->port_num, + compare_result, NUM_NOT_GOT); + /* skip the comparation of ports it attached, user can define + a special filter for that */ + out: + return compare_result; +} + +int eth_iface_filter_by_ref(const EthIface *piface, void *pref) +{ + int compare_result = 1; + EthIface *ref = (EthIface *)pref; + char *p1, *p2; + + p1 = piface->name; + p2 = ref->name; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->dep_ifname; + p2 = ref->dep_ifname; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->attach_bridge; + p2 = ref->attach_bridge; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->mac; + p2 = ref->mac; + CHARS_COMPARE_CASE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(piface->eth_type, ref->eth_type, + compare_result, ETH_TYPE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + p1 = piface->ipv4_prop.ip; + p2 = ref->ipv4_prop.ip; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + p1 = piface->ipv4_prop.ip_mask; + p2 = ref->ipv4_prop.ip_mask; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + NUM_COMPARE_BY_REF(piface->run_prop.state, ref->run_prop.state, + compare_result, ETH_STATE_NOT_GOT); + if (compare_result == 0) { + goto out; + } + + if (ref->pbr_prop != NULL) { + if (piface->pbr_prop != NULL) { + compare_result = br_prop_filter_by_ref(piface->pbr_prop, + ref->pbr_prop); + } else { + compare_result = 0; + } + if (compare_result == 0) { + goto out; + } + } + + if (ref->pvlan_prop != NULL) { + if (piface->pvlan_prop != NULL) { + compare_result = vlan_prop_filter_by_ref(piface->pvlan_prop, + ref->pvlan_prop); + + } else { + compare_result = 0; + } + if (compare_result == 0) { + goto out; + } + } + + out: + return compare_result; +} + +int eth_iface_filter_by_refname(const EthIface *piface, void *pref) +{ + int compare_result = 1; + EthIface *ref = (EthIface *)pref; + char *p1, *p2; + + p1 = piface->name; + p2 = ref->name; + CHARS_COMPARE_BY_REF(p1, p2, compare_result); + if (compare_result == 0) { + goto out; + } + + out: + return compare_result; +} + +int eth_iface_filter_vlans(const EthIface *piface, void *nouse) +{ + if (piface->name == NULL) { + return 0; + } + if (NULL == strstr(piface->name, ".")) { + return 0; + } else { + return 1; + } +} + +/* the judgement condition is weak, but I can't find a better way */ +int eth_iface_filter_peths(const EthIface *piface, void *nouse) +{ + if (piface->name == NULL) { + return 0; + } + if (NULL == strstr(piface->name, ".")) { + if (0 == strncmp(piface->name, "eth", 3)) { + return 1; + } else { + return 0; + } + } else { + return 0; + } +} diff --git a/libxkutil/host_network_basic.h b/libxkutil/host_network_basic.h new file mode 100644 index 0000000..d1dd128 --- /dev/null +++ b/libxkutil/host_network_basic.h @@ -0,0 +1,166 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia<xiawenc@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. + */ + +#ifndef NETWORK_BASIC_HOST_H +#define NETWORK_BASIC_HOST_H + +/* value defines */ +#define MAX_IFACE_NUM 4096 + +#define NUM_NOT_GOT -1 Why not name 'NUM_NOT_GOT' to something like 'NONE' or 'NOT_DEFINED'?
I thought NUM_NOT_GOT was more precise to show the situation that the information was not there. For eg, ifconfig would not show eth port active state, but ip addr would give that information.
+ +typedef enum { + ETH_STATE_NOT_GOT = NUM_NOT_GOT, + ETH_STATE_UNKNOWN = 0, + ETH_STATE_DOWN = 1, + ETH_STATE_UP = 2 +} EthState; + +typedef enum { + ETH_TYPE_NOT_GOT = NUM_NOT_GOT, + ETH_TYPE_UNKNOWN = 0, + ETH_TYPE_LOOPBACK = 1, + ETH_TYPE_PHYSICAL = 2, + ETH_TYPE_NORMAL = 4, + ETH_TYPE_BRIDGE = 8, + ETH_TYPE_VLAN = 16 +} EthType; + +typedef enum { + BR_TYPE_NOT_GOT = NUM_NOT_GOT, + BR_TYPE_UNKNOWN = 0, + BR_TYPE_SWITCH = 1, + BR_TYPE_NAT = 2 +} BrType; + +typedef enum { + VLAN_TYPE_NOT_GOT = NUM_NOT_GOT, + VLAN_TYPE_802_1_Q = 1, + VLAN_TYPE_802_1_QBG = 2, + VLAN_TYPE_802_1_QBH = 4 +} VLANType; + +/* structure defines */ +typedef struct IPV4_Prop { + char *ip; + char *ip_mask; +} IPV4_Prop; What about IPv6?
ignored.... it seems now configuration of vlan did not need IP information, planning adding that in the future.
+ +typedef struct BR_Prop { + char *bridge_id; + int STP; + BrType type; + char **port_names; + int port_num; +} BR_Prop; + +typedef struct Run_Prop { + long long rx_bytes; + long long tx_bytes; + EthState state; +} Run_Prop; + +typedef struct VLAN_Qos_8021q_elem { + int from; + int to; +} VLAN_Qos_8021q_elem; + +typedef struct VLAN_Qos_8021q { + VLAN_Qos_8021q_elem values[8]; + int count; +} VLAN_Qos_8021q; + +typedef struct VLAN_Prop_8021q { + int vlan_id; + int reorder_hdr; + int priv_flag; + VLAN_Qos_8021q ingress; + VLAN_Qos_8021q egress; + char *parent; +} VLAN_Prop_8021q; + +/* HP vlan standard, TBD */ +typedef struct VLAN_Prop_8021qbg { + int invalid; +} VLAN_Prop_8021qbg; + +/* Cisco and VMware vlan standard, TBD */ +typedef struct VLAN_Prop_8021qbh { + int invalid; +} VLAN_Prop_8021qbh; + +typedef struct VLAN_Prop { + int vlan_type; + union { + VLAN_Prop_8021q prop_8021q; + VLAN_Prop_8021qbg prop_8021qbg; + VLAN_Prop_8021qbh prop_8021qbh; + } props; +} VLAN_Prop; + +/* EthIface is logical devices include eth ports and bridges */ +typedef struct EthIface { + char *name; + char *dep_ifname; /* parent dev name */ + char *attach_bridge; /* bridge the iface is attached to */ + char *mac; + EthType eth_type; + Run_Prop run_prop; + IPV4_Prop ipv4_prop; + /* optional properties */ + BR_Prop *pbr_prop; + VLAN_Prop *pvlan_prop; +} EthIface; + +typedef struct EthIfacesList { + EthIface *pifaces[MAX_IFACE_NUM]; + int count; +} EthIfacesList; + +typedef int (*eth_iface_filter_func)(const EthIface *piface, void *opaque); + +/* uninit functions are only called when there is resource malloc */ +void vlan_prop_init(VLAN_Prop *pvlan_prop, int vlan_type); +void vlan_prop_uninit(VLAN_Prop *pvlan_prop); + +void br_prop_init(BR_Prop *pbr_prop); +void br_prop_uninit(BR_Prop *pbr_prop); + +void eth_iface_print(EthIface *piface); +void eth_iface_init(EthIface *piface); +void eth_iface_add_br_prop(EthIface *piface); +void eth_iface_add_vlan_prop(EthIface *piface, int vlan_type); +void eth_iface_uninit(EthIface *piface); +void eth_ifaces_clear(EthIface **ppifaces, int num); + +void eth_ifaceslist_init(EthIfacesList *plist); +void eth_ifaceslist_uninit(EthIfacesList *plist); +void eth_ifaceslist_print(EthIfacesList *plist); + +/* this function assume dest have been uninited if it was used before*/ +void eth_iface_dup(EthIface *dest, const EthIface *src); + +/* see if it is refered to the same device */ +int eth_iface_compare(const EthIface *p1, const EthIface *p2); + +/* merge the properties that dest do not have value set, if style is set to 1, + the char* properties was moved instead of copy, safely reduce the memory + fragments, but src is modified. */ +void eth_iface_merge(EthIface *dest, EthIface *src, int style); + +int eth_iface_filter_by_ref(const EthIface *piface, void *pref); +int eth_iface_filter_by_refname(const EthIface *piface, void *pref); +int eth_iface_filter_vlans(const EthIface *piface, void *nouse); +int eth_iface_filter_peths(const EthIface *piface, void *nouse); + + +#endif
-- Best Regards Wayne Xia mail:xiawenc@linux.vnet.ibm.com tel:86-010-82450803

this is the helper function for the lib. Signed-off-by: Wayne Xia <xiawenc@linux.vnet.ibm.com> --- libxkutil/host_network_error.h | 28 ++ libxkutil/host_network_helper.c | 659 +++++++++++++++++++++++++++++++++++++++ libxkutil/host_network_helper.h | 192 ++++++++++++ 3 files changed, 879 insertions(+), 0 deletions(-) create mode 100644 libxkutil/host_network_error.h create mode 100644 libxkutil/host_network_helper.c create mode 100644 libxkutil/host_network_helper.h diff --git a/libxkutil/host_network_error.h b/libxkutil/host_network_error.h new file mode 100644 index 0000000..d809033 --- /dev/null +++ b/libxkutil/host_network_error.h @@ -0,0 +1,28 @@ +#ifndef HOST_NETWORK_ERROR_H +#define HOST_NETWORK_ERROR_H + +#define ERR_REQUEST_NOT_SUPPORT -1 + +#define ERR_COMMAND_NOT_SET -11 +#define ERR_COMMAND_PIPE_ERR -12 +#define ERR_COMMAND_NOT_SUPPORT -13 +#define ERR_COMMAND_NO_PERMISSION -14 +#define ERR_COMMAND_NO_READY -15 +#define ERR_COMMAND_PARAMETER_WRONG -16 +#define ERR_COMMAND_EXECUTION -17 + +#define ERR_DEVICE_EXCEED_MAXNUM -100 +#define ERR_DEVICE_EXIST -101 +#define ERR_DEVICE_NOT_EXIST -102 +#define ERR_DEVICE_ALREADY_DONE -103 +#define ERR_DEVICE_CONNECT_OTHER -104 + +#define ERR_FILE_OP_FAIL -125 +#define ERR_FILE_EMPTY -126 +#define ERR_FILE_TOO_LARGE -127 +#define ERR_FILE_CONT_TOO_LARGE -128 +#define ERR_FILE_LOCK_FAIL -129 + +#define ERR_PERSIST_NOT_REDHAT -200 + +#endif diff --git a/libxkutil/host_network_helper.c b/libxkutil/host_network_helper.c new file mode 100644 index 0000000..dc9f775 --- /dev/null +++ b/libxkutil/host_network_helper.c @@ -0,0 +1,659 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia <xiawenc@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. + */ + + + +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> + +#include "host_network_helper.h" +#include "host_network_error.h" + +#define CONFIGURE_FILE_MAX_SIZE 2048 + +#define PIPE_CMD_SUFFIX " 2>&1" + +static int g_linux_version = LINUX_UNKNOWN; + +static int compare_qos_8021q(const void *p1, const void *p2) +{ + const VLAN_Qos_8021q_elem *qos1 = (VLAN_Qos_8021q_elem *)p1; + const VLAN_Qos_8021q_elem *qos2 = (VLAN_Qos_8021q_elem *)p2; + int ret = 0; + if ((qos1->from) > (qos2->from)) { + ret = 1; + } + return ret; +} + +/* it need to be checked see whether these are the conditions */ +int vlan_8021q_qos_check_valid(VLAN_Qos_8021q *pqos) +{ + int ret = 1; + int i = 0; + int last_num = -1; + if ((pqos->count < 0) || (pqos->count > 8)) { + ret = 0; + goto out; + } else if (pqos->count == 0) { + goto out; + } + qsort((void *)pqos->values, pqos->count, sizeof(VLAN_Qos_8021q_elem), + compare_qos_8021q); + + while (i < pqos->count) { + if (pqos->values[i].from == last_num) { + CU_DEBUG("error: vlan 802.1.q qos setting have same <from> values: " + "last is %d, new is %d", last_num, pqos->values[i].from); + ret = 0; + goto out; + } + last_num = pqos->values[i].from; + if ((pqos->values[i].from < 0) || (pqos->values[i].from >= 8)) { + CU_DEBUG("error: vlan 802.1.q qos setting have outbound value: " + "from is %d.", pqos->values[i].from); + ret = 0; + goto out; + } + if ((pqos->values[i].to < 0) || (pqos->values[i].to >= 8)) { + CU_DEBUG("error: vlan 802.1.q qos setting have outbound value: " + "to is %d.", pqos->values[i].to); + ret = 0; + goto out; + } + i++; + } + + out: + return ret; +} + +int vlan_8021q_qos_str_to_num(VLAN_Qos_8021q *pqos, const char* str) +{ + int ret = 1; + char *str_line = NULL; + char *temp; + char *saveptr = NULL; + char *invalptr1, *invalptr2; + int qos_num1, qos_num2; + VLAN_Qos_8021q qos; + + if (str == NULL) { + ret = 0; + goto out; + } + if (str[0] == '\0') { + ret = 1; + pqos->count = 0; + CU_DEBUG("empty vlan 802.1.q qos string found."); + goto out; + } + str_line = SAFE_STRDUP(str); + qos.count = 0; + + temp = strtok_r(str_line, " ", &saveptr); + while (temp != NULL) { + qos_num1 = strtol(temp, &invalptr1, 10); + if (temp == invalptr1) { + ret = 0; + goto out; + } + if (*invalptr1 != ':') { + ret = 0; + goto out; + } + invalptr1++; + qos_num2 = strtol(invalptr1, &invalptr2, 10); + if (invalptr1 == invalptr2) { + ret = 0; + goto out; + } + if (*invalptr2 != '\0') { + ret = 0; + goto out; + } + if (qos.count >= 8) { + ret = 0; + CU_DEBUG("too many settings found in vlan 802.1.q qos string [%s]", + str); + goto out; + } + qos.values[qos.count].from = qos_num1; + qos.values[qos.count].to = qos_num2; + qos.count++; + temp = strtok_r(NULL, " ", &saveptr); + } + ret = vlan_8021q_qos_check_valid(&qos); + if (ret == 1) { + *pqos = qos; + } + + out: + if (ret != 1) { + CU_DEBUG("vlan 802.1.q qos string [%s] is invalid.", str); + } + SAFE_FREE(str_line); + return ret; +} + +int vlan_8021q_qos_num_to_str(char **str, const VLAN_Qos_8021q *pqos) +{ + char temp[16]; + int i; + VLAN_Qos_8021q qos = *pqos; + int ret = vlan_8021q_qos_check_valid(&qos); + if (ret != 1) { + goto out; + } + SAFE_MALLOC(*str, 64); + *str[0] = '\0'; + if (qos.count == 0) { + goto out; + } + i = 0; + snprintf(temp, sizeof(temp), "%d:%d", + qos.values[i].from, qos.values[i].to); + strcat(*str, temp); + i++; + while (i < qos.count) { + strcat(*str, " "); + snprintf(temp, sizeof(temp), "%d:%d", + qos.values[i].from, qos.values[i].to); + strcat(*str, temp); + i++; + } + + out: + return ret; +} + +int netmask_easy_to_inaddr(struct in_addr *paddr, const char* pmask) +{ + long mask_one_num = -1; + unsigned char *p; + int bitnum; + + mask_one_num = strtol(pmask, NULL, 10); + if ((mask_one_num < 0) || (mask_one_num > 32)) { + return 0; + } + + /* use network byte order */ + p = (unsigned char *)&paddr->s_addr; + memset(p, 0, 4); + while (mask_one_num > 8) { + *(p++) = 255; + mask_one_num -= 8; + } + bitnum = 7; + while (mask_one_num > 0) { + *p = *p + (1<<bitnum); + mask_one_num--; + bitnum--; + } + return 1; +} + +char *strtok_onetime(const char *str, const char *delim) +{ + char *t = strstr(str, delim); + char *ret_char; + int len; + if (t == NULL) { + return NULL; + } + len = t - str; + if (len <= 0) { + return NULL; + } + SAFE_MALLOC(ret_char, len+1); + strncpy(ret_char, str, len); + ret_char[len] = '\0'; + + return ret_char; +} + +char *combine_file_name(const char *prefix, const char *name) +{ + char *ret = NULL; + int size; + size = strlen(prefix) + strlen(name) + 1; + SAFE_CALLOC(ret, size, sizeof(char)); + snprintf(ret, size, "%s%s", prefix, name); + return ret; +} + +/* return the whole content length that need update. The data length keep + unchanged in the head part is returned in *unchanged_len which could be + used to avoid write whole data later. + requriement: cont must contain end character, prefix must be not NULL */ +static int replace_prop_str(char *cont, const int maxsize, const char *prefix, + const char *prop, int *unchanged_len) +{ + int target_len, origin_len; + int cont_len; + int valid_len = 0; + int prefix_len, prop_len = 0; + char *endchar1 = "\n"; + char *pprop_start, *pprop_end; + int head_len; + + cont_len = strlen(cont); + head_len = cont_len; + prefix_len = strlen(prefix); + if ((prop == NULL) || (*prop == '\0')) { + /* want the property removed */ + target_len = 0; + } else { + /* want the property changed */ + prop_len = strlen(prop); + target_len = prefix_len + prop_len; + } + + pprop_start = strstr(cont, prefix); + if (pprop_start == NULL) { + /* the content do not exist in original contents */ + if (target_len > 0) { + /* add the property */ + if ((cont_len + target_len) >= maxsize) { + CU_DEBUG("buffer is too small for the operation."); + valid_len = -1; + goto out; + } + strcat(cont, prefix); + strcat(cont, prop); + valid_len = cont_len + target_len; + } else { + /* remove the property, but it do not exist, so skip */ + } + } else { + /* the content exist in original contents */ + /* locate the end of the property */ + pprop_end = strstr(pprop_start, endchar1); + if (pprop_end == NULL) { + /* last line */ + origin_len = strlen(pprop_start); + pprop_end = cont+cont_len; + } else { + origin_len = pprop_end - pprop_start; + } + if (target_len > 0) { + /* change the property */ + /* check the bound */ + if ((cont_len + target_len - origin_len) >= maxsize) { + CU_DEBUG("buffer is too small for the operation."); + valid_len = -1; + goto out; + } + /* move contents in the tail */ + memmove(pprop_end+target_len-origin_len, pprop_end, + cont+cont_len+1-pprop_end); + /* copy the content of the new string */ + memcpy(pprop_start+prefix_len, prop, prop_len); + head_len = pprop_start - cont + prefix_len; + } else { + /* remove the property */ + /* move contents in the tail to replace original string*/ + memmove(pprop_end+target_len-origin_len, pprop_end, + cont+cont_len+1-pprop_end); + head_len = pprop_start - cont; + } + valid_len = cont_len + target_len - origin_len; + } + + out: + if (unchanged_len != NULL) { + *unchanged_len = head_len; + } + return valid_len; +} + +int configure_file_replace_attr(const char *path, const char *prefix, + const char *prop) +{ + int fd = -1; + int fop_ret; + struct stat s; + struct flock lock; + int lock_state = -1; + char *cont = NULL; + char *pbuff; + int write_len; + int cont_len_update; + int cont_len_unchanged; + int ret = 0; + + if ((prefix == NULL) || (*prefix == '\0')) { + CU_DEBUG("no prefix for property set, could not replace the content."); + goto out; + } + + fd = open(path, O_RDWR, 0644); + if (fd < 0) { + CU_DEBUG("Unable to open [%s], it does not exist.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + lock_state = fcntl(fd, F_SETLK, &lock); + if (lock_state < 0) { + CU_DEBUG("Failed to lock file [%s], it may be locked by other.", path); + ret = ERR_FILE_LOCK_FAIL; + goto out; + } + + fstat(fd, &s); + if (s.st_size == 0) { + CU_DEBUG("file [%s] is empty, will not replace attr for it.", path); + ret = ERR_FILE_EMPTY; + goto out; + } else if (s.st_size >= CONFIGURE_FILE_MAX_SIZE) { + CU_DEBUG("file [%s] is too large, " + "it have %lld bytes, will not read it.", + path, (long long)s.st_size); + ret = ERR_FILE_TOO_LARGE; + goto out; + } + + SAFE_MALLOC(cont, CONFIGURE_FILE_MAX_SIZE); + lseek(fd, 0, SEEK_SET); + fop_ret = read(fd, cont, s.st_size); + cont[s.st_size] = '\0'; + cont_len_update = replace_prop_str(cont, CONFIGURE_FILE_MAX_SIZE, + prefix, prop, &cont_len_unchanged); + if (cont_len_update < 0) { + CU_DEBUG("file [%s] is too big to expand it with [%s%s].", + path, prefix, prop); + ret = ERR_FILE_TOO_LARGE; + goto out; + } else if (cont_len_update == 0) { + CU_DEBUG("the contents was not changed, do not need update it"); + ret = 1; + goto out; + } else { + if (ftruncate(fd, cont_len_unchanged) != 0) { + CU_DEBUG("file [%s] Unable to truncate it", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + write_len = cont_len_update-cont_len_unchanged; + if (write_len > 0) { + lseek(fd, cont_len_unchanged, SEEK_SET); + CU_DEBUG("writing file [%s] for %d bytes with offset %d," + " cont is :\n%s\n", + path, write_len, cont_len_unchanged, cont); + pbuff = cont+cont_len_unchanged; + fop_ret = write(fd, pbuff, write_len); + } + } + ret = 1; + + out: + if (fd >= 0) { + if (lock_state >= 0) { + lock.l_type = F_UNLCK; + fcntl(fd, F_SETLK, &lock); + } + close(fd); + } + SAFE_FREE(cont); + return ret; +} + +int configure_file_update(const char *path, const char *cont) +{ + int fd = -1; + int fop_ret; + struct flock lock; + int lock_state = -1; + int write_len; + int ret = 0; + + fd = open(path, O_RDWR|O_CREAT, 0644); + if (fd < 0) { + CU_DEBUG("Unable to open [%s], it does not exist.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + lock_state = fcntl(fd, F_SETLK, &lock); + if (lock_state < 0) { + CU_DEBUG("Failed to lock file [%s], it may be locked by other.", path); + ret = ERR_FILE_LOCK_FAIL; + goto out; + } + + if (ftruncate(fd, 0) != 0) { + CU_DEBUG("file [%s] Unable to truncate it", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + write_len = strlen(cont); + if (write_len > 0) { + lseek(fd, 0, SEEK_SET); + CU_DEBUG("writing file [%s] for %d bytes with offset 0," + " cont is :\n%s\n", + path, write_len, cont); + fop_ret = write(fd, cont, write_len); + } + ret = 1; + + out: + if (fd >= 0) { + if (lock_state >= 0) { + lock.l_type = F_UNLCK; + fcntl(fd, F_SETLK, &lock); + } + close(fd); + } + return ret; +} + +int configure_file_remove(const char *path) +{ + int fd_ret; + int ret = 0; + if (access(path, F_OK) == 0) { + CU_DEBUG("Deleting %s.", path); + fd_ret = remove(path); + if (fd_ret != 0) { + CU_DEBUG("failed to remove %s.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + } + + ret = 1; + out: + return ret; +} + +FILE *pipe_excute_command_type_read(char *cmd, const int buf_size, + const char *type, int *errno) +{ + FILE *stream = NULL; + char *suffix = PIPE_CMD_SUFFIX; + if ((strlen(cmd) + strlen(suffix)) >= buf_size) { + CU_DEBUG("cmd [%s] is too long to append the suffix", cmd); + *errno = ERR_COMMAND_NO_READY; + goto out; + } + strcat(cmd, suffix); + CU_DEBUG("excuting readonly cmd [%s].", cmd); + stream = popen(cmd, type); + if (stream == NULL) { + CU_DEBUG("Failed to open pipe to run command"); + *errno = ERR_COMMAND_PIPE_ERR; + } + +out: + return stream; +} + +FILE *pipe_excute_command_type_write(char *cmd, const int buf_size, + const char *type, int *errno) +{ + FILE *stream = NULL; + char *suffix = PIPE_CMD_SUFFIX; + if ((strlen(cmd) + strlen(suffix)) >= buf_size) { + CU_DEBUG("cmd [%s] is too long to append the suffix", cmd); + *errno = ERR_COMMAND_NO_READY; + goto out; + } + strcat(cmd, suffix); + CU_DEBUG("excuting system modification cmd [%s].", cmd); + stream = popen(cmd, type); + if (stream == NULL) { + CU_DEBUG("Failed to open pipe to run command"); + *errno = ERR_COMMAND_PIPE_ERR; + } + usleep(10000); + +out: + return stream; +} + +int get_host_linux_version(void) +{ + FILE *stream = NULL; + char cmd[64]; + char buff[256]; + int linenum; + int errno; + + if (g_linux_version != LINUX_UNKNOWN) { + goto out; + } + + cmd[0] = '\0'; + strcat(cmd, "lsb_release -a"); + stream = pipe_excute_command_type_read(cmd, sizeof(cmd), "r", &errno); + if (stream == NULL) { + goto out; + } + + linenum = -1; + g_linux_version = LINUX_OTHER; + while (fgets(buff, 256, stream) != NULL) { + linenum++; + if (linenum == 0) { + if (NULL == strstr(buff, "LSB")) { + CU_DEBUG("ERR: unable to get linux distribution version."); + g_linux_version = LINUX_FAIL_TO_GET; + } + } + if ((NULL != strstr(buff, "Red Hat")) || + (NULL != strstr(buff, "RedHat"))) { + g_linux_version = LINUX_REDHAT; + break; + } + } + + out: + if (stream != NULL) { + pclose(stream); + } + return g_linux_version; +} + +char *translate_error_no(int errno) +{ + char *ret = NULL; + switch (errno) { + case ERR_REQUEST_NOT_SUPPORT: + ret = "request is not supported now"; + break; + + case ERR_COMMAND_NOT_SET: + ret = "command is not set."; + break; + case ERR_COMMAND_PIPE_ERR: + ret = "failed in creating pipe to execute the command."; + break; + case ERR_COMMAND_NOT_SUPPORT: + ret = "command is not found, check u environment."; + break; + case ERR_COMMAND_NO_PERMISSION: + ret = "not enough authority to execute the command."; + break; + case ERR_COMMAND_NO_READY: + ret = "failed to build up the command line, check your input, " + "maybe it is too long."; + break; + case ERR_COMMAND_PARAMETER_WRONG: + ret = "got invalid paramenter, check your input."; + break; + case ERR_COMMAND_EXECUTION: + ret = "error happened in the excution of command."; + break; + + case ERR_DEVICE_EXCEED_MAXNUM: + ret = "too many devices found or set, check the environment."; + break; + case ERR_DEVICE_EXIST: + ret = "device already exist, can not execute the command."; + break; + case ERR_DEVICE_NOT_EXIST: + ret = "device do not exist, can not execute the command."; + break; + case ERR_DEVICE_ALREADY_DONE: + ret = "the operation you want have been done before, " + "will not do it again."; + break; + case ERR_DEVICE_CONNECT_OTHER: + ret = "the device you want to connect have been connect to another" + " device, can't change it directly."; + break; + + case ERR_FILE_OP_FAIL: + ret = "failed in accessing the file."; + break; + case ERR_FILE_EMPTY: + ret = "the file it want is empty."; + break; + case ERR_FILE_TOO_LARGE: + ret = "the file it want is too large."; + break; + case ERR_FILE_CONT_TOO_LARGE: + ret = "the content it want to combine to file is too large."; + break; + case ERR_FILE_LOCK_FAIL: + ret = "failed in locking the file, " + "check if other process is using it."; + break; + + case ERR_PERSIST_NOT_REDHAT: + ret = "host is not a RedHat distribution, can't persist the " + "configuration, it would not take effect after host is " + "rebooted. Other version would be supported in the future. " + "If you are sure host is RedHat, make sure command " + "<lsb_release -a> could work."; + break; + + default: + ret = "internal error."; + break; + } + return ret; +} diff --git a/libxkutil/host_network_helper.h b/libxkutil/host_network_helper.h new file mode 100644 index 0000000..a232221 --- /dev/null +++ b/libxkutil/host_network_helper.h @@ -0,0 +1,192 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia <xiawenc@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. + */ + + +#ifndef HOST_NETWORK_HELPER_H +#define HOST_NETWORK_HELPER_H + +#include <stdio.h> +#include <stdlib.h> +#include <arpa/inet.h> + +#include "host_network_basic.h" + +#ifdef TESTLIB +#include "TestDefines.h" +#else +#include <libcmpiutil/libcmpiutil.h> +#endif + +#define LINUX_FAIL_TO_GET -2 +#define LINUX_UNKNOWN -1 +#define LINUX_OTHER 0 +#define LINUX_REDHAT 1 + +#define CMD_DEBUG_LEVEL 2 + +/* macro functions */ +#define CMD_DEBUG(lvl, fmt, args...) do { \ + if (CMD_DEBUG_LEVEL && (lvl) <= CMD_DEBUG_LEVEL) { \ + debug_print(fmt, ##args); \ + } \ +} while (0) + +#define SAFE_MALLOC(p, size) \ +{ \ + (p) = malloc((size)); \ + if ((p) == NULL) { \ + CU_DEBUG("malloc failed."); \ + } \ +} + +#define SAFE_CALLOC(p, nmen, size) \ +{ \ + (p) = calloc((nmen), (size)); \ + if ((p) == NULL) { \ + CU_DEBUG("calloc failed."); \ + } \ +} + +#define SAFE_FREE(p) {free(p); (p) = NULL; } + + +/* Macro used to compare two char*, it would skip if ref is NULL. It would + only set the result when src != ref, user need to set the result to 1 by + default before use the macro. If not set, the it could be used to do + check multi times in "one fail all die" mode. Empty lines is the place + where result should be set to 1. */ +#define CHARS_COMPARE_BY_REF(src, ref, result) do { \ + if ((ref) == NULL) { \ + ; \ + } else { \ + if ((src) == NULL) { \ + (result) = 0; \ + } else { \ + if (0 == strcmp((src), (ref))) { \ + ; \ + } else { \ + (result) = 0; \ + } \ + } \ + } \ +} while (0) + +#define CHARS_COMPARE_CASE_BY_REF(src, ref, result) do { \ + if ((ref) == NULL) { \ + ; \ + } else { \ + if ((src) == NULL) { \ + (result) = 0; \ + } else { \ + if (0 == strcasecmp((src), (ref))) { \ + ; \ + } else { \ + (result) = 0; \ + } \ + } \ + } \ +} while (0) + +#define NUM_COMPARE_BY_REF(src, ref, result, default) do { \ + if ((ref) == (default)) { \ + ; \ + } else { \ + if ((src) == (ref)) { \ + ; \ + } else { \ + result = 0; \ + } \ + } \ +} while (0) + +#define CHARS_MERGE_NORMAL(dest, src) do { \ + if (((dest) == NULL) && ((src) != NULL)) { \ + (dest) = strdup((src)); \ + } \ +} while (0) + +#define CHARS_MERGE_MOVE(dest, src) do { \ + if (((dest) == NULL) && ((src) != NULL)) { \ + (dest) = (src); \ + (src) = NULL; \ + } \ +} while (0) + +#define NUM_MERGE(dest, src, default) do { \ + if ((dest) == (default)) { \ + (dest) = (src); \ + } \ +} while (0) + +/* this macro may cause "p" to be excuted twice if it is a function */ +#define SAFE_STRDUP(p) (p) == NULL ? NULL : strdup(p); + +/* this macro make sure "src" to be excuted once if it is function, so it is + safe for functions that have state logged, such as "strtok" */ +#define SAFE_STRDUP_WITH_FUNC(dest, src, iter) do { \ + (iter) = (src); \ + if ((iter) == NULL) { \ + (dest) = NULL; \ + } else { \ + (dest) = strdup((iter)); \ + } \ +} while (0) + +#define SAFE_PSTR_ARRAY_DUP(ppdest, dest_num, ppsrc, src_num, iter) do { \ + (dest_num) = (src_num); \ + (ppdest) = NULL; \ + if (((ppsrc) != NULL) && ((src_num) > 0)) { \ + SAFE_CALLOC((ppdest), (src_num), sizeof(char *)); \ + (iter) = 0; \ + while ((iter) < (src_num)) { \ + *((ppdest)+(iter)) = SAFE_STRDUP(*((ppsrc)+(iter))); \ + (iter)++; \ + } \ + } \ +} while (0) + +/* functions */ +/* this function convert ip mask "24" in "192.1.0.9/24" to real mask num as + 255.255.255.0 */ +int netmask_easy_to_inaddr(struct in_addr *paddr, const char *pmask); + +/* this function would sort the pqos and check its values. */ +int vlan_8021q_qos_check_valid(VLAN_Qos_8021q *pqos); + +/* converting qos string of 802.1.Q, it should be as "0:0 1:0 2:0" */ +int vlan_8021q_qos_str_to_num(VLAN_Qos_8021q *pqos, const char *str); +int vlan_8021q_qos_num_to_str(char **str, const VLAN_Qos_8021q *pqos); + +/* following functions would return FILE popened, so it need pclose later, + cmd would be appended so it must be writable. */ +FILE *pipe_excute_command_type_read(char *cmd, const int buf_size, + const char *type, int *errno); +FILE *pipe_excute_command_type_write(char *cmd, const int buf_size, + const char *type, int *errno); + +/* following functions would return string by malloc, so it need free later */ +char *strtok_onetime(const char *str, const char *delim); +char *combine_file_name(const char *prefix, const char *name); + +/* write the configuration file */ +int configure_file_update(const char *path, const char *cont); +/* remove the configuration file */ +int configure_file_remove(const char *path); +/* replace one attribute, the file have format with one line for one propety */ +int configure_file_replace_attr(const char *path, const char *prefix, + const char *prop); + +int get_host_linux_version(void); + +char *translate_error_no(int errno); + +#endif -- 1.7.6

On 12/07/2011 04:25 AM, Wayne Xia wrote:
this is the helper function for the lib.
Signed-off-by: Wayne Xia<xiawenc@linux.vnet.ibm.com> --- libxkutil/host_network_error.h | 28 ++ libxkutil/host_network_helper.c | 659 +++++++++++++++++++++++++++++++++++++++ libxkutil/host_network_helper.h | 192 ++++++++++++ 3 files changed, 879 insertions(+), 0 deletions(-) create mode 100644 libxkutil/host_network_error.h create mode 100644 libxkutil/host_network_helper.c create mode 100644 libxkutil/host_network_helper.h
diff --git a/libxkutil/host_network_error.h b/libxkutil/host_network_error.h new file mode 100644 index 0000000..d809033 --- /dev/null +++ b/libxkutil/host_network_error.h @@ -0,0 +1,28 @@ +#ifndef HOST_NETWORK_ERROR_H +#define HOST_NETWORK_ERROR_H + +#define ERR_REQUEST_NOT_SUPPORT -1 + +#define ERR_COMMAND_NOT_SET -11 +#define ERR_COMMAND_PIPE_ERR -12 +#define ERR_COMMAND_NOT_SUPPORT -13 +#define ERR_COMMAND_NO_PERMISSION -14 +#define ERR_COMMAND_NO_READY -15 +#define ERR_COMMAND_PARAMETER_WRONG -16 +#define ERR_COMMAND_EXECUTION -17 + +#define ERR_DEVICE_EXCEED_MAXNUM -100 +#define ERR_DEVICE_EXIST -101 +#define ERR_DEVICE_NOT_EXIST -102 +#define ERR_DEVICE_ALREADY_DONE -103 +#define ERR_DEVICE_CONNECT_OTHER -104 + +#define ERR_FILE_OP_FAIL -125 +#define ERR_FILE_EMPTY -126 +#define ERR_FILE_TOO_LARGE -127 +#define ERR_FILE_CONT_TOO_LARGE -128 +#define ERR_FILE_LOCK_FAIL -129 + +#define ERR_PERSIST_NOT_REDHAT -200 Any particular reason for negative numbers? + +#endif diff --git a/libxkutil/host_network_helper.c b/libxkutil/host_network_helper.c new file mode 100644 index 0000000..dc9f775 --- /dev/null +++ b/libxkutil/host_network_helper.c @@ -0,0 +1,659 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia<xiawenc@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. + */ + + + +#include<string.h> +#include<sys/types.h> +#include<sys/stat.h> +#include<unistd.h> +#include<fcntl.h> + +#include "host_network_helper.h" +#include "host_network_error.h" + +#define CONFIGURE_FILE_MAX_SIZE 2048 + +#define PIPE_CMD_SUFFIX " 2>&1" + +static int g_linux_version = LINUX_UNKNOWN; I assume this is needed because the parse output varies? + +static int compare_qos_8021q(const void *p1, const void *p2) +{ + const VLAN_Qos_8021q_elem *qos1 = (VLAN_Qos_8021q_elem *)p1; + const VLAN_Qos_8021q_elem *qos2 = (VLAN_Qos_8021q_elem *)p2; + int ret = 0; + if ((qos1->from)> (qos2->from)) { + ret = 1; + } + return ret; +} + +/* it need to be checked see whether these are the conditions */ +int vlan_8021q_qos_check_valid(VLAN_Qos_8021q *pqos) +{ + int ret = 1; + int i = 0; + int last_num = -1; + if ((pqos->count< 0) || (pqos->count> 8)) { + ret = 0; + goto out; + } else if (pqos->count == 0) { + goto out; + } + qsort((void *)pqos->values, pqos->count, sizeof(VLAN_Qos_8021q_elem), + compare_qos_8021q); + + while (i< pqos->count) { + if (pqos->values[i].from == last_num) { + CU_DEBUG("error: vlan 802.1.q qos setting have same<from> values: " + "last is %d, new is %d", last_num, pqos->values[i].from); + ret = 0; + goto out; + } + last_num = pqos->values[i].from; + if ((pqos->values[i].from< 0) || (pqos->values[i].from>= 8)) { + CU_DEBUG("error: vlan 802.1.q qos setting have outbound value: " + "from is %d.", pqos->values[i].from); + ret = 0; + goto out; + } + if ((pqos->values[i].to< 0) || (pqos->values[i].to>= 8)) { + CU_DEBUG("error: vlan 802.1.q qos setting have outbound value: " + "to is %d.", pqos->values[i].to); + ret = 0; + goto out; + } + i++; + } + + out: + return ret; +} + +int vlan_8021q_qos_str_to_num(VLAN_Qos_8021q *pqos, const char* str) +{ + int ret = 1; + char *str_line = NULL; + char *temp; + char *saveptr = NULL; + char *invalptr1, *invalptr2; + int qos_num1, qos_num2; + VLAN_Qos_8021q qos; + + if (str == NULL) { + ret = 0; + goto out; + } + if (str[0] == '\0') { + ret = 1; + pqos->count = 0; + CU_DEBUG("empty vlan 802.1.q qos string found."); + goto out; + } + str_line = SAFE_STRDUP(str); + qos.count = 0; + + temp = strtok_r(str_line, " ",&saveptr); + while (temp != NULL) { + qos_num1 = strtol(temp,&invalptr1, 10); + if (temp == invalptr1) { + ret = 0; + goto out; + } + if (*invalptr1 != ':') { + ret = 0; + goto out; + } + invalptr1++; + qos_num2 = strtol(invalptr1,&invalptr2, 10); + if (invalptr1 == invalptr2) { + ret = 0; + goto out; + } + if (*invalptr2 != '\0') { + ret = 0; + goto out; + } + if (qos.count>= 8) { + ret = 0; + CU_DEBUG("too many settings found in vlan 802.1.q qos string [%s]", + str); + goto out; + } + qos.values[qos.count].from = qos_num1; + qos.values[qos.count].to = qos_num2; + qos.count++; + temp = strtok_r(NULL, " ",&saveptr); + } + ret = vlan_8021q_qos_check_valid(&qos); + if (ret == 1) { + *pqos = qos; + } + + out: + if (ret != 1) { + CU_DEBUG("vlan 802.1.q qos string [%s] is invalid.", str); + } + SAFE_FREE(str_line); + return ret; +} + +int vlan_8021q_qos_num_to_str(char **str, const VLAN_Qos_8021q *pqos) +{ + char temp[16]; + int i; + VLAN_Qos_8021q qos = *pqos; + int ret = vlan_8021q_qos_check_valid(&qos); + if (ret != 1) { + goto out; + } + SAFE_MALLOC(*str, 64); + *str[0] = '\0'; + if (qos.count == 0) { + goto out; + } + i = 0; + snprintf(temp, sizeof(temp), "%d:%d", + qos.values[i].from, qos.values[i].to); + strcat(*str, temp); + i++; + while (i< qos.count) { + strcat(*str, " "); + snprintf(temp, sizeof(temp), "%d:%d", + qos.values[i].from, qos.values[i].to); + strcat(*str, temp); + i++; + } + + out: + return ret; +} + +int netmask_easy_to_inaddr(struct in_addr *paddr, const char* pmask) +{ + long mask_one_num = -1; + unsigned char *p; + int bitnum; + + mask_one_num = strtol(pmask, NULL, 10); + if ((mask_one_num< 0) || (mask_one_num> 32)) { + return 0; + } + + /* use network byte order */ + p = (unsigned char *)&paddr->s_addr; + memset(p, 0, 4); + while (mask_one_num> 8) { + *(p++) = 255; + mask_one_num -= 8; + } + bitnum = 7; + while (mask_one_num> 0) { + *p = *p + (1<<bitnum); + mask_one_num--; + bitnum--; + } + return 1; +} + +char *strtok_onetime(const char *str, const char *delim) +{ + char *t = strstr(str, delim); + char *ret_char; + int len; + if (t == NULL) { + return NULL; + } + len = t - str; + if (len<= 0) { + return NULL; + } + SAFE_MALLOC(ret_char, len+1); + strncpy(ret_char, str, len); + ret_char[len] = '\0'; + + return ret_char; +} + +char *combine_file_name(const char *prefix, const char *name) +{ + char *ret = NULL; + int size; + size = strlen(prefix) + strlen(name) + 1; + SAFE_CALLOC(ret, size, sizeof(char)); + snprintf(ret, size, "%s%s", prefix, name); + return ret; +} + +/* return the whole content length that need update. The data length keep + unchanged in the head part is returned in *unchanged_len which could be + used to avoid write whole data later. + requriement: cont must contain end character, prefix must be not NULL */ +static int replace_prop_str(char *cont, const int maxsize, const char *prefix, + const char *prop, int *unchanged_len) +{ + int target_len, origin_len; + int cont_len; + int valid_len = 0; + int prefix_len, prop_len = 0; + char *endchar1 = "\n"; + char *pprop_start, *pprop_end; + int head_len; + + cont_len = strlen(cont); + head_len = cont_len; + prefix_len = strlen(prefix); + if ((prop == NULL) || (*prop == '\0')) { + /* want the property removed */ + target_len = 0; + } else { + /* want the property changed */ + prop_len = strlen(prop); + target_len = prefix_len + prop_len; + } + + pprop_start = strstr(cont, prefix); + if (pprop_start == NULL) { + /* the content do not exist in original contents */ + if (target_len> 0) { + /* add the property */ + if ((cont_len + target_len)>= maxsize) { + CU_DEBUG("buffer is too small for the operation."); + valid_len = -1; + goto out; + } + strcat(cont, prefix); + strcat(cont, prop); + valid_len = cont_len + target_len; + } else { + /* remove the property, but it do not exist, so skip */ + } + } else { + /* the content exist in original contents */ + /* locate the end of the property */ + pprop_end = strstr(pprop_start, endchar1); + if (pprop_end == NULL) { + /* last line */ + origin_len = strlen(pprop_start); + pprop_end = cont+cont_len; + } else { + origin_len = pprop_end - pprop_start; + } + if (target_len> 0) { + /* change the property */ + /* check the bound */ + if ((cont_len + target_len - origin_len)>= maxsize) { + CU_DEBUG("buffer is too small for the operation."); + valid_len = -1; + goto out; + } + /* move contents in the tail */ + memmove(pprop_end+target_len-origin_len, pprop_end, + cont+cont_len+1-pprop_end); + /* copy the content of the new string */ + memcpy(pprop_start+prefix_len, prop, prop_len); + head_len = pprop_start - cont + prefix_len; + } else { + /* remove the property */ + /* move contents in the tail to replace original string*/ + memmove(pprop_end+target_len-origin_len, pprop_end, + cont+cont_len+1-pprop_end); + head_len = pprop_start - cont; + } + valid_len = cont_len + target_len - origin_len; + } + + out: + if (unchanged_len != NULL) { + *unchanged_len = head_len; + } + return valid_len; +} + +int configure_file_replace_attr(const char *path, const char *prefix, + const char *prop) +{ + int fd = -1; + int fop_ret; + struct stat s; + struct flock lock; + int lock_state = -1; + char *cont = NULL; + char *pbuff; + int write_len; + int cont_len_update; + int cont_len_unchanged; + int ret = 0; + + if ((prefix == NULL) || (*prefix == '\0')) { + CU_DEBUG("no prefix for property set, could not replace the content."); + goto out; + } + + fd = open(path, O_RDWR, 0644); + if (fd< 0) { + CU_DEBUG("Unable to open [%s], it does not exist.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + lock_state = fcntl(fd, F_SETLK,&lock); + if (lock_state< 0) { + CU_DEBUG("Failed to lock file [%s], it may be locked by other.", path); + ret = ERR_FILE_LOCK_FAIL; + goto out; + } + + fstat(fd,&s); + if (s.st_size == 0) { + CU_DEBUG("file [%s] is empty, will not replace attr for it.", path); + ret = ERR_FILE_EMPTY; + goto out; + } else if (s.st_size>= CONFIGURE_FILE_MAX_SIZE) { + CU_DEBUG("file [%s] is too large, " + "it have %lld bytes, will not read it.", + path, (long long)s.st_size); + ret = ERR_FILE_TOO_LARGE; + goto out; + } + + SAFE_MALLOC(cont, CONFIGURE_FILE_MAX_SIZE); + lseek(fd, 0, SEEK_SET); + fop_ret = read(fd, cont, s.st_size); + cont[s.st_size] = '\0'; + cont_len_update = replace_prop_str(cont, CONFIGURE_FILE_MAX_SIZE, + prefix, prop,&cont_len_unchanged); + if (cont_len_update< 0) { + CU_DEBUG("file [%s] is too big to expand it with [%s%s].", + path, prefix, prop); + ret = ERR_FILE_TOO_LARGE; + goto out; + } else if (cont_len_update == 0) { + CU_DEBUG("the contents was not changed, do not need update it"); + ret = 1; + goto out; + } else { + if (ftruncate(fd, cont_len_unchanged) != 0) { + CU_DEBUG("file [%s] Unable to truncate it", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + write_len = cont_len_update-cont_len_unchanged; + if (write_len> 0) { + lseek(fd, cont_len_unchanged, SEEK_SET); + CU_DEBUG("writing file [%s] for %d bytes with offset %d," + " cont is :\n%s\n", + path, write_len, cont_len_unchanged, cont); + pbuff = cont+cont_len_unchanged; + fop_ret = write(fd, pbuff, write_len); + } + } + ret = 1; + + out: + if (fd>= 0) { + if (lock_state>= 0) { + lock.l_type = F_UNLCK; + fcntl(fd, F_SETLK,&lock); + } + close(fd); + } + SAFE_FREE(cont); + return ret; +} + +int configure_file_update(const char *path, const char *cont) +{ + int fd = -1; + int fop_ret; + struct flock lock; + int lock_state = -1; + int write_len; + int ret = 0; + + fd = open(path, O_RDWR|O_CREAT, 0644); + if (fd< 0) { + CU_DEBUG("Unable to open [%s], it does not exist.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + lock_state = fcntl(fd, F_SETLK,&lock); + if (lock_state< 0) { + CU_DEBUG("Failed to lock file [%s], it may be locked by other.", path); + ret = ERR_FILE_LOCK_FAIL; + goto out; + } + + if (ftruncate(fd, 0) != 0) { + CU_DEBUG("file [%s] Unable to truncate it", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + write_len = strlen(cont); + if (write_len> 0) { + lseek(fd, 0, SEEK_SET); + CU_DEBUG("writing file [%s] for %d bytes with offset 0," + " cont is :\n%s\n", + path, write_len, cont); + fop_ret = write(fd, cont, write_len); + } + ret = 1; + + out: + if (fd>= 0) { + if (lock_state>= 0) { + lock.l_type = F_UNLCK; + fcntl(fd, F_SETLK,&lock); + } + close(fd); + } + return ret; +} + +int configure_file_remove(const char *path) +{ + int fd_ret; + int ret = 0; + if (access(path, F_OK) == 0) { + CU_DEBUG("Deleting %s.", path); + fd_ret = remove(path); + if (fd_ret != 0) { + CU_DEBUG("failed to remove %s.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + } + + ret = 1; + out: + return ret; +} + +FILE *pipe_excute_command_type_read(char *cmd, const int buf_size, + const char *type, int *errno) +{ + FILE *stream = NULL; + char *suffix = PIPE_CMD_SUFFIX; + if ((strlen(cmd) + strlen(suffix))>= buf_size) { + CU_DEBUG("cmd [%s] is too long to append the suffix", cmd); + *errno = ERR_COMMAND_NO_READY; + goto out; + } + strcat(cmd, suffix); + CU_DEBUG("excuting readonly cmd [%s].", cmd); + stream = popen(cmd, type); + if (stream == NULL) { + CU_DEBUG("Failed to open pipe to run command"); + *errno = ERR_COMMAND_PIPE_ERR; + } + +out: + return stream; +} + +FILE *pipe_excute_command_type_write(char *cmd, const int buf_size, + const char *type, int *errno) +{ + FILE *stream = NULL; + char *suffix = PIPE_CMD_SUFFIX; + if ((strlen(cmd) + strlen(suffix))>= buf_size) { + CU_DEBUG("cmd [%s] is too long to append the suffix", cmd); + *errno = ERR_COMMAND_NO_READY; + goto out; + } + strcat(cmd, suffix); + CU_DEBUG("excuting system modification cmd [%s].", cmd); + stream = popen(cmd, type); + if (stream == NULL) { + CU_DEBUG("Failed to open pipe to run command"); + *errno = ERR_COMMAND_PIPE_ERR; + } + usleep(10000); + +out: + return stream; +} + +int get_host_linux_version(void) +{ + FILE *stream = NULL; + char cmd[64]; + char buff[256]; + int linenum; + int errno; + + if (g_linux_version != LINUX_UNKNOWN) { + goto out; + } + + cmd[0] = '\0'; + strcat(cmd, "lsb_release -a"); + stream = pipe_excute_command_type_read(cmd, sizeof(cmd), "r",&errno); + if (stream == NULL) { + goto out; + } + + linenum = -1; + g_linux_version = LINUX_OTHER; + while (fgets(buff, 256, stream) != NULL) { + linenum++; + if (linenum == 0) { + if (NULL == strstr(buff, "LSB")) { + CU_DEBUG("ERR: unable to get linux distribution version."); + g_linux_version = LINUX_FAIL_TO_GET; + } + } + if ((NULL != strstr(buff, "Red Hat")) || + (NULL != strstr(buff, "RedHat"))) { + g_linux_version = LINUX_REDHAT; + break; + } + } + + out: + if (stream != NULL) { + pclose(stream); + } + return g_linux_version; +} + +char *translate_error_no(int errno) +{ + char *ret = NULL; + switch (errno) { + case ERR_REQUEST_NOT_SUPPORT: + ret = "request is not supported now"; + break; + + case ERR_COMMAND_NOT_SET: + ret = "command is not set."; + break; + case ERR_COMMAND_PIPE_ERR: + ret = "failed in creating pipe to execute the command."; + break; + case ERR_COMMAND_NOT_SUPPORT: + ret = "command is not found, check u environment."; + break; + case ERR_COMMAND_NO_PERMISSION: + ret = "not enough authority to execute the command."; + break; + case ERR_COMMAND_NO_READY: + ret = "failed to build up the command line, check your input, " + "maybe it is too long."; + break; + case ERR_COMMAND_PARAMETER_WRONG: + ret = "got invalid paramenter, check your input."; + break; + case ERR_COMMAND_EXECUTION: + ret = "error happened in the excution of command."; + break; + + case ERR_DEVICE_EXCEED_MAXNUM: + ret = "too many devices found or set, check the environment."; + break; + case ERR_DEVICE_EXIST: + ret = "device already exist, can not execute the command."; + break; + case ERR_DEVICE_NOT_EXIST: + ret = "device do not exist, can not execute the command."; + break; + case ERR_DEVICE_ALREADY_DONE: + ret = "the operation you want have been done before, " + "will not do it again."; + break; + case ERR_DEVICE_CONNECT_OTHER: + ret = "the device you want to connect have been connect to another" + " device, can't change it directly."; + break; + + case ERR_FILE_OP_FAIL: + ret = "failed in accessing the file."; + break; + case ERR_FILE_EMPTY: + ret = "the file it want is empty."; + break; + case ERR_FILE_TOO_LARGE: + ret = "the file it want is too large."; + break; + case ERR_FILE_CONT_TOO_LARGE: + ret = "the content it want to combine to file is too large."; + break; + case ERR_FILE_LOCK_FAIL: + ret = "failed in locking the file, " + "check if other process is using it."; + break; + + case ERR_PERSIST_NOT_REDHAT: + ret = "host is not a RedHat distribution, can't persist the " + "configuration, it would not take effect after host is " + "rebooted. Other version would be supported in the future. " + "If you are sure host is RedHat, make sure command " + "<lsb_release -a> could work."; + break; + + default: + ret = "internal error."; + break; + } + return ret; +} diff --git a/libxkutil/host_network_helper.h b/libxkutil/host_network_helper.h new file mode 100644 index 0000000..a232221 --- /dev/null +++ b/libxkutil/host_network_helper.h @@ -0,0 +1,192 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia<xiawenc@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. + */ + + +#ifndef HOST_NETWORK_HELPER_H +#define HOST_NETWORK_HELPER_H + +#include<stdio.h> +#include<stdlib.h> +#include<arpa/inet.h> + +#include "host_network_basic.h" + +#ifdef TESTLIB +#include "TestDefines.h" +#else +#include<libcmpiutil/libcmpiutil.h> +#endif + +#define LINUX_FAIL_TO_GET -2 +#define LINUX_UNKNOWN -1 +#define LINUX_OTHER 0 +#define LINUX_REDHAT 1 + +#define CMD_DEBUG_LEVEL 2 + +/* macro functions */ +#define CMD_DEBUG(lvl, fmt, args...) do { \ + if (CMD_DEBUG_LEVEL&& (lvl)<= CMD_DEBUG_LEVEL) { \ + debug_print(fmt, ##args); \ + } \ +} while (0) + +#define SAFE_MALLOC(p, size) \ +{ \ + (p) = malloc((size)); \ + if ((p) == NULL) { \ + CU_DEBUG("malloc failed."); \ + } \ +} + +#define SAFE_CALLOC(p, nmen, size) \ +{ \ + (p) = calloc((nmen), (size)); \ + if ((p) == NULL) { \ + CU_DEBUG("calloc failed."); \ + } \ +} + +#define SAFE_FREE(p) {free(p); (p) = NULL; } + + +/* Macro used to compare two char*, it would skip if ref is NULL. It would + only set the result when src != ref, user need to set the result to 1 by + default before use the macro. If not set, the it could be used to do + check multi times in "one fail all die" mode. Empty lines is the place + where result should be set to 1. */ +#define CHARS_COMPARE_BY_REF(src, ref, result) do { \ + if ((ref) == NULL) { \ + ; \ + } else { \ + if ((src) == NULL) { \ + (result) = 0; \ + } else { \ + if (0 == strcmp((src), (ref))) { \ + ; \ + } else { \ + (result) = 0; \ + } \ + } \ + } \ +} while (0) + +#define CHARS_COMPARE_CASE_BY_REF(src, ref, result) do { \ + if ((ref) == NULL) { \ + ; \ + } else { \ + if ((src) == NULL) { \ + (result) = 0; \ + } else { \ + if (0 == strcasecmp((src), (ref))) { \ + ; \ + } else { \ + (result) = 0; \ + } \ + } \ + } \ +} while (0) + +#define NUM_COMPARE_BY_REF(src, ref, result, default) do { \ + if ((ref) == (default)) { \ + ; \ + } else { \ + if ((src) == (ref)) { \ + ; \ + } else { \ + result = 0; \ + } \ + } \ +} while (0) + +#define CHARS_MERGE_NORMAL(dest, src) do { \ + if (((dest) == NULL)&& ((src) != NULL)) { \ + (dest) = strdup((src)); \ + } \ +} while (0) + +#define CHARS_MERGE_MOVE(dest, src) do { \ + if (((dest) == NULL)&& ((src) != NULL)) { \ + (dest) = (src); \ + (src) = NULL; \ + } \ +} while (0) + +#define NUM_MERGE(dest, src, default) do { \ + if ((dest) == (default)) { \ + (dest) = (src); \ + } \ +} while (0) + +/* this macro may cause "p" to be excuted twice if it is a function */ +#define SAFE_STRDUP(p) (p) == NULL ? NULL : strdup(p); + +/* this macro make sure "src" to be excuted once if it is function, so it is + safe for functions that have state logged, such as "strtok" */ +#define SAFE_STRDUP_WITH_FUNC(dest, src, iter) do { \ + (iter) = (src); \ + if ((iter) == NULL) { \ + (dest) = NULL; \ + } else { \ + (dest) = strdup((iter)); \ + } \ +} while (0) + +#define SAFE_PSTR_ARRAY_DUP(ppdest, dest_num, ppsrc, src_num, iter) do { \ + (dest_num) = (src_num); \ + (ppdest) = NULL; \ + if (((ppsrc) != NULL)&& ((src_num)> 0)) { \ + SAFE_CALLOC((ppdest), (src_num), sizeof(char *)); \ + (iter) = 0; \ + while ((iter)< (src_num)) { \ + *((ppdest)+(iter)) = SAFE_STRDUP(*((ppsrc)+(iter))); \ + (iter)++; \ + } \ + } \ +} while (0) + +/* functions */ +/* this function convert ip mask "24" in "192.1.0.9/24" to real mask num as + 255.255.255.0 */ +int netmask_easy_to_inaddr(struct in_addr *paddr, const char *pmask); + +/* this function would sort the pqos and check its values. */ +int vlan_8021q_qos_check_valid(VLAN_Qos_8021q *pqos); + +/* converting qos string of 802.1.Q, it should be as "0:0 1:0 2:0" */ +int vlan_8021q_qos_str_to_num(VLAN_Qos_8021q *pqos, const char *str); +int vlan_8021q_qos_num_to_str(char **str, const VLAN_Qos_8021q *pqos); + +/* following functions would return FILE popened, so it need pclose later, + cmd would be appended so it must be writable. */ +FILE *pipe_excute_command_type_read(char *cmd, const int buf_size, + const char *type, int *errno); +FILE *pipe_excute_command_type_write(char *cmd, const int buf_size, + const char *type, int *errno); + +/* following functions would return string by malloc, so it need free later */ +char *strtok_onetime(const char *str, const char *delim); +char *combine_file_name(const char *prefix, const char *name); + +/* write the configuration file */ +int configure_file_update(const char *path, const char *cont); +/* remove the configuration file */ +int configure_file_remove(const char *path); +/* replace one attribute, the file have format with one line for one propety */ +int configure_file_replace_attr(const char *path, const char *prefix, + const char *prop); + +int get_host_linux_version(void); + +char *translate_error_no(int errno); + +#endif
-- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent@linux.vnet.ibm.com

于 2011-12-24 4:18, Chip Vincent 写道:
On 12/07/2011 04:25 AM, Wayne Xia wrote:
this is the helper function for the lib.
Signed-off-by: Wayne Xia<xiawenc@linux.vnet.ibm.com> --- libxkutil/host_network_error.h | 28 ++ libxkutil/host_network_helper.c | 659 +++++++++++++++++++++++++++++++++++++++ libxkutil/host_network_helper.h | 192 ++++++++++++ 3 files changed, 879 insertions(+), 0 deletions(-) create mode 100644 libxkutil/host_network_error.h create mode 100644 libxkutil/host_network_helper.c create mode 100644 libxkutil/host_network_helper.h
diff --git a/libxkutil/host_network_error.h b/libxkutil/host_network_error.h new file mode 100644 index 0000000..d809033 --- /dev/null +++ b/libxkutil/host_network_error.h @@ -0,0 +1,28 @@ +#ifndef HOST_NETWORK_ERROR_H +#define HOST_NETWORK_ERROR_H + +#define ERR_REQUEST_NOT_SUPPORT -1 + +#define ERR_COMMAND_NOT_SET -11 +#define ERR_COMMAND_PIPE_ERR -12 +#define ERR_COMMAND_NOT_SUPPORT -13 +#define ERR_COMMAND_NO_PERMISSION -14 +#define ERR_COMMAND_NO_READY -15 +#define ERR_COMMAND_PARAMETER_WRONG -16 +#define ERR_COMMAND_EXECUTION -17 + +#define ERR_DEVICE_EXCEED_MAXNUM -100 +#define ERR_DEVICE_EXIST -101 +#define ERR_DEVICE_NOT_EXIST -102 +#define ERR_DEVICE_ALREADY_DONE -103 +#define ERR_DEVICE_CONNECT_OTHER -104 + +#define ERR_FILE_OP_FAIL -125 +#define ERR_FILE_EMPTY -126 +#define ERR_FILE_TOO_LARGE -127 +#define ERR_FILE_CONT_TOO_LARGE -128 +#define ERR_FILE_LOCK_FAIL -129 + +#define ERR_PERSIST_NOT_REDHAT -200 Any particular reason for negative numbers?
No, just a custom to use negative number indicating errors. Is that bad?
+ +#endif diff --git a/libxkutil/host_network_helper.c b/libxkutil/host_network_helper.c new file mode 100644 index 0000000..dc9f775 --- /dev/null +++ b/libxkutil/host_network_helper.c @@ -0,0 +1,659 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia<xiawenc@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. + */ + + + +#include<string.h> +#include<sys/types.h> +#include<sys/stat.h> +#include<unistd.h> +#include<fcntl.h> + +#include "host_network_helper.h" +#include "host_network_error.h" + +#define CONFIGURE_FILE_MAX_SIZE 2048 + +#define PIPE_CMD_SUFFIX " 2>&1" + +static int g_linux_version = LINUX_UNKNOWN; I assume this is needed because the parse output varies?
Tried some version, it seems the output was almost the same, but persisting of configuration was linux distribution depending.
+ +static int compare_qos_8021q(const void *p1, const void *p2) +{ + const VLAN_Qos_8021q_elem *qos1 = (VLAN_Qos_8021q_elem *)p1; + const VLAN_Qos_8021q_elem *qos2 = (VLAN_Qos_8021q_elem *)p2; + int ret = 0; + if ((qos1->from)> (qos2->from)) { + ret = 1; + } + return ret; +} + +/* it need to be checked see whether these are the conditions */ +int vlan_8021q_qos_check_valid(VLAN_Qos_8021q *pqos) +{ + int ret = 1; + int i = 0; + int last_num = -1; + if ((pqos->count< 0) || (pqos->count> 8)) { + ret = 0; + goto out; + } else if (pqos->count == 0) { + goto out; + } + qsort((void *)pqos->values, pqos->count, sizeof(VLAN_Qos_8021q_elem), + compare_qos_8021q); + + while (i< pqos->count) { + if (pqos->values[i].from == last_num) { + CU_DEBUG("error: vlan 802.1.q qos setting have same<from> values: " + "last is %d, new is %d", last_num, pqos->values[i].from); + ret = 0; + goto out; + } + last_num = pqos->values[i].from; + if ((pqos->values[i].from< 0) || (pqos->values[i].from>= 8)) { + CU_DEBUG("error: vlan 802.1.q qos setting have outbound value: " + "from is %d.", pqos->values[i].from); + ret = 0; + goto out; + } + if ((pqos->values[i].to< 0) || (pqos->values[i].to>= 8)) { + CU_DEBUG("error: vlan 802.1.q qos setting have outbound value: " + "to is %d.", pqos->values[i].to); + ret = 0; + goto out; + } + i++; + } + + out: + return ret; +} + +int vlan_8021q_qos_str_to_num(VLAN_Qos_8021q *pqos, const char* str) +{ + int ret = 1; + char *str_line = NULL; + char *temp; + char *saveptr = NULL; + char *invalptr1, *invalptr2; + int qos_num1, qos_num2; + VLAN_Qos_8021q qos; + + if (str == NULL) { + ret = 0; + goto out; + } + if (str[0] == '\0') { + ret = 1; + pqos->count = 0; + CU_DEBUG("empty vlan 802.1.q qos string found."); + goto out; + } + str_line = SAFE_STRDUP(str); + qos.count = 0; + + temp = strtok_r(str_line, " ",&saveptr); + while (temp != NULL) { + qos_num1 = strtol(temp,&invalptr1, 10); + if (temp == invalptr1) { + ret = 0; + goto out; + } + if (*invalptr1 != ':') { + ret = 0; + goto out; + } + invalptr1++; + qos_num2 = strtol(invalptr1,&invalptr2, 10); + if (invalptr1 == invalptr2) { + ret = 0; + goto out; + } + if (*invalptr2 != '\0') { + ret = 0; + goto out; + } + if (qos.count>= 8) { + ret = 0; + CU_DEBUG("too many settings found in vlan 802.1.q qos string [%s]", + str); + goto out; + } + qos.values[qos.count].from = qos_num1; + qos.values[qos.count].to = qos_num2; + qos.count++; + temp = strtok_r(NULL, " ",&saveptr); + } + ret = vlan_8021q_qos_check_valid(&qos); + if (ret == 1) { + *pqos = qos; + } + + out: + if (ret != 1) { + CU_DEBUG("vlan 802.1.q qos string [%s] is invalid.", str); + } + SAFE_FREE(str_line); + return ret; +} + +int vlan_8021q_qos_num_to_str(char **str, const VLAN_Qos_8021q *pqos) +{ + char temp[16]; + int i; + VLAN_Qos_8021q qos = *pqos; + int ret = vlan_8021q_qos_check_valid(&qos); + if (ret != 1) { + goto out; + } + SAFE_MALLOC(*str, 64); + *str[0] = '\0'; + if (qos.count == 0) { + goto out; + } + i = 0; + snprintf(temp, sizeof(temp), "%d:%d", + qos.values[i].from, qos.values[i].to); + strcat(*str, temp); + i++; + while (i< qos.count) { + strcat(*str, " "); + snprintf(temp, sizeof(temp), "%d:%d", + qos.values[i].from, qos.values[i].to); + strcat(*str, temp); + i++; + } + + out: + return ret; +} + +int netmask_easy_to_inaddr(struct in_addr *paddr, const char* pmask) +{ + long mask_one_num = -1; + unsigned char *p; + int bitnum; + + mask_one_num = strtol(pmask, NULL, 10); + if ((mask_one_num< 0) || (mask_one_num> 32)) { + return 0; + } + + /* use network byte order */ + p = (unsigned char *)&paddr->s_addr; + memset(p, 0, 4); + while (mask_one_num> 8) { + *(p++) = 255; + mask_one_num -= 8; + } + bitnum = 7; + while (mask_one_num> 0) { + *p = *p + (1<<bitnum); + mask_one_num--; + bitnum--; + } + return 1; +} + +char *strtok_onetime(const char *str, const char *delim) +{ + char *t = strstr(str, delim); + char *ret_char; + int len; + if (t == NULL) { + return NULL; + } + len = t - str; + if (len<= 0) { + return NULL; + } + SAFE_MALLOC(ret_char, len+1); + strncpy(ret_char, str, len); + ret_char[len] = '\0'; + + return ret_char; +} + +char *combine_file_name(const char *prefix, const char *name) +{ + char *ret = NULL; + int size; + size = strlen(prefix) + strlen(name) + 1; + SAFE_CALLOC(ret, size, sizeof(char)); + snprintf(ret, size, "%s%s", prefix, name); + return ret; +} + +/* return the whole content length that need update. The data length keep + unchanged in the head part is returned in *unchanged_len which could be + used to avoid write whole data later. + requriement: cont must contain end character, prefix must be not NULL */ +static int replace_prop_str(char *cont, const int maxsize, const char *prefix, + const char *prop, int *unchanged_len) +{ + int target_len, origin_len; + int cont_len; + int valid_len = 0; + int prefix_len, prop_len = 0; + char *endchar1 = "\n"; + char *pprop_start, *pprop_end; + int head_len; + + cont_len = strlen(cont); + head_len = cont_len; + prefix_len = strlen(prefix); + if ((prop == NULL) || (*prop == '\0')) { + /* want the property removed */ + target_len = 0; + } else { + /* want the property changed */ + prop_len = strlen(prop); + target_len = prefix_len + prop_len; + } + + pprop_start = strstr(cont, prefix); + if (pprop_start == NULL) { + /* the content do not exist in original contents */ + if (target_len> 0) { + /* add the property */ + if ((cont_len + target_len)>= maxsize) { + CU_DEBUG("buffer is too small for the operation."); + valid_len = -1; + goto out; + } + strcat(cont, prefix); + strcat(cont, prop); + valid_len = cont_len + target_len; + } else { + /* remove the property, but it do not exist, so skip */ + } + } else { + /* the content exist in original contents */ + /* locate the end of the property */ + pprop_end = strstr(pprop_start, endchar1); + if (pprop_end == NULL) { + /* last line */ + origin_len = strlen(pprop_start); + pprop_end = cont+cont_len; + } else { + origin_len = pprop_end - pprop_start; + } + if (target_len> 0) { + /* change the property */ + /* check the bound */ + if ((cont_len + target_len - origin_len)>= maxsize) { + CU_DEBUG("buffer is too small for the operation."); + valid_len = -1; + goto out; + } + /* move contents in the tail */ + memmove(pprop_end+target_len-origin_len, pprop_end, + cont+cont_len+1-pprop_end); + /* copy the content of the new string */ + memcpy(pprop_start+prefix_len, prop, prop_len); + head_len = pprop_start - cont + prefix_len; + } else { + /* remove the property */ + /* move contents in the tail to replace original string*/ + memmove(pprop_end+target_len-origin_len, pprop_end, + cont+cont_len+1-pprop_end); + head_len = pprop_start - cont; + } + valid_len = cont_len + target_len - origin_len; + } + + out: + if (unchanged_len != NULL) { + *unchanged_len = head_len; + } + return valid_len; +} + +int configure_file_replace_attr(const char *path, const char *prefix, + const char *prop) +{ + int fd = -1; + int fop_ret; + struct stat s; + struct flock lock; + int lock_state = -1; + char *cont = NULL; + char *pbuff; + int write_len; + int cont_len_update; + int cont_len_unchanged; + int ret = 0; + + if ((prefix == NULL) || (*prefix == '\0')) { + CU_DEBUG("no prefix for property set, could not replace the content."); + goto out; + } + + fd = open(path, O_RDWR, 0644); + if (fd< 0) { + CU_DEBUG("Unable to open [%s], it does not exist.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + lock_state = fcntl(fd, F_SETLK,&lock); + if (lock_state< 0) { + CU_DEBUG("Failed to lock file [%s], it may be locked by other.", path); + ret = ERR_FILE_LOCK_FAIL; + goto out; + } + + fstat(fd,&s); + if (s.st_size == 0) { + CU_DEBUG("file [%s] is empty, will not replace attr for it.", path); + ret = ERR_FILE_EMPTY; + goto out; + } else if (s.st_size>= CONFIGURE_FILE_MAX_SIZE) { + CU_DEBUG("file [%s] is too large, " + "it have %lld bytes, will not read it.", + path, (long long)s.st_size); + ret = ERR_FILE_TOO_LARGE; + goto out; + } + + SAFE_MALLOC(cont, CONFIGURE_FILE_MAX_SIZE); + lseek(fd, 0, SEEK_SET); + fop_ret = read(fd, cont, s.st_size); + cont[s.st_size] = '\0'; + cont_len_update = replace_prop_str(cont, CONFIGURE_FILE_MAX_SIZE, + prefix, prop,&cont_len_unchanged); + if (cont_len_update< 0) { + CU_DEBUG("file [%s] is too big to expand it with [%s%s].", + path, prefix, prop); + ret = ERR_FILE_TOO_LARGE; + goto out; + } else if (cont_len_update == 0) { + CU_DEBUG("the contents was not changed, do not need update it"); + ret = 1; + goto out; + } else { + if (ftruncate(fd, cont_len_unchanged) != 0) { + CU_DEBUG("file [%s] Unable to truncate it", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + write_len = cont_len_update-cont_len_unchanged; + if (write_len> 0) { + lseek(fd, cont_len_unchanged, SEEK_SET); + CU_DEBUG("writing file [%s] for %d bytes with offset %d," + " cont is :\n%s\n", + path, write_len, cont_len_unchanged, cont); + pbuff = cont+cont_len_unchanged; + fop_ret = write(fd, pbuff, write_len); + } + } + ret = 1; + + out: + if (fd>= 0) { + if (lock_state>= 0) { + lock.l_type = F_UNLCK; + fcntl(fd, F_SETLK,&lock); + } + close(fd); + } + SAFE_FREE(cont); + return ret; +} + +int configure_file_update(const char *path, const char *cont) +{ + int fd = -1; + int fop_ret; + struct flock lock; + int lock_state = -1; + int write_len; + int ret = 0; + + fd = open(path, O_RDWR|O_CREAT, 0644); + if (fd< 0) { + CU_DEBUG("Unable to open [%s], it does not exist.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + lock_state = fcntl(fd, F_SETLK,&lock); + if (lock_state< 0) { + CU_DEBUG("Failed to lock file [%s], it may be locked by other.", path); + ret = ERR_FILE_LOCK_FAIL; + goto out; + } + + if (ftruncate(fd, 0) != 0) { + CU_DEBUG("file [%s] Unable to truncate it", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + write_len = strlen(cont); + if (write_len> 0) { + lseek(fd, 0, SEEK_SET); + CU_DEBUG("writing file [%s] for %d bytes with offset 0," + " cont is :\n%s\n", + path, write_len, cont); + fop_ret = write(fd, cont, write_len); + } + ret = 1; + + out: + if (fd>= 0) { + if (lock_state>= 0) { + lock.l_type = F_UNLCK; + fcntl(fd, F_SETLK,&lock); + } + close(fd); + } + return ret; +} + +int configure_file_remove(const char *path) +{ + int fd_ret; + int ret = 0; + if (access(path, F_OK) == 0) { + CU_DEBUG("Deleting %s.", path); + fd_ret = remove(path); + if (fd_ret != 0) { + CU_DEBUG("failed to remove %s.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + } + + ret = 1; + out: + return ret; +} + +FILE *pipe_excute_command_type_read(char *cmd, const int buf_size, + const char *type, int *errno) +{ + FILE *stream = NULL; + char *suffix = PIPE_CMD_SUFFIX; + if ((strlen(cmd) + strlen(suffix))>= buf_size) { + CU_DEBUG("cmd [%s] is too long to append the suffix", cmd); + *errno = ERR_COMMAND_NO_READY; + goto out; + } + strcat(cmd, suffix); + CU_DEBUG("excuting readonly cmd [%s].", cmd); + stream = popen(cmd, type); + if (stream == NULL) { + CU_DEBUG("Failed to open pipe to run command"); + *errno = ERR_COMMAND_PIPE_ERR; + } + +out: + return stream; +} + +FILE *pipe_excute_command_type_write(char *cmd, const int buf_size, + const char *type, int *errno) +{ + FILE *stream = NULL; + char *suffix = PIPE_CMD_SUFFIX; + if ((strlen(cmd) + strlen(suffix))>= buf_size) { + CU_DEBUG("cmd [%s] is too long to append the suffix", cmd); + *errno = ERR_COMMAND_NO_READY; + goto out; + } + strcat(cmd, suffix); + CU_DEBUG("excuting system modification cmd [%s].", cmd); + stream = popen(cmd, type); + if (stream == NULL) { + CU_DEBUG("Failed to open pipe to run command"); + *errno = ERR_COMMAND_PIPE_ERR; + } + usleep(10000); + +out: + return stream; +} + +int get_host_linux_version(void) +{ + FILE *stream = NULL; + char cmd[64]; + char buff[256]; + int linenum; + int errno; + + if (g_linux_version != LINUX_UNKNOWN) { + goto out; + } + + cmd[0] = '\0'; + strcat(cmd, "lsb_release -a"); + stream = pipe_excute_command_type_read(cmd, sizeof(cmd), "r",&errno); + if (stream == NULL) { + goto out; + } + + linenum = -1; + g_linux_version = LINUX_OTHER; + while (fgets(buff, 256, stream) != NULL) { + linenum++; + if (linenum == 0) { + if (NULL == strstr(buff, "LSB")) { + CU_DEBUG("ERR: unable to get linux distribution version."); + g_linux_version = LINUX_FAIL_TO_GET; + } + } + if ((NULL != strstr(buff, "Red Hat")) || + (NULL != strstr(buff, "RedHat"))) { + g_linux_version = LINUX_REDHAT; + break; + } + } + + out: + if (stream != NULL) { + pclose(stream); + } + return g_linux_version; +} + +char *translate_error_no(int errno) +{ + char *ret = NULL; + switch (errno) { + case ERR_REQUEST_NOT_SUPPORT: + ret = "request is not supported now"; + break; + + case ERR_COMMAND_NOT_SET: + ret = "command is not set."; + break; + case ERR_COMMAND_PIPE_ERR: + ret = "failed in creating pipe to execute the command."; + break; + case ERR_COMMAND_NOT_SUPPORT: + ret = "command is not found, check u environment."; + break; + case ERR_COMMAND_NO_PERMISSION: + ret = "not enough authority to execute the command."; + break; + case ERR_COMMAND_NO_READY: + ret = "failed to build up the command line, check your input, " + "maybe it is too long."; + break; + case ERR_COMMAND_PARAMETER_WRONG: + ret = "got invalid paramenter, check your input."; + break; + case ERR_COMMAND_EXECUTION: + ret = "error happened in the excution of command."; + break; + + case ERR_DEVICE_EXCEED_MAXNUM: + ret = "too many devices found or set, check the environment."; + break; + case ERR_DEVICE_EXIST: + ret = "device already exist, can not execute the command."; + break; + case ERR_DEVICE_NOT_EXIST: + ret = "device do not exist, can not execute the command."; + break; + case ERR_DEVICE_ALREADY_DONE: + ret = "the operation you want have been done before, " + "will not do it again."; + break; + case ERR_DEVICE_CONNECT_OTHER: + ret = "the device you want to connect have been connect to another" + " device, can't change it directly."; + break; + + case ERR_FILE_OP_FAIL: + ret = "failed in accessing the file."; + break; + case ERR_FILE_EMPTY: + ret = "the file it want is empty."; + break; + case ERR_FILE_TOO_LARGE: + ret = "the file it want is too large."; + break; + case ERR_FILE_CONT_TOO_LARGE: + ret = "the content it want to combine to file is too large."; + break; + case ERR_FILE_LOCK_FAIL: + ret = "failed in locking the file, " + "check if other process is using it."; + break; + + case ERR_PERSIST_NOT_REDHAT: + ret = "host is not a RedHat distribution, can't persist the " + "configuration, it would not take effect after host is " + "rebooted. Other version would be supported in the future. " + "If you are sure host is RedHat, make sure command " + "<lsb_release -a> could work."; + break; + + default: + ret = "internal error."; + break; + } + return ret; +} diff --git a/libxkutil/host_network_helper.h b/libxkutil/host_network_helper.h new file mode 100644 index 0000000..a232221 --- /dev/null +++ b/libxkutil/host_network_helper.h @@ -0,0 +1,192 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia<xiawenc@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. + */ + + +#ifndef HOST_NETWORK_HELPER_H +#define HOST_NETWORK_HELPER_H + +#include<stdio.h> +#include<stdlib.h> +#include<arpa/inet.h> + +#include "host_network_basic.h" + +#ifdef TESTLIB +#include "TestDefines.h" +#else +#include<libcmpiutil/libcmpiutil.h> +#endif + +#define LINUX_FAIL_TO_GET -2 +#define LINUX_UNKNOWN -1 +#define LINUX_OTHER 0 +#define LINUX_REDHAT 1 + +#define CMD_DEBUG_LEVEL 2 + +/* macro functions */ +#define CMD_DEBUG(lvl, fmt, args...) do { \ + if (CMD_DEBUG_LEVEL&& (lvl)<= CMD_DEBUG_LEVEL) { \ + debug_print(fmt, ##args); \ + } \ +} while (0) + +#define SAFE_MALLOC(p, size) \ +{ \ + (p) = malloc((size)); \ + if ((p) == NULL) { \ + CU_DEBUG("malloc failed."); \ + } \ +} + +#define SAFE_CALLOC(p, nmen, size) \ +{ \ + (p) = calloc((nmen), (size)); \ + if ((p) == NULL) { \ + CU_DEBUG("calloc failed."); \ + } \ +} + +#define SAFE_FREE(p) {free(p); (p) = NULL; } + + +/* Macro used to compare two char*, it would skip if ref is NULL. It would + only set the result when src != ref, user need to set the result to 1 by + default before use the macro. If not set, the it could be used to do + check multi times in "one fail all die" mode. Empty lines is the place + where result should be set to 1. */ +#define CHARS_COMPARE_BY_REF(src, ref, result) do { \ + if ((ref) == NULL) { \ + ; \ + } else { \ + if ((src) == NULL) { \ + (result) = 0; \ + } else { \ + if (0 == strcmp((src), (ref))) { \ + ; \ + } else { \ + (result) = 0; \ + } \ + } \ + } \ +} while (0) + +#define CHARS_COMPARE_CASE_BY_REF(src, ref, result) do { \ + if ((ref) == NULL) { \ + ; \ + } else { \ + if ((src) == NULL) { \ + (result) = 0; \ + } else { \ + if (0 == strcasecmp((src), (ref))) { \ + ; \ + } else { \ + (result) = 0; \ + } \ + } \ + } \ +} while (0) + +#define NUM_COMPARE_BY_REF(src, ref, result, default) do { \ + if ((ref) == (default)) { \ + ; \ + } else { \ + if ((src) == (ref)) { \ + ; \ + } else { \ + result = 0; \ + } \ + } \ +} while (0) + +#define CHARS_MERGE_NORMAL(dest, src) do { \ + if (((dest) == NULL)&& ((src) != NULL)) { \ + (dest) = strdup((src)); \ + } \ +} while (0) + +#define CHARS_MERGE_MOVE(dest, src) do { \ + if (((dest) == NULL)&& ((src) != NULL)) { \ + (dest) = (src); \ + (src) = NULL; \ + } \ +} while (0) + +#define NUM_MERGE(dest, src, default) do { \ + if ((dest) == (default)) { \ + (dest) = (src); \ + } \ +} while (0) + +/* this macro may cause "p" to be excuted twice if it is a function */ +#define SAFE_STRDUP(p) (p) == NULL ? NULL : strdup(p); + +/* this macro make sure "src" to be excuted once if it is function, so it is + safe for functions that have state logged, such as "strtok" */ +#define SAFE_STRDUP_WITH_FUNC(dest, src, iter) do { \ + (iter) = (src); \ + if ((iter) == NULL) { \ + (dest) = NULL; \ + } else { \ + (dest) = strdup((iter)); \ + } \ +} while (0) + +#define SAFE_PSTR_ARRAY_DUP(ppdest, dest_num, ppsrc, src_num, iter) do { \ + (dest_num) = (src_num); \ + (ppdest) = NULL; \ + if (((ppsrc) != NULL)&& ((src_num)> 0)) { \ + SAFE_CALLOC((ppdest), (src_num), sizeof(char *)); \ + (iter) = 0; \ + while ((iter)< (src_num)) { \ + *((ppdest)+(iter)) = SAFE_STRDUP(*((ppsrc)+(iter))); \ + (iter)++; \ + } \ + } \ +} while (0) + +/* functions */ +/* this function convert ip mask "24" in "192.1.0.9/24" to real mask num as + 255.255.255.0 */ +int netmask_easy_to_inaddr(struct in_addr *paddr, const char *pmask); + +/* this function would sort the pqos and check its values. */ +int vlan_8021q_qos_check_valid(VLAN_Qos_8021q *pqos); + +/* converting qos string of 802.1.Q, it should be as "0:0 1:0 2:0" */ +int vlan_8021q_qos_str_to_num(VLAN_Qos_8021q *pqos, const char *str); +int vlan_8021q_qos_num_to_str(char **str, const VLAN_Qos_8021q *pqos); + +/* following functions would return FILE popened, so it need pclose later, + cmd would be appended so it must be writable. */ +FILE *pipe_excute_command_type_read(char *cmd, const int buf_size, + const char *type, int *errno); +FILE *pipe_excute_command_type_write(char *cmd, const int buf_size, + const char *type, int *errno); + +/* following functions would return string by malloc, so it need free later */ +char *strtok_onetime(const char *str, const char *delim); +char *combine_file_name(const char *prefix, const char *name); + +/* write the configuration file */ +int configure_file_update(const char *path, const char *cont); +/* remove the configuration file */ +int configure_file_remove(const char *path); +/* replace one attribute, the file have format with one line for one propety */ +int configure_file_replace_attr(const char *path, const char *prefix, + const char *prop); + +int get_host_linux_version(void); + +char *translate_error_no(int errno); + +#endif
-- Best Regards Wayne Xia mail:xiawenc@linux.vnet.ibm.com tel:86-010-82450803

On 12/30/2011 05:29 AM, Wayne Xia wrote:
于 2011-12-24 4:18, Chip Vincent 写道:
On 12/07/2011 04:25 AM, Wayne Xia wrote:
this is the helper function for the lib.
Signed-off-by: Wayne Xia<xiawenc@linux.vnet.ibm.com> --- libxkutil/host_network_error.h | 28 ++ libxkutil/host_network_helper.c | 659 +++++++++++++++++++++++++++++++++++++++ libxkutil/host_network_helper.h | 192 ++++++++++++ 3 files changed, 879 insertions(+), 0 deletions(-) create mode 100644 libxkutil/host_network_error.h create mode 100644 libxkutil/host_network_helper.c create mode 100644 libxkutil/host_network_helper.h
diff --git a/libxkutil/host_network_error.h b/libxkutil/host_network_error.h new file mode 100644 index 0000000..d809033 --- /dev/null +++ b/libxkutil/host_network_error.h @@ -0,0 +1,28 @@ +#ifndef HOST_NETWORK_ERROR_H +#define HOST_NETWORK_ERROR_H + +#define ERR_REQUEST_NOT_SUPPORT -1 + +#define ERR_COMMAND_NOT_SET -11 +#define ERR_COMMAND_PIPE_ERR -12 +#define ERR_COMMAND_NOT_SUPPORT -13 +#define ERR_COMMAND_NO_PERMISSION -14 +#define ERR_COMMAND_NO_READY -15 +#define ERR_COMMAND_PARAMETER_WRONG -16 +#define ERR_COMMAND_EXECUTION -17 + +#define ERR_DEVICE_EXCEED_MAXNUM -100 +#define ERR_DEVICE_EXIST -101 +#define ERR_DEVICE_NOT_EXIST -102 +#define ERR_DEVICE_ALREADY_DONE -103 +#define ERR_DEVICE_CONNECT_OTHER -104 + +#define ERR_FILE_OP_FAIL -125 +#define ERR_FILE_EMPTY -126 +#define ERR_FILE_TOO_LARGE -127 +#define ERR_FILE_CONT_TOO_LARGE -128 +#define ERR_FILE_LOCK_FAIL -129 + +#define ERR_PERSIST_NOT_REDHAT -200 Any particular reason for negative numbers?
No, just a custom to use negative number indicating errors. Is that bad? I would not say bad, just odd looking to me. In general, we've not had this level of detail in return codes thus far. IIRC, you're using these as "extended" error codes via errorno, so the caller can get more detail if the API returns an unexpected result. With that in mind, I don't have an objection.
+ +#endif diff --git a/libxkutil/host_network_helper.c b/libxkutil/host_network_helper.c new file mode 100644 index 0000000..dc9f775 --- /dev/null +++ b/libxkutil/host_network_helper.c @@ -0,0 +1,659 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia<xiawenc@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. + */ + + + +#include<string.h> +#include<sys/types.h> +#include<sys/stat.h> +#include<unistd.h> +#include<fcntl.h> + +#include "host_network_helper.h" +#include "host_network_error.h" + +#define CONFIGURE_FILE_MAX_SIZE 2048 + +#define PIPE_CMD_SUFFIX " 2>&1" + +static int g_linux_version = LINUX_UNKNOWN; I assume this is needed because the parse output varies?
Tried some version, it seems the output was almost the same, but persisting of configuration was linux distribution depending.
+ +static int compare_qos_8021q(const void *p1, const void *p2) +{ + const VLAN_Qos_8021q_elem *qos1 = (VLAN_Qos_8021q_elem *)p1; + const VLAN_Qos_8021q_elem *qos2 = (VLAN_Qos_8021q_elem *)p2; + int ret = 0; + if ((qos1->from)> (qos2->from)) { + ret = 1; + } + return ret; +} + +/* it need to be checked see whether these are the conditions */ +int vlan_8021q_qos_check_valid(VLAN_Qos_8021q *pqos) +{ + int ret = 1; + int i = 0; + int last_num = -1; + if ((pqos->count< 0) || (pqos->count> 8)) { + ret = 0; + goto out; + } else if (pqos->count == 0) { + goto out; + } + qsort((void *)pqos->values, pqos->count, sizeof(VLAN_Qos_8021q_elem), + compare_qos_8021q); + + while (i< pqos->count) { + if (pqos->values[i].from == last_num) { + CU_DEBUG("error: vlan 802.1.q qos setting have same<from> values: " + "last is %d, new is %d", last_num, pqos->values[i].from); + ret = 0; + goto out; + } + last_num = pqos->values[i].from; + if ((pqos->values[i].from< 0) || (pqos->values[i].from>= 8)) { + CU_DEBUG("error: vlan 802.1.q qos setting have outbound value: " + "from is %d.", pqos->values[i].from); + ret = 0; + goto out; + } + if ((pqos->values[i].to< 0) || (pqos->values[i].to>= 8)) { + CU_DEBUG("error: vlan 802.1.q qos setting have outbound value: " + "to is %d.", pqos->values[i].to); + ret = 0; + goto out; + } + i++; + } + + out: + return ret; +} + +int vlan_8021q_qos_str_to_num(VLAN_Qos_8021q *pqos, const char* str) +{ + int ret = 1; + char *str_line = NULL; + char *temp; + char *saveptr = NULL; + char *invalptr1, *invalptr2; + int qos_num1, qos_num2; + VLAN_Qos_8021q qos; + + if (str == NULL) { + ret = 0; + goto out; + } + if (str[0] == '\0') { + ret = 1; + pqos->count = 0; + CU_DEBUG("empty vlan 802.1.q qos string found."); + goto out; + } + str_line = SAFE_STRDUP(str); + qos.count = 0; + + temp = strtok_r(str_line, " ",&saveptr); + while (temp != NULL) { + qos_num1 = strtol(temp,&invalptr1, 10); + if (temp == invalptr1) { + ret = 0; + goto out; + } + if (*invalptr1 != ':') { + ret = 0; + goto out; + } + invalptr1++; + qos_num2 = strtol(invalptr1,&invalptr2, 10); + if (invalptr1 == invalptr2) { + ret = 0; + goto out; + } + if (*invalptr2 != '\0') { + ret = 0; + goto out; + } + if (qos.count>= 8) { + ret = 0; + CU_DEBUG("too many settings found in vlan 802.1.q qos string [%s]", + str); + goto out; + } + qos.values[qos.count].from = qos_num1; + qos.values[qos.count].to = qos_num2; + qos.count++; + temp = strtok_r(NULL, " ",&saveptr); + } + ret = vlan_8021q_qos_check_valid(&qos); + if (ret == 1) { + *pqos = qos; + } + + out: + if (ret != 1) { + CU_DEBUG("vlan 802.1.q qos string [%s] is invalid.", str); + } + SAFE_FREE(str_line); + return ret; +} + +int vlan_8021q_qos_num_to_str(char **str, const VLAN_Qos_8021q *pqos) +{ + char temp[16]; + int i; + VLAN_Qos_8021q qos = *pqos; + int ret = vlan_8021q_qos_check_valid(&qos); + if (ret != 1) { + goto out; + } + SAFE_MALLOC(*str, 64); + *str[0] = '\0'; + if (qos.count == 0) { + goto out; + } + i = 0; + snprintf(temp, sizeof(temp), "%d:%d", + qos.values[i].from, qos.values[i].to); + strcat(*str, temp); + i++; + while (i< qos.count) { + strcat(*str, " "); + snprintf(temp, sizeof(temp), "%d:%d", + qos.values[i].from, qos.values[i].to); + strcat(*str, temp); + i++; + } + + out: + return ret; +} + +int netmask_easy_to_inaddr(struct in_addr *paddr, const char* pmask) +{ + long mask_one_num = -1; + unsigned char *p; + int bitnum; + + mask_one_num = strtol(pmask, NULL, 10); + if ((mask_one_num< 0) || (mask_one_num> 32)) { + return 0; + } + + /* use network byte order */ + p = (unsigned char *)&paddr->s_addr; + memset(p, 0, 4); + while (mask_one_num> 8) { + *(p++) = 255; + mask_one_num -= 8; + } + bitnum = 7; + while (mask_one_num> 0) { + *p = *p + (1<<bitnum); + mask_one_num--; + bitnum--; + } + return 1; +} + +char *strtok_onetime(const char *str, const char *delim) +{ + char *t = strstr(str, delim); + char *ret_char; + int len; + if (t == NULL) { + return NULL; + } + len = t - str; + if (len<= 0) { + return NULL; + } + SAFE_MALLOC(ret_char, len+1); + strncpy(ret_char, str, len); + ret_char[len] = '\0'; + + return ret_char; +} + +char *combine_file_name(const char *prefix, const char *name) +{ + char *ret = NULL; + int size; + size = strlen(prefix) + strlen(name) + 1; + SAFE_CALLOC(ret, size, sizeof(char)); + snprintf(ret, size, "%s%s", prefix, name); + return ret; +} + +/* return the whole content length that need update. The data length keep + unchanged in the head part is returned in *unchanged_len which could be + used to avoid write whole data later. + requriement: cont must contain end character, prefix must be not NULL */ +static int replace_prop_str(char *cont, const int maxsize, const char *prefix, + const char *prop, int *unchanged_len) +{ + int target_len, origin_len; + int cont_len; + int valid_len = 0; + int prefix_len, prop_len = 0; + char *endchar1 = "\n"; + char *pprop_start, *pprop_end; + int head_len; + + cont_len = strlen(cont); + head_len = cont_len; + prefix_len = strlen(prefix); + if ((prop == NULL) || (*prop == '\0')) { + /* want the property removed */ + target_len = 0; + } else { + /* want the property changed */ + prop_len = strlen(prop); + target_len = prefix_len + prop_len; + } + + pprop_start = strstr(cont, prefix); + if (pprop_start == NULL) { + /* the content do not exist in original contents */ + if (target_len> 0) { + /* add the property */ + if ((cont_len + target_len)>= maxsize) { + CU_DEBUG("buffer is too small for the operation."); + valid_len = -1; + goto out; + } + strcat(cont, prefix); + strcat(cont, prop); + valid_len = cont_len + target_len; + } else { + /* remove the property, but it do not exist, so skip */ + } + } else { + /* the content exist in original contents */ + /* locate the end of the property */ + pprop_end = strstr(pprop_start, endchar1); + if (pprop_end == NULL) { + /* last line */ + origin_len = strlen(pprop_start); + pprop_end = cont+cont_len; + } else { + origin_len = pprop_end - pprop_start; + } + if (target_len> 0) { + /* change the property */ + /* check the bound */ + if ((cont_len + target_len - origin_len)>= maxsize) { + CU_DEBUG("buffer is too small for the operation."); + valid_len = -1; + goto out; + } + /* move contents in the tail */ + memmove(pprop_end+target_len-origin_len, pprop_end, + cont+cont_len+1-pprop_end); + /* copy the content of the new string */ + memcpy(pprop_start+prefix_len, prop, prop_len); + head_len = pprop_start - cont + prefix_len; + } else { + /* remove the property */ + /* move contents in the tail to replace original string*/ + memmove(pprop_end+target_len-origin_len, pprop_end, + cont+cont_len+1-pprop_end); + head_len = pprop_start - cont; + } + valid_len = cont_len + target_len - origin_len; + } + + out: + if (unchanged_len != NULL) { + *unchanged_len = head_len; + } + return valid_len; +} + +int configure_file_replace_attr(const char *path, const char *prefix, + const char *prop) +{ + int fd = -1; + int fop_ret; + struct stat s; + struct flock lock; + int lock_state = -1; + char *cont = NULL; + char *pbuff; + int write_len; + int cont_len_update; + int cont_len_unchanged; + int ret = 0; + + if ((prefix == NULL) || (*prefix == '\0')) { + CU_DEBUG("no prefix for property set, could not replace the content."); + goto out; + } + + fd = open(path, O_RDWR, 0644); + if (fd< 0) { + CU_DEBUG("Unable to open [%s], it does not exist.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + lock_state = fcntl(fd, F_SETLK,&lock); + if (lock_state< 0) { + CU_DEBUG("Failed to lock file [%s], it may be locked by other.", path); + ret = ERR_FILE_LOCK_FAIL; + goto out; + } + + fstat(fd,&s); + if (s.st_size == 0) { + CU_DEBUG("file [%s] is empty, will not replace attr for it.", path); + ret = ERR_FILE_EMPTY; + goto out; + } else if (s.st_size>= CONFIGURE_FILE_MAX_SIZE) { + CU_DEBUG("file [%s] is too large, " + "it have %lld bytes, will not read it.", + path, (long long)s.st_size); + ret = ERR_FILE_TOO_LARGE; + goto out; + } + + SAFE_MALLOC(cont, CONFIGURE_FILE_MAX_SIZE); + lseek(fd, 0, SEEK_SET); + fop_ret = read(fd, cont, s.st_size); + cont[s.st_size] = '\0'; + cont_len_update = replace_prop_str(cont, CONFIGURE_FILE_MAX_SIZE, + prefix, prop,&cont_len_unchanged); + if (cont_len_update< 0) { + CU_DEBUG("file [%s] is too big to expand it with [%s%s].", + path, prefix, prop); + ret = ERR_FILE_TOO_LARGE; + goto out; + } else if (cont_len_update == 0) { + CU_DEBUG("the contents was not changed, do not need update it"); + ret = 1; + goto out; + } else { + if (ftruncate(fd, cont_len_unchanged) != 0) { + CU_DEBUG("file [%s] Unable to truncate it", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + write_len = cont_len_update-cont_len_unchanged; + if (write_len> 0) { + lseek(fd, cont_len_unchanged, SEEK_SET); + CU_DEBUG("writing file [%s] for %d bytes with offset %d," + " cont is :\n%s\n", + path, write_len, cont_len_unchanged, cont); + pbuff = cont+cont_len_unchanged; + fop_ret = write(fd, pbuff, write_len); + } + } + ret = 1; + + out: + if (fd>= 0) { + if (lock_state>= 0) { + lock.l_type = F_UNLCK; + fcntl(fd, F_SETLK,&lock); + } + close(fd); + } + SAFE_FREE(cont); + return ret; +} + +int configure_file_update(const char *path, const char *cont) +{ + int fd = -1; + int fop_ret; + struct flock lock; + int lock_state = -1; + int write_len; + int ret = 0; + + fd = open(path, O_RDWR|O_CREAT, 0644); + if (fd< 0) { + CU_DEBUG("Unable to open [%s], it does not exist.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + lock_state = fcntl(fd, F_SETLK,&lock); + if (lock_state< 0) { + CU_DEBUG("Failed to lock file [%s], it may be locked by other.", path); + ret = ERR_FILE_LOCK_FAIL; + goto out; + } + + if (ftruncate(fd, 0) != 0) { + CU_DEBUG("file [%s] Unable to truncate it", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + write_len = strlen(cont); + if (write_len> 0) { + lseek(fd, 0, SEEK_SET); + CU_DEBUG("writing file [%s] for %d bytes with offset 0," + " cont is :\n%s\n", + path, write_len, cont); + fop_ret = write(fd, cont, write_len); + } + ret = 1; + + out: + if (fd>= 0) { + if (lock_state>= 0) { + lock.l_type = F_UNLCK; + fcntl(fd, F_SETLK,&lock); + } + close(fd); + } + return ret; +} + +int configure_file_remove(const char *path) +{ + int fd_ret; + int ret = 0; + if (access(path, F_OK) == 0) { + CU_DEBUG("Deleting %s.", path); + fd_ret = remove(path); + if (fd_ret != 0) { + CU_DEBUG("failed to remove %s.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + } + + ret = 1; + out: + return ret; +} + +FILE *pipe_excute_command_type_read(char *cmd, const int buf_size, + const char *type, int *errno) +{ + FILE *stream = NULL; + char *suffix = PIPE_CMD_SUFFIX; + if ((strlen(cmd) + strlen(suffix))>= buf_size) { + CU_DEBUG("cmd [%s] is too long to append the suffix", cmd); + *errno = ERR_COMMAND_NO_READY; + goto out; + } + strcat(cmd, suffix); + CU_DEBUG("excuting readonly cmd [%s].", cmd); + stream = popen(cmd, type); + if (stream == NULL) { + CU_DEBUG("Failed to open pipe to run command"); + *errno = ERR_COMMAND_PIPE_ERR; + } + +out: + return stream; +} + +FILE *pipe_excute_command_type_write(char *cmd, const int buf_size, + const char *type, int *errno) +{ + FILE *stream = NULL; + char *suffix = PIPE_CMD_SUFFIX; + if ((strlen(cmd) + strlen(suffix))>= buf_size) { + CU_DEBUG("cmd [%s] is too long to append the suffix", cmd); + *errno = ERR_COMMAND_NO_READY; + goto out; + } + strcat(cmd, suffix); + CU_DEBUG("excuting system modification cmd [%s].", cmd); + stream = popen(cmd, type); + if (stream == NULL) { + CU_DEBUG("Failed to open pipe to run command"); + *errno = ERR_COMMAND_PIPE_ERR; + } + usleep(10000); + +out: + return stream; +} + +int get_host_linux_version(void) +{ + FILE *stream = NULL; + char cmd[64]; + char buff[256]; + int linenum; + int errno; + + if (g_linux_version != LINUX_UNKNOWN) { + goto out; + } + + cmd[0] = '\0'; + strcat(cmd, "lsb_release -a"); + stream = pipe_excute_command_type_read(cmd, sizeof(cmd), "r",&errno); + if (stream == NULL) { + goto out; + } + + linenum = -1; + g_linux_version = LINUX_OTHER; + while (fgets(buff, 256, stream) != NULL) { + linenum++; + if (linenum == 0) { + if (NULL == strstr(buff, "LSB")) { + CU_DEBUG("ERR: unable to get linux distribution version."); + g_linux_version = LINUX_FAIL_TO_GET; + } + } + if ((NULL != strstr(buff, "Red Hat")) || + (NULL != strstr(buff, "RedHat"))) { + g_linux_version = LINUX_REDHAT; + break; + } + } + + out: + if (stream != NULL) { + pclose(stream); + } + return g_linux_version; +} + +char *translate_error_no(int errno) +{ + char *ret = NULL; + switch (errno) { + case ERR_REQUEST_NOT_SUPPORT: + ret = "request is not supported now"; + break; + + case ERR_COMMAND_NOT_SET: + ret = "command is not set."; + break; + case ERR_COMMAND_PIPE_ERR: + ret = "failed in creating pipe to execute the command."; + break; + case ERR_COMMAND_NOT_SUPPORT: + ret = "command is not found, check u environment."; + break; + case ERR_COMMAND_NO_PERMISSION: + ret = "not enough authority to execute the command."; + break; + case ERR_COMMAND_NO_READY: + ret = "failed to build up the command line, check your input, " + "maybe it is too long."; + break; + case ERR_COMMAND_PARAMETER_WRONG: + ret = "got invalid paramenter, check your input."; + break; + case ERR_COMMAND_EXECUTION: + ret = "error happened in the excution of command."; + break; + + case ERR_DEVICE_EXCEED_MAXNUM: + ret = "too many devices found or set, check the environment."; + break; + case ERR_DEVICE_EXIST: + ret = "device already exist, can not execute the command."; + break; + case ERR_DEVICE_NOT_EXIST: + ret = "device do not exist, can not execute the command."; + break; + case ERR_DEVICE_ALREADY_DONE: + ret = "the operation you want have been done before, " + "will not do it again."; + break; + case ERR_DEVICE_CONNECT_OTHER: + ret = "the device you want to connect have been connect to another" + " device, can't change it directly."; + break; + + case ERR_FILE_OP_FAIL: + ret = "failed in accessing the file."; + break; + case ERR_FILE_EMPTY: + ret = "the file it want is empty."; + break; + case ERR_FILE_TOO_LARGE: + ret = "the file it want is too large."; + break; + case ERR_FILE_CONT_TOO_LARGE: + ret = "the content it want to combine to file is too large."; + break; + case ERR_FILE_LOCK_FAIL: + ret = "failed in locking the file, " + "check if other process is using it."; + break; + + case ERR_PERSIST_NOT_REDHAT: + ret = "host is not a RedHat distribution, can't persist the " + "configuration, it would not take effect after host is " + "rebooted. Other version would be supported in the future. " + "If you are sure host is RedHat, make sure command " + "<lsb_release -a> could work."; + break; + + default: + ret = "internal error."; + break; + } + return ret; +} diff --git a/libxkutil/host_network_helper.h b/libxkutil/host_network_helper.h new file mode 100644 index 0000000..a232221 --- /dev/null +++ b/libxkutil/host_network_helper.h @@ -0,0 +1,192 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia<xiawenc@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. + */ + + +#ifndef HOST_NETWORK_HELPER_H +#define HOST_NETWORK_HELPER_H + +#include<stdio.h> +#include<stdlib.h> +#include<arpa/inet.h> + +#include "host_network_basic.h" + +#ifdef TESTLIB +#include "TestDefines.h" +#else +#include<libcmpiutil/libcmpiutil.h> +#endif + +#define LINUX_FAIL_TO_GET -2 +#define LINUX_UNKNOWN -1 +#define LINUX_OTHER 0 +#define LINUX_REDHAT 1 + +#define CMD_DEBUG_LEVEL 2 + +/* macro functions */ +#define CMD_DEBUG(lvl, fmt, args...) do { \ + if (CMD_DEBUG_LEVEL&& (lvl)<= CMD_DEBUG_LEVEL) { \ + debug_print(fmt, ##args); \ + } \ +} while (0) + +#define SAFE_MALLOC(p, size) \ +{ \ + (p) = malloc((size)); \ + if ((p) == NULL) { \ + CU_DEBUG("malloc failed."); \ + } \ +} + +#define SAFE_CALLOC(p, nmen, size) \ +{ \ + (p) = calloc((nmen), (size)); \ + if ((p) == NULL) { \ + CU_DEBUG("calloc failed."); \ + } \ +} + +#define SAFE_FREE(p) {free(p); (p) = NULL; } + + +/* Macro used to compare two char*, it would skip if ref is NULL. It would + only set the result when src != ref, user need to set the result to 1 by + default before use the macro. If not set, the it could be used to do + check multi times in "one fail all die" mode. Empty lines is the place + where result should be set to 1. */ +#define CHARS_COMPARE_BY_REF(src, ref, result) do { \ + if ((ref) == NULL) { \ + ; \ + } else { \ + if ((src) == NULL) { \ + (result) = 0; \ + } else { \ + if (0 == strcmp((src), (ref))) { \ + ; \ + } else { \ + (result) = 0; \ + } \ + } \ + } \ +} while (0) + +#define CHARS_COMPARE_CASE_BY_REF(src, ref, result) do { \ + if ((ref) == NULL) { \ + ; \ + } else { \ + if ((src) == NULL) { \ + (result) = 0; \ + } else { \ + if (0 == strcasecmp((src), (ref))) { \ + ; \ + } else { \ + (result) = 0; \ + } \ + } \ + } \ +} while (0) + +#define NUM_COMPARE_BY_REF(src, ref, result, default) do { \ + if ((ref) == (default)) { \ + ; \ + } else { \ + if ((src) == (ref)) { \ + ; \ + } else { \ + result = 0; \ + } \ + } \ +} while (0) + +#define CHARS_MERGE_NORMAL(dest, src) do { \ + if (((dest) == NULL)&& ((src) != NULL)) { \ + (dest) = strdup((src)); \ + } \ +} while (0) + +#define CHARS_MERGE_MOVE(dest, src) do { \ + if (((dest) == NULL)&& ((src) != NULL)) { \ + (dest) = (src); \ + (src) = NULL; \ + } \ +} while (0) + +#define NUM_MERGE(dest, src, default) do { \ + if ((dest) == (default)) { \ + (dest) = (src); \ + } \ +} while (0) + +/* this macro may cause "p" to be excuted twice if it is a function */ +#define SAFE_STRDUP(p) (p) == NULL ? NULL : strdup(p); + +/* this macro make sure "src" to be excuted once if it is function, so it is + safe for functions that have state logged, such as "strtok" */ +#define SAFE_STRDUP_WITH_FUNC(dest, src, iter) do { \ + (iter) = (src); \ + if ((iter) == NULL) { \ + (dest) = NULL; \ + } else { \ + (dest) = strdup((iter)); \ + } \ +} while (0) + +#define SAFE_PSTR_ARRAY_DUP(ppdest, dest_num, ppsrc, src_num, iter) do { \ + (dest_num) = (src_num); \ + (ppdest) = NULL; \ + if (((ppsrc) != NULL)&& ((src_num)> 0)) { \ + SAFE_CALLOC((ppdest), (src_num), sizeof(char *)); \ + (iter) = 0; \ + while ((iter)< (src_num)) { \ + *((ppdest)+(iter)) = SAFE_STRDUP(*((ppsrc)+(iter))); \ + (iter)++; \ + } \ + } \ +} while (0) + +/* functions */ +/* this function convert ip mask "24" in "192.1.0.9/24" to real mask num as + 255.255.255.0 */ +int netmask_easy_to_inaddr(struct in_addr *paddr, const char *pmask); + +/* this function would sort the pqos and check its values. */ +int vlan_8021q_qos_check_valid(VLAN_Qos_8021q *pqos); + +/* converting qos string of 802.1.Q, it should be as "0:0 1:0 2:0" */ +int vlan_8021q_qos_str_to_num(VLAN_Qos_8021q *pqos, const char *str); +int vlan_8021q_qos_num_to_str(char **str, const VLAN_Qos_8021q *pqos); + +/* following functions would return FILE popened, so it need pclose later, + cmd would be appended so it must be writable. */ +FILE *pipe_excute_command_type_read(char *cmd, const int buf_size, + const char *type, int *errno); +FILE *pipe_excute_command_type_write(char *cmd, const int buf_size, + const char *type, int *errno); + +/* following functions would return string by malloc, so it need free later */ +char *strtok_onetime(const char *str, const char *delim); +char *combine_file_name(const char *prefix, const char *name); + +/* write the configuration file */ +int configure_file_update(const char *path, const char *cont); +/* remove the configuration file */ +int configure_file_remove(const char *path); +/* replace one attribute, the file have format with one line for one propety */ +int configure_file_replace_attr(const char *path, const char *prefix, + const char *prop); + +int get_host_linux_version(void); + +char *translate_error_no(int errno); + +#endif
-- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent@linux.vnet.ibm.com

this file use tools ip, brctl, ifconfig to provide the functionalities. Signed-off-by: Wayne Xia <xiawenc@linux.vnet.ibm.com> --- libxkutil/host_network_implement_cmdline.c | 2002 ++++++++++++++++++++++++++++ libxkutil/host_network_implement_cmdline.h | 55 + 2 files changed, 2057 insertions(+), 0 deletions(-) create mode 100644 libxkutil/host_network_implement_cmdline.c create mode 100644 libxkutil/host_network_implement_cmdline.h diff --git a/libxkutil/host_network_implement_cmdline.c b/libxkutil/host_network_implement_cmdline.c new file mode 100644 index 0000000..fc9226b --- /dev/null +++ b/libxkutil/host_network_implement_cmdline.c @@ -0,0 +1,2002 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia <xiawenc@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. + * + * Note: + * the string example used below is all reformed to avoid code format check + * errors, so it just says the command output format as a reference. + * char "tab" is changed to "space", tailing space is removed, lines over 80 + * characters was foldered. + */ + +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "host_network_implement_cmdline.h" +#include "host_network_helper.h" +#include "host_network_error.h" + +/* macro defines */ +#define COMMAND_NOTFOUND_STRING "command not found" +#define COMMAND_NOPERMISSION_STRING "Permission denied" +#define BRCTL_EXPECT_STRING "bridge name" +#define VLAN8021Q_CAT_ETH_EXPECT_STRING "REORDER_HDR:" +#define VLAN8021Q_CONFIG_EXPECT_STRING "VLAN Dev name" + +#define IFACE_CONFIG_FILE_PREFIX_RH "/etc/sysconfig/network-scripts/ifcfg-" + +#define CONT_BUFF_SIZE 256 + +/* the bridge seems have 0 value when it is up , so adjust the value, + and found out which are physical cards */ +static int host_iface_adjust(EthIface *piface) +{ + if (piface->eth_type == ETH_TYPE_BRIDGE) { + if (piface->run_prop.state == ETH_TYPE_UNKNOWN) { + piface->run_prop.state = ETH_STATE_UP; + } + } + if (1 == eth_iface_filter_peths(piface, NULL)) { + piface->eth_type = ETH_TYPE_PHYSICAL; + } + return 1; +} + +int host_ifacelist_is_present_cmd(EthIfacesList *plist, int *retvalues, + int compare_name_only) +{ + EthIfacesList ifaces_list; + int retvalue; + int i, j; + eth_iface_filter_func func; + + eth_ifaceslist_init(&ifaces_list); + retvalue = get_host_eth_ifaces_ip_addr(ifaces_list.pifaces, + &ifaces_list.count, MAX_IFACE_NUM, NULL, NULL); + if (retvalue != 1) { + goto out; + } + + if (compare_name_only == 0) { + func = eth_iface_filter_by_refname; + } else { + func = eth_iface_filter_by_ref; + } + i = 0; + while (i < plist->count) { + retvalues[i] = 0; + j = 0; + while (j < ifaces_list.count) { + if (1 == func(ifaces_list.pifaces[j], plist->pifaces[i])) { + retvalues[i] = 1; + break; + } + j++; + } + i++; + } + + out: + eth_ifaceslist_uninit(&ifaces_list); + return retvalue; +} + +static int host_iface_is_present_cmd(EthIface *piface) +{ + EthIface *pifaces[1]; + int retvalue; + int ifaces_num; + int exist_flag = 0; + EthIface ref; + eth_iface_init(&ref); + ref.name = SAFE_STRDUP(piface->name); + + retvalue = get_host_eth_ifaces_ip_addr(pifaces, &ifaces_num, + 1, eth_iface_filter_by_ref, &ref); + + if ((retvalue == 1) && (ifaces_num == 1)) { + exist_flag = 1; + } + eth_ifaces_clear(pifaces, ifaces_num); + eth_iface_uninit(&ref); + return exist_flag; +} + +static int host_br_is_present_cmd(EthIface *piface) +{ + EthIface *pifaces[1]; + int retvalue; + int ifaces_num; + int exist_flag = 0; + EthIface ref; + eth_iface_init(&ref); + ref.name = SAFE_STRDUP(piface->name); + + retvalue = get_host_eth_ifaces_brctl(pifaces, &ifaces_num, + 1, eth_iface_filter_by_ref, &ref); + + if ((retvalue == 1) && (ifaces_num == 1)) { + exist_flag = 1; + } + eth_ifaces_clear(pifaces, ifaces_num); + eth_iface_uninit(&ref); + return exist_flag; +} + +/* 1: the bridge have the iface attached + 2: the iface is attached to other bridge + other: not found */ +int host_br_have_iface_attached_cmd(EthIface *pbr, EthIface *piface, + EthIface **ppbr_result) +{ + int ret = 0; + BR_Prop *pbr_prop; + EthIface **pifaces = NULL; + int retvalue; + int ifaces_num = 0; + int i, j; + + if (0 == host_iface_is_present_cmd(piface)) { + return -1; + } + + SAFE_CALLOC(pifaces, MAX_IFACE_NUM, sizeof(EthIface *)); + + retvalue = get_host_eth_ifaces_brctl(pifaces, &ifaces_num, + MAX_IFACE_NUM, NULL, NULL); + + if ((retvalue == 1) && (ifaces_num > 0)) { + i = 0; + while (i < ifaces_num) { + if (0 == strcmp(pbr->name, pifaces[i]->name)) { + /* found the bridge */ + pbr_prop = pifaces[i]->pbr_prop; + j = 0; + while (j < pbr_prop->port_num) { + if (0 == strcmp(piface->name, pbr_prop->port_names[j])) { + ret = 1; + break; + } + j++; + } + if (ppbr_result != NULL) { + *ppbr_result = pifaces[i]; + pifaces[i] = NULL; + } + goto out; + } else { + /* not the bridge */ + pbr_prop = pifaces[i]->pbr_prop; + j = 0; + while (j < pbr_prop->port_num) { + if (0 == strcmp(piface->name, pbr_prop->port_names[j])) { + ret = 2; + goto out; + } + j++; + } + } + i++; + } + } else { + ret = -2; + } + + out: + if (pifaces != NULL) { + eth_ifaces_clear(pifaces, ifaces_num); + SAFE_FREE(pifaces); + } + return ret; +} + +static int host_vlan_is_present_8021q_cmd(EthIface *piface) +{ + EthIface *pifaces[1]; + int retvalue; + int ifaces_num; + int exist_flag = 0; + EthIface ref; + eth_iface_init(&ref); + ref.name = SAFE_STRDUP(piface->name); + + retvalue = get_host_eth_ifaces_cat_vlan_config(pifaces, &ifaces_num, + 1, eth_iface_filter_by_ref, &ref); + + if ((retvalue == 1) && (ifaces_num == 1)) { + exist_flag = 1; + } + eth_ifaces_clear(pifaces, ifaces_num); + eth_iface_uninit(&ref); + return exist_flag; +} + +int get_host_eth_ifaces_ip_addr(EthIface **ppifaces, int *retnum, int maxnum, + eth_iface_filter_func filter_func, void *filter_opaque) +{ + FILE *stream = NULL; + char cmd[64]; + char *buff = NULL; + int ret = 0; + EthIface tcard, **ppdest; + char *temp, *temp2, *temp3; + char *search_str; + int count = 0; + int filter_ret; + int line_count = 0; + struct in_addr addr; + + SAFE_MALLOC(buff, CONT_BUFF_SIZE); + cmd[0] = '\0'; + strcat(cmd, "ip addr"); + stream = pipe_excute_command_type_read(cmd, sizeof(cmd), "r", &ret); + if (stream == NULL) { + goto out; + } + + eth_iface_init(&tcard); + while (fgets(buff, CONT_BUFF_SIZE, stream) != NULL) { + CMD_DEBUG(3, "%s", buff); + if (line_count == 0) { + if (NULL != strstr(buff, COMMAND_NOTFOUND_STRING)) { + CU_DEBUG("Got [%s] with command [%s], check u environment.\n", + COMMAND_NOTFOUND_STRING, cmd); + ret = ERR_COMMAND_NOT_SUPPORT; + goto out; + } + if (NULL != strstr(buff, COMMAND_NOPERMISSION_STRING)) { + CU_DEBUG("Got [%s] with command [%s], check u environment.\n", + COMMAND_NOPERMISSION_STRING, cmd); + ret = ERR_COMMAND_NO_PERMISSION; + goto out; + } + } + line_count++; + /*analysis the output, example is something like following: + +3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc \ +pfifo_fast run_prop.state UP qlen 1000 + link/ether 08:00:27:e3:13:f8 brd ff:ff:ff:ff:ff:ff + inet 10.0.3.15/24 brd 10.0.3.255 scope global eth1 + inet6 fe80::a00:27ff:fee3:13f8/64 scope link + valid_lft forever preferred_lft forever +4: eth1.5@eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc \ +noqueue run_prop.state UP + link/ether 08:00:27:e3:13:f8 brd ff:ff:ff:ff:ff:ff + inet6 fe80::a00:27ff:fee3:13f8/64 scope link + valid_lft forever preferred_lft forever + + */ + /* for line that divide two devices */ + if ((0 != strncmp(buff, " ", 1)) && (0 != strncmp(buff, "\t", 1))) { + if (tcard.name != NULL) { + /* device found, copy the content */ + filter_ret = 1; + if (filter_func != NULL) { + filter_ret = filter_func(&tcard, filter_opaque); + } + /* found a device match the requirement, put it to the list */ + if (filter_ret == 1) { + if (count >= maxnum) { + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + ppdest = ppifaces + count; + SAFE_MALLOC(*ppdest, sizeof(EthIface)); + eth_iface_dup(*ppdest, &tcard); + count++; + } + eth_iface_uninit(&tcard); + eth_iface_init(&tcard); + } + /* discovery names */ + search_str = ": "; + temp = strstr(buff, search_str); + if (temp != NULL) { + temp += strlen(search_str); + temp2 = strstr(temp, search_str); + if (temp2 != NULL) { + /* found string that contains names, + start point is temp, end point is temp2 */ + search_str = "@"; + temp3 = strstr(temp, search_str); + if ((temp3 != NULL) && (temp3 < temp2)) { + /* have parent dev, temp3 holds the division */ + SAFE_FREE(tcard.dep_ifname); + tcard.dep_ifname = strndup(temp3+1, temp2-temp3-1); + SAFE_FREE(tcard.name); + tcard.name = strndup(temp, temp3-temp); + } else { + SAFE_FREE(tcard.name); + tcard.name = strndup(temp, temp2-temp); + } + } + } + /* discovery run_prop.state */ + search_str = "state "; + temp = strstr(buff, search_str); + if (temp != NULL) { + temp += strlen(search_str); + if (0 == strncmp(temp, "UP", 2)) { + tcard.run_prop.state = ETH_STATE_UP; + } else if (0 == strncmp(temp, "DOWN", 4)) { + tcard.run_prop.state = ETH_STATE_DOWN; + } else if (0 == strncmp(temp, "UNKNOWN", 7)) { + tcard.run_prop.state = ETH_STATE_UNKNOWN; + } + } + continue; + } + /* for lines that saying other properties */ + /* dicovering mac */ + search_str = "ether "; + temp = strstr(buff, search_str); + if (temp != NULL) { + temp += strlen(search_str); + SAFE_FREE(tcard.mac); + tcard.mac = strtok_onetime(temp, " "); + } + /* dicovering ip and ip_mask for ipv4 */ + search_str = "inet "; + temp = strstr(buff, search_str); + if (temp != NULL) { + temp += strlen(search_str); + temp2 = strstr(temp, "/"); + if (temp2 != NULL) { + /* found the ip and mask, temp2 holds the division */ + SAFE_FREE(tcard.ipv4_prop.ip); + tcard.ipv4_prop.ip = strndup(temp, temp2-temp); + if (1 == netmask_easy_to_inaddr(&addr, temp2+1)) { + SAFE_FREE(tcard.ipv4_prop.ip_mask); + SAFE_MALLOC(tcard.ipv4_prop.ip_mask, INET_ADDRSTRLEN); + tcard.ipv4_prop.ip_mask[INET_ADDRSTRLEN-1] = '\0'; + if (NULL == inet_ntop(AF_INET, &addr, + tcard.ipv4_prop.ip_mask, INET_ADDRSTRLEN)) { + SAFE_FREE(tcard.ipv4_prop.ip_mask); + } + } + } + } + } + + /* because the output have no indication about end, so need to try add + the latest device found to the list */ + if (tcard.name != NULL) { + /* device found, copy the content */ + filter_ret = 1; + if (filter_func != NULL) { + filter_ret = filter_func(&tcard, filter_opaque); + } + /* found a device match the requirement, put it to the list */ + if (filter_ret == 1) { + if (count >= maxnum) { + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + ppdest = ppifaces + count; + SAFE_MALLOC(*ppdest, sizeof(EthIface)); + eth_iface_dup(*ppdest, &tcard); + count++; + } + } + + ret = 1; + + out: + if (stream != NULL) { + pclose(stream); + } + eth_iface_uninit(&tcard); + SAFE_FREE(buff); + *retnum = count; + + return ret; +} + +int get_host_eth_ifaces_ifconfig(EthIface **ppifaces, int *retnum, int maxnum, + eth_iface_filter_func filter_func, void *filter_opaque) +{ + FILE *stream = NULL; + char cmd[64]; + char *buff = NULL; + int ret = 0; + EthIface tcard, **ppdest; + char *temp, *temp2; + char *search_str; + int count = 0; + int filter_ret; + int line_count = 0; + + SAFE_MALLOC(buff, CONT_BUFF_SIZE); + cmd[0] = '\0'; + strcat(cmd, "ifconfig"); + stream = pipe_excute_command_type_read(cmd, sizeof(cmd), "r", &ret); + if (stream == NULL) { + goto out; + } + + eth_iface_init(&tcard); + while (fgets(buff, CONT_BUFF_SIZE, stream) != NULL) { + CMD_DEBUG(3, "%s", buff); + if (line_count == 0) { + if (NULL != strstr(buff, COMMAND_NOTFOUND_STRING)) { + CU_DEBUG("Got [%s] with command [%s], check u environment.\n", + COMMAND_NOTFOUND_STRING, cmd); + ret = ERR_COMMAND_NOT_SUPPORT; + goto out; + } + if (NULL != strstr(buff, COMMAND_NOPERMISSION_STRING)) { + CU_DEBUG("Got [%s] with command [%s], check u environment.\n", + COMMAND_NOPERMISSION_STRING, cmd); + ret = ERR_COMMAND_NO_PERMISSION; + goto out; + } + } + line_count++; + /*analysis the output, example is something like following: + +eth1 Link encap:Ethernet HWaddr 08:00:27:E3:13:F8 + inet addr:10.0.3.15 Bcast:10.0.3.255 Mask:255.255.255.0 + inet6 addr: fe80::a00:27ff:fee3:13f8/64 Scope:Link + UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 + RX packets:236 errors:0 dropped:0 overruns:0 frame:0 + TX packets:346 errors:0 dropped:0 overruns:0 carrier:0 + collisions:0 txqueuelen:1000 + RX bytes:100464 (98.1 KiB) TX bytes:30721 (30.0 KiB) + +eth1.5 Link encap:Ethernet HWaddr 08:00:27:E3:13:F8 + ... + + */ + /* for line that divide two devices */ + if (0 == strncmp(buff, "\n", 1)) { + /* device found, copy the content */ + filter_ret = 1; + if (filter_func != NULL) { + filter_ret = filter_func(&tcard, filter_opaque); + } + /* found a device match the requirement, put it to the list */ + if (filter_ret == 1) { + if (count >= maxnum) { + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + ppdest = ppifaces + count; + SAFE_MALLOC(*ppdest, sizeof(EthIface)); + eth_iface_dup(*ppdest, &tcard); + count++; + } + eth_iface_uninit(&tcard); + eth_iface_init(&tcard); + continue; + } + /* for line that saying other properties */ + if (0 == strncmp(buff, " ", 1)) { + /* discovery ip for ip v4 */ + search_str = "inet addr:"; + temp = strstr(buff, search_str); + if (temp != NULL) { + temp += strlen(search_str); + SAFE_FREE(tcard.ipv4_prop.ip); + tcard.ipv4_prop.ip = strtok_onetime(temp, " "); + /* discovery ip mask*/ + search_str = "Mask"; + temp = strstr(buff, search_str); + if (temp != NULL) { + temp += strlen(search_str); + SAFE_FREE(tcard.ipv4_prop.ip_mask); + tcard.ipv4_prop.ip_mask = strtok_onetime(temp, " "); + if (tcard.ipv4_prop.ip_mask == NULL) { + tcard.ipv4_prop.ip_mask = strtok_onetime(temp, "\n"); + } + } + } + + /* discovery RX and TX bytes */ + search_str = "RX bytes:"; + temp = strstr(buff, search_str); + if (temp != NULL) { + temp += strlen(search_str); + tcard.run_prop.rx_bytes = strtoll(temp, &temp2, 10); + if (temp == temp2) { + /*failed to get the value, restore it to default */ + tcard.run_prop.rx_bytes = NUM_NOT_GOT; + } + search_str = "TX bytes:"; + temp = strstr(buff, search_str); + if (temp != NULL) { + temp += strlen(search_str); + tcard.run_prop.tx_bytes = strtoll(temp, &temp2, 10); + if (temp == temp2) { + /*failed to get the value, restore it to default */ + tcard.run_prop.tx_bytes = NUM_NOT_GOT; + } + } + } + continue; + } + /* for lines that saying the device with title */ + /* discovery name */ + SAFE_FREE(tcard.name); + tcard.name = strtok_onetime(buff, " "); + /* discovery mac */ + search_str = "HWaddr "; + temp = strstr(buff, search_str); + if (temp != NULL) { + temp += strlen(search_str); + SAFE_FREE(tcard.mac); + tcard.mac = strtok_onetime(temp, " "); + if (tcard.mac == NULL) { + tcard.mac = strtok_onetime(temp, "\n"); + } + } + /* discovery type */ + search_str = "Local Loopback"; + temp = strstr(buff, search_str); + if (temp != NULL) { + tcard.eth_type = ETH_TYPE_LOOPBACK; + } + continue; + } + + ret = 1; + + out: + if (stream != NULL) { + pclose(stream); + } + eth_iface_uninit(&tcard); + SAFE_FREE(buff); + *retnum = count; + + return ret; +} + +int get_host_eth_ifaces_brctl(EthIface **ppifaces, int *retnum, int maxnum, + eth_iface_filter_func filter_func, void *filter_opaque) +{ + FILE *stream = NULL; + char cmd[64]; + char *buff = NULL; + int ret = 0; + EthIface tcard, **ppdest; + BR_Prop tbr; + char *last = NULL, *iter; + char *char_stp = NULL; + char *port_name = NULL; + int count = 0; + int filter_ret; + int line_count = 0; + + SAFE_MALLOC(buff, CONT_BUFF_SIZE); + cmd[0] = '\0'; + strcat(cmd, "brctl show"); + stream = pipe_excute_command_type_read(cmd, sizeof(cmd), "r", &ret); + if (stream == NULL) { + goto out; + } + + eth_iface_init(&tcard); + br_prop_init(&tbr); + tbr.port_num = 0; + port_name = NULL; + while (fgets(buff, CONT_BUFF_SIZE, stream) != NULL) { + CMD_DEBUG(3, "%s", buff); +/* output string should be something like following + +bridge name bridge id STP enabled interfaces +testbr 8000.000000000000 no +virbr0 8000.5254004ac14c yes virbr0-nic + vnet0 +virbr3 8000.5254004ac16c yes virbr3-nic +... +*/ + if (line_count == 0) { + if (NULL == strstr(buff, BRCTL_EXPECT_STRING)) { + CU_DEBUG("[%s] not found with command [%s]," + "check u environment.\n", + BRCTL_EXPECT_STRING, cmd); + ret = ERR_COMMAND_NOT_SUPPORT; + goto out; + } + line_count++; + continue; + } + if ((buff[0] == ' ') || (buff[0] == '\t')) { + /* the line saying ifaces it attached */ + port_name = strtok_r(buff, "\n", &last); + if (port_name == NULL) { + CU_DEBUG("command [%s] did not output as expected.", cmd); + continue; + } + port_name = strtok_r(buff, "\t", &last); + if (port_name == NULL) { + CU_DEBUG("command [%s] did not output as expected.", cmd); + continue; + } + /* adding the port */ + if (tbr.port_names == NULL) { + SAFE_CALLOC(tbr.port_names, MAX_IFACE_NUM, sizeof(char *)); + tbr.port_num = 0; + } + if (tbr.port_num >= MAX_IFACE_NUM) { + CU_DEBUG("bridge [%s] have too much eth attached!", + tcard.name); + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + tbr.port_names[tbr.port_num] = SAFE_STRDUP(port_name); + tbr.port_num++; + } else { + /* the line saying a new bridge */ + if (tcard.name != NULL) { + /* have a valid iface, so add it to the list */ + tcard.pbr_prop = &tbr; + tcard.eth_type = ETH_TYPE_BRIDGE; + filter_ret = 1; + if (filter_func != NULL) { + filter_ret = filter_func(&tcard, filter_opaque); + } + /* found a device match the requirement, put it to the list */ + if (filter_ret == 1) { + if (count >= maxnum) { + CU_DEBUG("too much bridge found, max is %d", + maxnum); + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + ppdest = ppifaces + count; + SAFE_MALLOC(*ppdest, sizeof(EthIface)); + eth_iface_dup(*ppdest, &tcard); + count++; + } + tcard.pbr_prop = NULL; + eth_iface_uninit(&tcard); + eth_iface_init(&tcard); + br_prop_uninit(&tbr); + br_prop_init(&tbr); + tbr.port_num = 0; + } + SAFE_STRDUP_WITH_FUNC(tcard.name, + strtok_r(buff, "\t", &last), iter); + SAFE_STRDUP_WITH_FUNC(tbr.bridge_id, + strtok_r(NULL, "\t", &last), iter); + char_stp = strtok_r(NULL, "\t", &last); + if (char_stp != NULL) { + if (0 == strcmp(char_stp, "yes")) { + tbr.STP = 1; + } else if (0 == strcmp(char_stp, "no")) { + tbr.STP = 0; + } + } + if (last != NULL) { + if ((*last == '\0') || (*(last+1) == '\0')) { + CU_DEBUG("command [%s] did not output as expected," + "string left [%s].", cmd, last); + continue; + } + last++; + } + if (*last == '\t') { + port_name = NULL; + } else { + port_name = strtok_r(NULL, "\n", &last); + if (port_name != NULL) { + /* adding the port */ + if (tbr.port_names == NULL) { + SAFE_CALLOC(tbr.port_names, + MAX_IFACE_NUM, sizeof(char *)); + tbr.port_num = 0; + } + if (tbr.port_num >= MAX_IFACE_NUM) { + CU_DEBUG("bridge [%s] have too much eth attached!", + tcard.name); + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + tbr.port_names[tbr.port_num] = SAFE_STRDUP(port_name); + tbr.port_num++; + } + } + } + line_count++; + } + + if (tcard.name != NULL) { + /* have a valid iface, so add it to the list */ + tcard.pbr_prop = &tbr; + tcard.eth_type = ETH_TYPE_BRIDGE; + filter_ret = 1; + if (filter_func != NULL) { + filter_ret = filter_func(&tcard, filter_opaque); + } + /* found a device match the requirement, put it to the list */ + if (filter_ret == 1) { + if (count >= maxnum) { + CU_DEBUG("too much bridge found, max is %d", + maxnum); + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + ppdest = ppifaces + count; + SAFE_MALLOC(*ppdest, sizeof(EthIface)); + eth_iface_dup(*ppdest, &tcard); + count++; + } + tcard.pbr_prop = NULL; + } + + ret = 1; + + out: + if (stream != NULL) { + pclose(stream); + } + br_prop_uninit(&tbr); + eth_iface_uninit(&tcard); + SAFE_FREE(buff); + *retnum = count; + + return ret; +} + +static int get_iface_cat_vlan_one_eth_8021q(EthIface *piface) +{ + FILE *stream = NULL; + char cmd[64]; + char *cmd_prefix = "cat /proc/net/vlan/"; + char *buff = NULL; + VLAN_Prop_8021q *pprop_8021q; + char *last = NULL; + char *char_temp = NULL; + char *search_str, *iter, *temp1, *temp2, *temp3, *qos; + int ret = 0; + int line_count = -1; + + SAFE_MALLOC(buff, CONT_BUFF_SIZE); + if ((piface->name == NULL) || + ((strlen(piface->name)+strlen(cmd_prefix)) > (sizeof(cmd)-1))) { + CU_DEBUG("error in building up cmd line, name is %s.", piface->name); + ret = ERR_COMMAND_NO_READY; + goto out; + } + memcpy(cmd, cmd_prefix, strlen(cmd_prefix)+1); + strcat(cmd, piface->name); + + stream = pipe_excute_command_type_read(cmd, sizeof(cmd), "r", &ret); + if (stream == NULL) { + goto out; + } + + if (piface->pvlan_prop == NULL) { + SAFE_MALLOC(piface->pvlan_prop, sizeof(VLAN_Prop)); + vlan_prop_init(piface->pvlan_prop, VLAN_TYPE_802_1_Q); + } + if (piface->pvlan_prop->vlan_type != VLAN_TYPE_802_1_Q) { + ret = 0; + goto out; + } + pprop_8021q = &(piface->pvlan_prop->props.prop_8021q); + + while (fgets(buff, CONT_BUFF_SIZE, stream) != NULL) { + line_count++; + CMD_DEBUG(3, "%s", buff); +/* output is expected some thing like following +eth1.7.7 VID: 7 REORDER_HDR: 1 dev->priv_flags: 1 + total frames received 0 + total bytes received 0 + Broadcast/Multicast Rcvd 0 + + total frames transmitted 0 + total bytes transmitted 0 + total headroom inc 0 + total encap on xmit 0 +Device: eth1.7 +INGRESS priority mappings: 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:0 + EGRESS priority mappings: +*/ + if (line_count == 0) { + if (NULL == strstr(buff, VLAN8021Q_CAT_ETH_EXPECT_STRING)) { + CU_DEBUG("[%s] not found with command [%s]," + "check u environment.\n", + VLAN8021Q_CAT_ETH_EXPECT_STRING, cmd); + ret = ERR_COMMAND_NOT_SUPPORT; + goto out; + } + } + search_str = "VID: "; + temp1 = strstr(buff, search_str); + if (temp1 != NULL) { + /* first line */ + temp1 += strlen(search_str); + search_str = "REORDER_HDR: "; + temp2 = strstr(buff, search_str); + if (temp2 != NULL) { + temp2 += strlen(search_str); + } + search_str = "priv_flags: "; + temp3 = strstr(buff, search_str); + if (temp3 != NULL) { + temp3 += strlen(search_str); + } + if ((temp2 != NULL) && (temp3 != NULL)) { + char_temp = strtok_r(temp1, " ", &last); + if (char_temp != NULL) { + pprop_8021q->vlan_id = strtol(char_temp, &iter, 10); + } + char_temp = strtok_r(temp2, " ", &last); + if (char_temp != NULL) { + pprop_8021q->reorder_hdr = strtol(char_temp, &iter, 10); + } + char_temp = strtok_r(temp3, " ", &last); + if (char_temp != NULL) { + pprop_8021q->priv_flag = strtol(char_temp, &iter, 10); + } + } + continue; + } + search_str = "total bytes received"; + temp1 = strstr(buff, search_str); + if (temp1 != NULL) { + temp1 += strlen(search_str); + char_temp = strtok_r(temp1, " ", &last); + if (char_temp != NULL) { + piface->run_prop.rx_bytes = strtoll(char_temp, &iter, 10); + } + continue; + } + search_str = "total bytes transmitted"; + temp1 = strstr(buff, search_str); + if (temp1 != NULL) { + temp1 += strlen(search_str); + char_temp = strtok_r(temp1, " ", &last); + if (char_temp != NULL) { + piface->run_prop.tx_bytes = strtoll(char_temp, &iter, 10); + } + continue; + } + search_str = "Device: "; + temp1 = strstr(buff, search_str); + if (temp1 != NULL) { + temp1 += strlen(search_str); + pprop_8021q->parent = strtok_onetime(temp1, " "); + if (pprop_8021q->parent == NULL) { + pprop_8021q->parent = strtok_onetime(temp1, "\n"); + } + continue; + } + search_str = "INGRESS priority mappings: "; + temp1 = strstr(buff, search_str); + if (temp1 != NULL) { + temp1 += strlen(search_str); + if (NULL != strstr(temp1, ":")) { + qos = strtok_onetime(temp1, "\n"); + if (qos != NULL) { + vlan_8021q_qos_str_to_num(&(pprop_8021q->ingress), qos); + SAFE_FREE(qos); + } + } + continue; + } + search_str = "EGRESS priority mappings: "; + temp1 = strstr(buff, search_str); + if (temp1 != NULL) { + temp1 += strlen(search_str); + if (NULL != strstr(temp1, ":")) { + qos = strtok_onetime(temp1, "\n"); + if (qos != NULL) { + vlan_8021q_qos_str_to_num(&(pprop_8021q->egress), qos); + SAFE_FREE(qos); + } + } + continue; + } + } + piface->eth_type = ETH_TYPE_VLAN; + ret = 1; + + out: + if (stream != NULL) { + pclose(stream); + } + SAFE_FREE(buff); + + return ret; +} + +int get_host_eth_ifaces_cat_vlan_config(EthIface **ppifaces, int *retnum, + int maxnum, eth_iface_filter_func filter_func, void *filter_opaque) +{ + FILE *stream = NULL; + char cmd[64]; + char *buff = NULL; + int ret = 0; + EthIface tcard, **ppdest; + VLAN_Prop tvlan; + int count = 0; + int filter_ret; + int line_count = -1; + + SAFE_MALLOC(buff, CONT_BUFF_SIZE); + cmd[0] = '\0'; + strcat(cmd, "cat /proc/net/vlan/config"); + stream = pipe_excute_command_type_read(cmd, sizeof(cmd), "r", &ret); + if (stream == NULL) { + goto out; + } + + eth_iface_init(&tcard); + vlan_prop_init(&tvlan, VLAN_TYPE_802_1_Q); + while (fgets(buff, CONT_BUFF_SIZE, stream) != NULL) { + line_count++; + CMD_DEBUG(3, "%s", buff); +/* output string should be something like following + +VLAN Dev name | VLAN ID +Name-Type: VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD +eth1.5 | 5 | eth1 +... +*/ + if (line_count == 0) { + if (NULL == strstr(buff, VLAN8021Q_CONFIG_EXPECT_STRING)) { + CU_DEBUG("[%s] not found with command [%s]," + "check u environment.\n", + VLAN8021Q_CONFIG_EXPECT_STRING, cmd); + ret = ERR_COMMAND_NOT_SUPPORT; + goto out; + } + continue; + } + if (line_count < 2) { + continue; + } + + /* the line saying a new bridge */ + if (tcard.name != NULL) { + /* have a valid iface, so add it to the list */ + tcard.pvlan_prop = &tvlan; + /* get additional information for this vlan */ + get_iface_cat_vlan_one_eth_8021q(&tcard); + /* filt it */ + filter_ret = 1; + if (filter_func != NULL) { + filter_ret = filter_func(&tcard, filter_opaque); + } + /* found a device match the requirement, put it to the list */ + if (filter_ret == 1) { + if (count >= maxnum) { + CU_DEBUG("too much vlan found, max is %d", + maxnum); + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + ppdest = ppifaces + count; + SAFE_MALLOC(*ppdest, sizeof(EthIface)); + eth_iface_dup(*ppdest, &tcard); + count++; + } + tcard.pvlan_prop = NULL; + eth_iface_uninit(&tcard); + eth_iface_init(&tcard); + vlan_prop_uninit(&tvlan); + vlan_prop_init(&tvlan, VLAN_TYPE_802_1_Q); + } + /* get the name, other properties would be got in special file */ + tcard.name = strtok_onetime(buff, " "); + } + + if (tcard.name != NULL) { + /* have a valid iface, so add it to the list */ + tcard.pvlan_prop = &tvlan; + /* get additional information for this vlan */ + get_iface_cat_vlan_one_eth_8021q(&tcard); + /* filt it */ + filter_ret = 1; + if (filter_func != NULL) { + filter_ret = filter_func(&tcard, filter_opaque); + } + /* found a device match the requirement, put it to the list */ + if (filter_ret == 1) { + if (count >= maxnum) { + CU_DEBUG("too much vlan found, max is %d", + maxnum); + ret = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + ppdest = ppifaces + count; + SAFE_MALLOC(*ppdest, sizeof(EthIface)); + eth_iface_dup(*ppdest, &tcard); + count++; + } + tcard.pvlan_prop = NULL; + } + + ret = 1; + + out: + if (stream != NULL) { + pclose(stream); + } + vlan_prop_uninit(&tvlan); + eth_iface_uninit(&tcard); + SAFE_FREE(buff); + *retnum = count; + + return ret; +} + +int change_state_host_iface_cmd(EthIface *piface, int state) +{ + FILE *stream = NULL; + char cmd[64]; + char *cmd_prefix = "ifconfig "; + char *cmd_suffix = NULL; + char *buff = NULL; + int ret = 0; + + SAFE_MALLOC(buff, CONT_BUFF_SIZE); + if (state == ETH_STATE_UP) { + cmd_suffix = " up"; + } else if (state == ETH_STATE_DOWN) { + cmd_suffix = " down"; + } + + if (cmd_suffix == NULL) { + CU_DEBUG("state change have not target state set."); + goto out; + } + + if (piface->name == NULL) { + ret = ERR_COMMAND_PARAMETER_WRONG; + CU_DEBUG("bridge name not set, direct goto out."); + goto out; + } + + if (0 == host_iface_is_present_cmd(piface)) { + CU_DEBUG("iface %s do not exist, can't change state.", piface->name); + ret = ERR_DEVICE_NOT_EXIST; + goto out; + } + + if ((strlen(cmd_prefix)+strlen(piface->name)+strlen(cmd_suffix)) + > (sizeof(cmd)-1)) { + CU_DEBUG("error in building up cmd line, name is %s.", piface->name); + ret = ERR_COMMAND_NO_READY; + goto out; + } + snprintf(cmd, sizeof(cmd), "%s%s%s", cmd_prefix, piface->name, cmd_suffix); + + stream = pipe_excute_command_type_write(cmd, sizeof(cmd), "r", &ret); + if (stream == NULL) { + goto out; + } + + while (fgets(buff, CONT_BUFF_SIZE, stream) != NULL) { + CU_DEBUG("get exception: %s", buff); + ret = ERR_COMMAND_NOT_SUPPORT; + goto out; + } + + ret = 1; + +out: + if (stream != NULL) { + pclose(stream); + stream = NULL; + } + SAFE_FREE(buff); + + return ret; +} + +int add_host_br_cmd(EthIface *piface, int persist_flag) +{ + FILE *stream = NULL; + char cmd[64]; + char *cmd_prefix = "brctl addbr "; + char *path; + char *path_prefix = IFACE_CONFIG_FILE_PREFIX_RH; + char *cont, *c_stp; + char *buff = NULL; + int ret = 0; + + SAFE_MALLOC(buff, CONT_BUFF_SIZE); + if (piface->name == NULL) { + ret = ERR_COMMAND_PARAMETER_WRONG; + CU_DEBUG("bridge name not set, direct goto out."); + goto out; + } + + if (1 == host_iface_is_present_cmd(piface)) { + CU_DEBUG("%s already exist, cann't create it as bridge.", piface->name); + ret = ERR_DEVICE_EXIST; + goto out; + } + + if ((strlen(cmd_prefix)+strlen(piface->name)) > (sizeof(cmd)-1)) { + CU_DEBUG("error in building up cmd line, name is %s.", piface->name); + ret = ERR_COMMAND_NO_READY; + goto out; + } + snprintf(cmd, sizeof(cmd), "%s%s", cmd_prefix, piface->name); + + stream = pipe_excute_command_type_write(cmd, sizeof(cmd), "r", &ret); + if (stream == NULL) { + goto out; + } + + while (fgets(buff, CONT_BUFF_SIZE, stream) != NULL) { + CU_DEBUG("get exception: %s", buff); + ret = ERR_COMMAND_EXECUTION; + goto out; + } + + if ((piface->pbr_prop != NULL) && + (piface->pbr_prop->STP == 1)) { + c_stp = "on"; + if (stream != NULL) { + pclose(stream); + stream = NULL; + } + cmd_prefix = "brctl stp "; + if ((strlen(cmd_prefix)+strlen(piface->name) + +strlen(c_stp)) > (sizeof(cmd)-2)) { + CU_DEBUG("error in building up cmd line, name is %s.", + piface->name); + ret = ERR_COMMAND_NO_READY; + goto out; + } + snprintf(cmd, sizeof(cmd), "%s%s %s", cmd_prefix, piface->name, c_stp); + stream = pipe_excute_command_type_write(cmd, sizeof(cmd), "r", &ret); + if (stream == NULL) { + goto out; + } + while (fgets(buff, CONT_BUFF_SIZE, stream) != NULL) { + CU_DEBUG("get exception: %s", buff); + ret = ERR_COMMAND_EXECUTION; + goto out; + } + } else { + c_stp = "off"; + } + + if (persist_flag == 1) { + if (LINUX_REDHAT != get_host_linux_version()) { + ret = ERR_PERSIST_NOT_REDHAT; + CU_DEBUG("Host is not a RedHat version, return is %d", + get_host_linux_version()); + goto out; + } + path = combine_file_name(path_prefix, piface->name); + SAFE_CALLOC(cont, 1024, sizeof(char)); + cont[1023] = 1; + snprintf(cont, 1024, + "DEVICE=%s\nTYPE=Bridge\nBOOTPROTO=dhcp\n" + "ONBOOT=yes\nDELAY=0\nSTP=%s\n", + piface->name, c_stp); + if (cont[1023] == '\0') { + CU_DEBUG("failed to build up contents, check the parameter."); + ret = ERR_FILE_CONT_TOO_LARGE; + SAFE_FREE(path); + SAFE_FREE(cont); + goto out; + } + ret = configure_file_update(path, cont); + SAFE_FREE(path); + SAFE_FREE(cont); + if (ret != 1) { + goto out; + } + + } + ret = 1; + +out: + if (stream != NULL) { + pclose(stream); + stream = NULL; + } + SAFE_FREE(buff); + + return ret; +} + +int del_host_br_cmd(EthIface *piface, int persist_flag) +{ + FILE *stream = NULL; + char cmd[64]; + char *cmd_prefix = "brctl delbr "; + char *path; + char *path_prefix = IFACE_CONFIG_FILE_PREFIX_RH; + char *buff = NULL; + int ret = 0; + + SAFE_MALLOC(buff, CONT_BUFF_SIZE); + if (piface->name == NULL) { + ret = ERR_COMMAND_PARAMETER_WRONG; + CU_DEBUG("bridge name not set, direct goto out."); + goto out; + } + + if (persist_flag == 1) { + if (LINUX_REDHAT != get_host_linux_version()) { + ret = ERR_PERSIST_NOT_REDHAT; + CU_DEBUG("Host is not a RedHat version, return is %d", + get_host_linux_version()); + goto out; + } + path = combine_file_name(path_prefix, piface->name); + ret = configure_file_remove(path); + SAFE_FREE(path); + if (ret != 1) { + goto out; + } + } + + if (0 == host_br_is_present_cmd(piface)) { + CU_DEBUG("bridge %s do not exist, can't delete it.", piface->name); + ret = ERR_DEVICE_NOT_EXIST; + goto out; + } + + if ((strlen(cmd_prefix)+strlen(piface->name)) > (sizeof(cmd)-1)) { + CU_DEBUG("error in building up cmd line, name is %s.", piface->name); + ret = ERR_COMMAND_NO_READY; + goto out; + } + snprintf(cmd, sizeof(cmd), "%s%s", cmd_prefix, piface->name); + + /* bring down the iface */ + change_state_host_iface_cmd(piface, ETH_STATE_DOWN); + + stream = pipe_excute_command_type_write(cmd, sizeof(cmd), "r", &ret); + if (stream == NULL) { + goto out; + } + + while (fgets(buff, CONT_BUFF_SIZE, stream) != NULL) { + CU_DEBUG("get exception: %s", buff); + ret = ERR_COMMAND_EXECUTION; + goto out; + } + + ret = 1; + +out: + if (stream != NULL) { + pclose(stream); + stream = NULL; + } + SAFE_FREE(buff); + + return ret; +} + +int mod_host_br_cmd(EthIface *piface, int persist_flag) +{ + FILE *stream = NULL; + char cmd[64]; + char *cmd_prefix = "brctl stp "; + char *path; + char *path_prefix = IFACE_CONFIG_FILE_PREFIX_RH; + char *c_stp; + char *buff = NULL; + int ret = 0; + + SAFE_MALLOC(buff, CONT_BUFF_SIZE); + if (piface->name == NULL) { + ret = ERR_COMMAND_PARAMETER_WRONG; + CU_DEBUG("bridge name not set, direct goto out."); + goto out; + } + + if (0 == host_br_is_present_cmd(piface)) { + CU_DEBUG("bridge %s do not exist, cann't modify it.", piface->name); + ret = ERR_DEVICE_EXIST; + goto out; + } + + if ((piface->pbr_prop != NULL) && + (piface->pbr_prop->STP == 1)) { + c_stp = "on"; + } else { + c_stp = "off"; + } + + if ((strlen(cmd_prefix)+strlen(piface->name) + +strlen(c_stp)) > (sizeof(cmd)-2)) { + CU_DEBUG("error in building up cmd line, name is %s.", piface->name); + ret = ERR_COMMAND_NO_READY; + goto out; + } + snprintf(cmd, sizeof(cmd), "%s%s %s", cmd_prefix, piface->name, c_stp); + stream = pipe_excute_command_type_write(cmd, sizeof(cmd), "r", &ret); + if (stream == NULL) { + goto out; + } + while (fgets(buff, CONT_BUFF_SIZE, stream) != NULL) { + CU_DEBUG("get exception: %s", buff); + ret = ERR_COMMAND_EXECUTION; + goto out; + } + + if (persist_flag == 1) { + if (LINUX_REDHAT != get_host_linux_version()) { + ret = ERR_PERSIST_NOT_REDHAT; + CU_DEBUG("Host is not a RedHat version, return is %d", + get_host_linux_version()); + goto out; + } + path = combine_file_name(path_prefix, piface->name); + ret = configure_file_replace_attr(path, "STP=", c_stp); + SAFE_FREE(path); + if (ret != 1) { + CU_DEBUG("error happened in persisting file."); + goto out; + } + } + ret = 1; + +out: + if (stream != NULL) { + pclose(stream); + stream = NULL; + } + SAFE_FREE(buff); + + return ret; +} + +static int append_vlan_8021q_parameters(char *cmd, int cmd_size, + VLAN_Prop_8021q *p_8021q) +{ + char *reorder = NULL; + char *egress = NULL, *ingress = NULL; + char *cmd_prefix; + int ret = 0; + + if (p_8021q->reorder_hdr == 1) { + reorder = " reorder_hdr on"; + } else if (p_8021q->reorder_hdr == 0) { + reorder = " reorder_hdr off"; + } + if (reorder != NULL) { + if ((strlen(reorder)+strlen(cmd)) < (cmd_size-1)) { + strcat(cmd, reorder); + } else { + CU_DEBUG("cmd line too long, it is [%s]+[%s].", cmd, reorder); + ret = ERR_COMMAND_NO_READY; + goto out; + } + } + + vlan_8021q_qos_num_to_str(&ingress, &(p_8021q->ingress)); + if (ingress != NULL) { + cmd_prefix = " ingress-qos-map "; + if ((strlen(ingress)+strlen(cmd)+strlen(cmd_prefix)) < (cmd_size-1)) { + strcat(cmd, cmd_prefix); + strcat(cmd, ingress); + } else { + CU_DEBUG("cmd line too long, it is [%s]+[%s]+[%s].", + cmd, cmd_prefix, ingress); + ret = ERR_COMMAND_NO_READY; + goto out; + } + } + + vlan_8021q_qos_num_to_str(&egress, &(p_8021q->egress)); + if (egress != NULL) { + cmd_prefix = " egress-qos-map "; + if ((strlen(egress)+strlen(cmd)+strlen(cmd_prefix)) < (cmd_size-1)) { + strcat(cmd, cmd_prefix); + strcat(cmd, egress); + } else { + CU_DEBUG("cmd line too long, it is [%s]+[%s]+[%s].", + cmd, cmd_prefix, egress); + ret = ERR_COMMAND_NO_READY; + goto out; + } + } + + ret = 1; + + out: + SAFE_FREE(ingress); + SAFE_FREE(egress); + return ret; +} + +int add_host_vlan_8021q_cmd(EthIface *piface, int persist_flag) +{ + FILE *stream = NULL; + char cmd[192]; + char *path; + char *path_prefix = IFACE_CONFIG_FILE_PREFIX_RH; + char *cont; + char *buff = NULL; + int ret = 0; + int str_size; + EthIface iface; + VLAN_Prop_8021q *p_8021q; + + SAFE_MALLOC(buff, CONT_BUFF_SIZE); + eth_iface_init(&iface); + if (piface->pvlan_prop == NULL) { + CU_DEBUG("pvlan_prop not set, direct goto out."); + goto out; + } + if (piface->pvlan_prop->vlan_type != VLAN_TYPE_802_1_Q) { + CU_DEBUG("not a 802.1.q vlan, direct goto out."); + goto out; + } + p_8021q = &(piface->pvlan_prop->props.prop_8021q); + if ((p_8021q->vlan_id < 1) || (p_8021q->vlan_id > 4095)) { + CU_DEBUG("vlan_id for 802.1.q must be 0-4095, " + "and 0 is kept by system, request is %d.", p_8021q->vlan_id); + goto out; + } + if ((p_8021q->parent == NULL)) { + CU_DEBUG("creation of vlan iface for 802.1.q need parent iface set"); + goto out; + } + iface.name = p_8021q->parent; + if (0 == host_iface_is_present_cmd(&iface)) { + CU_DEBUG("iface %s do not exist, cann't use it as parent iface.", + iface.name); + iface.name = NULL; + ret = ERR_DEVICE_NOT_EXIST; + goto out; + } + + /* restrict the iface name to ethx.x, so the name would be combined here */ + str_size = strlen(p_8021q->parent)+6; + SAFE_MALLOC(iface.name, str_size); + snprintf(iface.name, str_size, "%s.%d", + p_8021q->parent, p_8021q->vlan_id); + if (1 == host_iface_is_present_cmd(&iface)) { + CU_DEBUG("iface %s already exist, cann't create it as a 802.1.q vlan.", + iface.name); + ret = ERR_DEVICE_EXIST; + goto out; + } + + /* building up command line */ + cmd[sizeof(cmd)-1] = 1; + snprintf(cmd, sizeof(cmd), "ip link add link %s name %s type vlan id %d", + p_8021q->parent, iface.name, p_8021q->vlan_id); + if (cmd[sizeof(cmd)-1] == '\0') { + CU_DEBUG("cmd line too long, it is [%s].", cmd); + ret = ERR_COMMAND_NO_READY; + goto out; + } + + ret = append_vlan_8021q_parameters(cmd, sizeof(cmd), p_8021q); + if (ret != 1) { + goto out; + } + + stream = pipe_excute_command_type_write(cmd, sizeof(cmd), "r", &ret); + if (stream == NULL) { + goto out; + } + + while (fgets(buff, CONT_BUFF_SIZE, stream) != NULL) { + CU_DEBUG("get exception: %s", buff); + ret = ERR_COMMAND_EXECUTION; + goto out; + } + + if (persist_flag == 1) { + if (LINUX_REDHAT != get_host_linux_version()) { + ret = ERR_PERSIST_NOT_REDHAT; + CU_DEBUG("Host is not a RedHat version, return is %d", + get_host_linux_version()); + goto out; + } + path = combine_file_name(path_prefix, iface.name); + SAFE_CALLOC(cont, 1024, sizeof(char)); + cont[1023] = 1; + snprintf(cont, 1024, + "DEVICE=%s\nPEERDNS=yes\nVLAN=yes\n", iface.name); + if (cont[1023] == '\0') { + CU_DEBUG("failed to build up contents, check the parameter."); + ret = ERR_FILE_CONT_TOO_LARGE; + SAFE_FREE(path); + SAFE_FREE(cont); + goto out; + } + ret = configure_file_update(path, cont); + SAFE_FREE(path); + SAFE_FREE(cont); + if (ret != 1) { + goto out; + } + } + ret = 1; + +out: + if (stream != NULL) { + pclose(stream); + stream = NULL; + } + eth_iface_uninit(&iface); + SAFE_FREE(buff); + + return ret; +} + +int del_host_vlan_8021q_cmd(EthIface *piface, int persist_flag) +{ + FILE *stream = NULL; + char cmd[128]; + char *path; + char *path_prefix = IFACE_CONFIG_FILE_PREFIX_RH; + char *buff = NULL; + int ret = 0; + + SAFE_MALLOC(buff, CONT_BUFF_SIZE); + if (piface->name == NULL) { + CU_DEBUG("piface name was not set, direct goto out."); + ret = ERR_COMMAND_PARAMETER_WRONG; + goto out; + } + + if (persist_flag == 1) { + if (LINUX_REDHAT != get_host_linux_version()) { + ret = ERR_PERSIST_NOT_REDHAT; + CU_DEBUG("Host is not a RedHat version, return is %d", + get_host_linux_version()); + goto out; + } + path = combine_file_name(path_prefix, piface->name); + ret = configure_file_remove(path); + SAFE_FREE(path); + if (ret != 1) { + goto out; + } + } + + if (piface->pvlan_prop == NULL) { + CU_DEBUG("pvlan_prop not set, direct goto out."); + goto out; + } + if (piface->pvlan_prop->vlan_type != VLAN_TYPE_802_1_Q) { + CU_DEBUG("not a 802.1.q vlan, direct goto out."); + goto out; + } + + if (0 == host_vlan_is_present_8021q_cmd(piface)) { + CU_DEBUG("vlan %s do not exist, cann't delete it.", piface->name); + ret = ERR_DEVICE_EXIST; + goto out; + } + + /* building up command line */ + cmd[sizeof(cmd)-1] = 1; + snprintf(cmd, sizeof(cmd), "ip link del %s", piface->name); + if (cmd[sizeof(cmd)-1] == '\0') { + CU_DEBUG("cmd line too long, it is [%s].", cmd); + ret = ERR_COMMAND_NO_READY; + goto out; + } + + stream = pipe_excute_command_type_write(cmd, sizeof(cmd), "r", &ret); + if (stream == NULL) { + ret = ERR_COMMAND_PIPE_ERR; + goto out; + } + + while (fgets(buff, CONT_BUFF_SIZE, stream) != NULL) { + CU_DEBUG("get exception: %s", buff); + ret = ERR_COMMAND_EXECUTION; + goto out; + } + + ret = 1; + +out: + if (stream != NULL) { + pclose(stream); + stream = NULL; + } + SAFE_FREE(buff); + + return ret; +} + +int mod_host_vlan_8021q_cmd(EthIface *piface, int persist_flag) +{ + FILE *stream = NULL; + char cmd[192]; + char *buff = NULL; + int ret = 0; + VLAN_Prop_8021q *p_8021q; + + SAFE_MALLOC(buff, CONT_BUFF_SIZE); + if (piface->name == NULL) { + ret = ERR_COMMAND_PARAMETER_WRONG; + CU_DEBUG("piface name was not set, direct goto out."); + goto out; + } + if (piface->pvlan_prop == NULL) { + CU_DEBUG("pvlan_prop not set, direct goto out."); + goto out; + } + if (piface->pvlan_prop->vlan_type != VLAN_TYPE_802_1_Q) { + CU_DEBUG("not a 802.1.q vlan, direct goto out."); + goto out; + } + if (0 == host_vlan_is_present_8021q_cmd(piface)) { + CU_DEBUG("vlan %s do not exist, cann't modify it.", piface->name); + ret = ERR_DEVICE_EXIST; + goto out; + } + p_8021q = &(piface->pvlan_prop->props.prop_8021q); + + /* building up command line */ + cmd[sizeof(cmd)-1] = 1; + snprintf(cmd, sizeof(cmd), "ip link set %s type vlan", + piface->name); + if (cmd[sizeof(cmd)-1] == '\0') { + CU_DEBUG("cmd line too long, it is [%s].", cmd); + ret = ERR_COMMAND_NO_READY; + goto out; + } + + ret = append_vlan_8021q_parameters(cmd, sizeof(cmd), p_8021q); + if (ret != 1) { + goto out; + } + + stream = pipe_excute_command_type_write(cmd, sizeof(cmd), "r", &ret); + if (stream == NULL) { + goto out; + } + + while (fgets(buff, CONT_BUFF_SIZE, stream) != NULL) { + CU_DEBUG("get exception: %s", buff); + ret = ERR_COMMAND_EXECUTION; + goto out; + } + + if (persist_flag == 1) { + /* modification is logged by linux system itself in /proc/net/vlan */ + } + ret = 1; + +out: + if (stream != NULL) { + pclose(stream); + stream = NULL; + } + SAFE_FREE(buff); + + return ret; +} + +int add_host_iface_to_br_cmd(EthIface *piface, EthIface *pbr, + int persist_flag) +{ + FILE *stream = NULL; + char cmd[64]; + char *buff = NULL; + int ret = 0; + int check_value; + char *path_prefix = IFACE_CONFIG_FILE_PREFIX_RH; + char *path; + + SAFE_MALLOC(buff, CONT_BUFF_SIZE); + if ((piface->name == NULL) || (pbr->name == NULL)) { + ret = ERR_COMMAND_PARAMETER_WRONG; + CU_DEBUG("name was not set, direct goto out."); + goto out; + } + + check_value = host_br_have_iface_attached_cmd(pbr, piface, NULL); + if (check_value < 0) { + CU_DEBUG("iface %s or bridge %s do not exist, direct goto out.", + piface->name, pbr->name); + ret = ERR_DEVICE_NOT_EXIST; + goto out; + } else if (check_value == 1) { + CU_DEBUG("iface %s already attached to bridge %s, can't do it again.", + piface->name, pbr->name); + ret = ERR_DEVICE_ALREADY_DONE; + goto out; + } else if (check_value == 2) { + CU_DEBUG("iface %s is attached to another bridge, " + "can't direct change it.", + piface->name); + ret = ERR_DEVICE_CONNECT_OTHER; + goto out; + } + + /* building up command line */ + cmd[sizeof(cmd)-1] = 1; + snprintf(cmd, sizeof(cmd), "brctl addif %s %s", + pbr->name, piface->name); + if (cmd[sizeof(cmd)-1] == '\0') { + CU_DEBUG("cmd line too long, it is [%s].", cmd); + ret = ERR_COMMAND_NO_READY; + goto out; + } + + stream = pipe_excute_command_type_write(cmd, sizeof(cmd), "r", &ret); + if (stream == NULL) { + goto out; + } + + while (fgets(buff, CONT_BUFF_SIZE, stream) != NULL) { + CU_DEBUG("get exception: %s", buff); + ret = ERR_COMMAND_EXECUTION; + goto out; + } + + if (persist_flag == 1) { + /* if the configuration file do not exist, would not create it */ + if (LINUX_REDHAT != get_host_linux_version()) { + ret = ERR_PERSIST_NOT_REDHAT; + CU_DEBUG("Host is not a RedHat version, return is %d", + get_host_linux_version()); + goto out; + } + path = combine_file_name(path_prefix, piface->name); + ret = configure_file_replace_attr(path, "BRIDGE=", pbr->name); + SAFE_FREE(path); + if (ret != 1) { + CU_DEBUG("error happened in persisting file."); + goto out; + } + } + ret = 1; + +out: + if (stream != NULL) { + pclose(stream); + stream = NULL; + } + SAFE_FREE(buff); + + return ret; +} + +int remove_host_iface_from_br_cmd(EthIface *piface, EthIface *pbr, + int persist_flag) +{ + FILE *stream = NULL; + char cmd[64]; + char *buff = NULL; + int ret = 0; + int check_value; + char *path_prefix = IFACE_CONFIG_FILE_PREFIX_RH; + char *path; + + SAFE_MALLOC(buff, CONT_BUFF_SIZE); + if ((piface->name == NULL) || (pbr->name == NULL)) { + ret = ERR_COMMAND_PARAMETER_WRONG; + CU_DEBUG("name was not set, direct goto out."); + goto out; + } + + check_value = host_br_have_iface_attached_cmd(pbr, piface, NULL); + if (check_value < 0) { + CU_DEBUG("iface %s or bridge %s do not exist, direct goto out.", + piface->name, pbr->name); + ret = ERR_DEVICE_NOT_EXIST; + goto out; + } else if (check_value == 0) { + CU_DEBUG("iface %s is not attached to bridge %s, can't remove it.", + piface->name, pbr->name); + ret = ERR_DEVICE_ALREADY_DONE; + goto out; + } else if (check_value == 2) { + CU_DEBUG("iface %s is attached to another device, can't remove it.", + piface->name); + ret = ERR_DEVICE_CONNECT_OTHER; + goto out; + } + + /* building up command line */ + cmd[sizeof(cmd)-1] = 1; + snprintf(cmd, sizeof(cmd), "brctl delif %s %s", + pbr->name, piface->name); + if (cmd[sizeof(cmd)-1] == '\0') { + CU_DEBUG("cmd line too long, it is [%s].", cmd); + ret = ERR_COMMAND_NO_READY; + goto out; + } + + stream = pipe_excute_command_type_write(cmd, sizeof(cmd), "r", &ret); + if (stream == NULL) { + goto out; + } + + while (fgets(buff, CONT_BUFF_SIZE, stream) != NULL) { + CU_DEBUG("get exception: %s", buff); + ret = ERR_COMMAND_EXECUTION; + goto out; + } + + if (persist_flag == 1) { + /* if the configuration file do not exist, would not create it */ + if (LINUX_REDHAT != get_host_linux_version()) { + ret = ERR_PERSIST_NOT_REDHAT; + CU_DEBUG("Host is not a RedHat version, return is %d", + get_host_linux_version()); + goto out; + } + path = combine_file_name(path_prefix, piface->name); + ret = configure_file_replace_attr(path, "BRIDGE=", NULL); + SAFE_FREE(path); + if (ret != 1) { + CU_DEBUG("error happened in persisting file."); + goto out; + } + } + ret = 1; + +out: + if (stream != NULL) { + pclose(stream); + stream = NULL; + } + SAFE_FREE(buff); + + return ret; +} + +static void merge_eth_list(EthIfacesList *pdest, EthIfacesList *psrc, int flag) +{ + int i, j; + i = 0; + while (i < pdest->count) { + j = 0; + while (j < psrc->count) { + if (1 == eth_iface_compare(pdest->pifaces[i], psrc->pifaces[j])) { + /* found the matched device, merge them */ + eth_iface_merge(pdest->pifaces[i], psrc->pifaces[j], flag); + break; + } + j++; + } + i++; + } + return; +} + +static void find_iface_attached_bridge(EthIfacesList *peth_list, EthIface *pbr) +{ + int i, j; + char *name_on_br, *name_iface; + if (pbr->pbr_prop == NULL) { + return; + } + i = 0; + while (i < pbr->pbr_prop->port_num) { + name_on_br = pbr->pbr_prop->port_names[i]; + j = 0; + while (j < peth_list->count) { + name_iface = peth_list->pifaces[j]->name; + if (0 == strcmp(name_on_br, name_iface)) { + if (peth_list->pifaces[j]->attach_bridge == NULL) { + peth_list->pifaces[j]->attach_bridge = + SAFE_STRDUP(pbr->name); + } + break; + } + j++; + } + i++; + } +} + +/* assuming that one peth would be attached to at most 1 bridge */ +static void merge_eth_list_for_bridge(EthIfacesList *peth_list, + EthIfacesList *pbr_list, + int flag) +{ + int i, j; + i = 0; + while (i < pbr_list->count) { + find_iface_attached_bridge(peth_list, pbr_list->pifaces[i]); + j = 0; + while (j < peth_list->count) { + if (1 == eth_iface_compare(peth_list->pifaces[j], + pbr_list->pifaces[i])) { + /* found the matched device, merge them */ + eth_iface_merge(peth_list->pifaces[j], + pbr_list->pifaces[i], flag); + break; + } + j++; + } + i++; + } + return; +} + +int get_host_eth_ifaces_cmd_all(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque) +{ + int retvalue; + EthIfacesList *ifaces1, *ifaces2; + int i; + int filter_ret; + int count = 0; + SAFE_MALLOC(ifaces1, sizeof(EthIfacesList)); + SAFE_MALLOC(ifaces2, sizeof(EthIfacesList)); + eth_ifaceslist_init(ifaces1); + eth_ifaceslist_init(ifaces2); + + retvalue = get_host_eth_ifaces_ip_addr(ifaces1->pifaces, &(ifaces1->count), + MAX_IFACE_NUM, NULL, NULL); + if (retvalue != 1) { + goto out; + } + + + retvalue = get_host_eth_ifaces_ifconfig(ifaces2->pifaces, &(ifaces2->count), + MAX_IFACE_NUM, NULL, NULL); + if (retvalue != 1) { + goto out; + } + /* merge the information */ + merge_eth_list(ifaces1, ifaces2, 1); + eth_ifaceslist_uninit(ifaces2); + + retvalue = get_host_eth_ifaces_brctl(ifaces2->pifaces, &(ifaces2->count), + MAX_IFACE_NUM, NULL, NULL); + if (retvalue != 1) { + goto out; + } + /* merge the information */ + merge_eth_list_for_bridge(ifaces1, ifaces2, 1); + eth_ifaceslist_uninit(ifaces2); + + retvalue = get_host_eth_ifaces_cat_vlan_config(ifaces2->pifaces, + &(ifaces2->count), MAX_IFACE_NUM, NULL, NULL); + if (retvalue != 1) { + goto out; + } + + /* merge the information */ + merge_eth_list(ifaces1, ifaces2, 1); + eth_ifaceslist_uninit(ifaces2); + + /* filter the result */ + i = 0; + while (i < ifaces1->count) { + /* see if the result need to be put to the list */ + filter_ret = 1; + if (filter_func != NULL) { + filter_ret = filter_func(ifaces1->pifaces[i], filter_opaque); + } + if (filter_ret == 1) { + if (count >= MAX_IFACE_NUM) { + retvalue = ERR_DEVICE_EXCEED_MAXNUM; + goto out; + } + host_iface_adjust(ifaces1->pifaces[i]); + plist->pifaces[count] = ifaces1->pifaces[i]; + ifaces1->pifaces[i] = NULL; + count++; + } + i++; + } + + out: + eth_ifaceslist_uninit(ifaces1); + SAFE_FREE(ifaces1); + eth_ifaceslist_uninit(ifaces2); + SAFE_FREE(ifaces2); + plist->count = count; + return retvalue; +} diff --git a/libxkutil/host_network_implement_cmdline.h b/libxkutil/host_network_implement_cmdline.h new file mode 100644 index 0000000..90e5891 --- /dev/null +++ b/libxkutil/host_network_implement_cmdline.h @@ -0,0 +1,55 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia <xiawenc@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. + */ + +#ifndef HOST_NETWORK_IMPLEMENT_CMDLINE_H +#define HOST_NETWORK_IMPLEMENT_CMDLINE_H + +#include "host_network_basic.h" + +int get_host_eth_ifaces_ip_addr(EthIface **ppifaces, int *retnum, int maxnum, + eth_iface_filter_func filter_func, void *filter_opaque); + +int get_host_eth_ifaces_ifconfig(EthIface **ppifaces, int *retnum, int maxnum, + eth_iface_filter_func filter_func, void *filter_opaque); + +int get_host_eth_ifaces_brctl(EthIface **ppifaces, int *retnum, int maxnum, + eth_iface_filter_func filter_func, void *filter_opaque); + +int get_host_eth_ifaces_cat_vlan_config(EthIface **ppifaces, int *retnum, + int maxnum, eth_iface_filter_func filter_func, void *filter_opaque); + +int get_host_eth_ifaces_cmd_all(EthIfacesList *plist, + eth_iface_filter_func filter_func, void *filter_opaque); + +int add_host_br_cmd(EthIface *piface, int persist_flag); +int del_host_br_cmd(EthIface *piface, int persist_flag); +int mod_host_br_cmd(EthIface *piface, int persist_flag); +int add_host_iface_to_br_cmd(EthIface *piface, EthIface *pbr, + int persist_flag); +int remove_host_iface_from_br_cmd(EthIface *piface, EthIface *pbr, + int persist_flag); + +int add_host_vlan_8021q_cmd(EthIface *piface, int persist_flag); +int del_host_vlan_8021q_cmd(EthIface *piface, int persist_flag); +int mod_host_vlan_8021q_cmd(EthIface *piface, int persist_flag); + +int change_state_host_iface_cmd(EthIface *piface, int state); + +int host_br_have_iface_attached_cmd(EthIface *pbr, EthIface *piface, + EthIface **ppbr_result); + +/* check a batch of iface's state with one call of get_host_ifaces, + retvalues must be allocated big enough */ +int host_ifacelist_is_present_cmd(EthIfacesList *plist, int *retvalues, + int compare_name_only); + +#endif -- 1.7.6
participants (2)
-
Chip Vincent
-
Wayne Xia