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