]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
bpf-firewall: give a name to maps used
authorDominique Martinet <asmadeus@codewreck.org>
Sun, 16 Apr 2023 07:14:49 +0000 (16:14 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 17 Apr 2023 23:23:55 +0000 (08:23 +0900)
Running systemd with IP accounting enabled generates many bpf maps (two
per unit for accounting, another two if IPAddressAllow/Deny are used).

Systemd itself knows which maps belong to what unit and commands like
`systemctl status <unit>` can be used to query what service has which
map, but monitoring these values all the time costs 4 dbus requests
(calling the .IP{E,I}gress{Bytes,Packets} method for each unit) and
makes services like the prometheus systemd_exporter[1] somewhat slow
when doing that for every units, while less precise information could
quickly be obtained by looking directly at the maps.

Unfortunately, bpf map names are rather limited:
- only 15 characters in length (16, but last byte must be 0)
- only allows isalnum(), _ and . characters

If it wasn't for the length limit we could use the normal unit escape
functions but I've opted to just make any forbidden character into
underscores for maximum brievty -- the map prefix is also rather short:
This isn't meant as a precise mapping, but as a hint for admins who want
to look at these.

(Note there is no problem if multiple maps have the same name)

Link: https://github.com/povilasv/systemd_exporter
src/core/bpf-firewall.c
src/shared/bpf-program.c
src/shared/bpf-program.h

index 5878a8187915456f11510d211bbcf845b2fef8da..0861b4b829110060afe9af9a7fb2a7b40ce48acf 100644 (file)
@@ -451,7 +451,9 @@ static int bpf_firewall_prepare_access_maps(
         }
 
         if (n_ipv4 > 0) {
+                char *name = strjoina("4_", u->id);
                 ipv4_map_fd = bpf_map_new(
+                                name,
                                 BPF_MAP_TYPE_LPM_TRIE,
                                 offsetof(struct bpf_lpm_trie_key, data) + sizeof(uint32_t),
                                 sizeof(uint64_t),
@@ -462,7 +464,9 @@ static int bpf_firewall_prepare_access_maps(
         }
 
         if (n_ipv6 > 0) {
+                char *name = strjoina("6_", u->id);
                 ipv6_map_fd = bpf_map_new(
+                                name,
                                 BPF_MAP_TYPE_LPM_TRIE,
                                 offsetof(struct bpf_lpm_trie_key, data) + sizeof(uint32_t)*4,
                                 sizeof(uint64_t),
@@ -500,7 +504,8 @@ static int bpf_firewall_prepare_accounting_maps(Unit *u, bool enabled, int *fd_i
 
         if (enabled) {
                 if (*fd_ingress < 0) {
-                        r = bpf_map_new(BPF_MAP_TYPE_ARRAY, sizeof(int), sizeof(uint64_t), 2, 0);
+                        char *name = strjoina("I_", u->id);
+                        r = bpf_map_new(name, BPF_MAP_TYPE_ARRAY, sizeof(int), sizeof(uint64_t), 2, 0);
                         if (r < 0)
                                 return r;
 
@@ -508,8 +513,8 @@ static int bpf_firewall_prepare_accounting_maps(Unit *u, bool enabled, int *fd_i
                 }
 
                 if (*fd_egress < 0) {
-
-                        r = bpf_map_new(BPF_MAP_TYPE_ARRAY, sizeof(int), sizeof(uint64_t), 2, 0);
+                        char *name = strjoina("E_", u->id);
+                        r = bpf_map_new(name, BPF_MAP_TYPE_ARRAY, sizeof(int), sizeof(uint64_t), 2, 0);
                         if (r < 0)
                                 return r;
 
index 531ae9b6805e667f82aa24936a8ba2a22476bada..d5eb6f4ccbaa64347a0b4a09cffffd674f6b6df9 100644 (file)
@@ -300,8 +300,16 @@ int bpf_program_cgroup_detach(BPFProgram *p) {
         return 0;
 }
 
-int bpf_map_new(enum bpf_map_type type, size_t key_size, size_t value_size, size_t max_entries, uint32_t flags) {
+int bpf_map_new(
+                const char *name,
+                enum bpf_map_type type,
+                size_t key_size,
+                size_t value_size,
+                size_t max_entries,
+                uint32_t flags) {
+
         union bpf_attr attr;
+        const char *n = name;
 
         zero(attr);
         attr.map_type = type;
@@ -310,6 +318,13 @@ int bpf_map_new(enum bpf_map_type type, size_t key_size, size_t value_size, size
         attr.max_entries = max_entries;
         attr.map_flags = flags;
 
+        /* The map name is primarily informational for debugging purposes, and typically too short
+         * to carry the full unit name, hence we employ a trivial lossy escaping to make it fit
+         * (truncation + only alphanumerical, "." and "_" are allowed as per
+         * https://www.kernel.org/doc/html/next/bpf/maps.html#usage-notes) */
+        for (size_t i = 0; i < sizeof(attr.map_name) - 1 && *n; i++, n++)
+                attr.map_name[i] = strchr(ALPHANUMERICAL ".", *n) ? *n : '_';
+
         return RET_NERRNO(bpf(BPF_MAP_CREATE, &attr, sizeof(attr)));
 }
 
index b640fb9d9f655fa5c9f3c30aa179a3461604f773..0e0b666df6ff9ab8ae44a35e14f028bec04cbdeb 100644 (file)
@@ -54,7 +54,8 @@ int bpf_program_deserialize_attachment_set(const char *v, FDSet *fds, Set **bpfs
 
 extern const struct hash_ops bpf_program_hash_ops;
 
-int bpf_map_new(enum bpf_map_type type, size_t key_size, size_t value_size, size_t max_entries, uint32_t flags);
+int bpf_map_new(const char *name, enum bpf_map_type type, size_t key_size, size_t value_size,
+                size_t max_entries, uint32_t flags);
 int bpf_map_update_element(int fd, const void *key, void *value);
 int bpf_map_lookup_element(int fd, const void *key, void *value);