]> git.proxmox.com Git - mirror_frr.git/blame - lib/agentx.c
Merge pull request #11003 from anlancs/bgpd-mh-trival-remove
[mirror_frr.git] / lib / agentx.c
CommitLineData
d6be5fb9
VB
1/* SNMP support
2 * Copyright (C) 2012 Vincent Bernat <bernat@luffy.cx>
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
896014f4
DL
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
d6be5fb9
VB
19 */
20
21#include <zebra.h>
22
5986b66b 23#ifdef SNMP_AGENTX
d6be5fb9
VB
24#include <net-snmp/net-snmp-config.h>
25#include <net-snmp/net-snmp-includes.h>
56e2c5e8
DL
26#include <net-snmp/agent/net-snmp-agent-includes.h>
27#include <net-snmp/agent/snmp_vars.h>
d6be5fb9
VB
28
29#include "command.h"
30#include "smux.h"
d11f748b 31#include "memory.h"
56e2c5e8 32#include "linklist.h"
09781197 33#include "lib/version.h"
220d7368 34#include "lib_errors.h"
b2fa8c0f
DL
35#include "xref.h"
36
80413c20 37XREF_SETUP();
d6be5fb9 38
8451921b 39DEFINE_HOOK(agentx_enabled, (), ());
ec48460e 40
56e2c5e8
DL
41static int agentx_enabled = 0;
42
43static struct thread_master *agentx_tm;
44static struct thread *timeout_thr = NULL;
45static struct list *events = NULL;
46
47static void agentx_events_update(void);
48
cc9f21da 49static void agentx_timeout(struct thread *t)
56e2c5e8 50{
d62a17ae 51 timeout_thr = NULL;
56e2c5e8 52
d62a17ae 53 snmp_timeout();
54 run_alarms();
55 netsnmp_check_outstanding_agent_requests();
56 agentx_events_update();
56e2c5e8
DL
57}
58
cc9f21da 59static void agentx_read(struct thread *t)
56e2c5e8 60{
d62a17ae 61 fd_set fds;
19d95d40 62 int flags, new_flags = 0;
3b717261 63 int nonblock = false;
d62a17ae 64 struct listnode *ln = THREAD_ARG(t);
7640e3c6
IR
65 struct thread **thr = listgetdata(ln);
66 XFREE(MTYPE_TMP, thr);
d62a17ae 67 list_delete_node(events, ln);
56e2c5e8 68
3b717261 69 /* fix for non blocking socket */
70 flags = fcntl(THREAD_FD(t), F_GETFL, 0);
19d95d40
DS
71 if (-1 == flags) {
72 flog_err(EC_LIB_SYSTEM_CALL, "Failed to get FD settings fcntl: %s(%d)",
73 strerror(errno), errno);
cc9f21da 74 return;
19d95d40 75 }
3b717261 76
77 if (flags & O_NONBLOCK)
78 nonblock = true;
79 else
19d95d40
DS
80 new_flags = fcntl(THREAD_FD(t), F_SETFL, flags | O_NONBLOCK);
81
82 if (new_flags == -1)
83 flog_err(EC_LIB_SYSTEM_CALL, "Failed to set snmp fd non blocking: %s(%d)",
84 strerror(errno), errno);
3b717261 85
d62a17ae 86 FD_ZERO(&fds);
87 FD_SET(THREAD_FD(t), &fds);
88 snmp_read(&fds);
56e2c5e8 89
3b717261 90 /* Reset the flag */
19d95d40
DS
91 if (!nonblock) {
92 new_flags = fcntl(THREAD_FD(t), F_SETFL, flags);
93
94 if (new_flags == -1)
95 flog_err(
96 EC_LIB_SYSTEM_CALL,
97 "Failed to set snmp fd back to original settings: %s(%d)",
98 strerror(errno), errno);
99 }
3b717261 100
d62a17ae 101 netsnmp_check_outstanding_agent_requests();
102 agentx_events_update();
56e2c5e8
DL
103}
104
d62a17ae 105static void agentx_events_update(void)
56e2c5e8 106{
d62a17ae 107 int maxfd = 0;
108 int block = 1;
109 struct timeval timeout = {.tv_sec = 0, .tv_usec = 0};
110 fd_set fds;
111 struct listnode *ln;
7640e3c6 112 struct thread **thr;
d62a17ae 113 int fd, thr_fd;
114
50478845 115 thread_cancel(&timeout_thr);
d62a17ae 116
117 FD_ZERO(&fds);
118 snmp_select_info(&maxfd, &fds, &timeout, &block);
119
120 if (!block) {
121 timeout_thr = NULL;
122 thread_add_timer_tv(agentx_tm, agentx_timeout, NULL, &timeout,
123 &timeout_thr);
124 }
125
126 ln = listhead(events);
127 thr = ln ? listgetdata(ln) : NULL;
7640e3c6 128 thr_fd = thr ? THREAD_FD(*thr) : -1;
d62a17ae 129
130 /* "two-pointer" / two-list simultaneous iteration
131 * ln/thr/thr_fd point to the next existing event listener to hit while
132 * fd counts to catch up */
133 for (fd = 0; fd < maxfd; fd++) {
134 /* caught up */
135 if (thr_fd == fd) {
136 struct listnode *nextln = listnextnode(ln);
137 if (!FD_ISSET(fd, &fds)) {
7640e3c6
IR
138 thread_cancel(thr);
139 XFREE(MTYPE_TMP, thr);
d62a17ae 140 list_delete_node(events, ln);
141 }
142 ln = nextln;
143 thr = ln ? listgetdata(ln) : NULL;
7640e3c6 144 thr_fd = thr ? THREAD_FD(*thr) : -1;
d62a17ae 145 }
146 /* need listener, but haven't hit one where it would be */
147 else if (FD_ISSET(fd, &fds)) {
148 struct listnode *newln;
7640e3c6
IR
149 thr = XCALLOC(MTYPE_TMP, sizeof(struct thread *));
150 thread_add_read(agentx_tm, agentx_read, NULL, fd, thr);
d62a17ae 151 newln = listnode_add_before(events, ln, thr);
7640e3c6 152 (*thr)->arg = newln;
d62a17ae 153 }
154 }
155
156 /* leftover event listeners at this point have fd > maxfd, delete them
157 */
158 while (ln) {
159 struct listnode *nextln = listnextnode(ln);
b3d6bc6e 160 thr = listgetdata(ln);
7640e3c6
IR
161 thread_cancel(thr);
162 XFREE(MTYPE_TMP, thr);
d62a17ae 163 list_delete_node(events, ln);
164 ln = nextln;
165 }
56e2c5e8 166}
d6be5fb9
VB
167
168/* AgentX node. */
612c2c15 169static int config_write_agentx(struct vty *vty);
62b346ee 170static struct cmd_node agentx_node = {
f4b8291f 171 .name = "smux",
62b346ee
DL
172 .node = SMUX_NODE,
173 .prompt = "",
612c2c15 174 .config_write = config_write_agentx,
62b346ee 175};
d6be5fb9
VB
176
177/* Logging NetSNMP messages */
d62a17ae 178static int agentx_log_callback(int major, int minor, void *serverarg,
179 void *clientarg)
d6be5fb9 180{
d62a17ae 181 struct snmp_log_message *slm = (struct snmp_log_message *)serverarg;
182 char *msg = XSTRDUP(MTYPE_TMP, slm->msg);
183 if (msg)
184 msg[strlen(msg) - 1] = '\0';
185 switch (slm->priority) {
186 case LOG_EMERG:
1c50c1c0 187 flog_err(EC_LIB_SNMP, "snmp[emerg]: %s", msg ? msg : slm->msg);
d62a17ae 188 break;
189 case LOG_ALERT:
1c50c1c0 190 flog_err(EC_LIB_SNMP, "snmp[alert]: %s", msg ? msg : slm->msg);
d62a17ae 191 break;
192 case LOG_CRIT:
1c50c1c0 193 flog_err(EC_LIB_SNMP, "snmp[crit]: %s", msg ? msg : slm->msg);
d62a17ae 194 break;
195 case LOG_ERR:
1c50c1c0 196 flog_err(EC_LIB_SNMP, "snmp[err]: %s", msg ? msg : slm->msg);
d62a17ae 197 break;
198 case LOG_WARNING:
450971aa 199 flog_warn(EC_LIB_SNMP, "snmp[warning]: %s",
ade6974d 200 msg ? msg : slm->msg);
d62a17ae 201 break;
202 case LOG_NOTICE:
203 zlog_notice("snmp[notice]: %s", msg ? msg : slm->msg);
204 break;
205 case LOG_INFO:
206 zlog_info("snmp[info]: %s", msg ? msg : slm->msg);
207 break;
208 case LOG_DEBUG:
209 zlog_debug("snmp[debug]: %s", msg ? msg : slm->msg);
210 break;
211 }
212 XFREE(MTYPE_TMP, msg);
213 return SNMP_ERR_NOERROR;
d6be5fb9
VB
214}
215
d62a17ae 216static int config_write_agentx(struct vty *vty)
d6be5fb9 217{
d62a17ae 218 if (agentx_enabled)
219 vty_out(vty, "agentx\n");
220 return 1;
d6be5fb9
VB
221}
222
223DEFUN (agentx_enable,
224 agentx_enable_cmd,
225 "agentx",
007b0667 226 "SNMP AgentX protocol settings\n")
d6be5fb9 227{
d62a17ae 228 if (!agentx_enabled) {
229 init_snmp(FRR_SMUX_NAME);
230 events = list_new();
231 agentx_events_update();
232 agentx_enabled = 1;
ec48460e 233 hook_call(agentx_enabled);
d62a17ae 234 }
5fedee18 235
d62a17ae 236 return CMD_SUCCESS;
d6be5fb9
VB
237}
238
239DEFUN (no_agentx,
240 no_agentx_cmd,
241 "no agentx",
242 NO_STR
007b0667 243 "SNMP AgentX protocol settings\n")
d6be5fb9 244{
d62a17ae 245 if (!agentx_enabled)
246 return CMD_SUCCESS;
247 vty_out(vty, "SNMP AgentX support cannot be disabled once enabled\n");
248 return CMD_WARNING_CONFIG_FAILED;
d6be5fb9
VB
249}
250
1ee746d9 251int smux_enabled(void)
252{
253 return agentx_enabled;
254}
255
d62a17ae 256void smux_init(struct thread_master *tm)
d6be5fb9 257{
d62a17ae 258 agentx_tm = tm;
259
260 netsnmp_enable_subagent();
261 snmp_disable_log();
262 snmp_enable_calllog();
263 snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_LOGGING,
264 agentx_log_callback, NULL);
265 init_agent(FRR_SMUX_NAME);
266
612c2c15 267 install_node(&agentx_node);
d62a17ae 268 install_element(CONFIG_NODE, &agentx_enable_cmd);
269 install_element(CONFIG_NODE, &no_agentx_cmd);
d6be5fb9
VB
270}
271
ec48460e
KS
272void smux_agentx_enable(void)
273{
274 if (!agentx_enabled) {
275 init_snmp(FRR_SMUX_NAME);
276 events = list_new();
277 agentx_events_update();
278 agentx_enabled = 1;
279 }
280}
281
d62a17ae 282void smux_register_mib(const char *descr, struct variable *var, size_t width,
283 int num, oid name[], size_t namelen)
d6be5fb9 284{
d62a17ae 285 register_mib(descr, var, width, num, name, namelen);
d6be5fb9
VB
286}
287
97e21b4b
DS
288void smux_trap(struct variable *vp, size_t vp_len, const oid *ename,
289 size_t enamelen, const oid *name, size_t namelen,
290 const oid *iname, size_t inamelen,
291 const struct trap_object *trapobj, size_t trapobjlen,
292 uint8_t sptrap)
4eb8c74f
PR
293{
294 struct index_oid trap_index[1];
295
296 /* copy the single index into the multi-index format */
297 oid_copy(trap_index[0].indexname, iname, inamelen);
298 trap_index[0].indexlen = inamelen;
299
97e21b4b
DS
300 smux_trap_multi_index(vp, vp_len, ename, enamelen, name, namelen,
301 trap_index, array_size(trap_index), trapobj,
302 trapobjlen, sptrap);
4eb8c74f
PR
303}
304
305int smux_trap_multi_index(struct variable *vp, size_t vp_len, const oid *ename,
306 size_t enamelen, const oid *name, size_t namelen,
307 struct index_oid *iname, size_t index_len,
308 const struct trap_object *trapobj, size_t trapobjlen,
309 uint8_t sptrap)
d6be5fb9 310{
d62a17ae 311 oid objid_snmptrap[] = {1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0};
0d6f7fd6 312 size_t objid_snmptrap_len = sizeof(objid_snmptrap) / sizeof(oid);
d62a17ae 313 oid notification_oid[MAX_OID_LEN];
314 size_t notification_oid_len;
315 unsigned int i;
316
317 netsnmp_variable_list *notification_vars = NULL;
318 if (!agentx_enabled)
319 return 0;
320
321 /* snmpTrapOID */
322 oid_copy(notification_oid, ename, enamelen);
323 notification_oid[enamelen] = sptrap;
324 notification_oid_len = enamelen + 1;
325 snmp_varlist_add_variable(&notification_vars, objid_snmptrap,
326 objid_snmptrap_len, ASN_OBJECT_ID,
d7c0a89a 327 (uint8_t *)notification_oid,
d62a17ae 328 notification_oid_len * sizeof(oid));
329
330 /* Provided bindings */
331 for (i = 0; i < trapobjlen; i++) {
332 unsigned int j;
333 oid oid[MAX_OID_LEN];
334 size_t oid_len, onamelen;
d7c0a89a 335 uint8_t *val;
d62a17ae 336 size_t val_len;
337 WriteMethod *wm = NULL;
338 struct variable cvp;
4eb8c74f
PR
339 unsigned int iindex;
340 /*
341 * this allows the behaviour of smux_trap with a singe index
342 * for all objects to be maintained whilst allowing traps which
343 * have different indices per object to be supported
344 */
345 iindex = (index_len == 1) ? 0 : i;
d62a17ae 346
347 /* Make OID. */
348 if (trapobj[i].namelen > 0) {
349 /* Columnar object */
350 onamelen = trapobj[i].namelen;
351 oid_copy(oid, name, namelen);
352 oid_copy(oid + namelen, trapobj[i].name, onamelen);
4eb8c74f
PR
353 oid_copy(oid + namelen + onamelen,
354 iname[iindex].indexname,
355 iname[iindex].indexlen);
356 oid_len = namelen + onamelen + iname[iindex].indexlen;
d62a17ae 357 } else {
358 /* Scalar object */
359 onamelen = trapobj[i].namelen * (-1);
360 oid_copy(oid, name, namelen);
361 oid_copy(oid + namelen, trapobj[i].name, onamelen);
362 oid[onamelen + namelen] = 0;
363 oid_len = namelen + onamelen + 1;
364 }
365
366 /* Locate the appropriate function and type in the MIB registry.
367 */
368 for (j = 0; j < vp_len; j++) {
369 if (oid_compare(trapobj[i].name, onamelen, vp[j].name,
370 vp[j].namelen)
371 != 0)
372 continue;
373 /* We found the appropriate variable in the MIB
374 * registry. */
375 oid_copy(cvp.name, name, namelen);
376 oid_copy(cvp.name + namelen, vp[j].name, vp[j].namelen);
377 cvp.namelen = namelen + vp[j].namelen;
378 cvp.type = vp[j].type;
379 cvp.magic = vp[j].magic;
380 cvp.acl = vp[j].acl;
381 cvp.findVar = vp[j].findVar;
4eb8c74f 382
d62a17ae 383 /* Grab the result. */
384 val = cvp.findVar(&cvp, oid, &oid_len, 1, &val_len,
385 &wm);
386 if (!val)
387 break;
388 snmp_varlist_add_variable(&notification_vars, oid,
389 oid_len, vp[j].type, val,
390 val_len);
391 break;
392 }
b7c0d065 393 }
b7c0d065
VB
394
395
d62a17ae 396 send_v2trap(notification_vars);
397 snmp_free_varbind(notification_vars);
398 agentx_events_update();
399 return 1;
d6be5fb9
VB
400}
401
1ee746d9 402void smux_events_update(void)
403{
404 agentx_events_update();
405}
406
5986b66b 407#endif /* SNMP_AGENTX */