2024-01-23 23:23:31 +00:00
|
|
|
/** BIRD -- Simple Network Management Protocol (SNMP) *
|
2022-08-01 11:01:49 +00:00
|
|
|
* (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.
|
|
|
|
*/
|
|
|
|
|
2023-09-04 07:25:51 +00:00
|
|
|
/**
|
2023-11-16 06:11:14 +00:00
|
|
|
* DOC: Simple Network Management Protocol
|
|
|
|
*
|
|
|
|
* The SNMP protocol is divided into several parts: |snmp.c| which implements
|
|
|
|
* the BIRD intergration, |subagent.c| contains functions for creating and
|
2024-05-24 13:20:30 +00:00
|
|
|
* parsing packets, |bgp4_mib.c| takes care of the bgp MIB subtree of standard
|
2023-11-16 06:11:14 +00:00
|
|
|
* BGP4-MIB and |snmp_utils.c| which is collections of helper functions for
|
|
|
|
* working with OIDs, VarBinds.
|
|
|
|
*
|
|
|
|
* Althrough called SNMP the BIRD does not implement SNMP directly but acts as
|
|
|
|
* an AgentX subagent. AgentX subagent connects to AgentX master agent that
|
|
|
|
* processes incomming SNMP requests and passes them down to the correct
|
|
|
|
* subagent. Therefore you need also a running master agent somewhere.
|
|
|
|
* Advantages of this design are that you are capable of doing aggregation of
|
|
|
|
* statuses of multiple BIRDs at the master agent level and much simpler
|
|
|
|
* implementation.
|
|
|
|
*
|
|
|
|
* Before any of the SNMP request could be processed, the SNMP need to
|
|
|
|
* established AgentX session with the master agent and need to register all
|
|
|
|
* subtrees to make them accessible from the master agent. The establishement of
|
|
|
|
* the of session is handled by snmp_start(), snmp_start_locked() and
|
|
|
|
* snmp_start_subagent(). Then we register all MIBs from configuration in
|
|
|
|
* snmp_register_mibs().
|
|
|
|
*
|
|
|
|
* The AgentX request are handled only during MIB subtree registrations and
|
|
|
|
* after then on established session (in states SNMP_REGISTER and SNMP_CONN, see
|
|
|
|
* below). It is also guaranteed that no request is received before MIB subtree
|
|
|
|
* registration because the specific subagent is not authoratitave and also the
|
|
|
|
* master agent has no info about MIB subtree supported by subagent. The AgentX
|
|
|
|
* requests are handled by function snmp_rx() in |subagent.c|.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* SNMP State Machine
|
2023-09-04 07:25:51 +00:00
|
|
|
*
|
|
|
|
* States with main transitions
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* +-----------------+
|
|
|
|
* | SNMP_INIT | entry state after call snmp_start()
|
|
|
|
* +-----------------+
|
|
|
|
* |
|
|
|
|
* | acquiring object lock for communication socket
|
|
|
|
* V
|
|
|
|
* +-----------------+
|
|
|
|
* | SNMP_LOCKED | object lock aquired
|
|
|
|
* +-----------------+
|
|
|
|
* |
|
2023-10-25 10:41:23 +00:00
|
|
|
* | opening communication socket
|
2023-09-04 07:25:51 +00:00
|
|
|
* V
|
|
|
|
* +-----------------+
|
|
|
|
* | SNMP_OPEN | socket created, starting subagent
|
|
|
|
* +-----------------+
|
|
|
|
* |
|
2023-11-08 09:55:42 +00:00
|
|
|
* | BIRD receive response for Open-PDU
|
2023-09-04 07:25:51 +00:00
|
|
|
* V
|
|
|
|
* +-----------------+
|
|
|
|
* | SNMP_REGISTER | session was established, subagent registers MIBs
|
|
|
|
* +-----------------+
|
|
|
|
* |
|
2023-11-08 09:55:42 +00:00
|
|
|
* | subagent received responses for all registration requests
|
2023-09-04 07:25:51 +00:00
|
|
|
* V
|
|
|
|
* +-----------------+
|
|
|
|
* | SNMP_CONN | everything is set
|
|
|
|
* +-----------------+
|
|
|
|
* |
|
|
|
|
* | function snmp_shutdown() is called, BIRD sends Close-PDU
|
|
|
|
* V
|
|
|
|
* +-----------------+
|
|
|
|
* | SNMP_STOP | waiting for response
|
|
|
|
* +-----------------+
|
|
|
|
* |
|
|
|
|
* | cleaning old state information
|
|
|
|
* V
|
|
|
|
* +-----------------+
|
|
|
|
* | SNMP_DOWN | session is closed
|
|
|
|
* +-----------------+
|
|
|
|
*
|
|
|
|
*
|
2023-10-25 10:56:23 +00:00
|
|
|
* +-----------------+
|
|
|
|
* | SNMP_RESET | waiting to transmit response to malformed packet
|
|
|
|
* +-----------------+
|
|
|
|
* |
|
|
|
|
* | response was send, reseting the session (with socket)
|
|
|
|
* |
|
|
|
|
* \--> SNMP_LOCKED
|
|
|
|
*
|
|
|
|
*
|
2023-09-04 07:25:51 +00:00
|
|
|
* Erroneous transitions:
|
|
|
|
* SNMP is UP in states SNMP_CONN and also in SNMP_REGISTER because the
|
|
|
|
* session is establised and the GetNext request should be responsed
|
|
|
|
* without regard to MIB registration.
|
|
|
|
*
|
2023-11-08 09:55:42 +00:00
|
|
|
* When the session has been closed for some reason (socket error, receipt of
|
2023-09-04 07:25:51 +00:00
|
|
|
* Close-PDU) SNMP cleans the session information and message queue and goes
|
|
|
|
* back to the SNMP_LOCKED state.
|
|
|
|
*
|
|
|
|
* Reconfiguration is done in similar fashion to BGP, the reconfiguration
|
|
|
|
* request is declined, the protocols is stoped and started with new
|
|
|
|
* configuration.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2022-08-01 11:01:49 +00:00
|
|
|
#include "nest/bird.h"
|
|
|
|
#include "nest/cli.h"
|
2022-08-10 15:31:32 +00:00
|
|
|
#include "nest/locks.h"
|
|
|
|
#include "lib/socket.h"
|
2022-09-20 12:28:57 +00:00
|
|
|
#include "lib/lists.h"
|
2022-08-01 11:01:49 +00:00
|
|
|
|
2022-08-10 15:31:32 +00:00
|
|
|
#include "snmp.h"
|
|
|
|
#include "subagent.h"
|
2023-07-26 12:34:01 +00:00
|
|
|
#include "snmp_utils.h"
|
2024-07-04 14:33:44 +00:00
|
|
|
#include "mib_tree.h"
|
2022-08-10 15:31:32 +00:00
|
|
|
|
2024-07-09 14:56:16 +00:00
|
|
|
// TODO: remove me
|
|
|
|
#include "proto/bgp/bgp.h"
|
|
|
|
|
|
|
|
|
2023-11-15 14:03:55 +00:00
|
|
|
static void snmp_start_locked(struct object_lock *lock);
|
|
|
|
static void snmp_sock_err(sock *sk, int err);
|
|
|
|
static void snmp_stop_timeout(timer *tm);
|
|
|
|
static void snmp_cleanup(struct snmp_proto *p);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* snmp_rx_skip - skip all received data
|
|
|
|
* @sk: communication socket
|
|
|
|
* @size: size of received PDUs
|
|
|
|
*
|
|
|
|
* Socket rx_hook used when we are reseting the connection due to malformed PDU.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
snmp_rx_skip(sock UNUSED *sk, uint UNUSED size)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2024-01-10 11:21:46 +00:00
|
|
|
* snmp_tx_skip - handle empty TX-buffer during session reset
|
2023-11-15 14:03:55 +00:00
|
|
|
* @sk: communication socket
|
|
|
|
*
|
|
|
|
* The socket tx_hook is called when the TX-buffer is empty, i.e. all data was
|
|
|
|
* send. This function is used only when we found malformed PDU and we are
|
2024-01-23 23:23:31 +00:00
|
|
|
* resetting the established session. If called, we are reseting the session.
|
2023-11-15 14:03:55 +00:00
|
|
|
*/
|
|
|
|
static void
|
2024-01-10 11:21:46 +00:00
|
|
|
snmp_tx_skip(sock *sk)
|
2023-11-15 14:03:55 +00:00
|
|
|
{
|
|
|
|
struct snmp_proto *p = sk->data;
|
2024-01-23 23:23:31 +00:00
|
|
|
proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN));
|
2023-11-15 14:03:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* snmp_set_state - change state with associated actions
|
|
|
|
* @p - SNMP protocol instance
|
|
|
|
* @state - new SNMP protocol state
|
2024-01-23 23:23:31 +00:00
|
|
|
*
|
|
|
|
* This function does not notify the bird about protocol state. It is therefore
|
|
|
|
* a responsibility of the caller to use the returned value appropriately.
|
|
|
|
*
|
|
|
|
* Return current protocol state.
|
2023-11-15 14:03:55 +00:00
|
|
|
*/
|
2024-01-23 23:23:31 +00:00
|
|
|
int
|
2023-11-15 14:03:55 +00:00
|
|
|
snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
|
|
|
|
{
|
|
|
|
enum snmp_proto_state last = p->state;
|
|
|
|
|
|
|
|
TRACE(D_EVENTS, "SNMP changing state to %u", state);
|
|
|
|
|
2024-01-23 23:23:31 +00:00
|
|
|
if (state == SNMP_DOWN && (last == SNMP_REGISTER || last == SNMP_CONN))
|
|
|
|
{
|
|
|
|
/* We have a connection established (at least send out agentx-Open-PDU) */
|
|
|
|
state = SNMP_STOP;
|
|
|
|
}
|
|
|
|
/* else - We did not send any packet, we perform protocol cleanup only. */
|
2023-11-15 14:03:55 +00:00
|
|
|
|
|
|
|
if (last == SNMP_RESET)
|
2024-01-10 11:21:46 +00:00
|
|
|
{
|
2023-11-15 14:03:55 +00:00
|
|
|
rfree(p->sock);
|
2024-01-10 11:21:46 +00:00
|
|
|
p->sock = NULL;
|
|
|
|
}
|
2023-11-15 14:03:55 +00:00
|
|
|
|
2024-01-23 23:23:31 +00:00
|
|
|
p->state = state;
|
|
|
|
|
2023-11-15 14:03:55 +00:00
|
|
|
switch (state)
|
|
|
|
{
|
|
|
|
case SNMP_INIT:
|
2024-01-23 23:23:31 +00:00
|
|
|
DBG("snmp -> SNMP_INIT\n");
|
2023-11-15 14:03:55 +00:00
|
|
|
ASSERT(last == SNMP_DOWN);
|
|
|
|
struct object_lock *lock;
|
|
|
|
lock = p->lock = olock_new(p->pool);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* lock->addr
|
|
|
|
* lock->port
|
|
|
|
* lock->iface
|
|
|
|
* lock->vrf
|
|
|
|
*/
|
|
|
|
lock->type = OBJLOCK_TCP;
|
|
|
|
lock->hook = snmp_start_locked;
|
|
|
|
lock->data = p;
|
|
|
|
olock_acquire(lock);
|
2024-01-23 23:23:31 +00:00
|
|
|
return PS_START;
|
2023-11-15 14:03:55 +00:00
|
|
|
|
|
|
|
case SNMP_LOCKED:
|
2024-01-23 23:23:31 +00:00
|
|
|
DBG("snmp -> SNMP_LOCKED\n");
|
2023-11-15 14:03:55 +00:00
|
|
|
ASSERT(last == SNMP_INIT || SNMP_RESET);
|
|
|
|
sock *s = sk_new(p->pool);
|
|
|
|
s->type = SK_TCP_ACTIVE;
|
2024-01-10 11:21:46 +00:00
|
|
|
s->saddr = ipa_from_ip4(p->local_ip);
|
|
|
|
s->daddr = ipa_from_ip4(p->remote_ip);
|
2023-11-15 14:03:55 +00:00
|
|
|
s->dport = p->remote_port;
|
|
|
|
s->rbsize = SNMP_RX_BUFFER_SIZE;
|
|
|
|
s->tbsize = SNMP_TX_BUFFER_SIZE;
|
|
|
|
|
|
|
|
/* s->tos = IP_PREC_INTERNET_CONTROL */
|
|
|
|
s->tx_hook = snmp_connected;
|
|
|
|
s->err_hook = snmp_sock_err;
|
|
|
|
|
|
|
|
p->sock = s;
|
|
|
|
s->data = p;
|
|
|
|
|
|
|
|
/* Try opening the socket, schedule a retry on fail */
|
|
|
|
if (sk_open(s) < 0)
|
|
|
|
{
|
|
|
|
rfree(s);
|
|
|
|
p->sock = NULL;
|
|
|
|
tm_start(p->startup_timer, p->timeout);
|
|
|
|
}
|
2024-01-23 23:23:31 +00:00
|
|
|
return PS_START;
|
2023-11-15 14:03:55 +00:00
|
|
|
|
|
|
|
case SNMP_OPEN:
|
2024-01-23 23:23:31 +00:00
|
|
|
DBG("snmp -> SNMP_OPEN\n");
|
2023-11-15 14:03:55 +00:00
|
|
|
ASSERT(last == SNMP_LOCKED);
|
|
|
|
p->sock->rx_hook = snmp_rx;
|
|
|
|
p->sock->tx_hook = NULL;
|
|
|
|
snmp_start_subagent(p);
|
|
|
|
// handle no response (for long time)
|
2024-01-23 23:23:31 +00:00
|
|
|
return PS_START;
|
2023-11-15 14:03:55 +00:00
|
|
|
|
|
|
|
case SNMP_REGISTER:
|
2024-01-23 23:23:31 +00:00
|
|
|
DBG("snmp -> SNMP_REGISTER\n");
|
2023-11-15 14:03:55 +00:00
|
|
|
ASSERT(last == SNMP_OPEN);
|
|
|
|
snmp_register_mibs(p);
|
2024-01-23 23:23:31 +00:00
|
|
|
return PS_START;
|
2023-11-15 14:03:55 +00:00
|
|
|
|
|
|
|
case SNMP_CONN:
|
2024-01-23 23:23:31 +00:00
|
|
|
DBG("snmp -> SNMP_CONN\n");
|
2023-11-15 14:03:55 +00:00
|
|
|
ASSERT(last == SNMP_REGISTER);
|
2024-01-23 23:23:31 +00:00
|
|
|
return PS_UP;
|
2023-11-15 14:03:55 +00:00
|
|
|
|
|
|
|
case SNMP_STOP:
|
2024-01-23 23:23:31 +00:00
|
|
|
DBG("snmp -> SNMP_STOP\n");
|
2023-11-15 14:03:55 +00:00
|
|
|
ASSUME(last == SNMP_REGISTER || last == SNMP_CONN);
|
|
|
|
snmp_stop_subagent(p);
|
2024-01-10 11:21:46 +00:00
|
|
|
p->sock->rx_hook = snmp_rx_skip;
|
|
|
|
p->sock->tx_hook = snmp_tx_skip;
|
2023-11-15 14:03:55 +00:00
|
|
|
p->startup_timer->hook = snmp_stop_timeout;
|
|
|
|
tm_start(p->startup_timer, p->timeout);
|
2024-01-23 23:23:31 +00:00
|
|
|
return PS_STOP;
|
2023-11-15 14:03:55 +00:00
|
|
|
|
|
|
|
case SNMP_DOWN:
|
2024-01-23 23:23:31 +00:00
|
|
|
DBG("snmp -> SNMP_DOWN\n");
|
2023-11-15 14:03:55 +00:00
|
|
|
snmp_cleanup(p);
|
|
|
|
// FIXME: handle the state in which we call proto_notify_state and
|
|
|
|
// immediately return PS_DOWN from snmp_shutdown()
|
2024-01-23 23:23:31 +00:00
|
|
|
return PS_DOWN;
|
2023-11-15 14:03:55 +00:00
|
|
|
|
|
|
|
case SNMP_RESET:
|
2024-01-23 23:23:31 +00:00
|
|
|
DBG("snmp -> SNMP_RESET\n");
|
2023-11-15 14:03:55 +00:00
|
|
|
ASSUME(last == SNMP_REGISTER || last == SNMP_CONN);
|
2024-01-10 11:21:46 +00:00
|
|
|
ASSUME(p->sock);
|
2023-11-15 14:03:55 +00:00
|
|
|
p->sock->rx_hook = snmp_rx_skip;
|
2024-01-10 11:21:46 +00:00
|
|
|
p->sock->tx_hook = snmp_tx_skip;
|
2024-01-23 23:23:31 +00:00
|
|
|
return PS_STOP;
|
2023-11-15 14:03:55 +00:00
|
|
|
|
|
|
|
default:
|
2024-01-23 23:23:31 +00:00
|
|
|
die("unknown snmp state transition");
|
|
|
|
return PS_DOWN;
|
2023-11-15 14:03:55 +00:00
|
|
|
}
|
|
|
|
}
|
2022-11-29 15:30:20 +00:00
|
|
|
|
2023-11-08 09:55:42 +00:00
|
|
|
/*
|
|
|
|
* snmp_init - preinitialize SNMP instance
|
|
|
|
* @CF - SNMP configuration generic handle
|
|
|
|
*
|
2024-01-23 23:23:31 +00:00
|
|
|
* Returns a generic handle pointing to preinitialized SNMP procotol
|
2023-11-08 09:55:42 +00:00
|
|
|
* instance.
|
|
|
|
*/
|
2022-08-01 11:01:49 +00:00
|
|
|
static struct proto *
|
|
|
|
snmp_init(struct proto_config *CF)
|
|
|
|
{
|
|
|
|
struct proto *P = proto_new(CF);
|
2022-08-10 15:31:32 +00:00
|
|
|
struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
|
2022-08-01 11:01:49 +00:00
|
|
|
|
|
|
|
p->rl_gen = (struct tbf) TBF_DEFAULT_LOG_LIMITS;
|
|
|
|
|
2024-01-10 11:21:46 +00:00
|
|
|
p->state = SNMP_DOWN;
|
2022-08-10 15:31:32 +00:00
|
|
|
|
2022-08-01 11:01:49 +00:00
|
|
|
return P;
|
|
|
|
}
|
|
|
|
|
2023-11-08 09:55:42 +00:00
|
|
|
/*
|
|
|
|
* snmp_cleanup - free all resources allocated by SNMP protocol
|
|
|
|
* @p - SNMP protocol instance
|
|
|
|
*
|
|
|
|
* This function forcefully stops and cleans all resources and memory acqiured
|
|
|
|
* by given SNMP protocol instance, such as timers, lists, hash tables etc.
|
|
|
|
* Function snmp_cleanup() does not change the protocol state to PS_DOWN for
|
|
|
|
* practical reasons, it should be done by the caller.
|
|
|
|
*/
|
2023-10-25 10:41:23 +00:00
|
|
|
static inline void
|
2022-12-17 17:16:19 +00:00
|
|
|
snmp_cleanup(struct snmp_proto *p)
|
2022-12-10 12:23:50 +00:00
|
|
|
{
|
2023-09-04 11:58:59 +00:00
|
|
|
/* Function tm_stop() is called inside rfree() */
|
2022-12-17 17:16:19 +00:00
|
|
|
rfree(p->startup_timer);
|
2023-08-08 17:00:54 +00:00
|
|
|
p->startup_timer = NULL;
|
|
|
|
|
2022-12-17 17:16:19 +00:00
|
|
|
rfree(p->ping_timer);
|
2023-08-08 17:00:54 +00:00
|
|
|
p->ping_timer = NULL;
|
2022-12-17 17:16:19 +00:00
|
|
|
|
2023-08-08 17:00:54 +00:00
|
|
|
rfree(p->sock);
|
2023-07-26 12:34:01 +00:00
|
|
|
p->sock = NULL;
|
2022-12-10 12:23:50 +00:00
|
|
|
|
2023-08-08 17:00:54 +00:00
|
|
|
rfree(p->lock);
|
2023-07-26 12:34:01 +00:00
|
|
|
p->lock = NULL;
|
2022-12-10 12:23:50 +00:00
|
|
|
|
2023-11-15 14:03:55 +00:00
|
|
|
struct snmp_registration *r, *r2;
|
|
|
|
WALK_LIST_DELSAFE(r, r2, p->registration_queue)
|
2023-09-11 11:06:20 +00:00
|
|
|
{
|
|
|
|
rem_node(&r->n);
|
|
|
|
mb_free(r);
|
|
|
|
r = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HASH_FREE(p->bgp_hash);
|
|
|
|
|
2023-10-18 14:51:21 +00:00
|
|
|
rfree(p->lp);
|
|
|
|
p->bgp_trie = NULL;
|
2022-12-17 17:16:19 +00:00
|
|
|
}
|
|
|
|
|
2023-11-08 09:55:42 +00:00
|
|
|
/*
|
2024-01-23 23:23:31 +00:00
|
|
|
* snmp_connected - start AgentX session on created socket
|
2023-11-08 09:55:42 +00:00
|
|
|
* @sk - socket owned by SNMP protocol instance
|
|
|
|
*
|
|
|
|
* Starts the AgentX communication by sending an agentx-Open-PDU.
|
|
|
|
* This function is internal and shouldn't be used outside the SNMP module.
|
|
|
|
*/
|
2023-10-18 11:30:14 +00:00
|
|
|
void
|
|
|
|
snmp_connected(sock *sk)
|
|
|
|
{
|
|
|
|
struct snmp_proto *p = sk->data;
|
2023-11-15 14:03:55 +00:00
|
|
|
snmp_set_state(p, SNMP_OPEN);
|
2023-10-18 11:30:14 +00:00
|
|
|
}
|
|
|
|
|
2023-11-08 09:55:42 +00:00
|
|
|
/*
|
2024-01-23 23:23:31 +00:00
|
|
|
* snmp_reset - end the communication on AgentX session
|
2023-11-08 09:55:42 +00:00
|
|
|
* @p - SNMP protocol instance
|
|
|
|
*
|
2024-01-23 23:23:31 +00:00
|
|
|
* End the communication on AgentX session by downing the whole procotol. This
|
|
|
|
* causes socket closure that implies AgentX session disconnection.
|
2023-11-08 09:55:42 +00:00
|
|
|
* This function is internal and shouldn't be used outside the SNMP module.
|
|
|
|
*/
|
2023-10-25 10:56:23 +00:00
|
|
|
void
|
2024-01-23 23:23:31 +00:00
|
|
|
snmp_reset(struct snmp_proto *p)
|
2022-09-30 07:36:09 +00:00
|
|
|
{
|
2023-09-04 11:48:28 +00:00
|
|
|
tm_stop(p->ping_timer);
|
2024-01-23 23:23:31 +00:00
|
|
|
proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN));
|
2022-12-17 17:16:19 +00:00
|
|
|
}
|
|
|
|
|
2023-11-08 09:55:42 +00:00
|
|
|
/*
|
|
|
|
* snmp_sock_err - handle errors on socket by reopenning the socket
|
|
|
|
* @sk - socket owned by SNMP protocol instance
|
|
|
|
* @err - socket error errno
|
|
|
|
*/
|
2023-10-25 10:56:23 +00:00
|
|
|
static void
|
|
|
|
snmp_sock_err(sock *sk, int UNUSED err)
|
|
|
|
{
|
|
|
|
struct snmp_proto *p = sk->data;
|
|
|
|
|
2023-11-15 14:03:55 +00:00
|
|
|
TRACE(D_EVENTS, "SNMP socket error %d", err);
|
2024-01-23 23:23:31 +00:00
|
|
|
snmp_reset(p);
|
2023-10-25 10:56:23 +00:00
|
|
|
}
|
2022-09-30 07:36:09 +00:00
|
|
|
|
2023-11-08 09:55:42 +00:00
|
|
|
/*
|
|
|
|
* snmp_start_locked - open the socket on locked address
|
|
|
|
* @lock - object lock guarding the communication mean (address, ...)
|
|
|
|
*
|
|
|
|
* This function is called when the object lock is acquired. Main goal is to set
|
|
|
|
* socket parameters and try to open configured socket. Function
|
|
|
|
* snmp_connected() handles next stage of SNMP protocol start. When the socket
|
|
|
|
* coundn't be opened, a new try is scheduled after a small delay.
|
|
|
|
*/
|
2022-08-10 15:31:32 +00:00
|
|
|
static void
|
|
|
|
snmp_start_locked(struct object_lock *lock)
|
2022-08-02 14:04:25 +00:00
|
|
|
{
|
2022-08-10 15:31:32 +00:00
|
|
|
struct snmp_proto *p = lock->data;
|
2023-11-15 14:03:55 +00:00
|
|
|
if (p->startup_delay)
|
2023-10-18 11:30:14 +00:00
|
|
|
{
|
2023-11-15 14:03:55 +00:00
|
|
|
ASSERT(p->startup_timer);
|
|
|
|
p->startup_timer->hook = snmp_startup_timeout;
|
|
|
|
tm_start(p->startup_timer, p->startup_delay);
|
2023-10-18 11:30:14 +00:00
|
|
|
}
|
2023-11-15 14:03:55 +00:00
|
|
|
else
|
|
|
|
snmp_set_state(p, SNMP_LOCKED);
|
2022-08-10 15:31:32 +00:00
|
|
|
}
|
|
|
|
|
2023-11-08 09:55:42 +00:00
|
|
|
/*
|
|
|
|
* snmp_reconnect - helper restarting the AgentX session on packet errors
|
|
|
|
* @tm - the startup_timer holding the SNMP protocol instance
|
|
|
|
*
|
2024-01-23 23:23:31 +00:00
|
|
|
* Try to recover from an error by reseting the SNMP protocol. It is a simple
|
|
|
|
* snmp_reset() wrapper for timers.
|
2023-11-08 09:55:42 +00:00
|
|
|
*/
|
2023-10-25 14:23:39 +00:00
|
|
|
void
|
|
|
|
snmp_reconnect(timer *tm)
|
|
|
|
{
|
|
|
|
struct snmp_proto *p = tm->data;
|
2024-01-23 23:23:31 +00:00
|
|
|
snmp_reset(p);
|
2023-11-15 14:03:55 +00:00
|
|
|
return;
|
2022-08-10 15:31:32 +00:00
|
|
|
}
|
2022-08-02 14:04:25 +00:00
|
|
|
|
2023-11-08 09:55:42 +00:00
|
|
|
/*
|
|
|
|
* snmp_startup_timeout - start the initiliazed SNMP protocol
|
|
|
|
* @tm - the startup_timer holding the SNMP protocol instance.
|
|
|
|
*
|
|
|
|
* When the timer rings, the function snmp_startup() is invoked.
|
2023-11-15 14:03:55 +00:00
|
|
|
* This function is internal and shouldn't be used outside the SNMP module.
|
2023-11-08 09:55:42 +00:00
|
|
|
* Used when we delaying the start procedure, or we want to resend
|
|
|
|
* an agentx-Open-PDU for non-responding master agent.
|
|
|
|
*/
|
2023-10-18 11:30:14 +00:00
|
|
|
void
|
2023-11-08 09:55:42 +00:00
|
|
|
snmp_startup_timeout(timer *tm)
|
2022-08-10 15:31:32 +00:00
|
|
|
{
|
2023-11-15 14:03:55 +00:00
|
|
|
struct snmp_proto *p = tm->data;
|
|
|
|
snmp_set_state(p, SNMP_LOCKED);
|
2023-09-04 11:48:28 +00:00
|
|
|
}
|
2023-07-26 12:34:01 +00:00
|
|
|
|
2023-11-08 09:55:42 +00:00
|
|
|
/*
|
|
|
|
* snmp_stop_timeout - a timeout for nonresponding master agent
|
|
|
|
* @tm - the startup_timer holding the SNMP protocol instance.
|
|
|
|
*
|
|
|
|
* We are shutting down the SNMP protocol instance and we sent the
|
|
|
|
* agentx-Close-PDU. This function forcefully closes the AgentX session and
|
|
|
|
* stops the SNMP protocol instance. Used only when we did not receive any
|
|
|
|
* agentx-Response-PDU for the sent closed packet (before timeout).
|
|
|
|
*/
|
2023-09-04 11:48:28 +00:00
|
|
|
static void
|
2023-11-08 09:55:42 +00:00
|
|
|
snmp_stop_timeout(timer *tm)
|
2023-09-04 11:48:28 +00:00
|
|
|
{
|
2023-11-15 14:03:55 +00:00
|
|
|
struct snmp_proto *p = tm->data;
|
2024-01-23 23:23:31 +00:00
|
|
|
proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN));
|
2023-09-04 11:48:28 +00:00
|
|
|
}
|
2022-11-29 15:30:20 +00:00
|
|
|
|
2023-11-08 09:55:42 +00:00
|
|
|
/*
|
|
|
|
* snmp_ping_timeout - send a agentx-Ping-PDU
|
|
|
|
* @tm - the ping_timer holding the SNMP protocol instance.
|
|
|
|
*
|
2024-01-23 23:23:31 +00:00
|
|
|
* Send an agentx-Ping-PDU. This function is periodically called by ping
|
|
|
|
* timer.
|
2023-11-08 09:55:42 +00:00
|
|
|
*/
|
2023-09-04 11:48:28 +00:00
|
|
|
static void
|
2023-10-18 11:30:14 +00:00
|
|
|
snmp_ping_timeout(timer *tm)
|
2023-09-04 11:48:28 +00:00
|
|
|
{
|
|
|
|
struct snmp_proto *p = tm->data;
|
2023-11-15 14:03:55 +00:00
|
|
|
snmp_ping(p);
|
2022-08-02 14:04:25 +00:00
|
|
|
}
|
|
|
|
|
2023-11-08 09:55:42 +00:00
|
|
|
/*
|
|
|
|
* snmp_start - Initialize the SNMP protocol instance
|
|
|
|
* @P - SNMP protocol generic handle
|
|
|
|
*
|
|
|
|
* The first step in AgentX subagent startup is protocol initialition.
|
2024-01-23 23:23:31 +00:00
|
|
|
* We must prepare lists, find BGP peers and finally asynchronously open
|
2023-11-08 09:55:42 +00:00
|
|
|
* a AgentX subagent session through snmp_startup() function call.
|
|
|
|
*/
|
2022-08-01 11:01:49 +00:00
|
|
|
static int
|
|
|
|
snmp_start(struct proto *P)
|
|
|
|
{
|
2022-08-10 15:31:32 +00:00
|
|
|
struct snmp_proto *p = (void *) P;
|
2022-09-20 12:28:57 +00:00
|
|
|
struct snmp_config *cf = (struct snmp_config *) P->cf;
|
2022-08-10 15:31:32 +00:00
|
|
|
|
2023-11-15 14:03:55 +00:00
|
|
|
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->bgp_local_as = cf->bgp_local_as;
|
|
|
|
p->bgp_local_id = cf->bgp_local_id;
|
|
|
|
p->timeout = cf->timeout;
|
2024-01-23 23:23:31 +00:00
|
|
|
// TODO add default value for startup_delay inside bison .Y file
|
2023-11-15 14:03:55 +00:00
|
|
|
p->startup_delay = cf->startup_delay;
|
2022-09-30 07:36:09 +00:00
|
|
|
|
2023-10-18 14:51:21 +00:00
|
|
|
p->pool = p->p.pool;
|
|
|
|
p->lp = lp_new(p->pool);
|
2024-07-04 14:33:44 +00:00
|
|
|
p->mib_tree = mb_alloc(p->pool, sizeof(struct mib_tree));
|
2023-10-18 14:51:21 +00:00
|
|
|
p->bgp_trie = f_new_trie(p->lp, 0);
|
2022-09-30 07:36:09 +00:00
|
|
|
|
2023-11-15 14:03:55 +00:00
|
|
|
p->startup_timer = tm_new_init(p->pool, snmp_startup_timeout, p, 0, 0);
|
|
|
|
p->ping_timer = tm_new_init(p->pool, snmp_ping_timeout, p, p->timeout, 0);
|
|
|
|
|
|
|
|
init_list(&p->registration_queue);
|
2022-08-10 15:31:32 +00:00
|
|
|
|
2023-09-04 12:01:08 +00:00
|
|
|
/* We create copy of bonds to BGP protocols. */
|
2023-10-18 14:51:21 +00:00
|
|
|
HASH_INIT(p->bgp_hash, p->pool, 10);
|
2024-07-04 14:33:44 +00:00
|
|
|
|
|
|
|
mib_tree_init(p->pool, p->mib_tree);
|
|
|
|
snmp_bgp4_start(p);
|
2022-09-06 16:04:29 +00:00
|
|
|
|
2024-01-23 23:23:31 +00:00
|
|
|
return snmp_set_state(p, SNMP_INIT);
|
2022-08-01 11:01:49 +00:00
|
|
|
}
|
|
|
|
|
2024-01-10 11:21:46 +00:00
|
|
|
static inline int
|
|
|
|
snmp_reconfigure_logic(struct snmp_proto *p, const struct snmp_config *new)
|
2022-08-01 11:01:49 +00:00
|
|
|
{
|
2023-09-04 11:58:59 +00:00
|
|
|
const struct snmp_config *old = SKIP_BACK(struct snmp_config, cf, p->p.cf);
|
2022-08-10 15:31:32 +00:00
|
|
|
|
2024-01-10 11:21:46 +00:00
|
|
|
if (old->bonds != new->bonds)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
uint bonds = old->bonds;
|
2023-09-11 11:06:20 +00:00
|
|
|
struct snmp_bond *b1, *b2;
|
|
|
|
WALK_LIST(b1, new->bgp_entries)
|
|
|
|
{
|
|
|
|
WALK_LIST(b2, old->bgp_entries)
|
|
|
|
{
|
2023-11-15 14:03:55 +00:00
|
|
|
if (!strcmp(b1->config->name, b2->config->name))
|
2023-09-11 11:06:20 +00:00
|
|
|
goto skip;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2024-01-10 11:21:46 +00:00
|
|
|
skip:
|
|
|
|
bonds--;
|
2023-09-11 11:06:20 +00:00
|
|
|
}
|
|
|
|
|
2024-01-10 11:21:46 +00:00
|
|
|
if (bonds != 0)
|
|
|
|
return 0;
|
|
|
|
|
2023-09-04 12:01:08 +00:00
|
|
|
return !memcmp(((byte *) old) + sizeof(struct proto_config),
|
2023-09-04 11:58:59 +00:00
|
|
|
((byte *) new) + sizeof(struct proto_config),
|
|
|
|
OFFSETOF(struct snmp_config, description) - sizeof(struct proto_config))
|
|
|
|
&& ! strncmp(old->description, new->description, UINT32_MAX);
|
2022-08-01 11:01:49 +00:00
|
|
|
}
|
2022-09-30 07:36:09 +00:00
|
|
|
|
2023-11-08 09:55:42 +00:00
|
|
|
/*
|
2024-04-22 10:55:33 +00:00
|
|
|
* snmp_reconfigure - Indicate instance reconfigurability
|
2024-01-10 11:21:46 +00:00
|
|
|
* @P - SNMP protocol generic handle, current state
|
|
|
|
* @CF - SNMP protocol configuration generic handle carring new values
|
|
|
|
*
|
|
|
|
* We accept the reconfiguration if the new configuration @CF is identical with
|
2024-01-23 23:23:31 +00:00
|
|
|
* the currently deployed configuration. Otherwise we deny reconfiguration because
|
2024-01-10 11:21:46 +00:00
|
|
|
* the implementation would be cumbersome.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
snmp_reconfigure(struct proto *P, struct proto_config *CF)
|
|
|
|
{
|
|
|
|
struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
|
|
|
|
const struct snmp_config *new = SKIP_BACK(struct snmp_config, cf, CF);
|
|
|
|
|
2024-01-23 23:23:31 +00:00
|
|
|
/* We are searching for configuration changes */
|
2024-04-22 10:55:33 +00:00
|
|
|
int config_changed = snmp_reconfigure_logic(p, new);
|
2024-01-10 11:21:46 +00:00
|
|
|
|
2024-04-22 10:55:33 +00:00
|
|
|
if (config_changed)
|
2024-01-23 23:23:31 +00:00
|
|
|
{
|
2024-01-10 11:21:46 +00:00
|
|
|
/* Reinitialize the hash after snmp_shutdown() */
|
|
|
|
HASH_INIT(p->bgp_hash, p->pool, 10);
|
2024-07-04 14:33:44 +00:00
|
|
|
snmp_bgp4_start(p);
|
2024-01-10 11:21:46 +00:00
|
|
|
}
|
|
|
|
|
2024-04-22 10:55:33 +00:00
|
|
|
return config_changed;
|
2024-01-10 11:21:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* snmp_show_proto_info - print basic information about SNMP protocol instance
|
|
|
|
* @P: SNMP protocol generic handle
|
2023-11-08 09:55:42 +00:00
|
|
|
*/
|
2023-07-26 12:34:01 +00:00
|
|
|
static void
|
|
|
|
snmp_show_proto_info(struct proto *P)
|
2022-08-01 11:01:49 +00:00
|
|
|
{
|
2023-11-15 14:03:55 +00:00
|
|
|
struct snmp_proto *p = (void *) P;
|
2022-08-02 14:04:25 +00:00
|
|
|
|
2023-11-15 14:03:55 +00:00
|
|
|
cli_msg(-1006, " SNMP state %u", p->state);
|
|
|
|
cli_msg(-1006, " MIBs");
|
2022-08-02 14:04:25 +00:00
|
|
|
|
2023-11-15 14:03:55 +00:00
|
|
|
// TODO move me into the bgp_mib.c
|
|
|
|
cli_msg(-1006, " BGP4-MIB");
|
|
|
|
cli_msg(-1006, " Local AS %u", p->bgp_local_as);
|
|
|
|
cli_msg(-1006, " Local router id %R", p->bgp_local_id);
|
|
|
|
cli_msg(-1006, " BGP peers");
|
2022-08-02 14:04:25 +00:00
|
|
|
|
2024-01-10 11:21:46 +00:00
|
|
|
if (p->state == SNMP_DOWN || p->state == SNMP_RESET)
|
|
|
|
return;
|
|
|
|
|
2023-11-15 14:03:55 +00:00
|
|
|
HASH_WALK(p->bgp_hash, next, peer)
|
|
|
|
{
|
|
|
|
cli_msg(-1006, " protocol name: %s", peer->bgp_proto->p.name);
|
2024-01-10 11:21:46 +00:00
|
|
|
cli_msg(-1006, " Remote IPv4 address: %I4", peer->peer_ip);
|
|
|
|
cli_msg(-1006, " Remote router id %R", peer->bgp_proto->remote_id);
|
2022-08-01 11:01:49 +00:00
|
|
|
}
|
2023-11-15 14:03:55 +00:00
|
|
|
HASH_WALK_END;
|
2022-08-01 11:01:49 +00:00
|
|
|
}
|
|
|
|
|
2023-11-08 09:55:42 +00:00
|
|
|
/*
|
|
|
|
* snmp_postconfig - Check configuration correctness
|
2024-01-10 11:21:46 +00:00
|
|
|
* @CF: SNMP procotol configuration generic handle
|
2023-11-08 09:55:42 +00:00
|
|
|
*/
|
2022-09-20 12:28:57 +00:00
|
|
|
static void
|
|
|
|
snmp_postconfig(struct proto_config *CF)
|
|
|
|
{
|
2023-09-04 12:01:08 +00:00
|
|
|
/* Walk the BGP protocols and cache their references. */
|
2023-10-11 08:44:18 +00:00
|
|
|
if (((struct snmp_config *) CF)->bgp_local_as == 0)
|
2022-09-20 12:28:57 +00:00
|
|
|
cf_error("local as not specified");
|
|
|
|
}
|
|
|
|
|
2023-11-08 09:55:42 +00:00
|
|
|
/*
|
|
|
|
* snmp_shutdown - Forcefully stop the SNMP protocol instance
|
|
|
|
* @P - SNMP protocol generic handle
|
|
|
|
*
|
|
|
|
* If we have established connection, we firstly stop the subagent and then
|
|
|
|
* later cleanup the protocol. The subagent stopping consist of sending the
|
|
|
|
* agentx-Close-PDU and changing the current protocol state to PS_STOP.
|
|
|
|
* If we have no connection created, we simple do the cleanup.
|
|
|
|
* The cleanup is transition straight to PS_DOWN state with snmp_cleanup() call.
|
|
|
|
*/
|
2022-08-10 15:31:32 +00:00
|
|
|
static int
|
|
|
|
snmp_shutdown(struct proto *P)
|
2022-08-01 11:01:49 +00:00
|
|
|
{
|
2022-08-10 15:31:32 +00:00
|
|
|
struct snmp_proto *p = SKIP_BACK(struct snmp_proto, p, P);
|
2024-01-23 23:23:31 +00:00
|
|
|
return snmp_set_state(p, SNMP_DOWN);
|
2022-08-01 11:01:49 +00:00
|
|
|
}
|
|
|
|
|
2023-11-08 09:55:42 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Protocol infrastructure
|
|
|
|
*/
|
|
|
|
|
2022-08-01 11:01:49 +00:00
|
|
|
struct protocol proto_snmp = {
|
2023-11-08 12:10:13 +00:00
|
|
|
.name = "SNMP",
|
2022-08-01 11:01:49 +00:00
|
|
|
.template = "snmp%d",
|
2023-11-08 12:10:13 +00:00
|
|
|
.channel_mask = 0,
|
2022-08-01 11:01:49 +00:00
|
|
|
.proto_size = sizeof(struct snmp_proto),
|
|
|
|
.config_size = sizeof(struct snmp_config),
|
2022-09-20 12:28:57 +00:00
|
|
|
.postconfig = snmp_postconfig,
|
2022-08-01 11:01:49 +00:00
|
|
|
.init = snmp_init,
|
|
|
|
.start = snmp_start,
|
|
|
|
.reconfigure = snmp_reconfigure,
|
2022-08-10 15:31:32 +00:00
|
|
|
.shutdown = snmp_shutdown,
|
2022-08-01 11:01:49 +00:00
|
|
|
.show_proto_info = snmp_show_proto_info,
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
2022-08-10 15:31:32 +00:00
|
|
|
snmp_build(void)
|
2022-08-01 11:01:49 +00:00
|
|
|
{
|
|
|
|
proto_build(&proto_snmp);
|
|
|
|
}
|
2023-09-04 07:25:51 +00:00
|
|
|
|