]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
SNMP: tmp
authorVojtech Vilimek <vojtech.vilimek@nic.cz>
Tue, 9 Jul 2024 14:30:04 +0000 (16:30 +0200)
committerVojtech Vilimek <vojtech.vilimek@nic.cz>
Tue, 9 Jul 2024 14:30:04 +0000 (16:30 +0200)
proto/snmp/bgp4_mib.c
proto/snmp/mib_tree.c
proto/snmp/mib_tree.h
proto/snmp/snmp_utils.c
proto/snmp/subagent.c

index 1c1a4afb6b5fc491365147c5a8be29024bac3343..5cd896c2b4d23cc8847651da9bf2a11a683f5287 100644 (file)
@@ -603,7 +603,7 @@ populate_bgp4(struct snmp_data *d, ip4_addr *addr, const struct bgp_proto **prot
 **conn, const struct bgp_stats **stats, const struct bgp_config **config)
 {
   const struct oid * const oid = &d->c->sr_vb_start->name;
-  if (snmp_bgp_valid_ip4(oid))
+  if (snmp_bgp_valid_ip4(oid) && LOAD_U8(oid->n_subid) == 9)
     *addr = ip4_from_oid(oid);
   else
   {
@@ -649,6 +649,8 @@ static enum snmp_search_res
 fill_bgp_version(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
 {
   snmp_log("fill ver");
+  if (LOAD_U8(d->c->sr_vb_start->name.n_subid) != 3)
+    return SNMP_SEARCH_NO_INSTANCE;
   d->c->size -= snmp_str_size_from_len(1);
   snmp_varbind_nstr(d->c, BGP4_VERSIONS, 1);
   return SNMP_SEARCH_OK;
@@ -658,6 +660,8 @@ static enum snmp_search_res
 fill_local_as(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
 {
   snmp_log("fill as");
+  if (LOAD_U8(d->c->sr_vb_start->name.n_subid) != 3)
+    return SNMP_SEARCH_NO_INSTANCE;
   snmp_varbind_int(d->c, d->p->bgp_local_as);
   return SNMP_SEARCH_OK;
 }
@@ -1040,6 +1044,8 @@ static enum snmp_search_res
 fill_local_id(struct mib_walk_state *walk UNUSED, struct snmp_data *d)
 {
   snmp_log("fill local id");
+  if (LOAD_U8(d->c->sr_vb_start->name.n_subid) != 3)
+    return SNMP_SEARCH_NO_INSTANCE;
   snmp_varbind_ip4(d->c, d->p->bgp_local_id);
   return SNMP_SEARCH_OK;
 }
@@ -1695,8 +1701,6 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_data *data)
   //struct agentx_varbind *vb = data->c->sr_vb_start;
   struct oid *oid = &data->c->sr_vb_start->name;
 
-  ip4_addr ip4 = ip4_from_oid(oid);
-
   /* BGP4-MIB::bgpPeerIdentifier */
   STATIC_OID(9) bgp4_peer_id = {
     .n_subid = 9,
@@ -1708,12 +1712,16 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_data *data)
       /* IP4_NONE */ 0, 0, 0, 0 }
   };
 
+  ip4_addr ip4 = ip4_from_oid(oid);
+
   const struct oid *peer_oid = (const struct oid *) &bgp4_peer_id;
 
-  if (snmp_oid_compare(oid, peer_oid) < 0 || LOAD_U8(oid->n_subid) < 9)
-  {
-    die("unreachable?");
+  int precise = 1;
+  if (LOAD_U8(oid->n_subid) > 9)
+    precise = 0;
 
+  if (LOAD_U8(oid->n_subid) != 9 || snmp_oid_compare(oid, peer_oid) < 0)
+  {
     int old = snmp_oid_size(oid);
     int new = snmp_oid_size(peer_oid);
 
@@ -1721,18 +1729,21 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_data *data)
     {
       snmp_log("bgp4_next_peer small buffer");
       snmp_manage_tbuf(data->p, data->c);
+      oid = &data->c->sr_vb_start->name;  // TODO fix sr_vb_start in manage_tbuf
     }
 
-    if (new > old)
-      data->c->buffer += (new - old);
+    data->c->buffer += (new - old);
 
     snmp_oid_copy(oid, peer_oid);
-
     STORE_U8(oid->include, 1);
   }
 
+
   ASSUME(oid->n_subid == 9);
-  /* +1 includes empty prefix */
+  /* full path BGP4-MIB::bgpPeerEntry.x: .1.3.6.1.2.1.15.3.1.x
+   * index offset = ARRAY_SIZE(snmp_internet) + 1 <prefix> + 4 + 1 <identifier x> */
+  ASSUME(state->stack_pos > 10);
+  oid->ids[4] = state->stack[10]->empty.id;
 
   net_addr net;
   net_fill_ip4(&net, ip4, IP4_MAX_PREFIX_LENGTH);
@@ -1740,7 +1751,7 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_data *data)
 
   int match = trie_walk_init(&ws, data->p->bgp_trie, &net, 1);
 
-  if (match && LOAD_U8(oid->include))
+  if (match && LOAD_U8(oid->include) && precise)
   {
     STORE_U8(oid->include, 0);
     ip4_to_oid(oid, ip4);
@@ -1860,7 +1871,7 @@ snmp_bgp4_start(struct snmp_proto *p)
     leaf = &node->leaf;
 
     leaf->filler = leafs[i].filler;
-    leaf->call_next = NULL; // TODO
+    leaf->call_next = NULL;
     leaf->type = leafs[i].type;
     leaf->size = leafs[i].size;
   }
index 709f7014bc523b41adaa6c508d2a93030eaac0a3..5af26e394146f913ae48690e2c04552d655765ba 100644 (file)
@@ -429,7 +429,7 @@ mib_tree_find(const struct mib_tree *t, struct mib_walk_state *walk, const struc
   {
     /* In any of cases below we did not move in the tree therefore the
      * walk->id_pos is left untouched. */
-    if (snmp_oid_is_prefixed(oid) && 
+    if (snmp_oid_is_prefixed(oid) &&
        LOAD_U8(oid->n_subid) + ARRAY_SIZE(snmp_internet) + 1 == walk->id_pos)
       return node;
 
@@ -623,6 +623,68 @@ mib_tree_walk_to_oid(const struct mib_walk_state *walk, struct oid *result, u32
   return 0;
 }
 
+/*
+ * return -1 if walk_oid < oid
+ * return 0 if walk_oid == oid
+ * return +1 if walk_oid > oid
+ *
+ */
+// TODO tests
+int
+mib_tree_walk_oid_compare(const struct mib_walk_state *walk, const struct oid *oid)
+{
+  /* code is very similar to snmp_oid_compare() */
+  if (!walk->stack_pos)
+    return -1;
+
+  uint walk_idx = 1;
+  u8 walk_subids = walk->stack_pos;      /* left_subids */
+  u8 oid_subids = LOAD_U8(oid->n_subid);  /* right_subids */
+
+  const u8 oid_prefix = LOAD_U8(oid->prefix);
+
+  if (oid_prefix != 0)
+  {
+    for (; walk_idx < walk_subids && walk_idx < ARRAY_SIZE(snmp_internet) + 1; walk_idx++)
+    {
+      u32 id = walk->stack[walk_idx]->empty.id;
+      if (id < snmp_internet[walk_idx - 1])
+       return -1;
+      else if (id > snmp_internet[walk_idx - 1])
+       return 1;
+    }
+
+    if (walk_idx == walk_subids)
+      return 1;
+
+    const u8 walk_prefix = walk->stack[walk_idx++]->empty.id;
+    if (walk_prefix < oid_prefix)
+      return -1;
+    else if (walk_prefix > oid_prefix)
+      return 1;
+  }
+
+  uint i = 0;
+  for (; i < oid_subids && walk_idx < walk_subids; i++, walk_idx++)
+  {
+    u32 walk_id = walk->stack[walk_idx]->empty.id;
+    u32 oid_id = LOAD_U32(oid->ids[i]);
+    if (walk_id < oid_id)
+      return -1;
+    else if (walk_id > oid_id)
+      return 1;
+  }
+
+  if (walk_idx == walk_subids && i == oid_subids)
+    return 0;
+  else if (walk_idx == walk_subids)
+    return -1;
+  else /* if (i == oid_subids) */
+    return 1;
+}
+
+
+
 /**
  * mib_tree_walk_is_oid_descendant - check if OID is in walk subtree
  * @walk: MIB tree walk state
@@ -727,7 +789,7 @@ mib_tree_walk_next(const struct mib_tree *t, struct mib_walk_state *walk)
 }
 
 struct mib_leaf *
-mib_tree_walk_next_leaf(const struct mib_tree *t, struct mib_walk_state *walk)
+mib_tree_walk_next_leaf(const struct mib_tree *t, struct mib_walk_state *walk, u32 skip)
 {
   (void)t;
 
@@ -737,7 +799,7 @@ mib_tree_walk_next_leaf(const struct mib_tree *t, struct mib_walk_state *walk)
     return NULL;
   }
 
-  u32 next_id = 0;
+  u32 next_id = skip;
   mib_node_u *node = walk->stack[walk->stack_pos - 1];
 
   if (mib_node_is_leaf(node) && walk->stack_pos > 1)
index cf1b94fd444a9c6a57b1310f8539561be281b1e3..082c942f256d2482772d288e26e6386fc8658b94 100644 (file)
@@ -102,13 +102,14 @@ void mib_tree_init(pool *p, struct mib_tree *t);
 // TODO: remove need for argument include_root
 void mib_tree_walk_init(struct mib_walk_state *state, const struct mib_tree *t);
 int mib_tree_walk_to_oid(const struct mib_walk_state *state, struct oid *result, u32 subids);
+int mib_tree_walk_oid_compare(const struct mib_walk_state *state, const struct oid *oid);
 
 mib_node_u *mib_tree_add(pool *p, struct mib_tree *tree, const struct oid *oid, int is_leaf);
 int mib_tree_remove(struct mib_tree *t, const struct oid *oid);
 int mib_tree_delete(struct mib_tree *t, struct mib_walk_state *state);
 mib_node_u *mib_tree_find(const struct mib_tree *tree, struct mib_walk_state *walk, const struct oid *oid);
 mib_node_u *mib_tree_walk_next(const struct mib_tree *t, struct mib_walk_state *walk);
-struct mib_leaf *mib_tree_walk_next_leaf(const struct mib_tree *t, struct mib_walk_state *walk);
+struct mib_leaf *mib_tree_walk_next_leaf(const struct mib_tree *t, struct mib_walk_state *walk, u32 skip);
 
 int mib_tree_hint(pool *p, struct mib_tree *t, const struct oid *oid, uint size);
 int mib_tree_walk_is_oid_descendant(const struct mib_walk_state *walk, const struct oid *oid);
index 53f862cab9091465b81071f11d467bc1022d58a6..540870362e90fd4783778c7b23f55300b4758b9b 100644 (file)
@@ -178,6 +178,19 @@ snmp_oid_copy2(struct oid *dest, const struct oid *src)
   memcpy(dest->ids, src->ids, LOAD_U8(src->n_subid) * sizeof(u32));
 }
 
+/*
+ * snmp_oid_update
+ *
+ */
+void
+snmp_oid_update(struct oid *dest, const struct oid *src)
+{
+  dest->prefix = src->prefix;
+  dest->include = src->include;
+  dest->reserved = 0;
+  memcpy(dest->ids, src->ids, MIN(dest->n_subid, src->n_subid) * sizeof(u32));
+}
+
 /*
  * snmp_oid_duplicate - duplicate an OID from memory pool
  * @pool: pool to use
@@ -675,8 +688,8 @@ snmp_oid_compare(const struct oid *left, const struct oid *right)
 
   if (left_prefix == 0)
   {
-    size_t bound = MIN((size_t) left_subids, ARRAY_SIZE(snmp_internet));
-    for (size_t idx = 0; idx < bound; idx++)
+    uint bound = MIN((uint) left_subids, (uint) ARRAY_SIZE(snmp_internet));
+    for (uint idx = 0; idx < bound; idx++)
     {
       u32 id = LOAD_U32(left->ids[idx]);
       if (id < snmp_internet[idx])
@@ -1102,18 +1115,40 @@ snmp_walk_next(struct mib_tree *tree, struct mib_walk_state *walk, struct snmp_d
 
   int found = 0;
   struct mib_leaf *leaf = &node->leaf;
-  if (mib_node_is_leaf(node) && LOAD_U8(data->c->sr_vb_start->name.include))
+
+  if (mib_node_is_leaf(node) && leaf->call_next)
+  {
+    const struct oid *oid = &data->c->sr_vb_start->name;
+    if (mib_tree_walk_oid_compare(walk, oid) > 0)
+    {
+      int old = snmp_oid_size(&data->c->sr_vb_start->name);
+      if (mib_tree_walk_to_oid(walk,
+         &data->c->sr_vb_start->name, 20 * sizeof(u32)))
+      {
+       snmp_log("walk_next copy failed");
+       return NULL;
+      }
+
+      int new = snmp_oid_size(&data->c->sr_vb_start->name);
+      data->c->buffer += (new - old);
+    }
+
+    found = !leaf->call_next(walk, data);
+  }
+  else if (mib_node_is_leaf(node) && LOAD_U8(data->c->sr_vb_start->name.include))
   {
     found = 1;
     STORE_U8(data->c->sr_vb_start->name.include, 0);
   }
 
-  if (!found && mib_node_is_leaf(node) && leaf->call_next && !leaf->call_next(walk, data))
-    found = 1;
-
-  while (!found && (leaf = mib_tree_walk_next_leaf(tree, walk)) != NULL)
+  const struct oid *oid = &data->c->sr_vb_start->name;
+  u32 skip = (walk->id_pos < LOAD_U8(oid->n_subid)) ?
+    LOAD_U32(oid->ids[walk->id_pos]) : 0;
+  while (!found && (leaf = mib_tree_walk_next_leaf(tree, walk, skip)) != NULL)
   {
+    /* mib_tree_walk_next() forces VarBind's name OID overwriting */
     int old = snmp_oid_size(&data->c->sr_vb_start->name);
+    // TODO autogrow
     if (mib_tree_walk_to_oid(walk, &data->c->sr_vb_start->name, 20 * sizeof(u32)))
     {
       snmp_log("walk_next copy failed");
@@ -1127,12 +1162,15 @@ snmp_walk_next(struct mib_tree *tree, struct mib_walk_state *walk, struct snmp_d
       found = 1;
     else if (!leaf->call_next)
       found = 1;
+
+    oid = &data->c->sr_vb_start->name;
+    skip = (walk->id_pos < LOAD_U8(oid->n_subid)) ?
+      LOAD_U32(oid->ids[walk->id_pos]) : 0;
   }
 
   if (!found)
     return NULL;
 
-
   return leaf;
 }
 
@@ -1179,7 +1217,6 @@ snmp_walk_fill(struct mib_leaf *leaf, struct mib_walk_state *walk, struct snmp_d
     snmp_set_varbind_type(vb, snmp_search_res_to_type(res));
 
   u16 type = snmp_load_varbind_type(vb);
-  /* Test that hook() did not overwrite the VarBind type to non-matching type */
   ASSUME(type == leaf->type || type == AGENTX_END_OF_MIB_VIEW || type == AGENTX_NO_SUCH_OBJECT ||
     type == AGENTX_NO_SUCH_INSTANCE);
 
index b46d1ea3c7b678f71671752d1a1168ef1b4a0abb..3c012a4f46bea36d3fef062d207b92ce62eccafb 100644 (file)
@@ -1498,7 +1498,7 @@ snmp_get_next_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_
     .c = c,
   };
 
-  snmp_walk_init(p->mib_tree, walk, o_start, &d);
+  (void) snmp_walk_init(p->mib_tree, walk, o_start, &d);
   struct mib_leaf *leaf = snmp_walk_next(p->mib_tree, walk, &d);
 
   enum snmp_search_res res;
@@ -2137,6 +2137,15 @@ snmp_manage_tbuf2(struct snmp_proto *p, void **ptr, struct snmp_pdu *c)
     *ptr = sk->tbuf + diff;
 }
 
+void
+snmp_tbuf_reserve(struct snmp_data *data, size_t size)
+{
+  if (size > data->c->size)
+  {
+    snmp_manage_tbuf(data->p, data->c);
+  }
+}
+
 /*
  * prepare_response - fill buffer with AgentX PDU header
  * @p: SNMP protocol instance