tools: cgroup filtering in execsnoop/opensnoop

Add a new option --cgroupmap in execsnoop and opensnoop to only display
results from processes that belong to one of the cgroups whose id,
returned by bpf_get_current_cgroup_id(), is in a pinned BPF hash map.

Examples of commands:
    # opensnoop --cgroupmap /sys/fs/bpf/test01
    # execsnoop --cgroupmap /sys/fs/bpf/test01

Cgroup ids can be discovered in userspace by the system call
name_to_handle_at(); an example of C program doing that is available in
examples/cgroupid/cgroupid.c.

More complete documentation is added in docs/filtering_by_cgroups.md

The documentation is independent from Kubernetes. However, my goal is to
use this feature in Kubernetes: I am preparing to use this in Inspektor
Gadget to select specific Kubernetes pods, depending on a Kubernetes
label selector. Kubernetes pods matching the label selector can come and
go during the execution of the bcc tools; Inspektor Gadget is updating
the BPF hash map used by the bcc tools accordingly.
diff --git a/tools/opensnoop.py b/tools/opensnoop.py
index 60d11c6..6d1388b 100755
--- a/tools/opensnoop.py
+++ b/tools/opensnoop.py
@@ -35,6 +35,7 @@
     ./opensnoop -n main   # only print process names containing "main"
     ./opensnoop -e        # show extended fields
     ./opensnoop -f O_WRONLY -f O_RDWR  # only print calls for writing
+    ./opensnoop --cgroupmap ./mappath  # only trace cgroups in this BPF map
 """
 parser = argparse.ArgumentParser(
     description="Trace open() syscalls",
@@ -50,6 +51,8 @@
     help="trace this PID only")
 parser.add_argument("-t", "--tid",
     help="trace this TID only")
+parser.add_argument("--cgroupmap",
+    help="trace cgroups in this BPF map only")
 parser.add_argument("-u", "--uid",
     help="trace this UID only")
 parser.add_argument("-d", "--duration",
@@ -99,6 +102,9 @@
     int flags; // EXTENDED_STRUCT_MEMBER
 };
 
+#if CGROUPSET
+BPF_TABLE_PINNED("hash", u64, u64, cgroupset, 1024, "CGROUPPATH");
+#endif
 BPF_HASH(infotmp, u64, struct val_t);
 BPF_PERF_OUTPUT(events);
 
@@ -113,6 +119,12 @@
     PID_TID_FILTER
     UID_FILTER
     FLAGS_FILTER
+#if CGROUPSET
+    u64 cgroupid = bpf_get_current_cgroup_id();
+    if (cgroupset.lookup(&cgroupid) == NULL) {
+      return 0;
+    }
+#endif
     if (bpf_get_current_comm(&val.comm, sizeof(val.comm)) == 0) {
         val.id = id;
         val.fname = filename;
@@ -163,6 +175,11 @@
         'if (uid != %s) { return 0; }' % args.uid)
 else:
     bpf_text = bpf_text.replace('UID_FILTER', '')
+if args.cgroupmap:
+    bpf_text = bpf_text.replace('CGROUPSET', '1')
+    bpf_text = bpf_text.replace('CGROUPPATH', args.cgroupmap)
+else:
+    bpf_text = bpf_text.replace('CGROUPSET', '0')
 if args.flag_filter:
     bpf_text = bpf_text.replace('FLAGS_FILTER',
         'if (!(flags & %d)) { return 0; }' % flag_filter_mask)