
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