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