]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
tmp: compiles, first tests
authorVojtech Vilimek <vojtech.vilimek@nic.cz>
Sat, 5 Nov 2022 15:29:00 +0000 (16:29 +0100)
committerVojtech Vilimek <vojtech.vilimek@nic.cz>
Sat, 5 Nov 2022 15:29:00 +0000 (16:29 +0100)
proto/snmp/Makefile
proto/snmp/bgp_mib.c
proto/snmp/bgp_mib.h
proto/snmp/snmp.c
proto/snmp/snmp.h
proto/snmp/snmp_test.c [new file with mode: 0644]
proto/snmp/subagent.c
proto/snmp/subagent.h

index 0965e4488d86f918db89d6b61c6e3f7afbb2915b..86070d4f461bc103e48a0d0840ba2d79d3ae4a17 100644 (file)
@@ -4,4 +4,6 @@ $(all-daemon)
 $(cf-local)
 $(call proto-build,snmp_build)
 
+tests_src := snmp_test.c
+tests_targets := $(tests_targets) $(tests-target-files)
 tests_objs := $(tests_objs) $(src-o-files)
index 9318d620ce1ebc9de94a996dd8ab227d2d04595d..2b36af841de4225a1a6e4c97024c07a9f7ce7b40 100644 (file)
  *      (c) 2022 CZ.NIC z.s.p.o
  *
  *     Can be freely distributed and used under the terms of the GNU GPL.
- *
- *      Parts of this file were auto-generated using mib2c
- *      using mib2c.create-dataset.conf
  */
 
-/*
-#include <net-snmp/net-snmp-config.h>
-#include <net-snmp/net-snmp-includes.h>
-#include <net-snmp/varbind_api.h>
-#include <net-snmp/agent/net-snmp-agent-includes.h>
-*/
-
-// fix conflicts
-#undef PACKAGE_BUGREPORT
-#undef PACKAGE_NAME
-#undef PACKAGE_STRING
-#undef PACKAGE_TARNAME
-#undef PACKAGE_VERSION
+/* BGP_MIB states see enum BGP_INTERNAL_STATES */
 
 #include "snmp.h"
 #include "subagent.h"
 #include "bgp_mib.h"
 
+static const char * const debug_bgp_states[] = {
+  [BGP_INTERNAL_INVALID] = "BGP_INTERNAL_INVALID",
+  [BGP_INTERNAL_BGP] = "BGP_INTERNAL_BGP",
+  [BGP_INTERNAL_VERSION] = "BGP_INTERNAL_VERSION",
+  [BGP_INTERNAL_LOCAL_AS] = "BGP_INTERNAL_LOCAL_AS",
+  [BGP_INTERNAL_PEER_TABLE] = "BGP_INTERNAL_PEER_TABLE",
+  [BGP_INTERNAL_PEER_ENTRY] = "BGP_INTERNAL_PEER_ENTRY",
+  [BGP_INTERNAL_IDENTIFIER] = "BGP_INTERNAL_IDENTIFIER",
+  [BGP_INTERNAL_STATE] = "BGP_INTERNAL_STATE",
+  [BGP_INTERNAL_ADMIN_STATUS] = "BGP_INTERNAL_ADMIN_STATUS",
+  [BGP_INTERNAL_NEGOTIATED_VERSION] = "BGP_INTERNAL_NEGOTIATED_VERSION", 
+  [BGP_INTERNAL_LOCAL_ADDR] = "BGP_INTERNAL_LOCAL_ADDR",
+  [BGP_INTERNAL_LOCAL_PORT] = "BGP_INTERNAL_LOCAL_PORT", 
+  [BGP_INTERNAL_REMOTE_ADDR] = "BGP_INTERNAL_REMOTE_ADDR",
+  [BGP_INTERNAL_REMOTE_PORT] = "BGP_INTERNAL_REMOTE_PORT", 
+  [BGP_INTERNAL_REMOTE_AS] = "BGP_INTERNAL_REMOTE_AS",
+  [BGP_INTERNAL_RX_UPDATES] = "BGP_INTERNAL_RX_UPDATES",
+  [BGP_INTERNAL_TX_UPDATES] = "BGP_INTERNAL_TX_UPDATES",
+  [BGP_INTERNAL_RX_MESSAGES] = "BGP_INTERNAL_RX_MESSAGES",
+  [BGP_INTERNAL_TX_MESSAGES] = "BGP_INTERNAL_TX_MESSAGES",
+  [BGP_INTERNAL_LAST_ERROR] = "BGP_INTERNAL_LAST_ERROR", 
+  [BGP_INTERNAL_FSM_TRANSITIONS] = "BGP_INTERNAL_FSM_TRANSITIONS",
+  [BGP_INTERNAL_FSM_ESTABLISHED_TIME] = "BGP_INTERNAL_FSM_ESTABLISHED_TIME",
+  [BGP_INTERNAL_RETRY_INTERVAL] = "BGP_INTERNAL_RETRY_INTERVAL",
+  [BGP_INTERNAL_HOLD_TIME] = "BGP_INTERNAL_HOLD_TIME",
+  [BGP_INTERNAL_KEEPALIVE] = "BGP_INTERNAL_KEEPALIVE",
+  [BGP_INTERNAL_HOLD_TIME_CONFIGURED] = "BGP_INTERNAL_HOLD_TIME_CONFIGURED",
+  [BGP_INTERNAL_KEEPALIVE_CONFIGURED] = "BGP_INTERNAL_KEEPALIVE_CONFIGURED",  
+  [BGP_INTERNAL_ORIGINATION_INTERVAL] = "BGP_INTERNAL_ORIGINATION_INTERVAL",
+  [BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT] = "BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT",
+  [BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME] = "BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME",
+  [BGP_INTERNAL_END] = "BGP_INTERNAL_END",
+  [BGP_INTERNAL_NO_VALUE] = "BGP_INTERNAL_NO_VALUE",
+};
+
 void
 snmp_bgp_register()
 {}
 
+int
+snmp_bgp_valid_ip4(struct oid *o)
+{
+  return snmp_valid_ip4_index_safe(o, 6);
+}
+
+static u8
+bgp_get_candidate(u32 field)
+{
+  const u8 translation_table[] = {
+    [SNMP_BGP_IDENTIFIER]              = BGP_INTERNAL_IDENTIFIER,
+    [SNMP_BGP_STATE]                   = BGP_INTERNAL_STATE,
+    [SNMP_BGP_ADMIN_STATUS]            = BGP_INTERNAL_ADMIN_STATUS,
+    [SNMP_BGP_NEGOTIATED_VERSION]      = BGP_INTERNAL_NEGOTIATED_VERSION,
+    [SNMP_BGP_LOCAL_ADDR]              = BGP_INTERNAL_LOCAL_ADDR,
+    [SNMP_BGP_LOCAL_PORT]              = BGP_INTERNAL_LOCAL_PORT,
+    [SNMP_BGP_REMOTE_ADDR]             = BGP_INTERNAL_REMOTE_ADDR,
+    [SNMP_BGP_REMOTE_PORT]             = BGP_INTERNAL_REMOTE_PORT,
+    [SNMP_BGP_REMOTE_AS]               = BGP_INTERNAL_REMOTE_AS,
+    [SNMP_BGP_RX_UPDATES]              = BGP_INTERNAL_RX_UPDATES,
+    [SNMP_BGP_TX_UPDATES]              = BGP_INTERNAL_TX_UPDATES,
+    [SNMP_BGP_RX_MESSAGES]             = BGP_INTERNAL_RX_MESSAGES,
+    [SNMP_BGP_TX_MESSAGES]             = BGP_INTERNAL_TX_MESSAGES,
+    [SNMP_BGP_LAST_ERROR]              = BGP_INTERNAL_LAST_ERROR,
+    [SNMP_BGP_FSM_TRANSITIONS]         = BGP_INTERNAL_FSM_TRANSITIONS,
+    [SNMP_BGP_FSM_ESTABLISHED_TIME]    = BGP_INTERNAL_FSM_ESTABLISHED_TIME,
+    [SNMP_BGP_RETRY_INTERVAL]          = BGP_INTERNAL_RETRY_INTERVAL,
+    [SNMP_BGP_HOLD_TIME]               = BGP_INTERNAL_HOLD_TIME,
+    [SNMP_BGP_KEEPALIVE]               = BGP_INTERNAL_KEEPALIVE,
+    [SNMP_BGP_HOLD_TIME_CONFIGURED]    = BGP_INTERNAL_HOLD_TIME_CONFIGURED,
+    [SNMP_BGP_KEEPALIVE_CONFIGURED]     = BGP_INTERNAL_KEEPALIVE_CONFIGURED,
+    [SNMP_BGP_ORIGINATION_INTERVAL]     = BGP_INTERNAL_ORIGINATION_INTERVAL,
+    [SNMP_BGP_MIN_ROUTE_ADVERTISEMENT]  = BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT,
+    [SNMP_BGP_IN_UPDATE_ELAPSED_TIME]   = BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME,
+  };
+
+  /* first value is in secord cell of array translation_table (as the
+   * SNMP_BPG_IDENTIFIER == 1
+   */
+  if (field > 0 && field < sizeof(translation_table) / sizeof(translation_table[0]))
+    return translation_table[field];
+  else
+    return BGP_INTERNAL_NO_VALUE;
+}
+
+static inline struct ip4_addr
+ip4_from_oid(const struct oid *o)
+{
+  return (o->n_subid == 9) ? ip4_build(o->ids[5], o->ids[6], o->ids[7],
+o->ids[8]) : IP4_NONE;
+}
+
+/**
+ * snmp_bgp_state - linearize oid from BGP4-MIB
+ * @oid: prefixed object identifier from BGP4-MIB::bgp subtree
+ *
+ * Returns linearized state for Get-PDU, GetNext-PDU and GetBulk-PDU packets.
+ */
+u8
+snmp_bgp_state(struct oid *oid)
+{
+  /* already checked:
+            xxxxxxxx p
+   *  (*oid): .1.3.6.1.2.1.15
+   *   -> BGP4-MIB::bgp (root)
+   */
+
+  u8 state = BGP_INTERNAL_NO_VALUE;
+      
+  u8 candidate;
+  switch (oid->n_subid)
+  {
+    default:
+      if (oid->n_subid < 2)
+      {
+       state = BGP_INTERNAL_INVALID;
+       break;
+      }
+      /* else oid->n_subid >= 2 */
+        /* fall through */
+
+   /* between ids[6] and ids[9] should be IP address
+    * validity is checked later in execution because
+    *  this field also could mean a boundry (upper or lower)
+    */
+    case 9:
+    case 8:
+    case 7:
+    case 6:
+    case 5:
+      state = bgp_get_candidate(oid->ids[4]);
+
+      /* fall through */
+
+    case 4:
+      if (oid->ids[3] == BGP4_PEER_ENTRY)
+       state = (state == BGP_INTERNAL_NO_VALUE) ?
+         BGP_INTERNAL_PEER_ENTRY : state;
+      else
+       state = BGP_INTERNAL_NO_VALUE;
+
+      /* fall through */
+
+    case 3:
+      /* u8 candidate; */
+      switch (oid->ids[2])
+      {
+       
+       case SNMP_BGP_VERSION:
+         state = BGP_INTERNAL_VERSION; 
+         break;
+       case SNMP_BGP_LOCAL_AS:
+         state = BGP_INTERNAL_LOCAL_AS;
+         break;
+       case SNMP_BGP_PEER_TABLE:
+         /* candidate avoid overriding more specific state */
+         candidate = BGP_INTERNAL_PEER_TABLE;
+         break;
+
+
+       default:  /* test fails */
+         /* invalidate the state forcefully */
+         if (oid->ids[2] < SNMP_BGP_VERSION)
+         {
+           state = BGP_INTERNAL_NO_VALUE;
+           candidate = BGP_INTERNAL_NO_VALUE;
+         }
+
+         else /* oid->ids[2] > SNMP_BGP_PEER_TABLE */
+           state = BGP_INTERNAL_END; 
+      }
+      state = (state == BGP_INTERNAL_NO_VALUE) ? 
+       candidate : state;
+
+      /* fall through */
+
+    case 2: /* bare BGP4-MIB::bgp */
+      if (state == BGP_INTERNAL_NO_VALUE ||
+         state == BGP_INTERNAL_INVALID)
+       state = BGP_INTERNAL_BGP;
+  }
+
+  return state;
+}
+
+inline int
+is_dynamic(u8 state)
+{
+  return (state >= BGP_INTERNAL_IDENTIFIER && 
+         state <= BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME);
+}
+
+static inline int
+snmp_bgp_has_value(u8 state)
+{
+  /* bitmap would be faster */
+  if (state <= BGP_INTERNAL_BGP ||
+      state == BGP_INTERNAL_PEER_TABLE ||
+      state == BGP_INTERNAL_PEER_ENTRY)
+    return 0; /* hasn't value */
+  else
+  {
+    
+  }
+    return 1; /* has value */
+}
+
+/**
+ * snmp_bgp_get_valid - only states with valid value
+ * @state: BGP linearized state
+ *
+ * Returns @state if has value in BGP4-MIB, zero otherwise. Used for Get-PDU
+ * packets.
+ */
+u8
+snmp_bgp_get_valid(u8 state)
+{
+  /* invalid
+   * SNMP_BGP SNMP_BGP_PEER_TABLE SNMP_BGP_PEER_ENTRY
+   * SNMP_BGP_FSM_ESTABLISHED_TIME SNMP_BGP_IN_UPDATE_ELAPSED_TIME
+   */
+  if (state == 1 || state == 4 || state == 5 ||
+      state == 21 || state == 29) 
+    return 0;
+  else
+    return state;
+}
+
+/**
+ * snmp_bgp_next_state - next state that has value
+ * @state: BGP linearized state
+ *
+ * Returns successor state of @state with valid value in BG4-MIB. Used for
+ * GetNext-PDU and GetBulk-PDU packets.
+ */
+u8
+snmp_bgp_next_state(u8 state)
+{
+  switch (state)
+  {
+    case BGP_INTERNAL_LOCAL_AS:
+    case BGP_INTERNAL_PEER_TABLE:
+    case BGP_INTERNAL_PEER_ENTRY:
+      return BGP_INTERNAL_IDENTIFIER;
+
+    case BGP_INTERNAL_FSM_TRANSITIONS:
+    case BGP_INTERNAL_FSM_ESTABLISHED_TIME:
+      return BGP_INTERNAL_RETRY_INTERVAL;
+
+
+    case BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME:
+
+    case BGP_INTERNAL_END:
+
+      return BGP_INTERNAL_END;
+
+    default:
+      return state + 1;
+  }
+}
+
 int
 snmp_bgp_is_supported(struct oid *o)
 {
+  /* most likely not functioning */
   if (o->prefix == 2 && o->n_subid > 0 && o->ids[0] == 1)
   {
     if (o->n_subid == 2 && o->ids[1] == BGP4_MIB_VERSION ||
@@ -57,6 +299,253 @@ snmp_bgp_is_supported(struct oid *o)
     else
       return 0;
   }
+
+  return 0;
+}
+
+static struct oid *
+update_bgp_oid(struct oid *oid, u8 state)
+{
+  ASSERT (state != BGP_INTERNAL_INVALID);
+  ASSERT (state != BGP_INTERNAL_NO_VALUE);
+  ASSERT (state != BGP_INTERNAL_END);
+
+  /* if same state, no need to realloc anything */
+  if (snmp_bgp_state(oid) == state)
+    return oid;
+
+  switch (state)
+  {
+    case BGP_INTERNAL_BGP:
+      /* could destroy same old data */
+      oid = mb_realloc(oid, sizeof(struct oid) + 2 * sizeof(u32));
+      oid->n_subid = 2;
+      oid->ids[0] = 1;
+      oid->ids[1] = SNMP_BGP4_MIB;
+      break;
+
+    case BGP_INTERNAL_VERSION:
+      oid = mb_realloc(oid, sizeof(struct oid) + 3 * sizeof(u32));
+      oid->n_subid = 3;
+      oid->ids[2] = SNMP_BGP_VERSION;
+      break;
+
+    case BGP_INTERNAL_LOCAL_AS:
+      oid->ids[2] = 2;
+      break;
+
+    case BGP_INTERNAL_IDENTIFIER:
+      oid = mb_realloc(oid, sizeof(struct oid) + 9 * sizeof(u32));
+      oid->n_subid = 9;
+      oid->ids[2] = SNMP_BGP_PEER_TABLE;
+      oid->ids[3] = SNMP_BGP_PEER_ENTRY;
+      oid->ids[4] = SNMP_BGP_IDENTIFIER;
+      /* zero the ip */
+      oid->ids[5] = oid->ids[6] = oid->ids[7] = oid->ids[8] = 0;
+      break;
+
+#define SNMP_UPDATE_CASE(num, update)        \
+    case num:                                \
+      oid->ids[4] = update;                  \
+      break;
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_STATE, SNMP_BGP_STATE) 
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_ADMIN_STATUS, SNMP_BGP_ADMIN_STATUS)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_NEGOTIATED_VERSION, SNMP_BGP_NEGOTIATED_VERSION)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_LOCAL_ADDR, SNMP_BGP_LOCAL_ADDR)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_LOCAL_PORT, SNMP_BGP_LOCAL_PORT)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_REMOTE_ADDR, SNMP_BGP_REMOTE_ADDR)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_REMOTE_PORT, SNMP_BGP_REMOTE_PORT)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_REMOTE_AS, SNMP_BGP_REMOTE_AS)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_RX_UPDATES, SNMP_BGP_RX_UPDATES)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_TX_UPDATES, SNMP_BGP_TX_UPDATES)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_RX_MESSAGES, SNMP_BGP_RX_MESSAGES)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_TX_MESSAGES, SNMP_BGP_TX_MESSAGES)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_LAST_ERROR, SNMP_BGP_LAST_ERROR)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_FSM_TRANSITIONS, SNMP_BGP_FSM_TRANSITIONS)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_FSM_ESTABLISHED_TIME, SNMP_BGP_FSM_ESTABLISHED_TIME)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_RETRY_INTERVAL, SNMP_BGP_RETRY_INTERVAL)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_HOLD_TIME, SNMP_BGP_HOLD_TIME)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_KEEPALIVE, SNMP_BGP_KEEPALIVE)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_HOLD_TIME_CONFIGURED, SNMP_BGP_HOLD_TIME_CONFIGURED)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_KEEPALIVE_CONFIGURED, SNMP_BGP_KEEPALIVE_CONFIGURED)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_ORIGINATION_INTERVAL, SNMP_BGP_ORIGINATION_INTERVAL)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT, SNMP_BGP_MIN_ROUTE_ADVERTISEMENT)
+
+    SNMP_UPDATE_CASE(BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME, SNMP_BGP_IN_UPDATE_ELAPSED_TIME)
+  }
+
+  return oid;
+#undef SNMP_UPDATE_CASE
+}
+
+// TODO test bgp_find_dynamic_oid
+static struct oid *
+bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, u8 state UNUSED)
+{
+  ip4_addr ip4 = ip4_from_oid(o_start);
+  ip4_addr dest = ip4_from_oid(o_end);
+
+  net_addr *net = mb_allocz(p->p.pool, sizeof(struct net_addr));
+  net_fill_ip4(net, ip4, IP4_MAX_PREFIX_LENGTH);
+
+  log(L_INFO "dynamic part of BGP mib");
+
+  struct f_trie_walk_state *ws = mb_allocz(p->p.pool,
+                                          sizeof(struct f_trie_walk_state));
+
+  trie_walk_init(ws, p->bgp_trie, NULL);
+
+  if (trie_walk_next(ws, net) && ip4_less(net4_prefix(net), dest))
+  {
+    struct oid *o = mb_allocz(p->p.pool, sizeof(struct oid) + 9 * sizeof(u32));
+    o->n_subid = 9;
+
+    memcpy(o, o_start, snmp_oid_size(o_start));
+    snmp_oid_ip4_index(o, net4_prefix(net));
+
+    mb_free(net);
+    mb_free(ws);
+
+    return o;
+  }
+
   else
-    return 0;
+  {
+    mb_free(net);
+    mb_free(ws);
+  }
+
+  return NULL;
+}
+
+byte *
+snmp_bgp_fill(struct snmp_proto *p UNUSED, struct oid *oid, byte *buf UNUSED,
+uint size UNUSED, uint contid UNUSED, int byte_ord UNUSED)
+{
+  u8 state = snmp_bgp_state(oid);
+  (void)state;
+  return NULL;
+}
+
+/* o_start could be o_curr, but has basically same meaning for searching */
+struct oid *
+search_bgp_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid UNUSED)
+{
+  u8 start_state = snmp_bgp_state(o_start);
+  //u8 state_curr = snmp_bgp_state(o_start);
+  //u8 state_end = (o_end) ? snmp_bgp_state(o_end) : 0;
+
+  if (o_start->include && snmp_bgp_has_value(start_state) &&
+      !is_dynamic(start_state) && o_start->n_subid == 3)
+  {
+    o_start->include = 0;  /* disable including for next time */
+    return o_start;
+  }
+
+  /* if state is_dynamic() then has more value and need find the right one */
+  else if (!is_dynamic(start_state))
+  {
+    u8 next_state = snmp_bgp_next_state(start_state);
+    o_start = update_bgp_oid(o_start, next_state);
+
+    if (!is_dynamic(next_state))
+      return o_start;
+
+    else
+    {
+      struct oid *copy = o_start;
+      do {
+       /* update_bgp_oid can reallocate the underlaying struct */
+       o_start = copy = update_bgp_oid(copy, next_state);
+
+       o_start = bgp_find_dynamic_oid(p, o_start, o_end, next_state);
+
+       next_state = snmp_bgp_next_state(next_state);
+
+      } while (o_start != NULL && next_state < BGP_INTERNAL_END);
+
+      return o_start;
+    }
+  }
+
+  /* else - is_dynamic(start_state) */  
+    /* ... (same as do ... while above) */
+
+
+  return NULL;
+  /* TODO not implemented yet */
+
+  /* older implementation - untested */
+  /* if o_curr is in invalid state, o_curr->include does't make any
+   * difference; invalid state ~ no value to put in response packet 
+   */
+  /* indent \v/ */
+  u8 state_curr = snmp_bgp_getnext_valid(state_curr);
+
+  struct oid *o_curr = update_bgp_oid(o_curr, state_curr);
+
+  /* static part of BGP4-MIB tree, not depending on BGP connections */
+  if (state_curr <= 5)
+  {
+    return o_curr;
+  }
+  /* dynamic part of BGP4-MIB tree, depending on BGP connections */
+  else /* state_curr > 5 */
+  {
+    ip4_addr ip4 = ip4_from_oid(o_curr);
+    ip4_addr dest = ip4_from_oid(o_end);
+
+    net_addr *net = mb_allocz(p->p.pool, sizeof(struct net_addr));
+    net_fill_ip4(net, ip4, IP4_MAX_PREFIX_LENGTH);
+
+    log(L_INFO "dynamic part of BGP mib");
+
+    struct f_trie_walk_state *ws = mb_allocz(p->p.pool,
+                                            sizeof(struct f_trie_walk_state));
+
+    struct oid *o = mb_allocz(p->p.pool, sizeof(struct oid) + 8 * sizeof(u32));
+    o->n_subid = 9;
+    trie_walk_init(ws, p->bgp_trie, NULL);
+
+    if (trie_walk_next(ws, net) && ip4_less(net4_prefix(net), dest))
+    {
+      memcpy(o, o_curr, snmp_oid_size(o_curr));
+      snmp_oid_ip4_index(o, net4_prefix(net));
+
+      mb_free(net);
+      mb_free(ws);
+
+      return o;
+    }
+
+    else
+    {
+      mb_free(net);
+      mb_free(ws);
+
+      return NULL;
+    }
+  }
 }
index 5854bcf40d494a65d725b52772f4a2dbcef441df..1a7b6c0710ed0b184cd5e5f0448d5c97d29ca27e 100644 (file)
@@ -8,7 +8,7 @@ enum BGP4_MIB {
   SNMP_BGP_IDENTIFIER              =  1,
   SNMP_BGP_STATE                   =  2,
   SNMP_BGP_ADMIN_STATUS                    =  3,   /* in read-only mode */
-  SNMP_BGP_VERSION                 =  4,
+  SNMP_BGP_NEGOTIATED_VERSION      =  4,
   SNMP_BGP_LOCAL_ADDR              =  5,
   SNMP_BGP_LOCAL_PORT              =  6,
   SNMP_BGP_REMOTE_ADDR             =  7,
@@ -34,12 +34,63 @@ enum BGP4_MIB {
 //void snmp_init_bgp_table(void);
 //void snmp_del_bgp_table(void);
 
+struct oid;
+
 void snmp_bgp_register(void);
 int snmp_bgp_is_supported(struct oid *o);
 
-#define BGP4_MIB_VERSION  1
+int snmp_bgp_valid_ip4(struct oid *o);
+u8 snmp_bgp_state(struct oid *o);
+u8 snmp_bgp_get_valid(u8 state);
+u8 snmp_bgp_getnext_valid(u8 state);
+
+struct oid *search_bgp_mib(struct snmp_proto *p , struct oid *o_start, struct oid *o_end, uint contid);
+byte * snmp_bgp_fill(struct snmp_proto *p, struct oid *oid, byte *buf, uint size, uint contid UNUSED, int byte_ord);
+
+#define BGP4_MIB_VERSION 1
 #define BGP4_MIB_LOCAL_AS 2
 #define BGP4_PEER_TABLE          3
 #define BGP4_PEER_ENTRY            1
 
+#define SNMP_BGP_VERSION    1
+#define SNMP_BGP_LOCAL_AS   2
+#define SNMP_BGP_PEER_TABLE 3
+#define SNMP_BGP_PEER_ENTRY   1
+
+/* BGP linearized state */
+enum BGP_INTERNAL_STATES {
+  BGP_INTERNAL_INVALID = 0,
+  BGP_INTERNAL_BGP = 1,
+  BGP_INTERNAL_VERSION,
+  BGP_INTERNAL_LOCAL_AS,
+  BGP_INTERNAL_PEER_TABLE,
+  BGP_INTERNAL_PEER_ENTRY,
+  BGP_INTERNAL_IDENTIFIER,
+  BGP_INTERNAL_STATE,
+  BGP_INTERNAL_ADMIN_STATUS,
+  BGP_INTERNAL_NEGOTIATED_VERSION, 
+  BGP_INTERNAL_LOCAL_ADDR,
+  BGP_INTERNAL_LOCAL_PORT, 
+  BGP_INTERNAL_REMOTE_ADDR,
+  BGP_INTERNAL_REMOTE_PORT, 
+  BGP_INTERNAL_REMOTE_AS,
+  BGP_INTERNAL_RX_UPDATES,
+  BGP_INTERNAL_TX_UPDATES,
+  BGP_INTERNAL_RX_MESSAGES,
+  BGP_INTERNAL_TX_MESSAGES,
+  BGP_INTERNAL_LAST_ERROR, 
+  BGP_INTERNAL_FSM_TRANSITIONS,
+  BGP_INTERNAL_FSM_ESTABLISHED_TIME,
+  BGP_INTERNAL_RETRY_INTERVAL,
+  BGP_INTERNAL_HOLD_TIME,
+  BGP_INTERNAL_KEEPALIVE,
+  BGP_INTERNAL_HOLD_TIME_CONFIGURED,
+  BGP_INTERNAL_KEEPALIVE_CONFIGURED,  
+  BGP_INTERNAL_ORIGINATION_INTERVAL,
+  BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT,
+  BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME,
+  BGP_INTERNAL_END,
+  BGP_INTERNAL_NO_VALUE = 255,
+} PACKED;
+
 #endif
index ee8dd6f731899ea280efb4a8ecb2d343ffba4bc2..0343168dcb3017c93def79df54ff7207845d7a74 100644 (file)
@@ -5,9 +5,6 @@
  *      (c) 2022 CZ.NIC z.s.p.o.
  *
  *     Can be freely distributed and used under the terms of the GNU GPL.
- *
- *      Parts of this file were auto-generated using mib2c
- *      using mib2c.create-dataset.conf
  */
 
 #include "nest/bird.h"
index ac2f01d6e7d11ea7a35462a89c00da26b39e2506..45f24aa7504fff121d7f7a96a6b7bda7b2e8a264 100644 (file)
@@ -106,4 +106,7 @@ struct snmp_proto {
   uint errs;
 };
 
+/* fixes bugs when making tests */
+//struct protocol proto_snmp;
+
 #endif
diff --git a/proto/snmp/snmp_test.c b/proto/snmp/snmp_test.c
new file mode 100644 (file)
index 0000000..dd4adc0
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ *     BIRD -- Simple Network Management Protocol (SNMP) Unit tests
+ *
+ *      (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.
+ */
+
+#include "test/birdtest.h"
+
+#include "bgp_mib.h"
+#include "subagent.h"
+#include "snmp.h"
+
+#define SNMP_EXPECTED(actual, expected) \
+  bt_debug("%s  expected: %3u   actual: %3u\n", \
+    #expected, expected, actual);
+
+void
+dump_oid(struct oid *oid)
+{
+  bt_debug(" OID DUMP: \n");
+  bt_debug("  n_subid = %3u  prefix = %3u  include %s  --- \n",
+    oid->n_subid, oid->prefix, (oid->include != 0) ? "yes" : "no" );
+
+  for (int i = 0; i < oid->n_subid; i++)
+    bt_debug(" %u:  %u\n", i + 1, oid->ids[i]);
+
+  bt_debug(" OID DUMP END\n");
+}
+
+void
+dump_bgp_state_values(void)
+{
+    // TODO XXX here
+}
+
+
+static void
+test_oid(struct oid *oid, uint base_size)
+{
+  /* tests all states one by one */
+
+  oid->n_subid = base_size + 2;
+  oid->ids[0] = 1;
+  oid->ids[1] = 15;  // BGP4-MIB::bgp
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_BGP);
+
+  oid->n_subid = base_size + 3;
+  oid->ids[2] = 1;   // BGP4-MIB::bgpVersion
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_VERSION);
+
+  oid->ids[2] = 2;   // BGP4-MIB::bgpLocalAs
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_LOCAL_AS);
+
+  oid->ids[2] = 3;   // BGP4-MIB::bgpPeerTable
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_PEER_TABLE);
+
+  bt_debug("testing BGP4-MIB::bgpPeerEntry\n");
+  oid->n_subid = base_size + 4;
+  oid->ids[2] = 3;
+  oid->ids[3] = 1;   // BGP4-MIB::bgpPeerEntry
+  dump_oid(oid);
+  SNMP_EXPECTED(snmp_bgp_state(oid), BGP_INTERNAL_PEER_ENTRY);
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_PEER_ENTRY);
+
+  oid->n_subid = base_size + 5;
+  oid->ids[2] = 3;
+  oid->ids[3] = 1;
+  oid->ids[4] = 1;    // BGP4-MIB::bgpPeerIdentifier
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_IDENTIFIER);
+
+  oid->ids[4] = 2;    // BGP4-MIB::bgpPeerState
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_STATE);
+
+  oid->ids[4] = 3;    // BGP4-MIB::bgpPeerAdminStatus
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_ADMIN_STATUS);
+  
+  oid->ids[4] = 4;    // BGP4-MIB::bgpPeerNegotiatedVersion
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_NEGOTIATED_VERSION);
+  
+  oid->ids[4] = 5;    // BGP4-MIB::bgpPeerLocalAddr
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_LOCAL_ADDR);
+  
+  oid->ids[4] = 6;    // BGP4-MIB::bgpPeerLocalPort
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_LOCAL_PORT);
+  
+  oid->ids[4] = 7;    // BGP4-MIB::bgpPeerRemoteAddr
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_REMOTE_ADDR);
+  
+  oid->ids[4] = 8;    // BGP4-MIB::bgpPeerRemotePort
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_REMOTE_PORT);
+  
+  oid->ids[4] = 9;    // BGP4-MIB::bgpPeerRemoteAs
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_REMOTE_AS);
+  
+  oid->ids[4] = 10;   // BGP4-MIB::bgpPeerInUpdates
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_RX_UPDATES);
+  
+  oid->ids[4] = 11;   // BGP4-MIB::bgpPeerOutUpdates
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_TX_UPDATES);
+  
+  oid->ids[4] = 12;   // BGP4-MIB::bgpPeerInTotalMessages
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_RX_MESSAGES);
+  
+  oid->ids[4] = 13;   // BGP4-MIB::bgpPeerOutTotalMessages
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_TX_MESSAGES);
+  
+  oid->ids[4] = 14;   // BGP4-MIB::bgpPeerLastError
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_LAST_ERROR);
+  
+  oid->ids[4] = 15;   // BGP4-MIB::bgpPeerFsmEstablishedTransitions
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_FSM_TRANSITIONS);
+  
+  oid->ids[4] = 16;   // BGP4-MIB::bgpPeerFsmEstablishedTime
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_FSM_ESTABLISHED_TIME);
+  
+  oid->ids[4] = 17;   // BGP4-MIB::bgpPeerConnectionRetryInterval
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_RETRY_INTERVAL);
+  
+  oid->ids[4] = 18;   // BGP4-MIB::bgpPeerHoldTime
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_HOLD_TIME);
+  
+  oid->ids[4] = 19;   // BGP4-MIB::bgpPeerKeepAlive
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_KEEPALIVE);
+  
+  oid->ids[4] = 20;   // BGP4-MIB::bgpPeerHoldTimeConfigured
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_HOLD_TIME_CONFIGURED);
+  
+  oid->ids[4] = 21;   // BGP4-MIB::bgpPeerKeepAliveConfigured
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_KEEPALIVE_CONFIGURED);
+  
+  oid->ids[4] = 22;   // BGP4-MIB::bgpPeerMinASOriginationInterval
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_ORIGINATION_INTERVAL);
+  
+  oid->ids[4] = 23;   // BGP4-MIB::bgpPeerMinRouteAdvertisementInverval
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT);
+
+  oid->ids[4] = 24;   // BGP4-MIB::bgpPeerInUpdateElapsedTime
+  bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME);
+}
+
+static int
+t_s_bgp_state(void)
+{
+  struct oid *oid = alloca(sizeof(struct oid) + 10 * sizeof(32));
+
+  /* oid header */
+  oid->n_subid = 0;
+  oid->prefix = 2;
+  oid->include = 0;
+  oid->pad = 0;
+
+  /* test all states with expected oid length */
+  bt_debug("testing precise oids\n");
+  test_oid(oid, 0);
+
+  for (int i = 0; i < 10; i++)
+    oid->ids[i] = (u32) bt_random();
+
+  /* if this subid is too high it does not match the test case
+   * in general test_oid() func
+   */
+  oid->ids[2] = 0;
+
+  /* test all states with garbage ip */
+  bt_debug("testing oids with random ip index\n");
+  test_oid(oid, 4);
+
+  /* test all states with invalid ip */
+  bt_debug("testing oids with invalid ip index\n");
+  /* zero the states that overlap */
+  oid->ids[2] = 0;
+  oid->ids[3] = 0;
+  oid->ids[4] = 0;
+
+  oid->ids[5] = 0;
+  oid->ids[6] = 257;
+  oid->ids[7] = 127;
+  oid->ids[8] = 0xFFFF;
+  test_oid(oid, 4);
+
+  bt_debug("testing too long oids\n");
+  bt_debug("not implemented\n");
+  bt_debug("exiting\n");
+  return 1;
+}
+
+int main(int argc, char **argv)
+{
+  bt_init(argc, argv);
+
+  bt_test_suite(t_s_bgp_state, "Function snmp_bgp_state()");
+
+  return bt_exit_value();
+}
index 475e6fe5c14aa1b5c5954218af2bdf0c347de7d7..7a0ad4dbb44f085ee22b02e6415008b140b1fa98 100644 (file)
@@ -24,7 +24,6 @@
  */
 
 static int parse_response(struct snmp_proto *p, byte *buf, uint size);
-static inline uint oid_size(struct oid *o);
 static inline uint vb_size(struct agentx_varbind *vb);
 static int snmp_stop_ack(sock *sk, uint size);
 static void do_response(struct snmp_proto *p, byte *buf, uint size);
@@ -32,7 +31,7 @@ static uint parse_get_pdu(struct snmp_proto *p, byte *buf, uint size);
 static uint parse_gets_pdu(struct snmp_proto *p, byte *buf, uint size);
 static byte *prepare_response(struct snmp_proto *p, byte *buf, uint size);
 static void response_err_ind(byte *buf, uint err, uint ind);
-static struct oid *bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, struct oid *o_curr);
+static struct oid *search_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, struct oid *o_curr, uint contid);
 static struct oid *prefixize(struct snmp_proto *p, struct oid *o, int byte_ord);
 static inline byte *find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid, int byte_ord);
 static byte *no_such_object(byte *buf, struct agentx_varbind *vb);
@@ -67,6 +66,25 @@ str_size(const char *str)
   return 4 + BIRD_ALIGN(strlen(str), 4);
 }
 
+int
+snmp_valid_ip4_index(struct oid *o, uint start)
+{
+  for (int i = 0; i < 4; i++)
+    if (o->ids[start + i] >= 256)
+      return 0;        // false
+  return 1; // true 
+}
+
+int
+snmp_valid_ip4_index_safe(struct oid *o, uint start)
+{
+  if (start + 3 < o->n_subid)
+    return snmp_valid_ip4_index(o, start);
+  else
+    return 0; // false
+}
+
 static byte *
 put_str(byte *buf, const char *str)
 {
@@ -131,8 +149,8 @@ put_oid(byte *buf, struct oid *oid)
   return buf + (oid->n_subid << 2);
 }
 
-static void
-oid_ip4_index(struct oid *o, ip4_addr addr)
+void
+snmp_oid_ip4_index(struct oid *o, ip4_addr addr)
 {
   u32 temp = ip4_to_u32(addr);
   STORE(o->ids[5], temp >> 24);
@@ -166,7 +184,7 @@ open_pdu(struct snmp_proto *p, struct oid *oid)
 
   //uint pkt_size = 0;
 
-  if (size > AGENTX_HEADER_SIZE + oid_size(oid) + str_size(str))
+  if (size > AGENTX_HEADER_SIZE + snmp_oid_size(oid) + str_size(str))
   {
     log(L_INFO "open_pdu()");
 
@@ -196,7 +214,7 @@ open_pdu(struct snmp_proto *p, struct oid *oid)
 
   else
     log(L_INFO "open_pdu() insufficient size, %u <= %u ",
-       size, AGENTX_HEADER_SIZE + oid_size(oid) + str_size(str));
+       size, AGENTX_HEADER_SIZE + snmp_oid_size(oid) + str_size(str));
 }
 
 /* index allocate / deallocate pdu * /
@@ -237,7 +255,7 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8
   uint size = sk->tbsize;
 
   /* conditional +4 for upper-bound */
-  if (size > AGENTX_HEADER_SIZE + oid_size(oid) + ((len > 1) ? 4 : 0))
+  if (size > AGENTX_HEADER_SIZE + snmp_oid_size(oid) + ((len > 1) ? 4 : 0))
   {
     log(L_INFO "un_register_pdu()");
     struct agentx_un_register_pdu *ur;
@@ -447,11 +465,11 @@ do_response(struct snmp_proto *p, byte *buf, uint size UNUSED)
 
       // register whole BGP4-MIB
       u32 arr_bgp[] = {1, 15, 1};
-      struct oid *o = mb_allocz(p->p.pool, 4 * 4);
+      struct oid *o = mb_allocz(p->p.pool, 4 * sizeof(u32));
       put_u8(&o->n_subid, 2);
       put_u8(&o->prefix, 2);
 
-      memcpy(o->ids, arr_bgp, 2 * 4);
+      memcpy(o->ids, arr_bgp, 2 * sizeof(u32));
 
       snmp_register(p, o, 0, 1);
 
@@ -466,12 +484,12 @@ do_response(struct snmp_proto *p, byte *buf, uint size UNUSED)
       mb_free(o);
 
       u32 arr_with_prefix[] = {1, 15, 3, 1, 1};
-      struct oid *o2 = mb_allocz(p->p.pool, 10 * 4);
+      struct oid *o2 = mb_allocz(p->p.pool, 10 * sizeof(u32));
 
       put_u8(&o2->n_subid, 9);
-      memcpy(o2->ids, arr_with_prefix, 5 * 4);
+      memcpy(o2->ids, arr_with_prefix, 5 * sizeof(u32));
       u32 remote_addr[] = {10, 0, 0, 0};
-      memcpy(o2->ids + 5, remote_addr, 4 * 4);
+      memcpy(o2->ids + 5, remote_addr, 4 * sizeof(u32));
       STORE(o2->prefix, 2);
 
       // register first line in BGP4-MIB bgpPeerTable
@@ -481,7 +499,7 @@ do_response(struct snmp_proto *p, byte *buf, uint size UNUSED)
       log(L_INFO "before hash walk");
       HASH_WALK(p->bgp_hash, next, peer)
       {
-       oid_ip4_index(o2, ipa_to_ip4(peer->peer_ip));
+       snmp_oid_ip4_index(o2, ipa_to_ip4(peer->peer_ip));
 
        log(L_INFO "");
        log(L_INFO "o2 n_subid %u prefix %u include %u", o2->n_subid,
@@ -552,12 +570,12 @@ parse_get_pdu(struct snmp_proto *p, byte *buf, uint size)
   {
     struct oid *o_start, *o_end;
     o_start = (struct oid *) pkt;
-    pkt += oid_size(o_start);
+    pkt += snmp_oid_size(o_start);
     o_end = (struct oid *) pkt;  // for Get-PDU always null
-    pkt += oid_size(o_end);
+    pkt += snmp_oid_size(o_end);
 
-    log(L_INFO "sizes o_start %lu o_end %lu", oid_size(o_start),
-       oid_size(o_end));
+    log(L_INFO "sizes o_start %lu o_end %lu", snmp_oid_size(o_start),
+       snmp_oid_size(o_end));
 
     log(L_INFO "o_subid: %u o_prefix %u o_include %u ---",
        o_start->n_subid, o_start->prefix, o_start->include);
@@ -609,6 +627,21 @@ parse_get_pdu(struct snmp_proto *p, byte *buf, uint size)
   return 1;
 }
 
+static u8
+get_mib_class(struct oid *oid)
+{
+  if (oid->prefix != 2 && oid->ids[0] != 1)
+    return SNMP_CLASS_INVALID;
+
+  switch (oid->ids[1])
+  {
+    case SNMP_BGP4_MIB:
+      return SNMP_CLASS_BGP;
+
+    default:
+      return SNMP_CLASS_END;
+  } 
+}
 
 /* req is request */
 static uint
@@ -641,37 +674,43 @@ parse_gets_pdu(struct snmp_proto *p, byte *req, uint size)
   int err = 0;
   while (!err && pkt - req < pkt_size)
   {
-    struct oid *o_start, *o_end;
-    o_start = (struct oid *) pkt;
-    pkt += oid_size(o_start);
-    o_end = (struct oid *) pkt;
-    pkt += oid_size(o_end);
-
-    // TODO normalize OID to prefix form
+    struct oid *o_start_b, *o_end_b;
+    o_start_b = (struct oid *) pkt;
+    pkt += snmp_oid_size(o_start_b);
+    o_end_b = (struct oid *) pkt;
+    pkt += snmp_oid_size(o_end_b);
 
     /* advertised size of oid is greater then size of message */
-    if (oid_size(o_start) > size || oid_size(o_end) > size)
+    if (snmp_oid_size(o_start_b) > size || snmp_oid_size(o_end_b) > size)
     {
       log(L_INFO "too big o_start or o_end");
       err = -1;  /* parse error too big n_subid (greater than message) */
       continue;
     }
 
+    /* object identifier (oid) normalization */
+    struct oid *o_start = prefixize(p, o_start_b, byte_ord);
+    struct oid *o_end = prefixize(p, o_end_b, byte_ord);
+
+    u8 mib_class = get_mib_class(o_start);
     switch (h->type)
     {
       case AGENTX_GET_PDU:
        log(L_INFO "type Get-PDU");
-       res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
+       res_pkt = snmp_mib_fill(p, o_start, mib_class, res_pkt, rsize, 0, byte_ord);
+       //res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
        break;
 
       case AGENTX_GET_NEXT_PDU:
        log(L_INFO "type GetNext-PDU");
-       o_start = bgp_search(p, o_start, o_end, NULL);
+
+       o_start = search_mib(p, o_start, o_end, NULL, 0);
        if (o_start)
-         res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
+         res_pkt = snmp_mib_fill(p, o_start, mib_class, res_pkt, rsize, 0, byte_ord);
+         //res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
        else
        {
-         log(L_INFO "null o_start GetNext-PDU");
+         log(L_INFO "null o_start GetNext-PDU err handling next");
          err = -2;
          continue;
        }
@@ -680,13 +719,17 @@ parse_gets_pdu(struct snmp_proto *p, byte *req, uint size)
       case AGENTX_GET_BULK_PDU:
       {
        log(L_INFO "type GetBulk-PDU");
+
        struct oid  *o_curr = NULL;
        /* TODO add res packet size limiting logic */
-       while ((o_curr = bgp_search(p, o_start, o_end, o_curr)) != NULL)
+       while ((o_curr = search_mib(p, o_start, o_end, o_curr, 0)) != NULL)
        {
-         res_pkt = find_n_fill(p, o_curr, res_pkt, rsize, 0, byte_ord);
+         res_pkt = snmp_mib_fill(p, o_curr, mib_class, res_pkt, rsize, 0, byte_ord);
+         //res_pkt = find_n_fill(p, o_curr, res_pkt, rsize, 0, byte_ord);
        }
 
+        mb_free(o_curr);
+
        /* no item found */
        if (res_pkt == res + sizeof(struct agentx_response))
        {
@@ -694,11 +737,13 @@ parse_gets_pdu(struct snmp_proto *p, byte *req, uint size)
          err = -2;
          continue;
        }
-
        break;
       }
     }
 
+    mb_free(o_start);
+    mb_free(o_end);
+
     ind++;
   }
 
@@ -757,19 +802,29 @@ snmp_stop_subagent(struct snmp_proto *p)
 }
 
 /* return number of bytes used  by @o */
-static inline uint
-oid_size(struct oid *o)
+uint
+snmp_oid_size(struct oid *o)
 {
   /* faster multipication by 4 */
   return 4 + (o->n_subid << 2);
 }
 
+static inline int
+oid_prefix(struct oid *o, u32 *prefix, uint len)
+{
+  for (uint i = 0; i < len; i++)
+    if (o->ids[i] != prefix[i])
+      return 0; // false
+
+  return 1; // true
+}
+
 /* return number of bytes used by @vb */
 static inline uint
 vb_size(struct agentx_varbind *vb)
 {
   /* +4B for type and pad */
-  return oid_size(&vb->name) + 4;
+  return snmp_oid_size(&vb->name) + 4;
 }
 
 int
@@ -926,51 +981,37 @@ has_inet_prefix(struct oid *o)
          o->ids[3] == 1);
 }
 
-static inline struct ip4_addr
-ip4_from_oid(const struct oid *o)
-{
-  return (o->n_subid == 9) ? ip4_build(o->ids[5], o->ids[6], o->ids[7],
-o->ids[8]) : IP4_NONE;
-}
-
-/* tree is tree with "internet" prefix .1.3.6.1 */
+/* tree is tree with "internet" prefix .1.3.6.1 
+   working only with o_start, o_end allocated in heap (not from buffer)*/
 static struct oid *
-bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, struct oid *o_curr)
+search_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, struct oid *o_curr, uint contid UNUSED)
 {
-  ip4_addr ip4 = ip4_from_oid(o_start);
-  ip4_addr dest = ip4_from_oid(o_end);
-
-  net_addr *net = mb_allocz(p->p.pool, sizeof(struct net_addr));
-  net_fill_ip4(net, ip4, IP4_MAX_PREFIX_LENGTH);
+  log(L_INFO "search_mib()");
 
-  log(L_INFO "o_start n_sub %u prefix %u include %u",
-    o_start->n_subid, o_start->prefix, o_start->include);
-  for (int i = 0; i < o_start->n_subid; i++)
-    log(L_INFO "n_subid %u: %u", i, o_start->ids[i]);
-  log(L_INFO "preparing include /sive> return %d %d %d",
-    !o_curr,(int) o_start->include, trie_match_net(p->bgp_trie, net));
-  if (!o_curr && o_start->include && trie_match_net(p->bgp_trie, net))
-    return o_start;
-
-  log(L_INFO "doesn't returned");
-
-  if (o_curr)
-    net_fill_ip4(net, dest, IP4_MAX_PREFIX_LENGTH);
+  if (!o_start)
+    return NULL;
 
-  struct f_trie_walk_state *ws = mb_allocz(p->p.pool,
-                                          sizeof(struct f_trie_walk_state));
+  if (!o_curr)
+  {
+    o_curr = mb_alloc(p->p.pool, snmp_oid_size(o_start));
+    memcpy(o_curr, o_start, snmp_oid_size(o_start));
+    // XXX is it right time to free o_start right now (here) ?
+  }
 
-  struct oid *o = mb_allocz(p->p.pool, sizeof(struct oid) + 8 * sizeof(u32));
-  o->n_subid = 9;
-  trie_walk_init(ws, p->bgp_trie, NULL);
-  if (trie_walk_next(ws, net) && ip4_less(net4_prefix(net), dest))
+  if (o_curr->n_subid > 1 &&
+      o_curr->ids[0] == 1)
   {
-    memcpy(o, o_start, oid_size(o_start));
-    oid_ip4_index(o, net4_prefix(net));
-    return o;
+    switch (o_curr->ids[1])
+    {
+      case SNMP_BGP4_MIB:
+       return search_bgp_mib(p, o_curr, o_end, 0);
+        
+      default:
+        return NULL;
+    }
   }
-  else
-    return NULL;
+
+  return NULL;
 }
 
 static byte *
@@ -1027,7 +1068,7 @@ find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt, uint size UNUSED, u
       BGP_DATA(vb, AGENTX_INTEGER, pkt);
       break;
 
-    case SNMP_BGP_VERSION:
+    case SNMP_BGP_NEGOTIATED_VERSION:
       if (b_state == BS_OPENCONFIRM || b_state == BS_ESTABLISHED)
        STORE_PTR(pkt, 4);
       else
@@ -1090,7 +1131,7 @@ find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt, uint size UNUSED, u
       pkt += 4;
       /* force network order */
       put_u32(pkt,
-       (bp->last_error_code << 8 | bp->last_error_code << 48) & 0xFFFF0000);
+       (bp->last_error_code << 8 | bp->last_error_code << 24) & 0xFFFF0000);
       /* real size is 8 but we already shifted the pkt by 4 */
       BGP_DATA(vb, AGENTX_OCTET_STRING, pkt);
       break;
@@ -1158,7 +1199,7 @@ snmp_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint
 
   switch (o->ids[2])
   {
-    case BGP4_MIB_VERSION:
+    case SNMP_BGP_VERSION:
       STORE_PTR(pkt, 1);   // string len
       pkt += 4;
       STORE_PTR(pkt, BGP4_VERSIONS);
@@ -1166,15 +1207,15 @@ snmp_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint
       BGP_DATA(vb, AGENTX_OCTET_STRING, pkt);
       break;
 
-    case BGP4_MIB_LOCAL_AS:
+    case SNMP_BGP_LOCAL_AS:
       // XXX local as to use
       STORE_PTR(pkt, p->local_as);
       BGP_DATA(vb, AGENTX_INTEGER, pkt);
       break;
 
-    case BGP4_PEER_TABLE:
+    case SNMP_BGP_PEER_TABLE:
       /* end part of .1.3.6.1.2.1.15.3.1.x.a.b.c.d */
-      if (o->n_subid < 9 || o->ids[3] != BGP4_PEER_ENTRY
+      if (o->n_subid < 9 || o->ids[3] != SNMP_BGP_PEER_ENTRY
          || o->ids[4] == 0 || o->ids[4] > 24)
        return no_such_object(pkt, vb);
 
@@ -1233,7 +1274,7 @@ no_such_object(byte *buf, struct agentx_varbind *vb)
   return buf;
 }
 
-static byte * UNUSED
+static UNUSED byte *
 no_such_instance(byte *buf, struct agentx_varbind *vb)
 {
   vb->type = AGENTX_NO_SUCH_INSTANCE;
@@ -1245,7 +1286,7 @@ find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint co
 {
   struct agentx_varbind *vb = (void *) buf;
 
-  memcpy(&vb->name, o, oid_size(o));
+  memcpy(&vb->name, o, snmp_oid_size(o));
 
                        /* SNMPv2   mgmt                     mib-2 */
   if (o->n_subid < 2 || (o->prefix != 2 && o->ids[0] != 1))
@@ -1254,6 +1295,7 @@ find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint co
   switch (o->ids[1])
   {
     case SNMP_BGP4_MIB:
+      log(L_INFO "find_prefixed() BGP4");
       return snmp_bgp_record(p, o, buf, size, contid);
 
     case SNMP_OSPFv3_MIB:
@@ -1265,28 +1307,42 @@ find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint co
   }
 }
 
+/** 
+ * prefixize - return prefixed oid copy if possible
+ * @proto: allocation pool holder
+ * @oid: from packet loaded object identifier
+ * @byte_ord: byte order of @oid 
+ *
+ * Returns prefixed (meaning with nonzero prefix field) oid copy of @oid if
+ * possible. NULL otherwise. Returned pointer is always allocated from @proto's
+ * pool not a pointer to recieve buffer (from which is most likely @oid).
+ */
 static struct oid *
-prefixize(struct snmp_proto *p, struct oid *o, int byte_ord)
+prefixize(struct snmp_proto *proto, struct oid *oid, int byte_ord)
 {
   const u32 prefix[] = {1, 3, 6, 1};
 
-  if (o->n_subid < 5)
+  if (oid->n_subid < 5)
     return NULL;
 
   for (int i = 0; i < 4; i++)
-    if (LOAD(o->ids[i], byte_ord) != prefix[i])
+    if (LOAD(oid->ids[i], byte_ord) != prefix[i])
       return NULL;
 
-  struct oid *new = mb_alloc(p->p.pool, sizeof(struct oid) + MAX((o->n_subid - 5) * 4, 0));
+  if (oid->ids[4] >= 256)
+    return NULL;
+
+  struct oid *new = mb_alloc(proto->p.pool, 
+          sizeof(struct oid) + MAX((oid->n_subid - 5) * sizeof(u32), 0));
 
-  memcpy(new, o, sizeof(struct oid));
-  new->n_subid = o->n_subid - 5;
+  memcpy(new, oid, sizeof(struct oid));
+  new->n_subid = oid->n_subid - 5;
 
-  if (o->ids[4] < 256)
-    new->prefix = o->ids[4];
-  else return NULL;
+  /* validity check before allocation => ids[4] < 256 
+     and can be copied to one byte new->prefix */
+  new->prefix = oid->ids[4];
 
-  memcpy(&new->ids, &o->ids[5], new->n_subid * 4);
+  memcpy(&new->ids, &oid->ids[5], new->n_subid * sizeof(u32));
   return new;
 }
 
@@ -1302,6 +1358,31 @@ find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint cont
   return NULL;
 }
 
+/**
+ * snmp_mib_fill - 
+ */
+static byte *
+snmp_mib_fill(struct snmp_proto *p, struct oid *oid, u8 mib_class, byte *buf,
+uint size, uint contid, int byte_ord)
+{ 
+  struct agentx_varbind *vb = (void *) buf;
+
+  memcpy(&vb->name, oid, snmp_oid_size(oid));
+
+                       /* SNMPv2   mgmt                     mib-2 */
+  if (oid->n_subid < 2 || (oid->prefix != 2 && oid->ids[0] != 1))
+    return no_such_object(buf + vb_size(vb), vb);
+
+  switch (mib_class)
+  {
+    case SNMP_CLASS_BGP:
+      buf = snmp_bgp_fill(p, oid, buf, size, contid, byte_ord);
+      break;   
+  }
+  return buf; 
+}
+
 static byte *
 prepare_response(struct snmp_proto *p, byte *buf, uint size)
 {
index 16da447bace9ffd72bb3efb8aeb5a6fe593edfbe..808c5cfbc0763e2641a8f4af27b1a0003059502f 100644 (file)
@@ -10,10 +10,22 @@ void snmp_ping(struct snmp_proto *p);
 
 #define AGENTX_VERSION              1
 
-#define SNMP_OSPF_MIB 14             /* part of oid .1.3.6.1.2.1.14 */
-#define SNMP_BGP4_MIB 15             /* part of oid .1.3.6.1.2.1.15 */
+#define SNMP_STATE_START 0
+#define SNMP_STATE_BGP 1
+#define SNMP_STATE_INVALID 2
+
+#define SNMP_MIB_2        1           /* last of oid .1.3.6.1.2.1     */
+#define SNMP_OSPF_MIB    14          /* part of oid .1.3.6.1.2.1.14  */
+#define SNMP_BGP4_MIB    15          /* part of oid .1.3.6.1.2.1.15  */
 #define SNMP_OSPFv3_MIB 192          /* part of oid .1.3.6.1.2.1.192 */
 
+enum SNMP_CLASSES {
+  SNMP_CLASS_INVALID = 0,
+  SNMP_CLASS_BGP = 1,
+  SNMP_CLASS_OSPF,
+  SNMP_CLASS_END,
+};
+
 #define BGP4_VERSIONS 0x10
 
 enum agentx_type {
@@ -243,4 +255,11 @@ enum agentx_response_err {
 } PACKED;
 
 int snmp_rx(sock *sk, uint size);
+int snmp_valid_ip4_index_safe(struct oid *o, uint start);
+int snmp_valid_ip4_index(struct oid *o, uint start);
+void snmp_oid_ip4_index(struct oid *o, ip4_addr addr);
+
+uint snmp_oid_size(struct oid *o);
+
+static byte *snmp_mib_fill(struct snmp_proto *p, struct oid *oid, u8 mib_class, byte *buf, uint size, uint contid, int byte_ord);
 #endif