]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
SNMP: Slow integraion of MIB tree in SNMP code
authorVojtech Vilimek <vojtech.vilimek@nic.cz>
Fri, 24 May 2024 13:20:30 +0000 (15:20 +0200)
committerVojtech Vilimek <vojtech.vilimek@nic.cz>
Fri, 24 May 2024 13:20:30 +0000 (15:20 +0200)
14 files changed:
proto/snmp/Doc
proto/snmp/Makefile
proto/snmp/bgp4_mib.c [moved from proto/snmp/bgp_mib.c with 62% similarity]
proto/snmp/bgp4_mib.h [moved from proto/snmp/bgp_mib.h with 89% similarity]
proto/snmp/config.Y
proto/snmp/mib_tree.c
proto/snmp/mib_tree.h
proto/snmp/snmp.c
proto/snmp/snmp.h
proto/snmp/snmp_test.c
proto/snmp/snmp_utils.c
proto/snmp/snmp_utils.h
proto/snmp/subagent.c
proto/snmp/subagent.h

index 7d2ec70b64aa9728eba1f92291adc6cf3d29aa95..b1475b8a3c65e32ee50ac5b1b4ca37563b9b56c4 100644 (file)
@@ -1,4 +1,4 @@
 S snmp.c
 S subagent.c
 S snmp_utils.c
-S bgp_mib.c
+S bgp4_mib.c
index 637815affce5a992ecb08c25b000733abb7381f3..038c85c91a88648939f5a0f0202ea57eecb499ae 100644 (file)
@@ -1,4 +1,4 @@
-src := snmp.c snmp_utils.c subagent.c bgp_mib.c mib_tree.c
+src := snmp.c snmp_utils.c subagent.c bgp4_mib.c mib_tree.c
 obj := $(src-o-files)
 $(all-daemon)
 $(cf-local)
similarity index 62%
rename from proto/snmp/bgp_mib.c
rename to proto/snmp/bgp4_mib.c
index 7559042aa42bcd96907f9ca490e7b44d2911d9de..b3ac160e5d147875bdedea0a8aae0d425d1f4e5f 100644 (file)
@@ -8,10 +8,12 @@
  *     Can be freely distributed and used under the terms of the GNU GPL.
  */
 
+/* need to be first header file included */
+#include "bgp4_mib.h"
+
 #include "snmp.h"
 #include "snmp_utils.h"
 #include "subagent.h"
-#include "bgp_mib.h"
 
 /* hash table macros */
 #define SNMP_HASH_KEY(n)  n->peer_ip
 /* hash table only store ip4 addresses */
 #define SNMP_HASH_LESS(ip1, ip2) SNMP_HASH_LESS4(ip1,ip2)
 
+// TODO delete me
+#define SNMP_MANAGE_TBUF(...) (void)0
 
-/* Simply discard type */
-#define SNMP_MANAGE_TBUF(p, vb, c) snmp_manage_tbuf(p, (void **) vb, c)
+#define DECLARE_BGP4(addr, proto, conn, stats, config) \
+  ip4_addr addr; \
+  const struct bgp_proto *proto; \
+  const struct bgp_conn *conn; \
+  const struct bgp_stats *stats; \
+  const struct bgp_config *config
 
-static inline void ip4_to_oid(struct oid *oid, ip4_addr addr);
+#define POPULATE_BGP4(addr, proto, conn, stats, config) populate_bgp4(p, c, &(addr), &(proto), &(conn), &(stats), &(config))
 
 
+static inline void ip4_to_oid(struct oid *oid, ip4_addr addr);
+
 static inline void
 snmp_hash_add_peer(struct snmp_proto *p, struct snmp_bgp_peer *peer)
 {
@@ -83,7 +93,7 @@ bgp_get_candidate(u32 field)
 
   /*
    * First value is in secord cell of array translation_table, as the
-   * SNMP_BPG_IDENTIFIER == 1
+   * SNMP_BGP_IDENTIFIER == 1
    */
   if (field > 0 && field <= ARRAY_SIZE(translation_table)- 1)
     return translation_table[field];
@@ -193,25 +203,22 @@ snmp_bgp_state(const struct oid *oid)
   return state;
 }
 
-void
-snmp_bgp_reg_ok(struct snmp_proto *p, struct agentx_response *r, struct oid *oid)
+static void
+snmp_bgp_reg_ok(struct snmp_proto *p, const struct agentx_response *res, struct snmp_registration *reg)
 {
-  (void)p;
-  (void)r;
+  const struct oid * const oid = reg->oid;
   (void)oid;
-  /* TODO: EXPENSIVE_CHECK() that
-  const struct oid *in_buf = ((void *) r) + sizeof(r);
-  struct oid *dup = snmp_prefixize(p, in_buf);
-    ASSUME(snmp_bgp_state(oid) == snmp_bgp_state(dup));
-  mb_free(dup);
-   */
+  (void)p;
+  (void) res;
 }
 
-void
-snmp_bgp_reg_failed(struct snmp_proto *p, struct agentx_response UNUSED *r, struct oid UNUSED *oid)
+static void
+snmp_bgp_reg_failed(struct snmp_proto *p, const struct agentx_response *res, struct snmp_registration *reg)
 {
-  // TODO add more sensible action
-  snmp_stop_subagent(p);
+  const struct oid * const oid = reg->oid;
+  (void) res;
+  (void)oid;
+  (void)p;
 }
 
 /*
@@ -280,8 +287,9 @@ snmp_bgp_notify_common(struct snmp_proto *p, uint type, ip4_addr ip4, char last_
     ip4_to_oid(addr, ip4);
   }
   /* We have enough space inside the TX-buffer prepared */
-  struct snmp_pdu sink = { 0 };
-  snmp_varbind_ip4(addr_vb, &sink, ip4);
+  struct snmp_pdu dummy = { 0 };
+  dummy.sr_vb_start = addr_vb;
+  snmp_varbind_ip4(&dummy, ip4);
 
   { /* BGP4-MIB::bgpPeerLastError */
     struct oid *error = &error_vb->name;
@@ -294,7 +302,9 @@ snmp_bgp_notify_common(struct snmp_proto *p, uint type, ip4_addr ip4, char last_
     error->ids[ENTRY_TYPE] = BGP4_MIB_LAST_ERROR;
     ip4_to_oid(error, ip4);
   }
-  snmp_varbind_nstr(error_vb, &sink, last_error, 2);
+
+  dummy.sr_vb_start = error_vb;
+  snmp_varbind_nstr(&dummy, last_error, 2);
 
   { /* BGP4-MIB::bgpPeerState */
     struct oid *state = &state_vb->name;
@@ -307,7 +317,9 @@ snmp_bgp_notify_common(struct snmp_proto *p, uint type, ip4_addr ip4, char last_
     state->ids[ENTRY_TYPE] = BGP4_MIB_STATE;
     ip4_to_oid(state, ip4);
   }
-  snmp_varbind_int(state_vb, &sink, state_val);
+
+  dummy.sr_vb_start = state_vb;
+  snmp_varbind_int(&dummy, state_val);
 
   /* We do not send the systemUpTime.0 */
   snmp_notify_pdu(p, head, data, sz, 0);
@@ -364,9 +376,10 @@ snmp_bgp_notify_backward_trans(struct snmp_proto *p, struct bgp_proto *bgp)
 }
 
 void
-snmp_bgp_register(struct snmp_proto *p)
+snmp_bgp4_register(struct snmp_proto *p)
 {
   u32 bgp_mib_prefix[] = { 1, 15 };
+  // TODO
 
   {
     /* Register the whole BGP4-MIB::bgp root tree node */
@@ -380,6 +393,8 @@ snmp_bgp_register(struct snmp_proto *p)
 
     memcpy(oid->ids, bgp_mib_prefix, sizeof(bgp_mib_prefix));
     reg->oid = oid;
+    reg->reg_hook_ok = snmp_bgp_reg_ok;
+    reg->reg_hook_fail = snmp_bgp_reg_failed;
 
     /*
      * We set both upper bound and index to zero, therefore only single OID
@@ -390,7 +405,7 @@ snmp_bgp_register(struct snmp_proto *p)
 }
 
 static int
-snmp_bgp_valid_ip4(struct oid *o)
+snmp_bgp_valid_ip4(const struct oid *o)
 {
   return snmp_valid_ip4_index(o, 5);
 }
@@ -586,6 +601,565 @@ oid_state_compare(const struct oid *oid, u8 state)
   return -1;
 }
 
+static inline enum snmp_search_res
+populate_bgp4(struct snmp_proto *p, struct snmp_pdu *c, ip4_addr *addr, const struct bgp_proto **proto, const struct bgp_conn
+**conn, const struct bgp_stats **stats, const struct bgp_config **config)
+{
+  const struct oid * const oid = &c->sr_vb_start->name;
+  if (snmp_bgp_valid_ip4(oid))
+    *addr = ip4_from_oid(oid);
+  else
+    return SNMP_SEARCH_NO_INSTANCE;
+
+  struct snmp_bgp_peer *pe = snmp_hash_find(p, *addr);
+  if (!pe)
+    return SNMP_SEARCH_NO_INSTANCE;
+
+  const struct bgp_proto *bgp_proto;
+  *proto = bgp_proto = pe->bgp_proto;
+  if (ipa_is_ip4(bgp_proto->remote_ip))
+  {
+    log(L_ERR, "%s: Found BGP protocol instance with IPv6 address", bgp_proto->p.name);
+    c->error = AGENTX_RES_GEN_ERROR;
+    return SNMP_SEARCH_NO_INSTANCE;
+  }
+
+  ip4_addr proto_ip = ipa_to_ip4(bgp_proto->remote_ip);
+  if (!ip4_equal(proto_ip, pe->peer_ip))
+  {
+    /* Here, we could be in problem as the bgp_proto IP address could be changed */
+    log(L_ERR, "%s: Stored hash key IP address and peer remote address differ.",
+      bgp_proto->p.name);
+    c->error = AGENTX_RES_GEN_ERROR;
+    return SNMP_SEARCH_NO_INSTANCE;
+  }
+
+  *conn = bgp_proto->conn;
+  *stats = &bgp_proto->stats;
+  *config = bgp_proto->cf;
+
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_bgp_version(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  if (c->sr_vb_start->name.n_subid != 4)
+  {
+    snmp_set_varbind_type(c->sr_vb_start, AGENTX_NO_SUCH_INSTANCE);
+    return SNMP_SEARCH_NO_INSTANCE;
+  }
+
+  uint sz = snmp_str_size_from_len(1);
+  if (c->size < sz)
+    snmp_manage_tbuf(p, c);
+
+  c->size -= sz;
+  snmp_varbind_nstr(c, BGP4_VERSIONS, 1);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_local_as(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  if (c->size < AGENTX_TYPE_INT_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_int(c, p->bgp_local_as);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_peer_id(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  uint fsm_state = snmp_bgp_fsm_state(bgp_proto);
+
+  if (c->size < AGENTX_TYPE_IP4_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  if (fsm_state == BGP4_MIB_OPENCONFIRM || fsm_state == BGP4_MIB_ESTABLISHED)
+    // TODO last
+    snmp_varbind_ip4(c, ip4_from_u32(bgp_proto->remote_id));
+  else
+    snmp_varbind_ip4(c, IP4_NONE);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_peer_state(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  uint fsm_state = snmp_bgp_fsm_state(bgp_proto);
+
+  if (c->size < AGENTX_TYPE_INT_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_int(c, fsm_state);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_admin_status(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_INT_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  if (bgp_proto->p.disabled)
+    snmp_varbind_int(c, AGENTX_ADMIN_STOP);
+  else
+    snmp_varbind_int(c, AGENTX_ADMIN_START);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_neg_version(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  uint fsm_state = snmp_bgp_fsm_state(bgp_proto);
+
+  if (c->size < AGENTX_TYPE_INT_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  if (fsm_state == BGP4_MIB_ESTABLISHED || fsm_state == BGP4_MIB_ESTABLISHED)
+    snmp_varbind_int(c, BGP4_MIB_NEGOTIATED_VER_VALUE);
+  else
+    snmp_varbind_int(c, BGP4_MIB_NEGOTIATED_VER_NO_VALUE);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_local_addr(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_IP4_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_ip4(c, ipa_to_ip4(bgp_proto->local_ip));
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_local_port(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_INT_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_int(c, bgp_conf->local_port);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_remove_addr(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_IP4_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_ip4(c, ipa_to_ip4(bgp_proto->remote_ip));
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_remote_port(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_INT_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_int(c, bgp_conf->remote_port);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_remote_as(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_INT_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_int(c, bgp_proto->remote_as);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_in_updates(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_COUNTER32_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_counter32(c, bgp_stats->rx_updates);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_out_update(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_COUNTER32_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_counter32(c, bgp_stats->tx_updates);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_in_total_msg(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_COUNTER32_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_counter32(c, bgp_stats->rx_messages);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_out_total_msg(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_COUNTER32_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_counter32(c, bgp_stats->tx_messages);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_last_err(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < snmp_str_size_from_len(2))
+    snmp_manage_tbuf(p, c);
+
+  char last_error[2];
+  snmp_bgp_last_error(bgp_proto, last_error);
+
+  snmp_varbind_nstr(c, last_error, 2);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_established_trans(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_COUNTER32_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_counter32(c,
+      bgp_stats->fsm_established_transitions);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_established_time(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_COUNTER32_SIZE)
+    snmp_manage_tbuf(p, c);
+
+
+  snmp_varbind_gauge32(c,
+       (current_time() - bgp_proto->last_established) TO_S);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_retry_interval(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_INT_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_int(c, bgp_conf->connect_retry_time);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_hold_time(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_INT_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_int(c, (bgp_conn) ?  bgp_conn->hold_time : 0);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_keep_alive(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_INT_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  if (!bgp_conf->hold_time)
+    snmp_varbind_int(c, 0);
+  else
+    snmp_varbind_int(c,
+      (bgp_conn) ? bgp_conn->keepalive_time : 0);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_hold_time_conf(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_INT_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_int(c, bgp_conf->hold_time);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_keep_alive_conf(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_INT_SIZE)
+    snmp_manage_tbuf(p, c);
+
+
+  if (!bgp_conf->keepalive_time)
+    snmp_varbind_int(c, 0);
+  else
+    snmp_varbind_int(c,
+      (bgp_conn) ? bgp_conn->keepalive_time : 0);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_min_as_org_interval(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  /* value should be in 1..65535 but is not supported by bird */
+  if (c->size < AGENTX_TYPE_INT_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_int(c, 0);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_route_adv_interval(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  /* value should be in 1..65535 but is not supported by bird */
+  if (c->size < AGENTX_TYPE_INT_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_int(c, 0);
+  return SNMP_SEARCH_OK;
+}
+
+static enum snmp_search_res
+fill_in_update_elapsed_time(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  enum snmp_search_res res;
+  DECLARE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  res = POPULATE_BGP4(addr, bgp_proto, bgp_conn, bgp_stats, bgp_conf);
+  if (res != SNMP_SEARCH_OK)
+  {
+    (void) snmp_set_varbind_type(c->sr_vb_start, res);
+    return res;
+  }
+
+  if (c->size < AGENTX_TYPE_INT_SIZE)
+    snmp_manage_tbuf(p, c);
+
+  snmp_varbind_gauge32(c,
+    (current_time() - bgp_proto->last_rx_update) TO_S
+  );
+  return SNMP_SEARCH_OK;
+}
+
 static struct oid *
 update_bgp_vb(struct snmp_proto *p, struct agentx_varbind **vb, u8 state, struct snmp_pdu *c)
 {
@@ -892,19 +1466,26 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p
   if (oid_state_compare(oid, state) == 0 && snmp_bgp_valid_ip4(oid))
     addr = ip4_from_oid(oid);
   else
-    return snmp_set_varbind_type(*vb, AGENTX_NO_SUCH_INSTANCE);
+  {
+    snmp_set_varbind_type(*vb, AGENTX_NO_SUCH_INSTANCE);
+    return;
+  }
 
   struct snmp_bgp_peer *pe = snmp_hash_find(p, addr);
 
   if (!pe)
-    return snmp_set_varbind_type(*vb, AGENTX_NO_SUCH_INSTANCE);
+  {
+    snmp_set_varbind_type(*vb, AGENTX_NO_SUCH_INSTANCE);
+    return;
+  }
 
   const struct bgp_proto *bgp_proto = pe->bgp_proto;
   if (!ipa_is_ip4(bgp_proto->remote_ip))
   {
     log(L_ERR, "%s: Found BGP protocol instance with IPv6 address", bgp_proto->p.name);
     c->error = AGENTX_RES_GEN_ERROR;
-    return snmp_set_varbind_type(*vb, AGENTX_NO_SUCH_INSTANCE);
+    snmp_set_varbind_type(*vb, AGENTX_NO_SUCH_INSTANCE);
+    return;
   }
 
   ip4_addr proto_ip = ipa_to_ip4(bgp_proto->remote_ip);
@@ -914,7 +1495,8 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p
     log(L_ERR, "%s: Stored hash key IP address and peer remote address differ.",
       bgp_proto->p.name);
     c->error = AGENTX_RES_GEN_ERROR;
-    return snmp_set_varbind_type(*vb, AGENTX_NO_SUCH_INSTANCE);
+    snmp_set_varbind_type(*vb, AGENTX_NO_SUCH_INSTANCE);
+    return;
   }
 
   const struct bgp_conn *bgp_conn = bgp_proto->conn;
@@ -931,20 +1513,20 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p
   {
     case BGP4_MIB_S_PEER_IDENTIFIER:
       if (c->size < AGENTX_TYPE_IP4_SIZE)
-       SNMP_MANAGE_TBUF(p, vb, c);
+       snmp_manage_tbuf(p, c);
 
       if (fsm_state == BGP4_MIB_OPENCONFIRM || fsm_state == BGP4_MIB_ESTABLISHED)
        // TODO last
-       snmp_varbind_ip4(*vb, c, ip4_from_u32(bgp_proto->remote_id));
+       ; //snmp_varbind_ip4(*vb, c, ip4_from_u32(bgp_proto->remote_id));
       else
-       snmp_varbind_ip4(*vb, c, IP4_NONE);
+       ; //snmp_varbind_ip4(*vb, c, IP4_NONE);
       break;
 
     case BGP4_MIB_S_STATE:
       if (c->size < AGENTX_TYPE_INT_SIZE)
-       SNMP_MANAGE_TBUF(p, vb, c);
+       snmp_manage_tbuf(p, c);
 
-      snmp_varbind_int(*vb, c, fsm_state);
+      //snmp_varbind_int(*vb, c, fsm_state);
       break;
 
     case BGP4_MIB_S_ADMIN_STATUS:
@@ -952,9 +1534,9 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p
        SNMP_MANAGE_TBUF(p, vb, c);
 
       if (bgp_proto->p.disabled)
-       snmp_varbind_int(*vb, c, AGENTX_ADMIN_STOP);
+       ; //snmp_varbind_int(*vb, c, AGENTX_ADMIN_STOP);
       else
-       snmp_varbind_int(*vb, c, AGENTX_ADMIN_START);
+       ; //snmp_varbind_int(*vb, c, AGENTX_ADMIN_START);
 
       break;
 
@@ -962,10 +1544,12 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p
       if (c->size < AGENTX_TYPE_INT_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
+      uint fsm_state = snmp_bgp_fsm_state(bgp_proto);
+
       if (fsm_state == BGP4_MIB_ESTABLISHED || fsm_state == BGP4_MIB_ESTABLISHED)
-       snmp_varbind_int(*vb, c, BGP4_MIB_NEGOTIATED_VER_VALUE);
+       ; //snmp_varbind_int(*vb, c, BGP4_MIB_NEGOTIATED_VER_VALUE);
       else
-       snmp_varbind_int(*vb, c, BGP4_MIB_NEGOTIATED_VER_NO_VALUE);
+       ; //snmp_varbind_int(*vb, c, BGP4_MIB_NEGOTIATED_VER_NO_VALUE);
 
       break;
 
@@ -973,78 +1557,78 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p
       if (c->size < AGENTX_TYPE_IP4_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_ip4(*vb, c, ipa_to_ip4(bgp_proto->local_ip));
+      ; //snmp_varbind_ip4(*vb, c, ipa_to_ip4(bgp_proto->local_ip));
       break;
 
     case BGP4_MIB_S_LOCAL_PORT:
       if (c->size < AGENTX_TYPE_INT_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_int(*vb, c, bgp_conf->local_port);
+      ; //snmp_varbind_int(*vb, c, bgp_conf->local_port);
       break;
 
     case BGP4_MIB_S_REMOTE_ADDR:
       if (c->size < AGENTX_TYPE_IP4_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_ip4(*vb, c, ipa_to_ip4(bgp_proto->remote_ip));
+      ; //snmp_varbind_ip4(*vb, c, ipa_to_ip4(bgp_proto->remote_ip));
       break;
 
     case BGP4_MIB_S_REMOTE_PORT:
       if (c->size < AGENTX_TYPE_INT_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_int(*vb, c, bgp_conf->remote_port);
+      ; //snmp_varbind_int(*vb, c, bgp_conf->remote_port);
       break;
 
     case BGP4_MIB_S_REMOTE_AS:
       if (c->size < AGENTX_TYPE_INT_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_int(*vb, c, bgp_proto->remote_as);
+      ; //snmp_varbind_int(*vb, c, bgp_proto->remote_as);
       break;
 
     case BGP4_MIB_S_RX_UPDATES:          /* bgpPeerInUpdates */
       if (c->size < AGENTX_TYPE_COUNTER32_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_counter32(*vb, c, bgp_stats->rx_updates);
+      ; //snmp_varbind_counter32(*vb, c, bgp_stats->rx_updates);
       break;
 
     case BGP4_MIB_S_TX_UPDATES:          /* bgpPeerOutUpdate */
       if (c->size < AGENTX_TYPE_COUNTER32_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_counter32(*vb, c, bgp_stats->tx_updates);
+      ; //snmp_varbind_counter32(*vb, c, bgp_stats->tx_updates);
       break;
 
     case BGP4_MIB_S_RX_MESSAGES:  /* bgpPeerInTotalMessages */
       if (c->size < AGENTX_TYPE_COUNTER32_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_counter32(*vb, c, bgp_stats->rx_messages);
+      ; //snmp_varbind_counter32(*vb, c, bgp_stats->rx_messages);
       break;
 
     case BGP4_MIB_S_TX_MESSAGES:  /* bgpPeerOutTotalMessages */
       if (c->size < AGENTX_TYPE_COUNTER32_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_counter32(*vb, c, bgp_stats->tx_messages);
+      ; //snmp_varbind_counter32(*vb, c, bgp_stats->tx_messages);
       break;
 
     case BGP4_MIB_S_LAST_ERROR:
       if (c->size < snmp_str_size_from_len(2))
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_nstr(*vb, c, last_error, 2);
+      ; //snmp_varbind_nstr(*vb, c, last_error, 2);
       break;
 
     case BGP4_MIB_S_FSM_TRANSITIONS:
       if (c->size < AGENTX_TYPE_COUNTER32_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_counter32(*vb, c,
-         bgp_stats->fsm_established_transitions);
+      //snmp_varbind_counter32(*vb, c,
+        // bgp_stats->fsm_established_transitions);
       break;
 
     case BGP4_MIB_S_FSM_ESTABLISHED_TIME:
@@ -1052,22 +1636,22 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p
        SNMP_MANAGE_TBUF(p, vb, c);
 
 
-      snmp_varbind_gauge32(*vb, c,
-           (current_time() - bgp_proto->last_established) TO_S);
+      //snmp_varbind_gauge32(*vb, c,
+      // (current_time() - bgp_proto->last_established) TO_S);
       break;
 
     case BGP4_MIB_S_RETRY_INTERVAL: /* retry inverval value should be != 0 */
       if (c->size < AGENTX_TYPE_INT_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_int(*vb, c, bgp_conf->connect_retry_time);
+      //snmp_varbind_int(*vb, c, bgp_conf->connect_retry_time);
       break;
 
     case BGP4_MIB_S_HOLD_TIME: /* hold time should be == 0 or in 3..65535 */
       if (c->size < AGENTX_TYPE_INT_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_int(*vb, c, (bgp_conn) ?  bgp_conn->hold_time : 0);
+      //snmp_varbind_int(*vb, c, (bgp_conn) ?  bgp_conn->hold_time : 0);
       break;
 
     case BGP4_MIB_S_KEEPALIVE:
@@ -1075,17 +1659,17 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p
        SNMP_MANAGE_TBUF(p, vb, c);
 
       if (!bgp_conf->hold_time)
-       snmp_varbind_int(*vb, c, 0);
+       ; //snmp_varbind_int(*vb, c, 0);
       else
-       snmp_varbind_int(*vb, c,
-         (bgp_conn) ? bgp_conn->keepalive_time : 0);
+       ; //snmp_varbind_int(*vb, c,
+       //  (bgp_conn) ? bgp_conn->keepalive_time : 0);
       break;
 
     case BGP4_MIB_S_HOLD_TIME_CONFIGURED:
       if (c->size < AGENTX_TYPE_INT_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_int(*vb, c, bgp_conf->hold_time);
+      //snmp_varbind_int(*vb, c, bgp_conf->hold_time);
       break;
 
     case BGP4_MIB_S_KEEPALIVE_CONFIGURED:
@@ -1094,10 +1678,10 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p
 
 
       if (!bgp_conf->keepalive_time)
-       snmp_varbind_int(*vb, c, 0);
+       ; //snmp_varbind_int(*vb, c, 0);
       else
-       snmp_varbind_int(*vb, c,
-         (bgp_conn) ? bgp_conn->keepalive_time : 0);
+       ; //snmp_varbind_int(*vb, c,
+         // (bgp_conn) ? bgp_conn->keepalive_time : 0);
       break;
 
     case BGP4_MIB_S_ORIGINATION_INTERVAL:
@@ -1105,7 +1689,7 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p
       if (c->size < AGENTX_TYPE_INT_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_int(*vb, c, 0);
+      //snmp_varbind_int(*vb, c, 0);
       break;
 
     case BGP4_MIB_S_MIN_ROUTE_ADVERTISEMENT:
@@ -1113,16 +1697,16 @@ bgp_fill_dynamic(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_p
       if (c->size < AGENTX_TYPE_INT_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_int(*vb, c, 0);
+      //snmp_varbind_int(*vb, c, 0);
       break;
 
     case BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME:
       if (c->size < AGENTX_TYPE_INT_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_gauge32(*vb, c,
-       (current_time() - bgp_proto->last_rx_update) TO_S
-      );
+      //snmp_varbind_gauge32(*vb, c,
+       //(current_time() - bgp_proto->last_rx_update) TO_S
+      //);
       break;
 
     case BGP4_MIB_S_END:
@@ -1167,21 +1751,21 @@ bgp_fill_static(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_pd
        SNMP_MANAGE_TBUF(p, vb, c);
 
       c->size -= sz;
-      snmp_varbind_nstr(*vb, c, BGP4_VERSIONS, 1);
+      //snmp_varbind_nstr(*vb, c, BGP4_VERSIONS, 1);
       break;
 
     case BGP4_MIB_S_LOCAL_AS:
       if (c->size < AGENTX_TYPE_INT_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_int(*vb, c, p->bgp_local_as);
+      //snmp_varbind_int(*vb, c, p->bgp_local_as);
       break;
 
     case BGP4_MIB_S_IDENTIFIER:
       if (c->size < AGENTX_TYPE_IP4_SIZE)
        SNMP_MANAGE_TBUF(p, vb, c);
 
-      snmp_varbind_ip4(*vb, c, p->bgp_local_id);
+      //snmp_varbind_ip4(*vb, c, p->bgp_local_id);
       break;
 
     default:
similarity index 89%
rename from proto/snmp/bgp_mib.h
rename to proto/snmp/bgp4_mib.h
index e2a6ea84eb9e274fce83a4c9efa6068296cfd42d..2cac7d8caf1264c654f515ac65530262609d2212 100644 (file)
@@ -1,9 +1,29 @@
-#ifndef _BIRD_SNMP_BGP_MIB_H_
-#define _BIRD_SNMP_BGP_MIB_H_
+#ifndef _BIRD_SNMP_BGP4_MIB_H_
+#define _BIRD_SNMP_BGP4_MIB_H_
+
+#ifdef _BIRD_SNMP_SUBAGENT_H_
+#define BIRD_SNMP_BGP4_SKIP
+#endif
 
 #include "snmp.h"
+#include "proto/bgp/bgp.h"
+
+void snmp_bgp4_register(struct snmp_proto *p);
+
+struct bgp4_mib {
+  enum snmp_tags tag; /* always BGP4_MIB, see subagent.h for more details */
+
+  ip4_addr addr;
+  const struct bgp_proto *bgp_proto;
+  const struct bgp_conn *bgp_conn;
+  const struct bgp_stats *bgp_stats;
+  const struct bgp_config *bgp_conf;
+};
+
 #include "subagent.h"
 
+#ifndef BIRD_SNMP_BGP4_SKIP
+
 #define BGP4_MIB 15
 
 /* peers attributes */
@@ -40,11 +60,6 @@ enum bgp4_mib_peer_entry_row {
 #define BGP4_MIB_NEGOTIATED_VER_VALUE 4
 #define BGP4_MIB_NEGOTIATED_VER_NO_VALUE 0
 
-
-void snmp_bgp_register(struct snmp_proto *p);
-void snmp_bgp_reg_ok(struct snmp_proto *p, struct agentx_response *r, struct oid *oid);
-void snmp_bgp_reg_failed(struct snmp_proto *p, struct agentx_response *r, struct oid *oid);
-
 u8 snmp_bgp_get_valid(u8 state);
 u8 snmp_bgp_getnext_valid(u8 state);
 
@@ -127,3 +142,5 @@ STATIC_ASSERT(BGP4_MIB_ESTABLISHED == BS_ESTABLISHED + 1);
 #define BGP4_MIB_BACKWARD_TRANS_NOTIFICATION 2
 
 #endif
+
+#endif
index 9067cf80c0fe3070c71bdc2a4085276ef4e4a593..1d7c421d9850e5f7947cc4c88888e2af2fa77d1c 100644 (file)
@@ -18,7 +18,7 @@ CF_DEFINES
 
 CF_DECLS
 
-CF_KEYWORDS(SNMP, PROTOCOL, BPG, LOCAL, AS, REMOTE, ADDRESS, PORT, DESCRIPTION,
+CF_KEYWORDS(SNMP, PROTOCOL, BGP, LOCAL, AS, REMOTE, ADDRESS, PORT, DESCRIPTION,
            TIMEOUT, PRIORITY, CONTEXT, DEFAULT, MESSAGE)
 
 CF_GRAMMAR
index a74c7cf95775c7f8b442c64bd8d2d3941aa3cc63..a76723e2bbef2160fe5e8a3c39831bae7a12cdc0 100644 (file)
@@ -28,7 +28,7 @@ mib_mb_realloc(pool *p, void *ptr, unsigned size)
 }
 
 /*
- *mib_tree_init - Initialize a MIB tree
+ * mib_tree_init - Initialize a MIB tree
  * @p: allocation source pool
  * @t: pointer to a tree being initialized
  *
index feae332d069d1857ae9349d08bcc5f16060496c1..14e8d7d8f68e74ab6c9b2440db603d4f140d2745 100644 (file)
@@ -24,10 +24,13 @@ struct mib_node {
   u32 child_len;
 };
 
+struct mib_walk_state;
+
 struct mib_leaf {
   struct mib_node_core c;
   enum snmp_search_res (*filler)(struct snmp_proto *p, struct snmp_pdu *c);
   //enum snmp_search_res (*filler)(struct snmp_proto_pdu *pc, struct agentx_varbind **vb);
+  int (*call_next)(struct snmp_proto *p, struct snmp_pdu *c, struct mib_walk_state *state);
   enum agentx_type type;
   int size;
 };
index e6067ff7fdebd023c00c2f9691c9c4effaa77710..dcc75491b643524a35caa67e3a57a03697ea2d2d 100644 (file)
@@ -10,7 +10,7 @@
  *
  * 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
+ * parsing packets, |bgp4_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.
  *
@@ -334,14 +334,6 @@ snmp_cleanup(struct snmp_proto *p)
     r = NULL;
   }
 
-  struct snmp_registered_oid *ro, *ro2;
-  WALK_LIST_DELSAFE(ro, ro2, p->bgp_registered)
-  {
-    rem_node(&r->n);
-    mb_free(ro);
-    ro = NULL;
-  }
-
   HASH_FREE(p->bgp_hash);
 
   rfree(p->lp);
@@ -507,7 +499,6 @@ snmp_start(struct proto *P)
   p->ping_timer = tm_new_init(p->pool, snmp_ping_timeout, p, p->timeout, 0);
 
   init_list(&p->registration_queue);
-  init_list(&p->bgp_registered);
 
   /* We create copy of bonds to BGP protocols. */
   HASH_INIT(p->bgp_hash, p->pool, 10);
index cb80cdf4e7bb7bd03967ab209c0cb075e6a38a51..fde7f99502f17055faf7f017171a413390cee43f 100644 (file)
@@ -17,8 +17,7 @@
 #include "nest/bird.h"
 #include "nest/protocol.h"
 #include "filter/data.h"
-#include "proto/bgp/bgp.h"
-
+#include "proto/bgp/bgp.h" // TODO remove me
 
 #define SNMP_UNDEFINED 0
 #define SNMP_BGP       1
@@ -42,6 +41,11 @@ enum snmp_proto_state {
   SNMP_RESET,
 };
 
+enum snmp_tags {
+  EMPTY_TAG = 0,
+  BGP4_TAG,
+};
+
 struct snmp_bond {
   node n;
   struct proto_config *config;
@@ -81,20 +85,13 @@ struct snmp_bgp_peer {
   struct snmp_bgp_peer *next;
 };
 
-struct snmp_registration {
-  node n;
-  u8 mib_class;
-  u32 session_id;
-  u32 transaction_id;
-  u32 packet_id;
-  struct oid *oid;
-};
-
 struct snmp_registered_oid {
   node n;
   struct oid *oid;
 };
 
+struct mib_tree;      /* see mib_tree.h */
+
 struct snmp_proto {
   struct proto p;
   struct object_lock *lock;
@@ -125,8 +122,6 @@ struct snmp_proto {
 
   uint registrations_to_ack;               /* counter of pending responses to register-pdu */
   list registration_queue;                 /* list containing snmp_register records */
-  list bgp_registered;             /* list of currently registered bgp oids
-                                    * (struct snmp_registered_oid) */
 
   // map
   struct f_trie *bgp_trie;
@@ -138,6 +133,23 @@ struct snmp_proto {
   timer *ping_timer;
   btime startup_delay;
   timer *startup_timer;
+
+  struct mib_tree *mib_tree;
+};
+
+struct snmp_registration;
+struct agentx_response; /* declared in subagent.h */
+typedef void (*snmp_reg_hook_t)(struct snmp_proto *p, const struct agentx_response *res, struct snmp_registration *reg);
+
+struct snmp_registration {
+  node n;
+  u8 mib_class;
+  u32 session_id;
+  u32 transaction_id;
+  u32 packet_id;
+  struct oid *oid;
+  snmp_reg_hook_t reg_hook_ok; /* hook called when successful response to OID registration is recieved */
+  snmp_reg_hook_t reg_hook_fail; /* hook called when OID registration fail */
 };
 
 //void snmp_tx(sock *sk);
index aecef3375a4b9e604328dda540c8e6e2b1d26fd7..43b38fed160998d8ae0384d720ae8586c52d41e2 100644 (file)
@@ -385,7 +385,7 @@ t_oid_compare(void)
   bt_assert(snmp_oid_compare(no_pref2, pref2) == 0);
 
   bt_assert(snmp_oid_compare(pref, pref2) < 0);
-  bt_assert(snmp_oid_compare(pref2, pref) > 0); 
+  bt_assert(snmp_oid_compare(pref2, pref) > 0);
   bt_assert(snmp_oid_compare(pref, no_pref2) < 0);
   bt_assert(snmp_oid_compare(no_pref2, pref) > 0);
   bt_assert(snmp_oid_compare(no_pref, pref2) < 0);
@@ -1119,7 +1119,7 @@ gen_test_find(struct oid *(*generator)(void))
       last = found;
 
       /* test finding with walk state not pointing at the root of the tree */
-      u8 subids = LOAD_U8(oids[i]->n_subid); 
+      u8 subids = LOAD_U8(oids[i]->n_subid);
       if (subids > 0)
       {
        found = NULL;
@@ -1204,10 +1204,10 @@ gen_test_find(struct oid *(*generator)(void))
        mib_tree_walk_init(&walk, (xrandom(2)) ? tree : NULL);
 
        STORE_U8(searched[search]->n_subid, new_ids);
-  
+
        mib_node_u *ignored UNUSED;
        ignored = mib_tree_find(tree, &walk, searched[search]);
-  
+
        STORE_U8(searched[search]->n_subid, subids);
 
        found = mib_tree_find(tree, &walk, searched[search]);
@@ -1375,7 +1375,7 @@ gen_test_delete_remove(struct oid *(*generator)(void), int remove)
        //mib_tree_walk_init(&walk, tree, 0);
        mib_tree_walk_init(&walk, NULL);
        mib_node_u *node = mib_tree_find(tree, &walk, sorted[j]);
-       
+
        if (snmp_is_oid_empty(oid))
          ;
        /* the oid could have multiple instances in the oids dataset */
@@ -1478,7 +1478,7 @@ gen_test_traverse(struct oid *(*generator)(void))
       nodes[d] = mib_tree_find(tree, &walk, sorted[d]);
     }
 
-    int bound = 0; 
+    int bound = 0;
 
     for (int d = 0; d < distinct; d++)
     {
@@ -1630,8 +1630,8 @@ gen_test_leafs(struct oid *(*generator)(void))
 
       bt_assert(snmp_oid_compare(last, oid) < 0);
       bt_assert(mib_node_is_leaf(((mib_node_u *)current)));
-  
-      while (oid_index < distinct && 
+
+      while (oid_index < distinct &&
          (nodes[oid_index] == NULL || !mib_node_is_leaf(nodes[oid_index])))
        oid_index++;
 
@@ -1646,7 +1646,7 @@ gen_test_leafs(struct oid *(*generator)(void))
 
     current = mib_tree_walk_next_leaf(tree, &walk);
     bt_assert(current == NULL);
-    bt_assert(oid_index == distinct); 
+    bt_assert(oid_index == distinct);
     bt_assert(i == leafs);
 
     mb_free(oids);
index bb7c6efd7447e0210948d11a430e4f60a2d3fedb..76b866848ef16a02f283940ddb4527bd262afeb4 100644 (file)
@@ -65,7 +65,7 @@ snmp_varbind_set_name_len(struct snmp_proto *p, struct agentx_varbind **vb, u8 l
   uint diff_size = (len - LOAD_U8(oid->n_subid)) * sizeof(u32);
   if (c->size < diff_size)
   {
-    snmp_manage_tbuf(p, (void **) vb, c);
+    snmp_manage_tbuf(p, c);
     oid = &(*vb)->name;
   }
 
@@ -81,7 +81,7 @@ snmp_varbind_duplicate_hdr(struct snmp_proto *p, struct agentx_varbind **vb, str
   ASSUME(vb != NULL && *vb != NULL);
   uint hdr_size = snmp_varbind_header_size(*vb);
   if (c->size < hdr_size)
-    snmp_manage_tbuf(p, (void **) vb, c);
+    snmp_manage_tbuf(p, c);
 
   ASSERT(c->size >= hdr_size);
   byte *buffer = c->buffer;
@@ -260,12 +260,38 @@ snmp_varbind_hdr_size_from_oid(const struct oid *oid)
  *
  * This function assumes valid @t.
  */
-inline void
+inline enum snmp_search_res
 snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t)
 {
   ASSUME(t != AGENTX_INVALID);
   STORE_U16(vb->type, t);
   STORE_U16(vb->reserved, 0);
+
+  switch (t)
+  {
+    case AGENTX_END_OF_MIB_VIEW:
+      return SNMP_SEARCH_END_OF_VIEW;
+    case AGENTX_NO_SUCH_OBJECT:
+      return SNMP_SEARCH_NO_OBJECT;
+    case AGENTX_NO_SUCH_INSTANCE:
+      return SNMP_SEARCH_NO_INSTANCE;
+
+    /* valid varbind types */
+    case AGENTX_INTEGER:
+    case AGENTX_OCTET_STRING:
+    case AGENTX_NULL:
+    case AGENTX_OBJECT_ID:
+    case AGENTX_IP_ADDRESS:
+    case AGENTX_COUNTER_32:
+    case AGENTX_GAUGE_32:
+    case AGENTX_TIME_TICKS:
+    case AGENTX_OPAQUE:
+    case AGENTX_COUNTER_64:
+      return SNMP_SEARCH_OK;
+
+    default:
+      die("invalid varbind type");
+  }
 }
 
 /* Internal wrapper */
@@ -660,7 +686,7 @@ snmp_oid_compare(const struct oid *left, const struct oid *right)
     /* check prefix */
     if (LOAD_U32(left->ids[4]) < (u32) right_prefix)
       return -1;
-    else if (LOAD_U32(left->ids[4]) > (u32) right_prefix) 
+    else if (LOAD_U32(left->ids[4]) > (u32) right_prefix)
       return 1;
 
     /* the right prefix is already checked (+1) */
@@ -798,45 +824,46 @@ snmp_varbind_type32(struct agentx_varbind *vb, struct snmp_pdu *c, enum agentx_t
 }
 
 inline void
-snmp_varbind_int(struct agentx_varbind *vb, struct snmp_pdu *c, u32 val)
+snmp_varbind_int(struct snmp_pdu *c, u32 val)
 {
-  snmp_varbind_type32(vb, c, AGENTX_INTEGER, val);
+  snmp_varbind_type32(c->sr_vb_start, c, AGENTX_INTEGER, val);
 }
 
 inline void
-snmp_varbind_counter32(struct agentx_varbind *vb, struct snmp_pdu *c, u32 val)
+snmp_varbind_counter32(struct snmp_pdu *c, u32 val)
 {
-  snmp_varbind_type32(vb, c, AGENTX_COUNTER_32, val);
+  snmp_varbind_type32(c->sr_vb_start, c, AGENTX_COUNTER_32, val);
 }
 
 inline void
-snmp_varbind_ticks(struct agentx_varbind *vb, struct snmp_pdu *c, u32 val)
+snmp_varbind_ticks(struct snmp_pdu *c, u32 val)
 {
-  snmp_varbind_type32(vb, c, AGENTX_TIME_TICKS, val);
+  snmp_varbind_type32(c->sr_vb_start, c, AGENTX_TIME_TICKS, val);
 }
 
 inline void
-snmp_varbind_gauge32(struct agentx_varbind *vb, struct snmp_pdu *c, s64 time)
+snmp_varbind_gauge32(struct snmp_pdu *c, s64 time)
 {
-  snmp_varbind_type32(vb, c, AGENTX_GAUGE_32, MAX(0, MIN(time, UINT32_MAX)));
+  snmp_varbind_type32(c->sr_vb_start, c,
+    AGENTX_GAUGE_32, MAX(0, MIN(time, UINT32_MAX)));
 }
 
 inline void
-snmp_varbind_ip4(struct agentx_varbind *vb, struct snmp_pdu *c, ip4_addr addr)
+snmp_varbind_ip4(struct snmp_pdu *c, ip4_addr addr)
 {
-  snmp_set_varbind_type(vb, AGENTX_IP_ADDRESS);
-  c->buffer = snmp_put_ip4(snmp_varbind_data(vb), addr);
+  snmp_set_varbind_type(c->sr_vb_start, AGENTX_IP_ADDRESS);
+  c->buffer = snmp_put_ip4(snmp_varbind_data(c->sr_vb_start), addr);
 }
 
 // TODO doc string, we have already the varbind prepared
 inline byte *
-snmp_varbind_nstr2(struct agentx_varbind *vb, uint size, const char *str, uint len)
+snmp_varbind_nstr2(struct snmp_pdu *c, uint size, const char *str, uint len)
 {
   if (size < snmp_str_size_from_len(len))
     return NULL;
 
-  snmp_set_varbind_type(vb, AGENTX_OCTET_STRING);
-  return snmp_put_nstr(snmp_varbind_data(vb), str, len);
+  snmp_set_varbind_type(c->sr_vb_start, AGENTX_OCTET_STRING);
+  return snmp_put_nstr(snmp_varbind_data(c->sr_vb_start), str, len);
 }
 
 /*
@@ -851,10 +878,10 @@ snmp_varbind_nstr2(struct agentx_varbind *vb, uint size, const char *str, uint l
  * more info.
  */
 void
-snmp_varbind_nstr(struct agentx_varbind *vb, struct snmp_pdu *c, const char *str, uint len)
+snmp_varbind_nstr(struct snmp_pdu *c, const char *str, uint len)
 {
-  snmp_set_varbind_type(vb, AGENTX_OCTET_STRING);
-  c->buffer = snmp_put_nstr(snmp_varbind_data(vb), str, len);
+  snmp_set_varbind_type(c->sr_vb_start, AGENTX_OCTET_STRING);
+  c->buffer = snmp_put_nstr(snmp_varbind_data(c->sr_vb_start), str, len);
 }
 
 inline enum agentx_type
index c01d82fb42664d25971fa57538865c9f3a7cab19..ede6a43e6cdc5951a34c6f3f1415918682f447ba 100644 (file)
@@ -14,7 +14,7 @@ uint snmp_pkt_len(const byte *start, const byte *end);
 /*
  *  AgentX - Variable Binding (VarBind) type utils
  */
-void snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t);
+enum snmp_search_res snmp_set_varbind_type(struct agentx_varbind *vb, enum agentx_type t);
 enum agentx_type snmp_get_varbind_type(const struct agentx_varbind *vb);
 int agentx_type_size(enum agentx_type t);
 
@@ -74,12 +74,12 @@ int snmp_test_close_reason(byte value);
 /* Functions filling buffer a typed value */
 struct agentx_varbind *snmp_create_varbind(byte *buf, struct oid *oid);
 struct agentx_varbind *snmp_create_varbind_null(byte *buf);
-void snmp_varbind_int(struct agentx_varbind *vb, struct snmp_pdu *c, u32 val);
-void snmp_varbind_counter32(struct agentx_varbind *vb, struct snmp_pdu *c, u32 val);
-void snmp_varbind_gauge32(struct agentx_varbind *vb, struct snmp_pdu *c, s64 time);
-void snmp_varbind_ticks(struct agentx_varbind *vb, struct snmp_pdu *c, u32 val);
-void snmp_varbind_ip4(struct agentx_varbind *vb, struct snmp_pdu *c, ip4_addr addr);
-void snmp_varbind_nstr(struct agentx_varbind *vb, struct snmp_pdu *c, const char *str, uint len);
+void snmp_varbind_int(struct snmp_pdu *c, u32 val);
+void snmp_varbind_counter32(struct snmp_pdu *c, u32 val);
+void snmp_varbind_gauge32(struct snmp_pdu *c, s64 time);
+void snmp_varbind_ticks(struct snmp_pdu *c, u32 val);
+void snmp_varbind_ip4(struct snmp_pdu *c, ip4_addr addr);
+void snmp_varbind_nstr(struct snmp_pdu *c, const char *str, uint len);
 
 /* Raw */
 byte *snmp_no_such_object(byte *buf, struct agentx_varbind *vb, struct oid *oid);
index 0892e8904d0b3135f432064d9b5ad8cab9c5d3de..21712dc09ca3f38921639afcc27fd5620f876330 100644 (file)
@@ -10,8 +10,9 @@
 
 #include "lib/unaligned.h"
 #include "subagent.h"
+#include "mib_tree.h"
 #include "snmp_utils.h"
-#include "bgp_mib.h"
+#include "bgp4_mib.h"
 
 /* =============================================================
  *  Problems
@@ -115,45 +116,11 @@ snmp_blank_header(struct agentx_header *h, enum agentx_pdu_types type)
   snmp_header(h, type, (u8) 0);
 }
 
-/*
- * snmp_register_ok - registration of OID was successful
- * @p: SNMP protocol instance
- * @res: header of agentx-Response-PDU
- * @oid: OID that was successfully registered
- * @class: MIB subtree of @oid
- *
- * Send a notification to MIB (selected by @class) about successful registration
- * of @oid.
- */
-static void
-snmp_register_ok(struct snmp_proto *p, struct agentx_response *res, struct oid *oid, u8 UNUSED class)
-{
-  // todo switch based on oid type
-  snmp_bgp_reg_ok(p, res, oid);
-}
-
-/*
- * snmp_regsiter_failed - registration of OID failed
- * @p: SNMP protocol instance
- * @res: header of agentx-Response-PDU
- * @oid: OID whose registration failed
- * @class: MIB subtree of @oid
- *
- * Send a notification to MIB (selected by @class) about @oid registration
- * failure.
- */
-static void
-snmp_register_failed(struct snmp_proto *p, struct agentx_response *res, struct oid *oid, u8 UNUSED class)
-{
-  // todo switch based on oid type
-  snmp_bgp_reg_failed(p, res, oid);
-}
-
 /*
  * snmp_register_ack - handle registration response
  * @p: SNMP protocol instance
  * @res: header of agentx-Response-PDU
- * @class: MIB subtree associated with agentx-Register-PDU 
+ * @class: MIB subtree associated with agentx-Register-PDU
  */
 void
 snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, u8 class)
@@ -161,26 +128,18 @@ snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, u8 class)
   struct snmp_registration *reg;
   WALK_LIST(reg, p->registration_queue)
   {
-    // todo add support for more mib trees (other than BGP4-MIB)
     if (snmp_registration_match(reg, &res->h, class))
     {
-      struct snmp_registered_oid *ro = \
-        mb_alloc(p->p.pool, sizeof(struct snmp_registered_oid));
-
-      ro->n.prev = ro->n.next = NULL;
-
-      ro->oid = reg->oid;
-
       rem_node(&reg->n);
-      mb_free(reg);
       p->registrations_to_ack--;
 
-      add_tail(&p->bgp_registered, &ro->n);
-
       if (res->error == AGENTX_RES_NO_ERROR)
-       snmp_register_ok(p, res, ro->oid, class);
+       reg->reg_hook_ok(p, (const struct agentx_response *) res, reg);
       else
-       snmp_register_failed(p, res, ro->oid, class);
+       reg->reg_hook_fail(p, (const struct agentx_response *) res, reg);
+
+      mb_free(reg->oid);
+      mb_free(reg);
       return;
     }
   }
@@ -247,7 +206,7 @@ open_pdu(struct snmp_proto *p, struct oid *oid)
   /* Make sure that we have enough space in TX-buffer */
   if (c.size < AGENTX_HEADER_SIZE + TIMEOUT_SIZE + snmp_oid_size(oid) +
       + snmp_str_size(cf->description))
-    snmp_manage_tbuf(p, NULL, &c);
+    snmp_manage_tbuf(p, &c);
 
   struct agentx_header *h = (void *) c.buffer;
   ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
@@ -293,6 +252,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
   struct snmp_pdu c;
   snmp_pdu_context(&c, sk);
 
+// TODO use more readable anonymous structure decl.
 #define UPTIME_SIZE \
   (6 * sizeof(u32)) /* sizeof( { u32 vb_type, u32 oid_hdr, u32 ids[4] } ) */
 #define TRAP0_HEADER_SIZE \
@@ -306,7 +266,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
 
   /* Make sure that we have enough space in TX-buffer */
   if (c.size < sz)
-    snmp_manage_tbuf(p, NULL, &c);
+    snmp_manage_tbuf(p, &c);
 
   struct agentx_header *h = (void *) c.buffer;
   ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
@@ -332,7 +292,7 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
 
     /* TODO use time from last reconfiguration instead? [config->load_time] */
     btime uptime = current_time() - boot_time;
-    snmp_varbind_ticks(vb, &c, (uptime TO_S) / 100);
+    snmp_varbind_ticks(&c, (uptime TO_S) / 100);
     ASSUME(snmp_test_varbind(vb));
     ADVANCE(c.buffer, c.size, snmp_varbind_size_unsafe(vb));
   }
@@ -397,11 +357,11 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, u32 bound, uint index, en
 
 #define BOUND_SIZE sizeof(u32)
   /* conditional +4 for upper-bound (optinal field) */
-  uint sz = AGENTX_HEADER_SIZE + snmp_oid_size(oid) + 
+  uint sz = AGENTX_HEADER_SIZE + snmp_oid_size(oid) +
       ((bound > 1) ? BOUND_SIZE : 0);
 
   if (c.size < sz)
-    snmp_manage_tbuf(p, NULL, &c);
+    snmp_manage_tbuf(p, &c);
 
   struct agentx_header *h = (void *) c.buffer;
   ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
@@ -483,7 +443,7 @@ close_pdu(struct snmp_proto *p, enum agentx_close_reasons reason)
 
 #define REASON_SIZE sizeof(u32)
   if (c.size < AGENTX_HEADER_SIZE + REASON_SIZE)
-    snmp_manage_tbuf(p, NULL, &c);
+    snmp_manage_tbuf(p, &c);
 
   struct agentx_header *h = (void *) c.buffer;
   ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
@@ -614,7 +574,7 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start)
   snmp_pdu_context(&c, sk);
 
   if (c.size < AGENTX_HEADER_SIZE)
-    snmp_manage_tbuf(p, NULL, &c);
+    snmp_manage_tbuf(p, &c);
 
   res = prepare_response(p, &c);
 
@@ -675,7 +635,6 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start)
   {
     TRACE(D_PACKETS, "SNMP SET action failed (not writable)");
     /* This is a recoverable error, we do not need to reset the connection */
-    //response_err_ind(p, res, AGENTX_RES_RESOURCE_UNAVAILABLE, c.index + 1);
     response_err_ind(p, res, AGENTX_RES_NOT_WRITABLE, c.index + 1);
   }
 
@@ -711,7 +670,7 @@ parse_sets_pdu(struct snmp_proto *p, byte * const pkt_start, enum agentx_respons
   struct snmp_pdu c;
   snmp_pdu_context(&c, p->sock);
   if (c.size < sizeof(struct agentx_response))
-    snmp_manage_tbuf(p, NULL, &c);
+    snmp_manage_tbuf(p, &c);
 
   struct agentx_response *r = prepare_response(p, &c);
 
@@ -786,6 +745,7 @@ parse_cleanup_set_pdu(struct snmp_proto *p, byte * const pkt_start)
   if (pkt_size != 0)
   {
     // TODO should we free even for malformed packets ??
+    // TODO -> check that data is not freed
     return AGENTX_HEADER_SIZE;
   }
 
@@ -981,8 +941,7 @@ parse_response(struct snmp_proto *p, byte *res)
 void
 snmp_register_mibs(struct snmp_proto *p)
 {
-  snmp_bgp_register(p);
-  /* snmp_ospf_regsiter(p); ... */
+  snmp_bgp4_register(p);
 }
 
 /*
@@ -1071,7 +1030,8 @@ snmp_get_mib_class(const struct oid *oid)
  *
  * Return 0 if the created VarBind type is endOfMibView, 1 otherwise.
  */
-static int
+// TODO remove me
+static int UNUSED
 snmp_get_next2(struct snmp_proto *p, struct agentx_varbind **vb_search, struct oid *o_end, struct snmp_pdu *c)
 {
   enum snmp_search_res r;
@@ -1111,7 +1071,7 @@ snmp_get_next2(struct snmp_proto *p, struct agentx_varbind **vb_search, struct o
 
   o_start = &(*vb_search)->name;
   if (c->size < snmp_varbind_hdr_size_from_oid(o_start))
-    snmp_manage_tbuf(p, (void **) vb_search, c);
+    snmp_manage_tbuf(p, c);
 
   snmp_set_varbind_type(*vb_search, AGENTX_END_OF_MIB_VIEW);
   return 0;
@@ -1186,7 +1146,7 @@ snmp_get_next3(struct snmp_proto *p, struct oid *o_start, struct oid *o_end,
   }
 
   if (c->size < snmp_varbind_hdr_size_from_oid(o_start))
-    snmp_manage_tbuf(p, (void **) vb, c);
+    snmp_manage_tbuf(p, c);
 
   vb = snmp_create_varbind(c->buffer, o_start);
   vb->type = AGENTX_END_OF_MIB_VIEW;
@@ -1368,7 +1328,7 @@ snmp_oid_prefixize(struct snmp_proto *p, const struct oid *oid, struct snmp_pdu
   uint oid_size = snmp_oid_size(oid);
 
   if (c->size < oid_size)
-    snmp_manage_tbuf(p, NULL, c);
+    snmp_manage_tbuf(p, c);
 
   // TODO check if the @oid is prefixable
   ASSERT(c->size >= oid_size);
@@ -1393,7 +1353,7 @@ snmp_vb_to_tx(struct snmp_proto *p, const struct oid *oid, struct snmp_pdu *c)
 {
   uint vb_hdr_size = snmp_varbind_hdr_size_from_oid(oid);
   if (c->size < vb_hdr_size)
-    snmp_manage_tbuf(p, NULL, c);
+    snmp_manage_tbuf(p, c);
 
   ASSERT(c->size >= vb_hdr_size);
   struct agentx_varbind *vb = (void *) c->buffer;
@@ -1500,6 +1460,78 @@ parse_gets_error(struct snmp_proto *p, struct snmp_pdu *c, uint len)
 
   return len + AGENTX_HEADER_SIZE;
 }
+
+static enum snmp_search_res
+snmp_mib_fill2(struct snmp_proto *p, struct snmp_pdu *c, mib_node_u *mib_node)
+{
+  if (!mib_node || !mib_node_is_leaf(mib_node))
+  {
+    snmp_set_varbind_type(c->sr_vb_start, AGENTX_NO_SUCH_OBJECT);
+    ADVANCE(c->buffer, c->size, snmp_varbind_header_size(c->sr_vb_start));
+    return AGENTX_NO_SUCH_OBJECT;
+  }
+
+  struct mib_leaf *leaf = &mib_node->leaf;
+
+  return leaf->filler(p, c);
+}
+
+void
+snmp_get_pdu(struct snmp_proto *p, struct snmp_pdu *c, struct mib_walk_state *walk)
+{
+  mib_node_u *node;
+  node = mib_tree_find(p->mib_tree, walk, &c->sr_vb_start->name);
+
+  (void) snmp_mib_fill2(p, c, node);
+}
+
+int
+snmp_get_next_pdu(struct snmp_proto *p, struct snmp_pdu *c, struct mib_walk_state *walk)
+{
+  mib_node_u *node;
+  node = mib_tree_find(p->mib_tree, walk, &c->sr_vb_start->name);
+
+  int inclusive = c->sr_vb_start->name.include;
+
+  int move_next;
+  if (!node && inclusive)
+    move_next = 1;
+  else if (!node && !inclusive)
+    move_next = 1;
+  else if (node && inclusive && mib_node_is_leaf(node))
+    move_next = 0;
+  else if (node && inclusive)
+    move_next = 1;
+  else if (node && !inclusive)
+    move_next = 0;
+
+  struct mib_leaf *leaf = &node->leaf;
+  if (move_next && node && mib_node_is_leaf(node))
+    move_next = leaf->call_next(p, c, walk);
+
+  if (move_next)
+    node = (mib_node_u *) mib_tree_walk_next_leaf(p->mib_tree, walk);
+
+  enum snmp_search_res res;
+  res = snmp_mib_fill2(p, c, node);
+
+  if (res != SNMP_SEARCH_OK)
+    snmp_set_varbind_type(c->sr_vb_start, AGENTX_END_OF_MIB_VIEW);
+
+  return res == SNMP_SEARCH_OK;
+}
+
+void
+snmp_get_bulk_pdu(struct snmp_proto *p, struct snmp_pdu *c, struct mib_walk_state *walk, struct agentx_bulk_state *bulk)
+{
+  if (c->index >= bulk->getbulk.non_repeaters)
+    bulk->repeaters++;
+
+  // store the o_start and o_end
+
+  bulk->has_any |= snmp_get_next_pdu(p, c, walk);
+}
+
 /*
  * parse_gets_pdu - parse received gets PDUs
  * @p: SNMP protocol instance
@@ -1513,9 +1545,7 @@ static uint
 parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
 {
   // TODO checks for c.size underflow
-  //struct agentx_varbind *vb = NULL;
-  struct agentx_varbind *vb_start = NULL;
-  struct oid *o_end = NULL;
+  struct mib_walk_state walk;
   byte *pkt = pkt_start;
 
   struct agentx_header *h = (void *) pkt;
@@ -1530,7 +1560,6 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
    * Get-Bulk processing stops if all the varbind have type END_OF_MIB_VIEW
    * has_any is true if some varbind has type other than END_OF_MIB_VIEW
    */
-  int has_any = 0;
   struct agentx_bulk_state bulk_state = { };
   if (h->type == AGENTX_GET_BULK_PDU)
   {
@@ -1544,6 +1573,7 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
     struct agentx_getbulk *bulk_info = (void *) pkt;
     ADVANCE(pkt, pkt_size, sizeof(struct agentx_getbulk));
 
+    //TODO: bulk_state = AGENTX_BULK_STATE_INITIALIZER(bulk_info);
     bulk_state = (struct agentx_bulk_state) {
       .getbulk = {
        .non_repeaters = LOAD_U32(bulk_info->non_repeaters),
@@ -1552,6 +1582,7 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
       /* In contrast to the RFC, we use 0-based indices. */
       .index = 0,
       .repetition = 0,
+      .has_any = 0,
     };
   }
 
@@ -1592,30 +1623,34 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
     /* We don't too to check for oversided OID because the PDU has 8k size limit */
 
     /* We create copy of OIDs outside of rx-buffer and also prefixize them */
-    vb_start = snmp_vb_to_tx(p, o_start_rx, &c);
-    o_end = snmp_oid_to_scratch(o_end_rx);
+    c.sr_vb_start = snmp_vb_to_tx(p, o_start_rx, &c);
+    c.sr_o_end = snmp_oid_to_scratch(o_end_rx);
 
-    ASSERT(vb_start);
-    ASSERT(o_end);
+    ASSERT(c.sr_vb_start); // TODO implement failed parsing logic
+    ASSERT(c.sr_o_end);
 
-    if (!snmp_is_oid_empty(o_end) && snmp_oid_compare(&vb_start->name, o_end) > 0)
+    if (!snmp_is_oid_empty(c.sr_o_end) &&
+       snmp_oid_compare(&c.sr_vb_start->name, c.sr_o_end) > 0)
     {
       c.error = AGENTX_RES_GEN_ERROR;
       return parse_gets_error(p, &c, pkt_size);
     }
 
-    /* TODO find mib_class, check if type is GET of GET_NEXT, act accordingly */
     switch (h->type)
     {
       case AGENTX_GET_PDU:
-       snmp_mib_fill(p, &vb_start, &c);
+       snmp_get_pdu(p, &c, &walk);
+       //snmp_mib_fill(p, &vb_start, &c);
        break;
 
       case AGENTX_GET_NEXT_PDU:
-       snmp_get_next2(p, &vb_start, o_end, &c);
+       snmp_get_next_pdu(p, &c, &walk);
+       //snmp_get_next2(p, &vb_start, o_end, &c);
        break;
 
       case AGENTX_GET_BULK_PDU:
+       snmp_get_bulk_pdu(p, &c, &walk, &bulk_state);
+       #if 0
        if (c.index >= bulk_state.getbulk.non_repeaters)
          bulk_state.repeaters++;
 
@@ -1624,14 +1659,15 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
        /* The behavior of GetBulk pdu in the first iteration is
         * identical to GetNext pdu. */
        has_any = snmp_get_next2(p, &vb_start, o_end, &c) || has_any;
+       #endif
        break;
 
       default:
        die("incorrect usage");
     }
 
-    vb_start = NULL;
-    o_end = NULL;
+    c.sr_vb_start = NULL;
+    c.sr_o_end = NULL;
 
     c.index++;
   } /* while (c.error == AGENTX_RES_NO_ERROR && size > 0) */
@@ -1641,6 +1677,7 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
   if (h->type == AGENTX_GET_BULK_PDU)
   {
   #if 0
+    // TODO
     for (bulk_state.repetition++;
         has_any && bulk_state.repetition < bulk_state.getbulk.max_repetitions;
         bulk_state.repetition++)
@@ -1660,6 +1697,7 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
 
   /* We send the message in TX-buffer. */
   sk_send(sk, s);
+
   // TODO think through the error state
 
   /* number of bytes parsed from RX-buffer */
@@ -2022,6 +2060,7 @@ snmp_prefixize(struct snmp_proto *proto, const struct oid *oid)
 static void
 snmp_mib_fill(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_pdu *c)
 {
+  (void) p;
   ASSUME(vb != NULL && *vb != NULL);
 
   struct oid *oid = &((*vb)->name);
@@ -2037,7 +2076,7 @@ snmp_mib_fill(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_pdu
   switch (mib_class)
   {
     case SNMP_CLASS_BGP:
-      snmp_bgp_fill(p, vb, c);
+      //snmp_bgp_fill(p, vb, c);
       break;
 
     case SNMP_CLASS_INVALID:
@@ -2050,7 +2089,26 @@ snmp_mib_fill(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_pdu
 }
 
 /*
- * snmp_manage_tbuf - handle situation with too short transmit buffer
+ * snmp_manage_tbuf - TODO
+ */
+void
+snmp_manage_tbuf(struct snmp_proto *p, struct snmp_pdu *c)
+{
+  sock *sk = p->sock;
+  int diff;
+  if (c->sr_vb_start != NULL)
+    diff = (void *) c->sr_vb_start - (void *) sk->tbuf;
+
+  log(L_INFO "snmp_manage_tbuf2()");
+  sk_set_tbsize(sk, sk->tbsize + 2048);
+  c->size += 2048;
+
+  if (c->sr_vb_start != NULL)
+    c->sr_vb_start = (struct agentx_varbind *) (sk->tbuf + diff);
+}
+
+/*
+ * snmp_manage_tbuf2 - handle situation with too short transmit buffer
  * @p: SNMP protocol instance
  * @c: transmit packet context to use
  *
@@ -2058,7 +2116,7 @@ snmp_mib_fill(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_pdu
  *  are invalidated!
  */
 void
-snmp_manage_tbuf(struct snmp_proto *p, void **ptr, struct snmp_pdu *c)
+snmp_manage_tbuf2(struct snmp_proto *p, void **ptr, struct snmp_pdu *c)
 {
   sock *sk = p->sock;
   int diff;
@@ -2069,7 +2127,6 @@ snmp_manage_tbuf(struct snmp_proto *p, void **ptr, struct snmp_pdu *c)
   sk_set_tbsize(sk, sk->tbsize + 2048);
   c->size += 2048;
 
-  
   if (ptr)
     *ptr = sk->tbuf + diff;
 }
index 9701ba41412b714f559b9e7a509e637aa2d0fe4d..93db65f29ec1a6aa155809bb82c7baa51a1750ff 100644 (file)
@@ -191,11 +191,6 @@ struct agentx_octet_str {
   byte data[0];
 };
 
-struct agentx_getbulk {
-  u16 non_repeaters;
-  u16 max_repetitions;
-};
-
 struct agentx_response {
   struct agentx_header h;
   u32 uptime;
@@ -219,11 +214,17 @@ struct agentx_un_register_hdr {
   u8 reserved; /* always zero filled */
 };
 
+struct agentx_getbulk {
+  u16 non_repeaters;
+  u16 max_repetitions;
+};
+
 struct agentx_bulk_state {
   struct agentx_getbulk getbulk;
   u16 index;
   u16 repetition;
   u32 repeaters;
+  int has_any;     /* flag is clear when all responses are EndOfMibView */
 };
 
 enum agentx_pdu_types {
@@ -292,17 +293,29 @@ enum agentx_response_errs {
   AGENTX_RES_PROCESSING_ERR        = 268,      /* processingError */
 } PACKED;
 
-/* SNMP PDU TX-buffer info */
+/* SNMP PDU info */
 struct snmp_pdu {
+  /* TX buffer */
   byte *buffer;                            /* pointer to buffer */
   uint size;                       /* unused space in buffer */
+
+  /* Search Range */
+  struct agentx_varbind *sr_vb_start; /* search range starting OID inside TX buffer (final storage) */
+  struct oid *sr_o_end;                    /* search range ending OID */
+
+  /* Control */
   enum agentx_response_errs error;  /* storage for result of current action */
   u32 index;                       /* index on which the error was found */
+
+  union snmp_mibs_data *mibs_data;  /* data passed from MIB search phase to MIB fill phase */
 };
 
-struct snmp_proto_pdu {
-  struct snmp_proto *p;
-  struct snmp_pdu *c;
+#include "bgp4_mib.h"
+
+union snmp_mibs_data {
+  enum snmp_tags empty;
+
+  struct bgp4_mib bgp4;
 };
 
 struct snmp_packet_info {
@@ -331,7 +344,7 @@ void snmp_register(struct snmp_proto *p, struct oid *oid, uint index, uint len,
 void snmp_unregister(struct snmp_proto *p, struct oid *oid, uint index, uint len, uint contid);
 void snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, int include_uptime);
 
-void snmp_manage_tbuf(struct snmp_proto *p, void **ptr, struct snmp_pdu *c);
+void snmp_manage_tbuf(struct snmp_proto *p, struct snmp_pdu *c);
 
 struct agentx_varbind *snmp_vb_to_tx(struct snmp_proto *p, const struct oid *oid, struct snmp_pdu *c);
 u8 snmp_get_mib_class(const struct oid *oid);