]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
SNMP: AgentX over UNIX-domain sockets
authorVojtech Vilimek <vojtech.vilimek@nic.cz>
Mon, 22 Jul 2024 16:17:35 +0000 (18:17 +0200)
committerVojtech Vilimek <vojtech.vilimek@nic.cz>
Mon, 22 Jul 2024 16:17:35 +0000 (18:17 +0200)
proto/snmp/config.Y
proto/snmp/snmp.c
proto/snmp/snmp.h

index 1d7c421d9850e5f7947cc4c88888e2af2fa77d1c..e7fe5364a844bbc34b3a7d73a4205dfe99523987 100644 (file)
@@ -31,7 +31,6 @@ snmp_proto:
 snmp_proto_item:
    proto_item
  | snmp_bgp_bond
- /* | INTERFACE snmp_interface TODO */
  | LOCAL PORT expr {
     if (($3 < 1) || ($3 > 65535)) cf_error("Invalid port number");
     SNMP_CFG->local_port = $3;
@@ -42,12 +41,31 @@ snmp_proto_item:
   }
  | LOCAL ID IP4 { SNMP_CFG->bgp_local_id = $3; }
  | LOCAL ADDRESS IP4 { SNMP_CFG->local_ip = $3; }
+ | REMOTE ADDRESS DEFAULT {
+    if (SNMP_CFG->trans_type != SNMP_TRANS_DEFAULT)
+      cf_error("Duplicit option remote address");
+  }
  | REMOTE ADDRESS IP4 {
-    if (ip4_zero($3)) cf_error("Invalid remote ip address");
+    if (SNMP_CFG->trans_type != SNMP_TRANS_DEFAULT)
+      cf_error("Duplicit option remote address");
+
+    // TODO
+    //if (ip4_zero($3)) cf_error("Invalid remote ip address");
+
     SNMP_CFG->remote_ip = $3;
+    SNMP_CFG->trans_type = SNMP_TRANS_TCP;
+  }
+ | REMOTE ADDRESS text {
+    if (SNMP_CFG->trans_type != SNMP_TRANS_DEFAULT)
+      cf_error("Duplicit option remote address");
+
+    if (strcmp($3, agentx_master_addr)) {
+      SNMP_CFG->remote_path = $3;
+      SNMP_CFG->trans_type = SNMP_TRANS_UNIX;
+    }
   }
  | LOCAL AS expr {
-    if ($3 < 1 || $3 > 65535) cf_error("Invalid local AS");
+    if ($3 < 1 || $3 > UINT16_MAX) cf_error("Invalid local AS");
     SNMP_CFG->bgp_local_as = $3;
   }
  | SNMP DESCRIPTION text {
@@ -87,7 +105,9 @@ snmp_proto_start: proto_start SNMP
   SNMP_CFG->bonds = 0;
 
   SNMP_CFG->local_ip = IP4_NONE;
-  SNMP_CFG->remote_ip = ip4_build(127,0,0,1);
+  SNMP_CFG->remote_ip = IP4_NONE;
+  SNMP_CFG->remote_path = agentx_master_addr;
+  SNMP_CFG->trans_type = SNMP_TRANS_DEFAULT;
   SNMP_CFG->bgp_local_id = IP4_NONE;
   SNMP_CFG->local_port = 0;
   SNMP_CFG->remote_port = 705;
index f08386fbe7aeda53732a47e34b5dc0ec0321f956..2d81a29739bb0e9d38f57c88d9e492f405672069 100644 (file)
 // TODO: remove me
 #include "proto/bgp/bgp.h"
 
+const char agentx_master_addr[] = AGENTX_MASTER_ADDR;
 
 static void snmp_start_locked(struct object_lock *lock);
 static void snmp_sock_err(sock *sk, int err);
@@ -170,6 +171,7 @@ int
 snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
 {
   enum snmp_proto_state last = p->state;
+  const struct snmp_config *cf = (struct snmp_config *) p->p.cf;
 
   TRACE(D_EVENTS, "SNMP changing state to %u", state);
 
@@ -193,31 +195,50 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
   case SNMP_INIT:
     DBG("snmp -> SNMP_INIT\n");
     ASSERT(last == SNMP_DOWN);
-    struct object_lock *lock;
-    lock = p->lock = olock_new(p->pool);
-
-    /*
-     * lock->addr
-     * lock->port
-     * lock->iface
-     * lock->vrf
-     */
-    lock->type = OBJLOCK_TCP;
-    lock->hook = snmp_start_locked;
-    lock->data = p;
-    olock_acquire(lock);
-    return PS_START;
+
+    if (cf->trans_type == SNMP_TRANS_TCP)
+    {
+      /* We need to lock the IP address */
+      struct object_lock *lock;
+      lock = p->lock = olock_new(p->pool);
+
+      /*
+       * lock->iface
+       * lock->vrf
+       */
+      lock->addr = ipa_from_ip4(cf->remote_ip);
+      lock->port = cf->remote_port;
+      lock->type = OBJLOCK_TCP;
+      lock->hook = snmp_start_locked;
+      lock->data = p;
+      olock_acquire(lock);
+      return PS_START;
+    }
+
+    p->state = state = SNMP_LOCKED;
+    /* Fall thru */
 
   case SNMP_LOCKED:
     DBG("snmp -> SNMP_LOCKED\n");
     ASSERT(last == SNMP_INIT || SNMP_RESET);
     sock *s = sk_new(p->pool);
-    s->type = SK_TCP_ACTIVE;
-    s->saddr = ipa_from_ip4(p->local_ip);
-    s->daddr = ipa_from_ip4(p->remote_ip);
-    s->dport = p->remote_port;
-    s->rbsize = SNMP_RX_BUFFER_SIZE;
-    s->tbsize = SNMP_TX_BUFFER_SIZE;
+
+    if (cf->trans_type == SNMP_TRANS_TCP)
+    {
+      s->type = SK_TCP_ACTIVE;
+      s->saddr = ipa_from_ip4(p->local_ip);
+      s->daddr = ipa_from_ip4(p->remote_ip);
+      s->dport = p->remote_port;
+      s->rbsize = SNMP_RX_BUFFER_SIZE;
+      s->tbsize = SNMP_TX_BUFFER_SIZE;
+    }
+    else
+    {
+      s->type = SK_UNIX_ACTIVE;
+      s->host = cf->remote_path; /* daddr */
+      s->rbsize = SNMP_RX_BUFFER_SIZE;
+      s->tbsize = SNMP_TX_BUFFER_SIZE;
+    }
 
     /* s->tos = IP_PREC_INTERNET_CONTROL */
     s->tx_hook = snmp_connected;
@@ -241,12 +262,14 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
     p->sock->rx_hook = snmp_rx;
     p->sock->tx_hook = NULL;
     snmp_start_subagent(p);
-    // handle no response (for long time)
+    p->startup_timer->hook = snmp_stop_timeout;
+    tm_start(p->startup_timer, 1 S);
     return PS_START;
 
   case SNMP_REGISTER:
     DBG("snmp -> SNMP_REGISTER\n");
     ASSERT(last == SNMP_OPEN);
+    tm_stop(p->startup_timer); /* stop timeout */
     snmp_register_mibs(p);
     return PS_START;
 
@@ -276,6 +299,7 @@ snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state)
     DBG("snmp -> SNMP_RESET\n");
     ASSUME(last == SNMP_REGISTER || last == SNMP_CONN);
     ASSUME(p->sock);
+    snmp_stop_subagent(p);
     p->sock->rx_hook = snmp_rx_skip;
     p->sock->tx_hook = snmp_tx_skip;
     return PS_STOP;
@@ -612,8 +636,10 @@ snmp_show_proto_info(struct proto *P)
 static void
 snmp_postconfig(struct proto_config *CF)
 {
+  const struct snmp_config *cf  = (struct snmp_config *) CF;
+
   /* Walk the BGP protocols and cache their references. */
-  if (((struct snmp_config *) CF)->bgp_local_as == 0)
+  if (cf->bgp_local_as == 0)
     cf_error("local as not specified");
 }
 
index 1f2552a5ff405ea56aa82169a230c3ee286450e1..e5f126c66ca983100c3f0ca480ce4d174d9bf3a7 100644 (file)
@@ -29,6 +29,8 @@
 #define SNMP_TX_BUFFER_SIZE 8192
 #define SNMP_PKT_SIZE_MAX 4098
 
+#define AGENTX_MASTER_ADDR "/var/agentx/master"
+
 enum snmp_proto_state {
   SNMP_DOWN = 0,
   SNMP_INIT = 1,
@@ -46,12 +48,20 @@ struct snmp_bond {
   u8 type;
 };
 
+enum snmp_transport_type {
+  SNMP_TRANS_DEFAULT,
+  SNMP_TRANS_UNIX,
+  SNMP_TRANS_TCP,
+};
+
 struct snmp_config {
   struct proto_config cf;
+  enum snmp_transport_type trans_type;
   ip4_addr local_ip;
-  ip4_addr remote_ip;
   u16 local_port;
+  ip4_addr remote_ip;            /* master agentx IP address for TCP transport */
   u16 remote_port;
+  const char *remote_path;       /* master agentx UNIX socket name */
 
   ip4_addr bgp_local_id;         /* BGP4-MIB related fields */
   u32 bgp_local_as;
@@ -67,7 +77,7 @@ struct snmp_config {
                                   * We use this fact to check differences of
                                   * nonallocated parts of configs with memcpy
                                   */
-  //const struct oid *oid_identifier;  TODO 
+  //const struct oid *oid_identifier;  TODO
 };
 
 #define SNMP_BGP_P_REGISTERING 0x01
@@ -84,6 +94,7 @@ struct snmp_registered_oid {
   struct oid *oid;
 };
 
+
 struct snmp_proto {
   struct proto p;
   struct object_lock *lock;
@@ -153,4 +164,6 @@ int snmp_set_state(struct snmp_proto *p, enum snmp_proto_state state);
 
 void snmp_reset(struct snmp_proto *p);
 
+extern const char agentx_master_addr[sizeof(AGENTX_MASTER_ADDR)];
+
 #endif