#include #include #include #include #include #include "list.h" #include "configm.h" #include "brconfig.h" #include "rpc.h" #include "parsefile.h" #include "brnetlink.h" #include "parsefile.h" #include "libbridge.h" /* 事件通知函数 */ br_event_head_t br_event_tbl = {.head.first = NULL, .lock = 0, .init = false}; int br_invoke_event(BR_EVENT_TYPE event_type, br_event_t event_arg) { br_event_node_t *hnode; pthread_mutex_lock(&(br_event_tbl.lock)); hlist_for_each_entry(hnode, &(br_event_tbl.head), list) { if(hnode->br_event == event_type) { hnode->event_func(event_type, event_arg); } } pthread_mutex_unlock(&(br_event_tbl.lock)); } int br_event_register(BR_EVENT_TYPE event_type, BR_EVENT_FUNC event_func) { br_event_node_t *hnode = NULL; if(br_event_tbl.init == false) { INIT_HLIST_HEAD(&(br_event_tbl.head)); pthread_mutex_init(&(br_event_tbl.lock), NULL); br_event_tbl.init = true; } hnode = (br_event_node_t *)rpc_new0(br_event_node_t, 1); if(!hnode) { rpc_log_error("br_event_register failed\n"); return -1; } INIT_HLIST_NODE(&hnode->list); hnode->br_event = event_type; hnode->event_func = event_func; pthread_mutex_lock(&(br_event_tbl.lock)); hlist_add_head(&hnode->list, &(br_event_tbl.head)); pthread_mutex_unlock(&(br_event_tbl.lock)); return 0; } int br_event_unregister(BR_EVENT_TYPE event_type, BR_EVENT_FUNC event_func) { br_event_node_t *hnode = NULL; struct hlist_node *n; if(br_event_tbl.init == false) { return 0; } pthread_mutex_lock(&(br_event_tbl.lock)); hlist_for_each_entry_safe(hnode, n, &(br_event_tbl.head), list) { if(event_type == hnode->br_event && event_func == hnode->event_func) { hlist_del(&hnode->list); rpc_free(hnode); break; } } pthread_mutex_unlock(&(br_event_tbl.lock)); return 0; } /* 桥配置辅助函数 */ int br_copy_port_name(const char *b, const char *p, void *arg) { br_if_temp_t *br_if = (br_if_temp_t *)arg; char *dst_ptr = NULL; br_if->if_list = realloc(br_if->if_list, INTERFACE_NAMSIZ); ASSERT_PTR_RET(br_if->if_list); dst_ptr = br_if->if_list + br_if->index * INTERFACE_NAMSIZ strncpy(dst_ptr, p, INTERFACE_NAMSIZ - 1); br_if->index++; return 0; } ret_code br_name_chk(char *br_name) { if(strlen(br_name) == 0 || strlen(br_name) > BR_NAMSIZ - 1 || strstr(br_name, "br-vl") != NULL) { return RET_BR_INVALID; } return RET_OK; } int br_name_cmp(char *br_name, void *args) { br_temp_t *cmp_args = (br_temp_t *)args; if(strcmp(br_name, cmp_args->br_name) == 0) { cmp_args->result = true; return 1; } return 0; } boolean br_is_exist(char *br_name) { br_temp_t cmp_args = {br_name, false}; br_foreach_bridge(br_name_cmp, &cmp_args); return cmp_args.result; } ret_code br_if_bridge_get(char *port_name, char* br_name) { char bridge_name[BR_NAMSIZ] = {0}; if(get_br_from_port(port_name, bridge_name) == RET_OK) { if(br_name) { strncpy(br_name, bridge_name, BR_NAMSIZ - 1); } return RET_OK; } return RET_NOTFOUND; } ret_code br_if_bridge_check(char *port_list, int cnt, uint config_type) { char *ptr_name = NULL; int i; for(i = 0; i< cnt; i++) { ptr_name = port_list + INTERFACE_NAMSIZ * i; if (if_nametoindex(ptr_name) == 0) { return RET_NOTFOUND; } if(br_if_bridge_get(ptr_name, NULL) == RET_OK) { if(config_type == CM_CONFIG_ADD) { return RET_EXIST; } } else if(config_type == CM_CONFIG_DEL) { return RET_NOTFOUND; } } return RET_OK; } ret_code br_save_file(BR_EVENT_TYPE event_type, char *br_name, char *port_name) { char *key_str = "bridge_ports"; char config_str[IF_BUFF_LEN] = {0}; ret_code ret; switch(event_type) { case BR_CREATE_EVENT: if_conf_file_add(br_name); break; case BR_DELETE_EVENT: if_conf_file_del(br_name) break; case BR_IF_JOIN_EVENT: if(if_conf_file_get(br_name, key_str, config_str) == RET_OK) { if(strstr(config_str, port_name) != NULL) { return RET_OK; } strcat(config_str, " "); strcat(config_str, port_name); } if_conf_file_set(br_name, key_str, config_str); break; case BR_IF_LEAVE_EVENT: if(if_conf_file_get(br_name, key_str, config_str) == RET_OK) { if(strstr(config_str, port_name) != NULL) { del_sub_string(config_str, port_name); rpc_log_info("BR_IF_LEAVE_EVENT: %s\n", config_str); if_conf_file_set(br_name, key_str, config_str); return RET_OK; } } break; default: break; } return RET_OK; } ret_code br_if_bridge_add(char *br_name, char *port_list, int cnt, int *sys_err) { ret_code ret = RET_OK; char *port_name; int err = 0; int i; for(i = 0; i < cnt) { br_invoke_event(BR_IF_JOIN_EVENT_PRE, event_arg); port_name = port_list + INTERFACE_NAMSIZ * i; err = br_add_interface(br_name, port_name); if(err != 0) { sys_err = err; ret = RET_SYSERR; continue; } br_event_t event_arg = {br_name, port_name}; br_invoke_event(BR_IF_JOIN_EVENT, event_arg); br_save_file(BR_IF_JOIN_EVENT, br_name, port_name); } return ret; } ret_code br_if_bridge_del(char * br_name, char *port_list, int cnt, int *sys_err) { ret_code ret = RET_OK; char *port_name; int err = 0; int i; for(i = 0; i < cnt) { br_invoke_event(BR_IF_LEAVE_EVENT_PRE, event_arg); port_name = port_list + INTERFACE_NAMSIZ * i; err = br_del_interface(br_name, port_name); if(err != 0) { sys_err = err; ret = RET_SYSERR; continue; } br_event_t event_arg = {br_name, port_name}; br_invoke_event(BR_IF_LEAVE_EVENT, event_arg); br_save_file(BR_IF_LEAVE_EVENT, br_name, port_name); } return ret; } int br_if_bridge_num(char *br_name) { int cnt = 0; err = br_for_port_num(br_name, &cnt); cnt = (err != 0) ? 0 : cnt; return cnt; } ret_code br_bridge_add(char *br_name, int *sys_err) { br_event_t event_arg = {br_name, NULL}; int sys_ret = 0; br_invoke_event(BR_CREATE_EVENT_PRE, event_arg); sys_ret = br_add_bridge(br_name); *sys_err = sys_ret; if(sys_ret != 0) { return RET_SYSERR; } br_invoke_event(BR_CREATE_EVENT, event_arg); br_save_file(BR_CREATE_EVENT, br_name, NULL); return RET_OK; } ret_code br_bridge_del(char * br_name, int *sys_err) { br_event_t event_arg = {br_name, NULL}; int sys_ret = 0; br_invoke_event(BR_DELETE_EVENT_PRE, event_arg); sys_ret = br_del_bridge(br_name); *sys_err = sys_ret; if(sys_ret != 0) { return RET_SYSERR; } br_invoke_event(BR_DELETE_EVENT, event_arg); br_save_file(BR_DELETE_EVENT, br_name, NULL); return RET_OK; } /* 桥配置json格式转换函数 */ ret_code br_config_json_parse(pointer input, uint *conf_type, char *br_name) { cJSON *json_obj; json_obj = cJSON_Parse(input); ASSERT_PTR_RET(json_obj); rpc_log_info("json input:\n %s\n", cJSON_Print(json_obj)); s2j_create_struct_obj(br_config, br_config_string_t); if(br_config == NULL) { cJSON_Delete(json_obj); return RET_NOMEM; } s2j_struct_get_basic_element(br_config, json_obj, int, config_type); s2j_struct_get_string_element(br_config, json_obj, br_name, BR_NAMSIZ); strncpy(br_name, br_config->br_name, BR_NAMSIZ - 1); *conf_type = br_config->config_type; s2j_delete_struct_obj(br_config); cJSON_Delete(json_obj); return RET_OK; } int br_json_to_string( cJSON *json_obj, pointer output) { char *json_str; int output_len = 0; if(json_obj == NULL) { return 0; } json_str = cJSON_PrintUnformatted(json_array); output_len = strlen(json_str) + 1; if(output_len > CM_BUFF_SIZE) { rpc_log_warn("output len is too long %d, cut off!", output_len); json_str[CM_BUFF_SIZE - 1] = '\0'; output_len = CM_BUFF_SIZE; } memcpy(output, json_str, output_len); rpc_free(json_str); s2j_delete_json_obj(json_obj); return output_len; } cJSON *br_config_format_json(br_config_t *br_config) { cJSON *json_obj; s2j_create_json_obj(json_obj); if(json_obj == NULL) { return NULL; } s2j_json_set_basic_element(json_obj, br_config, string, br_name); s2j_json_set_array_element(json_obj, br_config, string, ports, br_config->port_num); return json_obj; } ret_code br_bridge_info( char *br_name, cJSON *json_obj, int *err) { ret_code ret = RET_OK; br_if_temp_t br_if = {0}; br_config_t br_config = {0}; br_if.index = 0; br_if.if_list = NULL; *err = br_foreach_port(br_name, br_copy_port_name, &br_if) if (*err >= 0) { strncpy(br_config.br_name, br_name, BR_NAMSIZ - 1); br_config.ports = br_if.if_list; br_config.port_num = br_if.index; json_obj = br_config_format_json(&br_config); } else { ret = RET_SYSERR; } if(br_if.if_list) { rpc_free(br_if.if_list); } return ret; } int br_bridge_info_each(const char *br_name, void *args) { cJSON *json_array = (cJSON *)args; cJSON *json_obj = NULL; ret_code ret = RET_OK; int err = 0; ret = br_bridge_info(br_name, json_obj, &err); if(json_obj) { cJSON_AddItemToArray(json_array, json_obj); } return 0; } ret_code br_if_config_json_parse(pointer input, uint *conf_type, br_config_t *br_if) { cJSON *json_obj; int port_num = 0; json_obj = cJSON_Parse(input); ASSERT_PTR_RET(json_obj); rpc_log_info("json input:\n %s\n", cJSON_Print(json_obj)); s2j_create_struct_obj(br_if_conf, br_if_config_string_t); if(br_if_conf == NULL) { cJSON_Delete(json_obj); return RET_NOMEM; } s2j_struct_get_basic_element(br_if_conf, json_obj, int, config_type); *conf_type = br_if_conf->config_type; if(br_if_conf->config_type != CM_CONFIG_GET_ALL) { s2j_struct_get_string_element(br_if_conf, json_obj, string, br_name, BR_NAMSIZ); strncpy(br_if->br_name, br_if_conf->br_name, BR_NAMSIZ - 1); } if(br_if_conf->config_type == CM_CONFIG_ADD || br_if_conf->config_type == CM_CONFIG_DEL) { s2j_struct_get_array_string_n(br_if_conf, json_obj, string, ports, port_num, INTERFACE_NAMSIZ); br_if->port_num = port_num; br_if->ports = br_if_conf->ports; /*指针赋值,后续需要对该指针进行内存释放*/ br_if_conf->ports = NULL; } s2j_delete_struct_obj(br_if_conf); cJSON_Delete(json_obj); return RET_OK; } /* 桥配置钩子函数 */ ret_code br_config_chk(uint source,uint *config_type, pointer input, int *input_len, pointer output, int *output_len) { int config_len = 0; uint conf_type = CM_CONFIG_GET; char br_name[BR_NAMSIZ] = {0}; ret_code ret = RET_OK; int code = 0; br_config_json_parse(input, &conf_type, br_name); config_len = strlen(br_name) + 1; switch (conf_type) { case CM_CONFIG_ADD: case CM_CONFIG_DEL: case CM_CONFIG_GET: ret = br_name_chk(br_name); break; case CM_CONFIG_GET_ALL: break; default: ret = RET_NOTSUPPORT; } /* 将传入的json数据转换成结构体,便于后续处理 */ if(config_len <= CM_BUFF_SIZE) { memset(input, 0, *input_len); memcpy(input, br_name, config_len); *config_type = conf_type; *input_len = config_len; } else { ret = RET_NOMEM; } RET_ERR_FORMART(ret, code, output, *output_len); return ret; } ret_code br_config_proc(uint source, uint config_type, pointer input, int input_len, pointer output, int *output_len) { ret_code ret = RET_OK; int sys_ret = 0; char *br_name; br_name = (char *)input; if(config_type == CM_CONFIG_ADD) { ret = br_bridge_add(br_name, &sys_ret); } else if(config_type == CM_CONFIG_DEL) { ret = br_bridge_del(br_name, &sys_ret); } RET_ERR_FORMART(ret, sys_ret, output, *output_len); return ret; } /* 桥接口配置钩子函数 */ ret_code br_if_config_chk(uint source,uint *config_type, pointer input, int *input_len, pointer output, int *output_len) { ret_code ret = RET_OK; br_config_t br_config = {0}; br_config_t *temp_conf = NULL; int cfg_len = 0; br_if_config_json_parse(input, config_type, &br_config); cfg_len = BR_NAMSIZ + sizeof(br_config.port_num) + br_config.port_num * INTERFACE_NAMSIZ; if(cfg_len > CM_BUFF_SIZE) { ret = RET_NOMEM; goto exit; } ret = br_name_chk(br_config.br_name); if(ret != RET_OK) { goto exit; } if(br_is_exist(br_config.br_name) == false) { ret = RET_NOTFOUND; goto exit; } if(*config_type != CM_CONFIG_ADD && *config_type != CM_CONFIG_DEL) { ret = RET_INPUTERR; goto exit; } ret = br_if_bridge_check(br_config.ports, br_config.port_num, *config_type); if(ret != RET_OK) { goto exit; } memset(input, 0, *input_len); temp_conf = (br_config_t *)input; strncpy(temp_conf->br_name, br_config.br_name, BR_NAMSIZ - 1); temp_conf->port_num = br_config.port_num; memcpy(temp_conf->ports, br_config.ports, br_config.port_num * INTERFACE_NAMSIZ); *input_len = cfg_len; exit: RET_ERR_FORMART(ret, 0, output, *output_len); rpc_free(br_config.ports); return ret; } ret_code br_if_config_proc(uint source, uint config_type, pointer input, int input_len, pointer output, int *output_len) { br_config_t *br_conf = (br_config_t *)input; ret_code ret = RET_OK; int err = 0; if(config_type == CM_CONFIG_ADD) { ret = br_if_bridge_add(br_conf->br_name, br_conf->ports, br_conf->port_num, &err); } else if(config_type == CM_CONFIG_DEL) { ret = br_if_bridge_del(br_conf->br_name, br_conf->ports, br_conf->port_num, &err); } RET_ERR_FORMART(ret, err, output, *output_len); return ret; } ret_code br_if_config_get(uint source, pointer input, int input_len, pointer output, int *output_len) { ret_code ret = RET_OK; cJSON *json_obj = NULL; int err = 0; ret = br_bridge_info((char *)input, json_obj, &err); if(ret != RET_OK) { RET_ERR_FORMART(ret, err, output, *output_len); } else { *output_len = br_json_to_string(json_obj, output); } return ret; } ret_code br_if_config_get_all(uint source, pointer output, int *output_len) { cJSON *json_obj = NULL; ret_code ret = RET_OK; int err = 0; json_obj = cJSON_CreateArray(); if(json_obj == NULL) { ret = RET_NOMEM; RET_ERR_FORMART(RET_NOMEM, err, output, *output_len); return ret; } if(br_foreach_bridge(br_bridge_info_each, json_obj) > 0) { *output_len = br_json_to_string(json_obj, output); } return ret; } /* 桥FDB配置辅助函数 */ void br_format_time(const struct timeval *tv, char *str, int len) { snprintf(str, len, "%4i.%.2i", (int)tv->tv_sec, (int)tv->tv_usec/10000); } int br_compare_fdbs(const void *_f0, const void *_f1) { const struct fdb_entry *f0 = _f0; const struct fdb_entry *f1 = _f1; return memcmp(f0->mac_addr, f1->mac_addr, 6); } int br_get_if_from_portno(const char *brname, int port_no, char *ifname) { int ifindices[MAX_PORTS]; unsigned long args[4] = { BRCTL_GET_PORT_LIST, (unsigned long)ifindices, MAX_PORTS, 0 }; struct ifreq ifr; if (port_no >= MAX_PORTS) return -1; memset(ifindices, 0, sizeof(ifindices)); strncpy(ifr.ifr_name, brname, IFNAMSIZ); ifr.ifr_data = (char *) &args; if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) { dprintf("get_portno: get ports of %s failed: %s\n", brname, strerror(errno)); return -1; } if(if_indextoname(ifindices[port_no], ifname) == NULL) { return -1; } return 0; } int br_fdb_get(char *brname, struct fdb_entry **br_fdb) { struct fdb_entry *fdb; int i = 0, n = 0; int offset = 0; fdb = NULL; *br_fdb = NULL; for(;;) { fdb = realloc(fdb, (offset + FDB_CHUNK) * sizeof(struct fdb_entry)); if (!fdb) { rpc_log_error("Out of memory\n"); return offset; } *br_fdb = fdb; n = br_read_fdb(brname, fdb+offset, offset, FDB_CHUNK); if (n == 0) break; if (n < 0) { rpc_log_error( "read of forward table failed: %s\n", strerror(errno)); return offset; } offset += n; } qsort(fdb, offset, sizeof(struct fdb_entry), br_compare_fdbs); #if 0 printf("port no\tmac addr\t\tis local?\tageing timer\n"); for (i = 0; i < offset; i++) { const struct fdb_entry *f = fdb + i; printf("%3i\t", f->port_no); printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\t", f->mac_addr[0], f->mac_addr[1], f->mac_addr[2], f->mac_addr[3], f->mac_addr[4], f->mac_addr[5]); printf("%s\t\t", f->is_local?"yes":"no"); br_show_timer(&f->ageing_timer_value); printf("\n"); } #endif return offset; } int br_fdb_cpy(br_fdb_status_t *fdb_status, struct fdb_entry *fdb) { struct fdb_entry *temp_fdb; char if_name[INTERFACE_NAMSIZ]; int i = 0; for(i = 0; i < fdb_status->fdb_num && i < MAC_MAXIZS; i++) { temp_fdb = fdb + i; memset(if_name, 0, INTERFACE_NAMSIZ); if(br_get_if_from_portno(fdb_status->br_name, temp_fdb->port_no, if_name) != 0) { rpc_log_error("port no %d can not get ifname\n", temp_fdb->port_no); continue; } snprintf(fdb_status->fdb_info[i].mac_addr, MAC_STRSIZ, "%02x:%02x:%02x:%02x:%02x:%02x", temp_fdb->mac_addr[0], temp_fdb->mac_addr[1], temp_fdb->mac_addr[2], temp_fdb->mac_addr[3], temp_fdb->mac_addr[4], temp_fdb->mac_addr[5]); strncpy(fdb_status->fdb_info[i].port, if_name, INTERFACE_NAMSIZ - 1); if(temp_fdb->is_local) { strncpy(fdb_status->fdb_info[i].local, "true", LOCAL_STRSIZ - 1); } else { strncpy(fdb_status->fdb_info[i].local, "false", LOCAL_STRSIZ - 1); } br_format_time(&temp_fdb->ageing_timer_value, fdb_status->fdb_info[i].time, TIME_STRSIZ); } return i; } /* 桥FDB配置json格式转换 */ ret_code br_fdb_config_json_parse(pointer input, uint *conf_type, br_fdb_config_t *br_fdb) { cJSON *json_obj; int port_num = 0; json_obj = cJSON_Parse(input); if(!json_obj) { return RET_INPUTERR; } rpc_log_info("json input:\n %s\n", cJSON_Print(json_obj)); s2j_create_struct_obj(br_fdb_conf, br_fdb_string_t); if(br_fdb_conf == NULL) { cJSON_Delete(json_obj); return RET_NOMEM; } s2j_struct_get_string_element(br_fdb_conf, json_obj, string, br_name, BR_NAMSIZ); *conf_type = br_fdb_conf->config_type; strncpy(br_fdb->br_name, br_fdb_conf->br_name, BR_NAMSIZ - 1); s2j_delete_struct_obj(br_fdb_conf); cJSON_Delete(json_obj); return RET_OK; } ret_code br_each_fdb_to_json_string(cJSON *json_array, fdb_info_t *fdb_info) { cJSON *fdb_obj; s2j_create_json_obj(fdb_obj); if(fdb_obj == NULL) { return RET_NOMEM; } s2j_json_set_basic_element(fdb_obj, fdb_info, string, mac_addr); s2j_json_set_basic_element(fdb_obj, fdb_info, string, port); s2j_json_set_basic_element(fdb_obj, fdb_info, string, local); s2j_json_set_basic_element(fdb_obj, fdb_info, string, time); cJSON_AddItemToArray(json_array, fdb_obj); return RET_OK } int br_fdb_to_json_string(br_fdb_status_t *fdb_status, char *output) { cJSON *br_obj; cJSON *fdb_array; char *json_str; int i; s2j_create_json_obj(br_obj); fdb_array = cJSON_CreateArray(); if(br_obj == NULL || fdb_array) { return 0; } s2j_json_set_basic_element(br_obj, fdb_status, string, br_name); s2j_json_set_basic_element(br_obj, fdb_status, int, fdb_num); for(i = 0; i < fdb_status->fdb_num; i++) { br_each_fdb_to_json_string(fdb_array, &(fdb_status->fdb_info[i])); } cJSON_AddItemToObject(br_obj, "fdb", fdb_array); br_json_to_string(br_obj, output); return (strlen(output) + 1); } /* 桥FDB表配置钩子函数 */ ret_code br_fdb_config_chk(uint source,uint *config_type, pointer input, int *input_len, pointer output, int *output_len) { ret_code ret = RET_OK; br_fdb_config_t br_fdb = {0}; br_fdb_config_t *temp_conf; int cfg_len = 0; ret = br_fdb_config_json_parse(input, config_type, &br_fdb); if(ret != RET_OK) { RET_ERR_FORMART(ret, 0, output, *output_len); return ret; } if(*config_type != CM_CONFIG_GET) { ret = RET_INPUTERR; RET_ERR_FORMART(ret, 0, output, *output_len); return ret; } /* 回填解析过的数据 */ memset(input, 0, *input_len); temp_conf = (br_fdb_config_t *)input; strncpy(temp_conf->br_name, br_fdb.br_name, BR_NAMSIZ - 1); *input_len = cfg_len; return ret; } ret_code br_fdb_config_get(uint source, pointer input, int input_len, pointer output, int *output_len) { br_fdb_status_t *fdb_status; br_fdb_config_t *br_fdb; struct fdb_entry *fdb; ret_code ret = RET_OK; int err = 0; br_fdb = (br_fdb_config_t *)input; fdb_status = (br_fdb_status_t *)rpc_new0(br_fdb_status_t, 1); if(fdb_status == NULL) { ret = RET_NOMEM; RET_ERR_FORMART(ret, 0, output, *output_len); return ret; } strncpy(fdb_status->br_name, br_fdb->br_name, BR_NAMSIZ - 1); fdb_status->fdb_num = br_fdb_get(br_fdb->br_name, &fdb); fdb_status->fdb_num = br_fdb_cpy(fdb_status, fdb); *output_len = br_fdb_to_json_string(fdb_status, output); rpc_free(fdb); rpc_free(fdb_status); return ret; }