]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
fix the Get and GetNext
authorVojtech Vilimek <vojtech.vilimek@nic.cz>
Tue, 15 Nov 2022 15:29:03 +0000 (16:29 +0100)
committerVojtech Vilimek <vojtech.vilimek@nic.cz>
Tue, 15 Nov 2022 15:29:03 +0000 (16:29 +0100)
missing some functionality around GetBulk

proto/snmp/Makefile
proto/snmp/bgp_mib.c
proto/snmp/bgp_mib.h
proto/snmp/snmp.h
proto/snmp/snmp_test.c
proto/snmp/subagent.c
proto/snmp/subagent.h

index 86070d4f461bc103e48a0d0840ba2d79d3ae4a17..24451dfc5749e5e0f776d785f426e70c7c18cb52 100644 (file)
@@ -1,4 +1,4 @@
-src := snmp.c subagent.c bgp_mib.c
+src := snmp.c snmp_utils.c subagent.c bgp_mib.c
 obj := $(src-o-files)
 $(all-daemon)
 $(cf-local)
index 2b36af841de4225a1a6e4c97024c07a9f7ce7b40..f958b8ede7a1042b3052a7de3769c60d9632ec76 100644 (file)
@@ -11,6 +11,7 @@
 /* BGP_MIB states see enum BGP_INTERNAL_STATES */
 
 #include "snmp.h"
+#include "snmp_utils.h"
 #include "subagent.h"
 #include "bgp_mib.h"
 
@@ -56,7 +57,7 @@ snmp_bgp_register()
 int
 snmp_bgp_valid_ip4(struct oid *o)
 {
-  return snmp_valid_ip4_index_safe(o, 6);
+  return snmp_valid_ip4_index(o, 5);
 }
 
 static u8
@@ -134,9 +135,9 @@ snmp_bgp_state(struct oid *oid)
       /* else oid->n_subid >= 2 */
         /* fall through */
 
-   /* between ids[6] and ids[9] should be IP address
+   /* between ids[5] and ids[8] (n_subid == 9) should be IP address
     * validity is checked later in execution because
-    *  this field also could mean a boundry (upper or lower)
+    *  this field also could mean a query boundry (upper or lower)
     */
     case 9:
     case 8:
@@ -198,7 +199,7 @@ snmp_bgp_state(struct oid *oid)
   return state;
 }
 
-inline int
+static inline int
 is_dynamic(u8 state)
 {
   return (state >= BGP_INTERNAL_IDENTIFIER && 
@@ -208,15 +209,17 @@ is_dynamic(u8 state)
 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)
+      state == BGP_INTERNAL_PEER_ENTRY ||
+
+      /* unsupported fields */
+      state == BGP_INTERNAL_FSM_ESTABLISHED_TIME ||
+      state == BGP_INTERNAL_ORIGINATION_INTERVAL ||
+      state == BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT ||
+      state == BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME)
     return 0; /* hasn't value */
   else
-  {
-    
-  }
     return 1; /* has value */
 }
 
@@ -423,7 +426,7 @@ bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, struct oid *o_en
     o->n_subid = 9;
 
     memcpy(o, o_start, snmp_oid_size(o_start));
-    snmp_oid_ip4_index(o, net4_prefix(net));
+    snmp_oid_ip4_index(o, 5, net4_prefix(net));
 
     mb_free(net);
     mb_free(ws);
@@ -440,13 +443,22 @@ bgp_find_dynamic_oid(struct snmp_proto *p, struct oid *o_start, struct oid *o_en
   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)
+static struct oid *
+search_bgp_dynamic(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uint contid
+UNUSED, u8 next_state)
 {
-  u8 state = snmp_bgp_state(oid);
-  (void)state;
-  return NULL;
+  /* TODO can be remove after implementing all BGP4-MIB::bgpPeerTable columns */
+  struct oid *copy = o_start;
+  do {
+    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;
 }
 
 /* o_start could be o_curr, but has basically same meaning for searching */
@@ -474,78 +486,266 @@ search_bgp_mib(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, uin
       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);
+      /* no need to check that retval < o_end -- done by bgp_find_dynamic_oid() */
+      return search_bgp_dynamic(p, o_start, o_end, 0, next_state);
+  }
 
-       o_start = bgp_find_dynamic_oid(p, o_start, o_end, next_state);
+  /* no need to check that retval < o_end -- done by bgp_find_dynamic_oid() */
+  return search_bgp_dynamic(p, o_start, o_end, 0, start_state);
+}
 
-       next_state = snmp_bgp_next_state(next_state);
+static byte *
+bgp_fill_dynamic(struct snmp_proto *p, struct oid *oid, byte *pkt, uint size
+UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state)
+{
+  struct agentx_varbind *vb = (void *) pkt;
+  *pkt += snmp_vb_size(vb);
+
+  ip_addr addr;
+  if (snmp_bgp_valid_ip4(oid))
+    addr = ipa_from_ip4(ip4_from_oid(oid));
+  else
+    return snmp_no_such_object(pkt, vb);
 
-      } while (o_start != NULL && next_state < BGP_INTERNAL_END);
+  // TODO XXX deal with possible change of (remote) ip
+  struct snmp_bgp_peer *pe = HASH_FIND(p->bgp_hash, SNMP_HASH, addr);
 
-      return o_start;
+  struct bgp_proto *bgp_proto = NULL;
+  struct proto *proto = NULL;
+  if (pe)
+  {
+    proto = ((struct proto_config *) pe->config)->proto;
+    if (proto->proto == &proto_bgp &&
+       ipa_equal(addr, ((struct bgp_proto *) proto)->remote_ip))
+    {
+      bgp_proto = (struct bgp_proto *) proto;
     }
-  }
 
-  /* else - is_dynamic(start_state) */  
-    /* ... (same as do ... while above) */
+    /* binded bgp protocol not found */
+    else
+    {
+      die("Binded bgp protocol not found!");
+      return snmp_no_such_object(pkt, vb);
+    }
+  }
 
+  struct bgp_conn *bgp_conn = bgp_proto->conn;
+  struct bgp_conn *bgp_in = &bgp_proto->incoming_conn;
+  struct bgp_conn *bgp_out = &bgp_proto->outgoing_conn;
 
-  return NULL;
-  /* TODO not implemented yet */
+  struct bgp_stats *bgp_stats = &bgp_proto->stats;
+  const struct bgp_config *bgp_conf = bgp_proto->cf;
 
-  /* 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);
+  uint bgp_state;
 
-  struct oid *o_curr = update_bgp_oid(o_curr, state_curr);
+  if (bgp_conn)
+    bgp_state = bgp_conn->state;
+  else if (MAX(bgp_in->state, bgp_out->state) == BS_CLOSE &&
+          MIN(bgp_in->state, bgp_out->state) != BS_CLOSE)
+    bgp_state = MIN(bgp_in->state, bgp_out->state);
+  else if (MIN(bgp_in->state, bgp_out->state) == BS_CLOSE)
+    bgp_state = BS_IDLE;
+  else
+    bgp_state = MAX(bgp_in->state, bgp_out->state);
 
-  /* static part of BGP4-MIB tree, not depending on BGP connections */
-  if (state_curr <= 5)
+  switch (state)
   {
-    return o_curr;
+
+    case BGP_INTERNAL_IDENTIFIER:
+      if (bgp_state == BS_OPENCONFIRM || bgp_state == BS_ESTABLISHED)
+      {
+       STORE_PTR(pkt, ipa_to_u32(bgp_proto->remote_ip));
+       BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
+      }
+      else
+      {
+       snmp_put_blank(pkt);      /* stores 4B of zeroes */
+       BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
+      }
+      break;
+
+    case BGP_INTERNAL_STATE:
+      STORE_PTR(pkt, bgp_state);
+      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
+
+    case BGP_INTERNAL_ADMIN_STATUS:
+      /* struct proto ~ (struct proto *) bgp_proto */
+      if (proto->disabled)
+       STORE_PTR(pkt, AGENTX_ADMIN_STOP);
+      else
+       STORE_PTR(pkt, AGENTX_ADMIN_START);
+
+      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
+
+    case BGP_INTERNAL_NEGOTIATED_VERSION:
+      if (bgp_state == BS_OPENCONFIRM || bgp_state == BS_ESTABLISHED)
+       STORE_PTR(pkt, 4); // TODO replace with MACRO
+      else
+       STORE_PTR(pkt, 0); /* zero dictated by rfc */
+
+      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
+
+    case BGP_INTERNAL_LOCAL_ADDR:
+      // TODO XXX bgp_proto->link_addr & zero local_ip
+      STORE_PTR(pkt, ipa_to_u32(bgp_proto->local_ip));
+      BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
+      break;
+
+    case BGP_INTERNAL_LOCAL_PORT:
+      STORE_PTR(pkt, bgp_conf->local_port);
+      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
+
+    case BGP_INTERNAL_REMOTE_ADDR:
+      STORE_PTR(pkt, ipa_to_u32(bgp_proto->remote_ip));
+      BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
+      break;
+
+    case BGP_INTERNAL_REMOTE_PORT:
+      STORE_PTR(pkt, bgp_conf->remote_port);
+      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
+
+    case BGP_INTERNAL_REMOTE_AS:
+      STORE_PTR(pkt, bgp_proto->remote_as);
+      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
+
+    /* IN UPDATES */
+    case BGP_INTERNAL_RX_UPDATES:
+      STORE_PTR(pkt, bgp_stats->rx_updates);
+      BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+      break;
+
+    /* OUT UPDATES */
+    case BGP_INTERNAL_TX_UPDATES:
+      STORE_PTR(pkt, bgp_stats->tx_updates);
+      BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+      break;
+
+    /* IN MESSAGES */
+    case BGP_INTERNAL_RX_MESSAGES:
+      STORE_PTR(pkt, bgp_stats->rx_messages);
+      BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+      break;
+
+    /* OUT MESSAGES */
+    case BGP_INTERNAL_TX_MESSAGES:
+      STORE_PTR(pkt, bgp_stats->tx_messages);
+      BGP_DATA(vb, AGENTX_COUNTER_32, pkt);
+      break;
+
+    case BGP_INTERNAL_LAST_ERROR:
+      STORE_PTR(pkt, 2);
+      pkt += 4;
+
+      if (bgp_proto->last_error_code)
+      {
+       /* force network order */
+       put_u32(pkt, bgp_proto->last_error_code & 0x00FF0000 << 8 |
+         bgp_proto->last_error_code & 0x000000FF << 24);
+      }
+      else
+       snmp_put_blank(pkt);
+
+      BGP_DATA(vb, AGENTX_OCTET_STRING, pkt);
+      break;
+
+    case BGP_INTERNAL_FSM_TRANSITIONS:
+      break;
+    case BGP_INTERNAL_FSM_ESTABLISHED_TIME:
+      break;
+    case BGP_INTERNAL_RETRY_INTERVAL:
+      break;
+    case BGP_INTERNAL_HOLD_TIME:
+      break;
+    case BGP_INTERNAL_KEEPALIVE:
+      break;
+    case BGP_INTERNAL_HOLD_TIME_CONFIGURED:
+      break;
+    case BGP_INTERNAL_KEEPALIVE_CONFIGURED:
+      break;
+    case BGP_INTERNAL_ORIGINATION_INTERVAL:
+      break;
+    case BGP_INTERNAL_MIN_ROUTE_ADVERTISEMENT:
+      break;
+    case BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME:
+      break;
+    case BGP_INTERNAL_END:
+      break;
+
+    case BGP_INTERNAL_INVALID:
+      break;
+
+    case BGP_INTERNAL_BGP:
+      break;
+    case BGP_INTERNAL_PEER_TABLE:
+      break;
+    case BGP_INTERNAL_PEER_ENTRY:
+      break;
+    case BGP_INTERNAL_NO_VALUE:
+      break;
   }
-  /* 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);
+  return NULL;
+}
 
-    log(L_INFO "dynamic part of BGP mib");
+static byte *
+bgp_fill_static(struct snmp_proto *p, struct oid *oid, byte *buf, uint size
+UNUSED, uint contid UNUSED, int byte_ord UNUSED, u8 state)
+{
+  log(L_INFO "snmp bgp_fill_static ()\n");
 
-    struct f_trie_walk_state *ws = mb_allocz(p->p.pool,
-                                            sizeof(struct f_trie_walk_state));
+  struct agentx_varbind *vb = (void *) buf;
+  byte *pkt = buf + snmp_vb_size(vb);
 
-    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);
+  /* snmp_bgp_state() check only prefix. To be sure on oid equivalence we need to
+   * compare the oid->n_subid length. All BGP static fields have same n_subid.
+   */
+  if (oid->n_subid != 3)
+    return snmp_no_such_object(buf, vb);
 
-    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));
+  switch (state)
+  {
+    case BGP_INTERNAL_VERSION:
+      STORE_PTR(pkt, 1);   /* store string len */
+      pkt += 4;
+      STORE_PTR(pkt, BGP4_VERSIONS);
 
-      mb_free(net);
-      mb_free(ws);
+      /* real size is 8 but we already shifted the pkt by 4 */
+      BGP_DATA(vb, AGENTX_OCTET_STRING, pkt);
+      break;
 
-      return o;
-    }
+    case BGP_INTERNAL_LOCAL_AS:
+      // XXX local as to use
 
-    else
-    {
-      mb_free(net);
-      mb_free(ws);
+      STORE_PTR(pkt, p->local_as);
+      BGP_DATA(vb, AGENTX_INTEGER, pkt);
+      break;
+  }
 
-      return NULL;
-    }
+  log(L_INFO "snmp ended with non empty pkt\n");
+  return pkt;
+}
+
+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);
+
+  if (!is_dynamic(state))
+    return bgp_fill_static(p, oid, buf, size, contid, byte_ord, state);
+
+  if (is_dynamic(state) && snmp_bgp_has_value(state))
+    return bgp_fill_dynamic(p, oid, buf, size, contid, byte_ord, state);
+
+  else
+  {
+    // TODO XXX fix here
+    return snmp_no_such_object(buf, NULL);
   }
 }
index 1a7b6c0710ed0b184cd5e5f0448d5c97d29ca27e..fb1a0b1c53a4b367fcaf1045b3a651ab3521d3cf 100644 (file)
@@ -37,7 +37,7 @@ enum BGP4_MIB {
 struct oid;
 
 void snmp_bgp_register(void);
-int snmp_bgp_is_supported(struct oid *o);
+// - int snmp_bgp_is_supported(struct oid *o);
 
 int snmp_bgp_valid_ip4(struct oid *o);
 u8 snmp_bgp_state(struct oid *o);
index 45f24aa7504fff121d7f7a96a6b7bda7b2e8a264..ac2f01d6e7d11ea7a35462a89c00da26b39e2506 100644 (file)
@@ -106,7 +106,4 @@ struct snmp_proto {
   uint errs;
 };
 
-/* fixes bugs when making tests */
-//struct protocol proto_snmp;
-
 #endif
index dd4adc0dc6ec54d08062bb73fa6e0a76052ae651..d4cb8300436ccd790c119e479888444121ea0be6 100644 (file)
 #include "bgp_mib.h"
 #include "subagent.h"
 #include "snmp.h"
+#include "snmp_utils.h"
+#include "snmp_internal.h"
 
 #define SNMP_EXPECTED(actual, expected) \
   bt_debug("%s  expected: %3u   actual: %3u\n", \
     #expected, expected, actual);
 
+#ifdef CPU_BIG_ENDIAN
+  #define BYTE_ORD 1
+#else
+  #define BYTE_ORD 0
+#endif
+
 void
 dump_oid(struct oid *oid)
 {
@@ -31,12 +39,11 @@ dump_oid(struct oid *oid)
 }
 
 void
-dump_bgp_state_values(void)
+test_fill(struct snmp_proto *p)
 {
-    // TODO XXX here
+  ((struct proto *) p)->pool = &root_pool;
 }
 
-
 static void
 test_oid(struct oid *oid, uint base_size)
 {
@@ -141,10 +148,132 @@ test_oid(struct oid *oid, uint base_size)
   bt_assert(snmp_bgp_state(oid) == BGP_INTERNAL_IN_UPDATE_ELAPSED_TIME);
 }
 
+static int
+t_s_is_oid_empty(void)
+{
+  bt_assert(snmp_is_oid_empty(NULL) == 0);
+
+  struct oid *blank = mb_alloc(&root_pool, sizeof(struct oid));
+  blank->n_subid = 0;
+  blank->prefix = 0;
+  blank->include = 0;
+
+  bt_assert(snmp_is_oid_empty(blank) == 1);
+
+  struct oid *prefixed = mb_alloc(&root_pool, sizeof(struct oid) + 3 * sizeof(u32));
+  prefixed->n_subid = 3;
+  prefixed->prefix = 100;
+  prefixed->include = 1;
+
+  u32 prefixed_arr[] = { ~((u32) 0), 0, 256 };
+  memcpy(&prefixed->ids, prefixed_arr, sizeof(prefixed_arr) /
+    sizeof(prefixed_arr[0]));
+
+  bt_assert(snmp_is_oid_empty(prefixed) == 0);
+
+  struct oid *to_prefix = mb_alloc(&root_pool, sizeof(struct oid) + 8 * sizeof(u32));
+  to_prefix->n_subid = 8;
+  to_prefix->prefix = 0;
+  to_prefix->include = 1;
+
+  u32 to_prefix_arr[] = {1, 3, 6, 1, 100, ~((u32) 0), 0, 256 };
+  memcpy(&to_prefix->n_subid, to_prefix_arr, sizeof(to_prefix_arr) /
+    sizeof(to_prefix_arr[0]));
+
+  bt_assert(snmp_is_oid_empty(to_prefix) == 0);
+
+  struct oid *unprefixable = mb_alloc(&root_pool, sizeof(struct oid) + 2 * sizeof(u32));
+  unprefixable->n_subid = 2;
+  unprefixable->prefix = 0;
+  unprefixable->include = 0;
+
+  u32 unpref[] = { 65535, 4 };
+  memcpy(&unprefixable->ids, unpref, sizeof(unpref) / sizeof(unpref[0]));
+
+  bt_assert(snmp_is_oid_empty(unprefixable) == 0);
+
+  struct oid *unprefixable2 = mb_alloc(&root_pool, sizeof(struct oid) + 8 * sizeof(u32));
+  unprefixable2->n_subid = 8;
+  unprefixable2->prefix = 0;
+  unprefixable2->include = 1;
+
+  u32 unpref2[] = { 1, 3, 6, 2, 1, 2, 15, 6 };
+  memcpy(&unprefixable2->ids, unpref2, sizeof(unpref2) / sizeof(unpref2[0]));
+
+  bt_assert(snmp_is_oid_empty(unprefixable2) == 0);
+
+  return 1;
+}
+
+static int
+t_s_prefixize(void)
+{
+  struct oid *nulled = NULL;
+
+  struct snmp_proto snmp_proto;
+
+  test_fill(&snmp_proto);
+
+  bt_debug("before seg fault\n");
+  struct oid *tmp = snmp_prefixize(&snmp_proto, nulled, BYTE_ORD);
+  bt_debug("after snmp_prefixize() call\n");
+  bt_assert( NULL == tmp );
+
+  bt_debug("after assert\n");
+  struct oid *blank = mb_allocz(&root_pool, sizeof(struct oid));
+
+  /* here the byte order should not matter */
+  bt_assert(snmp_is_oid_empty(snmp_prefixize(&snmp_proto, blank, 1 - BYTE_ORD)) == 1);
+
+  struct oid *prefixed = mb_alloc(&root_pool, sizeof(struct oid) + 3 * sizeof(u32));
+  prefixed->n_subid = 3;
+  prefixed->prefix = 100;
+  prefixed->include = 1;
+
+  u32 prefixed_arr[] = { ~((u32) 0), 0, 256 };
+  memcpy(&prefixed->ids, prefixed_arr, sizeof(prefixed_arr) /
+    sizeof(prefixed_arr[0]));
+
+    bt_assert(memcmp(snmp_prefixize(&snmp_proto, prefixed, BYTE_ORD), prefixed, snmp_oid_size(prefixed)) == 0);
+
+  struct oid *to_prefix = mb_alloc(&root_pool, sizeof(struct oid) + 8 * sizeof(u32));
+  to_prefix->n_subid = 8;
+  to_prefix->prefix = 0;
+  to_prefix->include = 1;
+
+  u32 to_prefix_arr[] = {1, 3, 6, 1, 100, ~((u32) 0), 0, 256 };
+  memcpy(&to_prefix->n_subid, to_prefix_arr, sizeof(to_prefix_arr) /
+    sizeof(to_prefix_arr[0]));
+
+  bt_assert(memcmp(snmp_prefixize(&snmp_proto, to_prefix, BYTE_ORD), prefixed, snmp_oid_size(prefixed)) == 0);
+
+  struct oid *unprefixable = mb_alloc(&root_pool, sizeof(struct oid) + 2 * sizeof(u32));
+  unprefixable->n_subid = 2;
+  unprefixable->prefix = 0;
+  unprefixable->include = 0;
+
+  u32 unpref[] = { 65535, 4 };
+  memcpy(&unprefixable->ids, unpref, sizeof(unpref) / sizeof(unpref[0]));
+
+  bt_assert(snmp_prefixize(&snmp_proto, unprefixable, BYTE_ORD) == NULL);
+
+  struct oid *unprefixable2 = mb_alloc(&root_pool, sizeof(struct oid) + 8 * sizeof(u32));
+  unprefixable2->n_subid = 8;
+  unprefixable2->prefix = 0;
+  unprefixable2->include = 1;
+
+  u32 unpref2[] = { 1, 3, 6, 2, 1, 2, 15, 6 };
+  memcpy(&unprefixable2->ids, unpref2, sizeof(unpref2) / sizeof(unpref2[0]));
+
+  bt_assert(snmp_prefixize(&snmp_proto, unprefixable2, BYTE_ORD) == NULL);
+
+  return 1;
+}
+
 static int
 t_s_bgp_state(void)
 {
-  struct oid *oid = alloca(sizeof(struct oid) + 10 * sizeof(32));
+  struct oid *oid = mb_alloc(&root_pool, sizeof(struct oid) + 10 * sizeof(u32));
 
   /* oid header */
   oid->n_subid = 0;
@@ -181,9 +310,6 @@ t_s_bgp_state(void)
   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;
 }
 
@@ -193,5 +319,9 @@ int main(int argc, char **argv)
 
   bt_test_suite(t_s_bgp_state, "Function snmp_bgp_state()");
 
+  bt_test_suite(t_s_is_oid_empty, "Function snmp_is_oid_empty()");
+
+  bt_test_suite(t_s_prefixize, "Function snmp_prefixize()");
+
   return bt_exit_value();
 }
index 7a0ad4dbb44f085ee22b02e6415008b140b1fa98..151ce01ae017e4f4b9de5950a211174d4ba4c383 100644 (file)
 
 #include "lib/unaligned.h"
 #include "subagent.h"
+#include "snmp_utils.h"
 #include "bgp_mib.h"
 
+#include "snmp_internal.h"
+
 /* =============================================================
  *  Problems
  *  ------------------------------------------------------------
@@ -24,7 +27,6 @@
  */
 
 static int parse_response(struct snmp_proto *p, byte *buf, uint size);
-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);
 static uint parse_get_pdu(struct snmp_proto *p, byte *buf, uint size);
@@ -32,9 +34,7 @@ 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 *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);
 
 static const char * const snmp_errs[] = {
   #define SNMP_ERR_SHIFT 256
@@ -53,124 +53,6 @@ static const char * const snmp_errs[] = {
   [AGENTX_RES_PROCESSING_ERR - SNMP_ERR_SHIFT] = "Processing error",
 };
 
-/* payload length in bytes */
-static inline size_t
-pkt_len(byte *buf, byte *pkt)
-{
-  return (pkt - buf) - AGENTX_HEADER_SIZE;
-}
-
-static inline size_t
-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)
-{
-  uint len = strlen(str);
-  uint slen = BIRD_ALIGN(len, 4);
-
-  if (len > MAX_STR)
-    return NULL;
-
-  STORE_PTR(buf, len);
-
-  memcpy(buf + 4, str, len);
-
-  for (uint i = 0; i < slen - len; i++)
-    buf[len + i] = 0x00;  // PADDING
-
-  return buf + str_size(str);
-}
-
-static byte *
-put_blank(byte *buf)
-{
-  STORE_PTR(buf, 0);
-  return buf + 4;
-}
-
-static byte *
-put_oid(byte *buf, struct oid *oid)
-{
-  log(L_INFO "testing oid");
-  for (uint i = 0; i < oid->n_subid; i++)
-    log(L_INFO "oid id %d:  %u", i, oid->ids[i]);
-  log(L_INFO "put_oid()");
-  put_u8(buf, oid->n_subid);
-  log(L_INFO "data %p: %02X", buf, *buf);
-  put_u8(++buf, oid->prefix);
-  log(L_INFO "data %p: %02X", buf, *buf);
-  put_u8(++buf, oid->include);
-  log(L_INFO "data %p: %02X", buf, *buf);
-  put_u8(++buf, 0);  // PADDING
-  /* last increment */
-  ++buf;
-  log(L_INFO "oid head end %p", buf);
-
-  /* copy OID data */
-#ifdef SNMP_NATIVE
-  for (uint i = 0; i < oid->n_subid; i++)
-    *(((u32 *) buf) + i) = oid->ids[i];
-#else
-  put_u32s(buf, oid->ids, oid->n_subid << 2);
-#endif
-/*
-  for (uint i = 0; i <= (oid->n_subid << 2) +4 ; i += 4)
-    log(L_INFO "OID % 3u: %02X %02X %02X %02X", i,
-      *(buf - 4 + i),
-      *(buf - 4 + i + 1),
-      *(buf - 4 + i + 2),
-      *(buf - 4  + i + 3)
-  );
-*/
-
-  return buf + (oid->n_subid << 2);
-}
-
-void
-snmp_oid_ip4_index(struct oid *o, ip4_addr addr)
-{
-  u32 temp = ip4_to_u32(addr);
-  STORE(o->ids[5], temp >> 24);
-  STORE(o->ids[6], (temp & 0x00FF0000) >> 16);
-  STORE(o->ids[7], (temp & 0x0000FF00) >> 8);
-  STORE(o->ids[8], temp & 0x000000FF);
-}
-
-/* paste data at first byte in message
- *   with 3B of padding
- */
-static byte *
-paste_fbyte(byte *buf, u8 data)
-{
-  log(L_INFO "paste_fbyte()");
-  put_u8(buf, data);
-  put_u24(++buf, 0);  // PADDING
-  return buf + 3;
-}
-
 static void
 open_pdu(struct snmp_proto *p, struct oid *oid)
 {
@@ -184,7 +66,7 @@ open_pdu(struct snmp_proto *p, struct oid *oid)
 
   //uint pkt_size = 0;
 
-  if (size > AGENTX_HEADER_SIZE + snmp_oid_size(oid) + str_size(str))
+  if (size > AGENTX_HEADER_SIZE + snmp_oid_size(oid) + snmp_str_size(str))
   {
     log(L_INFO "open_pdu()");
 
@@ -196,11 +78,11 @@ open_pdu(struct snmp_proto *p, struct oid *oid)
     STORE(h->transaction_id, 1);
     STORE(h->packet_id, 1);
 
-    pkt = paste_fbyte(pkt, p->timeout);
-    pkt = put_oid(pkt, oid);
-    pkt = put_str(pkt, str);
+    pkt = snmp_put_fbyte(pkt, p->timeout);
+    pkt = snmp_put_oid(pkt, oid);
+    pkt = snmp_put_str(pkt, str);
 
-    SNMP_UPDATE(h, pkt_len(buf, pkt));
+    SNMP_UPDATE(h, snmp_pkt_len(buf, pkt));
 
     int ret = sk_send(sk, pkt - buf);
 
@@ -214,7 +96,7 @@ open_pdu(struct snmp_proto *p, struct oid *oid)
 
   else
     log(L_INFO "open_pdu() insufficient size, %u <= %u ",
-       size, AGENTX_HEADER_SIZE + snmp_oid_size(oid) + str_size(str));
+       size, AGENTX_HEADER_SIZE + snmp_oid_size(oid) + snmp_str_size(str));
 }
 
 /* index allocate / deallocate pdu * /
@@ -272,7 +154,7 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8
     STORE(ur->priority, AGENTX_PRIORITY);
     STORE(ur->range_subid, (len > 1) ? index : 0);
 
-    pkt = put_oid(pkt, oid);
+    pkt = snmp_put_oid(pkt, oid);
     log(L_INFO "pkt - buf : %lu sizeof %u", pkt -buf, AGENTX_HEADER_SIZE);
 
     /* place upper-bound if needed */
@@ -282,8 +164,8 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8
       pkt += 4;
     }
 
-    log("size of pkt: %u", pkt_len(buf,pkt));
-    SNMP_UPDATE(h, pkt_len(buf, pkt));
+    log("size of pkt: %u", snmp_pkt_len(buf,pkt));
+    SNMP_UPDATE(h, snmp_pkt_len(buf, pkt));
 
     for (uint i = 0; i < pkt - buf; i++)
       log(L_INFO "%p:  %02X", buf+i, *(buf + i));
@@ -337,9 +219,9 @@ close_pdu(struct snmp_proto *p, u8 reason)
 
     SNMP_SESSION(h, p)
 
-    pkt = paste_fbyte(pkt, reason);
+    pkt = snmp_put_fbyte(pkt, reason);
 
-    SNMP_UPDATE(h, pkt_len(buf, pkt));
+    SNMP_UPDATE(h, snmp_pkt_len(buf, pkt));
 
     log(L_INFO "preparing to sk_send()");
     int ret = sk_send(sk, pkt - buf);
@@ -499,7 +381,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)
       {
-       snmp_oid_ip4_index(o2, ipa_to_ip4(peer->peer_ip));
+       snmp_oid_ip4_index(o2, 5, ipa_to_ip4(peer->peer_ip));
 
        log(L_INFO "");
        log(L_INFO "o2 n_subid %u prefix %u include %u", o2->n_subid,
@@ -605,7 +487,7 @@ parse_get_pdu(struct snmp_proto *p, byte *buf, uint size)
   }
 
   struct agentx_header *rh = (void *) res;
-  SNMP_UPDATE(rh, pkt_len(res, res_pkt));
+  SNMP_UPDATE(rh, snmp_pkt_len(res, res_pkt));
 
   if (err)
     response_err_ind(res, err, ind);
@@ -670,10 +552,12 @@ parse_gets_pdu(struct snmp_proto *p, byte *req, uint size)
   SNMP_LOAD_CONTEXT(p, h, req, context, clen);
 
   res_pkt = prepare_response(p, res, rsize);
+
   uint ind = 1;
   int err = 0;
   while (!err && pkt - req < pkt_size)
   {
+    /* oids from message buffer */
     struct oid *o_start_b, *o_end_b;
     o_start_b = (struct oid *) pkt;
     pkt += snmp_oid_size(o_start_b);
@@ -688,11 +572,20 @@ parse_gets_pdu(struct snmp_proto *p, byte *req, uint size)
       continue;
     }
 
+    snmp_oid_dump(o_start_b);
+    snmp_oid_dump(o_end_b);
     /* 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);
+
+    struct oid *o_start = snmp_prefixize(p, o_start_b, byte_ord);
+    struct oid *o_end = snmp_prefixize(p, o_end_b, byte_ord);
+
+    snmp_oid_dump(o_start);
+    snmp_oid_dump(o_end);
 
     u8 mib_class = get_mib_class(o_start);
+
+    log(L_INFO "get mib_class () -> next pdu parsing ... ");
+
     switch (h->type)
     {
       case AGENTX_GET_PDU:
@@ -765,7 +658,7 @@ parse_gets_pdu(struct snmp_proto *p, byte *req, uint size)
 
   log(L_INFO " pasting size");
   struct agentx_header *rh = (void *) res;
-  SNMP_UPDATE(rh, pkt_len(res, res_pkt));
+  SNMP_UPDATE(rh, snmp_pkt_len(res, res_pkt));
 
   log(L_INFO "%p %lu", p->sock->ttx, res_pkt - res);
   log(L_INFO "%p %p", res_pkt, res);
@@ -801,14 +694,6 @@ snmp_stop_subagent(struct snmp_proto *p)
   }
 }
 
-/* return number of bytes used  by @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)
 {
@@ -819,14 +704,6 @@ oid_prefix(struct oid *o, u32 *prefix, uint len)
   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 snmp_oid_size(&vb->name) + 4;
-}
-
 int
 snmp_rx(sock *sk, uint size)
 {
@@ -1038,7 +915,7 @@ find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt, uint size UNUSED, u
     b_state = MAX(b_in->state, b_out->state);
 
   struct agentx_varbind *vb = (void *) pkt;
-  pkt += vb_size(vb);
+  pkt += snmp_vb_size(vb);
 
   switch (o->ids[4])
   {
@@ -1050,7 +927,7 @@ find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt, uint size UNUSED, u
       }
       else
       {
-       put_blank(pkt);         /* store 4B of zeroes */
+       snmp_put_blank(pkt);            /* store 4B of zeroes */
        BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
       }
       break;
@@ -1182,7 +1059,7 @@ find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt, uint size UNUSED, u
 
     case SNMP_BGP_FSM_ESTABLISHED_TIME:
     case SNMP_BGP_IN_UPDATE_ELAPSED_TIME:
-      return no_such_object(pkt, vb);
+      return snmp_no_such_object(pkt, vb);
 
     /* no default */
   }
@@ -1195,7 +1072,7 @@ static byte *
 snmp_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid)
 {
   struct agentx_varbind *vb = (void *) buf;
-  byte *pkt = buf + vb_size(vb);
+  byte *pkt = buf + snmp_vb_size(vb);
 
   switch (o->ids[2])
   {
@@ -1217,7 +1094,7 @@ snmp_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint
       /* 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] != SNMP_BGP_PEER_ENTRY
          || o->ids[4] == 0 || o->ids[4] > 24)
-       return no_such_object(pkt, vb);
+       return snmp_no_such_object(pkt, vb);
 
       // TODO enumerate range requests
       ip_addr addr = ipa_build4(o->ids[5], o->ids[6], o->ids[7], o->ids[8]);
@@ -1245,14 +1122,14 @@ snmp_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint
 
       if (!bp)
        /* pkt += 0; no data */
-       return no_such_object(pkt, vb);
+       return snmp_no_such_object(pkt, vb);
 
       return find_bgp_one(bp, o, buf, size, contid);
       break;
 
     default:
       /* pkt += 0; no data */
-      return no_such_object(pkt, vb);
+      return snmp_no_such_object(pkt, vb);
   }
 
   return pkt;
@@ -1267,20 +1144,6 @@ find_ospf_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size)
 }
 */
 
-static byte *
-no_such_object(byte *buf, struct agentx_varbind *vb)
-{
-  vb->type = AGENTX_NO_SUCH_OBJECT;
-  return buf;
-}
-
-static UNUSED byte *
-no_such_instance(byte *buf, struct agentx_varbind *vb)
-{
-  vb->type = AGENTX_NO_SUCH_INSTANCE;
-  return buf;
-}
-
 static inline byte *
 find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid)
 {
@@ -1290,7 +1153,7 @@ find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint co
 
                        /* SNMPv2   mgmt                     mib-2 */
   if (o->n_subid < 2 || (o->prefix != 2 && o->ids[0] != 1))
-    no_such_object(buf + vb_size(vb), vb);
+    snmp_no_such_object(buf + snmp_vb_size(vb), vb);
 
   switch (o->ids[1])
   {
@@ -1299,16 +1162,16 @@ find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint co
       return snmp_bgp_record(p, o, buf, size, contid);
 
     case SNMP_OSPFv3_MIB:
-      return no_such_object(buf, vb);
+      return snmp_no_such_object(buf, vb);
       //return find_ospf_record(p, o, buf, size);
 
     default:
-      return no_such_object(buf, vb);
+      return snmp_no_such_object(buf, vb);
   }
 }
 
 /** 
- * prefixize - return prefixed oid copy if possible
+ * snmp_prefixize - return prefixed oid copy if possible
  * @proto: allocation pool holder
  * @oid: from packet loaded object identifier
  * @byte_ord: byte order of @oid 
@@ -1317,11 +1180,24 @@ find_prefixed(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint co
  * 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 *proto, struct oid *oid, int byte_ord)
+struct oid *
+snmp_prefixize(struct snmp_proto *proto, struct oid *oid, int byte_ord)
 {
   const u32 prefix[] = {1, 3, 6, 1};
 
+  if (snmp_is_oid_empty(oid))
+  {
+    /* allocate new zeroed oid */
+    struct oid *new = mb_allocz(proto->p.pool, sizeof(struct oid));
+    return new;
+  }
+  else if (LOAD(oid->n_subid, byte_ord) != 0)
+  {
+    struct oid *new = mb_allocz(proto->p.pool, snmp_oid_size(oid));
+    memcpy(new, oid, snmp_oid_size(oid));
+    return new;
+  }
+
   if (oid->n_subid < 5)
     return NULL;
 
@@ -1350,7 +1226,7 @@ static inline byte *
 find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid, int byte_ord)
 {
   struct oid *new;
-  if (!o->prefix && (new = prefixize(p, o, byte_ord)) != NULL)
+  if (!o->prefix && (new = snmp_prefixize(p, o, byte_ord)) != NULL)
     return find_prefixed(p, new, buf, size, contid);
   else if (o->prefix)
     return find_prefixed(p, o, buf, size, contid);
@@ -1361,26 +1237,25 @@ find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint cont
 /**
  * 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)
+static byte *snmp_mib_fill(struct snmp_proto *p, struct oid *oid, u8 mib_class, byte *buf, uint size, uint contid, int byte_ord)
 { 
+  log(L_INFO "snmp_mib_fill()");
   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);
+    return snmp_no_such_object(buf + snmp_vb_size(vb), vb);
 
   switch (mib_class)
   {
     case SNMP_CLASS_BGP:
       buf = snmp_bgp_fill(p, oid, buf, size, contid, byte_ord);
-      break;   
+      break;
   }
  
-  return buf; 
+  return buf;
 }
 
 static byte *
index 808c5cfbc0763e2641a8f4af27b1a0003059502f..4896faa1a10986c270f768896c1e6d4e51bfbc06 100644 (file)
@@ -103,7 +103,7 @@ enum agentx_type {
   log(L_INFO "LOAD_STR(), %p %u", p->p.pool, l + 1); \
   s = mb_allocz(p->p.pool, l + 1);  \
   memcpy(s, b, l);                 \
-  b += str_size(s);
+  b += snmp_str_size(s);
 
 #define SNMP_LOAD_CONTEXT(p, h, b, s, l)      \
   if (h->flags & AGENTX_NON_DEFAULT_CONTEXT)  \
@@ -111,8 +111,8 @@ enum agentx_type {
     LOAD_STR(p, b, s, l, h->flags & AGENTX_NETWORK_BYTE_ORDER); }
 
 #define SNMP_COPY_OID(b, o) \
-  memcpy(b, o, oid_size(o));   \
-  b += oid_size(o);
+  memcpy(b, o, snmp_oid_size(o));   \
+  b += snmp_oid_size(o);
 
 #define SNMP_COPY_VB(b, s, e)  \
   memcpy(b, s, 4);             \
@@ -120,11 +120,11 @@ enum agentx_type {
   SNMP_COPY_OID(b, &s->name)   \
   SNMP_COPY_OID(b, e)
 
-#define BGP_DATA_(v, d, p, o) \
-  (v)->type = d;                 \
-  p += o;
+#define BGP_DATA_(varbind, type_, packet, offset) \
+  (varbind)->type = type_;               \
+  packet += offset;
 
-#define BGP_DATA(v, d, p) BGP_DATA_(v, d, p, 4)
+#define BGP_DATA(varbind, type_, packet) BGP_DATA_(varbind, type_, packet, 4)
 
 struct agentx_header {
   u8 version;
@@ -160,6 +160,11 @@ struct agentx_search_range {
   struct oid end;
 };
 
+struct agentx_getbulk {
+  u16 non_repeaters;
+  u16 max_repetitions;
+};
+
 struct agentx_response {
   struct agentx_header h;
   u32 uptime;
@@ -255,11 +260,6 @@ 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