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