/* RIP SNMP support * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #ifdef HAVE_SNMP #include #include #include "if.h" #include "log.h" #include "prefix.h" #include "command.h" #include "table.h" #include "smux.h" #include "ripd/ripd.h" /* RIPv2-MIB. */ #define RIPV2MIB 1,3,6,1,2,1,23 /* RIPv2-MIB rip2Globals values. */ #define RIP2GLOBALROUTECHANGES 1 #define RIP2GLOBALQUERIES 2 /* RIPv2-MIB rip2IfStatEntry. */ #define RIP2IFSTATENTRY 1 /* RIPv2-MIB rip2IfStatTable. */ #define RIP2IFSTATADDRESS 1 #define RIP2IFSTATRCVBADPACKETS 2 #define RIP2IFSTATRCVBADROUTES 3 #define RIP2IFSTATSENTUPDATES 4 #define RIP2IFSTATSTATUS 5 /* RIPv2-MIB rip2IfConfTable. */ #define RIP2IFCONFADDRESS 1 #define RIP2IFCONFDOMAIN 2 #define RIP2IFCONFAUTHTYPE 3 #define RIP2IFCONFAUTHKEY 4 #define RIP2IFCONFSEND 5 #define RIP2IFCONFRECEIVE 6 #define RIP2IFCONFDEFAULTMETRIC 7 #define RIP2IFCONFSTATUS 8 #define RIP2IFCONFSRCADDRESS 9 /* RIPv2-MIB rip2PeerTable. */ #define RIP2PEERADDRESS 1 #define RIP2PEERDOMAIN 2 #define RIP2PEERLASTUPDATE 3 #define RIP2PEERVERSION 4 #define RIP2PEERRCVBADPACKETS 5 #define RIP2PEERRCVBADROUTES 6 /* SNMP value hack. */ #define COUNTER ASN_COUNTER #define INTEGER ASN_INTEGER #define TIMETICKS ASN_TIMETICKS #define IPADDRESS ASN_IPADDRESS #define STRING ASN_OCTET_STR /* Define SNMP local variables. */ SNMP_LOCAL_VARIABLES /* RIP-MIB instances. */ oid rip_oid [] = { RIPV2MIB }; /* Interface cache table sorted by interface's address. */ struct route_table *rip_ifaddr_table; /* Hook functions. */ static u_char *rip2Globals (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *rip2IfStatEntry (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *rip2IfConfAddress (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); static u_char *rip2PeerTable (struct variable *, oid [], size_t *, int, size_t *, WriteMethod **); struct variable rip_variables[] = { /* RIP Global Counters. */ {RIP2GLOBALROUTECHANGES, COUNTER, RONLY, rip2Globals, 2, {1, 1}}, {RIP2GLOBALQUERIES, COUNTER, RONLY, rip2Globals, 2, {1, 2}}, /* RIP Interface Tables. */ {RIP2IFSTATADDRESS, IPADDRESS, RONLY, rip2IfStatEntry, 3, {2, 1, 1}}, {RIP2IFSTATRCVBADPACKETS, COUNTER, RONLY, rip2IfStatEntry, 3, {2, 1, 2}}, {RIP2IFSTATRCVBADROUTES, COUNTER, RONLY, rip2IfStatEntry, 3, {2, 1, 3}}, {RIP2IFSTATSENTUPDATES, COUNTER, RONLY, rip2IfStatEntry, 3, {2, 1, 4}}, {RIP2IFSTATSTATUS, COUNTER, RWRITE, rip2IfStatEntry, 3, {2, 1, 5}}, {RIP2IFCONFADDRESS, IPADDRESS, RONLY, rip2IfConfAddress, /* RIP Interface Configuration Table. */ 3, {3, 1, 1}}, {RIP2IFCONFDOMAIN, STRING, RONLY, rip2IfConfAddress, 3, {3, 1, 2}}, {RIP2IFCONFAUTHTYPE, COUNTER, RONLY, rip2IfConfAddress, 3, {3, 1, 3}}, {RIP2IFCONFAUTHKEY, STRING, RONLY, rip2IfConfAddress, 3, {3, 1, 4}}, {RIP2IFCONFSEND, COUNTER, RONLY, rip2IfConfAddress, 3, {3, 1, 5}}, {RIP2IFCONFRECEIVE, COUNTER, RONLY, rip2IfConfAddress, 3, {3, 1, 6}}, {RIP2IFCONFDEFAULTMETRIC, COUNTER, RONLY, rip2IfConfAddress, 3, {3, 1, 7}}, {RIP2IFCONFSTATUS, COUNTER, RONLY, rip2IfConfAddress, 3, {3, 1, 8}}, {RIP2IFCONFSRCADDRESS, IPADDRESS, RONLY, rip2IfConfAddress, 3, {3, 1, 9}}, {RIP2PEERADDRESS, IPADDRESS, RONLY, rip2PeerTable, /* RIP Peer Table. */ 3, {4, 1, 1}}, {RIP2PEERDOMAIN, STRING, RONLY, rip2PeerTable, 3, {4, 1, 2}}, {RIP2PEERLASTUPDATE, TIMETICKS, RONLY, rip2PeerTable, 3, {4, 1, 3}}, {RIP2PEERVERSION, INTEGER, RONLY, rip2PeerTable, 3, {4, 1, 4}}, {RIP2PEERRCVBADPACKETS, COUNTER, RONLY, rip2PeerTable, 3, {4, 1, 5}}, {RIP2PEERRCVBADROUTES, COUNTER, RONLY, rip2PeerTable, 3, {4, 1, 6}} }; extern struct thread_master *master; static u_char * rip2Globals (struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { if (smux_header_generic(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; /* Retrun global counter. */ switch (v->magic) { case RIP2GLOBALROUTECHANGES: return SNMP_INTEGER (rip_global_route_changes); break; case RIP2GLOBALQUERIES: return SNMP_INTEGER (rip_global_queries); break; default: return NULL; break; } return NULL; } void rip_ifaddr_add (struct interface *ifp, struct connected *ifc) { struct prefix *p; struct route_node *rn; p = ifc->address; if (p->family != AF_INET) return; rn = route_node_get (rip_ifaddr_table, p); rn->info = ifp; } void rip_ifaddr_delete (struct interface *ifp, struct connected *ifc) { struct prefix *p; struct route_node *rn; struct interface *i; p = ifc->address; if (p->family != AF_INET) return; rn = route_node_lookup (rip_ifaddr_table, p); if (! rn) return; i = rn->info; if (rn && !strncmp(i->name,ifp->name,INTERFACE_NAMSIZ)) { rn->info = NULL; route_unlock_node (rn); route_unlock_node (rn); } } static struct interface * rip_ifaddr_lookup_next (struct in_addr *addr) { struct prefix_ipv4 p; struct route_node *rn; struct interface *ifp; p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; p.prefix = *addr; rn = route_node_get (rip_ifaddr_table, (struct prefix *) &p); for (rn = route_next (rn); rn; rn = route_next (rn)) if (rn->info) break; if (rn && rn->info) { ifp = rn->info; *addr = rn->p.u.prefix4; route_unlock_node (rn); return ifp; } return NULL; } static struct interface * rip2IfLookup (struct variable *v, oid name[], size_t *length, struct in_addr *addr, int exact) { int len; struct interface *ifp; if (exact) { /* Check the length. */ if (*length - v->namelen != sizeof (struct in_addr)) return NULL; oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); return if_lookup_exact_address (*addr); } else { len = *length - v->namelen; if (len > 4) len = 4; oid2in_addr (name + v->namelen, len, addr); ifp = rip_ifaddr_lookup_next (addr); if (ifp == NULL) return NULL; oid_copy_addr (name + v->namelen, addr, sizeof (struct in_addr)); *length = v->namelen + sizeof (struct in_addr); return ifp; } return NULL; } static struct rip_peer * rip2PeerLookup (struct variable *v, oid name[], size_t *length, struct in_addr *addr, int exact) { int len; struct rip_peer *peer; if (exact) { /* Check the length. */ if (*length - v->namelen != sizeof (struct in_addr) + 1) return NULL; oid2in_addr (name + v->namelen, sizeof (struct in_addr), addr); peer = rip_peer_lookup (addr); if (peer->domain == name[v->namelen + sizeof (struct in_addr)]) return peer; return NULL; } else { len = *length - v->namelen; if (len > 4) len = 4; oid2in_addr (name + v->namelen, len, addr); len = *length - v->namelen; peer = rip_peer_lookup (addr); if (peer) { if ((len < sizeof (struct in_addr) + 1) || (peer->domain > name[v->namelen + sizeof (struct in_addr)])) { oid_copy_addr (name + v->namelen, &peer->addr, sizeof (struct in_addr)); name[v->namelen + sizeof (struct in_addr)] = peer->domain; *length = sizeof (struct in_addr) + v->namelen + 1; return peer; } } peer = rip_peer_lookup_next (addr); if (! peer) return NULL; oid_copy_addr (name + v->namelen, &peer->addr, sizeof (struct in_addr)); name[v->namelen + sizeof (struct in_addr)] = peer->domain; *length = sizeof (struct in_addr) + v->namelen + 1; return peer; } return NULL; } static u_char * rip2IfStatEntry (struct variable *v, oid name[], size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { struct interface *ifp; struct rip_interface *ri; static struct in_addr addr; static long valid = SNMP_VALID; if (smux_header_table(v, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; memset (&addr, 0, sizeof (struct in_addr)); /* Lookup interface. */ ifp = rip2IfLookup (v, name, length, &addr, exact); if (! ifp) return NULL; /* Fetch rip_interface information. */ ri = ifp->info; switch (v->magic) { case RIP2IFSTATADDRESS: return SNMP_IPADDRESS (addr); break; case RIP2IFSTATRCVBADPACKETS: *var_len = sizeof (long); return (u_char *) &ri->recv_badpackets; case RIP2IFSTATRCVBADROUTES: *var_len = sizeof (long); return (u_char *) &ri->recv_badroutes; case RIP2IFSTATSENTUPDATES: *var_len = sizeof (long); return (u_char *) &ri->sent_updates; case RIP2IFSTATSTATUS: *var_len = sizeof (long); v->type = ASN_INTEGER; return (u_char *) &valid; default: return NULL; } return NULL; } static long rip2IfConfSend (struct rip_interface *ri) { #define doNotSend 1 #define ripVersion1 2 #define rip1Compatible 3 #define ripVersion2 4 #define ripV1Demand 5 #define ripV2Demand 6 if (! ri->running) return doNotSend; if (ri->ri_send & RIPv2) return ripVersion2; else if (ri->ri_send & RIPv1) return ripVersion1; else if (rip) { if (rip->version_send == RIPv2) return ripVersion2; else if (rip->version_send == RIPv1) return ripVersion1; } return doNotSend; } static long rip2IfConfReceive (struct rip_interface *ri) { #define rip1 1 #define rip2 2 #define rip1OrRip2 3 #define doNotReceive 4 int recvv; if (! ri->running) return doNotReceive; recvv = (ri->ri_receive == RI_RIP_UNSPEC) ? rip->version_recv : ri->ri_receive; if (recvv == RI_RIP_VERSION_1_AND_2) return rip1OrRip2; else if (recvv & RIPv2) return rip2; else if (recvv & RIPv1) return rip1; else return doNotReceive; } static u_char * rip2IfConfAddress (struct variable *v, oid name[], size_t *length, int exact, size_t *val_len, WriteMethod **write_method) { static struct in_addr addr; static long valid = SNMP_INVALID; static long domain = 0; static long config = 0; static u_int auth = 0; struct interface *ifp; struct rip_interface *ri; if (smux_header_table(v, name, length, exact, val_len, write_method) == MATCH_FAILED) return NULL; memset (&addr, 0, sizeof (struct in_addr)); /* Lookup interface. */ ifp = rip2IfLookup (v, name, length, &addr, exact); if (! ifp) return NULL; /* Fetch rip_interface information. */ ri = ifp->info; switch (v->magic) { case RIP2IFCONFADDRESS: *val_len = sizeof (struct in_addr); return (u_char *) &addr; case RIP2IFCONFDOMAIN: *val_len = 2; return (u_char *) &domain; case RIP2IFCONFAUTHTYPE: auth = ri->auth_type; *val_len = sizeof (long); v->type = ASN_INTEGER; return (u_char *)&auth; case RIP2IFCONFAUTHKEY: *val_len = 0; return (u_char *) &domain; case RIP2IFCONFSEND: config = rip2IfConfSend (ri); *val_len = sizeof (long); v->type = ASN_INTEGER; return (u_char *) &config; case RIP2IFCONFRECEIVE: config = rip2IfConfReceive (ri); *val_len = sizeof (long); v->type = ASN_INTEGER; return (u_char *) &config; case RIP2IFCONFDEFAULTMETRIC: *val_len = sizeof (long); v->type = ASN_INTEGER; return (u_char *) &ifp->metric; case RIP2IFCONFSTATUS: *val_len = sizeof (long); v->type = ASN_INTEGER; return (u_char *) &valid; case RIP2IFCONFSRCADDRESS: *val_len = sizeof (struct in_addr); return (u_char *) &addr; default: return NULL; } return NULL; } static u_char * rip2PeerTable (struct variable *v, oid name[], size_t *length, int exact, size_t *val_len, WriteMethod **write_method) { static struct in_addr addr; static int domain = 0; static int version; /* static time_t uptime; */ struct rip_peer *peer; if (smux_header_table(v, name, length, exact, val_len, write_method) == MATCH_FAILED) return NULL; memset (&addr, 0, sizeof (struct in_addr)); /* Lookup interface. */ peer = rip2PeerLookup (v, name, length, &addr, exact); if (! peer) return NULL; switch (v->magic) { case RIP2PEERADDRESS: *val_len = sizeof (struct in_addr); return (u_char *) &peer->addr; case RIP2PEERDOMAIN: *val_len = 2; return (u_char *) &domain; case RIP2PEERLASTUPDATE: #if 0 /* We don't know the SNMP agent startup time. We have two choices here: * - assume ripd startup time equals SNMP agent startup time * - don't support this variable, at all * Currently, we do the latter... */ *val_len = sizeof (time_t); uptime = peer->uptime; /* now - snmp_agent_startup - peer->uptime */ return (u_char *) &uptime; #else return (u_char *) NULL; #endif case RIP2PEERVERSION: *val_len = sizeof (int); version = peer->version; return (u_char *) &version; case RIP2PEERRCVBADPACKETS: *val_len = sizeof (int); return (u_char *) &peer->recv_badpackets; case RIP2PEERRCVBADROUTES: *val_len = sizeof (int); return (u_char *) &peer->recv_badroutes; default: return NULL; } return NULL; } /* Register RIPv2-MIB. */ void rip_snmp_init () { rip_ifaddr_table = route_table_init (); smux_init (master); REGISTER_MIB("mibII/rip", rip_variables, variable, rip_oid); } #endif /* HAVE_SNMP */