Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 
0003 /*
0004  * Copyright 2020 Google LLC.
0005  */
0006 
0007 #include <test_progs.h>
0008 #include <cgroup_helpers.h>
0009 #include <network_helpers.h>
0010 
0011 #include "progs/cg_storage_multi.h"
0012 
0013 #include "cg_storage_multi_egress_only.skel.h"
0014 #include "cg_storage_multi_isolated.skel.h"
0015 #include "cg_storage_multi_shared.skel.h"
0016 
0017 #define PARENT_CGROUP "/cgroup_storage"
0018 #define CHILD_CGROUP "/cgroup_storage/child"
0019 
0020 static int duration;
0021 
0022 static bool assert_storage(struct bpf_map *map, const void *key,
0023                struct cgroup_value *expected)
0024 {
0025     struct cgroup_value value;
0026     int map_fd;
0027 
0028     map_fd = bpf_map__fd(map);
0029 
0030     if (CHECK(bpf_map_lookup_elem(map_fd, key, &value) < 0,
0031           "map-lookup", "errno %d", errno))
0032         return true;
0033     if (CHECK(memcmp(&value, expected, sizeof(struct cgroup_value)),
0034           "assert-storage", "storages differ"))
0035         return true;
0036 
0037     return false;
0038 }
0039 
0040 static bool assert_storage_noexist(struct bpf_map *map, const void *key)
0041 {
0042     struct cgroup_value value;
0043     int map_fd;
0044 
0045     map_fd = bpf_map__fd(map);
0046 
0047     if (CHECK(bpf_map_lookup_elem(map_fd, key, &value) == 0,
0048           "map-lookup", "succeeded, expected ENOENT"))
0049         return true;
0050     if (CHECK(errno != ENOENT,
0051           "map-lookup", "errno %d, expected ENOENT", errno))
0052         return true;
0053 
0054     return false;
0055 }
0056 
0057 static bool connect_send(const char *cgroup_path)
0058 {
0059     bool res = true;
0060     int server_fd = -1, client_fd = -1;
0061 
0062     if (join_cgroup(cgroup_path))
0063         goto out_clean;
0064 
0065     server_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 0, 0);
0066     if (server_fd < 0)
0067         goto out_clean;
0068 
0069     client_fd = connect_to_fd(server_fd, 0);
0070     if (client_fd < 0)
0071         goto out_clean;
0072 
0073     if (send(client_fd, "message", strlen("message"), 0) < 0)
0074         goto out_clean;
0075 
0076     res = false;
0077 
0078 out_clean:
0079     close(client_fd);
0080     close(server_fd);
0081     return res;
0082 }
0083 
0084 static void test_egress_only(int parent_cgroup_fd, int child_cgroup_fd)
0085 {
0086     struct cg_storage_multi_egress_only *obj;
0087     struct cgroup_value expected_cgroup_value;
0088     struct bpf_cgroup_storage_key key;
0089     struct bpf_link *parent_link = NULL, *child_link = NULL;
0090     bool err;
0091 
0092     key.attach_type = BPF_CGROUP_INET_EGRESS;
0093 
0094     obj = cg_storage_multi_egress_only__open_and_load();
0095     if (CHECK(!obj, "skel-load", "errno %d", errno))
0096         return;
0097 
0098     /* Attach to parent cgroup, trigger packet from child.
0099      * Assert that there is only one run and in that run the storage is
0100      * parent cgroup's storage.
0101      * Also assert that child cgroup's storage does not exist
0102      */
0103     parent_link = bpf_program__attach_cgroup(obj->progs.egress,
0104                          parent_cgroup_fd);
0105     if (!ASSERT_OK_PTR(parent_link, "parent-cg-attach"))
0106         goto close_bpf_object;
0107     err = connect_send(CHILD_CGROUP);
0108     if (CHECK(err, "first-connect-send", "errno %d", errno))
0109         goto close_bpf_object;
0110     if (CHECK(obj->bss->invocations != 1,
0111           "first-invoke", "invocations=%d", obj->bss->invocations))
0112         goto close_bpf_object;
0113     key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
0114     expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 };
0115     if (assert_storage(obj->maps.cgroup_storage,
0116                &key, &expected_cgroup_value))
0117         goto close_bpf_object;
0118     key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
0119     if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
0120         goto close_bpf_object;
0121 
0122     /* Attach to parent and child cgroup, trigger packet from child.
0123      * Assert that there are two additional runs, one that run with parent
0124      * cgroup's storage and one with child cgroup's storage.
0125      */
0126     child_link = bpf_program__attach_cgroup(obj->progs.egress,
0127                         child_cgroup_fd);
0128     if (!ASSERT_OK_PTR(child_link, "child-cg-attach"))
0129         goto close_bpf_object;
0130     err = connect_send(CHILD_CGROUP);
0131     if (CHECK(err, "second-connect-send", "errno %d", errno))
0132         goto close_bpf_object;
0133     if (CHECK(obj->bss->invocations != 3,
0134           "second-invoke", "invocations=%d", obj->bss->invocations))
0135         goto close_bpf_object;
0136     key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
0137     expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
0138     if (assert_storage(obj->maps.cgroup_storage,
0139                &key, &expected_cgroup_value))
0140         goto close_bpf_object;
0141     key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
0142     expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 1 };
0143     if (assert_storage(obj->maps.cgroup_storage,
0144                &key, &expected_cgroup_value))
0145         goto close_bpf_object;
0146 
0147 close_bpf_object:
0148     bpf_link__destroy(parent_link);
0149     bpf_link__destroy(child_link);
0150 
0151     cg_storage_multi_egress_only__destroy(obj);
0152 }
0153 
0154 static void test_isolated(int parent_cgroup_fd, int child_cgroup_fd)
0155 {
0156     struct cg_storage_multi_isolated *obj;
0157     struct cgroup_value expected_cgroup_value;
0158     struct bpf_cgroup_storage_key key;
0159     struct bpf_link *parent_egress1_link = NULL, *parent_egress2_link = NULL;
0160     struct bpf_link *child_egress1_link = NULL, *child_egress2_link = NULL;
0161     struct bpf_link *parent_ingress_link = NULL, *child_ingress_link = NULL;
0162     bool err;
0163 
0164     obj = cg_storage_multi_isolated__open_and_load();
0165     if (CHECK(!obj, "skel-load", "errno %d", errno))
0166         return;
0167 
0168     /* Attach to parent cgroup, trigger packet from child.
0169      * Assert that there is three runs, two with parent cgroup egress and
0170      * one with parent cgroup ingress, stored in separate parent storages.
0171      * Also assert that child cgroup's storages does not exist
0172      */
0173     parent_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
0174                              parent_cgroup_fd);
0175     if (!ASSERT_OK_PTR(parent_egress1_link, "parent-egress1-cg-attach"))
0176         goto close_bpf_object;
0177     parent_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
0178                              parent_cgroup_fd);
0179     if (!ASSERT_OK_PTR(parent_egress2_link, "parent-egress2-cg-attach"))
0180         goto close_bpf_object;
0181     parent_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
0182                              parent_cgroup_fd);
0183     if (!ASSERT_OK_PTR(parent_ingress_link, "parent-ingress-cg-attach"))
0184         goto close_bpf_object;
0185     err = connect_send(CHILD_CGROUP);
0186     if (CHECK(err, "first-connect-send", "errno %d", errno))
0187         goto close_bpf_object;
0188     if (CHECK(obj->bss->invocations != 3,
0189           "first-invoke", "invocations=%d", obj->bss->invocations))
0190         goto close_bpf_object;
0191     key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
0192     key.attach_type = BPF_CGROUP_INET_EGRESS;
0193     expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
0194     if (assert_storage(obj->maps.cgroup_storage,
0195                &key, &expected_cgroup_value))
0196         goto close_bpf_object;
0197     key.attach_type = BPF_CGROUP_INET_INGRESS;
0198     expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 1 };
0199     if (assert_storage(obj->maps.cgroup_storage,
0200                &key, &expected_cgroup_value))
0201         goto close_bpf_object;
0202     key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
0203     key.attach_type = BPF_CGROUP_INET_EGRESS;
0204     if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
0205         goto close_bpf_object;
0206     key.attach_type = BPF_CGROUP_INET_INGRESS;
0207     if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
0208         goto close_bpf_object;
0209 
0210     /* Attach to parent and child cgroup, trigger packet from child.
0211      * Assert that there is six additional runs, parent cgroup egresses and
0212      * ingress, child cgroup egresses and ingress.
0213      * Assert that egree and ingress storages are separate.
0214      */
0215     child_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
0216                             child_cgroup_fd);
0217     if (!ASSERT_OK_PTR(child_egress1_link, "child-egress1-cg-attach"))
0218         goto close_bpf_object;
0219     child_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
0220                             child_cgroup_fd);
0221     if (!ASSERT_OK_PTR(child_egress2_link, "child-egress2-cg-attach"))
0222         goto close_bpf_object;
0223     child_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
0224                             child_cgroup_fd);
0225     if (!ASSERT_OK_PTR(child_ingress_link, "child-ingress-cg-attach"))
0226         goto close_bpf_object;
0227     err = connect_send(CHILD_CGROUP);
0228     if (CHECK(err, "second-connect-send", "errno %d", errno))
0229         goto close_bpf_object;
0230     if (CHECK(obj->bss->invocations != 9,
0231           "second-invoke", "invocations=%d", obj->bss->invocations))
0232         goto close_bpf_object;
0233     key.cgroup_inode_id = get_cgroup_id(PARENT_CGROUP);
0234     key.attach_type = BPF_CGROUP_INET_EGRESS;
0235     expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 4 };
0236     if (assert_storage(obj->maps.cgroup_storage,
0237                &key, &expected_cgroup_value))
0238         goto close_bpf_object;
0239     key.attach_type = BPF_CGROUP_INET_INGRESS;
0240     expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 2 };
0241     if (assert_storage(obj->maps.cgroup_storage,
0242                &key, &expected_cgroup_value))
0243         goto close_bpf_object;
0244     key.cgroup_inode_id = get_cgroup_id(CHILD_CGROUP);
0245     key.attach_type = BPF_CGROUP_INET_EGRESS;
0246     expected_cgroup_value = (struct cgroup_value) { .egress_pkts = 2 };
0247     if (assert_storage(obj->maps.cgroup_storage,
0248                &key, &expected_cgroup_value))
0249         goto close_bpf_object;
0250     key.attach_type = BPF_CGROUP_INET_INGRESS;
0251     expected_cgroup_value = (struct cgroup_value) { .ingress_pkts = 1 };
0252     if (assert_storage(obj->maps.cgroup_storage,
0253                &key, &expected_cgroup_value))
0254         goto close_bpf_object;
0255 
0256 close_bpf_object:
0257     bpf_link__destroy(parent_egress1_link);
0258     bpf_link__destroy(parent_egress2_link);
0259     bpf_link__destroy(parent_ingress_link);
0260     bpf_link__destroy(child_egress1_link);
0261     bpf_link__destroy(child_egress2_link);
0262     bpf_link__destroy(child_ingress_link);
0263 
0264     cg_storage_multi_isolated__destroy(obj);
0265 }
0266 
0267 static void test_shared(int parent_cgroup_fd, int child_cgroup_fd)
0268 {
0269     struct cg_storage_multi_shared *obj;
0270     struct cgroup_value expected_cgroup_value;
0271     __u64 key;
0272     struct bpf_link *parent_egress1_link = NULL, *parent_egress2_link = NULL;
0273     struct bpf_link *child_egress1_link = NULL, *child_egress2_link = NULL;
0274     struct bpf_link *parent_ingress_link = NULL, *child_ingress_link = NULL;
0275     bool err;
0276 
0277     obj = cg_storage_multi_shared__open_and_load();
0278     if (CHECK(!obj, "skel-load", "errno %d", errno))
0279         return;
0280 
0281     /* Attach to parent cgroup, trigger packet from child.
0282      * Assert that there is three runs, two with parent cgroup egress and
0283      * one with parent cgroup ingress.
0284      * Also assert that child cgroup's storage does not exist
0285      */
0286     parent_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
0287                              parent_cgroup_fd);
0288     if (!ASSERT_OK_PTR(parent_egress1_link, "parent-egress1-cg-attach"))
0289         goto close_bpf_object;
0290     parent_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
0291                              parent_cgroup_fd);
0292     if (!ASSERT_OK_PTR(parent_egress2_link, "parent-egress2-cg-attach"))
0293         goto close_bpf_object;
0294     parent_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
0295                              parent_cgroup_fd);
0296     if (!ASSERT_OK_PTR(parent_ingress_link, "parent-ingress-cg-attach"))
0297         goto close_bpf_object;
0298     err = connect_send(CHILD_CGROUP);
0299     if (CHECK(err, "first-connect-send", "errno %d", errno))
0300         goto close_bpf_object;
0301     if (CHECK(obj->bss->invocations != 3,
0302           "first-invoke", "invocations=%d", obj->bss->invocations))
0303         goto close_bpf_object;
0304     key = get_cgroup_id(PARENT_CGROUP);
0305     expected_cgroup_value = (struct cgroup_value) {
0306         .egress_pkts = 2,
0307         .ingress_pkts = 1,
0308     };
0309     if (assert_storage(obj->maps.cgroup_storage,
0310                &key, &expected_cgroup_value))
0311         goto close_bpf_object;
0312     key = get_cgroup_id(CHILD_CGROUP);
0313     if (assert_storage_noexist(obj->maps.cgroup_storage, &key))
0314         goto close_bpf_object;
0315 
0316     /* Attach to parent and child cgroup, trigger packet from child.
0317      * Assert that there is six additional runs, parent cgroup egresses and
0318      * ingress, child cgroup egresses and ingress.
0319      */
0320     child_egress1_link = bpf_program__attach_cgroup(obj->progs.egress1,
0321                             child_cgroup_fd);
0322     if (!ASSERT_OK_PTR(child_egress1_link, "child-egress1-cg-attach"))
0323         goto close_bpf_object;
0324     child_egress2_link = bpf_program__attach_cgroup(obj->progs.egress2,
0325                             child_cgroup_fd);
0326     if (!ASSERT_OK_PTR(child_egress2_link, "child-egress2-cg-attach"))
0327         goto close_bpf_object;
0328     child_ingress_link = bpf_program__attach_cgroup(obj->progs.ingress,
0329                             child_cgroup_fd);
0330     if (!ASSERT_OK_PTR(child_ingress_link, "child-ingress-cg-attach"))
0331         goto close_bpf_object;
0332     err = connect_send(CHILD_CGROUP);
0333     if (CHECK(err, "second-connect-send", "errno %d", errno))
0334         goto close_bpf_object;
0335     if (CHECK(obj->bss->invocations != 9,
0336           "second-invoke", "invocations=%d", obj->bss->invocations))
0337         goto close_bpf_object;
0338     key = get_cgroup_id(PARENT_CGROUP);
0339     expected_cgroup_value = (struct cgroup_value) {
0340         .egress_pkts = 4,
0341         .ingress_pkts = 2,
0342     };
0343     if (assert_storage(obj->maps.cgroup_storage,
0344                &key, &expected_cgroup_value))
0345         goto close_bpf_object;
0346     key = get_cgroup_id(CHILD_CGROUP);
0347     expected_cgroup_value = (struct cgroup_value) {
0348         .egress_pkts = 2,
0349         .ingress_pkts = 1,
0350     };
0351     if (assert_storage(obj->maps.cgroup_storage,
0352                &key, &expected_cgroup_value))
0353         goto close_bpf_object;
0354 
0355 close_bpf_object:
0356     bpf_link__destroy(parent_egress1_link);
0357     bpf_link__destroy(parent_egress2_link);
0358     bpf_link__destroy(parent_ingress_link);
0359     bpf_link__destroy(child_egress1_link);
0360     bpf_link__destroy(child_egress2_link);
0361     bpf_link__destroy(child_ingress_link);
0362 
0363     cg_storage_multi_shared__destroy(obj);
0364 }
0365 
0366 void serial_test_cg_storage_multi(void)
0367 {
0368     int parent_cgroup_fd = -1, child_cgroup_fd = -1;
0369 
0370     parent_cgroup_fd = test__join_cgroup(PARENT_CGROUP);
0371     if (CHECK(parent_cgroup_fd < 0, "cg-create-parent", "errno %d", errno))
0372         goto close_cgroup_fd;
0373     child_cgroup_fd = create_and_get_cgroup(CHILD_CGROUP);
0374     if (CHECK(child_cgroup_fd < 0, "cg-create-child", "errno %d", errno))
0375         goto close_cgroup_fd;
0376 
0377     if (test__start_subtest("egress_only"))
0378         test_egress_only(parent_cgroup_fd, child_cgroup_fd);
0379 
0380     if (test__start_subtest("isolated"))
0381         test_isolated(parent_cgroup_fd, child_cgroup_fd);
0382 
0383     if (test__start_subtest("shared"))
0384         test_shared(parent_cgroup_fd, child_cgroup_fd);
0385 
0386 close_cgroup_fd:
0387     close(child_cgroup_fd);
0388     close(parent_cgroup_fd);
0389 }