mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-03 23:47:16 +00:00 
			
		
		
		
	This reverts commit c14777c6bf.
clang 5 is not widely available enough for people to indent with.  This
is particularly problematic when rebasing/adjusting branches.
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
		
	
			
		
			
				
	
	
		
			946 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			946 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* 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 this program; see the file COPYING; if not, write to the Free Software
 | 
						|
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 | 
						|
 */
 | 
						|
 | 
						|
#include <zebra.h>
 | 
						|
 | 
						|
#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 "hook.h"
 | 
						|
#include "libfrr.h"
 | 
						|
#include "version.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"
 | 
						|
 | 
						|
/* 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. */
 | 
						|
static oid bgp_oid[] = {BGP4MIB};
 | 
						|
static 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 (); */
 | 
						|
 | 
						|
static 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;
 | 
						|
 | 
						|
	sockunion_init(&su);
 | 
						|
 | 
						|
	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;
 | 
						|
 | 
						|
	sockunion_init(&su);
 | 
						|
 | 
						|
#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 */
 | 
						|
		return SNMP_INTEGER(binfo->attr->aggregator_as);
 | 
						|
		break;
 | 
						|
	case BGP4PATHATTRAGGREGATORADDR: /* 11 */
 | 
						|
		return SNMP_IPADDRESS(binfo->attr->aggregator_addr);
 | 
						|
		break;
 | 
						|
	case BGP4PATHATTRCALCLOCALPREF: /* 12 */
 | 
						|
		return SNMP_INTEGER(-1);
 | 
						|
		break;
 | 
						|
	case BGP4PATHATTRBEST: /* 13 */
 | 
						|
			       /* $FRR indent$ */
 | 
						|
			       /* clang-format off */
 | 
						|
#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. */
 | 
						|
static struct trap_object bgpTrapList[] = {{3, {3, 1, BGPPEERLASTERROR}},
 | 
						|
					   {3, {3, 1, BGPPEERSTATE}}};
 | 
						|
 | 
						|
static int 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 0;
 | 
						|
 | 
						|
	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);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int 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 0;
 | 
						|
 | 
						|
	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);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int bgp_snmp_init(struct thread_master *tm)
 | 
						|
{
 | 
						|
	smux_init(tm);
 | 
						|
	REGISTER_MIB("mibII/bgp", bgp_variables, variable, bgp_oid);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int bgp_snmp_module_init(void)
 | 
						|
{
 | 
						|
	hook_register(peer_established, bgpTrapEstablished);
 | 
						|
	hook_register(peer_backward_transition, bgpTrapBackwardTransition);
 | 
						|
	hook_register(frr_late_init, bgp_snmp_init);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
FRR_MODULE_SETUP(.name = "bgpd_snmp", .version = FRR_VERSION,
 | 
						|
		 .description = "bgpd AgentX SNMP module",
 | 
						|
		 .init = bgp_snmp_module_init)
 |