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 **/
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
27 #if !KERNEL_LINUX
28 # error "No applicable input method."
29 #endif
31 /*
32 see /proc/net/rpc/nfs
33 see http://www.missioncriticallinux.com/orph/NFS-Statistics
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.
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.
46 proc2 x x x...
47 proc3 x x x...
49 Procedure NFS Version NFS Version 3
50 Number Procedures Procedures
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 */
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;
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;
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
138 /* Possibly TODO: NFSv4 statistics */
140 #if 0
141 static int nfs_init (void)
142 {
143 #if HAVE_LIBKSTAT && 0
144 kstat_t *ksp_chain;
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;
153 if (kc == NULL)
154 return;
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
176 return (0);
177 } /* int nfs_init */
178 #endif
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;
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));
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 */
208 static void nfs_read_stats_file (FILE *fh, char *inst)
209 {
210 char buffer[BUFSIZE];
212 char plugin_instance[DATA_MAX_NAME_LEN];
214 char *fields[48];
215 int numfields = 0;
217 if (fh == NULL)
218 return;
220 while (fgets (buffer, BUFSIZE, fh) != NULL)
221 {
222 numfields = strsplit (buffer, fields, 48);
224 if (((numfields - 2) != nfs2_procedures_names_num)
225 && ((numfields - 2)
226 != nfs3_procedures_names_num))
227 continue;
229 if (strcmp (fields[0], "proc2") == 0)
230 {
231 int i;
232 unsigned long long *values;
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 }
243 snprintf (plugin_instance, sizeof (plugin_instance),
244 "v2%s", inst);
245 plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
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 }
257 for (i = 0; i < nfs2_procedures_names_num; i++)
258 values[i] = atoll (fields[i + 2]);
260 nfs_procedures_submit (plugin_instance, values,
261 nfs2_procedures_names,
262 nfs2_procedures_names_num);
264 free (values);
265 }
266 else if (strncmp (fields[0], "proc3", 5) == 0)
267 {
268 int i;
269 unsigned long long *values;
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 }
280 snprintf (plugin_instance, sizeof (plugin_instance),
281 "v3%s", inst);
282 plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
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 }
294 for (i = 0; i < nfs3_procedures_names_num; i++)
295 values[i] = atoll (fields[i + 2]);
297 nfs_procedures_submit (plugin_instance, values,
298 nfs3_procedures_names,
299 nfs3_procedures_names_num);
301 free (values);
302 }
303 } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
304 } /* void nfs_read_stats_file */
305 #undef BUFSIZE
307 #if HAVE_LIBKSTAT && 0
308 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
309 {
310 unsigned long long values[18];
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");
331 nfs2_procedures_submit (values, inst);
332 }
333 #endif
335 static int nfs_read (void)
336 {
337 FILE *fh;
339 if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
340 {
341 nfs_read_stats_file (fh, "client");
342 fclose (fh);
343 }
345 if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
346 {
347 nfs_read_stats_file (fh, "server");
348 fclose (fh);
349 }
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) */
358 return (0);
359 }
361 void module_register (void)
362 {
363 plugin_register_read ("nfs", nfs_read);
364 } /* void module_register */