On 02/13/2013 12:48 AM, Jan Safranek wrote:
> On 02/12/2013 08:11 PM, John Fastabend wrote:
>> From: John Fastabend <john.fastab...@gmail.com>
>>
>> Add routine to scan rules.conf file and move matching running tasks
>> in /proc/pid/* into configured control groups. Then at init time
>> we can move running tasks into the correct control group. Also
>> add tracking to get events when new directories are added to a
>> control group so we can move running tasks into these new sub-control
>> groups.
>
> This can be easily achieved by executing something like cgclassify `cat
> /sys/fs/cgroup/*/task` after starting the daemon. I don't like the code,
> see below.
>

But isn't this something most (all?) users would expect to be handled
by the daemon itself? At a minimum we should add 'cgclassify `cat ...`'
to the init.d scripts so the service calls work in this case. Although
I still think it is easy enough to handle in the daemon.

w.r.t. the code, your right it is backwards. Looking at the cgclassify.c
snippet we should be able to accomplish this with a much neater patch by
using the cglib APIs correctly.

>> To accomplish this track the watched directories in a list adding
>> additional directories and removing them as needed. When inotify
>> events are received scan the rules.conf file.
>
> I don't follow here. Event of 'creating control group' does not indicate
> that cgrules.conf has changed and should be reloaded. Shouldn't you
> watch the cgrules.conf file instead?
>

In our use case we edit the cgrules.conf first then 'create control 
group' later. The use case here is an administrator needs to come
in and bind applications to an application type and then later what
priority this should actually use is decided via networking protocols.

A specific example might help. Take a webserver we don't actually know
what daemon the user might want to use before hand httpd, nginx,
lighttpd, etc. So we expect the administrator or pkg tools to create
an entry in cgrules.conf to bind the application to a known net_prio
control group. When the network protocol negotiates the priority to
use for http we then create the control group and assign the priority.
The cgrules.conf entry is already added so the webserver should
somehow be moved into this control group.

>> Without this adding control group after cgrulesengd has started
>> does not work correctly and processes running before cgrulesengd
>> is started are not managed.
>>
>> This allows for a couple use cases that I could not find a way to
>> handle without this infrastructure. First processes that are used
>> in initd time frame are run before cgrulesengd is started. Often
>> these are daemons that we would like to manage via control groups.
>>
>> Another example is the net_{cls|prio} cgroups. In these cases
>> we may be adding/removing groups somewhat dynamically based on
>> control protocols (DCBX) or user input. In the DCB case DCBX
>> negotiates what priority an application should use via
>> link layer discovery protocol (LLDP). Then we use control
>> groups to set this up but this usually happens after cgrulesengd
>> has started so prior to this happening we don't know which apps
>> and directories we need to support.
>
> If you add/remove cgroups dynamically, you should also add rules to
> cgrules.conf dynamically, so the daemon knows it should move something
> to the new groups. And if you modify cgrules.conf, you can also send
> SIGUSR2 to cgrulesengd to reload the rules.

As described our flow is the other way around. However if we don't want
to monitor for create/delete events in the control group fs we can
have our application force a rescan basically doing what cgclassify
would do when we add the directory.

I just thought this might be more generic but I'm fine with putting it
in my application. I guess the key point being we created/destroyed the
directory so we should deal with doing the classify step as well?

>
> (alternatively, I can imagine some socket/dbus/whatever in cgrulesengd
> which would allow adding rules dynamically without fiddling with
> cgrules.conf)
>
>>
>> Signed-off-by: John Fastabend <john.r.fastab...@intel.com>
>> ---
>>   include/libcgroup/tasks.h |    1
>>   src/api.c                 |   83 +++++++++++++++++++
>>   src/daemon/cgrulesengd.c  |  193 
>> ++++++++++++++++++++++++++++++++++++++++++++-
>>   src/libcgroup.map         |    1
>>   4 files changed, 273 insertions(+), 5 deletions(-)
>>
>> diff --git a/include/libcgroup/tasks.h b/include/libcgroup/tasks.h
>> index 0f79220..fc0cb63 100644
>> --- a/include/libcgroup/tasks.h
>> +++ b/include/libcgroup/tasks.h
>> @@ -109,6 +109,7 @@ int cgroup_reload_cached_rules(void);
>>    * @param fp Destination file, where the rules will be printed.
>>    */
>>   void cgroup_print_rules_config(FILE *fp);
>> +void cgroup_search_rules_config(void);
>>
>>   /**
>>    * @}
>> diff --git a/src/api.c b/src/api.c
>> index 11cd1b4..c9861a5 100644
>> --- a/src/api.c
>> +++ b/src/api.c
>> @@ -3055,6 +3055,89 @@ int cgroup_change_cgroup_path(const char *dest, pid_t 
>> pid,
>>      return ret;
>>   }
>>
>> +static int cg_get_pid_from_flags(int uid, int gid, char *procname, int *pid)
>> +{
>> +    DIR *dir;
>> +    struct dirent *pid_dir = NULL;
>> +    char *path = "/proc/";
>> +    char *pid_name;
>> +    char pid_path[PATH_MAX];
>> +    char buff[CGROUP_RULE_MAXLINE];
>> +    int sgid, suid, spid, err;
>> +    FILE *fd;
>> +
>> +    dir = opendir(path);
>> +    if (!dir)
>> +            return -ECGOTHER;
>> +
>> +    while ((pid_dir = readdir(dir)) != NULL) {
>> +            err = snprintf(pid_path, sizeof(pid_path),
>> +                           "%s%s/status", path, pid_dir->d_name);
>> +            if (err < 0) {
>> +                    cgroup_dbg("%s pid_path failure\n", __func__);
>> +                    continue;
>> +            }
>> +
>> +            fd = fopen(pid_path, "r");
>> +            if (!fd)
>> +                    continue;
>> +            memset(pid_path, 0, sizeof(pid_path));
>> +            sgid = suid = spid = -1;
>> +            while (fgets(buff, sizeof(buff), fd) != NULL) {
>> +                    sscanf(buff, "Name: %as", &pid_name);
>> +                    sscanf(buff, "Gid: %i", &sgid);
>> +                    sscanf(buff, "Uid: %i", &suid);
>> +                    sscanf(buff, "Pid: %i", &spid);
>> +            }
>> +
>> +            fclose(fd);
>> +            if ((!procname ||
>> +                 (strncmp(procname, pid_name, strlen(procname)) == 0)) &&
>> +                (gid == (int) CGRULE_WILD || gid == sgid) &&
>> +                (uid == (int) CGRULE_WILD || uid == suid)) {
>> +                    free(pid_name);
>> +                    closedir(dir);
>> +                    *pid = spid;
>> +                    return 0;
>> +            }
>> +
>> +            free(pid_name);
>> +    }
>> +
>> +    closedir(dir);
>> +    return 1;
>> +}
>> +
>> +void cgroup_search_rules_config(void)
>> +{
>> +    struct cgroup_rule *itr;
>> +
>> +    pthread_rwlock_rdlock(&rl_lock);
>> +
>> +    if (!(rl.head)) {
>> +            pthread_rwlock_unlock(&rl_lock);
>> +            return;
>> +    }
>> +
>> +    itr = rl.head;
>> +    while (itr) {
>> +            int err, pid = 0;
>> +
>> +            err = cg_get_pid_from_flags(itr->uid, itr->gid,
>> +                                        itr->procname, &pid);
>> +
>> +            if (!err) {
>> +                    pthread_rwlock_unlock(&rl_lock);
>> +                    cgroup_change_cgroup_flags(itr->uid, itr->gid,
>> +                                               itr->procname, pid, 0);
>> +                    pthread_rwlock_rdlock(&rl_lock);
>> +            }
>> +            itr = itr->next;
>> +    }
>> +    pthread_rwlock_unlock(&rl_lock);
>> +}
>
> If I read the code correctly, for each rule in cgrules.conf it finds
> *one* PID and moves it to the right group. Shouldn't it work like for
> *every* PID find a matching rule and add it to its group? I think we
> have API for the "find a matching rule and add it to its group", all you
> need is to enumerate all PIDs.
>

You are correct I'll clean it up, cgclassify.c has a nice snippet of
code that uses the API to do a similar thing.

.John

------------------------------------------------------------------------------
Free Next-Gen Firewall Hardware Offer
Buy your Sophos next-gen firewall before the end March 2013 
and get the hardware for free! Learn more.
http://p.sf.net/sfu/sophos-d2d-feb
_______________________________________________
Libcg-devel mailing list
Libcg-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libcg-devel

Reply via email to