File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / ripd / rip_snmp.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:12 2012 UTC (12 years, 4 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_21, v0_99_20_1, v0_99_20, HEAD
quagga

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>