Path: blob/main/usr.sbin/bsnmpd/modules/snmp_hast/hast_snmp.c
109330 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2013 Mikolaj Golub <[email protected]>4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728#include <sys/param.h>29#include <sys/queue.h>3031#include <bsnmp/snmpmod.h>3233#include <string.h>3435#include "hast.h"36#include "hast_oid.h"37#include "hast_proto.h"38#include "hast_tree.h"39#include "nv.h"40#include "pjdlog.h"41#include "proto.h"4243#define UPDATE_INTERVAL 500 /* update interval in ticks */4445static struct lmodule *module;4647static const struct asn_oid oid_hast = OIDX_begemotHast;4849/* the Object Resource registration index */50static u_int hast_index = 0;5152/*53* Structure that describes single resource.54*/55struct hast_snmp_resource {56TAILQ_ENTRY(hast_snmp_resource) link;57int32_t index;58char name[NAME_MAX];59int error;60int role;61char provname[NAME_MAX];62char localpath[PATH_MAX];63int32_t extentsize;64int32_t keepdirty;65char remoteaddr[HAST_ADDRSIZE];66char sourceaddr[HAST_ADDRSIZE];67int replication;68int status;69uint64_t dirty;70uint64_t reads;71uint64_t writes;72uint64_t deletes;73uint64_t flushes;74uint64_t activemap_updates;75uint64_t read_errors;76uint64_t write_errors;77uint64_t delete_errors;78uint64_t flush_errors;79pid_t workerpid;80uint32_t local_queue;81uint32_t send_queue;82uint32_t recv_queue;83uint32_t done_queue;84uint32_t idle_queue;85};8687static TAILQ_HEAD(, hast_snmp_resource) resources =88TAILQ_HEAD_INITIALIZER(resources);8990/* Path to configuration file. */91static u_char *cfgpath;92/* Ticks of the last hast resources update. */93static uint64_t last_resources_update;9495static void free_resources(void);96static int hastctl(struct nv *nvin, struct nv **nvout);97static int hast_fini(void);98static int hast_init(struct lmodule *mod, int argc, char *argv[]);99static void hast_start(void);100static int set_role(const char *resource, int role);101static int str2role(const char *str);102static int str2replication(const char *str);103static int str2status(const char *str);104static int update_resources(void);105106const struct snmp_module config = {107.comment = "This module implements the BEGEMOT MIB for HAST.",108.init = hast_init,109.start = hast_start,110.fini = hast_fini,111.tree = hast_ctree,112.tree_size = hast_CTREE_SIZE,113};114115static int116hast_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)117{118119module = mod;120121pjdlog_init(PJDLOG_MODE_SYSLOG);122pjdlog_debug_set(0);123124cfgpath = malloc(sizeof(HAST_CONFIG));125if (cfgpath == NULL) {126pjdlog_error("Unable to allocate %zu bytes for cfgpath",127sizeof(HAST_CONFIG));128return (-1);129}130strcpy(cfgpath, HAST_CONFIG);131return(0);132}133134static void135hast_start(void)136{137hast_index = or_register(&oid_hast,138"The MIB module for BEGEMOT-HAST-MIB.", module);139}140141static int142hast_fini(void)143{144145or_unregister(hast_index);146free_resources();147free(cfgpath);148return (0);149}150151static void152free_resources(void)153{154struct hast_snmp_resource *res;155156while ((res = TAILQ_FIRST(&resources)) != NULL) {157TAILQ_REMOVE(&resources, res, link);158free(res);159}160}161162static int163str2role(const char *str)164{165166if (strcmp(str, "init") == 0)167return (HAST_ROLE_INIT);168if (strcmp(str, "primary") == 0)169return (HAST_ROLE_PRIMARY);170if (strcmp(str, "secondary") == 0)171return (HAST_ROLE_SECONDARY);172return (HAST_ROLE_UNDEF);173}174175static int176str2replication(const char *str)177{178179if (strcmp(str, "fullsync") == 0)180return (HAST_REPLICATION_FULLSYNC);181if (strcmp(str, "memsync") == 0)182return (HAST_REPLICATION_MEMSYNC);183if (strcmp(str, "async") == 0)184return (HAST_REPLICATION_ASYNC);185return (-1);186}187188static int189str2status(const char *str)190{191192if (strcmp(str, "complete") == 0)193return (0);194if (strcmp(str, "degraded") == 0)195return (1);196return (-1);197}198199static int200hastctl(struct nv *nvin, struct nv **nvout)201{202struct hastd_config *cfg;203struct proto_conn *conn;204struct nv *nv;205int error;206207cfg = yy_config_parse(cfgpath, true);208if (cfg == NULL)209return (-1);210211/* Setup control connection... */212if (proto_client(NULL, cfg->hc_controladdr, &conn) == -1) {213pjdlog_error("Unable to setup control connection to %s",214cfg->hc_controladdr);215return (-1);216}217/* ...and connect to hastd. */218if (proto_connect(conn, HAST_TIMEOUT) == -1) {219pjdlog_error("Unable to connect to hastd via %s",220cfg->hc_controladdr);221proto_close(conn);222return (-1);223}224/* Send the command to the server... */225if (hast_proto_send(NULL, conn, nvin, NULL, 0) == -1) {226pjdlog_error("Unable to send command to hastd via %s",227cfg->hc_controladdr);228proto_close(conn);229return (-1);230}231/* ...and receive reply. */232if (hast_proto_recv_hdr(conn, &nv) == -1) {233pjdlog_error("cannot receive reply from hastd via %s",234cfg->hc_controladdr);235proto_close(conn);236return (-1);237}238proto_close(conn);239error = nv_get_int16(nv, "error");240if (error != 0) {241pjdlog_error("Error %d received from hastd.", error);242nv_free(nv);243return (-1);244}245nv_set_error(nv, 0);246*nvout = nv;247return (0);248}249250static int251set_role(const char *resource, int role)252{253struct nv *nvin, *nvout;254int error;255256nvin = nv_alloc();257nv_add_string(nvin, resource, "resource%d", 0);258nv_add_uint8(nvin, HASTCTL_CMD_SETROLE, "cmd");259nv_add_uint8(nvin, role, "role");260error = hastctl(nvin, &nvout);261nv_free(nvin);262if (error != 0)263return (-1);264nv_free(nvout);265return (SNMP_ERR_NOERROR);266}267268static int269update_resources(void)270{271struct hast_snmp_resource *res;272struct nv *nvin, *nvout;273static uint64_t now;274unsigned int i;275const char *str;276int error;277278now = get_ticks();279if (now - last_resources_update < UPDATE_INTERVAL)280return (0);281282last_resources_update = now;283284free_resources();285286nvin = nv_alloc();287nv_add_uint8(nvin, HASTCTL_CMD_STATUS, "cmd");288nv_add_string(nvin, "all", "resource%d", 0);289error = hastctl(nvin, &nvout);290nv_free(nvin);291if (error != 0)292return (-1);293294for (i = 0; ; i++) {295str = nv_get_string(nvout, "resource%u", i);296if (str == NULL)297break;298res = calloc(1, sizeof(*res));299if (res == NULL) {300pjdlog_error("Unable to allocate %zu bytes for "301"resource", sizeof(*res));302return (-1);303}304res->index = i + 1;305strncpy(res->name, str, sizeof(res->name) - 1);306error = nv_get_int16(nvout, "error%u", i);307if (error != 0)308continue;309str = nv_get_string(nvout, "role%u", i);310res->role = str != NULL ? str2role(str) : HAST_ROLE_UNDEF;311str = nv_get_string(nvout, "provname%u", i);312if (str != NULL)313strncpy(res->provname, str, sizeof(res->provname) - 1);314str = nv_get_string(nvout, "localpath%u", i);315if (str != NULL) {316strncpy(res->localpath, str,317sizeof(res->localpath) - 1);318}319res->extentsize = nv_get_uint32(nvout, "extentsize%u", i);320res->keepdirty = nv_get_uint32(nvout, "keepdirty%u", i);321str = nv_get_string(nvout, "remoteaddr%u", i);322if (str != NULL) {323strncpy(res->remoteaddr, str,324sizeof(res->remoteaddr) - 1);325}326str = nv_get_string(nvout, "sourceaddr%u", i);327if (str != NULL) {328strncpy(res->sourceaddr, str,329sizeof(res->sourceaddr) - 1);330}331str = nv_get_string(nvout, "replication%u", i);332res->replication = str != NULL ? str2replication(str) : -1;333str = nv_get_string(nvout, "status%u", i);334res->status = str != NULL ? str2status(str) : -1;335res->dirty = nv_get_uint64(nvout, "dirty%u", i);336res->reads = nv_get_uint64(nvout, "stat_read%u", i);337res->writes = nv_get_uint64(nvout, "stat_write%u", i);338res->deletes = nv_get_uint64(nvout, "stat_delete%u", i);339res->flushes = nv_get_uint64(nvout, "stat_flush%u", i);340res->activemap_updates =341nv_get_uint64(nvout, "stat_activemap_update%u", i);342res->read_errors =343nv_get_uint64(nvout, "stat_read_error%u", i);344res->write_errors =345nv_get_uint64(nvout, "stat_write_error%u", i);346res->delete_errors =347nv_get_uint64(nvout, "stat_delete_error%u", i);348res->flush_errors =349nv_get_uint64(nvout, "stat_flush_error%u", i);350res->workerpid = nv_get_int32(nvout, "workerpid%u", i);351res->local_queue =352nv_get_uint64(nvout, "local_queue_size%u", i);353res->send_queue =354nv_get_uint64(nvout, "send_queue_size%u", i);355res->recv_queue =356nv_get_uint64(nvout, "recv_queue_size%u", i);357res->done_queue =358nv_get_uint64(nvout, "done_queue_size%u", i);359res->idle_queue =360nv_get_uint64(nvout, "idle_queue_size%u", i);361TAILQ_INSERT_TAIL(&resources, res, link);362}363nv_free(nvout);364return (0);365}366367int368op_hastConfig(struct snmp_context *context, struct snmp_value *value,369u_int sub, u_int iidx __unused, enum snmp_op op)370{371asn_subid_t which;372373which = value->var.subs[sub - 1];374375switch (op) {376case SNMP_OP_GET:377switch (which) {378case LEAF_hastConfigFile:379return (string_get(value, cfgpath, -1));380default:381return (SNMP_ERR_RES_UNAVAIL);382}383case SNMP_OP_SET:384switch (which) {385case LEAF_hastConfigFile:386return (string_save(value, context, -1,387(u_char **)&cfgpath));388default:389return (SNMP_ERR_RES_UNAVAIL);390}391case SNMP_OP_GETNEXT:392case SNMP_OP_ROLLBACK:393case SNMP_OP_COMMIT:394return (SNMP_ERR_NOERROR);395default:396return (SNMP_ERR_RES_UNAVAIL);397}398}399400int401op_hastResourceTable(struct snmp_context *context __unused,402struct snmp_value *value, u_int sub, u_int iidx __unused, enum snmp_op op)403{404struct hast_snmp_resource *res;405asn_subid_t which;406int ret;407408if (update_resources() == -1)409return (SNMP_ERR_RES_UNAVAIL);410411which = value->var.subs[sub - 1];412413switch (op) {414case SNMP_OP_GETNEXT:415res = NEXT_OBJECT_INT(&resources, &value->var, sub);416if (res == NULL)417return (SNMP_ERR_NOSUCHNAME);418value->var.len = sub + 1;419value->var.subs[sub] = res->index;420break;421case SNMP_OP_GET:422if (value->var.len - sub != 1)423return (SNMP_ERR_NOSUCHNAME);424res = FIND_OBJECT_INT(&resources, &value->var, sub);425if (res == NULL)426return (SNMP_ERR_NOSUCHNAME);427break;428case SNMP_OP_SET:429res = FIND_OBJECT_INT(&resources, &value->var, sub);430if (res == NULL)431return (SNMP_ERR_NOSUCHNAME);432switch (which) {433case LEAF_hastResourceRole:434ret = set_role(res->name, value->v.integer);435/* force update on next run */436last_resources_update = 0;437break;438default:439ret = SNMP_ERR_NOT_WRITEABLE;440break;441}442return ret;443case SNMP_OP_ROLLBACK:444case SNMP_OP_COMMIT:445return (SNMP_ERR_NOERROR);446default:447return (SNMP_ERR_RES_UNAVAIL);448}449450ret = SNMP_ERR_NOERROR;451452switch (which) {453case LEAF_hastResourceIndex:454value->v.integer = res->index;455break;456case LEAF_hastResourceName:457ret = string_get(value, res->name, -1);458break;459case LEAF_hastResourceRole:460value->v.integer = res->role;461break;462case LEAF_hastResourceProvName:463ret = string_get(value, res->provname, -1);464break;465case LEAF_hastResourceLocalPath:466ret = string_get(value, res->localpath, -1);467break;468case LEAF_hastResourceExtentSize:469value->v.integer = res->extentsize;470break;471case LEAF_hastResourceKeepDirty:472value->v.integer = res->keepdirty;473break;474case LEAF_hastResourceRemoteAddr:475ret = string_get(value, res->remoteaddr, -1);476break;477case LEAF_hastResourceSourceAddr:478ret = string_get(value, res->sourceaddr, -1);479break;480case LEAF_hastResourceReplication:481value->v.integer = res->replication;482break;483case LEAF_hastResourceStatus:484value->v.integer = res->status;485break;486case LEAF_hastResourceDirty:487value->v.counter64 = res->dirty;488break;489case LEAF_hastResourceReads:490value->v.counter64 = res->reads;491break;492case LEAF_hastResourceWrites:493value->v.counter64 = res->writes;494break;495case LEAF_hastResourceDeletes:496value->v.counter64 = res->deletes;497break;498case LEAF_hastResourceFlushes:499value->v.counter64 = res->flushes;500break;501case LEAF_hastResourceActivemapUpdates:502value->v.counter64 = res->activemap_updates;503break;504case LEAF_hastResourceReadErrors:505value->v.counter64 = res->read_errors;506break;507case LEAF_hastResourceWriteErrors:508value->v.counter64 = res->write_errors;509break;510case LEAF_hastResourceDeleteErrors:511value->v.counter64 = res->delete_errors;512break;513case LEAF_hastResourceFlushErrors:514value->v.counter64 = res->flush_errors;515break;516case LEAF_hastResourceWorkerPid:517value->v.integer = res->workerpid;518break;519case LEAF_hastResourceLocalQueue:520value->v.uint32 = res->local_queue;521break;522case LEAF_hastResourceSendQueue:523value->v.uint32 = res->send_queue;524break;525case LEAF_hastResourceRecvQueue:526value->v.uint32 = res->recv_queue;527break;528case LEAF_hastResourceDoneQueue:529value->v.uint32 = res->done_queue;530break;531case LEAF_hastResourceIdleQueue:532value->v.uint32 = res->idle_queue;533break;534default:535ret = SNMP_ERR_RES_UNAVAIL;536break;537}538return (ret);539}540541542