| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "plugin_proc.h" |
| 4 | |
| 5 | #define PLUGIN_PROC_MODULE_NET_SOCKSTAT6_NAME "/proc/net/sockstat6" |
| 6 | |
| 7 | static struct proc_net_sockstat6 { |
| 8 | kernel_uint_t tcp6_inuse; |
| 9 | kernel_uint_t udp6_inuse; |
| 10 | kernel_uint_t udplite6_inuse; |
| 11 | kernel_uint_t raw6_inuse; |
| 12 | kernel_uint_t frag6_inuse; |
| 13 | } sockstat6_root = { 0 }; |
| 14 | |
| 15 | int do_proc_net_sockstat6(int update_every, usec_t dt) { |
| 16 | (void)dt; |
| 17 | |
| 18 | static procfile *ff = NULL; |
| 19 | |
| 20 | static uint32_t hash_raw = 0, |
| 21 | hash_frag = 0, |
| 22 | hash_tcp = 0, |
| 23 | hash_udp = 0, |
| 24 | hash_udplite = 0; |
| 25 | |
| 26 | static ARL_BASE *arl_tcp = NULL; |
| 27 | static ARL_BASE *arl_udp = NULL; |
| 28 | static ARL_BASE *arl_udplite = NULL; |
| 29 | static ARL_BASE *arl_raw = NULL; |
| 30 | static ARL_BASE *arl_frag = NULL; |
| 31 | |
| 32 | static int do_tcp_sockets = -1, do_udp_sockets = -1, do_udplite_sockets = -1, do_raw_sockets = -1, do_frag_sockets = -1; |
| 33 | |
| 34 | static char *keys[6] = { NULL }; |
| 35 | static uint32_t hashes[6] = { 0 }; |
| 36 | static ARL_BASE *bases[6] = { NULL }; |
| 37 | |
| 38 | if(unlikely(!arl_tcp)) { |
| 39 | do_tcp_sockets = inicfg_get_boolean_ondemand(&netdata_config, "plugin:proc:/proc/net/sockstat6", "ipv6 TCP sockets", CONFIG_BOOLEAN_AUTO); |
| 40 | do_udp_sockets = inicfg_get_boolean_ondemand(&netdata_config, "plugin:proc:/proc/net/sockstat6", "ipv6 UDP sockets", CONFIG_BOOLEAN_AUTO); |
| 41 | do_udplite_sockets = inicfg_get_boolean_ondemand(&netdata_config, "plugin:proc:/proc/net/sockstat6", "ipv6 UDPLITE sockets", CONFIG_BOOLEAN_AUTO); |
| 42 | do_raw_sockets = inicfg_get_boolean_ondemand(&netdata_config, "plugin:proc:/proc/net/sockstat6", "ipv6 RAW sockets", CONFIG_BOOLEAN_AUTO); |
| 43 | do_frag_sockets = inicfg_get_boolean_ondemand(&netdata_config, "plugin:proc:/proc/net/sockstat6", "ipv6 FRAG sockets", CONFIG_BOOLEAN_AUTO); |
| 44 | |
| 45 | arl_tcp = arl_create("sockstat6/TCP6", arl_callback_str2kernel_uint_t, 60); |
| 46 | arl_expect(arl_tcp, "inuse", &sockstat6_root.tcp6_inuse); |
| 47 | |
| 48 | arl_udp = arl_create("sockstat6/UDP6", arl_callback_str2kernel_uint_t, 60); |
| 49 | arl_expect(arl_udp, "inuse", &sockstat6_root.udp6_inuse); |
| 50 | |
| 51 | arl_udplite = arl_create("sockstat6/UDPLITE6", arl_callback_str2kernel_uint_t, 60); |
| 52 | arl_expect(arl_udplite, "inuse", &sockstat6_root.udplite6_inuse); |
| 53 | |
| 54 | arl_raw = arl_create("sockstat6/RAW6", arl_callback_str2kernel_uint_t, 60); |
| 55 | arl_expect(arl_raw, "inuse", &sockstat6_root.raw6_inuse); |
| 56 | |
| 57 | arl_frag = arl_create("sockstat6/FRAG6", arl_callback_str2kernel_uint_t, 60); |
| 58 | arl_expect(arl_frag, "inuse", &sockstat6_root.frag6_inuse); |
| 59 | |
| 60 | hash_tcp = simple_hash("TCP6"); |
| 61 | hash_udp = simple_hash("UDP6"); |
| 62 | hash_udplite = simple_hash("UDPLITE6"); |
| 63 | hash_raw = simple_hash("RAW6"); |
| 64 | hash_frag = simple_hash("FRAG6"); |
| 65 | |
| 66 | keys[0] = "TCP6"; hashes[0] = hash_tcp; bases[0] = arl_tcp; |
| 67 | keys[1] = "UDP6"; hashes[1] = hash_udp; bases[1] = arl_udp; |
| 68 | keys[2] = "UDPLITE6"; hashes[2] = hash_udplite; bases[2] = arl_udplite; |
| 69 | keys[3] = "RAW6"; hashes[3] = hash_raw; bases[3] = arl_raw; |
| 70 | keys[4] = "FRAG6"; hashes[4] = hash_frag; bases[4] = arl_frag; |
| 71 | keys[5] = NULL; // terminator |
| 72 | } |
| 73 | |
| 74 | if(unlikely(!ff)) { |
| 75 | char filename[FILENAME_MAX + 1]; |
| 76 | snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/sockstat6"); |
| 77 | ff = procfile_open(inicfg_get(&netdata_config, "plugin:proc:/proc/net/sockstat6", "filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT); |
| 78 | if(unlikely(!ff)) return 1; |
| 79 | } |
| 80 | |
| 81 | ff = procfile_readall(ff); |
| 82 | if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time |
| 83 | |
| 84 | size_t lines = procfile_lines(ff), l; |
| 85 | |
| 86 | for(l = 0; l < lines ;l++) { |
| 87 | size_t words = procfile_linewords(ff, l); |
| 88 | char *key = procfile_lineword(ff, l, 0); |
| 89 | uint32_t hash = simple_hash(key); |
| 90 | |
| 91 | int k; |
| 92 | for(k = 0; keys[k] ; k++) { |
| 93 | if(unlikely(hash == hashes[k] && strcmp(key, keys[k]) == 0)) { |
| 94 | // fprintf(stderr, "KEY: '%s', l=%zu, w=1, words=%zu\n", key, l, words); |
| 95 | ARL_BASE *arl = bases[k]; |
| 96 | arl_begin(arl); |
| 97 | size_t w = 1; |
| 98 | |
| 99 | while(w + 1 < words) { |
| 100 | char *name = procfile_lineword(ff, l, w); w++; |
| 101 | char *value = procfile_lineword(ff, l, w); w++; |
| 102 | // fprintf(stderr, " > NAME '%s', VALUE '%s', l=%zu, w=%zu, words=%zu\n", name, value, l, w, words); |
| 103 | if(unlikely(arl_check(arl, name, value) != 0)) |
| 104 | break; |
| 105 | } |
| 106 | |
| 107 | break; |
| 108 | } |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | // ------------------------------------------------------------------------ |
| 113 | |
| 114 | if (do_tcp_sockets == CONFIG_BOOLEAN_YES || do_tcp_sockets == CONFIG_BOOLEAN_AUTO) { |
| 115 | do_tcp_sockets = CONFIG_BOOLEAN_YES; |
| 116 | |
| 117 | static RRDSET *st = NULL; |
| 118 | static RRDDIM *rd_inuse = NULL; |
| 119 | |
| 120 | if(unlikely(!st)) { |
| 121 | st = rrdset_create_localhost( |
| 122 | "ipv6" |
| 123 | , "sockstat6_tcp_sockets" |
| 124 | , NULL |
| 125 | , "tcp6" |
| 126 | , NULL |
| 127 | , "IPv6 TCP Sockets" |
| 128 | , "sockets" |
| 129 | , PLUGIN_PROC_NAME |
| 130 | , PLUGIN_PROC_MODULE_NET_SOCKSTAT6_NAME |
| 131 | , NETDATA_CHART_PRIO_IPV6_TCP_SOCKETS |
| 132 | , update_every |
| 133 | , RRDSET_TYPE_LINE |
| 134 | ); |
| 135 | |
| 136 | rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 137 | } |
| 138 | |
| 139 | rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat6_root.tcp6_inuse); |
| 140 | rrdset_done(st); |
| 141 | } |
| 142 | |
| 143 | // ------------------------------------------------------------------------ |
| 144 | |
| 145 | if (do_udp_sockets == CONFIG_BOOLEAN_YES || do_udp_sockets == CONFIG_BOOLEAN_AUTO) { |
| 146 | do_udp_sockets = CONFIG_BOOLEAN_YES; |
| 147 | |
| 148 | static RRDSET *st = NULL; |
| 149 | static RRDDIM *rd_inuse = NULL; |
| 150 | |
| 151 | if(unlikely(!st)) { |
| 152 | st = rrdset_create_localhost( |
| 153 | "ipv6" |
| 154 | , "sockstat6_udp_sockets" |
| 155 | , NULL |
| 156 | , "udp6" |
| 157 | , NULL |
| 158 | , "IPv6 UDP Sockets" |
| 159 | , "sockets" |
| 160 | , PLUGIN_PROC_NAME |
| 161 | , PLUGIN_PROC_MODULE_NET_SOCKSTAT6_NAME |
| 162 | , NETDATA_CHART_PRIO_IPV6_UDP_SOCKETS |
| 163 | , update_every |
| 164 | , RRDSET_TYPE_LINE |
| 165 | ); |
| 166 | |
| 167 | rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 168 | } |
| 169 | |
| 170 | rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat6_root.udp6_inuse); |
| 171 | rrdset_done(st); |
| 172 | } |
| 173 | |
| 174 | // ------------------------------------------------------------------------ |
| 175 | |
| 176 | if (do_udplite_sockets == CONFIG_BOOLEAN_YES || do_udplite_sockets == CONFIG_BOOLEAN_AUTO) { |
| 177 | do_udplite_sockets = CONFIG_BOOLEAN_YES; |
| 178 | |
| 179 | static RRDSET *st = NULL; |
| 180 | static RRDDIM *rd_inuse = NULL; |
| 181 | |
| 182 | if(unlikely(!st)) { |
| 183 | st = rrdset_create_localhost( |
| 184 | "ipv6" |
| 185 | , "sockstat6_udplite_sockets" |
| 186 | , NULL |
| 187 | , "udplite6" |
| 188 | , NULL |
| 189 | , "IPv6 UDPLITE Sockets" |
| 190 | , "sockets" |
| 191 | , PLUGIN_PROC_NAME |
| 192 | , PLUGIN_PROC_MODULE_NET_SOCKSTAT6_NAME |
| 193 | , NETDATA_CHART_PRIO_IPV6_UDPLITE_SOCKETS |
| 194 | , update_every |
| 195 | , RRDSET_TYPE_LINE |
| 196 | ); |
| 197 | |
| 198 | rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 199 | } |
| 200 | |
| 201 | rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat6_root.udplite6_inuse); |
| 202 | rrdset_done(st); |
| 203 | } |
| 204 | |
| 205 | // ------------------------------------------------------------------------ |
| 206 | |
| 207 | if (do_raw_sockets == CONFIG_BOOLEAN_YES || do_raw_sockets == CONFIG_BOOLEAN_AUTO) { |
| 208 | do_raw_sockets = CONFIG_BOOLEAN_YES; |
| 209 | |
| 210 | static RRDSET *st = NULL; |
| 211 | static RRDDIM *rd_inuse = NULL; |
| 212 | |
| 213 | if(unlikely(!st)) { |
| 214 | st = rrdset_create_localhost( |
| 215 | "ipv6" |
| 216 | , "sockstat6_raw_sockets" |
| 217 | , NULL |
| 218 | , "raw6" |
| 219 | , NULL |
| 220 | , "IPv6 RAW Sockets" |
| 221 | , "sockets" |
| 222 | , PLUGIN_PROC_NAME |
| 223 | , PLUGIN_PROC_MODULE_NET_SOCKSTAT6_NAME |
| 224 | , NETDATA_CHART_PRIO_IPV6_RAW_SOCKETS |
| 225 | , update_every |
| 226 | , RRDSET_TYPE_LINE |
| 227 | ); |
| 228 | |
| 229 | rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 230 | } |
| 231 | |
| 232 | rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat6_root.raw6_inuse); |
| 233 | rrdset_done(st); |
| 234 | } |
| 235 | |
| 236 | // ------------------------------------------------------------------------ |
| 237 | |
| 238 | if (do_frag_sockets == CONFIG_BOOLEAN_YES || do_frag_sockets == CONFIG_BOOLEAN_AUTO) { |
| 239 | do_frag_sockets = CONFIG_BOOLEAN_YES; |
| 240 | |
| 241 | static RRDSET *st = NULL; |
| 242 | static RRDDIM *rd_inuse = NULL; |
| 243 | |
| 244 | if(unlikely(!st)) { |
| 245 | st = rrdset_create_localhost( |
| 246 | "ipv6" |
| 247 | , "sockstat6_frag_sockets" |
| 248 | , NULL |
| 249 | , "fragments6" |
| 250 | , NULL |
| 251 | , "IPv6 FRAG Sockets" |
| 252 | , "fragments" |
| 253 | , PLUGIN_PROC_NAME |
| 254 | , PLUGIN_PROC_MODULE_NET_SOCKSTAT6_NAME |
| 255 | , NETDATA_CHART_PRIO_IPV6_FRAGMENTS_SOCKETS |
| 256 | , update_every |
| 257 | , RRDSET_TYPE_LINE |
| 258 | ); |
| 259 | |
| 260 | rd_inuse = rrddim_add(st, "inuse", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE); |
| 261 | } |
| 262 | |
| 263 | rrddim_set_by_pointer(st, rd_inuse, (collected_number)sockstat6_root.frag6_inuse); |
| 264 | rrdset_done(st); |
| 265 | } |
| 266 | |
| 267 | return 0; |
| 268 | } |