#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "cgroup_helpers.h" /* * To avoid relying on the system setup, when setup_cgroup_env is called * we create a new mount namespace, and cgroup namespace. The cgroup2 * root is mounted at CGROUP_MOUNT_PATH * * Unfortunately, most people don't have cgroupv2 enabled at this point in time. * It's easier to create our own mount namespace and manage it ourselves. * * We assume /mnt exists. */ #define WALK_FD_LIMIT 16 #define CGROUP_MOUNT_PATH "/mnt" #define CGROUP_WORK_DIR "/cgroup-test-work-dir" #define format_cgroup_path(buf, path) \ snprintf(buf, sizeof(buf), "%s%s%s", CGROUP_MOUNT_PATH, \ CGROUP_WORK_DIR, path) /** * setup_cgroup_environment() - Setup the cgroup environment * * After calling this function, cleanup_cgroup_environment should be called * once testing is complete. * * This function will print an error to stderr and return 1 if it is unable * to setup the cgroup environment. If setup is successful, 0 is returned. */ int setup_cgroup_environment(void) { char cgroup_workdir[PATH_MAX + 1]; format_cgroup_path(cgroup_workdir, ""); if (unshare(CLONE_NEWNS)) { log_err("unshare"); return 1; } if (mount("none", "/", NULL, MS_REC | MS_PRIVATE, NULL)) { log_err("mount fakeroot"); return 1; } if (mount("none", CGROUP_MOUNT_PATH, "cgroup2", 0, NULL)) { log_err("mount cgroup2"); return 1; } /* Cleanup existing failed runs, now that the environment is setup */ cleanup_cgroup_environment(); if (mkdir(cgroup_workdir, 0777) && errno != EEXIST) { log_err("mkdir cgroup work dir"); return 1; } return 0; } static int nftwfunc(const char *filename, const struct stat *statptr, int fileflags, struct FTW *pfwt) { if ((fileflags & FTW_D) && rmdir(filename)) log_err("Removing cgroup: %s", filename); return 0; } static int join_cgroup_from_top(char *cgroup_path) { char cgroup_procs_path[PATH_MAX + 1]; pid_t pid = getpid(); int fd, rc = 0; snprintf(cgroup_procs_path, sizeof(cgroup_procs_path), "%s/cgroup.procs", cgroup_path); fd = open(cgroup_procs_path, O_WRONLY); if (fd < 0) { log_err("Opening Cgroup Procs: %s", cgroup_procs_path); return 1; } if (dprintf(fd, "%d\n", pid) < 0) { log_err("Joining Cgroup"); rc = 1; } close(fd); return rc; } /** * join_cgroup() - Join a cgroup * @path: The cgroup path, relative to the workdir, to join * * This function expects a cgroup to already be created, relative to the cgroup * work dir, and it joins it. For example, passing "/my-cgroup" as the path * would actually put the calling process into the cgroup * "/cgroup-test-work-dir/my-cgroup" * * On success, it returns 0, otherwise on failure it returns 1. */ int join_cgroup(char *path) { char cgroup_path[PATH_MAX + 1]; format_cgroup_path(cgroup_path, path); return join_cgroup_from_top(cgroup_path); } /** * cleanup_cgroup_environment() - Cleanup Cgroup Testing Environment * * This is an idempotent function to delete all temporary cgroups that * have been created during the test, including the cgroup testing work * directory. * * At call time, it moves the calling process to the root cgroup, and then * runs the deletion process. It is idempotent, and should not fail, unless * a process is lingering. * * On failure, it will print an error to stderr, and try to continue. */ void cleanup_cgroup_environment(void) { char cgroup_workdir[PATH_MAX + 1]; format_cgroup_path(cgroup_workdir, ""); join_cgroup_from_top(CGROUP_MOUNT_PATH); nftw(cgroup_workdir, nftwfunc, WALK_FD_LIMIT, FTW_DEPTH | FTW_MOUNT); } /** * create_and_get_cgroup() - Create a cgroup, relative to workdir, and get the FD * @path: The cgroup path, relative to the workdir, to join * * This function creates a cgroup under the top level workdir and returns the * file descriptor. It is idempotent. * * On success, it returns the file descriptor. On failure it returns 0. * If there is a failure, it prints the error to stderr. */ int create_and_get_cgroup(char *path) { char cgroup_path[PATH_MAX + 1]; int fd; format_cgroup_path(cgroup_path, path); if (mkdir(cgroup_path, 0777) && errno != EEXIST) { log_err("mkdiring cgroup"); return 0; } fd = open(cgroup_path, O_RDONLY); if (fd < 0) { log_err("Opening Cgroup"); return 0; } return fd; } >1-0/+16 2017-02-08bridge: vlan tunnel id info range fill size calc cleanupsRoopa Prabhu1-18/+16 2017-02-07bridge: avoid unnecessary read of jiffiesstephen hemminger2-4/+8 2017-02-07bridge: remove unnecessary check for vtbegin in br_fill_vlan_tinfo_rangeRoopa Prabhu1-1/+1 2017-02-07bridge: tunnel: fix attribute checks in br_parse_vlan_tunnel_infoNikolay Aleksandrov1-4/+4 2017-02-07net: bridge: remove redundant check to see if err is setColin Ian King1-3/+0 2017-02-06bridge: fdb: write to used and updated at most once per jiffyNikolay Aleksandrov2-2/+4 2017-02-06bridge: move write-heavy fdb members in their own cache lineNikolay Aleksandrov1-4/+6 2017-02-06bridge: move to workqueue gcNikolay Aleksandrov10-23/+29 2017-02-06bridge: modify bridge and port to have often accessed fields in one cache lineNikolay Aleksandrov1-23/+20 2017-02-06net: remove ndo_neigh_{construct, destroy} from stacked devicesIdo Schimmel1-2/+0 2017-02-03Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-nextDavid S. Miller3-32/+49 2017-02-03bridge: vlan dst_metadata hooks in ingress and egress pathsRoopa Prabhu6-2/+82 2017-02-03bridge: per vlan dst_metadata netlink supportRoopa Prabhu7-48/+641 2017-02-02netfilter: allow logging from non-init namespacesMichal Kubeček1-1/+1