0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-08 20:28:43 +00:00

TMP: compiles, some pdus working

This commit is contained in:
Vojtech Vilimek 2022-08-10 17:31:32 +02:00
parent a5bdba428b
commit 7961bbb26a
8 changed files with 718 additions and 108 deletions

View File

@ -9,6 +9,8 @@
#ifndef _BIRD_LISTS_H_ #ifndef _BIRD_LISTS_H_
#define _BIRD_LISTS_H_ #define _BIRD_LISTS_H_
#include "lib/birdlib.h"
/* /*
* I admit the list structure is very tricky and also somewhat awkward, * I admit the list structure is very tricky and also somewhat awkward,
* but it's both efficient and easy to manipulate once one understands the * but it's both efficient and easy to manipulate once one understands the

View File

@ -1,8 +1,8 @@
src := snmp.c bgp_mib.c subagent.c src := snmp.c subagent.c
obj := $(src-o-files) obj := $(src-o-files)
LIBS += `net-snmp-config --agent-libs` LIBS += `net-snmp-config --agent-libs`
$(all-daemon) $(all-daemon)
$(cf-local) $(cf-local)
$(call proto-build,snmp_build_) $(call proto-build,snmp_build)
tests_objs := $(tests_objs) $(src-o-files) tests_objs := $(tests_objs) $(src-o-files)

View File

@ -24,15 +24,16 @@
#undef PACKAGE_TARNAME #undef PACKAGE_TARNAME
#undef PACKAGE_VERSION #undef PACKAGE_VERSION
#include "proto/snmp/bgp_mib.h" #include "bgp_mib.h"
#include "lib/birdlib.h" #include "snmp.h"
static int static int
bgpPeerTable_handler( bgpPeerTable_handler(
netsnmp_mib_handler *handler, // contains void * for internal use netsnmp_mib_handler *handler, // contains void * for internal use
netsnmp_handler_registration *reginfo, netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo, netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests) { netsnmp_request_info *requests)
{
/* perform anything here that you need to do. The requests have /* perform anything here that you need to do. The requests have
already been processed by the master table_dataset handler, but already been processed by the master table_dataset handler, but

View File

@ -28,15 +28,32 @@ snmp_proto:
snmp_proto_start '{' snmp_proto_start '{'
| snmp_proto proto_item ';' | snmp_proto proto_item ';'
| snmp_proto snmp_bgp_bond ';' | snmp_proto snmp_bgp_bond ';'
| snmp_proto ';' | snmp_proto LOCAL PORT expr ';' { SNMP_CFG->local_port = $4; if (($4<1) ||
($4>65535)) cf_error("Invalid port number"); }
| 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))
cf_error("Invalid remote ip address"); }
; ;
snmp_proto_start: proto_start SNMP snmp_proto_start: proto_start SNMP
{ {
this_proto = proto_config_new(&proto_snmp, $1); this_proto = proto_config_new(&proto_snmp, $1);
init_list(&SNMP_CFG->bgp_entries); 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->timeout = 15;
} }
proto_name ;
snmp_bgp_bond: BGP symbol snmp_bgp_bond: BGP symbol
{ {
struct snmp_bond *this_bond = cfg_alloc(sizeof(struct snmp_bond)); struct snmp_bond *this_bond = cfg_alloc(sizeof(struct snmp_bond));

View File

@ -11,53 +11,142 @@
*/ */
#include "nest/bird.h" #include "nest/bird.h"
#include "nest/protocol.h"
#include "nest/cli.h" #include "nest/cli.h"
#include "nest/locks.h"
#include "lib/socket.h"
#include "proto/snmp/snmp.h" #include "snmp.h"
#include "proto/snmp/subagent.h" #include "subagent.h"
#include "proto/snmp/bgp_mib.h"
static void snmp_connected(sock *sk);
static void snmp_sock_err(sock *sk, int err);
static void snmp_ping_timer(struct timer *tm);
static struct proto * static struct proto *
snmp_init(struct proto_config *CF) snmp_init(struct proto_config *CF)
{ {
struct proto *P = proto_new(CF); struct proto *P = proto_new(CF);
struct snmp_proto *p = (void *) P; struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
struct snmp_config *cf = SKIP_BACK(struct snmp_config, cf, CF);
p->rl_gen = (struct tbf) TBF_DEFAULT_LOG_LIMITS; p->rl_gen = (struct tbf) TBF_DEFAULT_LOG_LIMITS;
p->local_ip = cf->local_ip;
p->remote_ip = cf->remote_ip;
p->local_port = cf->local_port;
p->remote_port = cf->remote_port;
// p->timeout = cf->timeout;
p->timeout = 15;
log(L_INFO "snmp_reconfigure() lip: %I:%u rip: %I:%u",
cf->local_ip, cf->local_port, cf->remote_ip, cf->remote_port);
return P; return P;
} }
void start_multihook(void) static void
snmp_start_locked(struct object_lock *lock)
{ {
/* init bgp MIB table */ log(L_INFO "snmp_start_locked() - preparing socket ");
snmp_init_bgp_table(); struct snmp_proto *p = lock->data;
/* init ospf MIB table */ sock *s = sk_new(p->p.pool);
//snmp_inti_ospf_table(); s->type = SK_TCP_ACTIVE;
s->saddr = p->local_ip;
s->daddr = p->remote_ip;
s->dport = p->remote_port;
s->rbsize = SNMP_RX_BUFFER_SIZE;
s->tbsize = SNMP_TX_BUFFER_SIZE;
// s->tos = IP_PREC_INTERNET_CONTROL
//s->rx_hook = snmp_connected;
s->tx_hook = snmp_connected;
s->err_hook = snmp_sock_err;
p->sock = s;
s->data = p;
if (sk_open(s) < 0)
log(L_ERR "Cannot open listening socket");
log(L_INFO "socket ready!, trying to connect");
}
static void
snmp_tx(sock *sk UNUSED)
{
log(L_INFO "snmp_tx() recieved something, yay!");
}
static void
snmp_connected(sock *sk)
{
struct snmp_proto *p = sk->data;
log(L_INFO "snmp_connected() connection created");
byte *buf UNUSED = sk->rbuf;
sk->rx_hook = snmp_rx;
sk->tx_hook = snmp_tx;
snmp_start_subagent(p);
}
static void
snmp_sock_err(sock *sk UNUSED, int err UNUSED)
{
log(L_INFO "snmp_sock_err() ");
} }
static int static int
snmp_start(struct proto *P) snmp_start(struct proto *P)
{ {
/* init MIB tables */ log(L_INFO "snmp_start() - starting timer (almost)");
if (snmp_start_subagent(start_multihook)) struct snmp_proto *p = (void *) P;
return PS_UP;
else p->ping_timer = tm_new_init(p->p.pool, snmp_ping_timer, p, 0, 0);
return PS_DOWN; tm_set(p->ping_timer, current_time() + (7 S_));
/* starting agentX communicaiton channel */
log(L_INFO "preparing lock");
struct object_lock *lock;
lock = p->lock = olock_new(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);
return PS_START;
} }
static int static int
snmp_reconfigure(struct proto *P, struct proto_config *CF) snmp_reconfigure(struct proto *P, struct proto_config *CF)
{ {
struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
struct snmp_config *cf = SKIP_BACK(struct snmp_config, cf, CF);
p->local_ip = cf->local_ip;
p->remote_ip = cf->remote_ip;
p->local_port = cf->local_port;
p->remote_port = cf->remote_port;
p->timeout = 15;
log(L_INFO "snmp_reconfigure() lip: %I:%u rip: %I:%u",
p->local_ip, p->local_port, p->remote_ip, p->remote_port);
return 0; return 0;
} }
static void static void
snmp_show_proto_info(struct proto *P) snmp_show_proto_info(struct proto *P)
{ {
struct snmp_proto *sp = (void *) P; //struct snmp_proto *sp = (void *) P;
struct snmp_config *c = (void *) P->cf; struct snmp_config *c = (void *) P->cf;
cli_msg(-1006, " BGP peers"); cli_msg(-1006, " BGP peers");
@ -66,7 +155,6 @@ snmp_show_proto_info(struct proto *P)
{ {
struct proto_config *cf = P->cf; struct proto_config *cf = P->cf;
struct bgp_config *bcf = (struct bgp_config *) cf; struct bgp_config *bcf = (struct bgp_config *) cf;
struct proto_config *pcf = (void *) bond->proto;
struct proto *p = cf->proto; struct proto *p = cf->proto;
struct bgp_proto *bp = (struct bgp_proto *) cf->proto; struct bgp_proto *bp = (struct bgp_proto *) cf->proto;
struct bgp_conn *conn = bp->conn; struct bgp_conn *conn = bp->conn;
@ -83,10 +171,12 @@ snmp_show_proto_info(struct proto *P)
cli_msg(-1006, " remote ip: %u", bcf->remote_ip); cli_msg(-1006, " remote ip: %u", bcf->remote_ip);
cli_msg(-1006, " local port: %u", bcf->local_port); cli_msg(-1006, " local port: %u", bcf->local_port);
cli_msg(-1006, " remote port: %u", bcf->remote_port); cli_msg(-1006, " remote port: %u", bcf->remote_port);
/*
if (conn) { if (conn) {
cli_msg(-1006, " state: %u", conn->state); cli_msg(-1006, " state: %u", conn->state);
cli_msg(-1006, " remote as: %u", conn->remote_caps->as4_number); cli_msg(-1006, " remote as: %u", conn->remote_caps->as4_number);
} }
*/
cli_msg(-1006, " in updates: %u", bp->stats.rx_updates); cli_msg(-1006, " in updates: %u", bp->stats.rx_updates);
cli_msg(-1006, " out updates: %u", bp->stats.tx_updates); cli_msg(-1006, " out updates: %u", bp->stats.tx_updates);
cli_msg(-1006, " in total: %u", bp->stats.rx_messages); cli_msg(-1006, " in total: %u", bp->stats.rx_messages);
@ -98,10 +188,12 @@ bp->stats.fsm_established_transitions);
cli_msg(-1006, " fsm total time: --"); cli_msg(-1006, " fsm total time: --");
cli_msg(-1006, " retry interval: %u", bcf->connect_retry_time); cli_msg(-1006, " retry interval: %u", bcf->connect_retry_time);
/*
if (conn) { if (conn) {
cli_msg(-1006, " hold time: %u", conn->hold_time); cli_msg(-1006, " hold time: %u", conn->hold_time);
cli_msg(-1006, " keep alive: %u", conn->keepalive_time ); cli_msg(-1006, " keep alive: %u", conn->keepalive_time );
} }
*/
cli_msg(-1006, " hold configurated: %u", bcf->hold_time ); cli_msg(-1006, " hold configurated: %u", bcf->hold_time );
cli_msg(-1006, " keep alive config: %u", bcf->keepalive_time ); cli_msg(-1006, " keep alive config: %u", bcf->keepalive_time );
@ -119,19 +211,22 @@ bp->stats.fsm_established_transitions);
} }
} }
static void
void snmp_ping_timer(struct timer *tm)
shutdown_multihook(void)
{ {
snmp_del_bgp_table(); log(L_INFO "snmp_ping_timer() ");
//snmp_del_ospf_table(); struct snmp_proto *p = tm->data;
// ping here
ping_pdu(p);
} }
/* snmp_shutdown already occupied by net-snmp */ /* snmp_shutdown already occupied by net-snmp */
void static int
snmp_shutdown_(struct proto *P) snmp_shutdown(struct proto *P)
{ {
snmp_stop_subagent(shutdown_multihook); struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
snmp_stop_subagent(p);
} }
struct protocol proto_snmp = { struct protocol proto_snmp = {
@ -143,13 +238,13 @@ struct protocol proto_snmp = {
.init = snmp_init, .init = snmp_init,
.start = snmp_start, .start = snmp_start,
.reconfigure = snmp_reconfigure, .reconfigure = snmp_reconfigure,
.shutdown = snmp_shutdown_, .shutdown = snmp_shutdown,
.show_proto_info = snmp_show_proto_info, .show_proto_info = snmp_show_proto_info,
}; };
/* strange name because conflict with net-snmp lib snmp_lib() */ /* strange name because of conflict with net-snmp lib snmp_lib() */
void void
snmp_build_(void) snmp_build(void)
{ {
proto_build(&proto_snmp); proto_build(&proto_snmp);
} }

View File

@ -8,15 +8,26 @@
*/ */
#ifndef _BIRD_SNMP_H_ #ifndef _BIRD_SNMP_H_
#define _BIRD_SNPM_H_ #define _BIRD_SNMP_H_
#include "lib/ip.h"
#include "lib/socket.h"
#include "lib/timer.h"
#include "nest/bird.h"
#include "nest/protocol.h"
#include "proto/bgp/bgp.h" #include "proto/bgp/bgp.h"
#define SNMP_UNDEFINED 0 #define SNMP_UNDEFINED 0
#define SNMP_BGP 1 #define SNMP_BGP 1
#define SNMP_OSPF 2 #define SNMP_OSPF 2
#define SNMP_INVALID 255 #define SNMP_INVALID 255
#define SNMP_PORT 705
#define SNMP_RX_BUFFER_SIZE 2048
#define SNMP_TX_BUFFER_SIZE 2048
struct snmp_bond { struct snmp_bond {
node n; node n;
struct proto_config *proto; struct proto_config *proto;
@ -24,13 +35,32 @@ struct snmp_bond {
}; };
struct snmp_config { struct snmp_config {
struct channel_config c; struct proto_config cf;
ip_addr local_ip;
ip_addr remote_ip;
u16 local_port;
u16 remote_port;
u8 timeout;
//struct iface *iface;
list bgp_entries; list bgp_entries;
}; };
struct snmp_proto { struct snmp_proto {
struct channel c; struct proto p;
struct object_lock *lock;
ip_addr local_ip;
ip_addr remote_ip;
u16 local_port;
u16 remote_port;
sock *sock;
u8 timeout;
u32 session_id;
u32 transaction_id;
u32 packet_id;
//struct iface *iface;
// map goes here
struct tbf rl_gen; struct tbf rl_gen;
timer *ping_timer;
}; };
struct snmp_channel_config { struct snmp_channel_config {
@ -43,4 +73,6 @@ struct snmp_channel {
struct channel c; struct channel c;
}; };
#endif #endif

View File

@ -6,89 +6,412 @@
* *
* Can be freely distributed and used under the terms of the GNU GPL. * 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> #include "lib/unaligned.h"
#include "subagent.h"
#ifdef HAVE_SIGNAL static int parse_response(struct snmp_proto *p, byte *buf, uint size);
#include <signal.h> static void header_update_len(byte *buf, u32 len);
#endif static uint oid_size(struct oid* o);
#ifdef HAV_SYS_STAT_H static const char * const snmp_errs[] = {
#include <sys/stat.h> #define SNMP_ERR_SHIFT 256
#endif [AGENTX_RES_OPEN_FAILED - SNMP_ERR_SHIFT] = "Open failed",
[AGENTX_RES_NOT_OPEN - SNMP_ERR_SHIFT] = "Not open",
[AGENTX_RES_INDEX_WRONG_TYPE - SNMP_ERR_SHIFT] = "Index wrong type",
[AGENTX_RES_INDEX_ALREADY_ALLOC - SNMP_ERR_SHIFT] = "Index already allocated",
[AGENTX_RES_INDEX_NONE_AVAIL - SNMP_ERR_SHIFT] = "Index none availlable",
[AGENTX_RES_NOT_ALLOCATED - SNMP_ERR_SHIFT] = "Not allocated",
[AGENTX_RES_UNSUPPORTED_CONTEXT - SNMP_ERR_SHIFT] = "Unsupported contex",
[AGENTX_RES_DUPLICATE_REGISTR - SNMP_ERR_SHIFT] = "Duplicate registration",
[AGENTX_RES_UNKNOWN_REGISTR - SNMP_ERR_SHIFT] = "Unknown registration",
[AGENTX_RES_UNKNOWN_AGENT_CAPS - SNMP_ERR_SHIFT] = "Unknown agent caps",
[AGENTX_RES_PARSE_ERROR - SNMP_ERR_SHIFT] = "Parse error",
[AGENTX_RES_REQUEST_DENIED - SNMP_ERR_SHIFT] = "Request denied",
[AGENTX_RES_PROCESSING_ERR - SNMP_ERR_SHIFT] = "Processing error",
};
#ifdef HAVE_FCNTL_H static int
#include <fcntl.h> put_str(byte *buf, const char *str, uint *size)
#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 */ uint len = strlen(str);
netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, uint pkt_len = BIRD_ALIGN(len, 4);
NETSNMP_DS_AGENT_ROLE, 1);
/* forking netsnmp mechanism * / if (len > MAX_STR)
if (netsnmp_daemonize(1, snmp_stderrolog_status()) != 0) return -1;
return 0; // start FAILED
*/
/* for Win32 only */ put_u32(buf, len);
SOCK_STARTUP;
/* init library */ memcpy(buf + 4, str, len);
init_agent("bird");
if (hook) // make the value 32-bit aligned
hook(); for (uint i = 0; i < pkt_len - len; i++)
buf[len + i] = 0x00; // PADDING
/* used for loading config 'bird-snmp.conf' */ *size += (4 + pkt_len);
init_snmp("bird-snmp");
return 1; // SUCCESS return 0;
} }
static void
put_blank(byte *buf, uint *size)
{
buf[0] = buf[1] = buf[2] = buf[3] = 0;
*size += 4;
}
static void
put_oid(byte *buf, struct oid *oid, uint *size)
{
put_u8(buf, oid->n_subid);
put_u8(buf + 1, oid->prefix);
put_u8(buf + 2, oid->include);
put_u8(buf + 3, 0); // PADDING
put_u32s(buf + 4, oid->subid.ids, oid->subid.len);
*size += (4 + oid->subid.len);
}
/* paste data at first byte in message
* with 3B of padding
*/
static void
paste_fbyte(byte *buf, u8 data, uint *size)
{
buf[0] = data;
buf[1] = buf[2] = buf[3] = 0x00; // PADDING
*size += 4;
}
static u32
store_in_order(u32 val, int order)
{
/* AGENTX_BIG_ENDIAN */
if (order)
{
}
else
{
}
return 0;
}
static void
open_pdu(struct snmp_proto *p, struct oid *oid)
{
sock *sk = p->sock;
byte *buf, *pkt, *end;
buf = pkt = sk->tbuf;
uint size = sk->tbsize;
// should be configurable
const char *str = "bird";
uint pkt_size = 0;
uint slen = BIRD_ALIGN(strlen(str), 4);
/* +8 - header of oid (4) and octet string length (4) */
if (size > AGENTX_HEADER_SIZE + oid->subid.len + slen + 8)
{
log(L_INFO "open_pdu() sufficient size nw order: %u",
AGENTX_NETWORK_BYTE_ORDER);
PASTE_HEADER(pkt, AGENTX_OPEN_PDU, AGENTX_NETWORK_BYTE_ORDER, size);
// use random num instead
put_u32(&h->session_id, 1);
put_u32(&h->transaction_id, 1);
put_u32(&h->packet_id, 1);
paste_fbyte(pkt, p->timeout, &pkt_size);
ADVANCE(pkt, size, 4);
put_oid(pkt, oid, &pkt_size);
ADVANCE(pkt, size, oid_size(oid));
/* paste description */
put_str(pkt, str, &pkt_size);
ADVANCE(pkt, size, slen);
header_update_len(buf, pkt_size);
log(L_INFO "sk_send()-ing %u", AGENTX_HEADER_SIZE + pkt_size);
int ret = sk_send(sk, AGENTX_HEADER_SIZE + pkt_size);
if (ret == 0)
log(L_INFO "sleep");
else if (ret < 0)
log(L_INFO "err %d", ret);
else
log(L_INFO "ok !!! ");
}
else
log(L_INFO "open_pdu() insufficient size, %u <= %u ",
size, AGENTX_HEADER_SIZE + oid->subid.len + slen + 8);
}
static void
close_pdu(struct snmp_proto *p, u8 reason)
{
sock *sk = p->sock;
byte *buf, *pkt;
buf = pkt = sk->tbuf;
uint size = sk->tbsize;
log(L_INFO "close_pdu() size: %u %c %u", size, (size > AGENTX_HEADER_SIZE + 4)
? '>':'<', AGENTX_HEADER_SIZE);
/* +4B for reason */
if (size > AGENTX_HEADER_SIZE + 4)
{
PASTE_HEADER(buf, AGENTX_CLOSE_PDU, AGENTX_NETWORK_BYTE_ORDER, size);
log(L_INFO "session_id %u", p->session_id);
h->session_id = p->session_id;
p->transaction_id++;
p->transaction_id = get_u32(&p->transaction_id);
put_u32(&h->transaction_id, p->transaction_id);
put_u32(&h->packet_id, 1);
ADVANCE(pkt, size, sizeof(struct agentx_header));
paste_fbyte(pkt, reason, &size);
ADVANCE(pkt, size, 4);
/* 4 - reason size */
header_update_len(sk->tbuf, 4);
int ret = sk_send(sk, sizeof(struct agentx_header) + 4);
if (ret == 0)
log(L_INFO "sleep");
else if (ret < 0)
log(L_INFO "err");
else
log(L_INFO, "ok !! ");
}
}
static int
parse_pkt(struct snmp_proto *p, byte *buf, uint size)
{
if (size < AGENTX_HEADER_SIZE)
return 0;
struct agentx_header *h = (void *) buf;
switch (h->type)
{
case AGENTX_RESPONSE_PDU:
return parse_response(p, buf, size);
break;
/* should not happen */
default:
die("unknown packet type");
}
}
static int
parse_response(struct snmp_proto *p, byte *buf, uint size)
{
if (size < sizeof(struct agentx_response))
return 0;
struct agentx_response *r = (void *) buf;
struct agentx_header *h = &r->h;
log(L_INFO "endianity: %s, session %u", (h->flags & AGENTX_NETWORK_BYTE_ORDER) ? "big end":
"little end", h->session_id);
p->session_id = h->session_id;
p->transaction_id = h->transaction_id;
p->packet_id = h->packet_id;
log(L_INFO "size %u", get_u32(&h->payload));
log(L_INFO "uptime: %u s", get_u32(&r->uptime));
switch (r->err)
{
case AGENTX_RES_NO_ERROR:
break;
default:
log(L_INFO "an error occured: '%s'", snmp_errs[get_u16(&r->err) -
SNMP_ERR_SHIFT]);
break;
}
proto_notify_state(&p->p, PS_UP);
return 1;
}
static void
header_update_len(byte *buf, u32 len)
{
struct agentx_header *h = (void *) buf;
put_u32(&h->payload, len);
log(L_INFO "header_update_len() %d 0x%02X 0x%02X 0x%02X 0x%02X", len, *((unsigned char
*) &h->payload), *(((unsigned char *) &h->payload) + 1), *(((unsigned char *)
&h->payload) + 2), *(((unsigned char *) &h->payload) + 3));
}
void
snmp_start_subagent(struct snmp_proto *p)
{
log(L_INFO "snmp_start_subagent() starting subagent");
/* blank oid means unsupported */
struct oid *o = mb_allocz(p->p.pool, sizeof(struct oid));
open_pdu(p, o);
mb_free(o);
}
void
snmp_stop_subagent(struct snmp_proto *p)
{
sock *sk = p->sock;
close_pdu(p, AGENTX_CLOSE_SHUTDOWN);
sk->rx_hook = snmp_stop_ack;
}
static uint
oid_size(struct oid *o)
{
return 4 + o->subid.len;
}
int
snmp_rx(sock *sk, uint size)
{
log(L_INFO "snmp_rx()");
struct snmp_proto *p = sk->data;
byte *pkt = sk->rbuf;
byte *end = pkt + size;
parse_pkt(p, pkt, size);
/*
while (end >= ptk + AGENTX_HEADER_SIZE)
{
parse_header(p);
parse_pkt(p, );
}
*/
return 0;
// 1 means all done
}
void
ping_pdu(struct snmp_proto *p)
{
/* this does not support non-default context */
sock *sk = p->sock;
byte *buf = sk->tbuf;
uint size = sk->tbsize;
PASTE_HEADER(buf, AGENTX_PING_PDU, AGENTX_NETWORK_BYTE_ORDER, size);
put_u32(&h->session_id, p->session_id);
p->transaction_id++;
put_u32(&h->transaction_id, p->transaction_id);
put_u32(&h->packet_id, 1);
put_u32(&h->payload, 0);
sk_send(sk, AGENTX_HEADER_SIZE);
}
/*
* cont is optional context
* upp_b is upper_bond
*/
int
snmp_register_oid(sock *sk, struct oid *subtree, u8 range, const char *cont, u32 upp_b)
{
struct snmp_proto *p = sk->data;
byte *buf = sk->tbuf;
uint size = sk->tbsize;
log(L_INFO "snmp_register_oid() ");
u8 flags = AGENTX_NETWORK_BYTE_ORDER | ((cont) ? AGENTX_NON_DEFAULT_CONTEXT :
0);
PASTE_HEADER(buf, AGENTX_REGISTER_PDU, flags, size);
if (cont)
put_str(buf, cont, &size);
put_u8(buf, p->timeout);
put_u8(buf + 1, AGENTX_PRIORITY);
put_u8(buf + 2, range);
put_u8(buf + 3, 0); // PADDING
ADVANCE(buf, size, 4);
put_oid(buf, subtree, &size);
ADVANCE(buf, size, oid_size(subtree));
if (upp_b)
{
put_u32(buf, upp_b);
ADVANCE(buf, size, 4);
}
header_update_len(sk->tbuf, buf - sk->tbuf + AGENTX_HEADER_SIZE);
sk_send(sk, buf - sk->tbuf);
}
/*
* cont is optional context nullable
* upp_b is upper_bond
*/
int
snmp_unregister_oid(sock *sk, struct oid *subtree, const char *cont, u32 upp_b)
{
byte *buf = sk->tbuf;
uint size = sk->tbsize;
log(L_INFO "snmp_unregister_oid()");
u8 flags = AGENTX_NETWORK_BYTE_ORDER | ((cont) ? AGENTX_NON_DEFAULT_CONTEXT :
0);
PASTE_HEADER(buf, AGENTX_UNREGISTER_PDU, flags, size);
if (cont)
{
put_str(buf, cont, &size);
ADVANCE(buf, size, strlen(cont) + 4);
}
put_oid(buf, subtree, &size);
ADVANCE(buf, size, oid_size(subtree));
if (upp_b)
{
put_u32(buf, upp_b);
ADVANCE(buf, size, 4);
}
sk_send(sk, buf - sk->tbuf);
}
static void
snmp_stop_ack(sock *sk, uint size)
{
struct snmp_proto *p = sk->data;
byte *buf = sk->rbuf;
if (size < AGENTX_HEADER_SIZE)
return 0;
if (parse_response(p, buf, size))
{
p->p.disabled = 1;
proto_notify_state(&p->p, PS_DOWN);
}
}
/*
void void
snmp_agent_reconfigure(void) snmp_agent_reconfigure(void)
{ {
free_config();
read_configs();
} }
*/
void #undef SNMP_ERR_SHIFT
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();
}

View File

@ -1,8 +1,148 @@
#ifndef _BIRD_SNMP_SUBAGENT_H_ #ifndef _BIRD_SNMP_SUBAGENT_H_
#define _BIRD_SNMP_SUBAGENT_H_ #define _BIRD_SNMP_SUBAGENT_H_
int snmp_start_subagent(void (*hook)(void)); #include "nest/bird.h"
void snmp_agent_reconfigure(void); #include "snmp.h"
void snmp_stop_subagent(void (*hook)(void));
void snmp_start_subagent(struct snmp_proto *p);
void snmp_stop_subagent(struct snmp_proto *p);
#define AGENTX_INTEGER 2
#define AGENTX_OCTET_STRING 4
#define AGENTX_NULL 5
#define AGENTX_OBJECT_ID 6
#define AGENTX_IP_ADDRESS 64
#define AGENTX_COUNTER_32 65
#define AGENTX_GAUGE_32 66
#define AGENTX_TIME_TICKS 67
#define AGENTX_OPAQUE 68
#define AGENTX_COUNTER_64 70
#define AGENTX_NO_SUCH_OBJECT 128
#define AGENTX_NO_SUCH_INSTANCE 129
#define AGENTX_END_OF_MIB_VIEW 130
#define AGENTX_PRIORITY 127
#define MAX_STR 0xFFFFFFFF
#define PASTE_HEADER_(buf, v, t, f, s) \
memset(buf, 0, sizeof(struct agentx_header)); \
struct agentx_header *h = (void *) buf; \
log(L_INFO "value : %d", (void *) h == buf? 1:0); \
h->version = v; \
h->type = t; \
h->flags = f; \
h->pad = 0; \
ADVANCE(buf, s, sizeof(struct agentx_header)); \
#define PASTE_HEADER(buf, t, f, s) PASTE_HEADER_(buf, AGENTX_VERSION, t, f, s)
#define U32_CPY(w, u) memcpy((w), (u), 4); ADVANCE((w), 4, 4);
struct agentx_header {
u8 version;
u8 type;
u8 flags;
u8 pad;
u32 session_id;
u32 transaction_id;
u32 packet_id;
u32 payload; /* length of the packet without header */
};
#define AGENTX_HEADER_SIZE sizeof(struct agentx_header)
struct subid{
u32 len;
u32 ids[];
};
struct oid {
u8 n_subid;
u8 prefix;
u8 include;
u8 pad;
struct subid subid;
};
struct agentx_varbind {
u16 type;
u16 pad;
/* oid part */
struct oid name;
};
struct agentx_search_range {
struct oid start;
struct oid end;
};
struct agentx_response {
struct agentx_header h;
u32 uptime;
u16 err;
u16 index;
};
#define AGENTX_VERSION 1
enum agentx_pdu {
AGENTX_OPEN_PDU = 1,
AGENTX_CLOSE_PDU = 2,
AGENTX_REGISTER_PDU = 3,
AGENTX_UNREGISTER_PDU = 4,
AGENTX_GET_PDU = 5,
AGENTX_GET_NEXT_PDU = 6,
AGENTX_GET_BULK_PDU = 7,
AGENTX_TEST_SET_PDU = 8,
AGENTX_COMMIT_SET_PDU = 9,
AGENTX_UNDO_SET_PDU = 10,
AGENTX_CLEANUP_SET_PDU = 11,
AGENTX_NOTIFY_PDU = 12,
AGENTX_PING_PDU = 13,
AGENTX_INDEX_ALLOCATE_PDU = 14,
AGENTX_INDEX_DEALLOCATE_PDU = 15,
AGENTX_ADD_AGENT_CAPS_PDU = 16,
AGENTX_REMOVE_AGENT_CAPS_PDU = 17,
AGENTX_RESPONSE_PDU = 18,
} PACKED;
#define AGENTX_FLAGS_MASK 0x1F
enum agentx_flags {
AGENTX_FLAG_INSTANCE_REGISTRATION = 0x01,
AGENTX_FLAG_NEW_INDEX = 0x02,
AGENTX_FLAG_ANY_INDEX = 0x04,
AGENTX_NON_DEFAULT_CONTEXT = 0x08,
AGENTX_NETWORK_BYTE_ORDER = 0x10,
} PACKED;
/* CLOSE_PDU close reasons */
enum agentx_close_reasons {
AGENTX_CLOSE_OTHER = 1,
AGENTX_CLOSE_PARSE_ERROR = 2,
AGENTX_CLOSE_PROTOCOL_ERROR = 3,
AGENTX_CLOSE_TIMEOUTS = 4,
AGENTX_CLOSE_SHUTDOWN = 5,
AGENTX_CLOSE_BY_MANAGER = 6,
} PACKED;
/* 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,
} PACKED;
int snmp_rx(sock *sk, uint size);
#endif #endif