-src := snmp.c
+src := snmp.c bgp_mib.c subagent.c
obj := $(src-o-files)
+LIBS += `net-snmp-config --agent-libs`
$(all-daemon)
$(cf-local)
-$(call proto-build,snmp_build)
+$(call proto-build,snmp_build_)
tests_objs := $(tests_objs) $(src-o-files)
--- /dev/null
+/*
+ * BIRD -- Simple Network Management Protocol (SNMP)
+ * BGP4-MIB bgpPeerTable
+ *
+ * (c) 2022 Vojtech Vilimek <vojtech.vilimek@nic.cz>
+ * (c) 2022 CZ.NIC z.s.p.o
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ *
+ * Parts of this file were auto-generated using mib2c
+ * using mib2c.create-dataset.conf
+ */
+
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/varbind_api.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+// fix conflicts
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
+#include "proto/snmp/bgp_mib.h"
+#include "lib/birdlib.h"
+
+static int
+bgpPeerTable_handler(
+ netsnmp_mib_handler *handler, // contains void * for internal use
+ netsnmp_handler_registration *reginfo,
+ netsnmp_agent_request_info *reqinfo,
+ netsnmp_request_info *requests) {
+
+ /* perform anything here that you need to do. The requests have
+ already been processed by the master table_dataset handler, but
+ this gives you chance to act on the request in some other way
+ if need be. */
+
+ log(L_INFO " bgpPeerTable_handler()");
+ // walk list of netsnmp_data_list
+ for (netsnmp_data_list *l = reqinfo->agent_data;
+ l; l->next)
+ {
+ log(L_INFO " name: %s, poniter %p", l->name, l->data);
+ }
+
+ char buff[64];
+ // walk list of netsnmp_variable_list VB
+ for (netsnmp_variable_list *var = requests->requestvb;
+ var; var->next_variable)
+ {
+ snprint_value(buff, 64, var->name, var->name_length, var);
+ log(L_INFO "variable %s", buff);
+ memset((void *) buff, 0, 64);
+ }
+
+ return SNMP_ERR_NOERROR;
+}
+
+void
+snmp_init_bgp_table(void)
+{
+ const oid bgpPeerTable_oid[] = {1,3,6,1,2,1,15,3};
+ netsnmp_table_data_set *table_set;
+
+ /* create the table structure itself */
+ table_set = netsnmp_create_table_data_set("bgpPeerTable");
+
+ log(L_INFO "adding indexes to SNMP table bgpPeerTable");
+
+ netsnmp_table_set_add_indexes(
+ table_set,
+ ASN_IPADDRESS, /* index: bgpPeerRemoteAddr */
+ 0
+ );
+
+ log(L_INFO "adding column types to SNMP table bgpPeerTable");
+ netsnmp_table_set_multi_add_default_row(
+ table_set,
+ SNMP_BGP_IDENTIFIER, ASN_IPADDRESS, 0, NULL, 0,
+ SNMP_BGP_STATE, ASN_INTEGER, 0, NULL, 0,
+ /* change to ASN_INTEGER, 1, NULL, 0, below to allow write */
+ SNMP_BGP_ADMIN_STATUS, ASN_INTEGER, 0, NULL, 0,
+ SNMP_BGP_VERSION, ASN_INTEGER, 0, NULL, 0,
+ SNMP_BGP_LOCAL_ADDR, ASN_IPADDRESS, 0, NULL, 0,
+ SNMP_BGP_LOCAL_PORT, ASN_INTEGER, 0, NULL, 0,
+ SNMP_BGP_REMOTE_ADDR, ASN_IPADDRESS, 0, NULL, 0,
+ SNMP_BGP_REMOTE_PORT, ASN_INTEGER, 0, NULL, 0,
+ SNMP_BGP_REMOTE_AS, ASN_INTEGER, 0, NULL, 0,
+ SNMP_BGP_RX_UPDATES, ASN_COUNTER, 0, NULL, 0,
+ SNMP_BGP_TX_UPDATES, ASN_COUNTER, 0, NULL, 0,
+ SNMP_BGP_RX_MESSAGES, ASN_COUNTER, 0, NULL, 0,
+ SNMP_BGP_TX_MESSAGES, ASN_COUNTER, 0, NULL, 0,
+ SNMP_BGP_LAST_ERROR, ASN_OCTET_STR, 0, NULL, 0,
+ SNMP_BGP_FSM_TRANSITIONS, ASN_COUNTER, 0, NULL, 0,
+ SNMP_BGP_FSM_ESTABLISHED_TIME, ASN_GAUGE, 0, NULL, 0,
+ SNMP_BGP_RETRY_INTERVAL, ASN_INTEGER, 1, NULL, 0,
+ SNMP_BGP_HOLD_TIME, ASN_INTEGER, 0, NULL, 0,
+ SNMP_BGP_KEEPALIVE, ASN_INTEGER, 0, NULL, 0,
+ SNMP_BGP_HOLD_TIME_CONFIGURED, ASN_INTEGER, 1, NULL, 0,
+ SNMP_BGP_KEEPALIVE_CONFIGURED, ASN_INTEGER, 1, NULL, 0,
+ SNMP_BGP_ORIGINATION_INTERVAL, ASN_INTEGER, 1, NULL, 0,
+ SNMP_BGP_MIN_ROUTE_ADVERTISEMENT, ASN_INTEGER, 1, NULL, 0,
+ SNMP_BGP_MIN_UPDATE_ELAPSED_TIME, ASN_GAUGE, 0, NULL, 0,
+ 0
+ );
+
+ /* registering the table with the master agent */
+ /* note: if you don't need a subhandler to deal with any aspects
+ of the request, change bgpPeerTable_handler to "NULL" */
+ netsnmp_register_table_data_set(
+ netsnmp_create_handler_registration(
+ "bgpPeerTable", bgpPeerTable_handler,
+ bgpPeerTable_oid,
+ OID_LENGTH(bgpPeerTable_oid),
+ HANDLER_CAN_RONLY
+ // HANDLER_CAN_RWRITE
+ ),
+ table_set, NULL
+ );
+}
+
+void
+snmp_del_bgp_table(void)
+{
+ // XXX really needed ?
+ const oid bgpPeerTable_oid[] = {1,3,6,1,2,1,15,3};
+
+ remove_tree_entry(bgpPeerTable_oid, OID_LENGTH(bgpPeerTable_oid));
+}
--- /dev/null
+#ifndef _BIRD_SNMP_BGP_MIB_H_
+#define _BIRD_SNMP_BGP_MIB_H_
+
+/* peers attributes */
+#define SNMP_BGP_IDENTIFIER 1
+#define SNMP_BGP_STATE 2
+#define SNMP_BGP_ADMIN_STATUS 3 /* in read-only mode */
+#define SNMP_BGP_VERSION 4
+#define SNMP_BGP_LOCAL_ADDR 5
+#define SNMP_BGP_LOCAL_PORT 6
+#define SNMP_BGP_REMOTE_ADDR 7
+#define SNMP_BGP_REMOTE_PORT 8
+#define SNMP_BGP_REMOTE_AS 9
+#define SNMP_BGP_RX_UPDATES 10 /* in updates */
+#define SNMP_BGP_TX_UPDATES 11 /* out updates */
+#define SNMP_BGP_RX_MESSAGES 12 /* in total messages */
+#define SNMP_BGP_TX_MESSAGES 13 /* out total messages */
+#define SNMP_BGP_LAST_ERROR 14 /* UNSUPPORTED */
+#define SNMP_BGP_FSM_TRANSITIONS 15 /* FSM established transitions */
+#define SNMP_BGP_FSM_ESTABLISHED_TIME 16 /* UNSUPPORTED FSM established time */
+#define SNMP_BGP_RETRY_INTERVAL 17
+#define SNMP_BGP_HOLD_TIME 18
+#define SNMP_BGP_KEEPALIVE 19
+#define SNMP_BGP_HOLD_TIME_CONFIGURED 20
+#define SNMP_BGP_KEEPALIVE_CONFIGURED 21
+#define SNMP_BGP_ORIGINATION_INTERVAL 22 /* UNSUPPORTED */
+#define SNMP_BGP_MIN_ROUTE_ADVERTISEMENT 23 /* UNSUPPORTED */
+#define SNMP_BGP_MIN_UPDATE_ELAPSED_TIME 24 /* UNSUPPORTED */
+
+void snmp_init_bgp_table(void);
+void snmp_del_bgp_table(void);
+
+#endif
CF_KEYWORDS(SNMP, TABLE, PROTOCOL, BPG)
-%type <cc> snmp_channel_start
-
CF_GRAMMAR
proto: snmp_proto '}' { this_channel = NULL; } ;
snmp_proto:
snmp_proto_start '{'
| snmp_proto proto_item ';'
- | snmp_proto snmp_proto_channel ';'
+ | snmp_proto snmp_bgp_bond ';'
| snmp_proto ';'
;
snmp_proto_start: proto_start SNMP
{
this_proto = proto_config_new(&proto_snmp, $1);
+ init_list(&SNMP_CFG->bgp_entries);
}
-snmp_proto_channel: snmp_channel_start snmp_channel_opt_list channel_end ;
-
-snmp_channel_start: net_type symbol
+snmp_bgp_bond: BGP symbol
{
- this_channel = channel_config_get(&channel_snmp, $2->name, $1, this_proto);
-}
-
-snmp_channel_opt_list:
- /* empty */
- | '{' snmp_opts '}'
- ;
+ struct snmp_bond *this_bond = cfg_alloc(sizeof(struct snmp_bond));
+ this_bond->type = SNMP_BGP;
-snmp_opts:
- /* empty */
- | snmp_opts channel_item ';'
- | snmp_opts snmp_opt ';'
- ;
+ struct proto_config *pc;
+ WALK_LIST(pc, this_proto->global->protos)
+ if (!strcmp(pc->name, $2->name) && pc->protocol == &proto_bgp)
+ this_bond->proto = pc;
-snmp_opt:
- PROTOCOL BGP symbol {
- SNMP_CC->bgp = NULL;
-
- struct proto_config *pc;
- WALK_LIST(pc, this_proto->global->protos)
- if (!strcmp(pc->name, $3->name)
- && pc->protocol == &proto_bgp)
- SNMP_CC->bgp = (struct bgp_config *) pc;
-
- if (!SNMP_CC->bgp) cf_error("BGP protocol %s not found", $3);
- }
- ;
+ if (!this_bond->proto) cf_error("BGP protocol %s not found", $2->name);
+ add_tail(&SNMP_CFG->bgp_entries, (node *) this_bond);
+}
CF_CODE
* (c) 2022 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
+ *
+ * Parts of this file were auto-generated using mib2c
+ * using mib2c.create-dataset.conf
*/
#include "nest/bird.h"
#include "nest/cli.h"
#include "proto/snmp/snmp.h"
+#include "proto/snmp/subagent.h"
+#include "proto/snmp/bgp_mib.h"
static struct proto *
snmp_init(struct proto_config *CF)
return P;
}
+void start_multihook(void)
+{
+ /* init bgp MIB table */
+ snmp_init_bgp_table();
+
+ /* init ospf MIB table */
+ //snmp_inti_ospf_table();
+}
+
static int
snmp_start(struct proto *P)
{
- struct channel_config *cc;
- WALK_LIST(cc, P->cf->channels)
- {
- struct channel *c = NULL;
- proto_configure_channel(P, &c, cc);
- }
-
- return PS_UP;
+ /* init MIB tables */
+ if (snmp_start_subagent(start_multihook))
+ return PS_UP;
+ else
+ return PS_DOWN;
}
static int
static void
snmp_show_proto_info(struct proto *P)
{
- //struct stats_proto *p = (void *) P;
-
- struct snmp_channel *sc;
+ struct snmp_proto *sp = (void *) P;
+ struct snmp_config *c = (void *) P->cf;
- WALK_LIST(sc, P->channels)
+ cli_msg(-1006, " BGP peers");
+ struct snmp_bond *bond;
+ WALK_LIST(bond, c->bgp_entries)
{
- cli_msg(-1006, " Channel %s", sc->c.name);
-
- if (!P->disabled)
- {
- cli_msg(-1006, " enabled");
+ struct proto_config *cf = P->cf;
+ struct bgp_config *bcf = (struct bgp_config *) cf;
+ struct proto_config *pcf = (void *) bond->proto;
+ struct proto *p = cf->proto;
+ struct bgp_proto *bp = (struct bgp_proto *) cf->proto;
+ struct bgp_conn *conn = bp->conn;
+
+ cli_msg(-1006, " name: %s", cf->name);
+ cli_msg(-1006, "");
+ cli_msg(-1006, " rem. identifier: %u", bp->remote_id);
+ // learn more !!
+ cli_msg(-1006, " admin status: %s", (p->disabled) ? "start" :
+ "stop");
+ // version ?
+ cli_msg(-1006, " version: ??, likely 4");
+ cli_msg(-1006, " local ip: %u", bcf->local_ip);
+ cli_msg(-1006, " remote ip: %u", bcf->remote_ip);
+ cli_msg(-1006, " local port: %u", bcf->local_port);
+ cli_msg(-1006, " remote port: %u", bcf->remote_port);
+ if (conn) {
+ cli_msg(-1006, " state: %u", conn->state);
+ cli_msg(-1006, " remote as: %u", conn->remote_caps->as4_number);
+ }
+ cli_msg(-1006, " in updates: %u", bp->stats.rx_updates);
+ cli_msg(-1006, " out updates: %u", bp->stats.tx_updates);
+ cli_msg(-1006, " in total: %u", bp->stats.rx_messages);
+ cli_msg(-1006, " out total: %u", bp->stats.tx_messages);
+ cli_msg(-1006, " fsm transitions: %u",
+bp->stats.fsm_established_transitions);
+
+ // not supported yet
+ cli_msg(-1006, " fsm total time: --");
+ cli_msg(-1006, " retry interval: %u", bcf->connect_retry_time);
+
+ if (conn) {
+ cli_msg(-1006, " hold time: %u", conn->hold_time);
+ cli_msg(-1006, " keep alive: %u", conn->keepalive_time );
}
- else
- cli_msg(-1006, " disabled");
+
+ cli_msg(-1006, " hold configurated: %u", bcf->hold_time );
+ cli_msg(-1006, " keep alive config: %u", bcf->keepalive_time );
+
+ // unknown
+ cli_msg(-1006, " min AS origin. int.: --");
+ cli_msg(-1006, " min route advertisement: %u", 0 );
+ cli_msg(-1006, " in update elapsed time: %u", 0 );
+
+ if (!conn)
+ cli_msg(-1006, " no default connection");
+
+ cli_msg(-1006, " outgoinin_conn state %u", bp->outgoing_conn.state + 1);
+ cli_msg(-1006, " incoming_conn state: %u", bp->incoming_conn.state + 1);
}
}
-static int
-snmp_channel_start(struct channel *C)
+
+void
+shutdown_multihook(void)
{
- return 0;
+ snmp_del_bgp_table();
+ //snmp_del_ospf_table();
}
-static void
-snmp_channel_shutdown(struct channel *C)
+/* snmp_shutdown already occupied by net-snmp */
+void
+snmp_shutdown_(struct proto *P)
{
-
+ snmp_stop_subagent(shutdown_multihook);
}
-struct channel_class channel_snmp = {
- .channel_size = sizeof(struct snmp_channel),
- .config_size = sizeof(struct snmp_channel_config),
- .start = snmp_channel_start,
- .shutdown = snmp_channel_shutdown,
-};
-
struct protocol proto_snmp = {
.name = "Snmp",
.template = "snmp%d",
.init = snmp_init,
.start = snmp_start,
.reconfigure = snmp_reconfigure,
+ .shutdown = snmp_shutdown_,
.show_proto_info = snmp_show_proto_info,
};
+/* strange name because conflict with net-snmp lib snmp_lib() */
void
-snmp_build(void)
+snmp_build_(void)
{
proto_build(&proto_snmp);
}
#include "proto/bgp/bgp.h"
+#define SNMP_UNDEFINED 0
+#define SNMP_BGP 1
+#define SNMP_OSPF 2
+#define SNMP_INVALID 255
+
+struct snmp_bond {
+ node n;
+ struct proto_config *proto;
+ u8 type;
+};
+
struct snmp_config {
struct channel_config c;
+ list bgp_entries;
};
struct snmp_proto {
struct snmp_channel_config {
struct channel_config c;
struct bgp_config *bgp;
+ u8 type;
};
struct snmp_channel {
--- /dev/null
+/*
+ * BIRD -- Simple Network Management Protocol (SNMP)
+ *
+ * (c) 2022 Vojtech Vilimek <vojtech.vilimek@nic.cz>
+ * (c) 2022 CZ.NIC z.s.p.o
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ *
+ * Parts of this file were auto-generated from net-snmp-config
+ */
+
+#include <net-snmp/net-snmp-config.h>
+
+#ifdef HAVE_SIGNAL
+#include <signal.h>
+#endif
+
+#ifdef HAV_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+extern int netsnmp_running;
+
+int
+snmp_start_subagent(void (*hook)(void))
+{
+ /* subagent mode */
+ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
+ NETSNMP_DS_AGENT_ROLE, 1);
+
+ /* forking netsnmp mechanism * /
+ if (netsnmp_daemonize(1, snmp_stderrolog_status()) != 0)
+ return 0; // start FAILED
+ */
+
+ /* for Win32 only */
+ SOCK_STARTUP;
+
+ /* init library */
+ init_agent("bird");
+
+ if (hook)
+ hook();
+
+ /* used for loading config 'bird-snmp.conf' */
+ init_snmp("bird-snmp");
+
+ return 1; // SUCCESS
+}
+
+void
+snmp_agent_reconfigure(void)
+{
+ free_config();
+ read_configs();
+}
+
+void
+snmp_shutdown_subagent(void (*hook)(void))
+{
+ /* at shutdown time */
+ snmp_shutdown("bird");
+
+ /* shutdown hook */
+ if (hook)
+ hook();
+
+ /* shutdown the agent library */
+ shutdown_agent();
+
+ /* for Win32 only */
+ SOCK_CLEANUP;
+}
+
+void
+snmp_stop_subagent(void (*hook)(void))
+{
+ /* at shutdown time */
+ snmp_shutdown("bird");
+
+ /* deinitialize MIB code */
+ if (hook)
+ hook();
+
+ /* shutdown the agent library */
+ shutdown_agent();
+}
--- /dev/null
+#ifndef _BIRD_SNMP_SUBAGENT_H_
+#define _BIRD_SNMP_SUBAGENT_H_
+
+int snmp_start_subagent(void (*hook)(void));
+void snmp_agent_reconfigure(void);
+void snmp_stop_subagent(void (*hook)(void));
+
+#endif