Implemented `LoadDS' which tells plugins to only register their DataSources.
[collectd.git] / src / nfs.c
1 /**
2  * collectd - src/nfs.c
3  * Copyright (C) 2005,2006  Jason Pepas
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Jason Pepas <cell at ices.utexas.edu>
20  *   Florian octo Forster <octo at verplant.org>
21  **/
22
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26
27 /* #if defined(KERNEL_LINUX) || defined(HAVE_LIBKSTAT) */
28 #if KERNEL_LINUX
29 # define NFS_HAVE_READ 1
30 #else
31 # define NFS_HAVE_READ 0
32 #endif
33
34 /*
35 see /proc/net/rpc/nfs
36 see http://www.missioncriticallinux.com/orph/NFS-Statistics
37
38 net x x x x
39 rpc_stat.netcnt         Not used; always zero.
40 rpc_stat.netudpcnt      Not used; always zero.
41 rpc_stat.nettcpcnt      Not used; always zero.
42 rpc_stat.nettcpconn     Not used; always zero.
43
44 rpc x x x
45 rpc_stat.rpccnt             The number of RPC calls.
46 rpc_stat.rpcretrans         The number of retransmitted RPC calls.
47 rpc_stat.rpcauthrefresh     The number of credential refreshes.
48
49 proc2 x x x...
50 proc3 x x x...
51
52 Procedure   NFS Version NFS Version 3
53 Number      Procedures  Procedures
54
55 0           null        null
56 1           getattr     getattr
57 2           setattr     setattr
58 3           root        lookup
59 4           lookup      access
60 5           readlink    readlink
61 6           read        read
62 7           wrcache     write
63 8           write       create
64 9           create      mkdir
65 10          remove      symlink
66 11          rename      mknod
67 12          link        remove
68 13          symlink     rmdir
69 14          mkdir       rename
70 15          rmdir       link
71 16          readdir     readdir
72 17          fsstat      readdirplus
73 18                      fsstat
74 19                      fsinfo
75 20                      pathconf
76 21                      commit
77 */
78
79 static data_source_t procedure_dsrc[1] =
80 {
81         {"value", DS_TYPE_COUNTER, 0, 4294967295.0}
82 };
83
84 static data_set_t procedure_ds =
85 {
86         "nfs_procedure", 1, procedure_dsrc
87 };
88
89 #if NFS_HAVE_READ
90 static const char *nfs2_procedures_names[] =
91 {
92         "null",
93         "getattr",
94         "setattr",
95         "root",
96         "lookup",
97         "readlink",
98         "read",
99         "wrcache",
100         "write",
101         "create",
102         "remove",
103         "rename",
104         "link",
105         "symlink",
106         "mkdir",
107         "rmdir",
108         "readdir",
109         "fsstat",
110         NULL
111 };
112 static int nfs2_procedures_names_num = 18;
113
114 static const char *nfs3_procedures_names[] =
115 {
116         "null",
117         "getattr",
118         "setattr",
119         "lookup",
120         "access",
121         "readlink",
122         "read",
123         "write",
124         "create",
125         "mkdir",
126         "symlink",
127         "mknod",
128         "remove",
129         "rmdir",
130         "rename",
131         "link",
132         "readdir",
133         "readdirplus",
134         "fsstat",
135         "fsinfo",
136         "pathconf",
137         "commit",
138         NULL
139 };
140 static int nfs3_procedures_names_num = 22;
141
142 #if HAVE_LIBKSTAT && 0
143 extern kstat_ctl_t *kc;
144 static kstat_t *nfs2_ksp_client;
145 static kstat_t *nfs2_ksp_server;
146 static kstat_t *nfs3_ksp_client;
147 static kstat_t *nfs3_ksp_server;
148 static kstat_t *nfs4_ksp_client;
149 static kstat_t *nfs4_ksp_server;
150 #endif
151
152 /* Possibly TODO: NFSv4 statistics */
153
154 #if 0
155 static int nfs_init (void)
156 {
157 #if HAVE_LIBKSTAT && 0
158         kstat_t *ksp_chain;
159
160         nfs2_ksp_client = NULL;
161         nfs2_ksp_server = NULL;
162         nfs3_ksp_client = NULL;
163         nfs3_ksp_server = NULL;
164         nfs4_ksp_client = NULL;
165         nfs4_ksp_server = NULL;
166         
167         if (kc == NULL)
168                 return;
169
170         for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
171                         ksp_chain = ksp_chain->ks_next)
172         {
173                 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
174                         continue;
175                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
176                         nfs2_ksp_server = ksp_chain;
177                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
178                         nfs3_ksp_server = ksp_chain;
179                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
180                         nfs4_ksp_server = ksp_chain;
181                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
182                         nfs2_ksp_client = ksp_chain;
183                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
184                         nfs3_ksp_client = ksp_chain;
185                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
186                         nfs4_ksp_client = ksp_chain;
187         }
188 #endif
189
190         return (0);
191 } /* int nfs_init */
192 #endif
193
194 #define BUFSIZE 1024
195 static void nfs_procedures_submit (const char *plugin_instance,
196                 unsigned long long *val, const char **names, int len)
197 {
198         value_t values[1];
199         value_list_t vl = VALUE_LIST_INIT;
200         int i;
201
202         vl.values = values;
203         vl.values_len = 1;
204         vl.time = time (NULL);
205         strcpy (vl.host, hostname_g);
206         strcpy (vl.plugin, "nfs");
207         strncpy (vl.plugin_instance, plugin_instance,
208                         sizeof (vl.plugin_instance));
209
210         for (i = 0; i < len; i++)
211         {
212                 values[0].counter = val[i];
213                 strncpy (vl.type_instance, names[i],
214                                 sizeof (vl.type_instance));
215                 DEBUG ("%s-%s/nfs_procedure-%s = %llu",
216                                 vl.plugin, vl.plugin_instance,
217                                 vl.type_instance, val[i]);
218                 plugin_dispatch_values ("nfs_procedure", &vl);
219         }
220 } /* void nfs_procedures_submit */
221
222 #if KERNEL_LINUX
223 static void nfs_read_stats_file (FILE *fh, char *inst)
224 {
225         char buffer[BUFSIZE];
226
227         char plugin_instance[DATA_MAX_NAME_LEN];
228
229         char *fields[48];
230         int numfields = 0;
231
232         if (fh == NULL)
233                 return;
234
235         while (fgets (buffer, BUFSIZE, fh) != NULL)
236         {
237                 numfields = strsplit (buffer, fields, 48);
238
239                 if (((numfields - 2) != nfs2_procedures_names_num)
240                                 && ((numfields - 2)
241                                         != nfs3_procedures_names_num))
242                         continue;
243
244                 if (strcmp (fields[0], "proc2") == 0)
245                 {
246                         int i;
247                         unsigned long long *values;
248
249                         if ((numfields - 2) != nfs2_procedures_names_num)
250                         {
251                                 WARNING ("nfs plugin: Wrong "
252                                                 "number of fields (= %i) "
253                                                 "for NFSv2 statistics.",
254                                                 numfields - 2);
255                                 continue;
256                         }
257
258                         snprintf (plugin_instance, sizeof (plugin_instance),
259                                         "v2%s", inst);
260                         plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
261
262                         values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
263                         if (values == NULL)
264                         {
265                                 char errbuf[1024];
266                                 ERROR ("nfs plugin: malloc "
267                                                 "failed: %s",
268                                                 sstrerror (errno, errbuf, sizeof (errbuf)));
269                                 continue;
270                         }
271
272                         for (i = 0; i < nfs2_procedures_names_num; i++)
273                                 values[i] = atoll (fields[i + 2]);
274
275                         nfs_procedures_submit (plugin_instance, values,
276                                         nfs2_procedures_names,
277                                         nfs2_procedures_names_num);
278
279                         free (values);
280                 }
281                 else if (strncmp (fields[0], "proc3", 5) == 0)
282                 {
283                         int i;
284                         unsigned long long *values;
285
286                         if ((numfields - 2) != nfs3_procedures_names_num)
287                         {
288                                 WARNING ("nfs plugin: Wrong "
289                                                 "number of fields (= %i) "
290                                                 "for NFSv3 statistics.",
291                                                 numfields - 2);
292                                 continue;
293                         }
294
295                         snprintf (plugin_instance, sizeof (plugin_instance),
296                                         "v3%s", inst);
297                         plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
298
299                         values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
300                         if (values == NULL)
301                         {
302                                 char errbuf[1024];
303                                 ERROR ("nfs plugin: malloc "
304                                                 "failed: %s",
305                                                 sstrerror (errno, errbuf, sizeof (errbuf)));
306                                 continue;
307                         }
308
309                         for (i = 0; i < nfs3_procedures_names_num; i++)
310                                 values[i] = atoll (fields[i + 2]);
311
312                         nfs_procedures_submit (plugin_instance, values,
313                                         nfs3_procedures_names,
314                                         nfs3_procedures_names_num);
315
316                         free (values);
317                 }
318         } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
319 } /* void nfs_read_stats_file */
320 #endif /* defined(KERNEL_LINUX) */
321 #undef BUFSIZE
322
323 #if HAVE_LIBKSTAT && 0
324 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
325 {
326         unsigned long long values[18];
327
328         values[0] = get_kstat_value (ksp, "null");
329         values[1] = get_kstat_value (ksp, "getattr");
330         values[2] = get_kstat_value (ksp, "setattr");
331         values[3] = get_kstat_value (ksp, "root");
332         values[4] = get_kstat_value (ksp, "lookup");
333         values[5] = get_kstat_value (ksp, "readlink");
334         values[6] = get_kstat_value (ksp, "read");
335         values[7] = get_kstat_value (ksp, "wrcache");
336         values[8] = get_kstat_value (ksp, "write");
337         values[9] = get_kstat_value (ksp, "create");
338         values[10] = get_kstat_value (ksp, "remove");
339         values[11] = get_kstat_value (ksp, "rename");
340         values[12] = get_kstat_value (ksp, "link");
341         values[13] = get_kstat_value (ksp, "symlink");
342         values[14] = get_kstat_value (ksp, "mkdir");
343         values[15] = get_kstat_value (ksp, "rmdir");
344         values[16] = get_kstat_value (ksp, "readdir");
345         values[17] = get_kstat_value (ksp, "statfs");
346
347         nfs2_procedures_submit (values, inst);
348 }
349 #endif
350
351 static int nfs_read (void)
352 {
353 #if KERNEL_LINUX
354         FILE *fh;
355
356         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
357         {
358                 nfs_read_stats_file (fh, "client");
359                 fclose (fh);
360         }
361
362         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
363         {
364                 nfs_read_stats_file (fh, "server");
365                 fclose (fh);
366         }
367
368 /* #endif defined(KERNEL_LINUX) */
369
370 #elif HAVE_LIBKSTAT && 0
371         if (nfs2_ksp_client != NULL)
372                 nfs2_read_kstat (nfs2_ksp_client, "client");
373         if (nfs2_ksp_server != NULL)
374                 nfs2_read_kstat (nfs2_ksp_server, "server");
375 #endif /* defined(HAVE_LIBKSTAT) */
376
377         return (0);
378 }
379 #endif /* NFS_HAVE_READ */
380
381 void module_register (modreg_e load)
382 {
383         if (load & MR_DATASETS)
384                 plugin_register_data_set (&procedure_ds);
385
386 #if NFS_HAVE_READ
387         if (load & MR_READ)
388                 plugin_register_read ("nfs", nfs_read);
389 #endif
390 } /* void module_register */