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