From c6a08db6dbd80aaf60094b9a0bc0456f2cc0afb8 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Tue, 10 Dec 2013 11:05:26 +0100 Subject: [PATCH] Added support for cgroups --- doc/sample.config | 19 +++++++++----- src/config.c | 3 +++ src/group-config.c | 3 +++ src/main-misc.c | 63 ++++++++++++++++++++++++++++++++++++++++++--- src/main.c | 4 +++ src/main.h | 2 ++ src/ocserv-args.def | 18 ++++++++----- src/vpn.h | 4 +++ 8 files changed, 99 insertions(+), 17 deletions(-) diff --git a/doc/sample.config b/doc/sample.config index 06be160a..c5bc5cf2 100644 --- a/doc/sample.config +++ b/doc/sample.config @@ -134,6 +134,17 @@ socket-file = /var/run/ocserv-socket run-as-user = nobody run-as-group = nobody +# Set the protocol-defined priority (SO_PRIORITY) for packets to +# be sent. That is a number from 0 to 6 with 0 being the lowest +# priority. Alternatively this can be used to set the IP Type- +# Of-Service, by setting it to a hexadecimal number (e.g., 0x20). +# This can be set per user/group or globally. +#net-priority = 3 + +# Set the VPN worker process into a specific cgroup. This is Linux +# specific and can be set per user/group or globally. +#cgroup = "cpuset,cpu:test" + # Network settings device = vpns @@ -173,13 +184,6 @@ ping-leases = false # Setting it higher will improve throughput. output-buffer = 10 -# Set the protocol-defined priority (SO_PRIORITY) for packets to -# be sent. That is a number from 0 to 6 with 0 being the lowest -# priority. Alternatively this can be used to set the IP Type- -# Of-Service, by setting it to a hexadecimal number (e.g., 0x20). -# This can be set per user/group or globally. -#net-priority = 3 - route = 192.168.1.0/255.255.255.0 #route = 192.168.5.0/255.255.255.0 @@ -196,6 +200,7 @@ route = 192.168.1.0/255.255.255.0 config-per-user = /etc/ocserv/config-per-user/ config-per-group = /etc/ocserv/config-per-group/ + # The system command to use to setup a route. %R will be replaced with the # route/mask and %D with the (tun) device. # diff --git a/src/config.c b/src/config.c index 4451ddb5..0ba4d350 100644 --- a/src/config.c +++ b/src/config.c @@ -93,6 +93,7 @@ static struct cfg_options available_options[] = { { .name = "run-as-user", .type = OPTION_STRING, .mandatory = 0 }, { .name = "run-as-group", .type = OPTION_STRING, .mandatory = 0 }, { .name = "device", .type = OPTION_STRING, .mandatory = 1 }, + { .name = "cgroup", .type = OPTION_STRING, .mandatory = 0 }, { .name = "ipv4-network", .type = OPTION_STRING, .mandatory = 0 }, { .name = "ipv4-netmask", .type = OPTION_STRING, .mandatory = 0 }, @@ -371,6 +372,7 @@ unsigned prefix = 0; } READ_STRING("device", config->network.name); + READ_STRING("cgroup", config->cgroup); READ_STRING("ipv4-network", config->network.ipv4); READ_STRING("ipv4-netmask", config->network.ipv4_netmask); @@ -523,6 +525,7 @@ unsigned i; DEL(config->xml_config_hash); DEL(config->cert_hash); #endif + DEL(config->cgroup); DEL(config->route_add_cmd); DEL(config->route_del_cmd); DEL(config->per_user_dir); diff --git a/src/group-config.c b/src/group-config.c index 87064b17..32623155 100644 --- a/src/group-config.c +++ b/src/group-config.c @@ -54,6 +54,7 @@ static struct cfg_options available_options[] = { { .name = "rx-data-per-sec", .type = OPTION_NUMERIC, }, { .name = "tx-data-per-sec", .type = OPTION_NUMERIC, }, { .name = "net-priority", .type = OPTION_STRING, }, + { .name = "cgroup", .type = OPTION_STRING, }, }; #define READ_RAW_MULTI_LINE(name, s_name, num) \ @@ -147,6 +148,7 @@ unsigned prefix = 0; READ_RAW_MULTI_LINE("route", config->routes, config->routes_size); READ_RAW_MULTI_LINE("iroute", config->iroutes, config->iroutes_size); + READ_RAW_STRING("cgroup", config->cgroup); READ_RAW_STRING("ipv4-dns", config->ipv4_dns); READ_RAW_STRING("ipv6-dns", config->ipv6_dns); READ_RAW_STRING("ipv4-nbns", config->ipv4_nbns); @@ -187,6 +189,7 @@ unsigned i; } free(config->iroutes); + free(config->cgroup); free(config->ipv4_dns); free(config->ipv6_dns); free(config->ipv4_nbns); diff --git a/src/main-misc.c b/src/main-misc.c index ae55a512..44f74426 100644 --- a/src/main-misc.c +++ b/src/main-misc.c @@ -158,7 +158,7 @@ fail: return ret; } -static int read_config_file(main_server_st* s, struct proc_st* proc, const char* file, const char* type) +static int read_additional_config_file(main_server_st* s, struct proc_st* proc, const char* file, const char* type) { struct group_cfg_st cfg; int ret; @@ -239,6 +239,11 @@ unsigned i; cfg.ipv6_netmask = NULL; } + if (proc->config.cgroup == NULL) { + proc->config.cgroup = cfg.cgroup; + cfg.cgroup = NULL; + } + if (proc->config.rx_per_sec == 0) { proc->config.rx_per_sec = cfg.rx_per_sec; } @@ -270,7 +275,7 @@ int ret; if (s->config->per_user_dir != NULL) { snprintf(file, sizeof(file), "%s/%s", s->config->per_user_dir, proc->username); - ret = read_config_file(s, proc, file, "user"); + ret = read_additional_config_file(s, proc, file, "user"); if (ret < 0) return ret; } @@ -278,10 +283,14 @@ int ret; if (s->config->per_group_dir != NULL && proc->groupname[0] != 0) { snprintf(file, sizeof(file), "%s/%s", s->config->per_group_dir, proc->groupname); - ret = read_config_file(s, proc, file, "group"); + ret = read_additional_config_file(s, proc, file, "group"); if (ret < 0) return ret; } + + if (proc->config.cgroup != NULL) { + put_into_cgroup(s, proc->config.cgroup, proc->pid); + } return 0; } @@ -675,3 +684,51 @@ const char *p; exit(1); } } + +/* Puts the provided PIN into the config's cgroup */ +void put_into_cgroup(main_server_st * s, const char* _cgroup, pid_t pid) +{ +char* name, *p, *savep; +char cgroup[128]; +char file[_POSIX_PATH_MAX]; +FILE* fd; + + if (_cgroup == NULL) + return; + +#ifdef __linux__ + /* format: cpu,memory:cgroup-name */ + snprintf(cgroup, sizeof(cgroup), "%s", _cgroup); + + name = strchr(cgroup, ':'); + if (name == NULL) { + mslog(s, NULL, LOG_ERR, "error parsing cgroup name: %s", cgroup); + return; + } + name[0] = 0; + name++; + + p = strtok_r(cgroup, ",", &savep); + while (p != NULL) { + mslog(s, NULL, LOG_DEBUG, "putting process %u to cgroup '%s:%s'", (unsigned)pid, p, name); + + snprintf(file, sizeof(file), "/sys/fs/cgroup/%s/%s/tasks", p, name); + + fd = fopen(file, "w"); + if (fd == NULL) { + mslog(s, NULL, LOG_ERR, "cannot open: %s", file); + return; + } + + if (fprintf(fd, "%u", (unsigned)pid) <= 0) { + mslog(s, NULL, LOG_ERR, "could not write to: %s", file); + } + fclose(fd); + p = strtok_r(NULL, ",", &savep); + } + + return; +#else + mslog(s, NULL, LOG_DEBUG, "Ignoring cgroup option as it is not supported on this system"); +#endif +} diff --git a/src/main.c b/src/main.c index e9b0d470..0244e8a8 100644 --- a/src/main.c +++ b/src/main.c @@ -822,6 +822,7 @@ int main(int argc, char** argv) setproctitle(PACKAGE_NAME"-worker"); kill_on_parent_kill(SIGTERM); + ws.config = &config; ws.cmd_fd = cmd_fd[1]; @@ -853,6 +854,9 @@ fork_failed: set_cloexec_flag (cmd_fd[0], 1); list_add(&s.clist.head, &(ctmp->list)); + + put_into_cgroup(&s, s.config->cgroup, pid); + s.active_clients++; } close(cmd_fd[1]); diff --git a/src/main.h b/src/main.h index 98f2eca9..7fca56c1 100644 --- a/src/main.h +++ b/src/main.h @@ -215,4 +215,6 @@ int parse_group_cfg_file(main_server_st* s, const char* file, struct group_cfg_s void del_additional_config(struct group_cfg_st* config); void remove_proc(main_server_st* s, struct proc_st *proc, unsigned k); +void put_into_cgroup(main_server_st * s, const char* cgroup, pid_t pid); + #endif diff --git a/src/ocserv-args.def b/src/ocserv-args.def index 274a305d..4f305f57 100644 --- a/src/ocserv-args.def +++ b/src/ocserv-args.def @@ -224,6 +224,17 @@ socket-file = /var/run/ocserv-socket run-as-user = nobody run-as-group = nogroup +# Set the protocol-defined priority (SO_PRIORITY) for packets to +# be sent. That is a number from 0 to 6 with 0 being the lowest +# priority. Alternatively this can be used to set the IP Type- +# Of-Service, by setting it to a hexadecimal number (e.g., 0x20). +# This can be set per user/group or globally. +#net-priority = 3 + +# Set the VPN worker process into a specific cgroup. This is Linux +# specific and can be set per user/group or globally. +cgroup = "cpuset,cpu:test" + # # Network settings # @@ -271,13 +282,6 @@ ping-leases = false # Setting it higher will improve throughput. output-buffer = 10 -# Set the protocol-defined priority (SO_PRIORITY) for packets to -# be sent. That is a number from 0 to 6 with 0 being the lowest -# priority. Alternatively this can be used to set the IP Type- -# Of-Service, by setting it to a hexadecimal number (e.g., 0x20). -# This can be set per user/group or globally. -#net-priority = 3 - # Routes to be forwarded to the client. If you need the # client to forward routes to the server, you may use the connect # and disconnect scripts. diff --git a/src/vpn.h b/src/vpn.h index 0521825d..4619325f 100644 --- a/src/vpn.h +++ b/src/vpn.h @@ -98,6 +98,8 @@ struct group_cfg_st { char *ipv6_network; char *ipv4_netmask; char *ipv6_netmask; + + char *cgroup; size_t rx_per_sec; size_t tx_per_sec; @@ -177,6 +179,8 @@ struct cfg_st { char *connect_script; char *disconnect_script; + + char *cgroup; #ifdef ANYCONNECT_CLIENT_COMPAT char *xml_config_file;