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