]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - usr.sbin/bsnmpd/modules/snmp_hast/hast_snmp.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.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         uint32_t        local_queue;
83         uint32_t        send_queue;
84         uint32_t        recv_queue;
85         uint32_t        done_queue;
86         uint32_t        idle_queue;
87 };
88
89 static TAILQ_HEAD(, hast_snmp_resource) resources =
90     TAILQ_HEAD_INITIALIZER(resources);
91
92 /* Path to configuration file. */
93 static u_char *cfgpath;
94 /* Ticks of the last hast resources update. */
95 static uint64_t last_resources_update;
96
97 static void free_resources(void);
98 static int hastctl(struct nv *nvin, struct nv **nvout);
99 static int hast_fini(void);
100 static int hast_init(struct lmodule *mod, int argc, char *argv[]);
101 static void hast_start(void);
102 static int set_role(const char *resource, int role);
103 static int str2role(const char *str);
104 static int str2replication(const char *str);
105 static int str2status(const char *str);
106 static int update_resources(void);
107
108 const struct snmp_module config = {
109     .comment   = "This module implements the BEGEMOT MIB for HAST.",
110     .init      = hast_init,
111     .start     = hast_start,
112     .fini      = hast_fini,
113     .tree      = hast_ctree,
114     .tree_size = hast_CTREE_SIZE,
115 };
116
117 static int
118 hast_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
119 {
120
121         module = mod;
122
123         pjdlog_init(PJDLOG_MODE_SYSLOG);
124         pjdlog_debug_set(0);
125
126         cfgpath = malloc(sizeof(HAST_CONFIG));
127         if (cfgpath == NULL) {
128                 pjdlog_error("Unable to allocate %zu bytes for cfgpath",
129                     sizeof(HAST_CONFIG));
130                 return (-1);
131         }
132         strcpy(cfgpath, HAST_CONFIG);
133         return(0);
134 }
135
136 static void
137 hast_start(void)
138 {
139         hast_index = or_register(&oid_hast,
140             "The MIB module for BEGEMOT-HAST-MIB.", module);
141 }
142
143 static int
144 hast_fini(void)
145 {
146
147         or_unregister(hast_index);
148         free_resources();
149         free(cfgpath);
150         return (0);
151 }
152
153 static void
154 free_resources(void)
155 {
156         struct hast_snmp_resource *res;
157
158         while ((res = TAILQ_FIRST(&resources)) != NULL) {
159                 TAILQ_REMOVE(&resources, res, link);
160                 free(res);
161         }
162 }
163
164 static int
165 str2role(const char *str)
166 {
167
168         if (strcmp(str, "init") == 0)
169                 return (HAST_ROLE_INIT);
170         if (strcmp(str, "primary") == 0)
171                 return (HAST_ROLE_PRIMARY);
172         if (strcmp(str, "secondary") == 0)
173                 return (HAST_ROLE_SECONDARY);
174         return (HAST_ROLE_UNDEF);
175 }
176
177 static int
178 str2replication(const char *str)
179 {
180
181         if (strcmp(str, "fullsync") == 0)
182                 return (HAST_REPLICATION_FULLSYNC);
183         if (strcmp(str, "memsync") == 0)
184                 return (HAST_REPLICATION_MEMSYNC);
185         if (strcmp(str, "async") == 0)
186                 return (HAST_REPLICATION_ASYNC);
187         return (-1);
188 }
189
190 static int
191 str2status(const char *str)
192 {
193
194         if (strcmp(str, "complete") == 0)
195                 return (0);
196         if (strcmp(str, "degraded") == 0)
197                 return (1);
198         return (-1);
199 }
200
201 static int
202 hastctl(struct nv *nvin, struct nv **nvout)
203 {
204         struct hastd_config *cfg;
205         struct proto_conn *conn;
206         struct nv *nv;
207         int error;
208
209         cfg = yy_config_parse(cfgpath, true);
210         if (cfg == NULL)
211                 return (-1);
212
213         /* Setup control connection... */
214         if (proto_client(NULL, cfg->hc_controladdr, &conn) == -1) {
215                 pjdlog_error("Unable to setup control connection to %s",
216                     cfg->hc_controladdr);
217                 return (-1);
218         }
219         /* ...and connect to hastd. */
220         if (proto_connect(conn, HAST_TIMEOUT) == -1) {
221                 pjdlog_error("Unable to connect to hastd via %s",
222                     cfg->hc_controladdr);
223                 proto_close(conn);
224                 return (-1);
225         }
226         /* Send the command to the server... */
227         if (hast_proto_send(NULL, conn, nvin, NULL, 0) == -1) {
228                 pjdlog_error("Unable to send command to hastd via %s",
229                     cfg->hc_controladdr);
230                 proto_close(conn);
231                 return (-1);
232         }
233         /* ...and receive reply. */
234         if (hast_proto_recv_hdr(conn, &nv) == -1) {
235                 pjdlog_error("cannot receive reply from hastd via %s",
236                     cfg->hc_controladdr);
237                 proto_close(conn);
238                 return (-1);
239         }
240         proto_close(conn);
241         error = nv_get_int16(nv, "error");
242         if (error != 0) {
243                 pjdlog_error("Error %d received from hastd.", error);
244                 nv_free(nv);
245                 return (-1);
246         }
247         nv_set_error(nv, 0);
248         *nvout = nv;
249         return (0);
250 }
251
252 static int
253 set_role(const char *resource, int role)
254 {
255         struct nv *nvin, *nvout;
256         int error;
257
258         nvin = nv_alloc();
259         nv_add_string(nvin, resource, "resource%d", 0);
260         nv_add_uint8(nvin, HASTCTL_CMD_SETROLE, "cmd");
261         nv_add_uint8(nvin, role, "role");
262         error = hastctl(nvin, &nvout);
263         nv_free(nvin);
264         if (error != 0)
265                 return (-1);
266         nv_free(nvout);
267         return (SNMP_ERR_NOERROR);
268 }
269
270 static int
271 update_resources(void)
272 {
273         struct hast_snmp_resource *res;
274         struct nv *nvin, *nvout;
275         static uint64_t now;
276         unsigned int i;
277         const char *str;
278         int error;
279
280         now = get_ticks();
281         if (now - last_resources_update < UPDATE_INTERVAL)
282                 return (0);
283
284         last_resources_update = now;
285
286         free_resources();
287
288         nvin = nv_alloc();
289         nv_add_uint8(nvin, HASTCTL_CMD_STATUS, "cmd");
290         nv_add_string(nvin, "all", "resource%d", 0);
291         error = hastctl(nvin, &nvout);
292         nv_free(nvin);
293         if (error != 0)
294                 return (-1);
295
296         for (i = 0; ; i++) {
297                 str = nv_get_string(nvout, "resource%u", i);
298                 if (str == NULL)
299                         break;
300                 res = calloc(1, sizeof(*res));
301                 if (res == NULL) {
302                         pjdlog_error("Unable to allocate %zu bytes for "
303                             "resource", sizeof(*res));
304                         return (-1);
305                 }
306                 res->index = i + 1;
307                 strncpy(res->name, str, sizeof(res->name) - 1);
308                 error = nv_get_int16(nvout, "error%u", i);
309                 if (error != 0)
310                         continue;
311                 str = nv_get_string(nvout, "role%u", i);
312                 res->role = str != NULL ? str2role(str) : HAST_ROLE_UNDEF;
313                 str = nv_get_string(nvout, "provname%u", i);
314                 if (str != NULL)
315                         strncpy(res->provname, str, sizeof(res->provname) - 1);
316                 str = nv_get_string(nvout, "localpath%u", i);
317                 if (str != NULL) {
318                         strncpy(res->localpath, str,
319                             sizeof(res->localpath) - 1);
320                 }
321                 res->extentsize = nv_get_uint32(nvout, "extentsize%u", i);
322                 res->keepdirty = nv_get_uint32(nvout, "keepdirty%u", i);
323                 str = nv_get_string(nvout, "remoteaddr%u", i);
324                 if (str != NULL) {
325                         strncpy(res->remoteaddr, str,
326                             sizeof(res->remoteaddr) - 1);
327                 }
328                 str = nv_get_string(nvout, "sourceaddr%u", i);
329                 if (str != NULL) {
330                         strncpy(res->sourceaddr, str,
331                             sizeof(res->sourceaddr) - 1);
332                 }
333                 str = nv_get_string(nvout, "replication%u", i);
334                 res->replication = str != NULL ? str2replication(str) : -1;
335                 str = nv_get_string(nvout, "status%u", i);
336                 res->status = str != NULL ? str2status(str) : -1;
337                 res->dirty = nv_get_uint64(nvout, "dirty%u", i);
338                 res->reads = nv_get_uint64(nvout, "stat_read%u", i);
339                 res->writes = nv_get_uint64(nvout, "stat_write%u", i);
340                 res->deletes = nv_get_uint64(nvout, "stat_delete%u", i);
341                 res->flushes = nv_get_uint64(nvout, "stat_flush%u", i);
342                 res->activemap_updates =
343                     nv_get_uint64(nvout, "stat_activemap_update%u", i);
344                 res->read_errors =
345                     nv_get_uint64(nvout, "stat_read_error%u", i);
346                 res->write_errors =
347                     nv_get_uint64(nvout, "stat_write_error%u", i);
348                 res->delete_errors =
349                     nv_get_uint64(nvout, "stat_delete_error%u", i);
350                 res->flush_errors =
351                     nv_get_uint64(nvout, "stat_flush_error%u", i);
352                 res->workerpid = nv_get_int32(nvout, "workerpid%u", i);
353                 res->local_queue =
354                     nv_get_uint64(nvout, "local_queue_size%u", i);
355                 res->send_queue =
356                     nv_get_uint64(nvout, "send_queue_size%u", i);
357                 res->recv_queue =
358                     nv_get_uint64(nvout, "recv_queue_size%u", i);
359                 res->done_queue =
360                     nv_get_uint64(nvout, "done_queue_size%u", i);
361                 res->idle_queue =
362                     nv_get_uint64(nvout, "idle_queue_size%u", i);
363                 TAILQ_INSERT_TAIL(&resources, res, link);
364         }
365         nv_free(nvout);
366         return (0);
367 }
368
369 int
370 op_hastConfig(struct snmp_context *context, struct snmp_value *value,
371     u_int sub, u_int iidx __unused, enum snmp_op op)
372 {
373         asn_subid_t which;
374
375         which = value->var.subs[sub - 1];
376
377         switch (op) {
378         case SNMP_OP_GET:
379                 switch (which) {
380                 case LEAF_hastConfigFile:
381                         return (string_get(value, cfgpath, -1));
382                 default:
383                         return (SNMP_ERR_RES_UNAVAIL);
384                 }
385         case SNMP_OP_SET:
386                 switch (which) {
387                 case LEAF_hastConfigFile:
388                         return (string_save(value, context, -1,
389                             (u_char **)&cfgpath));
390                 default:
391                         return (SNMP_ERR_RES_UNAVAIL);
392                 }
393         case SNMP_OP_GETNEXT:
394         case SNMP_OP_ROLLBACK:
395         case SNMP_OP_COMMIT:
396                 return (SNMP_ERR_NOERROR);
397         default:
398                 return (SNMP_ERR_RES_UNAVAIL);
399         }
400 }
401
402 int
403 op_hastResourceTable(struct snmp_context *context __unused,
404     struct snmp_value *value, u_int sub, u_int iidx __unused, enum snmp_op op)
405 {
406         struct hast_snmp_resource *res;
407         asn_subid_t which;
408         int ret;
409
410         if (update_resources() == -1)
411                 return (SNMP_ERR_RES_UNAVAIL);
412
413         which = value->var.subs[sub - 1];
414
415         switch (op) {
416         case SNMP_OP_GETNEXT:
417                 res = NEXT_OBJECT_INT(&resources, &value->var, sub);
418                 if (res == NULL)
419                         return (SNMP_ERR_NOSUCHNAME);
420                 value->var.len = sub + 1;
421                 value->var.subs[sub] = res->index;
422                 break;
423         case SNMP_OP_GET:
424                 if (value->var.len - sub != 1)
425                         return (SNMP_ERR_NOSUCHNAME);
426                 res = FIND_OBJECT_INT(&resources, &value->var, sub);
427                 if (res == NULL)
428                         return (SNMP_ERR_NOSUCHNAME);
429                 break;
430         case SNMP_OP_SET:
431                 res = FIND_OBJECT_INT(&resources, &value->var, sub);
432                 if (res == NULL)
433                         return (SNMP_ERR_NOSUCHNAME);
434                 switch (which) {
435                 case LEAF_hastResourceRole:
436                         ret = set_role(res->name, value->v.integer);
437                         /* force update on next run */
438                         last_resources_update = 0;
439                         break;
440                 default:
441                         ret = SNMP_ERR_NOT_WRITEABLE;
442                         break;
443                 }
444                 return ret;
445         case SNMP_OP_ROLLBACK:
446         case SNMP_OP_COMMIT:
447                 return (SNMP_ERR_NOERROR);
448         default:
449                 return (SNMP_ERR_RES_UNAVAIL);
450         }
451
452         ret = SNMP_ERR_NOERROR;
453
454         switch (which) {
455         case LEAF_hastResourceIndex:
456                 value->v.integer = res->index;
457                 break;
458         case LEAF_hastResourceName:
459                 ret = string_get(value, res->name, -1);
460                 break;
461         case LEAF_hastResourceRole:
462                 value->v.integer = res->role;
463                 break;
464         case LEAF_hastResourceProvName:
465                 ret = string_get(value, res->provname, -1);
466                 break;
467         case LEAF_hastResourceLocalPath:
468                 ret = string_get(value, res->localpath, -1);
469                 break;
470         case LEAF_hastResourceExtentSize:
471                 value->v.integer = res->extentsize;
472                 break;
473         case LEAF_hastResourceKeepDirty:
474                 value->v.integer = res->keepdirty;
475                 break;
476         case LEAF_hastResourceRemoteAddr:
477                 ret = string_get(value, res->remoteaddr, -1);
478                 break;
479         case LEAF_hastResourceSourceAddr:
480                 ret = string_get(value, res->sourceaddr, -1);
481                 break;
482         case LEAF_hastResourceReplication:
483                 value->v.integer = res->replication;
484                 break;
485         case LEAF_hastResourceStatus:
486                 value->v.integer = res->status;
487                 break;
488         case LEAF_hastResourceDirty:
489                 value->v.counter64 = res->dirty;
490                 break;
491         case LEAF_hastResourceReads:
492                 value->v.counter64 = res->reads;
493                 break;
494         case LEAF_hastResourceWrites:
495                 value->v.counter64 = res->writes;
496                 break;
497         case LEAF_hastResourceDeletes:
498                 value->v.counter64 = res->deletes;
499                 break;
500         case LEAF_hastResourceFlushes:
501                 value->v.counter64 = res->flushes;
502                 break;
503         case LEAF_hastResourceActivemapUpdates:
504                 value->v.counter64 = res->activemap_updates;
505                 break;
506         case LEAF_hastResourceReadErrors:
507                 value->v.counter64 = res->read_errors;
508                 break;
509         case LEAF_hastResourceWriteErrors:
510                 value->v.counter64 = res->write_errors;
511                 break;
512         case LEAF_hastResourceDeleteErrors:
513                 value->v.counter64 = res->delete_errors;
514                 break;
515         case LEAF_hastResourceFlushErrors:
516                 value->v.counter64 = res->flush_errors;
517                 break;
518         case LEAF_hastResourceWorkerPid:
519                 value->v.integer = res->workerpid;
520                 break;
521         case LEAF_hastResourceLocalQueue:
522                 value->v.uint32 = res->local_queue;
523                 break;
524         case LEAF_hastResourceSendQueue:
525                 value->v.uint32 = res->send_queue;
526                 break;
527         case LEAF_hastResourceRecvQueue:
528                 value->v.uint32 = res->recv_queue;
529                 break;
530         case LEAF_hastResourceDoneQueue:
531                 value->v.uint32 = res->done_queue;
532                 break;
533         case LEAF_hastResourceIdleQueue:
534                 value->v.uint32 = res->idle_queue;
535                 break;
536         default:
537                 ret = SNMP_ERR_RES_UNAVAIL;
538                 break;
539         }
540         return (ret);
541 }