Projet

Général

Profil

Paste
Télécharger au format
Statistiques
| Branche: | Révision:

root / plugins / network / if1sec-c.c @ 17f78427

Historique | Voir | Annoter | Télécharger (6,57 ko)

1 54becf68 Steve Schnepp
/*
2
 * if1sec C plugin
3
 */
4
#include <stdlib.h>
5
#include <stdio.h>
6
#include <string.h>
7
#include <unistd.h>
8
#include <stdint.h>
9
#include <inttypes.h>
10
#include <fcntl.h>
11
12
#include <time.h>
13
14
#include <sys/file.h>
15
16
#define PROC_STAT "/proc/net/dev"
17
#define PLUGIN_NAME "if1sec-c"
18
19
int fail(char* msg) {
20
        perror(msg);
21
22
        return 1;
23
}
24
25
/* Returns the ifname from a /proc/net/dev line
26
 * It will return an inside pointer to line, and modifiy the end with a \0
27
 */
28
char* get_ifname_from_procstatline(char* line) {
29
        char *ifname;
30
        for (ifname = line; (*ifname) == ' '; ifname ++);
31
32
        char *ifname_end;
33
        for (ifname_end = ifname; (*ifname_end) != ':'; ifname_end ++);
34
        (*ifname_end) = '\0';
35
36
        return ifname;
37
}
38
39
int config() {
40
        /* Get the number of if */
41 cc0b0949 Steve Schnepp
        int f = open(PROC_STAT, O_RDONLY);
42
        if ( f == -1 ) {
43 54becf68 Steve Schnepp
                return fail("cannot open " PROC_STAT);
44
        }
45
46
        // Starting with -2, since the 2 lines on top are header lines
47
        int nif = -2;
48
49
        const int buffer_size = 64 * 1024;
50
        char buffer[buffer_size];
51
52
        // whole /proc/stat can be read in 1 syscall
53
        if (read(f, buffer, buffer_size) <= 0) {
54
                return fail("cannot read " PROC_STAT);
55
        }
56
57
        // tokenization per-line
58
        char* line; char *saveptr;
59
        char* newl = "\n";
60
        for (line = strtok_r(buffer, newl, &saveptr); line; line = strtok_r(NULL, newl, &saveptr)) {
61
                // Skip the header lines
62
                if (nif ++ < 0) { continue; }
63
64
                char* if_name = get_ifname_from_procstatline(line);
65
                printf(
66
                        "multigraph if_%s_1sec" "\n"
67
                        "graph_order down up" "\n"
68
                        "graph_title %s traffic" "\n"
69 7fdb4741 dipohl
                        "graph_category 1sec" "\n"
70 54becf68 Steve Schnepp
                        "graph_vlabel bits in (-) / out (+) per ${graph_period}" "\n"
71
                        "graph_data_size custom 1d, 10s for 1w, 1m for 1t, 5m for 1y" "\n"
72
                        , if_name, if_name
73
                );
74
75
                printf(
76
                        "down.label -" "\n"
77
                        "down.type DERIVE" "\n"
78
                        "down.graph no" "\n"
79
                        "down.cdef down,8,*" "\n"
80
                        "down.min 0" "\n"
81 17f78427 Lars Kruse
82 54becf68 Steve Schnepp
                        "up.label bps" "\n"
83
                        "up.type DERIVE" "\n"
84
                        "up.negative down" "\n"
85
                        "up.cdef down,8,*" "\n"
86
                        "up.min 0" "\n"
87
                );
88
        }
89
90
        close(f);
91
92
93
        return 0;
94
}
95
96
char* pid_filename;
97
char* cache_filename;
98
99
/* Wait until the next second, and return the EPOCH */
100
time_t wait_until_next_second() {
101
        struct timespec tp;
102
        clock_gettime(CLOCK_REALTIME, &tp);
103
104
        time_t current_epoch = tp.tv_sec;
105
        long nsec_to_sleep = 1000*1000*1000 - tp.tv_nsec;
106
107
108
        /* Only sleep if needed */
109
        if (nsec_to_sleep > 0) {
110
                tp.tv_sec = 0;
111
                tp.tv_nsec = nsec_to_sleep;
112
                nanosleep(&tp, NULL);
113
        }
114
115
        return current_epoch + 1;
116
}
117
118
int acquire() {
119
120
        /* fork ourselves if not asked otherwise */
121
        char* no_fork = getenv("no_fork");
122
        if (! no_fork || strcmp("1", no_fork)) {
123 0a40358f Steve Schnepp
                pid_t child_pid = fork();
124
                if (child_pid) {
125
                        printf("# acquire() launched as PID %d\n", child_pid);
126
                        return 0;
127
                }
128
129 54becf68 Steve Schnepp
                // we are the child, complete the daemonization
130
131
                /* Close standard IO */
132
                fclose(stdin);
133
                fclose(stdout);
134
                fclose(stderr);
135
136
                /* create new session and process group */
137
                setsid();
138
        }
139
140
        /* write the pid */
141
        FILE* pid_file = fopen(pid_filename, "w");
142
        fprintf(pid_file, "%d\n", getpid());
143
        fclose(pid_file);
144
145
        /* Reading /proc/stat */
146
        int f = open(PROC_STAT, O_RDONLY);
147 cc0b0949 Steve Schnepp
        if ( f == -1 ) {
148
                return fail("cannot open " PROC_STAT);
149
        }
150 54becf68 Steve Schnepp
151
        /* open the spoolfile */
152
        int cache_file = open(cache_filename, O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR);
153 cc0b0949 Steve Schnepp
        if ( cache_file == -1 ) {
154 0a40358f Steve Schnepp
                return fail("# cannot open cache_file");
155 cc0b0949 Steve Schnepp
        }
156 54becf68 Steve Schnepp
157
        /* loop each second */
158
        while (1) {
159
                /* wait until next second */
160
                time_t epoch = wait_until_next_second();
161
162
                const int buffer_size = 64 * 1024;
163
                char buffer[buffer_size];
164
165
                if (lseek(f, 0, SEEK_SET) < 0) {
166
                        return fail("cannot seek " PROC_STAT);
167
                }
168
169
                // whole PROC file can be read in 1 syscall
170
                if (read(f, buffer, buffer_size) <= 0) {
171
                        return fail("cannot read " PROC_STAT);
172
                }
173
174
                // ignore the 1rst line
175
                char* line; char *saveptr;
176
                const char* newl = "\n";
177
178
                /* lock */
179
                flock(cache_file, LOCK_EX);
180
181
                int nif = -2;
182
                for (line = strtok_r(buffer, newl, &saveptr); line; line = strtok_r(NULL, newl, &saveptr)) {
183
                        // Skip the header lines
184
                        if (nif ++ < 0) { continue; }
185
186
                        char if_id[64];
187
                        uint_fast64_t r_bytes, r_packets, r_errs, r_drop, r_fifo, r_frame, r_compressed, r_multicast;
188
                        uint_fast64_t t_bytes, t_packets, t_errs, t_drop, t_fifo, t_frame, t_compressed, t_multicast;
189 17f78427 Lars Kruse
                        sscanf(line, "%s"
190
                                " "
191
                                "%llu %llu %llu %llu %llu %llu %llu %llu"
192 54becf68 Steve Schnepp
                                " "
193
                                "%llu %llu %llu %llu %llu %llu %llu %llu"
194
                                , if_id
195
                                , &r_bytes, &r_packets, &r_errs, &r_drop, &r_fifo, &r_frame, &r_compressed, &r_multicast
196
                                , &t_bytes, &t_packets, &t_errs, &t_drop, &t_fifo, &t_frame, &t_compressed, &t_multicast
197
                        );
198
199
                        // Remove trailing ':' of if_id
200
                        if_id[strlen(if_id) - 1] = '\0';
201
202
                        char out_buffer[1024];
203 17f78427 Lars Kruse
                        sprintf(out_buffer,
204 54becf68 Steve Schnepp
                                "multigraph if_%s_1sec" "\n"
205
                                "up.value %ld:%llu" "\n"
206
                                "down.value %ld:%llu" "\n"
207 17f78427 Lars Kruse
                                , if_id
208 54becf68 Steve Schnepp
                                , epoch, r_bytes
209
                                , epoch, t_bytes
210
                        );
211
212
                        write(cache_file, out_buffer, strlen(out_buffer));
213
                }
214
215
                /* unlock */
216
                flock(cache_file, LOCK_UN);
217
        }
218
219
        close(cache_file);
220
        close(f);
221
222
        return 0;
223
}
224
225
int fetch() {
226
        FILE* cache_file = fopen(cache_filename, "r+");
227 cc0b0949 Steve Schnepp
        if ( !cache_file ) {
228 0a40358f Steve Schnepp
                return acquire();
229 cc0b0949 Steve Schnepp
        }
230 54becf68 Steve Schnepp
231
        /* lock */
232
        flock(fileno(cache_file), LOCK_EX);
233
234
        /* cat the cache_file to stdout */
235
        char buffer[1024];
236
        while (fgets(buffer, 1024, cache_file)) {
237
                printf("%s", buffer);
238
        }
239
240
        ftruncate(fileno(cache_file), 0);
241
        fclose(cache_file);
242
243
        return 0;
244
}
245
246
int main(int argc, char **argv) {
247
        /* resolve paths */
248
        char *MUNIN_PLUGSTATE = getenv("MUNIN_PLUGSTATE");
249
250
        /* Default is current directory */
251
        if (! MUNIN_PLUGSTATE) MUNIN_PLUGSTATE = ".";
252
253
        size_t MUNIN_PLUGSTATE_length = strlen(MUNIN_PLUGSTATE);
254
255
        pid_filename = malloc(MUNIN_PLUGSTATE_length + strlen("/" PLUGIN_NAME ".") + strlen("pid") + 1); pid_filename[0] = '\0';
256
        cache_filename = malloc(MUNIN_PLUGSTATE_length + strlen("/" PLUGIN_NAME ".") + strlen("value") + 1); cache_filename[0] = '\0';
257
258
        strcat(pid_filename, MUNIN_PLUGSTATE);
259
        strcat(pid_filename, "/" PLUGIN_NAME "." "pid");
260
261
        strcat(cache_filename, MUNIN_PLUGSTATE);
262
        strcat(cache_filename, "/" PLUGIN_NAME "." "value");
263
264
        if (argc > 1) {
265
                char* first_arg = argv[1];
266
                if (! strcmp(first_arg, "config")) {
267
                        return config();
268
                }
269
270
                if (! strcmp(first_arg, "acquire")) {
271
                        return acquire();
272
                }
273
        }
274
275
        return fetch();
276
}
277
278
/***** DEMO
279 17f78427 Lars Kruse

280 54becf68 Steve Schnepp
/proc/net/dev sample
281

282
Inter-|   Receive                                                |  Transmit
283
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
284
    lo:    4364      54    0    0    0     0          0         0     4364      54    0    0    0     0       0          0
285
  eth0: 3459461624 22016512    0   70    0     0          0         0 3670486138 18117144    0    0    0     0       0          0
286

287
*****/