1/* RIP SNMP support 2 * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org> 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 HAVE_SNMP 25#include <asn1.h> 26#include <snmp.h> 27#include <snmp_impl.h> 28 29#include "if.h" 30#include "log.h" 31#include "prefix.h" 32#include "command.h" 33#include "table.h" 34#include "smux.h" 35 36#include "ripd/ripd.h" 37 38/* RIPv2-MIB. */ 39#define RIPV2MIB 1,3,6,1,2,1,23 40 41/* Zebra enterprise RIP MIB. This variable is used for register 42 RIPv2-MIB to SNMP agent under SMUX protocol. */ 43#define RIPDOID 1,3,6,1,4,1,3317,1,2,3 44 45/* RIPv2-MIB rip2Globals values. */ 46#define RIP2GLOBALROUTECHANGES 1 47#define RIP2GLOBALQUERIES 2 48 49/* RIPv2-MIB rip2IfStatEntry. */ 50#define RIP2IFSTATENTRY 1 51 52/* RIPv2-MIB rip2IfStatTable. */ 53#define RIP2IFSTATADDRESS 1 54#define RIP2IFSTATRCVBADPACKETS 2 55#define RIP2IFSTATRCVBADROUTES 3 56#define RIP2IFSTATSENTUPDATES 4 57#define RIP2IFSTATSTATUS 5 58 59/* RIPv2-MIB rip2IfConfTable. */ 60#define RIP2IFCONFADDRESS 1 61#define RIP2IFCONFDOMAIN 2 62#define RIP2IFCONFAUTHTYPE 3 63#define RIP2IFCONFAUTHKEY 4 64#define RIP2IFCONFSEND 5 65#define RIP2IFCONFRECEIVE 6 66#define RIP2IFCONFDEFAULTMETRIC 7 67#define RIP2IFCONFSTATUS 8 68#define RIP2IFCONFSRCADDRESS 9 69 70/* RIPv2-MIB rip2PeerTable. */ 71#define RIP2PEERADDRESS 1 72#define RIP2PEERDOMAIN 2 73#define RIP2PEERLASTUPDATE 3 74#define RIP2PEERVERSION 4 75#define RIP2PEERRCVBADPACKETS 5 76#define RIP2PEERRCVBADROUTES 6 77 78/* SNMP value hack. */ 79#define COUNTER ASN_COUNTER 80#define INTEGER ASN_INTEGER 81#define TIMETICKS ASN_TIMETICKS 82#define IPADDRESS ASN_IPADDRESS 83#define STRING ASN_OCTET_STR 84 85/* Define SNMP local variables. */ 86SNMP_LOCAL_VARIABLES 87 88/* RIP-MIB instances. */ 89oid rip_oid [] = { RIPV2MIB }; 90oid ripd_oid [] = { RIPDOID }; 91 92/* Interface cache table sorted by interface's address. */ 93struct route_table *rip_ifaddr_table; 94 95/* Hook functions. */ 96static u_char *rip2Globals (); 97static u_char *rip2IfStatEntry (); 98static u_char *rip2IfConfAddress (); 99static u_char *rip2PeerTable (); 100 101struct variable rip_variables[] = 102{ 103 /* RIP Global Counters. */ 104 {RIP2GLOBALROUTECHANGES, COUNTER, RONLY, rip2Globals, 105 2, {1, 1}}, 106 {RIP2GLOBALQUERIES, COUNTER, RONLY, rip2Globals, 107 2, {1, 2}}, 108 /* RIP Interface Tables. */ 109 {RIP2IFSTATADDRESS, IPADDRESS, RONLY, rip2IfStatEntry, 110 3, {2, 1, 1}}, 111 {RIP2IFSTATRCVBADPACKETS, COUNTER, RONLY, rip2IfStatEntry, 112 3, {2, 1, 2}}, 113 {RIP2IFSTATRCVBADROUTES, COUNTER, RONLY, rip2IfStatEntry, 114 3, {2, 1, 3}}, 115 {RIP2IFSTATSENTUPDATES, COUNTER, RONLY, rip2IfStatEntry, 116 3, {2, 1, 4}}, 117 {RIP2IFSTATSTATUS, COUNTER, RWRITE, rip2IfStatEntry, 118 3, {2, 1, 5}}, 119 {RIP2IFCONFADDRESS, IPADDRESS, RONLY, rip2IfConfAddress, 120 /* RIP Interface Configuration Table. */ 121 3, {3, 1, 1}}, 122 {RIP2IFCONFDOMAIN, STRING, RONLY, rip2IfConfAddress, 123 3, {3, 1, 2}}, 124 {RIP2IFCONFAUTHTYPE, COUNTER, RONLY, rip2IfConfAddress, 125 3, {3, 1, 3}}, 126 {RIP2IFCONFAUTHKEY, STRING, RONLY, rip2IfConfAddress, 127 3, {3, 1, 4}}, 128 {RIP2IFCONFSEND, COUNTER, RONLY, rip2IfConfAddress, 129 3, {3, 1, 5}}, 130 {RIP2IFCONFRECEIVE, COUNTER, RONLY, rip2IfConfAddress, 131 3, {3, 1, 6}}, 132 {RIP2IFCONFDEFAULTMETRIC, COUNTER, RONLY, rip2IfConfAddress, 133 3, {3, 1, 7}}, 134 {RIP2IFCONFSTATUS, COUNTER, RONLY, rip2IfConfAddress, 135 3, {3, 1, 8}}, 136 {RIP2IFCONFSRCADDRESS, IPADDRESS, RONLY, rip2IfConfAddress, 137 3, {3, 1, 9}}, 138 {RIP2PEERADDRESS, IPADDRESS, RONLY, rip2PeerTable, 139 /* RIP Peer Table. */ 140 3, {4, 1, 1}}, 141 {RIP2PEERDOMAIN, INTEGER, RONLY, rip2PeerTable, 142 3, {4, 1, 2}}, 143 {RIP2PEERLASTUPDATE, TIMETICKS, RONLY, rip2PeerTable, 144 3, {4, 1, 3}}, 145 {RIP2PEERVERSION, INTEGER, RONLY, rip2PeerTable, 146 3, {4, 1, 4}}, 147 {RIP2PEERRCVBADPACKETS, COUNTER, RONLY, rip2PeerTable, 148 3, {4, 1, 5}}, 149 {RIP2PEERRCVBADROUTES, COUNTER, RONLY, rip2PeerTable, 150 3, {4, 1, 6}} 151}; 152 153static u_char * 154rip2Globals (struct variable *v, oid name[], size_t *length, 155 int exact, size_t *var_len, WriteMethod **write_method) 156{ 157 if (smux_header_generic(v, name, length, exact, var_len, write_method) 158 == MATCH_FAILED) 159 return NULL; 160 161 /* Retrun global counter. */ 162 switch (v->magic) 163 { 164 case RIP2GLOBALROUTECHANGES: 165 return SNMP_INTEGER (rip_global_route_changes); 166 break; 167 case RIP2GLOBALQUERIES: 168 return SNMP_INTEGER (rip_global_queries); 169 break; 170 default: 171 return NULL; 172 break; 173 } 174 return NULL; 175} 176 177void 178rip_ifaddr_add (struct interface *ifp, struct connected *ifc) 179{ 180 struct prefix *p; 181 struct route_node *rn; 182 183 p = ifc->address; 184 185 if (p->family != AF_INET) 186 return; 187 188 rn = route_node_get (rip_ifaddr_table, p); 189 rn->info = ifp; 190} 191 192void 193rip_ifaddr_delete (struct interface *ifp, struct connected *ifc) 194{ 195 struct prefix *p; 196 struct route_node *rn; 197 struct interface *i; 198 199 p = ifc->address; 200 201 if (p->family != AF_INET) 202 return; 203 204 rn = route_node_lookup (rip_ifaddr_table, p); 205 if (! rn) 206 return; 207 i = rn->info; 208 if (rn && !strncmp(i->name,ifp->name,INTERFACE_NAMSIZ)) 209 { 210 rn->info = NULL; 211 route_unlock_node (rn); 212 route_unlock_node (rn); 213 } 214} 215 216struct interface * 217rip_ifaddr_lookup_next (struct in_addr *addr) 218{ 219 struct prefix_ipv4 p; 220 struct route_node *rn; 221 struct interface *ifp; 222 223 p.family = AF_INET; 224 p.prefixlen = IPV4_MAX_BITLEN; 225 p.prefix = *addr; 226 227 rn = route_node_get (rip_ifaddr_table, (struct prefix *) &p); 228 229 for (rn = route_next (rn); rn; rn = route_next (rn)) 230 if (rn->info) 231 break; 232 233 if (rn && rn->info) 234 { 235 ifp = rn->info; 236 *addr = rn->p.u.prefix4; 237 route_unlock_node (rn); 238 return ifp; 239 } 240 return NULL; 241} 242 243static struct interface * 244rip2IfLookup (struct variable *v, oid name[], size_t *length, 245 struct in_addr *addr, int exact) 246{ 247 int len; 248 struct interface *ifp; 249 250 if (exact) 251 { 252 /* Check the length. */ 253 if (*length - v->namelen != sizeof (struct in_addr)) 254 return NULL; 255 256 oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); 257 258 return if_lookup_exact_address (*addr); 259 } 260 else 261 { 262 len = *length - v->namelen; 263 if (len > 4) len = 4; 264 265 oid2in_addr (name + v->namelen, len, addr); 266 267 ifp = rip_ifaddr_lookup_next (addr); 268 269 if (ifp == NULL) 270 return NULL; 271 272 oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); 273 274 *length = v->namelen + sizeof (struct in_addr); 275 276 return ifp; 277 } 278 return NULL; 279} 280 281static struct rip_peer * 282rip2PeerLookup (struct variable *v, oid name[], size_t *length, 283 struct in_addr *addr, int exact) 284{ 285 int len; 286 struct rip_peer *peer; 287 288 if (exact) 289 { 290 /* Check the length. */ 291 if (*length - v->namelen != sizeof (struct in_addr) + 1) 292 return NULL; 293 294 oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); 295 296 peer = rip_peer_lookup (addr); 297 298 if (peer->domain == name[v->namelen + sizeof (struct in_addr)]) 299 return peer; 300 301 return NULL; 302 } 303 else 304 { 305 len = *length - v->namelen; 306 if (len > 4) len = 4; 307 308 oid2in_addr (name + v->namelen, len, addr); 309 310 len = *length - v->namelen; 311 peer = rip_peer_lookup (addr); 312 if (peer) 313 { 314 if ((len < sizeof (struct in_addr) + 1) || 315 (peer->domain > name[v->namelen + sizeof (struct in_addr)])) 316 { 317 oid_copy_addr (name + v->namelen, &peer->addr, 318 sizeof (struct in_addr)); 319 name[v->namelen + sizeof (struct in_addr)] = peer->domain; 320 *length = sizeof (struct in_addr) + v->namelen + 1; 321 return peer; 322 } 323 } 324 peer = rip_peer_lookup_next (addr); 325 326 if (! peer) 327 return NULL; 328 329 oid_copy_addr (name + v->namelen, &peer->addr, 330 sizeof (struct in_addr)); 331 name[v->namelen + sizeof (struct in_addr)] = peer->domain; 332 *length = sizeof (struct in_addr) + v->namelen + 1; 333 334 return peer; 335 } 336 return NULL; 337} 338 339static u_char * 340rip2IfStatEntry (struct variable *v, oid name[], size_t *length, 341 int exact, size_t *var_len, WriteMethod **write_method) 342{ 343 struct interface *ifp; 344 struct rip_interface *ri; 345 static struct in_addr addr; 346 static long valid = SNMP_VALID; 347 348 memset (&addr, 0, sizeof (struct in_addr)); 349 350 /* Lookup interface. */ 351 ifp = rip2IfLookup (v, name, length, &addr, exact); 352 if (! ifp) 353 return NULL; 354 355 /* Fetch rip_interface information. */ 356 ri = ifp->info; 357 358 switch (v->magic) 359 { 360 case RIP2IFSTATADDRESS: 361 return SNMP_IPADDRESS (addr); 362 break; 363 case RIP2IFSTATRCVBADPACKETS: 364 *var_len = sizeof (long); 365 return (u_char *) &ri->recv_badpackets; 366 367 case RIP2IFSTATRCVBADROUTES: 368 *var_len = sizeof (long); 369 return (u_char *) &ri->recv_badroutes; 370 371 case RIP2IFSTATSENTUPDATES: 372 *var_len = sizeof (long); 373 return (u_char *) &ri->sent_updates; 374 375 case RIP2IFSTATSTATUS: 376 *var_len = sizeof (long); 377 v->type = ASN_INTEGER; 378 return (u_char *) &valid; 379 380 default: 381 return NULL; 382 383 } 384 return NULL; 385} 386 387static long 388rip2IfConfSend (struct rip_interface *ri) 389{ 390#define doNotSend 1 391#define ripVersion1 2 392#define rip1Compatible 3 393#define ripVersion2 4 394#define ripV1Demand 5 395#define ripV2Demand 6 396 397 if (! ri->running) 398 return doNotSend; 399 400 if (ri->ri_send & RIPv2) 401 return ripVersion2; 402 else if (ri->ri_send & RIPv1) 403 return ripVersion1; 404 else if (rip) 405 { 406 if (rip->version == RIPv2) 407 return ripVersion2; 408 else if (rip->version == RIPv1) 409 return ripVersion1; 410 } 411 return doNotSend; 412} 413 414static long 415rip2IfConfReceive (struct rip_interface *ri) 416{ 417#define rip1 1 418#define rip2 2 419#define rip1OrRip2 3 420#define doNotReceive 4 421 422 if (! ri->running) 423 return doNotReceive; 424 425 if (ri->ri_receive == RI_RIP_VERSION_1_AND_2) 426 return rip1OrRip2; 427 else if (ri->ri_receive & RIPv2) 428 return ripVersion2; 429 else if (ri->ri_receive & RIPv1) 430 return ripVersion1; 431 else 432 return doNotReceive; 433} 434 435static u_char * 436rip2IfConfAddress (struct variable *v, oid name[], size_t *length, 437 int exact, size_t *val_len, WriteMethod **write_method) 438{ 439 static struct in_addr addr; 440 static long valid = SNMP_INVALID; 441 static long domain = 0; 442 static long config = 0; 443 static u_int auth = 0; 444 struct interface *ifp; 445 struct rip_interface *ri; 446 447 memset (&addr, 0, sizeof (struct in_addr)); 448 449 /* Lookup interface. */ 450 ifp = rip2IfLookup (v, name, length, &addr, exact); 451 if (! ifp) 452 return NULL; 453 454 /* Fetch rip_interface information. */ 455 ri = ifp->info; 456 457 switch (v->magic) 458 { 459 case RIP2IFCONFADDRESS: 460 *val_len = sizeof (struct in_addr); 461 return (u_char *) &addr; 462 463 case RIP2IFCONFDOMAIN: 464 *val_len = 2; 465 return (u_char *) &domain; 466 467 case RIP2IFCONFAUTHTYPE: 468 auth = ri->auth_type; 469 *val_len = sizeof (long); 470 v->type = ASN_INTEGER; 471 return (u_char *)&auth; 472 473 case RIP2IFCONFAUTHKEY: 474 *val_len = 0; 475 return (u_char *) &domain; 476 case RIP2IFCONFSEND: 477 config = rip2IfConfSend (ri); 478 *val_len = sizeof (long); 479 v->type = ASN_INTEGER; 480 return (u_char *) &config; 481 case RIP2IFCONFRECEIVE: 482 config = rip2IfConfReceive (ri); 483 *val_len = sizeof (long); 484 v->type = ASN_INTEGER; 485 return (u_char *) &config; 486 487 case RIP2IFCONFDEFAULTMETRIC: 488 *val_len = sizeof (long); 489 v->type = ASN_INTEGER; 490 return (u_char *) &ifp->metric; 491 case RIP2IFCONFSTATUS: 492 *val_len = sizeof (long); 493 v->type = ASN_INTEGER; 494 return (u_char *) &valid; 495 case RIP2IFCONFSRCADDRESS: 496 *val_len = sizeof (struct in_addr); 497 return (u_char *) &addr; 498 499 default: 500 return NULL; 501 502 } 503 return NULL; 504} 505 506static u_char * 507rip2PeerTable (struct variable *v, oid name[], size_t *length, 508 int exact, size_t *val_len, WriteMethod **write_method) 509{ 510 static struct in_addr addr; 511 static int version; 512 /* static time_t uptime; */ 513 514 struct rip_peer *peer; 515 516 memset (&addr, 0, sizeof (struct in_addr)); 517 518 /* Lookup interface. */ 519 peer = rip2PeerLookup (v, name, length, &addr, exact); 520 if (! peer) 521 return NULL; 522 523 switch (v->magic) 524 { 525 case RIP2PEERADDRESS: 526 *val_len = sizeof (struct in_addr); 527 return (u_char *) &peer->addr; 528 529 case RIP2PEERDOMAIN: 530 *val_len = sizeof (int); 531 return (u_char *) &peer->domain; 532 533 case RIP2PEERLASTUPDATE: 534#if 0 535 /* We don't know the SNMP agent startup time. We have two choices here: 536 * - assume ripd startup time equals SNMP agent startup time 537 * - don't support this variable, at all 538 * Currently, we do the latter... 539 */ 540 *val_len = sizeof (time_t); 541 uptime = peer->uptime; /* now - snmp_agent_startup - peer->uptime */ 542 return (u_char *) &uptime; 543#else 544 return (u_char *) NULL; 545#endif 546 547 case RIP2PEERVERSION: 548 *val_len = sizeof (int); 549 version = peer->version; 550 return (u_char *) &version; 551 552 case RIP2PEERRCVBADPACKETS: 553 *val_len = sizeof (int); 554 return (u_char *) &peer->recv_badpackets; 555 556 case RIP2PEERRCVBADROUTES: 557 *val_len = sizeof (int); 558 return (u_char *) &peer->recv_badroutes; 559 560 default: 561 return NULL; 562 563 } 564 return NULL; 565} 566 567/* Register RIPv2-MIB. */ 568void 569rip_snmp_init () 570{ 571 rip_ifaddr_table = route_table_init (); 572 573 smux_init (ripd_oid, sizeof (ripd_oid) / sizeof (oid)); 574 REGISTER_MIB("mibII/rip", rip_variables, variable, rip_oid); 575 smux_start (); 576} 577#endif /* HAVE_SNMP */ 578