From 5390ed72086f1d9ffce2b4ca367daf2cbda4d358 Mon Sep 17 00:00:00 2001 From: hejingxian Date: Tue, 18 Feb 2020 14:49:31 +0800 Subject: [PATCH] feature: encapsulate and compile the functions in irqbalance-ui into a shared library users can send settings msg to irqbalance or get information from irqbalance by calling external functions in the shared library. Signed-off-by: Liu Chao Signed-off-by: He Jingxian --- irqbalance.c | 4 +- irqbalance.h | 1 + ui/Makefile | 29 ++++ ui/client.c | 435 +++++++++++++++++++++++++++++++++++++++++++++++++ ui/irqbalance-ui.c | 4 +- ui/irqbalance-ui.h | 1 + ui/irqbalance_client.h | 111 +++++++++++++ 7 files changed, 581 insertions(+), 4 deletions(-) create mode 100644 ui/Makefile create mode 100644 ui/client.c create mode 100644 ui/irqbalance_client.h diff --git a/irqbalance.c b/irqbalance.c index 1af23c6..7c79087 100644 --- a/irqbalance.c +++ b/irqbalance.c @@ -452,12 +452,12 @@ void get_object_stat(struct topo_obj *object, void *data) gboolean sock_handle(gint fd, GIOCondition condition, gpointer user_data __attribute__((unused))) { - char buff[500]; + char buff[SOCKET_RECV_BUF_LEN]; int sock; int recv_size = 0; int valid_user = 0; - struct iovec iov = { buff, 500 }; + struct iovec iov = { buff, SOCKET_RECV_BUF_LEN }; struct msghdr msg = { 0 }; msg.msg_iov = &iov; msg.msg_iovlen = 1; diff --git a/irqbalance.h b/irqbalance.h index b2e5409..842cead 100644 --- a/irqbalance.h +++ b/irqbalance.h @@ -175,6 +175,7 @@ extern unsigned int log_mask; #define SOCKET_PATH "irqbalance" #define SOCKET_TMPFS "/run/irqbalance" #define MAX_CLIENT_NUM 32 +#define SOCKET_RECV_BUF_LEN 4096 extern int process_one_line(char *path, void (*cb)(char *line, void *data), void *data); extern void get_mask_from_bitmap(char *line, void *mask); diff --git a/ui/Makefile b/ui/Makefile new file mode 100644 index 0000000..27e0fbf --- /dev/null +++ b/ui/Makefile @@ -0,0 +1,29 @@ +#!/bin/make +export SHELL = /bin/bash +DIR = $(shell pwd) +TARGET = libirqbalance_client.so + +RM = rm +CC = gcc + +SRC = $(wildcard $(DIR)/*.c) +OBJ = $(patsubst $(DIR)/%.c,$(DIR)/%.o,$(SRC)) + +INC = -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include +CFLAG = -g3 -Wall -fPIC -D_GNU_SOURCE -fstack-protector-strong -D_FORTIFY_SOURCE=2 -O2 -ftrapv +SHARED = -shared +LFLAG = -lglib-2.0 -lncursesw -z now -s + +CFLAG += $(INC) + +all: $(TARGET) + +$(TARGET): $(OBJ) + $(CC) $(SHARED) $(LFLAG) -o $@ $(OBJ) + +$(DIR)/%.o: $(DIR)/%.c + $(CC) $(CFLAG) -c $< -o $@ + +clean: + -$(RM) $(DIR)/*.o + -$(RM) $(TARGET) diff --git a/ui/client.c b/ui/client.c new file mode 100644 index 0000000..027404b --- /dev/null +++ b/ui/client.c @@ -0,0 +1,435 @@ +/* + * Copyright (C) 2020. Huawei Technologies Co., Ltd. All rights reserved. + * + * This program file is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License + * for more details. + */ +#include +#include +#include + +#include "irqbalance-ui.h" +#include "irqbalance_client.h" + +extern int irqbalance_pid; +extern GList *tree; + +void irqbalance_set_pid(int pid) +{ + irqbalance_pid = pid; +} + +/* + * string format: + * ... or NONE + */ +int irqbalance_set_ban_irqs(const char *irqs) +{ + char *data = NULL; + const char *tmp; + int ret = IRQBALANCE_SUCCESS; + int socket_fd = 0; + int i; + struct msghdr *msg = NULL; + struct iovec iov; + + if (irqs == NULL || strlen(irqs) == 0) { + ret = IRQBALANCE_INPUT_ILLEGAL; + goto out; + } + if (strncmp(irqs, "NONE", strlen("NONE"))) { + tmp = irqs; + for (i = 0; i < strlen(irqs); i++) { + if (*tmp != ' ' && (*tmp < '0' || *tmp > '9')) { + ret = IRQBALANCE_INPUT_ILLEGAL; + goto out; + } + tmp++; + } + } + + socket_fd = init_connection(); + if (!socket_fd) { + ret = IRQBALANCE_CONNECT_FAIL; + goto out; + } + + data = (char *)malloc(strlen(irqs) + strlen(BAN_IRQS) + 1); + if (!data) { + ret = IRQBALANCE_MALLOC_FAIL; + goto out; + } + msg = create_credentials_msg(); + if (!msg) { + ret = IRQBALANCE_MALLOC_FAIL; + goto out; + } + snprintf(data, strlen(irqs) + strlen(BAN_IRQS) + 1, + "%s%s", BAN_IRQS, irqs); + iov.iov_base = (void *) data; + iov.iov_len = strlen(data) + 1; + msg->msg_iov = &iov; + if (sendmsg(socket_fd, msg, 0) == -1) + ret = IRQBALANCE_SEND_FAIL; + +out: + if (socket_fd > 0) + close(socket_fd); + if (msg) + free(msg->msg_control); + free(msg); + free(data); + return ret; +} + +unsigned int char_to_hex(char c) +{ + unsigned int hex; + + if (c >= '0' && c <= '9') { + hex = c - '0'; + } else { + hex = c - 'a' + 10; + } + return hex; +} + +char *parse_cpus_to_cpulist(const char *cpus) +{ + int i, ret; + const char *tmp; + char *cpulist; + int cpus_len; + unsigned int hex; + int index; + + if (cpus == NULL + || strlen(cpus) == 0 + || strlen(cpus) > CPU_MASK_MAX_LEN) + return NULL; + + if (strncmp(cpus, "NULL", strlen("NULL"))) { + tmp = cpus; + cpus_len = strlen(cpus); + for (i = 0; i < cpus_len; i++) { + if ((*tmp < '0' || *tmp > '9') + && (*tmp < 'a' || *tmp > 'f')) + return NULL; + tmp++; + } + cpulist = (char *)malloc(CPU_LIST_MAX_LEN); + if (!cpulist) + return NULL; + cpulist[0] = 0; + for (i = 0; i < cpus_len; i++) { + hex = char_to_hex(cpus[cpus_len - 1 - i]); + index = 0; + while (hex) { + if (hex & 1) { + ret = snprintf(cpulist + strlen(cpulist), + CPU_LIST_MAX_LEN - strlen(cpulist), "%d,", (i << 2) + index); + if (ret < 0) + break; + } + index++; + hex = (hex >> 1); + } + } + } else { + cpulist = strdup(cpus); + } + return cpulist; +} + +/* + * string format: + * 00000001 or NULL + */ +int irqbalance_set_ban_cpus(const char *cpus) +{ + int socket_fd = 0; + int ret = IRQBALANCE_SUCCESS; + char *data = NULL; + char *cpulist = NULL; + struct msghdr *msg = NULL; + struct iovec iov; + + cpulist = parse_cpus_to_cpulist(cpus); + if(!cpulist) { + ret = IRQBALANCE_INPUT_ILLEGAL; + goto out; + } + + socket_fd = init_connection(); + if(!socket_fd) { + ret = IRQBALANCE_CONNECT_FAIL; + goto out; + } + + data = (char *)malloc(strlen(cpulist) + strlen(BAN_CPUS) + 1); + if (!data) { + ret = IRQBALANCE_MALLOC_FAIL; + goto out; + } + msg = create_credentials_msg(); + if (!msg) { + ret = IRQBALANCE_MALLOC_FAIL; + goto out; + } + snprintf(data, strlen(cpulist) + strlen(BAN_CPUS) + 1, + "%s%s", BAN_CPUS, cpulist); + iov.iov_base = (void *) data; + iov.iov_len = strlen(data) + 1; + msg->msg_iov = &iov; + if (sendmsg(socket_fd, msg, 0) == -1) + ret = IRQBALANCE_SEND_FAIL; + +out: + if (socket_fd) + close(socket_fd); + if (msg) + free(msg->msg_control); + free(msg); + free(data); + free(cpulist); + return ret; +} + +int irqbalance_set_sleep_interval(int sleep) +{ + char data[DATA_BUF_MAX_LEN]; + int ret = IRQBALANCE_SUCCESS; + int socket_fd = 0; + struct msghdr *msg = NULL; + struct iovec iov; + + if (sleep < 1) { + ret = IRQBALANCE_INPUT_ILLEGAL; + goto out; + } + + socket_fd = init_connection(); + if(!socket_fd) { + ret = IRQBALANCE_CONNECT_FAIL; + goto out; + } + + msg = create_credentials_msg(); + if (!msg) { + ret = IRQBALANCE_MALLOC_FAIL; + goto out; + } + snprintf(data, DATA_BUF_MAX_LEN, "%s %d", SET_SLEEP, sleep); + iov.iov_base = (void *) data; + iov.iov_len = strlen(data) + 1; + msg->msg_iov = &iov; + if (sendmsg(socket_fd, msg, 0) == -1) + ret = IRQBALANCE_SEND_FAIL; + +out: + if (socket_fd) + close(socket_fd); + if (msg) + free(msg->msg_control); + free(msg); + return ret; +} + +void free_banned_irq_list(irqbalance_banned_irq_list_t *list_head) +{ + irqbalance_banned_irq_list_t *banned_irq = list_head; + irqbalance_banned_irq_list_t *next_banned_irq; + + while (banned_irq) { + next_banned_irq = banned_irq->next; + free(banned_irq); + banned_irq = next_banned_irq; + } +} + +/* get user setup info, including sleep setting, banned irqs and banned cpus info */ +irqbalance_setup_t *irqbalance_get_setup_info() +{ + char *token, *ptr, *setup_info; + char *copy = NULL; + char *scan; + int i, sleep, setup_size; + int ban_irq_num = 0; + int ban_irq_size = sizeof(irqbalance_banned_irq_t); + irqbalance_setup_t *setup_data = NULL; + irqbalance_banned_irq_list_t *banned_irq = NULL; + irqbalance_banned_irq_list_t *list_head = NULL; + + setup_info = get_data(SETUP); + if (setup_info == NULL || strlen(setup_info) == 0) + return NULL; + copy = strdup(setup_info); + if (!copy) + goto out; + + token = strtok_r(copy, " ", &ptr); + if (!token) + goto out; + if(strncmp(token, "SLEEP", strlen("SLEEP"))) + goto out; + scan = strtok_r(NULL, " ", &ptr); + if (!scan) + goto out; + sleep = strtol(scan, NULL, 10); + token = strtok_r(NULL, " ", &ptr); + while(token && !strncmp(token, "IRQ", strlen("IRQ"))) { + banned_irq = (irqbalance_banned_irq_list_t *)malloc(sizeof(irqbalance_banned_irq_list_t)); + if (!banned_irq) + goto out; + scan = strtok_r(NULL, " ", &ptr); + if (!scan) + goto out; + banned_irq->irq = strtol(scan, NULL, 10); + token = strtok_r(NULL, " ", &ptr); + if (!token || strncmp(token, "LOAD", strlen("LOAD"))) + goto out; + scan = strtok_r(NULL, " ", &ptr); + if (!scan) + goto out; + banned_irq->load = strtol(scan, NULL, 10); + token = strtok_r(NULL, " ", &ptr); + if (!token || strncmp(token, "DIFF", strlen("DIFF"))) + goto out; + scan = strtok_r(NULL, " ", &ptr); + if (!scan) + goto out; + banned_irq->diff = strtol(scan, NULL, 10); + token = strtok_r(ptr, " ", &ptr); + if (!token || strncmp(token, "CLASS", strlen("CLASS"))) + goto out; + scan = strtok_r(NULL, " ", &ptr); + if (!scan) + goto out; + banned_irq->class = strtol(scan, NULL, 10); + banned_irq->next = list_head; + list_head = banned_irq; + ban_irq_num++; + token = strtok_r(NULL, " ", &ptr); + banned_irq = NULL; + } + if (ban_irq_num > 1) + setup_size = sizeof(irqbalance_setup_t) + (ban_irq_num - 1) * ban_irq_size; + else + setup_size = sizeof(irqbalance_setup_t); + setup_data = (irqbalance_setup_t *)malloc(setup_size); + if (!setup_data) + goto out; + memset(setup_data->banned_cpus, 0, NR_CPUS + 1); + setup_data->sleep = sleep; + setup_data->ban_irq_num = ban_irq_num; + banned_irq = list_head; + for (i = ban_irq_num; i > 0; i--) { + memcpy(&(setup_data->banned_irqs[i - 1]), banned_irq, ban_irq_size); + banned_irq = banned_irq->next; + } + if(strncmp(token, "BANNED", strlen("BANNED"))) + goto out; + token = strtok_r(NULL, " ", &ptr); + if (strlen(token) > NR_CPUS) + goto out; + strcpy(setup_data->banned_cpus, token); +out: + free(setup_info); + free(copy); + free_banned_irq_list(list_head); + return setup_data; +} + +/* the type of the GList pointer data is irqbalance_cpu_node_t*/ +GList *irqbalance_get_stats_info() +{ + char *stats_data; + + stats_data = get_data(STATS); + if (stats_data == NULL) + return NULL; + parse_into_tree(stats_data); + free(stats_data); + return tree; +} + +/* get banned cpus mask */ +char *irqbalance_get_banned_cpus() +{ + char *setup_info; + char *copy; + char *bancpu_str; + + setup_info = get_data(SETUP); + if (setup_info == NULL) + return NULL; + bancpu_str = strstr(setup_info, "BANNED"); + if (bancpu_str == NULL) { + free(setup_info); + return NULL; + } + copy = strdup(bancpu_str + strlen("BANNED") + 1); + free(setup_info); + return copy; +} + +/* get banned irqs string */ +char *irqbalance_get_banned_irqs() +{ + char *setup_info; + char *copy; + char *start_ptr, *end_ptr; + char *ret_str, *temp, *last_temp;; + + setup_info = get_data(SETUP); + if (setup_info == NULL) + return NULL; + start_ptr = strstr(setup_info, "IRQ"); + if (start_ptr == NULL) { + free(setup_info); + return NULL; + } + copy = strdup(start_ptr); + free(setup_info); + if (copy == NULL) + return NULL; + end_ptr = strstr(copy, "BANNED"); + if (end_ptr) + *end_ptr = '\0'; + + ret_str = (char*)malloc(strlen(copy) + 1); + if (ret_str == NULL) { + free(copy); + return NULL; + } + memset(ret_str, 0, strlen(copy) + 1); + temp = copy + strlen("IRQ") + 1; + last_temp = temp; + while (*temp) { + temp = strstr(last_temp, " "); + if (temp) + *temp = '\0'; + else + break; + strcat(ret_str, last_temp); + strcat(ret_str, " "); + last_temp = strstr(temp + 1, "IRQ"); + if (last_temp == NULL) + break; + last_temp = last_temp + strlen("IRQ") + 1; + temp = last_temp; + } + free(copy); + if (strlen(ret_str) == 0) { + free(ret_str); + return NULL; + } + return ret_str; +} + diff --git a/ui/irqbalance-ui.c b/ui/irqbalance-ui.c index 943f008..f0deaf8 100644 --- a/ui/irqbalance-ui.c +++ b/ui/irqbalance-ui.c @@ -120,8 +120,8 @@ char * get_data(char *string) * With a select, ioctl to determine size, and malloc based * on that */ - char *data = malloc(8192); - int len = recv(socket_fd, data, 8192, 0); + char *data = malloc(RECV_BUF_SIZE); + int len = recv(socket_fd, data, RECV_BUF_SIZE, 0); close(socket_fd); data[len] = '\0'; free(msg->msg_control); diff --git a/ui/irqbalance-ui.h b/ui/irqbalance-ui.h index b32d58a..503c0c5 100644 --- a/ui/irqbalance-ui.h +++ b/ui/irqbalance-ui.h @@ -26,6 +26,7 @@ #define IRQ_10GBETH 6 #define IRQ_VIRT_EVENT 7 +#define RECV_BUF_SIZE (4096 * 8) /* Typedefs */ diff --git a/ui/irqbalance_client.h b/ui/irqbalance_client.h new file mode 100644 index 0000000..8f18b79 --- /dev/null +++ b/ui/irqbalance_client.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2020. Huawei Technologies Co., Ltd. All rights reserved. + * + * This program file is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License + * for more details. + */ +#include +#include + +#ifndef IRQBALANCE_CLIENT_H +#define IRQBALANCE_CLIENT_H + +/* ERRORNO */ +#define IRQBALANCE_SUCCESS 0 +#define IRQBALANCE_INPUT_ILLEGAL 1 +#define IRQBALANCE_CONNECT_FAIL 2 +#define IRQBALANCE_SEND_FAIL 3 +#define IRQBALANCE_MALLOC_FAIL 4 + +#define BAN_CPUS "settings cpus " +#define DATA_BUF_MAX_LEN 128 +#define NR_CPUS 1024 +#define CPU_LIST_MAX_LEN 4096 +#define CPU_MASK_MAX_LEN 256 + +typedef enum irqbalance_node_type { + IRQ_OBJ_TYPE_CPU, + IRQ_OBJ_TYPE_CACHE, + IRQ_OBJ_TYPE_PACKAGE, + IRQ_OBJ_TYPE_NODE +} irqbalance_node_type_e; + +typedef struct irqbalance_irq { + int vector; + unsigned long load; + unsigned long diff; + char is_banned; + GList *assigned_to; + int class; +} irqbalance_irq_t; + +typedef struct irqbalance_cpu_node { + irqbalance_node_type_e type; + int number; + unsigned long load; + int is_powersave; + struct irqbalance_cpu_node *parent; + GList *children; + GList *irqs; + GList *cpu_list; + char *cpu_mask; +} irqbalance_cpu_node_t; + +typedef struct irqbalance_banned_irq_list { + int irq; + int class; + unsigned long load; + unsigned long diff; + struct irqbalance_banned_irq_list *next; +} irqbalance_banned_irq_list_t; + +typedef struct irqbalance_banned_irq_info { + int irq; + int class; + unsigned long load; + unsigned long diff; +} irqbalance_banned_irq_t; + +typedef struct irqbalance_setup_data { + int sleep; + char banned_cpus[NR_CPUS + 1]; + int ban_irq_num; + irqbalance_banned_irq_t banned_irqs[1]; +} irqbalance_setup_t; + +/* + * set_ban_irqs string format: + * ... or NONE + * */ +int irqbalance_set_ban_irqs(const char *irqs); + +/* + * set_ban_cpus string format: + * 00000001 or NULL + * */ +int irqbalance_set_ban_cpus(const char *cpus); + +/* set sleep interval of irqbalance main loop */ +int irqbalance_set_sleep_interval(int sleep); + +/* get user setup info, including sleep setting, banned irqs and banned cpus info */ +irqbalance_setup_t *irqbalance_get_setup_info(); + +/* get irqbalance stats tree */ +GList *irqbalance_get_stats_info(); + +/* get banned cpus mask */ +char *irqbalance_get_banned_cpus(); + +/* get banned irqs string */ +char *irqbalance_get_banned_irqs(); + +/* set the pid of irqbalance server */ +void irqbalance_set_pid(int pid); +#endif -- 1.8.3.1