chiark / gitweb /
core: serialize/deserialize IP accounting across daemon reload/reexec
authorLennart Poettering <lennart@poettering.net>
Thu, 7 Sep 2017 12:07:13 +0000 (14:07 +0200)
committerSven Eden <yamakuzure@gmx.net>
Thu, 7 Sep 2017 12:07:13 +0000 (14:07 +0200)
Make sure the current IP accounting counters aren't lost during
reload/reexec.

Note that we destroy all BPF file objects during a reload: the BPF
programs, the access and the accounting maps. The former two need to be
regenerated anyway with the newly loaded configuration data, but the
latter one needs to survive reloads/reexec. In this implementation I
opted to only save/restore the accounting map content instead of the map
itself. While this opens a (theoretic) window where IP traffic is still
accounted to the old map after we read it out, and we thus miss a few
bytes this has the benefit that we can alter the map layout between
versions should the need arise.

src/core/cgroup.c

index 4d15a1e3bb9831b2b31b84d6859f85a0196d4450..1d1e2d38ec1189fdbc23c5ee8ac7deb31872ed74 100644 (file)
@@ -2281,6 +2281,7 @@ int unit_get_ip_accounting(
                 CGroupIPAccountingMetric metric,
                 uint64_t *ret) {
 
+        uint64_t value;
         int fd, r;
 
         assert(u);
@@ -2296,9 +2297,17 @@ int unit_get_ip_accounting(
                 return -ENODATA;
 
         if (IN_SET(metric, CGROUP_IP_INGRESS_BYTES, CGROUP_IP_EGRESS_BYTES))
-                r = bpf_firewall_read_accounting(fd, ret, NULL);
+                r = bpf_firewall_read_accounting(fd, &value, NULL);
         else
-                r = bpf_firewall_read_accounting(fd, NULL, ret);
+                r = bpf_firewall_read_accounting(fd, NULL, &value);
+        if (r < 0)
+                return r;
+
+        /* Add in additional metrics from a previous runtime. Note that when reexecing/reloading the daemon we compile
+         * all BPF programs and maps anew, but serialize the old counters. When deserializing we store them in the
+         * ip_accounting_extra[] field, and add them in here transparently. */
+
+        *ret = value + u->ip_accounting_extra[metric];
 
         return r;
 }
@@ -2332,6 +2341,8 @@ int unit_reset_ip_accounting(Unit *u) {
         if (u->ip_accounting_egress_map_fd >= 0)
                 q = bpf_firewall_reset_accounting(u->ip_accounting_egress_map_fd);
 
+        zero(u->ip_accounting_extra);
+
         return r < 0 ? r : q;
 }