From: Daniel Wagner <[email protected]>
When a new interface is registerd, __connman_cgroup_add_interface()
should be called. This will create a new cgroup under the root
cgroup with the interface name.
When a interface is removed, __connman_cgroup_rem_interface() should
be called. That will first move all assign PIDs to the root cgroup
before remove the directory.
---
src/cgroup.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/connman.h | 2 +
2 files changed, 186 insertions(+)
diff --git a/src/cgroup.c b/src/cgroup.c
index e3c29d6..cb21c82 100644
--- a/src/cgroup.c
+++ b/src/cgroup.c
@@ -28,12 +28,190 @@
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include <connman/inet.h>
#include "connman.h"
#define CGROUP_PATH "/sys/fs/cgroup/connman"
static connman_bool_t enabled;
+static GHashTable *if_hash = NULL;
+
+struct cgroup_info {
+ char *path;
+};
+
+static int write_line(const char *path, const char *line)
+{
+ ssize_t len;
+ int fd;
+ int err = 0;
+
+ fd = open(path, O_WRONLY | O_CLOEXEC);
+ if (fd < 0) {
+ err = -errno;
+ connman_error("Failed to open %s: %s", path, strerror(errno));
+ return err;
+ }
+
+ len = write(fd, line, strlen(line));
+ if (len < 0) {
+ err = -errno;
+ connman_error("Failed to write line '%s' to %s: %s",
+ line, path, strerror(errno));
+ goto out;
+ }
+
+ close(fd);
+
+out:
+ return err;
+}
+
+static int cgroup_attach(const char *path, pid_t pid)
+{
+ char *line, *tasks;
+ int err;
+
+ DBG("path %s pid %d", path, pid);
+
+ line = g_strdup_printf("%lu\n", (unsigned long) pid);
+ tasks = g_strdup_printf("%s/tasks", path);
+
+ err = write_line(tasks, line);
+
+ g_free(line);
+ g_free(tasks);
+
+ return err;
+}
+
+static int read_one_pid(const char *path, pid_t *pid)
+{
+ unsigned long ul;
+ char *tasks;
+ FILE *file;
+ int err;
+
+ tasks = g_strdup_printf("%s/tasks", path);
+ file = fopen(tasks, "r");
+ if (file == NULL) {
+ g_free(tasks);
+ return -errno;
+ }
+
+ err = fscanf(file, "%lu", &ul);
+ fclose(file);
+ g_free(tasks);
+
+ if (err < 0) {
+ if (errno == 0)
+ return -ENOENT;
+ return -errno;
+ }
+
+ if (err != 1)
+ return -EIO;
+
+ *pid = ul;
+
+ return 0;
+}
+
+static void cleanup_cgroup(gpointer user_data)
+{
+ struct cgroup_info *info = user_data;
+ pid_t pid = 0;
+
+ DBG("remove %s", info->path);
+
+ while (read_one_pid(info->path, &pid) == 0)
+ cgroup_attach(CGROUP_PATH, pid);
+
+ rmdir(info->path);
+ g_free(info->path);
+ g_free(info);
+}
+
+int __connman_cgroup_add_interface(int index, uint32_t fwmark)
+{
+ struct cgroup_info *info;
+ char *interface = NULL, *mpath, *marker;
+ int err;
+
+ DBG("index %d", index);
+
+ info = g_try_new0(struct cgroup_info, 1);
+ if (info == NULL)
+ return -ENOMEM;
+
+ if (g_hash_table_lookup(if_hash, GINT_TO_POINTER(index)) != NULL) {
+ connman_error("Trying to add an already registered interface");
+ err = -EALREADY;
+ goto err;
+ }
+
+ interface = connman_inet_ifname(index);
+ if (interface == NULL) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ info->path = g_strdup_printf("%s/%s", CGROUP_PATH, interface);
+ g_free(interface);
+ if (info->path == NULL) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ err = mkdir(info->path, S_IRWXU | S_IRGRP | S_IXGRP |
+ S_IROTH | S_IXOTH);
+ if (err < 0) {
+ err = -errno;
+ connman_error("Could not create %s: %s", info->path,
+ strerror(errno));
+ goto err;
+ }
+
+ mpath = g_strdup_printf("%s/net_sock.mark", info->path);
+ marker = g_strdup_printf("0x%x", fwmark);
+ err = write_line(mpath, marker);
+ g_free(mpath);
+ g_free(marker);
+ if (err < 0) {
+ connman_error("Could not set routing marker: %s",
+ strerror(err));
+ goto err;
+ }
+
+ g_hash_table_replace(if_hash, GINT_TO_POINTER(index), info);
+
+ return 0;
+
+err:
+ g_free(info->path);
+ g_free(info);
+
+ return err;
+}
+
+int __connman_cgroup_rem_interface(int index)
+{
+ DBG("index %d", index);
+
+ if (g_hash_table_lookup(if_hash, GINT_TO_POINTER(index)) == NULL) {
+ connman_error("Trying to remove an unkonwn interface");
+ return -EINVAL;
+ }
+
+ g_hash_table_remove(if_hash, GINT_TO_POINTER(index));
+
+ return 0;
+}
+
static int check_mount_point(const char *path)
{
@@ -114,6 +292,9 @@ int __connman_cgroup_init(void)
return err;
}
+ if_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, cleanup_cgroup);
+
enabled = TRUE;
return 0;
@@ -126,5 +307,8 @@ void __connman_cgroup_cleanup(void)
if (enabled == FALSE)
return;
+ g_hash_table_destroy(if_hash);
+ if_hash = NULL;
+
cgroup_cleanup();
}
diff --git a/src/connman.h b/src/connman.h
index 06c0bc5..eb43001 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -850,3 +850,5 @@ void __connman_nat_disable(const char *name);
int __connman_cgroup_init(void);
void __connman_cgroup_cleanup(void);
+int __connman_cgroup_add_interface(int index, uint32_t fwmark);
+int __connman_cgroup_rem_interface(int index);
--
1.7.12.rc1.16.g05a20c8
_______________________________________________
connman mailing list
[email protected]
http://lists.connman.net/listinfo/connman