diff --git a/src/core/cgroup.c b/src/core/cgroup.c index af611e7e7b..c6667b39c7 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -2224,6 +2224,7 @@ int unit_get_ip_accounting( CGroupIPAccountingMetric metric, uint64_t *ret) { + uint64_t value; int fd, r; assert(u); @@ -2239,9 +2240,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; } @@ -2275,6 +2284,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; } diff --git a/src/core/unit.c b/src/core/unit.c index bb40baf236..5ed5764455 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -2770,7 +2770,15 @@ static int unit_serialize_cgroup_mask(FILE *f, const char *key, CGroupMask mask) return r; } +static const char *ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = { + [CGROUP_IP_INGRESS_BYTES] = "ip-accounting-ingress-bytes", + [CGROUP_IP_INGRESS_PACKETS] = "ip-accounting-ingress-packets", + [CGROUP_IP_EGRESS_BYTES] = "ip-accounting-egress-bytes", + [CGROUP_IP_EGRESS_PACKETS] = "ip-accounting-egress-packets", +}; + int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { + CGroupIPAccountingMetric m; int r; assert(u); @@ -2831,6 +2839,14 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { bus_track_serialize(u->bus_track, f, "ref"); + for (m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++) { + uint64_t v; + + r = unit_get_ip_accounting(u, m, &v); + if (r >= 0) + unit_serialize_item_format(u, f, ip_accounting_metric_field[m], "%" PRIu64, v); + } + if (serialize_jobs) { if (u->job) { fprintf(f, "job\n"); @@ -2937,6 +2953,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { for (;;) { char line[LINE_MAX], *l, *v; + CGroupIPAccountingMetric m; size_t k; if (!fgets(line, sizeof(line), f)) { @@ -3147,6 +3164,21 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { continue; } + /* Check if this is an IP accounting metric serialization field */ + for (m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++) + if (streq(l, ip_accounting_metric_field[m])) + break; + if (m < _CGROUP_IP_ACCOUNTING_METRIC_MAX) { + uint64_t c; + + r = safe_atou64(v, &c); + if (r < 0) + log_unit_debug(u, "Failed to parse IP accounting value %s, ignoring.", v); + else + u->ip_accounting_extra[m] = c; + continue; + } + if (unit_can_serialize(u)) { if (rt) { r = exec_runtime_deserialize_item(u, rt, l, v, fds); diff --git a/src/core/unit.h b/src/core/unit.h index a707e5259d..2759bd07a2 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -34,6 +34,7 @@ typedef struct UnitStatusMessageFormats UnitStatusMessageFormats; #include "install.h" #include "list.h" #include "unit-name.h" +#include "cgroup.h" typedef enum KillOperation { KILL_TERMINATE, @@ -224,6 +225,8 @@ struct Unit { BPFProgram *ip_bpf_ingress; BPFProgram *ip_bpf_egress; + uint64_t ip_accounting_extra[_CGROUP_IP_ACCOUNTING_METRIC_MAX]; + /* How to start OnFailure units */ JobMode on_failure_job_mode;