]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
SNMP: tmp
authorVojtech Vilimek <vojtech.vilimek@nic.cz>
Wed, 24 Jul 2024 11:38:36 +0000 (13:38 +0200)
committerVojtech Vilimek <vojtech.vilimek@nic.cz>
Wed, 24 Jul 2024 11:38:36 +0000 (13:38 +0200)
proto/snmp/bgp4_mib.c
proto/snmp/snmp.c
proto/snmp/snmp.h
proto/snmp/subagent.c
proto/snmp/subagent.h

index 32ec536aabe3e10572421e5cffefee06d438cc01..134b3d3bd41b59d1b2b7ff0d0b4de24276facb50 100644 (file)
@@ -26,9 +26,6 @@
 /* hash table only store ip4 addresses */
 #define SNMP_HASH_LESS(ip1, ip2) SNMP_HASH_LESS4(ip1,ip2)
 
-// delete me
-#define SNMP_MANAGE_TBUF(...) (void)0
-
 #define DECLARE_BGP4(addr, proto, conn, stats, config) \
   ip4_addr addr; \
   const struct bgp_proto UNUSED *proto; \
@@ -63,6 +60,7 @@ snmp_bgp_last_error(const struct bgp_proto *bgp, char err[2])
 static void
 snmp_bgp_reg_ok(struct snmp_proto *p, const struct agentx_response *res, struct snmp_registration *reg)
 {
+  /* TODO(contexts): add meaningful action */
   const struct oid * const oid = reg->oid;
   (void)oid;
   (void)p;
@@ -72,6 +70,7 @@ snmp_bgp_reg_ok(struct snmp_proto *p, const struct agentx_response *res, struct
 static void
 snmp_bgp_reg_failed(struct snmp_proto *p, const struct agentx_response *res, struct snmp_registration *reg)
 {
+  /* TODO(contexts): add meaningful action */
   const struct oid * const oid = reg->oid;
   (void) res;
   (void)oid;
@@ -379,6 +378,13 @@ populate_bgp4(struct snmp_pdu *c, ip4_addr *addr, const struct bgp_proto **proto
   return SNMP_SEARCH_OK;
 }
 
+
+/*
+ *
+ *    MIB tree fill hooks
+ *
+ */
+
 static enum snmp_search_res
 fill_bgp_version(struct mib_walk_state *walk UNUSED, struct snmp_pdu *c)
 {
@@ -785,7 +791,11 @@ fill_local_id(struct mib_walk_state *walk UNUSED, struct snmp_pdu *c)
 }
 
 /*
- * bgp4_next_peer
+ * bgp4_next_peer - find next BGP peer with IPv4 address
+ * @state: MIB tree walk state
+ * @c: SNMP PDU context data
+ *
+ * Update TX-buffer VarBind name to next peer address.
  */
 static int
 bgp4_next_peer(struct mib_walk_state *state, struct snmp_pdu *c)
@@ -821,8 +831,7 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_pdu *c)
 
 
   ASSUME(oid->n_subid == 9);
-  /* full path BGP4-MIB::bgpPeerEntry.x: .1.3.6.1.2.1.15.3.1.x
-   * index offset = ARRAY_SIZE(snmp_internet) + 1 <prefix> + 4 + 1 <identifier x> */
+  /* Stack has one more node for empty prefix (tree root) */
   ASSUME(state->stack_pos > 10);
   oid->ids[4] = state->stack[10]->empty.id;
 
@@ -871,8 +880,8 @@ snmp_bgp4_start(struct snmp_proto *p)
 
 
   struct snmp_config *cf = SKIP_BACK(struct snmp_config, cf, p->p.cf);
-  /* Create binding to BGP protocols */
 
+  /* Create binding to BGP protocols */
   struct snmp_bond *b;
   WALK_LIST(b, cf->bgp_entries)
   {
index f3bf543171478ed3b42df0cdf9a0323c9ae8c06d..2168e490ca448d8888398b8a2ca937a020970668 100644 (file)
@@ -151,10 +151,10 @@ void agentx_get_mib_init(pool *p)
 
 /*
  * agentx_get_mib - classify an OID based on MIB prefix
- *
  */
 enum agentx_mibs agentx_get_mib(const struct oid *o)
 {
+  /* TODO: move me into MIB tree as hooks/MIB module root */
   enum agentx_mibs mib = AGENTX_MIB_UNKNOWN;
   for (uint i = 0; i < AGENTX_MIB_COUNT + 1; i++)
   {
@@ -214,19 +214,6 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
 
   TRACE(D_EVENTS, "SNMP changing state to %u", state);
 
-  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. */
-
-  if (last == SNMP_RESET)
-  {
-    rfree(p->sock);
-    p->sock = NULL;
-  }
-
   p->state = state;
 
   switch (state)
@@ -321,14 +308,17 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
     DBG("snmp -> SNMP_STOP\n");
     ASSUME(last == SNMP_REGISTER || last == SNMP_CONN);
     snmp_stop_subagent(p);
+    // FIXME: special treatment for SNMP_OPEN last state?
     p->sock->rx_hook = snmp_rx_skip;
     p->sock->tx_hook = snmp_tx_skip;
+
     p->startup_timer->hook = snmp_stop_timeout;
     tm_start(p->startup_timer, p->timeout);
     return PS_STOP;
 
   case SNMP_DOWN:
     DBG("snmp -> SNMP_DOWN\n");
+    ASSERT(last == SNMP_STOP || last == SNMP_RESET);
     snmp_cleanup(p);
     // FIXME: handle the state in which we call proto_notify_state and
     // immediately return PS_DOWN from snmp_shutdown()
@@ -338,7 +328,8 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
     DBG("snmp -> SNMP_RESET\n");
     ASSUME(last == SNMP_REGISTER || last == SNMP_CONN);
     ASSUME(p->sock);
-    snmp_stop_subagent(p);
+    tm_stop(p->ping_timer);
+    // FIXME: special treatment for SNMP_OPEN last state?
     p->sock->rx_hook = snmp_rx_skip;
     p->sock->tx_hook = snmp_tx_skip;
     return PS_STOP;
@@ -423,20 +414,35 @@ snmp_connected(sock *sk)
 }
 
 /*
- * snmp_reset - end the communication on AgentX session
- * @p - SNMP protocol instance
+ * snmp_reset - reset AgentX session
+ * @p: SNMP protocol instance
  *
- * End the communication on AgentX session by downing the whole procotol. This
- * causes socket closure that implies AgentX session disconnection.
- * This function is internal and shouldn't be used outside the SNMP module.
+ * We wait until the last PDU written into the socket is send while ignoring all
+ * incomming PDUs. Then we hard reset the connection by socket closure. The
+ * protocol instance is automatically restarted by nest.
  */
 void
 snmp_reset(struct snmp_proto *p)
 {
-  tm_stop(p->ping_timer);
-  proto_notify_state(&p->p, snmp_set_state(p, SNMP_DOWN));
+  proto_notify_state(&p->p, snmp_set_state(p, SNMP_RESET));
+}
+
+
+/*
+ * snmp_stop - close AgentX session
+ * @p: SNMP protocol instance
+ *
+ * We write agentx-Close-PDU into the socket, wait until all written PDUs are
+ * send and then close the socket. The protocol instance is automatically
+ * restarted by nest.
+ */
+void
+snmp_stop(struct snmp_proto *p)
+{
+  proto_notify_state(&p->p, snmp_set_state(p, SNMP_STOP));
 }
 
+
 /*
  * snmp_sock_err - handle errors on socket by reopenning the socket
  * @sk - socket owned by SNMP protocol instance
index 2e73c3134319fc2564d112f08d7194f36e459d4a..f1fc5e21a4f158e62cf0c5dee5ca94d7451bd78e 100644 (file)
@@ -171,6 +171,7 @@ void snmp_reconnect(timer *tm);
 int snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state);
 
 void snmp_reset(struct snmp_proto *p);
+void snmp_stop(struct snmp_proto *p);
 
 extern const char agentx_master_addr[sizeof(AGENTX_MASTER_ADDR)];
 
index 1a1adbeffa4f489b5e635ab1b5a68a3d9be97825..6e23e90c884e585fd0a9704ae10534bd145233c4 100644 (file)
@@ -20,9 +20,6 @@
  */
 
 /**
- *
- *
- *
  *
  * Handling of malformed packet:
  *
@@ -91,7 +88,7 @@ snmp_header(struct agentx_header *h, enum agentx_pdu_types type, u8 flags)
 }
 
 /*
- * snmp_blank_header - create header with no flags except default
+ * snmp_blank_header - create header with no flags except byte order
  * @h: pointer to created header in TX-buffer
  * @type: create PDU type
  *
@@ -239,7 +236,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
   if (snmp_tbuf_reserve(&c, sz))
     snmp_log("agentx-Notify-PDU small buffer");
 
-  struct agentx_header *h = (void *) c.buffer;
+  struct agentx_header *h = (struct agentx_header *) c.buffer;
   ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
   snmp_blank_header(h, AGENTX_NOTIFY_PDU);
   p->packet_id++;   /* New packet id */
@@ -351,7 +348,7 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, u32 bound, uint index, en
   STORE_U8(ur->reserved, 0);
   ADVANCE(c.buffer, c.size, sizeof(struct agentx_un_register_hdr));
 
-  snmp_put_oid(c.buffer, oid);
+  (void) snmp_put_oid(c.buffer, oid);
   ADVANCE(c.buffer, c.size, snmp_oid_size(oid));
 
   /* place upper-bound if needed */
@@ -522,7 +519,7 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start)
   if (c.error != AGENTX_RES_NO_ERROR)
   {
     response_err_ind(p, res, c.error, c.index + 1);
-    snmp_reset(p);  // error
+    snmp_reset(p);
   }
   else if (all_possible)
   {
@@ -676,24 +673,24 @@ space_for_response(const sock *sk)
 static uint
 parse_pkt(struct snmp_proto *p, byte *pkt, uint size)
 {
-  snmp_log("parse_pkt %t", current_time());
-  /* TX-buffer free space */
   if (size < AGENTX_HEADER_SIZE)
     return 0;
 
-  struct agentx_header *h = (void *) pkt;
+  struct agentx_header *h = (struct agentx_header *) pkt;
   if (h->flags & AGENTX_NETWORK_BYTE_ORDER)
   {
     TRACE(D_PACKETS, "SNMP received PDU with unexpected byte order");
+    snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
     snmp_reset(p);
     return 0;
   }
 
-  uint pkt_size = LOAD_U32(h->payload);
+  u32 pkt_size = LOAD_U32(h->payload);
 
   /* RX side checks - too big packet */
   if (pkt_size > SNMP_PKT_SIZE_MAX)
   {
+    TRACE(D_PACKETS, "SNMP received PDU is too long");
     snmp_simple_response(p, AGENTX_RES_GEN_ERROR, 0);
     snmp_reset(p);
     return 0; /* no bytes parsed */
@@ -703,7 +700,8 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size)
   if (size < pkt_size + AGENTX_HEADER_SIZE)
     return 0; /* no bytes parsed */
 
-  /* We need to see the responses for PDU such as
+  /*
+   * We need to see the responses for PDU such as
    * agentx-Open-PDU, agentx-Register-PDU, ...
    * even when we are outside the SNMP_CONNECTED state
    */
@@ -726,7 +724,6 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size)
     p->session_id = copy.session_id;
     p->transaction_id = copy.transaction_id;
     p->packet_id = copy.packet_id;
-    snmp_log("restoring packet_id %u from temporal state", p->packet_id);
 
     /*
      * After unexpected state, we simply reset the session
@@ -740,11 +737,12 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size)
   {
     TRACE(D_PACKETS, "SNMP received PDU with non-default context");
     snmp_simple_response(p, AGENTX_RES_UNSUPPORTED_CONTEXT, 0);
-    return pkt_size + AGENTX_HEADER_SIZE;
+    snmp_reset(p);
+    return 0;
   }
 
   refresh_ids(p, h);
-  switch (h->type)
+  switch (LOAD_U8(h->type))
   {
     case AGENTX_GET_PDU:
     case AGENTX_GET_NEXT_PDU:
@@ -768,8 +766,8 @@ parse_pkt(struct snmp_proto *p, byte *pkt, uint size)
 
     default:
       /* We reset the connection for malformed packet (Unknown packet type) */
-      TRACE(D_PACKETS, "SNMP received unknown packet with type %u", h->type);
-      snmp_set_state(p, SNMP_RESET);
+      TRACE(D_PACKETS, "SNMP received unknown packet with type %u", LOAD_U8(h->type));
+      snmp_reset(p);
       return 0;
   }
 }
@@ -821,8 +819,8 @@ parse_response(struct snmp_proto *p, byte *res)
     case AGENTX_RES_PARSE_ERROR:
     case AGENTX_RES_PROCESSING_ERR:
     default:
-      DBG("SNMP agentx-Response-PDU with unexpected error %u", r->error);
-      snmp_set_state(p, SNMP_DOWN);
+      TRACE(D_PACKETS, "SNMP agentx-Response-PDU with unexepected error %u", r->error);
+      snmp_stop(p);
       break;
   }
 
@@ -924,7 +922,7 @@ snmp_vb_to_tx(struct snmp_pdu *c, const struct oid *oid)
     snmp_log("SNMP vb_to_tx small buffer");
 
   ASSERT(c->size >= vb_hdr_size);
-  struct agentx_varbind *vb = (void *) c->buffer;
+  struct agentx_varbind *vb = (struct agentx_varbind *) c->buffer;
   ADVANCE(c->buffer, c->size, sizeof(struct agentx_varbind) - sizeof(struct oid));
   /* Move the c->buffer so that is points at &vb->name */
   snmp_set_varbind_type(vb, AGENTX_NULL);
@@ -973,12 +971,12 @@ update_packet_size(struct agentx_header *start, byte *end)
 static inline void
 response_err_ind(struct snmp_proto *p, struct agentx_response *res, enum agentx_response_errs err, u16 ind)
 {
-  STORE_U32(res->error, (u16) err);
+  STORE_U16(res->error, (u16) err);
   // TODO deal with auto-incrementing of snmp_pdu context c.ind
   if (err != AGENTX_RES_NO_ERROR && err != AGENTX_RES_GEN_ERROR)
   {
     TRACE(D_PACKETS, "Last PDU resulted in error %u", err);
-    STORE_U32(res->index, ind);
+    STORE_U16(res->index, ind);
     TRACE(D_PACKETS, "Storing packet size %u (was %u)", sizeof(struct agentx_response) - AGENTX_HEADER_SIZE, LOAD_U32(res->h.payload));
     STORE_U32(res->h.payload,
       sizeof(struct agentx_response) - AGENTX_HEADER_SIZE);
@@ -986,13 +984,13 @@ response_err_ind(struct snmp_proto *p, struct agentx_response *res, enum agentx_
   else if (err == AGENTX_RES_GEN_ERROR)
   {
     TRACE(D_PACKETS, "Last PDU resulted in error %u genErr", err);
-    STORE_U32(res->index, 0);
+    STORE_U16(res->index, 0);
     TRACE(D_PACKETS, "Storing packet size %u (was %u)", sizeof(struct agentx_response) - AGENTX_HEADER_SIZE, LOAD_U32(res->h.payload));
     STORE_U32(res->h.payload,
       sizeof(struct agentx_response) - AGENTX_HEADER_SIZE);
   }
   else
-    STORE_U32(res->index, 0);
+    STORE_U16(res->index, 0);
 }
 
 static inline uint
@@ -1263,8 +1261,7 @@ snmp_stop_subagent(struct snmp_proto *p)
 int
 snmp_rx(sock *sk, uint size)
 {
-  snmp_log("snmp_rx with size %u", size);
-  struct snmp_proto *p = sk->data;
+  struct snmp_proto *p = (struct snmp_proto *) sk->data;
   byte *pkt_start = sk->rbuf;
   byte *end = pkt_start + size;
 
index 234b137a318f80305122559d4b2e259f7aa01b55..cf53a2123c93f53e436614f9f8dc747b851b4c48 100644 (file)
@@ -148,7 +148,6 @@ enum agentx_flags {
 
 #define COPY_STR(proto, buf, str, length) ({                                 \
   length = LOAD_PTR(buf);                                                    \
-  /*log(L_INFO "LOAD_STR(), %p %u", proto->pool, length + 1); */             \
   str = mb_alloc(proto->pool, length + 1);                                   \
   memcpy(str, buf+4, length);                                                \
   str[length] = '\0'; /* set term. char */                                   \
@@ -235,6 +234,13 @@ struct agentx_response {
 
 STATIC_ASSERT(4 + 2 + 2 + AGENTX_HEADER_SIZE == sizeof(struct agentx_response));
 
+struct agentx_open_pdu {
+  struct agentx_header h;
+  u8 timeout;
+  u8 reserved1;          /* reserved u24 */
+  u16 reserved2;  /* whole u24 is always zero filled */
+};
+
 struct agentx_close_pdu {
   struct agentx_header h;
   u8 reason;