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