2 * Copyright (c) 2013 Mikolaj Golub <trociny@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/queue.h>
33 #include <bsnmp/snmpmod.h>
39 #include "hast_proto.h"
40 #include "hast_tree.h"
45 #define UPDATE_INTERVAL 500 /* update interval in ticks */
47 static struct lmodule *module;
49 static const struct asn_oid oid_hast = OIDX_begemotHast;
51 /* the Object Resource registration index */
52 static u_int hast_index = 0;
55 * Structure that describes single resource.
57 struct hast_snmp_resource {
58 TAILQ_ENTRY(hast_snmp_resource) link;
63 char provname[NAME_MAX];
64 char localpath[PATH_MAX];
67 char remoteaddr[HAST_ADDRSIZE];
68 char sourceaddr[HAST_ADDRSIZE];
76 uint64_t activemap_updates;
78 uint64_t write_errors;
79 uint64_t delete_errors;
80 uint64_t flush_errors;
84 static TAILQ_HEAD(, hast_snmp_resource) resources =
85 TAILQ_HEAD_INITIALIZER(resources);
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;
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);
103 const struct snmp_module config = {
104 .comment = "This module implements the BEGEMOT MIB for HAST.",
109 .tree_size = hast_CTREE_SIZE,
113 hast_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
118 pjdlog_init(PJDLOG_MODE_SYSLOG);
121 cfgpath = malloc(sizeof(HAST_CONFIG));
122 if (cfgpath == NULL) {
123 pjdlog_error("Unable to allocate %zu bytes for cfgpath",
124 sizeof(HAST_CONFIG));
127 strcpy(cfgpath, HAST_CONFIG);
134 hast_index = or_register(&oid_hast,
135 "The MIB module for BEGEMOT-HAST-MIB.", module);
142 or_unregister(hast_index);
151 struct hast_snmp_resource *res;
153 while ((res = TAILQ_FIRST(&resources)) != NULL) {
154 TAILQ_REMOVE(&resources, res, link);
160 str2role(const char *str)
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);
173 str2replication(const char *str)
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);
186 str2status(const char *str)
189 if (strcmp(str, "complete") == 0)
191 if (strcmp(str, "degraded") == 0)
197 hastctl(struct nv *nvin, struct nv **nvout)
199 struct hastd_config *cfg;
200 struct proto_conn *conn;
204 cfg = yy_config_parse(cfgpath, true);
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);
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);
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);
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);
236 error = nv_get_int16(nv, "error");
238 pjdlog_error("Error %d received from hastd.", error);
248 set_role(const char *resource, int role)
250 struct nv *nvin, *nvout;
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);
262 return (SNMP_ERR_NOERROR);
266 update_resources(void)
268 struct hast_snmp_resource *res;
269 struct nv *nvin, *nvout;
276 if (now - last_resources_update < UPDATE_INTERVAL)
279 last_resources_update = now;
284 nv_add_uint8(nvin, HASTCTL_CMD_STATUS, "cmd");
285 nv_add_string(nvin, "all", "resource%d", 0);
286 error = hastctl(nvin, &nvout);
292 str = nv_get_string(nvout, "resource%u", i);
295 res = calloc(1, sizeof(*res));
297 pjdlog_error("Unable to allocate %zu bytes for "
298 "resource", sizeof(*res));
302 strncpy(res->name, str, sizeof(res->name) - 1);
303 error = nv_get_int16(nvout, "error%u", i);
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);
310 strncpy(res->provname, str, sizeof(res->provname) - 1);
311 str = nv_get_string(nvout, "localpath%u", i);
313 strncpy(res->localpath, str,
314 sizeof(res->localpath) - 1);
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);
320 strncpy(res->remoteaddr, str,
321 sizeof(res->remoteaddr) - 1);
323 str = nv_get_string(nvout, "sourceaddr%u", i);
325 strncpy(res->sourceaddr, str,
326 sizeof(res->sourceaddr) - 1);
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);
340 nv_get_uint64(nvout, "stat_read_error%u", i);
342 nv_get_uint64(nvout, "stat_write_error%u", i);
344 nv_get_uint64(nvout, "stat_delete_error%u", i);
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);
355 op_hastConfig(struct snmp_context *context, struct snmp_value *value,
356 u_int sub, u_int iidx __unused, enum snmp_op op)
360 which = value->var.subs[sub - 1];
365 case LEAF_hastConfigFile:
366 return (string_get(value, cfgpath, -1));
368 return (SNMP_ERR_RES_UNAVAIL);
372 case LEAF_hastConfigFile:
373 return (string_save(value, context, -1,
374 (u_char **)&cfgpath));
376 return (SNMP_ERR_RES_UNAVAIL);
378 case SNMP_OP_GETNEXT:
379 case SNMP_OP_ROLLBACK:
381 return (SNMP_ERR_NOERROR);
383 return (SNMP_ERR_RES_UNAVAIL);
388 op_hastResourceTable(struct snmp_context *context __unused,
389 struct snmp_value *value, u_int sub, u_int iidx __unused, enum snmp_op op)
391 struct hast_snmp_resource *res;
395 if (update_resources() == -1)
396 return (SNMP_ERR_RES_UNAVAIL);
398 which = value->var.subs[sub - 1];
401 case SNMP_OP_GETNEXT:
402 res = NEXT_OBJECT_INT(&resources, &value->var, sub);
404 return (SNMP_ERR_NOSUCHNAME);
405 value->var.len = sub + 1;
406 value->var.subs[sub] = res->index;
409 if (value->var.len - sub != 1)
410 return (SNMP_ERR_NOSUCHNAME);
411 res = FIND_OBJECT_INT(&resources, &value->var, sub);
413 return (SNMP_ERR_NOSUCHNAME);
416 res = FIND_OBJECT_INT(&resources, &value->var, sub);
418 return (SNMP_ERR_NOSUCHNAME);
420 case LEAF_hastResourceRole:
421 ret = set_role(res->name, value->v.integer);
422 /* force update on next run */
423 last_resources_update = 0;
426 ret = SNMP_ERR_NOT_WRITEABLE;
430 case SNMP_OP_ROLLBACK:
432 return (SNMP_ERR_NOERROR);
434 return (SNMP_ERR_RES_UNAVAIL);
437 ret = SNMP_ERR_NOERROR;
440 case LEAF_hastResourceIndex:
441 value->v.integer = res->index;
443 case LEAF_hastResourceName:
444 ret = string_get(value, res->name, -1);
446 case LEAF_hastResourceRole:
447 value->v.integer = res->role;
449 case LEAF_hastResourceProvName:
450 ret = string_get(value, res->provname, -1);
452 case LEAF_hastResourceLocalPath:
453 ret = string_get(value, res->localpath, -1);
455 case LEAF_hastResourceExtentSize:
456 value->v.integer = res->extentsize;
458 case LEAF_hastResourceKeepDirty:
459 value->v.integer = res->keepdirty;
461 case LEAF_hastResourceRemoteAddr:
462 ret = string_get(value, res->remoteaddr, -1);
464 case LEAF_hastResourceSourceAddr:
465 ret = string_get(value, res->sourceaddr, -1);
467 case LEAF_hastResourceReplication:
468 value->v.integer = res->replication;
470 case LEAF_hastResourceStatus:
471 value->v.integer = res->status;
473 case LEAF_hastResourceDirty:
474 value->v.counter64 = res->dirty;
476 case LEAF_hastResourceReads:
477 value->v.counter64 = res->reads;
479 case LEAF_hastResourceWrites:
480 value->v.counter64 = res->writes;
482 case LEAF_hastResourceDeletes:
483 value->v.counter64 = res->deletes;
485 case LEAF_hastResourceFlushes:
486 value->v.counter64 = res->flushes;
488 case LEAF_hastResourceActivemapUpdates:
489 value->v.counter64 = res->activemap_updates;
491 case LEAF_hastResourceReadErrors:
492 value->v.counter64 = res->read_errors;
494 case LEAF_hastResourceWriteErrors:
495 value->v.counter64 = res->write_errors;
497 case LEAF_hastResourceDeleteErrors:
498 value->v.counter64 = res->delete_errors;
500 case LEAF_hastResourceFlushErrors:
501 value->v.counter64 = res->flush_errors;
503 case LEAF_hastResourceWorkerPid:
504 value->v.integer = res->workerpid;
507 ret = SNMP_ERR_RES_UNAVAIL;