]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
TMP: compiles and runs
authorVojtech Vilimek <vojtech.vilimek@nic.cz>
Fri, 30 Sep 2022 07:36:09 +0000 (09:36 +0200)
committerVojtech Vilimek <vojtech.vilimek@nic.cz>
Fri, 30 Sep 2022 07:36:09 +0000 (09:36 +0200)
lib/ip.h
proto/snmp/Makefile
proto/snmp/bgp_mib.c
proto/snmp/bgp_mib.h
proto/snmp/config.Y
proto/snmp/snmp.c
proto/snmp/snmp.h
proto/snmp/subagent.c

index 20e7a33633bd12373eaf64eda0eac2ca435c0ea4..73083ac991cb5f8354e0eb5d9ff5649df7d41d21 100644 (file)
--- a/lib/ip.h
+++ b/lib/ip.h
@@ -145,6 +145,9 @@ static inline ip4_addr ip4_xor(ip4_addr a, ip4_addr b)
 static inline ip4_addr ip4_not(ip4_addr a)
 { return _MI4(~_I(a)); }
 
+static inline int ip4_less(ip4_addr a, ip4_addr b)
+{ return _I(a) < _I(b); }
+
 
 static inline int ip6_equal(ip6_addr a, ip6_addr b)
 { return _I0(a) == _I0(b) && _I1(a) == _I1(b) && _I2(a) == _I2(b) && _I3(a) == _I3(b); }
index b80cb135a4a82482c5b2bf2dc907371638bc6e3d..0965e4488d86f918db89d6b61c6e3f7afbb2915b 100644 (file)
@@ -1,4 +1,4 @@
-src := snmp.c subagent.c
+src := snmp.c subagent.c bgp_mib.c
 obj := $(src-o-files)
 $(all-daemon)
 $(cf-local)
index f3d2de5b361c6e953ee5cfc3aaf9c9cbacdf15e0..9318d620ce1ebc9de94a996dd8ab227d2d04595d 100644 (file)
 #undef PACKAGE_TARNAME
 #undef PACKAGE_VERSION
 
-#include "bgp_mib.h"
 #include "snmp.h"
+#include "subagent.h"
+#include "bgp_mib.h"
 
 void
 snmp_bgp_register()
 {}
 
-static inline int
-is_bgp_peer_entry(struct oid *o)
-{
-  if (o->ids[2] == BGP4_PEER_ENTRY &&
-      o->ids[3] > 0 &&
-      /* do not include bgpPeerInUpdatesElapsedTime
-         and bgpPeerFsmEstablishedTime */
-      o->ids[3] < SNMP_BGP_IN_UPDATE_ELAPSED_TIME &&
-      o->ids[3] != SNMP_BGP_FSM_ESTABLISHED_TIME)
-    return 1;
-  else
-    return 0;
-}
-
 int
 snmp_bgp_is_supported(struct oid *o)
 {
-  if (o->prefix == 2 && o->ids[0] == 1)
+  if (o->prefix == 2 && o->n_subid > 0 && o->ids[0] == 1)
   {
-    if (o->ids[1] == BGP4_MIB_VERSION ||
-        o->ids == BGP4_MIB_LOCAL_AS)
+    if (o->n_subid == 2 && o->ids[1] == BGP4_MIB_VERSION ||
+        o->ids[1] == BGP4_MIB_LOCAL_AS)
       return 1;
-    else if (o->ids[1] == BGP4_PEER_TABLE)
-      return is_bgp_peer_entry(o)
+    else if (o->n_subid > 2 && o->ids[1] == BGP4_PEER_TABLE &&
+             o->ids[2] == BGP4_PEER_ENTRY)
+    {
+       if (o->n_subid == 3)
+         return 1;
+       if (o->n_subid == 8 &&
+           o->ids[3] > 0 &&
+           /* do not include bgpPeerInUpdatesElapsedTime
+              and bgpPeerFsmEstablishedTime */
+           o->ids[3] < SNMP_BGP_IN_UPDATE_ELAPSED_TIME &&
+           o->ids[3] != SNMP_BGP_FSM_ESTABLISHED_TIME)
+             return 1;
+    }
     else
       return 0;
   }
   else
     return 0;
 }
-
index 6c538b63936c3ac42ae3eb8fbf153e77a42be327..5854bcf40d494a65d725b52772f4a2dbcef441df 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _BIRD_SNMP_BGP_MIB_H_
 #define _BIRD_SNMP_BGP_MIB_H_
 
+#include "snmp.h"
+
 /* peers attributes */
 enum BGP4_MIB {
   SNMP_BGP_IDENTIFIER              =  1,
index 33f653427cd77d096221afa4f3853bc236261d6f..bed169676d8d69cfcda74f666e4db528558318da 100644 (file)
@@ -43,6 +43,7 @@ snmp_proto_start: proto_start SNMP
   this_proto = proto_config_new(&proto_snmp, $1);
 
   init_list(&SNMP_CFG->bgp_entries);
+  SNMP_CFG->bonds = 0;
 
   SNMP_CFG->local_ip = IPA_NONE;
   SNMP_CFG->remote_ip = ipa_build4(127,0,0,1);
@@ -61,14 +62,12 @@ snmp_bgp_bond: BGP symbol
   struct snmp_bond *this_bond = cfg_alloc(sizeof(struct snmp_bond));
   this_bond->type = SNMP_BGP;
 
-  struct proto_config *pc;
-  WALK_LIST(pc, this_proto->global->protos)
-    if (!strcmp(pc->name, $2->name) && pc->protocol == &proto_bgp
-        && !ipa_zero(((struct bgp_proto *) pc)->remote_ip)) 
-      this_bond->proto = pc;
+  cf_assert_symbol($2, SYM_PROTO);
+  this_bond->proto = $2->proto;
 
   if (!this_bond->proto) cf_error("BGP protocol %s not found", $2->name);
-  add_tail(&SNMP_CFG->bgp_entries, (node *) this_bond);
+  add_tail(&SNMP_CFG->bgp_entries, NODE this_bond);
+  SNMP_CFG->bonds++;
 }
 
 CF_CODE
index 587921a84a859ee8840a2bff5ff4429d2b3cd248..ee8dd6f731899ea280efb4a8ecb2d343ffba4bc2 100644 (file)
@@ -22,7 +22,9 @@
 static void snmp_connected(sock *sk);
 static void snmp_sock_err(sock *sk, int err);
 static void snmp_ping_timer(struct timer *tm);
-static void snmp_retry_timer(struct timer *tm);
+static void snmp_startup(struct snmp_proto *p);
+static void snmp_startup_timeout(timer *t);
+static void snmp_start_locked(struct object_lock *lock);
 
 static struct proto *
 snmp_init(struct proto_config *CF)
@@ -48,6 +50,31 @@ snmp_init(struct proto_config *CF)
   return P;
 }
 
+static void
+snmp_startup_timeout(timer *t)
+{
+  snmp_startup(t->data);
+}
+
+static void
+snmp_startup(struct snmp_proto *p)
+{
+  /* starting agentX communicaiton channel */
+  log(L_INFO "preparing lock");
+  struct object_lock *lock;
+  lock = p->lock = olock_new(p->p.pool);
+
+  lock->type = OBJLOCK_TCP;
+  lock->hook = snmp_start_locked;
+  lock->data = p;
+
+  olock_acquire(lock);
+  log(L_INFO "lock acquiring");
+
+  log(L_INFO "local ip: %I:%u, remote ip: %I:%u",
+    p->local_ip, p->local_port, p->remote_ip, p->remote_port);
+}
+
 static void
 snmp_start_locked(struct object_lock *lock)
 {
@@ -61,7 +88,7 @@ snmp_start_locked(struct object_lock *lock)
   s->dport = p->remote_port;
   s->rbsize = SNMP_RX_BUFFER_SIZE;
   s->tbsize = SNMP_TX_BUFFER_SIZE;
-  
+
   //s->tos = IP_PREC_INTERNET_CONTROL
   //s->rx_hook = snmp_connected;
   s->tx_hook = snmp_connected;
@@ -70,9 +97,14 @@ snmp_start_locked(struct object_lock *lock)
   p->sock = s;
   s->data = p;
 
-  if (sk_open(s) < 0) 
+  p->to_send = 0;
+  p->errs = 0;
+
+  snmp_startup(p);
+
+  if (sk_open(s) < 0)
     log(L_ERR "Cannot open listening socket");
-  
+
   log(L_INFO "socket ready!, trying to connect");
 }
 
@@ -97,17 +129,18 @@ snmp_connected(sock *sk)
 }
 
 static void
-snmp_sock_err(sock *sk UNUSED, int err UNUSED)
+snmp_sock_err(sock *sk, int err)
 {
   log(L_INFO "snmp_sock_err() %s - err no: %d",  strerror(err), err);
 
   struct snmp_proto *p = sk->data;
+  tm_stop(p->ping_timer);
 
-  p->state = SNMP_ERR;
-  if (p->p.proto_state == PS_UP)
-    proto_notify_state(&p->p, PS_START);
+  rfree(p->sock);
+  p->sock = NULL;
 
-  tm_set(p->retry_timer, current_time() + 5 S);
+  p->state = SNMP_ERR;
+  tm_start(p->startup_timer, 15 S);
 }
 
 static int
@@ -117,10 +150,17 @@ snmp_start(struct proto *P)
   struct snmp_proto *p = (void *) P;
   struct snmp_config *cf = (struct snmp_config *) P->cf;
 
+  p->startup_timer = tm_new_init(p->p.pool, snmp_startup_timeout, p, 0, 0);
+
+  p->to_send = 0;
+  p->errs = 0;
+
+  p->pool = lp_new(p->p.pool);
+  p->bgp_trie = f_new_trie(p->pool, cf->bonds);
+
   p->ping_timer = tm_new_init(p->p.pool, snmp_ping_timer, p, 0, 0);
   tm_set(p->ping_timer, current_time() + 2 S);
 
-  p->retry_timer = tm_new_init(p->p.pool, snmp_retry_timer, p, 0, 0);
 
   /* starting agentX communicaiton channel */
   log(L_INFO "preparing lock");
@@ -137,12 +177,10 @@ snmp_start(struct proto *P)
   log(L_INFO "local ip: %I:%u, remote ip: %I:%u",
     p->local_ip, p->local_port, p->remote_ip, p->remote_port);
 
-  init_list(&p->bgp_entries);
-
   /* create copy of bonds to bgp */
   HASH_INIT(p->bgp_hash, p->p.pool, 10);
 
-  struct snmp_bond *b, *b2;
+  struct snmp_bond *b;
   WALK_LIST(b, cf->bgp_entries)
   {
     struct bgp_config *bc = (struct bgp_config *) b->proto;
@@ -150,20 +188,19 @@ snmp_start(struct proto *P)
     {
       struct snmp_bgp_peer *peer =
        mb_allocz(p->p.pool, sizeof(struct snmp_bgp_peer));
-      peer->bond = b;
+      peer->config = (struct bgp_config *) b->proto;
       peer->peer_ip = bc->remote_ip;
 
+      struct net_addr *net = mb_allocz(p->p.pool, sizeof(struct net_addr));
+      net_fill_ip4(net, ipa_to_ip4(peer->peer_ip), IP4_MAX_PREFIX_LENGTH);
+
+      trie_add_prefix(p->bgp_trie, net, IP4_MAX_PREFIX_LENGTH, IP4_MAX_PREFIX_LENGTH);
+
       HASH_INSERT(p->bgp_hash, SNMP_HASH, peer);
-       
-      b2 = mb_allocz(p->p.pool, sizeof(struct snmp_bond));
-      b2->proto = b->proto;
-      b2->type = b->type;
-      add_tail(&p->bgp_entries, NODE b2);
-      mb_free(peer);
     }
   }
-   
-  return PS_START; 
+
+  return PS_START;
 }
 
 static int
@@ -183,8 +220,9 @@ snmp_reconfigure(struct proto *P, struct proto_config *CF)
     to update HASH table */
   log(L_INFO "snmp_reconfigure() lip: %I:%u rip: %I:%u",
     p->local_ip, p->local_port, p->remote_ip, p->remote_port);
-  return PS_START;
+  return 1;
 }
+
 static void snmp_show_proto_info(struct proto *P)
 {
   //struct snmp_proto *sp = (void *) P;
@@ -263,37 +301,15 @@ static void
 snmp_ping_timer(struct timer *tm)
 {
   log(L_INFO "snmp_ping_timer() ");
-  struct snmp_proto *p = tm->data;  
+  struct snmp_proto *p = tm->data;
 
   if (p->state == SNMP_CONN)
   {
     snmp_ping(p);
   }
 
-  //tm_set(tm, current_time() + (7 S_));
-}
-
-static void
-snmp_retry_timer(struct timer *tm)
-{
-  log(L_INFO "snmp_retry_timer()");
-
-  struct snmp_proto *p = tm->data;
-
-  /* starting agentX communicaiton channel */
-  log(L_INFO "preparing lock");
-  struct object_lock *lock;
-  lock = p->lock = olock_new(p->p.pool);
-
-  lock->type = OBJLOCK_TCP;
-  lock->hook = snmp_start_locked;
-  lock->data = p;
-
-  olock_acquire(lock);
-  log(L_INFO "lock acquired");
-
-  log(L_INFO "local ip: %I:%u, remote ip: %I:%u",
-    p->local_ip, p->local_port, p->remote_ip, p->remote_port);
+  //tm_set(tm, current_time() + (15 S));
+  tm_set(tm, current_time() + 15 S);
 }
 
 static int
@@ -303,7 +319,7 @@ snmp_shutdown(struct proto *P)
   p->state = SNMP_INIT;
 
   tm_stop(p->ping_timer);
-  tm_stop(p->retry_timer);
+  tm_stop(p->startup_timer);
 
   snmp_stop_subagent(p);
   return PS_DOWN;
index baf643c30831ee710dd19a4c78a655c5e6b340b4..ac2f01d6e7d11ea7a35462a89c00da26b39e2506 100644 (file)
@@ -15,6 +15,7 @@
 #include "lib/timer.h"
 #include "nest/bird.h"
 #include "nest/protocol.h"
+#include "filter/data.h"
 #include "proto/bgp/bgp.h"
 
 
 #define SNMP_RX_BUFFER_SIZE 2048
 #define SNMP_TX_BUFFER_SIZE 2048
 
-#define SNMP_INIT 1
-#define SNMP_REGISTR 2
-#define SNMP_CONN 3
-#define SNMP_ERR 4
-
-#define SNMP_OFF 0
-
+#define SNMP_ERR 0
+#define SNMP_DELAY 1
+#define SNMP_INIT 2
+#define SNMP_REGISTR 3
+#define SNMP_CONN 4
 
 /* hash table macros */
 #define SNMP_HASH_KEY(n)  n->peer_ip
 #define SNMP_HASH_EQ(ip1, ip2) ipa_equal(ip1, ip2)
 #define SNMP_HASH_FN(ip)  ipa_hash(ip)
 
+#define SNMP_HASH_LESS4(ip1, ip2) ip4_less(ip1, ip2)
+#define SNMP_HASH_LESS6(ip1, ip2) ip6_less(ip1, ip2)
+
+/* hash table only store ip4 addresses */
+#define SNMP_HASH_LESS(ip1, ip2) SNMP_HASH_LESS4(ip1,ip2)
+
 struct snmp_bond {
   node n;
   struct proto_config *proto;
@@ -58,10 +63,11 @@ struct snmp_config {
   u8 timeout;
   //struct iface *iface;
   list bgp_entries;
+  u32 bonds;
 };
 
 struct snmp_bgp_peer {
-  struct snmp_bond *bond;
+  struct bgp_config *config;
   ip_addr peer_ip;
   struct snmp_bgp_peer *next;
 };
@@ -69,7 +75,8 @@ struct snmp_bgp_peer {
 struct snmp_proto {
   struct proto p;
   struct object_lock *lock;
+  struct linpool *pool;
+
   ip_addr local_ip;
   ip_addr remote_ip;
   u16 local_port;
@@ -85,27 +92,18 @@ struct snmp_proto {
 
   //struct iface *iface;
   // map goes here
+  struct f_trie *bgp_trie;
   HASH(struct snmp_bgp_peer) bgp_hash;
   struct tbf rl_gen;
 
   timer *ping_timer;
-  timer *retry_timer;
-  u8 state;
-
-  list bgp_entries;
-};
 
-/*
-struct snmp_channel_config {
-  struct channel_config c;
-  struct bgp_config *bgp;
-  u8 type;
-};
+  uint startup_delay;
+  timer *startup_timer;
+  u8 state;
 
-struct snmp_channel {
-  struct channel c;
+  uint to_send;
+  uint errs;
 };
-*/
-
 
 #endif
index ca84e3f8362e3272c605f81465ac8820ba1fe8dd..475e6fe5c14aa1b5c5954218af2bdf0c347de7d7 100644 (file)
@@ -16,7 +16,7 @@
  *  Problems
  *  ------------------------------------------------------------
  *
- *    change of remote ip -> no notification, no update 
+ *    change of remote ip -> no notification, no update
  *    same ip, different ports
  *    distinct VRF (two interfaces with overlapping private addrs)
  *    posible link-local addresses in LOCAL_IP
  */
 
 static int parse_response(struct snmp_proto *p, byte *buf, uint size);
-static void header_update_len(byte *buf, u32 len);
 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);
-static int parse_get_pdu(struct snmp_proto *p, byte *buf, uint size);
-static int parse_gets_pdu(struct snmp_proto *p, byte *buf, uint size);
-//static void response_fail(struct snmp_proto *p, u16 err_no, u16 index);
+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 oid *o_start, struct oid *o_end, struct oid *o_curr);
+static struct oid *bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, struct oid *o_curr);
 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
@@ -132,8 +131,17 @@ put_oid(byte *buf, struct oid *oid)
   return buf + (oid->n_subid << 2);
 }
 
+static void
+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 
+/* paste data at first byte in message
  *   with 3B of padding
  */
 static byte *
@@ -179,11 +187,11 @@ open_pdu(struct snmp_proto *p, struct oid *oid)
     int ret = sk_send(sk, pkt - buf);
 
     if (ret == 0)
-      log(L_INFO "sleep");
+      log(L_INFO "sk_send sleep");
     else if (ret < 0)
-      log(L_INFO "err %d", ret);
+      log(L_INFO "sk_send err %d", ret);
     else
-      log(L_INFO "ok !!! ");
+      log(L_INFO "sk_send ok !!! ");
   }
 
   else
@@ -266,11 +274,11 @@ un_register_pdu(struct snmp_proto *p, struct oid *oid, uint index, uint len, u8
     int ret = sk_send(sk, pkt - buf);
 
     if (ret == 0)
-      log(L_INFO "sleep");
+      log(L_INFO "sk_send sleep");
     else if (ret < 0)
-      log(L_INFO "err %d", ret);
+      log(L_INFO "sk_send err %d", ret);
     else
-      log(L_INFO "ok !!");
+      log(L_INFO "sk_send ok !!");
   }
 
   else
@@ -286,7 +294,7 @@ snmp_register(struct snmp_proto *p, struct oid *oid, uint index, uint len)
 
 
 /* unregister pdu */
-static void
+static void UNUSED
 snmp_unregister(struct snmp_proto *p, struct oid *oid, uint index, uint len)
 {
   un_register_pdu(p, oid, index, len, AGENTX_UNREGISTER_PDU);
@@ -319,11 +327,11 @@ close_pdu(struct snmp_proto *p, u8 reason)
     int ret = sk_send(sk, pkt - buf);
 
     if (ret == 0)
-      log(L_INFO "sleep");
+      log(L_INFO "sk_send sleep");
     else if (ret < 0)
-      log(L_INFO "err");
-    else 
-      log(L_INFO, "ok !!");
+      log(L_INFO "sk_send err");
+    else
+      log(L_INFO, "sk_send ok !!");
   }
 }
 
@@ -341,6 +349,7 @@ parse_pkt(struct snmp_proto *p, byte *buf, uint size)
   if (size < AGENTX_HEADER_SIZE)
     return 0;
 
+  uint len = 0;
   struct agentx_header *h = (void *) buf;
   log(L_INFO "parse_pkt got type %u", h->type);
   switch (h->type)
@@ -356,13 +365,33 @@ parse_pkt(struct snmp_proto *p, byte *buf, uint size)
 
     case AGENTX_GET_PDU:
     case AGENTX_GET_NEXT_PDU:
+    case AGENTX_GET_BULK_PDU:
       refresh_ids(p, h);
-      return parse_gets_pdu(p, buf, size);
+      len = parse_gets_pdu(p, buf, size);
+      break;
 
     /* should not happen */
     default:
       die("unknown packet type %u", h->type);
   }
+
+  log(L_INFO "parsed, sending ... to addr %I:%u -> %I:%u",
+    p->sock->saddr, p->sock->sport, p->sock->daddr, p->sock->dport);
+  if (len && p->state != SNMP_ERR)
+  {
+    p->to_send = len;
+    int ret = sk_send(p->sock, len);
+    log(L_INFO "message sent");
+
+    if (ret == 0)
+      log(L_INFO "sk_send sleep");
+    else if (ret < 0)
+      log(L_INFO "sk_send err no: %d '%s'", ret, strerror(ret));
+    else
+      log("sk_send OK ! !!");
+  }
+
+  return len;
 }
 
 static int
@@ -448,6 +477,24 @@ do_response(struct snmp_proto *p, byte *buf, uint size UNUSED)
       // register first line in BGP4-MIB bgpPeerTable
       // TODO register all bind bgp connections
       snmp_register(p, o2, 9, 24);
+
+      log(L_INFO "before hash walk");
+      HASH_WALK(p->bgp_hash, next, peer)
+      {
+       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,
+         o2->prefix, o2->include);
+       for (int i = 0; i < o2->n_subid; i++)
+         log(L_INFO "%d: %u", i, o2->ids[i]);
+       log(L_INFO "");
+
+       snmp_register(p, o2, 9, 24);
+      }
+      HASH_WALK_END;
+      log(L_INFO "after hash walk");
+
       mb_free(o2);
 
       p->state = SNMP_REGISTR;
@@ -466,7 +513,7 @@ do_response(struct snmp_proto *p, byte *buf, uint size UNUSED)
   }
 }
 
-static int
+static uint UNUSED
 parse_get_pdu(struct snmp_proto *p, byte *buf, uint size)
 {
   log(L_INFO "parse_get_pdu()");
@@ -548,23 +595,23 @@ parse_get_pdu(struct snmp_proto *p, byte *buf, uint size)
   log(L_INFO "res->payload %u (loaded) %u, trying to send: %u",
     rh->payload, LOAD(rh->payload, rh->flags & AGENTX_NETWORK_BYTE_ORDER),
     res_pkt - res + 4);
-   
+
   int ret = sk_send(sk, res_pkt - res);
   log(L_INFO "message sent");
 
   if (ret == 0)
-    log(L_INFO "sleep");
+    log(L_INFO "sk_send sleep");
   else if (ret < 0)
-    log(L_INFO "err no: %d", ret);
+    log(L_INFO "sk_send err no: %d", ret);
   else
-    log(L_INFO "OK !!");
+    log(L_INFO "sk_send OK !!");
 
   return 1;
 }
 
 
 /* req is request */
-static int
+static uint
 parse_gets_pdu(struct snmp_proto *p, byte *req, uint size)
 {
   log(L_INFO "parse_gets_pdu");
@@ -605,22 +652,26 @@ parse_gets_pdu(struct snmp_proto *p, byte *req, uint size)
     /* advertised size of oid is greater then size of message */
     if (oid_size(o_start) > size || oid_size(o_end) > size)
     {
-      err = -1;  /* parse error too big n_subid */
+      log(L_INFO "too big o_start or o_end");
+      err = -1;  /* parse error too big n_subid (greater than message) */
       continue;
     }
 
     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);
        break;
 
       case AGENTX_GET_NEXT_PDU:
-       o_start = bgp_search(o_start, o_end, NULL);
+       log(L_INFO "type GetNext-PDU");
+       o_start = bgp_search(p, o_start, o_end, NULL);
        if (o_start)
          res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
        else
        {
+         log(L_INFO "null o_start GetNext-PDU");
          err = -2;
          continue;
        }
@@ -628,16 +679,18 @@ 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(o_start, o_end, o_curr)) != NULL)
+       while ((o_curr = bgp_search(p, o_start, o_end, o_curr)) != NULL)
        {
-         res_pkt = find_n_fill(p, o_start, res_pkt, rsize, 0, byte_ord);
+         res_pkt = find_n_fill(p, o_curr, res_pkt, rsize, 0, byte_ord);
        }
 
        /* no item found */
        if (res_pkt == res + sizeof(struct agentx_response))
        {
+         log(L_INFO "no item found ");
          err = -2;
          continue;
        }
@@ -665,32 +718,17 @@ parse_gets_pdu(struct snmp_proto *p, byte *req, uint size)
       break;
   }
 
+  log(L_INFO " pasting size");
   struct agentx_header *rh = (void *) res;
   SNMP_UPDATE(rh, pkt_len(res, res_pkt));
 
-  int ret = sk_send(sk, res_pkt - res);
-  log(L_INFO "message sent");
-
-  if (ret == 0)
-    log(L_INFO "sleep");
-  else if (ret < 0)
-    log(L_INFO "err no: %d", ret);
-  else
-    log("OK ! !!");
-
-  return err;
-}
-
+  log(L_INFO "%p %lu", p->sock->ttx, res_pkt - res);
+  log(L_INFO "%p %p", res_pkt, res);
 
-static void
-header_update_len(byte *buf, u32 len)
-{
-  struct agentx_header *h = (void *) buf;
-  put_u32(&h->payload, len);
-  log(L_INFO "header_update_len() %d 0x%02X 0x%02X 0x%02X 0x%02X", len, *((unsigned char
-*) &h->payload), *(((unsigned char *) &h->payload) + 1), *(((unsigned char *)
-&h->payload) + 2), *(((unsigned char *) &h->payload) + 3));
+  for (int i = 0; i < res_pkt - res; i++)
+    log(L_INFO "%p: %02X", res + i, *(res + i));
 
+  return res_pkt - res;
 }
 
 void
@@ -702,7 +740,6 @@ snmp_start_subagent(struct snmp_proto *p)
   struct oid *o = mb_allocz(p->p.pool, sizeof(struct oid));
   open_pdu(p, o);
   mb_free(o);
-
 }
 
 void
@@ -719,6 +756,7 @@ snmp_stop_subagent(struct snmp_proto *p)
   }
 }
 
+/* return number of bytes used  by @o */
 static inline uint
 oid_size(struct oid *o)
 {
@@ -726,6 +764,7 @@ oid_size(struct oid *o)
   return 4 + (o->n_subid << 2);
 }
 
+/* return number of bytes used by @vb */
 static inline uint
 vb_size(struct agentx_varbind *vb)
 {
@@ -735,27 +774,27 @@ vb_size(struct agentx_varbind *vb)
 
 int
 snmp_rx(sock *sk, uint size)
-{ 
+{
   log(L_INFO "snmp_rx()");
   struct snmp_proto *p = sk->data;
   byte *pkt = sk->rbuf;
 
   // 1 means all done; 0 means to be continued
   return parse_pkt(p, pkt, size);
-  /* 
+  /*
   while (end >= pkt + AGENTX_HEADER_SIZE)
   {
     parse_header(p);
     parse_pkt(p, );
   }
-  */ 
+  */
 }
 
 /* ping pdu */
 void
 snmp_ping(struct snmp_proto *p)
 {
-  /* this does not support non-default context */ 
+  /* this does not support non-default context */
   sock *sk = p->sock;
   byte *pkt = sk->tbuf;
   uint size = sk->tbsize;
@@ -771,12 +810,13 @@ snmp_ping(struct snmp_proto *p)
 
     /* sending only header => pkt - buf */
     int ret = sk_send(sk, AGENTX_HEADER_SIZE);
+
     if (ret == 0)
-      log(L_INFO "sleep");
+      log(L_INFO "sk_send sleep");
     else if (ret < 0)
-      log(L_INFO "err %d", ret);
+      log(L_INFO "sk_send err %d", ret);
     else
-      log("ok ! !");
+      log("sk_send ok ! !");
   }
 
   else
@@ -812,48 +852,129 @@ snmp_agent_reconfigure(void)
 {
 
 }
-*/
 
 static int
 compare(struct oid *left, struct oid *right)
 {
+  const u32 INTERNET_PREFIX[] = {1, 3, 6, 1};
+
+  if (left->prefix == 0 && right->prefix == 0)
+    goto test_ids;
+
+  if (right->prefix == 0)
+  {
+    struct oid *temp = left;
+    left = right;
+    right = temp;
+  }
+
+  if (left->prefix == 0)
+  {
+    for (int i = 0; i < 4; i++)
+      if (left->ids[i] < INTERNET_PREFIX[i])
+       return -1;
+      else if (left->ids[i] > INTERNET_PREFIX[i])
+       return 1;
+
+    for (int i = 0; i < MIN(left->n_subid - 4, right->n_subid); i++)
+      if (left->ids[i + 4] < right->ids[i])
+       return -1;
+      else if (left->ids[i + 4] > right->ids[i])
+       return 1;
+
+    goto all_same;
+  }
+
   if (left->prefix < right->prefix)
     return -1;
-
   else if (left->prefix > right->prefix)
     return 1;
 
+test_ids:
   for (int i = 0; i < MIN(left->n_subid, right->n_subid); i++)
-  {
     if (left->ids[i] < right->ids[i])
       return -1;
     else if (left->ids[i] > right->ids[i])
       return 1;
-  }
-  return 0;
+
+all_same:
+  / * shorter sequence is before longer in lexicografical order * /
+  if (left->n_subid < right->n_subid)
+    return -1;
+  else if (left->n_subid > right->n_subid)
+    return 1;
+  else
+    return 0;
 }
 
+*/
+
 static inline int
 is_bgp4_mib_prefix(struct oid *o)
 {
   if (o->prefix == 2 && o->ids[0] == 15)
-    return 1; 
+    return 1;
   else
     return 0;
 }
 
+static inline int
+has_inet_prefix(struct oid *o)
+{
+  return (o->n_subid > 4 && o->ids[0] == 1 &&
+         o->ids[1] == 3 && o->ids[2] == 6 &&
+         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 */
 static struct oid *
-bgp_search(struct oid *o_start, struct oid *e_end, struct oid *o_curr)
+bgp_search(struct snmp_proto *p, struct oid *o_start, struct oid *o_end, struct oid *o_curr)
 {
-  if (o_start->include);
-    // if valid o_start
+  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 "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");
 
-  // search o_start.0 (resp. o_start.1)
-  return o_start;
+  if (o_curr)
+    net_fill_ip4(net, dest, IP4_MAX_PREFIX_LENGTH);
+
+  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_start, oid_size(o_start));
+    oid_ip4_index(o, net4_prefix(net));
+    return o;
+  }
+  else
+    return NULL;
 }
 
 static byte *
-find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt,  uint size, uint contid)
+find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt, uint size UNUSED, uint contid UNUSED)
 {
   struct bgp_conn *b_conn = bp->conn;
   struct bgp_conn *b_in = &bp->incoming_conn;
@@ -868,16 +989,16 @@ find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt,  uint size, uint co
     b_state = b_conn->state;
   else if (MAX(b_in->state, b_out->state) == BS_CLOSE &&
     MIN(b_in->state, b_out->state) != BS_CLOSE)
-    b_state = MIN(b_in->state, b_out->state); 
+    b_state = MIN(b_in->state, b_out->state);
   /* BS_CLOSE is unsupported by BGP4-MIB */
   else if (MIN(b_in->state, b_out->state) == BS_CLOSE)
     b_state = BS_IDLE;
   else
     b_state = MAX(b_in->state, b_out->state);
-  
+
   struct agentx_varbind *vb = (void *) pkt;
   pkt += vb_size(vb);
-  
+
   switch (o->ids[4])
   {
     case SNMP_BGP_IDENTIFIER:
@@ -888,12 +1009,12 @@ find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt,  uint size, uint co
       }
       else
       {
-       STORE_PTR(pkt, ipa_to_u32(IPA_NONE));
+       put_blank(pkt);         /* store 4B of zeroes */
        BGP_DATA(vb, AGENTX_IP_ADDRESS, pkt);
       }
       break;
-      
-    case SNMP_BGP_STATE: 
+
+    case SNMP_BGP_STATE:
       STORE_PTR(pkt, b_state);
       BGP_DATA(vb, AGENTX_INTEGER, pkt);
       break;
@@ -1020,9 +1141,7 @@ find_bgp_one(struct bgp_proto *bp, struct oid *o, byte *pkt,  uint size, uint co
 
     case SNMP_BGP_FSM_ESTABLISHED_TIME:
     case SNMP_BGP_IN_UPDATE_ELAPSED_TIME:
-      vb->type = AGENTX_NO_SUCH_OBJECT;
-      /* pkt += 0;  no data */
-      break;
+      return no_such_object(pkt, vb);
 
     /* no default */
   }
@@ -1046,7 +1165,7 @@ snmp_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint
       /* real size is 8 but we already shifted the pkt by 4 */
       BGP_DATA(vb, AGENTX_OCTET_STRING, pkt);
       break;
-      
+
     case BGP4_MIB_LOCAL_AS:
       // XXX local as to use
       STORE_PTR(pkt, p->local_as);
@@ -1054,29 +1173,26 @@ snmp_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint
       break;
 
     case BGP4_PEER_TABLE:
-      /* end part of .1.3.6.1.2.1.15.3.1.x.a.b.c.d */ 
+      /* 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
          || o->ids[4] == 0 || o->ids[4] > 24)
-      {
-       vb->type = AGENTX_NO_SUCH_OBJECT;
-       return buf + vb_size(vb);
-      }
+       return 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]);  
+      ip_addr addr = ipa_build4(o->ids[5], o->ids[6], o->ids[7], o->ids[8]);
       struct snmp_bgp_peer *pe =
         HASH_FIND(p->bgp_hash, SNMP_HASH, addr);
 
       struct bgp_proto *bp = NULL;
-      if (pe && pe->bond->proto->proto && 
+      if (pe && ((struct proto_config *)pe->config)->proto &&
          ipa_equal(addr,
-           ((struct bgp_proto *) pe->bond->proto->proto)->remote_ip))
+           (((struct bgp_proto *) ((struct proto_config *)pe->config)->proto)->remote_ip)))
       {
-       bp = (void *) pe->bond->proto->proto;
+       bp = (void *) ((struct proto_config *) pe->config)->proto;
       }
 
       /* IF WE CONSIDER CHANGES OF REMOTE IP
-      else 
+      else
       {
        struct snmp_bond *b;
        WALK_LIST(b, p->bgp_entries)
@@ -1087,37 +1203,41 @@ snmp_bgp_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint
       */
 
       if (!bp)
-      {
-       vb->type = AGENTX_NO_SUCH_OBJECT;
        /* pkt += 0; no data */
-       return pkt;     
-      }
-      
-      return find_bgp_one(bp, o, buf, size, contid); 
+       return no_such_object(pkt, vb);
+
+      return find_bgp_one(bp, o, buf, size, contid);
       break;
 
     default:
-      vb->type = AGENTX_NO_SUCH_OBJECT;
-      /* pkt += 0; no data */ 
-      break;
+      /* pkt += 0; no data */
+      return no_such_object(pkt, vb);
   }
 
   return pkt;
 }
 
+/*
 static byte *
 find_ospf_record(struct snmp_proto *p, struct oid *o, byte *buf, uint size)
 {
   // TODO XXX
   return NULL;
 }
+*/
 
 static byte *
-unsupported_oid(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint contid)
+no_such_object(byte *buf, struct agentx_varbind *vb)
 {
-  struct agentx_varbind *vb = (void *) buf;
   vb->type = AGENTX_NO_SUCH_OBJECT;
-  return buf + vb_size(vb);
+  return buf;
+}
+
+static byte * UNUSED
+no_such_instance(byte *buf, struct agentx_varbind *vb)
+{
+  vb->type = AGENTX_NO_SUCH_INSTANCE;
+  return buf;
 }
 
 static inline byte *
@@ -1126,58 +1246,25 @@ 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));
-  
+
                        /* SNMPv2   mgmt                     mib-2 */
   if (o->n_subid < 2 || (o->prefix != 2 && o->ids[0] != 1))
-  {
-    vb->type = AGENTX_NO_SUCH_OBJECT;
-    return buf + vb_size(vb);
-  }
+    no_such_object(buf + vb_size(vb), vb);
+
   switch (o->ids[1])
   {
     case SNMP_BGP4_MIB:
-      if (snmp_bgp_is_supported(o))
-       return snmp_bgp_record(p, o, buf, size, contid);
-      else
-       return unsupported_oid(p, o, buf, size, contid);
+      return snmp_bgp_record(p, o, buf, size, contid);
 
     case SNMP_OSPFv3_MIB:
-      return unsupported_oid(p, o, buf, size, contid);
+      return no_such_object(buf, vb);
       //return find_ospf_record(p, o, buf, size);
 
     default:
-      return unsupported_oid(p, o, buf, size, contid);
-      log(L_INFO "unsupported oid");
-      break;
+      return no_such_object(buf, vb);
   }
 }
 
-/* tests if there is present canonical "internet" prefix .1.3.6.1
-  and if so it shortens the oid to the ``prefix'' form */
-static int
-prefixize_in_place(struct oid *o, int byte_ord)
-{
-  const u32 prefix[] = {1, 3, 6, 1};
-
-  /* NETWORK_BYTE_ORDER */
-  if (byte_ord)
-    /* prefix len == 4 */
-    for (uint i = 0; i < 4; i++)
-      if (get_u32(&o->ids[i]) != prefix[i]) return 0;
-
-  else
-    /* prefix len == 4 */
-    for (uint i = 0; i < 4; i++)
-      if (o->ids[i] != prefix[i]) return 0;
-
-  o->n_subid -= 5;
-  o->prefix = o->ids[4];
-  /* n_subid contains number of elements, not bytes */
-  memmove(&o->ids, &o->ids[5], o->n_subid << 2);
-  return 1;
-}
-
 static struct oid *
 prefixize(struct snmp_proto *p, struct oid *o, int byte_ord)
 {
@@ -1208,12 +1295,11 @@ find_n_fill(struct snmp_proto *p, struct oid *o, byte *buf, uint size, uint cont
 {
   struct oid *new;
   if (!o->prefix && (new = prefixize(p, o, byte_ord)) != NULL)
-    find_prefixed(p, new, buf, size, contid);
+    return find_prefixed(p, new, buf, size, contid);
   else if (o->prefix)
-    find_prefixed(p, o, buf, size, contid);
-  else
-    // TODO handle unprefixable oids
-    return NULL;
+    return find_prefixed(p, o, buf, size, contid);
+
+  return NULL;
 }
 
 static byte *
@@ -1241,7 +1327,7 @@ prepare_response(struct snmp_proto *p, byte *buf, uint size)
 static void
 response_err_ind(byte *buf, uint err, uint ind)
 {
-  log(L_INFO "reponse_err_ind()");
+  log(L_INFO "reponse_err_ind() %u %u", err, ind);
   struct agentx_response *res = (void *) buf;
 
   res->err = err;