2 * Copyright (C) 2012 Vincent Bernat <bernat@luffy.cx>
4 * This file is part of GNU Zebra.
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
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.
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
24 #if defined HAVE_SNMP && defined SNMP_AGENTX
25 #include <net-snmp/net-snmp-config.h>
26 #include <net-snmp/net-snmp-includes.h>
27 #include <net-snmp/agent/net-snmp-agent-includes.h>
28 #include <net-snmp/agent/snmp_vars.h>
33 static int agentx_enabled = 0;
35 static struct thread_master *agentx_tm;
36 static struct thread *timeout_thr = NULL;
37 static struct list *events = NULL;
39 static void agentx_events_update(void);
42 agentx_timeout(struct thread *t)
48 netsnmp_check_outstanding_agent_requests ();
49 agentx_events_update ();
54 agentx_read(struct thread *t)
57 struct listnode *ln = THREAD_ARG (t);
58 list_delete_node (events, ln);
61 FD_SET (THREAD_FD (t), &fds);
64 netsnmp_check_outstanding_agent_requests ();
65 agentx_events_update ();
70 agentx_events_update(void)
74 struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 };
80 THREAD_OFF (timeout_thr);
83 snmp_select_info (&maxfd, &fds, &timeout, &block);
86 timeout_thr = thread_add_timer_tv (agentx_tm, agentx_timeout, NULL, &timeout);
88 ln = listhead (events);
89 thr = ln ? listgetdata (ln) : NULL;
90 thr_fd = thr ? THREAD_FD (thr) : -1;
92 /* "two-pointer" / two-list simultaneous iteration
93 * ln/thr/thr_fd point to the next existing event listener to hit while
94 * fd counts to catch up */
95 for (fd = 0; fd < maxfd; fd++)
100 struct listnode *nextln = listnextnode (ln);
101 if (!FD_ISSET (fd, &fds))
104 list_delete_node (events, ln);
107 thr = ln ? listgetdata (ln) : NULL;
108 thr_fd = thr ? THREAD_FD (thr) : -1;
110 /* need listener, but haven't hit one where it would be */
111 else if (FD_ISSET (fd, &fds))
113 struct listnode *newln;
114 thr = thread_add_read (agentx_tm, agentx_read, NULL, fd);
115 newln = listnode_add_before (events, ln, thr);
120 /* leftover event listeners at this point have fd > maxfd, delete them */
123 struct listnode *nextln = listnextnode (ln);
124 thread_cancel (listgetdata (ln));
125 list_delete_node (events, ln);
131 static struct cmd_node agentx_node =
134 "" /* AgentX has no interface. */
137 /* Logging NetSNMP messages */
139 agentx_log_callback(int major, int minor,
140 void *serverarg, void *clientarg)
142 struct snmp_log_message *slm = (struct snmp_log_message *)serverarg;
143 char *msg = strdup (slm->msg);
144 if (msg) msg[strlen(msg)-1] = '\0';
145 switch (slm->priority)
147 case LOG_EMERG: zlog_err ("snmp[emerg]: %s", msg?msg:slm->msg); break;
148 case LOG_ALERT: zlog_err ("snmp[alert]: %s", msg?msg:slm->msg); break;
149 case LOG_CRIT: zlog_err ("snmp[crit]: %s", msg?msg:slm->msg); break;
150 case LOG_ERR: zlog_err ("snmp[err]: %s", msg?msg:slm->msg); break;
151 case LOG_WARNING: zlog_warn ("snmp[warning]: %s", msg?msg:slm->msg); break;
152 case LOG_NOTICE: zlog_notice("snmp[notice]: %s", msg?msg:slm->msg); break;
153 case LOG_INFO: zlog_info ("snmp[info]: %s", msg?msg:slm->msg); break;
154 case LOG_DEBUG: zlog_debug ("snmp[debug]: %s", msg?msg:slm->msg); break;
157 return SNMP_ERR_NOERROR;
161 config_write_agentx (struct vty *vty)
164 vty_out (vty, "agentx%s", VTY_NEWLINE);
168 DEFUN (agentx_enable,
171 "SNMP AgentX protocol settings\n"
172 "SNMP AgentX settings\n")
178 agentx_events_update ();
182 vty_out (vty, "SNMP AgentX already enabled%s", VTY_NEWLINE);
190 "SNMP AgentX protocol settings\n"
191 "SNMP AgentX settings\n")
193 if (!agentx_enabled) return CMD_SUCCESS;
194 vty_out (vty, "SNMP AgentX support cannot be disabled once enabled%s", VTY_NEWLINE);
199 smux_init (struct thread_master *tm)
203 netsnmp_enable_subagent ();
205 snmp_enable_calllog ();
206 snmp_register_callback (SNMP_CALLBACK_LIBRARY,
207 SNMP_CALLBACK_LOGGING,
210 init_agent ("quagga");
212 install_node (&agentx_node, config_write_agentx);
213 install_element (CONFIG_NODE, &agentx_enable_cmd);
214 install_element (CONFIG_NODE, &no_agentx_cmd);
218 smux_register_mib (const char *descr, struct variable *var,
219 size_t width, int num,
220 oid name[], size_t namelen)
222 register_mib (descr, var, width, num, name, namelen);
226 smux_trap (struct variable *vp, size_t vp_len,
227 const oid *ename, size_t enamelen,
228 const oid *name, size_t namelen,
229 const oid *iname, size_t inamelen,
230 const struct trap_object *trapobj, size_t trapobjlen,
233 oid objid_snmptrap[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
234 size_t objid_snmptrap_len = sizeof objid_snmptrap / sizeof (oid);
235 oid notification_oid[MAX_OID_LEN];
236 size_t notification_oid_len;
239 netsnmp_variable_list *notification_vars = NULL;
240 if (!agentx_enabled) return 0;
243 oid_copy (notification_oid, ename, enamelen);
244 notification_oid[enamelen] = sptrap;
245 notification_oid_len = enamelen + 1;
246 snmp_varlist_add_variable (¬ification_vars,
247 objid_snmptrap, objid_snmptrap_len,
249 (u_char *) notification_oid,
250 notification_oid_len * sizeof(oid));
252 /* Provided bindings */
253 for (i = 0; i < trapobjlen; i++)
256 oid oid[MAX_OID_LEN];
257 size_t oid_len, onamelen;
260 WriteMethod *wm = NULL;
264 if (trapobj[i].namelen > 0)
266 /* Columnar object */
267 onamelen = trapobj[i].namelen;
268 oid_copy (oid, name, namelen);
269 oid_copy (oid + namelen, trapobj[i].name, onamelen);
270 oid_copy (oid + namelen + onamelen, iname, inamelen);
271 oid_len = namelen + onamelen + inamelen;
276 onamelen = trapobj[i].namelen * (-1);
277 oid_copy (oid, name, namelen);
278 oid_copy (oid + namelen, trapobj[i].name, onamelen);
279 oid[onamelen + namelen] = 0;
280 oid_len = namelen + onamelen + 1;
283 /* Locate the appropriate function and type in the MIB registry. */
284 for (j = 0; j < vp_len; j++)
286 if (oid_compare (trapobj[i].name, onamelen, vp[j].name, vp[j].namelen) != 0)
288 /* We found the appropriate variable in the MIB registry. */
289 oid_copy(cvp.name, name, namelen);
290 oid_copy(cvp.name + namelen, vp[j].name, vp[j].namelen);
291 cvp.namelen = namelen + vp[j].namelen;
292 cvp.type = vp[j].type;
293 cvp.magic = vp[j].magic;
295 cvp.findVar = vp[j].findVar;
296 /* Grab the result. */
297 val = cvp.findVar (&cvp, oid, &oid_len, 1, &val_len, &wm);
299 snmp_varlist_add_variable (¬ification_vars,
309 send_v2trap (notification_vars);
310 snmp_free_varbind (notification_vars);
311 agentx_events_update ();
315 #endif /* HAVE_SNMP */