PERF_SAMPLE_TYPE(TRANSACTION, "--transaction"),
        PERF_SAMPLE_TYPE(CODE_PAGE_SIZE, "--code-page-size"),
        PERF_SAMPLE_TYPE(DATA_PAGE_SIZE, "--data-page-size"),
+       PERF_SAMPLE_TYPE(CGROUP, "--all-cgroups"),
 };
 
 static int get_pinned_fd(const char *name);
 
 #include "bpf-filter.h"
 #include "bpf-filter-bison.h"
 
+extern int perf_bpf_filter_needs_path;
+
 static int sample(enum perf_bpf_filter_term term)
 {
+       perf_bpf_filter_needs_path = 0;
        perf_bpf_filter_lval.sample.term = term;
        perf_bpf_filter_lval.sample.part = 0;
        return BFT_SAMPLE;
 
 static int sample_part(enum perf_bpf_filter_term term, int part)
 {
+       perf_bpf_filter_needs_path = 0;
        perf_bpf_filter_lval.sample.term = term;
        perf_bpf_filter_lval.sample.part = part;
        return BFT_SAMPLE;
 }
 
+static int sample_path(enum perf_bpf_filter_term term)
+{
+       perf_bpf_filter_needs_path = 1;
+       perf_bpf_filter_lval.sample.term = term;
+       perf_bpf_filter_lval.sample.part = 0;
+       return BFT_SAMPLE_PATH;
+}
+
 static int operator(enum perf_bpf_filter_op op)
 {
        perf_bpf_filter_lval.op = op;
        return BFT_NUM;
 }
 
-static int error(const char *str)
+static int path_or_error(void)
 {
-       printf("perf_bpf_filter: Unexpected filter %s: %s\n", str, perf_bpf_filter_text);
-       return BFT_ERROR;
+       if (!perf_bpf_filter_needs_path) {
+               printf("perf_bpf_filter: Error: Unexpected item: %s\n",
+                       perf_bpf_filter_text);
+               return BFT_ERROR;
+       }
+       perf_bpf_filter_lval.path = perf_bpf_filter_text;
+       return BFT_PATH;
 }
 
 %}
 num_dec                [0-9]+
 num_hex                0[Xx][0-9a-fA-F]+
 space          [ \t]+
+path           [^ \t\n]+
 ident          [_a-zA-Z][_a-zA-Z0-9]+
 
 %%
 mem_hops       { return sample_part(PBF_TERM_DATA_SRC, 8); }
 uid            { return sample(PBF_TERM_UID); }
 gid            { return sample(PBF_TERM_GID); }
+cgroup         { return sample_path(PBF_TERM_CGROUP); }
 
 "=="           { return operator(PBF_OP_EQ); }
 "!="           { return operator(PBF_OP_NEQ); }
 ","            { return ','; }
 "||"           { return BFT_LOGICAL_OR; }
 
-{ident}                { return error("ident"); }
-.              { return error("input"); }
+{path}         { return path_or_error(); }
 
 %%
 
 #include <linux/compiler.h>
 #include <linux/list.h>
 #include "bpf-filter.h"
+#include "cgroup.h"
 
 int perf_bpf_filter_lex(void);
 
+/* To indicate if the current term needs a pathname or not */
+int perf_bpf_filter_needs_path;
+
 static void perf_bpf_filter_error(struct list_head *expr __maybe_unused,
                                  char const *msg)
 {
 %union
 {
        unsigned long num;
+       char *path;
        struct {
                enum perf_bpf_filter_term term;
                int part;
        struct perf_bpf_filter_expr *expr;
 }
 
-%token BFT_SAMPLE BFT_OP BFT_ERROR BFT_NUM BFT_LOGICAL_OR
+%token BFT_SAMPLE BFT_SAMPLE_PATH BFT_OP BFT_ERROR BFT_NUM BFT_LOGICAL_OR BFT_PATH
 %type <expr> filter_term filter_expr
 %destructor { free ($$); } <expr>
-%type <sample> BFT_SAMPLE
+%type <sample> BFT_SAMPLE BFT_SAMPLE_PATH
 %type <op> BFT_OP
 %type <num> BFT_NUM
+%type <path> BFT_PATH
 
 %%
 
 {
        $$ = perf_bpf_filter_expr__new($1.term, $1.part, $2, $3);
 }
+|
+BFT_SAMPLE_PATH BFT_OP BFT_PATH
+{
+       struct cgroup *cgrp;
+       unsigned long cgroup_id = 0;
+
+       if ($2 != PBF_OP_EQ && $2 != PBF_OP_NEQ) {
+               printf("perf_bpf_filter: cgroup accepts '==' or '!=' only\n");
+               YYERROR;
+       }
+
+       cgrp = cgroup__new($3, /*do_open=*/false);
+       if (cgrp && read_cgroup_id(cgrp) == 0)
+               cgroup_id = cgrp->id;
+
+       $$ = perf_bpf_filter_expr__new($1.term, $1.part, $2, cgroup_id);
+       cgroup__put(cgrp);
+}
 
 %%
 
        __PBF_UNUSED_TERM18     = PBF_TERM_SAMPLE_START + 18, /* SAMPLE_REGS_INTR = 1U << 18 */
        PBF_TERM_PHYS_ADDR      = PBF_TERM_SAMPLE_START + 19, /* SAMPLE_PHYS_ADDR = 1U << 19 */
        __PBF_UNUSED_TERM20     = PBF_TERM_SAMPLE_START + 20, /* SAMPLE_AUX = 1U << 20 */
-       __PBF_UNUSED_TERM21     = PBF_TERM_SAMPLE_START + 21, /* SAMPLE_CGROUP = 1U << 21 */
+       PBF_TERM_CGROUP         = PBF_TERM_SAMPLE_START + 21, /* SAMPLE_CGROUP = 1U << 21 */
        PBF_TERM_DATA_PAGE_SIZE = PBF_TERM_SAMPLE_START + 22, /* SAMPLE_DATA_PAGE_SIZE = 1U << 22 */
        PBF_TERM_CODE_PAGE_SIZE = PBF_TERM_SAMPLE_START + 23, /* SAMPLE_CODE_PAGE_SIZE = 1U << 23 */
        PBF_TERM_WEIGHT_STRUCT  = PBF_TERM_SAMPLE_START + 24, /* SAMPLE_WEIGHT_STRUCT = 1U << 24 */
 
        BUILD_CHECK_SAMPLE(DATA_SRC);
        BUILD_CHECK_SAMPLE(TRANSACTION);
        BUILD_CHECK_SAMPLE(PHYS_ADDR);
+       BUILD_CHECK_SAMPLE(CGROUP);
        BUILD_CHECK_SAMPLE(DATA_PAGE_SIZE);
        BUILD_CHECK_SAMPLE(CODE_PAGE_SIZE);
        BUILD_CHECK_SAMPLE(WEIGHT_STRUCT);
                return kctx->data->weight.full;
        case PBF_TERM_PHYS_ADDR:
                return kctx->data->phys_addr;
+       case PBF_TERM_CGROUP:
+               return kctx->data->cgroup;
        case PBF_TERM_CODE_PAGE_SIZE:
                return kctx->data->code_page_size;
        case PBF_TERM_DATA_PAGE_SIZE:
        case __PBF_UNUSED_TERM16:
        case __PBF_UNUSED_TERM18:
        case __PBF_UNUSED_TERM20:
-       case __PBF_UNUSED_TERM21:
        default:
                break;
        }
 
                u32              cpu;
        } cpu_entry;
        u64                      phys_addr;
+       u64                      cgroup;
        u64                      data_page_size;
        u64                      code_page_size;
 } __attribute__((__aligned__(64))) __attribute__((preserve_access_index));