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