0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-01-03 07:31:54 +00:00

SNMP: Documentation improvements

This commit is contained in:
Vojtech Vilimek 2023-11-16 07:11:14 +01:00
parent c18e6dd58d
commit a6a07ffb19
2 changed files with 70 additions and 16 deletions

View File

@ -8,7 +8,39 @@
*/ */
/** /**
* Simple Network Management Protocol State Machine * 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
* parsing packets, |bgp_mib.c| takes care of the bgp MIB subtree of standard
* 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
* *
* States with main transitions * States with main transitions
* *

View File

@ -28,23 +28,34 @@
*/ */
/** /**
*
*
*
*
* Handling of malformed packet: * Handling of malformed packet:
* When we find an error in PDU data, we create and send a response with error *
* defined by the RFC. We await until the packet is send and then we close the * When we find an error in PDU data, we create and send a response with error
* communication socket. This also closes the established session. We chose * defined by the RFC. We await until the packet is send and then we close the
* this approach because we cannot easily mark the boundary between packets. * communication socket. This implicitly closes the established session. We
* When we are reseting the connection, we change the snmp_state to SNMP_RESET. * chose this approach because we cannot easily mark the boundary between packets.
* In SNMP_RESET state we skip all received bytes and wait for snmp_tx() * When we are reseting the connection, we change the snmp_state to SNMP_RESET.
* to be called. The socket's tx_hook is called when the TX-buffer is empty, * In SNMP_RESET state we skip all received bytes and wait for snmp_tx()
* meaning our response (agentx-Response-PDU) was send. * to be called. The socket's tx_hook is called when the TX-buffer is empty,
* meaning our response (agentx-Response-PDU) was send.
* *
* *
* Partial parsing * Partial parsing:
* It may happen that we received only staring part of some PDU from the *
* communication socket. In most cases if we recognize this situation we * It may happen that we received only staring part of some PDU from the
* immediately return, waiting for rest of the PDU to arrive. But for packets * communication socket. In most cases, if we recognize this situation we
* like agentx-Get-PDU, agentx-GetNext-PDU and agentx-GetBulk-PDU it could be * immediately return, waiting for rest of the PDU to arrive. But for packets
* costly as they could hold many VarBinds. In these cases we process. * like agentx-Get-PDU, agentx-GetNext-PDU and agentx-GetBulk-PDU it could be
* costly as they could hold many VarBinds. We don't want to process these
* packet twice because it is a lot work. We parse all VarBinds until we hit the
* first incomplete one. The logic behind this is to release as much as
* possible space from receive buffer. When we hit the first incomplete VarBind,
* we store information about the parsing state and move the header inside the
* receive buffer.
* *
* Transmit packet context * Transmit packet context
* *
@ -1498,6 +1509,7 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s
{ {
res = p->last_header; res = p->last_header;
p->last_header = NULL; p->last_header = NULL;
p->last_size = 0;
} }
else else
res = response_header; res = response_header;
@ -1520,6 +1532,7 @@ partial:
STORE_U32(h->payload, pkt_size); STORE_U32(h->payload, pkt_size);
*skip = AGENTX_HEADER_SIZE; *skip = AGENTX_HEADER_SIZE;
p->last_header = h; p->last_header = h;
p->last_size = c.buffer - sk->tpos;
/* number of bytes parsed from RX-buffer */ /* number of bytes parsed from RX-buffer */
ret = pkt - pkt_start; ret = pkt - pkt_start;
@ -1632,7 +1645,16 @@ snmp_ping(struct snmp_proto *p)
snmp_pdu_context(&c, sk); snmp_pdu_context(&c, sk);
if (c.size < AGENTX_HEADER_SIZE) if (c.size < AGENTX_HEADER_SIZE)
snmp_manage_tbuf(p, &c); return;
int unused = (sk->tbsize - (sk->tpos - sk->tbuf)) - (p->last_size + AGENTX_HEADER_SIZE);
if (p->last_header && unused >= 0)
{
}
else if (p->last_header)
{
}
struct agentx_header *h = (struct agentx_header *) c.buffer; struct agentx_header *h = (struct agentx_header *) c.buffer;
ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE); ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);