mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2025-03-11 17:08:46 +00:00
TMP: work on Get-PDU and GetNext-PDU
This commit is contained in:
parent
eb5a749046
commit
8ea2e991fa
@ -11,11 +11,12 @@
|
||||
* 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
|
||||
@ -27,108 +28,38 @@
|
||||
#include "bgp_mib.h"
|
||||
#include "snmp.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)
|
||||
snmp_bgp_register()
|
||||
{}
|
||||
|
||||
static inline int
|
||||
is_bgp_peer_entry(struct oid *o)
|
||||
{
|
||||
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
|
||||
);
|
||||
if (o->ids[2] == BGP4_PEER_ENTRY &&
|
||||
o->ids[3] > 0 &&
|
||||
/* do not include bgpPeerInUpdatesElapsedTime
|
||||
and bgpPeerFsmEstablishedTime */
|
||||
o->ids[3] < SNMP_BGP_IN_UPDATE_ELAPSED_TIME &&
|
||||
o->ids[3] != SNMP_BGP_FSM_ESTABLISHED_TIME)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
snmp_del_bgp_table(void)
|
||||
int
|
||||
snmp_bgp_is_supported(struct oid *o)
|
||||
{
|
||||
// XXX really needed ?
|
||||
const oid bgpPeerTable_oid[] = {1,3,6,1,2,1,15,3};
|
||||
|
||||
remove_tree_entry(bgpPeerTable_oid, OID_LENGTH(bgpPeerTable_oid));
|
||||
if (o->prefix == 2 && o->ids[0] == 1)
|
||||
{
|
||||
if (o->ids[1] == BGP4_MIB_VERSION ||
|
||||
o->ids == BGP4_MIB_LOCAL_AS)
|
||||
return 1;
|
||||
else if (o->ids[1] == BGP4_PEER_TABLE)
|
||||
return is_bgp_peer_entry(o)
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3,33 +3,41 @@
|
||||
|
||||
/* peers attributes */
|
||||
enum BGP4_MIB {
|
||||
SNMP_BGP_IDENTIFIER = 1;
|
||||
SNMP_BGP_STATE = 2;
|
||||
SNMP_BGP_ADMIN_STATUS = 3; /* in read-only mode */
|
||||
SNMP_BGP_VERSION = 4;
|
||||
SNMP_BGP_LOCAL_ADDR = 5;
|
||||
SNMP_BGP_LOCAL_PORT = 6;
|
||||
SNMP_BGP_REMOTE_ADDR = 7;
|
||||
SNMP_BGP_REMOTE_PORT = 8;
|
||||
SNMP_BGP_REMOTE_AS = 9;
|
||||
SNMP_BGP_RX_UPDATES = 10; /* in updates */
|
||||
SNMP_BGP_TX_UPDATES = 11; /* out updates */
|
||||
SNMP_BGP_RX_MESSAGES = 12; /* in total messages */
|
||||
SNMP_BGP_TX_MESSAGES = 13; /* out total messages */
|
||||
SNMP_BGP_LAST_ERROR = 14;
|
||||
SNMP_BGP_FSM_TRANSITIONS = 15; /* FSM established transitions */
|
||||
SNMP_BGP_FSM_ESTABLISHED_TIME = 16; /* UNSUPPORTED FSM established time */
|
||||
SNMP_BGP_RETRY_INTERVAL = 17;
|
||||
SNMP_BGP_HOLD_TIME = 18;
|
||||
SNMP_BGP_KEEPALIVE = 19;
|
||||
SNMP_BGP_HOLD_TIME_CONFIGURED = 20;
|
||||
SNMP_BGP_KEEPALIVE_CONFIGURED = 21;
|
||||
SNMP_BGP_ORIGINATION_INTERVAL = 22; /* UNSUPPORTED 0 */
|
||||
SNMP_BGP_MIN_ROUTE_ADVERTISEMENT = 23; /* UNSUPPORTED 0*/
|
||||
SNMP_BGP_MIN_UPDATE_ELAPSED_TIME = 24; /* UNSUPPORTED */
|
||||
SNMP_BGP_IDENTIFIER = 1,
|
||||
SNMP_BGP_STATE = 2,
|
||||
SNMP_BGP_ADMIN_STATUS = 3, /* in read-only mode */
|
||||
SNMP_BGP_VERSION = 4,
|
||||
SNMP_BGP_LOCAL_ADDR = 5,
|
||||
SNMP_BGP_LOCAL_PORT = 6,
|
||||
SNMP_BGP_REMOTE_ADDR = 7,
|
||||
SNMP_BGP_REMOTE_PORT = 8,
|
||||
SNMP_BGP_REMOTE_AS = 9,
|
||||
SNMP_BGP_RX_UPDATES = 10, /* in updates */
|
||||
SNMP_BGP_TX_UPDATES = 11, /* out updates */
|
||||
SNMP_BGP_RX_MESSAGES = 12, /* in total messages */
|
||||
SNMP_BGP_TX_MESSAGES = 13, /* out total messages */
|
||||
SNMP_BGP_LAST_ERROR = 14,
|
||||
SNMP_BGP_FSM_TRANSITIONS = 15, /* FSM established transitions */
|
||||
SNMP_BGP_FSM_ESTABLISHED_TIME = 16, /* UNSUPPORTED FSM established time */
|
||||
SNMP_BGP_RETRY_INTERVAL = 17,
|
||||
SNMP_BGP_HOLD_TIME = 18,
|
||||
SNMP_BGP_KEEPALIVE = 19,
|
||||
SNMP_BGP_HOLD_TIME_CONFIGURED = 20,
|
||||
SNMP_BGP_KEEPALIVE_CONFIGURED = 21,
|
||||
SNMP_BGP_ORIGINATION_INTERVAL = 22, /* UNSUPPORTED - 0 */
|
||||
SNMP_BGP_MIN_ROUTE_ADVERTISEMENT = 23, /* UNSUPPORTED - 0 */
|
||||
SNMP_BGP_IN_UPDATE_ELAPSED_TIME = 24, /* UNSUPPORTED */
|
||||
} PACKED;
|
||||
|
||||
void snmp_init_bgp_table(void);
|
||||
void snmp_del_bgp_table(void);
|
||||
//void snmp_init_bgp_table(void);
|
||||
//void snmp_del_bgp_table(void);
|
||||
|
||||
void snmp_bgp_register(void);
|
||||
int snmp_bgp_is_supported(struct oid *o);
|
||||
|
||||
#define BGP4_MIB_VERSION 1
|
||||
#define BGP4_MIB_LOCAL_AS 2
|
||||
#define BGP4_PEER_TABLE 3
|
||||
#define BGP4_PEER_ENTRY 1
|
||||
|
||||
#endif
|
||||
|
@ -14,11 +14,10 @@ CF_HDR
|
||||
CF_DEFINES
|
||||
|
||||
#define SNMP_CFG ((struct snmp_config *) this_proto)
|
||||
#define SNMP_CC ((struct snmp_channel_config *) this_channel)
|
||||
|
||||
CF_DECLS
|
||||
|
||||
CF_KEYWORDS(SNMP, TABLE, PROTOCOL, BPG)
|
||||
CF_KEYWORDS(SNMP, PROTOCOL, BPG, LOCAL, AS, REMOTE, PORT)
|
||||
|
||||
CF_GRAMMAR
|
||||
|
||||
@ -33,19 +32,23 @@ snmp_proto:
|
||||
| snmp_proto REMOTE PORT expr ';' { SNMP_CFG->remote_port = $4; if (($4<1) ||
|
||||
($4>65545)) cf_error("Invalid port number"); }
|
||||
| snmp_proto LOCAL ipa ';' { SNMP_CFG->local_ip = $3; }
|
||||
| snmp_proto REMOTE ipa ';' { SNMP_CFG->remote_ip = $3; if(!ipa_nonzero($3))
|
||||
| snmp_proto REMOTE ipa ';' { SNMP_CFG->remote_ip = $3; if(ipa_zero($3))
|
||||
cf_error("Invalid remote ip address"); }
|
||||
| snmp_proto LOCAL AS expr ';' { if ($4<1 || $4>65535) cf_error("invalid local as");
|
||||
SNMP_CFG->local_as = $4; }
|
||||
;
|
||||
|
||||
snmp_proto_start: proto_start SNMP
|
||||
{
|
||||
this_proto = proto_config_new(&proto_snmp, $1);
|
||||
|
||||
init_list(&SNMP_CFG->bgp_entries);
|
||||
|
||||
SNMP_CFG->local_ip = IPA_NONE;
|
||||
SNMP_CFG->remote_ip = ipa_build4(127,0,0,1);
|
||||
SNMP_CFG->local_port = 0;
|
||||
SNMP_CFG->remote_port = 705;
|
||||
SNMP_CFG->local_as = 0;
|
||||
|
||||
SNMP_CFG->timeout = 15;
|
||||
}
|
||||
@ -53,7 +56,6 @@ snmp_proto_start: proto_start SNMP
|
||||
proto_name ;
|
||||
|
||||
|
||||
|
||||
snmp_bgp_bond: BGP symbol
|
||||
{
|
||||
struct snmp_bond *this_bond = cfg_alloc(sizeof(struct snmp_bond));
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "nest/cli.h"
|
||||
#include "nest/locks.h"
|
||||
#include "lib/socket.h"
|
||||
#include "lib/lists.h"
|
||||
|
||||
#include "snmp.h"
|
||||
#include "subagent.h"
|
||||
@ -21,6 +22,7 @@
|
||||
static void snmp_connected(sock *sk);
|
||||
static void snmp_sock_err(sock *sk, int err);
|
||||
static void snmp_ping_timer(struct timer *tm);
|
||||
static void snmp_retry_timer(struct timer *tm);
|
||||
|
||||
static struct proto *
|
||||
snmp_init(struct proto_config *CF)
|
||||
@ -98,7 +100,14 @@ static void
|
||||
snmp_sock_err(sock *sk UNUSED, int err UNUSED)
|
||||
{
|
||||
log(L_INFO "snmp_sock_err() %s - err no: %d", strerror(err), err);
|
||||
die("socket error");
|
||||
|
||||
struct snmp_proto *p = sk->data;
|
||||
|
||||
p->state = SNMP_ERR;
|
||||
if (p->p.proto_state == PS_UP)
|
||||
proto_notify_state(&p->p, PS_START);
|
||||
|
||||
tm_set(p->retry_timer, current_time() + 5 S);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -106,15 +115,17 @@ snmp_start(struct proto *P)
|
||||
{
|
||||
log(L_INFO "snmp_start() - starting timer (almost)");
|
||||
struct snmp_proto *p = (void *) P;
|
||||
struct snmp_config *cf = P->cf;
|
||||
struct snmp_config *cf = (struct snmp_config *) P->cf;
|
||||
|
||||
p->ping_timer = tm_new_init(p->p.pool, snmp_ping_timer, p, 0, 0);
|
||||
tm_set(p->ping_timer, current_time() + (2 S_));
|
||||
tm_set(p->ping_timer, current_time() + 2 S);
|
||||
|
||||
p->retry_timer = tm_new_init(p->p.pool, snmp_retry_timer, p, 0, 0);
|
||||
|
||||
/* starting agentX communicaiton channel */
|
||||
log(L_INFO "preparing lock");
|
||||
struct object_lock *lock;
|
||||
lock = p->lock = olock_new(P->pool);
|
||||
lock = p->lock = olock_new(p->p.pool);
|
||||
|
||||
lock->type = OBJLOCK_TCP;
|
||||
lock->hook = snmp_start_locked;
|
||||
@ -126,26 +137,29 @@ snmp_start(struct proto *P)
|
||||
log(L_INFO "local ip: %I:%u, remote ip: %I:%u",
|
||||
p->local_ip, p->local_port, p->remote_ip, p->remote_port);
|
||||
|
||||
init_list(p->bgp_entries);
|
||||
init_list(&p->bgp_entries);
|
||||
|
||||
/* create copy of bonds to bgp */
|
||||
HASH_INIT(p->peer_hash, p->p.pool, 10);
|
||||
HASH_INIT(p->bgp_hash, p->p.pool, 10);
|
||||
|
||||
struct snmp_bond *b;
|
||||
struct snmp_bond *b, *b2;
|
||||
WALK_LIST(b, cf->bgp_entries)
|
||||
{
|
||||
struct bgp_config *bc = b->proto;
|
||||
struct bgp_config *bc = (struct bgp_config *) b->proto;
|
||||
if (bc && !ipa_zero(bc->remote_ip))
|
||||
{
|
||||
struct snmp_bgp_peer_entry pe = {
|
||||
.bond = b;
|
||||
.peer_ip = bc->remote_ip;
|
||||
.next = NULL;
|
||||
};
|
||||
struct snmp_bgp_peer *peer =
|
||||
mb_allocz(p->p.pool, sizeof(struct snmp_bgp_peer));
|
||||
peer->bond = b;
|
||||
peer->peer_ip = bc->remote_ip;
|
||||
|
||||
HASH_INSERT(p->peer_hash, SNMP_HASH, pe)
|
||||
HASH_INSERT(p->bgp_hash, SNMP_HASH, peer);
|
||||
|
||||
add_tail(&p->bgp_entries, b);
|
||||
b2 = mb_allocz(p->p.pool, sizeof(struct snmp_bond));
|
||||
b2->proto = b->proto;
|
||||
b2->type = b->type;
|
||||
add_tail(&p->bgp_entries, NODE b2);
|
||||
mb_free(peer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,6 +176,7 @@ snmp_reconfigure(struct proto *P, struct proto_config *CF)
|
||||
p->remote_ip = cf->remote_ip;
|
||||
p->local_port = cf->local_port;
|
||||
p->remote_port = cf->remote_port;
|
||||
p->local_as = cf->local_as;
|
||||
p->timeout = 15;
|
||||
|
||||
/* TODO walk all bind protocols and find their (new) IP
|
||||
@ -192,7 +207,7 @@ static void snmp_show_proto_info(struct proto *P)
|
||||
cli_msg(-1006, " admin status: %s", (p->disabled) ? "start" :
|
||||
"stop");
|
||||
// version ?
|
||||
cli_msg(-1006, " version: ??, likely 4");
|
||||
cli_msg(-1006, " version: 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);
|
||||
@ -237,21 +252,59 @@ bp->stats.fsm_established_transitions);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
snmp_postconfig(struct proto_config *CF)
|
||||
{
|
||||
if (((struct snmp_config *) CF)->local_as == 0)
|
||||
cf_error("local as not specified");
|
||||
}
|
||||
|
||||
static void
|
||||
snmp_ping_timer(struct timer *tm)
|
||||
{
|
||||
log(L_INFO "snmp_ping_timer() ");
|
||||
struct snmp_proto *p = tm->data;
|
||||
|
||||
snmp_ping(p);
|
||||
if (p->state == SNMP_CONN)
|
||||
{
|
||||
snmp_ping(p);
|
||||
}
|
||||
|
||||
//tm_set(tm, current_time() + (7 S_));
|
||||
}
|
||||
|
||||
static void
|
||||
snmp_retry_timer(struct timer *tm)
|
||||
{
|
||||
log(L_INFO "snmp_retry_timer()");
|
||||
|
||||
struct snmp_proto *p = tm->data;
|
||||
|
||||
/* starting agentX communicaiton channel */
|
||||
log(L_INFO "preparing lock");
|
||||
struct object_lock *lock;
|
||||
lock = p->lock = olock_new(p->p.pool);
|
||||
|
||||
lock->type = OBJLOCK_TCP;
|
||||
lock->hook = snmp_start_locked;
|
||||
lock->data = p;
|
||||
|
||||
olock_acquire(lock);
|
||||
log(L_INFO "lock acquired");
|
||||
|
||||
log(L_INFO "local ip: %I:%u, remote ip: %I:%u",
|
||||
p->local_ip, p->local_port, p->remote_ip, p->remote_port);
|
||||
}
|
||||
|
||||
static int
|
||||
snmp_shutdown(struct proto *P)
|
||||
{
|
||||
struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
|
||||
p->state = SNMP_INIT;
|
||||
|
||||
tm_stop(p->ping_timer);
|
||||
tm_stop(p->retry_timer);
|
||||
|
||||
snmp_stop_subagent(p);
|
||||
return PS_DOWN;
|
||||
}
|
||||
@ -262,6 +315,7 @@ struct protocol proto_snmp = {
|
||||
.channel_mask = NB_ANY,
|
||||
.proto_size = sizeof(struct snmp_proto),
|
||||
.config_size = sizeof(struct snmp_config),
|
||||
.postconfig = snmp_postconfig,
|
||||
.init = snmp_init,
|
||||
.start = snmp_start,
|
||||
.reconfigure = snmp_reconfigure,
|
||||
|
@ -37,8 +37,8 @@
|
||||
|
||||
|
||||
/* hash table macros */
|
||||
#define SNMP_HASH_KEY(n) n->peer_ip;
|
||||
#define SNMP_HASH_NEXT(n) n->next;
|
||||
#define SNMP_HASH_KEY(n) n->peer_ip
|
||||
#define SNMP_HASH_NEXT(n) n->next
|
||||
#define SNMP_HASH_EQ(ip1, ip2) ipa_equal(ip1, ip2)
|
||||
#define SNMP_HASH_FN(ip) ipa_hash(ip)
|
||||
|
||||
@ -54,16 +54,17 @@ struct snmp_config {
|
||||
ip_addr remote_ip;
|
||||
u16 local_port;
|
||||
u16 remote_port;
|
||||
u32 local_as;
|
||||
u8 timeout;
|
||||
//struct iface *iface;
|
||||
list bgp_entries;
|
||||
};
|
||||
|
||||
struct snmp_bgp_peer_entry {
|
||||
struct snmp_bgp_peer {
|
||||
struct snmp_bond *bond;
|
||||
ip_addr peer_ip;
|
||||
struct snmp_bgp_peer_entry *next;
|
||||
}
|
||||
struct snmp_bgp_peer *next;
|
||||
};
|
||||
|
||||
struct snmp_proto {
|
||||
struct proto p;
|
||||
@ -73,6 +74,7 @@ struct snmp_proto {
|
||||
ip_addr remote_ip;
|
||||
u16 local_port;
|
||||
u16 remote_port;
|
||||
u32 local_as;
|
||||
|
||||
sock *sock;
|
||||
u8 timeout;
|
||||
@ -83,10 +85,11 @@ struct snmp_proto {
|
||||
|
||||
//struct iface *iface;
|
||||
// map goes here
|
||||
HASH(struct snmp_bgp_peer_entry) bgp_hash;
|
||||
HASH(struct snmp_bgp_peer) bgp_hash;
|
||||
struct tbf rl_gen;
|
||||
|
||||
timer *ping_timer;
|
||||
timer *retry_timer;
|
||||
u8 state;
|
||||
|
||||
list bgp_entries;
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "lib/unaligned.h"
|
||||
#include "subagent.h"
|
||||
#include "bgp_mib.h"
|
||||
|
||||
/* =============================================================
|
||||
* Problems
|
||||
@ -18,6 +19,7 @@
|
||||
* change of remote ip -> no notification, no update
|
||||
* same ip, different ports
|
||||
* distinct VRF (two interfaces with overlapping private addrs)
|
||||
* posible link-local addresses in LOCAL_IP
|
||||
*
|
||||
*/
|
||||
|
||||
@ -28,8 +30,13 @@ static inline uint vb_size(struct agentx_varbind *vb);
|
||||
static int snmp_stop_ack(sock *sk, uint size);
|
||||
static void do_response(struct snmp_proto *p, byte *buf, uint size);
|
||||
static int parse_get_pdu(struct snmp_proto *p, byte *buf, uint size);
|
||||
static void response_fail(struct snmp_proto *p, u16 err_no, u16 index);
|
||||
static byte *prepare_response(struct snmp_proto *p, byte *buf, uint size, u16 err_no, u16 index);
|
||||
static int parse_gets_pdu(struct snmp_proto *p, byte *buf, uint size);
|
||||
//static void response_fail(struct snmp_proto *p, u16 err_no, u16 index);
|
||||
static byte *prepare_response(struct snmp_proto *p, byte *buf, uint size);
|
||||
static void response_err_ind(byte *buf, uint err, uint ind);
|
||||
static struct oid *bgp_search(struct oid *o_start, struct oid *o_end, struct oid *o_curr);
|
||||
static struct oid *prefixize(struct snmp_proto *p, struct oid *o, int byte_ord);
|
||||
static inline byte *find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid, int byte_ord);
|
||||
|
||||
static const char * const snmp_errs[] = {
|
||||
#define SNMP_ERR_SHIFT 256
|
||||
@ -341,9 +348,16 @@ parse_pkt(struct snmp_proto *p, byte *buf, uint size)
|
||||
case AGENTX_RESPONSE_PDU:
|
||||
return parse_response(p, buf, size);
|
||||
|
||||
/*
|
||||
case AGENTX_GET_PDU:
|
||||
refresh_ids(p, h);
|
||||
return parse_get_pdu(p, buf, size);
|
||||
*/
|
||||
|
||||
case AGENTX_GET_PDU:
|
||||
case AGENTX_GET_NEXT_PDU:
|
||||
refresh_ids(p, h);
|
||||
return parse_gets_pdu(p, buf, size);
|
||||
|
||||
/* should not happen */
|
||||
default:
|
||||
@ -378,7 +392,7 @@ SNMP_ERR_SHIFT]);
|
||||
}
|
||||
|
||||
static void
|
||||
do_response(struct snmp_proto *p, byte *buf, uint size)
|
||||
do_response(struct snmp_proto *p, byte *buf, uint size UNUSED)
|
||||
{
|
||||
struct agentx_response *r = (void *) buf;
|
||||
struct agentx_header *h = &r->h;
|
||||
@ -401,34 +415,47 @@ do_response(struct snmp_proto *p, byte *buf, uint size)
|
||||
p->transaction_id++;
|
||||
|
||||
log(L_INFO "sending register-pdu");
|
||||
|
||||
// register whole BGP4-MIB
|
||||
u32 arr_bgp[] = {1, 15, 1};
|
||||
struct oid *o = mb_allocz(p->p.pool, 4 * 4);
|
||||
put_u8(&o->n_subid, 2);
|
||||
put_u8(&o->prefix, 2);
|
||||
|
||||
memcpy(o->ids, arr_bgp, 2 * 4);
|
||||
|
||||
snmp_register(p, o, 0, 1);
|
||||
|
||||
put_u8(&o->n_subid, 3);
|
||||
STORE(o->ids[2], arr_bgp[2]);
|
||||
snmp_register(p, o, 0, 1);
|
||||
|
||||
|
||||
STORE(o->ids[2], 2);
|
||||
snmp_register(p, o, 0, 1);
|
||||
|
||||
mb_free(o);
|
||||
|
||||
u32 arr_with_prefix[] = {1, 15, 3, 1, 1};
|
||||
struct oid *o2 = mb_allocz(p->p.pool, 10 * 4);
|
||||
put_u8(&o2->n_subid, 9);
|
||||
put_u8(&o2->prefix, 2);
|
||||
|
||||
put_u8(&o2->n_subid, 9);
|
||||
memcpy(o2->ids, arr_with_prefix, 5 * 4);
|
||||
u32 remote_addr[] = {10, 0, 0, 0};
|
||||
memcpy(o2->ids + 5, remote_addr, 4 * 4);
|
||||
STORE(o2->prefix, 2);
|
||||
|
||||
// register first line in BGP4-MIB bgpPeerTable
|
||||
// TODO register all bind bgp connections
|
||||
snmp_register(p, o2, 9, 24);
|
||||
|
||||
// register whole BGP4 mib-tree section
|
||||
u32 arr_bgp[] = {1, 15, 1};
|
||||
struct oid *o3 = mb_allocz(p->p.pool, 4 * 4);
|
||||
put_u8(&o3->n_subid, 3);
|
||||
put_u8(&o3->prefix, 2);
|
||||
|
||||
memcpy(o3->ids, arr_bgp, 3 * 4);
|
||||
|
||||
snmp_register(p, o3, 0, 1);
|
||||
mb_free(o2);
|
||||
|
||||
p->state = SNMP_REGISTR;
|
||||
//proto_notify_state(&p->p, PS_UP);
|
||||
break;
|
||||
|
||||
case SNMP_REGISTR:
|
||||
p->state = SNMP_CONN;
|
||||
break;
|
||||
|
||||
case SNMP_CONN:
|
||||
@ -452,68 +479,80 @@ parse_get_pdu(struct snmp_proto *p, byte *buf, uint size)
|
||||
return 0;
|
||||
|
||||
log(L_INFO "Get-PDU enough room %p", buf);
|
||||
|
||||
struct agentx_header *h = (void *) buf;
|
||||
int byte_ord = h->flags & AGENTX_NETWORK_BYTE_ORDER;
|
||||
ADVANCE(buf, size, AGENTX_HEADER_SIZE);
|
||||
log(L_INFO "advancing %p cause %u", buf, AGENTX_HEADER_SIZE);
|
||||
|
||||
int byte_ord = h->flags & AGENTX_NETWORK_BYTE_ORDER;
|
||||
|
||||
byte *pkt = buf;
|
||||
uint pkt_size = LOAD(h->payload, byte_ord);
|
||||
log(L_INFO "packet size is %u", pkt_size);
|
||||
log(L_INFO "RX packet size is %u", pkt_size);
|
||||
|
||||
uint clen;
|
||||
uint clen; /* context len */
|
||||
char *context = NULL;
|
||||
SNMP_LOAD_CONTEXT(p, h, pkt, context, clen)
|
||||
log(L_INFO "after context load %p, pkt == buf %d", pkt, pkt == buf);
|
||||
|
||||
/* parsing one search range */
|
||||
struct oid *o_start, *o_end;
|
||||
o_start = (struct oid *) pkt;
|
||||
pkt += oid_size(o_start);
|
||||
o_end = (struct oid *) pkt; // for Get-PDU always null
|
||||
pkt += oid_size(o_end);
|
||||
|
||||
log(L_INFO "sizes o_start %lu o_end %lu", oid_size(o_start),
|
||||
oid_size(o_end));
|
||||
|
||||
log(L_INFO " creating response header rpkt %p %u", res_pkt, res_pkt - res);
|
||||
log(L_INFO "o_subid: %u o_prefix %u o_include %u ---",
|
||||
o_start->n_subid, o_start->prefix, o_start->include);
|
||||
// TODO read a oid
|
||||
// TODO allow multiple values
|
||||
|
||||
res_pkt = prepare_response(p, res, rsize, AGENTX_RES_NO_ERROR, 0);
|
||||
res_pkt = prepare_response(p, res, rsize);
|
||||
log(L_INFO "response header created: %p (%u)", res_pkt, res_pkt - res);
|
||||
/* parsing one search range */
|
||||
uint ind = 1;
|
||||
int err = 0;
|
||||
/* parsed */
|
||||
while (!err && pkt - buf < pkt_size)
|
||||
{
|
||||
struct oid *o_start, *o_end;
|
||||
o_start = (struct oid *) pkt;
|
||||
pkt += oid_size(o_start);
|
||||
o_end = (struct oid *) pkt; // for Get-PDU always null
|
||||
pkt += oid_size(o_end);
|
||||
|
||||
res_pkt = request(res_pkt, o_start);
|
||||
struct agentx_varbind *vb_start;
|
||||
vb_start = (void *) res_pkt;
|
||||
log(L_INFO " SNMP_CREATEish rpkt %p %u", res_pkt, res_pkt - res);
|
||||
log(L_INFO "sizes o_start %lu o_end %lu", oid_size(o_start),
|
||||
oid_size(o_end));
|
||||
|
||||
memcpy(&vb_start->name, o_start, oid_size(o_start));
|
||||
STORE_16(vb_start->type, AGENTX_INTEGER);
|
||||
STORE_16(vb_start->pad, 0); // padding zeroing
|
||||
res_pkt += vb_size(vb_start);
|
||||
log(L_INFO "o_subid: %u o_prefix %u o_include %u ---",
|
||||
o_start->n_subid, o_start->prefix, o_start->include);
|
||||
|
||||
log(L_INFO " vb_size() rpkt %p %u", res_pkt, res_pkt - res);
|
||||
|
||||
STORE_PTR(res_pkt, 0x1234ABCD);
|
||||
|
||||
log(L_INFO " STORE_PTR int-value rpkt %p %u", res_pkt, res_pkt - res);
|
||||
res_pkt += 4;
|
||||
log(L_INFO " shift rpkt %p %u", res_pkt, res_pkt - res);
|
||||
|
||||
log(L_INFO "after integer write");
|
||||
/* currently unsupported non-default context */
|
||||
res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
|
||||
|
||||
/*
|
||||
struct agentx_varbind *vb_start;
|
||||
vb_start = (void *) res_pkt;
|
||||
|
||||
memcpy(&vb_start->name, o_start, oid_size(o_start));
|
||||
STORE_16(vb_start->type, AGENTX_INTEGER);
|
||||
STORE_16(vb_start->pad, 0); // padding zeroing
|
||||
res_pkt += vb_size(vb_start);
|
||||
|
||||
log(L_INFO " vb_size() rpkt %p %u", res_pkt, res_pkt - res);
|
||||
|
||||
STORE_PTR(res_pkt, 0x1234ABCD);
|
||||
|
||||
log(L_INFO " STORE_PTR int-value rpkt %p %u", res_pkt, res_pkt - res);
|
||||
res_pkt += 4;
|
||||
log(L_INFO " shift rpkt %p %u", res_pkt, res_pkt - res);
|
||||
*/
|
||||
ind++;
|
||||
}
|
||||
|
||||
struct agentx_header *rh = (void *) res;
|
||||
SNMP_UPDATE(rh, pkt_len(res, res_pkt));
|
||||
|
||||
if (err)
|
||||
response_err_ind(res, err, ind);
|
||||
|
||||
log(L_INFO "res->payload %u (loaded) %u, trying to send: %u",
|
||||
rh->payload, LOAD(rh->payload, rh->flags & AGENTX_NETWORK_BYTE_ORDER),
|
||||
res_pkt - res);
|
||||
res_pkt - res + 4);
|
||||
|
||||
int ret = sk_send(sk, res_pkt - res);
|
||||
log(L_INFO "message sent");
|
||||
|
||||
if (res == 0)
|
||||
if (ret == 0)
|
||||
log(L_INFO "sleep");
|
||||
else if (ret < 0)
|
||||
log(L_INFO "err no: %d", ret);
|
||||
@ -523,6 +562,126 @@ parse_get_pdu(struct snmp_proto *p, byte *buf, uint size)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* req is request */
|
||||
static int
|
||||
parse_gets_pdu(struct snmp_proto *p, byte *req, uint size)
|
||||
{
|
||||
log(L_INFO "parse_gets_pdu");
|
||||
|
||||
sock *sk = p->sock;
|
||||
byte *res_pkt, *res = sk->tbuf;
|
||||
uint rsize = sk->tbsize;
|
||||
|
||||
if (size < AGENTX_HEADER_SIZE)
|
||||
return 0;
|
||||
|
||||
struct agentx_header *h = (void *) req;
|
||||
ADVANCE(req, size, AGENTX_HEADER_SIZE);
|
||||
log(L_INFO "advancing %p cause header", req);
|
||||
|
||||
byte *pkt = req;
|
||||
|
||||
int byte_ord = h->flags & AGENTX_NETWORK_BYTE_ORDER;
|
||||
uint pkt_size = LOAD(h->payload, byte_ord);
|
||||
|
||||
uint clen;
|
||||
char *context;
|
||||
SNMP_LOAD_CONTEXT(p, h, req, context, clen);
|
||||
|
||||
res_pkt = prepare_response(p, res, rsize);
|
||||
uint ind = 1;
|
||||
int err = 0;
|
||||
while (!err && pkt - req < pkt_size)
|
||||
{
|
||||
struct oid *o_start, *o_end;
|
||||
o_start = (struct oid *) pkt;
|
||||
pkt += oid_size(o_start);
|
||||
o_end = (struct oid *) pkt;
|
||||
pkt += oid_size(o_end);
|
||||
|
||||
// TODO normalize OID to prefix form
|
||||
|
||||
/* advertised size of oid is greater then size of message */
|
||||
if (oid_size(o_start) > size || oid_size(o_end) > size)
|
||||
{
|
||||
err = -1; /* parse error too big n_subid */
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (h->type)
|
||||
{
|
||||
case AGENTX_GET_PDU:
|
||||
res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
|
||||
break;
|
||||
|
||||
case AGENTX_GET_NEXT_PDU:
|
||||
o_start = bgp_search(o_start, o_end, NULL);
|
||||
if (o_start)
|
||||
res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
|
||||
else
|
||||
{
|
||||
err = -2;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case AGENTX_GET_BULK_PDU:
|
||||
{
|
||||
struct oid *o_curr = NULL;
|
||||
/* TODO add res packet size limiting logic */
|
||||
while ((o_curr = bgp_search(o_start, o_end, o_curr)) != NULL)
|
||||
{
|
||||
res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
|
||||
}
|
||||
|
||||
/* no item found */
|
||||
if (res_pkt == res + sizeof(struct agentx_response))
|
||||
{
|
||||
err = -2;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ind++;
|
||||
}
|
||||
|
||||
switch (err)
|
||||
{
|
||||
case 0:
|
||||
response_err_ind(req, AGENTX_RES_NO_ERROR, 0);
|
||||
err = 1;
|
||||
break;
|
||||
case -1:
|
||||
response_err_ind(req, AGENTX_RES_PARSE_ERROR, ind);
|
||||
break;
|
||||
|
||||
/* no item found - could it happen? */
|
||||
case -2:
|
||||
response_err_ind(req, AGENTX_RES_GEN_ERROR, ind);
|
||||
break;
|
||||
}
|
||||
|
||||
struct agentx_header *rh = (void *) res;
|
||||
SNMP_UPDATE(rh, pkt_len(res, res_pkt));
|
||||
|
||||
int ret = sk_send(sk, res_pkt - res);
|
||||
log(L_INFO "message sent");
|
||||
|
||||
if (ret == 0)
|
||||
log(L_INFO "sleep");
|
||||
else if (ret < 0)
|
||||
log(L_INFO "err no: %d", ret);
|
||||
else
|
||||
log("OK ! !!");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
header_update_len(byte *buf, u32 len)
|
||||
{
|
||||
@ -552,9 +711,12 @@ snmp_stop_subagent(struct snmp_proto *p)
|
||||
log(L_INFO "snmp_stop_subagent()");
|
||||
sock *sk = p->sock;
|
||||
|
||||
close_pdu(p, AGENTX_CLOSE_SHUTDOWN);
|
||||
if (p->state == SNMP_CONN)
|
||||
{
|
||||
close_pdu(p, AGENTX_CLOSE_SHUTDOWN);
|
||||
|
||||
sk->rx_hook = snmp_stop_ack;
|
||||
sk->rx_hook = snmp_stop_ack;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint
|
||||
@ -652,12 +814,53 @@ snmp_agent_reconfigure(void)
|
||||
}
|
||||
*/
|
||||
|
||||
static int
|
||||
compare(struct oid *left, struct oid *right)
|
||||
{
|
||||
if (left->prefix < right->prefix)
|
||||
return -1;
|
||||
|
||||
else if (left->prefix > right->prefix)
|
||||
return 1;
|
||||
|
||||
for (int i = 0; i < MIN(left->n_subid, right->n_subid); i++)
|
||||
{
|
||||
if (left->ids[i] < right->ids[i])
|
||||
return -1;
|
||||
else if (left->ids[i] > right->ids[i])
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
is_bgp4_mib_prefix(struct oid *o)
|
||||
{
|
||||
if (o->prefix == 2 && o->ids[0] == 15)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct oid *
|
||||
bgp_search(struct oid *o_start, struct oid *e_end, struct oid *o_curr)
|
||||
{
|
||||
if (o_start->include);
|
||||
// if valid o_start
|
||||
|
||||
// search o_start.0 (resp. o_start.1)
|
||||
return o_start;
|
||||
}
|
||||
|
||||
static byte *
|
||||
find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *buf, uint size, uint contid)
|
||||
find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt, uint size, uint contid)
|
||||
{
|
||||
struct bgp_conn *b_conn = bp->conn;
|
||||
struct bgp_conn *b_in = bp->incomming_conn;
|
||||
struct bgp_conn *b_out = bp->outgoing_conn;
|
||||
struct bgp_conn *b_in = &bp->incoming_conn;
|
||||
struct bgp_conn *b_out = &bp->outgoing_conn;
|
||||
|
||||
struct bgp_stats *b_stats = &bp->stats;
|
||||
const struct bgp_config *b_conf = bp->cf;
|
||||
|
||||
uint b_state;
|
||||
|
||||
@ -672,122 +875,216 @@ find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *buf, uint size, uint co
|
||||
else
|
||||
b_state = MAX(b_in->state, b_out->state);
|
||||
|
||||
struct agentx_varbind *vb = (void *) buf;
|
||||
|
||||
struct agentx_varbind *vb = (void *) pkt;
|
||||
pkt += vb_size(vb);
|
||||
|
||||
switch (o->ids[4])
|
||||
{
|
||||
case SNMP_BGP_IDENTIFIER:
|
||||
if (b_state == BS_ESTABLISHED)
|
||||
STORE_PTR(pkt, ip_to_u32(b_conn->remote_ip));
|
||||
BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
|
||||
else if (b_state == BS_OPENCONFIRM)
|
||||
STORE_PTR(pkt, ip4_to_u32( (b_state == b_in->state) ? b_in->state : b_out->state));
|
||||
if (b_state == BS_OPENCONFIRM || b_state == BS_ESTABLISHED)
|
||||
{
|
||||
STORE_PTR(pkt, ipa_to_u32(bp->remote_ip));
|
||||
BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
|
||||
}
|
||||
else
|
||||
STORE_PTR(pkt, ip4_to_u32(IPA_NONE));
|
||||
{
|
||||
STORE_PTR(pkt, ipa_to_u32(IPA_NONE));
|
||||
BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
|
||||
}
|
||||
break;
|
||||
|
||||
case SNMP_BGP_STATE:
|
||||
STORE_PTR(pkt, b_state);
|
||||
BGP_DATA(vb, AGENTX_INTEGER, pkt);
|
||||
break;
|
||||
|
||||
case SNMP_BGP_ADMIN_STATUS:
|
||||
STORE_PTR(pkt, (bp->disabled) ? AGENTX_ADMIN_STOP : AGENTX_ADMIN_START);
|
||||
if (((struct proto *) bp)->disabled)
|
||||
STORE_PTR(pkt, AGENTX_ADMIN_STOP);
|
||||
else
|
||||
STORE_PTR(pkt, AGENTX_ADMIN_START);
|
||||
BGP_DATA(vb, AGENTX_INTEGER, pkt);
|
||||
break;
|
||||
|
||||
case SNMP_BGP_VERSION:
|
||||
STORE(pkt, BGP4_VERSIONS);
|
||||
STORE
|
||||
if (b_state == BS_OPENCONFIRM || b_state == BS_ESTABLISHED)
|
||||
STORE_PTR(pkt, 4);
|
||||
else
|
||||
STORE_PTR(pkt, 0);
|
||||
BGP_DATA(vb, AGENTX_INTEGER, pkt);
|
||||
break;
|
||||
|
||||
case SNMP_BGP_LOCAL_ADDR:
|
||||
// TODO XXX bp->link_addr & zero local_ip
|
||||
STORE_PTR(pkt, ipa_to_u32(bp->local_ip));
|
||||
BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
|
||||
break;
|
||||
|
||||
case SNMP_BGP_LOCAL_PORT:
|
||||
STORE_PTR(pkt, b_conf->local_port);
|
||||
BGP_DATA(vb, AGENTX_INTEGER, pkt);
|
||||
break;
|
||||
|
||||
case SNMP_BGP_REMOTE_ADDR:
|
||||
STORE_PTR(pkt, ipa_to_u32(bp->remote_ip));
|
||||
BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
|
||||
break;
|
||||
|
||||
case SNMP_BGP_REMOTE_PORT:
|
||||
STORE_PTR(pkt, b_conf->remote_port);
|
||||
BGP_DATA(vb, AGENTX_INTEGER, pkt);
|
||||
break;
|
||||
|
||||
case SNMP_BGP_REMOTE_AS:
|
||||
STORE_PTR(pkt, bp->remote_as);
|
||||
BGP_DATA(vb, AGENTX_INTEGER, pkt);
|
||||
break;
|
||||
|
||||
/* IN UPDATES */
|
||||
case SNMP_BGP_RX_UPDATES:
|
||||
STORE_PTR(pkt, b_stats->rx_updates);
|
||||
BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
|
||||
break;
|
||||
|
||||
/* OUT UPDATES */
|
||||
case SNMP_BGP_TX_UPDATES:
|
||||
STORE_PTR(pkt, b_stats->tx_updates);
|
||||
BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
|
||||
break;
|
||||
|
||||
/* IN MESSAGES */
|
||||
case SNMP_BGP_RX_MESSAGES:
|
||||
STORE_PTR(pkt, b_stats->rx_messages);
|
||||
BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
|
||||
break;
|
||||
|
||||
/* OUT MESSAGES */
|
||||
case SNMP_BGP_TX_MESSAGES:
|
||||
STORE_PTR(pkt, b_stats->tx_messages);
|
||||
BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
|
||||
break;
|
||||
|
||||
case SNMP_BGP_LAST_ERROR:
|
||||
STORE_PTR(pkt, 2);
|
||||
pkt += 4;
|
||||
/* force network order */
|
||||
put_u32(pkt,
|
||||
(bp->last_error_code << 8 | bp->last_error_code << 48) & 0xFFFF0000);
|
||||
/* real size is 8 but we already shifted the pkt by 4 */
|
||||
BGP_DATA(vb, AGENTX_OCTET_STRING, pkt);
|
||||
break;
|
||||
|
||||
case SNMP_BGP_FSM_TRANSITIONS:
|
||||
STORE_PTR(pkt, b_stats->fsm_established_transitions);
|
||||
BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
|
||||
break;
|
||||
|
||||
case SNMP_BGP_RETRY_INTERVAL:
|
||||
STORE_PTR(pkt, b_conf->connect_retry_time);
|
||||
BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
|
||||
break;
|
||||
|
||||
case SNMP_BGP_HOLD_TIME:
|
||||
if (b_conn && b_conf->hold_time)
|
||||
STORE_PTR(pkt, b_conn->hold_time);
|
||||
else
|
||||
STORE_PTR(pkt, 0);
|
||||
BGP_DATA(vb, AGENTX_INTEGER, pkt);
|
||||
break;
|
||||
|
||||
case SNMP_BGP_KEEPALIVE:
|
||||
if (b_conn && b_conf->keepalive_time)
|
||||
STORE_PTR(pkt, b_conn->keepalive_time);
|
||||
else
|
||||
STORE_PTR(pkt, 0);
|
||||
BGP_DATA(vb, AGENTX_INTEGER, pkt);
|
||||
break;
|
||||
|
||||
case SNMP_BGP_HOLD_TIME_CONFIGURED:
|
||||
STORE_PTR(pkt, b_conf->hold_time);
|
||||
BGP_DATA(vb, AGENTX_INTEGER, pkt);
|
||||
break;
|
||||
|
||||
case SNMP_BGP_KEEPALIVE_CONFIGURED:
|
||||
STORE_PTR(pkt, b_conf->keepalive_time);
|
||||
BGP_DATA(vb, AGENTX_INTEGER, pkt);
|
||||
break;
|
||||
|
||||
/* UNSUPPORTED */
|
||||
case SNMP_BGP_LAST_ERROR:
|
||||
|
||||
case SNMP_BGP_FSM_ESTABLISHED_TIME:
|
||||
|
||||
/* TODO XXX forbiden value 0 */
|
||||
case SNMP_BGP_ORIGINATION_INTERVAL:
|
||||
case SNMP_BGP_MIN_ROUTE_ADVERTISEMENT:
|
||||
case SNMP_BGP_MIN_UPDATE_ELAPSED_TIME:
|
||||
defualt:
|
||||
STORE_PTR(pkt, 0);
|
||||
BGP_DATA(vb, AGENTX_INTEGER, pkt);
|
||||
break;
|
||||
|
||||
case SNMP_BGP_FSM_ESTABLISHED_TIME:
|
||||
case SNMP_BGP_IN_UPDATE_ELAPSED_TIME:
|
||||
vb->type = AGENTX_NO_SUCH_OBJECT;
|
||||
/* pkt += 0; no data */
|
||||
break;
|
||||
|
||||
/* no default */
|
||||
}
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
||||
/* contid - context identification number */
|
||||
static byte *
|
||||
find_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid)
|
||||
snmp_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid)
|
||||
{
|
||||
struct agentx_varbind *vb = (void *) buf;
|
||||
|
||||
if (o->n_subid < 3)
|
||||
{
|
||||
vb->type = AGENTX_NO_SUCH_OBJECT;
|
||||
return buff + vb_size(vb);
|
||||
}
|
||||
|
||||
byte *pkt = buf + vb_size(vb);
|
||||
|
||||
switch (o->ids[2])
|
||||
{
|
||||
case BGP4_MIB_VERSION:
|
||||
vb->type = AGENTX_OCTET_STRING;
|
||||
STORE(pkt, BGP4_VERSIONS);
|
||||
pkt += 4;
|
||||
STORE_PTR(pkt, 1); // string len
|
||||
pkt += 4;
|
||||
STORE_PTR(pkt, BGP4_VERSIONS);
|
||||
/* real size is 8 but we already shifted the pkt by 4 */
|
||||
BGP_DATA(vb, AGENTX_OCTET_STRING, pkt);
|
||||
break;
|
||||
|
||||
case BGP4_MIB_LOCAL_AS:
|
||||
vb->type = AGENTX_INTEGER;
|
||||
// XXX local as to use
|
||||
STORE(pkt, p->local_as);
|
||||
pkt += 4;
|
||||
STORE_PTR(pkt, p->local_as);
|
||||
BGP_DATA(vb, AGENTX_INTEGER, pkt);
|
||||
break;
|
||||
|
||||
case BGP4_PEER_TABLE:
|
||||
/* end part of .1.3.6.1.2.1.15.3.1.x.a.b.c.d */
|
||||
if (o->n_subid < 9 || o->ids[3] != 1
|
||||
if (o->n_subid < 9 || o->ids[3] != BGP4_PEER_ENTRY
|
||||
|| o->ids[4] == 0 || o->ids[4] > 24)
|
||||
{
|
||||
vb->type = AGENTX_NO_SUCH_OBJECT;
|
||||
return buff + vb_size(vb);
|
||||
return buf + vb_size(vb);
|
||||
}
|
||||
|
||||
// TODO enumerate range requests
|
||||
ip_addr addr = ipa_build4(o->ids[5], o->ids[6], o->ids[7], o->ids[8]);
|
||||
struct snmp_bgp_peer_entry *pe =
|
||||
HASH_FIND(p->bgp_entries, SNMP_HASH, addr);
|
||||
struct snmp_bgp_peer *pe =
|
||||
HASH_FIND(p->bgp_hash, SNMP_HASH, addr);
|
||||
|
||||
struct bgp_proto *bp = NULL;
|
||||
if (pe && pe->bond->proto->proto &&
|
||||
ipa_equal(pe->bond->proto->proto->remote_ip, addr))
|
||||
ipa_equal(addr,
|
||||
((struct bgp_proto *) pe->bond->proto->proto)->remote_ip))
|
||||
{
|
||||
bp = pe->bond->proto->proto;
|
||||
bp = (void *) pe->bond->proto->proto;
|
||||
}
|
||||
|
||||
/* IF WE CONSIDER CHANGES OF REMOTE IP
|
||||
else
|
||||
{
|
||||
struct snmp_bond *b;
|
||||
WALK_LIST(b, p->bgp_entries)
|
||||
if (b->proto->proto &&
|
||||
ipa_equal(b->proto->proto->remote_ip, addr))
|
||||
bp = b->proto->proto;
|
||||
ipa_equal(((struct bgp_proto *) b->proto->proto)->remote_ip, addr))
|
||||
bp = (struct bgp_proto *) b->proto->proto;
|
||||
}
|
||||
*/
|
||||
|
||||
if (!bp)
|
||||
{
|
||||
@ -815,15 +1112,23 @@ find_ospf_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline byte *
|
||||
find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size)
|
||||
static byte *
|
||||
unsupported_oid(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid)
|
||||
{
|
||||
struct agetnx_varbind *vb = (void *) buf;
|
||||
struct agentx_varbind *vb = (void *) buf;
|
||||
vb->type = AGENTX_NO_SUCH_OBJECT;
|
||||
return buf + vb_size(vb);
|
||||
}
|
||||
|
||||
static inline byte *
|
||||
find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid)
|
||||
{
|
||||
struct agentx_varbind *vb = (void *) buf;
|
||||
|
||||
memcpy(&vb->name, o, oid_size(o));
|
||||
|
||||
/* SNMPv2 mgmt mib-2 */
|
||||
if (o->n_subid < 2 || (o->prefix != 2 && o->ides[0] != 1))
|
||||
/* SNMPv2 mgmt mib-2 */
|
||||
if (o->n_subid < 2 || (o->prefix != 2 && o->ids[0] != 1))
|
||||
{
|
||||
vb->type = AGENTX_NO_SUCH_OBJECT;
|
||||
return buf + vb_size(vb);
|
||||
@ -832,29 +1137,26 @@ find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size)
|
||||
switch (o->ids[1])
|
||||
{
|
||||
case SNMP_BGP4_MIB:
|
||||
return find_bgp_record(p, o, buf, size);
|
||||
if (snmp_bgp_is_supported(o))
|
||||
return snmp_bgp_record(p, o, buf, size, contid);
|
||||
else
|
||||
return unsupported_oid(p, o, buf, size, contid);
|
||||
|
||||
case SNMP_OSPFv3_MIB:
|
||||
return find_ospf_record(p, o, buf, size);
|
||||
|
||||
/* the old OSPF */
|
||||
case SNMP_OSPF_MIB:
|
||||
log("too old OSPF oid request");
|
||||
break;
|
||||
return unsupported_oid(p, o, buf, size, contid);
|
||||
//return find_ospf_record(p, o, buf, size);
|
||||
|
||||
default:
|
||||
return unsupported_oid(p, o, buf, size, contid);
|
||||
log(L_INFO "unsupported oid");
|
||||
break;
|
||||
}
|
||||
|
||||
vb->type = AGENTX_NO_SUCH_OBJECT;
|
||||
return buf + vb_size(vb);
|
||||
}
|
||||
|
||||
/* tests if there is present canonical "internet" prefix .1.3.6.1
|
||||
and if so it shortens the oid to the ``prefix'' form */
|
||||
static int
|
||||
prefixize(struct oid *o, int byte_ord)
|
||||
prefixize_in_place(struct oid *o, int byte_ord)
|
||||
{
|
||||
const u32 prefix[] = {1, 3, 6, 1};
|
||||
|
||||
@ -876,25 +1178,51 @@ prefixize(struct oid *o, int byte_ord)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline byte *
|
||||
find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, int byte_ord)
|
||||
static struct oid *
|
||||
prefixize(struct snmp_proto *p, struct oid *o, int byte_ord)
|
||||
{
|
||||
if (!o->prefix && prefixize(o, byte_ord))
|
||||
find_prefixed(p, o, buf, size);
|
||||
const u32 prefix[] = {1, 3, 6, 1};
|
||||
|
||||
if (o->n_subid < 5)
|
||||
return NULL;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
if (LOAD(o->ids[i], byte_ord) != prefix[i])
|
||||
return NULL;
|
||||
|
||||
struct oid *new = mb_alloc(p->p.pool, sizeof(struct oid) + MAX((o->n_subid - 5) * 4, 0));
|
||||
|
||||
memcpy(new, o, sizeof(struct oid));
|
||||
new->n_subid = o->n_subid - 5;
|
||||
|
||||
if (o->ids[4] < 256)
|
||||
new->prefix = o->ids[4];
|
||||
else return NULL;
|
||||
|
||||
memcpy(&new->ids, &o->ids[5], new->n_subid * 4);
|
||||
return new;
|
||||
}
|
||||
|
||||
static inline byte *
|
||||
find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid, int byte_ord)
|
||||
{
|
||||
struct oid *new;
|
||||
if (!o->prefix && (new = prefixize(p, o, byte_ord)) != NULL)
|
||||
find_prefixed(p, new, buf, size, contid);
|
||||
else if (o->prefix)
|
||||
find_prefixed(p, o, buf, size);
|
||||
find_prefixed(p, o, buf, size, contid);
|
||||
else
|
||||
// TODO handle unprefixable oids
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static byte *
|
||||
prepare_response(struct snmp_proto *p, byte *buf, uint size, u16 err_no, u16 index)
|
||||
prepare_response(struct snmp_proto *p, byte *buf, uint size)
|
||||
{
|
||||
log(L_INFO "prepare_response()");
|
||||
|
||||
if (size < sizeof(struct agentx_response))
|
||||
return NULL;
|
||||
|
||||
struct agentx_response *r = (void *) buf;
|
||||
struct agentx_header *h = &r->h;
|
||||
|
||||
@ -903,11 +1231,21 @@ prepare_response(struct snmp_proto *p, byte *buf, uint size, u16 err_no, u16 ind
|
||||
|
||||
/* protocol doesn't care about subagent upTime */
|
||||
STORE(r->uptime, 0);
|
||||
STORE_16(r->err, err_no);
|
||||
STORE_16(r->index, index);
|
||||
STORE_16(r->err, AGENTX_RES_NO_ERROR);
|
||||
STORE_16(r->index, 0);
|
||||
|
||||
buf += sizeof(struct agentx_response);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void
|
||||
response_err_ind(byte *buf, uint err, uint ind)
|
||||
{
|
||||
log(L_INFO "reponse_err_ind()");
|
||||
struct agentx_response *res = (void *) buf;
|
||||
|
||||
res->err = err;
|
||||
res->index = ind;
|
||||
}
|
||||
|
||||
#undef SNMP_ERR_SHIFT
|
||||
|
@ -14,20 +14,22 @@ void snmp_ping(struct snmp_proto *p);
|
||||
#define SNMP_BGP4_MIB 15 /* part of oid .1.3.6.1.2.1.15 */
|
||||
#define SNMP_OSPFv3_MIB 192 /* part of oid .1.3.6.1.2.1.192 */
|
||||
|
||||
#define BGP4_VERSIONS 0x10
|
||||
|
||||
enum agentx_type {
|
||||
AGENTX_INTEGER = 2;
|
||||
AGENTX_OCTET_STRING = 4;
|
||||
AGENTX_NULL = 5;
|
||||
AGENTX_OBJECT_ID = 6;
|
||||
AGENTX_IP_ADDRESS = 64;
|
||||
AGENTX_COUNTER_32 = 65;
|
||||
AGENTX_GAUGE_32 = 66;
|
||||
AGENTX_TIME_TICKS = 67;
|
||||
AGENTX_OPAQUE = 68;
|
||||
AGENTX_COUNTER_64 = 70;
|
||||
AGENTX_NO_SUCH_OBJECT = 128;
|
||||
AGENTX_NO_SUCH_INSTANCE = 129;
|
||||
AGENTX_END_OF_MIB_VIEW = 130;
|
||||
AGENTX_INTEGER = 2,
|
||||
AGENTX_OCTET_STRING = 4,
|
||||
AGENTX_NULL = 5,
|
||||
AGENTX_OBJECT_ID = 6,
|
||||
AGENTX_IP_ADDRESS = 64,
|
||||
AGENTX_COUNTER_32 = 65,
|
||||
AGENTX_GAUGE_32 = 66,
|
||||
AGENTX_TIME_TICKS = 67,
|
||||
AGENTX_OPAQUE = 68,
|
||||
AGENTX_COUNTER_64 = 70,
|
||||
AGENTX_NO_SUCH_OBJECT = 128,
|
||||
AGENTX_NO_SUCH_INSTANCE = 129,
|
||||
AGENTX_END_OF_MIB_VIEW = 130,
|
||||
} PACKED;
|
||||
|
||||
#define AGENTX_ADMIN_STOP 1
|
||||
@ -110,7 +112,7 @@ enum agentx_type {
|
||||
(v)->type = d; \
|
||||
p += o;
|
||||
|
||||
#define BGP_DATA(v, d, p) BGP_DATA(v, d, p, 4)
|
||||
#define BGP_DATA(v, d, p) BGP_DATA_(v, d, p, 4)
|
||||
|
||||
struct agentx_header {
|
||||
u8 version;
|
||||
@ -211,20 +213,33 @@ enum agentx_close_reasons {
|
||||
|
||||
/* RESPONSE_PDU - result error */
|
||||
enum agentx_response_err {
|
||||
AGENTX_RES_NO_ERROR = 0,
|
||||
AGENTX_RES_OPEN_FAILED = 256,
|
||||
AGENTX_RES_NOT_OPEN = 257,
|
||||
AGENTX_RES_INDEX_WRONG_TYPE = 258,
|
||||
AGENTX_RES_INDEX_ALREADY_ALLOC = 259,
|
||||
AGENTX_RES_INDEX_NONE_AVAIL = 260,
|
||||
AGENTX_RES_NOT_ALLOCATED = 261,
|
||||
AGENTX_RES_UNSUPPORTED_CONTEXT = 262,
|
||||
AGENTX_RES_DUPLICATE_REGISTR = 263,
|
||||
AGENTX_RES_UNKNOWN_REGISTR = 264,
|
||||
AGENTX_RES_UNKNOWN_AGENT_CAPS = 265,
|
||||
AGENTX_RES_PARSE_ERROR = 266,
|
||||
AGENTX_RES_REQUEST_DENIED = 267,
|
||||
AGENTX_RES_PROCESSING_ERR = 268,
|
||||
AGENTX_RES_NO_ERROR = 0,
|
||||
/* TEST_SET_PDU response errors */
|
||||
AGENTX_RES_GEN_ERROR = 5,
|
||||
AGENTX_RES_NO_ACCESS = 6,
|
||||
AGENTX_RES_WRONG_TYPE = 7,
|
||||
AGENTX_RES_WRONG_LENGTH = 8,
|
||||
AGENTX_RES_WRONG_ENCODING = 9,
|
||||
AGENTX_RES_WRONG_VALUE = 10,
|
||||
AGENTX_RES_NO_CREATION = 11,
|
||||
AGENTX_RES_INCONSISTENT_VALUE = 12,
|
||||
AGENTX_RES_RESOURCE_UNAVAILABLE = 13,
|
||||
AGENTX_RES_NOT_WRITEABLE = 17,
|
||||
AGENTX_RES_INCONSISTENT_NAME = 18,
|
||||
/* end of TEST_SET_PDU resonse errs */
|
||||
AGENTX_RES_OPEN_FAILED = 256,
|
||||
AGENTX_RES_NOT_OPEN = 257,
|
||||
AGENTX_RES_INDEX_WRONG_TYPE = 258,
|
||||
AGENTX_RES_INDEX_ALREADY_ALLOC = 259,
|
||||
AGENTX_RES_INDEX_NONE_AVAIL = 260,
|
||||
AGENTX_RES_NOT_ALLOCATED = 261,
|
||||
AGENTX_RES_UNSUPPORTED_CONTEXT = 262,
|
||||
AGENTX_RES_DUPLICATE_REGISTR = 263,
|
||||
AGENTX_RES_UNKNOWN_REGISTR = 264,
|
||||
AGENTX_RES_UNKNOWN_AGENT_CAPS = 265,
|
||||
AGENTX_RES_PARSE_ERROR = 266,
|
||||
AGENTX_RES_REQUEST_DENIED = 267,
|
||||
AGENTX_RES_PROCESSING_ERR = 268,
|
||||
} PACKED;
|
||||
|
||||
int snmp_rx(sock *sk, uint size);
|
||||
|
Loading…
x
Reference in New Issue
Block a user