]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
SNMP: Minor improvements
authorVojtech Vilimek <vojtech.vilimek@nic.cz>
Tue, 23 Jul 2024 11:48:20 +0000 (13:48 +0200)
committerVojtech Vilimek <vojtech.vilimek@nic.cz>
Tue, 23 Jul 2024 11:48:20 +0000 (13:48 +0200)
proto/snmp/bgp4_mib.c
proto/snmp/bgp4_mib.h
proto/snmp/snmp.c
proto/snmp/snmp.h
proto/snmp/snmp_test.c
proto/snmp/snmp_utils.c
proto/snmp/snmp_utils.h
proto/snmp/subagent.c
proto/snmp/subagent.h

index 366f49ef4b1702cb590b5245aa9eb1e6fb210ad0..32ec536aabe3e10572421e5cffefee06d438cc01 100644 (file)
@@ -39,6 +39,7 @@
 #define POPULATE_BGP4(addr, proto, conn, stats, config) populate_bgp4(c, &(addr), &(proto), &(conn), &(stats), &(config))
 
 static inline void ip4_to_oid(struct oid *oid, ip4_addr addr);
+static const STATIC_OID(2) bgp4_mib_oid = STATIC_OID_INITIALIZER(2, SNMP_MGMT, SNMP_MIB_2, SNMP_BGP4_MIB);
 
 static inline void
 snmp_hash_add_peer(struct snmp_proto *p, struct snmp_bgp_peer *peer)
@@ -117,7 +118,7 @@ snmp_bgp_notify_common(struct snmp_proto *p, uint type, ip4_addr ip4, char last_
     (void *) error_vb + snmp_varbind_size_from_len(9, AGENTX_OCTET_STRING, 2);
 
   u32 oid_ids[] = {
-    SNMP_MIB_2, BGP4_MIB, BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY
+    SNMP_MIB_2, SNMP_BGP4_MIB, BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY
   };
 
   /*
@@ -234,12 +235,12 @@ snmp_bgp_notify_backward_trans(struct snmp_proto *p, struct bgp_proto *bgp)
 void
 snmp_bgp4_register(struct snmp_proto *p)
 {
-  u32 bgp_mib_prefix[] = { SNMP_MIB_2, BGP4_MIB };
+  u32 bgp_mib_prefix[] = { SNMP_MIB_2, SNMP_BGP4_MIB };
 
   {
     /* Register the whole BGP4-MIB::bgp root tree node */
     struct snmp_registration *reg;
-    reg = snmp_registration_create(p, BGP4_MIB);
+    reg = snmp_registration_create(p, BGP4_MIB_ID);
 
     struct oid *oid = mb_allocz(p->pool,
       snmp_oid_size_from_len(ARRAY_SIZE(bgp_mib_prefix)));
@@ -446,9 +447,9 @@ fill_admin_status(struct mib_walk_state *walk UNUSED, struct snmp_pdu *c)
     return res;
 
   if (bgp_proto->p.disabled)
-    snmp_varbind_int(c, AGENTX_ADMIN_STOP);
+    snmp_varbind_int(c, BGP4_ADMIN_STOP);
   else
-    snmp_varbind_int(c, AGENTX_ADMIN_START);
+    snmp_varbind_int(c, BGP4_ADMIN_START);
   return SNMP_SEARCH_OK;
 }
 
@@ -792,15 +793,9 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_pdu *c)
   struct oid *oid = &c->sr_vb_start->name;
 
   /* BGP4-MIB::bgpPeerIdentifier */
-  STATIC_OID(9) bgp4_peer_id = {
-    .n_subid = 9,
-    .prefix = SNMP_MGMT,
-    .include = 0,
-    .reserved = 0,
-    .ids = { SNMP_MIB_2, BGP4_MIB,
-      BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY, BGP4_MIB_PEER_IDENTIFIER,
-      /* IP4_NONE */ 0, 0, 0, 0 }
-  };
+  STATIC_OID(9) bgp4_peer_id = STATIC_OID_INITIALIZER(9, SNMP_MGMT,
+    /* ids */ SNMP_MIB_2, SNMP_BGP4_MIB,
+      BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY, BGP4_MIB_PEER_IDENTIFIER);
 
   ip4_addr ip4 = ip4_from_oid(oid);
 
@@ -815,12 +810,8 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_pdu *c)
     int old = snmp_oid_size(oid);
     int new = snmp_oid_size(peer_oid);
 
-    if (new - old > 0 && (uint) new - old > c->size)
-    {
-      snmp_log("bgp4_next_peer small buffer");
-      snmp_manage_tbuf(c->p, c);
-      oid = &c->sr_vb_start->name;  // TODO fix sr_vb_start in manage_tbuf
-    }
+    if (new - old > 0 && snmp_tbuf_reserve(c, new - old))
+      oid = &c->sr_vb_start->name;
 
     c->buffer += (new - old);
 
@@ -864,7 +855,7 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_pdu *c)
 }
 
 /*
- * snmp_bgp_start - prepare BGP4-MIB
+ * snmp_bgp4_start - prepare BGP4-MIB
  * @p - SNMP protocol instance holding memory pool
  *
  * This function create all runtime bindings to BGP procotol structures.
@@ -873,6 +864,12 @@ bgp4_next_peer(struct mib_walk_state *state, struct snmp_pdu *c)
 void
 snmp_bgp4_start(struct snmp_proto *p)
 {
+  agentx_available_mibs[BGP4_MIB_ID] = (struct oid *) &bgp4_mib_oid;
+
+  snmp_log("snmp_bgp4_start setting bgp4_mib oid %u %p %p %p",
+    BGP4_MIB_ID, &agentx_available_mibs[BGP4_MIB_ID], agentx_available_mibs[BGP4_MIB_ID], &bgp4_mib_oid);
+
+
   struct snmp_config *cf = SKIP_BACK(struct snmp_config, cf, p->p.cf);
   /* Create binding to BGP protocols */
 
@@ -897,36 +894,18 @@ snmp_bgp4_start(struct snmp_proto *p)
     snmp_hash_add_peer(p, peer);
   }
 
-  const STATIC_OID(2) bgp4_mib_root = {
-    .n_subid = 2,
-    .prefix = SNMP_MGMT,
-    .include = 0,
-    .reserved = 0,
-    .ids = { SNMP_MIB_2, BGP4_MIB },
-  };
-
-  const STATIC_OID(4) bgp4_mib_peer_entry = {
-    .n_subid = 4,
-    .prefix = SNMP_MGMT,
-    .include = 0,
-    .reserved = 0,
-    .ids = { SNMP_MIB_2, BGP4_MIB, BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY },
-  };
+  const STATIC_OID(4) bgp4_mib_peer_entry = STATIC_OID_INITIALIZER(4, SNMP_MGMT,
+    /* ids */ SNMP_MIB_2, SNMP_BGP4_MIB, BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY);
 
   (void) mib_tree_hint(p->pool, p->mib_tree,
-    (const struct oid *) &bgp4_mib_root, BGP4_MIB_IDENTIFIER);
+    (const struct oid *) &bgp4_mib_oid, BGP4_MIB_IDENTIFIER);
   (void) mib_tree_hint(p->pool, p->mib_tree,
     (const struct oid *) &bgp4_mib_peer_entry, BGP4_MIB_IN_UPDATE_ELAPSED_TIME);
 
   mib_node_u *node;
   struct mib_leaf *leaf;
-  STATIC_OID(3) bgp4_var = {
-    .n_subid = 3,
-    .prefix = SNMP_MGMT,
-    .include = 0,
-    .reserved = 0,
-    .ids = { SNMP_MIB_2, BGP4_MIB, BGP4_MIB_VERSION },
-  };
+  STATIC_OID(3) bgp4_var = STATIC_OID_INITIALIZER(3, SNMP_MGMT,
+    /* ids */ SNMP_MIB_2, SNMP_BGP4_MIB, BGP4_MIB_VERSION);
 
   struct {
     u32 id;
@@ -966,14 +945,9 @@ snmp_bgp4_start(struct snmp_proto *p)
     leaf->size = leafs[i].size;
   }
 
-  STATIC_OID(5) bgp4_entry_var = {
-    .n_subid = 5,
-    .prefix = SNMP_MGMT,
-    .include = 0,
-    .reserved = 0,
-    .ids = { SNMP_MIB_2, BGP4_MIB,
-       BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY, BGP4_MIB_PEER_IDENTIFIER },
-  };
+  STATIC_OID(5) bgp4_entry_var = STATIC_OID_INITIALIZER(5, SNMP_MGMT,
+    /* ids */ SNMP_MIB_2, SNMP_BGP4_MIB,
+       BGP4_MIB_PEER_TABLE, BGP4_MIB_PEER_ENTRY, BGP4_MIB_PEER_IDENTIFIER);
 
   struct {
       enum snmp_search_res (*filler)(struct mib_walk_state *state, struct snmp_pdu *c);
index b77f7f34cc5a56c82fbabc077b8a237ca2224ec8..2639e1a2c0c63afb163022e94cab8045a07e03f1 100644 (file)
@@ -5,7 +5,7 @@
 #include "proto/bgp/bgp.h"
 #include "subagent.h"
 
-#define BGP4_MIB 15
+/* BGP4-MIB root identifier is found in snmp.h as SNMP_BGP4_MIB */
 
 /* peers attributes */
 enum bgp4_mib_peer_entry_row {
@@ -26,8 +26,8 @@ enum bgp4_mib_peer_entry_row {
   BGP4_MIB_FSM_TRANSITIONS         = 15,   /* FSM established transitions */
   BGP4_MIB_FSM_ESTABLISHED_TIME            = 16,
   BGP4_MIB_RETRY_INTERVAL          = 17,
-  BGP4_MIB_HOLD_TIME               = 18,
-  BGP4_MIB_KEEPALIVE               = 19,
+  BGP4_MIB_HOLD_TIME               = 18,   /* in read-only mode */
+  BGP4_MIB_KEEPALIVE               = 19,   /* in read-only mode */
   BGP4_MIB_HOLD_TIME_CONFIGURED            = 20,
   BGP4_MIB_KEEPALIVE_CONFIGURED            = 21,
   BGP4_MIB_ORIGINATION_INTERVAL            = 22,   /* UNSUPPORTED - 0 */
@@ -36,11 +36,18 @@ enum bgp4_mib_peer_entry_row {
 } PACKED;
 
 /* version of BGP, here BGP-4 */
-#define BGP4_VERSIONS ((char[]) { 0x10 }) /* OID bgp.bgpVersion */
-/* for OID bgp.bgpPeerTable.bgpPeerEntry.bgpPeerNegotiatedVersion */
+#define BGP4_VERSIONS ((char[]) { 0x10 }) /* OID BGP4-MIB::bgpVersion */
+
+/* values for BGP4-MIB::bgpPeerNegotiatedVersion */
 #define BGP4_MIB_NEGOTIATED_VER_VALUE 4
 #define BGP4_MIB_NEGOTIATED_VER_NO_VALUE 0
 
+/* values for BGP4-MIB::bgpPeerAdminStatus */
+enum bgp4_admin_status {
+  BGP4_ADMIN_STOP = 1,
+  BGP4_ADMIN_START = 2,
+};
+
 u8 snmp_bgp_get_valid(u8 state);
 u8 snmp_bgp_getnext_valid(u8 state);
 
@@ -65,44 +72,6 @@ enum bgp4_mib_peer_table_rows {
   BGP4_MIB_PEER_ENTRY = 1,
 };
 
-enum bgp4_mib_linearized_states {
-  BGP4_MIB_S_INVALID = 0, /* state invalid */
-  BGP4_MIB_S_START = 1,
-  BGP4_MIB_S_BGP,
-  BGP4_MIB_S_VERSION,
-  BGP4_MIB_S_LOCAL_AS,
-  BGP4_MIB_S_PEER_TABLE,
-  BGP4_MIB_S_PEER_ENTRY,
-  BGP4_MIB_S_PEER_IDENTIFIER,
-  BGP4_MIB_S_STATE,
-  BGP4_MIB_S_ADMIN_STATUS,
-  BGP4_MIB_S_NEGOTIATED_VERSION,
-  BGP4_MIB_S_LOCAL_ADDR,
-  BGP4_MIB_S_LOCAL_PORT,
-  BGP4_MIB_S_REMOTE_ADDR,
-  BGP4_MIB_S_REMOTE_PORT,
-  BGP4_MIB_S_REMOTE_AS,
-  BGP4_MIB_S_RX_UPDATES,
-  BGP4_MIB_S_TX_UPDATES,
-  BGP4_MIB_S_RX_MESSAGES,
-  BGP4_MIB_S_TX_MESSAGES,
-  BGP4_MIB_S_LAST_ERROR,
-  BGP4_MIB_S_FSM_TRANSITIONS,
-  BGP4_MIB_S_FSM_ESTABLISHED_TIME,
-  BGP4_MIB_S_RETRY_INTERVAL,
-  BGP4_MIB_S_HOLD_TIME,
-  BGP4_MIB_S_KEEPALIVE,
-  BGP4_MIB_S_HOLD_TIME_CONFIGURED,
-  BGP4_MIB_S_KEEPALIVE_CONFIGURED,
-  BGP4_MIB_S_ORIGINATION_INTERVAL,
-  BGP4_MIB_S_MIN_ROUTE_ADVERTISEMENT,
-  BGP4_MIB_S_IN_UPDATE_ELAPSED_TIME,
-  BGP4_MIB_S_PEER_TABLE_END,
-  BGP4_MIB_S_IDENTIFIER,       /* state local identification */
-  BGP4_MIB_S_END,
-  BGP4_MIB_S_NO_VALUE = 255,
-} PACKED;
-
 /* valid values for BGP4_MIB_STATE */
 enum bgp4_mib_bgp_states {
   BGP4_MIB_IDLE = 1,
@@ -121,7 +90,9 @@ STATIC_ASSERT(BGP4_MIB_OPENCONFIRM == BS_OPENCONFIRM + 1);
 STATIC_ASSERT(BGP4_MIB_ESTABLISHED == BS_ESTABLISHED + 1);
 
 /* Traps OID sub-identifiers */
-#define BGP4_MIB_ESTABLISHED_NOTIFICATION 1
-#define BGP4_MIB_BACKWARD_TRANS_NOTIFICATION 2
+enum bgp4_traps_subids {
+  BGP4_MIB_ESTABLISHED_NOTIFICATION = 1,
+  BGP4_MIB_BACKWARD_TRANS_NOTIFICATION = 2,
+};
 
 #endif
index 2d81a29739bb0e9d38f57c88d9e492f405672069..f3bf543171478ed3b42df0cdf9a0323c9ae8c06d 100644 (file)
 #include "proto/bgp/bgp.h"
 
 const char agentx_master_addr[] = AGENTX_MASTER_ADDR;
+const struct oid *agentx_available_mibs[AGENTX_MIB_COUNT + 1] = { 0 };
 
 static void snmp_start_locked(struct object_lock *lock);
 static void snmp_sock_err(sock *sk, int err);
 static void snmp_stop_timeout(timer *tm);
 static void snmp_cleanup(struct snmp_proto *p);
 
+/*
+ * agentx_get_mib_init - init function for agentx_get_mib()
+ * @p: SNMP instance protocol pool
+ */
+void agentx_get_mib_init(pool *p)
+{
+  const struct oid *src = agentx_available_mibs[AGENTX_MIB_COUNT - 1];
+  size_t size = snmp_oid_size(src);
+  struct oid *dest = mb_alloc(p, size);
+
+  memcpy(dest, src, size);
+  u8 ids = LOAD_U8(src->n_subid);
+
+  if (ids > 0)
+    STORE_U32(dest->ids[ids - 1], LOAD_U32(src->ids[ids - 1]) + 1);
+
+  agentx_available_mibs[AGENTX_MIB_COUNT] = dest;
+}
+
+/*
+ * agentx_get_mib - classify an OID based on MIB prefix
+ *
+ */
+enum agentx_mibs agentx_get_mib(const struct oid *o)
+{
+  enum agentx_mibs mib = AGENTX_MIB_UNKNOWN;
+  for (uint i = 0; i < AGENTX_MIB_COUNT + 1; i++)
+  {
+    ASSERT(agentx_available_mibs[i]);
+    if (snmp_oid_compare(o, agentx_available_mibs[i]) < 0)
+      return mib;
+    mib = (enum agentx_mibs) i;
+  }
+
+  return AGENTX_MIB_UNKNOWN;
+}
+
+
 /*
  * snmp_rx_skip - skip all received data
  * @sk: communication socket
@@ -517,7 +556,6 @@ snmp_start(struct proto *P)
   p->bgp_local_as = cf->bgp_local_as;
   p->bgp_local_id = cf->bgp_local_id;
   p->timeout = cf->timeout;
-  // TODO add default value for startup_delay inside bison .Y file
   p->startup_delay = cf->startup_delay;
 
   p->pool = p->p.pool;
@@ -535,6 +573,7 @@ snmp_start(struct proto *P)
 
   mib_tree_init(p->pool, p->mib_tree);
   snmp_bgp4_start(p);
+  agentx_get_mib_init(p->pool);
 
   return snmp_set_state(p, SNMP_INIT);
 }
index e5f126c66ca983100c3f0ca480ce4d174d9bf3a7..2e73c3134319fc2564d112f08d7194f36e459d4a 100644 (file)
@@ -100,7 +100,6 @@ struct snmp_proto {
   struct object_lock *lock;
   pool *pool;                    /* a shortcut to the procotol mem. pool */
   linpool *lp;                   /* linpool for bgp_trie nodes */
-  slab *request_storage;                 /* manages storages storage for incomming requests */
 
   enum snmp_proto_state state;
 
@@ -140,13 +139,23 @@ struct snmp_proto {
   struct mib_tree *mib_tree;
 };
 
+enum agentx_mibs {
+  BGP4_MIB_ID,
+  AGENTX_MIB_COUNT,
+  AGENTX_MIB_UNKNOWN,
+};
+
+extern const struct oid *agentx_available_mibs[AGENTX_MIB_COUNT + 1];
+void agentx_get_mib_init(pool *p);
+enum agentx_mibs agentx_get_mib(const struct oid *o);
+
 struct snmp_registration;
 struct agentx_response; /* declared in subagent.h */
 typedef void (*snmp_reg_hook_t)(struct snmp_proto *p, const struct agentx_response *res, struct snmp_registration *reg);
 
 struct snmp_registration {
   node n;
-  u8 mib_class;
+  enum agentx_mibs mib;
   u32 session_id;
   u32 transaction_id;
   u32 packet_id;
@@ -155,7 +164,6 @@ struct snmp_registration {
   snmp_reg_hook_t reg_hook_fail; /* hook called when OID registration fail */
 };
 
-//void snmp_tx(sock *sk);
 void snmp_startup(struct snmp_proto *p);
 void snmp_connected(sock *sk);
 void snmp_startup_timeout(timer *tm);
index 5b5b770e71fe22f50d400071081f39babdf6cdf8..1223d13527b2727140218df41de83989a97228a4 100644 (file)
@@ -401,7 +401,7 @@ t_oid_compare(void)
 static struct oid *
 snmp_oid_prefixize(struct snmp_proto *p, const struct oid *oid, struct snmp_pdu *c)
 {
-  snmp_vb_to_tx(p, oid, c);
+  snmp_vb_to_tx(c, oid);
   struct agentx_varbind *vb = c->sr_vb_start;
   bt_assert(vb->reserved == 0);
   return &vb->name;
index e3fd96ee070059d60fb6110d4e5494c73e5c892d..bd4263fa5f9d81fede27c84f70b86f55e7c19ced 100644 (file)
@@ -50,7 +50,7 @@ snmp_varbind_data(const struct agentx_varbind *vb)
 }
 
 struct oid *
-snmp_varbind_set_name_len(struct snmp_proto *p, struct agentx_varbind **vb, u8 len, struct snmp_pdu *c)
+snmp_varbind_set_name_len(struct snmp_pdu *c, struct agentx_varbind **vb, u8 len)
 {
   struct oid *oid = &(*vb)->name;
 
@@ -64,10 +64,10 @@ snmp_varbind_set_name_len(struct snmp_proto *p, struct agentx_varbind **vb, u8 l
   /* We need more space */
   ASSUME(len >= LOAD_U8(oid->n_subid));
   uint diff_size = (len - LOAD_U8(oid->n_subid)) * sizeof(u32);
-  if (c->size < diff_size)
+
+  if (snmp_tbuf_reserve(c, diff_size))
   {
     snmp_log("varbind_set_name_len small buffer");
-    snmp_manage_tbuf(p, c);
     oid = &(*vb)->name;
   }
 
@@ -78,15 +78,12 @@ snmp_varbind_set_name_len(struct snmp_proto *p, struct agentx_varbind **vb, u8 l
 }
 
 void
-snmp_varbind_duplicate_hdr(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_pdu *c)
+snmp_varbind_duplicate_hdr(struct snmp_pdu *c, struct agentx_varbind **vb)
 {
   ASSUME(vb != NULL && *vb != NULL);
   uint hdr_size = snmp_varbind_header_size(*vb);
-  if (c->size < hdr_size)
-  {
+  if (snmp_tbuf_reserve(c, hdr_size))
     snmp_log("varbind_duplicate small buffer");
-    snmp_manage_tbuf(p, c);
-  }
 
   ASSERT(c->size >= hdr_size);
   byte *buffer = c->buffer;
@@ -732,7 +729,7 @@ all_same:
 }
 
 struct snmp_registration *
-snmp_registration_create(struct snmp_proto *p, u8 mib_class)
+snmp_registration_create(struct snmp_proto *p, enum agentx_mibs mib)
 {
   struct snmp_registration *r;
   r = mb_alloc(p->p.pool, sizeof(struct snmp_registration));
@@ -743,21 +740,20 @@ snmp_registration_create(struct snmp_proto *p, u8 mib_class)
   /* will be incremented by snmp_session() macro during packet assembly */
   r->transaction_id = p->transaction_id;
   r->packet_id = p->packet_id + 1;
-  snmp_log("using registration packet_id %u", r->packet_id);
-
-  r->mib_class = mib_class;
+  r->mib = mib;
 
+  snmp_log("using registration packet_id %u", r->packet_id);
   add_tail(&p->registration_queue, &r->n);
 
   return r;
 }
 
 int
-snmp_registration_match(struct snmp_registration *r, struct agentx_header *h, u8 class)
+snmp_registration_match(struct snmp_registration *r, struct agentx_header *h, enum agentx_mibs mib)
 {
   snmp_log("snmp_reg_same() r->packet_id %u p->packet_id %u", r->packet_id, h->packet_id);
   return
-    (r->mib_class == class) &&
+    (r->mib == mib) &&
     (r->session_id == h->session_id) &&
     (r->transaction_id == h->transaction_id) &&
     (r->packet_id == h->packet_id);
@@ -1066,7 +1062,7 @@ snmp_walk_init(struct mib_tree *tree, struct mib_walk_state *walk, const struct
 {
   mib_tree_walk_init(walk, tree);
 
-  snmp_vb_to_tx(c->p, oid, c);
+  snmp_vb_to_tx(c, oid);
 
   mib_node_u *node = mib_tree_find(tree, walk, &c->sr_vb_start->name);
 
@@ -1178,11 +1174,8 @@ snmp_walk_fill(struct mib_leaf *leaf, struct mib_walk_state *walk, struct snmp_p
 
   snmp_log("walk_fill got size %u based on lt %u ls %u, calling filler()", size, leaf->type, leaf->size);
 
-  if (size >= c->size)
-  {
-    snmp_log("walk_fill small buffer size %d to %d", size, c->size);
-    snmp_manage_tbuf(c->p, c);
-  }
+  if (snmp_tbuf_reserve(c, size))
+    snmp_log("walk_fill small buffer size");
 
   enum snmp_search_res res = leaf->filler(walk, c);
 
index c4b252e79e3677c5602ce141818a6404c04bf7c3..66fa1d37957d96b439ec19bad3f658e888c789bc 100644 (file)
@@ -54,8 +54,8 @@ uint snmp_varbind_size_unsafe(const struct agentx_varbind *vb);
 size_t snmp_varbind_size_from_len(uint n_subid, enum agentx_type t, uint len);
 int snmp_test_varbind(const struct agentx_varbind *vb);
 void *snmp_varbind_data(const struct agentx_varbind *vb);
-struct oid *snmp_varbind_set_name_len(struct snmp_proto *p, struct agentx_varbind **vb, u8 len, struct snmp_pdu *c);
-void snmp_varbind_duplicate_hdr(struct snmp_proto *p, struct agentx_varbind **vb, struct snmp_pdu *c);
+struct oid *snmp_varbind_set_name_len(struct snmp_pdu *c, struct agentx_varbind **vb, u8 len);
+void snmp_varbind_duplicate_hdr(struct snmp_pdu *c, struct agentx_varbind **vb);
 
 /*
  *  AgentX - PDU headers, types, contexts
@@ -98,8 +98,8 @@ byte *snmp_put_fbyte(byte *buf, u8 data);
  *    Helpers, Misc, Debugging
  *
  */
-struct snmp_registration *snmp_registration_create(struct snmp_proto *p, u8 mib_class);
-int snmp_registration_match(struct snmp_registration *r, struct agentx_header *h, u8 class);
+struct snmp_registration *snmp_registration_create(struct snmp_proto *p, enum agentx_mibs mib);
+int snmp_registration_match(struct snmp_registration *r, struct agentx_header *h, enum agentx_mibs mib);
 
 void snmp_dump_packet(byte *pkt, uint size);
 void snmp_oid_dump(const struct oid *oid);
index b18c37d97b2d0a880580a5ae16a792f218d9f657..1a1adbeffa4f489b5e635ab1b5a68a3d9be97825 100644 (file)
@@ -107,15 +107,17 @@ snmp_blank_header(struct agentx_header *h, enum agentx_pdu_types type)
  * snmp_register_ack - handle registration response
  * @p: SNMP protocol instance
  * @res: header of agentx-Response-PDU
- * @class: MIB subtree associated with agentx-Register-PDU
+ * @mib: MIB subtree identifier
  */
 void
-snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, u8 class)
+snmp_register_ack(struct snmp_proto *p, struct agentx_response *res, const struct oid *oid)
 {
+  enum agentx_mibs mib = agentx_get_mib(oid);
+
   struct snmp_registration *reg;
   WALK_LIST(reg, p->registration_queue)
   {
-    if (snmp_registration_match(reg, &res->h, class))
+    if (snmp_registration_match(reg, &res->h, mib))
     {
       rem_node(&reg->n);
       p->registrations_to_ack--;
@@ -175,12 +177,10 @@ open_pdu(struct snmp_proto *p, struct oid *oid)
 #define TIMEOUT_SIZE sizeof(u32) /* 1B timeout, 3B zero padding */
 
   /* Make sure that we have enough space in TX-buffer */
-  if (c.size < AGENTX_HEADER_SIZE + TIMEOUT_SIZE + snmp_oid_size(oid) +
-      + snmp_str_size(cf->description))
-  {
+  uint s = AGENTX_HEADER_SIZE + TIMEOUT_SIZE + snmp_oid_size(oid) +
+    snmp_str_size(cf->description);
+  if (snmp_tbuf_reserve(&c, s))
     snmp_log("agentx-Open-PDU small buffer");
-    snmp_manage_tbuf(p, &c);
-  }
 
   struct agentx_header *h = (void *) c.buffer;
   ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
@@ -205,7 +205,7 @@ open_pdu(struct snmp_proto *p, struct oid *oid)
   c.buffer = snmp_put_oid(c.buffer, oid);
   c.buffer = snmp_put_str(c.buffer, cf->description);
 
-  uint s = update_packet_size(h, c.buffer);
+  s = update_packet_size(h, c.buffer);
   sk_send(sk, s);
 #undef TIMEOUT_SIZE
 }
@@ -226,8 +226,8 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
   struct snmp_pdu c;
   snmp_pdu_context(&c, p, sk);
 
-#define UPTIME_SIZE sizeof(STATIC_OID(4))
-#define TRAP0_HEADER_SIZE sizeof(STATIC_OID(6))
+#define UPTIME_SIZE sizeof(STATIC_OID(4)) /* see sys_up_time_0 */
+#define TRAP0_HEADER_SIZE sizeof(STATIC_OID(6)) /* see snmp_trap_oid_0 */
 
   uint sz = AGENTX_HEADER_SIZE + TRAP0_HEADER_SIZE + snmp_oid_size(oid) \
     + size;
@@ -236,11 +236,8 @@ snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, in
     sz += UPTIME_SIZE;
 
   /* Make sure that we have enough space in TX-buffer */
-  if (c.size < sz)
-  {
+  if (snmp_tbuf_reserve(&c, sz))
     snmp_log("agentx-Notify-PDU small buffer");
-    snmp_manage_tbuf(p, &c);
-  }
 
   struct agentx_header *h = (void *) c.buffer;
   ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
@@ -334,11 +331,8 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, u32 bound, uint index, en
   uint sz = AGENTX_HEADER_SIZE + snmp_oid_size(oid) +
       ((bound > 1) ? BOUND_SIZE : 0);
 
-  if (c.size < sz)
-  {
+  if (snmp_tbuf_reserve(&c, sz))
     snmp_log("agentx-Register-PDU small buffer");
-    snmp_manage_tbuf(p, &c);
-  }
 
   struct agentx_header *h = (void *) c.buffer;
   ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
@@ -419,11 +413,8 @@ close_pdu(struct snmp_proto *p, enum agentx_close_reasons reason)
   snmp_pdu_context(&c, p, sk);
 
 #define REASON_SIZE sizeof(u32)
-  if (c.size < AGENTX_HEADER_SIZE + REASON_SIZE)
-  {
+  if (snmp_tbuf_reserve(&c, AGENTX_HEADER_SIZE + REASON_SIZE))
     snmp_log("agentx-Close-PDU small buffer");
-    snmp_manage_tbuf(p, &c);
-  }
 
   struct agentx_header *h = (void *) c.buffer;
   ADVANCE(c.buffer, c.size, AGENTX_HEADER_SIZE);
@@ -515,11 +506,8 @@ parse_test_set_pdu(struct snmp_proto *p, byte * const pkt_start)
   struct snmp_pdu c;
   snmp_pdu_context(&c, p, sk);
 
-  if (c.size < AGENTX_HEADER_SIZE)
-  {
+  if (snmp_tbuf_reserve(&c, AGENTX_HEADER_SIZE))
     snmp_log("agentx-TestSet-PDU small buffer");
-    snmp_manage_tbuf(p, &c);
-  }
 
   res = prepare_response(p, &c);
 
@@ -577,11 +565,8 @@ parse_sets_pdu(struct snmp_proto *p, byte * const pkt_start, enum agentx_respons
 
   struct snmp_pdu c;
   snmp_pdu_context(&c, p, p->sock);
-  if (c.size < sizeof(struct agentx_response))
-  {
+  if (snmp_tbuf_reserve(&c, sizeof(struct agentx_response)))
     snmp_log("parse_sets_pdu small buffer");
-    snmp_manage_tbuf(p, &c);
-  }
 
   struct agentx_response *r = prepare_response(p, &c);
 
@@ -820,8 +805,8 @@ parse_response(struct snmp_proto *p, byte *res)
       // TODO more direct path to mib-specific code
       TRACE(D_PACKETS, "SNMP received agentx-Response-PDU with error %u", r->error);
       byte *pkt = res + sizeof(struct agentx_response);
-      struct oid *failed = (void *) pkt;
-      snmp_register_ack(p, r, snmp_get_mib_class(failed));
+      struct oid *failed = (struct oid *) pkt;
+      snmp_register_ack(p, r, failed);
       break;
 
     /*
@@ -867,7 +852,6 @@ do_response(struct snmp_proto *p, byte *pkt)
   struct agentx_response *r = (void *) pkt;
   struct agentx_header *h = (void *) r;
 
-  /* TODO make it asynchronous for better speed */
   switch (p->state)
   {
     case SNMP_INIT:
@@ -891,9 +875,8 @@ do_response(struct snmp_proto *p, byte *pkt)
     case SNMP_REGISTER:;
       pkt += AGENTX_HEADER_SIZE;
 
-      const struct oid *oid = (void *) pkt;
-
-      snmp_register_ack(p, r, snmp_get_mib_class(oid));
+      const struct oid *oid = (struct oid *) pkt;
+      snmp_register_ack(p, r, oid);
 
       if (p->registrations_to_ack == 0)
        snmp_set_state(p, SNMP_CONN);
@@ -910,27 +893,6 @@ do_response(struct snmp_proto *p, byte *pkt)
   }
 }
 
-/*
- * snmp_get_mib_class - classify MIB tree belongings of OID
- * @oid: OID to be classified based on prefix
- */
-u8
-snmp_get_mib_class(const struct oid *oid)
-{
-  // TODO check code paths for oid->n_subid < 3
-  if (oid->prefix != SNMP_MGMT && oid->ids[0] != SNMP_MIB_2)
-    return SNMP_CLASS_INVALID;
-
-  switch (oid->ids[1])
-  {
-    case SNMP_BGP4_MIB:
-      return SNMP_CLASS_BGP;
-
-    default:
-      return SNMP_CLASS_END;
-  }
-}
-
 static inline struct oid *
 snmp_oid_prefixize_unsafe(struct oid *dest, const struct oid *src)
 {
@@ -948,22 +910,18 @@ snmp_oid_prefixize_unsafe(struct oid *dest, const struct oid *src)
 
 /*
  * snmp_vb_to_tx - create varbind from RX buffer OID
- * @p: SNMP protocol instance
- * @oid: object identifier located in RX buffer
  * @c: PDU context
+ * @oid: object identifier located in RX buffer
  *
  * Create NULL initialized VarBind inside TX buffer (from @c) whose vb->name is
  * @oid. The @oid prefixed if possible. The result is stored in @c->sr_vb_start.
  */
 void
-snmp_vb_to_tx(struct snmp_proto *p, const struct oid *oid, struct snmp_pdu *c)
+snmp_vb_to_tx(struct snmp_pdu *c, const struct oid *oid)
 {
   uint vb_hdr_size = snmp_varbind_hdr_size_from_oid(oid);
-  if (c->size < vb_hdr_size)
-  {
+  if (snmp_tbuf_reserve(c, vb_hdr_size))
     snmp_log("SNMP vb_to_tx small buffer");
-    snmp_manage_tbuf(p, c);
-  }
 
   ASSERT(c->size >= vb_hdr_size);
   struct agentx_varbind *vb = (void *) c->buffer;
@@ -1017,7 +975,6 @@ response_err_ind(struct snmp_proto *p, struct agentx_response *res, enum agentx_
 {
   STORE_U32(res->error, (u16) err);
   // TODO deal with auto-incrementing of snmp_pdu context c.ind
-  // FIXME for packets with errors reset reset payload size to null (by move c.buffer appropriately)
   if (err != AGENTX_RES_NO_ERROR && err != AGENTX_RES_GEN_ERROR)
   {
     TRACE(D_PACKETS, "Last PDU resulted in error %u", err);
@@ -1053,6 +1010,8 @@ parse_gets_error(struct snmp_proto *p, struct snmp_pdu *c, uint len)
 /*
  * AgentX GetPDU, GetNextPDU and GetBulkPDU
  */
+
+/* agentx-Get-PDU */
 void
 snmp_get_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start, struct mib_walk_state *walk)
 {
@@ -1072,6 +1031,7 @@ snmp_get_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start
     snmp_set_varbind_type(c->sr_vb_start, snmp_search_res_to_type(res));
 }
 
+/* agentx-GetNext-PDU */
 int
 snmp_get_next_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start, struct mib_walk_state *walk)
 {
@@ -1087,6 +1047,7 @@ snmp_get_next_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_
   return res == SNMP_SEARCH_OK;
 }
 
+/* agentx-GetBulk-PDU */
 void
 snmp_get_bulk_pdu(struct snmp_proto *p, struct snmp_pdu *c, const struct oid *o_start, struct mib_walk_state *walk, struct agentx_bulk_state *bulk)
 {
@@ -1191,7 +1152,6 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
     struct agentx_getbulk *bulk_info = (void *) pkt;
     ADVANCE(pkt, pkt_size, sizeof(struct agentx_getbulk));
 
-    //TODO: bulk_state = AGENTX_BULK_STATE_INITIALIZER(bulk_info);
     bulk_state = (struct agentx_bulk_state) {
       .getbulk = {
        .non_repeaters = LOAD_U32(bulk_info->non_repeaters),
@@ -1247,6 +1207,7 @@ parse_gets_pdu(struct snmp_proto *p, byte * const pkt_start)
 
   if (h->type == AGENTX_GET_BULK_PDU)
   {
+    // TODO: an error for now
   }
 
   /* We update the error, index pair on the beginning of the packet. */
@@ -1404,55 +1365,32 @@ snmp_search_check_end_oid(const struct oid *found, const struct oid *bound)
 }
 
 /*
- * snmp_manage_tbuf - TODO
- */
-void
-snmp_manage_tbuf(struct snmp_proto *p, struct snmp_pdu *c)
-{
-  sock *sk = p->sock;
-  int diff;
-  if (c->sr_vb_start != NULL)
-    diff = (void *) c->sr_vb_start - (void *) sk->tbuf;
-
-  snmp_log("snmp_manage_tbuf2()");
-  sk_set_tbsize(sk, sk->tbsize + 2048);
-  c->size += 2048;
-
-  if (c->sr_vb_start != NULL)
-    c->sr_vb_start = (struct agentx_varbind *) (sk->tbuf + diff);
-}
-
-/*
- * snmp_manage_tbuf2 - handle situation with too short transmit buffer
- * @p: SNMP protocol instance
- * @c: transmit packet context to use
+ * snmp_tbuf_reserve - TODO
  *
- * Important note: After managing insufficient buffer size all in buffer pointers
- *  are invalidated!
  */
-void
-snmp_manage_tbuf2(struct snmp_proto *p, void **ptr, struct snmp_pdu *c)
+int
+snmp_tbuf_reserve(struct snmp_pdu *c, size_t size)
 {
-  sock *sk = p->sock;
-  int diff;
-  if (ptr)
-    diff = *ptr - (void *) sk->tbuf;
+  if (size >= c->size)
+  {
+    struct snmp_proto *p = c->p;
+    sock *sk = p->sock;
 
-  snmp_log("snmp_manage_tbuf()");
-  sk_set_tbsize(sk, sk->tbsize + 2048);
-  c->size += 2048;
+    int diff;
+    if (c->sr_vb_start != NULL)
+      diff = (char *) c->sr_vb_start - (char *) sk->tbuf;
 
-  if (ptr)
-    *ptr = sk->tbuf + diff;
-}
+    snmp_log("snmp_tbuf_reserve()");
+    sk_set_tbsize(sk, sk->tbsize + 2048);
+    c->size += 2048;
 
-void
-snmp_tbuf_reserve(struct snmp_pdu *c, size_t size)
-{
-  if (size > c->size)
-  {
-    snmp_manage_tbuf(c->p, c);
+    if (c->sr_vb_start != NULL)
+      c->sr_vb_start = (struct agentx_varbind *) (sk->tbuf + diff);
+
+    return 1;
   }
+
+  return 0;
 }
 
 /*
index 6696d98c4955add6dbec7d52beb7da2c93c6f2df..234b137a318f80305122559d4b2e259f7aa01b55 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "nest/bird.h"
 #include "snmp.h"
+#include "lib/macro.h"
 
 void snmp_start_subagent(struct snmp_proto *p);
 void snmp_stop_subagent(struct snmp_proto *p);
@@ -43,13 +44,6 @@ extern const u32 snmp_internet[4];
 
 #define SNMP_DEFAULT_CONTEXT 0
 
-enum SNMP_CLASSES {
-  SNMP_CLASS_INVALID = 0,
-  SNMP_CLASS_BGP = 1,
-  SNMP_CLASS_OSPF,
-  SNMP_CLASS_END,
-};
-
 enum agentx_type {
   AGENTX_INTEGER           =   2,
   AGENTX_OCTET_STRING      =   4,
@@ -75,8 +69,6 @@ enum snmp_search_res {
   SNMP_SEARCH_END_OF_VIEW = 3,
 };
 
-#define AGENTX_ADMIN_STOP   1
-#define AGENTX_ADMIN_START  2
 
 #define AGENTX_PRIORITY                127
 
@@ -116,12 +108,17 @@ enum agentx_flags {
 #define SNMP_ORDER 0
 #endif
 
+/* We recommend using STORE_U32 over VALUE_U32 when possible */
 #ifdef SNMP_NATIVE
-#define STORE_U32(dest, val)  ((dest) = (u32) (val))
-#define STORE_U16(dest, val)  ((dest) = (u16) (val))
-#define STORE_U8(dest, val)   ((dest) = (u8) (val))
+#define STORE_U32(dest, val)  ((u32) ((dest) = (u32) (val)))
+#define STORE_U16(dest, val)  ((u16) ((dest) = (u16) (val)))
+#define STORE_U8(dest, val)   ((u8) ((dest) = (u8) (val)))
 #define STORE_PTR(ptr, val)   (*((u32 *) (ptr)) = (u32) (val))
 
+#define VALUE_U32(val)       ((u32) (val))
+#define VALUE_U16(val)       ((u16) (val))
+#define VALUE_U8(val)        ((u8) (val))
+
 #define LOAD_U32(src)        *((u32 *) &(src))
 #define LOAD_U16(src)        *((u16 *) &(src))
 #define LOAD_U8(src)         *((u8 *) &(src))
@@ -134,6 +131,11 @@ enum agentx_flags {
 #define STORE_U8(dest, val)   put_u8(&(dest), (val))
 #define STORE_PTR(ptr, val)   put_u32(ptr, val)
 
+#define VALUE_U32(val)       htonl(val)
+#define VALUE_U16(val)       htons(val)
+#define VALUE_U8(val)        ((u8) (val))
+
+
 #define LOAD_U32(src)        get_u32(&(src))
 #define LOAD_U16(src)        get_u16(&(src))
 #define LOAD_U8(src)         get_u8(&(src))
@@ -192,6 +194,16 @@ struct oid {
     u32 ids[sbids];                                                          \
   }
 
+#define VALUE_U32_HELPER(x) VALUE_U32(x),
+#define STATIC_OID_INITIALIZER(sbids, pref, ...)                             \
+  {                                                                          \
+    .n_subid = VALUE_U8(sbids),                                                      \
+    .prefix = VALUE_U8(pref),                                                \
+    .include = VALUE_U8(0),                                                  \
+    .reserved = VALUE_U8(0),                                                 \
+    .ids = { MACRO_FOREACH(VALUE_U32_HELPER, __VA_ARGS__) },                 \
+  }
+
 /* enforced by MIB tree, see mib_tree.h for more info */
 #define OID_MAX_LEN 32
 
@@ -319,7 +331,8 @@ enum agentx_response_errs {
 /* SNMP PDU info */
 struct snmp_pdu {
   struct snmp_proto *p;
- /* TX buffer */
+
+  /* TX buffer */
   byte *buffer;                            /* pointer to buffer */
   uint size;                       /* unused space in buffer */
 
@@ -348,9 +361,9 @@ void snmp_register(struct snmp_proto *p, struct oid *oid, uint index, uint len,
 void snmp_unregister(struct snmp_proto *p, struct oid *oid, uint index, uint len, uint contid);
 void snmp_notify_pdu(struct snmp_proto *p, struct oid *oid, void *data, uint size, int include_uptime);
 
-void snmp_manage_tbuf(struct snmp_proto *p, struct snmp_pdu *c);
+int snmp_tbuf_reserve(struct snmp_pdu *c, size_t bytes);
 
-void snmp_vb_to_tx(struct snmp_proto *p, const struct oid *oid, struct snmp_pdu *c);
+void snmp_vb_to_tx(struct snmp_pdu *c, const struct oid *oid);
 u8 snmp_get_mib_class(const struct oid *oid);
 
 void snmp_register_mibs(struct snmp_proto *p);
@@ -358,7 +371,6 @@ void snmp_register_mibs(struct snmp_proto *p);
 /* MIB modules */
 void snmp_bgp4_start(struct snmp_proto *p);
 
-
 #if 1
 #define snmp_log(...) log(L_INFO "SNMP " __VA_ARGS__)
 #else