]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/bsnmpd/modules/snmp_hast/hast_snmp.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / bsnmpd / modules / snmp_hast / hast_snmp.c
1 /*-
2  * Copyright (c) 2013 Mikolaj Golub <trociny@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/queue.h>
32
33 #include <bsnmp/snmpmod.h>
34
35 #include <string.h>
36
37 #include "hast.h"
38 #include "hast_oid.h"
39 #include "hast_proto.h"
40 #include "hast_tree.h"
41 #include "nv.h"
42 #include "pjdlog.h"
43 #include "proto.h"
44
45 #define UPDATE_INTERVAL 500     /* update interval in ticks */
46
47 static struct lmodule *module;
48
49 static const struct asn_oid oid_hast = OIDX_begemotHast;
50
51 /* the Object Resource registration index */
52 static u_int hast_index = 0;
53
54 /*
55  * Structure that describes single resource.
56  */
57 struct hast_snmp_resource {
58         TAILQ_ENTRY(hast_snmp_resource) link;
59         int32_t         index;
60         char            name[NAME_MAX];
61         int             error;
62         int             role;
63         char            provname[NAME_MAX];
64         char            localpath[PATH_MAX];
65         int32_t         extentsize;
66         int32_t         keepdirty;
67         char            remoteaddr[HAST_ADDRSIZE];
68         char            sourceaddr[HAST_ADDRSIZE];
69         int             replication;
70         int             status;
71         uint64_t        dirty;
72         uint64_t        reads;
73         uint64_t        writes;
74         uint64_t        deletes;
75         uint64_t        flushes;
76         uint64_t        activemap_updates;
77         uint64_t        read_errors;
78         uint64_t        write_errors;
79         uint64_t        delete_errors;
80         uint64_t        flush_errors;
81         pid_t           workerpid;
82 };
83
84 static TAILQ_HEAD(, hast_snmp_resource) resources =
85     TAILQ_HEAD_INITIALIZER(resources);
86
87 /* Path to configuration file. */
88 static u_char *cfgpath;
89 /* Ticks of the last hast resources update. */
90 static uint64_t last_resources_update;
91
92 static void free_resources(void);
93 static int hastctl(struct nv *nvin, struct nv **nvout);
94 static int hast_fini(void);
95 static int hast_init(struct lmodule *mod, int argc, char *argv[]);
96 static void hast_start(void);
97 static int set_role(const char *resource, int role);
98 static int str2role(const char *str);
99 static int str2replication(const char *str);
100 static int str2status(const char *str);
101 static int update_resources(void);
102
103 const struct snmp_module config = {
104     .comment   = "This module implements the BEGEMOT MIB for HAST.",
105     .init      = hast_init,
106     .start     = hast_start,
107     .fini      = hast_fini,
108     .tree      = hast_ctree,
109     .tree_size = hast_CTREE_SIZE,
110 };
111
112 static int
113 hast_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
114 {
115
116         module = mod;
117
118         pjdlog_init(PJDLOG_MODE_SYSLOG);
119         pjdlog_debug_set(0);
120
121         cfgpath = malloc(sizeof(HAST_CONFIG));
122         if (cfgpath == NULL) {
123                 pjdlog_error("Unable to allocate %zu bytes for cfgpath",
124                     sizeof(HAST_CONFIG));
125                 return (-1);
126         }
127         strcpy(cfgpath, HAST_CONFIG);
128         return(0);
129 }
130
131 static void
132 hast_start(void)
133 {
134         hast_index = or_register(&oid_hast,
135             "The MIB module for BEGEMOT-HAST-MIB.", module);
136 }
137
138 static int
139 hast_fini(void)
140 {
141
142         or_unregister(hast_index);
143         free_resources();
144         free(cfgpath);
145         return (0);
146 }
147
148 static void
149 free_resources(void)
150 {
151         struct hast_snmp_resource *res;
152
153         while ((res = TAILQ_FIRST(&resources)) != NULL) {
154                 TAILQ_REMOVE(&resources, res, link);
155                 free(res);
156         }
157 }
158
159 static int
160 str2role(const char *str)
161 {
162
163         if (strcmp(str, "init") == 0)
164                 return (HAST_ROLE_INIT);
165         if (strcmp(str, "primary") == 0)
166                 return (HAST_ROLE_PRIMARY);
167         if (strcmp(str, "secondary") == 0)
168                 return (HAST_ROLE_SECONDARY);
169         return (HAST_ROLE_UNDEF);
170 }
171
172 static int
173 str2replication(const char *str)
174 {
175
176         if (strcmp(str, "fullsync") == 0)
177                 return (HAST_REPLICATION_FULLSYNC);
178         if (strcmp(str, "memsync") == 0)
179                 return (HAST_REPLICATION_MEMSYNC);
180         if (strcmp(str, "async") == 0)
181                 return (HAST_REPLICATION_ASYNC);
182         return (-1);
183 }
184
185 static int
186 str2status(const char *str)
187 {
188
189         if (strcmp(str, "complete") == 0)
190                 return (0);
191         if (strcmp(str, "degraded") == 0)
192                 return (1);
193         return (-1);
194 }
195
196 static int
197 hastctl(struct nv *nvin, struct nv **nvout)
198 {
199         struct hastd_config *cfg;
200         struct proto_conn *conn;
201         struct nv *nv;
202         int error;
203
204         cfg = yy_config_parse(cfgpath, true);
205         if (cfg == NULL)
206                 return (-1);
207
208         /* Setup control connection... */
209         if (proto_client(NULL, cfg->hc_controladdr, &conn) == -1) {
210                 pjdlog_error("Unable to setup control connection to %s",
211                     cfg->hc_controladdr);
212                 return (-1);
213         }
214         /* ...and connect to hastd. */
215         if (proto_connect(conn, HAST_TIMEOUT) == -1) {
216                 pjdlog_error("Unable to connect to hastd via %s",
217                     cfg->hc_controladdr);
218                 proto_close(conn);
219                 return (-1);
220         }
221         /* Send the command to the server... */
222         if (hast_proto_send(NULL, conn, nvin, NULL, 0) == -1) {
223                 pjdlog_error("Unable to send command to hastd via %s",
224                     cfg->hc_controladdr);
225                 proto_close(conn);
226                 return (-1);
227         }
228         /* ...and receive reply. */
229         if (hast_proto_recv_hdr(conn, &nv) == -1) {
230                 pjdlog_error("cannot receive reply from hastd via %s",
231                     cfg->hc_controladdr);
232                 proto_close(conn);
233                 return (-1);
234         }
235         proto_close(conn);
236         error = nv_get_int16(nv, "error");
237         if (error != 0) {
238                 pjdlog_error("Error %d received from hastd.", error);
239                 nv_free(nv);
240                 return (-1);
241         }
242         nv_set_error(nv, 0);
243         *nvout = nv;
244         return (0);
245 }
246
247 static int
248 set_role(const char *resource, int role)
249 {
250         struct nv *nvin, *nvout;
251         int error;
252
253         nvin = nv_alloc();
254         nv_add_string(nvin, resource, "resource%d", 0);
255         nv_add_uint8(nvin, HASTCTL_CMD_SETROLE, "cmd");
256         nv_add_uint8(nvin, role, "role");
257         error = hastctl(nvin, &nvout);
258         nv_free(nvin);
259         if (error != 0)
260                 return (-1);
261         nv_free(nvout);
262         return (SNMP_ERR_NOERROR);
263 }
264
265 static int
266 update_resources(void)
267 {
268         struct hast_snmp_resource *res;
269         struct nv *nvin, *nvout;
270         static uint64_t now;
271         unsigned int i;
272         const char *str;
273         int error;
274
275         now = get_ticks();
276         if (now - last_resources_update < UPDATE_INTERVAL)
277                 return (0);
278
279         last_resources_update = now;
280
281         free_resources();
282
283         nvin = nv_alloc();
284         nv_add_uint8(nvin, HASTCTL_CMD_STATUS, "cmd");
285         nv_add_string(nvin, "all", "resource%d", 0);
286         error = hastctl(nvin, &nvout);
287         nv_free(nvin);
288         if (error != 0)
289                 return (-1);
290
291         for (i = 0; ; i++) {
292                 str = nv_get_string(nvout, "resource%u", i);
293                 if (str == NULL)
294                         break;
295                 res = calloc(1, sizeof(*res));
296                 if (res == NULL) {
297                         pjdlog_error("Unable to allocate %zu bytes for "
298                             "resource", sizeof(*res));
299                         return (-1);
300                 }
301                 res->index = i + 1;
302                 strncpy(res->name, str, sizeof(res->name) - 1);
303                 error = nv_get_int16(nvout, "error%u", i);
304                 if (error != 0)
305                         continue;
306                 str = nv_get_string(nvout, "role%u", i);
307                 res->role = str != NULL ? str2role(str) : HAST_ROLE_UNDEF;
308                 str = nv_get_string(nvout, "provname%u", i);
309                 if (str != NULL)
310                         strncpy(res->provname, str, sizeof(res->provname) - 1);
311                 str = nv_get_string(nvout, "localpath%u", i);
312                 if (str != NULL) {
313                         strncpy(res->localpath, str,
314                             sizeof(res->localpath) - 1);
315                 }
316                 res->extentsize = nv_get_uint32(nvout, "extentsize%u", i);
317                 res->keepdirty = nv_get_uint32(nvout, "keepdirty%u", i);
318                 str = nv_get_string(nvout, "remoteaddr%u", i);
319                 if (str != NULL) {
320                         strncpy(res->remoteaddr, str,
321                             sizeof(res->remoteaddr) - 1);
322                 }
323                 str = nv_get_string(nvout, "sourceaddr%u", i);
324                 if (str != NULL) {
325                         strncpy(res->sourceaddr, str,
326                             sizeof(res->sourceaddr) - 1);
327                 }
328                 str = nv_get_string(nvout, "replication%u", i);
329                 res->replication = str != NULL ? str2replication(str) : -1;
330                 str = nv_get_string(nvout, "status%u", i);
331                 res->status = str != NULL ? str2status(str) : -1;
332                 res->dirty = nv_get_uint64(nvout, "dirty%u", i);
333                 res->reads = nv_get_uint64(nvout, "stat_read%u", i);
334                 res->writes = nv_get_uint64(nvout, "stat_write%u", i);
335                 res->deletes = nv_get_uint64(nvout, "stat_delete%u", i);
336                 res->flushes = nv_get_uint64(nvout, "stat_flush%u", i);
337                 res->activemap_updates =
338                     nv_get_uint64(nvout, "stat_activemap_update%u", i);
339                 res->read_errors =
340                     nv_get_uint64(nvout, "stat_read_error%u", i);
341                 res->write_errors =
342                     nv_get_uint64(nvout, "stat_write_error%u", i);
343                 res->delete_errors =
344                     nv_get_uint64(nvout, "stat_delete_error%u", i);
345                 res->flush_errors =
346                     nv_get_uint64(nvout, "stat_flush_error%u", i);
347                 res->workerpid = nv_get_int32(nvout, "workerpid%u", i);
348                 TAILQ_INSERT_TAIL(&resources, res, link);
349         }
350         nv_free(nvout);
351         return (0);
352 }
353
354 int
355 op_hastConfig(struct snmp_context *context, struct snmp_value *value,
356     u_int sub, u_int iidx __unused, enum snmp_op op)
357 {
358         asn_subid_t which;
359
360         which = value->var.subs[sub - 1];
361
362         switch (op) {
363         case SNMP_OP_GET:
364                 switch (which) {
365                 case LEAF_hastConfigFile:
366                         return (string_get(value, cfgpath, -1));
367                 default:
368                         return (SNMP_ERR_RES_UNAVAIL);
369                 }
370         case SNMP_OP_SET:
371                 switch (which) {
372                 case LEAF_hastConfigFile:
373                         return (string_save(value, context, -1,
374                             (u_char **)&cfgpath));
375                 default:
376                         return (SNMP_ERR_RES_UNAVAIL);
377                 }
378         case SNMP_OP_GETNEXT:
379         case SNMP_OP_ROLLBACK:
380         case SNMP_OP_COMMIT:
381                 return (SNMP_ERR_NOERROR);
382         default:
383                 return (SNMP_ERR_RES_UNAVAIL);
384         }
385 }
386
387 int
388 op_hastResourceTable(struct snmp_context *context __unused,
389     struct snmp_value *value, u_int sub, u_int iidx __unused, enum snmp_op op)
390 {
391         struct hast_snmp_resource *res;
392         asn_subid_t which;
393         int ret;
394
395         if (update_resources() == -1)
396                 return (SNMP_ERR_RES_UNAVAIL);
397
398         which = value->var.subs[sub - 1];
399
400         switch (op) {
401         case SNMP_OP_GETNEXT:
402                 res = NEXT_OBJECT_INT(&resources, &value->var, sub);
403                 if (res == NULL)
404                         return (SNMP_ERR_NOSUCHNAME);
405                 value->var.len = sub + 1;
406                 value->var.subs[sub] = res->index;
407                 break;
408         case SNMP_OP_GET:
409                 if (value->var.len - sub != 1)
410                         return (SNMP_ERR_NOSUCHNAME);
411                 res = FIND_OBJECT_INT(&resources, &value->var, sub);
412                 if (res == NULL)
413                         return (SNMP_ERR_NOSUCHNAME);
414                 break;
415         case SNMP_OP_SET:
416                 res = FIND_OBJECT_INT(&resources, &value->var, sub);
417                 if (res == NULL)
418                         return (SNMP_ERR_NOSUCHNAME);
419                 switch (which) {
420                 case LEAF_hastResourceRole:
421                         ret = set_role(res->name, value->v.integer);
422                         /* force update on next run */
423                         last_resources_update = 0;
424                         break;
425                 default:
426                         ret = SNMP_ERR_NOT_WRITEABLE;
427                         break;
428                 }
429                 return ret;
430         case SNMP_OP_ROLLBACK:
431         case SNMP_OP_COMMIT:
432                 return (SNMP_ERR_NOERROR);
433         default:
434                 return (SNMP_ERR_RES_UNAVAIL);
435         }
436
437         ret = SNMP_ERR_NOERROR;
438
439         switch (which) {
440         case LEAF_hastResourceIndex:
441                 value->v.integer = res->index;
442                 break;
443         case LEAF_hastResourceName:
444                 ret = string_get(value, res->name, -1);
445                 break;
446         case LEAF_hastResourceRole:
447                 value->v.integer = res->role;
448                 break;
449         case LEAF_hastResourceProvName:
450                 ret = string_get(value, res->provname, -1);
451                 break;
452         case LEAF_hastResourceLocalPath:
453                 ret = string_get(value, res->localpath, -1);
454                 break;
455         case LEAF_hastResourceExtentSize:
456                 value->v.integer = res->extentsize;
457                 break;
458         case LEAF_hastResourceKeepDirty:
459                 value->v.integer = res->keepdirty;
460                 break;
461         case LEAF_hastResourceRemoteAddr:
462                 ret = string_get(value, res->remoteaddr, -1);
463                 break;
464         case LEAF_hastResourceSourceAddr:
465                 ret = string_get(value, res->sourceaddr, -1);
466                 break;
467         case LEAF_hastResourceReplication:
468                 value->v.integer = res->replication;
469                 break;
470         case LEAF_hastResourceStatus:
471                 value->v.integer = res->status;
472                 break;
473         case LEAF_hastResourceDirty:
474                 value->v.counter64 = res->dirty;
475                 break;
476         case LEAF_hastResourceReads:
477                 value->v.counter64 = res->reads;
478                 break;
479         case LEAF_hastResourceWrites:
480                 value->v.counter64 = res->writes;
481                 break;
482         case LEAF_hastResourceDeletes:
483                 value->v.counter64 = res->deletes;
484                 break;
485         case LEAF_hastResourceFlushes:
486                 value->v.counter64 = res->flushes;
487                 break;
488         case LEAF_hastResourceActivemapUpdates:
489                 value->v.counter64 = res->activemap_updates;
490                 break;
491         case LEAF_hastResourceReadErrors:
492                 value->v.counter64 = res->read_errors;
493                 break;
494         case LEAF_hastResourceWriteErrors:
495                 value->v.counter64 = res->write_errors;
496                 break;
497         case LEAF_hastResourceDeleteErrors:
498                 value->v.counter64 = res->delete_errors;
499                 break;
500         case LEAF_hastResourceFlushErrors:
501                 value->v.counter64 = res->flush_errors;
502                 break;
503         case LEAF_hastResourceWorkerPid:
504                 value->v.integer = res->workerpid;
505                 break;
506         default:
507                 ret = SNMP_ERR_RES_UNAVAIL;
508                 break;
509         }
510         return (ret);
511 }