blob: dc2b6212275ef5dad3f052c4db4be05c68942305 [file] [log] [blame]
/* RIP SNMP support
* Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
*
* 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 <zebra.h>
#ifdef HAVE_SNMP
#include <asn1.h>
#include <snmp.h>
#include <snmp_impl.h>
#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
/* Zebra enterprise RIP MIB. This variable is used for register
RIPv2-MIB to SNMP agent under SMUX protocol. */
#define RIPDOID 1,3,6,1,4,1,3317,1,2,3
/* 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 };
oid ripd_oid [] = { RIPDOID };
/* Interface cache table sorted by interface's address. */
struct route_table *rip_ifaddr_table;
/* Hook functions. */
static u_char *rip2Globals ();
static u_char *rip2IfStatEntry ();
static u_char *rip2IfConfAddress ();
static u_char *rip2PeerTable ();
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, INTEGER, 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}}
};
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);
}
}
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;
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 == RIPv2)
return ripVersion2;
else if (rip->version == RIPv1)
return ripVersion1;
}
return doNotSend;
}
static long
rip2IfConfReceive (struct rip_interface *ri)
{
#define rip1 1
#define rip2 2
#define rip1OrRip2 3
#define doNotReceive 4
if (! ri->running)
return doNotReceive;
if (ri->ri_receive == RI_RIP_VERSION_1_AND_2)
return rip1OrRip2;
else if (ri->ri_receive & RIPv2)
return ripVersion2;
else if (ri->ri_receive & RIPv1)
return ripVersion1;
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;
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 version;
/* static time_t uptime; */
struct rip_peer *peer;
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 = sizeof (int);
return (u_char *) &peer->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 (ripd_oid, sizeof (ripd_oid) / sizeof (oid));
REGISTER_MIB("mibII/rip", rip_variables, variable, rip_oid);
smux_start ();
}
#endif /* HAVE_SNMP */