/* BGP4 SNMP support
Copyright (C) 1999, 2000 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 <zebra.h>
#ifdef HAVE_SNMP
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include "if.h"
#include "log.h"
#include "prefix.h"
#include "command.h"
#include "thread.h"
#include "smux.h"
#include "filter.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_snmp.h"
/* BGP4-MIB described in RFC1657. */
#define BGP4MIB 1,3,6,1,2,1,15
/* BGP TRAP. */
#define BGPESTABLISHED 1
#define BGPBACKWARDTRANSITION 2
/* BGP MIB bgpVersion. */
#define BGPVERSION 0
/* BGP MIB bgpLocalAs. */
#define BGPLOCALAS 0
/* BGP MIB bgpPeerTable. */
#define BGPPEERIDENTIFIER 1
#define BGPPEERSTATE 2
#define BGPPEERADMINSTATUS 3
#define BGPPEERNEGOTIATEDVERSION 4
#define BGPPEERLOCALADDR 5
#define BGPPEERLOCALPORT 6
#define BGPPEERREMOTEADDR 7
#define BGPPEERREMOTEPORT 8
#define BGPPEERREMOTEAS 9
#define BGPPEERINUPDATES 10
#define BGPPEEROUTUPDATES 11
#define BGPPEERINTOTALMESSAGES 12
#define BGPPEEROUTTOTALMESSAGES 13
#define BGPPEERLASTERROR 14
#define BGPPEERFSMESTABLISHEDTRANSITIONS 15
#define BGPPEERFSMESTABLISHEDTIME 16
#define BGPPEERCONNECTRETRYINTERVAL 17
#define BGPPEERHOLDTIME 18
#define BGPPEERKEEPALIVE 19
#define BGPPEERHOLDTIMECONFIGURED 20
#define BGPPEERKEEPALIVECONFIGURED 21
#define BGPPEERMINROUTEADVERTISEMENTINTERVAL 22
#define BGPPEERINUPDATEELAPSEDTIME 23
/* BGP MIB bgpIdentifier. */
#define BGPIDENTIFIER 0
/* BGP MIB bgpRcvdPathAttrTable */
#define BGPPATHATTRPEER 1
#define BGPPATHATTRDESTNETWORK 2
#define BGPPATHATTRORIGIN 3
#define BGPPATHATTRASPATH 4
#define BGPPATHATTRNEXTHOP 5
#define BGPPATHATTRINTERASMETRIC 6
/* BGP MIB bgp4PathAttrTable. */
#define BGP4PATHATTRPEER 1
#define BGP4PATHATTRIPADDRPREFIXLEN 2
#define BGP4PATHATTRIPADDRPREFIX 3
#define BGP4PATHATTRORIGIN 4
#define BGP4PATHATTRASPATHSEGMENT 5
#define BGP4PATHATTRNEXTHOP 6
#define BGP4PATHATTRMULTIEXITDISC 7
#define BGP4PATHATTRLOCALPREF 8
#define BGP4PATHATTRATOMICAGGREGATE 9
#define BGP4PATHATTRAGGREGATORAS 10
#define BGP4PATHATTRAGGREGATORADDR 11
#define BGP4PATHATTRCALCLOCALPREF 12
#define BGP4PATHATTRBEST 13
#define BGP4PATHATTRUNKNOWN 14
/* SNMP value hack. */
#define INTEGER ASN_INTEGER
#define INTEGER32 ASN_INTEGER
#define COUNTER32 ASN_COUNTER
#define OCTET_STRING ASN_OCTET_STR
#define IPADDRESS ASN_IPADDRESS
#define GAUGE32 ASN_UNSIGNED
/* Declare static local variables for convenience. */
SNMP_LOCAL_VARIABLES
/* BGP-MIB instances. */
oid bgp_oid [] = { BGP4MIB };
oid bgp_trap_oid [] = { BGP4MIB, 0 };
/* IP address 0.0.0.0. */
static struct in_addr bgp_empty_addr = { .s_addr = 0 };
/* Hook functions. */
static u_char *bgpVersion (struct variable *, oid [], size_t *, int,
size_t *, WriteMethod **);
static u_char *bgpLocalAs (struct variable *, oid [], size_t *,
int, size_t *, WriteMethod **);
static u_char *bgpPeerTable (struct variable *, oid [], size_t *,
int, size_t *, WriteMethod **);
static u_char *bgpRcvdPathAttrTable (struct variable *, oid [], size_t *,
int, size_t *, WriteMethod **);
static u_char *bgpIdentifier (struct variable *, oid [], size_t *,
int, size_t *, WriteMethod **);
static u_char *bgp4PathAttrTable (struct variable *, oid [], size_t *,
int, size_t *, WriteMethod **);
/* static u_char *bgpTraps (); */
struct variable bgp_variables[] =
{
/* BGP version. */
{BGPVERSION, OCTET_STRING, RONLY, bgpVersion,
1, {1}},
/* BGP local AS. */
{BGPLOCALAS, INTEGER, RONLY, bgpLocalAs,
1, {2}},
/* BGP peer table. */
{BGPPEERIDENTIFIER, IPADDRESS, RONLY, bgpPeerTable,
3, {3, 1, 1}},
{BGPPEERSTATE, INTEGER, RONLY, bgpPeerTable,
3, {3, 1, 2}},
{BGPPEERADMINSTATUS, INTEGER, RWRITE, bgpPeerTable,
3, {3, 1, 3}},
{BGPPEERNEGOTIATEDVERSION, INTEGER32, RONLY, bgpPeerTable,
3, {3, 1, 4}},
{BGPPEERLOCALADDR, IPADDRESS, RONLY, bgpPeerTable,
3, {3, 1, 5}},
{BGPPEERLOCALPORT, INTEGER, RONLY, bgpPeerTable,
3, {3, 1, 6}},
{BGPPEERREMOTEADDR, IPADDRESS, RONLY, bgpPeerTable,
3, {3, 1, 7}},
{BGPPEERREMOTEPORT, INTEGER, RONLY, bgpPeerTable,
3, {3, 1, 8}},
{BGPPEERREMOTEAS, INTEGER, RONLY, bgpPeerTable,
3, {3, 1, 9}},
{BGPPEERINUPDATES, COUNTER32, RONLY, bgpPeerTable,
3, {3, 1, 10}},
{BGPPEEROUTUPDATES, COUNTER32, RONLY, bgpPeerTable,
3, {3, 1, 11}},
{BGPPEERINTOTALMESSAGES, COUNTER32, RONLY, bgpPeerTable,
3, {3, 1, 12}},
{BGPPEEROUTTOTALMESSAGES, COUNTER32, RONLY, bgpPeerTable,
3, {3, 1, 13}},
{BGPPEERLASTERROR, OCTET_STRING, RONLY, bgpPeerTable,
3, {3, 1, 14}},
{BGPPEERFSMESTABLISHEDTRANSITIONS, COUNTER32, RONLY, bgpPeerTable,
3, {3, 1, 15}},
{BGPPEERFSMESTABLISHEDTIME, GAUGE32, RONLY, bgpPeerTable,
3, {3, 1, 16}},
{BGPPEERCONNECTRETRYINTERVAL, INTEGER, RWRITE, bgpPeerTable,
3, {3, 1, 17}},
{BGPPEERHOLDTIME, INTEGER, RONLY, bgpPeerTable,
3, {3, 1, 18}},
{BGPPEERKEEPALIVE, INTEGER, RONLY, bgpPeerTable,
3, {3, 1, 19}},
{BGPPEERHOLDTIMECONFIGURED, INTEGER, RWRITE, bgpPeerTable,
3, {3, 1, 20}},
{BGPPEERKEEPALIVECONFIGURED, INTEGER, RWRITE, bgpPeerTable,
3, {3, 1, 21}},
{BGPPEERMINROUTEADVERTISEMENTINTERVAL, INTEGER, RWRITE, bgpPeerTable,
3, {3, 1, 23}},
{BGPPEERINUPDATEELAPSEDTIME, GAUGE32, RONLY, bgpPeerTable,
3, {3, 1, 24}},
/* BGP identifier. */
{BGPIDENTIFIER, IPADDRESS, RONLY, bgpIdentifier,
1, {4}},
/* BGP received path attribute table. */
{BGPPATHATTRPEER, IPADDRESS, RONLY, bgpRcvdPathAttrTable,
3, {5, 1, 1}},
{BGPPATHATTRDESTNETWORK, IPADDRESS, RONLY, bgpRcvdPathAttrTable,
3, {5, 1, 2}},
{BGPPATHATTRORIGIN, INTEGER, RONLY, bgpRcvdPathAttrTable,
3, {5, 1, 3}},
{BGPPATHATTRASPATH, OCTET_STRING, RONLY, bgpRcvdPathAttrTable,
3, {5, 1, 4}},
{BGPPATHATTRNEXTHOP, IPADDRESS, RONLY, bgpRcvdPathAttrTable,
3, {5, 1, 5}},
{BGPPATHATTRINTERASMETRIC, INTEGER32, RONLY, bgpRcvdPathAttrTable,
3, {5, 1, 6}},
/* BGP-4 received path attribute table. */
{BGP4PATHATTRPEER, IPADDRESS, RONLY, bgp4PathAttrTable,
3, {6, 1, 1}},
{BGP4PATHATTRIPADDRPREFIXLEN, INTEGER, RONLY, bgp4PathAttrTable,
3, {6, 1, 2}},
{BGP4PATHATTRIPADDRPREFIX, IPADDRESS, RONLY, bgp4PathAttrTable,
3, {6, 1, 3}},
{BGP4PATHATTRORIGIN, INTEGER, RONLY, bgp4PathAttrTable,
3, {6, 1, 4}},
{BGP4PATHATTRASPATHSEGMENT, OCTET_STRING, RONLY, bgp4PathAttrTable,
3, {6, 1, 5}},
{BGP4PATHATTRNEXTHOP, IPADDRESS, RONLY, bgp4PathAttrTable,
3, {6, 1, 6}},
{BGP4PATHATTRMULTIEXITDISC, INTEGER, RONLY, bgp4PathAttrTable,
3, {6, 1, 7}},
{BGP4PATHATTRLOCALPREF, INTEGER, RONLY, bgp4PathAttrTable,
3, {6, 1, 8}},
{BGP4PATHATTRATOMICAGGREGATE, INTEGER, RONLY, bgp4PathAttrTable,
3, {6, 1, 9}},
{BGP4PATHATTRAGGREGATORAS, INTEGER, RONLY, bgp4PathAttrTable,
3, {6, 1, 10}},
{BGP4PATHATTRAGGREGATORADDR, IPADDRESS, RONLY, bgp4PathAttrTable,
3, {6, 1, 11}},
{BGP4PATHATTRCALCLOCALPREF, INTEGER, RONLY, bgp4PathAttrTable,
3, {6, 1, 12}},
{BGP4PATHATTRBEST, INTEGER, RONLY, bgp4PathAttrTable,
3, {6, 1, 13}},
{BGP4PATHATTRUNKNOWN, OCTET_STRING, RONLY, bgp4PathAttrTable,
3, {6, 1, 14}},
};
static u_char *
bgpVersion (struct variable *v, oid name[], size_t *length, int exact,
size_t *var_len, WriteMethod **write_method)
{
static u_char version;
if (smux_header_generic(v, name, length, exact, var_len, write_method)
== MATCH_FAILED)
return NULL;
/* Retrun BGP version. Zebra bgpd only support version 4. */
version = (0x80 >> (BGP_VERSION_4 - 1));
/* Return octet string length 1. */
*var_len = 1;
return (u_char *)&version;
}
static u_char *
bgpLocalAs (struct variable *v, oid name[], size_t *length,
int exact, size_t *var_len, WriteMethod **write_method)
{
struct bgp *bgp;
if (smux_header_generic(v, name, length, exact, var_len, write_method)
== MATCH_FAILED)
return NULL;
/* Get BGP structure. */
bgp = bgp_get_default ();
if (! bgp)
return NULL;
return SNMP_INTEGER (bgp->as);
}
static struct peer *
peer_lookup_addr_ipv4 (struct in_addr *src)
{
struct bgp *bgp;
struct peer *peer;
struct listnode *node;
struct in_addr addr;
int ret;
bgp = bgp_get_default ();
if (! bgp)
return NULL;
for (ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
{
ret = inet_pton (AF_INET, peer->host, &addr);
if (ret > 0)
{
if (IPV4_ADDR_SAME (&addr, src))
return peer;
}
}
return NULL;
}
static struct peer *
bgp_peer_lookup_next (struct in_addr *src)
{
struct bgp *bgp;
struct peer *peer;
struct listnode *node;
struct in_addr *p;
union sockunion su;
int ret;
memset (&su, 0, sizeof (union sockunion));
bgp = bgp_get_default ();
if (! bgp)
return NULL;
for (ALL_LIST_ELEMENTS_RO (bgp->peer, node, peer))
{
ret = inet_pton (AF_INET, peer->host, &su.sin.sin_addr);
if (ret > 0)
{
p = &su.sin.sin_addr;
if (ntohl (p->s_addr) > ntohl (src->s_addr))
{
src->s_addr = p->s_addr;
return peer;
}
}
}
return NULL;
}
/* 1.3.6.1.2.1.15.3.1.x = 10 */
#define PEERTAB_NAMELEN 10
static struct peer *
bgpPeerTable_lookup (struct variable *v, oid name[], size_t *length,
struct in_addr *addr, int exact)
{
struct peer *peer = NULL;
size_t namelen = v ? v->namelen : PEERTAB_NAMELEN;
int len;
if (exact)
{
/* Check the length. */
if (*length - namelen != sizeof (struct in_addr))
return NULL;
oid2in_addr (name + namelen, IN_ADDR_SIZE, addr);
peer = peer_lookup_addr_ipv4 (addr);
return peer;
}
else
{
len = *length - namelen;
if (len > 4) len = 4;
oid2in_addr (name + namelen, len, addr);
peer = bgp_peer_lookup_next (addr);
if (peer == NULL)
return NULL;
oid_copy_addr (name + namelen, addr, sizeof (struct in_addr));
*length = sizeof (struct in_addr) + namelen;
return peer;
}
return NULL;
}
/* BGP write methods. */
static int
write_bgpPeerTable (int action, u_char *var_val,
u_char var_val_type, size_t var_val_len,
u_char *statP, oid *name, size_t length)
{
struct in_addr addr;
struct peer *peer;
long intval;
if (var_val_type != ASN_INTEGER)
{
return SNMP_ERR_WRONGTYPE;
}
if (var_val_len != sizeof (long))
{
return SNMP_ERR_WRONGLENGTH;
}
intval = *(long *)var_val;
memset (&addr, 0, sizeof (struct in_addr));
peer = bgpPeerTable_lookup (NULL, name, &length, &addr, 1);
if (! peer)
return SNMP_ERR_NOSUCHNAME;
if (action != SNMP_MSG_INTERNAL_SET_COMMIT)
return SNMP_ERR_NOERROR;
zlog_info ("%s: SNMP write .%ld = %ld",
peer->host, (long)name[PEERTAB_NAMELEN - 1], intval);
switch (name[PEERTAB_NAMELEN - 1])
{
case BGPPEERADMINSTATUS:
#define BGP_PeerAdmin_stop 1
#define BGP_PeerAdmin_start 2
/* When the peer is established, */
if (intval == BGP_PeerAdmin_stop)
BGP_EVENT_ADD (peer, BGP_Stop);
else if (intval == BGP_PeerAdmin_start)
; /* Do nothing. */
else
return SNMP_ERR_NOSUCHNAME;
break;
case BGPPEERCONNECTRETRYINTERVAL:
SET_FLAG (peer->config, PEER_CONFIG_CONNECT);
peer->connect = intval;
peer->v_connect = intval;
break;
case BGPPEERHOLDTIMECONFIGURED:
SET_FLAG (peer->config, PEER_CONFIG_TIMER);
peer->holdtime = intval;
peer->v_holdtime = intval;
break;
case BGPPEERKEEPALIVECONFIGURED:
SET_FLAG (peer->config, PEER_CONFIG_TIMER);
peer->keepalive = intval;
peer->v_keepalive = intval;
break;
case BGPPEERMINROUTEADVERTISEMENTINTERVAL:
peer->v_routeadv = intval;
break;
}
return SNMP_ERR_NOERROR;
}
static u_char *
bgpPeerTable (struct variable *v, oid name[], size_t *length,
int exact, size_t *var_len, WriteMethod **write_method)
{
static struct in_addr addr;
struct peer *peer;
if (smux_header_table(v, name, length, exact, var_len, write_method)
== MATCH_FAILED)
return NULL;
memset (&addr, 0, sizeof (struct in_addr));
peer = bgpPeerTable_lookup (v, name, length, &addr, exact);
if (! peer)
return NULL;
switch (v->magic)
{
case BGPPEERIDENTIFIER:
return SNMP_IPADDRESS (peer->remote_id);
break;
case BGPPEERSTATE:
return SNMP_INTEGER (peer->status);
break;
case BGPPEERADMINSTATUS:
*write_method = write_bgpPeerTable;
#define BGP_PeerAdmin_stop 1
#define BGP_PeerAdmin_start 2
if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN))
return SNMP_INTEGER (BGP_PeerAdmin_stop);
else
return SNMP_INTEGER (BGP_PeerAdmin_start);
break;
case BGPPEERNEGOTIATEDVERSION:
return SNMP_INTEGER (BGP_VERSION_4);
break;
case BGPPEERLOCALADDR:
if (peer->su_local)
return SNMP_IPADDRESS (peer->su_local->sin.sin_addr);
else
return SNMP_IPADDRESS (bgp_empty_addr);
break;
case BGPPEERLOCALPORT:
if (peer->su_local)
return SNMP_INTEGER (ntohs (peer->su_local->sin.sin_port));
else
return SNMP_INTEGER (0);
break;
case BGPPEERREMOTEADDR:
if (peer->su_remote)
return SNMP_IPADDRESS (peer->su_remote->sin.sin_addr);
else
return SNMP_IPADDRESS (bgp_empty_addr);
break;
case BGPPEERREMOTEPORT:
if (peer->su_remote)
return SNMP_INTEGER (ntohs (peer->su_remote->sin.sin_port));
else
return SNMP_INTEGER (0);
break;
case BGPPEERREMOTEAS:
return SNMP_INTEGER (peer->as);
break;
case BGPPEERINUPDATES:
return SNMP_INTEGER (peer->update_in);
break;
case BGPPEEROUTUPDATES:
return SNMP_INTEGER (peer->update_out);
break;
case BGPPEERINTOTALMESSAGES:
return SNMP_INTEGER (peer->open_in + peer->update_in
+ peer->keepalive_in + peer->notify_in
+ peer->refresh_in + peer->dynamic_cap_in);
break;
case BGPPEEROUTTOTALMESSAGES:
return SNMP_INTEGER (peer->open_out + peer->update_out
+ peer->keepalive_out + peer->notify_out
+ peer->refresh_out + peer->dynamic_cap_out);
break;
case BGPPEERLASTERROR:
{
static u_char lasterror[2];
lasterror[0] = peer->notify.code;
lasterror[1] = peer->notify.subcode;
*var_len = 2;
return (u_char *)&lasterror;
}
break;
case BGPPEERFSMESTABLISHEDTRANSITIONS:
return SNMP_INTEGER (peer->established);
break;
case BGPPEERFSMESTABLISHEDTIME:
if (peer->uptime == 0)
return SNMP_INTEGER (0);
else
return SNMP_INTEGER (bgp_clock () - peer->uptime);
break;
case BGPPEERCONNECTRETRYINTERVAL:
*write_method = write_bgpPeerTable;
return SNMP_INTEGER (peer->v_connect);
break;
case BGPPEERHOLDTIME:
return SNMP_INTEGER (peer->v_holdtime);
break;
case BGPPEERKEEPALIVE:
return SNMP_INTEGER (peer->v_keepalive);
break;
case BGPPEERHOLDTIMECONFIGURED:
*write_method = write_bgpPeerTable;
if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
return SNMP_INTEGER (peer->holdtime);
else
return SNMP_INTEGER (peer->v_holdtime);
break;
case BGPPEERKEEPALIVECONFIGURED:
*write_method = write_bgpPeerTable;
if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER))
return SNMP_INTEGER (peer->keepalive);
else
return SNMP_INTEGER (peer->v_keepalive);
break;
case BGPPEERMINROUTEADVERTISEMENTINTERVAL:
*write_method = write_bgpPeerTable;
return SNMP_INTEGER (peer->v_routeadv);
break;
case BGPPEERINUPDATEELAPSEDTIME:
if (peer->update_time == 0)
return SNMP_INTEGER (0);
else
return SNMP_INTEGER (bgp_clock () - peer->update_time);
break;
default:
return NULL;
break;
}
return NULL;
}
static u_char *
bgpIdentifier (struct variable *v, oid name[], size_t *length,
int exact, size_t *var_len, WriteMethod **write_method)
{
struct bgp *bgp;
if (smux_header_generic(v, name, length, exact, var_len, write_method)
== MATCH_FAILED)
return NULL;
bgp = bgp_get_default ();
if (!bgp)
return NULL;
return SNMP_IPADDRESS (bgp->router_id);
}
static u_char *
bgpRcvdPathAttrTable (struct variable *v, oid name[], size_t *length,
int exact, size_t *var_len, WriteMethod **write_method)
{
/* Received Path Attribute Table. This table contains, one entry
per path to a network, path attributes received from all peers
running BGP version 3 or less. This table is obsolete, having
been replaced in functionality with the bgp4PathAttrTable. */
return NULL;
}
static struct bgp_info *
bgp4PathAttrLookup (struct variable *v, oid name[], size_t *length,
struct bgp *bgp, struct prefix_ipv4 *addr, int exact)
{
oid *offset;
int offsetlen;
struct bgp_info *binfo;
struct bgp_info *min;
struct bgp_node *rn;
union sockunion su;
unsigned int len;
struct in_addr paddr;
#define BGP_PATHATTR_ENTRY_OFFSET \
(IN_ADDR_SIZE + 1 + IN_ADDR_SIZE)
if (exact)
{
if (*length - v->namelen != BGP_PATHATTR_ENTRY_OFFSET)
return NULL;
/* Set OID offset for prefix. */
offset = name + v->namelen;
oid2in_addr (offset, IN_ADDR_SIZE, &addr->prefix);
offset += IN_ADDR_SIZE;
/* Prefix length. */
addr->prefixlen = *offset;
offset++;
/* Peer address. */
su.sin.sin_family = AF_INET;
oid2in_addr (offset, IN_ADDR_SIZE, &su.sin.sin_addr);
/* Lookup node. */
rn = bgp_node_lookup (bgp->rib[AFI_IP][SAFI_UNICAST],
(struct prefix *) addr);
if (rn)
{
bgp_unlock_node (rn);
for (binfo = rn->info; binfo; binfo = binfo->next)
if (sockunion_same (&binfo->peer->su, &su))
return binfo;
}
}
else
{
offset = name + v->namelen;
offsetlen = *length - v->namelen;
len = offsetlen;
if (offsetlen == 0)
rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_UNICAST]);
else
{
if (len > IN_ADDR_SIZE)
len = IN_ADDR_SIZE;
oid2in_addr (offset, len, &addr->prefix);
offset += IN_ADDR_SIZE;
offsetlen -= IN_ADDR_SIZE;
if (offsetlen > 0)
addr->prefixlen = *offset;
else
addr->prefixlen = len * 8;
rn = bgp_node_get (bgp->rib[AFI_IP][SAFI_UNICAST],
(struct prefix *) addr);
offset++;
offsetlen--;
}
if (offsetlen > 0)
{
len = offsetlen;
if (len > IN_ADDR_SIZE)
len = IN_ADDR_SIZE;
oid2in_addr (offset, len, &paddr);
}
else
paddr.s_addr = 0;
if (! rn)
return NULL;
do
{
min = NULL;
for (binfo = rn->info; binfo; binfo = binfo->next)
{
if (binfo->peer->su.sin.sin_family == AF_INET
&& ntohl (paddr.s_addr)
< ntohl (binfo->peer->su.sin.sin_addr.s_addr))
{
if (min)
{
if (ntohl (binfo->peer->su.sin.sin_addr.s_addr)
< ntohl (min->peer->su.sin.sin_addr.s_addr))
min = binfo;
}
else
min = binfo;
}
}
if (min)
{
*length = v->namelen + BGP_PATHATTR_ENTRY_OFFSET;
offset = name + v->namelen;
oid_copy_addr (offset, &rn->p.u.prefix4, IN_ADDR_SIZE);
offset += IN_ADDR_SIZE;
*offset = rn->p.prefixlen;
offset++;
oid_copy_addr (offset, &min->peer->su.sin.sin_addr,
IN_ADDR_SIZE);
addr->prefix = rn->p.u.prefix4;
addr->prefixlen = rn->p.prefixlen;
bgp_unlock_node (rn);
return min;
}
paddr.s_addr = 0;
}
while ((rn = bgp_route_next (rn)) != NULL);
}
return NULL;
}
static u_char *
bgp4PathAttrTable (struct variable *v, oid name[], size_t *length,
int exact, size_t *var_len, WriteMethod **write_method)
{
struct bgp *bgp;
struct bgp_info *binfo;
struct prefix_ipv4 addr;
bgp = bgp_get_default ();
if (! bgp)
return NULL;
if (smux_header_table(v, name, length, exact, var_len, write_method)
== MATCH_FAILED)
return NULL;
memset (&addr, 0, sizeof (struct prefix_ipv4));
binfo = bgp4PathAttrLookup (v, name, length, bgp, &addr, exact);
if (! binfo)
return NULL;
switch (v->magic)
{
case BGP4PATHATTRPEER: /* 1 */
return SNMP_IPADDRESS (binfo->peer->su.sin.sin_addr);
break;
case BGP4PATHATTRIPADDRPREFIXLEN: /* 2 */
return SNMP_INTEGER (addr.prefixlen);
break;
case BGP4PATHATTRIPADDRPREFIX: /* 3 */
return SNMP_IPADDRESS (addr.prefix);
break;
case BGP4PATHATTRORIGIN: /* 4 */
return SNMP_INTEGER (binfo->attr->origin);
break;
case BGP4PATHATTRASPATHSEGMENT: /* 5 */
return aspath_snmp_pathseg (binfo->attr->aspath, var_len);
break;
case BGP4PATHATTRNEXTHOP: /* 6 */
return SNMP_IPADDRESS (binfo->attr->nexthop);
break;
case BGP4PATHATTRMULTIEXITDISC: /* 7 */
return SNMP_INTEGER (binfo->attr->med);
break;
case BGP4PATHATTRLOCALPREF: /* 8 */
return SNMP_INTEGER (binfo->attr->local_pref);
break;
case BGP4PATHATTRATOMICAGGREGATE: /* 9 */
return SNMP_INTEGER (1);
break;
case BGP4PATHATTRAGGREGATORAS: /* 10 */
if (binfo->attr->extra)
return SNMP_INTEGER (binfo->attr->extra->aggregator_as);
else
return SNMP_INTEGER (0);
break;
case BGP4PATHATTRAGGREGATORADDR: /* 11 */
if (binfo->attr->extra)
return SNMP_IPADDRESS (binfo->attr->extra->aggregator_addr);
else
return SNMP_INTEGER (0);
break;
case BGP4PATHATTRCALCLOCALPREF: /* 12 */
return SNMP_INTEGER (-1);
break;
case BGP4PATHATTRBEST: /* 13 */
#define BGP4_PathAttrBest_false 1
#define BGP4_PathAttrBest_true 2
if (CHECK_FLAG (binfo->flags, BGP_INFO_SELECTED))
return SNMP_INTEGER (BGP4_PathAttrBest_true);
else
return SNMP_INTEGER (BGP4_PathAttrBest_false);
break;
case BGP4PATHATTRUNKNOWN: /* 14 */
*var_len = 0;
return NULL;
break;
}
return NULL;
}
/* BGP Traps. */
struct trap_object bgpTrapList[] =
{
{3, {3, 1, BGPPEERLASTERROR}},
{3, {3, 1, BGPPEERSTATE}}
};
void
bgpTrapEstablished (struct peer *peer)
{
int ret;
struct in_addr addr;
oid index[sizeof (oid) * IN_ADDR_SIZE];
ret = inet_aton (peer->host, &addr);
if (ret == 0)
return;
oid_copy_addr (index, &addr, IN_ADDR_SIZE);
smux_trap (bgp_variables, sizeof bgp_variables / sizeof (struct variable),
bgp_trap_oid, sizeof bgp_trap_oid / sizeof (oid),
bgp_oid, sizeof bgp_oid / sizeof (oid),
index, IN_ADDR_SIZE,
bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object),
BGPESTABLISHED);
}
void
bgpTrapBackwardTransition (struct peer *peer)
{
int ret;
struct in_addr addr;
oid index[sizeof (oid) * IN_ADDR_SIZE];
ret = inet_aton (peer->host, &addr);
if (ret == 0)
return;
oid_copy_addr (index, &addr, IN_ADDR_SIZE);
smux_trap (bgp_variables, sizeof bgp_variables / sizeof (struct variable),
bgp_trap_oid, sizeof bgp_trap_oid / sizeof (oid),
bgp_oid, sizeof bgp_oid / sizeof (oid),
index, IN_ADDR_SIZE,
bgpTrapList, sizeof bgpTrapList / sizeof (struct trap_object),
BGPBACKWARDTRANSITION);
}
void
bgp_snmp_init (void)
{
smux_init (bm->master);
REGISTER_MIB("mibII/bgp", bgp_variables, variable, bgp_oid);
}
#endif /* HAVE_SNMP */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>