Merge branch 'pull/collectd-4.0' into collectd-4.0
[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 #if NFS_HAVE_READ
80 static const char *nfs2_procedures_names[] =
81 {
82         "null",
83         "getattr",
84         "setattr",
85         "root",
86         "lookup",
87         "readlink",
88         "read",
89         "wrcache",
90         "write",
91         "create",
92         "remove",
93         "rename",
94         "link",
95         "symlink",
96         "mkdir",
97         "rmdir",
98         "readdir",
99         "fsstat",
100         NULL
101 };
102 static int nfs2_procedures_names_num = 18;
103
104 static const char *nfs3_procedures_names[] =
105 {
106         "null",
107         "getattr",
108         "setattr",
109         "lookup",
110         "access",
111         "readlink",
112         "read",
113         "write",
114         "create",
115         "mkdir",
116         "symlink",
117         "mknod",
118         "remove",
119         "rmdir",
120         "rename",
121         "link",
122         "readdir",
123         "readdirplus",
124         "fsstat",
125         "fsinfo",
126         "pathconf",
127         "commit",
128         NULL
129 };
130 static int nfs3_procedures_names_num = 22;
131
132 #if HAVE_LIBKSTAT && 0
133 extern kstat_ctl_t *kc;
134 static kstat_t *nfs2_ksp_client;
135 static kstat_t *nfs2_ksp_server;
136 static kstat_t *nfs3_ksp_client;
137 static kstat_t *nfs3_ksp_server;
138 static kstat_t *nfs4_ksp_client;
139 static kstat_t *nfs4_ksp_server;
140 #endif
141
142 /* Possibly TODO: NFSv4 statistics */
143
144 #if 0
145 static int nfs_init (void)
146 {
147 #if HAVE_LIBKSTAT && 0
148         kstat_t *ksp_chain;
149
150         nfs2_ksp_client = NULL;
151         nfs2_ksp_server = NULL;
152         nfs3_ksp_client = NULL;
153         nfs3_ksp_server = NULL;
154         nfs4_ksp_client = NULL;
155         nfs4_ksp_server = NULL;
156         
157         if (kc == NULL)
158                 return;
159
160         for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
161                         ksp_chain = ksp_chain->ks_next)
162         {
163                 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
164                         continue;
165                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
166                         nfs2_ksp_server = ksp_chain;
167                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
168                         nfs3_ksp_server = ksp_chain;
169                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
170                         nfs4_ksp_server = ksp_chain;
171                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
172                         nfs2_ksp_client = ksp_chain;
173                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
174                         nfs3_ksp_client = ksp_chain;
175                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
176                         nfs4_ksp_client = ksp_chain;
177         }
178 #endif
179
180         return (0);
181 } /* int nfs_init */
182 #endif
183
184 #define BUFSIZE 1024
185 static void nfs_procedures_submit (const char *plugin_instance,
186                 unsigned long long *val, const char **names, int len)
187 {
188         value_t values[1];
189         value_list_t vl = VALUE_LIST_INIT;
190         int i;
191
192         vl.values = values;
193         vl.values_len = 1;
194         vl.time = time (NULL);
195         strcpy (vl.host, hostname_g);
196         strcpy (vl.plugin, "nfs");
197         strncpy (vl.plugin_instance, plugin_instance,
198                         sizeof (vl.plugin_instance));
199
200         for (i = 0; i < len; i++)
201         {
202                 values[0].counter = val[i];
203                 strncpy (vl.type_instance, names[i],
204                                 sizeof (vl.type_instance));
205                 DEBUG ("%s-%s/nfs_procedure-%s = %llu",
206                                 vl.plugin, vl.plugin_instance,
207                                 vl.type_instance, val[i]);
208                 plugin_dispatch_values ("nfs_procedure", &vl);
209         }
210 } /* void nfs_procedures_submit */
211
212 #if KERNEL_LINUX
213 static void nfs_read_stats_file (FILE *fh, char *inst)
214 {
215         char buffer[BUFSIZE];
216
217         char plugin_instance[DATA_MAX_NAME_LEN];
218
219         char *fields[48];
220         int numfields = 0;
221
222         if (fh == NULL)
223                 return;
224
225         while (fgets (buffer, BUFSIZE, fh) != NULL)
226         {
227                 numfields = strsplit (buffer, fields, 48);
228
229                 if (((numfields - 2) != nfs2_procedures_names_num)
230                                 && ((numfields - 2)
231                                         != nfs3_procedures_names_num))
232                         continue;
233
234                 if (strcmp (fields[0], "proc2") == 0)
235                 {
236                         int i;
237                         unsigned long long *values;
238
239                         if ((numfields - 2) != nfs2_procedures_names_num)
240                         {
241                                 WARNING ("nfs plugin: Wrong "
242                                                 "number of fields (= %i) "
243                                                 "for NFSv2 statistics.",
244                                                 numfields - 2);
245                                 continue;
246                         }
247
248                         snprintf (plugin_instance, sizeof (plugin_instance),
249                                         "v2%s", inst);
250                         plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
251
252                         values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
253                         if (values == NULL)
254                         {
255                                 char errbuf[1024];
256                                 ERROR ("nfs plugin: malloc "
257                                                 "failed: %s",
258                                                 sstrerror (errno, errbuf, sizeof (errbuf)));
259                                 continue;
260                         }
261
262                         for (i = 0; i < nfs2_procedures_names_num; i++)
263                                 values[i] = atoll (fields[i + 2]);
264
265                         nfs_procedures_submit (plugin_instance, values,
266                                         nfs2_procedures_names,
267                                         nfs2_procedures_names_num);
268
269                         free (values);
270                 }
271                 else if (strncmp (fields[0], "proc3", 5) == 0)
272                 {
273                         int i;
274                         unsigned long long *values;
275
276                         if ((numfields - 2) != nfs3_procedures_names_num)
277                         {
278                                 WARNING ("nfs plugin: Wrong "
279                                                 "number of fields (= %i) "
280                                                 "for NFSv3 statistics.",
281                                                 numfields - 2);
282                                 continue;
283                         }
284
285                         snprintf (plugin_instance, sizeof (plugin_instance),
286                                         "v3%s", inst);
287                         plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
288
289                         values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
290                         if (values == NULL)
291                         {
292                                 char errbuf[1024];
293                                 ERROR ("nfs plugin: malloc "
294                                                 "failed: %s",
295                                                 sstrerror (errno, errbuf, sizeof (errbuf)));
296                                 continue;
297                         }
298
299                         for (i = 0; i < nfs3_procedures_names_num; i++)
300                                 values[i] = atoll (fields[i + 2]);
301
302                         nfs_procedures_submit (plugin_instance, values,
303                                         nfs3_procedures_names,
304                                         nfs3_procedures_names_num);
305
306                         free (values);
307                 }
308         } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
309 } /* void nfs_read_stats_file */
310 #endif /* defined(KERNEL_LINUX) */
311 #undef BUFSIZE
312
313 #if HAVE_LIBKSTAT && 0
314 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
315 {
316         unsigned long long values[18];
317
318         values[0] = get_kstat_value (ksp, "null");
319         values[1] = get_kstat_value (ksp, "getattr");
320         values[2] = get_kstat_value (ksp, "setattr");
321         values[3] = get_kstat_value (ksp, "root");
322         values[4] = get_kstat_value (ksp, "lookup");
323         values[5] = get_kstat_value (ksp, "readlink");
324         values[6] = get_kstat_value (ksp, "read");
325         values[7] = get_kstat_value (ksp, "wrcache");
326         values[8] = get_kstat_value (ksp, "write");
327         values[9] = get_kstat_value (ksp, "create");
328         values[10] = get_kstat_value (ksp, "remove");
329         values[11] = get_kstat_value (ksp, "rename");
330         values[12] = get_kstat_value (ksp, "link");
331         values[13] = get_kstat_value (ksp, "symlink");
332         values[14] = get_kstat_value (ksp, "mkdir");
333         values[15] = get_kstat_value (ksp, "rmdir");
334         values[16] = get_kstat_value (ksp, "readdir");
335         values[17] = get_kstat_value (ksp, "statfs");
336
337         nfs2_procedures_submit (values, inst);
338 }
339 #endif
340
341 static int nfs_read (void)
342 {
343 #if KERNEL_LINUX
344         FILE *fh;
345
346         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
347         {
348                 nfs_read_stats_file (fh, "client");
349                 fclose (fh);
350         }
351
352         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
353         {
354                 nfs_read_stats_file (fh, "server");
355                 fclose (fh);
356         }
357
358 /* #endif defined(KERNEL_LINUX) */
359
360 #elif HAVE_LIBKSTAT && 0
361         if (nfs2_ksp_client != NULL)
362                 nfs2_read_kstat (nfs2_ksp_client, "client");
363         if (nfs2_ksp_server != NULL)
364                 nfs2_read_kstat (nfs2_ksp_server, "server");
365 #endif /* defined(HAVE_LIBKSTAT) */
366
367         return (0);
368 }
369 #endif /* NFS_HAVE_READ */
370
371 void module_register (void)
372 {
373 #if NFS_HAVE_READ
374         plugin_register_read ("nfs", nfs_read);
375 #endif
376 } /* void module_register */