Merge branch 'collectd-4.7' into collectd-4.8
[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         sstrncpy (vl.host, hostname_g, sizeof (vl.host));
191         sstrncpy (vl.plugin, "nfs", sizeof (vl.plugin));
192         sstrncpy (vl.plugin_instance, plugin_instance,
193                         sizeof (vl.plugin_instance));
194         sstrncpy (vl.type, "nfs_procedure", sizeof (vl.type));
195
196         for (i = 0; i < len; i++)
197         {
198                 values[0].counter = val[i];
199                 sstrncpy (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 (&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                         ssnprintf (plugin_instance, sizeof (plugin_instance),
244                                         "v2%s", inst);
245
246                         values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
247                         if (values == NULL)
248                         {
249                                 char errbuf[1024];
250                                 ERROR ("nfs plugin: malloc "
251                                                 "failed: %s",
252                                                 sstrerror (errno, errbuf, sizeof (errbuf)));
253                                 continue;
254                         }
255
256                         for (i = 0; i < nfs2_procedures_names_num; i++)
257                                 values[i] = atoll (fields[i + 2]);
258
259                         nfs_procedures_submit (plugin_instance, values,
260                                         nfs2_procedures_names,
261                                         nfs2_procedures_names_num);
262
263                         free (values);
264                 }
265                 else if (strncmp (fields[0], "proc3", 5) == 0)
266                 {
267                         int i;
268                         unsigned long long *values;
269
270                         if ((numfields - 2) != nfs3_procedures_names_num)
271                         {
272                                 WARNING ("nfs plugin: Wrong "
273                                                 "number of fields (= %i) "
274                                                 "for NFSv3 statistics.",
275                                                 numfields - 2);
276                                 continue;
277                         }
278
279                         ssnprintf (plugin_instance, sizeof (plugin_instance),
280                                         "v3%s", inst);
281
282                         values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
283                         if (values == NULL)
284                         {
285                                 char errbuf[1024];
286                                 ERROR ("nfs plugin: malloc "
287                                                 "failed: %s",
288                                                 sstrerror (errno, errbuf, sizeof (errbuf)));
289                                 continue;
290                         }
291
292                         for (i = 0; i < nfs3_procedures_names_num; i++)
293                                 values[i] = atoll (fields[i + 2]);
294
295                         nfs_procedures_submit (plugin_instance, values,
296                                         nfs3_procedures_names,
297                                         nfs3_procedures_names_num);
298
299                         free (values);
300                 }
301         } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
302 } /* void nfs_read_stats_file */
303 #undef BUFSIZE
304
305 #if HAVE_LIBKSTAT && 0
306 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
307 {
308         unsigned long long values[18];
309
310         values[0] = get_kstat_value (ksp, "null");
311         values[1] = get_kstat_value (ksp, "getattr");
312         values[2] = get_kstat_value (ksp, "setattr");
313         values[3] = get_kstat_value (ksp, "root");
314         values[4] = get_kstat_value (ksp, "lookup");
315         values[5] = get_kstat_value (ksp, "readlink");
316         values[6] = get_kstat_value (ksp, "read");
317         values[7] = get_kstat_value (ksp, "wrcache");
318         values[8] = get_kstat_value (ksp, "write");
319         values[9] = get_kstat_value (ksp, "create");
320         values[10] = get_kstat_value (ksp, "remove");
321         values[11] = get_kstat_value (ksp, "rename");
322         values[12] = get_kstat_value (ksp, "link");
323         values[13] = get_kstat_value (ksp, "symlink");
324         values[14] = get_kstat_value (ksp, "mkdir");
325         values[15] = get_kstat_value (ksp, "rmdir");
326         values[16] = get_kstat_value (ksp, "readdir");
327         values[17] = get_kstat_value (ksp, "statfs");
328
329         nfs2_procedures_submit (values, inst);
330 }
331 #endif
332
333 static int nfs_read (void)
334 {
335         FILE *fh;
336
337         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
338         {
339                 nfs_read_stats_file (fh, "client");
340                 fclose (fh);
341         }
342
343         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
344         {
345                 nfs_read_stats_file (fh, "server");
346                 fclose (fh);
347         }
348
349 #if HAVE_LIBKSTAT && 0
350         if (nfs2_ksp_client != NULL)
351                 nfs2_read_kstat (nfs2_ksp_client, "client");
352         if (nfs2_ksp_server != NULL)
353                 nfs2_read_kstat (nfs2_ksp_server, "server");
354 #endif /* defined(HAVE_LIBKSTAT) */
355
356         return (0);
357 }
358
359 void module_register (void)
360 {
361         plugin_register_read ("nfs", nfs_read);
362 } /* void module_register */