From 2c7cac91ed6e7db0f6937923d2b57f97dbdbc337 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 11:53:30 +0200 Subject: Adding upstream version 8.4.4. Signed-off-by: Daniel Baumann --- bgpd/bgp_snmp.c | 916 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 916 insertions(+) create mode 100644 bgpd/bgp_snmp.c (limited to 'bgpd/bgp_snmp.c') diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c new file mode 100644 index 0000000..6bc3134 --- /dev/null +++ b/bgpd/bgp_snmp.c @@ -0,0 +1,916 @@ +/* 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 + +#include +#include + +#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 "lib/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" +#include "bgpd/bgp_mplsvpn_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. */ +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 uint8_t *bgpVersion(struct variable *, oid[], size_t *, int, size_t *, + WriteMethod **); +static uint8_t *bgpLocalAs(struct variable *, oid[], size_t *, int, size_t *, + WriteMethod **); +static uint8_t *bgpPeerTable(struct variable *, oid[], size_t *, int, size_t *, + WriteMethod **); +static uint8_t *bgpRcvdPathAttrTable(struct variable *, oid[], size_t *, int, + size_t *, WriteMethod **); +static uint8_t *bgpIdentifier(struct variable *, oid[], size_t *, int, size_t *, + WriteMethod **); +static uint8_t *bgp4PathAttrTable(struct variable *, oid[], size_t *, int, + size_t *, WriteMethod **); +/* static uint8_t *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 uint8_t *bgpVersion(struct variable *v, oid name[], size_t *length, + int exact, size_t *var_len, + WriteMethod **write_method) +{ + static uint8_t version; + + if (smux_header_generic(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + + /* Return BGP version. Zebra bgpd only support version 4. */ + version = (0x80 >> (BGP_VERSION_4 - 1)); + + /* Return octet string length 1. */ + *var_len = 1; + return &version; +} + +static uint8_t *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 listnode *bgpnode; + + for (ALL_LIST_ELEMENTS_RO(bm->bgp, bgpnode, bgp)) { + for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + if (sockunion_family(&peer->su) != AF_INET) + continue; + + if (sockunion2ip(&peer->su) == src->s_addr) + return peer; + } + } + + return NULL; +} + +static struct peer *bgp_peer_lookup_next(struct in_addr *src) +{ + struct bgp *bgp; + struct peer *peer; + struct peer *next_peer = NULL; + struct listnode *node; + struct listnode *bgpnode; + + for (ALL_LIST_ELEMENTS_RO(bm->bgp, bgpnode, bgp)) { + for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + if (sockunion_family(&peer->su) != AF_INET) + continue; + if (ntohl(sockunion2ip(&peer->su)) <= ntohl(src->s_addr)) + continue; + + if (!next_peer + || ntohl(sockunion2ip(&next_peer->su)) + > ntohl(sockunion2ip(&peer->su))) { + next_peer = peer; + } + } + } + + if (next_peer) { + src->s_addr = sockunion2ip(&next_peer->su); + return next_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_in_addr(name + namelen, addr); + *length = sizeof(struct in_addr) + namelen; + + return peer; + } + return NULL; +} + +/* BGP write methods. */ +static int write_bgpPeerTable(int action, uint8_t *var_val, + uint8_t var_val_type, size_t var_val_len, + uint8_t *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(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: + peer_flag_set(peer, PEER_FLAG_TIMER_CONNECT); + peer->connect = intval; + peer->v_connect = intval; + break; + case BGPPEERHOLDTIMECONFIGURED: + peer_flag_set(peer, PEER_FLAG_TIMER); + peer->holdtime = intval; + peer->v_holdtime = intval; + break; + case BGPPEERKEEPALIVECONFIGURED: + peer_flag_set(peer, PEER_FLAG_TIMER); + peer->keepalive = intval; + peer->v_keepalive = intval; + break; + case BGPPEERMINROUTEADVERTISEMENTINTERVAL: + peer->v_routeadv = intval; + break; + } + return SNMP_ERR_NOERROR; +} + +static uint8_t *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; + uint32_t ui, uo; + + if (smux_header_table(v, name, length, exact, var_len, write_method) + == MATCH_FAILED) + return NULL; + memset(&addr, 0, sizeof(addr)); + + peer = bgpPeerTable_lookup(v, name, length, &addr, exact); + if (!peer) + return NULL; + + switch (v->magic) { + case BGPPEERIDENTIFIER: + return SNMP_IPADDRESS(peer->remote_id); + case BGPPEERSTATE: + return SNMP_INTEGER(peer->status); + 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); + case BGPPEERNEGOTIATEDVERSION: + return SNMP_INTEGER(BGP_VERSION_4); + case BGPPEERLOCALADDR: + if (peer->su_local) + return SNMP_IPADDRESS(peer->su_local->sin.sin_addr); + else + return SNMP_IPADDRESS(bgp_empty_addr); + case BGPPEERLOCALPORT: + if (peer->su_local) + return SNMP_INTEGER( + ntohs(peer->su_local->sin.sin_port)); + else + return SNMP_INTEGER(0); + case BGPPEERREMOTEADDR: + if (peer->su_remote) + return SNMP_IPADDRESS(peer->su_remote->sin.sin_addr); + else + return SNMP_IPADDRESS(bgp_empty_addr); + case BGPPEERREMOTEPORT: + if (peer->su_remote) + return SNMP_INTEGER( + ntohs(peer->su_remote->sin.sin_port)); + else + return SNMP_INTEGER(0); + case BGPPEERREMOTEAS: + return SNMP_INTEGER(peer->as); + case BGPPEERINUPDATES: + ui = atomic_load_explicit(&peer->update_in, + memory_order_relaxed); + return SNMP_INTEGER(ui); + case BGPPEEROUTUPDATES: + uo = atomic_load_explicit(&peer->update_out, + memory_order_relaxed); + return SNMP_INTEGER(uo); + case BGPPEERINTOTALMESSAGES: + return SNMP_INTEGER(PEER_TOTAL_RX(peer)); + case BGPPEEROUTTOTALMESSAGES: + return SNMP_INTEGER(PEER_TOTAL_TX(peer)); + case BGPPEERLASTERROR: { + static uint8_t lasterror[2]; + lasterror[0] = peer->notify.code; + lasterror[1] = peer->notify.subcode; + *var_len = 2; + return (uint8_t *)&lasterror; + } + case BGPPEERFSMESTABLISHEDTRANSITIONS: + return SNMP_INTEGER(peer->established); + case BGPPEERFSMESTABLISHEDTIME: + if (peer->uptime == 0) + return SNMP_INTEGER(0); + else + return SNMP_INTEGER(monotime(NULL) - peer->uptime); + case BGPPEERCONNECTRETRYINTERVAL: + *write_method = write_bgpPeerTable; + return SNMP_INTEGER(peer->v_connect); + case BGPPEERHOLDTIME: + return SNMP_INTEGER(peer->v_holdtime); + case BGPPEERKEEPALIVE: + return SNMP_INTEGER(peer->v_keepalive); + case BGPPEERHOLDTIMECONFIGURED: + *write_method = write_bgpPeerTable; + if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) + return SNMP_INTEGER(peer->holdtime); + else + return SNMP_INTEGER(peer->v_holdtime); + case BGPPEERKEEPALIVECONFIGURED: + *write_method = write_bgpPeerTable; + if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) + return SNMP_INTEGER(peer->keepalive); + else + return SNMP_INTEGER(peer->v_keepalive); + case BGPPEERMINROUTEADVERTISEMENTINTERVAL: + *write_method = write_bgpPeerTable; + return SNMP_INTEGER(peer->v_routeadv); + case BGPPEERINUPDATEELAPSEDTIME: + if (peer->update_time == 0) + return SNMP_INTEGER(0); + else + return SNMP_INTEGER(monotime(NULL) - peer->update_time); + default: + return NULL; + } + return NULL; +} + +static uint8_t *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 uint8_t *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_path_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_path_info *path; + struct bgp_path_info *min; + struct bgp_dest *dest; + 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. */ + dest = bgp_node_lookup(bgp->rib[AFI_IP][SAFI_UNICAST], + (struct prefix *)addr); + if (dest) { + for (path = bgp_dest_get_bgp_path_info(dest); path; + path = path->next) + if (sockunion_same(&path->peer->su, &su)) + return path; + + bgp_dest_unlock_node(dest); + } + } else { + offset = name + v->namelen; + offsetlen = *length - v->namelen; + len = offsetlen; + + if (offsetlen == 0) + dest = 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; + + dest = 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 = INADDR_ANY; + + if (!dest) + return NULL; + + do { + min = NULL; + + for (path = bgp_dest_get_bgp_path_info(dest); path; + path = path->next) { + if (path->peer->su.sin.sin_family == AF_INET + && ntohl(paddr.s_addr) + < ntohl(path->peer->su.sin + .sin_addr + .s_addr)) { + if (min) { + if (ntohl(path->peer->su.sin + .sin_addr + .s_addr) + < ntohl(min->peer->su.sin + .sin_addr + .s_addr)) + min = path; + } else + min = path; + } + } + + if (min) { + const struct prefix *rn_p = + bgp_dest_get_prefix(dest); + + *length = + v->namelen + BGP_PATHATTR_ENTRY_OFFSET; + + offset = name + v->namelen; + oid_copy_in_addr(offset, &rn_p->u.prefix4); + offset += IN_ADDR_SIZE; + *offset = rn_p->prefixlen; + offset++; + oid_copy_in_addr(offset, + &min->peer->su.sin.sin_addr); + addr->prefix = rn_p->u.prefix4; + addr->prefixlen = rn_p->prefixlen; + + bgp_dest_unlock_node(dest); + + return min; + } + + paddr.s_addr = INADDR_ANY; + } while ((dest = bgp_route_next(dest)) != NULL); + } + return NULL; +} + +static uint8_t *bgp4PathAttrTable(struct variable *v, oid name[], + size_t *length, int exact, size_t *var_len, + WriteMethod **write_method) +{ + struct bgp *bgp; + struct bgp_path_info *path; + 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(addr)); + + path = bgp4PathAttrLookup(v, name, length, bgp, &addr, exact); + if (!path) + return NULL; + + switch (v->magic) { + case BGP4PATHATTRPEER: /* 1 */ + return SNMP_IPADDRESS(path->peer->su.sin.sin_addr); + case BGP4PATHATTRIPADDRPREFIXLEN: /* 2 */ + return SNMP_INTEGER(addr.prefixlen); + case BGP4PATHATTRIPADDRPREFIX: /* 3 */ + return SNMP_IPADDRESS(addr.prefix); + case BGP4PATHATTRORIGIN: /* 4 */ + return SNMP_INTEGER(path->attr->origin); + case BGP4PATHATTRASPATHSEGMENT: /* 5 */ + return aspath_snmp_pathseg(path->attr->aspath, var_len); + case BGP4PATHATTRNEXTHOP: /* 6 */ + return SNMP_IPADDRESS(path->attr->nexthop); + case BGP4PATHATTRMULTIEXITDISC: /* 7 */ + return SNMP_INTEGER(path->attr->med); + case BGP4PATHATTRLOCALPREF: /* 8 */ + return SNMP_INTEGER(path->attr->local_pref); + case BGP4PATHATTRATOMICAGGREGATE: /* 9 */ + return SNMP_INTEGER(1); + case BGP4PATHATTRAGGREGATORAS: /* 10 */ + return SNMP_INTEGER(path->attr->aggregator_as); + case BGP4PATHATTRAGGREGATORADDR: /* 11 */ + return SNMP_IPADDRESS(path->attr->aggregator_addr); + case BGP4PATHATTRCALCLOCALPREF: /* 12 */ + return SNMP_INTEGER(-1); + case BGP4PATHATTRBEST: /* 13 */ +#define BGP4_PathAttrBest_false 1 +#define BGP4_PathAttrBest_true 2 + if (CHECK_FLAG(path->flags, BGP_PATH_SELECTED)) + return SNMP_INTEGER(BGP4_PathAttrBest_true); + else + return SNMP_INTEGER(BGP4_PathAttrBest_false); + case BGP4PATHATTRUNKNOWN: /* 14 */ + *var_len = 0; + return NULL; + } + return NULL; +} + +/* BGP Traps. */ +static struct trap_object bgpTrapList[] = {{3, {3, 1, BGPPEERREMOTEADDR} }, + {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]; + + /* Check if this peer just went to Established */ + if ((peer->ostatus != OpenConfirm) || !(peer_established(peer))) + return 0; + + ret = inet_aton(peer->host, &addr); + if (ret == 0) + return 0; + + oid_copy_in_addr(index, &addr); + + smux_trap(bgp_variables, array_size(bgp_variables), bgp_trap_oid, + array_size(bgp_trap_oid), bgp_oid, + sizeof(bgp_oid) / sizeof(oid), index, IN_ADDR_SIZE, + bgpTrapList, array_size(bgpTrapList), 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_in_addr(index, &addr); + + smux_trap(bgp_variables, array_size(bgp_variables), bgp_trap_oid, + array_size(bgp_trap_oid), bgp_oid, + sizeof(bgp_oid) / sizeof(oid), index, IN_ADDR_SIZE, + bgpTrapList, array_size(bgpTrapList), BGPBACKWARDTRANSITION); + return 0; +} + +static int bgp_snmp_init(struct thread_master *tm) +{ + smux_init(tm); + REGISTER_MIB("mibII/bgp", bgp_variables, variable, bgp_oid); + bgp_mpls_l3vpn_module_init(); + return 0; +} + +static int bgp_snmp_module_init(void) +{ + hook_register(peer_status_changed, 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, +); -- cgit v1.2.3