827 lines
25 KiB
Diff
827 lines
25 KiB
Diff
|
|
From a7d86761f9c66eb6fb6d13b77e753d6c42b90e12 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Zengruan Ye <yezengruan@huawei.com>
|
||
|
|
Date: Tue, 16 Jul 2019 00:07:36 +0800
|
||
|
|
Subject: [PATCH 6/6] feature: irqbalance: Add ability for socket communication
|
||
|
|
|
||
|
|
This will be used with user interface and also can be used as API for users
|
||
|
|
to create their own scripts on top of. The socket communication can be used
|
||
|
|
for receiving data about IRQs-to-CPUs assignments and setup, as well as
|
||
|
|
setting some options during runtime.
|
||
|
|
|
||
|
|
Socket address: /var/run/uvp_irqbalance.socket
|
||
|
|
|
||
|
|
Data to send to socket:
|
||
|
|
settings sleep <int>: set new sleep interval value
|
||
|
|
settings cpus <cpumask> <cpumask> ... : ban listed CPUs from
|
||
|
|
IRQ handling (old values are forgotten, not added to)
|
||
|
|
settings ban irqs <irq1> <irq2> ... : ban listed IRQs from balancing (old
|
||
|
|
values are forgotten, not added to)
|
||
|
|
|
||
|
|
Signed-off-by: Xu Yandong <xuyandong2@huawei.com>
|
||
|
|
---
|
||
|
|
Makefile.am | 6 +-
|
||
|
|
classify.c | 20 ++-
|
||
|
|
cputree.c | 5 +-
|
||
|
|
irqbalance.c | 164 ++----------------------
|
||
|
|
irqbalance.h | 2 +
|
||
|
|
sockapi.c | 400 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
|
sockapi.h | 18 +++
|
||
|
|
7 files changed, 452 insertions(+), 163 deletions(-)
|
||
|
|
create mode 100644 sockapi.c
|
||
|
|
create mode 100644 sockapi.h
|
||
|
|
|
||
|
|
diff --git a/Makefile.am b/Makefile.am
|
||
|
|
index abf1e8d..62ac482 100644
|
||
|
|
--- a/Makefile.am
|
||
|
|
+++ b/Makefile.am
|
||
|
|
@@ -30,7 +30,7 @@ UI_DIR = ui
|
||
|
|
AM_CFLAGS = $(LIBCAP_NG_CFLAGS) $(GLIB2_CFLAGS)
|
||
|
|
AM_CPPFLAGS = -I${top_srcdir} -W -Wall -Wshadow -Wformat -Wundef -D_GNU_SOURCE
|
||
|
|
noinst_HEADERS = bitmap.h constants.h cpumask.h irqbalance.h non-atomic.h \
|
||
|
|
- types.h $(UI_DIR)/helpers.h $(UI_DIR)/irqbalance-ui.h $(UI_DIR)/ui.h
|
||
|
|
+ types.h sockapi.h $(UI_DIR)/helpers.h $(UI_DIR)/irqbalance-ui.h $(UI_DIR)/ui.h
|
||
|
|
sbin_PROGRAMS = irqbalance
|
||
|
|
|
||
|
|
if IRQBALANCEUI
|
||
|
|
@@ -38,8 +38,8 @@ sbin_PROGRAMS += irqbalance-ui
|
||
|
|
endif
|
||
|
|
|
||
|
|
irqbalance_SOURCES = activate.c bitmap.c classify.c cputree.c irqbalance.c \
|
||
|
|
- irqlist.c numa.c placement.c procinterrupts.c
|
||
|
|
-irqbalance_LDADD = $(LIBCAP_NG_LIBS) $(GLIB2_LIBS)
|
||
|
|
+ irqlist.c numa.c placement.c procinterrupts.c sockapi.c
|
||
|
|
+irqbalance_LDADD = $(LIBCAP_NG_LIBS) $(GLIB2_LIBS) -lpthread
|
||
|
|
if IRQBALANCEUI
|
||
|
|
irqbalance_ui_SOURCES = $(UI_DIR)/helpers.c $(UI_DIR)/irqbalance-ui.c \
|
||
|
|
$(UI_DIR)/ui.c
|
||
|
|
diff --git a/classify.c b/classify.c
|
||
|
|
index 52fd74a..1e277c4 100644
|
||
|
|
--- a/classify.c
|
||
|
|
+++ b/classify.c
|
||
|
|
@@ -37,7 +37,10 @@ static GList *interrupts_db = NULL;
|
||
|
|
static GList *banned_irqs = NULL;
|
||
|
|
GList *cl_banned_irqs = NULL;
|
||
|
|
static GList *cl_banned_modules = NULL;
|
||
|
|
-static GList *vm_banned_irqs = NULL;
|
||
|
|
+GList *vm_banned_irqs = NULL;
|
||
|
|
+
|
||
|
|
+pthread_mutex_t cl_banned_list_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||
|
|
+pthread_mutex_t vm_banned_list_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||
|
|
|
||
|
|
#define SYSFS_DIR "/sys"
|
||
|
|
#define SYSPCI_DIR "/sys/bus/pci/devices"
|
||
|
|
@@ -299,12 +302,16 @@ void add_banned_list_irq(int irq)
|
||
|
|
|
||
|
|
void add_cl_banned_irq(int irq)
|
||
|
|
{
|
||
|
|
+ irqbalance_mutex_lock(&cl_banned_list_mutex);
|
||
|
|
add_banned_irq(irq, &cl_banned_irqs, 0);
|
||
|
|
+ irqbalance_mutex_unlock(&cl_banned_list_mutex);
|
||
|
|
}
|
||
|
|
|
||
|
|
void add_vm_banned_irq(int irq)
|
||
|
|
{
|
||
|
|
+ irqbalance_mutex_lock(&vm_banned_list_mutex);
|
||
|
|
add_banned_irq(irq, &vm_banned_irqs, IRQ_FLAG_VM_BANNED);
|
||
|
|
+ irqbalance_mutex_unlock(&vm_banned_list_mutex);
|
||
|
|
}
|
||
|
|
|
||
|
|
static int is_banned_irq(int irq)
|
||
|
|
@@ -314,7 +321,9 @@ static int is_banned_irq(int irq)
|
||
|
|
|
||
|
|
find.irq = irq;
|
||
|
|
|
||
|
|
+ irqbalance_mutex_lock(&vm_banned_list_mutex);
|
||
|
|
entry = g_list_find_custom(vm_banned_irqs, &find, compare_ints);
|
||
|
|
+ irqbalance_mutex_unlock(&vm_banned_list_mutex);
|
||
|
|
if (!entry)
|
||
|
|
entry = g_list_find_custom(banned_irqs, &find, compare_ints);
|
||
|
|
|
||
|
|
@@ -586,7 +595,9 @@ static int check_for_irq_ban(char *path __attribute__((unused)), int irq, GList
|
||
|
|
* Check to see if we banned this irq on the command line
|
||
|
|
*/
|
||
|
|
find.irq = irq;
|
||
|
|
+ irqbalance_mutex_lock(&cl_banned_list_mutex);
|
||
|
|
entry = g_list_find_custom(cl_banned_irqs, &find, compare_ints);
|
||
|
|
+ irqbalance_mutex_unlock(&cl_banned_list_mutex);
|
||
|
|
if (entry)
|
||
|
|
return 1;
|
||
|
|
|
||
|
|
@@ -821,9 +832,11 @@ void free_irq_db(void)
|
||
|
|
banned_irqs = NULL;
|
||
|
|
g_list_free(rebalance_irq_list);
|
||
|
|
rebalance_irq_list = NULL;
|
||
|
|
+ irqbalance_mutex_lock(&vm_banned_list_mutex);
|
||
|
|
for_each_irq(vm_banned_irqs, free_irq, NULL);
|
||
|
|
g_list_free(vm_banned_irqs);
|
||
|
|
vm_banned_irqs = NULL;
|
||
|
|
+ irqbalance_mutex_unlock(&vm_banned_list_mutex);
|
||
|
|
}
|
||
|
|
|
||
|
|
void free_cl_opts(void)
|
||
|
|
@@ -918,8 +931,11 @@ struct irq_info *get_irq_info(int irq)
|
||
|
|
find.irq = irq;
|
||
|
|
entry = g_list_find_custom(interrupts_db, &find, compare_ints);
|
||
|
|
|
||
|
|
- if (!entry)
|
||
|
|
+ if (!entry) {
|
||
|
|
+ irqbalance_mutex_lock(&vm_banned_list_mutex);
|
||
|
|
entry = g_list_find_custom(vm_banned_irqs, &find, compare_ints);
|
||
|
|
+ irqbalance_mutex_unlock(&vm_banned_list_mutex);
|
||
|
|
+ }
|
||
|
|
|
||
|
|
if (!entry)
|
||
|
|
entry = g_list_find_custom(banned_irqs, &find, compare_ints);
|
||
|
|
diff --git a/cputree.c b/cputree.c
|
||
|
|
index 5551784..0dbb5c8 100644
|
||
|
|
--- a/cputree.c
|
||
|
|
+++ b/cputree.c
|
||
|
|
@@ -39,6 +39,7 @@
|
||
|
|
#include "irqbalance.h"
|
||
|
|
|
||
|
|
extern char *banned_cpumask_from_ui;
|
||
|
|
+extern int is_set_banned_cpumask_from_ui;
|
||
|
|
|
||
|
|
GList *cpus;
|
||
|
|
GList *cache_domains;
|
||
|
|
@@ -77,8 +78,8 @@ static void setup_banned_cpus(void)
|
||
|
|
cpus_clear(nohz_full);
|
||
|
|
|
||
|
|
/* A manually specified cpumask overrides auto-detection. */
|
||
|
|
- if (banned_cpumask_from_ui != NULL) {
|
||
|
|
- cpulist_parse(banned_cpumask_from_ui,
|
||
|
|
+ if (is_set_banned_cpumask_from_ui) {
|
||
|
|
+ cpumask_parse_user(banned_cpumask_from_ui,
|
||
|
|
strlen(banned_cpumask_from_ui), banned_cpus);
|
||
|
|
goto out;
|
||
|
|
}
|
||
|
|
diff --git a/irqbalance.c b/irqbalance.c
|
||
|
|
index 27cf2eb..6e9de88 100644
|
||
|
|
--- a/irqbalance.c
|
||
|
|
+++ b/irqbalance.c
|
||
|
|
@@ -34,6 +34,7 @@
|
||
|
|
#include <sys/socket.h>
|
||
|
|
#include <sys/un.h>
|
||
|
|
#include <fcntl.h>
|
||
|
|
+#include <pthread.h>
|
||
|
|
#ifdef HAVE_GETOPT_LONG
|
||
|
|
#include <getopt.h>
|
||
|
|
#endif
|
||
|
|
@@ -42,6 +43,7 @@
|
||
|
|
#include <cap-ng.h>
|
||
|
|
#endif
|
||
|
|
#include "irqbalance.h"
|
||
|
|
+#include "sockapi.h"
|
||
|
|
|
||
|
|
volatile int keep_going = 1;
|
||
|
|
volatile int ban_pci_assigned_irq = 1;
|
||
|
|
@@ -430,160 +432,6 @@ 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];
|
||
|
|
- int sock;
|
||
|
|
- int recv_size = 0;
|
||
|
|
- int valid_user = 0;
|
||
|
|
-
|
||
|
|
- struct iovec iov = { buff, 500 };
|
||
|
|
- struct msghdr msg = { 0 };
|
||
|
|
- msg.msg_iov = &iov;
|
||
|
|
- msg.msg_iovlen = 1;
|
||
|
|
- msg.msg_control = malloc(CMSG_SPACE(sizeof(struct ucred)));
|
||
|
|
- msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
|
||
|
|
-
|
||
|
|
- struct cmsghdr *cmsg;
|
||
|
|
-
|
||
|
|
- if (condition == G_IO_IN) {
|
||
|
|
- sock = accept(fd, NULL, NULL);
|
||
|
|
- if (sock < 0) {
|
||
|
|
- log(TO_ALL, LOG_WARNING, "Connection couldn't be accepted.\n");
|
||
|
|
- goto out;
|
||
|
|
- }
|
||
|
|
- if ((recv_size = recvmsg(sock, &msg, 0)) < 0) {
|
||
|
|
- log(TO_ALL, LOG_WARNING, "Error while receiving data.\n");
|
||
|
|
- goto out_close;
|
||
|
|
- }
|
||
|
|
- cmsg = CMSG_FIRSTHDR(&msg);
|
||
|
|
- if ((cmsg->cmsg_level == SOL_SOCKET) &&
|
||
|
|
- (cmsg->cmsg_type == SCM_CREDENTIALS)) {
|
||
|
|
- struct ucred *credentials = (struct ucred *) CMSG_DATA(cmsg);
|
||
|
|
- if (!credentials->uid) {
|
||
|
|
- valid_user = 1;
|
||
|
|
- }
|
||
|
|
- }
|
||
|
|
- if (!valid_user) {
|
||
|
|
- log(TO_ALL, LOG_INFO, "Permission denied for user to connect to socket.\n");
|
||
|
|
- goto out_close;
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- if (!strncmp(buff, "stats", strlen("stats"))) {
|
||
|
|
- char *stats = NULL;
|
||
|
|
- for_each_object(numa_nodes, get_object_stat, &stats);
|
||
|
|
- send(sock, stats, strlen(stats), 0);
|
||
|
|
- free(stats);
|
||
|
|
- }
|
||
|
|
- if (!strncmp(buff, "settings ", strlen("settings "))) {
|
||
|
|
- if (!(strncmp(buff + strlen("settings "), "sleep ",
|
||
|
|
- strlen("sleep ")))) {
|
||
|
|
- char *sleep_string = malloc(
|
||
|
|
- sizeof(char) * (recv_size - strlen("settings sleep ")));
|
||
|
|
- strncpy(sleep_string, buff + strlen("settings sleep "),
|
||
|
|
- recv_size - strlen("settings sleep "));
|
||
|
|
- int new_iterval = strtoul(sleep_string, NULL, 10);
|
||
|
|
- if (new_iterval >= 1) {
|
||
|
|
- sleep_interval = new_iterval;
|
||
|
|
- }
|
||
|
|
- free(sleep_string);
|
||
|
|
- } else if (!(strncmp(buff + strlen("settings "), "ban irqs ",
|
||
|
|
- strlen("ban irqs ")))) {
|
||
|
|
- char *end;
|
||
|
|
- char *irq_string = malloc(
|
||
|
|
- sizeof(char) * (recv_size - strlen("settings ban irqs ")));
|
||
|
|
- strncpy(irq_string, buff + strlen("settings ban irqs "),
|
||
|
|
- recv_size - strlen("settings ban irqs "));
|
||
|
|
- g_list_free_full(cl_banned_irqs, free);
|
||
|
|
- cl_banned_irqs = NULL;
|
||
|
|
- need_rescan = 1;
|
||
|
|
- if (!strncmp(irq_string, "NONE", strlen("NONE"))) {
|
||
|
|
- free(irq_string);
|
||
|
|
- goto out_close;
|
||
|
|
- }
|
||
|
|
- int irq = strtoul(irq_string, &end, 10);
|
||
|
|
- do {
|
||
|
|
- add_cl_banned_irq(irq);
|
||
|
|
- } while((irq = strtoul(end, &end, 10)));
|
||
|
|
- free(irq_string);
|
||
|
|
- } else if (!(strncmp(buff + strlen("settings "), "cpus ",
|
||
|
|
- strlen("cpus")))) {
|
||
|
|
- char *cpu_ban_string = malloc(
|
||
|
|
- sizeof(char) * (recv_size - strlen("settings cpus ")));
|
||
|
|
- strncpy(cpu_ban_string, buff + strlen("settings cpus "),
|
||
|
|
- recv_size - strlen("settings cpus "));
|
||
|
|
- banned_cpumask_from_ui = strtok(cpu_ban_string, " ");
|
||
|
|
- if (!strncmp(banned_cpumask_from_ui, "NULL", strlen("NULL"))) {
|
||
|
|
- banned_cpumask_from_ui = NULL;
|
||
|
|
- }
|
||
|
|
- need_rescan = 1;
|
||
|
|
- free(cpu_ban_string);
|
||
|
|
- }
|
||
|
|
- }
|
||
|
|
- if (!strncmp(buff, "setup", strlen("setup"))) {
|
||
|
|
- char banned[512];
|
||
|
|
- char *setup = calloc(strlen("SLEEP ") + 11 + 1, 1);
|
||
|
|
- snprintf(setup, strlen("SLEEP ") + 11 + 1, "SLEEP %d ", sleep_interval);
|
||
|
|
- if(g_list_length(cl_banned_irqs) > 0) {
|
||
|
|
- for_each_irq(cl_banned_irqs, get_irq_data, setup);
|
||
|
|
- }
|
||
|
|
- cpumask_scnprintf(banned, 512, banned_cpus);
|
||
|
|
- setup = realloc(setup, strlen(setup) + strlen(banned) + 7 + 1);
|
||
|
|
- snprintf(setup + strlen(setup), strlen(banned) + 7 + 1,
|
||
|
|
- "BANNED %s", banned);
|
||
|
|
- send(sock, setup, strlen(setup), 0);
|
||
|
|
- free(setup);
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
-out_close:
|
||
|
|
- close(sock);
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
-out:
|
||
|
|
- free(msg.msg_control);
|
||
|
|
- return TRUE;
|
||
|
|
-}
|
||
|
|
-
|
||
|
|
-int init_socket()
|
||
|
|
-{
|
||
|
|
- struct sockaddr_un addr;
|
||
|
|
- memset(&addr, 0, sizeof(struct sockaddr_un));
|
||
|
|
-
|
||
|
|
- socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
|
||
|
|
- if (socket_fd < 0) {
|
||
|
|
- log(TO_ALL, LOG_WARNING, "Socket couldn't be created.\n");
|
||
|
|
- return 1;
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- /*
|
||
|
|
- * First try to create a file-based socket in tmpfs. If that doesn't
|
||
|
|
- * succeed, fall back to an abstract socket (non file-based).
|
||
|
|
- */
|
||
|
|
- addr.sun_family = AF_UNIX;
|
||
|
|
- snprintf(socket_name, 64, "%s/%s%d.sock", SOCKET_TMPFS, SOCKET_PATH, getpid());
|
||
|
|
- strncpy(addr.sun_path, socket_name, sizeof(addr.sun_path));
|
||
|
|
- if (bind(socket_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||
|
|
- log(TO_ALL, LOG_WARNING, "Daemon couldn't be bound to the file-based socket.\n");
|
||
|
|
-
|
||
|
|
- /* Try binding to abstract */
|
||
|
|
- memset(&addr, 0, sizeof(struct sockaddr_un));
|
||
|
|
- addr.sun_family = AF_UNIX;
|
||
|
|
- if (bind(socket_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||
|
|
- log(TO_ALL, LOG_WARNING, "Daemon couldn't be bound to the abstract socket, bailing out.\n");
|
||
|
|
- return 1;
|
||
|
|
- }
|
||
|
|
- }
|
||
|
|
-
|
||
|
|
- int optval = 1;
|
||
|
|
- if (setsockopt(socket_fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) < 0) {
|
||
|
|
- log(TO_ALL, LOG_WARNING, "Unable to set socket options.\n");
|
||
|
|
- return 1;
|
||
|
|
- }
|
||
|
|
- listen(socket_fd, 1);
|
||
|
|
- g_unix_fd_add(socket_fd, G_IO_IN, sock_handle, NULL);
|
||
|
|
- return 0;
|
||
|
|
-}
|
||
|
|
-
|
||
|
|
static int create_lock_pidfile(const char *lockfile)
|
||
|
|
{
|
||
|
|
struct flock lock = { 0 };
|
||
|
|
@@ -657,7 +505,9 @@ error_close:
|
||
|
|
|
||
|
|
int main(int argc, char** argv)
|
||
|
|
{
|
||
|
|
- struct sigaction action, hupaction;
|
||
|
|
+ int err;
|
||
|
|
+ pthread_t socket_tid;
|
||
|
|
+ struct sigaction action, hupaction;
|
||
|
|
sigset_t sigset, old_sigset;
|
||
|
|
|
||
|
|
sigemptyset(&sigset);
|
||
|
|
@@ -781,7 +631,9 @@ int main(int argc, char** argv)
|
||
|
|
parse_proc_interrupts();
|
||
|
|
parse_proc_stat();
|
||
|
|
|
||
|
|
- if (init_socket()) {
|
||
|
|
+ err = pthread_create(&socket_tid, NULL, &handle_socket_api_event, NULL);
|
||
|
|
+ if (0 != err) {
|
||
|
|
+ log(TO_CONSOLE, LOG_WARNING, "WARNING: Failed to create irqbalance socket thread, return %d.\n", err);
|
||
|
|
return EXIT_FAILURE;
|
||
|
|
}
|
||
|
|
|
||
|
|
diff --git a/irqbalance.h b/irqbalance.h
|
||
|
|
index 339e2a3..f9b554e 100644
|
||
|
|
--- a/irqbalance.h
|
||
|
|
+++ b/irqbalance.h
|
||
|
|
@@ -44,6 +44,8 @@ extern void set_msi_interrupt_numa(int number);
|
||
|
|
|
||
|
|
extern GList *rebalance_irq_list;
|
||
|
|
|
||
|
|
+void irqbalance_mutex_lock(pthread_mutex_t *lock);
|
||
|
|
+void irqbalance_mutex_unlock(pthread_mutex_t *lock);
|
||
|
|
void update_migration_status(void);
|
||
|
|
void dump_workloads(void);
|
||
|
|
void sort_irq_list(GList **list);
|
||
|
|
diff --git a/sockapi.c b/sockapi.c
|
||
|
|
new file mode 100644
|
||
|
|
index 0000000..4a0e683
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/sockapi.c
|
||
|
|
@@ -0,0 +1,410 @@
|
||
|
|
+/*
|
||
|
|
+ * Copyright (C) 2019. Huawei Technologies Co., Ltd. All rights reserved.
|
||
|
|
+ *
|
||
|
|
+ * This program is free software; you can redistribute it and/or modify
|
||
|
|
+ * it under the terms of the MuLan PSL v1.
|
||
|
|
+ *
|
||
|
|
+ * 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 MuLan PSL v1 for more details.
|
||
|
|
+ */
|
||
|
|
+#include <stdio.h>
|
||
|
|
+#include <stdlib.h>
|
||
|
|
+#include <unistd.h>
|
||
|
|
+#include <string.h>
|
||
|
|
+#include <ctype.h>
|
||
|
|
+#include <errno.h>
|
||
|
|
+#include <fcntl.h>
|
||
|
|
+#include <sys/time.h>
|
||
|
|
+#include <sys/types.h>
|
||
|
|
+#include <sys/socket.h>
|
||
|
|
+#include <sys/un.h>
|
||
|
|
+#include <sys/epoll.h>
|
||
|
|
+#include <pthread.h>
|
||
|
|
+
|
||
|
|
+#include "sockapi.h"
|
||
|
|
+#include "irqbalance.h"
|
||
|
|
+
|
||
|
|
+volatile int is_set_banned_cpumask_from_ui = 0;
|
||
|
|
+
|
||
|
|
+extern char *banned_cpumask_from_ui;
|
||
|
|
+extern int socket_fd;
|
||
|
|
+extern char socket_name[64];
|
||
|
|
+extern int sleep_interval;
|
||
|
|
+extern pthread_mutex_t cl_banned_list_mutex;
|
||
|
|
+extern GList *cl_banned_irqs;
|
||
|
|
+extern pthread_mutex_t vm_banned_list_mutex;
|
||
|
|
+extern GList *vm_banned_irqs;
|
||
|
|
+extern cpumask_t banned_cpus;
|
||
|
|
+extern int keep_going;
|
||
|
|
+
|
||
|
|
+void irqbalance_mutex_lock(pthread_mutex_t *lock)
|
||
|
|
+{
|
||
|
|
+ int err = 0;
|
||
|
|
+
|
||
|
|
+ err = pthread_mutex_lock(lock);
|
||
|
|
+ if (err) {
|
||
|
|
+ log(TO_ALL, LOG_ERR, "irqbalance: err(%d) irqbalance_mutex_lock failed", err);
|
||
|
|
+ exit(-1);
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void irqbalance_mutex_unlock(pthread_mutex_t *lock)
|
||
|
|
+{
|
||
|
|
+ int err = 0;
|
||
|
|
+
|
||
|
|
+ err = pthread_mutex_unlock(lock);
|
||
|
|
+ if (err) {
|
||
|
|
+ log(TO_ALL, LOG_ERR, "irqbalance: err(%d) irqbalance_mutex_unlock failed", err);
|
||
|
|
+ exit(-1);
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static void fill_banned_cpus(char *cpustr, int length)
|
||
|
|
+{
|
||
|
|
+ (void)snprintf(cpustr, length, "CPU:");
|
||
|
|
+ cpumask_scnprintf(cpustr + strlen(cpustr), length - strlen(cpustr), banned_cpus);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static void fill_banned_irqs(char *irqstr, int length)
|
||
|
|
+{
|
||
|
|
+ GList *entry = NULL;
|
||
|
|
+ GList *next = NULL;
|
||
|
|
+ struct irq_info *info = NULL;
|
||
|
|
+
|
||
|
|
+ (void)snprintf(irqstr, length, "IRQ:");
|
||
|
|
+
|
||
|
|
+ irqbalance_mutex_lock(&cl_banned_list_mutex);
|
||
|
|
+ entry = g_list_first(cl_banned_irqs);
|
||
|
|
+ if (!entry)
|
||
|
|
+ (void)snprintf(irqstr + strlen(irqstr), length - strlen(irqstr), "None ");
|
||
|
|
+ while (entry) {
|
||
|
|
+ next = g_list_next(entry);
|
||
|
|
+ info = entry->data;
|
||
|
|
+ (void)snprintf(irqstr + strlen(irqstr), length - strlen(irqstr),
|
||
|
|
+ "%d,", info->irq);
|
||
|
|
+ entry = next;
|
||
|
|
+ }
|
||
|
|
+ irqbalance_mutex_unlock(&cl_banned_list_mutex);
|
||
|
|
+
|
||
|
|
+ (void)snprintf(irqstr + strlen(irqstr) - 1, length - strlen(irqstr), " PCI:");
|
||
|
|
+
|
||
|
|
+ irqbalance_mutex_lock(&vm_banned_list_mutex);
|
||
|
|
+ entry = g_list_first(vm_banned_irqs);
|
||
|
|
+ if (!entry)
|
||
|
|
+ (void)snprintf(irqstr + strlen(irqstr), length - strlen(irqstr), "None");
|
||
|
|
+ while (entry) {
|
||
|
|
+ next = g_list_next(entry);
|
||
|
|
+ info = entry->data;
|
||
|
|
+ (void)snprintf(irqstr + strlen(irqstr), length - strlen(irqstr),
|
||
|
|
+ "%d,", info->irq);
|
||
|
|
+ entry = next;
|
||
|
|
+ }
|
||
|
|
+ irqbalance_mutex_unlock(&vm_banned_list_mutex);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static int send_msg(int fd, char* buf, int len)
|
||
|
|
+{
|
||
|
|
+ int ret = -1;
|
||
|
|
+
|
||
|
|
+ do {
|
||
|
|
+ ret = send(fd, buf, len, 0);
|
||
|
|
+ } while ((ret <= 0) && (errno == EINTR));
|
||
|
|
+
|
||
|
|
+ return ret;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static int setnonblocking(int fd)
|
||
|
|
+{
|
||
|
|
+ if (fcntl(fd, F_SETFL, fcntl(socket_fd, F_GETFD, 0)|O_NONBLOCK) < 0) {
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static void prase_banned_irq_string(char *irq_string)
|
||
|
|
+{
|
||
|
|
+ char *end = NULL;
|
||
|
|
+ char *last = irq_string;
|
||
|
|
+ int irq;
|
||
|
|
+
|
||
|
|
+ irqbalance_mutex_lock(&cl_banned_list_mutex);
|
||
|
|
+ g_list_free_full(cl_banned_irqs, free);
|
||
|
|
+ cl_banned_irqs = NULL;
|
||
|
|
+ irqbalance_mutex_unlock(&cl_banned_list_mutex);
|
||
|
|
+
|
||
|
|
+ log(TO_ALL, LOG_INFO, "Ban irqs(%s) online.\n", irq_string);
|
||
|
|
+ if (!strncmp(irq_string, "NONE", strlen("NONE"))) {
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ irq = strtoul(irq_string, &end, 10);
|
||
|
|
+ while (last != end) {
|
||
|
|
+ add_cl_banned_irq(irq);
|
||
|
|
+ log(TO_ALL, LOG_INFO, "add banned irq %d from api.\n", irq);
|
||
|
|
+ last = end;
|
||
|
|
+ irq = strtoul(end, &end, 10);
|
||
|
|
+ };
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static void prase_banned_cpu_string(char *cpu_ban_string)
|
||
|
|
+{
|
||
|
|
+ if (strlen(cpu_ban_string) < 1)
|
||
|
|
+ return;
|
||
|
|
+ if (!is_set_banned_cpumask_from_ui)
|
||
|
|
+ is_set_banned_cpumask_from_ui = 1;
|
||
|
|
+
|
||
|
|
+ strcpy(banned_cpumask_from_ui, cpu_ban_string);
|
||
|
|
+ log(TO_ALL, LOG_INFO, "Ban cpus(%s) online.\n", cpu_ban_string);
|
||
|
|
+ if (!strncmp(banned_cpumask_from_ui, "NONE", strlen("NONE"))) {
|
||
|
|
+ memset((void*)banned_cpumask_from_ui, 0, NR_CPUS + 1);
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * recived cmdline format:
|
||
|
|
+ * 1: settings sleep <int>
|
||
|
|
+ * 2: settings ban irqs "<int> <int> <int> <int> ..." or settings ban irqs "NONE"
|
||
|
|
+ * 3: settings ban cpus <cpumask> <cpumask> or settings ban cpus NONE
|
||
|
|
+ * */
|
||
|
|
+int sock_handle(int client_fd)
|
||
|
|
+{
|
||
|
|
+ char buff[FILE_LINE_MAX_NUM] = { 0 };
|
||
|
|
+ int ret = -1;
|
||
|
|
+ int recv_size = 0;
|
||
|
|
+ int valid_user = 0;
|
||
|
|
+ int new_iterval = 0;
|
||
|
|
+
|
||
|
|
+ struct cmsghdr *cmsg = NULL;
|
||
|
|
+ struct ucred *credentials = NULL;
|
||
|
|
+ struct iovec iov = { buff, FILE_LINE_MAX_NUM - 1 };
|
||
|
|
+ struct msghdr msg = { NULL, 0, &iov, 1, NULL, 0, 0 };
|
||
|
|
+
|
||
|
|
+ msg.msg_control = malloc(CMSG_SPACE(sizeof(struct ucred)));
|
||
|
|
+ msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
|
||
|
|
+
|
||
|
|
+ if ((recv_size = recvmsg(client_fd, &msg, 0)) < 0) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "Error while receiving data.\n");
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ cmsg = CMSG_FIRSTHDR(&msg);
|
||
|
|
+ if (cmsg == NULL) {
|
||
|
|
+ log(TO_ALL, LOG_INFO, "There isn't enough space for a cmsghdr in the buffer.\n");
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if ((cmsg->cmsg_level == SOL_SOCKET) &&
|
||
|
|
+ (cmsg->cmsg_type == SCM_CREDENTIALS)) {
|
||
|
|
+ credentials = (struct ucred *) CMSG_DATA(cmsg);
|
||
|
|
+ if (!credentials->uid) {
|
||
|
|
+ valid_user = 1;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ if (!valid_user) {
|
||
|
|
+ log(TO_ALL, LOG_INFO, "Permission denied for user to connect to socket.\n");
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!strncmp(buff, "settings ", strlen("settings "))) {
|
||
|
|
+ if (!(strncmp(buff + strlen("settings "), "sleep ",
|
||
|
|
+ strlen("sleep ")))) {
|
||
|
|
+ new_iterval = strtoul(buff + strlen("settings sleep "), NULL, 10);
|
||
|
|
+ if (new_iterval >= 1) {
|
||
|
|
+ sleep_interval = new_iterval;
|
||
|
|
+ }
|
||
|
|
+ } else if (!(strncmp(buff + strlen("settings "), "ban irqs \"",
|
||
|
|
+ strlen("ban irqs \"")))
|
||
|
|
+ && buff[recv_size - 1] == '\"') {
|
||
|
|
+ buff[recv_size - 1] = '\0';
|
||
|
|
+ prase_banned_irq_string(buff + strlen("settings ban irqs \""));
|
||
|
|
+ need_rescan = 1;
|
||
|
|
+ } else if (!(strncmp(buff + strlen("settings "), "cpus ",
|
||
|
|
+ strlen("cpus")))) {
|
||
|
|
+ if (recv_size > (int)(NR_CPUS + strlen("settings cpus "))) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "Recived error setting cpus string %s, ONLY %d cpus support.\n", buff, NR_CPUS);
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+ buff[recv_size] = '\0';
|
||
|
|
+ prase_banned_cpu_string(buff + strlen("settings cpus "));
|
||
|
|
+ need_rescan = 1;
|
||
|
|
+ }
|
||
|
|
+ } else if (!strncmp(buff, "stats ", strlen("stats "))) {
|
||
|
|
+ if (!(strncmp(buff + strlen("stats "), "cpu", strlen("cpu")))) {
|
||
|
|
+ fill_banned_cpus(buff, FILE_LINE_MAX_NUM - 1);
|
||
|
|
+ send_msg(client_fd, buff, strlen(buff));
|
||
|
|
+ } else if (!(strncmp(buff + strlen("stats "), "irq", strlen("irq")))) {
|
||
|
|
+ fill_banned_irqs(buff, FILE_LINE_MAX_NUM - 1);
|
||
|
|
+ send_msg(client_fd, buff, strlen(buff));
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ ret = 0;
|
||
|
|
+
|
||
|
|
+cleanup:
|
||
|
|
+ free(msg.msg_control);
|
||
|
|
+ return ret;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int init_socket()
|
||
|
|
+{
|
||
|
|
+ struct sockaddr_un addr;
|
||
|
|
+ int optval = 1;
|
||
|
|
+
|
||
|
|
+ (void)unlink(socket_name);
|
||
|
|
+
|
||
|
|
+ socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
|
||
|
|
+ if (socket_fd < 0) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "Socket couldn't be created.\n");
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (access(SOCKET_TMPFS, F_OK) != 0) {
|
||
|
|
+ if (mkdir(SOCKET_TMPFS, 0644) == -1) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "Daemon couldn't create directory %s.\n", SOCKET_TMPFS);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * First try to create a file-based socket in tmpfs. If that doesn't
|
||
|
|
+ * succeed, fall back to an abstract socket (non file-based).
|
||
|
|
+ */
|
||
|
|
+ memset(&addr, 0, sizeof(struct sockaddr_un));
|
||
|
|
+ addr.sun_family = AF_UNIX;
|
||
|
|
+ strncpy(addr.sun_path, socket_name, sizeof(addr.sun_path));
|
||
|
|
+ if (bind(socket_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "Daemon couldn't be bound to the file-based socket.\n");
|
||
|
|
+ /* Try binding to abstract */
|
||
|
|
+ memset(&addr, 0, sizeof(struct sockaddr_un));
|
||
|
|
+ addr.sun_family = AF_UNIX;
|
||
|
|
+ if (bind(socket_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "Daemon couldn't be bound to the abstract socket, bailing out.\n");
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (chmod(socket_name, SOCK_RWX_MODE) != 0) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "socket name : %s, chmod failed\n", socket_name);
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (setsockopt(socket_fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) < 0) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "Unable to set socket options: %s.\n", strerror(errno));
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (listen(socket_fd, MAX_CLIENT) != 0) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "Daemon couldn't be listening to the socket: %s.\n", strerror(errno));
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (setnonblocking(socket_fd) < 0) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "Daemon set connection(listen) nonblocking failed: %s.\n", strerror(errno));
|
||
|
|
+ goto cleanup;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return socket_fd;
|
||
|
|
+
|
||
|
|
+cleanup:
|
||
|
|
+ if (socket_fd >= 0)
|
||
|
|
+ close(socket_fd);
|
||
|
|
+
|
||
|
|
+ return -1;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void *handle_socket_api_event(void *args __attribute__((unused)))
|
||
|
|
+{
|
||
|
|
+ int epoll_fd = -1;
|
||
|
|
+ int conn_fd = -1;
|
||
|
|
+ int nfds = -1;
|
||
|
|
+ int i = 0;
|
||
|
|
+ int cur_fd_count = 1;
|
||
|
|
+
|
||
|
|
+ struct epoll_event ev;
|
||
|
|
+ struct epoll_event *events = NULL;
|
||
|
|
+
|
||
|
|
+ snprintf(socket_name, 64, "%s/%s%d.sock", SOCKET_TMPFS, SOCKET_PATH, getpid());
|
||
|
|
+
|
||
|
|
+ memset((void*)&ev, 0, sizeof(ev));
|
||
|
|
+ socket_fd = init_socket();
|
||
|
|
+ if (socket_fd < 0)
|
||
|
|
+ exit(-1);
|
||
|
|
+
|
||
|
|
+ epoll_fd = epoll_create(MAX_EVENTS);
|
||
|
|
+ if (epoll_fd < 0) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "Unable to create epoll: %s.\n", strerror(errno));
|
||
|
|
+ exit(-1);
|
||
|
|
+ }
|
||
|
|
+ ev.events = EPOLLIN | EPOLLRDHUP;
|
||
|
|
+ ev.data.fd = socket_fd;
|
||
|
|
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket_fd, &ev) < 0) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "Daemon epoll set insertion error: %s.\n", strerror(errno));
|
||
|
|
+ exit(-1);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ events = (struct epoll_event *)malloc(sizeof(struct epoll_event) * MAX_EVENTS);
|
||
|
|
+ if (NULL == events) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "Daemon faild to malloc epoll event space.\n");
|
||
|
|
+ exit(-1);
|
||
|
|
+ }
|
||
|
|
+ memset((void*)events, 0, sizeof(struct epoll_event) * MAX_EVENTS);
|
||
|
|
+
|
||
|
|
+ banned_cpumask_from_ui = (char*)malloc(NR_CPUS + 1);
|
||
|
|
+ memset((void*)banned_cpumask_from_ui, 0, NR_CPUS + 1);
|
||
|
|
+
|
||
|
|
+ while (keep_going) {
|
||
|
|
+ nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
|
||
|
|
+ if ( 0 == nfds) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "Daemon epoll wait failed: %s.\n", strerror(errno));
|
||
|
|
+ (void)usleep(SLEEP_TIME);
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ for (i = 0; i < nfds; i++) {
|
||
|
|
+ if (events[i].data.fd == socket_fd) {
|
||
|
|
+ conn_fd = accept(socket_fd, NULL, NULL);
|
||
|
|
+ if (conn_fd < 0) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "Daemon accept failed: %s\n", strerror(errno));
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ if (cur_fd_count >= MAX_EVENTS) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "Daemon support no more than %d connection\n", MAX_EVENTS);
|
||
|
|
+ close(conn_fd);
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ if (setnonblocking(conn_fd) < 0) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "Daemon set connection nonblocking failed: %s.\n", strerror(errno));
|
||
|
|
+ close(conn_fd);
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ memset((void*)&ev, 0, sizeof(ev));
|
||
|
|
+ ev.events = EPOLLIN | EPOLLRDHUP;
|
||
|
|
+ ev.data.fd = conn_fd;
|
||
|
|
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_fd, &ev) < 0) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "Daemonadd socket '%d' to poll failed: %s\n", conn_fd, strerror(errno));
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ cur_fd_count++;
|
||
|
|
+ continue;
|
||
|
|
+ } else if (events[i].events&EPOLLERR || events[i].events&EPOLLHUP ) {
|
||
|
|
+ log(TO_ALL, LOG_WARNING, "epoll is error: %u\n", events[i].events);
|
||
|
|
+ } else {
|
||
|
|
+ /* one socket connection only support send&recv data once */
|
||
|
|
+ sock_handle(events[i].data.fd);
|
||
|
|
+ }
|
||
|
|
+ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, &ev);
|
||
|
|
+ close(events[i].data.fd);
|
||
|
|
+ events[i].data.fd = -1;
|
||
|
|
+ cur_fd_count--;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ free(events);
|
||
|
|
+ free(banned_cpumask_from_ui);
|
||
|
|
+ banned_cpumask_from_ui = NULL;
|
||
|
|
+ if (socket_fd >= 0)
|
||
|
|
+ close(socket_fd);
|
||
|
|
+ if (socket_name[0])
|
||
|
|
+ unlink(socket_name);
|
||
|
|
+
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
diff --git a/sockapi.h b/sockapi.h
|
||
|
|
new file mode 100644
|
||
|
|
index 0000000..254dd3f
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/sockapi.h
|
||
|
|
@@ -0,0 +1,28 @@
|
||
|
|
+/*
|
||
|
|
+ * Copyright (C) 2019. Huawei Technologies Co., Ltd. All rights reserved.
|
||
|
|
+ *
|
||
|
|
+ * This program is free software; you can redistribute it and/or modify
|
||
|
|
+ * it under the terms of the MuLan PSL v1.
|
||
|
|
+ *
|
||
|
|
+ * 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 MuLan PSL v1 for more details.
|
||
|
|
+ */
|
||
|
|
+#ifndef UVP_IRQBALANCE_SOCKAPI_H_
|
||
|
|
+#define UVP_IRQBALANCE_SOCKAPI_H_
|
||
|
|
+
|
||
|
|
+#include <sys/stat.h>
|
||
|
|
+
|
||
|
|
+/* set socket file mode to 660 */
|
||
|
|
+#define SOCK_RWX_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
|
||
|
|
+
|
||
|
|
+#define SLEEP_TIME (100 * 1000) /* 100ms */
|
||
|
|
+
|
||
|
|
+#define MAX_CLIENT 512
|
||
|
|
+#define MAX_EVENTS 1024
|
||
|
|
+
|
||
|
|
+#define FILE_LINE_MAX_NUM (4096*6)
|
||
|
|
+
|
||
|
|
+void *handle_socket_api_event(void *args);
|
||
|
|
+
|
||
|
|
+#endif
|
||
|
|
--
|
||
|
|
1.8.3.1
|
||
|
|
|