]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
SNMP: Documentation improvements
authorVojtech Vilimek <vojtech.vilimek@nic.cz>
Thu, 16 Nov 2023 06:11:14 +0000 (07:11 +0100)
committerVojtech Vilimek <vojtech.vilimek@nic.cz>
Thu, 16 Nov 2023 06:11:14 +0000 (07:11 +0100)
proto/snmp/snmp.c
proto/snmp/subagent.c

index 252803299acb61de7034183d9f6d52fd060523d1..85fcd797cc52f28d899a06f659a60929660ba653 100644 (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
  *
index 50900d1c07207624bc652e19ea6aea3f788fcffc..804cfa1ea9288e75c185e768c0957ee595e918f1 100644 (file)
  */
 
 /**
+ *
+ *
+ *
+ *
  * 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
- *  communication socket. This also closes the established session. We chose
- *  this approach because we cannot easily mark the boundary between packets.
- *  When we are reseting the connection, we change the snmp_state to SNMP_RESET.
- *  In SNMP_RESET state we skip all received bytes and wait for snmp_tx()
- *  to be called. The socket's tx_hook is called when the TX-buffer is empty,
- *  meaning our response (agentx-Response-PDU) was send.
  *
+ * 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
+ * communication socket. This implicitly closes the established session. We
+ * chose this approach because we cannot easily mark the boundary between packets.
+ * When we are reseting the connection, we change the snmp_state to SNMP_RESET.
+ * In SNMP_RESET state we skip all received bytes and wait for snmp_tx()
+ * 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
- *  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
- *  immediately return, waiting for rest of the PDU to arrive. But for packets
- *  like agentx-Get-PDU, agentx-GetNext-PDU and agentx-GetBulk-PDU it could be
- *  costly as they could hold many VarBinds. In these cases we process.
+ *
+ * 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
+ * immediately return, waiting for rest of the PDU to arrive. But for packets
+ * 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
  *
@@ -1498,6 +1509,7 @@ parse_gets2_pdu(struct snmp_proto *p, byte * const pkt_start, uint size, uint *s
   {
     res = p->last_header;
     p->last_header = NULL;
+    p->last_size = 0;
   }
   else
     res = response_header;
@@ -1520,6 +1532,7 @@ partial:
   STORE_U32(h->payload, pkt_size);
   *skip = AGENTX_HEADER_SIZE;
   p->last_header = h;
+  p->last_size = c.buffer - sk->tpos;
 
   /* number of bytes parsed from RX-buffer */
   ret = pkt - pkt_start;
@@ -1632,7 +1645,16 @@ snmp_ping(struct snmp_proto *p)
   snmp_pdu_context(&c, sk);
 
   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;
   ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);