]> git.proxmox.com Git - mirror_frr.git/blob - lib/agentx.c
*: reindent
[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 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 agentx_read(struct thread *t)
56 {
57 fd_set fds;
58 struct listnode *ln = THREAD_ARG(t);
59 list_delete_node(events, ln);
60
61 FD_ZERO(&fds);
62 FD_SET(THREAD_FD(t), &fds);
63 snmp_read(&fds);
64
65 netsnmp_check_outstanding_agent_requests();
66 agentx_events_update();
67 return 0;
68 }
69
70 static void agentx_events_update(void)
71 {
72 int maxfd = 0;
73 int block = 1;
74 struct timeval timeout = {.tv_sec = 0, .tv_usec = 0};
75 fd_set fds;
76 struct listnode *ln;
77 struct thread *thr;
78 int fd, thr_fd;
79
80 THREAD_OFF(timeout_thr);
81
82 FD_ZERO(&fds);
83 snmp_select_info(&maxfd, &fds, &timeout, &block);
84
85 if (!block)
86 timeout_thr = thread_add_timer_tv(agentx_tm, agentx_timeout,
87 NULL, &timeout);
88
89 ln = listhead(events);
90 thr = ln ? listgetdata(ln) : NULL;
91 thr_fd = thr ? THREAD_FD(thr) : -1;
92
93 /* "two-pointer" / two-list simultaneous iteration
94 * ln/thr/thr_fd point to the next existing event listener to hit while
95 * fd counts to catch up */
96 for (fd = 0; fd < maxfd; fd++) {
97 /* caught up */
98 if (thr_fd == fd) {
99 struct listnode *nextln = listnextnode(ln);
100 if (!FD_ISSET(fd, &fds)) {
101 thread_cancel(thr);
102 list_delete_node(events, ln);
103 }
104 ln = nextln;
105 thr = ln ? listgetdata(ln) : NULL;
106 thr_fd = thr ? THREAD_FD(thr) : -1;
107 }
108 /* need listener, but haven't hit one where it would be */
109 else if (FD_ISSET(fd, &fds)) {
110 struct listnode *newln;
111 thr = thread_add_read(agentx_tm, agentx_read, NULL, fd);
112 newln = listnode_add_before(events, ln, thr);
113 thr->arg = newln;
114 }
115 }
116
117 /* leftover event listeners at this point have fd > maxfd, delete them
118 */
119 while (ln) {
120 struct listnode *nextln = listnextnode(ln);
121 thread_cancel(listgetdata(ln));
122 list_delete_node(events, ln);
123 ln = nextln;
124 }
125 }
126
127 /* AgentX node. */
128 static struct cmd_node agentx_node = {
129 SMUX_NODE, "" /* AgentX has no interface. */
130 };
131
132 /* Logging NetSNMP messages */
133 static int agentx_log_callback(int major, int minor, void *serverarg,
134 void *clientarg)
135 {
136 struct snmp_log_message *slm = (struct snmp_log_message *)serverarg;
137 char *msg = XSTRDUP(MTYPE_TMP, slm->msg);
138 if (msg)
139 msg[strlen(msg) - 1] = '\0';
140 switch (slm->priority) {
141 case LOG_EMERG:
142 zlog_err("snmp[emerg]: %s", msg ? msg : slm->msg);
143 break;
144 case LOG_ALERT:
145 zlog_err("snmp[alert]: %s", msg ? msg : slm->msg);
146 break;
147 case LOG_CRIT:
148 zlog_err("snmp[crit]: %s", msg ? msg : slm->msg);
149 break;
150 case LOG_ERR:
151 zlog_err("snmp[err]: %s", msg ? msg : slm->msg);
152 break;
153 case LOG_WARNING:
154 zlog_warn("snmp[warning]: %s", msg ? msg : slm->msg);
155 break;
156 case LOG_NOTICE:
157 zlog_notice("snmp[notice]: %s", msg ? msg : slm->msg);
158 break;
159 case LOG_INFO:
160 zlog_info("snmp[info]: %s", msg ? msg : slm->msg);
161 break;
162 case LOG_DEBUG:
163 zlog_debug("snmp[debug]: %s", msg ? msg : slm->msg);
164 break;
165 }
166 XFREE(MTYPE_TMP, msg);
167 return SNMP_ERR_NOERROR;
168 }
169
170 static int config_write_agentx(struct vty *vty)
171 {
172 if (agentx_enabled)
173 vty_out(vty, "agentx%s", VTY_NEWLINE);
174 return 0;
175 }
176
177 DEFUN (agentx_enable,
178 agentx_enable_cmd,
179 "agentx",
180 "SNMP AgentX protocol settings\n"
181 "SNMP AgentX settings\n")
182 {
183 if (!agentx_enabled) {
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_WARNING;
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)
202 return CMD_SUCCESS;
203 vty_out(vty, "SNMP AgentX support cannot be disabled once enabled%s",
204 VTY_NEWLINE);
205 return CMD_WARNING;
206 }
207
208 void smux_init(struct thread_master *tm)
209 {
210 agentx_tm = tm;
211
212 netsnmp_enable_subagent();
213 snmp_disable_log();
214 snmp_enable_calllog();
215 snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_LOGGING,
216 agentx_log_callback, 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 smux_register_mib(const char *descr, struct variable *var, size_t width,
225 int num, oid name[], size_t namelen)
226 {
227 register_mib(descr, var, width, num, name, namelen);
228 }
229
230 int smux_trap(struct variable *vp, size_t vp_len, const oid *ename,
231 size_t enamelen, const oid *name, size_t namelen,
232 const oid *iname, size_t inamelen,
233 const struct trap_object *trapobj, size_t trapobjlen,
234 u_char sptrap)
235 {
236 oid objid_snmptrap[] = {1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0};
237 size_t objid_snmptrap_len = sizeof objid_snmptrap / sizeof(oid);
238 oid notification_oid[MAX_OID_LEN];
239 size_t notification_oid_len;
240 unsigned int i;
241
242 netsnmp_variable_list *notification_vars = NULL;
243 if (!agentx_enabled)
244 return 0;
245
246 /* snmpTrapOID */
247 oid_copy(notification_oid, ename, enamelen);
248 notification_oid[enamelen] = sptrap;
249 notification_oid_len = enamelen + 1;
250 snmp_varlist_add_variable(&notification_vars, objid_snmptrap,
251 objid_snmptrap_len, ASN_OBJECT_ID,
252 (u_char *)notification_oid,
253 notification_oid_len * sizeof(oid));
254
255 /* Provided bindings */
256 for (i = 0; i < trapobjlen; i++) {
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 /* Columnar object */
268 onamelen = trapobj[i].namelen;
269 oid_copy(oid, name, namelen);
270 oid_copy(oid + namelen, trapobj[i].name, onamelen);
271 oid_copy(oid + namelen + onamelen, iname, inamelen);
272 oid_len = namelen + onamelen + inamelen;
273 } else {
274 /* Scalar object */
275 onamelen = trapobj[i].namelen * (-1);
276 oid_copy(oid, name, namelen);
277 oid_copy(oid + namelen, trapobj[i].name, onamelen);
278 oid[onamelen + namelen] = 0;
279 oid_len = namelen + onamelen + 1;
280 }
281
282 /* Locate the appropriate function and type in the MIB registry.
283 */
284 for (j = 0; j < vp_len; j++) {
285 if (oid_compare(trapobj[i].name, onamelen, vp[j].name,
286 vp[j].namelen)
287 != 0)
288 continue;
289 /* We found the appropriate variable in the MIB
290 * 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,
300 &wm);
301 if (!val)
302 break;
303 snmp_varlist_add_variable(&notification_vars, oid,
304 oid_len, vp[j].type, 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 /* SNMP_AGENTX */