| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "proc_net_dev_renames.h" |
| 4 | |
| 5 | DICTIONARY *netdev_renames = NULL; |
| 6 | |
| 7 | static void netdev_rename_task_cleanup_unsafe(struct rename_task *r) { |
| 8 | cgroup_netdev_release(r->cgroup_netdev_link); |
| 9 | r->cgroup_netdev_link = NULL; |
| 10 | |
| 11 | rrdlabels_destroy(r->chart_labels); |
| 12 | r->chart_labels = NULL; |
| 13 | |
| 14 | freez_and_set_to_null(r->container_name); |
| 15 | freez_and_set_to_null(r->container_device); |
| 16 | freez_and_set_to_null(r->ctx_prefix); |
| 17 | } |
| 18 | |
| 19 | static void dictionary_netdev_rename_delete_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) { |
| 20 | struct rename_task *r = value; |
| 21 | |
| 22 | spinlock_lock(&r->spinlock); |
| 23 | netdev_rename_task_cleanup_unsafe(r); |
| 24 | spinlock_unlock(&r->spinlock); |
| 25 | } |
| 26 | |
| 27 | static bool dictionary_netdev_rename_conflict_cb(const DICTIONARY_ITEM *item __maybe_unused, void *old_value, void *new_value, void *data __maybe_unused) { |
| 28 | struct rename_task *old_r = old_value; |
| 29 | struct rename_task *new_r = new_value; |
| 30 | |
| 31 | spinlock_lock(&old_r->spinlock); |
| 32 | SWAP(old_r->cgroup_netdev_link, new_r->cgroup_netdev_link); |
| 33 | SWAP(old_r->chart_labels, new_r->chart_labels); |
| 34 | SWAP(old_r->container_device, new_r->container_device); |
| 35 | SWAP(old_r->container_name, new_r->container_name); |
| 36 | SWAP(old_r->ctx_prefix, new_r->ctx_prefix); |
| 37 | spinlock_unlock(&old_r->spinlock); |
| 38 | |
| 39 | netdev_rename_task_cleanup_unsafe(new_r); |
| 40 | |
| 41 | return true; |
| 42 | } |
| 43 | |
| 44 | static SPINLOCK netdev_renames_spinlock = SPINLOCK_INITIALIZER; |
| 45 | void netdev_renames_init(void) { |
| 46 | spinlock_lock(&netdev_renames_spinlock); |
| 47 | if(!netdev_renames) { |
| 48 | netdev_renames = dictionary_create_advanced(DICT_OPTION_FIXED_SIZE | DICT_OPTION_DONT_OVERWRITE_VALUE, NULL, sizeof(struct rename_task)); |
| 49 | dictionary_register_conflict_callback(netdev_renames, dictionary_netdev_rename_conflict_cb, NULL); |
| 50 | dictionary_register_delete_callback(netdev_renames, dictionary_netdev_rename_delete_cb, NULL); |
| 51 | } |
| 52 | spinlock_unlock(&netdev_renames_spinlock); |
| 53 | } |
| 54 | |
| 55 | void netdev_renames_destroy(void) { |
| 56 | spinlock_lock(&netdev_renames_spinlock); |
| 57 | dictionary_destroy(netdev_renames); |
| 58 | netdev_renames = NULL; |
| 59 | spinlock_unlock(&netdev_renames_spinlock); |
| 60 | } |
| 61 | |
| 62 | void cgroup_rename_task_add( |
| 63 | const char *host_device, |
| 64 | const char *container_device, |
| 65 | const char *container_name, |
| 66 | RRDLABELS *labels, |
| 67 | const char *ctx_prefix, |
| 68 | const DICTIONARY_ITEM *cgroup_netdev_link) |
| 69 | { |
| 70 | netdev_renames_init(); |
| 71 | |
| 72 | struct rename_task tmp = { |
| 73 | .container_device = strdupz(container_device), |
| 74 | .container_name = strdupz(container_name), |
| 75 | .ctx_prefix = strdupz(ctx_prefix), |
| 76 | .chart_labels = rrdlabels_create(), |
| 77 | .cgroup_netdev_link = cgroup_netdev_link, |
| 78 | }; |
| 79 | rrdlabels_migrate_to_these(tmp.chart_labels, labels); |
| 80 | |
| 81 | dictionary_set(netdev_renames, host_device, &tmp, sizeof(tmp)); |
| 82 | } |
| 83 | |
| 84 | // other threads can call this function to delete a rename to a netdev |
| 85 | void cgroup_rename_task_device_del(const char *host_device) { |
| 86 | dictionary_del(netdev_renames, host_device); |
| 87 | } |