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