agentx.c 8.5 KB

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